Skip to content

[DirectX] Add trig intrinsics and link them with DXIL backend #95968

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
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
222 changes: 222 additions & 0 deletions llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15384,6 +15384,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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is llvm.asin.f16 intentionally excluded here and everywhere else below?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. f16 is a target specific intrinsic. So there won’t be any general documentation for it.

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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have test cases with vectors too? We are not consistent - some intrinsics have vector tests in this folder and some do not.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A change is needed in the dxil backend to scalarize vectors. We don’t have support for that yet, so we can’t test it. The only exceptions to this are dot product and the instruction expansion pass test cases.

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
Loading