Skip to content

Commit

Permalink
[DirectX] Add trig intrinsics and link them with DXIL backend (llvm#9…
Browse files Browse the repository at this point in the history
…5968)

This change is part of this proposal:
https://discourse.llvm.org/t/rfc-all-the-math-intrinsics/78294

This is part 1 of 4 PRs. It sets the ground work for adding the
intrinsics.

Add DXIL Lower for `acos`, `asin`, `atan`, `cosh`, `sinh`, and `tanh` 
llvm#70079
llvm#70080
llvm#70081
llvm#70083
llvm#70084
llvm#95966
  • Loading branch information
farzonl authored and AlexisPerry committed Jun 27, 2024
1 parent d1282d8 commit 4e30cb5
Show file tree
Hide file tree
Showing 15 changed files with 427 additions and 0 deletions.
222 changes: 222 additions & 0 deletions llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15401,6 +15401,228 @@ trapping or setting ``errno``.
When specified with the fast-math-flag 'afn', the result may be approximated
using a less accurate calculation.

'``llvm.asin.*``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Syntax:
"""""""

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

::

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

Overview:
"""""""""

The '``llvm.asin.*``' intrinsics return the arcsine 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 '``asin``' 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.acos.*``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Syntax:
"""""""

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

::

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

Overview:
"""""""""

The '``llvm.acos.*``' intrinsics return the arccosine 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 '``acos``' 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.atan.*``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Syntax:
"""""""

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

::

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

Overview:
"""""""""

The '``llvm.atan.*``' intrinsics return the arctangent 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 '``atan``' 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.sinh.*``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Syntax:
"""""""

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

::

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

Overview:
"""""""""

The '``llvm.sinh.*``' intrinsics return the hyperbolic sine 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 '``sinh``' 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.cosh.*``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Syntax:
"""""""

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

::

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

Overview:
"""""""""

The '``llvm.cosh.*``' intrinsics return the hyperbolic cosine 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 '``cosh``' 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.tanh.*``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Syntax:
"""""""

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

::

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

Overview:
"""""""""

The '``llvm.tanh.*``' intrinsics return the hyperbolic 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 '``tanh``' 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
6 changes: 6 additions & 0 deletions llvm/include/llvm/IR/Intrinsics.td
Original file line number Diff line number Diff line change
Expand Up @@ -1019,9 +1019,15 @@ let IntrProperties = [IntrNoMem, IntrSpeculatable, IntrWillReturn] in {
// environment so they can be treated as readnone.
def int_sqrt : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
def int_powi : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>, llvm_anyint_ty]>;
def int_asin : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
def int_acos : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
def int_atan : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
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_sinh : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
def int_cosh : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
def int_tanh : 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
19 changes: 19 additions & 0 deletions llvm/lib/Target/DirectX/DXIL.td
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,25 @@ def Sin : DXILOpMapping<13, unary, int_sin,
def Tan : DXILOpMapping<14, unary, int_tan,
"Returns tangent(theta) for theta in radians.",
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
def ACos : DXILOpMapping<15, unary, int_acos,
"Returns the arccosine of each component of input.",
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
def ASin : DXILOpMapping<16, unary, int_asin,
"Returns the arcsine of each component of input.",
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
def ATan : DXILOpMapping<17, unary, int_atan,
"Returns the arctangent of each component of input.",
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
def HCos : DXILOpMapping<18, unary, int_cosh,
"Returns the hyperbolic cosine of the specified value.",
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
def HSin : DXILOpMapping<19, unary, int_sinh,
"Returns the hyperbolic sine of the specified value.",
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
def HTan : DXILOpMapping<20, unary, int_tanh,
"Returns the hyperbolic tan of the specified value.",
[llvm_halforfloat_ty, LLVMMatchType<0>]>;

def Exp2 : DXILOpMapping<21, unary, int_exp2,
"Returns the base 2 exponential, or 2**x, of the specified value."
"exp2(x) = 2**x.",
Expand Down
20 changes: 20 additions & 0 deletions llvm/test/CodeGen/DirectX/acos.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s

; Make sure dxil operation function calls for acos are generated for float and half.

define noundef float @tan_float(float noundef %a) {
entry:
; CHECK:call float @dx.op.unary.f32(i32 15, float %{{.*}})
%elt.acos = call float @llvm.acos.f32(float %a)
ret float %elt.acos
}

define noundef half @tan_half(half noundef %a) {
entry:
; CHECK:call half @dx.op.unary.f16(i32 15, half %{{.*}})
%elt.acos = call half @llvm.acos.f16(half %a)
ret half %elt.acos
}

declare half @llvm.acos.f16(half)
declare float @llvm.acos.f32(float)
10 changes: 10 additions & 0 deletions llvm/test/CodeGen/DirectX/acos_error.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s

; DXIL operation acos does not support double overload type
; CHECK: LLVM ERROR: Invalid Overload

define noundef double @acos_double(double noundef %a) {
entry:
%1 = call double @llvm.acos.f64(double %a)
ret double %1
}
20 changes: 20 additions & 0 deletions llvm/test/CodeGen/DirectX/asin.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s

; Make sure dxil operation function calls for asin are generated for float and half.

define noundef float @tan_float(float noundef %a) {
entry:
; CHECK:call float @dx.op.unary.f32(i32 16, float %{{.*}})
%elt.asin = call float @llvm.asin.f32(float %a)
ret float %elt.asin
}

define noundef half @tan_half(half noundef %a) {
entry:
; CHECK:call half @dx.op.unary.f16(i32 16, half %{{.*}})
%elt.asin = call half @llvm.asin.f16(half %a)
ret half %elt.asin
}

declare half @llvm.asin.f16(half)
declare float @llvm.asin.f32(float)
10 changes: 10 additions & 0 deletions llvm/test/CodeGen/DirectX/asin_error.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s

; DXIL operation asin does not support double overload type
; CHECK: LLVM ERROR: Invalid Overload

define noundef double @asin_double(double noundef %a) {
entry:
%1 = call double @llvm.asin.f64(double %a)
ret double %1
}
20 changes: 20 additions & 0 deletions llvm/test/CodeGen/DirectX/atan.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s

; Make sure dxil operation function calls for atan are generated for float and half.

define noundef float @tan_float(float noundef %a) {
entry:
; CHECK:call float @dx.op.unary.f32(i32 17, float %{{.*}})
%elt.atan = call float @llvm.atan.f32(float %a)
ret float %elt.atan
}

define noundef half @tan_half(half noundef %a) {
entry:
; CHECK:call half @dx.op.unary.f16(i32 17, half %{{.*}})
%elt.atan = call half @llvm.atan.f16(half %a)
ret half %elt.atan
}

declare half @llvm.atan.f16(half)
declare float @llvm.atan.f32(float)
10 changes: 10 additions & 0 deletions llvm/test/CodeGen/DirectX/atan_error.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s

; DXIL operation atan does not support double overload type
; CHECK: LLVM ERROR: Invalid Overload

define noundef double @atan_double(double noundef %a) {
entry:
%1 = call double @llvm.atan.f64(double %a)
ret double %1
}
20 changes: 20 additions & 0 deletions llvm/test/CodeGen/DirectX/cosh.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s

; Make sure dxil operation function calls for cosh are generated for float and half.

define noundef float @tan_float(float noundef %a) {
entry:
; CHECK:call float @dx.op.unary.f32(i32 18, float %{{.*}})
%elt.cosh = call float @llvm.cosh.f32(float %a)
ret float %elt.cosh
}

define noundef half @tan_half(half noundef %a) {
entry:
; CHECK:call half @dx.op.unary.f16(i32 18, half %{{.*}})
%elt.cosh = call half @llvm.cosh.f16(half %a)
ret half %elt.cosh
}

declare half @llvm.cosh.f16(half)
declare float @llvm.cosh.f32(float)
10 changes: 10 additions & 0 deletions llvm/test/CodeGen/DirectX/cosh_error.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s

; DXIL operation cosh does not support double overload type
; CHECK: LLVM ERROR: Invalid Overload

define noundef double @cosh_double(double noundef %a) {
entry:
%1 = call double @llvm.cosh.f64(double %a)
ret double %1
}
Loading

0 comments on commit 4e30cb5

Please sign in to comment.