summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source/slang/slang-check-decl.cpp5
-rw-r--r--source/slang/slang-diagnostic-defs.h1
-rw-r--r--source/slang/slang-ir-insts.h2
-rw-r--r--source/slang/slang-ir-lower-buffer-element-type.cpp81
-rw-r--r--source/slang/slang-ir-specialize-address-space.cpp2
-rw-r--r--source/slang/slang-ir.cpp6
-rw-r--r--tests/bugs/gh-3825.slang10
-rw-r--r--tests/spirv/ptr-unsized-array.slang23
8 files changed, 125 insertions, 5 deletions
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index b7f65a11a..5ca1baeec 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -8430,6 +8430,11 @@ namespace Slang
{
auto typeExpr = paramDecl->type;
+ if (!as<ArrayExpressionType>(paramDecl->type) && doesTypeHaveTag(paramDecl->type, TypeTag::Unsized))
+ {
+ getSink()->diagnose(paramDecl, Diagnostics::paramCannotBeUnsized, paramDecl);
+ }
+
// The "initializer" expression for a parameter represents
// a default argument value to use if an explicit one is
// not supplied.
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index 3f4376eb3..298c79f7e 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -329,6 +329,7 @@ DIAGNOSTIC(30068, Warning, mutatingMethodOnFunctionInputParameterWarning, "mutat
DIAGNOSTIC(30070, Error, unsizedMemberMustAppearLast, "member with unknown size at compile time can only appear as the last member in a composite type.")
DIAGNOSTIC(30071, Error, varCannotBeUnsized, "cannot instantiate a variable of unsized type.")
+DIAGNOSTIC(30072, Error, paramCannotBeUnsized, "function parameter cannot be unsized.")
DIAGNOSTIC(30075, Error, cannotSpecializeGeneric, "cannot specialize generic '$0' with the provided arguments.")
diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h
index 81b916791..c2fd9da0a 100644
--- a/source/slang/slang-ir-insts.h
+++ b/source/slang/slang-ir-insts.h
@@ -4330,7 +4330,7 @@ public:
IRInst* emitUpdateElement(IRInst* base, IRInst* index, IRInst* newElement);
IRInst* emitUpdateElement(IRInst* base, IRIntegerValue index, IRInst* newElement);
IRInst* emitUpdateElement(IRInst* base, ArrayView<IRInst*> accessChain, IRInst* newElement);
-
+ IRInst* emitGetOffsetPtr(IRInst* base, IRInst* offset);
IRInst* emitGetAddress(
IRType* type,
IRInst* value);
diff --git a/source/slang/slang-ir-lower-buffer-element-type.cpp b/source/slang/slang-ir-lower-buffer-element-type.cpp
index d0ad7483a..29999017a 100644
--- a/source/slang/slang-ir-lower-buffer-element-type.cpp
+++ b/source/slang/slang-ir-lower-buffer-element-type.cpp
@@ -361,7 +361,11 @@ namespace Slang
info.loweredInnerStructKey = structKey;
info.convertLoweredToOriginal = createArrayUnpackFunc(arrayType, loweredType, structKey, innerArrayType, loweredInnerTypeInfo);
info.convertOriginalToLowered = createArrayPackFunc(arrayType, loweredType, innerArrayType, loweredInnerTypeInfo);
-
+ return info;
+ }
+ else if (as<IRArrayTypeBase>(type))
+ {
+ info.loweredType = builder.getVoidType();
return info;
}
else if (auto structType = as<IRStructType>(type))
@@ -399,6 +403,11 @@ namespace Slang
Index fieldId = 0;
for (auto field : structType->getFields())
{
+ if (as<IRVoidType>(fieldLoweredTypeInfo[fieldId].loweredType))
+ {
+ fieldId++;
+ continue;
+ }
auto loweredFieldTypeInfo = fieldLoweredTypeInfo[fieldId];
builder.createStructField(loweredType, field->getKey(), loweredFieldTypeInfo.loweredType);
fieldId++;
@@ -418,6 +427,11 @@ namespace Slang
Index fieldId = 0;
for (auto field : structType->getFields())
{
+ if (as<IRVoidType>(fieldLoweredTypeInfo[fieldId].loweredType))
+ {
+ fieldId++;
+ continue;
+ }
auto storageField = builder.emitFieldExtract(fieldLoweredTypeInfo[fieldId].loweredType, loweredParam, field->getKey());
auto unpackedField = fieldLoweredTypeInfo[fieldId].convertLoweredToOriginal
? builder.emitCallInst(field->getFieldType(), fieldLoweredTypeInfo[fieldId].convertLoweredToOriginal, 1, &storageField)
@@ -442,6 +456,11 @@ namespace Slang
Index fieldId = 0;
for (auto field : structType->getFields())
{
+ if (as<IRVoidType>(fieldLoweredTypeInfo[fieldId].loweredType))
+ {
+ fieldId++;
+ continue;
+ }
auto fieldVal = builder.emitFieldExtract(field->getFieldType(), param, field->getKey());
auto packedField = fieldLoweredTypeInfo[fieldId].convertOriginalToLowered
? builder.emitCallInst(fieldLoweredTypeInfo[fieldId].loweredType, fieldLoweredTypeInfo[fieldId].convertOriginalToLowered, 1, &fieldVal)
@@ -641,6 +660,66 @@ namespace Slang
auto ptrVal = ptrValsWorkList[i];
auto oldPtrType = ptrVal->getFullType();
auto originalElementType = oldPtrType->getOperand(0);
+
+ // If we are accessing an unsized array element from a pointer, we need to compute
+ // the trailing ptr that points to the first element of the array.
+ // And then replace all getElementPtr(arrayPtr, index) with getOffsetPtr(trailingPtr, index).
+ if (auto fieldAddr = as<IRFieldAddress>(ptrVal))
+ {
+ if (auto ptrType = as<IRPtrType>(ptrVal->getDataType()))
+ {
+ if (auto unsizedArrayType = as<IRUnsizedArrayType>(ptrType->getValueType()))
+ {
+ builder.setInsertBefore(ptrVal);
+ auto newArrayPtrVal = builder.emitGetOffsetPtr(fieldAddr->getBase(), builder.getIntValue(builder.getIntType(), 1));
+ auto loweredInnerType = getLoweredTypeInfo(unsizedArrayType->getElementType(), layoutRules);
+
+ IRSizeAndAlignment arrayElementSizeAlignment;
+ getSizeAndAlignment(
+ target->getOptionSet(), layoutRules, loweredInnerType.loweredType, &arrayElementSizeAlignment);
+ IRSizeAndAlignment baseSizeAlignment;
+ getSizeAndAlignment(
+ target->getOptionSet(),
+ layoutRules,
+ tryGetPointedToType(&builder, fieldAddr->getBase()->getDataType()),
+ &baseSizeAlignment);
+
+ // Convert pointer to uint64 and adjust offset.
+ auto rawPtr = builder.emitBitCast(builder.getUInt64Type(), newArrayPtrVal);
+ IRIntegerValue offset = baseSizeAlignment.size;
+ offset = align(offset, arrayElementSizeAlignment.alignment);
+ newArrayPtrVal = builder.emitAdd(rawPtr->getFullType(), rawPtr,
+ builder.getIntValue(builder.getUInt64Type(), offset));
+
+ newArrayPtrVal = builder.emitBitCast(
+ builder.getPtrType(loweredInnerType.loweredType,
+ ptrType->getAddressSpace()), newArrayPtrVal);
+ traverseUses(ptrVal, [&](IRUse* use)
+ {
+ auto user = use->getUser();
+ if (user->getOp() == kIROp_GetElementPtr)
+ {
+ builder.setInsertBefore(user);
+ auto newElementPtr = builder.emitGetOffsetPtr(newArrayPtrVal, user->getOperand(1));
+ user->replaceUsesWith(newElementPtr);
+ user->removeAndDeallocate();
+ ptrValsWorkList.add(newElementPtr);
+ }
+ else if (user->getOp() == kIROp_GetOffsetPtr)
+ {
+ }
+ else
+ {
+ SLANG_UNEXPECTED("unknown use of pointer to unsized array.");
+ }
+ });
+ SLANG_ASSERT(!ptrVal->hasUses());
+ ptrVal->removeAndDeallocate();
+ continue;
+ }
+ }
+ }
+
auto loweredElementTypeInfo = getLoweredTypeInfo((IRType*)originalElementType, layoutRules);
if (!loweredElementTypeInfo.convertLoweredToOriginal)
continue;
diff --git a/source/slang/slang-ir-specialize-address-space.cpp b/source/slang/slang-ir-specialize-address-space.cpp
index 60aa1f10a..836601a00 100644
--- a/source/slang/slang-ir-specialize-address-space.cpp
+++ b/source/slang/slang-ir-specialize-address-space.cpp
@@ -177,6 +177,8 @@ namespace Slang
}
case kIROp_GetElementPtr:
case kIROp_FieldAddress:
+ case kIROp_GetOffsetPtr:
+ case kIROp_BitCast:
if (!mapInstToAddrSpace.containsKey(inst))
{
auto addrSpace = getAddrSpace(inst->getOperand(0));
diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp
index f0e7773c6..f190b3a11 100644
--- a/source/slang/slang-ir.cpp
+++ b/source/slang/slang-ir.cpp
@@ -5464,6 +5464,12 @@ namespace Slang
return inst;
}
+ IRInst* IRBuilder::emitGetOffsetPtr(IRInst* base, IRInst* offset)
+ {
+ IRInst* args[] = { base, offset };
+ return emitIntrinsicInst(base->getDataType(), kIROp_GetOffsetPtr, 2, args);
+ }
+
IRInst* IRBuilder::emitGetAddress(
IRType* type,
IRInst* value)
diff --git a/tests/bugs/gh-3825.slang b/tests/bugs/gh-3825.slang
index 1feadb588..c7c325864 100644
--- a/tests/bugs/gh-3825.slang
+++ b/tests/bugs/gh-3825.slang
@@ -4,7 +4,7 @@
//TEST:SIMPLE(filecheck=CHECK): -entry fragment -stage fragment -emit-spirv-directly -target spirv-assembly -emit-spirv-directly
struct Descriptors {
uint count;
- uint array[];
+ uint4 array[];
}
struct Context {
@@ -17,7 +17,11 @@ struct Context {
[shader("fragment")]
float4 fragment(): SV_Target
{
- return float4(float(context.descriptors[0].array[0]), 1., 1., 1.);
+ return float4(float(context.descriptors->array[0].x), 1., 1., 1.);
}
-// CHECK: OpDecorate %_ptr_PhysicalStorageBuffer__runtimearr_uint ArrayStride 65535
+// CHECK: OpDecorate %_ptr_PhysicalStorageBuffer_Descriptors_natural ArrayStride 4
+// CHECK: %{{.*}} = OpPtrAccessChain %_ptr_PhysicalStorageBuffer_Descriptors_natural %{{.*}} %int_1
+// CHECK: OpBitcast %ulong
+// CHECK: OpIAdd %ulong %{{.*}} %ulong_4
+// CHECK: OpBitcast %_ptr_PhysicalStorageBuffer \ No newline at end of file
diff --git a/tests/spirv/ptr-unsized-array.slang b/tests/spirv/ptr-unsized-array.slang
new file mode 100644
index 000000000..48added5c
--- /dev/null
+++ b/tests/spirv/ptr-unsized-array.slang
@@ -0,0 +1,23 @@
+//TEST:SIMPLE(filecheck=CHECK): -target spirv
+
+// CHECK: OpPtrAccessChain
+
+struct MeshVertex {
+ float3 Pos;
+ float2 TexCoord;
+};
+struct MeshData {
+ float4x4 ModelMat;
+ MeshVertex Vertices[];
+};
+struct DispatchParams {
+ MeshData* Mesh;
+ float3* Dest;
+};
+
+[vk::push_constant] DispatchParams pc;
+
+[numthreads(64)]
+void ComputeMain(uint tid: SV_DispatchThreadID) {
+ pc.Dest[tid] = pc.Mesh->Vertices[tid].Pos;
+} \ No newline at end of file