From 24fedddc648276a205f780ff7f1ad5a3e76c88b4 Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Thu, 1 Oct 2009 16:43:13 +0000 Subject: [PATCH] - refactoring of backend generator scripts: You can create multiple constructors (with different arguments and register constraints for the same node now) - Lots of cleanups/changes in the arm backend. We can represent all "shifter operands" now (but the code selection isn't optimal yet) - More fixes all over the place - arm backend handles 164.gzip now [r26673] --- ir/be/TEMPLATE/TEMPLATE_new_nodes.c | 35 - ir/be/TEMPLATE/TEMPLATE_spec.pl | 1 - ir/be/TEMPLATE/TEMPLATE_transform.c | 12 +- ir/be/TEMPLATE/bearch_TEMPLATE.c | 34 +- ir/be/arm/arm_emitter.c | 395 +++----- ir/be/arm/arm_emitter.h | 4 +- ir/be/arm/arm_new_nodes.c | 303 +++--- ir/be/arm/arm_new_nodes.h | 30 +- ir/be/arm/arm_nodes_attr.h | 115 ++- ir/be/arm/arm_optimize.c | 252 +++-- ir/be/arm/arm_optimize.h | 2 +- ir/be/arm/arm_spec.pl | 810 +++++----------- ir/be/arm/arm_transform.c | 1217 +++++++++++-------------- ir/be/arm/bearch_arm.c | 175 ++-- ir/be/beabi.c | 7 +- ir/be/beflags.c | 6 +- ir/be/bespillslots.c | 3 +- ir/be/ia32/ia32_emitter.c | 4 +- ir/be/ia32/ia32_simd_spec.pl | 12 - ir/be/ia32/ia32_spec.pl | 210 +---- ir/be/mips/mips_spec.pl | 1 - ir/be/ppc32/ppc32_spec.pl | 1 - ir/be/scripts/generate_new_opcodes.pl | 914 +++++++++++++------ ir/opt/code_placement.c | 71 +- 24 files changed, 2068 insertions(+), 2546 deletions(-) delete mode 100644 ir/be/ia32/ia32_simd_spec.pl diff --git a/ir/be/TEMPLATE/TEMPLATE_new_nodes.c b/ir/be/TEMPLATE/TEMPLATE_new_nodes.c index 095a918c9..100150b3c 100644 --- a/ir/be/TEMPLATE/TEMPLATE_new_nodes.c +++ b/ir/be/TEMPLATE/TEMPLATE_new_nodes.c @@ -45,19 +45,6 @@ #include "TEMPLATE_new_nodes.h" #include "gen_TEMPLATE_regalloc_if.h" - - -/*********************************************************************************** - * _ _ _ __ - * | | (_) | | / _| - * __| |_ _ _ __ ___ _ __ ___ _ __ _ _ __ | |_ ___ _ __| |_ __ _ ___ ___ - * / _` | | | | '_ ` _ \| '_ \ / _ \ '__| | | '_ \| __/ _ \ '__| _/ _` |/ __/ _ \ - * | (_| | |_| | | | | | | |_) | __/ | | | | | | || __/ | | || (_| | (_| __/ - * \__,_|\__,_|_| |_| |_| .__/ \___|_| |_|_| |_|\__\___|_| |_| \__,_|\___\___| - * | | - * |_| - ***********************************************************************************/ - /** * Dumper interface for dumping TEMPLATE nodes in vcg. * @param n the node to dump @@ -99,17 +86,6 @@ static int TEMPLATE_dump_node(ir_node *n, FILE *F, dump_reason_t reason) return 0; } -/*************************************************************************************************** - * _ _ _ __ _ _ _ _ - * | | | | | | / / | | | | | | | | - * __ _| |_| |_ _ __ ___ ___| |_ / /_ _ ___| |_ _ __ ___ ___| |_| |__ ___ __| |___ - * / _` | __| __| '__| / __|/ _ \ __| / / _` |/ _ \ __| | '_ ` _ \ / _ \ __| '_ \ / _ \ / _` / __| - * | (_| | |_| |_| | \__ \ __/ |_ / / (_| | __/ |_ | | | | | | __/ |_| | | | (_) | (_| \__ \ - * \__,_|\__|\__|_| |___/\___|\__/_/ \__, |\___|\__| |_| |_| |_|\___|\__|_| |_|\___/ \__,_|___/ - * __/ | - * |___/ - ***************************************************************************************************/ - const TEMPLATE_attr_t *get_TEMPLATE_attr_const(const ir_node *node) { assert(is_TEMPLATE_irn(node) && "need TEMPLATE node to get attributes"); @@ -171,16 +147,6 @@ void init_TEMPLATE_attributes(ir_node *node, arch_irn_flags_t flags, memset(info->out_infos, 0, n_res * sizeof(info->out_infos[0])); } -/*************************************************************************************** - * _ _ _ - * | | | | | | - * _ __ ___ __| | ___ ___ ___ _ __ ___| |_ _ __ _ _ ___| |_ ___ _ __ ___ - * | '_ \ / _ \ / _` |/ _ \ / __/ _ \| '_ \/ __| __| '__| | | |/ __| __/ _ \| '__/ __| - * | | | | (_) | (_| | __/ | (_| (_) | | | \__ \ |_| | | |_| | (__| || (_) | | \__ \ - * |_| |_|\___/ \__,_|\___| \___\___/|_| |_|___/\__|_| \__,_|\___|\__\___/|_| |___/ - * - ***************************************************************************************/ - static int TEMPLATE_compare_attr(ir_node *a, ir_node *b) { const TEMPLATE_attr_t *attr_a = get_TEMPLATE_attr_const(a); @@ -191,6 +157,5 @@ static int TEMPLATE_compare_attr(ir_node *a, ir_node *b) return 0; } - /* Include the generated constructor functions */ #include "gen_TEMPLATE_new_nodes.c.inl" diff --git a/ir/be/TEMPLATE/TEMPLATE_spec.pl b/ir/be/TEMPLATE/TEMPLATE_spec.pl index 49d31a939..f24a58dec 100644 --- a/ir/be/TEMPLATE/TEMPLATE_spec.pl +++ b/ir/be/TEMPLATE/TEMPLATE_spec.pl @@ -1,6 +1,5 @@ # Creation: 2006/02/13 # $Id$ -# This is a template specification for the Firm-Backend # the cpu architecture (ia32, ia64, mips, sparc, ppc, ...) diff --git a/ir/be/TEMPLATE/TEMPLATE_transform.c b/ir/be/TEMPLATE/TEMPLATE_transform.c index 28c05059c..289cf7869 100644 --- a/ir/be/TEMPLATE/TEMPLATE_transform.c +++ b/ir/be/TEMPLATE/TEMPLATE_transform.c @@ -286,15 +286,6 @@ static ir_node *gen_Jmp(TEMPLATE_transform_env_t *env) return new_bd_TEMPLATE_Jmp(env->dbg, env->block); } -/********************************************************* - * _ _ _ - * (_) | | (_) - * _ __ ___ __ _ _ _ __ __| |_ __ ___ _____ _ __ - * | '_ ` _ \ / _` | | '_ \ / _` | '__| \ \ / / _ \ '__| - * | | | | | | (_| | | | | | | (_| | | | |\ V / __/ | - * |_| |_| |_|\__,_|_|_| |_| \__,_|_| |_| \_/ \___|_| - * - *********************************************************/ @@ -404,8 +395,7 @@ bad: if (asm_node) { exchange(node, asm_node); DB((dbg, LEVEL_1, "created node %+F[%p]\n", asm_node, asm_node)); - } - else { + } else { DB((dbg, LEVEL_1, "ignored\n")); } } diff --git a/ir/be/TEMPLATE/bearch_TEMPLATE.c b/ir/be/TEMPLATE/bearch_TEMPLATE.c index e00e5c32e..4e0a2331a 100644 --- a/ir/be/TEMPLATE/bearch_TEMPLATE.c +++ b/ir/be/TEMPLATE/bearch_TEMPLATE.c @@ -53,17 +53,6 @@ DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;) -/************************************************** - * _ _ _ __ - * | | | (_)/ _| - * _ __ ___ __ _ __ _| | | ___ ___ _| |_ - * | '__/ _ \/ _` | / _` | | |/ _ \ / __| | | _| - * | | | __/ (_| | | (_| | | | (_) | (__ | | | - * |_| \___|\__, | \__,_|_|_|\___/ \___| |_|_| - * __/ | - * |___/ - **************************************************/ - static arch_irn_class_t TEMPLATE_classify(const ir_node *irn) { (void) irn; @@ -116,16 +105,7 @@ static const arch_irn_ops_t TEMPLATE_irn_ops = { NULL, /* perform_memory_operand */ }; -/************************************************** - * _ _ __ - * | | (_)/ _| - * ___ ___ __| | ___ __ _ ___ _ __ _| |_ - * / __/ _ \ / _` |/ _ \/ _` |/ _ \ '_ \ | | _| - * | (_| (_) | (_| | __/ (_| | __/ | | | | | | - * \___\___/ \__,_|\___|\__, |\___|_| |_| |_|_| - * __/ | - * |___/ - **************************************************/ + /** * Transforms the standard firm graph into @@ -214,16 +194,6 @@ static void *TEMPLATE_cg_init(be_irg_t *birg) -/***************************************************************** - * ____ _ _ _____ _____ - * | _ \ | | | | |_ _|/ ____| /\ - * | |_) | __ _ ___| | _____ _ __ __| | | | | (___ / \ - * | _ < / _` |/ __| |/ / _ \ '_ \ / _` | | | \___ \ / /\ \ - * | |_) | (_| | (__| < __/ | | | (_| | _| |_ ____) / ____ \ - * |____/ \__,_|\___|_|\_\___|_| |_|\__,_| |_____|_____/_/ \_\ - * - *****************************************************************/ - const arch_isa_if_t TEMPLATE_isa_if; static TEMPLATE_isa_t TEMPLATE_isa_template = { { @@ -240,7 +210,7 @@ static TEMPLATE_isa_t TEMPLATE_isa_template = { }; /** - * Initializes the backend ISA and opens the output file. + * Initializes the backend ISA */ static arch_env_t *TEMPLATE_init(FILE *outfile) { diff --git a/ir/be/arm/arm_emitter.c b/ir/be/arm/arm_emitter.c index bad7fb0ad..62a8d8555 100644 --- a/ir/be/arm/arm_emitter.c +++ b/ir/be/arm/arm_emitter.c @@ -68,7 +68,8 @@ static set *sym_or_tv; /** * Returns the register at in position pos. */ -static const arch_register_t *get_in_reg(const ir_node *irn, int pos) { +static const arch_register_t *get_in_reg(const ir_node *irn, int pos) +{ ir_node *op; const arch_register_t *reg = NULL; @@ -133,17 +134,6 @@ static const arch_register_t *get_out_reg(const ir_node *node, int pos) return reg; } -/************************************************************* - * _ _ __ _ _ - * (_) | | / _| | | | | - * _ __ _ __ _ _ __ | |_| |_ | |__ ___| |_ __ ___ _ __ - * | '_ \| '__| | '_ \| __| _| | '_ \ / _ \ | '_ \ / _ \ '__| - * | |_) | | | | | | | |_| | | | | | __/ | |_) | __/ | - * | .__/|_| |_|_| |_|\__|_| |_| |_|\___|_| .__/ \___|_| - * | | | | - * |_| |_| - *************************************************************/ - /** * Emit the name of the source register at given input position. */ @@ -163,18 +153,12 @@ void arm_emit_dest_register(const ir_node *node, int pos) { /** * Emit a node's offset. */ -void arm_emit_offset(const ir_node *node) { - int offset = 0; - ir_opcode opc = get_irn_opcode(node); +void arm_emit_offset(const ir_node *node) +{ + const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node); + assert(attr->base.is_load_store); - if (opc == beo_Reload || opc == beo_Spill) { - ir_entity *ent = be_get_frame_entity(node); - offset = get_entity_offset(ent); - } else { - assert(!"unimplemented arm_emit_offset for this node type"); - panic("unimplemented arm_emit_offset for this node type"); - } - be_emit_irprintf("%d", offset); + be_emit_irprintf("0x%X", attr->offset); } /** @@ -209,32 +193,119 @@ void arm_emit_mode(const ir_node *node) { /** * Emit a const or SymConst value. */ -void arm_emit_immediate(const ir_node *node) { +void arm_emit_immediate(const ir_node *node) +{ const arm_attr_t *attr = get_arm_attr_const(node); - if (ARM_GET_SHF_MOD(attr) == ARM_SHF_IMM) { - be_emit_irprintf("#0x%X", arm_decode_imm_w_shift(get_arm_imm_value(node))); - } else if (ARM_GET_FPA_IMM(attr)) { - be_emit_irprintf("#%s", arm_get_fpa_imm_name(get_arm_imm_value(node))); - } else if (is_arm_SymConst(node)) - be_emit_ident(get_arm_symconst_id(node)); - else { + if (ARM_GET_FPA_IMM(attr)) { + /* TODO */ + //be_emit_irprintf("#%s", arm_get_fpa_imm_name(get_arm_imm_value(node))); + } else { assert(!"not a Constant"); } } -/** - * Returns the tarval or offset of an arm node as a string. - */ -void arm_emit_shift(const ir_node *node) { - arm_shift_modifier mod; +void arm_emit_load_mode(const ir_node *node) +{ + const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node); + ir_mode *mode = attr->load_store_mode; + int bits = get_mode_size_bits(mode); + bool is_signed = mode_is_signed(mode); + if (bits == 16) { + be_emit_string(is_signed ? "sh" : "h"); + } else if (bits == 8) { + be_emit_string(is_signed ? "sb" : "b"); + } else { + assert(bits == 32); + } +} + +void arm_emit_store_mode(const ir_node *node) +{ + const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node); + ir_mode *mode = attr->load_store_mode; + int bits = get_mode_size_bits(mode); + if (bits == 16) { + be_emit_cstring("h"); + } else if (bits == 8) { + be_emit_cstring("b"); + } else { + assert(bits == 32); + } +} + + +static void emit_shf_mod_name(arm_shift_modifier mod) +{ + switch (mod) { + case ARM_SHF_ASR_REG: + case ARM_SHF_ASR_IMM: + be_emit_cstring("asr"); + return; + case ARM_SHF_LSL_REG: + case ARM_SHF_LSL_IMM: + be_emit_cstring("lsl"); + return; + case ARM_SHF_LSR_REG: + case ARM_SHF_LSR_IMM: + be_emit_cstring("lsr"); + return; + case ARM_SHF_ROR_REG: + case ARM_SHF_ROR_IMM: + be_emit_cstring("ror"); + return; + default: + break; + } + panic("can't emit this shf_mod_name %d", (int) mod); +} + +void arm_emit_shifter_operand(const ir_node *node) +{ + const arm_shifter_operand_t *attr = get_irn_generic_attr_const(node); - mod = get_arm_shift_modifier(node); - if (ARM_HAS_SHIFT(mod)) { - int v = get_arm_imm_value(node); + switch (attr->shift_modifier) { + case ARM_SHF_REG: + arm_emit_source_register(node, get_irn_arity(node) - 1); + return; + case ARM_SHF_IMM: { + unsigned val = attr->immediate_value; + val = (val >> attr->shift_immediate) + | (val << (32-attr->shift_immediate)); + val &= 0xFFFFFFFF; + be_emit_irprintf("#0x%X", val); + return; + } + case ARM_SHF_ASR_IMM: + case ARM_SHF_LSL_IMM: + case ARM_SHF_LSR_IMM: + case ARM_SHF_ROR_IMM: + arm_emit_source_register(node, get_irn_arity(node) - 1); + be_emit_cstring(", "); + emit_shf_mod_name(attr->shift_modifier); + be_emit_irprintf(" #0x%X", attr->shift_immediate); + return; + + case ARM_SHF_ASR_REG: + case ARM_SHF_LSL_REG: + case ARM_SHF_LSR_REG: + case ARM_SHF_ROR_REG: + arm_emit_source_register(node, get_irn_arity(node) - 2); + be_emit_cstring(", "); + emit_shf_mod_name(attr->shift_modifier); + be_emit_cstring(" "); + arm_emit_source_register(node, get_irn_arity(node) - 1); + return; + + case ARM_SHF_RRX: + arm_emit_source_register(node, get_irn_arity(node) - 1); + panic("RRX shifter emitter TODO"); + return; - be_emit_irprintf(", %s #%d", arm_shf_mod_name(mod), v); + case ARM_SHF_INVALID: + break; } + panic("Invalid shift_modifier while emitting %+F", node); } /** An entry in the sym_or_tv set. */ @@ -259,11 +330,15 @@ static unsigned get_unique_label(void) { /** * Emit a SymConst. */ -static void emit_arm_SymConst(const ir_node *irn) { +static void emit_arm_SymConst(const ir_node *irn) +{ + const arm_SymConst_attr_t *attr = get_arm_SymConst_attr_const(irn); sym_or_tv_t key, *entry; unsigned label; - key.u.id = get_arm_symconst_id(irn); + set_entity_backend_marked(attr->entity, 1); + + key.u.id = get_entity_ld_ident(attr->entity); key.is_ident = 1; key.label = 0; entry = (sym_or_tv_t *)set_insert(sym_or_tv, &key, sizeof(key), HASH_PTR(key.u.generic)); @@ -280,6 +355,19 @@ static void emit_arm_SymConst(const ir_node *irn) { be_emit_finish_line_gas(irn); } +static void emit_arm_FrameAddr(const ir_node *irn) +{ + const arm_SymConst_attr_t *attr = get_irn_generic_attr_const(irn); + + be_emit_cstring("\tadd "); + arm_emit_dest_register(irn, 0); + be_emit_cstring(", "); + arm_emit_source_register(irn, 0); + be_emit_cstring(", "); + be_emit_irprintf("#0x%X", attr->fp_offset); + be_emit_finish_line_gas(irn); +} + /** * Emit a floating point fpa constant. */ @@ -348,16 +436,20 @@ static void arm_emit_cfop_target(const ir_node *irn) { /** * Emit a Compare with conditional branch. */ -static void emit_arm_CmpBra(const ir_node *irn) { +static void emit_arm_B(const ir_node *irn) +{ const ir_edge_t *edge; const ir_node *proj_true = NULL; const ir_node *proj_false = NULL; const ir_node *block; const ir_node *next_block; ir_node *op1 = get_irn_n(irn, 0); - ir_mode *opmode = get_irn_mode(op1); const char *suffix; int proj_num = get_arm_CondJmp_proj_num(irn); + const arm_cmp_attr_t *cmp_attr = get_irn_generic_attr_const(op1); + bool is_signed = !cmp_attr->is_unsigned; + + assert(is_arm_Cmp(op1) || is_arm_Tst(op1)); foreach_out_edge(irn, edge) { ir_node *proj = get_edge_src_irn(edge); @@ -369,102 +461,8 @@ static void emit_arm_CmpBra(const ir_node *irn) { } } - /* for now, the code works for scheduled and non-schedules blocks */ - block = get_nodes_block(irn); - - /* we have a block schedule */ - next_block = sched_next_block(block); - - if (proj_num == pn_Cmp_False) { - /* always false: should not happen */ - be_emit_cstring("\tb "); - arm_emit_cfop_target(proj_false); - be_emit_finish_line_gas(proj_false); - } else if (proj_num == pn_Cmp_True) { - /* always true: should not happen */ - be_emit_cstring("\tb "); - arm_emit_cfop_target(proj_true); - be_emit_finish_line_gas(proj_true); - } else { - if (mode_is_float(opmode)) { - suffix = "ICHWILLIMPLEMENTIERTWERDEN"; - - be_emit_cstring("\tfcmp "); - arm_emit_source_register(irn, 0); - be_emit_cstring(", "); - arm_emit_source_register(irn, 1); - be_emit_finish_line_gas(irn); - - be_emit_cstring("\tfmstat"); - be_emit_pad_comment(); - be_emit_cstring("/* FCSPR -> CPSR */"); - be_emit_finish_line_gas(NULL); - } else { - if (get_cfop_target_block(proj_true) == next_block) { - /* exchange both proj's so the second one can be omitted */ - const ir_node *t = proj_true; - - proj_true = proj_false; - proj_false = t; - proj_num = get_negated_pnc(proj_num, mode_Iu); - } - switch (proj_num) { - case pn_Cmp_Eq: suffix = "eq"; break; - case pn_Cmp_Lt: suffix = "lt"; break; - case pn_Cmp_Le: suffix = "le"; break; - case pn_Cmp_Gt: suffix = "gt"; break; - case pn_Cmp_Ge: suffix = "ge"; break; - case pn_Cmp_Lg: suffix = "ne"; break; - case pn_Cmp_Leg: suffix = "al"; break; - default: assert(!"Cmp unsupported"); suffix = "al"; - } - be_emit_cstring("\tcmp "); - arm_emit_source_register(irn, 0); - be_emit_cstring(", "); - arm_emit_source_register(irn, 1); - be_emit_finish_line_gas(irn); - } - - /* emit the true proj */ - be_emit_irprintf("\tb%s ", suffix); - arm_emit_cfop_target(proj_true); - be_emit_finish_line_gas(proj_true); - - if (get_cfop_target_block(proj_false) == next_block) { - be_emit_cstring("\t/* fallthrough to "); - arm_emit_cfop_target(proj_false); - be_emit_cstring(" */"); - be_emit_finish_line_gas(proj_false); - } else { - be_emit_cstring("\tb "); - arm_emit_cfop_target(proj_false); - be_emit_finish_line_gas(proj_false); - } - } -} - - -/** - * Emit a Tst with conditional branch. - */ -static void emit_arm_TstBra(const ir_node *irn) -{ - const ir_edge_t *edge; - const ir_node *proj_true = NULL; - const ir_node *proj_false = NULL; - const ir_node *block; - const ir_node *next_block; - const char *suffix; - int proj_num = get_arm_CondJmp_proj_num(irn); - - foreach_out_edge(irn, edge) { - ir_node *proj = get_edge_src_irn(edge); - long nr = get_Proj_proj(proj); - if (nr == pn_Cond_true) { - proj_true = proj; - } else { - proj_false = proj; - } + if (cmp_attr->ins_permuted) { + proj_num = get_mirrored_pnc(proj_num); } /* for now, the code works for scheduled and non-schedules blocks */ @@ -484,21 +482,17 @@ static void emit_arm_TstBra(const ir_node *irn) proj_false = t; proj_num = get_negated_pnc(proj_num, mode_Iu); } + switch (proj_num) { case pn_Cmp_Eq: suffix = "eq"; break; - case pn_Cmp_Lt: suffix = "lt"; break; - case pn_Cmp_Le: suffix = "le"; break; - case pn_Cmp_Gt: suffix = "gt"; break; - case pn_Cmp_Ge: suffix = "ge"; break; + case pn_Cmp_Lt: suffix = is_signed ? "lt" : "lo"; break; + case pn_Cmp_Le: suffix = is_signed ? "le" : "ls"; break; + case pn_Cmp_Gt: suffix = is_signed ? "gt" : "hi"; break; + case pn_Cmp_Ge: suffix = is_signed ? "ge" : "hs"; break; case pn_Cmp_Lg: suffix = "ne"; break; case pn_Cmp_Leg: suffix = "al"; break; - default: assert(!"Cmp unsupported"); suffix = "al"; + default: panic("Cmp has unsupported pnc"); } - be_emit_cstring("\ttst "); - arm_emit_source_register(irn, 0); - be_emit_cstring(", "); - arm_emit_source_register(irn, 1); - be_emit_finish_line_gas(irn); /* emit the true proj */ be_emit_irprintf("\tb%s ", suffix); @@ -511,26 +505,12 @@ static void emit_arm_TstBra(const ir_node *irn) be_emit_cstring(" */"); be_emit_finish_line_gas(proj_false); } else { - be_emit_cstring("b "); + be_emit_cstring("\tb "); arm_emit_cfop_target(proj_false); be_emit_finish_line_gas(proj_false); } } -/** - * Emit a Compare with conditional branch. - */ -static void emit_arm_fpaCmfBra(const ir_node *irn) { - (void) irn; -} - -/** - * Emit a Compare with conditional branch. - */ -static void emit_arm_fpaCmfeBra(const ir_node *irn) { - (void) irn; -} - /** Sort register in ascending order. */ static int reg_cmp(const void *a, const void *b) { const arch_register_t * const *ra = a; @@ -542,8 +522,10 @@ static int reg_cmp(const void *a, const void *b) { /** * Create the CopyB instruction sequence. */ -static void emit_arm_CopyB(const ir_node *irn) { - unsigned size = (unsigned)get_arm_imm_value(irn); +static void emit_arm_CopyB(const ir_node *irn) +{ + const arm_CopyB_attr_t *attr = get_irn_generic_attr_const(irn); + unsigned size = attr->size; const char *tgt = arch_register_get_name(get_in_reg(irn, 0)); const char *src = arch_register_get_name(get_in_reg(irn, 1)); @@ -840,66 +822,6 @@ static void emit_be_Copy(const ir_node *irn) { } } -/** - * Emit code for a Spill. - */ -static void emit_be_Spill(const ir_node *irn) { - ir_mode *mode = get_irn_mode(be_get_Spill_val(irn)); - - if (mode_is_float(mode)) { - if (USE_FPA(cg->isa)) { - be_emit_cstring("\tstf"); - arm_emit_fpa_postfix(mode); - be_emit_char(' '); - } else { - assert(0 && "spill not supported for this mode"); - panic("emit_be_Spill: spill not supported for this mode"); - } - } else if (mode_is_dataM(mode)) { - be_emit_cstring("\tstr "); - } else { - assert(0 && "spill not supported for this mode"); - panic("emit_be_Spill: spill not supported for this mode"); - } - arm_emit_source_register(irn, 1); - be_emit_cstring(", ["); - arm_emit_source_register(irn, 0); - be_emit_cstring(", #"); - arm_emit_offset(irn); - be_emit_char(']'); - be_emit_finish_line_gas(irn); -} - -/** - * Emit code for a Reload. - */ -static void emit_be_Reload(const ir_node *irn) { - ir_mode *mode = get_irn_mode(irn); - - if (mode_is_float(mode)) { - if (USE_FPA(cg->isa)) { - be_emit_cstring("\tldf"); - arm_emit_fpa_postfix(mode); - be_emit_char(' '); - } else { - assert(0 && "reload not supported for this mode"); - panic("emit_be_Reload: reload not supported for this mode"); - } - } else if (mode_is_dataM(mode)) { - be_emit_cstring("\tldr "); - } else { - assert(0 && "reload not supported for this mode"); - panic("emit_be_Reload: reload not supported for this mode"); - } - arm_emit_dest_register(irn, 0); - be_emit_cstring(", ["); - arm_emit_source_register(irn, 0); - be_emit_cstring(", #"); - arm_emit_offset(irn); - be_emit_char(']'); - be_emit_finish_line_gas(irn); -} - static void emit_be_Perm(const ir_node *irn) { be_emit_cstring("\teor "); @@ -1024,16 +946,6 @@ static void emit_arm_LdTls(const ir_node *irn) { /* Er... our gcc does not support it... Install a newer toolchain. */ } -/*********************************************************************************** - * _ __ _ - * (_) / _| | | - * _ __ ___ __ _ _ _ __ | |_ _ __ __ _ _ __ ___ _____ _____ _ __| | __ - * | '_ ` _ \ / _` | | '_ \ | _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ / - * | | | | | | (_| | | | | | | | | | | (_| | | | | | | __/\ V V / (_) | | | < - * |_| |_| |_|\__,_|_|_| |_| |_| |_| \__,_|_| |_| |_|\___| \_/\_/ \___/|_| |_|\_\ - * - ***********************************************************************************/ - static void emit_nothing(const ir_node *irn) { (void) irn; @@ -1065,25 +977,22 @@ static void arm_register_emitters(void) arm_register_spec_emitters(); /* custom emitter */ - set_emitter(op_arm_CmpBra, emit_arm_CmpBra); + set_emitter(op_arm_B, emit_arm_B); set_emitter(op_arm_CopyB, emit_arm_CopyB); - set_emitter(op_arm_fpaCmfBra, emit_arm_fpaCmfBra); - set_emitter(op_arm_fpaCmfeBra, emit_arm_fpaCmfeBra); set_emitter(op_arm_fpaConst, emit_arm_fpaConst); set_emitter(op_arm_fpaDbl2GP, emit_arm_fpaDbl2GP); + set_emitter(op_arm_FrameAddr, emit_arm_FrameAddr); set_emitter(op_arm_Jmp, emit_arm_Jmp); set_emitter(op_arm_LdTls, emit_arm_LdTls); set_emitter(op_arm_SwitchJmp, emit_arm_SwitchJmp); set_emitter(op_arm_SymConst, emit_arm_SymConst); - set_emitter(op_arm_TstBra, emit_arm_TstBra); set_emitter(op_be_Call, emit_be_Call); set_emitter(op_be_Copy, emit_be_Copy); + set_emitter(op_be_CopyKeep, emit_be_Copy); set_emitter(op_be_IncSP, emit_be_IncSP); set_emitter(op_be_MemPerm, emit_be_MemPerm); set_emitter(op_be_Perm, emit_be_Perm); - set_emitter(op_be_Reload, emit_be_Reload); set_emitter(op_be_Return, emit_be_Return); - set_emitter(op_be_Spill, emit_be_Spill); /* no need to emit anything for the following nodes */ set_emitter(op_Phi, emit_nothing); diff --git a/ir/be/arm/arm_emitter.h b/ir/be/arm/arm_emitter.h index 0048dd347..0faeea45d 100644 --- a/ir/be/arm/arm_emitter.h +++ b/ir/be/arm/arm_emitter.h @@ -39,8 +39,10 @@ void arm_emit_mode(const ir_node *node); void arm_emit_source_register(const ir_node *node, int pos); void arm_emit_dest_register(const ir_node *node, int pos); void arm_emit_offset(const ir_node *node); -void arm_emit_immediate(const ir_node *node); void arm_emit_shift(const ir_node *node); +void arm_emit_shifter_operand(const ir_node *node); +void arm_emit_load_mode(const ir_node *node); +void arm_emit_store_mode(const ir_node *node); void arm_gen_routine(const arm_code_gen_t *cg, ir_graph *irg); diff --git a/ir/be/arm/arm_new_nodes.c b/ir/be/arm/arm_new_nodes.c index 9f052ff5e..051e52740 100644 --- a/ir/be/arm/arm_new_nodes.c +++ b/ir/be/arm/arm_new_nodes.c @@ -49,14 +49,6 @@ #include "../beabi.h" #include "bearch_arm_t.h" -/** - * Returns the shift modifier string. - */ -const char *arm_shf_mod_name(arm_shift_modifier mod) { - static const char *names[] = { NULL, NULL, "asr", "lsl", "lsr", "ror", "rrx" }; - return names[mod]; -} - /** * Return the fpa immediate from the encoding. */ @@ -74,16 +66,6 @@ const char *arm_get_fpa_imm_name(long imm_value) { return fpa_imm[imm_value]; } -/*********************************************************************************** - * _ _ _ __ - * | | (_) | | / _| - * __| |_ _ _ __ ___ _ __ ___ _ __ _ _ __ | |_ ___ _ __| |_ __ _ ___ ___ - * / _` | | | | '_ ` _ \| '_ \ / _ \ '__| | | '_ \| __/ _ \ '__| _/ _` |/ __/ _ \ - * | (_| | |_| | | | | | | |_) | __/ | | | | | | || __/ | | || (_| | (_| __/ - * \__,_|\__,_|_| |_| |_| .__/ \___|_| |_|_| |_|\__\___|_| |_| \__,_|\___\___| - * | | - * |_| - ***********************************************************************************/ /** * Dumper interface for dumping arm nodes in vcg. @@ -95,8 +77,7 @@ const char *arm_get_fpa_imm_name(long imm_value) { static int arm_dump_node(ir_node *n, FILE *F, dump_reason_t reason) { ir_mode *mode = NULL; - arm_attr_t *attr = get_arm_attr(n); - arm_shift_modifier mod; + //arm_attr_t *attr = get_arm_attr(n); switch (reason) { case dump_node_opcode_txt: @@ -115,33 +96,31 @@ static int arm_dump_node(ir_node *n, FILE *F, dump_reason_t reason) break; case dump_node_nodeattr_txt: - mod = ARM_GET_SHF_MOD(attr); - if (ARM_HAS_SHIFT(mod)) { - fprintf(F, "[%s #%ld]", arm_shf_mod_name(mod), attr->imm_value); - } - else if (mod == ARM_SHF_IMM) { - /* immediate */ - fprintf(F, "[#0x%X]", arm_decode_imm_w_shift(attr->imm_value)); - } + /* TODO: dump shift modifiers */ break; case dump_node_info_txt: arch_dump_reqs_and_registers(F, n); if (is_arm_CopyB(n)) { - fprintf(F, "size = %lu\n", get_arm_imm_value(n)); + //fprintf(F, "size = %lu\n", get_arm_imm_value(n)); } else { + /* TODO */ +#if 0 long v = get_arm_imm_value(n); if (ARM_GET_FPA_IMM(attr)) { fprintf(F, "immediate float value = %s\n", arm_get_fpa_imm_name(v)); } else { fprintf(F, "immediate value = %ld (0x%08lx)\n", v, v); } +#endif } +#if 0 if (is_arm_CmpBra(n) && get_arm_CondJmp_proj_num(n) >= 0) { fprintf(F, "proj_num = (%d)\n", get_arm_CondJmp_proj_num(n)); } +#endif break; } @@ -149,25 +128,15 @@ static int arm_dump_node(ir_node *n, FILE *F, dump_reason_t reason) } - -/*************************************************************************************************** - * _ _ _ __ _ _ _ _ - * | | | | | | / / | | | | | | | | - * __ _| |_| |_ _ __ ___ ___| |_ / /_ _ ___| |_ _ __ ___ ___| |_| |__ ___ __| |___ - * / _` | __| __| '__| / __|/ _ \ __| / / _` |/ _ \ __| | '_ ` _ \ / _ \ __| '_ \ / _ \ / _` / __| - * | (_| | |_| |_| | \__ \ __/ |_ / / (_| | __/ |_ | | | | | | __/ |_| | | | (_) | (_| \__ \ - * \__,_|\__|\__|_| |___/\___|\__/_/ \__, |\___|\__| |_| |_| |_|\___|\__|_| |_|\___/ \__,_|___/ - * __/ | - * |___/ - ***************************************************************************************************/ - /* Returns the attributes of a generic Arm node. */ -arm_attr_t *get_arm_attr(ir_node *node) { +arm_attr_t *get_arm_attr(ir_node *node) +{ assert(is_arm_irn(node) && "need arm node to get attributes"); return get_irn_generic_attr(node); } -const arm_attr_t *get_arm_attr_const(const ir_node *node) { +const arm_attr_t *get_arm_attr_const(const ir_node *node) +{ assert(is_arm_irn(node) && "need arm node to get attributes"); return get_irn_generic_attr_const(node); } @@ -175,13 +144,15 @@ const arm_attr_t *get_arm_attr_const(const ir_node *node) { /** * Returns the attributes of an ARM SymConst node. */ -arm_SymConst_attr_t *get_arm_SymConst_attr(ir_node *node) { - assert(is_arm_SymConst(node)); +arm_SymConst_attr_t *get_arm_SymConst_attr(ir_node *node) +{ + assert(is_arm_SymConst(node) || is_arm_FrameAddr(node)); return get_irn_generic_attr(node); } -const arm_SymConst_attr_t *get_arm_SymConst_attr_const(const ir_node *node) { - assert(is_arm_SymConst(node)); +const arm_SymConst_attr_t *get_arm_SymConst_attr_const(const ir_node *node) +{ + assert(is_arm_SymConst(node) || is_arm_FrameAddr(node)); return get_irn_generic_attr_const(node); } @@ -199,24 +170,16 @@ static arm_fpaConst_attr_t *get_arm_fpaConst_attr(ir_node *node) { return fpa_attr; } -#ifndef NDEBUG -static int is_arm_CondJmp(const ir_node *node) { - int code = get_arm_irn_opcode(node); - - return (code == iro_arm_CmpBra || code == iro_arm_fpaCmfBra || - code == iro_arm_fpaCnfBra || iro_arm_fpaCmfeBra || - code == iro_arm_fpaCnfeBra); -} -#endif - /* Returns the attributes of a CondJmp node. */ -arm_CondJmp_attr_t *get_arm_CondJmp_attr(ir_node *node) { - assert(is_arm_CondJmp(node)); +arm_CondJmp_attr_t *get_arm_CondJmp_attr(ir_node *node) +{ + assert(is_arm_B(node)); return get_irn_generic_attr(node); } -const arm_CondJmp_attr_t *get_arm_CondJmp_attr_const(const ir_node *node) { - assert(is_arm_CondJmp(node)); +const arm_CondJmp_attr_t *get_arm_CondJmp_attr_const(const ir_node *node) +{ + assert(is_arm_B(node)); return get_irn_generic_attr_const(node); } @@ -255,22 +218,6 @@ void set_arm_req_in(ir_node *node, const arch_register_req_t *req, int pos) { attr->in_req[pos] = req; } -/** - * Returns the immediate value - */ -long get_arm_imm_value(const ir_node *node) { - const arm_attr_t *attr = get_arm_attr_const(node); - return attr->imm_value; -} - -/** - * Sets the tarval value - */ -void set_arm_imm_value(ir_node *node, long imm_value) { - arm_attr_t *attr = get_arm_attr(node); - attr->imm_value = imm_value; -} - /** * Returns the fpaConst value */ @@ -303,22 +250,6 @@ void set_arm_CondJmp_proj_num(ir_node *node, int proj_num) { attr->proj_num = proj_num; } -/** - * Returns the SymConst label - */ -ident *get_arm_symconst_id(const ir_node *node) { - const arm_SymConst_attr_t *attr = get_arm_SymConst_attr_const(node); - return attr->symconst_id; -} - -/** - * Sets the SymConst label - */ -void set_arm_symconst_id(ir_node *node, ident *symconst_id) { - arm_SymConst_attr_t *attr = get_arm_SymConst_attr(node); - attr->symconst_id = symconst_id; -} - /** * Returns the number of projs of a SwitchJmp. */ @@ -351,14 +282,6 @@ void set_arm_SwitchJmp_default_proj_num(ir_node *node, long default_proj_num) { attr->default_proj_num = default_proj_num; } -/** - * Gets the shift modifier attribute. - */ -arm_shift_modifier get_arm_shift_modifier(const ir_node *node) { - const arm_attr_t *attr = get_arm_attr_const(node); - return ARM_GET_SHF_MOD(attr); -} - /* Set the ARM machine node attributes to default values. */ static void init_arm_attributes(ir_node *node, int flags, const arch_register_req_t ** in_reqs, @@ -373,78 +296,66 @@ static void init_arm_attributes(ir_node *node, int flags, arch_irn_set_flags(node, flags); attr->in_req = in_reqs; - attr->instr_fl = (ARM_COND_AL << 3) | ARM_SHF_NONE; - attr->imm_value = 0; + attr->instr_fl = 0; info = be_get_info(node); info->out_infos = NEW_ARR_D(reg_out_info_t, obst, n_res); memset(info->out_infos, 0, n_res * sizeof(info->out_infos[0])); } -void init_arm_load_store_attributes(ir_node *res, ir_entity *entity, - int entity_sign, long offset) +static void init_arm_load_store_attributes(ir_node *res, ir_mode *ls_mode, + ir_entity *entity, + int entity_sign, long offset, + bool is_frame_entity) { arm_load_store_attr_t *attr = get_irn_generic_attr(res); - attr->entity = entity; - attr->entity_sign = entity_sign; - attr->offset = offset; -} - -/************************************************ - * ___ _ _ _ * - * / _ \ _ __ | |_(_)_ __ ___ (_)_______ _ __ * - * | | | | '_ \| __| | '_ ` _ \| |_ / _ \ '__| * - * | |_| | |_) | |_| | | | | | | |/ / __/ | * - * \___/| .__/ \__|_|_| |_| |_|_/___\___|_| * - * |_| * - ************************************************/ - -typedef struct _opt_tuple { - ir_op *op_imm_left; /**< immediate is left */ - ir_op *op_imm_right; /**< immediate is right */ - ir_op *op_shf_left; /**< shift operand on left */ - ir_op *op_shf_right; /**< shift operand on right */ -} opt_tuple; - -//static const opt_tuple *opt_ops[iro_arm_last]; - -void arm_set_optimizers(void) { - /* -#define STD(op) p_##op = { op_arm_##op##_i, op_arm_##op##_i, op_arm_##op, op_arm_##op } -#define LEFT(op) p_##op = { op_arm_##op##_i, NULL, op_arm_##op, NULL } -#define SET(op) opt_ops[iro_arm_##op] = &p_##op; - - static const opt_tuple - STD(Add), - STD(And), - STD(Or), - STD(Eor), - LEFT(Bic), - LEFT(Shl), - LEFT(Shr), - LEFT(Shrs), - p_Sub = { op_arm_Sub_i, op_arm_Rsb_i, op_arm_Sub, op_arm_Rsb }, - - memset(opt_ops, 0, sizeof(opt_ops)); - SET(Add); - SET(And); - SET(Or); - SET(Eor); - SET(Sub); - SET(Bic); - SET(Shl); - SET(Shr); - SET(Shrs); - */ -} - -static int cmp_attr_arm(ir_node *a, ir_node *b) { + attr->load_store_mode = ls_mode; + attr->entity = entity; + attr->entity_sign = entity_sign; + attr->is_frame_entity = is_frame_entity; + attr->offset = offset; + attr->base.is_load_store = true; +} + +static void init_arm_shifter_operand(ir_node *res, unsigned immediate_value, + arm_shift_modifier shift_modifier, + unsigned shift_immediate) +{ + arm_shifter_operand_t *attr = get_irn_generic_attr(res); + attr->immediate_value = immediate_value; + attr->shift_modifier = shift_modifier; + attr->shift_immediate = shift_immediate; +} + +static void init_arm_cmp_attr(ir_node *res, bool ins_permuted, bool is_unsigned) +{ + arm_cmp_attr_t *attr = get_irn_generic_attr(res); + attr->ins_permuted = ins_permuted; + attr->is_unsigned = is_unsigned; +} + +static void init_arm_SymConst_attributes(ir_node *res, ir_entity *entity) +{ + arm_SymConst_attr_t *attr = get_irn_generic_attr(res); + attr->entity = entity; + attr->fp_offset = 0; +} + +static void init_arm_CopyB_attributes(ir_node *res, unsigned size) +{ + arm_CopyB_attr_t *attr = get_irn_generic_attr(res); + attr->size = size; +} + +static int cmp_attr_arm(ir_node *a, ir_node *b) +{ arm_attr_t *attr_a = get_irn_generic_attr(a); arm_attr_t *attr_b = get_irn_generic_attr(b); - return (attr_a->instr_fl != attr_b->instr_fl) || (attr_a->imm_value != attr_b->imm_value); + return attr_a->instr_fl != attr_b->instr_fl; } -static int cmp_attr_arm_SymConst(ir_node *a, ir_node *b) { +static int cmp_attr_arm_SymConst(ir_node *a, ir_node *b) +{ const arm_SymConst_attr_t *attr_a; const arm_SymConst_attr_t *attr_b; @@ -453,24 +364,41 @@ static int cmp_attr_arm_SymConst(ir_node *a, ir_node *b) { attr_a = get_irn_generic_attr_const(a); attr_b = get_irn_generic_attr_const(b); - return attr_a->symconst_id != attr_b->symconst_id; + return attr_a->entity != attr_b->entity + || attr_a->fp_offset != attr_b->fp_offset; } -static int cmp_attr_arm_CondJmp(ir_node *a, ir_node *b) { +static int cmp_attr_arm_CopyB(ir_node *a, ir_node *b) +{ + const arm_CopyB_attr_t *attr_a; + const arm_CopyB_attr_t *attr_b; + + if (cmp_attr_arm(a, b)) + return 1; + + attr_a = get_irn_generic_attr_const(a); + attr_b = get_irn_generic_attr_const(b); + return attr_a->size != attr_b->size; +} + +static int cmp_attr_arm_CondJmp(ir_node *a, ir_node *b) +{ (void) a; (void) b; /* never identical */ return 1; } -static int cmp_attr_arm_SwitchJmp(ir_node *a, ir_node *b) { +static int cmp_attr_arm_SwitchJmp(ir_node *a, ir_node *b) +{ (void) a; (void) b; /* never identical */ return 1; } -static int cmp_attr_arm_fpaConst(ir_node *a, ir_node *b) { +static int cmp_attr_arm_fpaConst(ir_node *a, ir_node *b) +{ const arm_fpaConst_attr_t *attr_a; const arm_fpaConst_attr_t *attr_b; @@ -483,11 +411,22 @@ static int cmp_attr_arm_fpaConst(ir_node *a, ir_node *b) { return attr_a->tv != attr_b->tv; } + arm_load_store_attr_t *get_arm_load_store_attr(ir_node *node) { return (arm_load_store_attr_t*) get_irn_generic_attr(node); } +const arm_load_store_attr_t *get_arm_load_store_attr_const(const ir_node *node) +{ + return (const arm_load_store_attr_t*) get_irn_generic_attr_const(node); +} + +arm_shifter_operand_t *get_arm_shifter_operand_attr(ir_node *node) +{ + return (arm_shifter_operand_t*) get_irn_generic_attr(node); +} + static int cmp_attr_arm_load_store(ir_node *a, ir_node *b) { const arm_load_store_attr_t *attr_a; @@ -506,6 +445,40 @@ static int cmp_attr_arm_load_store(ir_node *a, ir_node *b) return 0; } +static int cmp_attr_arm_shifter_operand(ir_node *a, ir_node *b) +{ + const arm_shifter_operand_t *attr_a; + const arm_shifter_operand_t *attr_b; + + if (cmp_attr_arm(a, b)) + return 1; + + attr_a = get_arm_shifter_operand_attr(a); + attr_b = get_arm_shifter_operand_attr(b); + if (attr_a->shift_modifier != attr_b->shift_modifier + || attr_a->immediate_value != attr_b->immediate_value + || attr_a->shift_immediate != attr_b->shift_immediate) + return 1; + + return 0; +} + +static int cmp_attr_arm_cmp(ir_node *a, ir_node *b) +{ + const arm_cmp_attr_t *attr_a; + const arm_cmp_attr_t *attr_b; + + if (cmp_attr_arm(a, b)) + return 1; + + attr_a = get_irn_generic_attr_const(a); + attr_b = get_irn_generic_attr_const(b); + if (attr_a->ins_permuted != attr_b->ins_permuted + || attr_a->is_unsigned != attr_b->is_unsigned) + return 1; + return 0; +} + /** copies the ARM attributes of a node. */ static void arm_copy_attr(const ir_node *old_node, ir_node *new_node) { ir_graph *irg = get_irn_irg(new_node); diff --git a/ir/be/arm/arm_new_nodes.h b/ir/be/arm/arm_new_nodes.h index 31cdbab78..9c3bb23af 100644 --- a/ir/be/arm/arm_new_nodes.h +++ b/ir/be/arm/arm_new_nodes.h @@ -29,17 +29,6 @@ #include "arm_nodes_attr.h" #include "bearch_arm_t.h" -/*************************************************************************************************** - * _ _ _ __ _ _ _ _ - * | | | | | | / / | | | | | | | | - * __ _| |_| |_ _ __ ___ ___| |_ / /_ _ ___| |_ _ __ ___ ___| |_| |__ ___ __| |___ - * / _` | __| __| '__| / __|/ _ \ __| / / _` |/ _ \ __| | '_ ` _ \ / _ \ __| '_ \ / _ \ / _` / __| - * | (_| | |_| |_| | \__ \ __/ |_ / / (_| | __/ |_ | | | | | | __/ |_| | | | (_) | (_| \__ \ - * \__,_|\__|\__|_| |___/\___|\__/_/ \__, |\___|\__| |_| |_| |_|\___|\__|_| |_|\___/ \__,_|___/ - * __/ | - * |___/ - ***************************************************************************************************/ - /** * Returns the attributes of a generic Arm node. */ @@ -64,6 +53,9 @@ const arm_CondJmp_attr_t *get_arm_CondJmp_attr_const(const ir_node *node); arm_SwitchJmp_attr_t *get_arm_SwitchJmp_attr(ir_node *node); const arm_SwitchJmp_attr_t *get_arm_SwitchJmp_attr_const(const ir_node *node); +arm_load_store_attr_t *get_arm_load_store_attr(ir_node *node); +const arm_load_store_attr_t *get_arm_load_store_attr_const(const ir_node *node); + /** * Returns the argument register requirements of an arm node. */ @@ -79,16 +71,6 @@ const arch_register_req_t *get_arm_in_req(const ir_node *node, int pos); */ void set_arm_req_in(ir_node *node, const arch_register_req_t *req, int pos); -/** - * Returns the immediate value - */ -long get_arm_imm_value(const ir_node *node); - -/** - * Sets the immediate value - */ -void set_arm_imm_value(ir_node *node, long imm_value); - /** * Return the tarval of a fpaConst */ @@ -109,9 +91,6 @@ int get_arm_CondJmp_proj_num(const ir_node *node); */ void set_arm_CondJmp_proj_num(ir_node *node, int proj_num); -ident *get_arm_symconst_id(const ir_node *node); -void set_arm_symconst_id(ir_node *node, ident *symconst_id); - ir_node *new_r_arm_StoreStackMInc(ir_graph *irg, ir_node *block, ir_node *mem, ir_node *sp, int n_regs, ir_node **regs, ir_mode *mode); @@ -140,9 +119,6 @@ void set_arm_SwitchJmp_default_proj_num(ir_node *node, long default_proj_num); */ arm_shift_modifier get_arm_shift_modifier(const ir_node *node); -void init_arm_load_store_attributes(ir_node *res, ir_entity *entity, - int entity_sign, long offset); - /* Include the generated headers */ #include "gen_arm_new_nodes.h" diff --git a/ir/be/arm/arm_nodes_attr.h b/ir/be/arm/arm_nodes_attr.h index 4b546ee51..df4d42145 100644 --- a/ir/be/arm/arm_nodes_attr.h +++ b/ir/be/arm/arm_nodes_attr.h @@ -31,27 +31,23 @@ #include "../bearch.h" /** - * Possible ARM register shift types. + * Possible ARM "shifter operand" addressing mode types. */ typedef enum _arm_shift_modifier { - ARM_SHF_NONE = 0, /**< no shift */ - ARM_SHF_IMM = 1, /**< immediate operand with implicit ROR */ - ARM_SHF_ASR = 2, /**< arithmetic shift right */ - ARM_SHF_LSL = 3, /**< logical shift left */ - ARM_SHF_LSR = 4, /**< logical shift right */ - ARM_SHF_ROR = 5, /**< rotate right */ - ARM_SHF_RRX = 6, /**< rotate right through carry bits */ + ARM_SHF_INVALID, /**< invalid shift */ + ARM_SHF_REG, /**< simple register operand */ + ARM_SHF_IMM, /**< immediate operand with implicit ROR */ + ARM_SHF_ASR_IMM, /**< arithmetic shift right */ + ARM_SHF_ASR_REG, /**< arithmetic shift right */ + ARM_SHF_LSL_IMM, /**< logical shift left */ + ARM_SHF_LSL_REG, /**< logical shift left */ + ARM_SHF_LSR_IMM, /**< logical shift right */ + ARM_SHF_LSR_REG, /**< logical shift right */ + ARM_SHF_ROR_IMM, /**< rotate right */ + ARM_SHF_ROR_REG, /**< rotate right */ + ARM_SHF_RRX, /**< rotate right through carry bits */ } arm_shift_modifier; -/** True, if the modifier implies a shift argument */ -#define ARM_HAS_SHIFT(mod) ((mod) > ARM_SHF_IMM) - -/** get the shift modifier from flags */ -#define ARM_GET_SHF_MOD(attr) ((attr)->instr_fl & 7) - -/** set the shift modifier to flags */ -#define ARM_SET_SHF_MOD(attr, mod) ((attr)->instr_fl = (((attr)->instr_fl & ~7) | (mod))) - /** fpa immediate bit */ #define ARM_FPA_IMM (1 << 3) /**< fpa floating point immediate */ @@ -59,34 +55,6 @@ typedef enum _arm_shift_modifier { #define ARM_SET_FPA_IMM(attr) ((attr)->instr_fl |= ARM_FPA_IMM) #define ARM_CLR_FPA_IMM(attr) ((attr)->instr_fl &= ~ARM_FPA_IMM) -/** - * Possible ARM condition codes. - */ -typedef enum _arm_condition { - ARM_COND_EQ = 0, /**< Equal, Z set. */ - ARM_COND_NE = 1, /**< Not Equal, Z clear */ - ARM_COND_CS = 2, /**< Carry set, unsigned >=, C set */ - ARM_COND_CC = 3, /**< Carry clear, unsigned <, C clear */ - ARM_COND_MI = 4, /**< Minus/Negative, N set */ - ARM_COND_PL = 5, /**< Plus/Positive or Zero, N clear */ - ARM_COND_VS = 6, /**< Overflow, V set */ - ARM_COND_VC = 7, /**< No overflow, V clear */ - ARM_COND_HI = 8, /**< unsigned >, C set and Z clear */ - ARM_COND_LS = 9, /**< unsigned <=, C clear or Z set */ - ARM_COND_GE = 10, /**< signed >=, N == V */ - ARM_COND_LT = 11, /**< signed <, N != V */ - ARM_COND_GT = 12, /**< signed >, Z clear and N == V */ - ARM_COND_LE = 13, /**< signed <=, Z set or N != V */ - ARM_COND_AL = 14, /**< Always (unconditional) */ - ARM_COND_NV = 15 /**< forbidden */ -} arm_condition; - -/** Get the condition code from flags */ -#define ARM_GET_COND(attr) (((attr)->instr_fl >> 4) & 15) - -/** Set the condition code to flags */ -#define ARM_SET_COND(attr, code) ((attr)->instr_fl = (((attr)->instr_fl & ~(15 << 4)) | ((code) << 4))) - /** Encoding for fpa immediates */ enum fpa_immediates { fpa_null = 0, @@ -106,48 +74,73 @@ typedef struct _arm_attr_t { const arch_register_req_t **in_req; /**< register requirements for arguments */ - ir_mode *op_mode; /**< operation mode if different from node's mode */ - unsigned instr_fl; /**< condition code, shift modifier */ - long imm_value; /**< immediate */ + ir_mode *op_mode; /**< operation mode if different from node's mode (used for fpa nodes) */ + unsigned instr_fl; /**< deprecated (was sometimes used for shift modifiers) */ + bool is_load_store : 1; } arm_attr_t; +/** + * This struct holds information needed to produce the arm + * "data processing operands" also called "shifter operand" addressing modes + */ +typedef struct arm_shifter_operand_t { + arm_attr_t base; + arm_shift_modifier shift_modifier; + unsigned char immediate_value; + unsigned char shift_immediate; +} arm_shifter_operand_t; + +typedef struct arm_cmp_attr_t { + arm_shifter_operand_t base; + bool ins_permuted : 1; + bool is_unsigned : 1; +} arm_cmp_attr_t; + +/** + * this struct holds information needed to produce the arm addressing modes + * for "Load and Store Word or Unsigned Byte", "Miscellaneous Loads and Stores" + * and "Load and Store Multiple" */ typedef struct arm_load_store_attr_t { - arm_attr_t attr; + arm_attr_t base; + ir_mode *load_store_mode; ir_entity *entity; long offset; - bool entity_sign : 1; + bool is_frame_entity : 1; + bool entity_sign : 1; } arm_load_store_attr_t; /** Attributes for a SymConst */ typedef struct _arm_SymConst_attr_t { - arm_attr_t attr; /**< base attributes */ - ident *symconst_id; /**< for SymConsts: its ident */ + arm_attr_t base; + ir_entity *entity; + int fp_offset; } arm_SymConst_attr_t; /** Attributes for a CondJmp */ typedef struct _arm_CondJmp_attr_t { - arm_attr_t attr; /**< base attributes */ + arm_attr_t base; int proj_num; } arm_CondJmp_attr_t; /** Attributes for a SwitchJmp */ typedef struct _arm_SwitchJmp_attr_t { - arm_attr_t attr; /**< base attributes */ + arm_attr_t base; int n_projs; long default_proj_num; } arm_SwitchJmp_attr_t; +/** CopyB attributes */ +typedef struct { + arm_attr_t base; + unsigned size; +} arm_CopyB_attr_t; + /** Attributes for a fpaConst */ typedef struct _arm_fpaConst_attr_t { - arm_attr_t attr; /**< base attributes */ - tarval *tv; /**< the tarval representing the FP const */ + arm_attr_t base; + tarval *tv; /**< the tarval representing the FP const */ } arm_fpaConst_attr_t; -/** - * Returns the shift modifier string. - */ -const char *arm_shf_mod_name(arm_shift_modifier mod); - /** * Return the fpa immediate from the encoding. */ diff --git a/ir/be/arm/arm_optimize.c b/ir/be/arm/arm_optimize.c index 64e49a6f8..fd4e0eb3d 100644 --- a/ir/be/arm/arm_optimize.c +++ b/ir/be/arm/arm_optimize.c @@ -27,6 +27,7 @@ #include "irgmod.h" #include "ircons.h" +#include "iredges.h" #include "error.h" #include "benode.h" @@ -36,12 +37,14 @@ #include "arm_optimize.h" #include "gen_arm_regalloc_if.h" #include "gen_arm_new_nodes.h" +#include "arm_nodes_attr.h" +#include "arm_new_nodes.h" static arm_code_gen_t *cg; -/** Execute ARM ROL. */ -static unsigned arm_rol(unsigned v, unsigned rol) { - return (v << rol) | (v >> (32 - rol)); +static unsigned arm_ror(unsigned v, unsigned ror) +{ + return (v << (32 - ror)) | (v >> ror); } /* @@ -51,61 +54,38 @@ void arm_gen_vals_from_word(unsigned int value, arm_vals *result) { int initial = 0; - memset(result, 0, sizeof(*result)); + /* TODO: not optimal yet, as we only "shift" the value and don't take advantage of rotations */ /* special case: we prefer shift amount 0 */ - if (value < 0x100) { + if (value <= 0xFF) { result->values[0] = value; + result->rors[0] = 0; result->ops = 1; return; } - while (value != 0) { - if (value & 0xFF) { - unsigned v = arm_rol(value, 8) & 0xFFFFFF; - int shf = 0; - for (;;) { - if ((v & 3) != 0) - break; - shf += 2; - v >>= 2; - } - v &= 0xFF; - shf = (initial + shf - 8) & 0x1F; - result->values[result->ops] = v; - result->shifts[result->ops] = shf; - ++result->ops; - - value ^= arm_rol(v, shf) >> initial; - } - else { - value >>= 8; - initial += 8; + result->ops = 0; + do { + while ( (value & 0x3) == 0) { + value >>= 2; + initial += 2; } - } -} -/** - * Encodes an immediate with shifter operand - */ -unsigned int arm_encode_imm_w_shift(unsigned int shift, unsigned int immediate) { - return immediate | ((shift>>1)<<8); -} + result->values[result->ops] = value & 0xFF; + result->rors[result->ops] = (32-initial) % 32; + ++result->ops; -/** - * Decode an immediate with shifter operand - */ -unsigned int arm_decode_imm_w_shift(long imm_value) { - unsigned l = (unsigned)imm_value; - unsigned rol = (l & ~0xFF) >> 7; - - return arm_rol(l & 0xFF, rol); + value >>= 8; + initial += 8; + } while(value != 0); } /** - * Returns non.zero if the given offset can be directly encoded into an ARM instruction. + * Returns non.zero if the given offset can be directly encoded into an ARM + * instruction. */ -static int allowed_arm_immediate(int offset, arm_vals *result) { +static int allowed_arm_immediate(int offset, arm_vals *result) +{ arm_gen_vals_from_word(offset, result); return result->ops <= 1; } @@ -113,10 +93,17 @@ static int allowed_arm_immediate(int offset, arm_vals *result) { /** * Fix an IncSP node if the offset gets too big */ -static void peephole_be_IncSP(ir_node *node) { +static void peephole_be_IncSP(ir_node *node) +{ + ir_node *first; + ir_node *last; ir_node *block; - int offset, cnt, align, sign = 1; - arm_vals v; + int offset; + int cnt; + int sign = 1; + arm_vals v; + const ir_edge_t *edge; + const ir_edge_t *next; /* first optimize incsp->incsp combinations */ node = be_peephole_IncSP_IncSP(node); @@ -130,16 +117,28 @@ static void peephole_be_IncSP(ir_node *node) { if (allowed_arm_immediate(offset, &v)) return; - be_set_IncSP_offset(node, (int)arm_rol(v.values[0], v.shifts[0]) * sign); + be_set_IncSP_offset(node, sign * arm_ror(v.values[0], v.rors[0])); + first = node; block = get_nodes_block(node); - align = be_get_IncSP_align(node); for (cnt = 1; cnt < v.ops; ++cnt) { - int value = (int)arm_rol(v.values[cnt], v.shifts[cnt]); - ir_node *next = be_new_IncSP(&arm_gp_regs[REG_SP], block, node, value * sign, align); + int value = sign * arm_ror(v.values[cnt], v.rors[cnt]); + ir_node *next = be_new_IncSP(&arm_gp_regs[REG_SP], block, node, + value, 1); sched_add_after(node, next); node = next; } + + /* reattach IncSP users */ + last = node; + node = sched_next(first); + foreach_out_edge_safe(first, edge, next) { + ir_node *user = get_edge_src_irn(edge); + int pos = get_edge_src_pos(edge); + if (user == node) + continue; + set_irn_n(user, pos, last); + } } /** @@ -147,18 +146,18 @@ static void peephole_be_IncSP(ir_node *node) { */ static ir_node *gen_ptr_add(ir_node *node, ir_node *frame, arm_vals *v) { - dbg_info *dbg = get_irn_dbg_info(node); + dbg_info *dbgi = get_irn_dbg_info(node); ir_node *block = get_nodes_block(node); int cnt; ir_node *ptr; - ptr = new_bd_arm_Add_i(dbg, block, frame, mode_Iu, arm_encode_imm_w_shift(v->shifts[0], v->values[0])); + ptr = new_bd_arm_Add_imm(dbgi, block, frame, v->values[0], v->rors[0]); arch_set_irn_register(ptr, &arm_gp_regs[REG_R12]); sched_add_before(node, ptr); for (cnt = 1; cnt < v->ops; ++cnt) { - long value = arm_encode_imm_w_shift(v->shifts[cnt], v->values[cnt]); - ir_node *next = new_bd_arm_Add_i(dbg, block, ptr, mode_Iu, value); + ir_node *next = new_bd_arm_Add_imm(dbgi, block, ptr, v->values[cnt], + v->rors[cnt]); arch_set_irn_register(next, &arm_gp_regs[REG_R12]); sched_add_before(node, next); ptr = next; @@ -171,18 +170,18 @@ static ir_node *gen_ptr_add(ir_node *node, ir_node *frame, arm_vals *v) */ static ir_node *gen_ptr_sub(ir_node *node, ir_node *frame, arm_vals *v) { - dbg_info *dbg = get_irn_dbg_info(node); + dbg_info *dbgi = get_irn_dbg_info(node); ir_node *block = get_nodes_block(node); int cnt; ir_node *ptr; - ptr = new_bd_arm_Sub_i(dbg, block, frame, mode_Iu, arm_encode_imm_w_shift(v->shifts[0], v->values[0])); + ptr = new_bd_arm_Sub_imm(dbgi, block, frame, v->values[0], v->rors[0]); arch_set_irn_register(ptr, &arm_gp_regs[REG_R12]); sched_add_before(node, ptr); for (cnt = 1; cnt < v->ops; ++cnt) { - long value = arm_encode_imm_w_shift(v->shifts[cnt], v->values[cnt]); - ir_node *next = new_bd_arm_Sub_i(dbg, block, ptr, mode_Iu, value); + ir_node *next = new_bd_arm_Sub_imm(dbgi, block, ptr, v->values[cnt], + v->rors[cnt]); arch_set_irn_register(next, &arm_gp_regs[REG_R12]); sched_add_before(node, next); ptr = next; @@ -190,117 +189,79 @@ static ir_node *gen_ptr_sub(ir_node *node, ir_node *frame, arm_vals *v) return ptr; } -/** - * Fix an be_Spill node if the offset gets too big - */ -static void peephole_be_Spill(ir_node *node) { - ir_entity *ent = be_get_frame_entity(node); - int use_add = 1, offset = get_entity_offset(ent); - ir_node *block, *ptr, *frame, *value, *store; - ir_mode *mode; - dbg_info *dbg; - ir_graph *irg; - arm_vals v; +/** fix frame addresses which are too big */ +static void peephole_arm_FrameAddr(ir_node *node) +{ + arm_SymConst_attr_t *attr = get_arm_SymConst_attr(node); + int offset = attr->fp_offset; + arm_vals v; + ir_node *base; + ir_node *ptr; if (allowed_arm_immediate(offset, &v)) return; - if (offset < 0) { - use_add = 0; - offset = -offset; - } - - frame = be_get_Spill_frame(node); - if (use_add) { - ptr = gen_ptr_add(node, frame, &v); - } else { - ptr = gen_ptr_sub(node, frame, &v); - } - value = be_get_Spill_val(node); - mode = get_irn_mode(value); - irg = current_ir_graph; - dbg = get_irn_dbg_info(node); - block = get_nodes_block(node); + base = get_irn_n(node, n_arm_FrameAddr_base); + /* TODO: suboptimal */ + ptr = gen_ptr_add(node, base, &v); - if (mode_is_float(mode)) { - if (USE_FPA(cg->isa)) { - /* transform into fpaStf */ - store = new_bd_arm_fpaStf(dbg, block, ptr, value, get_irg_no_mem(irg), mode); - sched_add_before(node, store); - } else { - panic("peephole_be_Spill: spill not supported for this mode"); - } - } else if (mode_is_dataM(mode)) { - /* transform into Store */; - store = new_bd_arm_Str(dbg, block, ptr, value, get_irg_no_mem(irg), - NULL, 0, 0); - sched_add_before(node, store); - } else { - panic("peephole_be_Spill: spill not supported for this mode"); - } - - be_peephole_exchange(node, store); + attr->fp_offset = 0; + set_irn_n(node, n_arm_FrameAddr_base, ptr); } /** - * Fix an be_Reload node if the offset gets too big + * Fix stackpointer relative stores if the offset gets too big */ -static void peephole_be_Reload(ir_node *node) { - ir_entity *ent = be_get_frame_entity(node); - int use_add = 1, offset = get_entity_offset(ent); - ir_node *block, *ptr, *frame, *load, *mem, *proj; - ir_mode *mode; - dbg_info *dbg; - arm_vals v; - const arch_register_t *reg; +static void peephole_arm_Str_Ldr(ir_node *node) +{ + arm_load_store_attr_t *attr = get_arm_load_store_attr(node); + int offset = attr->offset; + int use_add = 1; + ir_node *ptr; + arm_vals v; if (allowed_arm_immediate(offset, &v)) return; + + /* we should only have too big offsets for frame entities */ + if (!attr->is_frame_entity) { + fprintf(stderr, + "POSSIBLE ARM BACKEND PROBLEM: offset in Store too big\n"); + } if (offset < 0) { use_add = 0; offset = -offset; } - frame = be_get_Reload_frame(node); - if (use_add) { - ptr = gen_ptr_add(node, frame, &v); + if (is_arm_Str(node)) { + ptr = get_irn_n(node, n_arm_Str_ptr); } else { - ptr = gen_ptr_sub(node, frame, &v); + assert(is_arm_Ldr(node)); + ptr = get_irn_n(node, n_arm_Ldr_ptr); } - reg = arch_get_irn_register(node); - mem = be_get_Reload_mem(node); - mode = get_irn_mode(node); - dbg = get_irn_dbg_info(node); - block = get_nodes_block(node); - - if (mode_is_float(mode)) { - if (USE_FPA(cg->isa)) { - /* transform into fpaLdf */ - load = new_bd_arm_fpaLdf(dbg, block, ptr, mem, mode); - sched_add_before(node, load); - proj = new_rd_Proj(dbg, block, load, mode, pn_arm_fpaLdf_res); - arch_set_irn_register(proj, reg); - } else { - panic("peephole_be_Spill: spill not supported for this mode"); - } - } else if (mode_is_dataM(mode)) { - /* transform into Store */; - load = new_bd_arm_Ldr(dbg, block, ptr, mem, NULL, 0, 0); - sched_add_before(node, load); - proj = new_rd_Proj(dbg, block, load, mode_Iu, pn_arm_Ldr_res); - arch_set_irn_register(proj, reg); + if (use_add) { + ptr = gen_ptr_add(node, ptr, &v); } else { - panic("peephole_be_Spill: spill not supported for this mode"); + ptr = gen_ptr_sub(node, ptr, &v); } - be_peephole_exchange(node, proj); + /* TODO: sub-optimal, the last offset could probably be left inside the + store */ + if (is_arm_Str(node)) { + set_irn_n(node, n_arm_Str_ptr, ptr); + } else { + assert(is_arm_Ldr(node)); + set_irn_n(node, n_arm_Ldr_ptr, ptr); + } + attr->offset = 0; } /** * Register a peephole optimization function. */ -static void register_peephole_optimisation(ir_op *op, peephole_opt_func func) { +static void register_peephole_optimisation(ir_op *op, peephole_opt_func func) +{ assert(op->ops.generic == NULL); op->ops.generic = (op_func)func; } @@ -312,9 +273,10 @@ void arm_peephole_optimization(arm_code_gen_t *new_cg) /* register peephole optimizations */ clear_irp_opcodes_generic_func(); - register_peephole_optimisation(op_be_IncSP, peephole_be_IncSP); - register_peephole_optimisation(op_be_Spill, peephole_be_Spill); - register_peephole_optimisation(op_be_Reload, peephole_be_Reload); + register_peephole_optimisation(op_be_IncSP, peephole_be_IncSP); + register_peephole_optimisation(op_arm_Str, peephole_arm_Str_Ldr); + register_peephole_optimisation(op_arm_Ldr, peephole_arm_Str_Ldr); + register_peephole_optimisation(op_arm_FrameAddr, peephole_arm_FrameAddr); be_peephole_opt(cg->birg); } diff --git a/ir/be/arm/arm_optimize.h b/ir/be/arm/arm_optimize.h index 92f724364..9f487f526 100644 --- a/ir/be/arm/arm_optimize.h +++ b/ir/be/arm/arm_optimize.h @@ -32,7 +32,7 @@ typedef struct arm_vals { int ops; unsigned char values[4]; - unsigned char shifts[4]; + unsigned char rors[4]; } arm_vals; /** diff --git a/ir/be/arm/arm_spec.pl b/ir/be/arm/arm_spec.pl index a3c6033c8..968b36443 100644 --- a/ir/be/arm/arm_spec.pl +++ b/ir/be/arm/arm_spec.pl @@ -1,18 +1,15 @@ # Creation: 2006/02/13 # $Id$ -# This is a template specification for the Firm-Backend # the cpu architecture (ia32, ia64, mips, sparc, ppc, ...) $arch = "arm"; -# the number of additional opcodes you want to register -#$additional_opcodes = 0; - # # Modes # $mode_gp = "mode_Iu"; +$mode_flags = "mode_Bu"; $mode_fpa = "mode_E"; # register types: @@ -38,11 +35,10 @@ $state = 32; # register represents a state { name => "r9", type => $callee_save }, { name => "r10", type => $callee_save }, { name => "r11", type => $callee_save }, - { name => "r12", type => $ignore | $callee_save }, # reserved for linker - { name => "sp", type => $ignore | $callee_save }, # this is our stack pointer + { name => "r12", type => $ignore }, # reserved for linker/immediate fixups + { name => "sp", type => $ignore }, # this is our stack pointer { name => "lr", type => $callee_save | $caller_save }, # this is our return address - { name => "pc", type => $ignore | $callee_save }, # this is our program counter - { name => "gp_UKNWN", type => $ignore | $arbitrary | $virtual }, # we need a dummy register for Unknown nodes + { name => "pc", type => $ignore }, # this is our program counter { mode => $mode_gp } ], fpa => [ @@ -54,49 +50,51 @@ $state = 32; # register represents a state { name => "f5", type => $caller_save }, { name => "f6", type => $caller_save }, { name => "f7", type => $caller_save }, - { name => "fpa_UKNWN", type => $ignore | $arbitrary | $virtual }, # we need a dummy register for Unknown nodes { mode => $mode_fpa } - ] + ], + flags => [ + { name => "fl", type => 0 }, + { mode => $mode_flags, flags => "manual_ra" } + ], ); %emit_templates = ( - M => "${arch}_emit_mode(node);", - X => "${arch}_emit_shift(node);", - S0 => "${arch}_emit_source_register(node, 0);", - S1 => "${arch}_emit_source_register(node, 1);", - S2 => "${arch}_emit_source_register(node, 2);", - S3 => "${arch}_emit_source_register(node, 3);", - S4 => "${arch}_emit_source_register(node, 4);", - D0 => "${arch}_emit_dest_register(node, 0);", - D1 => "${arch}_emit_dest_register(node, 1);", - D2 => "${arch}_emit_dest_register(node, 2);", - C => "${arch}_emit_immediate(node);", - O => "${arch}_emit_offset(mode);", + M => "${arch}_emit_mode(node);", + LM => "${arch}_emit_load_mode(node);", + SM => "${arch}_emit_store_mode(node);", + SO => "${arch}_emit_shifter_operand(node);", + S0 => "${arch}_emit_source_register(node, 0);", + S1 => "${arch}_emit_source_register(node, 1);", + S2 => "${arch}_emit_source_register(node, 2);", + S3 => "${arch}_emit_source_register(node, 3);", + S4 => "${arch}_emit_source_register(node, 4);", + D0 => "${arch}_emit_dest_register(node, 0);", + D1 => "${arch}_emit_dest_register(node, 1);", + D2 => "${arch}_emit_dest_register(node, 2);", + O => "${arch}_emit_offset(node);", ); -#--------------------------------------------------# -# _ # -# (_) # -# _ __ _____ __ _ _ __ ___ _ __ ___ # -# | '_ \ / _ \ \ /\ / / | | '__| / _ \| '_ \/ __| # -# | | | | __/\ V V / | | | | (_) | |_) \__ \ # -# |_| |_|\___| \_/\_/ |_|_| \___/| .__/|___/ # -# | | # -# |_| # -#--------------------------------------------------# - $default_attr_type = "arm_attr_t"; $default_copy_attr = "arm_copy_attr"; %init_attr = ( arm_attr_t => "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);", - arm_SymConst_attr_t => "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);", + arm_SymConst_attr_t => + "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);\n". + "\tinit_arm_SymConst_attributes(res, entity);", arm_CondJmp_attr_t => "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);", arm_SwitchJmp_attr_t => "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);", arm_fpaConst_attr_t => "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);", arm_load_store_attr_t => "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);\n". - "\tinit_arm_load_store_attributes(res, entity, entity_sign, offset);", + "\tinit_arm_load_store_attributes(res, ls_mode, entity, entity_sign, offset, is_frame_entity);", + arm_shifter_operand_t => + "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);\n", + arm_cmp_attr_t => + "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);\n", + arm_CopyB_attr_t => + "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);\n". + "\tinit_arm_CopyB_attributes(res, size);", ); %compare_attr = ( @@ -106,380 +104,272 @@ $default_copy_attr = "arm_copy_attr"; arm_SwitchJmp_attr_t => "cmp_attr_arm_SwitchJmp", arm_fpaConst_attr_t => "cmp_attr_arm_fpaConst", arm_load_store_attr_t => "cmp_attr_arm_load_store", + arm_shifter_operand_t => "cmp_attr_arm_shifter_operand", + arm_CopyB_attr_t => "cmp_attr_arm_CopyB", + arm_cmp_attr_t => "cmp_attr_arm_cmp", ); -#%operands = ( -# -#Immediate => { -# comment => "blup di dup", -# irn_flags => "R", -# emit => ". [%S0]-10", -# reg_req => { }, -# attr => "tarval *tv", -# init_attr => "(void) attri;", -# # op_flags => O -# # cmp => "return 1;" -#}, -# -#ShfOp_I => { -# irn_flags => "R", -# emit => ". ...", -# reg_req => { in => [ "gp" ] }, -# attr => "tarval *tv", -# init_attr => "(void) tv;", -#}, -# -#ShfOp => { -# irn_flags => "R", -# emit => ". ...", -# reg_req => { in => [ "gp", "gp" ] }, -#}, -# -#); - -%nodes = ( +my %unop_shifter_operand_constructors = ( + imm => { + attr => "unsigned char immediate_value, unsigned char immediate_rot", + custominit => "init_arm_shifter_operand(res, immediate_value, ARM_SHF_IMM, immediate_rot);", + reg_req => { in => [], out => [ "gp" ] }, + }, + reg => { + custominit => "init_arm_shifter_operand(res, 0, ARM_SHF_REG, 0);", + reg_req => { in => [ "gp" ], out => [ "gp" ] }, + }, + reg_shift_reg => { + attr => "arm_shift_modifier shift_modifier", + custominit => "init_arm_shifter_operand(res, 0, shift_modifier, 0);", + reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] }, + }, + reg_shift_imm => { + attr => "arm_shift_modifier shift_modifier, unsigned shift_immediate", + custominit => "init_arm_shifter_operand(res, 0, shift_modifier, shift_immediate);", + reg_req => { in => [ "gp" ], out => [ "gp" ] }, + }, +); -Unknown_GP => { - state => "pinned", - op_flags => "c", - reg_req => { out => [ "gp_UKNWN:I" ] }, - emit => "", - mode => $mode_gp, -}, +my %binop_shifter_operand_constructors = ( + imm => { + attr => "unsigned char immediate_value, unsigned char immediate_rot", + custominit => "init_arm_shifter_operand(res, immediate_value, ARM_SHF_IMM, immediate_rot);", + reg_req => { in => [ "gp" ], out => [ "gp" ] }, + ins => [ "left" ], + }, + reg => { + custominit => "init_arm_shifter_operand(res, 0, ARM_SHF_REG, 0);", + reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] }, + ins => [ "left", "right" ], + }, + reg_shift_reg => { + attr => "arm_shift_modifier shift_modifier", + custominit => "init_arm_shifter_operand(res, 0, shift_modifier, 0);", + reg_req => { in => [ "gp", "gp", "gp" ], out => [ "gp" ] }, + ins => [ "left", "right", "shift" ], + }, + reg_shift_imm => { + attr => "arm_shift_modifier shift_modifier, unsigned shift_immediate", + custominit => "init_arm_shifter_operand(res, 0, shift_modifier, shift_immediate);", + reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] }, + ins => [ "left", "right" ], + }, +); -Unknown_FPA => { - state => "pinned", - op_flags => "c", - reg_req => { out => [ "fpa_UKNWN:I" ] }, - emit => "", - mode => $mode_fpa, -}, +my %cmp_shifter_operand_constructors = ( + imm => { + attr => "unsigned char immediate_value, unsigned char immediate_rot, bool ins_permuted, bool is_unsigned", + custominit => + "init_arm_shifter_operand(res, immediate_value, ARM_SHF_IMM, immediate_rot);\n". + "\tinit_arm_cmp_attr(res, ins_permuted, is_unsigned);", + reg_req => { in => [ "gp" ], out => [ "flags" ] }, + ins => [ "left" ], + }, + reg => { + attr => "bool ins_permuted, bool is_unsigned", + custominit => + "init_arm_shifter_operand(res, 0, ARM_SHF_REG, 0);\n". + "\tinit_arm_cmp_attr(res, ins_permuted, is_unsigned);", + reg_req => { in => [ "gp", "gp" ], out => [ "flags" ] }, + ins => [ "left", "right" ], + }, + reg_shift_reg => { + attr => "arm_shift_modifier shift_modifier, bool ins_permuted, bool is_unsigned", + custominit => + "init_arm_shifter_operand(res, 0, shift_modifier, 0);\n". + "\tinit_arm_cmp_attr(res, ins_permuted, is_unsigned);", + reg_req => { in => [ "gp", "gp", "gp" ], out => [ "flags" ] }, + ins => [ "left", "right", "shift" ], + }, + reg_shift_imm => { + attr => "arm_shift_modifier shift_modifier, unsigned shift_immediate, bool ins_permuted, bool is_unsigned", + custominit => + "init_arm_shifter_operand(res, 0, shift_modifier, shift_immediate);\n". + "\tinit_arm_cmp_attr(res, ins_permuted, is_unsigned);", + reg_req => { in => [ "gp", "gp" ], out => [ "flags" ] }, + ins => [ "left", "right" ], + }, +); -#-----------------------------------------------------------------# -# _ _ _ # -# (_) | | | | # -# _ _ __ | |_ ___ __ _ ___ _ __ _ __ ___ __| | ___ ___ # -# | | '_ \| __/ _ \/ _` |/ _ \ '__| | '_ \ / _ \ / _` |/ _ \/ __| # -# | | | | | || __/ (_| | __/ | | | | | (_) | (_| | __/\__ \ # -# |_|_| |_|\__\___|\__, |\___|_| |_| |_|\___/ \__,_|\___||___/ # -# __/ | # -# |___/ # -#-----------------------------------------------------------------# -# commutative operations +%nodes = ( Add => { - op_flags => "C", irn_flags => "R", - comment => "construct Add: Add(a, b) = Add(b, a) = a + b", - attr => "arm_shift_modifier mod, long shf", - init_attr => 'ARM_SET_SHF_MOD(attr, mod); attr->imm_value = shf;', - reg_req => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, - emit => '. add %D0, %S0, %S1%X' -}, - -Add_i => { - irn_flags => "R", - comment => "construct Add: Add(a, const) = Add(const, a) = a + const", - attr => "long imm", - init_attr => 'ARM_SET_SHF_MOD(attr, ARM_SHF_IMM); attr->imm_value = imm;', - reg_req => { "in" => [ "gp" ], "out" => [ "gp" ] }, - emit => '. add %D0, %S0, %C' + emit => '. add %D0, %S0, %SO', + mode => $mode_gp, + attr_type => "arm_shifter_operand_t", + constructors => \%binop_shifter_operand_constructors, }, Mul => { - #op_flags => "C", irn_flags => "R", - comment => "construct Mul: Mul(a, b) = Mul(b, a) = a * b", - reg_req => { "in" => [ "gp", "gp" ], "out" => [ "!in_r1" ] }, - emit =>'. mul %D0, %S0, %S1' + reg_req => { in => [ "gp", "gp" ], out => [ "!in_r1" ] }, + emit =>'. mul %D0, %S0, %S1', + mode => $mode_gp, }, Smull => { - #op_flags => "C", irn_flags => "R", - comment => "construct signed 64bit Mul: Mul(a, b) = Mul(b, a) = a * b", - reg_req => { "in" => [ "gp", "gp" ], "out" => [ "gp", "gp" ] }, + reg_req => { in => [ "gp", "gp" ], out => [ "gp", "gp" ] }, emit =>'. smull %D0, %D1, %S0, %S1', outs => [ "low", "high" ], }, Umull => { - #op_flags => "C", irn_flags => "R", - comment => "construct unsigned 64bit Mul: Mul(a, b) = Mul(b, a) = a * b", - reg_req => { "in" => [ "gp", "gp" ], "out" => [ "gp", "gp" ] }, + reg_req => { in => [ "gp", "gp" ], out => [ "gp", "gp" ] }, emit =>'. umull %D0, %D1, %S0, %S1', outs => [ "low", "high" ], + mode => $mode_gp, }, Mla => { - #op_flags => "C", irn_flags => "R", - comment => "construct Mla: Mla(a, b, c) = a * b + c", - reg_req => { "in" => [ "gp", "gp", "gp" ], "out" => [ "!in_r1" ] }, - emit =>'. mla %D0, %S0, %S1, %S2' + reg_req => { in => [ "gp", "gp", "gp" ], out => [ "!in_r1" ] }, + emit =>'. mla %D0, %S0, %S1, %S2', + mode => $mode_gp, }, And => { - op_flags => "C", - irn_flags => "R", - comment => "construct And: And(a, b) = And(b, a) = a AND b", - attr => "arm_shift_modifier mod, long shf", - init_attr => 'ARM_SET_SHF_MOD(attr, mod); attr->imm_value = shf;', - reg_req => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, - emit => '. and %D0, %S0, %S1%X' -}, - -And_i => { irn_flags => "R", - comment => "construct And: And(a, const) = And(const, a) = a AND const", - attr => "long imm", - init_attr => 'ARM_SET_SHF_MOD(attr, ARM_SHF_IMM); attr->imm_value = imm;', - reg_req => { "in" => [ "gp" ], "out" => [ "gp" ] }, - emit => '. and %D0, %S0, %C', + emit => '. and %D0, %S0, %SO', + mode => $mode_gp, + attr_type => "arm_shifter_operand_t", + constructors => \%binop_shifter_operand_constructors, }, Or => { - op_flags => "C", irn_flags => "R", - comment => "construct Or: Or(a, b) = Or(b, a) = a OR b", - attr => "arm_shift_modifier mod, long shf", - init_attr => 'ARM_SET_SHF_MOD(attr, mod); attr->imm_value = shf;', - reg_req => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, - emit => '. orr %D0, %S0, %S1%X' -}, - -Or_i => { - irn_flags => "R", - comment => "construct Or: Or(a, const) = Or(const, a) = a OR const", - attr => "long imm", - init_attr => 'ARM_SET_SHF_MOD(attr, ARM_SHF_IMM); attr->imm_value = imm;', - reg_req => { "in" => [ "gp" ], "out" => [ "gp" ] }, - emit => '. orr %D0, %S0, %C' + emit => '. orr %D0, %S0, %SO', + mode => $mode_gp, + attr_type => "arm_shifter_operand_t", + constructors => \%binop_shifter_operand_constructors, }, Eor => { - op_flags => "C", - irn_flags => "R", - comment => "construct Eor: Eor(a, b) = Eor(b, a) = a EOR b", - attr => "arm_shift_modifier mod, long shf", - init_attr => 'ARM_SET_SHF_MOD(attr, mod); attr->imm_value = shf;', - reg_req => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, - emit => '. eor %D0, %S0, %S1%X' -}, - -Eor_i => { irn_flags => "R", - comment => "construct Eor: Eor(a, const) = Eor(const, a) = a EOR const", - attr => "long imm", - init_attr => 'ARM_SET_SHF_MOD(attr, ARM_SHF_IMM); attr->imm_value = imm;', - reg_req => { "in" => [ "gp" ], "out" => [ "gp" ] }, - emit => '. eor %D0, %S0, %C' + emit => '. eor %D0, %S0, %SO', + mode => $mode_gp, + attr_type => "arm_shifter_operand_t", + constructors => \%binop_shifter_operand_constructors, }, -# not commutative operations - Bic => { irn_flags => "R", - comment => "construct Bic: Bic(a, b) = a AND ~b", - attr => "arm_shift_modifier mod, long shf", - init_attr => 'ARM_SET_SHF_MOD(attr, mod); attr->imm_value = shf;', - reg_req => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, - emit => '. bic %D0, %S0, %S1%X' -}, - -Bic_i => { - irn_flags => "R", - comment => "construct Bic: Bic(a, const) = a AND ~const", - attr => "long imm", - init_attr => 'ARM_SET_SHF_MOD(attr, ARM_SHF_IMM); attr->imm_value = imm;', - reg_req => { "in" => [ "gp" ], "out" => [ "gp" ] }, - emit => '. bic %D0, %S0, %C', + emit => '. bic %D0, %S0, %SO', + mode => $mode_gp, + attr_type => "arm_shifter_operand_t", + constructors => \%binop_shifter_operand_constructors, }, Sub => { irn_flags => "R", - comment => "construct Sub: Sub(a, b) = a - b", - attr => "arm_shift_modifier mod, long shf", - init_attr => 'ARM_SET_SHF_MOD(attr, mod); attr->imm_value = shf;', - reg_req => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, - emit => '. sub %D0, %S0, %S1%X' -}, - -Sub_i => { - irn_flags => "R", - comment => "construct Sub: Sub(a, const) = a - const", - attr => "long imm", - init_attr => 'ARM_SET_SHF_MOD(attr, ARM_SHF_IMM); attr->imm_value = imm;', - reg_req => { "in" => [ "gp" ], "out" => [ "gp" ] }, - emit => '. sub %D0, %S0, %C', + emit => '. sub %D0, %S0, %SO', + mode => $mode_gp, + attr_type => "arm_shifter_operand_t", + constructors => \%binop_shifter_operand_constructors, }, Rsb => { irn_flags => "R", - comment => "construct Rsb: Rsb(a, b) = b - a", - attr => "arm_shift_modifier mod, long shf", - init_attr => 'ARM_SET_SHF_MOD(attr, mod); attr->imm_value = shf;', - reg_req => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, - emit => '. rsb %D0, %S0, %S1%X' -}, - -Rsb_i => { - irn_flags => "R", - comment => "construct Rsb: Rsb(a, const) = const - a", - attr => "long imm", - init_attr => 'ARM_SET_SHF_MOD(attr, ARM_SHF_IMM); attr->imm_value = imm;', - reg_req => { "in" => [ "gp" ], "out" => [ "gp" ] }, - emit => '. rsb %D0, %S0, %C', -}, - -Shl => { - irn_flags => "R", - comment => "construct Shl: Shl(a, b) = a << b", - reg_req => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, - emit => '. mov %D0, %S0, lsl %S1' -}, - -Shr => { - irn_flags => "R", - comment => "construct Shr: Shr(a, b) = a >>u b", - reg_req => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, - emit => '. mov %D0, %S0, lsr %S1' -}, - -Shrs => { - irn_flags => "R", - comment => "construct Shrs: Shrs(a, b) = a >>s b", - reg_req => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, - emit => '. mov %D0, %S0, asr %S1' -}, - -Ror => { - irn_flags => "R", - comment => "construct Ror: Ror(a, b) = a <> b", - reg_req => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, - emit => '. mov %D0, %S0, ror %S1' + emit => '. rsb %D0, %S0, %SO', + mode => $mode_gp, + attr_type => "arm_shifter_operand_t", + constructors => \%binop_shifter_operand_constructors, }, -#RotL => { -# irn_flags => "R", -# comment => "construct RotL: RotL(a, b) = a ROTL b", -# reg_req => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, -# emit => '. rol %S0, %S1, %D0' -#}, - -#RotL_i => { -# irn_flags => "R", -# comment => "construct RotL: RotL(a, const) = a ROTL const", -# reg_req => { "in" => [ "gp" ], "out" => [ "gp" ] }, -# emit => '. rol %S0, %C, %D0' -#}, - Mov => { irn_flags => "R", - comment => "construct Mov: a = b", - attr => "arm_shift_modifier mod, long shf", - init_attr => 'ARM_SET_SHF_MOD(attr, mod); attr->imm_value = shf;', - reg_req => { "in" => [ "gp" ], "out" => [ "gp" ] }, - emit => '. mov %D0, %S0%X' -}, - -Mov_i => { - irn_flags => "R", - comment => "represents an integer constant", - attr => "long imm", - init_attr => 'ARM_SET_SHF_MOD(attr, ARM_SHF_IMM); attr->imm_value = imm;', - reg_req => { "out" => [ "gp" ] }, - emit => '. mov %D0, %C', + arity => "variable", + emit => '. mov %D0, %SO', + mode => $mode_gp, + attr_type => "arm_shifter_operand_t", + constructors => \%unop_shifter_operand_constructors, }, Mvn => { irn_flags => "R", - comment => "construct Not: Not(a) = !a", - attr => "arm_shift_modifier mod, long shf", - init_attr => 'ARM_SET_SHF_MOD(attr, mod); attr->imm_value = shf;', - reg_req => { "in" => [ "gp" ], "out" => [ "gp" ] }, - emit => '. mvn %D0, %S0%X' -}, - -Mvn_i => { - irn_flags => "R", - comment => "represents a negated integer constant", - attr => "long imm", - init_attr => 'ARM_SET_SHF_MOD(attr, ARM_SHF_IMM); attr->imm_value = imm;', - reg_req => { "out" => [ "gp" ] }, - emit => '. mvn %D0, %C', + attr_type => "arm_shifter_operand_t", + arity => "variable", + emit => '. mvn %D0, %SO', + mode => $mode_gp, + constructors => \%unop_shifter_operand_constructors, }, +# Deprecated - we should construct the movs and rsbmi directly... Abs => { irn_flags => "R", - comment => "construct Abs: Abs(a) = |a|", - reg_req => { "in" => [ "gp" ], "out" => [ "gp" ] }, + reg_req => { in => [ "gp" ], out => [ "gp" ] }, emit => '. movs %S0, %S0, #0 -. rsbmi %D0, %S0, #0' +. rsbmi %D0, %S0, #0', + mode => $mode_gp, }, -# other operations - -# # this node produces ALWAYS an empty (tempary) gp reg and cannot be CSE'd -# EmptyReg => { op_flags => "c", irn_flags => "R", - comment => "allocate an empty register for calculations", - reg_req => { "out" => [ "gp" ] }, + reg_req => { out => [ "gp" ] }, emit => '. /* %D0 now available for calculations */', - cmp_attr => 'return 1;' -}, - -Copy => { - comment => "implements a register copy", - reg_req => { "in" => [ "gp" ], "out" => [ "gp" ] }, + cmp_attr => 'return 1;', + mode => $mode_gp, }, CopyB => { op_flags => "F|H", state => "pinned", - comment => "implements a memcopy: CopyB(dst, src, size, mem) == memcpy(dst, src, size)", - attr => "long imm", - init_attr => 'attr->imm_value = imm;', - reg_req => { "in" => [ "!sp", "!sp", "gp", "gp", "gp", "none" ], "out" => [ "none" ] }, + attr => "unsigned size", + attr_type => "arm_CopyB_attr_t", + reg_req => { in => [ "!sp", "!sp", "gp", "gp", "gp", "none" ], out => [ "none" ] }, outs => [ "M" ], }, +FrameAddr => { + op_flags => "c", + irn_flags => "R", + attr => "ir_entity *entity", + reg_req => { in => [ "gp" ], out => [ "gp" ] }, + ins => [ "base" ], + attr_type => "arm_SymConst_attr_t", + mode => $mode_gp, +}, + SymConst => { op_flags => "c", irn_flags => "R", - comment => "represents a symbolic constant", - attr => "ident *id", - init_attr => "\tset_arm_symconst_id(res, id);", - reg_req => { "out" => [ "gp" ] }, - attr_type => "arm_SymConst_attr_t", + attr => "ir_entity *entity", + reg_req => { out => [ "gp" ] }, + attr_type => "arm_SymConst_attr_t", + mode => $mode_gp, }, -CmpBra => { - op_flags => "L|X|Y", - state => "pinned", - comment => "construct conditional branch: CMP A, B && JMPxx LABEL", - mode => "mode_T", - attr => "int proj_num", - init_attr => "\tset_arm_CondJmp_proj_num(res, proj_num);", - reg_req => { "in" => [ "gp", "gp" ], "out" => [ "none", "none"] }, - attr_type => "arm_CondJmp_attr_t", +Cmp => { + irn_flags => "R|F", + emit => '. cmp %S0, %SO', + mode => $mode_flags, + attr_type => "arm_cmp_attr_t", + constructors => \%cmp_shifter_operand_constructors, }, -TstBra => { +Tst => { + irn_flags => "R|F", + emit => '. tst %S0, %SO', + mode => $mode_flags, + attr_type => "arm_cmp_attr_t", + constructors => \%cmp_shifter_operand_constructors, +}, + +B => { op_flags => "L|X|Y", state => "pinned", - comment => "construct conditional branch: TST A, B && JMPxx LABEL", mode => "mode_T", + reg_req => { in => [ "flags" ], out => [ "none", "none" ] }, attr => "int proj_num", - init_attr => "\tset_arm_CondJmp_proj_num(res, proj_num);", - reg_req => { "in" => [ "gp", "gp" ], "out" => [ "none", "none"] }, attr_type => "arm_CondJmp_attr_t", + init_attr => "\tset_arm_CondJmp_proj_num(res, proj_num);", }, Jmp => { @@ -493,94 +383,23 @@ Jmp => { SwitchJmp => { op_flags => "L|X|Y", state => "pinned", - comment => "construct switch", mode => "mode_T", attr => "int n_projs, long def_proj_num", init_attr => "\tset_arm_SwitchJmp_n_projs(res, n_projs);\n". "\tset_arm_SwitchJmp_default_proj_num(res, def_proj_num);", - reg_req => { "in" => [ "gp" ], "out" => [ "none" ] }, + reg_req => { in => [ "gp" ], out => [ "none" ] }, attr_type => "arm_SwitchJmp_attr_t", }, -# Load / Store - Ldr => { op_flags => "L|F", state => "exc_pinned", ins => [ "ptr", "mem" ], outs => [ "res", "M" ], - reg_req => { "in" => [ "gp", "none" ], "out" => [ "gp", "none" ] }, - emit => '. ldr %D0, [%S0, #0]', - attr_type => "arm_load_store_attr_t", - attr => "ir_entity *entity, int entity_sign, long offset", -}, - -Ldrb => { - op_flags => "L|F", - state => "exc_pinned", - ins => [ "ptr", "mem" ], - outs => [ "res", "M" ], - reg_req => { "in" => [ "gp", "none" ], "out" => [ "gp", "none" ] }, - emit => '. ldrb %D0, [%S0, #0]', - attr_type => "arm_load_store_attr_t", - attr => "ir_entity *entity, int entity_sign, long offset", -}, - -Ldrbs => { - op_flags => "L|F", - state => "exc_pinned", - ins => [ "ptr", "mem" ], - outs => [ "res", "M" ], - reg_req => { "in" => [ "gp", "none" ], "out" => [ "gp", "none" ] }, - emit => '. ldrsb %D0, [%S0, #0]', - attr_type => "arm_load_store_attr_t", - attr => "ir_entity *entity, int entity_sign, long offset", -}, - -Ldrh => { - op_flags => "L|F", - state => "exc_pinned", - ins => [ "ptr", "mem" ], - outs => [ "res", "M" ], - reg_req => { "in" => [ "gp", "none" ], "out" => [ "gp", "none" ] }, - emit => '. ldrh %D0, [%S0, #0]', + reg_req => { in => [ "gp", "none" ], out => [ "gp", "none" ] }, + emit => '. ldr%LM %D0, [%S0, #%O]', attr_type => "arm_load_store_attr_t", - attr => "ir_entity *entity, int entity_sign, long offset", -}, - -Ldrhs => { - op_flags => "L|F", - state => "exc_pinned", - ins => [ "ptr", "mem" ], - outs => [ "res", "M" ], - reg_req => { "in" => [ "gp", "none" ], "out" => [ "gp", "none" ] }, - emit => '. ldrsh %D0, [%S0, #0]', - attr_type => "arm_load_store_attr_t", - attr => "ir_entity *entity, int entity_sign, long offset", -}, - -Strb => { - op_flags => "L|F", - state => "exc_pinned", - ins => [ "ptr", "val", "mem" ], - outs => [ "mem" ], - reg_req => { "in" => [ "gp", "gp", "none" ], "out" => [ "none" ] }, - emit => '. strb %S1, [%S0, #0]', - mode => "mode_M", - attr_type => "arm_load_store_attr_t", - attr => "ir_entity *entity, int entity_sign, long offset", -}, - -Strh => { - op_flags => "L|F", - state => "exc_pinned", - ins => [ "ptr", "val", "mem" ], - outs => [ "mem" ], - reg_req => { "in" => [ "gp", "gp", "none" ], out => [ "none" ] }, - emit => '. strh %S1, [%S0, #0]', - mode => "mode_M", - attr_type => "arm_load_store_attr_t", - attr => "ir_entity *entity, int entity_sign, long offset", + attr => "ir_mode *ls_mode, ir_entity *entity, int entity_sign, long offset, bool is_frame_entity", }, Str => { @@ -588,19 +407,18 @@ Str => { state => "exc_pinned", ins => [ "ptr", "val", "mem" ], outs => [ "mem" ], - reg_req => { "in" => [ "gp", "gp", "none" ], out => [ "none" ] }, - emit => '. str %S1, [%S0, #0]', + reg_req => { in => [ "gp", "gp", "none" ], out => [ "none" ] }, + emit => '. str%SM %S1, [%S0, #%O]', mode => "mode_M", attr_type => "arm_load_store_attr_t", - attr => "ir_entity *entity, int entity_sign, long offset", + attr => "ir_mode *ls_mode, ir_entity *entity, int entity_sign, long offset, bool is_frame_entity", }, StoreStackM4Inc => { op_flags => "L|F", irn_flags => "R", state => "exc_pinned", - comment => "construct Store: Push 4 Registers = ST ptr,val", - reg_req => { "in" => [ "sp", "gp", "gp", "gp", "gp", "none" ], "out" => [ "sp:I|S", "none" ] }, + reg_req => { in => [ "sp", "gp", "gp", "gp", "gp", "none" ], out => [ "sp:I|S", "none" ] }, emit => '. stmfd %S0!, {%S1, %S2, %S3, %S4}', outs => [ "ptr", "M" ], }, @@ -609,299 +427,164 @@ LoadStackM3Epilogue => { op_flags => "L|F", irn_flags => "R", state => "exc_pinned", - comment => "construct Load: Load(ptr, mem) = LD ptr -> reg", - reg_req => { "in" => [ "sp", "none" ], "out" => [ "r11:I", "sp:I|S", "pc:I", "none" ] }, + reg_req => { in => [ "sp", "none" ], out => [ "r11:I", "sp:I|S", "pc:I", "none" ] }, emit => '. ldmfd %S0, {%D0, %D1, %D2}', outs => [ "res0", "res1", "res2", "M" ], }, -#---------------------------------------------------# -# __ _ # -# / _| | | # -# | |_ _ __ __ _ _ __ ___ __| | ___ ___ # -# | _| '_ \ / _` | | '_ \ / _ \ / _` |/ _ \/ __| # -# | | | |_) | (_| | | | | | (_) | (_| | __/\__ \ # -# |_| | .__/ \__,_| |_| |_|\___/ \__,_|\___||___/ # -# | | # -# |_| # -#---------------------------------------------------# - -# commutative operations fpaAdf => { - op_flags => "C", irn_flags => "R", - comment => "construct FPA Add: Add(a, b) = Add(b, a) = a + b", - reg_req => { "in" => [ "fpa", "fpa" ], "out" => [ "fpa" ] }, + reg_req => { in => [ "fpa", "fpa" ], out => [ "fpa" ] }, emit => '. adf%M %D0, %S0, %S1', }, -fpaAdf_i => { - irn_flags => "R", - comment => "construct FPA Add: Add(a, b) = Add(b, a) = a + b", - attr => "long imm", - init_attr => 'ARM_SET_FPA_IMM(attr); attr->imm_value = imm;', - reg_req => { "in" => [ "fpa" ], "out" => [ "fpa" ] }, - emit => '. adf%M %D0, %S0, %C', -}, - fpaMuf => { - op_flags => "C", irn_flags => "R", - comment => "construct FPA Mul: Mul(a, b) = Mul(b, a) = a * b", - reg_req => { "in" => [ "fpa", "fpa" ], "out" => [ "fpa" ] }, + reg_req => { in => [ "fpa", "fpa" ], out => [ "fpa" ] }, emit =>'. muf%M %D0, %S0, %S1', }, -fpaMuf_i => { - irn_flags => "R", - comment => "construct FPA Mul: Mul(a, b) = Mul(b, a) = a * b", - attr => "long imm", - init_attr => 'ARM_SET_FPA_IMM(attr); attr->imm_value = imm;', - reg_req => { "in" => [ "fpa" ], "out" => [ "fpa" ] }, - emit => '. muf%M %D0, %S0, %C', -}, - fpaFml => { - op_flags => "C", irn_flags => "R", - comment => "construct FPA Fast Mul: Mul(a, b) = Mul(b, a) = a * b", - reg_req => { "in" => [ "fpa", "fpa" ], "out" => [ "fpa" ] }, + reg_req => { in => [ "fpa", "fpa" ], out => [ "fpa" ] }, emit =>'. fml%M %D0, %S0, %S1', }, fpaMax => { - op_flags => "C", irn_flags => "R", - comment => "construct FPA Max: Max(a, b) = Max(b, a) = a > b ? a : b", - reg_req => { "in" => [ "fpa", "fpa" ], "out" => [ "fpa" ] }, + reg_req => { in => [ "fpa", "fpa" ], out => [ "fpa" ] }, emit =>'. fmax %S0, %S1, %D0', }, fpaMin => { - op_flags => "C", irn_flags => "R", - comment => "construct FPA Min: Min(a, b) = Min(b, a) = a < b ? a : b", - reg_req => { "in" => [ "fpa", "fpa" ], "out" => [ "fpa" ] }, + reg_req => { in => [ "fpa", "fpa" ], out => [ "fpa" ] }, emit =>'. fmin %S0, %S1, %D0', }, -# not commutative operations - fpaSuf => { irn_flags => "R", - comment => "construct FPA Sub: Sub(a, b) = a - b", - reg_req => { "in" => [ "fpa", "fpa" ], "out" => [ "fpa" ] }, + reg_req => { in => [ "fpa", "fpa" ], out => [ "fpa" ] }, emit => '. suf%M %D0, %S0, %S1' }, -fpaSuf_i => { - irn_flags => "R", - comment => "construct FPA Sub: Sub(a, b) = a - b", - attr => "long imm", - init_attr => 'ARM_SET_FPA_IMM(attr); attr->imm_value = imm;', - reg_req => { "in" => [ "fpa" ], "out" => [ "fpa" ] }, - emit => '. suf%M %D0, %S0, %C' -}, - fpaRsf => { irn_flags => "R", - comment => "construct FPA reverse Sub: Sub(a, b) = b - a", - reg_req => { "in" => [ "fpa", "fpa" ], "out" => [ "fpa" ] }, + reg_req => { in => [ "fpa", "fpa" ], out => [ "fpa" ] }, emit => '. rsf%M %D0, %S0, %S1' }, -fpaRsf_i => { - irn_flags => "R", - comment => "construct FPA reverse Sub: Sub(a, b) = b - a", - attr => "long imm", - init_attr => 'ARM_SET_FPA_IMM(attr); attr->imm_value = imm;', - reg_req => { "in" => [ "fpa" ], "out" => [ "fpa" ] }, - emit => '. rsf%M %D0, %S0, %C' -}, - fpaDvf => { - comment => "construct FPA Div: Div(a, b) = a / b", attr => "ir_mode *op_mode", init_attr => "attr->op_mode = op_mode;", - reg_req => { "in" => [ "fpa", "fpa" ], "out" => [ "fpa", "none" ] }, + reg_req => { in => [ "fpa", "fpa" ], out => [ "fpa", "none" ] }, emit =>'. dvf%M %D0, %S0, %S1', outs => [ "res", "M" ], }, -fpaDvf_i => { - comment => "construct FPA Div: Div(a, b) = a / b", - attr => "ir_mode *op_mode, long imm", - init_attr => 'attr->op_mode = op_mode; ARM_SET_FPA_IMM(attr); attr->imm_value = imm;', - reg_req => { "in" => [ "fpa" ], "out" => [ "fpa", "none" ] }, - emit =>'. dvf%M %D0, %S0, %C', - outs => [ "res", "M" ], -}, - fpaRdf => { - comment => "construct FPA reverse Div: Div(a, b) = b / a", attr => "ir_mode *op_mode", init_attr => "attr->op_mode = op_mode;", - reg_req => { "in" => [ "fpa", "fpa" ], "out" => [ "fpa", "none" ] }, - emit =>'. rdf%M %D0, %S0, %S1', - outs => [ "res", "M" ], -}, - -fpaRdf_i => { - comment => "construct FPA reverse Div: Div(a, b) = b / a", - attr => "ir_mode *op_mode, long imm", - init_attr => 'attr->op_mode = op_mode; ARM_SET_FPA_IMM(attr); attr->imm_value = imm;', - reg_req => { "in" => [ "fpa" ], "out" => [ "fpa", "none" ] }, + reg_req => { in => [ "fpa", "fpa" ], out => [ "fpa", "none" ] }, emit =>'. rdf%M %D0, %S0, %S1', outs => [ "res", "M" ], }, fpaFdv => { - comment => "construct FPA Fast Div: Div(a, b) = a / b", attr => "ir_mode *op_mode", init_attr => "attr->op_mode = op_mode;", - reg_req => { "in" => [ "fpa", "fpa" ], "out" => [ "fpa", "none" ] }, + reg_req => { in => [ "fpa", "fpa" ], out => [ "fpa", "none" ] }, emit =>'. fdv%M %D0, %S0, %S1', outs => [ "res", "M" ], }, -fpaFdv_i => { - comment => "construct FPA Fast Div: Div(a, b) = a / b", - attr => "ir_mode *op_mode, long imm", - init_attr => 'attr->op_mode = op_mode; ARM_SET_FPA_IMM(attr); attr->imm_value = imm;', - reg_req => { "in" => [ "fpa" ], "out" => [ "fpa", "none" ] }, - emit =>'. fdv%M %D0, %S0, %C', - outs => [ "res", "M" ], -}, - fpaFrd => { - comment => "construct FPA Fast reverse Div: Div(a, b) = b / a", attr => "ir_mode *op_mode", init_attr => "attr->op_mode = op_mode;", - reg_req => { "in" => [ "fpa", "fpa" ], "out" => [ "fpa", "none" ] }, + reg_req => { in => [ "fpa", "fpa" ], out => [ "fpa", "none" ] }, emit =>'. frd%M %D0, %S0, %S1', outs => [ "res", "M" ], }, -fpaFrd_i => { - comment => "construct FPA Fast reverse Div: Div(a, b) = b / a", - attr => "ir_mode *op_mode, long imm", - init_attr => 'attr->op_mode = op_mode; ARM_SET_FPA_IMM(attr); attr->imm_value = imm;', - reg_req => { "in" => [ "fpa" ], "out" => [ "fpa", "none" ] }, - emit =>'. frd%M %D0, %S0, %C', - outs => [ "res", "M" ], -}, - fpaMvf => { irn_flags => "R", - comment => "construct FPA Move: b = a", - reg_req => { "in" => [ "fpa" ], "out" => [ "fpa" ] }, + reg_req => { in => [ "fpa" ], out => [ "fpa" ] }, emit => '. mvf%M %S0, %D0', }, -fpaMvf_i => { - irn_flags => "R", - comment => "represents a float constant", - attr => "long imm", - init_attr => 'ARM_SET_FPA_IMM(attr); attr->imm_value = imm;', - reg_req => { "out" => [ "fpa" ] }, - emit => '. mvf%M %D0, %C', -}, - fpaMnf => { irn_flags => "R", - comment => "construct FPA Move Negated: b = -a", - reg_req => { "in" => [ "fpa" ], "out" => [ "fpa" ] }, + reg_req => { in => [ "fpa" ], out => [ "fpa" ] }, emit => '. mnf%M %S0, %D0', }, -fpaMnf_i => { - irn_flags => "R", - comment => "represents a float constant", - attr => "long imm", - init_attr => 'ARM_SET_FPA_IMM(attr); attr->imm_value = imm;', - reg_req => { "out" => [ "fpa" ] }, - emit => '. mnf%M %D0, %C', -}, - fpaAbs => { irn_flags => "R", - comment => "construct FPA Absolute value: fAbsd(a) = |a|", - reg_req => { "in" => [ "fpa" ], "out" => [ "fpa" ] }, + reg_req => { in => [ "fpa" ], out => [ "fpa" ] }, emit => '. abs%M %D0, %S0', }, -# other operations - fpaFlt => { irn_flags => "R", - comment => "construct a FPA integer->float conversion", - reg_req => { "in" => ["gp"], "out" => [ "fpa" ] }, + reg_req => { in => ["gp"], out => [ "fpa" ] }, emit => '. flt%M %D0, %S0', }, fpaFix => { irn_flags => "R", - comment => "construct a FPA float->integer conversion", - reg_req => { "in" => ["fpa"], "out" => [ "gp" ] }, + reg_req => { in => ["fpa"], out => [ "gp" ] }, emit => '. fix %D0, %S0', }, fpaCmfBra => { op_flags => "L|X|Y", state => "pinned", - comment => "construct floating point Compare and Branch: CMF A, B && JMPxx LABEL", mode => "mode_T", attr => "int proj_num", init_attr => "\tset_arm_CondJmp_proj_num(res, proj_num);", - reg_req => { "in" => [ "fpa", "fpa" ], "out" => [ "none", "none"] }, + reg_req => { in => [ "fpa", "fpa" ], out => [ "none", "none"] }, attr_type => "arm_CondJmp_attr_t", }, fpaCnfBra => { op_flags => "L|X|Y", state => "pinned", - comment => "construct floating point Compare negative and Branch: CMF A, -B && JMPxx LABEL", mode => "mode_T", attr => "int proj_num", init_attr => "\tset_arm_CondJmp_proj_num(res, proj_num);", - reg_req => { "in" => [ "fpa", "fpa" ], "out" => [ "none", "none"] }, + reg_req => { in => [ "fpa", "fpa" ], out => [ "none", "none"] }, attr_type => "arm_CondJmp_attr_t", }, fpaCmfeBra => { op_flags => "L|X|Y", state => "pinned", - comment => "construct floating point Compare and Branch: CMF A, -B && JMPxx LABEL", mode => "mode_T", attr => "int proj_num", init_attr => "\tset_arm_CondJmp_proj_num(res, proj_num);", - reg_req => { "in" => [ "fpa", "fpa" ], "out" => [ "none", "none"] }, + reg_req => { in => [ "fpa", "fpa" ], out => [ "none", "none"] }, attr_type => "arm_CondJmp_attr_t", }, fpaCnfeBra => { op_flags => "L|X|Y", state => "pinned", - comment => "construct floating point Compare and Branch: CMF A, -B && JMPxx LABEL", mode => "mode_T", attr => "int proj_num", init_attr => "\tset_arm_CondJmp_proj_num(res, proj_num);", - reg_req => { "in" => [ "fpa", "fpa" ], "out" => [ "none", "none"] }, + reg_req => { in => [ "fpa", "fpa" ], out => [ "none", "none"] }, attr_type => "arm_CondJmp_attr_t", }, -# Load / Store - fpaLdf => { op_flags => "L|F", irn_flags => "R", state => "exc_pinned", - comment => "construct FPA Load: Load(ptr, mem) = LD ptr", attr => "ir_mode *op_mode", init_attr => "attr->op_mode = op_mode;", - reg_req => { "in" => [ "gp", "none" ], "out" => [ "fpa", "none" ] }, + reg_req => { in => [ "gp", "none" ], out => [ "fpa", "none" ] }, emit => '. ldf%M %D0, [%S0]', outs => [ "res", "M" ], }, @@ -910,10 +593,9 @@ fpaStf => { op_flags => "L|F", irn_flags => "R", state => "exc_pinned", - comment => "construct Store: Store(ptr, val, mem) = ST ptr,val", attr => "ir_mode *op_mode", init_attr => "attr->op_mode = op_mode;", - reg_req => { "in" => [ "gp", "fpa", "none" ], "out" => [ "none" ] }, + reg_req => { in => [ "gp", "fpa", "none" ], out => [ "none" ] }, emit => '. stf%M %S1, [%S0]', mode => "mode_M", }, @@ -921,20 +603,17 @@ fpaStf => { fpaDbl2GP => { op_flags => "L|F", irn_flags => "R", - comment => "construct fp double to 2 gp register transfer", - reg_req => { "in" => [ "fpa", "none" ], "out" => [ "gp", "gp", "none" ] }, + reg_req => { in => [ "fpa", "none" ], out => [ "gp", "gp", "none" ] }, outs => [ "low", "high", "M" ], }, AddSP => { - comment => "construct Add to stack pointer", reg_req => { in => [ "sp", "gp", "none" ], out => [ "sp:I|S", "none" ] }, emit => '. add %D0, %S0, %S1', outs => [ "stack", "M" ], }, SubSPandCopy => { - comment => "construct Sub from stack pointer and copy to Register", reg_req => { in => [ "sp", "gp", "none" ], out => [ "sp:I|S", "gp", "none" ] }, ins => [ "stack", "size", "mem" ], emit => ". sub %D0, %S0, %S1\n". @@ -944,7 +623,6 @@ SubSPandCopy => { LdTls => { irn_flags => "R", - comment => "load the TLS address", reg_req => { out => [ "gp" ] }, }, @@ -955,23 +633,11 @@ LdTls => { fpaConst => { op_flags => "c", irn_flags => "R", - comment => "construct a floating point constant", attr => "tarval *tv", init_attr => "attr->tv = tv;", mode => "get_tarval_mode(tv)", - reg_req => { "out" => [ "fpa" ] }, + reg_req => { out => [ "fpa" ] }, attr_type => "arm_fpaConst_attr_t", } -#---------------------------------------------------# -# __ _ # -# / _| | | # -# __ _| |_ _ __ _ __ ___ __| | ___ ___ # -# \ \ / / _| '_ \ | '_ \ / _ \ / _` |/ _ \/ __| # -# \ V /| | | |_) | | | | | (_) | (_| | __/\__ \ # -# \_/ |_| | .__/ |_| |_|\___/ \__,_|\___||___/ # -# | | # -# |_| # -#---------------------------------------------------# - ); # end of %nodes diff --git a/ir/be/arm/arm_transform.c b/ir/be/arm/arm_transform.c index 73055ef46..88827ba82 100644 --- a/ir/be/arm/arm_transform.c +++ b/ir/be/arm/arm_transform.c @@ -54,87 +54,46 @@ #include +DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;) /** hold the current code generator during transformation */ static arm_code_gen_t *env_cg; -extern ir_op *get_op_Mulh(void); - - -/**************************************************************************************************** - * _ _ __ _ _ - * | | | | / _| | | (_) - * _ __ ___ __| | ___ | |_ _ __ __ _ _ __ ___| |_ ___ _ __ _ __ ___ __ _| |_ _ ___ _ __ - * | '_ \ / _ \ / _` |/ _ \ | __| '__/ _` | '_ \/ __| _/ _ \| '__| '_ ` _ \ / _` | __| |/ _ \| '_ \ - * | | | | (_) | (_| | __/ | |_| | | (_| | | | \__ \ || (_) | | | | | | | | (_| | |_| | (_) | | | | - * |_| |_|\___/ \__,_|\___| \__|_| \__,_|_| |_|___/_| \___/|_| |_| |_| |_|\__,_|\__|_|\___/|_| |_| - * - ****************************************************************************************************/ - -static inline int mode_needs_gp_reg(ir_mode *mode) { +static inline int mode_needs_gp_reg(ir_mode *mode) +{ return mode_is_int(mode) || mode_is_reference(mode); } -/** - * Creates a arm_Const node. - */ -static ir_node *create_mov_node(dbg_info *dbg, ir_node *block, long value) { - ir_mode *mode = mode_Iu; - ir_node *res; - - if (mode_needs_gp_reg(mode)) - mode = mode_Iu; - res = new_bd_arm_Mov_i(dbg, block, mode, value); - be_dep_on_frame(res); - return res; -} - -/** - * Creates a arm_Const_Neg node. - */ -static ir_node *create_mvn_node(dbg_info *dbg, ir_node *block, long value) { - ir_mode *mode = mode_Iu; - ir_node *res; - - if (mode_needs_gp_reg(mode)) - mode = mode_Iu; - res = new_bd_arm_Mvn_i(dbg, block, mode, value); - be_dep_on_frame(res); - return res; -} - -#define NEW_BINOP_NODE(opname, env, op1, op2) new_bd_arm_##opname(env->dbg, current_ir_graph, env->block, op1, op2, env->mode) - /** * Creates a possible DAG for an constant. */ -static ir_node *create_const_graph_value(dbg_info *dbg, ir_node *block, unsigned int value) { +static ir_node *create_const_graph_value(dbg_info *dbgi, ir_node *block, + unsigned int value) +{ ir_node *result; arm_vals v, vn; int cnt; - ir_mode *mode = mode_Iu; arm_gen_vals_from_word(value, &v); arm_gen_vals_from_word(~value, &vn); if (vn.ops < v.ops) { /* remove bits */ - result = create_mvn_node(dbg, block, arm_encode_imm_w_shift(vn.shifts[0], vn.values[0])); + result = new_bd_arm_Mvn_imm(dbgi, block, vn.values[0], vn.rors[0]); + be_dep_on_frame(result); for (cnt = 1; cnt < vn.ops; ++cnt) { - long value = arm_encode_imm_w_shift(vn.shifts[cnt], vn.values[cnt]); - ir_node *bic_i_node = new_bd_arm_Bic_i(dbg, block, result, mode, value); - result = bic_i_node; + result = new_bd_arm_Bic_imm(dbgi, block, result, + vn.values[cnt], vn.rors[cnt]); } - } - else { + } else { /* add bits */ - result = create_mov_node(dbg, block, arm_encode_imm_w_shift(v.shifts[0], v.values[0])); + result = new_bd_arm_Mov_imm(dbgi, block, v.values[0], v.rors[0]); + be_dep_on_frame(result); for (cnt = 1; cnt < v.ops; ++cnt) { - long value = arm_encode_imm_w_shift(v.shifts[cnt], v.values[cnt]); - ir_node *orr_i_node = new_bd_arm_Or_i(dbg, block, result, mode, value); - result = orr_i_node; + result = new_bd_arm_Or_imm(dbgi, block, result, + v.values[cnt], v.rors[cnt]); } } return result; @@ -145,10 +104,11 @@ static ir_node *create_const_graph_value(dbg_info *dbg, ir_node *block, unsigned * * @param irn a Firm const */ -static ir_node *create_const_graph(ir_node *irn, ir_node *block) { +static ir_node *create_const_graph(ir_node *irn, ir_node *block) +{ tarval *tv = get_Const_tarval(irn); ir_mode *mode = get_tarval_mode(tv); - int value; + unsigned value; if (mode_is_reference(mode)) { /* ARM is 32bit, so we can safely convert a reference tarval into Iu */ @@ -162,23 +122,60 @@ static ir_node *create_const_graph(ir_node *irn, ir_node *block) { /** * Create an And that will mask all upper bits */ -static ir_node *gen_zero_extension(dbg_info *dbg, ir_node *block, ir_node *op, int result_bits) { - unsigned mask_bits = (1 << result_bits) - 1; - ir_node *mask_node = create_const_graph_value(dbg, block, mask_bits); - return new_bd_arm_And(dbg, block, op, mask_node, mode_Iu, ARM_SHF_NONE, 0); +static ir_node *gen_zero_extension(dbg_info *dbgi, ir_node *block, ir_node *op, + int src_bits) +{ + if (src_bits == 8) { + return new_bd_arm_And_imm(dbgi, block, op, 0xFF, 0); + } else if (src_bits == 16) { + ir_node *lshift = new_bd_arm_Mov_reg_shift_imm(dbgi, block, op, ARM_SHF_LSL_IMM, 16); + ir_node *rshift = new_bd_arm_Mov_reg_shift_imm(dbgi, block, lshift, ARM_SHF_LSR_IMM, 16); + return rshift; + } else { + panic("zero extension only supported for 8 and 16 bits"); + } } /** * Generate code for a sign extension. */ -static ir_node *gen_sign_extension(dbg_info *dbg, ir_node *block, ir_node *op, int result_bits) { - int shift_width = 32 - result_bits; - ir_node *shift_const_node = create_const_graph_value(dbg, block, shift_width); - ir_node *lshift_node = new_bd_arm_Shl(dbg, block, op, shift_const_node, mode_Iu); - ir_node *rshift_node = new_bd_arm_Shrs(dbg, block, lshift_node, shift_const_node, mode_Iu); +static ir_node *gen_sign_extension(dbg_info *dbgi, ir_node *block, ir_node *op, + int src_bits) +{ + int shift_width = 32 - src_bits; + ir_node *lshift_node = new_bd_arm_Mov_reg_shift_imm(dbgi, block, op, ARM_SHF_LSL_IMM, shift_width); + ir_node *rshift_node = new_bd_arm_Mov_reg_shift_imm(dbgi, block, lshift_node, ARM_SHF_ASR_IMM, shift_width); return rshift_node; } +static ir_node *gen_extension(dbg_info *dbgi, ir_node *block, ir_node *op, + ir_mode *orig_mode) +{ + int bits = get_mode_size_bits(orig_mode); + if (bits == 32) + return op; + + if (mode_is_signed(orig_mode)) { + return gen_sign_extension(dbgi, block, op, bits); + } else { + return gen_zero_extension(dbgi, block, op, bits); + } +} + +/** + * returns true if it is assured, that the upper bits of a node are "clean" + * which means for a 16 or 8 bit value, that the upper bits in the register + * are 0 for unsigned and a copy of the last significant bit for signed + * numbers. + */ +static bool upper_bits_clean(ir_node *transformed_node, ir_mode *mode) +{ + (void) transformed_node; + (void) mode; + /* TODO */ + return false; +} + /** * Transforms a Conv node. * @@ -213,71 +210,163 @@ static ir_node *gen_Conv(ir_node *node) { /* from int to float */ return new_bd_arm_fpaFlt(dbg, block, new_op, dst_mode); } - } - else if (USE_VFP(env_cg->isa)) { + } else if (USE_VFP(env_cg->isa)) { panic("VFP not supported yet"); return NULL; - } - else { + } else { panic("Softfloat not supported yet"); return NULL; } - } - else { /* complete in gp registers */ + } else { /* complete in gp registers */ int src_bits = get_mode_size_bits(src_mode); int dst_bits = get_mode_size_bits(dst_mode); int min_bits; ir_mode *min_mode; - if (is_Load(skip_Proj(op))) { - if (src_bits == dst_bits) { - /* kill unneccessary conv */ - return new_op; - } - /* after a load, the bit size is already converted */ - src_bits = 32; - } - if (src_bits == dst_bits) { /* kill unneccessary conv */ return new_op; - } else if (dst_bits <= 32 && src_bits <= 32) { - if (src_bits < dst_bits) { - min_bits = src_bits; - min_mode = src_mode; - } else { - min_bits = dst_bits; - min_mode = dst_mode; - } - if (mode_is_signed(min_mode)) { - return gen_sign_extension(dbg, block, new_op, min_bits); - } else { - return gen_zero_extension(dbg, block, new_op, min_bits); - } + } + + if (src_bits < dst_bits) { + min_bits = src_bits; + min_mode = src_mode; } else { - panic("Cannot handle Conv %+F->%+F with %d->%d bits", src_mode, dst_mode, - src_bits, dst_bits); - return NULL; + min_bits = dst_bits; + min_mode = dst_mode; + } + + if (upper_bits_clean(new_op, min_mode)) { + return new_op; + } + + if (mode_is_signed(min_mode)) { + return gen_sign_extension(dbg, block, new_op, min_bits); + } else { + return gen_zero_extension(dbg, block, new_op, min_bits); } } } -/** - * Return true if an operand is a shifter operand - */ -static int is_shifter_operand(ir_node *n, arm_shift_modifier *pmod) { - arm_shift_modifier mod = ARM_SHF_NONE; +typedef struct { + unsigned char imm_8; + unsigned char rot; +} arm_immediate_t; + +static bool try_encode_as_immediate(const ir_node *node, arm_immediate_t *res) +{ + unsigned val; + + if (!is_Const(node)) + return false; - if (is_arm_Mov(n)) - mod = get_arm_shift_modifier(n); + val = get_tarval_long(get_Const_tarval(node)); - *pmod = mod; - if (mod != ARM_SHF_NONE) { - long v = get_arm_imm_value(n); - if (v < 32) - return (int)v; + if (val == 0) { + res->imm_8 = 0; + res->rot = 0; + return true; + } + if (val <= 0xff) { + res->imm_8 = val; + res->rot = 0; + return true; } - return 0; + /* arm allows to use to rotate an 8bit immediate value by a multiple of 2 + (= 0, 2, 4, 6, ...). + So we determine the smallest even position with a bit set + and the highest even position with no bit set anymore. + If the difference between these 2 is <= 8, then we can encode the value + as immediate. + */ + unsigned low_pos = ntz(val) & ~1u; + unsigned high_pos = (32-nlz(val)+1) & ~1u; + + if (high_pos - low_pos <= 8) { + res->imm_8 = val >> low_pos; + res->rot = 32 - low_pos; + return true; + } + + if (high_pos > 24) { + res->rot = 34 - high_pos; + val = val >> (32-res->rot) | val << (res->rot); + if (val <= 0xff) { + res->imm_8 = val; + return true; + } + } + + return false; +} + +static int is_downconv(const ir_node *node) +{ + ir_mode *src_mode; + ir_mode *dest_mode; + + if (!is_Conv(node)) + return 0; + + /* we only want to skip the conv when we're the only user + * (not optimal but for now...) + */ + if (get_irn_n_edges(node) > 1) + return 0; + + src_mode = get_irn_mode(get_Conv_op(node)); + dest_mode = get_irn_mode(node); + return + mode_needs_gp_reg(src_mode) && + mode_needs_gp_reg(dest_mode) && + get_mode_size_bits(dest_mode) <= get_mode_size_bits(src_mode); +} + +static ir_node *arm_skip_downconv(ir_node *node) +{ + while (is_downconv(node)) + node = get_Conv_op(node); + return node; +} + +typedef enum { + MATCH_NONE = 0, + MATCH_COMMUTATIVE = 1 << 0, + MATCH_SIZE_NEUTRAL = 1 << 1, +} match_flags_t; + +typedef ir_node* (*new_binop_reg_func) (dbg_info *dbgi, ir_node *block, ir_node *op1, ir_node *op2); +typedef ir_node* (*new_binop_imm_func) (dbg_info *dbgi, ir_node *block, ir_node *op1, unsigned char imm8, unsigned char imm_rot); + +static ir_node *gen_int_binop(ir_node *node, match_flags_t flags, + new_binop_reg_func new_reg, new_binop_imm_func new_imm) +{ + ir_node *block = be_transform_node(get_nodes_block(node)); + ir_node *op1 = get_binop_left(node); + ir_node *new_op1; + ir_node *op2 = get_binop_right(node); + ir_node *new_op2; + dbg_info *dbgi = get_irn_dbg_info(node); + arm_immediate_t imm; + + if (flags & MATCH_SIZE_NEUTRAL) { + op1 = arm_skip_downconv(op1); + op2 = arm_skip_downconv(op2); + } else { + assert(get_mode_size_bits(get_irn_mode(node)) == 32); + } + + if (try_encode_as_immediate(op2, &imm)) { + ir_node *new_op1 = be_transform_node(op1); + return new_imm(dbgi, block, new_op1, imm.imm_8, imm.rot); + } + new_op2 = be_transform_node(op2); + if ((flags & MATCH_COMMUTATIVE) && try_encode_as_immediate(op1, &imm)) { + return new_imm(dbgi, block, new_op2, imm.imm_8, imm.rot); + } + new_op1 = be_transform_node(op1); + + return new_reg(dbgi, block, new_op1, new_op2); } /** @@ -285,26 +374,26 @@ static int is_shifter_operand(ir_node *n, arm_shift_modifier *pmod) { * * @return the created arm Add node */ -static ir_node *gen_Add(ir_node *node) { - ir_node *block = be_transform_node(get_nodes_block(node)); - ir_node *op1 = get_Add_left(node); - ir_node *new_op1 = be_transform_node(op1); - ir_node *op2 = get_Add_right(node); - ir_node *new_op2 = be_transform_node(op2); +static ir_node *gen_Add(ir_node *node) +{ ir_mode *mode = get_irn_mode(node); - ir_node *new_op3; - int v; - arm_shift_modifier mod; - dbg_info *dbg = get_irn_dbg_info(node); if (mode_is_float(mode)) { + ir_node *block = be_transform_node(get_nodes_block(node)); + ir_node *op1 = get_Add_left(node); + ir_node *op2 = get_Add_right(node); + dbg_info *dbgi = get_irn_dbg_info(node); + ir_node *new_op1 = be_transform_node(op1); + ir_node *new_op2 = be_transform_node(op2); env_cg->have_fp_insn = 1; if (USE_FPA(env_cg->isa)) { +#if 0 if (is_arm_fpaMvf_i(new_op1)) - return new_bd_arm_fpaAdf_i(dbg, block, new_op2, mode, get_arm_imm_value(new_op1)); + return new_bd_arm_fpaAdf_i(dbgi, block, new_op2, mode, get_arm_imm_value(new_op1)); if (is_arm_fpaMvf_i(new_op2)) - return new_bd_arm_fpaAdf_i(dbg, block, new_op1, mode, get_arm_imm_value(new_op2)); - return new_bd_arm_fpaAdf(dbg, block, new_op1, new_op2, mode); + return new_bd_arm_fpaAdf_i(dbgi, block, new_op1, mode, get_arm_imm_value(new_op2)); +#endif + return new_bd_arm_fpaAdf(dbgi, block, new_op1, new_op2, mode); } else if (USE_VFP(env_cg->isa)) { assert(mode != mode_E && "IEEE Extended FP not supported"); panic("VFP not supported yet"); @@ -315,47 +404,26 @@ static ir_node *gen_Add(ir_node *node) { return NULL; } } else { - assert(mode_is_data(mode)); - mode = mode_Iu; - - if (is_arm_Mov_i(new_op1)) - return new_bd_arm_Add_i(dbg, block, new_op2, mode, get_arm_imm_value(new_op1)); - if (is_arm_Mov_i(new_op2)) - return new_bd_arm_Add_i(dbg, block, new_op1, mode, get_arm_imm_value(new_op2)); - +#if 0 /* check for MLA */ if (is_arm_Mul(new_op1) && get_irn_n_edges(op1) == 1) { new_op3 = new_op2; new_op2 = get_irn_n(new_op1, 1); new_op1 = get_irn_n(new_op1, 0); - return new_bd_arm_Mla(dbg, block, new_op1, new_op2, new_op3, mode); + return new_bd_arm_Mla(dbgi, block, new_op1, new_op2, new_op3); } if (is_arm_Mul(new_op2) && get_irn_n_edges(op2) == 1) { new_op3 = new_op1; new_op1 = get_irn_n(new_op2, 0); new_op2 = get_irn_n(new_op2, 1); - return new_bd_arm_Mla(dbg, block, new_op1, new_op2, new_op3, mode); - } - -#if 0 - /* is the first a shifter */ - v = is_shifter_operand(new_op1, &mod); - if (v) { - new_op1 = get_irn_n(new_op1, 0); - return new_bd_arm_Add(dbg, block, new_op2, new_op1, mode, mod, v); - } - /* is the second a shifter */ - v = is_shifter_operand(new_op2, &mod); - if (v) { - new_op2 = get_irn_n(new_op2, 0); - return new_bd_arm_Add(dbg, block, new_op1, new_op2, mode, mod, v); + return new_bd_arm_Mla(dbgi, block, new_op1, new_op2, new_op3); } #endif - /* normal ADD */ - return new_bd_arm_Add(dbg, block, new_op1, new_op2, mode, ARM_SHF_NONE, 0); + return gen_int_binop(node, MATCH_COMMUTATIVE | MATCH_SIZE_NEUTRAL, + new_bd_arm_Add_reg, new_bd_arm_Add_imm); } } @@ -376,10 +444,12 @@ static ir_node *gen_Mul(ir_node *node) { if (mode_is_float(mode)) { env_cg->have_fp_insn = 1; if (USE_FPA(env_cg->isa)) { +#if 0 if (is_arm_Mov_i(new_op1)) return new_bd_arm_fpaMuf_i(dbg, block, new_op2, mode, get_arm_imm_value(new_op1)); if (is_arm_Mov_i(new_op2)) return new_bd_arm_fpaMuf_i(dbg, block, new_op1, mode, get_arm_imm_value(new_op2)); +#endif return new_bd_arm_fpaMuf(dbg, block, new_op1, new_op2, mode); } else if (USE_VFP(env_cg->isa)) { @@ -393,8 +463,7 @@ static ir_node *gen_Mul(ir_node *node) { } } assert(mode_is_data(mode)); - mode = mode_Iu; - return new_bd_arm_Mul(dbg, block, new_op1, new_op2, mode); + return new_bd_arm_Mul(dbg, block, new_op1, new_op2); } /** @@ -416,10 +485,12 @@ static ir_node *gen_Quot(ir_node *node) { env_cg->have_fp_insn = 1; if (USE_FPA(env_cg->isa)) { +#if 0 if (is_arm_Mov_i(new_op1)) return new_bd_arm_fpaRdf_i(dbg, block, new_op2, mode, get_arm_imm_value(new_op1)); if (is_arm_Mov_i(new_op2)) return new_bd_arm_fpaDvf_i(dbg, block, new_op1, mode, get_arm_imm_value(new_op2)); +#endif return new_bd_arm_fpaDvf(dbg, block, new_op1, new_op2, mode); } else if (USE_VFP(env_cg->isa)) { assert(mode != mode_E && "IEEE Extended FP not supported"); @@ -431,43 +502,15 @@ static ir_node *gen_Quot(ir_node *node) { } } -#define GEN_INT_OP(op) \ - ir_node *block = be_transform_node(get_nodes_block(node)); \ - ir_node *op1 = get_ ## op ## _left(node); \ - ir_node *new_op1 = be_transform_node(op1); \ - ir_node *op2 = get_ ## op ## _right(node); \ - ir_node *new_op2 = be_transform_node(op2); \ - ir_mode *mode = mode_Iu; \ - dbg_info *dbg = get_irn_dbg_info(node); \ - int v; \ - arm_shift_modifier mod; \ - \ - if (is_arm_Mov_i(new_op1)) \ - return new_bd_arm_ ## op ## _i(dbg, block, new_op2, mode, get_arm_imm_value(new_op1)); \ - if (is_arm_Mov_i(new_op2)) \ - return new_bd_arm_ ## op ## _i(dbg, block, new_op1, mode, get_arm_imm_value(new_op2)); \ - /* is the first a shifter */ \ - v = is_shifter_operand(new_op1, &mod); \ - if (v) { \ - new_op1 = get_irn_n(new_op1, 0); \ - return new_bd_arm_ ## op(dbg, block, new_op2, new_op1, mode, mod, v); \ - } \ - /* is the second a shifter */ \ - v = is_shifter_operand(new_op2, &mod); \ - if (v) { \ - new_op2 = get_irn_n(new_op2, 0); \ - return new_bd_arm_ ## op(dbg, block, new_op1, new_op2, mode, mod, v); \ - } \ - /* Normal op */ \ - return new_bd_arm_ ## op(dbg, block, new_op1, new_op2, mode, ARM_SHF_NONE, 0) \ - /** * Creates an ARM And. * * @return the created arm And node */ -static ir_node *gen_And(ir_node *node) { - GEN_INT_OP(And); +static ir_node *gen_And(ir_node *node) +{ + return gen_int_binop(node, MATCH_COMMUTATIVE | MATCH_SIZE_NEUTRAL, + new_bd_arm_And_reg, new_bd_arm_And_imm); } /** @@ -476,8 +519,10 @@ static ir_node *gen_And(ir_node *node) { * @param env The transformation environment * @return the created arm Or node */ -static ir_node *gen_Or(ir_node *node) { - GEN_INT_OP(Or); +static ir_node *gen_Or(ir_node *node) +{ + return gen_int_binop(node, MATCH_COMMUTATIVE | MATCH_SIZE_NEUTRAL, + new_bd_arm_Or_reg, new_bd_arm_Or_imm); } /** @@ -485,8 +530,10 @@ static ir_node *gen_Or(ir_node *node) { * * @return the created arm Eor node */ -static ir_node *gen_Eor(ir_node *node) { - GEN_INT_OP(Eor); +static ir_node *gen_Eor(ir_node *node) +{ + return gen_int_binop(node, MATCH_COMMUTATIVE | MATCH_SIZE_NEUTRAL, + new_bd_arm_Eor_reg, new_bd_arm_Eor_imm); } /** @@ -494,59 +541,57 @@ static ir_node *gen_Eor(ir_node *node) { * * @return the created arm Sub node */ -static ir_node *gen_Sub(ir_node *node) { +static ir_node *gen_Sub(ir_node *node) +{ ir_node *block = be_transform_node(get_nodes_block(node)); ir_node *op1 = get_Sub_left(node); ir_node *new_op1 = be_transform_node(op1); ir_node *op2 = get_Sub_right(node); ir_node *new_op2 = be_transform_node(op2); ir_mode *mode = get_irn_mode(node); - dbg_info *dbg = get_irn_dbg_info(node); - int v; - arm_shift_modifier mod; + dbg_info *dbgi = get_irn_dbg_info(node); if (mode_is_float(mode)) { env_cg->have_fp_insn = 1; if (USE_FPA(env_cg->isa)) { +#if 0 if (is_arm_Mov_i(new_op1)) - return new_bd_arm_fpaRsf_i(dbg, block, new_op2, mode, get_arm_imm_value(new_op1)); + return new_bd_arm_fpaRsf_i(dbgi, block, new_op2, mode, get_arm_imm_value(new_op1)); if (is_arm_Mov_i(new_op2)) - return new_bd_arm_fpaSuf_i(dbg, block, new_op1, mode, get_arm_imm_value(new_op2)); - return new_bd_arm_fpaSuf(dbg, block, new_op1, new_op2, mode); + return new_bd_arm_fpaSuf_i(dbgi, block, new_op1, mode, get_arm_imm_value(new_op2)); +#endif + return new_bd_arm_fpaSuf(dbgi, block, new_op1, new_op2, mode); } else if (USE_VFP(env_cg->isa)) { assert(mode != mode_E && "IEEE Extended FP not supported"); panic("VFP not supported yet"); return NULL; - } - else { + } else { panic("Softfloat not supported yet"); return NULL; } + } else { + return gen_int_binop(node, MATCH_SIZE_NEUTRAL, + new_bd_arm_Sub_reg, new_bd_arm_Sub_imm); } - else { - assert(mode_is_data(mode) && "unknown mode for Sub"); - mode = mode_Iu; - - if (is_arm_Mov_i(new_op1)) - return new_bd_arm_Rsb_i(dbg, block, new_op2, mode, get_arm_imm_value(new_op1)); - if (is_arm_Mov_i(new_op2)) - return new_bd_arm_Sub_i(dbg, block, new_op1, mode, get_arm_imm_value(new_op2)); +} - /* is the first a shifter */ - v = is_shifter_operand(new_op1, &mod); - if (v) { - new_op1 = get_irn_n(new_op1, 0); - return new_bd_arm_Rsb(dbg, block, new_op2, new_op1, mode, mod, v); - } - /* is the second a shifter */ - v = is_shifter_operand(new_op2, &mod); - if (v) { - new_op2 = get_irn_n(new_op2, 0); - return new_bd_arm_Sub(dbg, block, new_op1, new_op2, mode, mod, v); - } - /* normal sub */ - return new_bd_arm_Sub(dbg, block, new_op1, new_op2, mode, ARM_SHF_NONE, 0); +static ir_node *make_shift(ir_node *node, match_flags_t flags, + arm_shift_modifier shift_modifier) +{ + ir_node *block = be_transform_node(get_nodes_block(node)); + ir_node *op1 = get_binop_left(node); + ir_node *op2 = get_binop_right(node); + dbg_info *dbgi = get_irn_dbg_info(node); + ir_node *new_op1; + ir_node *new_op2; + + if (flags & MATCH_SIZE_NEUTRAL) { + op1 = arm_skip_downconv(op1); + op2 = arm_skip_downconv(op2); } + new_op1 = be_transform_node(op1); + new_op2 = be_transform_node(op2); + return new_bd_arm_Mov_reg_shift_reg(dbgi, block, new_op1, new_op2, shift_modifier); } /** @@ -554,19 +599,9 @@ static ir_node *gen_Sub(ir_node *node) { * * @return the created ARM Shl node */ -static ir_node *gen_Shl(ir_node *node) { - ir_node *block = be_transform_node(get_nodes_block(node)); - ir_node *op1 = get_Shl_left(node); - ir_node *new_op1 = be_transform_node(op1); - ir_node *op2 = get_Shl_right(node); - ir_node *new_op2 = be_transform_node(op2); - ir_mode *mode = mode_Iu; - dbg_info *dbg = get_irn_dbg_info(node); - - if (is_arm_Mov_i(new_op2)) { - return new_bd_arm_Mov(dbg, block, new_op1, mode, ARM_SHF_LSL, get_arm_imm_value(new_op2)); - } - return new_bd_arm_Shl(dbg, block, new_op1, new_op2, mode); +static ir_node *gen_Shl(ir_node *node) +{ + return make_shift(node, MATCH_SIZE_NEUTRAL, ARM_SHF_LSL_REG); } /** @@ -574,19 +609,9 @@ static ir_node *gen_Shl(ir_node *node) { * * @return the created ARM Shr node */ -static ir_node *gen_Shr(ir_node *node) { - ir_node *block = be_transform_node(get_nodes_block(node)); - ir_node *op1 = get_Shr_left(node); - ir_node *new_op1 = be_transform_node(op1); - ir_node *op2 = get_Shr_right(node); - ir_node *new_op2 = be_transform_node(op2); - ir_mode *mode = mode_Iu; - dbg_info *dbg = get_irn_dbg_info(node); - - if (is_arm_Mov_i(new_op2)) { - return new_bd_arm_Mov(dbg, block, new_op1, mode, ARM_SHF_LSR, get_arm_imm_value(new_op2)); - } - return new_bd_arm_Shr(dbg, block, new_op1, new_op2, mode); +static ir_node *gen_Shr(ir_node *node) +{ + return make_shift(node, MATCH_NONE, ARM_SHF_LSR_REG); } /** @@ -594,19 +619,9 @@ static ir_node *gen_Shr(ir_node *node) { * * @return the created ARM Shrs node */ -static ir_node *gen_Shrs(ir_node *node) { - ir_node *block = be_transform_node(get_nodes_block(node)); - ir_node *op1 = get_Shrs_left(node); - ir_node *new_op1 = be_transform_node(op1); - ir_node *op2 = get_Shrs_right(node); - ir_node *new_op2 = be_transform_node(op2); - ir_mode *mode = mode_Iu; - dbg_info *dbg = get_irn_dbg_info(node); - - if (is_arm_Mov_i(new_op2)) { - return new_bd_arm_Mov(dbg, block, new_op1, mode, ARM_SHF_ASR, get_arm_imm_value(new_op2)); - } - return new_bd_arm_Shrs(dbg, block, new_op1, new_op2, mode); +static ir_node *gen_Shrs(ir_node *node) +{ + return make_shift(node, MATCH_NONE, ARM_SHF_ASR_REG); } /** @@ -614,17 +629,15 @@ static ir_node *gen_Shrs(ir_node *node) { * * @return the created ARM Ror node */ -static ir_node *gen_Ror(ir_node *node, ir_node *op1, ir_node *op2) { +static ir_node *gen_Ror(ir_node *node, ir_node *op1, ir_node *op2) +{ ir_node *block = be_transform_node(get_nodes_block(node)); ir_node *new_op1 = be_transform_node(op1); + dbg_info *dbgi = get_irn_dbg_info(node); ir_node *new_op2 = be_transform_node(op2); - ir_mode *mode = mode_Iu; - dbg_info *dbg = get_irn_dbg_info(node); - if (is_arm_Mov_i(new_op2)) { - return new_bd_arm_Mov(dbg, block, new_op1, mode, ARM_SHF_ROR, get_arm_imm_value(new_op2)); - } - return new_bd_arm_Ror(dbg, block, new_op1, new_op2, mode); + return new_bd_arm_Mov_reg_shift_reg(dbgi, block, new_op1, new_op2, + ARM_SHF_ROR_REG); } /** @@ -634,15 +647,16 @@ static ir_node *gen_Ror(ir_node *node, ir_node *op1, ir_node *op2) { * * Note: there is no Rol on arm, we have to use Ror */ -static ir_node *gen_Rol(ir_node *node, ir_node *op1, ir_node *op2) { +static ir_node *gen_Rol(ir_node *node, ir_node *op1, ir_node *op2) +{ ir_node *block = be_transform_node(get_nodes_block(node)); ir_node *new_op1 = be_transform_node(op1); - ir_mode *mode = mode_Iu; - dbg_info *dbg = get_irn_dbg_info(node); + dbg_info *dbgi = get_irn_dbg_info(node); ir_node *new_op2 = be_transform_node(op2); - new_op2 = new_bd_arm_Rsb_i(dbg, block, new_op2, mode, 32); - return new_bd_arm_Ror(dbg, block, new_op1, new_op2, mode); + new_op2 = new_bd_arm_Rsb_imm(dbgi, block, new_op2, 32, 0); + return new_bd_arm_Mov_reg_shift_reg(dbgi, block, new_op1, new_op2, + ARM_SHF_ROR_REG); } /** @@ -650,7 +664,8 @@ static ir_node *gen_Rol(ir_node *node, ir_node *op1, ir_node *op2) { * * @return the created ARM Ror node */ -static ir_node *gen_Rotl(ir_node *node) { +static ir_node *gen_Rotl(ir_node *node) +{ ir_node *rotate = NULL; ir_node *op1 = get_Rotl_left(node); ir_node *op2 = get_Rotl_right(node); @@ -687,19 +702,18 @@ static ir_node *gen_Rotl(ir_node *node) { rotate = gen_Ror(node, op1, right); } } else if (is_Const(op2)) { - tarval *tv = get_Const_tarval(op2); - ir_mode *mode = get_irn_mode(node); - long bits = get_mode_size_bits(mode); + tarval *tv = get_Const_tarval(op2); + ir_mode *mode = get_irn_mode(node); + long bits = get_mode_size_bits(mode); - if (tarval_is_long(tv) && bits == 32) { - ir_node *block = be_transform_node(get_nodes_block(node)); - ir_node *new_op1 = be_transform_node(op1); - ir_mode *mode = mode_Iu; - dbg_info *dbg = get_irn_dbg_info(node); + if (tarval_is_long(tv) && bits == 32) { + ir_node *block = be_transform_node(get_nodes_block(node)); + ir_node *new_op1 = be_transform_node(op1); + dbg_info *dbgi = get_irn_dbg_info(node); - bits = (bits - get_tarval_long(tv)) & 31; - rotate = new_bd_arm_Mov(dbg, block, new_op1, mode, ARM_SHF_ROR, bits); - } + bits = (bits - get_tarval_long(tv)) & 31; + rotate = new_bd_arm_Mov_reg_shift_imm(dbgi, block, new_op1, ARM_SHF_ROR_IMM, bits); + } } if (rotate == NULL) { @@ -714,19 +728,16 @@ static ir_node *gen_Rotl(ir_node *node) { * * @return the created ARM Not node */ -static ir_node *gen_Not(ir_node *node) { +static ir_node *gen_Not(ir_node *node) +{ ir_node *block = be_transform_node(get_nodes_block(node)); ir_node *op = get_Not_op(node); ir_node *new_op = be_transform_node(op); - dbg_info *dbg = get_irn_dbg_info(node); - ir_mode *mode = mode_Iu; - arm_shift_modifier mod = ARM_SHF_NONE; - int v = is_shifter_operand(new_op, &mod); + dbg_info *dbgi = get_irn_dbg_info(node); - if (v) { - new_op = get_irn_n(new_op, 0); - } - return new_bd_arm_Mvn(dbg, block, new_op, mode, mod, v); + /* TODO: we could do alot more here with all the Mvn variations */ + + return new_bd_arm_Mvn_reg(dbgi, block, new_op); } /** @@ -735,17 +746,18 @@ static ir_node *gen_Not(ir_node *node) { * @param env The transformation environment * @return the created ARM Abs node */ -static ir_node *gen_Abs(ir_node *node) { +static ir_node *gen_Abs(ir_node *node) +{ ir_node *block = be_transform_node(get_nodes_block(node)); ir_node *op = get_Abs_op(node); ir_node *new_op = be_transform_node(op); - dbg_info *dbg = get_irn_dbg_info(node); + dbg_info *dbgi = get_irn_dbg_info(node); ir_mode *mode = get_irn_mode(node); if (mode_is_float(mode)) { env_cg->have_fp_insn = 1; if (USE_FPA(env_cg->isa)) - return new_bd_arm_fpaAbs(dbg, block, new_op, mode); + return new_bd_arm_fpaAbs(dbgi, block, new_op, mode); else if (USE_VFP(env_cg->isa)) { assert(mode != mode_E && "IEEE Extended FP not supported"); panic("VFP not supported yet"); @@ -755,8 +767,7 @@ static ir_node *gen_Abs(ir_node *node) { } } assert(mode_is_data(mode)); - mode = mode_Iu; - return new_bd_arm_Abs(dbg, block, new_op, mode); + return new_bd_arm_Abs(dbgi, block, new_op); } /** @@ -764,17 +775,18 @@ static ir_node *gen_Abs(ir_node *node) { * * @return the created ARM Minus node */ -static ir_node *gen_Minus(ir_node *node) { +static ir_node *gen_Minus(ir_node *node) +{ ir_node *block = be_transform_node(get_nodes_block(node)); ir_node *op = get_Minus_op(node); ir_node *new_op = be_transform_node(op); - dbg_info *dbg = get_irn_dbg_info(node); + dbg_info *dbgi = get_irn_dbg_info(node); ir_mode *mode = get_irn_mode(node); if (mode_is_float(mode)) { env_cg->have_fp_insn = 1; if (USE_FPA(env_cg->isa)) - return new_bd_arm_fpaMvf(dbg, block, op, mode); + return new_bd_arm_fpaMvf(dbgi, block, op, mode); else if (USE_VFP(env_cg->isa)) { assert(mode != mode_E && "IEEE Extended FP not supported"); panic("VFP not supported yet"); @@ -784,8 +796,7 @@ static ir_node *gen_Minus(ir_node *node) { } } assert(mode_is_data(mode)); - mode = mode_Iu; - return new_bd_arm_Rsb_i(dbg, block, new_op, mode, 0); + return new_bd_arm_Rsb_imm(dbgi, block, new_op, 0, 0); } /** @@ -800,61 +811,23 @@ static ir_node *gen_Load(ir_node *node) { ir_node *mem = get_Load_mem(node); ir_node *new_mem = be_transform_node(mem); ir_mode *mode = get_Load_mode(node); - dbg_info *dbg = get_irn_dbg_info(node); + dbg_info *dbgi = get_irn_dbg_info(node); ir_node *new_load = NULL; if (mode_is_float(mode)) { env_cg->have_fp_insn = 1; if (USE_FPA(env_cg->isa)) - new_load = new_bd_arm_fpaLdf(dbg, block, new_ptr, new_mem, mode); + new_load = new_bd_arm_fpaLdf(dbgi, block, new_ptr, new_mem, mode); else if (USE_VFP(env_cg->isa)) { assert(mode != mode_E && "IEEE Extended FP not supported"); panic("VFP not supported yet"); - } - else { + } else { panic("Softfloat not supported yet"); } - } - else { + } else { assert(mode_is_data(mode) && "unsupported mode for Load"); - if (mode_is_signed(mode)) { - /* sign extended loads */ - switch (get_mode_size_bits(mode)) { - case 8: - new_load = new_bd_arm_Ldrbs(dbg, block, new_ptr, new_mem, NULL, - 0, 0); - break; - case 16: - new_load = new_bd_arm_Ldrhs(dbg, block, new_ptr, new_mem, NULL, - 0, 0); - break; - case 32: - new_load = new_bd_arm_Ldr(dbg, block, new_ptr, new_mem, NULL, - 0, 0); - break; - default: - panic("mode size not supported"); - } - } else { - /* zero extended loads */ - switch (get_mode_size_bits(mode)) { - case 8: - new_load = new_bd_arm_Ldrb(dbg, block, new_ptr, new_mem, NULL, - 0, 0); - break; - case 16: - new_load = new_bd_arm_Ldrh(dbg, block, new_ptr, new_mem, NULL, - 0, 0); - break; - case 32: - new_load = new_bd_arm_Ldr(dbg, block, new_ptr, new_mem, NULL, - 0, 0); - break; - default: - panic("mode size not supported"); - } - } + new_load = new_bd_arm_Ldr(dbgi, block, new_ptr, new_mem, mode, NULL, 0, 0, false); } set_irn_pinned(new_load, get_irn_pinned(node)); @@ -883,13 +856,14 @@ static ir_node *gen_Store(ir_node *node) ir_node *val = get_Store_value(node); ir_node *new_val = be_transform_node(val); ir_mode *mode = get_irn_mode(val); - dbg_info *dbg = get_irn_dbg_info(node); + dbg_info *dbgi = get_irn_dbg_info(node); ir_node *new_store = NULL; if (mode_is_float(mode)) { env_cg->have_fp_insn = 1; if (USE_FPA(env_cg->isa)) - new_store = new_bd_arm_fpaStf(dbg, block, new_ptr, new_val, new_mem, mode); + new_store = new_bd_arm_fpaStf(dbgi, block, new_ptr, new_val, + new_mem, mode); else if (USE_VFP(env_cg->isa)) { assert(mode != mode_E && "IEEE Extended FP not supported"); panic("VFP not supported yet"); @@ -898,22 +872,8 @@ static ir_node *gen_Store(ir_node *node) } } else { assert(mode_is_data(mode) && "unsupported mode for Store"); - switch (get_mode_size_bits(mode)) { - case 8: - new_store = new_bd_arm_Strb(dbg, block, new_ptr, new_val, new_mem, - NULL, 0, 0); - break; - case 16: - new_store = new_bd_arm_Strh(dbg, block, new_ptr, new_val, new_mem, - NULL, 0, 0); - break; - case 32: - new_store = new_bd_arm_Str(dbg, block, new_ptr, new_val, new_mem, - NULL, 0, 0); - break; - default: - panic("unsupported store size %d bits\n", get_mode_size_bits(mode)); - } + new_store = new_bd_arm_Str(dbgi, block, new_ptr, new_val, new_mem, mode, + NULL, 0, 0, false); } set_irn_pinned(new_store, get_irn_pinned(node)); return new_store; @@ -928,114 +888,144 @@ static ir_node *gen_Jmp(ir_node *node) return new_bd_arm_Jmp(dbgi, new_block); } -/** - * Transforms a Cond. - * - * @return the created ARM Cond node - */ -static ir_node *gen_Cond(ir_node *node) { +static ir_node *gen_be_Call(ir_node *node) +{ + ir_node *res = be_duplicate_node(node); + arch_irn_add_flags(res, arch_irn_flags_modify_flags); + + return res; +} + +static ir_node *gen_SwitchJmp(ir_node *node) +{ ir_node *block = be_transform_node(get_nodes_block(node)); ir_node *selector = get_Cond_selector(node); - dbg_info *dbg = get_irn_dbg_info(node); - ir_mode *mode = get_irn_mode(selector); + dbg_info *dbgi = get_irn_dbg_info(node); + ir_node *new_op = be_transform_node(selector); + ir_node *const_graph; + ir_node *sub; + + ir_node *proj; + const ir_edge_t *edge; + int min = INT_MAX; + int max = INT_MIN; + int translation; + int pn; + int n_projs; + + foreach_out_edge(node, edge) { + proj = get_edge_src_irn(edge); + assert(is_Proj(proj) && "Only proj allowed at SwitchJmp"); + + pn = get_Proj_proj(proj); + + min = pnmax ? pn : max; + } + translation = min; + n_projs = max - translation + 1; - if (mode == mode_b) { - /* an conditional jump */ - ir_node *cmp_node = get_Proj_pred(selector); - ir_node *op1 = get_Cmp_left(cmp_node); - ir_node *new_op1 = be_transform_node(op1); - ir_node *op2 = get_Cmp_right(cmp_node); - - if (mode_is_float(get_irn_mode(op1))) { - ir_node *new_op2 = be_transform_node(op2); - /* floating point compare */ - pn_Cmp pnc = get_Proj_proj(selector); - - if (pnc & pn_Cmp_Uo) { - /* check for unordered, need cmf */ - return new_bd_arm_fpaCmfBra(dbg, block, new_op1, new_op2, pnc); - } - /* Hmm: use need cmfe */ - return new_bd_arm_fpaCmfeBra(dbg, block, new_op1, new_op2, pnc); - } else if (is_Const(op2) && tarval_is_null(get_Const_tarval(op2))) { - /* compare with 0 */ - return new_bd_arm_TstBra(dbg, block, new_op1, new_op1, get_Proj_proj(selector)); - } else { - /* integer compare */ - ir_node *new_op2 = be_transform_node(op2); - return new_bd_arm_CmpBra(dbg, block, new_op1, new_op2, get_Proj_proj(selector)); - } - } else { - /* SwitchJmp */ - ir_node *new_op = be_transform_node(selector); - ir_node *const_graph; - ir_node *sub; - - ir_node *proj; - const ir_edge_t *edge; - int min = INT_MAX; - int max = INT_MIN; - int translation; - int pn; - int n_projs; - - foreach_out_edge(node, edge) { - proj = get_edge_src_irn(edge); - assert(is_Proj(proj) && "Only proj allowed at SwitchJmp"); - - pn = get_Proj_proj(proj); - - min = pnmax ? pn : max; - } - translation = min; - n_projs = max - translation + 1; + foreach_out_edge(node, edge) { + proj = get_edge_src_irn(edge); + assert(is_Proj(proj) && "Only proj allowed at SwitchJmp"); - foreach_out_edge(node, edge) { - proj = get_edge_src_irn(edge); - assert(is_Proj(proj) && "Only proj allowed at SwitchJmp"); + pn = get_Proj_proj(proj) - translation; + set_Proj_proj(proj, pn); + } - pn = get_Proj_proj(proj) - translation; - set_Proj_proj(proj, pn); + const_graph = create_const_graph_value(dbgi, block, translation); + sub = new_bd_arm_Sub_reg(dbgi, block, new_op, const_graph); + return new_bd_arm_SwitchJmp(dbgi, block, sub, n_projs, get_Cond_default_proj(node) - translation); +} + +static ir_node *gen_Cmp(ir_node *node) +{ + ir_node *block = be_transform_node(get_nodes_block(node)); + ir_node *op1 = get_Cmp_left(node); + ir_node *op2 = get_Cmp_right(node); + ir_mode *cmp_mode = get_irn_mode(op1); + dbg_info *dbgi = get_irn_dbg_info(node); + ir_node *new_op1; + ir_node *new_op2; + bool is_unsigned; + + if (mode_is_float(cmp_mode)) { + /* TODO: revivie this code */ + panic("FloatCmp NIY"); +#if 0 + ir_node *new_op2 = be_transform_node(op2); + /* floating point compare */ + pn_Cmp pnc = get_Proj_proj(selector); + + if (pnc & pn_Cmp_Uo) { + /* check for unordered, need cmf */ + return new_bd_arm_fpaCmfBra(dbgi, block, new_op1, new_op2, pnc); } + /* Hmm: use need cmfe */ + return new_bd_arm_fpaCmfeBra(dbgi, block, new_op1, new_op2, pnc); +#endif + } - const_graph = create_const_graph_value(dbg, block, translation); - sub = new_bd_arm_Sub(dbg, block, new_op, const_graph, mode, ARM_SHF_NONE, 0); - return new_bd_arm_SwitchJmp(dbg, block, sub, n_projs, get_Cond_default_proj(node) - translation); + assert(get_irn_mode(op2) == cmp_mode); + is_unsigned = !mode_is_signed(cmp_mode); + + /* compare with 0 can be done with Tst */ + if (is_Const(op2) && tarval_is_null(get_Const_tarval(op2))) { + new_op1 = be_transform_node(op1); + new_op1 = gen_extension(dbgi, block, new_op1, cmp_mode); + return new_bd_arm_Tst_reg(dbgi, block, new_op1, new_op1, false, + is_unsigned); + } + if (is_Const(op1) && tarval_is_null(get_Const_tarval(op1))) { + new_op2 = be_transform_node(op2); + new_op2 = gen_extension(dbgi, block, new_op2, cmp_mode); + return new_bd_arm_Tst_reg(dbgi, block, new_op2, new_op2, true, + is_unsigned); } + + /* integer compare, TODO: use shifer_op in all its combinations */ + new_op1 = be_transform_node(op1); + new_op1 = gen_extension(dbgi, block, new_op1, cmp_mode); + new_op2 = be_transform_node(op2); + new_op2 = gen_extension(dbgi, block, new_op2, cmp_mode); + return new_bd_arm_Cmp_reg(dbgi, block, new_op1, new_op2, false, + is_unsigned); } /** - * Returns the name of a SymConst. - * @param symc the SymConst - * @return name of the SymConst + * Transforms a Cond. + * + * @return the created ARM Cond node */ -static ident *get_sc_ident(ir_node *symc) { - ir_entity *ent; - - switch (get_SymConst_kind(symc)) { - case symconst_addr_name: - return get_SymConst_name(symc); - - case symconst_addr_ent: - ent = get_SymConst_entity(symc); - set_entity_backend_marked(ent, 1); - return get_entity_ld_ident(ent); +static ir_node *gen_Cond(ir_node *node) +{ + ir_node *selector = get_Cond_selector(node); + ir_mode *mode = get_irn_mode(selector); + ir_node *block; + ir_node *flag_node; + dbg_info *dbgi; - default: - assert(0 && "Unsupported SymConst"); + if (mode != mode_b) { + return gen_SwitchJmp(node); } + assert(is_Proj(selector)); + + block = be_transform_node(get_nodes_block(node)); + dbgi = get_irn_dbg_info(node); + flag_node = be_transform_node(get_Proj_pred(selector)); - return NULL; + return new_bd_arm_B(dbgi, block, flag_node, get_Proj_proj(selector)); } static tarval *fpa_imm[3][fpa_max]; +#if 0 /** * Check, if a floating point tarval is an fpa immediate, i.e. * one of 0, 1, 2, 3, 4, 5, 10, or 0.5. */ -static int is_fpa_immediate(tarval *tv) { +static int is_fpa_immediate(tarval *tv) +{ ir_mode *mode = get_tarval_mode(tv); int i, j, res = 1; @@ -1061,6 +1051,7 @@ static int is_fpa_immediate(tarval *tv) { } return fpa_max; } +#endif /** * Transforms a Const node. @@ -1076,6 +1067,7 @@ static ir_node *gen_Const(ir_node *node) { env_cg->have_fp_insn = 1; if (USE_FPA(env_cg->isa)) { tarval *tv = get_Const_tarval(node); +#if 0 int imm = is_fpa_immediate(tv); if (imm != fpa_max) { @@ -1084,6 +1076,8 @@ static ir_node *gen_Const(ir_node *node) { else node = new_bd_arm_fpaMnf_i(dbg, block, mode, -imm); } else { +#endif + { node = new_bd_arm_fpaConst(dbg, block, tv); } be_dep_on_frame(node); @@ -1105,15 +1099,16 @@ static ir_node *gen_Const(ir_node *node) { * * @return The transformed ARM node. */ -static ir_node *gen_SymConst(ir_node *node) { - ir_node *block = be_transform_node(get_nodes_block(node)); - ir_mode *mode = mode_Iu; - dbg_info *dbg = get_irn_dbg_info(node); - ir_node *res; +static ir_node *gen_SymConst(ir_node *node) +{ + ir_node *block = be_transform_node(get_nodes_block(node)); + ir_entity *entity = get_SymConst_entity(node); + dbg_info *dbgi = get_irn_dbg_info(node); + ir_node *new_node; - res = new_bd_arm_SymConst(dbg, block, mode, get_sc_ident(node)); - be_dep_on_frame(res); - return res; + new_node = new_bd_arm_SymConst(dbgi, block, entity); + be_dep_on_frame(new_node); + return new_node; } /** @@ -1138,104 +1133,26 @@ static ir_node *gen_CopyB(ir_node *node) { dst_copy = be_new_Copy(&arm_reg_classes[CLASS_arm_gp], block, new_dst); return new_bd_arm_CopyB(dbg, block, dst_copy, src_copy, - new_bd_arm_EmptyReg(dbg, block, mode_Iu), - new_bd_arm_EmptyReg(dbg, block, mode_Iu), - new_bd_arm_EmptyReg(dbg, block, mode_Iu), + new_bd_arm_EmptyReg(dbg, block), + new_bd_arm_EmptyReg(dbg, block), + new_bd_arm_EmptyReg(dbg, block), new_mem, size); } - -/******************************************** - * _ _ - * | | | | - * | |__ ___ _ __ ___ __| | ___ ___ - * | '_ \ / _ \ '_ \ / _ \ / _` |/ _ \/ __| - * | |_) | __/ | | | (_) | (_| | __/\__ \ - * |_.__/ \___|_| |_|\___/ \__,_|\___||___/ - * - ********************************************/ - -/** - * Return an expanding stack offset. - * Note that function is called in the transform phase - * where the stack offsets are still relative regarding - * the first (frame allocating) IncSP. - * However this is exactly what we want because frame - * access must be done relative the the fist IncSP ... - */ -static int get_sp_expand_offset(ir_node *inc_sp) { - int offset = be_get_IncSP_offset(inc_sp); - - if (offset == BE_STACK_FRAME_SIZE_EXPAND) - return 0; - - return offset; -} - -#if 0 -static ir_node *gen_StackParam(ir_node *irn) { - ir_node *block = be_transform_node(get_nodes_block(node)); - ir_node *new_op = NULL; - ir_node *noreg = ia32_new_NoReg_gp(env->cg); - ir_node *mem = new_NoMem(); - ir_node *ptr = get_irn_n(irn, 0); - ir_entity *ent = be_get_frame_entity(irn); - ir_mode *mode = env->mode; - -// /* If the StackParam has only one user -> */ -// /* put it in the Block where the user resides */ -// if (get_irn_n_edges(node) == 1) { -// env->block = get_nodes_block(get_edge_src_irn(get_irn_out_edge_first(node))); -// } - - if (mode_is_float(mode)) { - if (USE_SSE2(env->cg)) - new_op = new_rd_ia32_fLoad(env->dbg, env->irg, block, ptr, noreg, mem, mode_T); - else { - env->cg->used_x87 = 1; - new_op = new_rd_ia32_vfld(env->dbg, env->irg, block, ptr, noreg, mem, mode_T); - } - } - else { - new_op = new_rd_ia32_Load(env->dbg, env->irg, block, ptr, noreg, mem, mode_T); - } - - set_ia32_frame_ent(new_op, ent); - set_ia32_use_frame(new_op); - - set_ia32_am_support(new_op, ia32_am_Source); - 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_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, env->irn)); - - return new_rd_Proj(env->dbg, env->irg, block, new_op, mode, 0); -} -#endif - /** * Transforms a FrameAddr into an ARM Add. */ -static ir_node *gen_be_FrameAddr(ir_node *node) { +static ir_node *gen_be_FrameAddr(ir_node *node) +{ ir_node *block = be_transform_node(get_nodes_block(node)); ir_entity *ent = be_get_frame_entity(node); - int offset = get_entity_offset(ent); - ir_node *op = be_get_FrameAddr_frame(node); - ir_node *new_op = be_transform_node(op); - dbg_info *dbg = get_irn_dbg_info(node); - ir_mode *mode = mode_Iu; - ir_node *cnst; - - if (be_is_IncSP(op)) { - /* BEWARE: we get an offset which is absolute from an offset that - is relative. Both must be merged */ - offset += get_sp_expand_offset(op); - } - cnst = create_const_graph_value(dbg, block, (unsigned)offset); - if (is_arm_Mov_i(cnst)) - return new_bd_arm_Add_i(dbg, block, new_op, mode, get_arm_imm_value(cnst)); - return new_bd_arm_Add(dbg, block, new_op, cnst, mode, ARM_SHF_NONE, 0); + ir_node *fp = be_get_FrameAddr_frame(node); + ir_node *new_fp = be_transform_node(fp); + dbg_info *dbgi = get_irn_dbg_info(node); + ir_node *new_node; + + new_node = new_bd_arm_FrameAddr(dbgi, block, new_fp, ent); + return new_node; } /** @@ -1303,10 +1220,6 @@ static ir_node *gen_Proj_Load(ir_node *node) { /* renumber the proj */ switch (get_arm_irn_opcode(new_load)) { case iro_arm_Ldr: - case iro_arm_Ldrb: - case iro_arm_Ldrbs: - case iro_arm_Ldrh: - case iro_arm_Ldrhs: /* handle all gp loads equal: they have the same proj numbers. */ if (proj == pn_Load_res) { return new_rd_Proj(dbgi, block, new_load, mode_Iu, pn_arm_Ldr_res); @@ -1363,24 +1276,24 @@ static ir_node *gen_Proj_Quot(ir_node *node) { switch (proj) { case pn_Quot_M: - if (is_arm_fpaDvf(new_pred) || is_arm_fpaDvf_i(new_pred)) { + if (is_arm_fpaDvf(new_pred)) { return new_rd_Proj(dbgi, block, new_pred, mode_M, pn_arm_fpaDvf_M); - } else if (is_arm_fpaRdf(new_pred) || is_arm_fpaRdf_i(new_pred)) { + } else if (is_arm_fpaRdf(new_pred)) { return new_rd_Proj(dbgi, block, new_pred, mode_M, pn_arm_fpaRdf_M); - } else if (is_arm_fpaFdv(new_pred) || is_arm_fpaFdv_i(new_pred)) { + } else if (is_arm_fpaFdv(new_pred)) { return new_rd_Proj(dbgi, block, new_pred, mode_M, pn_arm_fpaFdv_M); - } else if (is_arm_fpaFrd(new_pred) || is_arm_fpaFrd_i(new_pred)) { + } else if (is_arm_fpaFrd(new_pred)) { return new_rd_Proj(dbgi, block, new_pred, mode_M, pn_arm_fpaFrd_M); } break; case pn_Quot_res: - if (is_arm_fpaDvf(new_pred) || is_arm_fpaDvf_i(new_pred)) { + if (is_arm_fpaDvf(new_pred)) { return new_rd_Proj(dbgi, block, new_pred, mode, pn_arm_fpaDvf_res); - } else if (is_arm_fpaRdf(new_pred) || is_arm_fpaRdf_i(new_pred)) { + } else if (is_arm_fpaRdf(new_pred)) { return new_rd_Proj(dbgi, block, new_pred, mode, pn_arm_fpaRdf_res); - } else if (is_arm_fpaFdv(new_pred) || is_arm_fpaFdv_i(new_pred)) { + } else if (is_arm_fpaFdv(new_pred)) { return new_rd_Proj(dbgi, block, new_pred, mode, pn_arm_fpaFdv_res); - } else if (is_arm_fpaFrd(new_pred) || is_arm_fpaFrd_i(new_pred)) { + } else if (is_arm_fpaFrd(new_pred)) { return new_rd_Proj(dbgi, block, new_pred, mode, pn_arm_fpaFrd_res); } break; @@ -1526,37 +1439,24 @@ static inline ir_node *create_const(ir_node **place, return res; } -static ir_node *arm_new_Unknown_gp(void) { - return create_const(&env_cg->unknown_gp, new_bd_arm_Unknown_GP, - &arm_gp_regs[REG_GP_UKNWN]); -} - -static ir_node *arm_new_Unknown_fpa(void) { - return create_const(&env_cg->unknown_fpa, new_bd_arm_Unknown_FPA, - &arm_fpa_regs[REG_FPA_UKNWN]); -} +static ir_node *gen_Unknown(ir_node *node) +{ + ir_node *block = get_nodes_block(node); + ir_node *new_block = be_transform_node(block); + dbg_info *dbgi = get_irn_dbg_info(node); -/** - * This function just sets the register for the Unknown node - * as this is not done during register allocation because Unknown - * is an "ignore" node. - */ -static ir_node *gen_Unknown(ir_node *node) { + /* just produce a 0 */ ir_mode *mode = get_irn_mode(node); if (mode_is_float(mode)) { - if (USE_FPA(env_cg->isa)) - return arm_new_Unknown_fpa(); - else if (USE_VFP(env_cg->isa)) - panic("VFP not supported yet"); - else - panic("Softfloat not supported yet"); + tarval *tv = get_mode_null(mode); + ir_node *node = new_bd_arm_fpaConst(dbgi, new_block, tv); + be_dep_on_frame(node); + return node; } else if (mode_needs_gp_reg(mode)) { - return arm_new_Unknown_gp(); - } else { - assert(0 && "unsupported Unknown-Mode"); + return create_const_graph_value(dbgi, new_block, 0); } - return NULL; + panic("Unexpected Unknown mode"); } /** @@ -1595,111 +1495,79 @@ static ir_node *gen_Phi(ir_node *node) return phi; } -/********************************************************* - * _ _ _ - * (_) | | (_) - * _ __ ___ __ _ _ _ __ __| |_ __ ___ _____ _ __ - * | '_ ` _ \ / _` | | '_ \ / _` | '__| \ \ / / _ \ '__| - * | | | | | | (_| | | | | | | (_| | | | |\ V / __/ | - * |_| |_| |_|\__,_|_|_| |_| \__,_|_| |_| \_/ \___|_| - * - *********************************************************/ - /** * the BAD transformer. */ -static ir_node *bad_transform(ir_node *irn) { +static ir_node *bad_transform(ir_node *irn) +{ panic("ARM backend: Not implemented: %+F", irn); - return irn; } /** * Set a node emitter. Make it a bit more type safe. */ -static inline void set_transformer(ir_op *op, be_transform_func arm_transform_func) { +static void set_transformer(ir_op *op, be_transform_func arm_transform_func) +{ op->ops.generic = (op_func)arm_transform_func; } /** * Enters all transform functions into the generic pointer */ -static void arm_register_transformers(void) { +static void arm_register_transformers(void) +{ /* first clear the generic function pointer for all ops */ clear_irp_opcodes_generic_func(); -#define GEN(a) set_transformer(op_##a, gen_##a) -#define BAD(a) set_transformer(op_##a, bad_transform) - - GEN(Add); - GEN(Sub); - GEN(Mul); - BAD(Mulh); /* unsupported yet */ - GEN(And); - GEN(Or); - GEN(Eor); - - GEN(Shl); - GEN(Shr); - GEN(Shrs); - GEN(Rotl); - - GEN(Quot); - - /* should be lowered */ - BAD(Div); - BAD(Mod); - BAD(DivMod); - - GEN(Minus); - GEN(Conv); - GEN(Abs); - GEN(Not); - - GEN(Load); - GEN(Store); - GEN(Cond); - GEN(Jmp); - - BAD(ASM); /* unsupported yet */ - GEN(CopyB); - BAD(Mux); /* unsupported yet */ - GEN(Proj); - GEN(Phi); - - GEN(Const); - GEN(SymConst); - - /* we should never see these nodes */ - BAD(Raise); - BAD(Sel); - BAD(InstOf); - BAD(Cast); - BAD(Free); - BAD(Tuple); - BAD(Id); - //BAD(Bad); - BAD(Confirm); - BAD(Filter); - BAD(CallBegin); - BAD(EndReg); - BAD(EndExcept); - - /* handle builtins */ - BAD(Builtin); - - /* handle generic backend nodes */ - GEN(be_FrameAddr); - //GEN(be_Call); - //GEN(be_Return); - GEN(be_AddSP); - GEN(be_SubSP); - GEN(be_Copy); - - /* set the register for all Unknown nodes */ - GEN(Unknown); - -#undef GEN -#undef BAD + set_transformer(op_Abs, gen_Abs); + set_transformer(op_Add, gen_Add); + set_transformer(op_And, gen_And); + set_transformer(op_be_AddSP, gen_be_AddSP); + set_transformer(op_be_Call, gen_be_Call); + set_transformer(op_be_Copy, gen_be_Copy); + set_transformer(op_be_FrameAddr, gen_be_FrameAddr); + set_transformer(op_be_SubSP, gen_be_SubSP); + set_transformer(op_Cmp, gen_Cmp); + set_transformer(op_Cond, gen_Cond); + set_transformer(op_Const, gen_Const); + set_transformer(op_Conv, gen_Conv); + set_transformer(op_CopyB, gen_CopyB); + set_transformer(op_Eor, gen_Eor); + set_transformer(op_Jmp, gen_Jmp); + set_transformer(op_Load, gen_Load); + set_transformer(op_Minus, gen_Minus); + set_transformer(op_Mul, gen_Mul); + set_transformer(op_Not, gen_Not); + set_transformer(op_Or, gen_Or); + set_transformer(op_Phi, gen_Phi); + set_transformer(op_Proj, gen_Proj); + set_transformer(op_Quot, gen_Quot); + set_transformer(op_Rotl, gen_Rotl); + set_transformer(op_Shl, gen_Shl); + set_transformer(op_Shr, gen_Shr); + set_transformer(op_Shrs, gen_Shrs); + set_transformer(op_Store, gen_Store); + set_transformer(op_Sub, gen_Sub); + set_transformer(op_SymConst, gen_SymConst); + set_transformer(op_Unknown, gen_Unknown); + + set_transformer(op_ASM, bad_transform); + set_transformer(op_Builtin, bad_transform); + set_transformer(op_CallBegin, bad_transform); + set_transformer(op_Cast, bad_transform); + set_transformer(op_Confirm, bad_transform); + set_transformer(op_DivMod, bad_transform); + set_transformer(op_EndExcept, bad_transform); + set_transformer(op_EndReg, bad_transform); + set_transformer(op_Filter, bad_transform); + set_transformer(op_Free, bad_transform); + set_transformer(op_Id, bad_transform); + set_transformer(op_InstOf, bad_transform); + set_transformer(op_Mulh, bad_transform); + set_transformer(op_Mux, bad_transform); + set_transformer(op_Raise, bad_transform); + set_transformer(op_Sel, bad_transform); + set_transformer(op_Tuple, bad_transform); } /** @@ -1716,7 +1584,8 @@ static void arm_pretransform_node(void) /** * Initialize fpa Immediate support. */ -static void arm_init_fpa_immediate(void) { +static void arm_init_fpa_immediate(void) +{ /* 0, 1, 2, 3, 4, 5, 10, or 0.5. */ fpa_imm[0][fpa_null] = get_tarval_null(mode_F); fpa_imm[0][fpa_one] = get_tarval_one(mode_F); @@ -1749,7 +1618,8 @@ static void arm_init_fpa_immediate(void) { /** * Transform a Firm graph into an ARM graph. */ -void arm_transform_graph(arm_code_gen_t *cg) { +void arm_transform_graph(arm_code_gen_t *cg) +{ static int imm_initialized = 0; if (! imm_initialized) { @@ -1761,6 +1631,7 @@ void arm_transform_graph(arm_code_gen_t *cg) { be_transform_graph(cg->birg, arm_pretransform_node); } -void arm_init_transform(void) { - // FIRM_DBG_REGISTER(dbg, "firm.be.arm.transform"); +void arm_init_transform(void) +{ + FIRM_DBG_REGISTER(dbg, "firm.be.arm.transform"); } diff --git a/ir/be/arm/bearch_arm.c b/ir/be/arm/bearch_arm.c index 1add63412..fcc510462 100644 --- a/ir/be/arm/bearch_arm.c +++ b/ir/be/arm/bearch_arm.c @@ -20,7 +20,7 @@ /** * @file * @brief The main arm backend driver file. - * @author Oliver Richter, Tobias Gneist + * @author Matthias Braun, Oliver Richter, Tobias Gneist * @version $Id$ */ #include "config.h" @@ -44,7 +44,7 @@ #include "array_t.h" #include "irtools.h" -#include "../bearch.h" /* the general register allocator interface */ +#include "../bearch.h" #include "../benode.h" #include "../belower.h" #include "../besched.h" @@ -57,46 +57,43 @@ #include "../bespillslots.h" #include "../begnuas.h" #include "../belistsched.h" +#include "../beflags.h" #include "bearch_arm_t.h" -#include "arm_new_nodes.h" /* arm nodes interface */ -#include "gen_arm_regalloc_if.h" /* the generated interface (register type and class defenitions) */ +#include "arm_new_nodes.h" +#include "gen_arm_regalloc_if.h" #include "arm_transform.h" #include "arm_optimize.h" #include "arm_emitter.h" #include "arm_map_regs.h" -#define DEBUG_MODULE "firm.be.arm.isa" - -/* TODO: ugly, but we need it to get access to the registers assigned to Phi nodes */ -static set *cur_reg_set = NULL; - -/************************************************** - * _ _ _ __ - * | | | (_)/ _| - * _ __ ___ __ _ __ _| | | ___ ___ _| |_ - * | '__/ _ \/ _` | / _` | | |/ _ \ / __| | | _| - * | | | __/ (_| | | (_| | | | (_) | (__ | | | - * |_| \___|\__, | \__,_|_|_|\___/ \___| |_|_| - * __/ | - * |___/ - **************************************************/ - static arch_irn_class_t arm_classify(const ir_node *irn) { (void) irn; return 0; } -static ir_entity *arm_get_frame_entity(const ir_node *irn) { - /* we do NOT transform be_Spill or be_Reload nodes, so we never - have frame access using ARM nodes. */ - (void) irn; +static ir_entity *arm_get_frame_entity(const ir_node *irn) +{ + const arm_attr_t *attr = get_arm_attr_const(irn); + + if (is_arm_FrameAddr(irn)) { + const arm_SymConst_attr_t *attr = get_irn_generic_attr_const(irn); + return attr->entity; + } + if (attr->is_load_store) { + const arm_load_store_attr_t *load_store_attr + = get_arm_load_store_attr_const(irn); + if (load_store_attr->is_frame_entity) { + return load_store_attr->entity; + } + } return NULL; } -static void arm_set_frame_entity(ir_node *irn, ir_entity *ent) { +static void arm_set_frame_entity(ir_node *irn, ir_entity *ent) +{ (void) irn; (void) ent; panic("arm_set_frame_entity() called. This should not happen."); @@ -108,13 +105,20 @@ static void arm_set_frame_entity(ir_node *irn, ir_entity *ent) { */ static void arm_set_stack_bias(ir_node *irn, int bias) { - (void) irn; - (void) bias; - /* TODO: correct offset if irn accesses the stack */ + if (is_arm_FrameAddr(irn)) { + arm_SymConst_attr_t *attr = get_irn_generic_attr(irn); + attr->fp_offset += bias; + } else { + arm_load_store_attr_t *attr = get_arm_load_store_attr(irn); + assert(attr->base.is_load_store); + attr->offset += bias; + } } static int arm_get_sp_bias(const ir_node *irn) { + /* We don't have any nodes changing the stack pointer. + TODO: we probably want to support post-/pre increment/decrement later */ (void) irn; return 0; } @@ -134,17 +138,6 @@ static const arch_irn_ops_t arm_irn_ops = { NULL, /* perform_memory_operand */ }; -/************************************************** - * _ _ __ - * | | (_)/ _| - * ___ ___ __| | ___ __ _ ___ _ __ _| |_ - * / __/ _ \ / _` |/ _ \/ _` |/ _ \ '_ \ | | _| - * | (_| (_) | (_| | __/ (_| | __/ | | | | | | - * \___\___/ \__,_|\___|\__, |\___|_| |_| |_|_| - * __/ | - * |___/ - **************************************************/ - /** * Transforms the standard Firm graph into * a ARM firm graph. @@ -179,14 +172,30 @@ static void arm_finish_irg(void *self) arm_peephole_optimization(cg); } +static ir_node *arm_flags_remat(ir_node *node, ir_node *after) +{ + ir_node *block; + ir_node *copy; + + if (is_Block(after)) { + block = after; + } else { + block = get_nodes_block(after); + } + copy = exact_copy(node); + set_nodes_block(copy, block); + sched_add_after(after, copy); + return copy; +} static void arm_before_ra(void *self) { - (void) self; - /* Some stuff you need to do immediately after register allocation */ + arm_code_gen_t *cg = self; + + be_sched_fix_flags(cg->birg, &arm_reg_classes[CLASS_arm_flags], + &arm_flags_remat); } -#if 0 static void transform_Reload(ir_node *node) { ir_graph *irg = get_irn_irg(node); @@ -194,15 +203,50 @@ static void transform_Reload(ir_node *node) dbg_info *dbgi = get_irn_dbg_info(node); ir_node *ptr = get_irg_frame(irg); ir_node *mem = get_irn_n(node, be_pos_Reload_mem); + ir_mode *mode = get_irn_mode(node); ir_entity *entity = be_get_frame_entity(node); + const arch_register_t *reg; + ir_node *proj; ir_node *load; ir_node *sched_point = sched_prev(node); - load = new_bd_arm_Ldr(dbgi, block, ptr, mem, entity, false, 0); + load = new_bd_arm_Ldr(dbgi, block, ptr, mem, mode, entity, false, 0, true); + sched_add_after(sched_point, load); + sched_remove(node); + + proj = new_rd_Proj(dbgi, block, load, mode, pn_arm_Ldr_res); + + reg = arch_get_irn_register(node); + arch_set_irn_register(proj, reg); + + exchange(node, proj); +} + +static void transform_Spill(ir_node *node) +{ + ir_graph *irg = get_irn_irg(node); + ir_node *block = get_nodes_block(node); + dbg_info *dbgi = get_irn_dbg_info(node); + ir_node *ptr = get_irg_frame(irg); + ir_node *mem = new_NoMem(); + ir_node *val = get_irn_n(node, be_pos_Spill_val); + ir_mode *mode = get_irn_mode(val); + ir_entity *entity = be_get_frame_entity(node); + ir_node *sched_point; + ir_node *store; + + sched_point = sched_prev(node); + store = new_bd_arm_Str(dbgi, block, ptr, val, mem, mode, entity, false, 0, + true); + + sched_remove(node); + sched_add_after(sched_point, store); + + exchange(node, store); } -static void after_ra_walker(ir_node *block, void *data) +static void arm_after_ra_walker(ir_node *block, void *data) { ir_node *node, *prev; (void) data; @@ -214,17 +258,16 @@ static void after_ra_walker(ir_node *block, void *data) transform_Reload(node); } else if (be_is_Spill(node)) { transform_Spill(node); - } else if (be_is_MemPerm(node)) { - panic("memperm not implemented yet"); } } } -#endif static void arm_after_ra(void *self) { arm_code_gen_t *cg = self; be_coalesce_spillslots(cg->birg); + + irg_block_walk_graph(cg->irg, NULL, arm_after_ra_walker, NULL); } /** @@ -237,8 +280,6 @@ static void arm_emit_and_done(void *self) { arm_gen_routine(cg, irg); - cur_reg_set = NULL; - /* de-allocate code generator */ del_set(cg->reg_set); free(self); @@ -253,7 +294,8 @@ static void arm_emit_and_done(void *self) { * 2.) A load: simply split into two */ static ir_node *convert_dbl_to_int(ir_node *bl, ir_node *arg, ir_node *mem, - ir_node **resH, ir_node **resL) { + ir_node **resH, ir_node **resL) +{ if (is_Const(arg)) { tarval *tv = get_Const_tarval(arg); unsigned v; @@ -480,8 +522,6 @@ static void *arm_cg_init(be_irg_t *birg) { FIRM_DBG_REGISTER(cg->mod, "firm.be.arm.cg"); - cur_reg_set = cg->reg_set; - /* enter the current code generator */ isa->cg = cg; @@ -731,23 +771,14 @@ const arch_register_class_t *arm_get_reg_class_for_mode(const ir_mode *mode) { * it will contain the return address and space to store the old base pointer. * @return The Firm type modeling the ABI between type. */ -static ir_type *arm_get_between_type(void *self) { +static ir_type *arm_get_between_type(void *self) +{ static ir_type *between_type = NULL; - static ir_entity *old_bp_ent = NULL; (void) self; if (between_type == NULL) { - ir_entity *ret_addr_ent; - ir_type *ret_addr_type = new_type_primitive(new_id_from_str("return_addr"), mode_P); - ir_type *old_bp_type = new_type_primitive(new_id_from_str("bp"), mode_P); - - between_type = new_type_class(new_id_from_str("arm_between_type")); - old_bp_ent = new_entity(between_type, new_id_from_str("old_bp"), old_bp_type); - ret_addr_ent = new_entity(between_type, new_id_from_str("old_bp"), ret_addr_type); - - set_entity_offset(old_bp_ent, 0); - set_entity_offset(ret_addr_ent, get_type_size_bytes(old_bp_type)); - set_type_size_bytes(between_type, get_type_size_bytes(old_bp_type) + get_type_size_bytes(ret_addr_type)); + between_type = new_type_class(new_id_from_str("arm_between_type")); + set_type_size_bytes(between_type, 0); } return between_type; @@ -823,7 +854,7 @@ static const arch_register_t *arm_abi_prologue(void *self, ir_node **mem, pmap * *mem = new_r_Proj(block, store, mode_M, pn_arm_StoreStackM4Inc_M); /* frame pointer is ip-4 (because ip is our old sp value) */ - fp = new_bd_arm_Sub_i(NULL, block, ip, get_irn_mode(fp), 4); + fp = new_bd_arm_Sub_imm(NULL, block, ip, 4, 0); arch_set_irn_register(fp, env->arch_env->bp); /* beware: we change the fp but the StoreStackM4Inc above wants the old @@ -895,7 +926,8 @@ static const be_abi_callbacks_t arm_abi_callbacks = { * @param method_type The type of the method (procedure) in question. * @param abi The abi object to be modified */ -void arm_get_call_abi(const void *self, ir_type *method_type, be_abi_call_t *abi) { +void arm_get_call_abi(const void *self, ir_type *method_type, be_abi_call_t *abi) +{ ir_type *tp; ir_mode *mode; int i; @@ -956,7 +988,8 @@ void arm_get_call_abi(const void *self, ir_type *method_type, be_abi_call_t *abi } } -int arm_to_appear_in_schedule(void *block_env, const ir_node *irn) { +int arm_to_appear_in_schedule(void *block_env, const ir_node *irn) +{ (void) block_env; if(!is_arm_irn(irn)) return -1; @@ -967,7 +1000,8 @@ int arm_to_appear_in_schedule(void *block_env, const ir_node *irn) { /** * Initializes the code generator interface. */ -static const arch_code_generator_if_t *arm_get_code_generator_if(void *self) { +static const arch_code_generator_if_t *arm_get_code_generator_if(void *self) +{ (void) self; return &arm_code_gen_if; } @@ -977,7 +1011,8 @@ list_sched_selector_t arm_sched_selector; /** * Returns the reg_pressure scheduler with to_appear_in_schedule() over\loaded */ -static const list_sched_selector_t *arm_get_list_sched_selector(const void *self, list_sched_selector_t *selector) { +static const list_sched_selector_t *arm_get_list_sched_selector(const void *self, list_sched_selector_t *selector) +{ (void) self; memcpy(&arm_sched_selector, selector, sizeof(arm_sched_selector)); /* arm_sched_selector.exectime = arm_sched_exectime; */ diff --git a/ir/be/beabi.c b/ir/be/beabi.c index 00dee8f73..b2cf09a2b 100644 --- a/ir/be/beabi.c +++ b/ir/be/beabi.c @@ -329,7 +329,12 @@ static int stack_frame_compute_initial_offset(be_stack_layout_t *frame) ir_type *base = frame->stack_dir < 0 ? frame->between_type : frame->frame_type; ir_entity *ent = search_ent_with_offset(base, 0); - frame->initial_offset = ent ? get_stack_entity_offset(frame, ent, 0) : 0; + if (ent == NULL) { + frame->initial_offset + = frame->stack_dir < 0 ? get_type_size_bytes(frame->frame_type) : get_type_size_bytes(frame->between_type); + } else { + frame->initial_offset = get_stack_entity_offset(frame, ent, 0); + } return frame->initial_offset; } diff --git a/ir/be/beflags.c b/ir/be/beflags.c index a4cf30b38..0a3871a03 100644 --- a/ir/be/beflags.c +++ b/ir/be/beflags.c @@ -173,8 +173,10 @@ static void rematerialize_or_move(ir_node *flags_needed, ir_node *node, get_nodes_block(node) != get_nodes_block(flags_needed)) { int i; - for (i = get_irn_arity(copy) - 1; i >= 0; --i) { - be_liveness_update(lv, get_irn_n(copy, i)); + if (lv != NULL) { + for (i = get_irn_arity(copy) - 1; i >= 0; --i) { + be_liveness_update(lv, get_irn_n(copy, i)); + } } } } diff --git a/ir/be/bespillslots.c b/ir/be/bespillslots.c index 14c9b1bad..6265111aa 100644 --- a/ir/be/bespillslots.c +++ b/ir/be/bespillslots.c @@ -569,7 +569,8 @@ static void assign_spill_entity(ir_node *node, ir_entity *entity) return; } - /* beware: we might have Stores with Memory Proj's, ia32 fisttp for instance */ + /* beware: we might have Stores with Memory Proj's, ia32 fisttp for + instance */ node = skip_Proj(node); assert(arch_get_frame_entity(node) == NULL); arch_set_frame_entity(node, entity); diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c index 3d8d34c7c..6235db64e 100644 --- a/ir/be/ia32/ia32_emitter.c +++ b/ir/be/ia32/ia32_emitter.c @@ -2239,8 +2239,8 @@ static const lc_opt_table_entry_t ia32_emitter_options[] = { /* ==== Experimental binary emitter ==== */ static unsigned char reg_gp_map[N_ia32_gp_REGS]; -static unsigned char reg_mmx_map[N_ia32_mmx_REGS]; -static unsigned char reg_sse_map[N_ia32_xmm_REGS]; +//static unsigned char reg_mmx_map[N_ia32_mmx_REGS]; +//static unsigned char reg_sse_map[N_ia32_xmm_REGS]; static unsigned char pnc_map_signed[8]; static unsigned char pnc_map_unsigned[8]; diff --git a/ir/be/ia32/ia32_simd_spec.pl b/ir/be/ia32/ia32_simd_spec.pl deleted file mode 100644 index 07778a22d..000000000 --- a/ir/be/ia32/ia32_simd_spec.pl +++ /dev/null @@ -1,12 +0,0 @@ -# This file is generated! Do not edit, your changes will be lost! -# ___ _____ _____ _ _ -# / ___/ ___|| ____| __ _____ ___| |_ ___ _ __ _ __ ___ __| | ___ ___ -# \___ \___ \| _| \ \ / / _ \/ __| __/ _ \| '__| | '_ \ / _ \ / _` |/ _ \/ __| -# ___) |__) | |___ \ V / __/ (__| || (_) | | | | | | (_) | (_| | __/\__ \ -# |____/____/|_____| \_/ \___|\___|\__\___/|_| |_| |_|\___/ \__,_|\___||___/ - -$nodes{"mov_gp_variant0"} = { - reg_req => { "in" => [ "xmm", ], "out" => [ "gp", ] }, - emit => ". shl %S2, 15; .movd %S1, %S2", - latency => 3, -}; diff --git a/ir/be/ia32/ia32_spec.pl b/ir/be/ia32/ia32_spec.pl index 4cad362a8..5c0ba3fa4 100644 --- a/ir/be/ia32/ia32_spec.pl +++ b/ir/be/ia32/ia32_spec.pl @@ -33,7 +33,6 @@ $arch = "ia32"; # emit => "emit code with templates", # attr => "additional attribute arguments for constructor", # init_attr => "emit attribute initialization template", -# rd_constructor => "c source code which constructs an ir_node", # hash_func => "name of the hash function for this operation", # latency => "latency of this operation (can be float)" # attr_type => "name of the attribute struct", @@ -225,25 +224,18 @@ $arch = "ia32"; CMP3 => "${arch}_emit_cmp_suffix_node(node, 3);", ); -#--------------------------------------------------# -# _ # -# (_) # -# _ __ _____ __ _ _ __ ___ _ __ ___ # -# | '_ \ / _ \ \ /\ / / | | '__| / _ \| '_ \/ __| # -# | | | | __/\ V V / | | | | (_) | |_) \__ \ # -# |_| |_|\___| \_/\_/ |_|_| \___/| .__/|___/ # -# | | # -# |_| # -#--------------------------------------------------# + + $default_op_attr_type = "ia32_op_attr_t"; $default_attr_type = "ia32_attr_t"; $default_copy_attr = "ia32_copy_attr"; sub ia32_custom_init_attr { - my $node = shift; - my $name = shift; - my $res = ""; + my $constr = shift; + my $node = shift; + my $name = shift; + my $res = ""; if(defined($node->{modified_flags})) { $res .= "\tarch_irn_add_flags(res, arch_irn_flags_modify_flags);\n"; @@ -357,19 +349,6 @@ ProduceVal => { cmp_attr => "return 1;", }, -#-----------------------------------------------------------------# -# _ _ _ # -# (_) | | | | # -# _ _ __ | |_ ___ __ _ ___ _ __ _ __ ___ __| | ___ ___ # -# | | '_ \| __/ _ \/ _` |/ _ \ '__| | '_ \ / _ \ / _` |/ _ \/ __| # -# | | | | | || __/ (_| | __/ | | | | | (_) | (_| | __/\__ \ # -# |_|_| |_|\__\___|\__, |\___|_| |_| |_|\___/ \__,_|\___||___/ # -# __/ | # -# |___/ # -#-----------------------------------------------------------------# - -# commutative operations - Add => { irn_flags => "R", state => "exc_pinned", @@ -506,7 +485,6 @@ And => { out => [ "in_r4 in_r5", "flags", "none" ] }, ins => [ "base", "index", "mem", "left", "right" ], outs => [ "res", "flags", "M" ], - op_modes => "commutative | am | immediate | mode_neutral", am => "source,binary", emit => '. and%M %binop', units => [ "GP" ], @@ -629,8 +607,6 @@ XorMem8Bit => { modified_flags => $status_flags }, -# not commutative operations - Sub => { irn_flags => "R", state => "exc_pinned", @@ -914,8 +890,6 @@ RolMem => { modified_flags => $status_flags }, -# unary operations - Neg => { irn_flags => "R", reg_req => { in => [ "gp" ], @@ -1027,8 +1001,8 @@ NotMem => { }, Cmc => { - reg_req => { in => [ "flags" ], out => [ "flags" ] }, - emit => '.cmc', + reg_req => { in => [ "flags" ], out => [ "flags" ] }, + emit => '.cmc', units => [ "GP" ], latency => 1, mode => $mode_flags, @@ -1036,16 +1010,14 @@ Cmc => { }, Stc => { - reg_req => { out => [ "flags" ] }, - emit => '.stc', + reg_req => { out => [ "flags" ] }, + emit => '.stc', units => [ "GP" ], latency => 1, mode => $mode_flags, modified_flags => $status_flags }, -# other operations - Cmp => { irn_flags => "R", state => "exc_pinned", @@ -1752,15 +1724,6 @@ PrefetchW => { units => [ "GP" ], }, -#-----------------------------------------------------------------------------# -# _____ _____ ______ __ _ _ _ # -# / ____/ ____| ____| / _| | | | | | # -# | (___| (___ | |__ | |_| | ___ __ _| |_ _ __ ___ __| | ___ ___ # -# \___ \\___ \| __| | _| |/ _ \ / _` | __| | '_ \ / _ \ / _` |/ _ \/ __| # -# ____) |___) | |____ | | | | (_) | (_| | |_ | | | | (_) | (_| | __/\__ \ # -# |_____/_____/|______| |_| |_|\___/ \__,_|\__| |_| |_|\___/ \__,_|\___||___/ # -#-----------------------------------------------------------------------------# - # produces a 0/+0.0 xZero => { irn_flags => "R", @@ -1830,8 +1793,6 @@ xMovd => { mode => $mode_xmm }, -# commutative operations - xAdd => { irn_flags => "R", state => "exc_pinned", @@ -1930,8 +1891,6 @@ xXor => { mode => $mode_xmm }, -# not commutative operations - xAndNot => { irn_flags => "R", state => "exc_pinned", @@ -1973,8 +1932,6 @@ xDiv => { units => [ "SSE" ], }, -# other operations - Ucomi => { irn_flags => "R", state => "exc_pinned", @@ -1992,8 +1949,6 @@ Ucomi => { modified_flags => 1, }, -# Load / Store - xLoad => { op_flags => "L|F", state => "exc_pinned", @@ -2072,8 +2027,6 @@ l_FloattoLL => { reg_req => { in => [ "none" ], out => [ "none", "none" ] } }, -# CopyB - CopyB => { op_flags => "F|H", state => "pinned", @@ -2100,8 +2053,6 @@ CopyB_i => { # modified_flags => [ "DF" ] }, -# Conversions - Cwtl => { state => "exc_pinned", reg_req => { in => [ "eax" ], out => [ "eax" ] }, @@ -2171,20 +2122,6 @@ Conv_FP2FP => { mode => $mode_xmm, }, -#----------------------------------------------------------# -# _ _ _ __ _ _ # -# (_) | | | | / _| | | | # -# __ ___ _ __| |_ _ _ __ _| | | |_| | ___ __ _| |_ # -# \ \ / / | '__| __| | | |/ _` | | | _| |/ _ \ / _` | __| # -# \ V /| | | | |_| |_| | (_| | | | | | | (_) | (_| | |_ # -# \_/ |_|_| \__|\__,_|\__,_|_| |_| |_|\___/ \__,_|\__| # -# | | # -# _ __ ___ __| | ___ ___ # -# | '_ \ / _ \ / _` |/ _ \/ __| # -# | | | | (_) | (_| | __/\__ \ # -# |_| |_|\___/ \__,_|\___||___/ # -#----------------------------------------------------------# - # rematerialisation disabled for all float nodes for now, because the fpcw # handler runs before spilling and we might end up with wrong fpcw then @@ -2264,8 +2201,6 @@ vfchs => { attr_type => "ia32_x87_attr_t", }, -# virtual Load and Store - vfld => { irn_flags => "R", op_flags => "L|F", @@ -2297,8 +2232,6 @@ vfst => { attr_type => "ia32_x87_attr_t", }, -# Conversions - vfild => { state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none" ], @@ -2332,9 +2265,6 @@ vfisttp => { attr_type => "ia32_x87_attr_t", }, - -# constants - vfldz => { irn_flags => "R", reg_req => { out => [ "vfp" ] }, @@ -2405,10 +2335,8 @@ vfldl2e => { attr_type => "ia32_x87_attr_t", }, -# other - vFucomFnstsw => { -# we can't allow to rematerialize this node so we don't have +# we can't allow to rematerialize this node so we don't # accidently produce Phi(Fucom, Fucom(ins_permuted)) # irn_flags => "R", reg_req => { in => [ "vfp", "vfp" ], out => [ "eax" ] }, @@ -2459,245 +2387,208 @@ Sahf => { mode => $mode_flags, }, -#------------------------------------------------------------------------# -# ___ _____ __ _ _ _ # -# __ _( _ )___ | / _| | ___ __ _| |_ _ __ ___ __| | ___ ___ # -# \ \/ / _ \ / / | |_| |/ _ \ / _` | __| | '_ \ / _ \ / _` |/ _ \/ __| # -# > < (_) |/ / | _| | (_) | (_| | |_ | | | | (_) | (_| | __/\__ \ # -# /_/\_\___//_/ |_| |_|\___/ \__,_|\__| |_| |_|\___/ \__,_|\___||___/ # -#------------------------------------------------------------------------# - -# Note: gas is strangely buggy: fdivrp and fdivp as well as fsubrp and fsubp -# are swapped, we work this around in the emitter... - fadd => { state => "exc_pinned", - rd_constructor => "NONE", - reg_req => { }, emit => '. fadd%XM %x87_binop', latency => 4, attr_type => "ia32_x87_attr_t", + constructors => {}, }, faddp => { state => "exc_pinned", - rd_constructor => "NONE", - reg_req => { }, emit => '. faddp%XM %x87_binop', latency => 4, attr_type => "ia32_x87_attr_t", + constructors => {}, }, fmul => { state => "exc_pinned", - rd_constructor => "NONE", - reg_req => { }, emit => '. fmul%XM %x87_binop', latency => 4, attr_type => "ia32_x87_attr_t", + constructors => {}, }, fmulp => { state => "exc_pinned", - rd_constructor => "NONE", - reg_req => { }, emit => '. fmulp%XM %x87_binop',, latency => 4, attr_type => "ia32_x87_attr_t", + constructors => {}, }, fsub => { state => "exc_pinned", - rd_constructor => "NONE", - reg_req => { }, emit => '. fsub%XM %x87_binop', latency => 4, attr_type => "ia32_x87_attr_t", + constructors => {}, }, +# Note: gas is strangely buggy: fdivrp and fdivp as well as fsubrp and fsubp +# are swapped, we work this around in the emitter... + fsubp => { state => "exc_pinned", - rd_constructor => "NONE", - reg_req => { }, # see note about gas bugs emit => '. fsubrp%XM %x87_binop', latency => 4, attr_type => "ia32_x87_attr_t", + constructors => {}, }, fsubr => { state => "exc_pinned", - rd_constructor => "NONE", irn_flags => "R", - reg_req => { }, emit => '. fsubr%XM %x87_binop', latency => 4, attr_type => "ia32_x87_attr_t", + constructors => {}, }, fsubrp => { state => "exc_pinned", - rd_constructor => "NONE", irn_flags => "R", - reg_req => { }, -# see note about gas bugs +# see note about gas bugs before fsubp emit => '. fsubp%XM %x87_binop', latency => 4, attr_type => "ia32_x87_attr_t", + constructors => {}, }, fprem => { - rd_constructor => "NONE", - reg_req => { }, emit => '. fprem1', latency => 20, attr_type => "ia32_x87_attr_t", + constructors => {}, }, # this node is just here, to keep the simulator running # we can omit this when a fprem simulation function exists fpremp => { - rd_constructor => "NONE", - reg_req => { }, emit => '. fprem1\n'. '. fstp %X0', latency => 20, attr_type => "ia32_x87_attr_t", + constructors => {}, }, fdiv => { state => "exc_pinned", - rd_constructor => "NONE", - reg_req => { }, emit => '. fdiv%XM %x87_binop', latency => 20, attr_type => "ia32_x87_attr_t", + constructors => {}, }, fdivp => { state => "exc_pinned", - rd_constructor => "NONE", - reg_req => { }, -# see note about gas bugs +# see note about gas bugs before fsubp emit => '. fdivrp%XM %x87_binop', latency => 20, attr_type => "ia32_x87_attr_t", + constructors => {}, }, fdivr => { state => "exc_pinned", - rd_constructor => "NONE", - reg_req => { }, emit => '. fdivr%XM %x87_binop', latency => 20, attr_type => "ia32_x87_attr_t", + constructors => {}, }, fdivrp => { state => "exc_pinned", - rd_constructor => "NONE", - reg_req => { }, -# see note about gas bugs +# see note about gas bugs before fsubp emit => '. fdivp%XM %x87_binop', latency => 20, attr_type => "ia32_x87_attr_t", + constructors => {}, }, fabs => { - rd_constructor => "NONE", - reg_req => { }, emit => '. fabs', latency => 4, attr_type => "ia32_x87_attr_t", + constructors => {}, }, fchs => { op_flags => "R|K", - rd_constructor => "NONE", - reg_req => { }, emit => '. fchs', latency => 4, attr_type => "ia32_x87_attr_t", + constructors => {}, }, -# x87 Load and Store - fld => { - rd_constructor => "NONE", op_flags => "R|L|F", state => "exc_pinned", - reg_req => { }, emit => '. fld%XM %AM', attr_type => "ia32_x87_attr_t", latency => 2, + constructors => {}, }, fst => { - rd_constructor => "NONE", op_flags => "R|L|F", state => "exc_pinned", - reg_req => { }, emit => '. fst%XM %AM', mode => "mode_M", attr_type => "ia32_x87_attr_t", latency => 2, + constructors => {}, }, fstp => { - rd_constructor => "NONE", op_flags => "R|L|F", state => "exc_pinned", - reg_req => { }, emit => '. fstp%XM %AM', mode => "mode_M", attr_type => "ia32_x87_attr_t", latency => 2, + constructors => {}, }, -# Conversions - fild => { state => "exc_pinned", - rd_constructor => "NONE", - reg_req => { }, emit => '. fild%XM %AM', attr_type => "ia32_x87_attr_t", latency => 2, + constructors => {}, }, fist => { state => "exc_pinned", - rd_constructor => "NONE", - reg_req => { }, emit => '. fist%XM %AM', mode => "mode_M", attr_type => "ia32_x87_attr_t", latency => 2, + constructors => {}, }, fistp => { state => "exc_pinned", - rd_constructor => "NONE", - reg_req => { }, emit => '. fistp%XM %AM', mode => "mode_M", attr_type => "ia32_x87_attr_t", latency => 2, + constructors => {}, }, # SSE3 fisttp instruction fisttp => { state => "exc_pinned", - rd_constructor => "NONE", - reg_req => { }, emit => '. fisttp%XM %AM', mode => "mode_M", attr_type => "ia32_x87_attr_t", latency => 2, + constructors => {}, }, -# constants - fldz => { op_flags => "R|c|K", irn_flags => "R", @@ -2833,8 +2724,6 @@ femms => { latency => 3, }, -# compare - FucomFnstsw => { reg_req => { }, emit => ". fucom %X1\n". @@ -2881,17 +2770,6 @@ FtstFnstsw => { latency => 2, }, - -# -------------------------------------------------------------------------------- # -# ____ ____ _____ _ _ # -# / ___/ ___|| ____| __ _____ ___| |_ ___ _ __ _ __ ___ __| | ___ ___ # -# \___ \___ \| _| \ \ / / _ \/ __| __/ _ \| '__| | '_ \ / _ \ / _` |/ _ \/ __| # -# ___) |__) | |___ \ V / __/ (__| || (_) | | | | | | (_) | (_| | __/\__ \ # -# |____/____/|_____| \_/ \___|\___|\__\___/|_| |_| |_|\___/ \__,_|\___||___/ # -# # -# -------------------------------------------------------------------------------- # - - # Spilling and reloading of SSE registers, hardcoded, not generated # xxLoad => { @@ -2917,14 +2795,6 @@ xxStore => { ); # end of %nodes -# Include the generated SIMD node specification written by the SIMD optimization -$my_script_name = dirname($myname) . "/../ia32/ia32_simd_spec.pl"; -unless ($return = do $my_script_name) { - warn "couldn't parse $my_script_name: $@" if $@; - warn "couldn't do $my_script_name: $!" unless defined $return; - warn "couldn't run $my_script_name" unless $return; -} - # Transform some attributes foreach my $op (keys(%nodes)) { my $node = $nodes{$op}; diff --git a/ir/be/mips/mips_spec.pl b/ir/be/mips/mips_spec.pl index f5d7d7d2e..9d1c7f248 100644 --- a/ir/be/mips/mips_spec.pl +++ b/ir/be/mips/mips_spec.pl @@ -1,6 +1,5 @@ # Creation: 2006/02/13 # $Id$ -# This is a template specification for the Firm-Backend # the cpu architecture (ia32, ia64, mips, sparc, ppc, ...) diff --git a/ir/be/ppc32/ppc32_spec.pl b/ir/be/ppc32/ppc32_spec.pl index 6f900152f..c520fd0b8 100644 --- a/ir/be/ppc32/ppc32_spec.pl +++ b/ir/be/ppc32/ppc32_spec.pl @@ -1,6 +1,5 @@ # Creation: 2006/02/13 # $Id$ -# This is a template specification for the Firm-Backend # the cpu architecture (ia32, ia64, mips, sparc, ppc32, ...) diff --git a/ir/be/scripts/generate_new_opcodes.pl b/ir/be/scripts/generate_new_opcodes.pl index 0ea1282cd..7c1e4c9d0 100755 --- a/ir/be/scripts/generate_new_opcodes.pl +++ b/ir/be/scripts/generate_new_opcodes.pl @@ -114,13 +114,13 @@ my @obst_limit_func; my @obst_reg_reqs; my @obst_opvar; # stack for the "ir_op *op__ = NULL;" statements my @obst_get_opvar; # stack for the get_op__() functions -my @obst_constructor; # stack for node constructor functions +my $obst_constructor; # stack for node constructor functions my @obst_new_irop; # stack for the new_ir_op calls my @obst_enum_op; # stack for creating the _opcode enum -my @obst_header; # stack for function prototypes +my $obst_header; # stack for function prototypes my @obst_is_archirn; # stack for the is_$arch_irn() function my @obst_cmp_attr; # stack for the compare attribute functions -my @obst_proj; # stack for the pn_ numbers +my $obst_proj = ""; # stack for the pn_ numbers my $orig_op; my $arity; my $cmp_attr_func; @@ -158,9 +158,317 @@ foreach my $class_name (keys(%reg_classes)) { # for registering additional opcodes $n_opcodes += $additional_opcodes if (defined($additional_opcodes)); -push(@obst_header, "void ".$arch."_create_opcodes(const arch_irn_ops_t *be_ops);\n"); +$obst_header .= "void ${arch}_create_opcodes(const arch_irn_ops_t *be_ops);\n"; -push(@obst_enum_op, "typedef enum _$arch\_opcodes {\n"); +sub create_constructor { + my $op = shift; + my $name = shift; + my $n = shift; + my $on = shift; + my $known_mode; + + my $suffix = ""; + if ($name ne "") { + $suffix = "_${name}"; + } + + # determine mode + if (exists($n->{mode})) { + $known_mode = $n->{mode}; + } + + # determine arity + my $arity = 0; + if(exists($n->{"arity"})) { + $arity = $n->{"arity"}; + } elsif (exists($n->{"reg_req"}) && exists($n->{"reg_req"}{"in"})) { + $arity = scalar(@{ $n->{"reg_req"}{"in"} }); + } elsif (exists($n->{"ins"})) { + $arity = scalar(@{ $n->{"ins"} }); + } + if($arity eq "variable") { + $arity = $ARITY_VARIABLE; + } elsif($arity eq "dynamic") { + $arity = $ARITY_DYNAMIC; + } + + # determine out arity + my $out_arity = 0; + if(exists($n->{"out_arity"})) { + $out_arity = $n->{"out_arity"}; + } elsif (exists($n->{"reg_req"}) && exists($n->{"reg_req"}{"out"})) { + $out_arity = scalar(@{ $n->{"reg_req"}{"out"} }); + } elsif (exists($n->{"outs"})) { + $out_arity = scalar(@{ $n->{"outs"} }); + } + if($out_arity eq "variable") { + $out_arity = $ARITY_VARIABLE; + } elsif($out_arity eq "dynamic") { + $out_arity = $ARITY_DYNAMIC; + } + + + my $comment = $n->{"comment"}; + if(!exists($n->{"comment"})) { + $comment = "construct ${orig_op} node"; + } + $comment = + "/**\n". + " * ${comment}\n". + " */\n"; + + $obst_constructor .= $comment; + + # create constructor head + my $complete_args = ""; + $temp = ""; + + $temp = "ir_node *new_bd_${arch}_${op}${suffix}(dbg_info *dbgi, ir_node *block"; + if (!exists($n->{"args"})) { # default args + if ($arity == $ARITY_VARIABLE) { + $complete_args = ", int arity, ir_node *in[]"; + } elsif ($arity == $ARITY_DYNAMIC) { + $complete_args = ""; + } else { + for (my $i = 0; $i < $arity; $i++) { + my $opname = "op${i}"; + if (exists($n->{"ins"})) { + my @ins = @{ $n->{"ins"} }; + $opname = $ins[$i]; + } + + $complete_args .= ", ir_node *${opname}"; + } + } + if ($out_arity == $ARITY_VARIABLE) { + $complete_args .= ", int n_res"; + } + + if (!defined($known_mode)) { + $complete_args .= ", ir_mode *mode"; + } + } else { # user defined args + for my $href (@{ $n->{"args"} }) { + $href->{"type"} .= " " if ($href->{"type"} !~ / [*]?$/); # put a space between name and type if there is none at the end + $complete_args .= ", ".$href->{"type"}.$href->{"name"}; + } + } + + # we have additional attribute arguements + if (exists($n->{"attr"})) { + $complete_args .= ", ".$n->{"attr"}; + } + + $temp .= "$complete_args)"; + $obst_constructor .= "${temp}\n{\n"; + + $obst_header .= $comment; + $obst_header .= "${temp};\n"; + + # emit constructor code + $temp = < 0) { + $temp .= <{"units"})) { + $temp .= gen_execunit_list_initializer($n->{"units"}); + } else { + $temp .= <{"reg_req"})) { + my %req = %{ $n->{"reg_req"} }; + my $idx; + + undef my @in; + @in = @{ $req{"in"} } if (exists($req{"in"})); + undef my @out; + @out = @{ $req{"out"} } if exists(($req{"out"})); + + for(my $idx = 0; $idx < $#in; $idx++) { + my $req = $in[$idx]; + generate_requirements($req, $n, "${arch}_${op}", $idx, 1); + } + for(my $idx = 0; $idx < $#out; $idx++) { + my $req = $out[$idx]; + generate_requirements($req, $n, "${arch}_${op}", $idx, 0); + } + + if (@in) { + if($arity >= 0 && scalar(@in) != $arity) { + die "Fatal error: Arity and number of in requirements don't match for ${op}\n"; + } + + $temp .= "\tstatic const arch_register_req_t *in_reqs[] =\n"; + $temp .= "\t{\n"; + for ($idx = 0; $idx <= $#in; $idx++) { + my $req = $in[$idx]; + my $reqstruct = generate_requirements($req, $n, "${arch}_${op}", $idx, 1); + $temp .= "\t\t& ${reqstruct},\n"; + } + $temp .= "\t};\n"; + } else { + if($arity > 0) { + die "Fatal error: need in requirements for ${op}\n"; + } + $temp .= "\tstatic const arch_register_req_t **in_reqs = NULL;\n"; + } + + if (@out) { + if($out_arity >= 0 && scalar(@out) != $out_arity) { + die "Fatal error: Out-Arity and number of out requirements don't match for ${op}\n"; + } + + for ($idx = 0; $idx <= $#out; $idx++) { + my $req = $out[$idx]; + my $reqstruct = generate_requirements($req, $n, "${arch}_${op}", $idx, 0); + $set_out_reqs .= <out_infos[${idx}].req = &${reqstruct}; +EOF + } + } else { + if($out_arity > 0) { + die "Fatal error: need out requirements for ${op}\n"; + } + } + } else { + $temp .= "\tstatic const arch_register_req_t **in_reqs = NULL;\n"; + } + my $attr_type = $on->{attr_type}; + if(exists($n->{"init_attr"})) { + $temp .= "\t${attr_type} *attr;\n"; + } + + $temp .= "\n"; + + if($arity > 0) { + $temp .= "\t/* construct in array */\n"; + for (my $i = 0; $i < $arity; $i++) { + my $opname = "op${i}"; + if (exists($n->{"ins"})) { + my @ins = @{ $n->{"ins"} }; + $opname = $ins[$i]; + } + + $temp .= "\tin[${i}] = ${opname};\n"; + } + $temp .= "\n"; + } + + # set flags + if (exists($n->{"irn_flags"})) { + $temp .= "\t/* flags */\n"; + foreach my $flag (split(/\|/, $n->{"irn_flags"})) { + if ($flag eq "R") { + $temp .= "\tflags |= arch_irn_flags_rematerializable;\n"; + } elsif ($flag eq "N") { + $temp .= "\tflags |= arch_irn_flags_dont_spill;\n"; + } elsif ($flag eq "F") { + $temp .= "\tflags |= arch_irn_flags_modify_flags;\n"; + } elsif ($flag eq "J") { + $temp .= "\t flags |= arch_irn_flags_simple_jump;\n"; + } else { + die "Fatal error: unknown flag $flag for ${op}\n"; + } + } + $temp .= "\n"; + } + + # lookup init function + my $attr_init_code = $init_attr{$attr_type}; + if(!defined($attr_init_code)) { + die "Fatal error: Couldn't find attribute initialisation code for type '${attr_type}'"; + } + my $custominit = ""; + if(defined($custom_init_attr_func)) { + $custominit .= &$custom_init_attr_func($n, $on, "${arch}_${op}"); + } + if(defined($n->{custominit})) { + $custominit .= $n->{custominit}; + } + + $temp .= <{"init_attr"})) { + $temp .= "\tattr = get_irn_generic_attr(res);\n"; + $temp .= "\t".$n->{"init_attr"}."\n"; + } + + $temp .= <= 0 && scalar(@outs) != $out_arity) { die "Fatal error: Op ${op} has different number of outs and out_arity\n"; } $num_outs = $#outs + 1; - push(@obst_proj, "\nenum pn_$op {\n"); + $obst_proj .= "\nenum pn_${op} {\n"; for (my $idx = 0; $idx <= $#outs; $idx++) { # check, if we have additional flags annotated to out @@ -221,12 +529,14 @@ foreach my $op (keys(%nodes)) { push(@out_flags, $1); $outs[$idx] =~ s/:((S|I)(\|(S|I))*)//; } - push(@obst_proj, "\tpn_$op\_".$outs[$idx]." = $idx,\n"); + $obst_proj .= "\tpn_${op}_".$outs[$idx]." = ${idx},\n"; } - push(@obst_proj, "};\n"); + $obst_proj .= "};\n"; # outs have names, it must be a mode_T node - $known_mode = "mode_T"; + if (!defined($n{mode})) { + $n{mode} = "mode_T"; + } } if (exists($n{"ins"})) { undef my @ins; @@ -236,33 +546,30 @@ foreach my $op (keys(%nodes)) { die "Fatal error: Op ${op} has different number of ins and arity\n"; } - push(@obst_proj, "\nenum n_$op {\n"); - + $obst_proj .= "\nenum n_$op {\n"; for (my $idx = 0; $idx <= $#ins; $idx++) { - push(@obst_proj, "\tn_${op}_".$ins[$idx]." = $idx,\n"); + $obst_proj .= "\tn_${op}_".$ins[$idx]." = ${idx},\n"; } - - push(@obst_proj, "};\n"); - } - - # determine mode - if (exists($n{"mode"})) { - $known_mode = $n{"mode"}; + $obst_proj .= "};\n"; } + # Create opcode push(@obst_opvar, "ir_op *op_$op = NULL;\n"); push(@obst_get_opvar, "ir_op *get_op_$op(void) { return op_$op; }\n"); push(@obst_get_opvar, "int is_$op(const ir_node *n) { return get_$arch\_irn_opcode(n) == iro_$op; }\n\n"); push(@obst_is_archirn, "is_$op(node)"); - push(@obst_header, "extern ir_op *op_$op;\n"); - push(@obst_header, "ir_op *get_op_$op(void);\n"); - push(@obst_header, "int is_$op(const ir_node *n);\n"); + $obst_header .= <{"type"} .= " " if ($href->{"type"} !~ / [*]?$/); # put a space between name and type if there is none at the end - $complete_args .= ", ".$href->{"type"}.$href->{"name"}; - } - } - - # we have additional attribute arguements - if (exists($n{"attr"})) { - $complete_args .= ", ".$n{"attr"}; } + %constructors = ( "" => \%constructor ); + } - $temp .= "$complete_args)"; - push(@obst_constructor, $temp."\n{\n"); - push(@obst_header, $comment); - push(@obst_header, $temp.";\n"); - - # emit constructor code - if (!exists($n{"rd_constructor"})) { # default constructor - $temp = < 0) { - $temp .= <= 0 && scalar(@in) != $arity) { - die "Fatal error: Arity and number of in requirements don't match for ${op}\n"; - } - - $temp .= "\tstatic const arch_register_req_t *in_reqs[] =\n"; - $temp .= "\t{\n"; - for ($idx = 0; $idx <= $#in; $idx++) { - my $req = $in[$idx]; - my $reqstruct = generate_requirements($req, \%n, $op, $idx, 1); - $temp .= "\t\t& ${reqstruct},\n"; - } - $temp .= "\t};\n"; - } else { - if($arity > 0) { - die "Fatal error: need in requirements for ${op}\n"; - } - $temp .= "\tstatic const arch_register_req_t **in_reqs = NULL;\n"; - } - - if (@out) { - if($out_arity >= 0 && scalar(@out) != $out_arity) { - die "Fatal error: Out-Arity and number of out requirements don't match for ${op}\n"; - } - - for ($idx = 0; $idx <= $#out; $idx++) { - my $req = $out[$idx]; - my $reqstruct = generate_requirements($req, \%n, $op, $idx, 0); - $set_out_reqs .= <out_infos[${idx}].req = &${reqstruct}; -EOF - } - } else { - if($out_arity > 0) { - die "Fatal error: need out requirements for ${op}\n"; - } - } - } else { - $temp .= "\tstatic const arch_register_req_t **in_reqs = NULL;\n"; - } - if(exists($n{"init_attr"})) { - $temp .= "\t${attr_type} *attr;\n"; - } - - $temp .= "\n"; - - if($arity > 0) { - $temp .= "\t/* construct in array */\n"; - for (my $i = 0; $i < $arity; $i++) { - my $opname = "op${i}"; - if (exists($n{"ins"})) { - my @ins = @{ $n{"ins"} }; - $opname = $ins[$i]; - } - - $temp .= "\tin[${i}] = ${opname};\n"; - } - $temp .= "\n"; - } - - # set flags - if (exists($n{"irn_flags"})) { - $temp .= "\t/* flags */\n"; - foreach my $flag (split(/\|/, $n{"irn_flags"})) { - if ($flag eq "R") { - $temp .= "\tflags |= arch_irn_flags_rematerializable;\n"; - } elsif ($flag eq "N") { - $temp .= "\tflags |= arch_irn_flags_dont_spill;\n"; - } elsif ($flag eq "J") { - $temp .= "\t flags |= arch_irn_flags_simple_jump;\n"; - } else { - die "Fatal error: unknown flag $flag for ${op}\n"; - } - } - $temp .= "\n"; - } - - # lookup init function - my $attr_init_code = $init_attr{$attr_type}; - if(!defined($attr_init_code)) { - die "Fatal error: Couldn't find attribute initialisation code for type '${attr_type}'"; - } - my $custominit = ""; - if(defined($custom_init_attr_func)) { - $custominit .= &$custom_init_attr_func(\%n, $op); - } - - $temp .= <{"type"} .= " " if ($href->{"type"} !~ / [*]?$/); # put a space between name and type if there is none at the end +# $complete_args .= ", ".$href->{"type"}.$href->{"name"}; +# } +# } +# +# # we have additional attribute arguements +# if (exists($n{"attr"})) { +# $complete_args .= ", ".$n{"attr"}; +# } +# +# $temp .= "$complete_args)"; +# $obst_constructor .= "${temp}\n{\n"; +# $obst_header .= $comment; +# $obst_header .= "${temp};\n"; +# +# # emit constructor code +# if (!exists($n{"rd_constructor"})) { # default constructor +# $temp = < 0) { +# $temp .= <= 0 && scalar(@in) != $arity) { +# die "Fatal error: Arity and number of in requirements don't match for ${op}\n"; +# } +# +# $temp .= "\tstatic const arch_register_req_t *in_reqs[] =\n"; +# $temp .= "\t{\n"; +# for ($idx = 0; $idx <= $#in; $idx++) { +# my $req = $in[$idx]; +# my $reqstruct = generate_requirements($req, \%n, $op, $idx, 1); +# $temp .= "\t\t& ${reqstruct},\n"; +# } +# $temp .= "\t};\n"; +# } else { +# if($arity > 0) { +# die "Fatal error: need in requirements for ${op}\n"; +# } +# $temp .= "\tstatic const arch_register_req_t **in_reqs = NULL;\n"; +# } +# +# if (@out) { +# if($out_arity >= 0 && scalar(@out) != $out_arity) { +# die "Fatal error: Out-Arity and number of out requirements don't match for ${op}\n"; +# } +# +# for ($idx = 0; $idx <= $#out; $idx++) { +# my $req = $out[$idx]; +# my $reqstruct = generate_requirements($req, \%n, $op, $idx, 0); +# $set_out_reqs .= <out_infos[${idx}].req = &${reqstruct}; +#EOF +# } +# } else { +# if($out_arity > 0) { +# die "Fatal error: need out requirements for ${op}\n"; +# } +# } +# } else { +# $temp .= "\tstatic const arch_register_req_t **in_reqs = NULL;\n"; +# } +# if(exists($n{"init_attr"})) { +# $temp .= "\t${attr_type} *attr;\n"; +# } +# +# $temp .= "\n"; +# +# if($arity > 0) { +# $temp .= "\t/* construct in array */\n"; +# for (my $i = 0; $i < $arity; $i++) { +# my $opname = "op${i}"; +# if (exists($n{"ins"})) { +# my @ins = @{ $n{"ins"} }; +# $opname = $ins[$i]; +# } +# +# $temp .= "\tin[${i}] = ${opname};\n"; +# } +# $temp .= "\n"; +# } +# +# # set flags +# if (exists($n{"irn_flags"})) { +# $temp .= "\t/* flags */\n"; +# foreach my $flag (split(/\|/, $n{"irn_flags"})) { +# if ($flag eq "R") { +# $temp .= "\tflags |= arch_irn_flags_rematerializable;\n"; +# } elsif ($flag eq "N") { +# $temp .= "\tflags |= arch_irn_flags_dont_spill;\n"; +# } elsif ($flag eq "J") { +# $temp .= "\t flags |= arch_irn_flags_simple_jump;\n"; +# } else { +# die "Fatal error: unknown flag $flag for ${op}\n"; +# } +# } +# $temp .= "\n"; +# } +# +# # lookup init function +# my $attr_init_code = $init_attr{$attr_type}; +# if(!defined($attr_init_code)) { +# die "Fatal error: Couldn't find attribute initialisation code for type '${attr_type}'"; +# } +# my $custominit = ""; +# if(defined($custom_init_attr_func)) { +# $custominit .= &$custom_init_attr_func(\%n, $op); +# } +# +# $temp .= < depth)) { b = pred_block; depth = get_Block_dom_depth(pred_block); } - /* Avoid that the node is placed in the Start block if we are not in the - backend phase. */ + /* Avoid that the node is placed in the Start block if we are not + in the backend phase. */ if (depth == 1 && get_Block_dom_depth(get_nodes_block(n)) > 1 && get_irg_phase_state(current_ir_graph) != phase_backend) { @@ -142,7 +144,8 @@ place_floats_early(ir_node *n, waitq *worklist) { /* * Add predecessors of non floating nodes and non-floating predecessors - * of floating nodes to worklist and fix their blocks if the are in dead block. + * of floating nodes to worklist and fix their blocks if the are in dead + * block. */ irn_arity = get_irn_arity(n); @@ -220,13 +223,15 @@ place_floats_early(ir_node *n, waitq *worklist) { /** * Floating nodes form subgraphs that begin at nodes as Const, Load, - * Start, Call and that end at op_pin_state_pinned nodes as Store, Call. Place_early - * places all floating nodes reachable from its argument through floating - * nodes and adds all beginnings at op_pin_state_pinned nodes to the worklist. + * Start, Call and that end at op_pin_state_pinned nodes as Store, Call. + * Place_early places all floating nodes reachable from its argument through + * floating nodes and adds all beginnings at op_pin_state_pinned nodes to the + * worklist. * * @param worklist a worklist, used for the algorithm, empty on in/output */ -static void place_early(waitq *worklist) { +static void place_early(waitq *worklist) +{ assert(worklist); inc_irg_visited(current_ir_graph); @@ -251,8 +256,9 @@ static void place_early(waitq *worklist) { * * @return the deepest common dominator tree ancestor of block and dca */ -static ir_node *calc_dom_dca(ir_node *dca, ir_node *block) { - assert(block); +static ir_node *calc_dom_dca(ir_node *dca, ir_node *block) +{ + assert(block != NULL); /* we do not want to place nodes in dead blocks */ if (is_Block_dead(block)) @@ -305,7 +311,8 @@ static ir_node *consumer_dom_dca(ir_node *dca, ir_node *consumer, ir_node *produ return dca; } -static inline int get_block_loop_depth(ir_node *block) { +static inline int get_block_loop_depth(ir_node *block) +{ return get_loop_depth(get_irn_loop(block)); } @@ -316,7 +323,8 @@ static inline int get_block_loop_depth(ir_node *block) { * @param n the node that should be moved * @param early the earliest block we can n move to */ -static void move_out_of_loops(ir_node *n, ir_node *early) { +static void move_out_of_loops(ir_node *n, ir_node *early) +{ ir_node *best, *dca; assert(n && early); @@ -348,7 +356,8 @@ static void move_out_of_loops(ir_node *n, ir_node *early) { * * @return the deepest common dominator ancestor of all blocks of node's users */ -static ir_node *get_deepest_common_dom_ancestor(ir_node *node, ir_node *dca) { +static ir_node *get_deepest_common_dom_ancestor(ir_node *node, ir_node *dca) +{ int i; for (i = get_irn_n_outs(node) - 1; i >= 0; --i) { @@ -383,7 +392,8 @@ static ir_node *get_deepest_common_dom_ancestor(ir_node *node, ir_node *dca) { * @param node the mode_T node * @param block the block to put the Proj nodes to */ -static void set_projs_block(ir_node *node, ir_node *block) { +static void set_projs_block(ir_node *node, ir_node *block) +{ int i; for (i = get_irn_n_outs(node) - 1; i >= 0; --i) { @@ -410,7 +420,8 @@ static void set_projs_block(ir_node *node, ir_node *block) { * @param worklist a worklist, all successors of non-floating nodes are * placed here */ -static void place_floats_late(ir_node *n, pdeq *worklist) { +static void place_floats_late(ir_node *n, pdeq *worklist) +{ int i, n_outs; ir_node *early_blk; @@ -489,7 +500,8 @@ static void place_floats_late(ir_node *n, pdeq *worklist) { * * @param worklist the worklist containing the nodes to place */ -static void place_late(waitq *worklist) { +static void place_late(waitq *worklist) +{ assert(worklist); inc_irg_visited(current_ir_graph); @@ -505,7 +517,8 @@ static void place_late(waitq *worklist) { } /* Code Placement. */ -void place_code(ir_graph *irg) { +void place_code(ir_graph *irg) +{ waitq *worklist; ir_graph *rem = current_ir_graph; @@ -542,13 +555,15 @@ void place_code(ir_graph *irg) { /** * Wrapper for place_code() inside the place_code pass. */ -static void place_code_wrapper(ir_graph *irg) { +static void place_code_wrapper(ir_graph *irg) +{ set_opt_global_cse(1); optimize_graph_df(irg); place_code(irg); set_opt_global_cse(0); } -ir_graph_pass_t *place_code_pass(const char *name) { +ir_graph_pass_t *place_code_pass(const char *name) +{ return def_graph_pass(name ? name : "place", place_code_wrapper); } -- 2.20.1