2
0
Эх сурвалжийг харах

[spirv] Fix method call on temporary struct containing aliases (#976)

A temporary struct object containing alias fields are already
a rvalue. We should avoid loading it again in the CodeGen.
Lei Zhang 7 жил өмнө
parent
commit
4c190e74f0

+ 5 - 4
tools/clang/lib/SPIRV/DeclResultIdMapper.cpp

@@ -517,10 +517,11 @@ uint32_t DeclResultIdMapper::getOrRegisterFnResultId(const FunctionDecl *fn) {
 
   const uint32_t id = theBuilder.getSPIRVContext()->takeNextId();
   info.setResultId(id);
-  // No need to dereference to get the pointer. Alias function returns
-  // themselves are already pointers to values. All other cases should be
-  // normal rvalues.
-  if (!isAlias)
+  // No need to dereference to get the pointer. Function returns that are
+  // stand-alone aliases are already pointers to values. All other cases should
+  // be normal rvalues.
+  if (!isAlias ||
+      !TypeTranslator::isAKindOfStructuredOrByteBuffer(fn->getReturnType()))
     info.setRValue();
 
   // Create alias counter variable if suitable

+ 1 - 1
tools/clang/lib/SPIRV/SPIRVEmitter.cpp

@@ -3448,7 +3448,7 @@ SPIRVEmitter::doCXXOperatorCallExpr(const CXXOperatorCallExpr *expr) {
   //
   // TODO: We can optimize the codegen by emitting OpCompositeExtract if
   // all indices are contant integers.
-  if (!baseExpr->isGLValue()) {
+  if (base.isRValue()) {
     base = createTemporaryVar(baseExpr->getType(), "vector", base);
   }
 

+ 21 - 1
tools/clang/test/CodeGenSPIRV/spirv.legal.sbuffer.struct.hlsl

@@ -11,10 +11,14 @@ struct S {
     ConsumeStructuredBuffer<float4> consume;
 };
 
-// CHECK: %T = OpTypeStruct %_ptr_Uniform_type_StructuredBuffer_Basic %_ptr_Uniform_type_RWStructuredBuffer_Basic
+// CHECK: %T = OpTypeStruct %_ptr_Uniform_type_StructuredBuffer_Basic %_ptr_Uniform_type_RWStructuredBuffer_Basic %_ptr_Uniform_type_StructuredBuffer_int
 struct T {
       StructuredBuffer<Basic> ro;
     RWStructuredBuffer<Basic> rw;
+      StructuredBuffer<int>   ro2;
+
+    StructuredBuffer<Basic> getSBuffer() { return ro; }
+    StructuredBuffer<int>   getSBuffer2() { return ro2; }
 };
 
 // CHECK: %Combine = OpTypeStruct %S %T %_ptr_Uniform_type_ByteAddressBuffer %_ptr_Uniform_type_RWByteAddressBuffer
@@ -23,6 +27,8 @@ struct Combine {
                       T t;
       ByteAddressBuffer ro;
     RWByteAddressBuffer rw;
+
+    T getT() { return t; }
 };
 
        StructuredBuffer<Basic>  gSBuffer;
@@ -63,6 +69,20 @@ float4 main() : SV_Target {
 // CHECK-NEXT:                OpStore [[ptr]] %gRWBABuffer
     c.rw = gRWBABuffer;
 
+// Make sure that we create temporary variable for intermediate objects since
+// the function expect pointers as parameters.
+// CHECK:     [[call1:%\d+]] = OpFunctionCall %T %Combine_getT %c
+// CHECK-NEXT:                 OpStore %temp_var_T [[call1]]
+// CHECK-NEXT:[[call2:%\d+]] = OpFunctionCall %_ptr_Uniform_type_StructuredBuffer_Basic %T_getSBuffer %temp_var_T
+// CHECK-NEXT:  [[ptr:%\d+]] = OpAccessChain %_ptr_Uniform_v4float [[call2]] %int_0 %uint_10 %int_1
+// CHECK-NEXT:      {{%\d+}} = OpLoad %v4float [[ptr]]
+    float4 val = c.getT().getSBuffer()[10].b;
+
+// Check StructuredBuffer of scalar type
+// CHECK:     [[call2:%\d+]] = OpFunctionCall %_ptr_Uniform_type_StructuredBuffer_int %T_getSBuffer2 %temp_var_T_0
+// CHECK-NEXT:      {{%\d+}} = OpAccessChain %_ptr_Uniform_int [[call2]] %int_0 %uint_42
+    int index = c.getT().getSBuffer2()[42];
+
 // CHECK:      [[val:%\d+]] = OpLoad %Combine %c
 // CHECK-NEXT:                OpStore %param_var_comb [[val]]
     return foo(c);