ia32_perform_memory_operand,
};
-ia32_irn_ops_t ia32_irn_ops = {
+static ia32_irn_ops_t ia32_irn_ops = {
&ia32_irn_ops_if,
NULL
};
**************************************************/
static void ia32_before_abi(void *self) {
+ lower_mode_b_config_t lower_mode_b_config = {
+ mode_Iu, /* lowered mode */
+ mode_Bu, /* prefered mode for set */
+ 0, /* don't lower direct compares */
+ };
ia32_code_gen_t *cg = self;
- ir_lower_mode_b(cg->irg, mode_Iu, 0);
+ ir_lower_mode_b(cg->irg, &lower_mode_b_config);
if(cg->dump)
be_dump(cg->irg, "-lower_modeb", dump_ir_block_graph_sched);
}
}
}
+static void emit_ia32_IMul(const ir_node *node)
+{
+ ir_node *left = get_irn_n(node, n_ia32_IMul_left);
+ const arch_register_t *out_reg = get_out_reg(node, pn_ia32_IMul_res);
+
+ be_emit_cstring("\timul");
+ ia32_emit_mode_suffix(node);
+ be_emit_char(' ');
+
+ ia32_emit_binop(node);
+
+ /* do we need the 3-address form? */
+ if(is_ia32_NoReg_GP(left) ||
+ get_in_reg(node, n_ia32_IMul_left) != out_reg) {
+ be_emit_cstring(", ");
+ emit_register(out_reg, get_ia32_ls_mode(node));
+ }
+ be_emit_finish_line_gas(node);
+}
+
/*************************************************
* _ _ _
* (_) | | |
/* other ia32 emitter functions */
IA32_EMIT(Asm);
IA32_EMIT(CMov);
+ IA32_EMIT(IMul);
IA32_EMIT(SwitchJmp);
IA32_EMIT(CopyB);
IA32_EMIT(CopyB_i);
}
static INLINE int need_constraint_copy(ir_node *irn) {
+ /* the 3 operand form of IMul needs no constraint copy */
+ if(is_ia32_IMul(irn)) {
+ ir_node *right = get_irn_n(irn, n_ia32_IMul_right);
+ if(is_ia32_Immediate(right))
+ return 0;
+ }
+
return ! is_ia32_Lea(irn) &&
! is_ia32_Conv_I2I(irn) &&
! is_ia32_Conv_I2I8Bit(irn) &&
const ia32_attr_t *attr = get_ia32_attr_const(node);
const ia32_immediate_attr_t *imm_attr = CONST_CAST_IA32_ATTR(ia32_immediate_attr_t, attr);
- assert(is_ia32_Immediate(node) || is_ia32_Const(node));
return imm_attr;
}
ia32_attr_t *attr = get_ia32_attr(node);
ia32_condcode_attr_t *cc_attr = CAST_IA32_ATTR(ia32_condcode_attr_t, attr);
- assert(is_ia32_SwitchJmp(node) || is_ia32_CMov(node) || is_ia32_Set(node) || is_ia32_Jcc(node));
return cc_attr;
}
const ia32_attr_t *attr = get_ia32_attr_const(node);
const ia32_condcode_attr_t *cc_attr = CONST_CAST_IA32_ATTR(ia32_condcode_attr_t, attr);
- assert(is_ia32_SwitchJmp(node) || is_ia32_CMov(node) || is_ia32_Set(node) || is_ia32_Jcc(node));
return cc_attr;
}
ia32_attr_t *attr = get_ia32_attr(node);
ia32_copyb_attr_t *copyb_attr = CAST_IA32_ATTR(ia32_copyb_attr_t, attr);
- assert(is_ia32_CopyB(node) || is_ia32_CopyB_i(node));
return copyb_attr;
}
const ia32_attr_t *attr = get_ia32_attr_const(node);
const ia32_copyb_attr_t *copyb_attr = CONST_CAST_IA32_ATTR(ia32_copyb_attr_t, attr);
- assert(is_ia32_CopyB(node) || is_ia32_CopyB_i(node));
return copyb_attr;
}
#include "height.h"
#include "irbitset.h"
#include "irprintf.h"
+#include "error.h"
#include "../be_t.h"
#include "../beabi.h"
static const arch_env_t *arch_env;
static ia32_code_gen_t *cg;
-typedef int is_op_func_t(const ir_node *n);
-typedef ir_node *load_func_t(dbg_info *db, ir_graph *irg, ir_node *block, ir_node *base, ir_node *index, ir_node *mem);
+static void peephole_IncSP_IncSP(ir_node *node);
-/**
- * checks if a node represents the NOREG value
- */
-static INLINE int be_is_NoReg(ia32_code_gen_t *cg, const ir_node *irn) {
- return irn == cg->noreg_gp || irn == cg->noreg_xmm || irn == cg->noreg_vfp;
-}
+#if 0
+static void peephole_ia32_Store_IncSP_to_push(ir_node *node)
+{
+ ir_node *base = get_irn_n(node, n_ia32_Store_base);
+ ir_node *index = get_irn_n(node, n_ia32_Store_index);
+ ir_node *mem = get_irn_n(node, n_ia32_Store_mem);
+ ir_node *incsp = base;
+ ir_node *val;
+ ir_node *noreg;
+ ir_graph *irg;
+ ir_node *block;
+ dbg_info *dbgi;
+ ir_mode *mode;
+ ir_node *push;
+ ir_node *proj;
+ int offset;
+ int node_offset;
+
+ /* nomem inidicates the store doesn't alias with anything else */
+ if(!is_NoMem(mem))
+ return;
-/********************************************************************************************************
- * _____ _ _ ____ _ _ _ _ _
- * | __ \ | | | | / __ \ | | (_) (_) | | (_)
- * | |__) |__ ___ _ __ | |__ ___ | | ___ | | | |_ __ | |_ _ _ __ ___ _ ______ _| |_ _ ___ _ __
- * | ___/ _ \/ _ \ '_ \| '_ \ / _ \| |/ _ \ | | | | '_ \| __| | '_ ` _ \| |_ / _` | __| |/ _ \| '_ \
- * | | | __/ __/ |_) | | | | (_) | | __/ | |__| | |_) | |_| | | | | | | |/ / (_| | |_| | (_) | | | |
- * |_| \___|\___| .__/|_| |_|\___/|_|\___| \____/| .__/ \__|_|_| |_| |_|_/___\__,_|\__|_|\___/|_| |_|
- * | | | |
- * |_| |_|
- ********************************************************************************************************/
+ /* find an IncSP in front of us, we might have to skip barriers for this */
+ while(is_Proj(incsp)) {
+ ir_node *proj_pred = get_Proj_pred(incsp);
+ if(!be_is_Barrier(proj_pred))
+ return;
+ incsp = get_irn_n(proj_pred, get_Proj_proj(incsp));
+ }
+ if(!be_is_IncSP(incsp))
+ return;
-/**
- * NOTE: THESE PEEPHOLE OPTIMIZATIONS MUST BE CALLED AFTER SCHEDULING AND REGISTER ALLOCATION.
- */
+ peephole_IncSP_IncSP(incsp);
+
+ /* must be in the same block */
+ if(get_nodes_block(incsp) != get_nodes_block(node))
+ return;
+
+ if(!is_ia32_NoReg_GP(index) || get_ia32_am_sc(node) != NULL) {
+ panic("Invalid storeAM found (%+F)", node);
+ }
+
+ /* we should be the store to the end of the stackspace */
+ offset = be_get_IncSP_offset(incsp);
+ mode = get_ia32_ls_mode(node);
+ node_offset = get_ia32_am_offs_int(node);
+ if(node_offset != offset - get_mode_size_bytes(mode))
+ return;
+
+ /* we can use a push instead of the store */
+ irg = current_ir_graph;
+ block = get_nodes_block(node);
+ dbgi = get_irn_dbg_info(node);
+ noreg = ia32_new_NoReg_gp(cg);
+ base = be_get_IncSP_pred(incsp);
+ val = get_irn_n(node, n_ia32_Store_val);
+ push = new_rd_ia32_Push(dbgi, irg, block, noreg, noreg, mem, base, val);
+
+ proj = new_r_Proj(irg, block, push, mode_M, pn_ia32_Push_M);
+
+ be_set_IncSP_offset(incsp, offset - get_mode_size_bytes(mode));
+
+ sched_add_before(node, push);
+ sched_remove(node);
+
+ be_peephole_node_replaced(node, proj);
+ exchange(node, proj);
+}
+
+static void peephole_ia32_Store(ir_node *node)
+{
+ peephole_ia32_Store_IncSP_to_push(node);
+}
+#endif
// only optimize up to 48 stores behind IncSPs
#define MAXPUSH_OPTIMIZE 48
push = new_rd_ia32_Push(get_irn_dbg_info(store), irg, block, noreg, noreg, mem, curr_sp, val);
- set_ia32_am_support(push, ia32_am_Source, ia32_am_unary);
-
sched_add_before(irn, push);
// create stackpointer proj
/* register peephole optimisations */
clear_irp_opcodes_generic_func();
register_peephole_optimisation(op_ia32_Const, peephole_ia32_Const);
+ //register_peephole_optimisation(op_ia32_Store, peephole_ia32_Store);
register_peephole_optimisation(op_be_IncSP, peephole_be_IncSP);
register_peephole_optimisation(op_ia32_Lea, peephole_ia32_Lea);
static void optimize_conv_store(ir_node *node)
{
ir_node *pred;
+ ir_node *pred_proj;
ir_mode *conv_mode;
ir_mode *store_mode;
if(!is_ia32_Store(node) && !is_ia32_Store8Bit(node))
return;
- pred = get_irn_n(node, 2);
+ assert(n_ia32_Store_val == n_ia32_Store8Bit_val);
+ pred_proj = get_irn_n(node, n_ia32_Store_val);
+ if(is_Proj(pred_proj)) {
+ pred = get_Proj_pred(pred_proj);
+ } else {
+ pred = pred_proj;
+ }
if(!is_ia32_Conv_I2I(pred) && !is_ia32_Conv_I2I8Bit(pred))
return;
+ if(get_ia32_op_type(pred) != ia32_Normal)
+ return;
/* the store only stores the lower bits, so we only need the conv
* it it shrinks the mode */
if(get_mode_size_bits(conv_mode) < get_mode_size_bits(store_mode))
return;
- set_irn_n(node, 2, get_irn_n(pred, 2));
- if(get_irn_n_edges(pred) == 0) {
- be_kill_node(pred);
+ set_irn_n(node, n_ia32_Store_val, get_irn_n(pred, n_ia32_Conv_I2I_val));
+ if(get_irn_n_edges(pred_proj) == 0) {
+ be_kill_node(pred_proj);
+ if(pred != pred_proj)
+ be_kill_node(pred);
}
}
if (!is_ia32_Conv_I2I(node) && !is_ia32_Conv_I2I8Bit(node))
return;
- pred = get_irn_n(node, 2);
+ assert(n_ia32_Conv_I2I_val == n_ia32_Conv_I2I8Bit_val);
+ pred = get_irn_n(node, n_ia32_Conv_I2I_val);
if(!is_Proj(pred))
return;
/* kill the conv */
exchange(node, result_conv);
- if(get_irn_n_edges(pred) == 0) {
- be_kill_node(pred);
+ if(get_irn_n_edges(pred_proj) == 0) {
+ be_kill_node(pred_proj);
+ if(pred != pred_proj)
+ be_kill_node(pred);
}
optimize_conv_conv(result_conv);
}
binop => "${arch}_emit_binop(node);",
x87_binop => "${arch}_emit_x87_binop(node);",
CMP0 => "${arch}_emit_cmp_suffix_node(node, 0);",
+ CMP3 => "${arch}_emit_cmp_suffix_node(node, 3);",
);
#--------------------------------------------------#
IMul => {
irn_flags => "R",
state => "exc_pinned",
- reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "in_r4 in_r5" ] },
+ # TODO: adjust out requirements for the 3 operand form
+ # (no need for should_be_same then)
+ reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ],
+ out => [ "in_r4 in_r5", "none", "flags" ] },
ins => [ "base", "index", "mem", "left", "right" ],
- emit => '. imul%M %binop',
+ outs => [ "res", "M", "flags" ],
am => "source,binary",
latency => 5,
units => [ "GP" ],
mode => $mode_gp,
},
+SetMem => {
+ #irn_flags => "R",
+ state => "exc_pinned",
+ reg_req => { in => [ "gp", "gp", "none", "eflags" ], out => [ "none" ] },
+ ins => [ "base", "index", "mem","eflags" ],
+ attr_type => "ia32_condcode_attr_t",
+ attr => "pn_Cmp pnc, int ins_permuted",
+ init_attr => "attr->attr.data.ins_permuted = ins_permuted;\n".
+ "\tset_ia32_ls_mode(res, mode_Bu);\n",
+ emit => '. set%CMP3 %AM',
+ latency => 1,
+ units => [ "GP" ],
+ mode => 'mode_M',
+},
+
CMov => {
#irn_flags => "R",
# (note: leave the false,true order intact to make it compatible with other
ir_node *new_op1;
ir_node *new_op2;
op_pin_state pinned;
- unsigned commutative:1;
- unsigned ins_permuted:1;
+ unsigned commutative : 1;
+ unsigned ins_permuted : 1;
};
+static void build_address_ptr(ia32_address_t *addr, ir_node *ptr, ir_node *mem)
+{
+ ir_node *noreg_gp = ia32_new_NoReg_gp(env_cg);
+
+ /* construct load address */
+ memset(addr, 0, sizeof(addr[0]));
+ ia32_create_address_mode(addr, ptr, /*force=*/0);
+
+ if(addr->base == NULL) {
+ addr->base = noreg_gp;
+ } else {
+ addr->base = be_transform_node(addr->base);
+ }
+
+ if(addr->index == NULL) {
+ addr->index = noreg_gp;
+ } else {
+ addr->index = be_transform_node(addr->index);
+ }
+ addr->mem = be_transform_node(mem);
+}
+
static void build_address(ia32_address_mode_t *am, ir_node *node)
{
ir_node *noreg_gp = ia32_new_NoReg_gp(env_cg);
constraints
*/
return gen_binop(node, op1, op2, new_rd_ia32_IMul,
- match_commutative | match_am | match_mode_neutral);
+ match_commutative | match_am | match_mode_neutral |
+ match_immediate | match_am_and_immediates);
}
/**
return new_node;
}
+static ir_node *get_flags_node(ir_node *node, pn_Cmp *pnc_out)
+{
+ ir_graph *irg = current_ir_graph;
+ ir_node *flags;
+ ir_node *new_op;
+ ir_node *noreg;
+ ir_node *nomem;
+ ir_node *new_block;
+ dbg_info *dbgi;
+
+ /* we have a Cmp as input */
+ if(is_Proj(node)) {
+ ir_node *pred = get_Proj_pred(node);
+ if(is_Cmp(pred)) {
+ flags = be_transform_node(pred);
+ *pnc_out = get_Proj_proj(node);
+ return flags;
+ }
+ }
+
+ /* a mode_b value, we have to compare it against 0 */
+ dbgi = get_irn_dbg_info(node);
+ new_block = be_transform_node(get_nodes_block(node));
+ new_op = be_transform_node(node);
+ noreg = ia32_new_NoReg_gp(env_cg);
+ nomem = new_NoMem();
+ flags = new_rd_ia32_Test(dbgi, irg, new_block, noreg, noreg, nomem,
+ new_op, new_op, 0, 0);
+ *pnc_out = pn_Cmp_Lg;
+ return flags;
+}
+
/**
* Transforms a Load.
*
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_node *noreg_gp = ia32_new_NoReg_gp(env_cg);
- ir_graph *irg = current_ir_graph;
dbg_info *dbgi;
ir_node *new_node;
ia32_address_mode_t am;
build_address(&am, op);
- if(addr->base == NULL)
- addr->base = noreg_gp;
- if(addr->index == NULL)
- addr->index = noreg_gp;
- if(addr->mem == NULL)
- addr->mem = new_NoMem();
-
dbgi = get_irn_dbg_info(node);
block = be_transform_node(src_block);
new_node = func(dbgi, irg, block, addr->base, addr->index, addr->mem);
return new_node;
}
+static ir_node *try_create_SetMem(ir_node *node, ir_node *ptr, ir_node *mem) {
+ ir_mode *mode = get_irn_mode(node);
+ ir_node *psi_true = get_Psi_val(node, 0);
+ ir_node *psi_default = get_Psi_default(node);
+ ir_graph *irg;
+ ir_node *cond;
+ ir_node *new_mem;
+ dbg_info *dbgi;
+ ir_node *block;
+ ir_node *new_block;
+ ir_node *flags;
+ ir_node *new_node;
+ int negated;
+ pn_Cmp pnc;
+ ia32_address_t addr;
+
+ if(get_mode_size_bits(mode) != 8)
+ return NULL;
+
+ if(is_Const_1(psi_true) && is_Const_0(psi_default)) {
+ negated = 0;
+ } else if(is_Const_0(psi_true) && is_Const_1(psi_default)) {
+ negated = 1;
+ } else {
+ return NULL;
+ }
+
+ build_address_ptr(&addr, ptr, mem);
+
+ irg = current_ir_graph;
+ dbgi = get_irn_dbg_info(node);
+ block = get_nodes_block(node);
+ new_block = be_transform_node(block);
+ cond = get_Psi_cond(node, 0);
+ flags = get_flags_node(cond, &pnc);
+ new_mem = be_transform_node(mem);
+ new_node = new_rd_ia32_SetMem(dbgi, irg, new_block, addr.base,
+ addr.index, addr.mem, flags, pnc, negated);
+ 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));
+
+ return new_node;
+}
+
static ir_node *try_create_dest_am(ir_node *node) {
ir_node *val = get_Store_value(node);
ir_node *mem = get_Store_mem(node);
ir_node *ptr = get_Store_ptr(node);
ir_mode *mode = get_irn_mode(val);
+ int bits = get_mode_size_bits(mode);
ir_node *op1;
ir_node *op2;
ir_node *new_node;
if(!mode_needs_gp_reg(mode))
return NULL;
- /* store must be the only user of the val node */
- if(get_irn_n_edges(val) > 1)
+ while(1) {
+ /* store must be the only user of the val node */
+ if(get_irn_n_edges(val) > 1)
+ return NULL;
+ /* skip pointless convs */
+ if(is_Conv(val)) {
+ ir_node *conv_op = get_Conv_op(val);
+ ir_mode *pred_mode = get_irn_mode(conv_op);
+ if(pred_mode == mode_b || bits <= get_mode_size_bits(pred_mode)) {
+ val = conv_op;
+ continue;
+ }
+ }
+ break;
+ }
+
+ /* value must be in the same block */
+ if(get_nodes_block(node) != get_nodes_block(val))
return NULL;
switch(get_irn_opcode(val)) {
match_dest_am | match_immediate);
break;
/* TODO: match ROR patterns... */
+ case iro_Psi:
+ new_node = try_create_SetMem(val, ptr, mem);
+ break;
case iro_Minus:
op1 = get_Minus_op(val);
new_node = dest_am_unop(val, op1, mem, ptr, mode, new_rd_ia32_NegMem);
return NULL;
}
+ if(new_node != NULL) {
+ if(get_irn_pinned(new_node) != op_pin_state_pinned &&
+ get_irn_pinned(node) == op_pin_state_pinned) {
+ set_irn_pinned(new_node, op_pin_state_pinned);
+ }
+ }
+
return new_node;
}
return new_node;
}
-static ir_node *get_flags_node(ir_node *node, pn_Cmp *pnc_out)
-{
- ir_graph *irg = current_ir_graph;
- ir_node *flags;
- ir_node *new_op;
- ir_node *noreg;
- ir_node *nomem;
- ir_node *new_block;
- dbg_info *dbgi;
-
- /* we have a Cmp as input */
- if(is_Proj(node)) {
- ir_node *pred = get_Proj_pred(node);
- if(is_Cmp(pred)) {
- flags = be_transform_node(pred);
- *pnc_out = get_Proj_proj(node);
- return flags;
- }
- }
-
- /* a mode_b value, we have to compare it against 0 */
- dbgi = get_irn_dbg_info(node);
- new_block = be_transform_node(get_nodes_block(node));
- new_op = be_transform_node(node);
- noreg = ia32_new_NoReg_gp(env_cg);
- nomem = new_NoMem();
- flags = new_rd_ia32_Test(dbgi, irg, new_block, noreg, noreg, nomem,
- new_op, new_op, 0, 0);
- *pnc_out = pn_Cmp_Lg;
- return flags;
-}
-
static ir_node *gen_Cond(ir_node *node) {
ir_node *block = get_nodes_block(node);
ir_node *new_block = be_transform_node(block);
ir_graph *irg = current_ir_graph;
ir_node *noreg = ia32_new_NoReg_gp(env_cg);
ir_node *nomem = new_NoMem();
+ ir_mode *mode = get_irn_mode(orig_node);
ir_node *new_node;
new_node = new_rd_ia32_Set(dbgi, irg, new_block, flags, pnc, ins_permuted);
SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, orig_node));
- new_node = new_rd_ia32_Conv_I2I8Bit(dbgi, irg, new_block, noreg, noreg,
- nomem, new_node, mode_Bu);
- SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, orig_node));
- (void) orig_node;
+
+ /* we might need to conv the result up */
+ if(get_mode_size_bits(mode) > 8) {
+ new_node = new_rd_ia32_Conv_I2I8Bit(dbgi, irg, new_block, noreg, noreg,
+ nomem, new_node, mode_Bu);
+ SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, orig_node));
+ }
return new_node;
}
*/
static ir_node *gen_Proj_Cmp(ir_node *node)
{
+ (void) node;
+ panic("not all mode_b nodes are lowered");
+
+#if 0
/* normally Cmps are processed when looking at Cond nodes, but this case
* can happen in complicated Psi conditions */
dbg_info *dbgi = get_irn_dbg_info(node);
res = create_set_32bit(dbgi, new_block, new_cmp, pnc, node, 0);
return res;
+#endif
}
/**