From d58a66aa0faa64bfbd85e528be5104293dd41d0e Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 22 Jun 2021 10:16:18 +0200 Subject: i386: Use xor to write zero to memory with -Os even for more than 4 stores [PR11877] > > 2021-06-20 Roger Sayle > > > > gcc/ChangeLog > > PR target/11877 > > * config/i386/i386.md: New define_peephole2s to shrink writing > > 1, 2 or 4 consecutive zeros to memory when optimizing for size. It unfortunately doesn't extend well to larger memory clearing. Consider e.g. void foo (int *p) { p[0] = 0; p[7] = 0; p[23] = 0; p[41] = 0; p[48] = 0; p[59] = 0; p[69] = 0; p[78] = 0; p[83] = 0; p[89] = 0; p[98] = 0; p[121] = 0; p[132] = 0; p[143] = 0; p[154] = 0; } where with the patch we emit: xorl %eax, %eax xorl %edx, %edx xorl %ecx, %ecx xorl %esi, %esi xorl %r8d, %r8d movl %eax, (%rdi) movl %eax, 28(%rdi) movl %eax, 92(%rdi) movl %eax, 164(%rdi) movl %edx, 192(%rdi) movl %edx, 236(%rdi) movl %edx, 276(%rdi) movl %edx, 312(%rdi) movl %ecx, 332(%rdi) movl %ecx, 356(%rdi) movl %ecx, 392(%rdi) movl %ecx, 484(%rdi) movl %esi, 528(%rdi) movl %esi, 572(%rdi) movl %r8d, 616(%rdi) Here is an incremental patch that emits: xorl %eax, %eax movl %eax, (%rdi) movl %eax, 28(%rdi) movl %eax, 92(%rdi) movl %eax, 164(%rdi) movl %eax, 192(%rdi) movl %eax, 236(%rdi) movl %eax, 276(%rdi) movl %eax, 312(%rdi) movl %eax, 332(%rdi) movl %eax, 356(%rdi) movl %eax, 392(%rdi) movl %eax, 484(%rdi) movl %eax, 528(%rdi) movl %eax, 572(%rdi) movl %eax, 616(%rdi) instead. 2021-06-22 Jakub Jelinek PR target/11877 * config/i386/i386-protos.h (ix86_last_zero_store_uid): Declare. * config/i386/i386-expand.c (ix86_last_zero_store_uid): New variable. * config/i386/i386.c (ix86_expand_prologue): Clear it. * config/i386/i386.md (peephole2s for 1/2/4 stores of const0_rtx): Remove "" from match_operand. Emit new insns using emit_move_insn and set ix86_last_zero_store_uid to INSN_UID of the last store. Add peephole2s for 1/2/4 stores of const0_rtx following previous successful peep2s. * gcc.target/i386/pr11877-2.c: New test. --- gcc/config/i386/i386-expand.c | 3 ++ gcc/config/i386/i386-protos.h | 1 + gcc/config/i386/i386.c | 1 + gcc/config/i386/i386.md | 87 ++++++++++++++++++++++++++----- gcc/testsuite/gcc.target/i386/pr11877-2.c | 26 +++++++++ 5 files changed, 104 insertions(+), 14 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr11877-2.c (limited to 'gcc') diff --git a/gcc/config/i386/i386-expand.c b/gcc/config/i386/i386-expand.c index cc2eaee..2986b49 100644 --- a/gcc/config/i386/i386-expand.c +++ b/gcc/config/i386/i386-expand.c @@ -1316,6 +1316,9 @@ find_nearest_reg_def (rtx_insn *insn, int regno1, int regno2) return false; } +/* INSN_UID of the last insn emitted by zero store peephole2s. */ +int ix86_last_zero_store_uid; + /* Split lea instructions into a sequence of instructions which are executed on ALU to avoid AGU stalls. It is assumed that it is allowed to clobber flags register diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index e6ac939..1d05206 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -111,6 +111,7 @@ extern bool ix86_use_lea_for_mov (rtx_insn *, rtx[]); extern bool ix86_avoid_lea_for_addr (rtx_insn *, rtx[]); extern void ix86_split_lea_for_addr (rtx_insn *, rtx[], machine_mode); extern bool ix86_lea_for_add_ok (rtx_insn *, rtx[]); +extern int ix86_last_zero_store_uid; extern bool ix86_vec_interleave_v2df_operator_ok (rtx operands[3], bool high); extern bool ix86_dep_by_shift_count (const_rtx set_insn, const_rtx use_insn); extern bool ix86_agi_dependent (rtx_insn *set_insn, rtx_insn *use_insn); diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index c3740ff..3d5883b 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -8196,6 +8196,7 @@ ix86_expand_prologue (void) bool save_stub_call_needed; rtx static_chain = NULL_RTX; + ix86_last_zero_store_uid = 0; if (ix86_function_naked (current_function_decl)) { if (flag_stack_usage_info) diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 9116828..700c158 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -19360,37 +19360,96 @@ ;; When optimizing for size, zeroing memory should use a register. (define_peephole2 [(match_scratch:SWI48 0 "r") - (set (match_operand:SWI48 1 "memory_operand" "") (const_int 0)) - (set (match_operand:SWI48 2 "memory_operand" "") (const_int 0)) - (set (match_operand:SWI48 3 "memory_operand" "") (const_int 0)) - (set (match_operand:SWI48 4 "memory_operand" "") (const_int 0))] + (set (match_operand:SWI48 1 "memory_operand") (const_int 0)) + (set (match_operand:SWI48 2 "memory_operand") (const_int 0)) + (set (match_operand:SWI48 3 "memory_operand") (const_int 0)) + (set (match_operand:SWI48 4 "memory_operand") (const_int 0))] "optimize_insn_for_size_p () && peep2_regno_dead_p (0, FLAGS_REG)" - [(set (match_dup 1) (match_dup 0)) - (set (match_dup 2) (match_dup 0)) - (set (match_dup 3) (match_dup 0)) - (set (match_dup 4) (match_dup 0))] + [(const_int 0)] { ix86_expand_clear (operands[0]); + emit_move_insn (operands[1], operands[0]); + emit_move_insn (operands[2], operands[0]); + emit_move_insn (operands[3], operands[0]); + ix86_last_zero_store_uid + = INSN_UID (emit_move_insn (operands[4], operands[0])); + DONE; }) (define_peephole2 [(match_scratch:SWI48 0 "r") - (set (match_operand:SWI48 1 "memory_operand" "") (const_int 0)) - (set (match_operand:SWI48 2 "memory_operand" "") (const_int 0))] + (set (match_operand:SWI48 1 "memory_operand") (const_int 0)) + (set (match_operand:SWI48 2 "memory_operand") (const_int 0))] "optimize_insn_for_size_p () && peep2_regno_dead_p (0, FLAGS_REG)" - [(set (match_dup 1) (match_dup 0)) - (set (match_dup 2) (match_dup 0))] + [(const_int 0)] { ix86_expand_clear (operands[0]); + emit_move_insn (operands[1], operands[0]); + ix86_last_zero_store_uid + = INSN_UID (emit_move_insn (operands[2], operands[0])); + DONE; }) (define_peephole2 [(match_scratch:SWI48 0 "r") - (set (match_operand:SWI48 1 "memory_operand" "") (const_int 0))] + (set (match_operand:SWI48 1 "memory_operand") (const_int 0))] "optimize_insn_for_size_p () && peep2_regno_dead_p (0, FLAGS_REG)" - [(set (match_dup 1) (match_dup 0))] + [(const_int 0)] { ix86_expand_clear (operands[0]); + ix86_last_zero_store_uid + = INSN_UID (emit_move_insn (operands[1], operands[0])); + DONE; +}) + +(define_peephole2 + [(set (match_operand:SWI48 5 "memory_operand") + (match_operand:SWI48 0 "general_reg_operand")) + (set (match_operand:SWI48 1 "memory_operand") (const_int 0)) + (set (match_operand:SWI48 2 "memory_operand") (const_int 0)) + (set (match_operand:SWI48 3 "memory_operand") (const_int 0)) + (set (match_operand:SWI48 4 "memory_operand") (const_int 0))] + "optimize_insn_for_size_p () + && INSN_UID (peep2_next_insn (0)) == ix86_last_zero_store_uid" + [(const_int 0)] +{ + emit_move_insn (operands[5], operands[0]); + emit_move_insn (operands[1], operands[0]); + emit_move_insn (operands[2], operands[0]); + emit_move_insn (operands[3], operands[0]); + ix86_last_zero_store_uid + = INSN_UID (emit_move_insn (operands[4], operands[0])); + DONE; +}) + +(define_peephole2 + [(set (match_operand:SWI48 3 "memory_operand") + (match_operand:SWI48 0 "general_reg_operand")) + (set (match_operand:SWI48 1 "memory_operand") (const_int 0)) + (set (match_operand:SWI48 2 "memory_operand") (const_int 0))] + "optimize_insn_for_size_p () + && INSN_UID (peep2_next_insn (0)) == ix86_last_zero_store_uid" + [(const_int 0)] +{ + emit_move_insn (operands[3], operands[0]); + emit_move_insn (operands[1], operands[0]); + ix86_last_zero_store_uid + = INSN_UID (emit_move_insn (operands[2], operands[0])); + DONE; +}) + +(define_peephole2 + [(set (match_operand:SWI48 2 "memory_operand") + (match_operand:SWI48 0 "general_reg_operand")) + (set (match_operand:SWI48 1 "memory_operand") (const_int 0))] + "optimize_insn_for_size_p () + && INSN_UID (peep2_next_insn (0)) == ix86_last_zero_store_uid" + [(const_int 0)] +{ + emit_move_insn (operands[2], operands[0]); + ix86_last_zero_store_uid + = INSN_UID (emit_move_insn (operands[1], operands[0])); + DONE; }) ;; Reload dislikes loading constants directly into class_likely_spilled diff --git a/gcc/testsuite/gcc.target/i386/pr11877-2.c b/gcc/testsuite/gcc.target/i386/pr11877-2.c new file mode 100644 index 0000000..4782dd2 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr11877-2.c @@ -0,0 +1,26 @@ +/* PR target/11877 */ +/* { dg-do compile } */ +/* { dg-options "-Os" } */ + +void +foo (int *p) +{ + p[0] = 0; + p[7] = 0; + p[23] = 0; + p[41] = 0; + p[48] = 0; + p[59] = 0; + p[69] = 0; + p[78] = 0; + p[83] = 0; + p[89] = 0; + p[98] = 0; + p[121] = 0; + p[132] = 0; + p[143] = 0; + p[154] = 0; +} + +/* { dg-final { scan-assembler-times "xorl\[ \t\]" 1 } } */ +/* { dg-final { scan-assembler-not "\\\$0," } } */ -- cgit v1.1 From 26f05f5a823030ebb52b107a8c303d07f77fe317 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Tue, 22 Jun 2021 09:10:56 +0200 Subject: tree-optimization/101154 - fix out-of bound access in SLP This fixes an out-of-bound access of matches. 2021-06-22 Richard Biener PR tree-optimization/101154 * tree-vect-slp.c (vect_build_slp_tree_2): Fix out-of-bound access. --- gcc/tree-vect-slp.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'gcc') diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c index a32f86b..b9f91e7 100644 --- a/gcc/tree-vect-slp.c +++ b/gcc/tree-vect-slp.c @@ -1963,15 +1963,15 @@ vect_build_slp_tree_2 (vec_info *vinfo, slp_tree node, if (dt == vect_constant_def || dt == vect_external_def) { - /* We can always build those. Might want to sort last - or defer building. */ - vec ops; - ops.create (group_size); - for (lane = 0; lane < group_size; ++lane) - ops.quick_push (chains[lane][n].op); - slp_tree child = vect_create_new_slp_node (ops); - SLP_TREE_DEF_TYPE (child) = dt; - children.safe_push (child); + /* We can always build those. Might want to sort last + or defer building. */ + vec ops; + ops.create (group_size); + for (lane = 0; lane < group_size; ++lane) + ops.quick_push (chains[lane][n].op); + slp_tree child = vect_create_new_slp_node (ops); + SLP_TREE_DEF_TYPE (child) = dt; + children.safe_push (child); } else if (dt != vect_internal_def) { @@ -2036,9 +2036,10 @@ vect_build_slp_tree_2 (vec_info *vinfo, slp_tree node, dump_printf_loc (MSG_NOTE, vect_location, "failed to match up op %d\n", n); op_stmts.release (); - matches[lane] = false; if (lane != group_size - 1) matches[0] = false; + else + matches[lane] = false; goto out; } if (dump_enabled_p ()) -- cgit v1.1 From a5b773d3f86dd4333696cab0fe3a6953d3db74a3 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Tue, 22 Jun 2021 09:12:42 +0200 Subject: tree-optimization/101159 - fix missing NULL check in popcount pattern This fixes a missing check for a NULL vectype in the new popcount pattern. 2021-06-22 Richard Biener PR tree-optimization/101159 * tree-vect-patterns.c (vect_recog_popcount_pattern): Add missing NULL vectype check. --- gcc/tree-vect-patterns.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c index 5972705..d0a5c71 100644 --- a/gcc/tree-vect-patterns.c +++ b/gcc/tree-vect-patterns.c @@ -1385,9 +1385,9 @@ vect_recog_popcount_pattern (vec_info *vinfo, vect_pattern_detected ("vec_regcog_popcount_pattern", popcount_stmt); vec_type = get_vectype_for_scalar_type (vinfo, lhs_type); /* Do it only the backend existed popcount2. */ - if (!direct_internal_fn_supported_p (IFN_POPCOUNT, - vec_type, - OPTIMIZE_FOR_SPEED)) + if (!vec_type + || !direct_internal_fn_supported_p (IFN_POPCOUNT, vec_type, + OPTIMIZE_FOR_SPEED)) return NULL; /* Create B = .POPCOUNT (A). */ -- cgit v1.1 From 7a22d8a764418265680a6bb9a9aec31e984eb015 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Tue, 22 Jun 2021 09:24:24 +0200 Subject: tree-optimization/101158 - adjust SLP call matching sequence This moves the check for same operands after verifying we're facing compatible calls. 2021-06-22 Richard Biener PR tree-optimization/101158 * tree-vect-slp.c (vect_build_slp_tree_1): Move same operand checking after checking for matching operation. * gfortran.dg/pr101158.f90: New testcase. --- gcc/testsuite/gfortran.dg/pr101158.f90 | 25 +++++++++++++++++++++++++ gcc/tree-vect-slp.c | 31 ++++++++++++++++--------------- 2 files changed, 41 insertions(+), 15 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/pr101158.f90 (limited to 'gcc') diff --git a/gcc/testsuite/gfortran.dg/pr101158.f90 b/gcc/testsuite/gfortran.dg/pr101158.f90 new file mode 100644 index 0000000..9a4d9a2 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr101158.f90 @@ -0,0 +1,25 @@ +! { dg-do compile } +! { dg-options "-O1 -ftree-slp-vectorize -fwrapv" } +! { dg-additional-options "-march=armv8-a+sve" { target aarch64-*-* } } + +subroutine sprpl5 (left) + implicit none + + integer :: left + integer :: avail1, avail2, delx1, delx2, i2, ic + + ic = left + delx1 = ic / 2 + delx2 = delx1 + 1 + i2 = ic + delx2 + avail1 = i2 + avail2 = 1 + + do delx1 = 1, 2 + ic = left + nint (real (left) / 2) + if (ic .ge. avail1) avail1 = ic + 1 + + i2 = ic + delx2 + if (i2 .le. avail2) avail2 = i2 + 1 + end do +end subroutine sprpl5 diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c index b9f91e7..6c98acb 100644 --- a/gcc/tree-vect-slp.c +++ b/gcc/tree-vect-slp.c @@ -1177,21 +1177,6 @@ vect_build_slp_tree_1 (vec_info *vinfo, unsigned char *swap, continue; } - if (need_same_oprnds) - { - tree other_op1 = (call_stmt - ? gimple_call_arg (call_stmt, 1) - : gimple_assign_rhs2 (stmt)); - if (!operand_equal_p (first_op1, other_op1, 0)) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, - "Build SLP failed: different shift " - "arguments in %G", stmt); - /* Mismatch. */ - continue; - } - } if (!load_p && first_stmt_code == BIT_FIELD_REF && (TREE_OPERAND (gimple_assign_rhs1 (first_stmt_info->stmt), 0) @@ -1231,6 +1216,22 @@ vect_build_slp_tree_1 (vec_info *vinfo, unsigned char *swap, continue; } + if (need_same_oprnds) + { + tree other_op1 = (call_stmt + ? gimple_call_arg (call_stmt, 1) + : gimple_assign_rhs2 (stmt)); + if (!operand_equal_p (first_op1, other_op1, 0)) + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, + "Build SLP failed: different shift " + "arguments in %G", stmt); + /* Mismatch. */ + continue; + } + } + if (!types_compatible_p (vectype, *node_vectype)) { if (dump_enabled_p ()) -- cgit v1.1 From f0e40ea0640aa0b324ec17e72154997468f33bc7 Mon Sep 17 00:00:00 2001 From: Kito Cheng Date: Mon, 21 Jun 2021 21:19:38 +0800 Subject: testuite: Add pthread check to dg-module-cmi for omp module testing gcc/testsuite: * g++.dg/modules/omp-1_a.C: Check pthread is available for dg-module-cmi. * g++.dg/modules/omp-2_a.C: Ditto. --- gcc/testsuite/g++.dg/modules/omp-1_a.C | 2 +- gcc/testsuite/g++.dg/modules/omp-2_a.C | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/g++.dg/modules/omp-1_a.C b/gcc/testsuite/g++.dg/modules/omp-1_a.C index 94e1171..7ddb776 100644 --- a/gcc/testsuite/g++.dg/modules/omp-1_a.C +++ b/gcc/testsuite/g++.dg/modules/omp-1_a.C @@ -2,7 +2,7 @@ // { dg-require-effective-target pthread } export module foo; -// { dg-module-cmi foo } +// { dg-module-cmi foo { target pthread } } export inline void frob (unsigned (&ary)[64]) { diff --git a/gcc/testsuite/g++.dg/modules/omp-2_a.C b/gcc/testsuite/g++.dg/modules/omp-2_a.C index b0d4bbc..e030ac7 100644 --- a/gcc/testsuite/g++.dg/modules/omp-2_a.C +++ b/gcc/testsuite/g++.dg/modules/omp-2_a.C @@ -2,7 +2,7 @@ // { dg-require-effective-target pthread } export module foo; -// { dg-module-cmi foo } +// { dg-module-cmi foo { target pthread } } // The OpenMPness doesn't escape to the interface. export void frob (unsigned (&ary)[64]) -- cgit v1.1 From 7822285515cd4dab86f722a9f4969b6952904a37 Mon Sep 17 00:00:00 2001 From: Jojo R Date: Mon, 21 Jun 2021 20:42:43 +0800 Subject: RISC-V: Add tune info for T-HEAD C906. gcc/ * config/riscv/riscv.c (thead_c906_tune_info): New. (riscv_tune_info_table): Use new tune. --- gcc/config/riscv/riscv.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'gcc') diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c index 1baa299..576960b 100644 --- a/gcc/config/riscv/riscv.c +++ b/gcc/config/riscv/riscv.c @@ -300,6 +300,19 @@ static const struct riscv_tune_param sifive_7_tune_info = { true, /* slow_unaligned_access */ }; +/* Costs to use when optimizing for T-HEAD c906. */ +static const struct riscv_tune_param thead_c906_tune_info = { + {COSTS_N_INSNS (4), COSTS_N_INSNS (5)}, /* fp_add */ + {COSTS_N_INSNS (4), COSTS_N_INSNS (5)}, /* fp_mul */ + {COSTS_N_INSNS (20), COSTS_N_INSNS (20)}, /* fp_div */ + {COSTS_N_INSNS (4), COSTS_N_INSNS (4)}, /* int_mul */ + {COSTS_N_INSNS (6), COSTS_N_INSNS (6)}, /* int_div */ + 1, /* issue_rate */ + 3, /* branch_cost */ + 5, /* memory_cost */ + false, /* slow_unaligned_access */ +}; + /* Costs to use when optimizing for size. */ static const struct riscv_tune_param optimize_size_tune_info = { {COSTS_N_INSNS (1), COSTS_N_INSNS (1)}, /* fp_add */ @@ -348,6 +361,7 @@ static const struct riscv_tune_info riscv_tune_info_table[] = { { "sifive-3-series", generic, &rocket_tune_info }, { "sifive-5-series", generic, &rocket_tune_info }, { "sifive-7-series", sifive_7, &sifive_7_tune_info }, + { "thead-c906", generic, &thead_c906_tune_info }, { "size", generic, &optimize_size_tune_info }, }; -- cgit v1.1 From a2ef8395fa970498985764514044e5fd00f7d5c0 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Tue, 22 Jun 2021 10:14:02 +0200 Subject: tree-optimization/101151 - fix irreducible region check for sinking The check whether two blocks are in the same irreducible region and thus post-dominance checks being unreliable was incomplete since an irreducible region can contain reducible sub-regions but if one block is in the irreducible part and one not the check still doesn't work as expected. 2021-06-22 Richard Biener PR tree-optimization/101151 * tree-ssa-sink.c (statement_sink_location): Expand irreducible region check. * gcc.dg/torture/pr101151.c: New testcase. --- gcc/testsuite/gcc.dg/torture/pr101151.c | 19 +++++++++++++++++++ gcc/tree-ssa-sink.c | 9 ++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.dg/torture/pr101151.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/torture/pr101151.c b/gcc/testsuite/gcc.dg/torture/pr101151.c new file mode 100644 index 0000000..15c9a7b --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr101151.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ + +int a, *b = &a, c, d; +int main() { + *b; + if (a) { + L1: + a = 0; + L2: + if (d) { + while (b) + ; + goto L1; + } + } + if (c) + goto L2; + return 0; +} diff --git a/gcc/tree-ssa-sink.c b/gcc/tree-ssa-sink.c index d252cbb..92f444e 100644 --- a/gcc/tree-ssa-sink.c +++ b/gcc/tree-ssa-sink.c @@ -398,7 +398,14 @@ statement_sink_location (gimple *stmt, basic_block frombb, && dominated_by_p (CDI_POST_DOMINATORS, commondom, bb) /* If the blocks are possibly within the same irreducible cycle the above check breaks down. */ - && !(bb->flags & commondom->flags & BB_IRREDUCIBLE_LOOP)) + && !((bb->flags & commondom->flags & BB_IRREDUCIBLE_LOOP) + && bb->loop_father == commondom->loop_father) + && !((commondom->flags & BB_IRREDUCIBLE_LOOP) + && flow_loop_nested_p (commondom->loop_father, + bb->loop_father)) + && !((bb->flags & BB_IRREDUCIBLE_LOOP) + && flow_loop_nested_p (bb->loop_father, + commondom->loop_father))) continue; bb = EDGE_PRED (bb, PHI_ARG_INDEX_FROM_USE (use_p))->src; } -- cgit v1.1 From 3aaa69e5f30e1904d7ca2bb711b1cb0c62b6895f Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Thu, 17 Jun 2021 10:19:31 -0400 Subject: Initial value-relation code. This code provides a both an equivalence and relation oracle which can be accessed via a range_query object. This initial code drop includes the oracles and access them, but does not utilize them yet. * Makefile.in (OBJS): Add value-relation.o. * gimple-range.h: Adjust include files. * tree-data-ref.c: Adjust include file order. * value-query.cc (range_query::get_value_range): Default to no oracle. (range_query::query_relation): New. (range_query::query_relation): New. * value-query.h (class range_query): Adjust. * value-relation.cc: New. * value-relation.h: New. --- gcc/Makefile.in | 1 + gcc/gimple-range.h | 2 +- gcc/tree-data-ref.c | 2 +- gcc/value-query.cc | 50 +++ gcc/value-query.h | 11 + gcc/value-relation.cc | 932 ++++++++++++++++++++++++++++++++++++++++++++++++++ gcc/value-relation.h | 159 +++++++++ 7 files changed, 1155 insertions(+), 2 deletions(-) create mode 100644 gcc/value-relation.cc create mode 100644 gcc/value-relation.h (limited to 'gcc') diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 4cb2966..ebf2644 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1688,6 +1688,7 @@ OBJS = \ value-query.o \ value-range.o \ value-range-equiv.o \ + value-relation.o \ value-prof.o \ var-tracking.o \ varasm.o \ diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h index fc28123..b9cffdb 100644 --- a/gcc/gimple-range.h +++ b/gcc/gimple-range.h @@ -24,8 +24,8 @@ along with GCC; see the file COPYING3. If not see #include "range.h" -#include "range-op.h" #include "value-query.h" +#include "range-op.h" #include "gimple-range-edge.h" #include "gimple-range-gori.h" #include "gimple-range-cache.h" diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c index 6f3352f..b6abd8b 100644 --- a/gcc/tree-data-ref.c +++ b/gcc/tree-data-ref.c @@ -97,8 +97,8 @@ along with GCC; see the file COPYING3. If not see #include "tree-eh.h" #include "ssa.h" #include "internal-fn.h" -#include "range-op.h" #include "vr-values.h" +#include "range-op.h" static struct datadep_stats { diff --git a/gcc/value-query.cc b/gcc/value-query.cc index 93609f3..17dfdb1 100644 --- a/gcc/value-query.cc +++ b/gcc/value-query.cc @@ -174,6 +174,7 @@ range_query::get_value_range (const_tree expr, gimple *stmt) range_query::range_query () { equiv_alloc = new equiv_allocator; + m_oracle = NULL; } range_query::~range_query () @@ -452,3 +453,52 @@ global_range_query::range_of_expr (irange &r, tree expr, gimple *stmt) return true; } + +// Return any known relation between SSA1 and SSA2 before stmt S is executed. +// If GET_RANGE is true, query the range of both operands first to ensure +// the defintions have been processed and any relations have be created. + +relation_kind +range_query::query_relation (gimple *s, tree ssa1, tree ssa2, bool get_range) +{ + int_range_max tmp; + if (!m_oracle || TREE_CODE (ssa1) != SSA_NAME || TREE_CODE (ssa2) != SSA_NAME) + return VREL_NONE; + + // Ensure ssa1 and ssa2 have both been evaluated. + if (get_range) + { + range_of_expr (tmp, ssa1, s); + range_of_expr (tmp, ssa2, s); + } + return m_oracle->query_relation (gimple_bb (s), ssa1, ssa2); +} + +// Return any known relation between SSA1 and SSA2 on edge E. +// If GET_RANGE is true, query the range of both operands first to ensure +// the defintions have been processed and any relations have be created. + +relation_kind +range_query::query_relation (edge e, tree ssa1, tree ssa2, bool get_range) +{ + basic_block bb; + int_range_max tmp; + if (!m_oracle || TREE_CODE (ssa1) != SSA_NAME || TREE_CODE (ssa2) != SSA_NAME) + return VREL_NONE; + + // Use destination block if it has a single predecessor, and this picks + // up any relation on the edge. + // Otherwise choose the src edge and the result is the same as on-exit. + if (!single_pred_p (e->dest)) + bb = e->src; + else + bb = e->dest; + + // Ensure ssa1 and ssa2 have both been evaluated. + if (get_range) + { + range_on_edge (tmp, e, ssa1); + range_on_edge (tmp, e, ssa2); + } + return m_oracle->query_relation (bb, ssa1, ssa2); +} diff --git a/gcc/value-query.h b/gcc/value-query.h index 54af031..5161d23 100644 --- a/gcc/value-query.h +++ b/gcc/value-query.h @@ -22,6 +22,8 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_QUERY_H #define GCC_QUERY_H +#include "value-relation.h" + // The value_query class is used by optimization passes that require // valueizing SSA names in terms of a tree value, but have no neeed // for ranges. @@ -91,6 +93,14 @@ public: virtual bool range_on_edge (irange &r, edge, tree expr); virtual bool range_of_stmt (irange &r, gimple *, tree name = NULL); + // Query if there is any relation between SSA1 and SSA2. + relation_kind query_relation (gimple *s, tree ssa1, tree ssa2, + bool get_range = true); + relation_kind query_relation (edge e, tree ssa1, tree ssa2, + bool get_range = true); + // If present, Access relation oracle for more advanced uses. + inline relation_oracle *oracle () const { return m_oracle; } + // DEPRECATED: This method is used from vr-values. The plan is to // rewrite all uses of it to the above API. virtual const class value_range_equiv *get_value_range (const_tree, @@ -102,6 +112,7 @@ protected: void free_value_range_equiv (class value_range_equiv *); bool get_tree_range (irange &r, tree expr, gimple *stmt); bool get_arith_expr_range (irange &r, tree expr, gimple *stmt); + relation_oracle *m_oracle; private: class equiv_allocator *equiv_alloc; diff --git a/gcc/value-relation.cc b/gcc/value-relation.cc new file mode 100644 index 0000000..3c8698f --- /dev/null +++ b/gcc/value-relation.cc @@ -0,0 +1,932 @@ +/* Header file for the value range relational processing. + Copyright (C) 2020-2021 Free Software Foundation, Inc. + Contributed by Andrew MacLeod + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "tree.h" +#include "gimple.h" +#include "ssa.h" + +#include "gimple-range.h" +#include "tree-pretty-print.h" +#include "gimple-pretty-print.h" +#include "alloc-pool.h" +#include "dominance.h" + +// These VREL codes are arranged such that VREL_NONE is the first +// code, and all the rest are contiguous up to and including VREL_LAST. + +#define VREL_FIRST VREL_NONE +#define VREL_LAST NE_EXPR +#define VREL_COUNT (VREL_LAST - VREL_FIRST + 1) + +// vrel_range_assert will either assert that the tree code passed is valid, +// or mark invalid codes as unreachable to help with table optimation. +#if CHECKING_P + #define vrel_range_assert(c) \ + gcc_checking_assert ((c) >= VREL_FIRST && (c) <= VREL_LAST) +#else + #define vrel_range_assert(c) \ + if ((c) < VREL_FIRST || (c) > VREL_LAST) \ + gcc_unreachable (); +#endif + +static const char *kind_string[VREL_COUNT] = +{ "none", "<", "<=", ">", ">=", "empty", "==", "!=" }; + +// Print a relation_kind REL to file F. + +void +print_relation (FILE *f, relation_kind rel) +{ + vrel_range_assert (rel); + fprintf (f, " %s ", kind_string[rel - VREL_FIRST]); +} + +// This table is used to negate the operands. op1 REL op2 -> !(op1 REL op2). +relation_kind rr_negate_table[VREL_COUNT] = { +// NONE, LT_EXPR, LE_EXPR, GT_EXPR, GE_EXPR, EMPTY, EQ_EXPR, NE_EXPR + VREL_NONE, GE_EXPR, GT_EXPR, LE_EXPR, LT_EXPR, VREL_EMPTY, NE_EXPR, EQ_EXPR }; + +// Negate the relation, as in logical negation. + +relation_kind +relation_negate (relation_kind r) +{ + vrel_range_assert (r); + return rr_negate_table [r - VREL_FIRST]; +} + +// This table is used to swap the operands. op1 REL op2 -> op2 REL op1. +relation_kind rr_swap_table[VREL_COUNT] = { +// NONE, LT_EXPR, LE_EXPR, GT_EXPR, GE_EXPR, EMPTY, EQ_EXPR, NE_EXPR + VREL_NONE, GT_EXPR, GE_EXPR, LT_EXPR, LE_EXPR, VREL_EMPTY, EQ_EXPR, NE_EXPR }; + +// Return the relation as if the operands were swapped. + +relation_kind +relation_swap (relation_kind r) +{ + vrel_range_assert (r); + return rr_swap_table [r - VREL_FIRST]; +} + +// This table is used to perform an intersection between 2 relations. + +relation_kind rr_intersect_table[VREL_COUNT][VREL_COUNT] = { +// NONE, LT_EXPR, LE_EXPR, GT_EXPR, GE_EXPR, EMPTY, EQ_EXPR, NE_EXPR +// VREL_NONE + { VREL_NONE, LT_EXPR, LE_EXPR, GT_EXPR, GE_EXPR, VREL_EMPTY, EQ_EXPR, NE_EXPR }, +// LT_EXPR + { LT_EXPR, LT_EXPR, LT_EXPR, VREL_EMPTY, VREL_EMPTY, VREL_EMPTY, VREL_EMPTY, LT_EXPR }, +// LE_EXPR + { LE_EXPR, LT_EXPR, LE_EXPR, VREL_EMPTY, EQ_EXPR, VREL_EMPTY, EQ_EXPR, LT_EXPR }, +// GT_EXPR + { GT_EXPR, VREL_EMPTY, VREL_EMPTY, GT_EXPR, GT_EXPR, VREL_EMPTY, VREL_EMPTY, GT_EXPR }, +// GE_EXPR + { GE_EXPR, VREL_EMPTY, EQ_EXPR, GT_EXPR, GE_EXPR, VREL_EMPTY, EQ_EXPR, GT_EXPR }, +// VREL_EMPTY + { VREL_EMPTY, VREL_EMPTY, VREL_EMPTY, VREL_EMPTY, VREL_EMPTY, VREL_EMPTY, VREL_EMPTY, VREL_EMPTY }, +// EQ_EXPR + { EQ_EXPR, VREL_EMPTY, EQ_EXPR, VREL_EMPTY, EQ_EXPR, VREL_EMPTY, EQ_EXPR, VREL_EMPTY }, +// NE_EXPR + { NE_EXPR, LT_EXPR, LT_EXPR, GT_EXPR, GT_EXPR, VREL_EMPTY, VREL_EMPTY, NE_EXPR } }; + + +// Intersect relation R! with relation R2 and return the resulting relation. + +relation_kind +relation_intersect (relation_kind r1, relation_kind r2) +{ + vrel_range_assert (r1); + vrel_range_assert (r2); + return rr_intersect_table[r1 - VREL_FIRST][r2 - VREL_FIRST]; +} + + +// This table is used to perform a union between 2 relations. + +relation_kind rr_union_table[VREL_COUNT][VREL_COUNT] = { +// NONE, LT_EXPR, LE_EXPR, GT_EXPR, GE_EXPR, EMPTY, EQ_EXPR, NE_EXPR +// VREL_NONE + { VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE }, +// LT_EXPR + { VREL_NONE, LT_EXPR, LE_EXPR, NE_EXPR, VREL_NONE, LT_EXPR, LE_EXPR, NE_EXPR }, +// LE_EXPR + { VREL_NONE, LE_EXPR, LE_EXPR, VREL_NONE, VREL_NONE, LE_EXPR, LE_EXPR, VREL_NONE }, +// GT_EXPR + { VREL_NONE, NE_EXPR, VREL_NONE, GT_EXPR, GE_EXPR, GT_EXPR, GE_EXPR, NE_EXPR }, +// GE_EXPR + { VREL_NONE, VREL_NONE, VREL_NONE, GE_EXPR, GE_EXPR, GE_EXPR, GE_EXPR, VREL_NONE }, +// VREL_EMPTY + { VREL_NONE, LT_EXPR, LE_EXPR, GT_EXPR, GE_EXPR, VREL_EMPTY, EQ_EXPR, NE_EXPR }, +// EQ_EXPR + { VREL_NONE, LE_EXPR, LE_EXPR, GE_EXPR, GE_EXPR, EQ_EXPR, EQ_EXPR, VREL_NONE }, +// NE_EXPR + { VREL_NONE, NE_EXPR, VREL_NONE, NE_EXPR, VREL_NONE, NE_EXPR, VREL_NONE, NE_EXPR } }; + +// Union relation R1 with relation R2 and return the result. + +relation_kind +relation_union (relation_kind r1, relation_kind r2) +{ + vrel_range_assert (r1); + vrel_range_assert (r2); + return rr_union_table[r1 - VREL_FIRST][r2 - VREL_FIRST]; +} + + +// ------------------------------------------------------------------------- + +// This class represents an equivalency set, and contains a link to the next +// one in the list to be searched. + +// The very first element in the m_equiv chain is actually just a summary +// element in which the m_names bitmap is used to indicate that an ssa_name +// has an equivalence set in this block. +// This allows for much faster traversal of the DOM chain, as a search for +// SSA_NAME simply requires walking the DOM chain until a block is found +// which has the bit for SSA_NAME set. Then scan for the equivalency set in +// that block. No previous blcoks need be searched. + +class equiv_chain +{ +public: + bitmap m_names; // ssa-names in equiv set. + basic_block m_bb; // Block this belongs to + equiv_chain *m_next; // Next in block list. + void dump (FILE *f) const; // Show names in this list. +}; + + +// Dump the names in this equivalence set. + +void +equiv_chain::dump (FILE *f) const +{ + bitmap_iterator bi; + unsigned i; + + if (!m_names) + return; + fprintf (f, "Equivalence set : ["); + unsigned c = 0; + EXECUTE_IF_SET_IN_BITMAP (m_names, 0, i, bi) + { + if (ssa_name (i)) + { + if (c++) + fprintf (f, ", "); + print_generic_expr (f, ssa_name (i), TDF_SLIM); + } + } + fprintf (f, "]\n"); +} + +// Instantiate an equivalency oracle. + +equiv_oracle::equiv_oracle () +{ + bitmap_obstack_initialize (&m_bitmaps); + m_equiv.create (0); + m_equiv.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1); + m_equiv_set = BITMAP_ALLOC (&m_bitmaps); + obstack_init (&m_chain_obstack); +} + +// Destruct an equivalency oracle. + +equiv_oracle::~equiv_oracle () +{ + obstack_free (&m_chain_obstack, NULL); + m_equiv.release (); + bitmap_obstack_release (&m_bitmaps); +} + +// Find and return the equivalency set for SSA along the dominators of BB. +// This is the external API. + +const_bitmap +equiv_oracle::equiv_set (tree ssa, basic_block bb) const +{ + // Search the dominator tree for an equivalency. + equiv_chain *equiv = find_equiv_dom (ssa, bb); + if (equiv) + return equiv->m_names; + + return NULL; +} + + +// If SSA has an equivalence in block BB, find and return it. +// Otherwise return NULL. + +equiv_chain * +equiv_oracle::find_equiv_block (unsigned ssa, int bb) const +{ + equiv_chain *ptr = NULL; + if (bb >= (int)m_equiv.length ()) + return NULL; + + // If there are equiv sets and SSA is in one in this block, find it. + // Otherwise return NULL. + if (m_equiv[bb] && bitmap_bit_p (m_equiv[bb]->m_names, ssa)) + { + for (ptr = m_equiv[bb]->m_next; ptr; ptr = ptr->m_next) + if (bitmap_bit_p (ptr->m_names, ssa)) + break; + } + return ptr; +} + +// Starting at block BB, walk the dominator chain looking for the nearest +// equivalence set containing NAME. + +equiv_chain * +equiv_oracle::find_equiv_dom (tree name, basic_block bb) const +{ + unsigned v = SSA_NAME_VERSION (name); + // Short circuit looking for names which have no equivalences. + // Saves time looking for something which does not exist. + if (!bitmap_bit_p (m_equiv_set, v)) + return NULL; + + // NAME has at least once equivalence set, check to see if it has one along + // the dominator tree. + for ( ; bb; bb = get_immediate_dominator (CDI_DOMINATORS, bb)) + { + equiv_chain *ptr = find_equiv_block (v, bb->index); + if (ptr) + return ptr; + } + return NULL; +} + +// Register equivalance between ssa_name V and set EQUIV in block BB, + +bitmap +equiv_oracle::register_equiv (basic_block bb, unsigned v, equiv_chain *equiv) +{ + // V will have an equivalency now. + bitmap_set_bit (m_equiv_set, v); + + // If that equiv chain is in this block, simply use it. + if (equiv->m_bb == bb) + { + bitmap_set_bit (equiv->m_names, v); + bitmap_set_bit (m_equiv[bb->index]->m_names, v); + return NULL; + } + + // Otherwise create an equivalence for this block which is a copy + // of equiv, the add V to the set. + bitmap b = BITMAP_ALLOC (&m_bitmaps); + bitmap_copy (b, equiv->m_names); + bitmap_set_bit (b, v); + return b; +} + +// Register equivalence between set equiv_1 and equiv_2 in block BB. +// Return NULL if either name can be merged with the other. Otherwise +// return a pointer to the combined bitmap of names. This allows the +// caller to do any setup required for a new element. + +bitmap +equiv_oracle::register_equiv (basic_block bb, equiv_chain *equiv_1, + equiv_chain *equiv_2) +{ + // If equiv_1 is alreayd in BB, use it as the combined set. + if (equiv_1->m_bb == bb) + { + bitmap_ior_into (equiv_1->m_names, equiv_2->m_names); + // Its hard to delete from a single linked list, so + // just clear the second one. + if (equiv_2->m_bb == bb) + bitmap_clear (equiv_2->m_names); + else + // Ensure equiv_2s names are in the summary for BB. + bitmap_ior_into (m_equiv[bb->index]->m_names, equiv_2->m_names); + return NULL; + } + // If equiv_2 is in BB, use it for the combined set. + if (equiv_2->m_bb == bb) + { + bitmap_ior_into (equiv_2->m_names, equiv_1->m_names); + // Add equiv_1 names into the summary. + bitmap_ior_into (m_equiv[bb->index]->m_names, equiv_1->m_names); + return NULL; + } + + // At this point, neither equivalence is from this block. + bitmap b = BITMAP_ALLOC (&m_bitmaps); + bitmap_copy (b, equiv_1->m_names); + bitmap_ior_into (b, equiv_2->m_names); + return b; +} + + +// Register an equivalence between SSA1 and SSA2 in block BB. +// The equivalence oracle maintains a vector of equivalencies indexed by basic +// block. When an equivalence bteween SSA1 and SSA2 is registered in block BB, +// a query is made as to what equivalences both names have already, and +// any preexisting equivalences are merged to create a single equivalence +// containing all the ssa_names in this basic block. + +void +equiv_oracle::register_equiv (basic_block bb, tree ssa1, tree ssa2) +{ + unsigned v1 = SSA_NAME_VERSION (ssa1); + unsigned v2 = SSA_NAME_VERSION (ssa2); + equiv_chain *equiv_1 = find_equiv_dom (ssa1, bb); + equiv_chain *equiv_2 = find_equiv_dom (ssa2, bb); + + // Check if they are the same set + if (equiv_1 && equiv_1 == equiv_2) + return; + + bitmap equiv_set; + + // Case where we have 2 SSA_NAMEs that are not in any set. + if (!equiv_1 && !equiv_2) + { + bitmap_set_bit (m_equiv_set, v1); + bitmap_set_bit (m_equiv_set, v2); + + equiv_set = BITMAP_ALLOC (&m_bitmaps); + bitmap_set_bit (equiv_set, v1); + bitmap_set_bit (equiv_set, v2); + } + else if (!equiv_1 && equiv_2) + equiv_set = register_equiv (bb, v1, equiv_2); + else if (equiv_1 && !equiv_2) + equiv_set = register_equiv (bb, v2, equiv_1); + else + equiv_set = register_equiv (bb, equiv_1, equiv_2); + + // A non-null return is a bitmap that is to be added to the current + // block as a new equivalence. + if (!equiv_set) + return; + + equiv_chain *ptr; + + // Check if this is the first time a block has an equivalence added. + // and create a header block. And set the summary for this block. + if (!m_equiv[bb->index]) + { + ptr = (equiv_chain *) obstack_alloc (&m_chain_obstack, + sizeof (equiv_chain)); + ptr->m_names = BITMAP_ALLOC (&m_bitmaps); + bitmap_copy (ptr->m_names, equiv_set); + ptr->m_bb = bb; + ptr->m_next = NULL; + m_equiv[bb->index] = ptr; + } + + // Now create the element for this equiv set and initialize it. + ptr = (equiv_chain *) obstack_alloc (&m_chain_obstack, sizeof (equiv_chain)); + ptr->m_names = equiv_set; + ptr->m_bb = bb; + gcc_checking_assert (bb->index < (int)m_equiv.length ()); + ptr->m_next = m_equiv[bb->index]->m_next; + m_equiv[bb->index]->m_next = ptr; + bitmap_ior_into (m_equiv[bb->index]->m_names, equiv_set); +} + +// Make sure the BB vector is big enough and grow it if needed. + +void +equiv_oracle::limit_check (basic_block bb) +{ + int i = (bb) ? bb->index : last_basic_block_for_fn (cfun); + if (i >= (int)m_equiv.length ()) + m_equiv.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1); +} + +// Dump the equivalence sets in BB to file F. + +void +equiv_oracle::dump (FILE *f, basic_block bb) const +{ + if (bb->index >= (int)m_equiv.length ()) + return; + if (!m_equiv[bb->index]) + return; + + equiv_chain *ptr = m_equiv[bb->index]->m_next; + for (; ptr; ptr = ptr->m_next) + ptr->dump (f); +} + +// Dump all equivalence sets known to the oracle. + +void +equiv_oracle::dump (FILE *f) const +{ + fprintf (f, "Equivalency dump\n"); + for (unsigned i = 0; i < m_equiv.length (); i++) + if (m_equiv[i]) + { + fprintf (f, "BB%d\n", i); + dump (f, BASIC_BLOCK_FOR_FN (cfun, i)); + } +} + + +// -------------------------------------------------------------------------- + +// The value-relation class is used to encapsulate the represention of an +// individual relation between 2 ssa-names, and to facilitate operating on +// the relation. + +class value_relation +{ +public: + value_relation (); + value_relation (relation_kind kind, tree n1, tree n2); + void set_relation (relation_kind kind, tree n1, tree n2); + + inline relation_kind kind () const { return related; } + inline tree op1 () const { return name1; } + inline tree op2 () const { return name2; } + + bool union_ (value_relation &p); + bool intersect (value_relation &p); + void negate (); + void swap (); + + void dump (FILE *f) const; +private: + relation_kind related; + tree name1, name2; +}; + +// Set relation R between ssa_name N1 and N2. + +inline void +value_relation::set_relation (relation_kind r, tree n1, tree n2) +{ + gcc_checking_assert (SSA_NAME_VERSION (n1) != SSA_NAME_VERSION (n2)); + related = r; + name1 = n1; + name2 = n2; +} + +// Default constructor. + +inline +value_relation::value_relation () +{ + related = VREL_NONE; + name1 = NULL_TREE; + name2 = NULL_TREE; +} + +// Constructor for relation R between SSA version N1 nd N2. + +inline +value_relation::value_relation (relation_kind kind, tree n1, tree n2) +{ + set_relation (kind, n1, n2); +} + +// Negate the current relation. + +void +value_relation::negate () +{ + related = relation_negate (related); +} + +// Modify the relation as if the operands were being swapped. + +void +value_relation::swap () +{ + related = relation_swap (related); +} + +// Perform an intersection between 2 relations. *this &&= p. + +bool +value_relation::intersect (value_relation &p) +{ + // Save previous value + relation_kind old = related; + + if (p.op1 () == op1 () && p.op2 () == op2 ()) + related = relation_intersect (kind (), p.kind ()); + else if (p.op2 () == op1 () && p.op1 () == op2 ()) + related = relation_intersect (kind (), relation_swap (p.kind ())); + else + return false; + + return old != related; +} + +// Perform a union between 2 relations. *this ||= p. + +bool +value_relation::union_ (value_relation &p) +{ + // Save previous value + relation_kind old = related; + + if (p.op1 () == op1 () && p.op2 () == op2 ()) + related = relation_union (kind(), p.kind()); + else if (p.op2 () == op1 () && p.op1 () == op2 ()) + related = relation_union (kind(), relation_swap (p.kind ())); + else + return false; + + return old != related; +} + + +// Dump the relation to file F. + +void +value_relation::dump (FILE *f) const +{ + if (!name1 || !name2) + { + fprintf (f, "uninitialized"); + return; + } + fputc ('(', f); + print_generic_expr (f, op1 (), TDF_SLIM); + print_relation (f, kind ()); + print_generic_expr (f, op2 (), TDF_SLIM); + fputc(')', f); +} + +// This container is used to link relations in a chain. + +class relation_chain : public value_relation +{ +public: + relation_chain *m_next; +}; + +// ------------------------------------------------------------------------ + +// Instantiate a relation oracle. + +relation_oracle::relation_oracle () +{ + m_relations.create (0); + m_relations.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1); + m_relation_set = BITMAP_ALLOC (&m_bitmaps); + m_tmp = BITMAP_ALLOC (&m_bitmaps); +} + +// Destruct a relation oracle. + +relation_oracle::~relation_oracle () +{ + m_relations.release (); +} + +// Register relation K between ssa_name OP1 and OP2 on STMT. + +void +relation_oracle::register_relation (gimple *stmt, relation_kind k, tree op1, + tree op2) +{ + gcc_checking_assert (TREE_CODE (op1) == SSA_NAME); + gcc_checking_assert (TREE_CODE (op2) == SSA_NAME); + gcc_checking_assert (stmt && gimple_bb (stmt)); + + // Don't register lack of a relation. + if (k == VREL_NONE) + return; + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + value_relation vr (k, op1, op2); + fprintf (dump_file, " Registering value_relation "); + vr.dump (dump_file); + fprintf (dump_file, " (bb%d) at ", gimple_bb (stmt)->index); + print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); + } + + // This relation applies to the entire block, use STMT's block. + // Equivalencies are handled by the equivalence oracle. + if (k == EQ_EXPR) + register_equiv (gimple_bb (stmt), op1, op2); + else + register_relation (gimple_bb (stmt), k, op1, op2); +} + +// Register relation K between ssa_name OP1 and OP2 on edge E. + +void +relation_oracle::register_relation (edge e, relation_kind k, tree op1, + tree op2) +{ + gcc_checking_assert (TREE_CODE (op1) == SSA_NAME); + gcc_checking_assert (TREE_CODE (op2) == SSA_NAME); + + // Do not register lack of relation, or blocks which have more than + // edge E for a predecessor. + if (k == VREL_NONE || !single_pred_p (e->dest)) + return; + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + value_relation vr (k, op1, op2); + fprintf (dump_file, " Registering value_relation "); + vr.dump (dump_file); + fprintf (dump_file, " on (%d->%d)\n", e->src->index, e->dest->index); + } + + // Equivalencies are handled by the equivalence oracle. + if (k == EQ_EXPR) + register_equiv (e->dest, op1, op2); + else + register_relation (e->dest, k, op1, op2); +} + +// Register relation K between OP! and OP2 in block BB. +// This creates the record and searches for existing records in the dominator +// tree to merge with. + +void +relation_oracle::register_relation (basic_block bb, relation_kind k, tree op1, + tree op2) +{ + gcc_checking_assert (k != VREL_NONE); + + value_relation vr(k, op1, op2); + int bbi = bb->index; + + if (bbi >= (int)m_relations.length()) + m_relations.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1); + + // Summary bitmap indicating what ssa_names have relations in this BB. + bitmap bm = m_relations[bbi].m_names; + if (!bm) + bm = m_relations[bbi].m_names = BITMAP_ALLOC (&m_bitmaps); + unsigned v1 = SSA_NAME_VERSION (op1); + unsigned v2 = SSA_NAME_VERSION (op2); + + relation_kind curr; + relation_chain *ptr; + curr = find_relation_block (bbi, v1, v2, &ptr); + // There is an existing relation in this block, just intersect with it. + if (curr != VREL_NONE) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, " Intersecting with existing "); + ptr->dump (dump_file); + } + // Check into whether we can simply replace the relation rather than + // intersecting it. THis may help with some optimistic iterative + // updating algorithms. + ptr->intersect (vr); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, " to produce "); + ptr->dump (dump_file); + fprintf (dump_file, "\n"); + } + return; + } + + // Check for an existing relation further up the DOM chain. + // By including dominating relations, The first one found in any search + // will be the aggregate of all the previous ones. + curr = find_relation_dom (bb, v1, v2); + if (curr != VREL_NONE) + k = relation_intersect (curr, k); + + bitmap_set_bit (bm, v1); + bitmap_set_bit (bm, v2); + bitmap_set_bit (m_relation_set, v1); + bitmap_set_bit (m_relation_set, v2); + + ptr = (relation_chain *) obstack_alloc (&m_chain_obstack, + sizeof (relation_chain)); + ptr->set_relation (k, op1, op2); + ptr->m_next = m_relations[bbi].m_head; + m_relations[bbi].m_head = ptr;; +} + +// Find the relation between any ssa_name in B1 and any name in B2 in block BB. +// This will allow equivalencies to be applied to any SSA_NAME in a relation. + +relation_kind +relation_oracle::find_relation_block (unsigned bb, const_bitmap b1, + const_bitmap b2) +{ + const_bitmap bm; + if (bb >= m_relations.length()) + return VREL_NONE; + + bm = m_relations[bb].m_names; + if (!bm) + return VREL_NONE; + + // If both b1 and b2 aren't referenced in thie block, cant be a relation + if (!bitmap_intersect_p (bm, b1) || !bitmap_intersect_p (bm, b2)) + return VREL_NONE; + + // Search for the fiorst relation that contains BOTH an element from B1 + // and B2, and return that relation. + for (relation_chain *ptr = m_relations[bb].m_head; ptr ; ptr = ptr->m_next) + { + unsigned op1 = SSA_NAME_VERSION (ptr->op1 ()); + unsigned op2 = SSA_NAME_VERSION (ptr->op2 ()); + if (bitmap_bit_p (b1, op1) && bitmap_bit_p (b1, op2)) + return ptr->kind (); + if (bitmap_bit_p (b1, op2) && bitmap_bit_p (b1, op1)) + return relation_swap (ptr->kind ()); + } + + return VREL_NONE; +} + +// Search the DOM tree for a relation between an element of B1 and B2, starting +// with block BB. + +relation_kind +relation_oracle::find_relation_dom (basic_block bb, const_bitmap b1, + const_bitmap b2) +{ + relation_kind r; + // If either name does not occur in a relation anywhere, there isnt one. + if (!bitmap_intersect_p (m_relation_set, b1) + || !bitmap_intersect_p (m_relation_set, b2)) + return VREL_NONE; + + // Search each block in the DOM tree checking. + for ( ; bb; bb = get_immediate_dominator (CDI_DOMINATORS, bb)) + { + r = find_relation_block (bb->index, b1, b2); + if (r != VREL_NONE) + return r; + } + return VREL_NONE; + +} + +// Find a relation in block BB between ssa version V1 and V2. If a relation +// is found, return a pointer to the chain object in OBJ. + +relation_kind +relation_oracle::find_relation_block (int bb, unsigned v1, unsigned v2, + relation_chain **obj) +{ + if (bb >= (int)m_relations.length()) + return VREL_NONE; + + const_bitmap bm = m_relations[bb].m_names; + if (!bm) + return VREL_NONE; + + // If both b1 and b2 aren't referenced in thie block, cant be a relation + if (!bitmap_bit_p (bm, v1) || !bitmap_bit_p (bm, v2)) + return VREL_NONE; + + relation_chain *ptr; + for (ptr = m_relations[bb].m_head; ptr ; ptr = ptr->m_next) + { + unsigned op1 = SSA_NAME_VERSION (ptr->op1 ()); + unsigned op2 = SSA_NAME_VERSION (ptr->op2 ()); + if (v1 == op1 && v2 == op2) + { + if (obj) + *obj = ptr; + return ptr->kind (); + } + if (v1 == op2 && v2 == op1) + { + if (obj) + *obj = ptr; + return relation_swap (ptr->kind ()); + } + } + + return VREL_NONE; +} + +// Find a relation between SSA version V1 and V2 in the dominator tree +// starting with block BB + +relation_kind +relation_oracle::find_relation_dom (basic_block bb, unsigned v1, unsigned v2) +{ + relation_kind r; + // IF either name does not occur in a relation anywhere, there isnt one. + if (!bitmap_bit_p (m_relation_set, v1) || !bitmap_bit_p (m_relation_set, v2)) + return VREL_NONE; + + for ( ; bb; bb = get_immediate_dominator (CDI_DOMINATORS, bb)) + { + r = find_relation_block (bb->index, v1, v2); + if (r != VREL_NONE) + return r; + } + return VREL_NONE; + +} + +// Query if there is a relation between SSA1 and SS2 in block BB or a +// dominator of BB + +relation_kind +relation_oracle::query_relation (basic_block bb, tree ssa1, tree ssa2) +{ + relation_kind kind; + unsigned v1 = SSA_NAME_VERSION (ssa1); + unsigned v2 = SSA_NAME_VERSION (ssa2); + if (v1 == v2) + return EQ_EXPR; + + // Check for equivalence first. + const_bitmap equiv1 = equiv_set (ssa1, bb); + if (equiv1 && bitmap_bit_p (equiv1, v2)) + return EQ_EXPR; + + // Initially look for a direct relationship and just return that. + kind = find_relation_dom (bb, v1, v2); + if (kind != VREL_NONE) + return kind; + + // If one is not found, see if there is a relationship between equivalences. + // If v2 isn't in v1s equiv set, then v1 shouldn't be in v2's set either. + const_bitmap equiv2 = equiv_set (ssa2, bb); + gcc_checking_assert (!equiv2 || !bitmap_bit_p (equiv2, v1)); + + if (!equiv1 && !equiv2) + kind = VREL_NONE; + else if (!equiv1) + { + bitmap_clear (m_tmp); + bitmap_set_bit (m_tmp, v1); + kind = find_relation_dom (bb, m_tmp, equiv2); + } + else if (!equiv2) + { + bitmap_clear (m_tmp); + bitmap_set_bit (m_tmp, v2); + kind = find_relation_dom (bb, equiv1, m_tmp); + } + else + kind = find_relation_dom (bb, equiv1, equiv2); + return kind; +} + +// Dump all the relations in block BB to file F. + +void +relation_oracle::dump (FILE *f, basic_block bb) const +{ + equiv_oracle::dump (f,bb); + + if (bb->index >= (int)m_relations.length ()) + return; + if (!m_relations[bb->index].m_names) + return; + + relation_chain *ptr = m_relations[bb->index].m_head; + for (; ptr; ptr = ptr->m_next) + { + fprintf (f, "Relational : "); + ptr->dump (f); + fprintf (f, "\n"); + } +} + +// Dump all the relations known to file F. + +void +relation_oracle::dump (FILE *f) const +{ + fprintf (f, "Relation dump\n"); + for (unsigned i = 0; i < m_relations.length (); i++) + { + fprintf (f, "BB%d\n", i); + dump (f, BASIC_BLOCK_FOR_FN (cfun, i)); + } +} diff --git a/gcc/value-relation.h b/gcc/value-relation.h new file mode 100644 index 0000000..1148854 --- /dev/null +++ b/gcc/value-relation.h @@ -0,0 +1,159 @@ +/* Header file for the value range relational processing. + Copyright (C) 2020-2021 Free Software Foundation, Inc. + Contributed by Andrew MacLeod + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#ifndef GCC_VALUE_RELATION_H +#define GCC_VALUE_RELATION_H + + +// This file provides access to a relation oracle which can be used to +// maintain and query relations and equivalences between SSA_NAMES. +// +// The general range_query object provided in value-query.h provides +// access to an oracle, if one is available, via the oracle() method. +// Thre are also a couple of access routines provided, which even if there is +// no oracle, will return the default VREL_NONE no relation. +// +// Typically, when a ranger object is active, there will be an oracle, and +// any information available can be directly queried. Ranger also sets and +// utilizes the relation information to enhance it's range calculations, this +// is totally transparent to the client, and they are free to make queries. +// +// +// relation_kind is a typedef of enum tree_code, but has restricted range +// and a couple of extra values. +// +// A query is made requesting the relation between SSA1 and SSA@ in a basic +// block, or on an edge, the possible return values are: +// +// EQ_EXPR, NE_EXPR, LT_EXPR, LE_EXPR, GT_EXPR, and GE_EXPR mean the same. +// VREL_NONE : No relation between the 2 names. +// VREL_EMPTY : Impossible relation (ie, A < B && A > B produces VREL_EMPTY. +// +// The oracle maintains EQ_EXPR relations with equivalency sets, so if a +// relation comes back EQ_EXPR, it is also possible to query the set of +// equivlaencies. These are basically bitmaps over ssa_names. +// +// relations are maintained via the dominace trees, are are optimized assuming +// they are registered in dominance order. When a new relation is added, it +// is intersected with whatever existing relation exists in the dominance tree +// and registered at the specified block. + + +// Rather than introduce a new enumerated type for relations, we can use the +// existing tree_codes for relations, plus add a couple of #defines for +// the other cases. These codes are arranged such that VREL_NONE is the first +// code, and all the rest are contiguous. + +typedef enum tree_code relation_kind; + +#define VREL_NONE TRUTH_NOT_EXPR +#define VREL_EMPTY LTGT_EXPR + +// General relation kind transformations. +relation_kind relation_union (relation_kind r1, relation_kind r2); +relation_kind relation_intersect (relation_kind r1, relation_kind r2); +relation_kind relation_negate (relation_kind r); +relation_kind relation_swap (relation_kind r); +void print_relation (FILE *f, relation_kind rel); + +// Declared internally in value-relation.cc +class equiv_chain; + +// The equivalency oracle maintains equivalencies using the dominator tree. +// Equivalencies apply to an entire basic block. Equivalencies on edges +// can be represented only on edges whose destination is a single-pred block, +// and the equivalence is simply applied to that succesor block. + +class equiv_oracle +{ +public: + equiv_oracle (); + ~equiv_oracle (); + + const_bitmap equiv_set (tree ssa, basic_block bb) const; + void register_equiv (basic_block bb, tree ssa1, tree ssa2); + + void dump (FILE *f, basic_block bb) const; + void dump (FILE *f) const; + +protected: + bitmap_obstack m_bitmaps; + struct obstack m_chain_obstack; +private: + bitmap m_equiv_set; // Index by ssa-name. true if an equivalence exists. + vec m_equiv; // Index by BB. list of equivalences. + + void limit_check (basic_block bb = NULL); + equiv_chain *find_equiv_block (unsigned ssa, int bb) const; + equiv_chain *find_equiv_dom (tree name, basic_block bb) const; + + bitmap register_equiv (basic_block bb, unsigned v, equiv_chain *equiv_1); + bitmap register_equiv (basic_block bb, equiv_chain *equiv_1, + equiv_chain *equiv_2); + +}; + +// Summary block header for relations. + +class relation_chain_head +{ +public: + bitmap m_names; // ssa_names with relations in this block. + class relation_chain *m_head; // List of relations in block. +}; + +// A relation oracle maintains a set of relations between ssa_names using the +// dominator tree structures. Equivalencies are considered a subset of +// a general relation and maintained by an equivalence oracle by transparently +// passing any EQ_EXPR relations to it. +// Relations are handled at the basic block level. All relations apply to +// an entire block, and are thus kept in a summary index by block. +// Similar to the equivalence oracle, edges are handled by applying the +// relation to the destination block of the edge, but ONLY if that block +// has a single successor. For now. + +class relation_oracle : public equiv_oracle +{ +public: + relation_oracle (); + ~relation_oracle (); + + void register_relation (gimple *stmt, relation_kind k, tree op1, tree op2); + void register_relation (edge e, relation_kind k, tree op1, tree op2); + + relation_kind query_relation (basic_block bb, tree ssa1, tree ssa2); + + void dump (FILE *f, basic_block bb) const; + void dump (FILE *f) const; +private: + bitmap m_tmp; + bitmap m_relation_set; // Index by ssa-name. True if a relation exists + vec m_relations; // Index by BB, list of relations. + relation_kind find_relation_block (unsigned bb, const_bitmap b1, + const_bitmap b2); + relation_kind find_relation_dom (basic_block bb, const_bitmap b1, + const_bitmap b2); + relation_kind find_relation_block (int bb, unsigned v1, unsigned v2, + relation_chain **obj = NULL); + relation_kind find_relation_dom (basic_block bb, unsigned v1, unsigned v2); + void register_relation (basic_block bb, relation_kind k, tree op1, tree op2); +}; + +#endif /* GCC_VALUE_RELATION_H */ -- cgit v1.1 From 80dd13f5c3bdc7899ee6e863e05b254815ec0cef Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Thu, 17 Jun 2021 11:49:21 -0400 Subject: Add relational support to range-op. This patch integrates relations with range-op functionality so that any known relations can be used to help reduce or resolve ranges. Initially handle EQ_EXPR, NE_EXPR, LE_EXPR, LT_EXPR, GT_EXPR and GE_EXPR. * range-op.cc (range_operator::wi_fold): Apply relation effect. (range_operator::fold_range): Adjust and apply relation effect. (*::fold_range): Add relation parameters. (*::op1_range): Ditto. (*::op2_range): Ditto. (range_operator::lhs_op1_relation): New. (range_operator::lhs_op2_relation): New. (range_operator::op1_op2_relation): New. (range_operator::op1_op2_relation_effect): New. (relop_early_resolve): New. (operator_equal::op1_op2_relation): New. (operator_equal::fold_range): Call relop_early_resolve. (operator_not_equal::op1_op2_relation): New. (operator_not_equal::fold_range): Call relop_early_resolve. (operator_lt::op1_op2_relation): New. (operator_lt::fold_range): Call relop_early_resolve. (operator_le::op1_op2_relation): New. (operator_le::fold_range): Call relop_early_resolve. (operator_gt::op1_op2_relation): New. (operator_gt::fold_range): Call relop_early_resolve. (operator_ge::op1_op2_relation): New. (operator_ge::fold_range): Call relop_early_resolve. * range-op.h (class range_operator): Adjust parameters and methods. --- gcc/range-op.cc | 584 +++++++++++++++++++++++++++++++++++++++++++------------- gcc/range-op.h | 24 ++- 2 files changed, 469 insertions(+), 139 deletions(-) (limited to 'gcc') diff --git a/gcc/range-op.cc b/gcc/range-op.cc index e805f26..d807693 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see #include "gimple-walk.h" #include "tree-cfg.h" #include "wide-int.h" +#include "value-relation.h" #include "range-op.h" // Return the upper limit for a type. @@ -138,7 +139,8 @@ range_operator::wi_fold (irange &r, tree type, bool range_operator::fold_range (irange &r, tree type, const irange &lh, - const irange &rh) const + const irange &rh, + relation_kind rel) const { gcc_checking_assert (irange::supports_type_p (type)); if (empty_range_varying (r, type, lh, rh)) @@ -152,6 +154,7 @@ range_operator::fold_range (irange &r, tree type, { wi_fold (r, type, lh.lower_bound (0), lh.upper_bound (0), rh.lower_bound (0), rh.upper_bound (0)); + op1_op2_relation_effect (r, type, lh, rh, rel); return true; } @@ -167,8 +170,12 @@ range_operator::fold_range (irange &r, tree type, wi_fold (tmp, type, lh_lb, lh_ub, rh_lb, rh_ub); r.union_ (tmp); if (r.varying_p ()) - return true; + { + op1_op2_relation_effect (r, type, lh, rh, rel); + return true; + } } + op1_op2_relation_effect (r, type, lh, rh, rel); return true; } @@ -178,7 +185,8 @@ bool range_operator::op1_range (irange &r ATTRIBUTE_UNUSED, tree type ATTRIBUTE_UNUSED, const irange &lhs ATTRIBUTE_UNUSED, - const irange &op2 ATTRIBUTE_UNUSED) const + const irange &op2 ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const { return false; } @@ -189,11 +197,47 @@ bool range_operator::op2_range (irange &r ATTRIBUTE_UNUSED, tree type ATTRIBUTE_UNUSED, const irange &lhs ATTRIBUTE_UNUSED, - const irange &op1 ATTRIBUTE_UNUSED) const + const irange &op1 ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const { return false; } +// The default relation routines return VREL_NONE. + +enum tree_code +range_operator::lhs_op1_relation (const irange &lhs ATTRIBUTE_UNUSED, + const irange &op1 ATTRIBUTE_UNUSED, + const irange &op2 ATTRIBUTE_UNUSED) const +{ + return VREL_NONE; +} + +enum tree_code +range_operator::lhs_op2_relation (const irange &lhs ATTRIBUTE_UNUSED, + const irange &op1 ATTRIBUTE_UNUSED, + const irange &op2 ATTRIBUTE_UNUSED) const +{ + return VREL_NONE; +} + +enum tree_code +range_operator::op1_op2_relation (const irange &lhs ATTRIBUTE_UNUSED) const +{ + return VREL_NONE; +} + +// Default is no relation affects the LHS. + +bool +range_operator::op1_op2_relation_effect (irange &lhs_range ATTRIBUTE_UNUSED, + tree type ATTRIBUTE_UNUSED, + const irange &op1_range ATTRIBUTE_UNUSED, + const irange &op2_range ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const +{ + return false; +} // Create and return a range from a pair of wide-ints that are known // to have overflowed (or underflowed). @@ -385,27 +429,82 @@ get_bool_state (irange &r, const irange &lhs, tree val_type) return BRS_TRUE; } +// For relation opcodes, first try to see if the supplied relation +// forces a true or false result, and return that. +// Then check for undefined operands. If none of this applies, +// return false. + +static inline bool +relop_early_resolve (irange &r, tree type, const irange &op1, + const irange &op2, relation_kind rel, + relation_kind my_rel) +{ + // If known relation is a complete subset of this relation, always true. + if (relation_union (rel, my_rel) == my_rel) + { + r = range_true (type); + return true; + } + + // If known relation has no subset of this relation, always false. + if (relation_intersect (rel, my_rel) == VREL_EMPTY) + { + r = range_false (type); + return true; + } + + // If either operand is undefined, return VARYING. + if (empty_range_varying (r, type, op1, op2)) + return true; + + return false; +} + class operator_equal : public range_operator { public: virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &val) const; + const irange &val, + relation_kind rel = VREL_NONE) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &val) const; + const irange &val, + relation_kind rel = VREL_NONE) const; + virtual enum tree_code op1_op2_relation (const irange &lhs) const; } op_equal; +// Check if the LHS range indicates a relation between OP1 and OP2. + +enum tree_code +operator_equal::op1_op2_relation (const irange &lhs) const +{ + if (lhs.undefined_p ()) + return VREL_EMPTY; + + // FALSE = op1 == op2 indicates NE_EXPR. + if (lhs.zero_p ()) + return NE_EXPR; + + // TRUE = op1 == op2 indicates EQ_EXPR. + if (!lhs.contains_p (build_zero_cst (lhs.type ()))) + return EQ_EXPR; + return VREL_NONE; +} + + bool operator_equal::fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const + const irange &op2, + relation_kind rel) const { - if (empty_range_varying (r, type, op1, op2)) + if (relop_early_resolve (r, type, op1, op2, rel, EQ_EXPR)) return true; // We can be sure the values are always equal or not if both ranges @@ -435,7 +534,8 @@ operator_equal::fold_range (irange &r, tree type, bool operator_equal::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { switch (get_bool_state (r, lhs, type)) { @@ -465,32 +565,55 @@ operator_equal::op1_range (irange &r, tree type, bool operator_equal::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel) const { - return operator_equal::op1_range (r, type, lhs, op1); + return operator_equal::op1_range (r, type, lhs, op1, rel); } - class operator_not_equal : public range_operator { public: virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel = VREL_NONE) const; + virtual enum tree_code op1_op2_relation (const irange &lhs) const; } op_not_equal; +// Check if the LHS range indicates a relation between OP1 and OP2. + +enum tree_code +operator_not_equal::op1_op2_relation (const irange &lhs) const +{ + if (lhs.undefined_p ()) + return VREL_EMPTY; + + // FALSE = op1 != op2 indicates EQ_EXPR. + if (lhs.zero_p ()) + return EQ_EXPR; + + // TRUE = op1 != op2 indicates NE_EXPR. + if (!lhs.contains_p (build_zero_cst (lhs.type ()))) + return NE_EXPR; + return VREL_NONE; +} + bool operator_not_equal::fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const + const irange &op2, + relation_kind rel) const { - if (empty_range_varying (r, type, op1, op2)) + if (relop_early_resolve (r, type, op1, op2, rel, NE_EXPR)) return true; // We can be sure the values are always equal or not if both ranges @@ -520,7 +643,8 @@ operator_not_equal::fold_range (irange &r, tree type, bool operator_not_equal::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { switch (get_bool_state (r, lhs, type)) { @@ -551,9 +675,10 @@ operator_not_equal::op1_range (irange &r, tree type, bool operator_not_equal::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel) const { - return operator_not_equal::op1_range (r, type, lhs, op1); + return operator_not_equal::op1_range (r, type, lhs, op1, rel); } // (X < VAL) produces the range of [MIN, VAL - 1]. @@ -607,21 +732,44 @@ class operator_lt : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel = VREL_NONE) const; + virtual enum tree_code op1_op2_relation (const irange &lhs) const; } op_lt; +// Check if the LHS range indicates a relation between OP1 and OP2. + +enum tree_code +operator_lt::op1_op2_relation (const irange &lhs) const +{ + if (lhs.undefined_p ()) + return VREL_EMPTY; + + // FALSE = op1 < op2 indicates GE_EXPR. + if (lhs.zero_p ()) + return GE_EXPR; + + // TRUE = op1 < op2 indicates LT_EXPR. + if (!lhs.contains_p (build_zero_cst (lhs.type ()))) + return LT_EXPR; + return VREL_NONE; +} + bool operator_lt::fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const + const irange &op2, + relation_kind rel) const { - if (empty_range_varying (r, type, op1, op2)) + if (relop_early_resolve (r, type, op1, op2, rel, LT_EXPR)) return true; signop sign = TYPE_SIGN (op1.type ()); @@ -639,7 +787,8 @@ operator_lt::fold_range (irange &r, tree type, bool operator_lt::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { switch (get_bool_state (r, lhs, type)) { @@ -660,7 +809,8 @@ operator_lt::op1_range (irange &r, tree type, bool operator_lt::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const { switch (get_bool_state (r, lhs, type)) { @@ -684,21 +834,44 @@ class operator_le : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel = VREL_NONE) const; + virtual enum tree_code op1_op2_relation (const irange &lhs) const; } op_le; +// Check if the LHS range indicates a relation between OP1 and OP2. + +enum tree_code +operator_le::op1_op2_relation (const irange &lhs) const +{ + if (lhs.undefined_p ()) + return VREL_EMPTY; + + // FALSE = op1 <= op2 indicates GT_EXPR. + if (lhs.zero_p ()) + return GT_EXPR; + + // TRUE = op1 <= op2 indicates LE_EXPR. + if (!lhs.contains_p (build_zero_cst (lhs.type ()))) + return LE_EXPR; + return VREL_NONE; +} + bool operator_le::fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const + const irange &op2, + relation_kind rel) const { - if (empty_range_varying (r, type, op1, op2)) + if (relop_early_resolve (r, type, op1, op2, rel, LE_EXPR)) return true; signop sign = TYPE_SIGN (op1.type ()); @@ -716,7 +889,8 @@ operator_le::fold_range (irange &r, tree type, bool operator_le::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { switch (get_bool_state (r, lhs, type)) { @@ -737,7 +911,8 @@ operator_le::op1_range (irange &r, tree type, bool operator_le::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const { switch (get_bool_state (r, lhs, type)) { @@ -761,20 +936,44 @@ class operator_gt : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel = VREL_NONE) const; + virtual enum tree_code op1_op2_relation (const irange &lhs) const; } op_gt; +// Check if the LHS range indicates a relation between OP1 and OP2. + +enum tree_code +operator_gt::op1_op2_relation (const irange &lhs) const +{ + if (lhs.undefined_p ()) + return VREL_EMPTY; + + // FALSE = op1 > op2 indicates LE_EXPR. + if (lhs.zero_p ()) + return LE_EXPR; + + // TRUE = op1 > op2 indicates GT_EXPR. + if (!lhs.contains_p (build_zero_cst (lhs.type ()))) + return GT_EXPR; + return VREL_NONE; +} + + bool operator_gt::fold_range (irange &r, tree type, - const irange &op1, const irange &op2) const + const irange &op1, const irange &op2, + relation_kind rel) const { - if (empty_range_varying (r, type, op1, op2)) + if (relop_early_resolve (r, type, op1, op2, rel, GT_EXPR)) return true; signop sign = TYPE_SIGN (op1.type ()); @@ -791,7 +990,8 @@ operator_gt::fold_range (irange &r, tree type, bool operator_gt::op1_range (irange &r, tree type, - const irange &lhs, const irange &op2) const + const irange &lhs, const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { switch (get_bool_state (r, lhs, type)) { @@ -812,7 +1012,8 @@ operator_gt::op1_range (irange &r, tree type, bool operator_gt::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const { switch (get_bool_state (r, lhs, type)) { @@ -836,21 +1037,44 @@ class operator_ge : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel = VREL_NONE) const; + virtual enum tree_code op1_op2_relation (const irange &lhs) const; } op_ge; +// Check if the LHS range indicates a relation between OP1 and OP2. + +enum tree_code +operator_ge::op1_op2_relation (const irange &lhs) const +{ + if (lhs.undefined_p ()) + return VREL_EMPTY; + + // FALSE = op1 >= op2 indicates LT_EXPR. + if (lhs.zero_p ()) + return LT_EXPR; + + // TRUE = op1 >= op2 indicates GE_EXPR. + if (!lhs.contains_p (build_zero_cst (lhs.type ()))) + return GE_EXPR; + return VREL_NONE; +} + bool operator_ge::fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const + const irange &op2, + relation_kind rel) const { - if (empty_range_varying (r, type, op1, op2)) + if (relop_early_resolve (r, type, op1, op2, rel, GE_EXPR)) return true; signop sign = TYPE_SIGN (op1.type ()); @@ -868,7 +1092,8 @@ operator_ge::fold_range (irange &r, tree type, bool operator_ge::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { switch (get_bool_state (r, lhs, type)) { @@ -889,7 +1114,8 @@ operator_ge::op1_range (irange &r, tree type, bool operator_ge::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const { switch (get_bool_state (r, lhs, type)) { @@ -913,10 +1139,12 @@ class operator_plus : public range_operator public: virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const; virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, @@ -939,7 +1167,8 @@ operator_plus::wi_fold (irange &r, tree type, bool operator_plus::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op2); } @@ -947,7 +1176,8 @@ operator_plus::op1_range (irange &r, tree type, bool operator_plus::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const { return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op1); } @@ -958,10 +1188,12 @@ class operator_minus : public range_operator public: virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const; virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, @@ -984,7 +1216,8 @@ operator_minus::wi_fold (irange &r, tree type, bool operator_minus::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { return range_op_handler (PLUS_EXPR, type)->fold_range (r, type, lhs, op2); } @@ -992,7 +1225,8 @@ operator_minus::op1_range (irange &r, tree type, bool operator_minus::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const { return fold_range (r, type, op1, lhs); } @@ -1127,15 +1361,18 @@ public: const wide_int &w0, const wide_int &w1) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const; } op_mult; bool operator_mult::op1_range (irange &r, tree type, - const irange &lhs, const irange &op2) const + const irange &lhs, const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { tree offset; @@ -1153,9 +1390,10 @@ operator_mult::op1_range (irange &r, tree type, bool operator_mult::op2_range (irange &r, tree type, - const irange &lhs, const irange &op1) const + const irange &lhs, const irange &op1, + relation_kind rel) const { - return operator_mult::op1_range (r, type, lhs, op1); + return operator_mult::op1_range (r, type, lhs, op1, rel); } bool @@ -1391,14 +1629,16 @@ public: operator_exact_divide () : operator_div (TRUNC_DIV_EXPR) { } virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const; } op_exact_div; bool operator_exact_divide::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { tree offset; // [2, 4] = op1 / [3,3] since its exact divide, no need to worry about @@ -1419,10 +1659,12 @@ class operator_lshift : public cross_product_operator public: virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, @@ -1438,7 +1680,8 @@ class operator_rshift : public cross_product_operator public: virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, @@ -1450,14 +1693,16 @@ public: const wide_int &w1) const; virtual bool op1_range (irange &, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; } op_rshift; bool operator_lshift::fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { int_range_max shift_range; if (!get_shift_range (shift_range, type, op2)) @@ -1572,7 +1817,8 @@ bool operator_lshift::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { tree shift_amount; if (op2.singleton_p (&shift_amount)) @@ -1632,7 +1878,8 @@ bool operator_rshift::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { tree shift; if (op2.singleton_p (&shift)) @@ -1708,7 +1955,8 @@ operator_rshift::wi_op_overflows (wide_int &res, bool operator_rshift::fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { int_range_max shift; if (!get_shift_range (shift, type, op2)) @@ -1737,10 +1985,12 @@ class operator_cast: public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; private: bool truncating_cast_p (const irange &inner, const irange &outer) const; bool inside_domain_p (const wide_int &min, const wide_int &max, @@ -1818,7 +2068,8 @@ operator_cast::fold_pair (irange &r, unsigned index, bool operator_cast::fold_range (irange &r, tree type ATTRIBUTE_UNUSED, const irange &inner, - const irange &outer) const + const irange &outer, + relation_kind rel ATTRIBUTE_UNUSED) const { if (empty_range_varying (r, type, inner, outer)) return true; @@ -1844,7 +2095,8 @@ operator_cast::fold_range (irange &r, tree type ATTRIBUTE_UNUSED, bool operator_cast::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { tree lhs_type = lhs.type (); gcc_checking_assert (types_compatible_p (op2.type(), type)); @@ -1954,20 +2206,24 @@ class operator_logical_and : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &lh, - const irange &rh) const; + const irange &rh, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel = VREL_NONE) const; } op_logical_and; bool operator_logical_and::fold_range (irange &r, tree type, const irange &lh, - const irange &rh) const + const irange &rh, + relation_kind rel ATTRIBUTE_UNUSED) const { if (empty_range_varying (r, type, lh, rh)) return true; @@ -1989,7 +2245,8 @@ operator_logical_and::fold_range (irange &r, tree type, bool operator_logical_and::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2 ATTRIBUTE_UNUSED) const + const irange &op2 ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const { switch (get_bool_state (r, lhs, type)) { @@ -2010,7 +2267,8 @@ operator_logical_and::op1_range (irange &r, tree type, bool operator_logical_and::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const { return operator_logical_and::op1_range (r, type, lhs, op1); } @@ -2021,13 +2279,16 @@ class operator_bitwise_and : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &lh, - const irange &rh) const; + const irange &rh, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel = VREL_NONE) const; virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, @@ -2106,7 +2367,8 @@ operator_bitwise_and::remove_impossible_ranges (irange &r, bool operator_bitwise_and::fold_range (irange &r, tree type, const irange &lh, - const irange &rh) const + const irange &rh, + relation_kind rel ATTRIBUTE_UNUSED) const { if (range_operator::fold_range (r, type, lh, rh)) { @@ -2397,7 +2659,8 @@ operator_bitwise_and::simple_op1_range_solver (irange &r, tree type, bool operator_bitwise_and::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { if (types_compatible_p (type, boolean_type_node)) return op_logical_and.op1_range (r, type, lhs, op2); @@ -2420,7 +2683,8 @@ operator_bitwise_and::op1_range (irange &r, tree type, bool operator_bitwise_and::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const { return operator_bitwise_and::op1_range (r, type, lhs, op1); } @@ -2431,19 +2695,23 @@ class operator_logical_or : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &lh, - const irange &rh) const; + const irange &rh, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel = VREL_NONE) const; } op_logical_or; bool operator_logical_or::fold_range (irange &r, tree type ATTRIBUTE_UNUSED, const irange &lh, - const irange &rh) const + const irange &rh, + relation_kind rel ATTRIBUTE_UNUSED) const { if (empty_range_varying (r, type, lh, rh)) return true; @@ -2456,7 +2724,8 @@ operator_logical_or::fold_range (irange &r, tree type ATTRIBUTE_UNUSED, bool operator_logical_or::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2 ATTRIBUTE_UNUSED) const + const irange &op2 ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const { switch (get_bool_state (r, lhs, type)) { @@ -2477,7 +2746,8 @@ operator_logical_or::op1_range (irange &r, tree type, bool operator_logical_or::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const { return operator_logical_or::op1_range (r, type, lhs, op1); } @@ -2488,10 +2758,12 @@ class operator_bitwise_or : public range_operator public: virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel= VREL_NONE) const; virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, @@ -2553,7 +2825,8 @@ operator_bitwise_or::wi_fold (irange &r, tree type, bool operator_bitwise_or::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { // If this is really a logical wi_fold, call that. if (types_compatible_p (type, boolean_type_node)) @@ -2572,7 +2845,8 @@ operator_bitwise_or::op1_range (irange &r, tree type, bool operator_bitwise_or::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const { return operator_bitwise_or::op1_range (r, type, lhs, op1); } @@ -2588,10 +2862,12 @@ public: const wide_int &rh_ub) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel = VREL_NONE) const; } op_bitwise_xor; void @@ -2628,7 +2904,8 @@ operator_bitwise_xor::wi_fold (irange &r, tree type, bool operator_bitwise_xor::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { if (lhs.undefined_p () || lhs.varying_p ()) { @@ -2662,7 +2939,8 @@ operator_bitwise_xor::op1_range (irange &r, tree type, bool operator_bitwise_xor::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const { return operator_bitwise_xor::op1_range (r, type, lhs, op1); } @@ -2677,10 +2955,12 @@ public: const wide_int &rh_ub) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const; } op_trunc_mod; void @@ -2730,7 +3010,8 @@ operator_trunc_mod::wi_fold (irange &r, tree type, bool operator_trunc_mod::op1_range (irange &r, tree type, const irange &lhs, - const irange &) const + const irange &, + relation_kind rel ATTRIBUTE_UNUSED) const { // PR 91029. signop sign = TYPE_SIGN (type); @@ -2753,7 +3034,8 @@ operator_trunc_mod::op1_range (irange &r, tree type, bool operator_trunc_mod::op2_range (irange &r, tree type, const irange &lhs, - const irange &) const + const irange &, + relation_kind rel ATTRIBUTE_UNUSED) const { // PR 91029. signop sign = TYPE_SIGN (type); @@ -2792,10 +3074,12 @@ class operator_logical_not : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &lh, - const irange &rh) const; + const irange &rh, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; } op_logical_not; // Folding a logical NOT, oddly enough, involves doing nothing on the @@ -2815,7 +3099,8 @@ public: bool operator_logical_not::fold_range (irange &r, tree type, const irange &lh, - const irange &rh ATTRIBUTE_UNUSED) const + const irange &rh ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const { if (empty_range_varying (r, type, lh, rh)) return true; @@ -2831,7 +3116,8 @@ bool operator_logical_not::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { // Logical NOT is involutary...do it again. return fold_range (r, type, lhs, op2); @@ -2843,16 +3129,19 @@ class operator_bitwise_not : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &lh, - const irange &rh) const; + const irange &rh, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; } op_bitwise_not; bool operator_bitwise_not::fold_range (irange &r, tree type, const irange &lh, - const irange &rh) const + const irange &rh, + relation_kind rel ATTRIBUTE_UNUSED) const { if (empty_range_varying (r, type, lh, rh)) return true; @@ -2870,7 +3159,8 @@ operator_bitwise_not::fold_range (irange &r, tree type, bool operator_bitwise_not::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { if (types_compatible_p (type, boolean_type_node)) return op_logical_not.op1_range (r, type, lhs, op2); @@ -2885,13 +3175,15 @@ class operator_cst : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; } op_integer_cst; bool operator_cst::fold_range (irange &r, tree type ATTRIBUTE_UNUSED, const irange &lh, - const irange &rh ATTRIBUTE_UNUSED) const + const irange &rh ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const { r = lh; return true; @@ -2903,16 +3195,19 @@ class operator_identity : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; } op_identity; bool operator_identity::fold_range (irange &r, tree type ATTRIBUTE_UNUSED, const irange &lh, - const irange &rh ATTRIBUTE_UNUSED) const + const irange &rh ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const { r = lh; return true; @@ -2921,7 +3216,8 @@ operator_identity::fold_range (irange &r, tree type ATTRIBUTE_UNUSED, bool operator_identity::op1_range (irange &r, tree type ATTRIBUTE_UNUSED, const irange &lhs, - const irange &op2 ATTRIBUTE_UNUSED) const + const irange &op2 ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const { r = lhs; return true; @@ -2933,13 +3229,15 @@ class operator_unknown : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; } op_unknown; bool operator_unknown::fold_range (irange &r, tree type, const irange &lh ATTRIBUTE_UNUSED, - const irange &rh ATTRIBUTE_UNUSED) const + const irange &rh ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const { r.set_varying (type); return true; @@ -2956,7 +3254,8 @@ class operator_abs : public range_operator const wide_int &rh_ub) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const; } op_abs; void @@ -3036,7 +3335,8 @@ operator_abs::wi_fold (irange &r, tree type, bool operator_abs::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { if (empty_range_varying (r, type, lhs, op2)) return true; @@ -3108,16 +3408,19 @@ class operator_negate : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; } op_negate; bool operator_negate::fold_range (irange &r, tree type, const irange &lh, - const irange &rh) const + const irange &rh, + relation_kind rel ATTRIBUTE_UNUSED) const { if (empty_range_varying (r, type, lh, rh)) return true; @@ -3130,7 +3433,8 @@ operator_negate::fold_range (irange &r, tree type, bool operator_negate::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { // NEGATE is involutory. return fold_range (r, type, lhs, op2); @@ -3142,16 +3446,19 @@ class operator_addr_expr : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; } op_addr; bool operator_addr_expr::fold_range (irange &r, tree type, const irange &lh, - const irange &rh) const + const irange &rh, + relation_kind rel ATTRIBUTE_UNUSED) const { if (empty_range_varying (r, type, lh, rh)) return true; @@ -3169,7 +3476,8 @@ operator_addr_expr::fold_range (irange &r, tree type, bool operator_addr_expr::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { return operator_addr_expr::fold_range (r, type, lhs, op2); } @@ -3288,10 +3596,12 @@ class pointer_or_operator : public range_operator public: virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel = VREL_NONE) const; virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const; @@ -3300,7 +3610,8 @@ public: bool pointer_or_operator::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2 ATTRIBUTE_UNUSED) const + const irange &op2 ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const { if (lhs.zero_p ()) { @@ -3315,7 +3626,8 @@ pointer_or_operator::op1_range (irange &r, tree type, bool pointer_or_operator::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const { return pointer_or_operator::op1_range (r, type, lhs, op1); } diff --git a/gcc/range-op.h b/gcc/range-op.h index d3d4408..2b5db64 100644 --- a/gcc/range-op.h +++ b/gcc/range-op.h @@ -52,7 +52,8 @@ public: // Perform an operation between 2 ranges and return it. virtual bool fold_range (irange &r, tree type, const irange &lh, - const irange &rh) const; + const irange &rh, + relation_kind rel = VREL_NONE) const; // Return the range for op[12] in the general case. LHS is the range for // the LHS of the expression, OP[12]is the range for the other @@ -67,11 +68,23 @@ public: // is re-formed as R = [LHS] - OP2. virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel = VREL_NONE) const; + // The following routines are used to represent relations between the + // various operations. If the caller knows where the symbolics are, + // it can query for relationships between them given known ranges. + virtual enum tree_code lhs_op1_relation (const irange &lhs, + const irange &op1, + const irange &op2) const; + virtual enum tree_code lhs_op2_relation (const irange &lhs, + const irange &op1, + const irange &op2) const; + virtual enum tree_code op1_op2_relation (const irange &lhs) const; protected: // Perform an integral operation between 2 sub-ranges and return it. virtual void wi_fold (irange &r, tree type, @@ -79,6 +92,11 @@ protected: const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const; + // Side effect of relation for generic fold_range clients. + virtual bool op1_op2_relation_effect (irange &lhs_range, tree type, + const irange &op1_range, + const irange &op2_range, + relation_kind rel) const; }; extern range_operator *range_op_handler (enum tree_code code, tree type); -- cgit v1.1 From a2c9173331914eff3d728c07afaeee71892689ba Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Thu, 17 Jun 2021 14:09:48 -0400 Subject: Add relational support to fold_using_range Enable a relation oracle in ranger, and add full range-op relation support to fold_using_range. * gimple-range-cache.cc (ranger_cache::ranger_cache): Create a relation_oracle if dominators exist. (ranger_cache::~ranger_cache): Dispose of oracle. (ranger_cache::dump_bb): Dump oracle. * gimple-range.cc (fur_source::fur_source): New. (fur_source::get_operand): Use mmeber query. (fur_source::get_phi_operand): Use member_query. (fur_source::query_relation): New. (fur_source::register_dependency): Delete. (fur_source::register_relation): New. (fur_edge::fur_edge): Adjust. (fur_edge::get_phi_operand): Fix comment. (fur_edge::query): Delete. (fur_stmt::fur_stmt): Adjust. (fur_stmt::query): Delete. (fur_depend::fur_depend): Adjust. (fur_depend::register_relation): New. (fur_depend::register_relation): New. (fur_list::fur_list): Adjust. (fur_list::get_operand): Use member query. (fold_using_range::range_of_range_op): Process and query relations. (fold_using_range::range_of_address): Adjust dependency call. (fold_using_range::range_of_phi): Ditto. (gimple_ranger::gimple_ranger): New. Use ranger_ache oracle. (fold_using_range::relation_fold_and_or): New. (fold_using_range::postfold_gcond_edges): New. * gimple-range.h (class gimple_ranger): Adjust. (class fur_source): Adjust members. (class fur_stmt): Ditto. (class fold_using_range): Ditto. --- gcc/gimple-range-cache.cc | 10 ++ gcc/gimple-range.cc | 355 ++++++++++++++++++++++++++++++++++++++-------- gcc/gimple-range.h | 22 ++- 3 files changed, 324 insertions(+), 63 deletions(-) (limited to 'gcc') diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc index def604dc..4347485 100644 --- a/gcc/gimple-range-cache.cc +++ b/gcc/gimple-range-cache.cc @@ -714,6 +714,12 @@ ranger_cache::ranger_cache () m_update_list.safe_grow_cleared (last_basic_block_for_fn (cfun)); m_update_list.truncate (0); m_temporal = new temporal_cache; + // If DOM info is available, spawn an oracle as well. + if (dom_info_available_p (CDI_DOMINATORS)) + m_oracle = new relation_oracle (); + else + m_oracle = NULL; + unsigned x, lim = last_basic_block_for_fn (cfun); // Calculate outgoing range info upfront. This will fully populate the // m_maybe_variant bitmap which will help eliminate processing of names @@ -728,6 +734,8 @@ ranger_cache::ranger_cache () ranger_cache::~ranger_cache () { + if (m_oracle) + delete m_oracle; delete m_temporal; m_workback.release (); m_update_list.release (); @@ -750,6 +758,8 @@ ranger_cache::dump_bb (FILE *f, basic_block bb) { m_gori.gori_map::dump (f, bb, false); m_on_entry.dump (f, bb); + if (m_oracle) + m_oracle->dump (f, bb); } // Get the global range for NAME, and return in R. Return false if the diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc index 0a2c72b..385cecf 100644 --- a/gcc/gimple-range.cc +++ b/gcc/gimple-range.cc @@ -47,14 +47,25 @@ along with GCC; see the file COPYING3. If not see #include "vr-values.h" #include "gimple-range.h" -// Evaluate expression EXPR using the source information the class was -// instantiated with. Place the result in R, and return TRUE. If a range -// cannot be calculated, return FALSE. +// Construct a fur_source, and set the m_query field. + +fur_source::fur_source (range_query *q) +{ + if (q) + m_query = q; + else if (cfun) + m_query = get_range_query (cfun); + else + m_query = get_global_range_query (); + m_gori = NULL; +} + +// Invoke range_of_expr on EXPR. bool fur_source::get_operand (irange &r, tree expr) { - return get_range_query (cfun)->range_of_expr (r, expr); + return m_query->range_of_expr (r, expr); } // Evaluate EXPR for this stmt as a PHI argument on edge E. Use the current @@ -63,23 +74,36 @@ fur_source::get_operand (irange &r, tree expr) bool fur_source::get_phi_operand (irange &r, tree expr, edge e) { - return get_range_query (cfun)->range_on_edge (r, e, expr); + return m_query->range_on_edge (r, e, expr); +} + +// Default is no relation. + +relation_kind +fur_source::query_relation (tree op1 ATTRIBUTE_UNUSED, + tree op2 ATTRIBUTE_UNUSED) +{ + return VREL_NONE; } -// Default is to not register any dependencies from fold_using_range. +// Default registers nothing. void -fur_source::register_dependency (tree lhs ATTRIBUTE_UNUSED, - tree rhs ATTRIBUTE_UNUSED) +fur_source::register_relation (gimple *s ATTRIBUTE_UNUSED, + relation_kind k ATTRIBUTE_UNUSED, + tree op1 ATTRIBUTE_UNUSED, + tree op2 ATTRIBUTE_UNUSED) { } -// Default object is the current range query. +// Default registers nothing. -range_query * -fur_source::query () +void +fur_source::register_relation (edge e ATTRIBUTE_UNUSED, + relation_kind k ATTRIBUTE_UNUSED, + tree op1 ATTRIBUTE_UNUSED, + tree op2 ATTRIBUTE_UNUSED) { - return get_range_query (cfun); } // This version of fur_source will pick a range up off an edge. @@ -90,22 +114,16 @@ public: fur_edge (edge e, range_query *q = NULL); virtual bool get_operand (irange &r, tree expr) OVERRIDE; virtual bool get_phi_operand (irange &r, tree expr, edge e) OVERRIDE; - virtual range_query *query () OVERRIDE; private: - range_query *m_query; edge m_edge; }; // Instantiate an edge based fur_source. inline -fur_edge::fur_edge (edge e, range_query *q) +fur_edge::fur_edge (edge e, range_query *q) : fur_source (q) { m_edge = e; - if (q) - m_query = q; - else - m_query = get_range_query (cfun); } // Get the value of EXPR on edge m_edge. @@ -122,31 +140,19 @@ fur_edge::get_operand (irange &r, tree expr) bool fur_edge::get_phi_operand (irange &r, tree expr, edge e) { - // edge to edge recalculations not supoprted yet, until we sort it out. + // Edge to edge recalculations not supoprted yet, until we sort it out. gcc_checking_assert (e == m_edge); return m_query->range_on_edge (r, e, expr); } -// Return the current range_query object. - -range_query * -fur_edge::query () -{ - return m_query; -} - // Instantiate a stmt based fur_source. -fur_stmt::fur_stmt (gimple *s, range_query *q) +fur_stmt::fur_stmt (gimple *s, range_query *q) : fur_source (q) { m_stmt = s; - if (q) - m_query = q; - else - m_query = get_global_range_query (); } -// Retrieve range of EXPR as it occurs as a use on stmt M_STMT. +// Retreive range of EXPR as it occurs as a use on stmt M_STMT. bool fur_stmt::get_operand (irange &r, tree expr) @@ -165,12 +171,12 @@ fur_stmt::get_phi_operand (irange &r, tree expr, edge e) return e_src.get_operand (r, expr); } -// Return the current range_query object. +// Return relation based from m_stmt. -range_query * -fur_stmt::query () +relation_kind +fur_stmt::query_relation (tree op1, tree op2) { - return m_query; + return m_query->query_relation (m_stmt, op1, op2); } // This version of fur_source will pick a range from a stmt, and also register @@ -180,12 +186,15 @@ class fur_depend : public fur_stmt { public: fur_depend (gimple *s, gori_compute *gori, range_query *q = NULL); - virtual void register_dependency (tree lhs, tree rhs) OVERRIDE; + virtual void register_relation (gimple *stmt, relation_kind k, tree op1, + tree op2) OVERRIDE; + virtual void register_relation (edge e, relation_kind k, tree op1, + tree op2) OVERRIDE; private: - gori_compute *m_gori; + relation_oracle *m_oracle; }; -// Instantiate a stmt based fur_source with a GORI object +// Instantiate a stmt based fur_source with a GORI object. inline fur_depend::fur_depend (gimple *s, gori_compute *gori, range_query *q) @@ -193,14 +202,28 @@ fur_depend::fur_depend (gimple *s, gori_compute *gori, range_query *q) { gcc_checking_assert (gori); m_gori = gori; + // Set relations if there is an oracle in the range_query. + // This will enable registering of relationships as they are discovered. + m_oracle = q->oracle (); + +} + +// Register a relation on a stmt if there is an oracle. + +void +fur_depend::register_relation (gimple *s, relation_kind k, tree op1, tree op2) +{ + if (m_oracle) + m_oracle->register_relation (s, k, op1, op2); } -// find and add any dependnecy between LHS and RHS +// Register a relation on an edge if there is an oracle. void -fur_depend::register_dependency (tree lhs, tree rhs) +fur_depend::register_relation (edge e, relation_kind k, tree op1, tree op2) { - m_gori->register_dependency (lhs, rhs); + if (m_oracle) + m_oracle->register_relation (e, k, op1, op2); } // This version of fur_source will pick a range up from a list of ranges @@ -223,7 +246,7 @@ private: // One range supplied for unary operations. -fur_list::fur_list (irange &r1) +fur_list::fur_list (irange &r1) : fur_source (NULL) { m_list = m_local; m_index = 0; @@ -233,7 +256,7 @@ fur_list::fur_list (irange &r1) // Two ranges supplied for binary operations. -fur_list::fur_list (irange &r1, irange &r2) +fur_list::fur_list (irange &r1, irange &r2) : fur_source (NULL) { m_list = m_local; m_index = 0; @@ -244,7 +267,7 @@ fur_list::fur_list (irange &r1, irange &r2) // Arbitrary number of ranges in a vector. -fur_list::fur_list (unsigned num, irange *list) +fur_list::fur_list (unsigned num, irange *list) : fur_source (NULL) { m_list = list; m_index = 0; @@ -257,7 +280,7 @@ bool fur_list::get_operand (irange &r, tree expr) { if (m_index >= m_limit) - return get_range_query (cfun)->range_of_expr (r, expr); + return m_query->range_of_expr (r, expr); r = m_list[m_index++]; gcc_checking_assert (range_compatible_p (TREE_TYPE (expr), r.type ())); return true; @@ -290,7 +313,6 @@ fold_range (irange &r, gimple *s, irange &r1, irange &r2) return f.fold_stmt (r, s, src); } - // Fold stmt S into range R using NUM_ELEMENTS from VECTOR as the initial // operands encountered. @@ -636,18 +658,50 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src) // Fold range, and register any dependency if available. int_range<2> r2 (type); handler->fold_range (r, type, range1, r2); - if (lhs) - src.register_dependency (lhs, op1); + if (lhs && gimple_range_ssa_p (op1)) + { + if (src.gori ()) + src.gori ()->register_dependency (lhs, op1); + relation_kind rel; + rel = handler->lhs_op1_relation (r, range1, range1); + if (rel != VREL_NONE) + src.register_relation (s, rel, lhs, op1); + } } else if (src.get_operand (range2, op2)) { + relation_kind rel = src.query_relation (op1, op2); + if (dump_file && (dump_flags & TDF_DETAILS) && rel != VREL_NONE) + { + fprintf (dump_file, " folding with relation "); + print_relation (dump_file, rel); + fputc ('\n', dump_file); + } // Fold range, and register any dependency if available. - handler->fold_range (r, type, range1, range2); + handler->fold_range (r, type, range1, range2, rel); + relation_fold_and_or (r, s, src); if (lhs) { - src.register_dependency (lhs, op1); - src.register_dependency (lhs, op2); + if (src.gori ()) + { + src.gori ()->register_dependency (lhs, op1); + src.gori ()->register_dependency (lhs, op2); + } + if (gimple_range_ssa_p (op1)) + { + rel = handler->lhs_op1_relation (r, range1, range2); + if (rel != VREL_NONE) + src.register_relation (s, rel, lhs, op1); + } + if (gimple_range_ssa_p (op2)) + { + rel= handler->lhs_op2_relation (r, range1, range2); + if (rel != VREL_NONE) + src.register_relation (s, rel, lhs, op2); + } } + else if (is_a (s)) + postfold_gcond_edges (as_a (s), src); } else r.set_varying (type); @@ -686,8 +740,8 @@ fold_using_range::range_of_address (irange &r, gimple *stmt, fur_source &src) { tree ssa = TREE_OPERAND (base, 0); tree lhs = gimple_get_lhs (stmt); - if (lhs && gimple_range_ssa_p (ssa)) - src.register_dependency (lhs, ssa); + if (lhs && gimple_range_ssa_p (ssa) && src.gori ()) + src.gori ()->register_dependency (lhs, ssa); gcc_checking_assert (irange::supports_type_p (TREE_TYPE (ssa))); src.get_operand (r, ssa); range_cast (r, TREE_TYPE (gimple_assign_rhs1 (stmt))); @@ -764,8 +818,8 @@ fold_using_range::range_of_phi (irange &r, gphi *phi, fur_source &src) edge e = gimple_phi_arg_edge (phi, x); // Register potential dependencies for stale value tracking. - if (gimple_range_ssa_p (arg)) - src.register_dependency (phi_def, arg); + if (gimple_range_ssa_p (arg) && src.gori ()) + src.gori ()->register_dependency (phi_def, arg); // Get the range of the argument on its edge. src.get_phi_operand (arg_range, arg, e); @@ -1149,6 +1203,12 @@ fold_using_range::range_of_cond_expr (irange &r, gassign *s, fur_source &src) return true; } +gimple_ranger::gimple_ranger () +{ + // If the cache has a relation oracle, use it. + m_oracle = m_cache.oracle (); +} + bool gimple_ranger::range_of_expr (irange &r, tree expr, gimple *stmt) { @@ -1464,6 +1524,185 @@ fold_using_range::range_of_ssa_name_with_loop_info (irange &r, tree name, r.set_varying (type); } +// ----------------------------------------------------------------------- + +// Check if an && or || expression can be folded based on relations. ie +// c_2 = a_6 > b_7 +// c_3 = a_6 < b_7 +// c_4 = c_2 && c_3 +// c_2 and c_3 can never be true at the same time, +// Therefore c_4 can always resolve to false based purely on the relations. + +void +fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s, + fur_source &src) +{ + // No queries or already folded. + if (!src.gori () || !src.query ()->oracle () || lhs_range.singleton_p ()) + return; + + // Only care about AND and OR expressions. + enum tree_code code = gimple_expr_code (s); + bool is_and = false; + if (code == BIT_AND_EXPR || code == TRUTH_AND_EXPR) + is_and = true; + else if (code != BIT_IOR_EXPR && code != TRUTH_OR_EXPR) + return; + + tree lhs = gimple_get_lhs (s); + tree ssa1 = gimple_range_ssa_p (gimple_range_operand1 (s)); + tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (s)); + + // Deal with || and && only when there is a full set of symbolics. + if (!lhs || !ssa1 || !ssa2 + || (TREE_CODE (TREE_TYPE (lhs)) != BOOLEAN_TYPE) + || (TREE_CODE (TREE_TYPE (ssa1)) != BOOLEAN_TYPE) + || (TREE_CODE (TREE_TYPE (ssa2)) != BOOLEAN_TYPE)) + return; + + // Now we know its a boolean AND or OR expression with boolean operands. + // Ideally we search dependencies for common names, and see what pops out. + // until then, simply try to resolve direct dependencies. + + // Both names will need to have 2 direct dependencies. + tree ssa1_dep2 = src.gori ()->depend2 (ssa1); + tree ssa2_dep2 = src.gori ()->depend2 (ssa2); + if (!ssa1_dep2 || !ssa2_dep2) + return; + + tree ssa1_dep1 = src.gori ()->depend1 (ssa1); + tree ssa2_dep1 = src.gori ()->depend1 (ssa2); + // Make sure they are the same dependencies, and detect the order of the + // relationship. + bool reverse_op2 = true; + if (ssa1_dep1 == ssa2_dep1 && ssa1_dep2 == ssa2_dep2) + reverse_op2 = false; + else if (ssa1_dep1 != ssa2_dep2 || ssa1_dep2 != ssa2_dep1) + return; + + range_operator *handler1 = gimple_range_handler (SSA_NAME_DEF_STMT (ssa1)); + range_operator *handler2 = gimple_range_handler (SSA_NAME_DEF_STMT (ssa2)); + + int_range<2> bool_one (boolean_true_node, boolean_true_node); + + relation_kind relation1 = handler1->op1_op2_relation (bool_one); + relation_kind relation2 = handler2->op1_op2_relation (bool_one); + if (relation1 == VREL_NONE || relation2 == VREL_NONE) + return; + + if (reverse_op2) + relation2 = relation_negate (relation2); + + // x && y is false if the relation intersection of the true cases is NULL. + if (is_and && relation_intersect (relation1, relation2) == VREL_EMPTY) + lhs_range = int_range<2> (boolean_false_node, boolean_false_node); + // x || y is true if the union of the true cases is NO-RELATION.. + // ie, one or the other being true covers the full range of possibilties. + else if (!is_and && relation_union (relation1, relation2) == VREL_NONE) + lhs_range = bool_one; + else + return; + + range_cast (lhs_range, TREE_TYPE (lhs)); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, " Relation adjustment: "); + print_generic_expr (dump_file, ssa1, TDF_SLIM); + fprintf (dump_file, " and "); + print_generic_expr (dump_file, ssa2, TDF_SLIM); + fprintf (dump_file, " combine to produce "); + lhs_range.dump (dump_file); + fputc ('\n', dump_file); + } + + return; +} + +// Register any outgoing edge relations from a conditional branch. + +void +fold_using_range::postfold_gcond_edges (gcond *s, fur_source &src) +{ + int_range_max r; + tree name; + range_operator *handler; + basic_block bb = gimple_bb (s); + + edge e0 = EDGE_SUCC (bb, 0); + if (!single_pred_p (e0->dest)) + e0 = NULL; + + edge e1 = EDGE_SUCC (bb, 1); + if (!single_pred_p (e1->dest)) + e1 = NULL; + + // At least one edge needs to be single pred. + if (!e0 && !e1) + return; + + // First, register the gcond itself. This will catch statements like + // if (a_2 < b_5) + tree ssa1 = gimple_range_ssa_p (gimple_range_operand1 (s)); + tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (s)); + if (ssa1 && ssa2) + { + handler = gimple_range_handler (s); + gcc_checking_assert (handler); + if (e0) + { + gcond_edge_range (r, e0); + relation_kind relation = handler->op1_op2_relation (r); + if (relation != VREL_NONE) + src.register_relation (e0, relation, ssa1, ssa2); + } + if (e1) + { + gcond_edge_range (r, e1); + relation_kind relation = handler->op1_op2_relation (r); + if (relation != VREL_NONE) + src.register_relation (e1, relation, ssa1, ssa2); + } + } + + // Outgoing relations of GORI exports require a gori engine. + if (!src.gori ()) + return; + + range_query *q = src.query (); + // Now look for other relations in the exports. This will find stmts + // leading to the condition such as: + // c_2 = a_4 < b_7 + // if (c_2) + + FOR_EACH_GORI_EXPORT_NAME (*(src.gori ()), bb, name) + { + if (TREE_CODE (TREE_TYPE (name)) != BOOLEAN_TYPE) + continue; + gimple *stmt = SSA_NAME_DEF_STMT (name); + handler = gimple_range_handler (stmt); + if (!handler) + continue; + tree ssa1 = gimple_range_ssa_p (gimple_range_operand1 (stmt)); + tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (stmt)); + if (ssa1 && ssa2) + { + if (e0 && src.gori ()->outgoing_edge_range_p (r, e0, name, *q) + && r.singleton_p ()) + { + relation_kind relation = handler->op1_op2_relation (r); + if (relation != VREL_NONE) + src.register_relation (e0, relation, ssa1, ssa2); + } + if (e1 && src.gori ()->outgoing_edge_range_p (r, e1, name, *q) + && r.singleton_p ()) + { + relation_kind relation = handler->op1_op2_relation (r); + if (relation != VREL_NONE) + src.register_relation (e1, relation, ssa1, ssa2); + } + } + } +} // -------------------------------------------------------------------------- // trace_ranger implementation. diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h index b9cffdb..87911b9 100644 --- a/gcc/gimple-range.h +++ b/gcc/gimple-range.h @@ -58,6 +58,7 @@ along with GCC; see the file COPYING3. If not see class gimple_ranger : public range_query { public: + gimple_ranger (); virtual bool range_of_stmt (irange &r, gimple *, tree name = NULL) OVERRIDE; virtual bool range_of_expr (irange &r, tree name, gimple * = NULL) OVERRIDE; virtual bool range_on_edge (irange &r, edge e, tree name) OVERRIDE; @@ -74,15 +75,25 @@ protected: // Source of all operands for fold_using_range and gori_compute. // It abstracts out the source of an operand so it can come from a stmt or -// and edge or anywhere a derived classof fur_source wants. +// and edge or anywhere a derived class of fur_source wants. +// THe default simply picks up ranges from the current range_query. class fur_source { public: + fur_source (range_query *q = NULL); + inline range_query *query () { return m_query; } + inline class gori_compute *gori () { return m_gori; }; virtual bool get_operand (irange &r, tree expr); virtual bool get_phi_operand (irange &r, tree expr, edge e); - virtual void register_dependency (tree lhs, tree rhs); - virtual range_query *query (); + virtual relation_kind query_relation (tree op1, tree op2); + virtual void register_relation (gimple *stmt, relation_kind k, tree op1, + tree op2); + virtual void register_relation (edge e, relation_kind k, tree op1, + tree op2); +protected: + range_query *m_query; + gori_compute *m_gori; }; // fur_stmt is the specification for drawing an operand from range_query Q @@ -94,9 +105,8 @@ public: fur_stmt (gimple *s, range_query *q = NULL); virtual bool get_operand (irange &r, tree expr) OVERRIDE; virtual bool get_phi_operand (irange &r, tree expr, edge e) OVERRIDE; - virtual range_query *query () OVERRIDE; + virtual relation_kind query_relation (tree op1, tree op2) OVERRIDE; private: - range_query *m_query; gimple *m_stmt; }; @@ -132,6 +142,8 @@ protected: bool range_of_phi (irange &r, gphi *phi, fur_source &src); void range_of_ssa_name_with_loop_info (irange &, tree, class loop *, gphi *, fur_source &src); + void relation_fold_and_or (irange& lhs_range, gimple *s, fur_source &src); + void postfold_gcond_edges (gcond *s, fur_source &src); }; -- cgit v1.1 From c526de3f432a037bdbdd44eb6fa43af4f3b22694 Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Thu, 17 Jun 2021 13:35:10 -0400 Subject: Add relations between LHS and op1/op2 for PLUS_EXPR. * range-op.cc (operator_plus::lhs_op1_relation): New. (operator_plus::lhs_op2_relation): New. --- gcc/range-op.cc | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) (limited to 'gcc') diff --git a/gcc/range-op.cc b/gcc/range-op.cc index d807693..a7698f2 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -1150,8 +1150,88 @@ public: const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const; + virtual enum tree_code lhs_op1_relation (const irange &lhs, const irange &op1, + const irange &op2) const; + virtual enum tree_code lhs_op2_relation (const irange &lhs, const irange &op1, + const irange &op2) const; } op_plus; +// Check to see if the range of OP2 indicates anything about the relation +// between LHS and OP1. + +enum tree_code +operator_plus::lhs_op1_relation (const irange &lhs, + const irange &op1, + const irange &op2) const +{ + if (lhs.undefined_p () || op1.undefined_p () || op2.undefined_p ()) + return VREL_NONE; + + tree type = lhs.type (); + unsigned prec = TYPE_PRECISION (type); + wi::overflow_type ovf1, ovf2; + signop sign = TYPE_SIGN (type); + + // LHS = OP1 + 0 indicates LHS == OP1. + if (op2.zero_p ()) + return EQ_EXPR; + + if (TYPE_OVERFLOW_WRAPS (type)) + { + wi::add (op1.lower_bound (), op2.lower_bound (), sign, &ovf1); + wi::add (op1.upper_bound (), op2.upper_bound (), sign, &ovf2); + } + else + ovf1 = ovf2 = wi::OVF_NONE; + + // Never wrapping additions. + if (!ovf1 && !ovf2) + { + // Positive op2 means lhs > op1. + if (wi::gt_p (op2.lower_bound (), wi::zero (prec), sign)) + return GT_EXPR; + if (wi::ge_p (op2.lower_bound (), wi::zero (prec), sign)) + return GE_EXPR; + + // Negative op2 means lhs < op1. + if (wi::lt_p (op2.upper_bound (), wi::zero (prec), sign)) + return LT_EXPR; + if (wi::le_p (op2.upper_bound (), wi::zero (prec), sign)) + return LE_EXPR; + } + // Always wrapping additions. + else if (ovf1 && ovf1 == ovf2) + { + // Positive op2 means lhs < op1. + if (wi::gt_p (op2.lower_bound (), wi::zero (prec), sign)) + return LT_EXPR; + if (wi::ge_p (op2.lower_bound (), wi::zero (prec), sign)) + return LE_EXPR; + + // Negative op2 means lhs > op1. + if (wi::lt_p (op2.upper_bound (), wi::zero (prec), sign)) + return GT_EXPR; + if (wi::le_p (op2.upper_bound (), wi::zero (prec), sign)) + return GE_EXPR; + } + + // If op2 does not contain 0, then LHS and OP1 can never be equal. + if (!range_includes_zero_p (&op2)) + return NE_EXPR; + + return VREL_NONE; +} + +// PLUS is symmetrical, so we can simply call lhs_op1_relation with reversed +// operands. + +enum tree_code +operator_plus::lhs_op2_relation (const irange &lhs, const irange &op1, + const irange &op2) const +{ + return lhs_op1_relation (lhs, op2, op1); +} + void operator_plus::wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, -- cgit v1.1 From ae6b830f31a47aca7ca24c4fea245c29214eef3a Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Thu, 17 Jun 2021 13:38:03 -0400 Subject: Add relation effects between operands to MINUS_EXPR. * range-op.cc (operator_minus::op1_op2_relation_effect): New. --- gcc/range-op.cc | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'gcc') diff --git a/gcc/range-op.cc b/gcc/range-op.cc index a7698f2..ec4816d 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -1279,6 +1279,11 @@ public: const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const; + virtual bool op1_op2_relation_effect (irange &lhs_range, + tree type, + const irange &op1_range, + const irange &op2_range, + relation_kind rel) const; } op_minus; void @@ -1293,6 +1298,45 @@ operator_minus::wi_fold (irange &r, tree type, value_range_with_overflow (r, type, new_lb, new_ub, ov_lb, ov_ub); } +// Check to see if the relation REL between OP1 and OP2 has any effect on the +// LHS of the epxression. If so, apply it to LHS_RANGE. + +bool +operator_minus::op1_op2_relation_effect (irange &lhs_range, tree type, + const irange &op1_range ATTRIBUTE_UNUSED, + const irange &op2_range ATTRIBUTE_UNUSED, + relation_kind rel) const +{ + if (rel == VREL_NONE) + return false; + + int_range<2> rel_range; + unsigned prec = TYPE_PRECISION (type); + signop sgn = TYPE_SIGN (type); + + switch (rel) + { + // op1 > op2, op1 - op2 can be restricted to [1, max] + case GT_EXPR: + rel_range = int_range<2> (type, wi::one (prec), + wi::max_value (prec, sgn)); + break; + // op1 >= op2, op1 - op2 can be restricted to [0, max] + case GE_EXPR: + rel_range = int_range<2> (type, wi::zero (prec), + wi::max_value (prec, sgn)); + break; + // op1 == op2, op1 - op2 can be restricted to [0, 0] + case EQ_EXPR: + rel_range = int_range<2> (type, wi::zero (prec), wi::zero (prec)); + break; + default: + return false; + } + lhs_range.intersect (rel_range); + return true; +} + bool operator_minus::op1_range (irange &r, tree type, const irange &lhs, -- cgit v1.1 From 0f7ccc063a42407f91fa52a54cc480950a45e75c Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Thu, 17 Jun 2021 13:39:02 -0400 Subject: Add relation between LHS and op1 for casts and copies. * range-op.cc (operator_cast::lhs_op1_relation): New. (operator_identity::lhs_op1_relation): Mew. --- gcc/range-op.cc | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'gcc') diff --git a/gcc/range-op.cc b/gcc/range-op.cc index ec4816d..92b314d 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -2115,6 +2115,10 @@ public: const irange &lhs, const irange &op2, relation_kind rel = VREL_NONE) const; + virtual enum tree_code lhs_op1_relation (const irange &lhs, + const irange &op1, + const irange &op2) const; + private: bool truncating_cast_p (const irange &inner, const irange &outer) const; bool inside_domain_p (const wide_int &min, const wide_int &max, @@ -2123,6 +2127,27 @@ private: const irange &outer) const; } op_convert; +// Determine if there is a relationship between LHS and OP1. + +enum tree_code +operator_cast::lhs_op1_relation (const irange &lhs, + const irange &op1, + const irange &op2 ATTRIBUTE_UNUSED) const +{ + if (op1.undefined_p ()) + return VREL_NONE; + // We can't make larger types equivalent to smaller types because we can + // miss sign extensions in a chain of casts. + // u32 = 0xfffff + // s32 = (s32) u32 + // s64 = (s64) s32 + // we cant simply "convert" s64 = (s64)u32 or we get positive 0xffff + // value instead of sign extended negative value. + if (TYPE_PRECISION (lhs.type ()) == TYPE_PRECISION (op1.type ())) + return EQ_EXPR; + return VREL_NONE; +} + // Return TRUE if casting from INNER to OUTER is a truncating cast. inline bool @@ -3325,8 +3350,24 @@ public: const irange &lhs, const irange &op2, relation_kind rel = VREL_NONE) const; + virtual enum tree_code lhs_op1_relation (const irange &lhs, + const irange &op1, + const irange &op2) const; } op_identity; +// Determine if there is a relationship between LHS and OP1. + +enum tree_code +operator_identity::lhs_op1_relation (const irange &lhs, + const irange &op1 ATTRIBUTE_UNUSED, + const irange &op2 ATTRIBUTE_UNUSED) const +{ + if (lhs.undefined_p ()) + return VREL_NONE; + // Simply a copy, so they are equivalent. + return EQ_EXPR; +} + bool operator_identity::fold_range (irange &r, tree type ATTRIBUTE_UNUSED, const irange &lh, -- cgit v1.1 From ca1f9f22854049d6f9cab5b4bfbc46edbcb5c990 Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Thu, 17 Jun 2021 13:40:05 -0400 Subject: Add relational self-tests. * range-op.cc (range_relational_tests): New. (range_op_tests): Call range_relational_tests. --- gcc/range-op.cc | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'gcc') diff --git a/gcc/range-op.cc b/gcc/range-op.cc index 92b314d..1692a09 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -4244,6 +4244,30 @@ range_op_bitwise_and_tests () ASSERT_FALSE (res.contains_p (INT (0))); } +static void +range_relational_tests () +{ + int_range<2> lhs (unsigned_char_type_node); + int_range<2> op1 (UCHAR (8), UCHAR (10)); + int_range<2> op2 (UCHAR (20), UCHAR (20)); + + // Never wrapping additions mean LHS > OP1. + tree_code code = op_plus.lhs_op1_relation (lhs, op1, op2); + ASSERT_TRUE (code == GT_EXPR); + + // Most wrapping additions mean nothing... + op1 = int_range<2> (UCHAR (8), UCHAR (10)); + op2 = int_range<2> (UCHAR (0), UCHAR (255)); + code = op_plus.lhs_op1_relation (lhs, op1, op2); + ASSERT_TRUE (code == VREL_NONE); + + // However, always wrapping additions mean LHS < OP1. + op1 = int_range<2> (UCHAR (1), UCHAR (255)); + op2 = int_range<2> (UCHAR (255), UCHAR (255)); + code = op_plus.lhs_op1_relation (lhs, op1, op2); + ASSERT_TRUE (code == LT_EXPR); +} + void range_op_tests () { @@ -4251,6 +4275,7 @@ range_op_tests () range_op_lshift_tests (); range_op_bitwise_and_tests (); range_op_cast_tests (); + range_relational_tests (); } } // namespace selftest -- cgit v1.1 From 92d9c9e705f039f42734139c233202888d2bf01b Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 22 Jun 2021 15:20:14 +0200 Subject: fold-const: Return corresponding integral type for OFFSET_TYPE in range_check_type [PR101162] Andrew's recent r12-1608-g2f1686ff70b25fceb04ca2ffc0a450fb682913ef change to fail verification on various unary and binary operations with OFFSET_TYPE revealed that e.g. switchconv happily performs multiplications and additions in OFFSET_TYPE. 2021-06-22 Jakub Jelinek Andrew Pinski PR tree-optimization/101162 * fold-const.c (range_check_type): Handle OFFSET_TYPE like pointer types. * g++.dg/opt/pr101162.C: New test. --- gcc/fold-const.c | 2 +- gcc/testsuite/g++.dg/opt/pr101162.C | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/opt/pr101162.C (limited to 'gcc') diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 95673d2..0b33ee9 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -5360,7 +5360,7 @@ range_check_type (tree etype) else return NULL_TREE; } - else if (POINTER_TYPE_P (etype)) + else if (POINTER_TYPE_P (etype) || TREE_CODE (etype) == OFFSET_TYPE) etype = unsigned_type_for (etype); return etype; } diff --git a/gcc/testsuite/g++.dg/opt/pr101162.C b/gcc/testsuite/g++.dg/opt/pr101162.C new file mode 100644 index 0000000..4032189 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/pr101162.C @@ -0,0 +1,21 @@ +// PR tree-optimization/101162 +// { dg-do compile } +// { dg-options "-O2" } + +struct A { int i1, i2, i3, i4, i5, i6; }; + +int A::* +foo (int i) +{ + switch (i) + { + case 1: return &A::i1; + case 2: return &A::i2; + case 3: return &A::i3; + case 4: return &A::i4; + case 5: return &A::i5; + case 6: return &A::i6; + } + + return 0; +} -- cgit v1.1 From 9b613e825d706b18f69e40edaee3eaf27d28f5cb Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 22 Jun 2021 15:21:35 +0200 Subject: expand: Fix up empty class return optimization [PR101160] On Mon, Jun 14, 2021 at 11:24:22PM -0400, Jason Merrill via Gcc-patches wrote: > The x86_64 psABI says that an empty class isn't passed or returned in memory or > registers, so we shouldn't set %eax in this function. Is this a reasonable > place to implement that? Another possibility would be to remove the hack to > prevent i386.c:function_value_64 from returning NULL in this case and fix the > callers to deal, but that seems like more work. > > The df-scan hunk catches the case where we look at a 0-length reg and build > a range the length of unsigned int, which happened before I changed > assign_parms to match expand_function_end. The assign_params change unfortunately breaks e.g. the following testcase. The problem is that some passes (e.g. subreg lowering but assign_parms comments also talk about delayed slot scheduling) rely on crtl->return_rtx not to contain pseudo registers, and the assign_parms change results in the pseudo in there not being replaced with a hard register. The following patch instead clears the crtl->return_rtx if a function returns TYPE_EMPTY_P structure, that way (use (pseudo)) is not emitted into the IL and it is treated like more like functions returning void. I've also changed the effective target on the empty-class1.C testcase, so that it doesn't fail on x86_64-linux with -m32 testing. 2021-06-22 Jakub Jelinek PR middle-end/101160 * function.c (assign_parms): For decl_result with TYPE_EMPTY_P type clear crtl->return_rtx instead of keeping it referencing a pseudo. * g++.target/i386/empty-class1.C: Require lp64 effective target instead of x86_64-*-*. * g++.target/i386/empty-class2.C: New test. --- gcc/function.c | 21 +++++++++++++-------- gcc/testsuite/g++.target/i386/empty-class1.C | 2 +- gcc/testsuite/g++.target/i386/empty-class2.C | 20 ++++++++++++++++++++ 3 files changed, 34 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/g++.target/i386/empty-class2.C (limited to 'gcc') diff --git a/gcc/function.c b/gcc/function.c index 6abaf3d..00b2fe7 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -3821,17 +3821,22 @@ assign_parms (tree fndecl) tree decl_result = DECL_RESULT (fndecl); rtx decl_rtl = DECL_RTL (decl_result); - if ((REG_P (decl_rtl) - ? REGNO (decl_rtl) >= FIRST_PSEUDO_REGISTER - : DECL_REGISTER (decl_result)) - /* Unless the psABI says not to. */ - && !TYPE_EMPTY_P (TREE_TYPE (decl_result))) + if (REG_P (decl_rtl) + ? REGNO (decl_rtl) >= FIRST_PSEUDO_REGISTER + : DECL_REGISTER (decl_result)) { rtx real_decl_rtl; - real_decl_rtl = targetm.calls.function_value (TREE_TYPE (decl_result), - fndecl, true); - REG_FUNCTION_VALUE_P (real_decl_rtl) = 1; + /* Unless the psABI says not to. */ + if (TYPE_EMPTY_P (TREE_TYPE (decl_result))) + real_decl_rtl = NULL_RTX; + else + { + real_decl_rtl + = targetm.calls.function_value (TREE_TYPE (decl_result), + fndecl, true); + REG_FUNCTION_VALUE_P (real_decl_rtl) = 1; + } /* The delay slot scheduler assumes that crtl->return_rtx holds the hard register containing the return value, not a temporary pseudo. */ diff --git a/gcc/testsuite/g++.target/i386/empty-class1.C b/gcc/testsuite/g++.target/i386/empty-class1.C index c199277..96a1fad 100644 --- a/gcc/testsuite/g++.target/i386/empty-class1.C +++ b/gcc/testsuite/g++.target/i386/empty-class1.C @@ -1,5 +1,5 @@ // PR target/88529 -// { dg-do compile { target { c++11 && x86_64-*-* } } } +// { dg-do compile { target { c++11 && lp64 } } } // { dg-additional-options -fdump-rtl-expand } // { dg-final { scan-rtl-dump-not "set" "expand" } } // The x86_64 psABI says that f() doesn't put the return value anywhere. diff --git a/gcc/testsuite/g++.target/i386/empty-class2.C b/gcc/testsuite/g++.target/i386/empty-class2.C new file mode 100644 index 0000000..b9317c5 --- /dev/null +++ b/gcc/testsuite/g++.target/i386/empty-class2.C @@ -0,0 +1,20 @@ +// PR middle-end/101160 +// Test passing aligned empty aggregate +// { dg-do compile } +// { dg-options "-O2" } +// { dg-additional-options "-Wno-psabi" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } + +struct S { union {} a; } __attribute__((aligned)); + +S +foo (S arg) +{ + return arg; +} + +void +bar (void) +{ + S arg; + foo (arg); +} -- cgit v1.1 From 3adb9ac6626c15ba21e4eaf27fec95688a3ca8c2 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 22 Jun 2021 15:22:51 +0200 Subject: testsuite: Add testcase for recently fixed PR [PR101159] On Tue, Jun 22, 2021 at 11:00:51AM +0200, Richard Biener wrote: > 2021-06-22 Richard Biener > > PR tree-optimization/101159 > * tree-vect-patterns.c (vect_recog_popcount_pattern): Add > missing NULL vectype check. The following patch adds the testcase for it, IMHO it can't hurt and from my experience testcases often trigger other bugs later on (rather than the original bugs reappearing, though even that happens), and also fixes a couple of typos in the new function. 2021-06-22 Jakub Jelinek PR tree-optimization/101159 * tree-vect-patterns.c (vect_recog_popcount_pattern): Fix some comment typos. * gcc.c-torture/compile/pr101159.c: New test. --- gcc/testsuite/gcc.c-torture/compile/pr101159.c | 10 ++++++++++ gcc/tree-vect-patterns.c | 8 ++++---- 2 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr101159.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.c-torture/compile/pr101159.c b/gcc/testsuite/gcc.c-torture/compile/pr101159.c new file mode 100644 index 0000000..81b2d2c --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr101159.c @@ -0,0 +1,10 @@ +/* PR tree-optimization/101159 */ + +unsigned long a; +long b; + +void +foo (void) +{ + a += __builtin_popcountl (b); +} diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c index d0a5c71..b2e7fc2 100644 --- a/gcc/tree-vect-patterns.c +++ b/gcc/tree-vect-patterns.c @@ -1300,7 +1300,7 @@ vect_recog_widen_minus_pattern (vec_info *vinfo, stmt_vec_info last_stmt_info, TYPE1 B; UTYPE2 temp_in; TYPE3 temp_out; - temp_in = (TYPE2)A; + temp_in = (UTYPE2)A; temp_out = __builtin_popcount{,l,ll} (temp_in); B = (TYPE1) temp_out; @@ -1372,8 +1372,8 @@ vect_recog_popcount_pattern (vec_info *vinfo, if (!rhs_origin) return NULL; - /* Input and outout of .POPCOUNT should be same-precision integer. - Also A should be unsigned or same presion as temp_in, + /* Input and output of .POPCOUNT should be same-precision integer. + Also A should be unsigned or same precision as temp_in, otherwise there would be sign_extend from A to temp_in. */ if (TYPE_PRECISION (unprom_diff.type) != TYPE_PRECISION (lhs_type) || (!TYPE_UNSIGNED (unprom_diff.type) @@ -1384,7 +1384,7 @@ vect_recog_popcount_pattern (vec_info *vinfo, vect_pattern_detected ("vec_regcog_popcount_pattern", popcount_stmt); vec_type = get_vectype_for_scalar_type (vinfo, lhs_type); - /* Do it only the backend existed popcount2. */ + /* Do it only if the backend has popcount2 pattern. */ if (!vec_type || !direct_internal_fn_supported_p (IFN_POPCOUNT, vec_type, OPTIMIZE_FOR_SPEED)) -- cgit v1.1 From b4e21c80462682c4e6e5e487fe87107b27f8b4bd Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Tue, 22 Jun 2021 12:13:44 +0200 Subject: middle-end/101156 - remove not working optimization in gimplification This removes a premature and not working optimization from the gimplifier. When gimplification is requested not to produce a SSA name we try to avoid generating a copy when we did so anyway but instead replace the LHS of its definition. But that only works in case there are no uses of the SSA name already which is something we cannot easily check, so the following removes said optimization. Statistics on the whole bootstrap shows we hit this optimization only for libiberty/cp-demangle.c and overall we have 21652112 gimplifications where just 240 copies are elided. Preserving the optimization would require scanning the original expression and the pre and post sequences for SSA names and uses, that seems excessive to avoid these 240 copies. 2021-06-22 Richard Biener PR middle-end/101156 * gimplify.c (gimplify_expr): Remove premature incorrect optimization. * gcc.dg/pr101156.c: New testcase. --- gcc/gimplify.c | 15 +-------------- gcc/testsuite/gcc.dg/pr101156.c | 8 ++++++++ 2 files changed, 9 insertions(+), 14 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pr101156.c (limited to 'gcc') diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 41bae9c..21e7a6c 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -15128,24 +15128,11 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, bool (*gimple_test_f) (tree), fallback_t fallback, bool allow_ssa) { - bool was_ssa_name_p = TREE_CODE (*expr_p) == SSA_NAME; enum gimplify_status ret = gimplify_expr (expr_p, pre_p, post_p, gimple_test_f, fallback); if (! allow_ssa && TREE_CODE (*expr_p) == SSA_NAME) - { - tree name = *expr_p; - if (was_ssa_name_p) - *expr_p = get_initialized_tmp_var (*expr_p, pre_p, NULL, false); - else - { - /* Avoid the extra copy if possible. */ - *expr_p = create_tmp_reg (TREE_TYPE (name)); - if (!gimple_nop_p (SSA_NAME_DEF_STMT (name))) - gimple_set_lhs (SSA_NAME_DEF_STMT (name), *expr_p); - release_ssa_name (name); - } - } + *expr_p = get_initialized_tmp_var (*expr_p, pre_p, NULL, false); return ret; } diff --git a/gcc/testsuite/gcc.dg/pr101156.c b/gcc/testsuite/gcc.dg/pr101156.c new file mode 100644 index 0000000..5c25bd7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr101156.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-fchecking" } */ + +struct S { int i; }; +void baz(struct S *p) +{ + __builtin_setjmp(p--); +} -- cgit v1.1 From 83bd60452df732a048de601c45e292a9ccec3514 Mon Sep 17 00:00:00 2001 From: Sergei Trofimovich Date: Mon, 21 Jun 2021 23:39:56 +0100 Subject: docs: drop unbalanced parenthesis in rtl.texi gcc/ChangeLog: * doc/rtl.texi: drop unbalanced parenthesis. --- gcc/doc/rtl.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi index 5af7113..e1e76a9 100644 --- a/gcc/doc/rtl.texi +++ b/gcc/doc/rtl.texi @@ -144,7 +144,7 @@ Currently, @file{rtl.def} defines these classes: @item RTX_OBJ An RTX code that represents an actual object, such as a register (@code{REG}) or a memory location (@code{MEM}, @code{SYMBOL_REF}). -@code{LO_SUM}) is also included; instead, @code{SUBREG} and +@code{LO_SUM} is also included; instead, @code{SUBREG} and @code{STRICT_LOW_PART} are not in this class, but in class @code{RTX_EXTRA}. -- cgit v1.1 From ea4e32181d7a36055b57421abd0ced4735654cf6 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Tue, 22 Jun 2021 13:44:57 -0400 Subject: analyzer: fix ICE on malloc/alloca param type mismatch [PR101143] gcc/analyzer/ChangeLog: PR analyzer/101143 * region-model.cc (compat_types_p): New function. (region_model::create_region_for_heap_alloc): Convert assertion to an error check. (region_model::create_region_for_alloca): Likewise. gcc/testsuite/ChangeLog: PR analyzer/101143 * gcc.dg/analyzer/pr101143.c: New test. Signed-off-by: David Malcolm --- gcc/analyzer/region-model.cc | 19 +++++++++++++++---- gcc/testsuite/gcc.dg/analyzer/pr101143.c | 18 ++++++++++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/analyzer/pr101143.c (limited to 'gcc') diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index 462fe6d..ee11e82 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -1443,6 +1443,17 @@ assert_compat_types (tree src_type, tree dst_type) } } +/* Return true if SRC_TYPE can be converted to DST_TYPE as a no-op. */ + +static bool +compat_types_p (tree src_type, tree dst_type) +{ + if (src_type && dst_type && !VOID_TYPE_P (dst_type)) + if (!(useless_type_conversion_p (src_type, dst_type))) + return false; + return true; +} + /* Get the region for PV within this region_model, emitting any diagnostics to CTXT. */ @@ -3402,8 +3413,8 @@ const region * region_model::create_region_for_heap_alloc (const svalue *size_in_bytes) { const region *reg = m_mgr->create_region_for_heap_alloc (); - assert_compat_types (size_in_bytes->get_type (), size_type_node); - set_dynamic_extents (reg, size_in_bytes); + if (compat_types_p (size_in_bytes->get_type (), size_type_node)) + set_dynamic_extents (reg, size_in_bytes); return reg; } @@ -3414,8 +3425,8 @@ const region * region_model::create_region_for_alloca (const svalue *size_in_bytes) { const region *reg = m_mgr->create_region_for_alloca (m_current_frame); - assert_compat_types (size_in_bytes->get_type (), size_type_node); - set_dynamic_extents (reg, size_in_bytes); + if (compat_types_p (size_in_bytes->get_type (), size_type_node)) + set_dynamic_extents (reg, size_in_bytes); return reg; } diff --git a/gcc/testsuite/gcc.dg/analyzer/pr101143.c b/gcc/testsuite/gcc.dg/analyzer/pr101143.c new file mode 100644 index 0000000..bcc0974 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/pr101143.c @@ -0,0 +1,18 @@ +/* { dg-additional-options "-Wno-builtin-declaration-mismatch" } */ + +extern void *malloc (unsigned int); +extern void *alloca (unsigned int); +extern void unknown_fn (void *); + +void * +test_malloc (void) +{ + return malloc (sizeof (int)); +} + +void * +test_alloca (void) +{ + void *p = alloca (sizeof (int)); + unknown_fn (p); +} -- cgit v1.1 From f61e5d4d8b6d4cfa96863187fa61b8c6b057a491 Mon Sep 17 00:00:00 2001 From: Sandra Loosemore Date: Tue, 22 Jun 2021 12:42:17 -0700 Subject: Fortran: fix sm computation in CFI_allocate [PR93524] This patch fixes a bug in setting the step multiplier field in the C descriptor for array dimensions > 2. 2021-06-21 Sandra Loosemore Tobias Burnus libgfortran/ PR fortran/93524 * runtime/ISO_Fortran_binding.c (CFI_allocate): Fix sm computation. gcc/testsuite/ PR fortran/93524 * gfortran.dg/pr93524.c: New. * gfortran.dg/pr93524.f90: New. --- gcc/testsuite/gfortran.dg/pr93524.c | 33 +++++++++++++++++++++++++++++++++ gcc/testsuite/gfortran.dg/pr93524.f90 | 17 +++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 gcc/testsuite/gfortran.dg/pr93524.c create mode 100644 gcc/testsuite/gfortran.dg/pr93524.f90 (limited to 'gcc') diff --git a/gcc/testsuite/gfortran.dg/pr93524.c b/gcc/testsuite/gfortran.dg/pr93524.c new file mode 100644 index 0000000..24e5e09 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr93524.c @@ -0,0 +1,33 @@ +/* Test the fix for PR93524, in which CFI_allocate was computing + sm incorrectly for dimensions > 2. */ + +#include // For size_t +#include "../../../libgfortran/ISO_Fortran_binding.h" + +void my_fortran_sub_1 (CFI_cdesc_t *dv); +void my_fortran_sub_2 (CFI_cdesc_t *dv); + +int main () +{ + CFI_CDESC_T (3) a; + CFI_cdesc_t *dv = (CFI_cdesc_t *) &a; + // dv, base_addr, attribute, type, elem_len, rank, extents + CFI_establish (dv, NULL, CFI_attribute_allocatable, CFI_type_float, 0, 3, NULL); + + if (dv->base_addr != NULL) + return 1; // shall not be allocated + + CFI_index_t lower_bounds[] = {-10, 0, 3}; + CFI_index_t upper_bounds[] = {10, 5, 10}; + size_t elem_len = 0; // only needed for strings + if (CFI_SUCCESS != CFI_allocate (dv, lower_bounds, upper_bounds, elem_len)) + return 2; + + if (!CFI_is_contiguous (dv)) + return 2; // allocatables shall be contiguous,unless a strided section is used + + my_fortran_sub_1 (dv); + my_fortran_sub_2 (dv); + CFI_deallocate (dv); + return 0; +} diff --git a/gcc/testsuite/gfortran.dg/pr93524.f90 b/gcc/testsuite/gfortran.dg/pr93524.f90 new file mode 100644 index 0000000..0cebc8f --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr93524.f90 @@ -0,0 +1,17 @@ +! { dg-additional-sources pr93524.c } +! { dg-do run } +! +! Test the fix for PR93524. The main program is in pr93524.c. + +subroutine my_fortran_sub_1 (A) bind(C) + real :: A(:, :, :) + if (any (lbound(A) /= 1)) stop 1 + if (any (ubound(A) /= [21,6,8])) stop 2 + if (.not. is_contiguous (A)) stop 3 +end +subroutine my_fortran_sub_2 (A) bind(C) + real, ALLOCATABLE :: A(:, :, :) + if (any (lbound(A) /= [-10,0,3])) stop 1 + if (any (ubound(A) /= [10,5,10])) stop 2 + if (.not. is_contiguous (A)) stop 3 +end subroutine my_fortran_sub_2 -- cgit v1.1 From 419af06a35933fb1bb7c87fe9c7306755afce9a0 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 23 Jun 2021 00:16:28 +0000 Subject: Daily bump. --- gcc/ChangeLog | 193 ++++++++++++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/analyzer/ChangeLog | 8 ++ gcc/testsuite/ChangeLog | 87 ++++++++++++++++++++++ 4 files changed, 289 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5e73922..502a814 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,196 @@ +2021-06-22 Sergei Trofimovich + + * doc/rtl.texi: drop unbalanced parenthesis. + +2021-06-22 Richard Biener + + PR middle-end/101156 + * gimplify.c (gimplify_expr): Remove premature incorrect + optimization. + +2021-06-22 Jakub Jelinek + + PR tree-optimization/101159 + * tree-vect-patterns.c (vect_recog_popcount_pattern): Fix some + comment typos. + +2021-06-22 Jakub Jelinek + + PR middle-end/101160 + * function.c (assign_parms): For decl_result with TYPE_EMPTY_P type + clear crtl->return_rtx instead of keeping it referencing a pseudo. + +2021-06-22 Jakub Jelinek + Andrew Pinski + + PR tree-optimization/101162 + * fold-const.c (range_check_type): Handle OFFSET_TYPE like pointer + types. + +2021-06-22 Andrew MacLeod + + * range-op.cc (range_relational_tests): New. + (range_op_tests): Call range_relational_tests. + +2021-06-22 Andrew MacLeod + + * range-op.cc (operator_cast::lhs_op1_relation): New. + (operator_identity::lhs_op1_relation): Mew. + +2021-06-22 Andrew MacLeod + + * range-op.cc (operator_minus::op1_op2_relation_effect): New. + +2021-06-22 Andrew MacLeod + + * range-op.cc (operator_plus::lhs_op1_relation): New. + (operator_plus::lhs_op2_relation): New. + +2021-06-22 Andrew MacLeod + + * gimple-range-cache.cc (ranger_cache::ranger_cache): Create a + relation_oracle if dominators exist. + (ranger_cache::~ranger_cache): Dispose of oracle. + (ranger_cache::dump_bb): Dump oracle. + * gimple-range.cc (fur_source::fur_source): New. + (fur_source::get_operand): Use mmeber query. + (fur_source::get_phi_operand): Use member_query. + (fur_source::query_relation): New. + (fur_source::register_dependency): Delete. + (fur_source::register_relation): New. + (fur_edge::fur_edge): Adjust. + (fur_edge::get_phi_operand): Fix comment. + (fur_edge::query): Delete. + (fur_stmt::fur_stmt): Adjust. + (fur_stmt::query): Delete. + (fur_depend::fur_depend): Adjust. + (fur_depend::register_relation): New. + (fur_depend::register_relation): New. + (fur_list::fur_list): Adjust. + (fur_list::get_operand): Use member query. + (fold_using_range::range_of_range_op): Process and query relations. + (fold_using_range::range_of_address): Adjust dependency call. + (fold_using_range::range_of_phi): Ditto. + (gimple_ranger::gimple_ranger): New. Use ranger_ache oracle. + (fold_using_range::relation_fold_and_or): New. + (fold_using_range::postfold_gcond_edges): New. + * gimple-range.h (class gimple_ranger): Adjust. + (class fur_source): Adjust members. + (class fur_stmt): Ditto. + (class fold_using_range): Ditto. + +2021-06-22 Andrew MacLeod + + * range-op.cc (range_operator::wi_fold): Apply relation effect. + (range_operator::fold_range): Adjust and apply relation effect. + (*::fold_range): Add relation parameters. + (*::op1_range): Ditto. + (*::op2_range): Ditto. + (range_operator::lhs_op1_relation): New. + (range_operator::lhs_op2_relation): New. + (range_operator::op1_op2_relation): New. + (range_operator::op1_op2_relation_effect): New. + (relop_early_resolve): New. + (operator_equal::op1_op2_relation): New. + (operator_equal::fold_range): Call relop_early_resolve. + (operator_not_equal::op1_op2_relation): New. + (operator_not_equal::fold_range): Call relop_early_resolve. + (operator_lt::op1_op2_relation): New. + (operator_lt::fold_range): Call relop_early_resolve. + (operator_le::op1_op2_relation): New. + (operator_le::fold_range): Call relop_early_resolve. + (operator_gt::op1_op2_relation): New. + (operator_gt::fold_range): Call relop_early_resolve. + (operator_ge::op1_op2_relation): New. + (operator_ge::fold_range): Call relop_early_resolve. + * range-op.h (class range_operator): Adjust parameters and methods. + +2021-06-22 Andrew MacLeod + + * Makefile.in (OBJS): Add value-relation.o. + * gimple-range.h: Adjust include files. + * tree-data-ref.c: Adjust include file order. + * value-query.cc (range_query::get_value_range): Default to no oracle. + (range_query::query_relation): New. + (range_query::query_relation): New. + * value-query.h (class range_query): Adjust. + * value-relation.cc: New. + * value-relation.h: New. + +2021-06-22 Richard Biener + + PR tree-optimization/101151 + * tree-ssa-sink.c (statement_sink_location): Expand irreducible + region check. + +2021-06-22 Jojo R + + * config/riscv/riscv.c (thead_c906_tune_info): New. + (riscv_tune_info_table): Use new tune. + +2021-06-22 Richard Biener + + PR tree-optimization/101158 + * tree-vect-slp.c (vect_build_slp_tree_1): Move same operand + checking after checking for matching operation. + +2021-06-22 Richard Biener + + PR tree-optimization/101159 + * tree-vect-patterns.c (vect_recog_popcount_pattern): Add + missing NULL vectype check. + +2021-06-22 Richard Biener + + PR tree-optimization/101154 + * tree-vect-slp.c (vect_build_slp_tree_2): Fix out-of-bound access. + +2021-06-22 Jakub Jelinek + + PR target/11877 + * config/i386/i386-protos.h (ix86_last_zero_store_uid): Declare. + * config/i386/i386-expand.c (ix86_last_zero_store_uid): New variable. + * config/i386/i386.c (ix86_expand_prologue): Clear it. + * config/i386/i386.md (peephole2s for 1/2/4 stores of const0_rtx): + Remove "" from match_operand. Emit new insns using emit_move_insn and + set ix86_last_zero_store_uid to INSN_UID of the last store. + Add peephole2s for 1/2/4 stores of const0_rtx following previous + successful peep2s. + +2021-06-22 Martin Liska + + * auto-profile.c (AUTO_PROFILE_VERSION): Bump as string format + was changed. + +2021-06-22 Martin Liska + + * gcov-io.h: Remove padding entries. + +2021-06-22 liuhongt + + PR tree-optimization/97770 + * tree-vect-patterns.c (vect_recog_popcount_pattern): + New. + (vect_recog_func vect_vect_recog_func_ptrs): Add new pattern. + +2021-06-22 liuhongt + + PR target/100267 + * config/i386/i386-builtin.def (BDESC): Adjust builtin name. + * config/i386/sse.md (_expand_mask): Rename to .. + (expand_mask): this .. + (*expand_mask): New pre_reload splitter to transform + v{,p}expand* to vmov* when mask is zero, all ones, or has all + ones in it's lower part, otherwise still generate + v{,p}expand*. + +2021-06-22 liuhongt + + PR target/100310 + * config/i386/i386-expand.c + (ix86_expand_special_args_builtin): Keep constm1_operand only + if it satisfies insn's operand predicate. + 2021-06-21 Jason Merrill PR target/88529 diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index bb14796..e8c8a9f 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20210622 +20210623 diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog index 84fa208..3630b2e 100644 --- a/gcc/analyzer/ChangeLog +++ b/gcc/analyzer/ChangeLog @@ -1,3 +1,11 @@ +2021-06-22 David Malcolm + + PR analyzer/101143 + * region-model.cc (compat_types_p): New function. + (region_model::create_region_for_heap_alloc): Convert assertion to + an error check. + (region_model::create_region_for_alloca): Likewise. + 2021-06-18 David Malcolm * store.cc (binding_cluster::get_any_binding): Make symbolic reads diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 3b11dcf..b2de840 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,90 @@ +2021-06-22 Sandra Loosemore + Tobias Burnus + + PR fortran/93524 + * gfortran.dg/pr93524.c: New. + * gfortran.dg/pr93524.f90: New. + +2021-06-22 David Malcolm + + PR analyzer/101143 + * gcc.dg/analyzer/pr101143.c: New test. + +2021-06-22 Richard Biener + + PR middle-end/101156 + * gcc.dg/pr101156.c: New testcase. + +2021-06-22 Jakub Jelinek + + PR tree-optimization/101159 + * gcc.c-torture/compile/pr101159.c: New test. + +2021-06-22 Jakub Jelinek + + PR middle-end/101160 + * g++.target/i386/empty-class1.C: Require lp64 effective target + instead of x86_64-*-*. + * g++.target/i386/empty-class2.C: New test. + +2021-06-22 Jakub Jelinek + Andrew Pinski + + PR tree-optimization/101162 + * g++.dg/opt/pr101162.C: New test. + +2021-06-22 Richard Biener + + PR tree-optimization/101151 + * gcc.dg/torture/pr101151.c: New testcase. + +2021-06-22 Kito Cheng + + * g++.dg/modules/omp-1_a.C: Check pthread is available for + dg-module-cmi. + * g++.dg/modules/omp-2_a.C: Ditto. + +2021-06-22 Richard Biener + + PR tree-optimization/101158 + * gfortran.dg/pr101158.f90: New testcase. + +2021-06-22 Jakub Jelinek + + PR target/11877 + * gcc.target/i386/pr11877-2.c: New test. + +2021-06-22 liuhongt + + PR tree-optimization/97770 + * gcc.target/i386/avx512bitalg-pr97770-1.c: Remove xfail. + * gcc.target/i386/avx512vpopcntdq-pr97770-1.c: Remove xfail. + +2021-06-22 liuhongt + + PR target/100267 + * gcc.target/i386/avx512bw-pr100267-1.c: New test. + * gcc.target/i386/avx512bw-pr100267-b-2.c: New test. + * gcc.target/i386/avx512bw-pr100267-d-2.c: New test. + * gcc.target/i386/avx512bw-pr100267-q-2.c: New test. + * gcc.target/i386/avx512bw-pr100267-w-2.c: New test. + * gcc.target/i386/avx512f-pr100267-1.c: New test. + * gcc.target/i386/avx512f-pr100267-pd-2.c: New test. + * gcc.target/i386/avx512f-pr100267-ps-2.c: New test. + * gcc.target/i386/avx512vl-pr100267-1.c: New test. + * gcc.target/i386/avx512vl-pr100267-pd-2.c: New test. + * gcc.target/i386/avx512vl-pr100267-ps-2.c: New test. + * gcc.target/i386/avx512vlbw-pr100267-1.c: New test. + * gcc.target/i386/avx512vlbw-pr100267-b-2.c: New test. + * gcc.target/i386/avx512vlbw-pr100267-d-2.c: New test. + * gcc.target/i386/avx512vlbw-pr100267-q-2.c: New test. + * gcc.target/i386/avx512vlbw-pr100267-w-2.c: New test. + +2021-06-22 liuhongt + + PR target/100310 + * gcc.target/i386/pr100310.c: New test. + 2021-06-21 Jason Merrill PR target/88529 -- cgit v1.1