Browse Source

[spirv] Fix extra OpLoad when using images on lhs of assignment (#981)

When using a storage image on the lhs of a compound assignment,
we need to load the image and do the calculation with rhs first
before actually assigning back to the storage image again. That
load won't result in an OpAccessChain, actually it will result
in a rvalue.
Lei Zhang 7 years ago
parent
commit
4e01373037

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

@@ -3981,8 +3981,8 @@ SpirvEvalInfo SPIRVEmitter::processBinaryOp(const Expr *lhs, const Expr *rhs,
     rhsVal = doExpr(rhs);
     lhsVal = lhsPtr = doExpr(lhs);
     // This is a compound assignment. We need to load the lhs value if lhs
-    // does not generate a vector shuffle.
-    if (!isVectorShuffle(lhs)) {
+    // is not already rvalue and does not generate a vector shuffle.
+    if (!lhsPtr.isRValue() && !isVectorShuffle(lhs)) {
       const uint32_t lhsTy = typeTranslator.translateType(lhs->getType());
       lhsVal = theBuilder.createLoad(lhsTy, lhsPtr);
     }

+ 16 - 0
tools/clang/test/CodeGenSPIRV/binary-op.assign.vector.hlsl → tools/clang/test/CodeGenSPIRV/binary-op.assign.image.hlsl

@@ -50,4 +50,20 @@ void main() {
 // CHECK-NEXT: [[tex:%\d+]] = OpLoad %type_3d_image %MyRWTexture3
 // CHECK-NEXT:                OpImageWrite [[tex]] {{%\d+}} [[new]]
     MyRWTexture3[uint3(8, 9, 10)].xy = 28;
+
+// CHECK:      [[buf:%\d+]] = OpLoad %type_buffer_image %MyRWBuffer
+// CHECK-NEXT: [[old:%\d+]] = OpImageRead %v4uint [[buf]] %uint_11 None
+// CHECK-NEXT: [[val:%\d+]] = OpCompositeExtract %uint [[old]] 0
+// CHECK-NEXT: [[add:%\d+]] = OpIAdd %uint [[val]] %uint_30
+// CHECK-NEXT: [[buf:%\d+]] = OpLoad %type_buffer_image %MyRWBuffer
+// CHECK-NEXT:                OpImageWrite [[buf]] %uint_11 [[add]]
+    MyRWBuffer[11] += 30;
+
+// CHECK:      [[tex:%\d+]] = OpLoad %type_2d_image %MyRWTexture
+// CHECK-NEXT: [[old:%\d+]] = OpImageRead %v4int [[tex]] {{%\d+}} None
+// CHECK-NEXT: [[val:%\d+]] = OpCompositeExtract %int [[old]] 0
+// CHECK-NEXT: [[mul:%\d+]] = OpIMul %int [[val]] %int_31
+// CHECK-NEXT: [[tex:%\d+]] = OpLoad %type_2d_image %MyRWTexture
+// CHECK-NEXT:                OpImageWrite [[tex]] {{%\d+}} [[mul]]
+    MyRWTexture[uint2(12, 13)] *= 31;
 }

+ 2 - 2
tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp

@@ -156,8 +156,8 @@ TEST_F(FileTest, UnaryOpLogicalNot) {
 
 // For assignments
 TEST_F(FileTest, BinaryOpAssign) { runFileTest("binary-op.assign.hlsl"); }
-TEST_F(FileTest, BinaryOpAssignVector) {
-  runFileTest("binary-op.assign.vector.hlsl");
+TEST_F(FileTest, BinaryOpAssignImage) {
+  runFileTest("binary-op.assign.image.hlsl");
 }
 TEST_F(FileTest, BinaryOpAssignComposite) {
   runFileTest("binary-op.assign.composite.hlsl");