summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorTheresa Foley <10618364+tangent-vector@users.noreply.github.com>2023-06-13 14:40:02 -0700
committerGitHub <noreply@github.com>2023-06-13 17:40:02 -0400
commitf161686e8e260a4b0e6e0a773cf1cf16069f41bf (patch)
tree1daf16da7f0826eb26cf352b0fab9aa1c61b4327 /source
parentb255ef068b77a45fdd0b595a555386928a61d56e (diff)
Fixes for Shader Execution Reordering on VK (#2929)
* Fixes for Shader Execution Reordering on VK There are some mismatches between the way that hit objects are handled between the current NVAPI/HLSL and proposed GLSL extensions for shader execution reordering. These mismatches create complications for generating valid GLSL/SPIR-V code from input Slang. Many of the problems that apply to `HitObject` also apply to the existing `RayQuery<>` type used for "inline" ray tracing. In the case of `RayQuery<>` we have that for *both* HLSL and GLSL/SPIR-V: * A `RayQuery` (or `rayQueryEXT`) is an opaque handle to underlying mutable storage * The storage that backs a `RayQuery` is allocated as part of the "defualt constructor" for a local variable declared with type `RayQuery`. * The `RayQuery` API provides numerous operations that mutate the storage referred to by the opaque handle. The key difference between HLSL and GLSL/SPIR-V for the case of a `RayQuery` amounts to: * In HLSL, local variables of type `RayQuery` can be assigned to, and assignment has by-reference semantics. It is possible to create multiple aliased handles to the same underlying storage. * In GLSL/SPIR-V, local variables of type `rayQueryEXT` cannot be assigned to, returned from functions, etc. It is impossible to create multiple aliased handles to the same underlying storage. The case for `HitObject`s is signicantly *more* messy, because: * In NVAPI/HLSL a `HitObject` is effectively a "value type" in that it only exposes constructors, and there is no way to mutate the state of a `HitObject` other than by assignment to a variable of that type. It makes no semantic difference whether a `HitObject` directly stores the value(s), or if it is a handle, since there is no way to introduce aliasing of mutable state. Assignment of `HitObject`s semantically creates a copy. * In GLSL/SPIR-V, a `hitObjectNV` is, like a `rayQueryEXT`, a handle to underlying mutable state. These handles cannot be assigned, returned from functions, etc. There is no way to make a copy of a hit object. This change includes several changes to how *both* `RayQuery<>` and `HitObject` are implemented, with the intention of getting more cases to work correctly when compiling for GLSL/SPIR-V, and to set up a more clear mental model for the semantics we want to give to these types in Slang, and how those semantics can/should map to our targets. An overview of important changes: * Marked a few operations on `RayQuery` as `[mutating]` that realistically should have already been that way. * Marked the `HitObject` type as being non-copyable (an attribute we do not currently enforce), and marked the various GLSL operations that construct a hit object as having an `out` parameter of the `HitObject` type (even if they are nominally specified in GLSL as not writing to the correspondign parameter). * Added a distinct IR opcode (`allocateOpaqueHandle`) to represent the implicit allocation that happens when declaring a variable of type `HitObject` or `RayQuery`, and made the "implicit constructor" for those types map to the new op. This operation took a lot of tweaking to get emitting in a reasonable way, and I'm still not 100% sure that all of the emission-related logic for it is strictly required (or correct). * Added new IR instructions for `HitObject` and `RayQuery` types, and made the stdlib types map to those IR instructions. * Treat `HitObject` and `RayQuery` as resource types for the purpose of our existing pass that specializes calls to functions that have outputs of resource type * Added a new test case that includes a function that returns a `HitObject` as its result. * Many test cases saw slight changes in their output (especially around the relative ordering of declarations of `HitObject`s and `RayQuery`s with other instructions) * Remove debugging logic
Diffstat (limited to 'source')
-rw-r--r--source/slang/hlsl.meta.slang59
-rw-r--r--source/slang/slang-emit-c-like.cpp117
-rw-r--r--source/slang/slang-emit-c-like.h6
-rw-r--r--source/slang/slang-emit-glsl.cpp65
-rw-r--r--source/slang/slang-emit-glsl.h3
-rw-r--r--source/slang/slang-emit-hlsl.cpp37
-rw-r--r--source/slang/slang-emit-hlsl.h2
-rw-r--r--source/slang/slang-ir-inst-defs.h5
-rw-r--r--source/slang/slang-ir-specialize-resources.cpp5
-rw-r--r--source/slang/slang-ir.cpp1
-rw-r--r--source/slang/slang-ir.h10
-rw-r--r--source/slang/slang-lower-to-ir.cpp2
12 files changed, 271 insertions, 41 deletions
diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang
index 40a372a32..b42e17fbe 100644
--- a/source/slang/hlsl.meta.slang
+++ b/source/slang/hlsl.meta.slang
@@ -5702,13 +5702,41 @@ static const CANDIDATE_TYPE CANDIDATE_PROCEDURAL_PRIMITIVE = 1;
// code can resume to continue tracing the ray, and which yields
// back to the user code at interesting events along the ray.
//
-__target_intrinsic(hlsl, RayQuery)
-__target_intrinsic(glsl, rayQueryEXT)
+// Note: The treatment of the `RayQuery` type in Slang does not
+// perfectly match its semantics in vanilla HLSL in some corner
+// cases. Specifically, a `RayQuery` in vanilla HLSL is an
+// opaque handle to mutable storage, and assigning a `RayQuery`
+// or passing one as a parameter will only copy the *handle*,
+// potentially resulting in aliasing of the underlying mutable
+// storage.
+//
+// In contrast, Slang considers a `RayQuery` to own its mutable
+// state, and (because the API does not support cloning of queries),
+// `RayQuery` values are non-copyable (aka "move-only").
+//
+// The main place where this arises as a consideration is when
+// passing a `RayQuery` down into a function that will perform
+// mutating operations on it (e.g., `TraceRay` or `Proceed`):
+//
+// void myFunc( inout RayQuery<FLAGS> q )
+// {
+// q.Proceed();
+// }
+//
+// In Slang, a parameter like `q` above should be declared `inout`.
+// HLSL does not care about whether `q` is declared `inout` or not.
+//
__glsl_extension(GL_EXT_ray_query)
__glsl_version(460)
[__NonCopyableType]
+__intrinsic_type($(kIROp_RayQueryType))
struct RayQuery <let rayFlagsGeneric : RAY_FLAG = RAY_FLAG_NONE>
{
+ // Create a new ray query, initialized to its default state.
+ //
+ __intrinsic_op($(kIROp_AllocateOpaqueHandle))
+ __init();
+
// Initialize a ray-tracing query.
//
// This method may be called on a "fresh" ray query, or
@@ -5733,6 +5761,7 @@ struct RayQuery <let rayFlagsGeneric : RAY_FLAG = RAY_FLAG_NONE>
__target_intrinsic(glsl, "rayQueryInitializeEXT($0, $1, $2, $3, $4, $5, $6, $7)")
__glsl_extension(GL_EXT_ray_query)
__glsl_version(460)
+ [mutating]
void __rayQueryInitializeEXT(
RaytracingAccelerationStructure accelerationStructure,
RAY_FLAG rayFlags,
@@ -5745,6 +5774,7 @@ struct RayQuery <let rayFlagsGeneric : RAY_FLAG = RAY_FLAG_NONE>
[__unsafeForceInlineEarly]
__specialized_for_target(glsl)
[__NoSideEffect]
+ [mutating]
void TraceRayInline(
RaytracingAccelerationStructure accelerationStructure,
RAY_FLAG rayFlags,
@@ -6114,12 +6144,15 @@ int __hitObjectAttributesLocation(__ref Attributes attributes);
/// or as a key in ReorderThread. Created by one of several methods described below. HitObject
/// and its related functions are available in raytracing shader types only.
[__requiresNVAPI]
-__target_intrinsic(hlsl, NvHitObject)
__glsl_extension(GL_NV_shader_invocation_reorder)
__glsl_extension(GL_EXT_ray_tracing)
-__target_intrinsic(glsl, hitObjectNV)
+[__NonCopyableType]
+__intrinsic_type($(kIROp_HitObjectType))
struct HitObject
{
+ __intrinsic_op($(kIROp_AllocateOpaqueHandle))
+ __init();
+
/// Executes ray traversal (including anyhit and intersection shaders) like TraceRay, but returns the
/// resulting hit information as a HitObject and does not trigger closesthit or miss shaders.
__specialized_for_target(hlsl)
@@ -6672,7 +6705,7 @@ struct HitObject
__glsl_extension(GL_EXT_ray_tracing)
__target_intrinsic(glsl, "hitObjectRecordMissNV")
static void __glslMakeMiss(
- HitObject hitObj,
+ out HitObject hitObj,
uint MissShaderIndex,
float3 Origin,
float TMin,
@@ -6685,7 +6718,7 @@ struct HitObject
__glsl_extension(GL_NV_ray_tracing_motion_blur)
__target_intrinsic(glsl, "hitObjectRecordMissNV")
static void __glslMakeMotionMiss(
- HitObject hitObj,
+ out HitObject hitObj,
uint MissShaderIndex,
float3 Origin,
float TMin,
@@ -6696,7 +6729,7 @@ struct HitObject
__glsl_extension(GL_NV_shader_invocation_reorder)
__glsl_extension(GL_EXT_ray_tracing)
__target_intrinsic(glsl, "hitObjectRecordEmptyNV($0)")
- static void __glslMakeNop(HitObject hitObj);
+ static void __glslMakeNop(out HitObject hitObj);
__glsl_extension(GL_NV_shader_invocation_reorder)
__target_intrinsic(glsl, "hitObjectGetObjectRayDirectionNV($0)")
@@ -6719,7 +6752,7 @@ struct HitObject
__glsl_extension(GL_EXT_ray_tracing)
__target_intrinsic(glsl, "hitObjectRecordHitWithIndexNV")
static void __glslMakeHitWithIndex(
- HitObject hitObj,
+ out HitObject hitObj,
RaytracingAccelerationStructure accelerationStructure,
int instanceid,
int primitiveid,
@@ -6738,7 +6771,7 @@ struct HitObject
__glsl_extension(GL_NV_ray_tracing_motion_blur)
__target_intrinsic(glsl, "hitObjectRecordHitWithIndexMotionNV")
static void __glslMakeMotionHitWithIndex(
- HitObject hitObj,
+ out HitObject hitObj,
RaytracingAccelerationStructure accelerationStructure,
int instanceid,
int primitiveid,
@@ -6757,7 +6790,7 @@ struct HitObject
__glsl_extension(GL_NV_shader_invocation_reorder)
__target_intrinsic(glsl, "hitObjectRecordHitNV")
static void __glslMakeHit(
- HitObject hitObj,
+ out HitObject hitObj,
RaytracingAccelerationStructure accelerationStructure,
int instanceid,
int primitiveid,
@@ -6777,7 +6810,7 @@ struct HitObject
__glsl_extension(GL_NV_ray_tracing_motion_blur)
__target_intrinsic(glsl, "hitObjectRecordHitMotionNV")
static void __glslMakeMotionHit(
- HitObject hitObj,
+ out HitObject hitObj,
RaytracingAccelerationStructure accelerationStructure,
int instanceid,
int primitiveid,
@@ -6802,7 +6835,7 @@ struct HitObject
__glsl_extension(GL_NV_shader_invocation_reorder)
__target_intrinsic(glsl, "hitObjectTraceRayNV")
static void __glslTraceRay(
- HitObject hitObj,
+ out HitObject hitObj,
RaytracingAccelerationStructure accelerationStructure,
uint rayFlags,
uint cullMask,
@@ -6820,7 +6853,7 @@ struct HitObject
__glsl_extension(GL_NV_ray_tracing_motion_blur)
__target_intrinsic(glsl, "hitObjectTraceRayMotionNV")
static void __glslTraceMotionRay(
- HitObject hitObj,
+ out HitObject hitObj,
RaytracingAccelerationStructure accelerationStructure,
uint rayFlags,
uint cullMask,
diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp
index 75d7b3cf8..c7ea3a09a 100644
--- a/source/slang/slang-emit-c-like.cpp
+++ b/source/slang/slang-emit-c-like.cpp
@@ -1239,10 +1239,12 @@ bool CLikeSourceEmitter::shouldFoldInstIntoUseSites(IRInst* inst)
{
return true;
}
+ if (as<IRHitObjectType>(type))
+ {
+ return true;
+ }
}
-
-
// If the instruction is at global scope, then it might represent
// a constant (e.g., the value of an enum case).
//
@@ -1292,6 +1294,7 @@ bool CLikeSourceEmitter::shouldFoldInstIntoUseSites(IRInst* inst)
// definition for certain types on certain targets (e.g. `out TriangleStream<T>`
// for GLSL), so we check this only after all those special cases are
// considered.
+ //
if (inst->getOp() == kIROp_undefined)
return false;
@@ -1382,6 +1385,7 @@ bool CLikeSourceEmitter::shouldFoldInstIntoUseSites(IRInst* inst)
if(inst->getParent() != user->getParent())
return false;
+
// Now let's look at all the instructions between this instruction
// and the user. If any of them might have side effects, then lets
// bail out now.
@@ -1410,6 +1414,25 @@ bool CLikeSourceEmitter::shouldFoldInstIntoUseSites(IRInst* inst)
if(as<IRUnconditionalBranch>(user))
return false;
+ // HACK: As a special case, an `allocateOpaqueHandle` operation should
+ // only be folded in if its only use is as the operand of a `store`
+ // that will *itself* get peephole merged in as the initial-value expression
+ // of a `var`:
+ //
+ if (inst->getOp() == kIROp_AllocateOpaqueHandle)
+ {
+ auto store = as<IRStore>(user);
+ if (!store) return false;
+ if (store->getVal() != inst) return false;
+
+ auto var = as<IRVar>(store->getPtr());
+ if (!var) return false;
+
+ if(var->getNextInst() != store) return false;
+
+ return true;
+ }
+
// Okay, if we reach this point then the user comes later in
// the same block, and there are no instructions with side
// effects in between, so it seems safe to fold things in.
@@ -1843,6 +1866,7 @@ void CLikeSourceEmitter::defaultEmitInstExpr(IRInst* inst, const EmitOpInfo& inO
case kIROp_undefined:
case kIROp_DefaultConstruct:
+ case kIROp_AllocateOpaqueHandle:
m_writer->emit(getName(inst));
break;
@@ -2441,19 +2465,13 @@ void CLikeSourceEmitter::_emitInst(IRInst* inst)
case kIROp_DefaultConstruct:
{
auto type = inst->getDataType();
- emitType(type, getName(inst));
+ _emitInstAsDefaultInitializedVar(inst, type);
+ }
+ break;
- // On targets that support empty initializers, we will emit it.
- switch (this->getTarget())
- {
- case CodeGenTarget::CPPSource:
- case CodeGenTarget::HostCPPSource:
- case CodeGenTarget::PyTorchCppBinding:
- case CodeGenTarget::CUDASource:
- m_writer->emit(" = {}");
- break;
- }
- m_writer->emit(";\n");
+ case kIROp_AllocateOpaqueHandle:
+ {
+ _emitAllocateOpaqueHandleImpl(inst);
}
break;
@@ -2466,17 +2484,8 @@ void CLikeSourceEmitter::_emitInst(IRInst* inst)
case kIROp_Store:
{
- if (inst->getPrevInst() == inst->getOperand(0) && inst->getOperand(0)->getOp() == kIROp_Var)
- {
- // If we are storing into a var that is defined right before the store, we have
- // already folded the store in the initialization of the var, so we can skip here.
- break;
- }
- auto prec = getInfo(EmitOp::Assign);
- emitDereferenceOperand(inst->getOperand(0), leftSide(getInfo(EmitOp::General), prec));
- m_writer->emit(" = ");
- emitOperand(inst->getOperand(1), rightSide(prec, getInfo(EmitOp::General)));
- m_writer->emit(";\n");
+ auto store = cast<IRStore>(inst);
+ emitStore(store);
}
break;
@@ -2620,6 +2629,51 @@ void CLikeSourceEmitter::_emitInst(IRInst* inst)
}
}
+void CLikeSourceEmitter::emitStore(IRStore* store)
+{
+ if (store->getPrevInst() == store->getOperand(0) && store->getOperand(0)->getOp() == kIROp_Var)
+ {
+ // If we are storing into a `var` that is defined right before the store, we have
+ // already folded the store in the initialization of the `var`, so we can skip here.
+ //
+ return;
+ }
+ _emitStoreImpl(store);
+}
+
+void CLikeSourceEmitter::_emitStoreImpl(IRStore* store)
+{
+ auto srcVal = store->getVal();
+ auto dstPtr = store->getPtr();
+ auto prec = getInfo(EmitOp::Assign);
+ emitDereferenceOperand(dstPtr, leftSide(getInfo(EmitOp::General), prec));
+ m_writer->emit(" = ");
+ emitOperand(srcVal, rightSide(prec, getInfo(EmitOp::General)));
+ m_writer->emit(";\n");
+}
+
+void CLikeSourceEmitter::_emitInstAsDefaultInitializedVar(IRInst* inst, IRType* type)
+{
+ emitType(type, getName(inst));
+
+ // On targets that support empty initializers, we will emit it.
+ switch (this->getTarget())
+ {
+ case CodeGenTarget::CPPSource:
+ case CodeGenTarget::HostCPPSource:
+ case CodeGenTarget::PyTorchCppBinding:
+ case CodeGenTarget::CUDASource:
+ m_writer->emit(" = {}");
+ break;
+ }
+ m_writer->emit(";\n");
+}
+
+void CLikeSourceEmitter::_emitAllocateOpaqueHandleImpl(IRInst* allocateInst)
+{
+ _emitInstAsDefaultInitializedVar(allocateInst, allocateInst->getDataType());
+}
+
void CLikeSourceEmitter::emitSemanticsUsingVarLayout(IRVarLayout* varLayout)
{
if(auto semanticAttr = varLayout->findAttr<IRSemanticAttr>())
@@ -3415,18 +3469,27 @@ void CLikeSourceEmitter::emitVar(IRVar* varDecl)
emitLayoutSemantics(varDecl);
+ // TODO: ideally this logic should scan ahead to see if it can find a `store`
+ // instruction that writes to the `var`, within the same block, such that all
+ // of the intervening instructions are safe to fold.
+ //
if (auto store = as<IRStore>(varDecl->getNextInst()))
{
if (store->getPtr() == varDecl)
{
- m_writer->emit(" = ");
- emitOperand(store->getVal(), getInfo(EmitOp::General));
+ _emitInstAsVarInitializerImpl(store->getVal());
}
}
m_writer->emit(";\n");
}
+void CLikeSourceEmitter::_emitInstAsVarInitializerImpl(IRInst* inst)
+{
+ m_writer->emit(" = ");
+ emitOperand(inst, getInfo(EmitOp::General));
+}
+
void CLikeSourceEmitter::emitGlobalVar(IRGlobalVar* varDecl)
{
auto allocatedType = varDecl->getDataType();
diff --git a/source/slang/slang-emit-c-like.h b/source/slang/slang-emit-c-like.h
index 393ab602c..636faad46 100644
--- a/source/slang/slang-emit-c-like.h
+++ b/source/slang/slang-emit-c-like.h
@@ -307,6 +307,12 @@ public:
void emitVal(IRInst* val, const EmitOpInfo& outerPrec);
+ void emitStore(IRStore* store);
+ virtual void _emitStoreImpl(IRStore* store);
+ virtual void _emitInstAsVarInitializerImpl(IRInst* inst);
+ void _emitInstAsDefaultInitializedVar(IRInst* inst, IRType* type);
+ virtual void _emitAllocateOpaqueHandleImpl(IRInst* allocateInst);
+
UInt getBindingOffset(EmitVarChain* chain, LayoutResourceKind kind);
UInt getBindingSpace(EmitVarChain* chain, LayoutResourceKind kind);
diff --git a/source/slang/slang-emit-glsl.cpp b/source/slang/slang-emit-glsl.cpp
index bc170dadc..a86971bf5 100644
--- a/source/slang/slang-emit-glsl.cpp
+++ b/source/slang/slang-emit-glsl.cpp
@@ -869,6 +869,61 @@ void GLSLSourceEmitter::emitLoopControlDecorationImpl(IRLoopControlDecoration* d
}
}
+void GLSLSourceEmitter::_emitInstAsVarInitializerImpl(IRInst* inst)
+{
+ // Some opcodes can be folded into a variable initialization
+ // by allowing the variable to be "default-constructed."
+ //
+ switch (inst->getOp())
+ {
+ case kIROp_AllocateOpaqueHandle:
+ //
+ // Note: semantically, we should only elide the initializer
+ // if `inst` is able to be folded here, since otherwise
+ // it could be a single allocation that is used to initialize
+ // multiple local variables (which should then alias the
+ // same location).
+ //
+ // However, since GlSL doesn't support assignment of opaque
+ // handle types, code will fail to compile downstream in
+ // the case where the initializer *doesn't* fold.
+ //
+ // The decision being made here should help ensure that we
+ // don't emit code that silently has different semantics
+ // than the input.
+ //
+ if (shouldFoldInstIntoUseSites(inst))
+ {
+ return;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // We fall back to the default behavior for all targets,
+ // which is to emit `inst` as an initial-value expression
+ // after an `=`.
+ //
+ Super::_emitInstAsVarInitializerImpl(inst);
+}
+
+void GLSLSourceEmitter::_emitStoreImpl(IRStore* store)
+{
+ auto srcVal = store->getVal();
+ switch (srcVal->getOp())
+ {
+ default:
+ Super::_emitStoreImpl(store);
+ break;
+
+ case kIROp_AllocateOpaqueHandle:
+ break;
+ }
+
+}
+
void GLSLSourceEmitter::_emitSpecialFloatImpl(IRType* type, const char* valueExpr)
{
if( type->getOp() != kIROp_FloatType )
@@ -2153,6 +2208,16 @@ void GLSLSourceEmitter::emitSimpleTypeImpl(IRType* type)
m_writer->emit("int");
return;
}
+ case kIROp_RayQueryType:
+ {
+ m_writer->emit("rayQueryEXT");
+ return;
+ }
+ case kIROp_HitObjectType:
+ {
+ m_writer->emit("hitObjectNV");
+ return;
+ }
default: break;
}
diff --git a/source/slang/slang-emit-glsl.h b/source/slang/slang-emit-glsl.h
index 48c6971aa..757955677 100644
--- a/source/slang/slang-emit-glsl.h
+++ b/source/slang/slang-emit-glsl.h
@@ -52,6 +52,9 @@ protected:
virtual void emitSimpleValueImpl(IRInst* inst) SLANG_OVERRIDE;
virtual void emitLoopControlDecorationImpl(IRLoopControlDecoration* decl) SLANG_OVERRIDE;
+ virtual void _emitInstAsVarInitializerImpl(IRInst* inst) SLANG_OVERRIDE;
+ virtual void _emitStoreImpl(IRStore* store) SLANG_OVERRIDE;
+
void _emitGLSLTextureOrTextureSamplerType(IRTextureTypeBase* type, char const* baseName);
void _emitGLSLStructuredBuffer(IRGlobalParam* varDecl, IRHLSLStructuredBufferTypeBase* structuredBufferType);
diff --git a/source/slang/slang-emit-hlsl.cpp b/source/slang/slang-emit-hlsl.cpp
index 96b751789..3f6e79f4a 100644
--- a/source/slang/slang-emit-hlsl.cpp
+++ b/source/slang/slang-emit-hlsl.cpp
@@ -897,6 +897,18 @@ void HLSLSourceEmitter::emitSimpleTypeImpl(IRType* type)
m_writer->emit("int");
return;
}
+ case kIROp_RayQueryType:
+ {
+ m_writer->emit("RayQuery<");
+ emitSimpleValue(type->getOperand(0));
+ m_writer->emit(" >");
+ return;
+ }
+ case kIROp_HitObjectType:
+ {
+ m_writer->emit("HitObject");
+ return;
+ }
default: break;
}
@@ -1095,6 +1107,31 @@ void HLSLSourceEmitter::_emitPrefixTypeAttr(IRAttr* attr)
}
}
+void HLSLSourceEmitter::_emitInstAsVarInitializerImpl(IRInst* inst)
+{
+ // Some opcodes can be folded into a variable initialization
+ // by allowing the variable to be "default-constructed."
+ //
+ switch (inst->getOp())
+ {
+ case kIROp_AllocateOpaqueHandle:
+ if (shouldFoldInstIntoUseSites(inst))
+ {
+ return;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // We fall back to the default behavior for all targets,
+ // which is to emit `inst` as an initial-value expression
+ // after an `=`.
+ //
+ Super::_emitInstAsVarInitializerImpl(inst);
+}
+
void HLSLSourceEmitter::emitSimpleFuncParamImpl(IRParam* param)
{
emitRateQualifiers(param);
diff --git a/source/slang/slang-emit-hlsl.h b/source/slang/slang-emit-hlsl.h
index d69e054b4..2e4eb29b9 100644
--- a/source/slang/slang-emit-hlsl.h
+++ b/source/slang/slang-emit-hlsl.h
@@ -61,6 +61,8 @@ protected:
void _emitPrefixTypeAttr(IRAttr* attr) SLANG_OVERRIDE;
+ virtual void _emitInstAsVarInitializerImpl(IRInst* inst) SLANG_OVERRIDE;
+
// Emit a single `register` semantic, as appropriate for a given resource-type-specific layout info
// Keyword to use in the uniform case (`register` for globals, `packoffset` inside a `cbuffer`)
void _emitHLSLRegisterSemantic(LayoutResourceKind kind, EmitVarChain* chain, char const* uniformSemanticSpelling = "register");
diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h
index da0c3618d..fc020403d 100644
--- a/source/slang/slang-ir-inst-defs.h
+++ b/source/slang/slang-ir-inst-defs.h
@@ -204,7 +204,8 @@ INST(Nop, nop, 0, 0)
INST_RANGE(PointerLikeType, ConstantBufferType, GLSLOutputParameterGroupType)
INST_RANGE(BuiltinGenericType, HLSLPointStreamType, GLSLOutputParameterGroupType)
-
+INST(RayQueryType, RayQuery, 1, HOISTABLE)
+INST(HitObjectType, HitObject, 0, HOISTABLE)
// A user-defined structure declaration at the IR level.
@@ -617,6 +618,8 @@ INST(AllocateTorchTensor, allocTorchTensor, 0, 0)
INST(TorchGetCudaStream, TorchGetCudaStream, 0, 0)
INST(TorchTensorGetView, TorchTensorGetView, 0, 0)
+INST(AllocateOpaqueHandle, allocateOpaqueHandle, 0, 0)
+
/* Decoration */
INST(HighLevelDeclDecoration, highLevelDecl, 1, 0)
diff --git a/source/slang/slang-ir-specialize-resources.cpp b/source/slang/slang-ir-specialize-resources.cpp
index 3d28e0bb0..09c8f1f22 100644
--- a/source/slang/slang-ir-specialize-resources.cpp
+++ b/source/slang/slang-ir-specialize-resources.cpp
@@ -352,6 +352,11 @@ struct ResourceOutputSpecializationPass
if(as<IRSamplerStateTypeBase>(type))
return true;
+ if(as<IRHitObjectType>(type))
+ return true;
+ if(as<IRRayQueryType>(type))
+ return true;
+
// TODO: more cases here?
return false;
diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp
index 72b65ea3e..0a001892a 100644
--- a/source/slang/slang-ir.cpp
+++ b/source/slang/slang-ir.cpp
@@ -7276,6 +7276,7 @@ namespace Slang
case kIROp_MakeTensorView:
case kIROp_TorchTensorGetView:
case kIROp_GetStringHash:
+ case kIROp_AllocateOpaqueHandle:
return false;
case kIROp_ForwardDifferentiate:
diff --git a/source/slang/slang-ir.h b/source/slang/slang-ir.h
index 66295b0fb..f5697c9e1 100644
--- a/source/slang/slang-ir.h
+++ b/source/slang/slang-ir.h
@@ -1625,6 +1625,16 @@ struct IRFuncType : IRType
IR_LEAF_ISA(FuncType)
};
+struct IRRayQueryType : IRType
+{
+ IR_LEAF_ISA(RayQueryType)
+};
+
+struct IRHitObjectType : IRType
+{
+ IR_LEAF_ISA(HitObjectType)
+};
+
bool isDefinition(
IRInst* inVal);
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index 144875e8c..937262758 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -2025,6 +2025,8 @@ struct ValLoweringVisitor : ValVisitor<ValLoweringVisitor, LoweredValInfo, Lower
// type with the appropriate opcode.
IRType* lowerSimpleIntrinsicType(DeclRefType* type)
{
+ SLANG_ASSERT(getBuilder()->getInsertLoc().getMode() != IRInsertLoc::Mode::None);
+
auto intrinsicTypeModifier = type->declRef.getDecl()->findModifier<IntrinsicTypeModifier>();
SLANG_ASSERT(intrinsicTypeModifier);
IROp op = IROp(intrinsicTypeModifier->irOp);