return NULL;
}
-static void abi_set_frame_entity(const void *_self, const ir_node *irn, entity *ent)
+static void abi_set_frame_entity(const void *_self, ir_node *irn, entity *ent)
{
}
* @param irn The node in question.
* @param ent The entity to set
*/
- void (*set_frame_entity)(const void *self, const ir_node *irn, entity *ent);
+ void (*set_frame_entity)(const void *self, ir_node *irn, entity *ent);
/**
* Set the offset of a node carrying an entity on the stack frame.
dump(BE_CH_DUMP_SPILL, irg, chordal_env.cls, "-spill", dump_ir_block_graph_sched);
- // commented out for now, since spillslot coalescer currently doesn't
- // detect memory as reloads
- //check_for_memory_operands(&chordal_env);
+ check_for_memory_operands(&chordal_env);
+
be_abi_fix_stack_nodes(bi->abi, chordal_env.lv);
BE_TIMER_PUSH(ra_timer.t_verify);
/* verify spillslots */
if (options.vrfy_option == BE_CH_VRFY_WARN) {
- be_verify_spillslots(irg);
+ be_verify_spillslots(main_env->arch_env, irg);
}
else if (options.vrfy_option == BE_CH_VRFY_ASSERT) {
- assert(be_verify_spillslots(irg) && "Spillslot verification failed");
+ assert(be_verify_spillslots(main_env->arch_env, irg) && "Spillslot verification failed");
}
BE_TIMER_POP(ra_timer.t_verify);
/* assure that branches and constants are executed last */
for (irn = nodeset_first(ready_set); irn; irn = nodeset_next(ready_set)) {
- arch_irn_class_t irn_class = arch_irn_classify(arch_env, irn);
-
if (! arch_irn_class_is(arch_env, irn, branch) && (const_last ? (! arch_irn_class_is(arch_env, irn, const)) : 1)) {
nodeset_break(ready_set);
return irn;
nodeset_insert(env->cands, irn);
- /* calculate the etime of this node */
- etime = env->curr_time;
- if (pred) {
- etime_p = get_irn_etime(env, pred);
- etime += latency(env->sched_env, pred, 1, irn, 0);
+ /* calculate the etime of this node */
+ etime = env->curr_time;
+ if (pred) {
+ etime_p = get_irn_etime(env, pred);
+ etime += latency(env->sched_env, pred, 1, irn, 0);
- etime = etime_p > etime ? etime_p : etime;
- }
+ etime = etime_p > etime ? etime_p : etime;
+ }
- set_irn_etime(env, irn, etime);
+ set_irn_etime(env, irn, etime);
DB((env->dbg, LEVEL_2, "\tmaking ready: %+F etime %u\n", irn, etime));
}
}
-entity *be_get_frame_entity(const ir_node *irn)
+entity* be_get_frame_entity(const ir_node *irn)
{
if(be_has_frame_entity(irn)) {
be_frame_attr_t *a = get_irn_attr(irn);
return NULL;
}
-void be_set_frame_entity(const ir_node *irn, entity* ent)
-{
- be_frame_attr_t *a;
-
- assert(be_has_frame_entity(irn));
-
- a = get_irn_attr(irn);
- a->ent = ent;
-}
-
void be_set_MemPerm_in_entity(const ir_node *irn, int n, entity *ent)
{
be_memperm_attr_t *attr = get_irn_attr(irn);
XXX(StackParam, stackparam);
#undef XXX
default:
- return 0;
+ return arch_irn_class_normal;
}
return 0;
return be_get_frame_entity(irn);
}
-static void be_node_set_frame_entity(const void *self, const ir_node *irn, entity *ent)
+static void be_node_set_frame_entity(const void *self, ir_node *irn, entity *ent)
{
- be_set_frame_entity(irn, ent);
+ be_frame_attr_t *a;
+
+ assert(be_has_frame_entity(irn));
+
+ a = get_irn_attr(irn);
+ a->ent = ent;
}
static void be_node_set_frame_offset(const void *self, ir_node *irn, int offset)
return NULL;
}
-static void phi_set_frame_entity(const void *_self, const ir_node *irn, entity *ent)
+static void phi_set_frame_entity(const void *_self, ir_node *irn, entity *ent)
{
}
int be_is_Barrier(const ir_node *irn);
/**
- * Get the entity on the stack frame the given node uses.
- * @param irn The node.
- * @return The entity on the stack frame used by the node or NULL,
- * if the node does not access the stack frame or is no back-end node.
+ * Try to avoid this function and better call arch_get_frame_entity!
*
+ * Returns the frame entity used by the be node
*/
-entity *be_get_frame_entity(const ir_node *irn);
-
-void be_set_frame_entity(const ir_node *irn, entity* ent);
+entity* be_get_frame_entity(const ir_node *irn);
ir_node* be_get_Reload_mem(const ir_node *irn);
ir_node* be_get_Reload_frame(const ir_node* irn);
#include "bejavacoal.h"
// only rematerialise when costs are less than REMAT_COST_LIMIT
-#define REMAT_COST_LIMIT 4
-
-/* This enables re-computation of values. Current state: Unfinished and buggy. */
-#undef BUGGY_REMAT
+// TODO determine a good value here...
+#define REMAT_COST_LIMIT 80
typedef struct _reloader_t reloader_t;
struct _spill_env_t {
const arch_register_class_t *cls;
+ const arch_env_t *arch_env;
const be_chordal_env_t *chordal_env;
struct obstack obst;
set *spills; /**< all spill_info_t's, which must be placed */
env->spills = new_set(cmp_spillinfo, 1024);
env->cls = chordal_env->cls;
env->chordal_env = chordal_env;
+ env->arch_env = env->chordal_env->birg->main_env->arch_env;
env->mem_phis = pset_new_ptr_default();
obstack_init(&env->obst);
return env;
reloader_t *rel;
assert(sched_is_scheduled(before));
- assert(arch_irn_consider_in_reg_alloc(env->chordal_env->birg->main_env->arch_env, env->cls, to_spill));
+ assert(arch_irn_consider_in_reg_alloc(env->arch_env, env->cls, to_spill));
info = get_spillinfo(env, to_spill);
* @return a be_Spill node
*/
static void spill_irn(spill_env_t *env, spill_info_t *spillinfo) {
- const be_main_env_t *mainenv = env->chordal_env->birg->main_env;
ir_node *to_spill = spillinfo->spilled_node;
DBG((env->dbg, LEVEL_1, "%+F\n", to_spill));
return;
}
- spillinfo->spill = be_spill(mainenv->arch_env, to_spill);
+ spillinfo->spill = be_spill(env->arch_env, to_spill);
sched_add_after_insn(to_spill, spillinfo->spill);
}
if(arg == get_irg_frame(env->chordal_env->irg))
return 1;
-#if 0
- /* we want to remat before the insn reloader
- * thus an arguments is alive if
- * - it interferes with the reloaders result
- * or
- * - or it is (last-) used by reloader itself
+ /* the following test does not work while spilling,
+ * because the liveness info is not adapted yet to the effects of the
+ * additional spills/reloads.
+ *
+ * So we can only do this test for ignore registers (of our register class)
*/
- int i, m;
-
- if (values_interfere(reloader, arg))
- return 1;
+ if(arch_get_irn_reg_class(env->arch_env, arg, -1) == env->chordal_env->cls
+ && arch_irn_is(env->arch_env, arg, ignore)) {
+ int i, arity;
- for (i=0, m=get_irn_arity(reloader); i<m; ++i) {
- ir_node *rel_arg = get_irn_n(reloader, i);
- if (rel_arg == arg)
+ /* we want to remat before the insn reloader
+ * thus an arguments is alive if
+ * - it interferes with the reloaders result
+ * - or it is (last-) used by reloader itself
+ */
+ if (values_interfere(env->chordal_env->lv, reloader, arg)) {
return 1;
- }
+ }
- /* arg is not alive before reloader */
- return 0;
-#endif
+ arity = get_irn_arity(reloader);
+ for (i = 0; i < arity; ++i) {
+ ir_node *rel_arg = get_irn_n(reloader, i);
+ if (rel_arg == arg)
+ return 1;
+ }
+ }
- return 0;
+ return 0;
}
/**
* Checks whether the node can principally be rematerialized
*/
static int is_remat_node(spill_env_t *env, ir_node *node) {
- const arch_env_t *arch_env = env->chordal_env->birg->main_env->arch_env;
+ const arch_env_t *arch_env = env->arch_env;
assert(!be_is_Spill(node));
if(be_is_Reload(spilled)) {
costs += 2;
- } else if(is_Proj(spilled)) {
- costs += 0;
} else {
- costs += 1;
+ costs += arch_get_op_estimated_cost(env->arch_env, spilled);
}
if(parentcosts + costs >= REMAT_COST_LIMIT)
return REMAT_COST_LIMIT;
*/
void be_insert_spills_reloads(spill_env_t *env) {
- const arch_env_t *arch_env = env->chordal_env->birg->main_env->arch_env;
+ const arch_env_t *arch_env = env->arch_env;
spill_info_t *si;
/* process each spilled node */
typedef struct _ss_env_t {
struct obstack obst;
+ const arch_env_t *arch_env;
const be_chordal_env_t *chordal_env;
set *spills;
ir_node **reloads;
* |_|
*/
-static spill_t *collect_spill(ss_env_t *env, ir_node *node, const arch_register_class_t *cls) {
+static ir_node *get_memory_edge(const ir_node *node) {
+ int i, arity;
+
+ arity = get_irn_arity(node);
+ for(i = arity - 1; i >= 0; --i) {
+ ir_node *arg = get_irn_n(node, i);
+ if(get_irn_mode(arg) == mode_M)
+ return arg;
+ }
+
+ return NULL;
+}
+
+static spill_t *collect_spill(ss_env_t *env, ir_node *node) {
+ const arch_env_t *arch_env = env->arch_env;
+ const arch_register_class_t *cls;
spill_t spill, *res;
int hash = HASH_PTR(node);
- assert(be_is_Spill(node));
+ assert(arch_irn_class_is(arch_env, node, spill));
+
+ if(be_is_Spill(node)) {
+ cls = arch_get_irn_reg_class(arch_env, node, be_pos_Spill_val);
+ } else {
+ // TODO add a way to detect the type of the spilled value
+ assert(0);
+ }
spill.spill = node;
res = set_find(env->spills, &spill, sizeof(spill), hash);
spill.spillslot = set_count(env->spills);
spill.cls = cls;
res = set_insert(env->spills, &spill, sizeof(spill), hash);
- } else {
- assert(cls == res->cls);
}
return res;
}
-static spill_t *collect_memphi(ss_env_t *env, ir_node *node, const arch_register_class_t *cls) {
+static spill_t *collect_memphi(ss_env_t *env, ir_node *node) {
int i, arity;
spill_t spill, *res;
int hash = HASH_PTR(node);
}
spill.spillslot = set_count(env->spills);
- spill.cls = cls;
+ spill.cls = NULL;
res = set_insert(env->spills, &spill, sizeof(spill), hash);
// is 1 of the arguments a spill?
spill_t* arg_spill;
if(be_is_Spill(arg)) {
- arg_spill = collect_spill(env, arg, cls);
+ arg_spill = collect_spill(env, arg);
} else {
// if it wasn't a spill then it must be a Mem-Phi
assert(is_Phi(arg));
- arg_spill = collect_memphi(env, arg, cls);
+ arg_spill = collect_memphi(env, arg);
+ }
+
+ if(i == 0) {
+ res->cls = arg_spill->cls;
+ } else {
+ assert(res->cls == arg_spill->cls);
}
// add an affinity edge
*/
static void collect_spills_walker(ir_node *node, void *data) {
ss_env_t *env = data;
+ const arch_env_t *arch_env = env->arch_env;
+
+ // @@@ ia32 classify returns classification of the irn the proj is attached
+ // too, why oh why?...
+ if(is_Proj(node))
+ return;
+
+ if(arch_irn_class_is(arch_env, node, reload)) {
+ ir_node *spillnode = get_memory_edge(node);
+ spill_t *spill;
- if(be_is_Reload(node)) {
- ir_node *spill = get_irn_n(node, be_pos_Reload_mem);
- const arch_env_t *arch_env = env->chordal_env->birg->main_env->arch_env;
- const arch_register_class_t *cls = arch_get_irn_reg_class(arch_env, node, -1);
+ assert(spill != NULL);
- if(is_Phi(spill)) {
- collect_memphi(env, spill, cls);
+ if(is_Phi(spillnode)) {
+ spill = collect_memphi(env, spillnode);
} else {
- collect_spill(env, spill, cls);
+ spill = collect_spill(env, spillnode);
}
+
+ assert(!be_is_Reload(node) || spill->cls == arch_get_irn_reg_class(arch_env, node, -1));
ARR_APP1(ir_node*, env->reloads, node);
}
}
}
}
- // assign spillslots
+ // assign spillslots to spills
for(i = 0; i < spillcount; ++i) {
spill_t *spill = spilllist[i];
* reload nodes.
*/
static void assign_spillslots(ss_env_t *env) {
+ const arch_env_t *arch_env = env->arch_env;
int i;
int spillcount;
spill_t *spill;
create_stack_entity(env, slot);
}
- if(be_is_Spill(node)) {
- be_set_frame_entity(node, slot->entity);
- } else {
+ if(is_Phi(node)) {
int i, arity;
ir_node *block = get_nodes_block(node);
memperm->entries = entry;
}
}
+ } else {
+ assert(arch_irn_class_is(arch_env, node, spill));
+ arch_set_frame_entity(arch_env, node, slot->entity);
}
}
for(i = 0; i < ARR_LEN(env->reloads); ++i) {
- const ir_node* reload = env->reloads[i];
- ir_node* spillnode = get_irn_n(reload, be_pos_Reload_mem);
+ ir_node* reload = env->reloads[i];
+ ir_node* spillnode = get_memory_edge(reload);
spill_t *spill = get_spill(env, spillnode);
const spill_slot_t *slot = & spillslots[spill->spillslot];
assert(slot->entity != NULL);
- be_set_frame_entity(reload, slot->entity);
+ arch_set_frame_entity(arch_env, reload, slot->entity);
}
}
ss_env_t env;
obstack_init(&env.obst);
+ env.arch_env = chordal_env->birg->main_env->arch_env;
env.chordal_env = chordal_env;
env.spills = new_set(cmp_spill, 10);
env.reloads = NEW_ARR_F(ir_node*, 0);
} spill_t;
typedef struct {
- be_lv_t *lv;
+ const arch_env_t *arch_env;
ir_graph *irg;
set *spills;
ir_node **reloads;
return res;
}
+static ir_node *get_memory_edge(const ir_node *node) {
+ int i, arity;
+ ir_node *result = NULL;
+
+ arity = get_irn_arity(node);
+ for(i = arity - 1; i >= 0; --i) {
+ ir_node *arg = get_irn_n(node, i);
+ if(get_irn_mode(arg) == mode_M) {
+ assert(result == NULL);
+ result = arg;
+ }
+ }
+
+ return result;
+}
+
static void collect(be_verify_spillslots_env_t *env, ir_node *node, ir_node *reload, entity* ent);
static void check_entity(be_verify_spillslots_env_t *env, ir_node *node, entity *ent) {
}
static void collect_spill(be_verify_spillslots_env_t *env, ir_node *node, ir_node *reload, entity* ent) {
- entity *spillent = be_get_frame_entity(node);
+ entity *spillent = arch_get_frame_entity(env->arch_env, node);
check_entity(env, node, spillent);
get_spill(env, node, ent);
*/
static void collect_spills_walker(ir_node *node, void *data) {
be_verify_spillslots_env_t *env = data;
+ const arch_env_t *arch_env = env->arch_env;
- if(be_is_Reload(node)) {
- ir_node *spill = get_irn_n(node, be_pos_Reload_mem);
- entity* ent = be_get_frame_entity(node);
+ // @@@ ia32_classify returns classification of Proj_pred :-/
+ if(is_Proj(node))
+ return;
+
+ if(arch_irn_class_is(arch_env, node, reload)) {
+ ir_node *spill = get_memory_edge(node);
+ if(spill == NULL) {
+ ir_fprintf(stderr, "Verify warning: No spill attached to reload %+F in block %+F(%s)\n",
+ node, get_nodes_block(node), get_irg_dump_name(env->irg));
+ env->problem_found = 1;
+ return;
+ }
+ entity* ent = arch_get_frame_entity(env->arch_env, node);
check_entity(env, node, ent);
collect(env, spill, node, ent);
sp2->spill, get_nodes_block(sp2->spill), get_irg_dump_name(env->irg));
env->problem_found = 1;
my_values_interfere(sp1->spill, sp2->spill);
- printf("Intf: %d\n", values_interfere(env->lv, sp1->spill, sp2->spill));
}
}
}
if(be_is_Spill(node) || (is_Proj(node) && be_is_MemPerm(get_Proj_pred(node)))) {
spill_t *spill = find_spill(env, node);
if(be_is_Spill(node)) {
- entity *ent = be_get_frame_entity(node);
+ entity *ent = arch_get_frame_entity(env->arch_env, node);
check_entity(env, node, ent);
}
}
}
-int be_verify_spillslots(ir_graph *irg)
+int be_verify_spillslots(const arch_env_t *arch_env, ir_graph *irg)
{
be_verify_spillslots_env_t env;
+ env.arch_env = arch_env;
env.irg = irg;
env.spills = new_set(cmp_spill, 10);
env.reloads = NEW_ARR_F(ir_node*, 0);
env.problem_found = 0;
- env.lv = be_liveness(irg);
irg_walk_graph(irg, collect_spills_walker, NULL, &env);
irg_walk_graph(irg, check_lonely_spills, NULL, &env);
check_spillslot_interference(&env);
- be_liveness_free(env.lv);
DEL_ARR_F(env.reloads);
del_set(env.spills);
* @param irg The irg to check
* @return 1 if spillslots are valid, 0 otherwise
*/
-int be_verify_spillslots(ir_graph *irg);
+int be_verify_spillslots(const arch_env_t *arch_env, ir_graph *irg);
/**
* Verify register allocation: Checks that no 2 live nodes have the same
return is_ia32_irn(irn) ? get_ia32_frame_ent(irn) : NULL;
}
-static void ia32_set_frame_entity(const void *self, const ir_node *irn, entity *ent) {
+static void ia32_set_frame_entity(const void *self, ir_node *irn, entity *ent) {
set_ia32_frame_ent(irn, ent);
}
*/
static void transform_to_Load(ia32_transform_env_t *env) {
ir_node *irn = env->irn;
- entity *ent = be_get_frame_entity(irn);
+ entity *ent = arch_get_frame_entity(env->cg->arch_env, irn);
ir_mode *mode = env->mode;
ir_node *noreg = ia32_new_NoReg_gp(env->cg);
ir_node *nomem = new_rd_NoMem(env->irg);
*/
static void transform_to_Store(ia32_transform_env_t *env) {
ir_node *irn = env->irn;
- entity *ent = be_get_frame_entity(irn);
+ entity *ent = arch_get_frame_entity(env->cg->arch_env, irn);
ir_mode *mode = env->mode;
ir_node *noreg = ia32_new_NoReg_gp(env->cg);
ir_node *nomem = new_rd_NoMem(env->irg);
ir_node *noreg = ia32_new_NoReg_gp(env->cg);
ir_node *mem = new_rd_NoMem(env->irg);
ir_node *ptr = get_irn_n(node, 0);
- entity *ent = be_get_frame_entity(node);
+ entity *ent = arch_get_frame_entity(env->cg->arch_env, node);
ir_mode *mode = env->mode;
/* choose the block where to place the load */
set_ia32_op_type(new_op, ia32_AddrModeS);
set_ia32_am_flavour(new_op, ia32_B);
set_ia32_ls_mode(new_op, mode);
+ set_ia32_flags(new_op, get_ia32_flags(new_op) | arch_irn_flags_rematerializable);
SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, env->irn));
ir_node *nomem = new_rd_NoMem(env->irg);
new_op = new_rd_ia32_Add(env->dbg, env->irg, env->block, noreg, noreg, op, noreg, nomem);
- set_ia32_frame_ent(new_op, be_get_frame_entity(node));
+ set_ia32_frame_ent(new_op, arch_get_frame_entity(env->cg->arch_env, node));
set_ia32_am_support(new_op, ia32_am_Full);
set_ia32_use_frame(new_op);
set_ia32_immop_type(new_op, ia32_ImmConst);
ir_node *noreg = ia32_new_NoReg_gp(env->cg);
ir_node *mem = get_irn_n(node, 0);
ir_node *ptr = get_irn_n(node, 1);
- entity *ent = be_get_frame_entity(node);
+ entity *ent = arch_get_frame_entity(env->cg->arch_env, node);
ir_mode *mode = get_type_mode(get_entity_type(ent));
if (mode_is_float(mode)) {
ir_node *mem = get_irn_n(node, 0);
ir_node *ptr = get_irn_n(node, 1);
ir_node *val = get_irn_n(node, 2);
- entity *ent = be_get_frame_entity(node);
+ entity *ent = arch_get_frame_entity(env->cg->arch_env, node);
ir_mode *mode = get_irn_mode(val);
if (mode_is_float(mode)) {
return NULL;
}
-static void mips_set_frame_entity(const void *self, const ir_node *irn, entity *ent) {
+static void mips_set_frame_entity(const void *self, ir_node *irn, entity *ent) {
mips_attr_t *attr = get_mips_attr(irn);
assert(is_mips_load_r(irn) || is_mips_store_r(irn));
attr->stack_entity = ent;
@test -z $(RESDIR) || mkdir -p $(RESDIR)
diff -u gcc/$*.result firm/$*.result || echo "$*.c" >> $(RESDIR)/compare_failed.txt
+gcc/%.s: %.c
+ @test -z gcc || mkdir -p gcc
+ @test -z $(RESDIR) || mkdir -p $(RESDIR)
+ $(GCC) -c -S $(GCC_CFLAGS) $*.c -o $@
+
gcc/%.exe: %.c
@test -z gcc || mkdir -p gcc
@test -z $(RESDIR) || mkdir -p $(RESDIR)
@test -z firm || mkdir -p firm
@test -z $(RESDIR) || mkdir -p $(RESDIR)
cd firm ; $(EDG) $(EDG_CFLAGS) ../$*.c || echo "$*.c" >> ../$(RESDIR)/compile_failed.txt
- mv $*.s firm || echo "" > firm/$*.s
+ mv $*.s firm
firm/%.exe: firm/%.s
@test -z $(RESDIR) || mkdir -p $(RESDIR)
+#include <stdio.h>
+
static int test(int a, int i)
{
- a &= ~(1 << (i & 0x0000001F));
- return a;
+ a &= ~(1 << (i & 0x0000001F));
+ return a;
}
int A = 15;
int main()
{
- printf("test(%d, %d) = %d\n", A, I, test(A,I));
+ printf("test(%d, %d) = %d\n", A, I, test(A,I));
return 0;
}