mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 11:04:34 +02:00
7079317: Incorrect branch's destination block in PrintoOptoAssembly output
Save/restore label and block in scratch_emit_size() Reviewed-by: never
This commit is contained in:
parent
134c40b4db
commit
080f790edc
11 changed files with 84 additions and 85 deletions
|
@ -331,6 +331,11 @@ void ArchDesc::inspectInstructions() {
|
|||
// 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 &&
|
||||
|
|
|
@ -340,12 +340,11 @@ bool InstructForm::is_ideal_jump() const {
|
|||
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_nop() const {
|
|||
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
|
||||
|
|
|
@ -3094,6 +3094,13 @@ void ArchDesc::defineClasses(FILE *fp) {
|
|||
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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1519,8 +1519,9 @@ void ArchDesc::declareClasses(FILE *fp) {
|
|||
// 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 @@ void ArchDesc::declareClasses(FILE *fp) {
|
|||
}
|
||||
}
|
||||
|
||||
// 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 ) {
|
||||
|
|
|
@ -839,7 +839,7 @@ void PhaseCFG::fixup_flow() {
|
|||
|
||||
// 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
|
||||
|
|
|
@ -519,15 +519,18 @@ uint Compile::scratch_emit_size(const Node* n) {
|
|||
// 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);
|
||||
|
|
|
@ -441,9 +441,6 @@ void IdealGraphPrinter::visit_node(Node *n, void *param) {
|
|||
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");
|
||||
}
|
||||
|
|
|
@ -389,12 +389,6 @@ int MachNode::operand_index( uint operand ) const {
|
|||
}
|
||||
|
||||
|
||||
//------------------------------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 @@ void MachNode::add_case_label( int index_num, Label* blockLabel) {
|
|||
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::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
|||
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;
|
||||
|
|
|
@ -185,7 +185,6 @@ public:
|
|||
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 @@ public:
|
|||
// 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 @@ public:
|
|||
#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 @@ public:
|
|||
|
||||
//------------------------------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 @@ public:
|
|||
|
||||
//------------------------------MachGotoNode-----------------------------------
|
||||
// Machine-specific versions of GotoNodes
|
||||
class MachGotoNode : public MachNode {
|
||||
class MachGotoNode : public MachBranchNode {
|
||||
public:
|
||||
MachGotoNode() : MachNode() {
|
||||
MachGotoNode() : MachBranchNode() {
|
||||
init_class_id(Class_MachGoto);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -77,6 +77,7 @@ class LoadNode;
|
|||
class LoadStoreNode;
|
||||
class LockNode;
|
||||
class LoopNode;
|
||||
class MachBranchNode;
|
||||
class MachCallDynamicJavaNode;
|
||||
class MachCallJavaNode;
|
||||
class MachCallLeafNode;
|
||||
|
@ -572,13 +573,14 @@ public:
|
|||
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 @@ public:
|
|||
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 @@ public:
|
|||
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 @@ public:
|
|||
// 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
|
||||
|
|
|
@ -420,7 +420,7 @@ void Compile::shorten_branches(uint* blk_starts, int& code_size, int& reloc_size
|
|||
}
|
||||
}
|
||||
if (mach->may_be_short_branch()) {
|
||||
if (!nj->is_Branch()) {
|
||||
if (!nj->is_MachBranch()) {
|
||||
#ifndef PRODUCT
|
||||
nj->dump(3);
|
||||
#endif
|
||||
|
@ -473,7 +473,7 @@ void Compile::shorten_branches(uint* blk_starts, int& code_size, int& reloc_size
|
|||
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 @@ void Compile::shorten_branches(uint* blk_starts, int& code_size, int& reloc_size
|
|||
|
||||
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 @@ void Compile::finalize_offsets_and_shorten(uint* blk_starts) {
|
|||
|
||||
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,9 +1525,11 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) {
|
|||
}
|
||||
|
||||
// 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) {
|
||||
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++) {
|
||||
|
@ -1539,12 +1541,6 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) {
|
|||
}
|
||||
}
|
||||
}
|
||||
} 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 );
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
|
@ -2229,7 +2225,7 @@ void Scheduling::AddNodeToBundle(Node *n, const Block *bb) {
|
|||
// 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 @@ void Scheduling::ComputeRegisterAntidependencies(Block *b) {
|
|||
// 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()) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue