#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
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");
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);
return 0;
}
-
/* Include the generated constructor functions */
#include "gen_TEMPLATE_new_nodes.c.inl"
# Creation: 2006/02/13
# $Id$
-# This is a template specification for the Firm-Backend
# the cpu architecture (ia32, ia64, mips, sparc, ppc, ...)
return new_bd_TEMPLATE_Jmp(env->dbg, env->block);
}
-/*********************************************************
- * _ _ _
- * (_) | | (_)
- * _ __ ___ __ _ _ _ __ __| |_ __ ___ _____ _ __
- * | '_ ` _ \ / _` | | '_ \ / _` | '__| \ \ / / _ \ '__|
- * | | | | | | (_| | | | | | | (_| | | | |\ V / __/ |
- * |_| |_| |_|\__,_|_|_| |_| \__,_|_| |_| \_/ \___|_|
- *
- *********************************************************/
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"));
}
}
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
-/**************************************************
- * _ _ _ __
- * | | | (_)/ _|
- * _ __ ___ __ _ __ _| | | ___ ___ _| |_
- * | '__/ _ \/ _` | / _` | | |/ _ \ / __| | | _|
- * | | | __/ (_| | | (_| | | | (_) | (__ | | |
- * |_| \___|\__, | \__,_|_|_|\___/ \___| |_|_|
- * __/ |
- * |___/
- **************************************************/
-
static arch_irn_class_t TEMPLATE_classify(const ir_node *irn)
{
(void) irn;
NULL, /* perform_memory_operand */
};
-/**************************************************
- * _ _ __
- * | | (_)/ _|
- * ___ ___ __| | ___ __ _ ___ _ __ _| |_
- * / __/ _ \ / _` |/ _ \/ _` |/ _ \ '_ \ | | _|
- * | (_| (_) | (_| | __/ (_| | __/ | | | | | |
- * \___\___/ \__,_|\___|\__, |\___|_| |_| |_|_|
- * __/ |
- * |___/
- **************************************************/
+
/**
* Transforms the standard firm graph into
-/*****************************************************************
- * ____ _ _ _____ _____
- * | _ \ | | | | |_ _|/ ____| /\
- * | |_) | __ _ ___| | _____ _ __ __| | | | | (___ / \
- * | _ < / _` |/ __| |/ / _ \ '_ \ / _` | | | \___ \ / /\ \
- * | |_) | (_| | (__| < __/ | | | (_| | _| |_ ____) / ____ \
- * |____/ \__,_|\___|_|\_\___|_| |_|\__,_| |_____|_____/_/ \_\
- *
- *****************************************************************/
-
const arch_isa_if_t TEMPLATE_isa_if;
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)
{
/**
* 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;
return reg;
}
-/*************************************************************
- * _ _ __ _ _
- * (_) | | / _| | | | |
- * _ __ _ __ _ _ __ | |_| |_ | |__ ___| |_ __ ___ _ __
- * | '_ \| '__| | '_ \| __| _| | '_ \ / _ \ | '_ \ / _ \ '__|
- * | |_) | | | | | | | |_| | | | | | __/ | |_) | __/ |
- * | .__/|_| |_|_| |_|\__|_| |_| |_|\___|_| .__/ \___|_|
- * | | | |
- * |_| |_|
- *************************************************************/
-
/**
* Emit the name of the source register at given input position.
*/
/**
* 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);
}
/**
/**
* 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. */
/**
* 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));
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.
*/
/**
* 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);
}
}
- /* 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 */
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);
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;
/**
* 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));
}
}
-/**
- * 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 ");
/* Er... our gcc does not support it... Install a newer toolchain. */
}
-/***********************************************************************************
- * _ __ _
- * (_) / _| | |
- * _ __ ___ __ _ _ _ __ | |_ _ __ __ _ _ __ ___ _____ _____ _ __| | __
- * | '_ ` _ \ / _` | | '_ \ | _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
- * | | | | | | (_| | | | | | | | | | | (_| | | | | | | __/\ V V / (_) | | | <
- * |_| |_| |_|\__,_|_|_| |_| |_| |_| \__,_|_| |_| |_|\___| \_/\_/ \___/|_| |_|\_\
- *
- ***********************************************************************************/
-
static void emit_nothing(const ir_node *irn)
{
(void) irn;
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);
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);
#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.
*/
return fpa_imm[imm_value];
}
-/***********************************************************************************
- * _ _ _ __
- * | | (_) | | / _|
- * __| |_ _ _ __ ___ _ __ ___ _ __ _ _ __ | |_ ___ _ __| |_ __ _ ___ ___
- * / _` | | | | '_ ` _ \| '_ \ / _ \ '__| | | '_ \| __/ _ \ '__| _/ _` |/ __/ _ \
- * | (_| | |_| | | | | | | |_) | __/ | | | | | | || __/ | | || (_| | (_| __/
- * \__,_|\__,_|_| |_| |_| .__/ \___|_| |_|_| |_|\__\___|_| |_| \__,_|\___\___|
- * | |
- * |_|
- ***********************************************************************************/
/**
* Dumper interface for dumping arm nodes in vcg.
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:
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;
}
}
-
-/***************************************************************************************************
- * _ _ _ __ _ _ _ _
- * | | | | | | / / | | | | | | | |
- * __ _| |_| |_ _ __ ___ ___| |_ / /_ _ ___| |_ _ __ ___ ___| |_| |__ ___ __| |___
- * / _` | __| __| '__| / __|/ _ \ __| / / _` |/ _ \ __| | '_ ` _ \ / _ \ __| '_ \ / _ \ / _` / __|
- * | (_| | |_| |_| | \__ \ __/ |_ / / (_| | __/ |_ | | | | | | __/ |_| | | | (_) | (_| \__ \
- * \__,_|\__|\__|_| |___/\___|\__/_/ \__, |\___|\__| |_| |_| |_|\___|\__|_| |_|\___/ \__,_|___/
- * __/ |
- * |___/
- ***************************************************************************************************/
-
/* 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);
}
/**
* 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);
}
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);
}
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
*/
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.
*/
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,
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;
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;
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;
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);
#include "arm_nodes_attr.h"
#include "bearch_arm_t.h"
-/***************************************************************************************************
- * _ _ _ __ _ _ _ _
- * | | | | | | / / | | | | | | | |
- * __ _| |_| |_ _ __ ___ ___| |_ / /_ _ ___| |_ _ __ ___ ___| |_| |__ ___ __| |___
- * / _` | __| __| '__| / __|/ _ \ __| / / _` |/ _ \ __| | '_ ` _ \ / _ \ __| '_ \ / _ \ / _` / __|
- * | (_| | |_| |_| | \__ \ __/ |_ / / (_| | __/ |_ | | | | | | __/ |_| | | | (_) | (_| \__ \
- * \__,_|\__|\__|_| |___/\___|\__/_/ \__, |\___|\__| |_| |_| |_|\___|\__|_| |_|\___/ \__,_|___/
- * __/ |
- * |___/
- ***************************************************************************************************/
-
/**
* Returns the attributes of a generic Arm 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.
*/
*/
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
*/
*/
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);
*/
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"
#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 */
#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,
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.
*/
#include "irgmod.h"
#include "ircons.h"
+#include "iredges.h"
#include "error.h"
#include "benode.h"
#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);
}
/*
{
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;
}
/**
* 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);
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);
+ }
}
/**
*/
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;
*/
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;
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;
}
/* 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);
}
typedef struct arm_vals {
int ops;
unsigned char values[4];
- unsigned char shifts[4];
+ unsigned char rors[4];
} arm_vals;
/**
# 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:
{ 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 => [
{ 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 = (
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 <<r>> 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 => {
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 => {
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" ],
},
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" ],
},
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",
},
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".
LdTls => {
irn_flags => "R",
- comment => "load the TLS address",
reg_req => { out => [ "gp" ] },
},
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
#include <limits.h>
+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;
*
* @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 */
/**
* 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.
*
/* 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);
}
/**
*
* @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");
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);
}
}
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)) {
}
}
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);
}
/**
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");
}
}
-#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);
}
/**
* @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);
}
/**
*
* @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);
}
/**
*
* @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);
}
/**
*
* @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);
}
/**
*
* @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);
}
/**
*
* @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);
}
/**
*
* @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);
}
/**
*
* 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);
}
/**
*
* @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);
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) {
*
* @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);
}
/**
* @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");
}
}
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);
}
/**
*
* @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");
}
}
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);
}
/**
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));
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");
}
} 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;
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 = pn<min ? pn : min;
+ max = pn>max ? 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 = pn<min ? pn : min;
- max = pn>max ? 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;
}
return fpa_max;
}
+#endif
/**
* Transforms a Const 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) {
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);
*
* @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;
}
/**
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;
}
/**
/* 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);
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;
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");
}
/**
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);
}
/**
/**
* 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);
/**
* 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) {
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");
}
/**
* @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"
#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"
#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.");
*/
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;
}
NULL, /* perform_memory_operand */
};
-/**************************************************
- * _ _ __
- * | | (_)/ _|
- * ___ ___ __| | ___ __ _ ___ _ __ _| |_
- * / __/ _ \ / _` |/ _ \/ _` |/ _ \ '_ \ | | _|
- * | (_| (_) | (_| | __/ (_| | __/ | | | | | |
- * \___\___/ \__,_|\___|\__, |\___|_| |_| |_|_|
- * __/ |
- * |___/
- **************************************************/
-
/**
* Transforms the standard Firm graph into
* a ARM firm graph.
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);
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;
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);
}
/**
arm_gen_routine(cg, irg);
- cur_reg_set = NULL;
-
/* de-allocate code generator */
del_set(cg->reg_set);
free(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;
FIRM_DBG_REGISTER(cg->mod, "firm.be.arm.cg");
- cur_reg_set = cg->reg_set;
-
/* enter the current code generator */
isa->cg = cg;
* 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;
*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
* @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;
}
}
-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;
/**
* 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;
}
/**
* 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; */
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;
}
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));
+ }
}
}
}
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);
/* ==== 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];
+++ /dev/null
-# 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,
-};
# 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",
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";
cmp_attr => "return 1;",
},
-#-----------------------------------------------------------------#
-# _ _ _ #
-# (_) | | | | #
-# _ _ __ | |_ ___ __ _ ___ _ __ _ __ ___ __| | ___ ___ #
-# | | '_ \| __/ _ \/ _` |/ _ \ '__| | '_ \ / _ \ / _` |/ _ \/ __| #
-# | | | | | || __/ (_| | __/ | | | | | (_) | (_| | __/\__ \ #
-# |_|_| |_|\__\___|\__, |\___|_| |_| |_|\___/ \__,_|\___||___/ #
-# __/ | #
-# |___/ #
-#-----------------------------------------------------------------#
-
-# commutative operations
-
Add => {
irn_flags => "R",
state => "exc_pinned",
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" ],
modified_flags => $status_flags
},
-# not commutative operations
-
Sub => {
irn_flags => "R",
state => "exc_pinned",
modified_flags => $status_flags
},
-# unary operations
-
Neg => {
irn_flags => "R",
reg_req => { in => [ "gp" ],
},
Cmc => {
- reg_req => { in => [ "flags" ], out => [ "flags" ] },
- emit => '.cmc',
+ reg_req => { in => [ "flags" ], out => [ "flags" ] },
+ emit => '.cmc',
units => [ "GP" ],
latency => 1,
mode => $mode_flags,
},
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",
units => [ "GP" ],
},
-#-----------------------------------------------------------------------------#
-# _____ _____ ______ __ _ _ _ #
-# / ____/ ____| ____| / _| | | | | | #
-# | (___| (___ | |__ | |_| | ___ __ _| |_ _ __ ___ __| | ___ ___ #
-# \___ \\___ \| __| | _| |/ _ \ / _` | __| | '_ \ / _ \ / _` |/ _ \/ __| #
-# ____) |___) | |____ | | | | (_) | (_| | |_ | | | | (_) | (_| | __/\__ \ #
-# |_____/_____/|______| |_| |_|\___/ \__,_|\__| |_| |_|\___/ \__,_|\___||___/ #
-#-----------------------------------------------------------------------------#
-
# produces a 0/+0.0
xZero => {
irn_flags => "R",
mode => $mode_xmm
},
-# commutative operations
-
xAdd => {
irn_flags => "R",
state => "exc_pinned",
mode => $mode_xmm
},
-# not commutative operations
-
xAndNot => {
irn_flags => "R",
state => "exc_pinned",
units => [ "SSE" ],
},
-# other operations
-
Ucomi => {
irn_flags => "R",
state => "exc_pinned",
modified_flags => 1,
},
-# Load / Store
-
xLoad => {
op_flags => "L|F",
state => "exc_pinned",
reg_req => { in => [ "none" ], out => [ "none", "none" ] }
},
-# CopyB
-
CopyB => {
op_flags => "F|H",
state => "pinned",
# modified_flags => [ "DF" ]
},
-# Conversions
-
Cwtl => {
state => "exc_pinned",
reg_req => { in => [ "eax" ], out => [ "eax" ] },
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
attr_type => "ia32_x87_attr_t",
},
-# virtual Load and Store
-
vfld => {
irn_flags => "R",
op_flags => "L|F",
attr_type => "ia32_x87_attr_t",
},
-# Conversions
-
vfild => {
state => "exc_pinned",
reg_req => { in => [ "gp", "gp", "none" ],
attr_type => "ia32_x87_attr_t",
},
-
-# constants
-
vfldz => {
irn_flags => "R",
reg_req => { out => [ "vfp" ] },
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" ] },
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",
latency => 3,
},
-# compare
-
FucomFnstsw => {
reg_req => { },
emit => ". fucom %X1\n".
latency => 2,
},
-
-# -------------------------------------------------------------------------------- #
-# ____ ____ _____ _ _ #
-# / ___/ ___|| ____| __ _____ ___| |_ ___ _ __ _ __ ___ __| | ___ ___ #
-# \___ \___ \| _| \ \ / / _ \/ __| __/ _ \| '__| | '_ \ / _ \ / _` |/ _ \/ __| #
-# ___) |__) | |___ \ V / __/ (__| || (_) | | | | | | (_) | (_| | __/\__ \ #
-# |____/____/|_____| \_/ \___|\___|\__\___/|_| |_| |_|\___/ \__,_|\___||___/ #
-# #
-# -------------------------------------------------------------------------------- #
-
-
# Spilling and reloading of SSE registers, hardcoded, not generated #
xxLoad => {
); # 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};
# Creation: 2006/02/13
# $Id$
-# This is a template specification for the Firm-Backend
# the cpu architecture (ia32, ia64, mips, sparc, ppc, ...)
# Creation: 2006/02/13
# $Id$
-# This is a template specification for the Firm-Backend
# the cpu architecture (ia32, ia64, mips, sparc, ppc32, ...)
my @obst_reg_reqs;
my @obst_opvar; # stack for the "ir_op *op_<arch>_<op-name> = NULL;" statements
my @obst_get_opvar; # stack for the get_op_<arch>_<op-name>() 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 <arch>_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;
# 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 = <<EOF;
+ ir_node *res;
+ ir_op *op = op_${arch}_${op};
+ int flags = 0;
+ backend_info_t *info;
+EOF
+
+ if($arity == $ARITY_DYNAMIC) {
+ $temp .= <<EOF;
+ int arity = -1;
+ ir_node **in = NULL;
+EOF
+ } elsif($arity == $ARITY_VARIABLE) {
+ } else {
+ $temp .= <<EOF;
+ int arity = $arity;
+EOF
+ if($arity > 0) {
+ $temp .= <<EOF;
+ ir_node *in[$arity];
+EOF
+ } else {
+ $temp .= <<EOF;
+ ir_node **in = NULL;
+EOF
+ }
+ }
+ if($out_arity == $ARITY_DYNAMIC) {
+ $temp .= <<EOF;
+ int n_res = -1;
+EOF
+ } elsif($out_arity == $ARITY_VARIABLE) {
+ } else {
+ $temp .= <<EOF;
+ int n_res = ${out_arity};
+EOF
+ }
+
+ if (defined($known_mode)) {
+ $temp .= <<EOF;
+ ir_mode *mode = ${known_mode};
+EOF
+ }
+
+ # set up static variables for cpu execution unit assigments
+ if (exists($n->{"units"})) {
+ $temp .= gen_execunit_list_initializer($n->{"units"});
+ } else {
+ $temp .= <<EOF;
+ static const be_execution_unit_t ***exec_units = NULL;
+EOF
+ }
+
+ undef my $in_req_var;
+ undef my $out_req_var;
+
+ my $set_out_reqs = "";
+
+ # set up static variables for requirements and registers
+ if (exists($n->{"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 .= <<EOF;
+info->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 .= <<EOF;
+ /* create node */
+ assert(op != NULL);
+ res = new_ir_node(dbgi, current_ir_graph, block, op, mode, arity, in);
+
+ /* init node attributes */
+ ${attr_init_code}
+ ${custominit}
+ info = be_get_info(res);
+ ${set_out_reqs}
+
+EOF
+
+ if (exists($n->{"init_attr"})) {
+ $temp .= "\tattr = get_irn_generic_attr(res);\n";
+ $temp .= "\t".$n->{"init_attr"}."\n";
+ }
+
+ $temp .= <<EOF;
+ /* optimize node */
+ res = optimize_node(res);
+ irn_vrfy_irg(res, current_ir_graph);
+
+ return res;
+EOF
+
+ $obst_constructor .= $temp;
+
+ # close constructor function
+ $obst_constructor .= "}\n\n";
+}
+
+push(@obst_enum_op, "typedef enum _${arch}_opcodes {\n");
foreach my $op (keys(%nodes)) {
my %n = %{ $nodes{"$op"} };
my $known_mode;
if (exists($n{"outs"})) {
undef my @outs;
- @outs = @{ $n{"outs"} };
+ @outs = @{ $n{"outs"} };
if($out_arity >= 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
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;
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 .= <<EOF;
+extern ir_op *op_${op};
+ir_op *get_op_${op}(void);
+int is_${op}(const ir_node *n);
+EOF
- my $attr_type= $n{"attr_type"};
+ my $attr_type= $n{attr_type};
if(!defined($attr_type)) {
$attr_type = $default_attr_type;
+ $n{attr_type} = $attr_type;
}
# determine hash function
}
}
- if (exists($n{"rd_constructor"}) && $n{"rd_constructor"} =~ /^NONE$/i) {
- # we explicitly skip the constructor if the specification entry says NONE
+ my %constructors;
+ if (exists($n{constructors})) {
+ %constructors = %{ $n{constructors} };
} else {
- my $comment = $n{"comment"};
- if(!exists($n{"comment"})) {
- $comment = "construct ${orig_op} node";
- }
- $comment =
- "/**\n".
- " * ${comment}\n".
- " */\n";
-
- push(@obst_constructor, $comment);
-
- # create constructor head
- my $complete_args = "";
- $temp = "";
-
- $temp = "ir_node *new_bd_$op(dbg_info *db, 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";
+ # Create 1 default constructor
+ my %constructor = ();
+ foreach my $a ("comment", "ins", "outs", "args", "attr", "units",
+ "reg_req", "init_attr", "irn_flags", "mode", "arity",
+ "out_arity", "custominit") {
+ if (defined($n{$a})) {
+ $constructor{$a} = $n{$a};
}
-
- 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"};
}
+ %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 = <<EOF;
- ir_node *res;
- ir_op *op = op_${op};
- int flags = 0;
- backend_info_t *info;
-EOF
-
- if($arity == $ARITY_DYNAMIC) {
- $temp .= <<EOF;
- int arity = -1;
- ir_node **in = NULL;
-EOF
- } elsif($arity == $ARITY_VARIABLE) {
- } else {
- $temp .= <<EOF;
- int arity = $arity;
-EOF
- if($arity > 0) {
- $temp .= <<EOF;
- ir_node *in[$arity];
-EOF
- } else {
- $temp .= <<EOF;
- ir_node **in = NULL;
-EOF
- }
- }
- if($out_arity == $ARITY_DYNAMIC) {
- $temp .= <<EOF;
- int n_res = -1;
-EOF
- } elsif($out_arity == $ARITY_VARIABLE) {
- } else {
- $temp .= <<EOF;
- int n_res = ${out_arity};
-EOF
- }
-
- if (defined($known_mode)) {
- $temp .= <<EOF;
- ir_mode *mode = ${known_mode};
-EOF
- }
-
- # set up static variables for cpu execution unit assigments
- if (exists($n{"units"})) {
- $temp .= gen_execunit_list_initializer($n{"units"});
- } else {
- $temp .= <<EOF;
- static const be_execution_unit_t ***exec_units = NULL;
-EOF
- }
-
- undef my $in_req_var;
- undef my $out_req_var;
-
- my $set_out_reqs = "";
-
- # set up static variables for requirements and registers
- if (exists($n{"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, $op, $idx, 1);
- }
- for(my $idx = 0; $idx < $#out; $idx++) {
- my $req = $out[$idx];
- generate_requirements($req, \%n, $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, $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 .= <<EOF;
- info->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 .= <<EOF;
- /* create node */
- assert(op != NULL);
- res = new_ir_node(db, current_ir_graph, block, op, mode, arity, in);
-
- /* init node attributes */
- ${attr_init_code}
- ${custominit}
- info = be_get_info(res);
- ${set_out_reqs}
-
-EOF
-
- if (exists($n{"init_attr"})) {
- $temp .= "\tattr = get_irn_generic_attr(res);\n";
- $temp .= "\t".$n{"init_attr"}."\n";
+ foreach my $constr (keys(%constructors)) {
+ my %cstr = %{ $constructors{$constr} };
+ # Copy some values from outer node if they don't exists in the constr
+ foreach my $a ("ins", "outs", "irn_flags", "mode", "args", "attr",
+ "custominit") {
+ if (!defined($cstr{$a}) && defined($n{$a})) {
+ $cstr{$a} = $n{$a};
}
-
- $temp .= <<EOF;
- /* optimize node */
- res = optimize_node(res);
- irn_vrfy_irg(res, current_ir_graph);
-
- return res;
-EOF
-
- push(@obst_constructor, $temp);
- }
- else { # user defined constructor
- push(@obst_constructor, $n{"rd_constructor"});
}
+ create_constructor($orig_op, $constr, \%cstr, \%n);
+ }
- # close constructor function
- push(@obst_constructor, "}\n\n");
- } # constructor creation
+# if (exists($n{"rd_constructor"}) && $n{"rd_constructor"} =~ /^NONE$/i) {
+# # we explicitly skip the constructor if the specification entry says NONE
+# } else {
+# 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_$op(dbg_info *db, 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
+# if (!exists($n{"rd_constructor"})) { # default constructor
+# $temp = <<EOF;
+# ir_node *res;
+# ir_op *op = op_${op};
+# int flags = 0;
+# backend_info_t *info;
+#EOF
+#
+# if($arity == $ARITY_DYNAMIC) {
+# $temp .= <<EOF;
+# int arity = -1;
+# ir_node **in = NULL;
+#EOF
+# } elsif($arity == $ARITY_VARIABLE) {
+# } else {
+# $temp .= <<EOF;
+# int arity = $arity;
+#EOF
+# if($arity > 0) {
+# $temp .= <<EOF;
+# ir_node *in[$arity];
+#EOF
+# } else {
+# $temp .= <<EOF;
+# ir_node **in = NULL;
+#EOF
+# }
+# }
+# if($out_arity == $ARITY_DYNAMIC) {
+# $temp .= <<EOF;
+# int n_res = -1;
+#EOF
+# } elsif($out_arity == $ARITY_VARIABLE) {
+# } else {
+# $temp .= <<EOF;
+# int n_res = ${out_arity};
+#EOF
+# }
+#
+# if (defined($known_mode)) {
+# $temp .= <<EOF;
+# ir_mode *mode = ${known_mode};
+#EOF
+# }
+#
+# # set up static variables for cpu execution unit assigments
+# if (exists($n{"units"})) {
+# $temp .= gen_execunit_list_initializer($n{"units"});
+# } else {
+# $temp .= <<EOF;
+# static const be_execution_unit_t ***exec_units = NULL;
+#EOF
+# }
+#
+# undef my $in_req_var;
+# undef my $out_req_var;
+#
+# my $set_out_reqs = "";
+#
+# # set up static variables for requirements and registers
+# if (exists($n{"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, $op, $idx, 1);
+# }
+# for(my $idx = 0; $idx < $#out; $idx++) {
+# my $req = $out[$idx];
+# generate_requirements($req, \%n, $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, $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 .= <<EOF;
+# info->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 .= <<EOF;
+# /* create node */
+# assert(op != NULL);
+# res = new_ir_node(db, current_ir_graph, block, op, mode, arity, in);
+#
+# /* init node attributes */
+# ${attr_init_code}
+# ${custominit}
+# info = be_get_info(res);
+# ${set_out_reqs}
+#
+#EOF
+#
+# if (exists($n{"init_attr"})) {
+# $temp .= "\tattr = get_irn_generic_attr(res);\n";
+# $temp .= "\t".$n{"init_attr"}."\n";
+# }
+#
+# $temp .= <<EOF;
+# /* optimize node */
+# res = optimize_node(res);
+# irn_vrfy_irg(res, current_ir_graph);
+#
+# return res;
+#EOF
+#
+# $obst_constructor .= $temp;
+# }
+# else { # user defined constructor
+# $obst_constructor .= $n{"rd_constructor"};
+# }
+#
+# # close constructor function
+# $obst_constructor .= "}\n\n";
+# } # constructor creation
# set default values for state and flags if not given
$n{"state"} = "floats" if (! exists($n{"state"}));
}
$n_opcodes++;
- my $n_res = $out_arity;
- if($n_res < 0) {
- $n_res = "20"; # hacky....
- }
$temp = "\top_$op = new_ir_op(cur_opcode + iro_$op, \"$op\", op_pin_state_".$n{"state"}.", ".$n{"op_flags"};
$temp .= "|M, ".translate_arity($arity).", 0, sizeof(${attr_type}), &ops);\n";
push(@obst_new_irop, $temp);
push(@obst_enum_op, "\tiro_$op,\n");
- push(@obst_header, "\n");
+ $obst_header .= "\n";
}
push(@obst_enum_op, "\tiro_$arch\_last_generated,\n");
push(@obst_enum_op, "\tiro_$arch\_last = iro_$arch\_last_generated");
print OUT @obst_reg_reqs;
print OUT "\n";
-print OUT @obst_constructor;
-
print OUT<<ENDOFMAIN;
+$obst_constructor
+
/**
* Creates the $arch specific Firm machine operations
* needed for the assembler irgs.
EOF
print OUT @obst_enum_op;
-print OUT "int is_$arch\_irn(const ir_node *node);\n\n";
-print OUT "int get_$arch\_opcode_first(void);\n";
-print OUT "int get_$arch\_opcode_last(void);\n";
-print OUT "int get_$arch\_irn_opcode(const ir_node *node);\n";
-print OUT @obst_header;
-print OUT @obst_proj;
-
print OUT <<EOF;
+int is_${arch}_irn(const ir_node *node);
+
+int get_${arch}_opcode_first(void);
+int get_${arch}_opcode_last(void);
+int get_${arch}_irn_opcode(const ir_node *node);
+${obst_header}
+${obst_proj}
+
#endif
EOF
*
* @param block the block to test
*/
-static int
-is_Block_unreachable(ir_node *block) {
+static int is_Block_unreachable(ir_node *block)
+{
return is_Block_dead(block) || get_Block_dom_depth(block) < 0;
}
* @param n the node to be placed
* @param worklist a worklist, predecessors of non-floating nodes are placed here
*/
-static void
-place_floats_early(ir_node *n, waitq *worklist) {
+static void place_floats_early(ir_node *n, waitq *worklist)
+{
int i, irn_arity;
/* we must not run into an infinite loop */
/*
* If the current node is NOT in a dead block, but one of its
- * predecessors is, we must move the predecessor to a live block.
- * Such thing can happen, if global CSE chose a node from a dead block.
- * We move it simply to our block.
+ * predecessors is, we must move the predecessor to a live
+ * block.
+ * Such thing can happen, if global CSE chose a node from a
+ * dead block. We move it simply to our block.
* Note that neither Phi nor End nodes are floating, so we don't
* need to handle them here.
*/
if (in_dead_block)
continue;
- /* Because all loops contain at least one op_pin_state_pinned node, now all
- our inputs are either op_pin_state_pinned or place_early() has already
- been finished on them. We do not have any unfinished inputs! */
+ /* Because all loops contain at least one op_pin_state_pinned node,
+ now all our inputs are either op_pin_state_pinned or
+ place_early() has already been finished on them.
+ We do not have any unfinished inputs! */
pred_block = get_nodes_block(pred);
if ((!is_Block_dead(pred_block)) &&
(get_Block_dom_depth(pred_block) > 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) {
/*
* 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);
/**
* 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);
*
* @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))
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));
}
* @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);
*
* @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) {
* @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) {
* @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;
*
* @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);
}
/* Code Placement. */
-void place_code(ir_graph *irg) {
+void place_code(ir_graph *irg)
+{
waitq *worklist;
ir_graph *rem = current_ir_graph;
/**
* 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);
}