#include "xmalloc.h"
#include "irtools.h"
#include "iroptimize.h"
+#include "instrument.h"
#include "../beabi.h"
#include "../beirg_t.h"
#include "gen_ia32_regalloc_if.h"
#include "gen_ia32_machine.h"
#include "ia32_transform.h"
-#include "ia32_pbqp_transform.h"
#include "ia32_emitter.h"
#include "ia32_map_regs.h"
#include "ia32_optimize.h"
#include "ia32_fpu.h"
#include "ia32_architecture.h"
+#ifdef FIRM_GRGEN_BE
+#include "ia32_pbqp_transform.h"
+#endif
+
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
/* TODO: ugly */
set_ia32_frame_ent(irn, ent);
}
-static void ia32_set_frame_offset(const void *self, ir_node *irn, int bias) {
+static void ia32_set_frame_offset(const void *self, ir_node *irn, int bias)
+{
const ia32_irn_ops_t *ops = self;
- if (get_ia32_frame_ent(irn)) {
- if (is_ia32_Pop(irn)) {
- int omit_fp = be_abi_omit_fp(ops->cg->birg->abi);
- if (omit_fp) {
- /* Pop nodes modify the stack pointer before calculating the destination
- * address, so fix this here
- */
- bias -= 4;
- }
- }
+ if (get_ia32_frame_ent(irn) == NULL)
+ return;
- add_ia32_am_offs_int(irn, bias);
+ if (is_ia32_Pop(irn)) {
+ int omit_fp = be_abi_omit_fp(ops->cg->birg->abi);
+ if (omit_fp) {
+ /* Pop nodes modify the stack pointer before calculating the
+ * destination address, so fix this here
+ */
+ bias -= 4;
+ }
}
+ add_ia32_am_offs_int(irn, bias);
}
static int ia32_get_sp_bias(const void *self, const ir_node *node)
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, BE_STACK_FRAME_SIZE_SHRINK);
+ curr_sp = be_new_IncSP(env->isa->sp, env->irg, bl, curr_sp, BE_STACK_FRAME_SIZE_SHRINK, 0);
add_irn_dep(curr_sp, *mem);
} else {
- const ia32_isa_t *isa = (ia32_isa_t *)env->isa;
- ia32_code_gen_t *cg = isa->cg;
ir_mode *mode_bp = env->isa->bp->reg_class->mode;
ir_graph *irg = current_ir_graph;
curr_bp = new_r_Proj(irg, bl, leave, mode_bp, pn_ia32_Leave_frame);
curr_sp = new_r_Proj(irg, bl, leave, get_irn_mode(curr_sp), pn_ia32_Leave_stack);
} else {
- ir_node *noreg = ia32_new_NoReg_gp(cg);
ir_node *pop;
/* the old SP is not needed anymore (kill the proj) */
be_node_set_flags(curr_sp, BE_OUT_POS(0), arch_irn_flags_ignore);
/* pop ebp */
- pop = new_rd_ia32_Pop(NULL, env->irg, bl, noreg, noreg, *mem, curr_sp);
+ pop = new_rd_ia32_Pop(NULL, env->irg, bl, *mem, curr_sp);
set_ia32_flags(pop, arch_irn_flags_ignore);
curr_bp = new_r_Proj(irg, bl, pop, mode_bp, pn_ia32_Pop_res);
curr_sp = new_r_Proj(irg, bl, pop, get_irn_mode(curr_sp), pn_ia32_Pop_stack);
}
/**
- * Check if irn can load it's operand at position i from memory (source addressmode).
+ * Check if irn can load its operand at position i from memory (source addressmode).
* @param self Pointer to irn ops itself
* @param irn The irn to be checked
* @param i The operands position
* |___/
**************************************************/
+static ir_entity *mcount = NULL;
+
+#define ID(s) new_id_from_chars(s, sizeof(s) - 1)
+
static void ia32_before_abi(void *self) {
lower_mode_b_config_t lower_mode_b_config = {
mode_Iu, /* lowered mode */
ia32_code_gen_t *cg = self;
ir_lower_mode_b(cg->irg, &lower_mode_b_config);
- if(cg->dump)
+ if (cg->dump)
be_dump(cg->irg, "-lower_modeb", dump_ir_block_graph_sched);
+ if (cg->gprof) {
+ if (mcount == NULL) {
+ ir_type *tp = new_type_method(ID("FKT.mcount"), 0, 0);
+ mcount = new_entity(get_glob_type(), ID("mcount"), tp);
+ /* FIXME: enter the right ld_ident here */
+ set_entity_ld_ident(mcount, get_entity_ident(mcount));
+ set_entity_visibility(mcount, visibility_external_allocated);
+ }
+ instrument_initcall(cg->irg, mcount);
+ }
}
/**
edges_activate(cg->irg);
#endif
- if(cg->dump)
+ if (cg->dump)
be_dump(cg->irg, "-pre_transform", dump_ir_block_graph_sched);
- /* used for examination purposes only
- * if(cg->dump)
- dump_irg_grgen(cg->irg, "-pre_transform");
- */
-
- /* transform nodes into assembler instructions by PBQP magic */
- ia32_transform_graph_by_pbqp(cg);
+#ifdef FIRM_GRGEN_BE
+ /* transform nodes into assembler instructions by PBQP magic */
+ ia32_transform_graph_by_pbqp(cg);
+#endif
- if(cg->dump)
+ if (cg->dump)
be_dump(cg->irg, "-after_pbqp_transform", dump_ir_block_graph_sched);
/* transform remaining nodes into assembler instructions */
clear_ia32_am_sc_sign(node);
/* rewire mem-proj */
- if(get_irn_mode(node) == mode_T) {
+ if (get_irn_mode(node) == mode_T) {
mem_proj = NULL;
foreach_out_edge(node, edge) {
ir_node *out = get_edge_src_irn(edge);
}
set_ia32_op_type(node, ia32_Normal);
- if(sched_is_scheduled(node))
+ if (sched_is_scheduled(node))
sched_add_before(node, load);
}
ir_node *block;
ir_node *copy;
- if(is_Block(after)) {
+ if (is_Block(after)) {
block = after;
} else {
block = get_nodes_block(after);
ir_node *noreg = ia32_new_NoReg_gp(cg);
ir_node *frame = get_irg_frame(irg);
- ir_node *pop = new_rd_ia32_Pop(dbg, irg, block, frame, noreg, new_NoMem(), sp);
+ ir_node *pop = new_rd_ia32_PopMem(dbg, irg, block, frame, noreg, new_NoMem(), sp);
set_ia32_frame_ent(pop, ent);
set_ia32_use_frame(pop);
free(cg);
}
+/**
+ * Returns the node representing the PIC base.
+ */
+static ir_node *ia32_get_pic_base(void *self) {
+ ir_node *block;
+ ia32_code_gen_t *cg = self;
+ ir_node *get_eip = cg->get_eip;
+ if (get_eip != NULL)
+ return get_eip;
+
+ block = get_irg_start_block(cg->irg);
+ get_eip = new_rd_ia32_GetEIP(NULL, cg->irg, block);
+ cg->get_eip = get_eip;
+
+ add_irn_dep(get_eip, get_irg_frame(cg->irg));
+
+ return get_eip;
+}
+
static void *ia32_cg_init(be_irg_t *birg);
static const arch_code_generator_if_t ia32_code_gen_if = {
ia32_cg_init,
+ ia32_get_pic_base, /* return node used as base in pic code addresses */
ia32_before_abi, /* before abi introduce hook */
ia32_prepare_graph,
NULL, /* spill */
* Initializes a IA32 code generator.
*/
static void *ia32_cg_init(be_irg_t *birg) {
- ia32_isa_t *isa = (ia32_isa_t *)birg->main_env->arch_env->isa;
+ ia32_isa_t *isa = (ia32_isa_t *)birg->main_env->arch_env.isa;
ia32_code_gen_t *cg = xcalloc(1, sizeof(*cg));
cg->impl = &ia32_code_gen_if;
cg->irg = birg->irg;
cg->reg_set = new_set(ia32_cmp_irn_reg_assoc, 1024);
- cg->arch_env = birg->main_env->arch_env;
+ cg->arch_env = &birg->main_env->arch_env;
cg->isa = isa;
cg->birg = birg;
cg->blk_sched = NULL;
cg->dump = (birg->main_env->options->dump_flags & DUMP_BE) ? 1 : 0;
+ cg->gprof = (birg->main_env->options->gprof) ? 1 : 0;
+
+ if (cg->gprof) {
+ /* Linux gprof implementation needs base pointer */
+ birg->main_env->options->omit_fp = 0;
+ }
/* enter it */
isa->cg = cg;
&ia32_gp_regs[REG_ESP], /* stack pointer register */
&ia32_gp_regs[REG_EBP], /* base pointer register */
-1, /* stack direction */
+ 16, /* stack alignment */
NULL, /* main environment */
7, /* costs for a spill instruction */
5, /* costs for a reload instruction */
static const lc_opt_table_entry_t ia32_options[] = {
LC_OPT_ENT_ENUM_INT("gasmode", "set the GAS compatibility mode", &gas_var),
+ LC_OPT_ENT_INT("stackalign", "set stack alignment for calls",
+ &ia32_isa_template.arch_isa.stack_alignment),
LC_OPT_LAST
};