#include "../beblocksched.h"
#include "../beirg_t.h"
#include "../begnuas.h"
+#include "../be_dbgout.h"
#include "arm_emitter.h"
#include "gen_arm_emitter.h"
#undef SILENCE
}
-static const char *last_name = NULL;
-static unsigned last_line = -1;
-static unsigned num = -1;
-
-/**
- * Emit the debug support for node node.
- */
-static void arm_emit_dbg(const ir_node *irn) {
- dbg_info *db = get_irn_dbg_info(irn);
- unsigned lineno;
- const char *fname = ir_retrieve_dbg_info(db, &lineno);
-
- if (! cg->birg->main_env->options->stabs_debug_support)
- return;
-
- if (fname) {
- if (last_name != fname) {
- last_line = -1;
- be_dbg_include_begin(cg->birg->main_env->db_handle, fname);
- last_name = fname;
- }
- if (last_line != lineno) {
- char name[64];
-
- snprintf(name, sizeof(name), ".LM%u", ++num);
- last_line = lineno;
- be_dbg_line(cg->birg->main_env->db_handle, lineno, name);
- be_emit_string(name);
- be_emit_cstring(":\n");
- be_emit_write_line();
- }
- }
-}
-
/**
* Emits code for a node.
*/
if (op->ops.generic) {
emit_func *emit = (emit_func *)op->ops.generic;
- arm_emit_dbg(irn);
+ be_dbg_set_dbg_info(get_irn_dbg_info(irn));
(*emit)(irn);
} else {
be_emit_cstring("\t/* TODO */");
ir_node *irn;
arm_emit_block_header(block, prev_block);
- arm_emit_dbg(block);
+ be_dbg_set_dbg_info(get_irn_dbg_info(block));
sched_foreach(block, irn) {
arm_emit_node(irn);
}
#ifndef FIRM_BE_BE_DBGOUT_H
#define FIRM_BE_BE_DBGOUT_H
-#include "obst.h"
-#include "beabi_t.h"
+#include "beabi.h"
-typedef struct dbg_handle dbg_handle;
-
-/**
- * Debug operations.
- */
-typedef struct debug_ops {
- /** close the stabs handler. */
- void (*close)(dbg_handle *handle);
-
- /** start a new source object (compilation unit) */
- void (*so)(dbg_handle *handle, const char *filename);
-
- /** start an include file */
- void (*include_begin)(dbg_handle *handle, const char *filename);
-
- /** end an include file */
- void (*include_end)(dbg_handle *handle);
-
- /** Main Program */
- void (*main_program)(dbg_handle *handle);
-
- /** dumps the stabs for a method begin */
- void (*method_begin)(dbg_handle *handle, ir_entity *ent, const be_stack_layout_t *layout);
-
- /** dumps the stabs for a method end */
- void (*method_end)(dbg_handle *handle);
-
- /** dumps a line number */
- void (*line)(dbg_handle *handle, unsigned lineno, const char *address);
-
- /** dump types */
- void (*types)(dbg_handle *handle);
-
- /** dump a variable in the global type */
- void (*variable)(dbg_handle *h, struct obstack *obst, ir_entity *ent);
-
-} debug_ops;
-
-/** The base class of all debug implementations. */
-struct dbg_handle {
- const debug_ops *ops;
-};
+/* initialize and open debug handle */
+void be_dbg_open(void);
/** close a debug handler. */
-void be_dbg_close(dbg_handle *handle);
+void be_dbg_close(void);
/** start a new source object (compilation unit) */
-void be_dbg_so(dbg_handle *handle, const char *filename);
-
-/** start an include file */
-void be_dbg_include_begin(dbg_handle *handle, const char *filename);
-
-/** end an include file */
-void be_dbg_include_end(dbg_handle *handle);
+void be_dbg_so(const char *filename);
/** Main program */
-void be_dbg_main_program(dbg_handle *handle);
+void be_dbg_main_program(void);
/** debug for a method begin */
-void be_dbg_method_begin(dbg_handle *handle, ir_entity *ent, const be_stack_layout_t *layout);
+void be_dbg_method_begin(ir_entity *ent, const be_stack_layout_t *layout);
/** debug for a method end */
-void be_dbg_method_end(dbg_handle *handle);
-
-/** debug for line number */
-void be_dbg_line(dbg_handle *handle, unsigned lineno, const char *address);
+void be_dbg_method_end(void);
/** dump types */
-void be_dbg_types(dbg_handle *handle);
+void be_dbg_types(void);
/** dump a variable in the global type */
-void be_dbg_variable(dbg_handle *handle, struct obstack *obst, ir_entity *ent);
-
-/** Opens the NULL handler: no debug support. */
-dbg_handle *be_nulldbg_open(void);
+void be_dbg_variable(struct obstack *obst, ir_entity *ent);
-/** Opens a stabs handler. */
-dbg_handle *be_stabs_open(FILE *out);
+void be_dbg_set_dbg_info(dbg_info *dbgi);
-#endif /* FIRM_BE_BE_DBGOUT_H */
+#endif
--- /dev/null
+/*
+ * 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 Debug output support.
+ * @author Michael Beck
+ * @date 11.9.2006
+ * @version $Id: be_dbgout.h 17143 2008-01-02 20:56:33Z beck $
+ */
+#ifndef FIRM_BE_BE_DBGOUT_T_H
+#define FIRM_BE_BE_DBGOUT_T_H
+
+#include "obst.h"
+#include "beabi_t.h"
+#include "firm_types.h"
+
+typedef struct dbg_handle dbg_handle;
+
+/**
+ * Debug operations.
+ */
+typedef struct debug_ops {
+ /** close the stabs handler. */
+ void (*close)(dbg_handle *handle);
+
+ /** start a new source object (compilation unit) */
+ void (*so)(dbg_handle *handle, const char *filename);
+
+ /** Main Program */
+ void (*main_program)(dbg_handle *handle);
+
+ /** dumps the stabs for a method begin */
+ void (*method_begin)(dbg_handle *handle, ir_entity *ent, const be_stack_layout_t *layout);
+
+ /** dumps the stabs for a method end */
+ void (*method_end)(dbg_handle *handle);
+
+ /** dump types */
+ void (*types)(dbg_handle *handle);
+
+ /** dump a variable in the global type */
+ void (*variable)(dbg_handle *h, struct obstack *obst, ir_entity *ent);
+
+ /** notify debug info about position change */
+ void (*set_dbg_info)(dbg_handle *h, dbg_info *dbgi);
+} debug_ops;
+
+/** The base class of all debug implementations. */
+struct dbg_handle {
+ const debug_ops *ops;
+};
+
+typedef dbg_handle* (*be_create_dbgout_module_func)(void);
+void be_register_dbgout_module(const char *name,
+ be_create_dbgout_module_func func);
+
+#endif
#include "be.h"
#include "bearch.h"
-#include "be_dbgout.h"
#include "beirg.h"
#define DUMP_NONE 0
int timing; /**< time the backend phases */
int opt_profile; /**< instrument code for profiling */
int omit_fp; /**< try to omit the frame pointer */
- int stabs_debug_support; /**< enable stabs debugging support */
int vrfy_option; /**< backend verify option */
int scheduler; /**< the scheduler */
+ char target_os[128]; /**< target operating system name */
char ilp_server[128]; /**< the ilp server name */
char ilp_solver[128]; /**< the ilp solver name */
int statev; /**< enable stat event dumping */
be_options_t *options;
arch_code_generator_t *cg;
arch_irn_handler_t *phi_handler;
- dbg_handle *db_handle;
const char *cup_name;
};
--- /dev/null
+/*
+ * 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 Stabs support.
+ * @author Michael Beck
+ * @date 11.9.2006
+ * @version $Id: bestabs.c 17143 2008-01-02 20:56:33Z beck $
+ */
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "be_dbgout_t.h"
+#include "bemodule.h"
+#include "irtools.h"
+
+static dbg_handle *handle = NULL;
+
+void be_dbg_close(void) {
+ if (handle->ops->close)
+ handle->ops->close(handle);
+}
+
+void be_dbg_so(const char *filename) {
+ if (handle->ops->so)
+ handle->ops->so(handle, filename);
+}
+
+void be_dbg_main_program(void) {
+ if (handle->ops->main_program)
+ handle->ops->main_program(handle);
+}
+
+void be_dbg_method_begin(ir_entity *ent, const be_stack_layout_t *layout) {
+ if (handle->ops->method_begin)
+ handle->ops->method_begin(handle, ent, layout);
+}
+
+void be_dbg_method_end(void) {
+ if (handle->ops->method_end)
+ handle->ops->method_end(handle);
+}
+
+void be_dbg_types(void) {
+ if (handle->ops->types)
+ handle->ops->types(handle);
+}
+
+void be_dbg_variable(struct obstack *obst, ir_entity *ent) {
+ if (handle->ops->variable)
+ handle->ops->variable(handle, obst, ent);
+}
+
+void be_dbg_set_dbg_info(dbg_info *dbgi) {
+ if (handle->ops->set_dbg_info)
+ handle->ops->set_dbg_info(handle, dbgi);
+}
+
+static be_module_list_entry_t *dbgout_modules = NULL;
+static be_create_dbgout_module_func selected_dbgout_module = NULL;
+
+void be_dbg_open(void) {
+ handle = selected_dbgout_module();
+}
+
+void be_register_dbgout_module(const char *name,
+ be_create_dbgout_module_func func);
+
+void be_register_dbgout_module(const char *name,
+ be_create_dbgout_module_func func)
+{
+ if (selected_dbgout_module == NULL)
+ selected_dbgout_module = func;
+ be_add_module_to_list(&dbgout_modules, name, func);
+}
+
+static dbg_handle *create_null_dbgout_module(void)
+{
+ static const debug_ops null_ops;
+ static dbg_handle null_handle = { &null_ops };
+ return &null_handle;
+}
+
+void be_init_dbgout(void) {
+ lc_opt_entry_t *be_grp = lc_opt_get_grp(firm_opt_get_root(), "be");
+
+ be_add_module_list_opt(be_grp, "debuginfo", "debug info format",
+ &dbgout_modules, (void**) &selected_dbgout_module);
+ be_register_dbgout_module("null", create_null_dbgout_module);
+}
+
+BE_REGISTER_MODULE_CONSTRUCTOR(be_init_dbgout);
typedef struct obstack obstack_t;
/** by default, we generate assembler code for the Linux gas */
-be_gas_flavour_t be_gas_flavour = GAS_FLAVOUR_NORMAL;
+be_gas_flavour_t be_gas_flavour = GAS_FLAVOUR_ELF;
/**
* Return the pseudo-instruction to be issued for a section switch
* @return the pseudo-instruction
*/
static const char *get_section_name(be_gas_section_t section) {
- static const char *text[GAS_FLAVOUR_MAX][GAS_SECTION_MAX] = {
- {
+ static const char *text[GAS_FLAVOUR_LAST+1][GAS_SECTION_LAST+1] = {
+ { /* GAS_FLAVOUR_ELF */
".section\t.text",
".section\t.data",
".section\t.rodata",
".section\t.tbss,\"awT\",@nobits",
".section\t.ctors,\"aw\",@progbits"
},
- {
+ { /* GAS_FLAVOUR_MINGW */
".section\t.text",
".section\t.data",
".section .rdata,\"dr\"",
".section\t.tbss,\"awT\",@nobits",
".section\t.ctors,\"aw\",@progbits"
},
- {
+ { /* GAS_FLAVOUR_YASM */
".section\t.text",
- ".section\t.data",
- ".section\t.rodata",
- ".section\t.bss",
- ".section\t.tbss,\"awT\",@nobits",
- ".section\t.ctors,\"aw\",@progbits"
+ ".section\t.data",
+ ".section\t.rodata",
+ ".section\t.bss",
+ ".section\t.tbss,\"awT\",@nobits",
+ ".section\t.ctors,\"aw\",@progbits"
+ },
+ { /* GAS_FLAVOUR_MACH_O */
+ ".text",
+ ".data",
+ ".const",
+ ".data",
+ "", /* TLS is not supported on Mach-O */
+ "" /* constructors aren't marked with sections in Mach-O */
}
};
- assert((int) be_gas_flavour >= 0 && be_gas_flavour < GAS_FLAVOUR_MAX);
- assert((int) section >= 0 && section < GAS_SECTION_MAX);
+ assert((int) be_gas_flavour >= 0 && be_gas_flavour <= GAS_FLAVOUR_LAST);
+ assert((int) section >= 0 && section <= GAS_SECTION_LAST);
return text[be_gas_flavour][section];
}
-/**
- * Emit necessary code to switch to a section.
- *
- * @param env the emitter environment
- * @param section the section to switch to
- */
void be_gas_emit_switch_section(be_gas_section_t section) {
be_emit_char('\t');
be_emit_string(get_section_name(section));
be_emit_write_line();
}
+void be_gas_emit_function_prolog(ir_entity *entity, unsigned alignment)
+{
+ const char *name = get_entity_ld_name(entity);
+
+ be_gas_emit_switch_section(GAS_SECTION_TEXT);
+
+ /* write the begin line (used by scripts processing the assembler... */
+ be_emit_write_line();
+ be_emit_cstring("# -- Begin ");
+ be_emit_string(name);
+ be_emit_char('\n');
+ be_emit_write_line();
+
+ if (be_gas_flavour != GAS_FLAVOUR_MACH_O) {
+ unsigned maximum_skip = (1 << alignment) - 1;
+ be_emit_cstring("\t.p2align ");
+ be_emit_irprintf("%u,,%u\n", alignment, maximum_skip);
+ be_emit_write_line();
+ }
+
+ if (get_entity_visibility(entity) == visibility_external_visible) {
+ be_emit_cstring(".global ");
+ be_emit_string(name);
+ be_emit_char('\n');
+ be_emit_write_line();
+ }
+
+ switch (be_gas_flavour) {
+ case GAS_FLAVOUR_ELF:
+ be_emit_cstring("\t.type\t");
+ be_emit_string(name);
+ be_emit_cstring(", @function\n");
+ be_emit_write_line();
+ break;
+ case GAS_FLAVOUR_MINGW:
+ be_emit_cstring("\t.def\t");
+ be_emit_string(name);
+ be_emit_cstring(";\t.scl\t2;\t.type\t32;\t.endef\n");
+ be_emit_write_line();
+ break;
+ case GAS_FLAVOUR_MACH_O:
+ case GAS_FLAVOUR_YASM:
+ break;
+ }
+ be_emit_string(name);
+ be_emit_cstring(":\n");
+ be_emit_write_line();
+}
+
+void be_gas_emit_function_epilog(ir_entity *entity)
+{
+ const char *name = get_entity_ld_name(entity);
+
+ if (be_gas_flavour == GAS_FLAVOUR_ELF) {
+ be_emit_cstring("\t.size\t");
+ be_emit_string(name);
+ be_emit_cstring(", .-");
+ be_emit_string(name);
+ be_emit_char('\n');
+ be_emit_write_line();
+ }
+
+ be_emit_cstring("# -- End ");
+ be_emit_string(name);
+ be_emit_char('\n');
+ be_emit_write_line();
+}
+
/**
* An environment containing all needed dumper data.
* Currently we create the file completely in memory first, then
break;
default:
- fprintf(stderr, "Try to dump a type with %d bytes\n", size);
+ fprintf(stderr, "Try to dump a type with %u bytes\n", (unsigned) size);
assert(0);
}
}
obst = env->data_obst;
if (is_Method_type(type)) {
- if (get_method_img_section(ent) == section_constructors) {
+ if (be_gas_flavour != GAS_FLAVOUR_MACH_O
+ && get_method_img_section(ent) == section_constructors) {
obst = env->ctor_obst;
obstack_printf(obst, ".balign\t%u\n", align);
dump_size_type(obst, align);
obstack_printf(obst, "%s\n", ld_name);
}
+
return;
}
emit_as_common = 1;
}
- be_dbg_variable(env->main_env->db_handle, obst, ent);
+ be_dbg_variable(obst, ent);
/* global or not global */
if (visibility == visibility_external_visible && !emit_as_common) {
if (variability == variability_uninitialized) {
if (emit_as_common) {
switch (be_gas_flavour) {
- case GAS_FLAVOUR_NORMAL:
+ case GAS_FLAVOUR_ELF:
+ case GAS_FLAVOUR_MACH_O:
case GAS_FLAVOUR_YASM:
obstack_printf(obst, "\t.comm %s,%u,%u\n",
ld_name, get_type_size_bytes(type), align);
obstack_printf(obst, "\t.comm %s,%u # %u\n",
ld_name, get_type_size_bytes(type), align);
break;
- case GAS_FLAVOUR_MAX:
- panic("invalid gas flavour selected");
}
} else {
obstack_printf(obst, "\t.zero %u\n", get_type_size_bytes(type));
* Sections.
*/
typedef enum section_t {
- GAS_SECTION_TEXT = 0, /**< text section */
- GAS_SECTION_DATA = 1, /**< data section */
- GAS_SECTION_RODATA = 2, /**< rodata section */
- GAS_SECTION_COMMON = 3, /**< common section */
- GAS_SECTION_TLS = 4, /**< thread local storage section */
- GAS_SECTION_CTOR = 5, /**< ctor section for instrumentation code init */
- GAS_SECTION_MAX = 6
+ GAS_SECTION_TEXT, /**< text section */
+ GAS_SECTION_DATA, /**< data section */
+ GAS_SECTION_RODATA, /**< rodata section */
+ GAS_SECTION_COMMON, /**< common section */
+ GAS_SECTION_TLS, /**< thread local storage section */
+ GAS_SECTION_CTOR, /**< ctor section for instrumentation code init */
+ GAS_SECTION_LAST = GAS_SECTION_CTOR
} be_gas_section_t;
/**
* Support for some GAS "dialects".
*/
typedef enum asm_flavour_t {
- GAS_FLAVOUR_NORMAL = 0, /**< normal gas (ELF) */
- GAS_FLAVOUR_MINGW = 1, /**< MinGW variant (no-ELF) */
- GAS_FLAVOUR_YASM = 2, /**< YASM GNU parser */
- GAS_FLAVOUR_MAX = 3
+ GAS_FLAVOUR_ELF, /**< ELF variant */
+ GAS_FLAVOUR_MINGW, /**< MinGW variant (no-ELF) */
+ GAS_FLAVOUR_YASM, /**< YASM GNU parser */
+ GAS_FLAVOUR_MACH_O, /**< Mach-O variant (as found on darwin, OS/X) */
+ GAS_FLAVOUR_LAST = GAS_FLAVOUR_MACH_O
} be_gas_flavour_t;
/** The variable where the GAS dialect is stored. */
/**
* Generate all entities.
- * @param env the emitter environment
* @param main_env the main backend environment
* @param emit_commons if non-zero, emit commons (non-local uninitialized entities)
* @param only_emit_marked if non-zero, external allocated entities that do not have
/**
* Switch the current output section to the given out.
*
- * @param env the emitter environment
* @param section the new output section
*/
void be_gas_emit_switch_section(be_gas_section_t section);
+/**
+ * emit assembler instructions necessary before starting function code
+ */
+void be_gas_emit_function_prolog(ir_entity *entity, unsigned alignment);
+
+void be_gas_emit_function_epilog(ir_entity *entity);
+
/**
* Return the label prefix for labeled blocks.
*/
const char *be_gas_label_prefix(void);
-#endif /* FIRM_BE_BEGNUAS_H */
+#endif
#include "beirg.h"
#include "be_t.h"
+#include "beabi.h"
#include "irlivechk.h"
/**
BE_TIME_OFF, /* no timing */
0, /* no opt profile */
0, /* try to omit frame pointer */
- 0, /* no stabs debugging output */
BE_VRFY_WARN, /* verification level: warn */
BE_SCHED_LIST, /* scheduler: list scheduler */
+ "linux", /* target OS name */
"i44pc52.info.uni-karlsruhe.de", /* ilp server */
"cplex", /* ilp solver */
0, /* enable statistic event dumping */
LC_OPT_ENT_STR ("config", "read another config file containing backend options", config_file, sizeof(config_file)),
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 ("stabs", "enable stabs debug support", &be_options.stabs_debug_support),
LC_OPT_ENT_ENUM_PTR ("vrfy", "verify the backend irg", &vrfy_var),
LC_OPT_ENT_BOOL ("time", "get backend timing statistics", &be_options.timing),
LC_OPT_ENT_BOOL ("profile", "instrument the code for execution count profiling", &be_options.opt_profile),
LC_OPT_ENT_ENUM_PTR ("sched", "select a scheduler", &sched_var),
+ LC_OPT_ENT_STR ("os", "specify target operating system", &be_options.target_os, sizeof(be_options.target_os)),
#ifdef FIRM_STATISTICS
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.printev, sizeof(be_options.printev)),
env->phi_handler = be_phi_handler_new(env->arch_env);
arch_env_push_irn_handler(env->arch_env, env->phi_handler);
- env->db_handle = be_options.stabs_debug_support ? be_stabs_open(file_handle) : be_nulldbg_open();
+ be_dbg_open();
return env;
}
static void be_done_env(be_main_env_t *env)
{
env->arch_env->isa->impl->done(env->arch_env->isa);
- be_dbg_close(env->db_handle);
+ be_dbg_close();
be_phi_handler_free(env->phi_handler);
obstack_free(&env->obst, NULL);
}
isa = arch_env_get_isa(env.arch_env);
- be_dbg_so(env.db_handle, cup_name);
- be_dbg_types(env.db_handle);
+ be_dbg_so(cup_name);
+ be_dbg_types();
/* backend may provide an ordered list of irgs where code should be generated for */
irg_list = NEW_ARR_F(ir_graph *, 0);
void be_init_copyheur5(void);
void be_init_copystat(void);
void be_init_daemelspill(void);
+void be_init_dbgout(void);
void be_init_arch_ia32(void);
void be_init_arch_ppc32(void);
void be_init_arch_mips(void);
void be_init_spillbelady2(void);
void be_init_spillbelady3(void);
void be_init_ssaconstr(void);
+void be_init_stabs(void);
void be_init_ifg(void);
void be_init_irgmod(void);
void be_init_loopana(void);
be_init_blocksched();
be_init_spill();
be_init_spilloptions();
+ be_init_dbgout();
be_init_listsched();
be_init_schedrss();
be_init_chordal_main();
be_init_ssaconstr();
be_init_state();
be_init_ifg();
+ be_init_stabs();
be_init_arch_ia32();
be_init_arch_ppc32();
void be_do_spill(be_irg_t *birg, const arch_register_class_t *cls);
-#endif /* FIRM_BE_BESPILL_OPTIONS_H */
+#endif
#include "irtools.h"
#include "obst.h"
#include "array.h"
-#include "be_dbgout.h"
+#include "be_dbgout_t.h"
#include "beabi.h"
+#include "bemodule.h"
+#include "beemitter.h"
+#include "dbginfo.h"
/* Non-Stab Symbol and Stab Symbol Types */
enum stabs_types {
*/
typedef struct stabs_handle {
dbg_handle base; /**< the base class */
- FILE *f; /**< the file write to */
ir_entity *cur_ent; /**< current method entity */
const be_stack_layout_t *layout; /**< current stack layout */
unsigned next_type_nr; /**< next type number */
pmap *type_map; /**< a map from type to type number */
const char *main_file; /**< name of the main source file */
const char *curr_file; /**< name of the current source file */
+ unsigned label_num;
+ unsigned last_line;
} stabs_handle;
/**
* generate the void type.
*/
static void gen_void_type(stabs_handle *h) {
- fprintf(h->f, "\t.stabs\t\"void:t%u=%u\",%d,0,0,0\n", 0, 0, N_LSYM);
+ (void) h;
+ be_emit_irprintf("\t.stabs\t\"void:t%u=%u\",%d,0,0,0\n", 0, 0, N_LSYM);
+ be_emit_write_line();
} /* gen_void_type */
typedef struct walker_env {
type_num = get_type_number(h, tp);
if (mode_is_int(mode)) {
- char buf[64];
- fprintf(h->f, "\t.stabs\t\"%s:t%u=r%u;", get_type_name(tp), type_num, type_num);
- tarval_snprintf(buf, sizeof(buf), get_mode_min(mode));
- fprintf(h->f, "%s;", buf);
- tarval_snprintf(buf, sizeof(buf), get_mode_max(mode));
- fprintf(h->f, "%s;\",%d,0,0,0\n", buf, N_LSYM);
+ be_emit_irprintf("\t.stabs\t\"%s:t%u=r%u;", get_type_name(tp), type_num, type_num);
+ be_emit_tarval(get_mode_min(mode));
+ be_emit_char(';');
+ be_emit_tarval(get_mode_max(mode));
+ be_emit_irprintf(";\",%d,0,0,0\n", N_LSYM);
+ be_emit_write_line();
} else if (mode_is_float(mode)) {
int size = get_type_size_bytes(tp);
- fprintf(h->f, "\t.stabs\t\"%s:t%u=r1;%d;0;\",%d,0,0,0\n", get_type_name(tp), type_num, size, N_LSYM);
+ be_emit_irprintf("\t.stabs\t\"%s:t%u=r1;%d;0;\",%d,0,0,0\n", get_type_name(tp), type_num, size, N_LSYM);
+ be_emit_write_line();
}
} /* gen_primitive_type */
int i, n;
SET_TYPE_READY(tp);
- fprintf(h->f, "\t.stabs\t\"%s:T%u=e", get_type_name(tp), type_num);
+ be_emit_irprintf("\t.stabs\t\"%s:T%u=e", get_type_name(tp), type_num);
for (i = 0, n = get_enumeration_n_enums(tp); i < n; ++i) {
ir_enum_const *ec = get_enumeration_const(tp, i);
char buf[64];
tarval_snprintf(buf, sizeof(buf), get_enumeration_value(ec));
- fprintf(h->f, "%s:%s,", get_enumeration_name(ec), buf);
+ be_emit_irprintf("%s:%s,", get_enumeration_name(ec), buf);
}
- fprintf(h->f, ";\",%d,0,0,0\n", N_LSYM);
+ be_emit_irprintf(";\",%d,0,0,0\n", N_LSYM);
+ be_emit_write_line();
} /* gen_enum_type */
/**
ir_type *el_tp = get_pointer_points_to_type(tp);
unsigned el_num = get_type_number(h, el_tp);
- fprintf(h->f, "%u=*%u", type_num, el_num);
+ be_emit_irprintf("%u=*%u", type_num, el_num);
}
/**
if (! IS_TYPE_READY(el_tp))
waitq_put(env->wq, el_tp);
- fprintf(h->f, "\t.stabs\t\"%s:t", get_type_name(tp));
+ be_emit_irprintf("\t.stabs\t\"%s:t", get_type_name(tp));
print_pointer_type(h, tp, 0);
- fprintf(h->f, "\",%d,0,0,0\n", N_LSYM);
+ be_emit_irprintf("\",%d,0,0,0\n", N_LSYM);
+ be_emit_write_line();
} /* gen_pointer_type */
/**
unsigned type_num = local ? h->next_type_nr++ : get_type_number(h, tp);
int *perm;
- fprintf(h->f, "%u=a", type_num);
+ be_emit_irprintf("%u=a", type_num);
NEW_ARR_A(int, perm, n);
for (i = 0; i < n; ++i) {
perm[i] = get_array_order(tp, i);
long max = get_array_upper_bound_int(tp, dim);
/* FIXME r1 must be integer type, but seems to work for now */
- fprintf(h->f, "r1;%ld;%ld;", min, max-1);
+ be_emit_irprintf("r1;%ld;%ld;", min, max-1);
}
}
type_num = get_type_number(h, etp);
- fprintf(h->f, "%d", type_num);
+ be_emit_irprintf("%d", type_num);
}
/**
if (! IS_TYPE_READY(etp))
waitq_put(env->wq, etp);
- fprintf(h->f, "\t.stabs\t\"%s:t", get_type_name(tp));
+ be_emit_irprintf("\t.stabs\t\"%s:t", get_type_name(tp));
print_array_type(h, tp, 0);
- fprintf(h->f, "\",%d,0,0,0\n", N_LSYM);
+ be_emit_irprintf("\",%d,0,0,0\n", N_LSYM);
+ be_emit_write_line();
} /* gen_array_type */
/**
else if (is_Union_type(tp))
desc = 'u';
- fprintf(h->f, "\t.stabs\t\"%s:Tt%u=%c%d",
+ be_emit_irprintf("\t.stabs\t\"%s:Tt%u=%c%d",
get_type_name(tp), type_num, desc, get_type_size_bytes(tp));
for (i = 0, n = get_compound_n_members(tp); i < n; ++i) {
bofs = (ofs + get_entity_offset(ent)) * 8 + get_entity_offset_bits_remainder(ent);
/* name:type, bit offset from the start of the struct', number of bits in the element. */
- fprintf(h->f, "%s:%u,%d,%u;", get_entity_name(ent), type_num, bofs, size);
+ be_emit_irprintf("%s:%u,%d,%u;", get_entity_name(ent), type_num, bofs, size);
}
} else {
/* no bitfield */
- fprintf(h->f, "%s:", get_entity_name(ent));
+ be_emit_irprintf("%s:", get_entity_name(ent));
if (is_Array_type(mtp)) {
/* use a local array definition */
type_num = get_type_number(h, mtp);
/* name:type, bit offset from the start of the struct', number of bits in the element. */
- fprintf(h->f, "%u", type_num);
+ be_emit_irprintf("%u", type_num);
}
size = get_type_size_bytes(mtp) * 8;
- fprintf(h->f, ",%d,%u;", ofs * 8, size);
+ be_emit_irprintf(",%d,%u;", ofs * 8, size);
}
}
- fprintf(h->f, ";\",%d,0,0,0\n", N_LSYM);
+ be_emit_irprintf(";\",%d,0,0,0\n", N_LSYM);
+ be_emit_write_line();
} /* gen_struct_type */
/**
}
res_type_num = get_type_number(h, rtp);
- fprintf(h->f, "\t.stabs\t\"%s:t%u=f%u", get_type_name(tp), type_num, res_type_num);
+ be_emit_irprintf("\t.stabs\t\"%s:t%u=f%u", get_type_name(tp), type_num, res_type_num);
/* handle more than one return type */
for (i = 1; i < n; ++i) {
if (! IS_TYPE_READY(rtp))
waitq_put(env->wq, rtp);
res_type_num = get_type_number(h, rtp);
- fprintf(h->f, ",%u", res_type_num);
+ be_emit_irprintf(",%u", res_type_num);
}
- fprintf(h->f, "\",%d,0,0,0\n", N_LSYM);
+ be_emit_irprintf("\",%d,0,0,0\n", N_LSYM);
+ be_emit_write_line();
} /* gen_method_type */
/**
static void stabs_so(dbg_handle *handle, const char *filename) {
stabs_handle *h = (stabs_handle *)handle;
h->main_file = h->curr_file = filename;
- fprintf(h->f, "\t.stabs\t\"%s\",%d,0,0,.Ltext0\n", filename, N_SO);
+ be_emit_irprintf("\t.stabs\t\"%s\",%d,0,0,.Ltext0\n", filename, N_SO);
+ be_emit_write_line();
} /* stabs_so */
-/**
- * end an include file
- */
-static void stabs_include_end(dbg_handle *handle) {
- stabs_handle *h = (stabs_handle *)handle;
- h->curr_file = h->main_file;
-} /* stabs_include_end */
-
-/**
- * start an include file
- */
-static void stabs_include_begin(dbg_handle *handle, const char *filename) {
- stabs_handle *h = (stabs_handle *)handle;
- if (h->main_file != h->curr_file)
- stabs_include_end(handle);
- h->curr_file = filename;
- fprintf(h->f, "\t.stabs\t\"%s\",%d,0,0,0\n", filename, N_SOL);
-} /* stabs_include_begin */
-
/**
* Main Program
*/
static void stabs_main_program(dbg_handle *handle) {
- stabs_handle *h = (stabs_handle *)handle;
+ (void) handle;
ir_graph *irg = get_irp_main_irg();
if (irg) {
- fprintf(h->f, "\t.stabs\t\"%s\",%d,0,0,0\n", get_entity_name(get_irg_entity(irg)), N_MAIN);
+ be_emit_irprintf("\t.stabs\t\"%s\",%d,0,0,0\n", get_entity_name(get_irg_entity(irg)), N_MAIN);
+ be_emit_write_line();
}
} /* stabs_main_program */
-/**
- * prints a line number
- */
-static void stabs_line(dbg_handle *handle, unsigned lineno, const char *address) {
- stabs_handle *h = (stabs_handle *)handle;
- fprintf(h->f, "\t.stabn\t%d, 0, %u, %s-%s\n", N_SLINE, lineno, address, get_entity_ld_name(h->cur_ent));
-} /* stabs_line */
+static void stabs_set_dbg_info(dbg_handle *h, dbg_info *dbgi)
+{
+ stabs_handle *handle = (stabs_handle*) h;
+ unsigned lineno;
+ const char *fname = ir_retrieve_dbg_info(dbgi, &lineno);
+
+ if (fname == NULL)
+ return;
+
+ if (handle->curr_file != fname) {
+ /* TODO: escape filename correctly */
+ if (handle->curr_file != handle->main_file) {
+ be_emit_irprintf("\t.stabs\t\"%s\",%d,0,0,0\n", handle->curr_file,
+ N_EINCL);
+ be_emit_write_line();
+ }
+ if (fname != handle->main_file) {
+ be_emit_irprintf("\t.stabs\t\"%s\",%d,0,0,0\n", fname, N_SOL);
+ be_emit_write_line();
+ }
+ handle->curr_file = fname;
+ }
+ if (handle->last_line != lineno) {
+ char label[64];
+
+ snprintf(label, sizeof(label), ".LM%u", ++handle->label_num);
+ handle->last_line = lineno;
+
+ be_emit_irprintf("\t.stabn\t%d, 0, %u, %s-%s\n", N_SLINE, lineno,
+ label, get_entity_ld_name(handle->cur_ent));
+ be_emit_write_line();
+
+ be_emit_string(label);
+ be_emit_cstring(":\n");
+ be_emit_write_line();
+ }
+}
/**
* dump the stabs for a method begin
else
rtp = NULL;
type_num = get_type_number(h, rtp);
- fprintf(h->f, "\t.stabs\t\"%s:%c%u\",%u,0,0,%s\n",
+ be_emit_irprintf("\t.stabs\t\"%s:%c%u\",%u,0,0,%s\n",
get_entity_name(ent),
get_entity_visibility(ent) == visibility_external_visible ? 'F' : 'f',
type_num,
N_FUN,
get_entity_ld_name(ent));
+ be_emit_write_line();
/* create parameter entries */
between_size = get_type_size_bytes(layout->between_type);
if (stack_ent) {
ofs = get_entity_offset(stack_ent) + between_size;
}
- fprintf(h->f, "\t.stabs\t\"%s:p", name);
+ be_emit_irprintf("\t.stabs\t\"%s:p", name);
if (is_Array_type(ptp)) {
/* use a local array definition */
print_array_type(h, ptp, 1);
type_num = get_type_number(h, ptp);
/* name:type, bit offset from the start of the struct', number of bits in the element. */
- fprintf(h->f, "%u", type_num);
+ be_emit_irprintf("%u", type_num);
}
- fprintf(h->f, "\",%d,0,0,%d\n", N_PSYM, ofs);
+ be_emit_irprintf("\",%d,0,0,%d\n", N_PSYM, ofs);
+ be_emit_write_line();
}
} /* stabs_method_begin */
type_num = get_type_number(h, tp);
ofs = -frame_size + get_entity_offset(ent);
- fprintf(h->f, "\t.stabs\t\"%s:%u\",%d,0,0,%d\n",
+ be_emit_irprintf("\t.stabs\t\"%s:%u\",%d,0,0,%d\n",
get_entity_name(ent), type_num, N_LSYM, ofs);
+ be_emit_write_line();
}
/* we need a lexical block here */
- fprintf(h->f, "\t.stabn\t%d,0,0,%s-%s\n", N_LBRAC, ld_name, ld_name);
- fprintf(h->f, "\t.stabn\t%d,0,0,.Lscope%u-%s\n", N_RBRAC, scope_nr, ld_name);
- fprintf(h->f, ".Lscope%u:\n", scope_nr);
+ be_emit_irprintf("\t.stabn\t%d,0,0,%s-%s\n", N_LBRAC, ld_name, ld_name);
+ be_emit_write_line();
+ be_emit_irprintf("\t.stabn\t%d,0,0,.Lscope%u-%s\n", N_RBRAC, scope_nr, ld_name);
+ be_emit_write_line();
+ be_emit_irprintf(".Lscope%u:\n", scope_nr);
+ be_emit_write_line();
++scope_nr;
h->cur_ent = NULL;
if (obst)
obstack_printf(obst, "%s", buf);
else
- fprintf(h->f, "%s", buf);
+ be_emit_irprintf("%s", buf);
} /* stabs_variable */
/**
static const debug_ops stabs_ops = {
stabs_close,
stabs_so,
- stabs_include_begin,
- stabs_include_end,
stabs_main_program,
stabs_method_begin,
stabs_method_end,
- stabs_line,
stabs_types,
- stabs_variable
+ stabs_variable,
+ stabs_set_dbg_info
};
-/* Opens the NULL handler */
-dbg_handle *be_nulldbg_open(void) {
- return NULL;
-} /* be_nulldbg_open */
-
/* Opens a stabs handler */
-dbg_handle *be_stabs_open(FILE *out) {
+dbg_handle *be_stabs_open(void) {
stabs_handle *h = xmalloc(sizeof(*h));
h->base.ops = &stabs_ops;
- h->f = out;
h->cur_ent = NULL;
h->layout = NULL;
h->next_type_nr = 0;
h->curr_file = NULL;
return &h->base;
-} /* stabs_open */
-
-/** close a debug handler. */
-void be_dbg_close(dbg_handle *h) {
- if (h && h->ops->close)
- h->ops->close(h);
-} /* be_dbg_close */
-
-/**
- * start a new source object (compilation unit)
- */
-void be_dbg_so(dbg_handle *h, const char *filename) {
- if (h && h->ops->so)
- h->ops->so(h, filename);
-} /* be_dbg_begin */
-
-/**
- * start an include file
- */
-void be_dbg_include_begin(dbg_handle *h, const char *filename) {
- if (h && h->ops->include_begin)
- h->ops->include_begin(h, filename);
-} /* stabs_include_begin */
+}
-/**
- * end an include file
- */
-void be_dbg_include_end(dbg_handle *h) {
- if (h && h->ops->include_end)
- h->ops->include_end(h);
-} /* stabs_include_end */
+void be_init_stabs(void)
+{
+ be_register_dbgout_module("stabs", be_stabs_open);
+}
-/**
- * Main program
- */
-void be_dbg_main_program(dbg_handle *h) {
- if (h && h->ops->main_program)
- h->ops->main_program(h);
-} /* be_dbg_main_program */
-
-/** debug for a method begin */
-void be_dbg_method_begin(dbg_handle *h, ir_entity *ent, const be_stack_layout_t *layout) {
- if (h && h->ops->method_begin)
- h->ops->method_begin(h, ent, layout);
-} /* be_dbg_method_begin */
-
-/** debug for a method end */
-void be_dbg_method_end(dbg_handle *h) {
- if (h && h->ops->method_end)
- h->ops->method_end(h);
-} /* be_dbg_method_end */
-
-/** debug for line number */
-void be_dbg_line(dbg_handle *h, unsigned lineno, const char *address) {
- if (h && h->ops->line)
- h->ops->line(h, lineno, address);
-} /* be_dbg_line */
-
-/** dump types */
-void be_dbg_types(dbg_handle *h) {
- if (h && h->ops->types)
- h->ops->types(h);
-} /* be_dbg_types */
-
-/** dump a global */
-void be_dbg_variable(dbg_handle *h, struct obstack *obst, ir_entity *ent) {
- if (h && h->ops->variable)
- h->ops->variable(h, obst, ent);
-} /* be_dbg_variable */
+BE_REGISTER_MODULE_CONSTRUCTOR(be_init_stabs);
}
static const lc_opt_enum_int_items_t gas_items[] = {
- { "normal", GAS_FLAVOUR_NORMAL },
+ { "elf", GAS_FLAVOUR_ELF },
{ "mingw", GAS_FLAVOUR_MINGW },
{ "yasm", GAS_FLAVOUR_YASM },
+ { "macho", GAS_FLAVOUR_MACH_O },
{ NULL, 0 }
};
#include "../beemitter.h"
#include "../begnuas.h"
#include "../beirg_t.h"
+#include "../be_dbgout.h"
#include "ia32_emitter.h"
#include "gen_ia32_emitter.h"
}
}
-static void ia32_emit_function_object(const char *name)
-{
- switch (be_gas_flavour) {
- case GAS_FLAVOUR_NORMAL:
- be_emit_cstring("\t.type\t");
- be_emit_string(name);
- be_emit_cstring(", @function\n");
- be_emit_write_line();
- break;
- case GAS_FLAVOUR_MINGW:
- be_emit_cstring("\t.def\t");
- be_emit_string(name);
- be_emit_cstring(";\t.scl\t2;\t.type\t32;\t.endef\n");
- be_emit_write_line();
- break;
- case GAS_FLAVOUR_YASM:
- break;
- default:
- break;
- }
-}
-
-static void ia32_emit_function_size(const char *name)
-{
- switch (be_gas_flavour) {
- case GAS_FLAVOUR_NORMAL:
- be_emit_cstring("\t.size\t");
- be_emit_string(name);
- be_emit_cstring(", .-");
- be_emit_string(name);
- be_emit_char('\n');
- be_emit_write_line();
- break;
- case GAS_FLAVOUR_MINGW:
- case GAS_FLAVOUR_YASM:
- break;
- default:
- break;
- }
-}
-
-
void ia32_emit_source_register_or_immediate(const ir_node *node, int pos)
{
ir_node *in = get_irn_n(node, pos);
#undef IA32_EMIT
}
-static const char *last_name = NULL;
-static unsigned last_line = -1;
-static unsigned num = -1;
-
-/**
- * Emit the debug support for node node.
- */
-static void ia32_emit_dbg(const ir_node *node)
-{
- dbg_info *db = get_irn_dbg_info(node);
- unsigned lineno;
- const char *fname = ir_retrieve_dbg_info(db, &lineno);
-
- if (! cg->birg->main_env->options->stabs_debug_support)
- return;
-
- if (fname) {
- if (last_name != fname) {
- last_line = -1;
- be_dbg_include_begin(cg->birg->main_env->db_handle, fname);
- last_name = fname;
- }
- if (last_line != lineno) {
- char name[64];
-
- snprintf(name, sizeof(name), ".LM%u", ++num);
- last_line = lineno;
- be_dbg_line(cg->birg->main_env->db_handle, lineno, name);
- be_emit_string(name);
- be_emit_cstring(":\n");
- be_emit_write_line();
- }
- }
-}
-
typedef void (*emit_func_ptr) (const ir_node *);
/**
if (op->ops.generic) {
emit_func_ptr func = (emit_func_ptr) op->ops.generic;
- ia32_emit_dbg(node);
+
+ be_dbg_set_dbg_info(get_irn_dbg_info(node));
+
(*func) (node);
} else {
emit_Nothing(node);
be_emit_write_line();
}
-/**
- * Emits gas alignment directives for Functions depended on cpu architecture.
- */
-static void ia32_emit_align_func(void)
-{
- unsigned align = ia32_cg_config.function_alignment;
- unsigned maximum_skip = (1 << align) - 1;
-
- ia32_emit_alignment(align, maximum_skip);
-}
-
/**
* Emits gas alignment directives for Labels depended on cpu architecture.
*/
ia32_emit_block_header(block, last_block);
/* emit the contents of the block */
- ia32_emit_dbg(block);
+ be_dbg_set_dbg_info(get_irn_dbg_info(block));
sched_foreach(block, node) {
ia32_emit_node(node);
}
}
-/**
- * Emits code for function start.
- */
-static void ia32_emit_func_prolog(ir_graph *irg)
-{
- ir_entity *irg_ent = get_irg_entity(irg);
- const char *irg_name = get_entity_ld_name(irg_ent);
- const be_irg_t *birg = cg->birg;
-
- /* write the begin line (used by scripts processing the assembler... */
- be_emit_write_line();
- be_emit_cstring("# -- Begin ");
- be_emit_string(irg_name);
- be_emit_char('\n');
- be_emit_write_line();
-
- be_gas_emit_switch_section(GAS_SECTION_TEXT);
- be_dbg_method_begin(birg->main_env->db_handle, irg_ent, be_abi_get_stack_layout(birg->abi));
- ia32_emit_align_func();
- if (get_entity_visibility(irg_ent) == visibility_external_visible) {
- be_emit_cstring(".global ");
- be_emit_string(irg_name);
- be_emit_char('\n');
- be_emit_write_line();
- }
- ia32_emit_function_object(irg_name);
- be_emit_string(irg_name);
- be_emit_cstring(":\n");
- be_emit_write_line();
-}
-
-/**
- * Emits code for function end
- */
-static void ia32_emit_func_epilog(ir_graph *irg)
-{
- const char *irg_name = get_entity_ld_name(get_irg_entity(irg));
- const be_irg_t *birg = cg->birg;
-
- ia32_emit_function_size(irg_name);
- be_dbg_method_end(birg->main_env->db_handle);
-
- be_emit_cstring("# -- End ");
- be_emit_string(irg_name);
- be_emit_char('\n');
- be_emit_write_line();
-
- be_emit_char('\n');
- be_emit_write_line();
-}
-
/**
* Block-walker:
* Sets labels for control flow nodes (jump target)
*/
void ia32_gen_routine(ia32_code_gen_t *ia32_cg, ir_graph *irg)
{
- ir_node *block;
- ir_node *last_block = NULL;
+ ir_node *block;
+ ir_node *last_block = NULL;
+ ir_entity *entity = get_irg_entity(irg);
int i, n;
cg = ia32_cg;
ia32_register_emitters();
- ia32_emit_func_prolog(irg);
+ be_dbg_method_begin(entity, be_abi_get_stack_layout(cg->birg->abi));
+ be_gas_emit_function_prolog(entity, ia32_cg_config.function_alignment);
+
irg_block_walk_graph(irg, ia32_gen_labels, NULL, NULL);
n = ARR_LEN(cg->blk_sched);
last_block = block;
}
- ia32_emit_func_epilog(irg);
+ be_gas_emit_function_epilog(entity);
+ be_dbg_method_end();
+ be_emit_char('\n');
+ be_emit_write_line();
}
void ia32_init_emitter(void)