diff options
| author | Yong He <yonghe@outlook.com> | 2025-07-01 19:09:29 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-07-02 02:09:29 +0000 |
| commit | c701ec00ccce6dfa8094d6550ce2db929fc8cefe (patch) | |
| tree | 4f729e8fa5700b2d6d7d99f34514682e3ad351f8 | |
| parent | 83c72fd8772d312233f4e3ccd4154b81030d4795 (diff) | |
Defer immutable buffer loads when emitting spirv. (#7579)
* Defer immutable buffer loads when emitting spirv.
* Fix.
* Fix.
* Fix.
* Fix tests.
* Fix test.
24 files changed, 218 insertions, 61 deletions
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 6d8788b4f..9c77303b9 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -14471,6 +14471,15 @@ VarDeclBase* getTrailingUnsizedArrayElement( return nullptr; } +bool isImmutableBufferType(Type* type) +{ + if (as<UniformParameterGroupType>(type)) + return true; + if (auto resourceType = as<ResourceType>(type)) + return resourceType->getAccess() == SLANG_RESOURCE_ACCESS_READ; + return false; +} + bool isOpaqueHandleType(Type* type) { while (auto modifiedType = as<ModifiedType>(type)) diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index c3238bd9b..b28b458da 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -538,6 +538,11 @@ Expr* SemanticsVisitor::constructDerefExpr(Expr* base, QualType elementType, Sou { derefExpr->type.isLeftValue = true; } + else if (isImmutableBufferType(base->type)) + { + derefExpr->type.isLeftValue = false; + derefExpr->type.isWriteOnly = false; + } else { derefExpr->type.isLeftValue = base->type.isLeftValue; diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index e73f65d75..7ddec20fb 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -3145,6 +3145,8 @@ bool isUnsizedArrayType(Type* type); bool isInterfaceType(Type* type); +bool isImmutableBufferType(Type* type); + // Check if `type` is nullable. An `Optional<T>` will occupy the same space as `T`, if `T` // is nullable. bool isNullableType(Type* type); diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index 24acea42f..af4345942 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -2707,7 +2707,7 @@ void CLikeSourceEmitter::defaultEmitInstExpr(IRInst* inst, const EmitOpInfo& inO case kIROp_NonUniformResourceIndex: emitOperand( inst->getOperand(0), - getInfo(EmitOp::General)); // Directly emit NonUniformResourceIndex Operand0; + outerPrec); // Directly emit NonUniformResourceIndex Operand0; break; case kIROp_GetNativeStr: diff --git a/source/slang/slang-emit-spirv-ops.h b/source/slang/slang-emit-spirv-ops.h index 4d33e045e..a5e4d730a 100644 --- a/source/slang/slang-emit-spirv-ops.h +++ b/source/slang/slang-emit-spirv-ops.h @@ -672,6 +672,21 @@ SpvInst* emitOpAccessChain( return emitInst(parent, inst, SpvOpAccessChain, idResultType, kResultID, base, indexes); } +// https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpInBoundsAccessChain +template<typename T1, typename T2, typename Ts> +SpvInst* emitOpInBoundsAccessChain( + SpvInstParent* parent, + IRInst* inst, + const T1& idResultType, + const T2& base, + const Ts& indexes) +{ + static_assert(isSingular<T1>); + static_assert(isSingular<T2>); + static_assert(isPlural<Ts>); + return emitInst(parent, inst, SpvOpInBoundsAccessChain, idResultType, kResultID, base, indexes); +} + // https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpPtrAccessChain template<typename T1, typename T2, typename T3> diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp index 1e6f27e7f..62c667de1 100644 --- a/source/slang/slang-emit-spirv.cpp +++ b/source/slang/slang-emit-spirv.cpp @@ -6824,7 +6824,7 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex getStructFieldId(baseStructType, as<IRStructKey>(fieldAddress->getField())), builder.getIntType()); SLANG_ASSERT(as<IRPtrTypeBase>(fieldAddress->getFullType())); - return emitOpAccessChain( + return emitOpInBoundsAccessChain( parent, fieldAddress, fieldAddress->getFullType(), @@ -6869,7 +6869,6 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex // We might replace resultType with a different storage class equivalent auto resultType = as<IRPtrTypeBase>(inst->getDataType()); SLANG_ASSERT(resultType); - if (const auto basePtrType = as<IRPtrTypeBase>(base->getDataType())) { // If the base pointer has a specific address space and the diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index 49b27383d..db8a9ba61 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -1227,11 +1227,6 @@ Result linkAndOptimizeIR( // Inline calls to any functions marked with [__unsafeInlineEarly] or [ForceInline]. performForceInlining(irModule); - // Push `structuredBufferLoad` to the end of access chain to avoid loading unnecessary data. - if (isKhronosTarget(targetRequest) || isMetalTarget(targetRequest) || - isWGPUTarget(targetRequest)) - deferBufferLoad(irModule); - // Specialization can introduce dead code that could trip // up downstream passes like type legalization, so we // will run a DCE pass to clean up after the specialization. @@ -1386,6 +1381,11 @@ Result linkAndOptimizeIR( specializeResourceUsage(codeGenContext, irModule); specializeFuncsForBufferLoadArgs(codeGenContext, irModule); + // Push `structuredBufferLoad` to the end of access chain to avoid loading unnecessary data. + if (isKhronosTarget(targetRequest) || isMetalTarget(targetRequest) || + isWGPUTarget(targetRequest)) + deferBufferLoad(irModule); + // We also want to specialize calls to functions that // takes unsized array parameters if possible. // Moreover, for Khronos targets, we also want to specialize calls to functions diff --git a/source/slang/slang-ir-defer-buffer-load.cpp b/source/slang/slang-ir-defer-buffer-load.cpp index bd3b78f9e..e71892fe5 100644 --- a/source/slang/slang-ir-defer-buffer-load.cpp +++ b/source/slang/slang-ir-defer-buffer-load.cpp @@ -18,7 +18,6 @@ struct DeferBufferLoadContext Dictionary<IRInst*, IRInst*> mapPtrToValue; IRFunc* currentFunc = nullptr; - IRDominatorTree* dominatorTree = nullptr; // Ensure that for an original SSA value, we have formed a pointer that can be used to load the // value. @@ -57,6 +56,9 @@ struct DeferBufferLoadContext result = b.emitFieldAddress(ptr, valueInst->getOperand(1)); break; } + case kIROp_Load: + result = valueInst->getOperand(0); + break; } if (result) { @@ -65,7 +67,39 @@ struct DeferBufferLoadContext return result; } - static bool isStructuredBufferLoad(IRInst* inst) + static bool isImmutableLocation(IRInst* loc) + { + switch (loc->getOp()) + { + case kIROp_GetStructuredBufferPtr: + case kIROp_ImageSubscript: + return isImmutableLocation(loc->getOperand(0)); + default: + break; + } + + auto type = loc->getDataType(); + if (!type) + return false; + + switch (type->getOp()) + { + case kIROp_HLSLStructuredBufferType: + case kIROp_HLSLByteAddressBufferType: + case kIROp_ConstantBufferType: + case kIROp_ParameterBlockType: + return true; + default: + break; + } + + if (auto textureType = as<IRTextureType>(type)) + return textureType->getAccess() == SLANG_RESOURCE_ACCESS_READ; + + return false; + } + + static bool isImmutableBufferLoad(IRInst* inst) { // Note: we cannot defer loads from RWStructuredBuffer because there can be other // instructions that modify the buffer. @@ -74,6 +108,11 @@ struct DeferBufferLoadContext case kIROp_StructuredBufferLoad: case kIROp_StructuredBufferLoadStatus: return true; + case kIROp_Load: + { + auto rootAddr = getRootAddr(inst->getOperand(0)); + return isImmutableLocation(rootAddr); + } default: return false; } @@ -88,33 +127,49 @@ struct DeferBufferLoadContext IRInst* result = nullptr; if (mapPtrToValue.tryGetValue(ptr, result)) return result; - builder.setInsertAfter(ptr); - result = builder.emitLoad(ptr); - mapPtrToValue[ptr] = result; + IRAlignedAttr* align = nullptr; + if (auto load = as<IRLoad>(loadInst)) + align = load->findAttr<IRAlignedAttr>(); + if (!as<IRModuleInst>(ptr->getParent())) + { + builder.setInsertAfter(ptr); + IRType* valueType = tryGetPointedToType(&builder, ptr->getFullType()); + result = builder.emitLoad(valueType, ptr, align); + mapPtrToValue[ptr] = result; + } + else + { + builder.setInsertBefore(loadInst); + IRType* valueType = tryGetPointedToType(&builder, ptr->getFullType()); + result = builder.emitLoad(valueType, ptr, align); + // Since we are inserting the load in a local scope, we can't register + // the mapping to the pointer, since the global pointer needs to be + // loaded once per function. + } return result; } static bool isSimpleType(IRInst* type) { - if (as<IRBasicType>(type)) - return true; - if (as<IRVectorType>(type)) - return true; - if (as<IRMatrixType>(type)) - return true; - return false; + if (auto modType = as<IRRateQualifiedType>(type)) + type = modType->getValueType(); + if (as<IRStructType>(type)) + return false; + if (as<IRTupleType>(type)) + return false; + if (as<IRArrayTypeBase>(type)) + return false; + return true; } void deferBufferLoadInst(IRBuilder& builder, List<IRInst*>& workList, IRInst* loadInst) { // Don't defer the load anymore if the type is simple. - if (isSimpleType(loadInst->getDataType())) + if (isSimpleType(loadInst->getDataType()) || loadInst->findAttr<IRAlignedAttr>()) { - if (!isStructuredBufferLoad(loadInst)) - { - auto materializedVal = materializePointer(builder, loadInst); - loadInst->replaceUsesWith(materializedVal); - } + auto materializedVal = materializePointer(builder, loadInst); + loadInst->transferDecorationsTo(materializedVal); + loadInst->replaceUsesWith(materializedVal); return; } @@ -141,18 +196,15 @@ struct DeferBufferLoadContext } break; default: - if (!isStructuredBufferLoad(loadInst)) - { - needMaterialize = true; - return; - } - break; + needMaterialize = true; + return; } }); if (needMaterialize) { auto val = materializePointer(builder, loadInst); + loadInst->transferDecorationsTo(val); loadInst->replaceUsesWith(val); loadInst->removeAndDeallocate(); } @@ -170,7 +222,6 @@ struct DeferBufferLoadContext removeRedundancyInFunc(func, false); currentFunc = func; - dominatorTree = func->getModule()->findOrCreateDominatorTree(func); List<IRInst*> workList; @@ -178,7 +229,7 @@ struct DeferBufferLoadContext { for (auto inst : block->getChildren()) { - if (isStructuredBufferLoad(inst)) + if (isImmutableBufferLoad(inst)) { workList.add(inst); } diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h index 8ce4e46cd..afe06f9a1 100644 --- a/source/slang/slang-ir-insts.h +++ b/source/slang/slang-ir-insts.h @@ -4310,6 +4310,7 @@ public: IRInst* emitLoad(IRType* type, IRInst* ptr); IRInst* emitLoad(IRType* type, IRInst* ptr, IRInst* align); + IRInst* emitLoad(IRType* type, IRInst* ptr, IRAlignedAttr* align); IRInst* emitLoad(IRInst* ptr); IRInst* emitLoadReverseGradient(IRType* type, IRInst* diffValue); diff --git a/source/slang/slang-ir-specialize-function-call.cpp b/source/slang/slang-ir-specialize-function-call.cpp index 7a9fc5f6f..c03e644de 100644 --- a/source/slang/slang-ir-specialize-function-call.cpp +++ b/source/slang/slang-ir-specialize-function-call.cpp @@ -338,7 +338,9 @@ struct FunctionParameterSpecializationContext // correctly check the preconditions. // auto oldFunc = as<IRFunc>(oldCall->getCallee()); - SLANG_ASSERT(oldFunc); + if (!oldFunc) + return; + SLANG_ASSERT(oldFunc->isDefinition()); // Our first information-gathering pass will @@ -390,6 +392,14 @@ struct FunctionParameterSpecializationContext newCall->insertBefore(oldCall); oldCall->replaceUsesWith(newCall); oldCall->removeAndDeallocate(); + + // If old func is no longer used after the specialization, + // remove it. + if (!oldFunc->hasUses()) + { + if (!shouldInstBeLiveIfParentIsLive(oldFunc, IRDeadCodeEliminationOptions{})) + oldFunc->removeAndDeallocate(); + } } // Before diving into the details on how we gather information diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index dc25b1489..7c687f4f1 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -5107,6 +5107,20 @@ IRInst* IRBuilder::emitLoad(IRType* type, IRInst* ptr, IRInst* align) return inst; } +IRInst* IRBuilder::emitLoad(IRType* type, IRInst* ptr, IRAlignedAttr* align) +{ + if (align) + { + auto inst = createInst<IRLoad>(this, kIROp_Load, type, ptr, align); + addInst(inst); + return inst; + } + else + { + return emitLoad(type, ptr); + } +} + IRInst* IRBuilder::emitLoad(IRInst* ptr) { // Note: a `load` operation does not consider the rate diff --git a/tests/diagnostics/parameter-block-to-mutating-func.slang b/tests/diagnostics/parameter-block-to-mutating-func.slang new file mode 100644 index 000000000..b5bdb4550 --- /dev/null +++ b/tests/diagnostics/parameter-block-to-mutating-func.slang @@ -0,0 +1,27 @@ +//TEST:SIMPLE(filecheck=CHECK):-target spirv +struct Data { + StructuredBuffer<float> input[2]; + RWStructuredBuffer<float> output; + uint input_tensor_count; + StructuredBuffer<uint> index_buffer; + uint index_count; + + [mutating] + float fetch(int buffer, int index) + { + return input[buffer][index]; + } +}; + +[shader("compute")] +[numthreads(8, 8, 1)] +void compute_main(uint3 tid: SV_DispatchThreadID, ParameterBlock<Data> data) +{ + float result = 0.0; + for (int i = 0; i < data.index_count; ++i) { + uint buffer = data.index_buffer[i]; + //CHECK: ([[# @LINE+1]]): error + result += data.fetch(buffer, tid.x * 1024 + tid.y); + } + data.output[tid.x * 1024 + tid.y] = result; +} diff --git a/tests/glsl-intrinsic/intrinsic-basic.slang b/tests/glsl-intrinsic/intrinsic-basic.slang index 4e1dfe8c4..7e4a76734 100644 --- a/tests/glsl-intrinsic/intrinsic-basic.slang +++ b/tests/glsl-intrinsic/intrinsic-basic.slang @@ -56,7 +56,7 @@ bool Test_ScalarType() const mat3 identity3x3 = mat3(vec3(1,0,0),vec3(0,1,0),vec3(0,0,1)); const mat4 identity4x4 = mat4(vec4(1,0,0,0),vec4(0,1,0,0),vec4(0,0,1,0),vec4(0,0,0,1)); - // CHECK_SPIR-LABEL: OpAccessChain {{.*}} %inputBuffer + // CHECK_SPIR-LABEL: Op{{.*}}AccessChain {{.*}} %inputBuffer const int zero = inputBuffer.data[0]; const int one = inputBuffer.data[1]; const int negaOne = inputBuffer.data[2]; @@ -539,7 +539,7 @@ bool Test_VectorType() constexpr const float epsilon = 0.000001; - // CHECK_SPIR-LABEL: OpAccessChain {{.*}} %inputBuffer + // CHECK_SPIR-LABEL: Op{{.*}}AccessChain {{.*}} %inputBuffer const int zero = inputBuffer.data[0]; const int one = inputBuffer.data[1]; const int negaOne = inputBuffer.data[2]; @@ -1106,7 +1106,7 @@ bool Test_VectorType() ; // CHECK_GLSL-LABEL: bool Test_VectorType_1 - // CHECK_SPIR-LABEL: OpAccessChain {{.*}} %inputBuffer + // CHECK_SPIR-LABEL: Op{{.*}}AccessChain {{.*}} %inputBuffer } [numthreads(4, 1, 1)] diff --git a/tests/spirv/aligned-load-store.slang b/tests/spirv/aligned-load-store.slang index e8bee779e..c2f50b66c 100644 --- a/tests/spirv/aligned-load-store.slang +++ b/tests/spirv/aligned-load-store.slang @@ -3,8 +3,8 @@ // CHECK: OpLoad {{.*}} Aligned 8 // CHECK: OpStore {{.*}} Aligned 16 -// CHECK: OpLoad {{.*}} Aligned 8 -// CHECK: OpLoad {{.*}} Aligned 8 +// CHECK: OpLoad {{.*}} Aligned 16 +// CHECK: OpLoad {{.*}} Aligned 16 // CHECK: OpStore {{.*}} Aligned 16 // CHECK: OpStore {{.*}} Aligned 16 @@ -20,6 +20,7 @@ void computeMain() var v = loadAligned<8>((float2x4*)data); storeAligned<16>((float2x4*)data+1, v); - var v1 = loadAligned<8>(data2); + var v1 = loadAligned<16>(data2); + v1.v0 += 1.0f; storeAligned<16>(data2, v1); }
\ No newline at end of file diff --git a/tests/spirv/fetch-array-from-parameter-block.slang b/tests/spirv/fetch-array-from-parameter-block.slang new file mode 100644 index 000000000..4a86bfb8d --- /dev/null +++ b/tests/spirv/fetch-array-from-parameter-block.slang @@ -0,0 +1,22 @@ +//TEST:SIMPLE(filecheck=CHECK):-target spirv + +//CHECK-NOT: OpCompositeConstruct +//CHECK-COUNT-1: OpStore + +struct Data +{ + int bigArray[8]; + int fetch(int i) + { + return bigArray[i]; + } +} + +ParameterBlock<Data> pData; +uniform int* result; + +[numthreads(16,1,1)] +void main(int id : SV_DispatchThreadID) +{ + *result = pData.fetch(id); +}
\ No newline at end of file diff --git a/tests/spirv/large-struct.slang b/tests/spirv/large-struct.slang index 7738a5fcf..2d79c0aaf 100644 --- a/tests/spirv/large-struct.slang +++ b/tests/spirv/large-struct.slang @@ -3,9 +3,8 @@ //TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-d3d12 -compute -output-using-type //TEST(compute, vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=BUF):-cpu -compute -output-using-type -// Check that when generating spirv directly, we use a loop -// to copy large arrays in input data out into a local variable, instead of emitting -// unrolled code that reads each element of the array individually. +// Check that when generating spirv directly, we do not load the entire big array +// from the constant buffer into registers. struct WorkData { @@ -21,7 +20,9 @@ ConstantBuffer<WorkData> input; //TEST_INPUT:set resultBuffer = out ubuffer(data=[0 0 0 0], stride=4) RWStructuredBuffer<float> resultBuffer; -// CHECK: OpLoopMerge +// CHECK-NOT: OpLoopMerge +// CHECK-NOT: OpCompositeConstruct +// CHECK-COUNT-1: OpStore [numthreads(2, 1, 1)] void computeMain(uint3 tid: SV_DispatchThreadID) diff --git a/tests/spirv/pointer-data-marshal.slang b/tests/spirv/pointer-data-marshal.slang index 3ad6c373b..a07a365ce 100644 --- a/tests/spirv/pointer-data-marshal.slang +++ b/tests/spirv/pointer-data-marshal.slang @@ -8,9 +8,9 @@ struct Params { Foo *foo; }; -// CHECK: %[[PTR0:[A-Za-z0-9_]+]] = OpAccessChain %_ptr_PhysicalStorageBuffer__arr_v3float_int_2 %{{.*}} %int_0 -// CHECK: %[[PTR1:[A-Za-z0-9_]+]] = OpAccessChain %_ptr_PhysicalStorageBuffer_v3float %[[PTR0]] %int_1 -// CHECK: %[[PTR2:[A-Za-z0-9_]+]] = OpAccessChain %_ptr_PhysicalStorageBuffer_float %[[PTR1]] %int_2 +// CHECK: %[[PTR0:[A-Za-z0-9_]+]] = Op{{.*}}AccessChain %_ptr_PhysicalStorageBuffer__arr_v3float_int_2 %{{.*}} %int_0 +// CHECK: %[[PTR1:[A-Za-z0-9_]+]] = Op{{.*}}AccessChain %_ptr_PhysicalStorageBuffer_v3float %[[PTR0]] %int_1 +// CHECK: %[[PTR2:[A-Za-z0-9_]+]] = Op{{.*}}AccessChain %_ptr_PhysicalStorageBuffer_float %[[PTR1]] %int_2 ConstantBuffer<Params> params; diff --git a/tests/spirv/ptr-unsized-array-2.slang b/tests/spirv/ptr-unsized-array-2.slang index ac0911d76..eb653d0a6 100644 --- a/tests/spirv/ptr-unsized-array-2.slang +++ b/tests/spirv/ptr-unsized-array-2.slang @@ -3,7 +3,7 @@ // CHECK-DAG: %[[cbuffer__t:[A-Za-z0-9_]+]] = OpTypeStruct %_ptr_PhysicalStorageBuffer_uint // CHECK-DAG: %light_buffer = OpVariable %_ptr_PushConstant_[[cbuffer__t]] PushConstant -// CHECK: OpAccessChain %_ptr_PushConstant +// CHECK: Op{{.*}}AccessChain %_ptr_PushConstant // CHECK-NEXT: OpLoad // CHECK-NEXT: OpBitcast %_ptr_PhysicalStorageBuffer diff --git a/tests/spirv/ref-this.slang b/tests/spirv/ref-this.slang index de4263975..890e1451f 100644 --- a/tests/spirv/ref-this.slang +++ b/tests/spirv/ref-this.slang @@ -1,6 +1,6 @@ //TEST:SIMPLE(filecheck=CHECK): -target spirv -// CHECK: %[[PTR:[0-9a-zA-Z_]+]] = OpAccessChain %_ptr_PhysicalStorageBuffer_uint %{{.*}} %int_0 +// CHECK: %[[PTR:[0-9a-zA-Z_]+]] = Op{{.*}}AccessChain %_ptr_PhysicalStorageBuffer_uint %{{.*}} %int_0 // CHECK: %{{.*}} = OpAtomicIAdd %uint %[[PTR]] %uint_1 %uint_0 %uint_1 struct Buf diff --git a/tests/spirv/subgroup-size-2.slang b/tests/spirv/subgroup-size-2.slang index 500bd63c8..f7376f584 100644 --- a/tests/spirv/subgroup-size-2.slang +++ b/tests/spirv/subgroup-size-2.slang @@ -15,12 +15,12 @@ uint3 f() { return WorkgroupSize(); } void compute1() { // CHECK_EXPERIMENTAL-DAG: %[[VAR:[A-Za-z0-9_]+]] = OpTypePointer Function %v3int - // CHECK_EXPERIMENTAL: OpAccessChain %[[VAR]] + // CHECK_EXPERIMENTAL: Op{{.*}}AccessChain %[[VAR]] // // CHECK_EXPERIMENTAL-DAG: %[[CALL_RS:[A-Za-z0-9_]+]] = OpFunctionCall %v3uint %f // CHECK_EXPERIMENTAL: OpCompositeExtract %uint %[[CALL_RS]] 0 // - // CHECK_EXPERIMENTAL-DAG: %[[PTR:[A-Za-z0-9_]+]] = OpAccessChain %_ptr_StorageBuffer_int %outputBuffer %int_0 %int_1 + // CHECK_EXPERIMENTAL-DAG: %[[PTR:[A-Za-z0-9_]+]] = Op{{.*}}AccessChain %_ptr_StorageBuffer_int %outputBuffer %int_0 %int_1 // CHECK_EXPERIMENTAL: OpStore %[[PTR]] %int_2 // CHECK-DAG: %[[VAR:[A-Za-z0-9_]+]] = OpVariable %_ptr_Private_v3int Private @@ -29,7 +29,7 @@ void compute1() // CHECK-DAG: %[[CALL_RS:[A-Za-z0-9_]+]] = OpFunctionCall %v3uint %f // CHECK: OpCompositeExtract %uint %[[CALL_RS]] 0 // - // CHECK-DAG: %[[PTR:[A-Za-z0-9_]+]] = OpAccessChain %_ptr_StorageBuffer_int %outputBuffer %int_0 %int_1 + // CHECK-DAG: %[[PTR:[A-Za-z0-9_]+]] = Op{{.*}}AccessChain %_ptr_StorageBuffer_int %outputBuffer %int_0 %int_1 // CHECK: OpStore %[[PTR]] %int_2 const int x = f().x; diff --git a/tests/vkray/callable.slang b/tests/vkray/callable.slang index f3aa55979..51f69ad1c 100644 --- a/tests/vkray/callable.slang +++ b/tests/vkray/callable.slang @@ -22,5 +22,5 @@ void main(in out MaterialPayload ioPayload) // CHECK-DAG: OpTypePointer IncomingCallableData{{NV|KHR}} // CHECK-DAG: OpTypePointer IncomingCallableData{{NV|KHR}} // CHECK-DAG: OpTypePointer IncomingCallableData{{NV|KHR}} -// CHECK-DAG: %{{.*}} = OpAccessChain %{{.*}} %{{.*}} %{{.*}} -// CHECK-DAG: %{{.*}} = OpAccessChain %{{.*}} %{{.*}} %{{.*}} +// CHECK-DAG: %{{.*}} = Op{{.*}}AccessChain %{{.*}} %{{.*}} %{{.*}} +// CHECK-DAG: %{{.*}} = Op{{.*}}AccessChain %{{.*}} %{{.*}} %{{.*}}
\ No newline at end of file diff --git a/tests/vkray/closesthit.slang b/tests/vkray/closesthit.slang index b7d40e5f9..9d767ccae 100644 --- a/tests/vkray/closesthit.slang +++ b/tests/vkray/closesthit.slang @@ -56,8 +56,8 @@ void main( // CHECK-DAG: %{{.*}} = OpVariable %_ptr_IncomingRayPayload{{NV|KHR}}_ReflectionRay{{.*}} IncomingRayPayload{{NV|KHR}} // CHECK-DAG: %{{.*}} = OpLoad %{{u?}}int %[[INSTANCE_ID]] // CHECK-DAG: %{{.*}} = OpLoad %{{u?}}int %[[INSTANCE_INDEX]] -// CHECK-DAG: %{{.*}} = OpAccessChain %_ptr_ShaderRecordBuffer{{NV|KHR}}_uint %ShaderRecord{{.*}} %int_0 -// CHECK-DAG: %{{.*}} = OpAccessChain %_ptr_IncomingRayPayload{{NV|KHR}}_v4float %{{.*}} %int_0 -// CHECK-DAG: %{{.*}} = OpAccessChain %_ptr_Input_v3float %{{.*}} %{{u?}}int_0 -// CHECK-DAG: %{{.*}} = OpAccessChain %_ptr_Input_v3float %{{.*}} %{{u?}}int_1 -// CHECK-DAG: %{{.*}} = OpAccessChain %_ptr_Input_v3float %{{.*}} %{{u?}}int_2 +// CHECK-DAG: %{{.*}} = Op{{.*}}AccessChain %_ptr_ShaderRecordBuffer{{NV|KHR}}_uint %ShaderRecord{{.*}} %int_0 +// CHECK-DAG: %{{.*}} = Op{{.*}}AccessChain %_ptr_IncomingRayPayload{{NV|KHR}}_v4float %{{.*}} %int_0 +// CHECK-DAG: %{{.*}} = Op{{.*}}AccessChain %_ptr_Input_v3float %{{.*}} %{{u?}}int_0 +// CHECK-DAG: %{{.*}} = Op{{.*}}AccessChain %_ptr_Input_v3float %{{.*}} %{{u?}}int_1 +// CHECK-DAG: %{{.*}} = Op{{.*}}AccessChain %_ptr_Input_v3float %{{.*}} %{{u?}}int_2 diff --git a/tests/vkray/entry-point-params.slang b/tests/vkray/entry-point-params.slang index e3f29bc5b..47b108414 100644 --- a/tests/vkray/entry-point-params.slang +++ b/tests/vkray/entry-point-params.slang @@ -20,4 +20,4 @@ void main( // CHECK-DAG: OpDecorate %[[LaunchID:[A-Za-z0-9_]+]] BuiltIn LaunchId{{NV|KHR}} // CHECK-DAG: %[[LaunchID]] = OpVariable %_ptr_Input_v3uint Input // CHECK-DAG: %{{.*}} = OpLoad %v3uint %[[LaunchID]] -// CHECK-DAG: %{{.*}} = OpAccessChain %_ptr_ShaderRecordBuffer{{NV|KHR}}_float %{{.*}} %int_0 +// CHECK-DAG: %{{.*}} = Op{{.*}}AccessChain %_ptr_ShaderRecordBuffer{{NV|KHR}}_float %{{.*}} %int_0 |
