X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fsparc%2Fsparc_emitter.c;h=d55c6daa910880b89fece2217559b9fcfc6e89c9;hb=b151d11c50d89b9dffadfb63f7ccfd81ea8db44f;hp=427b89e1628a99a481726563f900168eec8958a2;hpb=222011a88ba00fbcc3a8a572a5c3ad09871f6437;p=libfirm diff --git a/ir/be/sparc/sparc_emitter.c b/ir/be/sparc/sparc_emitter.c index 427b89e16..d55c6daa9 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" @@ -47,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" @@ -116,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); @@ -128,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("); @@ -188,13 +185,6 @@ void sparc_emit_reg_or_imm(const ir_node *node, int 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 */ @@ -210,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 @@ -331,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); } /** @@ -351,7 +337,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; } @@ -365,12 +351,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) @@ -380,7 +367,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 @@ -395,7 +383,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); } /** @@ -426,6 +414,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; } @@ -433,9 +435,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; @@ -443,6 +442,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; @@ -464,39 +466,26 @@ static const ir_node *pick_delay_slot_for(const ir_node *node) */ 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) + 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 */ @@ -565,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 */ @@ -687,21 +664,41 @@ 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); + 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(", "); @@ -709,67 +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); 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; @@ -790,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 */ @@ -798,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); @@ -857,12 +848,11 @@ static void emit_sparc_Ba(const ir_node *node) static void emit_jump_table(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; + unsigned long length; const ir_edge_t *edge; unsigned i; ir_node **table; @@ -877,12 +867,18 @@ static void emit_jump_table(const ir_node *node) 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); + assert(switch_max > LONG_MIN); + + length = (unsigned long) switch_max + 1; + /* the 16000 isn't a real limit of the architecture. But should protect us + * from seamingly endless compiler runs */ + if (length > 16000) { + /* switch lowerer should have broken this monster to pieces... */ + panic("too large switch encountered"); + } table = XMALLOCNZ(ir_node*, length); foreach_out_edge(node, edge) { @@ -891,7 +887,7 @@ static void emit_jump_table(const ir_node *node) if (pn == default_pn) continue; - table[pn - switch_min] = get_jump_target(proj); + table[pn] = get_jump_target(proj); } /* emit table */ @@ -926,20 +922,20 @@ static void emit_sparc_SwitchJmp(const ir_node *node) 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]); + unsigned index = reg->global_index; + assert(reg == &sparc_registers[index]); index++; - assert(index < N_sparc_fp_REGS); - return &sparc_fp_regs[index]; + assert(index - REG_F0 < N_sparc_fp_REGS); + return &sparc_registers[index]; } static void emit_be_Copy(const ir_node *node) @@ -1008,13 +1004,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); @@ -1032,7 +1026,7 @@ 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); } } @@ -1124,8 +1118,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;