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 @@ -5808,10 +5808,11 @@ << OrigArg->getType() << OrigArg->getSourceRange(); // If this is an implicit conversion from float -> float, double, or - // long double, remove it. + // long double, or half -> half, float, double, or long double, remove it. if (ImplicitCastExpr *Cast = dyn_cast(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( @@ -5820,6 +5821,19 @@ 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)) { + 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); } diff --git a/clang/test/CodeGen/builtins.c b/clang/test/CodeGen/builtins.c --- a/clang/test/CodeGen/builtins.c +++ b/clang/test/CodeGen/builtins.c @@ -193,8 +193,12 @@ } // CHECK-LABEL: define void @test_float_builtins -void test_float_builtins(float F, double D, long double LD) { +void test_float_builtins(__fp16 *H, float F, double D, long double LD) { volatile int res; + res = __builtin_isinf(*H); + // CHECK: call half @llvm.fabs.f16(half + // CHECK: fcmp oeq half {{.*}}, 0xH7C00 + res = __builtin_isinf(F); // CHECK: call float @llvm.fabs.f32(float // CHECK: fcmp oeq float {{.*}}, 0x7FF0000000000000 @@ -207,6 +211,14 @@ // CHECK: call x86_fp80 @llvm.fabs.f80(x86_fp80 // CHECK: fcmp oeq x86_fp80 {{.*}}, 0xK7FFF8000000000000000 + res = __builtin_isinf_sign(*H); + // CHECK: %[[ABS:.*]] = call half @llvm.fabs.f16(half %[[ARG:.*]]) + // CHECK: %[[ISINF:.*]] = fcmp oeq half %[[ABS]], 0xH7C00 + // CHECK: %[[BITCAST:.*]] = bitcast half %[[ARG]] to i16 + // CHECK: %[[ISNEG:.*]] = icmp slt i16 %[[BITCAST]], 0 + // CHECK: %[[SIGN:.*]] = select i1 %[[ISNEG]], i32 -1, i32 1 + // CHECK: select i1 %[[ISINF]], i32 %[[SIGN]], i32 0 + res = __builtin_isinf_sign(F); // CHECK: %[[ABS:.*]] = call float @llvm.fabs.f32(float %[[ARG:.*]]) // CHECK: %[[ISINF:.*]] = fcmp oeq float %[[ABS]], 0x7FF0000000000000 @@ -231,6 +243,10 @@ // CHECK: %[[SIGN:.*]] = select i1 %[[ISNEG]], i32 -1, i32 1 // CHECK: select i1 %[[ISINF]], i32 %[[SIGN]], i32 0 + res = __builtin_isfinite(*H); + // CHECK: call half @llvm.fabs.f16(half + // CHECK: fcmp one half {{.*}}, 0xH7C00 + res = __builtin_isfinite(F); // CHECK: call float @llvm.fabs.f32(float // CHECK: fcmp one float {{.*}}, 0x7FF0000000000000 @@ -239,6 +255,14 @@ // CHECK: call double @llvm.fabs.f64(double // CHECK: fcmp one double {{.*}}, 0x7FF0000000000000 + res = __builtin_isnormal(*H); + // CHECK: fcmp oeq half + // CHECK: call half @llvm.fabs.f16(half + // CHECK: fcmp ult half {{.*}}, 0xH7C00 + // CHECK: fcmp uge half {{.*}}, 0xH0400 + // CHECK: and i1 + // CHECK: and i1 + res = __builtin_isnormal(F); // CHECK: fcmp oeq float // CHECK: call float @llvm.fabs.f32(float