#include "irnode.h"
#include "irprog_t.h"
#include "ircons.h"
+#include "irtools.h"
#include "firm_types.h"
#include "iredges.h"
#include "tv.h"
right = get_irn_n(irn, 3);
if (pred_is_specific_nodeblock(block, left, is_ia32_Ld)) {
- n = ia32_get_irn_n_edges(left);
+ n = ia32_get_irn_n_edges(left);
/* load with only one user: don't create LEA */
if(n == 1)
return 0;
}
if (pred_is_specific_nodeblock(block, right, is_ia32_Ld)) {
- n = ia32_get_irn_n_edges(right);
+ n = ia32_get_irn_n_edges(right);
if(n == 1)
return 0;
}
static ia32_am_cand_t is_am_candidate(heights_t *h, const ir_node *block, ir_node *irn) {
ir_node *in, *load, *other, *left, *right;
int is_cand = 0, cand;
- int arity;
+ int arity;
+ int is_binary;
if (is_ia32_Ld(irn) || is_ia32_St(irn) ||
is_ia32_vfild(irn) || is_ia32_vfist(irn) ||
if(get_ia32_frame_ent(irn) != NULL)
return IA32_AM_CAND_NONE;
- left = get_irn_n(irn, 2);
- arity = get_irn_arity(irn);
- if(get_ia32_am_arity(irn) == ia32_am_binary) {
+ left = get_irn_n(irn, 2);
+ arity = get_irn_arity(irn);
+ is_binary = get_ia32_am_arity(irn) == ia32_am_binary;
+ if(is_binary) {
/* binary op */
right = get_irn_n(irn, 3);
} else {
}
/* If there is a data dependency of other irn from load: cannot use AM */
- if (is_cand && get_nodes_block(other) == block) {
+ if (is_cand && is_binary && get_nodes_block(other) == block) {
other = skip_Proj(other);
is_cand = heights_reachable_in_block(h, other, load) ? 0 : is_cand;
/* this could happen in loops */
other = left;
/* 8bit Loads are not supported, they cannot be used with every register */
- if (get_mode_size_bits(get_ia32_ls_mode(load)) < 16)
+ /* 8bit Loads are not supported (for binary ops),
+ * they cannot be used with every register */
+ if (get_ia32_am_arity(irn) == ia32_am_binary &&
+ get_mode_size_bits(get_ia32_ls_mode(load)) < 16) {
is_cand = 0;
+ }
/* If there is a data dependency of other irn from load: cannot use load */
- if (is_cand && get_nodes_block(other) == block) {
+ if (is_cand && is_binary && get_nodes_block(other) == block) {
other = skip_Proj(other);
is_cand = heights_reachable_in_block(h, other, load) ? 0 : is_cand;
/* this could happen in loops */
static void optimize_conv_conv(ir_node *node)
{
- ir_node *pred;
- ir_mode *pred_mode;
- ir_mode *conv_mode;
+ ir_node *pred_proj, *pred, *result_conv;
+ ir_mode *pred_mode, *conv_mode;
if (!is_ia32_Conv_I2I(node) && !is_ia32_Conv_I2I8Bit(node))
return;
assert(n_ia32_Conv_I2I_val == n_ia32_Conv_I2I8Bit_val);
- pred = get_irn_n(node, n_ia32_Conv_I2I_val);
+ pred_proj = get_irn_n(node, n_ia32_Conv_I2I_val);
+ if(is_Proj(pred_proj))
+ pred = get_Proj_pred(pred_proj);
+ else
+ pred = pred_proj;
+
if(!is_ia32_Conv_I2I(pred) && !is_ia32_Conv_I2I8Bit(pred))
return;
* so we only need the 2nd conv if it shrinks the mode */
conv_mode = get_ia32_ls_mode(node);
pred_mode = get_ia32_ls_mode(pred);
- if(get_mode_size_bits(conv_mode) < get_mode_size_bits(pred_mode))
- return;
+ /* if 2nd conv is smaller then first conv, then we can always take the 2nd
+ * conv */
+ if(get_mode_size_bits(conv_mode) <= get_mode_size_bits(pred_mode)) {
+ if(get_irn_n_edges(pred_proj) == 1) {
+ result_conv = pred_proj;
+ set_ia32_ls_mode(pred, conv_mode);
+ } else {
+ /* TODO: construct syncs/stuff here but we'll probably end up with
+ * 2 statements anyway */
+ if(get_irn_mode(pred) == mode_T) {
+ return;
+ }
- /* we can't eliminate an upconv signed->unsigned */
- if (get_mode_size_bits(conv_mode) != get_mode_size_bits(pred_mode) &&
- !get_mode_sign(conv_mode) && get_mode_sign(pred_mode))
- return;
+ result_conv = exact_copy(pred);
+ set_ia32_ls_mode(result_conv, conv_mode);
+ }
+ } else {
+ /* if both convs have the same sign, then we can take the smaller one */
+ if(get_mode_sign(conv_mode) == get_mode_sign(pred_mode)) {
+ result_conv = pred_proj;
+ } else {
+ /* no optimisation possible if smaller conv is sign-extend */
+ if(mode_is_signed(pred_mode)) {
+ return;
+ }
+ /* we can take the smaller conv if it is unsigned */
+ result_conv = pred_proj;
+ }
+ }
/* kill the conv */
- exchange(node, pred);
+ exchange(node, result_conv);
+
+ if(get_irn_n_edges(pred) == 0) {
+ be_kill_node(pred);
+ }
+ optimize_conv_conv(result_conv);
}
static void optimize_node(ir_node *node, void *env)
assert(cand & IA32_AM_CAND_RIGHT);
load = get_Proj_pred(right);
+ if(get_irn_n_edges(right) > 1) {
+ source_possible = 0;
+ }
+#if 1
+ /* TODO: this isn't really needed, but the code below is buggy
+ as heights won't get recomputed when the graph is reconstructed
+ so we can only transform loads with the result proj only */
if(get_irn_n_edges(load) > 1) {
source_possible = 0;
}
+#endif
}
if (source_possible) {
ir_mode *ls_mode = get_ia32_ls_mode(load);
- if(get_mode_size_bits(ls_mode) != 32
- || ls_mode == mode_D)
+ if(get_mode_size_bits(ls_mode) != 32 || ls_mode == mode_D)
source_possible = 0;
}
if (source_possible) {
+ const ia32_attr_t *attr_load = get_ia32_attr_const(load);
+ ia32_attr_t *attr_irn = get_ia32_attr(irn);
addr_b = get_irn_n(load, 0);
addr_i = get_irn_n(load, 1);
set_ia32_am_flavour(irn, get_ia32_am_flavour(load));
set_ia32_op_type(irn, ia32_AddrModeS);
set_ia32_frame_ent(irn, get_ia32_frame_ent(load));
- set_ia32_ls_mode(irn, get_ia32_ls_mode(load));
+ attr_irn->data.need_64bit_stackent
+ = attr_load->data.need_64bit_stackent;
+ attr_irn->data.need_32bit_stackent
+ = attr_load->data.need_32bit_stackent;
+
+ /* set ls_mode if not already present (conv nodes already have ls_mode
+ set) */
+ if(get_ia32_ls_mode(irn) == NULL) {
+ set_ia32_ls_mode(irn, get_ia32_ls_mode(load));
+ }
set_ia32_am_sc(irn, get_ia32_am_sc(load));
if (is_ia32_am_sc_sign(load))
ir_node *res_proj;
ir_mode *mode = get_irn_mode(irn);
- assert(mode != mode_T);
-
- res_proj = new_rd_Proj(get_irn_dbg_info(irn), irg,
- get_nodes_block(irn), new_Unknown(mode_T),
- mode, 0);
- set_irn_mode(irn, mode_T);
- edges_reroute(irn, res_proj, irg);
- set_Proj_pred(res_proj, irn);
+ if(mode != mode_T) {
+ res_proj = new_rd_Proj(get_irn_dbg_info(irn), irg,
+ get_nodes_block(irn),
+ new_Unknown(mode_T), mode, 0);
+ set_irn_mode(irn, mode_T);
+ edges_reroute(irn, res_proj, irg);
+ set_Proj_pred(res_proj, irn);
- set_Proj_pred(mem_proj, irn);
- set_Proj_proj(mem_proj, 1);
+ set_Proj_pred(mem_proj, irn);
+ set_Proj_proj(mem_proj, 1);
+ } else {
+ /* hacky: we need some proj number which is not used yet... */
+ set_Proj_proj(mem_proj, -1);
+ set_Proj_pred(mem_proj, irn);
+ }
}
try_kill(load);