first implementation of floatingpoint arithmetic operations
[libfirm] / ir / be / sparc / sparc_emitter.c
index 2e72bae..898605d 100644 (file)
 #include "sparc_new_nodes.h"
 #include "gen_sparc_regalloc_if.h"
 
-
-#define SNPRINTF_BUF_LEN 128
 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
 
-/**
- * attribute of SAVE node which follows immediatelly after the START node
- * we need this to correct all offsets since SPARC expects
- * some reserved stack space after the stackpointer
- */
-const sparc_save_attr_t *save_attr;
-
 /**
  * Returns the register at in position pos.
  */
@@ -118,22 +109,11 @@ static const arch_register_t *get_out_reg(const ir_node *node, int pos)
        return reg;
 }
 
-/*************************************************************
- *             _       _    __   _          _
- *            (_)     | |  / _| | |        | |
- *  _ __  _ __ _ _ __ | |_| |_  | |__   ___| |_ __   ___ _ __
- * | '_ \| '__| | '_ \| __|  _| | '_ \ / _ \ | '_ \ / _ \ '__|
- * | |_) | |  | | | | | |_| |   | | | |  __/ | |_) |  __/ |
- * | .__/|_|  |_|_| |_|\__|_|   |_| |_|\___|_| .__/ \___|_|
- * | |                                       | |
- * |_|                                       |_|
- *************************************************************/
-
 void sparc_emit_immediate(const ir_node *node)
 {
-       const sparc_attr_t *attr = get_sparc_attr_const(node);
-       assert(-4096 <= attr->immediate_value && attr->immediate_value < 4096);
-       be_emit_irprintf("%d", attr->immediate_value);
+       int const val = get_sparc_attr_const(node)->immediate_value;
+       assert(-4096 <= val && val < 4096);
+       be_emit_irprintf("%d", val);
 }
 
 void sparc_emit_source_register(const ir_node *node, int pos)
@@ -166,16 +146,28 @@ 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
  */
 void sparc_emit_offset(const ir_node *node)
 {
        const sparc_load_store_attr_t *attr = get_sparc_load_store_attr_const(node);
-       assert(attr->base.is_load_store);
-
-       if (attr->offset > 0)
-               be_emit_irprintf("+%ld", attr->offset);
+       long                           offset = attr->offset;
+
+       /* 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) {
+               be_emit_irprintf("%+ld", offset);
+       }
 }
 
 
@@ -185,19 +177,19 @@ void sparc_emit_offset(const ir_node *node)
 void sparc_emit_load_mode(const ir_node *node)
 {
        const sparc_load_store_attr_t *attr = get_sparc_load_store_attr_const(node);
-    ir_mode *mode      = attr->load_store_mode;
-    int      bits      = get_mode_size_bits(mode);
-    bool     is_signed = mode_is_signed(mode);
-
-    if (bits == 16) {
-        be_emit_string(is_signed ? "sh" : "uh");
-    } else if (bits == 8) {
-        be_emit_string(is_signed ? "sb" : "ub");
-    } else if (bits == 64) {
-        be_emit_string("d");
-    } else {
-        assert(bits == 32);
-    }
+       ir_mode *mode      = attr->load_store_mode;
+       int      bits      = get_mode_size_bits(mode);
+       bool     is_signed = mode_is_signed(mode);
+
+       if (bits == 16) {
+               be_emit_string(is_signed ? "sh" : "uh");
+       } else if (bits == 8) {
+               be_emit_string(is_signed ? "sb" : "ub");
+       } else if (bits == 64) {
+               be_emit_string("d");
+       } else {
+               assert(bits == 32);
+       }
 }
 
 /**
@@ -206,18 +198,18 @@ void sparc_emit_load_mode(const ir_node *node)
 void sparc_emit_store_mode(const ir_node *node)
 {
        const sparc_load_store_attr_t *attr = get_sparc_load_store_attr_const(node);
-    ir_mode *mode      = attr->load_store_mode;
-    int      bits      = get_mode_size_bits(mode);
-
-    if (bits == 16) {
-        be_emit_string("h");
-    } else if (bits == 8) {
-        be_emit_string("b");
-    } else if (bits == 64) {
-        be_emit_string("d");
-    } else {
-        assert(bits == 32);
-    }
+       ir_mode *mode      = attr->load_store_mode;
+       int      bits      = get_mode_size_bits(mode);
+
+       if (bits == 16) {
+               be_emit_string("h");
+       } else if (bits == 8) {
+               be_emit_string("b");
+       } else if (bits == 64) {
+               be_emit_string("d");
+       } else {
+               assert(bits == 32);
+       }
 }
 
 /**
@@ -225,49 +217,37 @@ void sparc_emit_store_mode(const ir_node *node)
  */
 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");
+       ir_mode *mode      = get_irn_mode(node);
+       bool     is_signed = mode_is_signed(mode);
+       be_emit_string(is_signed ? "s" : "u");
 }
 
-/**
- * emit FP load mode char
- */
-void sparc_emit_fp_load_mode(const ir_node *node)
+static void emit_fp_suffix(const ir_mode *mode)
 {
-       const sparc_load_store_attr_t *attr = get_sparc_load_store_attr_const(node);
-    ir_mode *mode      = attr->load_store_mode;
-    int      bits      = get_mode_size_bits(mode);
-
-    assert(mode_is_float(mode));
+       unsigned bits = get_mode_size_bits(mode);
+       assert(mode_is_float(mode));
 
-    if (bits == 32) {
-        be_emit_string("f");
-    } else if (bits == 64) {
-        be_emit_string("df");
-    } else {
-               panic("FP load mode > 64bits not implemented yet");
-    }
+       if (bits == 32) {
+               be_emit_char('s');
+       } else if (bits == 64) {
+               be_emit_char('d');
+       } else if (bits == 128) {
+               be_emit_char('q');
+       } else {
+               panic("invalid FP mode");
+       }
 }
 
-/**
- * emit FP store mode char
- */
-void sparc_emit_fp_store_mode(const ir_node *node)
+void sparc_emit_fp_conv_source(const ir_node *node)
 {
-       const sparc_load_store_attr_t *attr = get_sparc_load_store_attr_const(node);
-    ir_mode *mode      = attr->load_store_mode;
-    int      bits      = get_mode_size_bits(mode);
-
-    assert(mode_is_float(mode));
+       const sparc_fp_conv_attr_t *attr = get_sparc_fp_conv_attr_const(node);
+       emit_fp_suffix(attr->src_mode);
+}
 
-    if (bits == 32) {
-        be_emit_string("f");
-    } else if (bits == 64) {
-        be_emit_string("df");
-    } else {
-               panic("FP store mode > 64bits not implemented yet");
-    }
+void sparc_emit_fp_conv_destination(const ir_node *node)
+{
+       const sparc_fp_conv_attr_t *attr = get_sparc_fp_conv_attr_const(node);
+       emit_fp_suffix(attr->dest_mode);
 }
 
 /**
@@ -275,18 +255,8 @@ void sparc_emit_fp_store_mode(const ir_node *node)
  */
 void sparc_emit_fp_mode_suffix(const ir_node *node)
 {
-    ir_mode *mode      = get_irn_mode(node);
-    int      bits      = get_mode_size_bits(mode);
-
-    assert(mode_is_float(mode));
-
-    if (bits == 32) {
-               be_emit_string("s");
-    } else if (bits == 64) {
-               be_emit_string("d");
-    } else {
-               panic("FP mode > 64bits not implemented yet");
-    }
+       const sparc_fp_attr_t *attr = get_sparc_fp_attr_const(node);
+       emit_fp_suffix(attr->fp_mode);
 }
 
 /**
@@ -306,17 +276,6 @@ static void sparc_emit_entity(ir_entity *entity)
        be_gas_emit_entity(entity);
 }
 
-/***********************************************************************************
- *                  _          __                                             _
- *                 (_)        / _|                                           | |
- *  _ __ ___   __ _ _ _ __   | |_ _ __ __ _ _ __ ___   _____      _____  _ __| | __
- * | '_ ` _ \ / _` | | '_ \  |  _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
- * | | | | | | (_| | | | | | | | | | | (_| | | | | | |  __/\ V  V / (_) | |  |   <
- * |_| |_| |_|\__,_|_|_| |_| |_| |_|  \__,_|_| |_| |_|\___| \_/\_/ \___/|_|  |_|\_\
- *
- ***********************************************************************************/
-
-
 /**
  * Emits code for stack space management
  */
@@ -347,7 +306,7 @@ static void emit_be_IncSP(const ir_node *irn)
  */
 static void emit_sparc_Save(const ir_node *irn)
 {
-       save_attr = get_sparc_save_attr_const(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);
@@ -380,40 +339,6 @@ static void emit_sparc_LoImm(const ir_node *irn)
        be_emit_finish_line_gas(irn);
 }
 
-/**
- * emit code for div with the correct sign prefix
- */
-static void emit_sparc_Div(const ir_node *irn)
-{
-       be_emit_cstring("\t");
-       sparc_emit_mode_sign_prefix(irn);
-       be_emit_cstring("div ");
-
-       sparc_emit_source_register(irn, 0);
-       be_emit_cstring(", ");
-       sparc_emit_reg_or_imm(irn, 1);
-       be_emit_cstring(", ");
-       sparc_emit_dest_register(irn, 0);
-       be_emit_finish_line_gas(irn);
-}
-
-/**
- * emit code for mul with the correct sign prefix
- */
-static void emit_sparc_Mul(const ir_node *irn)
-{
-       be_emit_cstring("\t");
-       sparc_emit_mode_sign_prefix(irn);
-       be_emit_cstring("mul ");
-
-       sparc_emit_source_register(irn, 0);
-       be_emit_cstring(", ");
-       sparc_emit_reg_or_imm(irn, 1);
-       be_emit_cstring(", ");
-       sparc_emit_dest_register(irn, 0);
-       be_emit_finish_line_gas(irn);
-}
-
 /**
  * emits code for mulh
  */
@@ -455,24 +380,24 @@ static void emit_be_Return(const ir_node *irn)
 /**
  * Emits code for Call node
  */
-static void emit_be_Call(const ir_node *irn)
+static void emit_sparc_Call(const ir_node *node)
 {
-       ir_entity *entity = be_Call_get_entity(irn);
+       const sparc_attr_t *attr   = get_sparc_attr_const(node);
+       ir_entity          *entity = attr->immediate_value_entity;
 
+       be_emit_cstring("\tcall ");
        if (entity != NULL) {
-               be_emit_cstring("\tcall ");
            sparc_emit_entity(entity);
                be_emit_cstring(", 0");
-               be_emit_finish_line_gas(irn);
-               be_emit_cstring("\tnop");
-               be_emit_pad_comment();
-               be_emit_cstring("/* TODO: use delay slot */\n");
        } else {
-               be_emit_cstring("\tnop\n");
-               be_emit_pad_comment();
-               be_emit_cstring("/* TODO: Entity == NULL */\n");
-               be_emit_finish_line_gas(irn);
+               int last = get_irn_arity(node);
+               sparc_emit_source_register(node, last-1);
        }
+       be_emit_finish_line_gas(node);
+
+       /* fill delay slot */
+       be_emit_cstring("\tnop");
+       be_emit_finish_line_gas(node);
 }
 
 /**
@@ -513,6 +438,11 @@ static void emit_be_MemPerm(const ir_node *node)
        int i;
        int memperm_arity;
        int sp_change = 0;
+       ir_graph          *irg    = get_irn_irg(node);
+       be_stack_layout_t *layout = be_get_irg_stack_layout(irg);
+
+       /* this implementation only works with frame pointers currently */
+       assert(layout->sp_relative == false);
 
        /* TODO: this implementation is slower than necessary.
           The longterm goal is however to avoid the memperm node completely */
@@ -522,34 +452,40 @@ static void emit_be_MemPerm(const ir_node *node)
        if (memperm_arity > 8)
                panic("memperm with more than 8 inputs not supported yet");
 
+       be_emit_irprintf("\tsub %%sp, %d, %%sp", memperm_arity*4);
+       be_emit_finish_line_gas(node);
+
        for (i = 0; i < memperm_arity; ++i) {
-               int offset;
                ir_entity *entity = be_get_MemPerm_in_entity(node, i);
+               int        offset = be_get_stack_entity_offset(layout, entity, 0);
 
                /* spill register */
-               sp_change += 4;
-               be_emit_irprintf("\tst %%l%d, [%%sp-%d]", i, sp_change);
+               be_emit_irprintf("\tst %%l%d, [%%sp%+d]", i, sp_change + SPARC_MIN_STACKSIZE);
                be_emit_finish_line_gas(node);
 
                /* load from entity */
-               offset = get_entity_offset(entity) + sp_change;
-               be_emit_irprintf("\tld [%%sp+%d], %%l%d", offset, i);
+               be_emit_irprintf("\tld [%%fp%+d], %%l%d", offset, i);
                be_emit_finish_line_gas(node);
+               sp_change += 4;
        }
 
        for (i = memperm_arity-1; i >= 0; --i) {
-               int        offset;
                ir_entity *entity = be_get_MemPerm_out_entity(node, i);
+               int        offset = be_get_stack_entity_offset(layout, entity, 0);
+
+               sp_change -= 4;
 
                /* store to new entity */
-               offset = get_entity_offset(entity) + sp_change;
-               be_emit_irprintf("\tst %%l%d, [%%sp+%d]", i, offset);
+               be_emit_irprintf("\tst %%l%d, [%%fp%+d]", i, offset);
                be_emit_finish_line_gas(node);
                /* restore register */
-               be_emit_irprintf("\tld [%%sp-%d], %%l%d", sp_change, i);
-               sp_change -= 4;
+               be_emit_irprintf("\tld [%%sp%+d], %%l%d", sp_change + SPARC_MIN_STACKSIZE, i);
                be_emit_finish_line_gas(node);
        }
+
+       be_emit_irprintf("\tadd %%sp, %d, %%sp", memperm_arity*4);
+       be_emit_finish_line_gas(node);
+
        assert(sp_change == 0);
 }
 
@@ -591,7 +527,7 @@ static void emit_sparc_FrameAddr(const ir_node *irn)
                be_emit_cstring("\tadd ");
                sparc_emit_source_register(irn, 0);
                be_emit_cstring(", ");
-               be_emit_irprintf("%ld", attr->fp_offset + save_attr->initial_stacksize);
+               be_emit_irprintf("%ld", attr->fp_offset);
        } else {
                be_emit_cstring("\tsub ");
                sparc_emit_source_register(irn, 0);
@@ -608,22 +544,19 @@ static void emit_sparc_FrameAddr(const ir_node *irn)
 /**
  * Emits code for Branch
  */
-static void emit_sparc_Branch(const ir_node *irn)
+static void emit_sparc_BXX(const ir_node *node)
 {
+       const sparc_jmp_cond_attr_t *attr = get_sparc_jmp_cond_attr_const(node);
+       int              proj_num    = attr->proj_num;
+       bool             is_unsigned = attr->is_unsigned;
+       const ir_node   *proj_true   = NULL;
+       const ir_node   *proj_false  = NULL;
        const ir_edge_t *edge;
-       const ir_node *proj_true  = NULL;
-       const ir_node *proj_false = NULL;
-       const ir_node *block;
-       const ir_node *next_block;
-       ir_node *op1 = get_irn_n(irn, 0);
-       const char *suffix;
-       int proj_num = get_sparc_jmp_cond_proj_num(irn);
-       const sparc_cmp_attr_t *cmp_attr = get_irn_generic_attr_const(op1);
-       // bool is_signed = !cmp_attr->is_unsigned;
-
-       assert(is_sparc_Cmp(op1) || is_sparc_Tst(op1));
-
-       foreach_out_edge(irn, edge) {
+       const ir_node   *block;
+       const ir_node   *next_block;
+       const char      *suffix;
+
+       foreach_out_edge(node, edge) {
                ir_node *proj = get_edge_src_irn(edge);
                long nr = get_Proj_proj(proj);
                if (nr == pn_Cond_true) {
@@ -633,12 +566,8 @@ static void emit_sparc_Branch(const ir_node *irn)
                }
        }
 
-       if (cmp_attr->ins_permuted) {
-               proj_num = get_mirrored_pnc(proj_num);
-       }
-
        /* for now, the code works for scheduled and non-schedules blocks */
-       block = get_nodes_block(irn);
+       block = get_nodes_block(node);
 
        /* we have a block schedule */
        next_block = get_irn_link(block);
@@ -655,20 +584,32 @@ static void emit_sparc_Branch(const ir_node *irn)
                proj_num   = get_negated_pnc(proj_num, mode_Iu);
        }
 
-
-       switch (proj_num) {
-               case pn_Cmp_Eq:  suffix = "e"; break;
-               case pn_Cmp_Lt:  suffix = "l"; break;
-               case pn_Cmp_Le:  suffix = "le"; break;
-               case pn_Cmp_Gt:  suffix = "g"; break;
-               case pn_Cmp_Ge:  suffix = "ge"; break;
-               case pn_Cmp_Lg:  suffix = "ne"; break;
-               case pn_Cmp_Leg: suffix = "a"; break;
-               default: panic("Cmp has unsupported pnc");
+       if (is_unsigned) {
+               switch (proj_num) {
+                       case pn_Cmp_Eq:  suffix = "e"; break;
+                       case pn_Cmp_Lt:  suffix = "lu"; break;
+                       case pn_Cmp_Le:  suffix = "leu"; break;
+                       case pn_Cmp_Gt:  suffix = "gu"; break;
+                       case pn_Cmp_Ge:  suffix = "geu"; break;
+                       case pn_Cmp_Lg:  suffix = "ne"; break;
+                       default: panic("Cmp has unsupported pnc");
+               }
+       } else {
+               switch (proj_num) {
+                       case pn_Cmp_Eq:  suffix = "e"; break;
+                       case pn_Cmp_Lt:  suffix = "l"; break;
+                       case pn_Cmp_Le:  suffix = "le"; break;
+                       case pn_Cmp_Gt:  suffix = "g"; break;
+                       case pn_Cmp_Ge:  suffix = "ge"; break;
+                       case pn_Cmp_Lg:  suffix = "ne"; break;
+                       default: panic("Cmp has unsupported pnc");
+               }
        }
 
        /* emit the true proj */
-       be_emit_irprintf("\tb%s ", suffix);
+       be_emit_cstring("\tb");
+       be_emit_string(suffix);
+       be_emit_char(' ');
        sparc_emit_cfop_target(proj_true);
        be_emit_finish_line_gas(proj_true);
 
@@ -693,7 +634,7 @@ static void emit_sparc_Branch(const ir_node *irn)
 /**
  * emit Jmp (which actually is a branch always (ba) instruction)
  */
-static void emit_sparc_Jmp(const ir_node *node)
+static void emit_sparc_Ba(const ir_node *node)
 {
        ir_node *block, *next_block;
 
@@ -770,50 +711,33 @@ static inline void set_emitter(ir_op *op, emit_func sparc_emit_node)
  */
 static void sparc_register_emitters(void)
 {
-
        /* first clear the generic function pointer for all ops */
        clear_irp_opcodes_generic_func();
-
        /* register all emitter functions defined in spec */
        sparc_register_spec_emitters();
 
        /* custom emitter */
-    set_emitter(op_be_IncSP,                   emit_be_IncSP);
-    set_emitter(op_be_Return,                  emit_be_Return);
-    set_emitter(op_be_Call,                            emit_be_Call);
-    set_emitter(op_sparc_FrameAddr,            emit_sparc_FrameAddr);
-    set_emitter(op_sparc_Branch,               emit_sparc_Branch);
-    set_emitter(op_sparc_SymConst,             emit_sparc_SymConst);
-    set_emitter(op_sparc_Jmp,                  emit_sparc_Jmp);
-    set_emitter(op_sparc_Save,                 emit_sparc_Save);
-
-    set_emitter(op_sparc_HiImm,                        emit_sparc_HiImm);
-    set_emitter(op_sparc_LoImm,                        emit_sparc_LoImm);
-    set_emitter(op_sparc_Div,                  emit_sparc_Div);
-    set_emitter(op_sparc_Mul,                  emit_sparc_Mul);
-    set_emitter(op_sparc_Mulh,                 emit_sparc_Mulh);
-
-    set_emitter(op_be_Copy,                            emit_be_Copy);
-    set_emitter(op_be_CopyKeep,                        emit_be_Copy);
-
-    set_emitter(op_be_Perm,                            emit_be_Perm);
-    set_emitter(op_be_MemPerm,                 emit_be_MemPerm);
-
-/*
-    set_emitter(op_arm_B,          emit_arm_B);
-    set_emitter(op_arm_CopyB,      emit_arm_CopyB);
-    set_emitter(op_arm_fpaConst,   emit_arm_fpaConst);
-    set_emitter(op_arm_fpaDbl2GP,  emit_arm_fpaDbl2GP);
-    set_emitter(op_arm_LdTls,      emit_arm_LdTls);
-    set_emitter(op_arm_SwitchJmp,  emit_arm_SwitchJmp);
-
-*/
-    /* no need to emit anything for the following nodes */
-       set_emitter(op_Phi,            emit_nothing);
-       set_emitter(op_be_Keep,        emit_nothing);
-       set_emitter(op_be_Start,       emit_nothing);
-       set_emitter(op_be_Barrier,     emit_nothing);
-
+       set_emitter(op_be_Copy,         emit_be_Copy);
+       set_emitter(op_be_CopyKeep,     emit_be_Copy);
+       set_emitter(op_be_IncSP,        emit_be_IncSP);
+       set_emitter(op_be_MemPerm,      emit_be_MemPerm);
+       set_emitter(op_be_Perm,         emit_be_Perm);
+       set_emitter(op_be_Return,       emit_be_Return);
+       set_emitter(op_sparc_BXX,       emit_sparc_BXX);
+       set_emitter(op_sparc_Call,      emit_sparc_Call);
+       set_emitter(op_sparc_FrameAddr, emit_sparc_FrameAddr);
+       set_emitter(op_sparc_HiImm,     emit_sparc_HiImm);
+       set_emitter(op_sparc_Ba,        emit_sparc_Ba);
+       set_emitter(op_sparc_LoImm,     emit_sparc_LoImm);
+       set_emitter(op_sparc_Mulh,      emit_sparc_Mulh);
+       set_emitter(op_sparc_Save,      emit_sparc_Save);
+       set_emitter(op_sparc_SymConst,  emit_sparc_SymConst);
+
+       /* 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);
 }
 
 /**
@@ -940,9 +864,6 @@ void sparc_gen_routine(const sparc_code_gen_t *cg, ir_graph *irg)
                last_block = block;
        }
 
-
-       //irg_walk_blkwise_graph(irg, NULL, sparc_gen_block, NULL);
-
        // emit function epilog
        sparc_emit_func_epilog(irg);
 }