Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
8 changes: 8 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -5172,6 +5172,14 @@ def HLSLVkConstantId : InheritableAttr {
let Documentation = [VkConstantIdDocs];
}

def HLSLVkLocation : HLSLAnnotationAttr {
let Spellings = [CXX11<"vk", "location">];
let Args = [IntArgument<"Location">];
let Subjects = SubjectList<[ParmVar, Field, Function], ErrorDiag>;
let LangOpts = [HLSL];
let Documentation = [HLSLVkLocationDocs];
}

def RandomizeLayout : InheritableAttr {
let Spellings = [GCC<"randomize_layout">];
let Subjects = SubjectList<[Record]>;
Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -8981,6 +8981,18 @@ The descriptor set is optional and defaults to 0 if not provided.
}];
}

def HLSLVkLocationDocs : Documentation {
let Category = DocCatVariable;
let Content = [{
Attribute used for specifying the location number for the stage input/output
variables. Allowed on function parameters, function returns, and struct
fields. This parameter has no effect when used outside of an entrypoint
parameter/parameter field/return value.

This attribute maps to the 'Location' SPIR-V decoration.
}];
}

def WebAssemblyFuncrefDocs : Documentation {
let Category = DocCatType;
let Content = [{
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -13231,6 +13231,12 @@ def err_hlsl_semantic_indexing_not_supported
def err_hlsl_init_priority_unsupported : Error<
"initializer priorities are not supported in HLSL">;
def err_hlsl_semantic_index_overlap : Error<"semantic index overlap %0">;
def err_hlsl_semantic_unsupported_iotype_for_stage
: Error<"semantic %0 is unsupported in %2 shaders as %1, requires one of "
"the following: %3">;
def err_hlsl_semantic_partial_explicit_indexing
: Error<"partial explicit stage input location assignment via "
"vk::location(X) unsupported">;

def warn_hlsl_user_defined_type_missing_member: Warning<"binding type '%select{t|u|b|s|c}0' only applies to types containing %select{SRV resources|UAV resources|constant buffer resources|sampler state|numeric types}0">, InGroup<LegacyConstantRegisterBinding>;
def err_hlsl_binding_type_mismatch: Error<"binding type '%select{t|u|b|s|c}0' only applies to %select{SRV resources|UAV resources|constant buffer resources|sampler state|numeric variables in the global scope}0">;
Expand Down
25 changes: 22 additions & 3 deletions clang/include/clang/Sema/SemaHLSL.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,6 @@ class SemaHLSL : public SemaBase {
void CheckEntryPoint(FunctionDecl *FD);
bool CheckResourceBinOp(BinaryOperatorKind Opc, Expr *LHSExpr, Expr *RHSExpr,
SourceLocation Loc);
void DiagnoseAttrStageMismatch(
const Attr *A, llvm::Triple::EnvironmentType Stage,
std::initializer_list<llvm::Triple::EnvironmentType> AllowedStages);

QualType handleVectorBinOpConversion(ExprResult &LHS, ExprResult &RHS,
QualType LHSType, QualType RHSType,
Expand Down Expand Up @@ -171,6 +168,7 @@ class SemaHLSL : public SemaBase {
void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL);
void handleVkConstantIdAttr(Decl *D, const ParsedAttr &AL);
void handleVkBindingAttr(Decl *D, const ParsedAttr &AL);
void handleVkLocationAttr(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);
Expand Down Expand Up @@ -243,6 +241,19 @@ class SemaHLSL : public SemaBase {
HLSLParsedSemanticAttr *Semantic;
std::optional<uint32_t> Index;
};
std::optional<bool> InputUsesExplicitVkLocations = std::nullopt;
std::optional<bool> OutputUsesExplicitVkLocations = std::nullopt;

enum IOType {
In = 0b01,
Out = 0b10,
InOut = 0b11,
};

struct SemanticStageInfo {
llvm::Triple::EnvironmentType Stage;
IOType AllowedIOTypesMask;
};

private:
void collectResourceBindingsOnVarDecl(VarDecl *D);
Expand All @@ -269,6 +280,14 @@ class SemaHLSL : public SemaBase {

void diagnoseAvailabilityViolations(TranslationUnitDecl *TU);

void diagnoseAttrStageMismatch(
const Attr *A, llvm::Triple::EnvironmentType Stage,
std::initializer_list<llvm::Triple::EnvironmentType> AllowedStages);

void diagnoseSemanticStageMismatch(
const Attr *A, llvm::Triple::EnvironmentType Stage, bool IsInput,
std::initializer_list<SemanticStageInfo> AllowedStages);

uint32_t getNextImplicitBindingOrderID() {
return ImplicitBindingNextOrderID++;
}
Expand Down
25 changes: 18 additions & 7 deletions clang/lib/CodeGen/CGHLSLRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -582,20 +582,22 @@ static llvm::Value *createSPIRVLocationLoad(IRBuilder<> &B, llvm::Module &M,
return B.CreateLoad(Ty, GV);
}

llvm::Value *
CGHLSLRuntime::emitSPIRVUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
HLSLAppliedSemanticAttr *Semantic,
std::optional<unsigned> Index) {
llvm::Value *CGHLSLRuntime::emitSPIRVUserSemanticLoad(
llvm::IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl,
HLSLAppliedSemanticAttr *Semantic, std::optional<unsigned> Index) {
Twine BaseName = Twine(Semantic->getAttrName()->getName());
Twine VariableName = BaseName.concat(Twine(Index.value_or(0)));

unsigned Location = SPIRVLastAssignedInputSemanticLocation;
if (auto *L = Decl->getAttr<HLSLVkLocationAttr>())
Location = L->getLocation();

// DXC completely ignores the semantic/index pair. Location are assigned from
// the first semantic to the last.
llvm::ArrayType *AT = dyn_cast<llvm::ArrayType>(Type);
unsigned ElementCount = AT ? AT->getNumElements() : 1;
SPIRVLastAssignedInputSemanticLocation += ElementCount;

return createSPIRVLocationLoad(B, CGM.getModule(), Type, Location,
VariableName.str());
}
Expand All @@ -616,10 +618,14 @@ static void createSPIRVLocationStore(IRBuilder<> &B, llvm::Module &M,

void CGHLSLRuntime::emitSPIRVUserSemanticStore(
llvm::IRBuilder<> &B, llvm::Value *Source,
HLSLAppliedSemanticAttr *Semantic, std::optional<unsigned> Index) {
const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic,
std::optional<unsigned> Index) {
Twine BaseName = Twine(Semantic->getAttrName()->getName());
Twine VariableName = BaseName.concat(Twine(Index.value_or(0)));

unsigned Location = SPIRVLastAssignedOutputSemanticLocation;
if (auto *L = Decl->getAttr<HLSLVkLocationAttr>())
Location = L->getLocation();

// DXC completely ignores the semantic/index pair. Location are assigned from
// the first semantic to the last.
Expand Down Expand Up @@ -671,7 +677,7 @@ llvm::Value *CGHLSLRuntime::emitUserSemanticLoad(
IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl,
HLSLAppliedSemanticAttr *Semantic, std::optional<unsigned> Index) {
if (CGM.getTarget().getTriple().isSPIRV())
return emitSPIRVUserSemanticLoad(B, Type, Semantic, Index);
return emitSPIRVUserSemanticLoad(B, Type, Decl, Semantic, Index);

if (CGM.getTarget().getTriple().isDXIL())
return emitDXILUserSemanticLoad(B, Type, Semantic, Index);
Expand All @@ -684,7 +690,7 @@ void CGHLSLRuntime::emitUserSemanticStore(IRBuilder<> &B, llvm::Value *Source,
HLSLAppliedSemanticAttr *Semantic,
std::optional<unsigned> Index) {
if (CGM.getTarget().getTriple().isSPIRV())
return emitSPIRVUserSemanticStore(B, Source, Semantic, Index);
return emitSPIRVUserSemanticStore(B, Source, Decl, Semantic, Index);

if (CGM.getTarget().getTriple().isDXIL())
return emitDXILUserSemanticStore(B, Source, Semantic, Index);
Expand Down Expand Up @@ -783,6 +789,11 @@ void CGHLSLRuntime::emitSystemSemanticStore(IRBuilder<> &B, llvm::Value *Source,
}
}

if (SemanticName == "SV_TARGET") {
emitUserSemanticStore(B, Source, Decl, Semantic, Index);
return;
}

llvm_unreachable(
"Store hasn't been implemented yet for this system semantic. FIXME");
}
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CGHLSLRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ class CGHLSLRuntime {
HLSLResourceBindingAttr *RBA);

llvm::Value *emitSPIRVUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
const clang::DeclaratorDecl *Decl,
HLSLAppliedSemanticAttr *Semantic,
std::optional<unsigned> Index);
llvm::Value *emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
Expand All @@ -289,6 +290,7 @@ class CGHLSLRuntime {
std::optional<unsigned> Index);

void emitSPIRVUserSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Source,
const clang::DeclaratorDecl *Decl,
HLSLAppliedSemanticAttr *Semantic,
std::optional<unsigned> Index);
void emitDXILUserSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Source,
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7703,6 +7703,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_HLSLUnparsedSemantic:
S.HLSL().handleSemanticAttr(D, AL);
break;
case ParsedAttr::AT_HLSLVkLocation:
S.HLSL().handleVkLocationAttr(D, AL);
break;

case ParsedAttr::AT_AbiTag:
handleAbiTagAttr(S, D, AL);
Expand Down
117 changes: 109 additions & 8 deletions clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -771,6 +771,22 @@ void SemaHLSL::ActOnTopLevelFunction(FunctionDecl *FD) {
}
}

static bool isPipelineBuiltin(const ASTContext &AstContext, FunctionDecl *FD,
HLSLAppliedSemanticAttr *Semantic) {
if (AstContext.getTargetInfo().getTriple().getOS() != llvm::Triple::Vulkan)
return false;

const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
assert(ShaderAttr && "Entry point has no shader attribute");
llvm::Triple::EnvironmentType ST = ShaderAttr->getType();
auto SemanticName = Semantic->getSemanticName().upper();

if (ST == llvm::Triple::Pixel && SemanticName == "SV_POSITION")
return true;

return false;
}

bool SemaHLSL::determineActiveSemanticOnScalar(FunctionDecl *FD,
DeclaratorDecl *OutputDecl,
DeclaratorDecl *D,
Expand Down Expand Up @@ -800,6 +816,22 @@ bool SemaHLSL::determineActiveSemanticOnScalar(FunctionDecl *FD,

unsigned Location = ActiveSemantic.Index.value_or(0);

if (!isPipelineBuiltin(getASTContext(), FD, A)) {
bool HasVkLocation = false;
if (auto *A = D->getAttr<HLSLVkLocationAttr>()) {
HasVkLocation = true;
Location = A->getLocation();
}

auto &UsesExplicitVkLocations =
IsInput ? InputUsesExplicitVkLocations : OutputUsesExplicitVkLocations;
if (UsesExplicitVkLocations.value_or(HasVkLocation) != HasVkLocation) {
Diag(D->getLocation(), diag::err_hlsl_semantic_partial_explicit_indexing);
return false;
}
UsesExplicitVkLocations = HasVkLocation;
}

const ConstantArrayType *AT = dyn_cast<ConstantArrayType>(D->getType());
unsigned ElementCount = AT ? AT->getZExtSize() : 1;
ActiveSemantic.Index = Location + ElementCount;
Expand Down Expand Up @@ -873,14 +905,14 @@ void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) {
case llvm::Triple::Miss:
case llvm::Triple::Callable:
if (const auto *NT = FD->getAttr<HLSLNumThreadsAttr>()) {
DiagnoseAttrStageMismatch(NT, ST,
diagnoseAttrStageMismatch(NT, ST,
{llvm::Triple::Compute,
llvm::Triple::Amplification,
llvm::Triple::Mesh});
FD->setInvalidDecl();
}
if (const auto *WS = FD->getAttr<HLSLWaveSizeAttr>()) {
DiagnoseAttrStageMismatch(WS, ST,
diagnoseAttrStageMismatch(WS, ST,
{llvm::Triple::Compute,
llvm::Triple::Amplification,
llvm::Triple::Mesh});
Expand Down Expand Up @@ -954,7 +986,8 @@ void SemaHLSL::checkSemanticAnnotation(
SemanticName == "SV_GROUPID") {

if (ST != llvm::Triple::Compute)
DiagnoseAttrStageMismatch(SemanticAttr, ST, {llvm::Triple::Compute});
diagnoseSemanticStageMismatch(SemanticAttr, ST, IsInput,
{{llvm::Triple::Compute, IOType::In}});

if (SemanticAttr->getSemanticIndex() != 0) {
std::string PrettyName =
Expand All @@ -969,10 +1002,15 @@ void SemaHLSL::checkSemanticAnnotation(
if (SemanticName == "SV_POSITION") {
// SV_Position can be an input or output in vertex shaders,
// but only an input in pixel shaders.
if (ST == llvm::Triple::Vertex || (ST == llvm::Triple::Pixel && IsInput))
return;
DiagnoseAttrStageMismatch(SemanticAttr, ST,
{llvm::Triple::Pixel, llvm::Triple::Vertex});
diagnoseSemanticStageMismatch(SemanticAttr, ST, IsInput,
{{llvm::Triple::Vertex, IOType::InOut},
{llvm::Triple::Pixel, IOType::In}});
return;
}

if (SemanticName == "SV_TARGET") {
diagnoseSemanticStageMismatch(SemanticAttr, ST, IsInput,
{{llvm::Triple::Pixel, IOType::Out}});
return;
}

Expand All @@ -982,7 +1020,7 @@ void SemaHLSL::checkSemanticAnnotation(
llvm_unreachable("Unknown SemanticAttr");
}

void SemaHLSL::DiagnoseAttrStageMismatch(
void SemaHLSL::diagnoseAttrStageMismatch(
const Attr *A, llvm::Triple::EnvironmentType Stage,
std::initializer_list<llvm::Triple::EnvironmentType> AllowedStages) {
SmallVector<StringRef, 8> StageStrings;
Expand All @@ -996,6 +1034,50 @@ void SemaHLSL::DiagnoseAttrStageMismatch(
<< (AllowedStages.size() != 1) << join(StageStrings, ", ");
}

void SemaHLSL::diagnoseSemanticStageMismatch(
const Attr *A, llvm::Triple::EnvironmentType Stage, bool IsInput,
std::initializer_list<SemanticStageInfo> Allowed) {

for (auto &Case : Allowed) {
if (Case.Stage != Stage)
continue;

if (IsInput && Case.AllowedIOTypesMask & IOType::In)
return;
if (!IsInput && Case.AllowedIOTypesMask & IOType::Out)
return;

SmallVector<std::string, 8> ValidCases;
llvm::transform(
Allowed, std::back_inserter(ValidCases), [](SemanticStageInfo Case) {
SmallVector<std::string, 2> ValidType;
if (Case.AllowedIOTypesMask & IOType::In)
ValidType.push_back("input");
if (Case.AllowedIOTypesMask & IOType::Out)
ValidType.push_back("output");
return std::string(
HLSLShaderAttr::ConvertEnvironmentTypeToStr(Case.Stage)) +
" " + join(ValidType, "/");
});
Diag(A->getLoc(), diag::err_hlsl_semantic_unsupported_iotype_for_stage)
<< A->getAttrName() << (IsInput ? "input" : "output")
<< llvm::Triple::getEnvironmentTypeName(Case.Stage)
<< join(ValidCases, ", ");
return;
}

SmallVector<StringRef, 8> StageStrings;
llvm::transform(
Allowed, std::back_inserter(StageStrings), [](SemanticStageInfo Case) {
return StringRef(
HLSLShaderAttr::ConvertEnvironmentTypeToStr(Case.Stage));
});

Diag(A->getLoc(), diag::err_hlsl_attr_unsupported_in_stage)
<< A->getAttrName() << llvm::Triple::getEnvironmentTypeName(Stage)
<< (Allowed.size() != 1) << join(StageStrings, ", ");
}

template <CastKind Kind>
static void castVector(Sema &S, ExprResult &E, QualType &Ty, unsigned Sz) {
if (const auto *VTy = Ty->getAs<VectorType>())
Expand Down Expand Up @@ -1707,6 +1789,15 @@ void SemaHLSL::handleVkBindingAttr(Decl *D, const ParsedAttr &AL) {
HLSLVkBindingAttr(getASTContext(), AL, Binding, Set));
}

void SemaHLSL::handleVkLocationAttr(Decl *D, const ParsedAttr &AL) {
uint32_t Location;
if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Location))
return;

D->addAttr(::new (getASTContext())
HLSLVkLocationAttr(getASTContext(), AL, Location));
}

bool SemaHLSL::diagnoseInputIDType(QualType T, const ParsedAttr &AL) {
const auto *VT = T->getAs<VectorType>();

Expand Down Expand Up @@ -1797,6 +1888,16 @@ void SemaHLSL::diagnoseSystemSemanticAttr(Decl *D, const ParsedAttr &AL,
return;
}

if (SemanticName == "SV_TARGET") {
const auto *VT = ValueType->getAs<VectorType>();
if (!ValueType->hasFloatingRepresentation() ||
(VT && VT->getNumElements() > 4))
Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
<< AL << "float/float1/float2/float3/float4";
D->addAttr(createSemanticAttr<HLSLParsedSemanticAttr>(AL, Index));
return;
}

Diag(AL.getLoc(), diag::err_hlsl_unknown_semantic) << AL;
}

Expand Down
Loading