Author: Zhengxing li Date: 2024-09-27T17:26:06-04:00 New Revision: 5d08f3256b134e9c5414b4e50563e5de0f1735c6
URL: https://github.com/llvm/llvm-project/commit/5d08f3256b134e9c5414b4e50563e5de0f1735c6 DIFF: https://github.com/llvm/llvm-project/commit/5d08f3256b134e9c5414b4e50563e5de0f1735c6.diff LOG: [HLSL] Implementation of the elementwise fmod builtin (#108849) This change add the elementwise fmod builtin to support HLSL function 'fmod' in clang for #99118 Builtins.td - add the fmod builtin CGBuiltin.cpp - lower the builtin to llvm FRem instruction hlsl_intrinsics.h - add the fmod api SemaChecking.cpp - add type checks for builtin SemaHLSL.cpp - add HLSL type checks for builtin clang/docs/LanguageExtensions.rst - add the builtin in *Elementwise Builtins* clang/docs/ReleaseNotes.rst - announce the builtin Added: clang/test/CodeGenHLSL/builtins/fmod.hlsl clang/test/SemaHLSL/BuiltIns/fmod-errors.hlsl Modified: clang/docs/LanguageExtensions.rst clang/docs/ReleaseNotes.rst clang/include/clang/Basic/Builtins.td clang/lib/CodeGen/CGBuiltin.cpp clang/lib/Headers/hlsl/hlsl_intrinsics.h clang/lib/Sema/SemaChecking.cpp clang/lib/Sema/SemaHLSL.cpp clang/test/CodeGen/builtins-elementwise-math.c clang/test/CodeGen/strictfp-elementwise-bulitins.cpp clang/test/Sema/builtins-elementwise-math.c clang/test/SemaCXX/builtins-elementwise-math.cpp Removed: ################################################################################ diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 0c6b9b1b8f9ce4..ea4b4bcec55e77 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -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 diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index a9cd68d392c753..4492270f9df724 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -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``. diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 33791270800c9d..8090119e512fbb 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -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]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 9033cd1ccd781d..d739597de4c855 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -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)); diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 9d426de4cca2a2..810a16d75f0228 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -929,6 +929,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 //===----------------------------------------------------------------------===// diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index af1dc21594da8a..8634b54b0535d0 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -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(); diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index f17b606a8f262a..43cc6c81ae5cb0 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -1965,6 +1965,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: diff --git a/clang/test/CodeGen/builtins-elementwise-math.c b/clang/test/CodeGen/builtins-elementwise-math.c index 7e094a52653ef0..0e53d3e141b01b 100644 --- a/clang/test/CodeGen/builtins-elementwise-math.c +++ b/clang/test/CodeGen/builtins-elementwise-math.c @@ -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) { diff --git a/clang/test/CodeGen/strictfp-elementwise-bulitins.cpp b/clang/test/CodeGen/strictfp-elementwise-bulitins.cpp index 55ba17a1955800..651f5bfc94c6c4 100644 --- a/clang/test/CodeGen/strictfp-elementwise-bulitins.cpp +++ b/clang/test/CodeGen/strictfp-elementwise-bulitins.cpp @@ -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); +} diff --git a/clang/test/CodeGenHLSL/builtins/fmod.hlsl b/clang/test/CodeGenHLSL/builtins/fmod.hlsl new file mode 100644 index 00000000000000..708779daaa7b60 --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/fmod.hlsl @@ -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); } + diff --git a/clang/test/Sema/builtins-elementwise-math.c b/clang/test/Sema/builtins-elementwise-math.c index 1727be1d6286d5..26b153dd5b210b 100644 --- a/clang/test/Sema/builtins-elementwise-math.c +++ b/clang/test/Sema/builtins-elementwise-math.c @@ -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 diff erent 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 diff erent 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 diff erent 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 diff erent 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 diff erent types ('int *' vs 'double')}} @@ -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); diff --git a/clang/test/SemaCXX/builtins-elementwise-math.cpp b/clang/test/SemaCXX/builtins-elementwise-math.cpp index c3d8bc593c0bbc..5910796c5d2983 100644 --- a/clang/test/SemaCXX/builtins-elementwise-math.cpp +++ b/clang/test/SemaCXX/builtins-elementwise-math.cpp @@ -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; diff --git a/clang/test/SemaHLSL/BuiltIns/fmod-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/fmod-errors.hlsl new file mode 100644 index 00000000000000..e4fa609dd6a05d --- /dev/null +++ b/clang/test/SemaHLSL/BuiltIns/fmod-errors.hlsl @@ -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)}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits