Skip to content

Commit 6a1944e

Browse files
committed
[LLVMABI] Scaffolding the SysV ABI
1 parent a48eefc commit 6a1944e

File tree

3 files changed

+230
-0
lines changed

3 files changed

+230
-0
lines changed

llvm/include/llvm/ABI/ABIInfo.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,50 @@
1717
#include "llvm/ABI/ABIFunctionInfo.h"
1818
#include "llvm/ABI/Types.h"
1919
#include <cassert>
20+
#include <climits>
21+
#include <cstdint>
2022

2123
namespace llvm {
2224
namespace abi {
2325

26+
struct ABICompatInfo {
27+
unsigned Version = UINT_MAX;
28+
29+
struct ABIFlags {
30+
bool PassInt128VectorsInMem : 1;
31+
bool ReturnCXXRecordGreaterThan128InMem : 1;
32+
bool ClassifyIntegerMMXAsSSE : 1;
33+
bool HonorsRevision98 : 1;
34+
35+
ABIFlags()
36+
: PassInt128VectorsInMem(true),
37+
ReturnCXXRecordGreaterThan128InMem(true),
38+
ClassifyIntegerMMXAsSSE(true), HonorsRevision98(true) {}
39+
40+
} Flags;
41+
42+
ABICompatInfo() : Version(UINT_MAX) {}
43+
ABICompatInfo(unsigned Ver) : Version(Ver) {}
44+
};
45+
2446
/// Abstract base class for target-specific ABI information.
2547
class ABIInfo {
48+
private:
49+
ABICompatInfo CompatInfo;
50+
2651
public:
52+
ABIInfo() : CompatInfo() {}
53+
explicit ABIInfo(const ABICompatInfo &Info) : CompatInfo(Info) {}
54+
2755
virtual ~ABIInfo() = default;
2856

2957
virtual ABIArgInfo classifyReturnType(const Type *RetTy) const = 0;
3058
virtual ABIArgInfo classifyArgumentType(const Type *ArgTy) const = 0;
3159
virtual void computeInfo(ABIFunctionInfo &FI) const = 0;
3260
virtual bool isPassByRef(const Type *Ty) const { return false; }
61+
const ABICompatInfo &getABICompatInfo() const { return CompatInfo; }
62+
63+
void setABICompatInfo(const struct ABICompatInfo &Info) { CompatInfo = Info; }
3364
};
3465

3566
} // namespace abi

llvm/lib/ABI/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ add_llvm_component_library(LLVMABI
33
ABITypeMapper.cpp
44
TargetCodeGenInfo.cpp
55
Targets/BPF.cpp
6+
Targets/X86.cpp
67

78
ADDITIONAL_HEADER_DIRS
89
${LLVM_MAIN_INCLUDE_DIR}/llvm/ABI

llvm/lib/ABI/Targets/X86.cpp

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
//===- X86.cpp ------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "llvm/ABI/ABIFunctionInfo.h"
10+
#include "llvm/ABI/ABIInfo.h"
11+
#include "llvm/ABI/TargetCodegenInfo.h"
12+
#include "llvm/ABI/Types.h"
13+
#include "llvm/IR/DerivedTypes.h"
14+
#include "llvm/IR/Type.h"
15+
#include "llvm/Support/Casting.h"
16+
#include "llvm/TargetParser/Triple.h"
17+
18+
namespace llvm {
19+
namespace abi {
20+
21+
enum class AVXABILevel { None, AVX, AVX512 };
22+
23+
class X86_64ABIInfo : public ABIInfo {
24+
public:
25+
enum Class {
26+
Integer = 0,
27+
SSE,
28+
SSEUp,
29+
X87,
30+
X87UP,
31+
Complex_X87,
32+
NoClass,
33+
Memory
34+
};
35+
36+
private:
37+
AVXABILevel AVXLevel;
38+
bool Has64BitPointers;
39+
const llvm::Triple &TargetTriple;
40+
41+
static Class merge(Class Accum, Class Field);
42+
43+
void postMerge(unsigned AggregateSize, Class &Lo, Class &Hi) const;
44+
45+
void classify(Type T, uint64_t OffsetBase, Class &Lo, Class &Hi,
46+
bool IsNamedArg, bool IsRegCall = false) const;
47+
48+
llvm::Type *getByteVectorType(const Type *Ty) const;
49+
llvm::Type *getSseTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
50+
const Type *SourceTy,
51+
unsigned SourceOffset) const;
52+
53+
llvm::Type *getIntegerTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
54+
const Type *SourceTy,
55+
unsigned SourceOffset) const;
56+
57+
ABIArgInfo getIndirectReturnResult(const Type *Ty) const;
58+
59+
ABIArgInfo getIndirectResult(const Type *Ty, unsigned FreeIntRegs) const;
60+
61+
ABIArgInfo classifyReturnType(const Type *RetTy) const override;
62+
63+
ABIArgInfo classifyArgumentType(const Type *Ty, unsigned FreeIntRegs,
64+
unsigned &NeededInt, unsigned &NeededSse,
65+
bool IsNamedArg,
66+
bool IsRegCall = false) const;
67+
68+
ABIArgInfo classifyRegCallStructType(const Type *Ty, unsigned &NeededInt,
69+
unsigned &NeededSSE,
70+
unsigned &MaxVectorWidth) const;
71+
72+
ABIArgInfo classifyRegCallStructTypeImpl(const Type *Ty, unsigned &NeededInt,
73+
unsigned &NeededSSE,
74+
unsigned &MaxVectorWidth) const;
75+
76+
bool isIllegalVectorType(const Type *Ty) const;
77+
78+
// The Functionality of these methods will be moved to
79+
// llvm::abi::ABICompatInfo
80+
81+
bool honorsRevision98() const { return !TargetTriple.isOSDarwin(); }
82+
83+
bool classifyIntegerMMXAsSSE() const {
84+
if (TargetTriple.isOSDarwin() || TargetTriple.isPS() ||
85+
TargetTriple.isOSFreeBSD())
86+
return false;
87+
return true;
88+
}
89+
90+
bool passInt128VectorsInMem() const {
91+
// TODO: accept ABICompat info from the frontends
92+
return TargetTriple.isOSLinux() || TargetTriple.isOSNetBSD();
93+
}
94+
95+
bool returnCXXRecordGreaterThan128InMem() const {
96+
// TODO: accept ABICompat info from the frontends
97+
return true;
98+
}
99+
100+
public:
101+
X86_64ABIInfo(const Triple &Triple, AVXABILevel AVXABILevel,
102+
bool Has64BitPtrs, const ABICompatInfo &Compat)
103+
: ABIInfo(Compat), AVXLevel(AVXABILevel), Has64BitPointers(Has64BitPtrs),
104+
TargetTriple(Triple) {}
105+
106+
bool isPassedUsingAVXType(const Type *Type) const {
107+
unsigned NeededInt, NeededSse;
108+
ABIArgInfo Info = classifyArgumentType(Type, 0, NeededInt, NeededSse, true);
109+
110+
if (Info.isDirect()) {
111+
auto *Ty = Info.getCoerceToType();
112+
if (auto *VectorTy = dyn_cast_or_null<VectorType>(Ty))
113+
return VectorTy->getSizeInBits().getFixedValue();
114+
}
115+
return false;
116+
}
117+
118+
void computeInfo(ABIFunctionInfo &FI) const override;
119+
120+
bool has64BitPointers() const { return Has64BitPointers; }
121+
};
122+
123+
void X86_64ABIInfo::postMerge(unsigned AggregateSize, Class &Lo,
124+
Class &Hi) const {
125+
// AMD64-ABI 3.2.3p2: Rule 5. Then a post merger cleanup is done:
126+
//
127+
// (a) If one of the classes is Memory, the whole argument is passed in
128+
// memory.
129+
//
130+
// (b) If X87UP is not preceded by X87, the whole argument is passed in
131+
// memory.
132+
//
133+
// (c) If the size of the aggregate exceeds two eightbytes and the first
134+
// eightbyte isn't SSE or any other eightbyte isn't SSEUP, the whole
135+
// argument is passed in memory. NOTE: This is necessary to keep the
136+
// ABI working for processors that don't support the __m256 type.
137+
//
138+
// (d) If SSEUP is not preceded by SSE or SSEUP, it is converted to SSE.
139+
//
140+
// Some of these are enforced by the merging logic. Others can arise
141+
// only with unions; for example:
142+
// union { _Complex double; unsigned; }
143+
//
144+
// Note that clauses (b) and (c) were added in 0.98.
145+
146+
if (Hi == Memory)
147+
Lo = Memory;
148+
if (Hi == X87UP && Lo != X87 && getABICompatInfo().Flags.HonorsRevision98)
149+
Lo = Memory;
150+
if (AggregateSize > 128 && (Lo != SSE && Hi != SSEUp))
151+
Lo = Memory;
152+
if (Hi == SSEUp && Lo != SSE)
153+
Hi = SSE;
154+
}
155+
X86_64ABIInfo::Class X86_64ABIInfo::merge(Class Accum, Class Field) {
156+
// AMD64-ABI 3.2.3p2: Rule 4. Each field of an object is
157+
// classified recursively so that always two fields are
158+
// considered. The resulting class is calculated according to
159+
// the classes of the fields in the eightbyte:
160+
//
161+
// (a) If both classes are equal, this is the resulting class.
162+
//
163+
// (b) If one of the classes is NO_CLASS, the resulting class is
164+
// the other class.
165+
//
166+
// (c) If one of the classes is MEMORY, the result is the MEMORY
167+
// class.
168+
//
169+
// (d) If one of the classes is INTEGER, the result is the
170+
// INTEGER.
171+
//
172+
// (e) If one of the classes is X87, X87UP, COMPLEX_X87 class,
173+
// MEMORY is used as class.
174+
//
175+
// (f) Otherwise class SSE is used.
176+
177+
// Accum should never be memory (we should have returned) or
178+
// ComplexX87 (because this cannot be passed in a structure).
179+
assert((Accum != Memory && Accum != Complex_X87) &&
180+
"Invalid accumulated classification during merge.");
181+
182+
if (Accum == Field || Field == NoClass)
183+
return Accum;
184+
if (Accum == NoClass)
185+
return Field;
186+
if (Field == Memory)
187+
return Memory;
188+
if (Accum == Integer || Field == Integer)
189+
return Integer;
190+
if (Field == X87 || Field == X87UP || Field == Complex_X87 || Accum == X87 ||
191+
Accum == X87UP)
192+
return Memory;
193+
194+
return SSE;
195+
}
196+
197+
} // namespace abi
198+
} // namespace llvm

0 commit comments

Comments
 (0)