handle arm ABI in arm transform phase
authorMatthias Braun <matze@braunis.de>
Fri, 9 Jul 2010 16:17:07 +0000 (16:17 +0000)
committerMatthias Braun <matze@braunis.de>
Fri, 9 Jul 2010 16:17:07 +0000 (16:17 +0000)
[r27726]

ir/be/arm/arm_cconv.c [new file with mode: 0644]
ir/be/arm/arm_cconv.h [new file with mode: 0644]
ir/be/arm/arm_new_nodes.c
ir/be/arm/arm_spec.pl
ir/be/arm/arm_transform.c
ir/be/arm/bearch_arm.c
ir/be/beabi.c
ir/be/beabihelper.c
ir/be/beabihelper.h
ir/be/bemain.c

diff --git a/ir/be/arm/arm_cconv.c b/ir/be/arm/arm_cconv.c
new file mode 100644 (file)
index 0000000..e76bd42
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   calling convention helpers
+ * @author  Matthias Braun
+ * @version $Id$
+ */
+#include "config.h"
+
+#include "arm_cconv.h"
+#include "irmode.h"
+#include "typerep.h"
+#include "xmalloc.h"
+#include "error.h"
+
+calling_convention_t *decide_calling_convention(ir_type *function_type)
+{
+       int                   stack_offset = 0;
+       reg_or_stackslot_t   *params;
+       reg_or_stackslot_t   *results;
+       int                   n_param_regs
+               = sizeof(param_regs)/sizeof(param_regs[0]);
+       int                   n_result_regs
+               = sizeof(result_regs)/sizeof(result_regs[0]);
+       int                   n_params;
+       int                   n_results;
+       int                   i;
+       int                   regnum;
+       calling_convention_t *cconv;
+
+       /* determine how parameters are passed */
+       n_params = get_method_n_params(function_type);
+       regnum   = 0;
+       params   = XMALLOCNZ(reg_or_stackslot_t, n_params);
+
+       for (i = 0; i < n_params; ++i) {
+               ir_type            *param_type = get_method_param_type(function_type,i);
+               ir_mode            *mode       = get_type_mode(param_type);
+               int                 bits       = get_mode_size_bits(mode);
+               reg_or_stackslot_t *param      = &params[i];
+
+               if (regnum < n_param_regs) {
+                       const arch_register_t *reg = param_regs[regnum++];
+                       param->reg0 = reg;
+               } else {
+                       param->type   = param_type;
+                       param->offset = stack_offset;
+                       /* increase offset 4 bytes so everything is aligned */
+                       stack_offset += 4;
+                       continue;
+               }
+
+               /* we might need a 2nd 32bit component (for 64bit or double values) */
+               if (bits > 32) {
+                       if (bits > 64)
+                               panic("only 32 and 64bit modes supported in arm backend");
+
+                       if (regnum < n_param_regs) {
+                               const arch_register_t *reg = param_regs[regnum++];
+                               param->reg1 = reg;
+                       } else {
+                               ir_mode *mode = param_regs[0]->reg_class->mode;
+                               ir_type *type = get_type_for_mode(mode);
+                               param->type   = type;
+                               param->offset = stack_offset;
+                               stack_offset += 4;
+                       }
+               }
+       }
+
+       n_results = get_method_n_ress(function_type);
+       regnum    = 0;
+       results   = XMALLOCNZ(reg_or_stackslot_t, n_results);
+       for (i = 0; i < n_results; ++i) {
+               ir_type            *result_type = get_method_res_type(function_type, i);
+               ir_mode            *result_mode = get_type_mode(result_type);
+               reg_or_stackslot_t *result      = &results[i];
+
+               if (get_mode_size_bits(result_mode) > 32) {
+                       panic("Results with more than 32bits not supported by arm backend yet");
+               }
+
+               if (regnum >= n_result_regs) {
+                       panic("Too many results for arm backend");
+               } else {
+                       const arch_register_t *reg = result_regs[regnum++];
+                       result->reg0 = reg;
+               }
+       }
+
+       cconv                   = XMALLOCZ(calling_convention_t);
+       cconv->parameters       = params;
+       cconv->param_stack_size = stack_offset;
+       cconv->results          = results;
+
+       return cconv;
+}
+
+void free_calling_convention(calling_convention_t *cconv)
+{
+       free(cconv->parameters);
+       free(cconv->results);
+       free(cconv);
+}
diff --git a/ir/be/arm/arm_cconv.h b/ir/be/arm/arm_cconv.h
new file mode 100644 (file)
index 0000000..18418b4
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   support functions for calling conventions
+ * @author  Matthias Braun
+ * @version $Id$
+ */
+#ifndef FIRM_BE_ARM_ARM_CCONV_H
+#define FIRM_BE_ARM_ARM_CCONV_H
+
+#include "firm_types.h"
+#include "../be_types.h"
+#include "gen_arm_regalloc_if.h"
+
+static const arch_register_t *const callee_saves[] = {
+       &arm_gp_regs[REG_R4],
+       &arm_gp_regs[REG_R5],
+       &arm_gp_regs[REG_R6],
+       &arm_gp_regs[REG_R7],
+       &arm_gp_regs[REG_R8],
+       &arm_gp_regs[REG_R9],
+       &arm_gp_regs[REG_R10],
+       &arm_gp_regs[REG_R11],
+       &arm_gp_regs[REG_LR],
+};
+
+static const arch_register_t *const caller_saves[] = {
+       &arm_gp_regs[REG_R0],
+       &arm_gp_regs[REG_R1],
+       &arm_gp_regs[REG_R2],
+       &arm_gp_regs[REG_R3],
+       &arm_gp_regs[REG_LR]
+};
+
+static const arch_register_t* const param_regs[] = {
+       &arm_gp_regs[REG_R0],
+       &arm_gp_regs[REG_R1],
+       &arm_gp_regs[REG_R2],
+       &arm_gp_regs[REG_R3]
+};
+
+static const arch_register_t* const result_regs[] = {
+       &arm_gp_regs[REG_R0],
+       &arm_gp_regs[REG_R1],
+       &arm_gp_regs[REG_R2],
+       &arm_gp_regs[REG_R3]
+};
+
+/** information about a single parameter or result */
+typedef struct reg_or_stackslot_t
+{
+       const arch_register_t *reg0;
+       const arch_register_t *reg1;
+       ir_type               *type;   /**< indicates that an entity of the specific
+                                                                           type is needed */
+       int                    offset;
+       ir_entity             *entity; /**< entity in frame type */
+} reg_or_stackslot_t;
+
+typedef struct calling_convention_t
+{
+       reg_or_stackslot_t *parameters;
+       int                 param_stack_size;
+       reg_or_stackslot_t *results;
+} calling_convention_t;
+
+/**
+ * determine how function parameters and return values are passed.
+ * Decides what goes to register or to stack and what stack offsets/
+ * datatypes are used.
+ */
+calling_convention_t *decide_calling_convention(ir_type *function_type);
+
+/**
+ * free memory used by a calling_convention_t
+ */
+void free_calling_convention(calling_convention_t *cconv);
+
+#endif
index ec331dc..e3402bd 100644 (file)
@@ -67,12 +67,12 @@ const char *arm_get_fpa_imm_name(long imm_value)
 
 static bool arm_has_symconst_attr(const ir_node *node)
 {
-       return is_arm_SymConst(node) || is_arm_FrameAddr(node);
+       return is_arm_SymConst(node) || is_arm_FrameAddr(node) || is_arm_Bl(node);
 }
 
 static bool has_load_store_attr(const ir_node *node)
 {
-       return is_arm_Ldr(node) || is_arm_Str(node);
+       return is_arm_Ldr(node) || is_arm_Str(node) || is_arm_LinkLdrPC(node);
 }
 
 static bool has_shifter_operand(const ir_node *node)
@@ -80,7 +80,7 @@ static bool has_shifter_operand(const ir_node *node)
        return is_arm_Add(node) || is_arm_And(node) || is_arm_Or(node)
                || is_arm_Eor(node) || is_arm_Bic(node) || is_arm_Sub(node)
                || is_arm_Rsb(node) || is_arm_Mov(node) || is_arm_Mvn(node)
-               || is_arm_Cmp(node) || is_arm_Tst(node);
+               || is_arm_Cmp(node) || is_arm_Tst(node) || is_arm_LinkMovPC(node);
 }
 
 static bool has_cmp_attr(const ir_node *node)
@@ -215,7 +215,7 @@ const arm_attr_t *get_arm_attr_const(const ir_node *node)
 
 static bool has_symconst_attr(const ir_node *node)
 {
-       return is_arm_SymConst(node) || is_arm_FrameAddr(node);
+       return is_arm_SymConst(node) || is_arm_FrameAddr(node) || is_arm_Bl(node);
 }
 
 arm_SymConst_attr_t *get_arm_SymConst_attr(ir_node *node)
index 40863b5..1732dba 100644 (file)
@@ -309,6 +309,46 @@ Abs => {
        mode      => $mode_gp,
 },
 
+# mov lr, pc\n mov pc, XXX -- This combination is used for calls to function
+# pointers
+LinkMovPC => {
+       state        => "exc_pinned",
+       arity        => "variable",
+       out_arity    => "variable",
+       attr_type    => "arm_shifter_operand_t",
+       attr         => "arm_shift_modifier_t shift_modifier, unsigned char immediate_value, unsigned char immediate_rot",
+       custominit   => "init_arm_shifter_operand(res, immediate_value, shift_modifier, immediate_rot);\n".
+                       "\tarch_irn_add_flags(res, arch_irn_flags_modify_flags);",
+       emit         => ". mov lr, pc\n".
+                       ". mov pc, %SO",
+       mode         => "mode_T",
+},
+
+# mov lr, pc\n ldr pc, XXX -- This combination is used for calls to function
+# pointers
+LinkLdrPC => {
+       state        => "exc_pinned",
+       arity        => "variable",
+       out_arity    => "variable",
+       attr_type    => "arm_load_store_attr_t",
+       attr         => "ir_mode *ls_mode, ir_entity *entity, int entity_sign, long offset, bool is_frame_entity",
+       custominit   => "arch_irn_add_flags(res, arch_irn_flags_modify_flags);",
+       emit         => ". mov lr, pc\n".
+                       ". ldr pc, %SO",
+       mode         => "mode_T",
+},
+
+Bl => {
+       state      => "exc_pinned",
+       arity      => "variable",
+       out_arity  => "variable",
+       attr_type  => "arm_SymConst_attr_t",
+       attr       => "ir_entity *entity, int symconst_offset",
+       custominit => "arch_irn_add_flags(res, arch_irn_flags_modify_flags);",
+       emit       => '. bl %SC',
+       mode       => "mode_T",
+},
+
 # this node produces ALWAYS an empty (tempary) gp reg and cannot be CSE'd
 EmptyReg => {
        op_flags  => "c",
@@ -539,44 +579,24 @@ fpaFix => {
        emit      => '. fix %D0, %S0',
 },
 
-fpaCmfBra => {
-       op_flags  => "L|X|Y",
-       state     => "pinned",
-       mode      => "mode_T",
-       attr      => "pn_Cmp pnc",
-       init_attr => "\tset_arm_CondJmp_pnc(res, pnc);",
-       reg_req   => { in => [ "fpa", "fpa" ], out => [ "none", "none"] },
-       attr_type => "arm_CondJmp_attr_t",
-},
-
-fpaCnfBra => {
-       op_flags  => "L|X|Y",
-       state     => "pinned",
-       mode      => "mode_T",
-       attr      => "int pnc",
-       init_attr => "\tset_arm_CondJmp_pnc(res, pnc);",
-       reg_req   => { in => [ "fpa", "fpa" ], out => [ "none", "none"] },
-       attr_type => "arm_CondJmp_attr_t",
-},
-
-fpaCmfeBra => {
-       op_flags  => "L|X|Y",
-       state     => "pinned",
-       mode      => "mode_T",
-       attr      => "int pnc",
-       init_attr => "\tset_arm_CondJmp_pnc(res, pnc);",
-       reg_req   => { in => [ "fpa", "fpa" ], out => [ "none", "none"] },
-       attr_type => "arm_CondJmp_attr_t",
-},
-
-fpaCnfeBra => {
-       op_flags  => "L|X|Y",
-       state     => "pinned",
-       mode      => "mode_T",
-       attr      => "int pnc",
-       init_attr => "\tset_arm_CondJmp_pnc(res, pnc);",
-       reg_req   => { in => [ "fpa", "fpa" ], out => [ "none", "none"] },
-       attr_type => "arm_CondJmp_attr_t",
+Cmf => {
+       irn_flags => "R|F",
+       mode      => $mode_flags,
+       attr_type => "arm_cmp_attr_t",
+       attr      => "bool ins_permuted",
+       init_attr => "init_arm_cmp_attr(res, ins_permuted, false);",
+       reg_req   => { in => [ "fpa", "fpa" ], out => [ "flags" ] },
+       emit      => '. cmf %S0, %S1',
+},
+
+Cmfe => {
+       irn_flags => "R|F",
+       mode      => $mode_flags,
+       attr_type => "arm_cmp_attr_t",
+       attr      => "bool ins_permuted",
+       init_attr => "init_arm_cmp_attr(res, ins_permuted, false);",
+       reg_req   => { in => [ "fpa", "fpa" ], out => [ "flags" ] },
+       emit      => '. cmfe %S0, %S1',
 },
 
 fpaLdf => {
index 4febec5..edaea9f 100644 (file)
@@ -20,7 +20,7 @@
 /**
  * @file
  * @brief   The codegenerator (transform FIRM into arm FIRM)
- * @author  Oliver Richter, Tobias Gneist, Michael Beck
+ * @author  Matthias Braun, Oliver Richter, Tobias Gneist, Michael Beck
  * @version $Id$
  */
 #include "config.h"
 #include "../beirg.h"
 #include "../beutil.h"
 #include "../betranshlp.h"
-#include "bearch_arm_t.h"
+#include "../beabihelper.h"
+#include "../beabi.h"
 
+#include "bearch_arm_t.h"
 #include "arm_nodes_attr.h"
 #include "arm_transform.h"
 #include "arm_optimize.h"
 #include "arm_new_nodes.h"
 #include "arm_map_regs.h"
+#include "arm_cconv.h"
 
 #include "gen_arm_regalloc_if.h"
 
@@ -59,13 +62,20 @@ DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
 /** hold the current code generator during transformation */
 static arm_code_gen_t *env_cg;
 
-static inline int mode_needs_gp_reg(ir_mode *mode)
+static const arch_register_t *sp_reg = &arm_gp_regs[REG_SP];
+static ir_mode               *mode_gp;
+static beabi_helper_env_t    *abihelper;
+static calling_convention_t  *cconv = NULL;
+
+static pmap                  *node_to_stack;
+
+static bool mode_needs_gp_reg(ir_mode *mode)
 {
        return mode_is_int(mode) || mode_is_reference(mode);
 }
 
 /**
- * Creates a possible DAG for an constant.
+ * create firm graph for a constant
  */
 static ir_node *create_const_graph_value(dbg_info *dbgi, ir_node *block,
                                          unsigned int value)
@@ -74,6 +84,12 @@ static ir_node *create_const_graph_value(dbg_info *dbgi, ir_node *block,
        arm_vals v, vn;
        int cnt;
 
+       /* We only have 8 bit immediates. So we possibly have to combine several
+        * operations to construct the desired value.
+        *
+        * we can either create the value by adding bits to 0 or by removing bits
+        * from an register with all bits set. Try which alternative needs fewer
+        * operations */
        arm_gen_vals_from_word(value, &v);
        arm_gen_vals_from_word(~value, &vn);
 
@@ -206,13 +222,11 @@ static ir_node *gen_Conv(ir_node *node)
                                if (mode_is_float(dst_mode)) {
                                        /* from float to float */
                                        return new_bd_arm_fpaMvf(dbg, block, new_op, dst_mode);
-                               }
-                               else {
+                               } else {
                                        /* from float to int */
                                        return new_bd_arm_fpaFix(dbg, block, new_op, dst_mode);
                                }
-                       }
-                       else {
+                       } else {
                                /* from int to float */
                                return new_bd_arm_fpaFlt(dbg, block, new_op, dst_mode);
                        }
@@ -401,8 +415,7 @@ static ir_node *gen_Add(ir_node *node)
                } else if (USE_VFP(env_cg->isa)) {
                        assert(mode != mode_E && "IEEE Extended FP not supported");
                        panic("VFP not supported yet");
-               }
-               else {
+               } else {
                        panic("Softfloat not supported yet");
                }
        } else {
@@ -454,12 +467,10 @@ static ir_node *gen_Mul(ir_node *node)
                                return new_bd_arm_fpaMuf_i(dbg, block, new_op1, mode, get_arm_imm_value(new_op2));
 #endif
                        return new_bd_arm_fpaMuf(dbg, block, new_op1, new_op2, mode);
-               }
-               else if (USE_VFP(env_cg->isa)) {
+               } else if (USE_VFP(env_cg->isa)) {
                        assert(mode != mode_E && "IEEE Extended FP not supported");
                        panic("VFP not supported yet");
-               }
-               else {
+               } else {
                        panic("Softfloat not supported yet");
                }
        }
@@ -467,12 +478,6 @@ static ir_node *gen_Mul(ir_node *node)
        return new_bd_arm_Mul(dbg, block, new_op1, new_op2);
 }
 
-/**
- * Creates an ARM floating point Div.
- *
- * @param env   The transformation environment
- * @return the created arm fDiv node
- */
 static ir_node *gen_Quot(ir_node *node)
 {
        ir_node  *block   = be_transform_node(get_nodes_block(node));
@@ -497,51 +502,29 @@ static ir_node *gen_Quot(ir_node *node)
        } else if (USE_VFP(env_cg->isa)) {
                assert(mode != mode_E && "IEEE Extended FP not supported");
                panic("VFP not supported yet");
-       }
-       else {
+       } else {
                panic("Softfloat not supported yet");
        }
 }
 
-/**
- * Creates an ARM And.
- *
- * @return the created arm And node
- */
 static ir_node *gen_And(ir_node *node)
 {
        return gen_int_binop(node, MATCH_COMMUTATIVE | MATCH_SIZE_NEUTRAL,
                        new_bd_arm_And_reg, new_bd_arm_And_imm);
 }
 
-/**
- * Creates an ARM Orr.
- *
- * @param env   The transformation environment
- * @return the created arm Or node
- */
 static ir_node *gen_Or(ir_node *node)
 {
        return gen_int_binop(node, MATCH_COMMUTATIVE | MATCH_SIZE_NEUTRAL,
                        new_bd_arm_Or_reg, new_bd_arm_Or_imm);
 }
 
-/**
- * Creates an ARM Eor.
- *
- * @return the created arm Eor node
- */
 static ir_node *gen_Eor(ir_node *node)
 {
        return gen_int_binop(node, MATCH_COMMUTATIVE | MATCH_SIZE_NEUTRAL,
                        new_bd_arm_Eor_reg, new_bd_arm_Eor_imm);
 }
 
-/**
- * Creates an ARM Sub.
- *
- * @return the created arm Sub node
- */
 static ir_node *gen_Sub(ir_node *node)
 {
        ir_node  *block   = be_transform_node(get_nodes_block(node));
@@ -622,41 +605,21 @@ static ir_node *make_shift(ir_node *node, match_flags_t flags,
                                            shift_modifier);
 }
 
-/**
- * Creates an ARM Shl.
- *
- * @return the created ARM Shl node
- */
 static ir_node *gen_Shl(ir_node *node)
 {
        return make_shift(node, MATCH_SIZE_NEUTRAL, ARM_SHF_LSL_REG);
 }
 
-/**
- * Creates an ARM Shr.
- *
- * @return the created ARM Shr node
- */
 static ir_node *gen_Shr(ir_node *node)
 {
        return make_shift(node, MATCH_NONE, ARM_SHF_LSR_REG);
 }
 
-/**
- * Creates an ARM Shrs.
- *
- * @return the created ARM Shrs node
- */
 static ir_node *gen_Shrs(ir_node *node)
 {
        return make_shift(node, MATCH_NONE, ARM_SHF_ASR_REG);
 }
 
-/**
- * Creates an ARM Ror.
- *
- * @return the created ARM Ror node
- */
 static ir_node *gen_Ror(ir_node *node, ir_node *op1, ir_node *op2)
 {
        ir_node  *block   = be_transform_node(get_nodes_block(node));
@@ -668,13 +631,6 @@ static ir_node *gen_Ror(ir_node *node, ir_node *op1, ir_node *op2)
                                            ARM_SHF_ROR_REG);
 }
 
-/**
- * Creates an ARM Rol.
- *
- * @return the created ARM Rol node
- *
- * Note: there is no Rol on arm, we have to use Ror
- */
 static ir_node *gen_Rol(ir_node *node, ir_node *op1, ir_node *op2)
 {
        ir_node  *block   = be_transform_node(get_nodes_block(node));
@@ -682,16 +638,12 @@ static ir_node *gen_Rol(ir_node *node, ir_node *op1, ir_node *op2)
        dbg_info *dbgi    = get_irn_dbg_info(node);
        ir_node  *new_op2 = be_transform_node(op2);
 
+       /* Note: there is no Rol on arm, we have to use Ror */
        new_op2 = new_bd_arm_Rsb_imm(dbgi, block, new_op2, 32, 0);
        return new_bd_arm_Mov_reg_shift_reg(dbgi, block, new_op1, new_op2,
                                            ARM_SHF_ROR_REG);
 }
 
-/**
- * Creates an ARM ROR from a Firm Rotl.
- *
- * @return the created ARM Ror node
- */
 static ir_node *gen_Rotl(ir_node *node)
 {
        ir_node *rotate = NULL;
@@ -751,11 +703,6 @@ static ir_node *gen_Rotl(ir_node *node)
        return rotate;
 }
 
-/**
- * Transforms a Not node.
- *
- * @return the created ARM Not node
- */
 static ir_node *gen_Not(ir_node *node)
 {
        ir_node  *block   = be_transform_node(get_nodes_block(node));
@@ -768,12 +715,6 @@ static ir_node *gen_Not(ir_node *node)
        return new_bd_arm_Mvn_reg(dbgi, block, new_op);
 }
 
-/**
- * Transforms an Abs node.
- *
- * @param env   The transformation environment
- * @return the created ARM Abs node
- */
 static ir_node *gen_Abs(ir_node *node)
 {
        ir_node  *block   = be_transform_node(get_nodes_block(node));
@@ -784,13 +725,12 @@ static ir_node *gen_Abs(ir_node *node)
 
        if (mode_is_float(mode)) {
                env_cg->have_fp_insn = 1;
-               if (USE_FPA(env_cg->isa))
+               if (USE_FPA(env_cg->isa)) {
                        return new_bd_arm_fpaAbs(dbgi, block, new_op, mode);
-               else if (USE_VFP(env_cg->isa)) {
+               else if (USE_VFP(env_cg->isa)) {
                        assert(mode != mode_E && "IEEE Extended FP not supported");
                        panic("VFP not supported yet");
-               }
-               else {
+               } else {
                        panic("Softfloat not supported yet");
                }
        }
@@ -798,11 +738,6 @@ static ir_node *gen_Abs(ir_node *node)
        return new_bd_arm_Abs(dbgi, block, new_op);
 }
 
-/**
- * Transforms a Minus node.
- *
- * @return the created ARM Minus node
- */
 static ir_node *gen_Minus(ir_node *node)
 {
        ir_node  *block   = be_transform_node(get_nodes_block(node));
@@ -813,13 +748,12 @@ static ir_node *gen_Minus(ir_node *node)
 
        if (mode_is_float(mode)) {
                env_cg->have_fp_insn = 1;
-               if (USE_FPA(env_cg->isa))
+               if (USE_FPA(env_cg->isa)) {
                        return new_bd_arm_fpaMvf(dbgi, block, op, mode);
-               else if (USE_VFP(env_cg->isa)) {
+               else if (USE_VFP(env_cg->isa)) {
                        assert(mode != mode_E && "IEEE Extended FP not supported");
                        panic("VFP not supported yet");
-               }
-               else {
+               } else {
                        panic("Softfloat not supported yet");
                }
        }
@@ -827,11 +761,6 @@ static ir_node *gen_Minus(ir_node *node)
        return new_bd_arm_Rsb_imm(dbgi, block, new_op, 0, 0);
 }
 
-/**
- * Transforms a Load.
- *
- * @return the created ARM Load node
- */
 static ir_node *gen_Load(ir_node *node)
 {
        ir_node  *block    = be_transform_node(get_nodes_block(node));
@@ -845,9 +774,9 @@ static ir_node *gen_Load(ir_node *node)
 
        if (mode_is_float(mode)) {
                env_cg->have_fp_insn = 1;
-               if (USE_FPA(env_cg->isa))
+               if (USE_FPA(env_cg->isa)) {
                        new_load = new_bd_arm_fpaLdf(dbgi, block, new_ptr, new_mem, mode);
-               else if (USE_VFP(env_cg->isa)) {
+               else if (USE_VFP(env_cg->isa)) {
                        assert(mode != mode_E && "IEEE Extended FP not supported");
                        panic("VFP not supported yet");
                } else {
@@ -870,11 +799,6 @@ static ir_node *gen_Load(ir_node *node)
        return new_load;
 }
 
-/**
- * Transforms a Store.
- *
- * @return the created ARM Store node
- */
 static ir_node *gen_Store(ir_node *node)
 {
        ir_node  *block    = be_transform_node(get_nodes_block(node));
@@ -890,10 +814,10 @@ static ir_node *gen_Store(ir_node *node)
 
        if (mode_is_float(mode)) {
                env_cg->have_fp_insn = 1;
-               if (USE_FPA(env_cg->isa))
+               if (USE_FPA(env_cg->isa)) {
                        new_store = new_bd_arm_fpaStf(dbgi, block, new_ptr, new_val,
                                                      new_mem, mode);
-               else if (USE_VFP(env_cg->isa)) {
+               else if (USE_VFP(env_cg->isa)) {
                        assert(mode != mode_E && "IEEE Extended FP not supported");
                        panic("VFP not supported yet");
                } else {
@@ -917,14 +841,6 @@ static ir_node *gen_Jmp(ir_node *node)
        return new_bd_arm_Jmp(dbgi, new_block);
 }
 
-static ir_node *gen_be_Call(ir_node *node)
-{
-       ir_node *res = be_duplicate_node(node);
-       arch_irn_add_flags(res, arch_irn_flags_modify_flags);
-
-       return res;
-}
-
 static ir_node *gen_SwitchJmp(ir_node *node)
 {
        ir_node  *block    = be_transform_node(get_nodes_block(node));
@@ -979,7 +895,12 @@ static ir_node *gen_Cmp(ir_node *node)
        bool      is_unsigned;
 
        if (mode_is_float(cmp_mode)) {
-               /* TODO: revivie this code */
+               /* TODO: this is broken... */
+               new_op1 = be_transform_node(op1);
+               new_op2 = be_transform_node(op2);
+
+               return new_bd_arm_Cmfe(dbgi, block, new_op1, new_op2, false);
+
                panic("FloatCmp NIY");
 #if 0
                ir_node *new_op2  = be_transform_node(op2);
@@ -1021,11 +942,6 @@ static ir_node *gen_Cmp(ir_node *node)
                                  is_unsigned);
 }
 
-/**
- * Transforms a Cond.
- *
- * @return the created ARM Cond node
- */
 static ir_node *gen_Cond(ir_node *node)
 {
        ir_node  *selector = get_Cond_selector(node);
@@ -1082,11 +998,6 @@ static int is_fpa_immediate(tarval *tv)
 }
 #endif
 
-/**
- * Transforms a Const node.
- *
- * @return The transformed ARM node.
- */
 static ir_node *gen_Const(ir_node *node)
 {
        ir_node  *block = be_transform_node(get_nodes_block(node));
@@ -1101,10 +1012,11 @@ static ir_node *gen_Const(ir_node *node)
                        int imm = is_fpa_immediate(tv);
 
                        if (imm != fpa_max) {
-                               if (imm > 0)
+                               if (imm > 0) {
                                        node = new_bd_arm_fpaMvf_i(dbg, block, mode, imm);
-                               else
+                               } else {
                                        node = new_bd_arm_fpaMnf_i(dbg, block, mode, -imm);
+                               }
                        } else {
 #endif
                        {
@@ -1112,23 +1024,16 @@ static ir_node *gen_Const(ir_node *node)
                        }
                        be_dep_on_frame(node);
                        return node;
-               }
-               else if (USE_VFP(env_cg->isa)) {
+               } else if (USE_VFP(env_cg->isa)) {
                        assert(mode != mode_E && "IEEE Extended FP not supported");
                        panic("VFP not supported yet");
-               }
-               else {
+               } else {
                        panic("Softfloat not supported yet");
                }
        }
        return create_const_graph(node, block);
 }
 
-/**
- * Transforms a SymConst node.
- *
- * @return The transformed ARM node.
- */
 static ir_node *gen_SymConst(ir_node *node)
 {
        ir_node   *block  = be_transform_node(get_nodes_block(node));
@@ -1141,11 +1046,6 @@ static ir_node *gen_SymConst(ir_node *node)
        return new_node;
 }
 
-/**
- * Transforms a CopyB node.
- *
- * @return The transformed ARM node.
- */
 static ir_node *gen_CopyB(ir_node *node)
 {
        ir_node  *block    = be_transform_node(get_nodes_block(node));
@@ -1163,87 +1063,13 @@ static ir_node *gen_CopyB(ir_node *node)
        src_copy = be_new_Copy(&arm_reg_classes[CLASS_arm_gp], block, new_src);
        dst_copy = be_new_Copy(&arm_reg_classes[CLASS_arm_gp], block, new_dst);
 
-       return new_bd_arm_CopyB(dbg, block, dst_copy, src_copy,
+       return new_bd_arm_CopyB(dbg, block, dst_copy, src_copy,
                        new_bd_arm_EmptyReg(dbg, block),
                        new_bd_arm_EmptyReg(dbg, block),
                        new_bd_arm_EmptyReg(dbg, block),
                        new_mem, size);
 }
 
-/**
- * Transforms a FrameAddr into an ARM Add.
- */
-static ir_node *gen_be_FrameAddr(ir_node *node)
-{
-       ir_node   *block  = be_transform_node(get_nodes_block(node));
-       ir_entity *ent    = be_get_frame_entity(node);
-       ir_node   *fp     = be_get_FrameAddr_frame(node);
-       ir_node   *new_fp = be_transform_node(fp);
-       dbg_info  *dbgi   = get_irn_dbg_info(node);
-       ir_node   *new_node;
-
-       new_node = new_bd_arm_FrameAddr(dbgi, block, new_fp, ent, 0);
-       return new_node;
-}
-
-/**
- * Transform a be_AddSP into an arm_AddSP. Eat up const sizes.
- */
-static ir_node *gen_be_AddSP(ir_node *node)
-{
-       ir_node  *block  = be_transform_node(get_nodes_block(node));
-       ir_node  *sz     = get_irn_n(node, be_pos_AddSP_size);
-       ir_node  *new_sz = be_transform_node(sz);
-       ir_node  *sp     = get_irn_n(node, be_pos_AddSP_old_sp);
-       ir_node  *new_sp = be_transform_node(sp);
-       dbg_info *dbgi   = get_irn_dbg_info(node);
-       ir_node  *nomem  = new_NoMem();
-       ir_node  *new_op;
-
-       /* ARM stack grows in reverse direction, make a SubSPandCopy */
-       new_op = new_bd_arm_SubSPandCopy(dbgi, block, new_sp, new_sz, nomem);
-
-       return new_op;
-}
-
-/**
- * Transform a be_SubSP into an arm_SubSP. Eat up const sizes.
- */
-static ir_node *gen_be_SubSP(ir_node *node)
-{
-       ir_node  *block  = be_transform_node(get_nodes_block(node));
-       ir_node  *sz     = get_irn_n(node, be_pos_SubSP_size);
-       ir_node  *new_sz = be_transform_node(sz);
-       ir_node  *sp     = get_irn_n(node, be_pos_SubSP_old_sp);
-       ir_node  *new_sp = be_transform_node(sp);
-       dbg_info *dbgi   = get_irn_dbg_info(node);
-       ir_node  *nomem  = new_NoMem();
-       ir_node  *new_op;
-
-       /* ARM stack grows in reverse direction, make an AddSP */
-       new_op = new_bd_arm_AddSP(dbgi, block, new_sp, new_sz, nomem);
-
-       return new_op;
-}
-
-/**
- * Transform a be_Copy.
- */
-static ir_node *gen_be_Copy(ir_node *node)
-{
-       ir_node *result = be_duplicate_node(node);
-       ir_mode *mode   = get_irn_mode(result);
-
-       if (mode_needs_gp_reg(mode)) {
-               set_irn_mode(node, mode_Iu);
-       }
-
-       return result;
-}
-
-/**
- * Transform a Proj from a Load.
- */
 static ir_node *gen_Proj_Load(ir_node *node)
 {
        ir_node  *load     = get_Proj_pred(node);
@@ -1275,9 +1101,6 @@ static ir_node *gen_Proj_Load(ir_node *node)
        panic("Unsupported Proj from Load");
 }
 
-/**
- * Transform and renumber the Projs from a CopyB.
- */
 static ir_node *gen_Proj_CopyB(ir_node *node)
 {
        ir_node  *pred     = get_Proj_pred(node);
@@ -1286,7 +1109,7 @@ static ir_node *gen_Proj_CopyB(ir_node *node)
        long     proj      = get_Proj_proj(node);
 
        switch (proj) {
-       case pn_CopyB_M_regular:
+       case pn_CopyB_M:
                if (is_arm_CopyB(new_pred)) {
                        return new_rd_Proj(dbgi, new_pred, mode_M, pn_arm_CopyB_M);
                }
@@ -1297,9 +1120,6 @@ static ir_node *gen_Proj_CopyB(ir_node *node)
        panic("Unsupported Proj from CopyB");
 }
 
-/**
- * Transform and renumber the Projs from a Quot.
- */
 static ir_node *gen_Proj_Quot(ir_node *node)
 {
        ir_node  *pred     = get_Proj_pred(node);
@@ -1338,67 +1158,134 @@ static ir_node *gen_Proj_Quot(ir_node *node)
 }
 
 /**
- * Transform the Projs of a be_AddSP.
+ * Transform the Projs from a Cmp.
  */
-static ir_node *gen_Proj_be_AddSP(ir_node *node)
+static ir_node *gen_Proj_Cmp(ir_node *node)
 {
-       ir_node  *pred     = get_Proj_pred(node);
-       ir_node  *new_pred = be_transform_node(pred);
-       dbg_info *dbgi     = get_irn_dbg_info(node);
+       (void) node;
+       /* we should only be here in case of a Mux node */
+       panic("Mux NYI");
+}
+
+static ir_node *gen_Proj_Start(ir_node *node)
+{
+       ir_node *block     = get_nodes_block(node);
+       ir_node *new_block = be_transform_node(block);
+       ir_node *barrier   = be_transform_node(get_Proj_pred(node));
        long     proj      = get_Proj_proj(node);
 
-       if (proj == pn_be_AddSP_sp) {
-               ir_node *res = new_rd_Proj(dbgi, new_pred, mode_Iu,
-                                          pn_arm_SubSPandCopy_stack);
-               arch_set_irn_register(res, &arm_gp_regs[REG_SP]);
-               return res;
-       } else if (proj == pn_be_AddSP_res) {
-               return new_rd_Proj(dbgi, new_pred, mode_Iu, pn_arm_SubSPandCopy_addr);
-       } else if (proj == pn_be_AddSP_M) {
-               return new_rd_Proj(dbgi, new_pred, mode_M, pn_arm_SubSPandCopy_M);
+       switch ((pn_Start) proj) {
+       case pn_Start_X_initial_exec:
+               /* we exchange the ProjX with a jump */
+               return new_bd_arm_Jmp(NULL, new_block);
+
+       case pn_Start_M:
+               return new_r_Proj(barrier, mode_M, 0);
+
+       case pn_Start_T_args:
+               /* TODO */
+               return barrier;
+
+       case pn_Start_P_frame_base:
+               return be_prolog_get_reg_value(abihelper, sp_reg);
+
+       case pn_Start_P_tls:
+               return new_bd_arm_LdTls(NULL, new_block);
+
+       case pn_Start_max:
+               break;
        }
-       panic("Unsupported Proj from AddSP");
+       panic("unexpected start proj: %ld\n", proj);
 }
 
-/**
- * Transform the Projs of a be_SubSP.
- */
-static ir_node *gen_Proj_be_SubSP(ir_node *node)
+static ir_node *gen_Proj_Proj_Start(ir_node *node)
 {
-       ir_node  *pred     = get_Proj_pred(node);
-       ir_node  *new_pred = be_transform_node(pred);
-       dbg_info *dbgi     = get_irn_dbg_info(node);
-       long     proj      = get_Proj_proj(node);
+       long                      pn = get_Proj_proj(node);
+       const reg_or_stackslot_t *param;
+
+       /* Proj->Proj->Start must be a method argument */
+       assert(get_Proj_proj(get_Proj_pred(node)) == pn_Start_T_args);
+
+       param = &cconv->parameters[pn];
 
-       if (proj == pn_be_SubSP_sp) {
-               ir_node *res = new_rd_Proj(dbgi, new_pred, mode_Iu,
-                                          pn_arm_AddSP_stack);
-               arch_set_irn_register(res, &arm_gp_regs[REG_SP]);
-               return res;
-       } else if (proj == pn_be_SubSP_M) {
-               return new_rd_Proj(dbgi, new_pred, mode_M, pn_arm_AddSP_M);
+       if (param->reg0 != NULL) {
+               /* argument transmitted in register */
+               return be_prolog_get_reg_value(abihelper, param->reg0);
+       } else {
+               /* argument transmitted on stack */
+               ir_graph *irg       = get_irn_irg(node);
+               ir_node  *block     = get_nodes_block(node);
+               ir_node  *new_block = be_transform_node(block);
+               ir_node  *fp        = get_irg_frame(irg);
+               ir_node  *mem       = be_prolog_get_memory(abihelper);
+               ir_mode  *mode      = get_type_mode(param->type);
+               ir_node  *load      = new_bd_arm_Ldr(NULL, new_block, fp, mem, mode,
+                                                    param->entity, 0, 0, true);
+               ir_node  *value     = new_r_Proj(load, mode_gp, pn_arm_Ldr_res);
+               set_irn_pinned(load, op_pin_state_floats);
+
+               return value;
        }
-       panic("Unsupported Proj from SubSP");
 }
 
 /**
- * Transform the Projs from a Cmp.
+ * Finds number of output value of a mode_T node which is constrained to
+ * a single specific register.
  */
-static ir_node *gen_Proj_Cmp(ir_node *node)
+static int find_out_for_reg(ir_node *node, const arch_register_t *reg)
 {
-       (void) node;
-       panic("Mux NYI");
-}
+       int n_outs = arch_irn_get_n_outs(node);
+       int o;
 
+       for (o = 0; o < n_outs; ++o) {
+               const arch_register_req_t *req = arch_get_out_register_req(node, o);
+               if (req == reg->single_req)
+                       return o;
+       }
+       return -1;
+}
 
-/**
- * Transform the Thread Local Storage Proj.
- */
-static ir_node *gen_Proj_tls(ir_node *node)
+static ir_node *gen_Proj_Proj_Call(ir_node *node)
 {
-       ir_node *block = be_transform_node(get_nodes_block(node));
+       long                  pn            = get_Proj_proj(node);
+       ir_node              *call          = get_Proj_pred(get_Proj_pred(node));
+       ir_node              *new_call      = be_transform_node(call);
+       ir_type              *function_type = get_Call_type(call);
+       calling_convention_t *cconv = decide_calling_convention(function_type);
+       const reg_or_stackslot_t *res = &cconv->results[pn];
+       ir_mode              *mode;
+       int                   regn;
+
+       /* TODO 64bit modes */
+       assert(res->reg0 != NULL && res->reg1 == NULL);
+       regn = find_out_for_reg(new_call, res->reg0);
+       if (regn < 0) {
+               panic("Internal error in calling convention for return %+F", node);
+       }
+       mode = res->reg0->reg_class->mode;
 
-       return new_bd_arm_LdTls(NULL, block);
+       free_calling_convention(cconv);
+
+       return new_r_Proj(new_call, mode, regn);
+}
+
+static ir_node *gen_Proj_Call(ir_node *node)
+{
+       long     pn        = get_Proj_proj(node);
+       ir_node *call      = get_Proj_pred(node);
+       ir_node *new_call  = be_transform_node(call);
+
+       switch ((pn_Call) pn) {
+       case pn_Call_M:
+               return new_r_Proj(new_call, mode_M, 0);
+       case pn_Call_X_regular:
+       case pn_Call_X_except:
+       case pn_Call_T_result:
+       case pn_Call_P_value_res_base:
+       case pn_Call_max:
+               break;
+       }
+       panic("Unexpected Call proj %ld\n", pn);
 }
 
 /**
@@ -1406,54 +1293,43 @@ static ir_node *gen_Proj_tls(ir_node *node)
  */
 static ir_node *gen_Proj(ir_node *node)
 {
-       ir_graph *irg  = current_ir_graph;
-       dbg_info *dbgi = get_irn_dbg_info(node);
        ir_node  *pred = get_Proj_pred(node);
-       long     proj  = get_Proj_proj(node);
+       long      proj = get_Proj_proj(node);
 
-       if (is_Store(pred)) {
+       switch (get_irn_opcode(pred)) {
+       case iro_Store:
                if (proj == pn_Store_M) {
                        return be_transform_node(pred);
                } else {
                        panic("Unsupported Proj from Store");
                }
-       } else if (is_Load(pred)) {
+       case iro_Load:
                return gen_Proj_Load(node);
-       } else if (is_CopyB(pred)) {
+       case iro_Call:
+               return gen_Proj_Call(node);
+       case iro_CopyB:
                return gen_Proj_CopyB(node);
-       } else if (is_Quot(pred)) {
+       case iro_Quot:
                return gen_Proj_Quot(node);
-       } else if (be_is_SubSP(pred)) {
-               return gen_Proj_be_SubSP(node);
-       } else if (be_is_AddSP(pred)) {
-               return gen_Proj_be_AddSP(node);
-       } else if (is_Cmp(pred)) {
+       case iro_Cmp:
                return gen_Proj_Cmp(node);
-       } else if (is_Start(pred)) {
-               if (proj == pn_Start_X_initial_exec) {
-                       ir_node *block = get_nodes_block(pred);
-                       ir_node *jump;
-
-                       /* we exchange the ProjX with a jump */
-                       block = be_transform_node(block);
-                       jump  = new_rd_Jmp(dbgi, block);
-                       return jump;
-               }
-               if (node == get_irg_anchor(irg, anchor_tls)) {
-                       return gen_Proj_tls(node);
-               }
-       } else {
-               ir_node *new_pred = be_transform_node(pred);
-               ir_mode *mode     = get_irn_mode(node);
-               if (mode_needs_gp_reg(mode)) {
-                       ir_node *new_proj = new_r_Proj(new_pred, mode_Iu,
-                                                      get_Proj_proj(node));
-                       new_proj->node_nr = node->node_nr;
-                       return new_proj;
+       case iro_Start:
+               return gen_Proj_Start(node);
+       case iro_Cond:
+               /* nothing to do */
+               return be_duplicate_node(node);
+       case iro_Proj: {
+               ir_node *pred_pred = get_Proj_pred(pred);
+               if (is_Call(pred_pred)) {
+                       return gen_Proj_Proj_Call(node);
+               } else if (is_Start(pred_pred)) {
+                       return gen_Proj_Proj_Start(node);
                }
+               /* FALLTHROUGH */
+       }
+       default:
+               panic("code selection didn't expect Proj after %+F\n", pred);
        }
-
-       return be_duplicate_node(node);
 }
 
 typedef ir_node *(*create_const_node_func)(dbg_info *db, ir_node *block);
@@ -1494,6 +1370,374 @@ static ir_node *gen_Unknown(ir_node *node)
        panic("Unexpected Unknown mode");
 }
 
+/**
+ * Produces the type which sits between the stack args and the locals on the
+ * stack. It will contain the return address and space to store the old base
+ * pointer.
+ * @return The Firm type modeling the ABI between type.
+ */
+static ir_type *arm_get_between_type(void)
+{
+       static ir_type *between_type = NULL;
+
+       if (between_type == NULL) {
+               between_type = new_type_class(new_id_from_str("arm_between_type"));
+               set_type_size_bytes(between_type, 0);
+       }
+
+       return between_type;
+}
+
+static void create_stacklayout(ir_graph *irg)
+{
+       ir_entity         *entity        = get_irg_entity(irg);
+       ir_type           *function_type = get_entity_type(entity);
+       be_stack_layout_t *layout        = be_get_irg_stack_layout(irg);
+       ir_type           *arg_type;
+       int                p;
+       int                n_params;
+
+       /* calling conventions must be decided by now */
+       assert(cconv != NULL);
+
+       /* construct argument type */
+       arg_type = new_type_struct(id_mangle_u(get_entity_ident(entity), new_id_from_chars("arg_type", 8)));
+       n_params = get_method_n_params(function_type);
+       for (p = 0; p < n_params; ++p) {
+               reg_or_stackslot_t *param = &cconv->parameters[p];
+               char                buf[128];
+               ident              *id;
+
+               if (param->type == NULL)
+                       continue;
+
+               snprintf(buf, sizeof(buf), "param_%d", p);
+               id            = new_id_from_str(buf);
+               param->entity = new_entity(arg_type, id, param->type);
+               set_entity_offset(param->entity, param->offset);
+       }
+
+       /* TODO: what about external functions? we don't know most of the stack
+        * layout for them. And probably don't need all of this... */
+       memset(layout, 0, sizeof(*layout));
+
+       layout->frame_type     = get_irg_frame_type(irg);
+       layout->between_type   = arm_get_between_type();
+       layout->arg_type       = arg_type;
+       layout->param_map      = NULL; /* TODO */
+       layout->initial_offset = 0;
+       layout->initial_bias   = 0;
+       layout->stack_dir      = -1;
+
+       assert(N_FRAME_TYPES == 3);
+       layout->order[0] = layout->frame_type;
+       layout->order[1] = layout->between_type;
+       layout->order[2] = layout->arg_type;
+}
+
+/**
+ * transform the start node to the prolog code + initial barrier
+ */
+static ir_node *gen_Start(ir_node *node)
+{
+       ir_graph  *irg           = get_irn_irg(node);
+       ir_entity *entity        = get_irg_entity(irg);
+       ir_type   *function_type = get_entity_type(entity);
+       ir_node   *block         = get_nodes_block(node);
+       ir_node   *new_block     = be_transform_node(block);
+       dbg_info  *dbgi          = get_irn_dbg_info(node);
+       ir_node   *start;
+       ir_node   *incsp;
+       ir_node   *sp;
+       ir_node   *barrier;
+       int        i;
+
+       /* stackpointer is important at function prolog */
+       be_prolog_add_reg(abihelper, sp_reg,
+                       arch_register_req_type_produces_sp | arch_register_req_type_ignore);
+       /* function parameters in registers */
+       for (i = 0; i < get_method_n_params(function_type); ++i) {
+               const reg_or_stackslot_t *param = &cconv->parameters[i];
+               if (param->reg0 != NULL)
+                       be_prolog_add_reg(abihelper, param->reg0, 0);
+               if (param->reg1 != NULL)
+                       be_prolog_add_reg(abihelper, param->reg1, 0);
+       }
+       /* announce that we need the values of the callee save regs */
+       for (i = 0; i < (int) (sizeof(callee_saves)/sizeof(callee_saves[0])); ++i) {
+               be_prolog_add_reg(abihelper, callee_saves[i], 0);
+       }
+
+       start = be_prolog_create_start(abihelper, dbgi, new_block);
+       sp    = be_prolog_get_reg_value(abihelper, sp_reg);
+       incsp = be_new_IncSP(sp_reg, new_block, sp, BE_STACK_FRAME_SIZE_EXPAND, 0);
+       be_prolog_set_reg_value(abihelper, sp_reg, incsp);
+       barrier = be_prolog_create_barrier(abihelper, new_block);
+
+       return barrier;
+}
+
+static ir_node *get_stack_pointer_for(ir_node *node)
+{
+       /* get predecessor in stack_order list */
+       ir_node *stack_pred = be_get_stack_pred(abihelper, node);
+       ir_node *stack_pred_transformed;
+       ir_node *stack;
+
+       if (stack_pred == NULL) {
+               /* first stack user in the current block. We can simply use the
+                * initial sp_proj for it */
+               ir_node *sp_proj = be_prolog_get_reg_value(abihelper, sp_reg);
+               return sp_proj;
+       }
+
+       stack_pred_transformed = be_transform_node(stack_pred);
+       stack                  = pmap_get(node_to_stack, stack_pred);
+       if (stack == NULL) {
+               return get_stack_pointer_for(stack_pred);
+       }
+
+       return stack;
+}
+
+/**
+ * transform a Return node into epilogue code + return statement
+ */
+static ir_node *gen_Return(ir_node *node)
+{
+       ir_node   *block          = get_nodes_block(node);
+       ir_node   *new_block      = be_transform_node(block);
+       dbg_info  *dbgi           = get_irn_dbg_info(node);
+       ir_node   *mem            = get_Return_mem(node);
+       ir_node   *new_mem        = be_transform_node(mem);
+       int        n_callee_saves = sizeof(callee_saves)/sizeof(callee_saves[0]);
+       ir_node   *sp_proj        = get_stack_pointer_for(node);
+       ir_node   *bereturn;
+       ir_node   *incsp;
+       int        i;
+       int        n_res;
+       const arch_register_t *const result_regs[] = {
+               &arm_gp_regs[REG_R0],
+               &arm_gp_regs[REG_R1]
+       };
+
+       be_epilog_begin(abihelper);
+       be_epilog_set_memory(abihelper, new_mem);
+       /* connect stack pointer with initial stack pointer. fix_stack phase
+          will later serialize all stack pointer adjusting nodes */
+       be_epilog_add_reg(abihelper, sp_reg,
+                       arch_register_req_type_produces_sp | arch_register_req_type_ignore,
+                       sp_proj);
+
+       /* result values */
+       n_res = get_Return_n_ress(node);
+       if (n_res > (int) (sizeof(result_regs)/sizeof(result_regs[0]))) {
+               panic("Too many return values for arm backend (%+F)", node);
+       }
+       for (i = 0; i < n_res; ++i) {
+               ir_node               *res_value     = get_Return_res(node, i);
+               ir_node               *new_res_value = be_transform_node(res_value);
+               const arch_register_t *reg           = result_regs[i];
+               be_epilog_add_reg(abihelper, reg, 0, new_res_value);
+       }
+
+       /* connect callee saves with their values at the function begin */
+       for (i = 0; i < n_callee_saves; ++i) {
+               const arch_register_t *reg   = callee_saves[i];
+               ir_node               *value = be_prolog_get_reg_value(abihelper, reg);
+               be_epilog_add_reg(abihelper, reg, 0, value);
+       }
+
+       /* create the barrier before the epilog code */
+       be_epilog_create_barrier(abihelper, new_block);
+
+       /* epilog code: an incsp */
+       sp_proj = be_epilog_get_reg_value(abihelper, sp_reg);
+       incsp   = be_new_IncSP(sp_reg, new_block, sp_proj,
+                              BE_STACK_FRAME_SIZE_SHRINK, 0);
+       be_epilog_set_reg_value(abihelper, sp_reg, incsp);
+
+       bereturn = be_epilog_create_return(abihelper, dbgi, new_block);
+
+       return bereturn;
+}
+
+static ir_node *gen_Call(ir_node *node)
+{
+       ir_graph             *irg          = get_irn_irg(node);
+       ir_node              *callee       = get_Call_ptr(node);
+       ir_node              *block        = get_nodes_block(node);
+       ir_node              *new_block    = be_transform_node(block);
+       ir_node              *mem          = get_Call_mem(node);
+       ir_node              *new_mem      = be_transform_node(mem);
+       dbg_info             *dbgi         = get_irn_dbg_info(node);
+       ir_type              *type         = get_Call_type(node);
+       calling_convention_t *cconv        = decide_calling_convention(type);
+       int                   n_params     = get_Call_n_params(node);
+       int                   n_param_regs = sizeof(param_regs)/sizeof(param_regs[0]);
+       /* max inputs: memory, callee, register arguments */
+       int                   max_inputs   = 2 + n_param_regs;
+       ir_node             **in           = ALLOCAN(ir_node*, max_inputs);
+       ir_node             **sync_ins     = ALLOCAN(ir_node*, max_inputs);
+       struct obstack       *obst         = be_get_be_obst(irg);
+       const arch_register_req_t **in_req
+               = OALLOCNZ(obst, const arch_register_req_t*, max_inputs);
+       int                   in_arity     = 0;
+       int                   sync_arity   = 0;
+       int                   n_caller_saves
+               = sizeof(caller_saves)/sizeof(caller_saves[0]);
+       ir_entity            *entity       = NULL;
+       ir_node              *incsp        = NULL;
+       int                   mem_pos;
+       ir_node              *res;
+       int                   p;
+       int                   o;
+       int                   out_arity;
+
+       assert(n_params == get_method_n_params(type));
+
+       /* construct arguments */
+
+       /* memory input */
+       in_req[in_arity] = arch_no_register_req;
+       mem_pos          = in_arity;
+       ++in_arity;
+       /* parameters */
+       for (p = 0; p < n_params; ++p) {
+               ir_node                  *value     = get_Call_param(node, p);
+               ir_node                  *new_value = be_transform_node(value);
+               const reg_or_stackslot_t *param     = &cconv->parameters[p];
+               const arch_register_t    *reg       = param->reg0;
+
+               /* double not implemented yet */
+               assert(get_mode_size_bits(get_irn_mode(value)) <= 32);
+               assert(param->reg1 == NULL);
+
+               if (reg != NULL) {
+                       in[in_arity] = new_value;
+                       if (reg == &arm_gp_regs[REG_LR]) {
+                               in_req[in_arity] = be_create_reg_req(obst,
+                                               reg, arch_register_req_type_ignore);
+                       } else {
+                               in_req[in_arity] = reg->single_req;
+                       }
+                       ++in_arity;
+               } else {
+                       ir_mode *mode;
+                       ir_node *str;
+                       if (incsp == NULL) {
+                               ir_node *new_frame = get_stack_pointer_for(node);
+                               incsp = be_new_IncSP(sp_reg, new_block, new_frame, cconv->param_stack_size, 1);
+                       }
+                       mode = get_irn_mode(value);
+                       str  = new_bd_arm_Str(dbgi, new_block, incsp, value, new_mem, mode,
+                                             NULL, 0, param->offset, true);
+
+                       sync_ins[sync_arity++] = str;
+               }
+       }
+       assert(in_arity <= max_inputs);
+
+       /* construct memory input */
+       if (sync_arity == 0) {
+               in[mem_pos] = new_mem;
+       } else if (sync_arity == 1) {
+               in[mem_pos] = sync_ins[0];
+       } else {
+               in[mem_pos] = new_rd_Sync(NULL, new_block, sync_arity, sync_ins);
+       }
+
+       /* TODO: use a generic symconst matcher here */
+       if (is_SymConst(callee)) {
+               entity = get_SymConst_entity(callee);
+       } else {
+               /* TODO: finish load matcher here */
+#if 0
+               /* callee */
+               if (is_Proj(callee) && is_Load(get_Proj_pred(callee))) {
+                       ir_node *load    = get_Proj_pred(callee);
+                       ir_node *ptr     = get_Load_ptr(load);
+                       ir_node *new_ptr = be_transform_node(ptr);
+                       ir_node *mem     = get_Load_mem(load);
+                       ir_node *new_mem = be_transform_node(mem);
+                       ir_mode *mode    = get_Load_mode(node);
+
+               } else {
+#endif
+                       in[in_arity]     = be_transform_node(callee);
+                       in_req[in_arity] = arm_reg_classes[CLASS_arm_gp].class_req;
+                       ++in_arity;
+               //}
+       }
+
+       /* outputs:
+        *  - memory
+        *  - caller saves
+        */
+       out_arity = 1 + n_caller_saves;
+
+       if (entity != NULL) {
+               /* TODO: use a generic symconst matcher here
+                * so we can also handle entity+offset, etc. */
+               res = new_bd_arm_Bl(dbgi, new_block, in_arity, in, out_arity,entity, 0);
+       } else {
+               /* TODO:
+                * - use a proper shifter_operand matcher
+                * - we could also use LinkLdrPC
+                */
+               res = new_bd_arm_LinkMovPC(dbgi, new_block, in_arity, in, out_arity,
+                                          ARM_SHF_REG, 0, 0);
+       }
+
+       if (incsp != NULL) {
+               /* IncSP to destroy the call stackframe */
+               incsp = be_new_IncSP(sp_reg, new_block, incsp, -cconv->param_stack_size,
+                                    0);
+               /* if we are the last IncSP producer in a block then we have to keep
+                * the stack value.
+                * Note: This here keeps all producers which is more than necessary */
+               add_irn_dep(incsp, res);
+               keep_alive(incsp);
+
+               pmap_insert(node_to_stack, node, incsp);
+       }
+
+       set_arm_in_req_all(res, in_req);
+
+       /* create output register reqs */
+       arch_set_out_register_req(res, 0, arch_no_register_req);
+       for (o = 1; o < n_caller_saves + 1; ++o) {
+               const arch_register_t *reg = caller_saves[o-1];
+               arch_set_out_register_req(res, o, reg->single_req);
+       }
+
+       /* copy pinned attribute */
+       set_irn_pinned(res, get_irn_pinned(node));
+
+       free_calling_convention(cconv);
+       return res;
+}
+
+static ir_node *gen_Sel(ir_node *node)
+{
+       dbg_info  *dbgi      = get_irn_dbg_info(node);
+       ir_node   *block     = get_nodes_block(node);
+       ir_node   *new_block = be_transform_node(block);
+       ir_node   *ptr       = get_Sel_ptr(node);
+       ir_node   *new_ptr   = be_transform_node(ptr);
+       ir_entity *entity    = get_Sel_entity(node);
+
+       /* must be the frame pointer all other sels must have been lowered
+        * already */
+       assert(is_Proj(ptr) && is_Start(get_Proj_pred(ptr)));
+       /* we should not have value types from parameters anymore - they should be
+          lowered */
+       assert(get_entity_owner(entity) !=
+                       get_method_value_param_type(get_entity_type(get_irg_entity(get_irn_irg(node)))));
+
+       return new_bd_arm_FrameAddr(dbgi, new_block, new_ptr, entity, 0);
+}
+
 /**
  * Change some phi modes
  */
@@ -1530,6 +1774,7 @@ static ir_node *gen_Phi(ir_node *node)
        return phi;
 }
 
+
 /**
  * Enters all transform functions into the generic pointer
  */
@@ -1537,37 +1782,36 @@ static void arm_register_transformers(void)
 {
        be_start_transform_setup();
 
-       be_set_transform_function(op_Abs,          gen_Abs);
-       be_set_transform_function(op_Add,          gen_Add);
-       be_set_transform_function(op_And,          gen_And);
-       be_set_transform_function(op_be_AddSP,     gen_be_AddSP);
-       be_set_transform_function(op_be_Call,      gen_be_Call);
-       be_set_transform_function(op_be_Copy,      gen_be_Copy);
-       be_set_transform_function(op_be_FrameAddr, gen_be_FrameAddr);
-       be_set_transform_function(op_be_SubSP,     gen_be_SubSP);
-       be_set_transform_function(op_Cmp,          gen_Cmp);
-       be_set_transform_function(op_Cond,         gen_Cond);
-       be_set_transform_function(op_Const,        gen_Const);
-       be_set_transform_function(op_Conv,         gen_Conv);
-       be_set_transform_function(op_CopyB,        gen_CopyB);
-       be_set_transform_function(op_Eor,          gen_Eor);
-       be_set_transform_function(op_Jmp,          gen_Jmp);
-       be_set_transform_function(op_Load,         gen_Load);
-       be_set_transform_function(op_Minus,        gen_Minus);
-       be_set_transform_function(op_Mul,          gen_Mul);
-       be_set_transform_function(op_Not,          gen_Not);
-       be_set_transform_function(op_Or,           gen_Or);
-       be_set_transform_function(op_Phi,          gen_Phi);
-       be_set_transform_function(op_Proj,         gen_Proj);
-       be_set_transform_function(op_Quot,         gen_Quot);
-       be_set_transform_function(op_Rotl,         gen_Rotl);
-       be_set_transform_function(op_Shl,          gen_Shl);
-       be_set_transform_function(op_Shr,          gen_Shr);
-       be_set_transform_function(op_Shrs,         gen_Shrs);
-       be_set_transform_function(op_Store,        gen_Store);
-       be_set_transform_function(op_Sub,          gen_Sub);
-       be_set_transform_function(op_SymConst,     gen_SymConst);
-       be_set_transform_function(op_Unknown,      gen_Unknown);
+       be_set_transform_function(op_Abs,      gen_Abs);
+       be_set_transform_function(op_Add,      gen_Add);
+       be_set_transform_function(op_And,      gen_And);
+       be_set_transform_function(op_Call,     gen_Call);
+       be_set_transform_function(op_Cmp,      gen_Cmp);
+       be_set_transform_function(op_Cond,     gen_Cond);
+       be_set_transform_function(op_Const,    gen_Const);
+       be_set_transform_function(op_Conv,     gen_Conv);
+       be_set_transform_function(op_CopyB,    gen_CopyB);
+       be_set_transform_function(op_Eor,      gen_Eor);
+       be_set_transform_function(op_Jmp,      gen_Jmp);
+       be_set_transform_function(op_Load,     gen_Load);
+       be_set_transform_function(op_Minus,    gen_Minus);
+       be_set_transform_function(op_Mul,      gen_Mul);
+       be_set_transform_function(op_Not,      gen_Not);
+       be_set_transform_function(op_Or,       gen_Or);
+       be_set_transform_function(op_Phi,      gen_Phi);
+       be_set_transform_function(op_Proj,     gen_Proj);
+       be_set_transform_function(op_Quot,     gen_Quot);
+       be_set_transform_function(op_Return,   gen_Return);
+       be_set_transform_function(op_Rotl,     gen_Rotl);
+       be_set_transform_function(op_Sel,      gen_Sel);
+       be_set_transform_function(op_Shl,      gen_Shl);
+       be_set_transform_function(op_Shr,      gen_Shr);
+       be_set_transform_function(op_Shrs,     gen_Shrs);
+       be_set_transform_function(op_Start,    gen_Start);
+       be_set_transform_function(op_Store,    gen_Store);
+       be_set_transform_function(op_Sub,      gen_Sub);
+       be_set_transform_function(op_SymConst, gen_SymConst);
+       be_set_transform_function(op_Unknown,  gen_Unknown);
 }
 
 /**
@@ -1610,6 +1854,11 @@ static void arm_init_fpa_immediate(void)
 void arm_transform_graph(arm_code_gen_t *cg)
 {
        static int imm_initialized = 0;
+       ir_graph  *irg             = cg->irg;
+       ir_entity *entity          = get_irg_entity(irg);
+       ir_type   *frame_type;
+
+       mode_gp = mode_Iu;
 
        if (! imm_initialized) {
                arm_init_fpa_immediate();
@@ -1617,7 +1866,33 @@ void arm_transform_graph(arm_code_gen_t *cg)
        }
        arm_register_transformers();
        env_cg = cg;
+
+       node_to_stack = pmap_create();
+
+       assert(abihelper == NULL);
+       abihelper = be_abihelper_prepare(irg);
+       be_collect_stacknodes(abihelper);
+       assert(cconv == NULL);
+       cconv = decide_calling_convention(get_entity_type(entity));
+       create_stacklayout(irg);
+
        be_transform_graph(cg->irg, NULL);
+
+       be_abihelper_finish(abihelper);
+       abihelper = NULL;
+
+       free_calling_convention(cconv);
+       cconv = NULL;
+
+       frame_type = get_irg_frame_type(irg);
+       if (get_type_state(frame_type) == layout_undefined) {
+               default_layout_compound_type(frame_type);
+       }
+
+       pmap_destroy(node_to_stack);
+       node_to_stack = NULL;
+
+       be_add_missing_keeps(irg);
 }
 
 void arm_init_transform(void)
index 023781f..383c1c0 100644 (file)
@@ -72,6 +72,7 @@
 static arch_irn_class_t arm_classify(const ir_node *irn)
 {
        (void) irn;
+       /* TODO: we should mark reload/spill instructions and classify them here */
        return 0;
 }
 
@@ -119,7 +120,7 @@ static void arm_set_stack_bias(ir_node *irn, int bias)
 static int arm_get_sp_bias(const ir_node *irn)
 {
        /* We don't have any nodes changing the stack pointer.
-               TODO: we probably want to support post-/pre increment/decrement later */
+          We probably want to support post-/pre increment/decrement later */
        (void) irn;
        return 0;
 }
@@ -200,10 +201,9 @@ static void arm_before_ra(void *self)
 
 static void transform_Reload(ir_node *node)
 {
-       ir_graph  *irg    = get_irn_irg(node);
        ir_node   *block  = get_nodes_block(node);
        dbg_info  *dbgi   = get_irn_dbg_info(node);
-       ir_node   *ptr    = get_irg_frame(irg);
+       ir_node   *ptr    = get_irn_n(node, be_pos_Reload_frame);
        ir_node   *mem    = get_irn_n(node, be_pos_Reload_mem);
        ir_mode   *mode   = get_irn_mode(node);
        ir_entity *entity = be_get_frame_entity(node);
@@ -227,10 +227,9 @@ static void transform_Reload(ir_node *node)
 
 static void transform_Spill(ir_node *node)
 {
-       ir_graph  *irg    = get_irn_irg(node);
        ir_node   *block  = get_nodes_block(node);
        dbg_info  *dbgi   = get_irn_dbg_info(node);
-       ir_node   *ptr    = get_irg_frame(irg);
+       ir_node   *ptr    = get_irn_n(node, be_pos_Spill_frame);
        ir_node   *mem    = new_NoMem();
        ir_node   *val    = get_irn_n(node, be_pos_Spill_val);
        ir_mode   *mode   = get_irn_mode(val);
@@ -288,205 +287,13 @@ static void arm_emit_and_done(void *self)
        free(self);
 }
 
-/**
- * Move a double floating point value into an integer register.
- * Place the move operation into block bl.
- *
- * Handle some special cases here:
- * 1.) A constant: simply split into two
- * 2.) A load: simply split into two
- */
-static ir_node *convert_dbl_to_int(ir_node *bl, ir_node *arg, ir_node *mem,
-                                   ir_node **resH, ir_node **resL)
-{
-       if (is_Const(arg)) {
-               tarval *tv = get_Const_tarval(arg);
-               unsigned v;
-
-               /* get the upper 32 bits */
-               v =            get_tarval_sub_bits(tv, 7);
-               v = (v << 8) | get_tarval_sub_bits(tv, 6);
-               v = (v << 8) | get_tarval_sub_bits(tv, 5);
-               v = (v << 8) | get_tarval_sub_bits(tv, 4);
-               *resH = new_Const_long(mode_Is, v);
-
-               /* get the lower 32 bits */
-               v =            get_tarval_sub_bits(tv, 3);
-               v = (v << 8) | get_tarval_sub_bits(tv, 2);
-               v = (v << 8) | get_tarval_sub_bits(tv, 1);
-               v = (v << 8) | get_tarval_sub_bits(tv, 0);
-               *resL = new_Const_long(mode_Is, v);
-       } else if (is_Load(skip_Proj(arg))) {
-               /* FIXME: handling of low/high depends on LE/BE here */
-               panic("Unimplemented convert_dbl_to_int() case");
-       }
-       else {
-               ir_node *conv;
-
-               conv = new_bd_arm_fpaDbl2GP(NULL, bl, arg, mem);
-               /* move high/low */
-               *resL = new_r_Proj(conv, mode_Is, pn_arm_fpaDbl2GP_low);
-               *resH = new_r_Proj(conv, mode_Is, pn_arm_fpaDbl2GP_high);
-               mem   = new_r_Proj(conv, mode_M,  pn_arm_fpaDbl2GP_M);
-       }
-       return mem;
-}
-
-/**
- * Move a single floating point value into an integer register.
- * Place the move operation into block bl.
- *
- * Handle some special cases here:
- * 1.) A constant: simply move
- * 2.) A load: simply load
- */
-static ir_node *convert_sng_to_int(ir_node *bl, ir_node *arg)
-{
-       (void) bl;
-
-       if (is_Const(arg)) {
-               tarval *tv = get_Const_tarval(arg);
-               unsigned v;
-
-               /* get the lower 32 bits */
-               v =            get_tarval_sub_bits(tv, 3);
-               v = (v << 8) | get_tarval_sub_bits(tv, 2);
-               v = (v << 8) | get_tarval_sub_bits(tv, 1);
-               v = (v << 8) | get_tarval_sub_bits(tv, 0);
-               return new_Const_long(mode_Is, v);
-       }
-       panic("Unimplemented convert_sng_to_int() case");
-}
-
-/**
- * Convert the arguments of a call to support the
- * ARM calling convention of general purpose AND floating
- * point arguments.
- */
-static void handle_calls(ir_node *call, void *env)
-{
-       arm_code_gen_t *cg = env;
-       int i, j, n, size, idx, flag, n_param, n_res, first_variadic;
-       ir_type *mtp, *new_mtd, *new_tp[5];
-       ir_node *new_in[5], **in;
-       ir_node *bl;
-
-       if (! is_Call(call))
-               return;
-
-       /* check, if we need conversions */
-       n = get_Call_n_params(call);
-       mtp = get_Call_type(call);
-       assert(get_method_n_params(mtp) == n);
-
-       /* it's always enough to handle the first 4 parameters */
-       if (n > 4)
-               n = 4;
-       flag = size = idx = 0;
-       bl = get_nodes_block(call);
-       for (i = 0; i < n; ++i) {
-               ir_type *param_tp = get_method_param_type(mtp, i);
-
-               if (is_compound_type(param_tp)) {
-                       /* an aggregate parameter: bad case */
-                       assert(0);
-               }
-               else {
-                       /* a primitive parameter */
-                       ir_mode *mode = get_type_mode(param_tp);
-
-                       if (mode_is_float(mode)) {
-                               if (get_mode_size_bits(mode) > 32) {
-                                       ir_node *mem = get_Call_mem(call);
-
-                                       /* Beware: ARM wants the high part first */
-                                       size += 2 * 4;
-                                       new_tp[idx]   = cg->int_tp;
-                                       new_tp[idx+1] = cg->int_tp;
-                                       mem = convert_dbl_to_int(bl, get_Call_param(call, i), mem, &new_in[idx], &new_in[idx+1]);
-                                       idx += 2;
-                                       set_Call_mem(call, mem);
-                               }
-                               else {
-                                       size += 4;
-                                       new_tp[idx] = cg->int_tp;
-                                       new_in[idx] = convert_sng_to_int(bl, get_Call_param(call, i));
-                                       ++idx;
-                               }
-                               flag = 1;
-                       }
-                       else {
-                               size += 4;
-                               new_tp[idx] = param_tp;
-                               new_in[idx] = get_Call_param(call, i);
-                               ++idx;
-                       }
-               }
-
-               if (size >= 16)
-                       break;
-       }
-
-       /* if flag is NOT set, no need to translate the method type */
-       if (! flag)
-               return;
-
-       /* construct a new method type */
-       n       = i;
-       n_param = get_method_n_params(mtp) - n + idx;
-       n_res   = get_method_n_ress(mtp);
-       new_mtd = new_d_type_method(n_param, n_res, get_type_dbg_info(mtp));
-
-       for (i = 0; i < idx; ++i)
-               set_method_param_type(new_mtd, i, new_tp[i]);
-       for (i = n, j = idx; i < get_method_n_params(mtp); ++i)
-               set_method_param_type(new_mtd, j++, get_method_param_type(mtp, i));
-       for (i = 0; i < n_res; ++i)
-               set_method_res_type(new_mtd, i, get_method_res_type(mtp, i));
-
-       set_method_calling_convention(new_mtd, get_method_calling_convention(mtp));
-       first_variadic = get_method_first_variadic_param_index(mtp);
-       if (first_variadic >= 0)
-               set_method_first_variadic_param_index(new_mtd, first_variadic);
-
-       if (is_lowered_type(mtp)) {
-               mtp = get_associated_type(mtp);
-       }
-       set_lowered_type(mtp, new_mtd);
-
-       set_Call_type(call, new_mtd);
-
-       /* calculate new in array of the Call */
-       NEW_ARR_A(ir_node *, in, n_param + 2);
-       for (i = 0; i < idx; ++i)
-               in[2 + i] = new_in[i];
-       for (i = n, j = idx; i < get_method_n_params(mtp); ++i)
-               in[2 + j++] = get_Call_param(call, i);
-
-       in[0] = get_Call_mem(call);
-       in[1] = get_Call_ptr(call);
-
-       /* finally, change the call inputs */
-       set_irn_in(call, n_param + 2, in);
-}
-
-/**
- * Handle graph transformations before the abi converter does its work.
- */
-static void arm_before_abi(void *self)
-{
-       arm_code_gen_t *cg = self;
-
-       irg_walk_graph(cg->irg, NULL, handle_calls, cg);
-}
-
 /* forward */
 static void *arm_cg_init(ir_graph *irg);
 
 static const arch_code_generator_if_t arm_code_gen_if = {
        arm_cg_init,
        NULL,               /* get_pic_base */
-       arm_before_abi,     /* before abi introduce */
+       NULL,               /* before abi introduce */
        arm_prepare_graph,
        NULL,               /* spill */
        arm_before_ra,      /* before register allocation hook */
@@ -667,7 +474,7 @@ static arm_isa_t arm_isa_template = {
                NULL,                  /* main environment */
                7,                     /* spill costs */
                5,                     /* reload costs */
-               false,                 /* no custom abi handling */
+               true,                  /* we do have custom abi handling */
        },
        0,                     /* use generic register names instead of SP, LR, PC */
        ARM_FPU_ARCH_FPE,      /* FPU architecture */
@@ -932,7 +739,7 @@ static void arm_get_call_abi(const void *self, ir_type *method_type, be_abi_call
        call_flags.bits.store_args_sequential = 0;
        /* call_flags.bits.try_omit_fp     don't change this we can handle both */
        call_flags.bits.fp_free               = 0;
-       call_flags.bits.call_has_imm          = 1;  /* IA32 calls can have immediate address */
+       call_flags.bits.call_has_imm          = 1;
 
        /* set stack parameter passing style */
        be_abi_call_set_flags(abi, call_flags, &arm_abi_callbacks);
index 958b4a3..06662f0 100644 (file)
@@ -2240,7 +2240,7 @@ static void fix_pic_symconsts(ir_node *node, void *data)
 
 be_abi_irg_t *be_abi_introduce(ir_graph *irg)
 {
-       be_abi_irg_t     *env         = XMALLOC(be_abi_irg_t);
+       be_abi_irg_t     *env         = XMALLOCZ(be_abi_irg_t);
        ir_node          *old_frame   = get_irg_frame(irg);
        struct obstack   *obst        = be_get_be_obst(irg);
        be_options_t     *options     = be_get_irg_options(irg);
@@ -2283,13 +2283,12 @@ be_abi_irg_t *be_abi_introduce(ir_graph *irg)
         * Note: we shouldn't have to setup any be_abi_irg_t* stuff at all,
         * but need more cleanup to make this work
         */
+       be_set_irg_abi(irg, env);
        if (arch_env->custom_abi)
                return env;
 
        env->init_sp = dummy = new_r_Dummy(irg, arch_env->sp->reg_class->mode);
-
-       env->calls = NEW_ARR_F(ir_node*, 0);
-       be_set_irg_abi(irg, env);
+       env->calls   = NEW_ARR_F(ir_node*, 0);
 
        if (options->pic) {
                irg_walk_graph(irg, fix_pic_symconsts, NULL, env);
@@ -2339,8 +2338,10 @@ void be_abi_free(ir_graph *irg)
 
        be_abi_call_free(env->call);
        free_survive_dce(env->dce_survivor);
-       del_pset(env->ignore_regs);
-       pmap_destroy(env->regs);
+       if (env->ignore_regs != NULL)
+               del_pset(env->ignore_regs);
+       if (env->regs != NULL)
+               pmap_destroy(env->regs);
        free(env);
 
        be_set_irg_abi(irg, NULL);
index 7cdd205..e6d5928 100644 (file)
@@ -33,6 +33,8 @@
 #include "ircons.h"
 #include "iredges.h"
 #include "irgwalk.h"
+#include "irphase_t.h"
+#include "height.h"
 
 typedef struct reg_flag_t {
        const arch_register_t *reg;   /**< register at an input position.
@@ -58,6 +60,7 @@ struct beabi_helper_env_t {
        ir_graph                 *irg;
        register_state_mapping_t  prolog;
        register_state_mapping_t  epilog;
+       ir_phase                 *stack_order;
 };
 
 static void prepare_rsm(register_state_mapping_t *rsm,
@@ -441,3 +444,138 @@ void be_add_missing_keeps(ir_graph *irg)
 {
        irg_walk_graph(irg, add_missing_keep_walker, NULL, NULL);
 }
+
+
+
+static void collect_node(ir_node *node)
+{
+       ir_node *block = get_nodes_block(node);
+       ir_node *old   = get_irn_link(block);
+
+       set_irn_link(node, old);
+       set_irn_link(block, node);
+}
+
+static void link_ops_in_block_walker(ir_node *node, void *data)
+{
+       (void) data;
+
+       switch (get_irn_opcode(node)) {
+       case iro_Return:
+       case iro_Call:
+               collect_node(node);
+               break;
+       case iro_Alloc:
+               /** all non-stack alloc nodes should be lowered before the backend */
+               assert(get_Alloc_where(node) == stack_alloc);
+               collect_node(node);
+               break;
+       case iro_Free:
+               assert(get_Free_where(node) == stack_alloc);
+               collect_node(node);
+               break;
+       case iro_Builtin:
+               if (get_Builtin_kind(node) == ir_bk_return_address) {
+                       ir_node *param = get_Builtin_param(node, 0);
+                       tarval  *tv    = get_Const_tarval(param); /* must be Const */
+                       long     value = get_tarval_long(tv);
+                       if (value > 0) {
+                               /* we need esp for the climbframe algo */
+                               collect_node(node);
+                       }
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+static heights_t *heights;
+
+/**
+ * Check if a node is somehow data dependent on another one.
+ * both nodes must be in the same basic block.
+ * @param n1 The first node.
+ * @param n2 The second node.
+ * @return 1, if n1 is data dependent (transitively) on n2, 0 if not.
+ */
+static int dependent_on(const ir_node *n1, const ir_node *n2)
+{
+       assert(get_nodes_block(n1) == get_nodes_block(n2));
+
+       return heights_reachable_in_block(heights, n1, n2);
+}
+
+static int cmp_call_dependency(const void *c1, const void *c2)
+{
+       const ir_node *n1 = *(const ir_node **) c1;
+       const ir_node *n2 = *(const ir_node **) c2;
+
+       /*
+               Classical qsort() comparison function behavior:
+               0  if both elements are equal
+               1  if second is "smaller" that first
+               -1 if first is "smaller" that second
+       */
+       if (dependent_on(n1, n2))
+               return 1;
+
+       if (dependent_on(n2, n1))
+               return -1;
+
+       /* The nodes have no depth order, but we need a total order because qsort()
+        * is not stable. */
+       return get_irn_idx(n2) - get_irn_idx(n1);
+}
+
+static void process_ops_in_block(ir_node *block, void *data)
+{
+       ir_phase *phase = data;
+       unsigned  n;
+       unsigned  n_nodes;
+       ir_node  *node;
+       ir_node **nodes;
+
+       n_nodes = 0;
+       for (node = get_irn_link(block); node != NULL; node = get_irn_link(node)) {
+               ++n_nodes;
+       }
+
+       if (n_nodes == 0)
+               return;
+
+       nodes = XMALLOCN(ir_node*, n_nodes);
+       n = 0;
+       for (node = get_irn_link(block); node != NULL; node = get_irn_link(node)) {
+               nodes[n++] = node;;
+       }
+       assert(n == n_nodes);
+
+       /* order nodes according to their data dependencies */
+       qsort(nodes, n_nodes, sizeof(nodes[0]), cmp_call_dependency);
+
+       for (n = n_nodes-1; n > 0; --n) {
+               ir_node *node = nodes[n];
+               ir_node *pred = nodes[n-1];
+
+               phase_set_irn_data(phase, node, pred);
+       }
+}
+
+void be_collect_stacknodes(beabi_helper_env_t *env)
+{
+       ir_graph *irg = env->irg;
+       irg_walk_graph(irg, firm_clear_link, link_ops_in_block_walker, NULL);
+
+       assert(env->stack_order == NULL);
+       env->stack_order = new_phase(irg, phase_irn_init_default);
+
+       heights = heights_new(irg);
+       irg_block_walk_graph(irg, NULL, process_ops_in_block, env->stack_order);
+       heights_free(heights);
+}
+
+ir_node *be_get_stack_pred(const beabi_helper_env_t *env, const ir_node *node)
+{
+       return phase_get_irn_data(env->stack_order, node);
+}
index 09f8a86..9eb1a2d 100644 (file)
@@ -108,10 +108,21 @@ ir_node *be_epilog_create_barrier(beabi_helper_env_t *env, ir_node *block);
 ir_node *be_epilog_create_return(beabi_helper_env_t *env, dbg_info *dbgi,
                                  ir_node *block);
 
-
 /**
  * Adds a X->Proj->Keep for each output value of X which has no Proj yet
  */
 void be_add_missing_keeps(ir_graph *irg);
 
+/**
+ * Collect firm nodes that will probably modify the stack.
+ * Put them into an order that respects all their dependencies.
+ */
+void be_collect_stacknodes(beabi_helper_env_t *env);
+
+/**
+ * return node that should produce the predecessor stack node in a block.
+ * returns NULL if there's no predecessor in the current block.
+ */
+ir_node *be_get_stack_pred(const beabi_helper_env_t *env, const ir_node *node);
+
 #endif
index 5cf6d13..1ea9094 100644 (file)
@@ -445,6 +445,9 @@ static void dump(int mask, ir_graph *irg, const char *suffix)
  */
 static void initialize_birg(be_irg_t *birg, ir_graph *irg, be_main_env_t *env)
 {
+       /* don't duplicate locals in backend when dumping... */
+       ir_remove_dump_flags(ir_dump_flag_consts_local);
+
        dump(DUMP_INITIAL, irg, "begin");
 
        irg->be_data = birg;
@@ -629,6 +632,7 @@ static void be_main_loop(FILE *file_handle, const char *cup_name)
                birg->cg = cg_if->init(irg);
 
                /* some transformations need to be done before abi introduce */
+               assert(birg->cg->impl->before_abi == NULL || !arch_env->custom_abi);
                arch_code_generator_before_abi(birg->cg);
 
                /* implement the ABI conventions. */
@@ -636,23 +640,24 @@ static void be_main_loop(FILE *file_handle, const char *cup_name)
                be_abi_introduce(irg);
                be_timer_pop(T_ABI);
 
-               dump(DUMP_ABI, irg, "abi");
-
-               /* do local optimizations */
-               optimize_graph_df(irg);
+               if (!arch_env->custom_abi) {
+                       dump(DUMP_ABI, irg, "abi");
+                       /* do local optimizations */
+                       optimize_graph_df(irg);
+               }
 
                /* we have to do cfopt+remove_critical_edges as we can't have Bad-blocks
                 * or critical edges in the backend */
                optimize_cf(irg);
                remove_critical_cf_edges(irg);
 
-               /* TODO: we often have dead code reachable through out-edges here. So for
-                * now we rebuild edges (as we need correct user count for code selection)
-                */
+               /* We often have dead code reachable through out-edges here. So for
+                * now we rebuild edges (as we need correct user count for code
+                * selection) */
                edges_deactivate(irg);
                edges_activate(irg);
 
-               dump(DUMP_PREPARED, irg, "pre_transform");
+               dump(DUMP_PREPARED, irg, "before-code-selection");
 
                if (be_options.vrfy_option == BE_VRFY_WARN) {
                        be_check_dominance(irg);
@@ -660,13 +665,11 @@ static void be_main_loop(FILE *file_handle, const char *cup_name)
                        assert(be_check_dominance(irg) && "Dominance verification failed");
                }
 
-               /* generate code */
+               /* perform codeselection */
                be_timer_push(T_CODEGEN);
                arch_code_generator_prepare_graph(birg->cg);
                be_timer_pop(T_CODEGEN);
 
-               dump(DUMP_PREPARED, irg, "prepared");
-
                if (be_options.vrfy_option == BE_VRFY_WARN) {
                        be_check_dominance(irg);
                } else if (be_options.vrfy_option == BE_VRFY_ASSERT) {