From f1522129041d11a7b887abb5a3d8d5a2908758bb Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Tue, 29 Jul 2008 09:10:20 +0000 Subject: [PATCH] cleanups/fixes for ASM handling [r20749] --- include/libfirm/be.h | 4 +- ir/be/bemain.c | 15 +- ir/be/ia32/bearch_ia32.c | 5 +- ir/be/ia32/ia32_transform.c | 423 ++++++++++++++++++++---------------- ir/be/ia32/ia32_transform.h | 19 +- ir/be/test/asm_test.c | 22 +- 6 files changed, 272 insertions(+), 216 deletions(-) diff --git a/include/libfirm/be.h b/include/libfirm/be.h index 4d1a39e11..3f2cffd3c 100644 --- a/include/libfirm/be.h +++ b/include/libfirm/be.h @@ -105,12 +105,12 @@ void be_main(FILE *output, const char *compilation_unit_name); * parse assembler constraint strings and returns flags (so the frontend knows * which operands are inputs/outputs and wether memory is required) */ -asm_constraint_flags_t parse_asm_constraints(const char *constraint); +asm_constraint_flags_t be_parse_asm_constraints(const char *constraints); /** * tests wether a string is a valid clobber in an asm instruction */ -bool is_valid_clobber(const char *clobber); +bool be_is_valid_clobber(const char *clobber); typedef struct be_main_env_t be_main_env_t; typedef struct be_options_t be_options_t; diff --git a/ir/be/bemain.c b/ir/be/bemain.c index cb3bbb714..544a525a5 100644 --- a/ir/be/bemain.c +++ b/ir/be/bemain.c @@ -240,10 +240,10 @@ void be_init_default_asm_constraint_flags(void) asm_constraint_flags['\r'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT; } -asm_constraint_flags_t parse_asm_constraints(const char *constraint) +asm_constraint_flags_t be_parse_asm_constraints(const char *constraint) { + asm_constraint_flags_t flags = 0; const char *c; - asm_constraint_flags_t flags; asm_constraint_flags_t tflags; for (c = constraint; *c != '\0'; ++c) { @@ -279,16 +279,25 @@ asm_constraint_flags_t parse_asm_constraints(const char *constraint) && (flags & ASM_CONSTRAINT_FLAG_MODIFIER_NO_READ)))) { flags |= ASM_CONSTRAINT_FLAG_INVALID; } + if (! (flags & (ASM_CONSTRAINT_FLAG_MODIFIER_READ + | ASM_CONSTRAINT_FLAG_MODIFIER_WRITE + | ASM_CONSTRAINT_FLAG_MODIFIER_NO_WRITE + | ASM_CONSTRAINT_FLAG_MODIFIER_NO_READ))) { + flags |= ASM_CONSTRAINT_FLAG_MODIFIER_READ; + } return flags; } -bool is_valid_clobber(const char *clobber) +bool be_is_valid_clobber(const char *clobber) { /* memory is a valid clobber. (the frontend has to detect this case too, * because it has to add memory edges to the asm) */ if (strcmp(clobber, "memory") == 0) return true; + /* cc (condition code) is always valid */ + if (strcmp(clobber, "cc") == 0) + return true; return isa_if->is_valid_clobber(isa_if, clobber); } diff --git a/ir/be/ia32/bearch_ia32.c b/ir/be/ia32/bearch_ia32.c index 5ddc2704e..9886cc10d 100644 --- a/ir/be/ia32/bearch_ia32.c +++ b/ir/be/ia32/bearch_ia32.c @@ -1709,7 +1709,6 @@ static arch_env_t *ia32_init(FILE *file_handle) { return NULL; inited = 1; - init_asm_constraints(); set_tarval_output_modes(); isa = xmalloc(sizeof(*isa)); @@ -2254,6 +2253,10 @@ static const backend_params *ia32_get_libfirm_params(void) { ia32_setup_cg_config(); + /* doesn't really belong here, but this is the earliest place the backend + * is called... */ + init_asm_constraints(); + p.dep_param = &ad; p.if_conv_info = &ifconv; return &p; diff --git a/ir/be/ia32/ia32_transform.c b/ir/be/ia32/ia32_transform.c index d08404880..3e03f84e3 100644 --- a/ir/be/ia32/ia32_transform.c +++ b/ir/be/ia32/ia32_transform.c @@ -3497,11 +3497,12 @@ static ir_node *gen_Conv(ir_node *node) { return res; } -static int check_immediate_constraint(long val, char immediate_constraint_type) +static bool check_immediate_constraint(long val, char immediate_constraint_type) { switch (immediate_constraint_type) { case 0: - return 1; + case 'i': + return true; case 'I': return val >= 0 && val <= 32; case 'J': @@ -3520,7 +3521,7 @@ static int check_immediate_constraint(long val, char immediate_constraint_type) break; } panic("Invalid immediate constraint found"); - return 0; + return false; } static ir_node *try_create_Immediate(ir_node *node, @@ -3638,29 +3639,30 @@ static ir_node *create_immediate_or_transform(ir_node *node, -void parse_asm_constraint(int pos, constraint_t *constraint, const char *c) +void parse_asm_constraints(constraint_t *constraint, const char *c, + bool is_output) { - int immediate_possible = 0; - char immediate_type = 0; + asm_constraint_flags_t flags = 0; + char immediate_type = '\0'; unsigned limited = 0; const arch_register_class_t *cls = NULL; - ir_graph *irg = current_ir_graph; - struct obstack *obst = get_irg_obstack(irg); - arch_register_req_t *req; - unsigned *limited_ptr = NULL; + bool memory_possible = false; + bool all_registers_allowed = false; int p; int same_as = -1; - /* TODO: replace all the asserts with nice error messages */ + memset(constraint, 0, sizeof(constraint[0])); + constraint->same_as = -1; if(*c == 0) { /* a memory constraint: no need to do anything in backend about it * (the dependencies are already respected by the memory edge of * the node) */ - constraint->req = &no_register_req; return; } + /* TODO: improve error messages with node and source info. (As users can + * easily hit these) */ while(*c != 0) { switch(*c) { case ' ': @@ -3668,60 +3670,70 @@ void parse_asm_constraint(int pos, constraint_t *constraint, const char *c) case '\n': break; + case '=': + flags |= ASM_CONSTRAINT_FLAG_MODIFIER_WRITE + | ASM_CONSTRAINT_FLAG_MODIFIER_NO_READ; + break; + + case '+': + flags |= ASM_CONSTRAINT_FLAG_MODIFIER_WRITE + | ASM_CONSTRAINT_FLAG_MODIFIER_READ; + break; + + case '*': + ++c; + break; + case '#': + while(*c != 0 && *c != ',') + ++c; + break; + case 'a': - assert(cls == NULL || - (cls == &ia32_reg_classes[CLASS_ia32_gp] && limited != 0)); + assert(cls == NULL || cls == &ia32_reg_classes[CLASS_ia32_gp]); 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)); + assert(cls == NULL || cls == &ia32_reg_classes[CLASS_ia32_gp]); 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)); + assert(cls == NULL || cls == &ia32_reg_classes[CLASS_ia32_gp]); 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)); + assert(cls == NULL || cls == &ia32_reg_classes[CLASS_ia32_gp]); 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)); + assert(cls == NULL || cls == &ia32_reg_classes[CLASS_ia32_gp]); 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)); + assert(cls == NULL || cls == &ia32_reg_classes[CLASS_ia32_gp]); 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)); + case 'q': + /* q means lower part of the regs only, this makes no + * difference to Q for us (we only assign whole registers) */ + assert(cls == NULL || cls == &ia32_reg_classes[CLASS_ia32_gp]); 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)); + assert(cls == NULL || cls == &ia32_reg_classes[CLASS_ia32_gp]); 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)); + assert(cls == NULL || cls == &ia32_reg_classes[CLASS_ia32_gp]); 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 | @@ -3731,23 +3743,28 @@ void parse_asm_constraint(int pos, constraint_t *constraint, const char *c) case 'R': case 'r': case 'p': - assert(cls == NULL); - cls = &ia32_reg_classes[CLASS_ia32_gp]; + if (cls != NULL && cls != &ia32_reg_classes[CLASS_ia32_gp]) + panic("multiple register classes not supported"); + cls = &ia32_reg_classes[CLASS_ia32_gp]; + all_registers_allowed = true; break; case 'f': case 't': case 'u': /* TODO: mark values so the x87 simulator knows about t and u */ - assert(cls == NULL); - cls = &ia32_reg_classes[CLASS_ia32_vfp]; + if (cls != NULL && cls != &ia32_reg_classes[CLASS_ia32_vfp]) + panic("multiple register classes not supported"); + cls = &ia32_reg_classes[CLASS_ia32_vfp]; + all_registers_allowed = true; break; case 'Y': case 'x': - assert(cls == NULL); - /* TODO: check that sse2 is supported */ - cls = &ia32_reg_classes[CLASS_ia32_xmm]; + if (cls != NULL && cls != &ia32_reg_classes[CLASS_ia32_xmm]) + panic("multiple register classes not supproted"); + cls = &ia32_reg_classes[CLASS_ia32_xmm]; + all_registers_allowed = true; break; case 'I': @@ -3757,20 +3774,33 @@ void parse_asm_constraint(int pos, constraint_t *constraint, const char *c) case 'M': case 'N': case 'O': - assert(!immediate_possible); - immediate_possible = 1; - immediate_type = *c; + if (cls != NULL && cls != &ia32_reg_classes[CLASS_ia32_gp]) + panic("multiple register classes not supported"); + if (immediate_type != '\0') + panic("multiple immediate types not supported"); + cls = &ia32_reg_classes[CLASS_ia32_gp]; + immediate_type = *c; break; case 'n': case 'i': - assert(!immediate_possible); - immediate_possible = 1; + if (cls != NULL && cls != &ia32_reg_classes[CLASS_ia32_gp]) + panic("multiple register classes not supported"); + if (immediate_type != '\0') + panic("multiple immediate types not supported"); + cls = &ia32_reg_classes[CLASS_ia32_gp]; + immediate_type = 'i'; break; + case 'X': case 'g': - assert(!immediate_possible && cls == NULL); - immediate_possible = 1; - cls = &ia32_reg_classes[CLASS_ia32_gp]; + if (cls != NULL && cls != &ia32_reg_classes[CLASS_ia32_gp]) + panic("multiple register classes not supported"); + if (immediate_type != '\0') + panic("multiple immediate types not supported"); + immediate_type = 'i'; + cls = &ia32_reg_classes[CLASS_ia32_gp]; + all_registers_allowed = true; + memory_possible = true; break; case '0': @@ -3783,8 +3813,8 @@ void parse_asm_constraint(int pos, constraint_t *constraint, const char *c) case '7': case '8': case '9': - assert(constraint->is_in && "can only specify same constraint " - "on input"); + if (is_output) + panic("can only specify same constraint on input"); sscanf(c, "%d%n", &same_as, &p); if(same_as >= 0) { @@ -3799,13 +3829,12 @@ void parse_asm_constraint(int pos, constraint_t *constraint, const char *c) /* memory constraint no need to do anything in backend about it * (the dependencies are already respected by the memory edge of * the node) */ - constraint->req = &no_register_req; - return; + memory_possible = true; + 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 '<': /* no autodecrement on x86 */ case '>': /* no autoincrement on x86 */ case 'C': /* sse constant not supported yet */ @@ -3825,15 +3854,39 @@ void parse_asm_constraint(int pos, constraint_t *constraint, const char *c) } if(same_as >= 0) { + if (cls != NULL) + panic("same as and register constraint not supported"); + if (immediate_type != '\0') + panic("same as and immediate constraint not supported"); + } + + if (cls == NULL && same_as < 0) { + if (!memory_possible) + panic("no constraint specified for assembler input"); + } + + constraint->same_as = same_as; + constraint->cls = cls; + constraint->allowed_registers = limited; + constraint->all_registers_allowed = all_registers_allowed; + constraint->memory_possible = memory_possible; + constraint->immediate_type = immediate_type; +} + +const arch_register_req_t *make_register_req(const constraint_t *constraint, + int n_outs, const arch_register_req_t **out_reqs, int pos) +{ + struct obstack *obst = get_irg_obstack(current_ir_graph); + int same_as = constraint->same_as; + arch_register_req_t *req; + + 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"); + if (same_as >= n_outs) + panic("invalid output number in same_as constraint"); - other_constr = constraint->out_reqs[same_as]; + other_constr = out_reqs[same_as]; req = obstack_alloc(obst, sizeof(req[0])); req->cls = other_constr->cls; @@ -3845,44 +3898,34 @@ void parse_asm_constraint(int pos, constraint_t *constraint, const char *c) /* 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; + out_reqs[same_as] = req; + return other_constr; } - if(immediate_possible && cls == NULL) { - cls = &ia32_reg_classes[CLASS_ia32_gp]; + /* pure memory ops */ + if (constraint->cls == NULL) { + return &no_register_req; } - assert(!immediate_possible || cls == &ia32_reg_classes[CLASS_ia32_gp]); - assert(cls != NULL); - if(immediate_possible) { - assert(constraint->is_in - && "immediate make no sense for output constraints"); - } - /* todo: check types (no float input on 'r' constrained in and such... */ + if (constraint->allowed_registers != 0 + && !constraint->all_registers_allowed) { + unsigned *limited_ptr; - 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])); + req = obstack_alloc(obst, sizeof(req[0]) + sizeof(unsigned)); + memset(req, 0, sizeof(req[0])); + limited_ptr = (unsigned*) (req+1); - if(limited != 0) { req->type = arch_register_req_type_limited; - *limited_ptr = limited; + *limited_ptr = constraint->allowed_registers; req->limited = limited_ptr; } else { - req->type = arch_register_req_type_normal; + req = obstack_alloc(obst, sizeof(req[0])); + memset(req, 0, sizeof(req[0])); + req->type = arch_register_req_type_normal; } - req->cls = cls; + req->cls = constraint->cls; - constraint->req = req; - constraint->immediate_possible = immediate_possible; - constraint->immediate_type = immediate_type; + return req; } const arch_register_t *ia32_get_clobber_register(const char *clobber) @@ -3911,20 +3954,15 @@ const arch_register_t *ia32_get_clobber_register(const char *clobber) return reg; } -void parse_clobber(ir_node *node, int pos, constraint_t *constraint, - const char *clobber) +const arch_register_req_t *parse_clobber(const char *clobber) { - ir_graph *irg = get_irn_irg(node); - struct obstack *obst = get_irg_obstack(irg); - const arch_register_t *reg = ia32_get_clobber_register(clobber); - arch_register_req_t *req; - unsigned *limited; - - (void) pos; + struct obstack *obst = get_irg_obstack(current_ir_graph); + const arch_register_t *reg = ia32_get_clobber_register(clobber); + arch_register_req_t *req; + unsigned *limited; if(reg == NULL) { panic("Register '%s' mentioned in asm clobber is unknown\n", clobber); - return; } assert(reg->index < 32); @@ -3938,23 +3976,7 @@ void parse_clobber(ir_node *node, int pos, constraint_t *constraint, req->cls = arch_register_get_class(reg); req->limited = limited; - constraint->req = req; - constraint->immediate_possible = 0; - constraint->immediate_type = 0; -} - -static int is_memory_op(const ir_asm_constraint *constraint) -{ - ident *id = constraint->constraint; - const char *str = get_id_str(id); - const char *c; - - for(c = str; *c != '\0'; ++c) { - if(*c == 'm') - return 1; - } - - return 0; + return req; } /** @@ -3962,11 +3984,12 @@ static int is_memory_op(const ir_asm_constraint *constraint) */ static ir_node *gen_ASM(ir_node *node) { - int i, arity; ir_graph *irg = current_ir_graph; ir_node *block = get_nodes_block(node); ir_node *new_block = be_transform_node(block); dbg_info *dbgi = get_irn_dbg_info(node); + int i, arity; + int out_idx; ir_node **in; ir_node *new_node; int out_arity; @@ -3980,114 +4003,130 @@ static ir_node *gen_ASM(ir_node *node) const ir_asm_constraint *in_constraints; const ir_asm_constraint *out_constraints; ident **clobbers; - constraint_t parsed_constraint; + bool clobbers_flags = false; + + /* workaround for lots of buggy code out there as most people think volatile + * asm is enough for everything and forget the flags (linux kernel, etc.) + */ + if (get_irn_pinned(node) == op_pin_state_pinned) { + clobbers_flags = true; + } arity = get_irn_arity(node); in = alloca(arity * sizeof(in[0])); memset(in, 0, arity * sizeof(in[0])); + clobbers = get_ASM_clobbers(node); + n_clobbers = 0; + for(i = 0; i < get_ASM_n_clobbers(node); ++i) { + const char *c = get_id_str(clobbers[i]); + if (strcmp(c, "memory") == 0) + continue; + if (strcmp(c, "cc") == 0) { + clobbers_flags = true; + continue; + } + n_clobbers++; + } n_out_constraints = get_ASM_n_output_constraints(node); - n_clobbers = get_ASM_n_clobbers(node); out_arity = n_out_constraints + n_clobbers; - /* hack to keep space for mem proj */ - if(n_clobbers > 0) - out_arity += 1; in_constraints = get_ASM_input_constraints(node); out_constraints = get_ASM_output_constraints(node); - clobbers = get_ASM_clobbers(node); - - /* construct output constraints */ - obst = get_irg_obstack(irg); - out_reg_reqs = obstack_alloc(obst, out_arity * sizeof(out_reg_reqs[0])); - parsed_constraint.out_reqs = out_reg_reqs; - parsed_constraint.n_outs = n_out_constraints; - parsed_constraint.is_in = 0; - for(i = 0; i < out_arity; ++i) { - const char *c; - - if(i < n_out_constraints) { - const ir_asm_constraint *constraint = &out_constraints[i]; - c = get_id_str(constraint->constraint); - parse_asm_constraint(i, &parsed_constraint, c); - - if(constraint->pos > reg_map_size) - reg_map_size = constraint->pos; - - out_reg_reqs[i] = parsed_constraint.req; - } else if(i < out_arity - 1) { - ident *glob_id = clobbers [i - n_out_constraints]; - assert(glob_id != NULL); - c = get_id_str(glob_id); - parse_clobber(node, i, &parsed_constraint, c); - - out_reg_reqs[i+1] = parsed_constraint.req; - } + /* determine size of register_map */ + for(out_idx = 0; out_idx < n_out_constraints; ++out_idx) { + const ir_asm_constraint *constraint = &out_constraints[out_idx]; + if (constraint->pos > reg_map_size) + reg_map_size = constraint->pos; } - if(n_clobbers > 1) - out_reg_reqs[n_out_constraints] = &no_register_req; - - /* construct input constraints */ - in_reg_reqs = obstack_alloc(obst, arity * sizeof(in_reg_reqs[0])); - parsed_constraint.is_in = 1; for(i = 0; i < arity; ++i) { const ir_asm_constraint *constraint = &in_constraints[i]; - ident *constr_id = constraint->constraint; - const char *c = get_id_str(constr_id); - - parse_asm_constraint(i, &parsed_constraint, c); - in_reg_reqs[i] = parsed_constraint.req; - if(constraint->pos > reg_map_size) reg_map_size = constraint->pos; - - if(parsed_constraint.immediate_possible) { - ir_node *pred = get_irn_n(node, i); - char imm_type = parsed_constraint.immediate_type; - ir_node *immediate = try_create_Immediate(pred, imm_type); - - if(immediate != NULL) { - in[i] = immediate; - } - } } - reg_map_size++; + ++reg_map_size; + obst = get_irg_obstack(irg); register_map = NEW_ARR_D(ia32_asm_reg_t, obst, reg_map_size); memset(register_map, 0, reg_map_size * sizeof(register_map[0])); - for(i = 0; i < n_out_constraints; ++i) { - const ir_asm_constraint *constraint = &out_constraints[i]; - unsigned pos = constraint->pos; + /* construct output constraints */ + out_reg_reqs = obstack_alloc(obst, out_arity * sizeof(out_reg_reqs[0])); - assert(pos < reg_map_size); - register_map[pos].use_input = 0; - register_map[pos].valid = 1; - register_map[pos].memory = is_memory_op(constraint); - register_map[pos].inout_pos = i; + for(out_idx = 0; out_idx < n_out_constraints; ++out_idx) { + const ir_asm_constraint *constraint = &out_constraints[out_idx]; + const char *c = get_id_str(constraint->constraint); + unsigned pos = constraint->pos; + constraint_t parsed_constraint; + const arch_register_req_t *req; + + parse_asm_constraints(&parsed_constraint, c, true); + req = make_register_req(&parsed_constraint, n_out_constraints, + out_reg_reqs, out_idx); + out_reg_reqs[out_idx] = req; + + register_map[pos].use_input = false; + register_map[pos].valid = true; + register_map[pos].memory = false; + register_map[pos].inout_pos = out_idx; register_map[pos].mode = constraint->mode; } - /* transform inputs */ + /* inputs + input constraints */ + in_reg_reqs = obstack_alloc(obst, arity * sizeof(in_reg_reqs[0])); for(i = 0; i < arity; ++i) { - const ir_asm_constraint *constraint = &in_constraints[i]; - unsigned pos = constraint->pos; - ir_node *pred = get_irn_n(node, i); - ir_node *transformed; - - assert(pos < reg_map_size); - register_map[pos].use_input = 1; - register_map[pos].valid = 1; - register_map[pos].memory = is_memory_op(constraint); + ir_node *pred = get_irn_n(node, i); + const ir_asm_constraint *constraint = &in_constraints[i]; + ident *constr_id = constraint->constraint; + const char *c = get_id_str(constr_id); + unsigned pos = constraint->pos; + bool is_memory_op = false; + ir_node *input = NULL; + constraint_t parsed_constraint; + const arch_register_req_t *req; + + parse_asm_constraints(&parsed_constraint, c, false); + req = make_register_req(&parsed_constraint, n_out_constraints, + out_reg_reqs, i); + in_reg_reqs[i] = req; + + if (parsed_constraint.immediate_type != '\0') { + char imm_type = parsed_constraint.immediate_type; + input = try_create_Immediate(pred, imm_type); + } + + if (input == NULL) { + ir_node *pred = get_irn_n(node, i); + input = be_transform_node(pred); + + if (parsed_constraint.cls == NULL + && parsed_constraint.same_as < 0) { + is_memory_op = true; + } else if(parsed_constraint.memory_possible) { + /* TODO: match Load or Load/Store if memory possible is set */ + } + } + in[i] = input; + + register_map[pos].use_input = true; + register_map[pos].valid = true; + register_map[pos].memory = is_memory_op; register_map[pos].inout_pos = i; register_map[pos].mode = constraint->mode; + } + + /* parse clobbers */ + for(i = 0; i < get_ASM_n_clobbers(node); ++i) { + const char *c = get_id_str(clobbers[i]); + const arch_register_req_t *req; - if(in[i] != NULL) + if (strcmp(c, "memory") == 0 || strcmp(c, "cc") == 0) continue; - transformed = be_transform_node(pred); - in[i] = transformed; + req = parse_clobber(c); + out_reg_reqs[out_idx] = req; + ++out_idx; } new_node = new_rd_ia32_Asm(dbgi, irg, new_block, arity, in, out_arity, @@ -5503,9 +5542,9 @@ void ia32_transform_graph(ia32_code_gen_t *cg) { env_cg = cg; initial_fpcw = NULL; -BE_TIMER_PUSH(t_heights); + BE_TIMER_PUSH(t_heights); heights = heights_new(irg); -BE_TIMER_POP(t_heights); + BE_TIMER_POP(t_heights); ia32_calculate_non_address_mode_nodes(cg->birg); /* the transform phase is not safe for CSE (yet) because several nodes get diff --git a/ir/be/ia32/ia32_transform.h b/ir/be/ia32/ia32_transform.h index a95924b2f..f43c80474 100644 --- a/ir/be/ia32/ia32_transform.h +++ b/ir/be/ia32/ia32_transform.h @@ -67,13 +67,12 @@ static const arch_register_req_t no_register_req = { */ 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; + const arch_register_class_t *cls; + unsigned allowed_registers; + bool all_registers_allowed; + bool memory_possible; + char immediate_type; + int same_as; }; /** @@ -98,9 +97,9 @@ ir_type *ia32_get_prim_type(pmap *types, ir_mode *mode); */ int ia32_mode_needs_gp_reg(ir_mode *mode); -void parse_asm_constraint(int pos, constraint_t *constraint, const char *c); -void parse_clobber(ir_node *node, int pos, constraint_t *constraint, - const char *clobber); +void ia32_parse_asm_constraints(constraint_t *constraint, const char *c); +void ia32_parse_clobber(ir_node *node, int pos, constraint_t *constraint, + const char *clobber); /** * returns register by name (used for determining clobber specifications in diff --git a/ir/be/test/asm_test.c b/ir/be/test/asm_test.c index 16ce11cbe..a25e781d6 100644 --- a/ir/be/test/asm_test.c +++ b/ir/be/test/asm_test.c @@ -25,11 +25,11 @@ static void sincostest(double arg) printf("Arg: %f Sin: %f Cos: %f\n", arg, sin, cos); } -static inline int mov(int val) +static inline int mov_noeax(int val) { int res; - __asm__ ("movl %1, %0" : "=r"(res) : "ri" (val)); + __asm__ ("movl %1, %0" : "=r"(res) : "ri" (val) : "eax"); return res; } @@ -46,9 +46,14 @@ static inline unsigned int swap32(unsigned int x) return x; } -static inline void inc(int *v) +void inc(int *v) { - __asm__("incl %0" : "+g" (*v) : : "cc"); + __asm__("incl %0" : "+rm" (*v) : : "cc"); +} + +void inc2(int *v) +{ + __asm__("incl %0" : "+m" (*v) : : "cc"); } #if 1 @@ -61,7 +66,7 @@ typedef int kernel_fd_set; #endif void fd_set(int fd, kernel_fd_set* set) { - __asm__("btsl %1,%0" : "=m" (*(set)) : "r" (fd)); + __asm__("btsl %1,%0" : "=m" (*(set)) : "r" (fd) : "cc"); } int fd_isset(int fd, kernel_fd_set *set) { @@ -70,7 +75,8 @@ int fd_isset(int fd, kernel_fd_set *set) { __asm__ __volatile__("btl %1,%2\n" "\tsetb %0" : "=q" (result) - : "r" (fd), "m" (*set)); + : "r" (fd), "m" (*set) + : "cc"); return result; } @@ -93,9 +99,9 @@ int main() swap16(0xAABB), swap32(0xAABBCCDD)); k = 41; inc(&k); - printf("mov(inc(41)): %d\n", mov(k)); + printf("mov(inc(41)): %d\n", mov_noeax(k)); - return mov(0); + return mov_noeax(0); } #else -- 2.20.1