Browse Source

[spirv] Handle literal int and 64-bit int. (#851)

Also update the FlatConversion code to handle float and boolean
initializers.
Ehsan 7 years ago
parent
commit
fcde415c18

+ 2 - 0
tools/clang/include/clang/SPIRV/ModuleBuilder.h

@@ -339,7 +339,9 @@ public:
   uint32_t getVoidType();
   uint32_t getBoolType();
   uint32_t getInt32Type();
+  uint32_t getInt64Type();
   uint32_t getUint32Type();
+  uint32_t getUint64Type();
   uint32_t getFloat32Type();
   uint32_t getFloat64Type();
   uint32_t getVecType(uint32_t elemType, uint32_t elemCount);

+ 5 - 3
tools/clang/lib/SPIRV/ModuleBuilder.cpp

@@ -722,10 +722,10 @@ IMPL_GET_PRIMITIVE_TYPE(Float32)
 
 #undef IMPL_GET_PRIMITIVE_TYPE
 
-#define IMPL_GET_PRIMITIVE_TYPE_WITH_CAPABILITY(ty)                            \
+#define IMPL_GET_PRIMITIVE_TYPE_WITH_CAPABILITY(ty, cap)                       \
   \
 uint32_t ModuleBuilder::get##ty##Type() {                                      \
-    requireCapability(spv::Capability::ty);                                    \
+    requireCapability(spv::Capability::cap);                                    \
     const Type *type = Type::get##ty(theContext);                              \
     const uint32_t typeId = theContext.getResultIdForType(type);               \
     theModule.addType(type, typeId);                                           \
@@ -733,7 +733,9 @@ uint32_t ModuleBuilder::get##ty##Type() {                                      \
   \
 }
 
-IMPL_GET_PRIMITIVE_TYPE_WITH_CAPABILITY(Float64)
+IMPL_GET_PRIMITIVE_TYPE_WITH_CAPABILITY(Float64, Float64)
+IMPL_GET_PRIMITIVE_TYPE_WITH_CAPABILITY(Int64, Int64)
+IMPL_GET_PRIMITIVE_TYPE_WITH_CAPABILITY(Uint64, Int64)
 
 #undef IMPL_GET_PRIMITIVE_TYPE_WITH_CAPABILITY
 

+ 107 - 32
tools/clang/lib/SPIRV/SPIRVEmitter.cpp

@@ -259,6 +259,22 @@ inline bool canActAsOutParmVar(const ParmVarDecl *param) {
   return param->hasAttr<HLSLOutAttr>() || param->hasAttr<HLSLInOutAttr>();
 }
 
+/// Returns true if the given expression can be evaluated to a constant zero.
+/// Returns false otherwise.
+inline bool evaluatesToConstZero(const Expr *expr, ASTContext &astContext) {
+  const auto type = expr->getType();
+  assert(type->isBuiltinType());
+  Expr::EvalResult evalResult;
+  if (expr->EvaluateAsRValue(evalResult, astContext) &&
+      !evalResult.HasSideEffects) {
+    const auto &val = evalResult.Val;
+    return ((type->isBooleanType() && !val.getInt().getBoolValue()) ||
+            (type->isIntegerType() && !val.getInt().getBoolValue()) ||
+            (type->isFloatingType() && val.getFloat().isZero()));
+  }
+  return false;
+}
+
 } // namespace
 
 SPIRVEmitter::SPIRVEmitter(CompilerInstance &ci,
@@ -1493,6 +1509,7 @@ SpirvEvalInfo SPIRVEmitter::processCall(const CallExpr *callExpr) {
 
 SpirvEvalInfo SPIRVEmitter::doCastExpr(const CastExpr *expr) {
   const Expr *subExpr = expr->getSubExpr();
+  const QualType subExprType = subExpr->getType();
   const QualType toType = expr->getType();
 
   switch (expr->getCastKind()) {
@@ -1516,8 +1533,8 @@ SpirvEvalInfo SPIRVEmitter::doCastExpr(const CastExpr *expr) {
       return SpirvEvalInfo(valueId).setConstant().setRValue();
     }
 
-    const auto valueId = castToInt(doExpr(subExpr), subExpr->getType(), toType,
-                                   subExpr->getExprLoc());
+    const auto valueId =
+        castToInt(doExpr(subExpr), subExprType, toType, subExpr->getExprLoc());
     return SpirvEvalInfo(valueId).setRValue();
   }
   case CastKind::CK_FloatingCast:
@@ -1533,8 +1550,8 @@ SpirvEvalInfo SPIRVEmitter::doCastExpr(const CastExpr *expr) {
       return SpirvEvalInfo(valueId).setConstant().setRValue();
     }
 
-    const auto valueId = castToFloat(doExpr(subExpr), subExpr->getType(),
-                                     toType, subExpr->getExprLoc());
+    const auto valueId = castToFloat(doExpr(subExpr), subExprType, toType,
+                                     subExpr->getExprLoc());
     return SpirvEvalInfo(valueId).setRValue();
   }
   case CastKind::CK_IntegralToBoolean:
@@ -1549,8 +1566,7 @@ SpirvEvalInfo SPIRVEmitter::doCastExpr(const CastExpr *expr) {
       return SpirvEvalInfo(valueId).setConstant().setRValue();
     }
 
-    const auto valueId =
-        castToBool(doExpr(subExpr), subExpr->getType(), toType);
+    const auto valueId = castToBool(doExpr(subExpr), subExprType, toType);
     return SpirvEvalInfo(valueId).setRValue();
   }
   case CastKind::CK_HLSLVectorSplat: {
@@ -1580,7 +1596,7 @@ SpirvEvalInfo SPIRVEmitter::doCastExpr(const CastExpr *expr) {
   }
   case CastKind::CK_HLSLVectorToScalarCast: {
     // The underlying should already be a vector of size 1.
-    assert(hlsl::GetHLSLVecSize(subExpr->getType()) == 1);
+    assert(hlsl::GetHLSLVecSize(subExprType) == 1);
     return doExpr(subExpr);
   }
   case CastKind::CK_HLSLVectorToMatrixCast: {
@@ -1642,7 +1658,7 @@ SpirvEvalInfo SPIRVEmitter::doCastExpr(const CastExpr *expr) {
     }
   }
   case CastKind::CK_HLSLMatrixTruncationCast: {
-    const QualType srcType = subExpr->getType();
+    const QualType srcType = subExprType;
     const uint32_t srcId = doExpr(subExpr);
     const QualType elemType = hlsl::GetHLSLMatElementType(srcType);
     const uint32_t dstTypeId = typeTranslator.translateType(toType);
@@ -1699,32 +1715,49 @@ SpirvEvalInfo SPIRVEmitter::doCastExpr(const CastExpr *expr) {
   }
   case CastKind::CK_HLSLMatrixToScalarCast: {
     // The underlying should already be a matrix of 1x1.
-    assert(TypeTranslator::is1x1Matrix(subExpr->getType()));
+    assert(TypeTranslator::is1x1Matrix(subExprType));
     return doExpr(subExpr);
   }
   case CastKind::CK_HLSLMatrixToVectorCast: {
     // The underlying should already be a matrix of 1xN.
-    assert(TypeTranslator::is1xNMatrix(subExpr->getType()) ||
-           TypeTranslator::isMx1Matrix(subExpr->getType()));
+    assert(TypeTranslator::is1xNMatrix(subExprType) ||
+           TypeTranslator::isMx1Matrix(subExprType));
     return doExpr(subExpr);
   }
   case CastKind::CK_FunctionToPointerDecay:
     // Just need to return the function id
     return doExpr(subExpr);
   case CastKind::CK_FlatConversion: {
+    uint32_t subExprId = 0;
+    QualType evalType = subExprType;
+
     // Optimization: we can use OpConstantNull for cases where we want to
     // initialize an entire data structure to zeros.
-    llvm::APSInt intValue;
-    if (subExpr->EvaluateAsInt(intValue, astContext, Expr::SE_NoSideEffects) &&
-        intValue.getExtValue() == 0) {
-      const auto valId =
+    if (evaluatesToConstZero(subExpr, astContext)) {
+      subExprId =
           theBuilder.getConstantNull(typeTranslator.translateType(toType));
-      return SpirvEvalInfo(valId).setConstant().setRValue();
-    } else {
-      const auto valId = processFlatConversion(
-          toType, subExpr->getType(), doExpr(subExpr), expr->getExprLoc());
-      return SpirvEvalInfo(valId).setRValue();
+      return SpirvEvalInfo(subExprId).setRValue().setConstant();
+    }
+
+    // Try to evaluate 'literal float' as float rather than double.
+    if (const auto *floatLiteral = dyn_cast<FloatingLiteral>(subExpr)) {
+      subExprId = tryToEvaluateAsFloat32(floatLiteral->getValue());
+      if (subExprId)
+        evalType = astContext.FloatTy;
+    }
+    // Try to evaluate 'literal int' as 32-bit int rather than 64-bit int.
+    else if (const auto *intLiteral = dyn_cast<IntegerLiteral>(subExpr)) {
+      const bool isSigned = subExprType->isSignedIntegerType();
+      subExprId = tryToEvaluateAsInt32(intLiteral->getValue(), isSigned);
+      if (subExprId)
+        evalType = isSigned ? astContext.IntTy : astContext.UnsignedIntTy;
     }
+
+    if (!subExprId)
+      subExprId = doExpr(subExpr);
+    const auto valId =
+        processFlatConversion(toType, evalType, subExprId, expr->getExprLoc());
+    return SpirvEvalInfo(valId).setRValue();
   }
   default:
     emitError("implicit cast kind '%0' unimplemented", expr->getExprLoc())
@@ -1755,16 +1788,16 @@ uint32_t SPIRVEmitter::processFlatConversion(const QualType type,
         }
         case BuiltinType::Bool:
           return castToBool(initId, initType, ty);
-        // int, min16int (short), and min12int are all translated to 32-bit
-        // signed integers in SPIR-V.
+        // Target type is an integer variant.
+        // TODO: Add long and ulong.
         case BuiltinType::Int:
         case BuiltinType::Short:
         case BuiltinType::Min12Int:
         case BuiltinType::UShort:
         case BuiltinType::UInt:
           return castToInt(initId, initType, ty, srcLoc);
-        // float, min16float (half), and min10float are all translated to
-        // 32-bit float in SPIR-V.
+        // Target type is a float variant.
+        // TODO: Add double.
         case BuiltinType::Float:
         case BuiltinType::Half:
         case BuiltinType::Min10Float:
@@ -4132,6 +4165,12 @@ uint32_t SPIRVEmitter::castToInt(const uint32_t fromVal, QualType fromType,
     return fromVal;
 
   const uint32_t intType = typeTranslator.translateType(toIntType);
+
+  // AST may include a 'literal int' to 'int' conversion. No-op.
+  if (fromType->isLiteralType(astContext) && fromType->isIntegerType() &&
+      typeTranslator.translateType(fromType) == intType)
+    return fromVal;
+
   if (isBoolOrVecOfBoolType(fromType)) {
     const uint32_t one = getValueOne(toIntType);
     const uint32_t zero = getValueZero(toIntType);
@@ -6006,8 +6045,7 @@ uint32_t SPIRVEmitter::translateAPValue(const APValue &value,
   }
 
   if (targetType->isFloatingType()) {
-    const llvm::APFloat &floatValue = value.getFloat();
-    return translateAPFloat(floatValue, targetType);
+    return translateAPFloat(value.getFloat(), targetType);
   }
 
   if (hlsl::IsHLSLVecType(targetType)) {
@@ -6037,15 +6075,17 @@ uint32_t SPIRVEmitter::translateAPValue(const APValue &value,
 uint32_t SPIRVEmitter::translateAPInt(const llvm::APInt &intValue,
                                       QualType targetType) {
   if (targetType->isSignedIntegerType()) {
-    // Try to see if this integer can be represented in 32-bit
-    if (intValue.isSignedIntN(32))
+    // Try to see if this integer can be represented in 32-bit.
+    if (intValue.isSignedIntN(32)) {
       return theBuilder.getConstantInt32(
           static_cast<int32_t>(intValue.getSExtValue()));
+    }
   } else {
-    // Try to see if this integer can be represented in 32-bit
-    if (intValue.isIntN(32))
+    // Try to see if this integer can be represented in 32-bit.
+    if (intValue.isIntN(32)) {
       return theBuilder.getConstantUint32(
           static_cast<uint32_t>(intValue.getZExtValue()));
+    }
   }
 
   emitError("APInt for target bitwidth %0 unimplemented", {})
@@ -6054,11 +6094,47 @@ uint32_t SPIRVEmitter::translateAPInt(const llvm::APInt &intValue,
   return 0;
 }
 
+uint32_t SPIRVEmitter::tryToEvaluateAsInt32(const llvm::APInt &intValue,
+                                            bool isSigned) {
+  if (isSigned && intValue.isSignedIntN(32)) {
+    return theBuilder.getConstantInt32(
+        static_cast<int32_t>(intValue.getSExtValue()));
+  }
+  if (!isSigned && intValue.isIntN(32)) {
+    return theBuilder.getConstantUint32(
+        static_cast<uint32_t>(intValue.getZExtValue()));
+  }
+
+  // Couldn't evaluate as a 32-bit int without losing information.
+  return 0;
+}
+
+uint32_t SPIRVEmitter::tryToEvaluateAsFloat32(const llvm::APFloat &floatValue) {
+  const auto &semantics = floatValue.getSemantics();
+  // If the given value is already a 32-bit float, there is no need to convert.
+  if (&semantics == &llvm::APFloat::IEEEsingle) {
+    return theBuilder.getConstantFloat32(floatValue.convertToFloat());
+  }
+
+  // Try to see if this literal float can be represented in 32-bit.
+  // Since the convert function below may modify the fp value, we call it on a
+  // temporary copy.
+  llvm::APFloat eval = floatValue;
+  bool losesInfo = false;
+  const auto convertStatus =
+      eval.convert(llvm::APFloat::IEEEsingle,
+                   llvm::APFloat::rmNearestTiesToEven, &losesInfo);
+  if (convertStatus == llvm::APFloat::opOK && !losesInfo)
+    return theBuilder.getConstantFloat32(eval.convertToFloat());
+
+  // Couldn't evaluate as a 32-bit float without losing information.
+  return 0;
+}
+
 uint32_t SPIRVEmitter::translateAPFloat(const llvm::APFloat &floatValue,
                                         QualType targetType) {
   const auto &semantics = astContext.getFloatTypeSemantics(targetType);
   const auto bitwidth = llvm::APFloat::getSizeInBits(semantics);
-
   switch (bitwidth) {
   case 32:
     return theBuilder.getConstantFloat32(floatValue.convertToFloat());
@@ -6067,7 +6143,6 @@ uint32_t SPIRVEmitter::translateAPFloat(const llvm::APFloat &floatValue,
   default:
     break;
   }
-
   emitError("APFloat for target bitwidth %0 unimplemented", {}) << bitwidth;
   return 0;
 }

+ 10 - 0
tools/clang/lib/SPIRV/SPIRVEmitter.h

@@ -402,6 +402,16 @@ private:
   /// if success. Otherwise, returns 0.
   uint32_t tryToEvaluateAsConst(const Expr *expr);
 
+  /// Tries to evaluate the given APFloat as a 32-bit float. If the evaluation
+  /// can be performed without loss, it returns the <result-id> of the SPIR-V
+  /// constant for that value. Returns zero otherwise.
+  uint32_t tryToEvaluateAsFloat32(const llvm::APFloat &);
+
+  /// Tries to evaluate the given APInt as a 32-bit integer. If the evaluation
+  /// can be performed without loss, it returns the <result-id> of the SPIR-V
+  /// constant for that value.
+  uint32_t tryToEvaluateAsInt32(const llvm::APInt &, bool isSigned);
+
 private:
   /// Translates the given HLSL loop attribute into SPIR-V loop control mask.
   /// Emits an error if the given attribute is not a loop attribute.

+ 17 - 0
tools/clang/lib/SPIRV/TypeTranslator.cpp

@@ -140,6 +140,10 @@ uint32_t TypeTranslator::translateType(QualType type, LayoutRule rule,
         case BuiltinType::UShort:
         case BuiltinType::UInt:
           return theBuilder.getUint32Type();
+        case BuiltinType::LongLong:
+          return theBuilder.getInt64Type();
+        case BuiltinType::ULongLong:
+          return theBuilder.getUint64Type();
         // float, min16float (half), and min10float are all translated to 32-bit
         // float in SPIR-V.
         case BuiltinType::Float:
@@ -156,6 +160,19 @@ uint32_t TypeTranslator::translateType(QualType type, LayoutRule rule,
           else
             return theBuilder.getFloat64Type();
         }
+        case BuiltinType::LitInt: {
+          const auto bitwidth = astContext.getIntWidth(type);
+          // All integer variants with bitwidth larger than 32 are represented
+          // as 64-bit int in SPIR-V.
+          // All integer variants with bitwidth of 32 or less are represented as
+          // 32-bit int in SPIR-V.
+          if (type->isSignedIntegerType())
+            return bitwidth > 32 ? theBuilder.getInt64Type()
+                                 : theBuilder.getInt32Type();
+          else
+            return bitwidth > 32 ? theBuilder.getUint64Type()
+                                 : theBuilder.getUint32Type();
+        }
         default:
           emitError("primitive type %0 unimplemented")
               << builtinType->getTypeClassName();

+ 40 - 10
tools/clang/test/CodeGenSPIRV/cast.flat-conversion.implicit.hlsl

@@ -18,25 +18,25 @@ void main() {
 
 // CHECK: OpStore %output1 [[nullVSOutput]]
   VSOutput output1 = (VSOutput)0;
+// CHECK: OpStore %output2 [[nullVSOutput]]
+  VSOutput output2 = (VSOutput)0.0;
+// CHECK: OpStore %output3 [[nullVSOutput]]
+  VSOutput output3 = (VSOutput)false;
 
-// TODO: Avoid OpBitCast from 'literal int' to 'int'
-//
 // CHECK:                [[f1:%\d+]] = OpConvertSToF %float %int_1
 // CHECK-NEXT:         [[v4f1:%\d+]] = OpCompositeConstruct %v4float [[f1]] [[f1]] [[f1]] [[f1]]
 // CHECK-NEXT:           [[u1:%\d+]] = OpBitcast %uint %int_1
 // CHECK-NEXT:         [[v3u1:%\d+]] = OpCompositeConstruct %v3uint [[u1]] [[u1]] [[u1]]
-// CHECK-NEXT:         [[i1_0:%\d+]] = OpBitcast %int %int_1
-// CHECK-NEXT:         [[v2i1:%\d+]] = OpCompositeConstruct %v2int [[i1_0]] [[i1_0]]
+// CHECK-NEXT:         [[v2i1:%\d+]] = OpCompositeConstruct %v2int %int_1 %int_1
 // CHECK-NEXT:        [[bool1:%\d+]] = OpINotEqual %bool %int_1 %int_0
 // CHECK-NEXT:    [[arr2bool1:%\d+]] = OpCompositeConstruct %_arr_bool_uint_2 [[bool1]] [[bool1]]
-// CHECK-NEXT:         [[i1_1:%\d+]] = OpBitcast %int %int_1
-// CHECK-NEXT:       [[arr5i1:%\d+]] = OpCompositeConstruct %_arr_int_uint_5 [[i1_1]] [[i1_1]] [[i1_1]] [[i1_1]] [[i1_1]]
+// CHECK-NEXT:       [[arr5i1:%\d+]] = OpCompositeConstruct %_arr_int_uint_5 %int_1 %int_1 %int_1 %int_1 %int_1
 // CHECK-NEXT:         [[f1_1:%\d+]] = OpConvertSToF %float %int_1
 // CHECK-NEXT:         [[col3:%\d+]] = OpCompositeConstruct %v3float [[f1_1]] [[f1_1]] [[f1_1]]
 // CHECK-NEXT:    [[matFloat1:%\d+]] = OpCompositeConstruct %mat2v3float [[col3]] [[col3]]
 // CHECK-NEXT: [[flatConvert1:%\d+]] = OpCompositeConstruct %VSOutput [[v4f1]] [[v3u1]] [[v2i1]] [[arr2bool1]] [[arr5i1]] [[matFloat1]]
-// CHECK-NEXT:                         OpStore %output2 [[flatConvert1]]
-  VSOutput output2 = (VSOutput)1;
+// CHECK-NEXT:                         OpStore %output4 [[flatConvert1]]
+  VSOutput output4 = (VSOutput)1;
 
 // CHECK:                [[x:%\d+]] = OpLoad %int %x
 // CHECK-NEXT:       [[floatX:%\d+]] = OpConvertSToF %float [[x]]
@@ -51,6 +51,36 @@ void main() {
 // CHECK-NEXT:         [[v3fX:%\d+]] = OpCompositeConstruct %v3float [[floatX2]] [[floatX2]] [[floatX2]]
 // CHECK-NEXT:    [[matFloatX:%\d+]] = OpCompositeConstruct %mat2v3float [[v3fX]] [[v3fX]]
 // CHECK-NEXT: [[flatConvert2:%\d+]] = OpCompositeConstruct %VSOutput [[v4fX]] [[v3uX]] [[v2iX]] [[arr2boolX]] [[arr5iX]] [[matFloatX]]
-// CHECK-NEXT:                         OpStore %output3 [[flatConvert2]]
-  VSOutput output3 = (VSOutput)x;
+// CHECK-NEXT:                         OpStore %output5 [[flatConvert2]]
+  VSOutput output5 = (VSOutput)x;
+
+// CHECK:            [[v4f1_5:%\d+]] = OpCompositeConstruct %v4float %float_1_5 %float_1_5 %float_1_5 %float_1_5
+// CHECK-NEXT:         [[u1_5:%\d+]] = OpConvertFToU %uint %float_1_5
+// CHECK-NEXT:       [[v3u1_5:%\d+]] = OpCompositeConstruct %v3uint [[u1_5]] [[u1_5]] [[u1_5]]
+// CHECK-NEXT:         [[i1_5:%\d+]] = OpConvertFToS %int %float_1_5
+// CHECK-NEXT:       [[v2i1_5:%\d+]] = OpCompositeConstruct %v2int [[i1_5]] [[i1_5]]
+// CHECK-NEXT:      [[bool1_5:%\d+]] = OpFOrdNotEqual %bool %float_1_5 %float_0
+// CHECK-NEXT: [[arr2bool_1_5:%\d+]] = OpCompositeConstruct %_arr_bool_uint_2 [[bool1_5]] [[bool1_5]]
+// CHECK-NEXT:         [[i1_5:%\d+]] = OpConvertFToS %int %float_1_5
+// CHECK-NEXT:     [[arr5i1_5:%\d+]] = OpCompositeConstruct %_arr_int_uint_5 [[i1_5]] [[i1_5]] [[i1_5]] [[i1_5]] [[i1_5]]
+// CHECK-NEXT:      [[v3f_1_5:%\d+]] = OpCompositeConstruct %v3float %float_1_5 %float_1_5 %float_1_5
+// CHECK-NEXT: [[matFloat_1_5:%\d+]] = OpCompositeConstruct %mat2v3float [[v3f_1_5]] [[v3f_1_5]]
+// CHECK-NEXT:              {{%\d+}} = OpCompositeConstruct %VSOutput [[v4f1_5]] [[v3u1_5]] [[v2i1_5]] [[arr2bool_1_5]] [[arr5i1_5]] [[matFloat_1_5]]
+  VSOutput output6 = (VSOutput)1.5;
+
+// CHECK:      [[float_true:%\d+]] = OpSelect %float %true %float_1 %float_0
+// CHECK-NEXT:   [[v4f_true:%\d+]] = OpCompositeConstruct %v4float [[float_true]] [[float_true]] [[float_true]] [[float_true]]
+// CHECK-NEXT:  [[uint_true:%\d+]] = OpSelect %uint %true %uint_1 %uint_0
+// CHECK-NEXT:   [[v3u_true:%\d+]] = OpCompositeConstruct %v3uint [[uint_true]] [[uint_true]] [[uint_true]]
+// CHECK-NEXT:   [[int_true:%\d+]] = OpSelect %int %true %int_1 %int_0
+// CHECK-NEXT:   [[v2i_true:%\d+]] = OpCompositeConstruct %v2int [[int_true]] [[int_true]]
+// CHECK-NEXT:  [[arr2_true:%\d+]] = OpCompositeConstruct %_arr_bool_uint_2 %true %true
+// CHECK-NEXT:   [[int_true:%\d+]] = OpSelect %int %true %int_1 %int_0
+// CHECK-NEXT: [[arr5i_true:%\d+]] = OpCompositeConstruct %_arr_int_uint_5 [[int_true]] [[int_true]] [[int_true]] [[int_true]] [[int_true]]
+// CHECK-NEXT: [[float_true:%\d+]] = OpSelect %float %true %float_1 %float_0
+// CHECK-NEXT:   [[v3f_true:%\d+]] = OpCompositeConstruct %v3float [[float_true]] [[float_true]] [[float_true]]
+// CHECK-NEXT:[[mat2v3_true:%\d+]] = OpCompositeConstruct %mat2v3float [[v3f_true]] [[v3f_true]]
+// CHECK-NEXT:            {{%\d+}} = OpCompositeConstruct %VSOutput [[v4f_true]] [[v3u_true]] [[v2i_true]] [[arr2_true]] [[arr5i_true]] [[mat2v3_true]]
+  VSOutput output7 = (VSOutput)true;
+
 }

+ 11 - 0
tools/clang/test/CodeGenSPIRV/type.scalar.hlsl

@@ -1,5 +1,6 @@
 // Run: %dxc -T ps_6_0 -E main
 
+// CHECK: OpCapability Int64
 // CHECK: OpCapability Float64
 
 // CHECK: OpDecorate %m16i RelaxedPrecision
@@ -33,6 +34,14 @@ void main() {
   dword     dwordvar;
   min16uint m16u;
 
+// CHECK-DAG: %long = OpTypeInt 64 1
+// CHECK-DAG: %_ptr_Function_long = OpTypePointer Function %long
+  int64_t    int64var;
+
+// CHECK-DAG: %ulong = OpTypeInt 64 0
+// CHECK-DAG: %_ptr_Function_ulong = OpTypePointer Function %ulong
+  uint64_t   uint64var;
+
 // CHECK-DAG: %float = OpTypeFloat 32
 // CHECK-DAG: %_ptr_Function_float = OpTypePointer Function %float
   float      floatvar;
@@ -70,6 +79,8 @@ void main() {
 // CHECK-NEXT:    %uintvar = OpVariable %_ptr_Function_uint Function
 // CHECK-NEXT:   %dwordvar = OpVariable %_ptr_Function_uint Function
 // CHECK-NEXT:       %m16u = OpVariable %_ptr_Function_uint Function
+// CHECK-NEXT:   %int64var = OpVariable %_ptr_Function_long Function
+// CHECK-NEXT:  %uint64var = OpVariable %_ptr_Function_ulong Function
 // CHECK-NEXT:   %floatvar = OpVariable %_ptr_Function_float Function
 // CHECK-NEXT:    %halfvar = OpVariable %_ptr_Function_float Function
 // CHECK-NEXT:       %m16f = OpVariable %_ptr_Function_float Function