+
+ SET_IA32_ORIG_NODE(new_op, get_old_node_name(env));
+
+ return new_op;
+}
+
+
+/**
+ * Following conversion rules apply:
+ *
+ * INT -> INT
+ * ============
+ * 1) n bit -> m bit n < m (upscale)
+ * always ignored
+ * 2) n bit -> m bit n == m (sign change)
+ * always ignored
+ * 3) n bit -> m bit n > m (downscale)
+ * a) Un -> Um = AND Un, (1 << m) - 1
+ * b) Sn -> Um same as a)
+ * c) Un -> Sm same as a)
+ * d) Sn -> Sm = ASHL Sn, (n - m); ASHR Sn, (n - m)
+ *
+ * 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)
+ * if target mode < 32bit: additional INT -> INT conversion (see above)
+ *
+ * FLOAT -> FLOAT
+ * ================
+ * SSE(1/2) convert from float or double to double or float (cvtss/sd2sd/ss)
+ */
+
+static ir_node *gen_int_downscale_conv(ia32_transform_env_t *env, ir_node *op,
+ ir_mode *src_mode, ir_mode *tgt_mode)
+{
+ int n = get_mode_size_bits(src_mode);
+ int m = get_mode_size_bits(tgt_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_rd_NoMem(irg);
+ ir_node *new_op, *proj;
+
+ assert(n > m && "downscale expected");
+
+ if (mode_is_signed(src_mode) && mode_is_signed(tgt_mode)) {
+ /* ASHL Sn, n - m */
+ new_op = new_rd_ia32_Shl(dbg, irg, block, noreg, noreg, op, noreg, nomem, mode_T);
+ proj = new_rd_Proj(dbg, irg, block, new_op, src_mode, 0);
+ set_ia32_Immop_tarval(new_op, new_tarval_from_long(n - m, mode_Is));
+ set_ia32_am_support(new_op, ia32_am_Source);
+ SET_IA32_ORIG_NODE(new_op, get_old_node_name(env));
+
+ /* ASHR Sn, n - m */
+ new_op = new_rd_ia32_Shrs(dbg, irg, block, noreg, noreg, proj, noreg, nomem, mode_T);
+ set_ia32_Immop_tarval(new_op, new_tarval_from_long(n - m, mode_Is));
+ }
+ else {
+ new_op = new_rd_ia32_And(dbg, irg, block, noreg, noreg, op, noreg, nomem, mode_T);
+ set_ia32_Immop_tarval(new_op, new_tarval_from_long((1 << m) - 1, mode_Is));
+ }
+
+ return new_op;
+}
+
+/**
+ * Transforms a Conv node.
+ *
+ * @param env The transformation environment
+ * @param op The operator
+ * @return The created ia32 Conv node
+ */
+static ir_node *gen_Conv(ia32_transform_env_t *env, ir_node *op) {
+ dbg_info *dbg = env->dbg;
+ ir_graph *irg = env->irg;
+ ir_mode *src_mode = get_irn_mode(op);
+ ir_mode *tgt_mode = env->mode;
+ ir_node *block = env->block;
+ ir_node *new_op = NULL;
+ ir_node *noreg = ia32_new_NoReg_gp(env->cg);
+ ir_node *nomem = new_rd_NoMem(irg);
+ firm_dbg_module_t *mod = env->mod;
+ ir_node *proj;
+
+ if (src_mode == tgt_mode) {
+ /* this can happen when changing mode_P to mode_Is */
+ DB((mod, LEVEL_1, "killed Conv(mode, mode) ..."));
+ edges_reroute(env->irn, op, irg);
+ }
+ else if (mode_is_float(src_mode)) {
+ /* we convert from float ... */
+ if (mode_is_float(tgt_mode)) {
+ /* ... to float */
+ DB((mod, LEVEL_1, "create Conv(float, float) ..."));
+ new_op = new_rd_ia32_Conv_FP2FP(dbg, irg, block, noreg, noreg, op, nomem, mode_T);
+ }
+ else {
+ /* ... to int */
+ DB((mod, LEVEL_1, "create Conv(float, int) ..."));
+ new_op = new_rd_ia32_Conv_FP2I(dbg, irg, block, noreg, noreg, op, nomem, mode_T);
+ /* if target mode is not int: add an additional downscale convert */
+ if (get_mode_size_bits(tgt_mode) < 32) {
+ SET_IA32_ORIG_NODE(new_op, get_old_node_name(env));
+ set_ia32_res_mode(new_op, tgt_mode);
+ set_ia32_am_support(new_op, ia32_am_Source);
+
+ proj = new_rd_Proj(dbg, irg, block, new_op, mode_Is, 0);
+ new_op = gen_int_downscale_conv(env, proj, src_mode, tgt_mode);
+ }
+ }
+ }
+ else {
+ /* we convert from int ... */
+ if (mode_is_float(tgt_mode)) {
+ /* ... to float */
+ DB((mod, LEVEL_1, "create Conv(int, float) ..."));
+ new_op = new_rd_ia32_Conv_I2FP(dbg, irg, block, noreg, noreg, op, nomem, mode_T);
+ }
+ else {
+ /* ... to int */
+ if (get_mode_size_bits(src_mode) <= get_mode_size_bits(tgt_mode)) {
+ DB((mod, LEVEL_1, "omitting upscale Conv(%+F, %+F) ...", src_mode, tgt_mode));
+ edges_reroute(env->irn, op, irg);
+ }
+ else {
+ DB((mod, LEVEL_1, "create downscale Conv(%+F, %+F) ...", src_mode, tgt_mode));
+ new_op = gen_int_downscale_conv(env, op, src_mode, tgt_mode);
+ }
+ }
+ }
+
+ if (new_op) {
+ SET_IA32_ORIG_NODE(new_op, get_old_node_name(env));
+ set_ia32_res_mode(new_op, tgt_mode);
+
+ set_ia32_am_support(new_op, ia32_am_Source);
+
+ new_op = new_rd_Proj(dbg, irg, block, new_op, tgt_mode, 0);
+ }
+
+ return new_op;
+}
+
+
+
+/********************************************
+ * _ _
+ * | | | |
+ * | |__ ___ _ __ ___ __| | ___ ___
+ * | '_ \ / _ \ '_ \ / _ \ / _` |/ _ \/ __|
+ * | |_) | __/ | | | (_) | (_| | __/\__ \
+ * |_.__/ \___|_| |_|\___/ \__,_|\___||___/
+ *
+ ********************************************/
+
+static ir_node *gen_StackParam(ia32_transform_env_t *env) {
+ ir_node *new_op = NULL;
+ ir_node *node = env->irn;
+ ir_node *noreg = ia32_new_NoReg_gp(env->cg);
+ ir_node *mem = new_rd_NoMem(env->irg);
+ ir_node *ptr = get_irn_n(node, 0);
+ entity *ent = be_get_frame_entity(node);
+ ir_mode *mode = env->mode;
+
+ if (mode_is_float(mode)) {
+ new_op = new_rd_ia32_fLoad(env->dbg, env->irg, env->block, ptr, noreg, mem, mode_T);
+ }
+ else {
+ new_op = new_rd_ia32_Load(env->dbg, env->irg, env->block, ptr, noreg, mem, mode_T);
+ }
+
+ 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_B);
+ set_ia32_ls_mode(new_op, mode);
+
+ SET_IA32_ORIG_NODE(new_op, get_old_node_name(env));
+
+ return new_rd_Proj(env->dbg, env->irg, env->block, new_op, mode, 0);
+}
+
+/**
+ * Transforms a FrameAddr into an ia32 Add.
+ */
+static ir_node *gen_FrameAddr(ia32_transform_env_t *env) {
+ ir_node *new_op = NULL;
+ ir_node *node = env->irn;
+ ir_node *op = get_irn_n(node, 0);
+ ir_node *noreg = ia32_new_NoReg_gp(env->cg);
+ ir_node *nomem = new_rd_NoMem(env->irg);
+
+ new_op = new_rd_ia32_Add(env->dbg, env->irg, env->block, noreg, noreg, op, noreg, nomem, mode_T);
+ set_ia32_frame_ent(new_op, be_get_frame_entity(node));
+ set_ia32_am_support(new_op, ia32_am_Full);
+ set_ia32_use_frame(new_op);
+
+ SET_IA32_ORIG_NODE(new_op, get_old_node_name(env));
+
+ return new_rd_Proj(env->dbg, env->irg, env->block, new_op, env->mode, 0);
+}
+
+/**
+ * Transforms a FrameLoad into an ia32 Load.
+ */
+static ir_node *gen_FrameLoad(ia32_transform_env_t *env) {
+ ir_node *new_op = NULL;
+ ir_node *node = env->irn;
+ ir_node *noreg = ia32_new_NoReg_gp(env->cg);
+ ir_node *mem = get_irn_n(node, 0);
+ ir_node *ptr = get_irn_n(node, 1);
+ entity *ent = be_get_frame_entity(node);
+ ir_mode *mode = get_type_mode(get_entity_type(ent));
+
+ if (mode_is_float(mode)) {
+ new_op = new_rd_ia32_fLoad(env->dbg, env->irg, env->block, ptr, noreg, mem, mode_T);
+ }
+ else {
+ new_op = new_rd_ia32_Load(env->dbg, env->irg, env->block, ptr, noreg, mem, mode_T);
+ }
+
+ 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_B);
+ set_ia32_ls_mode(new_op, mode);
+
+ SET_IA32_ORIG_NODE(new_op, get_old_node_name(env));
+
+ return new_op;
+}
+
+
+/**
+ * Transforms a FrameStore into an ia32 Store.
+ */
+static ir_node *gen_FrameStore(ia32_transform_env_t *env) {
+ ir_node *new_op = NULL;
+ ir_node *node = env->irn;
+ ir_node *noreg = ia32_new_NoReg_gp(env->cg);
+ ir_node *mem = get_irn_n(node, 0);
+ ir_node *ptr = get_irn_n(node, 1);
+ ir_node *val = get_irn_n(node, 2);
+ entity *ent = be_get_frame_entity(node);
+ ir_mode *mode = get_irn_mode(val);
+
+ if (mode_is_float(mode)) {
+ new_op = new_rd_ia32_fStore(env->dbg, env->irg, env->block, ptr, noreg, val, mem, mode_T);
+ }
+ else {
+ new_op = new_rd_ia32_Store(env->dbg, env->irg, env->block, ptr, noreg, val, mem, mode_T);
+ }
+
+ 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_B);
+ set_ia32_ls_mode(new_op, mode);
+
+ SET_IA32_ORIG_NODE(new_op, get_old_node_name(env));
+
+ return new_op;