[gcc r17-2955] phiopt: Add some TARGET_MEM_REF support to factoring of loads [PR100173]

Andrea Pinski via Gcc-cvs <[email protected]> Tue, 4 Aug 2026 17:06:34 +0000 (GMT)
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:1a751916c6d506ba49b318d38675184191647bf8

commit r17-2955-g1a751916c6d506ba49b318d38675184191647bf8
Author: Andrea Pinski <[email protected]>
Date:   Wed Jul 22 19:52:44 2026 -0700

    phiopt: Add some TARGET_MEM_REF support to factoring of loads [PR100173]
    
    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.
    
            PR tree-optimization/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 <[email protected]>

Diff:
---
 gcc/fold-const.h                                   | 13 ++++++++
 .../tree-ssa/factor_op_phi-load-target_mem-1.c     | 24 ++++++++++++++
 gcc/tree-ssa-phiopt.cc                             | 38 ++++++++++++++++++++--
 3 files changed, 72 insertions(+), 3 deletions(-)

diff --git a/gcc/fold-const.h b/gcc/fold-const.h
index 25e1cbf911f5..ab03bf0aa35e 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 000000000000..2e2a9ad78348
--- /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 2a0fe0d643bc..2195be6c503c 100644
--- a/gcc/tree-ssa-phiopt.cc
+++ b/gcc/tree-ssa-phiopt.cc
@@ -4168,12 +4168,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.  */
@@ -4297,7 +4324,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);