Skip to content

[HLSL] Rewrite semantics parsing #152537

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions clang/include/clang/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,41 @@ class HLSLAnnotationAttr : public InheritableAttr {
}
};

class HLSLSemanticAttr : public HLSLAnnotationAttr {
unsigned SemanticIndex : 30;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to figure out if we had any documentation on the valid ranges for this. It looks like DXC does allow a 32-bit integer, and while I hope to god that nobody is actually doing this it seems to work up to UINT32_MAX:

https://godbolt.org/z/eEazEbfrM

It probably won't hurt us to give a full 32-bit integer for the semantic index and have the bools be an extra bitfield.

LLVM_PREFERRED_TYPE(bool)
unsigned SemanticIndexable : 1;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to store this at all? Isn't this a static property we can define from the semantic type itself?

User defined semantics are always indexable and system values may or may not be based on which system value they refer to. At the moment that's a unique attribute type, but even if we instead make it an enum on the HLSLSemanticAttr we could just have a switch statement that returns false for the handful of cases that aren't indexable and true for everything else.

LLVM_PREFERRED_TYPE(bool)
unsigned SemanticExplicitIndex : 1;

protected:
HLSLSemanticAttr(ASTContext &Context, const AttributeCommonInfo &CommonInfo,
attr::Kind AK, bool IsLateParsed,
bool InheritEvenIfAlreadyPresent, bool SemanticIndexable)
: HLSLAnnotationAttr(Context, CommonInfo, AK, IsLateParsed,
InheritEvenIfAlreadyPresent) {
this->SemanticIndexable = SemanticIndexable;
this->SemanticIndex = 0;
this->SemanticExplicitIndex = 0;
}

public:
bool isSemanticIndexable() const { return SemanticIndexable; }

void setSemanticIndex(unsigned SemanticIndex) {
this->SemanticIndex = SemanticIndex;
this->SemanticExplicitIndex = true;
}

unsigned getSemanticIndex() const { return SemanticIndex; }

// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) {
return A->getKind() >= attr::FirstHLSLSemanticAttr &&
A->getKind() <= attr::LastHLSLSemanticAttr;
}
};

/// A parameter attribute which changes the argument-passing ABI rule
/// for the parameter.
class ParameterABIAttr : public InheritableParamAttr {
Expand Down
68 changes: 36 additions & 32 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ class ClangGCC<string name, bit allowInC = 1, int version = 1>
}

// HLSL Annotation spellings
class HLSLAnnotation<string name> : Spelling<name, "HLSLAnnotation">;
class HLSLAnnotation<string name> : Spelling<name, "HLSLAnnotation"> {}

class Accessor<string name, list<Spelling> spellings> {
string Name = name;
Expand Down Expand Up @@ -779,6 +779,16 @@ class DeclOrStmtAttr : InheritableAttr;
/// An attribute class for HLSL Annotations.
class HLSLAnnotationAttr : InheritableAttr;

class HLSLSemanticAttr<bit Indexable> : HLSLAnnotationAttr {
bit SemanticIndexable = Indexable;
int SemanticIndex = 0;
bit SemanticExplicitIndex = 0;

let Spellings = [];
let Subjects = SubjectList<[ParmVar, Field, Function]>;
let LangOpts = [HLSL];
}

/// A target-specific attribute. This class is meant to be used as a mixin
/// with InheritableAttr or Attr depending on the attribute's needs.
class TargetSpecificAttr<TargetSpec target> {
Expand Down Expand Up @@ -4873,27 +4883,6 @@ def HLSLNumThreads: InheritableAttr {
let Documentation = [NumThreadsDocs];
}

def HLSLSV_GroupThreadID: HLSLAnnotationAttr {
let Spellings = [HLSLAnnotation<"sv_groupthreadid">];
let Subjects = SubjectList<[ParmVar, Field]>;
let LangOpts = [HLSL];
let Documentation = [HLSLSV_GroupThreadIDDocs];
}

def HLSLSV_GroupID: HLSLAnnotationAttr {
let Spellings = [HLSLAnnotation<"sv_groupid">];
let Subjects = SubjectList<[ParmVar, Field]>;
let LangOpts = [HLSL];
let Documentation = [HLSLSV_GroupIDDocs];
}

def HLSLSV_GroupIndex: HLSLAnnotationAttr {
let Spellings = [HLSLAnnotation<"sv_groupindex">];
let Subjects = SubjectList<[ParmVar, GlobalVar]>;
let LangOpts = [HLSL];
let Documentation = [HLSLSV_GroupIndexDocs];
}

def HLSLResourceBinding: InheritableAttr {
let Spellings = [HLSLAnnotation<"register">];
let Subjects = SubjectList<[HLSLBufferObj, ExternalGlobalVar], ErrorDiag>;
Expand Down Expand Up @@ -4943,13 +4932,35 @@ def HLSLResourceBinding: InheritableAttr {
}];
}

def HLSLSV_Position : HLSLAnnotationAttr {
let Spellings = [HLSLAnnotation<"sv_position">];
let Subjects = SubjectList<[ParmVar, Field]>;
def HLSLUnparsedSemantic : HLSLAnnotationAttr {
let Spellings = [];
let Args = [DefaultIntArgument<"Index", 0>,
DefaultBoolArgument<"ExplicitIndex", 0>];
let Subjects = SubjectList<[ParmVar, Field, Function]>;
let LangOpts = [HLSL];
let Documentation = [InternalOnly];
}

def HLSLSV_Position : HLSLSemanticAttr</* Indexable= */ 1> {
let Documentation = [HLSLSV_PositionDocs];
}

def HLSLSV_GroupThreadID : HLSLSemanticAttr</* Indexable= */ 0> {
let Documentation = [HLSLSV_GroupThreadIDDocs];
}

def HLSLSV_GroupID : HLSLSemanticAttr</* Indexable= */ 0> {
let Documentation = [HLSLSV_GroupIDDocs];
}

def HLSLSV_GroupIndex : HLSLSemanticAttr</* Indexable= */ 0> {
let Documentation = [HLSLSV_GroupIndexDocs];
}

def HLSLSV_DispatchThreadID : HLSLSemanticAttr</* Indexable= */ 0> {
let Documentation = [HLSLSV_DispatchThreadIDDocs];
}

def HLSLPackOffset: HLSLAnnotationAttr {
let Spellings = [HLSLAnnotation<"packoffset">];
let LangOpts = [HLSL];
Expand All @@ -4962,13 +4973,6 @@ def HLSLPackOffset: HLSLAnnotationAttr {
}];
}

def HLSLSV_DispatchThreadID: HLSLAnnotationAttr {
let Spellings = [HLSLAnnotation<"sv_dispatchthreadid">];
let Subjects = SubjectList<[ParmVar, Field]>;
let LangOpts = [HLSL];
let Documentation = [HLSLSV_DispatchThreadIDDocs];
}

def HLSLShader : InheritableAttr {
let Spellings = [Microsoft<"shader">];
let Subjects = SubjectList<[HLSLEntry]>;
Expand Down
8 changes: 8 additions & 0 deletions clang/include/clang/Basic/DiagnosticFrontendKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,14 @@ def warn_hlsl_langstd_minimal :
"recommend using %1 instead">,
InGroup<HLSLDXCCompat>;

def err_hlsl_semantic_index_overlap : Error<"semantic index overlap %0">;

def err_hlsl_semantic_missing : Error<"semantic annotations must be present "
"for all input and outputs of an entry "
"function or patch constant function">;

def note_hlsl_semantic_used_here : Note<"%0 used here">;

// ClangIR frontend errors
def err_cir_to_cir_transform_failed : Error<
"CIR-to-CIR transformation failed">, DefaultFatal;
Expand Down
5 changes: 2 additions & 3 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -1851,9 +1851,8 @@ def note_max_tokens_total_override : Note<"total token limit set here">;

def err_expected_semantic_identifier : Error<
"expected HLSL Semantic identifier">;
def err_invalid_declaration_in_hlsl_buffer : Error<
"invalid declaration inside %select{tbuffer|cbuffer}0">;
def err_unknown_hlsl_semantic : Error<"unknown HLSL semantic %0">;
def err_invalid_declaration_in_hlsl_buffer
: Error<"invalid declaration inside %select{tbuffer|cbuffer}0">;
def err_hlsl_separate_attr_arg_and_number : Error<"wrong argument format for hlsl attribute, use %0 instead">;
def ext_hlsl_access_specifiers : ExtWarn<
"access specifiers are a clang HLSL extension">,
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -13058,6 +13058,11 @@ def err_hlsl_duplicate_parameter_modifier : Error<"duplicate parameter modifier
def err_hlsl_missing_semantic_annotation : Error<
"semantic annotations must be present for all parameters of an entry "
"function or patch constant function">;
def err_hlsl_unknown_semantic : Error<"unknown HLSL semantic %0">;
def err_hlsl_semantic_output_not_supported
: Error<"semantic %0 does not support output">;
def err_hlsl_semantic_indexing_not_supported
: Error<"semantic %0 does not allow indexing">;
def err_hlsl_init_priority_unsupported : Error<
"initializer priorities are not supported in HLSL">;

Expand Down
8 changes: 8 additions & 0 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -5188,6 +5188,14 @@ class Parser : public CodeCompletionHandler {
ParseHLSLAnnotations(Attrs, EndLoc);
}

struct ParsedSemantic {
StringRef Name;
unsigned Index;
bool Explicit;
};

ParsedSemantic ParseHLSLSemantic();

void ParseHLSLAnnotations(ParsedAttributes &Attrs,
SourceLocation *EndLoc = nullptr,
bool CouldBeBitField = false);
Expand Down
25 changes: 21 additions & 4 deletions clang/include/clang/Sema/SemaHLSL.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "clang/AST/Attr.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Sema/SemaBase.h"
#include "llvm/ADT/SmallVector.h"
Expand Down Expand Up @@ -129,6 +130,7 @@ class SemaHLSL : public SemaBase {
bool ActOnUninitializedVarDecl(VarDecl *D);
void ActOnEndOfTranslationUnit(TranslationUnitDecl *TU);
void CheckEntryPoint(FunctionDecl *FD);
bool isSemanticValid(FunctionDecl *FD, DeclaratorDecl *D);
void CheckSemanticAnnotation(FunctionDecl *EntryPoint, const Decl *Param,
const HLSLAnnotationAttr *AnnotationAttr);
void DiagnoseAttrStageMismatch(
Expand Down Expand Up @@ -161,16 +163,31 @@ class SemaHLSL : public SemaBase {
void handleNumThreadsAttr(Decl *D, const ParsedAttr &AL);
void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL);
void handleVkConstantIdAttr(Decl *D, const ParsedAttr &AL);
void handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL);
void handleSV_GroupThreadIDAttr(Decl *D, const ParsedAttr &AL);
void handleSV_GroupIDAttr(Decl *D, const ParsedAttr &AL);
void handleSV_PositionAttr(Decl *D, const ParsedAttr &AL);
void handlePackOffsetAttr(Decl *D, const ParsedAttr &AL);
void handleShaderAttr(Decl *D, const ParsedAttr &AL);
void handleResourceBindingAttr(Decl *D, const ParsedAttr &AL);
void handleParamModifierAttr(Decl *D, const ParsedAttr &AL);
bool handleResourceTypeAttr(QualType T, const ParsedAttr &AL);

template <typename T>
T *createSemanticAttr(const ParsedAttr &AL,
std::optional<unsigned> Location) {
T *Attr = ::new (getASTContext()) T(getASTContext(), AL);
if (Attr->isSemanticIndexable())
Attr->setSemanticIndex(Location ? *Location : 0);
else if (Location.has_value()) {
Diag(Attr->getLocation(), diag::err_hlsl_semantic_indexing_not_supported)
<< Attr->getAttrName()->getName();
return nullptr;
}

return Attr;
}

void diagnoseSystemSemanticAttr(Decl *D, const ParsedAttr &AL,
std::optional<unsigned> Index);
void handleSemanticAttr(Decl *D, const ParsedAttr &AL);

void handleVkExtBuiltinInputAttr(Decl *D, const ParsedAttr &AL);

bool CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/Basic/Attributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,12 @@ AttributeCommonInfo::Kind
AttributeCommonInfo::getParsedKind(const IdentifierInfo *Name,
const IdentifierInfo *ScopeName,
Syntax SyntaxUsed) {
return ::getAttrKind(normalizeName(Name, ScopeName, SyntaxUsed), SyntaxUsed);
AttributeCommonInfo::Kind Kind =
::getAttrKind(normalizeName(Name, ScopeName, SyntaxUsed), SyntaxUsed);
if (SyntaxUsed == AS_HLSLAnnotation &&
Kind == AttributeCommonInfo::Kind::UnknownAttribute)
return AttributeCommonInfo::Kind::AT_HLSLUnparsedSemantic;
return Kind;
}

AttributeCommonInfo::AttrArgsInfo
Expand Down
Loading