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

fixed convs

parent 0210ef67
......@@ -26,6 +26,7 @@
#include "ia32_emitter.h"
#include "gen_ia32_emitter.h"
#include "gen_ia32_regalloc_if.h"
#include "ia32_nodes_attr.h"
#include "ia32_new_nodes.h"
#include "ia32_map_regs.h"
......@@ -251,6 +252,20 @@ const lc_arg_env_t *ia32_get_arg_env(void) {
return env;
}
static char *ia32_get_reg_name_for_mode(ia32_emit_env_t *env, ir_mode *mode, const arch_register_t *reg) {
switch(get_mode_size_bits(mode)) {
case 8:
return ia32_get_mapped_reg_name(env->isa->regs_8bit, reg);
case 16:
return ia32_get_mapped_reg_name(env->isa->regs_16bit, reg);
case 32:
return (char *)arch_register_get_name(reg);
default:
assert(0 && "unsupported mode size");
return NULL;
}
}
/**
* Emits registers and/or address mode of a binary operation.
*/
......@@ -304,27 +319,11 @@ char *ia32_emit_binop(const ir_node *n, ia32_emit_env_t *env) {
}
else {
const arch_register_t *in1 = get_in_reg(n, 2);
const char *reg_name;
ir_mode *mode = get_ia32_res_mode(n);
ir_mode *mode = get_ia32_res_mode(n);
mode = mode ? mode : get_ia32_ls_mode(n);
switch(get_mode_size_bits(mode)) {
case 8:
reg_name = ia32_get_mapped_reg_name(env->isa->regs_8bit, in1);
break;
case 16:
reg_name = ia32_get_mapped_reg_name(env->isa->regs_16bit, in1);
break;
case 32:
reg_name = arch_register_get_name(in1);
break;
default:
assert(0 && "unsupported mode size");
break;
}
lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s, %%%s", ia32_emit_am(n, env), reg_name);
lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s, %%%s",
ia32_emit_am(n, env), ia32_get_reg_name_for_mode(env, mode, in1));
}
break;
default:
......@@ -1007,7 +1006,7 @@ void emit_ia32_CopyB_i(const ir_node *irn, ia32_emit_env_t *emit_env) {
/**
* Emit code for conversions (I, FP), (FP, I) and (FP, FP).
*/
static void emit_ia32_Conv(const ir_node *irn, ia32_emit_env_t *emit_env) {
static void emit_ia32_Conv_with_FP(const ir_node *irn, ia32_emit_env_t *emit_env) {
FILE *F = emit_env->out;
const lc_arg_env_t *env = ia32_get_arg_env();
char *from, *to, buf[64];
......@@ -1037,18 +1036,90 @@ static void emit_ia32_Conv(const ir_node *irn, ia32_emit_env_t *emit_env) {
}
void emit_ia32_Conv_I2FP(const ir_node *irn, ia32_emit_env_t *emit_env) {
emit_ia32_Conv(irn, emit_env);
emit_ia32_Conv_with_FP(irn, emit_env);
}
void emit_ia32_Conv_FP2I(const ir_node *irn, ia32_emit_env_t *emit_env) {
emit_ia32_Conv(irn, emit_env);
emit_ia32_Conv_with_FP(irn, emit_env);
}
void emit_ia32_Conv_FP2FP(const ir_node *irn, ia32_emit_env_t *emit_env) {
emit_ia32_Conv(irn, emit_env);
emit_ia32_Conv_with_FP(irn, emit_env);
}
/**
* Emits code for an Int conversion.
*/
void emit_ia32_Conv_I2I(const ir_node *irn, ia32_emit_env_t *emit_env) {
FILE *F = emit_env->out;
const lc_arg_env_t *env = ia32_get_arg_env();
char *move_cmd, *conv_cmd;
ir_mode *src_mode, *tgt_mode;
int n, m;
char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
const arch_register_t *in_reg, *out_reg;
src_mode = is_ia32_AddrModeS(irn) ? get_ia32_ls_mode(irn) : get_irn_mode(get_irn_n(irn, 2));
tgt_mode = get_ia32_res_mode(irn);
n = get_mode_size_bits(src_mode);
m = get_mode_size_bits(tgt_mode);
if (mode_is_signed(n < m ? src_mode : tgt_mode)) {
move_cmd = "movsx";
if (n == 8 || m == 8)
conv_cmd = "cbw";
else if (n == 16 || m == 16)
conv_cmd = "cwde";
else
assert(0 && "unsupported Conv_I2I");
}
else {
move_cmd = "movzx";
conv_cmd = NULL;
}
switch(get_ia32_op_type(irn)) {
case ia32_Normal:
in_reg = get_in_reg(irn, 2);
out_reg = get_out_reg(irn, 0);
if (REGS_ARE_EQUAL(in_reg, &ia32_gp_regs[REG_EAX]) &&
REGS_ARE_EQUAL(out_reg, in_reg) &&
mode_is_signed(n < m ? src_mode : tgt_mode))
{
/* argument and result are both in EAX and */
/* signedness is ok: -> use converts */
lc_esnprintf(env, cmd_buf, SNPRINTF_BUF_LEN, "%s", conv_cmd);
}
else if (REGS_ARE_EQUAL(out_reg, in_reg) &&
! mode_is_signed(n < m ? src_mode : tgt_mode))
{
/* argument and result are in the same register */
/* and signedness is ok: -> use and with mask */
int mask = (1 << (n < m ? n : m)) - 1;
lc_esnprintf(env, cmd_buf, SNPRINTF_BUF_LEN, "and %1D, 0x%x", irn, mask);
}
else {
/* use move w/o sign extension */
lc_esnprintf(env, cmd_buf, SNPRINTF_BUF_LEN, "%s %1D, %%%s",
move_cmd, irn, ia32_get_reg_name_for_mode(emit_env, n < m ? src_mode : tgt_mode, in_reg));
}
break;
case ia32_AddrModeS:
lc_esnprintf(env, cmd_buf, SNPRINTF_BUF_LEN, "%s %1D, %s",
move_cmd, irn, ia32_emit_am(irn, emit_env));
break;
default:
assert(0 && "unsupported op type for Conv");
}
lc_esnprintf(env, cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F(%d Bit mode_%F -> %d Bit mode_%F) */",
irn, n, src_mode, m, tgt_mode);
IA32_DO_EMIT;
}
/*******************************************
* _ _
......@@ -1173,6 +1244,7 @@ static void ia32_register_emitters(void) {
IA32_EMIT(Conv_I2FP);
IA32_EMIT(Conv_FP2I);
IA32_EMIT(Conv_FP2FP);
IA32_EMIT(Conv_I2I);
/* benode emitter */
BE_EMIT(Call);
......
......@@ -156,6 +156,8 @@ $comment_string = "/*";
"cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] },
"emit" => '. add %ia32_emit_binop /* Add(%A1, %A2) -> %D1 */'
# "params" => "int a_x, int a_y",
# "init" => " attr.x = x; attr.y = y;"
},
"Mul" => {
......@@ -575,6 +577,12 @@ $comment_string = "/*";
# Conversions
"Conv_I2I" => {
"reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "gp", "none" ] },
"cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"comment" => "construct Conv Int -> Int"
},
"Conv_I2FP" => {
"reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "fp", "none" ] },
"cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
......
......@@ -1380,15 +1380,14 @@ static ir_node *gen_Mux(ia32_transform_env_t *env) {
*
* INT -> INT
* ============
* 1) n bit -> m bit n < m (upscale)
* always ignored
* 1) n bit -> m bit n > m (downscale)
* a) target is signed: movsx
* b) target is unsigned: and with lower bits sets
* 2) n bit -> m bit n == m (sign change)
* always ignored
* 3) n bit -> m bit n > m (downscale)
* a) Un -> Um = AND Un, (1 << m) - 1
* b) Sn -> Um same as a)
* c) Un -> Sm same as a)
* d) Sn -> Sm = ASHL Sn, (n - m); ASHR Sn, (n - m)
* 3) n bit -> m bit n < m (upscale)
* a) source is signed: movsx
* b) source is unsigned: and with lower bits sets
*
* INT -> FLOAT
* ==============
......@@ -1404,39 +1403,35 @@ static ir_node *gen_Mux(ia32_transform_env_t *env) {
* SSE(1/2) convert from float or double to double or float (cvtss/sd2sd/ss)
*/
static ir_node *gen_int_downscale_conv(ia32_transform_env_t *env, ir_node *op,
ir_mode *src_mode, ir_mode *tgt_mode)
{
int n = get_mode_size_bits(src_mode);
int m = get_mode_size_bits(tgt_mode);
dbg_info *dbg = env->dbg;
ir_graph *irg = env->irg;
ir_node *block = env->block;
ir_node *noreg = ia32_new_NoReg_gp(env->cg);
ir_node *nomem = new_rd_NoMem(irg);
ir_node *new_op, *proj;
assert(n > m && "downscale expected");
if (mode_is_signed(src_mode) && mode_is_signed(tgt_mode)) {
/* ASHL Sn, n - m */
new_op = new_rd_ia32_Shl(dbg, irg, block, noreg, noreg, op, noreg, nomem, mode_T);
proj = new_rd_Proj(dbg, irg, block, new_op, src_mode, 0);
set_ia32_Immop_tarval(new_op, new_tarval_from_long(n - m, mode_Is));
set_ia32_am_support(new_op, ia32_am_Source);
SET_IA32_ORIG_NODE(new_op, get_old_node_name(env));
/* ASHR Sn, n - m */
new_op = new_rd_ia32_Shrs(dbg, irg, block, noreg, noreg, proj, noreg, nomem, mode_T);
set_ia32_Immop_tarval(new_op, new_tarval_from_long(n - m, mode_Is));
}
else {
new_op = new_rd_ia32_And(dbg, irg, block, noreg, noreg, op, noreg, nomem, mode_T);
set_ia32_Immop_tarval(new_op, new_tarval_from_long((1 << m) - 1, mode_Is));
}
return new_op;
}
//static ir_node *gen_int_downscale_conv(ia32_transform_env_t *env, ir_node *op,
// ir_mode *src_mode, ir_mode *tgt_mode)
//{
// int n = get_mode_size_bits(src_mode);
// int m = get_mode_size_bits(tgt_mode);
// dbg_info *dbg = env->dbg;
// ir_graph *irg = env->irg;
// ir_node *block = env->block;
// ir_node *noreg = ia32_new_NoReg_gp(env->cg);
// ir_node *nomem = new_rd_NoMem(irg);
// ir_node *new_op, *proj;
// assert(n > m && "downscale expected");
// if (mode_is_signed(src_mode) && mode_is_signed(tgt_mode)) {
// /* ASHL Sn, n - m */
// new_op = new_rd_ia32_Shl(dbg, irg, block, noreg, noreg, op, noreg, nomem, mode_T);
// proj = new_rd_Proj(dbg, irg, block, new_op, src_mode, 0);
// set_ia32_Immop_tarval(new_op, new_tarval_from_long(n - m, mode_Is));
// set_ia32_am_support(new_op, ia32_am_Source);
// SET_IA32_ORIG_NODE(new_op, get_old_node_name(env));
// /* ASHR Sn, n - m */
// new_op = new_rd_ia32_Shrs(dbg, irg, block, noreg, noreg, proj, noreg, nomem, mode_T);
// set_ia32_Immop_tarval(new_op, new_tarval_from_long(n - m, mode_Is));
// }
// else {
// new_op = new_rd_ia32_And(dbg, irg, block, noreg, noreg, op, noreg, nomem, mode_T);
// set_ia32_Immop_tarval(new_op, new_tarval_from_long((1 << m) - 1, mode_Is));
// }
// return new_op;
//}
/**
* Transforms a Conv node.
......@@ -1480,7 +1475,7 @@ static ir_node *gen_Conv(ia32_transform_env_t *env, ir_node *op) {
set_ia32_am_support(new_op, ia32_am_Source);
proj = new_rd_Proj(dbg, irg, block, new_op, mode_Is, 0);
new_op = gen_int_downscale_conv(env, proj, src_mode, tgt_mode);
new_op = new_rd_ia32_Conv_I2I(dbg, irg, block, noreg, noreg, proj, nomem, mode_T);
}
}
}
......@@ -1493,13 +1488,13 @@ static ir_node *gen_Conv(ia32_transform_env_t *env, ir_node *op) {
}
else {
/* ... to int */
if (get_mode_size_bits(src_mode) <= get_mode_size_bits(tgt_mode)) {
DB((mod, LEVEL_1, "omitting upscale Conv(%+F, %+F) ...", src_mode, tgt_mode));
if (get_mode_size_bits(src_mode) == get_mode_size_bits(tgt_mode)) {
DB((mod, LEVEL_1, "omitting equal size Conv(%+F, %+F) ...", src_mode, tgt_mode));
edges_reroute(env->irn, op, irg);
}
else {
DB((mod, LEVEL_1, "create downscale Conv(%+F, %+F) ...", src_mode, tgt_mode));
new_op = gen_int_downscale_conv(env, op, src_mode, tgt_mode);
DB((mod, LEVEL_1, "create Conv(int, int) ...", src_mode, tgt_mode));
new_op = new_rd_ia32_Conv_I2I(dbg, irg, block, noreg, noreg, op, nomem, mode_T);
}
}
}
......
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