X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fsparc%2Fsparc_emitter.c;h=9f78eafcdfdafb58d541e0f869a6159630e66958;hb=fc81b817119d8635eaeb345c8623255fc51bdb22;hp=07eef6137e5e6d277a69580e5753c5526c247b7c;hpb=e50e95fbed5212b07773f5a118ee338c814ff368;p=libfirm diff --git a/ir/be/sparc/sparc_emitter.c b/ir/be/sparc/sparc_emitter.c index 07eef6137..9f78eafcd 100644 --- a/ir/be/sparc/sparc_emitter.c +++ b/ir/be/sparc/sparc_emitter.c @@ -20,6 +20,7 @@ /** * @file * @brief emit assembler for a backend graph + * @author Hannes Rapp, Matthias Braun * @version $Id$ */ #include "config.h" @@ -39,6 +40,7 @@ #include "error.h" #include "raw_bitset.h" #include "dbginfo.h" +#include "heights.h" #include "../besched.h" #include "../beblocksched.h" @@ -46,6 +48,7 @@ #include "../begnuas.h" #include "../be_dbgout.h" #include "../benode.h" +#include "../bestack.h" #include "sparc_emitter.h" #include "gen_sparc_emitter.h" @@ -55,6 +58,12 @@ DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;) +static ir_heights_t *heights; +static const ir_node *delay_slot_filler; /**< this node has been choosen to fill + the next delay slot */ + +static void sparc_emit_node(const ir_node *node); + /** * Returns the register at in position pos. */ @@ -109,11 +118,6 @@ static const arch_register_t *get_out_reg(const ir_node *node, int pos) return reg; } -static bool is_valid_immediate(int32_t value) -{ - return -4096 <= value && value < 4096; -} - void sparc_emit_immediate(const ir_node *node) { const sparc_attr_t *attr = get_sparc_attr_const(node); @@ -121,7 +125,7 @@ void sparc_emit_immediate(const ir_node *node) if (entity == NULL) { int32_t value = attr->immediate_value; - assert(is_valid_immediate(value)); + assert(sparc_is_value_imm_encodeable(value)); be_emit_irprintf("%d", value); } else { be_emit_cstring("%lo("); @@ -172,22 +176,15 @@ void sparc_emit_dest_register(const ir_node *node, int pos) */ void sparc_emit_reg_or_imm(const ir_node *node, int pos) { - if (get_irn_arity(node) > pos) { - // we have reg input - sparc_emit_source_register(node, pos); - } else { + if (arch_irn_get_flags(node) & ((arch_irn_flags_t)sparc_arch_irn_flag_immediate_form)) { // we have a imm input sparc_emit_immediate(node); + } else { + // we have reg input + sparc_emit_source_register(node, pos); } } -static bool is_stack_pointer_relative(const ir_node *node) -{ - const arch_register_t *sp = &sparc_gp_regs[REG_SP]; - return (is_sparc_St(node) && get_in_reg(node, n_sparc_St_ptr) == sp) - || (is_sparc_Ld(node) && get_in_reg(node, n_sparc_Ld_ptr) == sp); -} - /** * emit SP offset */ @@ -203,12 +200,8 @@ void sparc_emit_offset(const ir_node *node, int offset_node_pos) sparc_emit_source_register(node, offset_node_pos); } else if (attr->is_frame_entity) { int32_t offset = attr->base.immediate_value; - /* bad hack: the real stack stuff is behind the always-there spill - * space for the register window and stack */ - if (is_stack_pointer_relative(node)) - offset += SPARC_MIN_STACKSIZE; if (offset != 0) { - assert(is_valid_immediate(offset)); + assert(sparc_is_value_imm_encodeable(offset)); be_emit_irprintf("%+ld", offset); } } else if (attr->base.immediate_value != 0 @@ -324,7 +317,7 @@ void sparc_emit_fp_mode_suffix(const ir_node *node) static ir_node *get_jump_target(const ir_node *jump) { - return get_irn_link(jump); + return (ir_node*)get_irn_link(jump); } /** @@ -336,12 +329,136 @@ static void sparc_emit_cfop_target(const ir_node *node) be_gas_emit_block_name(block); } +static int get_sparc_Call_dest_addr_pos(const ir_node *node) +{ + return get_irn_arity(node)-1; +} + +static bool ba_is_fallthrough(const ir_node *node) +{ + ir_node *block = get_nodes_block(node); + ir_node *next_block = (ir_node*)get_irn_link(block); + return get_irn_link(node) == next_block; +} + +static bool is_no_instruction(const ir_node *node) +{ + /* copies are nops if src_reg == dest_reg */ + if (be_is_Copy(node) || be_is_CopyKeep(node)) { + const arch_register_t *src_reg = get_in_reg(node, 0); + const arch_register_t *dest_reg = get_out_reg(node, 0); + + if (src_reg == dest_reg) + return true; + } + if (be_is_IncSP(node) && be_get_IncSP_offset(node) == 0) + return true; + /* Ba is not emitted if it is a simple fallthrough */ + if (is_sparc_Ba(node) && ba_is_fallthrough(node)) + return true; + + return be_is_Keep(node) || be_is_Start(node) || is_Phi(node); +} + +static bool has_delay_slot(const ir_node *node) +{ + if (is_sparc_Ba(node) && ba_is_fallthrough(node)) + return false; + + return is_sparc_Bicc(node) || is_sparc_fbfcc(node) || is_sparc_Ba(node) + || is_sparc_SwitchJmp(node) || is_sparc_Call(node) + || is_sparc_SDiv(node) || is_sparc_UDiv(node) + || be_is_Return(node); +} + +/** returns true if the emitter for this sparc node can produce more than one + * actual sparc instruction. + * Usually it is a bad sign if we have to add instructions here. We should + * rather try to get them lowered down. So we can actually put them into + * delay slots and make them more accessible to the scheduler. + */ +static bool emits_multiple_instructions(const ir_node *node) +{ + if (has_delay_slot(node)) + return true; + + return is_sparc_Mulh(node) || is_sparc_SDiv(node) || is_sparc_UDiv(node) + || be_is_MemPerm(node) || be_is_Perm(node); +} + /** - * Emit single entity + * search for an instruction that can fill the delay slot of @p node */ -static void sparc_emit_entity(ir_entity *entity) +static const ir_node *pick_delay_slot_for(const ir_node *node) { - be_gas_emit_entity(entity); + const ir_node *check = node; + const ir_node *schedpoint = node; + unsigned tries = 0; + /* currently we don't track which registers are still alive, so we can't + * pick any other instructions other than the one directly preceding */ + static const unsigned PICK_DELAY_SLOT_MAX_DISTANCE = 1; + + assert(has_delay_slot(node)); + + if (is_sparc_Call(node)) { + const sparc_attr_t *attr = get_sparc_attr_const(node); + ir_entity *entity = attr->immediate_value_entity; + if (entity != NULL) { + check = NULL; /* pick any instruction, dependencies on Call + don't matter */ + } else { + /* we only need to check the value for the call destination */ + check = get_irn_n(node, get_sparc_Call_dest_addr_pos(node)); + } + + /* the Call also destroys the value of %o7, but since this is currently + * marked as ignore register in the backend, it should never be used by + * the instruction in the delay slot. */ + } else if (be_is_Return(node)) { + /* we only have to check the jump destination value */ + int arity = get_irn_arity(node); + int i; + + check = NULL; + for (i = 0; i < arity; ++i) { + ir_node *in = get_irn_n(node, i); + const arch_register_t *reg = arch_get_irn_register(in); + if (reg == &sparc_registers[REG_O7]) { + check = skip_Proj(in); + break; + } + } + } else { + check = node; + } + + while (sched_has_prev(schedpoint)) { + schedpoint = sched_prev(schedpoint); + + if (has_delay_slot(schedpoint)) + break; + + /* skip things which don't really result in instructions */ + if (is_no_instruction(schedpoint)) + continue; + + if (tries++ >= PICK_DELAY_SLOT_MAX_DISTANCE) + break; + + if (emits_multiple_instructions(schedpoint)) + continue; + + /* allowed for delayslot: any instruction which is not necessary to + * compute an input to the branch. */ + if (check != NULL + && heights_reachable_in_block(heights, check, schedpoint)) + continue; + + /* found something */ + return schedpoint; + } + + return NULL; } /** @@ -349,39 +466,26 @@ static void sparc_emit_entity(ir_entity *entity) */ static void emit_be_IncSP(const ir_node *irn) { - int offs = -be_get_IncSP_offset(irn); + int offset = be_get_IncSP_offset(irn); - if (offs == 0) - return; + if (offset == 0) + return; /* SPARC stack grows downwards */ - if (offs < 0) { + if (offset < 0) { be_emit_cstring("\tsub "); - offs = -offs; + offset = -offset; } else { be_emit_cstring("\tadd "); } sparc_emit_source_register(irn, 0); - be_emit_irprintf(", %d", offs); + be_emit_irprintf(", %d", -offset); be_emit_cstring(", "); sparc_emit_dest_register(irn, 0); be_emit_finish_line_gas(irn); } -/** - * emits code for save instruction with min. required stack space - */ -static void emit_sparc_Save(const ir_node *irn) -{ - const sparc_save_attr_t *save_attr = get_sparc_save_attr_const(irn); - be_emit_cstring("\tsave "); - sparc_emit_source_register(irn, 0); - be_emit_irprintf(", %d, ", -save_attr->initial_stacksize); - sparc_emit_dest_register(irn, 0); - be_emit_finish_line_gas(irn); -} - /** * emits code for mulh */ @@ -407,8 +511,13 @@ static void emit_sparc_Mulh(const ir_node *irn) static void fill_delay_slot(void) { - be_emit_cstring("\tnop\n"); - be_emit_write_line(); + if (delay_slot_filler != NULL) { + sparc_emit_node(delay_slot_filler); + delay_slot_filler = NULL; + } else { + be_emit_cstring("\tnop\n"); + be_emit_write_line(); + } } static void emit_sparc_Div(const ir_node *node, bool is_signed) @@ -445,18 +554,6 @@ static void emit_sparc_UDiv(const ir_node *node) emit_sparc_Div(node, false); } -/** - * Emits code for return node - */ -static void emit_be_Return(const ir_node *irn) -{ - be_emit_cstring("\tret"); - //be_emit_cstring("\tjmp %i7+8"); - be_emit_finish_line_gas(irn); - be_emit_cstring("\trestore"); - be_emit_finish_line_gas(irn); -} - /** * Emits code for Call node */ @@ -467,14 +564,14 @@ static void emit_sparc_Call(const ir_node *node) be_emit_cstring("\tcall "); if (entity != NULL) { - sparc_emit_entity(entity); + be_gas_emit_entity(entity); if (attr->immediate_value != 0) { be_emit_irprintf("%+d", attr->immediate_value); } be_emit_cstring(", 0"); } else { - int last = get_irn_arity(node); - sparc_emit_source_register(node, last-1); + int dest_addr = get_sparc_Call_dest_addr_pos(node); + sparc_emit_source_register(node, dest_addr); } be_emit_finish_line_gas(node); @@ -511,9 +608,6 @@ static void emit_be_Perm(const ir_node *irn) be_emit_finish_line_gas(irn); } -/** - * TODO: not really tested but seems to work with memperm_arity == 1 - */ static void emit_be_MemPerm(const ir_node *node) { int i; @@ -570,24 +664,41 @@ static void emit_be_MemPerm(const ir_node *node) assert(sp_change == 0); } -/** - * Emits code for FrameAddr fix - */ +static void emit_be_Return(const ir_node *node) +{ + const char *destreg = "%o7"; + + /* hack: we don't explicitely model register changes because of the + * restore node. So we have to do it manually here */ + if (delay_slot_filler != NULL && + (is_sparc_Restore(delay_slot_filler) + || is_sparc_RestoreZero(delay_slot_filler))) { + destreg = "%i7"; + } + be_emit_cstring("\tjmp "); + be_emit_string(destreg); + be_emit_cstring("+8"); + be_emit_finish_line_gas(node); + fill_delay_slot(); +} + static void emit_sparc_FrameAddr(const ir_node *node) { - const sparc_attr_t *attr = get_sparc_attr_const(node); + const sparc_attr_t *attr = get_sparc_attr_const(node); + int32_t offset = attr->immediate_value; - // no need to fix offset as we are adressing via the framepointer - if (attr->immediate_value >= 0) { + if (offset < 0) { be_emit_cstring("\tadd "); sparc_emit_source_register(node, 0); be_emit_cstring(", "); - be_emit_irprintf("%ld", attr->immediate_value); + assert(sparc_is_value_imm_encodeable(offset)); + be_emit_irprintf("%ld", offset); } else { be_emit_cstring("\tsub "); sparc_emit_source_register(node, 0); be_emit_cstring(", "); - be_emit_irprintf("%ld", -attr->immediate_value); + assert(sparc_is_value_imm_encodeable(-offset)); + be_emit_irprintf("%ld", -offset); } be_emit_cstring(", "); @@ -595,70 +706,65 @@ static void emit_sparc_FrameAddr(const ir_node *node) be_emit_finish_line_gas(node); } -static const char *get_icc_unsigned(pn_Cmp pnc) +static const char *get_icc_unsigned(ir_relation relation) { - switch (pnc) { - case pn_Cmp_False: return "bn"; - case pn_Cmp_Eq: return "be"; - case pn_Cmp_Lt: return "blu"; - case pn_Cmp_Le: return "bleu"; - case pn_Cmp_Gt: return "bgu"; - case pn_Cmp_Ge: return "bgeu"; - case pn_Cmp_Lg: return "bne"; - case pn_Cmp_Leg: return "ba"; - default: panic("Cmp has unsupported pnc"); + switch (relation & (ir_relation_less_equal_greater)) { + case ir_relation_false: return "bn"; + case ir_relation_equal: return "be"; + case ir_relation_less: return "blu"; + case ir_relation_less_equal: return "bleu"; + case ir_relation_greater: return "bgu"; + case ir_relation_greater_equal: return "bgeu"; + case ir_relation_less_greater: return "bne"; + case ir_relation_less_equal_greater: return "ba"; + default: panic("Cmp has unsupported relation"); } } -static const char *get_icc_signed(pn_Cmp pnc) +static const char *get_icc_signed(ir_relation relation) { - switch (pnc) { - case pn_Cmp_False: return "bn"; - case pn_Cmp_Eq: return "be"; - case pn_Cmp_Lt: return "bl"; - case pn_Cmp_Le: return "ble"; - case pn_Cmp_Gt: return "bg"; - case pn_Cmp_Ge: return "bge"; - case pn_Cmp_Lg: return "bne"; - case pn_Cmp_Leg: return "ba"; - default: panic("Cmp has unsupported pnc"); + switch (relation & (ir_relation_less_equal_greater)) { + case ir_relation_false: return "bn"; + case ir_relation_equal: return "be"; + case ir_relation_less: return "bl"; + case ir_relation_less_equal: return "ble"; + case ir_relation_greater: return "bg"; + case ir_relation_greater_equal: return "bge"; + case ir_relation_less_greater: return "bne"; + case ir_relation_less_equal_greater: return "ba"; + default: panic("Cmp has unsupported relation"); } } -static const char *get_fcc(pn_Cmp pnc) +static const char *get_fcc(ir_relation relation) { - switch (pnc) { - case pn_Cmp_False: return "fbn"; - case pn_Cmp_Eq: return "fbe"; - case pn_Cmp_Lt: return "fbl"; - case pn_Cmp_Le: return "fble"; - case pn_Cmp_Gt: return "fbg"; - case pn_Cmp_Ge: return "fbge"; - case pn_Cmp_Lg: return "fblg"; - case pn_Cmp_Leg: return "fbo"; - case pn_Cmp_Uo: return "fbu"; - case pn_Cmp_Ue: return "fbue"; - case pn_Cmp_Ul: return "fbul"; - case pn_Cmp_Ule: return "fbule"; - case pn_Cmp_Ug: return "fbug"; - case pn_Cmp_Uge: return "fbuge"; - case pn_Cmp_Ne: return "fbne"; - case pn_Cmp_True: return "fba"; - case pn_Cmp_max: - break; + switch (relation) { + case ir_relation_false: return "fbn"; + case ir_relation_equal: return "fbe"; + case ir_relation_less: return "fbl"; + case ir_relation_less_equal: return "fble"; + case ir_relation_greater: return "fbg"; + case ir_relation_greater_equal: return "fbge"; + case ir_relation_less_greater: return "fblg"; + case ir_relation_less_equal_greater: return "fbo"; + case ir_relation_unordered: return "fbu"; + case ir_relation_unordered_equal: return "fbue"; + case ir_relation_unordered_less: return "fbul"; + case ir_relation_unordered_less_equal: return "fbule"; + case ir_relation_unordered_greater: return "fbug"; + case ir_relation_unordered_greater_equal: return "fbuge"; + case ir_relation_unordered_less_greater: return "fbne"; + case ir_relation_true: return "fba"; } - panic("invalid pnc"); + panic("invalid relation"); } -typedef const char* (*get_cc_func)(pn_Cmp pnc); +typedef const char* (*get_cc_func)(ir_relation relation); -/** - * Emits code for Branch - */ static void emit_sparc_branch(const ir_node *node, get_cc_func get_cc) { const sparc_jmp_cond_attr_t *attr = get_sparc_jmp_cond_attr_const(node); - pn_Cmp pnc = attr->pnc; + ir_relation relation = attr->relation; const ir_node *proj_true = NULL; const ir_node *proj_false = NULL; const ir_edge_t *edge; @@ -679,7 +785,7 @@ static void emit_sparc_branch(const ir_node *node, get_cc_func get_cc) block = get_nodes_block(node); /* we have a block schedule */ - next_block = get_irn_link(block); + next_block = (ir_node*)get_irn_link(block); if (get_irn_link(proj_true) == next_block) { /* exchange both proj's so the second one can be omitted */ @@ -687,16 +793,12 @@ static void emit_sparc_branch(const ir_node *node, get_cc_func get_cc) proj_true = proj_false; proj_false = t; - if (is_sparc_fbfcc(node)) { - pnc = get_negated_pnc(pnc, mode_F); - } else { - pnc = get_negated_pnc(pnc, mode_Iu); - } + relation = get_negated_relation(relation); } /* emit the true proj */ be_emit_cstring("\t"); - be_emit_string(get_cc(pnc)); + be_emit_string(get_cc(relation)); be_emit_char(' '); sparc_emit_cfop_target(proj_true); be_emit_finish_line_gas(proj_true); @@ -728,122 +830,53 @@ static void emit_sparc_fbfcc(const ir_node *node) emit_sparc_branch(node, get_fcc); } -/** - * emit Jmp (which actually is a branch always (ba) instruction) - */ static void emit_sparc_Ba(const ir_node *node) { - ir_node *block, *next_block; - - /* for now, the code works for scheduled and non-schedules blocks */ - block = get_nodes_block(node); - - /* we have a block schedule */ - next_block = get_irn_link(block); - if (get_irn_link(node) != next_block) { + if (ba_is_fallthrough(node)) { + be_emit_cstring("\t/* fallthrough to "); + sparc_emit_cfop_target(node); + be_emit_cstring(" */"); + } else { be_emit_cstring("\tba "); sparc_emit_cfop_target(node); be_emit_finish_line_gas(node); fill_delay_slot(); - } else { - be_emit_cstring("\t/* fallthrough to "); - sparc_emit_cfop_target(node); - be_emit_cstring(" */"); } be_emit_finish_line_gas(node); } -static void emit_jump_table(const ir_node *node) +static void emit_sparc_SwitchJmp(const ir_node *node) { const sparc_switch_jmp_attr_t *attr = get_sparc_switch_jmp_attr_const(node); - long switch_min = LONG_MAX; - long switch_max = LONG_MIN; - long default_pn = attr->default_proj_num; - ir_entity *entity = attr->jump_table; - ir_node *default_block = NULL; - unsigned length; - const ir_edge_t *edge; - unsigned i; - ir_node **table; - - /* go over all proj's and collect them */ - foreach_out_edge(node, edge) { - ir_node *proj = get_edge_src_irn(edge); - long pn = get_Proj_proj(proj); - - /* check for default proj */ - if (pn == default_pn) { - assert(default_block == NULL); /* more than 1 default_pn? */ - default_block = get_jump_target(proj); - } else { - switch_min = pn < switch_min ? pn : switch_min; - switch_max = pn > switch_max ? pn : switch_max; - } - } - length = (unsigned long) (switch_max - switch_min) + 1; - assert(switch_min < LONG_MAX || switch_max > LONG_MIN); - - table = XMALLOCNZ(ir_node*, length); - foreach_out_edge(node, edge) { - ir_node *proj = get_edge_src_irn(edge); - long pn = get_Proj_proj(proj); - if (pn == default_pn) - continue; - table[pn - switch_min] = get_jump_target(proj); - } - - /* emit table */ - be_gas_emit_switch_section(GAS_SECTION_RODATA); - be_emit_cstring("\t.align 4\n"); - be_gas_emit_entity(entity); - be_emit_cstring(":\n"); - for (i = 0; i < length; ++i) { - ir_node *block = table[i]; - if (block == NULL) - block = default_block; - be_emit_cstring("\t.long "); - be_gas_emit_block_name(block); - be_emit_char('\n'); - be_emit_write_line(); - } - be_gas_emit_switch_section(GAS_SECTION_TEXT); - - xfree(table); -} - -static void emit_sparc_SwitchJmp(const ir_node *node) -{ be_emit_cstring("\tjmp "); sparc_emit_source_register(node, 0); be_emit_finish_line_gas(node); fill_delay_slot(); - emit_jump_table(node); + emit_jump_table(node, attr->default_proj_num, attr->jump_table, + get_jump_target); } static void emit_fmov(const ir_node *node, const arch_register_t *src_reg, const arch_register_t *dst_reg) { - be_emit_cstring("\tfmov "); + be_emit_cstring("\tfmovs %"); be_emit_string(arch_register_get_name(src_reg)); - be_emit_cstring(", "); + be_emit_cstring(", %"); be_emit_string(arch_register_get_name(dst_reg)); be_emit_finish_line_gas(node); } static const arch_register_t *get_next_fp_reg(const arch_register_t *reg) { - unsigned index = reg->index; - assert(reg == &sparc_fp_regs[index]); - index++; - assert(index < N_sparc_fp_REGS); - return &sparc_fp_regs[index]; + unsigned idx = reg->global_index; + assert(reg == &sparc_registers[idx]); + idx++; + assert(idx - REG_F0 < N_sparc_fp_REGS); + return &sparc_registers[idx]; } -/** - * emit copy node - */ static void emit_be_Copy(const ir_node *node) { ir_mode *mode = get_irn_mode(node); @@ -874,23 +907,13 @@ static void emit_be_Copy(const ir_node *node) } } - -/** - * dummy emitter for ignored nodes - */ static void emit_nothing(const ir_node *irn) { (void) irn; } -/** - * type of emitter function - */ typedef void (*emit_func) (const ir_node *); -/** - * Set a node emitter. Make it a bit more type safe. - */ static inline void set_emitter(ir_op *op, emit_func sparc_emit_node) { op->ops.generic = (op_func)sparc_emit_node; @@ -920,13 +943,11 @@ static void sparc_register_emitters(void) set_emitter(op_sparc_fbfcc, emit_sparc_fbfcc); set_emitter(op_sparc_FrameAddr, emit_sparc_FrameAddr); set_emitter(op_sparc_Mulh, emit_sparc_Mulh); - set_emitter(op_sparc_Save, emit_sparc_Save); set_emitter(op_sparc_SDiv, emit_sparc_SDiv); set_emitter(op_sparc_SwitchJmp, emit_sparc_SwitchJmp); set_emitter(op_sparc_UDiv, emit_sparc_UDiv); /* no need to emit anything for the following nodes */ - set_emitter(op_be_Barrier, emit_nothing); set_emitter(op_be_Keep, emit_nothing); set_emitter(op_be_Start, emit_nothing); set_emitter(op_Phi, emit_nothing); @@ -944,33 +965,57 @@ static void sparc_emit_node(const ir_node *node) be_dbg_set_dbg_info(get_irn_dbg_info(node)); (*func) (node); } else { - panic("No emit handler for node %+F (graph %+F)\n", node, + panic("No emit handler for node %+F (graph %+F)\n", node, current_ir_graph); } } +static ir_node *find_next_delay_slot(ir_node *from) +{ + ir_node *schedpoint = from; + while (!has_delay_slot(schedpoint)) { + if (!sched_has_next(schedpoint)) + return NULL; + schedpoint = sched_next(schedpoint); + } + return schedpoint; +} + /** * Walks over the nodes in a block connected by scheduling edges * and emits code for each node. */ -static void sparc_gen_block(ir_node *block, void *data) +static void sparc_emit_block(ir_node *block) { ir_node *node; - (void) data; + ir_node *next_delay_slot; - if (! is_Block(block)) - return; + assert(is_Block(block)); be_gas_emit_block_name(block); be_emit_cstring(":\n"); be_emit_write_line(); + next_delay_slot = find_next_delay_slot(sched_first(block)); + if (next_delay_slot != NULL) + delay_slot_filler = pick_delay_slot_for(next_delay_slot); + sched_foreach(block, node) { + if (node == delay_slot_filler) { + continue; + } + sparc_emit_node(node); + + if (node == next_delay_slot) { + assert(delay_slot_filler == NULL); + next_delay_slot = find_next_delay_slot(sched_next(node)); + if (next_delay_slot != NULL) + delay_slot_filler = pick_delay_slot_for(next_delay_slot); + } } } - /** * Emits code for function start. */ @@ -996,11 +1041,6 @@ static void sparc_emit_func_epilog(ir_graph *irg) be_emit_write_line(); } -/** - * Block-walker: - * TODO: Sets labels for control flow nodes (jump target). - * Links control predecessors to there destination blocks. - */ static void sparc_gen_labels(ir_node *block, void *env) { ir_node *pred; @@ -1013,51 +1053,47 @@ static void sparc_gen_labels(ir_node *block, void *env) } } - -/** - * Main driver - */ -void sparc_gen_routine(const sparc_code_gen_t *cg, ir_graph *irg) +void sparc_emit_routine(ir_graph *irg) { - ir_node **blk_sched; - ir_node *last_block = NULL; - ir_entity *entity = get_irg_entity(irg); - int i, n; - (void) cg; + ir_entity *entity = get_irg_entity(irg); + ir_node **block_schedule; + size_t i; + size_t n; - be_gas_elf_type_char = '#'; + be_gas_elf_type_char = '#'; be_gas_object_file_format = OBJECT_FILE_FORMAT_ELF_SPARC; + heights = heights_new(irg); + /* register all emitter functions */ sparc_register_emitters(); be_dbg_method_begin(entity); /* create the block schedule. For now, we don't need it earlier. */ - blk_sched = be_create_block_schedule(irg); + block_schedule = be_create_block_schedule(irg); - // emit function prolog sparc_emit_func_prolog(irg); - - // generate BLOCK labels irg_block_walk_graph(irg, sparc_gen_labels, NULL, NULL); - // inject block scheduling links & emit code of each block - n = ARR_LEN(blk_sched); - for (i = 0; i < n;) { - ir_node *block, *next_bl; - - block = blk_sched[i]; - ++i; - next_bl = i < n ? blk_sched[i] : NULL; + /* inject block scheduling links & emit code of each block */ + n = ARR_LEN(block_schedule); + for (i = 0; i < n; ++i) { + ir_node *block = block_schedule[i]; + ir_node *next_block = i+1 < n ? block_schedule[i+1] : NULL; + set_irn_link(block, next_block); + } - /* set here the link. the emitter expects to find the next block here */ - set_irn_link(block, next_bl); - sparc_gen_block(block, last_block); - last_block = block; + for (i = 0; i < n; ++i) { + ir_node *block = block_schedule[i]; + if (block == get_irg_end_block(irg)) + continue; + sparc_emit_block(block); } - // emit function epilog + /* emit function epilog */ sparc_emit_func_epilog(irg); + + heights_free(heights); } void sparc_init_emitter(void)