Commit 72fca46d authored by Matthias Braun's avatar Matthias Braun
Browse files

modernize TEMPLATE backend and simplify some backend APIs

[r27460]
parent 523e83e3
......@@ -38,6 +38,8 @@
#include "../besched.h"
#include "../begnuas.h"
#include "../beblocksched.h"
#include "../benode.h"
#include "TEMPLATE_emitter.h"
#include "gen_TEMPLATE_emitter.h"
......@@ -113,8 +115,8 @@ static const arch_register_t *get_out_reg(const ir_node *node, int pos)
void TEMPLATE_emit_immediate(const ir_node *node)
{
(void) node;
/* TODO */
const TEMPLATE_attr_t *attr = get_irn_generic_attr_const(node);
be_emit_tarval(attr->value);
}
void TEMPLATE_emit_source_register(const ir_node *node, int pos)
......@@ -151,38 +153,77 @@ static void TEMPLATE_emit_cfop_target(const ir_node *node)
/**
* Emits code for a unconditional jump.
*/
static void emit_Jmp(const ir_node *node)
static void emit_TEMPLATE_Jmp(const ir_node *node)
{
be_emit_cstring("\tjmp ");
TEMPLATE_emit_cfop_target(node);
be_emit_finish_line_gas(node);
}
static void emit_be_IncSP(const ir_node *node)
{
int offset = be_get_IncSP_offset(node);
if (offset == 0)
return;
/* downwards growing stack */
if (offset > 0) {
be_emit_cstring("\tsub ");
} else {
be_emit_cstring("\tadd ");
offset = -offset;
}
TEMPLATE_emit_source_register(node, 0);
be_emit_irprintf(", %d, ", offset);
TEMPLATE_emit_dest_register(node, 0);
be_emit_finish_line_gas(node);
}
static void emit_be_Return(const ir_node *node)
{
be_emit_cstring("\tret");
be_emit_finish_line_gas(node);
}
static void emit_nothing(const ir_node *node)
{
(void) node;
}
/**
* The type of a emitter function.
*/
typedef void (emit_func)(const ir_node *node);
static inline void set_emitter(ir_op *op, emit_func func)
{
op->ops.generic = (op_func)func;
}
/**
* Enters the emitter functions for handled nodes into the generic
* pointer of an opcode.
*/
static void TEMPLATE_register_emitters(void)
{
/* some convienience macros to register additional emitter functions
(other than the generated ones) */
#define TEMPLATE_EMIT(a) op_TEMPLATE_##a->ops.generic = (op_func)emit_TEMPLATE_##a
#define EMIT(a) op_##a->ops.generic = (op_func)emit_##a
#define BE_EMIT(a) op_be_##a->ops.generic = (op_func)emit_be_##a
/* first clear the generic function pointer for all ops */
clear_irp_opcodes_generic_func();
/* register all emitter functions defined in spec */
TEMPLATE_register_spec_emitters();
/* register addtional emitter functions if needed */
EMIT(Jmp);
/* custom emitters not provided by the spec */
set_emitter(op_TEMPLATE_Jmp, emit_TEMPLATE_Jmp);
set_emitter(op_be_Return, emit_be_Return);
set_emitter(op_be_IncSP, emit_be_IncSP);
#undef TEMPLATE_EMIT
#undef BE_EMIT
#undef EMIT
/* no need to emit anything for the following nodes */
set_emitter(op_Phi, emit_nothing);
set_emitter(op_be_Keep, emit_nothing);
set_emitter(op_be_Start, emit_nothing);
set_emitter(op_be_Barrier, emit_nothing);
}
typedef void (*emit_func_ptr) (const ir_node *);
......@@ -206,13 +247,9 @@ static void TEMPLATE_emit_node(const ir_node *node)
* Walks over the nodes in a block connected by scheduling edges
* and emits code for each node.
*/
static void TEMPLATE_gen_block(ir_node *block, void *data)
static void TEMPLATE_emit_block(ir_node *block)
{
ir_node *node;
(void) data;
if (! is_Block(block))
return;
be_gas_emit_block_name(block);
be_emit_cstring(":\n");
......@@ -223,35 +260,6 @@ static void TEMPLATE_gen_block(ir_node *block, void *data)
}
}
/**
* Emits code for function start.
*/
static void TEMPLATE_emit_func_prolog(ir_graph *irg)
{
const char *irg_name = get_entity_name(get_irg_entity(irg));
/* TODO: emit function header */
be_emit_cstring("/* start of ");
be_emit_string(irg_name);
be_emit_cstring(" */\n");
be_emit_write_line();
}
/**
* Emits code for function end
*/
static void TEMPLATE_emit_func_epilog(ir_graph *irg)
{
const char *irg_name = get_entity_name(get_irg_entity(irg));
/* TODO: emit function end */
be_emit_cstring("/* end of ");
be_emit_string(irg_name);
be_emit_cstring(" */\n");
be_emit_write_line();
}
/**
* Sets labels for control flow nodes (jump target)
*/
......@@ -270,15 +278,29 @@ static void TEMPLATE_gen_labels(ir_node *block, void *env)
/**
* Main driver
*/
void TEMPLATE_gen_routine(const TEMPLATE_code_gen_t *cg, ir_graph *irg)
void TEMPLATE_emit_routine(ir_graph *irg)
{
(void)cg;
ir_node **block_schedule;
ir_entity *entity = get_irg_entity(irg);
int i;
int n;
/* register all emitter functions */
TEMPLATE_register_emitters();
TEMPLATE_emit_func_prolog(irg);
/* create the block schedule */
block_schedule = be_create_block_schedule(irg);
/* emit assembler prolog */
be_gas_emit_function_prolog(entity, 4);
/* populate jump link fields with their destinations */
irg_block_walk_graph(irg, TEMPLATE_gen_labels, NULL, NULL);
irg_walk_blkwise_graph(irg, NULL, TEMPLATE_gen_block, NULL);
TEMPLATE_emit_func_epilog(irg);
n = ARR_LEN(block_schedule);
for (i = 0; i < n; ++i) {
ir_node *block = block_schedule[i];
TEMPLATE_emit_block(block);
}
be_gas_emit_function_epilog(entity);
}
......@@ -38,10 +38,6 @@ void TEMPLATE_emit_source_register(const ir_node *node, int pos);
void TEMPLATE_emit_dest_register(const ir_node *node, int pos);
void TEMPLATE_emit_immediate(const ir_node *node);
int get_TEMPLATE_reg_nr(ir_node *irn, int posi, int in_out);
const char *get_TEMPLATE_in_reg_name(ir_node *irn, int pos);
void TEMPLATE_gen_routine(const TEMPLATE_code_gen_t *cg, ir_graph *irg);
void TEMPLATE_emit_routine(ir_graph *irg);
#endif
......@@ -147,6 +147,12 @@ static void init_TEMPLATE_attributes(ir_node *node, arch_irn_flags_t flags,
memset(info->out_infos, 0, n_res * sizeof(info->out_infos[0]));
}
static void set_TEMPLATE_value(ir_node *node, tarval *value)
{
TEMPLATE_attr_t *attr = get_TEMPLATE_attr(node);
attr->value = value;
}
static int TEMPLATE_compare_attr(ir_node *a, ir_node *b)
{
const TEMPLATE_attr_t *attr_a = get_TEMPLATE_attr_const(a);
......
......@@ -31,6 +31,8 @@ typedef struct TEMPLATE_attr_t TEMPLATE_attr_t;
struct TEMPLATE_attr_t
{
tarval *value;
const arch_register_req_t **in_req; /**< register requirements for arguments */
const arch_register_req_t **out_req; /**< register requirements for results */
};
......
......@@ -5,6 +5,12 @@
$arch = "TEMPLATE";
#
# Modes
#
$mode_gp = "mode_Iu"; # mode used by general purpose registers
$mode_fp = "mode_E"; # mode used by floatingpoint registers
# The node description is done as a perl hash initializer with the
# following structure:
#
......@@ -114,7 +120,7 @@ $arch = "TEMPLATE";
{ name => "r13", type => 2 },
{ name => "sp", realname => "r14", type => 4 }, # stackpointer
{ name => "bp", realname => "r15", type => 4 }, # basepointer
{ mode => "mode_Iu" }
{ mode => $mode_gp }
],
fp => [
{ name => "f0", type => 1 },
......@@ -133,7 +139,7 @@ $arch = "TEMPLATE";
{ name => "f13", type => 1 },
{ name => "f14", type => 1 },
{ name => "f15", type => 1 },
{ mode => "mode_D" }
{ mode => $mode_fp }
]
);
......@@ -161,157 +167,91 @@ Add => {
op_flags => "C",
irn_flags => "R",
reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
emit => '. add %S1, %S2, %D1'
},
Add_i => {
irn_flags => "R",
reg_req => { in => [ "gp" ], out => [ "gp" ] },
emit => '. add %S1, %C, %D1'
emit => '. add %S1, %S2, %D1',
mode => $mode_gp,
},
Mul => {
op_flags => "C",
irn_flags => "R",
reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
emit =>'. mul %S1, %S2, %D1'
},
Mul_i => {
irn_flags => "R",
reg_req => { in => [ "gp" ], out => [ "gp" ] },
emit => '. mul %S1, %C, %D1'
emit =>'. mul %S1, %S2, %D1',
mode => $mode_gp,
},
And => {
op_flags => "C",
irn_flags => "R",
reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
emit => '. and %S1, %S2, %D1'
},
And_i => {
irn_flags => "R",
reg_req => { in => [ "gp" ], out => [ "gp" ] },
emit => '. and %S1, %C, %D1'
emit => '. and %S1, %S2, %D1',
mode => $mode_gp,
},
Or => {
op_flags => "C",
irn_flags => "R",
reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
emit => '. or %S1, %S2, %D1'
},
Or_i => {
op_flags => "C",
irn_flags => "R",
reg_req => { in => [ "gp" ], out => [ "gp" ] },
emit => '. or %S1, %C, %D1'
emit => '. or %S1, %S2, %D1',
mode => $mode_gp,
},
Eor => {
Xor => {
op_flags => "C",
irn_flags => "R",
reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
emit => '. xor %S1, %S2, %D1'
},
Eor_i => {
irn_flags => "R",
reg_req => { in => [ "gp" ], out => [ "gp" ] },
emit => '. xor %S1, %C, %D1'
emit => '. xor %S1, %S2, %D1',
mode => $mode_gp,
},
Sub => {
irn_flags => "R",
reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
emit => '. sub %S1, %S2, %D1'
},
Sub_i => {
irn_flags => "R",
reg_req => { in => [ "gp" ], out => [ "gp" ] },
emit => '. subl %S1, %C, %D1'
emit => '. sub %S1, %S2, %D1',
mode => $mode_gp,
},
Shl => {
irn_flags => "R",
reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
emit => '. shl %S1, %S2, %D1'
},
Shl_i => {
irn_flags => "R",
reg_req => { in => [ "gp" ], out => [ "gp" ] },
emit => '. shl %S1, %C, %D1'
emit => '. shl %S1, %S2, %D1',
mode => $mode_gp,
},
Shr => {
irn_flags => "R",
reg_req => { in => [ "gp", "gp" ], out => [ "in_r1" ] },
emit => '. shr %S2, %D1'
},
Shr_i => {
irn_flags => "R",
reg_req => { in => [ "gp" ], out => [ "gp" ] },
emit => '. shr %S1, %C, %D1'
},
RotR => {
irn_flags => "R",
reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
emit => '. ror %S1, %S2, %D1'
},
RotL => {
irn_flags => "R",
reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
emit => '. rol %S1, %S2, %D1'
},
RotL_i => {
irn_flags => "R",
reg_req => { in => [ "gp" ], out => [ "gp" ] },
emit => '. rol %S1, %C, %D1'
emit => '. shr %S2, %D1',
mode => $mode_gp,
},
Minus => {
irn_flags => "R",
reg_req => { in => [ "gp" ], out => [ "gp" ] },
emit => '. neg %S1, %D1'
},
Inc => {
irn_flags => "R",
reg_req => { in => [ "gp" ], out => [ "gp" ] },
emit => '. inc %S1, %D1'
},
Dec => {
irn_flags => "R",
reg_req => { in => [ "gp" ], out => [ "gp" ] },
emit => '. dec %S1, %D1'
emit => '. neg %S1, %D1',
mode => $mode_gp,
},
Not => {
arity => 1,
remat => 1,
reg_req => { in => [ "gp" ], out => [ "gp" ] },
emit => '. not %S1, %D1'
arity => 1,
remat => 1,
reg_req => { in => [ "gp" ], out => [ "gp" ] },
emit => '. not %S1, %D1',
mode => $mode_gp,
},
Const => {
op_flags => "c",
irn_flags => "R",
reg_req => { out => [ "gp" ] },
emit => '. mov %C, %D1',
cmp_attr =>
op_flags => "c",
irn_flags => "R",
attr => "tarval *value",
custominit => "set_TEMPLATE_value(res, value);",
reg_req => { out => [ "gp" ] },
emit => '. mov %C, %D1',
cmp_attr =>
'
/* TODO: compare Const attributes */
return 1;
'
',
mode => $mode_gp,
},
# Control Flow
......@@ -331,7 +271,7 @@ Load => {
irn_flags => "R",
state => "exc_pinned",
reg_req => { in => [ "gp", "none" ], out => [ "gp" ] },
emit => '. mov (%S1), %D1'
emit => '. mov (%S1), %D1',
},
Store => {
......@@ -339,7 +279,7 @@ Store => {
irn_flags => "R",
state => "exc_pinned",
reg_req => { in => [ "gp", "gp", "none" ] },
emit => '. movl %S2, (%S1)'
emit => '. movl %S2, (%S1)',
},
# Floating Point operations
......@@ -348,44 +288,35 @@ fAdd => {
op_flags => "C",
irn_flags => "R",
reg_req => { in => [ "fp", "fp" ], out => [ "fp" ] },
emit => '. fadd %S1, %S2, %D1'
emit => '. fadd %S1, %S2, %D1',
mode => $mode_fp,
},
fMul => {
op_flags => "C",
reg_req => { in => [ "fp", "fp" ], out => [ "fp" ] },
emit =>'. fmul %S1, %S2, %D1'
},
fMax => {
op_flags => "C",
irn_flags => "R",
reg_req => { in => [ "fp", "fp" ], out => [ "fp" ] },
emit =>'. fmax %S1, %S2, %D1'
},
fMin => {
op_flags => "C",
irn_flags => "R",
reg_req => { in => [ "fp", "fp" ], out => [ "fp" ] },
emit =>'. fmin %S1, %S2, %D1'
emit =>'. fmul %S1, %S2, %D1',
mode => $mode_fp,
},
fSub => {
irn_flags => "R",
reg_req => { in => [ "fp", "fp" ], out => [ "fp" ] },
emit => '. fsub %S1, %S2, %D1'
emit => '. fsub %S1, %S2, %D1',
mode => $mode_fp,
},
fDiv => {
reg_req => { in => [ "fp", "fp" ], out => [ "fp" ] },
emit => '. fdiv %S1, %S2, %D1'
emit => '. fdiv %S1, %S2, %D1',
mode => $mode_fp,
},
fMinus => {
irn_flags => "R",
reg_req => { in => [ "fp" ], out => [ "fp" ] },
emit => '. fneg %S1, %D1'
emit => '. fneg %S1, %D1',
mode => $mode_fp,
},
fConst => {
......@@ -397,7 +328,8 @@ fConst => {
'
/* TODO: compare fConst attributes */
return 1;
'
',
mode => $mode_fp,
},
# Load / Store
......@@ -407,7 +339,7 @@ fLoad => {
irn_flags => "R",
state => "exc_pinned",
reg_req => { in => [ "gp", "none" ], out => [ "fp" ] },
emit => '. fmov (%S1), %D1'
emit => '. fmov (%S1), %D1',
},
fStore => {
......@@ -415,7 +347,7 @@ fStore => {
irn_flags => "R",
state => "exc_pinned",
reg_req => { in => [ "gp", "fp", "none" ] },
emit => '. fmov %S2, (%S1)'
emit => '. fmov %S2, (%S1)',
},
);
......@@ -33,8 +33,10 @@
#include "ircons.h"
#include "iropt_t.h"
#include "debug.h"
#include "error.h"
#include "../benode.h"
#include "../betranshlp.h"
#include "bearch_TEMPLATE_t.h"
#include "TEMPLATE_nodes_attr.h"
......@@ -45,359 +47,271 @@
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
/**
* 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)
typedef ir_node* (*new_binop_func)(dbg_info *dbgi, ir_node *block,
ir_node *left, ir_node *right);
static ir_node *transform_binop(ir_node *node, new_binop_func new_func)
{
return new_bd_TEMPLATE_Add(env->dbg, env->block, op1, op2, env->mode);
ir_node *block = get_nodes_block(node);
ir_node *new_block = be_transform_node(block);
dbg_info *dbgi = get_irn_dbg_info(node);
ir_node *left = get_binop_left(node);
ir_node *new_left = be_transform_node(left);
ir_node *right = get_binop_right(node);
ir_node *new_right = be_transform_node(right);
return new_func(dbgi, new_block, new_left, new_right);
}
/**
* 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)
static ir_node *gen_And(ir_node *node)
{
if (mode_is_float(env->mode)) {
return new_bd_TEMPLATE_fMul(env->dbg, env->block, op1, op2, env->mode);
} else {
return new_bd_TEMPLATE_Mul(env->dbg, env->block, op1, op2, env->mode);
}
return transform_binop(node, new_bd_TEMPLATE_And);
}