[PUSHED,v4] phiopt: Add some TARGET_MEM_REF support to factoring of loads [PR100173]
Checks
Commit Message
The testcase in factor_op_phi-load-target_mem-1.c at -O2 gets:
```
if (_4 > _6)
goto <bb 4>; [50.00%]
else
goto <bb 5>; [50.00%]
<bb 4> [local count: 531502204]:
t_21 = MEM[(int *)c_19(D) + ivtmp.23_12 * 1];
goto <bb 6>; [100.00%]
<bb 5> [local count: 531502204]:
t_20 = MEM[(int *)c_19(D) + 8B + ivtmp.23_12 * 1];
<bb 6> [local count: 1063004408]:
# t_13 = PHI <t_21(4), t_20(5)>
# t1_14 = PHI <_4(4), _6(5)>
```
But that MEM is a TARGET_MEM_REF which is not supported by
factor_out_conditional_load yet. This adds simple TARGET_MEM_REF
support by requiring the index/step and index2 to be all the same.
It even supports a mismatched TARGET_MEM_REF with a MEM_REF but
only if the TARGET_MEM_REF had an null index/step and index2.
We now get a similar code generation for telecom/viterb00data_1 (EEMBC)
at -O2 as LLVM.
Changes since v1:
* v2: Fix small issue checking of equality and nullptr of TARGET_MEM_REF
operands.
* v3: Fix operand_equal check.
* v4: Add safe_operand_equal. Also use TMR_* instead of TREE_OPERAND.
Bootstrapped and tested on x86_64-linux-gnu.
Pushed as approved already.
PR tree-optmization/100173
gcc/ChangeLog:
* fold-const.h (safe_operand_equal_p): New function.
* tree-ssa-phiopt.cc (factor_out_conditional_load): Add simple
support for TARGET_MEM_REF.
gcc/testsuite/ChangeLog:
* gcc.dg/tree-ssa/factor_op_phi-load-target_mem-1.c: New test.
Signed-off-by: Andrea Pinski <andrew.pinski@oss.qualcomm.com>
---
gcc/fold-const.h | 13 +++++++
.../factor_op_phi-load-target_mem-1.c | 24 ++++++++++++
gcc/tree-ssa-phiopt.cc | 38 +++++++++++++++++--
3 files changed, 72 insertions(+), 3 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/factor_op_phi-load-target_mem-1.c
Comments
On Tue, Aug 4, 2026 at 8:52 AM Andrea Pinski
<andrew.pinski@oss.qualcomm.com> wrote:
>
> The testcase in factor_op_phi-load-target_mem-1.c at -O2 gets:
> ```
> if (_4 > _6)
> goto <bb 4>; [50.00%]
> else
> goto <bb 5>; [50.00%]
>
> <bb 4> [local count: 531502204]:
> t_21 = MEM[(int *)c_19(D) + ivtmp.23_12 * 1];
> goto <bb 6>; [100.00%]
>
> <bb 5> [local count: 531502204]:
> t_20 = MEM[(int *)c_19(D) + 8B + ivtmp.23_12 * 1];
>
> <bb 6> [local count: 1063004408]:
> # t_13 = PHI <t_21(4), t_20(5)>
> # t1_14 = PHI <_4(4), _6(5)>
> ```
>
> But that MEM is a TARGET_MEM_REF which is not supported by
> factor_out_conditional_load yet. This adds simple TARGET_MEM_REF
> support by requiring the index/step and index2 to be all the same.
> It even supports a mismatched TARGET_MEM_REF with a MEM_REF but
> only if the TARGET_MEM_REF had an null index/step and index2.
>
> We now get a similar code generation for telecom/viterb00data_1 (EEMBC)
> at -O2 as LLVM.
>
> Changes since v1:
> * v2: Fix small issue checking of equality and nullptr of TARGET_MEM_REF
> operands.
> * v3: Fix operand_equal check.
> * v4: Add safe_operand_equal. Also use TMR_* instead of TREE_OPERAND.
>
> Bootstrapped and tested on x86_64-linux-gnu.
> Pushed as approved already.
Note I have not pushed this yet as the current trunk bootstrap is
broken (unrelated to this patch).
>
> PR tree-optmization/100173
>
> gcc/ChangeLog:
>
> * fold-const.h (safe_operand_equal_p): New function.
> * tree-ssa-phiopt.cc (factor_out_conditional_load): Add simple
> support for TARGET_MEM_REF.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.dg/tree-ssa/factor_op_phi-load-target_mem-1.c: New test.
>
> Signed-off-by: Andrea Pinski <andrew.pinski@oss.qualcomm.com>
> ---
> gcc/fold-const.h | 13 +++++++
> .../factor_op_phi-load-target_mem-1.c | 24 ++++++++++++
> gcc/tree-ssa-phiopt.cc | 38 +++++++++++++++++--
> 3 files changed, 72 insertions(+), 3 deletions(-)
> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/factor_op_phi-load-target_mem-1.c
>
> diff --git a/gcc/fold-const.h b/gcc/fold-const.h
> index 25e1cbf911f..ab03bf0aa35 100644
> --- a/gcc/fold-const.h
> +++ b/gcc/fold-const.h
> @@ -301,4 +301,17 @@ private:
> unsigned int flags);
> };
>
> +/* Like operand_equal_p but supports nullptrs which compare
> + equals to each other but not to others. */
> +
> +inline bool
> +safe_operand_equal_p (const_tree op0, const_tree op1, unsigned int flags = 0)
> +{
> + if (op0 == op1)
> + return true;
> + if (!op0 || !op1)
> + return false;
> + return operand_equal_p (op0, op1, flags);
> +}
> +
> #endif // GCC_FOLD_CONST_H
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/factor_op_phi-load-target_mem-1.c b/gcc/testsuite/gcc.dg/tree-ssa/factor_op_phi-load-target_mem-1.c
> new file mode 100644
> index 00000000000..2e2a9ad7834
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/factor_op_phi-load-target_mem-1.c
> @@ -0,0 +1,24 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-phiopt4-details" } */
> +/* PR tree-optmization/100173 */
> +/* TARGET_MEM_REF was not being supported for load factoring. */
> +
> +void f(int a, int *b, int *d, int *c)
> +{
> + for(int i = 0; i < 1024; i++)
> + {
> + int t;
> + int t1;
> + if (b[i] > d[i]) {
> + t1 = b[i];
> + t = c[i];
> + }
> + else {
> + t1 = d[i];
> + t = c[i+2];
> + }
> + b[i] = t+t1;
> + }
> +}
> +
> +/* { dg-final { scan-tree-dump "changed to factor out load from COND_EXPR" "phiopt4" } } */
> diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc
> index d63a47cc615..e29289c59bb 100644
> --- a/gcc/tree-ssa-phiopt.cc
> +++ b/gcc/tree-ssa-phiopt.cc
> @@ -4174,12 +4174,39 @@ factor_out_conditional_load (edge e0, edge e1, basic_block merge, gphi *phi,
>
> tree ref0 = gimple_assign_rhs1 (load0);
> tree ref1 = gimple_assign_rhs1 (load1);
> + tree index = nullptr;
> + tree step = nullptr;
> + tree index2 = nullptr;
>
> /* Both must be *P loads of a compatible value type. The
> TBAA alias-ptr type carried by MEM_REF operand 1 need not match; it is
> merged the way get_alias_type_for_stmts does when the load is built. */
> - if (TREE_CODE (ref0) != MEM_REF || TREE_CODE (ref1) != MEM_REF
> - || !types_compatible_p (TREE_TYPE (ref0), TREE_TYPE (ref1)))
> + if (TREE_CODE (ref0) != MEM_REF)
> + {
> + if (TREE_CODE (ref0) != TARGET_MEM_REF)
> + return false;
> + index = TMR_INDEX (ref0);
> + step = TMR_STEP (ref0);
> + index2 = TMR_INDEX2 (ref0);
> + }
> + if (TREE_CODE (ref1) == MEM_REF)
> + {
> + if (index || step || index2)
> + return false;
> + }
> + else
> + {
> + if (TREE_CODE (ref1) != TARGET_MEM_REF)
> + return false;
> + if (!safe_operand_equal_p (index, TMR_INDEX (ref1)))
> + return false;
> + if (!safe_operand_equal_p (step, TMR_STEP (ref1)))
> + return false;
> + if (!safe_operand_equal_p (index2, TMR_INDEX2 (ref1)))
> + return false;
> + }
> +
> + if (!types_compatible_p (TREE_TYPE (ref0), TREE_TYPE (ref1)))
> return false;
>
> /* The alignment of the two accesses need to be the same. */
> @@ -4303,7 +4330,12 @@ factor_out_conditional_load (edge e0, edge e1, basic_block merge, gphi *phi,
>
> /* Build the combined load RES = *PTR, reusing the PHI result so any range
> info on it is preserved (as factor_out_conditional_operation does). */
> - tree nref = build2 (MEM_REF, TREE_TYPE (ref0), newptr, newindex);
> + tree nref;
> + if (index || step || index2)
> + nref = build5 (TARGET_MEM_REF, TREE_TYPE (ref0), newptr,
> + newindex, index, step, index2);
> + else
> + nref = build2 (MEM_REF, TREE_TYPE (ref0), newptr, newindex);
> MR_DEPENDENCE_CLIQUE (nref) = clique;
> MR_DEPENDENCE_BASE (nref) = base;
> tree res = gimple_phi_result (phi);
> --
> 2.43.0
>
@@ -301,4 +301,17 @@ private:
unsigned int flags);
};
+/* Like operand_equal_p but supports nullptrs which compare
+ equals to each other but not to others. */
+
+inline bool
+safe_operand_equal_p (const_tree op0, const_tree op1, unsigned int flags = 0)
+{
+ if (op0 == op1)
+ return true;
+ if (!op0 || !op1)
+ return false;
+ return operand_equal_p (op0, op1, flags);
+}
+
#endif // GCC_FOLD_CONST_H
new file mode 100644
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-phiopt4-details" } */
+/* PR tree-optmization/100173 */
+/* TARGET_MEM_REF was not being supported for load factoring. */
+
+void f(int a, int *b, int *d, int *c)
+{
+ for(int i = 0; i < 1024; i++)
+ {
+ int t;
+ int t1;
+ if (b[i] > d[i]) {
+ t1 = b[i];
+ t = c[i];
+ }
+ else {
+ t1 = d[i];
+ t = c[i+2];
+ }
+ b[i] = t+t1;
+ }
+}
+
+/* { dg-final { scan-tree-dump "changed to factor out load from COND_EXPR" "phiopt4" } } */
@@ -4174,12 +4174,39 @@ factor_out_conditional_load (edge e0, edge e1, basic_block merge, gphi *phi,
tree ref0 = gimple_assign_rhs1 (load0);
tree ref1 = gimple_assign_rhs1 (load1);
+ tree index = nullptr;
+ tree step = nullptr;
+ tree index2 = nullptr;
/* Both must be *P loads of a compatible value type. The
TBAA alias-ptr type carried by MEM_REF operand 1 need not match; it is
merged the way get_alias_type_for_stmts does when the load is built. */
- if (TREE_CODE (ref0) != MEM_REF || TREE_CODE (ref1) != MEM_REF
- || !types_compatible_p (TREE_TYPE (ref0), TREE_TYPE (ref1)))
+ if (TREE_CODE (ref0) != MEM_REF)
+ {
+ if (TREE_CODE (ref0) != TARGET_MEM_REF)
+ return false;
+ index = TMR_INDEX (ref0);
+ step = TMR_STEP (ref0);
+ index2 = TMR_INDEX2 (ref0);
+ }
+ if (TREE_CODE (ref1) == MEM_REF)
+ {
+ if (index || step || index2)
+ return false;
+ }
+ else
+ {
+ if (TREE_CODE (ref1) != TARGET_MEM_REF)
+ return false;
+ if (!safe_operand_equal_p (index, TMR_INDEX (ref1)))
+ return false;
+ if (!safe_operand_equal_p (step, TMR_STEP (ref1)))
+ return false;
+ if (!safe_operand_equal_p (index2, TMR_INDEX2 (ref1)))
+ return false;
+ }
+
+ if (!types_compatible_p (TREE_TYPE (ref0), TREE_TYPE (ref1)))
return false;
/* The alignment of the two accesses need to be the same. */
@@ -4303,7 +4330,12 @@ factor_out_conditional_load (edge e0, edge e1, basic_block merge, gphi *phi,
/* Build the combined load RES = *PTR, reusing the PHI result so any range
info on it is preserved (as factor_out_conditional_operation does). */
- tree nref = build2 (MEM_REF, TREE_TYPE (ref0), newptr, newindex);
+ tree nref;
+ if (index || step || index2)
+ nref = build5 (TARGET_MEM_REF, TREE_TYPE (ref0), newptr,
+ newindex, index, step, index2);
+ else
+ nref = build2 (MEM_REF, TREE_TYPE (ref0), newptr, newindex);
MR_DEPENDENCE_CLIQUE (nref) = clique;
MR_DEPENDENCE_BASE (nref) = base;
tree res = gimple_phi_result (phi);