Browse Source

[spirv] Boolean layout in struct reconstruction. (#1211)

Ehsan 7 years ago
parent
commit
6d152bf14c

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

@@ -4824,6 +4824,45 @@ void SPIRVEmitter::storeValue(const SpirvEvalInfo &lhsPtr,
 uint32_t SPIRVEmitter::reconstructValue(const SpirvEvalInfo &srcVal,
                                         const QualType valType,
                                         LayoutRule dstLR) {
+  // Lambda for casting scalar or vector of bool<-->uint in cases where one side
+  // of the reconstruction (lhs or rhs) has a layout rule.
+  const auto handleBooleanLayout = [this, &srcVal, dstLR](uint32_t val,
+                                                          QualType valType) {
+    // We only need to cast if we have a scalar or vector of booleans.
+    if (!isBoolOrVecOfBoolType(valType))
+      return val;
+
+    LayoutRule srcLR = srcVal.getLayoutRule();
+    // Source value has a layout rule, and has therefore been represented
+    // as a uint. Cast it to boolean before using.
+    bool shouldCastToBool =
+        srcLR != LayoutRule::Void && dstLR == LayoutRule::Void;
+    // Destination has a layout rule, and should therefore be represented
+    // as a uint. Cast to uint before using.
+    bool shouldCastToUint =
+        srcLR == LayoutRule::Void && dstLR != LayoutRule::Void;
+    // No boolean layout issues to take care of.
+    if (!shouldCastToBool && !shouldCastToUint)
+      return val;
+
+    uint32_t vecSize = 1;
+    TypeTranslator::isVectorType(valType, nullptr, &vecSize);
+    QualType boolType =
+        vecSize == 1 ? astContext.BoolTy
+                     : astContext.getExtVectorType(astContext.BoolTy, vecSize);
+    QualType uintType =
+        vecSize == 1
+            ? astContext.UnsignedIntTy
+            : astContext.getExtVectorType(astContext.UnsignedIntTy, vecSize);
+
+    if (shouldCastToBool)
+      return castToBool(val, uintType, boolType);
+    if (shouldCastToUint)
+      return castToInt(val, boolType, uintType, {});
+
+    return val;
+  };
+
   // Lambda for cases where we want to reconstruct an array
   const auto reconstructArray = [this, &srcVal, valType,
                                  dstLR](uint32_t arraySize,
@@ -4834,7 +4873,6 @@ uint32_t SPIRVEmitter::reconstructValue(const SpirvEvalInfo &srcVal,
           typeTranslator.translateType(arrayElemType, srcVal.getLayoutRule());
       const auto subSrcVal =
           theBuilder.createCompositeExtract(subSrcValType, srcVal, {i});
-
       elements.push_back(reconstructValue(srcVal.substResultId(subSrcVal),
                                           arrayElemType, dstLR));
     }
@@ -4868,7 +4906,7 @@ uint32_t SPIRVEmitter::reconstructValue(const SpirvEvalInfo &srcVal,
   // Note: This check should happen before the RecordType check since
   // vector/matrix/resource types are represented as RecordType in the AST.
   if (hlsl::IsHLSLVecMatType(valType) || hlsl::IsHLSLResourceType(valType))
-    return srcVal;
+    return handleBooleanLayout(srcVal, valType);
 
   // Structs
   if (const auto *recordType = valType->getAs<RecordType>()) {
@@ -4888,7 +4926,7 @@ uint32_t SPIRVEmitter::reconstructValue(const SpirvEvalInfo &srcVal,
     return theBuilder.createCompositeConstruct(dstValType, elements);
   }
 
-  return srcVal;
+  return handleBooleanLayout(srcVal, valType);
 }
 
 SpirvEvalInfo SPIRVEmitter::processBinaryOp(const Expr *lhs, const Expr *rhs,

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

@@ -1281,10 +1281,10 @@ void TypeTranslator::collectDeclsInField(
     return;
   }
 
-  (*decls).push_back(field);
+  decls->push_back(field);
 }
 
-const llvm::SmallVector<const Decl *, 4>
+llvm::SmallVector<const Decl *, 4>
 TypeTranslator::collectDeclsInDeclContext(const DeclContext *declContext) {
   llvm::SmallVector<const Decl *, 4> decls;
   for (const auto *field : declContext->decls()) {

+ 1 - 1
tools/clang/lib/SPIRV/TypeTranslator.h

@@ -274,7 +274,7 @@ public:
   /// DeclContext. If it sees a NamespaceDecl, it recursively dives in and
   /// collects decls in the correct order.
   /// Utilizes collectDeclsInNamespace and collectDeclsInField private methods.
-  const llvm::SmallVector<const Decl *, 4>
+  llvm::SmallVector<const Decl *, 4>
   collectDeclsInDeclContext(const DeclContext *declContext);
 
 private:

+ 41 - 1
tools/clang/test/CodeGenSPIRV/vk.layout.cbuffer.boolean.hlsl

@@ -7,12 +7,18 @@
 // CHECK: OpMemberDecorate %type_CONSTANTS 0 Offset 0
 // CHECK: OpDecorate %type_CONSTANTS Block
 
-// CHECK: %FrameConstants = OpTypeStruct %uint %v3uint %_arr_v3uint_uint_2
+// CHECK: %T = OpTypeStruct %_arr_uint_uint_1
+struct T {
+  bool boolArray[1];
+};
+
+// CHECK: %FrameConstants = OpTypeStruct %uint %v3uint %_arr_v3uint_uint_2 %T
 struct FrameConstants
 {
   bool  boolScalar;
   bool3 boolVec;
   row_major bool2x3 boolMat;
+  T t;
 };
 
 [[vk::binding(0, 0)]]
@@ -23,6 +29,11 @@ cbuffer CONSTANTS
 
 // CHECK: [[v3uint0:%\d+]] = OpConstantComposite %v3uint %uint_0 %uint_0 %uint_0
 // CHECK: [[v2uint0:%\d+]] = OpConstantComposite %v2uint %uint_0 %uint_0
+
+// These are the types that hold SPIR-V booleans, rather than Uints.
+// CHECK:              %T_0 = OpTypeStruct %_arr_bool_uint_1
+// CHECK: %FrameConstants_0 = OpTypeStruct %bool %v3bool %_arr_v3bool_uint_2 %T_0
+
 float4 main(in float4 texcoords : TEXCOORD0) : SV_TARGET
 {
 // CHECK:      [[FrameConstants:%\d+]] = OpAccessChain %_ptr_Uniform_FrameConstants %CONSTANTS %int_0
@@ -118,5 +129,34 @@ float4 main(in float4 texcoords : TEXCOORD0) : SV_TARGET
 // CHECK-NEXT:                           OpStore %k [[boolVec]]
     bool2   k = frameConstants.boolMat._m12_m01;
 
+// CHECK:      [[FrameConstants:%\d+]] = OpAccessChain %_ptr_Uniform_FrameConstants %CONSTANTS %int_0
+// CHECK-NEXT:            [[ptr:%\d+]] = OpAccessChain %_ptr_Uniform_uint [[FrameConstants]] %int_3 %int_0 %int_2
+// CHECK-NEXT:           [[uint:%\d+]] = OpLoad %uint [[ptr]]
+// CHECK-NEXT:           [[bool:%\d+]] = OpINotEqual %bool [[uint]] %uint_0
+// CHECK-NEXT:                           OpStore %l [[bool]]
+    bool    l = frameConstants.t.boolArray[2];
+
+// CHECK:           [[FrameConstantsPtr:%\d+]] = OpAccessChain %_ptr_Uniform_FrameConstants %CONSTANTS %int_0
+// CHECK-NEXT:         [[FrameConstants:%\d+]] = OpLoad %FrameConstants [[FrameConstantsPtr]]
+// CHECK-NEXT:              [[fc_0_uint:%\d+]] = OpCompositeExtract %uint [[FrameConstants]] 0
+// CHECK-NEXT:              [[fc_0_bool:%\d+]] = OpINotEqual %bool [[fc_0_uint]] %uint_0
+// CHECK-NEXT:             [[fc_1_uint3:%\d+]] = OpCompositeExtract %v3uint [[FrameConstants]] 1
+// CHECK-NEXT:             [[fc_1_bool3:%\d+]] = OpINotEqual %v3bool [[fc_1_uint3]] [[v3uint0]]
+// CHECK-NEXT:           [[fc_2_uintMat:%\d+]] = OpCompositeExtract %_arr_v3uint_uint_2 [[FrameConstants]] 2
+// CHECK-NEXT: [[fc_2_uintMat_row0_uint:%\d+]] = OpCompositeExtract %v3uint [[fc_2_uintMat]] 0
+// CHECK-NEXT: [[fc_2_uintMat_row0_bool:%\d+]] = OpINotEqual %v3bool [[fc_2_uintMat_row0_uint]] [[v3uint0]]
+// CHECK-NEXT: [[fc_2_uintMat_row1_uint:%\d+]] = OpCompositeExtract %v3uint [[fc_2_uintMat]] 1
+// CHECK-NEXT: [[fc_2_uintMat_row1_bool:%\d+]] = OpINotEqual %v3bool [[fc_2_uintMat_row1_uint]] [[v3uint0]]
+// CHECK-NEXT:           [[fc_2_boolMat:%\d+]] = OpCompositeConstruct %_arr_v3bool_uint_2 [[fc_2_uintMat_row0_bool]] [[fc_2_uintMat_row1_bool]]
+// CHECK-NEXT:                 [[fc_3_T:%\d+]] = OpCompositeExtract %T [[FrameConstants]] 3
+// CHECK-NEXT:      [[fc_3_T_0_uint_arr:%\d+]] = OpCompositeExtract %_arr_uint_uint_1 [[fc_3_T]] 0
+// CHECK-NEXT:        [[fc_3_T_0_0_uint:%\d+]] = OpCompositeExtract %uint [[fc_3_T_0_uint_arr]] 0
+// CHECK-NEXT:        [[fc_3_T_0_0_bool:%\d+]] = OpINotEqual %bool [[fc_3_T_0_0_uint]] %uint_0
+// CHECK-NEXT:      [[fc_3_T_0_bool_arr:%\d+]] = OpCompositeConstruct %_arr_bool_uint_1 [[fc_3_T_0_0_bool]]
+// CHECK-NEXT:            [[fc_3_T_bool:%\d+]] = OpCompositeConstruct %T_0 [[fc_3_T_0_bool_arr]]
+// CHECK-NEXT:                     [[fc:%\d+]] = OpCompositeConstruct %FrameConstants_0 [[fc_0_bool]] [[fc_1_bool3]] [[fc_2_boolMat]] [[fc_3_T_bool]]
+// CHECK-NEXT:                                   OpStore %fc [[fc]]
+    FrameConstants fc = frameConstants;
+
     return (1.0).xxxx;
 }

+ 56 - 0
tools/clang/test/CodeGenSPIRV/vk.layout.rwstructuredbuffer.boolean.hlsl

@@ -1,16 +1,28 @@
 // Run: %dxc -T vs_6_0 -E main
 
+// CHECK: %T = OpTypeStruct %_arr_uint_uint_1
+struct T {
+  bool boolArray[1];
+};
+
+// CHECK: %S = OpTypeStruct %uint %v3uint %_arr_v3uint_uint_2 %T
 struct S
 {
   bool  boolScalar;
   bool3 boolVec;
   row_major bool2x3 boolMat;
+  T t;
 };
 
 RWStructuredBuffer<S> values;
 
 // CHECK: [[v3uint1:%\d+]] = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
 // CHECK: [[v3uint0:%\d+]] = OpConstantComposite %v3uint %uint_0 %uint_0 %uint_0
+
+// These are the types that hold SPIR-V booleans, rather than Uints.
+// CHECK: %T_0 = OpTypeStruct %_arr_bool_uint_1
+// CHECK: %S_0 = OpTypeStruct %bool %v3bool %_arr_v3bool_uint_2 %T_0
+
 void main()
 {
   bool3 boolVecVar;
@@ -32,4 +44,48 @@ void main()
   // values[2].boolMat = boolMatVar;
   // values[0].boolVec.yzx = boolVecVar;
   // values[0].boolMat._m12_m11 = boolVecVar2;
+
+// CHECK:              [[sPtr:%\d+]] = OpAccessChain %_ptr_Uniform_S %values %int_0 %uint_0
+// CHECK-NEXT:            [[s:%\d+]] = OpLoad %S [[sPtr]]
+// CHECK-NEXT:           [[s0:%\d+]] = OpCompositeExtract %uint [[s]] 0
+// CHECK-NEXT:      [[s0_bool:%\d+]] = OpINotEqual %bool [[s0]] %uint_0
+// CHECK-NEXT:           [[s1:%\d+]] = OpCompositeExtract %v3uint [[s]] 1
+// CHECK-NEXT:      [[s1_bool:%\d+]] = OpINotEqual %v3bool [[s1]] [[v3uint0]]
+// CHECK-NEXT:           [[s2:%\d+]] = OpCompositeExtract %_arr_v3uint_uint_2 [[s]] 2
+// CHECK-NEXT:      [[s2_row0:%\d+]] = OpCompositeExtract %v3uint [[s2]] 0
+// CHECK-NEXT: [[s2_row0_bool:%\d+]] = OpINotEqual %v3bool [[s2_row0]] [[v3uint0]]
+// CHECK-NEXT:      [[s2_row1:%\d+]] = OpCompositeExtract %v3uint [[s2]] 1
+// CHECK-NEXT: [[s2_row1_bool:%\d+]] = OpINotEqual %v3bool [[s2_row1]] [[v3uint0]]
+// CHECK-NEXT:      [[s2_bool:%\d+]] = OpCompositeConstruct %_arr_v3bool_uint_2 [[s2_row0_bool]] [[s2_row1_bool]]
+// CHECK-NEXT:            [[t:%\d+]] = OpCompositeExtract %T [[s]] 3
+// CHECK-NEXT:  [[t0_uint_arr:%\d+]] = OpCompositeExtract %_arr_uint_uint_1 [[t]] 0
+// CHECK-NEXT:    [[t0_0_uint:%\d+]] = OpCompositeExtract %uint [[t0_uint_arr]] 0
+// CHECK-NEXT:    [[t0_0_bool:%\d+]] = OpINotEqual %bool [[t0_0_uint]] %uint_0
+// CHECK-NEXT:      [[t0_bool:%\d+]] = OpCompositeConstruct %_arr_bool_uint_1 [[t0_0_bool]]
+// CHECK-NEXT:       [[t_bool:%\d+]] = OpCompositeConstruct %T_0 [[t0_bool]]
+// CHECK-NEXT:       [[s_bool:%\d+]] = OpCompositeConstruct %S_0 [[s0_bool]] [[s1_bool]] [[s2_bool]] [[t_bool]]
+// CHECK-NEXT:                         OpStore %s [[s_bool]]
+  S s = values[0];
+
+// CHECK:                         [[s:%\d+]] = OpLoad %S_0 %s
+// CHECK-NEXT:            [[resultPtr:%\d+]] = OpAccessChain %_ptr_Uniform_S %values %int_0 %uint_1
+// CHECK-NEXT:              [[s0_bool:%\d+]] = OpCompositeExtract %bool [[s]] 0
+// CHECK-NEXT:              [[s0_uint:%\d+]] = OpSelect %uint [[s0_bool]] %uint_1 %uint_0
+// CHECK-NEXT:           [[s1_boolVec:%\d+]] = OpCompositeExtract %v3bool [[s]] 1
+// CHECK-NEXT:           [[s1_uintVec:%\d+]] = OpSelect %v3uint [[s1_boolVec]]
+// CHECK-NEXT:           [[s2_boolMat:%\d+]] = OpCompositeExtract %_arr_v3bool_uint_2 [[s]] 2
+// CHECK-NEXT:      [[s2_boolMat_row0:%\d+]] = OpCompositeExtract %v3bool [[s2_boolMat]] 0
+// CHECK-NEXT: [[s2_boolMat_row0_uint:%\d+]] = OpSelect %v3uint [[s2_boolMat_row0]]
+// CHECK-NEXT:      [[s2_boolMat_row1:%\d+]] = OpCompositeExtract %v3bool [[s2_boolMat]] 1
+// CHECK-NEXT: [[s2_boolMat_row1_uint:%\d+]] = OpSelect %v3uint [[s2_boolMat_row1]]
+// CHECK-NEXT:           [[s2_uintMat:%\d+]] = OpCompositeConstruct %_arr_v3uint_uint_2 [[s2_boolMat_row0_uint]] [[s2_boolMat_row1_uint]]
+// CHECK-NEXT:                    [[t:%\d+]] = OpCompositeExtract %T_0 [[s]] 3
+// CHECK-NEXT:          [[t0_bool_arr:%\d+]] = OpCompositeExtract %_arr_bool_uint_1 [[t]] 0
+// CHECK-NEXT:        [[t0_bool_arr_0:%\d+]] = OpCompositeExtract %bool [[t0_bool_arr]] 0
+// CHECK-NEXT:   [[t0_bool_arr_0_uint:%\d+]] = OpSelect %uint [[t0_bool_arr_0]] %uint_1 %uint_0
+// CHECK-NEXT:          [[t0_uint_arr:%\d+]] = OpCompositeConstruct %_arr_uint_uint_1 [[t0_bool_arr_0_uint]]
+// CHECK-NEXT:               [[t_uint:%\d+]] = OpCompositeConstruct %T [[t0_uint_arr]]
+// CHECK-NEXT:               [[s_uint:%\d+]] = OpCompositeConstruct %S [[s0_uint]] [[s1_uintVec]] [[s2_uintMat]] [[t_uint]]
+// CHECK-NEXT:                                 OpStore [[resultPtr:%\d+]] [[s_uint]]
+  values[1] = s;
 }