From e787df99468d3875805a509c1f8128cd38673cd3 Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Fri, 15 Jun 2007 09:03:32 +0000 Subject: [PATCH] psi transform and emit logical rewritten from scratch [r14513] --- ir/be/ia32/bearch_ia32.c | 11 +- ir/be/ia32/ia32_emitter.c | 148 ++++++++------- ir/be/ia32/ia32_finish.c | 1 - ir/be/ia32/ia32_new_nodes.c | 37 ++++ ir/be/ia32/ia32_new_nodes.h | 4 + ir/be/ia32/ia32_nodes_attr.h | 25 ++- ir/be/ia32/ia32_optimize.c | 9 - ir/be/ia32/ia32_spec.pl | 37 ++-- ir/be/ia32/ia32_transform.c | 348 +++++++++++++++++------------------ ir/be/ia32/ia32_transform.h | 8 - 10 files changed, 324 insertions(+), 304 deletions(-) diff --git a/ir/be/ia32/bearch_ia32.c b/ir/be/ia32/bearch_ia32.c index 684d5cf30..7802d985b 100644 --- a/ir/be/ia32/bearch_ia32.c +++ b/ir/be/ia32/bearch_ia32.c @@ -867,17 +867,10 @@ ia32_irn_ops_t ia32_irn_ops = { static void ia32_prepare_graph(void *self) { ia32_code_gen_t *cg = self; - /* transform psi condition trees */ - ia32_pre_transform_phase(cg); - - /* transform all remaining nodes */ + /* transform nodes into assembler instructions */ ia32_transform_graph(cg); - //add_fpu_edges(cg->birg); - // Matze: disabled for now. Because after transformation start block has no - // self-loop anymore so it might be merged with its successor block. This - // will bring several nodes to the startblock which sometimes get scheduled - // before the initial IncSP/Barrier + /* do local optimisations (mainly CSE) */ local_optimize_graph(cg->irg); if (cg->dump) diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c index ab56822ab..51372159d 100644 --- a/ir/be/ia32/ia32_emitter.c +++ b/ir/be/ia32/ia32_emitter.c @@ -930,25 +930,58 @@ void emit_ia32_x87CondJmp(ia32_emit_env_t *env, const ir_node *node) { finish_CondJmp(env, node, mode_E, pnc); } +static +void emit_register_or_immediate(ia32_emit_env_t *env, const ir_node *node, + int pos) +{ + ir_node *op = get_irn_n(node, pos); + if(is_ia32_Immediate(op)) { + emit_ia32_Immediate(env, op); + } else { + ia32_emit_source_register(env, node, pos); + } +} + +static +int is_ia32_Immediate_0(const ir_node *node) +{ + const ia32_immediate_attr_t *attr = get_ia32_immediate_attr_const(node); + tarval *tv = attr->offset; + + if(tv == NULL || attr->symconst != NULL) + return 0; + + return classify_tarval(tv) == CNST_NULL; +} + static void CMov_emitter(ia32_emit_env_t *env, const ir_node *node) { long pnc = get_ia32_pncode(node); - int is_PsiCondCMov = is_ia32_PsiCondCMov(node); - int idx_left = 2 - is_PsiCondCMov; - int idx_right = 3 - is_PsiCondCMov; const arch_register_t *in1, *in2, *out; out = arch_get_irn_register(env->arch_env, node); - in1 = arch_get_irn_register(env->arch_env, get_irn_n(node, idx_left)); - in2 = arch_get_irn_register(env->arch_env, get_irn_n(node, idx_right)); + in1 = arch_get_irn_register(env->arch_env, get_irn_n(node, 2)); + in2 = arch_get_irn_register(env->arch_env, get_irn_n(node, 3)); /* we have to emit the cmp first, because the destination register */ /* could be one of the compare registers */ if (is_ia32_CmpCMov(node)) { - be_emit_cstring(env, "\tcmp "); - ia32_emit_source_register(env, node, 1); - be_emit_cstring(env, ", "); - ia32_emit_source_register(env, node, 0); + long pncr = pnc & ~ia32_pn_Cmp_Unsigned; + ir_node *cmp_right = get_irn_n(node, 1); + + if( (pncr == pn_Cmp_Eq || pncr == pn_Cmp_Lg) + && is_ia32_Immediate(cmp_right) + && is_ia32_Immediate_0(cmp_right)) { + be_emit_cstring(env, "\ttest "); + ia32_emit_source_register(env, node, 0); + be_emit_cstring(env, ", "); + ia32_emit_source_register(env, node, 0); + } else { + be_emit_cstring(env, "\tcmp "); + emit_register_or_immediate(env, node, 1); + be_emit_cstring(env, ", "); + ia32_emit_source_register(env, node, 0); + } } else if (is_ia32_xCmpCMov(node)) { be_emit_cstring(env, "\tucomis"); ia32_emit_mode_suffix_mode(env, get_irn_mode(node)); @@ -956,12 +989,6 @@ void CMov_emitter(ia32_emit_env_t *env, const ir_node *node) { ia32_emit_source_register(env, node, 1); be_emit_cstring(env, ", "); ia32_emit_source_register(env, node, 0); - } else if (is_PsiCondCMov) { - /* omit compare because flags are already set by And/Or */ - be_emit_cstring(env, "\ttest "); - ia32_emit_source_register(env, node, 0); - be_emit_cstring(env, ", "); - ia32_emit_source_register(env, node, 0); } else { assert(0 && "unsupported CMov"); } @@ -972,42 +999,26 @@ void CMov_emitter(ia32_emit_env_t *env, const ir_node *node) { } else if (REGS_ARE_EQUAL(out, in1)) { ir_node *n = (ir_node*) node; /* true in == out -> need complement compare and exchange true and default in */ - ir_node *t = get_irn_n(n, idx_left); - set_irn_n(n, idx_left, get_irn_n(n, idx_right)); - set_irn_n(n, idx_right, t); + ir_node *t = get_irn_n(n, 2); + set_irn_n(n, 2, get_irn_n(n, 3)); + set_irn_n(n, 3, t); pnc = get_negated_pnc(pnc, get_irn_mode(node)); } else { /* out is different from in: need copy default -> out */ - if (is_PsiCondCMov) { - be_emit_cstring(env, "\tmovl "); - ia32_emit_dest_register(env, node, 2); - be_emit_cstring(env, ", "); - ia32_emit_dest_register(env, node, 0); - } else { - be_emit_cstring(env, "\tmovl "); - ia32_emit_source_register(env, node, 3); - be_emit_cstring(env, ", "); - ia32_emit_dest_register(env, node, 0); - } - be_emit_finish_line_gas(env, node); - } - - if (is_PsiCondCMov) { - be_emit_cstring(env, "\tcmov"); - ia32_emit_cmp_suffix(env, pnc); - be_emit_cstring(env, "l "); - ia32_emit_source_register(env, node, 1); - be_emit_cstring(env, ", "); - ia32_emit_dest_register(env, node, 0); - } else { - be_emit_cstring(env, "\tcmov"); - ia32_emit_cmp_suffix(env, pnc); - be_emit_cstring(env, "l "); - ia32_emit_source_register(env, node, 2); + be_emit_cstring(env, "\tmovl "); + ia32_emit_source_register(env, node, 3); be_emit_cstring(env, ", "); ia32_emit_dest_register(env, node, 0); + be_emit_finish_line_gas(env, node); } + + be_emit_cstring(env, "\tcmov"); + ia32_emit_cmp_suffix(env, pnc); + be_emit_cstring(env, "l "); + ia32_emit_source_register(env, node, 2); + be_emit_cstring(env, ", "); + ia32_emit_dest_register(env, node, 0); be_emit_finish_line_gas(env, node); } @@ -1016,11 +1027,6 @@ void emit_ia32_CmpCMov(ia32_emit_env_t *env, const ir_node *node) { CMov_emitter(env, node); } -static -void emit_ia32_PsiCondCMov(ia32_emit_env_t *env, const ir_node *node) { - CMov_emitter(env, node); -} - static void emit_ia32_xCmpCMov(ia32_emit_env_t *env, const ir_node *node) { CMov_emitter(env, node); @@ -1028,7 +1034,7 @@ void emit_ia32_xCmpCMov(ia32_emit_env_t *env, const ir_node *node) { static void Set_emitter(ia32_emit_env_t *env, const ir_node *node, ir_mode *mode) { - int pnc = get_ia32_pncode(node); + long pnc = get_ia32_pncode(node); const char *reg8bit; const arch_register_t *out; @@ -1036,16 +1042,25 @@ void Set_emitter(ia32_emit_env_t *env, const ir_node *node, ir_mode *mode) { reg8bit = ia32_get_mapped_reg_name(env->isa->regs_8bit, out); if (is_ia32_CmpSet(node)) { - be_emit_cstring(env, "\tcmp "); - ia32_emit_binop(env, node); + long pncr = pnc & ~ia32_pn_Cmp_Unsigned; + ir_node *cmp_right = get_irn_n(node, n_ia32_CmpSet_cmp_right); + + if( (pncr == pn_Cmp_Eq || pncr == pn_Cmp_Lg) + && is_ia32_Immediate(cmp_right) + && is_ia32_Immediate_0(cmp_right)) { + be_emit_cstring(env, "\ttest "); + ia32_emit_source_register(env, node, n_ia32_CmpSet_cmp_left); + be_emit_cstring(env, ", "); + ia32_emit_source_register(env, node, n_ia32_CmpSet_cmp_left); + } else { + be_emit_cstring(env, "\tcmp "); + ia32_emit_binop(env, node); + } } else if (is_ia32_xCmpSet(node)) { be_emit_cstring(env, "\tucomis"); ia32_emit_mode_suffix_mode(env, get_irn_mode(get_irn_n(node, 2))); be_emit_char(env, ' '); ia32_emit_binop(env, node); - } else if (is_ia32_PsiCondSet(node)) { - be_emit_cstring(env, "\tcmp $0, "); - ia32_emit_source_register(env, node, 0); } else { assert(0 && "unsupported Set"); } @@ -1068,11 +1083,6 @@ void emit_ia32_CmpSet(ia32_emit_env_t *env, const ir_node *node) { Set_emitter(env, node, get_irn_mode(get_irn_n(node, 2))); } -static -void emit_ia32_PsiCondSet(ia32_emit_env_t *env, const ir_node *node) { - Set_emitter(env, node, get_irn_mode(get_irn_n(node, 0))); -} - static void emit_ia32_xCmpSet(ia32_emit_env_t *env, const ir_node *node) { Set_emitter(env, node, get_irn_mode(get_irn_n(node, 2))); @@ -1336,22 +1346,22 @@ void emit_Jmp(ia32_emit_env_t *env, const ir_node *node) { static void emit_ia32_Immediate(ia32_emit_env_t *env, const ir_node *node) { - const ia32_attr_t *attr = get_ia32_attr_const(node); + const ia32_immediate_attr_t *attr = get_ia32_immediate_attr_const(node); - assert(attr->am_sc != NULL || attr->cnst_val.tv != NULL); - if(attr->am_sc != NULL) { - ident *id = get_entity_ld_ident(attr->am_sc); + assert(attr->symconst != NULL || attr->offset != NULL); + if(attr->symconst != NULL) { + ident *id = get_entity_ld_ident(attr->symconst); - if(attr->data.am_sc_sign) + if(attr->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) + if(attr->offset != NULL) { + if(attr->symconst != NULL) be_emit_char(env, '+'); else be_emit_char(env, '$'); - be_emit_tarval(env, attr->cnst_val.tv); + be_emit_tarval(env, attr->offset); } } @@ -1956,9 +1966,7 @@ void ia32_register_emitters(void) { IA32_EMIT(CJmp); IA32_EMIT(CJmpAM); IA32_EMIT(CmpCMov); - IA32_EMIT(PsiCondCMov); IA32_EMIT(CmpSet); - IA32_EMIT(PsiCondSet); IA32_EMIT(SwitchJmp); IA32_EMIT(CopyB); IA32_EMIT(CopyB_i); diff --git a/ir/be/ia32/ia32_finish.c b/ir/be/ia32/ia32_finish.c index eb6b8873f..b7db6cd5c 100644 --- a/ir/be/ia32/ia32_finish.c +++ b/ir/be/ia32/ia32_finish.c @@ -272,7 +272,6 @@ static INLINE int need_constraint_copy(ir_node *irn) { ! is_ia32_Conv_I2I(irn) && ! is_ia32_Conv_I2I8Bit(irn) && ! is_ia32_CmpCMov(irn) && - ! is_ia32_PsiCondCMov(irn) && ! is_ia32_CmpSet(irn); } diff --git a/ir/be/ia32/ia32_new_nodes.c b/ir/be/ia32/ia32_new_nodes.c index 41899f67f..0cbed07a5 100644 --- a/ir/be/ia32/ia32_new_nodes.c +++ b/ir/be/ia32/ia32_new_nodes.c @@ -430,6 +430,15 @@ const ia32_asm_attr_t *get_ia32_asm_attr_const(const ir_node *node) { return asm_attr; } +const ia32_immediate_attr_t *get_ia32_immediate_attr_const(const ir_node *node) +{ + const ia32_attr_t *attr = get_ia32_attr_const(node); + const ia32_immediate_attr_t *immediate_attr + = CONST_CAST_IA32_ATTR(ia32_immediate_attr_t, attr); + + return immediate_attr; +} + /** * Gets the type of an ia32 node. */ @@ -1195,6 +1204,20 @@ init_ia32_asm_attributes(ir_node *res) #endif } +void +init_ia32_immediate_attributes(ir_node *res, ir_entity *symconst, + int symconst_sign, tarval *offset) +{ + ia32_immediate_attr_t *attr = get_irn_generic_attr(res); + +#ifndef DEBUG + attr->attr.attr_type |= IA32_ATTR_ia32_immediate_attr_t; +#endif + attr->symconst = symconst; + attr->attr.data.am_sc_sign = symconst_sign; + attr->offset = offset; +} + ir_node *get_ia32_result_proj(const ir_node *node) { const ir_edge_t *edge; @@ -1291,6 +1314,20 @@ int ia32_compare_asm_attr(ir_node *a, ir_node *b) return 0; } +static +int ia32_compare_immediate_attr(ir_node *a, ir_node *b) +{ + const ia32_immediate_attr_t *attr_a = get_ia32_immediate_attr_const(a); + const ia32_immediate_attr_t *attr_b = get_ia32_immediate_attr_const(b); + + if(attr_a->symconst != attr_b->symconst || + attr_a->attr.data.am_sc_sign != attr_b->attr.data.am_sc_sign || + attr_a->offset != attr_b->offset) + return 1; + + return 0; +} + /* copies the ia32 attributes */ static void ia32_copy_attr(const ir_node *old_node, ir_node *new_node) { diff --git a/ir/be/ia32/ia32_new_nodes.h b/ir/be/ia32/ia32_new_nodes.h index 74093d3fb..5d408d078 100644 --- a/ir/be/ia32/ia32_new_nodes.h +++ b/ir/be/ia32/ia32_new_nodes.h @@ -57,6 +57,8 @@ const ia32_attr_t *get_ia32_attr_const(const ir_node *node); ia32_x87_attr_t *get_ia32_x87_attr(ir_node *node); const ia32_x87_attr_t *get_ia32_x87_attr_const(const ir_node *node); +const ia32_immediate_attr_t *get_ia32_immediate_attr_const(const ir_node *node); + /** * Gets the type of an ia32 node. */ @@ -492,6 +494,8 @@ void init_ia32_attributes(ir_node *node, arch_irn_flags_t flags, void init_ia32_x87_attributes(ir_node *node); void init_ia32_asm_attributes(ir_node *node); +void init_ia32_immediate_attributes(ir_node *node, ir_entity *symconst, + int symconst_sign, tarval *offset); /** * Registers the ia32_copy_attr function for all ia32 opcodes. diff --git a/ir/be/ia32/ia32_nodes_attr.h b/ir/be/ia32/ia32_nodes_attr.h index 37ad31045..996a3cbe3 100644 --- a/ir/be/ia32/ia32_nodes_attr.h +++ b/ir/be/ia32/ia32_nodes_attr.h @@ -31,6 +31,7 @@ #include "firm_types.h" #include "../bearch_t.h" #include "../bemachine.h" +#include "irnode_t.h" typedef enum { flavour_Div = 1, flavour_Mod, flavour_DivMod } ia32_op_flavour_t; typedef enum { pn_EAX, pn_EDX } pn_ia32_Register; @@ -87,15 +88,17 @@ enum { #ifndef NDEBUG typedef enum { - IA32_ATTR_INVALID = 0, - IA32_ATTR_ia32_attr_t = 1 << 0, - IA32_ATTR_ia32_x87_attr_t = 1 << 1, - IA32_ATTR_ia32_asm_attr_t = 1 << 2, + IA32_ATTR_INVALID = 0, + IA32_ATTR_ia32_attr_t = 1 << 0, + IA32_ATTR_ia32_x87_attr_t = 1 << 1, + IA32_ATTR_ia32_asm_attr_t = 1 << 2, + IA32_ATTR_ia32_immediate_attr_t = 1 << 3, } ia32_attr_type_t; #endif typedef struct ia32_attr_t ia32_attr_t; struct ia32_attr_t { + except_attr exc; /**< the exception attribute. MUST be the first one. */ struct { unsigned tp:3; /**< ia32 node type. */ unsigned imm_tp:2; /**< ia32 immop type. */ @@ -152,6 +155,13 @@ struct ia32_attr_t { const arch_register_t **slots; /**< register slots for assigned registers */ }; +typedef struct ia32_immediate_attr_t ia32_immediate_attr_t; +struct ia32_immediate_attr_t { + ia32_attr_t attr; + ir_entity *symconst; + tarval *offset; +}; + typedef struct ia32_x87_attr_t ia32_x87_attr_t; struct ia32_x87_attr_t { ia32_attr_t attr; @@ -167,9 +177,10 @@ struct ia32_asm_attr_t { /* the following union is necessary to indicate to the compiler that we might want to cast * the structs (we use them to simulate OO-inheritance) */ union allow_casts_attr_t_ { - ia32_attr_t attr; - ia32_x87_attr_t x87_attr; - ia32_asm_attr_t asm_attr; + ia32_attr_t attr; + ia32_x87_attr_t x87_attr; + ia32_asm_attr_t asm_attr; + ia32_immediate_attr_t immediate_attr; }; #ifndef NDEBUG diff --git a/ir/be/ia32/ia32_optimize.c b/ir/be/ia32/ia32_optimize.c index aba8b0e8c..627078943 100644 --- a/ir/be/ia32/ia32_optimize.c +++ b/ir/be/ia32/ia32_optimize.c @@ -71,15 +71,6 @@ static INLINE int be_is_NoReg(ia32_code_gen_t *cg, const ir_node *irn) { return irn == cg->noreg_gp || irn == cg->noreg_xmm || irn == cg->noreg_vfp; } -void ia32_pre_transform_phase(ia32_code_gen_t *cg) { - /* - We need to transform the consts twice: - - the psi condition tree transformer needs existing constants to be ia32 constants - - the psi condition tree transformer inserts new firm constants which need to be transformed - */ - irg_walk_graph(cg->irg, NULL, ia32_transform_psi_cond_tree, cg); -} - /******************************************************************************************************** * _____ _ _ ____ _ _ _ _ _ * | __ \ | | | | / __ \ | | (_) (_) | | (_) diff --git a/ir/be/ia32/ia32_spec.pl b/ir/be/ia32/ia32_spec.pl index 452258505..b2a02948a 100644 --- a/ir/be/ia32/ia32_spec.pl +++ b/ir/be/ia32/ia32_spec.pl @@ -303,13 +303,17 @@ $default_attr_type = "ia32_attr_t"; ia32_asm_attr_t => "\tinit_ia32_attributes(res, flags, in_reqs, out_reqs, exec_units, n_res, latency);\n". "\tinit_ia32_x87_attributes(res);". - "\tinit_ia32_asm_attributes(res);" + "\tinit_ia32_asm_attributes(res);", + ia32_immediate_attr_t => + "\tinit_ia32_attributes(res, flags, in_reqs, out_reqs, exec_units, n_res, latency);\n". + "\tinit_ia32_immediate_attributes(res, symconst, symconst_sign, offset);" ); %compare_attr = ( - ia32_attr_t => "ia32_compare_nodes_attr", - ia32_x87_attr_t => "ia32_compare_x87_attr", - ia32_asm_attr_t => "ia32_compare_asm_attr", + ia32_attr_t => "ia32_compare_nodes_attr", + ia32_x87_attr_t => "ia32_compare_x87_attr", + ia32_asm_attr_t => "ia32_compare_asm_attr", + ia32_immediate_attr_t => "ia32_compare_immediate_attr", ); %operands = ( @@ -329,6 +333,8 @@ Immediate => { op_flags => "c", irn_flags => "I", reg_req => { out => [ "gp_NOREG" ] }, + attr => "ir_entity *symconst, int symconst_sign, tarval *offset", + attr_type => "ia32_immediate_attr_t", mode => $mode_gp, }, @@ -752,6 +758,7 @@ Dec => { Not => { irn_flags => "R", reg_req => { in => [ "gp", "gp", "gp", "none" ], out => [ "in_r3" ] }, + ins => [ "base", "index", "val", "mem" ], emit => '. not%M %unop2', units => [ "GP" ], mode => $mode_gp, @@ -1321,14 +1328,9 @@ Conv_FP2FP => { CmpCMov => { irn_flags => "R", reg_req => { in => [ "gp", "gp", "gp", "gp" ], out => [ "in_r4" ] }, - latency => 2, - units => [ "GP" ], - mode => $mode_gp, -}, - -PsiCondCMov => { - irn_flags => "R", - reg_req => { in => [ "gp", "gp", "gp" ], out => [ "in_r3" ] }, + ins => [ "cmp_left", "cmp_right", "val_true", "val_false" ], + attr => "pn_Cmp pn_code", + init_attr => "attr->pn_code = pn_code;", latency => 2, units => [ "GP" ], mode => $mode_gp, @@ -1354,14 +1356,9 @@ vfCmpCMov => { CmpSet => { irn_flags => "R", reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "eax ebx ecx edx" ] }, - latency => 2, - units => [ "GP" ], - mode => $mode_gp, -}, - -PsiCondSet => { - irn_flags => "R", - reg_req => { in => [ "gp" ], out => [ "eax ebx ecx edx" ] }, + ins => [ "base", "index", "cmp_left", "cmp_right", "mem" ], + attr => "pn_Cmp pn_code", + init_attr => "attr->pn_code = pn_code;", latency => 2, units => [ "GP" ], mode => $mode_gp, diff --git a/ir/be/ia32/ia32_transform.c b/ir/be/ia32/ia32_transform.c index 59338f578..aa9dde943 100644 --- a/ir/be/ia32/ia32_transform.c +++ b/ir/be/ia32/ia32_transform.c @@ -238,6 +238,20 @@ static ir_entity *get_entity_for_tv(ia32_code_gen_t *cg, ir_node *cnst) return res; } +static int is_Const_0(ir_node *node) { + if(!is_Const(node)) + return 0; + + return classify_Const(node) == CNST_NULL; +} + +static int is_Const_1(ir_node *node) { + if(!is_Const(node)) + return 0; + + return classify_Const(node) == CNST_ONE; +} + /** * Transforms a Const. */ @@ -352,6 +366,7 @@ static ir_node *gen_SymConst(ir_node *node) { return cnst; } +#if 0 /** * SSE convert of an integer node into a floating point node. */ @@ -392,6 +407,7 @@ static ir_node *gen_sse_conv_f2d(ia32_code_gen_t *cg, dbg_info *dbgi, return conv; } +#endif /* Generates an entity for a known FP const (used for FP Neg + Abs) */ ir_entity *ia32_gen_fp_known_const(ia32_known_const_t kct) { @@ -1004,9 +1020,8 @@ static ir_node *gen_Max(ir_node *node) { if (! mode_is_signed(op_mode)) { pnc |= ia32_pn_Cmp_Unsigned; } - new_op = new_rd_ia32_CmpCMov(dbgi, irg, block, new_op1, new_op2, new_op1, new_op2); - set_ia32_pncode(new_op, pnc); - set_ia32_am_support(new_op, ia32_am_None); + new_op = new_rd_ia32_CmpCMov(dbgi, irg, block, new_op1, new_op2, + new_op1, new_op2, pnc); } SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env_cg, node)); @@ -1044,9 +1059,8 @@ static ir_node *gen_Min(ir_node *node) { if (! mode_is_signed(op_mode)) { pnc |= ia32_pn_Cmp_Unsigned; } - new_op = new_rd_ia32_CmpCMov(dbgi, irg, block, new_op1, new_op2, new_op1, new_op2); - set_ia32_pncode(new_op, pnc); - set_ia32_am_support(new_op, ia32_am_None); + new_op = new_rd_ia32_CmpCMov(dbgi, irg, block, new_op1, new_op2, + new_op1, new_op2, pnc); } SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env_cg, node)); @@ -1657,6 +1671,7 @@ static ir_node *gen_Load(ir_node *node) { } } + set_irn_pinned(new_op, get_irn_pinned(node)); set_ia32_am_support(new_op, ia32_am_Source); set_ia32_op_type(new_op, ia32_AddrModeS); set_ia32_am_flavour(new_op, am_flav); @@ -1744,6 +1759,7 @@ static ir_node *gen_Store(ir_node *node) { } } + set_irn_pinned(new_op, get_irn_pinned(node)); set_ia32_am_support(new_op, ia32_am_Dest); set_ia32_op_type(new_op, ia32_AddrModeD); set_ia32_am_flavour(new_op, am_flav); @@ -1997,36 +2013,83 @@ typedef ir_node *cmov_func_t(dbg_info *db, ir_graph *irg, ir_node *block, static ir_node *gen_Psi(ir_node *node) { ir_node *block = be_transform_node(get_nodes_block(node)); ir_node *psi_true = get_Psi_val(node, 0); - ir_node *new_psi_true = be_transform_node(psi_true); ir_node *psi_default = get_Psi_default(node); - ir_node *new_psi_default = be_transform_node(psi_default); ia32_code_gen_t *cg = env_cg; ir_graph *irg = current_ir_graph; dbg_info *dbgi = get_irn_dbg_info(node); - ir_mode *mode = get_irn_mode(node); - ir_node *cmp_proj = get_Mux_sel(node); - ir_node *noreg = ia32_new_NoReg_gp(cg); - ir_node *nomem = new_rd_NoMem(irg); - ir_node *cmp, *cmp_a, *cmp_b, *and1, *and2, *new_op = NULL; + ir_node *cond = get_Psi_cond(node, 0); + ir_node *noreg = ia32_new_NoReg_gp(env_cg); + ir_node *nomem = new_NoMem(); + ir_node *new_op; + ir_node *cmp, *cmp_a, *cmp_b; ir_node *new_cmp_a, *new_cmp_b; ir_mode *cmp_mode; - int pnc; - - assert(get_irn_mode(cmp_proj) == mode_b && "Condition for Psi must have mode_b"); + int pnc; + + assert(get_Psi_n_conds(node) == 1); + assert(get_irn_mode(cond) == mode_b); + + if(is_And(cond) || is_Or(cond)) { + ir_node *new_cond = be_transform_node(cond); + tarval *tv_zero = new_tarval_from_long(0, mode_Iu); + ir_node *zero = new_rd_ia32_Immediate(NULL, irg, block, NULL, 0, + tv_zero); + arch_set_irn_register(env_cg->arch_env, zero, + &ia32_gp_regs[REG_GP_NOREG]); + + /* we have to compare the result against zero */ + new_cmp_a = new_cond; + new_cmp_b = zero; + pnc = pn_Cmp_Lg; + } else { + cmp = get_Proj_pred(cond); + cmp_a = get_Cmp_left(cmp); + cmp_b = get_Cmp_right(cmp); + cmp_mode = get_irn_mode(cmp_a); + pnc = get_Proj_proj(cond); + + new_cmp_b = try_create_Immediate(cmp_b, 0); + if(new_cmp_b == NULL) { + new_cmp_b = try_create_Immediate(cmp_a, 0); + if(new_cmp_b != NULL) { + pnc = get_inversed_pnc(pnc); + new_cmp_a = be_transform_node(cmp_b); + } + } else { + new_cmp_a = be_transform_node(cmp_a); + } + if(new_cmp_b == NULL) { + new_cmp_a = be_transform_node(cmp_a); + new_cmp_b = be_transform_node(cmp_b); + } - cmp = get_Proj_pred(cmp_proj); - cmp_a = get_Cmp_left(cmp); - cmp_b = get_Cmp_right(cmp); - cmp_mode = get_irn_mode(cmp_a); - new_cmp_a = be_transform_node(cmp_a); - new_cmp_b = be_transform_node(cmp_b); + if (!mode_is_signed(cmp_mode)) { + pnc |= ia32_pn_Cmp_Unsigned; + } + } - pnc = get_Proj_proj(cmp_proj); - if (mode_is_float(cmp_mode) || !mode_is_signed(cmp_mode)) { - pnc |= ia32_pn_Cmp_Unsigned; + if(is_Const_1(psi_true) && is_Const_0(psi_default)) { + new_op = new_rd_ia32_CmpSet(dbgi, irg, block, noreg, noreg, + new_cmp_a, new_cmp_b, nomem, pnc); + } else if(is_Const_0(psi_true) && is_Const_1(psi_default)) { + pnc = get_inversed_pnc(pnc); + new_op = new_rd_ia32_CmpSet(dbgi, irg, block, noreg, noreg, + new_cmp_a, new_cmp_b, nomem, pnc); + } else { + ir_node *new_psi_true = be_transform_node(psi_true); + ir_node *new_psi_default = be_transform_node(psi_default); + new_op = new_rd_ia32_CmpCMov(dbgi, irg, block, new_cmp_a, new_cmp_b, + new_psi_true, new_psi_default, pnc); } + SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(cg, node)); + return new_op; +#if 0 if (mode_is_float(mode)) { + if(mode_is_float(cmp_mode)) { + pnc |= ia32_pn_Cmp_Unsigned; + } + /* floating point psi */ FP_USED(cg); @@ -2144,6 +2207,7 @@ static ir_node *gen_Psi(ir_node *node) { } } } +#endif return new_op; } @@ -2195,6 +2259,7 @@ static ir_node *gen_x87_fp_to_gp(ir_node *node) { fist = new_rd_ia32_vfist(dbgi, irg, block, get_irg_frame(irg), noreg, new_op, trunc_mode, new_NoMem()); + set_irn_pinned(load, op_pin_state_floats); set_ia32_use_frame(fist); set_ia32_am_support(fist, ia32_am_Dest); set_ia32_op_type(fist, ia32_AddrModeD); @@ -2205,6 +2270,7 @@ static ir_node *gen_x87_fp_to_gp(ir_node *node) { /* do a Load */ load = new_rd_ia32_Load(dbgi, irg, block, get_irg_frame(irg), noreg, fist); + set_irn_pinned(load, op_pin_state_floats); set_ia32_use_frame(load); set_ia32_am_support(load, ia32_am_Source); set_ia32_op_type(load, ia32_AddrModeS); @@ -2425,7 +2491,6 @@ ir_node *try_create_Immediate(ir_node *node, char immediate_constraint_type) 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) && @@ -2502,25 +2567,20 @@ ir_node *try_create_Immediate(ir_node *node, char immediate_constraint_type) if(cnst == NULL && symconst == NULL) return NULL; + if(offset_sign && offset != NULL) { + offset = tarval_neg(offset); + } + irg = current_ir_graph; dbgi = get_irn_dbg_info(node); block = get_irg_start_block(irg); - res = new_rd_ia32_Immediate(dbgi, irg, block); + res = new_rd_ia32_Immediate(dbgi, irg, block, symconst_ent, symconst_sign, + offset); 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; } @@ -2922,6 +2982,7 @@ static ir_node *gen_be_StackParam(ir_node *node) { pn_res = pn_ia32_Load_res; } + set_irn_pinned(new_op, op_pin_state_floats); set_ia32_frame_ent(new_op, ent); set_ia32_use_frame(new_op); @@ -2991,6 +3052,7 @@ static ir_node *gen_be_FrameLoad(ir_node *node) { new_op = new_rd_ia32_Load(dbgi, irg, block, new_ptr, noreg, new_mem); } + set_irn_pinned(new_op, op_pin_state_floats); set_ia32_frame_ent(new_op, ent); set_ia32_use_frame(new_op); @@ -4078,6 +4140,73 @@ static ir_node *gen_Proj_be_Call(ir_node *node) { return new_rd_Proj(dbgi, irg, block, new_call, mode, proj); } +static ir_node *gen_Proj_Cmp(ir_node *node) +{ + /* normally Cmps are processed when looking at Cond nodes, but this case + * can happen in complicated Psi conditions */ + + ir_graph *irg = current_ir_graph; + dbg_info *dbgi = get_irn_dbg_info(node); + ir_node *block = be_transform_node(get_nodes_block(node)); + ir_node *cmp = get_Proj_pred(node); + long pnc = get_Proj_proj(node); + ir_node *cmp_left = get_Cmp_left(cmp); + ir_node *cmp_right = get_Cmp_right(cmp); + ir_node *new_cmp_left; + ir_node *new_cmp_right; + ir_node *noreg = ia32_new_NoReg_gp(env_cg); + ir_node *nomem = new_rd_NoMem(irg); + ir_mode *cmp_mode = get_irn_mode(cmp_left); + ir_node *new_op; + + assert(!mode_is_float(cmp_mode)); + + /* (a != b) -> (a ^ b) */ + if(pnc == pn_Cmp_Lg) { + if(is_Const_0(cmp_left)) { + new_op = be_transform_node(cmp_right); + } else if(is_Const_0(cmp_right)) { + new_op = be_transform_node(cmp_left); + } else { + new_op = gen_binop(cmp, cmp_left, cmp_right, new_rd_ia32_Xor, 1); + } + + return new_op; + } + /* TODO: + * (a == b) -> !(a ^ b) + * (a < 0) -> (a & 0x80000000) + * (a <= 0) -> !(a & 0x7fffffff) + * (a > 0) -> (a & 0x7fffffff) + * (a >= 0) -> !(a & 0x80000000) + */ + + if(!mode_is_signed(cmp_mode)) { + pnc |= ia32_pn_Cmp_Unsigned; + } + + new_cmp_right = try_create_Immediate(cmp_right, 0); + if(new_cmp_right == NULL) { + new_cmp_right = try_create_Immediate(cmp_left, 0); + if(new_cmp_left != NULL) { + pnc = get_inversed_pnc(pnc); + new_cmp_left = be_transform_node(cmp_right); + } + } else { + new_cmp_left = be_transform_node(cmp_left); + } + if(new_cmp_right == NULL) { + new_cmp_left = be_transform_node(cmp_left); + new_cmp_right = be_transform_node(cmp_right); + } + + new_op = new_rd_ia32_CmpSet(dbgi, irg, block, noreg, noreg, new_cmp_left, + new_cmp_right, nomem, pnc); + SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env_cg, cmp)); + + return new_op; +} + static ir_node *gen_Proj(ir_node *node) { ir_graph *irg = current_ir_graph; dbg_info *dbgi = get_irn_dbg_info(node); @@ -4107,6 +4236,8 @@ static ir_node *gen_Proj(ir_node *node) { return gen_Proj_be_AddSP(node); } else if (be_is_Call(pred)) { return gen_Proj_be_Call(node); + } else if (is_Cmp(pred)) { + return gen_Proj_Cmp(node); } else if (get_irn_op(pred) == op_Start) { if (proj == pn_Start_X_initial_exec) { ir_node *block = get_nodes_block(pred); @@ -4280,149 +4411,6 @@ void ia32_transform_graph(ia32_code_gen_t *cg) { be_transform_graph(cg->birg, ia32_pretransform_node, cg); } -/** - * Transforms a psi condition. - */ -static void transform_psi_cond(ir_node *cond, ir_mode *mode, ia32_code_gen_t *cg) { - int i; - - /* if the mode is target mode, we have already seen this part of the tree */ - if (get_irn_mode(cond) == mode) - return; - - assert(get_irn_mode(cond) == mode_b && "logical operator for condition must be mode_b"); - - set_irn_mode(cond, mode); - - for (i = get_irn_arity(cond) - 1; i >= 0; i--) { - ir_node *in = get_irn_n(cond, i); - - /* if in is a compare: transform into Set/xCmp */ - if (is_Proj(in)) { - ir_node *new_op = NULL; - ir_node *cmp = get_Proj_pred(in); - ir_node *cmp_a = get_Cmp_left(cmp); - ir_node *cmp_b = get_Cmp_right(cmp); - dbg_info *dbgi = get_irn_dbg_info(cmp); - ir_graph *irg = get_irn_irg(cmp); - ir_node *block = get_nodes_block(cmp); - ir_node *noreg = ia32_new_NoReg_gp(cg); - ir_node *nomem = new_rd_NoMem(irg); - int pnc = get_Proj_proj(in); - - /* this is a compare */ - if (mode_is_float(mode)) { - /* Psi is float, we need a floating point compare */ - - if (USE_SSE2(cg)) { - ir_mode *m = get_irn_mode(cmp_a); - /* SSE FPU */ - if (! mode_is_float(m)) { - cmp_a = gen_sse_conv_int2float(cg, dbgi, irg, block, cmp_a, cmp_a, mode); - cmp_b = gen_sse_conv_int2float(cg, dbgi, irg, block, cmp_b, cmp_b, mode); - } else if (m == mode_F) { - /* we convert cmp values always to double, to get correct bitmask with cmpsd */ - cmp_a = gen_sse_conv_f2d(cg, dbgi, irg, block, cmp_a, cmp_a); - cmp_b = gen_sse_conv_f2d(cg, dbgi, irg, block, cmp_b, cmp_b); - } - - new_op = new_rd_ia32_xCmp(dbgi, irg, block, noreg, noreg, cmp_a, cmp_b, nomem); - set_ia32_pncode(new_op, pnc); - SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(cg, cmp)); - } else { - /* x87 FPU */ - assert(0); - } - } else { - /* integer Psi */ - construct_binop_func *set_func = NULL; - - if (mode_is_float(get_irn_mode(cmp_a))) { - /* 1st case: compare operands are floats */ - FP_USED(cg); - - if (USE_SSE2(cg)) { - /* SSE FPU */ - set_func = new_rd_ia32_xCmpSet; - } else { - /* x87 FPU */ - set_func = new_rd_ia32_vfCmpSet; - } - - pnc &= 7; /* fp compare -> int compare */ - } else { - /* 2nd case: compare operand are integer too */ - set_func = new_rd_ia32_CmpSet; - } - - new_op = set_func(dbgi, irg, block, noreg, noreg, cmp_a, cmp_b, nomem); - if (! mode_is_signed(mode)) - pnc |= ia32_pn_Cmp_Unsigned; - - set_ia32_pncode(new_op, pnc); - set_ia32_am_support(new_op, ia32_am_Source); - } - - /* the the new compare as in */ - set_irn_n(cond, i, new_op); - } else { - /* another complex condition */ - transform_psi_cond(in, mode, cg); - } - } -} - -/** - * The Psi selector can be a tree of compares combined with "And"s and "Or"s. - * We create a Set node, respectively a xCmp in case the Psi is a float, for - * each compare, which causes the compare result to be stored in a register. The - * "And"s and "Or"s are transformed later, we just have to set their mode right. - */ -void ia32_transform_psi_cond_tree(ir_node *node, void *env) { - ia32_code_gen_t *cg = env; - ir_node *psi_sel, *new_cmp, *block; - ir_graph *irg; - ir_mode *mode; - - /* check for Psi */ - if (get_irn_opcode(node) != iro_Psi) - return; - - psi_sel = get_Psi_cond(node, 0); - - /* if psi_cond is a cmp: do nothing, this case is covered by gen_Psi */ - if (is_Proj(psi_sel)) { - assert(is_Cmp(get_Proj_pred(psi_sel))); - return; - } - - //mode = get_irn_mode(node); - // TODO probably wrong... - mode = mode_Iu; - - transform_psi_cond(psi_sel, mode, cg); - - irg = get_irn_irg(node); - block = get_nodes_block(node); - - /* we need to compare the evaluated condition tree with 0 */ - mode = get_irn_mode(node); - if (mode_is_float(mode)) { - /* BEWARE: new_r_Const_long works for floating point as well */ - ir_node *zero = new_r_Const_long(irg, block, mode, 0); - - psi_sel = gen_sse_conv_int2float(cg, NULL, irg, block, psi_sel, NULL, mode); - new_cmp = new_r_Cmp(irg, block, psi_sel, zero); - new_cmp = new_r_Proj(irg, block, new_cmp, mode_b, pn_Cmp_Ne); - } else { - ir_node *zero = new_r_Const_long(irg, block, mode_Iu, 0); - new_cmp = new_r_Cmp(irg, block, psi_sel, zero); - new_cmp = new_r_Proj(irg, block, new_cmp, mode_b, pn_Cmp_Gt | pn_Cmp_Lt); - } - - set_Psi_cond(node, 0, new_cmp); -} - void ia32_init_transform(void) { FIRM_DBG_REGISTER(dbg, "firm.be.ia32.transform"); diff --git a/ir/be/ia32/ia32_transform.h b/ir/be/ia32/ia32_transform.h index afb839a67..ecf1ba3d8 100644 --- a/ir/be/ia32/ia32_transform.h +++ b/ir/be/ia32/ia32_transform.h @@ -34,14 +34,6 @@ */ void ia32_transform_graph(ia32_code_gen_t *cg); -/** - * The Psi selector can be a tree of compares combined with "And"s and "Or"s. - * We create a Set node, respectively a xCmp in case the Psi is a float, for each - * compare, which causes the compare result to be stores in a register. The - * "And"s and "Or"s are transformed later, we only adjust their mode. - */ -void ia32_transform_psi_cond_tree(ir_node *node, void *env); - #ifndef NDEBUG /** * Prints the old node name on cg obst and returns a pointer to it. -- 2.20.1