Skip to content

Commit

Permalink
clang: Add elementwise pow builtin
Browse files Browse the repository at this point in the history
Add codegen for llvm pow elementwise builtin
The pow elementwise builtin is necessary for HLSL codegen.
Tests were added to make sure that the expected errors are encountered when these functions are given inputs of incompatible types, or too many inputs.
The new builtin is restricted to floating point types only.

Reviewed By: arsenm

Differential Revision: https://reviews.llvm.org/D153310
  • Loading branch information
bob80905 committed Jul 24, 2023
1 parent 4e680ae commit 3a98e73
Show file tree
Hide file tree
Showing 11 changed files with 109 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 @@ -639,6 +639,7 @@ Unless specified otherwise operation(±0) = ±0 and operation(±infinity) = ±in
T __builtin_elementwise_log(T x) return the natural logarithm of x floating point types
T __builtin_elementwise_log2(T x) return the base 2 logarithm of x floating point types
T __builtin_elementwise_log10(T x) return the base 10 logarithm of x floating point types
T __builtin_elementwise_pow(T x, T y) return x raised to the power of y floating point types
T __builtin_elementwise_exp(T x) returns the base-e exponential, e^x, of the specified value floating point types
T __builtin_elementwise_exp2(T x) returns the base-2 exponential, 2^x, of the specified value floating point types
T __builtin_elementwise_roundeven(T x) round x to the nearest integer value in floating point format, floating point types
Expand Down
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -961,6 +961,7 @@ Floating Point Support in Clang
- Add ``__builtin_elementwise_exp`` builtin for floating point types only.
- Add ``__builtin_elementwise_exp2`` builtin for floating point types only.
- Add ``__builtin_set_flt_rounds`` builtin for X86, x86_64, Arm and AArch64 only.
- Add ``__builtin_elementwise_pow`` builtin for floating point types only.

AST Matchers
------------
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/Builtins.def
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,7 @@ BUILTIN(__builtin_elementwise_floor, "v.", "nct")
BUILTIN(__builtin_elementwise_log, "v.", "nct")
BUILTIN(__builtin_elementwise_log2, "v.", "nct")
BUILTIN(__builtin_elementwise_log10, "v.", "nct")
BUILTIN(__builtin_elementwise_pow, "v.", "nct")
BUILTIN(__builtin_elementwise_roundeven, "v.", "nct")
BUILTIN(__builtin_elementwise_round, "v.", "nct")
BUILTIN(__builtin_elementwise_rint, "v.", "nct")
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 @@ -3234,6 +3234,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_elementwise_log10:
return RValue::get(
emitUnaryBuiltin(*this, E, llvm::Intrinsic::log10, "elt.log10"));
case Builtin::BI__builtin_elementwise_pow: {
return RValue::get(emitBinaryBuiltin(*this, E, llvm::Intrinsic::pow));
}
case Builtin::BI__builtin_elementwise_cos:
return RValue::get(
emitUnaryBuiltin(*this, E, llvm::Intrinsic::cos, "elt.cos"));
Expand Down
16 changes: 16 additions & 0 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2657,6 +2657,22 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
return ExprError();
break;
}

// These builtins restrict the element type to floating point
// types only, and take in two arguments.
case Builtin::BI__builtin_elementwise_pow: {
if (SemaBuiltinElementwiseMath(TheCall))
return ExprError();

QualType ArgTy = TheCall->getArg(0)->getType();
if (checkFPMathBuiltinElementType(*this, TheCall->getArg(0)->getBeginLoc(),
ArgTy, 1) ||
checkFPMathBuiltinElementType(*this, TheCall->getArg(1)->getBeginLoc(),
ArgTy, 2))
return ExprError();
break;
}

// These builtins restrict the element type to integer
// types only.
case Builtin::BI__builtin_elementwise_add_sat:
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 @@ -452,6 +452,26 @@ void test_builtin_elementwise_log2(float f1, float f2, double d1, double d2,
vf2 = __builtin_elementwise_log2(vf1);
}

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

// CHECK-LABEL: define void @test_builtin_elementwise_pow(
// CHECK: [[F1:%.+]] = load float, ptr %f1.addr, align 4
// CHECK: [[F2:%.+]] = load float, ptr %f2.addr, align 4
// CHECK-NEXT: call float @llvm.pow.f32(float [[F1]], float [[F2]])
f2 = __builtin_elementwise_pow(f1, f2);

// CHECK: [[D1:%.+]] = load double, ptr %d1.addr, align 8
// CHECK: [[D2:%.+]] = load double, ptr %d2.addr, align 8
// CHECK-NEXT: call double @llvm.pow.f64(double [[D1]], double [[D2]])
d2 = __builtin_elementwise_pow(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: call <4 x float> @llvm.pow.v4f32(<4 x float> [[VF1]], <4 x float> [[VF2]])
vf2 = __builtin_elementwise_pow(vf1, vf2);
}

void test_builtin_elementwise_roundeven(float f1, float f2, double d1, double d2,
float4 vf1, float4 vf2) {
// CHECK-LABEL: define void @test_builtin_elementwise_roundeven(
Expand Down
9 changes: 9 additions & 0 deletions clang/test/CodeGen/strictfp-elementwise-bulitins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,3 +217,12 @@ float4 strict_elementwise_fma(float4 a, float4 b, float4 c) {
return __builtin_elementwise_fma(a, b, c);
}

// CHECK-LABEL: define dso_local noundef <4 x float> @_Z22strict_elementwise_powDv4_fS_
// CHECK-SAME: (<4 x float> noundef [[A:%.*]], <4 x float> noundef [[B:%.*]]) local_unnamed_addr #[[ATTR2]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP0:%.*]] = tail call <4 x float> @llvm.pow.v4f32(<4 x float> [[A]], <4 x float> [[B]]) #[[ATTR4]]
// CHECK-NEXT: ret <4 x float> [[TMP0]]
//
float4 strict_elementwise_pow(float4 a, float4 b) {
return __builtin_elementwise_pow(a, b);
}
12 changes: 12 additions & 0 deletions clang/test/Sema/aarch64-sve-vector-pow-ops.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// RUN: %clang_cc1 -triple aarch64 -target-feature +f -target-feature +d \
// RUN: -target-feature +v -target-feature +zfh -target-feature +sve -target-feature +experimental-zvfh \
// RUN: -disable-O0-optnone -o - -fsyntax-only %s -verify
// REQUIRES: aarch64-registered-target

#include <arm_sve.h>

svfloat32_t test_pow_vv_i8mf8(svfloat32_t v) {

return __builtin_elementwise_pow(v, v);
// expected-error@-1 {{1st argument must be a vector, integer or floating point type}}
}
25 changes: 25 additions & 0 deletions clang/test/Sema/builtins-elementwise-math.c
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,31 @@ void test_builtin_elementwise_log2(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_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')}}

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

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

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

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

i = __builtin_elementwise_pow(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_pow(uv, iv);
// expected-error@-1 {{arguments are of different types ('unsigned3' (vector of 3 'unsigned int' values) vs 'int3' (vector of 3 'int' values))}}

}


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
13 changes: 13 additions & 0 deletions clang/test/Sema/riscv-sve-vector-pow-ops.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// RUN: %clang_cc1 -triple riscv64 -target-feature +f -target-feature +d \
// RUN: -target-feature +v -target-feature +zfh -target-feature +experimental-zvfh \
// RUN: -disable-O0-optnone -o - -fsyntax-only %s -verify
// REQUIRES: riscv-registered-target

#include <riscv_vector.h>


vfloat32mf2_t test_pow_vv_i8mf8(vfloat32mf2_t v) {

return __builtin_elementwise_pow(v, v);
// expected-error@-1 {{1st argument must be a vector, integer or floating point type}}
}
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 @@ -198,3 +198,11 @@ void test_builtin_elementwise_fma() {
static_assert(!is_const<decltype(__builtin_elementwise_fma(b, a, c))>::value);
static_assert(!is_const<decltype(__builtin_elementwise_fma(c, c, c))>::value);
}

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

0 comments on commit 3a98e73

Please sign in to comment.