Skip to content

[HLSL] implement the rcp intrinsic #83857

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 5, 2024
Merged

Conversation

farzonl
Copy link
Member

@farzonl farzonl commented Mar 4, 2024

This PR implements the frontend for #70100
This PR is part 1 of 2.
Part 2 requires an intrinsic to instructions lowering.

  • Builtins.td - add an rcp builtin
  • CGBuiltin.cpp - add the builtin to intrinsic lowering
  • hlsl_intrinsics.h - add the rcp api
  • SemaChecking.cpp - reuse frac's sema checks
  • IntrinsicsDirectX.td - add the llvm intrinsic

@llvmbot llvmbot added clang Clang issues not falling into any other category backend:X86 clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:headers Headers provided by Clang, e.g. for intrinsics clang:codegen IR generation bugs: mangling, exceptions, etc. backend:DirectX HLSL HLSL Language Support llvm:ir labels Mar 4, 2024
@llvmbot
Copy link
Member

llvmbot commented Mar 4, 2024

@llvm/pr-subscribers-backend-directx
@llvm/pr-subscribers-llvm-ir
@llvm/pr-subscribers-clang-codegen
@llvm/pr-subscribers-backend-x86
@llvm/pr-subscribers-hlsl

@llvm/pr-subscribers-clang

Author: Farzon Lotfi (farzonl)

Changes

This PR implements the frontend for llvm#70100
This PR is part 1 of 2.
Part 2 depends on DXILIntrinsicExpansion.cpp in dixl-lerp-intrinsic-lowering PR
which will have an intrinsic to instruction expansion pass.
That pass is what we need to complete the DXIL lowering portion of this PR:

  • Builtins.td - add an rcp builtin
  • CGBuiltin.cpp - add the builtin to intrinsic lowering
  • hlsl_intrinsics.h - add the rcp api
  • SemaChecking.cpp - reuse frac's sema checks
  • IntrinsicsDirectX.td - add the llvm intrinsic

Full diff: https://github.com/llvm/llvm-project/pull/83857.diff

7 Files Affected:

  • (modified) clang/include/clang/Basic/Builtins.td (+6)
  • (modified) clang/lib/CodeGen/CGBuiltin.cpp (+8)
  • (modified) clang/lib/Headers/hlsl/hlsl_intrinsics.h (+41)
  • (modified) clang/lib/Sema/SemaChecking.cpp (+1)
  • (added) clang/test/CodeGenHLSL/builtins/rcp.hlsl (+53)
  • (added) clang/test/SemaHLSL/BuiltIns/rcp-errors.hlsl (+27)
  • (modified) llvm/include/llvm/IR/IntrinsicsDirectX.td (+2)
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 2c83dca248fb7d..a30953f4a94fa3 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4548,6 +4548,12 @@ def HLSLLerp : LangBuiltin<"HLSL_LANG"> {
   let Prototype = "void(...)";
 }
 
+def HLSLRcp : LangBuiltin<"HLSL_LANG"> {
+  let Spellings = ["__builtin_hlsl_elementwise_rcp"];
+  let Attributes = [NoThrow, Const];
+  let Prototype = "void(...)";
+}
+
 // Builtins for XRay.
 def XRayCustomEvent : Builtin {
   let Spellings = ["__xray_customevent"];
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index e90014261217bc..aefc09767378a6 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -18057,6 +18057,14 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
         /*ReturnType*/ Op0->getType(), Intrinsic::dx_frac,
         ArrayRef<Value *>{Op0}, nullptr, "dx.frac");
   }
+  case Builtin::BI__builtin_hlsl_elementwise_rcp: {
+    Value *Op0 = EmitScalarExpr(E->getArg(0));
+    if (!E->getArg(0)->getType()->hasFloatingRepresentation())
+      llvm_unreachable("rcp operand must have a float representation");
+    return Builder.CreateIntrinsic(
+        /*ReturnType*/ Op0->getType(), Intrinsic::dx_rcp,
+        ArrayRef<Value *>{Op0}, nullptr, "dx.rcp");
+  }
   }
   return nullptr;
 }
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index 5180530363889f..6174461cfa8802 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -831,6 +831,47 @@ uint64_t3 reversebits(uint64_t3);
 _HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse)
 uint64_t4 reversebits(uint64_t4);
 
+//===----------------------------------------------------------------------===//
+// rcp builtins
+//===----------------------------------------------------------------------===//
+
+/// \fn T rcp(T x)
+/// \brief Calculates a fast, approximate, per-component reciprocal ie 1 / \a x.
+/// \param x The specified input value.
+///
+/// The return value is the reciprocal of the \a x parameter.
+
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rcp)
+half rcp(half);
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rcp)
+half2 rcp(half2);
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rcp)
+half3 rcp(half3);
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rcp)
+half4 rcp(half4);
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rcp)
+float rcp(float);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rcp)
+float2 rcp(float2);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rcp)
+float3 rcp(float3);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rcp)
+float4 rcp(float4);
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rcp)
+double rcp(double);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rcp)
+double2 rcp(double2);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rcp)
+double3 rcp(double3);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rcp)
+double4 rcp(double4);
+
 //===----------------------------------------------------------------------===//
 // round builtins
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 0d4d57db01c93a..237c838cb8c255 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5280,6 +5280,7 @@ bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
       return true;
     break;
   }
+  case Builtin::BI__builtin_hlsl_elementwise_rcp:
   case Builtin::BI__builtin_hlsl_elementwise_frac: {
     if (PrepareBuiltinElementwiseMathOneArgCall(TheCall))
       return true;
diff --git a/clang/test/CodeGenHLSL/builtins/rcp.hlsl b/clang/test/CodeGenHLSL/builtins/rcp.hlsl
new file mode 100644
index 00000000000000..9b8406e1f0b605
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/rcp.hlsl
@@ -0,0 +1,53 @@
+// 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: %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
+
+// NATIVE_HALF: define noundef half @
+// NATIVE_HALF: %dx.rcp = call half @llvm.dx.rcp.f16(
+// NATIVE_HALF: ret half %dx.rcp
+// NO_HALF: define noundef float @"?test_rcp_half@@YA$halff@$halff@@Z"(
+// NO_HALF: %dx.rcp = call float @llvm.dx.rcp.f32(
+// NO_HALF: ret float %dx.rcp
+half test_rcp_half(half p0) { return rcp(p0); }
+// NATIVE_HALF: define noundef <2 x half> @
+// NATIVE_HALF: %dx.rcp = call <2 x half> @llvm.dx.rcp.v2f16
+// NATIVE_HALF: ret <2 x half> %dx.rcp
+// NO_HALF: define noundef <2 x float> @
+// NO_HALF: %dx.rcp = call <2 x float> @llvm.dx.rcp.v2f32(
+// NO_HALF: ret <2 x float> %dx.rcp
+half2 test_rcp_half2(half2 p0) { return rcp(p0); }
+// NATIVE_HALF: define noundef <3 x half> @
+// NATIVE_HALF: %dx.rcp = call <3 x half> @llvm.dx.rcp.v3f16
+// NATIVE_HALF: ret <3 x half> %dx.rcp
+// NO_HALF: define noundef <3 x float> @
+// NO_HALF: %dx.rcp = call <3 x float> @llvm.dx.rcp.v3f32(
+// NO_HALF: ret <3 x float> %dx.rcp
+half3 test_rcp_half3(half3 p0) { return rcp(p0); }
+// NATIVE_HALF: define noundef <4 x half> @
+// NATIVE_HALF: %dx.rcp = call <4 x half> @llvm.dx.rcp.v4f16
+// NATIVE_HALF: ret <4 x half> %dx.rcp
+// NO_HALF: define noundef <4 x float> @
+// NO_HALF: %dx.rcp = call <4 x float> @llvm.dx.rcp.v4f32(
+// NO_HALF: ret <4 x float> %dx.rcp
+half4 test_rcp_half4(half4 p0) { return rcp(p0); }
+
+// CHECK: define noundef float @
+// CHECK: %dx.rcp = call float @llvm.dx.rcp.f32(
+// CHECK: ret float %dx.rcp
+float test_rcp_float(float p0) { return rcp(p0); }
+// CHECK: define noundef <2 x float> @
+// CHECK: %dx.rcp = call <2 x float> @llvm.dx.rcp.v2f32
+// CHECK: ret <2 x float> %dx.rcp
+float2 test_rcp_float2(float2 p0) { return rcp(p0); }
+// CHECK: define noundef <3 x float> @
+// CHECK: %dx.rcp = call <3 x float> @llvm.dx.rcp.v3f32
+// CHECK: ret <3 x float> %dx.rcp
+float3 test_rcp_float3(float3 p0) { return rcp(p0); }
+// CHECK: define noundef <4 x float> @
+// CHECK: %dx.rcp = call <4 x float> @llvm.dx.rcp.v4f32
+// CHECK: ret <4 x float> %dx.rcp
+float4 test_rcp_float4(float4 p0) { return rcp(p0); }
diff --git a/clang/test/SemaHLSL/BuiltIns/rcp-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/rcp-errors.hlsl
new file mode 100644
index 00000000000000..dc4501dbd6d15a
--- /dev/null
+++ b/clang/test/SemaHLSL/BuiltIns/rcp-errors.hlsl
@@ -0,0 +1,27 @@
+
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm -disable-llvm-passes -verify -verify-ignore-unexpected
+
+float test_too_few_arg() {
+  return __builtin_hlsl_elementwise_rcp();
+  // expected-error@-1 {{too few arguments to function call, expected 1, have 0}}
+}
+
+float2 test_too_many_arg(float2 p0) {
+  return __builtin_hlsl_elementwise_rcp(p0, p0);
+  // expected-error@-1 {{too many arguments to function call, expected 1, have 2}}
+}
+
+float builtin_bool_to_float_type_promotion(bool p1) {
+  return __builtin_hlsl_elementwise_rcp(p1);
+  // expected-error@-1 {{1st argument must be a vector, integer or floating point type (was 'bool')}}
+}
+
+float builtin_rcp_int_to_float_promotion(int p1) {
+  return __builtin_hlsl_elementwise_rcp(p1);
+  // expected-error@-1 {{passing 'int' to parameter of incompatible type 'float'}}
+}
+
+float2 builtin_rcp_int2_to_float2_promotion(int2 p1) {
+  return __builtin_hlsl_elementwise_rcp(p1);
+  // expected-error@-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/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td
index b44d1c6d3d2f06..86defee4a563a7 100644
--- a/llvm/include/llvm/IR/IntrinsicsDirectX.td
+++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td
@@ -31,4 +31,6 @@ def int_dx_lerp :
     Intrinsic<[LLVMScalarOrSameVectorWidth<0, LLVMVectorElementType<0>>],
     [llvm_anyvector_ty, LLVMScalarOrSameVectorWidth<0, LLVMVectorElementType<0>>,LLVMScalarOrSameVectorWidth<0, LLVMVectorElementType<0>>],
     [IntrNoMem, IntrWillReturn] >;
+
+def int_dx_rcp  : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
 }

Copy link

github-actions bot commented Mar 5, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@farzonl farzonl force-pushed the hlsl-rcp-intrinsic branch from 512a902 to 93ae0c5 Compare March 5, 2024 17:35
@farzonl farzonl force-pushed the hlsl-rcp-intrinsic branch from 93ae0c5 to 786d0b4 Compare March 5, 2024 18:03
@farzonl farzonl merged commit 5a52662 into llvm:main Mar 5, 2024
@farzonl farzonl deleted the hlsl-rcp-intrinsic branch March 5, 2024 21:11
@farzonl farzonl linked an issue Mar 12, 2024 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:DirectX clang:codegen IR generation bugs: mangling, exceptions, etc. clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:headers Headers provided by Clang, e.g. for intrinsics clang Clang issues not falling into any other category HLSL HLSL Language Support llvm:ir
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[HLSL] implement rcp intrinsic
5 participants