/** @} */
-/** @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
* @{
*/
/** @} */
-/**
- * @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
* @{
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.
*
/* 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);
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 {
/* 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) {
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)))
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)))
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);
}
/**
- * 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);
}
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)) {
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 */
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;
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;
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))
}
}
-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);
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;
#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)
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)
{
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);
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) {
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;
}
}
}
}
/* 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);
+ }
}
}
}
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. */
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. */
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);
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);
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 */
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;
case iro_Const:
key.u.tv = get_Const_tarval(irn);
break;
- case iro_Conv:
- key.u.intVal = get_Conv_strict(irn);
- break;
case iro_Load:
key.mode = get_Load_mode(irn);
break;
class Conv(Unop):
"""Converts values between modes"""
flags = []
- attrs = [
- dict(
- name = "strict",
- type = "int",
- init = "0",
- comment = "force floating point to restrict precision even if backend computes in higher precision (deprecated)",
- )
- ]
- attr_struct = "conv_attr"
@op
class CopyB: