Skip to content
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
11 changes: 11 additions & 0 deletions include/dxc/Support/HLSLOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,17 @@ def Wno_vk_emulated_features : Joined<["-"], "Wno-vk-emulated-features">, Group<
HelpText<"Do not emit warnings for emulated features resulting from no direct mapping">;
def fspv_print_all: Flag<["-"], "fspv-print-all">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
HelpText<"Print the SPIR-V module before each pass and after the last one. Useful for debugging SPIR-V legalization and optimization passes.">;
def fspv_use_emulated_heap
: Flag<["-"], "fspv-use-emulated-heap">,
Group<spirv_Group>,
Flags<[CoreOption, DriverOption]>,
HelpText<
"Use emulated descriptor heap using descriptor indexing (default).">;
def fspv_use_descriptor_heap
: Flag<["-"], "fspv-use-descriptor-heap">,
Group<spirv_Group>,
Flags<[CoreOption, DriverOption]>,
HelpText<"Use SPV_EXT_descriptor_heap for HLSL descriptor heaps.">;
Comment on lines +432 to +442
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why do you need two options?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I was thinking about the migration for users:

  • extension is brand new, we don't want to push it
  • but long term, extension is better, so we want to encourage it.

Idea was to use the emulated by default for now, and in a future version, switch the default to use the extension, while allowing users to downgrade to emulation.
But no strong feeling about this.

Copy link
Collaborator

@s-perron s-perron Mar 24, 2026

Choose a reason for hiding this comment

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

We let fspv-use-descriptor-heap default to false now. Then if we flip it, people can use fno-spv-use-descriptor-heap. Right?

If we have the two options, we have the odd situation: what if both are set to true or both are set to false?

def Oconfig : CommaJoined<["-"], "Oconfig=">, Group<spirv_Group>, Flags<[CoreOption]>,
HelpText<"Specify a comma-separated list of SPIRV-Tools passes to customize optimization configuration (see http://khr.io/hlsl2spirv#optimization)">;
def fspv_preserve_bindings : Flag<["-"], "fspv-preserve-bindings">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
Expand Down
1 change: 1 addition & 0 deletions include/dxc/Support/SPIRVOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ struct SpirvCodeGenOptions {
bool enableMaximalReconvergence = false;
bool useVulkanMemoryModel = false;
bool useUnknownImageFormat = false;
bool useDescriptorHeap = false;
bool IEEEStrict = false;
/// Maximum length in words for the OpString literal containing the shader
/// source for DebugSource and DebugSourceContinued. If the source code length
Expand Down
5 changes: 5 additions & 0 deletions lib/DxcSupport/HLSLOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1139,6 +1139,9 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
opts.SpirvOptions.useUnknownImageFormat =
Args.hasFlag(OPT_fspv_use_unknown_image_format, OPT_INVALID, false);

opts.SpirvOptions.useDescriptorHeap = Args.hasFlag(
OPT_fspv_use_descriptor_heap, OPT_fspv_use_emulated_heap, false);

if (!handleVkShiftArgs(Args, OPT_fvk_b_shift, "b", &opts.SpirvOptions.bShift,
errors) ||
!handleVkShiftArgs(Args, OPT_fvk_t_shift, "t", &opts.SpirvOptions.tShift,
Expand Down Expand Up @@ -1295,6 +1298,8 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
Args.hasFlag(OPT_fspv_reflect, OPT_INVALID, false) ||
Args.hasFlag(OPT_fspv_fix_func_call_arguments, OPT_INVALID, false) ||
Args.hasFlag(OPT_fspv_print_all, OPT_INVALID, false) ||
Args.hasFlag(OPT_fspv_use_emulated_heap, OPT_INVALID, false) ||
Args.hasFlag(OPT_fspv_use_descriptor_heap, OPT_INVALID, false) ||
Args.hasFlag(OPT_Wno_vk_ignored_features, OPT_INVALID, false) ||
Args.hasFlag(OPT_Wno_vk_emulated_features, OPT_INVALID, false) ||
Args.hasFlag(OPT_fvk_auto_shift_bindings, OPT_INVALID, false) ||
Expand Down
2 changes: 2 additions & 0 deletions tools/clang/include/clang/SPIRV/FeatureManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ enum class Extension {
KHR_float_controls,
NV_shader_subgroup_partitioned,
KHR_quad_control,
EXT_descriptor_heap,
KHR_untyped_pointers,
Unknown,
};

Expand Down
29 changes: 23 additions & 6 deletions tools/clang/include/clang/SPIRV/SpirvBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,12 @@ class SpirvBuilder {
SpirvInstruction *sample,
SourceLocation);

/// \brief Creates an OpUntypedImageTexelPointerEXT SPIR-V instruction with
/// the given parameters.
SpirvUntypedImageTexelPointerEXT *createUntypedImageTexelPointerEXT(
QualType resultType, SpirvInstruction *image,
SpirvInstruction *coordinate, SpirvInstruction *sample, SourceLocation);

/// \brief Creates an OpConverPtrToU SPIR-V instruction with the given
/// parameters.
SpirvConvertPtrToU *createConvertPtrToU(SpirvInstruction *ptr, QualType type);
Expand Down Expand Up @@ -630,8 +636,7 @@ class SpirvBuilder {
/// support a single entry point per module for now.
inline void addEntryPoint(spv::ExecutionModel em, SpirvFunction *target,
llvm::StringRef targetName,
llvm::ArrayRef<SpirvVariable *> interfaces);

llvm::ArrayRef<SpirvVariableLike *> interfaces);
/// \brief Sets the shader model version, source file name, and source file
/// content. Returns the SpirvString instruction of the file name.
inline SpirvString *setDebugSource(uint32_t major, uint32_t minor,
Expand Down Expand Up @@ -708,6 +713,19 @@ class SpirvBuilder {
llvm::Optional<SpirvInstruction *> init = llvm::None,
SourceLocation loc = {});

/// \brief Adds an untyped module variable.
SpirvUntypedVariableKHR *
createUntypedVariableKHR(const SpirvType *valueType,
spv::StorageClass storageClass, llvm::StringRef name,
SourceLocation loc = {});

/// \brief Creates an OpUntypedAccessChainKHR instruction.
SpirvUntypedAccessChainKHR *
createUntypedAccessChainKHR(const SpirvType *resultType,
const SpirvType *baseType, SpirvInstruction *base,
llvm::ArrayRef<SpirvInstruction *> indexes,
SourceLocation loc);

/// \brief Decorates the given target with the given location.
void decorateLocation(SpirvInstruction *target, uint32_t location);

Expand Down Expand Up @@ -974,13 +992,12 @@ void SpirvBuilder::setMemoryModel(spv::AddressingModel addrModel,
mod->setMemoryModel(new (context) SpirvMemoryModel(addrModel, memModel));
}

void SpirvBuilder::addEntryPoint(spv::ExecutionModel em, SpirvFunction *target,
llvm::StringRef targetName,
llvm::ArrayRef<SpirvVariable *> interfaces) {
void SpirvBuilder::addEntryPoint(
spv::ExecutionModel em, SpirvFunction *target, llvm::StringRef targetName,
llvm::ArrayRef<SpirvVariableLike *> interfaces) {
mod->addEntryPoint(new (context) SpirvEntryPoint(
target->getSourceLocation(), em, target, targetName, interfaces));
}

SpirvString *
SpirvBuilder::setDebugSource(uint32_t major, uint32_t minor,
const std::vector<llvm::StringRef> &fileNames,
Expand Down
5 changes: 5 additions & 0 deletions tools/clang/include/clang/SPIRV/SpirvContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,8 @@ class SpirvContext {
const SpirvPointerType *getPointerType(const SpirvType *pointee,
spv::StorageClass);

const UntypedPointerKHRType *getUntypedPointerKHRType(spv::StorageClass sc);

FunctionType *getFunctionType(const SpirvType *ret,
llvm::ArrayRef<const SpirvType *> param);

Expand Down Expand Up @@ -531,6 +533,9 @@ class SpirvContext {
llvm::SmallVector<const HybridStructType *, 8> hybridStructTypes;
llvm::DenseMap<const SpirvType *, SCToPtrTyMap> pointerTypes;
llvm::SmallVector<const HybridPointerType *, 8> hybridPointerTypes;
llvm::DenseMap<spv::StorageClass, const UntypedPointerKHRType *,
StorageClassDenseMapInfo>
untypedPointerKHRTypes;
llvm::MapVector<QualType, const ForwardPointerType *> forwardPointerTypes;
llvm::MapVector<QualType, const SpirvPointerType *> forwardReferences;
llvm::DenseSet<FunctionType *, FunctionTypeMapInfo> functionTypes;
Expand Down
154 changes: 120 additions & 34 deletions tools/clang/include/clang/SPIRV/SpirvInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,20 @@ class SpirvInstruction {
// "Metadata" kinds
// In the order of logical layout

IK_Capability, // OpCapability
IK_Extension, // OpExtension
IK_ExtInstImport, // OpExtInstImport
IK_MemoryModel, // OpMemoryModel
IK_EntryPoint, // OpEntryPoint
IK_ExecutionMode, // OpExecutionMode
IK_ExecutionModeId, // OpExecutionModeId
IK_String, // OpString (debug)
IK_Source, // OpSource (debug)
IK_ModuleProcessed, // OpModuleProcessed (debug)
IK_Decoration, // Op*Decorate
IK_Type, // OpType*
IK_Variable, // OpVariable
IK_Capability, // OpCapability
IK_Extension, // OpExtension
IK_ExtInstImport, // OpExtInstImport
IK_MemoryModel, // OpMemoryModel
IK_EntryPoint, // OpEntryPoint
IK_ExecutionMode, // OpExecutionMode
IK_ExecutionModeId, // OpExecutionModeId
IK_String, // OpString (debug)
IK_Source, // OpSource (debug)
IK_ModuleProcessed, // OpModuleProcessed (debug)
IK_Decoration, // Op*Decorate
IK_Type, // OpType*
IK_Variable, // OpVariable
IK_UntypedVariableKHR, // OpUntypedVariableKHR

// Different kind of constants. Order matters.
IK_ConstantBoolean,
Expand All @@ -73,6 +74,7 @@ class SpirvInstruction {
// Pointer <-> uint conversions.
IK_ConvertPtrToU,
IK_ConvertUToPtr,
IK_BufferPointerEXT, // OpBufferPointerEXT

// OpUndef
IK_Undef,
Expand Down Expand Up @@ -101,6 +103,7 @@ class SpirvInstruction {
// In alphabetical order

IK_AccessChain, // OpAccessChain
IK_UntypedAccessChainKHR, // OpUntypedAccessChainKHR
IK_ArrayLength, // OpArrayLength
IK_Atomic, // OpAtomic*
IK_Barrier, // Op*Barrier
Expand All @@ -123,23 +126,24 @@ class SpirvInstruction {

IK_GroupNonUniformOp, // Group non-uniform operations

IK_ImageOp, // OpImage*
IK_ImageQuery, // OpImageQuery*
IK_ImageSparseTexelsResident, // OpImageSparseTexelsResident
IK_ImageTexelPointer, // OpImageTexelPointer
IK_Load, // OpLoad
IK_RayQueryOpKHR, // KHR rayquery ops
IK_RayTracingOpNV, // NV raytracing ops
IK_ReadClock, // OpReadClock
IK_SampledImage, // OpSampledImage
IK_Select, // OpSelect
IK_SpecConstantBinaryOp, // SpecConstant binary operations
IK_SpecConstantUnaryOp, // SpecConstant unary operations
IK_Store, // OpStore
IK_UnaryOp, // Unary operations
IK_NullaryOp, // Nullary operations
IK_VectorShuffle, // OpVectorShuffle
IK_SpirvIntrinsicInstruction, // Spirv Intrinsic Instructions
IK_ImageOp, // OpImage*
IK_ImageQuery, // OpImageQuery*
IK_ImageSparseTexelsResident, // OpImageSparseTexelsResident
IK_ImageTexelPointer, // OpImageTexelPointer
IK_UntypedImageTexelPointerEXT, // OpUntypedImageTexelPointerEXT
IK_Load, // OpLoad
IK_RayQueryOpKHR, // KHR rayquery ops
IK_RayTracingOpNV, // NV raytracing ops
IK_ReadClock, // OpReadClock
IK_SampledImage, // OpSampledImage
IK_Select, // OpSelect
IK_SpecConstantBinaryOp, // SpecConstant binary operations
IK_SpecConstantUnaryOp, // SpecConstant unary operations
IK_Store, // OpStore
IK_UnaryOp, // Unary operations
IK_NullaryOp, // Nullary operations
IK_VectorShuffle, // OpVectorShuffle
IK_SpirvIntrinsicInstruction, // Spirv Intrinsic Instructions

// For DebugInfo instructions defined in
// OpenCL.DebugInfo.100 and NonSemantic.Shader.DebugInfo.100
Expand Down Expand Up @@ -293,6 +297,14 @@ class SpirvInstruction {
bool isRasterizerOrdered_;
};

/// \brief class wrapping OpVariable and OpUntypedVariableKHR
class SpirvVariableLike : public SpirvInstruction {

protected:
SpirvVariableLike(Kind kind, spv::Op opcode, QualType astResultType,
SourceLocation loc, SourceRange range = {});
};

/// \brief OpCapability instruction
class SpirvCapability : public SpirvInstruction {
public:
Expand Down Expand Up @@ -387,7 +399,7 @@ class SpirvEntryPoint : public SpirvInstruction {
public:
SpirvEntryPoint(SourceLocation loc, spv::ExecutionModel executionModel,
SpirvFunction *entryPoint, llvm::StringRef nameStr,
llvm::ArrayRef<SpirvVariable *> iface);
llvm::ArrayRef<SpirvVariableLike *> iface);

DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvEntryPoint)

Expand All @@ -401,13 +413,15 @@ class SpirvEntryPoint : public SpirvInstruction {
spv::ExecutionModel getExecModel() const { return execModel; }
SpirvFunction *getEntryPoint() const { return entryPoint; }
llvm::StringRef getEntryPointName() const { return name; }
llvm::ArrayRef<SpirvVariable *> getInterface() const { return interfaceVec; }
llvm::ArrayRef<SpirvVariableLike *> getInterface() const {
return interfaceVec;
}

private:
spv::ExecutionModel execModel;
SpirvFunction *entryPoint;
std::string name;
llvm::SmallVector<SpirvVariable *, 8> interfaceVec;
llvm::SmallVector<SpirvVariableLike *, 8> interfaceVec;
};

class SpirvExecutionModeBase : public SpirvInstruction {
Expand Down Expand Up @@ -605,7 +619,7 @@ class SpirvDecoration : public SpirvInstruction {
};

/// \brief OpVariable instruction
class SpirvVariable : public SpirvInstruction {
class SpirvVariable : public SpirvVariableLike {
public:
SpirvVariable(QualType resultType, SourceLocation loc, spv::StorageClass sc,
bool isPrecise, bool isNointerp,
Expand Down Expand Up @@ -640,6 +654,52 @@ class SpirvVariable : public SpirvInstruction {
std::string hlslUserType;
};

/// \brief OpUntypedVariableKHR instruction
class SpirvUntypedVariableKHR : public SpirvVariableLike {
public:
SpirvUntypedVariableKHR(QualType resultType, SourceLocation loc,
spv::StorageClass sc);

SpirvUntypedVariableKHR(const SpirvType *spvType, SourceLocation loc,
spv::StorageClass sc);

DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvUntypedVariableKHR)

// For LLVM-style RTTI
static bool classof(const SpirvInstruction *inst) {
return inst->getKind() == IK_UntypedVariableKHR;
}

bool invokeVisitor(Visitor *v) override;
};

/// \brief Untyped Access Chain instruction representation
/// (OpUntypedAccessChainKHR)
class SpirvUntypedAccessChainKHR : public SpirvInstruction {
public:
SpirvUntypedAccessChainKHR(const SpirvType *resultType, SourceLocation loc,
const SpirvType *baseType, SpirvInstruction *base,
llvm::ArrayRef<SpirvInstruction *> indexVec);

DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvUntypedAccessChainKHR)

// For LLVM-style RTTI
static bool classof(const SpirvInstruction *inst) {
return inst->getKind() == IK_UntypedAccessChainKHR;
}

bool invokeVisitor(Visitor *v) override;

SpirvInstruction *getBase() const { return base; }
const SpirvType *getBaseType() const { return baseType; };
llvm::ArrayRef<SpirvInstruction *> getIndices() const { return indices; }

private:
const SpirvType *baseType;
SpirvInstruction *base;
llvm::SmallVector<SpirvInstruction *, 4> indices;
};

class SpirvFunctionParameter : public SpirvInstruction {
public:
SpirvFunctionParameter(QualType resultType, bool isPrecise, bool isNointerp,
Expand Down Expand Up @@ -2002,6 +2062,32 @@ class SpirvImageTexelPointer : public SpirvInstruction {
SpirvInstruction *sample;
};

class SpirvUntypedImageTexelPointerEXT : public SpirvInstruction {
public:
SpirvUntypedImageTexelPointerEXT(QualType resultType, SourceLocation loc,
SpirvInstruction *image,
SpirvInstruction *coordinate,
SpirvInstruction *sample);

DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvUntypedImageTexelPointerEXT)

// For LLVM-style RTTI
static bool classof(const SpirvInstruction *inst) {
return inst->getKind() == IK_UntypedImageTexelPointerEXT;
}

bool invokeVisitor(Visitor *v) override;

SpirvInstruction *getImage() const { return image; }
SpirvInstruction *getCoordinate() const { return coordinate; }
SpirvInstruction *getSample() const { return sample; }

private:
SpirvInstruction *image;
SpirvInstruction *coordinate;
SpirvInstruction *sample;
};

/// \brief Load instruction representation
class SpirvLoad : public SpirvInstruction {
public:
Expand Down
8 changes: 4 additions & 4 deletions tools/clang/include/clang/SPIRV/SpirvModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,11 @@ class SpirvModule {
SpirvExtInstImport *getExtInstSet(llvm::StringRef name);

// Adds a variable to the module.
void addVariable(SpirvVariable *);
void addVariable(SpirvVariableLike *);

// Adds a variable to the module immediately before `pos`.
// If `pos` is not found, `var` is added at the end of the variable list.
void addVariable(SpirvVariable *var, SpirvInstruction *pos);
void addVariable(SpirvVariableLike *var, SpirvInstruction *pos);

// Adds a decoration to the module.
void addDecoration(SpirvDecoration *);
Expand Down Expand Up @@ -172,7 +172,7 @@ class SpirvModule {
// Adds the given OpModuleProcessed to the module.
void addModuleProcessed(SpirvModuleProcessed *);

llvm::ArrayRef<SpirvVariable *> getVariables() const { return variables; }
llvm::ArrayRef<SpirvVariableLike *> getVariables() const { return variables; }

llvm::ArrayRef<SpirvEntryPoint *> getEntryPoints() const {
return entryPoints;
Expand Down Expand Up @@ -217,7 +217,7 @@ class SpirvModule {

std::vector<SpirvConstant *> constants;
std::vector<SpirvUndef *> undefs;
std::vector<SpirvVariable *> variables;
std::vector<SpirvVariableLike *> variables;
// A vector of functions in the module in the order that they should be
// emitted. The order starts with the entry-point function followed by a
// depth-first discovery of functions reachable from the entry-point function.
Expand Down
Loading
Loading