https://github.com/inbelic updated https://github.com/llvm/llvm-project/pull/140962
>From 6ee2563c4b2d69b252467b9896a1d8b943af384d Mon Sep 17 00:00:00 2001 From: Finn Plummer <canadienf...@gmail.com> Date: Tue, 20 May 2025 19:47:29 +0000 Subject: [PATCH 1/2] rebased original version --- .../clang/Basic/DiagnosticSemaKinds.td | 5 + clang/include/clang/Sema/SemaHLSL.h | 2 + clang/lib/Sema/SemaHLSL.cpp | 113 +++++++++++++++++- .../RootSignature-resource-ranges-err.hlsl | 26 ++++ .../RootSignature-resource-ranges.hlsl | 22 ++++ .../Frontend/HLSL/HLSLRootSignatureUtils.h | 10 +- 6 files changed, 174 insertions(+), 4 deletions(-) create mode 100644 clang/test/SemaHLSL/RootSignature-resource-ranges-err.hlsl create mode 100644 clang/test/SemaHLSL/RootSignature-resource-ranges.hlsl diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 34b798a09c216..f2f2152b8bbbe 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -13054,6 +13054,11 @@ def err_invalid_hlsl_resource_type: Error< def err_hlsl_spirv_only: Error<"%0 is only available for the SPIR-V target">; def err_hlsl_vk_literal_must_contain_constant: Error<"the argument to vk::Literal must be a vk::integral_constant">; +def err_hlsl_resource_range_overlap: Error< + "resource ranges %select{t|u|b|s}0[%1;%2] and %select{t|u|b|s}3[%4;%5] " + "overlap within space = %6 and visibility = " + "%select{All|Vertex|Hull|Domain|Geometry|Pixel|Amplification|Mesh}7">; + // Layout randomization diagnostics. def err_non_designated_init_used : Error< "a randomized struct can only be initialized with a designated initializer">; diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index 97091792ba236..7d7eae4db532c 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -134,6 +134,8 @@ class SemaHLSL : public SemaBase { SourceLocation Loc, IdentifierInfo *DeclIdent, SmallVector<llvm::hlsl::rootsig::RootElement> &Elements); + // Returns true when D is invalid and a diagnostic was produced + bool handleRootSignatureDecl(HLSLRootSignatureDecl *D, SourceLocation Loc); void handleRootSignatureAttr(Decl *D, const ParsedAttr &AL); void handleNumThreadsAttr(Decl *D, const ParsedAttr &AL); void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL); diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 9b43ee00810b2..650fd733b71a9 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -39,6 +39,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +#include "llvm/Frontend/HLSL/HLSLRootSignatureUtils.h" #include "llvm/Support/Casting.h" #include "llvm/Support/DXILABI.h" #include "llvm/Support/ErrorHandling.h" @@ -1068,10 +1069,121 @@ void SemaHLSL::ActOnFinishRootSignatureDecl( SemaRef.getASTContext(), /*DeclContext=*/SemaRef.CurContext, Loc, DeclIdent, Elements); + // Perform validation of constructs here + if (handleRootSignatureDecl(SignatureDecl, Loc)) + return; + SignatureDecl->setImplicit(); SemaRef.PushOnScopeChains(SignatureDecl, SemaRef.getCurScope()); } +namespace { + +// A resource range overlaps with another resource range if they have: +// - equivalent ResourceClass (SRV, UAV, CBuffer, Sampler) +// - equivalent resource space +// - overlapping visbility +class ResourceRanges { +public: + // KeyT: 32-lsb denotes resource space, and 32-msb denotes ResourceClass enum + using KeyT = std::pair<ResourceClass, uint32_t>; + + static const size_t NumVisEnums = 8; + +private: + llvm::hlsl::rootsig::ResourceRange::MapT::Allocator Allocator; + + // Denotes a mapping of a unique combination of ResourceClass and register + // space to a ResourceRange + using MapT = llvm::SmallDenseMap<KeyT, llvm::hlsl::rootsig::ResourceRange>; + + // Denotes a mapping for each unique visibility + MapT RangeMaps[NumVisEnums]; + + constexpr static KeyT getKey(const llvm::hlsl::rootsig::RangeInfo &Info) { + return {Info.Class, Info.Space}; + } + +public: + // Returns std::nullopt if there was no collision. Otherwise, it will + // return the RangeInfo of the collision + std::optional<const llvm::hlsl::rootsig::RangeInfo *> + addRange(const llvm::hlsl::rootsig::RangeInfo &Info) { + MapT &VisRangeMap = RangeMaps[llvm::to_underlying(Info.Vis)]; + auto [It, _] = VisRangeMap.insert( + {getKey(Info), llvm::hlsl::rootsig::ResourceRange(Allocator)}); + auto Res = It->second.insert(Info); + if (Res.has_value()) + return Res; + + // If the range that we are inserting has ShaderVisiblity::All it needs to + // check for an overlap in all other visibility types as well. + // Otherwise, the range that is inserted needs to check that it does not + // overlap with ShaderVisibility::All. + // + // Maps will be an ArrayRef to all non-all visibility RangeMaps in the + // former case and it will be an ArrayRef to just the all visiblity + // RangeMap in the latter case. + MutableArrayRef<MapT> Maps = + Info.Vis == llvm::hlsl::rootsig::ShaderVisibility::All + ? MutableArrayRef<MapT>{RangeMaps}.drop_front() + : MutableArrayRef<MapT>{RangeMaps}.take_front(); + + for (MapT &CurMap : Maps) { + auto CurIt = CurMap.find(getKey(Info)); + if (CurIt != CurMap.end()) + if (auto Overlapping = CurIt->second.getOverlapping(Info)) + return Overlapping; + } + + return std::nullopt; + } +}; + +} // namespace + +bool SemaHLSL::handleRootSignatureDecl(HLSLRootSignatureDecl *D, + SourceLocation Loc) { + auto Elements = D->getRootElements(); + + // First we will go through and collect our range info + llvm::SmallVector<llvm::hlsl::rootsig::RangeInfo> Infos; + for (const auto &Elem : Elements) { + if (const auto *Descriptor = + std::get_if<llvm::hlsl::rootsig::RootDescriptor>(&Elem)) { + llvm::hlsl::rootsig::RangeInfo Info; + Info.LowerBound = Descriptor->Reg.Number; + Info.UpperBound = Info.LowerBound; // use inclusive ranges [] + + Info.Class = llvm::dxil::ResourceClass(llvm::to_underlying(Descriptor->Type)); + Info.Space = Descriptor->Space; + Info.Vis = Descriptor->Visibility; + Infos.push_back(Info); + } + } + + // Iterate through info and attempt to insert corresponding range + ResourceRanges Ranges; + bool HadOverlap = false; + for (const llvm::hlsl::rootsig::RangeInfo &Info : Infos) + if (auto MaybeOverlappingInfo = Ranges.addRange(Info)) { + const llvm::hlsl::rootsig::RangeInfo *OInfo = + MaybeOverlappingInfo.value(); + auto CommonVis = Info.Vis == llvm::hlsl::rootsig::ShaderVisibility::All + ? OInfo->Vis + : Info.Vis; + + Diag(Loc, diag::err_hlsl_resource_range_overlap) + << llvm::to_underlying(Info.Class) << Info.LowerBound + << Info.UpperBound << llvm::to_underlying(OInfo->Class) + << OInfo->LowerBound << OInfo->UpperBound << Info.Space << CommonVis; + + HadOverlap = true; + } + + return HadOverlap; +} + void SemaHLSL::handleRootSignatureAttr(Decl *D, const ParsedAttr &AL) { if (AL.getNumArgs() != 1) { Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1; @@ -1093,7 +1205,6 @@ void SemaHLSL::handleRootSignatureAttr(Decl *D, const ParsedAttr &AL) { if (SemaRef.LookupQualifiedName(R, D->getDeclContext())) if (auto *SignatureDecl = dyn_cast<HLSLRootSignatureDecl>(R.getFoundDecl())) { - // Perform validation of constructs here D->addAttr(::new (getASTContext()) RootSignatureAttr( getASTContext(), AL, Ident, SignatureDecl)); } diff --git a/clang/test/SemaHLSL/RootSignature-resource-ranges-err.hlsl b/clang/test/SemaHLSL/RootSignature-resource-ranges-err.hlsl new file mode 100644 index 0000000000000..a4b5b9c77a248 --- /dev/null +++ b/clang/test/SemaHLSL/RootSignature-resource-ranges-err.hlsl @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - %s -verify + +#define Overlap0 "CBV(b42), CBV(b42)" + +[RootSignature(Overlap0)] // expected-error {{resource ranges b[42;42] and b[42;42] overlap within space = 0 and visibility = All}} +void bad_root_signature_0() {} + +#define Overlap1 "SRV(t0, space = 3), SRV(t0, space = 3)" + +[RootSignature(Overlap1)] // expected-error {{resource ranges t[0;0] and t[0;0] overlap within space = 3 and visibility = All}} +void bad_root_signature_1() {} + +#define Overlap2 "UAV(u0, visibility = SHADER_VISIBILITY_PIXEL), UAV(u0, visibility = SHADER_VISIBILITY_PIXEL)" + +[RootSignature(Overlap2)] // expected-error {{resource ranges u[0;0] and u[0;0] overlap within space = 0 and visibility = Pixel}} +void bad_root_signature_2() {} + +#define Overlap3 "UAV(u0, visibility = SHADER_VISIBILITY_ALL), UAV(u0, visibility = SHADER_VISIBILITY_PIXEL)" + +[RootSignature(Overlap3)] // expected-error {{resource ranges u[0;0] and u[0;0] overlap within space = 0 and visibility = Pixel}} +void bad_root_signature_3() {} + +#define Overlap4 "UAV(u0, visibility = SHADER_VISIBILITY_PIXEL), UAV(u0, visibility = SHADER_VISIBILITY_ALL)" + +[RootSignature(Overlap4)] // expected-error {{resource ranges u[0;0] and u[0;0] overlap within space = 0 and visibility = Pixel}} +void bad_root_signature_4() {} diff --git a/clang/test/SemaHLSL/RootSignature-resource-ranges.hlsl b/clang/test/SemaHLSL/RootSignature-resource-ranges.hlsl new file mode 100644 index 0000000000000..3145b5b332dba --- /dev/null +++ b/clang/test/SemaHLSL/RootSignature-resource-ranges.hlsl @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - %s -verify +// expected-no-diagnostics + +#define NoOverlap0 "CBV(b0), CBV(b1)" + +[RootSignature(NoOverlap0)] +void valid_root_signature_0() {} + +#define NoOverlap1 "CBV(b0, visibility = SHADER_VISIBILITY_DOMAIN), CBV(b0, visibility = SHADER_VISIBILITY_PIXEL)" + +[RootSignature(NoOverlap1)] +void valid_root_signature_1() {} + +#define NoOverlap2 "CBV(b0, space = 1), CBV(b0, space = 2)" + +[RootSignature(NoOverlap2)] +void valid_root_signature_2() {} + +#define NoOverlap3 "CBV(b0), SRV(t0)" + +[RootSignature(NoOverlap3)] +void valid_root_signature_3() {} diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h index 25c2a9f0cc808..8a3e2ea63891a 100644 --- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h +++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h @@ -71,13 +71,17 @@ class MetadataBuilder { SmallVector<Metadata *> GeneratedMetadata; }; -// RangeInfo holds the information to correctly construct a ResourceRange -// and retains this information to be used for displaying a better diagnostic struct RangeInfo { - const static uint32_t Unbounded = ~0u; + const static uint32_t Unbounded = static_cast<uint32_t>(-1); + // Interval information uint32_t LowerBound; uint32_t UpperBound; + + // Information retained for diagnostics + llvm::dxil::ResourceClass Class; + uint32_t Space; + ShaderVisibility Vis; }; class ResourceRange { >From 75402c3d73b7120bfb487b8488e0871ae27afa32 Mon Sep 17 00:00:00 2001 From: Finn Plummer <canadienf...@gmail.com> Date: Thu, 19 Jun 2025 21:29:17 +0000 Subject: [PATCH 2/2] review: use sorted RangeInfo as opposed to storing in a densemap - this will improve readability and efficiency as we will be able to free all ResourceRanges after they are used --- clang/lib/Sema/SemaHLSL.cpp | 184 ++++++++++-------- .../Frontend/HLSL/HLSLRootSignatureUtils.h | 3 + .../Frontend/HLSL/HLSLRootSignatureUtils.cpp | 2 + 3 files changed, 106 insertions(+), 83 deletions(-) diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 650fd733b71a9..0c400f7eaf671 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -1077,110 +1077,128 @@ void SemaHLSL::ActOnFinishRootSignatureDecl( SemaRef.PushOnScopeChains(SignatureDecl, SemaRef.getCurScope()); } -namespace { - -// A resource range overlaps with another resource range if they have: -// - equivalent ResourceClass (SRV, UAV, CBuffer, Sampler) -// - equivalent resource space -// - overlapping visbility -class ResourceRanges { -public: - // KeyT: 32-lsb denotes resource space, and 32-msb denotes ResourceClass enum - using KeyT = std::pair<ResourceClass, uint32_t>; - - static const size_t NumVisEnums = 8; - -private: - llvm::hlsl::rootsig::ResourceRange::MapT::Allocator Allocator; - - // Denotes a mapping of a unique combination of ResourceClass and register - // space to a ResourceRange - using MapT = llvm::SmallDenseMap<KeyT, llvm::hlsl::rootsig::ResourceRange>; - - // Denotes a mapping for each unique visibility - MapT RangeMaps[NumVisEnums]; - - constexpr static KeyT getKey(const llvm::hlsl::rootsig::RangeInfo &Info) { - return {Info.Class, Info.Space}; - } - -public: - // Returns std::nullopt if there was no collision. Otherwise, it will - // return the RangeInfo of the collision - std::optional<const llvm::hlsl::rootsig::RangeInfo *> - addRange(const llvm::hlsl::rootsig::RangeInfo &Info) { - MapT &VisRangeMap = RangeMaps[llvm::to_underlying(Info.Vis)]; - auto [It, _] = VisRangeMap.insert( - {getKey(Info), llvm::hlsl::rootsig::ResourceRange(Allocator)}); - auto Res = It->second.insert(Info); - if (Res.has_value()) - return Res; - - // If the range that we are inserting has ShaderVisiblity::All it needs to - // check for an overlap in all other visibility types as well. - // Otherwise, the range that is inserted needs to check that it does not - // overlap with ShaderVisibility::All. - // - // Maps will be an ArrayRef to all non-all visibility RangeMaps in the - // former case and it will be an ArrayRef to just the all visiblity - // RangeMap in the latter case. - MutableArrayRef<MapT> Maps = - Info.Vis == llvm::hlsl::rootsig::ShaderVisibility::All - ? MutableArrayRef<MapT>{RangeMaps}.drop_front() - : MutableArrayRef<MapT>{RangeMaps}.take_front(); - - for (MapT &CurMap : Maps) { - auto CurIt = CurMap.find(getKey(Info)); - if (CurIt != CurMap.end()) - if (auto Overlapping = CurIt->second.getOverlapping(Info)) - return Overlapping; - } - - return std::nullopt; - } -}; - -} // namespace - bool SemaHLSL::handleRootSignatureDecl(HLSLRootSignatureDecl *D, SourceLocation Loc) { auto Elements = D->getRootElements(); - // First we will go through and collect our range info - llvm::SmallVector<llvm::hlsl::rootsig::RangeInfo> Infos; + // The following conducts analysis on resource ranges to detect and report + // any overlaps in resource ranges. + // + // A resource range overlaps with another resource range if they have: + // - equivalent ResourceClass (SRV, UAV, CBuffer, Sampler) + // - equivalent resource space + // - overlapping visbility + // + // The following algorithm is implemented in the following steps: + // + // 1. Collect RangeInfo from relevant RootElements: + // - RangeInfo will retain the interval, ResourceClass, Space and Visibility + // 2. Sort the RangeInfo's such that they are grouped together by + // ResourceClass and Space (GroupT defined below) + // 3. Iterate through the collected RangeInfos by their groups + // - For each group we will have a ResourceRange for each visibility + // - As we iterate through we will: + // A: Insert the current RangeInfo into the corresponding Visibility + // ResourceRange + // B: Check for overlap with any overlapping Visibility ResourceRange + using RangeInfo = llvm::hlsl::rootsig::RangeInfo; + using ResourceRange = llvm::hlsl::rootsig::ResourceRange; + using GroupT = std::pair<ResourceClass, /*Space*/ uint32_t>; + + // 1. Collect RangeInfos + llvm::SmallVector<RangeInfo> Infos; for (const auto &Elem : Elements) { if (const auto *Descriptor = std::get_if<llvm::hlsl::rootsig::RootDescriptor>(&Elem)) { - llvm::hlsl::rootsig::RangeInfo Info; + RangeInfo Info; Info.LowerBound = Descriptor->Reg.Number; Info.UpperBound = Info.LowerBound; // use inclusive ranges [] - Info.Class = llvm::dxil::ResourceClass(llvm::to_underlying(Descriptor->Type)); + Info.Class = + llvm::dxil::ResourceClass(llvm::to_underlying(Descriptor->Type)); Info.Space = Descriptor->Space; Info.Vis = Descriptor->Visibility; Infos.push_back(Info); } } - // Iterate through info and attempt to insert corresponding range - ResourceRanges Ranges; + // 2. Sort the RangeInfo's by their GroupT to form groupings + std::sort(Infos.begin(), Infos.end(), [](RangeInfo A, RangeInfo B) { + return std::tie(A.Class, A.Space) < std::tie(B.Class, B.Space); + }); + + // 3. First we will init our state to track: + if (Infos.size() == 0) + return false; // No ranges to overlap + GroupT CurGroup = {Infos[0].Class, Infos[0].Space}; bool HadOverlap = false; - for (const llvm::hlsl::rootsig::RangeInfo &Info : Infos) - if (auto MaybeOverlappingInfo = Ranges.addRange(Info)) { - const llvm::hlsl::rootsig::RangeInfo *OInfo = - MaybeOverlappingInfo.value(); - auto CommonVis = Info.Vis == llvm::hlsl::rootsig::ShaderVisibility::All - ? OInfo->Vis - : Info.Vis; - Diag(Loc, diag::err_hlsl_resource_range_overlap) - << llvm::to_underlying(Info.Class) << Info.LowerBound - << Info.UpperBound << llvm::to_underlying(OInfo->Class) - << OInfo->LowerBound << OInfo->UpperBound << Info.Space << CommonVis; + // Create a ResourceRange for each Visibility + ResourceRange::MapT::Allocator Allocator; + SmallVector<ResourceRange, 8> Ranges = { + ResourceRange(Allocator), // All + ResourceRange(Allocator), // Vertex + ResourceRange(Allocator), // Hull + ResourceRange(Allocator), // Domain + ResourceRange(Allocator), // Geometry + ResourceRange(Allocator), // Pixel + ResourceRange(Allocator), // Amplification + ResourceRange(Allocator), // Mesh + }; + + // Reset the ResourceRanges for when we iterate through a new group + auto ClearRanges = [&Ranges]() { + for (ResourceRange &Range : Ranges) + Range.clear(); + }; - HadOverlap = true; + // Helper to report diagnostics + auto ReportOverlap = [this, Loc, &HadOverlap](const RangeInfo *Info, + const RangeInfo *OInfo) { + HadOverlap = true; + auto CommonVis = Info->Vis == llvm::hlsl::rootsig::ShaderVisibility::All + ? OInfo->Vis + : Info->Vis; + this->Diag(Loc, diag::err_hlsl_resource_range_overlap) + << llvm::to_underlying(Info->Class) << Info->LowerBound + << Info->UpperBound << llvm::to_underlying(OInfo->Class) + << OInfo->LowerBound << OInfo->UpperBound << Info->Space << CommonVis; + }; + + // 3: Iterate throught collected RangeInfos + for (const RangeInfo &Info : Infos) { + GroupT InfoGroup = {Info.Class, Info.Space}; + // Reset our ResourceRanges when we enter a new group + if (CurGroup != InfoGroup) { + ClearRanges(); + CurGroup = InfoGroup; } + // 3A: Insert range info into corresponding Visibility ResourceRange + ResourceRange &VisRange = Ranges[llvm::to_underlying(Info.Vis)]; + if (auto Overlapping = VisRange.insert(Info)) + ReportOverlap(&Info, Overlapping.value()); + + // 3B: Check for overlap in all overlapping Visibility ResourceRanges + // + // If the range that we are inserting has ShaderVisiblity::All it needs to + // check for an overlap in all other visibility types as well. + // Otherwise, the range that is inserted needs to check that it does not + // overlap with ShaderVisibility::All. + // + // Maps will be an ArrayRef to all non-all visibility RangeMaps in the + // former case and it will be an ArrayRef to just the all visiblity + // RangeMap in the latter case. + MutableArrayRef<ResourceRange> OverlapRanges = + Info.Vis == llvm::hlsl::rootsig::ShaderVisibility::All + ? MutableArrayRef<ResourceRange>{Ranges}.drop_front() + : MutableArrayRef<ResourceRange>{Ranges}.take_front(); + + for (ResourceRange &Range : OverlapRanges) + if (auto Overlapping = Range.getOverlapping(Info)) + ReportOverlap(&Info, Overlapping.value()); + } + return HadOverlap; } diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h index 8a3e2ea63891a..f3be3bd0b915c 100644 --- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h +++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h @@ -102,6 +102,9 @@ class ResourceRange { // Return the mapped RangeInfo at X or nullptr if no mapping exists const RangeInfo *lookup(uint32_t X) const; + // Removes all entries of the ResourceRange + void clear(); + // Insert the required (sub-)intervals such that the interval of [a;b] = // [Info.LowerBound, Info.UpperBound] is covered and points to a valid // RangeInfo &. diff --git a/llvm/lib/Frontend/HLSL/HLSLRootSignatureUtils.cpp b/llvm/lib/Frontend/HLSL/HLSLRootSignatureUtils.cpp index a1ddb318055be..f95c141c54d8d 100644 --- a/llvm/lib/Frontend/HLSL/HLSLRootSignatureUtils.cpp +++ b/llvm/lib/Frontend/HLSL/HLSLRootSignatureUtils.cpp @@ -509,6 +509,8 @@ const RangeInfo *ResourceRange::lookup(uint32_t X) const { return Intervals.lookup(X, nullptr); } +void ResourceRange::clear() { return Intervals.clear(); } + std::optional<const RangeInfo *> ResourceRange::insert(const RangeInfo &Info) { uint32_t LowerBound = Info.LowerBound; uint32_t UpperBound = Info.UpperBound; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits