diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2023-07-26 19:11:12 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2023-07-26 19:11:12 +0000 |
commit | 2d22c9abbd20fdc3d3a469075bd151ca1bd02ee4 (patch) | |
tree | bc941261e4067c56d7da297e4f3e606bad5695c1 | |
parent | 7fa27ce4a07f19b07799a767fc29416f3b625afb (diff) |
-rw-r--r-- | clang/lib/Basic/Targets/LoongArch.cpp | 25 | ||||
-rw-r--r-- | clang/lib/Basic/Targets/LoongArch.h | 3 | ||||
-rw-r--r-- | clang/lib/Driver/ToolChains/Arch/LoongArch.cpp | 23 | ||||
-rw-r--r-- | clang/lib/Driver/ToolChains/Clang.cpp | 22 | ||||
-rw-r--r-- | libcxx/include/__mdspan/extents.h | 63 | ||||
-rw-r--r-- | libcxx/include/__mdspan/layout_left.h | 30 | ||||
-rw-r--r-- | libcxx/include/__mdspan/layout_right.h | 30 | ||||
-rw-r--r-- | libcxx/include/__mdspan/mdspan.h | 308 | ||||
-rw-r--r-- | libcxx/include/mdspan | 130 | ||||
-rw-r--r-- | libcxx/include/module.modulemap.in | 1 | ||||
-rw-r--r-- | libcxx/modules/std/mdspan.cppm | 2 | ||||
-rw-r--r-- | llvm/include/llvm/TargetParser/LoongArchTargetParser.h | 9 | ||||
-rw-r--r-- | llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h | 15 | ||||
-rw-r--r-- | llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp | 4 | ||||
-rw-r--r-- | llvm/lib/Target/LoongArch/LoongArch.td | 5 | ||||
-rw-r--r-- | llvm/lib/TargetParser/LoongArchTargetParser.cpp | 25 | ||||
-rw-r--r-- | llvm/lib/Transforms/IPO/FunctionSpecialization.cpp | 82 | ||||
-rw-r--r-- | openmp/runtime/src/ompt-event-specific.h | 13 |
18 files changed, 644 insertions, 146 deletions
diff --git a/clang/lib/Basic/Targets/LoongArch.cpp b/clang/lib/Basic/Targets/LoongArch.cpp index 6958479cd7c4..f08e5e732b03 100644 --- a/clang/lib/Basic/Targets/LoongArch.cpp +++ b/clang/lib/Basic/Targets/LoongArch.cpp @@ -15,7 +15,7 @@ #include "clang/Basic/MacroBuilder.h" #include "clang/Basic/TargetBuiltins.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/TargetParser/TargetParser.h" +#include "llvm/TargetParser/LoongArchTargetParser.h" using namespace clang; using namespace clang::targets; @@ -198,7 +198,19 @@ void LoongArchTargetInfo::getTargetDefines(const LangOptions &Opts, else Builder.defineMacro("__loongarch_frlen", "0"); - // TODO: define __loongarch_arch and __loongarch_tune. + // Define __loongarch_arch. + StringRef Arch = llvm::LoongArch::getArch(); + if (Arch.empty()) + Arch = llvm::LoongArch::getDefaultArch(GRLen == 64); + if (!Arch.empty()) + Builder.defineMacro("__loongarch_arch", Arch); + + // Define __loongarch_tune. + StringRef TuneCPU = llvm::LoongArch::getTuneCPU(); + if (TuneCPU.empty()) + TuneCPU = Arch; + if (!TuneCPU.empty()) + Builder.defineMacro("__loongarch_tune", TuneCPU); StringRef ABI = getABI(); if (ABI == "lp64d" || ABI == "lp64f" || ABI == "lp64s") @@ -270,3 +282,12 @@ bool LoongArchTargetInfo::handleTargetFeatures( } return true; } + +bool LoongArchTargetInfo::isValidTuneCPUName(StringRef Name) const { + return llvm::LoongArch::isValidTuneCPUName(Name); +} + +void LoongArchTargetInfo::fillValidTuneCPUList( + SmallVectorImpl<StringRef> &Values) const { + llvm::LoongArch::fillValidTuneCPUList(Values); +} diff --git a/clang/lib/Basic/Targets/LoongArch.h b/clang/lib/Basic/Targets/LoongArch.h index 52c4ce425368..60d545566b30 100644 --- a/clang/lib/Basic/Targets/LoongArch.h +++ b/clang/lib/Basic/Targets/LoongArch.h @@ -80,6 +80,9 @@ public: const std::vector<std::string> &FeaturesVec) const override; bool hasFeature(StringRef Feature) const override; + + bool isValidTuneCPUName(StringRef Name) const override; + void fillValidTuneCPUList(SmallVectorImpl<StringRef> &Values) const override; }; class LLVM_LIBRARY_VISIBILITY LoongArch32TargetInfo diff --git a/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp b/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp index 856ad58f3bd9..6cbb06b9a91f 100644 --- a/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp +++ b/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp @@ -12,6 +12,7 @@ #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" +#include "llvm/TargetParser/Host.h" #include "llvm/TargetParser/LoongArchTargetParser.h" using namespace clang::driver; @@ -128,21 +129,29 @@ void loongarch::getLoongArchTargetFeatures(const Driver &D, std::vector<StringRef> &Features) { StringRef ArchName; if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { - if (!llvm::LoongArch::isValidArchName(A->getValue())) { + ArchName = A->getValue(); + + // Handle -march=native. + if (ArchName == "native") { + ArchName = llvm::sys::getHostCPUName(); + if (ArchName == "generic") + ArchName = llvm::LoongArch::getDefaultArch(Triple.isLoongArch64()); + } + + if (!llvm::LoongArch::isValidArchName(ArchName)) { D.Diag(clang::diag::err_drv_invalid_arch_name) << A->getAsString(Args); return; } - ArchName = A->getValue(); } - // TODO: handle -march=native and -mtune=xx. - // Select a default arch name. - if (ArchName.empty() && Triple.isLoongArch64()) - ArchName = "loongarch64"; + if (ArchName.empty()) + ArchName = llvm::LoongArch::getDefaultArch(Triple.isLoongArch64()); - if (!ArchName.empty()) + if (!ArchName.empty()) { llvm::LoongArch::getArchFeatures(ArchName, Features); + llvm::LoongArch::setArch(ArchName); + } // Select floating-point features determined by -mdouble-float, // -msingle-float, -msoft-float and -mfpu. diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index adb550d9c5da..e3fa315ffcb1 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -56,6 +56,7 @@ #include "llvm/Support/YAMLParser.h" #include "llvm/TargetParser/ARMTargetParserCommon.h" #include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/LoongArchTargetParser.h" #include "llvm/TargetParser/RISCVTargetParser.h" #include <cctype> @@ -1853,10 +1854,25 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, void Clang::AddLoongArchTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { + const llvm::Triple &Triple = getToolChain().getTriple(); + CmdArgs.push_back("-target-abi"); - CmdArgs.push_back(loongarch::getLoongArchABI(getToolChain().getDriver(), Args, - getToolChain().getTriple()) - .data()); + CmdArgs.push_back( + loongarch::getLoongArchABI(getToolChain().getDriver(), Args, Triple) + .data()); + + // Handle -mtune. + if (const Arg *A = Args.getLastArg(options::OPT_mtune_EQ)) { + StringRef TuneCPU = A->getValue(); + if (TuneCPU == "native") { + TuneCPU = llvm::sys::getHostCPUName(); + if (TuneCPU == "generic") + TuneCPU = llvm::LoongArch::getDefaultArch(Triple.isLoongArch64()); + } + CmdArgs.push_back("-tune-cpu"); + CmdArgs.push_back(Args.MakeArgString(TuneCPU)); + llvm::LoongArch::setTuneCPU(TuneCPU); + } } void Clang::AddMIPSTargetArgs(const ArgList &Args, diff --git a/libcxx/include/__mdspan/extents.h b/libcxx/include/__mdspan/extents.h index 42355678d60c..a510220d4096 100644 --- a/libcxx/include/__mdspan/extents.h +++ b/libcxx/include/__mdspan/extents.h @@ -171,11 +171,14 @@ public: _TStatic __static_val = _StaticValues::__get(__i); if (__static_val == _DynTag) { __dyn_vals_[_DynamicIdxMap::__get(__i)] = __values[__i]; - } - // Precondition check - else - _LIBCPP_ASSERT_UNCATEGORIZED(__values[__i] == static_cast<_TDynamic>(__static_val), - "extents construction: mismatch of provided arguments with static extents."); + } else + // Not catching this could lead to out of bounds errors later + // e.g. using my_mdspan_t = mdspan<int, extents<int, 10>>; my_mdspan_t = m(new int[5], 5); + // Right-hand-side construction looks ok with allocation and size matching, + // but since (potentially elsewhere defined) my_mdspan_t has static size m now thinks its range is 10 not 5 + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __values[__i] == static_cast<_TDynamic>(__static_val), + "extents construction: mismatch of provided arguments with static extents."); } } @@ -187,11 +190,14 @@ public: _TStatic __static_val = _StaticValues::__get(__i); if (__static_val == _DynTag) { __dyn_vals_[_DynamicIdxMap::__get(__i)] = static_cast<_TDynamic>(__vals[__i]); - } - // Precondition check - else - _LIBCPP_ASSERT_UNCATEGORIZED(static_cast<_TDynamic>(__vals[__i]) == static_cast<_TDynamic>(__static_val), - "extents construction: mismatch of provided arguments with static extents."); + } else + // Not catching this could lead to out of bounds errors later + // e.g. using my_mdspan_t = mdspan<int, extents<int, 10>>; my_mdspan_t = m(new int[N], span<int,1>(&N)); + // Right-hand-side construction looks ok with allocation and size matching, + // but since (potentially elsewhere defined) my_mdspan_t has static size m now thinks its range is 10 not N + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + static_cast<_TDynamic>(__vals[__i]) == static_cast<_TDynamic>(__static_val), + "extents construction: mismatch of provided arguments with static extents."); } } @@ -310,28 +316,37 @@ public: (sizeof...(_OtherIndexTypes) == __rank_ || sizeof...(_OtherIndexTypes) == __rank_dynamic_)) _LIBCPP_HIDE_FROM_ABI constexpr explicit extents(_OtherIndexTypes... __dynvals) noexcept : __vals_(static_cast<index_type>(__dynvals)...) { - _LIBCPP_ASSERT_UNCATEGORIZED(__mdspan_detail::__are_representable_as<index_type>(__dynvals...), - "extents ctor: arguments must be representable as index_type and nonnegative"); + // Not catching this could lead to out of bounds errors later + // e.g. mdspan m(ptr, dextents<char, 1>(200u)); leads to an extent of -56 on m + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__are_representable_as<index_type>(__dynvals...), + "extents ctor: arguments must be representable as index_type and nonnegative"); } template <class _OtherIndexType, size_t _Size> - requires(is_convertible_v<_OtherIndexType, index_type> && is_nothrow_constructible_v<index_type, _OtherIndexType> && + requires(is_convertible_v<const _OtherIndexType&, index_type> && + is_nothrow_constructible_v<index_type, const _OtherIndexType&> && (_Size == __rank_ || _Size == __rank_dynamic_)) explicit(_Size != __rank_dynamic_) _LIBCPP_HIDE_FROM_ABI constexpr extents(const array<_OtherIndexType, _Size>& __exts) noexcept : __vals_(span(__exts)) { - _LIBCPP_ASSERT_UNCATEGORIZED(__mdspan_detail::__are_representable_as<index_type>(span(__exts)), - "extents ctor: arguments must be representable as index_type and nonnegative"); + // Not catching this could lead to out of bounds errors later + // e.g. mdspan m(ptr, dextents<char, 1>(array<unsigned,1>(200))); leads to an extent of -56 on m + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__are_representable_as<index_type>(span(__exts)), + "extents ctor: arguments must be representable as index_type and nonnegative"); } template <class _OtherIndexType, size_t _Size> - requires(is_convertible_v<_OtherIndexType, index_type> && is_nothrow_constructible_v<index_type, _OtherIndexType> && + requires(is_convertible_v<const _OtherIndexType&, index_type> && + is_nothrow_constructible_v<index_type, const _OtherIndexType&> && (_Size == __rank_ || _Size == __rank_dynamic_)) explicit(_Size != __rank_dynamic_) _LIBCPP_HIDE_FROM_ABI constexpr extents(const span<_OtherIndexType, _Size>& __exts) noexcept : __vals_(__exts) { - _LIBCPP_ASSERT_UNCATEGORIZED(__mdspan_detail::__are_representable_as<index_type>(__exts), - "extents ctor: arguments must be representable as index_type and nonnegative"); + // Not catching this could lead to out of bounds errors later + // e.g. array a{200u}; mdspan<int, dextents<char,1>> m(ptr, extents(span<unsigned,1>(a))); leads to an extent of -56 + // on m + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__are_representable_as<index_type>(__exts), + "extents ctor: arguments must be representable as index_type and nonnegative"); } private: @@ -380,10 +395,16 @@ public: for (size_t __r = 0; __r < rank(); __r++) { if constexpr (static_cast<make_unsigned_t<index_type>>(numeric_limits<index_type>::max()) < static_cast<make_unsigned_t<_OtherIndexType>>(numeric_limits<_OtherIndexType>::max())) { - _LIBCPP_ASSERT_UNCATEGORIZED(__mdspan_detail::__is_representable_as<index_type>(__other.extent(__r)), - "extents ctor: arguments must be representable as index_type and nonnegative"); + // Not catching this could lead to out of bounds errors later + // e.g. dextents<char,1>> e(dextents<unsigned,1>(200)) leads to an extent of -56 on e + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __mdspan_detail::__is_representable_as<index_type>(__other.extent(__r)), + "extents ctor: arguments must be representable as index_type and nonnegative"); } - _LIBCPP_ASSERT_UNCATEGORIZED( + // Not catching this could lead to out of bounds errors later + // e.g. mdspan<int, extents<int, 10>> m = mdspan<int, dextents<int, 1>>(new int[5], 5); + // Right-hand-side construction was ok, but m now thinks its range is 10 not 5 + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( (_Values::__static_value(__r) == dynamic_extent) || (static_cast<index_type>(__other.extent(__r)) == static_cast<index_type>(_Values::__static_value(__r))), "extents construction: mismatch of provided arguments with static extents."); diff --git a/libcxx/include/__mdspan/layout_left.h b/libcxx/include/__mdspan/layout_left.h index e81e0d10b595..f890c5ae0256 100644 --- a/libcxx/include/__mdspan/layout_left.h +++ b/libcxx/include/__mdspan/layout_left.h @@ -75,8 +75,11 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr mapping() noexcept = default; _LIBCPP_HIDE_FROM_ABI constexpr mapping(const mapping&) noexcept = default; _LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext) noexcept : __extents_(__ext) { - _LIBCPP_ASSERT(__required_span_size_is_representable(__ext), - "layout_left::mapping extents ctor: product of extents must be representable as index_type."); + // not catching this could lead to out-of-bounds access later when used inside mdspan + // mapping<dextents<char, 2>> map(dextents<char, 2>(40,40)); map(10, 3) == -126 + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __required_span_size_is_representable(__ext), + "layout_left::mapping extents ctor: product of extents must be representable as index_type."); } template <class _OtherExtents> @@ -84,7 +87,9 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) mapping(const mapping<_OtherExtents>& __other) noexcept : __extents_(__other.extents()) { - _LIBCPP_ASSERT( + // not catching this could lead to out-of-bounds access later when used inside mdspan + // mapping<dextents<char, 2>> map(mapping<dextents<int, 2>>(dextents<int, 2>(40,40))); map(10, 3) == -126 + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( __mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()), "layout_left::mapping converting ctor: other.required_span_size() must be representable as index_type."); } @@ -94,7 +99,13 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) mapping(const layout_right::mapping<_OtherExtents>& __other) noexcept : __extents_(__other.extents()) { - _LIBCPP_ASSERT( + // not catching this could lead to out-of-bounds access later when used inside mdspan + // Note: since this is constraint to rank 1, extents itself would catch the invalid conversion first + // and thus this assertion should never be triggered, but keeping it here for consistency + // layout_left::mapping<dextents<char, 1>> map( + // layout_right::mapping<dextents<unsigned, 1>>(dextents<unsigned, 1>(200))); map.extents().extent(0) == + // -56 + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( __mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()), "layout_left::mapping converting ctor: other.required_span_size() must be representable as index_type."); } @@ -122,6 +133,10 @@ public: requires((sizeof...(_Indices) == extents_type::rank()) && (is_convertible_v<_Indices, index_type> && ...) && (is_nothrow_constructible_v<index_type, _Indices> && ...)) _LIBCPP_HIDE_FROM_ABI constexpr index_type operator()(_Indices... __idx) const noexcept { + // Mappings are generally meant to be used for accessing allocations and are meant to guarantee to never + // return a value exceeding required_span_size(), which is used to know how large an allocation one needs + // Thus, this is a canonical point in multi-dimensional data structures to make invalid element access checks + // However, mdspan does check this on its own, so for now we avoid double checking in hardened mode _LIBCPP_ASSERT(__mdspan_detail::__is_multidimensional_index_in(__extents_, __idx...), "layout_left::mapping: out of bounds indexing"); array<index_type, extents_type::rank()> __idx_a{static_cast<index_type>(__idx)...}; @@ -144,7 +159,10 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr index_type stride(rank_type __r) const noexcept requires(extents_type::rank() > 0) { - _LIBCPP_ASSERT(__r < extents_type::rank(), "layout_left::mapping::stride(): invalid rank index"); + // While it would be caught by extents itself too, using a too large __r + // is functionally an out of bounds access on the stored information needed to compute strides + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __r < extents_type::rank(), "layout_left::mapping::stride(): invalid rank index"); index_type __s = 1; for (rank_type __i = extents_type::rank() - 1; __i > __r; __i--) __s *= __extents_.extent(__i); @@ -159,7 +177,7 @@ public: } private: - extents_type __extents_{}; // exposition only + _LIBCPP_NO_UNIQUE_ADDRESS extents_type __extents_{}; }; #endif // _LIBCPP_STD_VER >= 23 diff --git a/libcxx/include/__mdspan/layout_right.h b/libcxx/include/__mdspan/layout_right.h index a8a91b86c714..3d814554a1be 100644 --- a/libcxx/include/__mdspan/layout_right.h +++ b/libcxx/include/__mdspan/layout_right.h @@ -74,8 +74,11 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr mapping() noexcept = default; _LIBCPP_HIDE_FROM_ABI constexpr mapping(const mapping&) noexcept = default; _LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext) noexcept : __extents_(__ext) { - _LIBCPP_ASSERT(__required_span_size_is_representable(__ext), - "layout_right::mapping extents ctor: product of extents must be representable as index_type."); + // not catching this could lead to out-of-bounds access later when used inside mdspan + // mapping<dextents<char, 2>> map(dextents<char, 2>(40,40)); map(3, 10) == -126 + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __required_span_size_is_representable(__ext), + "layout_right::mapping extents ctor: product of extents must be representable as index_type."); } template <class _OtherExtents> @@ -83,7 +86,9 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) mapping(const mapping<_OtherExtents>& __other) noexcept : __extents_(__other.extents()) { - _LIBCPP_ASSERT( + // not catching this could lead to out-of-bounds access later when used inside mdspan + // mapping<dextents<char, 2>> map(mapping<dextents<int, 2>>(dextents<int, 2>(40,40))); map(3, 10) == -126 + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( __mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()), "layout_right::mapping converting ctor: other.required_span_size() must be representable as index_type."); } @@ -93,7 +98,13 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) mapping(const layout_left::mapping<_OtherExtents>& __other) noexcept : __extents_(__other.extents()) { - _LIBCPP_ASSERT( + // not catching this could lead to out-of-bounds access later when used inside mdspan + // Note: since this is constraint to rank 1, extents itself would catch the invalid conversion first + // and thus this assertion should never be triggered, but keeping it here for consistency + // layout_right::mapping<dextents<char, 1>> map( + // layout_left::mapping<dextents<unsigned, 1>>(dextents<unsigned, 1>(200))); map.extents().extent(0) == + // -56 + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( __mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()), "layout_right::mapping converting ctor: other.required_span_size() must be representable as index_type."); } @@ -121,6 +132,10 @@ public: requires((sizeof...(_Indices) == extents_type::rank()) && (is_convertible_v<_Indices, index_type> && ...) && (is_nothrow_constructible_v<index_type, _Indices> && ...)) _LIBCPP_HIDE_FROM_ABI constexpr index_type operator()(_Indices... __idx) const noexcept { + // Mappings are generally meant to be used for accessing allocations and are meant to guarantee to never + // return a value exceeding required_span_size(), which is used to know how large an allocation one needs + // Thus, this is a canonical point in multi-dimensional data structures to make invalid element access checks + // However, mdspan does check this on its own, so for now we avoid double checking in hardened mode _LIBCPP_ASSERT(__mdspan_detail::__is_multidimensional_index_in(__extents_, __idx...), "layout_right::mapping: out of bounds indexing"); return [&]<size_t... _Pos>(index_sequence<_Pos...>) { @@ -141,7 +156,10 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr index_type stride(rank_type __r) const noexcept requires(extents_type::rank() > 0) { - _LIBCPP_ASSERT(__r < extents_type::rank(), "layout_right::mapping::stride(): invalid rank index"); + // While it would be caught by extents itself too, using a too large __r + // is functionally an out of bounds access on the stored information needed to compute strides + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __r < extents_type::rank(), "layout_right::mapping::stride(): invalid rank index"); index_type __s = 1; for (rank_type __i = extents_type::rank() - 1; __i > __r; __i--) __s *= __extents_.extent(__i); @@ -156,7 +174,7 @@ public: } private: - extents_type __extents_{}; // exposition only + _LIBCPP_NO_UNIQUE_ADDRESS extents_type __extents_{}; }; #endif // _LIBCPP_STD_VER >= 23 diff --git a/libcxx/include/__mdspan/mdspan.h b/libcxx/include/__mdspan/mdspan.h new file mode 100644 index 000000000000..58f3b9cf1b18 --- /dev/null +++ b/libcxx/include/__mdspan/mdspan.h @@ -0,0 +1,308 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Kokkos v. 4.0 +// Copyright (2022) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// the U.S. Government retains certain rights in this software. +// +//===---------------------------------------------------------------------===// + +#ifndef _LIBCPP___MDSPAN_MDSPAN_H +#define _LIBCPP___MDSPAN_MDSPAN_H + +#include <__assert> +#include <__config> +#include <__fwd/mdspan.h> +#include <__mdspan/default_accessor.h> +#include <__mdspan/extents.h> +#include <__type_traits/extent.h> +#include <__type_traits/is_abstract.h> +#include <__type_traits/is_array.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_default_constructible.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_pointer.h> +#include <__type_traits/is_same.h> +#include <__type_traits/rank.h> +#include <__type_traits/remove_all_extents.h> +#include <__type_traits/remove_cv.h> +#include <__type_traits/remove_pointer.h> +#include <__type_traits/remove_reference.h> +#include <__utility/integer_sequence.h> +#include <array> +#include <cinttypes> +#include <cstddef> +#include <limits> +#include <span> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +// Helper for lightweight test checking that one did pass a layout policy as LayoutPolicy template argument +namespace __mdspan_detail { +template <class _Layout, class _Extents> +concept __has_invalid_mapping = !requires { typename _Layout::template mapping<_Extents>; }; +} // namespace __mdspan_detail + +template <class _ElementType, + class _Extents, + class _LayoutPolicy = layout_right, + class _AccessorPolicy = default_accessor<_ElementType> > +class mdspan { +private: + static_assert(__mdspan_detail::__is_extents_v<_Extents>, + "mdspan: Extents template parameter must be a specialization of extents."); + static_assert(!is_array_v<_ElementType>, "mdspan: ElementType template parameter may not be an array type"); + static_assert(!is_abstract_v<_ElementType>, "mdspan: ElementType template parameter may not be an abstract class"); + static_assert(is_same_v<_ElementType, typename _AccessorPolicy::element_type>, + "mdspan: ElementType template parameter must match AccessorPolicy::element_type"); + static_assert(!__mdspan_detail::__has_invalid_mapping<_LayoutPolicy, _Extents>, + "mdspan: LayoutPolicy template parameter is invalid. A common mistake is to pass a layout mapping " + "instead of a layout policy"); + +public: + using extents_type = _Extents; + using layout_type = _LayoutPolicy; + using accessor_type = _AccessorPolicy; + using mapping_type = typename layout_type::template mapping<extents_type>; + using element_type = _ElementType; + using value_type = remove_cv_t<element_type>; + using index_type = typename extents_type::index_type; + using size_type = typename extents_type::size_type; + using rank_type = typename extents_type::rank_type; + using data_handle_type = typename accessor_type::data_handle_type; + using reference = typename accessor_type::reference; + + _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank() noexcept { return extents_type::rank(); } + _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank_dynamic() noexcept { return extents_type::rank_dynamic(); } + _LIBCPP_HIDE_FROM_ABI static constexpr size_t static_extent(rank_type __r) noexcept { + return extents_type::static_extent(__r); + } + _LIBCPP_HIDE_FROM_ABI constexpr index_type extent(rank_type __r) const noexcept { + return __map_.extents().extent(__r); + }; + +public: + //-------------------------------------------------------------------------------- + // [mdspan.mdspan.cons], mdspan constructors, assignment, and destructor + + _LIBCPP_HIDE_FROM_ABI constexpr mdspan() + requires((extents_type::rank_dynamic() > 0) && is_default_constructible_v<data_handle_type> && + is_default_constructible_v<mapping_type> && is_default_constructible_v<accessor_type>) + = default; + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(const mdspan&) = default; + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(mdspan&&) = default; + + template <class... _OtherIndexTypes> + requires((is_convertible_v<_OtherIndexTypes, index_type> && ...) && + (is_nothrow_constructible_v<index_type, _OtherIndexTypes> && ...) && + ((sizeof...(_OtherIndexTypes) == rank()) || (sizeof...(_OtherIndexTypes) == rank_dynamic())) && + is_constructible_v<mapping_type, extents_type> && is_default_constructible_v<accessor_type>) + _LIBCPP_HIDE_FROM_ABI explicit constexpr mdspan(data_handle_type __p, _OtherIndexTypes... __exts) + : __ptr_(std::move(__p)), __map_(extents_type(static_cast<index_type>(std::move(__exts))...)), __acc_{} {} + + template <class _OtherIndexType, size_t _Size> + requires(is_convertible_v<const _OtherIndexType&, index_type> && + is_nothrow_constructible_v<index_type, const _OtherIndexType&> && + ((_Size == rank()) || (_Size == rank_dynamic())) && is_constructible_v<mapping_type, extents_type> && + is_default_constructible_v<accessor_type>) + explicit(_Size != rank_dynamic()) + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(data_handle_type __p, const array<_OtherIndexType, _Size>& __exts) + : __ptr_(std::move(__p)), __map_(extents_type(__exts)), __acc_{} {} + + template <class _OtherIndexType, size_t _Size> + requires(is_convertible_v<const _OtherIndexType&, index_type> && + is_nothrow_constructible_v<index_type, const _OtherIndexType&> && + ((_Size == rank()) || (_Size == rank_dynamic())) && is_constructible_v<mapping_type, extents_type> && + is_default_constructible_v<accessor_type>) + explicit(_Size != rank_dynamic()) + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(data_handle_type __p, span<_OtherIndexType, _Size> __exts) + : __ptr_(std::move(__p)), __map_(extents_type(__exts)), __acc_{} {} + + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(data_handle_type __p, const extents_type& __exts) + requires(is_default_constructible_v<accessor_type> && is_constructible_v<mapping_type, const extents_type&>) + : __ptr_(std::move(__p)), __map_(__exts), __acc_{} {} + + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(data_handle_type __p, const mapping_type& __m) + requires(is_default_constructible_v<accessor_type>) + : __ptr_(std::move(__p)), __map_(__m), __acc_{} {} + + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(data_handle_type __p, const mapping_type& __m, const accessor_type& __a) + : __ptr_(std::move(__p)), __map_(__m), __acc_(__a) {} + + template <class _OtherElementType, class _OtherExtents, class _OtherLayoutPolicy, class _OtherAccessor> + requires(is_constructible_v<mapping_type, const typename _OtherLayoutPolicy::template mapping<_OtherExtents>&> && + is_constructible_v<accessor_type, const _OtherAccessor&>) + explicit(!is_convertible_v<const typename _OtherLayoutPolicy::template mapping<_OtherExtents>&, mapping_type> || + !is_convertible_v<const _OtherAccessor&, accessor_type>) + _LIBCPP_HIDE_FROM_ABI constexpr mdspan( + const mdspan<_OtherElementType, _OtherExtents, _OtherLayoutPolicy, _OtherAccessor>& __other) + : __ptr_(__other.__ptr_), __map_(__other.__map_), __acc_(__other.__acc_) { + static_assert(is_constructible_v<data_handle_type, const typename _OtherAccessor::data_handle_type&>, + "mdspan: incompatible data_handle_type for mdspan construction"); + static_assert( + is_constructible_v<extents_type, _OtherExtents>, "mdspan: incompatible extents for mdspan construction"); + + // The following precondition is part of the standard, but is unlikely to be triggered. + // The extents constructor checks this and the mapping must be storing the extents, since + // its extents() function returns a const reference to extents_type. + // The only way this can be triggered is if the mapping conversion constructor would for example + // always construct its extents() only from the dynamic extents, instead of from the other extents. + if constexpr (rank() > 0) { + for (size_t __r = 0; __r < rank(); __r++) { + // Not catching this could lead to out of bounds errors later + // e.g. mdspan<int, dextents<char,1>, non_checking_layout> m = + // mdspan<int, dextents<unsigned, 1>, non_checking_layout>(ptr, 200); leads to an extent of -56 on m + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + (static_extent(__r) == dynamic_extent) || + (static_cast<index_type>(__other.extent(__r)) == static_cast<index_type>(static_extent(__r))), + "mdspan: conversion mismatch of source dynamic extents with static extents"); + } + } + } + + _LIBCPP_HIDE_FROM_ABI constexpr mdspan& operator=(const mdspan&) = default; + _LIBCPP_HIDE_FROM_ABI constexpr mdspan& operator=(mdspan&&) = default; + + //-------------------------------------------------------------------------------- + // [mdspan.mdspan.members], members + + template <class... _OtherIndexTypes> + requires((is_convertible_v<_OtherIndexTypes, index_type> && ...) && + (is_nothrow_constructible_v<index_type, _OtherIndexTypes> && ...) && + (sizeof...(_OtherIndexTypes) == rank())) + _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](_OtherIndexTypes... __indices) const { + // Note the standard layouts would also check this, but user provided ones may not, so we + // check the precondition here + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__is_multidimensional_index_in(extents(), __indices...), + "mdspan: operator[] out of bounds access"); + return __acc_.access(__ptr_, __map_(static_cast<index_type>(std::move(__indices))...)); + } + + template <class _OtherIndexType> + requires(is_convertible_v<const _OtherIndexType&, index_type> && + is_nothrow_constructible_v<index_type, const _OtherIndexType&>) + _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](const array< _OtherIndexType, rank()>& __indices) const { + return __acc_.access(__ptr_, [&]<size_t... _Idxs>(index_sequence<_Idxs...>) { + return __map_(__indices[_Idxs]...); + }(make_index_sequence<rank()>())); + } + + template <class _OtherIndexType> + requires(is_convertible_v<const _OtherIndexType&, index_type> && + is_nothrow_constructible_v<index_type, const _OtherIndexType&>) + _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](span<_OtherIndexType, rank()> __indices) const { + return __acc_.access(__ptr_, [&]<size_t... _Idxs>(index_sequence<_Idxs...>) { + return __map_(__indices[_Idxs]...); + }(make_index_sequence<rank()>())); + } + + _LIBCPP_HIDE_FROM_ABI constexpr size_type size() const noexcept { + // Could leave this as only checked in debug mode: semantically size() is never + // guaranteed to be related to any accessible range + _LIBCPP_ASSERT_UNCATEGORIZED( + false == ([&]<size_t... _Idxs>(index_sequence<_Idxs...>) { + size_type __prod = 1; + return (__builtin_mul_overflow(__prod, extent(_Idxs), &__prod) || ... || false); + }(make_index_sequence<rank()>())), + "mdspan: size() is not representable as size_type"); + return [&]<size_t... _Idxs>(index_sequence<_Idxs...>) { + return ((static_cast<size_type>(__map_.extents().extent(_Idxs))) * ... * size_type(1)); + }(make_index_sequence<rank()>()); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const noexcept { + return [&]<size_t... _Idxs>(index_sequence<_Idxs...>) { + return (rank() > 0) && ((__map_.extents().extent(_Idxs) == index_type(0)) || ... || false); + }(make_index_sequence<rank()>()); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr void swap(mdspan& __x, mdspan& __y) noexcept { + swap(__x.__ptr_, __y.__ptr_); + swap(__x.__map_, __y.__map_); + swap(__x.__acc_, __y.__acc_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr const extents_type& extents() const noexcept { return __map_.extents(); }; + _LIBCPP_HIDE_FROM_ABI constexpr const data_handle_type& data_handle() const noexcept { return __ptr_; }; + _LIBCPP_HIDE_FROM_ABI constexpr const mapping_type& mapping() const noexcept { return __map_; }; + _LIBCPP_HIDE_FROM_ABI constexpr const accessor_type& accessor() const noexcept { return __acc_; }; + + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_unique() { return mapping_type::is_always_unique(); }; + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_exhaustive() { return mapping_type::is_always_exhaustive(); }; + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_strided() { return mapping_type::is_always_strided(); }; + + _LIBCPP_HIDE_FROM_ABI constexpr bool is_unique() const { return __map_.is_unique(); }; + _LIBCPP_HIDE_FROM_ABI constexpr bool is_exhaustive() const { return __map_.is_exhaustive(); }; + _LIBCPP_HIDE_FROM_ABI constexpr bool is_strided() const { return __map_.is_strided(); }; + _LIBCPP_HIDE_FROM_ABI constexpr index_type stride(rank_type __r) const { return __map_.stride(__r); }; + +private: + _LIBCPP_NO_UNIQUE_ADDRESS data_handle_type __ptr_{}; + _LIBCPP_NO_UNIQUE_ADDRESS mapping_type __map_{}; + _LIBCPP_NO_UNIQUE_ADDRESS accessor_type __acc_{}; + + template <class, class, class, class> + friend class mdspan; +}; + +template <class _ElementType, class... _OtherIndexTypes> + requires((is_convertible_v<_OtherIndexTypes, size_t> && ...) && (sizeof...(_OtherIndexTypes) > 0)) +explicit mdspan(_ElementType*, _OtherIndexTypes...) + -> mdspan<_ElementType, dextents<size_t, sizeof...(_OtherIndexTypes)>>; + +template <class _Pointer> + requires(is_pointer_v<remove_reference_t<_Pointer>>) +mdspan(_Pointer&&) -> mdspan<remove_pointer_t<remove_reference_t<_Pointer>>, extents<size_t>>; + +template <class _CArray> + requires(is_array_v<_CArray> && (rank_v<_CArray> == 1)) +mdspan(_CArray&) -> mdspan<remove_all_extents_t<_CArray>, extents<size_t, extent_v<_CArray, 0>>>; + +template <class _ElementType, class _OtherIndexType, size_t _Size> +mdspan(_ElementType*, const array<_OtherIndexType, _Size>&) -> mdspan<_ElementType, dextents<size_t, _Size>>; + +template <class _ElementType, class _OtherIndexType, size_t _Size> +mdspan(_ElementType*, span<_OtherIndexType, _Size>) -> mdspan<_ElementType, dextents<size_t, _Size>>; + +// This one is necessary because all the constructors take `data_handle_type`s, not +// `_ElementType*`s, and `data_handle_type` is taken from `accessor_type::data_handle_type`, which +// seems to throw off automatic deduction guides. +template <class _ElementType, class _OtherIndexType, size_t... _ExtentsPack> +mdspan(_ElementType*, const extents<_OtherIndexType, _ExtentsPack...>&) + -> mdspan<_ElementType, extents<_OtherIndexType, _ExtentsPack...>>; + +template <class _ElementType, class _MappingType> +mdspan(_ElementType*, const _MappingType&) + -> mdspan<_ElementType, typename _MappingType::extents_type, typename _MappingType::layout_type>; + +template <class _MappingType, class _AccessorType> +mdspan(const typename _AccessorType::data_handle_type, const _MappingType&, const _AccessorType&) + -> mdspan<typename _AccessorType::element_type, + typename _MappingType::extents_type, + typename _MappingType::layout_type, + _AccessorType>; + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___MDSPAN_MDSPAN_H diff --git a/libcxx/include/mdspan b/libcxx/include/mdspan index 701def50b40a..9082eb8bdb55 100644 --- a/libcxx/include/mdspan +++ b/libcxx/include/mdspan @@ -208,6 +208,135 @@ namespace std { }; } +// mdspan synopsis + +namespace std { + template<class ElementType, class Extents, class LayoutPolicy = layout_right, + class AccessorPolicy = default_accessor<ElementType>> + class mdspan { + public: + using extents_type = Extents; + using layout_type = LayoutPolicy; + using accessor_type = AccessorPolicy; + using mapping_type = typename layout_type::template mapping<extents_type>; + using element_type = ElementType; + using value_type = remove_cv_t<element_type>; + using index_type = typename extents_type::index_type; + using size_type = typename extents_type::size_type; + using rank_type = typename extents_type::rank_type; + using data_handle_type = typename accessor_type::data_handle_type; + using reference = typename accessor_type::reference; + + static constexpr rank_type rank() noexcept { return extents_type::rank(); } + static constexpr rank_type rank_dynamic() noexcept { return extents_type::rank_dynamic(); } + static constexpr size_t static_extent(rank_type r) noexcept + { return extents_type::static_extent(r); } + constexpr index_type extent(rank_type r) const noexcept { return extents().extent(r); } + + // [mdspan.mdspan.cons], constructors + constexpr mdspan(); + constexpr mdspan(const mdspan& rhs) = default; + constexpr mdspan(mdspan&& rhs) = default; + + template<class... OtherIndexTypes> + constexpr explicit mdspan(data_handle_type ptr, OtherIndexTypes... exts); + template<class OtherIndexType, size_t N> + constexpr explicit(N != rank_dynamic()) + mdspan(data_handle_type p, span<OtherIndexType, N> exts); + template<class OtherIndexType, size_t N> + constexpr explicit(N != rank_dynamic()) + mdspan(data_handle_type p, const array<OtherIndexType, N>& exts); + constexpr mdspan(data_handle_type p, const extents_type& ext); + constexpr mdspan(data_handle_type p, const mapping_type& m); + constexpr mdspan(data_handle_type p, const mapping_type& m, const accessor_type& a); + + template<class OtherElementType, class OtherExtents, + class OtherLayoutPolicy, class OtherAccessorPolicy> + constexpr explicit(see below) + mdspan(const mdspan<OtherElementType, OtherExtents, + OtherLayoutPolicy, OtherAccessorPolicy>& other); + + constexpr mdspan& operator=(const mdspan& rhs) = default; + constexpr mdspan& operator=(mdspan&& rhs) = default; + + // [mdspan.mdspan.members], members + template<class... OtherIndexTypes> + constexpr reference operator[](OtherIndexTypes... indices) const; + template<class OtherIndexType> + constexpr reference operator[](span<OtherIndexType, rank()> indices) const; + template<class OtherIndexType> + constexpr reference operator[](const array<OtherIndexType, rank()>& indices) const; + + constexpr size_type size() const noexcept; + [[nodiscard]] constexpr bool empty() const noexcept; + + friend constexpr void swap(mdspan& x, mdspan& y) noexcept; + + constexpr const extents_type& extents() const noexcept { return map_.extents(); } + constexpr const data_handle_type& data_handle() const noexcept { return ptr_; } + constexpr const mapping_type& mapping() const noexcept { return map_; } + constexpr const accessor_type& accessor() const noexcept { return acc_; } + + static constexpr bool is_always_unique() + { return mapping_type::is_always_unique(); } + static constexpr bool is_always_exhaustive() + { return mapping_type::is_always_exhaustive(); } + static constexpr bool is_always_strided() + { return mapping_type::is_always_strided(); } + + constexpr bool is_unique() const + { return map_.is_unique(); } + constexpr bool is_exhaustive() const + { return map_.is_exhaustive(); } + constexpr bool is_strided() const + { return map_.is_strided(); } + constexpr index_type stride(rank_type r) const + { return map_.stride(r); } + + private: + accessor_type acc_; // exposition only + mapping_type map_; // exposition only + data_handle_type ptr_; // exposition only + }; + + template<class CArray> + requires(is_array_v<CArray> && rank_v<CArray> == 1) + mdspan(CArray&) + -> mdspan<remove_all_extents_t<CArray>, extents<size_t, extent_v<CArray, 0>>>; + + template<class Pointer> + requires(is_pointer_v<remove_reference_t<Pointer>>) + mdspan(Pointer&&) + -> mdspan<remove_pointer_t<remove_reference_t<Pointer>>, extents<size_t>>; + + template<class ElementType, class... Integrals> + requires((is_convertible_v<Integrals, size_t> && ...) && sizeof...(Integrals) > 0) + explicit mdspan(ElementType*, Integrals...) + -> mdspan<ElementType, dextents<size_t, sizeof...(Integrals)>>; + + template<class ElementType, class OtherIndexType, size_t N> + mdspan(ElementType*, span<OtherIndexType, N>) + -> mdspan<ElementType, dextents<size_t, N>>; + + template<class ElementType, class OtherIndexType, size_t N> + mdspan(ElementType*, const array<OtherIndexType, N>&) + -> mdspan<ElementType, dextents<size_t, N>>; + + template<class ElementType, class IndexType, size_t... ExtentsPack> + mdspan(ElementType*, const extents<IndexType, ExtentsPack...>&) + -> mdspan<ElementType, extents<IndexType, ExtentsPack...>>; + + template<class ElementType, class MappingType> + mdspan(ElementType*, const MappingType&) + -> mdspan<ElementType, typename MappingType::extents_type, + typename MappingType::layout_type>; + + template<class MappingType, class AccessorType> + mdspan(const typename AccessorType::data_handle_type&, const MappingType&, + const AccessorType&) + -> mdspan<typename AccessorType::element_type, typename MappingType::extents_type, + typename MappingType::layout_type, AccessorType>; +} */ #ifndef _LIBCPP_MDSPAN @@ -219,6 +348,7 @@ namespace std { #include <__mdspan/extents.h> #include <__mdspan/layout_left.h> #include <__mdspan/layout_right.h> +#include <__mdspan/mdspan.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in index 9ff8b67a6a20..0b418d2b7897 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -1516,6 +1516,7 @@ module std_private_mdspan_extents [system] { } module std_private_mdspan_layout_left [system] { header "__mdspan/layout_left.h" } module std_private_mdspan_layout_right [system] { header "__mdspan/layout_right.h" } +module std_private_mdspan_mdspan [system] { header "__mdspan/mdspan.h" } module std_private_mdspan_mdspan_fwd [system] { header "__fwd/mdspan.h" } module std_private_memory_addressof [system] { header "__memory/addressof.h" } diff --git a/libcxx/modules/std/mdspan.cppm b/libcxx/modules/std/mdspan.cppm index 5023dfb925ea..d92024d9a77a 100644 --- a/libcxx/modules/std/mdspan.cppm +++ b/libcxx/modules/std/mdspan.cppm @@ -27,5 +27,5 @@ export namespace std { using std::default_accessor; // [mdspan.mdspan], class template mdspan - // using std::mdspan; + using std::mdspan; } // namespace std diff --git a/llvm/include/llvm/TargetParser/LoongArchTargetParser.h b/llvm/include/llvm/TargetParser/LoongArchTargetParser.h index 2aa65ec070ec..82ab064211d7 100644 --- a/llvm/include/llvm/TargetParser/LoongArchTargetParser.h +++ b/llvm/include/llvm/TargetParser/LoongArchTargetParser.h @@ -66,9 +66,16 @@ struct ArchInfo { bool isValidArchName(StringRef Arch); bool getArchFeatures(StringRef Arch, std::vector<StringRef> &Features); +bool isValidTuneCPUName(StringRef TuneCPU); +void fillValidTuneCPUList(SmallVectorImpl<StringRef> &Values); +StringRef getDefaultArch(bool Is64Bit); +void setArch(StringRef Arch); +StringRef getArch(); +void setTuneCPU(StringRef TuneCPU); +StringRef getTuneCPU(); } // namespace LoongArch } // namespace llvm -#endif // LLVM_SUPPORT_LOONGARCHTARGETPARSER_H +#endif // LLVM_TARGETPARSER_LOONGARCHTARGETPARSER_H diff --git a/llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h b/llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h index 4e78d9db024c..f780385f7f67 100644 --- a/llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h +++ b/llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h @@ -126,15 +126,6 @@ class InstCostVisitor : public InstVisitor<InstCostVisitor, Constant *> { SCCPSolver &Solver; ConstMap KnownConstants; - // Basic blocks known to be unreachable after constant propagation. - DenseSet<BasicBlock *> DeadBlocks; - // PHI nodes we have visited before. - DenseSet<Instruction *> VisitedPHIs; - // PHI nodes we have visited once without successfully constant folding them. - // Once the InstCostVisitor has processed all the specialization arguments, - // it should be possible to determine whether those PHIs can be folded - // (some of their incoming values may have become constant or dead). - SmallVector<Instruction *> PendingPHIs; ConstMap::iterator LastVisited; @@ -143,10 +134,7 @@ public: TargetTransformInfo &TTI, SCCPSolver &Solver) : DL(DL), BFI(BFI), TTI(TTI), Solver(Solver) {} - Cost getUserBonus(Instruction *User, Value *Use = nullptr, - Constant *C = nullptr); - - Cost getBonusFromPendingPHIs(); + Cost getUserBonus(Instruction *User, Value *Use, Constant *C); private: friend class InstVisitor<InstCostVisitor, Constant *>; @@ -155,7 +143,6 @@ private: Cost estimateBranchInst(BranchInst &I); Constant *visitInstruction(Instruction &I) { return nullptr; } - Constant *visitPHINode(PHINode &I); Constant *visitFreezeInst(FreezeInst &I); Constant *visitCallBase(CallBase &I); Constant *visitLoadInst(LoadInst &I); diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp index 3994552884c4..647f570ab807 100644 --- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -2628,12 +2628,12 @@ MCSymbol *TargetLoweringObjectFileXCOFF::getFunctionEntryPointSymbol( // function entry point csect instead. And for function delcarations, the // undefined symbols gets treated as csect with XTY_ER property. if (((TM.getFunctionSections() && !Func->hasSection()) || - Func->isDeclaration()) && + Func->isDeclarationForLinker()) && isa<Function>(Func)) { return getContext() .getXCOFFSection( NameStr, SectionKind::getText(), - XCOFF::CsectProperties(XCOFF::XMC_PR, Func->isDeclaration() + XCOFF::CsectProperties(XCOFF::XMC_PR, Func->isDeclarationForLinker() ? XCOFF::XTY_ER : XCOFF::XTY_SD)) ->getQualNameSymbol(); diff --git a/llvm/lib/Target/LoongArch/LoongArch.td b/llvm/lib/Target/LoongArch/LoongArch.td index 7241a5d63526..0675caa3b601 100644 --- a/llvm/lib/Target/LoongArch/LoongArch.td +++ b/llvm/lib/Target/LoongArch/LoongArch.td @@ -117,6 +117,11 @@ include "LoongArchInstrInfo.td" def : ProcessorModel<"generic-la32", NoSchedModel, [Feature32Bit]>; def : ProcessorModel<"generic-la64", NoSchedModel, [Feature64Bit, FeatureUAL]>; +// Generic 64-bit processor with double-precision floating-point support. +def : ProcessorModel<"loongarch64", NoSchedModel, [Feature64Bit, + FeatureUAL, + FeatureBasicD]>; + // Support generic for compatibility with other targets. The triple will be used // to change to the appropriate la32/la64 version. def : ProcessorModel<"generic", NoSchedModel, []>; diff --git a/llvm/lib/TargetParser/LoongArchTargetParser.cpp b/llvm/lib/TargetParser/LoongArchTargetParser.cpp index 18b04600dbc6..72781513ff12 100644 --- a/llvm/lib/TargetParser/LoongArchTargetParser.cpp +++ b/llvm/lib/TargetParser/LoongArchTargetParser.cpp @@ -16,6 +16,9 @@ using namespace llvm; using namespace llvm::LoongArch; +StringRef Arch; +StringRef TuneCPU; + const FeatureInfo AllFeatures[] = { #define LOONGARCH_FEATURE(NAME, KIND) {NAME, KIND}, #include "llvm/TargetParser/LoongArchTargetParser.def" @@ -46,3 +49,25 @@ bool LoongArch::getArchFeatures(StringRef Arch, } return false; } + +bool LoongArch::isValidTuneCPUName(StringRef TuneCPU) { + return isValidArchName(TuneCPU); +} + +void LoongArch::fillValidTuneCPUList(SmallVectorImpl<StringRef> &Values) { + for (const auto A : AllArchs) + Values.emplace_back(A.Name); +} + +StringRef LoongArch::getDefaultArch(bool Is64Bit) { + // TODO: use a real 32-bit arch name. + return Is64Bit ? "loongarch64" : ""; +} + +void LoongArch::setArch(StringRef Name) { Arch = Name; } + +StringRef LoongArch::getArch() { return Arch; } + +void LoongArch::setTuneCPU(StringRef Name) { TuneCPU = Name; } + +StringRef LoongArch::getTuneCPU() { return TuneCPU; } diff --git a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp index 3d6c501e4596..ac5dbc7cfb2a 100644 --- a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp +++ b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp @@ -78,11 +78,6 @@ static cl::opt<unsigned> MaxClones( "The maximum number of clones allowed for a single function " "specialization")); -static cl::opt<unsigned> MaxIncomingPhiValues( - "funcspec-max-incoming-phi-values", cl::init(4), cl::Hidden, cl::desc( - "The maximum number of incoming values a PHI node can have to be " - "considered during the specialization bonus estimation")); - static cl::opt<unsigned> MinFunctionSize( "funcspec-min-function-size", cl::init(100), cl::Hidden, cl::desc( "Don't specialize functions that have less than this number of " @@ -109,7 +104,6 @@ static cl::opt<bool> SpecializeLiteralConstant( // the combination of size and latency savings in comparison to the non // specialized version of the function. static Cost estimateBasicBlocks(SmallVectorImpl<BasicBlock *> &WorkList, - DenseSet<BasicBlock *> &DeadBlocks, ConstMap &KnownConstants, SCCPSolver &Solver, BlockFrequencyInfo &BFI, TargetTransformInfo &TTI) { @@ -124,12 +118,6 @@ static Cost estimateBasicBlocks(SmallVectorImpl<BasicBlock *> &WorkList, if (!Weight) continue; - // These blocks are considered dead as far as the InstCostVisitor is - // concerned. They haven't been proven dead yet by the Solver, but - // may become if we propagate the constant specialization arguments. - if (!DeadBlocks.insert(BB).second) - continue; - for (Instruction &I : *BB) { // Disregard SSA copies. if (auto *II = dyn_cast<IntrinsicInst>(&I)) @@ -164,19 +152,9 @@ static Constant *findConstantFor(Value *V, ConstMap &KnownConstants) { return nullptr; } -Cost InstCostVisitor::getBonusFromPendingPHIs() { - Cost Bonus = 0; - while (!PendingPHIs.empty()) { - Instruction *Phi = PendingPHIs.pop_back_val(); - Bonus += getUserBonus(Phi); - } - return Bonus; -} - Cost InstCostVisitor::getUserBonus(Instruction *User, Value *Use, Constant *C) { // Cache the iterator before visiting. - LastVisited = Use ? KnownConstants.insert({Use, C}).first - : KnownConstants.end(); + LastVisited = KnownConstants.insert({Use, C}).first; if (auto *I = dyn_cast<SwitchInst>(User)) return estimateSwitchInst(*I); @@ -203,15 +181,13 @@ Cost InstCostVisitor::getUserBonus(Instruction *User, Value *Use, Constant *C) { for (auto *U : User->users()) if (auto *UI = dyn_cast<Instruction>(U)) - if (UI != User && Solver.isBlockExecutable(UI->getParent())) + if (Solver.isBlockExecutable(UI->getParent())) Bonus += getUserBonus(UI, User, C); return Bonus; } Cost InstCostVisitor::estimateSwitchInst(SwitchInst &I) { - assert(LastVisited != KnownConstants.end() && "Invalid iterator!"); - if (I.getCondition() != LastVisited->first) return 0; @@ -232,13 +208,10 @@ Cost InstCostVisitor::estimateSwitchInst(SwitchInst &I) { WorkList.push_back(BB); } - return estimateBasicBlocks(WorkList, DeadBlocks, KnownConstants, Solver, BFI, - TTI); + return estimateBasicBlocks(WorkList, KnownConstants, Solver, BFI, TTI); } Cost InstCostVisitor::estimateBranchInst(BranchInst &I) { - assert(LastVisited != KnownConstants.end() && "Invalid iterator!"); - if (I.getCondition() != LastVisited->first) return 0; @@ -250,39 +223,10 @@ Cost InstCostVisitor::estimateBranchInst(BranchInst &I) { Succ->getUniquePredecessor() == I.getParent()) WorkList.push_back(Succ); - return estimateBasicBlocks(WorkList, DeadBlocks, KnownConstants, Solver, BFI, - TTI); -} - -Constant *InstCostVisitor::visitPHINode(PHINode &I) { - if (I.getNumIncomingValues() > MaxIncomingPhiValues) - return nullptr; - - bool Inserted = VisitedPHIs.insert(&I).second; - Constant *Const = nullptr; - - for (unsigned Idx = 0, E = I.getNumIncomingValues(); Idx != E; ++Idx) { - Value *V = I.getIncomingValue(Idx); - if (auto *Inst = dyn_cast<Instruction>(V)) - if (Inst == &I || DeadBlocks.contains(I.getIncomingBlock(Idx))) - continue; - Constant *C = findConstantFor(V, KnownConstants); - if (!C) { - if (Inserted) - PendingPHIs.push_back(&I); - return nullptr; - } - if (!Const) - Const = C; - else if (C != Const) - return nullptr; - } - return Const; + return estimateBasicBlocks(WorkList, KnownConstants, Solver, BFI, TTI); } Constant *InstCostVisitor::visitFreezeInst(FreezeInst &I) { - assert(LastVisited != KnownConstants.end() && "Invalid iterator!"); - if (isGuaranteedNotToBeUndefOrPoison(LastVisited->second)) return LastVisited->second; return nullptr; @@ -309,8 +253,6 @@ Constant *InstCostVisitor::visitCallBase(CallBase &I) { } Constant *InstCostVisitor::visitLoadInst(LoadInst &I) { - assert(LastVisited != KnownConstants.end() && "Invalid iterator!"); - if (isa<ConstantPointerNull>(LastVisited->second)) return nullptr; return ConstantFoldLoadFromConstPtr(LastVisited->second, I.getType(), DL); @@ -333,8 +275,6 @@ Constant *InstCostVisitor::visitGetElementPtrInst(GetElementPtrInst &I) { } Constant *InstCostVisitor::visitSelectInst(SelectInst &I) { - assert(LastVisited != KnownConstants.end() && "Invalid iterator!"); - if (I.getCondition() != LastVisited->first) return nullptr; @@ -350,8 +290,6 @@ Constant *InstCostVisitor::visitCastInst(CastInst &I) { } Constant *InstCostVisitor::visitCmpInst(CmpInst &I) { - assert(LastVisited != KnownConstants.end() && "Invalid iterator!"); - bool Swap = I.getOperand(1) == LastVisited->first; Value *V = Swap ? I.getOperand(0) : I.getOperand(1); Constant *Other = findConstantFor(V, KnownConstants); @@ -365,14 +303,10 @@ Constant *InstCostVisitor::visitCmpInst(CmpInst &I) { } Constant *InstCostVisitor::visitUnaryOperator(UnaryOperator &I) { - assert(LastVisited != KnownConstants.end() && "Invalid iterator!"); - return ConstantFoldUnaryOpOperand(I.getOpcode(), LastVisited->second, DL); } Constant *InstCostVisitor::visitBinaryOperator(BinaryOperator &I) { - assert(LastVisited != KnownConstants.end() && "Invalid iterator!"); - bool Swap = I.getOperand(1) == LastVisited->first; Value *V = Swap ? I.getOperand(0) : I.getOperand(1); Constant *Other = findConstantFor(V, KnownConstants); @@ -779,17 +713,13 @@ bool FunctionSpecializer::findSpecializations(Function *F, Cost SpecCost, AllSpecs[Index].CallSites.push_back(&CS); } else { // Calculate the specialisation gain. - Cost Score = 0; + Cost Score = 0 - SpecCost; InstCostVisitor Visitor = getInstCostVisitorFor(F); for (ArgInfo &A : S.Args) Score += getSpecializationBonus(A.Formal, A.Actual, Visitor); - Score += Visitor.getBonusFromPendingPHIs(); - - LLVM_DEBUG(dbgs() << "FnSpecialization: Specialization score = " - << Score << "\n"); // Discard unprofitable specialisations. - if (!ForceSpecialization && Score <= SpecCost) + if (!ForceSpecialization && Score <= 0) continue; // Create a new specialisation entry. diff --git a/openmp/runtime/src/ompt-event-specific.h b/openmp/runtime/src/ompt-event-specific.h index 5ac7f6d1e4e6..7736ba853163 100644 --- a/openmp/runtime/src/ompt-event-specific.h +++ b/openmp/runtime/src/ompt-event-specific.h @@ -55,13 +55,12 @@ #define ompt_callback_implicit_task_implemented ompt_event_MAY_ALWAYS -#define ompt_callback_target_implemented ompt_event_UNIMPLEMENTED -#define ompt_callback_target_emi_implemented ompt_event_UNIMPLEMENTED -#define ompt_callback_target_data_op_implemented ompt_event_UNIMPLEMENTED -#define ompt_callback_target_data_op_emi_implemented ompt_event_UNIMPLEMENTED -#define ompt_callback_target_submit_implemented ompt_event_UNIMPLEMENTED -#define ompt_callback_target_submit_emi_implemented ompt_event_UNIMPLEMENTED - +#define ompt_callback_target_implemented ompt_event_MAY_ALWAYS +#define ompt_callback_target_emi_implemented ompt_event_MAY_ALWAYS +#define ompt_callback_target_data_op_implemented ompt_event_MAY_ALWAYS +#define ompt_callback_target_data_op_emi_implemented ompt_event_MAY_ALWAYS +#define ompt_callback_target_submit_implemented ompt_event_MAY_ALWAYS +#define ompt_callback_target_submit_emi_implemented ompt_event_MAY_ALWAYS #define ompt_callback_control_tool_implemented ompt_event_MAY_ALWAYS #define ompt_callback_device_initialize_implemented ompt_event_MAY_ALWAYS |