From: Matthias Braun Date: Sat, 2 Jun 2007 16:49:17 +0000 (+0000) Subject: more work on ia32 assembler nodes X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=69d4cb08c348caa3952009f263f55dec5eeb34b9;p=libfirm more work on ia32 assembler nodes [r14270] --- diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c index c9d1f743e..9986a803f 100644 --- a/ir/be/ia32/ia32_emitter.c +++ b/ir/be/ia32/ia32_emitter.c @@ -1311,18 +1311,135 @@ void emit_Jmp(ia32_emit_env_t *env, const ir_node *node) { be_emit_finish_line_gas(env, node); } +static +const char* emit_asm_operand(ia32_emit_env_t *env, const ir_node *node, + const char *s) +{ + const arch_register_t *reg; + const char *reg_name; + char c; + char modifier = 0; + int num = -1; + ia32_attr_t *attr; + int n_outs; + int p; + + assert(*s == '%'); + c = *(++s); + + /* parse modifiers */ + switch(c) { + case 0: + ir_fprintf(stderr, "Warning: asm text (%+F) ends with %\n", node); + be_emit_char(env, '%'); + return s + 1; + case '%': + be_emit_char(env, '%'); + return s + 1; + case 'w': + case 'b': + modifier = c; + ++s; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + break; + default: + ir_fprintf(stderr, "Warning: asm text (%+F) contains unknown modifier " + "'%c' for asm op\n", node, c); + ++s; + break; + } + + /* parse number */ + sscanf(s, "%d%n", &num, &p); + if(num < 0) { + ir_fprintf(stderr, "Warning: Couldn't parse assembler operand (%+F)\n", + node); + return s; + } else { + s += p; + } + + /* get register */ + attr = get_ia32_attr(node); + n_outs = attr->data.n_res; + if(num < n_outs) { + reg = get_out_reg(env, node, num); + } else { + 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; + } + reg = get_in_reg(env, node, in); + } + if(reg == NULL) { + ir_fprintf(stderr, "Warning: no register assigned for %d asm op " + "(%+F)\n", num, node); + return s; + } + + /* emit it */ + be_emit_char(env, '%'); + switch(modifier) { + case 0: + reg_name = arch_register_get_name(reg); + break; + case 'b': + reg_name = ia32_get_mapped_reg_name(env->isa->regs_8bit, reg); + break; + case 'w': + reg_name = ia32_get_mapped_reg_name(env->isa->regs_16bit, reg); + break; + default: + panic("Invalid asm op modifier"); + } + be_emit_string(env, reg_name); + + return s; +} + /** * Emits code for an ASM pseudo op. */ static -void emit_ASM(ia32_emit_env_t *env, const ir_node *node) { - /* for now, really simple */ - const char *s = get_ASM_text(node); +void emit_ia32_Asm(ia32_emit_env_t *env, const ir_node *node) +{ + ia32_attr_t *attr = get_ia32_attr(node); + ident *asm_text = attr->cnst_val.asm_text; + const char *s = get_id_str(asm_text); - if (s[0] != '\t') - be_emit_cstring(env, "\t"); - be_emit_string(env, s); + be_emit_cstring(env, "# Begin ASM \t"); be_emit_finish_line_gas(env, node); + + if (s[0] != '\t') + be_emit_char(env, '\t'); + + while(*s != 0) { + if(*s == '%') { + s = emit_asm_operand(env, node, s); + continue; + } else { + be_emit_char(env, *s); + } + ++s; + } + + be_emit_char(env, '\n'); + be_emit_write_line(env); + + be_emit_cstring(env, "# End ASM\n"); + be_emit_write_line(env); } /********************************** @@ -1788,6 +1905,7 @@ void ia32_register_emitters(void) { ia32_register_spec_emitters(); /* other ia32 emitter functions */ + IA32_EMIT(Asm); IA32_EMIT(CondJmp); IA32_EMIT(TestJmp); IA32_EMIT(CJmp); @@ -1832,7 +1950,6 @@ void ia32_register_emitters(void) { /* firm emitter */ EMIT(Jmp); - EMIT(ASM); IGN(Proj); IGN(Phi); IGN(Start); diff --git a/ir/be/ia32/ia32_nodes_attr.h b/ir/be/ia32/ia32_nodes_attr.h index 3ef45f2a5..1e8b0265d 100644 --- a/ir/be/ia32/ia32_nodes_attr.h +++ b/ir/be/ia32/ia32_nodes_attr.h @@ -121,6 +121,7 @@ struct ia32_attr_t { union { tarval *tv; /**< tarval for immediate operations */ ir_entity *sc; /**< the symconst ident */ + ident *asm_text; /**< used by asm node */ } cnst_val; ir_mode *ls_mode; /**< Load/Store mode: This is the mode of the value diff --git a/ir/be/ia32/ia32_transform.c b/ir/be/ia32/ia32_transform.c index 3d1a36831..97268ff9b 100644 --- a/ir/be/ia32/ia32_transform.c +++ b/ir/be/ia32/ia32_transform.c @@ -2392,7 +2392,71 @@ static ir_node *gen_Conv(ia32_transform_env_t *env, ir_node *node) { return res; } +static +ir_node *gen_ASM(ia32_transform_env_t *env, ir_node *node) +{ + int i, arity; + ir_graph *irg = env->irg; + ir_node *block = transform_node(env, get_nodes_block(node)); + dbg_info *dbgi = get_irn_dbg_info(node); + ir_node **in; + ir_node *res; + int out_arity; + ia32_attr_t *attr; + const arch_register_req_t **out_reqs; + const arch_register_req_t **in_reqs; + struct obstack *obst; + + + /* assembler could contain float statements */ + FP_USED(env->cg); + + /* 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; + } + + 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); + + /* 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])); + + /* TODO: parse constraints */ + req->type = arch_register_req_type_normal; + req->cls = &ia32_reg_classes[CLASS_ia32_gp]; + out_reqs[i] = 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])); + + /* TODO: parse constraints */ + req->type = arch_register_req_type_normal; + req->cls = &ia32_reg_classes[CLASS_ia32_gp]; + in_reqs[i] = req; + } + set_ia32_in_req_all(res, in_reqs); + + attr = get_ia32_attr(res); + attr->cnst_val.asm_text = get_ASM_text(node); + SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env->cg, node)); + + return res; +} /******************************************** * _ _ @@ -3703,6 +3767,7 @@ static void register_transformers(void) { GEN(Store); GEN(Cond); + GEN(ASM); GEN(CopyB); //GEN(Mux); BAD(Mux); diff --git a/ir/be/test/asm_test.c b/ir/be/test/asm_test.c index 6c8a4c7c4..d6c369656 100644 --- a/ir/be/test/asm_test.c +++ b/ir/be/test/asm_test.c @@ -1,9 +1,42 @@ -double test(double angle) { - double result; - asm ("fsinx %1,%0" : "=f" (result) : "f" (angle)); - return result; +#include + +static inline unsigned char inb(const unsigned short port) +{ + unsigned char val; + + __asm__ __volatile__ ("inb %w1, %0" : "=a"(val) : "dN"(port)); + + return val; +} + +static inline void outb(const unsigned short port, const unsigned char val) +{ + int k = val; /* just here to test the b modifier in %b0 */ + __asm__ __volatile__ ("outb %b0, %1" : : "a"(k), "dN"(port)); +} + +static void sincostest(double arg) +{ + double cos, sin; + + __asm__ ("fsincos" : "=t"(cos), "=u"(sin) : "0" (arg)); + printf("Arg: %f Sin: %f Cos: %f\n", arg, sin, cos); } -int main(int argc, char *argv[]) { - printf("%f\n", test(0.5)); +static inline int mov(int val) +{ + int res; + + __asm__ ("movl %0, %1" : "=r"(res) : "ri" (val)); + + return res; +} + + +int main() +{ + //sincostest(0.5); + //outb(123, 42); + + return mov(0); }