fixed some bugs
[libfirm] / ir / be / ia32 / ia32_transform.c
index 517d12d..f0a7543 100644 (file)
@@ -5,12 +5,14 @@
 #include "irnode_t.h"
 #include "irgraph_t.h"
 #include "irmode_t.h"
+#include "iropt_t.h"
+#include "irop_t.h"
+#include "irprog_t.h"
 #include "irgmod.h"
 #include "iredges.h"
 #include "irvrfy.h"
 #include "ircons.h"
 #include "dbginfo.h"
-#include "iropt_t.h"
 #include "debug.h"
 
 #include "../benode_t.h"
@@ -20,7 +22,6 @@
 #include "../arch/archop.h"     /* we need this for Min and Max nodes */
 #include "ia32_transform.h"
 #include "ia32_new_nodes.h"
-#include "ia32_map_regs.h"
 
 #include "gen_ia32_regalloc_if.h"
 
@@ -146,19 +147,17 @@ static char *gen_fp_known_const(ir_mode *mode, ia32_known_const_t kct) {
 }
 
 
-#undef is_cnst
-#define is_cnst(op) (is_ia32_Const(op) || is_ia32_fConst(op))
 
 /* determine if one operator is an Imm */
 static ir_node *get_immediate_op(ir_node *op1, ir_node *op2) {
        if (op1)
-               return is_cnst(op1) ? op1 : (is_cnst(op2) ? op2 : NULL);
-       else return is_cnst(op2) ? op2 : NULL;
+               return is_ia32_Cnst(op1) ? op1 : (is_ia32_Cnst(op2) ? op2 : NULL);
+       else return is_ia32_Cnst(op2) ? op2 : NULL;
 }
 
 /* determine if one operator is not an Imm */
 static ir_node *get_expr_op(ir_node *op1, ir_node *op2) {
-       return !is_cnst(op1) ? op1 : (!is_cnst(op2) ? op2 : NULL);
+       return !is_ia32_Cnst(op1) ? op1 : (!is_ia32_Cnst(op2) ? op2 : NULL);
 }
 
 
@@ -232,6 +231,10 @@ static ir_node *gen_binop(ia32_transform_env_t *env, ir_node *op1, ir_node *op2,
                }
        }
 
+       if (is_op_commutative(get_irn_op(env->irn))) {
+               set_ia32_commutative(new_op);
+       }
+
        return new_rd_Proj(dbg, irg, block, new_op, mode, 0);
 }
 
@@ -458,7 +461,7 @@ static ir_node *gen_Add(ia32_transform_env_t *env, ir_node *op1, ir_node *op2) {
  * @param mode      node mode
  * @return the created ia32 Mul node
  */
-ir_node *gen_Mul(ia32_transform_env_t *env, ir_node *op1, ir_node *op2) {
+static ir_node *gen_Mul(ia32_transform_env_t *env, ir_node *op1, ir_node *op2) {
        ir_node *new_op;
 
        if (mode_is_float(env->mode)) {
@@ -1107,6 +1110,10 @@ static ir_node *gen_Load(ia32_transform_env_t *env) {
        }
 
        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, get_Load_mode(node));
+
        return new_op;
 }
 
@@ -1121,19 +1128,36 @@ static ir_node *gen_Load(ia32_transform_env_t *env) {
  * @param mode    node mode
  * @return the created ia32 Store node
  */
-ir_node *gen_Store(ia32_transform_env_t *env) {
+static ir_node *gen_Store(ia32_transform_env_t *env) {
        ir_node *node  = env->irn;
        ir_node *noreg = ia32_new_NoReg_gp(env->cg);
+       ir_node *val   = get_Store_value(node);
+       ir_node *ptr   = get_Store_ptr(node);
+       ir_node *mem   = get_Store_mem(node);
+       ir_node *sval  = val;
        ir_node *new_op;
 
+       /* in case of storing a const -> make it an attribute */
+       if (is_ia32_Cnst(val)) {
+               sval = noreg;
+       }
+
        if (mode_is_float(env->mode)) {
-               new_op = new_rd_ia32_fStore(env->dbg, env->irg, env->block, get_Store_ptr(node), noreg, get_Store_value(node), get_Store_mem(node), env->mode);
+               new_op = new_rd_ia32_fStore(env->dbg, env->irg, env->block, ptr, noreg, sval, mem, env->mode);
        }
        else {
-               new_op = new_rd_ia32_Store(env->dbg, env->irg, env->block, get_Store_ptr(node), noreg, get_Store_value(node), get_Store_mem(node), env->mode);
+               new_op = new_rd_ia32_Store(env->dbg, env->irg, env->block, ptr, noreg, sval, mem, env->mode);
+       }
+
+       /* stored const is an attribute (saves a register) */
+       if (is_ia32_Cnst(val)) {
+               set_ia32_Immop_attr(new_op, val);
        }
 
        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, get_irn_mode(val));
        return new_op;
 }
 
@@ -1142,128 +1166,10 @@ ir_node *gen_Store(ia32_transform_env_t *env) {
 /**
  * Transforms a Call and its arguments corresponding to the calling convention.
  *
- * @param mod     the debug module
- * @param block   the block the new node should belong to
- * @param node    the ir Call node
- * @param dummy   mode doesn't matter
- * @return the created ia32 Call node
+ * @param env   The transformation environment
+ * @return The created ia32 Call node
  */
 static ir_node *gen_Call(ia32_transform_env_t *env) {
-#if 0
-       const ia32_register_req_t **in_req;
-       ir_node          **in;
-       ir_node           *new_call, *sync;
-       int                i, j, n_new_call_in, ignore = 0;
-       ia32_attr_t       *attr;
-       dbg_info          *dbg          = env->dbg;
-       ir_graph          *irg          = env->irg;
-       ir_node           *block        = env->block;
-       ir_node           *call         = env->irn;
-       ir_node          **stack_param  = NULL;
-       ir_node          **param        = get_Call_param_arr(call);
-       ir_node           *call_Mem     = get_Call_mem(call);
-       unsigned           cc           = get_method_calling_convention(get_Call_type(call));
-       int                n            = get_Call_n_params(call);
-       int                stack_idx    = 0;
-       int                biggest_n    = -1;
-       int                n_res        = get_method_n_ress(get_Call_type(call));
-
-       assert(n_res <= 2 && "method with more than two results not supported");
-
-       if (cc & cc_reg_param)
-               biggest_n = ia32_get_n_regparam_class(n, param, &ignore, &ignore);
-
-       /* remember: biggest_n = x means we can pass (x + 1) parameters in register */
-
-       /* do we need to pass arguments on stack? */
-       if (biggest_n + 1 < n)
-               stack_param = xcalloc(n - biggest_n - 1, sizeof(ir_node *));
-
-       /* we need at least one in, either for the stack params or the call_Mem */
-       n_new_call_in = biggest_n + 2;
-
-       /* the call has one IN for all stack parameter and one IN for each reg param */
-       in     = xcalloc(n_new_call_in, sizeof(ir_node *));
-       in_req = xcalloc(n_new_call_in, sizeof(arch_register_req_t *));
-
-       /* loop over all parameters and set the register requirements */
-       for (i = 0; i <= biggest_n && (cc & cc_reg_param); i++) {
-               in_req[i] = ia32_get_RegParam_req(n, param, i, cc);
-       }
-       stack_idx = i;
-
-       /* create remaining stack parameters */
-       if (cc & cc_last_on_top) {
-               for (i = stack_idx; i < n; i++) {
-                       /* pass it on stack */
-                       if (mode_is_float(get_irn_mode(param[i]))) {
-                               stack_param[i - stack_idx] = new_rd_ia32_fStackArg(get_irn_dbg_info(param[i]), irg,
-                                                                                                               block, call_Mem, param[i], mode_M);
-                       }
-                       else {
-                               stack_param[i - stack_idx] = new_rd_ia32_StackArg(get_irn_dbg_info(param[i]), irg,
-                                                                                                               block, call_Mem, param[i], mode_M);
-                       }
-                       /* set the argument number for later lowering */
-                       set_ia32_pncode(stack_param[i - stack_idx], i - stack_idx);
-               }
-       }
-       else {
-               for (i = n - 1, j = 0; i >= stack_idx; i--, j++) {
-                       /* pass it on stack */
-                       if (mode_is_float(get_irn_mode(param[i]))) {
-                               stack_param[j] = new_rd_ia32_fStackArg(get_irn_dbg_info(param[i]), irg,
-                                                                                                               block, call_Mem, param[i], mode_M);
-                       }
-                       else {
-                               stack_param[j] = new_rd_ia32_StackArg(get_irn_dbg_info(param[i]), irg,
-                                                                                                               block, call_Mem, param[i], mode_M);
-                       }
-                       /* set the argument number for later lowering */
-                       set_ia32_pncode(stack_param[j], j);
-               }
-       }
-
-       if (stack_param) {
-               sync = new_r_Sync(irg, block, n - biggest_n - 1, stack_param);
-               in[n_new_call_in - 1] = sync;
-       }
-       else {
-               in[n_new_call_in - 1] = call_Mem;
-       }
-
-       /* create the new node */
-       new_call = new_rd_ia32_Call(dbg, irg, block, n_new_call_in, in);
-       set_ia32_Immop_attr(new_call, get_Call_ptr(call));
-
-       /* set register requirements for in and out */
-       attr             = get_ia32_attr(new_call);
-       attr->in_req     = in_req;
-
-       set_ia32_n_res(new_call, n_res);
-
-       if (n_res > 0) {
-               attr->out_req    = xcalloc(n_res, sizeof(ia32_register_req_t *));
-               attr->slots      = xcalloc(n_res, sizeof(arch_register_t *));
-       }
-
-       /* two results only appear when a 64bit int result is broken up into two 32bit results */
-       if (n_res == 1) {
-               if (mode_is_float(get_type_mode(get_method_res_type(get_Call_type(call), 0))))
-                       attr->out_req[0] = &ia32_default_req_ia32_fp_xmm0;
-               else
-                       attr->out_req[0] = &ia32_default_req_ia32_gp_eax;
-       }
-       else if (n_res == 2) {
-               attr->out_req[0] = &ia32_default_req_ia32_gp_eax;
-               attr->out_req[1] = &ia32_default_req_ia32_gp_edx;
-       }
-
-       /* stack parameter has no OUT register */
-       attr->in_req[n_new_call_in - 1] = &ia32_default_req_none;
-
-       return new_call;
-#endif
 }
 
 
@@ -1319,131 +1225,89 @@ static ir_node *gen_Cond(ia32_transform_env_t *env) {
 
 
 /**
- * Transform the argument projs from a start node corresponding to the
- * calling convention.
- * It transforms "Proj Arg x -> ProjT -> Start <- ProjM" into
- * "RegParam x   -> ProjT -> Start" OR
- * "StackParam x -> ProjM -> Start"
- * whether parameter is passed in register or on stack.
+ * Transforms a CopyB node.
  *
- * @param mod     the debug module
- * @param block   the block the nodes should belong to
- * @param proj    the ProjT node which points to Start
- * @param start   the Start node
- * @return Should be always NULL
+ * @param env   The transformation environment
+ * @return The transformed node.
  */
-static ir_node *gen_Proj_Start(ia32_transform_env_t *env, ir_node *proj, ir_node *start) {
-#if 0
-       const ia32_register_req_t *temp_req;
-       const ir_edge_t   *edge;
-       ir_node           *succ, *irn;
-       ir_node          **projargs;
-       ir_mode           *mode;
-       int                n, i;
-       unsigned           cc;
-       ir_node           *proj_M     = get_irg_initial_mem(current_ir_graph);
-       entity            *irg_ent    = get_irg_entity(current_ir_graph);
-       ir_type           *tp         = get_entity_type(irg_ent);
-       int                cur_pn     = 0;
-       ir_graph          *irg        = env->irg;
-       ir_node           *block      = env->block;
-
-       assert(is_Method_type(tp) && "irg type is not a method");
-
-       switch(get_Proj_proj(proj)) {
-               case pn_Start_T_args:
-                       /* We cannot use get_method_n_params here as the function might
-                          be variadic or one argument is not used. */
-                       n = get_irn_n_edges(proj);
-
-                       /* Allocate memory for all non variadic parameters in advance to be on the save side */
-                       env->cg->reg_param_req = xcalloc(get_method_n_params(tp), sizeof(ia32_register_req_t *));
-
-                       /* we are done here when there are no parameters */
-                       if (n < 1)
-                               break;
-
-                       /* temporary remember all proj arg x */
-                       projargs = xcalloc(n, sizeof(ir_node *));
-
-                       i = 0;
-                       foreach_out_edge((const ir_node *)proj, edge) {
-                               succ = get_edge_src_irn(edge);
-                               assert(is_Proj(succ) && "non-Proj from a Proj_T (pn_Start_T_args).");
-                               projargs[i++] = succ;
-                       }
-
-                       cc = get_method_calling_convention(tp);
-
-                       /* loop over all parameters and check whether its a int or float */
-                       for (i = 0; i < n; i++) {
-                               mode   = get_irn_mode(projargs[i]);
-                               cur_pn = get_Proj_proj(projargs[i]);
-
-                               if (cc & cc_reg_param) {
-                                       temp_req = ia32_get_RegParam_req(n, projargs, cur_pn, cc);
-                               }
-                               else {
-                                       temp_req = NULL;
-                               }
-
-                               if (temp_req) {
-                                       /* passed in register */
-                                       env->cg->reg_param_req[cur_pn] = temp_req;
-                               }
-                               else {
-                                       /* passed on stack */
-                                       if (mode_is_float(mode))
-                                               irn = new_rd_ia32_fStackParam(get_irn_dbg_info(projargs[i]), irg, block, proj_M, mode);
-                                       else
-                                               irn = new_rd_ia32_StackParam(get_irn_dbg_info(projargs[i]), irg, block, proj_M, mode);
-
-                                       set_ia32_pncode(irn, cur_pn);
-
-                                       /* kill the old "Proj Arg" and replace with the new stack param */
-                                       exchange(projargs[i], irn);
-                               }
-                       }
-
-                       free(projargs);
-
-                       break;
-               case pn_Start_P_frame_base:
-               case pn_Start_X_initial_exec:
-               case pn_Start_M:
-               case pn_Start_P_globals:
-               case pn_Start_P_value_arg_base:
-                       break;
-               default:
-                       assert(0 && "unsupported Proj(Start)");
+static ir_node *gen_CopyB(ia32_transform_env_t *env) {
+       ir_node  *res   = NULL;
+       dbg_info *dbg   = env->dbg;
+       ir_graph *irg   = env->irg;
+       ir_mode  *mode  = env->mode;
+       ir_node  *block = env->block;
+       ir_node  *node  = env->irn;
+       ir_node  *src   = get_CopyB_src(node);
+       ir_node  *dst   = get_CopyB_dst(node);
+       ir_node  *mem   = get_CopyB_mem(node);
+       ir_node  *noreg = ia32_new_NoReg_gp(env->cg);
+       int       size  = get_type_size_bytes(get_CopyB_type(node));
+       int       rem;
+
+       /* If we have to copy more than 16 bytes, we use REP MOVSx and */
+       /* then we need the size explicitly in ECX.                    */
+       if (size >= 16) {
+               rem = size & 0x3; /* size % 4 */
+               size >>= 2;
+
+               res = new_rd_ia32_Const(dbg, irg, block, mode_Is);
+               set_ia32_op_type(res, ia32_Const);
+               set_ia32_Immop_tarval(res, new_tarval_from_long(size, mode_Is));
+
+               res = new_rd_ia32_CopyB(dbg, irg, block, dst, src, res, mem, mode);
+               set_ia32_Immop_tarval(res, new_tarval_from_long(rem, mode_Is));
+       }
+       else {
+               res = new_rd_ia32_CopyB_i(dbg, irg, block, dst, src, mem, mode);
+               set_ia32_Immop_tarval(res, new_tarval_from_long(size, mode_Is));
        }
 
-       return NULL;
-#endif
+       return res;
 }
 
+
+
 /**
- * Transform some Proj's (Proj_Proj, Proj_Start, Proj_Cmp, Proj_Cond, Proj_Call).
- * All others are ignored.
+ * Transforms a Mux node into CMov.
  *
- * @param mod     the debug module
- * @param block   the block the new node should belong to
- * @param node    the ir Proj node
- * @param mode    mode of the Proj
+ * @param env   The transformation environment
  * @return The transformed node.
  */
-static ir_node *gen_Proj(ia32_transform_env_t *env) {
-       ir_node *new_node  = NULL;
-       ir_node *pred      = get_Proj_pred(env->irn);
+static ir_node *gen_Mux(ia32_transform_env_t *env) {
+       ir_node  *node  = env->irn;
 
-       if (env->mode == mode_M)
-               return NULL;
+       return new_rd_ia32_CMov(env->dbg, env->irg, env->block,
+               get_Mux_sel(node), get_Mux_false(node), get_Mux_true(node), env->mode);
+}
 
-       if (get_irn_op(pred) == op_Start) {
-               new_node = gen_Proj_Start(env, env->irn, pred);
-       }
 
-       return new_node;
+
+/********************************************
+ *  _                          _
+ * | |                        | |
+ * | |__   ___ _ __   ___   __| | ___  ___
+ * | '_ \ / _ \ '_ \ / _ \ / _` |/ _ \/ __|
+ * | |_) |  __/ | | | (_) | (_| |  __/\__ \
+ * |_.__/ \___|_| |_|\___/ \__,_|\___||___/
+ *
+ ********************************************/
+
+static ir_node *gen_FrameAddr(ia32_transform_env_t *tenv) {
+       ir_node *new_op = NULL;
+
+       return new_op;
+}
+
+static ir_node *gen_FrameLoad(ia32_transform_env_t *tenv) {
+       ir_node *new_op = NULL;
+
+       return new_op;
+}
+
+static ir_node *gen_FrameStore(ia32_transform_env_t *tenv) {
+       ir_node *new_op = NULL;
+
+       return new_op;
 }
 
 
@@ -1458,8 +1322,6 @@ static ir_node *gen_Proj(ia32_transform_env_t *env) {
  *
  *********************************************************/
 
-
-
 /**
  * Transforms the given firm node (and maybe some other related nodes)
  * into one or more assembler nodes.
@@ -1476,7 +1338,6 @@ void ia32_transform_node(ir_node *node, void *env) {
        if (is_Block(node))
                return;
 
-       tenv.arch_env = cgenv->arch_env;
        tenv.block    = get_nodes_block(node);
        tenv.dbg      = get_irn_dbg_info(node);
        tenv.irg      = current_ir_graph;
@@ -1490,6 +1351,16 @@ void ia32_transform_node(ir_node *node, void *env) {
 #define GEN(a)   case iro_##a: asm_node = gen_##a(&tenv); break
 #define IGN(a)   case iro_##a: break
 #define BAD(a)   case iro_##a: goto bad
+#define OTHER_BIN(a)                                                       \
+       if (get_irn_op(node) == get_op_##a()) {                                \
+               asm_node = gen_##a(&tenv, get_irn_n(node, 0), get_irn_n(node, 1)); \
+               break;                                                             \
+       }
+#define BE_GEN(a)                  \
+       if (be_is_##a(node)) {         \
+               asm_node = gen_##a(&tenv); \
+               break;                     \
+       }
 
        DBG((tenv.mod, LEVEL_1, "check %+F ... ", node));
 
@@ -1520,10 +1391,13 @@ void ia32_transform_node(ir_node *node, void *env) {
                GEN(Store);
                GEN(Cond);
 
-               IGN(Proj);
+               GEN(CopyB);
+               GEN(Mux);
+
                IGN(Call);
                IGN(Alloc);
 
+               IGN(Proj);
                IGN(Block);
                IGN(Start);
                IGN(End);
@@ -1533,16 +1407,17 @@ void ia32_transform_node(ir_node *node, void *env) {
                IGN(Break);
                IGN(Cmp);
                IGN(Unknown);
+
                /* constant transformation happens earlier */
                IGN(Const);
                IGN(SymConst);
+               IGN(Sync);
 
                BAD(Raise);
                BAD(Sel);
                BAD(InstOf);
                BAD(Cast);
                BAD(Free);
-               BAD(Sync);
                BAD(Tuple);
                BAD(Id);
                BAD(Bad);
@@ -1551,25 +1426,22 @@ void ia32_transform_node(ir_node *node, void *env) {
                BAD(CallBegin);
                BAD(EndReg);
                BAD(EndExcept);
-               BAD(Mux);
-               BAD(CopyB);
 
                default:
-                       if (get_irn_op(node) == get_op_Max()) {
-                               asm_node = gen_Max(&tenv, get_irn_n(node, 0), get_irn_n(node, 1));
-                       }
-                       else if (get_irn_op(node) == get_op_Min()) {
-                               asm_node = gen_Min(&tenv, get_irn_n(node, 0), get_irn_n(node, 1));
-                       }
-                       else if (get_irn_op(node) == get_op_Mulh()) {
-                               asm_node = gen_Mulh(&tenv, get_irn_n(node, 0), get_irn_n(node, 1));
-                       }
+                       OTHER_BIN(Max);
+                       OTHER_BIN(Min);
+                       OTHER_BIN(Mulh);
+
+                       BE_GEN(FrameAddr);
+                       BE_GEN(FrameLoad);
+                       BE_GEN(FrameStore);
                        break;
 bad:
                fprintf(stderr, "Not implemented: %s\n", get_irn_opname(node));
                assert(0);
        }
 
+       /* exchange nodes if a new one was generated */
        if (asm_node) {
                exchange(node, asm_node);
                DB((tenv.mod, LEVEL_1, "created node %+F[%p]\n", asm_node, asm_node));
@@ -1577,4 +1449,12 @@ bad:
        else {
                DB((tenv.mod, LEVEL_1, "ignored\n"));
        }
+
+#undef UNOP
+#undef BINOP
+#undef GEN
+#undef IGN
+#undef BAD
+#undef OTHER_BIN
+#undef BE_GEN
 }