Re: Re: [PATCH v2 1/1] [RISC-V] Add support for _Bfloat16

2024-05-04 Thread Xiao Zeng
2024-05-04 23:23  Jeff Law  wrote:
>
 
>
>
>On 4/2/24 3:22 AM, Xiao Zeng wrote:
>> 1 At point ,
>>    BF16 has already been completed "post public review".
>>
>> 2 LLVM has also added support for RISCV BF16 in
>>  and
>> .
>>
>> 3 According to the discussion 
>> ,
>>    this use __bf16 and use DF16b in riscv_mangle_type like x86.
>>
>> Below test are passed for this patch
>>  * The riscv fully regression test.
>>
>> gcc/ChangeLog:
>>
>> * config/riscv/iterators.md: New mode iterator HFBF.
>> * config/riscv/riscv-builtins.cc (riscv_init_builtin_types):
>> Initialize data type _Bfloat16.
>> * config/riscv/riscv-modes.def (FLOAT_MODE): New.
>> (ADJUST_FLOAT_FORMAT): New.
>> * config/riscv/riscv.cc (riscv_mangle_type): Support for BFmode.
>> (riscv_scalar_mode_supported_p): Ditto.
>> (riscv_libgcc_floating_mode_supported_p): Ditto.
>> (riscv_init_libfuncs): Set the conversion method for BFmode and
>> HFmode.
>> (riscv_block_arith_comp_libfuncs_for_mode): Set the arithmetic
>> and comparison libfuncs for the mode.
>> * config/riscv/riscv.md (mode" ): Add BF.
>> (movhf): Support for BFmode.
>> (mov): Ditto.
>> (*movhf_softfloat): Ditto.
>> (*mov_softfloat): Ditto.
>>
>> libgcc/ChangeLog:
>>
>> * config/riscv/sfp-machine.h (_FP_NANFRAC_B): New.
>> (_FP_NANSIGN_B): Ditto.
>> * config/riscv/t-softfp32: Add support for BF16 libfuncs.
>> * config/riscv/t-softfp64: Ditto.
>> * soft-fp/floatsibf.c: For si -> bf16.
>> * soft-fp/floatunsibf.c: For unsi -> bf16.
>>
>> gcc/testsuite/ChangeLog:
>>
>> * gcc.target/riscv/bf16_arithmetic.c: New test.
>> * gcc.target/riscv/bf16_call.c: New test.
>> * gcc.target/riscv/bf16_comparison.c: New test.
>> * gcc.target/riscv/bf16_float_libcall_convert.c: New test.
>> * gcc.target/riscv/bf16_integer_libcall_convert.c: New test.
>Just some nits.  In t-softfp32 and t-softfp64 the code you've added
>should be using tabs, not 8 spaces, as noted by the CI "Lint Status":
>
>https://github.com/ewlu/gcc-precommit-ci/issues/1412#issuecomment-2031568644
In the future, my patch will strictly adhere to the formatting suggestions 
provided by CI.

>
>With that fixed, this is fine for the trunk.  No need to repost, 
>go ahead and commit.
Currently, I do not have commit permission. Can I have this permission?

>
>Thanks for your patience,
>Jeff
 
Thanks
Xiao Zeng



[RFA][RISC-V] Use "uw" forms for constant synthesis

2024-05-04 Thread Jeff Law


So another constant synthesis improvement.

In this patch we're looking at cases where we'd like to be able to use 
lui+slli, but can't because of the sign extending nature of lui on 
TARGET_64BIT.  For example: 0x800110020UL.  The trunk currently 
generates 4 instructions for that constant, when it can be done with 3 
(lui+slli.uw+addi).


When Zba is enabled, we can use lui+slli.uw as the slli.uw masks off the 
bits 32..63 before shifting, giving us the precise semantics we want.


I strongly suspect we'll want to do the same for a set of constants with 
lui+add.uw, lui+shNadd.uw, so you'll see the beginnings of generalizing 
support for lui followed by a "uw" instruction.


The new test just tests the set of cases that showed up while exploring 
a particular space of the constant synthesis problem.  It's not meant to 
be exhaustive (failure to use shadd when profitable).


Tested on rv64gc and rv32gcv.  OK for the trunk assuming it passes CI?

Jeff


gcc/

* config/riscv/riscv.cc (riscv_integer_op): Add field tracking if we
want to use a "uw" instruction variant.
(riscv_build_integer_1): Initialize the new field in various places.
Use lui+slli.uw for some constants.
(riscv_move_integer): Handle slli.uw.  

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 44945d47fd6..fd81f69e230 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -249,6 +249,7 @@ struct riscv_arg_info {
where A is an accumulator, each CODE[i] is a binary rtl operation
and each VALUE[i] is a constant integer.  CODE[0] is undefined.  */
 struct riscv_integer_op {
+  bool use_uw;
   enum rtx_code code;
   unsigned HOST_WIDE_INT value;
 };
@@ -734,6 +735,7 @@ riscv_build_integer_1 (struct riscv_integer_op 
codes[RISCV_MAX_INTEGER_OPS],
   /* Simply ADDI or LUI.  */
   codes[0].code = UNKNOWN;
   codes[0].value = value;
+  codes[0].use_uw = false;
   return 1;
 }
   if (TARGET_ZBS && SINGLE_BIT_MASK_OPERAND (value))
@@ -741,6 +743,7 @@ riscv_build_integer_1 (struct riscv_integer_op 
codes[RISCV_MAX_INTEGER_OPS],
   /* Simply BSETI.  */
   codes[0].code = UNKNOWN;
   codes[0].value = value;
+  codes[0].use_uw = false;
 
   /* RISC-V sign-extends all 32bit values that live in a 32bit
 register.  To avoid paradoxes, we thus need to use the
@@ -769,6 +772,7 @@ riscv_build_integer_1 (struct riscv_integer_op 
codes[RISCV_MAX_INTEGER_OPS],
{
  alt_codes[alt_cost-1].code = PLUS;
  alt_codes[alt_cost-1].value = low_part;
+ alt_codes[alt_cost-1].use_uw = false;
  memcpy (codes, alt_codes, sizeof (alt_codes));
  cost = alt_cost;
}
@@ -782,6 +786,7 @@ riscv_build_integer_1 (struct riscv_integer_op 
codes[RISCV_MAX_INTEGER_OPS],
{
  alt_codes[alt_cost-1].code = XOR;
  alt_codes[alt_cost-1].value = low_part;
+ alt_codes[alt_cost-1].use_uw = false;
  memcpy (codes, alt_codes, sizeof (alt_codes));
  cost = alt_cost;
}
@@ -792,17 +797,37 @@ riscv_build_integer_1 (struct riscv_integer_op 
codes[RISCV_MAX_INTEGER_OPS],
 {
   int shift = ctz_hwi (value);
   unsigned HOST_WIDE_INT x = value;
+  bool use_uw = false;
   x = sext_hwi (x >> shift, HOST_BITS_PER_WIDE_INT - shift);
 
   /* Don't eliminate the lower 12 bits if LUI might apply.  */
-  if (shift > IMM_BITS && !SMALL_OPERAND (x) && LUI_OPERAND (x << 
IMM_BITS))
+  if (shift > IMM_BITS
+ && !SMALL_OPERAND (x)
+ && (LUI_OPERAND (x << IMM_BITS)
+ || (TARGET_64BIT
+ && TARGET_ZBA
+ && LUI_OPERAND ((x << IMM_BITS)
+ & ~HOST_WIDE_INT_C (0x8000)
shift -= IMM_BITS, x <<= IMM_BITS;
 
+  /* Adjust X if it isn't a LUI operand in isolation, but we can use
+a subsequent "uw" instruction form to mask off the undesirable
+bits.  */
+  if (!LUI_OPERAND (x)
+ && TARGET_64BIT
+ && TARGET_ZBA
+ && LUI_OPERAND (x & ~HOST_WIDE_INT_C (0x8000UL)))
+   {
+ x = sext_hwi (x, 32);
+ use_uw = true;
+   }
+
   alt_cost = 1 + riscv_build_integer_1 (alt_codes, x, mode);
   if (alt_cost < cost)
{
  alt_codes[alt_cost-1].code = ASHIFT;
  alt_codes[alt_cost-1].value = shift;
+ alt_codes[alt_cost-1].use_uw = use_uw;
  memcpy (codes, alt_codes, sizeof (alt_codes));
  cost = alt_cost;
}
@@ -823,8 +848,10 @@ riscv_build_integer_1 (struct riscv_integer_op 
codes[RISCV_MAX_INTEGER_OPS],
  /* The sign-bit might be zero, so just rotate to be safe.  */
  codes[0].value = (((unsigned HOST_WIDE_INT) value >> trailing_ones)
| (value << (64 - trailing_ones)));
+ codes[0].use_uw = false;
  codes[1].code = ROTATERT;
  codes[1].value = 64 - trailing_ones

[PATCH v3] DCE __cxa_atexit calls where the function is pure/const [PR19661]

2024-05-04 Thread Andrew Pinski
In C++ sometimes you have a deconstructor function which is "empty", like for an
example with unions or with arrays.  The front-end might not know it is empty 
either
so this should be done on during optimization.o
To implement it I added it to DCE where we mark if a statement is necessary or 
not.

Bootstrapped and tested on x86_64-linux-gnu with no regressions.

Changes since v1:
  * v2: Add support for __aeabi_atexit for arm-*eabi. Add extra comments.
Add cxa_atexit-5.C testcase for -fPIC case.
  * v3: Fix testcases for the __aeabi_atexit (forgot to do in the v2).

PR tree-optimization/19661

gcc/ChangeLog:

* tree-ssa-dce.cc (is_cxa_atexit): New function.
(is_removable_cxa_atexit_call): New function.
(mark_stmt_if_obviously_necessary): Don't mark removable
cxa_at_exit calls.
(mark_all_reaching_defs_necessary_1): Likewise.
(propagate_necessity): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/tree-ssa/cxa_atexit-1.C: New test.
* g++.dg/tree-ssa/cxa_atexit-2.C: New test.
* g++.dg/tree-ssa/cxa_atexit-3.C: New test.
* g++.dg/tree-ssa/cxa_atexit-4.C: New test.
* g++.dg/tree-ssa/cxa_atexit-5.C: New test.
* g++.dg/tree-ssa/cxa_atexit-6.C: New test.

Signed-off-by: Andrew Pinski 
---
 gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-1.C | 20 +++
 gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-2.C | 21 +++
 gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-3.C | 19 +++
 gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-4.C | 20 +++
 gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-5.C | 39 +
 gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-6.C | 24 
 gcc/tree-ssa-dce.cc  | 58 
 7 files changed, 201 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-1.C
 create mode 100644 gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-2.C
 create mode 100644 gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-3.C
 create mode 100644 gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-4.C
 create mode 100644 gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-5.C
 create mode 100644 gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-6.C

diff --git a/gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-1.C 
b/gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-1.C
new file mode 100644
index 000..82ff3d2b778
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-1.C
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-cddce1-details -fdump-tree-optimized" } */
+// { dg-require-effective-target cxa_atexit }
+/* PR tree-optimization/19661 */
+
+/* The call to axexit should be removed as A::~A() is a pure/const function 
call
+   and there is no visible effect if A::~A() call does not happen.  */
+
+struct A { 
+A(); 
+~A() {} 
+}; 
+ 
+void foo () { 
+  static A a; 
+} 
+
+/* { dg-final { scan-tree-dump-times "Deleting : 
(?:__cxxabiv1::__cxa_atexit|__aeabiv1::__aeabi_atexit)" 1 "cddce1" } } */
+/* { dg-final { scan-tree-dump-not "__cxa_atexit|__aeabi_atexit" "optimized" } 
} */
+
diff --git a/gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-2.C 
b/gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-2.C
new file mode 100644
index 000..726b6d7f156
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-2.C
@@ -0,0 +1,21 @@
+/* { dg-do compile { target c++11 } } */
+/* { dg-options "-O2 -fdump-tree-cddce1-details -fdump-tree-optimized" } */
+// { dg-require-effective-target cxa_atexit }
+/* PR tree-optimization/19661 */
+
+/* The call to axexit should be not removed as A::~A() as it marked with 
noipa.  */
+
+struct A { 
+A(); 
+~A();
+}; 
+
+[[gnu::noipa]] A::~A() {}
+ 
+void foo () { 
+  static A a; 
+} 
+
+/* { dg-final { scan-tree-dump-not "Deleting : 
(?:__cxxabiv1::__cxa_atexit|__aeabiv1::__aeabi_atexit)" "cddce1" } } */
+/* { dg-final { scan-tree-dump-times "(?:__cxa_atexit|__aeabi_atexit)" 1 
"optimized" } } */
+
diff --git a/gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-3.C 
b/gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-3.C
new file mode 100644
index 000..42cc7ccb11b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-3.C
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-cddce1-details -fdump-tree-optimized" } */
+// { dg-require-effective-target cxa_atexit }
+/* PR tree-optimization/19661 */
+
+/* We should not remove the call to atexit as A::~A is unknown.  */
+
+struct A { 
+A(); 
+~A();
+}; 
+
+void foo () { 
+  static A a; 
+} 
+
+/* { dg-final { scan-tree-dump-not "Deleting : 
(?:__cxxabiv1::__cxa_atexit|__aeabiv1::__aeabi_atexit)" "cddce1" } } */
+/* { dg-final { scan-tree-dump-times "(?:__cxa_atexit|__aeabi_atexit)" 1 
"optimized" } } */
+
diff --git a/gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-4.C 
b/gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-4.C
new file mode 100644
index 000..591c1c0552a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-4.C
@@ -0,0 +1,20 @@
+/* { dg-do compile { target c++11 } } */
+/* { dg-options "-

[PATCH v2] DCE __cxa_atexit calls where the function is pure/const [PR19661]

2024-05-04 Thread Andrew Pinski
In C++ sometimes you have a deconstructor function which is "empty", like for an
example with unions or with arrays.  The front-end might not know it is empty 
either
so this should be done on during optimization.o
To implement it I added it to DCE where we mark if a statement is necessary or 
not.

Bootstrapped and tested on x86_64-linux-gnu with no regressions.

Changes since v1:
  * v2: Add support for __aeabi_atexit for arm-*eabi. Add extra comments.
Add cxa_atexit-5.C testcase for -fPIC case.

PR tree-optimization/19661

gcc/ChangeLog:

* tree-ssa-dce.cc (is_cxa_atexit): New function.
(is_removable_cxa_atexit_call): New function.
(mark_stmt_if_obviously_necessary): Don't mark removable
cxa_at_exit calls.
(mark_all_reaching_defs_necessary_1): Likewise.
(propagate_necessity): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/tree-ssa/cxa_atexit-1.C: New test.
* g++.dg/tree-ssa/cxa_atexit-2.C: New test.
* g++.dg/tree-ssa/cxa_atexit-3.C: New test.
* g++.dg/tree-ssa/cxa_atexit-4.C: New test.
* g++.dg/tree-ssa/cxa_atexit-5.C: New test.
* g++.dg/tree-ssa/cxa_atexit-6.C: New test.

Signed-off-by: Andrew Pinski 
---
 gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-1.C | 20 +++
 gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-2.C | 21 +++
 gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-3.C | 19 +++
 gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-4.C | 20 +++
 gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-5.C | 39 +
 gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-6.C | 24 
 gcc/tree-ssa-dce.cc  | 58 
 7 files changed, 201 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-1.C
 create mode 100644 gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-2.C
 create mode 100644 gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-3.C
 create mode 100644 gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-4.C
 create mode 100644 gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-5.C
 create mode 100644 gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-6.C

diff --git a/gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-1.C 
b/gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-1.C
new file mode 100644
index 000..1f5f431c7e4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-1.C
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-cddce1-details -fdump-tree-optimized" } */
+// { dg-require-effective-target cxa_atexit }
+/* PR tree-optimization/19661 */
+
+/* The call to axexit should be removed as A::~A() is a pure/const function 
call
+   and there is no visible effect if A::~A() call does not happen.  */
+
+struct A { 
+A(); 
+~A() {} 
+}; 
+ 
+void foo () { 
+  static A a; 
+} 
+
+/* { dg-final { scan-tree-dump-times "Deleting : __cxxabiv1::__cxa_atexit" 1 
"cddce1" } } */
+/* { dg-final { scan-tree-dump-not "__cxa_atexit" "optimized" } } */
+
diff --git a/gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-2.C 
b/gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-2.C
new file mode 100644
index 000..4d0656b455c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-2.C
@@ -0,0 +1,21 @@
+/* { dg-do compile { target c++11 } } */
+/* { dg-options "-O2 -fdump-tree-cddce1-details -fdump-tree-optimized" } */
+// { dg-require-effective-target cxa_atexit }
+/* PR tree-optimization/19661 */
+
+/* The call to axexit should be not removed as A::~A() as it marked with 
noipa.  */
+
+struct A { 
+A(); 
+~A();
+}; 
+
+[[gnu::noipa]] A::~A() {}
+ 
+void foo () { 
+  static A a; 
+} 
+
+/* { dg-final { scan-tree-dump-not "Deleting : __cxxabiv1::__cxa_atexit" 
"cddce1" } } */
+/* { dg-final { scan-tree-dump-times "__cxa_atexit" 1 "optimized" } } */
+
diff --git a/gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-3.C 
b/gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-3.C
new file mode 100644
index 000..03a19209661
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-3.C
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-cddce1-details -fdump-tree-optimized" } */
+// { dg-require-effective-target cxa_atexit }
+/* PR tree-optimization/19661 */
+
+/* We should not remove the call to atexit as A::~A is unknown.  */
+
+struct A { 
+A(); 
+~A();
+}; 
+
+void foo () { 
+  static A a; 
+} 
+
+/* { dg-final { scan-tree-dump-not "Deleting : __cxxabiv1::__cxa_atexit" 
"cddce1" } } */
+/* { dg-final { scan-tree-dump-times "__cxa_atexit" 1 "optimized" } } */
+
diff --git a/gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-4.C 
b/gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-4.C
new file mode 100644
index 000..b85a7efd16b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/cxa_atexit-4.C
@@ -0,0 +1,20 @@
+/* { dg-do compile { target c++11 } } */
+/* { dg-options "-O2 -fdump-tree-cddce1-details -fdump-tree-optimized -w" } */
+// { dg-require-effective-target cxa_atexit }
+/* PR tree-optimization/19661 */
+
+/* The call to axexit should be removed as A::~A() is a pure/const funct

[PATCH 09/12] OpenMP: Extend dynamic selector support to declare variant

2024-05-04 Thread Sandra Loosemore
This patch extends the mechanisms previously added to support dynamic
selectors in metavariant constructs to also apply to "declare
variant".  The front-end mechanisms used to handle "declare variant"
via attributes attached to the function decls remain the same, but the
gimplifier now uses the same internal data structures and helper
functions as metadirective to score and sort "declare variant"
alternatives, and constructs a gomp_metadirective node for variant
calls that cannot be resolved at gimplification time.  During late
resolution, this gomp_metadirective is processed in exactly the same
way as for real metadirectives.

During implementation of this functionality, a number of bugs were
discovered in the previous selector scoring and matching code:

* Metadirective resolution was failing to account for scoring in
  "declare simd" clones, and was also relying on calling a function to
  match construct constructors that's only useful during
  gimplification during late resolution long after that pass.

* The construct constructor scoring was previously implemented backwards
  from the specification (PR114596); a number of testcases were also broken
  in the same way as the implementation.

* The special rules for matching simdlen and aligned properties on simd
  selectors were not implemented (nor were these properties on metadirectives
  being rejected per the OpenMP spec).

This patch includes a new implementation of this functionality that
has cleaner interfaces and is hopefully(!) easier to correlate to
requirements of the OpenMP specification.  Instead of relying on the
gimplifier to score construct selectors, the scoring code has been
consolidated in omp-general.cc with the gimplifier only providing
the OpenMP construct context surrounding the metadirective or variant
call.  This is cached on the gomp_metadirective if necessary for late
resolution.

An additional improvement added in this patch is that for both
metadirective and "declare variant", if late resolution is required the
gimplifier now discards all alternatives that are known not to match.

Note that this patch leaves a substantial amount of dead code that
was used to support the former late "declare variant" resolution strategy,
notably the declare_variant_alt and calls_declare_variant_alt flags on
cgraph_node and all the code that touches those fields.  The next
patch in this series removes that unused code.

Another issue not addressed in this patch is the special scoping rules
for expressions in "declare variant" dynamic selectors, which is still
under discussion in PR113904.  We expect this to be fixed separately.

gcc/c/ChangeLog
* c-parser.c (c_parser_omp_context_selector): Remove metadirective_p
parameter and conditionalization.
(c_parser_omp_context_selector_specification): Remove metadirective_p
parameter and adjust call not to pass it on.
(c_finish_omp_declare_variant): Adjust arguments on calls to
c_parser_omp_context_selector_specification and
omp_context_selector_matches.
(c_parser_omp_metadirective): Likewise.

gcc/cp/ChangeLog
* cp-tree.h (struct saved_scope): Add new field
x_processing_omp_trait_property_expr.
(processing_omp_trait_property_expr): Define
* decl.cc (omp_declare_variant_finalize_one): Adjust arguments
to omp_context_selector_matches.
* parser.cc (cp_parser_omp_context_selector): Remove metadirective_p
argument and conditionalization.
(cp_parser_omp_context_selector_specification): Remove metadirective_p
argument and adjust call not to pass it on.
(cp_finish_omp_declare_variant): Adjust arguments on call to above.
(cp_parser_omp_metadirective): Likewise.
* pt.cc (tsubst_omp_context_selector): Adjust error behavior.
(tsubst_stmt): Adjust call to omp_context_selector_matches.
* semantics.cc (finish_id_expression_1): Do not diagnose error
for use of parameter in declare variant selector here.

gcc/fortran/ChangeLog
* trans-openmp.cc (gfc_trans_omp_declare_variant): Adjust arguments
to omp_context_selector_matches.
(gfc_trans_omp_metadirective): Likewise.

gcc/Changelog
* gimple-streamer-in.cc (input_gimple_stmt): Restore
gomp_metadirective context.
* gimple-streamer-out.cc (output_gimple_stmt): Save
gomp_metadirective context.
* gimple.cc (gimple_build_omp_metadirective): Initialize
gomp_metadirective context.
* gimple.def (GIMPLE_OMP_METADIRECTIVE): Update comments.
* gimple.h (gomp_metadirective): Add context field and update comments.
(gimple_omp_metadirective_context): New.
(gimple_omp_metadirective_set_context): New.
* gimplify.cc (omp_resolved_variant_calls): New.
(gimplify_variant_call_expr): New.
(gimplify_call_expr): Adjust parameters.  Call
gimplify_variant_call_expr to handle declar

[PATCH 07/12] OpenMP: Fortran front-end support for metadirectives.

2024-05-04 Thread Sandra Loosemore
This patch adds support for metadirectives to the Fortran front end.

gcc/fortran/ChangeLog
* decl.cc (gfc_match_end): Handle metadirectives.
* dump-parse-tree.cc (show_omp_node): Likewise.
(show_code_node): Likewise.
* gfortran.h (enum gfc_statement): Add ST_OMP_METADIRECTIVE.
(struct gfc_omp_clauses): Rename target_first_st_is_teams field to
target_first_st_is_teams_or_meta.
(struct gfc_omp_variant): New.
(struct gfc_st_label): Add omp_region field.
(gfc_exec_op): Add EXEC_OMP_METADIRECTIVE.
(struct gfc_code): Add omp_variants field.
(gfc_free_omp_variants): Declare.
(match_omp_directive): Declare.
(is_omp_declarative_stmt): Declare.
* io.cc (format_asterisk): Add initializer for new omp_region field.
* match.h (gfc_match_omp_begin_metadirective): Declare.
(gfc_match_omp_metadirective): Declare.
* openmp.cc (gfc_match_omp_eos): Special case for matching an
OpenMP context selector.
(gfc_free_omp_variants): New.
(gfc_match_omp_clauses): Remove context_selector parameter.
(match_omp): Adjust call to gfc_match_omp_clauses.
(gfc_match_omp_context_selector): Add metadirective_p parameter.
Adjust error-checking logic and calls to gfc_match_omp_clauses.
Set gfc_matching_omp_context_selector.
(gfc_match_omp_context_selector_specification): Generalize to take
a set selector list pointer as parameter, instead of a
declare variant pointer.
(gfc_match_omp_declare_variant): Adjust call to match above change.
(match_omp_metadirective): New.
(gfc_match_omp_begin_metadirective): New.
(gfc_match_omp_metadirective): New.
(resolve_omp_metadirective): New.
(resolve_omp_target): Handle metadirectives.
(gfc_resolve_omp_directive): Handle metadirectives.
* parse.cc (gfc_matching_omp_context_selector): New.
(gfc_in_metadirective_body): New.
(gfc_omp_region_count): New.
(decode_omp_directive): Handle "begin metadirective", "end
metadirective", and "metadirective".
(match_omp_directive): New.
(case_omp_structured_block): New define.
(case_omp_do): New define.
(gfc_ascii_statement): Handle ST_OMP_BEGIN_METADIRECTIVE,
ST_OMP_END_METADIRECTIVE, and ST_OMP_METADIRECTIVE.
(accept_statement): Handle ST_OMP_BEGIN_METADIRECTIVE and
ST_OMP_METADIRECTIVE.
(gfc_omp_end_stmt): New.
(parse_omp_do): Use gfc_omp_end_stmt.  Special-case
"omp end metadirective" to end the current construct.
(parse_omp_structured_block): Likewise.  Adjust setting of
target_first_st_is_teams_or_meta flag.
(parse_omp_metadirective_body): New.
(parse_executable): Handle metadirectives.  Use
case_omp_structured_block and case_omp_do here.
(gfc_parse_file): Initialize gfc_omp_region_count,
gfc_in_metadirective_body, and gfc_matching_omp_context_selector.
(is_omp_declarative_stmt): New.
* parse.h (enum gfc_compile_state): Add metadirective constructs.
(gfc_omp_end_stmt): Declare.
(gfc_matching_omp_context_selector): Declare.
(gfc_in_metadirective_body): Declare.
(gfc_omp_region_count): Declare.
* resolve.cc (gfc_resolve_code): Handle EXEC_OMP_METADIRECTIVE.
* st.cc (gfc_free_statement): Handle EXEC_OMP_METADIRECTIVE.
* symbol.cc (compare_st_labels): Compare omp_region, not just the
value.
(gfc_get_st_label): Likewise.  Initialize the omp_region field when
creating a new label.
* trans-decl.cc (gfc_get_label_decl): Encode the omp_region in the
label name.
* trans-openmp.cc (gfc_trans_omp_directive): Handle
EXEC_OMP_METADIRECTIVE.
(gfc_trans_omp_set_selector): New, split from...
(gfc_trans_omp_declare_variant): ...here.
(gfc_trans_omp_metadirective): New.
* trans-stmt.h (gfc_trans_omp_metadirective): Declare.
* trans.cc (trans_code): Handle EXEC_OMP_METADIRECTIVE.

gcc/testsuite/ChangeLog

* gfortran.dg/gomp/metadirective-1.f90: New.
* gfortran.dg/gomp/metadirective-10.f90: New.
* gfortran.dg/gomp/metadirective-11.f90: New.
* gfortran.dg/gomp/metadirective-2.f90: New.
* gfortran.dg/gomp/metadirective-3.f90: New.
* gfortran.dg/gomp/metadirective-4.f90: New.
* gfortran.dg/gomp/metadirective-5.f90: New.
* gfortran.dg/gomp/metadirective-6.f90: New.
* gfortran.dg/gomp/metadirective-7.f90: New.
* gfortran.dg/gomp/metadirective-8.f90: New.
* gfortran.dg/gomp/metadirective-9.f90: New.
* gfortran.dg/gomp/metadirective-construct.f90: New.
* gfortran.dg/gomp/metadirective-no-score.f90: New.
* gfortran.dg/gomp/pure-1.f90: Add metadirective test.
* gfortran.dg/gom

[PATCH 11/12] OpenMP: Update "declare target"/OpenMP context interaction

2024-05-04 Thread Sandra Loosemore
The code and test case previously implemented the OpenMP 5.0 spec,
which said in section 2.3.1:

"For functions within a declare target block, the target trait is added
to the beginning of the set..."

In OpenMP 5.1, this was changed to
"For device routines, the target trait is added to the beginning of
the set..."

In OpenMP 5.2 and TR12, it says:
"For procedures that are determined to be target function variants
by a declare target directive..."

The definition of "device routine" in OpenMP 5.1 is confusing, but
certainly the intent of the later versions of the spec is clear that
it doesn't just apply to functions within a begin declare target/end
declare target block.

The only use of the "omp declare target block" function attribute was
to support the 5.0 language, so it can be removed.  This patch changes
the context augmentation to use the "omp declare target" attribute
instead.

gcc/c-family/ChangeLog
* c-attribs.cc (c_common_gnu_attributes): Delete "omp declare
target block".

gcc/c/ChangeLog
* c-decl.cc (c_decl_attributes): Don't add "omp declare target
block".

gcc/cp/decl2.cc
* decl2.cc (cplus_decl_attributes): Don't add "omp declare target
block".

gcc/ChangeLog
* omp-general.cc (omp_complete_construct_context): Check
"omp declare target" attribute, not "omp declare target block".

gcc/testsuite/ChangeLog
* c-c++-common/gomp/declare-target-indirect-2.c : Adjust
expected output for removal of "omp declare target block".
* c-c++-common/gomp/declare-variant-8.c: Likewise, the variant
call to f20 is now resolved differently.
* c-c++-common/gomp/reverse-offload-1.c: Adjust expected output.
* gfortran.dg/gomp/declare-variant-8.f90: Likewise, both f18
and f20 now resolve to the variant.  Delete obsolete comments.
---
 gcc/c-family/c-attribs.cc|  2 --
 gcc/c/c-decl.cc  |  8 ++--
 gcc/cp/decl2.cc  |  9 ++---
 gcc/omp-general.cc   |  2 +-
 .../c-c++-common/gomp/declare-target-indirect-2.c| 10 +-
 gcc/testsuite/c-c++-common/gomp/declare-variant-8.c  |  4 ++--
 gcc/testsuite/c-c++-common/gomp/reverse-offload-1.c  |  2 +-
 gcc/testsuite/gfortran.dg/gomp/declare-variant-8.f90 | 12 ++--
 8 files changed, 15 insertions(+), 34 deletions(-)

diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index 04e39b41bdf..582d99ada1b 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -570,8 +570,6 @@ const struct attribute_spec c_common_gnu_attributes[] =
  handle_omp_declare_target_attribute, NULL },
   { "omp declare target nohost", 0, 0, true, false, false, false,
  handle_omp_declare_target_attribute, NULL },
-  { "omp declare target block", 0, 0, true, false, false, false,
- handle_omp_declare_target_attribute, NULL },
   { "non overlapping",   0, 0, true, false, false, false,
  handle_non_overlapping_attribute, NULL },
   { "alloc_align",   1, 1, false, true, true, false,
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 52af8f32998..4ab7cd86030 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5414,12 +5414,8 @@ c_decl_attributes (tree *node, tree attributes, int 
flags)
attributes = tree_cons (get_identifier ("omp declare target implicit"),
NULL_TREE, attributes);
   else
-   {
- attributes = tree_cons (get_identifier ("omp declare target"),
- NULL_TREE, attributes);
- attributes = tree_cons (get_identifier ("omp declare target block"),
- NULL_TREE, attributes);
-   }
+   attributes = tree_cons (get_identifier ("omp declare target"),
+   NULL_TREE, attributes);
   if (TREE_CODE (*node) == FUNCTION_DECL)
{
  int device_type
diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
index 806a2a4bc69..028105a5b26 100644
--- a/gcc/cp/decl2.cc
+++ b/gcc/cp/decl2.cc
@@ -1777,13 +1777,8 @@ cplus_decl_attributes (tree *decl, tree attributes, int 
flags)
  = tree_cons (get_identifier ("omp declare target implicit"),
   NULL_TREE, attributes);
  else
-   {
- attributes = tree_cons (get_identifier ("omp declare target"),
- NULL_TREE, attributes);
- attributes
-   = tree_cons (get_identifier ("omp declare target block"),
-NULL_TREE, attributes);
-   }
+   attributes = tree_cons (get_identifier ("omp declare target"),
+   NULL_TREE, attributes);
  if (TREE_CODE (*decl) == FUNCTION_DECL)
{

[PATCH 10/12] OpenMP: Remove dead code from declare variant reimplementation

2024-05-04 Thread Sandra Loosemore
After reimplementing late resolution of "declare variant" to use the
same mechanisms as metadirective, the declare_variant_alt and
calls_declare_variant_alt flags on struct cgraph_node are no longer
used by anything.  For the purposes of marking functions that need
late resolution, the has_metadirectives flag has replaced
calls_declare_variant_alt.

Likewise struct omp_declare_variant_entry, struct
omp_declare_variant_base_entry, and the hash tables used to store
these structures are no longer needed, since the information needed for
late resolution is now stored in the gomp_metadirective nodes.

There are no functional changes in this patch, just removing dead code.

gcc/ChangeLog
* cgraph.cc (symbol_table::create_edge): Don't set
calls_declare_variant_alt in the caller.
* cgraph.h (struct cgraph_node): Remove declare_variant_alt
and calls_declare_variant_alt flags.
* cgraphclones.cc (cgraph_node::create_clone): Don't copy
calls_declare_variant_alt bit.
* ipa-free-lang-data.cc (free_lang_data_in_decl): Adjust code
referencing declare_variant_alt bit.
* ipa.cc (symbol_table::remove_unreachable_nodes): Likewise.
* lto-cgraph.cc (lto_output_node): Remove references to deleted
bits.
(output_refs): Adjust code referencing declare_variant_alt bit.
(input_overwrite_node): Remove references to deleted bits.
(input_refs): Adjust code referencing declare_variant_alt bit.
* lto-streamer-out.cc (lto_output): Likewise.
* lto-streamer.h (omp_lto_output_declare_variant_alt): Delete.
(omp_lto_input_declare_variant_alt): Delete.
* lto/lto-partition.cc (lto_balanced_map): Adjust code referencing
deleted declare_variant_alt bit.
* omp-expand.cc (expand_omp_target): Use has_metadirectives bit to
trigger pass_omp_device_lower instead of calls_declare_variant_alt.
* omp-general.cc (struct omp_declare_variant_entry): Delete.
(struct omp_declare_variant_base_entry): Delete.
(struct omp_declare_variant_hasher): Delete.
(omp_declare_variant_hasher::hash): Delete.
(omp_declare_variant_hasher::equal): Delete.
(omp_declare_variants): Delete.
(omp_declare_variant_alt_hasher): Delete.
(omp_declare_variant_alt_hasher::hash): Delete.
(omp_declare_variant_alt_hasher::equal): Delete.
(omp_declare_variant_alt): Delete.
(omp_lto_output_declare_variant_alt): Delete.
(omp_lto_input_declare_variant_alt): Delete.
(includes): Delete unnecessary include of gt-omp-general.h.
* omp-offload.cc (execute_omp_device_lower): Remove references
to deleted bit.
(pass_omp_device_lower::gate): Likewise.
* omp-simd-clone.cc (simd_clone_create): Likewise.
* passes.cc (ipa_write_summaries): Likeise.
* symtab.cc (symtab_node::get_partitioning_class): Likewise.
* tree-inline.cc (expand_call_inline): Likewise.
(tree_function_versioning): Likewise.
---
 gcc/cgraph.cc |   2 -
 gcc/cgraph.h  |  11 +-
 gcc/cgraphclones.cc   |   1 -
 gcc/ipa-free-lang-data.cc |   2 +-
 gcc/ipa.cc|   3 -
 gcc/lto-cgraph.cc |  10 --
 gcc/lto-streamer-out.cc   |   3 +-
 gcc/lto-streamer.h|   6 --
 gcc/lto/lto-partition.cc  |   5 +-
 gcc/omp-expand.cc |   2 +-
 gcc/omp-general.cc| 218 --
 gcc/omp-offload.cc|   8 +-
 gcc/omp-simd-clone.cc |   2 -
 gcc/passes.cc |   3 +-
 gcc/symtab.cc |   2 +-
 gcc/tree-inline.cc|   4 -
 16 files changed, 10 insertions(+), 272 deletions(-)

diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc
index 473d8410bc9..103bc2c0332 100644
--- a/gcc/cgraph.cc
+++ b/gcc/cgraph.cc
@@ -931,8 +931,6 @@ symbol_table::create_edge (cgraph_node *caller, cgraph_node 
*callee,
  caller->decl);
   else
 edge->in_polymorphic_cdtor = caller->thunk;
-  if (callee)
-caller->calls_declare_variant_alt |= callee->declare_variant_alt;
 
   if (callee && symtab->state != LTO_STREAMING
   && edge->callee->comdat_local_p ())
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 6653ce19c3e..dd210842df7 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -897,10 +897,8 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public 
symtab_node
   split_part (false), indirect_call_target (false), local (false),
   versionable (false), can_change_signature (false),
   redefined_extern_inline (false), tm_may_enter_irr (false),
-  ipcp_clone (false), declare_variant_alt (false),
-  calls_declare_variant_alt (false), gc_candidate (false),
-  called_by_ifunc_resolver (false),
-  has_metadirectives (false),
+  ipcp_clone (false), gc_candidate (false),
+  called_by_ifunc_resolver (false), has_metadirectives (false),
   m_uid (uid), m_summary_id (-1)
 

[PATCH 05/12] OpenMP: C++ front-end support for metadirectives

2024-05-04 Thread Sandra Loosemore
This patch adds C++ support for metadirectives.  It uses the
c-family support committed with the corresponding C front end patch
to do early parse-time metadirective resolution when possible.

Additional C/C++ common testcases are provided in a subsequent
patch in the series.

gcc/cp/ChangeLog
* parser.cc (cp_parser_skip_to_end_of_block_or_statement): Add
metadirective_p parameter, use it to control brace/parentheses
behavior for metadirectives.
(mangle_metadirective_region_label): New.
(cp_parser_label_for_labeled_statement): Use it.
(cp_parser_jump_statement): Likewise.
(cp_parser_omp_context_selector): Add metadirective_p
parameter, use it to control error behavior for non-constant exprs
properties.
(cp_parser_omp_context_selector_specification): Add metadirective_p
parameter, use it for cp_parser_omp_context_selector call.
(cp_finish_omp_declare_variant): Adjust call to
cp_parser_omp_context_selector_specification.
(analyze_metadirective_body): New.
(cp_parser_omp_metadirective): New.
(cp_parser_pragma): Handle PRAGMA_OMP_METADIRECTIVE.
* parser.h (struct cp_parser): Add fields for metadirective parsing
state.
* pt.cc (tsubst_omp_context_selector): New.
(tsubst_stmt): Handle OMP_METADIRECTIVE.

gcc/testsuite/ChangeLog
* g++.dg/gomp/attrs-metadirective-1.C: New.
* g++.dg/gomp/attrs-metadirective-2.C: New.
* g++.dg/gomp/attrs-metadirective-3.C: New.
* g++.dg/gomp/attrs-metadirective-4.C: New.
* g++.dg/gomp/attrs-metadirective-5.C: New.
* g++.dg/gomp/attrs-metadirective-6.C: New.
* g++.dg/gomp/attrs-metadirective-7.C: New.
* g++.dg/gomp/attrs-metadirective-8.C: New.

libgomp/ChangeLog
* testsuite/libgomp.c++/metadirective-template-1.C: New.
* testsuite/libgomp.c++/metadirective-template-2.C: New.
* testsuite/libgomp.c++/metadirective-template-3.C: New.

Co-Authored-By: Kwok Cheung Yeung 
Co-Authored-By: Sandra Loosemore 
---
 gcc/cp/parser.cc  | 524 +-
 gcc/cp/parser.h   |   7 +
 gcc/cp/pt.cc  | 119 
 .../g++.dg/gomp/attrs-metadirective-1.C   |  40 ++
 .../g++.dg/gomp/attrs-metadirective-2.C   |  74 +++
 .../g++.dg/gomp/attrs-metadirective-3.C   |  31 ++
 .../g++.dg/gomp/attrs-metadirective-4.C   |  41 ++
 .../g++.dg/gomp/attrs-metadirective-5.C   |  24 +
 .../g++.dg/gomp/attrs-metadirective-6.C   |  31 ++
 .../g++.dg/gomp/attrs-metadirective-7.C   |  31 ++
 .../g++.dg/gomp/attrs-metadirective-8.C   |  16 +
 .../libgomp.c++/metadirective-template-1.C|  37 ++
 .../libgomp.c++/metadirective-template-2.C|  41 ++
 .../libgomp.c++/metadirective-template-3.C|  41 ++
 14 files changed, 1044 insertions(+), 13 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/gomp/attrs-metadirective-1.C
 create mode 100644 gcc/testsuite/g++.dg/gomp/attrs-metadirective-2.C
 create mode 100644 gcc/testsuite/g++.dg/gomp/attrs-metadirective-3.C
 create mode 100644 gcc/testsuite/g++.dg/gomp/attrs-metadirective-4.C
 create mode 100644 gcc/testsuite/g++.dg/gomp/attrs-metadirective-5.C
 create mode 100644 gcc/testsuite/g++.dg/gomp/attrs-metadirective-6.C
 create mode 100644 gcc/testsuite/g++.dg/gomp/attrs-metadirective-7.C
 create mode 100644 gcc/testsuite/g++.dg/gomp/attrs-metadirective-8.C
 create mode 100644 libgomp/testsuite/libgomp.c++/metadirective-template-1.C
 create mode 100644 libgomp/testsuite/libgomp.c++/metadirective-template-2.C
 create mode 100644 libgomp/testsuite/libgomp.c++/metadirective-template-3.C

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 8b819b2ebfd..4bb9b086095 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -3001,7 +3001,7 @@ static void cp_parser_skip_to_end_of_statement
 static void cp_parser_consume_semicolon_at_end_of_statement
   (cp_parser *);
 static void cp_parser_skip_to_end_of_block_or_statement
-  (cp_parser *);
+  (cp_parser *, bool = false);
 static bool cp_parser_skip_to_closing_brace
   (cp_parser *);
 static bool cp_parser_skip_entire_template_parameter_list
@@ -4177,9 +4177,11 @@ cp_parser_consume_semicolon_at_end_of_statement 
(cp_parser *parser)
have consumed a non-nested `;'.  */
 
 static void
-cp_parser_skip_to_end_of_block_or_statement (cp_parser* parser)
+cp_parser_skip_to_end_of_block_or_statement (cp_parser* parser,
+bool metadirective_p)
 {
   int nesting_depth = 0;
+  int bracket_depth = 0;
 
   /* Unwind generic function template scope if necessary.  */
   if (parser->fully_implicit_function_template_p)
@@ -4201,7 +4203,7 @@ cp_parser_skip_to_end_of_block_or_statement (cp_parser* 
parser)
 
case CPP_SEMICOLON:
  /* Stop if this is an unnested ';'. */
- if (!nesting_depth)
+ if (!nesting_de

[PATCH 06/12] OpenMP: common c/c++ testcases for metadirectives

2024-05-04 Thread Sandra Loosemore
gcc/testsuite/ChangeLog
* c-c++-common/gomp/metadirective-1.c: New.
* c-c++-common/gomp/metadirective-2.c: New.
* c-c++-common/gomp/metadirective-3.c: New.
* c-c++-common/gomp/metadirective-4.c: New.
* c-c++-common/gomp/metadirective-5.c: New.
* c-c++-common/gomp/metadirective-6.c: New.
* c-c++-common/gomp/metadirective-7.c: New.
* c-c++-common/gomp/metadirective-8.c: New.
* c-c++-common/gomp/metadirective-construct.c: New.
* c-c++-common/gomp/metadirective-device.c: New.
* c-c++-common/gomp/metadirective-no-score.c: New.
* c-c++-common/gomp/metadirective-target-device.c: New.

libgomp/ChangeLog
* testsuite/libgomp.c-c++-common/metadirective-1.c: New.
* testsuite/libgomp.c-c++-common/metadirective-2.c: New.
* testsuite/libgomp.c-c++-common/metadirective-3.c: New.
* testsuite/libgomp.c-c++-common/metadirective-4.c: New.
* testsuite/libgomp.c-c++-common/metadirective-5.c: New.

Co-Authored-By: Kwok Cheung Yeung 
Co-Authored-By: Sandra Loosemore 
---
 .../c-c++-common/gomp/metadirective-1.c   |  52 +
 .../c-c++-common/gomp/metadirective-2.c   |  74 
 .../c-c++-common/gomp/metadirective-3.c   |  31 +++
 .../c-c++-common/gomp/metadirective-4.c   |  40 
 .../c-c++-common/gomp/metadirective-5.c   |  24 +++
 .../c-c++-common/gomp/metadirective-6.c   |  31 +++
 .../c-c++-common/gomp/metadirective-7.c   |  31 +++
 .../c-c++-common/gomp/metadirective-8.c   |  16 ++
 .../gomp/metadirective-construct.c| 177 ++
 .../c-c++-common/gomp/metadirective-device.c  | 147 +++
 .../gomp/metadirective-no-score.c |  95 ++
 .../gomp/metadirective-target-device.c| 147 +++
 .../libgomp.c-c++-common/metadirective-1.c|  35 
 .../libgomp.c-c++-common/metadirective-2.c|  41 
 .../libgomp.c-c++-common/metadirective-3.c|  34 
 .../libgomp.c-c++-common/metadirective-4.c|  52 +
 .../libgomp.c-c++-common/metadirective-5.c|  46 +
 17 files changed, 1073 insertions(+)
 create mode 100644 gcc/testsuite/c-c++-common/gomp/metadirective-1.c
 create mode 100644 gcc/testsuite/c-c++-common/gomp/metadirective-2.c
 create mode 100644 gcc/testsuite/c-c++-common/gomp/metadirective-3.c
 create mode 100644 gcc/testsuite/c-c++-common/gomp/metadirective-4.c
 create mode 100644 gcc/testsuite/c-c++-common/gomp/metadirective-5.c
 create mode 100644 gcc/testsuite/c-c++-common/gomp/metadirective-6.c
 create mode 100644 gcc/testsuite/c-c++-common/gomp/metadirective-7.c
 create mode 100644 gcc/testsuite/c-c++-common/gomp/metadirective-8.c
 create mode 100644 gcc/testsuite/c-c++-common/gomp/metadirective-construct.c
 create mode 100644 gcc/testsuite/c-c++-common/gomp/metadirective-device.c
 create mode 100644 gcc/testsuite/c-c++-common/gomp/metadirective-no-score.c
 create mode 100644 
gcc/testsuite/c-c++-common/gomp/metadirective-target-device.c
 create mode 100644 libgomp/testsuite/libgomp.c-c++-common/metadirective-1.c
 create mode 100644 libgomp/testsuite/libgomp.c-c++-common/metadirective-2.c
 create mode 100644 libgomp/testsuite/libgomp.c-c++-common/metadirective-3.c
 create mode 100644 libgomp/testsuite/libgomp.c-c++-common/metadirective-4.c
 create mode 100644 libgomp/testsuite/libgomp.c-c++-common/metadirective-5.c

diff --git a/gcc/testsuite/c-c++-common/gomp/metadirective-1.c 
b/gcc/testsuite/c-c++-common/gomp/metadirective-1.c
new file mode 100644
index 000..37b56237531
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/metadirective-1.c
@@ -0,0 +1,52 @@
+/* { dg-do compile } */
+
+#define N 100
+
+void f (int a[], int b[], int c[])
+{
+  int i;
+
+  #pragma omp metadirective \
+  default (teams loop) \
+  default (parallel loop) /* { dg-error "too many 'otherwise' or 'default' 
clauses in 'metadirective'" } */
+for (i = 0; i < N; i++) c[i] = a[i] * b[i];
+
+  #pragma omp metadirective \
+  otherwise (teams loop) \
+  default (parallel loop) /* { dg-error "too many 'otherwise' or 'default' 
clauses in 'metadirective'" } */
+for (i = 0; i < N; i++) c[i] = a[i] * b[i];
+
+  #pragma omp metadirective \
+  otherwise (teams loop) \
+  otherwise (parallel loop) /* { dg-error "too many 'otherwise' or 
'default' clauses in 'metadirective'" } */
+for (i = 0; i < N; i++) c[i] = a[i] * b[i];
+
+  #pragma omp metadirective \
+  default (bad_directive) /* { dg-error "unknown directive name before 
'\\)' token" } */
+for (i = 0; i < N; i++) c[i] = a[i] * b[i];
+
+  #pragma omp metadirective \
+  default (teams loop) \
+  where (device={arch("nvptx")}: parallel loop) /* { dg-error "'where' is 
not valid for 'metadirective'" } */
+for (i = 0; i < N; i++) c[i] = a[i] * b[i];
+
+  #pragma omp metadirective \
+  default (teams loop) \
+  when (device={arch("nvptx")} parallel loop) /* { dg-error "expected 

[PATCH 08/12] OpenMP: Reject other properties with kind(any)

2024-05-04 Thread Sandra Loosemore
The OpenMP spec says:

"If trait-property any is specified in the kind trait-selector of the
device selector set or the target_device selector sets, no other
trait-property may be specified in the same selector set."

GCC was not previously enforcing this restriction and several testcases
included such valid constructs.  This patch fixes it.

gcc/ChangeLog
* omp-general.cc (omp_check_context_selector): Reject other
properties in the same selector set with kind(any).

gcc/testsuite/ChangeLog
* c-c++-common/gomp/declare-variant-10.c: Fix broken tests.
* c-c++-common/gomp/declare-variant-3.c: Likewise.
* c-c++-common/gomp/declare-variant-9.c: Likewise.
* c-c++-common/gomp/declare-variant-any.c: New.
* gfortran.dg/gomp/declare-variant-10.f90: Fix broken tests.
* gfortran.dg/gomp/declare-variant-3.f90: Likewise.
* gfortran.dg/gomp/declare-variant-9.f90: Likewise.
* gfortran.dg/gomp/declare-variant-any.f90: Likewise.
---
 gcc/omp-general.cc| 31 +++
 .../c-c++-common/gomp/declare-variant-10.c|  4 +--
 .../c-c++-common/gomp/declare-variant-3.c | 10 ++
 .../c-c++-common/gomp/declare-variant-9.c |  4 +--
 .../c-c++-common/gomp/declare-variant-any.c   | 10 ++
 .../gfortran.dg/gomp/declare-variant-10.f90   |  4 +--
 .../gfortran.dg/gomp/declare-variant-3.f90| 12 ++-
 .../gfortran.dg/gomp/declare-variant-9.f90|  2 +-
 .../gfortran.dg/gomp/declare-variant-any.f90  | 28 +
 9 files changed, 82 insertions(+), 23 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/gomp/declare-variant-any.c
 create mode 100644 gcc/testsuite/gfortran.dg/gomp/declare-variant-any.f90

diff --git a/gcc/omp-general.cc b/gcc/omp-general.cc
index 6f36b5d163f..23072b10d75 100644
--- a/gcc/omp-general.cc
+++ b/gcc/omp-general.cc
@@ -1277,6 +1277,8 @@ omp_check_context_selector (location_t loc, tree ctx, 
bool metadirective_p)
   for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
 {
   enum omp_tss_code tss_code = OMP_TSS_CODE (tss);
+  bool saw_any_prop = false;
+  bool saw_other_prop = false;
 
   /* FIXME: not implemented yet.  */
   if (!metadirective_p && tss_code == OMP_TRAIT_SET_TARGET_DEVICE)
@@ -1314,6 +1316,27 @@ omp_check_context_selector (location_t loc, tree ctx, 
bool metadirective_p)
  else
ts_seen[ts_code] = true;
 
+
+ /* If trait-property "any" is specified in the "kind"
+trait-selector of the "device" selector set or the
+"target_device" selector sets, no other trait-property
+may be specified in the same selector set.  */
+ if (ts_code == OMP_TRAIT_DEVICE_KIND)
+   for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
+ {
+   const char *prop = omp_context_name_list_prop (p);
+   if (!prop)
+ continue;
+   else if (strcmp (prop, "any") == 0)
+ saw_any_prop = true;
+   else
+ saw_other_prop = true;
+ }
+   else if (ts_code == OMP_TRAIT_DEVICE_ARCH
+  || ts_code == OMP_TRAIT_DEVICE_ISA
+  || ts_code == OMP_TRAIT_DEVICE_NUM)
+   saw_other_prop = true;
+
  if (omp_ts_map[ts_code].valid_properties == NULL)
continue;
 
@@ -1366,6 +1389,14 @@ omp_check_context_selector (location_t loc, tree ctx, 
bool metadirective_p)
  break;
  }
}
+
+  if (saw_any_prop && saw_other_prop)
+   {
+ error_at (loc,
+   "no other trait-property may be specified "
+   "in the same selector set with %");
+ return error_mark_node;
+   }
 }
   return ctx;
 }
diff --git a/gcc/testsuite/c-c++-common/gomp/declare-variant-10.c 
b/gcc/testsuite/c-c++-common/gomp/declare-variant-10.c
index 2b8a39425b1..e77693430d1 100644
--- a/gcc/testsuite/c-c++-common/gomp/declare-variant-10.c
+++ b/gcc/testsuite/c-c++-common/gomp/declare-variant-10.c
@@ -7,7 +7,7 @@ void f01 (void);
 #pragma omp declare variant (f01) match (device={isa(avx512f,avx512bw)})
 void f02 (void);
 void f03 (void);
-#pragma omp declare variant (f03) match 
(device={kind("any"),arch(x86_64),isa(avx512f,avx512bw)})
+#pragma omp declare variant (f03) match 
(device={arch(x86_64),isa(avx512f,avx512bw)})
 void f04 (void);
 void f05 (void);
 #pragma omp declare variant (f05) match (device={kind(gpu)})
@@ -28,7 +28,7 @@ void f15 (void);
 #pragma omp declare variant (f15) match (device={isa(sse4,ssse3),arch(i386)})
 void f16 (void);
 void f17 (void);
-#pragma omp declare variant (f17) match (device={kind(any,fpga)})
+#pragma omp declare variant (f17) match (device={kind(fpga)})
 void f18 (void);
 
 #pragma omp declare target
diff --git a/gcc/testsuite/c-c++-common/gomp/declare-variant-3.c 
b/gcc/testsuite/c-c++-common/gomp/declare-variant-3.c
index f5

[PATCH 04/12] OpenMP: C front end support for metadirectives

2024-05-04 Thread Sandra Loosemore
This patch adds support to the C front end to parse OpenMP metadirective
constructs.  It includes support for early parse-time resolution
of metadirectives (when possible) that will also be used by the C++ front
end.

Additional common C/C++ testcases are in a later patch in the series.

gcc/c-family/ChangeLog
* c-common.h (enum c_omp_directive_kind): Add C_OMP_DIR_META.
(c_omp_expand_metadirective): Declare.
* c-gimplify.cc: Include omp-general.h.
(genericize_omp_metadirective_stmt): New.
(c_genericize_control_stmt): Call it.
* c-omp.cc (c_omp_directives): Add "metadirective" and fix
commented-out stubs for the begin/end form.
(c_omp_expand_metadirective_r): New.
(c_omp_expand_metadirective): New.
* c-pragma.cc (omp_pragmas): Add "metadirective".
* c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_METADIRECTIVE.

gcc/c/ChangeLog
* c-parser.cc (struct c_parser): Add new fields for metadirectives.
(c_parser_skip_to_end_of_block_or_statement):  Add metadirective_p
parameter; use it to control brace and parentheses behavior.
(mangle_metadirective_region_label): New.
(c_parser_label, c_parser_statement_after_labels): Use it.
(c_parser_pragma): Handle metadirective.
(c_parser_omp_context_selector): Add metadirective_p flag, use it
to gate support for non-constant user condition.
(c_parser_omp_context_selector_specification): Add metadirective_p
argument.
(c_parser_finish_omp_declare_variant): Adjust call to above.
(analyze_metadirective_body): New.
(c_parser_omp_metadirective): New.

gcc/testsuite/ChangeLog
* gcc.dg/gomp/metadirective-1.c: New.

Co-Authored-By: Kwok Cheung Yeung 
Co-Authored-By: Sandra Loosemore 
---
 gcc/c-family/c-common.h |   4 +-
 gcc/c-family/c-gimplify.cc  |  27 ++
 gcc/c-family/c-omp.cc   |  60 ++-
 gcc/c-family/c-pragma.cc|   1 +
 gcc/c-family/c-pragma.h |   1 +
 gcc/c/c-parser.cc   | 489 +++-
 gcc/testsuite/gcc.dg/gomp/metadirective-1.c |  15 +
 7 files changed, 577 insertions(+), 20 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/gomp/metadirective-1.c

diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 2d5f5399885..03f62571531 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1391,7 +1391,8 @@ enum c_omp_directive_kind {
   C_OMP_DIR_CONSTRUCT,
   C_OMP_DIR_DECLARATIVE,
   C_OMP_DIR_UTILITY,
-  C_OMP_DIR_INFORMATIONAL
+  C_OMP_DIR_INFORMATIONAL,
+  C_OMP_DIR_META
 };
 
 struct c_omp_directive {
@@ -1405,6 +1406,7 @@ extern const struct c_omp_directive c_omp_directives[];
 extern const struct c_omp_directive *c_omp_categorize_directive (const char *,
 const char *,
 const char *);
+extern tree c_omp_expand_metadirective (vec &);
 
 /* Return next tree in the chain for chain_next walking of tree nodes.  */
 inline tree
diff --git a/gcc/c-family/c-gimplify.cc b/gcc/c-family/c-gimplify.cc
index 494da49791d..c53aca60bcf 100644
--- a/gcc/c-family/c-gimplify.cc
+++ b/gcc/c-family/c-gimplify.cc
@@ -43,6 +43,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "context.h"
 #include "tree-pass.h"
 #include "internal-fn.h"
+#include "omp-general.h"
 
 /*  The gimplification pass converts the language-dependent trees
 (ld-trees) emitted by the parser into language-independent trees
@@ -485,6 +486,27 @@ genericize_omp_for_stmt (tree *stmt_p, int *walk_subtrees, 
void *data,
   finish_bc_block (&OMP_FOR_BODY (stmt), bc_continue, clab);
 }
 
+/* Genericize a OMP_METADIRECTIVE node *STMT_P.  */
+
+static void
+genericize_omp_metadirective_stmt (tree *stmt_p, int *walk_subtrees,
+  void *data, walk_tree_fn func,
+  walk_tree_lh lh)
+{
+  tree stmt = *stmt_p;
+
+  for (tree variant = OMP_METADIRECTIVE_VARIANTS (stmt);
+   variant != NULL_TREE;
+   variant = TREE_CHAIN (variant))
+{
+  walk_tree_1 (&OMP_METADIRECTIVE_VARIANT_DIRECTIVE (variant),
+  func, data, NULL, lh);
+  walk_tree_1 (&OMP_METADIRECTIVE_VARIANT_BODY (variant),
+  func, data, NULL, lh);
+}
+
+  *walk_subtrees = 0;
+}
 
 /* Lower structured control flow tree nodes, such as loops.  The
STMT_P, WALK_SUBTREES, and DATA arguments are as for the walk_tree_fn
@@ -533,6 +555,11 @@ c_genericize_control_stmt (tree *stmt_p, int 
*walk_subtrees, void *data,
   genericize_omp_for_stmt (stmt_p, walk_subtrees, data, func, lh);
   break;
 
+case OMP_METADIRECTIVE:
+  genericize_omp_metadirective_stmt (stmt_p, walk_subtrees, data, func,
+lh);
+  break;
+

[PATCH 12/12] OpenMP: Update documentation of metadirective implementation status.

2024-05-04 Thread Sandra Loosemore
libgomp/ChangeLog
* libgomp.texi (OpenMP 5.0): Mark metadirective and declare variant
as implemented.
(OpenMP 5.1): Mark target_device as supported.
Add changed interaction between declare target and OpenMP context
and dynamic selector support.
(OpenMP 5.2): Mark otherwise clause as supported, note that
default is also still accepted.
---
 libgomp/libgomp.texi | 21 ++---
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi
index 43048da4d6e..af7af63c504 100644
--- a/libgomp/libgomp.texi
+++ b/libgomp/libgomp.texi
@@ -192,9 +192,8 @@ The OpenMP 4.5 specification is fully supported.
 @item Array shaping @tab N @tab
 @item Array sections with non-unit strides in C and C++ @tab N @tab
 @item Iterators @tab Y @tab
-@item @code{metadirective} directive @tab N @tab
-@item @code{declare variant} directive
-  @tab P @tab @emph{simd} traits not handled correctly
+@item @code{metadirective} directive @tab Y @tab
+@item @code{declare variant} directive @tab Y @tab
 @item @var{target-offload-var} ICV and @code{OMP_TARGET_OFFLOAD}
   env variable @tab Y @tab
 @item Nested-parallel changes to @var{max-active-levels-var} ICV @tab Y @tab
@@ -289,8 +288,8 @@ The OpenMP 4.5 specification is fully supported.
 @headitem Description @tab Status @tab Comments
 @item OpenMP directive as C++ attribute specifiers @tab Y @tab
 @item @code{omp_all_memory} reserved locator @tab Y @tab
-@item @emph{target_device trait} in OpenMP Context @tab N @tab
-@item @code{target_device} selector set in context selectors @tab N @tab
+@item @emph{target_device trait} in OpenMP Context @tab Y
+@item @code{target_device} selector set in context selectors @tab Y @tab
 @item C/C++'s @code{declare variant} directive: elision support of
   preprocessed code @tab N @tab
 @item @code{declare variant}: new clauses @code{adjust_args} and
@@ -366,6 +365,12 @@ to address of matching mapped list item per 5.1, Sect. 
2.21.7.2 @tab N @tab
 @item @code{device_type(nohost)}/@code{device_type(host)} for variables @tab N 
@tab
 @item @code{present} modifier to the @code{map}, @code{to} and @code{from}
   clauses @tab Y @tab
+@item Changed interaction between @code{declare target} and OpenMP context
+  @tab Y @tab
+@item Dynamic selector support in @code{metadirective} @tab Y @tab
+@item Dynamic selector support in @code{declare variant} @tab P
+  @tab Fortran rejects non-constant expressions in dynamic selectors;
+  C/C++ reject expressions using argument variables.
 @end multitable
 
 
@@ -413,8 +418,10 @@ to address of matching mapped list item per 5.1, Sect. 
2.21.7.2 @tab N @tab
 @item Deprecation of traits array following the allocator_handle expression in
   @code{uses_allocators} @tab N @tab
 @item New @code{otherwise} clause as alias for @code{default} on metadirectives
-  @tab N @tab
-@item Deprecation of @code{default} clause on metadirectives @tab N @tab
+  @tab Y @tab
+@item Deprecation of @code{default} clause on metadirectives @tab N
+  @tab Both @code{otherwise} and @code{default} are accepted
+  without diagnostics.
 @item Deprecation of delimited form of @code{declare target} @tab N @tab
 @item Reproducible semantics changed for @code{order(concurrent)} @tab N @tab
 @item @code{allocate} and @code{firstprivate} clauses on @code{scope}
-- 
2.25.1



[PATCH 03/12] libgomp: runtime support for target_device selector

2024-05-04 Thread Sandra Loosemore
This patch implements the libgomp runtime support for the dynamic
target_device selector via the GOMP_evaluate_target_device function.

include/ChangeLog
* cuda/cuda.h (CUdevice_attribute): Add definitions for
CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR and
CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR.

libgomp/ChangeLog
* Makefile.am (libgomp_la_SOURCES): Add selector.c.
* Makefile.in: Regenerate.
* config/gcn/selector.c: New.
* config/linux/selector.c: New.
* config/linux/x86/selector.c: New.
* config/nvptx/selector.c: New.
* libgomp-plugin.h (GOMP_OFFLOAD_evaluate_device): New.
* libgomp.h (struct gomp_device_descr): Add evaluate_device_func field.
* libgomp.map (GOMP_5.1.3): New, add GOMP_evaluate_target_device.
* libgomp.texi (OpenMP Context Selectors): Document dynamic selector
matching of kind/arch/isa.
* libgomp_g.h (GOMP_evaluate_current_device): New.
(GOMP_evaluate_target_device): New.
* oacc-host.c (host_evaluate_device): New.
(host_openacc_exec): Initialize evaluate_device_func field to
host_evaluate_device.
* plugin/plugin-gcn.c (gomp_match_selectors): New.
(gomp_match_isa): New.
(GOMP_OFFLOAD_evaluate_device): New.
* plugin/plugin-nvptx.c (struct ptx_device): Add compute_major and
compute_minor fields.
(nvptx_open_device): Read compute capability information from device.
(gomp_match_selectors): New.
(gomp_match_selector): New.
(CHECK_ISA): New macro.
(GOMP_OFFLOAD_evaluate_device): New.
* selector.c: New.
* target.c (GOMP_evaluate_target_device): New.
(gomp_load_plugin_for_device): Load evaluate_device plugin function.

Co-Authored-By: Kwok Cheung Yeung 
Co-Authored-By: Sandra Loosemore 
---
 include/cuda/cuda.h |   2 +
 libgomp/Makefile.am |   2 +-
 libgomp/Makefile.in |   5 +-
 libgomp/config/gcn/selector.c   | 102 +++
 libgomp/config/linux/selector.c |  65 +
 libgomp/config/linux/x86/selector.c | 406 
 libgomp/config/nvptx/selector.c |  77 ++
 libgomp/libgomp-plugin.h|   2 +
 libgomp/libgomp.h   |   1 +
 libgomp/libgomp.map |   5 +
 libgomp/libgomp.texi|  18 +-
 libgomp/libgomp_g.h |   8 +
 libgomp/oacc-host.c |  11 +
 libgomp/plugin/plugin-gcn.c |  52 
 libgomp/plugin/plugin-nvptx.c   |  82 ++
 libgomp/selector.c  |  64 +
 libgomp/target.c|  40 +++
 17 files changed, 936 insertions(+), 6 deletions(-)
 create mode 100644 libgomp/config/gcn/selector.c
 create mode 100644 libgomp/config/linux/selector.c
 create mode 100644 libgomp/config/linux/x86/selector.c
 create mode 100644 libgomp/config/nvptx/selector.c
 create mode 100644 libgomp/selector.c

diff --git a/include/cuda/cuda.h b/include/cuda/cuda.h
index 0dca4b3a5c0..a775450df03 100644
--- a/include/cuda/cuda.h
+++ b/include/cuda/cuda.h
@@ -83,6 +83,8 @@ typedef enum {
   CU_DEVICE_ATTRIBUTE_MAX_THREADS_PER_MULTIPROCESSOR = 39,
   CU_DEVICE_ATTRIBUTE_ASYNC_ENGINE_COUNT = 40,
   CU_DEVICE_ATTRIBUTE_UNIFIED_ADDRESSING = 41,
+  CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR = 75,
+  CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR = 76,
   CU_DEVICE_ATTRIBUTE_MAX_REGISTERS_PER_MULTIPROCESSOR = 82
 } CUdevice_attribute;
 
diff --git a/libgomp/Makefile.am b/libgomp/Makefile.am
index 1871590596d..87658da2d5d 100644
--- a/libgomp/Makefile.am
+++ b/libgomp/Makefile.am
@@ -72,7 +72,7 @@ libgomp_la_SOURCES = alloc.c atomic.c barrier.c critical.c 
env.c error.c \
target.c splay-tree.c libgomp-plugin.c oacc-parallel.c oacc-host.c \
oacc-init.c oacc-mem.c oacc-async.c oacc-plugin.c oacc-cuda.c \
priority_queue.c affinity-fmt.c teams.c allocator.c oacc-profiling.c \
-   oacc-target.c target-indirect.c
+   oacc-target.c target-indirect.c selector.c
 
 include $(top_srcdir)/plugin/Makefrag.am
 
diff --git a/libgomp/Makefile.in b/libgomp/Makefile.in
index 11480d6a953..30e57571404 100644
--- a/libgomp/Makefile.in
+++ b/libgomp/Makefile.in
@@ -219,7 +219,7 @@ am_libgomp_la_OBJECTS = alloc.lo atomic.lo barrier.lo 
critical.lo \
oacc-parallel.lo oacc-host.lo oacc-init.lo oacc-mem.lo \
oacc-async.lo oacc-plugin.lo oacc-cuda.lo priority_queue.lo \
affinity-fmt.lo teams.lo allocator.lo oacc-profiling.lo \
-   oacc-target.lo target-indirect.lo $(am__objects_1)
+   oacc-target.lo target-indirect.lo selector.lo $(am__objects_1)
 libgomp_la_OBJECTS = $(am_libgomp_la_OBJECTS)
 AM_V_P = $(am__v_P_@AM_V@)
 am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
@@ -552,7 +552,7 @@ libgomp_la_SOURCES = alloc.c atomic.c barrier.c critical.c 
env.c \
oacc-parallel.c oacc-host.c oacc-init.c oacc-mem.c \
oacc-async.c oa

[PATCH 02/12] OpenMP: middle-end support for metadirectives

2024-05-04 Thread Sandra Loosemore
This patch adds middle-end support for OpenMP metadirectives.  Some
context selectors can be resolved during gimplification, but others need to
be deferred until the omp_device_lower pass, which requires that cgraph,
LTO streaming, inlining, etc all know about this construct as well.

gcc/ChangeLog
* cgraph.h (struct cgraph_node): Add has_metadirectives flag.
* cgraphclones.cc (cgraph_node::create_clone): Copy has_metadirectives
flag.
* doc/gimple.texi (Class hierarchy of GIMPLE statements): Document
gomp_metadirective and gomp_variant.
* gimple-low.cc (lower_omp_metadirective): New.
(lower_stmt): Call it.
* gimple-pretty-print.cc (dump_gimple_omp_metadirective): New.
(pp_gimple_stmt_1): Call it.
* gimple-streamer-in.cc (input_gimple_stmt): Handle
GIMPLE_OMP_METADIRECTIVE.
* gimple-streamer-out.cc (output_gimple_stmt): Likewise.
* gimple-walk.cc (walk_gimple_op): Likewise.
(walk_gimple_stmt): Likewise.
* gimple.cc (gimple_alloc_omp_metadirective): New.
(gimple_build_omp_metadirective): New.
(gimple_build_omp_variant): New.
* gimple.def (GIMPLE_OMP_METADIRECTIVE): New.
(GIMPLE_OMP_METADIRECTIVE_VARIANT): New.
* gimple.h (gomp_variant, gomp_metadirective): New.
(is_a_helper ::test): New.
(is_a_helper ::test): New.
(is_a_helper ::test): New.
(is_a_helper ::test): New.
(gimple_alloc_omp_metadirective): New.
(gimple_build_omp_metadirective): New.
(gimple_build_omp_variant): New.
(gimple_has_substatements): Handle GIMPLE_OMP_METADIRECTIVE.
(gimple_has_ops): Likewise.
(gimple_omp_metadirective_label): New.
(gimple_omp_metadirective_set_label): New.
(gimple_omp_variants): New.
(gimple_omp_metadirective_set_variants): New.
(gimple_return_set_retval): Handle GIMPLE_OMP_METADIRECTIVE.
* gimplify.cc (is_gimple_stmt): HANDLE OMP_METADIRECTIVE.
(expand_omp_metadirective): New.
(gimplify_omp_metadirective): New.
(gimplify_expr): Call it.
* gsstruct.def (GSS_OMP_METADIRECTIVE): New.
(GSS_OMP_METADIRECTIVE_VARIANT): New.
* lto-cgraph.cc (lto_output_node): Handle has_metadirectives flag.
(input_overwrite_node): Likewise.
* omp-expand.cc (expand_omp_target): Propagate has_metadirectives
flag.
(build_omp_regions_1): Handle GIMPLE_OMP_METADIRECTIVE.
(omp_make_gimple_edges): Likewise.
* omp-general.cc (omp_late_resolve_metadirective): New.
* omp-general.h (omp_late_resolve_metadirective): Declare.
* omp-low.cc (struct omp_context): Add next_clone field.
(new_omp_context): Handle next_clone field.
(clone_omp_context): New.
(delete_omp_context): Delete clones.
(create_omp_child_function): Propagate has_metadirectives bit.
(scan_omp_metadirective): New.
(scan_omp_1_stmt): Handle GIMPLE_OMP_METADIRECTIVE.
(lower_omp_metadirective): New.
(lower_omp_1): Handle GIMPLE_OMP_METADIRECTIVE.  Warn about
direct calls to offloadable functions containing metadirectives.
* omp-offload.cc: Include cfganal.h and cfghooks.h.
(omp_expand_metadirective): New.
(execute_omp_device_lower): Handle metadirectives.
(pass_omp_device_lower::gate):  Check has_metadirectives bit.
* omp-simd-clone.cc (simd_clone_create): Propagate has_metadirectives
flag.
* tree-cfg.cc (cleanup_dead_labels): Handle GIMPLE_OMP_METADIRECTIVE.
(gimple_redirect_edge_and_branch): Likewise.
* tree-inline.cc (remap_gimple_stmt): Handle GIMPLE_OMP_METADIRECTIVE.
(estimate_num_instructions): Likewise.
(expand_call_inline): Propagate has_metadirectives flag.
(tree_function_versioning): Likewise.
* tree-ssa-operands.cc: Include omp-general.h.
(operands_scanner::parse_ssa_operands): Handle
GIMPLE_OMP_METADIRECTIVE.

Co-Authored-By: Kwok Cheung Yeung 
Co-Authored-By: Sandra Loosemore 
Co-Authored-By: Marcel Vollweiler 
---
 gcc/cgraph.h   |   3 +
 gcc/cgraphclones.cc|   1 +
 gcc/doc/gimple.texi|   6 ++
 gcc/gimple-low.cc  |  36 
 gcc/gimple-pretty-print.cc |  64 +
 gcc/gimple-streamer-in.cc  |  10 ++
 gcc/gimple-streamer-out.cc |   6 ++
 gcc/gimple-walk.cc |  28 ++
 gcc/gimple.cc  |  35 +++
 gcc/gimple.def |   7 ++
 gcc/gimple.h   | 100 +++-
 gcc/gimplify.cc| 184 +
 gcc/gsstruct.def   |   2 +
 gcc/lto-cgraph.cc  |   2 +
 gcc/omp-expand.cc  |  30 ++
 gcc/omp-general.cc |  22 +
 gcc/omp-general.h  |   1 +
 gcc/omp-low.cc |  83 +
 gcc/omp-offload.cc | 105 

[PATCH 01/12] OpenMP: metadirective tree data structures and front-end interfaces

2024-05-04 Thread Sandra Loosemore
This patch adds the OMP_METADIRECTIVE tree node and shared tree-level
support for manipulating metadirectives.  It defines/exposes
interfaces that will be used in subsequent patches that add front-end
and middle-end support, but nothing generates these nodes yet.

This patch also adds compile-time support for dynamic context
selectors (the target_device selector set and the condition selector
of the user selector set) for metadirectives only.  The "declare
variant" directive still supports only static selectors.

gcc/ChangeLog
* Makefile.in (GTFILES): Move omp-general.h earlier in the list.
* builtin-types.def (BT_FN_BOOL_INT_CONST_PTR_CONST_PTR_CONST_PTR):
New.
* doc/generic.texi (OpenMP): Document OMP_METADIRECTIVE and
context selector interfaces.
* omp-builtins.def (BUILT_IN_GOMP_EVALUATE_TARGET_DEVICE): New.
* omp-general.cc (omp_check_context_selector): Add metadirective_p
parameter, use it to conditionalize target_device support.
(make_omp_metadirective_variant): New.
(omp_context_selector_matches): Add metadirective_p and delay_p
parameters, use them to control things that can only be matched
late.  Handle OMP_TRAIT_SET_TARGET_DEVICE.
(score_wide_int): Move definition to omp-general.h.
(omp_encode_kind_arch_isa_props): New.
(omp_dynamic_cond): New.
(omp_context_compute_score): Handle OMP_TRAIT_SET_TARGET_DEVICE.
(omp_resolve_late_declare_variant, omp_resolve_declare_variant):
Adjust calls to omp_context_selector_matches.
(sort_variant): New.
(omp_get_dynamic_candidates): New.
(omp_early_resolve_metadirective): New.
* omp-general.h (score_wide_int): Moved here from omp-general.cc.
(struct omp_variant): New.
(OMP_METADIRECTIVE_VARIANT_SELECTOR): New.
(OMP_METADIRECTIVE_VARIANT_DIRECTIVE): New.
(OMP_METADIRECTIVE_VARIANT_BODY): New.
(make_omp_metadirective_variant): Declare.
(omp_check_context_selector): Adjust to match definition.
(omp_context_selector_matches): Likewise.
(omp_early_resolve_metadirective): New.
* tree-pretty-print.cc (dump_omp_context_selector): Remove
static qualifier.
(dump_generic_node): Handle OMP_METADIRECTIVE.
* tree-pretty-print.h (dump_omp_context_selector): Declare.
* tree.def (OMP_METADIRECTIVE): New.
* tree.h (OMP_METADIRECTIVE_VARIANTS): New.

gcc/c/ChangeLog
* c-parser.cc (c_finish_omp_declare_variant): Update calls to
omp_check_context_selector and omp_context_selector_matches.

gcc/cp/ChangeLog
* decl.cc (omp_declare_variant_finalize_one):  Update call to
omp_context_selector_matches to pass additional arguments.
* parser.cc (cp_finish_omp_declare_variant): Likewise for
omp_check_context_selector.

gcc/fortran/ChangeLog
* trans-openmp.cc (gfc_trans_omp_declare_variant):  Update calls to
omp_check_context_selector and omp_context_selector_matches.
* types.def (BT_FN_BOOL_INT_CONST_PTR_CONST_PTR_CONST_PTR): New.

Co-Authored-By: Kwok Cheung Yeung 
Co-Authored-By: Sandra Loosemore 
---
 gcc/Makefile.in |   2 +-
 gcc/builtin-types.def   |   2 +
 gcc/c/c-parser.cc   |   4 +-
 gcc/cp/decl.cc  |   2 +-
 gcc/cp/parser.cc|   2 +-
 gcc/doc/generic.texi|  32 
 gcc/fortran/trans-openmp.cc |   4 +-
 gcc/fortran/types.def   |   2 +
 gcc/omp-builtins.def|   3 +
 gcc/omp-general.cc  | 357 ++--
 gcc/omp-general.h   |  31 +++-
 gcc/tree-pretty-print.cc|  36 +++-
 gcc/tree-pretty-print.h |   2 +
 gcc/tree.def|   6 +
 gcc/tree.h  |   3 +
 15 files changed, 461 insertions(+), 27 deletions(-)

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index a74761b7ab3..65638c7b5d6 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -2868,6 +2868,7 @@ GTFILES = $(CPPLIB_H) $(srcdir)/input.h 
$(srcdir)/coretypes.h \
   $(srcdir)/tree-ssa-operands.h \
   $(srcdir)/tree-profile.cc $(srcdir)/tree-nested.cc \
   $(srcdir)/omp-offload.h \
+  $(srcdir)/omp-general.h \
   $(srcdir)/omp-general.cc \
   $(srcdir)/omp-low.cc \
   $(srcdir)/targhooks.cc $(out_file) $(srcdir)/passes.cc \
@@ -2894,7 +2895,6 @@ GTFILES = $(CPPLIB_H) $(srcdir)/input.h 
$(srcdir)/coretypes.h \
   $(srcdir)/ipa-strub.cc \
   $(srcdir)/internal-fn.h \
   $(srcdir)/calls.cc \
-  $(srcdir)/omp-general.h \
   $(srcdir)/analyzer/analyzer-language.cc \
   @all_gtfiles@
 
diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def
index c97d6bad1de..605a38ab84d 100644
--- a/gcc/builtin-types.def
+++ b/gcc/builtin-types.def
@@ -878,6 +878,8 @@ DEF_FUNCTION_TYPE_4 (BT_FN_VOID_UINT_PTR_INT_PTR, BT_VOID, 
BT_INT, BT_PTR,
 BT_INT, BT_PTR)
 DEF_FUNCTION_TYPE_4 (BT_FN_BOOL_UINT_UINT_UINT_BOOL,
 BT_BOO

[PATCH 00/12] OpenMP: Metadirective support + "declare variant" improvements

2024-05-04 Thread Sandra Loosemore
This series of patches is a revised and extended version of the metadirective
patches I previously posted in January:

https://gcc.gnu.org/pipermail/gcc-patches/2024-January/642005.html

Those in turn were based on work by Kwok originally implemented on the
devel/omp/gcc-11 branch in 2021 and previously submitted for mainline 3+
years ago.

The current set comprises 12 parts.  Parts 1-7 are fairly close to the
January patch set, but incorporating a number of bug fixes and
revisions for the review comments from Tobias.  Part 3, in particular,
has a lot of changes to address both a buggy interface between the
compiler and libgomp, and Tobias's comments about bit-rotten target
support.

Parts 8-11 are new.  Part 9 is a big patch that merges the dynamic selector
support to "declare variant", revises internal interfaces, and also fixes
PR114596 and other bugs relating to matching and scoring.  The other pieces
are more self-contained fixes and improvements.

Part 12 is an updated patch for the implementation status table in the
libgomp manual.

As a general overview of what has changed here relative to the January patch
set:

* The dynamic selector support added for metadirective has been
  integrated with declare variant; both directives now use common data
  structures and scoring/sorting code.  In particular, for calls to
  "declare variant" functions that cannot be resolved during
  gimplification, it now creates the same gimple structure used by
  metadirective instead of using a magic placeholder symbol, and all
  the support code used to track and process the placeholders has been
  removed.

* Along the way, I found/fixed a serious bug in the resolution code in
  the previously-posted metadirective patches; it was not saving
  information about the OpenMP context needed to match/score construct
  selectors during gimplification for use in late resolution, and
  instead incorrectly calling the function dependent on being invoked
  during gimplification during late resolution.  It was also failing
  to account for "declare simd"'s effect on scoring.

* I also found/fixed a serious bug in the existing mainline "declare
  variant" scoring code that also affected the previous version of the
  metadirective patches (PR 114596).

* Overall I tried to improve the software engineering aspect of the
  scoring and matching code, making it better-documented and easier to
  follow and correlate to the OpenMP specification.

* In the Fortran front end, I moved the filtering-out of metadirective
  variants that can't possibly match from the parsing phase to the
  translation phase, following Tobias's recommendation.

* I've updated the logic for when "declare target" adds a target
  construct selector to the OpenMP context to follow recent versions
  of the spec (the implementation now on mainline was for the language
  in the 5.0 spec).

* For both metadirective and declare variant, when the gimplifier
  processes metadirectives/calls that can't be resolved at that time,
  it now filters out the variants that can't possibly match instead of
  preserving all of them for late resolution, which might produce
  better optimization opportunities.  (The front ends already do this
  once at parse time, but additional info is available during
  gimplification that may allow additional variants to be discarded.)

* I fixed some bit-rot in the libgomp support for the target_device
  selector, and adjusted the interface between the compiler and libgomp
  to correctly handle selectors with multiple properties (previously it
  was only handling the first one).

* I also added a diagnostic for requirement from the spec that
  kind(any) cannot be used with any other properties.  It turns out
  there were multiple testcases that incorrectly did this.

In terms of what remains to be done:

* There is one test regression in libgomp, declare-variant-1.f90 hangs
  during execution at -O0 only.  I looked at this briefly but didn't make
  any progress on debugging it.

* I haven't solved the issues discussed in issue PR113904 about the
  scoping of expressions in "declare variant" dynamic selectors.  For
  C and C++, I have a good idea of how to implement the provisions in
  the spec that allow references to argument variables of the variant
  function.  For now it diagnoses this with a "sorry"; meanwhile it
  *does* parse the argument variables in the correct scope, and
  correctly handles other symbols in scope, including class members
  and "this" in C++.  For Fortran, I'm unsure of the semantics, and
  for "declare variant" it currently rejects non-constant expressions
  in dynamic selectors.

I think both of those issues could be addressed with follow-up
patches.  This is already a large and complicated patch set, and I
hope that by submitting it for review early in stage 1 it will be
possible to get at least some parts of it committed in a timely manner
and reduce the burden of maintaining these patches out of tree.

-Sandra

Sandra

Fix gnu versioned namespace mode 02/03

2024-05-04 Thread François Dumont

    libstdc++: [_GLIBCXX_INLINE_VERSION] Use cxx11 abi [PR83077]

    Use cxx11 abi when activating versioned namespace mode. To do so 
support a new
    configuration mode where !_GLIBCXX_USE_DUAL_ABI and 
_GLIBCXX_USE_CXX11_ABI.


    The main change is that std::__cow_string is now defined whenever 
_GLIBCXX_USE_DUAL_ABI
    or _GLIBCXX_USE_CXX11_ABI is true. Implementation is using 
available std::string in

    case of dual abi and a subset of it when it's not.

    libstdcxx-v3/ChangeLog:

    PR libstdc++/83077
    * acinclude.m4 [GLIBCXX_ENABLE_LIBSTDCXX_DUAL_ABI]: Default 
to "new" libstdcxx abi

    when enable_symvers is gnu-versioned-namespace.
    * config/locale/dragonfly/monetary_members.cc 
[!_GLIBCXX_USE_DUAL_ABI]: Define money_base

    members.
    * config/locale/generic/monetary_members.cc 
[!_GLIBCXX_USE_DUAL_ABI]: Likewise.
    * config/locale/gnu/monetary_members.cc 
[!_GLIBCXX_USE_DUAL_ABI]: Likewise.

    * config/locale/gnu/numeric_members.cc
    [!_GLIBCXX_USE_DUAL_ABI](__narrow_multibyte_chars): Define.
    * configure: Regenerate.
    * include/bits/c++config
    [_GLIBCXX_INLINE_VERSION](_GLIBCXX_NAMESPACE_CXX11, 
_GLIBCXX_BEGIN_NAMESPACE_CXX11):

    Define empty.
[_GLIBCXX_INLINE_VERSION](_GLIBCXX_END_NAMESPACE_CXX11, 
_GLIBCXX_DEFAULT_ABI_TAG):

    Likewise.
    * include/bits/cow_string.h: Remove _GLIBCXX_USE_CXX11_ABI 
macro condition. Replace
_GLIBCXX_BEGIN_NAMESPACE_VERSION/_GLIBCXX_END_NAMESPACE_VERSION by 
__detail namespace.

    * include/std/stdexcept
    [_GLIBCXX_USE_DUAL_ABI || 
_GLIBCXX_USE_CXX11_ABI](__cow_string): Define.

    (__cow_string::c_str()): New.
    * python/libstdcxx/v6/printers.py 
(StdStringPrinter::__init__): Set self.new_string to True

    when std::__8::basic_string type is found.
    * src/Makefile.am 
[ENABLE_SYMVERS_GNU_NAMESPACE](ldbl_alt128_compat_sources): Define empty.

    * src/Makefile.in: Regenerate.
    * src/c++11/Makefile.am (cxx11_abi_sources): Rename into...
    (dual_abi_sources): ...this. Also move cow-local_init.cc, 
cxx11-hash_tr1.cc,

    cxx11-ios_failure.cc entries to...
    (sources): ...this.
    (extra_string_inst_sources): Move cow-fstream-inst.cc, 
cow-sstream-inst.cc, cow-string-inst.cc,
    cow-string-io-inst.cc, cow-wtring-inst.cc, 
cow-wstring-io-inst.cc, cxx11-locale-inst.cc,

    cxx11-wlocale-inst.cc entries to...
    (inst_sources): ...this.
    * src/c++11/Makefile.in: Regenerate.
    * src/c++11/cow-fstream-inst.cc [_GLIBCXX_USE_CXX11_ABI]: 
Skip content.
    * src/c++11/cow-locale_init.cc [_GLIBCXX_USE_CXX11_ABI]: 
Skip content.

    [!_GLIBCXX_USE_DUAL_ABI](locale::name()): Skip definition.
    * src/c++11/cow-sstream-inst.cc [_GLIBCXX_USE_CXX11_ABI]: 
Skip content.
    * src/c++11/cow-stdexcept.cc [_GLIBCXX_USE_CXX11_ABI]: 
Include .
    [_GLIBCXX_USE_DUAL_ABI || 
_GLIBCXX_USE_CXX11_ABI](__cow_string): Redefine before
    including . Define 
_GLIBCXX_DEFINE_STDEXCEPT_INSTANTIATIONS so that

    __cow_string definition in  is skipped.
    (__cow_string::c_str()): Define.
    [_GLIBCXX_USE_CXX11_ABI]: Skip Transaction Memory TS 
definitions.

    * src/c++11/cow-string-inst.cc
    [!_GLIBCXX_USE_DUAL_ABI || _GLIBCXX_USE_CXX11_ABI]: Skip 
content.
    * src/c++11/cow-string-io-inst.cc [_GLIBCXX_USE_CXX11_ABI]: 
Skip content.
    * src/c++11/cow-wstring-inst.cc [_GLIBCXX_USE_CXX11_ABI]: 
Skip content.
    * src/c++11/cow-wstring-io-inst.cc 
[_GLIBCXX_USE_CXX11_ABI]: Skip content.
    * src/c++11/cxx11-hash_tr1.cc [!_GLIBCXX_USE_CXX11_ABI]: 
Skip content.
    * src/c++11/cxx11-ios_failure.cc [!_GLIBCXX_USE_CXX11_ABI]: 
Skip content.

    [!_GLIBCXX_USE_DUAL_ABI] (__ios_failure): Remove.
    * src/c++11/cxx11-locale-inst.cc: Cleanup, just include 
locale-inst.cc.
    * src/c++11/cxx11-stdexcept.cc [!_GLIBCXX_USE_CXX11_ABI]: 
Skip definitions.
    * src/c++11/cxx11-wlocale-inst.cc 
[!_GLIBCXX_USE_CXX11_ABI]: Skip definitions.

    * src/c++11/locale-inst-numeric.h
[!_GLIBCXX_USE_DUAL_ABI](std::use_facet>, 
std::use_facet>): Instantiate.
[!_GLIBCXX_USE_DUAL_ABI](std::has_facet>, 
std::has_facet>): Instantiate.
    [!_GLIBCXX_USE_DUAL_ABI](std::num_getistreambuf_iterator>): Instantiate.
    [!_GLIBCXX_USE_DUAL_ABI](std::num_putostreambuf_iterator>): Instantiate.
    * src/c++11/locale-inst.cc [!_GLIBCXX_USE_DUAL_ABI]: Build 
only when configured

    _GLIBCXX_USE_CXX11_ABI is equal to currently built abi.
    [!_GLIBCXX_USE_DUAL_ABI](__moneypunct_cache): 
Instantiate.
    [!_GLIBCXX_USE_DUAL_ABI](__moneypunct_cache): 
Instantiate.

    

Fix gnu versioned namespace mode 03/03

2024-05-04 Thread François Dumont

    libstdc++: Review configuration options to control abi

    --disable-libstdcxx-dual-abi default to 'new' abi mode.

    --with-default-libstdcxx-abi consider the requested abi mode regardless
    of --disable-libstdcxx-dual-abi usage.

    libstdc++-v3/ChangeLog

    * acinclude.m4 (GLIBCXX_ENABLE_LIBSTDCXX_DUAL_ABI): Set
    default_libstdcxx_abi to "new" when not using versioned 
namespace.
    (GLIBCXX_DEFAULT_ABI): Remove enable_libstdcxx_dual_abi=yes 
check.

    * configure: Regenerate.

Ok to commit ?

François

diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4
index 3da1d5f1a01..0ba755b08d2 100644
--- a/libstdc++-v3/acinclude.m4
+++ b/libstdc++-v3/acinclude.m4
@@ -4867,7 +4867,7 @@ dnl
 dnl Control whether the library should define symbols for old and new ABIs.
 dnl This affects definitions of strings, stringstreams and locale facets.
 dnl
-dnl --disable-libstdcxx-dual-abi will use old ABI for all types.
+dnl --disable-libstdcxx-dual-abi will use new ABI for all types.
 dnl
 dnl Defines:
 dnl  _GLIBCXX_USE_DUAL_ABI (always defined, either to 1 or 0)
@@ -4883,7 +4883,7 @@ AC_DEFUN([GLIBCXX_ENABLE_LIBSTDCXX_DUAL_ABI], [
   else
 if test x"$enable_libstdcxx_dual_abi" != xyes; then
   AC_MSG_NOTICE([dual ABI is disabled])
-  default_libstdcxx_abi="gcc4-compatible"
+  default_libstdcxx_abi="new"
 fi
   fi
   GLIBCXX_CONDITIONAL(ENABLE_DUAL_ABI, test $enable_libstdcxx_dual_abi = yes)
@@ -4898,7 +4898,6 @@ dnl Defines:
 dnl  _GLIBCXX_USE_CXX11_ABI (always defined, either to 1 or 0)
 dnl
 AC_DEFUN([GLIBCXX_DEFAULT_ABI], [
-  if test x$enable_libstdcxx_dual_abi = xyes; then
   AC_MSG_CHECKING([for default std::string ABI to use])
   AC_ARG_WITH([default-libstdcxx-abi],
 AS_HELP_STRING([--with-default-libstdcxx-abi],
@@ -4912,7 +4911,6 @@ AC_DEFUN([GLIBCXX_DEFAULT_ABI], [
  ],
 [default_libstdcxx_abi="new"])
   AC_MSG_RESULT(${default_libstdcxx_abi})
-  fi
   if test $default_libstdcxx_abi = "new"; then
 glibcxx_cxx11_abi=1
 glibcxx_cxx98_abi=0
diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure
index 341a8b2cb25..89201086507 100755
--- a/libstdc++-v3/configure
+++ b/libstdc++-v3/configure
@@ -51276,13 +51276,12 @@ $as_echo "$as_me: dual ABI is disabled" >&6;}
 if test x"$enable_libstdcxx_dual_abi" != xyes; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: dual ABI is disabled" >&5
 $as_echo "$as_me: dual ABI is disabled" >&6;}
-  default_libstdcxx_abi="gcc4-compatible"
+  default_libstdcxx_abi="new"
 fi
   fi
 
 
 
-  if test x$enable_libstdcxx_dual_abi = xyes; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for default std::string 
ABI to use" >&5
 $as_echo_n "checking for default std::string ABI to use... " >&6; }
 
@@ -51301,7 +51300,6 @@ fi
 
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${default_libstdcxx_abi}" 
>&5
 $as_echo "${default_libstdcxx_abi}" >&6; }
-  fi
   if test $default_libstdcxx_abi = "new"; then
 glibcxx_cxx11_abi=1
 glibcxx_cxx98_abi=0


Fix gnu versioned namespace mode 01/03

2024-05-04 Thread François Dumont

libstdc++: Bump gnu versioned namespace to __9

libstdc++-v3/ChangeLog:

    * acinclude.m4 (libtool_VERSION): Bump to 9:0:0.
    * config/abi/pre/gnu-versioned-namespace.ver (GLIBCXX_8.0): 
Replace by GLIBCXX_9.0.

    Adapt all references to __8 namespace.
    * configure: Regenerate.
    * include/bits/c++config 
(_GLIBCXX_BEGIN_NAMESPACE_VERSION): Define as 'namespace __9{'.

    (_GLIBCXX_STD_V): Adapt.
    * include/std/format (to_chars): Update namespace version 
in symbols alias definitions.
    (__format::_Arg_store): Update namespace version in 
make_format_args friend

    declaration.
    * python/libstdcxx/v6/printers.py (_versioned_namespace): 
Assign '__9::'.

    * python/libstdcxx/v6/xmethods.py: Likewise.
    * testsuite/23_containers/map/48101_neg.cc: Adapt dg-error.
    * testsuite/23_containers/multimap/48101_neg.cc: Likewise.
    * testsuite/20_util/function/cons/70692.cc: Likewise.
    * testsuite/20_util/function_objects/bind_back/111327.cc: 
Likewise.
    * testsuite/20_util/function_objects/bind_front/111327.cc: 
Likewise.
    * testsuite/lib/prune.exp (libstdc++-dg-prune): Bump 
version namespace.


Ok to commit ?

François
diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4
index 51a08bcc8b1..8978355a6d3 100644
--- a/libstdc++-v3/acinclude.m4
+++ b/libstdc++-v3/acinclude.m4
@@ -4243,7 +4243,7 @@ case $enable_symvers in
  [Define to use GNU versioning in the shared library.])
 ;;
   gnu-versioned-namespace)
-libtool_VERSION=8:0:0
+libtool_VERSION=9:0:0
 SYMVER_FILE=config/abi/pre/gnu-versioned-namespace.ver
 AC_DEFINE(_GLIBCXX_SYMVER_GNU_NAMESPACE, 1,
  [Define to use GNU namespace versioning in the shared library.])
diff --git a/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver 
b/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
index bdf8f40f1f6..d3d30b5bafa 100644
--- a/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
+++ b/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
@@ -19,7 +19,7 @@
 ## with this library; see the file COPYING3.  If not see
 ## .
 
-GLIBCXX_8.0 {
+GLIBCXX_9.0 {
 
   global:
 
@@ -27,7 +27,7 @@ GLIBCXX_8.0 {
 extern "C++"
 {
   std::*;
-  std::__8::*;
+  std::__9::*;
 };
 
 # operator new(size_t)
@@ -59,7 +59,7 @@ GLIBCXX_8.0 {
 # vtable
 _ZTVSt*;
 _ZTVNSt*;
-_ZTVN9__gnu_cxx3__818stdio_sync_filebufI[cw]NSt3__811char_traitsI[cw];
+_ZTVN9__gnu_cxx3__918stdio_sync_filebufI[cw]NSt3__911char_traitsI[cw];
 
 # thunk
 _ZTv0_n12_NS*;
@@ -74,7 +74,7 @@ GLIBCXX_8.0 {
 _ZTSNSt*;
 
 # locale
-_ZNSt3__89has_facetINS_*;
+_ZNSt3__99has_facetINS_*;
 
 # thread/mutex/condition_variable/future
 __once_proxy;
@@ -84,37 +84,37 @@ GLIBCXX_8.0 {
 __emutls_v._ZSt3__815__once_callable;
 
 # std::__convert_to_v
-_ZNSt3__814__convert_to_v*;
+_ZNSt3__914__convert_to_v*;
 
 # std::__copy_streambufs
-_ZNSt3__817__copy_streambufsI*;
-_ZNSt3__821__copy_streambufs_eofI*;
+_ZNSt3__917__copy_streambufsI*;
+_ZNSt3__921__copy_streambufs_eofI*;
 
 # std::__istream_extract(wistream&, wchar_t*, streamsize)
-
_ZNSt3__817__istream_extractIwNS_11char_traitsIwvRNS_13basic_istreamIT_T0_EEPS4_[ilx];
+
_ZNSt3__917__istream_extractIwNS_11char_traitsIwvRNS_13basic_istreamIT_T0_EEPS4_[ilx];
 
 # __gnu_cxx::__atomic_add
 # __gnu_cxx::__exchange_and_add
-_ZN9__gnu_cxx3__812__atomic_addEPV[il][il];
-_ZN9__gnu_cxx3__818__exchange_and_addEPV[li][il];
+_ZN9__gnu_cxx3__912__atomic_addEPV[il][il];
+_ZN9__gnu_cxx3__918__exchange_and_addEPV[li][il];
 
 # __gnu_cxx::__pool
-_ZN9__gnu_cxx3__86__poolILb[01]EE13_M_initializeEv;
-_ZN9__gnu_cxx3__86__poolILb[01]EE16_M_reserve_blockE[jmy][jmy];
-_ZN9__gnu_cxx3__86__poolILb[01]EE16_M_reclaim_blockEPc[jmy];
-_ZN9__gnu_cxx3__86__poolILb[01]EE10_M_destroyEv;
-_ZN9__gnu_cxx3__86__poolILb1EE16_M_get_thread_idEv;
+_ZN9__gnu_cxx3__96__poolILb[01]EE13_M_initializeEv;
+_ZN9__gnu_cxx3__96__poolILb[01]EE16_M_reserve_blockE[jmy][jmy];
+_ZN9__gnu_cxx3__96__poolILb[01]EE16_M_reclaim_blockEPc[jmy];
+_ZN9__gnu_cxx3__96__poolILb[01]EE10_M_destroyEv;
+_ZN9__gnu_cxx3__96__poolILb1EE16_M_get_thread_idEv;
 
-_ZN9__gnu_cxx3__817__pool_alloc_base9_M_refillE[jmy];
-_ZN9__gnu_cxx3__817__pool_alloc_base16_M_get_free_listE[jmy];
-_ZN9__gnu_cxx3__817__pool_alloc_base12_M_get_mutexEv;
+_ZN9__gnu_cxx3__917__pool_alloc_base9_M_refillE[jmy];
+_ZN9__gnu_cxx3__917__pool_alloc_base16_M_get_free_listE[jmy];
+_ZN9__gnu_cxx3__917__pool_alloc_base12_M_get_mutexEv;
 
-_ZN9__gnu_cxx3__89free_list6_M_getE[jmy];
-_ZN9__gnu_cxx3__89free_list8_M_clearEv;
+_ZN9__gnu_cxx3__99free_list6_M_getE[jmy];
+_ZN9__gnu_cxx3__99free

Fix gnu versioned namespace mode 00/03

2024-05-04 Thread François Dumont

Here is the list of patches to restore gnu versioned namespace mode.

1/3: Bump gnu version namespace

This is important to be done first so that once build of gnu versioned 
namespace is fixed there is no chance to have another build of '__8' 
version with a different abi than last successful '__8' build.


2/3: Fix build using cxx11 abi for versioned namespace

3/3: Proposal to default to "new" abi when dual abi is disabled and 
accept any default-libstdcxx-abi either dual abi is enabled or not.


All testsuite run for following configs:

- dual abi

- gcc4-compatible only abi

- new only abi

- versioned namespace abi

François




[PATCH v2] Driver: Reject output filenames with source file suffixes [PR80182]

2024-05-04 Thread Peter Damianov
Currently, commands like:
gcc -o file.c -lm
will delete the user's code.

This patch checks the suffix of the output, and errors if the output ends in
any of the suffixes listed in default_compilers.

Unfortunately, I couldn't come up with a better heuristic to diagnose this case
more specifically, so it is now not possible to directly make executables with
said suffixes. I am unsure if any users are depending on this.

PR driver/80182
* gcc.cc (process_command): fatal_error if the output has the suffix of
  a source file.
(have_c): Change type to bool.
(have_O): Change type to bool.
(have_E): Change type to bool.
(have_S): New global variable.
(driver_handle_option): Assign have_S

Signed-off-by: Peter Damianov 
---
v2: use strrchr instead of lrealpath and strchr

 gcc/gcc.cc | 28 +---
 1 file changed, 25 insertions(+), 3 deletions(-)

diff --git a/gcc/gcc.cc b/gcc/gcc.cc
index 830a4700a87..1c4f7032091 100644
--- a/gcc/gcc.cc
+++ b/gcc/gcc.cc
@@ -2127,13 +2127,16 @@ static vec at_file_argbuf;
 static bool in_at_file = false;
 
 /* Were the options -c, -S or -E passed.  */
-static int have_c = 0;
+static bool have_c = false;
 
 /* Was the option -o passed.  */
-static int have_o = 0;
+static bool have_o = false;
 
 /* Was the option -E passed.  */
-static int have_E = 0;
+static bool have_E = false;
+
+/* Was the option -S passed.  */
+static bool have_S = false;
 
 /* Pointer to output file name passed in with -o. */
 static const char *output_file = 0;
@@ -4593,6 +4596,10 @@ driver_handle_option (struct gcc_options *opts,
   have_E = true;
   break;
 
+case OPT_S:
+  have_S = true;
+  break;
+
 case OPT_x:
   spec_lang = arg;
   if (!strcmp (spec_lang, "none"))
@@ -5058,6 +5065,21 @@ process_command (unsigned int decoded_options_count,
   output_file);
 }
 
+  /* Reject output file names that have the same suffix as a source
+ file. This is to catch mistakes like: gcc -o file.c -lm
+ that could delete the user's code. */
+  if (have_o && output_file != NULL && !have_E && !have_S)
+{
+  const char* suffix = strrchr(output_file, '.');
+  if (suffix != NULL)
+   for (int i = 0; i < n_default_compilers; ++i)
+ if (!strcmp(suffix, default_compilers[i].suffix))
+   fatal_error (input_location,
+"output file suffix %qs could be a source file",
+suffix);
+}
+
+
   if (output_file != NULL && output_file[0] == '\0')
 fatal_error (input_location, "output filename may not be empty");
 
-- 
2.39.2



[PATCH] Driver: Reject output filenames with the same suffixes as source files [PR80182]

2024-05-04 Thread Peter Damianov
Currently, commands like:
gcc -o file.c -lm
will delete the user's code.

This patch checks the suffix of the output, and errors if the output ends in
any of the suffixes listed in default_compilers.

Unfortunately, I couldn't come up with a better heuristic to diagnose this case
more specifically, so it is now not possible to directly make executables with
said suffixes. I am unsure if any users are depending on this.

PR driver/80182
* gcc.cc (process_command): fatal_error if the output has the suffix of
  a source file.
(have_c): Change type to bool.
(have_O): Change type to bool.
(have_E): Change type to bool.
(have_S): New global variable.
(driver_handle_option): Assign have_S

Signed-off-by: Peter Damianov 
---
 gcc/gcc.cc | 29 ++---
 1 file changed, 26 insertions(+), 3 deletions(-)

diff --git a/gcc/gcc.cc b/gcc/gcc.cc
index 830a4700a87..53169c16460 100644
--- a/gcc/gcc.cc
+++ b/gcc/gcc.cc
@@ -2127,13 +2127,16 @@ static vec at_file_argbuf;
 static bool in_at_file = false;
 
 /* Were the options -c, -S or -E passed.  */
-static int have_c = 0;
+static bool have_c = false;
 
 /* Was the option -o passed.  */
-static int have_o = 0;
+static bool have_o = false;
 
 /* Was the option -E passed.  */
-static int have_E = 0;
+static bool have_E = false;
+
+/* Was the option -S passed.  */
+static bool have_S = false;
 
 /* Pointer to output file name passed in with -o. */
 static const char *output_file = 0;
@@ -4593,6 +4596,10 @@ driver_handle_option (struct gcc_options *opts,
   have_E = true;
   break;
 
+case OPT_S:
+  have_S = true;
+  break;
+
 case OPT_x:
   spec_lang = arg;
   if (!strcmp (spec_lang, "none"))
@@ -5058,6 +5065,22 @@ process_command (unsigned int decoded_options_count,
   output_file);
 }
 
+  /* Reject output file names that have the same suffix as a source
+ file. This is to catch mistakes like: gcc -o file.c -lm
+ that could delete the user's code. */
+  if (have_o && output_file != NULL && !have_E && !have_S)
+{
+  const char* filename = lbasename(output_file);
+  const char* suffix = strchr(filename, '.');
+  if (suffix != NULL)
+   for (int i = 0; i < n_default_compilers; ++i)
+ if (!strcmp(suffix, default_compilers[i].suffix))
+   fatal_error (input_location,
+"output file suffix %qs could be a source file",
+suffix);
+}
+
+
   if (output_file != NULL && output_file[0] == '\0')
 fatal_error (input_location, "output filename may not be empty");
 
-- 
2.39.2



Ping: [PATCH 0/3] Recover in-tree libiconv build support

2024-05-04 Thread Arsen Arsenović
Hi!

Given that trunk is now GCC 15, it might be good to land this patch
early.  I will re-test it just in case after a rebase but, otherwise, OK
for trunk?

TIA, have a lovely day.
-- 
Arsen Arsenović


signature.asc
Description: PGP signature


Re: [PATCH v2 1/1] [RISC-V] Add support for _Bfloat16

2024-05-04 Thread Jeff Law




On 4/2/24 3:22 AM, Xiao Zeng wrote:

1 At point ,
   BF16 has already been completed "post public review".

2 LLVM has also added support for RISCV BF16 in
    and
   .

3 According to the discussion 
,
   this use __bf16 and use DF16b in riscv_mangle_type like x86.

Below test are passed for this patch
 * The riscv fully regression test.

gcc/ChangeLog:

* config/riscv/iterators.md: New mode iterator HFBF.
* config/riscv/riscv-builtins.cc (riscv_init_builtin_types):
Initialize data type _Bfloat16.
* config/riscv/riscv-modes.def (FLOAT_MODE): New.
(ADJUST_FLOAT_FORMAT): New.
* config/riscv/riscv.cc (riscv_mangle_type): Support for BFmode.
(riscv_scalar_mode_supported_p): Ditto.
(riscv_libgcc_floating_mode_supported_p): Ditto.
(riscv_init_libfuncs): Set the conversion method for BFmode and
HFmode.
(riscv_block_arith_comp_libfuncs_for_mode): Set the arithmetic
and comparison libfuncs for the mode.
* config/riscv/riscv.md (mode" ): Add BF.
(movhf): Support for BFmode.
(mov): Ditto.
(*movhf_softfloat): Ditto.
(*mov_softfloat): Ditto.

libgcc/ChangeLog:

* config/riscv/sfp-machine.h (_FP_NANFRAC_B): New.
(_FP_NANSIGN_B): Ditto.
* config/riscv/t-softfp32: Add support for BF16 libfuncs.
* config/riscv/t-softfp64: Ditto.
* soft-fp/floatsibf.c: For si -> bf16.
* soft-fp/floatunsibf.c: For unsi -> bf16.

gcc/testsuite/ChangeLog:

* gcc.target/riscv/bf16_arithmetic.c: New test.
* gcc.target/riscv/bf16_call.c: New test.
* gcc.target/riscv/bf16_comparison.c: New test.
* gcc.target/riscv/bf16_float_libcall_convert.c: New test.
* gcc.target/riscv/bf16_integer_libcall_convert.c: New test.
Just some nits.  In t-softfp32 and t-softfp64 the code you've added 
should be using tabs, not 8 spaces, as noted by the CI "Lint Status":


https://github.com/ewlu/gcc-precommit-ci/issues/1412#issuecomment-2031568644

With that fixed, this is fine for the trunk.  No need to repost, go 
ahead and commit.


Thanks for your patience,
Jeff


[PATCH v2] Fix auto deduction for template specialization scopes [PR114915]

2024-05-04 Thread Seyed Sajad Kahani
The limitations of the initial patch (checking specializiation template usage), 
have been discussed.

> I realized that for the case where we have a member function template
> of a class template, and a specialization of the enclosing class only
> (like below),
>
> template <>
> template 
> void S::f() {
>   // some constrained auto
> }
>
> When using S::f, DECL_TEMPLATE_INFO(fn) is non-zero, and
> DECL_TEMPLATE_SPECIALIZATION(fn) is zero, while
> DECL_TEMPLATE_SPECIALIZATION(DECL_TI_TEMPLATE(fn)) is non-zero.
> So it means that the patch will extract DECL_TI_ARGS(fn) as
> outer_targs, and it would be   while the type of the
> constrained auto will be as template  ... and will not be
> dependent on the parameters of the enclosing class.
> This means that again (outer_targs + targs) will have more depth than
> auto_node levels.
> This means that for the case where the function is not an explicit
> specialization, but it is defined in an explicitly specialized scope,
> the patch will not work.

As described in more detail below, this patch attempts to resolve this issue by 
trimming full_targs.

> > Another more context-unaware approach to fix this might be to only
> > use the innermost level from 'full_targs' for satisfaction if
> > TEMPLATE_TYPE_ORIG_LEVEL is 1 (which means this constrained auto
> > appeared in a context that doesn't have template parameters such as an
> > explicit specialization or ordinary non-template function, and so
> > only the level corresponding to the deduced type is needed for
> > satisfaction.)
> >
> > Generalizing on that, another approach might be to handle missing_levels < 0
> > by removing -missing_levels from full_targs via get_innermost_template_args.
> > But AFAICT it should suffice to handle the TEMPLATE_TYPE_ORIG_LEVEL == 1
> > case specifically.
>
> I was unable to understand why you think that it might not handle
> TEMPLATE_TYPE_ORIG_LEVEL > 1 cases, so I tried to formulate my
> reasoning as follows.
>
> Assuming contexts adc_variable_type, adc_return_type, adc_decomp_type:
> For any case where missing_level < 0, it means that the type depends
> on fewer levels than the template arguments used to materialize it.
> This can only happen when the type is defined in an explicit
> specialization scope. This explicit specialization might not occur in
> its immediate scope.
> Note that partial specialization (while changing the set of
> parameters) cannot reduce the number of levels for the type.
> Because of the fact that the enclosing scope of any explicit
> specialization is explicitly specialized
> (https://eel.is/c++draft/temp.expl.spec#16), the type will not depend
> on template parameters outside of its innermost explicit specialized
> scope.
> Assuming that there are no real missing levels, by removing those
> levels, missing_level should be = 0. As a result, by roughly doing
>
> if (missing_levels < 0) {
>   tree trimmed_full_args = get_innermost_template_args(full_targs,
> TEMPLATE_TYPE_ORIG_LEVEL(auto_node));
>   full_targs = trimmed_full_args;
> }
> in pt.cc:31262, where we calculate and check missing_levels, we would
> be able to fix the errors.
> Note that, for the case where there are real missing levels, we are
> putting irrelevant template arguments for the missing levels instead
> of make_tree_vec(0). By this change:
> - If the type is independent of those missing levels: it works fine either 
> way.
> - If the type is dependent on those missing levels: Instead of raising
> an ICE, the compiler exhibits undefined behavior.
---
 gcc/cp/pt.cc  | 14 ++--
 .../g++.dg/cpp2a/concepts-placeholder14.C | 19 +++
 .../g++.dg/cpp2a/concepts-placeholder15.C | 15 +
 .../g++.dg/cpp2a/concepts-placeholder16.C | 33 +++
 4 files changed, 78 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 3b2106dd3..bdf03a1a7 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -31044,7 +31044,8 @@ unparenthesized_id_or_class_member_access_p (tree init)
OUTER_TARGS is used during template argument deduction (context == 
adc_unify)
to properly substitute the result.  It's also used in the adc_unify and
adc_requirement contexts to communicate the necessary template arguments
-   to satisfaction.  OUTER_TARGS is ignored in other contexts.
+   to satisfaction.  OUTER_TARGS will be used for other contexts if it is a
+   function scope deduction. Otherwise it is ignored.
 
Additionally for adc_unify contexts TMPL is the template for which TYPE
is a template parameter type.
@@ -31260,8 +31261,15 @@ do_auto_deduction (tree type, tree init, tree 
auto_node,
 these missing levels, but this hack otherwise allows us to handle a
 large subset of possible

[PATCH 2/4] libcpp/init: remove unnecessary `struct` keyword

2024-05-04 Thread Ben Boeckel
The initial P1689 patches were written in 2019 and ended up having code
move around over time ended up introducing a `struct` keyword to the
implementation of `cpp_finish`. Remove it to match the rest of the file
and its declaration in the header.

Fixes: 024f135a1e9 (p1689r5: initial support, 2023-09-01)

Reported-by: Roland Illig 

libcpp/

* init.cc (cpp_finish): Remove unnecessary `struct` keyword.

Signed-off-by: Ben Boeckel 
---
 libcpp/init.cc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcpp/init.cc b/libcpp/init.cc
index 54fc9236d38..cbd22249b04 100644
--- a/libcpp/init.cc
+++ b/libcpp/init.cc
@@ -862,7 +862,7 @@ read_original_directory (cpp_reader *pfile)
Maybe it should also reset state, such that you could call
cpp_start_read with a new filename to restart processing.  */
 void
-cpp_finish (struct cpp_reader *pfile, FILE *deps_stream, FILE *fdeps_stream)
+cpp_finish (cpp_reader *pfile, FILE *deps_stream, FILE *fdeps_stream)
 {
   /* Warn about unused macros before popping the final buffer.  */
   if (CPP_OPTION (pfile, warn_unused_macros))
-- 
2.44.0



[PATCH 3/4] gcc/c-family/c-opts: fix quoting for `-fdeps-format=` error message

2024-05-04 Thread Ben Boeckel
Fixes: 024f135a1e9 (p1689r5: initial support, 2023-09-01)

Reported-by: Roland Illig 

gcc/c-family/

* c-opts.cc (c_common_handle_option): Fix quoting in
`-fdeps-format=` unrecognized parameter error message.

Signed-off-by: Ben Boeckel 
---
 gcc/c-family/c-opts.cc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc
index be3058dca63..4a164ad0c0b 100644
--- a/gcc/c-family/c-opts.cc
+++ b/gcc/c-family/c-opts.cc
@@ -370,7 +370,7 @@ c_common_handle_option (size_t scode, const char *arg, 
HOST_WIDE_INT value,
   if (!strcmp (arg, "p1689r5"))
cpp_opts->deps.fdeps_format = FDEPS_FMT_P1689R5;
   else
-   error ("%<-fdeps-format=%> unknown format %<%s%>", arg);
+   error ("%<-fdeps-format=%> unknown format %q", arg);
   break;
 
 case OPT_fdeps_file_:
-- 
2.44.0



[PATCH 4/4] gcc/c-family/c.opt: clarify `-fdeps-*` flag documentation

2024-05-04 Thread Ben Boeckel
Move the only supported value (as of today) to the flag name itself.
Also reword to clarify that the `-fdeps-file=` file will be written to.

Fixes: 024f135a1e9 (p1689r5: initial support, 2023-09-01)

Reported-by: Roland Illig 

gcc/c-family/

* c.opt: Clarify `-fdeps-*` documentation.

Signed-off-by: Ben Boeckel 
---
 gcc/c-family/c.opt | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 56cccf2a67b..fa82eebb518 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -256,13 +256,13 @@ MT
 C ObjC C++ ObjC++ Joined Separate MissingArgError(missing makefile target 
after %qs)
 -MTAdd a target that does not require quoting.
 
-fdeps-format=
+fdeps-format=p1689r5
 C ObjC C++ ObjC++ NoDriverArg Joined MissingArgError(missing format after %qs)
-Structured format for output dependency information.  Supported (\"p1689r5\").
+Structured format for output dependency information.
 
 fdeps-file=
 C ObjC C++ ObjC++ NoDriverArg Joined MissingArgError(missing output path after 
%qs)
-File for output dependency information.
+File to write dependency information to.
 
 fdeps-target=
 C ObjC C++ ObjC++ NoDriverArg Joined MissingArgError(missing path after %qs)
-- 
2.44.0



[PATCH 1/4] libcpp/mkdeps: fix indentation

2024-05-04 Thread Ben Boeckel
Fixes: 024f135a1e9 (p1689r5: initial support, 2023-09-01)

Reported-by: Roland Illig 

libcpp/

* mkdeps.cc (fdeps_add_target): Fix indentation.

Signed-off-by: Ben Boeckel 
---
 libcpp/mkdeps.cc | 11 ++-
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/libcpp/mkdeps.cc b/libcpp/mkdeps.cc
index 4cf0cf09178..8762ead4c34 100644
--- a/libcpp/mkdeps.cc
+++ b/libcpp/mkdeps.cc
@@ -307,11 +307,12 @@ fdeps_add_target (struct mkdeps *d, const char *o, bool 
is_primary)
 {
   o = apply_vpath (d, o);
   if (is_primary)
-  {
-if (d->primary_output)
-  d->fdeps_targets.push (d->primary_output);
-d->primary_output = xstrdup (o);
-  } else
+{
+  if (d->primary_output)
+   d->fdeps_targets.push (d->primary_output);
+  d->primary_output = xstrdup (o);
+}
+  else
 d->fdeps_targets.push (xstrdup (o));
 }
 
-- 
2.44.0



[PATCH 0/4] P1689 followup fixes

2024-05-04 Thread Ben Boeckel
Hi,

Here are some minor fixes to documentation, formatting, and styling to the
P1689R5 support through the `-fdeps-*` flags.

Thanks,

--Ben

Ben Boeckel (4):
  libcpp/mkdeps: fix indentation
  libcpp/init: remove unnecessary `struct` keyword
  gcc/c-family/c-opts: fix quoting for `-fdeps-format=` error message
  gcc/c-family/c.opt: clarify `-fdeps-*` flag documentation

 gcc/c-family/c-opts.cc |  2 +-
 gcc/c-family/c.opt |  6 +++---
 libcpp/init.cc |  2 +-
 libcpp/mkdeps.cc   | 11 ++-
 4 files changed, 11 insertions(+), 10 deletions(-)


base-commit: bba118db3f63cb1e3953a014aa3ac2ad89908950
-- 
2.44.0



[RFA][RISC-V] [PATCH v2] Enable inlining str* by default

2024-05-04 Thread Jeff Law
The CI system caught a latent bug in the inline string comparison code 
that shows up with rv32+zbb.  It was hardcoding 64 when AFAICT it should 
have been using BITS_PER_WORD.


So v2 with that fixed.

--


So with Chrstoph's patches from late 2022 we've had the ability to 
inline strlen, and str[n]cmp (scalar).  However, we never actually 
turned this capability on by default!


This patch flips the those default to allow inlinining by default.  It 
also fixes one bug exposed by our internal testing when NBYTES is zero 
for strncmp.  I don't think that case happens enough to try and optimize 
it, we just disable inline expansion for that instance.


This has been bootstrapped and regression tested on rv64gc at various 
times as well as cross tested on rv64gc more times than I can probably 
count (we've have this patch internally for a while).  More importantly, 
I just successfully tested it on rv64gc and rv32gcv elf configurations 
with the trunk ;-)


OK for the trunk (after passing pre-commit CI)?

Jeff
[RFA][RISC-V] Enable inlining str* by default

So with Chrstoph's patches from late 2022 we've had the ability to inline
strlen, and str[n]cmp (scalar).  However, we never actually turned this
capability on by default!

This patch flips the those default to allow inlinining by default.  It also
fixes one bug exposed by our internal testing when NBYTES is zero for strncmp.
I don't think that case happens enough to try and optimize it, we just disable
inline expansion for that instance.

This has been bootstrapped and regression tested on rv64gc at various times as
well as cross tested on rv64gc more times than I can probably count (we've have
this patch internally for a while).  More importantly, I just successfully
tested it on rv64gc and rv32gcv elf configurations with the trunk ;-)

OK for the trunk (assuming it passes pre-commit CI)?

gcc/


* config/riscv/riscv-string.cc (riscv_expand_strcmp): Do not inline
strncmp with zero size.
(emit_strcmp_scalar_compare_subword): Adjust rotation for rv32 vs rv64.
* config/riscv/riscv.opt (var_inline_strcmp): Enable by default.
(vriscv_inline_strncmp, riscv_inline_strlen): Likewise.


gcc/testsuite

* gcc.target/riscv/zbb-strlen-disabled-2.c: Turn off inlining.


diff --git a/gcc/config/riscv/riscv-string.cc b/gcc/config/riscv/riscv-string.cc
index b09b51d7526..41cb061c746 100644
--- a/gcc/config/riscv/riscv-string.cc
+++ b/gcc/config/riscv/riscv-string.cc
@@ -153,7 +153,7 @@ emit_strcmp_scalar_compare_subword (rtx data1, rtx data2, 
rtx orc1,
   rtx imask = gen_rtx_CONST_INT (Xmode, im);
   rtx m_reg = gen_reg_rtx (Xmode);
   emit_insn (gen_rtx_SET (m_reg, imask));
-  do_rotr3 (m_reg, m_reg, GEN_INT (64 - cmp_bytes * BITS_PER_UNIT));
+  do_rotr3 (m_reg, m_reg, GEN_INT (BITS_PER_WORD - cmp_bytes * BITS_PER_UNIT));
   do_and3 (data1, m_reg, data1);
   do_and3 (data2, m_reg, data2);
   if (TARGET_ZBB)
@@ -497,6 +497,13 @@ riscv_expand_strcmp (rtx result, rtx src1, rtx src2,
return false;
   nbytes = UINTVAL (bytes_rtx);
 
+  /* If NBYTES is zero the result of strncmp will always be zero,
+but that would require special casing in the caller.  So for
+now just don't do an inline expansion.  This probably rarely
+happens in practice, but it is tested by the testsuite.  */
+  if (nbytes == 0)
+   return false;
+
   /* We don't emit parts of a strncmp() call.  */
   if (nbytes > compare_max)
return false;
diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
index ee824756381..95165e5fa89 100644
--- a/gcc/config/riscv/riscv.opt
+++ b/gcc/config/riscv/riscv.opt
@@ -515,15 +515,15 @@ Target Var(TARGET_INLINE_SUBWORD_ATOMIC) Init(1)
 Always inline subword atomic operations.
 
 minline-strcmp
-Target Var(riscv_inline_strcmp) Init(0)
+Target Var(riscv_inline_strcmp) Init(1)
 Inline strcmp calls if possible.
 
 minline-strncmp
-Target Var(riscv_inline_strncmp) Init(0)
+Target Var(riscv_inline_strncmp) Init(1)
 Inline strncmp calls if possible.
 
 minline-strlen
-Target Var(riscv_inline_strlen) Init(0)
+Target Var(riscv_inline_strlen) Init(1)
 Inline strlen calls if possible.
 
 -param=riscv-strcmp-inline-limit=
diff --git a/gcc/testsuite/gcc.target/riscv/zbb-strlen-disabled-2.c 
b/gcc/testsuite/gcc.target/riscv/zbb-strlen-disabled-2.c
index a481068aa0c..1295aeb0086 100644
--- a/gcc/testsuite/gcc.target/riscv/zbb-strlen-disabled-2.c
+++ b/gcc/testsuite/gcc.target/riscv/zbb-strlen-disabled-2.c
@@ -1,6 +1,6 @@
 /* { dg-do compile } */
-/* { dg-options "-march=rv32gc_zbb" { target { rv32 } } } */
-/* { dg-options "-march=rv64gc_zbb" { target { rv64 } } } */
+/* { dg-options "-mno-inline-strlen -march=rv32gc_zbb" { target { rv32 } } } */
+/* { dg-options "-mno-inline-strlen -march=rv64gc_zbb" { target { rv64 } } } */
 /* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Og" "-Oz" } } */
 
 typedef long unsigned int size_t;


Re: [PATCH] Fix auto deduction for template specialization scopes [114915].

2024-05-04 Thread Seyed Sajad Kahani
Thanks for your helpful feedback. It has totally shaped my understanding.

While I was trying to develop other tests, as you suggested:

> It would be good to also test an explicit variable tmpl spec and
> an explicit spec of a member template of a class template.

I realized that for the case where we have a member function template
of a class template, and a specialization of the enclosing class only
(like below),

template <>
template 
void S::f() {
  // some constrained auto
}

When using S::f, DECL_TEMPLATE_INFO(fn) is non-zero, and
DECL_TEMPLATE_SPECIALIZATION(fn) is zero, while
DECL_TEMPLATE_SPECIALIZATION(DECL_TI_TEMPLATE(fn)) is non-zero.
So it means that the patch will extract DECL_TI_ARGS(fn) as
outer_targs, and it would be   while the type of the
constrained auto will be as template  ... and will not be
dependent on the parameters of the enclosing class.
This means that again (outer_targs + targs) will have more depth than
auto_node levels.
This means that for the case where the function is not an explicit
specialization, but it is defined in an explicitly specialized scope,
the patch will not work.

I have thought of two ideas to fully solve the problem:

1. Trimming the full_targs by - missing_level, as you have mentioned.
2. Traversing the TI_TEMPLATE associated with different levels of
outer_targs, finding the first one that is
DECL_TEMPLATE_SPECIALIZATION, then trimming outer_targs by that point.

For the first idea,

> Another more context-unaware approach to fix this might be to only
> use the innermost level from 'full_targs' for satisfaction if
> TEMPLATE_TYPE_ORIG_LEVEL is 1 (which means this constrained auto
> appeared in a context that doesn't have template parameters such as an
> explicit specialization or ordinary non-template function, and so
> only the level corresponding to the deduced type is needed for
> satisfaction.)
>
> Generalizing on that, another approach might be to handle missing_levels < 0
> by removing -missing_levels from full_targs via get_innermost_template_args.
> But AFAICT it should suffice to handle the TEMPLATE_TYPE_ORIG_LEVEL == 1
> case specifically.

I was unable to understand why you think that it might not handle
TEMPLATE_TYPE_ORIG_LEVEL > 1 cases, so I tried to formulate my
reasoning as follows.

Assuming contexts adc_variable_type, adc_return_type, adc_decomp_type:
For any case where missing_level < 0, it means that the type depends
on fewer levels than the template arguments used to materialize it.
This can only happen when the type is defined in an explicit
specialization scope. This explicit specialization might not occur in
its immediate scope.
Note that partial specialization (while changing the set of
parameters) cannot reduce the number of levels for the type.
Because of the fact that the enclosing scope of any explicit
specialization is explicitly specialized
(https://eel.is/c++draft/temp.expl.spec#16), the type will not depend
on template parameters outside of its innermost explicit specialized
scope.
Assuming that there are no real missing levels, by removing those
levels, missing_level should be = 0. As a result, by roughly doing

if (missing_levels < 0) {
  tree trimmed_full_args = get_innermost_template_args(full_targs,
TEMPLATE_TYPE_ORIG_LEVEL(auto_node));
  full_targs = trimmed_full_args;
}
in pt.cc:31262, where we calculate and check missing_levels, we would
be able to fix the errors.
Note that, for the case where there are real missing levels, we are
putting irrelevant template arguments for the missing levels instead
of make_tree_vec(0). By this change:
- If the type is independent of those missing levels: it works fine either way.
- If the type is dependent on those missing levels: Instead of raising
an ICE, the compiler exhibits undefined behavior.

Now, for the second idea, we need to do something like

int meaningful_levels = 0;
for (tree sc = fn;
 DECL_TEMPLATE_INFO(sc) && !DECL_TEMPLATE_SPECIALIZATION(sc);
 sc = DECL_TI_TEMPLATE(sc))
  meaningful_levels ++;
outer_targs = get_innermost_template_args(DECL_TI_ARGS(fn), meaningful_levels);

in pt.cc:31238, instead of assigning DECL_TI_ARGS(fn) to outer_targs directly.
Note that we need to do the same thing in decl:8528 and maybe other places.

I would really appreciate your comments on these two ideas.
I will send another patch, applying the first idea in reply to this thread.


Re: [V2][PATCH] gcc-14/changes.html: Deprecate a GCC C extension on flexible array members.

2024-05-04 Thread Sebastian Huber

On 07.08.23 16:22, Qing Zhao via Gcc-patches wrote:

Hi,

This is the 2nd version of the patch.
Comparing to the 1st version, the only change is to address Richard's
comment on refering a warning option for diagnosing deprecated behavior.


Okay for committing?

thanks.

Qing

==

*htdocs/gcc-14/changes.html (Caveats): Add notice about deprecating a C
extension about flexible array members.
---
  htdocs/gcc-14/changes.html | 13 -
  1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/htdocs/gcc-14/changes.html b/htdocs/gcc-14/changes.html
index dad1ba53..eae25f1a 100644
--- a/htdocs/gcc-14/changes.html
+++ b/htdocs/gcc-14/changes.html
@@ -30,7 +30,18 @@ a work-in-progress.
  
  Caveats
  
-  ...
+  C:
+  Support for the GCC extension, a structure containing a C99 flexible 
array
+  member, or a union containing such a structure, is not the last field of
+  another structure, is deprecated. Refer to
+  https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html";>
+  Zero Length Arrays.
+  Any code relying on this extension should be modifed to ensure that
+  C99 flexible array members only end up at the ends of structures.
+  Please use the warning option
+  https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wflex-array-member-not-at-end";>-Wflex-array-member-not-at-end
 to
+  identify all such cases in the source code and modify them.
+  
  


I have a question with respect to the static initialization of flexible 
array members. According to the documentation this is supported by GCC:


https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html

"GCC allows static initialization of flexible array members. This is 
equivalent to defining a new structure containing the original structure 
followed by an array of sufficient size to contain the data. E.g. in the 
following, f1 is constructed as if it were declared like f2.


struct f1 {
  int x; int y[];
} f1 = { 1, { 2, 3, 4 } };

struct f2 {
  struct f1 f1; int data[3];
} f2 = { { 1 }, { 2, 3, 4 } };
"

However, when I compile this code, I get a warning like this:

flex-array.c:6:13: warning: structure containing a flexible array member 
is not at the end of another structure [-Wflex-array-member-not-at-end]

6 |   struct f1 f1; int data[3];
  |

In general, I agree that flexible array members should be at the end, 
however the support for static initialization is quite important from my 
point of view especially for applications for embedded systems. Here, 
dynamic allocations may not be allowed or feasible.


--
embedded brains GmbH & Co. KG
Herr Sebastian HUBER
Dornierstr. 4
82178 Puchheim
Germany
email: sebastian.hu...@embedded-brains.de
phone: +49-89-18 94 741 - 16
fax:   +49-89-18 94 741 - 08

Registergericht: Amtsgericht München
Registernummer: HRB 157899
Vertretungsberechtigte Geschäftsführer: Peter Rasmussen, Thomas Dörfler
Unsere Datenschutzerklärung finden Sie hier:
https://embedded-brains.de/datenschutzerklaerung/


[PATCH] aarch64: Support multiple variants including up to 3

2024-05-04 Thread Andrew Pinski
On some of the Qualcomm's SoC that includes oryon-1 core, the variant
will be different on the cores due to big.little config. Though
the difference between big and little is not significant enough
to have seperate cost/scheduling models for them and the feature set
is the same across all variants.

Also on some SoCs, there are 3 variants of the core, big.middle.little
so this increases the support there for up to 3 cores and 3 variants
in the original parsing loop but it does not change the support for max
of 2 different cores.

After this patch and the patch that adds oryon-1, -mcpu=native works
on the SoCs I am working with.

Bootstrapped and tested on aarch64-linux-gnu with no regressions.

gcc/ChangeLog:

* config/aarch64/driver-aarch64.cc (host_detect_local_cpu): Support
3 cores and 3 variants. If there is one core but multiple variant,
then treat the variant as being all.

gcc/testsuite/ChangeLog:

* gcc.target/aarch64/cpunative/info_25: New file.
* gcc.target/aarch64/cpunative/info_26: New file.
* gcc.target/aarch64/cpunative/native_cpu_25.c: New test.
* gcc.target/aarch64/cpunative/native_cpu_26.c: New test.

Signed-off-by: Andrew Pinski 
---
 gcc/config/aarch64/driver-aarch64.cc  | 14 ++
 .../gcc.target/aarch64/cpunative/info_25  | 17 
 .../gcc.target/aarch64/cpunative/info_26  | 26 +++
 .../aarch64/cpunative/native_cpu_25.c | 11 
 .../aarch64/cpunative/native_cpu_26.c | 11 
 5 files changed, 74 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/aarch64/cpunative/info_25
 create mode 100644 gcc/testsuite/gcc.target/aarch64/cpunative/info_26
 create mode 100644 gcc/testsuite/gcc.target/aarch64/cpunative/native_cpu_25.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/cpunative/native_cpu_26.c

diff --git a/gcc/config/aarch64/driver-aarch64.cc 
b/gcc/config/aarch64/driver-aarch64.cc
index b620351e572..abe6e7df7dc 100644
--- a/gcc/config/aarch64/driver-aarch64.cc
+++ b/gcc/config/aarch64/driver-aarch64.cc
@@ -256,9 +256,9 @@ host_detect_local_cpu (int argc, const char **argv)
   bool cpu = false;
   unsigned int i = 0;
   unsigned char imp = INVALID_IMP;
-  unsigned int cores[2] = { INVALID_CORE, INVALID_CORE };
+  unsigned int cores[3] = { INVALID_CORE, INVALID_CORE, INVALID_CORE };
   unsigned int n_cores = 0;
-  unsigned int variants[2] = { ALL_VARIANTS, ALL_VARIANTS };
+  unsigned int variants[3] = { ALL_VARIANTS, ALL_VARIANTS, ALL_VARIANTS };
   unsigned int n_variants = 0;
   bool processed_exts = false;
   aarch64_feature_flags extension_flags = 0;
@@ -314,7 +314,7 @@ host_detect_local_cpu (int argc, const char **argv)
  unsigned cvariant = parse_field (buf);
  if (!contains_core_p (variants, cvariant))
{
-  if (n_variants == 2)
+ if (n_variants == 3)
 goto not_found;
 
   variants[n_variants++] = cvariant;
@@ -326,7 +326,7 @@ host_detect_local_cpu (int argc, const char **argv)
  unsigned ccore = parse_field (buf);
  if (!contains_core_p (cores, ccore))
{
- if (n_cores == 2)
+ if (n_cores == 3)
goto not_found;
 
  cores[n_cores++] = ccore;
@@ -383,11 +383,15 @@ host_detect_local_cpu (int argc, const char **argv)
   /* Weird cpuinfo format that we don't know how to handle.  */
   if (n_cores == 0
   || n_cores > 2
-  || (n_cores == 1 && n_variants != 1)
   || imp == INVALID_IMP
   || !processed_exts)
 goto not_found;
 
+  /* If we have one core type but multiple variants, consider
+ that as one variant with ALL_VARIANTS instead.  */
+  if (n_cores == 1 && n_variants != 1)
+variants[0] = ALL_VARIANTS;
+
   /* Simple case, one core type or just looking for the arch. */
   if (n_cores == 1 || arch)
 {
diff --git a/gcc/testsuite/gcc.target/aarch64/cpunative/info_25 
b/gcc/testsuite/gcc.target/aarch64/cpunative/info_25
new file mode 100644
index 000..d6e83ccab09
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/cpunative/info_25
@@ -0,0 +1,17 @@
+processor  : 0
+BogoMIPS   : 38.40
+Features   : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp 
asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 
asimdfhm dit uscat ilrcpc flagm ssbs sb paca pacg dcpodp flagm2 frint i8mm bf16 
rng bti ecv afp rpres
+CPU implementer: 0x51
+CPU architecture: 8
+CPU variant: 0x2
+CPU part   : 0x001
+CPU revision   : 1
+
+processor  : 1
+BogoMIPS   : 38.40
+Features   : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp 
asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 
asimdfhm dit uscat ilrcpc flagm ssbs sb paca pacg dcpodp flagm2 frint i8mm bf16 
rng bti ecv afp rpres
+CPU implementer: 0x51
+CPU architecture: 8
+CPU variant: 0x1
+CPU part   

[COMMITTED 21/23] Implement operator_gt for prange.

2024-05-04 Thread Aldy Hernandez
gcc/ChangeLog:

* range-op-mixed.h: Add overloaded declarations for pointer variants.
* range-op-ptr.cc (operator_gt::fold_range): New.
(operator_gt::op1_range): New.
(operator_gt::op2_range): New.
(operator_gt::op1_op2_relation): New.
(operator_gt::pointers_handled_p): New.
---
 gcc/range-op-mixed.h |  12 +
 gcc/range-op-ptr.cc  | 106 +++
 2 files changed, 118 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 571729e2ab6..f7a07b19635 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -320,6 +320,9 @@ public:
   bool fold_range (irange &r, tree type,
   const irange &op1, const irange &op2,
   relation_trio = TRIO_VARYING) const final override;
+  bool fold_range (irange &r, tree type,
+  const prange &op1, const prange &op2,
+  relation_trio = TRIO_VARYING) const final override;
   bool fold_range (irange &r, tree type,
   const frange &op1, const frange &op2,
   relation_trio = TRIO_VARYING) const final override;
@@ -327,6 +330,9 @@ public:
   bool op1_range (irange &r, tree type,
  const irange &lhs, const irange &op2,
  relation_trio = TRIO_VARYING) const final override;
+  bool op1_range (prange &r, tree type,
+ const irange &lhs, const prange &op2,
+ relation_trio = TRIO_VARYING) const final override;
   bool op1_range (frange &r, tree type,
  const irange &lhs, const frange &op2,
  relation_trio = TRIO_VARYING) const final override;
@@ -334,11 +340,16 @@ public:
   bool op2_range (irange &r, tree type,
  const irange &lhs, const irange &op1,
  relation_trio = TRIO_VARYING) const final override;
+  bool op2_range (prange &r, tree type,
+ const irange &lhs, const prange &op1,
+ relation_trio = TRIO_VARYING) const final override;
   bool op2_range (frange &r, tree type,
  const irange &lhs, const frange &op1,
  relation_trio = TRIO_VARYING) const final override;
   relation_kind op1_op2_relation (const irange &lhs, const irange &,
  const irange &) const final override;
+  relation_kind op1_op2_relation (const irange &lhs, const prange &,
+ const prange &) const final override;
   relation_kind op1_op2_relation (const irange &lhs, const frange &,
  const frange &) const final override;
   void update_bitmask (irange &r, const irange &lh,
@@ -346,6 +357,7 @@ public:
   // Check op1 and op2 for compatibility.
   bool operand_check_p (tree, tree t1, tree t2) const final override
 { return range_compatible_p (t1, t2); }
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final 
override;
 };
 
 class operator_ge :  public range_operator
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index eb28211b583..441a18c08c7 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -1747,6 +1747,112 @@ operator_le::pointers_handled_p (range_op_dispatch_type 
type,
 }
 }
 
+bool
+operator_gt::fold_range (irange &r, tree type,
+const prange &op1, const prange &op2,
+relation_trio rel) const
+{
+  if (relop_early_resolve (r, type, op1, op2, rel, VREL_GT))
+return true;
+
+  signop sign = TYPE_SIGN (op1.type ());
+  gcc_checking_assert (sign == TYPE_SIGN (op2.type ()));
+
+  if (wi::gt_p (op1.lower_bound (), op2.upper_bound (), sign))
+r = range_true ();
+  else if (!wi::gt_p (op1.upper_bound (), op2.lower_bound (), sign))
+r = range_false ();
+  else
+r = range_true_and_false ();
+
+  //update_known_bitmask (r, GT_EXPR, op1, op2);
+  return true;
+}
+
+bool
+operator_gt::op1_range (prange &r, tree type,
+   const irange &lhs, const prange &op2,
+   relation_trio) const
+{
+  if (op2.undefined_p ())
+return false;
+
+  switch (get_bool_state (r, lhs, type))
+{
+case BRS_TRUE:
+  build_gt (r, type, op2);
+  break;
+
+case BRS_FALSE:
+  build_le (r, type, op2);
+  break;
+
+default:
+  break;
+}
+  return true;
+}
+
+bool
+operator_gt::op2_range (prange &r, tree type,
+   const irange &lhs,
+   const prange &op1,
+   relation_trio) const
+{
+  if (op1.undefined_p ())
+return false;
+
+  switch (get_bool_state (r, lhs, type))
+{
+case BRS_TRUE:
+  build_lt (r, type, op1);
+  break;
+
+case BRS_FALSE:
+  build_ge (r, type, op1);
+  break;
+
+default:
+  break;
+}
+  return true;
+}
+
+relation_kind
+operator_gt::op1_op2_relation (const irange &lhs, const prange &,
+  const prange &) const
+{
+  if (lhs.undefi

[COMMITTED 18/23] Implement operator_equal for prange.

2024-05-04 Thread Aldy Hernandez
gcc/ChangeLog:

* range-op-mixed.h: Add overloaded declarations for pointer variants.
* range-op-ptr.cc (operator_equal::fold_range): New.
(operator_equal::op1_range): New.
(operator_equal::op2_range): New.
(operator_equal::op1_op2_relation): New.
(operator_equal::pointers_handled_p): New.
---
 gcc/range-op-mixed.h |  12 +
 gcc/range-op-ptr.cc  | 117 +++
 2 files changed, 129 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 980611dc339..ee8d9dd328f 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -115,6 +115,9 @@ public:
   bool fold_range (irange &r, tree type,
   const irange &op1, const irange &op2,
   relation_trio = TRIO_VARYING) const final override;
+  bool fold_range (irange &r, tree type,
+  const prange &op1, const prange &op2,
+  relation_trio = TRIO_VARYING) const final override;
   bool fold_range (irange &r, tree type,
   const frange &op1, const frange &op2,
   relation_trio = TRIO_VARYING) const final override;
@@ -122,6 +125,9 @@ public:
   bool op1_range (irange &r, tree type,
  const irange &lhs, const irange &val,
  relation_trio = TRIO_VARYING) const final override;
+  bool op1_range (prange &r, tree type,
+ const irange &lhs, const prange &val,
+ relation_trio = TRIO_VARYING) const final override;
   bool op1_range (frange &r, tree type,
  const irange &lhs, const frange &op2,
  relation_trio = TRIO_VARYING) const final override;
@@ -129,12 +135,17 @@ public:
   bool op2_range (irange &r, tree type,
  const irange &lhs, const irange &val,
  relation_trio = TRIO_VARYING) const final override;
+  bool op2_range (prange &r, tree type,
+ const irange &lhs, const prange &val,
+ relation_trio = TRIO_VARYING) const final override;
   bool op2_range (frange &r, tree type,
  const irange &lhs, const frange &op1,
  relation_trio rel = TRIO_VARYING) const final override;
 
   relation_kind op1_op2_relation (const irange &lhs, const irange &,
  const irange &) const final override;
+  relation_kind op1_op2_relation (const irange &lhs, const prange &,
+ const prange &) const final override;
   relation_kind op1_op2_relation (const irange &lhs, const frange &,
  const frange &) const final override;
   void update_bitmask (irange &r, const irange &lh,
@@ -142,6 +153,7 @@ public:
   // Check op1 and op2 for compatibility.
   bool operand_check_p (tree, tree t1, tree t2) const final override
 { return range_compatible_p (t1, t2); }
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final 
override;
 };
 
 class operator_not_equal : public range_operator
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index 081e8fdba1f..fb2888bf079 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -1230,6 +1230,123 @@ operator_bitwise_or::pointers_handled_p 
(range_op_dispatch_type,
   return false;
 }
 
+bool
+operator_equal::fold_range (irange &r, tree type,
+   const prange &op1,
+   const prange &op2,
+   relation_trio rel) const
+{
+  if (relop_early_resolve (r, type, op1, op2, rel, VREL_EQ))
+return true;
+
+  // We can be sure the values are always equal or not if both ranges
+  // consist of a single value, and then compare them.
+  bool op1_const = wi::eq_p (op1.lower_bound (), op1.upper_bound ());
+  bool op2_const = wi::eq_p (op2.lower_bound (), op2.upper_bound ());
+  if (op1_const && op2_const)
+{
+  if (wi::eq_p (op1.lower_bound (), op2.upper_bound()))
+   r = range_true ();
+  else
+   r = range_false ();
+}
+  else
+{
+  // If ranges do not intersect, we know the range is not equal,
+  // otherwise we don't know anything for sure.
+  prange tmp = op1;
+  tmp.intersect (op2);
+  if (tmp.undefined_p ())
+   r = range_false ();
+  // Check if a constant cannot satisfy the bitmask requirements.
+  else if (op2_const && !op1.get_bitmask ().member_p (op2.lower_bound ()))
+r = range_false ();
+  else if (op1_const && !op2.get_bitmask ().member_p (op1.lower_bound ()))
+r = range_false ();
+  else
+   r = range_true_and_false ();
+}
+
+  //update_known_bitmask (r, EQ_EXPR, op1, op2);
+  return true;
+}
+
+bool
+operator_equal::op1_range (prange &r, tree type,
+  const irange &lhs,
+  const prange &op2,
+  relation_trio) const
+{
+  switch (get_bool_state (r, lhs, type))
+{
+case BRS_TRUE:
+  // If it's true, the re

[COMMITTED 22/23] Implement operator_ge for prange....

2024-05-04 Thread Aldy Hernandez
gcc/ChangeLog:

* range-op-mixed.h: Add overloaded declarations for pointer variants.
* range-op-ptr.cc (operator_ge::fold_range): New.
(operator_ge::op1_range): New.
(operator_ge::op2_range): New.
(operator_ge::op1_op2_relation): New.
(operator_ge::pointers_handled_p): New.
---
 gcc/range-op-mixed.h |  12 +
 gcc/range-op-ptr.cc  | 108 +++
 2 files changed, 120 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index f7a07b19635..44d51d68655 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -371,6 +371,9 @@ public:
   bool fold_range (irange &r, tree type,
   const irange &op1, const irange &op2,
   relation_trio = TRIO_VARYING) const final override;
+  bool fold_range (irange &r, tree type,
+  const prange &op1, const prange &op2,
+  relation_trio = TRIO_VARYING) const final override;
   bool fold_range (irange &r, tree type,
   const frange &op1, const frange &op2,
   relation_trio = TRIO_VARYING) const final override;
@@ -378,6 +381,9 @@ public:
   bool op1_range (irange &r, tree type,
  const irange &lhs, const irange &op2,
  relation_trio = TRIO_VARYING) const final override;
+  bool op1_range (prange &r, tree type,
+ const irange &lhs, const prange &op2,
+ relation_trio = TRIO_VARYING) const final override;
   bool op1_range (frange &r, tree type,
  const irange &lhs, const frange &op2,
  relation_trio = TRIO_VARYING) const final override;
@@ -385,12 +391,17 @@ public:
   bool op2_range (irange &r, tree type,
  const irange &lhs, const irange &op1,
  relation_trio = TRIO_VARYING) const final override;
+  bool op2_range (prange &r, tree type,
+ const irange &lhs, const prange &op1,
+ relation_trio = TRIO_VARYING) const final override;
   bool op2_range (frange &r, tree type,
  const irange &lhs, const frange &op1,
  relation_trio = TRIO_VARYING) const final override;
 
   relation_kind op1_op2_relation (const irange &lhs, const irange &,
  const irange &) const final override;
+  relation_kind op1_op2_relation (const irange &lhs, const prange &,
+ const prange &) const final override;
   relation_kind op1_op2_relation (const irange &lhs, const frange &,
  const frange &) const final override;
   void update_bitmask (irange &r, const irange &lh,
@@ -398,6 +409,7 @@ public:
   // Check op1 and op2 for compatibility.
   bool operand_check_p (tree, tree t1, tree t2) const final override
 { return range_compatible_p (t1, t2); }
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final 
override;
 };
 
 class operator_identity : public range_operator
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index 441a18c08c7..466edc6bf74 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -1853,6 +1853,114 @@ operator_gt::pointers_handled_p (range_op_dispatch_type 
type,
 }
 }
 
+bool
+operator_ge::fold_range (irange &r, tree type,
+const prange &op1,
+const prange &op2,
+relation_trio rel) const
+{
+  if (relop_early_resolve (r, type, op1, op2, rel, VREL_GE))
+return true;
+
+  signop sign = TYPE_SIGN (op1.type ());
+  gcc_checking_assert (sign == TYPE_SIGN (op2.type ()));
+
+  if (wi::ge_p (op1.lower_bound (), op2.upper_bound (), sign))
+r = range_true ();
+  else if (!wi::ge_p (op1.upper_bound (), op2.lower_bound (), sign))
+r = range_false ();
+  else
+r = range_true_and_false ();
+
+  //update_known_bitmask (r, GE_EXPR, op1, op2);
+  return true;
+}
+
+bool
+operator_ge::op1_range (prange &r, tree type,
+   const irange &lhs,
+   const prange &op2,
+   relation_trio) const
+{
+  if (op2.undefined_p ())
+return false;
+
+  switch (get_bool_state (r, lhs, type))
+{
+case BRS_TRUE:
+  build_ge (r, type, op2);
+  break;
+
+case BRS_FALSE:
+  build_lt (r, type, op2);
+  break;
+
+default:
+  break;
+}
+  return true;
+}
+
+bool
+operator_ge::op2_range (prange &r, tree type,
+   const irange &lhs,
+   const prange &op1,
+   relation_trio) const
+{
+  if (op1.undefined_p ())
+return false;
+
+  switch (get_bool_state (r, lhs, type))
+{
+case BRS_TRUE:
+  build_le (r, type, op1);
+  break;
+
+case BRS_FALSE:
+  build_gt (r, type, op1);
+  break;
+
+default:
+  break;
+}
+  return true;
+}
+
+relation_kind
+operator_ge::op1_op2_relation (const irange &lhs, const prange &,
+

[COMMITTED 08/23] Implement operator_identity for prange.

2024-05-04 Thread Aldy Hernandez
gcc/ChangeLog:

* range-op-mixed.h: Add overloaded declarations for fold_range, 
op1_range,
lhs_op1_relation, pointers_handled_p.
* range-op-ptr.cc (operator_identity::fold_range): New.
(operator_identity::lhs_op1_relation): New.
(operator_identity::op1_range): New.
(operator_identity::pointers_handled_p): New.
---
 gcc/range-op-mixed.h | 10 ++
 gcc/range-op-ptr.cc  | 47 
 2 files changed, 57 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 8163a4b53ca..60aaea9563d 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -349,18 +349,28 @@ public:
   bool fold_range (irange &r, tree type,
   const irange &op1, const irange &op2,
   relation_trio rel = TRIO_VARYING) const final override;
+  bool fold_range (prange &r, tree type,
+  const prange &op1, const prange &op2,
+  relation_trio rel = TRIO_VARYING) const final override;
   bool fold_range (frange &r, tree type ATTRIBUTE_UNUSED,
   const frange &op1, const frange &op2 ATTRIBUTE_UNUSED,
   relation_trio = TRIO_VARYING) const final override;
   bool op1_range (irange &r, tree type,
  const irange &lhs, const irange &op2,
  relation_trio rel = TRIO_VARYING) const final override;
+  bool op1_range (prange &r, tree type,
+ const prange &lhs, const prange &op2,
+ relation_trio rel = TRIO_VARYING) const final override;
   bool op1_range (frange &r, tree type ATTRIBUTE_UNUSED,
  const frange &lhs, const frange &op2 ATTRIBUTE_UNUSED,
  relation_trio = TRIO_VARYING) const final override;
   relation_kind lhs_op1_relation (const irange &lhs,
  const irange &op1, const irange &op2,
  relation_kind rel) const final override;
+  relation_kind lhs_op1_relation (const prange &lhs,
+ const prange &op1, const prange &op2,
+ relation_kind rel) const final override;
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final 
override;
 };
 
 class operator_cst : public range_operator
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index 560c798b90a..08419bfc798 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -636,6 +636,53 @@ public:
 }
 } op_hybrid_max;
 
+bool
+operator_identity::fold_range (prange &r, tree type ATTRIBUTE_UNUSED,
+  const prange &lh ATTRIBUTE_UNUSED,
+  const prange &rh ATTRIBUTE_UNUSED,
+  relation_trio) const
+{
+  r = lh;
+  return true;
+}
+
+relation_kind
+operator_identity::lhs_op1_relation (const prange &lhs,
+const prange &op1 ATTRIBUTE_UNUSED,
+const prange &op2 ATTRIBUTE_UNUSED,
+relation_kind) const
+{
+  if (lhs.undefined_p ())
+return VREL_VARYING;
+  // Simply a copy, so they are equivalent.
+  return VREL_EQ;
+}
+
+bool
+operator_identity::op1_range (prange &r, tree type ATTRIBUTE_UNUSED,
+ const prange &lhs,
+ const prange &op2 ATTRIBUTE_UNUSED,
+ relation_trio) const
+{
+  r = lhs;
+  return true;
+}
+
+bool
+operator_identity::pointers_handled_p (range_op_dispatch_type type,
+  unsigned dispatch) const
+{
+  switch (type)
+{
+case DISPATCH_FOLD_RANGE:
+case DISPATCH_OP1_RANGE:
+case DISPATCH_LHS_OP1_RELATION:
+  return dispatch == RO_PPP;
+default:
+  return true;
+}
+}
+
 // Initialize any pointer operators to the primary table
 
 void
-- 
2.44.0



[COMMITTED 14/23] Implement operator_pointer_diff for prange.

2024-05-04 Thread Aldy Hernandez
gcc/ChangeLog:

* range-op-ptr.cc
(operator_pointer_diff::op1_op2_relation_effect): New.
(operator_pointer_diff::pointers_handled_p): New.
---
 gcc/range-op-ptr.cc | 32 
 1 file changed, 32 insertions(+)

diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index a4418215613..b90b8bb9f65 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -564,10 +564,42 @@ class operator_pointer_diff : public range_operator
const irange &op1_range,
const irange &op2_range,
relation_kind rel) const;
+  virtual bool op1_op2_relation_effect (irange &lhs_range,
+   tree type,
+   const prange &op1_range,
+   const prange &op2_range,
+   relation_kind rel) const final override;
   void update_bitmask (irange &r, const irange &lh, const irange &rh) const
 { update_known_bitmask (r, POINTER_DIFF_EXPR, lh, rh); }
+  void update_bitmask (irange &r,
+  const prange &lh, const prange &rh) const final override
+  { update_known_bitmask (r, POINTER_DIFF_EXPR, lh, rh); }
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final 
override;
 } op_pointer_diff;
 
+bool
+operator_pointer_diff::op1_op2_relation_effect (irange &lhs_range, tree type,
+   const prange &op1_range,
+   const prange &op2_range,
+   relation_kind rel) const
+{
+  int_range<2> op1, op2, tmp;
+  range_op_handler cast (CONVERT_EXPR);
+
+  if (!cast.fold_range (op1, type, op1_range, tmp)
+  || !cast.fold_range (op2, type, op2_range, tmp))
+return false;
+
+  return minus_op1_op2_relation_effect (lhs_range, type, op1, op2, rel);
+}
+
+bool
+operator_pointer_diff::pointers_handled_p (range_op_dispatch_type,
+  unsigned) const
+{
+  return true;
+}
+
 bool
 operator_pointer_diff::op1_op2_relation_effect (irange &lhs_range, tree type,
const irange &op1_range,
-- 
2.44.0



[COMMITTED 23/23] Add prange entries in gimple-range-op.cc.

2024-05-04 Thread Aldy Hernandez
gcc/ChangeLog:

* gimple-range-op.cc (class cfn_pass_through_arg1): Add overloads
for prange operations.
(cfn_strlen): Same.
---
 gcc/gimple-range-op.cc | 36 
 1 file changed, 36 insertions(+)

diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index 587de186db2..55dfbb23ce2 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -311,12 +311,37 @@ public:
 r = lh;
 return true;
   }
+  virtual bool fold_range (prange &r, tree, const prange &lh,
+  const prange &, relation_trio) const
+  {
+r = lh;
+return true;
+  }
   virtual bool op1_range (irange &r, tree, const irange &lhs,
  const irange &, relation_trio) const
   {
 r = lhs;
 return true;
   }
+  virtual bool op1_range (prange &r, tree, const prange &lhs,
+ const prange &, relation_trio) const
+  {
+r = lhs;
+return true;
+  }
+  virtual bool pointers_handled_p (range_op_dispatch_type type,
+  unsigned dispatch) const
+  {
+switch (type)
+  {
+  case DISPATCH_FOLD_RANGE:
+   return dispatch == RO_PPP;
+  case DISPATCH_OP1_RANGE:
+   return dispatch == RO_PPP;
+  default:
+   return true;
+  }
+  }
 } op_cfn_pass_through_arg1;
 
 // Implement range operator for CFN_BUILT_IN_SIGNBIT.
@@ -1107,6 +1132,17 @@ public:
 r.set (type, wi::zero (TYPE_PRECISION (type)), max - 2);
 return true;
   }
+  virtual bool pointers_handled_p (range_op_dispatch_type type,
+  unsigned dispatch) const
+  {
+switch (type)
+  {
+  case DISPATCH_FOLD_RANGE:
+   return dispatch == RO_IPI;
+  default:
+   return true;
+  }
+  }
 } op_cfn_strlen;
 
 
-- 
2.44.0



[COMMITTED 20/23] Implement operator_le for prange.

2024-05-04 Thread Aldy Hernandez
gcc/ChangeLog:

* range-op-mixed.h: Add overloaded declarations for pointer variants.
* range-op-ptr.cc (operator_le::fold_range): New.
(operator_le::op1_range): New.
(operator_le::op2_range): New.
(operator_le::op1_op2_relation): New.
(operator_le::pointers_handled_p): New.
---
 gcc/range-op-mixed.h |  12 +
 gcc/range-op-ptr.cc  | 108 +++
 2 files changed, 120 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index b82d06572a7..571729e2ab6 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -268,6 +268,9 @@ public:
   bool fold_range (irange &r, tree type,
   const irange &op1, const irange &op2,
   relation_trio = TRIO_VARYING) const final override;
+  bool fold_range (irange &r, tree type,
+  const prange &op1, const prange &op2,
+  relation_trio = TRIO_VARYING) const final override;
   bool fold_range (irange &r, tree type,
   const frange &op1, const frange &op2,
   relation_trio rel = TRIO_VARYING) const final override;
@@ -275,6 +278,9 @@ public:
   bool op1_range (irange &r, tree type,
  const irange &lhs, const irange &op2,
  relation_trio = TRIO_VARYING) const final override;
+  bool op1_range (prange &r, tree type,
+ const irange &lhs, const prange &op2,
+ relation_trio = TRIO_VARYING) const final override;
   bool op1_range (frange &r, tree type,
  const irange &lhs, const frange &op2,
  relation_trio rel = TRIO_VARYING) const final override;
@@ -282,12 +288,17 @@ public:
   bool op2_range (irange &r, tree type,
  const irange &lhs, const irange &op1,
  relation_trio = TRIO_VARYING) const final override;
+  bool op2_range (prange &r, tree type,
+ const irange &lhs, const prange &op1,
+ relation_trio = TRIO_VARYING) const final override;
   bool op2_range (frange &r, tree type,
  const irange &lhs, const frange &op1,
  relation_trio rel = TRIO_VARYING) const final override;
 
   relation_kind op1_op2_relation (const irange &lhs, const irange &,
  const irange &) const final override;
+  relation_kind op1_op2_relation (const irange &lhs, const prange &,
+ const prange &) const final override;
   relation_kind op1_op2_relation (const irange &lhs, const frange &,
  const frange &) const final override;
   void update_bitmask (irange &r, const irange &lh,
@@ -295,6 +306,7 @@ public:
   // Check op1 and op2 for compatibility.
   bool operand_check_p (tree, tree t1, tree t2) const final override
 { return range_compatible_p (t1, t2); }
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final 
override;
 };
 
 class operator_gt :  public range_operator
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index 11629ba6d8d..eb28211b583 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -1639,6 +1639,114 @@ operator_lt::pointers_handled_p (range_op_dispatch_type 
type,
 }
 }
 
+bool
+operator_le::fold_range (irange &r, tree type,
+const prange &op1,
+const prange &op2,
+relation_trio rel) const
+{
+  if (relop_early_resolve (r, type, op1, op2, rel, VREL_LE))
+return true;
+
+  signop sign = TYPE_SIGN (op1.type ());
+  gcc_checking_assert (sign == TYPE_SIGN (op2.type ()));
+
+  if (wi::le_p (op1.upper_bound (), op2.lower_bound (), sign))
+r = range_true ();
+  else if (!wi::le_p (op1.lower_bound (), op2.upper_bound (), sign))
+r = range_false ();
+  else
+r = range_true_and_false ();
+
+  //update_known_bitmask (r, LE_EXPR, op1, op2);
+  return true;
+}
+
+bool
+operator_le::op1_range (prange &r, tree type,
+   const irange &lhs,
+   const prange &op2,
+   relation_trio) const
+{
+  if (op2.undefined_p ())
+return false;
+
+  switch (get_bool_state (r, lhs, type))
+{
+case BRS_TRUE:
+  build_le (r, type, op2);
+  break;
+
+case BRS_FALSE:
+  build_gt (r, type, op2);
+  break;
+
+default:
+  break;
+}
+  return true;
+}
+
+bool
+operator_le::op2_range (prange &r, tree type,
+   const irange &lhs,
+   const prange &op1,
+   relation_trio) const
+{
+  if (op1.undefined_p ())
+return false;
+
+  switch (get_bool_state (r, lhs, type))
+{
+case BRS_TRUE:
+  build_ge (r, type, op1);
+  break;
+
+case BRS_FALSE:
+  build_lt (r, type, op1);
+  break;
+
+default:
+  break;
+}
+  return true;
+}
+
+relation_kind
+operator_le::op1_op2_relation (const irange &lhs, const prange &,
+ 

[COMMITTED 11/23] Implement operator_min and operator_max for prange.

2024-05-04 Thread Aldy Hernandez
gcc/ChangeLog:

* range-op-mixed.h: Add overloaded declarations for pointer variants.
* range-op-ptr.cc (operator_min::fold_range): New.
(operator_min::pointers_handled_p): New.
(operator_max::fold_range): New.
(operator_max::pointers_handled_p): New.
---
 gcc/range-op-mixed.h | 12 
 gcc/range-op-ptr.cc  | 70 
 2 files changed, 82 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 11b1bf0bca4..b69e674a78b 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -761,12 +761,18 @@ protected:
 class operator_min : public range_operator
 {
 public:
+  using range_operator::fold_range;
   using range_operator::update_bitmask;
+  bool fold_range (prange &r, tree type,
+  const prange &op1,
+  const prange &op2,
+  relation_trio) const final override;
   void update_bitmask (irange &r, const irange &lh,
   const irange &rh) const override;
   // Check compatibility of all operands.
   bool operand_check_p (tree t1, tree t2, tree t3) const final override
 { return range_compatible_p (t1, t2) && range_compatible_p (t1, t3); }
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final 
override;
 protected:
   void wi_fold (irange &r, tree type, const wide_int &lh_lb,
const wide_int &lh_ub, const wide_int &rh_lb,
@@ -776,12 +782,18 @@ protected:
 class operator_max : public range_operator
 {
 public:
+  using range_operator::fold_range;
   using range_operator::update_bitmask;
+  bool fold_range (prange &r, tree type,
+  const prange &op1,
+  const prange &op2,
+  relation_trio) const final override;
   void update_bitmask (irange &r, const irange &lh,
   const irange &rh) const override;
   // Check compatibility of all operands.
   bool operand_check_p (tree t1, tree t2, tree t3) const final override
 { return range_compatible_p (t1, t2) && range_compatible_p (t1, t3); }
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final 
override;
 protected:
   void wi_fold (irange &r, tree type, const wide_int &lh_lb,
const wide_int &lh_ub, const wide_int &rh_lb,
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index b8f86c8e838..0addd1096c2 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -951,6 +951,76 @@ operator_cast::pointers_handled_p (range_op_dispatch_type 
type,
 }
 }
 
+bool
+operator_min::fold_range (prange &r, tree type,
+ const prange &op1,
+ const prange &op2,
+ relation_trio) const
+{
+  // For MIN/MAX expressions with pointers, we only care about
+  // nullness.  If both are non null, then the result is nonnull.
+  // If both are null, then the result is null.  Otherwise they
+  // are varying.
+  if (!range_includes_zero_p (op1)
+  && !range_includes_zero_p (op2))
+r.set_nonzero (type);
+  else if (op1.zero_p () && op2.zero_p ())
+r.set_zero (type);
+  else
+r.set_varying (type);
+
+  update_known_bitmask (r, MIN_EXPR, op1, op2);
+  return true;
+}
+
+bool
+operator_min::pointers_handled_p (range_op_dispatch_type type,
+ unsigned dispatch) const
+{
+  switch (type)
+{
+case DISPATCH_FOLD_RANGE:
+  return dispatch == RO_PPP;
+default:
+  return true;
+}
+}
+
+bool
+operator_max::fold_range (prange &r, tree type,
+ const prange &op1,
+ const prange &op2,
+ relation_trio) const
+{
+  // For MIN/MAX expressions with pointers, we only care about
+  // nullness.  If both are non null, then the result is nonnull.
+  // If both are null, then the result is null.  Otherwise they
+  // are varying.
+  if (!range_includes_zero_p (op1)
+  && !range_includes_zero_p (op2))
+r.set_nonzero (type);
+  else if (op1.zero_p () && op2.zero_p ())
+r.set_zero (type);
+  else
+r.set_varying (type);
+
+  update_known_bitmask (r, MAX_EXPR, op1, op2);
+  return true;
+}
+
+bool
+operator_max::pointers_handled_p (range_op_dispatch_type type,
+ unsigned dispatch) const
+{
+  switch (type)
+{
+case DISPATCH_FOLD_RANGE:
+  return dispatch == RO_PPP;
+default:
+  return true;
+}
+}
+
 // Initialize any pointer operators to the primary table
 
 void
-- 
2.44.0



[COMMITTED 09/23] Implement operator_cst for prange.

2024-05-04 Thread Aldy Hernandez
gcc/ChangeLog:

* range-op-mixed.h: Add overloaded declarations for pointer variants.
* range-op-ptr.cc (operator_cst::fold_range): New.
(operator_cst::pointers_handled_p): New.
---
 gcc/range-op-mixed.h |  4 
 gcc/range-op-ptr.cc  | 23 +++
 2 files changed, 27 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 60aaea9563d..04c8acbd94a 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -380,9 +380,13 @@ public:
   bool fold_range (irange &r, tree type,
   const irange &op1, const irange &op2,
   relation_trio rel = TRIO_VARYING) const final override;
+  bool fold_range (prange &r, tree type,
+  const prange &op1, const prange &op2,
+  relation_trio rel = TRIO_VARYING) const final override;
   bool fold_range (frange &r, tree type,
   const frange &op1, const frange &op2,
   relation_trio = TRIO_VARYING) const final override;
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final 
override;
 };
 
 
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index 08419bfc798..e59e278cbd7 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -683,6 +683,29 @@ operator_identity::pointers_handled_p 
(range_op_dispatch_type type,
 }
 }
 
+bool
+operator_cst::fold_range (prange &r, tree type ATTRIBUTE_UNUSED,
+ const prange &lh,
+ const prange & ATTRIBUTE_UNUSED,
+ relation_trio) const
+{
+  r = lh;
+  return true;
+}
+
+bool
+operator_cst::pointers_handled_p (range_op_dispatch_type type,
+ unsigned dispatch) const
+{
+  switch (type)
+{
+case DISPATCH_FOLD_RANGE:
+  return dispatch == RO_PPP;
+default:
+  return true;
+}
+}
+
 // Initialize any pointer operators to the primary table
 
 void
-- 
2.44.0



[COMMITTED 17/23] Implement operator_not_equal for prange.

2024-05-04 Thread Aldy Hernandez
gcc/ChangeLog:

* range-op-mixed.h: Add overloaded declarations for pointer variants.
* range-op-ptr.cc (operator_not_equal::fold_range): New.
(operator_not_equal::op1_range): New.
(operator_not_equal::op2_range): New.
(operator_not_equal::op1_op2_relation): New.
(operator_not_equal::pointers_handled_p): New.
---
 gcc/range-op-mixed.h |  12 +
 gcc/range-op-ptr.cc  | 118 +++
 2 files changed, 130 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index c45aed93567..980611dc339 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -155,6 +155,9 @@ public:
   bool fold_range (irange &r, tree type,
   const irange &op1, const irange &op2,
   relation_trio = TRIO_VARYING) const final override;
+  bool fold_range (irange &r, tree type,
+  const prange &op1, const prange &op2,
+  relation_trio rel = TRIO_VARYING) const final override;
   bool fold_range (irange &r, tree type,
   const frange &op1, const frange &op2,
   relation_trio rel = TRIO_VARYING) const final override;
@@ -162,6 +165,9 @@ public:
   bool op1_range (irange &r, tree type,
  const irange &lhs, const irange &op2,
  relation_trio = TRIO_VARYING) const final override;
+  bool op1_range (prange &r, tree type,
+ const irange &lhs, const prange &op2,
+ relation_trio = TRIO_VARYING) const final override;
   bool op1_range (frange &r, tree type,
  const irange &lhs, const frange &op2,
  relation_trio = TRIO_VARYING) const final override;
@@ -169,12 +175,17 @@ public:
   bool op2_range (irange &r, tree type,
  const irange &lhs, const irange &op1,
  relation_trio = TRIO_VARYING) const final override;
+  bool op2_range (prange &r, tree type,
+ const irange &lhs, const prange &op1,
+ relation_trio = TRIO_VARYING) const final override;
   bool op2_range (frange &r, tree type,
  const irange &lhs, const frange &op1,
  relation_trio = TRIO_VARYING) const final override;
 
   relation_kind op1_op2_relation (const irange &lhs, const irange &,
  const irange &) const final override;
+  relation_kind op1_op2_relation (const irange &lhs, const prange &,
+ const prange &) const final override;
   relation_kind op1_op2_relation (const irange &lhs, const frange &,
  const frange &) const final override;
   void update_bitmask (irange &r, const irange &lh,
@@ -182,6 +193,7 @@ public:
   // Check op1 and op2 for compatibility.
   bool operand_check_p (tree, tree t1, tree t2) const final override
 { return range_compatible_p (t1, t2); }
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final 
override;
 };
 
 class operator_lt :  public range_operator
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index 2f2f4bb2b5d..081e8fdba1f 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -1230,6 +1230,124 @@ operator_bitwise_or::pointers_handled_p 
(range_op_dispatch_type,
   return false;
 }
 
+bool
+operator_not_equal::fold_range (irange &r, tree type,
+   const prange &op1,
+   const prange &op2,
+   relation_trio rel) const
+{
+  if (relop_early_resolve (r, type, op1, op2, rel, VREL_NE))
+return true;
+
+  // We can be sure the values are always equal or not if both ranges
+  // consist of a single value, and then compare them.
+  bool op1_const = wi::eq_p (op1.lower_bound (), op1.upper_bound ());
+  bool op2_const = wi::eq_p (op2.lower_bound (), op2.upper_bound ());
+  if (op1_const && op2_const)
+{
+  if (wi::ne_p (op1.lower_bound (), op2.upper_bound()))
+   r = range_true ();
+  else
+   r = range_false ();
+}
+  else
+{
+  // If ranges do not intersect, we know the range is not equal,
+  // otherwise we don't know anything for sure.
+  prange tmp = op1;
+  tmp.intersect (op2);
+  if (tmp.undefined_p ())
+   r = range_true ();
+  // Check if a constant cannot satisfy the bitmask requirements.
+  else if (op2_const && !op1.get_bitmask ().member_p (op2.lower_bound ()))
+r = range_true ();
+  else if (op1_const && !op2.get_bitmask ().member_p (op1.lower_bound ()))
+r = range_true ();
+  else
+   r = range_true_and_false ();
+}
+
+  //update_known_bitmask (r, NE_EXPR, op1, op2);
+  return true;
+}
+
+bool
+operator_not_equal::op1_range (prange &r, tree type,
+  const irange &lhs,
+  const prange &op2,
+  relation_trio) const
+{
+  switch (get_bool_state (r, lhs, type))
+{
+  

[COMMITTED 06/23] Add prange implementation for get_legacy_range.

2024-05-04 Thread Aldy Hernandez
gcc/ChangeLog:

* value-range.cc (get_legacy_range): New version for prange.
---
 gcc/value-range.cc | 35 +--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 62170a438bf..3e1ecf69517 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -1377,6 +1377,38 @@ get_legacy_range (const irange &r, tree &min, tree &max)
   return VR_RANGE;
 }
 
+static value_range_kind
+get_legacy_range (const prange &r, tree &min, tree &max)
+{
+  if (r.undefined_p ())
+{
+  min = NULL_TREE;
+  max = NULL_TREE;
+  return VR_UNDEFINED;
+}
+
+  tree type = r.type ();
+  if (r.varying_p ())
+{
+  min = r.lbound ();
+  max = r.ubound ();
+  return VR_VARYING;
+}
+  if (r.zero_p ())
+{
+  min = max = r.lbound ();
+  return VR_RANGE;
+}
+  if (r.nonzero_p ())
+{
+  min = max = build_zero_cst (type);
+  return VR_ANTI_RANGE;
+}
+  min = r.lbound ();
+  max = r.ubound ();
+  return VR_RANGE;
+}
+
 // Given a range in V, return an old-style legacy range consisting of
 // a value_range_kind with a MIN/MAX.  This is to maintain
 // compatibility with passes that still depend on VR_ANTI_RANGE, and
@@ -1388,8 +1420,7 @@ get_legacy_range (const vrange &v, tree &min, tree &max)
   if (is_a  (v))
 return get_legacy_range (as_a  (v), min, max);
 
-  gcc_unreachable ();
-  return VR_UNDEFINED;
+  return get_legacy_range (as_a  (v), min, max);
 }
 
 /* Set value range to the canonical form of {VRTYPE, MIN, MAX, EQUIV}.
-- 
2.44.0



[COMMITTED 19/23] Implement operator_lt for prange.

2024-05-04 Thread Aldy Hernandez
gcc/ChangeLog:

* range-op-mixed.h: Add overloaded declarations for pointer variants.
* range-op-ptr.cc (max_limit): New.
(min_limit): New.
(build_lt): New.
(build_le): New.
(build_gt): New.
(build_ge): New.
(operator_lt::fold_range): New.
(operator_lt::op1_range): New.
(operator_lt::op2_range): New.
(operator_lt::op1_op2_relation): New.
(operator_lt::pointers_handled_p): New.
---
 gcc/range-op-mixed.h |  12 +++
 gcc/range-op-ptr.cc  | 174 +++
 2 files changed, 186 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index ee8d9dd328f..b82d06572a7 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -219,23 +219,34 @@ public:
   bool fold_range (irange &r, tree type,
   const irange &op1, const irange &op2,
   relation_trio = TRIO_VARYING) const final override;
+  bool fold_range (irange &r, tree type,
+  const prange &op1, const prange &op2,
+  relation_trio = TRIO_VARYING) const final override;
   bool fold_range (irange &r, tree type,
   const frange &op1, const frange &op2,
   relation_trio = TRIO_VARYING) const final override;
   bool op1_range (irange &r, tree type,
  const irange &lhs, const irange &op2,
  relation_trio = TRIO_VARYING) const final override;
+  bool op1_range (prange &r, tree type,
+ const irange &lhs, const prange &op2,
+ relation_trio = TRIO_VARYING) const final override;
   bool op1_range (frange &r, tree type,
  const irange &lhs, const frange &op2,
  relation_trio = TRIO_VARYING) const final override;
   bool op2_range (irange &r, tree type,
  const irange &lhs, const irange &op1,
  relation_trio = TRIO_VARYING) const final override;
+  bool op2_range (prange &r, tree type,
+ const irange &lhs, const prange &op1,
+ relation_trio = TRIO_VARYING) const final override;
   bool op2_range (frange &r, tree type,
  const irange &lhs, const frange &op1,
  relation_trio = TRIO_VARYING) const final override;
   relation_kind op1_op2_relation (const irange &lhs, const irange &,
  const irange &) const final override;
+  relation_kind op1_op2_relation (const irange &lhs, const prange &,
+ const prange &) const final override;
   relation_kind op1_op2_relation (const irange &lhs, const frange &,
  const frange &) const final override;
   void update_bitmask (irange &r, const irange &lh,
@@ -243,6 +254,7 @@ public:
   // Check op1 and op2 for compatibility.
   bool operand_check_p (tree, tree t1, tree t2) const final override
 { return range_compatible_p (t1, t2); }
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final 
override;
 };
 
 class operator_le :  public range_operator
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index fb2888bf079..11629ba6d8d 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -262,6 +262,69 @@ range_operator::update_bitmask (irange &,
 {
 }
 
+// Return the upper limit for a type.
+
+static inline wide_int
+max_limit (const_tree type)
+{
+  return wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type));
+}
+
+// Return the lower limit for a type.
+
+static inline wide_int
+min_limit (const_tree type)
+{
+  return wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type));
+}
+
+// Build a range that is < VAL and store it in R.
+
+static void
+build_lt (prange &r, tree type, const prange &val)
+{
+  wi::overflow_type ov;
+  wide_int lim = wi::sub (val.upper_bound (), 1, UNSIGNED, &ov);
+
+  // If val - 1 underflows, check if X < MIN, which is an empty range.
+  if (ov)
+r.set_undefined ();
+  else
+r.set (type, min_limit (type), lim);
+}
+
+// Build a range that is <= VAL and store it in R.
+
+static void
+build_le (prange &r, tree type, const prange &val)
+{
+  r.set (type, min_limit (type), val.upper_bound ());
+}
+
+// Build a range that is > VAL and store it in R.
+
+static void
+build_gt (prange &r, tree type, const prange &val)
+{
+  wi::overflow_type ov;
+  wide_int lim = wi::add (val.lower_bound (), 1, UNSIGNED, &ov);
+
+  // If val + 1 overflows, check is for X > MAX, which is an empty range.
+  if (ov)
+r.set_undefined ();
+  else
+r.set (type, lim, max_limit (type));
+
+}
+
+// Build a range that is >= VAL and store it in R.
+
+static void
+build_ge (prange &r, tree type, const prange &val)
+{
+  r.set (type, val.lower_bound (), max_limit (type));
+}
+
 class pointer_plus_operator : public range_operator
 {
   using range_operator::update_bitmask;
@@ -1465,6 +1528,117 @@ operator_not_equal::pointers_handled_p 
(range_op_dispatch_type type,
 }
 }
 
+bool
+

[COMMITTED 12/23] Implement operator_addr_expr for prange.

2024-05-04 Thread Aldy Hernandez
gcc/ChangeLog:

* range-op-mixed.h: Add overloaded declarations for pointer variants.
* range-op-ptr.cc (operator_addr_expr::op1_range): New.
(operator_addr_expr::pointers_handled_p): New.
---
 gcc/range-op-mixed.h |  4 
 gcc/range-op-ptr.cc  | 38 ++
 2 files changed, 42 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index b69e674a78b..0df300781f1 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -655,6 +655,10 @@ public:
   bool op1_range (irange &r, tree type,
  const irange &lhs, const irange &op2,
  relation_trio rel = TRIO_VARYING) const final override;
+  bool op1_range (prange &r, tree type,
+ const prange &lhs, const prange &op2,
+ relation_trio rel = TRIO_VARYING) const final override;
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final 
override;
 };
 
 class operator_bitwise_not : public range_operator
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index 0addd1096c2..38d9f65566f 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -1021,6 +1021,44 @@ operator_max::pointers_handled_p (range_op_dispatch_type 
type,
 }
 }
 
+bool
+operator_addr_expr::op1_range (prange &r, tree type,
+  const prange &lhs,
+  const prange &op2,
+  relation_trio) const
+{
+  if (empty_range_varying (r, type, lhs, op2))
+return true;
+
+  // Return a non-null pointer of the LHS type (passed in op2), but only
+  // if we cant overflow, eitherwise a no-zero offset could wrap to zero.
+  // See PR 111009.
+  if (!lhs.undefined_p ()
+  && !range_includes_zero_p (lhs)
+  && TYPE_OVERFLOW_UNDEFINED (type))
+r.set_nonzero (type);
+  else
+r.set_varying (type);
+  return true;
+}
+
+bool
+operator_addr_expr::pointers_handled_p (range_op_dispatch_type type,
+   unsigned dispatch) const
+{
+  switch (type)
+{
+case DISPATCH_FOLD_RANGE:
+  // NOTE: It looks like we never generate this combination.
+  gcc_unreachable ();
+  return false;
+case DISPATCH_OP1_RANGE:
+  return dispatch == RO_PPP;
+default:
+  return true;
+}
+}
+
 // Initialize any pointer operators to the primary table
 
 void
-- 
2.44.0



[COMMITTED 10/23] Implement operator_cast for prange.

2024-05-04 Thread Aldy Hernandez
gcc/ChangeLog:

* range-op-mixed.h: Add overloaded declarations for pointer variants.
* range-op-ptr.cc (operator_cast::fold_range): New.
(operator_cast::op1_range): New.
(operator_cast::lhs_op1_relation): New.
(operator_cast::pointers_handled_p): New.
---
 gcc/range-op-mixed.h |  28 +
 gcc/range-op-ptr.cc  | 245 +++
 2 files changed, 273 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 04c8acbd94a..11b1bf0bca4 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -400,14 +400,42 @@ public:
   bool fold_range (irange &r, tree type,
   const irange &op1, const irange &op2,
   relation_trio rel = TRIO_VARYING) const final override;
+  bool fold_range (prange &r, tree type,
+  const prange &op1, const prange &op2,
+  relation_trio rel = TRIO_VARYING) const final override;
+  bool fold_range (irange &r, tree type,
+  const prange &op1, const irange &op2,
+  relation_trio rel = TRIO_VARYING) const final override;
+  bool fold_range (prange &r, tree type,
+  const irange &op1, const prange &op2,
+  relation_trio rel = TRIO_VARYING) const final override;
   bool op1_range (irange &r, tree type,
  const irange &lhs, const irange &op2,
  relation_trio rel = TRIO_VARYING) const final override;
+  bool op1_range (prange &r, tree type,
+ const prange &lhs, const prange &op2,
+ relation_trio rel = TRIO_VARYING) const final override;
+  bool op1_range (irange &r, tree type,
+ const prange &lhs, const irange &op2,
+ relation_trio rel = TRIO_VARYING) const final override;
+  bool op1_range (prange &r, tree type,
+ const irange &lhs, const prange &op2,
+ relation_trio rel = TRIO_VARYING) const final override;
   relation_kind lhs_op1_relation (const irange &lhs,
  const irange &op1, const irange &op2,
  relation_kind) const final override;
+  relation_kind lhs_op1_relation (const prange &lhs,
+ const prange &op1, const prange &op2,
+ relation_kind) const final override;
+  relation_kind lhs_op1_relation (const prange &lhs,
+ const irange &op1, const irange &op2,
+ relation_kind) const final override;
+  relation_kind lhs_op1_relation (const irange &lhs,
+ const prange &op1, const prange &op2,
+ relation_kind) const final override;
   void update_bitmask (irange &r, const irange &lh,
   const irange &rh) const final override;
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final 
override;
 private:
   bool truncating_cast_p (const irange &inner, const irange &outer) const;
   bool inside_domain_p (const wide_int &min, const wide_int &max,
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index e59e278cbd7..b8f86c8e838 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -706,6 +706,251 @@ operator_cst::pointers_handled_p (range_op_dispatch_type 
type,
 }
 }
 
+// Cast between pointers.
+
+bool
+operator_cast::fold_range (prange &r, tree type,
+  const prange &inner,
+  const prange &outer,
+  relation_trio) const
+{
+  if (empty_range_varying (r, type, inner, outer))
+return true;
+
+  r.set (type, inner.lower_bound (), inner.upper_bound ());
+  r.update_bitmask (inner.get_bitmask ());
+  return true;
+}
+
+// Cast a pointer to an integer.
+
+bool
+operator_cast::fold_range (irange &r, tree type,
+  const prange &inner,
+  const irange &outer,
+  relation_trio) const
+{
+  if (empty_range_varying (r, type, inner, outer))
+return true;
+
+  // Represent INNER as an integer of the same size, and then cast it
+  // to the resulting integer type.
+  tree pointer_uint_type = make_unsigned_type (TYPE_PRECISION (inner.type ()));
+  r.set (pointer_uint_type, inner.lower_bound (), inner.upper_bound ());
+  r.update_bitmask (inner.get_bitmask ());
+  range_cast (r, type);
+  return true;
+}
+
+// Cast an integer to a pointer.
+
+bool
+operator_cast::fold_range (prange &r, tree type,
+  const irange &inner,
+  const prange &outer,
+  relation_trio) const
+{
+  if (empty_range_varying (r, type, inner, outer))
+return true;
+
+  // Cast INNER to an integer of the same size as the pointer we want,
+  // and then copy the bounds to the resulting pointer range.
+  int_range<2> tmp = inner;
+  tree pointer_uint_type = make_unsigned_type

[COMMITTED 13/23] Implement pointer_plus_operator for prange.

2024-05-04 Thread Aldy Hernandez
gcc/ChangeLog:

* range-op-ptr.cc (class pointer_plus_operator): Add overloaded 
declarations
for pointer variants.
(pointer_plus_operator::fold_range): New.
(pointer_plus_operator::op2_range): New.
(pointer_plus_operator::pointers_handled_p): New.
---
 gcc/range-op-ptr.cc | 98 +
 1 file changed, 98 insertions(+)

diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index 38d9f65566f..a4418215613 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -265,8 +265,17 @@ range_operator::update_bitmask (irange &,
 class pointer_plus_operator : public range_operator
 {
   using range_operator::update_bitmask;
+  using range_operator::fold_range;
   using range_operator::op2_range;
 public:
+  virtual bool fold_range (prange &r, tree type,
+  const prange &op1,
+  const irange &op2,
+  relation_trio) const final override;
+  virtual bool op2_range (irange &r, tree type,
+ const prange &lhs,
+ const prange &op1,
+ relation_trio = TRIO_VARYING) const final override;
   virtual void wi_fold (irange &r, tree type,
const wide_int &lh_lb,
const wide_int &lh_ub,
@@ -276,10 +285,99 @@ public:
  const irange &lhs,
  const irange &op1,
  relation_trio = TRIO_VARYING) const;
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final 
override;
   void update_bitmask (irange &r, const irange &lh, const irange &rh) const
 { update_known_bitmask (r, POINTER_PLUS_EXPR, lh, rh); }
 } op_pointer_plus;
 
+bool
+pointer_plus_operator::fold_range (prange &r, tree type,
+  const prange &op1,
+  const irange &op2,
+  relation_trio) const
+{
+  if (empty_range_varying (r, type, op1, op2))
+return true;
+
+  const wide_int lh_lb = op1.lower_bound ();
+  const wide_int lh_ub = op1.upper_bound ();
+  const wide_int rh_lb = op2.lower_bound ();
+  const wide_int rh_ub = op2.upper_bound ();
+
+  // Check for [0,0] + const, and simply return the const.
+  if (lh_lb == 0 && lh_ub == 0 && rh_lb == rh_ub)
+{
+  r.set (type, rh_lb, rh_lb);
+  return true;
+}
+
+  // For pointer types, we are really only interested in asserting
+  // whether the expression evaluates to non-NULL.
+  //
+  // With -fno-delete-null-pointer-checks we need to be more
+  // conservative.  As some object might reside at address 0,
+  // then some offset could be added to it and the same offset
+  // subtracted again and the result would be NULL.
+  // E.g.
+  // static int a[12]; where &a[0] is NULL and
+  // ptr = &a[6];
+  // ptr -= 6;
+  // ptr will be NULL here, even when there is POINTER_PLUS_EXPR
+  // where the first range doesn't include zero and the second one
+  // doesn't either.  As the second operand is sizetype (unsigned),
+  // consider all ranges where the MSB could be set as possible
+  // subtractions where the result might be NULL.
+  if ((!wi_includes_zero_p (type, lh_lb, lh_ub)
+   || !wi_includes_zero_p (type, rh_lb, rh_ub))
+  && !TYPE_OVERFLOW_WRAPS (type)
+  && (flag_delete_null_pointer_checks
+ || !wi::sign_mask (rh_ub)))
+r.set_nonzero (type);
+  else if (lh_lb == lh_ub && lh_lb == 0
+  && rh_lb == rh_ub && rh_lb == 0)
+r.set_zero (type);
+  else
+   r.set_varying (type);
+
+  update_known_bitmask (r, POINTER_PLUS_EXPR, op1, op2);
+  return true;
+}
+
+bool
+pointer_plus_operator::op2_range (irange &r, tree type,
+ const prange &lhs ATTRIBUTE_UNUSED,
+ const prange &op1 ATTRIBUTE_UNUSED,
+ relation_trio trio) const
+{
+  relation_kind rel = trio.lhs_op1 ();
+  r.set_varying (type);
+
+  // If the LHS and OP1 are equal, the op2 must be zero.
+  if (rel == VREL_EQ)
+r.set_zero (type);
+  // If the LHS and OP1 are not equal, the offset must be non-zero.
+  else if (rel == VREL_NE)
+r.set_nonzero (type);
+  else
+return false;
+  return true;
+}
+
+bool
+pointer_plus_operator::pointers_handled_p (range_op_dispatch_type type,
+  unsigned dispatch) const
+{
+  switch (type)
+{
+case DISPATCH_FOLD_RANGE:
+  return dispatch == RO_PPI;
+case DISPATCH_OP2_RANGE:
+  return dispatch == RO_IPP;
+default:
+  return true;
+}
+}
+
 void
 pointer_plus_operator::wi_fold (irange &r, tree type,
const wide_int &lh_lb,
-- 
2.44.0



[COMMITTED 15/23] Implement operator_bitwise_and for prange.

2024-05-04 Thread Aldy Hernandez
gcc/ChangeLog:

* range-op-mixed.h: Add overloaded declarations for pointer variants.
* range-op-ptr.cc (operator_bitwise_and::fold_range): New.
(operator_bitwise_and::pointers_handled_p): New.
---
 gcc/range-op-mixed.h |  6 ++
 gcc/range-op-ptr.cc  | 30 ++
 2 files changed, 36 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 0df300781f1..6158fc51f8e 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -712,10 +712,15 @@ private:
 class operator_bitwise_and : public range_operator
 {
 public:
+  using range_operator::fold_range;
   using range_operator::op1_range;
   using range_operator::op2_range;
   using range_operator::lhs_op1_relation;
   using range_operator::update_bitmask;
+  bool fold_range (prange &r, tree type,
+  const prange &op1,
+  const prange &op2,
+  relation_trio) const final override;
   bool op1_range (irange &r, tree type,
  const irange &lhs, const irange &op2,
  relation_trio rel = TRIO_VARYING) const override;
@@ -730,6 +735,7 @@ public:
   // Check compatibility of all operands.
   bool operand_check_p (tree t1, tree t2, tree t3) const final override
 { return range_compatible_p (t1, t2) && range_compatible_p (t1, t3); }
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final 
override;
 protected:
   void wi_fold (irange &r, tree type, const wide_int &lh_lb,
const wide_int &lh_ub, const wide_int &rh_lb,
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index b90b8bb9f65..8d5049b1daf 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -1189,6 +1189,36 @@ operator_addr_expr::pointers_handled_p 
(range_op_dispatch_type type,
 }
 }
 
+bool
+operator_bitwise_and::fold_range (prange &r, tree type,
+ const prange &op1,
+ const prange &op2 ATTRIBUTE_UNUSED,
+ relation_trio) const
+{
+  // For pointer types, we are really only interested in asserting
+  // whether the expression evaluates to non-NULL.
+  if (op1.zero_p () || op2.zero_p ())
+r.set_zero (type);
+  else
+r.set_varying (type);
+
+  update_known_bitmask (r, BIT_AND_EXPR, op1, op2);
+  return true;
+}
+
+bool
+operator_bitwise_and::pointers_handled_p (range_op_dispatch_type type,
+ unsigned dispatch) const
+{
+  switch (type)
+{
+case DISPATCH_FOLD_RANGE:
+  return dispatch == RO_PPP;
+default:
+  return true;
+}
+}
+
 // Initialize any pointer operators to the primary table
 
 void
-- 
2.44.0



[COMMITTED 16/23] Implement operator_bitwise_or for prange.

2024-05-04 Thread Aldy Hernandez
We seem to have a range-op entry for pointer bitwise OR that we've
inherited from the original VRP implementation, but it never gets
used.  If this is not valid gimple, we can safely remove this entry.

gcc/ChangeLog:

* range-op-mixed.h: Add overloaded declarations for pointer variants.
* range-op-ptr.cc (operator_bitwise_or::pointers_handled_p): New.
---
 gcc/range-op-mixed.h |  1 +
 gcc/range-op-ptr.cc  | 11 +++
 2 files changed, 12 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 6158fc51f8e..c45aed93567 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -762,6 +762,7 @@ public:
   // Check compatibility of all operands.
   bool operand_check_p (tree t1, tree t2, tree t3) const final override
 { return range_compatible_p (t1, t2) && range_compatible_p (t1, t3); }
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final 
override;
 protected:
   void wi_fold (irange &r, tree type, const wide_int &lh_lb,
const wide_int &lh_ub, const wide_int &rh_lb,
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index 8d5049b1daf..2f2f4bb2b5d 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -1219,6 +1219,17 @@ operator_bitwise_and::pointers_handled_p 
(range_op_dispatch_type type,
 }
 }
 
+bool
+operator_bitwise_or::pointers_handled_p (range_op_dispatch_type,
+unsigned) const
+{
+  // NOTE: It looks like we never generate bitwise OR with pointers.
+  // If this is indeed the case, we can move operator_bitwise_or from
+  // range-op-mixed.h to range-op.h.
+  gcc_unreachable ();
+  return false;
+}
+
 // Initialize any pointer operators to the primary table
 
 void
-- 
2.44.0



[COMMITTED 05/23] Add hashing support for prange.

2024-05-04 Thread Aldy Hernandez
gcc/ChangeLog:

* value-range.cc (add_vrange): Add prange support.
---
 gcc/value-range.cc | 16 
 1 file changed, 16 insertions(+)

diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 84113ccfbd0..62170a438bf 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -346,6 +346,22 @@ add_vrange (const vrange &v, inchash::hash &hstate,
   hstate.add_wide_int (bm.mask ());
   return;
 }
+  if (is_a  (v))
+{
+  const prange &r = as_a  (v);
+  if (r.varying_p ())
+   hstate.add_int (VR_VARYING);
+  else
+   {
+ hstate.add_int (VR_RANGE);
+ hstate.add_wide_int (r.lower_bound ());
+ hstate.add_wide_int (r.upper_bound ());
+ irange_bitmask bm = r.get_bitmask ();
+ hstate.add_wide_int (bm.value ());
+ hstate.add_wide_int (bm.mask ());
+   }
+  return;
+}
   if (is_a  (v))
 {
   const frange &r = as_a  (v);
-- 
2.44.0



[COMMITTED 01/23] Minimal prange class showing inlining degradation to VRP.

2024-05-04 Thread Aldy Hernandez
There is a 2% slowdown to VRP unrelated to the work at hand.  This patch
is a skeleton implementation of prange that exhibits this degradation.  It
is meant as a place in the commit history we can return to in order to revisit
the issue.

The relevant discussion is here:

https://gcc.gnu.org/pipermail/gcc/2024-May/243898.html

gcc/ChangeLog:

* value-range.h (class prange): New.

---
 gcc/value-range.h | 59 +++
 1 file changed, 59 insertions(+)

diff --git a/gcc/value-range.h b/gcc/value-range.h
index 934eec9e386..f52d5165707 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -378,6 +378,39 @@ private:
   wide_int m_ranges[N*2];
 };
 
+class prange : public vrange
+{
+public:
+  static bool supports_p (const_tree) { return false; }
+  virtual bool supports_type_p (const_tree) const final override { return 
false; }
+  virtual void accept (const vrange_visitor &) const final override {}
+  virtual void set_undefined () final override {}
+  virtual void set_varying (tree) final override {}
+  virtual void set_nonzero (tree) final override {}
+  virtual void set_zero (tree) final override;
+  virtual void set_nonnegative (tree) final override {}
+  virtual bool contains_p (tree) const final override { return false; }
+  virtual bool fits_p (const vrange &) const final override { return false; }
+  virtual bool singleton_p (tree * = NULL) const final override { return 
false; }
+  virtual bool zero_p () const final override { return false; }
+  virtual bool nonzero_p () const final override { return false; }
+  virtual void set (tree, tree, value_range_kind = VR_RANGE) final override {}
+  virtual tree type () const final override { return NULL; }
+  virtual bool union_ (const vrange &) final override { return false; }
+  virtual bool intersect (const vrange &) final override { return false; }
+  virtual tree lbound () const final override { return NULL; }
+  virtual tree ubound () const final override { return NULL; }
+
+  wide_int lower_bound () const;
+  wide_int upper_bound () const;
+  irange_bitmask get_bitmask () const final override;
+  void update_bitmask (const irange_bitmask &) final override {}
+private:
+  wide_int m_min;
+  wide_int m_max;
+  irange_bitmask m_bitmask;
+};
+
 // Unsupported temporaries may be created by ranger before it's known
 // they're unsupported, or by vr_values::get_value_range.
 
@@ -1187,6 +1220,32 @@ irange_val_max (const_tree type)
   return wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type));
 }
 
+inline void
+prange::set_zero (tree type)
+{
+  wide_int zero = wi::zero (TYPE_PRECISION (type));
+  m_min = m_max = zero;
+  m_bitmask = irange_bitmask (zero, zero);
+}
+
+inline wide_int
+prange::lower_bound () const
+{
+  return m_min;
+}
+
+inline wide_int
+prange::upper_bound () const
+{
+  return m_max;
+}
+
+inline irange_bitmask
+prange::get_bitmask () const
+{
+  return m_bitmask;
+}
+
 inline
 frange::frange ()
   : vrange (VR_FRANGE)
-- 
2.44.0



[COMMITTED 07/23] Implement range-op dispatch for prange.

2024-05-04 Thread Aldy Hernandez
This patch adds the range-op dispatch code for prange, and adds some
temporary sanity checks (for flag_checking only) to make sure we handle
all the pointer/integer variants.

In order to make sure I got all the combinations right, I started with
a clean slate, trapping on all pointer operands.  Then I added support
for each one piecemeal.  To verify the work, I added a
pointers_handled_p() helper that is implemented for each range-op
entry and returns TRUE iff the operator can handle a given combination
of pointers.  If this helper returns false, we will trap, because it
indicates an operator that was not implemented.  This is temporary
checking code, and I will rip it out once the the dust has
settled in a few days.

gcc/ChangeLog:

* range-op-mixed.h: Add using declarator for all classes.
* range-op-ptr.cc (range_operator::pointers_handled_p): New.
(range_operator::fold_range): New.
(range_operator::op1_op2_relation_effect): New.
(range_operator::op1_range): New.
(range_operator::op2_range): New.
(range_operator::op1_op2_relation): New.
(range_operator::lhs_op1_relation): New.
(range_operator::update_bitmask): New.
(class pointer_plus_operator): New.
(class operator_pointer_diff): New.
(class hybrid_min_operator): New.
(class hybrid_max_operator): New.
* range-op.cc: Add RO_PPP, RO_PPI, RO_IPP, RO_IPI, RO_PIP, RO_PII.
(range_op_handler::discriminator_fail): New.
(has_pointer_operand_p): New.
(range_op_handler::fold_range): Add pointer support.
(range_op_handler::op1_range): Same.
(range_op_handler::op2_range): Same.
(range_op_handler::lhs_op1_relation): Same.
(range_op_handler::lhs_op2_relation): Same.
(range_op_handler::op1_op2_relation): Same.
(class operator_div): Add using.
(class operator_lshift): Add using.
(class operator_rshift):Add using.
(class operator_trunc_mod):Add using.
(class operator_absu):Add using.
* range-op.h (enum range_op_dispatch_type): New.
Add extern definitions for RO_*.
---
 gcc/range-op-mixed.h |  19 
 gcc/range-op-ptr.cc  | 220 +++
 gcc/range-op.cc  | 124 
 gcc/range-op.h   | 111 ++
 4 files changed, 474 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 3ee7c9d6e0d..8163a4b53ca 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -111,6 +111,7 @@ public:
   using range_operator::op1_range;
   using range_operator::op2_range;
   using range_operator::op1_op2_relation;
+  using range_operator::update_bitmask;
   bool fold_range (irange &r, tree type,
   const irange &op1, const irange &op2,
   relation_trio = TRIO_VARYING) const final override;
@@ -150,6 +151,7 @@ public:
   using range_operator::op1_range;
   using range_operator::op2_range;
   using range_operator::op1_op2_relation;
+  using range_operator::update_bitmask;
   bool fold_range (irange &r, tree type,
   const irange &op1, const irange &op2,
   relation_trio = TRIO_VARYING) const final override;
@@ -189,6 +191,7 @@ public:
   using range_operator::op1_range;
   using range_operator::op2_range;
   using range_operator::op1_op2_relation;
+  using range_operator::update_bitmask;
   bool fold_range (irange &r, tree type,
   const irange &op1, const irange &op2,
   relation_trio = TRIO_VARYING) const final override;
@@ -225,6 +228,7 @@ public:
   using range_operator::op1_range;
   using range_operator::op2_range;
   using range_operator::op1_op2_relation;
+  using range_operator::update_bitmask;
   bool fold_range (irange &r, tree type,
   const irange &op1, const irange &op2,
   relation_trio = TRIO_VARYING) const final override;
@@ -264,6 +268,7 @@ public:
   using range_operator::op1_range;
   using range_operator::op2_range;
   using range_operator::op1_op2_relation;
+  using range_operator::update_bitmask;
   bool fold_range (irange &r, tree type,
   const irange &op1, const irange &op2,
   relation_trio = TRIO_VARYING) const final override;
@@ -302,6 +307,7 @@ public:
   using range_operator::op1_range;
   using range_operator::op2_range;
   using range_operator::op1_op2_relation;
+  using range_operator::update_bitmask;
   bool fold_range (irange &r, tree type,
   const irange &op1, const irange &op2,
   relation_trio = TRIO_VARYING) const final override;
@@ -376,6 +382,7 @@ public:
   using range_operator::fold_range;
   using range_operator::op1_range;
   using range_operator::lhs_op1_relation;
+  using range_operator::update_bitmask;
   bool fold_range (irange &r, tree type,
   const irange &op1, const irange &op2,
   relatio

[COMMITTED 02/23] Implement basic prange class.

2024-05-04 Thread Aldy Hernandez
This provides a bare prange class with bounds and bitmasks.  It will
be a drop-in replacement for pointer ranges, so we can pull their
support from irange.  The range-op code will be contributed as a
follow-up.

The code is disabled by default, as irange::supports_p still accepts
pointers:

inline bool
irange::supports_p (const_tree type)
{
  return INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type);
}

Once the prange operators are implemented in range-ops, pointer
support will be removed from irange to activate pranges.

gcc/ChangeLog:

* value-range-pretty-print.cc (vrange_printer::visit): New.
* value-range-pretty-print.h: Declare prange visit() method.
* value-range.cc (vrange::operator=): Add prange support.
(vrange::operator==): Same.
(prange::accept): New.
(prange::set_nonnegative): New.
(prange::set): New.
(prange::contains_p): New.
(prange::singleton_p): New.
(prange::lbound): New.
(prange::ubound): New.
(prange::union_): New.
(prange::intersect): New.
(prange::operator=): New.
(prange::operator==): New.
(prange::invert): New.
(prange::verify_range): New.
(prange::update_bitmask): New.
(range_tests_misc): Use prange.
* value-range.h (enum value_range_discriminator): Add VR_PRANGE.
(class prange): New.
(Value_Range::init): Add prange support.
(Value_Range::operator=): Same.
(Value_Range::supports_type_p): Same.
(prange::prange):  New.
(prange::supports_p): New.
(prange::supports_type_p): New.
(prange::set_undefined): New.
(prange::set_varying): New.
(prange::set_nonzero): New.
(prange::set_zero): New.
(prange::contains_p): New.
(prange::zero_p): New.
(prange::nonzero_p): New.
(prange::type): New.
(prange::lower_bound): New.
(prange::upper_bound): New.
(prange::varying_compatible_p): New.
(prange::get_bitmask): New.
(prange::fits_p): New.
---
 gcc/value-range-pretty-print.cc |  25 +++
 gcc/value-range-pretty-print.h  |   1 +
 gcc/value-range.cc  | 303 +++-
 gcc/value-range.h   | 199 ++---
 4 files changed, 500 insertions(+), 28 deletions(-)

diff --git a/gcc/value-range-pretty-print.cc b/gcc/value-range-pretty-print.cc
index b6d23dce6d2..b11d6494774 100644
--- a/gcc/value-range-pretty-print.cc
+++ b/gcc/value-range-pretty-print.cc
@@ -112,6 +112,31 @@ vrange_printer::visit (const irange &r) const
   print_irange_bitmasks (pp, r.m_bitmask);
 }
 
+void
+vrange_printer::visit (const prange &r) const
+{
+  pp_string (pp, "[prange] ");
+  if (r.undefined_p ())
+{
+  pp_string (pp, "UNDEFINED");
+  return;
+}
+  dump_generic_node (pp, r.type (), 0, TDF_NONE | TDF_NOUID, false);
+  pp_character (pp, ' ');
+  if (r.varying_p ())
+{
+  pp_string (pp, "VARYING");
+  return;
+}
+
+  pp_character (pp, '[');
+  print_int_bound (pp, r.lower_bound (), r.type ());
+  pp_string (pp, ", ");
+  print_int_bound (pp, r.upper_bound (), r.type ());
+  pp_character (pp, ']');
+  print_irange_bitmasks (pp, r.m_bitmask);
+}
+
 void
 vrange_printer::print_real_value (tree type, const REAL_VALUE_TYPE &r) const
 {
diff --git a/gcc/value-range-pretty-print.h b/gcc/value-range-pretty-print.h
index 44cd6e81298..5522aad0673 100644
--- a/gcc/value-range-pretty-print.h
+++ b/gcc/value-range-pretty-print.h
@@ -27,6 +27,7 @@ public:
   vrange_printer (pretty_printer *pp_) : pp (pp_) { }
   void visit (const unsupported_range &) const override;
   void visit (const irange &) const override;
+  void visit (const prange &) const override;
   void visit (const frange &) const override;
 private:
   void print_frange_nan (const frange &) const;
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 7250115261f..84113ccfbd0 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -251,6 +251,8 @@ vrange::operator= (const vrange &src)
 {
   if (is_a  (src))
 as_a  (*this) = as_a  (src);
+  else if (is_a  (src))
+as_a  (*this) = as_a  (src);
   else if (is_a  (src))
 as_a  (*this) = as_a  (src);
   else
@@ -268,6 +270,8 @@ vrange::operator== (const vrange &src) const
 {
   if (is_a  (src))
 return as_a  (*this) == as_a  (src);
+  if (is_a  (src))
+return as_a  (*this) == as_a  (src);
   if (is_a  (src))
 return as_a  (*this) == as_a  (src);
   gcc_unreachable ();
@@ -397,6 +401,294 @@ irange::set_nonnegative (tree type)
wi::to_wide (TYPE_MAX_VALUE (type)));
 }
 
+// Prange implementation.
+
+void
+prange::accept (const vrange_visitor &v) const
+{
+  v.visit (*this);
+}
+
+void
+prange::set_nonnegative (tree type)
+{
+  set (type,
+   wi::zero (TYPE_PRECISION (type)),
+   wi::max_value (TYPE_PRECISION (type), UNSIGNED));
+}
+
+void
+prange::set (tree min, tree max, value_range_kind kind)

[COMMITTED 04/23] Add storage support for prange.

2024-05-04 Thread Aldy Hernandez
gcc/ChangeLog:

* value-range-storage.cc (vrange_allocator::clone_varying): Add
prange support.
(vrange_allocator::clone_undefined): Same.
(vrange_storage::alloc): Same.
(vrange_storage::set_vrange): Same.
(vrange_storage::get_vrange): Same.
(vrange_storage::fits_p): Same.
(vrange_storage::equal_p): Same.
(prange_storage::alloc): New.
(prange_storage::prange_storage): New.
(prange_storage::set_prange): New.
(prange_storage::get_prange): New.
(prange_storage::equal_p): New.
(prange_storage::fits_p): New.
* value-range-storage.h (class prange_storage): Add prange support.
---
 gcc/value-range-storage.cc | 117 +
 gcc/value-range-storage.h  |  33 +++
 2 files changed, 150 insertions(+)

diff --git a/gcc/value-range-storage.cc b/gcc/value-range-storage.cc
index 09a29776a0e..bbae0da4772 100644
--- a/gcc/value-range-storage.cc
+++ b/gcc/value-range-storage.cc
@@ -118,6 +118,8 @@ vrange_allocator::clone_varying (tree type)
 {
   if (irange::supports_p (type))
 return irange_storage::alloc (*m_alloc, int_range <1> (type));
+  if (prange::supports_p (type))
+return prange_storage::alloc (*m_alloc, prange (type));
   if (frange::supports_p (type))
 return frange_storage::alloc (*m_alloc, frange (type));
   return NULL;
@@ -128,6 +130,8 @@ vrange_allocator::clone_undefined (tree type)
 {
   if (irange::supports_p (type))
 return irange_storage::alloc (*m_alloc, int_range<1> ());
+  if (prange::supports_p (type))
+return prange_storage::alloc (*m_alloc, prange ());
   if (frange::supports_p (type))
 return frange_storage::alloc  (*m_alloc, frange ());
   return NULL;
@@ -141,6 +145,8 @@ vrange_storage::alloc (vrange_internal_alloc &allocator, 
const vrange &r)
 {
   if (is_a  (r))
 return irange_storage::alloc (allocator, as_a  (r));
+  if (is_a  (r))
+return prange_storage::alloc (allocator, as_a  (r));
   if (is_a  (r))
 return frange_storage::alloc (allocator, as_a  (r));
   return NULL;
@@ -157,6 +163,12 @@ vrange_storage::set_vrange (const vrange &r)
   gcc_checking_assert (s->fits_p (as_a  (r)));
   s->set_irange (as_a  (r));
 }
+  else if (is_a  (r))
+{
+  prange_storage *s = static_cast  (this);
+  gcc_checking_assert (s->fits_p (as_a  (r)));
+  s->set_prange (as_a  (r));
+}
   else if (is_a  (r))
 {
   frange_storage *s = static_cast  (this);
@@ -190,6 +202,11 @@ vrange_storage::get_vrange (vrange &r, tree type) const
   const irange_storage *s = static_cast  (this);
   s->get_irange (as_a  (r), type);
 }
+  else if (is_a  (r))
+{
+  const prange_storage *s = static_cast  (this);
+  s->get_prange (as_a  (r), type);
+}
   else if (is_a  (r))
 {
   const frange_storage *s = static_cast  (this);
@@ -209,6 +226,11 @@ vrange_storage::fits_p (const vrange &r) const
   const irange_storage *s = static_cast  (this);
   return s->fits_p (as_a  (r));
 }
+  if (is_a  (r))
+{
+  const prange_storage *s = static_cast  (this);
+  return s->fits_p (as_a  (r));
+}
   if (is_a  (r))
 {
   const frange_storage *s = static_cast  (this);
@@ -230,6 +252,11 @@ vrange_storage::equal_p (const vrange &r) const
   const irange_storage *s = static_cast  (this);
   return s->equal_p (as_a  (r));
 }
+  if (is_a  (r))
+{
+  const prange_storage *s = static_cast  (this);
+  return s->equal_p (as_a  (r));
+}
   if (is_a  (r))
 {
   const frange_storage *s = static_cast  (this);
@@ -559,6 +586,96 @@ frange_storage::fits_p (const frange &) const
   return true;
 }
 
+//
+// prange_storage implementation
+//
+
+prange_storage *
+prange_storage::alloc (vrange_internal_alloc &allocator, const prange &r)
+{
+  // Assume all pointers are the same size.
+  unsigned prec = TYPE_PRECISION (TREE_TYPE (null_pointer_node));
+  gcc_checking_assert (r.undefined_p () || TYPE_PRECISION (r.type ()) == prec);
+
+  typedef trailing_wide_ints twi;
+  size_t size = sizeof (prange_storage) + twi::extra_size (prec);
+  prange_storage *p = static_cast  (allocator.alloc (size));
+  new (p) prange_storage (r);
+  return p;
+}
+
+// Initialize the storage with R.
+
+prange_storage::prange_storage (const prange &r)
+{
+  // It is the caller's responsibility to allocate enough space such
+  // that the precision fits.
+  unsigned prec = TYPE_PRECISION (TREE_TYPE (null_pointer_node));
+  m_trailing_ints.set_precision (prec);
+
+  set_prange (r);
+}
+
+void
+prange_storage::set_prange (const prange &r)
+{
+  if (r.undefined_p ())
+m_kind = VR_UNDEFINED;
+  else if (r.varying_p ())
+m_kind = VR_VARYING;
+  else
+{
+  m_kind = VR_RANGE;
+  set_low (r.lower_bound ()

[PATCH 00/23] prange: pointer ranges

2024-05-04 Thread Aldy Hernandez
This patchset implements prange, a range class for pointers.

This is meant to be a drop-in replacement for pointer ranges, so we
can pull them out of irange, simplifying both irange and prange in the
process.  Initially we have two integer endpoints and the usual
value/mask bitmasks as this is how irange currently implements them,
but the end goal is to provide points-to info to replace the hacky
pointer equivalency we do in class pointer_equiv_analyzer.

I have split up the patchset into tiny pieces to make it easier to
track any problems.  I have also disabled it by default, choosing to
wait a few days until the dust has settled.  In a few days I will
throw the switch enabling pranges, which will make it invalid for
irange's to hold pointers.  Once pranges are enabled, I will do some
minor cleanups like removing pointer support from range-ops, etc.

The performance of prange is a wash for VRP and a 7% improvement for
IPA-cp.  This is taking into account the unrelated 2% hit we take due to
inlining as discussed here:

https://gcc.gnu.org/pipermail/gcc/2024-May/243898.html

Also, as part of this work, we improved VRP by 6% (on top of the above
numbers):

https://gcc.gnu.org/pipermail/gcc-patches/2024-May/650320.html

So things are looking relatively good.

The memory usage will also decrease, both by the 14% reduction in
Value_Range, and by prange's being smaller than say int_range_max or
int_range<3>.

Tested and benchmarked on x86-64 Linux.

Aldy Hernandez (23):
  Minimal prange class showing inlining degradation to VRP.
  Implement basic prange class.
  Add streaming support for prange.
  Add storage support for prange.
  Add hashing support for prange.
  Add prange implementation for get_legacy_range.
  Implement range-op dispatch for prange.
  Implement operator_identity for prange.
  Implement operator_cst for prange.
  Implement operator_cast for prange.
  Implement operator_min and operator_max for prange.
  Implement operator_addr_expr for prange.
  Implement pointer_plus_operator for prange.
  Implement operator_pointer_diff for prange.
  Implement operator_bitwise_and for prange.
  Implement operator_bitwise_or for prange.
  Implement operator_not_equal for prange.
  Implement operator_equal for prange.
  Implement operator_lt for prange.
  Implement operator_le for prange.
  Implement operator_gt for prange.
  Implement operator_ge for prange
  Add prange entries in gimple-range-op.cc.

 gcc/data-streamer-in.cc |   12 +
 gcc/data-streamer-out.cc|   10 +
 gcc/gimple-range-op.cc  |   36 +
 gcc/range-op-mixed.h|  156 
 gcc/range-op-ptr.cc | 1545 +++
 gcc/range-op.cc |  124 +++
 gcc/range-op.h  |  111 +++
 gcc/value-range-pretty-print.cc |   25 +
 gcc/value-range-pretty-print.h  |1 +
 gcc/value-range-storage.cc  |  117 +++
 gcc/value-range-storage.h   |   33 +
 gcc/value-range.cc  |  354 ++-
 gcc/value-range.h   |  214 -
 13 files changed, 2730 insertions(+), 8 deletions(-)

-- 
2.44.0



[COMMITTED 03/23] Add streaming support for prange.

2024-05-04 Thread Aldy Hernandez
gcc/ChangeLog:

* data-streamer-in.cc (streamer_read_value_range): Add prange support.
* data-streamer-out.cc (streamer_write_vrange): Same.
---
 gcc/data-streamer-in.cc  | 12 
 gcc/data-streamer-out.cc | 10 ++
 2 files changed, 22 insertions(+)

diff --git a/gcc/data-streamer-in.cc b/gcc/data-streamer-in.cc
index 3a0d3c6ad0f..12cb10e42c0 100644
--- a/gcc/data-streamer-in.cc
+++ b/gcc/data-streamer-in.cc
@@ -268,6 +268,18 @@ streamer_read_value_range (class lto_input_block *ib, 
data_in *data_in,
}
   return;
 }
+  if (is_a  (vr))
+{
+  prange &r = as_a  (vr);
+  wide_int lb = streamer_read_wide_int (ib);
+  wide_int ub = streamer_read_wide_int (ib);
+  r.set (type, lb, ub);
+  wide_int value = streamer_read_wide_int (ib);
+  wide_int mask = streamer_read_wide_int (ib);
+  irange_bitmask bm (value, mask);
+  r.update_bitmask (bm);
+  return;
+}
   gcc_unreachable ();
 }
 
diff --git a/gcc/data-streamer-out.cc b/gcc/data-streamer-out.cc
index 07cc6bd2018..c237e30f704 100644
--- a/gcc/data-streamer-out.cc
+++ b/gcc/data-streamer-out.cc
@@ -450,6 +450,16 @@ streamer_write_vrange (struct output_block *ob, const 
vrange &v)
}
   return;
 }
+  if (is_a  (v))
+{
+  const prange &r = as_a  (v);
+  streamer_write_wide_int (ob, r.lower_bound ());
+  streamer_write_wide_int (ob, r.upper_bound ());
+  irange_bitmask bm = r.get_bitmask ();
+  streamer_write_wide_int (ob, bm.value ());
+  streamer_write_wide_int (ob, bm.mask ());
+  return;
+}
   gcc_unreachable ();
 }
 
-- 
2.44.0