Browse Source

[spirv] Add support for casting from float4 to float2x2 (#849)

Lei Zhang 7 years ago
parent
commit
6a6290f2ed

+ 28 - 3
tools/clang/lib/SPIRV/SPIRVEmitter.cpp

@@ -1584,9 +1584,34 @@ SpirvEvalInfo SPIRVEmitter::doCastExpr(const CastExpr *expr) {
     return doExpr(subExpr);
   }
   case CastKind::CK_HLSLVectorToMatrixCast: {
-    // The target type should already be a 1xN matrix type.
-    assert(TypeTranslator::is1xNMatrix(toType));
-    return doExpr(subExpr);
+    // If target type is already an 1xN matrix type, we just return the
+    // underlying vector.
+    if (TypeTranslator::is1xNMatrix(toType))
+      return doExpr(subExpr);
+
+    // A vector can have no more than 4 elements. The only remaining case
+    // is casting from size-4 vector to size-2-by-2 matrix.
+
+    const auto vec = loadIfGLValue(subExpr);
+
+    QualType elemType = {};
+    uint32_t rowCount = 0, colCount = 0;
+    const bool isMat =
+        TypeTranslator::isMxNMatrix(toType, &elemType, &rowCount, &colCount);
+
+    assert(isMat && rowCount == 2 && colCount == 2);
+
+    uint32_t vec2Type =
+        theBuilder.getVecType(typeTranslator.translateType(elemType), 2);
+    const auto subVec1 =
+        theBuilder.createVectorShuffle(vec2Type, vec, vec, {0, 1});
+    const auto subVec2 =
+        theBuilder.createVectorShuffle(vec2Type, vec, vec, {2, 3});
+
+    const auto mat = theBuilder.createCompositeConstruct(
+        theBuilder.getMatType(vec2Type, 2), {subVec1, subVec2});
+
+    return SpirvEvalInfo(mat).setRValue();
   }
   case CastKind::CK_HLSLMatrixSplat: {
     // From scalar to matrix

+ 26 - 0
tools/clang/test/CodeGenSPIRV/cast.vec-to-mat.explicit.hlsl

@@ -0,0 +1,26 @@
+// Run: %dxc -T ps_6_0 -E main
+
+float4 main(float4 input : A) : SV_Target {
+// CHECK:       [[vec:%\d+]] = OpLoad %v4float %input
+// CHECK-NEXT: [[vec1:%\d+]] = OpVectorShuffle %v2float [[vec]] [[vec]] 0 1
+// CHECK-NEXT: [[vec2:%\d+]] = OpVectorShuffle %v2float [[vec]] [[vec]] 2 3
+// CHECK-NEXT:  [[mat:%\d+]] = OpCompositeConstruct %mat2v2float [[vec1]] [[vec2]]
+// CHECK-NEXT:                 OpStore %mat1 [[mat]]
+    float2x2 mat1 = (             float2x2)input;
+
+// CHECK:       [[vec:%\d+]] = OpLoad %v4float %input
+// CHECK-NEXT: [[vec1:%\d+]] = OpVectorShuffle %v2float [[vec]] [[vec]] 0 1
+// CHECK-NEXT: [[vec2:%\d+]] = OpVectorShuffle %v2float [[vec]] [[vec]] 2 3
+// CHECK-NEXT:  [[mat:%\d+]] = OpCompositeConstruct %mat2v2float [[vec1]] [[vec2]]
+// CHECK-NEXT:                 OpStore %mat2 [[mat]]
+    float2x2 mat2 = (row_major    float2x2)input;
+
+// CHECK:       [[vec:%\d+]] = OpLoad %v4float %input
+// CHECK-NEXT: [[vec1:%\d+]] = OpVectorShuffle %v2float [[vec]] [[vec]] 0 1
+// CHECK-NEXT: [[vec2:%\d+]] = OpVectorShuffle %v2float [[vec]] [[vec]] 2 3
+// CHECK-NEXT:  [[mat:%\d+]] = OpCompositeConstruct %mat2v2float [[vec1]] [[vec2]]
+// CHECK-NEXT:                 OpStore %mat3 [[mat]]
+    float2x2 mat3 = (column_major float2x2)input;
+
+    return float4(mat1[0][0], mat2[0][1], mat3[1][0], mat1[1][1]);
+}

+ 3 - 0
tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp

@@ -303,6 +303,9 @@ TEST_F(FileTest, CastExplicit2FP) { runFileTest("cast.2fp.explicit.hlsl"); }
 TEST_F(FileTest, CastImplicitFlatConversion) {
   runFileTest("cast.flat-conversion.implicit.hlsl");
 }
+TEST_F(FileTest, CastExplicitVecToMat) {
+  runFileTest("cast.vec-to-mat.explicit.hlsl");
+}
 
 // For vector/matrix splatting and trunction
 TEST_F(FileTest, CastTruncateVector) { runFileTest("cast.vector.trunc.hlsl"); }