mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 19:14:38 +02:00
7077312: Provide a CALL effect for instruct declaration in the ad file
Abstracted way to declare that the MachNode has the effect of a call (kills caller save registers, preserves callee save registers) Reviewed-by: twisti, never
This commit is contained in:
parent
89d4179a4b
commit
9d8e44db59
11 changed files with 93 additions and 36 deletions
|
@ -3818,7 +3818,7 @@ void ADLParser::effect_parse(InstructForm *instr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Get list of effect-operand pairs and insert into dictionary
|
// Get list of effect-operand pairs and insert into dictionary
|
||||||
else get_effectlist(instr->_effects, instr->_localNames);
|
else get_effectlist(instr->_effects, instr->_localNames, instr->_has_call);
|
||||||
|
|
||||||
// Debug Stuff
|
// Debug Stuff
|
||||||
if (_AD._adl_debug > 1) fprintf(stderr,"Effect description: %s\n", desc);
|
if (_AD._adl_debug > 1) fprintf(stderr,"Effect description: %s\n", desc);
|
||||||
|
@ -4596,7 +4596,7 @@ void ADLParser::get_oplist(NameList ¶meters, FormDict &operands) {
|
||||||
// effect, and the second must be the name of an operand defined in the
|
// effect, and the second must be the name of an operand defined in the
|
||||||
// operand list of this instruction. Stores the names with a pointer to the
|
// operand list of this instruction. Stores the names with a pointer to the
|
||||||
// effect form in a local effects table.
|
// effect form in a local effects table.
|
||||||
void ADLParser::get_effectlist(FormDict &effects, FormDict &operands) {
|
void ADLParser::get_effectlist(FormDict &effects, FormDict &operands, bool& has_call) {
|
||||||
OperandForm *opForm;
|
OperandForm *opForm;
|
||||||
Effect *eForm;
|
Effect *eForm;
|
||||||
char *ident;
|
char *ident;
|
||||||
|
@ -4629,6 +4629,10 @@ void ADLParser::get_effectlist(FormDict &effects, FormDict &operands) {
|
||||||
// Debugging Stuff
|
// Debugging Stuff
|
||||||
if (_AD._adl_debug > 1) fprintf(stderr, "\tEffect Type: %s\t", ident);
|
if (_AD._adl_debug > 1) fprintf(stderr, "\tEffect Type: %s\t", ident);
|
||||||
skipws();
|
skipws();
|
||||||
|
if (eForm->is(Component::CALL)) {
|
||||||
|
if (_AD._adl_debug > 1) fprintf(stderr, "\n");
|
||||||
|
has_call = true;
|
||||||
|
} else {
|
||||||
// Get name of operand and check that it is in the local name table
|
// Get name of operand and check that it is in the local name table
|
||||||
if( (ident = get_unique_ident(effects, "effect")) == NULL) {
|
if( (ident = get_unique_ident(effects, "effect")) == NULL) {
|
||||||
parse_err(SYNERR, "missing operand identifier in effect list\n");
|
parse_err(SYNERR, "missing operand identifier in effect list\n");
|
||||||
|
@ -4649,6 +4653,7 @@ void ADLParser::get_effectlist(FormDict &effects, FormDict &operands) {
|
||||||
effects.Insert(ident, eForm);
|
effects.Insert(ident, eForm);
|
||||||
// Debugging Stuff
|
// Debugging Stuff
|
||||||
if (_AD._adl_debug > 1) fprintf(stderr, "\tOperand Name: %s\n", ident);
|
if (_AD._adl_debug > 1) fprintf(stderr, "\tOperand Name: %s\n", ident);
|
||||||
|
}
|
||||||
skipws();
|
skipws();
|
||||||
} while(_curchar == ',');
|
} while(_curchar == ',');
|
||||||
|
|
||||||
|
|
|
@ -232,7 +232,7 @@ protected:
|
||||||
char *get_relation_dup(void);
|
char *get_relation_dup(void);
|
||||||
|
|
||||||
void get_oplist(NameList ¶meters, FormDict &operands);// Parse type-operand pairs
|
void get_oplist(NameList ¶meters, FormDict &operands);// Parse type-operand pairs
|
||||||
void get_effectlist(FormDict &effects, FormDict &operands); // Parse effect-operand pairs
|
void get_effectlist(FormDict &effects, FormDict &operands, bool& has_call); // Parse effect-operand pairs
|
||||||
// Return the contents of a parenthesized expression.
|
// Return the contents of a parenthesized expression.
|
||||||
// Requires initial '(' and consumes final ')', which is replaced by '\0'.
|
// Requires initial '(' and consumes final ')', which is replaced by '\0'.
|
||||||
char *get_paren_expr(const char *description, bool include_location = false);
|
char *get_paren_expr(const char *description, bool include_location = false);
|
||||||
|
|
|
@ -1018,6 +1018,9 @@ void ArchDesc::initBaseOpTypes() {
|
||||||
ident = "TEMP";
|
ident = "TEMP";
|
||||||
eForm = new Effect(ident);
|
eForm = new Effect(ident);
|
||||||
_globalNames.Insert(ident, eForm);
|
_globalNames.Insert(ident, eForm);
|
||||||
|
ident = "CALL";
|
||||||
|
eForm = new Effect(ident);
|
||||||
|
_globalNames.Insert(ident, eForm);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -31,7 +31,8 @@ InstructForm::InstructForm(const char *id, bool ideal_only)
|
||||||
: _ident(id), _ideal_only(ideal_only),
|
: _ident(id), _ideal_only(ideal_only),
|
||||||
_localNames(cmpstr, hashstr, Form::arena),
|
_localNames(cmpstr, hashstr, Form::arena),
|
||||||
_effects(cmpstr, hashstr, Form::arena),
|
_effects(cmpstr, hashstr, Form::arena),
|
||||||
_is_mach_constant(false)
|
_is_mach_constant(false),
|
||||||
|
_has_call(false)
|
||||||
{
|
{
|
||||||
_ftype = Form::INS;
|
_ftype = Form::INS;
|
||||||
|
|
||||||
|
@ -62,7 +63,8 @@ InstructForm::InstructForm(const char *id, InstructForm *instr, MatchRule *rule)
|
||||||
: _ident(id), _ideal_only(false),
|
: _ident(id), _ideal_only(false),
|
||||||
_localNames(instr->_localNames),
|
_localNames(instr->_localNames),
|
||||||
_effects(instr->_effects),
|
_effects(instr->_effects),
|
||||||
_is_mach_constant(false)
|
_is_mach_constant(false),
|
||||||
|
_has_call(false)
|
||||||
{
|
{
|
||||||
_ftype = Form::INS;
|
_ftype = Form::INS;
|
||||||
|
|
||||||
|
@ -1754,6 +1756,7 @@ static int effect_lookup(const char *name) {
|
||||||
if(!strcmp(name, "USE_KILL")) return Component::USE_KILL;
|
if(!strcmp(name, "USE_KILL")) return Component::USE_KILL;
|
||||||
if(!strcmp(name, "TEMP")) return Component::TEMP;
|
if(!strcmp(name, "TEMP")) return Component::TEMP;
|
||||||
if(!strcmp(name, "INVALID")) return Component::INVALID;
|
if(!strcmp(name, "INVALID")) return Component::INVALID;
|
||||||
|
if(!strcmp(name, "CALL")) return Component::CALL;
|
||||||
assert( false,"Invalid effect name specified\n");
|
assert( false,"Invalid effect name specified\n");
|
||||||
return Component::INVALID;
|
return Component::INVALID;
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,6 +111,8 @@ public:
|
||||||
ComponentList _components; // List of Components matches MachNode's
|
ComponentList _components; // List of Components matches MachNode's
|
||||||
// operand structure
|
// operand structure
|
||||||
|
|
||||||
|
bool _has_call; // contain a call and caller save registers should be saved?
|
||||||
|
|
||||||
// Public Methods
|
// Public Methods
|
||||||
InstructForm(const char *id, bool ideal_only = false);
|
InstructForm(const char *id, bool ideal_only = false);
|
||||||
InstructForm(const char *id, InstructForm *instr, MatchRule *rule);
|
InstructForm(const char *id, InstructForm *instr, MatchRule *rule);
|
||||||
|
@ -895,7 +897,8 @@ public:
|
||||||
DEF = 0x2, USE_DEF = 0x3,
|
DEF = 0x2, USE_DEF = 0x3,
|
||||||
KILL = 0x4, USE_KILL = 0x5,
|
KILL = 0x4, USE_KILL = 0x5,
|
||||||
SYNTHETIC = 0x8,
|
SYNTHETIC = 0x8,
|
||||||
TEMP = USE | SYNTHETIC
|
TEMP = USE | SYNTHETIC,
|
||||||
|
CALL = 0x10
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1720,6 +1720,16 @@ void ArchDesc::declareClasses(FILE *fp) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// flag: if this instruction is implemented with a call
|
||||||
|
if ( instr->_has_call ) {
|
||||||
|
if ( node_flags_set ) {
|
||||||
|
fprintf(fp," | Flag_has_call");
|
||||||
|
} else {
|
||||||
|
fprintf(fp,"init_flags(Flag_has_call");
|
||||||
|
node_flags_set = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( node_flags_set ) {
|
if ( node_flags_set ) {
|
||||||
fprintf(fp,"); ");
|
fprintf(fp,"); ");
|
||||||
}
|
}
|
||||||
|
|
|
@ -281,6 +281,8 @@ class Block : public CFGElement {
|
||||||
// Find and remove n from block list
|
// Find and remove n from block list
|
||||||
void find_remove( const Node *n );
|
void find_remove( const Node *n );
|
||||||
|
|
||||||
|
// helper function that adds caller save registers to MachProjNode
|
||||||
|
void add_call_kills(MachProjNode *proj, RegMask& regs, const char* save_policy, bool exclude_soe);
|
||||||
// Schedule a call next in the block
|
// Schedule a call next in the block
|
||||||
uint sched_call(Matcher &matcher, Block_Array &bbs, uint node_cnt, Node_List &worklist, int *ready_cnt, MachCallNode *mcall, VectorSet &next_call);
|
uint sched_call(Matcher &matcher, Block_Array &bbs, uint node_cnt, Node_List &worklist, int *ready_cnt, MachCallNode *mcall, VectorSet &next_call);
|
||||||
|
|
||||||
|
|
|
@ -447,6 +447,9 @@ void IdealGraphPrinter::visit_node(Node *n, bool edges, VectorSet* temp_set) {
|
||||||
if (flags & Node::Flag_may_be_short_branch) {
|
if (flags & Node::Flag_may_be_short_branch) {
|
||||||
print_prop("may_be_short_branch", "true");
|
print_prop("may_be_short_branch", "true");
|
||||||
}
|
}
|
||||||
|
if (flags & Node::Flag_has_call) {
|
||||||
|
print_prop("has_call", "true");
|
||||||
|
}
|
||||||
|
|
||||||
if (C->matcher() != NULL) {
|
if (C->matcher() != NULL) {
|
||||||
if (C->matcher()->is_shared(node)) {
|
if (C->matcher()->is_shared(node)) {
|
||||||
|
|
|
@ -548,6 +548,22 @@ void Block::needed_for_next_call(Node *this_call, VectorSet &next_call, Block_Ar
|
||||||
set_next_call(call, next_call, bbs);
|
set_next_call(call, next_call, bbs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------add_call_kills-------------------------------------
|
||||||
|
void Block::add_call_kills(MachProjNode *proj, RegMask& regs, const char* save_policy, bool exclude_soe) {
|
||||||
|
// Fill in the kill mask for the call
|
||||||
|
for( OptoReg::Name r = OptoReg::Name(0); r < _last_Mach_Reg; r=OptoReg::add(r,1) ) {
|
||||||
|
if( !regs.Member(r) ) { // Not already defined by the call
|
||||||
|
// Save-on-call register?
|
||||||
|
if ((save_policy[r] == 'C') ||
|
||||||
|
(save_policy[r] == 'A') ||
|
||||||
|
((save_policy[r] == 'E') && exclude_soe)) {
|
||||||
|
proj->_rout.Insert(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//------------------------------sched_call-------------------------------------
|
//------------------------------sched_call-------------------------------------
|
||||||
uint Block::sched_call( Matcher &matcher, Block_Array &bbs, uint node_cnt, Node_List &worklist, int *ready_cnt, MachCallNode *mcall, VectorSet &next_call ) {
|
uint Block::sched_call( Matcher &matcher, Block_Array &bbs, uint node_cnt, Node_List &worklist, int *ready_cnt, MachCallNode *mcall, VectorSet &next_call ) {
|
||||||
RegMask regs;
|
RegMask regs;
|
||||||
|
@ -631,17 +647,7 @@ uint Block::sched_call( Matcher &matcher, Block_Array &bbs, uint node_cnt, Node_
|
||||||
proj->_rout.OR(Matcher::method_handle_invoke_SP_save_mask());
|
proj->_rout.OR(Matcher::method_handle_invoke_SP_save_mask());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill in the kill mask for the call
|
add_call_kills(proj, regs, save_policy, exclude_soe);
|
||||||
for( OptoReg::Name r = OptoReg::Name(0); r < _last_Mach_Reg; r=OptoReg::add(r,1) ) {
|
|
||||||
if( !regs.Member(r) ) { // Not already defined by the call
|
|
||||||
// Save-on-call register?
|
|
||||||
if ((save_policy[r] == 'C') ||
|
|
||||||
(save_policy[r] == 'A') ||
|
|
||||||
((save_policy[r] == 'E') && exclude_soe)) {
|
|
||||||
proj->_rout.Insert(r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return node_cnt;
|
return node_cnt;
|
||||||
}
|
}
|
||||||
|
@ -776,6 +782,7 @@ bool Block::schedule_local(PhaseCFG *cfg, Matcher &matcher, int *ready_cnt, Vect
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
uint max_idx = matcher.C->unique();
|
||||||
// Pull from worklist and schedule
|
// Pull from worklist and schedule
|
||||||
while( worklist.size() ) { // Worklist is not ready
|
while( worklist.size() ) { // Worklist is not ready
|
||||||
|
|
||||||
|
@ -815,11 +822,28 @@ bool Block::schedule_local(PhaseCFG *cfg, Matcher &matcher, int *ready_cnt, Vect
|
||||||
phi_cnt = sched_call(matcher, cfg->_bbs, phi_cnt, worklist, ready_cnt, mcall, next_call);
|
phi_cnt = sched_call(matcher, cfg->_bbs, phi_cnt, worklist, ready_cnt, mcall, next_call);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (n->is_Mach() && n->as_Mach()->has_call()) {
|
||||||
|
RegMask regs;
|
||||||
|
regs.Insert(matcher.c_frame_pointer());
|
||||||
|
regs.OR(n->out_RegMask());
|
||||||
|
|
||||||
|
MachProjNode *proj = new (matcher.C, 1) MachProjNode( n, 1, RegMask::Empty, MachProjNode::fat_proj );
|
||||||
|
cfg->_bbs.map(proj->_idx,this);
|
||||||
|
_nodes.insert(phi_cnt++, proj);
|
||||||
|
|
||||||
|
add_call_kills(proj, regs, matcher._c_reg_save_policy, false);
|
||||||
|
}
|
||||||
|
|
||||||
// Children are now all ready
|
// Children are now all ready
|
||||||
for (DUIterator_Fast i5max, i5 = n->fast_outs(i5max); i5 < i5max; i5++) {
|
for (DUIterator_Fast i5max, i5 = n->fast_outs(i5max); i5 < i5max; i5++) {
|
||||||
Node* m = n->fast_out(i5); // Get user
|
Node* m = n->fast_out(i5); // Get user
|
||||||
if( cfg->_bbs[m->_idx] != this ) continue;
|
if( cfg->_bbs[m->_idx] != this ) continue;
|
||||||
if( m->is_Phi() ) continue;
|
if( m->is_Phi() ) continue;
|
||||||
|
if (m->_idx > max_idx) { // new node, skip it
|
||||||
|
assert(m->is_MachProj() && n->is_Mach() && n->as_Mach()->has_call(), "unexpected node types");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if( !--ready_cnt[m->_idx] )
|
if( !--ready_cnt[m->_idx] )
|
||||||
worklist.push(m);
|
worklist.push(m);
|
||||||
}
|
}
|
||||||
|
|
|
@ -190,6 +190,9 @@ public:
|
||||||
// Avoid back to back some instructions on some CPUs.
|
// Avoid back to back some instructions on some CPUs.
|
||||||
bool avoid_back_to_back() const { return (flags() & Flag_avoid_back_to_back) != 0; }
|
bool avoid_back_to_back() const { return (flags() & Flag_avoid_back_to_back) != 0; }
|
||||||
|
|
||||||
|
// instruction implemented with a call
|
||||||
|
bool has_call() const { return (flags() & Flag_has_call) != 0; }
|
||||||
|
|
||||||
// First index in _in[] corresponding to operand, or -1 if there is none
|
// First index in _in[] corresponding to operand, or -1 if there is none
|
||||||
int operand_index(uint operand) const;
|
int operand_index(uint operand) const;
|
||||||
|
|
||||||
|
|
|
@ -641,7 +641,8 @@ public:
|
||||||
Flag_is_dead_loop_safe = Flag_is_cisc_alternate << 1,
|
Flag_is_dead_loop_safe = Flag_is_cisc_alternate << 1,
|
||||||
Flag_may_be_short_branch = Flag_is_dead_loop_safe << 1,
|
Flag_may_be_short_branch = Flag_is_dead_loop_safe << 1,
|
||||||
Flag_avoid_back_to_back = Flag_may_be_short_branch << 1,
|
Flag_avoid_back_to_back = Flag_may_be_short_branch << 1,
|
||||||
_max_flags = (Flag_avoid_back_to_back << 1) - 1 // allow flags combination
|
Flag_has_call = Flag_avoid_back_to_back << 1,
|
||||||
|
_max_flags = (Flag_has_call << 1) - 1 // allow flags combination
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue