7079317: Incorrect branch's destination block in PrintoOptoAssembly output
Summary: save/restore label and block in scratch_emit_size()
Reviewed-by: never
--- a/hotspot/src/share/vm/adlc/archDesc.cpp Tue Aug 16 04:14:05 2011 -0700
+++ b/hotspot/src/share/vm/adlc/archDesc.cpp Tue Aug 16 11:53:57 2011 -0700
@@ -331,6 +331,11 @@
// Find result type for match
const char *result = instr->reduce_result();
+ if ( instr->is_ideal_branch() && instr->label_position() == -1 ||
+ !instr->is_ideal_branch() && instr->label_position() != -1) {
+ syntax_err(instr->_linenum, "%s: Only branches to a label are supported\n", rootOp);
+ }
+
Attribute *attr = instr->_attribs;
while (attr != NULL) {
if (strcmp(attr->_ident,"ins_short_branch") == 0 &&
--- a/hotspot/src/share/vm/adlc/formssel.cpp Tue Aug 16 04:14:05 2011 -0700
+++ b/hotspot/src/share/vm/adlc/formssel.cpp Tue Aug 16 11:53:57 2011 -0700
@@ -340,12 +340,11 @@
return _matrule->is_ideal_jump();
}
-// Return 'true' if instruction matches ideal 'If' | 'Goto' |
-// 'CountedLoopEnd' | 'Jump'
+// Return 'true' if instruction matches ideal 'If' | 'Goto' | 'CountedLoopEnd'
bool InstructForm::is_ideal_branch() const {
if( _matrule == NULL ) return false;
- return _matrule->is_ideal_if() || _matrule->is_ideal_goto() || _matrule->is_ideal_jump();
+ return _matrule->is_ideal_if() || _matrule->is_ideal_goto();
}
@@ -383,7 +382,7 @@
bool InstructForm::is_ideal_control() const {
if ( ! _matrule) return false;
- return is_ideal_return() || is_ideal_branch() || is_ideal_halt();
+ return is_ideal_return() || is_ideal_branch() || _matrule->is_ideal_jump() || is_ideal_halt();
}
// Return 'true' if this instruction matches an ideal 'Call' node
--- a/hotspot/src/share/vm/adlc/output_c.cpp Tue Aug 16 04:14:05 2011 -0700
+++ b/hotspot/src/share/vm/adlc/output_c.cpp Tue Aug 16 11:53:57 2011 -0700
@@ -3094,6 +3094,13 @@
fprintf(fp," oper->_label = label;\n");
fprintf(fp," oper->_block_num = block_num;\n");
fprintf(fp,"}\n");
+ // Save the label
+ fprintf(fp,"void %sNode::save_label( Label** label, uint* block_num ) {\n", instr->_ident);
+ fprintf(fp," labelOper* oper = (labelOper*)(opnd_array(%d));\n",
+ label_position );
+ fprintf(fp," *label = oper->_label;\n");
+ fprintf(fp," *block_num = oper->_block_num;\n");
+ fprintf(fp,"}\n");
}
}
--- a/hotspot/src/share/vm/adlc/output_h.cpp Tue Aug 16 04:14:05 2011 -0700
+++ b/hotspot/src/share/vm/adlc/output_h.cpp Tue Aug 16 11:53:57 2011 -0700
@@ -1519,8 +1519,9 @@
// Declare Node::methods that set operand Label's contents
int label_position = instr->label_position();
if( label_position != -1 ) {
- // Set the label, stored in labelOper::_branch_label
+ // Set/Save the label, stored in labelOper::_branch_label
fprintf(fp," virtual void label_set( Label* label, uint block_num );\n");
+ fprintf(fp," virtual void save_label( Label** label, uint* block_num );\n");
}
// If this instruction contains a methodOper
@@ -1678,16 +1679,6 @@
}
}
- // flag: if instruction matches 'If' | 'Goto' | 'CountedLoopEnd | 'Jump'
- if ( instr->is_ideal_branch() ) {
- if ( node_flags_set ) {
- fprintf(fp," | Flag_is_Branch");
- } else {
- fprintf(fp,"init_flags(Flag_is_Branch");
- node_flags_set = true;
- }
- }
-
// flag: if this instruction is cisc alternate
if ( can_cisc_spill() && instr->is_cisc_alternate() ) {
if ( node_flags_set ) {
--- a/hotspot/src/share/vm/opto/block.cpp Tue Aug 16 04:14:05 2011 -0700
+++ b/hotspot/src/share/vm/opto/block.cpp Tue Aug 16 11:53:57 2011 -0700
@@ -839,7 +839,7 @@
// Make sure we TRUE branch to the target
if( proj0->Opcode() == Op_IfFalse ) {
- iff->negate();
+ iff->as_MachIf()->negate();
}
b->_nodes.pop(); // Remove IfFalse & IfTrue projections
--- a/hotspot/src/share/vm/opto/compile.cpp Tue Aug 16 04:14:05 2011 -0700
+++ b/hotspot/src/share/vm/opto/compile.cpp Tue Aug 16 11:53:57 2011 -0700
@@ -519,15 +519,18 @@
// Do the emission.
Label fakeL; // Fake label for branch instructions.
- bool is_branch = n->is_Branch() && n->as_Mach()->ideal_Opcode() != Op_Jump;
+ Label* saveL = NULL;
+ uint save_bnum = 0;
+ bool is_branch = n->is_MachBranch();
if (is_branch) {
MacroAssembler masm(&buf);
masm.bind(fakeL);
- n->as_Mach()->label_set(&fakeL, 0);
+ n->as_MachBranch()->save_label(&saveL, &save_bnum);
+ n->as_MachBranch()->label_set(&fakeL, 0);
}
n->emit(buf, this->regalloc());
- if (is_branch) // Clear the reference to fake label.
- n->as_Mach()->label_set(NULL, 0);
+ if (is_branch) // Restore label.
+ n->as_MachBranch()->label_set(saveL, save_bnum);
// End scratch_emit_size section.
set_in_scratch_emit_size(false);
--- a/hotspot/src/share/vm/opto/idealGraphPrinter.cpp Tue Aug 16 04:14:05 2011 -0700
+++ b/hotspot/src/share/vm/opto/idealGraphPrinter.cpp Tue Aug 16 11:53:57 2011 -0700
@@ -441,9 +441,6 @@
if (flags & Node::Flag_is_cisc_alternate) {
print_prop("is_cisc_alternate", "true");
}
- if (flags & Node::Flag_is_Branch) {
- print_prop("is_branch", "true");
- }
if (flags & Node::Flag_is_dead_loop_safe) {
print_prop("is_dead_loop_safe", "true");
}
--- a/hotspot/src/share/vm/opto/machnode.cpp Tue Aug 16 04:14:05 2011 -0700
+++ b/hotspot/src/share/vm/opto/machnode.cpp Tue Aug 16 11:53:57 2011 -0700
@@ -389,12 +389,6 @@
}
-//------------------------------negate-----------------------------------------
-// Negate conditional branches. Error for non-branch Nodes
-void MachNode::negate() {
- ShouldNotCallThis();
-}
-
//------------------------------peephole---------------------------------------
// Apply peephole rule(s) to this instruction
MachNode *MachNode::peephole( Block *block, int block_index, PhaseRegAlloc *ra_, int &deleted, Compile* C ) {
@@ -407,12 +401,6 @@
ShouldNotCallThis();
}
-//------------------------------label_set--------------------------------------
-// Set the Label for a LabelOper, if an operand for this instruction
-void MachNode::label_set( Label* label, uint block_num ) {
- ShouldNotCallThis();
-}
-
//------------------------------method_set-------------------------------------
// Set the absolute address of a method
void MachNode::method_set( intptr_t addr ) {
@@ -517,6 +505,9 @@
void MachNullCheckNode::label_set(Label* label, uint block_num) {
// Nothing to emit
}
+void MachNullCheckNode::save_label( Label** label, uint* block_num ) {
+ // Nothing to emit
+}
const RegMask &MachNullCheckNode::in_RegMask( uint idx ) const {
if( idx == 0 ) return RegMask::Empty;
--- a/hotspot/src/share/vm/opto/machnode.hpp Tue Aug 16 04:14:05 2011 -0700
+++ b/hotspot/src/share/vm/opto/machnode.hpp Tue Aug 16 11:53:57 2011 -0700
@@ -185,7 +185,6 @@
virtual void use_cisc_RegMask();
// Support for short branches
- virtual MachNode *short_branch_version(Compile* C) { return NULL; }
bool may_be_short_branch() const { return (flags() & Flag_may_be_short_branch) != 0; }
// Avoid back to back some instructions on some CPUs.
@@ -272,18 +271,12 @@
// Call "get_base_and_disp" to decide which category of memory is used here.
virtual const class TypePtr *adr_type() const;
- // Negate conditional branches. Error for non-branch Nodes
- virtual void negate();
-
// Apply peephole rule(s) to this instruction
virtual MachNode *peephole( Block *block, int block_index, PhaseRegAlloc *ra_, int &deleted, Compile* C );
// Top-level ideal Opcode matched
virtual int ideal_Opcode() const { return Op_Node; }
- // Set the branch inside jump MachNodes. Error for non-branch Nodes.
- virtual void label_set( Label* label, uint block_num );
-
// Adds the label for the case
virtual void add_case_label( int switch_val, Label* blockLabel);
@@ -514,25 +507,41 @@
#endif
};
+//------------------------------MachBranchNode--------------------------------
+// Abstract machine branch Node
+class MachBranchNode : public MachIdealNode {
+public:
+ MachBranchNode() : MachIdealNode() {
+ init_class_id(Class_MachBranch);
+ }
+ virtual void label_set(Label* label, uint block_num) = 0;
+ virtual void save_label(Label** label, uint* block_num) = 0;
+
+ // Support for short branches
+ virtual MachNode *short_branch_version(Compile* C) { return NULL; }
+
+ virtual bool pinned() const { return true; };
+};
+
//------------------------------MachNullChkNode--------------------------------
// Machine-dependent null-pointer-check Node. Points a real MachNode that is
// also some kind of memory op. Turns the indicated MachNode into a
// conditional branch with good latency on the ptr-not-null path and awful
// latency on the pointer-is-null path.
-class MachNullCheckNode : public MachIdealNode {
+class MachNullCheckNode : public MachBranchNode {
public:
const uint _vidx; // Index of memop being tested
- MachNullCheckNode( Node *ctrl, Node *memop, uint vidx ) : MachIdealNode(), _vidx(vidx) {
+ MachNullCheckNode( Node *ctrl, Node *memop, uint vidx ) : MachBranchNode(), _vidx(vidx) {
init_class_id(Class_MachNullCheck);
- init_flags(Flag_is_Branch);
add_req(ctrl);
add_req(memop);
}
+ virtual uint size_of() const { return sizeof(*this); }
virtual void emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const;
virtual void label_set(Label* label, uint block_num);
- virtual bool pinned() const { return true; };
+ virtual void save_label(Label** label, uint* block_num);
virtual void negate() { }
virtual const class Type *bottom_type() const { return TypeTuple::IFBOTH; }
virtual uint ideal_reg() const { return NotAMachineReg; }
@@ -578,14 +587,16 @@
//------------------------------MachIfNode-------------------------------------
// Machine-specific versions of IfNodes
-class MachIfNode : public MachNode {
+class MachIfNode : public MachBranchNode {
virtual uint size_of() const { return sizeof(*this); } // Size is bigger
public:
float _prob; // Probability branch goes either way
float _fcnt; // Frequency counter
- MachIfNode() : MachNode() {
+ MachIfNode() : MachBranchNode() {
init_class_id(Class_MachIf);
}
+ // Negate conditional branches.
+ virtual void negate() = 0;
#ifndef PRODUCT
virtual void dump_spec(outputStream *st) const;
#endif
@@ -593,9 +604,9 @@
//------------------------------MachGotoNode-----------------------------------
// Machine-specific versions of GotoNodes
-class MachGotoNode : public MachNode {
+class MachGotoNode : public MachBranchNode {
public:
- MachGotoNode() : MachNode() {
+ MachGotoNode() : MachBranchNode() {
init_class_id(Class_MachGoto);
}
};
--- a/hotspot/src/share/vm/opto/node.hpp Tue Aug 16 04:14:05 2011 -0700
+++ b/hotspot/src/share/vm/opto/node.hpp Tue Aug 16 11:53:57 2011 -0700
@@ -77,6 +77,7 @@
class LoadStoreNode;
class LockNode;
class LoopNode;
+class MachBranchNode;
class MachCallDynamicJavaNode;
class MachCallJavaNode;
class MachCallLeafNode;
@@ -572,13 +573,14 @@
DEFINE_CLASS_ID(MachCallDynamicJava, MachCallJava, 1)
DEFINE_CLASS_ID(MachCallRuntime, MachCall, 1)
DEFINE_CLASS_ID(MachCallLeaf, MachCallRuntime, 0)
- DEFINE_CLASS_ID(MachSpillCopy, Mach, 1)
- DEFINE_CLASS_ID(MachNullCheck, Mach, 2)
- DEFINE_CLASS_ID(MachIf, Mach, 3)
- DEFINE_CLASS_ID(MachTemp, Mach, 4)
- DEFINE_CLASS_ID(MachConstantBase, Mach, 5)
- DEFINE_CLASS_ID(MachConstant, Mach, 6)
- DEFINE_CLASS_ID(MachGoto, Mach, 7)
+ DEFINE_CLASS_ID(MachBranch, Mach, 1)
+ DEFINE_CLASS_ID(MachIf, MachBranch, 0)
+ DEFINE_CLASS_ID(MachGoto, MachBranch, 1)
+ DEFINE_CLASS_ID(MachNullCheck, MachBranch, 2)
+ DEFINE_CLASS_ID(MachSpillCopy, Mach, 2)
+ DEFINE_CLASS_ID(MachTemp, Mach, 3)
+ DEFINE_CLASS_ID(MachConstantBase, Mach, 4)
+ DEFINE_CLASS_ID(MachConstant, Mach, 5)
DEFINE_CLASS_ID(Type, Node, 2)
DEFINE_CLASS_ID(Phi, Type, 0)
@@ -634,8 +636,7 @@
Flag_is_macro = Flag_needs_anti_dependence_check << 1,
Flag_is_Con = Flag_is_macro << 1,
Flag_is_cisc_alternate = Flag_is_Con << 1,
- Flag_is_Branch = Flag_is_cisc_alternate << 1,
- Flag_is_dead_loop_safe = Flag_is_Branch << 1,
+ Flag_is_dead_loop_safe = Flag_is_cisc_alternate << 1,
Flag_may_be_short_branch = Flag_is_dead_loop_safe << 1,
Flag_avoid_back_to_back = Flag_may_be_short_branch << 1,
_max_flags = (Flag_avoid_back_to_back << 1) - 1 // allow flags combination
@@ -721,6 +722,7 @@
DEFINE_CLASS_QUERY(Lock)
DEFINE_CLASS_QUERY(Loop)
DEFINE_CLASS_QUERY(Mach)
+ DEFINE_CLASS_QUERY(MachBranch)
DEFINE_CLASS_QUERY(MachCall)
DEFINE_CLASS_QUERY(MachCallDynamicJava)
DEFINE_CLASS_QUERY(MachCallJava)
@@ -787,9 +789,6 @@
// skip some other important test.)
virtual bool depends_only_on_test() const { assert(!is_CFG(), ""); return true; };
- // defined for MachNodes that match 'If' | 'Goto' | 'CountedLoopEnd' | 'Jump'
- bool is_Branch() const { return (_flags & Flag_is_Branch) != 0; }
-
// When building basic blocks, I need to have a notion of block beginning
// Nodes, next block selector Nodes (block enders), and next block
// projections. These calls need to work on their machine equivalents. The
--- a/hotspot/src/share/vm/opto/output.cpp Tue Aug 16 04:14:05 2011 -0700
+++ b/hotspot/src/share/vm/opto/output.cpp Tue Aug 16 11:53:57 2011 -0700
@@ -420,7 +420,7 @@
}
}
if (mach->may_be_short_branch()) {
- if (!nj->is_Branch()) {
+ if (!nj->is_MachBranch()) {
#ifndef PRODUCT
nj->dump(3);
#endif
@@ -473,7 +473,7 @@
MachNode* mach = (idx == -1) ? NULL: b->_nodes[idx]->as_Mach();
if (mach != NULL && mach->may_be_short_branch()) {
#ifdef ASSERT
- assert(jmp_size[i] > 0 && mach->is_Branch(), "sanity");
+ assert(jmp_size[i] > 0 && mach->is_MachBranch(), "sanity");
int j;
// Find the branch; ignore trailing NOPs.
for (j = b->_nodes.size()-1; j>=0; j--) {
@@ -500,7 +500,7 @@
if (_matcher->is_short_branch_offset(mach->rule(), br_size, offset)) {
// We've got a winner. Replace this branch.
- MachNode* replacement = mach->short_branch_version(this);
+ MachNode* replacement = mach->as_MachBranch()->short_branch_version(this);
// Update the jmp_size.
int new_size = replacement->size(_regalloc);
@@ -670,7 +670,7 @@
if (_matcher->is_short_branch_offset(mach->rule(), br_size, offset)) {
// We've got a winner. Replace this branch.
- MachNode* replacement = mach->short_branch_version(this);
+ MachNode* replacement = mach->as_MachBranch()->short_branch_version(this);
// Update the jmp_size.
int new_size = replacement->size(_regalloc);
@@ -1525,25 +1525,21 @@
}
// If this is a branch, then fill in the label with the target BB's label
- else if (mach->is_Branch()) {
-
- if (mach->ideal_Opcode() == Op_Jump) {
- for (uint h = 0; h < b->_num_succs; h++) {
- Block* succs_block = b->_succs[h];
- for (uint j = 1; j < succs_block->num_preds(); j++) {
- Node* jpn = succs_block->pred(j);
- if (jpn->is_JumpProj() && jpn->in(0) == mach) {
- uint block_num = succs_block->non_connector()->_pre_order;
- Label *blkLabel = &blk_labels[block_num];
- mach->add_case_label(jpn->as_JumpProj()->proj_no(), blkLabel);
- }
+ else if (mach->is_MachBranch()) {
+ // This requires the TRUE branch target be in succs[0]
+ uint block_num = b->non_connector_successor(0)->_pre_order;
+ mach->as_MachBranch()->label_set( &blk_labels[block_num], block_num );
+ } else if (mach->ideal_Opcode() == Op_Jump) {
+ for (uint h = 0; h < b->_num_succs; h++) {
+ Block* succs_block = b->_succs[h];
+ for (uint j = 1; j < succs_block->num_preds(); j++) {
+ Node* jpn = succs_block->pred(j);
+ if (jpn->is_JumpProj() && jpn->in(0) == mach) {
+ uint block_num = succs_block->non_connector()->_pre_order;
+ Label *blkLabel = &blk_labels[block_num];
+ mach->add_case_label(jpn->as_JumpProj()->proj_no(), blkLabel);
}
}
- } else {
- // For Branchs
- // This requires the TRUE branch target be in succs[0]
- uint block_num = b->non_connector_successor(0)->_pre_order;
- mach->label_set( &blk_labels[block_num], block_num );
}
}
@@ -2229,7 +2225,7 @@
// the first instruction at the branch target is
// copied to the delay slot, and the branch goes to
// the instruction after that at the branch target
- if ( n->is_Mach() && n->is_Branch() ) {
+ if ( n->is_MachBranch() ) {
assert( !n->is_MachNullCheck(), "should not look for delay slot for Null Check" );
assert( !n->is_Catch(), "should not look for delay slot for Catch" );
@@ -2890,7 +2886,7 @@
// Kill projections on a branch should appear to occur on the
// branch, not afterwards, so grab the masks from the projections
// and process them.
- if (n->is_Branch()) {
+ if (n->is_MachBranch() || n->is_Mach() && n->as_Mach()->ideal_Opcode() == Op_Jump) {
for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
Node* use = n->fast_out(i);
if (use->is_Proj()) {