Skip to content

[clang][hlsl] Add atan2 intrinsic part 1 #107923

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

Closed
wants to merge 3 commits into from
Closed
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
1 change: 1 addition & 0 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,7 @@ Unless specified otherwise operation(±0) = ±0 and operation(±infinity) = ±in
T __builtin_elementwise_asin(T x) return the arcsine of x interpreted as an angle in radians floating point types
T __builtin_elementwise_acos(T x) return the arccosine of x interpreted as an angle in radians floating point types
T __builtin_elementwise_atan(T x) return the arctangent of x interpreted as an angle in radians floating point types
T __builtin_elementwise_atan2(T y, T x) return the arctangent of y/x floating point types
T __builtin_elementwise_sinh(T x) return the hyperbolic sine of angle x in radians floating point types
T __builtin_elementwise_cosh(T x) return the hyperbolic cosine of angle x in radians floating point types
T __builtin_elementwise_tanh(T x) return the hyperbolic tangent of angle x in radians floating point types
Expand Down
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,8 @@ DWARF Support in Clang
Floating Point Support in Clang
-------------------------------

- Add ``__builtin_elementwise_atan2`` builtin for floating point types only.

Fixed Point Support in Clang
----------------------------

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 @@ -1250,6 +1250,12 @@ def ElementwiseATan : Builtin {
let Prototype = "void(...)";
}

def ElementwiseATan2 : Builtin {
let Spellings = ["__builtin_elementwise_atan2"];
let Attributes = [NoThrow, Const, CustomTypeChecking];
Copy link
Member

@farzonl farzonl Sep 10, 2024

Choose a reason for hiding this comment

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

This is more a note for me: We haven't been doing CustomTypeChecking for "__builtin_hlsl_elementwise_*" cases. Check to see if we should. I'm assuming CustomTypeChecking is used to have vector cases avoid impacting variadic argument Sema rules.

let Prototype = "void(...)";
}

def ElementwiseBitreverse : Builtin {
let Spellings = ["__builtin_elementwise_bitreverse"];
let Attributes = [NoThrow, Const, CustomTypeChecking];
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3800,6 +3800,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_elementwise_atan:
return RValue::get(emitBuiltinWithOneOverloadedType<1>(
*this, E, llvm::Intrinsic::atan, "elt.atan"));
case Builtin::BI__builtin_elementwise_atan2:
return RValue::get(emitBuiltinWithOneOverloadedType<2>(
*this, E, llvm::Intrinsic::atan2, "elt.atan2"));
case Builtin::BI__builtin_elementwise_ceil:
return RValue::get(emitBuiltinWithOneOverloadedType<1>(
*this, E, llvm::Intrinsic::ceil, "elt.ceil"));
Expand Down
30 changes: 30 additions & 0 deletions clang/lib/Headers/hlsl/hlsl_intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,36 @@ float3 atan(float3);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_atan)
float4 atan(float4);

//===----------------------------------------------------------------------===//
// atan2 builtins
//===----------------------------------------------------------------------===//

/// \fn T atan2(T y, T x)
/// \brief Returns the arctangent of y/x, using the signs of the arguments to
/// determine the correct quadrant.
/// \param y The y-coordinate.
/// \param x The x-coordinate.

#ifdef __HLSL_ENABLE_16_BIT
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_atan2)
half atan2(half y, half x);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_atan2)
half2 atan2(half2 y, half2 x);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_atan2)
half3 atan2(half3 y, half3 x);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_atan2)
half4 atan2(half4 y, half4 x);
#endif

_HLSL_BUILTIN_ALIAS(__builtin_elementwise_atan2)
float atan2(float y, float x);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_atan2)
float2 atan2(float2 y, float2 x);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_atan2)
float3 atan2(float3 y, float3 x);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_atan2)
float4 atan2(float4 y, float4 x);

//===----------------------------------------------------------------------===//
// ceil builtins
//===----------------------------------------------------------------------===//
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2755,6 +2755,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,

// These builtins restrict the element type to floating point
// types only, and take in two arguments.
case Builtin::BI__builtin_elementwise_atan2:
case Builtin::BI__builtin_elementwise_pow: {
if (BuiltinElementwiseMath(TheCall))
return ExprError();
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1736,6 +1736,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case Builtin::BI__builtin_elementwise_acos:
case Builtin::BI__builtin_elementwise_asin:
case Builtin::BI__builtin_elementwise_atan:
case Builtin::BI__builtin_elementwise_atan2:
case Builtin::BI__builtin_elementwise_ceil:
case Builtin::BI__builtin_elementwise_cos:
case Builtin::BI__builtin_elementwise_cosh:
Expand Down
20 changes: 20 additions & 0 deletions clang/test/CodeGen/builtins-elementwise-math.c
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,26 @@ void test_builtin_elementwise_atan(float f1, float f2, double d1, double d2,
vf2 = __builtin_elementwise_atan(vf1);
}

void test_builtin_elementwise_atan2(float f1, float f2, float f3, double d1,
double d2, double d3, float4 vf1,
float4 vf2, float4 vf3) {
// CHECK-LABEL: define void @test_builtin_elementwise_atan2(
// CHECK: [[F1:%.+]] = load float, ptr %f1.addr, align 4
// CHECK-NEXT: [[F2:%.+]] = load float, ptr %f2.addr, align 4
// CHECK-NEXT: call float @llvm.atan2.f32(float [[F1]], float [[F2]])
f3 = __builtin_elementwise_atan2(f1, f2);

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

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

void test_builtin_elementwise_cos(float f1, float f2, double d1, double d2,
float4 vf1, float4 vf2) {
// CHECK-LABEL: define void @test_builtin_elementwise_cos(
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 @@ -257,6 +257,16 @@ float4 strict_elementwise_tanh(float4 a) {
return __builtin_elementwise_tanh(a);
}

// CHECK-LABEL: define dso_local noundef <4 x float> @_Z24strict_elementwise_atan2Dv4_fS_
// CHECK-SAME: (<4 x float> noundef [[A:%.*]], <4 x float> noundef [[B:%.*]]) local_unnamed_addr #[[ATTR2]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: [[ELT_ATAN2:%.*]] = tail call <4 x float> @llvm.atan2.v4f32(<4 x float> [[A]], <4 x float> [[B]]) #[[ATTR4]]
// CHECK-NEXT: ret <4 x float> [[ELT_ATAN2]]
//
float4 strict_elementwise_atan2(float4 a, float4 b) {
return __builtin_elementwise_atan2(a, b);
}

// 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/atan2.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_atan2_half
// NATIVE_HALF: call half @llvm.atan2.f16
// NO_HALF: call float @llvm.atan2.f32
half test_atan2_half (half p0, half p1) {
return atan2(p0, p1);
}

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

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

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

// CHECK-LABEL: test_atan2_float
// CHECK: call float @llvm.atan2.f32
float test_atan2_float (float p0, float p1) {
return atan2(p0, p1);
}

// CHECK-LABEL: test_atan2_float2
// CHECK: call <2 x float> @llvm.atan2.v2f32
float2 test_atan2_float2 (float2 p0, float2 p1) {
return atan2(p0, p1);
}

// CHECK-LABEL: test_atan2_float3
// CHECK: call <3 x float> @llvm.atan2.v3f32
float3 test_atan2_float3 (float3 p0, float3 p1) {
return atan2(p0, p1);
}

// CHECK-LABEL: test_atan2_float4
// CHECK: call <4 x float> @llvm.atan2.v4f32
float4 test_atan2_float4 (float4 p0, float4 p1) {
return atan2(p0, p1);
}
6 changes: 6 additions & 0 deletions clang/test/Sema/aarch64-sve-vector-trig-ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ svfloat32_t test_atan_vv_i8mf8(svfloat32_t v) {
// expected-error@-1 {{1st argument must be a vector, integer or floating point type}}
}

svfloat32_t test_atan2_vv_i8mf8(svfloat32_t v) {

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

svfloat32_t test_sin_vv_i8mf8(svfloat32_t v) {

return __builtin_elementwise_sin(v);
Expand Down
24 changes: 24 additions & 0 deletions clang/test/Sema/builtins-elementwise-math.c
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,30 @@ void test_builtin_elementwise_atan(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_atan2(int i, float f, double d, float4 v, int3 iv, unsigned u, unsigned4 uv) {

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

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

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

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

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

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

uv = __builtin_elementwise_atan2(uv, uv);
// 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);
Expand Down
6 changes: 6 additions & 0 deletions clang/test/Sema/riscv-rvv-vector-trig-ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ vfloat32mf2_t test_asin_vv_i8mf8(vfloat32mf2_t v) {
// expected-error@-1 {{1st argument must be a vector, integer or floating point type}}
}

vfloat32mf2_t test_atan2_vv_i8mf8(vfloat32mf2_t v) {

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

vfloat32mf2_t test_sin_vv_i8mf8(vfloat32mf2_t v) {

return __builtin_elementwise_sin(v);
Expand Down
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 @@ -146,6 +146,13 @@ void test_builtin_elementwise_atan() {
static_assert(!is_const<decltype(__builtin_elementwise_atan(b))>::value);
}

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

void test_builtin_elementwise_tan() {
const float a = 42.0;
float b = 42.3;
Expand Down
7 changes: 7 additions & 0 deletions clang/test/SemaHLSL/BuiltIns/half-float-only-errors2.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,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_atan2
// 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_pow

double2 test_double_builtin(double2 p0, double2 p1) {
return TEST_FUNC(p0, p1);
// expected-error@-1 {{passing 'double2' (aka 'vector<double, 2>') to parameter of incompatible type '__attribute__((__vector_size__(2 * sizeof(float)))) float' (vector of 2 'float' values)}}
}
37 changes: 37 additions & 0 deletions llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15568,6 +15568,43 @@ trapping or setting ``errno``.
When specified with the fast-math-flag 'afn', the result may be approximated
using a less accurate calculation.

'``llvm.atan2.*``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Syntax:
"""""""

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

::

declare float @llvm.atan2.f32(float %X, float %Y)
declare double @llvm.atan2.f64(double %X, double %Y)
declare x86_fp80 @llvm.atan2.f80(x86_fp80 %X, x86_fp80 %Y)
declare fp128 @llvm.atan2.f128(fp128 %X, fp128 %Y)
declare ppc_fp128 @llvm.atan2.ppcf128(ppc_fp128 %X, ppc_fp128 %Y)

Overview:
"""""""""

The '``llvm.atan2.*``' intrinsics return the arctangent of the operand.

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

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

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

Return the same value as a corresponding libm '``atan2``' 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
^^^^^^^^^^^^^^^^^^^^^^^^^^^

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 @@ -1016,6 +1016,7 @@ let IntrProperties = [IntrNoMem, IntrSpeculatable, IntrWillReturn] in {
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_atan2 : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>, 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>]>;
Expand Down
Loading