+static
+int check_immediate_constraint(tarval *tv, char immediate_constraint_type)
+{
+ long val;
+
+ assert(tarval_is_long(tv));
+ val = get_tarval_long(tv);
+
+ switch (immediate_constraint_type) {
+ case 0:
+ return 1;
+ case 'I':
+ return val >= 0 && val <= 32;
+ case 'J':
+ return val >= 0 && val <= 63;
+ case 'K':
+ return val >= -128 && val <= 127;
+ case 'L':
+ return val == 0xff || val == 0xffff;
+ case 'M':
+ return val >= 0 && val <= 3;
+ case 'N':
+ return val >= 0 && val <= 255;
+ case 'O':
+ return val >= 0 && val <= 127;
+ default:
+ break;
+ }
+ panic("Invalid immediate constraint found");
+ return 0;
+}
+
+ir_node *try_create_Immediate(ir_node *node, char immediate_constraint_type)
+{
+ 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) {
+ offset = get_Const_tarval(cnst);
+ if(!tarval_is_long(offset)) {
+ ir_fprintf(stderr, "Optimisation Warning: tarval from %+F is not a "
+ "long?\n", cnst);
+ return NULL;
+ }
+
+ if(!check_immediate_constraint(offset, immediate_constraint_type))
+ return NULL;
+ }
+ if(symconst != NULL) {
+ if(immediate_constraint_type != 0) {
+ /* 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 {
+ int is_in;
+ int n_outs;
+ const arch_register_req_t **out_reqs;
+
+ const arch_register_req_t *req;
+ unsigned immediate_possible;
+ char immediate_type;
+};
+
+void parse_asm_constraint(ir_node *node, int pos, constraint_t *constraint,
+ const char *c)
+{
+ int immediate_possible = 0;
+ char immediate_type = 0;
+ unsigned limited = 0;
+ const arch_register_class_t *cls = NULL;
+ ir_graph *irg;
+ struct obstack *obst;
+ arch_register_req_t *req;
+ unsigned *limited_ptr;
+ int p;
+ int same_as = -1;
+
+ /* TODO: replace all the asserts with nice error messages */
+
+ 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 'Q':
+ case 'q': /* q means lower part of the regs only, this makes no
+ * difference to Q for us (we only assigne whole registers) */
+ assert(cls == NULL ||
+ (cls == &ia32_reg_classes[CLASS_ia32_gp] && limited != 0));
+ cls = &ia32_reg_classes[CLASS_ia32_gp];
+ limited |= 1 << REG_EAX | 1 << REG_EBX | 1 << REG_ECX |
+ 1 << REG_EDX;
+ 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 | 1 << REG_EDX;
+ break;
+ case 'l':
+ assert(cls == NULL ||
+ (cls == &ia32_reg_classes[CLASS_ia32_gp] && limited != 0));
+ cls = &ia32_reg_classes[CLASS_ia32_gp];
+ limited |= 1 << REG_EAX | 1 << REG_EBX | 1 << REG_ECX |
+ 1 << REG_EDX | 1 << REG_ESI | 1 << REG_EDI |
+ 1 << REG_EBP;
+ 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 'Y':
+ case 'x':
+ assert(cls == NULL);
+ /* TODO: check that sse2 is supported */
+ cls = &ia32_reg_classes[CLASS_ia32_xmm];
+ break;
+
+ case 'I':
+ case 'J':
+ case 'K':
+ case 'L':
+ case 'M':
+ case 'N':
+ case 'O':
+ assert(!immediate_possible);
+ immediate_possible = 1;
+ immediate_type = *c;
+ break;
+ case 'n':
+ case 'i':
+ assert(!immediate_possible);
+ immediate_possible = 1;
+ 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':
+ assert(constraint->is_in && "can only specify same constraint "
+ "on input");
+
+ sscanf(c, "%d%n", &same_as, &p);
+ if(same_as >= 0) {
+ c += p;
+ continue;
+ }
+ 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 */
+ assert(0 && "asm constraint not supported");
+ break;
+ default:
+ assert(0 && "unknown asm constraint found");
+ break;
+ }
+ ++c;
+ }
+
+ if(same_as >= 0) {
+ const arch_register_req_t *other_constr;
+
+ assert(cls == NULL && "same as and register constraint not supported");
+ assert(!immediate_possible && "same as and immediate constraint not "
+ "supported");
+ assert(same_as < constraint->n_outs && "wrong constraint number in "
+ "same_as constraint");
+
+ other_constr = constraint->out_reqs[same_as];
+
+ req = obstack_alloc(obst, sizeof(req[0]));
+ req->cls = other_constr->cls;
+ req->type = arch_register_req_type_should_be_same;
+ req->limited = NULL;
+ req->other_same = pos;
+ req->other_different = -1;
+
+ /* switch constraints. This is because in firm we have same_as
+ * constraints on the output constraints while in the gcc asm syntax
+ * they are specified on the input constraints */
+ constraint->req = other_constr;
+ constraint->out_reqs[same_as] = req;
+ constraint->immediate_possible = 0;
+ return;
+ }
+
+ 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(constraint->is_in
+ && "imeediates make no sense for output constraints");
+ }
+ /* 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_type = immediate_type;
+}
+
+static
+void parse_clobber(ir_node *node, int pos, constraint_t *constraint,
+ const char *c)
+{
+ panic("Clobbers not supported yet");
+}