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_ #ifndef _ARM_EMITTER_H_
#define _arm_EMITTER_H_ #define _ARM_EMITTER_H_
#include "irargs_t.h" // this also inlucdes <libcore/lc_print.h> #include "irargs_t.h" // this also inlucdes <libcore/lc_print.h>
#include "irnode.h" #include "irnode.h"
...@@ -12,8 +12,8 @@ ...@@ -12,8 +12,8 @@
typedef struct _arm_emit_env_t { typedef struct _arm_emit_env_t {
FILE *out; FILE *out;
const arch_env_t *arch_env; const arch_env_t *arch_env;
const arm_code_gen_t *cg; const arm_code_gen_t *cg;
DEBUG_ONLY(firm_dbg_module_t *mod;) DEBUG_ONLY(firm_dbg_module_t *mod;)
} arm_emit_env_t; } arm_emit_env_t;
const lc_arg_env_t *arm_get_arg_env(void); 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); ...@@ -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); 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 @@ ...@@ -9,24 +9,15 @@
#include <ctype.h> #include <ctype.h>
#include <assert.h> #include <assert.h>
#include "xmalloc.h" #include "obst.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 "tv.h" #include "tv.h"
#include "irnode.h" #include "irnode.h"
#include "entity.h" #include "entity.h"
#include "irprog.h" #include "irprog.h"
#include "arm_emitter.h"
#include "arm_gen_decls.h" #include "arm_gen_decls.h"
/************************************************************************/ /************************************************************************/
...@@ -574,21 +565,21 @@ void arm_gen_decls(FILE *out) { ...@@ -574,21 +565,21 @@ void arm_gen_decls(FILE *out) {
size = obstack_object_size(&data); size = obstack_object_size(&data);
cp = obstack_finish(&data); cp = obstack_finish(&data);
if (size > 0) { if (size > 0) {
fprintf(out, "\t.data\n"); arm_switch_section(out, SECTION_DATA);
fwrite(cp, 1, size, out); fwrite(cp, 1, size, out);
} }
size = obstack_object_size(&rodata); size = obstack_object_size(&rodata);
cp = obstack_finish(&rodata); cp = obstack_finish(&rodata);
if (size > 0) { if (size > 0) {
fprintf(out, "\t.section\t.rodata\n"); arm_switch_section(out, SECTION_RODATA);
fwrite(cp, 1, size, out); fwrite(cp, 1, size, out);
} }
size = obstack_object_size(&comm); size = obstack_object_size(&comm);
cp = obstack_finish(&comm); cp = obstack_finish(&comm);
if (size > 0) { if (size > 0) {
fprintf(out, "\t.common\n"); arm_switch_section(out, SECTION_COMMON);
fwrite(cp, 1, size, out); fwrite(cp, 1, size, out);
} }
......
...@@ -15,10 +15,10 @@ ...@@ -15,10 +15,10 @@
static const arch_register_t *gpreg_param_reg_std[] = { static const arch_register_t *gpreg_param_reg_std[] = {
&arm_general_purpose_regs[REG_R0], &arm_gp_regs[REG_R0],
&arm_general_purpose_regs[REG_R1], &arm_gp_regs[REG_R1],
&arm_general_purpose_regs[REG_R2], &arm_gp_regs[REG_R2],
&arm_general_purpose_regs[REG_R3], &arm_gp_regs[REG_R3],
}; };
const arch_register_t *arm_get_RegParam_reg(int n) { const arch_register_t *arm_get_RegParam_reg(int n) {
...@@ -71,12 +71,12 @@ long arm_translate_proj_pos(const ir_node *proj) { ...@@ -71,12 +71,12 @@ long arm_translate_proj_pos(const ir_node *proj) {
ir_node *pred = get_Proj_pred(proj); ir_node *pred = get_Proj_pred(proj);
long nr = get_Proj_proj(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) if (nr == pn_Load_res)
return 0; return 0;
assert(0 && "unsupported Proj(Load) number"); 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; return 0;
} }
else if (is_arm_fDiv(pred)) { else if (is_arm_fDiv(pred)) {
......
/** /**
* This file implements the creation of the achitecture specific firm opcodes * This file implements the creation of the architecture specific firm opcodes
* and the coresponding node constructors for the arm assembler irg. * and the corresponding node constructors for the arm assembler irg.
* $Id$ * $Id$
*/ */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#ifdef _WIN32 #ifdef HAVE_MALLOC_H
#include <malloc.h> #include <malloc.h>
#else #endif
#ifdef HAVE_ALLOCA_H
#include <alloca.h> #include <alloca.h>
#endif #endif
...@@ -35,6 +37,13 @@ ...@@ -35,6 +37,13 @@
#include "../beabi.h" #include "../beabi.h"
#include "bearch_arm_t.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 ...@@ -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 * @return 0 on success or != 0 on failure
*/ */
static int dump_node_arm(ir_node *n, FILE *F, dump_reason_t reason) { 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 bad = 0;
int i; int i;
arm_attr_t *attr; arm_attr_t *attr = get_arm_attr(n);
const arm_register_req_t **reqs; const arm_register_req_t **reqs;
const arch_register_t **slots; const arch_register_t **slots;
arm_shift_modifier mod;
switch (reason) { switch (reason) {
case dump_node_opcode_txt: case dump_node_opcode_txt:
...@@ -155,14 +165,17 @@ static int dump_node_arm(ir_node *n, FILE *F, dump_reason_t reason) { ...@@ -155,14 +165,17 @@ static int dump_node_arm(ir_node *n, FILE *F, dump_reason_t reason) {
break; break;
case dump_node_nodeattr_txt: case dump_node_nodeattr_txt:
mod = ARM_GET_SHF_MOD(attr);
/* TODO: dump some attributes which should show up */ if (ARM_HAS_SHIFT(mod)) {
/* in node name in dump (e.g. consts or the like) */ 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; break;
case dump_node_info_txt: case dump_node_info_txt:
attr = get_arm_attr(n);
fprintf(F, "=== arm attr begin ===\n"); fprintf(F, "=== arm attr begin ===\n");
/* dump IN requirements */ /* dump IN requirements */
...@@ -237,8 +250,6 @@ static int dump_node_arm(ir_node *n, FILE *F, dump_reason_t reason) { ...@@ -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 */ /* end of: case dump_node_info_txt */
break; break;
} }
return bad; return bad;
} }
...@@ -479,20 +490,28 @@ void set_arm_default_proj_num(ir_node *node, long default_proj_num) { ...@@ -479,20 +490,28 @@ void set_arm_default_proj_num(ir_node *node, long default_proj_num) {
attr->default_proj_num = 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, 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) {
arm_attr_t *attr = get_arm_attr(node); arm_attr_t *attr = get_arm_attr(node);
attr->in_req = in_reqs; attr->in_req = in_reqs;
attr->out_req = out_reqs; attr->out_req = out_reqs;
attr->n_res = n_res; attr->n_res = n_res;
attr->flags = flags; attr->flags = flags;
attr->slots = xcalloc(n_res, sizeof(attr->slots[0])); attr->slots = xcalloc(n_res, sizeof(attr->slots[0]));
attr->value = NULL; attr->instr_fl = (ARM_COND_AL << 3) | ARM_SHF_NONE;
attr->proj_num = -42; attr->value = NULL;
attr->symconst_label = NULL; attr->proj_num = -42;
attr->n_projs = 0; attr->symconst_label = NULL;
attr->n_projs = 0;
attr->default_proj_num = 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) { ...@@ -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) { 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) { 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) { ...@@ -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, 14); /* disallow ignore reg r13 */
bitset_clear(bs, 15); /* disallow ignore reg r15 */ bitset_clear(bs, 15); /* disallow ignore reg r15 */
bitset_clear(bs, 16); /* disallow ignore reg rxx */ 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 = { static const arm_register_req_t _arm_req_sp = {
{ {
arch_register_req_type_limited, arch_register_req_type_limited,
&arm_reg_classes[CLASS_arm_general_purpose], &arm_reg_classes[CLASS_arm_gp],
limit_reg_arm_StoreStackM4Inc_sp, limit_reg_arm_StoreStackM4Inc_sp,
NULL, /* limit environment */ NULL, /* limit environment */
NULL, /* same node */ NULL, /* same node */
...@@ -555,20 +573,20 @@ ir_node *new_r_arm_StoreStackMInc(ir_graph *irg, ir_node *block, ir_node *mem, i ...@@ -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_default_req_none,
&_arm_req_sp, &_arm_req_sp,
&arm_default_req_arm_general_purpose, &arm_default_req_arm_gp,
&arm_default_req_arm_general_purpose, &arm_default_req_arm_gp,
&arm_default_req_arm_general_purpose, &arm_default_req_arm_gp,
&arm_default_req_arm_general_purpose, &arm_default_req_arm_gp,
&arm_default_req_arm_general_purpose, &arm_default_req_arm_gp,
&arm_default_req_arm_general_purpose, &arm_default_req_arm_gp,
&arm_default_req_arm_general_purpose, &arm_default_req_arm_gp,
&arm_default_req_arm_general_purpose, &arm_default_req_arm_gp,
&arm_default_req_arm_general_purpose, &arm_default_req_arm_gp,
&arm_default_req_arm_general_purpose, &arm_default_req_arm_gp,
&arm_default_req_arm_general_purpose, &arm_default_req_arm_gp,
&arm_default_req_arm_general_purpose, &arm_default_req_arm_gp,
&arm_default_req_arm_general_purpose, &arm_default_req_arm_gp,
&arm_default_req_arm_general_purpose, &arm_default_req_arm_gp,
}; };
assert(n_regs <= 15); assert(n_regs <= 15);
...@@ -588,10 +606,52 @@ ir_node *new_r_arm_StoreStackMInc(ir_graph *irg, ir_node *block, ir_node *mem, i ...@@ -588,10 +606,52 @@ ir_node *new_r_arm_StoreStackMInc(ir_graph *irg, ir_node *block, ir_node *mem, i
return res; 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_ #ifndef _ARM_NEW_NODES_H_
#define _arm_NEW_NODES_H_ #define _ARM_NEW_NODES_H_
/** /**
* Function prototypes for the assembler ir node constructors. * Function prototypes for the assembler ir node constructors.
...@@ -100,8 +100,11 @@ void set_arm_n_res(ir_node *node, int n_res); ...@@ -100,8 +100,11 @@ void set_arm_n_res(ir_node *node, int n_res);
*/ */
int get_arm_n_res(const ir_node *node); 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, 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_gp(arm_code_gen_t *cg);
ir_node *arm_new_NoReg_fp(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); ...@@ -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); 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 the generated headers */
#include "gen_arm_new_nodes.h" #include "gen_arm_new_nodes.h"
#endif /* _arm_NEW_NODES_H_ */ #endif /* _ARM_NEW_NODES_H_ */
...@@ -4,28 +4,84 @@ ...@@ -4,28 +4,84 @@
#include "../bearch.h" #include "../bearch.h"
#include "../../common/firm_types.h" #include "../../common/firm_types.h"
/** A register requirement. */
typedef struct _arm_register_req_t { typedef struct _arm_register_req_t {
const arch_register_req_t req; 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 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 different_pos; /**< in case of "should be different" we need to remember the pos to get the irn */
} arm_register_req_t; } 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 { typedef struct _arm_attr_t {
arch_irn_flags_t flags; /**<< indicating if spillable, rematerializeable ... etc. */ arch_irn_flags_t flags; /**< indicating if spillable, rematerializeable ... etc. */
int n_res; /**<< number of results for this node */ 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 **in_req; /**< register requirements for arguments */
const arm_register_req_t **out_req; /**<< register requirements for results */ 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; const char *symconst_label;
int proj_num; int proj_num;
int n_projs; int n_projs;
long default_proj_num; long default_proj_num;
} arm_attr_t; } arm_attr_t;
/**
* Returns the shift modifier string.
*/
const char *arm_shf_mod_name(arm_shift_modifier mod);
#endif /* _ARM_NODES_ATTR_H_ */