Skip to content

Commit e1af0d4

Browse files
committed
[LLVMABI] Added Support for the BPF ABI
1 parent c180e24 commit e1af0d4

File tree

7 files changed

+564
-0
lines changed

7 files changed

+564
-0
lines changed

llvm/examples/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
add_subdirectory(ABI)
12
add_subdirectory(BrainF)
23
add_subdirectory(Fibonacci)
34
add_subdirectory(HowToUseJIT)

llvm/include/llvm/ABI/ABIInfo.h

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
//===- ABIInfo.h - ABI Information -----------------------------*- C++ -*-===//
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+
/// \file
10+
/// This file defines the interfaces used by frontends to get ABI information.
11+
///
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef LLVM_ABI_ABIINFO_H
15+
#define LLVM_ABI_ABIINFO_H
16+
17+
#include "llvm/ABI/ABIType.h"
18+
#include "llvm/ADT/ArrayRef.h"
19+
#include "llvm/IR/Type.h"
20+
#include "llvm/Support/ErrorHandling.h"
21+
#include <memory>
22+
#include <vector>
23+
24+
namespace llvm {
25+
class LLVMContext;
26+
27+
namespace abi {
28+
29+
/// Argument or return value ABI classification
30+
enum class ABIArgKind {
31+
Direct, // Just yeets the value straight into registers
32+
Indirect, // Passed indirectly via a hidden pointer
33+
Ignore, // exists in the source but ghosted at compile time
34+
Expand, // Expand into multiple arguments
35+
Coerce // Coerce to different type
36+
};
37+
38+
/// Information about how to handle an argument or return value
39+
class ABIArgInfo {
40+
ABIArgKind Kind;
41+
const ABIType *CoerceToABIType; // Target ABI type for coercion
42+
Type *CoerceToLLVMType; // Corresponding LLVM type
43+
unsigned DirectOffset; // Offset for direct passing
44+
bool CanBeFlattened; // Whether the type can be flattened
45+
bool InReg; // Whether to pass in registers
46+
47+
/// For Expand kind - holds component types
48+
std::vector<ABIArgInfo> ExpandedArgs;
49+
50+
public:
51+
ABIArgInfo(ABIArgKind Kind, const ABIType *CoerceToABIType = nullptr,
52+
Type *CoerceToLLVMType = nullptr, unsigned DirectOffset = 0,
53+
bool CanBeFlattened = false, bool InReg = false)
54+
: Kind(Kind), CoerceToABIType(CoerceToABIType),
55+
CoerceToLLVMType(CoerceToLLVMType), DirectOffset(DirectOffset),
56+
CanBeFlattened(CanBeFlattened), InReg(InReg) {}
57+
58+
// Factory methods
59+
static ABIArgInfo getDirect(const ABIType *ABITy = nullptr,
60+
Type *LLVMTy = nullptr, unsigned Offset = 0,
61+
bool CanBeFlattened = false, bool InReg = false) {
62+
return ABIArgInfo(ABIArgKind::Direct, ABITy, LLVMTy, Offset, CanBeFlattened,
63+
InReg);
64+
}
65+
66+
static ABIArgInfo getIndirect(const ABIType *ABITy = nullptr,
67+
bool InReg = false) {
68+
return ABIArgInfo(ABIArgKind::Indirect, ABITy, nullptr, 0, false, InReg);
69+
}
70+
71+
static ABIArgInfo getIgnore() { return ABIArgInfo(ABIArgKind::Ignore); }
72+
73+
static ABIArgInfo getCoerce(const ABIType *ABITy, Type *LLVMTy = nullptr) {
74+
return ABIArgInfo(ABIArgKind::Coerce, ABITy, LLVMTy);
75+
}
76+
77+
static ABIArgInfo getExpand() { return ABIArgInfo(ABIArgKind::Expand); }
78+
79+
// Accessors
80+
ABIArgKind getKind() const { return Kind; }
81+
const ABIType *getCoerceToABIType() const { return CoerceToABIType; }
82+
Type *getCoerceToLLVMType() const { return CoerceToLLVMType; }
83+
unsigned getDirectOffset() const { return DirectOffset; }
84+
bool canBeFlattened() const { return CanBeFlattened; }
85+
bool getInReg() const { return InReg; }
86+
87+
void setCoerceToLLVMType(Type *T) { CoerceToLLVMType = T; }
88+
89+
// Predicates
90+
bool isDirect() const { return Kind == ABIArgKind::Direct; }
91+
bool isIndirect() const { return Kind == ABIArgKind::Indirect; }
92+
bool isIgnore() const { return Kind == ABIArgKind::Ignore; }
93+
bool isCoerce() const { return Kind == ABIArgKind::Coerce; }
94+
bool isExpand() const { return Kind == ABIArgKind::Expand; }
95+
96+
// Expand kind management
97+
void setExpandedArgs(ArrayRef<ABIArgInfo> Args) {
98+
assert(Kind == ABIArgKind::Expand && "Not an expand kind");
99+
ExpandedArgs.assign(Args.begin(), Args.end());
100+
}
101+
102+
ArrayRef<ABIArgInfo> getExpandedArgs() const {
103+
assert(Kind == ABIArgKind::Expand && "Not an expand kind");
104+
return ExpandedArgs;
105+
}
106+
};
107+
108+
/// Base class for target-specific ABI information
109+
class ABIInfo {
110+
public:
111+
virtual ~ABIInfo() = default;
112+
113+
/// Classify how a type should be passed as an argument
114+
virtual ABIArgInfo classifyArgumentType(const ABIType *Ty) = 0;
115+
116+
/// Classify how a type should be returned
117+
virtual ABIArgInfo classifyReturnType(const ABIType *Ty) = 0;
118+
119+
/// Convert an ABIType to the corresponding LLVM IR type
120+
virtual Type *getLLVMType(const ABIType *Ty, LLVMContext &Context) = 0;
121+
};
122+
123+
/// Create target-specific ABI information based on the target triple
124+
std::unique_ptr<ABIInfo> createABIInfo(StringRef TargetTriple);
125+
126+
} // namespace abi
127+
} // namespace llvm
128+
129+
#endif // LLVM_ABI_ABIINFO_H

llvm/include/llvm/ABI/ABIType.h

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
#ifndef LLVM_ABI_ABITYPE_H
2+
#define LLVM_ABI_ABITYPE_H
3+
4+
#include "llvm/ADT/ArrayRef.h"
5+
#include "llvm/ADT/StringRef.h"
6+
#include "llvm/Support/Allocator.h"
7+
#include <cstdint>
8+
#include <vector>
9+
10+
namespace llvm {
11+
namespace abi {
12+
13+
enum class ABITypeKind {
14+
Void,
15+
Bool,
16+
Char,
17+
SChar,
18+
UChar,
19+
Short,
20+
UShort,
21+
Int,
22+
UInt,
23+
Long,
24+
ULong,
25+
LongLong,
26+
ULongLong,
27+
Float,
28+
Double,
29+
LongDouble,
30+
Pointer,
31+
Array,
32+
Record,
33+
Union
34+
};
35+
36+
/// Base class for all types in the ABI type system
37+
class ABIType {
38+
const ABITypeKind Kind;
39+
unsigned Alignment;
40+
41+
protected:
42+
ABIType(ABITypeKind K, unsigned Align) : Kind(K), Alignment(Align) {}
43+
44+
public:
45+
ABITypeKind getKind() const { return Kind; }
46+
unsigned getAlignment() const { return Alignment; }
47+
48+
// Support for LLVM RTTI
49+
static bool classof(const ABIType *) { return true; }
50+
51+
virtual ~ABIType() = default;
52+
};
53+
54+
class VoidType : public ABIType {
55+
public:
56+
VoidType() : ABIType(ABITypeKind::Void, 0) {}
57+
58+
static bool classof(const ABIType *T) {
59+
return T->getKind() == ABITypeKind::Void;
60+
}
61+
};
62+
63+
class ScalarType : public ABIType {
64+
uint64_t Size;
65+
66+
public:
67+
ScalarType(ABITypeKind Kind, unsigned Align, uint64_t Size)
68+
: ABIType(Kind, Align), Size(Size) {}
69+
70+
uint64_t getSize() const { return Size; }
71+
72+
static bool classof(const ABIType *T) {
73+
return T->getKind() >= ABITypeKind::Bool &&
74+
T->getKind() <= ABITypeKind::LongDouble;
75+
}
76+
};
77+
78+
class PointerType : public ABIType {
79+
const ABIType *PointeeType;
80+
uint64_t Size;
81+
82+
public:
83+
PointerType(const ABIType *Pointee, unsigned Align, uint64_t Size)
84+
: ABIType(ABITypeKind::Pointer, Align), PointeeType(Pointee), Size(Size) {
85+
}
86+
87+
const ABIType *getPointeeType() const { return PointeeType; }
88+
uint64_t getSize() const { return Size; }
89+
90+
static bool classof(const ABIType *T) {
91+
return T->getKind() == ABITypeKind::Pointer;
92+
}
93+
};
94+
95+
class ArrayType : public ABIType {
96+
const ABIType *ElementType;
97+
uint64_t NumElements;
98+
uint64_t Size;
99+
100+
public:
101+
ArrayType(const ABIType *ElemType, uint64_t Count, unsigned Align,
102+
uint64_t Size)
103+
: ABIType(ABITypeKind::Array, Align), ElementType(ElemType),
104+
NumElements(Count), Size(Size) {}
105+
106+
const ABIType *getElementType() const { return ElementType; }
107+
uint64_t getNumElements() const { return NumElements; }
108+
uint64_t getSize() const { return Size; }
109+
110+
static bool classof(const ABIType *T) {
111+
return T->getKind() == ABITypeKind::Array;
112+
}
113+
};
114+
115+
struct RecordField {
116+
StringRef Name;
117+
const ABIType *Type;
118+
uint64_t Offset;
119+
120+
RecordField(StringRef Name, const ABIType *Type, uint64_t Offset)
121+
: Name(Name), Type(Type), Offset(Offset) {}
122+
};
123+
124+
class RecordType : public ABIType {
125+
std::vector<RecordField> Fields;
126+
uint64_t Size;
127+
bool Packed;
128+
129+
public:
130+
RecordType(ArrayRef<RecordField> Fields, unsigned Align, uint64_t Size,
131+
bool Packed)
132+
: ABIType(ABITypeKind::Record, Align),
133+
Fields(Fields.begin(), Fields.end()), Size(Size), Packed(Packed) {}
134+
135+
ArrayRef<RecordField> getFields() const { return Fields; }
136+
uint64_t getSize() const { return Size; }
137+
bool isPacked() const { return Packed; }
138+
139+
static bool classof(const ABIType *T) {
140+
return T->getKind() == ABITypeKind::Record;
141+
}
142+
};
143+
144+
class UnionType : public ABIType {
145+
std::vector<RecordField> Fields;
146+
uint64_t Size;
147+
148+
public:
149+
UnionType(ArrayRef<RecordField> Fields, unsigned Align, uint64_t Size)
150+
: ABIType(ABITypeKind::Union, Align),
151+
Fields(Fields.begin(), Fields.end()), Size(Size) {}
152+
153+
ArrayRef<RecordField> getFields() const { return Fields; }
154+
uint64_t getSize() const { return Size; }
155+
156+
static bool classof(const ABIType *T) {
157+
return T->getKind() == ABITypeKind::Union;
158+
}
159+
};
160+
161+
class ABITypeContext {
162+
BumpPtrAllocator Allocator;
163+
VoidType VoidTy;
164+
165+
ScalarType BoolTy;
166+
ScalarType CharTy;
167+
ScalarType SCharTy;
168+
ScalarType UCharTy;
169+
ScalarType ShortTy;
170+
ScalarType UShortTy;
171+
ScalarType IntTy;
172+
ScalarType UIntTy;
173+
ScalarType LongTy;
174+
ScalarType ULongTy;
175+
ScalarType LongLongTy;
176+
ScalarType ULongLongTy;
177+
ScalarType FloatTy;
178+
ScalarType DoubleTy;
179+
ScalarType LongDoubleTy;
180+
181+
public:
182+
ABITypeContext()
183+
: VoidTy(),
184+
// Initialize scalar types with target-independent defaults
185+
// Real implementations would initialize these based on target info
186+
BoolTy(ABITypeKind::Bool, 1, 1), CharTy(ABITypeKind::Char, 1, 1),
187+
SCharTy(ABITypeKind::SChar, 1, 1), UCharTy(ABITypeKind::UChar, 1, 1),
188+
ShortTy(ABITypeKind::Short, 2, 2), UShortTy(ABITypeKind::UShort, 2, 2),
189+
IntTy(ABITypeKind::Int, 4, 4), UIntTy(ABITypeKind::UInt, 4, 4),
190+
LongTy(ABITypeKind::Long, 8, 8), ULongTy(ABITypeKind::ULong, 8, 8),
191+
LongLongTy(ABITypeKind::LongLong, 8, 8),
192+
ULongLongTy(ABITypeKind::ULongLong, 8, 8),
193+
FloatTy(ABITypeKind::Float, 4, 4), DoubleTy(ABITypeKind::Double, 8, 8),
194+
LongDoubleTy(ABITypeKind::LongDouble, 16, 16) {}
195+
196+
const VoidType *getVoidType() { return &VoidTy; }
197+
const ScalarType *getBoolType() { return &BoolTy; }
198+
const ScalarType *getCharType() { return &CharTy; }
199+
const ScalarType *getSCharType() { return &SCharTy; }
200+
const ScalarType *getUCharType() { return &UCharTy; }
201+
const ScalarType *getShortType() { return &ShortTy; }
202+
const ScalarType *getUShortType() { return &UShortTy; }
203+
const ScalarType *getIntType() { return &IntTy; }
204+
const ScalarType *getUIntType() { return &UIntTy; }
205+
const ScalarType *getLongType() { return &LongTy; }
206+
const ScalarType *getULongType() { return &ULongTy; }
207+
const ScalarType *getLongLongType() { return &LongLongTy; }
208+
const ScalarType *getULongLongType() { return &ULongLongTy; }
209+
const ScalarType *getFloatType() { return &FloatTy; }
210+
const ScalarType *getDoubleType() { return &DoubleTy; }
211+
const ScalarType *getLongDoubleType() { return &LongDoubleTy; }
212+
213+
const PointerType *getPointerType(const ABIType *Pointee, unsigned Align,
214+
uint64_t Size) {
215+
return new (Allocator) PointerType(Pointee, Align, Size);
216+
}
217+
218+
const ArrayType *getArrayType(const ABIType *ElementType,
219+
uint64_t NumElements, unsigned Align,
220+
uint64_t Size) {
221+
return new (Allocator) ArrayType(ElementType, NumElements, Align, Size);
222+
}
223+
const RecordType *getRecordType(ArrayRef<RecordField> Fields, unsigned Align,
224+
uint64_t Size, bool Packed = false) {
225+
// Take the allocator and make copy
226+
SmallVector<RecordField, 8> FieldsCopy;
227+
for (const auto &Field : Fields) {
228+
StringRef Name;
229+
if (!Field.Name.empty()) {
230+
char *NameBuf = Allocator.Allocate<char>(Field.Name.size() + 1);
231+
std::copy(Field.Name.begin(), Field.Name.end(), NameBuf);
232+
NameBuf[Field.Name.size()] = '\0';
233+
Name = StringRef(NameBuf, Field.Name.size());
234+
}
235+
FieldsCopy.emplace_back(Name, Field.Type, Field.Offset);
236+
}
237+
return new (Allocator) RecordType(FieldsCopy, Align, Size, Packed);
238+
}
239+
const UnionType *getUnionType(ArrayRef<RecordField> Fields, unsigned Align,
240+
uint64_t Size) {
241+
// Make a copy with the allocator
242+
SmallVector<RecordField, 8> FieldsCopy;
243+
for (const auto &Field : Fields) {
244+
StringRef Name;
245+
if (!Field.Name.empty()) {
246+
char *NameBuf = Allocator.Allocate<char>(Field.Name.size() + 1);
247+
std::copy(Field.Name.begin(), Field.Name.end(), NameBuf);
248+
NameBuf[Field.Name.size()] = '\0';
249+
Name = StringRef(NameBuf, Field.Name.size());
250+
}
251+
FieldsCopy.emplace_back(Name, Field.Type, Field.Offset);
252+
}
253+
return new (Allocator) UnionType(FieldsCopy, Align, Size);
254+
}
255+
};
256+
} // namespace abi
257+
} // namespace llvm
258+
259+
#endif // LLVM_ABI_ABITYPE_H

0 commit comments

Comments
 (0)