There's some longer latent issue with PTAs handling of offsetted MEM_REFs in get_constraint_for_component_ref when there are subfields involved. The following solves this by handling offsetted MEM_REFs manually.
Bootstrap & regtest running on x86_64-unknown-linux-gnu. Richard. 2019-07-31 Richard Biener <rguent...@suse.de> PR tree-optimization/91280 * tree-ssa-structalias.c (get_constraint_for_component_ref): Decompose MEM_REF manually for offset handling. * g++.dg/torture/pr91280.C: New testcase. Index: gcc/tree-ssa-structalias.c =================================================================== --- gcc/tree-ssa-structalias.c (revision 273930) +++ gcc/tree-ssa-structalias.c (working copy) @@ -3289,9 +3289,29 @@ get_constraint_for_component_ref (tree t return; } - /* Pretend to take the address of the base, we'll take care of - adding the required subset of sub-fields below. */ - get_constraint_for_1 (t, results, true, lhs_p); + /* Avoid creating pointer-offset constraints, so handle MEM_REF + offsets directly. Pretend to take the address of the base, + we'll take care of adding the required subset of sub-fields below. */ + if (TREE_CODE (t) == MEM_REF + && !integer_zerop (TREE_OPERAND (t, 0))) + { + poly_offset_int off = mem_ref_offset (t); + off <<= LOG2_BITS_PER_UNIT; + off += bitpos; + poly_int64 off_hwi; + if (off.to_shwi (&off_hwi)) + bitpos = off_hwi; + else + { + bitpos = 0; + bitmaxsize = -1; + } + get_constraint_for_1 (TREE_OPERAND (t, 0), results, false, lhs_p); + do_deref (results); + } + else + get_constraint_for_1 (t, results, true, lhs_p); + /* Strip off nothing_id. */ if (results->length () == 2) { Index: gcc/testsuite/g++.dg/torture/pr91280.C =================================================================== --- gcc/testsuite/g++.dg/torture/pr91280.C (nonexistent) +++ gcc/testsuite/g++.dg/torture/pr91280.C (working copy) @@ -0,0 +1,223 @@ +// { dg-do compile } + +enum { Aligned, RowMajor }; +enum { ReadOnlyAccessors }; +template <typename> struct K { + enum { value }; +}; +template <typename> struct traits; +template <typename T> struct traits<const T> : traits<T> {}; +struct A { + enum { has_write_access, value }; +}; +template <typename, int n> class array { +public: + int operator[](unsigned long p1) { return values[p1]; } + int values[n]; +}; +template <typename> struct I; +template <typename, int, template <class> class = I> class M; +template <typename, int, int, typename> class J; +template <typename, int> class N; +template <typename, typename> class D; +template <typename, typename, typename, typename> class TensorContractionOp; +template <long, typename> class TensorChippingOp; +class C; +template <typename DenseIndex, int NumDims> +struct K<array<DenseIndex, NumDims>> { + static const long value = NumDims; +}; +template <typename Scalar_, int NumIndices_, int Options_, typename IndexType_> +struct traits<J<Scalar_, NumIndices_, Options_, IndexType_>> { + typedef IndexType_ Index; +}; +template <typename PlainObjectType, int Options_, + template <class> class MakePointer_> +struct traits<M<PlainObjectType, Options_, MakePointer_>> + : traits<PlainObjectType> {}; +template <typename T> struct B { typedef T type; }; +template <typename Derived> class N<Derived, ReadOnlyAccessors> { +public: + typedef typename traits<Derived>::Index Index; + D<int, Derived> m_fn1(); + template <typename OtherDerived, typename Dimensions> + TensorContractionOp<Dimensions, Derived, const OtherDerived, int> + m_fn2(OtherDerived, Dimensions); + template <Index> TensorChippingOp<1, Derived> m_fn3(Index); +}; +template <typename Derived, int = A::value> +class N : public N<Derived, ReadOnlyAccessors> { +public: + template <typename DeviceType> C m_fn4(DeviceType); +}; +template <typename, typename> struct TensorEvaluator; +template <typename UnaryOp, typename ArgType, typename Device> +struct TensorEvaluator<const D<UnaryOp, ArgType>, Device> { + TensorEvaluator(D<UnaryOp, ArgType>, Device); +}; +template <typename, typename> class D { +public: + typedef typename B<D>::type Nested; +}; +template <typename Indices_, typename LeftArgType_, typename RightArgType_, + typename OutputKernelType_, typename Device_> +struct traits< + TensorEvaluator<const TensorContractionOp<Indices_, LeftArgType_, + RightArgType_, OutputKernelType_>, + Device_>> { + typedef Indices_ Indices; + typedef LeftArgType_ LeftArgType; + typedef RightArgType_ RightArgType; + typedef OutputKernelType_ OutputKernelType; + typedef Device_ Device; +}; +template <typename, typename LhsXprType, typename RhsXprType, typename> +class TensorContractionOp { +public: + typedef typename B<TensorContractionOp>::type Nested; + typename LhsXprType::Nested m_fn5(); + typename RhsXprType::Nested m_fn6(); +}; +template <typename Derived> struct TensorContractionEvaluatorBase { + typedef typename traits<Derived>::LeftArgType LeftArgType; + typedef typename traits<Derived>::RightArgType RightArgType; + typedef typename traits<Derived>::Device Device; + TensorContractionEvaluatorBase( + TensorContractionOp<typename traits<Derived>::Indices, LeftArgType, + RightArgType, + typename traits<Derived>::OutputKernelType> + p1, + Device p2) + : m_leftImpl(p1.m_fn6(), p2), m_rightImpl(p1.m_fn5(), p2) { + long nocontract_idx; + for (int i;; i++) { + bool contracting; + if (contracting) { + if (nocontract_idx < K<int>::value) + m_j_size = m_j_strides[nocontract_idx]; + nocontract_idx++; + } + } + } + array<long, 1> m_j_strides; + long m_j_size; + TensorEvaluator<RightArgType, Device> m_leftImpl; + TensorEvaluator<LeftArgType, Device> m_rightImpl; +}; +template <typename Indices, typename LeftArgType, typename RightArgType, + typename OutputKernelType, typename Device> +struct TensorEvaluator< + const TensorContractionOp<Indices, LeftArgType, RightArgType, + OutputKernelType>, + Device> + : TensorContractionEvaluatorBase<TensorEvaluator< + const TensorContractionOp<Indices, LeftArgType, RightArgType, + OutputKernelType>, + Device>> { + typedef TensorEvaluator Self; + typedef TensorContractionEvaluatorBase<Self> Base; + TensorEvaluator( + TensorContractionOp<Indices, LeftArgType, RightArgType, OutputKernelType> + p1, + Device p2) + : Base(p1, p2) {} +}; +template <long DimId, typename XprType> +struct traits<TensorChippingOp<DimId, XprType>> : traits<XprType> {}; +template <long, typename XprType> +class TensorChippingOp : public N<TensorChippingOp<1, XprType>> { +public: + typedef typename B<TensorChippingOp>::type Nested; +}; +template <long DimId, typename ArgType, typename Device> +struct TensorEvaluator<const TensorChippingOp<DimId, ArgType>, Device> { + static const int NumInputDims = K<typename ArgType::Dimensions>::value; + array<long, NumInputDims> m_dimensions; +}; +template <long DimId, typename ArgType, typename Device> +struct TensorEvaluator<TensorChippingOp<DimId, ArgType>, Device> + : TensorEvaluator<const TensorChippingOp<1, ArgType>, Device> { + TensorEvaluator(TensorChippingOp<DimId, ArgType>, Device); +}; +template <typename, typename RhsXprType> class TensorAssignOp { +public: + TensorAssignOp(TensorChippingOp<0, const M<J<int, 3, 1, int>, 1>>, + RhsXprType); + TensorChippingOp<0, const M<J<int, 3, 1, int>, 1>> m_fn7(); + typename RhsXprType::Nested m_fn8(); +}; +template <typename LeftArgType, typename RightArgType, typename Device> +struct TensorEvaluator<const TensorAssignOp<LeftArgType, RightArgType>, + Device> { + TensorEvaluator(TensorAssignOp<LeftArgType, RightArgType> p1, Device p2) + : m_leftImpl(p1.m_fn7(), p2), m_rightImpl(p1.m_fn8(), p2) {} + TensorEvaluator<LeftArgType, Device> m_leftImpl; + TensorEvaluator<RightArgType, Device> m_rightImpl; +}; +template <typename Expression> class F { +public: + static void m_fn9(Expression p1) { + int device; + TensorEvaluator<Expression, int>(p1, device); + } +}; +class C { +public: + void + operator=(TensorContractionOp<array<int, 1>, + TensorChippingOp<1, M<J<float, 3, 1, int>, 0>>, + const D<int, M<J<float, 3, 1, int>, 0>>, int> + p1) { + TensorAssignOp< + TensorChippingOp<0, const M<J<int, 3, 1, int>, 1>>, + const TensorContractionOp< + array<int, 1>, TensorChippingOp<1, M<J<float, 3, 1, int>, 0>>, + const D<int, M<J<float, 3, 1, int>, 0>>, int>> + assign(m_expression, p1); + F<const TensorAssignOp< + TensorChippingOp<0, const M<J<int, 3, 1, int>, 1>>, + const TensorContractionOp< + array<int, 1>, TensorChippingOp<1, M<J<float, 3, 1, int>, 0>>, + const D<int, M<J<float, 3, 1, int>, 0>>, int>>>::m_fn9(assign); + } + TensorChippingOp<0, const M<J<int, 3, 1, int>, 1>> m_expression; +}; +template <typename, int NumIndices_, int, typename> class J { +public: + typedef array<long, NumIndices_> Dimensions; +}; +template <typename PlainObjectType, int Options_, template <class> class> +class M : public N<M<PlainObjectType, Options_>> { +public: + typedef typename PlainObjectType::Dimensions Dimensions; +}; +template <int NDIMS> struct TTypes { + typedef M<J<float, NDIMS, RowMajor, int>, Aligned> ConstTensor; +}; +class L { +public: + template <typename, long NDIMS> typename TTypes<NDIMS>::ConstTensor m_fn10(); +}; +class H { +public: + H(int *); +}; +class G { +public: + G(H *(int *)); +}; +int Run_d; +class O : H { +public: + int BatchMatMul_context; + O() : H(&BatchMatMul_context) { + L out, in_y, in_x; + auto Tx = in_x.m_fn10<float, 3>(), Ty = in_y.m_fn10<float, 3>(), + Tz = out.m_fn10<float, 3>(), z = Tz; + array<int, 1> contract_pairs; + auto x = Tx.m_fn3<0>(0); + auto y = Ty.m_fn1(); + z.m_fn4(Run_d) = x.m_fn2(y, contract_pairs); + } +}; +G registrar__body__0__object([](int *) -> H * { O(); return 0; });