+/**
+ * Transforms a lowered Load into a "real" one.
+ */
+static ir_node *gen_lowered_Load(ia32_transform_env_t *env, construct_load_func func, char fp_unit) {
+ ir_node *node = env->irn;
+ ir_node *noreg = ia32_new_NoReg_gp(env->cg);
+ ir_mode *mode = get_ia32_ls_mode(node);
+ ir_node *new_op;
+ char *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(env->dbg, env->irg, env->block, get_irn_n(node, 0), noreg, get_irn_n(node, 1));
+ am_offs = get_ia32_am_offs(node);
+
+ if (am_offs) {
+ am_flav |= ia32_O;
+ add_ia32_am_offs(new_op, am_offs);
+ }
+
+ set_ia32_am_support(new_op, ia32_am_Source);
+ set_ia32_op_type(new_op, ia32_AddrModeS);
+ 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 a lowered Store into a "real" one.
+*/
+static ir_node *gen_lowered_Store(ia32_transform_env_t *env, construct_store_func func, char fp_unit) {
+ ir_node *node = env->irn;
+ ir_node *noreg = ia32_new_NoReg_gp(env->cg);
+ ir_mode *mode = get_ia32_ls_mode(node);
+ ir_node *new_op;
+ char *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(env->dbg, env->irg, env->block, get_irn_n(node, 0), noreg, get_irn_n(node, 1), get_irn_n(node, 2));
+
+ if (am_offs = get_ia32_am_offs(node)) {
+ am_flav |= ia32_O;
+ add_ia32_am_offs(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) { \
+ if (mode_is_float(env->mode)) \
+ FP_USED(env->cg); \
+ return gen_binop(env, get_binop_left(env->irn), get_binop_right(env->irn), new_rd_ia32_##op); \
+ }
+
+#define GEN_LOWERED_x87_OP(op) \
+ static ir_node *gen_ia32_l_##op(ia32_transform_env_t *env) { \
+ ir_node *new_op; \
+ FORCE_x87(env->cg); \
+ new_op = gen_binop(env, get_binop_left(env->irn), get_binop_right(env->irn), new_rd_ia32_##op); \
+ set_ia32_am_support(get_Proj_pred(new_op), ia32_am_None); \
+ return new_op; \
+ }
+
+#define GEN_LOWERED_UNOP(op) \
+ static ir_node *gen_ia32_l_##op(ia32_transform_env_t *env) { \
+ return gen_unop(env, get_unop_op(env->irn), new_rd_ia32_##op); \
+ }
+
+#define GEN_LOWERED_SHIFT_OP(op) \
+ static ir_node *gen_ia32_l_##op(ia32_transform_env_t *env) { \
+ return gen_shift_binop(env, get_binop_left(env->irn), get_binop_right(env->irn), new_rd_ia32_##op); \
+ }
+
+#define GEN_LOWERED_LOAD(op, fp_unit) \
+ static ir_node *gen_ia32_l_##op(ia32_transform_env_t *env) { \
+ return gen_lowered_Load(env, 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) { \
+ return gen_lowered_Store(env, new_rd_ia32_##op, fp_unit); \
+}
+
+GEN_LOWERED_OP(AddC)
+GEN_LOWERED_OP(Add)
+GEN_LOWERED_OP(SubC)
+GEN_LOWERED_OP(Sub)
+GEN_LOWERED_OP(Mul)
+GEN_LOWERED_OP(Eor)
+GEN_LOWERED_x87_OP(vfdiv)
+GEN_LOWERED_x87_OP(vfmul)
+GEN_LOWERED_x87_OP(vfsub)
+
+GEN_LOWERED_UNOP(Minus)
+
+GEN_LOWERED_LOAD(vfild, fp_x87)
+GEN_LOWERED_LOAD(Load, fp_none)
+GEN_LOWERED_STORE(vfist, fp_x87)
+GEN_LOWERED_STORE(Store, fp_none)
+
+/**
+ * Transforms a l_MulS into a "real" MulS node.
+ *
+ * @param env The transformation environment
+ * @return the created ia32 MulS node
+ */
+static ir_node *gen_ia32_l_MulS(ia32_transform_env_t *env) {
+
+ /* l_MulS is already a mode_T node, so we create the MulS in the normal way */
+ /* and then skip the result Proj, because all needed Projs are already there. */
+
+ ir_node *new_op = gen_binop(env, get_binop_left(env->irn), get_binop_right(env->irn), new_rd_ia32_MulS);
+ ir_node *muls = get_Proj_pred(new_op);
+
+ /* MulS cannot have AM for destination */
+ if (get_ia32_am_support(muls) != ia32_am_None)
+ set_ia32_am_support(muls, ia32_am_Source);
+
+ return muls;
+}
+
+GEN_LOWERED_SHIFT_OP(Shl)
+GEN_LOWERED_SHIFT_OP(Shr)
+GEN_LOWERED_SHIFT_OP(Shrs)
+
+/**
+ * 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 *op1, ir_node *op2, ir_node *count) {
+ ir_node *new_op = NULL;
+ ir_mode *mode = env->mode;
+ dbg_info *dbg = env->dbg;
+ ir_graph *irg = env->irg;
+ ir_node *block = env->block;
+ ir_node *noreg = ia32_new_NoReg_gp(env->cg);
+ ir_node *nomem = new_NoMem();
+ ir_node *imm_op;
+ 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, 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, mode_Iu));
+ 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(env->irn))
+ new_op = new_rd_ia32_ShlD(dbg, irg, block, noreg, noreg, op1, op2, noreg, nomem);
+ else
+ new_op = new_rd_ia32_ShrD(dbg, irg, block, noreg, noreg, op1, op2, noreg, nomem);
+ set_ia32_Immop_attr(new_op, imm_op);
+ }
+ else {
+ /* This is a normal ShiftD */
+ DB((mod, LEVEL_1, "ShiftD binop ..."));
+ if (is_ia32_l_ShlD(env->irn))
+ new_op = new_rd_ia32_ShlD(dbg, irg, block, noreg, noreg, op1, op2, count, nomem);
+ else
+ new_op = new_rd_ia32_ShrD(dbg, irg, block, noreg, noreg, op1, op2, count, nomem);
+ }
+
+ /* set AM support */
+ set_ia32_am_support(new_op, ia32_am_Dest);
+
+ SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, env->irn));
+
+ set_ia32_res_mode(new_op, mode);
+ set_ia32_emit_cl(new_op);
+
+ return new_rd_Proj(dbg, irg, block, new_op, mode, 0);
+}
+
+static ir_node *gen_ia32_l_ShlD(ia32_transform_env_t *env) {
+ return gen_lowered_64bit_shifts(env, get_irn_n(env->irn, 0), get_irn_n(env->irn, 1), get_irn_n(env->irn, 2));
+}
+
+static ir_node *gen_ia32_l_ShrD(ia32_transform_env_t *env) {
+ return gen_lowered_64bit_shifts(env, get_irn_n(env->irn, 0), get_irn_n(env->irn, 1), get_irn_n(env->irn, 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) {
+ ia32_code_gen_t *cg = env->cg;
+ ir_node *res = NULL;
+ ir_node *ptr = get_irn_n(env->irn, 0);
+ ir_node *val = get_irn_n(env->irn, 1);
+ ir_node *mem = get_irn_n(env->irn, 2);
+
+ if (USE_SSE2(cg)) {
+ ir_node *noreg = ia32_new_NoReg_gp(cg);
+
+ /* Store x87 -> MEM */
+ res = new_rd_ia32_vfst(env->dbg, env->irg, env->block, ptr, noreg, val, mem);
+ set_ia32_frame_ent(res, get_ia32_frame_ent(env->irn));
+ set_ia32_use_frame(res);
+ set_ia32_ls_mode(res, get_ia32_ls_mode(env->irn));
+ set_ia32_am_support(res, ia32_am_Dest);
+ set_ia32_am_flavour(res, ia32_B);
+ res = new_rd_Proj(env->dbg, env->irg, env->block, res, mode_M, pn_ia32_vfst_M);
+
+ /* Load MEM -> SSE */
+ res = new_rd_ia32_xLoad(env->dbg, env->irg, env->block, ptr, noreg, res);
+ set_ia32_frame_ent(res, get_ia32_frame_ent(env->irn));
+ set_ia32_use_frame(res);
+ set_ia32_ls_mode(res, get_ia32_ls_mode(env->irn));
+ set_ia32_am_support(res, ia32_am_Source);
+ set_ia32_am_flavour(res, ia32_B);
+ res = new_rd_Proj(env->dbg, env->irg, env->block, res, get_ia32_ls_mode(env->irn), pn_ia32_xLoad_res);
+ }
+ else {
+ /* SSE unit is not used -> skip this node. */
+ int i;
+
+ edges_reroute(env->irn, val, env->irg);
+ for (i = get_irn_arity(env->irn) - 1; i >= 0; i--)
+ set_irn_n(env->irn, i, get_irg_bad(env->irg));
+ }
+
+ 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) {
+ ia32_code_gen_t *cg = env->cg;
+ ir_node *res = NULL;
+ ir_node *ptr = get_irn_n(env->irn, 0);
+ ir_node *val = get_irn_n(env->irn, 1);
+ ir_node *mem = get_irn_n(env->irn, 2);
+
+ if (USE_SSE2(cg)) {
+ ir_node *noreg = ia32_new_NoReg_gp(cg);
+
+ /* Store SSE -> MEM */
+ res = new_rd_ia32_xStore(env->dbg, env->irg, env->block, ptr, noreg, val, mem);
+ set_ia32_frame_ent(res, get_ia32_frame_ent(env->irn));
+ set_ia32_use_frame(res);
+ set_ia32_ls_mode(res, get_ia32_ls_mode(env->irn));
+ set_ia32_am_support(res, ia32_am_Dest);
+ set_ia32_am_flavour(res, ia32_B);
+ res = new_rd_Proj(env->dbg, env->irg, env->block, res, mode_M, pn_ia32_xStore_M);
+
+ /* Load MEM -> x87 */
+ res = new_rd_ia32_vfld(env->dbg, env->irg, env->block, ptr, noreg, mem);
+ set_ia32_frame_ent(res, get_ia32_frame_ent(env->irn));
+ set_ia32_use_frame(res);
+ set_ia32_ls_mode(res, get_ia32_ls_mode(env->irn));
+ set_ia32_am_support(res, ia32_am_Source);
+ set_ia32_am_flavour(res, ia32_B);
+ res = new_rd_Proj(env->dbg, env->irg, env->block, res, get_ia32_ls_mode(env->irn), pn_ia32_vfld_res);
+ }
+ else {
+ /* SSE unit is not used -> skip this node. */
+ int i;
+
+ edges_reroute(env->irn, val, env->irg);
+ for (i = get_irn_arity(env->irn) - 1; i >= 0; i--)
+ set_irn_n(env->irn, i, get_irg_bad(env->irg));
+ }
+
+ return res;
+}