Skip to content

Commit e5374d4

Browse files
sitio-coutolanza
authored andcommitted
[CIR][ABI] Implement basic struct CC lowering for x86_64 (#784)
This patch adds the necessary bits for unraveling struct arguments and return values for the x86_64 calling convention.
1 parent b73a191 commit e5374d4

29 files changed

+1899
-87
lines changed

clang/include/clang/CIR/Dialect/IR/CIRDataLayout.h

Lines changed: 88 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -12,51 +12,52 @@
1212
#ifndef LLVM_CLANG_CIR_DIALECT_IR_CIRDATALAYOUT_H
1313
#define LLVM_CLANG_CIR_DIALECT_IR_CIRDATALAYOUT_H
1414

15-
#include "mlir/Dialect/DLTI/DLTI.h"
1615
#include "mlir/IR/BuiltinOps.h"
1716
#include "clang/CIR/Dialect/IR/CIRTypes.h"
18-
#include "llvm/ADT/StringRef.h"
17+
#include "llvm/IR/DataLayout.h"
18+
#include "llvm/Support/Alignment.h"
19+
#include "llvm/Support/TypeSize.h"
1920

2021
namespace cir {
2122

23+
class StructLayout;
24+
25+
// FIXME(cir): This might be replaced by a CIRDataLayout interface which can
26+
// provide the same functionalities.
2227
class CIRDataLayout {
2328
bool bigEndian = false;
2429

30+
/// Primitive type alignment data. This is sorted by type and bit
31+
/// width during construction.
32+
llvm::DataLayout::PrimitiveSpec StructAlignment;
33+
34+
// The StructType -> StructLayout map.
35+
mutable void *LayoutMap = nullptr;
36+
2537
public:
2638
mlir::DataLayout layout;
2739

28-
/// Constructs a DataLayout from a specification string. See reset().
29-
explicit CIRDataLayout(llvm::StringRef dataLayout, mlir::ModuleOp module)
30-
: layout(module) {
31-
reset(dataLayout);
32-
}
40+
/// Constructs a DataLayout the module's data layout attribute.
41+
CIRDataLayout(mlir::ModuleOp modOp);
3342

3443
/// Parse a data layout string (with fallback to default values).
35-
void reset(llvm::StringRef dataLayout);
44+
void reset();
3645

3746
// Free all internal data structures.
3847
void clear();
3948

40-
CIRDataLayout(mlir::ModuleOp modOp);
41-
4249
bool isBigEndian() const { return bigEndian; }
4350

44-
// `useABI` is `true` if not using prefered alignment.
45-
unsigned getAlignment(mlir::Type ty, bool useABI) const {
46-
if (llvm::isa<mlir::cir::StructType>(ty)) {
47-
auto sTy = mlir::cast<mlir::cir::StructType>(ty);
48-
if (sTy.getPacked() && useABI)
49-
return 1;
50-
} else if (llvm::isa<mlir::cir::ArrayType>(ty)) {
51-
return getAlignment(mlir::cast<mlir::cir::ArrayType>(ty).getEltType(),
52-
useABI);
53-
}
54-
55-
return useABI ? layout.getTypeABIAlignment(ty)
56-
: layout.getTypePreferredAlignment(ty);
57-
}
51+
/// Returns a StructLayout object, indicating the alignment of the
52+
/// struct, its size, and the offsets of its fields.
53+
///
54+
/// Note that this information is lazily cached.
55+
const StructLayout *getStructLayout(mlir::cir::StructType Ty) const;
56+
57+
/// Internal helper method that returns requested alignment for type.
58+
llvm::Align getAlignment(mlir::Type Ty, bool abi_or_pref) const;
5859

59-
unsigned getABITypeAlign(mlir::Type ty) const {
60+
llvm::Align getABITypeAlign(mlir::Type ty) const {
6061
return getAlignment(ty, true);
6162
}
6263

@@ -67,10 +68,10 @@ class CIRDataLayout {
6768
/// the runtime size will be a positive integer multiple of the base size.
6869
///
6970
/// For example, returns 5 for i36 and 10 for x86_fp80.
70-
unsigned getTypeStoreSize(mlir::Type Ty) const {
71-
// FIXME: this is a bit inaccurate, see DataLayout::getTypeStoreSize for
72-
// more information.
73-
return llvm::divideCeil(layout.getTypeSizeInBits(Ty), 8);
71+
llvm::TypeSize getTypeStoreSize(mlir::Type Ty) const {
72+
llvm::TypeSize BaseSize = getTypeSizeInBits(Ty);
73+
return {llvm::divideCeil(BaseSize.getKnownMinValue(), 8),
74+
BaseSize.isScalable()};
7475
}
7576

7677
/// Returns the offset in bytes between successive objects of the
@@ -81,20 +82,20 @@ class CIRDataLayout {
8182
///
8283
/// This is the amount that alloca reserves for this type. For example,
8384
/// returns 12 or 16 for x86_fp80, depending on alignment.
84-
unsigned getTypeAllocSize(mlir::Type Ty) const {
85+
llvm::TypeSize getTypeAllocSize(mlir::Type Ty) const {
8586
// Round up to the next alignment boundary.
86-
return llvm::alignTo(getTypeStoreSize(Ty), getABITypeAlign(Ty));
87+
return llvm::alignTo(getTypeStoreSize(Ty), getABITypeAlign(Ty).value());
8788
}
8889

89-
unsigned getPointerTypeSizeInBits(mlir::Type Ty) const {
90+
llvm::TypeSize getPointerTypeSizeInBits(mlir::Type Ty) const {
9091
assert(mlir::isa<mlir::cir::PointerType>(Ty) &&
9192
"This should only be called with a pointer type");
9293
return layout.getTypeSizeInBits(Ty);
9394
}
9495

95-
unsigned getTypeSizeInBits(mlir::Type Ty) const {
96-
return layout.getTypeSizeInBits(Ty);
97-
}
96+
// The implementation of this method is provided inline as it is particularly
97+
// well suited to constant folding when called on a specific Type subclass.
98+
llvm::TypeSize getTypeSizeInBits(mlir::Type Ty) const;
9899

99100
mlir::Type getIntPtrType(mlir::Type Ty) const {
100101
assert(mlir::isa<mlir::cir::PointerType>(Ty) && "Expected pointer type");
@@ -104,6 +105,58 @@ class CIRDataLayout {
104105
}
105106
};
106107

108+
/// Used to lazily calculate structure layout information for a target machine,
109+
/// based on the DataLayout structure.
110+
class StructLayout final
111+
: public llvm::TrailingObjects<StructLayout, llvm::TypeSize> {
112+
llvm::TypeSize StructSize;
113+
llvm::Align StructAlignment;
114+
unsigned IsPadded : 1;
115+
unsigned NumElements : 31;
116+
117+
public:
118+
llvm::TypeSize getSizeInBytes() const { return StructSize; }
119+
120+
llvm::TypeSize getSizeInBits() const { return 8 * StructSize; }
121+
122+
llvm::Align getAlignment() const { return StructAlignment; }
123+
124+
/// Returns whether the struct has padding or not between its fields.
125+
/// NB: Padding in nested element is not taken into account.
126+
bool hasPadding() const { return IsPadded; }
127+
128+
/// Given a valid byte offset into the structure, returns the structure
129+
/// index that contains it.
130+
unsigned getElementContainingOffset(uint64_t FixedOffset) const;
131+
132+
llvm::MutableArrayRef<llvm::TypeSize> getMemberOffsets() {
133+
return llvm::MutableArrayRef(getTrailingObjects<llvm::TypeSize>(),
134+
NumElements);
135+
}
136+
137+
llvm::ArrayRef<llvm::TypeSize> getMemberOffsets() const {
138+
return llvm::ArrayRef(getTrailingObjects<llvm::TypeSize>(), NumElements);
139+
}
140+
141+
llvm::TypeSize getElementOffset(unsigned Idx) const {
142+
assert(Idx < NumElements && "Invalid element idx!");
143+
return getMemberOffsets()[Idx];
144+
}
145+
146+
llvm::TypeSize getElementOffsetInBits(unsigned Idx) const {
147+
return getElementOffset(Idx) * 8;
148+
}
149+
150+
private:
151+
friend class CIRDataLayout; // Only DataLayout can create this class
152+
153+
StructLayout(mlir::cir::StructType ST, const CIRDataLayout &DL);
154+
155+
size_t numTrailingObjects(OverloadToken<llvm::TypeSize>) const {
156+
return NumElements;
157+
}
158+
};
159+
107160
} // namespace cir
108161

109162
#endif

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,12 @@ def StoreOp : CIR_Op<"store", [
589589
```
590590
}];
591591

592+
let builders = [
593+
OpBuilder<(ins "Value":$value, "Value":$addr), [{
594+
$_state.addOperands({value, addr});
595+
}]>
596+
];
597+
592598
let arguments = (ins CIR_AnyType:$value,
593599
Arg<CIR_PointerType, "the address to store the value",
594600
[MemWrite]>:$addr,

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ struct MissingFeatures {
7070
// ObjC
7171
static bool setObjCGCLValueClass() { return false; }
7272
static bool objCLifetime() { return false; }
73+
static bool objCIvarDecls() { return false; }
7374

7475
// Debug info
7576
static bool generateDebugInfo() { return false; }
@@ -205,17 +206,42 @@ struct MissingFeatures {
205206

206207
//-- Missing AST queries
207208

208-
static bool recordDeclCanPassInRegisters() { return false; }
209+
static bool CXXRecordDeclIsEmptyCXX11() { return false; }
210+
static bool CXXRecordDeclIsPOD() { return false; }
211+
static bool CXXRecordIsDynamicClass() { return false; }
212+
static bool astContextGetExternalSource() { return false; }
213+
static bool declGetMaxAlignment() { return false; }
214+
static bool declHasAlignMac68kAttr() { return false; }
215+
static bool declHasAlignNaturalAttr() { return false; }
216+
static bool declHasMaxFieldAlignmentAttr() { return false; }
217+
static bool fieldDeclIsBitfield() { return false; }
218+
static bool fieldDeclIsPotentiallyOverlapping() { return false; }
219+
static bool fieldDeclGetMaxFieldAlignment() { return false; }
220+
static bool fieldDeclisUnnamedBitField() { return false; }
209221
static bool funcDeclIsCXXConstructorDecl() { return false; }
210222
static bool funcDeclIsCXXDestructorDecl() { return false; }
211223
static bool funcDeclIsCXXMethodDecl() { return false; }
212224
static bool funcDeclIsInlineBuiltinDeclaration() { return false; }
213225
static bool funcDeclIsReplaceableGlobalAllocationFunction() { return false; }
226+
static bool isCXXRecordDecl() { return false; }
214227
static bool qualTypeIsReferenceType() { return false; }
215-
static bool typeGetAsEnumType() { return false; }
228+
static bool recordDeclCanPassInRegisters() { return false; }
229+
static bool recordDeclHasAlignmentAttr() { return false; }
230+
static bool recordDeclHasFlexibleArrayMember() { return false; }
231+
static bool recordDeclIsCXXDecl() { return false; }
232+
static bool recordDeclIsMSStruct() { return false; }
233+
static bool recordDeclIsPacked() { return false; }
234+
static bool recordDeclMayInsertExtraPadding() { return false; }
216235
static bool typeGetAsBuiltinType() { return false; }
236+
static bool typeGetAsEnumType() { return false; }
237+
static bool typeIsCXXRecordDecl() { return false; }
238+
static bool typeIsScalableType() { return false; }
239+
static bool typeIsSized() { return false; }
217240
static bool varDeclIsKNRPromoted() { return false; }
218241

242+
// We need to track parent (base) classes to determine the layout of a class.
243+
static bool getCXXRecordBases() { return false; }
244+
219245
//-- Missing types
220246

221247
static bool fixedWidthIntegers() { return false; }
@@ -232,6 +258,18 @@ struct MissingFeatures {
232258

233259
//-- Other missing features
234260

261+
// We need to track the parent record types that represent a field
262+
// declaration. This is necessary to determine the layout of a class.
263+
static bool fieldDeclAbstraction() { return false; }
264+
265+
// There are some padding diagnostic features for Itanium ABI that we might
266+
// wanna add later.
267+
static bool bitFieldPaddingDiagnostics() { return false; }
268+
269+
// Clang considers both enums and records as tag types. We don't have a way to
270+
// transparently handle both these types yet. Might need an interface here.
271+
static bool tagTypeClassAbstraction() { return false; }
272+
235273
// Empty values might be passed as arguments to serve as padding, ensuring
236274
// alignment and compliance (e.g. MIPS). We do not yet support this.
237275
static bool argumentPadding() { return false; }
@@ -268,7 +306,7 @@ struct MissingFeatures {
268306
// evaluating ABI-specific lowering.
269307
static bool qualifiedTypes() { return false; }
270308

271-
// We're ignoring several details regarding ABI-halding for Swift.
309+
// We're ignoring several details regarding ABI-handling for Swift.
272310
static bool swift() { return false; }
273311

274312
// The AppleARM64 is using ItaniumCXXABI, which is not quite right.
@@ -281,6 +319,7 @@ struct MissingFeatures {
281319
// If a store op is guaranteed to execute before the retun value load op, we
282320
// can optimize away the store and load ops. Seems like an early optimization.
283321
static bool returnValueDominatingStoreOptmiization() { return false; }
322+
284323
// Globals (vars and functions) may have attributes that are target depedent.
285324
static bool setTargetAttributes() { return false; }
286325

clang/lib/CIR/CodeGen/CIRGenBuilder.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -878,7 +878,7 @@ class CIRGenBuilderTy : public CIRBaseBuilderTy {
878878
unsigned Pos = 0;
879879
for (size_t I = 0; I < Elts.size(); ++I) {
880880
auto EltSize = Layout.getTypeAllocSize(Elts[I]);
881-
unsigned AlignMask = Layout.getABITypeAlign(Elts[I]) - 1;
881+
unsigned AlignMask = Layout.getABITypeAlign(Elts[I]).value() - 1;
882882
Pos = (Pos + AlignMask) & ~AlignMask;
883883
if (Offset < Pos + EltSize) {
884884
Indices.push_back(I);

0 commit comments

Comments
 (0)