From c66deafb73e6c426db2dba44864183b8e44cd4c2 Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Thu, 19 Mar 2015 22:39:51 +0000 Subject: [PATCH] [Modules] Implement __builtin_isinf_sign in Clang. Somehow, we never managed to implement this fully. We could constant fold it like crazy, including constant folding complex arguments, etc. But if you actually needed to generate code for it, error. I've implemented it using the somewhat obvious lowering. Happy for suggestions on a more clever way to lower this. Now, what you might ask does this have to do with modules? Fun story. So it turns out that libstdc++ actually uses __builtin_isinf_sign to implement std::isinf when in C++98 mode, but only inside of a template. So if we're lucky, and we never instantiate that, everything is good. But once we try to instantiate that template function, we need this builtin. All of my customers at least are using C++11 and so they never hit this code path. But what does that have to do with modules? Fun story. So it turns out that with modules we actually observe a bunch of bugs in libstdc++ where their header clobbers things exposed by . To fix these, we have to provide global function definitions to replace the macros that C99 would have used. And it turns out that ::isinf needs to be implemented using the exact semantics used by the C++98 variant of std::isinf. And so I started to fix this bug in libstdc++ and ceased to be able to compile libstdc++ with Clang. The yaks are legion. llvm-svn: 232778 --- clang/lib/CodeGen/CGBuiltin.cpp | 60 +++++++++++++++++++++++++++-------------- clang/test/CodeGen/builtins.c | 32 +++++++++++++++++++--- 2 files changed, 68 insertions(+), 24 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 4c79a34..fc9e4dd 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -158,6 +158,27 @@ static Value *EmitFAbs(CodeGenFunction &CGF, Value *V) { return Call; } +/// Emit the computation of the sign bit for a floating point value. Returns +/// the i1 sign bit value. +static Value *EmitSignBit(CodeGenFunction &CGF, Value *V) { + LLVMContext &C = CGF.CGM.getLLVMContext(); + + llvm::Type *Ty = V->getType(); + int Width = Ty->getPrimitiveSizeInBits(); + llvm::Type *IntTy = llvm::IntegerType::get(C, Width); + V = CGF.Builder.CreateBitCast(V, IntTy); + if (Ty->isPPC_FP128Ty()) { + // The higher-order double comes first, and so we need to truncate the + // pair to extract the overall sign. The order of the pair is the same + // in both little- and big-Endian modes. + Width >>= 1; + IntTy = llvm::IntegerType::get(C, Width); + V = CGF.Builder.CreateTrunc(V, IntTy); + } + Value *Zero = llvm::Constant::getNullValue(IntTy); + return CGF.Builder.CreateICmpSLT(V, Zero); +} + static RValue emitLibraryCall(CodeGenFunction &CGF, const FunctionDecl *Fn, const CallExpr *E, llvm::Value *calleeValue) { return CGF.EmitCall(E->getCallee()->getType(), calleeValue, E, @@ -558,8 +579,22 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType()))); } - // TODO: BI__builtin_isinf_sign - // isinf_sign(x) -> isinf(x) ? (signbit(x) ? -1 : 1) : 0 + case Builtin::BI__builtin_isinf_sign: { + // isinf_sign(x) -> fabs(x) == infinity ? (signbit(x) ? -1 : 1) : 0 + Value *Arg = EmitScalarExpr(E->getArg(0)); + Value *AbsArg = EmitFAbs(*this, Arg); + Value *IsInf = Builder.CreateFCmpOEQ( + AbsArg, ConstantFP::getInfinity(Arg->getType()), "isinf"); + Value *IsNeg = EmitSignBit(*this, Arg); + + llvm::Type *IntTy = ConvertType(E->getType()); + Value *Zero = Constant::getNullValue(IntTy); + Value *One = ConstantInt::get(IntTy, 1); + Value *NegativeOne = ConstantInt::get(IntTy, -1); + Value *SignResult = Builder.CreateSelect(IsNeg, NegativeOne, One); + Value *Result = Builder.CreateSelect(IsInf, SignResult, Zero); + return RValue::get(Result); + } case Builtin::BI__builtin_isnormal: { // isnormal(x) --> x == x && fabsf(x) < infinity && fabsf(x) >= float_min @@ -1398,24 +1433,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__builtin_signbit: case Builtin::BI__builtin_signbitf: case Builtin::BI__builtin_signbitl: { - LLVMContext &C = CGM.getLLVMContext(); - - Value *Arg = EmitScalarExpr(E->getArg(0)); - llvm::Type *ArgTy = Arg->getType(); - int ArgWidth = ArgTy->getPrimitiveSizeInBits(); - llvm::Type *ArgIntTy = llvm::IntegerType::get(C, ArgWidth); - Value *BCArg = Builder.CreateBitCast(Arg, ArgIntTy); - if (ArgTy->isPPC_FP128Ty()) { - // The higher-order double comes first, and so we need to truncate the - // pair to extract the overall sign. The order of the pair is the same - // in both little- and big-Endian modes. - ArgWidth >>= 1; - ArgIntTy = llvm::IntegerType::get(C, ArgWidth); - BCArg = Builder.CreateTrunc(BCArg, ArgIntTy); - } - Value *ZeroCmp = llvm::Constant::getNullValue(ArgIntTy); - Value *Result = Builder.CreateICmpSLT(BCArg, ZeroCmp); - return RValue::get(Builder.CreateZExt(Result, ConvertType(E->getType()))); + return RValue::get( + Builder.CreateZExt(EmitSignBit(*this, EmitScalarExpr(E->getArg(0))), + ConvertType(E->getType()))); } case Builtin::BI__builtin_annotation: { llvm::Value *AnnVal = EmitScalarExpr(E->getArg(0)); diff --git a/clang/test/CodeGen/builtins.c b/clang/test/CodeGen/builtins.c index bf7874b..39b2c12 100644 --- a/clang/test/CodeGen/builtins.c +++ b/clang/test/CodeGen/builtins.c @@ -42,8 +42,6 @@ int main() { P(fpclassify, (0, 1, 2, 3, 4, 1.0)); P(fpclassify, (0, 1, 2, 3, 4, 1.0f)); P(fpclassify, (0, 1, 2, 3, 4, 1.0l)); - // FIXME: - // P(isinf_sign, (1.0)); Q(nan, ("")); Q(nanf, ("")); @@ -61,6 +59,8 @@ int main() { P(islessgreater, (1., 2.)); P(isunordered, (1., 2.)); + P(isinf, (1.)); + P(isinf_sign, (1.)); P(isnan, (1.)); // Bitwise & Numeric Functions @@ -177,11 +177,35 @@ void test_float_builtins(float F, double D, long double LD) { res = __builtin_isinf(D); // CHECK: call double @llvm.fabs.f64(double // CHECK: fcmp oeq double {{.*}}, 0x7FF0000000000000 - + res = __builtin_isinf(LD); // CHECK: call x86_fp80 @llvm.fabs.f80(x86_fp80 // CHECK: fcmp oeq x86_fp80 {{.*}}, 0xK7FFF8000000000000000 - + + res = __builtin_isinf_sign(F); + // CHECK: %[[ABS:.*]] = call float @llvm.fabs.f32(float %[[ARG:.*]]) + // CHECK: %[[ISINF:.*]] = fcmp oeq float %[[ABS]], 0x7FF0000000000000 + // CHECK: %[[BITCAST:.*]] = bitcast float %[[ARG]] to i32 + // CHECK: %[[ISNEG:.*]] = icmp slt i32 %[[BITCAST]], 0 + // CHECK: %[[SIGN:.*]] = select i1 %[[ISNEG]], i32 -1, i32 1 + // CHECK: select i1 %[[ISINF]], i32 %[[SIGN]], i32 0 + + res = __builtin_isinf_sign(D); + // CHECK: %[[ABS:.*]] = call double @llvm.fabs.f64(double %[[ARG:.*]]) + // CHECK: %[[ISINF:.*]] = fcmp oeq double %[[ABS]], 0x7FF0000000000000 + // CHECK: %[[BITCAST:.*]] = bitcast double %[[ARG]] to i64 + // CHECK: %[[ISNEG:.*]] = icmp slt i64 %[[BITCAST]], 0 + // CHECK: %[[SIGN:.*]] = select i1 %[[ISNEG]], i32 -1, i32 1 + // CHECK: select i1 %[[ISINF]], i32 %[[SIGN]], i32 0 + + res = __builtin_isinf_sign(LD); + // CHECK: %[[ABS:.*]] = call x86_fp80 @llvm.fabs.f80(x86_fp80 %[[ARG:.*]]) + // CHECK: %[[ISINF:.*]] = fcmp oeq x86_fp80 %[[ABS]], 0xK7FFF8000000000000000 + // CHECK: %[[BITCAST:.*]] = bitcast x86_fp80 %[[ARG]] to i80 + // CHECK: %[[ISNEG:.*]] = icmp slt i80 %[[BITCAST]], 0 + // CHECK: %[[SIGN:.*]] = select i1 %[[ISNEG]], i32 -1, i32 1 + // CHECK: select i1 %[[ISINF]], i32 %[[SIGN]], i32 0 + res = __builtin_isfinite(F); // CHECK: fcmp oeq float // CHECK: call float @llvm.fabs.f32(float -- 2.7.4