* @brief This file implements the IR transformation from firm into
* ia32-Firm.
* @author Christian Wuerdig, Matthias Braun
- * @version $Id$
*/
#include "config.h"
{
ir_graph *irg = current_ir_graph;
- if (be_get_irg_options(irg)->pic) {
+ if (be_options.pic) {
const arch_env_t *arch_env = be_get_irg_arch_env(irg);
return arch_env->impl->get_pic_base(irg);
}
* input here, for unary operations use NULL).
*/
static int ia32_use_source_address_mode(ir_node *block, ir_node *node,
- ir_node *other, ir_node *other2, match_flags_t flags)
+ ir_node *other, ir_node *other2,
+ match_flags_t flags)
{
ir_node *load;
+ ir_mode *mode;
long pn;
/* float constants are always available */
if (is_Const(node)) {
- ir_mode *mode = get_irn_mode(node);
+ mode = get_irn_mode(node);
if (mode_is_float(mode)) {
+ ir_tarval *tv = get_Const_tarval(node);
+ if (!tarval_ieee754_can_conv_lossless(tv, mode_D))
+ return 0;
if (ia32_cg_config.use_sse2) {
if (is_simple_sse_Const(node))
return 0;
return 0;
return 1;
}
+ return 0;
}
if (!is_Proj(node))
return 0;
if (get_nodes_block(load) != block)
return 0;
+ mode = get_irn_mode(node);
+ /* we can't fold mode_E AM */
+ if (mode == ia32_mode_E)
+ return 0;
/* we only use address mode if we're the only user of the load */
if (get_irn_n_edges(node) != (flags & match_two_users ? 2 : 1))
return 0;
return initial_fpcw;
}
+static ir_node *skip_float_upconv(ir_node *node)
+{
+ ir_mode *mode = get_irn_mode(node);
+ assert(mode_is_float(mode));
+
+ while (is_Conv(node)) {
+ ir_node *pred = get_Conv_op(node);
+ ir_mode *pred_mode = get_irn_mode(pred);
+
+ /**
+ * suboptimal, but without this check the address mode matcher
+ * can incorrectly think that something has only 1 user
+ */
+ if (get_irn_n_edges(node) > 1)
+ break;
+
+ if (!mode_is_float(pred_mode)
+ || get_mode_size_bits(pred_mode) > get_mode_size_bits(mode))
+ break;
+ node = pred;
+ mode = pred_mode;
+ }
+ return node;
+}
+
/**
* Construct a standard binary operation, set AM and immediate if required.
*
static ir_node *gen_binop_x87_float(ir_node *node, ir_node *op1, ir_node *op2,
construct_binop_float_func *func)
{
- ir_mode *mode = get_irn_mode(node);
dbg_info *dbgi;
- ir_node *block, *new_block, *new_node;
+ ir_node *block;
+ ir_node *new_block;
+ ir_node *new_node;
ia32_address_mode_t am;
ia32_address_t *addr = &am.addr;
ia32_x87_attr_t *attr;
/* All operations are considered commutative, because there are reverse
* variants */
- match_flags_t flags = match_commutative;
-
- /* happens for div nodes... */
- if (mode == mode_T) {
- if (is_Div(node))
- mode = get_Div_resmode(node);
- else
- panic("can't determine mode");
- }
+ match_flags_t flags = match_commutative | match_am;
- /* cannot use address mode with long double on x87 */
- if (get_mode_size_bits(mode) <= 64)
- flags |= match_am;
+ op1 = skip_float_upconv(op1);
+ op2 = skip_float_upconv(op2);
block = get_nodes_block(node);
match_arguments(&am, block, op1, op2, NULL, flags);
ia32_mark_non_am(node);
- op2 = ia32_skip_downconv(op2);
- op1 = ia32_skip_downconv(op1);
-
/**
* Rules for an Add:
* 0. Immediate Trees (example Add(Symconst, Const) -> Const)
}
static ia32_condition_code_t relation_to_condition_code(ir_relation relation,
- ir_mode *mode)
+ ir_mode *mode,
+ bool overflow_possible)
{
if (mode_is_float(mode)) {
switch (relation) {
case ir_relation_unordered_equal:
case ir_relation_equal: return ia32_cc_equal;
case ir_relation_unordered_less:
- case ir_relation_less: return ia32_cc_less;
+ case ir_relation_less:
+ return overflow_possible ? ia32_cc_less : ia32_cc_sign;
case ir_relation_unordered_less_equal:
case ir_relation_less_equal: return ia32_cc_less_equal;
case ir_relation_unordered_greater:
case ir_relation_greater: return ia32_cc_greater;
case ir_relation_unordered_greater_equal:
- case ir_relation_greater_equal: return ia32_cc_greater_equal;
+ case ir_relation_greater_equal:
+ return overflow_possible ? ia32_cc_greater_equal : ia32_cc_not_sign;
case ir_relation_unordered_less_greater:
case ir_relation_less_greater: return ia32_cc_not_equal;
case ir_relation_less_equal_greater:
}
}
-static ir_node *get_flags_node_cmp(ir_node *cmp, ia32_condition_code_t *cc_out)
+static ir_node *get_flags_node(ir_node *cmp, ia32_condition_code_t *cc_out)
{
/* must have a Cmp as input */
ir_relation relation = get_Cmp_relation(cmp);
- ir_relation possible;
ir_node *l = get_Cmp_left(cmp);
ir_node *r = get_Cmp_right(cmp);
ir_mode *mode = get_irn_mode(l);
+ bool overflow_possible;
ir_node *flags;
/* check for bit-test */
- if (ia32_cg_config.use_bt && (relation == ir_relation_equal
- || (mode_is_signed(mode) && relation == ir_relation_less_greater)
- || (!mode_is_signed(mode) && ((relation & ir_relation_greater_equal) == ir_relation_greater)))
- && is_And(l)) {
+ if (ia32_cg_config.use_bt
+ && (relation == ir_relation_equal
+ || (mode_is_signed(mode) && relation == ir_relation_less_greater)
+ || (!mode_is_signed(mode) && ((relation & ir_relation_greater_equal) == ir_relation_greater)))
+ && is_And(l)) {
ir_node *la = get_And_left(l);
ir_node *ra = get_And_right(l);
if (is_Shl(ra)) {
if (is_Const_1(c) && is_Const_0(r)) {
/* (1 << n) & ra) */
ir_node *n = get_Shl_right(la);
- flags = gen_bt(cmp, ra, n);
+ flags = gen_bt(cmp, ra, n);
/* the bit is copied into the CF flag */
if (relation & ir_relation_equal)
*cc_out = ia32_cc_above_equal; /* test for CF=0 */
}
}
- /* the middle-end tries to eliminate impossible relations, so a ptr != 0
+ /* the middle-end tries to eliminate impossible relations, so a ptr <> 0
* test becomes ptr > 0. But for x86 an equal comparison is preferable to
* a >0 (we can sometimes eliminate the cmp in favor of flags produced by
- * a predecessor node). So add the < bit */
- possible = ir_get_possible_cmp_relations(l, r);
- if (((relation & ir_relation_less) && !(possible & ir_relation_greater))
- || ((relation & ir_relation_greater) && !(possible & ir_relation_less)))
- relation |= ir_relation_less_greater;
+ * a predecessor node). So add the < bit.
+ * (Note that we do not want to produce <=> (which can happen for
+ * unoptimized code), because no x86 flag can represent that */
+ if (!(relation & ir_relation_equal) && relation & ir_relation_less_greater)
+ relation |= get_negated_relation(ir_get_possible_cmp_relations(l, r)) & ir_relation_less_greater;
+
+ overflow_possible = true;
+ if (is_Const(r) && is_Const_null(r))
+ overflow_possible = false;
/* just do a normal transformation of the Cmp */
- *cc_out = relation_to_condition_code(relation, mode);
+ *cc_out = relation_to_condition_code(relation, mode, overflow_possible);
flags = be_transform_node(cmp);
return flags;
}
-/**
- * Transform a node returning a "flag" result.
- *
- * @param node the node to transform
- * @param cc_out the compare mode to use
- */
-static ir_node *get_flags_node(ir_node *node, ia32_condition_code_t *cc_out)
-{
- assert(is_Cmp(node));
- return get_flags_node_cmp(node, cc_out);
-}
-
/**
* Transforms a Load.
*
*
* @return the created ia32 SwitchJmp node
*/
-static ir_node *create_Switch(ir_node *node)
-{
- dbg_info *dbgi = get_irn_dbg_info(node);
- ir_node *block = be_transform_node(get_nodes_block(node));
- ir_node *sel = get_Cond_selector(node);
- ir_node *new_sel = be_transform_node(sel);
- long default_pn = get_Cond_default_proj(node);
- ir_node *new_node;
- ir_entity *entity;
-
- assert(get_mode_size_bits(get_irn_mode(sel)) == 32);
+static ir_node *gen_Switch(ir_node *node)
+{
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_graph *irg = get_irn_irg(node);
+ ir_node *block = be_transform_node(get_nodes_block(node));
+ ir_node *sel = get_Switch_selector(node);
+ ir_node *new_sel = be_transform_node(sel);
+ ir_mode *sel_mode = get_irn_mode(sel);
+ const ir_switch_table *table = get_Switch_table(node);
+ unsigned n_outs = get_Switch_n_outs(node);
+ ir_node *new_node;
+ ir_entity *entity;
+
+ assert(get_mode_size_bits(get_irn_mode(sel)) <= 32);
+ if (get_mode_size_bits(sel_mode) != 32)
+ new_sel = create_upconv(new_sel, sel);
entity = new_entity(NULL, id_unique("TBL%u"), get_unknown_type());
set_entity_visibility(entity, ir_visibility_private);
add_entity_linkage(entity, IR_LINKAGE_CONSTANT);
- /* TODO: we could perform some more matching here to also use the base
- * register of the address mode */
- new_node
- = new_bd_ia32_SwitchJmp(dbgi, block, noreg_GP, new_sel, default_pn);
+ table = ir_switch_table_duplicate(irg, table);
+
+ new_node = new_bd_ia32_SwitchJmp(dbgi, block, noreg_GP, new_sel, n_outs, table);
set_ia32_am_scale(new_node, 2);
set_ia32_am_sc(new_node, entity);
set_ia32_op_type(new_node, ia32_AddrModeS);
ir_node *new_block = be_transform_node(block);
dbg_info *dbgi = get_irn_dbg_info(node);
ir_node *sel = get_Cond_selector(node);
- ir_mode *sel_mode = get_irn_mode(sel);
ir_node *flags = NULL;
ir_node *new_node;
ia32_condition_code_t cc;
- if (sel_mode != mode_b) {
- return create_Switch(node);
- }
-
/* we get flags from a Cmp */
flags = get_flags_node(sel, &cc);
set_ia32_commutative(new_node);
SET_IA32_ORIG_NODE(new_node, node);
} else {
- if (ia32_cg_config.use_ftst && is_Const_0(right)) {
+ if (is_Const_0(right)) {
new_node = new_bd_ia32_vFtstFnstsw(dbgi, new_block, new_left, 0);
} else {
new_right = be_transform_node(right);
new_node = new_bd_ia32_vFucomFnstsw(dbgi, new_block, new_left, new_right, 0);
+ set_ia32_commutative(new_node);
}
- set_ia32_commutative(new_node);
-
SET_IA32_ORIG_NODE(new_node, node);
new_node = new_bd_ia32_Sahf(dbgi, new_block, new_node);
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_commutative |
+ match_am | match_8bit_am | match_16bit_am |
+ match_am_and_immediates | match_immediate);
/* use 32bit compare mode if possible since the opcode is smaller */
if (upper_bits_clean(am.new_op1, cmp_mode) &&
if (get_mode_size_bits(cmp_mode) == 8) {
new_node = new_bd_ia32_Test8Bit(dbgi, new_block, addr->base,
- addr->index, addr->mem, am.new_op1, am.new_op2, am.ins_permuted);
+ addr->index, addr->mem,
+ am.new_op1, am.new_op2,
+ am.ins_permuted);
} else {
- new_node = new_bd_ia32_Test(dbgi, new_block, addr->base, addr->index,
- addr->mem, am.new_op1, am.new_op2, am.ins_permuted);
+ new_node = new_bd_ia32_Test(dbgi, new_block, addr->base,
+ addr->index, addr->mem, am.new_op1,
+ am.new_op2, am.ins_permuted);
}
} else {
/* Cmp(left, right) */
am.new_op2, am.ins_permuted);
} else {
new_node = new_bd_ia32_Cmp(dbgi, new_block, addr->base, addr->index,
- addr->mem, am.new_op1, am.new_op2, am.ins_permuted);
+ addr->mem, am.new_op1, am.new_op2,
+ am.ins_permuted);
}
}
set_am_attributes(new_node, &am);
dbgi = get_irn_dbg_info(psi);
sbb = new_bd_ia32_Sbb0(dbgi, block, eflags);
+ set_ia32_ls_mode(sbb, mode_Iu);
notn = new_bd_ia32_Not(dbgi, block, sbb);
new_node = new_bd_ia32_And(dbgi, block, noreg_GP, noreg_GP, nomem, new_node, notn);
+ set_ia32_ls_mode(new_node, mode_Iu);
set_ia32_commutative(new_node);
return new_node;
}
/* special case for PIC trampoline calls */
old_no_pic_adjust = ia32_no_pic_adjust;
- ia32_no_pic_adjust = be_get_irg_options(current_ir_graph)->pic;
+ ia32_no_pic_adjust = be_options.pic;
match_arguments(&am, src_block, NULL, src_ptr, src_mem,
match_am | match_immediate);
/* or */
orn = new_bd_ia32_Or(dbgi, block, noreg_GP, noreg_GP, nomem, bsf, neg);
+ set_ia32_ls_mode(orn, mode_Iu);
set_ia32_commutative(orn);
/* add 1 */
ir_node *xor2 = new_bd_ia32_XorHighLow(dbgi, new_block, xor);
ir_node *flags;
+ set_ia32_ls_mode(xor, mode_Iu);
set_ia32_commutative(xor);
set_irn_mode(xor2, mode_T);
ir_node *new_block = be_transform_node(block);
ir_mode *mode = get_irn_mode(param);
unsigned size = get_mode_size_bits(mode);
- ir_node *m1, *m2, *m3, *m4, *s1, *s2, *s3, *s4;
switch (size) {
case 32:
- if (ia32_cg_config.use_i486) {
+ if (ia32_cg_config.use_bswap) {
/* swap available */
return new_bd_ia32_Bswap(dbgi, new_block, param);
+ } else {
+ ir_node *i8 = ia32_create_Immediate(NULL, 0, 8);
+ ir_node *rol1 = new_bd_ia32_Rol(dbgi, new_block, param, i8);
+ ir_node *i16 = ia32_create_Immediate(NULL, 0, 16);
+ ir_node *rol2 = new_bd_ia32_Rol(dbgi, new_block, rol1, i16);
+ ir_node *rol3 = new_bd_ia32_Rol(dbgi, new_block, rol2, i8);
+ set_ia32_ls_mode(rol1, mode_Hu);
+ set_ia32_ls_mode(rol2, mode_Iu);
+ set_ia32_ls_mode(rol3, mode_Hu);
+ return rol3;
}
- s1 = new_bd_ia32_Shl(dbgi, new_block, param, ia32_create_Immediate(NULL, 0, 24));
- s2 = new_bd_ia32_Shl(dbgi, new_block, param, ia32_create_Immediate(NULL, 0, 8));
-
- m1 = new_bd_ia32_And(dbgi, new_block, noreg_GP, noreg_GP, nomem, s2, ia32_create_Immediate(NULL, 0, 0xFF00));
- m2 = new_bd_ia32_Lea(dbgi, new_block, s1, m1);
-
- s3 = new_bd_ia32_Shr(dbgi, new_block, param, ia32_create_Immediate(NULL, 0, 8));
-
- m3 = new_bd_ia32_And(dbgi, new_block, noreg_GP, noreg_GP, nomem, s3, ia32_create_Immediate(NULL, 0, 0xFF0000));
- m4 = new_bd_ia32_Lea(dbgi, new_block, m2, m3);
-
- s4 = new_bd_ia32_Shr(dbgi, new_block, param, ia32_create_Immediate(NULL, 0, 24));
- return new_bd_ia32_Lea(dbgi, new_block, m4, s4);
case 16:
/* swap16 always available */
case ir_bk_parity:
case ir_bk_popcount:
case ir_bk_bswap:
- assert(get_Proj_proj(proj) == pn_Builtin_1_result);
+ assert(get_Proj_proj(proj) == pn_Builtin_max+1);
return new_node;
case ir_bk_trap:
case ir_bk_debugbreak:
assert(get_Proj_proj(proj) == pn_Builtin_M);
return new_node;
case ir_bk_inport:
- if (get_Proj_proj(proj) == pn_Builtin_1_result) {
+ if (get_Proj_proj(proj) == pn_Builtin_max+1) {
return new_r_Proj(new_node, get_irn_mode(proj), pn_ia32_Inport_res);
} else {
assert(get_Proj_proj(proj) == pn_Builtin_M);
return new_r_Proj(new_node, mode_M, pn_ia32_Inport_M);
}
case ir_bk_inner_trampoline:
- if (get_Proj_proj(proj) == pn_Builtin_1_result) {
+ if (get_Proj_proj(proj) == pn_Builtin_max+1) {
return get_Tuple_pred(new_node, 1);
} else {
assert(get_Proj_proj(proj) == pn_Builtin_M);
be_set_transform_function(op_Shrs, gen_Shrs);
be_set_transform_function(op_Store, gen_Store);
be_set_transform_function(op_Sub, gen_Sub);
+ be_set_transform_function(op_Switch, gen_Switch);
be_set_transform_function(op_SymConst, gen_SymConst);
be_set_transform_function(op_Unknown, ia32_gen_Unknown);
}