From ac6f04c15995061ebe8e0ddf62ecf7eb979afb65 Mon Sep 17 00:00:00 2001 From: Yong He Date: Wed, 9 Oct 2024 07:35:10 -0700 Subject: 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 --- source/slang/slang-check-decl.cpp | 5 ++ source/slang/slang-diagnostic-defs.h | 1 + source/slang/slang-ir-insts.h | 2 +- .../slang/slang-ir-lower-buffer-element-type.cpp | 81 +++++++++++++++++++++- source/slang/slang-ir-specialize-address-space.cpp | 2 + source/slang/slang-ir.cpp | 6 ++ 6 files changed, 95 insertions(+), 2 deletions(-) (limited to 'source') 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(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 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(type)) + { + info.loweredType = builder.getVoidType(); return info; } else if (auto structType = as(type)) @@ -399,6 +403,11 @@ namespace Slang Index fieldId = 0; for (auto field : structType->getFields()) { + if (as(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(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(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(ptrVal)) + { + if (auto ptrType = as(ptrVal->getDataType())) + { + if (auto unsizedArrayType = as(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) -- cgit v1.2.3