Commit dfc341ac authored by Michael Beck's avatar Michael Beck
Browse files

Several BugFixes and updates:

- arm_SymConst: label attribute is now an ident
- indirect accessed SymConsts are now hold in a map, eliminating double values
- fixed missed ignore marker for the mov lr,pc instruction
- add dependency edges from the arm constants to the barrier, so constants are not scheduled before the barrier

[r13738]
parent ebf1d3db
......@@ -36,6 +36,7 @@
#include "iredges.h"
#include "debug.h"
#include "irgwalk.h"
#include "irtools.h"
#include "irprintf.h"
#include "irop_t.h"
#include "irprog_t.h"
......@@ -207,7 +208,7 @@ void arm_emit_immediate(arm_emit_env_t *env, const ir_node *node) {
if (is_immediate_node(node)) {
be_emit_irprintf(env->emit, "#0x%X", arm_decode_imm_w_shift(get_arm_value(node)));
} else if (is_arm_SymConst(node))
be_emit_string(env->emit, get_arm_symconst_label(node));
be_emit_ident(env->emit, get_arm_symconst_id(node));
else {
assert(!"not a Constant");
}
......@@ -239,18 +240,22 @@ static unsigned get_unique_label(void) {
* Emit a SymConst.
*/
static void emit_arm_SymConst(arm_emit_env_t *env, const ir_node *irn) {
SymConstEntry *entry = obstack_alloc(&env->obst, sizeof(*entry));
/* allocate a new symbol entry */
entry->label = get_unique_label();
entry->symconst = irn;
entry->next = env->symbols;
env->symbols = entry;
ident *id = get_arm_symconst_id(irn);
pmap_entry *entry = pmap_find(env->symbols, id);
unsigned label;
if (entry == NULL) {
/* allocate a label */
label = get_unique_label();
pmap_insert(env->symbols, id, INT_TO_PTR(label));
} else {
label = PTR_TO_INT(entry->value);
}
/* load the symbol indirect */
be_emit_cstring(env->emit, "\tldr ");
arm_emit_dest_register(env, irn, 0);
be_emit_irprintf(env->emit, ", .L%u", entry->label);
be_emit_irprintf(env->emit, ", .L%u", label);
be_emit_finish_line_gas(env->emit, irn);
}
......@@ -333,7 +338,7 @@ static void emit_arm_CondJmp(arm_emit_env_t *env, const ir_node *irn) {
}
if (true_block == sched_next_block(block)) {
be_emit_irprintf(env->emit, "\tb%s", suffix);
be_emit_irprintf(env->emit, "\tb%s ", suffix);
arm_emit_block_label(env, true_block);
be_emit_pad_comment(env->emit);
be_emit_cstring(env->emit, "/* false case */");
......@@ -345,7 +350,7 @@ static void emit_arm_CondJmp(arm_emit_env_t *env, const ir_node *irn) {
be_emit_cstring(env->emit, " */");
be_emit_finish_line_gas(env->emit, NULL);
} else {
be_emit_irprintf(env->emit, "\tb%s", suffix);
be_emit_irprintf(env->emit, "\tb%s ", suffix);
arm_emit_block_label(env, true_block);
be_emit_pad_comment(env->emit);
be_emit_cstring(env->emit, "/* true case */");
......@@ -693,6 +698,7 @@ static void emit_be_Perm(arm_emit_env_t *env, const ir_node *irn) {
arm_emit_source_register(env, irn, 1);
be_emit_finish_line_gas(env->emit, NULL);
be_emit_cstring(env->emit, "\teor ");
arm_emit_source_register(env, irn, 0);
be_emit_cstring(env->emit, ", ");
arm_emit_source_register(env, irn, 0);
......@@ -729,10 +735,19 @@ static void emit_be_StackParam(arm_emit_env_t *env, const ir_node *irn) {
static void emit_Jmp(arm_emit_env_t *env, const ir_node *irn) {
const ir_edge_t *edge = get_irn_out_edge_first(irn);
ir_node *target_block = get_edge_src_irn(edge);
ir_node *block = get_nodes_block(irn);
be_emit_cstring(env->emit, "\tb ");
arm_emit_block_label(env, target_block);
be_emit_finish_line_gas(env->emit, irn);
if (target_block == sched_next_block(block)) {
be_emit_pad_comment(env->emit);
be_emit_cstring(env->emit, "/* fallthrough ");
arm_emit_block_label(env, target_block);
be_emit_cstring(env->emit, " */");
be_emit_finish_line_gas(env->emit, NULL);
} else {
be_emit_cstring(env->emit, "\tb ");
arm_emit_block_label(env, target_block);
be_emit_finish_line_gas(env->emit, irn);
}
}
static void emit_arm_fpaDbl2GP(arm_emit_env_t *env, const ir_node *irn) {
......@@ -820,10 +835,14 @@ static void arm_register_emitters(void) {
/* noisy stuff */
#ifdef SILENCER
SILENCE(Start);
SILENCE(Proj);
SILENCE(Phi);
SILENCE(be_Keep);
SILENCE(be_CopyKeep);
SILENCE(be_RegParams);
SILENCE(be_Barrier);
SILENCE(be_Return);
#endif
#undef ARM_EMIT
......@@ -909,16 +928,15 @@ void arm_gen_labels(ir_node *block, void *env) {
*/
void arm_gen_routine(const arm_code_gen_t *cg, ir_graph *irg)
{
SymConstEntry *entry;
arm_emit_env_t emit_env;
ir_node **blk_sched;
int i, n;
pmap_entry *entry;
emit_env.emit = &cg->isa->emit;
emit_env.arch_env = cg->arch_env;
emit_env.cg = cg;
emit_env.symbols = NULL;
obstack_init(&emit_env.obst);
emit_env.symbols = pmap_create();
FIRM_DBG_REGISTER(emit_env.mod, "firm.be.arm.emit");
/* set the global arch_env (needed by print hooks) */
......@@ -946,16 +964,20 @@ void arm_gen_routine(const arm_code_gen_t *cg, ir_graph *irg)
}
/* emit SymConst values */
if (emit_env.symbols)
if (pmap_count(emit_env.symbols) > 0) {
be_emit_cstring(emit_env.emit, "\t.align 2\n");
for (entry = emit_env.symbols; entry; entry = entry->next) {
be_emit_irprintf(emit_env.emit, ".L%u:\n", entry->label);
be_emit_cstring(emit_env.emit, "\t.word\t");
arm_emit_immediate(&emit_env, entry->symconst);
pmap_foreach(emit_env.symbols, entry) {
ident *id = entry->key;
be_emit_irprintf(emit_env.emit, ".L%u:\n", PTR_TO_INT(entry->value));
be_emit_cstring(emit_env.emit, "\t.word\t");
be_emit_ident(emit_env.emit, id);
be_emit_char(emit_env.emit, '\n');
be_emit_write_line(emit_env.emit);
}
be_emit_char(emit_env.emit, '\n');
be_emit_write_line(emit_env.emit);
}
obstack_free(&emit_env.obst, NULL);
pmap_destroy(emit_env.symbols);
}
......@@ -27,6 +27,7 @@
#define FIRM_BE_ARM_ARM_EMITTER_H
#include "firm_types.h"
#include "pmap.h"
#include "irargs_t.h"
#include "debug.h"
......@@ -34,16 +35,6 @@
#include "bearch_arm_t.h"
/**
* A SymConst entry. Used to create a table of used symconsts in a graph
* that must be loaded indirect.
*/
typedef struct _SymConstEntry {
unsigned label; /**< a label number for this label */
const ir_node *symconst; /**< the node holding this label */
struct _SymConstEntry *next; /**< links all entries */
} SymConstEntry;
/**
* The ARM emitter environment.
*/
......@@ -51,8 +42,7 @@ typedef struct _arm_emit_env_t {
be_emit_env_t *emit; /**< environment for the generic GAS emitter. */
const arch_env_t *arch_env; /**< the architecture environment */
const arm_code_gen_t *cg; /**< the code generator object */
struct obstack obst; /**< an temporary store for SymConstEntries */
SymConstEntry *symbols; /**< list containing all SymConstEntries */
pmap *symbols; /**< map containing all indirect symbols */
DEBUG_ONLY(firm_dbg_module_t *mod;)
} arm_emit_env_t;
......
......@@ -429,17 +429,17 @@ void set_arm_proj_num(ir_node *node, int proj_num) {
/**
* Returns the SymConst label
*/
const char *get_arm_symconst_label(const ir_node *node) {
ident *get_arm_symconst_id(const ir_node *node) {
arm_attr_t *attr = get_arm_attr(node);
return attr->symconst_label;
return attr->symconst_id;
}
/**
* Sets the SymConst label
*/
void set_arm_symconst_label(ir_node *node, const char *symconst_label) {
void set_arm_symconst_id(ir_node *node, ident *symconst_id) {
arm_attr_t *attr = get_arm_attr(node);
attr->symconst_label = symconst_label;
attr->symconst_id = symconst_id;
}
......@@ -495,7 +495,7 @@ void init_arm_attributes(ir_node *node, int flags, const arch_register_req_t **
attr->instr_fl = (ARM_COND_AL << 3) | ARM_SHF_NONE;
attr->value = NULL;
attr->proj_num = -42;
attr->symconst_label = NULL;
attr->symconst_id = NULL;
attr->n_projs = 0;
attr->default_proj_num = 0;
......
......@@ -146,8 +146,8 @@ int get_arm_proj_num(const ir_node *node);
*/
void set_arm_proj_num(ir_node *node, int proj_num);
const char *get_arm_symconst_label(const ir_node *node);
void set_arm_symconst_label(ir_node *node, const char *symconst_label);
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);
......
......@@ -90,7 +90,7 @@ typedef struct _arm_attr_t {
ir_mode *op_mode; /**< operation mode */
unsigned instr_fl; /**< condition code, shift modifier */
tarval *value; /**< immediate */
const char *symconst_label;
ident *symconst_id; /**< for SymConsts: its ident */
int proj_num;
int n_projs;
long default_proj_num;
......
......@@ -437,7 +437,7 @@ $new_emit_syntax = 1;
"comment" => "construct Abs: Abs(a) = |a|",
"reg_req" => { "in" => [ "gp" ], "out" => [ "gp" ] },
"emit" =>
'. movs %S0, %S0, #0 /* set condition flag */\n
'. movs %S0, %S0, #0
. rsbmi %D0, %S0, #0'
},
......@@ -468,12 +468,12 @@ $new_emit_syntax = 1;
"op_flags" => "c",
"irn_flags" => "R",
"comment" => "represents a symbolic constant",
"attr" => "const char *label",
"init_attr" => ' attr->symconst_label = label;',
"attr" => "ident *id",
"init_attr" => ' attr->symconst_id = id;',
"reg_req" => { "out" => [ "gp" ] },
"cmp_attr" =>
' /* should be identical but ...*/
return strcmp(attr_a->symconst_label, attr_b->symconst_label);'
return attr_a->symconst_id == attr_b->symconst_id;'
},
"CondJmp" => {
......
......@@ -40,6 +40,7 @@
#include "debug.h"
#include "../benode_t.h"
#include "../beirg_t.h"
#include "bearch_arm_t.h"
#include "arm_nodes_attr.h"
......@@ -122,19 +123,25 @@ static void gen_vals_from_word(unsigned int value, vals *result)
/**
* Creates a arm_Const node.
*/
static ir_node *create_const_node(ir_node *irn, ir_node *block, long value) {
static ir_node *create_const_node(be_abi_irg_t *abi, ir_node *irn, ir_node *block, long value) {
tarval *tv = new_tarval_from_long(value, mode_Iu);
dbg_info *dbg = get_irn_dbg_info(irn);
return new_rd_arm_Mov_i(dbg, current_ir_graph, block, get_irn_mode(irn), tv);
ir_node *res = new_rd_arm_Mov_i(dbg, current_ir_graph, block, get_irn_mode(irn), tv);
/* ensure the const is schedules AFTER the barrier */
add_irn_dep(res, be_abi_get_start_barrier(abi));
return res;
}
/**
* Creates a arm_Const_Neg node.
*/
static ir_node *create_const_neg_node(ir_node *irn, ir_node *block, long value) {
static ir_node *create_const_neg_node(be_abi_irg_t *abi, ir_node *irn, ir_node *block, long value) {
tarval *tv = new_tarval_from_long(value, mode_Iu);
dbg_info *dbg = get_irn_dbg_info(irn);
return new_rd_arm_Mvn_i(dbg, current_ir_graph, block, get_irn_mode(irn), tv);
ir_node *res = new_rd_arm_Mvn_i(dbg, current_ir_graph, block, get_irn_mode(irn), tv);
add_irn_dep(res, be_abi_get_start_barrier(abi));
/* ensure the const is schedules AFTER the barrier */
return res;
}
#define NEW_BINOP_NODE(opname, env, op1, op2) new_rd_arm_##opname(env->dbg, current_ir_graph, env->block, op1, op2, env->mode)
......@@ -159,7 +166,7 @@ unsigned int arm_decode_imm_w_shift(tarval *tv) {
/**
* Creates a possible DAG for an constant.
*/
static ir_node *create_const_graph_value(ir_node *irn, ir_node *block, unsigned int value) {
static ir_node *create_const_graph_value(be_abi_irg_t *abi, ir_node *irn, ir_node *block, unsigned int value) {
ir_node *result;
vals v, vn;
int cnt;
......@@ -171,7 +178,7 @@ static ir_node *create_const_graph_value(ir_node *irn, ir_node *block, unsigned
if (vn.ops < v.ops) {
/* remove bits */
result = create_const_neg_node(irn, block, arm_encode_imm_w_shift(vn.shifts[0], vn.values[0]));
result = create_const_neg_node(abi, irn, block, arm_encode_imm_w_shift(vn.shifts[0], vn.values[0]));
for (cnt = 1; cnt < vn.ops; ++cnt) {
tarval *tv = new_tarval_from_long(arm_encode_imm_w_shift(vn.shifts[cnt], vn.values[cnt]), mode_Iu);
......@@ -181,7 +188,7 @@ static ir_node *create_const_graph_value(ir_node *irn, ir_node *block, unsigned
}
else {
/* add bits */
result = create_const_node(irn, block, arm_encode_imm_w_shift(v.shifts[0], v.values[0]));
result = create_const_node(abi, irn, block, arm_encode_imm_w_shift(v.shifts[0], v.values[0]));
for (cnt = 1; cnt < v.ops; ++cnt) {
tarval *tv = new_tarval_from_long(arm_encode_imm_w_shift(v.shifts[cnt], v.values[cnt]), mode_Iu);
......@@ -197,9 +204,9 @@ static ir_node *create_const_graph_value(ir_node *irn, ir_node *block, unsigned
*
* @param irn a Firm const
*/
static ir_node *create_const_graph(ir_node *irn, ir_node *block) {
static ir_node *create_const_graph(be_abi_irg_t *abi, ir_node *irn, ir_node *block) {
int value = get_tarval_long(get_Const_tarval(irn));
return create_const_graph_value(irn, block, value);
return create_const_graph_value(abi, irn, block, value);
}
......@@ -221,22 +228,22 @@ static ir_node *gen_Const(ir_node *irn, arm_code_gen_t *cg) {
}
else if (mode_is_reference(mode))
return irn;
return create_const_graph(irn, block);
return create_const_graph(cg->birg->abi, irn, block);
}
static ir_node *gen_mask(ir_node *irn, ir_node *op, int result_bits) {
static ir_node *gen_mask(be_abi_irg_t *abi, ir_node *irn, ir_node *op, int result_bits) {
ir_node *block = get_nodes_block(irn);
unsigned mask_bits = (1 << result_bits) - 1;
ir_node *mask_node = create_const_graph_value(irn, block, mask_bits);
ir_node *mask_node = create_const_graph_value(abi, irn, block, mask_bits);
dbg_info *dbg = get_irn_dbg_info(irn);
return new_rd_arm_And(dbg, current_ir_graph, block, op, mask_node, get_irn_mode(irn), ARM_SHF_NONE, NULL);
}
static ir_node *gen_sign_extension(ir_node *irn, ir_node *op, int result_bits) {
static ir_node *gen_sign_extension(be_abi_irg_t *abi, ir_node *irn, ir_node *op, int result_bits) {
ir_node *block = get_nodes_block(irn);
int shift_width = 32 - result_bits;
ir_graph *irg = current_ir_graph;
ir_node *shift_const_node = create_const_graph_value(irn, block, shift_width);
ir_node *shift_const_node = create_const_graph_value(abi, irn, block, shift_width);
dbg_info *dbg = get_irn_dbg_info(irn);
ir_node *lshift_node = new_rd_arm_Shl(dbg, irg, block, op, shift_const_node, get_irn_mode(op));
ir_node *rshift_node = new_rd_arm_Shrs(dbg, irg, block, lshift_node, shift_const_node, get_irn_mode(irn));
......@@ -303,9 +310,9 @@ static ir_node *gen_Conv(ir_node *irn, arm_code_gen_t *cg) {
// NOP
if (in_bits == out_bits && out_bits < 32) {
if (in_sign && !out_sign) {
return gen_mask(irn, op, out_bits);
return gen_mask(cg->birg->abi, irn, op, out_bits);
} else {
return gen_sign_extension(irn, op, out_bits);
return gen_sign_extension(cg->birg->abi, irn, op, out_bits);
}
}
......@@ -320,7 +327,7 @@ static ir_node *gen_Conv(ir_node *irn, arm_code_gen_t *cg) {
// sign extension (31:16)=(15)
if (in_bits < out_bits) {
if (in_sign) {
return gen_sign_extension(irn, op, out_bits);
return gen_sign_extension(cg->birg->abi, irn, op, out_bits);
} else {
return op;
}
......@@ -337,9 +344,9 @@ static ir_node *gen_Conv(ir_node *irn, arm_code_gen_t *cg) {
// sign extension (erledigt auch maskieren) (31:16)=(15)
if (in_bits > out_bits) {
if (in_sign && out_sign) {
return gen_sign_extension(irn, op, out_bits);
return gen_sign_extension(cg->birg->abi, irn, op, out_bits);
} else {
return gen_mask(irn, op, out_bits);
return gen_mask(cg->birg->abi, irn, op, out_bits);
}
}
assert(0 && "recheck integer conversion logic!");
......@@ -894,19 +901,17 @@ static ir_node *gen_Cond(ir_node *irn, arm_code_gen_t *cg) {
* @param symc the SymConst
* @return name of the SymConst
*/
const char *get_sc_name(ir_node *symc) {
ident *get_sc_ident(ir_node *symc) {
ir_entity *ent;
if (get_irn_opcode(symc) != iro_SymConst)
return "NONE";
switch (get_SymConst_kind(symc)) {
case symconst_addr_name:
return get_id_str(get_SymConst_name(symc));
return get_SymConst_name(symc);
case symconst_addr_ent:
ent = get_SymConst_entity(symc);
mark_entity_visited(ent);
return get_entity_ld_name(ent);
return get_entity_ld_ident(ent);
default:
assert(0 && "Unsupported SymConst");
......@@ -919,7 +924,7 @@ static ir_node *gen_SymConst(ir_node *irn, arm_code_gen_t *cg) {
ir_node *block = get_nodes_block(irn);
ir_mode *mode = get_irn_mode(irn);
dbg_info *dbg = get_irn_dbg_info(irn);
return new_rd_arm_SymConst(dbg, current_ir_graph, block, mode, get_sc_name(irn));
return new_rd_arm_SymConst(dbg, current_ir_graph, block, mode, get_sc_ident(irn));
}
......@@ -1042,7 +1047,7 @@ static ir_node *gen_be_FrameAddr(ir_node *irn, arm_code_gen_t *cg) {
is relative. Both must be merged */
offset += get_sp_expand_offset(op);
}
cnst = create_const_graph_value(irn, block, (unsigned)offset);
cnst = create_const_graph_value(cg->birg->abi, irn, block, (unsigned)offset);
if (is_arm_Mov_i(cnst))
return new_rd_arm_Add_i(dbg, current_ir_graph, block, op, mode, get_arm_value(cnst));
return new_rd_arm_Add(dbg, current_ir_graph, block, op, cnst, mode, ARM_SHF_NONE, NULL);
......@@ -1147,6 +1152,7 @@ static ir_node *gen_FrameStore(ir_node *irn, arm_code_gen_t *cg) {
* move constants out of the start block
*/
void arm_move_consts(ir_node *node, void *env) {
arm_code_gen_t *cg = env;
int i;
if (is_Block(node))
......@@ -1158,18 +1164,18 @@ void arm_move_consts(ir_node *node, void *env) {
ir_opcode pred_code = get_irn_opcode(pred);
if (pred_code == iro_Const) {
ir_node *const_graph;
const_graph = create_const_graph(pred, get_nodes_block(get_irn_n(get_nodes_block(node),i)));
const_graph = create_const_graph(cg->birg->abi, pred, get_nodes_block(get_irn_n(get_nodes_block(node),i)));
set_irn_n(node, i, const_graph);
}
else if (pred_code == iro_SymConst) {
/* FIXME: in general, SymConst always require a load, so it
might be better to place them into the first real block
and let the spiller rematerialize them. */
const char *str = get_sc_name(pred);
ident *id = get_sc_ident(pred);
ir_node *symconst_node;
symconst_node = new_rd_arm_SymConst(get_irn_dbg_info(pred),
current_ir_graph, get_nodes_block(get_irn_n(get_nodes_block(node),i)),
get_irn_mode(pred), str);
get_irn_mode(pred), id);
set_irn_n(node, i, symconst_node);
}
}
......@@ -1180,14 +1186,14 @@ void arm_move_consts(ir_node *node, void *env) {
ir_opcode pred_code = get_irn_opcode(pred);
if (pred_code == iro_Const) {
ir_node *const_graph;
const_graph = create_const_graph(pred, get_nodes_block(node));
const_graph = create_const_graph(cg->birg->abi, pred, get_nodes_block(node));
set_irn_n(node, i, const_graph);
} else if (pred_code == iro_SymConst) {
const char *str = get_sc_name(pred);
ident *id = get_sc_ident(pred);
ir_node *symconst_node;
symconst_node = new_rd_arm_SymConst(get_irn_dbg_info(pred),
current_ir_graph, get_nodes_block(node),
get_irn_mode(pred), str);
get_irn_mode(pred), id);
set_irn_n(node, i, symconst_node);
}
}
......@@ -1208,11 +1214,11 @@ void arm_move_symconsts(ir_node *node, void *env) {
ir_opcode pred_code = get_irn_opcode(pred);
if (pred_code == iro_SymConst) {
const char *str = get_sc_name(pred);
ir_node *symconst_node;
ident *id = get_sc_ident(pred);
ir_node *symconst_node;
symconst_node = new_rd_arm_SymConst(get_irn_dbg_info(pred),
current_ir_graph, get_nodes_block(node), get_irn_mode(pred), str);
current_ir_graph, get_nodes_block(node), get_irn_mode(pred), id);
set_irn_n(node, i, symconst_node);
}
}
......
......@@ -937,6 +937,7 @@ static void arm_abi_epilogue(void *self, ir_node *bl, ir_node **mem, pmap *reg_m
curr_pc = be_new_Copy(&arm_reg_classes[CLASS_arm_gp], env->irg, bl, curr_lr );
arch_set_irn_register(env->arch_env, curr_pc, &arm_gp_regs[REG_PC]);
be_set_constr_single_reg(curr_pc, BE_OUT_POS(0), &arm_gp_regs[REG_PC] );
be_node_set_flags(curr_pc, BE_OUT_POS(0), arch_irn_flags_ignore);
} else {
ir_node *sub12_node;
ir_node *load_node;
......@@ -1093,8 +1094,8 @@ static ir_graph **arm_get_irg_list(const void *self, ir_graph ***irg_list) {
static const backend_params *arm_get_libfirm_params(void) {
static arch_dep_params_t ad = {
1, /* allow subs */
0, /* Muls are fast enough on ARM */
31, /* shift would be ok */
1, /* Muls are fast enough on ARM but ... */
1, /* ... one shift would be possible better */
0, /* SMUL is needed, only in Arch M*/
0, /* UMUL is needed, only in Arch M */
32, /* SMUL & UMUL available for 32 bit */
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment