Commit 5da0fab6 authored by Michael Beck's avatar Michael Beck
Browse files

Big Changes:

- reorganized most instructions to have _i and normal forms
- added support for shift-operand and condition
- removed unused double fp opcodes, use mode instead (not working yet)
- new constant create algorithm creates shorter sequences
- dumper now writes immediate operands
parent ced2f8e3
This diff is collapsed.
#ifndef _arm_EMITTER_H_
#define _arm_EMITTER_H_
#ifndef _ARM_EMITTER_H_
#define _ARM_EMITTER_H_
#include "irargs_t.h" // this also inlucdes <libcore/lc_print.h>
#include "irnode.h"
......@@ -12,8 +12,8 @@
typedef struct _arm_emit_env_t {
FILE *out;
const arch_env_t *arch_env;
const arm_code_gen_t *cg;
DEBUG_ONLY(firm_dbg_module_t *mod;)
const arm_code_gen_t *cg;
DEBUG_ONLY(firm_dbg_module_t *mod;)
} arm_emit_env_t;
const lc_arg_env_t *arm_get_arg_env(void);
......@@ -25,4 +25,17 @@ const char *get_arm_in_reg_name(ir_node *irn, int pos);
void arm_gen_routine(FILE *F, ir_graph *irg, const arm_code_gen_t *cg);
#endif /* _arm_EMITTER_H_ */
typedef enum sections {
NO_SECTION, /**< no section selected yet. */
SECTION_TEXT, /**< text section */
SECTION_DATA, /**< data section */
SECTION_RODATA, /**< rodata section */
SECTION_COMMON, /**< common section */
} sections;
/**
* Switch to a new section
*/
void arm_switch_section(FILE *f, sections sec);
#endif /* _ARM_EMITTER_H_ */
......@@ -9,24 +9,15 @@
#include <ctype.h>
#include <assert.h>
#include "xmalloc.h"
#include <obstack.h>
#ifdef obstack_chunk_alloc
# undef obstack_chunk_alloc
# define obstack_chunk_alloc xmalloc
#else
# define obstack_chunk_alloc xmalloc
# define obstack_chunk_free free
#endif
extern int obstack_printf(struct obstack *obst, char *fmt, ...);
#include "obst.h"
#include "tv.h"
#include "irnode.h"
#include "entity.h"
#include "irprog.h"
#include "arm_emitter.h"
#include "arm_gen_decls.h"
/************************************************************************/
......@@ -574,21 +565,21 @@ void arm_gen_decls(FILE *out) {
size = obstack_object_size(&data);
cp = obstack_finish(&data);
if (size > 0) {
fprintf(out, "\t.data\n");
arm_switch_section(out, SECTION_DATA);
fwrite(cp, 1, size, out);
}
size = obstack_object_size(&rodata);
cp = obstack_finish(&rodata);
if (size > 0) {
fprintf(out, "\t.section\t.rodata\n");
arm_switch_section(out, SECTION_RODATA);
fwrite(cp, 1, size, out);
}
size = obstack_object_size(&comm);
cp = obstack_finish(&comm);
if (size > 0) {
fprintf(out, "\t.common\n");
arm_switch_section(out, SECTION_COMMON);
fwrite(cp, 1, size, out);
}
......
......@@ -15,10 +15,10 @@
static const arch_register_t *gpreg_param_reg_std[] = {
&arm_general_purpose_regs[REG_R0],
&arm_general_purpose_regs[REG_R1],
&arm_general_purpose_regs[REG_R2],
&arm_general_purpose_regs[REG_R3],
&arm_gp_regs[REG_R0],
&arm_gp_regs[REG_R1],
&arm_gp_regs[REG_R2],
&arm_gp_regs[REG_R3],
};
const arch_register_t *arm_get_RegParam_reg(int n) {
......@@ -71,12 +71,12 @@ long arm_translate_proj_pos(const ir_node *proj) {
ir_node *pred = get_Proj_pred(proj);
long nr = get_Proj_proj(proj);
if (is_arm_Load(pred) || is_arm_fLoadd(pred) || is_arm_fLoads(pred)) {
if (is_arm_Load(pred) || is_arm_fLoad(pred)) {
if (nr == pn_Load_res)
return 0;
assert(0 && "unsupported Proj(Load) number");
}
else if (is_arm_Store(pred) || is_arm_fStores(pred) || is_arm_fStored(pred)) {
else if (is_arm_Store(pred) || is_arm_fStore(pred)) {
return 0;
}
else if (is_arm_fDiv(pred)) {
......
/**
* This file implements the creation of the achitecture specific firm opcodes
* and the coresponding node constructors for the arm assembler irg.
* This file implements the creation of the architecture specific firm opcodes
* and the corresponding node constructors for the arm assembler irg.
* $Id$
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef _WIN32
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#else
#endif
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#endif
......@@ -35,6 +37,13 @@
#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];
}
/***********************************************************************************
* _ _ _ __
......@@ -131,12 +140,13 @@ static void dump_reg_req(FILE *F, ir_node *n, const arm_register_req_t **reqs, i
* @return 0 on success or != 0 on failure
*/
static int dump_node_arm(ir_node *n, FILE *F, dump_reason_t reason) {
ir_mode *mode = NULL;
ir_mode *mode = NULL;
int bad = 0;
int i;
arm_attr_t *attr;
arm_attr_t *attr = get_arm_attr(n);
const arm_register_req_t **reqs;
const arch_register_t **slots;
arm_shift_modifier mod;
switch (reason) {
case dump_node_opcode_txt:
......@@ -155,14 +165,17 @@ static int dump_node_arm(ir_node *n, FILE *F, dump_reason_t reason) {
break;
case dump_node_nodeattr_txt:
/* TODO: dump some attributes which should show up */
/* in node name in dump (e.g. consts or the like) */
mod = ARM_GET_SHF_MOD(attr);
if (ARM_HAS_SHIFT(mod)) {
fprintf(F, "[%s #%ld]", arm_shf_mod_name(mod), get_tarval_long(attr->value));
}
else if (mod == ARM_SHF_IMM) {
/* immediate */
fprintf(F, "[#0x%X]", arm_decode_imm_w_shift(attr->value));
}
break;
case dump_node_info_txt:
attr = get_arm_attr(n);
fprintf(F, "=== arm attr begin ===\n");
/* dump IN requirements */
......@@ -237,8 +250,6 @@ static int dump_node_arm(ir_node *n, FILE *F, dump_reason_t reason) {
/* end of: case dump_node_info_txt */
break;
}
return bad;
}
......@@ -479,20 +490,28 @@ void set_arm_default_proj_num(ir_node *node, long default_proj_num) {
attr->default_proj_num = default_proj_num;
}
/**
* Gets the shift modifier attribute.
*/
arm_shift_modifier get_arm_shift_modifier(ir_node *node) {
arm_attr_t *attr = get_arm_attr(node);
return ARM_GET_SHF_MOD(attr);
}
/* Set the ARM machine node attributes to default values. */
void init_arm_attributes(ir_node *node, int flags, const arm_register_req_t ** in_reqs,
const arm_register_req_t ** out_reqs, int n_res) {
arm_attr_t *attr = get_arm_attr(node);
attr->in_req = in_reqs;
attr->out_req = out_reqs;
attr->n_res = n_res;
attr->flags = flags;
attr->slots = xcalloc(n_res, sizeof(attr->slots[0]));
attr->value = NULL;
attr->proj_num = -42;
attr->symconst_label = NULL;
attr->n_projs = 0;
attr->in_req = in_reqs;
attr->out_req = out_reqs;
attr->n_res = n_res;
attr->flags = flags;
attr->slots = xcalloc(n_res, sizeof(attr->slots[0]));
attr->instr_fl = (ARM_COND_AL << 3) | ARM_SHF_NONE;
attr->value = NULL;
attr->proj_num = -42;
attr->symconst_label = NULL;
attr->n_projs = 0;
attr->default_proj_num = 0;
}
......@@ -501,11 +520,11 @@ static int arm_comp_condJmp(arm_attr_t *attr_a, arm_attr_t *attr_b) {
}
ir_node *arm_new_NoReg_gp(arm_code_gen_t *cg) {
return be_abi_get_callee_save_irn(cg->birg->abi, &arm_general_purpose_regs[REG_RXX]);
return be_abi_get_callee_save_irn(cg->birg->abi, &arm_gp_regs[REG_RXX]);
}
ir_node *arm_new_NoReg_fp(arm_code_gen_t *cg) {
return be_abi_get_callee_save_irn(cg->birg->abi, &arm_floating_point_regs[REG_FXX]);
return be_abi_get_callee_save_irn(cg->birg->abi, &arm_fp_regs[REG_FXX]);
}
......@@ -529,13 +548,12 @@ static void limit_reg_arm_StoreStackM4Inc_sp(void *_unused, bitset_t *bs) {
bitset_clear(bs, 14); /* disallow ignore reg r13 */
bitset_clear(bs, 15); /* disallow ignore reg r15 */
bitset_clear(bs, 16); /* disallow ignore reg rxx */
bitset_clear(bs, 17); /* disallow ignore reg MURX */
}
static const arm_register_req_t _arm_req_sp = {
{
arch_register_req_type_limited,
&arm_reg_classes[CLASS_arm_general_purpose],
&arm_reg_classes[CLASS_arm_gp],
limit_reg_arm_StoreStackM4Inc_sp,
NULL, /* limit environment */
NULL, /* same node */
......@@ -555,20 +573,20 @@ ir_node *new_r_arm_StoreStackMInc(ir_graph *irg, ir_node *block, ir_node *mem, i
{
&arm_default_req_none,
&_arm_req_sp,
&arm_default_req_arm_general_purpose,
&arm_default_req_arm_general_purpose,
&arm_default_req_arm_general_purpose,
&arm_default_req_arm_general_purpose,
&arm_default_req_arm_general_purpose,
&arm_default_req_arm_general_purpose,
&arm_default_req_arm_general_purpose,
&arm_default_req_arm_general_purpose,
&arm_default_req_arm_general_purpose,
&arm_default_req_arm_general_purpose,
&arm_default_req_arm_general_purpose,
&arm_default_req_arm_general_purpose,
&arm_default_req_arm_general_purpose,
&arm_default_req_arm_general_purpose,
&arm_default_req_arm_gp,
&arm_default_req_arm_gp,
&arm_default_req_arm_gp,
&arm_default_req_arm_gp,
&arm_default_req_arm_gp,
&arm_default_req_arm_gp,
&arm_default_req_arm_gp,
&arm_default_req_arm_gp,
&arm_default_req_arm_gp,
&arm_default_req_arm_gp,
&arm_default_req_arm_gp,
&arm_default_req_arm_gp,
&arm_default_req_arm_gp,
&arm_default_req_arm_gp,
};
assert(n_regs <= 15);
......@@ -588,10 +606,52 @@ ir_node *new_r_arm_StoreStackMInc(ir_graph *irg, ir_node *block, ir_node *mem, i
return res;
}
/**
* Register additional opcodes here.
*/
static void arm_register_additional_opcodes(int cur_opcode) {
/************************************************
* ___ _ _ _ *
* / _ \ _ __ | |_(_)_ __ ___ (_)_______ _ __ *
* | | | | '_ \| __| | '_ ` _ \| |_ / _ \ '__| *
* | |_| | |_) | |_| | | | | | | |/ / __/ | *
* \___/| .__/ \__|_|_| |_| |_|_/___\___|_| *
* |_| *
************************************************/
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);
*/
}
......
#ifndef _arm_NEW_NODES_H_
#define _arm_NEW_NODES_H_
#ifndef _ARM_NEW_NODES_H_
#define _ARM_NEW_NODES_H_
/**
* Function prototypes for the assembler ir node constructors.
......@@ -100,8 +100,11 @@ void set_arm_n_res(ir_node *node, int n_res);
*/
int get_arm_n_res(const ir_node *node);
/**
* Set the ARM machine node attributes to default values.
*/
void init_arm_attributes(ir_node *node, int flags, const arm_register_req_t ** in_reqs,
const arm_register_req_t ** out_reqs, int n_res);
const arm_register_req_t ** out_reqs, int n_res);
ir_node *arm_new_NoReg_gp(arm_code_gen_t *cg);
ir_node *arm_new_NoReg_fp(arm_code_gen_t *cg);
......@@ -152,8 +155,17 @@ long get_arm_default_proj_num(ir_node *node);
*/
void set_arm_default_proj_num(ir_node *node, long default_proj_num);
/**
* Gets the shift modifier attribute.
*/
arm_shift_modifier get_arm_shift_modifier(ir_node *node);
/**
* Decode an immediate with shifter operand
*/
unsigned int arm_decode_imm_w_shift(tarval *tv);
/* Include the generated headers */
#include "gen_arm_new_nodes.h"
#endif /* _arm_NEW_NODES_H_ */
#endif /* _ARM_NEW_NODES_H_ */
......@@ -4,28 +4,84 @@
#include "../bearch.h"
#include "../../common/firm_types.h"
/** A register requirement. */
typedef struct _arm_register_req_t {
const arch_register_req_t req;
int same_pos; /**<< in case of "should be same" we need to remember the pos to get the irn */
int different_pos; /**<< in case of "should be different" we need to remember the pos to get the irn */
int same_pos; /**< in case of "should be same" we need to remember the pos to get the irn */
int different_pos; /**< in case of "should be different" we need to remember the pos to get the irn */
} arm_register_req_t;
/**
* Possible ARM register shift 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 with sign extend */
} 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)))
/**
* 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/Negativ, N set */
ARM_COND_PL = 5, /**< Plus/Positiv 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 >> 3) & 15)
/** Set the condition code to flags */
#define ARM_SET_COND(attr, code) ((attr)->instr_fl = (((attr)->instr_fl & ~(15 << 3)) | ((code) << 3)))
typedef struct _arm_attr_t {
arch_irn_flags_t flags; /**<< indicating if spillable, rematerializeable ... etc. */
int n_res; /**<< number of results for this node */
arch_irn_flags_t flags; /**< indicating if spillable, rematerializeable ... etc. */
int n_res; /**< number of results for this node */
const arm_register_req_t **in_req; /**<< register requirements for arguments */
const arm_register_req_t **out_req; /**<< register requirements for results */
const arm_register_req_t **in_req; /**< register requirements for arguments */
const arm_register_req_t **out_req; /**< register requirements for results */
const arch_register_t **slots; /**<< register slots for assigned registers */
const arch_register_t **slots; /**< register slots for assigned registers */
tarval *value;
unsigned instr_fl; /**< condition code, shift modifier */
tarval *value; /**< immediate */
const char *symconst_label;
int proj_num;
int n_projs;
long default_proj_num;
} arm_attr_t;
/**
* Returns the shift modifier string.
*/
const char *arm_shf_mod_name(arm_shift_modifier mod);
#endif /* _ARM_NODES_ATTR_H_ */
This diff is collapsed.
This diff is collapsed.
......@@ -3,6 +3,8 @@
void arm_move_consts(ir_node *node, void *env);
void arm_move_symconsts(ir_node *node, void *env);
void arm_register_transformers(void);
void arm_transform_node(ir_node *node, void *env);
#endif /* _ARM_TRANSFORM_H_ */
......@@ -122,10 +122,10 @@ static const arch_register_req_t *arm_get_irn_reg_req(const void *self, arch_reg
DB((mod, LEVEL_1, "returning standard reqs for %+F\n", irn));
if (mode_is_float(mode)) {
memcpy(req, &(arm_default_req_arm_floating_point.req), sizeof(*req));
memcpy(req, &(arm_default_req_arm_fp.req), sizeof(*req));
}
else if (mode_is_int(mode) || mode_is_reference(mode)) {
memcpy(req, &(arm_default_req_arm_general_purpose.req), sizeof(*req));
memcpy(req, &(arm_default_req_arm_gp.req), sizeof(*req));
}
else if (mode == mode_T || mode == mode_M) {
DBG((mod, LEVEL_1, "ignoring Phi node %+F\n", irn));
......@@ -265,12 +265,13 @@ arm_irn_ops_t arm_irn_ops = {
**************************************************/
/**
* Transforms the standard firm graph into
* a ARM firm graph
* Transforms the standard Firm graph into
* a ARM firm graph.
*/
static void arm_prepare_graph(void *self) {
arm_code_gen_t *cg = self;
arm_register_transformers();
irg_walk_blkwise_graph(cg->irg, arm_move_consts, arm_transform_node, cg);
}
......@@ -470,7 +471,7 @@ static void *arm_cg_init(FILE *F, const be_irg_t *birg) {
arm_isa_t *isa = (arm_isa_t *)birg->main_env->arch_env->isa;
arm_code_gen_t *cg;
if (! int_tp) {
if (! int_tp) {
/* create an integer type with machine size */
int_tp = new_type_primitive(new_id_from_chars("int", 3), mode_Is);
}
......@@ -483,6 +484,7 @@ static void *arm_cg_init(FILE *F, const be_irg_t *birg) {
cg->arch_env = birg->main_env->arch_env;
cg->birg = birg;
cg->int_tp = int_tp;
cg->have_fp = 0;
FIRM_DBG_REGISTER(cg->mod, "firm.be.arm.cg");
isa->num_codegens++;
......@@ -496,6 +498,9 @@ static void *arm_cg_init(FILE *F, const be_irg_t *birg) {
arm_irn_ops.cg = cg;
/* enter the current code generator */
isa->cg = cg;
return (arch_code_generator_t *)cg;
}
......@@ -505,7 +510,7 @@ static void *arm_cg_init(FILE *F, const be_irg_t *birg) {
* and map all instructions the backend did not support
* to runtime calls.
*/
void arm_global_init(void) {
static void arm_global_init(void) {
ir_type *tp, *int_tp, *uint_tp;
i_record records[8];
int n_records = 0;
......@@ -515,6 +520,7 @@ void arm_global_init(void) {
int_tp = new_type_primitive(ID("int"), mode_Is);
uint_tp = new_type_primitive(ID("uint"), mode_Iu);
/* ARM has neither a signed div instruction ... */
{
runtime_rt rt_Div;
i_instr_record *map_Div = &records[n_records++].i_instr;
......@@ -538,6 +544,7 @@ void arm_global_init(void) {
map_Div->i_mapper = (i_mapper_func)i_mapper_RuntimeCall;
map_Div->ctx = &rt_Div;
}
/* ... nor a signed div instruction ... */
{
runtime_rt rt_Div;
i_instr_record *map_Div = &records[n_records++].i_instr;
......@@ -561,6 +568,7 @@ void arm_global_init(void) {
map_Div->i_mapper = (i_mapper_func)i_mapper_RuntimeCall;
map_Div->ctx = &rt_Div;
}
/* ... nor a signed mod instruction ... */
{
runtime_rt rt_Mod;
i_instr_record *map_Mod = &records[n_records++].i_instr;
......@@ -584,6 +592,7 @@ void arm_global_init(void) {
map_Mod->i_mapper = (i_mapper_func)i_mapper_RuntimeCall;
map_Mod->ctx = &rt_Mod;
}
/* ... nor a unsigned mod. */
{
runtime_rt rt_Mod;
i_instr_record *map_Mod = &records[n_records++].i_instr;
......@@ -623,11 +632,13 @@ void arm_global_init(void) {
*****************************************************************/
static arm_isa_t arm_isa_template = {
&arm_isa_if, /* isa interface */
&arm_general_purpose_regs[REG_R13], /* stack pointer */
&arm_general_purpose_regs[REG_R11], /* base pointer */
-1, /* stack direction */
0 /* number of codegenerator objects */
&arm_isa_if, /* isa interface */
&arm_gp_regs[REG_SP], /* stack pointer */
&arm_gp_regs[REG_R11], /* base pointer */
-1, /* stack direction */
0, /* number of codegenerator objects */
0, /* use generic register names instead of SP, LR, PC */
NULL /* current code generator */
};
/**
......@@ -640,39 +651,57 @@ static void *arm_init(void) {
if(inited)
return NULL;
isa = xcalloc(1, sizeof(*isa));