}
static arch_irn_flags_t ia32_get_flags(const void *self, const ir_node *irn) {
+ arch_irn_flags_t flags = arch_irn_flags_none;
- if(is_Proj(irn)) {
- ir_node *pred = get_Proj_pred(irn);
- int ia32_op = get_ia32_irn_opcode(pred);
- long proj = get_Proj_proj(irn);
- if (iro_ia32_Push == ia32_op && proj == pn_ia32_Push_stack) {
- /* Push modifies always ESP, this cannot be changed */
- return arch_irn_flags_modify_sp | arch_irn_flags_ignore;
- }
- if (iro_ia32_Pop == ia32_op && proj == pn_ia32_Pop_stack) {
- /* Pop modifies always ESP, this cannot be changed */
- return arch_irn_flags_modify_sp | arch_irn_flags_ignore;
- }
- if (iro_ia32_AddSP == ia32_op && proj == pn_ia32_AddSP_stack) {
- /* AddSP modifies always ESP, this cannot be changed */
- return arch_irn_flags_modify_sp | arch_irn_flags_ignore;
- }
- if (iro_ia32_SubSP == ia32_op && proj == pn_ia32_SubSP_stack) {
- /* SubSP modifies always ESP, this cannot be changed */
- return arch_irn_flags_modify_sp | arch_irn_flags_ignore;
- }
+ if (is_Proj(irn) && is_ia32_irn(get_Proj_pred(irn))) {
+ flags |= get_ia32_out_flags(irn, get_Proj_proj(irn));
}
irn = skip_Proj(irn);
if (is_ia32_irn(irn))
- return get_ia32_flags(irn);
- else {
- if (is_Unknown(irn))
- return arch_irn_flags_ignore;
- return 0;
- }
+ flags |= get_ia32_flags(irn);
+ else if (is_Unknown(irn))
+ flags = arch_irn_flags_ignore;
+
+ return flags;
}
/**
attr->pn_code = code;
}
+/**
+ * Sets the flags for the n'th out.
+ */
+void set_ia32_out_flags(ir_node *node, arch_irn_flags_t flags, int pos) {
+ ia32_attr_t *attr = get_ia32_attr(node);
+ assert(pos < (int) attr->data.n_res && "Invalid OUT position.");
+ attr->out_flags[pos] = flags;
+}
+
+/**
+ * Gets the flags for the n'th out.
+ */
+arch_irn_flags_t get_ia32_out_flags(const ir_node *node, int pos) {
+ ia32_attr_t *attr = get_ia32_attr(node);
+ assert(pos < (int) attr->data.n_res && "Invalid OUT position.");
+ return attr->out_flags[pos];
+}
+
#ifndef NDEBUG
/**
const char *get_ia32_out_reg_name(const ir_node *node, int pos) {
ia32_attr_t *attr = get_ia32_attr(node);
- assert(is_ia32_irn(node) && "Not an ia32 node.");
assert(pos < (int) attr->data.n_res && "Invalid OUT position.");
assert(attr->slots[pos] && "No register assigned");
int get_ia32_out_regnr(const ir_node *node, int pos) {
ia32_attr_t *attr = get_ia32_attr(node);
- assert(is_ia32_irn(node) && "Not an ia32 node.");
assert(pos < (int) attr->data.n_res && "Invalid OUT position.");
assert(attr->slots[pos] && "No register assigned");
const arch_register_t *get_ia32_out_reg(const ir_node *node, int pos) {
ia32_attr_t *attr = get_ia32_attr(node);
- assert(is_ia32_irn(node) && "Not an ia32 node.");
assert(pos < (int) attr->data.n_res && "Invalid OUT position.");
assert(attr->slots[pos] && "No register assigned");
set_ia32_out_req_all(node, out_reqs);
set_ia32_latency(node, latency);
+ attr->out_flags = NEW_ARR_D(int, get_irg_obstack(get_irn_irg(node)), n_res);
+ memset(attr->out_flags, 0, n_res * sizeof(attr->out_flags[0]));
+
attr->data.n_res = n_res;
memset((void *)attr->slots, 0, n_res * sizeof(attr->slots[0]));
}
*/
void set_ia32_latency(ir_node *node, unsigned latency);
+
+/**
+ * Sets the flags for the n'th out.
+ */
+void set_ia32_out_flags(ir_node *node, arch_irn_flags_t flags, int pos);
+
+/**
+ * Gets the flags for the n'th out.
+ */
+arch_irn_flags_t get_ia32_out_flags(const ir_node *node, int pos);
+
#ifndef NDEBUG
/**
unsigned op_flav:2; /**< flavour of an op (flavour_Div/Mod/DivMod) */
- unsigned flags:4; /**< indicating if spillable and/or rematerializeable */
+ unsigned flags:4; /**< indicating if spillable, rematerializeable, stack modifying and/or ignore */
unsigned is_commutative:1; /**< indicates whether op is commutative or not */
unsigned n_res:6; /**< number of results produced by this node */
} data;
+ int *out_flags; /**< flags for each produced value */
+
int am_offs; /**< offsets for AddrMode */
ident *am_sc; /**< SymConst for AddrMode */
#
# outs: if a node defines more than one output, the names of the projections
# nodes having outs having automatically the mode mode_T
+# One can also annotate some flags for each out, additional to irn_flags.
+# They are separated from name with a colon ':', and concatenated by pipe '|'
+# Only I and S are available at the moment (same meaning as in irn_flags).
+# example: [ "frame:I", "stack:I|S", "M" ]
#
# comment: OPTIONAL comment for the node constructor
#
},
"Push" => {
- # We don't set class modify_stack here (but we will do this on proj 0)
"comment" => "push on the stack",
"reg_req" => { "in" => [ "gp", "gp", "gp", "esp", "none" ], "out" => [ "esp" ] },
"emit" => '. push %ia32_emit_unop /* PUSH(%A1) */',
- "outs" => [ "stack", "M" ],
+ "outs" => [ "stack:I|S", "M" ],
"latency" => 3,
},
"comment" => "pop a gp register from the stack",
"reg_req" => { "in" => [ "gp", "gp", "esp", "none" ], "out" => [ "gp", "esp" ] },
"emit" => '. pop %ia32_emit_unop /* POP(%A1) */',
- "outs" => [ "res", "stack", "M" ],
+ "outs" => [ "res", "stack:I|S", "M" ],
"latency" => 4,
},
"comment" => "create stack frame",
"reg_req" => { "in" => [ "esp" ], "out" => [ "ebp", "esp" ] },
"emit" => '. enter /* Enter */',
- "outs" => [ "frame", "stack", "M" ],
+ "outs" => [ "frame:I", "stack:I|S", "M" ],
"latency" => 15,
},
"comment" => "destroy stack frame",
"reg_req" => { "in" => [ "esp", "ebp" ], "out" => [ "ebp", "esp" ] },
"emit" => '. leave /* Leave */',
- "outs" => [ "frame", "stack", "M" ],
+ "outs" => [ "frame:I", "stack:I|S", "M" ],
"latency" => 3,
},
"irn_flags" => "I",
"comment" => "allocate space on stack",
"reg_req" => { "in" => [ "esp", "gp" ], "out" => [ "esp", "none" ] },
- "outs" => [ "stack", "M" ],
+ "outs" => [ "stack:S", "M" ],
},
"SubSP" => {
"irn_flags" => "I",
"comment" => "free space on stack",
"reg_req" => { "in" => [ "esp", "gp" ], "out" => [ "esp", "none" ] },
- "outs" => [ "stack", "M" ],
+ "outs" => [ "stack:S", "M" ],
},
"LdTls" => {
push(@obst_enum_op, "typedef enum _$arch\_opcodes {\n");
foreach my $op (keys(%nodes)) {
- my %n = %{ $nodes{"$op"} };
- my $tuple = 0;
- my $n_res = 0;
+ my %n = %{ $nodes{"$op"} };
+ my $tuple = 0;
+ my $n_res = 0;
+ my $num_outs = 0;
+ my @out_flags;
# determine arity from in requirements
$arity = exists($n{"arity"}) ? $n{"arity"} : 0;
$op = $arch."_".$op;
$temp = "";
+ # define some proj numbers
if (exists($n{"outs"})) {
undef my @outs;
- @outs = @{ $n{"outs"} };
+
+ @outs = @{ $n{"outs"} };
+ $num_outs = $#outs;
+
push(@obst_proj, "\nenum pn_$op {\n");
+
for (my $idx = 0; $idx <= $#outs; $idx++) {
+ # check, if we have additional flags annotated to out
+ if ($outs[$idx] =~ /:(S|I(\|(S|I))*)/) {
+ push(@out_flags, $1);
+ $outs[$idx] =~ s/:(S|I(\|(S|I))*)//;
+ }
push(@obst_proj, " pn_$op\_".$outs[$idx]." = $idx,\n");
}
+
push(@obst_proj, "};\n");
$tuple = 1;
}
$temp .= "\n /* init node attributes */\n";
$temp .= " init_$arch\_attributes(res, flags, $in_param, $out_param, $latency);\n";
+ # set flags for outs
+ if ($#out_flags >= 0) {
+ $temp .= "\n /* set flags for outs */\n";
+ for (my $idx = 0; $idx <= $#out_flags; $idx++) {
+ my $flags = "";
+ my $prefix = "";
+
+ foreach my $flag (split(/\|/, $out_flags[$idx])) {
+ if ($flag eq "I") {
+ $flags .= $prefix."arch_irn_flags_ignore";
+ $prefix = " | ";
+ }
+ elsif ($flag eq "S") {
+ $flags .= $prefix."arch_irn_flags_modify_sp";
+ $prefix = " | ";
+ }
+ }
+
+ $temp .= " set_$arch\_out_flags(res, $flags, $idx);\n";
+ }
+ }
+
+
if (exists($n{"init_attr"})) {
$temp .= " attr = get_$arch\_attr(res);\n";
$temp .= $n{"init_attr"}."\n";