some cleanups for middleend node creation in backends
[libfirm] / ir / be / sparc / sparc_emitter.c
index cdb1e57..413b59a 100644 (file)
@@ -64,60 +64,6 @@ static const ir_node *delay_slot_filler; /**< this node has been choosen to fill
 
 static void sparc_emit_node(const ir_node *node);
 
-/**
- * Returns the register at in position pos.
- */
-static const arch_register_t *get_in_reg(const ir_node *node, int pos)
-{
-       ir_node                *op;
-       const arch_register_t  *reg = NULL;
-
-       assert(get_irn_arity(node) > pos && "Invalid IN position");
-
-       /* The out register of the operator at position pos is the
-          in register we need. */
-       op = get_irn_n(node, pos);
-
-       reg = arch_get_irn_register(op);
-
-       assert(reg && "no in register found");
-       return reg;
-}
-
-/**
- * Returns the register at out position pos.
- */
-static const arch_register_t *get_out_reg(const ir_node *node, int pos)
-{
-       ir_node                *proj;
-       const arch_register_t  *reg = NULL;
-
-       /* 1st case: irn is not of mode_T, so it has only                 */
-       /*           one OUT register -> good                             */
-       /* 2nd case: irn is of mode_T -> collect all Projs and ask the    */
-       /*           Proj with the corresponding projnum for the register */
-
-       if (get_irn_mode(node) != mode_T) {
-               reg = arch_get_irn_register(node);
-       } else if (is_sparc_irn(node)) {
-               reg = arch_irn_get_register(node, pos);
-       } else {
-               const ir_edge_t *edge;
-
-               foreach_out_edge(node, edge) {
-                       proj = get_edge_src_irn(edge);
-                       assert(is_Proj(proj) && "non-Proj from mode_T node");
-                       if (get_Proj_proj(proj) == pos) {
-                               reg = arch_get_irn_register(proj);
-                               break;
-                       }
-               }
-       }
-
-       assert(reg && "no out register found");
-       return reg;
-}
-
 void sparc_emit_immediate(const ir_node *node)
 {
        const sparc_attr_t *attr   = get_sparc_attr_const(node);
@@ -128,7 +74,11 @@ void sparc_emit_immediate(const ir_node *node)
                assert(sparc_is_value_imm_encodeable(value));
                be_emit_irprintf("%d", value);
        } else {
-               be_emit_cstring("%lo(");
+               if (get_entity_owner(entity) == get_tls_type()) {
+                       be_emit_cstring("%tle_lox10(");
+               } else {
+                       be_emit_cstring("%lo(");
+               }
                be_gas_emit_entity(entity);
                if (attr->immediate_value != 0) {
                        be_emit_irprintf("%+d", attr->immediate_value);
@@ -142,29 +92,33 @@ void sparc_emit_high_immediate(const ir_node *node)
        const sparc_attr_t *attr   = get_sparc_attr_const(node);
        ir_entity          *entity = attr->immediate_value_entity;
 
-       be_emit_cstring("%hi(");
        if (entity == NULL) {
                uint32_t value = (uint32_t) attr->immediate_value;
-               be_emit_irprintf("0x%X", value);
+               be_emit_irprintf("%%hi(0x%X)", value);
        } else {
+               if (get_entity_owner(entity) == get_tls_type()) {
+                       be_emit_cstring("%tle_hix22(");
+               } else {
+                       be_emit_cstring("%hi(");
+               }
                be_gas_emit_entity(entity);
                if (attr->immediate_value != 0) {
                        be_emit_irprintf("%+d", attr->immediate_value);
                }
+               be_emit_char(')');
        }
-       be_emit_char(')');
 }
 
 void sparc_emit_source_register(const ir_node *node, int pos)
 {
-       const arch_register_t *reg = get_in_reg(node, pos);
+       const arch_register_t *reg = arch_get_irn_register_in(node, pos);
        be_emit_char('%');
        be_emit_string(arch_register_get_name(reg));
 }
 
 void sparc_emit_dest_register(const ir_node *node, int pos)
 {
-       const arch_register_t *reg = get_out_reg(node, pos);
+       const arch_register_t *reg = arch_get_irn_register_out(node, pos);
        be_emit_char('%');
        be_emit_string(arch_register_get_name(reg));
 }
@@ -176,7 +130,7 @@ void sparc_emit_dest_register(const ir_node *node, int pos)
  */
 void sparc_emit_reg_or_imm(const ir_node *node, int pos)
 {
-       if (arch_irn_get_flags(node) & ((arch_irn_flags_t)sparc_arch_irn_flag_immediate_form)) {
+       if (arch_get_irn_flags(node) & ((arch_irn_flags_t)sparc_arch_irn_flag_immediate_form)) {
                // we have a imm input
                sparc_emit_immediate(node);
        } else {
@@ -268,16 +222,6 @@ void sparc_emit_store_mode(const ir_node *node)
        }
 }
 
-/**
- * emit integer signed/unsigned prefix char
- */
-void sparc_emit_mode_sign_prefix(const ir_node *node)
-{
-       ir_mode *mode      = get_irn_mode(node);
-       bool     is_signed = mode_is_signed(mode);
-       be_emit_string(is_signed ? "s" : "u");
-}
-
 static void emit_fp_suffix(const ir_mode *mode)
 {
        unsigned bits = get_mode_size_bits(mode);
@@ -345,8 +289,8 @@ 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);
+               const arch_register_t *src_reg  = arch_get_irn_register_in(node, 0);
+               const arch_register_t *dest_reg = arch_get_irn_register_out(node, 0);
 
                if (src_reg == dest_reg)
                        return true;
@@ -382,7 +326,12 @@ 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)
+       if (is_sparc_Call(node)) {
+               return arch_get_irn_flags(node) & sparc_arch_irn_flag_aggregate_return;
+       }
+
+       return is_sparc_SMulh(node) || is_sparc_UMulh(node)
+               || is_sparc_SDiv(node) || is_sparc_UDiv(node)
                || be_is_MemPerm(node) || be_is_Perm(node);
 }
 
@@ -448,6 +397,11 @@ static const ir_node *pick_delay_slot_for(const ir_node *node)
                if (emits_multiple_instructions(schedpoint))
                        continue;
 
+               /* if check and schedpoint are not in the same block, give up. */
+               if (check != NULL
+                               && get_nodes_block(check) != get_nodes_block(schedpoint))
+                       break;
+
                /* allowed for delayslot: any instruction which is not necessary to
                 * compute an input to the branch. */
                if (check != NULL
@@ -492,7 +446,12 @@ static void emit_be_IncSP(const ir_node *irn)
 static void emit_sparc_Mulh(const ir_node *irn)
 {
        be_emit_cstring("\t");
-       sparc_emit_mode_sign_prefix(irn);
+       if (is_sparc_UMulh(irn)) {
+               be_emit_char('u');
+       } else {
+               assert(is_sparc_SMulh(irn));
+               be_emit_char('s');
+       }
        be_emit_cstring("mul ");
 
        sparc_emit_source_register(irn, 0);
@@ -576,6 +535,11 @@ static void emit_sparc_Call(const ir_node *node)
        be_emit_finish_line_gas(node);
 
        fill_delay_slot();
+
+       if (arch_get_irn_flags(node) & sparc_arch_irn_flag_aggregate_return) {
+               be_emit_cstring("\tunimp 8\n");
+               be_emit_write_line();
+       }
 }
 
 /**
@@ -666,6 +630,10 @@ static void emit_be_MemPerm(const ir_node *node)
 
 static void emit_sparc_Return(const ir_node *node)
 {
+       ir_graph  *irg    = get_irn_irg(node);
+       ir_entity *entity = get_irg_entity(irg);
+       ir_type   *type   = get_entity_type(entity);
+
        const char *destreg = "%o7";
 
        /* hack: we don't explicitely model register changes because of the
@@ -677,7 +645,11 @@ static void emit_sparc_Return(const ir_node *node)
        }
        be_emit_cstring("\tjmp ");
        be_emit_string(destreg);
-       be_emit_cstring("+8");
+       if (get_method_calling_convention(type) & cc_compound_ret) {
+               be_emit_cstring("+12");
+       } else {
+               be_emit_cstring("+8");
+       }
        be_emit_finish_line_gas(node);
        fill_delay_slot();
 }
@@ -827,6 +799,19 @@ static void emit_sparc_Bicc(const ir_node *node)
 
 static void emit_sparc_fbfcc(const ir_node *node)
 {
+       /* if the flags producing node was immediately in front of us, emit
+        * a nop */
+       ir_node *flags = get_irn_n(node, n_sparc_fbfcc_flags);
+       ir_node *prev  = sched_prev(node);
+       if (is_Block(prev)) {
+               /* TODO: when the flags come from another block, then we have to do
+                * more complicated tests to see wether the flag producing node is
+                * potentially in front of us (could happen for fallthroughs) */
+               panic("TODO: fbfcc flags come from other block");
+       }
+       if (skip_Proj(flags) == prev) {
+               be_emit_cstring("\tnop\n");
+       }
        emit_sparc_branch(node, get_fcc);
 }
 
@@ -880,8 +865,8 @@ static const arch_register_t *get_next_fp_reg(const arch_register_t *reg)
 static void emit_be_Copy(const ir_node *node)
 {
        ir_mode               *mode    = get_irn_mode(node);
-       const arch_register_t *src_reg = get_in_reg(node, 0);
-       const arch_register_t *dst_reg = get_out_reg(node, 0);
+       const arch_register_t *src_reg = arch_get_irn_register_in(node, 0);
+       const arch_register_t *dst_reg = arch_get_irn_register_out(node, 0);
 
        if (src_reg == dst_reg)
                return;
@@ -941,7 +926,8 @@ static void sparc_register_emitters(void)
        set_emitter(op_sparc_Call,      emit_sparc_Call);
        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_SMulh,     emit_sparc_Mulh);
+       set_emitter(op_sparc_UMulh,     emit_sparc_Mulh);
        set_emitter(op_sparc_Return,    emit_sparc_Return);
        set_emitter(op_sparc_SDiv,      emit_sparc_SDiv);
        set_emitter(op_sparc_SwitchJmp, emit_sparc_SwitchJmp);
@@ -1060,9 +1046,6 @@ void sparc_emit_routine(ir_graph *irg)
        size_t      i;
        size_t      n;
 
-       be_gas_elf_type_char      = '#';
-       be_gas_object_file_format = OBJECT_FILE_FORMAT_ELF_SPARC;
-
        heights = heights_new(irg);
 
        /* register all emitter functions */