we can parse lots of assembler constraints now (but not all yet), and emit immediates...
authorMatthias Braun <matze@braunis.de>
Sat, 2 Jun 2007 20:46:46 +0000 (20:46 +0000)
committerMatthias Braun <matze@braunis.de>
Sat, 2 Jun 2007 20:46:46 +0000 (20:46 +0000)
[r14275]

ir/be/ia32/bearch_ia32.c
ir/be/ia32/ia32_emitter.c
ir/be/ia32/ia32_new_nodes.c
ir/be/ia32/ia32_new_nodes.h
ir/be/ia32/ia32_nodes_attr.h
ir/be/ia32/ia32_spec.pl
ir/be/ia32/ia32_transform.c
ir/be/test/asm_test.c

index f683bba..d4276b9 100644 (file)
@@ -1767,7 +1767,8 @@ int ia32_to_appear_in_schedule(void *block_env, const ir_node *irn) {
 
        if(is_ia32_NoReg_GP(irn) || is_ia32_NoReg_VFP(irn) || is_ia32_NoReg_XMM(irn)
                || is_ia32_Unknown_GP(irn) || is_ia32_Unknown_XMM(irn)
-               || is_ia32_Unknown_VFP(irn) || is_ia32_ChangeCW(irn))
+               || is_ia32_Unknown_VFP(irn) || is_ia32_ChangeCW(irn)
+               || is_ia32_Immediate(irn))
                return 0;
 
        return 1;
index 9986a80..b28ff44 100644 (file)
@@ -224,6 +224,7 @@ char *get_unique_label(char *buf, size_t buflen, const char *prefix) {
 #undef be_emit_cstring
 #define be_emit_cstring(env,x)          { be_emit_string_len(env->emit, x, sizeof(x)-1); }
 #define be_emit_ident(env,i)            be_emit_ident(env->emit,i)
+#define be_emit_tarval(env,tv)          be_emit_tarval(env->emit,tv)
 #define be_emit_write_line(env)         be_emit_write_line(env->emit)
 #define be_emit_finish_line_gas(env,n)  be_emit_finish_line_gas(env->emit,n)
 #define be_emit_pad_comment(env)        be_emit_pad_comment(env->emit)
@@ -267,7 +268,7 @@ void ia32_emit_immediate(ia32_emit_env_t *env, const ir_node *node)
        switch(get_ia32_immop_type(node)) {
        case ia32_ImmConst:
                tv = get_ia32_Immop_tarval(node);
-               be_emit_tarval(env->emit, tv);
+               be_emit_tarval(env, tv);
                return;
        case ia32_ImmSymConst:
                ent = get_ia32_Immop_symconst(node);
@@ -275,6 +276,7 @@ void ia32_emit_immediate(ia32_emit_env_t *env, const ir_node *node)
                id = get_entity_ld_ident(ent);
                be_emit_ident(env, id);
                return;
+       case ia32_ImmAsm:
        case ia32_ImmNone:
                break;
        }
@@ -1311,6 +1313,25 @@ void emit_Jmp(ia32_emit_env_t *env, const ir_node *node) {
        be_emit_finish_line_gas(env, node);
 }
 
+static
+void emit_ia32_Immediate(ia32_emit_env_t *env, const ir_node *node)
+{
+       ia32_attr_t *attr = get_ia32_attr(node);
+
+       if(attr->am_sc != NULL) {
+               ident *id = get_entity_ld_ident(attr->am_sc);
+
+               if(attr->data.am_sc_sign)
+                       be_emit_char(env, '-');
+               be_emit_ident(env, id);
+       }
+       if(attr->cnst_val.tv != NULL) {
+               if(attr->am_sc != NULL)
+                       be_emit_char(env, '+');
+               be_emit_tarval(env, attr->cnst_val.tv);
+       }
+}
+
 static
 const char* emit_asm_operand(ia32_emit_env_t *env, const ir_node *node,
                              const char *s)
@@ -1375,12 +1396,19 @@ const char* emit_asm_operand(ia32_emit_env_t *env, const ir_node *node,
        if(num < n_outs) {
                reg = get_out_reg(env, node, num);
        } else {
-               int in = num - n_outs;
+               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);
+               /* might be an immediate value */
+               if(is_ia32_Immediate(pred)) {
+                       emit_ia32_Immediate(env, pred);
+                       return s;
+               }
                reg = get_in_reg(env, node, in);
        }
        if(reg == NULL) {
index 4cfea61..9776700 100644 (file)
@@ -132,6 +132,7 @@ static int ia32_dump_node(ir_node *n, FILE *F, dump_reason_t reason) {
        ir_mode     *mode = NULL;
        int          bad  = 0;
        int          i, n_res, am_flav, flags;
+       const ia32_attr_t *attr = get_ia32_attr_const(n);
        const arch_register_req_t **reqs;
        const arch_register_t     **slots;
 
@@ -239,6 +240,10 @@ static int ia32_dump_node(ir_node *n, FILE *F, dump_reason_t reason) {
                                case ia32_ImmSymConst:
                                        fprintf(F, "SymConst");
                                        break;
+                               case ia32_ImmAsm:
+                                       fprintf(F, "Asm '%s'\n",
+                                               get_id_str(attr->cnst_val.asm_text));
+                                       break;
                                default:
                                        fprintf(F, "unknown (%d)", get_ia32_immop_type(n));
                                        break;
@@ -422,6 +427,11 @@ ia32_attr_t *get_ia32_attr(const ir_node *node) {
        return (ia32_attr_t *)get_irn_generic_attr((ir_node *)node);
 }
 
+const ia32_attr_t *get_ia32_attr_const(const ir_node *node) {
+       assert(is_ia32_irn(node) && "need ia32 node to get ia32 attributes");
+       return (const ia32_attr_t*) get_irn_generic_attr_const(node);
+}
+
 /**
  * Gets the type of an ia32 node.
  */
@@ -1207,6 +1217,9 @@ int ia32_compare_attr(ia32_attr_t *a, ia32_attr_t *b) {
        if (a->data.imm_tp == ia32_ImmSymConst
                        && a->cnst_val.sc != b->cnst_val.sc)
                return 1;
+       if(a->data.imm_tp == ia32_ImmAsm
+                       && a->cnst_val.asm_text != b->cnst_val.asm_text)
+               return 1;
 
        if (a->data.am_flavour != b->data.am_flavour
            || a->data.am_scale != b->data.am_scale
index 9e4b2d8..c3cce8c 100644 (file)
@@ -52,6 +52,8 @@ int ia32_has_x87_register(const ir_node *n);
  * Returns the attributes of an ia32 node.
  */
 ia32_attr_t *get_ia32_attr(const ir_node *node);
+const ia32_attr_t *get_ia32_attr_const(const ir_node *node);
+
 
 /**
  * Gets the type of an ia32 node.
index 1e8b026..4742d79 100644 (file)
@@ -44,7 +44,8 @@ typedef enum {
 typedef enum {
        ia32_ImmNone     = 0,
        ia32_ImmConst    = 1,
-       ia32_ImmSymConst = 2
+       ia32_ImmSymConst = 2,
+       ia32_ImmAsm      = 3
 } ia32_immop_type_t;
 
 typedef        enum {
index 64e5a29..68c1963 100644 (file)
@@ -290,12 +290,13 @@ $fpcw_flags   = [ "FP_IM", "FP_DM", "FP_ZM", "FP_OM", "FP_UM", "FP_PM",
 
 %nodes = (
 
-#Immediate => {
-#      irn_flags => "i",
-#      reg_req   => { out => [ "NoReg_GP" ] },
-#      mode      => $mode_gp,
-#      attr_type => "ia32_imm_t",
-#},
+Immediate => {
+       state     => "pinned",
+       op_flags  => "c",
+       irn_flags => "I",
+       reg_req   => { out => [ "gp_NOREG" ] },
+       mode      => $mode_gp,
+},
 
 Asm => {
        mode      => "mode_T",
index 97268ff..353c722 100644 (file)
@@ -2392,6 +2392,320 @@ static ir_node *gen_Conv(ia32_transform_env_t *env, ir_node *node) {
        return res;
 }
 
+static
+ir_node *try_create_Immediate(ia32_transform_env_t *env, ir_node *node,
+                              unsigned immediate_max)
+{
+       int          minus         = 0;
+       tarval      *offset        = NULL;
+       int          offset_sign   = 0;
+       ir_entity   *symconst_ent  = NULL;
+       int          symconst_sign = 0;
+       ir_mode     *mode;
+       ir_node     *cnst          = NULL;
+       ir_node     *symconst      = NULL;
+       ir_node     *res;
+       ir_graph    *irg;
+       dbg_info    *dbgi;
+       ir_node     *block;
+       ia32_attr_t *attr;
+
+       mode = get_irn_mode(node);
+       if(!mode_is_int(mode) && !mode_is_character(mode) &&
+                       !mode_is_reference(mode)) {
+               return NULL;
+       }
+
+       if(is_Minus(node)) {
+               minus = 1;
+               node  = get_Minus_op(node);
+       }
+
+       if(is_Const(node)) {
+               cnst        = node;
+               symconst    = NULL;
+               offset_sign = minus;
+       } else if(is_SymConst(node)) {
+               cnst          = NULL;
+               symconst      = node;
+               symconst_sign = minus;
+       } else if(is_Add(node)) {
+               ir_node *left  = get_Add_left(node);
+               ir_node *right = get_Add_right(node);
+               if(is_Const(left) && is_SymConst(right)) {
+                       cnst          = left;
+                       symconst      = right;
+                       symconst_sign = minus;
+                       offset_sign   = minus;
+               } else if(is_SymConst(left) && is_Const(right)) {
+                       cnst          = right;
+                       symconst      = left;
+                       symconst_sign = minus;
+                       offset_sign   = minus;
+               }
+       } else if(is_Sub(node)) {
+               ir_node *left  = get_Add_left(node);
+               ir_node *right = get_Add_right(node);
+               if(is_Const(left) && is_SymConst(right)) {
+                       cnst          = left;
+                       symconst      = right;
+                       symconst_sign = !minus;
+                       offset_sign   = minus;
+               } else if(is_SymConst(left) && is_Const(right)) {
+                       cnst          = right;
+                       symconst      = left;
+                       symconst_sign = minus;
+                       offset_sign   = !minus;
+               }
+       } else {
+               return NULL;
+       }
+
+       if(cnst != NULL) {
+               tarval  *tv;
+               tarval  *tvu;
+               long     val;
+
+               tv = get_Const_tarval(cnst);
+               if(!tarval_is_long(tv)) {
+                       ir_fprintf(stderr, "Optimisation Warning: tarval from %+F is not a "
+                                  "long?\n", cnst);
+                       return NULL;
+               }
+
+               tvu = tarval_convert_to(tv, mode_Iu);
+               val = get_tarval_long(tvu);
+               if(val > immediate_max)
+                       return NULL;
+
+               offset = tvu;
+       }
+       if(symconst != NULL) {
+               if(immediate_max != 0xffffffff) {
+                       /* we need full 32bits for symconsts */
+                       return NULL;
+               }
+
+               if(get_SymConst_kind(symconst) != symconst_addr_ent)
+                       return NULL;
+               symconst_ent = get_SymConst_entity(symconst);
+       }
+
+       irg   = env->irg;
+       dbgi  = get_irn_dbg_info(node);
+       block = get_irg_start_block(irg);
+       res   = new_rd_ia32_Immediate(dbgi, irg, block);
+       arch_set_irn_register(env->cg->arch_env, res, &ia32_gp_regs[REG_GP_NOREG]);
+
+       /* make sure we don't schedule stuff before the barrier */
+       add_irn_dep(res, get_irg_frame(irg));
+
+       /* misuse some fields for now... */
+       attr                  = get_ia32_attr(res);
+       attr->am_sc           = symconst_ent;
+       attr->data.am_sc_sign = symconst_sign;
+       if(offset_sign && offset != NULL) {
+               offset = tarval_neg(offset);
+       }
+       attr->cnst_val.tv = offset;
+       attr->data.imm_tp = ia32_ImmConst;
+
+       return res;
+}
+
+typedef struct constraint_t constraint_t;
+struct constraint_t {
+       const arch_register_req_t *req;
+       unsigned                   immediate_possible;
+       unsigned                   immediate_max;
+};
+
+static
+void parse_asm_constraint(ia32_transform_env_t *env, ir_node *node,
+                          constraint_t *constraint, const char *c, int is_in)
+{
+       int                          immediate_possible = 0;
+       unsigned                     immediate_max      = 0xffffffff;
+       unsigned                     limited            = 0;
+       const arch_register_class_t *cls                = NULL;
+       ir_graph                    *irg;
+       struct obstack              *obst;
+       arch_register_req_t         *req;
+       unsigned                    *limited_ptr;
+
+       printf("Constraint: %s\n", c);
+
+       while(*c != 0) {
+               switch(*c) {
+               case ' ':
+               case '\t':
+               case '\n':
+                       break;
+
+               case 'a':
+                       assert(cls == NULL ||
+                                       (cls == &ia32_reg_classes[CLASS_ia32_gp] && limited != 0));
+                       cls      = &ia32_reg_classes[CLASS_ia32_gp];
+                       limited |= 1 << REG_EAX;
+                       break;
+               case 'b':
+                       assert(cls == NULL ||
+                                       (cls == &ia32_reg_classes[CLASS_ia32_gp] && limited != 0));
+                       cls      = &ia32_reg_classes[CLASS_ia32_gp];
+                       limited |= 1 << REG_EBX;
+                       break;
+               case 'c':
+                       assert(cls == NULL ||
+                                       (cls == &ia32_reg_classes[CLASS_ia32_gp] && limited != 0));
+                       cls      = &ia32_reg_classes[CLASS_ia32_gp];
+                       limited |= 1 << REG_ECX;
+                       break;
+               case 'd':
+                       assert(cls == NULL ||
+                                       (cls == &ia32_reg_classes[CLASS_ia32_gp] && limited != 0));
+                       cls      = &ia32_reg_classes[CLASS_ia32_gp];
+                       limited |= 1 << REG_EDX;
+                       break;
+               case 'D':
+                       assert(cls == NULL ||
+                                       (cls == &ia32_reg_classes[CLASS_ia32_gp] && limited != 0));
+                       cls      = &ia32_reg_classes[CLASS_ia32_gp];
+                       limited |= 1 << REG_EDI;
+                       break;
+               case 'S':
+                       assert(cls == NULL ||
+                                       (cls == &ia32_reg_classes[CLASS_ia32_gp] && limited != 0));
+                       cls      = &ia32_reg_classes[CLASS_ia32_gp];
+                       limited |= 1 << REG_ESI;
+                       break;
+
+               case 'R':
+               case 'r':
+               case 'p':
+                       assert(cls == NULL);
+                       cls      = &ia32_reg_classes[CLASS_ia32_gp];
+                       break;
+
+               case 'f':
+               case 't':
+               case 'u':
+                       assert(cls == NULL);
+                       cls = &ia32_reg_classes[CLASS_ia32_vfp];
+                       break;
+
+               case 'x':
+                       assert(cls == NULL);
+                       cls = &ia32_reg_classes[CLASS_ia32_xmm];
+                       break;
+
+               case 'I':
+                       assert(!immediate_possible);
+                       immediate_possible = 1;
+                       immediate_max      = 31;
+                       break;
+               case 'J':
+                       assert(!immediate_possible);
+                       immediate_possible = 1;
+                       immediate_max      = 63;
+                       break;
+               case 'n':
+               case 'i':
+                       assert(!immediate_possible);
+                       immediate_possible = 1;
+                       break;
+               case 'M':
+                       assert(!immediate_possible);
+                       immediate_possible = 1;
+                       immediate_max      = 3;
+                       break;
+               case 'N':
+                       assert(!immediate_possible);
+                       immediate_possible = 1;
+                       immediate_max      = 0xff;
+                       break;
+
+               case 'g':
+                       assert(!immediate_possible && cls == NULL);
+                       immediate_possible = 1;
+                       cls                = &ia32_reg_classes[CLASS_ia32_gp];
+                       break;
+
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+                       /* TODO */
+                       assert(0 && "other_same not implemented yet");
+                       break;
+
+               case 'E': /* no float consts yet */
+               case 'F': /* no float consts yet */
+               case 's': /* makes no sense on x86 */
+               case 'X': /* we can't support that in firm */
+               case 'm':
+               case 'o':
+               case 'V':
+               case '<': /* no autodecrement on x86 */
+               case '>': /* no autoincrement on x86 */
+               case 'C': /* sse constant not supported yet */
+               case 'G': /* 80387 constant not supported yet */
+               case 'y': /* we don't support mmx registers yet */
+               case 'Z': /* not available in 32 bit mode */
+               case 'e': /* not available in 32 bit mode */
+               case 'K': /* gcc docu is cryptic */
+               case 'L': /* gcc docu is cryptic */
+                       assert(0);
+                       break;
+               default:
+                       assert(0);
+                       break;
+               }
+               ++c;
+       }
+
+       if(immediate_possible && cls == NULL) {
+               cls = &ia32_reg_classes[CLASS_ia32_gp];
+       }
+       assert(!immediate_possible || cls == &ia32_reg_classes[CLASS_ia32_gp]);
+       assert(cls != NULL);
+
+       if(immediate_possible) {
+               assert(is_in && "imeediates make no sense for output constraints");
+               printf("Immediate possible 0-%x\n", immediate_max);
+       }
+       /* todo: check types (no float input on 'r' constrainted in and such... */
+
+       irg  = env->irg;
+       obst = get_irg_obstack(irg);
+
+       if(limited != 0) {
+               req          = obstack_alloc(obst, sizeof(req[0]) + sizeof(unsigned));
+               limited_ptr  = (unsigned*) (req+1);
+       } else {
+               req = obstack_alloc(obst, sizeof(req[0]));
+       }
+       memset(req, 0, sizeof(req[0]));
+
+       if(limited != 0) {
+               req->type    = arch_register_req_type_limited;
+               *limited_ptr = limited;
+               req->limited = limited_ptr;
+       } else {
+               req->type    = arch_register_req_type_normal;
+       }
+       req->cls = cls;
+
+       constraint->req                = req;
+       constraint->immediate_possible = immediate_possible;
+       constraint->immediate_max      = immediate_max;
+}
+
 static
 ir_node *gen_ASM(ia32_transform_env_t *env, ir_node *node)
 {
@@ -2402,6 +2716,8 @@ ir_node *gen_ASM(ia32_transform_env_t *env, ir_node *node)
        ir_node    **in;
        ir_node     *res;
        int          out_arity;
+       int          n_outs;
+       int          n_clobbers;
        ia32_attr_t *attr;
        const arch_register_req_t **out_reqs;
        const arch_register_req_t **in_reqs;
@@ -2414,44 +2730,75 @@ ir_node *gen_ASM(ia32_transform_env_t *env, ir_node *node)
        /* transform inputs */
        arity = get_irn_arity(node);
        in    = alloca(arity * sizeof(in[0]));
-       for(i = 0; i < arity; ++i) {
-               ir_node *pred        = get_irn_n(node, i);
-               ir_node *transformed = transform_node(env, pred);
-
-               in[i] = transformed;
-       }
+       memset(in, 0, arity * sizeof(in[0]));
 
-       out_arity = get_ASM_n_output_constraints(node) + get_ASM_n_clobbers(node);
-       res = new_rd_ia32_Asm(dbgi, irg, block, arity, in, out_arity);
+       n_outs     = get_ASM_n_output_constraints(node);
+       n_clobbers = get_ASM_n_clobbers(node);
+       out_arity  = n_outs + n_clobbers;
 
        /* construct register constraints */
        obst     = get_irg_obstack(irg);
        out_reqs = obstack_alloc(obst, out_arity * sizeof(out_reqs[0]));
        for(i = 0; i < out_arity; ++i) {
-               arch_register_req_t *req = obstack_alloc(obst, sizeof(req[0]));
-               memset(req, 0, sizeof(req[0]));
+               const char   *c;
+               constraint_t  parsed_constr;
 
-               /* TODO: parse constraints */
-               req->type   = arch_register_req_type_normal;
-               req->cls    = &ia32_reg_classes[CLASS_ia32_gp];
-               out_reqs[i] = req;
+               if(i < n_outs) {
+                       const ir_asm_constraint *constraint;
+                       constraint = & get_ASM_output_constraints(node) [i];
+                       c = get_id_str(constraint->constraint);
+               } else {
+                       ident *glob_id = get_ASM_clobbers(node) [i - n_outs];
+                       c = get_id_str(glob_id);
+               }
+               parse_asm_constraint(env, node, &parsed_constr, c, 0);
+               out_reqs[i] = parsed_constr.req;
        }
-       set_ia32_out_req_all(res, out_reqs);
 
        in_reqs = obstack_alloc(obst, arity * sizeof(in_reqs[0]));
        for(i = 0; i < arity; ++i) {
-               arch_register_req_t *req = obstack_alloc(obst, sizeof(req[0]));
-               memset(req, 0, sizeof(req[0]));
+               const ir_asm_constraint   *constraint;
+               ident                     *constr_id;
+               const char                *c;
+               constraint_t               parsed_constr;
+
+               constraint = & get_ASM_input_constraints(node) [i];
+               constr_id  = constraint->constraint;
+               c          = get_id_str(constr_id);
+               parse_asm_constraint(env, node, &parsed_constr, c, 1);
+               in_reqs[i] = parsed_constr.req;
+
+               if(parsed_constr.immediate_possible) {
+                       ir_node *pred = get_irn_n(node, i);
+                       ir_node *immediate
+                               = try_create_Immediate(env, pred, parsed_constr.immediate_max);
+
+                       if(immediate != NULL) {
+                               in[i] = immediate;
+                       }
+               }
+       }
+
+       /* transform inputs */
+       for(i = 0; i < arity; ++i) {
+               ir_node *pred;
+               ir_node *transformed;
+
+               if(in[i] != NULL)
+                       continue;
 
-               /* TODO: parse constraints */
-               req->type  = arch_register_req_type_normal;
-               req->cls   = &ia32_reg_classes[CLASS_ia32_gp];
-               in_reqs[i] = req;
+               pred        = get_irn_n(node, i);
+               transformed = transform_node(env, pred);
+               in[i]       = transformed;
        }
-       set_ia32_in_req_all(res, in_reqs);
+
+       res = new_rd_ia32_Asm(dbgi, irg, block, arity, in, out_arity);
 
        attr                    = get_ia32_attr(res);
        attr->cnst_val.asm_text = get_ASM_text(node);
+       attr->data.imm_tp       = ia32_ImmAsm;
+       set_ia32_out_req_all(res, out_reqs);
+       set_ia32_in_req_all(res, in_reqs);
 
        SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env->cg, node));
 
index d6c3696..27aff79 100644 (file)
@@ -36,7 +36,8 @@ static inline int mov(int val)
 int main()
 {
        //sincostest(0.5);
-       //outb(123, 42);
+       outb(123, 42);
+       outb(12345, 42);
 
-       return mov(0);
+       return mov(0) + inb(12345) + inb(123);
 }