+/*
+ _____ _ _ _ _ _
+ | ___| __ __ _ _ __ ___ ___ | | | | __ _ _ __ __| | (_)_ __ __ _
+ | |_ | '__/ _` | '_ ` _ \ / _ \ | |_| |/ _` | '_ \ / _` | | | '_ \ / _` |
+ | _|| | | (_| | | | | | | __/ | _ | (_| | | | | (_| | | | | | | (_| |
+ |_| |_| \__,_|_| |_| |_|\___| |_| |_|\__,_|_| |_|\__,_|_|_|_| |_|\__, |
+ |___/
+
+ Handling of the stack frame. It is composed of three types:
+ 1) The type of the arguments which are pushed on the stack.
+ 2) The "between type" which consists of stuff the call of the
+ function pushes on the stack (like the return address and
+ the old base pointer for ia32).
+ 3) The Firm frame type which consists of all local variables
+ and the spills.
+*/
+
+static int get_stack_entity_offset(be_stack_frame_t *frame, entity *ent, int bias)
+{
+ type *t = get_entity_owner(ent);
+ int ofs = get_entity_offset_bytes(ent);
+
+ int i, index;
+
+ /* Find the type the entity is contained in. */
+ for(index = 0; index < N_FRAME_TYPES; ++index) {
+ if(frame->order[index] == t)
+ break;
+ }
+
+ /* Add the size of all the types below the one of the entity to the entity's offset */
+ for(i = 0; i < index; ++i)
+ ofs += get_type_size_bytes(frame->order[i]);
+
+ /* correct the offset by the initial position of the frame pointer */
+ ofs -= frame->initial_offset;
+
+ /* correct the offset with the current bias. */
+ ofs += bias;
+
+ return ofs;
+}
+
+static entity *search_ent_with_offset(type *t, int offset)
+{
+ int i, n;
+
+ for(i = 0, n = get_class_n_members(t); i < n; ++i) {
+ entity *ent = get_class_member(t, i);
+ if(get_entity_offset_bytes(ent) == offset)
+ return ent;
+ }
+
+ return NULL;
+}
+
+static int stack_frame_compute_initial_offset(be_stack_frame_t *frame)
+{
+ type *base = frame->stack_dir < 0 ? frame->between_type : frame->frame_type;
+ entity *ent = search_ent_with_offset(base, 0);
+ frame->initial_offset = 0;
+ frame->initial_offset = get_stack_entity_offset(frame, ent, 0);
+ return frame->initial_offset;
+}
+
+static be_stack_frame_t *stack_frame_init(be_stack_frame_t *frame, type *args, type *between, type *locals, int stack_dir)
+{
+ frame->arg_type = args;
+ frame->between_type = between;
+ frame->frame_type = locals;
+ frame->initial_offset = 0;
+ frame->stack_dir = stack_dir;
+ frame->order[1] = between;
+
+ if(stack_dir > 0) {
+ frame->order[0] = args;
+ frame->order[2] = locals;
+ }
+
+ else {
+ frame->order[0] = locals;
+ frame->order[2] = args;
+ }
+
+ return frame;
+}
+
+static void stack_frame_dump(FILE *file, be_stack_frame_t *frame)
+{
+ int i, j, n;
+
+ ir_fprintf(file, "initial offset: %d\n", frame->initial_offset);
+ for(j = 0; j < N_FRAME_TYPES; ++j) {
+ type *t = frame->order[j];
+
+ ir_fprintf(file, "type %d: %Fm size: %d\n", j, t, get_type_size_bytes(t));
+ for(i = 0, n = get_class_n_members(t); i < n; ++i) {
+ entity *ent = get_class_member(t, i);
+ ir_fprintf(file, "\t%F int ofs: %d glob ofs: %d\n", ent, get_entity_offset_bytes(ent), get_stack_entity_offset(frame, ent, 0));
+ }
+ }
+}
+
+/**
+ * If irn is a Sel node computing the address of an entity
+ * on the frame type return the entity, else NULL.
+ */
+static INLINE entity *get_sel_ent(ir_node *irn)
+{
+ if(get_irn_opcode(irn) == iro_Sel
+ && get_Sel_ptr(irn) == get_irg_frame(get_irn_irg(irn))) {
+
+ return get_Sel_entity(irn);
+ }
+
+ return NULL;
+}
+
+/**
+ * Walker: Replaces Loads, Stores and Sels of frame type entities
+ * by FrameLoad, FrameStore and FrameAdress.
+ */
+static void lower_frame_sels_walker(ir_node *irn, void *data)
+{
+ const arch_register_class_t *cls;
+ be_abi_irg_t *env = data;
+ const arch_isa_t *isa = env->birg->main_env->arch_env->isa;
+ ir_graph *irg = get_irn_irg(irn);
+ ir_node *frame = get_irg_frame(irg);
+ ir_node *nw = NULL;
+ opcode opc = get_irn_opcode(irn);
+
+ if(opc == iro_Load) {
+ ir_node *bl = get_nodes_block(irn);
+ ir_node *sel = get_Load_ptr(irn);
+ entity *ent = get_sel_ent(sel);
+ cls = arch_isa_get_reg_class_for_mode(isa, get_Load_mode(irn));
+ if(ent != NULL)
+ nw = be_new_FrameLoad(isa->sp->reg_class, cls, irg, bl, get_Load_mem(irn), frame, ent);
+ }
+
+ else if(opc == iro_Store) {
+ ir_node *bl = get_nodes_block(irn);
+ ir_node *val = get_Store_value(irn);
+ ir_node *sel = get_Store_ptr(irn);
+ entity *ent = get_sel_ent(sel);
+ cls = arch_isa_get_reg_class_for_mode(isa, get_irn_mode(val));
+ if(ent != NULL)
+ nw = be_new_FrameStore(isa->sp->reg_class, cls, irg, bl, get_Store_mem(irn), frame, val, ent);
+ }
+
+ else {
+ entity *ent = get_sel_ent(irn);
+ if(ent != NULL) {
+ ir_node *bl = get_nodes_block(irn);
+ nw = be_new_FrameAddr(isa->sp->reg_class, irg, bl, frame, ent);
+ }
+ }
+
+ if(nw != NULL)
+ exchange(irn, nw);
+}
+