From 26bffd78b2878071884253c99b1cdf55587941ac Mon Sep 17 00:00:00 2001 From: Michael Beck Date: Mon, 18 Jan 2010 02:28:05 +0000 Subject: [PATCH] Add an cse_neutral opcode property. Nodes with this property are CSE neutral to its users, i.e. op(..., x, ...) ~ op(..., y, ...) if x and y are both neutral. Setting this property to ia32_ProduceVal nodes allow to CSE nodes that differ in ProduceVals only (which themself NEVER are cse'd). This "fixes" divmod. [r26981] --- include/libfirm/irnode.h | 5 ++++ include/libfirm/irop.h | 39 ++++++++++++++------------- ir/be/ia32/ia32_spec.pl | 4 +-- ir/be/scripts/generate_new_opcodes.pl | 1 + ir/ir/irnode.c | 10 ++++++- ir/ir/irnode_t.h | 5 ++++ ir/ir/irop_t.h | 5 ++++ ir/ir/iropt.c | 12 ++++++--- 8 files changed, 56 insertions(+), 25 deletions(-) diff --git a/include/libfirm/irnode.h b/include/libfirm/irnode.h index 7d2090370..a480cd3cb 100644 --- a/include/libfirm/irnode.h +++ b/include/libfirm/irnode.h @@ -1367,6 +1367,11 @@ int is_irn_machine_operand(const ir_node *node); */ int is_irn_machine_user(const ir_node *node, unsigned n); +/** + * Returns non-zero for nodes that are CSE neutral to its users. + */ +int is_irn_cse_neutral(const ir_node *node); + /** * A type to express conditional jump predictions. */ diff --git a/include/libfirm/irop.h b/include/libfirm/irop.h index 65cd16602..dc07dcb17 100644 --- a/include/libfirm/irop.h +++ b/include/libfirm/irop.h @@ -55,27 +55,28 @@ typedef enum { /** The irop flags */ typedef enum { - irop_flag_none = 0x00000000, /**< Nothing. */ - irop_flag_labeled = 0x00000001, /**< If set, output edge labels on in-edges in vcg graph. */ - irop_flag_commutative = 0x00000002, /**< This operation is commutative. */ - irop_flag_cfopcode = 0x00000004, /**< This operation is a control flow operation. */ - irop_flag_ip_cfopcode = 0x00000008, /**< This operation manipulates the interprocedural control flow. */ - irop_flag_fragile = 0x00000010, /**< Set if the operation can change the control flow because - of an exception. */ - irop_flag_forking = 0x00000020, /**< Forking control flow at this operation. */ - irop_flag_highlevel = 0x00000040, /**< This operation is a pure high-level one and can be - skipped in low-level optimizations. */ - irop_flag_constlike = 0x00000080, /**< This operation has no arguments and is some - kind of a constant. */ - irop_flag_always_opt = 0x00000100, /**< This operation must always be optimized .*/ - irop_flag_keep = 0x00000200, /**< This operation can be kept in End's keep-alive list. */ - irop_flag_start_block = 0x00000400, /**< This operation is always placed in the Start block. */ - irop_flag_uses_memory = 0x00000800, /**< This operation has a memory input and may change the memory state. */ + irop_flag_none = 0x00000000, /**< Nothing. */ + irop_flag_labeled = 0x00000001, /**< If set, output edge labels on in-edges in vcg graph. */ + irop_flag_commutative = 0x00000002, /**< This operation is commutative. */ + irop_flag_cfopcode = 0x00000004, /**< This operation is a control flow operation. */ + irop_flag_ip_cfopcode = 0x00000008, /**< This operation manipulates the interprocedural control flow. */ + irop_flag_fragile = 0x00000010, /**< Set if the operation can change the control flow because + of an exception. */ + irop_flag_forking = 0x00000020, /**< Forking control flow at this operation. */ + irop_flag_highlevel = 0x00000040, /**< This operation is a pure high-level one and can be + skipped in low-level optimizations. */ + irop_flag_constlike = 0x00000080, /**< This operation has no arguments and is some + kind of a constant. */ + irop_flag_always_opt = 0x00000100, /**< This operation must always be optimized .*/ + irop_flag_keep = 0x00000200, /**< This operation can be kept in End's keep-alive list. */ + irop_flag_start_block = 0x00000400, /**< This operation is always placed in the Start block. */ + irop_flag_uses_memory = 0x00000800, /**< This operation has a memory input and may change the memory state. */ irop_flag_dump_noblock = 0x00001000, /**< node should be dumped outside any blocks */ irop_flag_dump_noinput = 0x00002000, /**< node is a placeholder for "no input" */ - irop_flag_machine = 0x00010000, /**< This operation is a machine operation. */ - irop_flag_machine_op = 0x00020000, /**< This operation is a machine operand. */ - irop_flag_user = 0x00040000 /**< This flag and all higher ones are free for machine user. */ + irop_flag_machine = 0x00010000, /**< This operation is a machine operation. */ + irop_flag_machine_op = 0x00020000, /**< This operation is a machine operand. */ + irop_flag_cse_neutral = 0x00040000, /**< This operation is CSE neutral to its users. */ + irop_flag_user = 0x00080000 /**< This flag and all higher ones are free for machine user. */ } irop_flags; /** The opcodes of the libFirm predefined operations. */ diff --git a/ir/be/ia32/ia32_spec.pl b/ir/be/ia32/ia32_spec.pl index 155f22fd3..0196a9f95 100644 --- a/ir/be/ia32/ia32_spec.pl +++ b/ir/be/ia32/ia32_spec.pl @@ -15,7 +15,7 @@ $arch = "ia32"; # %nodes = ( # # => { -# op_flags => "N|L|C|X|I|F|Y|H|c|K", +# op_flags => "N|L|C|X|I|F|Y|H|c|K|n", # irn_flags => "R|N" # arity => "0|1|2|3 ... |variable|dynamic|any", # state => "floats|pinned|mem_pinned|exc_pinned", @@ -339,7 +339,7 @@ Asm => { # "allocates" a free register ProduceVal => { - op_flags => "c", + op_flags => "c|n", irn_flags => "R", reg_req => { out => [ "gp" ] }, emit => "", diff --git a/ir/be/scripts/generate_new_opcodes.pl b/ir/be/scripts/generate_new_opcodes.pl index 7c1e4c9d0..683aed82f 100755 --- a/ir/be/scripts/generate_new_opcodes.pl +++ b/ir/be/scripts/generate_new_opcodes.pl @@ -1048,6 +1048,7 @@ void $arch\_create_opcodes(const arch_irn_ops_t *be_ops) { #define O irop_flag_machine_op #define NB irop_flag_dump_noblock #define NI irop_flag_dump_noinput +#define n irop_flag_cse_neutral #define R (irop_flag_user << 0) ir_op_ops ops; diff --git a/ir/ir/irnode.c b/ir/ir/irnode.c index 6d0ffee8c..2ec8ff391 100644 --- a/ir/ir/irnode.c +++ b/ir/ir/irnode.c @@ -2782,6 +2782,10 @@ int (is_irn_machine_user)(const ir_node *node, unsigned n) { return _is_irn_machine_user(node, n); } +/* Returns non-zero for nodes that are CSE neutral to its users. */ +int (is_irn_cse_neutral)(const ir_node *node) { + return _is_irn_cse_neutral(node); +} /* Gets the string representation of the jump prediction .*/ const char *get_cond_jmp_predicate_name(cond_jmp_predicate pred) { @@ -2922,7 +2926,11 @@ unsigned firm_default_hash(const ir_node *node) { /* consider all in nodes... except the block if not a control flow. */ for (i = is_cfop(node) ? -1 : 0; i < irn_arity; ++i) { - h = 9*h + HASH_PTR(get_irn_intra_n(node, i)); + ir_node *pred = get_irn_intra_n(node, i); + if (is_irn_cse_neutral(pred)) + h *= 9; + else + h = 9*h + HASH_PTR(pred); } /* ...mode,... */ diff --git a/ir/ir/irnode_t.h b/ir/ir/irnode_t.h index 58e5ec5bc..3d6cfbf6b 100644 --- a/ir/ir/irnode_t.h +++ b/ir/ir/irnode_t.h @@ -600,6 +600,10 @@ static inline int _is_irn_machine_user(const ir_node *node, unsigned n) { return is_op_machine_user(_get_irn_op(node), n); } +static inline int _is_irn_cse_neutral(const ir_node *node) { + return is_op_cse_neutral(_get_irn_op(node)); +} + static inline cond_jmp_predicate _get_Cond_jmp_pred(const ir_node *node) { assert(_get_irn_op(node) == op_Cond); return node->attr.cond.jmp_pred; @@ -757,6 +761,7 @@ _is_arg_Proj(const ir_node *node) { #define is_irn_machine_op(node) _is_irn_machine_op(node) #define is_irn_machine_operand(node) _is_irn_machine_operand(node) #define is_irn_machine_user(node, n) _is_irn_machine_user(node, n) +#define is_irn_cse_neutral(node) _is_irn_cse_neutral(node) #define get_Cond_jmp_pred(node) _get_Cond_jmp_pred(node) #define set_Cond_jmp_pred(node, pred) _set_Cond_jmp_pred(node, pred) #define get_irn_generic_attr(node) _get_irn_generic_attr(node) diff --git a/ir/ir/irop_t.h b/ir/ir/irop_t.h index cdb68fb83..c0c328523 100644 --- a/ir/ir/irop_t.h +++ b/ir/ir/irop_t.h @@ -128,6 +128,11 @@ static inline int is_op_machine_operand(const ir_op *op) { return op->flags & irop_flag_machine_op; } +/** Returns non-zero if operation is CSE neutral */ +static inline int is_op_cse_neutral(const ir_op *op) { + return op->flags & irop_flag_cse_neutral; +} + /** Returns non-zero if operation is a machine user op number n */ static inline int is_op_machine_user(const ir_op *op, unsigned n) { return op->flags & (irop_flag_user << n); diff --git a/ir/ir/iropt.c b/ir/ir/iropt.c index 03c707be0..9eba1a3a1 100644 --- a/ir/ir/iropt.c +++ b/ir/ir/iropt.c @@ -6245,9 +6245,15 @@ int identities_cmp(const void *elt, const void *key) { } /* compare a->in[0..ins] with b->in[0..ins] */ - for (i = 0; i < irn_arity_a; i++) - if (get_irn_intra_n(a, i) != get_irn_intra_n(b, i)) - return 1; + for (i = 0; i < irn_arity_a; ++i) { + ir_node *pred_a = get_irn_intra_n(a, i); + ir_node *pred_b = get_irn_intra_n(b, i); + if (pred_a != pred_b) { + /* if both predecessors are CSE neutral they might be different */ + if (!is_irn_cse_neutral(pred_a) || !is_irn_cse_neutral(pred_b)) + return 1; + } + } /* * here, we already now that the nodes are identical except their -- 2.20.1