[clang] [Clang][HLSL] Add environment parameter to availability attribute (PR #89809)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Apr 25 17:39:09 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-x86
Author: Helena Kotas (hekota)
<details>
<summary>Changes</summary>
Add `environment` parameter to Clang availability attribute. The allowed values for this parameter are a subset of values allowed in the `llvm::Triple` environment component. If the `environment` parameters is present, the declared availability attribute applies only to targets with the same platform and environment.
This new parameter will be initially used for annotating HLSL functions for the `shadermodel` platform because in HLSL built-in function availability can depend not just on the shader model version (mapped to `llvm::Triple::OSType`) but also on the target shader stage (mapped to `llvm::Triple::EnvironmentType`). See example in #<!-- -->89802 and microsoft/hlsl-specs#<!-- -->204 for more details.
Fixes #<!-- -->89802
---
Patch is 42.70 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/89809.diff
19 Files Affected:
- (modified) clang/include/clang/Basic/Attr.td (+30-3)
- (modified) clang/include/clang/Basic/AttrDocs.td (+5)
- (modified) clang/include/clang/Basic/DiagnosticParseKinds.td (+2)
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+5-2)
- (modified) clang/include/clang/Parse/Parser.h (+3)
- (modified) clang/include/clang/Sema/ParsedAttr.h (+28-14)
- (modified) clang/include/clang/Sema/Sema.h (+8-7)
- (modified) clang/lib/AST/DeclBase.cpp (+22-6)
- (modified) clang/lib/Headers/hlsl/hlsl_intrinsics.h (+11-4)
- (modified) clang/lib/Index/CommentToXML.cpp (+6)
- (modified) clang/lib/Parse/ParseDecl.cpp (+19-1)
- (modified) clang/lib/Sema/SemaAPINotes.cpp (+2-1)
- (modified) clang/lib/Sema/SemaAvailability.cpp (+81-33)
- (modified) clang/lib/Sema/SemaDecl.cpp (+1-1)
- (modified) clang/lib/Sema/SemaDeclAttr.cpp (+30-9)
- (modified) clang/test/Parser/attr-availability.c (+4)
- (modified) clang/test/SemaHLSL/AvailabilityMarkup.hlsl (+4-4)
- (added) clang/test/SemaHLSL/AvailabilityMarkupStages.hlsl (+44)
- (modified) clang/test/SemaHLSL/WaveBuiltinAvailability.hlsl (+2-2)
``````````diff
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 4408d517e70e58..251a2cf04e37d7 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -956,7 +956,7 @@ def Availability : InheritableAttr {
VersionArgument<"deprecated">, VersionArgument<"obsoleted">,
BoolArgument<"unavailable">, StringArgument<"message">,
BoolArgument<"strict">, StringArgument<"replacement">,
- IntArgument<"priority">];
+ IntArgument<"priority">, IdentifierArgument<"environment">];
let AdditionalMembers =
[{static llvm::StringRef getPrettyPlatformName(llvm::StringRef Platform) {
return llvm::StringSwitch<llvm::StringRef>(Platform)
@@ -976,7 +976,7 @@ def Availability : InheritableAttr {
.Case("xros", "visionOS")
.Case("xros_app_extension", "visionOS (App Extension)")
.Case("swift", "Swift")
- .Case("shadermodel", "HLSL ShaderModel")
+ .Case("shadermodel", "Shader Model")
.Case("ohos", "OpenHarmony OS")
.Default(llvm::StringRef());
}
@@ -1016,7 +1016,34 @@ static llvm::StringRef canonicalizePlatformName(llvm::StringRef Platform) {
.Case("visionos_app_extension", "xros_app_extension")
.Case("ShaderModel", "shadermodel")
.Default(Platform);
-} }];
+}
+static llvm::StringRef getPrettyEnviromentName(llvm::StringRef Environment) {
+ return llvm::StringSwitch<llvm::StringRef>(Environment)
+ .Case("pixel", "pixel shader")
+ .Case("vertex", "vertex shader")
+ .Case("geometry", "geometry shader")
+ .Case("hull", "hull shader")
+ .Case("domain", "domain shader")
+ .Case("compute", "compute shader")
+ .Case("mesh", "mesh shader")
+ .Case("amplification", "amplification shader")
+ .Case("library", "shader library")
+ .Default(Environment);
+}
+static llvm::Triple::EnvironmentType getEnvironmentType(llvm::StringRef Environment) {
+ return llvm::StringSwitch<llvm::Triple::EnvironmentType>(Environment)
+ .Case("pixel", llvm::Triple::Pixel)
+ .Case("vertex", llvm::Triple::Vertex)
+ .Case("geometry", llvm::Triple::Geometry)
+ .Case("hull", llvm::Triple::Hull)
+ .Case("domain", llvm::Triple::Domain)
+ .Case("compute", llvm::Triple::Compute)
+ .Case("mesh", llvm::Triple::Mesh)
+ .Case("amplification", llvm::Triple::Amplification)
+ .Case("library", llvm::Triple::Library)
+ .Default(llvm::Triple::UnknownEnvironment);
+}
+}];
let HasCustomParsing = 1;
let InheritEvenIfAlreadyPresent = 1;
let Subjects = SubjectList<[Named]>;
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index a0bbe5861c5722..9c2f3f9e833a54 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -1593,6 +1593,11 @@ replacement=\ *string-literal*
a warning about use of a deprecated declaration. The Fix-It will replace
the deprecated declaration with the new declaration specified.
+environment=\ *identifier*
+ Target environment in which this declaration is available. If present,
+ the availability attribute applies only to targets with the same platform
+ and environment.
+
Multiple availability attributes can be placed on a declaration, which may
correspond to different platforms. For most platforms, the availability
attribute with the platform corresponding to the target platform will be used;
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 38174cf3549f14..31309b8cd70679 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1103,6 +1103,8 @@ def err_zero_version : Error<
"version number must have non-zero major, minor, or sub-minor version">;
def err_availability_expected_platform : Error<
"expected a platform name, e.g., 'macos'">;
+def err_availability_expected_environment : Error<
+ "expected an environment name, e.g., 'compute'">;
// objc_bridge_related attribute
def err_objcbridge_related_expected_related_class : Error<
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index fdca82934cb4dc..d59615cccb341c 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3827,6 +3827,9 @@ def note_cannot_use_trivial_abi_reason : Note<
// Availability attribute
def warn_availability_unknown_platform : Warning<
"unknown platform %0 in availability macro">, InGroup<Availability>;
+def warn_availability_unknown_environment : Warning<
+ "unknown environment %0 in availability macro">, InGroup<Availability>;
+
def warn_availability_version_ordering : Warning<
"feature cannot be %select{introduced|deprecated|obsoleted}0 in %1 version "
"%2 before it was %select{introduced|deprecated|obsoleted}3 in version %4; "
@@ -3859,7 +3862,7 @@ def warn_availability_fuchsia_unavailable_minor : Warning<
InGroup<Availability>;
def warn_unguarded_availability :
- Warning<"%0 is only available on %1 %2 or newer">,
+ Warning<"%0 %select{is only|is not}5 available %select{|in %4 environment }3on %1 %2 %select{or newer|}5">,
InGroup<UnguardedAvailability>, DefaultIgnore;
def warn_unguarded_availability_new :
Warning<warn_unguarded_availability.Summary>,
@@ -5855,7 +5858,7 @@ def note_availability_specified_here : Note<
"%0 has been explicitly marked "
"%select{unavailable|deleted|deprecated}1 here">;
def note_partial_availability_specified_here : Note<
- "%0 has been marked as being introduced in %1 %2 here, "
+ "%0 has been marked as being introduced in %1 %2 %select{|in %5 environment }4here, "
"but the deployment target is %1 %3">;
def note_implicitly_deleted : Note<
"explicitly defaulted function was implicitly deleted here">;
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index fb117bf04087ee..695ea4d7de0d90 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -151,6 +151,9 @@ class Parser : public CodeCompletionHandler {
/// Identifier for "replacement".
IdentifierInfo *Ident_replacement;
+ /// Identifier for "environment".
+ IdentifierInfo *Ident_environment;
+
/// Identifiers used by the 'external_source_symbol' attribute.
IdentifierInfo *Ident_language, *Ident_defined_in,
*Ident_generated_declaration, *Ident_USR;
diff --git a/clang/include/clang/Sema/ParsedAttr.h b/clang/include/clang/Sema/ParsedAttr.h
index 25a5fa05b21c7d..a2b35e71795cd5 100644
--- a/clang/include/clang/Sema/ParsedAttr.h
+++ b/clang/include/clang/Sema/ParsedAttr.h
@@ -40,6 +40,7 @@ class LangOptions;
class Sema;
class Stmt;
class TargetInfo;
+struct IdentifierLoc;
/// Represents information about a change in availability for
/// an entity, which is part of the encoding of the 'availability'
@@ -68,12 +69,14 @@ struct AvailabilityData {
AvailabilityChange Changes[NumAvailabilitySlots];
SourceLocation StrictLoc;
const Expr *Replacement;
+ const IdentifierLoc *EnvironmentLoc;
AvailabilityData(const AvailabilityChange &Introduced,
const AvailabilityChange &Deprecated,
- const AvailabilityChange &Obsoleted,
- SourceLocation Strict, const Expr *ReplaceExpr)
- : StrictLoc(Strict), Replacement(ReplaceExpr) {
+ const AvailabilityChange &Obsoleted, SourceLocation Strict,
+ const Expr *ReplaceExpr, const IdentifierLoc *EnvironmentLoc)
+ : StrictLoc(Strict), Replacement(ReplaceExpr),
+ EnvironmentLoc(EnvironmentLoc) {
Changes[IntroducedSlot] = Introduced;
Changes[DeprecatedSlot] = Deprecated;
Changes[ObsoletedSlot] = Obsoleted;
@@ -234,7 +237,7 @@ class ParsedAttr final
const AvailabilityChange &deprecated,
const AvailabilityChange &obsoleted, SourceLocation unavailable,
const Expr *messageExpr, Form formUsed, SourceLocation strict,
- const Expr *replacementExpr)
+ const Expr *replacementExpr, const IdentifierLoc *environmentLoc)
: AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc, formUsed),
NumArgs(1), Invalid(false), UsedAsTypeAttr(false), IsAvailability(true),
IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false),
@@ -243,8 +246,9 @@ class ParsedAttr final
Info(ParsedAttrInfo::get(*this)) {
ArgsUnion PVal(Parm);
memcpy(getArgsBuffer(), &PVal, sizeof(ArgsUnion));
- new (getAvailabilityData()) detail::AvailabilityData(
- introduced, deprecated, obsoleted, strict, replacementExpr);
+ new (getAvailabilityData())
+ detail::AvailabilityData(introduced, deprecated, obsoleted, strict,
+ replacementExpr, environmentLoc);
}
/// Constructor for objc_bridge_related attributes.
@@ -445,6 +449,12 @@ class ParsedAttr final
return getAvailabilityData()->Replacement;
}
+ const IdentifierLoc *getEnvironment() const {
+ assert(getParsedKind() == AT_Availability &&
+ "Not an availability attribute");
+ return getAvailabilityData()->EnvironmentLoc;
+ }
+
const ParsedType &getMatchingCType() const {
assert(getParsedKind() == AT_TypeTagForDatatype &&
"Not a type_tag_for_datatype attribute");
@@ -759,11 +769,13 @@ class AttributePool {
const AvailabilityChange &obsoleted,
SourceLocation unavailable, const Expr *MessageExpr,
ParsedAttr::Form form, SourceLocation strict,
- const Expr *ReplacementExpr) {
+ const Expr *ReplacementExpr,
+ IdentifierLoc *EnvironmentLoc) {
void *memory = allocate(AttributeFactory::AvailabilityAllocSize);
- return add(new (memory) ParsedAttr(
- attrName, attrRange, scopeName, scopeLoc, Param, introduced, deprecated,
- obsoleted, unavailable, MessageExpr, form, strict, ReplacementExpr));
+ return add(new (memory) ParsedAttr(attrName, attrRange, scopeName, scopeLoc,
+ Param, introduced, deprecated, obsoleted,
+ unavailable, MessageExpr, form, strict,
+ ReplacementExpr, EnvironmentLoc));
}
ParsedAttr *create(IdentifierInfo *attrName, SourceRange attrRange,
@@ -993,10 +1005,12 @@ class ParsedAttributes : public ParsedAttributesView {
const AvailabilityChange &obsoleted,
SourceLocation unavailable, const Expr *MessageExpr,
ParsedAttr::Form form, SourceLocation strict,
- const Expr *ReplacementExpr) {
- ParsedAttr *attr = pool.create(
- attrName, attrRange, scopeName, scopeLoc, Param, introduced, deprecated,
- obsoleted, unavailable, MessageExpr, form, strict, ReplacementExpr);
+ const Expr *ReplacementExpr,
+ IdentifierLoc *EnvironmentLoc) {
+ ParsedAttr *attr =
+ pool.create(attrName, attrRange, scopeName, scopeLoc, Param, introduced,
+ deprecated, obsoleted, unavailable, MessageExpr, form,
+ strict, ReplacementExpr, EnvironmentLoc);
addAtEnd(attr);
return attr;
}
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index aa182b15e66ecc..c511c018ba9a25 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -39,6 +39,7 @@
#include "clang/Basic/Cuda.h"
#include "clang/Basic/DarwinSDKInfo.h"
#include "clang/Basic/ExpressionTraits.h"
+#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/OpenCLOptions.h"
#include "clang/Basic/PragmaKinds.h"
@@ -3618,13 +3619,13 @@ class Sema final : public SemaBase {
bool CheckAttrTarget(const ParsedAttr &CurrAttr);
bool CheckAttrNoArgs(const ParsedAttr &CurrAttr);
- AvailabilityAttr *
- mergeAvailabilityAttr(NamedDecl *D, const AttributeCommonInfo &CI,
- IdentifierInfo *Platform, bool Implicit,
- VersionTuple Introduced, VersionTuple Deprecated,
- VersionTuple Obsoleted, bool IsUnavailable,
- StringRef Message, bool IsStrict, StringRef Replacement,
- AvailabilityMergeKind AMK, int Priority);
+ AvailabilityAttr *mergeAvailabilityAttr(
+ NamedDecl *D, const AttributeCommonInfo &CI, IdentifierInfo *Platform,
+ bool Implicit, VersionTuple Introduced, VersionTuple Deprecated,
+ VersionTuple Obsoleted, bool IsUnavailable, StringRef Message,
+ bool IsStrict, StringRef Replacement, AvailabilityMergeKind AMK,
+ int Priority, IdentifierInfo *IIEnvironment);
+
TypeVisibilityAttr *
mergeTypeVisibilityAttr(Decl *D, const AttributeCommonInfo &CI,
TypeVisibilityAttr::VisibilityType Vis);
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index c33babf8d1df3b..6210d715adea83 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -666,12 +666,28 @@ static AvailabilityResult CheckAvailability(ASTContext &Context,
// Make sure that this declaration has already been introduced.
if (!A->getIntroduced().empty() &&
EnclosingVersion < A->getIntroduced()) {
- if (Message) {
- Message->clear();
- llvm::raw_string_ostream Out(*Message);
- VersionTuple VTI(A->getIntroduced());
- Out << "introduced in " << PrettyPlatformName << ' '
- << VTI << HintMessage;
+ IdentifierInfo *IIEnv = A->getEnvironment();
+ StringRef TargetEnv =
+ Context.getTargetInfo().getTriple().getEnvironmentName();
+ StringRef EnvName = AvailabilityAttr::getPrettyEnviromentName(TargetEnv);
+ // Matching environment or no environment on attribute
+ if (!IIEnv || (!TargetEnv.empty() && IIEnv->getName() == TargetEnv)) {
+ if (Message) {
+ Message->clear();
+ llvm::raw_string_ostream Out(*Message);
+ VersionTuple VTI(A->getIntroduced());
+ Out << "introduced in " << PrettyPlatformName << " " << VTI << EnvName
+ << HintMessage;
+ }
+ }
+ // Non-matching environment or no environment on target
+ else {
+ if (Message) {
+ Message->clear();
+ llvm::raw_string_ostream Out(*Message);
+ Out << "not available on " << PrettyPlatformName << " " << EnvName
+ << HintMessage;
+ }
}
return A->getStrict() ? AR_Unavailable : AR_NotYetIntroduced;
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index 06409c6fc77417..6880e26600d0bb 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -18,14 +18,21 @@ namespace hlsl {
#define _HLSL_BUILTIN_ALIAS(builtin) \
__attribute__((clang_builtin_alias(builtin)))
-#define _HLSL_AVAILABILITY(environment, version) \
- __attribute__((availability(environment, introduced = version)))
+#define _HLSL_AVAILABILITY(platform, version) \
+ __attribute__((availability(platform, introduced = version)))
+#define _HLSL_AVAILABILITY_STAGE(platform, version, stage) \
+ __attribute__(( \
+ availability(platform, introduced = version, environment = stage)))
#ifdef __HLSL_ENABLE_16_BIT
-#define _HLSL_16BIT_AVAILABILITY(environment, version) \
- __attribute__((availability(environment, introduced = version)))
+#define _HLSL_16BIT_AVAILABILITY(platform, version) \
+ __attribute__((availability(platform, introduced = version)))
+#define _HLSL_16BIT_AVAILABILITY_STAGE(platform, version, stage) \
+ __attribute__(( \
+ availability(platform, introduced = version, environment = stage)))
#else
#define _HLSL_16BIT_AVAILABILITY(environment, version)
+#define _HLSL_16BIT_AVAILABILITY_STAGE(environment, version, stage)
#endif
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Index/CommentToXML.cpp b/clang/lib/Index/CommentToXML.cpp
index 295f3f228ff79b..3372fbba438317 100644
--- a/clang/lib/Index/CommentToXML.cpp
+++ b/clang/lib/Index/CommentToXML.cpp
@@ -12,6 +12,7 @@
#include "clang/AST/Comment.h"
#include "clang/AST/CommentVisitor.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Format/Format.h"
#include "clang/Index/USRGeneration.h"
@@ -1052,6 +1053,11 @@ void CommentASTToXMLConverter::visitFullComment(const FullComment *C) {
}
if (AA->getUnavailable())
Result << "<Unavailable/>";
+
+ IdentifierInfo *Environment = AA->getEnvironment();
+ if (Environment) {
+ Result << "<Environment>" << Environment->getName() << "</Environment>";
+ }
Result << "</Availability>";
}
}
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 53a33fa4add54e..839098f5267e0e 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -1224,6 +1224,7 @@ void Parser::ParseAvailabilityAttribute(
enum { Introduced, Deprecated, Obsoleted, Unknown };
AvailabilityChange Changes[Unknown];
ExprResult MessageExpr, ReplacementExpr;
+ IdentifierLoc *EnvironmentLoc = nullptr;
// Opening '('.
BalancedDelimiterTracker T(*this, tok::l_paren);
@@ -1271,6 +1272,7 @@ void Parser::ParseAvailabilityAttribute(
Ident_message = PP.getIdentifierInfo("message");
Ident_strict = PP.getIdentifierInfo("strict");
Ident_replacement = PP.getIdentifierInfo("replacement");
+ Ident_environment = PP.getIdentifierInfo("environment");
}
// Parse the optional "strict", the optional "replacement" and the set of
@@ -1318,6 +1320,13 @@ void Parser::ParseAvailabilityAttribute(
continue;
}
+ if (Keyword == Ident_environment) {
+ if (EnvironmentLoc != nullptr) {
+ Diag(KeywordLoc, diag::err_availability_redundant)
+ << Keyword << SourceRange(EnvironmentLoc->Loc);
+ }
+ }
+
if (Tok.isNot(tok::equal)) {
Diag(Tok, diag::err_expected_after) << Keyword << tok::equal;
SkipUntil(tok::r_paren, StopAtSemi);
@@ -1339,6 +1348,15 @@ void Parser::ParseAvailabilityAttribute(
continue;
}
}
+ if (Keyword == Ident_environment) {
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_availability_expected_environment);
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return;
+ }
+ EnvironmentLoc = ParseIdentifierLoc();
+ continue;
+ }
// Special handling of 'NA' only when applied to introduced or
// deprecated.
@@ -1420,7 +1438,7 @@ void Parser::ParseAvailabilityAttribute(
SourceRange(AvailabilityLoc, T.getCloseLocation()), ScopeName,
ScopeLoc, Platform, Changes[Introduced], Changes[Deprecated],
Changes[Obsoleted], UnavailableLoc, MessageExpr.get(), Form,
- StrictLoc, ReplacementExpr.get());
+ StrictLoc, ReplacementExpr.get(), EnvironmentLoc);
}
/// Parse the contents of the "external_source_symbol" attribute.
diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
index 4c445f28bba8c6..b904fa0b04448c 100644
--- a/clang/lib/Sema/SemaAPINotes.cpp
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -268,7 +268,8 @@ static void ProcessAPINotes(Sema &S, Decl *D,
ASTAllocateString(S.Context, Info.UnavailableMsg),
/*Strict=*/false,
/*Replacement=*/StringRef(),
- /*Priority=*/Sema::AP_Explicit);
+ /*Priority=*/Sema::AP_Explicit,
+ /*...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/89809
More information about the cfe-commits
mailing list