Răsfoiți Sursa

[spirv] Translate several intrinsic functions. (#654)

* frexp
* countbits
* clip
* ldexp
* lerp
* log10
* mad
* modf
* reversebits
Ehsan 8 ani în urmă
părinte
comite
015bdfd1d7

+ 12 - 2
docs/SPIR-V.rst

@@ -1068,6 +1068,10 @@ The following intrinsic HLSL functions are currently supported:
   requires the ``Kernel`` capability, translation is done using ``OpIsNan`` and ``OpIsInf``.
   A given value is finite iff it is not NaN and not infinite.
 - ``fmod`` : Returns the floating-point remainder for division of its arguments. Uses SPIR-V ``OpFMod``.
+- ``countbits`` : Counts the number of bits (per component) in the input integer. Uses SPIR-V ``OpBitCount``.
+- ``reversebits``: Reverses the order of the bits, per component. Uses SPIR-V ``OpBitReverse``.
+- ``clip``: Discards the current pixel if the specified value is less than zero. Uses conditional
+  control flow as well as SPIR-V ``OpKill``.
 
 Using GLSL extended instructions
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1075,9 +1079,9 @@ Using GLSL extended instructions
 the following intrinsic HLSL functions are translated using their equivalent
 instruction in the `GLSL extended instruction set <https://www.khronos.org/registry/spir-v/specs/1.0/GLSL.std.450.html>`_.
 
-======================= ===============================
+======================= ===================================
 HLSL Intrinsic Function   GLSL Extended Instruction
-======================= ===============================
+======================= ===================================
 ``abs``                 ``SAbs``/``FAbs``
 ``acos``                ``Acos``
 ``asin``                ``Asin``
@@ -1099,11 +1103,17 @@ HLSL Intrinsic Function   GLSL Extended Instruction
 ``floor``               ``Floor``
 ``fma``                 ``Fma``
 ``frac``                ``Fract``
+``frexp``               ``FrexpStruct``
+``ldexp``               ``Ldexp``
 ``length``              ``Length``
+``lerp``                ``FMix``
 ``log``                 ``Log``
+``log10``               ``Log2`` (scaled by ``1/log2(10)``)
 ``log2``                ``Log2``
+``mad``                 ``Fma``
 ``max``                 ``SMax``/``UMax``/``FMax``
 ``min``                 ``SMin``/``UMin``/``FMin``
+``modf``                ``ModfStruct``
 ``normalize``           ``Normalize``
 ``pow``                 ``Pow``
 ``reflect``             ``Reflect``

+ 285 - 0
tools/clang/lib/SPIRV/SPIRVEmitter.cpp

@@ -3419,9 +3419,16 @@ uint32_t SPIRVEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
   case hlsl::IntrinsicOp::IOP_asint:
   case hlsl::IntrinsicOp::IOP_asuint:
     return processIntrinsicAsType(callExpr);
+  case hlsl::IntrinsicOp::IOP_clip: {
+    return processIntrinsicClip(callExpr);
+  }
   case hlsl::IntrinsicOp::IOP_clamp:
   case hlsl::IntrinsicOp::IOP_uclamp:
     return processIntrinsicClamp(callExpr);
+  case hlsl::IntrinsicOp::IOP_frexp:
+    return processIntrinsicFrexp(callExpr);
+  case hlsl::IntrinsicOp::IOP_modf:
+    return processIntrinsicModf(callExpr);
   case hlsl::IntrinsicOp::IOP_sign: {
     if (isFloatOrVecMatOfFloatType(callExpr->getArg(0)->getType()))
       return processIntrinsicFloatSign(callExpr);
@@ -3438,11 +3445,16 @@ uint32_t SPIRVEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
   }
   case hlsl::IntrinsicOp::IOP_saturate: {
     return processIntrinsicSaturate(callExpr);
+  }
+  case hlsl::IntrinsicOp::IOP_log10: {
+    return processIntrinsicLog10(callExpr);
   }
     INTRINSIC_SPIRV_OP_CASE(transpose, Transpose, false);
+    INTRINSIC_SPIRV_OP_CASE(countbits, BitCount, false);
     INTRINSIC_SPIRV_OP_CASE(isinf, IsInf, true);
     INTRINSIC_SPIRV_OP_CASE(isnan, IsNan, true);
     INTRINSIC_SPIRV_OP_CASE(fmod, FMod, true);
+    INTRINSIC_SPIRV_OP_CASE(reversebits, BitReverse, false);
     INTRINSIC_OP_CASE(round, Round, true);
     INTRINSIC_OP_CASE_INT_FLOAT(abs, SAbs, FAbs, true);
     INTRINSIC_OP_CASE(acos, Acos, true);
@@ -3465,8 +3477,11 @@ uint32_t SPIRVEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
     INTRINSIC_OP_CASE(fma, Fma, true);
     INTRINSIC_OP_CASE(frac, Fract, true);
     INTRINSIC_OP_CASE(length, Length, false);
+    INTRINSIC_OP_CASE(ldexp, Ldexp, true);
+    INTRINSIC_OP_CASE(lerp, FMix, true);
     INTRINSIC_OP_CASE(log, Log, true);
     INTRINSIC_OP_CASE(log2, Log2, true);
+    INTRINSIC_OP_CASE(mad, Fma, true);
     INTRINSIC_OP_CASE_SINT_UINT_FLOAT(max, SMax, UMax, FMax, true);
     INTRINSIC_OP_CASE(umax, UMax, true);
     INTRINSIC_OP_CASE_SINT_UINT_FLOAT(min, SMin, UMin, FMin, true);
@@ -3497,6 +3512,259 @@ uint32_t SPIRVEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
   return 0;
 }
 
+uint32_t SPIRVEmitter::processIntrinsicModf(const CallExpr *callExpr) {
+  // Signature is: ret modf(x, ip)
+  // [in]    x: the input floating-point value.
+  // [out]  ip: the integer portion of x.
+  // [out] ret: the fractional portion of x.
+  // All of the above must be a scalar, vector, or matrix with the same
+  // component types. Component types can be float or int.
+
+  // The ModfStruct SPIR-V instruction returns a struct. The first member is the
+  // fractional part and the second member is the integer portion.
+  // ModfStruct {
+  //   <scalar or vector of float> frac;
+  //   <scalar or vector of float> ip;
+  // }
+
+  // Note if the input number (x) is not a float (i.e. 'x' is an int), it is
+  // automatically converted to float before modf is invoked. Sadly, the 'ip'
+  // argument is not treated the same way. Therefore, in such cases we'll have
+  // to manually convert the float result into int.
+
+  const uint32_t glslInstSetId = theBuilder.getGLSLExtInstSet();
+  const Expr *arg = callExpr->getArg(0);
+  const Expr *ipArg = callExpr->getArg(1);
+  const auto argType = arg->getType();
+  const auto ipType = ipArg->getType();
+  const auto returnType = callExpr->getType();
+  const auto returnTypeId = typeTranslator.translateType(returnType);
+  const auto ipTypeId = typeTranslator.translateType(ipType);
+  const uint32_t argId = doExpr(arg);
+  const uint32_t ipId = doExpr(ipArg);
+
+  // TODO: We currently do not support non-float matrices.
+  QualType ipElemType = {};
+  if (TypeTranslator::isMxNMatrix(ipType, &ipElemType) &&
+      !ipElemType->isFloatingType()) {
+    emitError("Non-FP matrices are currently not supported.");
+    return 0;
+  }
+
+  // For scalar and vector argument types.
+  {
+    if (TypeTranslator::isScalarType(argType) ||
+        TypeTranslator::isVectorType(argType)) {
+      const auto argTypeId = typeTranslator.translateType(argType);
+      // The struct members *must* have the same type.
+      const auto modfStructTypeId = theBuilder.getStructType(
+          {argTypeId, argTypeId}, "ModfStructType", {"frac", "ip"});
+      const auto modf =
+          theBuilder.createExtInst(modfStructTypeId, glslInstSetId,
+                                   GLSLstd450::GLSLstd450ModfStruct, {argId});
+      auto ip = theBuilder.createCompositeExtract(argTypeId, modf, {1});
+      // This will do nothing if the input number (x) and the ip are both of the
+      // same type. Otherwise, it will convert the ip into int as necessary.
+      ip = castToInt(ip, argType, ipType);
+      theBuilder.createStore(ipId, ip);
+      return theBuilder.createCompositeExtract(argTypeId, modf, {0});
+    }
+  }
+
+  // For matrix argument types.
+  {
+    uint32_t rowCount = 0, colCount = 0;
+    QualType elemType = {};
+    if (TypeTranslator::isMxNMatrix(argType, &elemType, &rowCount, &colCount)) {
+      const auto elemTypeId = typeTranslator.translateType(elemType);
+      const auto colTypeId = theBuilder.getVecType(elemTypeId, colCount);
+      const auto modfStructTypeId = theBuilder.getStructType(
+          {colTypeId, colTypeId}, "ModfStructType", {"frac", "ip"});
+      llvm::SmallVector<uint32_t, 4> fracs;
+      llvm::SmallVector<uint32_t, 4> ips;
+      for (uint32_t i = 0; i < rowCount; ++i) {
+        const auto curRow =
+            theBuilder.createCompositeExtract(colTypeId, argId, {i});
+        const auto modf = theBuilder.createExtInst(
+            modfStructTypeId, glslInstSetId, GLSLstd450::GLSLstd450ModfStruct,
+            {curRow});
+        auto ip = theBuilder.createCompositeExtract(colTypeId, modf, {1});
+        ips.push_back(ip);
+        fracs.push_back(
+            theBuilder.createCompositeExtract(colTypeId, modf, {0}));
+      }
+      theBuilder.createStore(
+          ipId, theBuilder.createCompositeConstruct(returnTypeId, ips));
+      return theBuilder.createCompositeConstruct(returnTypeId, fracs);
+    }
+  }
+
+  emitError("Unknown argument type passed to Modf function.");
+  return 0;
+}
+
+uint32_t SPIRVEmitter::processIntrinsicFrexp(const CallExpr *callExpr) {
+  // Signature is: ret frexp(x, exp)
+  // [in]   x: the input floating-point value.
+  // [out]  exp: the calculated exponent.
+  // [out]  ret: the calculated mantissa.
+  // All of the above must be a scalar, vector, or matrix of *float* type.
+
+  // The FrexpStruct SPIR-V instruction returns a struct. The first
+  // member is the significand (mantissa) and must be of the same type as the
+  // input parameter, and the second member is the exponent and must always be a
+  // scalar or vector of 32-bit *integer* type.
+  // FrexpStruct {
+  //   <scalar or vector of int/float> mantissa;
+  //   <scalar or vector of integers>  exponent;
+  // }
+
+  const uint32_t glslInstSetId = theBuilder.getGLSLExtInstSet();
+  const Expr *arg = callExpr->getArg(0);
+  const auto argType = arg->getType();
+  const auto intId = theBuilder.getInt32Type();
+  const auto returnTypeId = typeTranslator.translateType(callExpr->getType());
+  const uint32_t argId = doExpr(arg);
+  const uint32_t expId = doExpr(callExpr->getArg(1));
+
+  // For scalar and vector argument types.
+  {
+    uint32_t elemCount = 1;
+    if (TypeTranslator::isScalarType(argType) ||
+        TypeTranslator::isVectorType(argType, nullptr, &elemCount)) {
+      const auto argTypeId = typeTranslator.translateType(argType);
+      const auto expTypeId =
+          elemCount == 1 ? intId : theBuilder.getVecType(intId, elemCount);
+      const auto frexpStructTypeId = theBuilder.getStructType(
+          {argTypeId, expTypeId}, "FrexpStructType", {"mantissa", "exponent"});
+      const auto frexp =
+          theBuilder.createExtInst(frexpStructTypeId, glslInstSetId,
+                                   GLSLstd450::GLSLstd450FrexpStruct, {argId});
+      const auto exponentInt =
+          theBuilder.createCompositeExtract(expTypeId, frexp, {1});
+
+      // Since the SPIR-V instruction returns an int, and the intrinsic HLSL
+      // expects a float, an conversion must take place before writing the
+      // results.
+      const auto exponentFloat = theBuilder.createUnaryOp(
+          spv::Op::OpConvertSToF, returnTypeId, exponentInt);
+      theBuilder.createStore(expId, exponentFloat);
+      return theBuilder.createCompositeExtract(argTypeId, frexp, {0});
+    }
+  }
+
+  // For matrix argument types.
+  {
+    uint32_t rowCount = 0, colCount = 0;
+    if (TypeTranslator::isMxNMatrix(argType, nullptr, &rowCount, &colCount)) {
+      const auto floatId = theBuilder.getFloat32Type();
+      const auto expTypeId = theBuilder.getVecType(intId, colCount);
+      const auto colTypeId = theBuilder.getVecType(floatId, colCount);
+      const auto frexpStructTypeId = theBuilder.getStructType(
+          {colTypeId, expTypeId}, "FrexpStructType", {"mantissa", "exponent"});
+      llvm::SmallVector<uint32_t, 4> exponents;
+      llvm::SmallVector<uint32_t, 4> mantissas;
+      for (uint32_t i = 0; i < rowCount; ++i) {
+        const auto curRow =
+            theBuilder.createCompositeExtract(colTypeId, argId, {i});
+        const auto frexp = theBuilder.createExtInst(
+            frexpStructTypeId, glslInstSetId, GLSLstd450::GLSLstd450FrexpStruct,
+            {curRow});
+        const auto exponentInt =
+            theBuilder.createCompositeExtract(expTypeId, frexp, {1});
+
+        // Since the SPIR-V instruction returns an int, and the intrinsic HLSL
+        // expects a float, an conversion must take place before writing the
+        // results.
+        const auto exponentFloat = theBuilder.createUnaryOp(
+            spv::Op::OpConvertSToF, colTypeId, exponentInt);
+        exponents.push_back(exponentFloat);
+        mantissas.push_back(
+            theBuilder.createCompositeExtract(colTypeId, frexp, {0}));
+      }
+      const auto exponentsResultId =
+          theBuilder.createCompositeConstruct(returnTypeId, exponents);
+      theBuilder.createStore(expId, exponentsResultId);
+      return theBuilder.createCompositeConstruct(returnTypeId, mantissas);
+    }
+  }
+
+  emitError("Unknown argument type passed to Frexp function.");
+  return 0;
+}
+
+uint32_t SPIRVEmitter::processIntrinsicClip(const CallExpr *callExpr) {
+  // Discards the current pixel if the specified value is less than zero.
+  // TODO: If the argument can be const folded and evaluated, we could
+  // potentially avoid creating a branch. This would be a bit challenging for
+  // matrix/vector arguments.
+
+  assert(callExpr->getNumArgs() == 1u);
+  const Expr *arg = callExpr->getArg(0);
+  const auto argType = arg->getType();
+  const auto boolType = theBuilder.getBoolType();
+  uint32_t condition = 0;
+
+  // Could not determine the argument as a constant. We need to branch based on
+  // the argument. If the argument is a vector/matrix, clipping is done if *any*
+  // element of the vector/matrix is less than zero.
+  const uint32_t argId = doExpr(arg);
+
+  QualType elemType = {};
+  uint32_t elemCount = 0, rowCount = 0, colCount = 0;
+  if (TypeTranslator::isScalarType(argType)) {
+    const auto zero = getValueZero(argType);
+    condition = theBuilder.createBinaryOp(spv::Op::OpFOrdLessThan, boolType,
+                                          argId, zero);
+  } else if (TypeTranslator::isVectorType(argType, nullptr, &elemCount)) {
+    const auto zero = getValueZero(argType);
+    const auto boolVecType = theBuilder.getVecType(boolType, elemCount);
+    const auto cmp = theBuilder.createBinaryOp(spv::Op::OpFOrdLessThan,
+                                               boolVecType, argId, zero);
+    condition = theBuilder.createUnaryOp(spv::Op::OpAny, boolType, cmp);
+  } else if (TypeTranslator::isMxNMatrix(argType, &elemType, &rowCount,
+                                         &colCount)) {
+    const uint32_t elemTypeId = typeTranslator.translateType(elemType);
+    const uint32_t floatVecType = theBuilder.getVecType(elemTypeId, colCount);
+    const uint32_t elemZeroId = getValueZero(elemType);
+    llvm::SmallVector<uint32_t, 4> elements(size_t(colCount), elemZeroId);
+    const auto zero = theBuilder.getConstantComposite(floatVecType, elements);
+    llvm::SmallVector<uint32_t, 4> cmpResults;
+    for (uint32_t i = 0; i < rowCount; ++i) {
+      const uint32_t lhsVec =
+          theBuilder.createCompositeExtract(floatVecType, argId, {i});
+      const auto boolColType = theBuilder.getVecType(boolType, colCount);
+      const auto cmp = theBuilder.createBinaryOp(spv::Op::OpFOrdLessThan,
+                                                 boolColType, lhsVec, zero);
+      const auto any = theBuilder.createUnaryOp(spv::Op::OpAny, boolType, cmp);
+      cmpResults.push_back(any);
+    }
+    const auto boolRowType = theBuilder.getVecType(boolType, rowCount);
+    const auto results =
+        theBuilder.createCompositeConstruct(boolRowType, cmpResults);
+    condition = theBuilder.createUnaryOp(spv::Op::OpAny, boolType, results);
+  } else {
+    emitError("Invalid type passed to clip function.");
+    return 0;
+  }
+
+  // Then we need to emit the instruction for the conditional branch.
+  const uint32_t thenBB = theBuilder.createBasicBlock("if.true");
+  const uint32_t mergeBB = theBuilder.createBasicBlock("if.merge");
+  // Create the branch instruction. This will end the current basic block.
+  theBuilder.createConditionalBranch(condition, thenBB, mergeBB, mergeBB);
+  theBuilder.addSuccessor(thenBB);
+  theBuilder.addSuccessor(mergeBB);
+  theBuilder.setMergeTarget(mergeBB);
+  // Handle the then branch
+  theBuilder.setInsertPoint(thenBB);
+  theBuilder.createKill();
+  theBuilder.addSuccessor(mergeBB);
+  // From now on, we'll emit instructions into the merge block.
+  theBuilder.setInsertPoint(mergeBB);
+  return 0;
+}
+
 uint32_t SPIRVEmitter::processIntrinsicClamp(const CallExpr *callExpr) {
   // According the HLSL reference: clamp(X, Min, Max) takes 3 arguments. Each
   // one may be int, uint, or float.
@@ -4069,6 +4337,23 @@ uint32_t SPIRVEmitter::processIntrinsicUsingGLSLInst(
   return 0;
 }
 
+uint32_t SPIRVEmitter::processIntrinsicLog10(const CallExpr *callExpr) {
+  // Since there is no log10 instruction in SPIR-V, we can use:
+  // log10(x) = log2(x) * ( 1 / log2(10) )
+  // 1 / log2(10) = 0.30103
+  const auto scale = theBuilder.getConstantFloat32(0.30103f);
+  const auto log2 =
+      processIntrinsicUsingGLSLInst(callExpr, GLSLstd450::GLSLstd450Log2, true);
+  const auto returnType = callExpr->getType();
+  const auto returnTypeId = typeTranslator.translateType(returnType);
+  spv::Op scaleOp = TypeTranslator::isScalarType(returnType)
+                        ? spv::Op::OpFMul
+                        : TypeTranslator::isVectorType(returnType)
+                              ? spv::Op::OpVectorTimesScalar
+                              : spv::Op::OpMatrixTimesScalar;
+  return theBuilder.createBinaryOp(scaleOp, returnTypeId, log2, scale);
+}
+
 uint32_t SPIRVEmitter::getValueZero(QualType type) {
   {
     QualType scalarType = {};

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

@@ -258,15 +258,28 @@ private:
   /// Processes HLSL instrinsic functions.
   uint32_t processIntrinsicCallExpr(const CallExpr *);
 
+  /// Processes the 'clip' intrinsic function. Discards the current pixel if the
+  /// specified value is less than zero.
+  uint32_t processIntrinsicClip(const CallExpr *);
+
   /// Processes the 'clamp' intrinsic function.
   uint32_t processIntrinsicClamp(const CallExpr *);
 
+  /// Processes the 'frexp' intrinsic function.
+  uint32_t processIntrinsicFrexp(const CallExpr *);
+
+  /// Processes the 'modf' intrinsic function.
+  uint32_t processIntrinsicModf(const CallExpr *);
+
   /// Processes the 'mul' intrinsic function.
   uint32_t processIntrinsicMul(const CallExpr *);
 
   /// Processes the 'dot' intrinsic function.
   uint32_t processIntrinsicDot(const CallExpr *);
 
+  /// Processes the 'log10' intrinsic function.
+  uint32_t processIntrinsicLog10(const CallExpr *);
+
   /// Processes the 'all' and 'any' intrinsic functions.
   uint32_t processIntrinsicAllOrAny(const CallExpr *, spv::Op);
 

+ 48 - 0
tools/clang/test/CodeGenSPIRV/intrinsics.clip.hlsl

@@ -0,0 +1,48 @@
+// Run: %dxc -T ps_6_0 -E main
+
+// According to the HLSL reference, clip operates on scalar, vector, or matrix of floats.
+
+// CHECK: [[v4f0:%\d+]] = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
+// CHECK: [[v3f0:%\d+]] = OpConstantComposite %v3float %float_0 %float_0 %float_0
+
+void main() {
+  float    a;
+  float4   b;
+  float2x3 c;
+
+// CHECK:                      [[a:%\d+]] = OpLoad %float %a
+// CHECK-NEXT:          [[is_a_neg:%\d+]] = OpFOrdLessThan %bool [[a]] %float_0
+// CHECK-NEXT:                              OpSelectionMerge %if_merge None
+// CHECK-NEXT:                              OpBranchConditional [[is_a_neg]] %if_true %if_merge
+// CHECK-NEXT:                   %if_true = OpLabel
+// CHECK-NEXT:                              OpKill
+// CHECK-NEXT:                  %if_merge = OpLabel
+  clip(a);
+
+// CHECK-NEXT:                 [[b:%\d+]] = OpLoad %v4float %b
+// CHECK-NEXT:      [[is_b_neg_vec:%\d+]] = OpFOrdLessThan %v4bool [[b]] [[v4f0]]
+// CHECK-NEXT:          [[is_b_neg:%\d+]] = OpAny %bool [[is_b_neg_vec]]
+// CHECK-NEXT:                              OpSelectionMerge %if_merge_0 None
+// CHECK-NEXT:                              OpBranchConditional [[is_b_neg]] %if_true_0 %if_merge_0
+// CHECK-NEXT:                 %if_true_0 = OpLabel
+// CHECK-NEXT:                              OpKill
+// CHECK-NEXT:                %if_merge_0 = OpLabel
+  clip(b);
+
+// CHECK:                      [[c:%\d+]] = OpLoad %mat2v3float %c
+// CHECK-NEXT:            [[c_row0:%\d+]] = OpCompositeExtract %v3float [[c]] 0
+// CHECK-NEXT: [[is_c_row0_neg_vec:%\d+]] = OpFOrdLessThan %v3bool [[c_row0]] [[v3f0]]
+// CHECK-NEXT:     [[is_c_row0_neg:%\d+]] = OpAny %bool [[is_c_row0_neg_vec]]
+// CHECK-NEXT:            [[c_row1:%\d+]] = OpCompositeExtract %v3float [[c]] 1
+// CHECK-NEXT: [[is_c_row1_neg_vec:%\d+]] = OpFOrdLessThan %v3bool [[c_row1]] [[v3f0]]
+// CHECK-NEXT:     [[is_c_row1_neg:%\d+]] = OpAny %bool [[is_c_row1_neg_vec]]
+// CHECK-NEXT:      [[is_c_neg_vec:%\d+]] = OpCompositeConstruct %v2bool [[is_c_row0_neg]] [[is_c_row1_neg]]
+// CHECK-NEXT:          [[is_c_neg:%\d+]] = OpAny %bool [[is_c_neg_vec]]
+// CHECK-NEXT:                              OpSelectionMerge %if_merge_1 None
+// CHECK-NEXT:                              OpBranchConditional [[is_c_neg]] %if_true_1 %if_merge_1
+// CHECK-NEXT:                              %if_true_1 = OpLabel
+// CHECK-NEXT:                              OpKill
+  clip(c);
+// CHECK-NEXT:                %if_merge_1 = OpLabel
+// CHECK-NEXT:                              OpReturn
+}

+ 17 - 0
tools/clang/test/CodeGenSPIRV/intrinsics.countbits.hlsl

@@ -0,0 +1,17 @@
+// Run: %dxc -T vs_6_0 -E main
+
+// According to HLSL reference:
+// The 'countbits' function can only operate on scalar or vector of uints.
+
+void main() {
+  uint a;
+  uint4 b;
+  
+// CHECK:      [[a:%\d+]] = OpLoad %uint %a
+// CHECK-NEXT:   {{%\d+}} = OpBitCount %uint [[a]]
+  uint  cb  = countbits(a);
+
+// CHECK:      [[b:%\d+]] = OpLoad %v4uint %b
+// CHECK-NEXT:   {{%\d+}} = OpBitCount %v4uint [[b]]
+  uint4 cb4 = countbits(b);
+}

+ 63 - 0
tools/clang/test/CodeGenSPIRV/intrinsics.frexp.hlsl

@@ -0,0 +1,63 @@
+// Run: %dxc -T vs_6_0 -E main
+
+// According to HLSL reference:
+// The 'frexp' function can only operate on float, vector of float, and matrix of floats.
+
+// CHECK: [[glsl:%\d+]] = OpExtInstImport "GLSL.std.450"
+
+// CHECK: OpName %FrexpStructType "FrexpStructType"
+// CHECK: OpMemberName %FrexpStructType 0 "mantissa"
+// CHECK: OpMemberName %FrexpStructType 1 "exponent"
+
+// CHECK: OpName %FrexpStructType_0 "FrexpStructType"
+// CHECK: OpMemberName %FrexpStructType_0 0 "mantissa"
+// CHECK: OpMemberName %FrexpStructType_0 1 "exponent"
+
+// CHECK: OpName %FrexpStructType_1 "FrexpStructType"
+// CHECK: OpMemberName %FrexpStructType_1 0 "mantissa"
+// CHECK: OpMemberName %FrexpStructType_1 1 "exponent"
+
+// CHECK:   %FrexpStructType = OpTypeStruct %float %int
+// CHECK: %FrexpStructType_0 = OpTypeStruct %v4float %v4int
+// CHECK: %FrexpStructType_1 = OpTypeStruct %v3float %v3int
+
+void main() {
+  float    a, exp_a, mantissa_a;
+  float4   b, exp_b, mantissa_b;
+  float2x3 c, exp_c, mantissa_c;
+
+// CHECK:                [[a:%\d+]] = OpLoad %float %a
+// CHECK-NEXT:     [[frexp_a:%\d+]] = OpExtInst %FrexpStructType [[glsl]] FrexpStruct [[a]]
+// CHECK-NEXT:   [[int_exp_a:%\d+]] = OpCompositeExtract %int [[frexp_a]] 1
+// CHECK-NEXT: [[float_exp_a:%\d+]] = OpConvertSToF %float [[int_exp_a]]
+// CHECK-NEXT:                        OpStore %exp_a [[float_exp_a]]
+// CHECK-NEXT:  [[mantissa_a:%\d+]] = OpCompositeExtract %float [[frexp_a]] 0
+// CHECK-NEXT:                        OpStore %mantissa_a [[mantissa_a]]
+  mantissa_a = frexp(a, exp_a);
+
+// CHECK:                [[b:%\d+]] = OpLoad %v4float %b
+// CHECK-NEXT:     [[frexp_b:%\d+]] = OpExtInst %FrexpStructType_0 [[glsl]] FrexpStruct [[b]]
+// CHECK-NEXT:   [[int_exp_b:%\d+]] = OpCompositeExtract %v4int [[frexp_b]] 1
+// CHECK-NEXT: [[float_exp_b:%\d+]] = OpConvertSToF %v4float [[int_exp_b]]
+// CHECK-NEXT:                        OpStore %exp_b [[float_exp_b]]
+// CHECK-NEXT:  [[mantissa_b:%\d+]] = OpCompositeExtract %v4float [[frexp_b]] 0
+// CHECK-NEXT:                        OpStore %mantissa_b [[mantissa_b]]
+  mantissa_b = frexp(b, exp_b);
+
+// CHECK:                     [[c:%\d+]] = OpLoad %mat2v3float %c
+// CHECK-NEXT:           [[c_row0:%\d+]] = OpCompositeExtract %v3float [[c]] 0
+// CHECK-NEXT:     [[c_frexp_row0:%\d+]] = OpExtInst %FrexpStructType_1 [[glsl]] FrexpStruct [[c_row0]]
+// CHECK-NEXT:   [[int_exp_c_row0:%\d+]] = OpCompositeExtract %v3int [[c_frexp_row0]] 1
+// CHECK-NEXT: [[float_exp_c_row0:%\d+]] = OpConvertSToF %v3float [[int_exp_c_row0]]
+// CHECK-NEXT:  [[mantissa_c_row0:%\d+]] = OpCompositeExtract %v3float [[c_frexp_row0]] 0
+// CHECK-NEXT:           [[c_row1:%\d+]] = OpCompositeExtract %v3float [[c]] 1
+// CHECK-NEXT:     [[c_frexp_row1:%\d+]] = OpExtInst %FrexpStructType_1 [[glsl]] FrexpStruct [[c_row1]]
+// CHECK-NEXT:   [[int_exp_c_row1:%\d+]] = OpCompositeExtract %v3int [[c_frexp_row1]] 1
+// CHECK-NEXT: [[float_exp_c_row1:%\d+]] = OpConvertSToF %v3float [[int_exp_c_row1]]
+// CHECK-NEXT:  [[mantissa_c_row1:%\d+]] = OpCompositeExtract %v3float [[c_frexp_row1]] 0
+// CHECK-NEXT:      [[float_exp_c:%\d+]] = OpCompositeConstruct %mat2v3float [[float_exp_c_row0]] [[float_exp_c_row1]]
+// CHECK-NEXT:                             OpStore %exp_c [[float_exp_c]]
+// CHECK-NEXT:       [[mantissa_c:%\d+]] = OpCompositeConstruct %mat2v3float [[mantissa_c_row0]] [[mantissa_c_row1]]
+// CHECK-NEXT:                             OpStore %mantissa_c [[mantissa_c]]
+  mantissa_c = frexp(c, exp_c);
+}

+ 36 - 0
tools/clang/test/CodeGenSPIRV/intrinsics.ldexp.hlsl

@@ -0,0 +1,36 @@
+// Run: %dxc -T vs_6_0 -E main
+
+// According to HLSL reference:
+// The 'ldexp' function can only operate on float, vector of float, and matrix of floats.
+
+// CHECK:      [[glsl:%\d+]] = OpExtInstImport "GLSL.std.450"
+
+void main() {
+  float    a1, a2, ldexp_a;
+  float4   b1, b2, ldexp_b;
+  float2x3 c1, c2, ldexp_c;
+  
+// CHECK:          [[a1:%\d+]] = OpLoad %float %a1
+// CHECK-NEXT:     [[a2:%\d+]] = OpLoad %float %a2
+// CHECK-NEXT:[[ldexp_a:%\d+]] = OpExtInst %float [[glsl]] Ldexp [[a1]] [[a2]]
+// CHECK-NEXT:                   OpStore %ldexp_a [[ldexp_a]]
+  ldexp_a = ldexp(a1, a2);
+
+// CHECK:          [[b1:%\d+]] = OpLoad %v4float %b1
+// CHECK-NEXT:     [[b2:%\d+]] = OpLoad %v4float %b2
+// CHECK-NEXT:[[ldexp_b:%\d+]] = OpExtInst %v4float [[glsl]] Ldexp [[b1]] [[b2]]
+// CHECK-NEXT:                   OpStore %ldexp_b [[ldexp_b]]
+  ldexp_b = ldexp(b1, b2);
+
+// CHECK:               [[c1:%\d+]] = OpLoad %mat2v3float %c1
+// CHECK-NEXT:          [[c2:%\d+]] = OpLoad %mat2v3float %c2
+// CHECK-NEXT:     [[c1_row0:%\d+]] = OpCompositeExtract %v3float [[c1]] 0
+// CHECK-NEXT:     [[c2_row0:%\d+]] = OpCompositeExtract %v3float [[c2]] 0
+// CHECK-NEXT: [[ldexp_c_row0:%\d+]] = OpExtInst %v3float [[glsl]] Ldexp [[c1_row0]] [[c2_row0]]
+// CHECK-NEXT:     [[c1_row1:%\d+]] = OpCompositeExtract %v3float [[c1]] 1
+// CHECK-NEXT:     [[c2_row1:%\d+]] = OpCompositeExtract %v3float [[c2]] 1
+// CHECK-NEXT: [[ldexp_c_row1:%\d+]] = OpExtInst %v3float [[glsl]] Ldexp [[c1_row1]] [[c2_row1]]
+// CHECK-NEXT:      [[ldexp_c:%\d+]] = OpCompositeConstruct %mat2v3float [[ldexp_c_row0]] [[ldexp_c_row1]]
+// CHECK-NEXT:                        OpStore %ldexp_c [[ldexp_c]]
+  ldexp_c = ldexp(c1, c2);
+}

+ 41 - 0
tools/clang/test/CodeGenSPIRV/intrinsics.lerp.hlsl

@@ -0,0 +1,41 @@
+// Run: %dxc -T vs_6_0 -E main
+
+// According to HLSL reference:
+// The 'lerp' function can only operate on float, vector of float, and matrix of floats.
+
+// CHECK:      [[glsl:%\d+]] = OpExtInstImport "GLSL.std.450"
+
+void main() {
+  float    a1, a2, a3, lerp_a;
+  float4   b1, b2, b3, lerp_b;
+  float2x3 c1, c2, c3, lerp_c;
+  
+// CHECK:          [[a1:%\d+]] = OpLoad %float %a1
+// CHECK-NEXT:     [[a2:%\d+]] = OpLoad %float %a2
+// CHECK-NEXT:     [[a3:%\d+]] = OpLoad %float %a3
+// CHECK-NEXT: [[lerp_a:%\d+]] = OpExtInst %float [[glsl]] FMix [[a1]] [[a2]] [[a3]]
+// CHECK-NEXT:                   OpStore %lerp_a [[lerp_a]]
+  lerp_a = lerp(a1, a2, a3);
+
+// CHECK:          [[b1:%\d+]] = OpLoad %v4float %b1
+// CHECK-NEXT:     [[b2:%\d+]] = OpLoad %v4float %b2
+// CHECK-NEXT:     [[b3:%\d+]] = OpLoad %v4float %b3
+// CHECK-NEXT: [[lerp_b:%\d+]] = OpExtInst %v4float [[glsl]] FMix [[b1]] [[b2]] [[b3]]
+// CHECK-NEXT:                   OpStore %lerp_b [[lerp_b]]
+  lerp_b = lerp(b1, b2, b3);
+
+// CHECK:               [[c1:%\d+]] = OpLoad %mat2v3float %c1
+// CHECK-NEXT:          [[c2:%\d+]] = OpLoad %mat2v3float %c2
+// CHECK-NEXT:          [[c3:%\d+]] = OpLoad %mat2v3float %c3
+// CHECK-NEXT:     [[c1_row0:%\d+]] = OpCompositeExtract %v3float [[c1]] 0
+// CHECK-NEXT:     [[c2_row0:%\d+]] = OpCompositeExtract %v3float [[c2]] 0
+// CHECK-NEXT:     [[c3_row0:%\d+]] = OpCompositeExtract %v3float [[c3]] 0
+// CHECK-NEXT: [[lerp_c_row0:%\d+]] = OpExtInst %v3float [[glsl]] FMix [[c1_row0]] [[c2_row0]] [[c3_row0]]
+// CHECK-NEXT:     [[c1_row1:%\d+]] = OpCompositeExtract %v3float [[c1]] 1
+// CHECK-NEXT:     [[c2_row1:%\d+]] = OpCompositeExtract %v3float [[c2]] 1
+// CHECK-NEXT:     [[c3_row1:%\d+]] = OpCompositeExtract %v3float [[c3]] 1
+// CHECK-NEXT: [[lerp_c_row1:%\d+]] = OpExtInst %v3float [[glsl]] FMix [[c1_row1]] [[c2_row1]] [[c3_row1]]
+// CHECK-NEXT:      [[lerp_c:%\d+]] = OpCompositeConstruct %mat2v3float [[lerp_c_row0]] [[lerp_c_row1]]
+// CHECK-NEXT:                        OpStore %lerp_c [[lerp_c]]
+  lerp_c = lerp(c1, c2, c3);
+}

+ 35 - 0
tools/clang/test/CodeGenSPIRV/intrinsics.log10.hlsl

@@ -0,0 +1,35 @@
+// Run: %dxc -T vs_6_0 -E main
+
+// According to HLSL reference:
+// The 'log10' function can only operate on float, vector of float, and matrix of floats.
+
+// CHECK:  [[glsl:%\d+]] = OpExtInstImport "GLSL.std.450"
+// CHECK: %float_0_30103 = OpConstant %float 0.30103
+
+void main() {
+  float    a, log10_a;
+  float4   b, log10_b;
+  float2x3 c, log10_c;
+  
+// CHECK:           [[a:%\d+]] = OpLoad %float %a
+// CHECK-NEXT: [[log2_a:%\d+]] = OpExtInst %float [[glsl]] Log2 [[a]]
+// CHECK-NEXT:[[log10_a:%\d+]] = OpFMul %float [[log2_a]] %float_0_30103
+// CHECK-NEXT:                   OpStore %log10_a [[log10_a]]
+  log10_a = log10(a);
+
+// CHECK:           [[b:%\d+]] = OpLoad %v4float %b
+// CHECK-NEXT: [[log2_b:%\d+]] = OpExtInst %v4float [[glsl]] Log2 [[b]]
+// CHECK-NEXT:[[log10_b:%\d+]] = OpVectorTimesScalar %v4float [[log2_b]] %float_0_30103
+// CHECK-NEXT:                   OpStore %log10_b [[log10_b]]
+  log10_b = log10(b);
+
+// CHECK:                [[c:%\d+]] = OpLoad %mat2v3float %c
+// CHECK-NEXT:      [[c_row0:%\d+]] = OpCompositeExtract %v3float [[c]] 0
+// CHECK-NEXT: [[log2_c_row0:%\d+]] = OpExtInst %v3float [[glsl]] Log2 [[c_row0]]
+// CHECK-NEXT:      [[c_row1:%\d+]] = OpCompositeExtract %v3float [[c]] 1
+// CHECK-NEXT: [[log2_c_row1:%\d+]] = OpExtInst %v3float [[glsl]] Log2 [[c_row1]]
+// CHECK-NEXT:      [[log2_c:%\d+]] = OpCompositeConstruct %mat2v3float [[log2_c_row0]] [[log2_c_row1]]
+// CHECK-NEXT:     [[log10_c:%\d+]] = OpMatrixTimesScalar %mat2v3float [[log2_c]] %float_0_30103
+// CHECK-NEXT:                        OpStore %log10_c [[log10_c]]
+  log10_c = log10(c);
+}

+ 35 - 0
tools/clang/test/CodeGenSPIRV/intrinsics.mad.hlsl

@@ -0,0 +1,35 @@
+// Run: %dxc -T vs_6_0 -E main
+
+// CHECK: [[glsl:%\d+]] = OpExtInstImport "GLSL.std.450"
+
+void main() {
+  float    a1, a2, a3, fma_a;
+  float4   b1, b2, b3, fma_b;
+  float2x3 c1, c2, c3, fma_c;
+
+// CHECK:      [[a1:%\d+]] = OpLoad %float %a1
+// CHECK-NEXT: [[a2:%\d+]] = OpLoad %float %a2
+// CHECK-NEXT: [[a3:%\d+]] = OpLoad %float %a3
+// CHECK-NEXT:    {{%\d+}} = OpExtInst %float [[glsl]] Fma [[a1]] [[a2]] [[a3]]
+  fma_a = mad(a1, a2, a3);
+
+// CHECK:      [[b1:%\d+]] = OpLoad %v4float %b1
+// CHECK-NEXT: [[b2:%\d+]] = OpLoad %v4float %b2
+// CHECK-NEXT: [[b3:%\d+]] = OpLoad %v4float %b3
+// CHECK-NEXT:    {{%\d+}} = OpExtInst %v4float [[glsl]] Fma [[b1]] [[b2]] [[b3]]
+  fma_b = mad(b1, b2, b3);
+
+// CHECK:            [[c1:%\d+]] = OpLoad %mat2v3float %c1
+// CHECK-NEXT:       [[c2:%\d+]] = OpLoad %mat2v3float %c2
+// CHECK-NEXT:       [[c3:%\d+]] = OpLoad %mat2v3float %c3
+// CHECK-NEXT:  [[c1_row0:%\d+]] = OpCompositeExtract %v3float [[c1]] 0
+// CHECK-NEXT:  [[c2_row0:%\d+]] = OpCompositeExtract %v3float [[c2]] 0
+// CHECK-NEXT:  [[c3_row0:%\d+]] = OpCompositeExtract %v3float [[c3]] 0
+// CHECK-NEXT: [[fma_row0:%\d+]] = OpExtInst %v3float [[glsl]] Fma [[c1_row0]] [[c2_row0]] [[c3_row0]]
+// CHECK-NEXT:  [[c1_row1:%\d+]] = OpCompositeExtract %v3float [[c1]] 1
+// CHECK-NEXT:  [[c2_row1:%\d+]] = OpCompositeExtract %v3float [[c2]] 1
+// CHECK-NEXT:  [[c3_row1:%\d+]] = OpCompositeExtract %v3float [[c3]] 1
+// CHECK-NEXT: [[fma_row1:%\d+]] = OpExtInst %v3float [[glsl]] Fma [[c1_row1]] [[c2_row1]] [[c3_row1]]
+// CHECK-NEXT:          {{%\d+}} = OpCompositeConstruct %mat2v3float [[fma_row0]] [[fma_row1]]
+  fma_c = mad(c1, c2, c3);
+}

+ 66 - 0
tools/clang/test/CodeGenSPIRV/intrinsics.modf.hlsl

@@ -0,0 +1,66 @@
+// Run: %dxc -T vs_6_0 -E main
+
+// According to HLSL reference:
+// The 'modf' function can only operate on scalar/vector/matrix of float/int.
+
+// CHECK: [[glsl:%\d+]] = OpExtInstImport "GLSL.std.450"
+
+// CHECK: OpName %ModfStructType "ModfStructType"
+// CHECK: OpMemberName %ModfStructType 0 "frac"
+// CHECK: OpMemberName %ModfStructType 1 "ip"
+// CHECK: OpName %ModfStructType_0 "ModfStructType"
+// CHECK: OpMemberName %ModfStructType_0 0 "frac"
+// CHECK: OpMemberName %ModfStructType_0 1 "ip"
+// CHECK: OpName %ModfStructType_1 "ModfStructType"
+// CHECK: OpMemberName %ModfStructType_1 0 "frac"
+// CHECK: OpMemberName %ModfStructType_1 1 "ip"
+
+// Note: Even though we have used non-float types below,
+// DXC has casted the input of modf() into float. Therefore
+// all struct types have float members.
+// CHECK:   %ModfStructType = OpTypeStruct %float %float
+// CHECK: %ModfStructType_0 = OpTypeStruct %v4float %v4float
+// CHECK: %ModfStructType_1 = OpTypeStruct %v3float %v3float
+
+void main() {
+  uint     a, ip_a, frac_a;
+  int4     b, ip_b, frac_b;
+  float2x3 c, ip_c, frac_c;
+
+// CHECK:                 [[a:%\d+]] = OpLoad %uint %a
+// CHECK-NEXT:           [[af:%\d+]] = OpConvertUToF %float [[a]]
+// CHECK-NEXT:[[modf_struct_a:%\d+]] = OpExtInst %ModfStructType [[glsl]] ModfStruct [[af]]
+// CHECK-NEXT:         [[ip_a:%\d+]] = OpCompositeExtract %float [[modf_struct_a]] 1
+// CHECK-NEXT:    [[uint_ip_a:%\d+]] = OpConvertFToU %uint [[ip_a]]
+// CHECK-NEXT:                         OpStore %ip_a [[uint_ip_a]]
+// CHECK-NEXT:       [[frac_a:%\d+]] = OpCompositeExtract %float [[modf_struct_a]] 0
+// CHECK-NEXT:  [[uint_frac_a:%\d+]] = OpConvertFToU %uint [[frac_a]]
+// CHECK-NEXT:                         OpStore %frac_a [[uint_frac_a]]
+  frac_a = modf(a, ip_a);
+
+// CHECK:                 [[b:%\d+]] = OpLoad %v4int %b
+// CHECK-NEXT:           [[bf:%\d+]] = OpConvertSToF %v4float [[b]]
+// CHECK-NEXT:[[modf_struct_b:%\d+]] = OpExtInst %ModfStructType_0 [[glsl]] ModfStruct [[bf]]
+// CHECK-NEXT:         [[ip_b:%\d+]] = OpCompositeExtract %v4float [[modf_struct_b]] 1
+// CHECK-NEXT:    [[int4_ip_b:%\d+]] = OpConvertFToS %v4int [[ip_b]]
+// CHECK-NEXT:                         OpStore %ip_b [[int4_ip_b]]
+// CHECK-NEXT:       [[frac_b:%\d+]] = OpCompositeExtract %v4float [[modf_struct_b]] 0
+// CHECK-NEXT:  [[int4_frac_b:%\d+]] = OpConvertFToS %v4int [[frac_b]]
+// CHECK-NEXT:                         OpStore %frac_b [[int4_frac_b]]
+  frac_b = modf(b, ip_b);
+
+// CHECK:                      [[c:%\d+]] = OpLoad %mat2v3float %c
+// CHECK-NEXT:            [[c_row0:%\d+]] = OpCompositeExtract %v3float [[c]] 0
+// CHECK-NEXT:[[modf_struct_c_row0:%\d+]] = OpExtInst %ModfStructType_1 [[glsl]] ModfStruct [[c_row0]]
+// CHECK-NEXT:         [[ip_c_row0:%\d+]] = OpCompositeExtract %v3float [[modf_struct_c_row0]] 1
+// CHECK-NEXT:       [[frac_c_row0:%\d+]] = OpCompositeExtract %v3float [[modf_struct_c_row0]] 0
+// CHECK-NEXT:            [[c_row1:%\d+]] = OpCompositeExtract %v3float [[c]] 1
+// CHECK-NEXT:[[modf_struct_c_row1:%\d+]] = OpExtInst %ModfStructType_1 [[glsl]] ModfStruct [[c_row1]]
+// CHECK-NEXT:         [[ip_c_row1:%\d+]] = OpCompositeExtract %v3float [[modf_struct_c_row1]] 1
+// CHECK-NEXT:       [[frac_c_row1:%\d+]] = OpCompositeExtract %v3float [[modf_struct_c_row1]] 0
+// CHECK-NEXT:              [[ip_c:%\d+]] = OpCompositeConstruct %mat2v3float [[ip_c_row0]] [[ip_c_row1]]
+// CHECK-NEXT:                              OpStore %ip_c [[ip_c]]
+// CHECK-NEXT:            [[frac_c:%\d+]] = OpCompositeConstruct %mat2v3float [[frac_c_row0]] [[frac_c_row1]]
+// CHECK-NEXT:                              OpStore %frac_c [[frac_c]]
+  frac_c = modf(c, ip_c);
+}

+ 17 - 0
tools/clang/test/CodeGenSPIRV/intrinsics.reversebits.hlsl

@@ -0,0 +1,17 @@
+// Run: %dxc -T vs_6_0 -E main
+
+// According to HLSL reference:
+// The 'reversebits' function can only operate on scalar or vector of uints.
+
+void main() {
+  uint a;
+  uint4 b;
+  
+// CHECK:      [[a:%\d+]] = OpLoad %uint %a
+// CHECK-NEXT:   {{%\d+}} = OpBitReverse %uint [[a]]
+  uint  cb  = reversebits(a);
+
+// CHECK:      [[b:%\d+]] = OpLoad %v4uint %b
+// CHECK-NEXT:   {{%\d+}} = OpBitReverse %v4uint [[b]]
+  uint4 cb4 = reversebits(b);
+}

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

@@ -432,6 +432,9 @@ TEST_F(FileTest, RWTextureGetDimensions) {
 }
 
 // For intrinsic functions
+TEST_F(FileTest, IntrinsicsCountBits) {
+  runFileTest("intrinsics.countbits.hlsl");
+}
 TEST_F(FileTest, IntrinsicsDot) { runFileTest("intrinsics.dot.hlsl"); }
 TEST_F(FileTest, IntrinsicsMul) { runFileTest("intrinsics.mul.hlsl"); }
 TEST_F(FileTest, IntrinsicsAll) { runFileTest("intrinsics.all.hlsl"); }
@@ -444,6 +447,7 @@ TEST_F(FileTest, IntrinsicsAbs) { runFileTest("intrinsics.abs.hlsl"); }
 TEST_F(FileTest, IntrinsicsCross) { runFileTest("intrinsics.cross.hlsl"); }
 TEST_F(FileTest, IntrinsicsCeil) { runFileTest("intrinsics.ceil.hlsl"); }
 TEST_F(FileTest, IntrinsicsClamp) { runFileTest("intrinsics.clamp.hlsl"); }
+TEST_F(FileTest, IntrinsicsClip) { runFileTest("intrinsics.clip.hlsl"); }
 TEST_F(FileTest, IntrinsicsDegrees) { runFileTest("intrinsics.degrees.hlsl"); }
 TEST_F(FileTest, IntrinsicsDistance) {
   runFileTest("intrinsics.distance.hlsl");
@@ -464,15 +468,21 @@ TEST_F(FileTest, IntrinsicsFloor) { runFileTest("intrinsics.floor.hlsl"); }
 TEST_F(FileTest, IntrinsicsFma) { runFileTest("intrinsics.fma.hlsl"); }
 TEST_F(FileTest, IntrinsicsFmod) { runFileTest("intrinsics.fmod.hlsl"); }
 TEST_F(FileTest, IntrinsicsFrac) { runFileTest("intrinsics.frac.hlsl"); }
+TEST_F(FileTest, IntrinsicsFrexp) { runFileTest("intrinsics.frexp.hlsl"); }
 TEST_F(FileTest, IntrinsicsIsFinite) {
   runFileTest("intrinsics.isfinite.hlsl");
 }
 TEST_F(FileTest, IntrinsicsIsInf) { runFileTest("intrinsics.isinf.hlsl"); }
 TEST_F(FileTest, IntrinsicsIsNan) { runFileTest("intrinsics.isnan.hlsl"); }
 TEST_F(FileTest, IntrinsicsLength) { runFileTest("intrinsics.length.hlsl"); }
+TEST_F(FileTest, IntrinsicsLdexp) { runFileTest("intrinsics.ldexp.hlsl"); }
+TEST_F(FileTest, IntrinsicsLerp) { runFileTest("intrinsics.lerp.hlsl"); }
 TEST_F(FileTest, IntrinsicsLog) { runFileTest("intrinsics.log.hlsl"); }
+TEST_F(FileTest, IntrinsicsLog10) { runFileTest("intrinsics.log10.hlsl"); }
 TEST_F(FileTest, IntrinsicsLog2) { runFileTest("intrinsics.log2.hlsl"); }
 TEST_F(FileTest, IntrinsicsMin) { runFileTest("intrinsics.min.hlsl"); }
+TEST_F(FileTest, IntrinsicsModf) { runFileTest("intrinsics.modf.hlsl"); }
+TEST_F(FileTest, IntrinsicsMad) { runFileTest("intrinsics.mad.hlsl"); }
 TEST_F(FileTest, IntrinsicsMax) { runFileTest("intrinsics.max.hlsl"); }
 TEST_F(FileTest, IntrinsicsNormalize) {
   runFileTest("intrinsics.normalize.hlsl");
@@ -485,6 +495,9 @@ TEST_F(FileTest, IntrinsicsFloatSign) {
 TEST_F(FileTest, IntrinsicsIntSign) { runFileTest("intrinsics.intsign.hlsl"); }
 TEST_F(FileTest, IntrinsicsReflect) { runFileTest("intrinsics.reflect.hlsl"); }
 TEST_F(FileTest, IntrinsicsRefract) { runFileTest("intrinsics.refract.hlsl"); }
+TEST_F(FileTest, IntrinsicsReverseBits) {
+  runFileTest("intrinsics.reversebits.hlsl");
+}
 TEST_F(FileTest, IntrinsicsSaturate) {
   runFileTest("intrinsics.saturate.hlsl");
 }