neon_vld1<mode> pattern does not accept eliminable registers and due to this, testcase in PR ICE. The problem is in arm_expand_neon_args, in the NEON_ARG_MEMORY case, where it call force_reg. Since an eliminable reg is already a reg, it just returns that value, and we get the wrong result. It needs to call copy_to_mode_reg instead, like arm_expand_binop_builtin does. Attached patch does this. Regression tested on arm-none-linux-gnu with no new regression. Is this OK for trunk?
Thanks, Kugan gcc/ChangeLog: 2016-01-08 Kugan Vivekanandarajah <kug...@linaro.org> Jim Wilson <jim.wil...@linaro.org> PR target/69194 * config/arm/arm-builtins.c (arm_expand_neon_args): Call copy_to_mode_reg instead of force_reg. gcc/testsuite/ChangeLog: 2016-01-08 Kugan Vivekanandarajah <kug...@linaro.org> PR target/69194 * gcc.target/arm/pr69194.C: New test.
diff --git a/gcc/config/arm/arm-builtins.c b/gcc/config/arm/arm-builtins.c index 11cd17d..40dd620 100644 --- a/gcc/config/arm/arm-builtins.c +++ b/gcc/config/arm/arm-builtins.c @@ -2146,7 +2146,7 @@ constant_arg: if (!(*insn_data[icode].operand[opno].predicate) (op[argc], mode[argc])) op[argc] = (replace_equiv_address - (op[argc], force_reg (Pmode, XEXP (op[argc], 0)))); + (op[argc], copy_to_mode_reg (Pmode, XEXP (op[argc], 0)))); break; case NEON_ARG_STOP: diff --git a/gcc/testsuite/gcc.target/arm/pr69194.C b/gcc/testsuite/gcc.target/arm/pr69194.C index e69de29..b78fb5b 100644 --- a/gcc/testsuite/gcc.target/arm/pr69194.C +++ b/gcc/testsuite/gcc.target/arm/pr69194.C @@ -0,0 +1,504 @@ + +/* { dg-do-compile } */ +/* { dg-require-effective-target arm_neon } */ +/* { dg-options "-O2 -mfpu=neon -S -Wno-deprecated-declarations" } */ + +namespace std { + typedef int size_t; + typedef int ptrdiff_t; + template <typename _Tp> _Tp *__addressof(_Tp &__r) { return &__r; } + template <typename _Tp, size_t _Nm> struct __array_traits { + typedef _Tp _Type[_Nm]; + static _Tp &_S_ref(_Type __t, size_t __n) { return __t[__n]; } + }; + template <typename _Tp, size_t _Nm> struct array { + typedef _Tp *pointer; + typedef __array_traits<_Tp, _Nm> _AT_Type; + typename _AT_Type::_Type _M_elems; + pointer data() { return __addressof(_AT_Type::_S_ref(_M_elems, 0)); } + }; + template <typename> class complex; + template <> struct complex<float> { + typedef float _ComplexT; + complex(_ComplexT); + _ComplexT _M_value; + }; +} + +typedef __simd128_float32_t float32x4_t; +namespace Eigen { + const int Dynamic = -1; + void vld1q_f32(const float *__a) { __builtin_neon_vld1v4sf(__a); } + const int EvalBeforeNestingBit = 2; + const int NestByRefBit = 6; + enum { Unaligned }; + enum { + DefaultTraversal, + SliceVectorizedTraversal, + InvalidTraversal, + NoUnrolling, + ColMajor + }; + enum { ReadOnlyAccessors, WriteAccessors }; + struct Dense; + namespace internal { + template <typename> struct traits; + template <typename T> struct traits<const T> : traits<T> {}; + template <typename> struct accessors_level { + enum { has_write_access, value }; + }; + } + template <typename> struct EigenBase; + template <typename> class DenseBase; + template <typename Derived, int = internal::accessors_level<Derived>::value> + class DenseCoeffsBase; + template <typename, int _Rows, int _Cols, int = ColMajor, int = _Rows, + int = _Cols> + class Matrix; + template <typename> class MatrixBase; + template <typename, typename> class CwiseUnaryOp; + template <typename, typename, int> class CoeffBasedProduct; + template <typename, int = ReadOnlyAccessors> class MapBase; + template <int, int> class Stride; + template <typename, int = Unaligned, typename = Stride<0, 0>> class Map; + template <typename> class ArrayWrapper; + namespace internal { + template <typename, typename> struct product_type; + } + template <typename Lhs, typename Rhs, + int = internal::product_type<Lhs, Rhs>::value> + struct ProductReturnType; + namespace internal { + template <bool, typename Then, typename> struct conditional { + typedef Then type; + }; + template <typename Then, typename Else> struct conditional<false, Then, Else> { + typedef Else type; + }; + template <typename, typename> struct is_same { + enum { value = 1 }; + }; + template <typename T> struct remove_all { typedef T type; }; + template <typename T> struct remove_all<T &> { + typedef typename remove_all<T>::type type; + }; + template <typename T> struct add_const_on_value_type { typedef T type; }; + template <typename T, typename> struct scalar_product_traits { + typedef T ReturnType; + }; + } + typedef std::ptrdiff_t DenseIndex; + namespace internal { + class no_assignment_operator {}; + template <typename I1, typename I2> struct promote_index_type { + typedef typename conditional<sizeof(I2), I2, I1>::type type; + }; + template <typename T, int> class variable_if_dynamic { + public: + variable_if_dynamic(T) {} + }; + template <typename> struct packet_traits; + template <typename> struct unpacket_traits; + template <typename, int, int, int, int, int> class compute_matrix_flags { + public: + enum { ret }; + }; + template <typename T> struct plain_matrix_type { + typedef Matrix<typename traits<T>::Scalar, traits<T>::MaxRowsAtCompileTime, + traits<T>::MaxColsAtCompileTime> type; + }; + template <typename T> struct eval { + typedef typename plain_matrix_type<T>::type type; + }; + template <typename T> struct ref_selector { + typedef typename conditional<NestByRefBit, T const &, T>::type type; + }; + template <typename T, int = 1, typename PlainObject = typename eval<T>::type> + struct nested { + typedef typename conditional<traits<T>::Flags, PlainObject, + typename ref_selector<T>::type>::type type; + }; + template <typename Derived> struct dense_xpr_base { + typedef MatrixBase<Derived> type; + }; + template <typename, typename, typename, typename BaseType> + struct special_scalar_op_base : BaseType {}; + template <typename> struct is_lvalue { + enum { value }; + }; + } + template <typename T> struct GenericNumTraits { + enum { ReadCost, AddCost }; + typedef T Real; + }; + template <typename T> struct NumTraits : GenericNumTraits<T> {}; + namespace internal { + template <typename Packet> + Packet ploadu(const typename unpacket_traits<Packet>::type *); + template <typename Packet, int> + Packet ploadt(typename unpacket_traits<Packet>::type *from) { + ploadu<Packet>(from); + } + typedef float32x4_t Packet4f; + template <> struct packet_traits<float> { typedef Packet4f type; }; + template <> struct unpacket_traits<Packet4f> { typedef float type; }; + template <> Packet4f ploadu(const float *from) { vld1q_f32(from); } + struct Packet2cf {}; + template <> struct packet_traits<std::complex<float>> { + typedef Packet2cf type; + enum { AlignedOnScalar, size }; + }; + template <> struct unpacket_traits<Packet2cf> { + typedef std::complex<float> type; + }; + template <> Packet2cf ploadu(const std::complex<float> *from) { + ploadu<Packet4f>((float *)from); + } + template <typename> struct scalar_pow_op; + } + template <typename Derived> + class DenseCoeffsBase<Derived, ReadOnlyAccessors> : public EigenBase<Derived> { + }; + template <typename Derived> + class DenseCoeffsBase<Derived, WriteAccessors> + : public DenseCoeffsBase<Derived, ReadOnlyAccessors> { + public: + typedef DenseCoeffsBase<Derived, ReadOnlyAccessors> Base; + typedef typename internal::traits<Derived>::Index Index; + Base::derived; + template <typename OtherDerived, int StoreMode, int LoadMode> + void copyPacket(Index row, Index col, const DenseBase<OtherDerived> &other) { + derived().template writePacket<StoreMode>( + row, col, other.derived().template packet<LoadMode>(row, col)); + } + template <typename OtherDerived, int StoreMode, int LoadMode> + void copyPacketByOuterInner(Index, Index inner, + const DenseBase<OtherDerived> &other) { + Index row; + Index col; + copyPacket<OtherDerived, StoreMode, LoadMode>(row, col, other); + } + }; + template <typename Derived> + class DenseBase + : public internal::special_scalar_op_base< + Derived, typename internal::traits<Derived>::Scalar, + typename NumTraits<typename internal::traits<Derived>::Scalar>::Real, + DenseCoeffsBase<Derived>> { + public: + typedef typename internal::traits<Derived>::Index Index; + typedef typename internal::traits<Derived>::Scalar Scalar; + typedef typename internal::packet_traits<Scalar>::type PacketScalar; + typedef typename NumTraits<Scalar>::Real RealScalar; + typedef internal::special_scalar_op_base<Derived, Scalar, RealScalar, + DenseCoeffsBase<Derived>> Base; + Base::derived; + template <typename OtherDerived> + Derived &lazyAssign(const DenseBase<OtherDerived> &); + }; + template <typename Derived> class MatrixBase : public DenseBase<Derived> { + public: + typename internal::traits<Derived>; + typedef DenseBase<Derived> Base; + Base::derived; + template <typename OtherDerived> + const typename ProductReturnType<Derived, OtherDerived>::Type + operator*(const MatrixBase<OtherDerived> &) const; + ArrayWrapper<Derived> array() const { return derived(); } + }; + template <typename Derived> struct EigenBase { + Derived derived(); + const Derived &derived() const { return *static_cast<const Derived *>(this); } + }; + namespace internal { + template <typename, typename> struct assign_traits { + enum { DstIsAligned, SrcIsAligned }; + enum { MayInnerVectorize = SrcIsAligned, MaySliceVectorize }; + enum { + Traversal = MayInnerVectorize ?: MaySliceVectorize ?: DefaultTraversal, + Unrolling = DefaultTraversal ?: NoUnrolling + }; + }; + template <typename Derived1, typename Derived2, int, + int = assign_traits<Derived1, Derived2>::Unrolling> + struct assign_impl; + template <typename Derived1, typename Derived2, int Version> + struct assign_impl<Derived1, Derived2, SliceVectorizedTraversal, Version> { + typedef typename Derived1::Index Index; + static void run(Derived1 dst, Derived2 src) { + typedef typename Derived1::Scalar Scalar; + typedef packet_traits<Scalar> PacketTraits; + enum { + packetSize = PacketTraits::size, + alignable = PacketTraits::AlignedOnScalar, + dstAlignment + }; + for (Index outer;;) + for (Index inner;;) + dst.template copyPacketByOuterInner<Derived2, dstAlignment, Unaligned>( + outer, inner, src); + } + }; + } + template <typename Derived> + template <typename OtherDerived> + Derived &DenseBase<Derived>::lazyAssign(const DenseBase<OtherDerived> &other) { + enum { SameType = internal::is_same<Scalar, Scalar>::value }; + internal::assign_impl < Derived, OtherDerived, + SameType ? internal::assign_traits<Derived, OtherDerived>::Traversal + : InvalidTraversal > ::run(derived(), other.derived()); + } + namespace internal { + template <typename, typename, bool = 0> struct assign_selector; + template <typename Derived, typename OtherDerived> + struct assign_selector<Derived, OtherDerived> { + static Derived run(Derived dst, OtherDerived other) { dst.lazyAssign(other); } + }; + } + template <typename Derived> + class PlainObjectBase : public internal::dense_xpr_base<Derived>::type { + public: + typedef typename internal::traits<Derived>::Index Index; + typedef typename internal::traits<Derived>::Scalar Scalar; + typedef typename internal::packet_traits<Scalar>::type PacketScalar; + Scalar coeff(Index, Index) const; + template <int> void writePacket(Index, Index, PacketScalar); + template <typename OtherDerived> + Derived _set_noalias(const DenseBase<OtherDerived> &other) { + internal::assign_selector<Derived, OtherDerived>::run(this->derived(), + other.derived()); + } + }; + namespace internal { + template <typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, + int _MaxCols> + struct traits<Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>> { + typedef _Scalar Scalar; + typedef Dense StorageKind; + typedef DenseIndex Index; + enum { + RowsAtCompileTime, + ColsAtCompileTime, + MaxRowsAtCompileTime = _MaxRows, + MaxColsAtCompileTime, + Flags = compute_matrix_flags<_Scalar, _Rows, _Cols, _Options, _MaxRows, + _MaxCols>::ret, + CoeffReadCost = NumTraits<Scalar>::ReadCost + }; + }; + } + template <typename _Scalar, int _Rows, int, int, int, int _MaxCols> + class Matrix : public PlainObjectBase<Matrix<_Scalar, _Rows, _MaxCols>> { + public: + typedef PlainObjectBase<Matrix> Base; + enum { + RowsAtCompileTime = Eigen::internal::traits<Matrix>::RowsAtCompileTime, + ColsAtCompileTime = Eigen::internal::traits<Matrix>::ColsAtCompileTime, + MaxRowsAtCompileTime = + Eigen::internal::traits<Matrix>::MaxRowsAtCompileTime, + MaxColsAtCompileTime = + Eigen::internal::traits<Matrix>::MaxColsAtCompileTime, + Flags = Eigen::internal::traits<Matrix>::Flags, + CoeffReadCost = Eigen::internal::traits<Matrix>::CoeffReadCost + }; + template <typename OtherDerived> Matrix(MatrixBase<OtherDerived> &other) { + Base::_set_noalias(other); + } + template <typename OtherDerived> Matrix(const EigenBase<OtherDerived>); + }; + namespace internal { + template <typename UnaryOp, typename XprType> + struct traits<CwiseUnaryOp<UnaryOp, XprType>> : traits<XprType> {}; + } + template <typename, typename, typename> class CwiseUnaryOpImpl; + template <typename UnaryOp, typename XprType> + class CwiseUnaryOp + : internal::no_assignment_operator, + public CwiseUnaryOpImpl<UnaryOp, XprType, + typename internal::traits<XprType>::StorageKind> { + }; + template <typename UnaryOp, typename XprType> + class CwiseUnaryOpImpl<UnaryOp, XprType, Dense> + : public internal::dense_xpr_base<CwiseUnaryOp<UnaryOp, XprType>>::type {}; + template <typename Derived> + class MapBase<Derived> : public internal::dense_xpr_base<Derived>::type { + public: + typename internal::dense_xpr_base<Derived>; + enum { + RowsAtCompileTime = internal::traits<Derived>::RowsAtCompileTime, + ColsAtCompileTime = internal::traits<Derived>::ColsAtCompileTime + }; + typedef typename internal::traits<Derived>::Index Index; + typedef typename internal::traits<Derived>::Scalar Scalar; + typedef typename internal::packet_traits<Scalar>::type PacketScalar; + typedef typename internal::conditional<internal::is_lvalue<Derived>::value, + Scalar, Scalar *>::type PointerType; + template <int LoadMode> PacketScalar packet(Index, Index) const { + internal::ploadt<PacketScalar, LoadMode>(m_data); + } + MapBase(PointerType dataPtr) + : m_data(dataPtr), m_rows(RowsAtCompileTime), m_cols(ColsAtCompileTime) {} + PointerType m_data; + internal::variable_if_dynamic<Index, RowsAtCompileTime> m_rows; + internal::variable_if_dynamic<Index, ColsAtCompileTime> m_cols; + }; + namespace internal { + template <typename PlainObjectType, int MapOptions, typename StrideType> + struct traits<Map<PlainObjectType, MapOptions, StrideType>> + : traits<PlainObjectType> {}; + } + template <typename PlainObjectType, int, typename> + class Map : public MapBase<Map<PlainObjectType>> { + public: + typedef MapBase<Map> Base; + enum { + RowsAtCompileTime = Eigen::internal::traits<Map>::RowsAtCompileTime, + ColsAtCompileTime = Eigen::internal::traits<Map>::ColsAtCompileTime, + MaxRowsAtCompileTime = Eigen::internal::traits<Map>::MaxRowsAtCompileTime, + MaxColsAtCompileTime = Eigen::internal::traits<Map>::MaxColsAtCompileTime, + Flags = Eigen::internal::traits<Map>::Flags, + CoeffReadCost = Eigen::internal::traits<Map>::CoeffReadCost + }; + typedef typename Base::PointerType PointerArgType; + Map(PointerArgType dataPtr) : Base(dataPtr) {} + }; + enum { Large, Small }; + namespace internal { + template <int, int, int> struct product_type_selector; + template <int, int MaxSize> struct product_size_category { + enum { is_large = MaxSize == Dynamic, value = is_large ? Large : 1 ?: Small }; + }; + template <typename Lhs, typename Rhs> struct product_type { + typedef typename remove_all<Lhs>::type _Lhs; + typedef typename remove_all<Rhs>::type _Rhs; + enum { + MaxRows = _Lhs::MaxRowsAtCompileTime, + Rows = _Lhs::RowsAtCompileTime, + MaxCols = _Rhs::MaxColsAtCompileTime, + Cols = _Rhs::ColsAtCompileTime, + MaxDepth = _Lhs::MaxColsAtCompileTime <= _Rhs::MaxRowsAtCompileTime + ?: _Rhs::MaxRowsAtCompileTime, + Depth = _Lhs::ColsAtCompileTime <= _Rhs::RowsAtCompileTime + ?: _Rhs::RowsAtCompileTime + }; + enum { + rows_select = product_size_category<Rows, MaxRows>::value, + cols_select = product_size_category<Cols, MaxCols>::value, + depth_select = product_size_category<Depth, MaxDepth>::value + }; + typedef product_type_selector<rows_select, cols_select, depth_select> + selector; + enum { value = selector::ret }; + }; + template <> struct product_type_selector<Large, 1, Small> { + enum { ret }; + }; + } + template <typename Lhs, typename Rhs, int> struct ProductReturnType { + typedef typename internal::nested<Lhs, Rhs::ColsAtCompileTime>::type + LhsNested; + typedef typename internal::nested<Rhs, Lhs::RowsAtCompileTime>::type + RhsNested; + typedef CoeffBasedProduct<LhsNested, RhsNested, EvalBeforeNestingBit> Type; + }; + template <typename Derived> + template <typename OtherDerived> + const typename ProductReturnType<Derived, OtherDerived>::Type + MatrixBase<Derived>:: + operator*(const MatrixBase<OtherDerived> &other) const { + return typename ProductReturnType<Derived, OtherDerived>::Type( + derived(), other.derived()); + } + namespace internal { + template <int, int, typename, typename, typename, int> + struct product_packet_impl; + template <typename LhsNested, typename RhsNested, int NestingFlags> + struct traits<CoeffBasedProduct<LhsNested, RhsNested, NestingFlags>> { + typedef typename remove_all<LhsNested>::type _LhsNested; + typedef typename remove_all<RhsNested>::type _RhsNested; + typedef typename scalar_product_traits< + typename _LhsNested::Scalar, typename _RhsNested::Scalar>::ReturnType + Scalar; + typedef typename promote_index_type<typename traits<_LhsNested>::Index, + typename traits<_RhsNested>::Index>::type + Index; + enum { + LhsFlags = _LhsNested::Flags, + RhsFlags = _RhsNested::Flags, + RowsAtCompileTime = _LhsNested::RowsAtCompileTime, + ColsAtCompileTime = _RhsNested::ColsAtCompileTime, + InnerSize = _LhsNested::RowsAtCompileTime, + MaxRowsAtCompileTime = _LhsNested::MaxRowsAtCompileTime, + MaxColsAtCompileTime = is_same<Scalar, Scalar>::value, + CanVectorizeLhs = packet_traits<Scalar>::size, + Flags, + CoeffReadCost = NumTraits<Scalar>::AddCost + }; + }; + } + template <typename LhsNested, typename RhsNested, int NestingFlags> + class CoeffBasedProduct + : internal::no_assignment_operator, + public MatrixBase<CoeffBasedProduct<LhsNested, RhsNested, NestingFlags>> { + public: + typedef MatrixBase<CoeffBasedProduct> Base; + typedef typename Base::PacketScalar PacketScalar; + typedef typename Eigen::internal::nested<CoeffBasedProduct>::type Nested; + typedef typename Eigen::internal::traits<CoeffBasedProduct>::Index Index; + typedef typename internal::traits<CoeffBasedProduct>::_LhsNested _LhsNested; + typedef typename internal::traits<CoeffBasedProduct>::_RhsNested _RhsNested; + template <typename Lhs, typename Rhs> + CoeffBasedProduct(Lhs lhs, Rhs &rhs) + : m_lhs(lhs), m_rhs(rhs) {} + template <int LoadMode> PacketScalar packet(Index row, Index col) const { + PacketScalar res; + internal::product_packet_impl<ColMajor, Dynamic, _LhsNested, _RhsNested, + PacketScalar, LoadMode>::run(row, col, m_lhs, + m_rhs, res); + } + typename internal::add_const_on_value_type<LhsNested>::type m_lhs; + typename internal::add_const_on_value_type<RhsNested>::type m_rhs; + }; + namespace internal { + template <int UnrollingIndex, typename Lhs, typename Rhs, typename Packet, + int LoadMode> + struct product_packet_impl<ColMajor, UnrollingIndex, Lhs, Rhs, Packet, + LoadMode> { + typedef typename Lhs::Index Index; + static void run(Index row, Index col, Lhs lhs, Rhs rhs, Packet) { + lhs.coeff(row, 0), rhs.template packet<LoadMode>(0, col); + } + }; + } + template <typename Derived> class ArrayBase : public DenseBase<Derived> { + public: + typedef typename internal::traits<Derived>::Scalar Scalar; + CwiseUnaryOp<internal::scalar_pow_op<Scalar>, Derived> pow(Scalar); + }; + namespace internal { + template <typename ExpressionType> + struct traits<ArrayWrapper<ExpressionType>> + : traits<typename remove_all<typename ExpressionType::Nested>::type> {}; + } + template <typename ExpressionType> + class ArrayWrapper : public ArrayBase<ArrayWrapper<ExpressionType>> { + public: + typedef typename internal::nested<ExpressionType>::type NestedExpressionType; + ArrayWrapper(ExpressionType matrix) : m_expression(matrix) {} + NestedExpressionType m_expression; + }; +} + +struct crashes { + int x; + int y; +}; +using Scalar = std::complex<float>; +using Points = std::array<Scalar, 4>; +using Table = Eigen::Matrix<Scalar, Eigen::Dynamic, 4>; +using Vec = Eigen::Matrix<float, Eigen::Dynamic, 1>; +crashes do_crash(Table cal, Points p) { + using map_t = Eigen::Map<Eigen::Matrix<Scalar, 4, 1>>; + map_t points_mat(p.data()); + Vec top = (cal * points_mat).array().pow(2); +}