introduce be_foreach_use and use it
[libfirm] / ir / be / bemain.c
index 4c8e887..e55f1ef 100644 (file)
@@ -1,92 +1,99 @@
+/*
+ * Copyright (C) 1995-2011 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.
+ */
+
 /**
- * Backend driver.
- * @author Sebastian Hack
- * @date   25.11.2004
- * @cvsid  $Id$
+ * @file
+ * @brief       Main Backend driver.
+ * @author      Sebastian Hack
+ * @date        25.11.2004
  */
-#ifdef HAVE_CONFIG_H
 #include "config.h"
-#endif
 
 #include <stdarg.h>
+#include <stdio.h>
 
-#ifdef WITH_LIBCORE
-#include <libcore/lc_opts.h>
-#include <libcore/lc_opts_enum.h>
-#include <libcore/lc_timing.h>
-#endif /* WITH_LIBCORE */
+#include "lc_opts.h"
+#include "lc_opts_enum.h"
 
 #include "obst.h"
 #include "bitset.h"
-
+#include "statev.h"
 #include "irprog.h"
 #include "irgopt.h"
 #include "irgraph.h"
 #include "irdump.h"
-#include "phiclass.h"
 #include "irdom_t.h"
 #include "iredges_t.h"
 #include "irloop_t.h"
 #include "irtools.h"
-#include "return.h"
+#include "irverify.h"
+#include "irprintf.h"
+#include "iroptimize.h"
+#include "firmstat.h"
+#include "execfreq_t.h"
+#include "irprofile.h"
+#include "irpass_t.h"
+#include "ircons.h"
 
 #include "bearch.h"
-#include "firm/bearch_firm.h"
-#include "ia32/bearch_ia32.h"
-#include "arm/bearch_arm.h"
-#include "ppc32/bearch_ppc32.h"
-#include "mips/bearch_mips.h"
-
 #include "be_t.h"
-#include "benumb_t.h"
+#include "bemodule.h"
 #include "beutil.h"
-#include "benode_t.h"
+#include "benode.h"
 #include "beirgmod.h"
-#include "besched_t.h"
+#include "besched.h"
 #include "belistsched.h"
 #include "belive_t.h"
-#include "bespillilp.h"
-#include "bespillbelady.h"
 #include "bera.h"
-#include "beraextern.h"
 #include "bechordal_t.h"
 #include "beifg.h"
-#include "beifg_impl.h"
 #include "becopyopt.h"
 #include "becopystat.h"
 #include "bessadestr.h"
 #include "beabi.h"
 #include "belower.h"
-#include "beschedmris.h"
 #include "bestat.h"
 #include "beverify.h"
+#include "beirg.h"
+#include "bestack.h"
+#include "beemitter.h"
+
+#define NEW_ID(s) new_id_from_chars(s, sizeof(s) - 1)
 
 /* options visible for anyone */
-static be_options_t be_options = {
-       DUMP_NONE,                         /* dump options */
+be_options_t be_options = {
+       DUMP_NONE,                         /* dump flags */
        BE_TIME_OFF,                       /* no timing */
-       "i44pc52.info.uni-karlsruhe.de",   /* ilp server */
-       "cplex"                            /* ilp solver */
+       false,                             /* profile_generate */
+       false,                             /* profile_use */
+       0,                                 /* try to omit frame pointer */
+       0,                                 /* create PIC code */
+       BE_VERIFY_WARN,                    /* verification level: warn */
+       "",                                /* ilp server */
+       "",                                /* ilp solver */
+       0,                                 /* enable statistic event dumping */
+       "",                                /* print stat events */
+       1,                                 /* verbose assembler output */
 };
 
-/* dump flags */
-static unsigned dump_flags = 0;
-
-/* verify options */
-static unsigned vrfy_option = BE_VRFY_WARN;
-
-/* register allocator to use. */
-static const be_ra_t *ra = &be_ra_chordal_allocator;
-
 /* back end instruction set architecture to use */
-static const arch_isa_if_t *isa_if = &ia32_isa_if;
-
-/* mris option */
-static int be_enable_mris = 0;
-
-#ifdef WITH_LIBCORE
-
-static lc_opt_entry_t *be_grp_root = NULL;
+static const arch_isa_if_t *isa_if = NULL;
 
 /* possible dumping options */
 static const lc_opt_enum_mask_items_t dump_items[] = {
@@ -102,141 +109,287 @@ static const lc_opt_enum_mask_items_t dump_items[] = {
        { NULL,         0 }
 };
 
-/* register allocators */
-static const lc_opt_enum_const_ptr_items_t ra_items[] = {
-       { "chordal",  &be_ra_chordal_allocator },
-       { "external", &be_ra_external_allocator },
-       { NULL,      NULL }
-};
-
-/* instruction set architectures. */
-static const lc_opt_enum_const_ptr_items_t isa_items[] = {
-       { "ia32",    &ia32_isa_if },
-#if 0
-       { "arm",     &arm_isa_if },
-       { "ppc32",   &ppc32_isa_if },
-       { "mips",    &mips_isa_if },
-#endif
-       { NULL,      NULL }
-};
-
 /* verify options. */
-static const lc_opt_enum_int_items_t vrfy_items[] = {
-       { "off",    BE_VRFY_OFF    },
-       { "warn",   BE_VRFY_WARN   },
-       { "assert", BE_VRFY_ASSERT },
+static const lc_opt_enum_int_items_t verify_items[] = {
+       { "off",    BE_VERIFY_OFF    },
+       { "warn",   BE_VERIFY_WARN   },
+       { "assert", BE_VERIFY_ASSERT },
        { NULL,     0 }
 };
 
 static lc_opt_enum_mask_var_t dump_var = {
-       &dump_flags, dump_items
-};
-
-static lc_opt_enum_const_ptr_var_t ra_var = {
-       (const void **) &ra, ra_items
-};
-
-static lc_opt_enum_const_ptr_var_t isa_var = {
-       (const void **) &isa_if, isa_items
+       &be_options.dump_flags, dump_items
 };
 
-static lc_opt_enum_int_var_t vrfy_var = {
-       &vrfy_option, vrfy_items
+static lc_opt_enum_int_var_t verify_var = {
+       &be_options.verify_option, verify_items
 };
 
 static const lc_opt_table_entry_t be_main_options[] = {
-       LC_OPT_ENT_ENUM_MASK("dump",     "dump irg on several occasions",     &dump_var),
-       LC_OPT_ENT_ENUM_PTR ("ra",       "register allocator",                &ra_var),
-       LC_OPT_ENT_ENUM_PTR ("isa",      "the instruction set architecture",  &isa_var),
-       LC_OPT_ENT_NEGBOOL  ("noomitfp", "do not omit frame pointer",         &be_omit_fp),
-       LC_OPT_ENT_BOOL     ("mris",     "enable mris schedule preparation",  &be_enable_mris),
-       LC_OPT_ENT_ENUM_PTR ("vrfy",     "verify the backend irg (off, warn, assert)",  &vrfy_var),
-       LC_OPT_ENT_BOOL     ("time",     "get backend timing statistics",     &be_options.timing),
-
-#ifdef WITH_ILP
-       LC_OPT_ENT_STR ("ilp.server", "the ilp server name", be_options.ilp_server, sizeof(be_options.ilp_server)),
-       LC_OPT_ENT_STR ("ilp.solver", "the ilp solver name", be_options.ilp_solver, sizeof(be_options.ilp_solver)),
-#endif /* WITH_ILP */
-       { NULL }
+       LC_OPT_ENT_ENUM_MASK("dump",       "dump irg on several occasions",                       &dump_var),
+       LC_OPT_ENT_BOOL     ("omitfp",     "omit frame pointer",                                  &be_options.omit_fp),
+       LC_OPT_ENT_BOOL     ("pic",        "create PIC code",                                     &be_options.pic),
+       LC_OPT_ENT_ENUM_INT ("verify",     "verify the backend irg",                              &verify_var),
+       LC_OPT_ENT_BOOL     ("time",       "get backend timing statistics",                       &be_options.timing),
+       LC_OPT_ENT_BOOL     ("profilegenerate", "instrument the code for execution count profiling",   &be_options.opt_profile_generate),
+       LC_OPT_ENT_BOOL     ("profileuse",      "use existing profile data",                           &be_options.opt_profile_use),
+       LC_OPT_ENT_BOOL     ("statev",     "dump statistic events",                               &be_options.statev),
+       LC_OPT_ENT_STR      ("filtev",     "filter for stat events (regex if support is active",   be_options.filtev),
+       LC_OPT_ENT_BOOL     ("verboseasm", "enable verbose assembler output",                     &be_options.verbose_asm),
+
+       LC_OPT_ENT_STR("ilp.server", "the ilp server name", be_options.ilp_server),
+       LC_OPT_ENT_STR("ilp.solver", "the ilp solver name", be_options.ilp_solver),
+       LC_OPT_LAST
 };
 
-#endif /* WITH_LIBCORE */
+static be_module_list_entry_t *isa_ifs         = NULL;
+static bool                    isa_initialized = false;
 
-void be_opt_register(void)
+asm_constraint_flags_t asm_constraint_flags[256];
+
+static void initialize_isa(void)
 {
-#ifdef WITH_LIBCORE
-       int i;
-       lc_opt_entry_t *be_grp_ra;
-       static int run_once = 0;
+       if (isa_initialized)
+               return;
+       isa_if->init();
+       isa_initialized = true;
+}
 
-       if (! run_once) {
-               run_once    = 1;
-               be_grp_root = lc_opt_get_grp(firm_opt_get_root(), "be");
-               be_grp_ra   = lc_opt_get_grp(be_grp_root, "ra");
+static void finish_isa(void)
+{
+       if (isa_initialized) {
+               isa_if->finish();
+               isa_initialized = false;
+       }
+}
 
-               lc_opt_add_table(be_grp_root, be_main_options);
+void be_init_default_asm_constraint_flags(void)
+{
+       asm_constraint_flags['?'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+       asm_constraint_flags['!'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+       asm_constraint_flags['&'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT
+               | ASM_CONSTRAINT_FLAG_MODIFIER_EARLYCLOBBER;
+       asm_constraint_flags['%'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT
+               | ASM_CONSTRAINT_FLAG_MODIFIER_COMMUTATIVE;
+       asm_constraint_flags['!'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+
+       asm_constraint_flags['='] = ASM_CONSTRAINT_FLAG_MODIFIER_WRITE
+               | ASM_CONSTRAINT_FLAG_MODIFIER_NO_READ;
+       asm_constraint_flags['+'] = ASM_CONSTRAINT_FLAG_MODIFIER_READ
+               | ASM_CONSTRAINT_FLAG_MODIFIER_WRITE;
+
+       asm_constraint_flags['i'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+       asm_constraint_flags['s'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+       asm_constraint_flags['E'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+       asm_constraint_flags['F'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+       asm_constraint_flags['G'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+       asm_constraint_flags['H'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+       asm_constraint_flags['I'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+       asm_constraint_flags['J'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+       asm_constraint_flags['K'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+       asm_constraint_flags['L'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+       asm_constraint_flags['M'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+       asm_constraint_flags['N'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+       asm_constraint_flags['O'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+       asm_constraint_flags['P'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+
+       asm_constraint_flags['m'] = ASM_CONSTRAINT_FLAG_SUPPORTS_MEMOP;
+       asm_constraint_flags['o'] = ASM_CONSTRAINT_FLAG_SUPPORTS_MEMOP;
+       asm_constraint_flags['V'] = ASM_CONSTRAINT_FLAG_SUPPORTS_MEMOP;
+       asm_constraint_flags['<'] = ASM_CONSTRAINT_FLAG_SUPPORTS_MEMOP;
+       asm_constraint_flags['>'] = ASM_CONSTRAINT_FLAG_SUPPORTS_MEMOP;
+
+       asm_constraint_flags['p'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+       asm_constraint_flags['0'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+       asm_constraint_flags['1'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+       asm_constraint_flags['2'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+       asm_constraint_flags['3'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+       asm_constraint_flags['4'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+       asm_constraint_flags['5'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+       asm_constraint_flags['6'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+       asm_constraint_flags['7'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+       asm_constraint_flags['8'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+       asm_constraint_flags['9'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+
+       asm_constraint_flags['X'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER
+               | ASM_CONSTRAINT_FLAG_SUPPORTS_MEMOP
+               | ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+
+       /* these should have been catched by the parsing code already */
+       asm_constraint_flags['#']  = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+       asm_constraint_flags['*']  = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+       asm_constraint_flags[' ']  = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+       asm_constraint_flags['\t'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+       asm_constraint_flags['\n'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+       asm_constraint_flags['\r'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+}
 
-               /* register allocator options */
-               for(i = 0; ra_items[i].name != NULL; ++i) {
-                       const be_ra_t *ra = ra_items[i].value;
-                       ra->register_options(be_grp_ra);
+asm_constraint_flags_t be_parse_asm_constraints(const char *constraint)
+{
+       asm_constraint_flags_t  flags = ASM_CONSTRAINT_FLAG_NONE;
+       const char             *c;
+       asm_constraint_flags_t  tflags;
+
+       initialize_isa();
+
+       for (c = constraint; *c != '\0'; ++c) {
+               switch (*c) {
+               case '#':
+                       /* 'comment' stuff */
+                       while (*c != 0 && *c != ',')
+                               ++c;
+                       break;
+               case '*':
+                       /* 'comment' character */
+                       ++c;
+                       break;
+               case ' ':
+               case '\t':
+               case '\n':
+               case '\r':
+                       break;
+               default:
+                       tflags = asm_constraint_flags[(int) *c];
+                       if (tflags != 0) {
+                               flags |= tflags;
+                       } else {
+                               flags |= isa_if->parse_asm_constraint(&c);
+                       }
+                       break;
                }
+       }
 
-               /* register isa options */
-               for(i = 0; isa_items[i].name != NULL; ++i) {
-                       const arch_isa_if_t *isa = isa_items[i].value;
-                       isa->register_options(be_grp_root);
-               }
+       if ((
+               flags & ASM_CONSTRAINT_FLAG_MODIFIER_WRITE &&
+               flags & ASM_CONSTRAINT_FLAG_MODIFIER_NO_WRITE
+           ) || (
+               flags & ASM_CONSTRAINT_FLAG_MODIFIER_READ &&
+               flags & ASM_CONSTRAINT_FLAG_MODIFIER_NO_READ
+           )) {
+               flags |= ASM_CONSTRAINT_FLAG_INVALID;
+       }
+       if (!(flags & (ASM_CONSTRAINT_FLAG_MODIFIER_READ     |
+                      ASM_CONSTRAINT_FLAG_MODIFIER_WRITE    |
+                      ASM_CONSTRAINT_FLAG_MODIFIER_NO_WRITE |
+                      ASM_CONSTRAINT_FLAG_MODIFIER_NO_READ)
+           )) {
+               flags |= ASM_CONSTRAINT_FLAG_MODIFIER_READ;
        }
-#endif /* WITH_LIBCORE */
+
+       return flags;
+}
+
+int be_is_valid_clobber(const char *clobber)
+{
+       initialize_isa();
+
+       /* memory is a valid clobber. (the frontend has to detect this case too,
+        * because it has to add memory edges to the asm) */
+       if (strcmp(clobber, "memory") == 0)
+               return 1;
+       /* cc (condition code) is always valid */
+       if (strcmp(clobber, "cc") == 0)
+               return 1;
+
+       return isa_if->is_valid_clobber(clobber);
+}
+
+void be_register_isa_if(const char *name, const arch_isa_if_t *isa)
+{
+       if (isa_if == NULL)
+               isa_if = isa;
+
+       be_add_module_to_list(&isa_ifs, name, (void*) isa);
+}
+
+static void be_opt_register(void)
+{
+       lc_opt_entry_t *be_grp;
+       static int run_once = 0;
+
+       if (run_once)
+               return;
+       run_once = 1;
+
+       be_grp = lc_opt_get_grp(firm_opt_get_root(), "be");
+       lc_opt_add_table(be_grp, be_main_options);
+
+       be_add_module_list_opt(be_grp, "isa", "the instruction set architecture",
+                              &isa_ifs, (void**) &isa_if);
+
+       be_init_modules();
 }
 
 /* Parse one argument. */
-int be_parse_arg(const char *arg) {
-#ifdef WITH_LIBCORE
+int be_parse_arg(const char *arg)
+{
+       lc_opt_entry_t *be_grp = lc_opt_get_grp(firm_opt_get_root(), "be");
        if (strcmp(arg, "help") == 0 || (arg[0] == '?' && arg[1] == '\0')) {
-               lc_opt_print_help(be_grp_root, stdout);
+               lc_opt_print_help_for_entry(be_grp, '-', stdout);
                return -1;
        }
-       return lc_opt_from_single_arg(be_grp_root, NULL, arg, NULL);
-#else
-       return 0;
-#endif /* WITH_LIBCORE */
+       return lc_opt_from_single_arg(be_grp, NULL, arg, NULL);
 }
 
-/** The be parameters returned by default, all off. */
-const static backend_params be_params = {
-       NULL,
-       NULL,
-       0,
-       NULL,
-};
-
 /* Perform schedule verification if requested. */
-static void be_sched_vrfy(ir_graph *irg, int vrfy_opt) {
-       if (vrfy_opt == BE_VRFY_WARN) {
+static void be_sched_verify(ir_graph *irg, int verify_opt)
+{
+       if (verify_opt == BE_VERIFY_WARN) {
                be_verify_schedule(irg);
-       }
-       else if (vrfy_opt == BE_VRFY_ASSERT) {
+       } else if (verify_opt == BE_VERIFY_ASSERT) {
                assert(be_verify_schedule(irg) && "Schedule verification failed.");
        }
 }
 
-/* Initialize the Firm backend. Must be run BEFORE init_firm()! */
-const backend_params *be_init(void)
+/* Initialize the Firm backend. Must be run first in init_firm()! */
+void firm_be_init(void)
 {
        be_opt_register();
+       be_init_modules();
+}
 
-       be_sched_init();
-       be_liveness_init();
-       be_numbering_init();
-       be_copy_opt_init();
-       copystat_init();
-       phi_class_init();
+/* Finalize the Firm backend. */
+void firm_be_finish(void)
+{
+       finish_isa();
+       be_quit_modules();
+}
+
+/* Returns the backend parameter */
+const backend_params *be_get_backend_param(void)
+{
+       initialize_isa();
+       return isa_if->get_params();
+}
+
+int be_is_big_endian(void)
+{
+       return be_get_backend_param()->byte_order_big_endian;
+}
+
+unsigned be_get_machine_size(void)
+{
+       return be_get_backend_param()->machine_size;
+}
+
+ir_mode *be_get_mode_float_arithmetic(void)
+{
+       return be_get_backend_param()->mode_float_arithmetic;
+}
+
+ir_type *be_get_type_long_long(void)
+{
+       return be_get_backend_param()->type_long_long;
+}
+
+ir_type *be_get_type_unsigned_long_long(void)
+{
+       return be_get_backend_param()->type_unsigned_long_long;
+}
 
-       if (isa_if->get_params)
-               return isa_if->get_params();
-       return &be_params;
+ir_type *be_get_type_long_double(void)
+{
+       return be_get_backend_param()->type_long_double;
 }
 
 /**
@@ -245,38 +398,34 @@ const backend_params *be_init(void)
  * @param env          an empty environment
  * @param file_handle  the file handle where the output will be written to
  */
-static be_main_env_t *be_init_env(be_main_env_t *env, FILE *file_handle)
+static be_main_env_t *be_init_env(be_main_env_t *env, FILE *file_handle,
+                                  const char *compilation_unit_name)
 {
        memset(env, 0, sizeof(*env));
-       obstack_init(&env->obst);
-       env->arch_env = obstack_alloc(&env->obst, sizeof(env->arch_env[0]));
-       env->options  = &be_options;
-       env->options->dump_flags = dump_flags;
-       FIRM_DBG_REGISTER(env->dbg, "be.main");
+       env->file_handle          = file_handle;
+       env->ent_trampoline_map   = pmap_create();
+       env->pic_trampolines_type = new_type_class(NEW_ID("$PIC_TRAMPOLINE_TYPE"));
+       env->ent_pic_symbol_map   = pmap_create();
+       env->pic_symbols_type     = new_type_struct(NEW_ID("$PIC_SYMBOLS_TYPE"));
+       env->cup_name             = compilation_unit_name;
 
-       arch_env_init(env->arch_env, isa_if, file_handle);
+       set_class_final(env->pic_trampolines_type, 1);
 
-       /* Register the irn handler of the architecture */
-       if (arch_isa_get_irn_handler(env->arch_env->isa))
-               arch_env_push_irn_handler(env->arch_env, arch_isa_get_irn_handler(env->arch_env->isa));
-
-       /*
-        * Register the node handler of the back end infrastructure.
-        * This irn handler takes care of the platform independent
-        * spill, reload and perm nodes.
-        */
-       arch_env_push_irn_handler(env->arch_env, &be_node_irn_handler);
-       env->phi_handler = be_phi_handler_new(env->arch_env);
-       arch_env_push_irn_handler(env->arch_env, env->phi_handler);
+       memset(asm_constraint_flags, 0, sizeof(asm_constraint_flags));
+       env->arch_env = arch_env_begin_codegeneration(isa_if, env);
 
        return env;
 }
 
+/**
+ * Called when the be_main_env_t can be destroyed.
+ */
 static void be_done_env(be_main_env_t *env)
 {
-       env->arch_env->isa->impl->done(env->arch_env->isa);
-       be_phi_handler_free(env->phi_handler);
-       obstack_free(&env->obst, NULL);
+       pmap_destroy(env->ent_trampoline_map);
+       pmap_destroy(env->ent_pic_symbol_map);
+       free_type(env->pic_trampolines_type);
+       free_type(env->pic_symbols_type);
 }
 
 /**
@@ -288,41 +437,100 @@ static void be_done_env(be_main_env_t *env)
  * @param suffix  the suffix for the dumper
  * @param dumper  the dumper to be called
  */
-static void dump(int mask, ir_graph *irg, const char *suffix,
-                 void (*dumper)(ir_graph *, const char *))
+static void dump(int mask, ir_graph *irg, const char *suffix)
 {
-       if(dump_flags & mask)
-               be_dump(irg, suffix, dumper);
+       if (be_options.dump_flags & mask)
+               dump_ir_graph(irg, suffix);
 }
 
 /**
- * Prepare a backend graph for code generation.
+ * Prepare a backend graph for code generation and initialize its irg
  */
-static void prepare_graph(be_irg_t *birg)
+static void initialize_birg(be_irg_t *birg, ir_graph *irg, be_main_env_t *env)
 {
-       ir_graph *irg = birg->irg;
+       /* 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;
+
+       memset(birg, 0, sizeof(*birg));
+       birg->main_env = env;
+       obstack_init(&birg->obst);
+       birg->lv = be_liveness_new(irg);
+
+       edges_deactivate(irg);
+       edges_activate(irg);
 
-       /* Normalize proj nodes. */
-       normalize_proj_nodes(irg);
+       /* set the current graph (this is important for several firm functions) */
+       current_ir_graph = irg;
 
-       /* Make just one return node. */
-       normalize_one_return(irg);
+       /* we do this before critical edge split. As this produces less returns,
+          because sometimes (= 164.gzip) multiple returns are slower */
+       normalize_n_returns(irg);
 
        /* Remove critical edges */
-       remove_critical_cf_edges(irg);
+       remove_critical_cf_edges_ex(irg, /*ignore_exception_edges=*/0);
 
-       /* Compute the dominance information. */
-       free_dom(irg);
-       compute_doms(irg);
+       /* For code generation all unreachable code and Bad nodes should be gone */
+       remove_unreachable_code(irg);
+       remove_bads(irg);
 
        /* Ensure, that the ir_edges are computed. */
-       edges_activate(irg);
+       assure_edges(irg);
+
+       add_irg_constraints(irg, IR_GRAPH_CONSTRAINT_BACKEND);
+       be_info_init_irg(irg);
+
+       dump(DUMP_INITIAL, irg, "prepared");
+}
+
+int be_timing;
+
+static const char *get_timer_name(be_timer_id_t id)
+{
+       switch (id) {
+       case T_ABI:            return "abi";
+       case T_CODEGEN:        return "codegen";
+       case T_RA_PREPARATION: return "ra_preparation";
+       case T_SCHED:          return "sched";
+       case T_CONSTR:         return "constr";
+       case T_FINISH:         return "finish";
+       case T_EMIT:           return "emit";
+       case T_VERIFY:         return "verify";
+       case T_OTHER:          return "other";
+       case T_HEIGHTS:        return "heights";
+       case T_LIVE:           return "live";
+       case T_EXECFREQ:       return "execfreq";
+       case T_SSA_CONSTR:     return "ssa_constr";
+       case T_RA_EPILOG:      return "ra_epilog";
+       case T_RA_CONSTR:      return "ra_constr";
+       case T_RA_SPILL:       return "ra_spill";
+       case T_RA_SPILL_APPLY: return "ra_spill_apply";
+       case T_RA_COLOR:       return "ra_color";
+       case T_RA_IFG:         return "ra_ifg";
+       case T_RA_COPYMIN:     return "ra_copymin";
+       case T_RA_SSA:         return "ra_ssa";
+       case T_RA_OTHER:       return "ra_other";
+       }
+       return "unknown";
+}
+ir_timer_t *be_timers[T_LAST+1];
 
-       /* check, if the dominance property is fulfilled. */
-       be_check_dominance(irg);
+void be_lower_for_target(void)
+{
+       size_t i;
+
+       initialize_isa();
 
-       /* reset the phi handler. */
-       be_phi_handler_reset(birg->main_env->phi_handler);
+       isa_if->lower_for_target();
+       /* set the phase to low */
+       for (i = get_irp_n_irgs(); i > 0;) {
+               ir_graph *irg = get_irp_irg(--i);
+               assert(!irg_is_constrained(irg, IR_GRAPH_CONSTRAINT_TARGET_LOWERED));
+               add_irg_constraints(irg, IR_GRAPH_CONSTRAINT_TARGET_LOWERED);
+       }
 }
 
 /**
@@ -331,297 +539,351 @@ static void prepare_graph(be_irg_t *birg)
  * and call the architecture specific code generator.
  *
  * @param file_handle   the file handle the output will be written to
+ * @param cup_name      name of the compilation unit
  */
-static void be_main_loop(FILE *file_handle)
+static void be_main_loop(FILE *file_handle, const char *cup_name)
 {
-       int i, n;
-       arch_isa_t *isa;
+       static const char suffix[] = ".prof";
+
+       size_t        i;
+       size_t        num_irgs;
+       size_t        num_birgs;
        be_main_env_t env;
-       unsigned num_nodes_b = 0;
-       unsigned num_nodes_a = 0;
-       unsigned num_nodes_r = 0;
-       unsigned ra_prolog   = 0;
-       unsigned ra_epilog   = 0;
-       unsigned ra_live     = 0;
-       unsigned ra_spill    = 0;
-       unsigned ra_color    = 0;
-       unsigned ra_ifg      = 0;
-       unsigned ra_copymin  = 0;
-       unsigned ra_ssa      = 0;
-       lc_timer_t *t_prolog, *t_abi, *t_codegen, *t_sched, *t_constr, *t_regalloc, *t_finish, *t_emit, *t_other;
-       be_ra_timer_t *ra_timer;
+       char          prof_filename[256];
+       be_irg_t      *birgs;
+       arch_env_t    *arch_env;
 
-       if (be_options.timing == BE_TIME_ON) {
-               t_prolog   = lc_timer_register("prolog",   "prolog");
-               t_abi      = lc_timer_register("beabi",    "be abi introduction");
-               t_codegen  = lc_timer_register("codegen",  "codegeneration");
-               t_sched    = lc_timer_register("sched",    "scheduling");
-               t_constr   = lc_timer_register("constr",   "assure constraints");
-               t_regalloc = lc_timer_register("regalloc", "register allocation");
-               t_finish   = lc_timer_register("finish",   "graph finish");
-               t_emit     = lc_timer_register("emiter",   "code emiter");
-               t_other    = lc_timer_register("other",    "other");
-       }
+       be_timing = (be_options.timing == BE_TIME_ON);
 
-       be_init_env(&env, file_handle);
+       /* perform target lowering if it didn't happen yet */
+       if (get_irp_n_irgs() > 0 && !irg_is_constrained(get_irp_irg(0), IR_GRAPH_CONSTRAINT_TARGET_LOWERED))
+               be_lower_for_target();
 
-       isa = arch_env_get_isa(env.arch_env);
+       if (be_timing) {
+               for (i = 0; i < T_LAST+1; ++i) {
+                       be_timers[i] = ir_timer_new();
+               }
+       }
 
-       /* for debugging, anchors helps */
-       // dump_all_anchors(1);
+       be_init_env(&env, file_handle, cup_name);
 
-#define BE_TIMER_PUSH(timer)  if (be_options.timing == BE_TIME_ON) lc_timer_push(timer)
-#define BE_TIMER_POP()        if (be_options.timing == BE_TIME_ON) lc_timer_pop()
-#define BE_TIMER_ONLY(code)   if (be_options.timing == BE_TIME_ON) do { code; } while(0)
+       arch_env = env.arch_env;
 
-       /* For all graphs */
-       for (i = 0, n = get_irp_n_irgs(); i < n; ++i) {
-               ir_graph *irg = get_irp_irg(i);
-               const arch_code_generator_if_t *cg_if;
-               be_irg_t birg;
-               optimization_state_t state;
+       /* we might need 1 birg more for instrumentation constructor */
+       num_irgs = get_irp_n_irgs();
+       birgs    = ALLOCAN(be_irg_t, num_irgs + 1);
 
-               /* stop and reset timers */
-               if (be_options.timing == BE_TIME_ON) {
-                       LC_STOP_AND_RESET_TIMER(t_prolog);
-                       LC_STOP_AND_RESET_TIMER(t_abi);
-                       LC_STOP_AND_RESET_TIMER(t_codegen);
-                       LC_STOP_AND_RESET_TIMER(t_sched);
-                       LC_STOP_AND_RESET_TIMER(t_constr);
-                       LC_STOP_AND_RESET_TIMER(t_regalloc);
-                       LC_STOP_AND_RESET_TIMER(t_finish);
-                       LC_STOP_AND_RESET_TIMER(t_emit);
-                       LC_STOP_AND_RESET_TIMER(t_other);
-               }
-               BE_TIMER_PUSH(t_other);
+       be_info_init();
 
-               BE_TIMER_ONLY(num_nodes_b = get_num_reachable_nodes(irg));
+       /* First: initialize all birgs */
+       num_birgs = 0;
+       for (i = 0; i < num_irgs; ++i) {
+               ir_graph  *irg    = get_irp_irg(i);
+               ir_entity *entity = get_irg_entity(irg);
+               if (get_entity_linkage(entity) & IR_LINKAGE_NO_CODEGEN)
+                       continue;
+               initialize_birg(&birgs[num_birgs++], irg, &env);
+       }
+       arch_env_handle_intrinsics(arch_env);
 
-               birg.irg      = irg;
-               birg.main_env = &env;
+       /*
+               Get the filename for the profiling data.
+               Beware: '\0' is already included in sizeof(suffix)
+       */
+       sprintf(prof_filename, "%.*s%s",
+               (int)(sizeof(prof_filename) - sizeof(suffix)), cup_name, suffix);
+
+       bool have_profile = false;
+       if (be_options.opt_profile_use) {
+               bool res = ir_profile_read(prof_filename);
+               if (!res) {
+                       fprintf(stderr, "Warning: Couldn't read profile data '%s'\n",
+                               prof_filename);
+               } else {
+                       ir_create_execfreqs_from_profile();
+                       ir_profile_free();
+                       have_profile = true;
+               }
+       }
 
-               DBG((env.dbg, LEVEL_2, "====> IRG: %F\n", irg));
-               dump(DUMP_INITIAL, irg, "-begin", dump_ir_block_graph);
+       if (num_birgs > 0 && be_options.opt_profile_generate) {
+               ir_graph *const prof_init_irg = ir_profile_instrument(prof_filename);
+               assert(prof_init_irg->be_data == NULL);
+               initialize_birg(&birgs[num_birgs], prof_init_irg, &env);
+               num_birgs++;
+               num_irgs++;
+               assert(num_irgs == get_irp_n_irgs());
+       }
 
-               BE_TIMER_PUSH(t_prolog);
+       for (be_timer_id_t t = T_FIRST; t < T_LAST+1; ++t) {
+               ir_timer_init_parent(be_timers[t]);
+       }
+       if (!have_profile) {
+               be_timer_push(T_EXECFREQ);
+               for (i = 0; i < num_irgs; ++i) {
+                       ir_graph *irg = get_irp_irg(i);
+                       ir_estimate_execfreq(irg);
+               }
+               be_timer_pop(T_EXECFREQ);
+       }
 
-               be_stat_init_irg(env.arch_env, irg);
-               be_do_stat_nodes(irg, "01 Begin");
+       /* For all graphs */
+       for (i = 0; i < num_irgs; ++i) {
+               ir_graph  *const irg    = get_irp_irg(i);
+               ir_entity *const entity = get_irg_entity(irg);
+               if (get_entity_linkage(entity) & IR_LINKAGE_NO_CODEGEN)
+                       continue;
 
                /* set the current graph (this is important for several firm functions) */
-               current_ir_graph = birg.irg;
+               current_ir_graph = irg;
 
-               /* Get the code generator interface. */
-               cg_if = isa->impl->get_code_generator_if(isa);
+               if (stat_ev_enabled) {
+                       stat_ev_ctx_push_fmt("bemain_irg", "%+F", irg);
+                       stat_ev_ull("bemain_insns_start", be_count_insns(irg));
+                       stat_ev_ull("bemain_blocks_start", be_count_blocks(irg));
+               }
 
-               /* get a code generator for this graph. */
-               birg.cg = cg_if->init(&birg);
+               /* stop and reset timers */
+               be_timer_push(T_OTHER);
+
+               /* Verify the initial graph */
+               be_timer_push(T_VERIFY);
+               if (be_options.verify_option == BE_VERIFY_WARN) {
+                       irg_verify(irg, VERIFY_ENFORCE_SSA);
+               } else if (be_options.verify_option == BE_VERIFY_ASSERT) {
+                       assert(irg_verify(irg, VERIFY_ENFORCE_SSA) && "irg verification failed");
+               }
+               be_timer_pop(T_VERIFY);
 
-               /* create the code generator and generate code. */
-               prepare_graph(&birg);
+               /* get a code generator for this graph. */
+               if (arch_env->impl->init_graph)
+                       arch_env->impl->init_graph(irg);
 
                /* some transformations need to be done before abi introduce */
-               arch_code_generator_before_abi(birg.cg);
-
-               BE_TIMER_POP();
-               BE_TIMER_PUSH(t_abi);
+               if (arch_env->impl->before_abi != NULL)
+                       arch_env->impl->before_abi(irg);
 
                /* implement the ABI conventions. */
-               birg.abi = be_abi_introduce(&birg);
-               dump(DUMP_ABI, irg, "-abi", dump_ir_block_graph);
-
-               be_do_stat_nodes(irg, "02 Abi");
-
-               BE_TIMER_POP();
-               BE_TIMER_PUSH(t_codegen);
-
-               /* generate code */
-               arch_code_generator_prepare_graph(birg.cg);
+               if (!arch_env->custom_abi) {
+                       be_timer_push(T_ABI);
+                       be_abi_introduce(irg);
+                       be_timer_pop(T_ABI);
+                       dump(DUMP_ABI, irg, "abi");
+               }
 
-               be_do_stat_nodes(irg, "03 Prepare");
+               /* We can't have Bad-blocks or critical edges in the backend.
+                * Before removing Bads, we remove unreachable code. */
+               optimize_graph_df(irg);
+               remove_critical_cf_edges(irg);
+               remove_bads(irg);
 
-               /*
-                * Since the code generator made a lot of new nodes and skipped
-                * a lot of old ones, we should do dead node elimination here.
-                * Note that this requires disabling the edges here.
-                */
+               /* 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);
-               //dead_node_elimination(irg);
                edges_activate(irg);
 
-               /* Compute loop nesting information (for weighting copies) */
-               construct_cf_backedges(irg);
+               dump(DUMP_PREPARED, irg, "before-code-selection");
 
-               dump(DUMP_PREPARED, irg, "-prepared", dump_ir_block_graph);
+               /* perform codeselection */
+               be_timer_push(T_CODEGEN);
+               if (arch_env->impl->prepare_graph != NULL)
+                       arch_env->impl->prepare_graph(irg);
+               be_timer_pop(T_CODEGEN);
 
-               BE_TIMER_POP();
-               BE_TIMER_ONLY(num_nodes_r = get_num_reachable_nodes(irg));
-               BE_TIMER_PUSH(t_sched);
+               dump(DUMP_PREPARED, irg, "code-selection");
 
-               /* Schedule the graphs. */
-               arch_code_generator_before_sched(birg.cg);
-               list_sched(&birg, be_enable_mris);
-               dump(DUMP_SCHED, irg, "-sched", dump_ir_block_graph_sched);
+               /* disabled for now, fails for EmptyFor.c and XXEndless.c */
+               /* be_live_chk_compare(irg); */
 
-               /* check schedule */
-               be_sched_vrfy(birg.irg, vrfy_option);
+               /* schedule the irg */
+               be_timer_push(T_SCHED);
+               be_schedule_graph(irg);
+               be_timer_pop(T_SCHED);
 
-               be_do_stat_nodes(irg, "04 Schedule");
+               dump(DUMP_SCHED, irg, "sched");
 
-               BE_TIMER_POP();
-               BE_TIMER_PUSH(t_constr);
+               /* check schedule */
+               be_timer_push(T_VERIFY);
+               be_sched_verify(irg, be_options.verify_option);
+               be_timer_pop(T_VERIFY);
 
+               /* introduce patterns to assure constraints */
+               be_timer_push(T_CONSTR);
                /* we switch off optimizations here, because they might cause trouble */
+               optimization_state_t state;
                save_optimization_state(&state);
                set_optimize(0);
-               set_opt_normalize(0);
+               set_opt_cse(0);
 
                /* add Keeps for should_be_different constrained nodes  */
                /* beware: needs schedule due to usage of be_ssa_constr */
-               assure_constraints(&birg);
-               dump(DUMP_SCHED, irg, "-assured", dump_ir_block_graph_sched);
-
-               be_do_stat_nodes(irg, "05 Constraints");
+               assure_constraints(irg);
+               be_timer_pop(T_CONSTR);
 
-               /* connect all stack modifying nodes together (see beabi.c) */
-               be_abi_fix_stack_nodes(birg.abi);
-               dump(DUMP_SCHED, irg, "-fix_stack", dump_ir_block_graph_sched);
+               dump(DUMP_SCHED, irg, "assured");
 
-               /* check schedule */
-               be_sched_vrfy(birg.irg, vrfy_option);
+               /* stuff needs to be done after scheduling but before register allocation */
+               be_timer_push(T_RA_PREPARATION);
+               if (arch_env->impl->before_ra != NULL)
+                       arch_env->impl->before_ra(irg);
+               be_timer_pop(T_RA_PREPARATION);
 
-               /* do some statistics */
-               be_do_stat_reg_pressure(&birg);
+               /* connect all stack modifying nodes together (see beabi.c) */
+               be_timer_push(T_ABI);
+               be_abi_fix_stack_nodes(irg);
+               be_timer_pop(T_ABI);
 
-               /* stuff needs to be done after scheduling but before register allocation */
-               arch_code_generator_before_ra(birg.cg);
+               dump(DUMP_SCHED, irg, "fix_stack");
 
-               BE_TIMER_POP();
-               BE_TIMER_PUSH(t_regalloc);
+               /* check schedule */
+               be_timer_push(T_VERIFY);
+               be_sched_verify(irg, be_options.verify_option);
+               be_timer_pop(T_VERIFY);
+
+               if (stat_ev_enabled) {
+                       stat_ev_dbl("bemain_costs_before_ra", be_estimate_irg_costs(irg));
+                       stat_ev_ull("bemain_insns_before_ra", be_count_insns(irg));
+                       stat_ev_ull("bemain_blocks_before_ra", be_count_blocks(irg));
+               }
 
                /* Do register allocation */
-               ra_timer = ra->allocate(&birg);
-               dump(DUMP_RA, irg, "-ra", dump_ir_block_graph_sched);
-
-               if (be_options.timing == BE_TIME_ON && ra_timer) {
-                       ra_prolog  = lc_timer_elapsed_msec(ra_timer->t_prolog);
-                       ra_epilog  = lc_timer_elapsed_msec(ra_timer->t_epilog);
-                       ra_live    = lc_timer_elapsed_msec(ra_timer->t_live);
-                       ra_spill   = lc_timer_elapsed_msec(ra_timer->t_spill);
-                       ra_color   = lc_timer_elapsed_msec(ra_timer->t_color);
-                       ra_copymin = lc_timer_elapsed_msec(ra_timer->t_copymin);
-                       ra_ssa     = lc_timer_elapsed_msec(ra_timer->t_ssa);
-                       ra_ifg     = lc_timer_elapsed_msec(ra_timer->t_ifg);
-               }
+               be_allocate_registers(irg);
 
-               be_do_stat_nodes(irg, "06 Register Allocation");
+               stat_ev_dbl("bemain_costs_before_ra", be_estimate_irg_costs(irg));
 
-               BE_TIMER_POP();
-               BE_TIMER_PUSH(t_finish);
+               dump(DUMP_RA, irg, "ra");
 
-               arch_code_generator_after_ra(birg.cg);
-               be_abi_fix_stack_bias(birg.abi);
+               be_timer_push(T_FINISH);
+               if (arch_env->impl->finish_graph != NULL)
+                       arch_env->impl->finish_graph(irg);
+               be_timer_pop(T_FINISH);
 
-               /* check schedule */
-               be_sched_vrfy(birg.irg, vrfy_option);
+               dump(DUMP_FINAL, irg, "finish");
+
+               if (stat_ev_enabled) {
+                       stat_ev_ull("bemain_insns_finish", be_count_insns(irg));
+                       stat_ev_ull("bemain_blocks_finish", be_count_blocks(irg));
+               }
 
-               BE_TIMER_POP();
-               BE_TIMER_PUSH(t_emit);
+               /* check schedule and register allocation */
+               be_timer_push(T_VERIFY);
+               if (be_options.verify_option == BE_VERIFY_WARN) {
+                       irg_verify(irg, VERIFY_ENFORCE_SSA);
+                       be_verify_schedule(irg);
+                       be_verify_register_allocation(irg);
+               } else if (be_options.verify_option == BE_VERIFY_ASSERT) {
+                       assert(irg_verify(irg, VERIFY_ENFORCE_SSA) && "irg verification failed");
+                       assert(be_verify_schedule(irg) && "Schedule verification failed");
+                       assert(be_verify_register_allocation(irg)
+                              && "register allocation verification failed");
 
-               arch_code_generator_done(birg.cg);
-               dump(DUMP_FINAL, irg, "-end", dump_ir_extblock_graph_sched);
-               be_abi_free(birg.abi);
+               }
+               be_timer_pop(T_VERIFY);
 
-               be_do_stat_nodes(irg, "07 Final");
+               /* emit assembler code */
+               be_timer_push(T_EMIT);
+               if (arch_env->impl->emit != NULL)
+                       arch_env->impl->emit(irg);
+               be_timer_pop(T_EMIT);
 
-               BE_TIMER_POP();
+               dump(DUMP_FINAL, irg, "end");
 
                restore_optimization_state(&state);
 
-               BE_TIMER_ONLY(num_nodes_a = get_num_reachable_nodes(irg));
-
-               /* switched off due to statistics (statistic module needs all irgs) */
-               //              free_ir_graph(irg);
-               BE_TIMER_POP();
-
-#define LC_EMIT(timer)     printf("%-20s: %u msec\n", lc_timer_get_description(timer), lc_timer_elapsed_msec(timer))
-#define EMIT_RA_TIME(n, t) printf("%-20s: %u msec\n", n, t)
-               if (be_options.timing == BE_TIME_ON) {
-                       printf("==>> IRG %s <<==\n", get_entity_name(get_irg_entity(irg)));
-                       printf("# nodes at begin:  %u\n", num_nodes_b);
-                       printf("# nodes before ra: %u\n", num_nodes_r);
-                       printf("# nodes at end:    %u\n\n", num_nodes_a);
-                       LC_EMIT(t_prolog);
-                       LC_EMIT(t_abi);
-                       LC_EMIT(t_codegen);
-                       LC_EMIT(t_sched);
-                       LC_EMIT(t_constr);
-                       LC_EMIT(t_regalloc);
-                       EMIT_RA_TIME("prolog",    ra_prolog);
-                       EMIT_RA_TIME("liveness",  ra_live);
-                       EMIT_RA_TIME("spilling",  ra_spill);
-                       EMIT_RA_TIME("coloring",  ra_color);
-                       EMIT_RA_TIME("ifg build", ra_ifg);
-                       EMIT_RA_TIME("copymin",   ra_copymin);
-                       EMIT_RA_TIME("ssa destr", ra_ssa);
-                       EMIT_RA_TIME("epilog",    ra_epilog);
-                       LC_EMIT(t_finish);
-                       LC_EMIT(t_emit);
-                       LC_EMIT(t_other);
+               be_timer_pop(T_OTHER);
+
+               if (be_timing) {
+                       be_timer_id_t t;
+                       if (stat_ev_enabled) {
+                               for (t = T_FIRST; t < T_LAST+1; ++t) {
+                                       char buf[128];
+                                       snprintf(buf, sizeof(buf), "bemain_time_%s",
+                                                get_timer_name(t));
+                                       stat_ev_dbl(buf, ir_timer_elapsed_usec(be_timers[i]));
+                               }
+                       } else {
+                               printf("==>> IRG %s <<==\n",
+                                      get_entity_name(get_irg_entity(irg)));
+                               for (t = T_FIRST; t < T_LAST+1; ++t) {
+                                       double val = ir_timer_elapsed_usec(be_timers[t]) / 1000.0;
+                                       printf("%-20s: %10.3f msec\n", get_timer_name(t), val);
+                               }
+                       }
+                       for (t = T_FIRST; t < T_LAST+1; ++t) {
+                               ir_timer_reset(be_timers[t]);
+                       }
                }
-#undef LC_EMIT
+
+               be_free_birg(irg);
+               stat_ev_ctx_pop("bemain_irg");
        }
+
+       arch_env_end_codegeneration(arch_env);
+
        be_done_env(&env);
 
-#undef BE_TIME_START
-#undef BE_TIME_STOP
-#undef BE_TIME_ONLY
+       be_info_free();
 }
 
 /* Main interface to the frontend. */
-void be_main(FILE *file_handle)
+void be_main(FILE *file_handle, const char *cup_name)
 {
-#ifdef WITH_LIBCORE
-       lc_timer_t *t;
+       ir_timer_t *t = NULL;
 
        if (be_options.timing == BE_TIME_ON) {
-               t = lc_timer_register("bemain", "measure complete bemain loop");
+               t = ir_timer_new();
 
-               if (lc_timer_enter_high_priority()) {
+               if (ir_timer_enter_high_priority()) {
                        fprintf(stderr, "Warning: Could not enter high priority mode.\n");
                }
 
-               lc_timer_reset_and_start(t);
+               ir_timer_reset_and_start(t);
        }
-#endif /* WITH_LIBCORE */
 
-       /* never build code for pseudo irgs */
-       set_visit_pseudo_irgs(0);
+       if (be_options.statev) {
+               const char *dot = strrchr(cup_name, '.');
+               const char *pos = dot ? dot : cup_name + strlen(cup_name);
+               char       *buf = ALLOCAN(char, pos - cup_name + 1);
+               strncpy(buf, cup_name, pos - cup_name);
+               buf[pos - cup_name] = '\0';
 
-       be_node_init();
-       be_main_loop(file_handle);
+               be_options.statev = 1;
+               stat_ev_begin(buf, be_options.filtev);
+               stat_ev_ctx_push_str("bemain_compilation_unit", cup_name);
+       }
+
+       be_main_loop(file_handle, cup_name);
 
-#ifdef WITH_LIBCORE
        if (be_options.timing == BE_TIME_ON) {
-               lc_timer_stop(t);
-               lc_timer_leave_high_priority();
-               printf("%-20s: %lu msec\n", "BEMAINLOOP", lc_timer_elapsed_msec(t));
+               ir_timer_stop(t);
+               ir_timer_leave_high_priority();
+               if (stat_ev_enabled) {
+                       stat_ev_dbl("bemain_backend_time", ir_timer_elapsed_msec(t));
+               } else {
+                       double val = ir_timer_elapsed_usec(t) / 1000.0;
+                       printf("%-20s: %10.3f msec\n", "BEMAINLOOP", val);
+               }
        }
-#endif /* WITH_LIBCORE */
-}
 
-/** The debug info retriever function. */
-static retrieve_dbg_func retrieve_dbg = NULL;
+       if (be_options.statev) {
+               stat_ev_ctx_pop("bemain_compilation_unit");
+               stat_ev_end();
+       }
+}
 
-/* Sets a debug info retriever. */
-void be_set_debug_retrieve(retrieve_dbg_func func) {
-       retrieve_dbg = func;
+static int do_lower_for_target(ir_prog *irp, void *context)
+{
+       be_lower_for_target();
+       (void) context;
+       (void) irp;
+       return 0;
 }
 
-/* Retrieve the debug info. */
-const char *be_retrieve_dbg_info(const dbg_info *dbg, unsigned *line) {
-       if (retrieve_dbg)
-               return retrieve_dbg(dbg, line);
-       *line = 0;
-       return NULL;
+ir_prog_pass_t *lower_for_target_pass(const char *name)
+{
+       ir_prog_pass_t *pass = XMALLOCZ(ir_prog_pass_t);
+       return def_prog_pass_constructor(pass,
+                                        name ? name : "lower_for_target",
+                                        do_lower_for_target);
 }