* @file
* @brief This file implements the common parts of IR transformation from
* firm into ia32-Firm.
- * @author Sebastian Buchwald
+ * @author Matthias Braun, Sebastian Buchwald
* @version $Id: ia32_common_transform.c 21012 2008-08-06 13:35:17Z beck $
*/
+#include "config.h"
#include "error.h"
-#include "irargs_t.h"
#include "ircons.h"
#include "irprintf.h"
#include "typerep.h"
#include "../betranshlp.h"
+#include "../beirg_t.h"
#include "ia32_architecture.h"
#include "ia32_common_transform.h"
}
}
-/**
- * creates a unique ident by adding a number to a tag
- *
- * @param tag the tag string, must contain a %d if a number
- * should be added
- */
-static ident *unique_id(const char *tag)
+/* creates a unique ident by adding a number to a tag */
+ident *ia32_unique_id(const char *tag)
{
static unsigned id = 0;
char str[256];
}
/**
- * Get a primitive type for a mode.
+ * Get a primitive type for a mode with alignment 16.
*/
static ir_type *ia32_get_prim_type(pmap *types, ir_mode *mode)
{
char buf[64];
snprintf(buf, sizeof(buf), "prim_type_%s", get_mode_name(mode));
res = new_type_primitive(new_id_from_str(buf), mode);
+ /* FIXME: this is too much for most cases */
set_type_alignment_bytes(res, 16);
pmap_insert(types, mode, res);
}
} else
tp = ia32_get_prim_type(isa->types, mode);
- res = new_entity(get_glob_type(), unique_id(".LC%u"), tp);
+ res = new_entity(get_glob_type(), ia32_unique_id(".LC%u"), tp);
set_entity_ld_ident(res, get_entity_ident(res));
set_entity_visibility(res, visibility_local);
{
ir_graph *irg = current_ir_graph;
ir_node *start_block = get_irg_start_block(irg);
- ir_node *immediate = new_rd_ia32_Immediate(NULL, irg, start_block,
- symconst, symconst_sign, val);
- arch_set_irn_register(env_cg->arch_env, immediate, &ia32_gp_regs[REG_GP_NOREG]);
+ ir_node *immediate = new_bd_ia32_Immediate(NULL, start_block, symconst,
+ symconst_sign, val);
+ arch_set_irn_register(immediate, &ia32_gp_regs[REG_GP_NOREG]);
return immediate;
}
cls = & ia32_reg_classes[c];
for(r = 0; r < cls->n_regs; ++r) {
const arch_register_t *temp_reg = arch_register_for_index(cls, r);
- if(strcmp(temp_reg->name, clobber) == 0
+ if (strcmp(temp_reg->name, clobber) == 0
|| (c == CLASS_ia32_gp && strcmp(temp_reg->name+1, clobber) == 0)) {
reg = temp_reg;
break;
}
}
- if(reg != NULL)
+ if (reg != NULL)
break;
}
return reg;
}
-#ifndef NDEBUG
-const char *ia32_get_old_node_name(ia32_code_gen_t *cg, ir_node *irn) {
- ia32_isa_t *isa = (ia32_isa_t*) cg->arch_env;
-
- lc_eoprintf(firm_get_arg_env(), isa->name_obst, "%+F", irn);
- obstack_1grow(isa->name_obst, 0);
- return obstack_finish(isa->name_obst);
-}
-#endif /* NDEBUG */
-
int ia32_mode_needs_gp_reg(ir_mode *mode) {
- if(mode == mode_fpcw)
+ if (mode == mode_fpcw)
return 0;
- if(get_mode_size_bits(mode) > 32)
+ if (get_mode_size_bits(mode) > 32)
return 0;
return mode_is_int(mode) || mode_is_reference(mode) || mode == mode_b;
}
static void parse_asm_constraints(constraint_t *constraint, const char *c,
int is_output)
{
- asm_constraint_flags_t flags = 0;
char immediate_type = '\0';
unsigned limited = 0;
const arch_register_class_t *cls = NULL;
memset(constraint, 0, sizeof(constraint[0]));
constraint->same_as = -1;
- if(*c == 0) {
+ if (*c == 0) {
/* a memory constraint: no need to do anything in backend about it
* (the dependencies are already respected by the memory edge of
* the node) */
case '\n':
break;
- case '=':
- flags |= ASM_CONSTRAINT_FLAG_MODIFIER_WRITE
- | ASM_CONSTRAINT_FLAG_MODIFIER_NO_READ;
- break;
+ /* Skip out/in-out marker */
+ case '=': break;
+ case '+': break;
- case '+':
- flags |= ASM_CONSTRAINT_FLAG_MODIFIER_WRITE
- | ASM_CONSTRAINT_FLAG_MODIFIER_READ;
- break;
+ case '&': break;
case '*':
++c;
panic("can only specify same constraint on input");
sscanf(c, "%d%n", &same_as, &p);
- if(same_as >= 0) {
+ if (same_as >= 0) {
c += p;
continue;
}
++c;
}
- if(same_as >= 0) {
+ if (same_as >= 0) {
if (cls != NULL)
panic("same as and register constraint not supported");
if (immediate_type != '\0')
ir_node *gen_ASM(ir_node *node)
{
- ir_graph *irg = current_ir_graph;
- ir_node *block = get_nodes_block(node);
- ir_node *new_block = be_transform_node(block);
+ ir_node *block = NULL;
+ ir_node *new_block = NULL;
dbg_info *dbgi = get_irn_dbg_info(node);
int i, arity;
int out_idx;
const ir_asm_constraint *out_constraints;
ident **clobbers;
int clobbers_flags = 0;
- unsigned clobber_bits_gp = 0;
+ unsigned clobber_bits[N_CLASSES];
+
+ memset(&clobber_bits, 0, sizeof(clobber_bits));
+
+ switch (be_transformer) {
+ case TRANSFORMER_DEFAULT:
+ block = get_nodes_block(node);
+ new_block = be_transform_node(block);
+ break;
+
+#ifdef FIRM_GRGEN_BE
+ case TRANSFORMER_PBQP:
+ case TRANSFORMER_RAND:
+ new_block = get_nodes_block(node);
+ break;
+#endif
+
+ default:
+ panic("invalid transformer");
+ }
/* workaround for lots of buggy code out there as most people think volatile
* asm is enough for everything and forget the flags (linux kernel, etc.)
}
arity = get_irn_arity(node);
- in = alloca(arity * sizeof(in[0]));
- memset(in, 0, arity * sizeof(in[0]));
+ in = ALLOCANZ(ir_node*, arity);
clobbers = get_ASM_clobbers(node);
n_clobbers = 0;
- for(i = 0; i < get_ASM_n_clobbers(node); ++i) {
+ for (i = 0; i < get_ASM_n_clobbers(node); ++i) {
const arch_register_req_t *req;
const char *c = get_id_str(clobbers[i]);
}
req = parse_clobber(c);
- if (req->cls == &ia32_reg_classes[CLASS_ia32_gp]) {
- clobber_bits_gp |= *req->limited;
- }
+ clobber_bits[req->cls->index] |= *req->limited;
n_clobbers++;
}
out_constraints = get_ASM_output_constraints(node);
/* determine size of register_map */
- for(out_idx = 0; out_idx < n_out_constraints; ++out_idx) {
+ for (out_idx = 0; out_idx < n_out_constraints; ++out_idx) {
const ir_asm_constraint *constraint = &out_constraints[out_idx];
if (constraint->pos > reg_map_size)
reg_map_size = constraint->pos;
}
- for(i = 0; i < arity; ++i) {
+ for (i = 0; i < arity; ++i) {
const ir_asm_constraint *constraint = &in_constraints[i];
- if(constraint->pos > reg_map_size)
+ if (constraint->pos > reg_map_size)
reg_map_size = constraint->pos;
}
++reg_map_size;
- obst = get_irg_obstack(irg);
+ obst = get_irg_obstack(current_ir_graph);
register_map = NEW_ARR_D(ia32_asm_reg_t, obst, reg_map_size);
memset(register_map, 0, reg_map_size * sizeof(register_map[0]));
/* construct output constraints */
out_reg_reqs = obstack_alloc(obst, out_arity * sizeof(out_reg_reqs[0]));
- for(out_idx = 0; out_idx < n_out_constraints; ++out_idx) {
+ for (out_idx = 0; out_idx < n_out_constraints; ++out_idx) {
const ir_asm_constraint *constraint = &out_constraints[out_idx];
const char *c = get_id_str(constraint->constraint);
unsigned pos = constraint->pos;
/* inputs + input constraints */
in_reg_reqs = obstack_alloc(obst, arity * sizeof(in_reg_reqs[0]));
- for(i = 0; i < arity; ++i) {
+ for (i = 0; i < arity; ++i) {
ir_node *pred = get_irn_n(node, i);
const ir_asm_constraint *constraint = &in_constraints[i];
ident *constr_id = constraint->constraint;
unsigned pos = constraint->pos;
int is_memory_op = 0;
ir_node *input = NULL;
+ unsigned r_clobber_bits;
constraint_t parsed_constraint;
const arch_register_req_t *req;
parse_asm_constraints(&parsed_constraint, c, 0);
- if (clobber_bits_gp != 0 &&
- parsed_constraint.cls == &ia32_reg_classes[CLASS_ia32_gp]) {
- if (parsed_constraint.all_registers_allowed) {
- parsed_constraint.all_registers_allowed = 0;
- parsed_constraint.allowed_registers =
- 1 << REG_EAX |
- 1 << REG_EBX |
- 1 << REG_ECX |
- 1 << REG_EDX |
- 1 << REG_ESI |
- 1 << REG_EDI |
- 1 << REG_EBP;
+ if (parsed_constraint.cls != NULL) {
+ r_clobber_bits = clobber_bits[parsed_constraint.cls->index];
+ if (r_clobber_bits != 0) {
+ if (parsed_constraint.all_registers_allowed) {
+ parsed_constraint.all_registers_allowed = 0;
+ be_abi_set_non_ignore_regs(env_cg->birg->abi,
+ parsed_constraint.cls,
+ &parsed_constraint.allowed_registers);
+ }
+ parsed_constraint.allowed_registers &= ~r_clobber_bits;
}
- parsed_constraint.allowed_registers &= ~clobber_bits_gp;
}
req = make_register_req(&parsed_constraint, n_out_constraints,
}
if (input == NULL) {
- ir_node *pred = get_irn_n(node, i);
- input = be_transform_node(pred);
+ ir_node *pred = NULL;
+ switch (be_transformer) {
+ case TRANSFORMER_DEFAULT:
+ pred = get_irn_n(node, i);
+ input = be_transform_node(pred);
+ break;
+
+#ifdef FIRM_GRGEN_BE
+ case TRANSFORMER_PBQP:
+ case TRANSFORMER_RAND:
+ input = get_irn_n(node, i);
+ break;
+#endif
+
+ default: panic("invalid transformer");
+ }
if (parsed_constraint.cls == NULL
&& parsed_constraint.same_as < 0) {
is_memory_op = 1;
- } else if(parsed_constraint.memory_possible) {
+ } else if (parsed_constraint.memory_possible) {
/* TODO: match Load or Load/Store if memory possible is set */
}
}
}
/* parse clobbers */
- for(i = 0; i < get_ASM_n_clobbers(node); ++i) {
+ for (i = 0; i < get_ASM_n_clobbers(node); ++i) {
const char *c = get_id_str(clobbers[i]);
const arch_register_req_t *req;
++out_idx;
}
- new_node = new_rd_ia32_Asm(dbgi, irg, new_block, arity, in, out_arity,
+ new_node = new_bd_ia32_Asm(dbgi, new_block, arity, in, out_arity,
get_ASM_text(node), register_map);
+ if (arity == 0)
+ be_dep_on_frame(new_node);
+
set_ia32_out_req_all(new_node, out_reg_reqs);
set_ia32_in_req_all(new_node, in_reg_reqs);
- SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, node));
+ SET_IA32_ORIG_NODE(new_node, node);
return new_node;
}
+ir_node *gen_CopyB(ir_node *node) {
+ ir_node *block = NULL;
+ ir_node *src = NULL;
+ ir_node *new_src = NULL;
+ ir_node *dst = NULL;
+ ir_node *new_dst = NULL;
+ ir_node *mem = NULL;
+ ir_node *new_mem = NULL;
+ ir_node *res = NULL;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ int size = get_type_size_bytes(get_CopyB_type(node));
+ int rem;
+
+ switch (be_transformer) {
+ case TRANSFORMER_DEFAULT:
+ block = be_transform_node(get_nodes_block(node));
+ src = get_CopyB_src(node);
+ new_src = be_transform_node(src);
+ dst = get_CopyB_dst(node);
+ new_dst = be_transform_node(dst);
+ mem = get_CopyB_mem(node);
+ new_mem = be_transform_node(mem);
+ break;
+
+#ifdef FIRM_GRGEN_BE
+ case TRANSFORMER_PBQP:
+ case TRANSFORMER_RAND:
+ block = get_nodes_block(node);
+ new_src = get_CopyB_src(node);
+ new_dst = get_CopyB_dst(node);
+ new_mem = get_CopyB_mem(node);
+ break;
+#endif
+
+ default: panic("invalid transformer");
+ }
+
+ /* If we have to copy more than 32 bytes, we use REP MOVSx and */
+ /* then we need the size explicitly in ECX. */
+ if (size >= 32 * 4) {
+ rem = size & 0x3; /* size % 4 */
+ size >>= 2;
+
+ res = new_bd_ia32_Const(dbgi, block, NULL, 0, size);
+ be_dep_on_frame(res);
+
+ res = new_bd_ia32_CopyB(dbgi, block, new_dst, new_src, res, new_mem, rem);
+ } else {
+ if (size == 0) {
+ ir_fprintf(stderr, "Optimization warning copyb %+F with size <4\n",
+ node);
+ }
+ res = new_bd_ia32_CopyB_i(dbgi, block, new_dst, new_src, new_mem, size);
+ }
+
+ SET_IA32_ORIG_NODE(res, node);
+
+ return res;
+}
+
+ir_node *gen_Proj_tls(ir_node *node) {
+ ir_node *block = NULL;
+ dbg_info *dbgi = NULL;
+ ir_node *res = NULL;
+
+ switch (be_transformer) {
+ case TRANSFORMER_DEFAULT:
+ block = be_transform_node(get_nodes_block(node));
+ break;
+
+#ifdef FIRM_GRGEN_BE
+ case TRANSFORMER_PBQP:
+ case TRANSFORMER_RAND:
+ block = get_nodes_block(node);
+ break;
+#endif
+
+ default: panic("invalid transformer");
+ }
+
+ res = new_bd_ia32_LdTls(dbgi, block, mode_Iu);
+
+ return res;
+}
+
ir_node *gen_Unknown(ir_node *node)
{
ir_mode *mode = get_irn_mode(node);
ir_graph *irg = current_ir_graph;
dbg_info *dbgi = get_irn_dbg_info(node);
ir_node *block = get_irg_start_block(irg);
- ir_node *ret = new_rd_ia32_vfldz(dbgi, irg, block);
-
- /* Const Nodes before the initial IncSP are a bad idea, because
- * they could be spilled and we have no SP ready at that point yet.
- * So add a dependency to the initial frame pointer calculation to
- * avoid that situation.
- */
- add_irn_dep(ret, get_irg_frame(irg));
+ ir_node *ret = new_bd_ia32_vfldz(dbgi, block);
+
+ be_dep_on_frame(ret);
return ret;
}
} else if (ia32_mode_needs_gp_reg(mode)) {
if (same_as >= n_outs)
panic("invalid output number in same_as constraint");
- other_constr = out_reqs[same_as];
+ other_constr = out_reqs[same_as];
- req = obstack_alloc(obst, sizeof(req[0]));
- req->cls = other_constr->cls;
- req->type = arch_register_req_type_should_be_same;
- req->limited = NULL;
- req->other_same = 1U << pos;
- req->other_different = 0;
+ req = obstack_alloc(obst, sizeof(req[0]));
+ *req = *other_constr;
+ req->type |= arch_register_req_type_should_be_same;
+ req->other_same = 1U << pos;
/* switch constraints. This is because in firm we have same_as
* constraints on the output constraints while in the gcc asm syntax
arch_register_req_t *req;
unsigned *limited;
- if(reg == NULL) {
- panic("Register '%s' mentioned in asm clobber is unknown\n", clobber);
+ if (reg == NULL) {
+ panic("Register '%s' mentioned in asm clobber is unknown", clobber);
}
assert(reg->index < 32);
return req;
}
+
+int prevents_AM(ir_node *const block, ir_node *const am_candidate,
+ ir_node *const other)
+{
+ if (get_nodes_block(other) != block)
+ return 0;
+
+ if (is_Sync(other)) {
+ int i;
+
+ for (i = get_Sync_n_preds(other) - 1; i >= 0; --i) {
+ ir_node *const pred = get_Sync_pred(other, i);
+
+ if (get_nodes_block(pred) != block)
+ continue;
+
+ /* Do not block ourselves from getting eaten */
+ if (is_Proj(pred) && get_Proj_pred(pred) == am_candidate)
+ continue;
+
+ if (!heights_reachable_in_block(heights, pred, am_candidate))
+ continue;
+
+ return 1;
+ }
+
+ return 0;
+ } else {
+ /* Do not block ourselves from getting eaten */
+ if (is_Proj(other) && get_Proj_pred(other) == am_candidate)
+ return 0;
+
+ if (!heights_reachable_in_block(heights, other, am_candidate))
+ return 0;
+
+ return 1;
+ }
+}
+
ir_node *try_create_Immediate(ir_node *node, char immediate_constraint_type)
{
int minus = 0;
ir_node *new_node;
mode = get_irn_mode(node);
- if(!mode_is_int(mode) && !mode_is_reference(mode)) {
+ if (!mode_is_int(mode) && !mode_is_reference(mode)) {
return NULL;
}
- if(is_Minus(node)) {
+ if (is_Minus(node)) {
minus = 1;
node = get_Minus_op(node);
}
- if(is_Const(node)) {
+ if (is_Const(node)) {
cnst = node;
symconst = NULL;
offset_sign = minus;
- } else if(is_SymConst(node)) {
+ } else if (is_SymConst(node)) {
cnst = NULL;
symconst = node;
symconst_sign = minus;
- } else if(is_Add(node)) {
+ } else if (is_Add(node)) {
ir_node *left = get_Add_left(node);
ir_node *right = get_Add_right(node);
- if(is_Const(left) && is_SymConst(right)) {
+ if (is_Const(left) && is_SymConst(right)) {
cnst = left;
symconst = right;
symconst_sign = minus;
offset_sign = minus;
- } else if(is_SymConst(left) && is_Const(right)) {
+ } else if (is_SymConst(left) && is_Const(right)) {
cnst = right;
symconst = left;
symconst_sign = minus;
offset_sign = minus;
}
- } else if(is_Sub(node)) {
+ } else if (is_Sub(node)) {
ir_node *left = get_Sub_left(node);
ir_node *right = get_Sub_right(node);
- if(is_Const(left) && is_SymConst(right)) {
+ if (is_Const(left) && is_SymConst(right)) {
cnst = left;
symconst = right;
symconst_sign = !minus;
offset_sign = minus;
- } else if(is_SymConst(left) && is_Const(right)) {
+ } else if (is_SymConst(left) && is_Const(right)) {
cnst = right;
symconst = left;
symconst_sign = minus;
return NULL;
}
- if(cnst != NULL) {
+ if (cnst != NULL) {
offset = get_Const_tarval(cnst);
- if(tarval_is_long(offset)) {
+ if (tarval_is_long(offset)) {
val = get_tarval_long(offset);
} else {
ir_fprintf(stderr, "Optimisation Warning: tarval from %+F is not a "
return NULL;
}
- if(!check_immediate_constraint(val, immediate_constraint_type))
+ if (!check_immediate_constraint(val, immediate_constraint_type))
return NULL;
}
- if(symconst != NULL) {
- if(immediate_constraint_type != 0) {
+ if (symconst != NULL) {
+ if (immediate_constraint_type != 0) {
/* we need full 32bits for symconsts */
return NULL;
}
/* unfortunately the assembler/linker doesn't support -symconst */
- if(symconst_sign)
+ if (symconst_sign)
return NULL;
- if(get_SymConst_kind(symconst) != symconst_addr_ent)
+ if (get_SymConst_kind(symconst) != symconst_addr_ent)
return NULL;
symconst_ent = get_SymConst_entity(symconst);
}
- if(cnst == NULL && symconst == NULL)
+ if (cnst == NULL && symconst == NULL)
return NULL;
- if(offset_sign && offset != NULL) {
+ if (offset_sign && offset != NULL) {
offset = tarval_neg(offset);
}