Commit 17e47394 authored by Christian Würdig's avatar Christian Würdig
Browse files

finished TEMPLATE backend

parent 1afa952f
/* TEMPLATE emitter */
/* $Id$ */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
......@@ -170,7 +173,7 @@ static int TEMPLATE_get_reg_name(lc_appendable_t *app,
}
/**
* Returns the tarval or offset of an ia32 as a string.
* Returns the tarval or offset of an TEMPLATE node as a string.
*/
static int TEMPLATE_const_to_str(lc_appendable_t *app,
const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
......@@ -209,52 +212,35 @@ static int TEMPLATE_get_mode_suffix(lc_appendable_t *app,
}
/**
* Return the ia32 printf arg environment.
* Return the TEMPLATE printf arg environment.
* We use the firm environment with some additional handlers.
*/
const lc_arg_env_t *TEMPLATE_get_arg_env(void) {
static lc_arg_env_t *env = NULL;
static const lc_arg_handler_t ia32_reg_handler = { ia32_get_arg_type, ia32_get_reg_name };
static const lc_arg_handler_t ia32_const_handler = { ia32_get_arg_type, ia32_const_to_str };
static const lc_arg_handler_t ia32_mode_handler = { ia32_get_arg_type, ia32_get_mode_suffix };
static const lc_arg_handler_t TEMPLATE_reg_handler = { TEMPLATE_get_arg_type, TEMPLATE_get_reg_name };
static const lc_arg_handler_t TEMPLATE_const_handler = { TEMPLATE_get_arg_type, TEMPLATE_const_to_str };
static const lc_arg_handler_t TEMPLATE_mode_handler = { TEMPLATE_get_arg_type, TEMPLATE_get_mode_suffix };
if(env == NULL) {
/* extend the firm printer */
env = firm_get_arg_env();
//lc_arg_new_env();
lc_arg_register(env, "ia32:sreg", 'S', &ia32_reg_handler);
lc_arg_register(env, "ia32:dreg", 'D', &ia32_reg_handler);
lc_arg_register(env, "ia32:cnst", 'C', &ia32_const_handler);
lc_arg_register(env, "ia32:offs", 'O', &ia32_const_handler);
lc_arg_register(env, "ia32:mode", 'M', &ia32_mode_handler);
lc_arg_register(env, "TEMPLATE:sreg", 'S', &TEMPLATE_reg_handler);
lc_arg_register(env, "TEMPLATE:dreg", 'D', &TEMPLATE_reg_handler);
lc_arg_register(env, "TEMPLATE:cnst", 'C', &TEMPLATE_const_handler);
lc_arg_register(env, "TEMPLATE:offs", 'O', &TEMPLATE_const_handler);
lc_arg_register(env, "TEMPLATE:mode", 'M', &TEMPLATE_mode_handler);
}
return env;
}
/**
* For 2-address code we need to make sure the first src reg is equal to dest reg.
*/
void equalize_dest_src(FILE *F, ir_node *n) {
if (get_ia32_reg_nr(n, 0, 1) != get_ia32_reg_nr(n, 0, 0)) {
if (get_irn_arity(n) > 1 && get_ia32_reg_nr(n, 1, 1) == get_ia32_reg_nr(n, 0, 0)) {
if (! is_op_commutative(get_irn_op(n))) {
/* we only need to exchange for non-commutative ops */
lc_efprintf(ia32_get_arg_env(), F, "\txchg %1S, %2S\t\t\t/* xchg src1 <-> src2 for 2 address code */\n", n, n);
}
}
else {
lc_efprintf(ia32_get_arg_env(), F, "\tmovl %1S, %1D\t\t\t/* src -> dest for 2 address code */\n", n, n);
}
}
}
/*
* Add a number to a prefix. This number will not be used a second time.
*/
char *get_unique_label(char *buf, size_t buflen, const char *prefix) {
static char *get_unique_label(char *buf, size_t buflen, const char *prefix) {
static unsigned long id = 0;
snprintf(buf, buflen, "%s%lu", prefix, ++id);
return buf;
......@@ -271,62 +257,6 @@ static char *get_cfop_target(const ir_node *irn, char *buf) {
return buf;
}
/*********************************************************
* _ _ _
* (_) | (_)
* ___ _ __ ___ _| |_ _ _ _ _ __ ___ _ __ ___
* / _ \ '_ ` _ \| | __| | | | | | '_ ` _ \| '_ \/ __|
* | __/ | | | | | | |_ | | |_| | | | | | | |_) \__ \
* \___|_| |_| |_|_|\__| | |\__,_|_| |_| |_| .__/|___/
* _/ | | |
* |__/ |_|
*********************************************************/
/**
* Emits code for a Switch (creates a jump table if
* possible otherwise a cmp-jmp cascade).
*/
void emit_TEMPLATE_Switch(const ir_node *irn, emit_env_t *emit_env) {
unsigned long interval;
jmp_tbl_t *tbl;
ir_node **cases;
int def_projnum;
int do_jmp_tbl = 1;
const lc_arg_env_t *env = ia32_get_arg_env();
FILE *F = emit_env->out;
/* TODO: */
/* - create list of projs, each corresponding to one switch case */
/* - determine the projnumber of the default case */
tbl = create_jump_table(cases, def_projnum, "JMPTBL_");
/* two-complement's magic make this work without overflow */
interval = tbl.max_value - tbl.min_value;
/* check value interval: do not create jump table if interval is too large */
if (interval > 16 * 1024) {
do_jmp_tbl = 0;
}
/* check ratio of value interval to number of branches */
if (((float)(interval + 1) / (float)tbl.num_branches) > 8.0) {
do_jmp_tbl = 0;
}
if (do_jmp_tbl) {
/* TODO: emit table code */
}
else {
/* TODO: emit cmp - jmp cascade */
}
if (tbl.label)
free(tbl.label);
if (tbl.branches)
free(tbl.branches);
}
/***********************************************************************************
......@@ -351,10 +281,6 @@ void TEMPLATE_emit_node(ir_node *irn, void *env) {
#define BE_EMIT(a) if (is_TEMPLATE_##a(irn)) { emit_TEMPLATE_##a(irn, emit_env); return; }
/* generated int emitter functions */
BE_EMIT(Copy);
BE_EMIT(Perm);
BE_EMIT(Const);
BE_EMIT(Add);
......@@ -403,9 +329,6 @@ void TEMPLATE_emit_node(ir_node *irn, void *env) {
BE_EMIT(fLoad);
BE_EMIT(fStore);
/* other emitter functions */
// BE_EMIT(Switch);
ir_fprintf(F, "\t\t\t\t\t/* %+F */\n", irn);
}
......@@ -461,7 +384,7 @@ void TEMPLATE_gen_labels(ir_node *block, void *env) {
/**
* Main driver
*/
void TEMPLATE_gen_routine(FILE *F, ir_graph *irg, const ia32_code_gen_t *cg) {
void TEMPLATE_gen_routine(FILE *F, ir_graph *irg, const TEMPLATE_code_gen_t *cg) {
emit_env_t emit_env;
emit_env.mod = firm_dbg_register("firm.be.TEMPLATE.emit");
......
/**
* Dumps global variables and constants as TEMPLATE assembler.
* @author Christian Wuerdig
* @date 14.02.2006
* @version $Id$
*/
......
/**
* Register mapping for firm nodes. Stolen from bearch_firm :)
* $Id$
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include "TEMPLATE_map_regs.h"
#include "TEMPLATE_new_nodes.h"
/* Mapping to store registers in firm nodes */
struct TEMPLATE_irn_reg_assoc {
const ir_node *irn;
const arch_register_t *reg;
};
int TEMPLATE_cmp_irn_reg_assoc(const void *a, const void *b, size_t len) {
const struct TEMPLATE_irn_reg_assoc *x = a;
const struct TEMPLATE_irn_reg_assoc *y = b;
return x->irn != y->irn;
}
static struct TEMPLATE_irn_reg_assoc *get_irn_reg_assoc(const ir_node *irn, set *reg_set) {
struct TEMPLATE_irn_reg_assoc templ;
unsigned int hash;
templ.irn = irn;
templ.reg = NULL;
hash = HASH_PTR(irn);
return set_insert(reg_set, &templ, sizeof(templ), hash);
}
void TEMPLATE_set_firm_reg(ir_node *irn, const arch_register_t *reg, set *reg_set) {
struct TEMPLATE_irn_reg_assoc *assoc = get_irn_reg_assoc(irn, reg_set);
assoc->reg = reg;
}
const arch_register_t *TEMPLATE_get_firm_reg(const ir_node *irn, set *reg_set) {
struct TEMPLATE_irn_reg_assoc *assoc = get_irn_reg_assoc(irn, reg_set);
return assoc->reg;
}
/**
* Translates the projnum into a "real" argument position for register
* requirements dependend on the predecessor.
*/
long TEMPLATE_translate_proj_pos(const ir_node *proj) {
ir_node *pred = get_Proj_pred(proj);
long nr = get_Proj_proj(proj);
if (is_TEMPLATE_Load(pred)) {
if (nr == pn_Load_res)
return 0;
assert(0 && "unsupported Proj(Load) number");
}
else if (is_TEMPLATE_Store(pred)) {
return 0;
}
else if (is_TEMPLATE_fDiv(pred)) {
if (nr == pn_Quot_res)
return 0;
else
assert(0 && "there should be no more Projs for a fDiv");
}
// assert(0 && "unsupported Proj(X)");
return nr;
}
#ifndef _TEMPLATE_MAP_REGS_H_
#define _TEMPLATE_MAP_REGS_H_
#include "irnode.h"
#include "set.h"
#include "../bearch.h"
#include "TEMPLATE_nodes_attr.h"
int TEMPLATE_cmp_irn_reg_assoc(const void *a, const void *b, size_t len);
void TEMPLATE_set_firm_reg(ir_node *irn, const arch_register_t *reg, set *reg_set);
const arch_register_t *TEMPLATE_get_firm_reg(const ir_node *irn, set *reg_set);
long TEMPLATE_translate_proj_pos(const ir_node *proj);
#endif /* _TEMPLATE_MAP_REGS_H_ */
......@@ -7,6 +7,12 @@
#include "config.h"
#endif
#ifdef _WIN32
#include <malloc.h>
#else
#include <alloca.h>
#endif
#include <stdlib.h>
#include "irprog_t.h"
......@@ -18,6 +24,7 @@
#include "irop.h"
#include "firm_common_t.h"
#include "irvrfy_t.h"
#include "irprintf.h"
#include "../bearch.h"
......@@ -38,6 +45,82 @@
* |_|
***********************************************************************************/
/**
* Returns a string containing the names of all registers within the limited bitset
*/
static char *get_limited_regs(const arch_register_req_t *req, char *buf, int max) {
bitset_t *bs = bitset_alloca(req->cls->n_regs);
char *p = buf;
int size = 0;
int i, cnt;
req->limited(NULL, bs);
for (i = 0; i < req->cls->n_regs; i++) {
if (bitset_is_set(bs, i)) {
cnt = snprintf(p, max - size, " %s", req->cls->regs[i].name);
if (cnt < 0) {
fprintf(stderr, "dumper problem, exiting\n");
exit(1);
}
p += cnt;
size += cnt;
if (size >= max)
break;
}
}
return buf;
}
/**
* Dumps the register requirements for either in or out.
*/
static void dump_reg_req(FILE *F, ir_node *n, const TEMPLATE_register_req_t **reqs, int inout) {
char *dir = inout ? "out" : "in";
int max = inout ? get_TEMPLATE_n_res(n) : get_irn_arity(n);
char *buf = alloca(1024);
int i;
memset(buf, 0, 1024);
if (reqs) {
for (i = 0; i < max; i++) {
fprintf(F, "%sreq #%d =", dir, i);
if (reqs[i]->req.type == arch_register_req_type_none) {
fprintf(F, " n/a");
}
if (reqs[i]->req.type & arch_register_req_type_normal) {
fprintf(F, " %s", reqs[i]->req.cls->name);
}
if (reqs[i]->req.type & arch_register_req_type_limited) {
fprintf(F, " %s", get_limited_regs(&reqs[i]->req, buf, 1024));
}
if (reqs[i]->req.type & arch_register_req_type_should_be_same) {
ir_fprintf(F, " same as %+F", get_irn_n(n, reqs[i]->same_pos));
}
if (reqs[i]->req.type & arch_register_req_type_should_be_different) {
ir_fprintf(F, " different from %+F", get_irn_n(n, reqs[i]->different_pos));
}
fprintf(F, "\n");
}
fprintf(F, "\n");
}
else {
fprintf(F, "%sreq = N/A\n", dir);
}
}
/**
* Dumper interface for dumping TEMPLATE nodes in vcg.
* @param n the node to dump
......@@ -46,80 +129,50 @@
* @return 0 on success or != 0 on failure
*/
static int dump_node_TEMPLATE(ir_node *n, FILE *F, dump_reason_t reason) {
const char *name, *p;
ir_mode *mode = NULL;
int bad = 0;
int i;
ir_mode *mode = NULL;
int bad = 0;
int i;
TEMPLATE_attr_t *attr;
const TEMPLATE_register_req_t **reqs;
const arch_register_t **slots;
const arch_register_t **slots;
switch (reason) {
case dump_node_opcode_txt:
name = get_irn_opname(n);
fprintf(F, "%s", name);
fprintf(F, "%s", get_irn_opname(n));
break;
case dump_node_mode_txt:
mode = get_irn_mode(n);
if (mode == mode_BB || mode == mode_ANY || mode == mode_BAD || mode == mode_T) {
mode = NULL;
}
if (mode) {
fprintf(F, "[%s]", get_mode_name(mode));
}
else {
fprintf(F, "[?NOMODE?]");
}
break;
case dump_node_nodeattr_txt:
/* TODO: Dump node specific attributes which should */
/* visible in node name (e.g. const or the like). */
/* TODO: dump some attributes which should show up */
/* in node name in dump (e.g. consts or the like) */
break;
case dump_node_info_txt:
attr = get_TEMPLATE_attr(n);
fprintf(F, "=== TEMPLATE attr begin ===\n");
/* dump IN requirements */
if (get_irn_arity(n) > 0) {
reqs = get_TEMPLATE_in_req_all(n);
if (reqs) {
for (i = 0; i < get_irn_arity(n); i++) {
if (reqs[i]->req.type != arch_register_req_type_none) {
fprintf(F, "in req #%d = [%s]\n", i, reqs[i]->req.cls->name);
}
else {
fprintf(F, "in req #%d = n/a\n", i);
}
}
fprintf(F, "\n");
}
else {
fprintf(F, "in req = N/A\n");
}
dump_reg_req(F, n, reqs, 0);
}
/* dump OUT requirements */
if (attr->n_res > 0) {
reqs = get_TEMPLATE_out_req_all(n);
if (reqs) {
for (i = 0; i < attr->n_res; i++) {
if (reqs[i]->req.type != arch_register_req_type_none) {
fprintf(F, "out req #%d = [%s]\n", i, reqs[i]->req.cls->name);
}
else {
fprintf(F, "out req #%d = n/a\n", i);
}
}
}
else {
fprintf(F, "out req = N/A\n");
}
dump_reg_req(F, n, reqs, 1);
}
/* dump assigned registers */
......@@ -134,10 +187,37 @@ static int dump_node_TEMPLATE(ir_node *n, FILE *F, dump_reason_t reason) {
}
}
}
fprintf(F, "\n");
/* dump n_res */
fprintf(F, "n_res = %d\n", get_TEMPLATE_n_res(n));
/* dump flags */
fprintf(F, "flags =");
if (attr->flags == arch_irn_flags_none) {
fprintf(F, " none");
}
else {
if (attr->flags & arch_irn_flags_dont_spill) {
fprintf(F, " unspillable");
}
if (attr->flags & arch_irn_flags_rematerializable) {
fprintf(F, " remat");
}
if (attr->flags & arch_irn_flags_ignore) {
fprintf(F, " ignore");
}
}
fprintf(F, " (%d)\n", attr->flags);
/* TODO: dump all additional attributes */
fprintf(F, "=== TEMPLATE attr end ===\n");
/* end of: case dump_node_info_txt */
break;
}
return bad;
}
......
......@@ -22,7 +22,7 @@
/**
* Returns the attributes of an TEMPLATE node.
*/
TEMPLATE_attr *get_TEMPLATE_attr(const ir_node *node);
TEMPLATE_attr_t *get_TEMPLATE_attr(const ir_node *node);
/**
* Returns the argument register requirements of an TEMPLATE node.
......
......@@ -5,7 +5,8 @@
typedef struct _TEMPLATE_register_req_t {
const arch_register_req_t req;
int pos; /**<< in case of "should be same/different" we need to remember the pos to get the irn */
int same_pos; /**<< in case of "should be same" we need to remember the pos to get the irn */
int different_pos; /**<< in case of "should be different" we need to remember the pos to get the irn */
} TEMPLATE_register_req_t;
......
This diff is collapsed.
/* The codegenrator (transform FIRM into TEMPLATE FIRM */
/* $Id$ */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "irnode_t.h"
#include "irgraph_t.h"
#include "irmode_t.h"
#include "irgmod.h"
#include "iredges.h"
#include "irvrfy.h"
#include "ircons.h"
#include "dbginfo.h"
#include "iropt_t.h"
#include "debug.h"
#include "../benode_t.h"
#include "bearch_TEMPLATE_t.h"
#include "TEMPLATE_nodes_attr.h"
#include "../arch/archop.h" /* we need this for Min and Max nodes */
#include "TEMPLATE_transform.h"
#include "TEMPLATE_new_nodes.h"
#include "TEMPLATE_map_regs.h"
#include "gen_TEMPLATE_regalloc_if.h"
extern ir_op *get_op_Mulh(void);
/****************************************************************************************************
* _ _ __ _ _
* | | | | / _| | | (_)
* _ __ ___ __| | ___ | |_ _ __ __ _ _ __ ___| |_ ___ _ __ _ __ ___ __ _| |_ _ ___ _ __
* | '_ \ / _ \ / _` |/ _ \ | __| '__/ _` | '_ \/ __| _/ _ \| '__| '_ ` _ \ / _` | __| |/ _ \| '_ \
* | | | | (_) | (_| | __/ | |_| | | (_| | | | \__ \ || (_) | | | | | | | | (_| | |_| | (_) | | | |
* |_| |_|\___/ \__,_|\___| \__|_| \__,_|_| |_|___/_| \___/|_| |_| |_| |_|\__,_|\__|_|\___/|_| |_|
*
****************************************************************************************************/
/**
* Creates an TEMPLATE Add.
*
* @param env The transformation environment
* @param op1 first operator
* @param op2 second operator
* @return the created TEMPLATE Add node
*/
static ir_node *gen_Add(TEMPLATE_transform_env_t *env, ir_node *op1, ir_node *op2) {
return new_rd_TEMPLATE_Add(env->dbg, env->irg, env->block, op1, op2, env->mode);
}
/**
* Creates an TEMPLATE Mul.
*
* @param dbg firm node dbg
* @param block the block the new node should belong to
* @param op1 first operator
* @param op2 second operator
* @param mode node mode
* @return the created TEMPLATE Mul node
*/
static ir_node *gen_Mul(TEMPLATE_transform_env_t *env, ir_node *op1, ir_node *op2) {
if (mode_is_float(env->mode)) {
return new_rd_TEMPLATE_fMul(env->dbg, env->irg, env->block, op1, op2, env->mode);
}
else {
return new_rd_TEMPLATE_Mul(env->dbg, env->irg, env->block, op1, op2, env->mode);
}
}
/**
* Creates an TEMPLATE And.
*
* @param dbg firm node dbg
* @param block the block the new node should belong to
* @param op1 first operator
* @param op2 second operator