Browse Source

[spirv] Process the clamp intrinsic function (#562)

Uses SPIR-V Extended Instructions for GLSL.
Ehsan 8 years ago
parent
commit
8b2d5a0d0f

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

@@ -2399,6 +2399,9 @@ uint32_t SPIRVEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
   case hlsl::IntrinsicOp::IOP_asint:
   case hlsl::IntrinsicOp::IOP_asuint:
     return processIntrinsicAsType(callExpr);
+  case hlsl::IntrinsicOp::IOP_clamp:
+  case hlsl::IntrinsicOp::IOP_uclamp:
+    return processIntrinsicClamp(callExpr);
   case hlsl::IntrinsicOp::IOP_sign: {
     if (isFloatOrVecMatOfFloatType(callExpr->getArg(0)->getType()))
       return processIntrinsicFloatSign(callExpr);
@@ -2452,6 +2455,47 @@ uint32_t SPIRVEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
   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.
+  const uint32_t glslInstSetId = theBuilder.getGLSLExtInstSet();
+  const QualType returnType = callExpr->getType();
+  const uint32_t returnTypeId = typeTranslator.translateType(returnType);
+  GLSLstd450 glslOpcode = GLSLstd450::GLSLstd450UClamp;
+  if (isFloatOrVecMatOfFloatType(returnType))
+    glslOpcode = GLSLstd450::GLSLstd450FClamp;
+  else if (isSintOrVecMatOfSintType(returnType))
+    glslOpcode = GLSLstd450::GLSLstd450SClamp;
+
+  // Get the function parameters. Expect 3 parameters.
+  assert(callExpr->getNumArgs() == 3u);
+  const Expr *argX = callExpr->getArg(0);
+  const Expr *argMin = callExpr->getArg(1);
+  const Expr *argMax = callExpr->getArg(2);
+  const uint32_t argXId = doExpr(argX);
+  const uint32_t argMinId = doExpr(argMin);
+  const uint32_t argMaxId = doExpr(argMax);
+
+  // FClamp, UClamp, and SClamp do not operate on matrices, so we should perform
+  // the operation on each vector of the matrix.
+  if (TypeTranslator::isSpirvAcceptableMatrixType(argX->getType())) {
+    const auto actOnEachVec = [this, glslInstSetId, glslOpcode, argMinId,
+                               argMaxId](uint32_t index, uint32_t vecType,
+                                         uint32_t curRowId) {
+      const auto minRowId =
+          theBuilder.createCompositeExtract(vecType, argMinId, {index});
+      const auto maxRowId =
+          theBuilder.createCompositeExtract(vecType, argMaxId, {index});
+      return theBuilder.createExtInst(vecType, glslInstSetId, glslOpcode,
+                                      {curRowId, minRowId, maxRowId});
+    };
+    return processEachVectorInMatrix(argX, argXId, actOnEachVec);
+  }
+
+  return theBuilder.createExtInst(returnTypeId, glslInstSetId, glslOpcode,
+                                  {argXId, argMinId, argMaxId});
+}
+
 uint32_t SPIRVEmitter::processIntrinsicMul(const CallExpr *callExpr) {
   const QualType returnType = callExpr->getType();
   const uint32_t returnTypeId =

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

@@ -233,6 +233,9 @@ private:
   /// Processes HLSL instrinsic functions.
   uint32_t processIntrinsicCallExpr(const CallExpr *);
 
+  /// Processes the 'clamp' intrinsic function.
+  uint32_t processIntrinsicClamp(const CallExpr *);
+
   /// Processes the 'mul' intrinsic function.
   uint32_t processIntrinsicMul(const CallExpr *);
 

+ 44 - 0
tools/clang/test/CodeGenSPIRV/intrinsics.clamp.hlsl

@@ -0,0 +1,44 @@
+// Run: %dxc -T vs_6_0 -E main
+
+// CHECK:      [[glsl:%\d+]] = OpExtInstImport "GLSL.std.450"
+
+void main() {
+
+// CHECK:      [[int_x:%\d+]] = OpLoad %int %int_x
+// CHECK-NEXT: [[int_min:%\d+]] = OpLoad %int %int_min
+// CHECK-NEXT: [[int_max:%\d+]] = OpLoad %int %int_max
+// CHECK-NEXT: {{%\d+}} = OpExtInst %int [[glsl]] SClamp [[int_x]] [[int_min]] [[int_max]]
+  int int_x, int_min, int_max;
+  int int_result = clamp(int_x, int_min, int_max);
+
+// CHECK: {{%\d+}} = OpExtInst %v2uint [[glsl]] UClamp {{%\d+}} {{%\d+}} {{%\d+}}
+  uint2 uint2_x, uint2_min, uint2_max;
+  uint2 uint2_result = clamp(uint2_x, uint2_min, uint2_max);
+
+// CHECK: {{%\d+}} = OpExtInst %v3float [[glsl]] FClamp {{%\d+}} {{%\d+}} {{%\d+}}
+  float3 float3_x, float3_min, float3_max;
+  float3 float3_result = clamp(float3_x, float3_min, float3_max);
+
+// CHECK:      [[mat_x:%\d+]] = OpLoad %mat4v4float %float4x4_x
+// CHECK-NEXT: [[mat_min:%\d+]] = OpLoad %mat4v4float %float4x4_min
+// CHECK-NEXT: [[mat_max:%\d+]] = OpLoad %mat4v4float %float4x4_max
+// CHECK-NEXT: [[x_row0:%\d+]] = OpCompositeExtract %v4float [[mat_x]] 0
+// CHECK-NEXT: [[min_row0:%\d+]] = OpCompositeExtract %v4float [[mat_min]] 0
+// CHECK-NEXT: [[max_row0:%\d+]] = OpCompositeExtract %v4float [[mat_max]] 0
+// CHECK-NEXT: [[clamp_row0:%\d+]] = OpExtInst %v4float [[glsl]] FClamp [[x_row0]] [[min_row0]] [[max_row0]]
+// CHECK-NEXT: [[x_row1:%\d+]] = OpCompositeExtract %v4float [[mat_x]] 1
+// CHECK-NEXT: [[min_row1:%\d+]] = OpCompositeExtract %v4float [[mat_min]] 1
+// CHECK-NEXT: [[max_row1:%\d+]] = OpCompositeExtract %v4float [[mat_max]] 1
+// CHECK-NEXT: [[clamp_row1:%\d+]] = OpExtInst %v4float [[glsl]] FClamp [[x_row1]] [[min_row1]] [[max_row1]]
+// CHECK-NEXT: [[x_row2:%\d+]] = OpCompositeExtract %v4float [[mat_x]] 2
+// CHECK-NEXT: [[min_row2:%\d+]] = OpCompositeExtract %v4float [[mat_min]] 2
+// CHECK-NEXT: [[max_row2:%\d+]] = OpCompositeExtract %v4float [[mat_max]] 2
+// CHECK-NEXT: [[clamp_row2:%\d+]] = OpExtInst %v4float [[glsl]] FClamp [[x_row2]] [[min_row2]] [[max_row2]]
+// CHECK-NEXT: [[x_row3:%\d+]] = OpCompositeExtract %v4float [[mat_x]] 3
+// CHECK-NEXT: [[min_row3:%\d+]] = OpCompositeExtract %v4float [[mat_min]] 3
+// CHECK-NEXT: [[max_row3:%\d+]] = OpCompositeExtract %v4float [[mat_max]] 3
+// CHECK-NEXT: [[clamp_row3:%\d+]] = OpExtInst %v4float [[glsl]] FClamp [[x_row3]] [[min_row3]] [[max_row3]]
+// CHECK-NEXT: {{%\d+}} = OpCompositeConstruct %mat4v4float [[clamp_row0]] [[clamp_row1]] [[clamp_row2]] [[clamp_row3]]
+  float4x4 float4x4_x, float4x4_min, float4x4_max;
+  float4x4 float4x4_result = clamp(float4x4_x, float4x4_min, float4x4_max);
+}

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

@@ -283,6 +283,7 @@ TEST_F(FileTest, IntrinsicsRound) { runFileTest("intrinsics.round.hlsl"); }
 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, IntrinsicsDegrees) { runFileTest("intrinsics.degrees.hlsl"); }
 TEST_F(FileTest, IntrinsicsRadians) { runFileTest("intrinsics.radians.hlsl"); }
 TEST_F(FileTest, IntrinsicsDeterminant) {