+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);
+ unsigned bits = get_mode_size_bits(mode);
+ ir_node *op1;
+ ir_node *op2;
+ ir_node *new_node;
+
+ /* handle only GP modes for now... */
+ if(!ia32_mode_needs_gp_reg(mode))
+ return NULL;
+
+ 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 (!ia32_mode_needs_gp_reg(pred_mode))
+ break;
+ 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)) {
+ case iro_Add:
+ op1 = get_Add_left(val);
+ op2 = get_Add_right(val);
+ if(is_Const_1(op2)) {
+ new_node = dest_am_unop(val, op1, mem, ptr, mode,
+ new_rd_ia32_IncMem);
+ break;
+ } else if(is_Const_Minus_1(op2)) {
+ new_node = dest_am_unop(val, op1, mem, ptr, mode,
+ new_rd_ia32_DecMem);
+ break;
+ }
+ new_node = dest_am_binop(val, op1, op2, mem, ptr, mode,
+ new_rd_ia32_AddMem, new_rd_ia32_AddMem8Bit,
+ match_dest_am | match_commutative |
+ match_immediate);
+ break;
+ case iro_Sub:
+ op1 = get_Sub_left(val);
+ op2 = get_Sub_right(val);
+ 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,
+ match_dest_am | match_immediate |
+ match_immediate);
+ break;
+ case iro_And:
+ op1 = get_And_left(val);
+ op2 = get_And_right(val);
+ new_node = dest_am_binop(val, op1, op2, mem, ptr, mode,
+ new_rd_ia32_AndMem, new_rd_ia32_AndMem8Bit,
+ match_dest_am | match_commutative |
+ match_immediate);
+ break;
+ case iro_Or:
+ op1 = get_Or_left(val);
+ op2 = get_Or_right(val);
+ new_node = dest_am_binop(val, op1, op2, mem, ptr, mode,
+ new_rd_ia32_OrMem, new_rd_ia32_OrMem8Bit,
+ match_dest_am | match_commutative |
+ match_immediate);
+ break;
+ case iro_Eor:
+ op1 = get_Eor_left(val);
+ op2 = get_Eor_right(val);
+ new_node = dest_am_binop(val, op1, op2, mem, ptr, mode,
+ new_rd_ia32_XorMem, new_rd_ia32_XorMem8Bit,
+ match_dest_am | match_commutative |
+ match_immediate);
+ break;
+ case iro_Shl:
+ op1 = get_Shl_left(val);
+ op2 = get_Shl_right(val);
+ new_node = dest_am_binop(val, op1, op2, mem, ptr, mode,
+ new_rd_ia32_ShlMem, new_rd_ia32_ShlMem,
+ match_dest_am | match_immediate);
+ break;
+ case iro_Shr:
+ op1 = get_Shr_left(val);
+ op2 = get_Shr_right(val);
+ new_node = dest_am_binop(val, op1, op2, mem, ptr, mode,
+ new_rd_ia32_ShrMem, new_rd_ia32_ShrMem,
+ match_dest_am | match_immediate);
+ break;
+ case iro_Shrs:
+ op1 = get_Shrs_left(val);
+ op2 = get_Shrs_right(val);
+ new_node = dest_am_binop(val, op1, op2, mem, ptr, mode,
+ new_rd_ia32_SarMem, new_rd_ia32_SarMem,
+ match_dest_am | match_immediate);
+ break;
+ case iro_Rotl:
+ op1 = get_Rotl_left(val);
+ op2 = get_Rotl_right(val);
+ new_node = dest_am_binop(val, op1, op2, mem, ptr, mode,
+ new_rd_ia32_RolMem, new_rd_ia32_RolMem,
+ match_dest_am | match_immediate);
+ break;
+ /* TODO: match ROR patterns... */
+ case iro_Mux:
+ 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);
+ break;
+ case iro_Not:
+ /* should be lowered already */
+ assert(mode != mode_b);
+ op1 = get_Not_op(val);
+ new_node = dest_am_unop(val, op1, mem, ptr, mode, new_rd_ia32_NotMem);
+ break;
+ default:
+ 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;
+}
+
+static int is_float_to_int32_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))
+ return 0;
+
+ if(!is_Conv(node))
+ return 0;
+ conv_op = get_Conv_op(node);
+ conv_mode = get_irn_mode(conv_op);
+
+ if(!mode_is_float(conv_mode))
+ return 0;
+
+ return 1;
+}
+
+/**
+ * Transform a Store(floatConst).
+ *
+ * @return the created ia32 Store node
+ */
+static ir_node *gen_float_const_Store(ir_node *node, ir_node *cns)
+{
+ ir_mode *mode = get_irn_mode(cns);
+ unsigned size = get_mode_size_bytes(mode);
+ tarval *tv = get_Const_tarval(cns);
+ ir_node *block = get_nodes_block(node);
+ ir_node *new_block = be_transform_node(block);
+ ir_node *ptr = get_Store_ptr(node);
+ ir_node *mem = get_Store_mem(node);
+ ir_graph *irg = current_ir_graph;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ int ofs = 0;
+ size_t i = 0;
+ ir_node *ins[4];
+ ia32_address_t addr;
+
+ assert(size % 4 == 0);
+ assert(size <= 16);
+
+ build_address_ptr(&addr, ptr, mem);
+
+ do {
+ unsigned val =
+ get_tarval_sub_bits(tv, ofs) |
+ (get_tarval_sub_bits(tv, ofs + 1) << 8) |
+ (get_tarval_sub_bits(tv, ofs + 2) << 16) |
+ (get_tarval_sub_bits(tv, ofs + 3) << 24);
+ ir_node *imm = create_Immediate(NULL, 0, val);
+
+ ir_node *new_node = new_rd_ia32_Store(dbgi, irg, new_block, addr.base,
+ addr.index, addr.mem, imm);
+
+ set_irn_pinned(new_node, get_irn_pinned(node));
+ set_ia32_op_type(new_node, ia32_AddrModeD);
+ set_ia32_ls_mode(new_node, mode_Iu);
+ set_address(new_node, &addr);
+ SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, node));
+
+ ins[i++] = new_node;
+
+ size -= 4;
+ ofs += 4;
+ addr.offset += 4;
+ } while (size != 0);
+
+ return i == 1 ? ins[0] : new_rd_Sync(dbgi, irg, new_block, i, ins);
+}
+
+/**
+ * Generate a vfist or vfisttp instruction.
+ */
+static ir_node *gen_vfist(dbg_info *dbgi, ir_graph *irg, ir_node *block, ir_node *base, ir_node *index,
+ ir_node *mem, ir_node *val, ir_node **fist)
+{
+ ir_node *new_node;
+
+ if (ia32_cg_config.use_fisttp) {
+ /* Note: fisttp ALWAYS pop the tos. We have to ensure here that the value is copied
+ if other users exists */
+ const arch_register_class_t *reg_class = &ia32_reg_classes[CLASS_ia32_vfp];
+ ir_node *vfisttp = new_rd_ia32_vfisttp(dbgi, irg, block, base, index, mem, val);
+ ir_node *value = new_r_Proj(irg, block, vfisttp, mode_E, pn_ia32_vfisttp_res);
+ be_new_Keep(reg_class, irg, block, 1, &value);
+
+ new_node = new_r_Proj(irg, block, vfisttp, mode_M, pn_ia32_vfisttp_M);
+ *fist = vfisttp;
+ } else {
+ ir_node *trunc_mode = ia32_new_Fpu_truncate(env_cg);
+
+ /* do a fist */
+ new_node = new_rd_ia32_vfist(dbgi, irg, block, base, index, mem, val, trunc_mode);
+ *fist = new_node;
+ }
+ return new_node;
+}
+/**
+ * Transforms a normal Store.
+ *
+ * @return the created ia32 Store node
+ */
+static ir_node *gen_normal_Store(ir_node *node)
+{
+ ir_node *val = get_Store_value(node);
+ ir_mode *mode = get_irn_mode(val);
+ ir_node *block = get_nodes_block(node);
+ ir_node *new_block = be_transform_node(block);
+ ir_node *ptr = get_Store_ptr(node);
+ ir_node *mem = get_Store_mem(node);
+ ir_graph *irg = current_ir_graph;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *noreg = ia32_new_NoReg_gp(env_cg);
+ ir_node *new_val, *new_node, *store;
+ ia32_address_t addr;
+
+ /* check for destination address mode */
+ new_node = try_create_dest_am(node);
+ if (new_node != NULL)
+ return new_node;
+
+ /* construct store address */
+ memset(&addr, 0, sizeof(addr));
+ ia32_create_address_mode(&addr, ptr, /*force=*/0);
+
+ if (addr.base == NULL) {
+ addr.base = noreg;
+ } else {
+ addr.base = be_transform_node(addr.base);
+ }
+
+ if (addr.index == NULL) {
+ addr.index = noreg;
+ } else {
+ addr.index = be_transform_node(addr.index);
+ }
+ addr.mem = be_transform_node(mem);
+
+ if (mode_is_float(mode)) {
+ /* Convs (and strict-Convs) before stores are unnecessary if the mode
+ is the same. */
+ while (is_Conv(val) && mode == get_irn_mode(val)) {
+ ir_node *op = get_Conv_op(val);
+ if (!mode_is_float(get_irn_mode(op)))
+ break;
+ val = op;
+ }
+ new_val = be_transform_node(val);
+ if (ia32_cg_config.use_sse2) {
+ new_node = new_rd_ia32_xStore(dbgi, irg, new_block, addr.base,
+ addr.index, addr.mem, new_val);
+ } else {
+ new_node = new_rd_ia32_vfst(dbgi, irg, new_block, addr.base,
+ addr.index, addr.mem, new_val, mode);
+ }
+ store = new_node;
+ } else if (!ia32_cg_config.use_sse2 && is_float_to_int32_conv(val)) {
+ val = get_Conv_op(val);
+
+ /* TODO: is this optimisation still necessary at all (middleend)? */
+ /* We can skip ALL float->float up-Convs (and strict-up-Convs) before stores. */
+ while (is_Conv(val)) {
+ ir_node *op = get_Conv_op(val);
+ if (!mode_is_float(get_irn_mode(op)))
+ break;
+ if (get_mode_size_bits(get_irn_mode(op)) > get_mode_size_bits(get_irn_mode(val)))
+ break;
+ val = op;
+ }
+ new_val = be_transform_node(val);
+ new_node = gen_vfist(dbgi, irg, new_block, addr.base, addr.index, addr.mem, new_val, &store);
+ } else {
+ new_val = create_immediate_or_transform(val, 0);
+ assert(mode != mode_b);
+
+ if (get_mode_size_bits(mode) == 8) {
+ new_node = new_rd_ia32_Store8Bit(dbgi, irg, new_block, addr.base,
+ addr.index, addr.mem, new_val);
+ } else {
+ new_node = new_rd_ia32_Store(dbgi, irg, new_block, addr.base,
+ addr.index, addr.mem, new_val);
+ }
+ store = new_node;
+ }
+
+ set_irn_pinned(store, get_irn_pinned(node));
+ set_ia32_op_type(store, ia32_AddrModeD);
+ set_ia32_ls_mode(store, mode);
+
+ set_address(store, &addr);
+ SET_IA32_ORIG_NODE(store, ia32_get_old_node_name(env_cg, node));
+
+ return new_node;
+}
+
+/**
+ * Transforms a Store.
+ *
+ * @return the created ia32 Store node
+ */
+static ir_node *gen_Store(ir_node *node)
+{
+ ir_node *val = get_Store_value(node);
+ ir_mode *mode = get_irn_mode(val);
+
+ if (mode_is_float(mode) && is_Const(val)) {
+ int transform;
+
+ /* we are storing a floating point constant */
+ if (ia32_cg_config.use_sse2) {
+ transform = !is_simple_sse_Const(val);
+ } else {
+ transform = !is_simple_x87_Const(val);
+ }
+ if (transform)
+ return gen_float_const_Store(node, val);
+ }
+ return gen_normal_Store(node);
+}
+
+/**
+ * Transforms a Switch.
+ *
+ * @return the created ia32 SwitchJmp node
+ */
+static ir_node *create_Switch(ir_node *node)
+{
+ ir_graph *irg = current_ir_graph;
+ 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);
+ int switch_min = INT_MAX;
+ int switch_max = INT_MIN;
+ long default_pn = get_Cond_defaultProj(node);
+ ir_node *new_node;
+ const ir_edge_t *edge;