#endif
#include <limits.h>
+#include <stdbool.h>
#include "irargs_t.h"
#include "irnode_t.h"
#include "irdom.h"
#include "archop.h"
#include "error.h"
+#include "array_t.h"
#include "height.h"
#include "../benode_t.h"
ir_node *op, ir_node *orig_node);
/** Return non-zero is a node represents the 0 constant. */
-static int is_Const_0(ir_node *node) {
+static bool is_Const_0(ir_node *node) {
return is_Const(node) && is_Const_null(node);
}
/** Return non-zero is a node represents the 1 constant. */
-static int is_Const_1(ir_node *node) {
+static bool is_Const_1(ir_node *node) {
return is_Const(node) && is_Const_one(node);
}
/** Return non-zero is a node represents the -1 constant. */
-static int is_Const_Minus_1(ir_node *node) {
+static bool is_Const_Minus_1(ir_node *node) {
return is_Const(node) && is_Const_all_one(node);
}
/**
* returns true if constant can be created with a simple float command
*/
-static int is_simple_x87_Const(ir_node *node)
+static bool is_simple_x87_Const(ir_node *node)
{
tarval *tv = get_Const_tarval(node);
if (tarval_is_null(tv) || tarval_is_one(tv))
- return 1;
+ return true;
/* TODO: match all the other float constants */
- return 0;
+ return false;
}
/**
* returns true if constant can be created with a simple float command
*/
-static int is_simple_sse_Const(ir_node *node)
+static bool is_simple_sse_Const(ir_node *node)
{
tarval *tv = get_Const_tarval(node);
ir_mode *mode = get_tarval_mode(tv);
if (mode == mode_F)
- return 1;
+ return true;
if (tarval_is_null(tv) || tarval_is_one(tv))
- return 1;
+ return true;
if (mode == mode_D) {
unsigned val = get_tarval_sub_bits(tv, 0) |
(get_tarval_sub_bits(tv, 3) << 24);
if (val == 0)
/* lower 32bit are zero, really a 32bit constant */
- return 1;
+ return true;
}
/* TODO: match all the other float constants */
- return 0;
+ return false;
}
/**
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
ia32_address_t addr;
ir_mode *ls_mode;
ir_node *mem_proj;
+ ir_node *am_node;
ia32_op_type_t op_type;
ir_node *new_op1;
ir_node *new_op2;
am->pinned = get_irn_pinned(load);
am->ls_mode = get_Load_mode(load);
am->mem_proj = be_get_Proj_for_pn(load, pn_Load_M);
+ am->am_node = node;
/* construct load address */
ia32_create_address_mode(addr, ptr, /*force=*/0);
}
am->op_type = ia32_AddrModeS;
} else {
+ am->op_type = ia32_Normal;
+
if (flags & match_try_am) {
am->new_op1 = NULL;
am->new_op2 = NULL;
- am->op_type = ia32_Normal;
return;
}
new_op1 = (op1 == NULL ? NULL : be_transform_node(op1));
if (new_op2 == NULL)
new_op2 = be_transform_node(op2);
- am->op_type = ia32_Normal;
- am->ls_mode = get_irn_mode(op2);
- if (flags & match_mode_neutral)
- am->ls_mode = mode_Iu;
+ am->ls_mode =
+ (flags & match_mode_neutral ? mode_Iu : get_irn_mode(op2));
}
if (addr->base == NULL)
addr->base = noreg_gp;
mode = get_irn_mode(node);
load = get_Proj_pred(am->mem_proj);
- mark_irn_visited(load);
be_set_transformed_node(load, node);
if (mode != mode_T) {
am.new_op1, am.new_op2);
set_am_attributes(new_node, &am);
/* we can't use source address mode anymore when using immediates */
- if (is_ia32_Immediate(am.new_op1) || is_ia32_Immediate(am.new_op2))
- set_ia32_am_support(new_node, ia32_am_None, ia32_am_arity_none);
+ if (!(flags & match_am_and_immediates) &&
+ (is_ia32_Immediate(am.new_op1) || is_ia32_Immediate(am.new_op2)))
+ set_ia32_am_support(new_node, ia32_am_none);
SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, node));
new_node = fix_mem_proj(new_node, &am);
ir_node *src_block = get_nodes_block(node);
ir_node *op1 = get_irn_n(node, n_ia32_l_binop_left);
ir_node *op2 = get_irn_n(node, n_ia32_l_binop_right);
+ ir_node *eflags = get_irn_n(node, n_ia32_l_binop_eflags);
dbg_info *dbgi;
- ir_node *block, *new_node, *eflags, *new_eflags;
+ ir_node *block, *new_node, *new_eflags;
ia32_address_mode_t am;
ia32_address_t *addr = &am.addr;
- match_arguments(&am, src_block, op1, op2, NULL, flags);
+ match_arguments(&am, src_block, op1, op2, eflags, flags);
dbgi = get_irn_dbg_info(node);
block = be_transform_node(src_block);
- eflags = get_irn_n(node, n_ia32_l_binop_eflags);
new_eflags = be_transform_node(eflags);
new_node = func(dbgi, current_ir_graph, block, addr->base, addr->index,
addr->mem, am.new_op1, am.new_op2, new_eflags);
set_am_attributes(new_node, &am);
/* we can't use source address mode anymore when using immediates */
- if(is_ia32_Immediate(am.new_op1) || is_ia32_Immediate(am.new_op2))
- set_ia32_am_support(new_node, ia32_am_None, ia32_am_arity_none);
+ if (!(flags & match_am_and_immediates) &&
+ (is_ia32_Immediate(am.new_op1) || is_ia32_Immediate(am.new_op2)))
+ set_ia32_am_support(new_node, ia32_am_none);
SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, node));
new_node = fix_mem_proj(new_node, &am);
*
* @return the created ia32 Mulh node
*/
-static ir_node *gen_Mulh(ir_node *node)
-{
- ir_node *block = get_nodes_block(node);
- ir_node *new_block = be_transform_node(block);
- ir_graph *irg = current_ir_graph;
- dbg_info *dbgi = get_irn_dbg_info(node);
- ir_mode *mode = get_irn_mode(node);
- ir_node *op1 = get_Mulh_left(node);
- ir_node *op2 = get_Mulh_right(node);
- ir_node *proj_res_high;
- ir_node *new_node;
- ia32_address_mode_t am;
- ia32_address_t *addr = &am.addr;
-
- assert(!mode_is_float(mode) && "Mulh with float not supported");
- assert(get_mode_size_bits(mode) == 32);
-
- match_arguments(&am, block, op1, op2, NULL, match_commutative | match_am);
+static ir_node *gen_Mulh(ir_node *node) {
+ ir_node *block = get_nodes_block(node);
+ ir_node *new_block = be_transform_node(block);
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *op1 = get_Mulh_left(node);
+ ir_node *op2 = get_Mulh_right(node);
+ ir_mode *mode = get_irn_mode(node);
+ ir_node *new_node;
+ ir_node *proj_res_high;
if (mode_is_signed(mode)) {
- new_node = new_rd_ia32_IMul1OP(dbgi, irg, new_block, addr->base,
- addr->index, addr->mem, am.new_op1,
- am.new_op2);
+ new_node = gen_binop(node, op1, op2, new_rd_ia32_IMul1OP, match_commutative | match_am);
+ proj_res_high = new_rd_Proj(dbgi, current_ir_graph, new_block, new_node,
+ mode_Iu, pn_ia32_IMul1OP_res_high);
} else {
- new_node = new_rd_ia32_Mul(dbgi, irg, new_block, addr->base,
- addr->index, addr->mem, am.new_op1,
- am.new_op2);
+ new_node = gen_binop(node, op1, op2, new_rd_ia32_Mul, match_commutative | match_am);
+ proj_res_high = new_rd_Proj(dbgi, current_ir_graph, new_block, new_node,
+ mode_Iu, pn_ia32_Mul_res_high);
}
-
- set_am_attributes(new_node, &am);
- /* we can't use source address mode anymore when using immediates */
- if(is_ia32_Immediate(am.new_op1) || is_ia32_Immediate(am.new_op2))
- set_ia32_am_support(new_node, ia32_am_None, ia32_am_arity_none);
- SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, node));
-
- assert(get_irn_mode(new_node) == mode_T);
-
- fix_mem_proj(new_node, &am);
-
- assert(pn_ia32_IMul1OP_res_high == pn_ia32_Mul_res_high);
- proj_res_high = new_rd_Proj(dbgi, irg, block, new_node,
- mode_Iu, pn_ia32_IMul1OP_res_high);
-
return proj_res_high;
}
-
-
/**
* Creates an ia32 And.
*
{
ir_node *load;
- if(!is_Proj(node))
+ if (!is_Proj(node))
return 0;
/* we only use address mode if we're the only user of the load */
- if(get_irn_n_edges(node) > 1)
+ if (get_irn_n_edges(node) > 1)
return 0;
load = get_Proj_pred(node);
- if(!is_Load(load))
+ if (!is_Load(load))
return 0;
- if(get_nodes_block(load) != block)
+ if (get_nodes_block(load) != block)
return 0;
- /* Store should be attached to the load */
- if(!is_Proj(mem) || get_Proj_pred(mem) != load)
- return 0;
/* store should have the same pointer as the load */
- if(get_Load_ptr(load) != ptr)
+ if (get_Load_ptr(load) != ptr)
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 &&
+ get_nodes_block(other) == block &&
+ heights_reachable_in_block(heights, other, load)) {
return 0;
+ }
- return 1;
-}
+ if (is_Sync(mem)) {
+ int i;
-static void set_transformed_and_mark(ir_node *const old_node, ir_node *const new_node)
-{
- mark_irn_visited(old_node);
- be_set_transformed_node(old_node, new_node);
+ for (i = get_Sync_n_preds(mem) - 1; i >= 0; --i) {
+ ir_node *const pred = get_Sync_pred(mem, i);
+
+ if (is_Proj(pred) && get_Proj_pred(pred) == load)
+ continue;
+
+ if (get_nodes_block(pred) == block &&
+ heights_reachable_in_block(heights, pred, load)) {
+ return 0;
+ }
+ }
+ } else {
+ /* Store should be attached to the load */
+ if (!is_Proj(mem) || get_Proj_pred(mem) != load)
+ return 0;
+ }
+
+ return 1;
}
static ir_node *dest_am_binop(ir_node *node, ir_node *op1, ir_node *op2,
ir_node *noreg_gp = ia32_new_NoReg_gp(env_cg);
ir_graph *irg = current_ir_graph;
dbg_info *dbgi;
+ ir_node *new_mem;
ir_node *new_node;
ir_node *new_op;
ir_node *mem_proj;
if(addr->mem == NULL)
addr->mem = new_NoMem();
- dbgi = get_irn_dbg_info(node);
- block = be_transform_node(src_block);
+ dbgi = get_irn_dbg_info(node);
+ block = be_transform_node(src_block);
+ new_mem = transform_AM_mem(irg, block, am.am_node, mem, addr->mem);
+
if(get_mode_size_bits(mode) == 8) {
new_node = func8bit(dbgi, irg, block, addr->base, addr->index,
- addr->mem, new_op);
+ new_mem, new_op);
} else {
- new_node = func(dbgi, irg, block, addr->base, addr->index, addr->mem,
+ new_node = func(dbgi, irg, block, addr->base, addr->index, new_mem,
new_op);
}
set_address(new_node, addr);
set_ia32_ls_mode(new_node, mode);
SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, node));
- set_transformed_and_mark(get_Proj_pred(am.mem_proj), new_node);
+ be_set_transformed_node(get_Proj_pred(am.mem_proj), new_node);
mem_proj = be_transform_node(am.mem_proj);
- set_transformed_and_mark(mem_proj ? mem_proj : am.mem_proj, new_node);
+ be_set_transformed_node(mem_proj ? mem_proj : am.mem_proj, new_node);
return new_node;
}
ir_node *ptr, ir_mode *mode,
construct_unop_dest_func *func)
{
- ir_graph *irg = current_ir_graph;
- ir_node *src_block = get_nodes_block(node);
- ir_node *block;
+ ir_graph *irg = current_ir_graph;
+ ir_node *src_block = get_nodes_block(node);
+ ir_node *block;
dbg_info *dbgi;
- ir_node *new_node;
- ir_node *mem_proj;
+ ir_node *new_mem;
+ ir_node *new_node;
+ ir_node *mem_proj;
ia32_address_mode_t am;
ia32_address_t *addr = &am.addr;
memset(&am, 0, sizeof(am));
dbgi = get_irn_dbg_info(node);
block = be_transform_node(src_block);
- new_node = func(dbgi, irg, block, addr->base, addr->index, addr->mem);
+ new_mem = transform_AM_mem(irg, block, am.am_node, mem, addr->mem);
+ new_node = func(dbgi, irg, block, addr->base, addr->index, new_mem);
set_address(new_node, addr);
set_ia32_op_type(new_node, ia32_AddrModeD);
set_ia32_ls_mode(new_node, mode);
SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, node));
- set_transformed_and_mark(get_Proj_pred(am.mem_proj), new_node);
+ be_set_transformed_node(get_Proj_pred(am.mem_proj), new_node);
mem_proj = be_transform_node(am.mem_proj);
- set_transformed_and_mark(mem_proj ? mem_proj : am.mem_proj, new_node);
+ be_set_transformed_node(mem_proj ? mem_proj : am.mem_proj, new_node);
return new_node;
}
if(is_Conv(val)) {
ir_node *conv_op = get_Conv_op(val);
ir_mode *pred_mode = get_irn_mode(conv_op);
+ if (!ia32_mode_needs_gp_reg(pred_mode))
+ break;
if(pred_mode == mode_b || bits <= get_mode_size_bits(pred_mode)) {
val = conv_op;
continue;
case iro_Sub:
op1 = get_Sub_left(val);
op2 = get_Sub_right(val);
- if(is_Const(op2)) {
- ir_fprintf(stderr, "Optimisation warning: not-normalize sub ,C"
- "found\n");
+ if (is_Const(op2)) {
+ ir_fprintf(stderr, "Optimisation warning: not-normalized sub ,C found\n");
}
new_node = dest_am_binop(val, op1, op2, mem, ptr, mode,
new_rd_ia32_SubMem, new_rd_ia32_SubMem8Bit,
return new_node;
}
-static int is_float_to_int32_conv(const ir_node *node)
+static int is_float_to_int_conv(const ir_node *node)
{
ir_mode *mode = get_irn_mode(node);
ir_node *conv_op;
ir_mode *conv_mode;
- if(get_mode_size_bits(mode) != 32 || !ia32_mode_needs_gp_reg(mode))
- return 0;
- /* don't report unsigned as conv to 32bit, because we really need to do
- * a vfist with 64bit signed in this case */
- if(!mode_is_signed(mode))
+ if (mode != mode_Is && mode != mode_Hs)
return 0;
if(!is_Conv(node))
addr.index, addr.mem, new_val, mode);
}
store = new_node;
- } else if (!ia32_cg_config.use_sse2 && is_float_to_int32_conv(val)) {
+ } else if (!ia32_cg_config.use_sse2 && is_float_to_int_conv(val)) {
val = get_Conv_op(val);
/* TODO: is this optimisation still necessary at all (middleend)? */
}
/**
- * helper function: checks wether all Cmp projs are Lg or Eq which is needed
+ * helper function: checks whether all Cmp projs are Lg or Eq which is needed
* to fold an and into a test node
*/
-static int can_fold_test_and(ir_node *node)
+static bool can_fold_test_and(ir_node *node)
{
const ir_edge_t *edge;
ir_node *proj = get_edge_src_irn(edge);
pn_Cmp pnc = get_Proj_proj(proj);
if(pnc != pn_Cmp_Eq && pnc != pn_Cmp_Lg)
- return 0;
+ return false;
}
- return 1;
+ return true;
+}
+
+/**
+ * returns true if it is assured, that the upper bits of a node are "clean"
+ * which means for a 16 or 8 bit value, that the upper bits in the register
+ * are 0 for unsigned and a copy of the last significant bit for signed
+ * numbers.
+ */
+static bool upper_bits_clean(ir_node *transformed_node, ir_mode *mode)
+{
+ assert(ia32_mode_needs_gp_reg(mode));
+ if (get_mode_size_bits(mode) >= 32)
+ return true;
+
+ if (is_Proj(transformed_node))
+ return upper_bits_clean(get_Proj_pred(transformed_node), mode);
+
+ if (is_ia32_Conv_I2I(transformed_node)
+ || is_ia32_Conv_I2I8Bit(transformed_node)) {
+ ir_mode *smaller_mode = get_ia32_ls_mode(transformed_node);
+ if (mode_is_signed(smaller_mode) != mode_is_signed(mode))
+ return false;
+ if (get_mode_size_bits(smaller_mode) > get_mode_size_bits(mode))
+ return false;
+
+ return true;
+ }
+
+ if (is_ia32_Shr(transformed_node) && !mode_is_signed(mode)) {
+ ir_node *right = get_irn_n(transformed_node, n_ia32_Shr_count);
+ if (is_ia32_Immediate(right) || is_ia32_Const(right)) {
+ const ia32_immediate_attr_t *attr
+ = get_ia32_immediate_attr_const(right);
+ if (attr->symconst == 0
+ && (unsigned) attr->offset >= (32 - get_mode_size_bits(mode))) {
+ return true;
+ }
+ }
+ return upper_bits_clean(get_irn_n(transformed_node, n_ia32_Shr_val), mode);
+ }
+
+ if (is_ia32_And(transformed_node) && !mode_is_signed(mode)) {
+ ir_node *right = get_irn_n(transformed_node, n_ia32_And_right);
+ if (is_ia32_Immediate(right) || is_ia32_Const(right)) {
+ const ia32_immediate_attr_t *attr
+ = get_ia32_immediate_attr_const(right);
+ if (attr->symconst == 0
+ && (unsigned) attr->offset
+ <= (0xffffffff >> (32 - get_mode_size_bits(mode)))) {
+ return true;
+ }
+ }
+ /* TODO recurse? */
+ }
+
+ /* TODO recurse on Or, Xor, ... if appropriate? */
+
+ if (is_ia32_Immediate(transformed_node)
+ || is_ia32_Const(transformed_node)) {
+ const ia32_immediate_attr_t *attr
+ = get_ia32_immediate_attr_const(transformed_node);
+ if (mode_is_signed(mode)) {
+ long shifted = attr->offset >> (get_mode_size_bits(mode) - 1);
+ if (shifted == 0 || shifted == -1)
+ return true;
+ } else {
+ unsigned long shifted = (unsigned long) attr->offset;
+ shifted >>= get_mode_size_bits(mode);
+ if (shifted == 0)
+ return true;
+ }
+ }
+
+ return false;
}
/**
/* 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);
+
+ /* matze: code here used mode instead of cmd_mode, I think it is always
+ * the same as cmp_mode, but I leave this here to see if this is really
+ * true...
+ */
+ assert(get_irn_mode(and_left) == cmp_mode);
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) {
+
+ /* use 32bit compare mode if possible since the opcode is smaller */
+ if (upper_bits_clean(am.new_op1, cmp_mode) &&
+ upper_bits_clean(am.new_op2, cmp_mode)) {
+ cmp_mode = mode_is_signed(cmp_mode) ? mode_Is : mode_Iu;
+ }
+
+ 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_op1,
- am.new_op2, am.ins_permuted,
- cmp_unsigned);
+ 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);
+ addr->index, addr->mem, am.new_op1,
+ am.new_op2, am.ins_permuted,
+ cmp_unsigned);
}
} else {
/* Cmp(left, right) */
match_commutative | match_am | match_8bit_am |
match_16bit_am | match_am_and_immediates |
match_immediate | match_8bit | match_16bit);
+ /* use 32bit compare mode if possible since the opcode is smaller */
+ if (upper_bits_clean(am.new_op1, cmp_mode) &&
+ upper_bits_clean(am.new_op2, cmp_mode)) {
+ cmp_mode = mode_is_signed(cmp_mode) ? mode_Is : mode_Iu;
+ }
+
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_op1,
ir_node *new_node;
int src_bits;
- /* fild can use source AM if the operand is a signed 32bit integer */
- if (src_mode == mode_Is) {
+ /* fild can use source AM if the operand is a signed 16bit or 32bit integer */
+ if (src_mode == mode_Is || src_mode == mode_Hs) {
ia32_address_mode_t am;
match_arguments(&am, src_block, NULL, op, NULL,
- match_am | match_try_am);
+ match_am | match_try_am | match_16bit | match_16bit_am);
if (am.op_type == ia32_AddrModeS) {
ia32_address_t *addr = &am.addr;
match_arguments(&am, block, NULL, op, NULL,
match_8bit | match_16bit |
match_am | match_8bit_am | match_16bit_am);
+
+ if (upper_bits_clean(am.new_op2, smaller_mode)) {
+ /* unnecessary conv. in theory it shouldn't have been AM */
+ assert(is_ia32_NoReg_GP(addr->base));
+ assert(is_ia32_NoReg_GP(addr->index));
+ assert(is_NoMem(addr->mem));
+ assert(am.addr.offset == 0);
+ assert(am.addr.symconst_ent == NULL);
+ return am.new_op2;
+ }
+
if (smaller_bits == 8) {
new_node = new_rd_ia32_Conv_I2I8Bit(dbgi, irg, new_block, addr->base,
addr->index, addr->mem, am.new_op2,
switch (get_mode_size_bits(tgt_mode)) {
case 32: float_mantissa = 23 + 1; break; // + 1 for implicit 1
case 64: float_mantissa = 52 + 1; break;
- case 80: float_mantissa = 64 + 1; break;
+ case 80:
+ case 96: float_mantissa = 64; break;
default: float_mantissa = 0; break;
}
if (float_mantissa < int_mantissa) {
copy_node_attr(barrier, new_barrier);
be_duplicate_deps(barrier, new_barrier);
be_set_transformed_node(barrier, new_barrier);
- mark_irn_visited(barrier);
/* transform normally */
return be_duplicate_node(node);
ir_node *sz = get_irn_n(node, be_pos_AddSP_size);
ir_node *sp = get_irn_n(node, be_pos_AddSP_old_sp);
- return gen_binop(node, sp, sz, new_rd_ia32_SubSP, match_am);
+ return gen_binop(node, sp, sz, new_rd_ia32_SubSP,
+ match_am | match_immediate);
}
/**
ir_node *sz = get_irn_n(node, be_pos_SubSP_size);
ir_node *sp = get_irn_n(node, be_pos_SubSP_old_sp);
- return gen_binop(node, sp, sz, new_rd_ia32_AddSP, match_am);
+ return gen_binop(node, sp, sz, new_rd_ia32_AddSP,
+ match_am | match_immediate);
}
/**
copy_node_attr(node, phi);
be_duplicate_deps(node, phi);
- be_set_transformed_node(node, phi);
be_enqueue_preds(node);
return phi;
/* the shift amount can be any mode that is bigger than 5 bits, since all
* other bits are ignored anyway */
- while (is_Conv(count) && get_irn_n_edges(count) == 1) {
+ while (is_Conv(count) &&
+ get_irn_n_edges(count) == 1 &&
+ mode_is_int(get_irn_mode(count))) {
assert(get_mode_size_bits(get_irn_mode(count)) >= 5);
count = get_Conv_op(count);
}
return new_rd_Proj(dbgi, irg, block, new_pred, mode_M, pn_ia32_SubSP_M);
}
- assert(0);
- return new_rd_Unknown(irg, get_irn_mode(node));
+ panic("No idea how to transform proj->AddSP");
}
/**
return new_rd_Proj(dbgi, irg, block, new_pred, mode_M, pn_ia32_AddSP_M);
}
- assert(0);
- return new_rd_Unknown(irg, get_irn_mode(node));
+ panic("No idea how to transform proj->SubSP");
}
/**
return new_rd_Proj(dbgi, irg, block, new_pred, mode_M, 1);
}
- assert(0);
- return new_rd_Unknown(irg, get_irn_mode(node));
+ panic("No idea how to transform proj");
}
/**
ir_node *new_pred = be_transform_node(pred);
ir_graph *irg = current_ir_graph;
dbg_info *dbgi = get_irn_dbg_info(node);
- ir_mode *mode = get_irn_mode(node);
long proj = get_Proj_proj(node);
assert(is_ia32_Div(new_pred) || is_ia32_IDiv(new_pred));
break;
}
- assert(0);
- return new_rd_Unknown(irg, mode);
+ panic("No idea how to transform proj->DivMod");
}
/**
ir_node *new_pred = be_transform_node(pred);
ir_graph *irg = current_ir_graph;
dbg_info *dbgi = get_irn_dbg_info(node);
- ir_mode *mode = get_irn_mode(node);
long proj = get_Proj_proj(node);
switch(proj) {
break;
}
- assert(0);
- return new_rd_Unknown(irg, mode);
+ panic("No idea how to transform proj->CopyB");
}
/**
ir_node *new_pred = be_transform_node(pred);
ir_graph *irg = current_ir_graph;
dbg_info *dbgi = get_irn_dbg_info(node);
- ir_mode *mode = get_irn_mode(node);
long proj = get_Proj_proj(node);
switch(proj) {
break;
}
- assert(0);
- return new_rd_Unknown(irg, mode);
+ panic("No idea how to transform proj->Quot");
}
-static ir_node *gen_be_Call(ir_node *node) {
- ir_node *res = be_duplicate_node(node);
- ir_type *call_tp;
-
- be_node_add_flags(res, -1, arch_irn_flags_modify_flags);
+static ir_node *gen_be_Call(ir_node *node)
+{
+ dbg_info *const dbgi = get_irn_dbg_info(node);
+ ir_graph *const irg = current_ir_graph;
+ ir_node *const src_block = get_nodes_block(node);
+ ir_node *const block = be_transform_node(src_block);
+ ir_node *const src_mem = get_irn_n(node, be_pos_Call_mem);
+ ir_node *const src_sp = get_irn_n(node, be_pos_Call_sp);
+ ir_node *const sp = be_transform_node(src_sp);
+ ir_node *const src_ptr = get_irn_n(node, be_pos_Call_ptr);
+ ir_node *const noreg = ia32_new_NoReg_gp(env_cg);
+ ia32_address_mode_t am;
+ ia32_address_t *const addr = &am.addr;
+ ir_node * mem;
+ ir_node * call;
+ int i;
+ ir_node * fpcw;
+ ir_node * eax = noreg;
+ ir_node * ecx = noreg;
+ ir_node * edx = noreg;
+ unsigned const pop = be_Call_get_pop(node);
+ ir_type *const call_tp = be_Call_get_type(node);
/* Run the x87 simulator if the call returns a float value */
- call_tp = be_Call_get_type(node);
if (get_method_n_ress(call_tp) > 0) {
ir_type *const res_type = get_method_res_type(call_tp, 0);
ir_mode *const res_mode = get_type_mode(res_type);
}
}
- return res;
+ /* We do not want be_Call direct calls */
+ assert(be_Call_get_entity(node) == NULL);
+
+ match_arguments(&am, src_block, NULL, src_ptr, src_mem,
+ match_am | match_immediate);
+
+ i = get_irn_arity(node) - 1;
+ fpcw = be_transform_node(get_irn_n(node, i--));
+ for (; i >= be_pos_Call_first_arg; --i) {
+ arch_register_req_t const *const req =
+ arch_get_register_req(env_cg->arch_env, node, i);
+ ir_node *const reg_parm = be_transform_node(get_irn_n(node, i));
+
+ assert(req->type == arch_register_req_type_limited);
+ assert(req->cls == &ia32_reg_classes[CLASS_ia32_gp]);
+
+ switch (*req->limited) {
+ case 1 << REG_EAX: assert(eax == noreg); eax = reg_parm; break;
+ case 1 << REG_ECX: assert(ecx == noreg); ecx = reg_parm; break;
+ case 1 << REG_EDX: assert(edx == noreg); edx = reg_parm; break;
+ default: panic("Invalid GP register for register parameter");
+ }
+ }
+
+ mem = transform_AM_mem(irg, block, src_ptr, src_mem, addr->mem);
+ call = new_rd_ia32_Call(dbgi, irg, block, addr->base, addr->index, mem,
+ am.new_op2, sp, fpcw, eax, ecx, edx, pop, call_tp);
+ set_am_attributes(call, &am);
+ call = fix_mem_proj(call, &am);
+
+ if (get_irn_pinned(node) == op_pin_state_pinned)
+ set_irn_pinned(call, op_pin_state_pinned);
+
+ SET_IA32_ORIG_NODE(call, ia32_get_old_node_name(env_cg, node));
+ return call;
}
static ir_node *gen_be_IncSP(ir_node *node) {
/**
* Transform the Projs from a be_Call.
*/
-static ir_node *gen_Proj_be_Call(ir_node *node) {
+static ir_node *gen_Proj_be_Call(ir_node *node)
+{
ir_node *block = be_transform_node(get_nodes_block(node));
ir_node *call = get_Proj_pred(node);
ir_node *new_call = be_transform_node(call);
ir_mode *mode = get_irn_mode(node);
ir_node *sse_load;
const arch_register_class_t *cls;
+ ir_node *res;
/* The following is kinda tricky: If we're using SSE, then we have to
* move the result value of the call in floating point registers to an
call_res_pred = get_Proj_pred(call_res_new);
}
- if (call_res_pred == NULL || be_is_Call(call_res_pred)) {
+ if (call_res_pred == NULL || is_ia32_Call(call_res_pred)) {
return new_rd_Proj(dbgi, irg, block, new_call, mode_M,
- pn_be_Call_M_regular);
+ n_ia32_Call_mem);
} else {
assert(is_ia32_xLoad(call_res_pred));
return new_rd_Proj(dbgi, irg, block, call_res_pred, mode_M,
mode = cls->mode;
}
- return new_rd_Proj(dbgi, irg, block, new_call, mode, proj);
+ /* Map from be_Call to ia32_Call proj number */
+ if (proj == pn_be_Call_sp) {
+ proj = pn_ia32_Call_stack;
+ } else if (proj == pn_be_Call_M_regular) {
+ proj = pn_ia32_Call_M;
+ } else {
+ arch_register_req_t const *const req = arch_get_register_req(env_cg->arch_env, node, BE_OUT_POS(proj));
+ int const n_outs = get_ia32_n_res(new_call);
+ int i;
+
+ assert(proj >= pn_be_Call_first_res);
+ assert(req->type == arch_register_req_type_limited);
+
+ for (i = 0; i < n_outs; ++i) {
+ arch_register_req_t const *const new_req = get_ia32_out_req(new_call, i);
+
+ if (new_req->type != arch_register_req_type_limited ||
+ new_req->cls != req->cls ||
+ *new_req->limited != *req->limited)
+ continue;
+
+ proj = i;
+ break;
+ }
+ assert(i < n_outs);
+ }
+
+ res = new_rd_Proj(dbgi, irg, block, new_call, mode, proj);
+
+ /* TODO arch_set_irn_register() only operates on Projs, need variant with index */
+ switch (proj) {
+ case pn_ia32_Call_stack:
+ arch_set_irn_register(env_cg->arch_env, res, &ia32_gp_regs[REG_ESP]);
+ break;
+
+ case pn_ia32_Call_fpcw:
+ arch_set_irn_register(env_cg->arch_env, res, &ia32_fp_cw_regs[REG_FPCW]);
+ break;
+ }
+
+ return res;
}
/**
if (proj == pn_Store_M) {
return be_transform_node(pred);
} else {
- assert(0);
- return new_r_Bad(current_ir_graph);
+ panic("No idea how to transform proj->Store");
}
case iro_Load:
return gen_Proj_Load(node);
return gen_Proj_Bound(node);
case iro_Start:
proj = get_Proj_proj(node);
- if (proj == pn_Start_X_initial_exec) {
- ir_node *block = get_nodes_block(pred);
- dbg_info *dbgi = get_irn_dbg_info(node);
- ir_node *jump;
-
- /* we exchange the ProjX with a jump */
- block = be_transform_node(block);
- jump = new_rd_Jmp(dbgi, current_ir_graph, block);
- return jump;
- }
- if (node == be_get_old_anchor(anchor_tls)) {
- return gen_Proj_tls(node);
+ switch (proj) {
+ case pn_Start_X_initial_exec: {
+ ir_node *block = get_nodes_block(pred);
+ ir_node *new_block = be_transform_node(block);
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ /* we exchange the ProjX with a jump */
+ ir_node *jump = new_rd_Jmp(dbgi, current_ir_graph, new_block);
+
+ return jump;
+ }
+
+ case pn_Start_P_tls:
+ return gen_Proj_tls(node);
}
break;
/**
* Pre-transform all unknown and noreg nodes.
*/
-static void ia32_pretransform_node(void *arch_cg) {
- ia32_code_gen_t *cg = arch_cg;
+static void ia32_pretransform_node(void)
+{
+ ia32_code_gen_t *cg = env_cg;
cg->unknown_gp = be_pre_transform_node(cg->unknown_gp);
cg->unknown_vfp = be_pre_transform_node(cg->unknown_vfp);
assert(n_outs < (int) sizeof(unsigned) * 8);
foreach_out_edge(node, edge) {
ir_node *proj = get_edge_src_irn(edge);
- int pn = get_Proj_proj(proj);
+ int pn;
+
+ /* The node could be kept */
+ if (is_End(proj))
+ continue;
if (get_irn_mode(proj) == mode_M)
continue;
+ pn = get_Proj_proj(proj);
assert(pn < n_outs);
found_projs |= 1 << pn;
}
}
/* do the transformation */
-void ia32_transform_graph(ia32_code_gen_t *cg) {
+void ia32_transform_graph(ia32_code_gen_t *cg)
+{
int cse_last;
- ir_graph *irg = cg->irg;
register_transformers();
env_cg = cg;
initial_fpcw = NULL;
BE_TIMER_PUSH(t_heights);
- heights = heights_new(irg);
+ heights = heights_new(cg->irg);
BE_TIMER_POP(t_heights);
ia32_calculate_non_address_mode_nodes(cg->birg);
cse_last = get_opt_cse();
set_opt_cse(0);
- be_transform_graph(cg->birg, ia32_pretransform_node, cg);
+ be_transform_graph(cg->birg, ia32_pretransform_node);
set_opt_cse(cse_last);