Commit 24fedddc authored by Matthias Braun's avatar Matthias Braun
Browse files

- refactoring of backend generator scripts: You can create multiple constructors

  (with different arguments and register constraints for the same node now)
- Lots of cleanups/changes in the arm backend. We can represent all
  "shifter operands" now (but the code selection isn't optimal yet)
- More fixes all over the place - arm backend handles 164.gzip now

[r26673]
parent c48b7b03
......@@ -45,19 +45,6 @@
#include "TEMPLATE_new_nodes.h"
#include "gen_TEMPLATE_regalloc_if.h"
/***********************************************************************************
* _ _ _ __
* | | (_) | | / _|
* __| |_ _ _ __ ___ _ __ ___ _ __ _ _ __ | |_ ___ _ __| |_ __ _ ___ ___
* / _` | | | | '_ ` _ \| '_ \ / _ \ '__| | | '_ \| __/ _ \ '__| _/ _` |/ __/ _ \
* | (_| | |_| | | | | | | |_) | __/ | | | | | | || __/ | | || (_| | (_| __/
* \__,_|\__,_|_| |_| |_| .__/ \___|_| |_|_| |_|\__\___|_| |_| \__,_|\___\___|
* | |
* |_|
***********************************************************************************/
/**
* Dumper interface for dumping TEMPLATE nodes in vcg.
* @param n the node to dump
......@@ -99,17 +86,6 @@ static int TEMPLATE_dump_node(ir_node *n, FILE *F, dump_reason_t reason)
return 0;
}
/***************************************************************************************************
* _ _ _ __ _ _ _ _
* | | | | | | / / | | | | | | | |
* __ _| |_| |_ _ __ ___ ___| |_ / /_ _ ___| |_ _ __ ___ ___| |_| |__ ___ __| |___
* / _` | __| __| '__| / __|/ _ \ __| / / _` |/ _ \ __| | '_ ` _ \ / _ \ __| '_ \ / _ \ / _` / __|
* | (_| | |_| |_| | \__ \ __/ |_ / / (_| | __/ |_ | | | | | | __/ |_| | | | (_) | (_| \__ \
* \__,_|\__|\__|_| |___/\___|\__/_/ \__, |\___|\__| |_| |_| |_|\___|\__|_| |_|\___/ \__,_|___/
* __/ |
* |___/
***************************************************************************************************/
const TEMPLATE_attr_t *get_TEMPLATE_attr_const(const ir_node *node)
{
assert(is_TEMPLATE_irn(node) && "need TEMPLATE node to get attributes");
......@@ -171,16 +147,6 @@ void init_TEMPLATE_attributes(ir_node *node, arch_irn_flags_t flags,
memset(info->out_infos, 0, n_res * sizeof(info->out_infos[0]));
}
/***************************************************************************************
* _ _ _
* | | | | | |
* _ __ ___ __| | ___ ___ ___ _ __ ___| |_ _ __ _ _ ___| |_ ___ _ __ ___
* | '_ \ / _ \ / _` |/ _ \ / __/ _ \| '_ \/ __| __| '__| | | |/ __| __/ _ \| '__/ __|
* | | | | (_) | (_| | __/ | (_| (_) | | | \__ \ |_| | | |_| | (__| || (_) | | \__ \
* |_| |_|\___/ \__,_|\___| \___\___/|_| |_|___/\__|_| \__,_|\___|\__\___/|_| |___/
*
***************************************************************************************/
static int TEMPLATE_compare_attr(ir_node *a, ir_node *b)
{
const TEMPLATE_attr_t *attr_a = get_TEMPLATE_attr_const(a);
......@@ -191,6 +157,5 @@ static int TEMPLATE_compare_attr(ir_node *a, ir_node *b)
return 0;
}
/* Include the generated constructor functions */
#include "gen_TEMPLATE_new_nodes.c.inl"
# Creation: 2006/02/13
# $Id$
# This is a template specification for the Firm-Backend
# the cpu architecture (ia32, ia64, mips, sparc, ppc, ...)
......
......@@ -286,15 +286,6 @@ static ir_node *gen_Jmp(TEMPLATE_transform_env_t *env)
return new_bd_TEMPLATE_Jmp(env->dbg, env->block);
}
/*********************************************************
* _ _ _
* (_) | | (_)
* _ __ ___ __ _ _ _ __ __| |_ __ ___ _____ _ __
* | '_ ` _ \ / _` | | '_ \ / _` | '__| \ \ / / _ \ '__|
* | | | | | | (_| | | | | | | (_| | | | |\ V / __/ |
* |_| |_| |_|\__,_|_|_| |_| \__,_|_| |_| \_/ \___|_|
*
*********************************************************/
......@@ -404,8 +395,7 @@ bad:
if (asm_node) {
exchange(node, asm_node);
DB((dbg, LEVEL_1, "created node %+F[%p]\n", asm_node, asm_node));
}
else {
} else {
DB((dbg, LEVEL_1, "ignored\n"));
}
}
......
......@@ -53,17 +53,6 @@
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
/**************************************************
* _ _ _ __
* | | | (_)/ _|
* _ __ ___ __ _ __ _| | | ___ ___ _| |_
* | '__/ _ \/ _` | / _` | | |/ _ \ / __| | | _|
* | | | __/ (_| | | (_| | | | (_) | (__ | | |
* |_| \___|\__, | \__,_|_|_|\___/ \___| |_|_|
* __/ |
* |___/
**************************************************/
static arch_irn_class_t TEMPLATE_classify(const ir_node *irn)
{
(void) irn;
......@@ -116,16 +105,7 @@ static const arch_irn_ops_t TEMPLATE_irn_ops = {
NULL, /* perform_memory_operand */
};
/**************************************************
* _ _ __
* | | (_)/ _|
* ___ ___ __| | ___ __ _ ___ _ __ _| |_
* / __/ _ \ / _` |/ _ \/ _` |/ _ \ '_ \ | | _|
* | (_| (_) | (_| | __/ (_| | __/ | | | | | |
* \___\___/ \__,_|\___|\__, |\___|_| |_| |_|_|
* __/ |
* |___/
**************************************************/
/**
* Transforms the standard firm graph into
......@@ -214,16 +194,6 @@ static void *TEMPLATE_cg_init(be_irg_t *birg)
/*****************************************************************
* ____ _ _ _____ _____
* | _ \ | | | | |_ _|/ ____| /\
* | |_) | __ _ ___| | _____ _ __ __| | | | | (___ / \
* | _ < / _` |/ __| |/ / _ \ '_ \ / _` | | | \___ \ / /\ \
* | |_) | (_| | (__| < __/ | | | (_| | _| |_ ____) / ____ \
* |____/ \__,_|\___|_|\_\___|_| |_|\__,_| |_____|_____/_/ \_\
*
*****************************************************************/
const arch_isa_if_t TEMPLATE_isa_if;
static TEMPLATE_isa_t TEMPLATE_isa_template = {
{
......@@ -240,7 +210,7 @@ static TEMPLATE_isa_t TEMPLATE_isa_template = {
};
/**
* Initializes the backend ISA and opens the output file.
* Initializes the backend ISA
*/
static arch_env_t *TEMPLATE_init(FILE *outfile)
{
......
......@@ -68,7 +68,8 @@ static set *sym_or_tv;
/**
* Returns the register at in position pos.
*/
static const arch_register_t *get_in_reg(const ir_node *irn, int pos) {
static const arch_register_t *get_in_reg(const ir_node *irn, int pos)
{
ir_node *op;
const arch_register_t *reg = NULL;
......@@ -133,17 +134,6 @@ static const arch_register_t *get_out_reg(const ir_node *node, int pos)
return reg;
}
/*************************************************************
* _ _ __ _ _
* (_) | | / _| | | | |
* _ __ _ __ _ _ __ | |_| |_ | |__ ___| |_ __ ___ _ __
* | '_ \| '__| | '_ \| __| _| | '_ \ / _ \ | '_ \ / _ \ '__|
* | |_) | | | | | | | |_| | | | | | __/ | |_) | __/ |
* | .__/|_| |_|_| |_|\__|_| |_| |_|\___|_| .__/ \___|_|
* | | | |
* |_| |_|
*************************************************************/
/**
* Emit the name of the source register at given input position.
*/
......@@ -163,18 +153,12 @@ void arm_emit_dest_register(const ir_node *node, int pos) {
/**
* Emit a node's offset.
*/
void arm_emit_offset(const ir_node *node) {
int offset = 0;
ir_opcode opc = get_irn_opcode(node);
void arm_emit_offset(const ir_node *node)
{
const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
assert(attr->base.is_load_store);
if (opc == beo_Reload || opc == beo_Spill) {
ir_entity *ent = be_get_frame_entity(node);
offset = get_entity_offset(ent);
} else {
assert(!"unimplemented arm_emit_offset for this node type");
panic("unimplemented arm_emit_offset for this node type");
}
be_emit_irprintf("%d", offset);
be_emit_irprintf("0x%X", attr->offset);
}
/**
......@@ -209,32 +193,119 @@ void arm_emit_mode(const ir_node *node) {
/**
* Emit a const or SymConst value.
*/
void arm_emit_immediate(const ir_node *node) {
void arm_emit_immediate(const ir_node *node)
{
const arm_attr_t *attr = get_arm_attr_const(node);
if (ARM_GET_SHF_MOD(attr) == ARM_SHF_IMM) {
be_emit_irprintf("#0x%X", arm_decode_imm_w_shift(get_arm_imm_value(node)));
} else if (ARM_GET_FPA_IMM(attr)) {
be_emit_irprintf("#%s", arm_get_fpa_imm_name(get_arm_imm_value(node)));
} else if (is_arm_SymConst(node))
be_emit_ident(get_arm_symconst_id(node));
else {
if (ARM_GET_FPA_IMM(attr)) {
/* TODO */
//be_emit_irprintf("#%s", arm_get_fpa_imm_name(get_arm_imm_value(node)));
} else {
assert(!"not a Constant");
}
}
/**
* Returns the tarval or offset of an arm node as a string.
*/
void arm_emit_shift(const ir_node *node) {
arm_shift_modifier mod;
void arm_emit_load_mode(const ir_node *node)
{
const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
ir_mode *mode = attr->load_store_mode;
int bits = get_mode_size_bits(mode);
bool is_signed = mode_is_signed(mode);
if (bits == 16) {
be_emit_string(is_signed ? "sh" : "h");
} else if (bits == 8) {
be_emit_string(is_signed ? "sb" : "b");
} else {
assert(bits == 32);
}
}
void arm_emit_store_mode(const ir_node *node)
{
const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
ir_mode *mode = attr->load_store_mode;
int bits = get_mode_size_bits(mode);
if (bits == 16) {
be_emit_cstring("h");
} else if (bits == 8) {
be_emit_cstring("b");
} else {
assert(bits == 32);
}
}
static void emit_shf_mod_name(arm_shift_modifier mod)
{
switch (mod) {
case ARM_SHF_ASR_REG:
case ARM_SHF_ASR_IMM:
be_emit_cstring("asr");
return;
case ARM_SHF_LSL_REG:
case ARM_SHF_LSL_IMM:
be_emit_cstring("lsl");
return;
case ARM_SHF_LSR_REG:
case ARM_SHF_LSR_IMM:
be_emit_cstring("lsr");
return;
case ARM_SHF_ROR_REG:
case ARM_SHF_ROR_IMM:
be_emit_cstring("ror");
return;
default:
break;
}
panic("can't emit this shf_mod_name %d", (int) mod);
}
void arm_emit_shifter_operand(const ir_node *node)
{
const arm_shifter_operand_t *attr = get_irn_generic_attr_const(node);
mod = get_arm_shift_modifier(node);
if (ARM_HAS_SHIFT(mod)) {
int v = get_arm_imm_value(node);
switch (attr->shift_modifier) {
case ARM_SHF_REG:
arm_emit_source_register(node, get_irn_arity(node) - 1);
return;
case ARM_SHF_IMM: {
unsigned val = attr->immediate_value;
val = (val >> attr->shift_immediate)
| (val << (32-attr->shift_immediate));
val &= 0xFFFFFFFF;
be_emit_irprintf("#0x%X", val);
return;
}
case ARM_SHF_ASR_IMM:
case ARM_SHF_LSL_IMM:
case ARM_SHF_LSR_IMM:
case ARM_SHF_ROR_IMM:
arm_emit_source_register(node, get_irn_arity(node) - 1);
be_emit_cstring(", ");
emit_shf_mod_name(attr->shift_modifier);
be_emit_irprintf(" #0x%X", attr->shift_immediate);
return;
case ARM_SHF_ASR_REG:
case ARM_SHF_LSL_REG:
case ARM_SHF_LSR_REG:
case ARM_SHF_ROR_REG:
arm_emit_source_register(node, get_irn_arity(node) - 2);
be_emit_cstring(", ");
emit_shf_mod_name(attr->shift_modifier);
be_emit_cstring(" ");
arm_emit_source_register(node, get_irn_arity(node) - 1);
return;
case ARM_SHF_RRX:
arm_emit_source_register(node, get_irn_arity(node) - 1);
panic("RRX shifter emitter TODO");
return;
be_emit_irprintf(", %s #%d", arm_shf_mod_name(mod), v);
case ARM_SHF_INVALID:
break;
}
panic("Invalid shift_modifier while emitting %+F", node);
}
/** An entry in the sym_or_tv set. */
......@@ -259,11 +330,15 @@ static unsigned get_unique_label(void) {
/**
* Emit a SymConst.
*/
static void emit_arm_SymConst(const ir_node *irn) {
static void emit_arm_SymConst(const ir_node *irn)
{
const arm_SymConst_attr_t *attr = get_arm_SymConst_attr_const(irn);
sym_or_tv_t key, *entry;
unsigned label;
key.u.id = get_arm_symconst_id(irn);
set_entity_backend_marked(attr->entity, 1);
key.u.id = get_entity_ld_ident(attr->entity);
key.is_ident = 1;
key.label = 0;
entry = (sym_or_tv_t *)set_insert(sym_or_tv, &key, sizeof(key), HASH_PTR(key.u.generic));
......@@ -280,6 +355,19 @@ static void emit_arm_SymConst(const ir_node *irn) {
be_emit_finish_line_gas(irn);
}
static void emit_arm_FrameAddr(const ir_node *irn)
{
const arm_SymConst_attr_t *attr = get_irn_generic_attr_const(irn);
be_emit_cstring("\tadd ");
arm_emit_dest_register(irn, 0);
be_emit_cstring(", ");
arm_emit_source_register(irn, 0);
be_emit_cstring(", ");
be_emit_irprintf("#0x%X", attr->fp_offset);
be_emit_finish_line_gas(irn);
}
/**
* Emit a floating point fpa constant.
*/
......@@ -348,16 +436,20 @@ static void arm_emit_cfop_target(const ir_node *irn) {
/**
* Emit a Compare with conditional branch.
*/
static void emit_arm_CmpBra(const ir_node *irn) {
static void emit_arm_B(const ir_node *irn)
{
const ir_edge_t *edge;
const ir_node *proj_true = NULL;
const ir_node *proj_false = NULL;
const ir_node *block;
const ir_node *next_block;
ir_node *op1 = get_irn_n(irn, 0);
ir_mode *opmode = get_irn_mode(op1);
const char *suffix;
int proj_num = get_arm_CondJmp_proj_num(irn);
const arm_cmp_attr_t *cmp_attr = get_irn_generic_attr_const(op1);
bool is_signed = !cmp_attr->is_unsigned;
assert(is_arm_Cmp(op1) || is_arm_Tst(op1));
foreach_out_edge(irn, edge) {
ir_node *proj = get_edge_src_irn(edge);
......@@ -369,102 +461,8 @@ static void emit_arm_CmpBra(const ir_node *irn) {
}
}
/* for now, the code works for scheduled and non-schedules blocks */
block = get_nodes_block(irn);
/* we have a block schedule */
next_block = sched_next_block(block);
if (proj_num == pn_Cmp_False) {
/* always false: should not happen */
be_emit_cstring("\tb ");
arm_emit_cfop_target(proj_false);
be_emit_finish_line_gas(proj_false);
} else if (proj_num == pn_Cmp_True) {
/* always true: should not happen */
be_emit_cstring("\tb ");
arm_emit_cfop_target(proj_true);
be_emit_finish_line_gas(proj_true);
} else {
if (mode_is_float(opmode)) {
suffix = "ICHWILLIMPLEMENTIERTWERDEN";
be_emit_cstring("\tfcmp ");
arm_emit_source_register(irn, 0);
be_emit_cstring(", ");
arm_emit_source_register(irn, 1);
be_emit_finish_line_gas(irn);
be_emit_cstring("\tfmstat");
be_emit_pad_comment();
be_emit_cstring("/* FCSPR -> CPSR */");
be_emit_finish_line_gas(NULL);
} else {
if (get_cfop_target_block(proj_true) == next_block) {
/* exchange both proj's so the second one can be omitted */
const ir_node *t = proj_true;
proj_true = proj_false;
proj_false = t;
proj_num = get_negated_pnc(proj_num, mode_Iu);
}
switch (proj_num) {
case pn_Cmp_Eq: suffix = "eq"; break;
case pn_Cmp_Lt: suffix = "lt"; break;
case pn_Cmp_Le: suffix = "le"; break;
case pn_Cmp_Gt: suffix = "gt"; break;
case pn_Cmp_Ge: suffix = "ge"; break;
case pn_Cmp_Lg: suffix = "ne"; break;
case pn_Cmp_Leg: suffix = "al"; break;
default: assert(!"Cmp unsupported"); suffix = "al";
}
be_emit_cstring("\tcmp ");
arm_emit_source_register(irn, 0);
be_emit_cstring(", ");
arm_emit_source_register(irn, 1);
be_emit_finish_line_gas(irn);
}
/* emit the true proj */
be_emit_irprintf("\tb%s ", suffix);
arm_emit_cfop_target(proj_true);
be_emit_finish_line_gas(proj_true);
if (get_cfop_target_block(proj_false) == next_block) {
be_emit_cstring("\t/* fallthrough to ");
arm_emit_cfop_target(proj_false);
be_emit_cstring(" */");
be_emit_finish_line_gas(proj_false);
} else {
be_emit_cstring("\tb ");
arm_emit_cfop_target(proj_false);
be_emit_finish_line_gas(proj_false);
}
}
}
/**
* Emit a Tst with conditional branch.
*/
static void emit_arm_TstBra(const ir_node *irn)
{
const ir_edge_t *edge;
const ir_node *proj_true = NULL;
const ir_node *proj_false = NULL;
const ir_node *block;
const ir_node *next_block;
const char *suffix;
int proj_num = get_arm_CondJmp_proj_num(irn);
foreach_out_edge(irn, edge) {
ir_node *proj = get_edge_src_irn(edge);
long nr = get_Proj_proj(proj);
if (nr == pn_Cond_true) {
proj_true = proj;
} else {
proj_false = proj;
}
if (cmp_attr->ins_permuted) {
proj_num = get_mirrored_pnc(proj_num);
}
/* for now, the code works for scheduled and non-schedules blocks */
......@@ -484,21 +482,17 @@ static void emit_arm_TstBra(const ir_node *irn)
proj_false = t;
proj_num = get_negated_pnc(proj_num, mode_Iu);
}
switch (proj_num) {
case pn_Cmp_Eq: suffix = "eq"; break;
case pn_Cmp_Lt: suffix = "lt"; break;
case pn_Cmp_Le: suffix = "le"; break;
case pn_Cmp_Gt: suffix = "gt"; break;
case pn_Cmp_Ge: suffix = "ge"; break;
case pn_Cmp_Lt: suffix = is_signed ? "lt" : "lo"; break;
case pn_Cmp_Le: suffix = is_signed ? "le" : "ls"; break;
case pn_Cmp_Gt: suffix = is_signed ? "gt" : "hi"; break;
case pn_Cmp_Ge: suffix = is_signed ? "ge" : "hs"; break;
case pn_Cmp_Lg: suffix = "ne"; break;
case pn_Cmp_Leg: suffix = "al"; break;
default: assert(!"Cmp unsupported"); suffix = "al";
default: panic("Cmp has unsupported pnc");
}
be_emit_cstring("\ttst ");
arm_emit_source_register(irn, 0);
be_emit_cstring(", ");
arm_emit_source_register(irn, 1);
be_emit_finish_line_gas(irn);
/* emit the true proj */
be_emit_irprintf("\tb%s ", suffix);
......@@ -511,26 +505,12 @@ static void emit_arm_TstBra(const ir_node *irn)
be_emit_cstring(" */");
be_emit_finish_line_gas(proj_false);
} else {
be_emit_cstring("b ");
be_emit_cstring("\tb ");
arm_emit_cfop_target(proj_false);
be_emit_finish_line_gas(proj_false);
}
}
/**
* Emit a Compare with conditional branch.
*/
static void emit_arm_fpaCmfBra(const ir_node *irn) {
(void) irn;
}
/**
* Emit a Compare with conditional branch.
*/
static void emit_arm_fpaCmfeBra(const ir_node *irn) {
(void) irn;
}
/** Sort register in ascending order. */
static int reg_cmp(const void *a, const void *b) {
const arch_register_t * const *ra = a;
......@@ -542,8 +522,10 @@ static int reg_cmp(const void *a, const void *b) {
/**
* Create the CopyB instruction sequence.
*/
static void emit_arm_CopyB(const ir_node *irn) {
unsigned size = (unsigned)get_arm_imm_value(irn);
static void emit_arm_CopyB(const ir_node *irn)
{
const arm_CopyB_attr_t *attr = get_irn_generic_attr_const(irn);
unsigned size = attr->size;
const char *tgt = arch_register_get_name(get_in_reg(irn, 0));
const char *src = arch_register_get_name(get_in_reg(irn, 1));
......@@ -840,66 +822,6 @@ static void emit_be_Copy(const ir_node *irn) {
}
}
/**
* Emit code for a Spill.
*/
static void emit_be_Spill(const ir_node *irn) {
ir_mode *mode = get_irn_mode(be_get_Spill_val(irn));
if (mode_is_float(mode)) {
if (USE_FPA(cg->isa)) {
be_emit_cstring("\tstf");
arm_emit_fpa_postfix(mode);
be_emit_char(' ');
} else {
assert(0 && "spill not supported for this mode");
panic("emit_be_Spill: spill not supported for this mode");
}
} else if (mode_is_dataM(mode)) {
be_emit_cstring("\tstr ");
} else {
assert(0 && "spill not supported for this mode");
panic("emit_be_Spill: spill not supported for this mode");
}
arm_emit_source_register(irn, 1);
be_emit_cstring(", [");
arm_emit_source_register(irn, 0);
be_emit_cstring(", #");
arm_emit_offset(irn);
be_emit_char(']');
be_emit_finish_line_gas(irn);
}
/**
* Emit code for a Reload.
*/
static void emit_be_Reload(const ir_node *irn) {
ir_mode *mode = get_irn_mode(irn);
if (mode_is_float(mode)) {
if (USE_FPA(cg->isa)) {
be_emit_cstring("\tldf");
arm_emit_fpa_postfix(mode);
be_emit_char(' ');