Browse Source

De-duplicate numerical conversions code (#1885)

Lots of different code in CGHLSLMS.cpp did numerical conversions in slightly different ways, most of them forgetting to take into account bools. This change introduces a single ConvertScalarOrVector function which handles both and updates code to use it. This implied a partial rewrite of const init list handling code because they lost the QualType information necessary to properly cast. They were also not handling register/memory representations properly so that got fixed it at the same time.
Tristan Labelle 6 years ago
parent
commit
a7ee78049e

+ 4 - 2
include/dxc/HLSL/HLModule.h

@@ -196,8 +196,9 @@ public:
                                           llvm::ArrayRef<llvm::Value *> paramList,
                                           llvm::Module &M);
 
-  static unsigned FindCastOp(bool fromUnsigned, bool toUnsigned,
-                             llvm::Type *SrcTy, llvm::Type *DstTy);
+  // Caller must handle conversions to bool and no-ops
+  static unsigned GetNumericCastOp(
+    llvm::Type *SrcTy, bool SrcIsUnsigned, llvm::Type *DstTy, bool DstIsUnsigned);
 
   // Precise attribute.
   // Note: Precise will be marked on alloca inst with metadata in code gen.
@@ -319,3 +320,4 @@ public:
 };
 
 } // namespace hlsl
+

+ 15 - 15
lib/HLSL/HLMatrixLowerPass.cpp

@@ -397,29 +397,29 @@ INITIALIZE_PASS(HLMatrixLowerPass, "hlmatrixlower", "HLSL High-Level Matrix Lowe
 
 static Instruction *CreateTypeCast(HLCastOpcode castOp, Type *toTy, Value *src,
                                    IRBuilder<> Builder) {
-  // Cast to bool.
-  if (toTy->getScalarType()->isIntegerTy(1)) {
-    Type *fromTy = src->getType();
-    Constant *zero = llvm::Constant::getNullValue(src->getType());
-    bool isFloat = fromTy->getScalarType()->isFloatingPointTy();
-    if (isFloat)
-      return cast<Instruction>(Builder.CreateFCmpONE(src, zero));
-    else
-      return cast<Instruction>(Builder.CreateICmpNE(src, zero));
-  }
+  Type *srcTy = src->getType();
 
-  Type *eltToTy = toTy->getScalarType();
-  Type *eltFromTy = src->getType()->getScalarType();
+  // Conversions between equivalent types are no-ops,
+  // even between signed/unsigned variants.
+  if (srcTy == toTy) return cast<Instruction>(src);
 
   bool fromUnsigned = castOp == HLCastOpcode::FromUnsignedCast ||
                       castOp == HLCastOpcode::UnsignedUnsignedCast;
   bool toUnsigned = castOp == HLCastOpcode::ToUnsignedCast ||
                     castOp == HLCastOpcode::UnsignedUnsignedCast;
 
-  Instruction::CastOps castOps = static_cast<Instruction::CastOps>(
-      HLModule::FindCastOp(fromUnsigned, toUnsigned, eltFromTy, eltToTy));
+  // Conversions to bools are comparisons
+  if (toTy->getScalarSizeInBits() == 1) {
+    // fcmp une is what regular clang uses in C++ for (bool)f;
+    return cast<Instruction>(srcTy->isIntOrIntVectorTy()
+      ? Builder.CreateICmpNE(src, llvm::Constant::getNullValue(srcTy), "tobool")
+      : Builder.CreateFCmpUNE(src, llvm::Constant::getNullValue(srcTy), "tobool"));
+  }
 
-  return cast<Instruction>(Builder.CreateCast(castOps, src, toTy));
+  // Cast necessary
+  auto CastOp = static_cast<Instruction::CastOps>(HLModule::GetNumericCastOp(
+    srcTy, fromUnsigned, toTy, toUnsigned));
+  return cast<Instruction>(Builder.CreateCast(CastOp, src, toTy));
 }
 
 Instruction *HLMatrixLowerPass::MatCastToVec(CallInst *CI) {

+ 37 - 48
lib/HLSL/HLModule.cpp

@@ -957,6 +957,13 @@ void HLModule::MergeGepUse(Value *V) {
   }
 }
 
+template
+CallInst *HLModule::EmitHLOperationCall(IRBuilder<> &Builder,
+                                           HLOpcodeGroup group, unsigned opcode,
+                                           Type *RetType,
+                                           ArrayRef<Value *> paramList,
+                                           llvm::Module &M);
+
 template<typename BuilderTy>
 CallInst *HLModule::EmitHLOperationCall(BuilderTy &Builder,
                                            HLOpcodeGroup group, unsigned opcode,
@@ -984,58 +991,40 @@ CallInst *HLModule::EmitHLOperationCall(BuilderTy &Builder,
   return Builder.CreateCall(opFunc, opcodeParamList);
 }
 
-template
-CallInst *HLModule::EmitHLOperationCall(IRBuilder<> &Builder,
-                                           HLOpcodeGroup group, unsigned opcode,
-                                           Type *RetType,
-                                           ArrayRef<Value *> paramList,
-                                           llvm::Module &M);
-
-unsigned HLModule::FindCastOp(bool fromUnsigned, bool toUnsigned,
-                              llvm::Type *SrcTy, llvm::Type *DstTy) {
-  Instruction::CastOps castOp = llvm::Instruction::CastOps::BitCast;
-
-  if (SrcTy->isAggregateType() || DstTy->isAggregateType())
-    return llvm::Instruction::CastOps::BitCast;
-
+unsigned HLModule::GetNumericCastOp(
+  llvm::Type *SrcTy, bool SrcIsUnsigned, llvm::Type *DstTy, bool DstIsUnsigned) {
+  DXASSERT(SrcTy != DstTy, "No-op conversions are not casts and should have been handled by the callee.");
   uint32_t SrcBitSize = SrcTy->getScalarSizeInBits();
   uint32_t DstBitSize = DstTy->getScalarSizeInBits();
-  if (SrcTy->isIntOrIntVectorTy() && DstTy->isIntOrIntVectorTy()) {
-    if (SrcBitSize > DstBitSize)
-      return Instruction::Trunc;
-    // unsigned to unsigned: zext
-    // unsigned to signed: zext (fully representable)
-    // signed to signed: sext
-    // signed to unsigned: sext (like C++)
-    if (fromUnsigned)
-      return Instruction::ZExt;
-    else
-      return Instruction::SExt;
-  }
-
-  if (SrcTy->isFPOrFPVectorTy() && DstTy->isFPOrFPVectorTy()) {
-    if (SrcBitSize > DstBitSize)
-      return Instruction::FPTrunc;
-    else
-      return Instruction::FPExt;
-  }
-
-  if (SrcTy->isIntOrIntVectorTy() && DstTy->isFPOrFPVectorTy()) {
-    if (fromUnsigned)
-      return Instruction::UIToFP;
-    else
-      return Instruction::SIToFP;
+  bool SrcIsInt = SrcTy->isIntOrIntVectorTy();
+  bool DstIsInt = DstTy->isIntOrIntVectorTy();
+
+  DXASSERT(DstBitSize != 1, "Conversions to bool are not a cast and should have been handled by the callee.");
+
+  // Conversions from bools are like unsigned integer widening
+  if (SrcBitSize == 1) SrcIsUnsigned = true;
+
+  if (SrcIsInt) {
+    if (DstIsInt) { // int to int
+      if (SrcBitSize > DstBitSize) return Instruction::Trunc;
+      // unsigned to unsigned: zext
+      // unsigned to signed: zext (fully representable)
+      // signed to signed: sext
+      // signed to unsigned: sext (like C++)
+      return SrcIsUnsigned ? Instruction::ZExt : Instruction::SExt;
+    }
+    else { // int to float
+      return SrcIsUnsigned ? Instruction::UIToFP : Instruction::SIToFP;
+    }
   }
-
-  if (SrcTy->isFPOrFPVectorTy() && DstTy->isIntOrIntVectorTy()) {
-    if (toUnsigned)
-      return Instruction::FPToUI;
-    else
-      return Instruction::FPToSI;
+  else {
+    if (DstIsInt) { // float to int
+      return DstIsUnsigned ? Instruction::FPToUI : Instruction::FPToSI;
+    }
+    else { // float to float
+      return SrcBitSize > DstBitSize ? Instruction::FPTrunc : Instruction::FPExt;
+    }
   }
-
-  DXASSERT_NOMSG(0);
-  return castOp;
 }
 
 bool HLModule::HasPreciseAttributeWithMetadata(Instruction *I) {

+ 2 - 0
tools/clang/include/clang/AST/HlslTypes.h

@@ -372,6 +372,8 @@ bool IsHLSLVecType(clang::QualType type);
 bool IsHLSLMatType(clang::QualType type);
 clang::QualType GetElementTypeOrType(clang::QualType type);
 bool HasHLSLMatOrientation(clang::QualType type, bool *pIsRowMajor = nullptr);
+bool IsHLSLMatRowMajor(clang::QualType type, bool defaultValue);
+bool IsHLSLUnsigned(clang::QualType type);
 bool HasHLSLUNormSNorm(clang::QualType type, bool *pIsSNorm = nullptr);
 bool IsHLSLInputPatchType(clang::QualType type);
 bool IsHLSLOutputPatchType(clang::QualType type);

+ 20 - 0
tools/clang/lib/AST/HlslTypes.cpp

@@ -169,6 +169,26 @@ bool HasHLSLMatOrientation(clang::QualType type, bool *pIsRowMajor) {
   return false;
 }
 
+bool IsHLSLMatRowMajor(clang::QualType type, bool defaultValue) {
+  bool result = defaultValue;
+  HasHLSLMatOrientation(type, &result);
+  return result;
+}
+
+bool IsHLSLUnsigned(clang::QualType type) {
+  if (type->getAs<clang::BuiltinType>() == nullptr) {
+    type = type.getCanonicalType().getNonReferenceType();
+
+    if (IsHLSLVecMatType(type))
+      type = GetElementTypeOrType(type);
+
+    if (type->isExtVectorType())
+      type = type->getAs<clang::ExtVectorType>()->getElementType();
+  }
+
+  return type->isUnsignedIntegerType();
+}
+
 bool HasHLSLUNormSNorm(clang::QualType type, bool *pIsSNorm) {
   // snorm/unorm can be on outer vector/matrix as well as element type
   // in the template form.  Outer-most type attribute wins.

+ 2 - 7
tools/clang/lib/CodeGen/CGExpr.cpp

@@ -1244,11 +1244,7 @@ llvm::Value *CodeGenFunction::EmitToMemory(llvm::Value *Value, QualType Ty) {
   // HLSL Change Begin.
   // Bool scalar and vectors have a different representation in memory than in registers.
   if (hasBooleanScalarOrVectorRepresentation(Ty)) {
-    // This should really always be an i1, but sometimes it's already
-    // an i8, and it's awkward to track those cases down.
-    llvm::Type *ValTy = Value->getType();
-    llvm::Type *VecElemTy = ValTy->isVectorTy() ? ValTy->getVectorElementType() : ValTy;
-    if (VecElemTy->isIntegerTy(1))
+    if (Value->getType()->getScalarType()->isIntegerTy(1))
       return Builder.CreateZExt(Value, ConvertTypeForMem(Ty), "frombool");
   }
   // HLSL Change End.
@@ -1260,10 +1256,9 @@ llvm::Value *CodeGenFunction::EmitFromMemory(llvm::Value *Value, QualType Ty) {
   // HLSL Change Begin.
   // Bool scalar and vectors have a different representation in memory than in registers.
   if (hasBooleanScalarOrVectorRepresentation(Ty)) {
-    llvm::Type *ValTy = Value->getType();
     // Use ne v, 0 to convert to i1 instead of trunc.
     return Builder.CreateICmpNE(
-        Value, llvm::ConstantVector::getNullValue(ValTy), "tobool");
+        Value, llvm::ConstantVector::getNullValue(Value->getType()), "tobool");
   }
   // HLSL Change End.
 

+ 3 - 3
tools/clang/lib/CodeGen/CGExprConstant.cpp

@@ -1232,7 +1232,7 @@ llvm::Constant *CodeGenModule::EmitConstantInit(const VarDecl &D,
   assert(E && "No initializer to emit");
 
   llvm::Constant* C = ConstExprEmitter(*this, CGF).Visit(const_cast<Expr*>(E));
-  if (C && C->getType()->isIntegerTy(1)) {
+  if (C && C->getType()->getScalarType()->isIntegerTy(1)) { // HLSL Change
     llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType());
     C = llvm::ConstantExpr::getZExt(C, BoolTy);
   }
@@ -1257,7 +1257,7 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
   else
     C = ConstExprEmitter(*this, CGF).Visit(const_cast<Expr*>(E));
 
-  if (C && C->getType()->isIntegerTy(1)) {
+  if (C && C->getType()->getScalarType()->isIntegerTy(1)) { // HLSL Change
     llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType());
     C = llvm::ConstantExpr::getZExt(C, BoolTy);
   }
@@ -1472,7 +1472,7 @@ CodeGenModule::EmitConstantValueForMemory(const APValue &Value,
                                           QualType DestType,
                                           CodeGenFunction *CGF) {
   llvm::Constant *C = EmitConstantValue(Value, DestType, CGF);
-  if (C->getType()->isIntegerTy(1)) {
+  if (C->getType()->getScalarType()->isIntegerTy(1)) { // HLSL Change
     llvm::Type *BoolTy = getTypes().ConvertTypeForMem(DestType);
     C = llvm::ConstantExpr::getZExt(C, BoolTy);
   }

File diff suppressed because it is too large
+ 348 - 357
tools/clang/lib/CodeGen/CGHLSLMS.cpp


+ 0 - 20
tools/clang/lib/CodeGen/CGHLSLRuntime.cpp

@@ -21,23 +21,3 @@ using namespace clang;
 using namespace CodeGen;
 
 CGHLSLRuntime::~CGHLSLRuntime() {}
-
-bool CGHLSLRuntime::IsHLSLVecMatType(clang::QualType &type) {
-  return hlsl::IsHLSLVecMatType(type);
-}
-
-const clang::ExtVectorType *CGHLSLRuntime::ConvertHLSLVecMatTypeToExtVectorType(
-    const clang::ASTContext &context, clang::QualType &type) {
-  return hlsl::ConvertHLSLVecMatTypeToExtVectorType(context, type);
-}
-
-QualType CGHLSLRuntime::GetHLSLVecMatElementType(QualType type) {
-  const Type *Ty = type.getCanonicalType().getTypePtr();
-  // TODO: check isVecMatrix
-  const RecordType *RT = cast<RecordType>(Ty);
-  const ClassTemplateSpecializationDecl *templateDecl =
-            cast<ClassTemplateSpecializationDecl>(RT->getDecl());
-  const TemplateArgumentList &argList = templateDecl->getTemplateArgs();
-  const TemplateArgument &arg0 = argList[0];
-  return arg0.getAsType();
-}

+ 0 - 5
tools/clang/lib/CodeGen/CGHLSLRuntime.h

@@ -122,11 +122,6 @@ public:
   virtual void AddControlFlowHint(CodeGenFunction &CGF, const Stmt &S, llvm::TerminatorInst *TI, llvm::ArrayRef<const Attr *> Attrs) = 0;
 
   virtual void FinishAutoVar(CodeGenFunction &CGF, const VarDecl &D, llvm::Value *V) = 0;
-  static const clang::ExtVectorType *
-  ConvertHLSLVecMatTypeToExtVectorType(const clang::ASTContext &context,
-                                       clang::QualType &type);
-  static bool IsHLSLVecMatType(clang::QualType &type);
-  static clang::QualType GetHLSLVecMatElementType(clang::QualType type);
 };
 
 /// Create an instance of a HLSL runtime class.

+ 40 - 0
tools/clang/test/CodeGenHLSL/declarations/bool_representation/const_init_list_no_crash.hlsl

@@ -0,0 +1,40 @@
+// RUN: %dxc -E main -T vs_6_0 %s | FileCheck %s
+
+// Regression test for bools in constant initialization lists crashing
+// due to a mismatch between register and memory representations (GitHub #1880)
+
+// CHECK: ret void
+
+bool main() : OUT
+{
+    // There are special cases around structs, arrays and matrices,
+    // so it's important to test all combinations:
+    // scalars/vectors can be in memory representation or not
+    // matrices always store elements in register representation (until lowering to vector)
+    // arrays/structs always store elements in memory representation.
+
+    // Test target types
+    static const bool b = { false };
+    static const bool2 v = { false, true };
+    static const bool2x2 m = { false, true, false, true };
+    static const bool ab[] = { false };
+    static const bool2 av[] = { false, true };
+    static const bool2x2 am[] = { false, true, false, true };
+    static const struct { bool x; } sb = { false };
+    static const struct { bool2 x; } sv = { false, true };
+    static const struct { bool2x2 x; } sm = { false, true, false, true };
+
+    // Test source types
+    static const bool ab_b[] = { false, b };
+    static const bool ab_v[] = { bool2(false, true), v };
+    static const bool ab_m[] = { bool2x2(false, true, false, true), m };
+    static const bool ab_a[] = { ab, av, am };
+    static const bool ab_s[] = { sb, sv, sm };
+
+    // Reference everything to ensure they get codegen'd
+    // Bool matrix accesses crash due to GitHub #1881
+    return b && v.x /* && m._11 */
+        && ab[0] && av[0].x /* && am[0]._11 */
+        && sb.x && sv.x /* && sm.x._11 */
+        && ab_b[0] && ab_v[0] && ab_m[0] && ab_a[0] && ab_s[0];
+}

+ 37 - 0
tools/clang/test/CodeGenHLSL/declarations/matrix_pack/static_const_init_list.hlsl

@@ -0,0 +1,37 @@
+// RUN: %dxc /T vs_6_0 /E main %s | FileCheck %s
+
+// Test that matrix packing order does not cause undesirable transposes
+// with constant initialization lists. Constant initializers should
+// be emitted in the target memory packing order and "fixed up"
+// when the static variable gets loaded.
+
+AppendStructuredBuffer<int4> buf;
+
+void main()
+{
+    // Test building matrix constants
+    // Matrices need to be hidden in structures because
+    // otherwise we do not consider them for constant initialization.
+    static const struct { row_major int2x2 mat; } r = { 11, 12, 21, 22 };
+    static const struct { column_major int2x2 mat; } c = { 11, 12, 21, 22 };
+    
+    // CHECK: i32 11, i32 12, i32 21, i32 22, i8 15)
+    // CHECK: i32 11, i32 12, i32 21, i32 22, i8 15)
+    buf.Append((int4)r.mat);
+    buf.Append((int4)c.mat);
+
+    // Convert between packing orders (ie test flattening matrix constants).
+    // Use two fields per variable so that constant init list logic is used.
+    // If there is a single initializer, it becomes a mere cast. 
+    static const struct { row_major int2x2 mat1, mat2; } r2 = { r, c };
+    static const struct { column_major int2x2 mat1, mat2; } c2 = { r, c };
+
+    // CHECK: i32 11, i32 12, i32 21, i32 22, i8 15)
+    // CHECK: i32 11, i32 12, i32 21, i32 22, i8 15)
+    // CHECK: i32 11, i32 12, i32 21, i32 22, i8 15)
+    // CHECK: i32 11, i32 12, i32 21, i32 22, i8 15)
+    buf.Append((int4)r2.mat1);
+    buf.Append((int4)r2.mat2);
+    buf.Append((int4)c2.mat1);
+    buf.Append((int4)c2.mat2);
+}

+ 87 - 0
tools/clang/test/CodeGenHLSL/expressions/conversions_and_casts/numerical_const_init_list.hlsl

@@ -0,0 +1,87 @@
+// RUN: %dxc -E main -T vs_6_2 -enable-16bit-types %s | FileCheck %s
+
+// Tests conversion between numerical types which happen as of
+// constant initialization lists, since they use a different code path.
+
+RWStructuredBuffer<bool4> buf_b;
+RWStructuredBuffer<int4> buf_i;
+RWStructuredBuffer<uint4> buf_u;
+RWStructuredBuffer<float4> buf_f;
+
+void main() {
+    // To bool
+    // CHECK: i32 1, i32 1, i32 1, i32 1, i8
+    // CHECK: i32 1, i32 1, i32 1, i32 1, i8
+    // CHECK: i32 1, i32 1, i32 0, i32 0, i8
+    static const bool b[] = {
+        true, // No-op
+        (int)(-1), // icmp ne 0
+        (uint)0xFFFFFFFF, // icmp ne 0
+        (int16_t)(-1), // icmp ne 0
+        (uint16_t)0xFFFF, // icmp ne 0
+        (int64_t)(-1), // icmp ne 0
+        (uint64_t)0xFFFFFFFFFFFFFFFF, // icmp ne 0
+        (half)(-1.5f), // fcmp ne 0
+        -1.5f, // fcmp ne 0
+        (double)(-1.5f) }; // fcmp ne 0
+    buf_b[0] = bool4(b[0], b[1], b[2], b[3]);
+    buf_b[1] = bool4(b[4], b[5], b[6], b[7]);
+    buf_b[2] = bool4(b[8], b[9], false, false);
+
+    // To signed int
+    // CHECK: i32 1, i32 -1, i32 -1, i32 -1, i8
+    // CHECK: i32 65535, i32 -1, i32 -1, i32 -1, i8
+    // CHECK: i32 -1, i32 -1, i32 0, i32 0, i8
+    static const int i[] = {
+        true, // ZExt
+        (int)(-1), // No-op
+        (uint)0xFFFFFFFF, // No-op (reinterpret)
+        (int16_t)(-1), // SExt
+        (uint16_t)0xFFFF, // ZExt
+        (int64_t)(-1), // Trunc
+        (uint64_t)0xFFFFFFFFFFFFFFFF, // Trunc
+        (half)(-1.5f), // FPToSI
+        -1.5f, // FPToSI
+        (double)(-1.5f) }; // FPToSI
+    buf_i[0] = int4(i[0], i[1], i[2], i[3]);
+    buf_i[1] = int4(i[4], i[5], i[6], i[7]);
+    buf_i[2] = int4(i[8], i[9], 0, 0);
+    
+    // To unsigned int
+    // CHECK: i32 1, i32 -1, i32 -1, i32 -1, i8
+    // CHECK: i32 65535, i32 -1, i32 -1, i32 0, i8
+    // CHECK: i32 0, i32 0, i32 0, i32 0, i8
+    static const uint u[] = {
+        true, // ZExt
+        (int)(-1), // No-op (reinterpret)
+        (uint)0xFFFFFFFF, // No-op
+        (int16_t)(-1), // SExt
+        (uint16_t)0xFFFF, // ZExt
+        (int64_t)(-1), // Trunc
+        (uint64_t)0xFFFFFFFFFFFFFFFF, // Trunc
+        (half)(-1.5f), // FPToUI
+        -1.5f, // FPToUI
+        (double)(-1.5f) }; // FPToUI
+    buf_u[0] = uint4(u[0], u[1], u[2], u[3]);
+    buf_u[1] = uint4(u[4], u[5], u[6], u[7]);
+    buf_u[2] = uint4(u[8], u[9], 0, 0);
+    
+    // To float
+    // CHECK: float 1.000000e+00, float -1.000000e+00, float 0x41F0000000000000, float -1.000000e+00, i8
+    // CHECK: float 6.553500e+04, float -1.000000e+00, float 0x41F0000000000000, float -1.500000e+00, i8
+    // CHECK: float -1.500000e+00, float -1.500000e+00, float 0.000000e+00, float 0.000000e+00, i8
+    static const float f[] = {
+        true, // UIToFP
+        (int)(-1), // SIToFP
+        (uint)0xFFFFFFFF, // UIToFP
+        (int16_t)(-1), // SIToFP
+        (uint16_t)0xFFFF, // UIToFP
+        (int64_t)(-1), // SIToFP
+        (uint64_t)0xFFFFFFFFFFFFFFFF, // UIToFP
+        (half)(-1.5f), // FPExt
+        -1.5f, // No-op
+        (double)(-1.5f) }; // FPTrunc
+    buf_f[0] = float4(f[0], f[1], f[2], f[3]);
+    buf_f[1] = float4(f[4], f[5], f[6], f[7]);
+    buf_f[2] = float4(f[8], f[9], 0, 0);
+}

+ 103 - 0
tools/clang/test/CodeGenHLSL/expressions/conversions_and_casts/numerical_indirect.hlsl

@@ -0,0 +1,103 @@
+// RUN: %dxc -E main -T vs_6_2 -enable-16bit-types %s | FileCheck %s
+
+// Tests conversion between numerical types which happen as part
+// of a larger flat conversion between compound types.
+// Assume that struct-to-struct is representative of all
+// compound/numerical to compound/numerical flat casts.
+// Assume that conversions between 16 and 32-bit types
+// are representative of those between 16 and 64 or 32 and 64-bit types. 
+
+struct B { bool value; };
+struct I16 { int16_t value; };
+struct U16 { uint16_t value; };
+struct I32 { int value; };
+struct U32 { uint value; };
+struct F16 { half value; };
+struct F32 { float value; };
+
+RWStructuredBuffer<B> b;
+RWStructuredBuffer<I16> i16;
+RWStructuredBuffer<U16> u16;
+RWStructuredBuffer<I32> i32;
+RWStructuredBuffer<U32> u32;
+RWStructuredBuffer<F16> f16;
+RWStructuredBuffer<F32> f32;
+
+void main() {
+    int i = 0;
+    int j = 0;
+
+    // Integral casts
+    // CHECK-NOT: zext
+    // CHECK-NOT: sext
+    // CHECK-NOT: trunc
+    i32[i++] = (I32)u32[j++];
+    u32[i++] = (U32)i32[j++];
+
+    // CHECK: trunc
+    // CHECK: trunc
+    // CHECK: trunc
+    // CHECK: trunc
+    i16[i++] = (I16)i32[j++];
+    i16[i++] = (I16)u32[j++];
+    u16[i++] = (U16)i32[j++];
+    u16[i++] = (U16)u32[j++];
+    
+    // CHECK: sext
+    // CHECK: zext
+    // CHECK: sext
+    // CHECK: zext
+    i32[i++] = (I32)i16[j++];
+    i32[i++] = (I32)u16[j++];
+    u32[i++] = (U32)i16[j++];
+    u32[i++] = (U32)u16[j++];
+    
+    // Float casts
+    // CHECK: fpext
+    // CHECK: fptrunc
+    f32[i++] = (F32)f16[j++];
+    f16[i++] = (F16)f32[j++];
+    
+    // Integral/float casts
+    // CHECK: fptosi
+    // CHECK: fptoui
+    // CHECK: sitofp
+    // CHECK: uitofp
+    i32[i++] = (I32)f32[j++];
+    u32[i++] = (U32)f32[j++];
+    f32[i++] = (F32)i32[j++];
+    f32[i++] = (F32)u32[j++];
+
+    // CHECK: fptosi
+    // CHECK: fptoui
+    // CHECK: sitofp
+    // CHECK: uitofp
+    i16[i++] = (I16)f32[j++];
+    u16[i++] = (U16)f32[j++];
+    f16[i++] = (F16)i32[j++];
+    f16[i++] = (F16)u32[j++];
+    
+    // CHECK: fptosi
+    // CHECK: fptoui
+    // CHECK: sitofp
+    // CHECK: uitofp
+    i32[i++] = (I32)f16[j++];
+    u32[i++] = (U32)f16[j++];
+    f32[i++] = (F32)i16[j++];
+    f32[i++] = (F32)u16[j++];
+
+    // Casts to/from bool
+    // CHECK: icmp ne
+    // CHECK: icmp ne
+    // CHECK: fcmp fast une
+    b[i++] = (B)i32[j++];
+    b[i++] = (B)u32[j++];
+    b[i++] = (B)f32[j++];
+    
+    // CHECK: zext
+    // CHECK: zext
+    // CHECK: uitofp
+    i32[i++] = (I32)b[j++];
+    u32[i++] = (U32)b[j++];
+    f32[i++] = (F32)b[j++];
+}

+ 101 - 0
tools/clang/test/CodeGenHLSL/expressions/conversions_and_casts/numerical_matrices.hlsl

@@ -0,0 +1,101 @@
+// RUN: %dxc -E main -T vs_6_2 -enable-16bit-types %s | FileCheck %s
+
+// Tests conversions between numerical types in matrices.
+// This happens during matrix lowering so it needs its own testing.
+// Assume that conversions between 16 and 32-bit types
+// are representative of those between 16 and 64 or 32 and 64-bit types. 
+
+typedef bool1x1 B;
+typedef int16_t1x1 I16;
+typedef uint16_t1x1 U16;
+typedef int1x1 I32;
+typedef uint1x1 U32;
+typedef half1x1 F16;
+typedef float1x1 F32;
+
+RWStructuredBuffer<B> b;
+RWStructuredBuffer<I16> i16;
+RWStructuredBuffer<U16> u16;
+RWStructuredBuffer<I32> i32;
+RWStructuredBuffer<U32> u32;
+RWStructuredBuffer<F16> f16;
+RWStructuredBuffer<F32> f32;
+
+void main() {
+    int i = 0;
+    int j = 0;
+
+    // Integral casts
+    // CHECK-NOT: zext
+    // CHECK-NOT: sext
+    // CHECK-NOT: trunc
+    i32[i++] = (I32)u32[j++];
+    u32[i++] = (U32)i32[j++];
+
+    // CHECK: trunc
+    // CHECK: trunc
+    // CHECK: trunc
+    // CHECK: trunc
+    i16[i++] = (I16)i32[j++];
+    i16[i++] = (I16)u32[j++];
+    u16[i++] = (U16)i32[j++];
+    u16[i++] = (U16)u32[j++];
+    
+    // CHECK: sext
+    // CHECK: zext
+    // CHECK: sext
+    // CHECK: zext
+    i32[i++] = (I32)i16[j++];
+    i32[i++] = (I32)u16[j++];
+    u32[i++] = (U32)i16[j++];
+    u32[i++] = (U32)u16[j++];
+    
+    // Float casts
+    // CHECK: fpext
+    // CHECK: fptrunc
+    f32[i++] = (F32)f16[j++];
+    f16[i++] = (F16)f32[j++];
+    
+    // Integral/float casts
+    // CHECK: fptosi
+    // CHECK: fptoui
+    // CHECK: sitofp
+    // CHECK: uitofp
+    i32[i++] = (I32)f32[j++];
+    u32[i++] = (U32)f32[j++];
+    f32[i++] = (F32)i32[j++];
+    f32[i++] = (F32)u32[j++];
+
+    // CHECK: fptosi
+    // CHECK: fptoui
+    // CHECK: sitofp
+    // CHECK: uitofp
+    i16[i++] = (I16)f32[j++];
+    u16[i++] = (U16)f32[j++];
+    f16[i++] = (F16)i32[j++];
+    f16[i++] = (F16)u32[j++];
+    
+    // CHECK: fptosi
+    // CHECK: fptoui
+    // CHECK: sitofp
+    // CHECK: uitofp
+    i32[i++] = (I32)f16[j++];
+    u32[i++] = (U32)f16[j++];
+    f32[i++] = (F32)i16[j++];
+    f32[i++] = (F32)u16[j++];
+
+    // Casts to/from bool
+    // CHECK: icmp ne
+    // CHECK: icmp ne
+    // CHECK: fcmp fast une
+    b[i++] = (B)i32[j++];
+    b[i++] = (B)u32[j++];
+    b[i++] = (B)f32[j++];
+    
+    // CHECK: zext
+    // CHECK: zext
+    // CHECK: uitofp
+    i32[i++] = (I32)b[j++];
+    u32[i++] = (U32)b[j++];
+    f32[i++] = (F32)b[j++];
+}

+ 4 - 4
tools/clang/test/CodeGenHLSL/quick-test/bool_matrix_conversion.hlsl

@@ -4,10 +4,10 @@
 // CHECK: icmp ne i32 {{.*}}, 0
 // CHECK: icmp ne i32 {{.*}}, 0
 // CHECK: icmp ne i32 {{.*}}, 0
-// CHECK: fcmp fast one float {{.*}}, 0.000000e+00
-// CHECK: fcmp fast one float {{.*}}, 0.000000e+00
-// CHECK: fcmp fast one float {{.*}}, 0.000000e+00
-// CHECK: fcmp fast one float {{.*}}, 0.000000e+00
+// CHECK: fcmp fast une float {{.*}}, 0.000000e+00
+// CHECK: fcmp fast une float {{.*}}, 0.000000e+00
+// CHECK: fcmp fast une float {{.*}}, 0.000000e+00
+// CHECK: fcmp fast une float {{.*}}, 0.000000e+00
 
 struct Input
 {

Some files were not shown because too many files changed in this diff