diff options
| author | Yong He <yonghe@outlook.com> | 2024-10-09 07:35:10 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-10-09 22:35:10 +0800 |
| commit | ac6f04c15995061ebe8e0ddf62ecf7eb979afb65 (patch) | |
| tree | f16f0f01f1f8d0e73ecd774a22f87576f440f8e8 | |
| parent | bea1394ad35680940a0b69b9c67efc43764cc194 (diff) | |
Fix spirv lowering logic around pointer to unsized array. (#5243)
* Fix spirv lowering logic around pointer to unsized array.
* Fix.
---------
Co-authored-by: Ellie Hermaszewska <ellieh@nvidia.com>
| -rw-r--r-- | source/slang/slang-check-decl.cpp | 5 | ||||
| -rw-r--r-- | source/slang/slang-diagnostic-defs.h | 1 | ||||
| -rw-r--r-- | source/slang/slang-ir-insts.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-ir-lower-buffer-element-type.cpp | 81 | ||||
| -rw-r--r-- | source/slang/slang-ir-specialize-address-space.cpp | 2 | ||||
| -rw-r--r-- | source/slang/slang-ir.cpp | 6 | ||||
| -rw-r--r-- | tests/bugs/gh-3825.slang | 10 | ||||
| -rw-r--r-- | tests/spirv/ptr-unsized-array.slang | 23 |
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 |
