BUILTIN(__builtin_isunordered , "i.", "Fnct")
// Unary FP classification
-BUILTIN(__builtin_fpclassify, "iiiiii.", "Fnc")
-BUILTIN(__builtin_isfinite, "i.", "Fnc")
-BUILTIN(__builtin_isinf, "i.", "Fnc")
-BUILTIN(__builtin_isinf_sign, "i.", "Fnc")
-BUILTIN(__builtin_isnan, "i.", "Fnc")
-BUILTIN(__builtin_isnormal, "i.", "Fnc")
+BUILTIN(__builtin_fpclassify, "iiiiii.", "Fnct")
+BUILTIN(__builtin_isfinite, "i.", "Fnct")
+BUILTIN(__builtin_isinf, "i.", "Fnct")
+BUILTIN(__builtin_isinf_sign, "i.", "Fnct")
+BUILTIN(__builtin_isnan, "i.", "Fnct")
+BUILTIN(__builtin_isnormal, "i.", "Fnct")
// FP signbit builtins
-BUILTIN(__builtin_signbit, "i.", "Fnc")
+BUILTIN(__builtin_signbit, "i.", "Fnct")
BUILTIN(__builtin_signbitf, "if", "Fnc")
BUILTIN(__builtin_signbitl, "iLd", "Fnc")
<< SourceRange(TheCall->getArg(NumArgs)->getBeginLoc(),
(*(TheCall->arg_end() - 1))->getEndLoc());
+ // __builtin_fpclassify is the only case where NumArgs != 1, so we can count
+ // on all preceding parameters just being int. Try all of those.
+ for (unsigned i = 0; i < NumArgs - 1; ++i) {
+ Expr *Arg = TheCall->getArg(i);
+
+ if (Arg->isTypeDependent())
+ return false;
+
+ ExprResult Res = PerformImplicitConversion(Arg, Context.IntTy, AA_Passing);
+
+ if (Res.isInvalid())
+ return true;
+ TheCall->setArg(i, Res.get());
+ }
+
Expr *OrigArg = TheCall->getArg(NumArgs-1);
if (OrigArg->isTypeDependent())
return false;
+ // Usual Unary Conversions will convert half to float, which we want for
+ // machines that use fp16 conversion intrinsics. Else, we wnat to leave the
+ // type how it is, but do normal L->Rvalue conversions.
+ if (Context.getTargetInfo().useFP16ConversionIntrinsics())
+ OrigArg = UsualUnaryConversions(OrigArg).get();
+ else
+ OrigArg = DefaultFunctionArrayLvalueConversion(OrigArg).get();
+ TheCall->setArg(NumArgs - 1, OrigArg);
+
// This operation requires a non-_Complex floating-point number.
if (!OrigArg->getType()->isRealFloatingType())
return Diag(OrigArg->getBeginLoc(),
diag::err_typecheck_call_invalid_unary_fp)
<< OrigArg->getType() << OrigArg->getSourceRange();
- // If this is an implicit conversion from float -> float, double, or
- // long double, or half -> half, float, double, or long double, remove it.
- if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(OrigArg)) {
- // Only remove standard FloatCasts, leaving other casts inplace
- if (Cast->getCastKind() == CK_FloatingCast) {
- bool IgnoreCast = false;
- Expr *CastArg = Cast->getSubExpr();
- if (CastArg->getType()->isSpecificBuiltinType(BuiltinType::Float)) {
- assert(
- (Cast->getType()->isSpecificBuiltinType(BuiltinType::Double) ||
- Cast->getType()->isSpecificBuiltinType(BuiltinType::Float) ||
- Cast->getType()->isSpecificBuiltinType(BuiltinType::LongDouble)) &&
- "promotion from float to either float, double, or long double is "
- "the only expected cast here");
- IgnoreCast = true;
- } else if (CastArg->getType()->isSpecificBuiltinType(BuiltinType::Half) &&
- !Context.getTargetInfo().useFP16ConversionIntrinsics()) {
- assert(
- (Cast->getType()->isSpecificBuiltinType(BuiltinType::Double) ||
- Cast->getType()->isSpecificBuiltinType(BuiltinType::Float) ||
- Cast->getType()->isSpecificBuiltinType(BuiltinType::Half) ||
- Cast->getType()->isSpecificBuiltinType(BuiltinType::LongDouble)) &&
- "promotion from half to either half, float, double, or long double "
- "is the only expected cast here");
- IgnoreCast = true;
- }
-
- if (IgnoreCast) {
- Cast->setSubExpr(nullptr);
- TheCall->setArg(NumArgs-1, CastArg);
- }
- }
- }
-
return false;
}
-// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -triple x86_64-windows-pc -o - %s | FileCheck %s --check-prefixes=CHECK,FP16
+// RUN: %clang_cc1 -emit-llvm -triple ppc64-be -o - %s -DNO_FP16 | FileCheck %s --check-prefixes=CHECK,NOFP16
// test to ensure that these builtins don't do the variadic promotion of float->double.
void test_floats(float f1, float f2) {
// CHECK-NEXT: zext i1
}
+void test_half(__fp16 *H, __fp16 *H2) {
+ (void)__builtin_isgreater(*H, *H2);
+ // CHECK: fcmp ogt float
+ // CHECK-NEXT: zext i1
+ (void)__builtin_isinf(*H);
+ // NOFP16: fcmp oeq float %{{.+}}, 0x7FF
+ // FP16: fcmp oeq half %{{.+}}, 0xH7C
+}
+
void test_mixed(double d1, float f2) {
(void)__builtin_isgreater(d1, f2);
// CHECK: fpext float {{.*}} to double
--- /dev/null
+// RUN: %clang_cc1 %s -Wno-unused-value -verify -fsyntax-only
+// RUN: %clang_cc1 %s -Wno-unused-value -ast-dump -DAST_CHECK | FileCheck %s
+
+struct S {};
+void usage(float f, int i, double d) {
+#ifdef AST_CHECK
+ __builtin_fpclassify(d, 1, i, i, 3, d);
+ //CHECK: CallExpr
+ //CHECK-NEXT: ImplicitCastExpr
+ //CHECK-SAME: <BuiltinFnToFnPtr>
+ //CHECK-NEXT: DeclRefExpr
+ //CHECK-SAME: '__builtin_fpclassify'
+ //CHECK-NEXT: ImplicitCastExpr
+ //CHECK-SAME: 'int' <FloatingToIntegral>
+ //CHECK-NEXT: ImplicitCastExpr
+ //CHECK-SAME: 'double' <LValueToRValue>
+ //CHECK-NEXT: DeclRefExpr
+ //CHECK-SAME: 'd' 'double'
+ //CHECK-NEXT: IntegerLiteral
+ //CHECK-NEXT: ImplicitCastExpr
+ //CHECK-SAME: 'int' <LValueToRValue>
+ //CHECK-NEXT: DeclRefExpr
+ //CHECK-SAME: 'i' 'int'
+ //CHECK-NEXT: ImplicitCastExpr
+ //CHECK-SAME: 'int' <LValueToRValue>
+ //CHECK-NEXT: DeclRefExpr
+ //CHECK-SAME: 'i' 'int'
+ //CHECK-NEXT: IntegerLiteral
+ //CHECK-NEXT: ImplicitCastExpr
+ //CHECK-SAME: 'double' <LValueToRValue>
+ //CHECK-NEXT: DeclRefExpr
+ //CHECK-SAME: 'd' 'double'
+
+ __builtin_fpclassify(f, 1, i, i, 3, f);
+ //CHECK: CallExpr
+ //CHECK-NEXT: ImplicitCastExpr
+ //CHECK-SAME: <BuiltinFnToFnPtr>
+ //CHECK-NEXT: DeclRefExpr
+ //CHECK-SAME: '__builtin_fpclassify'
+ //CHECK-NEXT: ImplicitCastExpr
+ //CHECK-SAME: 'int' <FloatingToIntegral>
+ //CHECK-NEXT: ImplicitCastExpr
+ //CHECK-SAME: 'float' <LValueToRValue>
+ //CHECK-NEXT: DeclRefExpr
+ //CHECK-SAME: 'f' 'float'
+ //CHECK-NEXT: IntegerLiteral
+ //CHECK-NEXT: ImplicitCastExpr
+ //CHECK-SAME: 'int' <LValueToRValue>
+ //CHECK-NEXT: DeclRefExpr
+ //CHECK-SAME: 'i' 'int'
+ //CHECK-NEXT: ImplicitCastExpr
+ //CHECK-SAME: 'int' <LValueToRValue>
+ //CHECK-NEXT: DeclRefExpr
+ //CHECK-SAME: 'i' 'int'
+ //CHECK-NEXT: IntegerLiteral
+ //CHECK-NEXT: ImplicitCastExpr
+ //CHECK-SAME: 'float' <LValueToRValue>
+ //CHECK-NEXT: DeclRefExpr
+ //CHECK-SAME: 'f' 'float'
+
+ __builtin_isfinite(f);
+ //CHECK: CallExpr
+ //CHECK-NEXT: ImplicitCastExpr
+ //CHECK-SAME: <BuiltinFnToFnPtr>
+ //CHECK-NEXT: DeclRefExpr
+ //CHECK-SAME: '__builtin_isfinite'
+ //CHECK-NEXT: ImplicitCastExpr
+ //CHECK-SAME: 'float' <LValueToRValue>
+ //CHECK-NEXT: DeclRefExpr
+ //CHECK-SAME: 'f' 'float'
+
+ __builtin_isfinite(d);
+ //CHECK: CallExpr
+ //CHECK-NEXT: ImplicitCastExpr
+ //CHECK-SAME: <BuiltinFnToFnPtr>
+ //CHECK-NEXT: DeclRefExpr
+ //CHECK-SAME: '__builtin_isfinite'
+ //CHECK-NEXT: ImplicitCastExpr
+ //CHECK-SAME: 'double' <LValueToRValue>
+ //CHECK-NEXT: DeclRefExpr
+ //CHECK-SAME: 'd' 'double'
+#else
+ struct S s;
+ // expected-error@+1{{passing 'struct S' to parameter of incompatible type 'int'}}
+ __builtin_fpclassify(d, s, i, i, 3, d);
+ // expected-error@+1{{floating point classification requires argument of floating point type (passed in 'int')}}
+ __builtin_fpclassify(d, 1, i, i, 3, i);
+ // expected-error@+1{{floating point classification requires argument of floating point type (passed in 'int')}}
+ __builtin_isfinite(i);
+#endif
+}
// RUN: %clang_cc1 -triple=x86_64-apple-darwin -fsyntax-only -verify %s
// PR23086
-__builtin_isinf(...); // expected-warning {{type specifier missing, defaults to 'int'}} expected-error {{ISO C requires a named parameter before '...'}} // expected-error {{conflicting types for '__builtin_isinf'}} // expected-note {{'__builtin_isinf' is a builtin with type 'int ()'}}
+__builtin_isinf(...); // expected-warning {{type specifier missing, defaults to 'int'}} expected-error {{ISO C requires a named parameter before '...'}} // expected-error {{cannot redeclare builtin function '__builtin_isinf'}} // expected-note {{'__builtin_isinf' is a builtin with type 'int ()'}}