Skip to content

Commit 2ad4c3c

Browse files
committed
clang: Fix handling of __builtin_elementwise_copysign
I realized the handling of copysign made no sense at all. Only the type of the first operand should really matter, and it should not perform a conversion between them. Also fixes misleading errors and producing broken IR for integers. We could accept different FP types for the sign argument, if the intrinsic permitted different types like the DAG node. As it is we would need to insert a cast, which could have other effects (like trapping on snan) which should not happen for a copysign.
1 parent 1041053 commit 2ad4c3c

File tree

3 files changed

+137
-33
lines changed

3 files changed

+137
-33
lines changed

clang/lib/Sema/SemaChecking.cpp

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2025,6 +2025,33 @@ bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
20252025
}
20262026
}
20272027

2028+
// Check if \p Ty is a valid type for the elementwise math builtins. If it is
2029+
// not a valid type, emit an error message and return true. Otherwise return
2030+
// false.
2031+
static bool checkMathBuiltinElementType(Sema &S, SourceLocation Loc,
2032+
QualType Ty) {
2033+
if (!Ty->getAs<VectorType>() && !ConstantMatrixType::isValidElementType(Ty)) {
2034+
return S.Diag(Loc, diag::err_builtin_invalid_arg_type)
2035+
<< 1 << /* vector, integer or float ty*/ 0 << Ty;
2036+
}
2037+
2038+
return false;
2039+
}
2040+
2041+
static bool checkFPMathBuiltinElementType(Sema &S, SourceLocation Loc,
2042+
QualType ArgTy, int ArgIndex) {
2043+
QualType EltTy = ArgTy;
2044+
if (auto *VecTy = EltTy->getAs<VectorType>())
2045+
EltTy = VecTy->getElementType();
2046+
2047+
if (!EltTy->isRealFloatingType()) {
2048+
return S.Diag(Loc, diag::err_builtin_invalid_arg_type)
2049+
<< ArgIndex << /* vector or float ty*/ 5 << ArgTy;
2050+
}
2051+
2052+
return false;
2053+
}
2054+
20282055
ExprResult
20292056
Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
20302057
CallExpr *TheCall) {
@@ -2621,10 +2648,38 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
26212648

26222649
case Builtin::BI__builtin_elementwise_min:
26232650
case Builtin::BI__builtin_elementwise_max:
2624-
case Builtin::BI__builtin_elementwise_copysign:
26252651
if (SemaBuiltinElementwiseMath(TheCall))
26262652
return ExprError();
26272653
break;
2654+
case Builtin::BI__builtin_elementwise_copysign: {
2655+
if (checkArgCount(*this, TheCall, 2))
2656+
return ExprError();
2657+
2658+
ExprResult Magnitude = UsualUnaryConversions(TheCall->getArg(0));
2659+
ExprResult Sign = UsualUnaryConversions(TheCall->getArg(1));
2660+
if (Magnitude.isInvalid() || Sign.isInvalid())
2661+
return ExprError();
2662+
2663+
QualType MagnitudeTy = Magnitude.get()->getType();
2664+
QualType SignTy = Sign.get()->getType();
2665+
if (checkFPMathBuiltinElementType(*this, TheCall->getArg(0)->getBeginLoc(),
2666+
MagnitudeTy, 1) ||
2667+
checkFPMathBuiltinElementType(*this, TheCall->getArg(1)->getBeginLoc(),
2668+
SignTy, 2)) {
2669+
return ExprError();
2670+
}
2671+
2672+
if (MagnitudeTy.getCanonicalType() != SignTy.getCanonicalType()) {
2673+
return Diag(Sign.get()->getBeginLoc(),
2674+
diag::err_typecheck_call_different_arg_types)
2675+
<< MagnitudeTy << SignTy;
2676+
}
2677+
2678+
TheCall->setArg(0, Magnitude.get());
2679+
TheCall->setArg(1, Sign.get());
2680+
TheCall->setType(Magnitude.get()->getType());
2681+
break;
2682+
}
26282683
case Builtin::BI__builtin_reduce_max:
26292684
case Builtin::BI__builtin_reduce_min: {
26302685
if (PrepareBuiltinReduceMathOneArgCall(TheCall))
@@ -17669,19 +17724,6 @@ void Sema::CheckAddressOfPackedMember(Expr *rhs) {
1766917724
_2, _3, _4));
1767017725
}
1767117726

17672-
// Check if \p Ty is a valid type for the elementwise math builtins. If it is
17673-
// not a valid type, emit an error message and return true. Otherwise return
17674-
// false.
17675-
static bool checkMathBuiltinElementType(Sema &S, SourceLocation Loc,
17676-
QualType Ty) {
17677-
if (!Ty->getAs<VectorType>() && !ConstantMatrixType::isValidElementType(Ty)) {
17678-
S.Diag(Loc, diag::err_builtin_invalid_arg_type)
17679-
<< 1 << /* vector, integer or float ty*/ 0 << Ty;
17680-
return true;
17681-
}
17682-
return false;
17683-
}
17684-
1768517727
bool Sema::PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall) {
1768617728
if (checkArgCount(*this, TheCall, 1))
1768717729
return true;

clang/test/CodeGen/builtins-elementwise-math.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ void test_builtin_elementwise_canonicalize(float f1, float f2, double d1, double
432432
}
433433

434434
void test_builtin_elementwise_copysign(float f1, float f2, double d1, double d2,
435-
float4 vf1, float4 vf2) {
435+
float4 vf1, float4 vf2, double2 v2f64) {
436436
// CHECK-LABEL: define void @test_builtin_elementwise_copysign(
437437
// CHECK: [[F1:%.+]] = load float, ptr %f1.addr, align 4
438438
// CHECK-NEXT: [[F2:%.+]] = load float, ptr %f2.addr, align 4
@@ -463,4 +463,17 @@ void test_builtin_elementwise_copysign(float f1, float f2, double d1, double d2,
463463
// CHECK-NEXT: [[CVF1:%.+]] = load <4 x float>, ptr %cvf1, align 16
464464
// CHECK-NEXT: call <4 x float> @llvm.copysign.v4f32(<4 x float> [[VF2]], <4 x float> [[CVF1]])
465465
vf1 = __builtin_elementwise_copysign(vf2, cvf1);
466+
467+
468+
// CHECK: [[F1:%.+]] = load float, ptr %f1.addr
469+
// CHECK-NEXT: call float @llvm.copysign.f32(float [[F1]], float 2.000000e+00)
470+
f1 = __builtin_elementwise_copysign(f1, 2.0f);
471+
472+
// CHECK: [[F1:%.+]] = load float, ptr %f1.addr
473+
// CHECK-NEXT: call float @llvm.copysign.f32(float 2.000000e+00, float [[F1]])
474+
f1 = __builtin_elementwise_copysign(2.0f, f1);
475+
476+
// CHECK: [[V2F64:%.+]] = load <2 x double>, ptr %v2f64.addr, align 16
477+
// CHECK-NEXT: call <2 x double> @llvm.copysign.v2f64(<2 x double> <double 1.000000e+00, double 1.000000e+00>, <2 x double> [[V2F64]])
478+
v2f64 = __builtin_elementwise_copysign((double2)1.0, v2f64);
466479
}

clang/test/Sema/builtins-elementwise-math.c

Lines changed: 67 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
// RUN: %clang_cc1 -std=c99 %s -pedantic -verify -triple=x86_64-apple-darwin9
22

3+
typedef double double2 __attribute__((ext_vector_type(2)));
4+
typedef double double4 __attribute__((ext_vector_type(4)));
5+
typedef float float2 __attribute__((ext_vector_type(2)));
36
typedef float float4 __attribute__((ext_vector_type(4)));
47
typedef int int3 __attribute__((ext_vector_type(3)));
58
typedef unsigned unsigned3 __attribute__((ext_vector_type(3)));
@@ -13,6 +16,11 @@ __attribute__((address_space(1))) int int_as_one;
1316
typedef int bar;
1417
bar b;
1518

19+
__attribute__((address_space(1))) float float_as_one;
20+
typedef float waffle;
21+
waffle waf;
22+
23+
1624
void test_builtin_elementwise_abs(int i, double d, float4 v, int3 iv, unsigned u, unsigned4 uv) {
1725
struct Foo s = __builtin_elementwise_abs(i);
1826
// expected-error@-1 {{initializing 'struct Foo' with an expression of incompatible type 'int'}}
@@ -406,12 +414,12 @@ void test_builtin_elementwise_canonicalize(int i, float f, double d, float4 v, i
406414
// expected-error@-1 {{1st argument must be a floating point type (was 'unsigned4' (vector of 4 'unsigned int' values))}}
407415
}
408416

409-
void test_builtin_elementwise_copysign(int i, short s, double d, float4 v, int3 iv, unsigned3 uv, int *p) {
417+
void test_builtin_elementwise_copysign(int i, short s, double d, float f, float4 v, int3 iv, unsigned3 uv, int *p) {
410418
i = __builtin_elementwise_copysign(p, d);
411-
// expected-error@-1 {{arguments are of different types ('int *' vs 'double')}}
419+
// expected-error@-1 {{1st argument must be a floating point type (was 'int *')}}
412420

413-
struct Foo foo = __builtin_elementwise_copysign(i, i);
414-
// expected-error@-1 {{initializing 'struct Foo' with an expression of incompatible type 'int'}}
421+
i = __builtin_elementwise_copysign(i, i);
422+
// expected-error@-1 {{1st argument must be a floating point type (was 'int')}}
415423

416424
i = __builtin_elementwise_copysign(i);
417425
// expected-error@-1 {{too few arguments to function call, expected 2, have 1}}
@@ -423,40 +431,81 @@ void test_builtin_elementwise_copysign(int i, short s, double d, float4 v, int3
423431
// expected-error@-1 {{too many arguments to function call, expected 2, have 3}}
424432

425433
i = __builtin_elementwise_copysign(v, iv);
426-
// expected-error@-1 {{arguments are of different types ('float4' (vector of 4 'float' values) vs 'int3' (vector of 3 'int' values))}}
434+
// expected-error@-1 {{2nd argument must be a floating point type (was 'int3' (vector of 3 'int' values))}}
427435

428436
i = __builtin_elementwise_copysign(uv, iv);
429-
// expected-error@-1 {{arguments are of different types ('unsigned3' (vector of 3 'unsigned int' values) vs 'int3' (vector of 3 'int' values))}}
437+
// expected-error@-1 {{1st argument must be a floating point type (was 'unsigned3' (vector of 3 'unsigned int' values))}}
430438

431439
s = __builtin_elementwise_copysign(i, s);
440+
// expected-error@-1 {{1st argument must be a floating point type (was 'int')}}
441+
442+
f = __builtin_elementwise_copysign(f, i);
443+
// expected-error@-1 {{2nd argument must be a floating point type (was 'int')}}
444+
445+
f = __builtin_elementwise_copysign(i, f);
446+
// expected-error@-1 {{1st argument must be a floating point type (was 'int')}}
432447

433448
enum e { one,
434449
two };
435450
i = __builtin_elementwise_copysign(one, two);
451+
// expected-error@-1 {{1st argument must be a floating point type (was 'int')}}
436452

437453
enum f { three };
438454
enum f x = __builtin_elementwise_copysign(one, three);
455+
// expected-error@-1 {{1st argument must be a floating point type (was 'int')}}
439456

440457
_BitInt(32) ext; // expected-warning {{'_BitInt' in C17 and earlier is a Clang extension}}
441458
ext = __builtin_elementwise_copysign(ext, ext);
459+
// expected-error@-1 {{1st argument must be a floating point type (was '_BitInt(32)')}}
442460

443-
const int ci;
444-
i = __builtin_elementwise_copysign(ci, i);
445-
i = __builtin_elementwise_copysign(i, ci);
446-
i = __builtin_elementwise_copysign(ci, ci);
461+
const float cf32;
462+
f = __builtin_elementwise_copysign(cf32, f);
463+
f = __builtin_elementwise_copysign(f, cf32);
464+
f = __builtin_elementwise_copysign(cf32, f);
447465

448-
i = __builtin_elementwise_copysign(i, int_as_one); // ok (attributes don't match)?
449-
i = __builtin_elementwise_copysign(i, b); // ok (sugar doesn't match)?
466+
f = __builtin_elementwise_copysign(f, float_as_one); // ok (attributes don't match)?
467+
f = __builtin_elementwise_copysign(f, waf); // ok (sugar doesn't match)?
450468

451-
int A[10];
469+
float A[10];
452470
A = __builtin_elementwise_copysign(A, A);
453-
// expected-error@-1 {{1st argument must be a vector, integer or floating point type (was 'int *')}}
471+
// expected-error@-1 {{1st argument must be a floating point type (was 'float *')}}
454472

455-
int(ii);
456-
int j;
457-
j = __builtin_elementwise_copysign(i, j);
473+
float(ii);
474+
float j;
475+
j = __builtin_elementwise_copysign(f, j);
458476

459477
_Complex float c1, c2;
460478
c1 = __builtin_elementwise_copysign(c1, c2);
461-
// expected-error@-1 {{1st argument must be a vector, integer or floating point type (was '_Complex float')}}
479+
// expected-error@-1 {{1st argument must be a floating point type (was '_Complex float')}}
480+
481+
double f64 = 0.0;
482+
double tmp0 = __builtin_elementwise_copysign(f64, f);
483+
// expected-error@-1 {{arguments are of different types ('double' vs 'float')}}
484+
485+
float tmp1 = __builtin_elementwise_copysign(f, f64);
486+
//expected-error@-1 {{arguments are of different types ('float' vs 'double')}}
487+
488+
float4 v4f32 = 0.0f;
489+
float4 tmp2 = __builtin_elementwise_copysign(v4f32, f);
490+
// expected-error@-1 {{arguments are of different types ('float4' (vector of 4 'float' values) vs 'float')}}
491+
492+
float tmp3 = __builtin_elementwise_copysign(f, v4f32);
493+
// expected-error@-1 {{arguments are of different types ('float' vs 'float4' (vector of 4 'float' values))}}
494+
495+
float2 v2f32 = 0.0f;
496+
double4 v4f64 = 0.0;
497+
double4 tmp4 = __builtin_elementwise_copysign(v4f64, v4f32);
498+
// expected-error@-1 {{arguments are of different types ('double4' (vector of 4 'double' values) vs 'float4' (vector of 4 'float' values))}}
499+
500+
float4 tmp6 = __builtin_elementwise_copysign(v4f32, v4f64);
501+
// expected-error@-1 {{arguments are of different types ('float4' (vector of 4 'float' values) vs 'double4' (vector of 4 'double' values))}}
502+
503+
float4 tmp7 = __builtin_elementwise_copysign(v4f32, v2f32);
504+
// expected-error@-1 {{arguments are of different types ('float4' (vector of 4 'float' values) vs 'float2' (vector of 2 'float' values))}}
505+
506+
float2 tmp8 = __builtin_elementwise_copysign(v2f32, v4f32);
507+
// expected-error@-1 {{arguments are of different types ('float2' (vector of 2 'float' values) vs 'float4' (vector of 4 'float' values))}}
508+
509+
float2 tmp9 = __builtin_elementwise_copysign(v4f32, v4f32);
510+
// expected-error@-1 {{initializing 'float2' (vector of 2 'float' values) with an expression of incompatible type 'float4' (vector of 4 'float' values)}}
462511
}

0 commit comments

Comments
 (0)