Browse Source

[spirv] Cull RHS of shift operations (#1148)

In SPIR-V, if shifting a value by an amount that is greater than
the value's bitwidth, the result is undefined.

FXC and DXC/DXIL performs a bitwise and over the RHS of the shift
operation to only consider its (n - 1) least significant bits,
where n is the bitwidth of LHS.
Lei Zhang 7 years ago
parent
commit
cfd787a18e

+ 4 - 0
docs/SPIR-V.rst

@@ -1315,6 +1315,10 @@ corresponding SPIR-V opcodes according to the following table.
 | ``>>`` | ``OpShiftRightArithmetic``  | ``OpShiftRightLogical``       |
 +--------+-----------------------------+-------------------------------+
 
+Note that for ``<<``/``>>``, the right hand side will be culled: only the ``n``
+- 1 least significant bits are considered, where ``n`` is the bitwidth of the
+left hand side.
+
 Comparison operators
 --------------------
 

+ 49 - 5
tools/clang/lib/SPIRV/SPIRVEmitter.cpp

@@ -4854,6 +4854,16 @@ SpirvEvalInfo SPIRVEmitter::processBinaryOp(const Expr *lhs, const Expr *rhs,
                             : mandateGenOpcode;
 
   switch (opcode) {
+  case BO_Shl:
+  case BO_Shr:
+  case BO_ShlAssign:
+  case BO_ShrAssign:
+    // We need to cull the RHS to make sure that we are not shifting by an
+    // amount that is larger than the bitwidth of the LHS.
+    rhsVal.setResultId(theBuilder.createBinaryOp(
+        spv::Op::OpBitwiseAnd, typeTranslator.translateType(computationType),
+        rhsVal, getMaskForBitwidthValue(rhsType)));
+    // Fall through
   case BO_Add:
   case BO_Sub:
   case BO_Mul:
@@ -4868,8 +4878,6 @@ SpirvEvalInfo SPIRVEmitter::processBinaryOp(const Expr *lhs, const Expr *rhs,
   case BO_And:
   case BO_Or:
   case BO_Xor:
-  case BO_Shl:
-  case BO_Shr:
   case BO_LAnd:
   case BO_LOr:
   case BO_AddAssign:
@@ -4879,9 +4887,7 @@ SpirvEvalInfo SPIRVEmitter::processBinaryOp(const Expr *lhs, const Expr *rhs,
   case BO_RemAssign:
   case BO_AndAssign:
   case BO_OrAssign:
-  case BO_XorAssign:
-  case BO_ShlAssign:
-  case BO_ShrAssign: {
+  case BO_XorAssign: {
 
     // To evaluate this expression as an OpSpecConstantOp, we need to make sure
     // both operands are constant and at least one of them is a spec constant.
@@ -8363,6 +8369,44 @@ uint32_t SPIRVEmitter::getMatElemValueOne(QualType type) {
   return getVecValueOne(elemType, colCount);
 }
 
+uint32_t SPIRVEmitter::getMaskForBitwidthValue(QualType type) {
+  QualType elemType = {};
+  uint32_t count = 1;
+
+  if (TypeTranslator::isScalarType(type, &elemType) ||
+      TypeTranslator::isVectorType(type, &elemType, &count)) {
+    const auto bitwidth = typeTranslator.getElementSpirvBitwidth(elemType);
+    uint32_t mask = 0;
+    uint32_t elemTypeId = 0;
+    switch (bitwidth) {
+    case 16:
+      mask = theBuilder.getConstantUint16(bitwidth - 1);
+      elemTypeId = theBuilder.getUint16Type();
+      break;
+    case 32:
+      mask = theBuilder.getConstantUint32(bitwidth - 1);
+      elemTypeId = theBuilder.getUint32Type();
+      break;
+    case 64:
+      mask = theBuilder.getConstantUint64(bitwidth - 1);
+      elemTypeId = theBuilder.getUint64Type();
+      break;
+    default:
+      assert(false && "this method only supports 16-, 32-, and 64-bit types");
+    }
+
+    if (count == 1)
+      return mask;
+
+    const uint32_t typeId = theBuilder.getVecType(elemTypeId, count);
+    llvm::SmallVector<uint32_t, 4> elements(size_t(count), mask);
+    return theBuilder.getConstantComposite(typeId, elements);
+  }
+
+  assert(false && "this method only supports scalars and vectors");
+  return 0;
+}
+
 uint32_t SPIRVEmitter::translateAPValue(const APValue &value,
                                         const QualType targetType) {
   uint32_t result = 0;

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

@@ -490,6 +490,11 @@ private:
   /// one will be a vector of size N.
   uint32_t getMatElemValueOne(QualType type);
 
+  /// Returns a SPIR-V constant equal to the bitwdith of the given type minus
+  /// one. The returned constant has the same component count and bitwidth as
+  /// the given type.
+  uint32_t getMaskForBitwidthValue(QualType type);
+
 private:
   /// \brief Performs a FlatConversion implicit cast. Fills an instance of the
   /// given type with initializer <result-id>. The initializer is of type

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

@@ -402,10 +402,7 @@ uint32_t TypeTranslator::getElementSpirvBitwidth(QualType type) {
     case BuiltinType::Min12Int:
     case BuiltinType::Half:
     case BuiltinType::Min10Float: {
-      if (spirvOptions.enable16BitTypes)
-        return 16;
-      else
-        return 32;
+      return spirvOptions.enable16BitTypes ? 16 : 32;
     }
     case BuiltinType::LitFloat: {
       // First try to see if there are any hints about how this literal type
@@ -416,10 +413,7 @@ uint32_t TypeTranslator::getElementSpirvBitwidth(QualType type) {
 
       const auto &semantics = astContext.getFloatTypeSemantics(type);
       const auto bitwidth = llvm::APFloat::getSizeInBits(semantics);
-      if (bitwidth <= 32)
-        return 32;
-      else
-        return 64;
+      return bitwidth <= 32 ? 32 : 64;
     }
     case BuiltinType::LitInt: {
       // First try to see if there are any hints about how this literal type

+ 0 - 22
tools/clang/test/CodeGenSPIRV/binary-op.bitwise-assign.scalar.hlsl

@@ -37,26 +37,4 @@ void main() {
 // CHECK-NEXT: [[xor1:%\d+]] = OpBitwiseXor %uint [[j2]] [[i2]]
 // CHECK-NEXT: OpStore %j [[xor1]]
     j ^= i;
-
-// CHECK-NEXT: [[a3:%\d+]] = OpLoad %int %a
-// CHECK-NEXT: [[b3:%\d+]] = OpLoad %int %b
-// CHECK-NEXT: [[shl0:%\d+]] = OpShiftLeftLogical %int [[b3]] [[a3]]
-// CHECK-NEXT: OpStore %b [[shl0]]
-    b <<= a;
-// CHECK-NEXT: [[i3:%\d+]] = OpLoad %uint %i
-// CHECK-NEXT: [[j3:%\d+]] = OpLoad %uint %j
-// CHECK-NEXT: [[shl1:%\d+]] = OpShiftLeftLogical %uint [[j3]] [[i3]]
-// CHECK-NEXT: OpStore %j [[shl1]]
-    j <<= i;
-
-// CHECK-NEXT: [[a4:%\d+]] = OpLoad %int %a
-// CHECK-NEXT: [[b4:%\d+]] = OpLoad %int %b
-// CHECK-NEXT: [[shr0:%\d+]] = OpShiftRightArithmetic %int [[b4]] [[a4]]
-// CHECK-NEXT: OpStore %b [[shr0]]
-    b >>= a;
-// CHECK-NEXT: [[i4:%\d+]] = OpLoad %uint %i
-// CHECK-NEXT: [[j4:%\d+]] = OpLoad %uint %j
-// CHECK-NEXT: [[shr1:%\d+]] = OpShiftRightLogical %uint [[j4]] [[i4]]
-// CHECK-NEXT: OpStore %j [[shr1]]
-    j >>= i;
 }

+ 45 - 0
tools/clang/test/CodeGenSPIRV/binary-op.bitwise-assign.shift-left.hlsl

@@ -0,0 +1,45 @@
+// Run: %dxc -T ps_6_2 -E main -enable-16bit-types
+
+// CHECK: [[v2c31:%\d+]] = OpConstantComposite %v2uint %uint_31 %uint_31
+// CHECK: [[v3c63:%\d+]] = OpConstantComposite %v3ulong %ulong_63 %ulong_63 %ulong_63
+// CHECK: [[v4c15:%\d+]] = OpConstantComposite %v4ushort %ushort_15 %ushort_15 %ushort_15 %ushort_15
+void main() {
+    int       a, b;
+    uint2     d, e;
+
+    int64_t3  g, h;
+    uint64_t  j, k;
+
+    int16_t   m, n;
+    uint16_t4 p, q;
+
+// CHECK:        [[b:%\d+]] = OpLoad %int %b
+// CHECK:      [[rhs:%\d+]] = OpBitwiseAnd %int [[b]] %uint_31
+// CHECK-NEXT:                OpShiftLeftLogical %int {{%\d+}} [[rhs]]
+    a <<= b;
+
+// CHECK:        [[e:%\d+]] = OpLoad %v2uint %e
+// CHECK:      [[rhs:%\d+]] = OpBitwiseAnd %v2uint [[e]] [[v2c31]]
+// CHECK-NEXT:                OpShiftLeftLogical %v2uint {{%\d+}} [[rhs]]
+    d <<= e;
+
+// CHECK:        [[h:%\d+]] = OpLoad %v3long %h
+// CHECK:      [[rhs:%\d+]] = OpBitwiseAnd %v3long [[h]] [[v3c63]]
+// CHECK-NEXT:                OpShiftLeftLogical %v3long {{%\d+}} [[rhs]]
+    g <<= h;
+
+// CHECK:        [[k:%\d+]] = OpLoad %ulong %k
+// CHECK:      [[rhs:%\d+]] = OpBitwiseAnd %ulong [[k]] %ulong_63
+// CHECK-NEXT:                OpShiftLeftLogical %ulong {{%\d+}} [[rhs]]
+    j <<= k;
+
+// CHECK:        [[n:%\d+]] = OpLoad %short %n
+// CHECK:      [[rhs:%\d+]] = OpBitwiseAnd %short [[n]] %ushort_15
+// CHECK-NEXT:                OpShiftLeftLogical %short {{%\d+}} [[rhs]]
+    m <<= n;
+
+// CHECK:        [[q:%\d+]] = OpLoad %v4ushort %q
+// CHECK:      [[rhs:%\d+]] = OpBitwiseAnd %v4ushort [[q]] [[v4c15]]
+// CHECK-NEXT:                OpShiftLeftLogical %v4ushort {{%\d+}} [[rhs]]
+    p <<= q;
+}

+ 45 - 0
tools/clang/test/CodeGenSPIRV/binary-op.bitwise-assign.shift-right.hlsl

@@ -0,0 +1,45 @@
+// Run: %dxc -T ps_6_2 -E main -enable-16bit-types
+
+// CHECK: [[v2c31:%\d+]] = OpConstantComposite %v2uint %uint_31 %uint_31
+// CHECK: [[v3c63:%\d+]] = OpConstantComposite %v3ulong %ulong_63 %ulong_63 %ulong_63
+// CHECK: [[v4c15:%\d+]] = OpConstantComposite %v4ushort %ushort_15 %ushort_15 %ushort_15 %ushort_15
+void main() {
+    int       a, b;
+    uint2     d, e;
+
+    int64_t3  g, h;
+    uint64_t  j, k;
+
+    int16_t   m, n;
+    uint16_t4 p, q;
+
+// CHECK:        [[b:%\d+]] = OpLoad %int %b
+// CHECK:      [[rhs:%\d+]] = OpBitwiseAnd %int [[b]] %uint_31
+// CHECK-NEXT:                OpShiftRightArithmetic %int {{%\d+}} [[rhs]]
+    a >>= b;
+
+// CHECK:        [[e:%\d+]] = OpLoad %v2uint %e
+// CHECK:      [[rhs:%\d+]] = OpBitwiseAnd %v2uint [[e]] [[v2c31]]
+// CHECK-NEXT:                OpShiftRightLogical %v2uint {{%\d+}} [[rhs]]
+    d >>= e;
+
+// CHECK:        [[h:%\d+]] = OpLoad %v3long %h
+// CHECK:      [[rhs:%\d+]] = OpBitwiseAnd %v3long [[h]] [[v3c63]]
+// CHECK-NEXT:                OpShiftRightArithmetic %v3long {{%\d+}} [[rhs]]
+    g >>= h;
+
+// CHECK:        [[k:%\d+]] = OpLoad %ulong %k
+// CHECK:      [[rhs:%\d+]] = OpBitwiseAnd %ulong [[k]] %ulong_63
+// CHECK-NEXT:                OpShiftRightLogical %ulong {{%\d+}} [[rhs]]
+    j >>= k;
+
+// CHECK:        [[n:%\d+]] = OpLoad %short %n
+// CHECK:      [[rhs:%\d+]] = OpBitwiseAnd %short [[n]] %ushort_15
+// CHECK-NEXT:                OpShiftRightArithmetic %short {{%\d+}} [[rhs]]
+    m >>= n;
+
+// CHECK:        [[q:%\d+]] = OpLoad %v4ushort %q
+// CHECK:      [[rhs:%\d+]] = OpBitwiseAnd %v4ushort [[q]] [[v4c15]]
+// CHECK-NEXT:                OpShiftRightLogical %v4ushort {{%\d+}} [[rhs]]
+    p >>= q;
+}

+ 0 - 22
tools/clang/test/CodeGenSPIRV/binary-op.bitwise-assign.vector.hlsl

@@ -38,26 +38,4 @@ void main() {
 // CHECK-NEXT: [[xor1:%\d+]] = OpBitwiseXor %v2uint [[j2]] [[i2]]
 // CHECK-NEXT: OpStore %j [[xor1]]
     j ^= i;
-
-// CHECK-NEXT: [[a3:%\d+]] = OpLoad %int %a
-// CHECK-NEXT: [[b3:%\d+]] = OpLoad %int %b
-// CHECK-NEXT: [[shl0:%\d+]] = OpShiftLeftLogical %int [[b3]] [[a3]]
-// CHECK-NEXT: OpStore %b [[shl0]]
-    b <<= a;
-// CHECK-NEXT: [[i3:%\d+]] = OpLoad %v2uint %i
-// CHECK-NEXT: [[j3:%\d+]] = OpLoad %v2uint %j
-// CHECK-NEXT: [[shl1:%\d+]] = OpShiftLeftLogical %v2uint [[j3]] [[i3]]
-// CHECK-NEXT: OpStore %j [[shl1]]
-    j <<= i;
-
-// CHECK-NEXT: [[a4:%\d+]] = OpLoad %int %a
-// CHECK-NEXT: [[b4:%\d+]] = OpLoad %int %b
-// CHECK-NEXT: [[shr0:%\d+]] = OpShiftRightArithmetic %int [[b4]] [[a4]]
-// CHECK-NEXT: OpStore %b [[shr0]]
-    b >>= a;
-// CHECK-NEXT: [[i4:%\d+]] = OpLoad %v2uint %i
-// CHECK-NEXT: [[j4:%\d+]] = OpLoad %v2uint %j
-// CHECK-NEXT: [[shr1:%\d+]] = OpShiftRightLogical %v2uint [[j4]] [[i4]]
-// CHECK-NEXT: OpStore %j [[shr1]]
-    j >>= i;
 }

+ 0 - 22
tools/clang/test/CodeGenSPIRV/binary-op.bitwise.scalar.hlsl

@@ -42,28 +42,6 @@ void main() {
 // CHECK-NEXT: OpStore %k [[k2]]
     k = i ^ j;
 
-// CHECK-NEXT: [[a3:%\d+]] = OpLoad %int %a
-// CHECK-NEXT: [[b3:%\d+]] = OpLoad %int %b
-// CHECK-NEXT: [[c3:%\d+]] = OpShiftLeftLogical %int [[a3]] [[b3]]
-// CHECK-NEXT: OpStore %c [[c3]]
-    c = a << b;
-// CHECK-NEXT: [[i3:%\d+]] = OpLoad %uint %i
-// CHECK-NEXT: [[j3:%\d+]] = OpLoad %uint %j
-// CHECK-NEXT: [[k3:%\d+]] = OpShiftLeftLogical %uint [[i3]] [[j3]]
-// CHECK-NEXT: OpStore %k [[k3]]
-    k = i << j;
-
-// CHECK-NEXT: [[a4:%\d+]] = OpLoad %int %a
-// CHECK-NEXT: [[b4:%\d+]] = OpLoad %int %b
-// CHECK-NEXT: [[c4:%\d+]] = OpShiftRightArithmetic %int [[a4]] [[b4]]
-// CHECK-NEXT: OpStore %c [[c4]]
-    c = a >> b;
-// CHECK-NEXT: [[i4:%\d+]] = OpLoad %uint %i
-// CHECK-NEXT: [[j4:%\d+]] = OpLoad %uint %j
-// CHECK-NEXT: [[k4:%\d+]] = OpShiftRightLogical %uint [[i4]] [[j4]]
-// CHECK-NEXT: OpStore %k [[k4]]
-    k = i >> j;
-
 // CHECK-NEXT: [[a5:%\d+]] = OpLoad %int %a
 // CHECK-NEXT: [[b5:%\d+]] = OpNot %int [[a5]]
 // CHECK-NEXT: OpStore %b [[b5]]

+ 45 - 0
tools/clang/test/CodeGenSPIRV/binary-op.bitwise.shift-left.hlsl

@@ -0,0 +1,45 @@
+// Run: %dxc -T ps_6_2 -E main -enable-16bit-types
+
+// CHECK: [[v2c31:%\d+]] = OpConstantComposite %v2uint %uint_31 %uint_31
+// CHECK: [[v3c63:%\d+]] = OpConstantComposite %v3ulong %ulong_63 %ulong_63 %ulong_63
+// CHECK: [[v4c15:%\d+]] = OpConstantComposite %v4ushort %ushort_15 %ushort_15 %ushort_15 %ushort_15
+void main() {
+    int       a, b, c;
+    uint2     d, e, f;
+
+    int64_t3  g, h, i;
+    uint64_t  j, k, l;
+
+    int16_t   m, n, o;
+    uint16_t4 p, q, r;
+
+// CHECK:        [[b:%\d+]] = OpLoad %int %b
+// CHECK-NEXT: [[rhs:%\d+]] = OpBitwiseAnd %int [[b]] %uint_31
+// CHECK-NEXT:                OpShiftLeftLogical %int {{%\d+}} [[rhs]]
+    c = a << b;
+
+// CHECK:        [[e:%\d+]] = OpLoad %v2uint %e
+// CHECK-NEXT: [[rhs:%\d+]] = OpBitwiseAnd %v2uint [[e]] [[v2c31]]
+// CHECK-NEXT:                OpShiftLeftLogical %v2uint {{%\d+}} [[rhs]]
+    f = d << e;
+
+// CHECK:        [[h:%\d+]] = OpLoad %v3long %h
+// CHECK-NEXT: [[rhs:%\d+]] = OpBitwiseAnd %v3long [[h]] [[v3c63]]
+// CHECK-NEXT:                OpShiftLeftLogical %v3long {{%\d+}} [[rhs]]
+    i = g << h;
+
+// CHECK:        [[k:%\d+]] = OpLoad %ulong %k
+// CHECK-NEXT: [[rhs:%\d+]] = OpBitwiseAnd %ulong [[k]] %ulong_63
+// CHECK-NEXT:                OpShiftLeftLogical %ulong {{%\d+}} [[rhs]]
+    l = j << k;
+
+// CHECK:        [[n:%\d+]] = OpLoad %short %n
+// CHECK-NEXT: [[rhs:%\d+]] = OpBitwiseAnd %short [[n]] %ushort_15
+// CHECK-NEXT:                OpShiftLeftLogical %short {{%\d+}} [[rhs]]
+    o = m << n;
+
+// CHECK:        [[q:%\d+]] = OpLoad %v4ushort %q
+// CHECK-NEXT: [[rhs:%\d+]] = OpBitwiseAnd %v4ushort [[q]] [[v4c15]]
+// CHECK-NEXT:                OpShiftLeftLogical %v4ushort {{%\d+}} [[rhs]]
+    r = p << q;
+}

+ 45 - 0
tools/clang/test/CodeGenSPIRV/binary-op.bitwise.shift-right.hlsl

@@ -0,0 +1,45 @@
+// Run: %dxc -T ps_6_2 -E main -enable-16bit-types
+
+// CHECK: [[v2c31:%\d+]] = OpConstantComposite %v2uint %uint_31 %uint_31
+// CHECK: [[v3c63:%\d+]] = OpConstantComposite %v3ulong %ulong_63 %ulong_63 %ulong_63
+// CHECK: [[v4c15:%\d+]] = OpConstantComposite %v4ushort %ushort_15 %ushort_15 %ushort_15 %ushort_15
+void main() {
+    int       a, b, c;
+    uint2     d, e, f;
+
+    int64_t3  g, h, i;
+    uint64_t  j, k, l;
+
+    int16_t   m, n, o;
+    uint16_t4 p, q, r;
+
+// CHECK:        [[b:%\d+]] = OpLoad %int %b
+// CHECK-NEXT: [[rhs:%\d+]] = OpBitwiseAnd %int [[b]] %uint_31
+// CHECK-NEXT:                OpShiftRightArithmetic %int {{%\d+}} [[rhs]]
+    c = a >> b;
+
+// CHECK:        [[e:%\d+]] = OpLoad %v2uint %e
+// CHECK-NEXT: [[rhs:%\d+]] = OpBitwiseAnd %v2uint [[e]] [[v2c31]]
+// CHECK-NEXT:                OpShiftRightLogical %v2uint {{%\d+}} [[rhs]]
+    f = d >> e;
+
+// CHECK:        [[h:%\d+]] = OpLoad %v3long %h
+// CHECK-NEXT: [[rhs:%\d+]] = OpBitwiseAnd %v3long [[h]] [[v3c63]]
+// CHECK-NEXT:                OpShiftRightArithmetic %v3long {{%\d+}} [[rhs]]
+    i = g >> h;
+
+// CHECK:        [[k:%\d+]] = OpLoad %ulong %k
+// CHECK-NEXT: [[rhs:%\d+]] = OpBitwiseAnd %ulong [[k]] %ulong_63
+// CHECK-NEXT:                OpShiftRightLogical %ulong {{%\d+}} [[rhs]]
+    l = j >> k;
+
+// CHECK:        [[n:%\d+]] = OpLoad %short %n
+// CHECK-NEXT: [[rhs:%\d+]] = OpBitwiseAnd %short [[n]] %ushort_15
+// CHECK-NEXT:                OpShiftRightArithmetic %short {{%\d+}} [[rhs]]
+    o = m >> n;
+
+// CHECK:        [[q:%\d+]] = OpLoad %v4ushort %q
+// CHECK-NEXT: [[rhs:%\d+]] = OpBitwiseAnd %v4ushort [[q]] [[v4c15]]
+// CHECK-NEXT:                OpShiftRightLogical %v4ushort {{%\d+}} [[rhs]]
+    r = p >> q;
+}

+ 0 - 22
tools/clang/test/CodeGenSPIRV/binary-op.bitwise.vector.hlsl

@@ -39,28 +39,6 @@ void main() {
 // CHECK-NEXT: OpStore %k [[k2]]
     k = i ^ j;
 
-// CHECK-NEXT: [[a3:%\d+]] = OpLoad %int %a
-// CHECK-NEXT: [[b3:%\d+]] = OpLoad %int %b
-// CHECK-NEXT: [[c3:%\d+]] = OpShiftLeftLogical %int [[a3]] [[b3]]
-// CHECK-NEXT: OpStore %c [[c3]]
-    c = a << b;
-// CHECK-NEXT: [[i3:%\d+]] = OpLoad %v3uint %i
-// CHECK-NEXT: [[j3:%\d+]] = OpLoad %v3uint %j
-// CHECK-NEXT: [[k3:%\d+]] = OpShiftLeftLogical %v3uint [[i3]] [[j3]]
-// CHECK-NEXT: OpStore %k [[k3]]
-    k = i << j;
-
-// CHECK-NEXT: [[a4:%\d+]] = OpLoad %int %a
-// CHECK-NEXT: [[b4:%\d+]] = OpLoad %int %b
-// CHECK-NEXT: [[c4:%\d+]] = OpShiftRightArithmetic %int [[a4]] [[b4]]
-// CHECK-NEXT: OpStore %c [[c4]]
-    c = a >> b;
-// CHECK-NEXT: [[i4:%\d+]] = OpLoad %v3uint %i
-// CHECK-NEXT: [[j4:%\d+]] = OpLoad %v3uint %j
-// CHECK-NEXT: [[k4:%\d+]] = OpShiftRightLogical %v3uint [[i4]] [[j4]]
-// CHECK-NEXT: OpStore %k [[k4]]
-    k = i >> j;
-
 // CHECK-NEXT: [[a5:%\d+]] = OpLoad %int %a
 // CHECK-NEXT: [[b5:%\d+]] = OpNot %int [[a5]]
 // CHECK-NEXT: OpStore %b [[b5]]

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

@@ -213,6 +213,12 @@ TEST_F(FileTest, BinaryOpScalarBitwise) {
 TEST_F(FileTest, BinaryOpVectorBitwise) {
   runFileTest("binary-op.bitwise.vector.hlsl");
 }
+TEST_F(FileTest, BinaryOpBitwiseShiftLeft) {
+  runFileTest("binary-op.bitwise.shift-left.hlsl");
+}
+TEST_F(FileTest, BinaryOpBitwiseShiftRight) {
+  runFileTest("binary-op.bitwise.shift-right.hlsl");
+}
 
 // For bitwise assignments
 TEST_F(FileTest, BinaryOpScalarBitwiseAssign) {
@@ -221,6 +227,12 @@ TEST_F(FileTest, BinaryOpScalarBitwiseAssign) {
 TEST_F(FileTest, BinaryOpVectorBitwiseAssign) {
   runFileTest("binary-op.bitwise-assign.vector.hlsl");
 }
+TEST_F(FileTest, BinaryOpBitwiseAssignShiftLeft) {
+  runFileTest("binary-op.bitwise-assign.shift-left.hlsl");
+}
+TEST_F(FileTest, BinaryOpBitwiseAssignShiftRight) {
+  runFileTest("binary-op.bitwise-assign.shift-right.hlsl");
+}
 
 // For comparison operators
 TEST_F(FileTest, BinaryOpScalarComparison) {