aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2023-07-26 19:11:12 +0000
committerDimitry Andric <dim@FreeBSD.org>2023-07-26 19:11:12 +0000
commit2d22c9abbd20fdc3d3a469075bd151ca1bd02ee4 (patch)
treebc941261e4067c56d7da297e4f3e606bad5695c1
parent7fa27ce4a07f19b07799a767fc29416f3b625afb (diff)
downloadsrc-2d22c9abbd20fdc3d3a469075bd151ca1bd02ee4.tar.gz
src-2d22c9abbd20fdc3d3a469075bd151ca1bd02ee4.zip
-rw-r--r--clang/lib/Basic/Targets/LoongArch.cpp25
-rw-r--r--clang/lib/Basic/Targets/LoongArch.h3
-rw-r--r--clang/lib/Driver/ToolChains/Arch/LoongArch.cpp23
-rw-r--r--clang/lib/Driver/ToolChains/Clang.cpp22
-rw-r--r--libcxx/include/__mdspan/extents.h63
-rw-r--r--libcxx/include/__mdspan/layout_left.h30
-rw-r--r--libcxx/include/__mdspan/layout_right.h30
-rw-r--r--libcxx/include/__mdspan/mdspan.h308
-rw-r--r--libcxx/include/mdspan130
-rw-r--r--libcxx/include/module.modulemap.in1
-rw-r--r--libcxx/modules/std/mdspan.cppm2
-rw-r--r--llvm/include/llvm/TargetParser/LoongArchTargetParser.h9
-rw-r--r--llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h15
-rw-r--r--llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp4
-rw-r--r--llvm/lib/Target/LoongArch/LoongArch.td5
-rw-r--r--llvm/lib/TargetParser/LoongArchTargetParser.cpp25
-rw-r--r--llvm/lib/Transforms/IPO/FunctionSpecialization.cpp82
-rw-r--r--openmp/runtime/src/ompt-event-specific.h13
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