On Mon, Aug 10, 2015 at 10:33 AM, Chih-Hung Hsieh via cfe-commits < cfe-commits@lists.llvm.org> wrote:
> Author: chh > Date: Mon Aug 10 12:33:31 2015 > New Revision: 244468 > > URL: http://llvm.org/viewvc/llvm-project?rev=244468&view=rev > Log: > Correct x86_64 fp128 calling convention > > These changes are for Android x86_64 targets to be compatible > with current Android g++ and conform to AMD64 ABI. > > https://llvm.org/bugs/show_bug.cgi?id=23897 > * Return type of long double (fp128) should be fp128, not x86_fp80. > * Vararg of long double (fp128) could be in register and overflowed to > memory. > > https://llvm.org/bugs/show_bug.cgi?id=24111 > * Return value of long double (fp128) _Complex should be in memory like > a structure of {fp128,fp128}. > > Differential Revision: http://reviews.llvm.org/D11437 > > > Added: > cfe/trunk/test/CodeGen/x86_64-fp128.c > Modified: > cfe/trunk/lib/CodeGen/TargetInfo.cpp > > Modified: cfe/trunk/lib/CodeGen/TargetInfo.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.cpp?rev=244468&r1=244467&r2=244468&view=diff > > ============================================================================== > --- cfe/trunk/lib/CodeGen/TargetInfo.cpp (original) > +++ cfe/trunk/lib/CodeGen/TargetInfo.cpp Mon Aug 10 12:33:31 2015 > @@ -1862,13 +1862,20 @@ void X86_64ABIInfo::classify(QualType Ty > Hi = Integer; > } else if (k >= BuiltinType::Bool && k <= BuiltinType::LongLong) { > Current = Integer; > - } else if ((k == BuiltinType::Float || k == BuiltinType::Double) || > - (k == BuiltinType::LongDouble && > - getTarget().getTriple().isOSNaCl())) { > + } else if (k == BuiltinType::Float || k == BuiltinType::Double) { > Current = SSE; > } else if (k == BuiltinType::LongDouble) { > - Lo = X87; > - Hi = X87Up; > + const llvm::fltSemantics *LDF = &getTarget().getLongDoubleFormat(); > + if (LDF == &llvm::APFloat::IEEEquad) { > + Lo = SSE; > + Hi = SSEUp; > + } else if (LDF == &llvm::APFloat::x87DoubleExtended) { > + Lo = X87; > + Hi = X87Up; > + } else if (LDF == &llvm::APFloat::IEEEdouble) { > + Current = SSE; > + } else > + llvm_unreachable("unexpected long double representation!"); > } > // FIXME: _Decimal32 and _Decimal64 are SSE. > // FIXME: _float128 and _Decimal128 are (SSE, SSEUp). > @@ -1973,14 +1980,21 @@ void X86_64ABIInfo::classify(QualType Ty > Current = Integer; > else if (Size <= 128) > Lo = Hi = Integer; > - } else if (ET == getContext().FloatTy) > + } else if (ET == getContext().FloatTy) { > Current = SSE; > - else if (ET == getContext().DoubleTy || > - (ET == getContext().LongDoubleTy && > - getTarget().getTriple().isOSNaCl())) > + } else if (ET == getContext().DoubleTy) { > Lo = Hi = SSE; > - else if (ET == getContext().LongDoubleTy) > - Current = ComplexX87; > + } else if (ET == getContext().LongDoubleTy) { > + const llvm::fltSemantics *LDF = &getTarget().getLongDoubleFormat(); > + if (LDF == &llvm::APFloat::IEEEquad) > + Current = Memory; > + else if (LDF == &llvm::APFloat::x87DoubleExtended) > + Current = ComplexX87; > + else if (LDF == &llvm::APFloat::IEEEdouble) > + Lo = Hi = SSE; > + else > + llvm_unreachable("unexpected long double representation!"); > + } > > // If this complex type crosses an eightbyte boundary then it > // should be split. > @@ -2249,7 +2263,8 @@ llvm::Type *X86_64ABIInfo::GetByteVector > Ty = QualType(InnerTy, 0); > > llvm::Type *IRType = CGT.ConvertType(Ty); > - if(isa<llvm::VectorType>(IRType)) > + if (isa<llvm::VectorType>(IRType) || > + IRType->getTypeID() == llvm::Type::FP128TyID) > return IRType; > > // We couldn't find the preferred IR vector type for 'Ty'. > > Added: cfe/trunk/test/CodeGen/x86_64-fp128.c > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/x86_64-fp128.c?rev=244468&view=auto > > ============================================================================== > --- cfe/trunk/test/CodeGen/x86_64-fp128.c (added) > +++ cfe/trunk/test/CodeGen/x86_64-fp128.c Mon Aug 10 12:33:31 2015 > @@ -0,0 +1,116 @@ > +// RUN: %clang_cc1 -triple x86_64-linux-android -emit-llvm -O -o - %s \ > +// RUN: | FileCheck %s --check-prefix=ANDROID --check-prefix=CHECK > +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -O -o - %s \ > +// RUN: | FileCheck %s --check-prefix=GNU --check-prefix=CHECK > +// RUN: %clang_cc1 -triple x86_64 -emit-llvm -O -o - %s \ > +// RUN: | FileCheck %s --check-prefix=GNU --check-prefix=CHECK > + > +// Android uses fp128 for long double but other x86_64 targets use > x86_fp80. > + > +long double dataLD = 1.0L; > +// ANDROID: @dataLD = global fp128 0xL00000000000000003FFF000000000000, > align 16 > +// GNU: @dataLD = global x86_fp80 0xK3FFF8000000000000000, align 16 > + > +long double _Complex dataLDC = {1.0L, 1.0L}; > +// ANDROID: @dataLDC = global { fp128, fp128 } { fp128 > 0xL00000000000000003FFF000000000000, fp128 > 0xL00000000000000003FFF000000000000 }, align 16 > +// GNU: @dataLDC = global { x86_fp80, x86_fp80 } { x86_fp80 > 0xK3FFF8000000000000000, x86_fp80 0xK3FFF8000000000000000 }, align 16 > + > +long double TestLD(long double x) { > + return x * x; > +// ANDROID: define fp128 @TestLD(fp128 %x) > +// GNU: define x86_fp80 @TestLD(x86_fp80 %x) > +} > + > +long double _Complex TestLDC(long double _Complex x) { > + return x * x; > +// ANDROID: define void @TestLDC({ fp128, fp128 }* {{.*}}, { fp128, fp128 > }* {{.*}} %x) > +// GNU: define { x86_fp80, x86_fp80 } @TestLDC({ x86_fp80, x86_fp80 }* > {{.*}} %x) > +} > + > +typedef __builtin_va_list va_list; > + > +int TestGetVarInt(va_list ap) { > + return __builtin_va_arg(ap, int); > +// Since int can be passed in memory or in register there is a branch and > a phi. > +// CHECK: define i32 @TestGetVarInt( > +// CHECK: br > +// CHECK: load {{.*}} %overflow_arg_area_p > Checks like this are not resilient to -Asserts builds. When Clang is built without assertions, it does not create names for IR values (so that %overflow_arg_area_p will be %47 instead). Please update the test to be usable on a -Asserts build. - David > +// CHECK: = phi > +// CHECK: ret i32 > +} > + > +double TestGetVarDouble(va_list ap) { > + return __builtin_va_arg(ap, double); > +// Since double can be passed in memory or in register there is a branch > and a phi. > +// CHECK: define double @TestGetVarDouble( > +// CHECK: br > +// CHECK: load {{.*}} %overflow_arg_area_p > +// CHECK: = phi > +// CHECK: ret double > +} > + > +long double TestGetVarLD(va_list ap) { > + return __builtin_va_arg(ap, long double); > +// fp128 can be passed in memory or in register, but x86_fp80 is in > memory. > +// ANDROID: define fp128 @TestGetVarLD( > +// GNU: define x86_fp80 @TestGetVarLD( > +// ANDROID: br > +// GNU-NOT: br > +// CHECK: load {{.*}} %overflow_arg_area_p > +// ANDROID: = phi > +// GNU-NOT: = phi > +// ANDROID: ret fp128 > +// GNU: ret x86_fp80 > +} > + > +long double _Complex TestGetVarLDC(va_list ap) { > + return __builtin_va_arg(ap, long double _Complex); > +// Pair of fp128 or x86_fp80 are passed as struct in memory. > +// ANDROID: define void @TestGetVarLDC({ fp128, fp128 }* {{.*}}, > %struct.__va_list_tag* > +// GNU: define { x86_fp80, x86_fp80 } @TestGetVarLDC( > +// CHECK-NOT: br > +// CHECK: load {{.*}} %overflow_arg_area_p > +// CHECK-NOT: phi > +// ANDROID: ret void > +// GNU: ret { x86_fp80, x86_fp80 } > +} > + > +void TestVarArg(const char *s, ...); > + > +void TestPassVarInt(int x) { > + TestVarArg("A", x); > +// CHECK: define void @TestPassVarInt(i32 %x) > +// CHECK: call {{.*}} @TestVarArg(i8* {{.*}}, i32 %x) > +} > + > +void TestPassVarFloat(float x) { > + TestVarArg("A", x); > +// CHECK: define void @TestPassVarFloat(float %x) > +// CHECK: call {{.*}} @TestVarArg(i8* {{.*}}, double % > +} > + > +void TestPassVarDouble(double x) { > + TestVarArg("A", x); > +// CHECK: define void @TestPassVarDouble(double %x) > +// CHECK: call {{.*}} @TestVarArg(i8* {{.*}}, double %x > +} > + > +void TestPassVarLD(long double x) { > + TestVarArg("A", x); > +// ANDROID: define void @TestPassVarLD(fp128 %x) > +// ANDROID: call {{.*}} @TestVarArg(i8* {{.*}}, fp128 %x > +// GNU: define void @TestPassVarLD(x86_fp80 %x) > +// GNU: call {{.*}} @TestVarArg(i8* {{.*}}, x86_fp80 %x > +} > + > +void TestPassVarLDC(long double _Complex x) { > + TestVarArg("A", x); > +// ANDROID: define void @TestPassVarLDC({ fp128, fp128 }* {{.*}} %x) > +// ANDROID: store fp128 %x.{{.*}}, fp128* % > +// ANDROID-NEXT: store fp128 %x.{{.*}}, fp128* % > +// ANDROID-NEXT: call {{.*}} @TestVarArg(i8* {{.*}}, { fp128, fp128 }* > {{.*}} % > +// GNU: define void @TestPassVarLDC({ x86_fp80, x86_fp80 }* > {{.*}} %x) > +// GNU: store x86_fp80 %x.{{.*}}, x86_fp80* % > +// GNU-NEXT: store x86_fp80 %x.{{.*}}, x86_fp80* % > +// GNGNU-NEXT: call {{.*}} @TestVarArg(i8* {{.*}}, { x86_fp80, x86_fp80 > }* {{.*}} % > +} > > > _______________________________________________ > cfe-commits mailing list > cfe-commits@lists.llvm.org > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits