Pārlūkot izejas kodu

[spirv] Support casting to bool/int/float (vector) values (#500)

* [spirv] Translate casting to bool (vector) values

* Supported converting scalar/vector sint/uint/float values into
  scalar/vector bool values.

* [spirv] Translate casting to int (vector) values

* Supported converting scalar/vector bool/float values into
  scalar/vector sint/uint values.

* [spirv] Translate casting to float (vector) values

* Supported implicit/explicit casting from scalar/vector
  bool/sint/uint into scalar/vector float values
Lei Zhang 8 gadi atpakaļ
vecāks
revīzija
c760e02232

+ 17 - 0
docs/SPIR-V.rst

@@ -346,6 +346,23 @@ FOr `unary operators <https://msdn.microsoft.com/en-us/library/windows/desktop/b
 - ``+`` requires no additional SPIR-V instructions.
 - ``-`` is translated into ``OpSNegate`` and ``OpFNegate`` for (vectors of) integers and floats, respectively.
 
+Casts
++++++
+
+Casting between (vectors) of scalar types is translated according to the following table:
+
++------------+-------------------+-------------------+-------------------+-------------------+
+| From \\ To |        Bool       |       SInt        |      UInt         |       Float       |
++------------+-------------------+-------------------+-------------------+-------------------+
+|   Bool     |       no-op       |                 select between one and zero               |
++------------+-------------------+-------------------+-------------------+-------------------+
+|   SInt     |                   |     no-op         |  ``OpBitcast``    | ``OpConvertSToF`` |
++------------+                   +-------------------+-------------------+-------------------+
+|   UInt     | compare with zero |   ``OpBitcast``   |      no-op        | ``OpConvertUToF`` |
++------------+                   +-------------------+-------------------+-------------------+
+|   Float    |                   | ``OpConvertFToS`` | ``OpConvertFToU`` |      no-op        |
++------------+-------------------+-------------------+-------------------+-------------------+
+
 Control flows
 -------------
 

+ 13 - 2
tools/clang/lib/AST/ExprConstant.cpp

@@ -5629,7 +5629,14 @@ static bool EvaluateVector(const Expr* E, APValue& Result, EvalInfo &Info) {
 }
 
 bool VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
-  const VectorType *VTy = E->getType()->castAs<VectorType>();
+  // HLSL Change Begins.
+  const VectorType *VTy;
+  if (Info.getLangOpts().HLSL && hlsl::IsHLSLVecType(E->getType())) {
+    VTy = hlsl::ConvertHLSLVecMatTypeToExtVectorType(getEvalInfo().Ctx, E->getType());
+  } else {
+    VTy = E->getType()->castAs<VectorType>();
+  }
+  // HLSL Change Ends.
   unsigned NElts = VTy->getNumElements();
 
   const Expr *SE = E->getSubExpr();
@@ -5733,7 +5740,11 @@ VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
   while (CountElts < NumElements) {
     // Handle nested vector initialization.
     if (CountInits < NumInits 
-        && E->getInit(CountInits)->getType()->isVectorType()) {
+        && (E->getInit(CountInits)->getType()->isVectorType() ||
+            // HLSL Change Begins.
+            (Info.getLangOpts().HLSL &&
+             hlsl::IsHLSLVecType(E->getInit(CountInits)->getType())))) {
+            // HLSL Change Ends.
       APValue v;
       if (!EvaluateVector(E->getInit(CountInits), v, Info))
         return Error(E);

+ 231 - 49
tools/clang/lib/SPIRV/EmitSPIRVAction.cpp

@@ -26,6 +26,13 @@ namespace spirv {
 
 namespace {
 
+/// Returns true if the given type is a bool or vector of bool type.
+bool isBoolOrVecOfBoolType(QualType type) {
+  return type->isBooleanType() ||
+         (hlsl::IsHLSLVecType(type) &&
+          hlsl::GetHLSLVecElementType(type)->isBooleanType());
+}
+
 /// Returns true if the given type is a signed integer or vector of signed
 /// integer type.
 bool isSintOrVecOfSintType(QualType type) {
@@ -568,42 +575,12 @@ public:
       }
     }
 
-    if (const auto *castExpr = dyn_cast<ImplicitCastExpr>(expr)) {
-      return doImplicitCastExpr(castExpr);
-    }
-
-    if (const auto *cxxFunctionalCastExpr =
-            dyn_cast<CXXFunctionalCastExpr>(expr)) {
-      // Explicit cast is a NO-OP (e.g. vector<float, 4> -> float4)
-      if (cxxFunctionalCastExpr->getCastKind() == CK_NoOp) {
-        return doExpr(cxxFunctionalCastExpr->getSubExpr());
-      }
-      emitError("Found unhandled CXXFunctionalCastExpr cast type: %0")
-          << cxxFunctionalCastExpr->getCastKindName();
-      return 0;
+    if (const auto *castExpr = dyn_cast<CastExpr>(expr)) {
+      return doCastExpr(castExpr);
     }
 
     if (const auto *initListExpr = dyn_cast<InitListExpr>(expr)) {
-      // First try to evaluate the expression as constant expression
-      Expr::EvalResult evalResult;
-      if (expr->EvaluateAsRValue(evalResult, astContext) &&
-          !evalResult.HasSideEffects) {
-        return translateAPValue(evalResult.Val, expr->getType());
-      }
-
-      const uint32_t resultType =
-          typeTranslator.translateType(initListExpr->getType());
-
-      // Special case for vectors of size 1.
-      if (initListExpr->getNumInits() == 1) {
-        return doExpr(initListExpr->getInit(0));
-      }
-      std::vector<uint32_t> constituents;
-      for (size_t i = 0; i < initListExpr->getNumInits(); ++i) {
-        constituents.push_back(doExpr(initListExpr->getInit(i)));
-      }
-
-      return theBuilder.createCompositeConstruct(resultType, constituents);
+      return doInitListExpr(initListExpr);
     }
 
     if (const auto *boolLiteral = dyn_cast<CXXBoolLiteralExpr>(expr)) {
@@ -646,6 +623,77 @@ public:
     return 0;
   }
 
+  uint32_t doInitListExpr(const InitListExpr *expr) {
+    // First try to evaluate the expression as constant expression
+    Expr::EvalResult evalResult;
+    if (expr->EvaluateAsRValue(evalResult, astContext) &&
+        !evalResult.HasSideEffects) {
+      return translateAPValue(evalResult.Val, expr->getType());
+    }
+
+    const QualType type = expr->getType();
+
+    // InitListExpr is tricky to handle. It can have initializers of different
+    // types, and each initializer can itself be of a composite type.
+    // The front end parsing only gurantees the total number of elements in
+    // the initializers are the same as the one of the InitListExpr's type.
+
+    // For builtin types, we can assume the front end parsing has injected
+    // the necessary ImplicitCastExpr for type casting. So we just need to
+    // return the result of processing the only initializer.
+    if (type->isBuiltinType()) {
+      assert(expr->getNumInits() == 1);
+      return doExpr(expr->getInit(0));
+    }
+
+    // For composite types, we need to type cast the initializers if necessary.
+
+    const auto initCount = expr->getNumInits();
+    const uint32_t resultType = typeTranslator.translateType(type);
+
+    // For InitListExpr of vector type and having one initializer, we can avoid
+    // composite extraction and construction.
+    if (initCount == 1 && hlsl::IsHLSLVecType(type)) {
+      const Expr *init = expr->getInit(0);
+
+      // If the initializer already have the correct type, we don't need to
+      // type cast.
+      if (init->getType() == type) {
+        return doExpr(init);
+      }
+
+      // For the rest, we can do type cast as a whole.
+
+      const auto targetElemType = hlsl::GetHLSLVecElementType(type);
+      if (targetElemType->isBooleanType()) {
+        return castToBool(init, type);
+      } else if (targetElemType->isIntegerType()) {
+        return castToInt(init, type);
+      } else if (targetElemType->isFloatingType()) {
+        return castToFloat(init, type);
+      } else {
+        emitError("unimplemented vector InitList cases");
+        expr->dump();
+        return 0;
+      }
+    }
+
+    // Cases needing composite extraction and construction
+
+    std::vector<uint32_t> constituents;
+    for (size_t i = 0; i < initCount; ++i) {
+      const Expr *init = expr->getInit(i);
+      if (!init->getType()->isBuiltinType()) {
+        emitError("unimplemented InitList initializer type");
+        init->dump();
+        return 0;
+      }
+      constituents.push_back(doExpr(init));
+    }
+
+    return theBuilder.createCompositeConstruct(resultType, constituents);
+  }
+
   uint32_t doBinaryOperator(const BinaryOperator *expr) {
     const auto opcode = expr->getOpcode();
 
@@ -804,12 +852,24 @@ public:
     return 0;
   }
 
-  uint32_t doImplicitCastExpr(const ImplicitCastExpr *expr) {
+  uint32_t doCastExpr(const CastExpr *expr) {
     const Expr *subExpr = expr->getSubExpr();
     const QualType toType = expr->getType();
 
     switch (expr->getCastKind()) {
-    case CastKind::CK_IntegralCast: {
+    case CastKind::CK_LValueToRValue: {
+      const uint32_t fromValue = doExpr(subExpr);
+      // Using lvalue as rvalue means we need to OpLoad the contents from
+      // the parameter/variable first.
+      const uint32_t resultType = typeTranslator.translateType(toType);
+      return theBuilder.createLoad(resultType, fromValue);
+    }
+    case CastKind::CK_NoOp:
+      return doExpr(subExpr);
+    case CastKind::CK_IntegralCast:
+    case CastKind::CK_FloatingToIntegral:
+    case CastKind::CK_HLSLCC_IntegralCast:
+    case CastKind::CK_HLSLCC_FloatingToIntegral: {
       // Integer literals in the AST are represented using 64bit APInt
       // themselves and then implicitly casted into the expected bitwidth.
       // We need special treatment of integer literals here because generating
@@ -819,12 +879,14 @@ public:
       llvm::APSInt intValue;
       if (expr->EvaluateAsInt(intValue, astContext, Expr::SE_NoSideEffects)) {
         return translateAPInt(intValue, toType);
-      } else {
-        emitError("Integral cast is not supported yet");
-        return 0;
       }
+
+      return castToInt(subExpr, toType);
     }
-    case CastKind::CK_FloatingCast: {
+    case CastKind::CK_FloatingCast:
+    case CastKind::CK_IntegralToFloating:
+    case CastKind::CK_HLSLCC_FloatingCast:
+    case CastKind::CK_HLSLCC_IntegralToFloating: {
       // First try to see if we can do constant folding for floating point
       // numbers like what we are doing for integers in the above.
       Expr::EvalResult evalResult;
@@ -832,17 +894,22 @@ public:
           !evalResult.HasSideEffects) {
         return translateAPFloat(evalResult.Val.getFloat(), toType);
       }
-      emitError("floating cast unimplemented");
-      return 0;
-    }
-    case CastKind::CK_LValueToRValue: {
-      const uint32_t fromValue = doExpr(subExpr);
-      // Using lvalue as rvalue means we need to OpLoad the contents from
-      // the parameter/variable first.
-      const uint32_t resultType = typeTranslator.translateType(toType);
-      return theBuilder.createLoad(resultType, fromValue);
-    }
 
+      return castToFloat(subExpr, toType);
+    }
+    case CastKind::CK_IntegralToBoolean:
+    case CastKind::CK_FloatingToBoolean:
+    case CastKind::CK_HLSLCC_IntegralToBoolean:
+    case CastKind::CK_HLSLCC_FloatingToBoolean: {
+      // First try to see if we can do constant folding.
+      bool boolVal;
+      if (!expr->HasSideEffects(astContext) &&
+          expr->EvaluateAsBooleanCondition(boolVal, astContext)) {
+        return theBuilder.getConstantBool(boolVal);
+      }
+
+      return castToBool(subExpr, toType);
+    }
     case CastKind::CK_HLSLVectorSplat: {
       const size_t size = hlsl::GetHLSLVecSize(expr->getType());
       const uint32_t scalarValue = doExpr(subExpr);
@@ -950,6 +1017,58 @@ public:
     }
   }
 
+  /// Processes the given expr, casts the result into the given bool (vector)
+  /// type and returns the <result-id> of the casted value.
+  uint32_t castToBool(const Expr *expr, QualType toBoolType) {
+    // Converting to bool means comparing with value zero.
+
+    const uint32_t fromVal = doExpr(expr);
+
+    if (isBoolOrVecOfBoolType(expr->getType()))
+      return fromVal;
+
+    const spv::Op spvOp = translateOp(BO_NE, expr->getType());
+    const uint32_t boolType = typeTranslator.translateType(toBoolType);
+    const uint32_t zeroVal = getValueZero(expr->getType());
+
+    return theBuilder.createBinaryOp(spvOp, boolType, fromVal, zeroVal);
+  }
+
+  /// Processes the given expr, casts the result into the given integer (vector)
+  /// type and returns the <result-id> of the casted value.
+  uint32_t castToInt(const Expr *expr, QualType toIntType) {
+    const QualType fromType = expr->getType();
+    const uint32_t intType = typeTranslator.translateType(toIntType);
+    const uint32_t fromVal = doExpr(expr);
+
+    if (isBoolOrVecOfBoolType(fromType)) {
+      const uint32_t one = getValueOne(toIntType);
+      const uint32_t zero = getValueZero(toIntType);
+      return theBuilder.createSelect(intType, fromVal, one, zero);
+    } else if (isSintOrVecOfSintType(fromType) ||
+               isUintOrVecOfUintType(fromType)) {
+      if (fromType == toIntType)
+        return fromVal;
+      // TODO: handle different bitwidths
+      return theBuilder.createUnaryOp(spv::Op::OpBitcast, intType, fromVal);
+    } else if (isFloatOrVecOfFloatType(fromType)) {
+      if (isSintOrVecOfSintType(toIntType)) {
+        return theBuilder.createUnaryOp(spv::Op::OpConvertFToS, intType,
+                                        fromVal);
+      } else if (isUintOrVecOfUintType(toIntType)) {
+        return theBuilder.createUnaryOp(spv::Op::OpConvertFToU, intType,
+                                        fromVal);
+      } else {
+        emitError("unimplemented casting to integer from floating point");
+      }
+    } else {
+      emitError("unimplemented casting to integer");
+    }
+
+    expr->dump();
+    return 0;
+  }
+
   uint32_t processIntrinsicCallExpr(const CallExpr *callExpr) {
     const FunctionDecl *callee = callExpr->getDirectCallee();
     assert(hlsl::IsIntrinsicOp(callee) &&
@@ -974,6 +1093,36 @@ public:
     return 0;
   }
 
+  uint32_t castToFloat(const Expr *expr, QualType toFloatType) {
+    const QualType fromType = expr->getType();
+    const uint32_t floatType = typeTranslator.translateType(toFloatType);
+    const uint32_t fromVal = doExpr(expr);
+
+    if (isBoolOrVecOfBoolType(fromType)) {
+      const uint32_t one = getValueOne(toFloatType);
+      const uint32_t zero = getValueZero(toFloatType);
+      return theBuilder.createSelect(floatType, fromVal, one, zero);
+    }
+
+    if (isSintOrVecOfSintType(fromType)) {
+      return theBuilder.createUnaryOp(spv::Op::OpConvertSToF, floatType,
+                                      fromVal);
+    }
+
+    if (isUintOrVecOfUintType(fromType)) {
+      return theBuilder.createUnaryOp(spv::Op::OpConvertUToF, floatType,
+                                      fromVal);
+    }
+
+    if (isFloatOrVecOfFloatType(fromType)) {
+      return fromVal;
+    }
+
+    emitError("unimplemented casting to floating point");
+    expr->dump();
+    return 0;
+  }
+
   uint32_t doCallExpr(const CallExpr *callExpr) {
     const FunctionDecl *callee = callExpr->getDirectCallee();
 
@@ -1230,6 +1379,39 @@ case BO_##kind : {                                                             \
     return 0;
   }
 
+  /// Returns the <result-id> for constant value 0 of the given type.
+  uint32_t getValueZero(QualType type) {
+    if (type->isSignedIntegerType()) {
+      return theBuilder.getConstantInt32(0);
+    }
+
+    if (type->isUnsignedIntegerType()) {
+      return theBuilder.getConstantUint32(0);
+    }
+
+    if (type->isFloatingType()) {
+      return theBuilder.getConstantFloat32(0.0);
+    }
+
+    if (hlsl::IsHLSLVecType(type)) {
+      const QualType elemType = hlsl::GetHLSLVecElementType(type);
+      const uint32_t elemZeroId = getValueZero(elemType);
+
+      const size_t size = hlsl::GetHLSLVecSize(type);
+      if (size == 1)
+        return elemZeroId;
+
+      llvm::SmallVector<uint32_t, 4> elements(size, elemZeroId);
+
+      const uint32_t vecTypeId = typeTranslator.translateType(type);
+      return theBuilder.getConstantComposite(vecTypeId, elements);
+    }
+
+    emitError("getting value 0 for type '%0' unimplemented")
+        << type.getAsString();
+    return 0;
+  }
+
   /// Translates the given frontend APValue into its SPIR-V equivalent for the
   /// given targetType.
   uint32_t translateAPValue(const APValue &value, const QualType targetType) {

+ 103 - 0
tools/clang/test/CodeGenSPIRV/cast.2bool.explicit.hlsl

@@ -0,0 +1,103 @@
+// Run: %dxc -T ps_6_0 -E main
+
+// CHECK: [[v2uint_0_0:%\d+]] = OpConstantComposite %v2uint %uint_0 %uint_0
+// CHECK: [[v3float_0_0_0:%\d+]] = OpConstantComposite %v3float %float_0 %float_0 %float_0
+// CHECK: [[v2bool_1_1:%\d+]] = OpConstantComposite %v2bool %true %true
+
+void main() {
+// CHECK-LABEL: %bb_entry = OpLabel
+    bool b;
+    int from1;
+    uint from2;
+    float from3;
+
+    bool1 vb1;
+    bool2 vb2;
+    bool3 vb3;
+    int1 vfrom1;
+    uint2 vfrom2;
+    float3 vfrom3;
+
+    // C style cast
+
+    // From constant (explicit)
+// CHECK: OpStore %b %true
+    b = (bool)35;
+// CHECK-NEXT: OpStore %b %false
+    b = (bool)0.0;
+
+    // From constant expr
+// CHECK-NEXT: OpStore %b %true
+    b = (bool)(3.5 - 3.4);
+
+    // From variable (explicit)
+// CHECK-NEXT: [[from1:%\d+]] = OpLoad %int %from1
+// CHECK-NEXT: [[c1:%\d+]] = OpINotEqual %bool [[from1]] %int_0
+// CHECK-NEXT: OpStore %b [[c1]]
+    b = (bool)from1;
+// CHECK-NEXT: [[from2:%\d+]] = OpLoad %uint %from2
+// CHECK-NEXT: [[c2:%\d+]] = OpINotEqual %bool [[from2]] %uint_0
+// CHECK-NEXT: OpStore %b [[c2]]
+    b = (bool)from2;
+// CHECK-NEXT: [[from3:%\d+]] = OpLoad %float %from3
+// CHECK-NEXT: [[c3:%\d+]] = OpFOrdNotEqual %bool [[from3]] %float_0
+// CHECK-NEXT: OpStore %b [[c3]]
+    b = (bool)from3;
+
+    // C++ function style cast
+
+// CHECK-NEXT: OpStore %b %false
+    b = bool(0);
+// CHECK-NEXT: OpStore %b %true
+    b = bool(3.5);
+
+// CHECK-NEXT: OpStore %b %true
+    b = bool(42 + 1);
+
+// CHECK-NEXT: [[from4:%\d+]] = OpLoad %int %from1
+// CHECK-NEXT: [[c4:%\d+]] = OpINotEqual %bool [[from4]] %int_0
+// CHECK-NEXT: OpStore %b [[c4]]
+    b = bool(from1);
+// CHECK-NEXT: [[from5:%\d+]] = OpLoad %uint %from2
+// CHECK-NEXT: [[c5:%\d+]] = OpINotEqual %bool [[from5]] %uint_0
+// CHECK-NEXT: OpStore %b [[c5]]
+    b = bool(from2);
+// CHECK-NEXT: [[from6:%\d+]] = OpLoad %float %from3
+// CHECK-NEXT: [[c6:%\d+]] = OpFOrdNotEqual %bool [[from6]] %float_0
+// CHECK-NEXT: OpStore %b [[c6]]
+    b = bool(from3);
+
+    // Vector cases
+
+// CHECK-NEXT: OpStore %vb1 %true
+    vb1 = (bool1)42;
+// CHECK-NEXT: [[vfrom1:%\d+]] = OpLoad %int %vfrom1
+// CHECK-NEXT: [[vc1:%\d+]] = OpINotEqual %bool [[vfrom1]] %int_0
+// CHECK-NEXT: OpStore %vb1 [[vc1]]
+    vb1 = (bool1)vfrom1;
+// CHECK-NEXT: [[vfrom2:%\d+]] = OpLoad %v2uint %vfrom2
+// CHECK-NEXT: [[vc2:%\d+]] = OpINotEqual %v2bool [[vfrom2]] [[v2uint_0_0]]
+// CHECK-NEXT: OpStore %vb2 [[vc2]]
+    vb2 = (bool2)vfrom2;
+// CHECK-NEXT: [[vfrom3:%\d+]] = OpLoad %v3float %vfrom3
+// CHECK-NEXT: [[vc3:%\d+]] = OpFOrdNotEqual %v3bool [[vfrom3]] [[v3float_0_0_0]]
+// CHECK-NEXT: OpStore %vb3 [[vc3]]
+    vb3 = (bool3)vfrom3;
+
+// CHECK-NEXT: OpStore %vb1 %true
+    vb1 = bool1(3.5);
+// CHECK-NEXT: OpStore %vb2 [[v2bool_1_1]]
+    vb2 = bool2(1.1 + 1.2, 3.0);
+// CHECK-NEXT: [[vfrom4:%\d+]] = OpLoad %int %vfrom1
+// CHECK-NEXT: [[vc4:%\d+]] = OpINotEqual %bool [[vfrom4]] %int_0
+// CHECK-NEXT: OpStore %vb1 [[vc4]]
+    vb1 = bool1(vfrom1);
+// CHECK-NEXT: [[vfrom5:%\d+]] = OpLoad %v2uint %vfrom2
+// CHECK-NEXT: [[vc5:%\d+]] = OpINotEqual %v2bool [[vfrom5]] [[v2uint_0_0]]
+// CHECK-NEXT: OpStore %vb2 [[vc5]]
+    vb2 = bool2(vfrom2);
+// CHECK-NEXT: [[vfrom6:%\d+]] = OpLoad %v3float %vfrom3
+// CHECK-NEXT: [[vc6:%\d+]] = OpFOrdNotEqual %v3bool [[vfrom6]] [[v3float_0_0_0]]
+// CHECK-NEXT: OpStore %vb3 [[vc6]]
+    vb3 = bool3(vfrom3);
+}

+ 66 - 0
tools/clang/test/CodeGenSPIRV/cast.2bool.implicit.hlsl

@@ -0,0 +1,66 @@
+// Run: %dxc -T ps_6_0 -E main
+
+// CHECK: [[v2bool_1_0:%\d+]] = OpConstantComposite %v2bool %true %false
+// CHECK: [[v3bool_0_1_1:%\d+]] = OpConstantComposite %v3bool %false %true %true
+// CHECK: [[v2uint_0_0:%\d+]] = OpConstantComposite %v2uint %uint_0 %uint_0
+// CHECK: [[v3float_0_0_0:%\d+]] = OpConstantComposite %v3float %float_0 %float_0 %float_0
+
+void main() {
+// CHECK-LABEL: %bb_entry = OpLabel
+    bool b;
+    int from1;
+    uint from2;
+    float from3;
+
+    bool1 vb1;
+    bool2 vb2;
+    bool3 vb3;
+    int1 vfrom1;
+    uint2 vfrom2;
+    float3 vfrom3;
+// CHECK: %vbc2 = OpVariable %_ptr_Function_v2bool Function [[v2bool_1_0]]
+// CHECK: %vbc3 = OpVariable %_ptr_Function_v3bool Function [[v3bool_0_1_1]]
+
+    // From constant (implicit)
+// CHECK: OpStore %b %true
+    b = 42;
+// CHECK-NEXT: OpStore %b %false
+    b = 0.0;
+
+    // From constant expr
+// CHECK-NEXT: OpStore %b %false
+    b = 35 - 35;
+
+    // From variable (implicit)
+// CHECK-NEXT: [[from1:%\d+]] = OpLoad %int %from1
+// CHECK-NEXT: [[c1:%\d+]] = OpINotEqual %bool [[from1]] %int_0
+// CHECK-NEXT: OpStore %b [[c1]]
+    b = from1;
+// CHECK-NEXT: [[from2:%\d+]] = OpLoad %uint %from2
+// CHECK-NEXT: [[c2:%\d+]] = OpINotEqual %bool [[from2]] %uint_0
+// CHECK-NEXT: OpStore %b [[c2]]
+    b = from2;
+// CHECK-NEXT: [[from3:%\d+]] = OpLoad %float %from3
+// CHECK-NEXT: [[c3:%\d+]] = OpFOrdNotEqual %bool [[from3]] %float_0
+// CHECK-NEXT: OpStore %b [[c3]]
+    b = from3;
+
+    // Vector cases
+
+    // See the beginning for generated code
+    bool2 vbc2 = {1, 15 - 15};
+    bool3 vbc3 = {0.0, 1.2 + 1.1, 3}; // Mixed
+
+// CHECK-NEXT: [[vfrom1:%\d+]] = OpLoad %int %vfrom1
+// CHECK-NEXT: [[vc1:%\d+]] = OpINotEqual %bool [[vfrom1]] %int_0
+// CHECK-NEXT: OpStore %vb1 [[vc1]]
+    vb1 = vfrom1;
+// CHECK-NEXT: [[vfrom2:%\d+]] = OpLoad %v2uint %vfrom2
+// CHECK-NEXT: [[vc2:%\d+]] = OpINotEqual %v2bool [[vfrom2]] [[v2uint_0_0]]
+// CHECK-NEXT: OpStore %vb2 [[vc2]]
+    vb2 = vfrom2;
+// CHECK-NEXT: [[vfrom3:%\d+]] = OpLoad %v3float %vfrom3
+// CHECK-NEXT: [[vc3:%\d+]] = OpFOrdNotEqual %v3bool [[vfrom3]] [[v3float_0_0_0]]
+// CHECK-NEXT: OpStore %vb3 [[vc3]]
+    vb3 = vfrom3;
+}

+ 104 - 0
tools/clang/test/CodeGenSPIRV/cast.2fp.explicit.hlsl

@@ -0,0 +1,104 @@
+// Run: %dxc -T ps_6_0 -E main
+
+// CHECK: [[v2float_1_1:%\d+]] = OpConstantComposite %v2float %float_1 %float_1
+// CHECK: [[v2float_0_0:%\d+]] = OpConstantComposite %v2float %float_0 %float_0
+// CHECK: [[v3float_1_2_n3:%\d+]] = OpConstantComposite %v3float %float_1 %float_2 %float_n3
+
+void main() {
+// CHECK-LABEL: %bb_entry = OpLabel
+    float f;
+    uint from1;
+    bool from2;
+    int from3;
+
+    float1 vf1;
+    float2 vf2;
+    float3 vf3;
+    uint1 vfrom1;
+    bool2 vfrom2;
+    int3 vfrom3;
+
+    // C style cast
+
+    // From constant (explicit)
+// CHECK: OpStore %f %float_1
+    f = (float)true;
+// CHECK-NEXT: OpStore %f %float_4
+    f = (float)4u;
+
+    // From constant expr
+// CHECK-NEXT: OpStore %f %float_n2
+    f = (float)(3 - 5);
+
+    // From variable (explicit)
+// CHECK-NEXT: [[from1:%\d+]] = OpLoad %uint %from1
+// CHECK-NEXT: [[c1:%\d+]] = OpConvertUToF %float [[from1]]
+// CHECK-NEXT: OpStore %f [[c1]]
+    f = (float)from1;
+// CHECK-NEXT: [[from2:%\d+]] = OpLoad %bool %from2
+// CHECK-NEXT: [[c2:%\d+]] = OpSelect %float [[from2]] %float_1 %float_0
+// CHECK-NEXT: OpStore %f [[c2]]
+    f = (float)from2;
+// CHECK-NEXT: [[from3:%\d+]] = OpLoad %int %from3
+// CHECK-NEXT: [[c3:%\d+]] = OpConvertSToF %float [[from3]]
+// CHECK-NEXT: OpStore %f [[c3]]
+    f = (float)from3;
+
+    // C++ function style cast
+
+// CHECK-NEXT: OpStore %f %float_0
+    f = float(false);
+// CHECK-NEXT: OpStore %f %float_2
+    f = float(2u);
+
+// CHECK-NEXT: OpStore %f %float_3
+    f = float(-1 + 4);
+
+// CHECK-NEXT: [[from4:%\d+]] = OpLoad %uint %from1
+// CHECK-NEXT: [[c4:%\d+]] = OpConvertUToF %float [[from4]]
+// CHECK-NEXT: OpStore %f [[c4]]
+    f = float(from1);
+// CHECK-NEXT: [[from5:%\d+]] = OpLoad %bool %from2
+// CHECK-NEXT: [[c5:%\d+]] = OpSelect %float [[from5]] %float_1 %float_0
+// CHECK-NEXT: OpStore %f [[c5]]
+    f = float(from2);
+// CHECK-NEXT: [[from6:%\d+]] = OpLoad %int %from3
+// CHECK-NEXT: [[c6:%\d+]] = OpConvertSToF %float [[from6]]
+// CHECK-NEXT: OpStore %f [[c6]]
+    f = float(from3);
+
+    // Vector cases
+
+// CHECK-NEXT: OpStore %vf1 %float_7
+    vf1 = (float1)7;
+// CHECK-NEXT: [[vfrom1:%\d+]] = OpLoad %uint %vfrom1
+// CHECK-NEXT: [[vc1:%\d+]] = OpConvertUToF %float [[vfrom1]]
+// CHECK-NEXT: OpStore %vf1 [[vc1]]
+    vf1 = (float1)vfrom1;
+// CHECK-NEXT: [[vfrom2:%\d+]] = OpLoad %v2bool %vfrom2
+// CHECK-NEXT: [[vc2:%\d+]] = OpSelect %v2float [[vfrom2]] [[v2float_1_1]] [[v2float_0_0]]
+// CHECK-NEXT: OpStore %vf2 [[vc2]]
+    vf2 = (float2)vfrom2;
+// CHECK-NEXT: [[vfrom3:%\d+]] = OpLoad %v3int %vfrom3
+// CHECK-NEXT: [[vc3:%\d+]] = OpConvertSToF %v3float [[vfrom3]]
+// CHECK-NEXT: OpStore %vf3 [[vc3]]
+    vf3 = (float3)vfrom3;
+
+// CHECK-NEXT: OpStore %vf1 %float_3
+    vf1 = float1(3);
+// CHECK-NEXT: OpStore %vf3 [[v3float_1_2_n3]]
+    vf3 = float3(true, 2u, -3);
+// CHECK-NEXT: [[vfrom4:%\d+]] = OpLoad %uint %vfrom1
+// CHECK-NEXT: [[vc4:%\d+]] = OpConvertUToF %float [[vfrom4]]
+// CHECK-NEXT: OpStore %vf1 [[vc4]]
+    vf1 = float1(vfrom1);
+// CHECK-NEXT: [[vfrom5:%\d+]] = OpLoad %v2bool %vfrom2
+// CHECK-NEXT: [[vc5:%\d+]] = OpSelect %v2float [[vfrom5]] [[v2float_1_1]] [[v2float_0_0]]
+// CHECK-NEXT: OpStore %vf2 [[vc5]]
+    vf2 = float2(vfrom2);
+// CHECK-NEXT: [[vfrom6:%\d+]] = OpLoad %v3int %vfrom3
+// CHECK-NEXT: [[vc6:%\d+]] = OpConvertSToF %v3float [[vfrom6]]
+// CHECK-NEXT: OpStore %vf3 [[vc6]]
+    vf3 = float3(vfrom3);
+}
+

+ 64 - 0
tools/clang/test/CodeGenSPIRV/cast.2fp.implicit.hlsl

@@ -0,0 +1,64 @@
+// Run: %dxc -T ps_6_0 -E main
+
+// CHECK: [[v2float_1_0:%\d+]] = OpConstantComposite %v2float %float_1 %float_0
+// CHECK: [[v3float_0_4_n3:%\d+]] = OpConstantComposite %v3float %float_0 %float_4 %float_n3
+
+void main() {
+// CHECK-LABEL: %bb_entry = OpLabel
+    float f;
+    bool from1;
+    uint from2;
+    int from3;
+
+    float1 vf1;
+    float2 vf2;
+    float3 vf3;
+    bool1 vfrom1;
+    uint2 vfrom2;
+    int3 vfrom3;
+// CHECK: %vfc2 = OpVariable %_ptr_Function_v2float Function [[v2float_1_0]]
+// CHECK: %vfc3 = OpVariable %_ptr_Function_v3float Function [[v3float_0_4_n3]]
+
+    // From constant (implicit)
+// CHECK: OpStore %f %float_1
+    f = true;
+// CHECK-NEXT: OpStore %f %float_3
+    f = 3u;
+
+    // From constant expr
+// CHECK-NEXT: OpStore %f %float_n1
+    f = 5 - 6;
+
+    // From variable (implicit)
+// CHECK-NEXT: [[from1:%\d+]] = OpLoad %bool %from1
+// CHECK-NEXT: [[c1:%\d+]] = OpSelect %float [[from1]] %float_1 %float_0
+// CHECK-NEXT: OpStore %f [[c1]]
+    f = from1;
+// CHECK-NEXT: [[from2:%\d+]] = OpLoad %uint %from2
+// CHECK-NEXT: [[c2:%\d+]] = OpConvertUToF %float [[from2]]
+// CHECK-NEXT: OpStore %f [[c2]]
+    f = from2;
+// CHECK-NEXT: [[from3:%\d+]] = OpLoad %int %from3
+// CHECK-NEXT: [[c3:%\d+]] = OpConvertSToF %float [[from3]]
+// CHECK-NEXT: OpStore %f [[c3]]
+    f = from3;
+
+    // Vector cases
+
+    // See the beginning for generated code
+    float2 vfc2 = {true, false};
+    float3 vfc3 = {false, 4u, -3}; // Mixed
+
+// CHECK-NEXT: [[vfrom1:%\d+]] = OpLoad %bool %vfrom1
+// CHECK-NEXT: [[vc1:%\d+]] = OpSelect %float [[vfrom1]] %float_1 %float_0
+// CHECK-NEXT: OpStore %vf1 [[vc1]]
+    vf1 = vfrom1;
+// CHECK-NEXT: [[vfrom2:%\d+]] = OpLoad %v2uint %vfrom2
+// CHECK-NEXT: [[vc2:%\d+]] = OpConvertUToF %v2float [[vfrom2]]
+// CHECK-NEXT: OpStore %vf2 [[vc2]]
+    vf2 = vfrom2;
+// CHECK-NEXT: [[vfrom3:%\d+]] = OpLoad %v3int %vfrom3
+// CHECK-NEXT: [[vc3:%\d+]] = OpConvertSToF %v3float [[vfrom3]]
+// CHECK-NEXT: OpStore %vf3 [[vc3]]
+    vf3 = vfrom3;
+}

+ 103 - 0
tools/clang/test/CodeGenSPIRV/cast.2sint.explicit.hlsl

@@ -0,0 +1,103 @@
+// Run: %dxc -T ps_6_0 -E main
+
+// CHECK: [[v2int_1_1:%\d+]] = OpConstantComposite %v2int %int_1 %int_1
+// CHECK: [[v2int_0_0:%\d+]] = OpConstantComposite %v2int %int_0 %int_0
+// CHECK: [[v2int_2_n3:%\d+]] = OpConstantComposite %v2int %int_2 %int_n3
+
+void main() {
+// CHECK-LABEL: %bb_entry = OpLabel
+    int i;
+    uint from1;
+    bool from2;
+    float from3;
+
+    int1 vi1;
+    int2 vi2;
+    int3 vi3;
+    uint1 vfrom1;
+    bool2 vfrom2;
+    float3 vfrom3;
+
+    // C style cast
+
+    // From constant (explicit)
+// CHECK: OpStore %i %int_1
+    i = (int)true;
+// CHECK-NEXT: OpStore %i %int_3
+    i = (int)3.0;
+
+    // From constant expr
+// CHECK-NEXT: OpStore %i %int_n2
+    i = (int)(3.4 - 5.5);
+
+    // From variable (explicit)
+// CHECK-NEXT: [[from1:%\d+]] = OpLoad %uint %from1
+// CHECK-NEXT: [[c1:%\d+]] = OpBitcast %int [[from1]]
+// CHECK-NEXT: OpStore %i [[c1]]
+    i = (int)from1;
+// CHECK-NEXT: [[from2:%\d+]] = OpLoad %bool %from2
+// CHECK-NEXT: [[c2:%\d+]] = OpSelect %int [[from2]] %int_1 %int_0
+// CHECK-NEXT: OpStore %i [[c2]]
+    i = (int)from2;
+// CHECK-NEXT: [[from3:%\d+]] = OpLoad %float %from3
+// CHECK-NEXT: [[c3:%\d+]] = OpConvertFToS %int [[from3]]
+// CHECK-NEXT: OpStore %i [[c3]]
+    i = (int)from3;
+
+    // C++ function style cast
+
+// CHECK-NEXT: OpStore %i %int_0
+    i = int(false);
+// CHECK-NEXT: OpStore %i %int_3
+    i = int(3.5);
+
+// CHECK-NEXT: OpStore %i %int_5
+    i = int(3.3 + 2.2);
+
+// CHECK-NEXT: [[from4:%\d+]] = OpLoad %uint %from1
+// CHECK-NEXT: [[c4:%\d+]] = OpBitcast %int [[from4]]
+// CHECK-NEXT: OpStore %i [[c4]]
+    i = int(from1);
+// CHECK-NEXT: [[from5:%\d+]] = OpLoad %bool %from2
+// CHECK-NEXT: [[c5:%\d+]] = OpSelect %int [[from5]] %int_1 %int_0
+// CHECK-NEXT: OpStore %i [[c5]]
+    i = int(from2);
+// CHECK-NEXT: [[from6:%\d+]] = OpLoad %float %from3
+// CHECK-NEXT: [[c6:%\d+]] = OpConvertFToS %int [[from6]]
+// CHECK-NEXT: OpStore %i [[c6]]
+    i = int(from3);
+
+    // Vector cases
+
+// CHECK-NEXT: OpStore %vi1 %int_3
+    vi1 = (int1)3.6;
+// CHECK-NEXT: [[vfrom1:%\d+]] = OpLoad %uint %vfrom1
+// CHECK-NEXT: [[vc1:%\d+]] = OpBitcast %int [[vfrom1]]
+// CHECK-NEXT: OpStore %vi1 [[vc1]]
+    vi1 = (int1)vfrom1;
+// CHECK-NEXT: [[vfrom2:%\d+]] = OpLoad %v2bool %vfrom2
+// CHECK-NEXT: [[vc2:%\d+]] = OpSelect %v2int [[vfrom2]] [[v2int_1_1]] [[v2int_0_0]]
+// CHECK-NEXT: OpStore %vi2 [[vc2]]
+    vi2 = (int2)vfrom2;
+// CHECK-NEXT: [[vfrom3:%\d+]] = OpLoad %v3float %vfrom3
+// CHECK-NEXT: [[vc3:%\d+]] = OpConvertFToS %v3int [[vfrom3]]
+// CHECK-NEXT: OpStore %vi3 [[vc3]]
+    vi3 = (int3)vfrom3;
+
+// CHECK-NEXT: OpStore %vi1 %int_3
+    vi1 = int1(3.5);
+// CHECK-NEXT: OpStore %vi2 [[v2int_2_n3]]
+    vi2 = int2(1.1 + 1.2, -3);
+// CHECK-NEXT: [[vfrom4:%\d+]] = OpLoad %uint %vfrom1
+// CHECK-NEXT: [[vc4:%\d+]] = OpBitcast %int [[vfrom4]]
+// CHECK-NEXT: OpStore %vi1 [[vc4]]
+    vi1 = int1(vfrom1);
+// CHECK-NEXT: [[vfrom5:%\d+]] = OpLoad %v2bool %vfrom2
+// CHECK-NEXT: [[vc5:%\d+]] = OpSelect %v2int [[vfrom5]] [[v2int_1_1]] [[v2int_0_0]]
+// CHECK-NEXT: OpStore %vi2 [[vc5]]
+    vi2 = int2(vfrom2);
+// CHECK-NEXT: [[vfrom6:%\d+]] = OpLoad %v3float %vfrom3
+// CHECK-NEXT: [[vc6:%\d+]] = OpConvertFToS %v3int [[vfrom6]]
+// CHECK-NEXT: OpStore %vi3 [[vc6]]
+    vi3 = int3(vfrom3);
+}

+ 64 - 0
tools/clang/test/CodeGenSPIRV/cast.2sint.implicit.hlsl

@@ -0,0 +1,64 @@
+// Run: %dxc -T ps_6_0 -E main
+
+// CHECK: [[v2int_1_0:%\d+]] = OpConstantComposite %v2int %int_1 %int_0
+// CHECK: [[v3int_0_2_n3:%\d+]] = OpConstantComposite %v3int %int_0 %int_2 %int_n3
+
+void main() {
+// CHECK-LABEL: %bb_entry = OpLabel
+    int i;
+    bool from1;
+    uint from2;
+    float from3;
+
+    int1 vi1;
+    int2 vi2;
+    int3 vi3;
+    bool1 vfrom1;
+    uint2 vfrom2;
+    float3 vfrom3;
+// CHECK: %vic2 = OpVariable %_ptr_Function_v2int Function [[v2int_1_0]]
+// CHECK: %vic3 = OpVariable %_ptr_Function_v3int Function [[v3int_0_2_n3]]
+
+    // From constant (implicit)
+// CHECK: OpStore %i %int_1
+    i = true;
+// CHECK-NEXT: OpStore %i %int_0
+    i = 0.0;
+
+    // From constant expr
+// CHECK-NEXT: OpStore %i %int_n3
+    i = 1.1 - 4.3;
+
+    // From variable (implicit)
+// CHECK-NEXT: [[from1:%\d+]] = OpLoad %bool %from1
+// CHECK-NEXT: [[c1:%\d+]] = OpSelect %int [[from1]] %int_1 %int_0
+// CHECK-NEXT: OpStore %i [[c1]]
+    i = from1;
+// CHECK-NEXT: [[from2:%\d+]] = OpLoad %uint %from2
+// CHECK-NEXT: [[c2:%\d+]] = OpBitcast %int [[from2]]
+// CHECK-NEXT: OpStore %i [[c2]]
+    i = from2;
+// CHECK-NEXT: [[from3:%\d+]] = OpLoad %float %from3
+// CHECK-NEXT: [[c3:%\d+]] = OpConvertFToS %int [[from3]]
+// CHECK-NEXT: OpStore %i [[c3]]
+    i = from3;
+
+    // Vector cases
+
+    // See the beginning for generated code
+    int2 vic2 = {true, false};
+    int3 vic3 = {false, 1.1 + 1.2, -3}; // Mixed
+
+// CHECK-NEXT: [[vfrom1:%\d+]] = OpLoad %bool %vfrom1
+// CHECK-NEXT: [[vc1:%\d+]] = OpSelect %int [[vfrom1]] %int_1 %int_0
+// CHECK-NEXT: OpStore %vi1 [[vc1]]
+    vi1 = vfrom1;
+// CHECK-NEXT: [[vfrom2:%\d+]] = OpLoad %v2uint %vfrom2
+// CHECK-NEXT: [[vc2:%\d+]] = OpBitcast %v2int [[vfrom2]]
+// CHECK-NEXT: OpStore %vi2 [[vc2]]
+    vi2 = vfrom2;
+// CHECK-NEXT: [[vfrom3:%\d+]] = OpLoad %v3float %vfrom3
+// CHECK-NEXT: [[vc3:%\d+]] = OpConvertFToS %v3int [[vfrom3]]
+// CHECK-NEXT: OpStore %vi3 [[vc3]]
+    vi3 = vfrom3;
+}

+ 104 - 0
tools/clang/test/CodeGenSPIRV/cast.2uint.explicit.hlsl

@@ -0,0 +1,104 @@
+// Run: %dxc -T ps_6_0 -E main
+
+// CHECK: [[v2uint_1_1:%\d+]] = OpConstantComposite %v2uint %uint_1 %uint_1
+// CHECK: [[v2uint_0_0:%\d+]] = OpConstantComposite %v2uint %uint_0 %uint_0
+// CHECK: [[v2uint_2_3:%\d+]] = OpConstantComposite %v2uint %uint_2 %uint_3
+
+void main() {
+// CHECK-LABEL: %bb_entry = OpLabel
+    uint i;
+    int from1;
+    bool from2;
+    float from3;
+
+    uint1 vi1;
+    uint2 vi2;
+    uint3 vi3;
+    int1 vfrom1;
+    bool2 vfrom2;
+    float3 vfrom3;
+
+    // C style cast
+
+    // From constant (explicit)
+// CHECK: OpStore %i %uint_1
+    i = (uint)true;
+// CHECK-NEXT: OpStore %i %uint_3
+    i = (uint)3.0;
+
+    // From constant expr
+// CHECK-NEXT: OpStore %i %uint_2
+    i = (uint)(5.5 - 3.4);
+
+    // From variable (explicit)
+// CHECK-NEXT: [[from1:%\d+]] = OpLoad %int %from1
+// CHECK-NEXT: [[c1:%\d+]] = OpBitcast %uint [[from1]]
+// CHECK-NEXT: OpStore %i [[c1]]
+    i = (uint)from1;
+// CHECK-NEXT: [[from2:%\d+]] = OpLoad %bool %from2
+// CHECK-NEXT: [[c2:%\d+]] = OpSelect %uint [[from2]] %uint_1 %uint_0
+// CHECK-NEXT: OpStore %i [[c2]]
+    i = (uint)from2;
+// CHECK-NEXT: [[from3:%\d+]] = OpLoad %float %from3
+// CHECK-NEXT: [[c3:%\d+]] = OpConvertFToU %uint [[from3]]
+// CHECK-NEXT: OpStore %i [[c3]]
+    i = (uint)from3;
+
+    // C++ function style cast
+
+// CHECK-NEXT: OpStore %i %uint_0
+    i = uint(false);
+// CHECK-NEXT: OpStore %i %uint_3
+    i = uint(3.5);
+
+// CHECK-NEXT: OpStore %i %uint_5
+    i = uint(3.3 + 2.2);
+
+// CHECK-NEXT: [[from4:%\d+]] = OpLoad %int %from1
+// CHECK-NEXT: [[c4:%\d+]] = OpBitcast %uint [[from4]]
+// CHECK-NEXT: OpStore %i [[c4]]
+    i = uint(from1);
+// CHECK-NEXT: [[from5:%\d+]] = OpLoad %bool %from2
+// CHECK-NEXT: [[c5:%\d+]] = OpSelect %uint [[from5]] %uint_1 %uint_0
+// CHECK-NEXT: OpStore %i [[c5]]
+    i = uint(from2);
+// CHECK-NEXT: [[from6:%\d+]] = OpLoad %float %from3
+// CHECK-NEXT: [[c6:%\d+]] = OpConvertFToU %uint [[from6]]
+// CHECK-NEXT: OpStore %i [[c6]]
+    i = uint(from3);
+
+    // Vector cases
+
+// CHECK-NEXT: OpStore %vi1 %uint_3
+    vi1 = (uint1)3.6;
+// CHECK-NEXT: [[vfrom1:%\d+]] = OpLoad %int %vfrom1
+// CHECK-NEXT: [[vc1:%\d+]] = OpBitcast %uint [[vfrom1]]
+// CHECK-NEXT: OpStore %vi1 [[vc1]]
+    vi1 = (uint1)vfrom1;
+// CHECK-NEXT: [[vfrom2:%\d+]] = OpLoad %v2bool %vfrom2
+// CHECK-NEXT: [[vc2:%\d+]] = OpSelect %v2uint [[vfrom2]] [[v2uint_1_1]] [[v2uint_0_0]]
+// CHECK-NEXT: OpStore %vi2 [[vc2]]
+    vi2 = (uint2)vfrom2;
+// CHECK-NEXT: [[vfrom3:%\d+]] = OpLoad %v3float %vfrom3
+// CHECK-NEXT: [[vc3:%\d+]] = OpConvertFToU %v3uint [[vfrom3]]
+// CHECK-NEXT: OpStore %vi3 [[vc3]]
+    vi3 = (uint3)vfrom3;
+
+// CHECK-NEXT: OpStore %vi1 %uint_3
+    vi1 = uint1(3.5);
+// CHECK-NEXT: OpStore %vi2 [[v2uint_2_3]]
+    vi2 = uint2(1.1 + 1.2, 3);
+// CHECK-NEXT: [[vfrom4:%\d+]] = OpLoad %int %vfrom1
+// CHECK-NEXT: [[vc4:%\d+]] = OpBitcast %uint [[vfrom4]]
+// CHECK-NEXT: OpStore %vi1 [[vc4]]
+    vi1 = uint1(vfrom1);
+// CHECK-NEXT: [[vfrom5:%\d+]] = OpLoad %v2bool %vfrom2
+// CHECK-NEXT: [[vc5:%\d+]] = OpSelect %v2uint [[vfrom5]] [[v2uint_1_1]] [[v2uint_0_0]]
+// CHECK-NEXT: OpStore %vi2 [[vc5]]
+    vi2 = uint2(vfrom2);
+// CHECK-NEXT: [[vfrom6:%\d+]] = OpLoad %v3float %vfrom3
+// CHECK-NEXT: [[vc6:%\d+]] = OpConvertFToU %v3uint [[vfrom6]]
+// CHECK-NEXT: OpStore %vi3 [[vc6]]
+    vi3 = uint3(vfrom3);
+}
+

+ 64 - 0
tools/clang/test/CodeGenSPIRV/cast.2uint.implicit.hlsl

@@ -0,0 +1,64 @@
+// Run: %dxc -T ps_6_0 -E main
+
+// CHECK: [[v2uint_1_0:%\d+]] = OpConstantComposite %v2uint %uint_1 %uint_0
+// CHECK: [[v3uint_0_2_3:%\d+]] = OpConstantComposite %v3uint %uint_0 %uint_2 %uint_3
+
+void main() {
+// CHECK-LABEL: %bb_entry = OpLabel
+    uint i;
+    bool from1;
+    int from2;
+    float from3;
+
+    uint1 vi1;
+    uint2 vi2;
+    uint3 vi3;
+    bool1 vfrom1;
+    int2 vfrom2;
+    float3 vfrom3;
+// CHECK: %vic2 = OpVariable %_ptr_Function_v2uint Function [[v2uint_1_0]]
+// CHECK: %vic3 = OpVariable %_ptr_Function_v3uint Function [[v3uint_0_2_3]]
+
+    // From constant (implicit)
+// CHECK: OpStore %i %uint_1
+    i = true;
+// CHECK-NEXT: OpStore %i %uint_0
+    i = 0.0;
+
+    // From constant expr
+// CHECK-NEXT: OpStore %i %uint_3
+    i = 4.3 - 1.1;
+
+    // From variable (implicit)
+// CHECK-NEXT: [[from1:%\d+]] = OpLoad %bool %from1
+// CHECK-NEXT: [[c1:%\d+]] = OpSelect %uint [[from1]] %uint_1 %uint_0
+// CHECK-NEXT: OpStore %i [[c1]]
+    i = from1;
+// CHECK-NEXT: [[from2:%\d+]] = OpLoad %int %from2
+// CHECK-NEXT: [[c2:%\d+]] = OpBitcast %uint [[from2]]
+// CHECK-NEXT: OpStore %i [[c2]]
+    i = from2;
+// CHECK-NEXT: [[from3:%\d+]] = OpLoad %float %from3
+// CHECK-NEXT: [[c3:%\d+]] = OpConvertFToU %uint [[from3]]
+// CHECK-NEXT: OpStore %i [[c3]]
+    i = from3;
+
+    // Vector cases
+
+    // See the beginning for generated code
+    uint2 vic2 = {true, false};
+    uint3 vic3 = {false, 1.1 + 1.2, 3}; // Mixed
+
+// CHECK-NEXT: [[vfrom1:%\d+]] = OpLoad %bool %vfrom1
+// CHECK-NEXT: [[vc1:%\d+]] = OpSelect %uint [[vfrom1]] %uint_1 %uint_0
+// CHECK-NEXT: OpStore %vi1 [[vc1]]
+    vi1 = vfrom1;
+// CHECK-NEXT: [[vfrom2:%\d+]] = OpLoad %v2int %vfrom2
+// CHECK-NEXT: [[vc2:%\d+]] = OpBitcast %v2uint [[vfrom2]]
+// CHECK-NEXT: OpStore %vi2 [[vc2]]
+    vi2 = vfrom2;
+// CHECK-NEXT: [[vfrom3:%\d+]] = OpLoad %v3float %vfrom3
+// CHECK-NEXT: [[vc3:%\d+]] = OpConvertFToU %v3uint [[vfrom3]]
+// CHECK-NEXT: OpStore %vi3 [[vc3]]
+    vi3 = vfrom3;
+}

+ 19 - 0
tools/clang/test/CodeGenSPIRV/cast.no-op.hlsl

@@ -0,0 +1,19 @@
+// Run: %dxc -T ps_6_0 -E main
+
+void main() {
+// CHECK-LABEL: %bb_entry = OpLabel
+    int a, b;
+// CHECK: [[a0:%\d+]] = OpLoad %int %a
+// CHECK-NEXT: OpStore %b [[a0]]
+    b = int(a);
+
+    uint1 c, d;
+// CHECK-NEXT: [[c0:%\d+]] = OpLoad %uint %c
+// CHECK-NEXT: OpStore %d [[c0]]
+    d = uint1(c);
+
+    float2 e, f;
+// CHECK-NEXT: [[e0:%\d+]] = OpLoad %v2float %e
+// CHECK-NEXT: OpStore %f [[e0]]
+    f = float2(e);
+}

+ 13 - 0
tools/clang/test/CodeGenSPIRV/var.init.hlsl

@@ -5,7 +5,10 @@
 // CHECK-DAG: %float_2 = OpConstant %float 2
 // CHECK-DAG: %float_3 = OpConstant %float 3
 // CHECK-DAG: %float_4 = OpConstant %float 4
+// CHECK-DAG: %int_1 = OpConstant %int 1
+// CHECK-DAG: %int_2 = OpConstant %int 2
 // CHECK-DAG: [[float4constant:%\d+]] = OpConstantComposite %v4float %float_1 %float_2 %float_3 %float_4
+// CHECK-DAG: [[int2constant:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
 
 // Stage IO variables
 // CHECK-DAG: [[component:%\d+]] = OpVariable %_ptr_Input_float Input
@@ -23,6 +26,9 @@ float4 main(float component: COLOR) : SV_TARGET {
 // CHECK-NEXT: %n = OpVariable %_ptr_Function_v4float Function
 // CHECK-NEXT: %o = OpVariable %_ptr_Function_v4float Function
 
+// CHECK-NEXT: %p = OpVariable %_ptr_Function_v2int Function [[int2constant]]
+// CHECK-NEXT: %q = OpVariable %_ptr_Function_v3int Function
+
 // CHECK-NEXT: %x = OpVariable %_ptr_Function_uint Function
 
 // Initializer already attached to the var definition
@@ -52,6 +58,13 @@ float4 main(float component: COLOR) : SV_TARGET {
 // CHECK-NEXT: OpStore %o [[oinit]]
     float4 o = float4(1.0, j, 3.0, j);      // Mixed case
 
+    int2 p = {1, 2}; // All components are constants
+// CHECK-NEXT: [[b1:%\d+]] = OpLoad %int %b
+// CHECK-NEXT: [[a1:%\d+]] = OpLoad %int %a
+// CHECK-NEXT: [[qinit:%\d+]] = OpCompositeConstruct %v3int %int_4 [[b1]] [[a1]]
+// CHECK-NEXT: OpStore %q [[qinit]]
+    int3 q = {4, b, a}; // Mixed cases
+
 // CHECK-NEXT: OpStore %x %uint_1
     uint1 x = uint1(1); // Special case: vector of size 1
 

+ 12 - 1
tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp

@@ -43,7 +43,7 @@ TEST_F(FileTest, ScalarConstants) { runFileTest("constant.scalar.hlsl"); }
 TEST_F(FileTest, VectorConstants) { runFileTest("constant.vector.hlsl"); }
 
 // For variables
-TEST_F(FileTest, VariableInitialier) { runFileTest("var.init.hlsl"); }
+TEST_F(FileTest, VariableInitializer) { runFileTest("var.init.hlsl"); }
 
 // For prefix/postfix increment/decrement
 TEST_F(FileTest, UnaryOpPrefixIncrement) {
@@ -137,6 +137,17 @@ TEST_F(FileTest, TernaryOpConditionalOp) {
   runFileTest("ternary-op.cond-op.hlsl");
 }
 
+// For casting
+TEST_F(FileTest, CastNoOp) { runFileTest("cast.no-op.hlsl"); }
+TEST_F(FileTest, CastImplicit2Bool) { runFileTest("cast.2bool.implicit.hlsl"); }
+TEST_F(FileTest, CastExplicit2Bool) { runFileTest("cast.2bool.explicit.hlsl"); }
+TEST_F(FileTest, CastImplicit2SInt) { runFileTest("cast.2sint.implicit.hlsl"); }
+TEST_F(FileTest, CastExplicit2SInt) { runFileTest("cast.2sint.explicit.hlsl"); }
+TEST_F(FileTest, CastImplicit2UInt) { runFileTest("cast.2uint.implicit.hlsl"); }
+TEST_F(FileTest, CastExplicit2UInt) { runFileTest("cast.2uint.explicit.hlsl"); }
+TEST_F(FileTest, CastImplicit2FP) { runFileTest("cast.2fp.implicit.hlsl"); }
+TEST_F(FileTest, CastExplicit2FP) { runFileTest("cast.2fp.explicit.hlsl"); }
+
 // For if statements
 TEST_F(FileTest, IfStmtPlainAssign) { runFileTest("if-stmt.plain.hlsl"); }
 TEST_F(FileTest, IfStmtNestedIfStmt) { runFileTest("if-stmt.nested.hlsl"); }