[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);