Skip to content

Commit

Permalink
RV] Add support of the GL_EXT_spirv_intrinsics
Browse files Browse the repository at this point in the history
related to
issue:microsoft#3919

Add support to these two attributes:
 [[vk::ext_decorate(decoration, … int literal)]]
 [[vk::ext_decorate_string(decoration, … string literals)]]
  • Loading branch information
jiaolu committed Oct 25, 2021
1 parent b1b3e85 commit 7057642
Show file tree
Hide file tree
Showing 11 changed files with 173 additions and 11 deletions.
16 changes: 16 additions & 0 deletions tools/clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -1026,6 +1026,22 @@ def VKCounterBinding : InheritableAttr {
let Documentation = [Undocumented];
}

def VKDecorateExt : InheritableAttr {
let Spellings = [CXX11<"vk", "ext_decorate">];
let Subjects = SubjectList<[Function, Var, ParmVar, Field, TypedefName], ErrorDiag>;
let Args = [UnsignedArgument<"decorate">, VariadicUnsignedArgument<"literal">];
let LangOpts = [SPIRV];
let Documentation = [Undocumented];
}

def VKDecorateStringExt : InheritableAttr {
let Spellings = [CXX11<"vk", "ext_decorate_string">];
let Subjects = SubjectList<[Function, Var, ParmVar, Field, TypedefName], ErrorDiag>;
let Args = [UnsignedArgument<"decorate">, StringArgument<"literals">];
let LangOpts = [SPIRV];
let Documentation = [Undocumented];
}

def VKExtensionExt : InheritableAttr {
let Spellings = [CXX11<"vk", "ext_extension">];
let Subjects = SubjectList<[Function], ErrorDiag>;
Expand Down
9 changes: 9 additions & 0 deletions tools/clang/include/clang/SPIRV/SpirvBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,15 @@ class SpirvBuilder {
llvm::StringRef name, spv::LinkageType linkageType,
SourceLocation);

/// \brief Decorates the given target with information from VKDecorateExt
void decorateInst(SpirvInstruction *targetInst, unsigned decorate,
unsigned *literal, unsigned literalSize, SourceLocation);

/// \brief Decorates the given target with the given string.
void decorateString(SpirvInstruction *target, unsigned decorate,
llvm::StringRef strLiteral,
llvm::Optional<uint32_t> memberIdx = llvm::None);

/// --- Constants ---
/// Each of these methods can acquire a unique constant from the SpirvContext,
/// and add the context to the list of constants in the module.
Expand Down
5 changes: 4 additions & 1 deletion tools/clang/include/clang/SPIRV/SpirvInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -461,9 +461,12 @@ class SpirvModuleProcessed : public SpirvInstruction {
/// \brief OpDecorate(Id) and OpMemberDecorate instructions
class SpirvDecoration : public SpirvInstruction {
public:
// OpDecorate/OpMemberDecorate
SpirvDecoration(SourceLocation loc, SpirvInstruction *target,
spv::Decoration decor, llvm::ArrayRef<uint32_t> params = {},
llvm::Optional<uint32_t> index = llvm::None);

// OpDecorateString/OpMemberDecorateString
SpirvDecoration(SourceLocation loc, SpirvInstruction *target,
spv::Decoration decor, llvm::StringRef stringParam,
llvm::Optional<uint32_t> index = llvm::None);
Expand Down Expand Up @@ -497,7 +500,7 @@ class SpirvDecoration : public SpirvInstruction {
uint32_t getMemberIndex() const { return index.getValue(); }

private:
spv::Op getDecorateOpcode(spv::Decoration,
spv::Op getDecorateOpcode(bool isString,
const llvm::Optional<uint32_t> &memberIndex);

private:
Expand Down
47 changes: 47 additions & 0 deletions tools/clang/lib/SPIRV/DeclResultIdMapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2420,6 +2420,26 @@ bool DeclResultIdMapper::createStageVars(
stageVar.getStorageClass() == spv::StorageClass::Output) {
stageVar.setEntryPoint(entryFunction);
}

if (decl->hasAttr<VKDecorateExtAttr>()) {
bool isBuiltin = false;
bool isLocation = false;
auto lamda = [&stageVar, &isBuiltin, &isLocation](VKDecorateExtAttr *decoAttr) {
auto decorate = static_cast<spv::Decoration>(decoAttr->getDecorate());
if (!isBuiltin && decorate == spv::Decoration::BuiltIn) {
stageVar.setIsSpirvBuiltin();
isBuiltin = true;
}

if (!isLocation && decorate == spv::Decoration::Location) {
// Set as builtIn as avoid later location decoration
stageVar.setIsSpirvBuiltin();
isLocation = true;
}
};
decorateWithIntrinsicAttrs(decl, varInstr, lamda);
}

stageVars.push_back(stageVar);

// Emit OpDecorate* instructions to link this stage variable with the HLSL
Expand All @@ -2430,6 +2450,8 @@ bool DeclResultIdMapper::createStageVars(
// function/parameter/variable. All are DeclaratorDecls.
stageVarInstructions[cast<DeclaratorDecl>(decl)] = varInstr;



// Special case: The DX12 SV_InstanceID always counts from 0, even if the
// StartInstanceLocation parameter is non-zero. gl_InstanceIndex, however,
// starts from firstInstance. Thus it doesn't emulate actual DX12 shader
Expand Down Expand Up @@ -3962,5 +3984,30 @@ DeclResultIdMapper::createHullMainOutputPatch(const ParmVarDecl *param,
return hullMainOutputPatch;
}

template <typename Functor>
void DeclResultIdMapper::decorateWithIntrinsicAttrs(const NamedDecl *decl,
SpirvVariable *varInst,
Functor func) {
if (!decl->hasAttrs())
return;

for (auto &attr : decl->getAttrs()) {
if (auto decoAttr = dyn_cast<VKDecorateExtAttr>(attr)) {
func(decoAttr);
spvBuilder.decorateInst(
varInst, decoAttr->getDecorate(), decoAttr->literal_begin(),
decoAttr->literal_size(), varInst->getSourceLocation());
} else if (auto decoAttr = dyn_cast<VKDecorateStringExtAttr>(attr)) {
spvBuilder.decorateString(varInst, decoAttr->getDecorate(),
decoAttr->getLiterals());
}
}
}

void DeclResultIdMapper::decorateVariableWithIntrinsicAttrs(
const NamedDecl *decl, SpirvVariable *varInst) {
decorateWithIntrinsicAttrs(decl, varInst, [](VKDecorateExtAttr *) {});
}

} // end namespace spirv
} // end namespace clang
7 changes: 7 additions & 0 deletions tools/clang/lib/SPIRV/DeclResultIdMapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,9 @@ class DeclResultIdMapper {
return value;
}

void decorateVariableWithIntrinsicAttrs(const NamedDecl *decl,
SpirvVariable *varInst);

private:
/// \brief Wrapper method to create a fatal error message and report it
/// in the diagnostic engine associated with this consumer.
Expand Down Expand Up @@ -825,6 +828,10 @@ class DeclResultIdMapper {
bool getImplicitRegisterType(const ResourceVar &var,
char *registerTypeOut) const;

template <typename Functor>
void decorateWithIntrinsicAttrs(const NamedDecl *decl, SpirvVariable *varInst,
Functor func);

private:
SpirvBuilder &spvBuilder;
SpirvEmitter &theEmitter;
Expand Down
22 changes: 22 additions & 0 deletions tools/clang/lib/SPIRV/SpirvBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1441,6 +1441,28 @@ void SpirvBuilder::decorateLinkage(SpirvInstruction *targetInst,
mod->addDecoration(decor);
}

void SpirvBuilder::decorateInst(SpirvInstruction *targetInst, unsigned decorate,
unsigned *literal, unsigned literalSize,
SourceLocation srcLoc) {
SmallVector<uint32_t, 4> operands;
unsigned *literEnd = literal + literalSize;
operands.insert(operands.end(), literal, literEnd);
SpirvDecoration *decor = new (context) SpirvDecoration(
srcLoc, targetInst, static_cast<spv::Decoration>(decorate), operands);
assert(decor != nullptr);
mod->addDecoration(decor);
}

void SpirvBuilder::decorateString(SpirvInstruction *target, unsigned decorate,
llvm::StringRef strLiteral,
llvm::Optional<uint32_t> memberIdx) {

auto *decor = new (context) SpirvDecoration(
target->getSourceLocation(), target,
static_cast<spv::Decoration>(decorate), strLiteral, memberIdx);
mod->addDecoration(decor);
}

SpirvConstant *SpirvBuilder::getConstantInt(QualType type, llvm::APInt value,
bool specConst) {
// We do not reuse existing constant integers. Just create a new one.
Expand Down
4 changes: 4 additions & 0 deletions tools/clang/lib/SPIRV/SpirvEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1654,6 +1654,10 @@ void SpirvEmitter::doVarDecl(const VarDecl *decl) {
needsLegalization = true;
}

if (var != nullptr) {
declIdMapper.decorateVariableWithIntrinsicAttrs(decl, var);
}

// All variables that are of opaque struct types should request legalization.
if (!needsLegalization && isOpaqueStructType(decl->getType()))
needsLegalization = true;
Expand Down
17 changes: 7 additions & 10 deletions tools/clang/lib/SPIRV/SpirvInstruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ SpirvDecoration::SpirvDecoration(SourceLocation loc,
spv::Decoration decor,
llvm::ArrayRef<uint32_t> p,
llvm::Optional<uint32_t> idx)
: SpirvInstruction(IK_Decoration, getDecorateOpcode(decor, idx),
: SpirvInstruction(IK_Decoration, getDecorateOpcode(false, idx),
/*type*/ {}, loc),
target(targetInst), targetFunction(nullptr), decoration(decor), index(idx),
params(p.begin(), p.end()), idParams() {}
Expand All @@ -235,7 +235,7 @@ SpirvDecoration::SpirvDecoration(SourceLocation loc,
spv::Decoration decor,
llvm::StringRef strParam,
llvm::Optional<uint32_t> idx)
: SpirvInstruction(IK_Decoration, getDecorateOpcode(decor, idx),
: SpirvInstruction(IK_Decoration, getDecorateOpcode(true, idx),
/*type*/ {}, loc),
target(targetInst), targetFunction(nullptr), decoration(decor), index(idx),
params(), idParams() {
Expand All @@ -261,14 +261,11 @@ SpirvDecoration::SpirvDecoration(SourceLocation loc, SpirvFunction *targetFunc,
index(llvm::None), params(p.begin(), p.end()), idParams() {}

spv::Op SpirvDecoration::getDecorateOpcode(
spv::Decoration decoration, const llvm::Optional<uint32_t> &memberIndex) {
if (decoration == spv::Decoration::HlslSemanticGOOGLE ||
decoration == spv::Decoration::UserTypeGOOGLE)
return memberIndex.hasValue() ? spv::Op::OpMemberDecorateStringGOOGLE
: spv::Op::OpDecorateStringGOOGLE;

return memberIndex.hasValue() ? spv::Op::OpMemberDecorate
: spv::Op::OpDecorate;
bool isString, const llvm::Optional<uint32_t> &memberIndex) {
return (isString) ? (memberIndex.hasValue() ? spv::Op::OpMemberDecorateString
: spv::Op::OpDecorateString)
: (memberIndex.hasValue() ? spv::Op::OpMemberDecorate
: spv::Op::OpDecorate);
}

bool SpirvDecoration::operator==(const SpirvDecoration &that) const {
Expand Down
17 changes: 17 additions & 0 deletions tools/clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12068,6 +12068,23 @@ void hlsl::HandleDeclAttributeForHLSL(Sema &S, Decl *D, const AttributeList &A,
declAttr = ::new (S.Context) VKReferenceExtAttr(
A.getRange(), S.Context, A.getAttributeSpellingListIndex());
break;
case AttributeList::AT_VKDecorateExt: {
llvm::SmallVector<unsigned, 3> args;
auto argNum = A.getNumArgs();
for (unsigned i = 0; i < argNum; ++i) {
args.push_back(unsigned(ValidateAttributeIntArg(S, A, i)));
}
unsigned *literal = (argNum > 1) ? &args[1] : nullptr;
declAttr = ::new (S.Context)
VKDecorateExtAttr(A.getRange(), S.Context, args[0], literal, argNum - 1,
A.getAttributeSpellingListIndex());
} break;
case AttributeList::AT_VKDecorateStringExt:
declAttr = ::new (S.Context) VKDecorateStringExtAttr(
A.getRange(), S.Context, unsigned(ValidateAttributeIntArg(S, A)),
ValidateAttributeStringArg(S, A, nullptr, 1),
A.getAttributeSpellingListIndex());
break;
default:
Handled = false;
return;
Expand Down
39 changes: 39 additions & 0 deletions tools/clang/test/CodeGenSPIRV/spv.intrinsicDecorate.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Run: %dxc -T ps_6_0 -E main -fcgl -Vd -spirv

[[vk::ext_decorate(1, 0)]]
bool b0;

[[vk::ext_decorate(30, 23)]]
float4 main(

//CHECK: OpDecorate {{%\w+}} SpecId 0
//CHECK: OpDecorate {{%\w+}} BuiltIn BaryCoordNoPerspAMD
//CHECK: OpDecorate {{%\w+}} BuiltIn BaryCoordNoPerspCentroidAMD
//CHECK: OpDecorate {{%\w+}} BuiltIn BaryCoordNoPerspSampleAMD
//CHECK: OpDecorate {{%\w+}} BuiltIn BaryCoordSmoothAMD
//CHECK: OpDecorate {{%\w+}} BuiltIn BaryCoordSmoothCentroidAMD
//CHECK: OpDecorate {{%\w+}} BuiltIn BaryCoordSmoothSampleAMD
//CHECK: OpDecorate {{%\w+}} BuiltIn BaryCoordPullModelAMD
//CHECK: OpDecorate {{%\w+}} ExplicitInterpAMD
//CHECK: OpDecorate {{%\w+}} Location 23
//CHECK: OpDecorateString {{%\w+}} UserSemantic "return variable"
//CHECK: OpDecorate {{%\w+}} FPRoundingMode RTE

// spv::Decoration::builtIn = 11
[[vk::ext_decorate(11, 4992)]] float2 b0 : COLOR0,
[[vk::ext_decorate(11, 4993)]] float2 b1 : COLOR1,
[[vk::ext_decorate(11, 4994)]] float2 b2 : COLOR2,
[[vk::ext_decorate(11, 4995)]] float2 b3 : COLOR3,
[[vk::ext_decorate(11, 4996)]] float2 b4 : COLOR4,
[[vk::ext_decorate(11, 4997)]] float2 b5 : COLOR5,
[[vk::ext_decorate(11, 4998)]] float2 b6 : COLOR6,
// ExplicitInterpAMD
[[vk::location(12), vk::ext_decorate(4999)]] float2 b7 : COLOR7
) : SV_Target {

// spv::Decoration::FPRoundingMode = 39, RTZ=0
[[vk::ext_decorate(39, 0), vk::ext_decorate_string(5635, "return variable")]] float4 ret = 1.0;
ret.xy = b0 * b1 + b2 + b3 + b4;
ret.zw = b5 + b6 + b7;
return ret;
}
1 change: 1 addition & 0 deletions tools/clang/unittests/SPIRV/CodeGenSpirvTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1342,6 +1342,7 @@ TEST_F(FileTest, IntrinsicsVkQueueFamilyScope) {
TEST_F(FileTest, IntrinsicsSpirv) {
runFileTest("spv.intrinsicInstruction.hlsl");
runFileTest("spv.intrinsicLiteral.hlsl");
runFileTest("spv.intrinsicDecorate.hlsl", Expect::Success, false);
runFileTest("spv.intrinsic.reference.error.hlsl", Expect::Failure);
}
TEST_F(FileTest, IntrinsicsVkReadClock) {
Expand Down

0 comments on commit 7057642

Please sign in to comment.