*/
#include "config.h"
-#ifdef HAVE_STRING_H
-# include <string.h>
-#endif
-#ifdef HAVE_STDLIB_H
-# include <stdlib.h>
-#endif
-
+#include <string.h>
+#include <stdlib.h>
#include <assert.h>
#include "error.h"
typedef struct _lower_env_t {
node_entry_t **entries; /**< entries per node */
struct obstack obst; /**< an obstack holding the temporary data */
+ ir_type *l_mtp; /**< lowered method type of the current method */
tarval *tv_mode_bytes; /**< a tarval containing the number of bytes in the lowered modes */
tarval *tv_mode_bits; /**< a tarval containing the number of bits in the lowered modes */
pdeq *waitq; /**< a wait queue of all nodes that must be handled later */
pmap *proj_2_block; /**< a map from ProjX to its destination blocks */
+ ident *first_id; /**< .l for little and .h for big endian */
+ ident *next_id; /**< .h for little and .l for big endian */
const lwrdw_param_t *params; /**< transformation parameter */
unsigned flags; /**< some flags */
int n_entries; /**< number of entries */
+ ir_type *value_param_tp; /**< the old value param type */
} lower_env_t;
/**
* Translate a Load: create two.
*/
static void lower_Load(ir_node *node, ir_mode *mode, lower_env_t *env) {
- ir_mode *low_mode = env->params->low_unsigned;
- ir_graph *irg = current_ir_graph;
- ir_node *adr = get_Load_ptr(node);
- ir_node *mem = get_Load_mem(node);
- ir_node *low, *high, *proj;
- dbg_info *dbg;
- ir_node *block = get_nodes_block(node);
- int idx;
+ ir_mode *low_mode = env->params->low_unsigned;
+ ir_graph *irg = current_ir_graph;
+ ir_node *adr = get_Load_ptr(node);
+ ir_node *mem = get_Load_mem(node);
+ ir_node *low, *high, *proj;
+ dbg_info *dbg;
+ ir_node *block = get_nodes_block(node);
+ int idx;
+ ir_cons_flags volatility = get_Load_volatility(node) == volatility_is_volatile
+ ? cons_volatile : 0;
if (env->params->little_endian) {
low = adr;
/* create two loads */
dbg = get_irn_dbg_info(node);
- low = new_rd_Load(dbg, irg, block, mem, low, low_mode);
+ low = new_rd_Load(dbg, irg, block, mem, low, low_mode, volatility);
proj = new_r_Proj(irg, block, low, mode_M, pn_Load_M);
- high = new_rd_Load(dbg, irg, block, proj, high, mode);
-
- set_Load_volatility(low, get_Load_volatility(node));
- set_Load_volatility(high, get_Load_volatility(node));
+ high = new_rd_Load(dbg, irg, block, proj, high, mode, volatility);
idx = get_irn_idx(node);
assert(idx < env->n_entries);
* Translate a Store: create two.
*/
static void lower_Store(ir_node *node, ir_mode *mode, lower_env_t *env) {
- ir_graph *irg;
- ir_node *block, *adr, *mem;
- ir_node *low, *high, *irn, *proj;
- dbg_info *dbg;
- int idx;
+ ir_graph *irg;
+ ir_node *block, *adr, *mem;
+ ir_node *low, *high, *irn, *proj;
+ dbg_info *dbg;
+ int idx;
node_entry_t *entry;
- (void) node;
+ ir_cons_flags volatility = get_Store_volatility(node) == volatility_is_volatile
+ ? cons_volatile : 0;
(void) mode;
irn = get_Store_value(node);
/* create two Stores */
dbg = get_irn_dbg_info(node);
- low = new_rd_Store(dbg, irg, block, mem, low, entry->low_word);
+ low = new_rd_Store(dbg, irg, block, mem, low, entry->low_word, volatility);
proj = new_r_Proj(irg, block, low, mode_M, pn_Store_M);
- high = new_rd_Store(dbg, irg, block, proj, high, entry->high_word);
-
- set_Store_volatility(low, get_Store_volatility(node));
- set_Store_volatility(high, get_Store_volatility(node));
+ high = new_rd_Store(dbg, irg, block, proj, high, entry->high_word, volatility);
idx = get_irn_idx(node);
assert(idx < env->n_entries);
/**
* Lower the method type.
+ *
+ * @param mtp the method type to lower
+ * @param ent the lower environment
+ *
+ * @return the lowered type
*/
static ir_type *lower_mtp(ir_type *mtp, lower_env_t *env) {
pmap_entry *entry;
- ident *id;
- ir_type *res;
+ ident *id, *lid;
+ ir_type *res, *value_type;
if (is_lowered_type(mtp))
return mtp;
} /* if */
} /* for */
- id = id_mangle_u(new_id_from_chars("L", 1), get_type_ident(mtp));
+ id = id_mangle_u(new_id_from_chars("L", 1), get_type_ident(mtp));
res = new_type_method(id, n_param, n_res);
/* set param types and result types */
} /* for */
set_lowered_type(mtp, res);
pmap_insert(lowered_type, mtp, res);
+
+ value_type = get_method_value_param_type(mtp);
+ if (value_type != NULL) {
+ /* this creates a new value parameter type */
+ (void)get_method_value_param_ent(res, 0);
+
+ /* set new param positions */
+ for (i = n_param = 0; i < n; ++i) {
+ ir_type *tp = get_method_param_type(mtp, i);
+ ident *id = get_method_param_ident(mtp, i);
+ ir_entity *ent = get_method_value_param_ent(mtp, i);
+
+ set_entity_link(ent, INT_TO_PTR(n_param));
+ if (is_Primitive_type(tp)) {
+ ir_mode *mode = get_type_mode(tp);
+
+ if (mode == env->params->high_signed || mode == env->params->high_unsigned) {
+ if (id != NULL) {
+ lid = id_mangle(id, env->first_id);
+ set_method_param_ident(res, n_param, lid);
+ set_entity_ident(get_method_value_param_ent(res, n_param), lid);
+ lid = id_mangle(id, env->next_id);
+ set_method_param_ident(res, n_param + 1, lid);
+ set_entity_ident(get_method_value_param_ent(res, n_param + 1), lid);
+ } /* if */
+ n_param += 2;
+ continue;
+ } /* if */
+ } /* if */
+ if (id != NULL) {
+ set_method_param_ident(res, n_param, id);
+ set_entity_ident(get_method_value_param_ent(res, n_param), id);
+ } /* if */
+ ++n_param;
+ } /* for */
+
+ set_lowered_type(value_type, get_method_value_param_type(res));
+ } /* if */
} else {
res = entry->value;
} /* if */
env->entries[idx]->high_word = new_rd_Mux(dbg, irg, block, sel, false_h, true_h, mode);
} /* lower_Mux */
-static void lower_ASM(ir_node *asmn, ir_mode *mode, lower_env_t *env)
-{
+/**
+ * Translate an ASM node.
+ */
+static void lower_ASM(ir_node *asmn, ir_mode *mode, lower_env_t *env) {
ir_mode *his = env->params->high_signed;
ir_mode *hiu = env->params->high_unsigned;
int i;
ir_mode *op_mode = get_irn_mode(get_irn_n(asmn, i));
if (op_mode == his || op_mode == hiu) {
panic("lowering ASM unimplemented");
- }
- }
+ } /* if */
+ } /* for */
for (n = asmn;;) {
ir_mode *proj_mode;
proj_mode = get_irn_mode(n);
if (proj_mode == his || proj_mode == hiu) {
panic("lowering ASM unimplemented");
- }
- }
-}
+ } /* if */
+ } /* for */
+} /* lower_ASM */
+
+/**
+ * Translate a Sel node.
+ */
+static void lower_Sel(ir_node *sel, ir_mode *mode, lower_env_t *env) {
+ (void) mode;
+
+ /* we must only lower value parameter Sels if we change the
+ value parameter type. */
+ if (env->value_param_tp != NULL) {
+ ir_entity *ent = get_Sel_entity(sel);
+ if (get_entity_owner(ent) == env->value_param_tp) {
+ int pos = PTR_TO_INT(get_entity_link(ent));
+
+ ent = get_method_value_param_ent(env->l_mtp, pos);
+ set_Sel_entity(sel, ent);
+ } /* if */
+ } /* if */
+} /* lower_Sel */
/**
* check for opcodes that must always be lowered.
case iro_Return:
case iro_Cond:
case iro_Conv:
+ case iro_Sel:
return 1;
default:
return 0;
(void) size;
return (e1->imode - e2->imode) | (e1->omode - e2->omode);
-} /* static int cmp_conv_tp */
+} /* cmp_conv_tp */
/**
* Enter a lowering function into an ir_op.
*/
static void enter_lower_func(ir_op *op, lower_func func) {
op->ops.generic = (op_func)func;
-}
+} /* enter_lower_func */
+
+/**
+ * Returns non-zero if a method type must be lowered.
+ *
+ * @param mtp the method type
+ */
+static int mtp_must_to_lowered(ir_type *mtp, lower_env_t *env) {
+ int i, n_params;
+
+ n_params = get_method_n_params(mtp);
+ if (n_params <= 0)
+ return 0;
+
+ /* first check if we have parameters that must be fixed */
+ for (i = 0; i < n_params; ++i) {
+ ir_type *tp = get_method_param_type(mtp, i);
+
+ if (is_Primitive_type(tp)) {
+ ir_mode *mode = get_type_mode(tp);
+
+ if (mode == env->params->high_signed ||
+ mode == env->params->high_unsigned)
+ return 1;
+ } /* if */
+ } /* for */
+ return 0;
+} /* mtp_must_to_lowered */
/*
* Do the lowering.
void lower_dw_ops(const lwrdw_param_t *param)
{
lower_env_t lenv;
- int i;
- ir_graph *rem;
+ int i;
+ ir_graph *rem;
if (! param)
return;
shiftop_tp_s = new_type_method(IDENT("shiftop_s_intrinsic"), 3, 2);
set_method_param_type(shiftop_tp_s, 0, tp_u);
set_method_param_type(shiftop_tp_s, 1, tp_s);
- /* beware: shift count is always mode_Iu */
set_method_param_type(shiftop_tp_s, 2, tp_u);
set_method_res_type(shiftop_tp_s, 0, tp_u);
set_method_res_type(shiftop_tp_s, 1, tp_s);
lenv.tv_mode_bits = new_tarval_from_long(get_mode_size_bits(param->low_unsigned), param->low_unsigned);
lenv.waitq = new_pdeq();
lenv.params = param;
+ lenv.first_id = new_id_from_chars(param->little_endian ? ".l" : ".h", 2);
+ lenv.next_id = new_id_from_chars(param->little_endian ? ".h" : ".l", 2);
/* first clear the generic function pointer for all ops */
clear_irp_opcodes_generic_func();
LOWER(DivMod);
LOWER(Div);
LOWER(Mod);
+ LOWER(Sel);
LOWER_UN(Abs);
LOWER_UN(Minus);
/* transform all graphs */
rem = current_ir_graph;
for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
- ir_graph *irg = get_irp_irg(i);
+ ir_graph *irg = get_irp_irg(i);
+ ir_entity *ent;
+ ir_type *mtp;
int n_idx;
obstack_init(&lenv.obst);
lenv.entries = NEW_ARR_F(node_entry_t *, n_idx);
memset(lenv.entries, 0, n_idx * sizeof(lenv.entries[0]));
- /* first step: link all nodes and allocate data */
- lenv.flags = 0;
+ lenv.l_mtp = NULL;
+ lenv.flags = 0;
lenv.proj_2_block = pmap_create();
-
+ lenv.value_param_tp = NULL;
ir_reserve_resources(irg, IR_RESOURCE_PHI_LIST | IR_RESOURCE_IRN_LINK);
+ ent = get_irg_entity(irg);
+ mtp = get_entity_type(ent);
+
+ if (mtp_must_to_lowered(mtp, &lenv)) {
+ ir_type *ltp = lower_mtp(mtp, &lenv);
+ lenv.flags |= MUST_BE_LOWERED;
+ set_entity_type(ent, ltp);
+ lenv.l_mtp = ltp;
+ lenv.value_param_tp = get_method_value_param_type(mtp);
+ } /* if */
+
+ /* first step: link all nodes and allocate data */
irg_walk_graph(irg, firm_clear_node_and_phi_links, prepare_links_and_handle_rotl, &lenv);
if (lenv.flags & MUST_BE_LOWERED) {