[clang] [llvm] [HLSL] Implement the `degrees` intrinsic (PR #111209)

Finn Plummer via cfe-commits cfe-commits at lists.llvm.org
Thu Oct 10 11:59:45 PDT 2024


https://github.com/inbelic updated https://github.com/llvm/llvm-project/pull/111209

>From 398dcb5c1a354c12d4d43af152f6d3e14f001274 Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienfinn at gmail.com>
Date: Wed, 2 Oct 2024 13:30:33 -0700
Subject: [PATCH 1/3] [HLSL] Implementation the `degrees` intrinsic

    - add degrees builtin
    - link degrees api in hlsl_intrinsics.h
    - add degrees intrinsic to IntrinsicDirectX.td
    - add degrees intrinsic to IntrinsicSPIRV.td
    - add lowering from clang builtin to dx/spv intrinsics in
      CGBuiltin.cpp
    - add semantic checks to SemaHLSL.cpp
    - add expansion of directx intrinsic to llvm fmul for DirectX in
      DXILIntrinsicExpansion.cpp
    - add mapping to spir-v intrinsic in SPIRVInstructionSelector.cpp

    - add test coverage:
        - degrees.hlsl -> check hlsl lowering to dx/spv degrees intrinsics
        - degrees-errors.hlsl/half-float-only-errors ->
            check semantic warnings
        - hlsl-intrinsics/degrees.ll -> check lowering of spir-v
            degrees intrinsic to SPIR-V backend
        - DirectX/degrees.ll -> check expansion and scalarization of
          directx degrees intrinsic to fmul
---
 clang/include/clang/Basic/Builtins.td         |  6 ++
 clang/lib/CodeGen/CGBuiltin.cpp               | 11 +++
 clang/lib/CodeGen/CGHLSLRuntime.h             |  1 +
 clang/lib/Headers/hlsl/hlsl_intrinsics.h      | 30 ++++++++
 clang/lib/Sema/SemaHLSL.cpp                   |  1 +
 clang/test/CodeGenHLSL/builtins/degrees.hlsl  | 64 +++++++++++++++++
 .../SemaHLSL/BuiltIns/degrees-errors.hlsl     | 26 +++++++
 .../BuiltIns/half-float-only-errors.hlsl      |  1 +
 llvm/include/llvm/IR/IntrinsicsDirectX.td     |  1 +
 llvm/include/llvm/IR/IntrinsicsSPIRV.td       |  1 +
 .../Target/DirectX/DXILIntrinsicExpansion.cpp | 12 ++++
 .../Target/SPIRV/SPIRVInstructionSelector.cpp |  2 +
 llvm/test/CodeGen/DirectX/degrees.ll          | 54 +++++++++++++++
 .../CodeGen/SPIRV/hlsl-intrinsics/degrees.ll  | 68 +++++++++++++++++++
 llvm/test/CodeGen/SPIRV/opencl/degrees.ll     | 50 ++++++++++++++
 15 files changed, 328 insertions(+)
 create mode 100644 clang/test/CodeGenHLSL/builtins/degrees.hlsl
 create mode 100644 clang/test/SemaHLSL/BuiltIns/degrees-errors.hlsl
 create mode 100644 llvm/test/CodeGen/DirectX/degrees.ll
 create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/degrees.ll
 create mode 100644 llvm/test/CodeGen/SPIRV/opencl/degrees.ll

diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 5b504666365b32..44142298987f12 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4739,6 +4739,12 @@ def HLSLClamp : LangBuiltin<"HLSL_LANG"> {
   let Prototype = "void(...)";
 }
 
+def HLSLDegrees : LangBuiltin<"HLSL_LANG"> {
+  let Spellings = ["__builtin_hlsl_elementwise_degrees"];
+  let Attributes = [NoThrow, Const];
+  let Prototype = "void(...)";
+}
+
 def HLSLDotProduct : LangBuiltin<"HLSL_LANG"> {
   let Spellings = ["__builtin_hlsl_dot"];
   let Attributes = [NoThrow, Const];
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index c864714182e019..0f824fc2c4431a 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -18740,6 +18740,17 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
         CGM.getHLSLRuntime().getNormalizeIntrinsic(), ArrayRef<Value *>{X},
         nullptr, "hlsl.normalize");
   }
+  case Builtin::BI__builtin_hlsl_elementwise_degrees: {
+    Value *X = EmitScalarExpr(E->getArg(0));
+
+    assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
+        "degree operand must have a float representation");
+
+    return Builder.CreateIntrinsic(
+        /*ReturnType=*/X->getType(),
+        CGM.getHLSLRuntime().getDegreesIntrinsic(),
+        ArrayRef<Value *>{X}, nullptr, "hlsl.degrees");
+  }
   case Builtin::BI__builtin_hlsl_elementwise_frac: {
     Value *Op0 = EmitScalarExpr(E->getArg(0));
     if (!E->getArg(0)->getType()->hasFloatingRepresentation())
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index a8aabca7348ffb..966111a9600017 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -74,6 +74,7 @@ class CGHLSLRuntime {
 
   GENERATE_HLSL_INTRINSIC_FUNCTION(All, all)
   GENERATE_HLSL_INTRINSIC_FUNCTION(Any, any)
+  GENERATE_HLSL_INTRINSIC_FUNCTION(Degrees, degrees)
   GENERATE_HLSL_INTRINSIC_FUNCTION(Frac, frac)
   GENERATE_HLSL_INTRINSIC_FUNCTION(Length, length)
   GENERATE_HLSL_INTRINSIC_FUNCTION(Lerp, lerp)
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index d28f204e352de5..07004a48f96128 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -766,6 +766,36 @@ uint64_t3 countbits(uint64_t3);
 _HLSL_BUILTIN_ALIAS(__builtin_elementwise_popcount)
 uint64_t4 countbits(uint64_t4);
 
+//===----------------------------------------------------------------------===//
+// degrees builtins
+//===----------------------------------------------------------------------===//
+
+/// \fn T degrees(T x)
+/// \brief Converts the specified value from radians to degrees.
+/// \param x The specified input value.
+
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees)
+half degrees(half);
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees)
+half2 degrees(half2);
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees)
+half3 degrees(half3);
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees)
+half4 degrees(half4);
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees)
+float degrees(float);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees)
+float2 degrees(float2);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees)
+float3 degrees(float3);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees)
+float4 degrees(float4);
+
 //===----------------------------------------------------------------------===//
 // dot product builtins
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 5eda22f560c9d2..7e971e9fc92e05 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -1861,6 +1861,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
       return true;
     break;
   }
+  case Builtin::BI__builtin_hlsl_elementwise_degrees:
   case Builtin::BI__builtin_hlsl_elementwise_rsqrt:
   case Builtin::BI__builtin_hlsl_elementwise_frac: {
     if (CheckFloatOrHalfRepresentations(&SemaRef, TheCall))
diff --git a/clang/test/CodeGenHLSL/builtins/degrees.hlsl b/clang/test/CodeGenHLSL/builtins/degrees.hlsl
new file mode 100644
index 00000000000000..b861be2e79fa2c
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/degrees.hlsl
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN:   dxil-pc-shadermodel6.3-library %s -fnative-half-type \
+// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s \
+// RUN:   --check-prefixes=CHECK,NATIVE_HALF \
+// RUN:   -DFNATTRS=noundef -DTARGET=dx
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN:   dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \
+// RUN:   -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \
+// RUN:   -DFNATTRS=noundef -DTARGET=dx
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN:   spirv-unknown-vulkan-compute %s -fnative-half-type \
+// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s \
+// RUN:   --check-prefixes=CHECK,NATIVE_HALF \
+// RUN:   -DFNATTRS="spir_func noundef" -DTARGET=spv
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN:   spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \
+// RUN:   -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \
+// RUN:   -DFNATTRS="spir_func noundef" -DTARGET=spv
+
+// NATIVE_HALF: define [[FNATTRS]] half @
+// NATIVE_HALF: %hlsl.degrees = call half @llvm.[[TARGET]].degrees.f16(
+// NATIVE_HALF: ret half %hlsl.degrees
+// NO_HALF: define [[FNATTRS]] float @
+// NO_HALF: %hlsl.degrees = call float @llvm.[[TARGET]].degrees.f32(
+// NO_HALF: ret float %hlsl.degrees
+half test_degrees_half(half p0) { return degrees(p0); }
+// NATIVE_HALF: define [[FNATTRS]] <2 x half> @
+// NATIVE_HALF: %hlsl.degrees = call <2 x half> @llvm.[[TARGET]].degrees.v2f16
+// NATIVE_HALF: ret <2 x half> %hlsl.degrees
+// NO_HALF: define [[FNATTRS]] <2 x float> @
+// NO_HALF: %hlsl.degrees = call <2 x float> @llvm.[[TARGET]].degrees.v2f32(
+// NO_HALF: ret <2 x float> %hlsl.degrees
+half2 test_degrees_half2(half2 p0) { return degrees(p0); }
+// NATIVE_HALF: define [[FNATTRS]] <3 x half> @
+// NATIVE_HALF: %hlsl.degrees = call <3 x half> @llvm.[[TARGET]].degrees.v3f16
+// NATIVE_HALF: ret <3 x half> %hlsl.degrees
+// NO_HALF: define [[FNATTRS]] <3 x float> @
+// NO_HALF: %hlsl.degrees = call <3 x float> @llvm.[[TARGET]].degrees.v3f32(
+// NO_HALF: ret <3 x float> %hlsl.degrees
+half3 test_degrees_half3(half3 p0) { return degrees(p0); }
+// NATIVE_HALF: define [[FNATTRS]] <4 x half> @
+// NATIVE_HALF: %hlsl.degrees = call <4 x half> @llvm.[[TARGET]].degrees.v4f16
+// NATIVE_HALF: ret <4 x half> %hlsl.degrees
+// NO_HALF: define [[FNATTRS]] <4 x float> @
+// NO_HALF: %hlsl.degrees = call <4 x float> @llvm.[[TARGET]].degrees.v4f32(
+// NO_HALF: ret <4 x float> %hlsl.degrees
+half4 test_degrees_half4(half4 p0) { return degrees(p0); }
+
+// CHECK: define [[FNATTRS]] float @
+// CHECK: %hlsl.degrees = call float @llvm.[[TARGET]].degrees.f32(
+// CHECK: ret float %hlsl.degrees
+float test_degrees_float(float p0) { return degrees(p0); }
+// CHECK: define [[FNATTRS]] <2 x float> @
+// CHECK: %hlsl.degrees = call <2 x float> @llvm.[[TARGET]].degrees.v2f32
+// CHECK: ret <2 x float> %hlsl.degrees
+float2 test_degrees_float2(float2 p0) { return degrees(p0); }
+// CHECK: define [[FNATTRS]] <3 x float> @
+// CHECK: %hlsl.degrees = call <3 x float> @llvm.[[TARGET]].degrees.v3f32
+// CHECK: ret <3 x float> %hlsl.degrees
+float3 test_degrees_float3(float3 p0) { return degrees(p0); }
+// CHECK: define [[FNATTRS]] <4 x float> @
+// CHECK: %hlsl.degrees = call <4 x float> @llvm.[[TARGET]].degrees.v4f32
+// CHECK: ret <4 x float> %hlsl.degrees
+float4 test_degrees_float4(float4 p0) { return degrees(p0); }
diff --git a/clang/test/SemaHLSL/BuiltIns/degrees-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/degrees-errors.hlsl
new file mode 100644
index 00000000000000..e39ffda4696940
--- /dev/null
+++ b/clang/test/SemaHLSL/BuiltIns/degrees-errors.hlsl
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm-only -disable-llvm-passes -verify -verify-ignore-unexpected
+
+float test_too_few_arg() {
+  return __builtin_hlsl_elementwise_degrees();
+  // expected-error at -1 {{too few arguments to function call, expected 1, have 0}}
+}
+
+float2 test_too_many_arg(float2 p0) {
+  return __builtin_hlsl_elementwise_degrees(p0, p0);
+  // expected-error at -1 {{too many arguments to function call, expected 1, have 2}}
+}
+
+float builtin_bool_to_float_type_promotion(bool p1) {
+  return __builtin_hlsl_elementwise_degrees(p1);
+  // expected-error at -1 {{passing 'bool' to parameter of incompatible type 'float'}}
+}
+
+float builtin_degrees_int_to_float_promotion(int p1) {
+  return __builtin_hlsl_elementwise_degrees(p1);
+  // expected-error at -1 {{passing 'int' to parameter of incompatible type 'float'}}
+}
+
+float2 builtin_degrees_int2_to_float2_promotion(int2 p1) {
+  return __builtin_hlsl_elementwise_degrees(p1);
+  // expected-error at -1 {{passing 'int2' (aka 'vector<int, 2>') to parameter of incompatible type '__attribute__((__vector_size__(2 * sizeof(float)))) float' (vector of 2 'float' values)}}
+}
diff --git a/clang/test/SemaHLSL/BuiltIns/half-float-only-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/half-float-only-errors.hlsl
index 0c1f7022bad609..c12a230ea6f4eb 100644
--- a/clang/test/SemaHLSL/BuiltIns/half-float-only-errors.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/half-float-only-errors.hlsl
@@ -17,6 +17,7 @@
 // RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm-only -disable-llvm-passes -verify -DTEST_FUNC=__builtin_elementwise_tan
 // RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm-only -disable-llvm-passes -verify -DTEST_FUNC=__builtin_elementwise_tanh
 // RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm-only -disable-llvm-passes -verify -DTEST_FUNC=__builtin_elementwise_trunc
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm-only -disable-llvm-passes -verify -DTEST_FUNC=__builtin_hlsl_elementwise_degrees
 
 double test_double_builtin(double p0) {
     return TEST_FUNC(p0);
diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td
index 81d7e55047c77c..caacb65ac18837 100644
--- a/llvm/include/llvm/IR/IntrinsicsDirectX.td
+++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td
@@ -70,6 +70,7 @@ def int_dx_udot :
     [IntrNoMem, Commutative] >;
 
 def int_dx_frac  : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>;
+def int_dx_degrees : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty], [IntrNoMem]>;
 
 def int_dx_isinf : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i1_ty>],
     [llvm_anyfloat_ty], [IntrNoMem]>;
diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
index efe19f5a8370e5..ee61793bbea241 100644
--- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td
+++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
@@ -61,6 +61,7 @@ let TargetPrefix = "spv" in {
   def int_spv_thread_id : Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem, IntrWillReturn]>;
   def int_spv_all : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_any_ty], [IntrNoMem]>;
   def int_spv_any : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_any_ty], [IntrNoMem]>;
+  def int_spv_degrees : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty], [IntrNoMem]>;
   def int_spv_frac : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty], [IntrNoMem]>;
   def int_spv_lerp : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty, LLVMMatchType<0>,LLVMMatchType<0>],
     [IntrNoMem] >;
diff --git a/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp b/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
index fca5af9d19141e..0cb0dc4c48e541 100644
--- a/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
+++ b/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
@@ -55,6 +55,7 @@ static bool isIntrinsicExpansion(Function &F) {
   case Intrinsic::dx_any:
   case Intrinsic::dx_clamp:
   case Intrinsic::dx_uclamp:
+  case Intrinsic::dx_degrees:
   case Intrinsic::dx_lerp:
   case Intrinsic::dx_length:
   case Intrinsic::dx_normalize:
@@ -444,6 +445,14 @@ static Value *expandClampIntrinsic(CallInst *Orig,
                                  {MaxCall, Max}, nullptr, "dx.min");
 }
 
+static Value *expandDegreesIntrinsic(CallInst *Orig) {
+  Value *X = Orig->getOperand(0);
+  Type *Ty = X->getType();
+  IRBuilder<> Builder(Orig);
+  Value *DegreesRatio = ConstantFP::get(Ty, 180.0 * llvm::numbers::inv_pi);
+  return Builder.CreateFMul(X, DegreesRatio);
+}
+
 static Value *expandSignIntrinsic(CallInst *Orig) {
   Value *X = Orig->getOperand(0);
   Type *Ty = X->getType();
@@ -500,6 +509,9 @@ static bool expandIntrinsic(Function &F, CallInst *Orig) {
   case Intrinsic::dx_clamp:
     Result = expandClampIntrinsic(Orig, IntrinsicId);
     break;
+  case Intrinsic::dx_degrees:
+    Result = expandDegreesIntrinsic(Orig);
+    break;
   case Intrinsic::dx_lerp:
     Result = expandLerpIntrinsic(Orig);
     break;
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index c1a0cd9837d146..103103050d412c 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -2504,6 +2504,8 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
     return selectExtInst(ResVReg, ResType, I, CL::mix, GL::FMix);
   case Intrinsic::spv_length:
     return selectExtInst(ResVReg, ResType, I, CL::length, GL::Length);
+  case Intrinsic::spv_degrees:
+    return selectExtInst(ResVReg, ResType, I, CL::degrees, GL::Degrees);
   case Intrinsic::spv_frac:
     return selectExtInst(ResVReg, ResType, I, CL::fract, GL::Fract);
   case Intrinsic::spv_normalize:
diff --git a/llvm/test/CodeGen/DirectX/degrees.ll b/llvm/test/CodeGen/DirectX/degrees.ll
new file mode 100644
index 00000000000000..3cc4edadaa5e93
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/degrees.ll
@@ -0,0 +1,54 @@
+; RUN: opt -S -dxil-intrinsic-expansion -scalarizer -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
+
+; Make sure dxil op function calls for degrees are expanded and lowered as fmul for float and half.
+
+define noundef half @degrees_half(half noundef %a) {
+; CHECK-LABEL: define noundef half @degrees_half(
+; CHECK-SAME: half noundef [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[DX_DEGREES1:%.*]] = fmul half [[A]], 0xH5329
+; CHECK-NEXT:    ret half [[DX_DEGREES1]]
+;
+entry:
+  %dx.degrees = call half @llvm.dx.degrees.f16(half %a)
+  ret half %dx.degrees
+}
+
+define noundef float @degrees_float(float noundef %a) #0 {
+; CHECK-LABEL: define noundef float @degrees_float(
+; CHECK-SAME: float noundef [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[DX_DEGREES1:%.*]] = fmul float [[A]], 0x404CA5DC20000000
+; CHECK-NEXT:    ret float [[DX_DEGREES1]]
+;
+entry:
+  %dx.degrees = call float @llvm.dx.degrees.f32(float %a)
+  ret float %dx.degrees
+}
+
+define noundef <4 x float> @degrees_float4(<4 x float> noundef %a) #0 {
+; CHECK-LABEL: define noundef <4 x float> @degrees_float4(
+; CHECK-SAME: <4 x float> noundef [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[A_I0:%.*]] = extractelement <4 x float> [[A]], i64 0
+; CHECK-NEXT:    [[DOTI04:%.*]] = fmul float [[A_I0]], 0x404CA5DC20000000
+; CHECK-NEXT:    [[A_I1:%.*]] = extractelement <4 x float> [[A]], i64 1
+; CHECK-NEXT:    [[DOTI13:%.*]] = fmul float [[A_I1]], 0x404CA5DC20000000
+; CHECK-NEXT:    [[A_I2:%.*]] = extractelement <4 x float> [[A]], i64 2
+; CHECK-NEXT:    [[DOTI22:%.*]] = fmul float [[A_I2]], 0x404CA5DC20000000
+; CHECK-NEXT:    [[A_I3:%.*]] = extractelement <4 x float> [[A]], i64 3
+; CHECK-NEXT:    [[DOTI31:%.*]] = fmul float [[A_I3]], 0x404CA5DC20000000
+; CHECK-NEXT:    [[DOTUPTO0:%.*]] = insertelement <4 x float> poison, float [[DOTI04]], i64 0
+; CHECK-NEXT:    [[DOTUPTO1:%.*]] = insertelement <4 x float> [[DOTUPTO0]], float [[DOTI13]], i64 1
+; CHECK-NEXT:    [[DOTUPTO2:%.*]] = insertelement <4 x float> [[DOTUPTO1]], float [[DOTI22]], i64 2
+; CHECK-NEXT:    [[TMP0:%.*]] = insertelement <4 x float> [[DOTUPTO2]], float [[DOTI31]], i64 3
+; CHECK-NEXT:    ret <4 x float> [[TMP0]]
+;
+entry:
+  %2 = call <4 x float> @llvm.dx.degrees.v4f32(<4 x float> %a)
+  ret <4 x float> %2
+}
+
+declare half  @llvm.dx.degrees.f16(half)
+declare float @llvm.dx.degrees.f32(float)
+declare <4 x float> @llvm.dx.degrees.v4f32(<4 x float>)
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/degrees.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/degrees.ll
new file mode 100644
index 00000000000000..ce648e0e51ba2c
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/degrees.ll
@@ -0,0 +1,68 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "GLSL.std.450"
+
+; CHECK-DAG: %[[#float_32:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#float_16:]] = OpTypeFloat 16
+; CHECK-DAG: %[[#float_64:]] = OpTypeFloat 64
+
+; CHECK-DAG: %[[#vec4_float_32:]] = OpTypeVector %[[#float_32]] 4
+; CHECK-DAG: %[[#vec4_float_16:]] = OpTypeVector %[[#float_16]] 4
+; CHECK-DAG: %[[#vec4_float_64:]] = OpTypeVector %[[#float_64]] 4
+
+define noundef float @degrees_float(float noundef %a) {
+entry:
+; CHECK: %[[#float_32_arg:]] = OpFunctionParameter %[[#float_32]]
+; CHECK: %[[#]] = OpExtInst %[[#float_32]] %[[#op_ext_glsl]] Degrees %[[#float_32_arg]]
+  %elt.degrees = call float @llvm.spv.degrees.f32(float %a)
+  ret float %elt.degrees
+}
+
+define noundef half @degrees_half(half noundef %a) {
+entry:
+; CHECK: %[[#float_16_arg:]] = OpFunctionParameter %[[#float_16]]
+; CHECK: %[[#]] = OpExtInst %[[#float_16]] %[[#op_ext_glsl]] Degrees %[[#float_16_arg]]
+  %elt.degrees = call half @llvm.spv.degrees.f16(half %a)
+  ret half %elt.degrees
+}
+
+define noundef double @degrees_double(double noundef %a) {
+entry:
+; CHECK: %[[#float_64_arg:]] = OpFunctionParameter %[[#float_64]]
+; CHECK: %[[#]] = OpExtInst %[[#float_64]] %[[#op_ext_glsl]] Degrees %[[#float_64_arg]]
+  %elt.degrees = call double @llvm.spv.degrees.f64(double %a)
+  ret double %elt.degrees
+}
+
+define noundef <4 x float> @degrees_float_vector(<4 x float> noundef %a) {
+entry:
+; CHECK: %[[#vec4_float_32_arg:]] = OpFunctionParameter %[[#vec4_float_32]]
+; CHECK: %[[#]] = OpExtInst %[[#vec4_float_32]] %[[#op_ext_glsl]] Degrees %[[#vec4_float_32_arg]]
+  %elt.degrees = call <4 x float> @llvm.spv.degrees.v4f32(<4 x float> %a)
+  ret <4 x float> %elt.degrees
+}
+
+define noundef <4 x half> @degrees_half_vector(<4 x half> noundef %a) {
+entry:
+; CHECK: %[[#vec4_float_16_arg:]] = OpFunctionParameter %[[#vec4_float_16]]
+; CHECK: %[[#]] = OpExtInst %[[#vec4_float_16]] %[[#op_ext_glsl]] Degrees %[[#vec4_float_16_arg]]
+  %elt.degrees = call <4 x half> @llvm.spv.degrees.v4f16(<4 x half> %a)
+  ret <4 x half> %elt.degrees
+}
+
+define noundef <4 x double> @degrees_double_vector(<4 x double> noundef %a) {
+entry:
+; CHECK: %[[#vec4_float_64_arg:]] = OpFunctionParameter %[[#vec4_float_64]]
+; CHECK: %[[#]] = OpExtInst %[[#vec4_float_64]] %[[#op_ext_glsl]] Degrees %[[#vec4_float_64_arg]]
+  %elt.degrees = call <4 x double> @llvm.spv.degrees.v4f64(<4 x double> %a)
+  ret <4 x double> %elt.degrees
+}
+
+declare half @llvm.spv.degrees.f16(half)
+declare float @llvm.spv.degrees.f32(float)
+declare double @llvm.spv.degrees.f64(double)
+
+declare <4 x float> @llvm.spv.degrees.v4f32(<4 x float>)
+declare <4 x half> @llvm.spv.degrees.v4f16(<4 x half>)
+declare <4 x double> @llvm.spv.degrees.v4f64(<4 x double>)
diff --git a/llvm/test/CodeGen/SPIRV/opencl/degrees.ll b/llvm/test/CodeGen/SPIRV/opencl/degrees.ll
new file mode 100644
index 00000000000000..88f97835fe7194
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/opencl/degrees.ll
@@ -0,0 +1,50 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "OpenCL.std"
+
+; CHECK-DAG: %[[#float_32:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#float_16:]] = OpTypeFloat 16
+
+; CHECK-DAG: %[[#vec4_float_32:]] = OpTypeVector %[[#float_32]] 4
+; CHECK-DAG: %[[#vec4_float_16:]] = OpTypeVector %[[#float_16]] 4
+
+declare half @llvm.spv.degrees.f16(half)
+declare float @llvm.spv.degrees.f32(float)
+
+declare <4 x float> @llvm.spv.degrees.v4f32(<4 x float>)
+declare <4 x half> @llvm.spv.degrees.v4f16(<4 x half>)
+
+define noundef float @degrees_float(float noundef %a) {
+entry:
+; CHECK: %[[#float_32_arg:]] = OpFunctionParameter %[[#float_32]]
+; CHECK: %[[#]] = OpExtInst %[[#float_32]] %[[#op_ext_glsl]] degrees %[[#float_32_arg]]
+  %elt.degrees = call float @llvm.spv.degrees.f32(float %a)
+  ret float %elt.degrees
+}
+
+define noundef half @degrees_half(half noundef %a) {
+entry:
+; CHECK: %[[#float_16_arg:]] = OpFunctionParameter %[[#float_16]]
+; CHECK: %[[#]] = OpExtInst %[[#float_16]] %[[#op_ext_glsl]] degrees %[[#float_16_arg]]
+  %elt.degrees = call half @llvm.spv.degrees.f16(half %a)
+  ret half %elt.degrees
+}
+
+define noundef <4 x float> @degrees_float_vector(<4 x float> noundef %a) {
+entry:
+; CHECK: %[[#vec4_float_32_arg:]] = OpFunctionParameter %[[#vec4_float_32]]
+; CHECK: %[[#]] = OpExtInst %[[#vec4_float_32]] %[[#op_ext_glsl]] degrees %[[#vec4_float_32_arg]]
+  %elt.degrees = call <4 x float> @llvm.spv.degrees.v4f32(<4 x float> %a)
+  ret <4 x float> %elt.degrees
+}
+
+define noundef <4 x half> @degrees_half_vector(<4 x half> noundef %a) {
+entry:
+; CHECK: %[[#vec4_float_16_arg:]] = OpFunctionParameter %[[#vec4_float_16]]
+; CHECK: %[[#]] = OpExtInst %[[#vec4_float_16]] %[[#op_ext_glsl]] degrees %[[#vec4_float_16_arg]]
+  %elt.degrees = call <4 x half> @llvm.spv.degrees.v4f16(<4 x half> %a)
+  ret <4 x half> %elt.degrees
+}

>From f7f55b9613775f4e77acf50b3a3ea13d09252c1f Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienfinn at gmail.com>
Date: Wed, 9 Oct 2024 13:54:20 -0700
Subject: [PATCH 2/3] review comments:

improve testcases:
    - remove flags that were not needed
    - improve readability of FileCheck variables
    - add CHECK-LABEL to spirv check
---
 clang/test/CodeGenHLSL/builtins/degrees.hlsl  |  8 ++---
 .../SemaHLSL/BuiltIns/degrees-errors.hlsl     |  2 +-
 llvm/test/CodeGen/DirectX/degrees.ll          | 34 +++++++++----------
 .../CodeGen/SPIRV/hlsl-intrinsics/degrees.ll  |  6 ++++
 4 files changed, 28 insertions(+), 22 deletions(-)

diff --git a/clang/test/CodeGenHLSL/builtins/degrees.hlsl b/clang/test/CodeGenHLSL/builtins/degrees.hlsl
index b861be2e79fa2c..9e131f4badc19a 100644
--- a/clang/test/CodeGenHLSL/builtins/degrees.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/degrees.hlsl
@@ -1,18 +1,18 @@
-// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN: %clang_cc1 -finclude-default-header -triple \
 // RUN:   dxil-pc-shadermodel6.3-library %s -fnative-half-type \
 // RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s \
 // RUN:   --check-prefixes=CHECK,NATIVE_HALF \
 // RUN:   -DFNATTRS=noundef -DTARGET=dx
-// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN: %clang_cc1 -finclude-default-header -triple \
 // RUN:   dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \
 // RUN:   -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \
 // RUN:   -DFNATTRS=noundef -DTARGET=dx
-// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN: %clang_cc1 -finclude-default-header -triple \
 // RUN:   spirv-unknown-vulkan-compute %s -fnative-half-type \
 // RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s \
 // RUN:   --check-prefixes=CHECK,NATIVE_HALF \
 // RUN:   -DFNATTRS="spir_func noundef" -DTARGET=spv
-// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN: %clang_cc1 -finclude-default-header -triple \
 // RUN:   spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \
 // RUN:   -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \
 // RUN:   -DFNATTRS="spir_func noundef" -DTARGET=spv
diff --git a/clang/test/SemaHLSL/BuiltIns/degrees-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/degrees-errors.hlsl
index e39ffda4696940..9e981f6973572d 100644
--- a/clang/test/SemaHLSL/BuiltIns/degrees-errors.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/degrees-errors.hlsl
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm-only -disable-llvm-passes -verify -verify-ignore-unexpected
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -emit-llvm-only -disable-llvm-passes -verify
 
 float test_too_few_arg() {
   return __builtin_hlsl_elementwise_degrees();
diff --git a/llvm/test/CodeGen/DirectX/degrees.ll b/llvm/test/CodeGen/DirectX/degrees.ll
index 3cc4edadaa5e93..b38ac13d5f24e2 100644
--- a/llvm/test/CodeGen/DirectX/degrees.ll
+++ b/llvm/test/CodeGen/DirectX/degrees.ll
@@ -17,9 +17,9 @@ entry:
 define noundef float @degrees_float(float noundef %a) #0 {
 ; CHECK-LABEL: define noundef float @degrees_float(
 ; CHECK-SAME: float noundef [[A:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[DX_DEGREES1:%.*]] = fmul float [[A]], 0x404CA5DC20000000
-; CHECK-NEXT:    ret float [[DX_DEGREES1]]
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[DEGREES:%.*]] = fmul float [[A]], 0x404CA5DC20000000
+; CHECK-NEXT:    ret float [[DEGREES]]
 ;
 entry:
   %dx.degrees = call float @llvm.dx.degrees.f32(float %a)
@@ -29,20 +29,20 @@ entry:
 define noundef <4 x float> @degrees_float4(<4 x float> noundef %a) #0 {
 ; CHECK-LABEL: define noundef <4 x float> @degrees_float4(
 ; CHECK-SAME: <4 x float> noundef [[A:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[A_I0:%.*]] = extractelement <4 x float> [[A]], i64 0
-; CHECK-NEXT:    [[DOTI04:%.*]] = fmul float [[A_I0]], 0x404CA5DC20000000
-; CHECK-NEXT:    [[A_I1:%.*]] = extractelement <4 x float> [[A]], i64 1
-; CHECK-NEXT:    [[DOTI13:%.*]] = fmul float [[A_I1]], 0x404CA5DC20000000
-; CHECK-NEXT:    [[A_I2:%.*]] = extractelement <4 x float> [[A]], i64 2
-; CHECK-NEXT:    [[DOTI22:%.*]] = fmul float [[A_I2]], 0x404CA5DC20000000
-; CHECK-NEXT:    [[A_I3:%.*]] = extractelement <4 x float> [[A]], i64 3
-; CHECK-NEXT:    [[DOTI31:%.*]] = fmul float [[A_I3]], 0x404CA5DC20000000
-; CHECK-NEXT:    [[DOTUPTO0:%.*]] = insertelement <4 x float> poison, float [[DOTI04]], i64 0
-; CHECK-NEXT:    [[DOTUPTO1:%.*]] = insertelement <4 x float> [[DOTUPTO0]], float [[DOTI13]], i64 1
-; CHECK-NEXT:    [[DOTUPTO2:%.*]] = insertelement <4 x float> [[DOTUPTO1]], float [[DOTI22]], i64 2
-; CHECK-NEXT:    [[TMP0:%.*]] = insertelement <4 x float> [[DOTUPTO2]], float [[DOTI31]], i64 3
-; CHECK-NEXT:    ret <4 x float> [[TMP0]]
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[A0:%.*]] = extractelement <4 x float> [[A]], i64 0
+; CHECK-NEXT:    [[DEGREES_A0:%.*]] = fmul float [[A0]], 0x404CA5DC20000000
+; CHECK-NEXT:    [[A1:%.*]] = extractelement <4 x float> [[A]], i64 1
+; CHECK-NEXT:    [[DEGREES_A1:%.*]] = fmul float [[A1]], 0x404CA5DC20000000
+; CHECK-NEXT:    [[A2:%.*]] = extractelement <4 x float> [[A]], i64 2
+; CHECK-NEXT:    [[DEGREES_A2:%.*]] = fmul float [[A2]], 0x404CA5DC20000000
+; CHECK-NEXT:    [[A3:%.*]] = extractelement <4 x float> [[A]], i64 3
+; CHECK-NEXT:    [[DEGREES_A3:%.*]] = fmul float [[A3]], 0x404CA5DC20000000
+; CHECK-NEXT:    [[INSERT_0:%.*]] = insertelement <4 x float> poison, float [[DEGREES_A0]], i64 0
+; CHECK-NEXT:    [[INSERT_1:%.*]] = insertelement <4 x float> [[INSERT_0]], float [[DEGREES_A1]], i64 1
+; CHECK-NEXT:    [[INSERT_2:%.*]] = insertelement <4 x float> [[INSERT_1]], float [[DEGREES_A2]], i64 2
+; CHECK-NEXT:    [[RES:%.*]] = insertelement <4 x float> [[INSERT_2]], float [[DEGREES_A3]], i64 3
+; CHECK-NEXT:    ret <4 x float> [[RES]]
 ;
 entry:
   %2 = call <4 x float> @llvm.dx.degrees.v4f32(<4 x float> %a)
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/degrees.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/degrees.ll
index ce648e0e51ba2c..58383b72757eb9 100644
--- a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/degrees.ll
+++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/degrees.ll
@@ -11,6 +11,7 @@
 ; CHECK-DAG: %[[#vec4_float_16:]] = OpTypeVector %[[#float_16]] 4
 ; CHECK-DAG: %[[#vec4_float_64:]] = OpTypeVector %[[#float_64]] 4
 
+; CHECK-LABEL: Begin function degrees_float
 define noundef float @degrees_float(float noundef %a) {
 entry:
 ; CHECK: %[[#float_32_arg:]] = OpFunctionParameter %[[#float_32]]
@@ -19,6 +20,7 @@ entry:
   ret float %elt.degrees
 }
 
+; CHECK-LABEL: Begin function degrees_half
 define noundef half @degrees_half(half noundef %a) {
 entry:
 ; CHECK: %[[#float_16_arg:]] = OpFunctionParameter %[[#float_16]]
@@ -27,6 +29,7 @@ entry:
   ret half %elt.degrees
 }
 
+; CHECK-LABEL: Begin function degrees_double
 define noundef double @degrees_double(double noundef %a) {
 entry:
 ; CHECK: %[[#float_64_arg:]] = OpFunctionParameter %[[#float_64]]
@@ -35,6 +38,7 @@ entry:
   ret double %elt.degrees
 }
 
+; CHECK-LABEL: Begin function degrees_float_vector
 define noundef <4 x float> @degrees_float_vector(<4 x float> noundef %a) {
 entry:
 ; CHECK: %[[#vec4_float_32_arg:]] = OpFunctionParameter %[[#vec4_float_32]]
@@ -43,6 +47,7 @@ entry:
   ret <4 x float> %elt.degrees
 }
 
+; CHECK-LABEL: Begin function degrees_half_vector
 define noundef <4 x half> @degrees_half_vector(<4 x half> noundef %a) {
 entry:
 ; CHECK: %[[#vec4_float_16_arg:]] = OpFunctionParameter %[[#vec4_float_16]]
@@ -51,6 +56,7 @@ entry:
   ret <4 x half> %elt.degrees
 }
 
+; CHECK-LABEL: Begin function degrees_double_vector
 define noundef <4 x double> @degrees_double_vector(<4 x double> noundef %a) {
 entry:
 ; CHECK: %[[#vec4_float_64_arg:]] = OpFunctionParameter %[[#vec4_float_64]]

>From b7a20c9a217400d44d5b84df771a4d47d5f89bba Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienfinn at gmail.com>
Date: Thu, 10 Oct 2024 11:56:58 -0700
Subject: [PATCH 3/3] clang format

---
 clang/lib/CodeGen/CGBuiltin.cpp | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 23ea78337d6651..ff678ee04f9c2a 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -18759,11 +18759,10 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
     Value *X = EmitScalarExpr(E->getArg(0));
 
     assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
-        "degree operand must have a float representation");
+           "degree operand must have a float representation");
 
     return Builder.CreateIntrinsic(
-        /*ReturnType=*/X->getType(),
-        CGM.getHLSLRuntime().getDegreesIntrinsic(),
+        /*ReturnType=*/X->getType(), CGM.getHLSLRuntime().getDegreesIntrinsic(),
         ArrayRef<Value *>{X}, nullptr, "hlsl.degrees");
   }
   case Builtin::BI__builtin_hlsl_elementwise_frac: {



More information about the cfe-commits mailing list