From 041b099ee1e18ca85b0b07d66d3488092c1f4b91 Mon Sep 17 00:00:00 2001 From: Hal Finkel Date: Sun, 24 Aug 2014 03:47:06 +0000 Subject: [PATCH] Implement __builtin_signbitl for PowerPC PowerPC uses the special PPC_FP128 type for long double on Linux, which is composed of two 64-bit doubles. The higher-order double (which contains the overall sign) comes first, and so the __builtin_signbitl implementation requires special handling to extract the sign bit. Fixes PR20691. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@216341 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGBuiltin.cpp | 10 ++++++++-- test/CodeGen/ppc-signbit.c | 11 +++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 test/CodeGen/ppc-signbit.c diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 6734ffe357..76e6e7c4a4 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -1347,11 +1347,17 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Value *Arg = EmitScalarExpr(E->getArg(0)); llvm::Type *ArgTy = Arg->getType(); - if (ArgTy->isPPC_FP128Ty()) - break; // FIXME: I'm not sure what the right implementation is here. 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()))); diff --git a/test/CodeGen/ppc-signbit.c b/test/CodeGen/ppc-signbit.c new file mode 100644 index 0000000000..31b71d8cdb --- /dev/null +++ b/test/CodeGen/ppc-signbit.c @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - -triple powerpc64-linux-gnu | FileCheck %s +// RUN: %clang_cc1 %s -emit-llvm -o - -triple powerpc64le-linux-gnu | FileCheck %s + +int test(long double x) { return __builtin_signbitl(x); } + +// CHECK-LABEL: define signext i32 @test(ppc_fp128 %x) +// CHECK: bitcast ppc_fp128 %{{.*}} to i128 +// CHECK: trunc i128 %{{.*}} to i64 +// CHECK: icmp slt i64 %{{.*}}, 0 +// CHECK: zext i1 %{{.*}} to i32 + -- 2.40.0