summaryrefslogtreecommitdiffstats
path: root/source/slang
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang')
-rw-r--r--source/slang/hlsl.meta.slang31
-rw-r--r--source/slang/slang-diagnostic-defs.h2
-rw-r--r--source/slang/slang-emit-glsl.cpp22
-rw-r--r--source/slang/slang-emit-metal.cpp41
-rw-r--r--source/slang/slang-emit-spirv.cpp18
-rw-r--r--source/slang/slang-emit.cpp19
-rw-r--r--source/slang/slang-ir-glsl-legalize.cpp142
-rw-r--r--source/slang/slang-ir-glsl-legalize.h2
-rw-r--r--source/slang/slang-ir-insts.h28
-rw-r--r--source/slang/slang-ir-legalize-image-subscript.cpp203
-rw-r--r--source/slang/slang-ir-legalize-image-subscript.h11
-rw-r--r--source/slang/slang-ir-util.cpp13
-rw-r--r--source/slang/slang-ir-util.h3
-rw-r--r--source/slang/slang-ir.cpp11
14 files changed, 365 insertions, 181 deletions
diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang
index 597e4dc06..94a5208b0 100644
--- a/source/slang/hlsl.meta.slang
+++ b/source/slang/hlsl.meta.slang
@@ -2416,11 +2416,12 @@ extension __TextureImpl<T,Shape,isArray,0,sampleCount,0,isShadow,isCombined,form
__intrinsic_asm "$c$0.read(vec<uint,3>(($1).xyz), uint(($1).w))$z";
break;
case $(SLANG_TEXTURE_CUBE):
+ static_assert(isArray == 0, "Unsupported 'Load' of 'texture cube array' for 'metal' target");
if (isShadow == 1)
{
if (isArray == 1)
// T read(uint2 coord, uint face, uint array, uint lod = 0) const
- __intrinsic_asm "$0.read(vec<uint,2>(($1).xy), uint(($1).z), uint(($1).w))";
+ __intrinsic_asm "<invalid intrinsics>";
else
// T read(uint2 coord, uint face, uint lod = 0) const
__intrinsic_asm "$c$0.read(vec<uint,2>(($1).xy), uint(($1).z), uint(($1).w))$z";
@@ -2429,14 +2430,14 @@ extension __TextureImpl<T,Shape,isArray,0,sampleCount,0,isShadow,isCombined,form
{
if (isArray == 1)
// Tv read(uint2 coord, uint face, uint array, uint lod = 0) const
- __intrinsic_asm "$0.read(vec<uint,2>(($1).xy), uint(($1).z), uint(($1).w))";
+ __intrinsic_asm "<invalid intrinsics>";
else
// Tv read(uint2 coord, uint face, uint lod = 0) const
__intrinsic_asm "$c$0.read(vec<uint,2>(($1).xy), uint(($1).z), uint(($1).w))$z";
}
break;
}
- // TODO: This needs to be handled by the capability system
+ static_assert(false, "Unsupported 'Load' of 'texture' for 'metal' target");
__intrinsic_asm "<invalid intrinsics>";
case glsl:
__intrinsic_asm "$ctexelFetch($0, ($1).$w1b, ($1).$w1e)$z";
@@ -2819,6 +2820,7 @@ extension __TextureImpl<T,Shape,isArray,0,sampleCount,$(access),isShadow, 0,form
__intrinsic_asm "$c$0.read(vec<uint,3>(($1).xyz))$z";
break;
case $(SLANG_TEXTURE_CUBE):
+ static_assert(isArray == 0, "Unsupported 'Load' of 'texture cube array' for 'metal' target");
if (isShadow == 1)
{
if (isArray == 1)
@@ -2839,7 +2841,7 @@ extension __TextureImpl<T,Shape,isArray,0,sampleCount,$(access),isShadow, 0,form
}
break;
}
- // TODO: This needs to be handled by the capability system
+ static_assert(false, "Unsupported 'Load' of 'texture' for 'metal' target");
__intrinsic_asm "<invalid intrinsics>";
}
}
@@ -2960,10 +2962,10 @@ extension __TextureImpl<T,Shape,isArray,0,sampleCount,$(access),isShadow, 0,form
// lod is not supported for 1D texture
if (isArray == 1)
// void write(Tv color, uint coord, uint array, uint lod = 0) const
- __intrinsic_asm "$0.write($2, uint(($1).x))";
+ __intrinsic_asm "$0.write($2, uint(($1).x), uint(($1).y))";
else
// void write(Tv color, uint coord, uint lod = 0) const
- __intrinsic_asm "$0.write($2, uint(($1).x))";
+ __intrinsic_asm "$0.write($2, uint($1))";
break;
case $(SLANG_TEXTURE_2D):
if (isShadow == 1)
@@ -2991,23 +2993,16 @@ extension __TextureImpl<T,Shape,isArray,0,sampleCount,$(access),isShadow, 0,form
__intrinsic_asm "$0.write($2, vec<uint,3>(($1).xyz))";
break;
case $(SLANG_TEXTURE_CUBE):
+ static_assert(isArray == 0, "Unsupported 'Store' of 'texture cube array' for 'metal' target");
if (isShadow == 1)
{
- if (isArray == 1)
- // void write(Tv color, uint2 coord, uint face, uint array, uint lod = 0) const
- __intrinsic_asm "$0.write($2, vec<uint,2>(($1).xy), uint(($1).z)%6, uint(($1).z)/6)";
- else
- // void write(Tv color, uint2 coord, uint face, uint lod = 0) const
- __intrinsic_asm "$0.write($2, vec<uint,2>(($1).xy), uint(($1).z))";
+ // void write(Tv color, uint2 coord, uint face, uint lod = 0) const
+ __intrinsic_asm "$0.write($2, vec<uint,2>(($1).xy), uint(($1).z), uint(($1).w))";
}
else
{
- if (isArray == 1)
- // void write(Tv color, uint2 coord, uint face, uint array, uint lod = 0) const
- __intrinsic_asm "$0.write($2, vec<uint,2>(($1).xy), uint(($1).z)%6, uint(($1).z)/6)";
- else
- // void write(Tv color, uint2 coord, uint face, uint lod = 0) const
- __intrinsic_asm "$0.write($2, vec<uint,2>(($1).xy), uint(($1).z))";
+ // void write(Tv color, uint2 coord, uint face, uint lod = 0) const
+ __intrinsic_asm "$0.write($2, vec<uint,2>(($1).xy), uint(($1).z), uint(($1).w))";
}
break;
}
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index e27e40c59..5b9c3e65a 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -774,6 +774,8 @@ DIAGNOSTIC(41400, Error, staticAssertionFailure, "static assertion failed, $0")
DIAGNOSTIC(41401, Error, staticAssertionFailureWithoutMessage, "static assertion failed.")
DIAGNOSTIC(41402, Error, staticAssertionConditionNotConstant, "condition for static assertion cannot be evaluated at the compile-time.")
+DIAGNOSTIC(41402, Error, multiSampledTextureDoesNotAllowWrites, "cannot write to a multisampled texture with target '$0'.")
+
//
// 5xxxx - Target code generation.
//
diff --git a/source/slang/slang-emit-glsl.cpp b/source/slang/slang-emit-glsl.cpp
index 2a7f22905..b6c3c0d67 100644
--- a/source/slang/slang-emit-glsl.cpp
+++ b/source/slang/slang-emit-glsl.cpp
@@ -2021,21 +2021,33 @@ bool GLSLSourceEmitter::tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inOu
}
case kIROp_ImageLoad:
{
+ auto imageOp = as<IRImageLoad>(inst);
m_writer->emit("imageLoad(");
- emitOperand(inst->getOperand(0), getInfo(EmitOp::General));
+ emitOperand(imageOp->getImage(), getInfo(EmitOp::General));
m_writer->emit(",");
- emitOperand(inst->getOperand(1), getInfo(EmitOp::General));
+ emitOperand(imageOp->getCoord(), getInfo(EmitOp::General));
+ if (imageOp->hasAuxCoord1())
+ {
+ m_writer->emit(",");
+ emitOperand(imageOp->getAuxCoord1(), getInfo(EmitOp::General));
+ }
m_writer->emit(")");
return true;
}
case kIROp_ImageStore:
{
+ auto imageOp = as<IRImageStore>(inst);
m_writer->emit("imageStore(");
- emitOperand(inst->getOperand(0), getInfo(EmitOp::General));
+ emitOperand(imageOp->getImage(), getInfo(EmitOp::General));
m_writer->emit(",");
- emitOperand(inst->getOperand(1), getInfo(EmitOp::General));
+ emitOperand(imageOp->getCoord(), getInfo(EmitOp::General));
+ if (imageOp->hasAuxCoord1())
+ {
+ m_writer->emit(",");
+ emitOperand(imageOp->getAuxCoord1(), getInfo(EmitOp::General));
+ }
m_writer->emit(",");
- emitOperand(inst->getOperand(2), getInfo(EmitOp::General));
+ emitOperand(imageOp->getValue(), getInfo(EmitOp::General));
m_writer->emit(")");
return true;
}
diff --git a/source/slang/slang-emit-metal.cpp b/source/slang/slang-emit-metal.cpp
index d38c3de9b..e7df29e0c 100644
--- a/source/slang/slang-emit-metal.cpp
+++ b/source/slang/slang-emit-metal.cpp
@@ -451,6 +451,47 @@ bool MetalSourceEmitter::tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inO
emitOperand(inst->getOperand(2), getInfo(EmitOp::General));
return true;
}
+ case kIROp_ImageLoad:
+ {
+ auto imageOp = as<IRImageLoad>(inst);
+ emitOperand(imageOp->getImage(), getInfo(EmitOp::General));
+ m_writer->emit(".read(");
+ emitOperand(imageOp->getCoord(), getInfo(EmitOp::General));
+ if(imageOp->hasAuxCoord1())
+ {
+ m_writer->emit(",");
+ emitOperand(imageOp->getAuxCoord1(), getInfo(EmitOp::General));
+ }
+ if(imageOp->hasAuxCoord2())
+ {
+ m_writer->emit(",");
+ emitOperand(imageOp->getAuxCoord2(), getInfo(EmitOp::General));
+ }
+ m_writer->emit(")");
+ return true;
+ }
+ case kIROp_ImageStore:
+ {
+
+ auto imageOp = as<IRImageStore>(inst);
+ emitOperand(imageOp->getImage(), getInfo(EmitOp::General));
+ m_writer->emit(".write(");
+ emitOperand(imageOp->getValue(), getInfo(EmitOp::General));
+ m_writer->emit(",");
+ emitOperand(imageOp->getCoord(), getInfo(EmitOp::General));
+ if(imageOp->hasAuxCoord1())
+ {
+ m_writer->emit(",");
+ emitOperand(imageOp->getAuxCoord1(), getInfo(EmitOp::General));
+ }
+ if(imageOp->hasAuxCoord2())
+ {
+ m_writer->emit(",");
+ emitOperand(imageOp->getAuxCoord2(), getInfo(EmitOp::General));
+ }
+ m_writer->emit(")");
+ return true;
+ }
default: break;
}
// Not handled
diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp
index 3ee0d9241..51a71d65c 100644
--- a/source/slang/slang-emit-spirv.cpp
+++ b/source/slang/slang-emit-spirv.cpp
@@ -2989,12 +2989,26 @@ struct SPIRVEmitContext
SpvInst* emitImageLoad(SpvInstParent* parent, IRImageLoad* load)
{
- return emitInst(parent, load, SpvOpImageRead, load->getDataType(), kResultID, load->getImage(), load->getCoord());
+ if (load->hasAuxCoord1())
+ {
+ return emitInst(parent, load, SpvOpImageRead, load->getDataType(), kResultID, load->getImage(), load->getCoord(), SpvImageOperandsSampleMask, load->getAuxCoord1());
+ }
+ else
+ {
+ return emitInst(parent, load, SpvOpImageRead, load->getDataType(), kResultID, load->getImage(), load->getCoord());
+ }
}
SpvInst* emitImageStore(SpvInstParent* parent, IRImageStore* store)
{
- return emitInst(parent, store, SpvOpImageWrite, store->getImage(), store->getCoord(), store->getValue());
+ if (store->hasAuxCoord1())
+ {
+ return emitInst(parent, store, SpvOpImageWrite, store->getImage(), store->getCoord(), store->getValue(), SpvImageOperandsSampleMask, store->getAuxCoord1());
+ }
+ else
+ {
+ return emitInst(parent, store, SpvOpImageWrite, store->getImage(), store->getCoord(), store->getValue());
+ }
}
SpvInst* emitImageSubscript(SpvInstParent* parent, IRImageSubscript* subscript)
diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp
index 0f53f74cd..bb6bab0ab 100644
--- a/source/slang/slang-emit.cpp
+++ b/source/slang/slang-emit.cpp
@@ -50,6 +50,7 @@
#include "slang-ir-lower-l-value-cast.h"
#include "slang-ir-lower-reinterpret.h"
#include "slang-ir-loop-unroll.h"
+#include "slang-ir-legalize-image-subscript.h"
#include "slang-ir-legalize-vector-types.h"
#include "slang-ir-metadata.h"
#include "slang-ir-optix-entry-point-uniforms.h"
@@ -1153,14 +1154,28 @@ Result linkAndOptimizeIR(
if(isD3DTarget(targetRequest))
legalizeNonStructParameterToStructForHLSL(irModule);
- // Legalize `ImageSubscript` and constant buffer loads for GLSL.
+ // Legalize `ImageSubscript` loads.
+ switch (target)
+ {
+ case CodeGenTarget::Metal:
+ case CodeGenTarget::GLSL:
+ case CodeGenTarget::SPIRV:
+ case CodeGenTarget::SPIRVAssembly:
+ {
+ legalizeImageSubscript(targetRequest, irModule, sink);
+ }
+ break;
+ default:
+ break;
+ }
+
+ // Legalize constant buffer loads.
switch (target)
{
case CodeGenTarget::GLSL:
case CodeGenTarget::SPIRV:
case CodeGenTarget::SPIRVAssembly:
{
- legalizeImageSubscriptForGLSL(irModule);
legalizeConstantBufferLoadForGLSL(irModule);
legalizeDispatchMeshPayloadForGLSL(irModule);
}
diff --git a/source/slang/slang-ir-glsl-legalize.cpp b/source/slang/slang-ir-glsl-legalize.cpp
index be222c87f..0e23460ce 100644
--- a/source/slang/slang-ir-glsl-legalize.cpp
+++ b/source/slang/slang-ir-glsl-legalize.cpp
@@ -15,148 +15,6 @@
namespace Slang
{
-int getIRVectorElementSize(IRType* type)
-{
- if (type->getOp() != kIROp_VectorType)
- return 1;
- return (int)(as<IRIntLit>(as<IRVectorType>(type)->getElementCount())->value.intVal);
-}
-IRType* getIRVectorBaseType(IRType* type)
-{
- if (type->getOp() != kIROp_VectorType)
- return type;
- return as<IRVectorType>(type)->getElementType();
-}
-
-void legalizeImageSubscriptStoreForGLSL(IRBuilder& builder, IRInst* storeInst)
-{
- builder.setInsertBefore(storeInst);
- auto getElementPtr = as<IRGetElementPtr>(storeInst->getOperand(0));
- IRImageSubscript* imageSubscript = nullptr;
- if (getElementPtr)
- imageSubscript = as<IRImageSubscript>(getElementPtr->getBase());
- else
- imageSubscript = as<IRImageSubscript>(storeInst->getOperand(0));
- assert(imageSubscript);
- auto imageElementType = cast<IRPtrTypeBase>(imageSubscript->getDataType())->getValueType();
- auto coordType = imageSubscript->getCoord()->getDataType();
- auto coordVectorSize = getIRVectorElementSize(coordType);
- if (coordVectorSize != 1)
- {
- coordType = builder.getVectorType(
- builder.getIntType(), builder.getIntValue(builder.getIntType(), coordVectorSize));
- }
- else
- {
- coordType = builder.getIntType();
- }
- auto legalizedCoord = imageSubscript->getCoord();
- if (coordType != imageSubscript->getCoord()->getDataType())
- {
- legalizedCoord = builder.emitCast(coordType, legalizedCoord);
- }
- switch (storeInst->getOp())
- {
- case kIROp_Store:
- {
- IRInst* newValue = nullptr;
- if (getElementPtr)
- {
- auto vectorBaseType = getIRVectorBaseType(imageElementType);
- IRType* vector4Type = builder.getVectorType(vectorBaseType, 4);
- auto originalValue = builder.emitImageLoad(vector4Type, imageSubscript->getImage(), legalizedCoord);
- auto index = getElementPtr->getIndex();
- newValue = builder.emitSwizzleSet(vector4Type, originalValue, storeInst->getOperand(1), 1, &index);
- }
- else
- {
- newValue = storeInst->getOperand(1);
- if (getIRVectorElementSize(imageElementType) != 4)
- {
- auto vectorBaseType = getIRVectorBaseType(imageElementType);
- newValue = builder.emitVectorReshape(
- builder.getVectorType(
- vectorBaseType, builder.getIntValue(builder.getIntType(), 4)),
- newValue);
- }
- }
- auto imageStore = builder.emitImageStore(
- builder.getVoidType(),
- imageSubscript->getImage(),
- legalizedCoord,
- newValue);
- storeInst->replaceUsesWith(imageStore);
- storeInst->removeAndDeallocate();
- if (!imageSubscript->hasUses())
- {
- imageSubscript->removeAndDeallocate();
- }
- }
- break;
- case kIROp_SwizzledStore:
- {
- auto swizzledStore = cast<IRSwizzledStore>(storeInst);
- // Here we assume the imageElementType is already lowered into float4/uint4 types from any
- // user-defined type.
- assert(imageElementType->getOp() == kIROp_VectorType);
- auto vectorBaseType = getIRVectorBaseType(imageElementType);
- IRType* vector4Type = builder.getVectorType(vectorBaseType, 4);
- auto originalValue = builder.emitImageLoad(vector4Type, imageSubscript->getImage(), legalizedCoord);
- Array<IRInst*, 4> indices;
- for (UInt i = 0; i < swizzledStore->getElementCount(); i++)
- {
- indices.add(swizzledStore->getElementIndex(i));
- }
- auto newValue = builder.emitSwizzleSet(
- vector4Type,
- originalValue,
- swizzledStore->getSource(),
- swizzledStore->getElementCount(),
- indices.getBuffer());
- auto imageStore = builder.emitImageStore(
- builder.getVoidType(), imageSubscript->getImage(), legalizedCoord, newValue);
- storeInst->replaceUsesWith(imageStore);
- storeInst->removeAndDeallocate();
- if (!imageSubscript->hasUses())
- {
- imageSubscript->removeAndDeallocate();
- }
- }
- break;
- default:
- break;
- }
-}
-
-void legalizeImageSubscriptForGLSL(IRModule* module)
-{
- IRBuilder builder(module);
- for (auto globalInst : module->getModuleInst()->getChildren())
- {
- auto func = as<IRFunc>(globalInst);
- if (!func)
- continue;
- for (auto block : func->getBlocks())
- {
- auto inst = block->getFirstInst();
- IRInst* next;
- for ( ; inst; inst = next)
- {
- next = inst->getNextInst();
- switch (inst->getOp())
- {
- case kIROp_Store:
- case kIROp_SwizzledStore:
- if (getRootAddr(inst->getOperand(0))->getOp() == kIROp_ImageSubscript)
- {
- legalizeImageSubscriptStoreForGLSL(builder, inst);
- }
- }
- }
- }
- }
-}
-
//
// Legalization of entry points for GLSL:
//
diff --git a/source/slang/slang-ir-glsl-legalize.h b/source/slang/slang-ir-glsl-legalize.h
index 6fd0b642e..8ec164a96 100644
--- a/source/slang/slang-ir-glsl-legalize.h
+++ b/source/slang/slang-ir-glsl-legalize.h
@@ -21,8 +21,6 @@ void legalizeEntryPointsForGLSL(
CodeGenContext* context,
GLSLExtensionTracker* glslExtensionTracker);
-void legalizeImageSubscriptForGLSL(IRModule* module);
-
void legalizeConstantBufferLoadForGLSL(IRModule* module);
void legalizeDispatchMeshPayloadForGLSL(IRModule* module);
diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h
index 4781ea2c3..a63cc5c22 100644
--- a/source/slang/slang-ir-insts.h
+++ b/source/slang/slang-ir-insts.h
@@ -2440,6 +2440,8 @@ struct IRImageSubscript : IRInst
IR_LEAF_ISA(ImageSubscript);
IRInst* getImage() { return getOperand(0); }
IRInst* getCoord() { return getOperand(1); }
+ bool hasSampleCoord() { return getOperandCount() > 2 && getOperand(2) != nullptr; }
+ IRInst* getSampleCoord() { return getOperand(2); }
};
struct IRImageLoad : IRInst
@@ -2447,6 +2449,16 @@ struct IRImageLoad : IRInst
IR_LEAF_ISA(ImageLoad);
IRInst* getImage() { return getOperand(0); }
IRInst* getCoord() { return getOperand(1); }
+
+ /// If GLSL/SPIR-V, Sample coord
+ /// If Metal, Array or Sample coord
+ bool hasAuxCoord1() { return getOperandCount() > 2 && getOperand(2) != nullptr; }
+ IRInst* getAuxCoord1() { return getOperand(2); }
+
+ /// If Metal, Sample coord
+ bool hasAuxCoord2() { return getOperandCount() > 3 && getOperand(3) != nullptr; }
+ IRInst* getAuxCoord2() { return getOperand(3); }
+
};
struct IRImageStore : IRInst
@@ -2455,6 +2467,15 @@ struct IRImageStore : IRInst
IRInst* getImage() { return getOperand(0); }
IRInst* getCoord() { return getOperand(1); }
IRInst* getValue() { return getOperand(2); }
+
+ /// If GLSL/SPIR-V, Sample coord
+ /// If Metal, Array or Sample coord
+ bool hasAuxCoord1() { return getOperandCount() > 3 && getOperand(3) != nullptr; }
+ IRInst* getAuxCoord1() { return getOperand(3); }
+
+ /// If Metal, Sample coord
+ bool hasAuxCoord2() { return getOperandCount() > 4 && getOperand(4) != nullptr; }
+ IRInst* getAuxCoord2() { return getOperand(4); }
};
// Terminators
@@ -4048,14 +4069,11 @@ public:
IRInst* emitImageLoad(
IRType* type,
- IRInst* image,
- IRInst* coord);
+ ShortList<IRInst*> params);
IRInst* emitImageStore(
IRType* type,
- IRInst* image,
- IRInst* coord,
- IRInst* value);
+ ShortList<IRInst*> params);
IRInst* emitIsType(IRInst* value, IRInst* witness, IRInst* typeOperand, IRInst* targetWitness);
diff --git a/source/slang/slang-ir-legalize-image-subscript.cpp b/source/slang/slang-ir-legalize-image-subscript.cpp
new file mode 100644
index 000000000..b5b240675
--- /dev/null
+++ b/source/slang/slang-ir-legalize-image-subscript.cpp
@@ -0,0 +1,203 @@
+#include "slang-ir-legalize-image-subscript.h"
+
+#include "slang-ir.h"
+#include "slang-ir-insts.h"
+#include "slang-ir-util.h"
+#include "slang-ir-clone.h"
+#include "slang-ir-specialize-address-space.h"
+#include "slang-parameter-binding.h"
+#include "slang-ir-legalize-varying-params.h"
+
+namespace Slang
+{
+ void legalizeStore(TargetRequest* target, IRBuilder& builder, IRInst* storeInst, DiagnosticSink* sink)
+ {
+ SLANG_ASSERT(storeInst);
+
+ builder.setInsertBefore(storeInst);
+ IRImageSubscript* imageSubscript = nullptr;
+ auto getElementPtr = as<IRGetElementPtr>(storeInst->getOperand(0));
+ if(getElementPtr)
+ {
+ imageSubscript = as<IRImageSubscript>(getElementPtr->getBase());
+ }
+ else
+ {
+ imageSubscript = as<IRImageSubscript>(storeInst->getOperand(0));
+ }
+ SLANG_ASSERT(imageSubscript);
+ SLANG_ASSERT(imageSubscript->getImage());
+ IRTextureType* textureType = as<IRTextureType>(imageSubscript->getImage()->getFullType());
+ SLANG_ASSERT(textureType);
+ auto imageElementType = cast<IRPtrTypeBase>(imageSubscript->getDataType())->getValueType();
+ auto vectorBaseType = getIRVectorBaseType(imageElementType);
+ IRType* vector4Type = builder.getVectorType(vectorBaseType, 4);
+ IRType* coordType = imageSubscript->getCoord()->getDataType();
+ int coordVectorSize = getIRVectorElementSize(coordType);
+
+ bool seperateArrayCoord = (isMetalTarget(target) && textureType->isArray()); // seperate array param
+ bool seperateSampleCoord = (textureType->isMultisample()); // seperate sample param
+
+ if(seperateSampleCoord && isMetalTarget(target))
+ sink->diagnose(imageSubscript->getImage(), Diagnostics::multiSampledTextureDoesNotAllowWrites, target->getTarget());
+
+ IRType* indexingType = builder.getIntType();
+ if(isMetalTarget(target))
+ indexingType = builder.getUIntType();
+
+ if (coordVectorSize != 1)
+ {
+ coordType = builder.getVectorType(
+ indexingType, builder.getIntValue(builder.getIntType(), coordVectorSize));
+ }
+ else
+ {
+ coordType = indexingType;
+ }
+
+ auto legalizedCoord = imageSubscript->getCoord();
+ if (coordType != imageSubscript->getCoord()->getDataType())
+ {
+ legalizedCoord = builder.emitCast(coordType, legalizedCoord);
+ }
+
+ const Index kCoordParamIndex = 1;
+ const Index kValueParamIndex = 2;
+
+ ShortList<IRInst*> loadParams;
+ loadParams.reserveOverflowBuffer(4);
+ loadParams.add(imageSubscript->getImage()); // image
+ loadParams.add(legalizedCoord); // coord
+
+ ShortList<IRInst*> storeParams;
+ storeParams.reserveOverflowBuffer(5);
+ storeParams.add(imageSubscript->getImage()); // image
+ storeParams.add(legalizedCoord); // coord
+ storeParams.add(nullptr); // value
+
+ if (seperateArrayCoord)
+ {
+
+ UInt paramIndexToFetch = coordVectorSize - 1;
+
+ auto seperatedParam = builder.emitSwizzle(indexingType, legalizedCoord, 1, &paramIndexToFetch);
+ loadParams.add(seperatedParam);
+ storeParams.add(seperatedParam);
+
+ coordVectorSize -= 1;
+ ShortList<UInt> paramToFetch;
+ paramToFetch.reserveOverflowBuffer(coordVectorSize);
+ for (int i = 0; i < coordVectorSize; i++)
+ {
+ paramToFetch.add(i);
+ }
+ auto newCoord = builder.emitSwizzle(builder.getVectorType(indexingType, builder.getIntValue(builder.getIntType(), coordVectorSize)), legalizedCoord, coordVectorSize, paramToFetch.getArrayView().getBuffer());
+ storeParams[kCoordParamIndex] = newCoord;
+ loadParams[kCoordParamIndex] = newCoord;
+ }
+ if (seperateSampleCoord)
+ {
+ loadParams.add(imageSubscript->getSampleCoord());
+ storeParams.add(imageSubscript->getSampleCoord());
+ }
+
+ IRInst* legalizedStore = storeInst->getOperand(1);
+ switch (storeInst->getOp())
+ {
+ case kIROp_Store:
+ {
+ IRInst* newValue = nullptr;
+ if (getElementPtr)
+ {
+ auto originalValue = builder.emitImageLoad(vector4Type, loadParams);
+ auto index = getElementPtr->getIndex();
+ newValue = builder.emitSwizzleSet(vector4Type, originalValue, legalizedStore, 1, &index);
+ }
+ else
+ {
+ newValue = legalizedStore;
+ if (getIRVectorElementSize(imageElementType) != 4)
+ {
+ newValue = builder.emitVectorReshape(
+ builder.getVectorType(
+ vectorBaseType, builder.getIntValue(builder.getIntType(), 4)),
+ newValue);
+ }
+ }
+
+ storeParams[kValueParamIndex] = newValue;
+ auto imageStore = builder.emitImageStore(
+ builder.getVoidType(),
+ storeParams);
+ storeInst->replaceUsesWith(imageStore);
+ storeInst->removeAndDeallocate();
+ if (!imageSubscript->hasUses())
+ {
+ imageSubscript->removeAndDeallocate();
+ }
+ }
+ break;
+ case kIROp_SwizzledStore:
+ {
+ auto swizzledStore = cast<IRSwizzledStore>(storeInst);
+ // Here we assume the imageElementType is already lowered into float4/uint4 types from any
+ // user-defined type.
+ assert(imageElementType->getOp() == kIROp_VectorType);
+ auto originalValue = builder.emitImageLoad(vector4Type, loadParams);
+ Array<IRInst*, 4> indices;
+ for (UInt i = 0; i < swizzledStore->getElementCount(); i++)
+ {
+ indices.add(swizzledStore->getElementIndex(i));
+ }
+ auto newValue = builder.emitSwizzleSet(
+ vector4Type,
+ originalValue,
+ swizzledStore->getSource(),
+ swizzledStore->getElementCount(),
+ indices.getBuffer());
+ storeParams[kValueParamIndex] = newValue;
+ auto imageStore = builder.emitImageStore(
+ builder.getVoidType(),
+ storeParams);
+ storeInst->replaceUsesWith(imageStore);
+ storeInst->removeAndDeallocate();
+ if (!imageSubscript->hasUses())
+ {
+ imageSubscript->removeAndDeallocate();
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ void legalizeImageSubscript(TargetRequest* target, IRModule* module, DiagnosticSink* sink)
+ {
+ IRBuilder builder(module);
+ for (auto globalInst : module->getModuleInst()->getChildren())
+ {
+ auto func = as<IRFunc>(globalInst);
+ if (!func)
+ continue;
+ for (auto block : func->getBlocks())
+ {
+ auto inst = block->getFirstInst();
+ IRInst* next;
+ for ( ; inst; inst = next)
+ {
+ next = inst->getNextInst();
+ switch (inst->getOp())
+ {
+ case kIROp_Store:
+ case kIROp_SwizzledStore:
+ if (getRootAddr(inst->getOperand(0))->getOp() == kIROp_ImageSubscript)
+ {
+ legalizeStore(target, builder, inst, sink);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
diff --git a/source/slang/slang-ir-legalize-image-subscript.h b/source/slang/slang-ir-legalize-image-subscript.h
new file mode 100644
index 000000000..71d20b32d
--- /dev/null
+++ b/source/slang/slang-ir-legalize-image-subscript.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "slang-ir.h"
+#include "slang-compiler.h"
+
+namespace Slang
+{
+ class DiagnosticSink;
+
+ void legalizeImageSubscript(TargetRequest* target, IRModule* module, DiagnosticSink* sink);
+}
diff --git a/source/slang/slang-ir-util.cpp b/source/slang/slang-ir-util.cpp
index 40d169c48..10c7bfea6 100644
--- a/source/slang/slang-ir-util.cpp
+++ b/source/slang/slang-ir-util.cpp
@@ -1783,4 +1783,17 @@ void verifyComputeDerivativeGroupModifiers(
}
}
+int getIRVectorElementSize(IRType* type)
+{
+ if (type->getOp() != kIROp_VectorType)
+ return 1;
+ return (int)(as<IRIntLit>(as<IRVectorType>(type)->getElementCount())->value.intVal);
+}
+IRType* getIRVectorBaseType(IRType* type)
+{
+ if (type->getOp() != kIROp_VectorType)
+ return type;
+ return as<IRVectorType>(type)->getElementType();
+}
+
}
diff --git a/source/slang/slang-ir-util.h b/source/slang/slang-ir-util.h
index d78ceaaf8..855046c04 100644
--- a/source/slang/slang-ir-util.h
+++ b/source/slang/slang-ir-util.h
@@ -345,6 +345,9 @@ inline bool isSPIRV(CodeGenTarget codeGenTarget)
|| codeGenTarget == CodeGenTarget::SPIRVAssembly;
}
+int getIRVectorElementSize(IRType* type);
+IRType* getIRVectorBaseType(IRType* type);
+
}
#endif
diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp
index c0541f4c4..a4ea100dc 100644
--- a/source/slang/slang-ir.cpp
+++ b/source/slang/slang-ir.cpp
@@ -4841,17 +4841,18 @@ namespace Slang
return inst;
}
- IRInst* IRBuilder::emitImageLoad(IRType* type, IRInst* image, IRInst* coord)
+ /// @param params An ordered list of imageLoad parameters { image, coord, [optional] seperateArrayCoord, [optional] seperateSampleCoord }
+ IRInst* IRBuilder::emitImageLoad(IRType* type, ShortList<IRInst*> params)
{
- auto inst = createInst<IRImageLoad>(this, kIROp_ImageLoad, type, image, coord);
+ auto inst = createInst<IRImageLoad>(this, kIROp_ImageLoad, type, params.getCount(), params.getArrayView().getBuffer());
addInst(inst);
return inst;
}
- IRInst* IRBuilder::emitImageStore(IRType* type, IRInst* image, IRInst* coord, IRInst* value)
+ /// @param params An ordered list of imageStore parameters { image, coord, value, [optional] seperateArrayCoord, [optional] seperateSampleCoord }
+ IRInst* IRBuilder::emitImageStore(IRType* type, ShortList<IRInst*> params)
{
- IRInst* args[] = {image, coord, value};
- auto inst = createInst<IRImageStore>(this, kIROp_ImageStore, type, 3, args);
+ auto inst = createInst<IRImageStore>(this, kIROp_ImageStore, type, params.getCount(), params.getArrayView().getBuffer());
addInst(inst);
return inst;
}