X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fia32%2Fia32_common_transform.c;h=3aff73808c85b7fac76d52f9e62bac87011650d3;hb=fa58db3dfe73586f59ba99952806e418849c9740;hp=0c81ef4d8fd8709b555925f498302d137e1e7f27;hpb=b38b52e7426cd2bf243282db922e135422d435b7;p=libfirm diff --git a/ir/be/ia32/ia32_common_transform.c b/ir/be/ia32/ia32_common_transform.c index 0c81ef4d8..3aff73808 100644 --- a/ir/be/ia32/ia32_common_transform.c +++ b/ir/be/ia32/ia32_common_transform.c @@ -21,9 +21,12 @@ * @file * @brief This file implements the common parts of IR transformation from * firm into ia32-Firm. - * @author Sebastian Buchwald + * @author Matthias Braun, Sebastian Buchwald * @version $Id: ia32_common_transform.c 21012 2008-08-06 13:35:17Z beck $ */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include "error.h" #include "irargs_t.h" @@ -32,6 +35,7 @@ #include "typerep.h" #include "../betranshlp.h" +#include "../beirg_t.h" #include "ia32_architecture.h" #include "ia32_common_transform.h" @@ -41,7 +45,9 @@ #include "gen_ia32_regalloc_if.h" /** hold the current code generator during transformation */ -ia32_code_gen_t *env_cg = NULL; +ia32_code_gen_t *env_cg = NULL; + +heights_t *heights = NULL; static const arch_register_req_t no_register_req = { arch_register_req_type_none, @@ -54,28 +60,19 @@ static const arch_register_req_t no_register_req = { static int check_immediate_constraint(long val, char immediate_constraint_type) { switch (immediate_constraint_type) { - case 0: - case 'i': - 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; + case 0: + case 'i': return 1; + + case 'I': return 0 <= val && val <= 31; + case 'J': return 0 <= val && val <= 63; + case 'K': return -128 <= val && val <= 127; + case 'L': return val == 0xff || val == 0xffff; + case 'M': return 0 <= val && val <= 3; + case 'N': return 0 <= val && val <= 255; + case 'O': return 0 <= val && val <= 127; + + default: panic("Invalid immediate constraint found"); } - panic("Invalid immediate constraint found"); - return 0; } /** @@ -229,7 +226,6 @@ int ia32_mode_needs_gp_reg(ir_mode *mode) { static void parse_asm_constraints(constraint_t *constraint, const char *c, int is_output) { - asm_constraint_flags_t flags = 0; char immediate_type = '\0'; unsigned limited = 0; const arch_register_class_t *cls = NULL; @@ -257,15 +253,9 @@ static void parse_asm_constraints(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; + /* Skip out/in-out marker */ + case '=': break; + case '+': break; case '*': ++c; @@ -463,8 +453,8 @@ static void parse_asm_constraints(constraint_t *constraint, const char *c, ir_node *gen_ASM(ir_node *node) { ir_graph *irg = current_ir_graph; - ir_node *block = get_nodes_block(node); - ir_node *new_block = be_transform_node(block); + ir_node *block = NULL; + ir_node *new_block = NULL; dbg_info *dbgi = get_irn_dbg_info(node); int i, arity; int out_idx; @@ -482,6 +472,26 @@ ir_node *gen_ASM(ir_node *node) const ir_asm_constraint *out_constraints; ident **clobbers; int clobbers_flags = 0; + unsigned clobber_bits[N_CLASSES]; + + memset(&clobber_bits, 0, sizeof(clobber_bits)); + + switch (be_transformer) { + case TRANSFORMER_DEFAULT: + block = get_nodes_block(node); + new_block = be_transform_node(block); + break; + +#ifdef FIRM_GRGEN_BE + case TRANSFORMER_PBQP: + case TRANSFORMER_RAND: + new_block = get_nodes_block(node); + break; +#endif + + default: + panic("invalid transformer"); + } /* 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.) @@ -496,14 +506,20 @@ ir_node *gen_ASM(ir_node *node) 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]); + for (i = 0; i < get_ASM_n_clobbers(node); ++i) { + const arch_register_req_t *req; + const char *c = get_id_str(clobbers[i]); + if (strcmp(c, "memory") == 0) continue; if (strcmp(c, "cc") == 0) { clobbers_flags = 1; continue; } + + req = parse_clobber(c); + clobber_bits[req->cls->index] |= *req->limited; + n_clobbers++; } n_out_constraints = get_ASM_n_output_constraints(node); @@ -513,12 +529,12 @@ ir_node *gen_ASM(ir_node *node) out_constraints = get_ASM_output_constraints(node); /* determine size of register_map */ - for(out_idx = 0; out_idx < n_out_constraints; ++out_idx) { + 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; } - for(i = 0; i < arity; ++i) { + for (i = 0; i < arity; ++i) { const ir_asm_constraint *constraint = &in_constraints[i]; if(constraint->pos > reg_map_size) reg_map_size = constraint->pos; @@ -532,7 +548,7 @@ ir_node *gen_ASM(ir_node *node) /* construct output constraints */ out_reg_reqs = obstack_alloc(obst, out_arity * sizeof(out_reg_reqs[0])); - for(out_idx = 0; out_idx < n_out_constraints; ++out_idx) { + 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; @@ -553,7 +569,7 @@ ir_node *gen_ASM(ir_node *node) /* inputs + input constraints */ in_reg_reqs = obstack_alloc(obst, arity * sizeof(in_reg_reqs[0])); - for(i = 0; i < arity; ++i) { + for (i = 0; i < arity; ++i) { ir_node *pred = get_irn_n(node, i); const ir_asm_constraint *constraint = &in_constraints[i]; ident *constr_id = constraint->constraint; @@ -561,10 +577,24 @@ ir_node *gen_ASM(ir_node *node) unsigned pos = constraint->pos; int is_memory_op = 0; ir_node *input = NULL; + unsigned r_clobber_bits; constraint_t parsed_constraint; const arch_register_req_t *req; parse_asm_constraints(&parsed_constraint, c, 0); + if (parsed_constraint.cls != NULL) { + r_clobber_bits = clobber_bits[parsed_constraint.cls->index]; + if (r_clobber_bits != 0) { + if (parsed_constraint.all_registers_allowed) { + parsed_constraint.all_registers_allowed = 0; + be_abi_set_non_ignore_regs(env_cg->birg->abi, + parsed_constraint.cls, + &parsed_constraint.allowed_registers); + } + parsed_constraint.allowed_registers &= ~r_clobber_bits; + } + } + req = make_register_req(&parsed_constraint, n_out_constraints, out_reg_reqs, i); in_reg_reqs[i] = req; @@ -575,8 +605,22 @@ ir_node *gen_ASM(ir_node *node) } if (input == NULL) { - ir_node *pred = get_irn_n(node, i); - input = be_transform_node(pred); + ir_node *pred = NULL; + switch (be_transformer) { + case TRANSFORMER_DEFAULT: + pred = get_irn_n(node, i); + input = be_transform_node(pred); + break; + +#ifdef FIRM_GRGEN_BE + case TRANSFORMER_PBQP: + case TRANSFORMER_RAND: + input = get_irn_n(node, i); + break; +#endif + + default: panic("invalid transformer"); + } if (parsed_constraint.cls == NULL && parsed_constraint.same_as < 0) { @@ -595,7 +639,7 @@ ir_node *gen_ASM(ir_node *node) } /* parse clobbers */ - for(i = 0; i < get_ASM_n_clobbers(node); ++i) { + for (i = 0; i < get_ASM_n_clobbers(node); ++i) { const char *c = get_id_str(clobbers[i]); const arch_register_req_t *req; @@ -610,6 +654,12 @@ ir_node *gen_ASM(ir_node *node) new_node = new_rd_ia32_Asm(dbgi, irg, new_block, arity, in, out_arity, get_ASM_text(node), register_map); + /* Prevent the ASM node from being scheduled before the Barrier, if it has + * no inputs */ + if (arity == 0 && get_irg_start_block(irg) == new_block) { + add_irn_dep(new_node, get_irg_frame(irg)); + } + set_ia32_out_req_all(new_node, out_reg_reqs); set_ia32_in_req_all(new_node, in_reg_reqs); @@ -618,6 +668,93 @@ ir_node *gen_ASM(ir_node *node) return new_node; } +ir_node *gen_CopyB(ir_node *node) { + ir_node *block = NULL; + ir_node *src = NULL; + ir_node *new_src = NULL; + ir_node *dst = NULL; + ir_node *new_dst = NULL; + ir_node *mem = NULL; + ir_node *new_mem = NULL; + ir_node *res = NULL; + ir_graph *irg = current_ir_graph; + dbg_info *dbgi = get_irn_dbg_info(node); + int size = get_type_size_bytes(get_CopyB_type(node)); + int rem; + + switch (be_transformer) { + case TRANSFORMER_DEFAULT: + block = be_transform_node(get_nodes_block(node)); + src = get_CopyB_src(node); + new_src = be_transform_node(src); + dst = get_CopyB_dst(node); + new_dst = be_transform_node(dst); + mem = get_CopyB_mem(node); + new_mem = be_transform_node(mem); + break; + +#ifdef FIRM_GRGEN_BE + case TRANSFORMER_PBQP: + case TRANSFORMER_RAND: + block = get_nodes_block(node); + new_src = get_CopyB_src(node); + new_dst = get_CopyB_dst(node); + new_mem = get_CopyB_mem(node); + break; +#endif + + default: panic("invalid transformer"); + } + + /* If we have to copy more than 32 bytes, we use REP MOVSx and */ + /* then we need the size explicitly in ECX. */ + if (size >= 32 * 4) { + rem = size & 0x3; /* size % 4 */ + size >>= 2; + + res = new_rd_ia32_Const(dbgi, irg, block, NULL, 0, size); + add_irn_dep(res, get_irg_frame(irg)); + + res = new_rd_ia32_CopyB(dbgi, irg, block, new_dst, new_src, res, new_mem, rem); + } else { + if(size == 0) { + ir_fprintf(stderr, "Optimization warning copyb %+F with size <4\n", + node); + } + res = new_rd_ia32_CopyB_i(dbgi, irg, block, new_dst, new_src, new_mem, size); + } + + SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node)); + + return res; +} + +ir_node *gen_Proj_tls(ir_node *node) { + ir_node *block = NULL; + ir_graph *irg = current_ir_graph; + dbg_info *dbgi = NULL; + ir_node *res = NULL; + + switch (be_transformer) { + case TRANSFORMER_DEFAULT: + block = be_transform_node(get_nodes_block(node)); + break; + +#ifdef FIRM_GRGEN_BE + case TRANSFORMER_PBQP: + case TRANSFORMER_RAND: + block = get_nodes_block(node); + break; +#endif + + default: panic("invalid transformer"); + } + + res = new_rd_ia32_LdTls(dbgi, irg, block, mode_Iu); + + return res; +} + ir_node *gen_Unknown(ir_node *node) { ir_mode *mode = get_irn_mode(node); @@ -661,14 +798,12 @@ const arch_register_req_t *make_register_req(const constraint_t *constraint, if (same_as >= n_outs) panic("invalid output number in same_as constraint"); - other_constr = out_reqs[same_as]; + other_constr = 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 = 1U << pos; - req->other_different = 0; + req = obstack_alloc(obst, sizeof(req[0])); + *req = *other_constr; + req->type |= arch_register_req_type_should_be_same; + req->other_same = 1U << pos; /* switch constraints. This is because in firm we have same_as * constraints on the output constraints while in the gcc asm syntax @@ -711,7 +846,7 @@ const arch_register_req_t *parse_clobber(const char *clobber) unsigned *limited; if(reg == NULL) { - panic("Register '%s' mentioned in asm clobber is unknown\n", clobber); + panic("Register '%s' mentioned in asm clobber is unknown", clobber); } assert(reg->index < 32); @@ -728,6 +863,45 @@ const arch_register_req_t *parse_clobber(const char *clobber) return req; } + +int prevents_AM(ir_node *const block, ir_node *const am_candidate, + ir_node *const other) +{ + if (get_nodes_block(other) != block) + return 0; + + if (is_Sync(other)) { + int i; + + for (i = get_Sync_n_preds(other) - 1; i >= 0; --i) { + ir_node *const pred = get_Sync_pred(other, i); + + if (get_nodes_block(pred) != block) + continue; + + /* Do not block ourselves from getting eaten */ + if (is_Proj(pred) && get_Proj_pred(pred) == am_candidate) + continue; + + if (!heights_reachable_in_block(heights, pred, am_candidate)) + continue; + + return 1; + } + + return 0; + } else { + /* Do not block ourselves from getting eaten */ + if (is_Proj(other) && get_Proj_pred(other) == am_candidate) + return 0; + + if (!heights_reachable_in_block(heights, other, am_candidate)) + return 0; + + return 1; + } +} + ir_node *try_create_Immediate(ir_node *node, char immediate_constraint_type) { int minus = 0;