Skip to content

Commit d2444fd

Browse files
committed
[llvm][clang] duplicate long double layout logic from clang to LLVM
Information about the size and alignment of `long double` is currently part of clang. Copy this logic to LLVM so it can be used to control lowering of intrinsics. Additionally, add an assertion to make sure Clang and LLVM agree.
1 parent 90a465d commit d2444fd

File tree

5 files changed

+188
-2
lines changed

5 files changed

+188
-2
lines changed

clang/include/clang/Basic/TargetInfo.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,6 +1218,10 @@ class TargetInfo : public TransferrableTargetInfo,
12181218
return Triple;
12191219
}
12201220

1221+
/// Assert that layouts for C types computed by Clang are the same as layouts
1222+
/// stored in the LLVM target.
1223+
void validateCLayouts() const;
1224+
12211225
/// Returns the target ID if supported.
12221226
virtual std::optional<std::string> getTargetID() const {
12231227
return std::nullopt;

clang/lib/Basic/TargetInfo.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -925,6 +925,19 @@ bool TargetInfo::validateInputConstraint(
925925
return true;
926926
}
927927

928+
void TargetInfo::validateCLayouts() const {
929+
llvm::Triple::CLayouts TripleLayouts = Triple.getCLayouts();
930+
if (__builtin_expect(LongDoubleWidth != TripleLayouts.LongDoubleWidth ||
931+
LongDoubleAlign != TripleLayouts.LongDoubleAlign,
932+
0)) {
933+
fprintf(stderr, "'long double' width got %d but expected %d\n",
934+
LongDoubleWidth, TripleLayouts.LongDoubleWidth);
935+
fprintf(stderr, "'long double' align got %d but expected %d\n",
936+
LongDoubleAlign, TripleLayouts.LongDoubleAlign);
937+
llvm_unreachable("Clang & LLVM layout mismatch");
938+
}
939+
}
940+
928941
void TargetInfo::CheckFixedPointBits() const {
929942
// Check that the number of fractional and integral bits (and maybe sign) can
930943
// fit into the bits given for a fixed point type.

clang/lib/Basic/Targets.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,8 @@ void addCygMingDefines(const LangOptions &Opts, MacroBuilder &Builder) {
109109
// Driver code
110110
//===----------------------------------------------------------------------===//
111111

112-
std::unique_ptr<TargetInfo> AllocateTarget(const llvm::Triple &Triple,
113-
const TargetOptions &Opts) {
112+
std::unique_ptr<TargetInfo> AllocateTargetImpl(const llvm::Triple &Triple,
113+
const TargetOptions &Opts) {
114114
llvm::Triple::OSType os = Triple.getOS();
115115

116116
switch (Triple.getArch()) {
@@ -749,6 +749,15 @@ std::unique_ptr<TargetInfo> AllocateTarget(const llvm::Triple &Triple,
749749
}
750750
}
751751
}
752+
std::unique_ptr<TargetInfo> AllocateTarget(const llvm::Triple &Triple,
753+
const TargetOptions &Opts) {
754+
755+
std::unique_ptr<TargetInfo> target = AllocateTargetImpl(Triple, Opts);
756+
if (target != nullptr) {
757+
target->validateCLayouts();
758+
}
759+
return target;
760+
}
752761
} // namespace targets
753762
} // namespace clang
754763

llvm/include/llvm/TargetParser/Triple.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#ifndef LLVM_TARGETPARSER_TRIPLE_H
1010
#define LLVM_TARGETPARSER_TRIPLE_H
1111

12+
#include "llvm/ADT/APFloat.h"
1213
#include "llvm/ADT/Twine.h"
1314
#include "llvm/Support/VersionTuple.h"
1415

@@ -1161,6 +1162,23 @@ class Triple {
11611162
/// Returns a canonicalized OS version number for the specified OS.
11621163
static VersionTuple getCanonicalVersionForOS(OSType OSKind,
11631164
const VersionTuple &Version);
1165+
1166+
/// Layouts for C types that are relevant to libc calls generated by LLVM
1167+
struct CLayouts {
1168+
unsigned char LongDoubleWidth;
1169+
unsigned char LongDoubleAlign;
1170+
const fltSemantics *LongDoubleFormat;
1171+
};
1172+
1173+
/// Provide default layouts relevant to C. Frontends may override these
1174+
/// values.
1175+
CLayouts getCLayouts() const;
1176+
1177+
/// Return true if `long double` and `__float128` have the same layout.
1178+
bool isLongDoubleF128() const {
1179+
// TODO: do we also need to check alignment?
1180+
return getCLayouts().LongDoubleWidth == 128;
1181+
}
11641182
};
11651183

11661184
} // End llvm namespace

llvm/lib/TargetParser/Triple.cpp

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1900,6 +1900,148 @@ VersionTuple Triple::getCanonicalVersionForOS(OSType OSKind,
19001900
}
19011901
}
19021902

1903+
Triple::CLayouts Triple::getCLayouts() const {
1904+
Triple::CLayouts Layouts;
1905+
1906+
// Default to a 32-bit RISC platform
1907+
Layouts.LongDoubleWidth = 64;
1908+
Layouts.LongDoubleAlign = 64;
1909+
Layouts.LongDoubleFormat = &llvm::APFloat::IEEEdouble();
1910+
1911+
enum ArchType arch = getArch();
1912+
1913+
if (arch == aarch64 || arch == aarch64_be || arch == aarch64_32) {
1914+
Layouts.LongDoubleWidth = 128;
1915+
Layouts.LongDoubleAlign = 128;
1916+
Layouts.LongDoubleFormat = &llvm::APFloat::IEEEquad();
1917+
1918+
// TODO: verify this logic matches when WindowsARM64TargetInfo /
1919+
// DarwinAArch64TargetInfo is called
1920+
if (isOSWindows()) {
1921+
Layouts.LongDoubleWidth = Layouts.LongDoubleAlign = 64;
1922+
Layouts.LongDoubleFormat = &llvm::APFloat::IEEEdouble();
1923+
} else if (isMacOSX()) {
1924+
// TODO: should this just be isMacOSX or check specifically for darwin?
1925+
Layouts.LongDoubleWidth = Layouts.LongDoubleAlign = 64;
1926+
Layouts.LongDoubleFormat = &llvm::APFloat::IEEEdouble();
1927+
}
1928+
} else if (arch == avr) {
1929+
Layouts.LongDoubleWidth = 32;
1930+
Layouts.LongDoubleAlign = 8;
1931+
Layouts.LongDoubleFormat = &llvm::APFloat::IEEEsingle();
1932+
} else if (arch == arc) {
1933+
Layouts.LongDoubleAlign = 32;
1934+
} else if (arch == arm) {
1935+
// TODO: port the logic
1936+
} else if (arch == csky) {
1937+
Layouts.LongDoubleAlign = 32;
1938+
} else if (arch == loongarch32 || arch == loongarch64) {
1939+
Layouts.LongDoubleWidth = Layouts.LongDoubleAlign = 128;
1940+
Layouts.LongDoubleFormat = &llvm::APFloat::IEEEquad();
1941+
} else if (arch == mips || arch == mipsel || arch == mips64 ||
1942+
arch == mips64el) {
1943+
if (isMIPS32()) {
1944+
// o32
1945+
Layouts.LongDoubleWidth = Layouts.LongDoubleAlign = 64;
1946+
Layouts.LongDoubleFormat = &llvm::APFloat::IEEEdouble();
1947+
} else {
1948+
// n32 & n64
1949+
Layouts.LongDoubleWidth = Layouts.LongDoubleAlign = 128;
1950+
Layouts.LongDoubleFormat = &llvm::APFloat::IEEEquad();
1951+
if (isOSFreeBSD()) {
1952+
Layouts.LongDoubleWidth = Layouts.LongDoubleAlign = 64;
1953+
Layouts.LongDoubleFormat = &llvm::APFloat::IEEEdouble();
1954+
}
1955+
}
1956+
} else if (arch == msp430) {
1957+
Layouts.LongDoubleWidth = 64;
1958+
Layouts.LongDoubleAlign = 16;
1959+
} else if (arch == ppc || arch == ppcle || arch == ppc64 || arch == ppc64le) {
1960+
// TODO: figure out how to get features
1961+
1962+
if (getOS() == AIX) {
1963+
Layouts.LongDoubleWidth = 64;
1964+
Layouts.LongDoubleAlign = 32;
1965+
Layouts.LongDoubleFormat = &llvm::APFloat::IEEEdouble();
1966+
} else if (isOSFreeBSD() || isOSNetBSD() || isOSOpenBSD() || isMusl()) {
1967+
Layouts.LongDoubleWidth = 64;
1968+
Layouts.LongDoubleAlign = 64;
1969+
Layouts.LongDoubleFormat = &llvm::APFloat::IEEEdouble();
1970+
} else {
1971+
Layouts.LongDoubleWidth = 128;
1972+
Layouts.LongDoubleAlign = 128;
1973+
Layouts.LongDoubleFormat = &llvm::APFloat::PPCDoubleDouble();
1974+
}
1975+
} else if (arch == riscv32 || arch == riscv64) {
1976+
Layouts.LongDoubleWidth = 128;
1977+
Layouts.LongDoubleAlign = 128;
1978+
Layouts.LongDoubleFormat = &llvm::APFloat::IEEEquad();
1979+
} else if (arch == sparcv9) {
1980+
// The SPARCv8 System V ABI has long double 128-bits in size, but 64-bit
1981+
// aligned. The SPARCv9 SCD 2.4.1 says 16-byte aligned.
1982+
Layouts.LongDoubleWidth = 128;
1983+
Layouts.LongDoubleAlign = 128;
1984+
Layouts.LongDoubleFormat = &llvm::APFloat::IEEEquad();
1985+
} else if (arch == systemz) {
1986+
Layouts.LongDoubleWidth = 128;
1987+
Layouts.LongDoubleAlign = 64;
1988+
Layouts.LongDoubleFormat = &llvm::APFloat::IEEEquad();
1989+
} else if (arch == tce || arch == tcele) {
1990+
Layouts.LongDoubleWidth = 32;
1991+
Layouts.LongDoubleAlign = 32;
1992+
Layouts.LongDoubleFormat = &llvm::APFloat::IEEEsingle();
1993+
} else if (arch == ve) {
1994+
Layouts.LongDoubleWidth = 128;
1995+
Layouts.LongDoubleAlign = 128;
1996+
Layouts.LongDoubleFormat = &llvm::APFloat::IEEEquad();
1997+
} else if (arch == wasm32 || arch == wasm64) {
1998+
Layouts.LongDoubleWidth = Layouts.LongDoubleAlign = 128;
1999+
Layouts.LongDoubleFormat = &llvm::APFloat::IEEEquad();
2000+
} else if (arch == x86 || arch == x86_64) {
2001+
if (arch == x86_64) {
2002+
Layouts.LongDoubleWidth = 128;
2003+
Layouts.LongDoubleAlign = 128;
2004+
}
2005+
if (isOSDarwin()) {
2006+
Layouts.LongDoubleWidth = 128;
2007+
Layouts.LongDoubleAlign = 128;
2008+
Layouts.LongDoubleFormat = &llvm::APFloat::IEEEdouble();
2009+
} else if (isAndroid()) {
2010+
Layouts.LongDoubleWidth = 64;
2011+
Layouts.LongDoubleFormat = &llvm::APFloat::IEEEdouble();
2012+
} else if (isOSLinux()) {
2013+
Layouts.LongDoubleWidth = 96;
2014+
Layouts.LongDoubleAlign = 32;
2015+
Layouts.LongDoubleFormat = &llvm::APFloat::x87DoubleExtended();
2016+
} else if (isOSWindows()) {
2017+
if (isWindowsCygwinEnvironment()) {
2018+
Layouts.LongDoubleWidth = 64;
2019+
Layouts.LongDoubleAlign = 64;
2020+
} else if (isWindowsGNUEnvironment()) {
2021+
// Mingw64 rounds long double size and alignment up to 16 bytes, but
2022+
// sticks with x86 FP ops. Weird.
2023+
Layouts.LongDoubleWidth = 128;
2024+
Layouts.LongDoubleAlign = 128;
2025+
Layouts.LongDoubleFormat = &llvm::APFloat::x87DoubleExtended();
2026+
} else {
2027+
Layouts.LongDoubleWidth = 64;
2028+
Layouts.LongDoubleAlign = 64;
2029+
Layouts.LongDoubleFormat = &llvm::APFloat::IEEEdouble();
2030+
}
2031+
} else if (isOSIAMCU()) {
2032+
Layouts.LongDoubleWidth = 64;
2033+
Layouts.LongDoubleFormat = &llvm::APFloat::IEEEdouble();
2034+
} else if (isOHOSFamily()) {
2035+
Layouts.LongDoubleWidth = 64;
2036+
Layouts.LongDoubleFormat = &llvm::APFloat::IEEEdouble();
2037+
}
2038+
} else if (arch == xcore) {
2039+
Layouts.LongDoubleAlign = 32;
2040+
}
2041+
2042+
return Layouts;
2043+
}
2044+
19032045
// HLSL triple environment orders are relied on in the front end
19042046
static_assert(Triple::Vertex - Triple::Pixel == 1,
19052047
"incorrect HLSL stage order");

0 commit comments

Comments
 (0)