Skip to content

Commit 57e1846

Browse files
authored
[HLSL] Rewrite semantics parsing (#152537)
This is the first PR to implement the semantics proposal: https://github.com/llvm/wg-hlsl/blob/main/proposals/0031-semantics.md This PR focuses on the changes required to handle user semantics, but tried to be almost NFC. What changes is the error messages as the semantics case is not kept when reporting error messages. You might notice the SV_GroupIndex semantic is not properly validated as are others. This is an existing behavior that we'll need to fix, but wanted to keep this separated from this rewrite to stay as-close as an NFC as possible. The next PR will add support on the different kinds of I/O we can have using semantics (input, inout param, structs).
1 parent 80c2da6 commit 57e1846

22 files changed

+419
-128
lines changed

clang/include/clang/AST/Attr.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,40 @@ class HLSLAnnotationAttr : public InheritableAttr {
232232
}
233233
};
234234

235+
class HLSLSemanticAttr : public HLSLAnnotationAttr {
236+
unsigned SemanticIndex = 0;
237+
LLVM_PREFERRED_TYPE(bool)
238+
unsigned SemanticIndexable : 1;
239+
LLVM_PREFERRED_TYPE(bool)
240+
unsigned SemanticExplicitIndex : 1;
241+
242+
protected:
243+
HLSLSemanticAttr(ASTContext &Context, const AttributeCommonInfo &CommonInfo,
244+
attr::Kind AK, bool IsLateParsed,
245+
bool InheritEvenIfAlreadyPresent, bool SemanticIndexable)
246+
: HLSLAnnotationAttr(Context, CommonInfo, AK, IsLateParsed,
247+
InheritEvenIfAlreadyPresent) {
248+
this->SemanticIndexable = SemanticIndexable;
249+
this->SemanticExplicitIndex = false;
250+
}
251+
252+
public:
253+
bool isSemanticIndexable() const { return SemanticIndexable; }
254+
255+
void setSemanticIndex(unsigned SemanticIndex) {
256+
this->SemanticIndex = SemanticIndex;
257+
this->SemanticExplicitIndex = true;
258+
}
259+
260+
unsigned getSemanticIndex() const { return SemanticIndex; }
261+
262+
// Implement isa/cast/dyncast/etc.
263+
static bool classof(const Attr *A) {
264+
return A->getKind() >= attr::FirstHLSLSemanticAttr &&
265+
A->getKind() <= attr::LastHLSLSemanticAttr;
266+
}
267+
};
268+
235269
/// A parameter attribute which changes the argument-passing ABI rule
236270
/// for the parameter.
237271
class ParameterABIAttr : public InheritableParamAttr {

clang/include/clang/Basic/Attr.td

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,16 @@ class DeclOrStmtAttr : InheritableAttr;
779779
/// An attribute class for HLSL Annotations.
780780
class HLSLAnnotationAttr : InheritableAttr;
781781

782+
class HLSLSemanticAttr<bit Indexable> : HLSLAnnotationAttr {
783+
bit SemanticIndexable = Indexable;
784+
int SemanticIndex = 0;
785+
bit SemanticExplicitIndex = 0;
786+
787+
let Spellings = [];
788+
let Subjects = SubjectList<[ParmVar, Field, Function]>;
789+
let LangOpts = [HLSL];
790+
}
791+
782792
/// A target-specific attribute. This class is meant to be used as a mixin
783793
/// with InheritableAttr or Attr depending on the attribute's needs.
784794
class TargetSpecificAttr<TargetSpec target> {
@@ -4889,27 +4899,6 @@ def HLSLNumThreads: InheritableAttr {
48894899
let Documentation = [NumThreadsDocs];
48904900
}
48914901

4892-
def HLSLSV_GroupThreadID: HLSLAnnotationAttr {
4893-
let Spellings = [HLSLAnnotation<"sv_groupthreadid">];
4894-
let Subjects = SubjectList<[ParmVar, Field]>;
4895-
let LangOpts = [HLSL];
4896-
let Documentation = [HLSLSV_GroupThreadIDDocs];
4897-
}
4898-
4899-
def HLSLSV_GroupID: HLSLAnnotationAttr {
4900-
let Spellings = [HLSLAnnotation<"sv_groupid">];
4901-
let Subjects = SubjectList<[ParmVar, Field]>;
4902-
let LangOpts = [HLSL];
4903-
let Documentation = [HLSLSV_GroupIDDocs];
4904-
}
4905-
4906-
def HLSLSV_GroupIndex: HLSLAnnotationAttr {
4907-
let Spellings = [HLSLAnnotation<"sv_groupindex">];
4908-
let Subjects = SubjectList<[ParmVar, GlobalVar]>;
4909-
let LangOpts = [HLSL];
4910-
let Documentation = [HLSLSV_GroupIndexDocs];
4911-
}
4912-
49134902
def HLSLVkBinding : InheritableAttr {
49144903
let Spellings = [CXX11<"vk", "binding">];
49154904
let Subjects = SubjectList<[HLSLBufferObj, ExternalGlobalVar], ErrorDiag>;
@@ -4968,13 +4957,35 @@ def HLSLResourceBinding: InheritableAttr {
49684957
}];
49694958
}
49704959

4971-
def HLSLSV_Position : HLSLAnnotationAttr {
4972-
let Spellings = [HLSLAnnotation<"sv_position">];
4973-
let Subjects = SubjectList<[ParmVar, Field]>;
4960+
def HLSLUnparsedSemantic : HLSLAnnotationAttr {
4961+
let Spellings = [];
4962+
let Args = [DefaultIntArgument<"Index", 0>,
4963+
DefaultBoolArgument<"ExplicitIndex", 0>];
4964+
let Subjects = SubjectList<[ParmVar, Field, Function]>;
49744965
let LangOpts = [HLSL];
4966+
let Documentation = [InternalOnly];
4967+
}
4968+
4969+
def HLSLSV_Position : HLSLSemanticAttr</* Indexable= */ 1> {
49754970
let Documentation = [HLSLSV_PositionDocs];
49764971
}
49774972

4973+
def HLSLSV_GroupThreadID : HLSLSemanticAttr</* Indexable= */ 0> {
4974+
let Documentation = [HLSLSV_GroupThreadIDDocs];
4975+
}
4976+
4977+
def HLSLSV_GroupID : HLSLSemanticAttr</* Indexable= */ 0> {
4978+
let Documentation = [HLSLSV_GroupIDDocs];
4979+
}
4980+
4981+
def HLSLSV_GroupIndex : HLSLSemanticAttr</* Indexable= */ 0> {
4982+
let Documentation = [HLSLSV_GroupIndexDocs];
4983+
}
4984+
4985+
def HLSLSV_DispatchThreadID : HLSLSemanticAttr</* Indexable= */ 0> {
4986+
let Documentation = [HLSLSV_DispatchThreadIDDocs];
4987+
}
4988+
49784989
def HLSLPackOffset: HLSLAnnotationAttr {
49794990
let Spellings = [HLSLAnnotation<"packoffset">];
49804991
let LangOpts = [HLSL];
@@ -4987,13 +4998,6 @@ def HLSLPackOffset: HLSLAnnotationAttr {
49874998
}];
49884999
}
49895000

4990-
def HLSLSV_DispatchThreadID: HLSLAnnotationAttr {
4991-
let Spellings = [HLSLAnnotation<"sv_dispatchthreadid">];
4992-
let Subjects = SubjectList<[ParmVar, Field]>;
4993-
let LangOpts = [HLSL];
4994-
let Documentation = [HLSLSV_DispatchThreadIDDocs];
4995-
}
4996-
49975001
def HLSLShader : InheritableAttr {
49985002
let Spellings = [Microsoft<"shader">];
49995003
let Subjects = SubjectList<[HLSLEntry]>;

clang/include/clang/Basic/DiagnosticFrontendKinds.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,10 @@ def warn_hlsl_langstd_minimal :
400400
"recommend using %1 instead">,
401401
InGroup<HLSLDXCCompat>;
402402

403+
def err_hlsl_semantic_missing : Error<"semantic annotations must be present "
404+
"for all input and outputs of an entry "
405+
"function or patch constant function">;
406+
403407
// ClangIR frontend errors
404408
def err_cir_to_cir_transform_failed : Error<
405409
"CIR-to-CIR transformation failed">, DefaultFatal;

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1860,9 +1860,8 @@ def note_max_tokens_total_override : Note<"total token limit set here">;
18601860

18611861
def err_expected_semantic_identifier : Error<
18621862
"expected HLSL Semantic identifier">;
1863-
def err_invalid_declaration_in_hlsl_buffer : Error<
1864-
"invalid declaration inside %select{tbuffer|cbuffer}0">;
1865-
def err_unknown_hlsl_semantic : Error<"unknown HLSL semantic %0">;
1863+
def err_invalid_declaration_in_hlsl_buffer
1864+
: Error<"invalid declaration inside %select{tbuffer|cbuffer}0">;
18661865
def err_hlsl_separate_attr_arg_and_number : Error<"wrong argument format for hlsl attribute, use %0 instead">;
18671866
def ext_hlsl_access_specifiers : ExtWarn<
18681867
"access specifiers are a clang HLSL extension">,

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13121,6 +13121,11 @@ def err_hlsl_duplicate_parameter_modifier : Error<"duplicate parameter modifier
1312113121
def err_hlsl_missing_semantic_annotation : Error<
1312213122
"semantic annotations must be present for all parameters of an entry "
1312313123
"function or patch constant function">;
13124+
def err_hlsl_unknown_semantic : Error<"unknown HLSL semantic %0">;
13125+
def err_hlsl_semantic_output_not_supported
13126+
: Error<"semantic %0 does not support output">;
13127+
def err_hlsl_semantic_indexing_not_supported
13128+
: Error<"semantic %0 does not allow indexing">;
1312413129
def err_hlsl_init_priority_unsupported : Error<
1312513130
"initializer priorities are not supported in HLSL">;
1312613131

clang/include/clang/Parse/Parser.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5188,6 +5188,14 @@ class Parser : public CodeCompletionHandler {
51885188
ParseHLSLAnnotations(Attrs, EndLoc);
51895189
}
51905190

5191+
struct ParsedSemantic {
5192+
StringRef Name = "";
5193+
unsigned Index = 0;
5194+
bool Explicit = false;
5195+
};
5196+
5197+
ParsedSemantic ParseHLSLSemantic();
5198+
51915199
void ParseHLSLAnnotations(ParsedAttributes &Attrs,
51925200
SourceLocation *EndLoc = nullptr,
51935201
bool CouldBeBitField = false);

clang/include/clang/Sema/SemaHLSL.h

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "clang/AST/Attr.h"
1818
#include "clang/AST/Type.h"
1919
#include "clang/AST/TypeLoc.h"
20+
#include "clang/Basic/DiagnosticSema.h"
2021
#include "clang/Basic/SourceLocation.h"
2122
#include "clang/Sema/SemaBase.h"
2223
#include "llvm/ADT/SmallVector.h"
@@ -129,6 +130,7 @@ class SemaHLSL : public SemaBase {
129130
bool ActOnUninitializedVarDecl(VarDecl *D);
130131
void ActOnEndOfTranslationUnit(TranslationUnitDecl *TU);
131132
void CheckEntryPoint(FunctionDecl *FD);
133+
bool isSemanticValid(FunctionDecl *FD, DeclaratorDecl *D);
132134
void CheckSemanticAnnotation(FunctionDecl *EntryPoint, const Decl *Param,
133135
const HLSLAnnotationAttr *AnnotationAttr);
134136
void DiagnoseAttrStageMismatch(
@@ -166,16 +168,31 @@ class SemaHLSL : public SemaBase {
166168
void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL);
167169
void handleVkConstantIdAttr(Decl *D, const ParsedAttr &AL);
168170
void handleVkBindingAttr(Decl *D, const ParsedAttr &AL);
169-
void handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL);
170-
void handleSV_GroupThreadIDAttr(Decl *D, const ParsedAttr &AL);
171-
void handleSV_GroupIDAttr(Decl *D, const ParsedAttr &AL);
172-
void handleSV_PositionAttr(Decl *D, const ParsedAttr &AL);
173171
void handlePackOffsetAttr(Decl *D, const ParsedAttr &AL);
174172
void handleShaderAttr(Decl *D, const ParsedAttr &AL);
175173
void handleResourceBindingAttr(Decl *D, const ParsedAttr &AL);
176174
void handleParamModifierAttr(Decl *D, const ParsedAttr &AL);
177175
bool handleResourceTypeAttr(QualType T, const ParsedAttr &AL);
178176

177+
template <typename T>
178+
T *createSemanticAttr(const ParsedAttr &AL,
179+
std::optional<unsigned> Location) {
180+
T *Attr = ::new (getASTContext()) T(getASTContext(), AL);
181+
if (Attr->isSemanticIndexable())
182+
Attr->setSemanticIndex(Location ? *Location : 0);
183+
else if (Location.has_value()) {
184+
Diag(Attr->getLocation(), diag::err_hlsl_semantic_indexing_not_supported)
185+
<< Attr->getAttrName()->getName();
186+
return nullptr;
187+
}
188+
189+
return Attr;
190+
}
191+
192+
void diagnoseSystemSemanticAttr(Decl *D, const ParsedAttr &AL,
193+
std::optional<unsigned> Index);
194+
void handleSemanticAttr(Decl *D, const ParsedAttr &AL);
195+
179196
void handleVkExtBuiltinInputAttr(Decl *D, const ParsedAttr &AL);
180197

181198
bool CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);

clang/lib/Basic/Attributes.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,12 @@ AttributeCommonInfo::Kind
189189
AttributeCommonInfo::getParsedKind(const IdentifierInfo *Name,
190190
const IdentifierInfo *ScopeName,
191191
Syntax SyntaxUsed) {
192-
return ::getAttrKind(normalizeName(Name, ScopeName, SyntaxUsed), SyntaxUsed);
192+
AttributeCommonInfo::Kind Kind =
193+
::getAttrKind(normalizeName(Name, ScopeName, SyntaxUsed), SyntaxUsed);
194+
if (SyntaxUsed == AS_HLSLAnnotation &&
195+
Kind == AttributeCommonInfo::Kind::UnknownAttribute)
196+
return AttributeCommonInfo::Kind::AT_HLSLUnparsedSemantic;
197+
return Kind;
193198
}
194199

195200
AttributeCommonInfo::AttrArgsInfo

clang/lib/CodeGen/CGHLSLRuntime.cpp

Lines changed: 53 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "clang/AST/RecursiveASTVisitor.h"
2424
#include "clang/AST/Type.h"
2525
#include "clang/Basic/TargetOptions.h"
26+
#include "clang/Frontend/FrontendDiagnostic.h"
2627
#include "llvm/ADT/SmallString.h"
2728
#include "llvm/ADT/SmallVector.h"
2829
#include "llvm/Frontend/HLSL/RootSignatureMetadata.h"
@@ -552,47 +553,78 @@ static llvm::Value *createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M,
552553
return B.CreateLoad(Ty, GV);
553554
}
554555

555-
llvm::Value *CGHLSLRuntime::emitInputSemantic(IRBuilder<> &B,
556-
const ParmVarDecl &D,
557-
llvm::Type *Ty) {
558-
assert(D.hasAttrs() && "Entry parameter missing annotation attribute!");
559-
if (D.hasAttr<HLSLSV_GroupIndexAttr>()) {
556+
llvm::Value *
557+
CGHLSLRuntime::emitSystemSemanticLoad(IRBuilder<> &B, llvm::Type *Type,
558+
const clang::DeclaratorDecl *Decl,
559+
SemanticInfo &ActiveSemantic) {
560+
if (isa<HLSLSV_GroupIndexAttr>(ActiveSemantic.Semantic)) {
560561
llvm::Function *GroupIndex =
561562
CGM.getIntrinsic(getFlattenedThreadIdInGroupIntrinsic());
562563
return B.CreateCall(FunctionCallee(GroupIndex));
563564
}
564-
if (D.hasAttr<HLSLSV_DispatchThreadIDAttr>()) {
565+
566+
if (isa<HLSLSV_DispatchThreadIDAttr>(ActiveSemantic.Semantic)) {
565567
llvm::Intrinsic::ID IntrinID = getThreadIdIntrinsic();
566568
llvm::Function *ThreadIDIntrinsic =
567569
llvm::Intrinsic::isOverloaded(IntrinID)
568570
? CGM.getIntrinsic(IntrinID, {CGM.Int32Ty})
569571
: CGM.getIntrinsic(IntrinID);
570-
return buildVectorInput(B, ThreadIDIntrinsic, Ty);
572+
return buildVectorInput(B, ThreadIDIntrinsic, Type);
571573
}
572-
if (D.hasAttr<HLSLSV_GroupThreadIDAttr>()) {
574+
575+
if (isa<HLSLSV_GroupThreadIDAttr>(ActiveSemantic.Semantic)) {
573576
llvm::Intrinsic::ID IntrinID = getGroupThreadIdIntrinsic();
574577
llvm::Function *GroupThreadIDIntrinsic =
575578
llvm::Intrinsic::isOverloaded(IntrinID)
576579
? CGM.getIntrinsic(IntrinID, {CGM.Int32Ty})
577580
: CGM.getIntrinsic(IntrinID);
578-
return buildVectorInput(B, GroupThreadIDIntrinsic, Ty);
581+
return buildVectorInput(B, GroupThreadIDIntrinsic, Type);
579582
}
580-
if (D.hasAttr<HLSLSV_GroupIDAttr>()) {
583+
584+
if (isa<HLSLSV_GroupIDAttr>(ActiveSemantic.Semantic)) {
581585
llvm::Intrinsic::ID IntrinID = getGroupIdIntrinsic();
582586
llvm::Function *GroupIDIntrinsic =
583587
llvm::Intrinsic::isOverloaded(IntrinID)
584588
? CGM.getIntrinsic(IntrinID, {CGM.Int32Ty})
585589
: CGM.getIntrinsic(IntrinID);
586-
return buildVectorInput(B, GroupIDIntrinsic, Ty);
590+
return buildVectorInput(B, GroupIDIntrinsic, Type);
587591
}
588-
if (D.hasAttr<HLSLSV_PositionAttr>()) {
589-
if (getArch() == llvm::Triple::spirv)
590-
return createSPIRVBuiltinLoad(B, CGM.getModule(), Ty, "sv_position",
591-
/* BuiltIn::Position */ 0);
592-
llvm_unreachable("SV_Position semantic not implemented for this target.");
592+
593+
if (HLSLSV_PositionAttr *S =
594+
dyn_cast<HLSLSV_PositionAttr>(ActiveSemantic.Semantic)) {
595+
if (CGM.getTriple().getEnvironment() == Triple::EnvironmentType::Pixel)
596+
return createSPIRVBuiltinLoad(B, CGM.getModule(), Type,
597+
S->getAttrName()->getName(),
598+
/* BuiltIn::FragCoord */ 15);
593599
}
594-
assert(false && "Unhandled parameter attribute");
595-
return nullptr;
600+
601+
llvm_unreachable("non-handled system semantic. FIXME.");
602+
}
603+
604+
llvm::Value *
605+
CGHLSLRuntime::handleScalarSemanticLoad(IRBuilder<> &B, llvm::Type *Type,
606+
const clang::DeclaratorDecl *Decl,
607+
SemanticInfo &ActiveSemantic) {
608+
609+
if (!ActiveSemantic.Semantic) {
610+
ActiveSemantic.Semantic = Decl->getAttr<HLSLSemanticAttr>();
611+
if (!ActiveSemantic.Semantic) {
612+
CGM.getDiags().Report(Decl->getInnerLocStart(),
613+
diag::err_hlsl_semantic_missing);
614+
return nullptr;
615+
}
616+
ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex();
617+
}
618+
619+
return emitSystemSemanticLoad(B, Type, Decl, ActiveSemantic);
620+
}
621+
622+
llvm::Value *
623+
CGHLSLRuntime::handleSemanticLoad(IRBuilder<> &B, llvm::Type *Type,
624+
const clang::DeclaratorDecl *Decl,
625+
SemanticInfo &ActiveSemantic) {
626+
assert(!Type->isStructTy());
627+
return handleScalarSemanticLoad(B, Type, Decl, ActiveSemantic);
596628
}
597629

598630
void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD,
@@ -637,8 +669,10 @@ void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD,
637669
Args.emplace_back(PoisonValue::get(Param.getType()));
638670
continue;
639671
}
672+
640673
const ParmVarDecl *PD = FD->getParamDecl(Param.getArgNo() - SRetOffset);
641-
Args.push_back(emitInputSemantic(B, *PD, Param.getType()));
674+
SemanticInfo ActiveSemantic = {nullptr, 0};
675+
Args.push_back(handleSemanticLoad(B, Param.getType(), PD, ActiveSemantic));
642676
}
643677

644678
CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args, OB);

0 commit comments

Comments
 (0)