DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
static ir_node *initial_fpcw = NULL;
-static heights_t *heights = NULL;
extern ir_op *get_op_Mulh(void);
return ent_cache[kct];
}
+static 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;
+ }
+}
+
/**
* return true if the node is a Proj(Load) and could be used in source address
* mode for another node. Will return only true if the @p other node is not
return 0;
/* don't do AM if other node inputs depend on the load (via mem-proj) */
- if (other != NULL && get_nodes_block(other) == block &&
- heights_reachable_in_block(heights, other, load))
+ if (other != NULL && prevents_AM(block, load, other))
return 0;
- if (other2 != NULL && get_nodes_block(other2) == block &&
- heights_reachable_in_block(heights, other2, load))
+
+ if (other2 != NULL && prevents_AM(block, load, other2))
return 0;
return 1;
| match_am | match_immediate);
}
+static ir_node *transform_AM_mem(ir_graph *const irg, ir_node *const block,
+ ir_node *const src_val,
+ ir_node *const src_mem,
+ ir_node *const am_mem)
+{
+ if (is_NoMem(am_mem)) {
+ return be_transform_node(src_mem);
+ } else if (is_Proj(src_val) &&
+ is_Proj(src_mem) &&
+ get_Proj_pred(src_val) == get_Proj_pred(src_mem)) {
+ /* avoid memory loop */
+ return am_mem;
+ } else if (is_Proj(src_val) && is_Sync(src_mem)) {
+ ir_node *const ptr_pred = get_Proj_pred(src_val);
+ int const arity = get_Sync_n_preds(src_mem);
+ int n = 0;
+ ir_node ** ins;
+ int i;
+
+ NEW_ARR_A(ir_node*, ins, arity + 1);
+
+ for (i = arity - 1; i >= 0; --i) {
+ ir_node *const pred = get_Sync_pred(src_mem, i);
+
+ /* avoid memory loop */
+ if (is_Proj(pred) && get_Proj_pred(pred) == ptr_pred)
+ continue;
+
+ ins[n++] = be_transform_node(pred);
+ }
+
+ ins[n++] = am_mem;
+
+ return new_r_Sync(irg, block, n, ins);
+ } else {
+ ir_node *ins[2];
+
+ ins[0] = be_transform_node(src_mem);
+ ins[1] = am_mem;
+ return new_r_Sync(irg, block, 2, ins);
+ }
+}
+
/**
* Generates an ia32 DivMod with additional infrastructure for the
* register allocator if needed.
/* Beware: We don't need a Sync, if the memory predecessor of the Div node
is the memory of the consumed address. We can have only the second op as address
in Div nodes, so check only op2. */
- if(!is_NoMem(mem) && skip_Proj(mem) != skip_Proj(op2)) {
- new_mem = be_transform_node(mem);
- if(!is_NoMem(addr->mem)) {
- ir_node *in[2];
- in[0] = new_mem;
- in[1] = addr->mem;
- new_mem = new_rd_Sync(dbgi, irg, new_block, 2, in);
- }
- } else {
- new_mem = addr->mem;
- }
+ new_mem = transform_AM_mem(irg, block, op2, mem, addr->mem);
if (mode_is_signed(mode)) {
ir_node *produceval = new_rd_ia32_ProduceVal(dbgi, irg, new_block);
return new_node;
}
-/**
- * Transforms a CopyB node.
- *
- * @return The transformed node.
- */
-static ir_node *gen_CopyB(ir_node *node) {
- ir_node *block = be_transform_node(get_nodes_block(node));
- ir_node *src = get_CopyB_src(node);
- ir_node *new_src = be_transform_node(src);
- ir_node *dst = get_CopyB_dst(node);
- ir_node *new_dst = be_transform_node(dst);
- ir_node *mem = get_CopyB_mem(node);
- ir_node *new_mem = be_transform_node(mem);
- ir_node *res = NULL;
- ir_graph *irg = current_ir_graph;
- dbg_info *dbgi = get_irn_dbg_info(node);
- int size = get_type_size_bytes(get_CopyB_type(node));
- int rem;
-
- /* 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_rd_ia32_Const(dbgi, irg, block, NULL, 0, size);
- add_irn_dep(res, get_irg_frame(irg));
-
- res = new_rd_ia32_CopyB(dbgi, irg, block, new_dst, new_src, res, new_mem, rem);
- } else {
- if(size == 0) {
- ir_fprintf(stderr, "Optimisation warning copyb %+F with size <4\n",
- node);
- }
- res = new_rd_ia32_CopyB_i(dbgi, irg, block, new_dst, new_src, new_mem, size);
- }
-
- SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node));
-
- return res;
-}
-
static ir_node *gen_be_Copy(ir_node *node)
{
ir_node *new_node = be_duplicate_node(node);
assert(ia32_mode_needs_gp_reg(cmp_mode));
- /* we prefer the Test instruction where possible except cases where
- * we can use SourceAM */
+ /* Prefer the Test instruction, when encountering (x & y) ==/!= 0 */
cmp_unsigned = !mode_is_signed(cmp_mode);
- if (is_Const_0(right)) {
- if (is_And(left) &&
- get_irn_n_edges(left) == 1 &&
- can_fold_test_and(node)) {
- /* Test(and_left, and_right) */
- ir_node *and_left = get_And_left(left);
- ir_node *and_right = get_And_right(left);
- ir_mode *mode = get_irn_mode(and_left);
-
- match_arguments(&am, block, and_left, and_right, NULL,
- match_commutative |
- match_am | match_8bit_am | match_16bit_am |
- match_am_and_immediates | match_immediate |
- match_8bit | match_16bit);
- if (get_mode_size_bits(mode) == 8) {
- new_node = new_rd_ia32_Test8Bit(dbgi, irg, new_block, addr->base,
- addr->index, addr->mem, am.new_op1,
- am.new_op2, am.ins_permuted,
- cmp_unsigned);
- } else {
- new_node = new_rd_ia32_Test(dbgi, irg, new_block, addr->base,
- addr->index, addr->mem, am.new_op1,
- am.new_op2, am.ins_permuted, cmp_unsigned);
- }
+ if (is_Const_0(right) &&
+ is_And(left) &&
+ get_irn_n_edges(left) == 1 &&
+ can_fold_test_and(node)) {
+ /* Test(and_left, and_right) */
+ ir_node *and_left = get_And_left(left);
+ ir_node *and_right = get_And_right(left);
+ ir_mode *mode = get_irn_mode(and_left);
+
+ match_arguments(&am, block, and_left, and_right, NULL,
+ match_commutative |
+ match_am | match_8bit_am | match_16bit_am |
+ match_am_and_immediates | match_immediate |
+ match_8bit | match_16bit);
+ if (get_mode_size_bits(mode) == 8) {
+ new_node = new_rd_ia32_Test8Bit(dbgi, irg, new_block, addr->base,
+ addr->index, addr->mem, am.new_op1,
+ am.new_op2, am.ins_permuted,
+ cmp_unsigned);
} else {
- match_arguments(&am, block, NULL, left, NULL,
- match_am | match_8bit_am | match_16bit_am |
- match_8bit | match_16bit);
- if (am.op_type == ia32_AddrModeS) {
- /* Cmp(AM, 0) */
- ir_node *imm_zero = try_create_Immediate(right, 0);
- if (get_mode_size_bits(cmp_mode) == 8) {
- new_node = new_rd_ia32_Cmp8Bit(dbgi, irg, new_block, addr->base,
- addr->index, addr->mem, am.new_op2,
- imm_zero, am.ins_permuted,
- cmp_unsigned);
- } else {
- new_node = new_rd_ia32_Cmp(dbgi, irg, new_block, addr->base,
- addr->index, addr->mem, am.new_op2,
- imm_zero, am.ins_permuted, cmp_unsigned);
- }
- } else {
- /* Test(left, left) */
- if (get_mode_size_bits(cmp_mode) == 8) {
- new_node = new_rd_ia32_Test8Bit(dbgi, irg, new_block, addr->base,
- addr->index, addr->mem, am.new_op2,
- am.new_op2, am.ins_permuted,
- cmp_unsigned);
- } else {
- new_node = new_rd_ia32_Test(dbgi, irg, new_block, addr->base,
- addr->index, addr->mem, am.new_op2,
- am.new_op2, am.ins_permuted,
- cmp_unsigned);
- }
- }
+ new_node = new_rd_ia32_Test(dbgi, irg, new_block, addr->base,
+ addr->index, addr->mem, am.new_op1,
+ am.new_op2, am.ins_permuted, cmp_unsigned);
}
} else {
/* Cmp(left, right) */
}
}
set_am_attributes(new_node, &am);
- assert(cmp_mode != NULL);
set_ia32_ls_mode(new_node, cmp_mode);
SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, node));
return new_rd_Unknown(irg, mode);
}
-/**
- * Transform the Thread Local Storage Proj.
- */
-static ir_node *gen_Proj_tls(ir_node *node) {
- ir_node *block = be_transform_node(get_nodes_block(node));
- ir_graph *irg = current_ir_graph;
- dbg_info *dbgi = NULL;
- ir_node *res = new_rd_ia32_LdTls(dbgi, irg, block, mode_Iu);
-
- return res;
-}
-
static ir_node *gen_be_Call(ir_node *node) {
ir_node *res = be_duplicate_node(node);
be_node_add_flags(res, -1, arch_irn_flags_modify_flags);
}
/**
- * Walker, checks if all ia32 nodes producing more than one result have
- * its Projs, otherwise creates new Projs and keep them using a be_Keep node.
+ * Walker, checks if all ia32 nodes producing more than one result have their
+ * Projs, otherwise creates new Projs and keeps them using a be_Keep node.
*/
static void add_missing_keep_walker(ir_node *node, void *data)
{