Commit 021dd42c authored by Michael Beck's avatar Michael Beck
Browse files

Added arm backend from BE praktikum

parent aeb3ec50
This diff is collapsed.
#ifndef _arm_EMITTER_H_
#define _arm_EMITTER_H_
#include "irargs_t.h" // this also inlucdes <libcore/lc_print.h>
#include "irnode.h"
#include "debug.h"
#include "../bearch.h"
#include "bearch_arm_t.h"
typedef struct _arm_emit_env_t {
firm_dbg_module_t *mod;
FILE *out;
const arch_env_t *arch_env;
const arm_code_gen_t *cg;
} arm_emit_env_t;
const lc_arg_env_t *arm_get_arg_env(void);
void equalize_dest_src(FILE *F, ir_node *n);
int get_arm_reg_nr(ir_node *irn, int posi, int in_out);
const char *get_arm_in_reg_name(ir_node *irn, int pos);
void arm_gen_routine(FILE *F, ir_graph *irg, const arm_code_gen_t *cg);
#endif /* _arm_EMITTER_H_ */
/**
* Dumps global variables and constants as arm assembler.
* @date 14.02.2006
* @version $Id$
*/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include "xmalloc.h"
#include <obstack.h>
#ifdef obstack_chunk_alloc
# undef obstack_chunk_alloc
# define obstack_chunk_alloc xmalloc
#else
# define obstack_chunk_alloc xmalloc
# define obstack_chunk_free free
#endif
#include "tv.h"
#include "irnode.h"
#include "entity.h"
#include "irprog.h"
#include "arm_gen_decls.h"
/************************************************************************/
/*
* returns the highest bit value
*/
static unsigned highest_bit(unsigned v)
{
int res = -1;
if (v >= (1U << 16U)) {
res += 16;
v >>= 16;
}
if (v >= (1U << 8U)) {
res += 8;
v >>= 8;
}
if (v >= (1U << 4U)) {
res += 4;
v >>= 4;
}
if (v >= (1U << 2U)) {
res += 2;
v >>= 2;
}
if (v >= (1U << 1U)) {
res += 1;
v >>= 1;
}
if (v >= 1)
res += 1;
return res;
}
/*
* output the alignment
*/
static void arm_dump_align(struct obstack *obst, int align)
{
int h = highest_bit(align);
if ((1 << h) < align)
++h;
align = (1 << h);
if (align > 1)
obstack_printf(obst, "\t.align %d\n", align);
}
static void dump_arith_tarval(struct obstack *obst, tarval *tv, int bytes)
{
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;
case 10:
case 12:
break;
default:
fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes);
assert(0);
}
}
/*
* dump an arithmetic tarval
*/
static void arm_dump_arith_tarval(struct obstack *obst, tarval *tv, int bytes)
{
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;
case 10:
case 12:
break;
default:
fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes);
assert(0);
}
dump_arith_tarval(obst, tv, bytes);
}
/*
* dump an atomic value
*/
static void do_dump_atomic_init(struct obstack *obst, ir_node *init)
{
ir_mode *mode = get_irn_mode(init);
int bytes = get_mode_size_bytes(mode);
tarval *tv;
switch (get_irn_opcode(init)) {
case iro_Cast:
do_dump_atomic_init(obst, get_Cast_op(init));
return;
case iro_Conv:
do_dump_atomic_init(obst, get_Conv_op(init));
return;
case iro_Const:
tv = get_Const_tarval(init);
/* beware of old stuff */
assert(! mode_is_reference(mode));
/* it's a arithmetic value */
dump_arith_tarval(obst, tv, bytes);
return;
case iro_SymConst:
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");
}
return;
case iro_Add:
do_dump_atomic_init(obst, get_Add_left(init));
obstack_printf(obst, " + ");
do_dump_atomic_init(obst, get_Add_right(init));
return;
case iro_Sub:
do_dump_atomic_init(obst, get_Sub_left(init));
obstack_printf(obst, " - ");
do_dump_atomic_init(obst, get_Sub_right(init));
return;
case iro_Mul:
do_dump_atomic_init(obst, get_Mul_left(init));
obstack_printf(obst, " * ");
do_dump_atomic_init(obst, get_Mul_right(init));
return;
default:
assert(0 && "dump_atomic_init(): unknown IR-node");
}
}
/*
* dump an atomic value
*/
static void dump_atomic_init(struct obstack *obst, ir_node *init)
{
ir_mode *mode = get_irn_mode(init);
int bytes = get_mode_size_bytes(mode);
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;
case 10:
case 12:
/* handled in arith */
break;
default:
fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes);
assert(0);
}
do_dump_atomic_init(obst, init);
obstack_printf(obst, "\n");
}
/************************************************************************/
/* Routines to dump global variables */
/************************************************************************/
/**
* Determine if an entity is a string constant
* @param ent The entity
* @return 1 if it is a string constant, 0 otherwise
*/
static int ent_is_string_const(entity *ent)
{
int res = 0;
ir_type *ty;
ty = get_entity_type(ent);
/* if it's an array */
if (is_Array_type(ty)) {
ir_type *elm_ty = get_array_element_type(ty);
/* and the array's element type is primitive */
if (is_Primitive_type(elm_ty)) {
ir_mode *mode = get_type_mode(elm_ty);
/*
* and the mode of the element type is an int of
* the same size as the byte mode
*/
if (mode_is_int(mode)
&& get_mode_size_bits(mode) == get_mode_size_bits(mode_Bs))
{
int i, c, n;
n = get_compound_ent_n_values(ent);
for (i = 0; i < n; ++i) {
ir_node *irn = get_compound_ent_value(ent, i);
if(get_irn_opcode(irn) != iro_Const)
return 0;
c = (int) get_tarval_long(get_Const_tarval(irn));
if((i < n - 1 && !(isgraph(c) || isspace(c)))
|| (i == n - 1 && c != '\0'))
return 0;
}
res = 1;
}
}
}
return res;
}
/**
* Dump a atring constant.
* No checks are made!!
* @param obst The obst to dump on.
* @param ent The entity to dump.
*/
static void dump_string_cst(struct obstack *obst, entity *ent)
{
int i, n;
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");
}
struct arr_info {
int n_elems;
int visit_cnt;
int size;
};
/*
* Dumps the initialization of global variables that are not
* "uninitialized".
*/
static void dump_global(struct obstack *rdata_obstack, struct obstack *data_obstack, struct obstack *comm_obstack, entity *ent)
{
ir_type *ty = get_entity_type(ent);
const char *ld_name = get_entity_ld_name(ent);
int align, h;
struct obstack *obst = data_obstack;
/*
* FIXME: did NOT work for partly constant values
*/
if (! is_Method_type(ty)) {
ent_variability variability = get_entity_variability(ent);
visibility visibility = get_entity_visibility(ent);
if (variability == variability_constant) {
/* a constant entity, put it on the rdata */
obst = rdata_obstack;
}
/* check, wether it is initialized, if yes create data */
if (variability != variability_uninitialized) {
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, (get_type_size_bits(ty) + 7) >> 3);
align = get_type_alignment_bytes(ty);
arm_dump_align(obst, align);
obstack_printf(obst, "%s:\n", ld_name);
if (is_atomic_type(ty)) {
if (get_entity_visibility(ent) != visibility_external_allocated)
dump_atomic_init(obst, get_atomic_ent_value(ent));
}
else {
int i, size = 0;
if (ent_is_string_const(ent)) {
dump_string_cst(obst, ent);
}
else if (is_Array_type(ty)) {
int filler;
/* potential spare values should be already included! */
for (i = 0; i < get_compound_ent_n_values(ent); ++i) {
entity *step = get_compound_ent_value_member(ent, i);
ir_type *stype = get_entity_type(step);
if (get_type_mode(stype)) {
int align = (get_type_alignment_bits(stype) + 7) >> 3;
int n = size % align;
if (n > 0) {
obstack_printf(obst, "\t.zero\t%d\n", align - n);
size += align - n;
}
}
dump_atomic_init(obst, get_compound_ent_value(ent, i));
size += get_type_size_bytes(stype);
}
filler = get_type_size_bytes(ty) - size;
if (filler > 0)
obstack_printf(obst, "\t.zero\t%d\n", filler);
}
else if (is_compound_type(ty)) {
ir_node **vals;
int type_size, j;
/* Compound entities are NOT sorted.
* The sorting strategy used doesn't work for `value' compound fields nor
* for partially_constant entities.
*/
/*
* in the worst case, every entity allocates one byte, so the type
* size should be equal or bigger the number of fields
*/
type_size = get_type_size_bytes(ty);
vals = xcalloc(type_size, sizeof(*vals));
/* collect the values and store them at the offsets */
for(i = 0; i < get_compound_ent_n_values(ent); ++i) {
int graph_length, aipos, offset;
struct arr_info *ai;
int all_n = 1;
compound_graph_path *path = get_compound_ent_value_path(ent, i);
/* get the access path to the costant value */
graph_length = get_compound_graph_path_length(path);
ai = xcalloc(graph_length, sizeof(struct arr_info));
/* We wanna know how many arrays are on the path to the entity. We also have to know how
* many elements each array holds to calculate the offset for the entity. */
for (j = 0; j < graph_length; j++) {
entity *step = get_compound_graph_path_node(path, j);
ir_type *step_type = get_entity_type(step);
int ty_size = (get_type_size_bits(step_type) + 7) >> 3;
int k, n = 0;
if (is_Array_type(step_type))
for (k = 0; k < get_array_n_dimensions(step_type); k++)
n += get_tarval_long(get_Const_tarval(get_array_upper_bound(step_type, k)));
if (n) all_n *= n;
ai[j].n_elems = n ? all_n + 1 : 0;
ai[j].visit_cnt = 0;
ai[j].size = ty_size;
}
aipos = graph_length - 1;
if (aipos) aipos--;
for (offset = j = 0; j < graph_length; j++) {
entity *step = get_compound_graph_path_node(path, j);
ir_type *step_type = get_entity_type(step);
int ent_ofs = get_entity_offset_bytes(step);
int stepsize = 0;
/* add all positive offsets (= offsets in structs) */
if (ent_ofs >= 0) offset += ent_ofs;
if (j == graph_length - 1) {
stepsize = (get_type_size_bits(step_type) + 7) >> 3;
/* Search the next free position in vals depending on the information from above (ai). */
while (vals[offset]) {
if (ai[aipos].visit_cnt < ai[aipos].n_elems) {
offset += stepsize;
ai[aipos].visit_cnt++;
}
else
while (aipos >= 0 && ai[aipos].visit_cnt == ai[aipos].n_elems) {
stepsize = ai[aipos--].size;
offset += stepsize;
}
}
assert(aipos >= 0 && "couldn't store entity");
vals[offset] = get_compound_ent_value(ent, i);
}
}
free(ai);
}
/* now write them sorted */
for(i = 0; i < type_size; ) {
if (vals[i]) {
dump_atomic_init(obst, vals[i]);
i += (get_mode_size_bytes(get_irn_mode(vals[i])));
}
else {
/* a gap */
obstack_printf(obst, "\t.byte\t0\n");
++i;
}
}
free(vals);
}
else {
assert(0 && "unsupported type");
}
}
obstack_printf(obst, "\n");
}
else if (visibility != visibility_external_allocated) {
if (visibility == visibility_local) {
obstack_printf(comm_obstack, "\t.local\t%s\n", ld_name);
}
/* calculate the alignment */
align = get_type_alignment_bytes(ty);
h = highest_bit(align);
if ((1 << h) < align)
++h;
align = (1 << h);
if (align < 1)
align = 1;
obstack_printf(comm_obstack, "\t.comm\t%s,%d,%d\n", ld_name, (get_type_size_bits(ty) + 7) >> 3, align);
}
}
}
/*
* Dumps declarations of global variables and the initialization code.
*/
void arm_dump_globals(struct obstack *rdata_obstack, struct obstack *data_obstack, struct obstack *comm_obstack)
{
ir_type *gt = get_glob_type();
int i, n = get_class_n_members(gt);
for (i = 0; i < n; i++)
dump_global(rdata_obstack, data_obstack, comm_obstack, get_class_member(gt, i));
}
/************************************************************************/
void arm_gen_decls(FILE *out) {
struct obstack rodata, data, comm;
int size;
char *cp;
obstack_init(&rodata);
obstack_init(&data);
obstack_init(&comm);
arm_dump_globals(&rodata, &data, &comm);
size = obstack_object_size(&data);
cp = obstack_finish(&data);
if (size > 0) {
fprintf(out, "\t.data\n");
fwrite(cp, 1, size, out);
}
size = obstack_object_size(&rodata);
cp = obstack_finish(&rodata);
if (size > 0) {
fprintf(out, "\t.section\t.rodata\n");
fwrite(cp, 1, size, out);
}
size = obstack_object_size(&comm);
cp = obstack_finish(&comm);
if (size > 0) {
fprintf(out, "\t.common\n");
fwrite(cp, 1, size, out);
}
obstack_free(&rodata, NULL);
obstack_free(&data, NULL);