diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2635,7 +2635,6 @@ case Builtin::BI__builtin_elementwise_floor: case Builtin::BI__builtin_elementwise_log: case Builtin::BI__builtin_elementwise_log2: - case Builtin::BI__builtin_elementwise_pow: case Builtin::BI__builtin_elementwise_log10: case Builtin::BI__builtin_elementwise_roundeven: case Builtin::BI__builtin_elementwise_round: @@ -2658,6 +2657,23 @@ 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: diff --git a/clang/test/CodeGen/builtins-elementwise-math.c b/clang/test/CodeGen/builtins-elementwise-math.c --- a/clang/test/CodeGen/builtins-elementwise-math.c +++ b/clang/test/CodeGen/builtins-elementwise-math.c @@ -453,52 +453,23 @@ } void test_builtin_elementwise_pow(float f1, float f2, double d1, double d2, - float4 vf1, float4 vf2, long long int i1, - long long int i2, si8 vi1, si8 vi2, - unsigned u1, unsigned u2, u4 vu1, u4 vu2, - _BitInt(31) bi1, _BitInt(31) bi2, - unsigned _BitInt(55) bu1, unsigned _BitInt(55) bu2) { - // CHECK: [[I1:%.+]] = load i64, ptr %i1.addr, align 8 - // CHECK-NEXT: [[I2:%.+]] = load i64, ptr %i2.addr, align 8 - // CHECK-NEXT: call i64 @llvm.pow.i64(i64 [[I1]], i64 [[I2]]) - i1 = __builtin_elementwise_pow(i1, i2); - - // CHECK: [[I1:%.+]] = load i64, ptr %i1.addr, align 8 - // CHECK-NEXT: call i64 @llvm.pow.i64(i64 [[I1]], i64 10) - i1 = __builtin_elementwise_pow(i1, 10); - - // CHECK: [[VI1:%.+]] = load <8 x i16>, ptr %vi1.addr, align 16 - // CHECK-NEXT: [[VI2:%.+]] = load <8 x i16>, ptr %vi2.addr, align 16 - // CHECK-NEXT: call <8 x i16> @llvm.pow.v8i16(<8 x i16> [[VI1]], <8 x i16> [[VI2]]) - vi1 = __builtin_elementwise_pow(vi1, vi2); - - // CHECK: [[U1:%.+]] = load i32, ptr %u1.addr, align 4 - // CHECK-NEXT: [[U2:%.+]] = load i32, ptr %u2.addr, align 4 - // CHECK-NEXT: call i32 @llvm.pow.i32(i32 [[U1]], i32 [[U2]]) - u1 = __builtin_elementwise_pow(u1, u2); + float4 vf1, float4 vf2) { - // CHECK: [[VU1:%.+]] = load <4 x i32>, ptr %vu1.addr, align 16 - // CHECK-NEXT: [[VU2:%.+]] = load <4 x i32>, ptr %vu2.addr, align 16 - // CHECK-NEXT: call <4 x i32> @llvm.pow.v4i32(<4 x i32> [[VU1]], <4 x i32> [[VU2]]) - vu1 = __builtin_elementwise_pow(vu1, vu2); - - // CHECK: [[BI1:%.+]] = load i31, ptr %bi1.addr, align 4 - // CHECK-NEXT: [[BI2:%.+]] = load i31, ptr %bi2.addr, align 4 - // CHECK-NEXT: call i31 @llvm.pow.i31(i31 [[BI1]], i31 [[BI2]]) - bi1 = __builtin_elementwise_pow(bi1, bi2); - - // CHECK: [[BU1:%.+]] = load i55, ptr %bu1.addr, align 8 - // CHECK-NEXT: [[BU2:%.+]] = load i55, ptr %bu2.addr, align 8 - // CHECK-NEXT: call i55 @llvm.pow.i55(i55 [[BU1]], i55 [[BU2]]) - bu1 = __builtin_elementwise_pow(bu1, bu2); + // 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: [[IAS1:%.+]] = load i32, ptr addrspace(1) @int_as_one, align 4 - // CHECK-NEXT: [[B:%.+]] = load i32, ptr @b, align 4 - // CHECK-NEXT: call i32 @llvm.pow.i32(i32 [[IAS1]], i32 [[B]]) - int_as_one = __builtin_elementwise_pow(int_as_one, b); + // 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: call i32 @llvm.pow.i32(i32 1, i32 97) - i1 = __builtin_elementwise_pow(1, 'a'); + // 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, diff --git a/clang/test/Sema/builtins-elementwise-math.c b/clang/test/Sema/builtins-elementwise-math.c --- a/clang/test/Sema/builtins-elementwise-math.c +++ b/clang/test/Sema/builtins-elementwise-math.c @@ -443,7 +443,7 @@ // expected-error@-1 {{arguments are of different types ('int *' vs 'double')}} struct Foo foo = __builtin_elementwise_pow(i, i); - // expected-error@-1 {{initializing 'struct Foo' with an expression of incompatible type 'int'}} + // 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}} @@ -460,11 +460,6 @@ 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))}} - v = __builtin_elementwise_pow(v, v); - // expected-error@-1 {{1st argument must be a vector of integers (was 'float4' (vector of 4 'float' values))}} - - s = __builtin_elementwise_pow(i, s); - enum e { one, two }; i = __builtin_elementwise_pow(one, two);