Skip to content

[HLSL] Implementation of the elementwise fmod builtin #108849

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
Sep 27, 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
2 changes: 2 additions & 0 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,8 @@ Unless specified otherwise operation(±0) = ±0 and operation(±infinity) = ±in
T __builtin_elementwise_canonicalize(T x) return the platform specific canonical encoding floating point types
of a floating-point number
T __builtin_elementwise_copysign(T x, T y) return the magnitude of x with the sign of y. floating point types
T __builtin_elementwise_fmod(T x, T y) return The floating-point remainder of (x/y) whose sign floating point types
matches the sign of x.
T __builtin_elementwise_max(T x, T y) return x or y, whichever is larger integer and floating point types
T __builtin_elementwise_min(T x, T y) return x or y, whichever is smaller integer and floating point types
T __builtin_elementwise_add_sat(T x, T y) return the sum of x and y, clamped to the range of integer 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 @@ -141,6 +141,8 @@ C++ Language Changes

- Add ``__builtin_elementwise_popcount`` builtin for integer types only.

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

- The builtin type alias ``__builtin_common_type`` has been added to improve the
performance of ``std::common_type``.

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

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

def ElementwisePow : Builtin {
let Spellings = ["__builtin_elementwise_pow"];
let Attributes = [NoThrow, Const, CustomTypeChecking];
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2878,7 +2878,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_fmodf:
case Builtin::BI__builtin_fmodf16:
case Builtin::BI__builtin_fmodl:
case Builtin::BI__builtin_fmodf128: {
case Builtin::BI__builtin_fmodf128:
case Builtin::BI__builtin_elementwise_fmod: {
CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E);
Value *Arg1 = EmitScalarExpr(E->getArg(0));
Value *Arg2 = EmitScalarExpr(E->getArg(1));
Expand Down
34 changes: 34 additions & 0 deletions clang/lib/Headers/hlsl/hlsl_intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -913,6 +913,40 @@ float3 floor(float3);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_floor)
float4 floor(float4);

//===----------------------------------------------------------------------===//
// fmod builtins
//===----------------------------------------------------------------------===//

/// \fn T fmod(T x, T y)
/// \brief Returns the linear interpolation of x to y.
/// \param x [in] The dividend.
/// \param y [in] The divisor.
///
/// Return the floating-point remainder of the x parameter divided by the y
/// parameter.

_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_fmod)
half fmod(half, half);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_fmod)
half2 fmod(half2, half2);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_fmod)
half3 fmod(half3, half3);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_fmod)
half4 fmod(half4, half4);

_HLSL_BUILTIN_ALIAS(__builtin_elementwise_fmod)
float fmod(float, float);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_fmod)
float2 fmod(float2, float2);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_fmod)
float3 fmod(float3, float3);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_fmod)
float4 fmod(float4, float4);

//===----------------------------------------------------------------------===//
// frac 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_fmod:
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 @@ -1777,6 +1777,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case Builtin::BI__builtin_elementwise_exp:
case Builtin::BI__builtin_elementwise_exp2:
case Builtin::BI__builtin_elementwise_floor:
case Builtin::BI__builtin_elementwise_fmod:
case Builtin::BI__builtin_elementwise_log:
case Builtin::BI__builtin_elementwise_log2:
case Builtin::BI__builtin_elementwise_log10:
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 @@ -607,6 +607,26 @@ void test_builtin_elementwise_popcount(si8 vi1, si8 vi2,
si = __builtin_elementwise_popcount(si);
}

void test_builtin_elementwise_fmod(float f1, float f2, double d1, double d2,
float4 vf1, float4 vf2) {

// CHECK-LABEL: define void @test_builtin_elementwise_fmod(
// CHECK: [[F1:%.+]] = load float, ptr %f1.addr, align 4
// CHECK: [[F2:%.+]] = load float, ptr %f2.addr, align 4
// CHECK-NEXT: frem float [[F1]], [[F2]]
f2 = __builtin_elementwise_fmod(f1, f2);

// CHECK: [[D1:%.+]] = load double, ptr %d1.addr, align 8
// CHECK: [[D2:%.+]] = load double, ptr %d2.addr, align 8
// CHECK-NEXT: frem double [[D1]], [[D2]]
d2 = __builtin_elementwise_fmod(d1, d2);

// CHECK: [[VF1:%.+]] = load <4 x float>, ptr %vf1.addr, align 16
// CHECK: [[VF2:%.+]] = load <4 x float>, ptr %vf2.addr, align 16
// CHECK-NEXT: frem <4 x float> [[VF1]], [[VF2]]
vf2 = __builtin_elementwise_fmod(vf1, vf2);
}

void test_builtin_elementwise_pow(float f1, float f2, double d1, double d2,
float4 vf1, float4 vf2) {

Expand Down
11 changes: 11 additions & 0 deletions clang/test/CodeGen/strictfp-elementwise-bulitins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -306,3 +306,14 @@ float4 strict_elementwise_fma(float4 a, float4 b, float4 c) {
float4 strict_elementwise_pow(float4 a, float4 b) {
return __builtin_elementwise_pow(a, b);
}

// CHECK-LABEL: define dso_local noundef <4 x float> @_Z23strict_elementwise_fmodDv4_fS_
// CHECK-SAME: (<4 x float> noundef [[A:%.*]], <4 x float> noundef [[B:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP0:%.*]] = tail call <4 x float> @llvm.experimental.constrained.frem.v4f32(<4 x float> [[A]], <4 x float> [[B]],
// CHECK-SAME: metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR4]]
// CHECK-NEXT: ret <4 x float> [[TMP0]]
//
float4 strict_elementwise_fmod(float4 a, float4 b) {
return __builtin_elementwise_fmod(a, b);
}
77 changes: 77 additions & 0 deletions clang/test/CodeGenHLSL/builtins/fmod.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// DirectX target:
//
// ---------- Native Half support test -----------
//
// 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: -DFNATTRS=noundef -DTYPE=half

//
// ---------- No Native Half support test -----------
//
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
// RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \
// RUN: -o - | FileCheck %s \
// RUN: -DFNATTRS=noundef -DTYPE=float


// Spirv target:
//
// ---------- Native Half support test -----------
//
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
// RUN: spirv-unknown-vulkan-compute %s -fnative-half-type \
// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \
// RUN: -DFNATTRS="spir_func noundef" -DTYPE=half

//
// ---------- No Native Half support test -----------
//
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
// RUN: spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \
// RUN: -o - | FileCheck %s \
// RUN: -DFNATTRS="spir_func noundef" -DTYPE=float



// CHECK: define [[FNATTRS]] [[TYPE]] @
// CHECK: %fmod = frem [[TYPE]]
// CHECK: ret [[TYPE]] %fmod
half test_fmod_half(half p0, half p1) { return fmod(p0, p1); }

// CHECK: define [[FNATTRS]] <2 x [[TYPE]]> @
// CHECK: %fmod = frem <2 x [[TYPE]]>
// CHECK: ret <2 x [[TYPE]]> %fmod
half2 test_fmod_half2(half2 p0, half2 p1) { return fmod(p0, p1); }

// CHECK: define [[FNATTRS]] <3 x [[TYPE]]> @
// CHECK: %fmod = frem <3 x [[TYPE]]>
// CHECK: ret <3 x [[TYPE]]> %fmod
half3 test_fmod_half3(half3 p0, half3 p1) { return fmod(p0, p1); }

// CHECK: define [[FNATTRS]] <4 x [[TYPE]]> @
// CHECK: %fmod = frem <4 x [[TYPE]]>
// CHECK: ret <4 x [[TYPE]]> %fmod
half4 test_fmod_half4(half4 p0, half4 p1) { return fmod(p0, p1); }

// CHECK: define [[FNATTRS]] float @
// CHECK: %fmod = frem float
// CHECK: ret float %fmod
float test_fmod_float(float p0, float p1) { return fmod(p0, p1); }

// CHECK: define [[FNATTRS]] <2 x float> @
// CHECK: %fmod = frem <2 x float>
// CHECK: ret <2 x float> %fmod
float2 test_fmod_float2(float2 p0, float2 p1) { return fmod(p0, p1); }

// CHECK: define [[FNATTRS]] <3 x float> @
// CHECK: %fmod = frem <3 x float>
// CHECK: ret <3 x float> %fmod
float3 test_fmod_float3(float3 p0, float3 p1) { return fmod(p0, p1); }

// CHECK: define [[FNATTRS]] <4 x float> @
// CHECK: %fmod = frem <4 x float>
// CHECK: ret <4 x float> %fmod
float4 test_fmod_float4(float4 p0, float4 p1) { return fmod(p0, p1); }

27 changes: 26 additions & 1 deletion clang/test/Sema/builtins-elementwise-math.c
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,32 @@ void test_builtin_elementwise_popcount(int i, float f, double d, float4 v, int3
// expected-error@-1 {{assigning to 'int3' (vector of 3 'int' values) from incompatible type 'unsigned3' (vector of 3 'unsigned int' values)}}
}

void test_builtin_elementwise_fmod(int i, short s, double d, float4 v, int3 iv, unsigned3 uv, int *p) {
i = __builtin_elementwise_fmod(p, d);
// expected-error@-1 {{arguments are of different types ('int *' vs 'double')}}

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

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

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

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

i = __builtin_elementwise_fmod(v, iv);
// expected-error@-1 {{arguments are of different types ('float4' (vector of 4 'float' values) vs 'int3' (vector of 3 'int' values))}}

i = __builtin_elementwise_fmod(uv, iv);
// expected-error@-1 {{arguments are of different types ('unsigned3' (vector of 3 'unsigned int' values) vs 'int3' (vector of 3 'int' values))}}

i = __builtin_elementwise_fmod(d, v);
// expected-error@-1 {{arguments are of different types ('double' vs 'float4' (vector of 4 'float' values))}}
}

void test_builtin_elementwise_pow(int i, short s, double d, float4 v, int3 iv, unsigned3 uv, int *p) {
i = __builtin_elementwise_pow(p, d);
// expected-error@-1 {{arguments are of different types ('int *' vs 'double')}}
Expand All @@ -562,7 +588,6 @@ void test_builtin_elementwise_pow(int i, short s, double d, float4 v, int3 iv, u

}


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

struct Foo s = __builtin_elementwise_roundeven(f);
Expand Down
8 changes: 8 additions & 0 deletions clang/test/SemaCXX/builtins-elementwise-math.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,14 @@ void test_builtin_elementwise_fma() {
static_assert(!is_const<decltype(__builtin_elementwise_fma(c, c, c))>::value);
}

void test_builtin_elementwise_fmod() {
const double a = 2;
double b = 1;
static_assert(!is_const<decltype(__builtin_elementwise_fmod(a, b))>::value);
static_assert(!is_const<decltype(__builtin_elementwise_fmod(b, a))>::value);
static_assert(!is_const<decltype(__builtin_elementwise_fmod(a, a))>::value);
}

void test_builtin_elementwise_pow() {
const double a = 2;
double b = 1;
Expand Down
22 changes: 22 additions & 0 deletions clang/test/SemaHLSL/BuiltIns/fmod-errors.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm-only -disable-llvm-passes -verify -verify-ignore-unexpected

float builtin_bool_to_float_type_promotion(bool p1, bool p2) {
return __builtin_elementwise_fmod(p1, p2);
// expected-error@-1 {{1st argument must be a vector, integer or floating point type (was 'bool')}}
}

float2 builtin_fmod_int2_to_float2_promotion(int2 p1, int2 p2) {
return __builtin_elementwise_fmod(p1, p2);
// expected-error@-1 {{1st argument must be a floating point type (was 'int2' (aka 'vector<int, 2>'))}}
}

half builtin_fmod_double_type (double p0, double p1) {
return __builtin_elementwise_fmod(p0, p1);
// expected-error@-1 {{passing 'double' to parameter of incompatible type 'float'}}
}

half builtin_fmod_double2_type (double2 p0, double2 p1) {
return __builtin_elementwise_fmod(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)}}
}
Loading