#include <libcore/lc_opts_enum.h>
#endif /* WITH_LIBCORE */
+#include <math.h>
+
#include "pseudo_irg.h"
#include "irgwalk.h"
#include "irprog.h"
#include "../belower.h"
#include "../besched_t.h"
#include "../be.h"
+#include "../be_t.h"
#include "bearch_ia32_t.h"
#include "ia32_new_nodes.h" /* ia32 nodes interface */
}
static arch_irn_class_t ia32_classify(const void *self, const ir_node *irn) {
+ arch_irn_class_t classification = arch_irn_class_normal;
+
irn = my_skip_proj(irn);
+
if (is_cfop(irn))
- return arch_irn_class_branch;
- else if (is_ia32_Cnst(irn))
- return arch_irn_class_const;
- else if (is_ia32_Ld(irn))
- return arch_irn_class_load;
- else if (is_ia32_St(irn) || is_ia32_Store8Bit(irn))
- return arch_irn_class_store;
- else if (is_ia32_irn(irn))
- return arch_irn_class_normal;
- else
- return 0;
+ classification |= arch_irn_class_branch;
+
+ if (! is_ia32_irn(irn))
+ return classification & ~arch_irn_class_normal;
+
+ if (is_ia32_Cnst(irn))
+ classification |= arch_irn_class_const;
+
+ if (is_ia32_Ld(irn))
+ classification |= arch_irn_class_load;
+
+ if (is_ia32_St(irn) || is_ia32_Store8Bit(irn))
+ classification |= arch_irn_class_store;
+
+ if (is_ia32_got_reload(irn))
+ classification |= arch_irn_class_reload;
+
+ return classification;
}
static arch_irn_flags_t ia32_get_flags(const void *self, const ir_node *irn) {
+
+ if(is_Proj(irn)) {
+ ir_node *pred = get_Proj_pred(irn);
+ if(is_ia32_Push(pred) && get_Proj_proj(irn) == pn_ia32_Push_stack) {
+ return arch_irn_flags_modify_sp;
+ }
+ if(is_ia32_Pop(pred) && get_Proj_proj(irn) == pn_ia32_Pop_stack) {
+ return arch_irn_flags_modify_sp;
+ }
+ if(is_ia32_AddSP(pred) && get_Proj_proj(irn) == pn_ia32_AddSP_stack) {
+ return arch_irn_flags_modify_sp;
+ }
+ }
+
irn = my_skip_proj(irn);
if (is_ia32_irn(irn))
return get_ia32_flags(irn);
return is_ia32_irn(irn) ? get_ia32_frame_ent(irn) : NULL;
}
-static void ia32_set_stack_bias(const void *self, ir_node *irn, int bias) {
+static void ia32_set_frame_entity(const void *self, ir_node *irn, entity *ent) {
+ set_ia32_frame_ent(irn, ent);
+}
+
+static void ia32_set_frame_offset(const void *self, ir_node *irn, int bias) {
char buf[64];
const ia32_irn_ops_t *ops = self;
if (get_ia32_frame_ent(irn)) {
ia32_am_flavour_t am_flav = get_ia32_am_flavour(irn);
+ /* Pop nodes modify the stack pointer before reading the destination
+ * address, so fix this here
+ */
+ if(is_ia32_Pop(irn)) {
+ bias -= 4;
+ }
+
DBG((ops->cg->mod, LEVEL_1, "stack biased %+F with %d\n", irn, bias));
+
snprintf(buf, sizeof(buf), "%d", bias);
if (get_ia32_op_type(irn) == ia32_Normal) {
}
}
+static int ia32_get_sp_bias(const void *self, const ir_node *irn) {
+ if(is_Proj(irn)) {
+ int proj = get_Proj_proj(irn);
+ ir_node *pred = get_Proj_pred(irn);
+
+ if(is_ia32_Push(pred) && proj == 0)
+ return 4;
+ else if(is_ia32_Pop(pred) && proj == 1)
+ return -4;
+ }
+
+ return 0;
+}
+
typedef struct {
be_abi_call_flags_bits_t flags;
const arch_isa_t *isa;
*/
static const arch_register_t *ia32_abi_prologue(void *self, ir_node **mem, pmap *reg_map)
{
- ia32_abi_env_t *env = self;
+ ia32_abi_env_t *env = self;
- if (!env->flags.try_omit_fp) {
- ir_node *bl = get_irg_start_block(env->irg);
- ir_node *curr_sp = be_abi_reg_map_get(reg_map, env->isa->sp);
- ir_node *curr_bp = be_abi_reg_map_get(reg_map, env->isa->bp);
+ if (! env->flags.try_omit_fp) {
+ ir_node *bl = get_irg_start_block(env->irg);
+ ir_node *curr_sp = be_abi_reg_map_get(reg_map, env->isa->sp);
+ ir_node *curr_bp = be_abi_reg_map_get(reg_map, env->isa->bp);
ir_node *push;
/* push ebp */
*/
static void ia32_abi_epilogue(void *self, ir_node *bl, ir_node **mem, pmap *reg_map)
{
- ia32_abi_env_t *env = self;
- ir_node *curr_sp = be_abi_reg_map_get(reg_map, env->isa->sp);
- ir_node *curr_bp = be_abi_reg_map_get(reg_map, env->isa->bp);
+ ia32_abi_env_t *env = self;
+ ir_node *curr_sp = be_abi_reg_map_get(reg_map, env->isa->sp);
+ ir_node *curr_bp = be_abi_reg_map_get(reg_map, env->isa->bp);
if (env->flags.try_omit_fp) {
/* simply remove the stack frame here */
- curr_sp = be_new_IncSP(env->isa->sp, env->irg, bl, curr_sp, *mem, BE_STACK_FRAME_SIZE, be_stack_dir_shrink);
+ curr_sp = be_new_IncSP(env->isa->sp, env->irg, bl, curr_sp, BE_STACK_FRAME_SIZE_SHRINK);
+ add_irn_dep(curr_sp, *mem);
}
else {
- const ia32_isa_t *isa = (ia32_isa_t *)env->isa;
- ir_mode *mode_bp = env->isa->bp->reg_class->mode;
+ const ia32_isa_t *isa = (ia32_isa_t *)env->isa;
+ ir_mode *mode_bp = env->isa->bp->reg_class->mode;
/* gcc always emits a leave at the end of a routine */
if (1 || ARCH_AMD(isa->opt_arch)) {
ir_node *leave;
/* leave */
- leave = new_rd_ia32_Leave(NULL, env->irg, bl, curr_sp, *mem);
+ leave = new_rd_ia32_Leave(NULL, env->irg, bl, curr_sp, curr_bp);
set_ia32_flags(leave, arch_irn_flags_ignore);
curr_bp = new_r_Proj(current_ir_graph, bl, leave, mode_bp, pn_ia32_Leave_frame);
curr_sp = new_r_Proj(current_ir_graph, bl, leave, get_irn_mode(curr_sp), pn_ia32_Leave_stack);
curr_sp = be_new_SetSP(env->isa->sp, env->irg, bl, curr_sp, curr_bp, *mem);
/* pop ebp */
- pop = new_rd_ia32_Pop(NULL, env->irg, bl, curr_sp, *mem);
+ pop = new_rd_ia32_Pop(NULL, env->irg, bl, curr_sp, *mem);
set_ia32_flags(pop, arch_irn_flags_ignore);
curr_bp = new_r_Proj(current_ir_graph, bl, pop, mode_bp, pn_ia32_Pop_res);
curr_sp = new_r_Proj(current_ir_graph, bl, pop, get_irn_mode(curr_sp), pn_ia32_Pop_stack);
static int ia32_get_op_estimated_cost(const void *self, const ir_node *irn)
{
int cost;
+ ia32_op_type_t op_tp;
+ const ia32_irn_ops_t *ops = self;
- if(is_Proj(irn))
+ if (is_Proj(irn))
return 0;
- switch (get_ia32_irn_opcode(irn)) {
- case iro_ia32_xDiv:
- case iro_ia32_DivMod:
- cost = 8;
- break;
-
- case iro_ia32_xLoad:
- case iro_ia32_l_Load:
- case iro_ia32_Load:
- cost = 25;
- break;
-
- case iro_ia32_Push:
- case iro_ia32_Pop:
- cost = 5;
- break;
-
- case iro_ia32_xStore:
- case iro_ia32_l_Store:
- case iro_ia32_Store:
- case iro_ia32_Store8Bit:
- cost = 50;
- break;
-
- case iro_ia32_MulS:
- case iro_ia32_Mul:
- case iro_ia32_Mulh:
- case iro_ia32_xMul:
- case iro_ia32_l_MulS:
- case iro_ia32_l_Mul:
- cost = 2;
- break;
-
- default:
- cost = 1;
+ assert(is_ia32_irn(irn));
+
+ cost = get_ia32_latency(irn);
+ op_tp = get_ia32_op_type(irn);
+
+ if (is_ia32_CopyB(irn)) {
+ cost = 250;
+ if (ARCH_INTEL(ops->cg->arch))
+ cost += 150;
+ }
+ else if (is_ia32_CopyB_i(irn)) {
+ int size = get_tarval_long(get_ia32_Immop_tarval(irn));
+ cost = 20 + (int)ceil((4/3) * size);
+ if (ARCH_INTEL(ops->cg->arch))
+ cost += 150;
+ }
+ /* in case of address mode operations add additional cycles */
+ else if (op_tp == ia32_AddrModeD || op_tp == ia32_AddrModeS) {
+ /*
+ In case of stack access add 5 cycles (we assume stack is in cache),
+ other memory operations cost 20 cycles.
+ */
+ cost += is_ia32_use_frame(irn) ? 5 : 20;
}
return cost;
get_irn_arity(irn) != 5 || /* must be a binary operation */
get_ia32_op_type(irn) != ia32_Normal || /* must not already be a addressmode irn */
! (get_ia32_am_support(irn) & ia32_am_Source) || /* must be capable of source addressmode */
- (i != 2 && i != 3) || /* a "real" operand position must be requested */
+ (i != 2 && i != 3) || /* a "real" operand position must be requested */
(i == 2 && ! is_ia32_commutative(irn)) || /* if first operand requested irn must be commutative */
is_ia32_use_frame(irn)) /* must not already use frame */
return 0;
return 1;
}
-static void ia32_perform_memory_operand(const void *self, ir_node *irn, ir_node *reload, unsigned int i) {
+static void ia32_perform_memory_operand(const void *self, ir_node *irn, ir_node *spill, unsigned int i) {
assert(ia32_possible_memory_operand(self, irn, i) && "Cannot perform memory operand change");
- assert(get_nodes_block(reload) == get_nodes_block(irn) && "Reload must be in same block as irn.");
-
- if (get_irn_n_edges(reload) > 1)
- return;
if (i == 2) {
ir_node *tmp = get_irn_n(irn, 3);
set_ia32_am_support(irn, ia32_am_Source);
set_ia32_op_type(irn, ia32_AddrModeS);
set_ia32_am_flavour(irn, ia32_B);
- set_ia32_ls_mode(irn, get_irn_mode(reload));
- set_ia32_frame_ent(irn, be_get_frame_entity(reload));
+ set_ia32_ls_mode(irn, get_irn_mode(get_irn_n(irn, i)));
+ //TODO this will fail, if spill is a PhiM (give PhiMs entities?)
+ set_ia32_frame_ent(irn, be_get_frame_entity(spill));
set_ia32_use_frame(irn);
+ set_ia32_got_reload(irn);
- set_irn_n(irn, 0, be_get_Reload_frame(reload));
- set_irn_n(irn, 4, be_get_Reload_mem(reload));
+ set_irn_n(irn, 0, get_irg_frame(get_irn_irg(irn)));
+ set_irn_n(irn, 4, spill);
/*
Input at position one is index register, which is NoReg.
*/
set_irn_n(irn, 3, get_irn_n(irn, 1));
- DBG_OPT_AM_S(reload, irn);
+ //FIXME DBG_OPT_AM_S(reload, irn);
}
static const be_abi_callbacks_t ia32_abi_callbacks = {
ia32_classify,
ia32_get_flags,
ia32_get_frame_entity,
- ia32_set_stack_bias,
+ ia32_set_frame_entity,
+ ia32_set_frame_offset,
+ ia32_get_sp_bias,
ia32_get_inverse,
ia32_get_op_estimated_cost,
ia32_possible_memory_operand,
* |___/
**************************************************/
+static void ia32_kill_convs(ia32_code_gen_t *cg) {
+ ir_node *irn;
+
+ /* BEWARE: the Projs are inserted in the set */
+ foreach_nodeset(cg->kill_conv, irn) {
+ ir_node *in = get_irn_n(get_Proj_pred(irn), 2);
+ edges_reroute(irn, in, cg->birg->irg);
+ }
+}
+
/**
* Transforms the standard firm graph into
* an ia32 firm graph
/* 2nd: transform all remaining nodes */
ia32_register_transformers();
dom = be_compute_dominance_frontiers(cg->irg);
+
+ cg->kill_conv = new_nodeset(5);
irg_walk_blkwise_graph(cg->irg, NULL, ia32_transform_node, cg);
+ ia32_kill_convs(cg);
+ del_nodeset(cg->kill_conv);
+
be_free_dominance_frontiers(dom);
if (cg->dump)
return pop;
}
-static ir_node* create_spproj(ia32_transform_env_t *env, ir_node *pred, ir_node *schedpoint, const ir_node *oldsp) {
+static ir_node* create_spproj(ia32_transform_env_t *env, ir_node *pred, int pos, ir_node *schedpoint, const ir_node *oldsp) {
ir_mode *spmode = get_irn_mode(oldsp);
const arch_register_t *spreg = arch_get_irn_register(env->cg->arch_env, oldsp);
ir_node *sp;
- sp = new_rd_Proj(env->dbg, env->irg, env->block, pred, spmode, 0);
+ sp = new_rd_Proj(env->dbg, env->irg, env->block, pred, spmode, pos);
arch_set_irn_register(env->cg->arch_env, sp, spreg);
sched_add_before(schedpoint, sp);
assert( (entbits == 32 || entbits == 64) && "spillslot on x86 should be 32 or 64 bit");
push = create_push(env, node, sp, mem, ent, NULL);
- sp = create_spproj(env, push, node, sp);
+ sp = create_spproj(env, push, 0, node, sp);
if(entbits == 64) {
// add another push after the first one
push = create_push(env, node, sp, mem, ent, "4");
- sp = create_spproj(env, push, node, sp);
+ sp = create_spproj(env, push, 0, node, sp);
}
set_irn_n(node, i, new_Bad());
pop = create_pop(env, node, sp, ent, NULL);
if(entbits == 64) {
// add another pop after the first one
- sp = create_spproj(env, pop, node, sp);
+ sp = create_spproj(env, pop, 1, node, sp);
pop = create_pop(env, node, sp, ent, "4");
}
- if(i != 0) {
- sp = create_spproj(env, pop, node, sp);
- }
+ //if(i != 0) {
+ sp = create_spproj(env, pop, 1, node, sp);
+ //}
pops[i] = pop;
}
return &ia32_code_gen_if;
}
+/**
+ * Returns the estimated execution time of an ia32 irn.
+ */
+static sched_timestep_t ia32_sched_exectime(void *env, const ir_node *irn) {
+ const arch_env_t *arch_env = env;
+ return is_ia32_irn(irn) ? ia32_get_op_estimated_cost(arch_get_irn_ops(arch_env, irn), irn) : 1;
+}
+
list_sched_selector_t ia32_sched_selector;
/**
* Returns the reg_pressure scheduler with to_appear_in_schedule() overloaded
*/
-static const list_sched_selector_t *ia32_get_list_sched_selector(const void *self) {
-// memcpy(&ia32_sched_selector, reg_pressure_selector, sizeof(list_sched_selector_t));
- memcpy(&ia32_sched_selector, trivial_selector, sizeof(list_sched_selector_t));
+static const list_sched_selector_t *ia32_get_list_sched_selector(const void *self, list_sched_selector_t *selector) {
+ memcpy(&ia32_sched_selector, selector, sizeof(ia32_sched_selector));
+ ia32_sched_selector.exectime = ia32_sched_exectime;
ia32_sched_selector.to_appear_in_schedule = ia32_to_appear_in_schedule;
return &ia32_sched_selector;
}