Commit 31b3daf7 authored by Matthias Braun's avatar Matthias Braun
Browse files

remove the concept of a strictconv

This means floatingpoint calculation in a firm graph must be performed
in the mode specified (and may not be performed in a wider mode as
before).
parent d04b8b89
......@@ -557,45 +557,6 @@ FIRM_API ir_node *new_SymConst(ir_mode *mode, union symconst_symbol value,
/** @} */
/** @addtogroup Conv
* @{
*/
/** Constructor for a strictConv node.
*
* @param db A pointer for debug information.
* @param block The IR block the node belongs to.
* @param op The operand.
* @param mode The mode of this the operand muss be converted .
*/
FIRM_API ir_node *new_rd_strictConv(dbg_info *db, ir_node *block,
ir_node *op, ir_mode *mode);
/** Constructor for a strictConv node.
*
* @param block The IR block the node belongs to.
* @param op The operand.
* @param mode The mode of this the operand muss be converted .
*/
FIRM_API ir_node *new_r_strictConv(ir_node *block, ir_node *op, ir_mode *mode);
/** Constructor for a strict Conv node.
*
* @param db A pointer for debug information.
* @param op The operand.
* @param mode The mode of this the operand muss be converted .
*/
FIRM_API ir_node *new_d_strictConv(dbg_info *db, ir_node *op, ir_mode *mode);
/** Constructor for a strict Conv node.
*
* @param op The operand.
* @param mode The mode of this the operand muss be converted .
*/
FIRM_API ir_node *new_strictConv(ir_node *op, ir_mode *mode);
/** @} */
/** @addtogroup Sel
* @{
*/
......
......@@ -383,12 +383,6 @@ FIRM_API int is_Const_all_one(const ir_node *node);
/** @} */
/**
* @ingroup Conv
* Returns true if a node is a Conv node with strict attribute set.
*/
FIRM_API int is_strictConv(const ir_node *node);
/**
* @addtogroup SymConst
* @{
......
......@@ -1017,6 +1017,13 @@ static ir_node *skip_float_upconv(ir_node *node)
return node;
}
static void check_x87_floatmode(ir_mode *mode)
{
if (mode != ia32_mode_E) {
panic("ia32: x87 only supports x86 extended float mode");
}
}
/**
* Construct a standard binary operation, set AM and immediate if required.
*
......@@ -1038,6 +1045,9 @@ static ir_node *gen_binop_x87_float(ir_node *node, ir_node *op1, ir_node *op2,
/* All operations are considered commutative, because there are reverse
* variants */
match_flags_t flags = match_commutative | match_am;
ir_mode *mode
= is_Div(node) ? get_Div_resmode(node) : get_irn_mode(node);
check_x87_floatmode(mode);
op1 = skip_float_upconv(op1);
op2 = skip_float_upconv(op2);
......@@ -1907,6 +1917,7 @@ static ir_node *gen_Minus(ir_node *node)
set_ia32_op_type(new_node, ia32_AddrModeS);
set_ia32_ls_mode(new_node, mode);
} else {
check_x87_floatmode(mode);
new_node = new_bd_ia32_vfchs(dbgi, block, new_op);
}
} else {
......@@ -1963,6 +1974,7 @@ static ir_node *create_float_abs(dbg_info *dbgi, ir_node *block, ir_node *op,
/* TODO, implement -Abs case */
assert(!negate);
} else {
check_x87_floatmode(mode);
new_node = new_bd_ia32_vfabs(dbgi, new_block, new_op);
SET_IA32_ORIG_NODE(new_node, node);
if (negate) {
......@@ -2693,8 +2705,7 @@ static ir_node *gen_general_Store(ir_node *node)
addr.mem = be_transform_node(mem);
if (mode_is_float(mode)) {
/* Convs (and strict-Convs) before stores are unnecessary if the mode
is the same. */
/* Convs before stores are unnecessary if the mode is the same. */
while (is_Conv(val) && mode == get_irn_mode(val)) {
ir_node *op = get_Conv_op(val);
if (!mode_is_float(get_irn_mode(op)))
......@@ -2713,8 +2724,7 @@ static ir_node *gen_general_Store(ir_node *node)
val = get_Conv_op(val);
/* TODO: is this optimisation still necessary at all (middleend)? */
/* We can skip ALL float->float up-Convs (and strict-up-Convs) before
* stores. */
/* We can skip ALL float->float up-Convs before stores. */
while (is_Conv(val)) {
ir_node *op = get_Conv_op(val);
if (!mode_is_float(get_irn_mode(op)))
......@@ -2855,8 +2865,10 @@ static ir_node *create_Fucom(ir_node *node)
ir_node *left = get_Cmp_left(node);
ir_node *new_left = be_transform_node(left);
ir_node *right = get_Cmp_right(node);
ir_mode *cmp_mode = get_irn_mode(left);
ir_node *new_right;
ir_node *new_node;
check_x87_floatmode(cmp_mode);
if (ia32_cg_config.use_fucomi) {
new_right = be_transform_node(right);
......@@ -3654,9 +3666,9 @@ static ir_node *gen_x87_fp_to_gp(ir_node *node)
}
/**
* Creates a x87 strict Conv by placing a Store and a Load
* Creates a x87 Conv by placing a Store and a Load
*/
static ir_node *gen_x87_strict_conv(ir_mode *tgt_mode, ir_node *node)
static ir_node *gen_x87_conv(ir_mode *tgt_mode, ir_node *node)
{
ir_node *block = get_nodes_block(node);
ir_graph *irg = get_Block_irg(block);
......@@ -3869,17 +3881,10 @@ static ir_node *gen_Conv(ir_node *node)
}
if (src_mode == tgt_mode) {
if (get_Conv_strict(node)) {
if (ia32_cg_config.use_sse2) {
/* when we are in SSE mode, we can kill all strict no-op conversion */
return be_transform_node(op);
}
} else {
/* this should be optimized already, but who knows... */
DEBUG_ONLY(ir_fprintf(stderr, "Debug warning: conv %+F is pointless\n", node);)
/* this should be optimized already, but who knows... */
DEBUG_ONLY(ir_fprintf(stderr, "Debug warning: conv %+F is pointless\n", node);)
DB((dbg, LEVEL_1, "killed Conv(mode, mode) ..."));
return be_transform_node(op);
}
return be_transform_node(op);
}
if (mode_is_float(src_mode)) {
......@@ -3893,21 +3898,14 @@ static ir_node *gen_Conv(ir_node *node)
nomem, new_op);
set_ia32_ls_mode(res, tgt_mode);
} else {
if (get_Conv_strict(node)) {
/* if fp_no_float_fold is not set then we assume that we
* don't have any float operations in a non
* mode_float_arithmetic mode and can skip strict upconvs */
if (src_bits < tgt_bits) {
DB((dbg, LEVEL_1, "killed Conv(float, float) ..."));
return new_op;
} else {
res = gen_x87_strict_conv(tgt_mode, new_op);
SET_IA32_ORIG_NODE(get_Proj_pred(res), node);
return res;
}
if (src_bits < tgt_bits) {
DB((dbg, LEVEL_1, "killed Conv(float, float) ..."));
return new_op;
} else {
res = gen_x87_conv(tgt_mode, new_op);
SET_IA32_ORIG_NODE(get_Proj_pred(res), node);
return res;
}
DB((dbg, LEVEL_1, "killed Conv(float, float) ..."));
return new_op;
}
} else {
/* ... to int */
......@@ -3935,10 +3933,10 @@ static ir_node *gen_Conv(ir_node *node)
unsigned float_mantissa = get_mode_mantissa_size(tgt_mode);
res = gen_x87_gp_to_fp(node, src_mode);
/* we need a strict-Conv, if the int mode has more bits than the
/* we need a float-conv, if the int mode has more bits than the
* float mantissa */
if (float_mantissa < int_mantissa) {
res = gen_x87_strict_conv(tgt_mode, res);
res = gen_x87_conv(tgt_mode, res);
SET_IA32_ORIG_NODE(get_Proj_pred(res), node);
}
return res;
......
......@@ -404,39 +404,6 @@ ir_node *new_d_ASM(dbg_info *db, ir_node *mem, int arity, ir_node *in[],
inputs, n_outs, outputs, n_clobber, clobber, text);
}
ir_node *new_rd_strictConv(dbg_info *dbgi, ir_node *block, ir_node * irn_op, ir_mode * mode)
{
ir_node *res;
ir_graph *irg = get_Block_irg(block);
ir_node *in[1];
in[0] = irn_op;
res = new_ir_node(dbgi, irg, block, op_Conv, mode, 1, in);
res->attr.conv.strict = 1;
irn_verify_irg(res, irg);
res = optimize_node(res);
return res;
}
ir_node *new_r_strictConv(ir_node *block, ir_node * irn_op, ir_mode * mode)
{
return new_rd_strictConv(NULL, block, irn_op, mode);
}
ir_node *new_d_strictConv(dbg_info *dbgi, ir_node * irn_op, ir_mode * mode)
{
ir_node *res;
assert(get_irg_phase_state(current_ir_graph) == phase_building);
res = new_rd_strictConv(dbgi, current_ir_graph->current_block, irn_op, mode);
return res;
}
ir_node *new_strictConv(ir_node * irn_op, ir_mode * mode)
{
return new_d_strictConv(NULL, irn_op, mode);
}
ir_node *new_rd_DivRL(dbg_info *dbgi, ir_node *block, ir_node * irn_mem, ir_node * irn_left, ir_node * irn_right, ir_mode* resmode, op_pin_state pin_state)
{
ir_node *res;
......
......@@ -674,11 +674,6 @@ void dump_node_opcode(FILE *F, const ir_node *n)
fprintf(F, "%s%s", get_irn_opname(n),
(flags & ir_dump_flag_show_marks) ? (get_Block_mark(n) ? "*" : "") : "");
break;
case iro_Conv:
if (get_Conv_strict(n))
fprintf(F, "strict");
fprintf(F, "%s", get_irn_opname(n));
break;
case iro_Div:
fprintf(F, "%s", get_irn_opname(n));
if (get_Div_no_remainder(n))
......
......@@ -1397,11 +1397,6 @@ ir_node *skip_Id(ir_node *node)
}
}
int (is_strictConv)(const ir_node *node)
{
return is_strictConv_(node);
}
int (is_SymConst_addr_ent)(const ir_node *node)
{
return is_SymConst_addr_ent_(node);
......
......@@ -311,11 +311,6 @@ static inline int is_binop_(const ir_node *node)
return (node->op->opar == oparity_binary);
}
static inline int is_strictConv_(const ir_node *node)
{
return is_Conv_(node) && get_Conv_strict(node);
}
static inline int is_SymConst_addr_ent_(const ir_node *node)
{
return is_SymConst(node) && get_SymConst_kind(node) == symconst_addr_ent;
......@@ -592,7 +587,6 @@ void init_irnode(void);
#define is_binop(node) is_binop_(node)
#define is_Proj(node) is_Proj_(node)
#define is_Phi(node) is_Phi_(node)
#define is_strictConv(node) is_strictConv_(node)
#define is_SymConst_addr_ent(node) is_SymConst_addr_ent_(node)
#define get_Block_n_cfgpreds(node) get_Block_n_cfgpreds_(node)
#define get_Block_cfgpred(node, pos) get_Block_cfgpred_(node, pos)
......
......@@ -341,12 +341,6 @@ static int node_cmp_attr_Phi(const ir_node *a, const ir_node *b)
return 0;
}
/** Compares the attributes of two Conv nodes. */
static int node_cmp_attr_Conv(const ir_node *a, const ir_node *b)
{
return get_Conv_strict(a) != get_Conv_strict(b);
}
/** Compares the attributes of two Cast nodes. */
static int node_cmp_attr_Cast(const ir_node *a, const ir_node *b)
{
......@@ -610,7 +604,6 @@ void firm_init_op(void)
register_node_cmp_func(op_Cmp, node_cmp_attr_Cmp);
register_node_cmp_func(op_Confirm, node_cmp_attr_Confirm);
register_node_cmp_func(op_Const, node_cmp_attr_Const);
register_node_cmp_func(op_Conv, node_cmp_attr_Conv);
register_node_cmp_func(op_CopyB, node_cmp_attr_CopyB);
register_node_cmp_func(op_Div, node_cmp_attr_Div);
register_node_cmp_func(op_Dummy, node_cmp_attr_Dummy);
......
......@@ -1101,99 +1101,24 @@ static ir_node *equivalent_node_Conv(ir_node *n)
ir_mode *n_mode = get_irn_mode(n);
ir_mode *a_mode = get_irn_mode(a);
restart:
if (n_mode == a_mode) { /* No Conv necessary */
if (get_Conv_strict(n)) {
ir_node *p = a;
/* neither Minus nor Confirm change the precision,
so we can "look-through" */
for (;;) {
if (is_Minus(p)) {
p = get_Minus_op(p);
} else if (is_Confirm(p)) {
p = get_Confirm_value(p);
} else {
/* stop here */
break;
}
}
if (is_Conv(p) && get_Conv_strict(p)) {
/* we known already, that a_mode == n_mode, and neither
Minus change the mode, so the second Conv
can be kicked */
assert(get_irn_mode(p) == n_mode);
n = a;
DBG_OPT_ALGSIM0(oldn, n, FS_OPT_CONV);
return n;
}
if (is_Proj(p)) {
ir_node *pred = get_Proj_pred(p);
if (is_Load(pred)) {
/* Loads always return with the exact precision of n_mode */
assert(get_Load_mode(pred) == n_mode);
n = a;
DBG_OPT_ALGSIM0(oldn, n, FS_OPT_CONV);
return n;
}
if (is_Proj(pred) && get_Proj_proj(pred) == pn_Start_T_args) {
pred = get_Proj_pred(pred);
if (is_Start(pred)) {
/* Arguments always return with the exact precision,
as strictConv's are place before Call -- if the
caller was compiled with the same setting.
Otherwise, the semantics is probably still right. */
assert(get_irn_mode(p) == n_mode);
n = a;
DBG_OPT_ALGSIM0(oldn, n, FS_OPT_CONV);
return n;
}
}
}
if (is_Conv(a)) {
/* special case: the immediate predecessor is also a Conv */
if (! get_Conv_strict(a)) {
/* first one is not strict, kick it */
a = get_Conv_op(a);
a_mode = get_irn_mode(a);
set_Conv_op(n, a);
goto restart;
}
/* else both are strict conv, second is superfluous */
n = a;
DBG_OPT_ALGSIM0(oldn, n, FS_OPT_CONV);
return n;
}
} else {
n = a;
DBG_OPT_ALGSIM0(oldn, n, FS_OPT_CONV);
return n;
}
n = a;
DBG_OPT_ALGSIM0(oldn, n, FS_OPT_CONV);
return n;
} else if (is_Conv(a)) { /* Conv(Conv(b)) */
ir_node *b = get_Conv_op(a);
ir_mode *b_mode = get_irn_mode(b);
if (get_Conv_strict(n) && get_Conv_strict(a)) {
/* both are strict conv */
if (smaller_mode(a_mode, n_mode)) {
/* both are strict, but the first is smaller, so
the second cannot remove more precision, remove the
strict bit */
set_Conv_strict(n, 0);
}
}
if (n_mode == b_mode) {
if (! get_Conv_strict(n) && ! get_Conv_strict(a)) {
if (n_mode == mode_b) {
n = b; /* Convb(Conv*(xxxb(...))) == xxxb(...) */
if (n_mode == mode_b) {
n = b; /* Convb(Conv*(xxxb(...))) == xxxb(...) */
DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_CONV);
return n;
} else if (get_mode_arithmetic(n_mode) == get_mode_arithmetic(a_mode)) {
if (values_in_mode(b_mode, a_mode)) {
n = b; /* ConvS(ConvL(xxxS(...))) == xxxS(...) */
DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_CONV);
return n;
} else if (get_mode_arithmetic(n_mode) == get_mode_arithmetic(a_mode)) {
if (values_in_mode(b_mode, a_mode)) {
n = b; /* ConvS(ConvL(xxxS(...))) == xxxS(...) */
DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_CONV);
return n;
}
}
}
if (mode_is_int(n_mode) && get_mode_arithmetic(a_mode) == irma_ieee754) {
......@@ -1207,14 +1132,10 @@ restart:
return n;
}
}
if (is_Conv(b)) {
if (smaller_mode(b_mode, a_mode)) {
if (get_Conv_strict(n))
set_Conv_strict(b, 1);
n = b; /* ConvA(ConvB(ConvA(...))) == ConvA(...) */
DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_CONV);
return n;
}
if (is_Conv(b) && smaller_mode(b_mode, a_mode)) {
n = b; /* ConvA(ConvB(ConvA(...))) == ConvA(...) */
DBG_OPT_ALGSIM1(oldn, a, b, n, FS_OPT_CONV);
return n;
}
}
}
......@@ -4213,53 +4134,56 @@ static ir_node *transform_node_Cmp(ir_node *n)
}
/* Remove unnecessary conversions */
if (is_Conv(left) && is_Conv(right)) {
ir_node *op_left = get_Conv_op(left);
ir_node *op_right = get_Conv_op(right);
ir_mode *mode_left = get_irn_mode(op_left);
ir_mode *mode_right = get_irn_mode(op_right);
if (smaller_mode(mode_left, mode) && smaller_mode(mode_right, mode)
&& mode_left != mode_b && mode_right != mode_b) {
ir_node *block = get_nodes_block(n);
if (mode_left == mode_right) {
left = op_left;
right = op_right;
changed = true;
DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_CONV_CONV);
} else if (smaller_mode(mode_left, mode_right)) {
left = new_r_Conv(block, op_left, mode_right);
right = op_right;
changed = true;
DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_CONV);
} else if (smaller_mode(mode_right, mode_left)) {
left = op_left;
right = new_r_Conv(block, op_right, mode_left);
changed = true;
DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_CONV);
if (!mode_is_float(mode)
|| be_get_backend_param()->mode_float_arithmetic == NULL) {
if (is_Conv(left) && is_Conv(right)) {
ir_node *op_left = get_Conv_op(left);
ir_node *op_right = get_Conv_op(right);
ir_mode *mode_left = get_irn_mode(op_left);
ir_mode *mode_right = get_irn_mode(op_right);
if (smaller_mode(mode_left, mode) && smaller_mode(mode_right, mode)
&& mode_left != mode_b && mode_right != mode_b) {
ir_node *block = get_nodes_block(n);
if (mode_left == mode_right) {
left = op_left;
right = op_right;
changed = true;
DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_CONV_CONV);
} else if (smaller_mode(mode_left, mode_right)) {
left = new_r_Conv(block, op_left, mode_right);
right = op_right;
changed = true;
DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_CONV);
} else if (smaller_mode(mode_right, mode_left)) {
left = op_left;
right = new_r_Conv(block, op_right, mode_left);
changed = true;
DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_CONV);
}
mode = get_irn_mode(left);
}
mode = get_irn_mode(left);
}
}
if (is_Conv(left) && is_Const(right)) {
ir_node *op_left = get_Conv_op(left);
ir_mode *mode_left = get_irn_mode(op_left);
if (smaller_mode(mode_left, mode) && mode_left != mode_b) {
ir_tarval *tv = get_Const_tarval(right);
tarval_int_overflow_mode_t last_mode
= tarval_get_integer_overflow_mode();
ir_tarval *new_tv;
tarval_set_integer_overflow_mode(TV_OVERFLOW_BAD);
new_tv = tarval_convert_to(tv, mode_left);
tarval_set_integer_overflow_mode(last_mode);
if (new_tv != tarval_bad) {
ir_graph *irg = get_irn_irg(n);
left = op_left;
right = new_r_Const(irg, new_tv);
mode = get_irn_mode(left);
changed = true;
DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_CONV);
}
if (is_Conv(left) && is_Const(right)) {
ir_node *op_left = get_Conv_op(left);
ir_mode *mode_left = get_irn_mode(op_left);
if (smaller_mode(mode_left, mode) && mode_left != mode_b) {
ir_tarval *tv = get_Const_tarval(right);
tarval_int_overflow_mode_t last_mode
= tarval_get_integer_overflow_mode();
ir_tarval *new_tv;
tarval_set_integer_overflow_mode(TV_OVERFLOW_BAD);
new_tv = tarval_convert_to(tv, mode_left);
tarval_set_integer_overflow_mode(last_mode);
if (new_tv != tarval_bad) {
ir_graph *irg = get_irn_irg(n);
left = op_left;
right = new_r_Const(irg, new_tv);
mode = get_irn_mode(left);
changed = true;
DBG_OPT_ALGSIM0(n, n, FS_OPT_CMP_CONV);
}
}
}
}
......
......@@ -329,11 +329,6 @@ typedef struct bound_attr {
except_attr exc; /**< The exception attribute. MUST be the first one. */
} bound_attr;
/** Conv attribute. */
typedef struct conv_attr {
char strict; /**< If set, this is a strict Conv that cannot be removed. */
} conv_attr;
/** Div attribute. */
typedef struct div_attr {
except_attr exc; /**< The exception attribute. MUST be the first one. */
......@@ -392,7 +387,6 @@ typedef union ir_attr {
except_attr except; /**< For Phi node construction in case of exceptions */
copyb_attr copyb; /**< For CopyB operation */
bound_attr bound; /**< For Bound operation */
conv_attr conv; /**< For Conv operation */
div_attr div; /**< For Div operation */
mod_attr mod; /**< For Mod operation */
asm_attr assem; /**< For ASM operation. */
......
......@@ -391,9 +391,16 @@ int i_mapper_pow(ir_node *call, void *ctx)
dbg = get_irn_dbg_info(call);
if (irn == NULL) {
ir_mode *mode = get_irn_mode(left);
ir_mode *result_mode = get_irn_mode(left);
ir_node *div;
ir_mode *mode = result_mode;
ir_mode *float_arithmetic = be_get_backend_param()->mode_float_arithmetic;
if (float_arithmetic != NULL) {
left = new_r_Conv(block, left, float_arithmetic);
mode = float_arithmetic;
}
irn = new_r_Const(irg, get_mode_one(mode));
div = new_rd_Div(dbg, block, mem, irn, left, mode, op_pin_state_pinned);
mem = new_r_Proj(div, mode_M, pn_Div_M);
......@@ -403,6 +410,9 @@ int i_mapper_pow(ir_node *call, void *ctx)
exc_jmp = new_r_Proj(div, mode_X, pn_Div_X_except);
ir_set_throws_exception(div, true);
}
if (result_mode != mode) {
irn = new_r_Conv(block, irn, result_mode);
}
}
DBG_OPT_ALGSIM0(call, irn, FS_OPT_RTS_POW);
replace_call(irn, call, mem, reg_jmp, exc_jmp);
......@@ -487,7 +497,7 @@ static int i_mapper_symmetric_zero_to_one(ir_node *call, void *ctx, int reason)
ir_node *val = get_Call_param(call, 0);
(void) ctx;
if (is_strictConv(val)) {
if (is_Conv(val)) {
ir_node *op = get_Conv_op(val);
if (is_Minus(op)) {
/* f(-x) = f(x) with strictConv */
......@@ -497,10 +507,6 @@ static int i_mapper_symmetric_zero_to_one(ir_node *call, void *ctx, int reason)
op = get_Minus_op(op);
val = new_rd_Conv(dbg, block, op, mode);
if (is_Conv(val)) {
/* still a Conv ? */
set_Conv_strict(val, 1);
}
DBG_OPT_ALGSIM2(call, op, call, FS_OPT_RTS_SYMMETRIC);
set_Call_param(call, 0, val);
changed = 1;
......
......@@ -421,9 +421,6 @@ static opcode_key_t *opcode(const node_t *node, environment_t *env)
case iro_Const:
key.u.tv = get_Const_tarval(irn);
break;