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

llvm-svn: 252307
This commit is contained in:
Petar Jovanovic 2015-11-06 14:52:46 +00:00
parent 1aa4d1c56f
commit 73d1044abe
2 changed files with 56 additions and 3 deletions

View File

@ -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);
}

View File

@ -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
}