Skip to content

Commit

Permalink
[clang][hlsl] Add tan intrinsic part 1 (#90276)
Browse files Browse the repository at this point in the history
This change is an implementation of #87367's investigation on supporting
IEEE math operations as intrinsics.
Which was discussed in this RFC:
https://discourse.llvm.org/t/rfc-all-the-math-intrinsics/78294

If you want an overarching view of how this will all connect see:
#90088

Changes:
- `clang/docs/LanguageExtensions.rst` - Document the new elementwise tan
builtin.
-  `clang/include/clang/Basic/Builtins.td` - Implement the tan builtin.
- `clang/lib/CodeGen/CGBuiltin.cpp` - invoke the tan intrinsic on uses
of the builtin
- `clang/lib/Headers/hlsl/hlsl_intrinsics.h` - Associate the tan builtin
with the equivalent hlsl apis
- `clang/lib/Sema/SemaChecking.cpp` - Add generic sema checks as well as
HLSL specifc sema checks to the tan builtin
-  `llvm/include/llvm/IR/Intrinsics.td` - Create the tan intrinsic
-  `llvm/docs/LangRef.rst` - Document the tan intrinsic
  • Loading branch information
farzonl authored May 8, 2024
1 parent 1c8c2fd commit 31b45a9
Show file tree
Hide file tree
Showing 15 changed files with 236 additions and 38 deletions.
1 change: 1 addition & 0 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,7 @@ Unless specified otherwise operation(±0) = ±0 and operation(±infinity) = ±in
T __builtin_elementwise_ceil(T x) return the smallest integral value greater than or equal to x floating point types
T __builtin_elementwise_sin(T x) return the sine of x interpreted as an angle in radians floating point types
T __builtin_elementwise_cos(T x) return the cosine of x interpreted as an angle in radians floating point types
T __builtin_elementwise_tan(T x) return the tangent of x interpreted as an angle in radians floating point types
T __builtin_elementwise_floor(T x) return the largest integral value less than or equal to x floating point types
T __builtin_elementwise_log(T x) return the natural logarithm of x floating point types
T __builtin_elementwise_log2(T x) return the base 2 logarithm of x floating point types
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -1326,6 +1326,12 @@ def ElementwiseSqrt : Builtin {
let Prototype = "void(...)";
}

def ElementwiseTan : Builtin {
let Spellings = ["__builtin_elementwise_tan"];
let Attributes = [NoThrow, Const, CustomTypeChecking];
let Prototype = "void(...)";
}

def ElementwiseTrunc : Builtin {
let Spellings = ["__builtin_elementwise_trunc"];
let Attributes = [NoThrow, Const, CustomTypeChecking];
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3822,7 +3822,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_elementwise_sin:
return RValue::get(
emitUnaryBuiltin(*this, E, llvm::Intrinsic::sin, "elt.sin"));

case Builtin::BI__builtin_elementwise_tan:
return RValue::get(
emitUnaryBuiltin(*this, E, llvm::Intrinsic::tan, "elt.tan"));
case Builtin::BI__builtin_elementwise_trunc:
return RValue::get(
emitUnaryBuiltin(*this, E, llvm::Intrinsic::trunc, "elt.trunc"));
Expand Down
23 changes: 23 additions & 0 deletions clang/lib/Headers/hlsl/hlsl_intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -1441,6 +1441,29 @@ float3 sqrt(float3);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_sqrt)
float4 sqrt(float4);

//===----------------------------------------------------------------------===//
// tan builtins
//===----------------------------------------------------------------------===//
#ifdef __HLSL_ENABLE_16_BIT
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_tan)
half tan(half);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_tan)
half2 tan(half2);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_tan)
half3 tan(half3);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_tan)
half4 tan(half4);
#endif

_HLSL_BUILTIN_ALIAS(__builtin_elementwise_tan)
float tan(float);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_tan)
float2 tan(float2);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_tan)
float3 tan(float3);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_tan)
float4 tan(float4);

//===----------------------------------------------------------------------===//
// trunc builtins
//===----------------------------------------------------------------------===//
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3047,6 +3047,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
case Builtin::BI__builtin_elementwise_nearbyint:
case Builtin::BI__builtin_elementwise_sin:
case Builtin::BI__builtin_elementwise_sqrt:
case Builtin::BI__builtin_elementwise_tan:
case Builtin::BI__builtin_elementwise_trunc:
case Builtin::BI__builtin_elementwise_canonicalize: {
if (PrepareBuiltinElementwiseMathOneArgCall(TheCall))
Expand Down Expand Up @@ -5677,6 +5678,7 @@ bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case Builtin::BI__builtin_elementwise_roundeven:
case Builtin::BI__builtin_elementwise_sin:
case Builtin::BI__builtin_elementwise_sqrt:
case Builtin::BI__builtin_elementwise_tan:
case Builtin::BI__builtin_elementwise_trunc: {
if (CheckFloatOrHalfRepresentations(this, TheCall))
return true;
Expand Down
16 changes: 16 additions & 0 deletions clang/test/CodeGen/builtins-elementwise-math.c
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,22 @@ void test_builtin_elementwise_sqrt(float f1, float f2, double d1, double d2,
vf2 = __builtin_elementwise_sqrt(vf1);
}

void test_builtin_elementwise_tan(float f1, float f2, double d1, double d2,
float4 vf1, float4 vf2) {
// CHECK-LABEL: define void @test_builtin_elementwise_tan(
// CHECK: [[F1:%.+]] = load float, ptr %f1.addr, align 4
// CHECK-NEXT: call float @llvm.tan.f32(float [[F1]])
f2 = __builtin_elementwise_tan(f1);

// CHECK: [[D1:%.+]] = load double, ptr %d1.addr, align 8
// CHECK-NEXT: call double @llvm.tan.f64(double [[D1]])
d2 = __builtin_elementwise_tan(d1);

// CHECK: [[VF1:%.+]] = load <4 x float>, ptr %vf1.addr, align 16
// CHECK-NEXT: call <4 x float> @llvm.tan.v4f32(<4 x float> [[VF1]])
vf2 = __builtin_elementwise_tan(vf1);
}

void test_builtin_elementwise_trunc(float f1, float f2, double d1, double d2,
float4 vf1, float4 vf2) {
// CHECK-LABEL: define void @test_builtin_elementwise_trunc(
Expand Down
10 changes: 10 additions & 0 deletions clang/test/CodeGen/strictfp-elementwise-bulitins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,16 @@ float4 strict_elementwise_sqrt(float4 a) {
return __builtin_elementwise_sqrt(a);
}

// CHECK-LABEL: define dso_local noundef <4 x float> @_Z22strict_elementwise_tanDv4_f
// CHECK-SAME: (<4 x float> noundef [[A:%.*]]) local_unnamed_addr #[[ATTR2]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: [[ELT_TAN:%.*]] = tail call <4 x float> @llvm.tan.v4f32(<4 x float> [[A]]) #[[ATTR4]]
// CHECK-NEXT: ret <4 x float> [[ELT_TAN]]
//
float4 strict_elementwise_tan(float4 a) {
return __builtin_elementwise_tan(a);
}

// CHECK-LABEL: define dso_local noundef <4 x float> @_Z24strict_elementwise_truncDv4_f
// CHECK-SAME: (<4 x float> noundef [[A:%.*]]) local_unnamed_addr #[[ATTR2]] {
// CHECK-NEXT: entry:
Expand Down
59 changes: 59 additions & 0 deletions clang/test/CodeGenHLSL/builtins/tan.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// 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: spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \
// RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF

// CHECK-LABEL: test_tan_half
// NATIVE_HALF: call half @llvm.tan.f16
// NO_HALF: call float @llvm.tan.f32
half test_tan_half ( half p0 ) {
return tan ( p0 );
}

// CHECK-LABEL: test_tan_half2
// NATIVE_HALF: call <2 x half> @llvm.tan.v2f16
// NO_HALF: call <2 x float> @llvm.tan.v2f32
half2 test_tan_half2 ( half2 p0 ) {
return tan ( p0 );
}

// CHECK-LABEL: test_tan_half3
// NATIVE_HALF: call <3 x half> @llvm.tan.v3f16
// NO_HALF: call <3 x float> @llvm.tan.v3f32
half3 test_tan_half3 ( half3 p0 ) {
return tan ( p0 );
}

// CHECK-LABEL: test_tan_half4
// NATIVE_HALF: call <4 x half> @llvm.tan.v4f16
// NO_HALF: call <4 x float> @llvm.tan.v4f32
half4 test_tan_half4 ( half4 p0 ) {
return tan ( p0 );
}

// CHECK-LABEL: test_tan_float
// CHECK: call float @llvm.tan.f32
float test_tan_float ( float p0 ) {
return tan ( p0 );
}

// CHECK-LABEL: test_tan_float2
// CHECK: call <2 x float> @llvm.tan.v2f32
float2 test_tan_float2 ( float2 p0 ) {
return tan ( p0 );
}

// CHECK-LABEL: test_tan_float3
// CHECK: call <3 x float> @llvm.tan.v3f32
float3 test_tan_float3 ( float3 p0 ) {
return tan ( p0 );
}

// CHECK-LABEL: test_tan_float4
// CHECK: call <4 x float> @llvm.tan.v4f32
float4 test_tan_float4 ( float4 p0 ) {
return tan ( p0 );
}
42 changes: 24 additions & 18 deletions clang/test/Sema/aarch64-sve-vector-trig-ops.c
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
// RUN: %clang_cc1 -triple aarch64 -target-feature +sve \
// RUN: -disable-O0-optnone -o - -fsyntax-only %s -verify
// REQUIRES: aarch64-registered-target

#include <arm_sve.h>


svfloat32_t test_sin_vv_i8mf8(svfloat32_t v) {

return __builtin_elementwise_sin(v);
// expected-error@-1 {{1st argument must be a vector, integer or floating point type}}
}

svfloat32_t test_cos_vv_i8mf8(svfloat32_t v) {

return __builtin_elementwise_cos(v);
// expected-error@-1 {{1st argument must be a vector, integer or floating point type}}
}
// RUN: %clang_cc1 -triple aarch64 -target-feature +sve \
// RUN: -disable-O0-optnone -o - -fsyntax-only %s -verify
// REQUIRES: aarch64-registered-target

#include <arm_sve.h>


svfloat32_t test_sin_vv_i8mf8(svfloat32_t v) {

return __builtin_elementwise_sin(v);
// expected-error@-1 {{1st argument must be a vector, integer or floating point type}}
}

svfloat32_t test_cos_vv_i8mf8(svfloat32_t v) {

return __builtin_elementwise_cos(v);
// expected-error@-1 {{1st argument must be a vector, integer or floating point type}}
}

svfloat32_t test_tan_vv_i8mf8(svfloat32_t v) {

return __builtin_elementwise_tan(v);
// expected-error@-1 {{1st argument must be a vector, integer or floating point type}}
}
21 changes: 21 additions & 0 deletions clang/test/Sema/builtins-elementwise-math.c
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,27 @@ void test_builtin_elementwise_sqrt(int i, float f, double d, float4 v, int3 iv,
// expected-error@-1 {{1st argument must be a floating point type (was 'unsigned4' (vector of 4 'unsigned int' values))}}
}

void test_builtin_elementwise_tan(int i, float f, double d, float4 v, int3 iv, unsigned u, unsigned4 uv) {

struct Foo s = __builtin_elementwise_tan(f);
// expected-error@-1 {{initializing 'struct Foo' with an expression of incompatible type 'float'}}

i = __builtin_elementwise_tan();
// expected-error@-1 {{too few arguments to function call, expected 1, have 0}}

i = __builtin_elementwise_tan(i);
// expected-error@-1 {{1st argument must be a floating point type (was 'int')}}

i = __builtin_elementwise_tan(f, f);
// expected-error@-1 {{too many arguments to function call, expected 1, have 2}}

u = __builtin_elementwise_tan(u);
// expected-error@-1 {{1st argument must be a floating point type (was 'unsigned int')}}

uv = __builtin_elementwise_tan(uv);
// expected-error@-1 {{1st argument must be a floating point type (was 'unsigned4' (vector of 4 'unsigned int' values))}}
}

void test_builtin_elementwise_trunc(int i, float f, double d, float4 v, int3 iv, unsigned u, unsigned4 uv) {

struct Foo s = __builtin_elementwise_trunc(f);
Expand Down
44 changes: 25 additions & 19 deletions clang/test/Sema/riscv-rvv-vector-trig-ops.c
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
// RUN: %clang_cc1 -triple riscv64 -target-feature +f -target-feature +d \
// RUN: -target-feature +v -target-feature +zfh -target-feature +zvfh \
// RUN: -disable-O0-optnone -o - -fsyntax-only %s -verify
// REQUIRES: riscv-registered-target

#include <riscv_vector.h>


vfloat32mf2_t test_sin_vv_i8mf8(vfloat32mf2_t v) {

return __builtin_elementwise_sin(v);
// expected-error@-1 {{1st argument must be a vector, integer or floating point type}}
}

vfloat32mf2_t test_cos_vv_i8mf8(vfloat32mf2_t v) {

return __builtin_elementwise_cos(v);
// expected-error@-1 {{1st argument must be a vector, integer or floating point type}}
}
// RUN: %clang_cc1 -triple riscv64 -target-feature +f -target-feature +d \
// RUN: -target-feature +v -target-feature +zfh -target-feature +zvfh \
// RUN: -disable-O0-optnone -o - -fsyntax-only %s -verify
// REQUIRES: riscv-registered-target

#include <riscv_vector.h>


vfloat32mf2_t test_sin_vv_i8mf8(vfloat32mf2_t v) {

return __builtin_elementwise_sin(v);
// expected-error@-1 {{1st argument must be a vector, integer or floating point type}}
}

vfloat32mf2_t test_cos_vv_i8mf8(vfloat32mf2_t v) {

return __builtin_elementwise_cos(v);
// expected-error@-1 {{1st argument must be a vector, integer or floating point type}}
}

vfloat32mf2_t test_tan_vv_i8mf8(vfloat32mf2_t v) {

return __builtin_elementwise_tan(v);
// expected-error@-1 {{1st argument must be a vector, integer or floating point type}}
}
7 changes: 7 additions & 0 deletions clang/test/SemaCXX/builtins-elementwise-math.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ void test_builtin_elementwise_sin() {
static_assert(!is_const<decltype(__builtin_elementwise_sin(b))>::value);
}

void test_builtin_elementwise_tan() {
const float a = 42.0;
float b = 42.3;
static_assert(!is_const<decltype(__builtin_elementwise_tan(a))>::value);
static_assert(!is_const<decltype(__builtin_elementwise_tan(b))>::value);
}

void test_builtin_elementwise_sqrt() {
const float a = 42.0;
float b = 42.3;
Expand Down
1 change: 1 addition & 0 deletions clang/test/SemaHLSL/BuiltIns/half-float-only-errors.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,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_sin
// 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_sqrt
// 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_roundeven
// 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_trunc

double2 test_double_builtin(double2 p0) {
Expand Down
37 changes: 37 additions & 0 deletions llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15272,6 +15272,43 @@ trapping or setting ``errno``.
When specified with the fast-math-flag 'afn', the result may be approximated
using a less accurate calculation.

'``llvm.tan.*``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^

Syntax:
"""""""

This is an overloaded intrinsic. You can use ``llvm.tan`` on any
floating-point or vector of floating-point type. Not all targets support
all types however.

::

declare float @llvm.tan.f32(float %Val)
declare double @llvm.tan.f64(double %Val)
declare x86_fp80 @llvm.tan.f80(x86_fp80 %Val)
declare fp128 @llvm.tan.f128(fp128 %Val)
declare ppc_fp128 @llvm.tan.ppcf128(ppc_fp128 %Val)

Overview:
"""""""""

The '``llvm.tan.*``' intrinsics return the tangent of the operand.

Arguments:
""""""""""

The argument and return value are floating-point numbers of the same type.

Semantics:
""""""""""

Return the same value as a corresponding libm '``tan``' function but without
trapping or setting ``errno``.

When specified with the fast-math-flag 'afn', the result may be approximated
using a less accurate calculation.

'``llvm.pow.*``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/IR/Intrinsics.td
Original file line number Diff line number Diff line change
Expand Up @@ -1025,6 +1025,7 @@ let IntrProperties = [IntrNoMem, IntrSpeculatable, IntrWillReturn] in {
def int_powi : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>, llvm_anyint_ty]>;
def int_sin : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
def int_cos : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
def int_tan : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
def int_pow : DefaultAttrsIntrinsic<[llvm_anyfloat_ty],
[LLVMMatchType<0>, LLVMMatchType<0>]>;
def int_log : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
Expand Down

0 comments on commit 31b45a9

Please sign in to comment.