summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2025-02-27 16:57:52 -0800
committerGitHub <noreply@github.com>2025-02-27 16:57:52 -0800
commit6f2ce72b038b34e84819ddfc5d658166ed879eaa (patch)
tree486a85523114a428ccf4deee05bcbab0d4b9528b
parent90b3817498d9cf664346f04dcea71f48ce81993e (diff)
Map `SV_InstanceID` to `gl_InstanceIndex-gl_BaseInstance` (#6468)
* Map `SV_InstanceID` to `gl_InstanceIndex-gl_BaseInstance` * Fix ci.
-rw-r--r--.github/workflows/ci.yml2
-rw-r--r--source/slang/glsl.meta.slang22
-rw-r--r--source/slang/slang-artifact-output-util.cpp2
-rw-r--r--source/slang/slang-compiler.cpp22
-rw-r--r--source/slang/slang-compiler.h20
-rw-r--r--source/slang/slang-emit-c-like.cpp19
-rw-r--r--source/slang/slang-emit-c-like.h2
-rw-r--r--source/slang/slang-emit-glsl.cpp6
-rw-r--r--source/slang/slang-emit-spirv.cpp16
-rw-r--r--source/slang/slang-ir-glsl-legalize.cpp80
-rw-r--r--source/slang/slang-ir-inst-defs.h3
-rw-r--r--source/slang/slang-ir-insts.h32
-rw-r--r--source/slang/slang-ir-spirv-legalize.cpp52
-rw-r--r--tests/bugs/gh-3087-multi-entry-point.slang18
-rw-r--r--tests/hlsl-intrinsic/system-values-draw-parameters.slang2
-rw-r--r--tests/spirv/sv_instance.slang14
16 files changed, 259 insertions, 53 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 9e0b03dbc..4fc7be677 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -177,7 +177,7 @@ jobs:
-expected-failure-list tests/expected-failure-record-replay-tests.txt
fi
- name: Run Slang examples
- if: steps.filter.outputs.should-run == 'true' && matrix.platform != 'wasm'
+ if: steps.filter.outputs.should-run == 'true' && matrix.platform != 'wasm' && matrix.full-gpu-tests
run: |
.github/workflows/ci-examples.sh \
--bin-dir "$bin_dir" \
diff --git a/source/slang/glsl.meta.slang b/source/slang/glsl.meta.slang
index 6f0ca1bf3..eed6cc690 100644
--- a/source/slang/glsl.meta.slang
+++ b/source/slang/glsl.meta.slang
@@ -136,7 +136,27 @@ public property uint3 gl_WorkGroupSize
// TODO: define overload for tessellation control stage.
public in int gl_InvocationID : SV_GSInstanceID;
-public in int gl_InstanceIndex : SV_InstanceID;
+internal in int __sv_InstanceIndex : SV_InstanceID;
+
+// SPIRV InstanceIndex builtin for vertex shader
+public property int gl_InstanceIndex
+{
+ [require(vertex)]
+ get
+ {
+ __target_switch
+ {
+ default:
+ return __sv_InstanceIndex;
+ case glsl:
+ __intrinsic_asm "gl_InstanceIndex";
+ case spirv:
+ return spirv_asm {
+ result:$$int = OpLoad builtin(InstanceIndex:int);
+ };
+ }
+ }
+}
public in bool gl_FrontFacing : SV_IsFrontFace;
// TODO: define overload for geometry stage.
diff --git a/source/slang/slang-artifact-output-util.cpp b/source/slang/slang-artifact-output-util.cpp
index 2d9dae1cf..0e297955f 100644
--- a/source/slang/slang-artifact-output-util.cpp
+++ b/source/slang/slang-artifact-output-util.cpp
@@ -6,6 +6,8 @@
#include "../core/slang-string-util.h"
#include "../core/slang-type-text-util.h"
+#include <chrono>
+
// Artifact
#include "../compiler-core/slang-artifact-desc-util.h"
#include "../compiler-core/slang-artifact-util.h"
diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp
index 04ebb753c..58cc55e71 100644
--- a/source/slang/slang-compiler.cpp
+++ b/source/slang/slang-compiler.cpp
@@ -16,6 +16,8 @@
#include "slang-check-impl.h"
#include "slang-check.h"
+#include <chrono>
+
// Artifact
#include "../compiler-core/slang-artifact-associated.h"
#include "../compiler-core/slang-artifact-container-util.h"
@@ -1835,6 +1837,26 @@ SlangResult CodeGenContext::_emitEntryPoints(ComPtr<IArtifact>& outArtifact)
return SLANG_FAIL;
}
+// Helper class for recording compile time.
+struct CompileTimerRAII
+{
+ std::chrono::high_resolution_clock::time_point startTime;
+ Session* session;
+ CompileTimerRAII(Session* inSession)
+ {
+ startTime = std::chrono::high_resolution_clock::now();
+ session = inSession;
+ }
+ ~CompileTimerRAII()
+ {
+ double elapsedTime = std::chrono::duration_cast<std::chrono::microseconds>(
+ std::chrono::high_resolution_clock::now() - startTime)
+ .count() /
+ 1e6;
+ session->addTotalCompileTime(elapsedTime);
+ }
+};
+
// Do emit logic for a zero or more entry points
SlangResult CodeGenContext::emitEntryPoints(ComPtr<IArtifact>& outArtifact)
{
diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h
index 6175d25cc..10da32400 100644
--- a/source/slang/slang-compiler.h
+++ b/source/slang/slang-compiler.h
@@ -3757,26 +3757,6 @@ SLANG_FORCE_INLINE SlangSourceLanguage asExternal(SourceLanguage sourceLanguage)
return (SlangSourceLanguage)sourceLanguage;
}
-// Helper class for recording compile time.
-struct CompileTimerRAII
-{
- std::chrono::high_resolution_clock::time_point startTime;
- Session* session;
- CompileTimerRAII(Session* inSession)
- {
- startTime = std::chrono::high_resolution_clock::now();
- session = inSession;
- }
- ~CompileTimerRAII()
- {
- double elapsedTime = std::chrono::duration_cast<std::chrono::microseconds>(
- std::chrono::high_resolution_clock::now() - startTime)
- .count() /
- 1e6;
- session->addTotalCompileTime(elapsedTime);
- }
-};
-
// helpers for error/warning reporting
enum class DiagnosticCategory
{
diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp
index db2c0150f..946e9c429 100644
--- a/source/slang/slang-emit-c-like.cpp
+++ b/source/slang/slang-emit-c-like.cpp
@@ -345,6 +345,20 @@ IRNumThreadsDecoration* CLikeSourceEmitter::getComputeThreadGroupSize(
return decor;
}
+String CLikeSourceEmitter::getTargetBuiltinVarName(IRInst* inst, IRTargetBuiltinVarName builtinName)
+{
+ switch (builtinName)
+ {
+ case IRTargetBuiltinVarName::SpvInstanceIndex:
+ return "gl_InstanceIndex";
+ case IRTargetBuiltinVarName::SpvBaseInstance:
+ return "gl_BaseInstance";
+ }
+ if (auto linkage = inst->findDecoration<IRLinkageDecoration>())
+ return linkage->getMangledName();
+ return generateName(inst);
+}
+
List<IRWitnessTableEntry*> CLikeSourceEmitter::getSortedWitnessTableEntries(
IRWitnessTable* witnessTable)
{
@@ -1208,6 +1222,11 @@ String CLikeSourceEmitter::generateName(IRInst* inst)
return externCppDecoration->getName();
}
+ if (auto builtinTargetVarDecoration = inst->findDecoration<IRTargetBuiltinVarDecoration>())
+ {
+ return getTargetBuiltinVarName(inst, builtinTargetVarDecoration->getBuiltinVarName());
+ }
+
// If we have a name hint on the instruction, then we will try to use that
// to provide the basis for the actual name in the output code.
if (auto nameHintDecoration = inst->findDecoration<IRNameHintDecoration>())
diff --git a/source/slang/slang-emit-c-like.h b/source/slang/slang-emit-c-like.h
index e83b6e586..6fe7f5d34 100644
--- a/source/slang/slang-emit-c-like.h
+++ b/source/slang/slang-emit-c-like.h
@@ -243,7 +243,6 @@ public:
Linkage* getLinkage() { return m_codeGenContext->getLinkage(); }
ComponentType* getProgram() { return m_codeGenContext->getProgram(); }
TargetProgram* getTargetProgram() { return m_codeGenContext->getTargetProgram(); }
-
//
// Types
//
@@ -519,6 +518,7 @@ public:
protected:
virtual void emitGlobalParamDefaultVal(IRGlobalParam* inst) { SLANG_UNUSED(inst); }
virtual void emitPostDeclarationAttributesForType(IRInst* type) { SLANG_UNUSED(type); }
+ virtual String getTargetBuiltinVarName(IRInst* inst, IRTargetBuiltinVarName builtinName);
virtual bool doesTargetSupportPtrTypes() { return false; }
virtual bool isResourceTypeBindless(IRType* type)
{
diff --git a/source/slang/slang-emit-glsl.cpp b/source/slang/slang-emit-glsl.cpp
index 25dab3fb3..776c539b4 100644
--- a/source/slang/slang-emit-glsl.cpp
+++ b/source/slang/slang-emit-glsl.cpp
@@ -1791,6 +1791,12 @@ bool GLSLSourceEmitter::tryEmitGlobalParamImpl(IRGlobalParam* varDecl, IRType* v
}
}
+ if (varDecl->findDecoration<IRTargetBuiltinVarDecoration>())
+ {
+ // By default, we don't need to emit a definition for target builtin variables.
+ return true;
+ }
+
// Do the default thing
return false;
}
diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp
index e0367be89..802df915e 100644
--- a/source/slang/slang-emit-spirv.cpp
+++ b/source/slang/slang-emit-spirv.cpp
@@ -4417,8 +4417,11 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
continue;
}
}
- paramsSet.add(spvGlobalInst);
referencedBuiltinIRVars.add(globalInst);
+ // Don't add duplicate vars to the interface list.
+ bool paramAdded = paramsSet.add(spvGlobalInst);
+ if (!paramAdded)
+ continue;
// Don't add a global param to the interface if it is a
// specialization constant.
@@ -5288,6 +5291,17 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
{
IRBuilder builder(m_irModule);
builder.setInsertBefore(inst);
+ if (auto builtinVarDecor = inst->findDecoration<IRTargetBuiltinVarDecoration>())
+ {
+ switch (builtinVarDecor->getBuiltinVarName())
+ {
+ case IRTargetBuiltinVarName::SpvInstanceIndex:
+ return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInInstanceIndex, inst);
+ case IRTargetBuiltinVarName::SpvBaseInstance:
+ requireSPIRVCapability(SpvCapabilityDrawParameters);
+ return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInBaseInstance, inst);
+ }
+ }
if (auto layout = getVarLayout(inst))
{
if (auto systemValueAttr = layout->findAttr<IRSystemValueSemanticAttr>())
diff --git a/source/slang/slang-ir-glsl-legalize.cpp b/source/slang/slang-ir-glsl-legalize.cpp
index 11d5399cf..1123e1f2a 100644
--- a/source/slang/slang-ir-glsl-legalize.cpp
+++ b/source/slang/slang-ir-glsl-legalize.cpp
@@ -236,6 +236,9 @@ struct GLSLSystemValueInfo
// The kind of the system value that requires special treatment.
GLSLSystemValueKind kind = GLSLSystemValueKind::General;
+
+ // The target builtin name.
+ IRTargetBuiltinVarName targetVarName = IRTargetBuiltinVarName::Unknown;
};
static void leafAddressesImpl(List<IRInst*>& ret, const ScalarizedVal& v)
@@ -283,6 +286,7 @@ struct GLSLLegalizationContext
DiagnosticSink* sink;
Stage stage;
IRFunc* entryPointFunc;
+ Dictionary<IRTargetBuiltinVarName, IRInst*> builtinVarMap;
/// This dictionary stores all bindings of 'VaryingIn/VaryingOut'. We assume 'space' is 0.
Dictionary<LayoutResourceKind, UIntSet> usedBindingIndex;
@@ -414,7 +418,7 @@ GLSLSystemValueInfo* getGLSLSystemValueInfo(
char const* outerArrayName = nullptr;
int arrayIndex = -1;
GLSLSystemValueKind systemValueKind = GLSLSystemValueKind::General;
-
+ IRTargetBuiltinVarName targetVarName = IRTargetBuiltinVarName::Unknown;
auto semanticInst = varLayout->findSystemValueSemanticAttr();
if (!semanticInst)
return nullptr;
@@ -621,6 +625,9 @@ GLSLSystemValueInfo* getGLSLSystemValueInfo(
requiredType = builder->getBasicType(BaseType::Int);
name = "gl_InstanceIndex";
+ targetVarName = IRTargetBuiltinVarName::HlslInstanceID;
+ context->requireSPIRVVersion(SemanticVersion(1, 3));
+ context->requireGLSLExtension(toSlice("GL_ARB_shader_draw_parameters"));
}
else if (semanticName == "sv_isfrontface")
{
@@ -869,6 +876,7 @@ GLSLSystemValueInfo* getGLSLSystemValueInfo(
name = "gl_BaseInstance";
}
+ inStorage->targetVarName = targetVarName;
if (name)
{
inStorage->name = name;
@@ -976,6 +984,12 @@ void createVarLayoutForLegalizedGlobalParam(
default:
break;
}
+
+ if (systemValueInfo->targetVarName != IRTargetBuiltinVarName::Unknown)
+ {
+ builder->addTargetBuiltinVarDecoration(globalParam, systemValueInfo->targetVarName);
+ context->builtinVarMap[systemValueInfo->targetVarName] = globalParam;
+ }
}
}
@@ -1261,8 +1275,8 @@ ScalarizedVal createSimpleGLSLGlobalVarying(
auto systemSemantic = inVarLayout->findAttr<IRSystemValueSemanticAttr>();
// Validate the system value, convert to a regular parameter if this is not a valid system
// value for a given target.
- if (systemSemantic && isSPIRV(codeGenContext->getTargetFormat()) &&
- systemSemantic->getName().caseInsensitiveEquals(UnownedStringSlice("sv_instanceid")) &&
+ if (systemSemantic && systemValueInfo && isSPIRV(codeGenContext->getTargetFormat()) &&
+ systemValueInfo->targetVarName == IRTargetBuiltinVarName::HlslInstanceID &&
((stage == Stage::Fragment) ||
(stage == Stage::Vertex &&
inVarLayout->usesResourceKind(LayoutResourceKind::VaryingOutput))))
@@ -1287,6 +1301,7 @@ ScalarizedVal createSimpleGLSLGlobalVarying(
newVarLayout->sourceLoc = inVarLayout->sourceLoc;
inVarLayout->replaceUsesWith(newVarLayout);
+ systemValueInfo->targetVarName = IRTargetBuiltinVarName::Unknown;
}
}
@@ -3746,6 +3761,60 @@ ScalarizedVal legalizeEntryPointReturnValueForGLSL(
return result;
}
+void legalizeTargetBuiltinVar(GLSLLegalizationContext& context)
+{
+ List<KeyValuePair<IRTargetBuiltinVarName, IRInst*>> workItems;
+ for (auto [builtinVarName, varInst] : context.builtinVarMap)
+ {
+ if (builtinVarName == IRTargetBuiltinVarName::HlslInstanceID)
+ {
+ workItems.add(KeyValuePair(builtinVarName, varInst));
+ }
+ }
+
+ auto getOrCreateBuiltinVar = [&](IRTargetBuiltinVarName name, IRType* type)
+ {
+ if (auto var = context.builtinVarMap.tryGetValue(name))
+ return *var;
+ IRBuilder builder(context.entryPointFunc);
+ builder.setInsertBefore(context.entryPointFunc);
+ IRInst* var = builder.createGlobalParam(type);
+ builder.addTargetBuiltinVarDecoration(var, name);
+ return var;
+ };
+ for (auto& kv : workItems)
+ {
+ auto builtinVarName = kv.key;
+ auto varInst = kv.value;
+
+ // Repalce SV_InstanceID with gl_InstanceIndex - gl_BaseInstance.
+ if (builtinVarName == IRTargetBuiltinVarName::HlslInstanceID)
+ {
+ auto instanceIndex = getOrCreateBuiltinVar(
+ IRTargetBuiltinVarName::SpvInstanceIndex,
+ varInst->getDataType());
+ auto baseInstance = getOrCreateBuiltinVar(
+ IRTargetBuiltinVarName::SpvBaseInstance,
+ varInst->getDataType());
+ traverseUses(
+ varInst,
+ [&](IRUse* use)
+ {
+ auto user = use->getUser();
+ if (user->getOp() == kIROp_Load)
+ {
+ IRBuilder builder(use->getUser());
+ builder.setInsertBefore(use->getUser());
+ auto sub = builder.emitSub(
+ tryGetPointedToType(&builder, varInst->getDataType()),
+ builder.emitLoad(instanceIndex),
+ builder.emitLoad(baseInstance));
+ user->replaceUsesWith(sub);
+ }
+ });
+ }
+ }
+}
void legalizeEntryPointForGLSL(
Session* session,
@@ -3937,6 +4006,11 @@ void legalizeEntryPointForGLSL(
value.globalParam->setFullType(sizedArrayType);
}
}
+
+ // Some system value vars can't be mapped 1:1 to a GLSL/Vulkan builtin,
+ // for example, SV_InstanceID should map to gl_InstanceIndex - gl_BaseInstance,
+ // we will replace these builtins with additional compute logic here.
+ legalizeTargetBuiltinVar(context);
}
void decorateModuleWithSPIRVVersion(IRModule* module, SemanticVersion spirvVersion)
diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h
index 9ffaeeeb9..3e2872cb7 100644
--- a/source/slang/slang-ir-inst-defs.h
+++ b/source/slang/slang-ir-inst-defs.h
@@ -926,6 +926,9 @@ INST_RANGE(BindingQuery, GetRegisterIndex, GetRegisterSpace)
INST(ExportDecoration, export, 1, 0)
INST_RANGE(LinkageDecoration, ImportDecoration, ExportDecoration)
+ /// Mark a global variable as a target builtin variable.
+ INST(TargetBuiltinVarDecoration, TargetBuiltinVar, 1, 0)
+
/// Marks an inst as coming from an `extern` symbol defined in the user code.
INST(UserExternDecoration, UserExtern, 0, 0)
diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h
index 7c975cfcd..4efb7d671 100644
--- a/source/slang/slang-ir-insts.h
+++ b/source/slang/slang-ir-insts.h
@@ -193,6 +193,14 @@ enum class IRInterpolationMode
PerVertex,
};
+enum class IRTargetBuiltinVarName
+{
+ Unknown,
+ HlslInstanceID,
+ SpvInstanceIndex,
+ SpvBaseInstance,
+};
+
struct IRInterpolationModeDecoration : IRDecoration
{
enum
@@ -705,6 +713,18 @@ struct IRLinkageDecoration : IRDecoration
UnownedStringSlice getMangledName() { return getMangledNameOperand()->getStringSlice(); }
};
+// Mark a global variable as a target buitlin variable.
+struct IRTargetBuiltinVarDecoration : IRDecoration
+{
+ IR_LEAF_ISA(TargetBuiltinVarDecoration)
+
+ IRIntLit* getBuiltinVarOperand() { return cast<IRIntLit>(getOperand(0)); }
+ IRTargetBuiltinVarName getBuiltinVarName()
+ {
+ return IRTargetBuiltinVarName(getBuiltinVarOperand()->getValue());
+ }
+};
+
struct IRUserExternDecoration : IRDecoration
{
enum
@@ -4658,6 +4678,18 @@ public:
// void addLayoutDecoration(IRInst* value, Layout* layout);
IRLayoutDecoration* addLayoutDecoration(IRInst* value, IRLayout* layout);
+ IRDecoration* addTargetBuiltinVarDecoration(
+ IRInst* value,
+ IRTargetBuiltinVarName builtinVarName)
+ {
+ IRInst* operands[] = {getIntValue((IRIntegerValue)builtinVarName)};
+ return addDecoration(
+ value,
+ kIROp_TargetBuiltinVarDecoration,
+ operands,
+ SLANG_COUNT_OF(operands));
+ }
+
// IRLayout* getLayout(Layout* astLayout);
IRTypeSizeAttr* getTypeSizeAttr(LayoutResourceKind kind, LayoutSize size);
diff --git a/source/slang/slang-ir-spirv-legalize.cpp b/source/slang/slang-ir-spirv-legalize.cpp
index c672180b7..b19af364e 100644
--- a/source/slang/slang-ir-spirv-legalize.cpp
+++ b/source/slang/slang-ir-spirv-legalize.cpp
@@ -422,20 +422,10 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
}
AddressSpace addressSpace = AddressSpace::ThreadLocal;
- // Figure out storage class based on var layout.
- if (auto layout = getVarLayout(inst))
- {
- auto cls = getGlobalParamAddressSpace(layout);
- if (cls != AddressSpace::Generic)
- addressSpace = cls;
- else if (auto systemValueAttr = layout->findAttr<IRSystemValueSemanticAttr>())
- {
- String semanticName = systemValueAttr->getName();
- semanticName = semanticName.toLower();
- if (semanticName == "sv_pointsize")
- addressSpace = AddressSpace::BuiltinInput;
- }
- }
+ // Figure out storage class based on builtin info or var layout.
+ auto cls = getGlobalParamAddressSpace(inst);
+ if (cls != AddressSpace::Generic)
+ addressSpace = cls;
// Don't do any processing for specialization constants.
if (addressSpace == AddressSpace::SpecializationConstant)
@@ -635,8 +625,22 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
return addressSpace;
}
- AddressSpace getGlobalParamAddressSpace(IRVarLayout* varLayout)
+ AddressSpace getGlobalParamAddressSpace(IRInst* varInst)
{
+ if (auto builtinDecor = varInst->findDecoration<IRTargetBuiltinVarDecoration>())
+ {
+ switch (builtinDecor->getBuiltinVarName())
+ {
+ case IRTargetBuiltinVarName::SpvInstanceIndex:
+ case IRTargetBuiltinVarName::SpvBaseInstance:
+ return AddressSpace::BuiltinInput;
+ }
+ }
+
+ auto varLayout = getVarLayout(varInst);
+ if (!varLayout)
+ return AddressSpace::Generic;
+
auto typeLayout = varLayout->getTypeLayout()->unwrapArray();
if (auto parameterGroupTypeLayout = as<IRParameterGroupTypeLayout>(typeLayout))
{
@@ -663,15 +667,25 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
"resolve a storage class address space.");
}
}
+ auto systemValueAttr = varLayout->findSystemValueSemanticAttr();
+
+ if (systemValueAttr)
+ {
+ // TODO: is this needed?
+ String semanticName = systemValueAttr->getName();
+ semanticName = semanticName.toLower();
+ if (semanticName == "sv_pointsize")
+ result = AddressSpace::BuiltinInput;
+ }
switch (result)
{
case AddressSpace::Input:
- if (varLayout->findSystemValueSemanticAttr())
+ if (systemValueAttr)
result = AddressSpace::BuiltinInput;
break;
case AddressSpace::Output:
- if (varLayout->findSystemValueSemanticAttr())
+ if (systemValueAttr)
result = AddressSpace::BuiltinOutput;
break;
}
@@ -781,9 +795,9 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
{
addressSpace = AddressSpace::GroupShared;
}
- else if (const auto varLayout = getVarLayout(inst))
+ else
{
- auto cls = getGlobalParamAddressSpace(varLayout);
+ auto cls = getGlobalParamAddressSpace(inst);
if (cls != AddressSpace::Generic)
addressSpace = cls;
}
diff --git a/tests/bugs/gh-3087-multi-entry-point.slang b/tests/bugs/gh-3087-multi-entry-point.slang
index d3aa574c7..edfda08af 100644
--- a/tests/bugs/gh-3087-multi-entry-point.slang
+++ b/tests/bugs/gh-3087-multi-entry-point.slang
@@ -3,14 +3,20 @@
// CHECK-DAG: OpEntryPoint Vertex
// CHECK-DAG: OpEntryPoint Fragment
-// we should only have 1 'BuiltIn InstanceIndex' since the `Output` and `Input` semantic
-// for `InstanceIndex` should be converted to a non-builtin
-// CHECK-DAG: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex
-// CHECK-NOT: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex
-
// We require 1 `Flat` for the fragment input `uint`
// CHECK-DAG: OpDecorate %{{[1-9][0-9]*}} Flat
-// CHECK-NOT: OpDecorate %{{[1-9][0-9]*}} Flat
+
+// CHECK-DAG: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex
+
+// The vertex shader should be using the builtin InstanceIndex var.
+// CHECK: %vmain = OpFunction
+// CHECK: InstanceIndex
+// CHECK: OpFunctionEnd
+
+// The fragment shader should not be using the builtin InstanceIndex var.
+// CHECK: %pmain = OpFunction
+// CHECK-NOT: InstanceIndex
+// CHECK: OpFunctionEnd
struct VIn
{
diff --git a/tests/hlsl-intrinsic/system-values-draw-parameters.slang b/tests/hlsl-intrinsic/system-values-draw-parameters.slang
index e45366939..009efffa1 100644
--- a/tests/hlsl-intrinsic/system-values-draw-parameters.slang
+++ b/tests/hlsl-intrinsic/system-values-draw-parameters.slang
@@ -32,7 +32,7 @@ VSOutput main(VSInput input,
// CHECK_HLSL: SV_StartVertexLocation
// CHECK_METAL: base_vertex
- // CHECK_SPIRV: BuiltIn BaseInstance
+ // CHECK_SPIRV: BuiltIn InstanceIndex
// CHECK_GLSL: gl_BaseInstance
// CHECK_HLSL: SV_StartInstanceLocation
// CHECK_METAL: base_instance
diff --git a/tests/spirv/sv_instance.slang b/tests/spirv/sv_instance.slang
new file mode 100644
index 000000000..e71c6c7fa
--- /dev/null
+++ b/tests/spirv/sv_instance.slang
@@ -0,0 +1,14 @@
+//TEST:SIMPLE(filecheck=GLSL): -target glsl -entry vertMain -stage vertex
+//TEST:SIMPLE(filecheck=CHECK): -target spirv
+
+// CHECK-DAG: %[[REG1:[0-9a-zA-Z_]+]] = OpLoad %int %gl_BaseInstance
+// CHECK-DAG: %[[REG2:[0-9a-zA-Z_]+]] = OpLoad %int %gl_InstanceIndex
+// CHECK-DAG: OpISub %int %[[REG2]] %[[REG1]]
+
+// GLSL: gl_InstanceIndex - gl_BaseInstance
+
+[shader("vertex")]
+float4 vertMain(int i : SV_InstanceID) : SV_Position
+{
+ return i;
+} \ No newline at end of file