Commit 0d3ffb21 authored by Christian Würdig's avatar Christian Würdig
Browse files

code cleanups

fixed some bugs
added sub -> neg-add transformation in case OUT==IN2
parent 3c42b8dc
......@@ -286,6 +286,7 @@ static void ia32_prepare_graph(void *self) {
/**
* Insert copies for all ia32 nodes where the should_be_same requirement
* is not fulfilled.
* Transform Sub into Neg -- Add if IN2 == OUT
*/
static void ia32_finish_irg_walker(ir_node *irn, void *env) {
ia32_code_gen_t *cg = env;
......@@ -331,6 +332,9 @@ static void ia32_finish_irg_walker(ir_node *irn, void *env) {
}
}
}
/* check if there is a sub which need to be transformed */
ia32_transform_sub_to_neg_add(irn, cg);
}
/**
......
......@@ -44,147 +44,6 @@ extern int obstack_printf(struct obstack *obst, char *fmt, ...);
static const arch_env_t *arch_env = NULL;
/**
* Emits registers and/or address mode of a binary operation.
*/
char *ia32_emit_binop(const ir_node *n) {
static char *buf = NULL;
/* verify that this function is never called on non-AM supporting operations */
assert(get_ia32_am_support(n) != ia32_am_None && "emit binop expects addressmode support");
if (! buf) {
buf = xcalloc(1, SNPRINTF_BUF_LEN);
}
else {
memset(buf, 0, SNPRINTF_BUF_LEN);
}
switch(get_ia32_op_type(n)) {
case ia32_Normal:
if (get_ia32_cnst(n)) {
lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%3S, %s", n, get_ia32_cnst(n));
}
else {
lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%3S,%4S", n, n);
}
break;
case ia32_AddrModeS:
lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%4S, %s", n, ia32_emit_am(n));
break;
case ia32_AddrModeD:
if (get_ia32_cnst(n)) {
lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s, %s", ia32_emit_am(n), get_ia32_cnst(n));
}
else {
lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s, %3S", ia32_emit_am(n), n);
}
break;
default:
assert(0 && "unsupported op type");
}
return buf;
}
/**
* Emits registers and/or address mode of a unary operation.
*/
char *ia32_emit_unop(const ir_node *n) {
static char *buf = NULL;
if (! buf) {
buf = xcalloc(1, SNPRINTF_BUF_LEN);
}
else {
memset(buf, 0, SNPRINTF_BUF_LEN);
}
switch(get_ia32_op_type(n)) {
case ia32_Normal:
lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%1D", n);
break;
case ia32_am_Dest:
snprintf(buf, SNPRINTF_BUF_LEN, ia32_emit_am(n));
break;
default:
assert(0 && "unsupported op type");
}
return buf;
}
/**
* Emits adressmode.
*/
char *ia32_emit_am(const ir_node *n) {
ia32_am_flavour_t am_flav = get_ia32_am_flavour(n);
int had_output = 0;
char *s;
int size;
static struct obstack *obst = NULL;
ir_mode *mode = get_ia32_ls_mode(n);
if (! is_ia32_Lea(n))
assert(mode && "AM node must have ls_mode attribute set.");
if (! obst) {
obst = xcalloc(1, sizeof(*obst));
}
else {
obstack_free(obst, NULL);
}
/* obstack_free with NULL results in an uninitialized obstack */
obstack_init(obst);
if (mode) {
switch (get_mode_size_bits(mode)) {
case 8:
obstack_printf(obst, "BYTE PTR ");
break;
case 16:
obstack_printf(obst, "WORD PTR ");
break;
default:
break;
}
}
obstack_printf(obst, "[");
if (am_flav & ia32_B) {
lc_eoprintf(ia32_get_arg_env(), obst, "%1S", n);
had_output = 1;
}
if (am_flav & ia32_I) {
if (had_output) {
obstack_printf(obst, "+");
}
lc_eoprintf(ia32_get_arg_env(), obst, "%2S", n);
if (am_flav & ia32_S) {
obstack_printf(obst, "*%d", 1 << get_ia32_am_scale(n));
}
had_output = 1;
}
if (am_flav & ia32_O) {
obstack_printf(obst, get_ia32_am_offs(n));
}
obstack_printf(obst, "] ");
size = obstack_object_size(obst);
s = obstack_finish(obst);
s[size - 1] = '\0';
return s;
}
/*************************************************************
* _ _ __ _ _
* (_) | | / _| | | | |
......@@ -372,8 +231,159 @@ const lc_arg_env_t *ia32_get_arg_env(void) {
return env;
}
/**
* Emits registers and/or address mode of a binary operation.
*/
char *ia32_emit_binop(const ir_node *n) {
static char *buf = NULL;
/*
/* verify that this function is never called on non-AM supporting operations */
assert(get_ia32_am_support(n) != ia32_am_None && "emit binop expects addressmode support");
if (! buf) {
buf = xcalloc(1, SNPRINTF_BUF_LEN);
}
else {
memset(buf, 0, SNPRINTF_BUF_LEN);
}
switch(get_ia32_op_type(n)) {
case ia32_Normal:
if (get_ia32_cnst(n)) {
lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%3S, %s", n, get_ia32_cnst(n));
}
else {
const arch_register_t *in1 = get_in_reg(n, 2);
const arch_register_t *in2 = get_in_reg(n, 3);
const arch_register_t *out = get_ia32_n_res(n) > 0 ? get_out_reg(n, 0) : NULL;
const arch_register_t *in;
in = out ? (REGS_ARE_EQUAL(out, in2) ? in1 : in2) : in2;
out = out ? out : in1;
snprintf(buf, SNPRINTF_BUF_LEN, "%s, %s", \
arch_register_get_name(out), arch_register_get_name(in));
}
break;
case ia32_AddrModeS:
lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%4S, %s", n, ia32_emit_am(n));
break;
case ia32_AddrModeD:
if (get_ia32_cnst(n)) {
lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s, %s", ia32_emit_am(n), get_ia32_cnst(n));
}
else {
lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s, %3S", ia32_emit_am(n), n);
}
break;
default:
assert(0 && "unsupported op type");
}
return buf;
}
/**
* Emits registers and/or address mode of a unary operation.
*/
char *ia32_emit_unop(const ir_node *n) {
static char *buf = NULL;
if (! buf) {
buf = xcalloc(1, SNPRINTF_BUF_LEN);
}
else {
memset(buf, 0, SNPRINTF_BUF_LEN);
}
switch(get_ia32_op_type(n)) {
case ia32_Normal:
lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%1D", n);
break;
case ia32_am_Dest:
snprintf(buf, SNPRINTF_BUF_LEN, ia32_emit_am(n));
break;
default:
assert(0 && "unsupported op type");
}
return buf;
}
/**
* Emits adress mode.
*/
char *ia32_emit_am(const ir_node *n) {
ia32_am_flavour_t am_flav = get_ia32_am_flavour(n);
int had_output = 0;
char *s;
int size;
static struct obstack *obst = NULL;
ir_mode *mode = get_ia32_ls_mode(n);
if (! is_ia32_Lea(n))
assert(mode && "AM node must have ls_mode attribute set.");
if (! obst) {
obst = xcalloc(1, sizeof(*obst));
}
else {
obstack_free(obst, NULL);
}
/* obstack_free with NULL results in an uninitialized obstack */
obstack_init(obst);
if (mode) {
switch (get_mode_size_bits(mode)) {
case 8:
obstack_printf(obst, "BYTE PTR ");
break;
case 16:
obstack_printf(obst, "WORD PTR ");
break;
default:
break;
}
}
obstack_printf(obst, "[");
if (am_flav & ia32_B) {
lc_eoprintf(ia32_get_arg_env(), obst, "%1S", n);
had_output = 1;
}
if (am_flav & ia32_I) {
if (had_output) {
obstack_printf(obst, "+");
}
lc_eoprintf(ia32_get_arg_env(), obst, "%2S", n);
if (am_flav & ia32_S) {
obstack_printf(obst, "*%d", 1 << get_ia32_am_scale(n));
}
had_output = 1;
}
if (am_flav & ia32_O) {
obstack_printf(obst, get_ia32_am_offs(n));
}
obstack_printf(obst, "] ");
size = obstack_object_size(obst);
s = obstack_finish(obst);
s[size - 1] = '\0';
return s;
}
/**
* Add a number to a prefix. This number will not be used a second time.
*/
static char *get_unique_label(char *buf, size_t buflen, const char *prefix) {
......@@ -383,6 +393,7 @@ static char *get_unique_label(char *buf, size_t buflen, const char *prefix) {
}
/*************************************************
* _ _ _
* (_) | | |
......@@ -974,9 +985,8 @@ static void ia32_emit_node(const ir_node *irn, void *env) {
void (*emit)(const ir_node *, void *) = (void (*)(const ir_node *, void *))op->ops.generic;
(*emit)(irn, env);
}
else {
ir_fprintf(F, "\t\t\t\t\t/* %+F */\n", irn);
}
ir_fprintf(F, "\t\t\t\t\t/* %+F */\n", irn);
}
/**
......
......@@ -7,6 +7,15 @@
#include "../bearch.h"
#include "ia32_nodes_attr.h"
/**
* Convenience macro to check if register <code>out<\code>
* and register <code>in<\code> are equal.
*/
#define REGS_ARE_EQUAL(out, in) \
((arch_register_get_class(out) == arch_register_get_class(in)) && \
(arch_register_get_index(out) == arch_register_get_index(in)))
int ia32_cmp_irn_reg_assoc(const void *a, const void *b, size_t len);
void ia32_set_firm_reg(ir_node *irn, const arch_register_t *reg, set *reg_set);
const arch_register_t *ia32_get_firm_reg(const ir_node *irn, set *reg_set);
......
......@@ -328,6 +328,10 @@ static int pred_is_specific_nodeblock(const ir_node *bl, const ir_node *pred,
return 0;
}
static int is_addr_candidate(const ir_node *block, const ir_node *irn) {
}
/**
* Checks if irn is a candidate for address calculation or address mode.
*
......
......@@ -424,7 +424,7 @@ $arch = "ia32";
"comment" => "construct SSE Add: Add(a, b) = Add(b, a) = a + b",
"cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "fp", "fp", "none" ], "out" => [ "in_r3 !in_r4" ] },
"emit" => '. adds%M %ia32_emit_binop\t\t\t/* SSE Add(%A1, %A2) -> %D1 */'
"emit" => '. adds%M %ia32_emit_binop\t\t\t/* SSE Add(%A3, %A4) -> %D1 */'
},
"fMul" => {
......@@ -432,7 +432,7 @@ $arch = "ia32";
"comment" => "construct SSE Mul: Mul(a, b) = Mul(b, a) = a * b",
"cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "fp", "fp", "none" ], "out" => [ "in_r3 !in_r4" ] },
"emit" => '. muls%M %ia32_emit_binop\t\t\t/* SSE Mul(%A1, %A2) -> %D1 */'
"emit" => '. muls%M %ia32_emit_binop\t\t\t/* SSE Mul(%A3, %A4) -> %D1 */'
},
"fMax" => {
......@@ -440,7 +440,7 @@ $arch = "ia32";
"comment" => "construct SSE Max: Max(a, b) = Max(b, a) = a > b ? a : b",
"cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "fp", "fp", "none" ], "out" => [ "in_r3 !in_r4" ] },
"emit" => '. maxs%M %ia32_emit_binop\t\t\t/* SSE Max(%A1, %A2) -> %D1 */'
"emit" => '. maxs%M %ia32_emit_binop\t\t\t/* SSE Max(%A3, %A4) -> %D1 */'
},
"fMin" => {
......@@ -448,7 +448,7 @@ $arch = "ia32";
"comment" => "construct SSE Min: Min(a, b) = Min(b, a) = a < b ? a : b",
"cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "fp", "fp", "none" ], "out" => [ "in_r3 !in_r4" ] },
"emit" => '. mins%M %ia32_emit_binop\t\t\t/* SSE Min(%A1, %A2) -> %D1 */'
"emit" => '. mins%M %ia32_emit_binop\t\t\t/* SSE Min(%A3, %A4) -> %D1 */'
},
"fAnd" => {
......
......@@ -24,12 +24,15 @@
#include "debug.h"
#include "../benode_t.h"
#include "../besched.h"
#include "bearch_ia32_t.h"
#include "ia32_nodes_attr.h"
#include "../arch/archop.h" /* we need this for Min and Max nodes */
#include "ia32_transform.h"
#include "ia32_new_nodes.h"
#include "ia32_map_regs.h"
#include "gen_ia32_regalloc_if.h"
......@@ -1574,6 +1577,70 @@ static ir_node *gen_FrameStore(ia32_transform_env_t *env) {
*
*********************************************************/
/**
* Transforms a Sub or fSub into Neg--Add iff OUT_REG == SRC2_REG.
* THIS FUNCTIONS MUST BE CALLED AFTER REGISTER ALLOCATION.
*/
void ia32_transform_sub_to_neg_add(ir_node *irn, ia32_code_gen_t *cg) {
ia32_transform_env_t tenv;
ir_node *in1, *in2, *noreg, *nomem, *res;
const arch_register_t *in1_reg, *in2_reg, *out_reg, **slots;
/* Return if AM node or not a Sub or fSub */
if (get_ia32_op_type(irn) != ia32_Normal || !(is_ia32_Sub(irn) || is_ia32_fSub(irn)))
return;
noreg = ia32_new_NoReg_gp(cg);
nomem = new_rd_NoMem(cg->irg);
in1 = get_irn_n(irn, 2);
in2 = get_irn_n(irn, 3);
in1_reg = arch_get_irn_register(cg->arch_env, in1);
in2_reg = arch_get_irn_register(cg->arch_env, in2);
out_reg = get_ia32_out_reg(irn, 0);
tenv.block = get_nodes_block(irn);
tenv.dbg = get_irn_dbg_info(irn);
tenv.irg = cg->irg;
tenv.irn = irn;
tenv.mod = cg->mod;
tenv.mode = get_ia32_res_mode(irn);
tenv.cg = cg;
/* in case of sub and OUT == SRC2 we can transform the sequence into neg src2 -- add */
if (REGS_ARE_EQUAL(out_reg, in2_reg)) {
/* generate the neg src2 */
res = gen_Minus(&tenv, in2);
arch_set_irn_register(cg->arch_env, res, in2_reg);
/* add to schedule */
sched_add_before(irn, res);
/* generate the add */
if (mode_is_float(tenv.mode)) {
res = new_rd_ia32_fAdd(tenv.dbg, tenv.irg, tenv.block, noreg, noreg, res, in1, nomem, mode_T);
}
else {
res = new_rd_ia32_Add(tenv.dbg, tenv.irg, tenv.block, noreg, noreg, res, in1, nomem, mode_T);
}
#ifndef NDEBUG
set_ia32_orig_node(res, get_old_node_name(&tenv));
#endif /* NDEBUG */
/* copy register */
slots = get_ia32_slots(res);
slots[0] = in2_reg;
/* add to schedule */
sched_add_before(irn, res);
/* remove the old sub */
sched_remove(irn);
/* exchange the add and the sub */
exchange(irn, res);
}
}
/**
* Transforms the given firm node (and maybe some other related nodes)
* into one or more assembler nodes.
......
#ifndef _IA32_TRANSFORM_H_
#define _IA32_TRANSFORM_H_
/**
* Transforms the given Firm node into one or more appropriate ia32 nodes.
*/
void ia32_transform_node(ir_node *node, void *env);
/**
* Transforms a Sub or fSub into Neg--Add iff OUT_REG == SRC2_REG.
* THIS FUNCTIONS MUST BE CALLED AFTER REGISTER ALLOCATION.
*/
void ia32_transform_sub_to_neg_add(ir_node *irn, ia32_code_gen_t *cg);
#endif /* _IA32_TRANSFORM_H_ */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment