+/**
+ * Transforms a Store.
+ *
+ * @param env The transformation environment
+ * @return the created ia32 Store node
+ */
+static ir_node *gen_Store(ia32_transform_env_t *env, ir_node *node) {
+ ir_node *block = transform_node(env, get_nodes_block(node));
+ ir_node *ptr = get_Store_ptr(node);
+ ir_node *new_ptr = transform_node(env, ptr);
+ ir_node *val = get_Store_value(node);
+ ir_node *new_val = transform_node(env, val);
+ ir_node *mem = get_Store_mem(node);
+ ir_node *new_mem = transform_node(env, mem);
+ ir_graph *irg = env->irg;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *noreg = ia32_new_NoReg_gp(env->cg);
+ ir_node *sptr = new_ptr;
+ ir_mode *mode = get_irn_mode(val);
+ ir_node *sval = new_val;
+ int is_imm = 0;
+ ir_node *new_op;
+ ia32_am_flavour_t am_flav = ia32_am_B;
+
+ if (is_ia32_Const(new_val)) {
+ assert(!mode_is_float(mode));
+ sval = noreg;
+ }
+
+ /* address might be a constant (symconst or absolute address) */
+ if (is_ia32_Const(new_ptr)) {
+ sptr = noreg;
+ is_imm = 1;
+ }
+
+ if (mode_is_float(mode)) {
+ FP_USED(env->cg);
+ if (USE_SSE2(env->cg)) {
+ new_op = new_rd_ia32_xStore(dbgi, irg, block, sptr, noreg, sval, new_mem);
+ } else {
+ new_op = new_rd_ia32_vfst(dbgi, irg, block, sptr, noreg, sval, new_mem);
+ }
+ } else if (get_mode_size_bits(mode) == 8) {
+ new_op = new_rd_ia32_Store8Bit(dbgi, irg, block, sptr, noreg, sval, new_mem);
+ } else {
+ new_op = new_rd_ia32_Store(dbgi, irg, block, sptr, noreg, sval, new_mem);
+ }
+
+ /* stored const is an immediate value */
+ if (is_ia32_Const(new_val)) {
+ assert(!mode_is_float(mode));
+ copy_ia32_Immop_attr(new_op, new_val);
+ }
+
+ /* base is an constant address */
+ if (is_imm) {
+ if (get_ia32_immop_type(new_ptr) == ia32_ImmSymConst) {
+ set_ia32_am_sc(new_op, get_ia32_Immop_symconst(new_ptr));
+ am_flav = ia32_am_N;
+ } else {
+ tarval *tv = get_ia32_Immop_tarval(new_ptr);
+ long offs = get_tarval_long(tv);
+
+ add_ia32_am_offs_int(new_op, offs);
+ am_flav = ia32_am_O;
+ }
+ }
+
+ set_ia32_am_support(new_op, ia32_am_Dest);
+ set_ia32_op_type(new_op, ia32_AddrModeD);
+ set_ia32_am_flavour(new_op, am_flav);
+ set_ia32_ls_mode(new_op, mode);
+
+ SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, node));
+
+ return new_op;
+}
+
+
+
+/**
+ * Transforms a Cond -> Proj[b] -> Cmp into a CondJmp, CondJmp_i or TestJmp
+ *
+ * @param env The transformation environment
+ * @return The transformed node.
+ */
+static ir_node *gen_Cond(ia32_transform_env_t *env, ir_node *node) {
+ ir_node *block = transform_node(env, get_nodes_block(node));
+ ir_graph *irg = env->irg;
+ 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 *res = NULL;
+ ir_node *noreg = ia32_new_NoReg_gp(env->cg);
+ ir_node *cnst, *expr;
+
+ if (is_Proj(sel) && sel_mode == mode_b) {
+ ir_node *pred = get_Proj_pred(sel);
+ ir_node *cmp_a = get_Cmp_left(pred);
+ ir_node *new_cmp_a = transform_node(env, cmp_a);
+ ir_node *cmp_b = get_Cmp_right(pred);
+ ir_node *new_cmp_b = transform_node(env, cmp_b);
+ ir_mode *cmp_mode = get_irn_mode(cmp_a);
+ ir_node *nomem = new_NoMem();
+
+ int pnc = get_Proj_proj(sel);
+ if(mode_is_float(cmp_mode) || !mode_is_signed(cmp_mode)) {
+ pnc |= ia32_pn_Cmp_Unsigned;
+ }
+
+ /* check if we can use a CondJmp with immediate */
+ cnst = (env->cg->opt & IA32_OPT_IMMOPS) ? get_immediate_op(new_cmp_a, new_cmp_b) : NULL;
+ expr = get_expr_op(new_cmp_a, new_cmp_b);
+
+ if (cnst != NULL && expr != NULL) {
+ /* immop has to be the right operand, we might need to flip pnc */
+ if(cnst != new_cmp_b) {
+ pnc = get_inversed_pnc(pnc);
+ }
+
+ if ((pnc == pn_Cmp_Eq || pnc == pn_Cmp_Lg) && mode_needs_gp_reg(get_irn_mode(expr))) {
+ if (get_ia32_immop_type(cnst) == ia32_ImmConst &&
+ classify_tarval(get_ia32_Immop_tarval(cnst)) == TV_CLASSIFY_NULL)
+ {
+ /* a Cmp A =/!= 0 */
+ ir_node *op1 = expr;
+ ir_node *op2 = expr;
+ int is_and = 0;
+
+ /* check, if expr is an only once used And operation */
+ if (is_ia32_And(expr) && get_irn_n_edges(expr)) {
+ op1 = get_irn_n(expr, 2);
+ op2 = get_irn_n(expr, 3);
+
+ is_and = (is_ia32_ImmConst(expr) || is_ia32_ImmSymConst(expr));
+ }
+ res = new_rd_ia32_TestJmp(dbgi, irg, block, op1, op2);
+ set_ia32_pncode(res, pnc);
+
+ if (is_and) {
+ copy_ia32_Immop_attr(res, expr);
+ }
+
+ SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env->cg, node));
+ return res;
+ }
+ }
+
+ if (mode_is_float(cmp_mode)) {
+ FP_USED(env->cg);
+ if (USE_SSE2(env->cg)) {
+ res = new_rd_ia32_xCondJmp(dbgi, irg, block, noreg, noreg, expr, noreg, nomem);
+ set_ia32_ls_mode(res, cmp_mode);
+ } else {
+ assert(0);
+ }
+ }
+ else {
+ assert(get_mode_size_bits(cmp_mode) == 32);
+ res = new_rd_ia32_CondJmp(dbgi, irg, block, noreg, noreg, expr, noreg, nomem);
+ }
+ copy_ia32_Immop_attr(res, cnst);
+ }
+ else {
+ ir_mode *cmp_mode = get_irn_mode(cmp_a);
+
+ if (mode_is_float(cmp_mode)) {
+ FP_USED(env->cg);
+ if (USE_SSE2(env->cg)) {
+ res = new_rd_ia32_xCondJmp(dbgi, irg, block, noreg, noreg, cmp_a, cmp_b, nomem);
+ set_ia32_ls_mode(res, cmp_mode);
+ } else {
+ ir_node *proj_eax;
+ res = new_rd_ia32_vfCondJmp(dbgi, irg, block, noreg, noreg, cmp_a, cmp_b, nomem);
+ proj_eax = new_r_Proj(irg, block, res, mode_Iu, pn_ia32_vfCondJmp_temp_reg_eax);
+ be_new_Keep(&ia32_reg_classes[CLASS_ia32_gp], irg, block, 1, &proj_eax);
+ }
+ }
+ else {
+ assert(get_mode_size_bits(cmp_mode) == 32);
+ res = new_rd_ia32_CondJmp(dbgi, irg, block, noreg, noreg, cmp_a, cmp_b, nomem);
+ set_ia32_commutative(res);
+ }
+ }
+
+ set_ia32_pncode(res, pnc);
+ // Matze: disabled for now, because the default collect_spills_walker
+ // is not able to detect the mode of the spilled value
+ // moreover, the lea optimize phase freely exchanges left/right
+ // without updating the pnc
+ //set_ia32_am_support(res, ia32_am_Source);
+ }
+ else {
+ /* determine the smallest switch case value */
+ ir_node *new_sel = transform_node(env, sel);
+ int switch_min = INT_MAX;
+ const ir_edge_t *edge;
+
+ foreach_out_edge(node, edge) {
+ int pn = get_Proj_proj(get_edge_src_irn(edge));
+ switch_min = pn < switch_min ? pn : switch_min;
+ }
+
+ if (switch_min) {
+ /* if smallest switch case is not 0 we need an additional sub */
+ res = new_rd_ia32_Lea(dbgi, irg, block, new_sel, noreg);
+ SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env->cg, node));
+ add_ia32_am_offs_int(res, -switch_min);
+ set_ia32_am_flavour(res, ia32_am_OB);
+ set_ia32_am_support(res, ia32_am_Source);
+ set_ia32_op_type(res, ia32_AddrModeS);
+ }
+
+ res = new_rd_ia32_SwitchJmp(dbgi, irg, block, switch_min ? res : new_sel, mode_T);
+ set_ia32_pncode(res, get_Cond_defaultProj(node));
+ }
+
+ SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env->cg, node));
+ return res;
+}
+
+
+
+/**
+ * Transforms a CopyB node.
+ *
+ * @param env The transformation environment
+ * @return The transformed node.
+ */
+static ir_node *gen_CopyB(ia32_transform_env_t *env, ir_node *node) {
+ ir_node *block = transform_node(env, get_nodes_block(node));
+ ir_node *src = get_CopyB_src(node);
+ ir_node *new_src = transform_node(env, src);
+ ir_node *dst = get_CopyB_dst(node);
+ ir_node *new_dst = transform_node(env, dst);
+ ir_node *mem = get_CopyB_mem(node);
+ ir_node *new_mem = transform_node(env, mem);
+ ir_node *res = NULL;
+ ir_graph *irg = env->irg;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ int size = get_type_size_bytes(get_CopyB_type(node));
+ ir_mode *dst_mode = get_irn_mode(dst);
+ ir_mode *src_mode = get_irn_mode(src);
+ int rem;
+ ir_node *in[3];
+
+ /* 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);
+ add_irn_dep(res, be_abi_get_start_barrier(env->cg->birg->abi));
+ set_ia32_Immop_tarval(res, new_tarval_from_long(size, mode_Is));
+
+ res = new_rd_ia32_CopyB(dbgi, irg, block, new_dst, new_src, res, new_mem);
+ set_ia32_Immop_tarval(res, new_tarval_from_long(rem, mode_Is));
+
+ /* ok: now attach Proj's because rep movsd will destroy esi, edi and ecx */
+ in[0] = new_r_Proj(irg, block, res, dst_mode, pn_ia32_CopyB_DST);
+ in[1] = new_r_Proj(irg, block, res, src_mode, pn_ia32_CopyB_SRC);
+ in[2] = new_r_Proj(irg, block, res, mode_Iu, pn_ia32_CopyB_CNT);
+ be_new_Keep(&ia32_reg_classes[CLASS_ia32_gp], irg, block, 3, in);
+ }
+ else {
+ res = new_rd_ia32_CopyB_i(dbgi, irg, block, new_dst, new_src, new_mem);
+ set_ia32_Immop_tarval(res, new_tarval_from_long(size, mode_Is));
+
+ /* ok: now attach Proj's because movsd will destroy esi and edi */
+ in[0] = new_r_Proj(irg, block, res, dst_mode, pn_ia32_CopyB_i_DST);
+ in[1] = new_r_Proj(irg, block, res, src_mode, pn_ia32_CopyB_i_SRC);
+ be_new_Keep(&ia32_reg_classes[CLASS_ia32_gp], irg, block, 2, in);
+ }
+
+ SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env->cg, node));
+
+ return res;
+}
+
+
+#if 0
+/**
+ * Transforms a Mux node into CMov.
+ *
+ * @param env The transformation environment
+ * @return The transformed node.
+ */
+static ir_node *gen_Mux(ia32_transform_env_t *env, ir_node *node) {
+ ir_node *new_op = new_rd_ia32_CMov(env->dbgi, env->irg, env->block, \
+ get_Mux_sel(node), get_Mux_false(node), get_Mux_true(node), env->mode);
+
+ SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, node));
+
+ return new_op;
+}
+#endif
+
+typedef ir_node *cmov_func_t(dbg_info *db, ir_graph *irg, ir_node *block,
+ ir_node *cmp_a, ir_node *cmp_b, ir_node *psi_true,
+ ir_node *psi_default);
+
+/**
+ * Transforms a Psi node into CMov.
+ *
+ * @param env The transformation environment
+ * @return The transformed node.
+ */
+static ir_node *gen_Psi(ia32_transform_env_t *env, ir_node *node) {
+ ir_node *block = transform_node(env, get_nodes_block(node));
+ ir_node *psi_true = get_Psi_val(node, 0);
+ ir_node *new_psi_true = transform_node(env, psi_true);
+ ir_node *psi_default = get_Psi_default(node);
+ ir_node *new_psi_default = transform_node(env, psi_default);
+ ia32_code_gen_t *cg = env->cg;
+ ir_graph *irg = env->irg;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_mode *mode = get_irn_mode(node);
+ ir_node *cmp_proj = get_Mux_sel(node);
+ ir_node *noreg = ia32_new_NoReg_gp(cg);
+ ir_node *nomem = new_rd_NoMem(irg);
+ ir_node *cmp, *cmp_a, *cmp_b, *and1, *and2, *new_op = NULL;
+ ir_node *new_cmp_a, *new_cmp_b;
+ ir_mode *cmp_mode;
+ int pnc;
+
+ assert(get_irn_mode(cmp_proj) == mode_b && "Condition for Psi must have mode_b");
+
+ cmp = get_Proj_pred(cmp_proj);
+ cmp_a = get_Cmp_left(cmp);
+ cmp_b = get_Cmp_right(cmp);
+ cmp_mode = get_irn_mode(cmp_a);
+ new_cmp_a = transform_node(env, cmp_a);
+ new_cmp_b = transform_node(env, cmp_b);
+
+ pnc = get_Proj_proj(cmp_proj);
+ if (mode_is_float(cmp_mode) || !mode_is_signed(cmp_mode)) {
+ pnc |= ia32_pn_Cmp_Unsigned;
+ }
+
+ if (mode_is_float(mode)) {
+ /* floating point psi */
+ FP_USED(cg);
+
+ /* 1st case: compare operands are float too */
+ if (USE_SSE2(cg)) {
+ /* psi(cmp(a, b), t, f) can be done as: */
+ /* tmp = cmp a, b */
+ /* tmp2 = t and tmp */
+ /* tmp3 = f and not tmp */
+ /* res = tmp2 or tmp3 */
+
+ /* in case the compare operands are int, we move them into xmm register */
+ if (! mode_is_float(get_irn_mode(cmp_a))) {
+ new_cmp_a = gen_sse_conv_int2float(cg, dbgi, irg, block, new_cmp_a, node, mode_xmm);
+ new_cmp_b = gen_sse_conv_int2float(cg, dbgi, irg, block, new_cmp_b, node, mode_xmm);
+
+ pnc |= 8; /* transform integer compare to fp compare */
+ }
+
+ new_op = new_rd_ia32_xCmp(dbgi, irg, block, noreg, noreg, new_cmp_a, new_cmp_b, nomem);
+ set_ia32_pncode(new_op, pnc);
+ set_ia32_am_support(new_op, ia32_am_Source);
+ SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(cg, node));
+
+ and1 = new_rd_ia32_xAnd(dbgi, irg, block, noreg, noreg, new_psi_true, new_op, nomem);
+ set_ia32_am_support(and1, ia32_am_None);
+ set_ia32_commutative(and1);
+ SET_IA32_ORIG_NODE(and1, ia32_get_old_node_name(cg, node));
+
+ and2 = new_rd_ia32_xAndNot(dbgi, irg, block, noreg, noreg, new_op, new_psi_default, nomem);
+ set_ia32_am_support(and2, ia32_am_None);
+ set_ia32_commutative(and2);
+ SET_IA32_ORIG_NODE(and2, ia32_get_old_node_name(cg, node));
+
+ new_op = new_rd_ia32_xOr(dbgi, irg, block, noreg, noreg, and1, and2, nomem);
+ set_ia32_am_support(new_op, ia32_am_None);
+ set_ia32_commutative(new_op);
+ SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(cg, node));
+ }
+ else {
+ /* x87 FPU */
+ new_op = new_rd_ia32_vfCMov(dbgi, irg, block, new_cmp_a, new_cmp_b, new_psi_true, new_psi_default);
+ set_ia32_pncode(new_op, pnc);
+ SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, node));
+ }
+ }
+ else {
+ /* integer psi */
+ construct_binop_func *set_func = NULL;
+ cmov_func_t *cmov_func = NULL;
+
+ if (mode_is_float(get_irn_mode(cmp_a))) {
+ /* 1st case: compare operands are floats */
+ FP_USED(cg);
+
+ if (USE_SSE2(cg)) {
+ /* SSE FPU */
+ set_func = new_rd_ia32_xCmpSet;
+ cmov_func = new_rd_ia32_xCmpCMov;
+ }
+ else {
+ /* x87 FPU */
+ set_func = new_rd_ia32_vfCmpSet;
+ cmov_func = new_rd_ia32_vfCmpCMov;
+ }
+
+ pnc &= ~0x8; /* fp compare -> int compare */
+ }
+ else {
+ /* 2nd case: compare operand are integer too */
+ set_func = new_rd_ia32_CmpSet;
+ cmov_func = new_rd_ia32_CmpCMov;
+ }
+
+ /* check for special case first: And/Or -- Cmp with 0 -- Psi */
+ if (is_ia32_Const_0(new_cmp_b) && is_Proj(new_cmp_a) && (is_ia32_And(get_Proj_pred(new_cmp_a)) || is_ia32_Or(get_Proj_pred(new_cmp_a)))) {
+ if (is_ia32_Const_1(psi_true) && is_ia32_Const_0(psi_default)) {
+ /* first case for SETcc: default is 0, set to 1 iff condition is true */
+ new_op = new_rd_ia32_PsiCondSet(dbgi, irg, block, new_cmp_a);
+ set_ia32_pncode(new_op, pnc);
+ }
+ else if (is_ia32_Const_0(psi_true) && is_ia32_Const_1(psi_default)) {
+ /* second case for SETcc: default is 1, set to 0 iff condition is true: */
+ /* we invert condition and set default to 0 */
+ new_op = new_rd_ia32_PsiCondSet(dbgi, irg, block, new_cmp_a);
+ set_ia32_pncode(new_op, get_inversed_pnc(pnc));
+ }
+ else {
+ /* otherwise: use CMOVcc */
+ new_op = new_rd_ia32_PsiCondCMov(dbgi, irg, block, new_cmp_a, new_psi_true, new_psi_default);
+ set_ia32_pncode(new_op, pnc);
+ }
+
+ SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(cg, node));
+ }
+ else {
+ if (is_ia32_Const_1(psi_true) && is_ia32_Const_0(psi_default)) {
+ /* first case for SETcc: default is 0, set to 1 iff condition is true */
+ new_op = gen_binop(env, node, cmp_a, cmp_b, set_func);
+ set_ia32_pncode(new_op, pnc);
+ set_ia32_am_support(new_op, ia32_am_Source);
+ }
+ else if (is_ia32_Const_0(psi_true) && is_ia32_Const_1(psi_default)) {
+ /* second case for SETcc: default is 1, set to 0 iff condition is true: */
+ /* we invert condition and set default to 0 */
+ new_op = gen_binop(env, node, cmp_a, cmp_b, set_func);
+ set_ia32_pncode(new_op, get_inversed_pnc(pnc));
+ set_ia32_am_support(new_op, ia32_am_Source);
+ }
+ else {
+ /* otherwise: use CMOVcc */
+ new_op = cmov_func(dbgi, irg, block, new_cmp_a, new_cmp_b, new_psi_true, new_psi_default);
+ set_ia32_pncode(new_op, pnc);
+ SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(cg, node));
+ }
+ }
+ }
+
+ return new_op;
+}
+
+
+/**
+ * Following conversion rules apply:
+ *
+ * INT -> INT
+ * ============
+ * 1) n bit -> m bit n > m (downscale)
+ * always ignored
+ * 2) n bit -> m bit n == m (sign change)
+ * always ignored
+ * 3) n bit -> m bit n < m (upscale)
+ * a) source is signed: movsx
+ * b) source is unsigned: and with lower bits sets
+ *
+ * INT -> FLOAT
+ * ==============
+ * SSE(1/2) convert to float or double (cvtsi2ss/sd)
+ *
+ * FLOAT -> INT
+ * ==============
+ * SSE(1/2) convert from float or double to 32bit int (cvtss/sd2si)
+ *
+ * FLOAT -> FLOAT
+ * ================
+ * SSE(1/2) convert from float or double to double or float (cvtss/sd2sd/ss)
+ * x87 is mode_E internally, conversions happen only at load and store
+ * in non-strict semantic
+ */
+
+/**
+ * Create a conversion from x87 state register to general purpose.
+ */
+static ir_node *gen_x87_fp_to_gp(ia32_transform_env_t *env, ir_node *node) {
+ ir_node *block = transform_node(env, get_nodes_block(node));
+ ir_node *op = get_Conv_op(node);
+ ir_node *new_op = transform_node(env, op);
+ ia32_code_gen_t *cg = env->cg;
+ ir_graph *irg = env->irg;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *noreg = ia32_new_NoReg_gp(cg);
+ ir_node *trunc_mode = ia32_new_Fpu_truncate(cg);
+ ir_node *fist, *load;
+
+ /* do a fist */
+ fist = new_rd_ia32_vfist(dbgi, irg, block,
+ get_irg_frame(irg), noreg, new_op, trunc_mode, new_NoMem());
+
+ set_ia32_use_frame(fist);
+ set_ia32_am_support(fist, ia32_am_Dest);
+ set_ia32_op_type(fist, ia32_AddrModeD);
+ set_ia32_am_flavour(fist, ia32_am_B);
+ set_ia32_ls_mode(fist, mode_Iu);
+ SET_IA32_ORIG_NODE(fist, ia32_get_old_node_name(cg, node));
+
+ /* do a Load */
+ load = new_rd_ia32_Load(dbgi, irg, block, get_irg_frame(irg), noreg, fist);
+
+ set_ia32_use_frame(load);
+ set_ia32_am_support(load, ia32_am_Source);
+ set_ia32_op_type(load, ia32_AddrModeS);
+ set_ia32_am_flavour(load, ia32_am_B);
+ set_ia32_ls_mode(load, mode_Iu);
+ SET_IA32_ORIG_NODE(load, ia32_get_old_node_name(cg, node));
+
+ return new_r_Proj(irg, block, load, mode_Iu, pn_ia32_Load_res);
+}
+
+/**
+ * Create a conversion from general purpose to x87 register
+ */
+static ir_node *gen_x87_gp_to_fp(ia32_transform_env_t *env, ir_node *node, ir_mode *src_mode) {
+ ir_node *block = transform_node(env, get_nodes_block(node));
+ ir_node *op = get_Conv_op(node);
+ ir_node *new_op = transform_node(env, op);
+ ir_graph *irg = env->irg;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *noreg = ia32_new_NoReg_gp(env->cg);
+ ir_node *nomem = new_NoMem();
+ ir_node *fild, *store;
+ int src_bits;
+
+ /* first convert to 32 bit if necessary */
+ src_bits = get_mode_size_bits(src_mode);
+ if (src_bits == 8) {
+ new_op = new_rd_ia32_Conv_I2I8Bit(dbgi, irg, block, noreg, noreg, new_op, nomem);
+ set_ia32_am_support(new_op, ia32_am_Source);
+ set_ia32_ls_mode(new_op, src_mode);
+ SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, node));
+ } else if (src_bits < 32) {
+ new_op = new_rd_ia32_Conv_I2I(dbgi, irg, block, noreg, noreg, new_op, nomem);
+ set_ia32_am_support(new_op, ia32_am_Source);
+ set_ia32_ls_mode(new_op, src_mode);
+ SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, node));
+ }
+
+ /* do a store */
+ store = new_rd_ia32_Store(dbgi, irg, block, get_irg_frame(irg), noreg, new_op, nomem);
+
+ set_ia32_use_frame(store);
+ set_ia32_am_support(store, ia32_am_Dest);
+ set_ia32_op_type(store, ia32_AddrModeD);
+ set_ia32_am_flavour(store, ia32_am_OB);
+ set_ia32_ls_mode(store, mode_Iu);
+
+ /* do a fild */
+ fild = new_rd_ia32_vfild(dbgi, irg, block, get_irg_frame(irg), noreg, store);
+
+ set_ia32_use_frame(fild);
+ set_ia32_am_support(fild, ia32_am_Source);
+ set_ia32_op_type(fild, ia32_AddrModeS);
+ set_ia32_am_flavour(fild, ia32_am_OB);
+ set_ia32_ls_mode(fild, mode_Iu);
+
+ return new_r_Proj(irg, block, fild, mode_vfp, pn_ia32_vfild_res);
+}
+
+/**
+ * Transforms a Conv node.
+ *
+ * @param env The transformation environment
+ * @return The created ia32 Conv node
+ */
+static ir_node *gen_Conv(ia32_transform_env_t *env, ir_node *node) {
+ ir_node *block = transform_node(env, get_nodes_block(node));
+ ir_node *op = get_Conv_op(node);
+ ir_node *new_op = transform_node(env, op);
+ ir_graph *irg = env->irg;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_mode *src_mode = get_irn_mode(op);
+ ir_mode *tgt_mode = get_irn_mode(node);
+ int src_bits = get_mode_size_bits(src_mode);
+ int tgt_bits = get_mode_size_bits(tgt_mode);
+ ir_node *noreg = ia32_new_NoReg_gp(env->cg);
+ ir_node *nomem = new_rd_NoMem(irg);
+ ir_node *res;
+
+ if (src_mode == tgt_mode) {
+ if (get_Conv_strict(node)) {
+ if (USE_SSE2(env->cg)) {
+ /* when we are in SSE mode, we can kill all strict no-op conversion */
+ return new_op;
+ }
+ } else {
+ /* this should be optimized already, but who knows... */
+ DEBUG_ONLY(ir_fprintf(stderr, "Debug warning: conv %+F is pointless\n", node));
+ DB((dbg, LEVEL_1, "killed Conv(mode, mode) ..."));
+ return new_op;
+ }
+ }
+
+ if (mode_is_float(src_mode)) {
+ /* we convert from float ... */
+ if (mode_is_float(tgt_mode)) {
+ /* ... to float */
+ if (USE_SSE2(env->cg)) {
+ DB((dbg, LEVEL_1, "create Conv(float, float) ..."));
+ res = new_rd_ia32_Conv_FP2FP(dbgi, irg, block, noreg, noreg, new_op, nomem);
+ set_ia32_ls_mode(res, tgt_mode);
+ } else {
+ // Matze: TODO what about strict convs?
+ DEBUG_ONLY(ir_fprintf(stderr, "Debug warning: strict conv %+F ignored yet\n", node));
+ DB((dbg, LEVEL_1, "killed Conv(float, float) ..."));
+ return new_op;
+ }
+ } else {
+ /* ... to int */
+ DB((dbg, LEVEL_1, "create Conv(float, int) ..."));
+ if (USE_SSE2(env->cg)) {
+ res = new_rd_ia32_Conv_FP2I(dbgi, irg, block, noreg, noreg, new_op, nomem);
+ set_ia32_ls_mode(res, src_mode);
+ } else {
+ return gen_x87_fp_to_gp(env, node);
+ }
+ }
+ } else {
+ /* we convert from int ... */
+ if (mode_is_float(tgt_mode)) {
+ FP_USED(env->cg);
+ /* ... to float */
+ DB((dbg, LEVEL_1, "create Conv(int, float) ..."));
+ if (USE_SSE2(env->cg)) {
+ res = new_rd_ia32_Conv_I2FP(dbgi, irg, block, noreg, noreg, new_op, nomem);
+ set_ia32_ls_mode(res, tgt_mode);
+ if(src_bits == 32) {
+ set_ia32_am_support(res, ia32_am_Source);
+ }
+ } else {
+ return gen_x87_gp_to_fp(env, node, src_mode);
+ }
+ } else {
+ /* to int */
+ ir_mode *smaller_mode;
+ int smaller_bits;
+
+ if (src_bits == tgt_bits) {
+ DB((dbg, LEVEL_1, "omitting unnecessary Conv(%+F, %+F) ...", src_mode, tgt_mode));
+ return new_op;
+ }
+
+ if (src_bits < tgt_bits) {
+ smaller_mode = src_mode;
+ smaller_bits = src_bits;
+ } else {
+ smaller_mode = tgt_mode;
+ smaller_bits = tgt_bits;
+ }
+
+ /*
+ The following is not correct, we can't change the mode,
+ maybe others are using the load too
+ better move this to a separate phase!
+ */
+#if 0
+ /* ... to int */
+ if(is_Proj(new_op)) {
+ /* load operations do already sign/zero extend, so we have
+ * nothing left to do */
+ ir_node *pred = get_Proj_pred(new_op);
+ if(is_ia32_Load(pred)) {
+ set_ia32_ls_mode(pred, smaller_mode);
+ return new_op;
+ }
+ }
+#endif /* if 0 */
+
+ DB((dbg, LEVEL_1, "create Conv(int, int) ...", src_mode, tgt_mode));
+ if (smaller_bits == 8) {
+ res = new_rd_ia32_Conv_I2I8Bit(dbgi, irg, block, noreg, noreg, new_op, nomem);
+ set_ia32_ls_mode(res, smaller_mode);
+ } else {
+ res = new_rd_ia32_Conv_I2I(dbgi, irg, block, noreg, noreg, new_op, nomem);
+ set_ia32_ls_mode(res, smaller_mode);
+ }
+ set_ia32_am_support(res, ia32_am_Source);
+ }
+ }
+
+ SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env->cg, node));
+
+ return res;
+}
+
+
+
+/********************************************
+ * _ _
+ * | | | |
+ * | |__ ___ _ __ ___ __| | ___ ___
+ * | '_ \ / _ \ '_ \ / _ \ / _` |/ _ \/ __|
+ * | |_) | __/ | | | (_) | (_| | __/\__ \
+ * |_.__/ \___|_| |_|\___/ \__,_|\___||___/
+ *
+ ********************************************/
+
+static ir_node *gen_be_StackParam(ia32_transform_env_t *env, ir_node *node) {
+ ir_node *block = transform_node(env, get_nodes_block(node));
+ ir_node *ptr = get_irn_n(node, be_pos_StackParam_ptr);
+ ir_node *new_ptr = transform_node(env, ptr);
+ ir_node *new_op = NULL;
+ ir_graph *irg = env->irg;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *nomem = new_rd_NoMem(env->irg);
+ ir_entity *ent = arch_get_frame_entity(env->cg->arch_env, node);
+ ir_mode *load_mode = get_irn_mode(node);
+ ir_node *noreg = ia32_new_NoReg_gp(env->cg);
+ ir_mode *proj_mode;
+ long pn_res;
+
+ if (mode_is_float(load_mode)) {
+ FP_USED(env->cg);
+ if (USE_SSE2(env->cg)) {
+ new_op = new_rd_ia32_xLoad(dbgi, irg, block, new_ptr, noreg, nomem);
+ pn_res = pn_ia32_xLoad_res;
+ proj_mode = mode_xmm;
+ } else {
+ new_op = new_rd_ia32_vfld(dbgi, irg, block, new_ptr, noreg, nomem);
+ pn_res = pn_ia32_vfld_res;
+ proj_mode = mode_vfp;
+ }
+ } else {
+ new_op = new_rd_ia32_Load(dbgi, irg, block, new_ptr, noreg, nomem);
+ proj_mode = mode_Iu;
+ pn_res = pn_ia32_Load_res;
+ }
+
+ set_ia32_frame_ent(new_op, ent);
+ set_ia32_use_frame(new_op);
+
+ set_ia32_am_support(new_op, ia32_am_Source);
+ set_ia32_op_type(new_op, ia32_AddrModeS);
+ set_ia32_am_flavour(new_op, ia32_am_B);
+ set_ia32_ls_mode(new_op, load_mode);
+ set_ia32_flags(new_op, get_ia32_flags(new_op) | arch_irn_flags_rematerializable);
+
+ SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, node));
+
+ return new_rd_Proj(dbgi, irg, block, new_op, proj_mode, pn_res);
+}
+
+/**
+ * Transforms a FrameAddr into an ia32 Add.
+ */
+static ir_node *gen_be_FrameAddr(ia32_transform_env_t *env, ir_node *node) {
+ ir_node *block = transform_node(env, get_nodes_block(node));
+ ir_node *op = get_irn_n(node, be_pos_FrameAddr_ptr);
+ ir_node *new_op = transform_node(env, op);
+ ir_graph *irg = env->irg;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *noreg = ia32_new_NoReg_gp(env->cg);
+ ir_node *res;
+
+ res = new_rd_ia32_Lea(dbgi, irg, block, new_op, noreg);
+ set_ia32_frame_ent(res, arch_get_frame_entity(env->cg->arch_env, node));
+ set_ia32_am_support(res, ia32_am_Full);
+ set_ia32_use_frame(res);
+ set_ia32_am_flavour(res, ia32_am_OB);
+
+ SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env->cg, node));
+
+ return res;
+}
+
+/**
+ * Transforms a FrameLoad into an ia32 Load.
+ */
+static ir_node *gen_be_FrameLoad(ia32_transform_env_t *env, ir_node *node) {
+ ir_node *block = transform_node(env, get_nodes_block(node));
+ ir_node *mem = get_irn_n(node, be_pos_FrameLoad_mem);
+ ir_node *new_mem = transform_node(env, mem);
+ ir_node *ptr = get_irn_n(node, be_pos_FrameLoad_ptr);
+ ir_node *new_ptr = transform_node(env, ptr);
+ ir_node *new_op = NULL;
+ ir_graph *irg = env->irg;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *noreg = ia32_new_NoReg_gp(env->cg);
+ ir_entity *ent = arch_get_frame_entity(env->cg->arch_env, node);
+ ir_mode *mode = get_type_mode(get_entity_type(ent));
+ ir_node *projs[pn_Load_max];
+
+ ia32_collect_Projs(node, projs, pn_Load_max);
+
+ if (mode_is_float(mode)) {
+ FP_USED(env->cg);
+ if (USE_SSE2(env->cg)) {
+ new_op = new_rd_ia32_xLoad(dbgi, irg, block, new_ptr, noreg, new_mem);
+ }
+ else {
+ new_op = new_rd_ia32_vfld(dbgi, irg, block, new_ptr, noreg, new_mem);
+ }
+ }
+ else {
+ new_op = new_rd_ia32_Load(dbgi, irg, block, new_ptr, noreg, new_mem);
+ }
+
+ set_ia32_frame_ent(new_op, ent);
+ set_ia32_use_frame(new_op);
+
+ set_ia32_am_support(new_op, ia32_am_Source);
+ set_ia32_op_type(new_op, ia32_AddrModeS);
+ set_ia32_am_flavour(new_op, ia32_am_B);
+ set_ia32_ls_mode(new_op, mode);
+
+ SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, node));
+
+ return new_op;
+}
+
+
+/**
+ * Transforms a FrameStore into an ia32 Store.
+ */
+static ir_node *gen_be_FrameStore(ia32_transform_env_t *env, ir_node *node) {
+ ir_node *block = transform_node(env, get_nodes_block(node));
+ ir_node *mem = get_irn_n(node, be_pos_FrameStore_mem);
+ ir_node *new_mem = transform_node(env, mem);
+ ir_node *ptr = get_irn_n(node, be_pos_FrameStore_ptr);
+ ir_node *new_ptr = transform_node(env, ptr);
+ ir_node *val = get_irn_n(node, be_pos_FrameStore_val);
+ ir_node *new_val = transform_node(env, val);
+ ir_node *new_op = NULL;
+ ir_graph *irg = env->irg;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *noreg = ia32_new_NoReg_gp(env->cg);
+ ir_entity *ent = arch_get_frame_entity(env->cg->arch_env, node);
+ ir_mode *mode = get_irn_mode(val);
+
+ if (mode_is_float(mode)) {
+ FP_USED(env->cg);
+ if (USE_SSE2(env->cg)) {
+ new_op = new_rd_ia32_xStore(dbgi, irg, block, new_ptr, noreg, new_val, new_mem);
+ } else {
+ new_op = new_rd_ia32_vfst(dbgi, irg, block, new_ptr, noreg, new_val, new_mem);
+ }
+ } else if (get_mode_size_bits(mode) == 8) {
+ new_op = new_rd_ia32_Store8Bit(dbgi, irg, block, new_ptr, noreg, new_val, new_mem);
+ } else {
+ new_op = new_rd_ia32_Store(dbgi, irg, block, new_ptr, noreg, new_val, new_mem);
+ }
+
+ set_ia32_frame_ent(new_op, ent);
+ set_ia32_use_frame(new_op);
+
+ set_ia32_am_support(new_op, ia32_am_Dest);
+ set_ia32_op_type(new_op, ia32_AddrModeD);
+ set_ia32_am_flavour(new_op, ia32_am_B);
+ set_ia32_ls_mode(new_op, mode);
+
+ SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, node));
+
+ return new_op;
+}
+
+/**
+ * In case SSE is used we need to copy the result from XMM0 to FPU TOS before return.
+ */
+static ir_node *gen_be_Return(ia32_transform_env_t *env, ir_node *node) {
+ ir_graph *irg = env->irg;
+ ir_node *ret_val = get_irn_n(node, be_pos_Return_val);
+ ir_node *ret_mem = get_irn_n(node, be_pos_Return_mem);
+ ir_entity *ent = get_irg_entity(irg);
+ ir_type *tp = get_entity_type(ent);
+ dbg_info *dbgi;
+ ir_node *block;
+ ir_type *res_type;
+ ir_mode *mode;
+ ir_node *frame, *sse_store, *fld, *mproj, *barrier;
+ ir_node *new_barrier, *new_ret_val, *new_ret_mem;
+ ir_node **in;
+ int pn_ret_val, pn_ret_mem, arity, i;
+
+ assert(ret_val != NULL);
+ if (be_Return_get_n_rets(node) < 1 || ! USE_SSE2(env->cg)) {
+ return duplicate_node(env, node);
+ }
+
+ res_type = get_method_res_type(tp, 0);
+
+ if (! is_Primitive_type(res_type)) {
+ return duplicate_node(env, node);
+ }
+
+ mode = get_type_mode(res_type);
+ if (! mode_is_float(mode)) {
+ return duplicate_node(env, node);
+ }
+
+ assert(get_method_n_ress(tp) == 1);
+
+ pn_ret_val = get_Proj_proj(ret_val);
+ pn_ret_mem = get_Proj_proj(ret_mem);
+
+ /* get the Barrier */
+ barrier = get_Proj_pred(ret_val);
+
+ /* get result input of the Barrier */
+ ret_val = get_irn_n(barrier, pn_ret_val);
+ new_ret_val = transform_node(env, ret_val);
+
+ /* get memory input of the Barrier */
+ ret_mem = get_irn_n(barrier, pn_ret_mem);
+ new_ret_mem = transform_node(env, ret_mem);
+
+ frame = get_irg_frame(irg);
+
+ dbgi = get_irn_dbg_info(barrier);
+ block = transform_node(env, get_nodes_block(barrier));
+
+ /* store xmm0 onto stack */
+ sse_store = new_rd_ia32_xStoreSimple(dbgi, irg, block, frame, new_ret_val, new_ret_mem);
+ set_ia32_ls_mode(sse_store, mode);
+ set_ia32_op_type(sse_store, ia32_AddrModeD);
+ set_ia32_use_frame(sse_store);
+ set_ia32_am_flavour(sse_store, ia32_am_B);
+ set_ia32_am_support(sse_store, ia32_am_Dest);
+
+ /* load into st0 */
+ fld = new_rd_ia32_SetST0(dbgi, irg, block, frame, sse_store);
+ set_ia32_ls_mode(fld, mode);
+ set_ia32_op_type(fld, ia32_AddrModeS);
+ set_ia32_use_frame(fld);
+ set_ia32_am_flavour(fld, ia32_am_B);
+ set_ia32_am_support(fld, ia32_am_Source);
+
+ mproj = new_r_Proj(irg, block, fld, mode_M, pn_ia32_SetST0_M);
+ fld = new_r_Proj(irg, block, fld, mode_vfp, pn_ia32_SetST0_res);
+ arch_set_irn_register(env->cg->arch_env, fld, &ia32_vfp_regs[REG_VF0]);
+
+ /* create a new barrier */
+ arity = get_irn_arity(barrier);
+ in = alloca(arity * sizeof(in[0]));
+ for (i = 0; i < arity; ++i) {
+ ir_node *new_in;
+
+ if (i == pn_ret_val) {
+ new_in = fld;
+ } else if (i == pn_ret_mem) {
+ new_in = mproj;
+ } else {
+ ir_node *in = get_irn_n(barrier, i);
+ new_in = transform_node(env, in);
+ }
+ in[i] = new_in;
+ }
+
+ new_barrier = new_ir_node(dbgi, irg, block,
+ get_irn_op(barrier), get_irn_mode(barrier),
+ arity, in);
+ copy_node_attr(barrier, new_barrier);
+ duplicate_deps(env, barrier, new_barrier);
+ set_new_node(barrier, new_barrier);
+ mark_irn_visited(barrier);
+
+ /* transform normally */
+ return duplicate_node(env, node);
+}
+
+/**
+ * Transform a be_AddSP into an ia32_AddSP. Eat up const sizes.
+ */
+static ir_node *gen_be_AddSP(ia32_transform_env_t *env, ir_node *node) {
+ ir_node *block = transform_node(env, get_nodes_block(node));
+ ir_node *sz = get_irn_n(node, be_pos_AddSP_size);
+ ir_node *new_sz = transform_node(env, sz);
+ ir_node *sp = get_irn_n(node, be_pos_AddSP_old_sp);
+ ir_node *new_sp = transform_node(env, sp);
+ ir_graph *irg = env->irg;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *noreg = ia32_new_NoReg_gp(env->cg);
+ ir_node *nomem = new_NoMem();
+ ir_node *new_op;
+
+ /* ia32 stack grows in reverse direction, make a SubSP */
+ new_op = new_rd_ia32_SubSP(dbgi, irg, block, noreg, noreg, new_sp, new_sz, nomem);
+ set_ia32_am_support(new_op, ia32_am_Source);
+ fold_immediate(env, new_op, 2, 3);
+
+ SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, node));
+
+ return new_op;
+}
+
+/**
+ * Transform a be_SubSP into an ia32_SubSP. Eat up const sizes.
+ */
+static ir_node *gen_be_SubSP(ia32_transform_env_t *env, ir_node *node) {
+ ir_node *block = transform_node(env, get_nodes_block(node));
+ ir_node *sz = get_irn_n(node, be_pos_SubSP_size);
+ ir_node *new_sz = transform_node(env, sz);
+ ir_node *sp = get_irn_n(node, be_pos_SubSP_old_sp);
+ ir_node *new_sp = transform_node(env, sp);
+ ir_graph *irg = env->irg;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *noreg = ia32_new_NoReg_gp(env->cg);
+ ir_node *nomem = new_NoMem();
+ ir_node *new_op;
+
+ /* ia32 stack grows in reverse direction, make an AddSP */
+ new_op = new_rd_ia32_AddSP(dbgi, irg, block, noreg, noreg, new_sp, new_sz, nomem);
+ set_ia32_am_support(new_op, ia32_am_Source);
+ fold_immediate(env, new_op, 2, 3);
+
+ SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, node));
+
+ return new_op;
+}
+
+/**
+ * This function just sets the register for the Unknown node
+ * as this is not done during register allocation because Unknown
+ * is an "ignore" node.
+ */
+static ir_node *gen_Unknown(ia32_transform_env_t *env, ir_node *node) {
+ ir_mode *mode = get_irn_mode(node);
+
+ if (mode_is_float(mode)) {
+ if (USE_SSE2(env->cg))
+ return ia32_new_Unknown_xmm(env->cg);
+ else
+ return ia32_new_Unknown_vfp(env->cg);
+ } else if (mode_needs_gp_reg(mode)) {
+ return ia32_new_Unknown_gp(env->cg);
+ } else {
+ assert(0 && "unsupported Unknown-Mode");
+ }
+
+ return NULL;
+}
+
+/**
+ * Change some phi modes
+ */
+static ir_node *gen_Phi(ia32_transform_env_t *env, ir_node *node) {
+ ir_node *block = transform_node(env, get_nodes_block(node));
+ ir_graph *irg = env->irg;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_mode *mode = get_irn_mode(node);
+ ir_node *phi;
+ int i, arity;
+
+ if(mode_needs_gp_reg(mode)) {
+ /* we shouldn't have any 64bit stuff around anymore */
+ assert(get_mode_size_bits(mode) <= 32);
+ /* all integer operations are on 32bit registers now */
+ mode = mode_Iu;
+ } else if(mode_is_float(mode)) {
+ assert(mode == mode_D || mode == mode_F);
+ if (USE_SSE2(env->cg)) {
+ mode = mode_xmm;
+ } else {
+ mode = mode_vfp;
+ }
+ }
+
+ /* phi nodes allow loops, so we use the old arguments for now
+ * and fix this later */
+ phi = new_ir_node(dbgi, irg, block, op_Phi, mode, get_irn_arity(node), get_irn_in(node) + 1);
+ copy_node_attr(node, phi);
+ duplicate_deps(env, node, phi);
+
+ set_new_node(node, phi);
+
+ /* put the preds in the worklist */
+ arity = get_irn_arity(node);
+ for (i = 0; i < arity; ++i) {
+ ir_node *pred = get_irn_n(node, i);
+ pdeq_putr(env->worklist, pred);
+ }
+
+ return phi;
+}
+
+/**********************************************************************
+ * _ _ _
+ * | | | | | |
+ * | | _____ _____ _ __ ___ __| | _ __ ___ __| | ___ ___
+ * | |/ _ \ \ /\ / / _ \ '__/ _ \/ _` | | '_ \ / _ \ / _` |/ _ \/ __|
+ * | | (_) \ V V / __/ | | __/ (_| | | | | | (_) | (_| | __/\__ \
+ * |_|\___/ \_/\_/ \___|_| \___|\__,_| |_| |_|\___/ \__,_|\___||___/
+ *
+ **********************************************************************/
+
+/* These nodes are created in intrinsic lowering (64bit -> 32bit) */
+
+typedef ir_node *construct_load_func(dbg_info *db, ir_graph *irg, ir_node *block, ir_node *base, ir_node *index, \
+ ir_node *mem);
+
+typedef ir_node *construct_store_func(dbg_info *db, ir_graph *irg, ir_node *block, ir_node *base, ir_node *index, \
+ ir_node *val, ir_node *mem);
+
+/**
+ * Transforms a lowered Load into a "real" one.
+ */
+static ir_node *gen_lowered_Load(ia32_transform_env_t *env, ir_node *node, construct_load_func func, char fp_unit) {
+ ir_node *block = transform_node(env, get_nodes_block(node));
+ ir_node *ptr = get_irn_n(node, 0);
+ ir_node *new_ptr = transform_node(env, ptr);
+ ir_node *mem = get_irn_n(node, 1);
+ ir_node *new_mem = transform_node(env, mem);
+ ir_graph *irg = env->irg;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_mode *mode = get_ia32_ls_mode(node);
+ ir_node *noreg = ia32_new_NoReg_gp(env->cg);
+ ir_node *new_op;
+
+ /*
+ Could be that we have SSE2 unit, but due to 64Bit Div/Conv
+ lowering we have x87 nodes, so we need to enforce simulation.
+ */
+ if (mode_is_float(mode)) {
+ FP_USED(env->cg);
+ if (fp_unit == fp_x87)
+ FORCE_x87(env->cg);
+ }
+
+ new_op = func(dbgi, irg, block, new_ptr, noreg, new_mem);
+
+ set_ia32_am_support(new_op, ia32_am_Source);
+ set_ia32_op_type(new_op, ia32_AddrModeS);
+ set_ia32_am_flavour(new_op, ia32_am_OB);
+ set_ia32_am_offs_int(new_op, 0);
+ set_ia32_am_scale(new_op, 1);
+ set_ia32_am_sc(new_op, get_ia32_am_sc(node));
+ if (is_ia32_am_sc_sign(node))
+ set_ia32_am_sc_sign(new_op);
+ set_ia32_ls_mode(new_op, get_ia32_ls_mode(node));
+ if (is_ia32_use_frame(node)) {
+ set_ia32_frame_ent(new_op, get_ia32_frame_ent(node));
+ set_ia32_use_frame(new_op);
+ }
+
+ SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, node));
+
+ return new_op;
+}
+
+/**
+* Transforms a lowered Store into a "real" one.
+*/
+static ir_node *gen_lowered_Store(ia32_transform_env_t *env, ir_node *node, construct_store_func func, char fp_unit) {
+ ir_node *block = transform_node(env, get_nodes_block(node));
+ ir_node *ptr = get_irn_n(node, 0);
+ ir_node *new_ptr = transform_node(env, ptr);
+ ir_node *val = get_irn_n(node, 1);
+ ir_node *new_val = transform_node(env, val);
+ ir_node *mem = get_irn_n(node, 2);
+ ir_node *new_mem = transform_node(env, mem);
+ ir_graph *irg = env->irg;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *noreg = ia32_new_NoReg_gp(env->cg);
+ ir_mode *mode = get_ia32_ls_mode(node);
+ ir_node *new_op;
+ long am_offs;
+ ia32_am_flavour_t am_flav = ia32_B;
+
+ /*
+ Could be that we have SSE2 unit, but due to 64Bit Div/Conv
+ lowering we have x87 nodes, so we need to enforce simulation.
+ */
+ if (mode_is_float(mode)) {
+ FP_USED(env->cg);
+ if (fp_unit == fp_x87)
+ FORCE_x87(env->cg);
+ }
+
+ new_op = func(dbgi, irg, block, new_ptr, noreg, new_val, new_mem);
+
+ if ((am_offs = get_ia32_am_offs_int(node)) != 0) {
+ am_flav |= ia32_O;
+ add_ia32_am_offs_int(new_op, am_offs);
+ }
+
+ set_ia32_am_support(new_op, ia32_am_Dest);
+ set_ia32_op_type(new_op, ia32_AddrModeD);
+ set_ia32_am_flavour(new_op, am_flav);
+ set_ia32_ls_mode(new_op, mode);
+ set_ia32_frame_ent(new_op, get_ia32_frame_ent(node));
+ set_ia32_use_frame(new_op);
+
+ SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, node));
+
+ return new_op;
+}
+
+
+/**
+ * Transforms an ia32_l_XXX into a "real" XXX node
+ *
+ * @param env The transformation environment
+ * @return the created ia32 XXX node
+ */
+#define GEN_LOWERED_OP(op) \
+ static ir_node *gen_ia32_l_##op(ia32_transform_env_t *env, ir_node *node) {\
+ ir_mode *mode = get_irn_mode(node); \
+ if (mode_is_float(mode)) \
+ FP_USED(env->cg); \
+ return gen_binop(env, node, get_binop_left(node), \
+ get_binop_right(node), new_rd_ia32_##op); \
+ }
+
+#define GEN_LOWERED_x87_OP(op) \
+ static ir_node *gen_ia32_l_##op(ia32_transform_env_t *env, ir_node *node) {\
+ ir_node *new_op; \
+ FORCE_x87(env->cg); \
+ new_op = gen_binop_float(env, node, get_binop_left(node), \
+ get_binop_right(node), new_rd_ia32_##op); \
+ return new_op; \
+ }
+
+#define GEN_LOWERED_UNOP(op) \
+ static ir_node *gen_ia32_l_##op(ia32_transform_env_t *env, ir_node *node) {\
+ return gen_unop(env, node, get_unop_op(node), new_rd_ia32_##op); \
+ }
+
+#define GEN_LOWERED_SHIFT_OP(op) \
+ static ir_node *gen_ia32_l_##op(ia32_transform_env_t *env, ir_node *node) {\
+ return gen_shift_binop(env, node, get_binop_left(node), \
+ get_binop_right(node), new_rd_ia32_##op); \
+ }
+
+#define GEN_LOWERED_LOAD(op, fp_unit) \
+ static ir_node *gen_ia32_l_##op(ia32_transform_env_t *env, ir_node *node) {\
+ return gen_lowered_Load(env, node, new_rd_ia32_##op, fp_unit); \
+ }
+
+#define GEN_LOWERED_STORE(op, fp_unit) \
+ static ir_node *gen_ia32_l_##op(ia32_transform_env_t *env, ir_node *node) {\
+ return gen_lowered_Store(env, node, new_rd_ia32_##op, fp_unit); \
+ }
+
+GEN_LOWERED_OP(Adc)
+GEN_LOWERED_OP(Add)
+GEN_LOWERED_OP(Sbb)
+GEN_LOWERED_OP(Sub)
+GEN_LOWERED_OP(IMul)
+GEN_LOWERED_OP(Xor)
+GEN_LOWERED_x87_OP(vfprem)
+GEN_LOWERED_x87_OP(vfmul)
+GEN_LOWERED_x87_OP(vfsub)
+
+GEN_LOWERED_UNOP(Neg)
+
+GEN_LOWERED_LOAD(vfild, fp_x87)
+GEN_LOWERED_LOAD(Load, fp_none)
+/*GEN_LOWERED_STORE(vfist, fp_x87)
+ *TODO
+ */
+GEN_LOWERED_STORE(Store, fp_none)
+
+static ir_node *gen_ia32_l_vfdiv(ia32_transform_env_t *env, ir_node *node) {
+ ir_node *block = transform_node(env, get_nodes_block(node));
+ ir_node *left = get_binop_left(node);
+ ir_node *new_left = transform_node(env, left);
+ ir_node *right = get_binop_right(node);
+ ir_node *new_right = transform_node(env, right);
+ ir_node *noreg = ia32_new_NoReg_gp(env->cg);
+ ir_graph *irg = env->irg;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *vfdiv;
+
+ vfdiv = new_rd_ia32_vfdiv(dbgi, irg, block, noreg, noreg, new_left, new_right, new_NoMem());
+ clear_ia32_commutative(vfdiv);
+ set_ia32_am_support(vfdiv, ia32_am_Source);
+ fold_immediate(env, vfdiv, 2, 3);