X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fsparc%2Fsparc_emitter.c;h=9340fc72b446110514911c765666b0cc3fd25b69;hb=0929d78922b3e96f37ede5aeace5d2e413d15c63;hp=f796857d8792b757a8a13404aba0e48b0484fe17;hpb=b24c359be385d38d535efe35df5a937a8ee9cc0c;p=libfirm diff --git a/ir/be/sparc/sparc_emitter.c b/ir/be/sparc/sparc_emitter.c index f796857d8..9340fc72b 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" @@ -332,7 +333,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); } /** @@ -352,7 +353,7 @@ static int get_sparc_Call_dest_addr_pos(const ir_node *node) static bool ba_is_fallthrough(const ir_node *node) { ir_node *block = get_nodes_block(node); - ir_node *next_block = get_irn_link(block); + ir_node *next_block = (ir_node*)get_irn_link(block); return get_irn_link(node) == next_block; } @@ -366,12 +367,13 @@ static bool is_no_instruction(const ir_node *node) 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_Barrier(node) || be_is_Start(node) - || is_Phi(node); + return be_is_Keep(node) || be_is_Start(node) || is_Phi(node); } static bool has_delay_slot(const ir_node *node) @@ -381,7 +383,8 @@ static bool has_delay_slot(const ir_node *node) 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); + || 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 @@ -396,7 +399,7 @@ static bool emits_multiple_instructions(const ir_node *node) return true; return is_sparc_Mulh(node) || is_sparc_SDiv(node) || is_sparc_UDiv(node) - || be_is_MemPerm(node) || be_is_Perm(node) || be_is_Return(node); + || be_is_MemPerm(node) || be_is_Perm(node); } /** @@ -427,6 +430,20 @@ static const ir_node *pick_delay_slot_for(const ir_node *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; } @@ -434,9 +451,6 @@ static const ir_node *pick_delay_slot_for(const ir_node *node) while (sched_has_prev(schedpoint)) { schedpoint = sched_prev(schedpoint); - if (tries++ >= PICK_DELAY_SLOT_MAX_DISTANCE) - break; - if (has_delay_slot(schedpoint)) break; @@ -444,6 +458,9 @@ static const ir_node *pick_delay_slot_for(const ir_node *node) if (is_no_instruction(schedpoint)) continue; + if (tries++ >= PICK_DELAY_SLOT_MAX_DISTANCE) + break; + if (emits_multiple_instructions(schedpoint)) continue; @@ -485,19 +502,6 @@ static void emit_be_IncSP(const ir_node *irn) 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 */ @@ -566,18 +570,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 */ @@ -688,6 +680,24 @@ static void emit_be_MemPerm(const ir_node *node) assert(sp_change == 0); } +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); @@ -710,67 +720,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); 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; @@ -791,7 +799,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 */ @@ -799,16 +807,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); @@ -941,7 +945,7 @@ static void emit_fmov(const ir_node *node, const arch_register_t *src_reg, static const arch_register_t *get_next_fp_reg(const arch_register_t *reg) { - unsigned index = reg->index; + unsigned index = reg->global_index; assert(reg == &sparc_registers[index]); index++; assert(index - REG_F0 < N_sparc_fp_REGS); @@ -1014,13 +1018,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); @@ -1130,8 +1132,8 @@ void sparc_emit_routine(ir_graph *irg) { ir_entity *entity = get_irg_entity(irg); ir_node **block_schedule; - int i; - int n; + size_t i; + size_t n; be_gas_elf_type_char = '#'; be_gas_object_file_format = OBJECT_FILE_FORMAT_ELF_SPARC;