+/**
+ * Change some phi modes
+ */
+static ir_node *gen_Phi(ia32_transform_env_t *env, ir_node *node) {
+ ir_graph *irg = env->irg;
+ dbg_info *dbg = get_irn_dbg_info(node);
+ ir_mode *mode = get_irn_mode(node);
+ ir_node *block = transform_node(env, get_nodes_block(node));
+ ir_node *phi;
+ int i, arity;
+
+ if(mode_is_int(mode) || mode_is_reference(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);
+ // all float operations are on mode_E registers
+ mode = mode_E;
+ }
+
+ /* phi nodes allow loops, so we use the old arguments for now
+ * and fix this later */
+ phi = new_ir_node(dbg, 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_graph *irg = env->irg;
+ dbg_info *dbg = get_irn_dbg_info(node);
+ ir_node *block = transform_node(env, get_nodes_block(node));
+ ir_mode *mode = get_ia32_ls_mode(node);
+ ir_node *new_op;
+ ir_node *noreg = ia32_new_NoReg_gp(env->cg);
+ ir_node *ptr = get_irn_n(node, 0);
+ ir_node *mem = get_irn_n(node, 1);
+ ir_node *new_ptr = transform_node(env, ptr);
+ ir_node *new_mem = transform_node(env, mem);
+
+ /*
+ 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(dbg, 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_graph *irg = env->irg;
+ dbg_info *dbg = get_irn_dbg_info(node);
+ ir_node *block = transform_node(env, get_nodes_block(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;
+ ir_node *ptr = get_irn_n(node, 0);
+ ir_node *val = get_irn_n(node, 1);
+ ir_node *mem = get_irn_n(node, 2);
+ ir_node *new_ptr = transform_node(env, ptr);
+ ir_node *new_val = transform_node(env, val);
+ ir_node *new_mem = transform_node(env, mem);
+
+ /*
+ 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(dbg, 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)
+GEN_LOWERED_STORE(Store, fp_none)
+
+static ir_node *gen_ia32_l_vfdiv(ia32_transform_env_t *env, ir_node *node) {
+ ir_node *noreg = ia32_new_NoReg_gp(env->cg);
+ ir_graph *irg = env->irg;
+ dbg_info *dbg = get_irn_dbg_info(node);
+ ir_node *block = transform_node(env, get_nodes_block(node));
+ ir_node *left = get_binop_left(node);
+ ir_node *right = get_binop_right(node);
+ ir_node *new_left = transform_node(env, left);
+ ir_node *new_right = transform_node(env, right);
+ ir_node *vfdiv;
+
+ vfdiv = new_rd_ia32_vfdiv(dbg, 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);
+
+ SET_IA32_ORIG_NODE(vfdiv, ia32_get_old_node_name(env->cg, node));
+
+ FORCE_x87(env->cg);
+
+ return vfdiv;
+}
+
+/**
+ * Transforms a l_MulS into a "real" MulS node.
+ *
+ * @param env The transformation environment
+ * @return the created ia32 Mul node
+ */
+static ir_node *gen_ia32_l_Mul(ia32_transform_env_t *env, ir_node *node) {
+ ir_node *noreg = ia32_new_NoReg_gp(env->cg);
+ ir_graph *irg = env->irg;
+ dbg_info *dbg = get_irn_dbg_info(node);
+ ir_node *block = transform_node(env, get_nodes_block(node));
+ ir_node *left = get_binop_left(node);
+ ir_node *right = get_binop_right(node);
+ ir_node *new_left = transform_node(env, left);
+ ir_node *new_right = transform_node(env, right);
+ ir_node *in[2];
+
+ /* l_Mul is already a mode_T node, so we create the Mul in the normal way */
+ /* and then skip the result Proj, because all needed Projs are already there. */
+ ir_node *muls = new_rd_ia32_Mul(dbg, irg, block, noreg, noreg, new_left, new_right, new_NoMem());
+ clear_ia32_commutative(muls);
+ set_ia32_am_support(muls, ia32_am_Source);
+ fold_immediate(env, muls, 2, 3);
+
+ /* check if EAX and EDX proj exist, add missing one */
+ in[0] = new_rd_Proj(dbg, irg, block, muls, mode_Iu, pn_EAX);
+ in[1] = new_rd_Proj(dbg, irg, block, muls, mode_Iu, pn_EDX);
+ be_new_Keep(&ia32_reg_classes[CLASS_ia32_gp], irg, block, 2, in);
+
+ SET_IA32_ORIG_NODE(muls, ia32_get_old_node_name(env->cg, node));
+
+ return muls;
+}
+
+GEN_LOWERED_SHIFT_OP(Shl)
+GEN_LOWERED_SHIFT_OP(Shr)
+GEN_LOWERED_SHIFT_OP(Sar)
+
+/**
+ * Transforms a l_ShlD/l_ShrD into a ShlD/ShrD. Those nodes have 3 data inputs:
+ * op1 - target to be shifted
+ * op2 - contains bits to be shifted into target
+ * op3 - shift count
+ * Only op3 can be an immediate.
+ */
+static ir_node *gen_lowered_64bit_shifts(ia32_transform_env_t *env, ir_node *node,
+ ir_node *op1, ir_node *op2,
+ ir_node *count) {
+ ir_node *new_op = NULL;
+ ir_graph *irg = env->irg;
+ ir_mode *mode = get_irn_mode(node);
+ dbg_info *dbg = get_irn_dbg_info(node);
+ ir_node *block = transform_node(env, get_nodes_block(node));
+ ir_node *noreg = ia32_new_NoReg_gp(env->cg);
+ ir_node *nomem = new_NoMem();
+ ir_node *imm_op;
+ ir_node *new_op1 = transform_node(env, op1);
+ ir_node *new_op2 = transform_node(env, op2);
+ ir_node *new_count = transform_node(env, count);
+ tarval *tv;
+ DEBUG_ONLY(firm_dbg_module_t *mod = env->mod;)
+
+ assert(! mode_is_float(mode) && "Shift/Rotate with float not supported");
+
+ /* Check if immediate optimization is on and */
+ /* if it's an operation with immediate. */
+ imm_op = (env->cg->opt & IA32_OPT_IMMOPS) ? get_immediate_op(NULL, new_count) : NULL;
+
+ /* Limit imm_op within range imm8 */
+ if (imm_op) {
+ tv = get_ia32_Immop_tarval(imm_op);
+
+ if (tv) {
+ tv = tarval_mod(tv, new_tarval_from_long(32, get_tarval_mode(tv)));
+ set_ia32_Immop_tarval(imm_op, tv);
+ }
+ else {
+ imm_op = NULL;
+ }
+ }
+
+ /* integer operations */
+ if (imm_op) {
+ /* This is ShiftD with const */
+ DB((mod, LEVEL_1, "ShiftD with immediate ..."));
+
+ if (is_ia32_l_ShlD(node))
+ new_op = new_rd_ia32_ShlD(dbg, irg, block, noreg, noreg,
+ new_op1, new_op2, noreg, nomem);
+ else
+ new_op = new_rd_ia32_ShrD(dbg, irg, block, noreg, noreg,
+ new_op1, new_op2, noreg, nomem);
+ copy_ia32_Immop_attr(new_op, imm_op);
+ }
+ else {
+ /* This is a normal ShiftD */
+ DB((mod, LEVEL_1, "ShiftD binop ..."));
+ if (is_ia32_l_ShlD(node))
+ new_op = new_rd_ia32_ShlD(dbg, irg, block, noreg, noreg,
+ new_op1, new_op2, new_count, nomem);
+ else
+ new_op = new_rd_ia32_ShrD(dbg, irg, block, noreg, noreg,
+ new_op1, new_op2, new_count, nomem);
+ }
+
+ /* set AM support */
+ // Matze: node has unsupported format (6inputs)
+ //set_ia32_am_support(new_op, ia32_am_Dest);
+
+ SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, node));
+
+ set_ia32_emit_cl(new_op);
+
+ return new_op;
+}
+
+static ir_node *gen_ia32_l_ShlD(ia32_transform_env_t *env, ir_node *node) {
+ return gen_lowered_64bit_shifts(env, node, get_irn_n(node, 0),
+ get_irn_n(node, 1), get_irn_n(node, 2));
+}
+
+static ir_node *gen_ia32_l_ShrD(ia32_transform_env_t *env, ir_node *node) {
+ return gen_lowered_64bit_shifts(env, node, get_irn_n(node, 0),
+ get_irn_n(node, 1), get_irn_n(node, 2));
+}
+
+/**
+ * In case SSE Unit is used, the node is transformed into a vfst + xLoad.
+ */
+static ir_node *gen_ia32_l_X87toSSE(ia32_transform_env_t *env, ir_node *node) {
+ ia32_code_gen_t *cg = env->cg;
+ ir_node *res = NULL;
+ ir_graph *irg = env->irg;
+ dbg_info *dbg = get_irn_dbg_info(node);
+ ir_node *block = transform_node(env, get_nodes_block(node));
+ ir_node *ptr = get_irn_n(node, 0);
+ 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 *noreg, *new_ptr, *new_mem;
+
+ if (USE_SSE2(cg)) {
+ return new_val;
+ }
+
+ noreg = ia32_new_NoReg_gp(cg);
+ new_mem = transform_node(env, mem);
+ new_ptr = transform_node(env, ptr);
+
+ /* Store x87 -> MEM */
+ res = new_rd_ia32_vfst(dbg, irg, block, new_ptr, noreg, new_val, new_mem);
+ set_ia32_frame_ent(res, get_ia32_frame_ent(node));
+ set_ia32_use_frame(res);
+ set_ia32_ls_mode(res, get_ia32_ls_mode(node));
+ set_ia32_am_support(res, ia32_am_Dest);
+ set_ia32_am_flavour(res, ia32_B);
+ set_ia32_op_type(res, ia32_AddrModeD);
+
+ /* Load MEM -> SSE */
+ res = new_rd_ia32_xLoad(dbg, irg, block, new_ptr, noreg, res);
+ set_ia32_frame_ent(res, get_ia32_frame_ent(node));
+ set_ia32_use_frame(res);
+ set_ia32_ls_mode(res, get_ia32_ls_mode(node));
+ set_ia32_am_support(res, ia32_am_Source);
+ set_ia32_am_flavour(res, ia32_B);
+ set_ia32_op_type(res, ia32_AddrModeS);
+ res = new_rd_Proj(dbg, irg, block, res, mode_E, pn_ia32_xLoad_res);
+
+ return res;
+}
+
+/**
+ * In case SSE Unit is used, the node is transformed into a xStore + vfld.
+ */
+static ir_node *gen_ia32_l_SSEtoX87(ia32_transform_env_t *env, ir_node *node) {
+ ia32_code_gen_t *cg = env->cg;
+ ir_graph *irg = env->irg;
+ dbg_info *dbg = get_irn_dbg_info(node);
+ ir_node *block = transform_node(env, get_nodes_block(node));
+ ir_node *res = NULL;
+ ir_node *ptr = get_irn_n(node, 0);
+ ir_node *val = get_irn_n(node, 1);
+ ir_node *mem = get_irn_n(node, 2);
+ ir_entity *fent = get_ia32_frame_ent(node);
+ ir_mode *lsmode = get_ia32_ls_mode(node);
+ ir_node *new_val = transform_node(env, val);
+ ir_node *noreg, *new_ptr, *new_mem;
+ int offs = 0;
+
+ if (!USE_SSE2(cg)) {
+ /* SSE unit is not used -> skip this node. */
+ return new_val;
+ }
+
+ noreg = ia32_new_NoReg_gp(cg);
+ new_val = transform_node(env, val);
+ new_ptr = transform_node(env, ptr);
+ new_mem = transform_node(env, mem);
+
+ /* Store SSE -> MEM */
+ if (is_ia32_xLoad(skip_Proj(new_val))) {
+ ir_node *ld = skip_Proj(new_val);
+
+ /* we can vfld the value directly into the fpu */
+ fent = get_ia32_frame_ent(ld);
+ ptr = get_irn_n(ld, 0);
+ offs = get_ia32_am_offs_int(ld);
+ } else {
+ res = new_rd_ia32_xStore(dbg, irg, block, new_ptr, noreg, new_val, new_mem);
+ set_ia32_frame_ent(res, fent);
+ set_ia32_use_frame(res);
+ set_ia32_ls_mode(res, lsmode);
+ set_ia32_am_support(res, ia32_am_Dest);
+ set_ia32_am_flavour(res, ia32_B);
+ set_ia32_op_type(res, ia32_AddrModeD);
+ mem = res;
+ }
+
+ /* Load MEM -> x87 */
+ res = new_rd_ia32_vfld(dbg, irg, block, new_ptr, noreg, new_mem);
+ set_ia32_frame_ent(res, fent);
+ set_ia32_use_frame(res);
+ set_ia32_ls_mode(res, lsmode);
+ add_ia32_am_offs_int(res, offs);
+ set_ia32_am_support(res, ia32_am_Source);
+ set_ia32_am_flavour(res, ia32_B);
+ set_ia32_op_type(res, ia32_AddrModeS);
+ res = new_rd_Proj(dbg, irg, block, res, lsmode, pn_ia32_vfld_res);
+
+ return res;
+}