From 4f94c02616025ace168899b6fbdc8c3ba240062b Mon Sep 17 00:00:00 2001 From: Qiu Chaofan Date: Fri, 3 Dec 2021 17:40:52 +0800 Subject: [PATCH] [Clang] Mutate bulitin names under IEEE128 on PPC64 Glibc 2.32 and newer uses these symbol names to support IEEE-754 128-bit float. GCC transforms name of these builtins to align with Glibc header behavior. Since Clang doesn't have all GCC-compatible builtins implemented, this patch only mutates the implemented part. Note nexttoward is a special case (no nexttowardf128) so it's also handled here. Reviewed By: jsji Differential Revision: https://reviews.llvm.org/D112401 --- clang/lib/CodeGen/CGBuiltin.cpp | 24 +++++++++++- clang/test/CodeGen/math-builtins-long.c | 2 +- clang/test/CodeGen/ppc64-f128-builtins.c | 63 ++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 clang/test/CodeGen/ppc64-f128-builtins.c diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 5d6df59..0a98b5b 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -96,13 +96,33 @@ llvm::Constant *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD, StringRef Name; GlobalDecl D(FD); + // TODO: This list should be expanded or refactored after all GCC-compatible + // std libcall builtins are implemented. + static SmallDenseMap F128Builtins{ + {Builtin::BI__builtin_printf, "__printfieee128"}, + {Builtin::BI__builtin_vsnprintf, "__vsnprintfieee128"}, + {Builtin::BI__builtin_vsprintf, "__vsprintfieee128"}, + {Builtin::BI__builtin_sprintf, "__sprintfieee128"}, + {Builtin::BI__builtin_snprintf, "__snprintfieee128"}, + {Builtin::BI__builtin_fprintf, "__fprintfieee128"}, + {Builtin::BI__builtin_nexttowardf128, "__nexttowardieee128"}, + }; + // If the builtin has been declared explicitly with an assembler label, // use the mangled name. This differs from the plain label on platforms // that prefix labels. if (FD->hasAttr()) Name = getMangledName(D); - else - Name = Context.BuiltinInfo.getName(BuiltinID) + 10; + else { + // TODO: This mutation should also be applied to other targets other than + // PPC, after backend supports IEEE 128-bit style libcalls. + if (getTriple().isPPC64() && + &getTarget().getLongDoubleFormat() == &llvm::APFloat::IEEEquad() && + F128Builtins.find(BuiltinID) != F128Builtins.end()) + Name = F128Builtins[BuiltinID]; + else + Name = Context.BuiltinInfo.getName(BuiltinID) + 10; + } llvm::FunctionType *Ty = cast(getTypes().ConvertType(FD->getType())); diff --git a/clang/test/CodeGen/math-builtins-long.c b/clang/test/CodeGen/math-builtins-long.c index f5cee75..dfca1ed 100644 --- a/clang/test/CodeGen/math-builtins-long.c +++ b/clang/test/CodeGen/math-builtins-long.c @@ -307,7 +307,7 @@ void foo(long double f, long double *l, int *i, const char *c) { // F80: call x86_fp80 @nexttowardl(x86_fp80 %{{.+}}, x86_fp80 %{{.+}}) // PPC: call ppc_fp128 @nexttowardl(ppc_fp128 %{{.+}}, ppc_fp128 %{{.+}}) // X86F128: call fp128 @nexttowardl(fp128 %{{.+}}, fp128 %{{.+}}) - // PPCF128: call fp128 @nexttowardf128(fp128 %{{.+}}, fp128 %{{.+}}) + // PPCF128: call fp128 @__nexttowardieee128(fp128 %{{.+}}, fp128 %{{.+}}) __builtin_nexttowardl(f,f); // F80: call x86_fp80 @remainderl(x86_fp80 %{{.+}}, x86_fp80 %{{.+}}) diff --git a/clang/test/CodeGen/ppc64-f128-builtins.c b/clang/test/CodeGen/ppc64-f128-builtins.c new file mode 100644 index 0000000..07d1564 --- /dev/null +++ b/clang/test/CodeGen/ppc64-f128-builtins.c @@ -0,0 +1,63 @@ +// RUN: %clang_cc1 -triple powerpc64le-linux-gnu -emit-llvm -o - %s \ +// RUN: -mabi=ieeelongdouble | FileCheck --check-prefix=IEEE128 %s +// RUN: %clang_cc1 -triple powerpc64le-linux-gnu -emit-llvm -o - %s \ +// RUN: | FileCheck --check-prefix=PPC128 %s + +long double x; +char buf[20]; + +// IEEE128-LABEL: define dso_local void @test_printf +// IEEE128: call signext i32 (i8*, ...) @__printfieee128 +// PPC128-LABEL: define dso_local void @test_printf +// PPC128: call signext i32 (i8*, ...) @printf +void test_printf() { + __builtin_printf("%.Lf", x); +} + +// IEEE128-LABEL: define dso_local void @test_vsnprintf +// IEEE128: call signext i32 @__vsnprintfieee128 +// PPC128-LABEL: define dso_local void @test_vsnprintf +// PPC128: call signext i32 @vsnprintf +void test_vsnprintf(int n, ...) { + __builtin_va_list va; + __builtin_va_start(va, n); + __builtin_vsnprintf(buf, 20, "%.Lf", va); + __builtin_va_end(va); +} + +// IEEE128-LABEL: define dso_local void @test_vsprintf +// IEEE128: call signext i32 @__vsprintfieee128 +// PPC128-LABEL: define dso_local void @test_vsprintf +// PPC128: call signext i32 @vsprintf +void test_vsprintf(int n, ...) { + __builtin_va_list va; + __builtin_va_start(va, n); + __builtin_vsprintf(buf, "%.Lf", va); + __builtin_va_end(va); +} + +// IEEE128-LABEL: define dso_local void @test_sprintf +// IEEE128: call signext i32 (i8*, i8*, ...) @__sprintfieee128 +// PPC128-LABEL: define dso_local void @test_sprintf +// PPC128: call signext i32 (i8*, i8*, ...) @sprintf +void test_sprintf() { + __builtin_sprintf(buf, "%.Lf", x); +} + +// IEEE128-LABEL: define dso_local void @test_snprintf +// IEEE128: call signext i32 (i8*, i64, i8*, ...) @__snprintfieee128 +// PPC128-LABEL: define dso_local void @test_snprintf +// PPC128: call signext i32 (i8*, i64, i8*, ...) @snprintf +void test_snprintf() { + __builtin_snprintf(buf, 20, "%.Lf", x); +} + +// GLIBC has special handling of 'nexttoward' + +// IEEE128-LABEL: define dso_local fp128 @test_nexttoward +// IEEE128: call fp128 @__nexttowardieee128 +// PPC128-LABEL: define dso_local ppc_fp128 @test_nexttoward +// PPC128: call ppc_fp128 @nexttowardl +long double test_nexttoward(long double a, long double b) { + return __builtin_nexttowardl(a, b); +} -- 2.7.4