From df29cc33c216d5191980847f63843447954aed11 Mon Sep 17 00:00:00 2001 From: Hannes Jakschitsch Date: Mon, 28 Feb 2005 17:28:19 +0000 Subject: [PATCH] the partly done generic assemblerdumper --- ir/be/Makefile.in | 3 +- ir/be/beasm_asm_gnu.c | 282 ++++++++++++++++++++++++++++++++++++++++++ ir/be/beasm_asm_gnu.h | 26 ++++ ir/be/beasm_types.h | 105 ++++++++++++++++ ir/be/bemain.c | 11 ++ 5 files changed, 426 insertions(+), 1 deletion(-) create mode 100644 ir/be/beasm_asm_gnu.c create mode 100644 ir/be/beasm_asm_gnu.h create mode 100644 ir/be/beasm_types.h diff --git a/ir/be/Makefile.in b/ir/be/Makefile.in index 49b2f287a..6ffc755d6 100644 --- a/ir/be/Makefile.in +++ b/ir/be/Makefile.in @@ -22,7 +22,8 @@ SOURCES = $(INSTALL_HEADERS) SOURCES += Makefile.in besched.h belistsched.h belistsched.c \ beutil.h bemain.c besched.c bemain.c belive.c belive.h benumb.h \ benumb_t.h benumb.c bechordal.c bera.c beutil.c phistat.c \ - bephiopt.c bephicoal.c bera.h bechordalspill.c + bephiopt.c bephicoal.c bera.h bechordalspill.c \ + beasm_dump_globals.c beasm_asm_gnu.c include $(topdir)/MakeRules diff --git a/ir/be/beasm_asm_gnu.c b/ir/be/beasm_asm_gnu.c new file mode 100644 index 000000000..d57c7af93 --- /dev/null +++ b/ir/be/beasm_asm_gnu.c @@ -0,0 +1,282 @@ + +#include "beasm_asm_gnu.h" + +static struct obstack *get_obstack_for_segment ( gnuasm_privdata_t *privdata, asm_segment_t segment ) { + + switch(segment) { + case ASM_SEGMENT_CONST: + return &privdata->rdata_obst; + break; + case ASM_SEGMENT_DATA_INIT: + return &privdata->data_obst; + break; + case ASM_SEGMENT_CODE: + return &privdata->code_obst; + break; + case ASM_SEGMENT_DATA_UNINIT: + return &privdata->common_obst; + break; + default: + assert(0 && "unknown segment type"); + break; + } +} + + +/* + * the dumper callbacks + **/ + +void gnuasm_dump_align( gnuasm_privdata_t *privdata, asm_segment_t segment, int align ) { + struct obstack* obst = get_obstack_for_segment ( privdata, segment ); + obstack_printf(obst, "\t.align %d\n", align); +} + +void gnuasm_dump_arith_tarval ( gnuasm_privdata_t *privdata, asm_segment_t segment, + tarval *tv, int bytes ) { + + struct obstack* obst = get_obstack_for_segment ( privdata, segment ); + + switch (bytes) { + + case 1: + obstack_printf(obst, "0x%02x", get_tarval_sub_bits(tv, 0)); + break; + case 2: + obstack_printf(obst, "0x%02x%02x", get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0)); + break; + + case 4: + obstack_printf(obst, "0x%02x%02x%02x%02x", + get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2), get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0)); + break; + + case 8: + obstack_printf(obst, "0x%02x%02x%02x%02x%02x%02x%02x%02x", +get_tarval_sub_bits(tv, 7), get_tarval_sub_bits(tv, 6), get_tarval_sub_bits(tv, 5), get_tarval_sub_bits(tv, 4), get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2), get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0)); + break; + + default: + fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes); + assert(0); + } +} + + +void gnuasm_dump_atomic_decl ( gnuasm_privdata_t *privdata, asm_segment_t segment, int bytes ) { + + struct obstack* obst = get_obstack_for_segment ( privdata, segment ); + + switch (bytes) { + + case 1: + obstack_printf(obst, "\t.byte\t"); + break; + + case 2: + obstack_printf(obst, "\t.value\t"); + break; + + case 4: + obstack_printf(obst, "\t.long\t"); + break; + + case 8: + obstack_printf(obst, "\t.quad\t"); + break; + + default: + fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes); + assert(0); + } + +// obstack_printf(obst, "\n"); +} + +void gnuasm_dump_string ( gnuasm_privdata_t *privdata, asm_segment_t segment, entity* ent ) { + + int i, n; + + struct obstack* obst = get_obstack_for_segment ( privdata, segment ); + + obstack_printf(obst, "\t.string \""); + n = get_compound_ent_n_values(ent); + + for (i = 0; i < n-1; ++i) { + ir_node *irn; + int c; + + irn = get_compound_ent_value(ent, i); + c = (int) get_tarval_long(get_Const_tarval(irn)); + + switch (c) { + case '"' : obstack_printf(obst, "\\\""); break; + case '\n': obstack_printf(obst, "\\n"); break; + case '\r': obstack_printf(obst, "\\r"); break; + case '\t': obstack_printf(obst, "\\t"); break; + default: + if (isprint(c)) + obstack_printf(obst, "%c", c); + else + obstack_printf(obst, "%O", c); + break; + } + } + obstack_printf(obst, "\"\n"); + +} + + +void gnuasm_dump_declare_initialized_symbol(gnuasm_privdata_t* priv_data, asm_segment_t segment, const char* ld_name, int bytes, int align, ent_visibility visibility) { + + // get the obstack for the given segment (const, data) + struct obstack* obst = get_obstack_for_segment ( priv_data, segment ); + + // if the symbol is externally visibile, declare it so. + if (visibility == visibility_external_visible) + obstack_printf(obst, ".globl\t%s\n", ld_name); + + obstack_printf(obst, "\t.type\t%s,@object\n", ld_name); + obstack_printf(obst, "\t.size\t%s,%d\n", ld_name, bytes); + obstack_printf(obst, "\t.align\t%d\n", align); + obstack_printf(obst, "\t%s:\n", ld_name); +} + +void gnuasm_dump_declare_uninitialized_symbol(gnuasm_privdata_t* priv_data, asm_segment_t segment, const char* ld_name, int bytes, int align, ent_visibility visibility) { + + // external symbols are not required to be declared in gnuasm. + if(visibility == visibility_external_allocated) return; + + // declare local, uninitialized symbol to the uninit-obst + obstack_printf(&priv_data->common_obst, "\t.comm\t%s,%d,%d\n", ld_name, bytes, align); +} + + +void gnuasm_dump_zero_padding ( gnuasm_privdata_t *privdata, asm_segment_t segment, int size ) { + + struct obstack* obst = get_obstack_for_segment ( privdata, segment ); + obstack_printf(obst, "\t.zero\t%d\n", size); +} + +//////////////////////////////////////////////////////////////////////////// + +void gnuasm_dump_arith_op ( gnuasm_privdata_t *privdata, asm_segment_t segment, asm_arith_operation_t op ) { + struct obstack* obst = get_obstack_for_segment ( privdata, segment ); + switch (op) { + case ASM_ARITH_OPERATION_ADD: + obstack_printf(obst, "+"); + break; + case ASM_ARITH_OPERATION_SUB: + obstack_printf(obst, "-"); + break; + case ASM_ARITH_OPERATION_MUL: + obstack_printf(obst, "*"); + break; + } + //obstack_printf(obst, "+"); +} + +void gnuasm_dump_symconst ( gnuasm_privdata_t *privdata, asm_segment_t segment, ir_node *init ) { + + struct obstack* obst = get_obstack_for_segment ( privdata, segment ); + switch (get_SymConst_kind(init)) { + case symconst_addr_name: + obstack_printf(obst, "%s", get_id_str(get_SymConst_name(init))); + break; + + case symconst_addr_ent: + obstack_printf(obst, "%s", get_entity_ld_name(get_SymConst_entity(init))); + break; + + case symconst_size: + obstack_printf(obst, "%d", get_type_size_bytes(get_SymConst_type(init))); + break; + + default: + assert(0 && "dump_atomic_init(): don't know how to init from this SymConst"); + } +} + +void gnuasm_dump_newline ( gnuasm_privdata_t *privdata, asm_segment_t segment ) { + struct obstack* obst = get_obstack_for_segment ( privdata, segment ); + obstack_printf(obst, "\n"); +} + +////////////////////////////////////////////////////////////////////////////// + +void gnuasm_dump_header ( gnuasm_privdata_t *privdata ) { + +} + +void gnuasm_dump_footer ( gnuasm_privdata_t *privdata ) { + +} + +void gnuasm_dump_segment_header ( gnuasm_privdata_t *privdata ) { + +} + +////////////////////////////////////////////////////////////////////////////// + +assembler_t *gnuasm_create_assembler ( void ) { + + gnuasm_privdata_t *priv_data = malloc ( sizeof(gnuasm_privdata_t )); + assembler_t *assembler = malloc ( sizeof( assembler_t )); + memset(assembler, 0, sizeof( assembler_t )); + assembler->private_data = priv_data; + + obstack_init (&priv_data->common_obst); + obstack_init (&priv_data->data_obst); + obstack_init (&priv_data->rdata_obst); + obstack_init (&priv_data->code_obst); + + + assembler->dump_declare_uninitialized_symbol = (dump_declare_uninitialized_symbol_proc) &gnuasm_dump_declare_uninitialized_symbol; + assembler->dump_declare_initialized_symbol = (dump_declare_initialized_symbol_proc) &gnuasm_dump_declare_initialized_symbol; + +// assembler->dump_align = (dump_align_proc) &gnuasm_dump_align; + assembler->dump_arith_tarval = (dump_arith_tarval_proc) &gnuasm_dump_arith_tarval; + assembler->dump_atomic_decl = (dump_atomic_decl_proc) gnuasm_dump_atomic_decl; + assembler->dump_string = (dump_string_proc) &gnuasm_dump_string; + assembler->dump_zero_padding = (dump_zero_padding_proc) &gnuasm_dump_zero_padding; + assembler->dump_arith_op = (dump_arith_op_proc) &gnuasm_dump_arith_op; + assembler->dump_symconst = (dump_symconst_proc) &gnuasm_dump_symconst; + assembler->dump_newline = (dump_newline_proc) &gnuasm_dump_newline; + + assembler->dump_header = (dump_header_proc) &gnuasm_dump_header; + assembler->dump_footer = (dump_footer_proc) &gnuasm_dump_footer; + assembler->dump_segment_header = (dump_segment_header_proc) &gnuasm_dump_segment_header; + + + return assembler; + +} + +static void gnuasm_dump_obst ( struct obstack* obst, FILE* out ) { + + obstack_grow0 (obst, NULL, 0); + void *data = obstack_finish (obst); + fprintf(out, "%s", data); +} + +void gnuasm_dump ( assembler_t *assembler, FILE* out ) { + + gnuasm_privdata_t *privdata = assembler->private_data; + +// fprintf(out, "\n"); + gnuasm_dump_obst ( &privdata->common_obst, out); + fprintf(out, ".data\n"); + gnuasm_dump_obst ( &privdata->data_obst, out); + fprintf(out, ".section .rodata\n"); + gnuasm_dump_obst ( &privdata->rdata_obst, out); + fprintf(out, ".text\n"); + gnuasm_dump_obst ( &privdata->code_obst, out); + ////// + +} + +void gnuasm_delete_assembler ( assembler_t *assembler ) { + + free ( assembler->private_data ); + free ( assembler ); +} diff --git a/ir/be/beasm_asm_gnu.h b/ir/be/beasm_asm_gnu.h new file mode 100644 index 000000000..a3c735303 --- /dev/null +++ b/ir/be/beasm_asm_gnu.h @@ -0,0 +1,26 @@ +#ifndef BEASM_ASM_GNU_H +#define BEASM_ASM_GNU H + +#include "beasm_dump_globals.h" + +//#include + +#include +#include + +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free free + +typedef struct _gnuasm_privdata_t { + struct obstack common_obst; + struct obstack data_obst; + struct obstack rdata_obst; + struct obstack code_obst; +} gnuasm_privdata_t; + + +assembler_t *gnuasm_create_assembler ( void ); +void gnuasm_dump ( assembler_t *assembler, FILE* out ); +void gnuasm_delete_assembler ( assembler_t *assembler ); + +#endif diff --git a/ir/be/beasm_types.h b/ir/be/beasm_types.h new file mode 100644 index 000000000..85a60393a --- /dev/null +++ b/ir/be/beasm_types.h @@ -0,0 +1,105 @@ +/** + * the 'generic' assemblercode emitter + * @author Hannes Jakschitsch + * @date 19.01.2005 + */ + +#ifndef _BEASM_TYPES_H +#define _BEASM_TYPES_H + +#include +#include +#include "libfirm/firm.h" + + +/** + * Definition of symbolic segments + **/ +typedef enum _asm_segment_t { + ASM_SEGMENT_CONST = 1, /* < segment to store constant symbols */ + ASM_SEGMENT_DATA_INIT, /* < segment to store initialized symbols */ + ASM_SEGMENT_CODE, /* < segment to store code */ + ASM_SEGMENT_DATA_UNINIT, /* < segment to store uninitialized symbols */ +} asm_segment_t; + +typedef enum _asm_arith_operation_t { + + ASM_ARITH_OPERATION_ADD = 1, + ASM_ARITH_OPERATION_SUB, + ASM_ARITH_OPERATION_MUL + +} asm_arith_operation_t; + + + + +typedef struct _assembler_t assembler_t; + +typedef void (*dump_align_proc)(void* priv_data, asm_segment_t segment, int align); +typedef void (*dump_arith_tarval_proc)(void* priv_data, asm_segment_t segment, tarval *tv, int bytes); +typedef void (*dump_atomic_decl_proc)(void* priv_data, asm_segment_t segment, int bytes); +typedef void (*dump_string_proc)(void* priv_data, asm_segment_t segment, entity *ent); +typedef void (*dump_external_declaration_proc)(void* priv_data, asm_segment_t segment, const char* ld_name); +typedef void (*dump_local_declaration_proc)(void* priv_data, asm_segment_t segment, const char* ld_name ); +// declares an uninitialized symbol. +typedef void (*dump_declare_uninitialized_symbol_proc)(void* priv_data, asm_segment_t segment, const char* ldname, int bytes, int align, ent_visibility visibility); +typedef void (*dump_declare_initialized_symbol_proc)(void* priv_data, asm_segment_t segment, const char* ldname, int bytes, int align, ent_visibility visibility); +//typedef void (*dump_declare_object_symbol_proc)(void* priv_data, asm_segment_t segment, const char* ld_name, int bytes); +//typedef void (*dump_declare_function_symbol_proc)(void* priv_data, asm_segment_t segment, const char* ld_name); +//typedef void (*dump_object_symbol_init_decl_proc)(void* priv_data, asm_segment_t segment, const char* ld_name); +// emits a zero padding directive. +typedef void (*dump_zero_padding_proc)(void* priv_data, asm_segment_t segment, int bytes); +typedef void (*dump_arith_op_proc)(void* priv_data, asm_segment_t segment, asm_arith_operation_t op); +typedef void (*dump_symconst_proc)(void* priv_data, asm_segment_t segment, ir_node *init); +/*typedef void (*dump_size_proc)(void* priv_data, asm_segment_t segment, int size); +typedef void (*dump_addr_name_proc)(void* priv_data, asm_segment_t segment, const char* addr_name); +typedef void (*dump_addr_ent_proc)(void* priv_data, asm_segment_t segment, const char* addr_ent); */ +typedef void (*dump_newline_proc)(void* priv_data, asm_segment_t segment); + +/////////////////////////////////////////////////////////////////////////// + +typedef void (*dump_header_proc)(void* priv_data); +typedef void (*dump_footer_proc)(void* priv_data); +typedef void (*dump_segment_header_proc)(void* priv_data); + +struct _assembler_t { + + /////////////////////////////////////////////////////////////////////////// + // declarators + + dump_declare_uninitialized_symbol_proc dump_declare_uninitialized_symbol; + dump_declare_initialized_symbol_proc dump_declare_initialized_symbol; + + /////////////////////////////////////////////////////////////////////////// + // initializers + + + // declare an atomic value of BYTES size. + // e.g. .long or .byte + // needed when emitting an initializer + dump_atomic_decl_proc dump_atomic_decl; + // dump a target value. needed when emitting an initializer + dump_arith_tarval_proc dump_arith_tarval; + // dump a string. needed when emitting an initializer. improves readability. + dump_string_proc dump_string; + // dump a zero padding. + dump_zero_padding_proc dump_zero_padding; + // dump an arithmetic operator. used when initializers are expressions + // that cannot be evaluated and must be computed by the assembler. + dump_arith_op_proc dump_arith_op; + // dump a symconst + dump_symconst_proc dump_symconst; + + /////////////////////////////////////////////////////////////////////////// + // formatters. + dump_newline_proc dump_newline; + dump_header_proc dump_header; + dump_footer_proc dump_footer; + dump_segment_header_proc dump_segment_header; + + void *private_data; +}; + + + +#endif diff --git a/ir/be/bemain.c b/ir/be/bemain.c index 68556176f..ad923a39b 100644 --- a/ir/be/bemain.c +++ b/ir/be/bemain.c @@ -28,6 +28,9 @@ #include "bephiopt.h" #include "phistat.h" +#include "beasm_dump_globals.h" +#include "beasm_asm_gnu.h" + #define DUMP_ALLOCATED #undef DUMP_LOCALIZED @@ -135,4 +138,12 @@ static void be_main_loop(void) void be_main(int argc, const char *argv[]) { be_main_loop(); + assembler_t *gnu_assembler = gnuasm_create_assembler(); + FILE *asm_output_file = fopen("asm_output.asm", "w"); + + asm_dump_globals ( gnu_assembler ); + gnuasm_dump ( gnu_assembler, asm_output_file ); + gnuasm_delete_assembler ( gnu_assembler ); + fclose(asm_output_file); + } -- 2.20.1