#include "irtools.h"
#include "raw_bitset.h"
#include "error.h"
+#include "pset_new.h"
#include "be.h"
#include "beabi.h"
int n_params = get_method_n_params(call_tp);
ir_node *curr_mem = get_Call_mem(irn);
ir_node *bl = get_nodes_block(irn);
- pset *results = pset_new_ptr(8);
- pset *caller_save = pset_new_ptr(8);
- pset *states = pset_new_ptr(2);
int stack_size = 0;
int stack_dir = arch_env_stack_dir(arch_env);
const arch_register_t *sp = arch_env_sp(arch_env);
int n_stack_params = 0;
int n_ins;
+ pset_new_t destroyed_regs, states;
+ pset_new_iterator_t iter;
ir_node *low_call;
ir_node **in;
ir_node **res_projs;
const ir_edge_t *edge;
int *reg_param_idxs;
int *stack_param_idx;
- int i;
- int n;
+ int i, n, destroy_all_regs;
dbg_info *dbgi;
+ pset_new_init(&destroyed_regs);
+ pset_new_init(&states);
+
/* Let the isa fill out the abi description for that call node. */
arch_env_get_call_abi(arch_env, call_tp, call);
if (is_atomic_type(param_type)) {
ir_node *store;
ir_node *mem_input = do_seq ? curr_mem : new_NoMem();
- store = new_rd_Store(dbgi, irg, bl, mem_input, addr, param);
+ store = new_rd_Store(dbgi, irg, bl, mem_input, addr, param, 0);
mem = new_r_Proj(irg, bl, store, mode_M, pn_Store_M);
}
obstack_free(obst, in);
}
- /* Collect caller save registers */
+ /* check for the return_twice property */
+ destroy_all_regs = 0;
+ if (is_SymConst_addr_ent(call_ptr)) {
+ ir_entity *ent = get_SymConst_entity(call_ptr);
+
+ if (get_entity_additional_properties(ent) & mtp_property_returns_twice)
+ destroy_all_regs = 1;
+ } else {
+ ir_type *call_tp = get_Call_type(irn);
+
+ if (get_method_additional_properties(call_tp) & mtp_property_returns_twice)
+ destroy_all_regs = 1;
+ }
+
+ /* Put caller save into the destroyed set and state registers in the states set */
for (i = 0, n = arch_env_get_n_reg_class(arch_env); i < n; ++i) {
unsigned j;
const arch_register_class_t *cls = arch_env_get_reg_class(arch_env, i);
for (j = 0; j < cls->n_regs; ++j) {
const arch_register_t *reg = arch_register_for_index(cls, j);
- if (arch_register_type_is(reg, caller_save)) {
- pset_insert_ptr(caller_save, (void *) reg);
+
+ if (destroy_all_regs || arch_register_type_is(reg, caller_save)) {
+ if (! arch_register_type_is(reg, ignore))
+ pset_new_insert(&destroyed_regs, (void *) reg);
}
if (arch_register_type_is(reg, state)) {
- pset_insert_ptr(caller_save, (void*) reg);
- pset_insert_ptr(states, (void*) reg);
+ pset_new_insert(&destroyed_regs, (void*) reg);
+ pset_new_insert(&states, (void*) reg);
}
}
}
- /* search the greatest result proj number */
+ if (destroy_all_regs) {
+ /* even if destroyed all is specified, neither SP nor FP are destroyed (else bad things will happen) */
+ pset_new_remove(&destroyed_regs, arch_env->sp);
+ pset_new_remove(&destroyed_regs, arch_env->bp);
+ }
+ /* search the largest result proj number */
res_projs = ALLOCANZ(ir_node*, n_res);
foreach_out_edge(irn, edge) {
for (i = 0; i < n_reg_params; ++i) {
obstack_ptr_grow(obst, get_Call_param(irn, reg_param_idxs[i]));
}
- foreach_pset(states, reg) {
+
+ /* add state registers ins */
+ foreach_pset_new(&states, reg, iter) {
const arch_register_class_t *cls = arch_register_get_class(reg);
#if 0
ir_node *regnode = be_abi_reg_map_get(env->regs, reg);
ir_node *regnode = new_rd_Unknown(irg, arch_register_class_mode(cls));
obstack_ptr_grow(obst, regnode);
}
- n_ins = n_reg_params + pset_count(states);
+ n_ins = n_reg_params + pset_new_size(&states);
in = obstack_finish(obst);
+ /* ins collected, build the call */
if (env->call->flags.bits.call_has_imm && is_SymConst(call_ptr)) {
/* direct call */
low_call = be_new_Call(dbgi, irg, bl, curr_mem, curr_sp, curr_sp,
- n_reg_results + pn_be_Call_first_res + pset_count(caller_save),
+ n_reg_results + pn_be_Call_first_res + pset_new_size(&destroyed_regs),
n_ins, in, get_Call_type(irn));
be_Call_set_entity(low_call, get_SymConst_entity(call_ptr));
} else {
/* indirect call */
low_call = be_new_Call(dbgi, irg, bl, curr_mem, curr_sp, call_ptr,
- n_reg_results + pn_be_Call_first_res + pset_count(caller_save),
+ n_reg_results + pn_be_Call_first_res + pset_new_size(&destroyed_regs),
n_ins, in, get_Call_type(irn));
}
be_Call_set_pop(low_call, call->pop);
+
+ /* put the call into the list of all calls for later processing */
ARR_APP1(ir_node *, env->calls, low_call);
/* create new stack pointer */
arch_register_req_type_ignore | arch_register_req_type_produces_sp);
arch_set_irn_register(curr_sp, sp);
+ /* now handle results */
for (i = 0; i < n_res; ++i) {
int pn;
ir_node *proj = res_projs[i];
}
if (arg->in_reg) {
- pset_remove_ptr(caller_save, arg->reg);
+ pset_new_remove(&destroyed_regs, arg->reg);
}
}
/* Make additional projs for the caller save registers
and the Keep node which keeps them alive. */
- if (1 || pset_count(caller_save) + n_reg_results > 0) {
+ {
const arch_register_t *reg;
ir_node **in, *keep;
int i;
int n = 0;
- int curr_res_proj
- = pn_be_Call_first_res + n_reg_results;
+ int curr_res_proj = pn_be_Call_first_res + n_reg_results;
+ pset_new_iterator_t iter;
/* also keep the stack pointer */
++n;
set_irn_link(curr_sp, (void*) sp);
obstack_ptr_grow(obst, curr_sp);
- for (reg = pset_first(caller_save); reg; reg = pset_next(caller_save), ++n) {
- ir_node *proj = new_r_Proj(irg, bl, low_call, reg->reg_class->mode,
- curr_res_proj);
+ foreach_pset_new(&destroyed_regs, reg, iter) {
+ ir_node *proj = new_r_Proj(irg, bl, low_call, reg->reg_class->mode, curr_res_proj);
/* memorize the register in the link field. we need afterwards to set the register class of the keep correctly. */
be_set_constr_single_reg_out(low_call, curr_res_proj, reg, 0);
set_irn_link(proj, (void*) reg);
obstack_ptr_grow(obst, proj);
- curr_res_proj++;
+ ++curr_res_proj;
+ ++n;
}
for (i = 0; i < n_reg_results; ++i) {
be_abi_call_free(call);
obstack_free(obst, stack_param_idx);
- del_pset(results);
- del_pset(states);
- del_pset(caller_save);
+
+ pset_new_destroy(&states);
+ pset_new_destroy(&destroyed_regs);
return curr_sp;
}
mode = get_irn_mode(size);
tv = new_tarval_from_long(stack_alignment-1, mode);
- mask = new_r_Const(irg, mode, tv);
+ mask = new_r_Const(irg, tv);
size = new_rd_Add(dbg, irg, block, size, mask, mode);
tv = new_tarval_from_long(-(long)stack_alignment, mode);
- mask = new_r_Const(irg, mode, tv);
+ mask = new_r_Const(irg, tv);
size = new_rd_And(dbg, irg, block, size, mask, mode);
}
return size;
ir_mode *mode = get_irn_mode(size);
tarval *tv = new_tarval_from_long(get_type_size_bytes(type),
mode);
- ir_node *cnst = new_rd_Const(dbg, irg, mode, tv);
+ ir_node *cnst = new_rd_Const(dbg, irg, tv);
size = new_rd_Mul(dbg, irg, block, size, cnst, mode);
}
/* we might need to multiply the size with the element size */
if (type != firm_unknown_type && get_type_size_bytes(type) != 1) {
tarval *tv = new_tarval_from_long(get_type_size_bytes(type), mode_Iu);
- ir_node *cnst = new_rd_Const(dbg, irg, mode_Iu, tv);
+ ir_node *cnst = new_rd_Const(dbg, irg, tv);
ir_node *mul = new_rd_Mul(dbg, irg, block, get_Free_size(free),
cnst, mode_Iu);
size = mul;
}
set_irn_link(bl, curr_sp);
-} /* process_calls_in_block */
+} /* process_ops_in_block */
/**
* Adjust all call nodes in the graph to the ABI conventions.
/* the backing store itself */
store = new_r_Store(irg, first_bl, mem, addr,
- new_r_Proj(irg, args_bl, args, mode, i));
+ new_r_Proj(irg, args_bl, args, mode, i), 0);
}
/* the new memory Proj gets the last Proj from store */
set_Proj_pred(nmem, store);
}
}
-#if 1
/**
* The start block has no jump, instead it has an initial exec Proj.
* The backend wants to handle all blocks the same way, so we replace
* the out cfg edge with a real jump.
*/
-static void fix_start_block(ir_node *block, void *env) {
- int *done = env;
- int i;
- ir_node *start_block;
- ir_graph *irg;
+static void fix_start_block(ir_graph *irg) {
+ ir_node *initial_X = get_irg_initial_exec(irg);
+ ir_node *start_block = get_irg_start_block(irg);
+ const ir_edge_t *edge;
- /* we processed the start block, return */
- if (*done)
- return;
+ assert(is_Proj(initial_X));
- irg = get_irn_irg(block);
- start_block = get_irg_start_block(irg);
+ foreach_out_edge(initial_X, edge) {
+ ir_node *block = get_edge_src_irn(edge);
- for (i = get_Block_n_cfgpreds(block) - 1; i >= 0; --i) {
- ir_node *pred = get_Block_cfgpred(block, i);
- ir_node *pred_block = get_nodes_block(pred);
+ if (is_Anchor(block))
+ continue;
+ if (block != start_block) {
+ ir_node *jmp = new_r_Jmp(irg, start_block);
- /* ok, we are in the block, having start as cfg predecessor */
- if (pred_block == start_block) {
- ir_node *jump = new_r_Jmp(irg, pred_block);
- set_Block_cfgpred(block, i, jump);
- *done = 1;
+ set_Block_cfgpred(block, get_edge_src_pos(edge), jmp);
+ return;
}
}
+ panic("Initial exec has no follow block");
}
-#endif
/**
* Modify the irg itself and the frame type.
ir_mode *mode = get_type_mode(param_type);
ir_mode *load_mode = arg->load_mode;
- ir_node *load = new_r_Load(irg, reg_params_bl, new_NoMem(), addr, load_mode);
- set_irn_pinned(load, op_pin_state_floats);
+ ir_node *load = new_r_Load(irg, reg_params_bl, new_NoMem(), addr, load_mode, cons_floats);
repl = new_r_Proj(irg, reg_params_bl, load, load_mode, pn_Load_res);
if (mode != load_mode) {
obstack_free(&env->obst, args);
/* handle start block here (place a jump in the block) */
- i = 0;
- irg_block_walk_graph(irg, fix_start_block, NULL, &i);
+ fix_start_block(irg);
}
/** Fix the state inputs of calls that still hang on unknowns */
/* we need an extra indirection for global data outside our current
module. The loads are always safe and can therefore float
and need no memory input */
- load = new_r_Load(irg, block, new_NoMem(), add, mode);
+ load = new_r_Load(irg, block, new_NoMem(), add, mode, cons_floats);
load_res = new_r_Proj(irg, block, load, mode, pn_Load_res);
- set_irn_pinned(load, op_pin_state_floats);
set_irn_n(node, i, load_res);
}