瀏覽代碼

[spirv] Refresh dependencies and fix ldexp() translation (#962)

We cannot use GLSL extended instruction Ldexp for ldexp() since
they have different type requirements on the exponent parameter.
Lei Zhang 7 年之前
父節點
當前提交
7ff9ae75e8

+ 1 - 1
external/SPIRV-Headers

@@ -1 +1 @@
-Subproject commit 061097878467b8e040fbf153a837d844ef9f9f96
+Subproject commit 7bfaab982d2452bd990804f9815775342b3467cb

+ 1 - 1
external/SPIRV-Tools

@@ -1 +1 @@
-Subproject commit 4ba9dcc8a05bb0266e46135c6a48311dbc62524e
+Subproject commit 7834beea8017ed2db866227972539fb53ef81362

+ 1 - 1
external/effcee

@@ -1 +1 @@
-Subproject commit 4a6edb2f740b9b87b04306a7815f42de5ca149a4
+Subproject commit 2741bade14f1ab23f3b90f0e5c77c6b935fc2fff

+ 1 - 1
external/googletest

@@ -1 +1 @@
-Subproject commit d175c8bf823e709d570772b038757fadf63bc632
+Subproject commit a5014476f0c49c966e4ac602469cddefc7ed486d

+ 1 - 1
external/re2

@@ -1 +1 @@
-Subproject commit 2c220e7df3c10d42d74cb66290ec89116bb5e6be
+Subproject commit 715f0dcaafbeda5d9fef58194d9ce256f0317ecf

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

@@ -227,17 +227,8 @@ bool spirvToolsLegalize(std::vector<uint32_t> *module, std::string *messages) {
                  const spv_position_t & /*position*/,
                  const char *message) { *messages += message; });
 
-  optimizer.RegisterPass(spvtools::CreateInlineExhaustivePass());
-  optimizer.RegisterPass(spvtools::CreateEliminateDeadFunctionsPass());
-  optimizer.RegisterPass(spvtools::CreatePrivateToLocalPass());
-  optimizer.RegisterPass(spvtools::CreateScalarReplacementPass());
-  optimizer.RegisterPass(spvtools::CreateLocalMultiStoreElimPass());
-  optimizer.RegisterPass(spvtools::CreateInsertExtractElimPass());
-  optimizer.RegisterPass(spvtools::CreateCCPPass());
-  optimizer.RegisterPass(spvtools::CreateDeadBranchElimPass());
-  optimizer.RegisterPass(spvtools::CreateCFGCleanupPass());
-  optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());
-  optimizer.RegisterPass(spvtools::CreateDeadVariableEliminationPass());
+  optimizer.RegisterLegalizationPasses();
+
   optimizer.RegisterPass(spvtools::CreateCompactIdsPass());
 
   return optimizer.Run(module->data(), module->size(), module);
@@ -4937,6 +4928,9 @@ SpirvEvalInfo SPIRVEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
   case hlsl::IntrinsicOp::IOP_frexp:
     retVal = processIntrinsicFrexp(callExpr);
     break;
+  case hlsl::IntrinsicOp::IOP_ldexp:
+    retVal = processIntrinsicLdexp(callExpr);
+    break;
   case hlsl::IntrinsicOp::IOP_lit:
     retVal = processIntrinsicLit(callExpr);
     break;
@@ -5026,7 +5020,6 @@ SpirvEvalInfo 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);
@@ -5553,6 +5546,50 @@ uint32_t SPIRVEmitter::processIntrinsicFrexp(const CallExpr *callExpr) {
   return 0;
 }
 
+uint32_t SPIRVEmitter::processIntrinsicLdexp(const CallExpr *callExpr) {
+  // Signature: ret ldexp(x, exp)
+  // This function uses the following formula: x * 2^exp.
+  // Note that we cannot use GLSL extended instruction Ldexp since it requires
+  // the exponent to be an integer (vector) but HLSL takes an float (vector)
+  // exponent. So we must calculate the result manually.
+  const uint32_t glsl = theBuilder.getGLSLExtInstSet();
+  const Expr *x = callExpr->getArg(0);
+  const auto paramType = x->getType();
+  const uint32_t xId = doExpr(x);
+  const uint32_t expId = doExpr(callExpr->getArg(1));
+
+  // For scalar and vector argument types.
+  if (TypeTranslator::isScalarType(paramType) ||
+      TypeTranslator::isVectorType(paramType)) {
+    const auto paramTypeId = typeTranslator.translateType(paramType);
+    const auto twoExp = theBuilder.createExtInst(
+        paramTypeId, glsl, GLSLstd450::GLSLstd450Exp2, {expId});
+    return theBuilder.createBinaryOp(spv::Op::OpFMul, paramTypeId, xId, twoExp);
+  }
+
+  // For matrix argument types.
+  {
+    uint32_t rowCount = 0, colCount = 0;
+    if (TypeTranslator::isMxNMatrix(paramType, nullptr, &rowCount, &colCount)) {
+      const auto actOnEachVec = [this, glsl, expId](uint32_t index,
+                                                    uint32_t vecType,
+                                                    uint32_t xRowId) {
+        const auto expRowId =
+            theBuilder.createCompositeExtract(vecType, expId, {index});
+        const auto twoExp = theBuilder.createExtInst(
+            vecType, glsl, GLSLstd450::GLSLstd450Exp2, {expRowId});
+        return theBuilder.createBinaryOp(spv::Op::OpFMul, vecType, xRowId,
+                                         twoExp);
+      };
+      return processEachVectorInMatrix(x, xId, actOnEachVec);
+    }
+  }
+
+  emitError("invalid argument type passed to ldexp intrinsic function",
+            callExpr->getExprLoc());
+  return 0;
+}
+
 uint32_t SPIRVEmitter::processIntrinsicDst(const CallExpr *callExpr) {
   // Signature is float4 dst(float4 src0, float4 src1)
   // result.x = 1;

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

@@ -304,6 +304,9 @@ private:
   /// Processes the 'frexp' intrinsic function.
   uint32_t processIntrinsicFrexp(const CallExpr *);
 
+  /// Processes the 'ldexp' intrinsic function.
+  uint32_t processIntrinsicLdexp(const CallExpr *);
+
   /// Processes the 'D3DCOLORtoUBYTE4' intrinsic function.
   uint32_t processD3DCOLORtoUBYTE4(const CallExpr *);
 

+ 11 - 7
tools/clang/test/CodeGenSPIRV/intrinsics.ldexp.hlsl

@@ -12,25 +12,29 @@ void main() {
   
 // 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]]
+// CHECK-NEXT:    [[exp:%\d+]] = OpExtInst %float [[glsl]] Exp2 [[a2]]
+// CHECK-NEXT:    [[res:%\d+]] = OpFMul %float [[a1]] [[exp]]
+// CHECK-NEXT:                   OpStore %ldexp_a [[res]]
   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]]
+// CHECK-NEXT:    [[exp:%\d+]] = OpExtInst %v4float [[glsl]] Exp2 [[b2]]
+// CHECK-NEXT:    [[res:%\d+]] = OpFMul %v4float [[b1]] [[exp]]
+// CHECK-NEXT:                   OpStore %ldexp_b [[res]]
   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:         [[exp:%\d+]] = OpExtInst %v3float [[glsl]] Exp2 [[c2_row0]]
+// CHECK-NEXT:        [[res0:%\d+]] = OpFMul %v3float [[c1_row0]] [[exp]]
 // 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:         [[exp:%\d+]] = OpExtInst %v3float [[glsl]] Exp2 [[c2_row1]]
+// CHECK-NEXT:        [[res1:%\d+]] = OpFMul %v3float [[c1_row1]] [[exp]]
+// CHECK-NEXT:     [[ldexp_c:%\d+]] = OpCompositeConstruct %mat2v3float [[res0]] [[res1]]
 // CHECK-NEXT:                        OpStore %ldexp_c [[ldexp_c]]
   ldexp_c = ldexp(c1, c2);
 }