From: Petar Jovanovic Date: Fri, 6 Nov 2015 14:52:46 +0000 (+0000) Subject: Fix __builtin_signbit for ppcf128 type X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=db7ff082d2dbfb035d6ef21a107727ae61bf1e46;p=clang Fix __builtin_signbit for ppcf128 type Function__builtin_signbit returns wrong value for type ppcf128 on big endian machines. This patch fixes how value is generated in that case. Patch by Aleksandar Beserminji. Differential Revision: http://reviews.llvm.org/D14149 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@252307 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 50535d386e..e2bd9fc2c9 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -238,10 +238,20 @@ static Value *EmitSignBit(CodeGenFunction &CGF, Value *V) { 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. + // We want the sign bit of the higher-order double. The bitcast we just + // did works as if the double-double was stored to memory and then + // read as an i128. The "store" will put the higher-order double in the + // lower address in both little- and big-Endian modes, but the "load" + // will treat those bits as a different part of the i128: the low bits in + // little-Endian, the high bits in big-Endian. Therefore, on big-Endian + // we need to shift the high bits down to the low before truncating. Width >>= 1; + if (CGF.getTarget().isBigEndian()) { + Value *ShiftCst = llvm::ConstantInt::get(IntTy, Width); + V = CGF.Builder.CreateLShr(V, ShiftCst); + } + // We are truncating value in order to extract the higher-order + // double, which we will be using to extract the sign from. IntTy = llvm::IntegerType::get(C, Width); V = CGF.Builder.CreateTrunc(V, IntTy); } diff --git a/test/Analysis/builtin_signbit.cpp b/test/Analysis/builtin_signbit.cpp new file mode 100644 index 0000000000..bf91511c43 --- /dev/null +++ b/test/Analysis/builtin_signbit.cpp @@ -0,0 +1,43 @@ +// RUN: %clang -target powerpc-linux-gnu -emit-llvm -S -O0 %s -o - | FileCheck %s --check-prefix=CHECK-BE --check-prefix=CHECK +// RUN: %clang -target powerpc64-linux-gnu -emit-llvm -S -O0 %s -o - | FileCheck %s --check-prefix=CHECK-BE --check-prefix=CHECK +// RUN: %clang -target powerpc64le-linux-gnu -emit-llvm -S -O0 %s -o - | FileCheck %s --check-prefix=CHECK-LE --check-prefix=CHECK + +bool b; +double d = -1.0; +long double ld = -1.0L; +void test_signbit() +{ + b = __builtin_signbit(1.0L); + // CHECK: i128 + // CHECK-LE-NOT: lshr + // CHECK-BE: lshr + // CHECK: bitcast + // CHECK: ppc_fp128 + + b = __builtin_signbit(ld); + // CHECK: bitcast + // CHECK: ppc_fp128 + // CHECK-LE-NOT: lshr + // CHECK-BE: lshr + + b = __builtin_signbitf(1.0); + // CHECK: store i8 0 + + b = __builtin_signbitf(d); + // CHECK: bitcast + // CHECK-LE-NOT: lshr + // CHECK-BE-NOT: lshr + + b = __builtin_signbitl(1.0L); + // CHECK: i128 + // CHECK-LE-NOT: lshr + // CHECK-BE: lshr + // CHECK: bitcast + // CHECK: ppc_fp128 + + b = __builtin_signbitl(ld); + // CHECK: bitcast + // CHECK: ppc_fp128 + // CHECK-LE-NOT: lshr + // CHECK-BE: lshr +}