Allow loading of stack parameters with a different mode than the parameter mode....
[libfirm] / ir / be / ia32 / ia32_emitter.c
index 87f6c02..f20d23f 100644 (file)
@@ -721,9 +721,19 @@ static void ia32_emit_cmp_suffix(int pnc)
 void ia32_emit_cmp_suffix_node(const ir_node *node,
                                int flags_pos)
 {
+       const ia32_attr_t *attr = get_ia32_attr_const(node);
+
        pn_Cmp pnc = get_ia32_pncode(node);
 
        pnc = determine_final_pnc(node, flags_pos, pnc);
+       if(attr->data.ins_permuted) {
+               if(pnc & ia32_pn_Cmp_float) {
+                       pnc = get_negated_pnc(pnc, mode_F);
+               } else {
+                       pnc = get_negated_pnc(pnc, mode_Iu);
+               }
+       }
+
        ia32_emit_cmp_suffix(pnc);
 }
 
@@ -1136,15 +1146,26 @@ static void emit_ia32_Immediate(const ir_node *node)
        }
 }
 
+/**
+ * Emit an inline assembler operand.
+ *
+ * @param node  the ia32_ASM node
+ * @param s     points to the operand (a %c)
+ *
+ * @return  pointer to the first char in s NOT in the current operand
+ */
 static const char* emit_asm_operand(const ir_node *node, const char *s)
 {
+       const ia32_attr_t     *ia32_attr = get_ia32_attr_const(node);
+       const ia32_asm_attr_t *attr      = CONST_CAST_IA32_ATTR(ia32_asm_attr_t,
+                                                            ia32_attr);
        const arch_register_t *reg;
+       const ia32_asm_reg_t  *asm_regs = attr->register_map;
+       const ia32_asm_reg_t  *asm_reg;
        const char            *reg_name;
        char                   c;
        char                   modifier = 0;
        int                    num      = -1;
-       const ia32_attr_t     *attr;
-       int                    n_outs;
        int                    p;
 
        assert(*s == '%');
@@ -1193,26 +1214,26 @@ static const char* emit_asm_operand(const ir_node *node, const char *s)
                s += p;
        }
 
+       if(num < 0 || num >= ARR_LEN(asm_regs)) {
+               ir_fprintf(stderr, "Error: Custom assembler references invalid "
+                          "input/output (%+F)\n", node);
+               return s;
+       }
+       asm_reg = & asm_regs[num];
+       assert(asm_reg->valid);
+
        /* get register */
-       attr   = get_ia32_attr_const(node);
-       n_outs = ARR_LEN(attr->slots);
-       if(num < n_outs) {
-               reg = get_out_reg(node, num);
+       if(asm_reg->use_input == 0) {
+               reg = get_out_reg(node, asm_reg->inout_pos);
        } else {
-               ir_node *pred;
-               int      in = num - n_outs;
-               if(in >= get_irn_arity(node)) {
-                       ir_fprintf(stderr, "Warning: Invalid input %d specified in asm "
-                                  "op (%+F)\n", num, node);
-                       return s;
-               }
-               pred = get_irn_n(node, in);
+               ir_node *pred = get_irn_n(node, asm_reg->inout_pos);
+
                /* might be an immediate value */
                if(is_ia32_Immediate(pred)) {
                        emit_ia32_Immediate(pred);
                        return s;
                }
-               reg = get_in_reg(node, in);
+               reg = get_in_reg(node, asm_reg->inout_pos);
        }
        if(reg == NULL) {
                ir_fprintf(stderr, "Warning: no register assigned for %d asm op "
@@ -1220,25 +1241,34 @@ static const char* emit_asm_operand(const ir_node *node, const char *s)
                return s;
        }
 
+       if(asm_reg->memory) {
+               be_emit_char('(');
+       }
+
        /* emit it */
-       be_emit_char('%');
-       switch(modifier) {
-       case 0:
-               reg_name = arch_register_get_name(reg);
-               break;
-       case 'b':
-               reg_name = ia32_get_mapped_reg_name(isa->regs_8bit, reg);
-               break;
-       case 'h':
-               reg_name = ia32_get_mapped_reg_name(isa->regs_8bit_high, reg);
-               break;
-       case 'w':
-               reg_name = ia32_get_mapped_reg_name(isa->regs_16bit, reg);
-               break;
-       default:
-               panic("Invalid asm op modifier");
+       if(modifier != 0) {
+               be_emit_char('%');
+               switch(modifier) {
+               case 'b':
+                       reg_name = ia32_get_mapped_reg_name(isa->regs_8bit, reg);
+                       break;
+               case 'h':
+                       reg_name = ia32_get_mapped_reg_name(isa->regs_8bit_high, reg);
+                       break;
+               case 'w':
+                       reg_name = ia32_get_mapped_reg_name(isa->regs_16bit, reg);
+                       break;
+               default:
+                       panic("Invalid asm op modifier");
+               }
+               be_emit_string(reg_name);
+       } else {
+               emit_register(reg, asm_reg->mode);
+       }
+
+       if(asm_reg->memory) {
+               be_emit_char(')');
        }
-       be_emit_string(reg_name);
 
        return s;
 }
@@ -1964,7 +1994,7 @@ static void ia32_emit_align_label(cpu_support cpu)
 
 /**
  * Test wether a block should be aligned.
- * For cpus in the P4/Athlon class it is usefull to align jump labels to
+ * For cpus in the P4/Athlon class it is useful to align jump labels to
  * 16 bytes. However we should only do that if the alignment nops before the
  * label aren't executed more often than we have jumps to the label.
  */
@@ -2082,7 +2112,13 @@ static void ia32_emit_func_prolog(ir_graph *irg)
        cpu_support cpu      = isa->opt_arch;
        const be_irg_t *birg = cg->birg;
 
+       /* write the begin line (used by scripts processing the assembler... */
+       be_emit_write_line();
+       be_emit_cstring("# -- Begin  ");
+       be_emit_string(irg_name);
+       be_emit_char('\n');
        be_emit_write_line();
+
        be_gas_emit_switch_section(GAS_SECTION_TEXT);
        be_dbg_method_begin(birg->main_env->db_handle, irg_ent, be_abi_get_stack_layout(birg->abi));
        ia32_emit_align_func(cpu);
@@ -2108,6 +2144,12 @@ static void ia32_emit_func_epilog(ir_graph *irg)
 
        ia32_emit_function_size(irg_name);
        be_dbg_method_end(birg->main_env->db_handle);
+
+       be_emit_cstring("# -- End  ");
+       be_emit_string(irg_name);
+       be_emit_char('\n');
+       be_emit_write_line();
+
        be_emit_char('\n');
        be_emit_write_line();
 }