summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source/slang/core.meta.slang34
-rw-r--r--source/slang/hlsl.meta.slang70
-rw-r--r--source/slang/slang-ast-expr.h1
-rw-r--r--source/slang/slang-emit-spirv.cpp72
-rw-r--r--source/slang/slang-ir-inst-defs.h4
-rw-r--r--source/slang/slang-ir-insts.h1
-rw-r--r--source/slang/slang-ir-spirv-legalize.cpp134
-rw-r--r--source/slang/slang-ir-spirv-legalize.h3
-rw-r--r--source/slang/slang-ir.cpp12
-rw-r--r--source/slang/slang-lower-to-ir.cpp4
-rw-r--r--source/slang/slang-parser.cpp5
-rw-r--r--tests/pipeline/rasterization/conservative-rasterization/inner-coverage.slang8
-rw-r--r--tests/pipeline/rasterization/conservative-rasterization/inner-coverage.slang.glsl14
-rw-r--r--tests/pipeline/rasterization/fragment-shader-interlock.slang12
-rw-r--r--tests/pipeline/rasterization/get-attribute-at-vertex.slang9
15 files changed, 340 insertions, 43 deletions
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang
index e989e4ffa..55cf5896f 100644
--- a/source/slang/core.meta.slang
+++ b/source/slang/core.meta.slang
@@ -1760,16 +1760,42 @@ __target_intrinsic(cpp, "int(((char*)&($1)) - ((char*)&($0))")
int __offsetOf(in T t, in F field);
/// Mark beginning of "interlocked" operations in a fragment shader.
-__target_intrinsic(glsl, "beginInvocationInterlockARB")
__glsl_extension(GL_ARB_fragment_shader_interlock)
__glsl_version(420)
-void beginInvocationInterlock() {}
+void beginInvocationInterlock()
+{
+ __target_switch
+ {
+ case glsl:
+ __intrinsic_asm "beginInvocationInterlockARB";
+ case spirv:
+ spirv_asm {
+ OpCapability FragmentShaderPixelInterlockEXT;
+ OpExtension "SPV_EXT_fragment_shader_interlock";
+ OpExecutionMode __entryPoint PixelInterlockOrderedEXT;
+ OpBeginInvocationInterlockEXT;
+ };
+ }
+}
/// Mark end of "interlocked" operations in a fragment shader.
-__target_intrinsic(glsl, "endInvocationInterlockARB")
__glsl_extension(GL_ARB_fragment_shader_interlock)
__glsl_version(420)
-void endInvocationInterlock() {}
+void endInvocationInterlock()
+{
+ __target_switch
+ {
+ case glsl:
+ __intrinsic_asm "endInvocationInterlockARB";
+ case spirv:
+ spirv_asm {
+ OpCapability FragmentShaderPixelInterlockEXT;
+ OpExtension "SPV_EXT_fragment_shader_interlock";
+ OpExecutionMode __entryPoint PixelInterlockOrderedEXT;
+ OpEndInvocationInterlockEXT;
+ };
+ }
+}
// Operators to apply to `enum` types
diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang
index 5829a5109..d95c1e4d6 100644
--- a/source/slang/hlsl.meta.slang
+++ b/source/slang/hlsl.meta.slang
@@ -2898,15 +2898,26 @@ matrix<T, N, M> fwidth(matrix<T, N, M> x)
/// This function can be applied to scalars, vectors, and matrices of
/// built-in scalar types.
///
-/// Note: these functions are not curently implemented for Vulkan/SPIR-V output.
-///
__generic<T : __BuiltinType>
[__readNone]
-__target_intrinsic(hlsl)
-__target_intrinsic(GL_NV_fragment_shader_barycentric, "$0[$1]")
-__target_intrinsic(GL_EXT_fragment_shader_barycentric, "$0[$1]")
__glsl_version(450)
-T GetAttributeAtVertex(T attribute, uint vertexIndex);
+T GetAttributeAtVertex(T attribute, uint vertexIndex)
+{
+ __target_switch
+ {
+ case hlsl:
+ __intrinsic_asm "GetAttributeAtVertex";
+ case GL_NV_fragment_shader_barycentric:
+ case GL_EXT_fragment_shader_barycentric:
+ __intrinsic_asm "$0[$1]";
+ case spirv:
+ return spirv_asm {
+ %_ptr_Input_T = OpTypePointer Input $$T;
+ %addr = OpAccessChain %_ptr_Input_T $attribute $vertexIndex;
+ result:$$T = OpLoad %addr;
+ };
+ }
+}
/// Get the value of a vertex attribute at a specific vertex.
///
@@ -2920,15 +2931,26 @@ T GetAttributeAtVertex(T attribute, uint vertexIndex);
/// This function can be applied to scalars, vectors, and matrices of
/// built-in scalar types.
///
-/// Note: these functions are not curently implemented for Vulkan/SPIR-V output.
-///
__generic<T : __BuiltinType, let N : int>
[__readNone]
-__target_intrinsic(hlsl)
-__target_intrinsic(GL_NV_fragment_shader_barycentric, "$0[$1]")
-__target_intrinsic(GL_EXT_fragment_shader_barycentric, "$0[$1]")
__glsl_version(450)
-vector<T,N> GetAttributeAtVertex(vector<T,N> attribute, uint vertexIndex);
+vector<T,N> GetAttributeAtVertex(vector<T,N> attribute, uint vertexIndex)
+{
+ __target_switch
+ {
+ case hlsl:
+ __intrinsic_asm "GetAttributeAtVertex";
+ case GL_NV_fragment_shader_barycentric:
+ case GL_EXT_fragment_shader_barycentric:
+ __intrinsic_asm "$0[$1]";
+ case spirv:
+ return spirv_asm {
+ %_ptr_Input_vectorT = OpTypePointer Input $$vector<T,N>;
+ %addr = OpAccessChain %_ptr_Input_vectorT $attribute $vertexIndex;
+ result:$$vector<T,N> = OpLoad %addr;
+ };
+ }
+}
/// Get the value of a vertex attribute at a specific vertex.
///
@@ -2942,16 +2964,26 @@ vector<T,N> GetAttributeAtVertex(vector<T,N> attribute, uint vertexIndex);
/// This function can be applied to scalars, vectors, and matrices of
/// built-in scalar types.
///
-/// Note: these functions are not curently implemented for Vulkan/SPIR-V output.
-///
__generic<T : __BuiltinType, let N : int, let M : int>
[__readNone]
-__target_intrinsic(hlsl)
-__target_intrinsic(GL_NV_fragment_shader_barycentric, "$0[$1]")
-__target_intrinsic(GL_EXT_fragment_shader_barycentric, "$0[$1]")
__glsl_version(450)
-matrix<T,N,M> GetAttributeAtVertex(matrix<T,N,M> attribute, uint vertexIndex);
-
+matrix<T,N,M> GetAttributeAtVertex(matrix<T,N,M> attribute, uint vertexIndex)
+{
+ __target_switch
+ {
+ case hlsl:
+ __intrinsic_asm "GetAttributeAtVertex";
+ case GL_NV_fragment_shader_barycentric:
+ case GL_EXT_fragment_shader_barycentric:
+ __intrinsic_asm "$0[$1]";
+ case spirv:
+ return spirv_asm {
+ %_ptr_Input_matrixT = OpTypePointer Input $$matrix<T,N,M>;
+ %addr = OpAccessChain %_ptr_Input_matrixT $attribute $vertexIndex;
+ result:$$matrix<T,N,M> = OpLoad %addr;
+ };
+ }
+}
// Get number of samples in render target
[__readNone]
diff --git a/source/slang/slang-ast-expr.h b/source/slang/slang-ast-expr.h
index 9c604f6a0..5238cd4e2 100644
--- a/source/slang/slang-ast-expr.h
+++ b/source/slang/slang-ast-expr.h
@@ -659,6 +659,7 @@ public:
SlangType,
SampledType, // __sampledType(T), this becomes a 4 vector of the component type of T
TruncateMarker, // __truncate, an invented instruction which coerces to the result type by truncating the element count
+ EntryPoint, // __entryPoint, a placeholder for the id of a referencing entryPoint.
BuiltinVar,
GLSL450Set,
};
diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp
index 2be86cdfe..0aa4d4c60 100644
--- a/source/slang/slang-emit-spirv.cpp
+++ b/source/slang/slang-emit-spirv.cpp
@@ -1061,6 +1061,42 @@ struct SPIRVEmitContext
return spvInst;
}
+ template<typename OperandEmitFunc>
+ SpvInst* emitInstMemoizedNoResultIDCustomOperandFunc(
+ SpvInstParent* parent,
+ IRInst* irInst,
+ SpvOp opcode,
+ const OperandEmitFunc& f
+ )
+ {
+ List<SpvWord> ourOperands;
+ {
+ auto scopePeek = OperandMemoizeScope(this);
+ f();
+ // Steal our operands back, so we don't have to calculate them
+ // again
+ ourOperands = std::move(m_operandStack);
+ }
+
+ // Hash the whole global stack and opcode
+ SpvTypeInstKey key;
+ key.words.add(opcode);
+ key.words.addRange(ourOperands);
+
+ // If we have seen this before, return the memoized instruction
+ if (SpvInst** memoized = m_spvTypeInsts.tryGetValue(key))
+ return *memoized;
+
+ // Otherwise, we can construct our instruction and record the result
+ InstConstructScope scopeInst(this, opcode, irInst);
+ SpvInst* spvInst = scopeInst;
+ m_spvTypeInsts[key] = spvInst;
+
+ m_operandStack.addRange(ourOperands);
+
+ parent->addInst(spvInst);
+ return spvInst;
+ }
//
// Specific emit funcs
//
@@ -2313,12 +2349,12 @@ struct SPIRVEmitContext
// to the new globals, which would be used in the SPIR-V emit case.
auto entryPointDecor = cast<IREntryPointDecoration>(decoration);
+ auto entryPoint = as<IRFunc>(decoration->getParent());
auto spvStage = mapStageToExecutionModel(entryPointDecor->getProfile().getStage());
auto name = entryPointDecor->getName()->getStringSlice();
List<SpvInst*> params;
HashSet<SpvInst*> paramsSet;
// `interface` part: reference all global variables that are used by this entrypoint.
- // TODO: we may want to perform more accurate tracking.
for (auto globalInst : m_irModule->getModuleInst()->getChildren())
{
switch (globalInst->getOp())
@@ -2329,8 +2365,13 @@ struct SPIRVEmitContext
SpvInst* spvGlobalInst;
if (m_mapIRInstToSpvInst.tryGetValue(globalInst, spvGlobalInst))
{
- paramsSet.add(spvGlobalInst);
- params.add(spvGlobalInst);
+ // Is this globalInst referenced by this entry point?
+ auto refSet = m_referencingEntryPoints.tryGetValue(globalInst);
+ if (refSet && refSet->contains(entryPoint))
+ {
+ paramsSet.add(spvGlobalInst);
+ params.add(spvGlobalInst);
+ }
}
break;
}
@@ -2622,6 +2663,7 @@ struct SPIRVEmitContext
else if (semanticName == "sv_innercoverage")
{
requireSPIRVCapability(SpvCapabilityFragmentFullyCoveredEXT);
+ ensureExtensionDeclaration(UnownedStringSlice("SPV_EXT_fragment_fully_covered"));
return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInFullyCoveredEXT);
}
else if (semanticName == "sv_depth")
@@ -2694,6 +2736,7 @@ struct SPIRVEmitContext
else if (semanticName == "sv_stencilref")
{
requireSPIRVCapability(SpvCapabilityStencilExportEXT);
+ ensureExtensionDeclaration(UnownedStringSlice("SPV_EXT_shader_stencil_export"));
return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInFragStencilRefEXT);
}
else if (semanticName == "sv_tessfactor")
@@ -2722,6 +2765,7 @@ struct SPIRVEmitContext
else if (semanticName == "nv_viewport_mask")
{
requireSPIRVCapability(SpvCapabilityPerViewAttributesNV);
+ ensureExtensionDeclaration(UnownedStringSlice("SPV_NV_mesh_shader"));
return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInViewportMaskPerViewNV);
}
else if (semanticName == "sv_barycentrics")
@@ -2729,11 +2773,13 @@ struct SPIRVEmitContext
if (m_targetRequest->getTargetCaps().implies(CapabilityAtom::GL_NV_fragment_shader_barycentric))
{
requireSPIRVCapability(SpvCapabilityFragmentBarycentricNV);
+ ensureExtensionDeclaration(UnownedStringSlice("SPV_NV_fragment_shader_barycentric"));
return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInBaryCoordNV);
}
else
{
requireSPIRVCapability(SpvCapabilityFragmentBarycentricKHR);
+ ensureExtensionDeclaration(UnownedStringSlice("SPV_KHR_fragment_shader_barycentric"));
return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInBaryCoordKHR);
}
@@ -2744,11 +2790,13 @@ struct SPIRVEmitContext
else if (semanticName == "sv_cullprimitive")
{
requireSPIRVCapability(SpvCapabilityMeshShadingEXT);
+ ensureExtensionDeclaration(UnownedStringSlice("SPV_NV_mesh_shader"));
return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInCullPrimitiveEXT);
}
else if (semanticName == "sv_shadingrate")
{
requireSPIRVCapability(SpvCapabilityFragmentShadingRateKHR);
+ ensureExtensionDeclaration(UnownedStringSlice("SPV_KHR_fragment_shading_rate"));
return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInPrimitiveShadingRateKHR);
}
SLANG_UNREACHABLE("Unimplemented system value in spirv emit.");
@@ -3988,6 +4036,8 @@ struct SPIRVEmitContext
return getSection(SpvLogicalSectionID::Capabilities);
case SpvOpExtension:
return getSection(SpvLogicalSectionID::Extensions);
+ case SpvOpExecutionMode:
+ return getSection(SpvLogicalSectionID::ExecutionModes);
default:
return defaultParent;
@@ -4212,6 +4262,22 @@ struct SPIRVEmitContext
case SpvOpExtension:
ensureExtensionDeclaration(as<IRStringLit>(spvInst->getOperand(1)->getOperand(0))->getStringSlice());
continue;
+ case SpvOpExecutionMode:
+ {
+ if (auto refEntryPointSet = m_referencingEntryPoints.tryGetValue(getParentFunc(inst)))
+ {
+ for (auto entryPoint : *refEntryPointSet)
+ {
+ emitInstMemoizedNoResultIDCustomOperandFunc(getSection(SpvLogicalSectionID::ExecutionModes), nullptr, SpvOpExecutionMode,
+ [&]() {
+ emitOperand(entryPoint);
+ for (UInt s = 2; s < spvInst->getOperandCount(); s++)
+ emitSpvAsmOperand(as<IRSPIRVAsmOperand>(spvInst->getOperand(s)));
+ });
+ }
+ }
+ continue;
+ }
default:
break;
}
diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h
index b44b7b5d9..6b5d8e59a 100644
--- a/source/slang/slang-ir-inst-defs.h
+++ b/source/slang/slang-ir-inst-defs.h
@@ -1103,6 +1103,10 @@ INST(SPIRVAsmInst, SPIRVAsmInst, 1, 0)
// A special instruction which represents a type directed truncation
// operation where extra components are dropped
INST(SPIRVAsmOperandTruncate, __truncate, 0, HOISTABLE)
+
+ // A special instruction which represents an ID of an entry point that references the current function.
+ INST(SPIRVAsmOperandEntryPoint, __entryPoint, 0, HOISTABLE)
+
// A type function which returns the result type of sampling an image of
// this component type
INST(SPIRVAsmOperandSampledType, __sampledType, 1, HOISTABLE)
diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h
index 63555c08d..0fd48f546 100644
--- a/source/slang/slang-ir-insts.h
+++ b/source/slang/slang-ir-insts.h
@@ -4021,6 +4021,7 @@ public:
IRSPIRVAsmOperand* emitSPIRVAsmOperandGLSL450Set();
IRSPIRVAsmOperand* emitSPIRVAsmOperandSampledType(IRType* elementType);
IRSPIRVAsmOperand* emitSPIRVAsmOperandTruncate();
+ IRSPIRVAsmOperand* emitSPIRVAsmOperandEntryPoint();
IRSPIRVAsmInst* emitSPIRVAsmInst(IRInst* opcode, List<IRInst*> operands);
IRSPIRVAsm* emitSPIRVAsm(IRType* type);
IRInst* emitGenericAsm(UnownedStringSlice asmText);
diff --git a/source/slang/slang-ir-spirv-legalize.cpp b/source/slang/slang-ir-spirv-legalize.cpp
index 69abaa108..393b907f7 100644
--- a/source/slang/slang-ir-spirv-legalize.cpp
+++ b/source/slang/slang-ir-spirv-legalize.cpp
@@ -220,12 +220,50 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
}
}
+ Stage getReferencingEntryPointStage(IRInst* inst)
+ {
+ for (auto use = inst->firstUse; use; use = use->nextUse)
+ {
+ if (auto f = getParentFunc(use->getUser()))
+ {
+ if (auto d = f->findDecoration<IREntryPointDecoration>())
+ return d->getProfile().getStage();
+ }
+ }
+ return Stage::Unknown;
+ }
+
+ bool translatePerVertexInputType(IRInst* param)
+ {
+ if (auto interpolationModeDecor = param->findDecoration<IRInterpolationModeDecoration>())
+ {
+ if (interpolationModeDecor->getMode() == IRInterpolationMode::PerVertex)
+ {
+ if (getReferencingEntryPointStage(param) == Stage::Fragment)
+ {
+ auto originalType = param->getFullType();
+ IRBuilder builder(param);
+ builder.setInsertBefore(param);
+ auto arrayType = builder.getArrayType(originalType, builder.getIntValue(builder.getIntType(), 3));
+ param->setFullType(arrayType);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
void processGlobalParam(IRGlobalParam* inst)
{
// If the global param is not a pointer type, make it so and insert explicit load insts.
auto ptrType = as<IRPtrTypeBase>(inst->getDataType());
if (!ptrType)
{
+ bool needLoad = true;
+
+ if (translatePerVertexInputType(inst))
+ needLoad = false;
+
auto innerType = inst->getFullType();
auto arrayType = as<IRArrayType>(inst->getDataType());
@@ -261,7 +299,6 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
// Strip any HLSL wrappers
IRBuilder builder(m_sharedContext->m_irModule);
- bool needLoad = true;
auto cbufferType = as<IRConstantBufferType>(innerType);
auto paramBlockType = as<IRParameterBlockType>(innerType);
if (cbufferType || paramBlockType)
@@ -1055,6 +1092,100 @@ void legalizeSPIRV(SPIRVEmitSharedContext* sharedContext, IRModule* module)
context.processModule();
}
+void buildEntryPointReferenceGraph(SPIRVEmitSharedContext* context, IRModule* module)
+{
+ struct WorkItem
+ {
+ IRFunc* entryPoint; IRInst* inst;
+
+ HashCode getHashCode() const
+ {
+ return combineHash(Slang::getHashCode(entryPoint), Slang::getHashCode(inst));
+ }
+ bool operator == (const WorkItem& other) const
+ {
+ return entryPoint == other.entryPoint && inst == other.inst;
+ }
+ };
+ HashSet<WorkItem> workListSet;
+ List<WorkItem> workList;
+ auto addToWorkList = [&](WorkItem item)
+ {
+ if (workListSet.add(item))
+ workList.add(item);
+ };
+
+ auto registerEntryPointReference = [&](IRFunc* entryPoint, IRInst* inst)
+ {
+ if (auto set = context->m_referencingEntryPoints.tryGetValue(inst))
+ set->add(entryPoint);
+ else
+ {
+ HashSet<IRFunc*> newSet;
+ newSet.add(entryPoint);
+ context->m_referencingEntryPoints.add(inst, _Move(newSet));
+ }
+ };
+ auto visit = [&](IRFunc* entryPoint, IRInst* inst)
+ {
+ if (auto code = as<IRGlobalValueWithCode>(inst))
+ {
+ registerEntryPointReference(entryPoint, inst);
+ for (auto child : code->getChildren())
+ {
+ addToWorkList({ entryPoint, child });
+ }
+ return;
+ }
+ switch (inst->getOp())
+ {
+ case kIROp_GlobalParam:
+ registerEntryPointReference(entryPoint, inst);
+ break;
+ case kIROp_Block:
+ case kIROp_SPIRVAsm:
+ for (auto child : inst->getChildren())
+ {
+ addToWorkList({ entryPoint, child });
+ }
+ break;
+ case kIROp_Call:
+ {
+ auto call = as<IRCall>(inst);
+ addToWorkList({ entryPoint, call->getCallee() });
+ }
+ break;
+ case kIROp_SPIRVAsmOperandInst:
+ {
+ auto operand = as<IRSPIRVAsmOperandInst>(inst);
+ addToWorkList({ entryPoint, operand->getValue() });
+ }
+ break;
+ }
+ for (UInt i = 0; i < inst->getOperandCount(); i++)
+ {
+ auto operand = inst->getOperand(i);
+ switch (operand->getOp())
+ {
+ case kIROp_GlobalParam:
+ case kIROp_GlobalVar:
+ addToWorkList({ entryPoint, operand });
+ break;
+ }
+ }
+ };
+
+ for (auto globalInst : module->getGlobalInsts())
+ {
+ if (globalInst->getOp() == kIROp_Func && globalInst->findDecoration<IREntryPointDecoration>())
+ {
+ visit(as<IRFunc>(globalInst), globalInst);
+ }
+ }
+ for (Index i = 0; i < workList.getCount(); i++)
+ visit(workList[i].entryPoint, workList[i].inst);
+}
+
void legalizeIRForSPIRV(
SPIRVEmitSharedContext* context,
IRModule* module,
@@ -1064,6 +1195,7 @@ void legalizeIRForSPIRV(
GLSLExtensionTracker extensionTracker;
legalizeEntryPointsForGLSL(module->getSession(), module, entryPoints, codeGenContext, &extensionTracker);
legalizeSPIRV(context, module);
+ buildEntryPointReferenceGraph(context, module);
}
} // namespace Slang
diff --git a/source/slang/slang-ir-spirv-legalize.h b/source/slang/slang-ir-spirv-legalize.h
index b11cde72f..c9b75c07f 100644
--- a/source/slang/slang-ir-spirv-legalize.h
+++ b/source/slang/slang-ir-spirv-legalize.h
@@ -18,6 +18,9 @@ struct SPIRVEmitSharedContext
IRModule* m_irModule;
TargetRequest* m_targetRequest;
Dictionary<IRTargetIntrinsicDecoration*, RefPtr<SpvSnippet>> m_parsedSpvSnippets;
+
+ Dictionary<IRInst*, HashSet<IRFunc*>> m_referencingEntryPoints; // The entry-points that directly or transitively reference this global inst.
+
DiagnosticSink* m_sink;
const SPIRVCoreGrammarInfo* m_grammarInfo;
SPIRVEmitSharedContext(IRModule* module, TargetRequest* target, DiagnosticSink* sink)
diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp
index 6777c0b3a..a54bc1f2e 100644
--- a/source/slang/slang-ir.cpp
+++ b/source/slang/slang-ir.cpp
@@ -5797,6 +5797,18 @@ namespace Slang
return i;
}
+ IRSPIRVAsmOperand* IRBuilder::emitSPIRVAsmOperandEntryPoint()
+ {
+ SLANG_ASSERT(as<IRSPIRVAsm>(m_insertLoc.getParent()));
+ const auto i = createInst<IRSPIRVAsmOperand>(
+ this,
+ kIROp_SPIRVAsmOperandEntryPoint,
+ getVoidType()
+ );
+ addInst(i);
+ return i;
+ }
+
IRSPIRVAsmInst* IRBuilder::emitSPIRVAsmInst(IRInst* opcode, List<IRInst*> operands)
{
SLANG_ASSERT(as<IRSPIRVAsm>(m_insertLoc.getParent()));
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index 4f64087d8..640482f12 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -3906,6 +3906,10 @@ struct ExprLoweringVisitorBase : public ExprVisitor<Derived, LoweredValInfo>
{
return builder->emitSPIRVAsmOperandTruncate();
}
+ case SPIRVAsmOperand::EntryPoint:
+ {
+ return builder->emitSPIRVAsmOperandEntryPoint();
+ }
}
SLANG_UNREACHABLE("Unhandled case in visitSPIRVAsmExpr");
};
diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp
index 892edd328..0191b1e0c 100644
--- a/source/slang/slang-parser.cpp
+++ b/source/slang/slang-parser.cpp
@@ -6322,6 +6322,11 @@ namespace Slang
{
return SPIRVAsmOperand{SPIRVAsmOperand::TruncateMarker, parser->ReadToken()};
}
+ // The pseudo-operand for referencing entryPoint id.
+ else if (parser->LookAheadToken("__entryPoint"))
+ {
+ return SPIRVAsmOperand{ SPIRVAsmOperand::EntryPoint, parser->ReadToken() };
+ }
else if (AdvanceIf(parser, "builtin"))
{
// reference to a builtin var.
diff --git a/tests/pipeline/rasterization/conservative-rasterization/inner-coverage.slang b/tests/pipeline/rasterization/conservative-rasterization/inner-coverage.slang
index fe77095df..bfa7eb633 100644
--- a/tests/pipeline/rasterization/conservative-rasterization/inner-coverage.slang
+++ b/tests/pipeline/rasterization/conservative-rasterization/inner-coverage.slang
@@ -1,6 +1,12 @@
// inner-coverage.slang
-//TEST:CROSS_COMPILE:-target spirv -entry main -stage fragment
+//TEST:SIMPLE(filecheck=CHECK):-target spirv -entry main -stage fragment
+//TEST:SIMPLE(filecheck=CHECK):-emit-spirv-directly -target spirv -entry main -stage fragment
+
+// CHECK: OpCapability FragmentFullyCoveredEXT
+// CHECK: OpExtension "SPV_EXT_fragment_fully_covered"
+// CHECK: OpEntryPoint Fragment %main "main"
+// CHECK: OpDecorate %{{.*}} BuiltIn FullyCoveredEXT
[shader("fragment")]
void main(
diff --git a/tests/pipeline/rasterization/conservative-rasterization/inner-coverage.slang.glsl b/tests/pipeline/rasterization/conservative-rasterization/inner-coverage.slang.glsl
deleted file mode 100644
index 59fecd544..000000000
--- a/tests/pipeline/rasterization/conservative-rasterization/inner-coverage.slang.glsl
+++ /dev/null
@@ -1,14 +0,0 @@
-//TEST_IGNORE_FILE:
-#version 450
-#extension GL_NV_conservative_raster_underestimation : require
-layout(row_major) uniform;
-layout(row_major) buffer;
-
-layout(location = 0)
-out vec4 _S1;
-
-void main()
-{
- _S1 = vec4(uint(gl_FragFullyCoveredNV));
- return;
-}
diff --git a/tests/pipeline/rasterization/fragment-shader-interlock.slang b/tests/pipeline/rasterization/fragment-shader-interlock.slang
index 7215629a2..0e438c456 100644
--- a/tests/pipeline/rasterization/fragment-shader-interlock.slang
+++ b/tests/pipeline/rasterization/fragment-shader-interlock.slang
@@ -3,7 +3,17 @@
// Test that explicit use of fragment-shader interlock (FSI)
// operations is supported by Slang
-//TEST:CROSS_COMPILE:-target spirv -entry main -stage fragment
+//TEST:SIMPLE(filecheck=CHECK):-target spirv -entry main -stage fragment
+//TEST:SIMPLE(filecheck=CHECK):-emit-spirv-directly -target spirv -entry main -stage fragment
+
+
+// CHECK: OpCapability FragmentShaderPixelInterlockEXT
+// CHECK: OpExtension "SPV_EXT_fragment_shader_interlock"
+// CHECK: OpEntryPoint Fragment %main "main"
+
+// CHECK-DAG: OpExecutionMode %main OriginUpperLeft
+
+// CHECK-DAG: OpExecutionMode %main PixelInterlockOrderedEXT
[shader("fragment")]
void main(
diff --git a/tests/pipeline/rasterization/get-attribute-at-vertex.slang b/tests/pipeline/rasterization/get-attribute-at-vertex.slang
index 87d39c806..a88cf8d24 100644
--- a/tests/pipeline/rasterization/get-attribute-at-vertex.slang
+++ b/tests/pipeline/rasterization/get-attribute-at-vertex.slang
@@ -4,6 +4,15 @@
//TEST:CROSS_COMPILE:-target dxil -entry main -stage fragment -profile sm_6_1
//TEST:CROSS_COMPILE:-target spirv -entry main -stage fragment -profile glsl_450
+//TEST:SIMPLE(filecheck=CHECK):-emit-spirv-directly -target spirv -entry main -stage fragment -profile glsl_450
+
+// CHECK: OpCapability FragmentBarycentricKHR
+// CHECK: OpExtension "SPV_KHR_fragment_shader_barycentric"
+
+// CHECK: OpEntryPoint Fragment %main "main"
+// CHECK: %{{.*}} = OpAccessChain %_ptr_Input_{{.*}} %{{.*}} %uint_0
+// CHECK: %{{.*}} = OpAccessChain %_ptr_Input_{{.*}} %{{.*}} %uint_1
+// CHECK: %{{.*}} = OpAccessChain %_ptr_Input_{{.*}} %{{.*}} %uint_2
[shader("fragment")]
void main(