Skip to content

Commit

Permalink
[clang][hlsl] Add atan2 intrinsic part 1
Browse files Browse the repository at this point in the history
Issue: llvm#70096

Changes:
- Doc updates:
  - `clang/docs/LanguageExtensions.rst` - Document the new elementwise atan2 builtin.
  - `llvm/docs/LangRef.rst` - Document the atan2 intrinsic
- TableGen:
  - `clang/include/clang/Basic/Builtins.td` - Implement the atan2 builtin.
  - `llvm/include/llvm/IR/Intrinsics.td` - Create the atan2 intrinsic
- Sema checking:
  - `clang/lib/Sema/SemaChecking.cpp` - Add generic sema checks to the atan2 builtin
  - `clang/lib/Sema/SemaHLSL` Add HLSL specifc sema checks to the atan2 builtin
- `clang/lib/CodeGen/CGBuiltin.cpp` - invoke the atan2 intrinsic on uses of the builtin
- `clang/lib/Headers/hlsl/hlsl_intrinsics.h` - Associate the atan2 builtin with the equivalent hlsl apis
  • Loading branch information
tex3d committed Sep 10, 2024
1 parent ae02211 commit 44b3556
Show file tree
Hide file tree
Showing 16 changed files with 219 additions and 0 deletions.
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
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];
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);
// 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

0 comments on commit 44b3556

Please sign in to comment.