clang 20.0.0git
Mips.cpp
Go to the documentation of this file.
1//===- Mips.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 "ABIInfoImpl.h"
10#include "TargetInfo.h"
11
12using namespace clang;
13using namespace clang::CodeGen;
14
15//===----------------------------------------------------------------------===//
16// MIPS ABI Implementation. This works for both little-endian and
17// big-endian variants.
18//===----------------------------------------------------------------------===//
19
20namespace {
21class MipsABIInfo : public ABIInfo {
22 bool IsO32;
23 const unsigned MinABIStackAlignInBytes, StackAlignInBytes;
24 void CoerceToIntArgs(uint64_t TySize,
25 SmallVectorImpl<llvm::Type *> &ArgList) const;
26 llvm::Type* HandleAggregates(QualType Ty, uint64_t TySize) const;
27 llvm::Type* returnAggregateInRegs(QualType RetTy, uint64_t Size) const;
28 llvm::Type* getPaddingType(uint64_t Align, uint64_t Offset) const;
29public:
30 MipsABIInfo(CodeGenTypes &CGT, bool _IsO32) :
31 ABIInfo(CGT), IsO32(_IsO32), MinABIStackAlignInBytes(IsO32 ? 4 : 8),
32 StackAlignInBytes(IsO32 ? 8 : 16) {}
33
35 ABIArgInfo classifyArgumentType(QualType RetTy, uint64_t &Offset) const;
36 void computeInfo(CGFunctionInfo &FI) const override;
37 RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
38 AggValueSlot Slot) const override;
39 ABIArgInfo extendType(QualType Ty) const;
40};
41
42class MIPSTargetCodeGenInfo : public TargetCodeGenInfo {
43 unsigned SizeOfUnwindException;
44public:
45 MIPSTargetCodeGenInfo(CodeGenTypes &CGT, bool IsO32)
46 : TargetCodeGenInfo(std::make_unique<MipsABIInfo>(CGT, IsO32)),
47 SizeOfUnwindException(IsO32 ? 24 : 32) {}
48
49 int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const override {
50 return 29;
51 }
52
53 void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
54 CodeGen::CodeGenModule &CGM) const override {
55 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
56 if (!FD) return;
57 llvm::Function *Fn = cast<llvm::Function>(GV);
58
59 if (FD->hasAttr<MipsLongCallAttr>())
60 Fn->addFnAttr("long-call");
61 else if (FD->hasAttr<MipsShortCallAttr>())
62 Fn->addFnAttr("short-call");
63
64 // Other attributes do not have a meaning for declarations.
65 if (GV->isDeclaration())
66 return;
67
68 if (FD->hasAttr<Mips16Attr>()) {
69 Fn->addFnAttr("mips16");
70 }
71 else if (FD->hasAttr<NoMips16Attr>()) {
72 Fn->addFnAttr("nomips16");
73 }
74
75 if (FD->hasAttr<MicroMipsAttr>())
76 Fn->addFnAttr("micromips");
77 else if (FD->hasAttr<NoMicroMipsAttr>())
78 Fn->addFnAttr("nomicromips");
79
80 const MipsInterruptAttr *Attr = FD->getAttr<MipsInterruptAttr>();
81 if (!Attr)
82 return;
83
84 const char *Kind;
85 switch (Attr->getInterrupt()) {
86 case MipsInterruptAttr::eic: Kind = "eic"; break;
87 case MipsInterruptAttr::sw0: Kind = "sw0"; break;
88 case MipsInterruptAttr::sw1: Kind = "sw1"; break;
89 case MipsInterruptAttr::hw0: Kind = "hw0"; break;
90 case MipsInterruptAttr::hw1: Kind = "hw1"; break;
91 case MipsInterruptAttr::hw2: Kind = "hw2"; break;
92 case MipsInterruptAttr::hw3: Kind = "hw3"; break;
93 case MipsInterruptAttr::hw4: Kind = "hw4"; break;
94 case MipsInterruptAttr::hw5: Kind = "hw5"; break;
95 }
96
97 Fn->addFnAttr("interrupt", Kind);
98
99 }
100
102 llvm::Value *Address) const override;
103
104 unsigned getSizeOfUnwindException() const override {
105 return SizeOfUnwindException;
106 }
107};
108
109class WindowsMIPSTargetCodeGenInfo : public MIPSTargetCodeGenInfo {
110public:
111 WindowsMIPSTargetCodeGenInfo(CodeGenTypes &CGT, bool IsO32)
112 : MIPSTargetCodeGenInfo(CGT, IsO32) {}
113
114 void getDependentLibraryOption(llvm::StringRef Lib,
115 llvm::SmallString<24> &Opt) const override {
116 Opt = "/DEFAULTLIB:";
117 Opt += qualifyWindowsLibrary(Lib);
118 }
119
120 void getDetectMismatchOption(llvm::StringRef Name, llvm::StringRef Value,
121 llvm::SmallString<32> &Opt) const override {
122 Opt = "/FAILIFMISMATCH:\"" + Name.str() + "=" + Value.str() + "\"";
123 }
124};
125}
126
127void MipsABIInfo::CoerceToIntArgs(
128 uint64_t TySize, SmallVectorImpl<llvm::Type *> &ArgList) const {
129 llvm::IntegerType *IntTy =
130 llvm::IntegerType::get(getVMContext(), MinABIStackAlignInBytes * 8);
131
132 // Add (TySize / MinABIStackAlignInBytes) args of IntTy.
133 for (unsigned N = TySize / (MinABIStackAlignInBytes * 8); N; --N)
134 ArgList.push_back(IntTy);
135
136 // If necessary, add one more integer type to ArgList.
137 unsigned R = TySize % (MinABIStackAlignInBytes * 8);
138
139 if (R)
140 ArgList.push_back(llvm::IntegerType::get(getVMContext(), R));
141}
142
143// In N32/64, an aligned double precision floating point field is passed in
144// a register.
145llvm::Type* MipsABIInfo::HandleAggregates(QualType Ty, uint64_t TySize) const {
146 SmallVector<llvm::Type*, 8> ArgList, IntArgList;
147
148 if (IsO32) {
149 CoerceToIntArgs(TySize, ArgList);
150 return llvm::StructType::get(getVMContext(), ArgList);
151 }
152
153 if (Ty->isComplexType())
154 return CGT.ConvertType(Ty);
155
156 const RecordType *RT = Ty->getAs<RecordType>();
157
158 // Unions/vectors are passed in integer registers.
159 if (!RT || !RT->isStructureOrClassType()) {
160 CoerceToIntArgs(TySize, ArgList);
161 return llvm::StructType::get(getVMContext(), ArgList);
162 }
163
164 const RecordDecl *RD = RT->getDecl();
165 const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
166 assert(!(TySize % 8) && "Size of structure must be multiple of 8.");
167
168 uint64_t LastOffset = 0;
169 unsigned idx = 0;
170 llvm::IntegerType *I64 = llvm::IntegerType::get(getVMContext(), 64);
171
172 // Iterate over fields in the struct/class and check if there are any aligned
173 // double fields.
174 for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
175 i != e; ++i, ++idx) {
176 const QualType Ty = i->getType();
177 const BuiltinType *BT = Ty->getAs<BuiltinType>();
178
179 if (!BT || BT->getKind() != BuiltinType::Double)
180 continue;
181
182 uint64_t Offset = Layout.getFieldOffset(idx);
183 if (Offset % 64) // Ignore doubles that are not aligned.
184 continue;
185
186 // Add ((Offset - LastOffset) / 64) args of type i64.
187 for (unsigned j = (Offset - LastOffset) / 64; j > 0; --j)
188 ArgList.push_back(I64);
189
190 // Add double type.
191 ArgList.push_back(llvm::Type::getDoubleTy(getVMContext()));
192 LastOffset = Offset + 64;
193 }
194
195 CoerceToIntArgs(TySize - LastOffset, IntArgList);
196 ArgList.append(IntArgList.begin(), IntArgList.end());
197
198 return llvm::StructType::get(getVMContext(), ArgList);
199}
200
201llvm::Type *MipsABIInfo::getPaddingType(uint64_t OrigOffset,
202 uint64_t Offset) const {
203 if (OrigOffset + MinABIStackAlignInBytes > Offset)
204 return nullptr;
205
206 return llvm::IntegerType::get(getVMContext(), (Offset - OrigOffset) * 8);
207}
208
210MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const {
212
213 uint64_t OrigOffset = Offset;
214 uint64_t TySize = getContext().getTypeSize(Ty);
215 uint64_t Align = getContext().getTypeAlign(Ty) / 8;
216
217 Align = std::clamp(Align, (uint64_t)MinABIStackAlignInBytes,
218 (uint64_t)StackAlignInBytes);
219 unsigned CurrOffset = llvm::alignTo(Offset, Align);
220 Offset = CurrOffset + llvm::alignTo(TySize, Align * 8) / 8;
221
222 if (isAggregateTypeForABI(Ty) || Ty->isVectorType()) {
223 // Ignore empty aggregates.
224 if (TySize == 0)
225 return ABIArgInfo::getIgnore();
226
227 if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {
228 Offset = OrigOffset + MinABIStackAlignInBytes;
229 return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
230 }
231
232 // If we have reached here, aggregates are passed directly by coercing to
233 // another structure type. Padding is inserted if the offset of the
234 // aggregate is unaligned.
235 ABIArgInfo ArgInfo =
236 ABIArgInfo::getDirect(HandleAggregates(Ty, TySize), 0,
237 getPaddingType(OrigOffset, CurrOffset));
238 ArgInfo.setInReg(true);
239 return ArgInfo;
240 }
241
242 // Treat an enum type as its underlying type.
243 if (const EnumType *EnumTy = Ty->getAs<EnumType>())
244 Ty = EnumTy->getDecl()->getIntegerType();
245
246 // Make sure we pass indirectly things that are too large.
247 if (const auto *EIT = Ty->getAs<BitIntType>())
248 if (EIT->getNumBits() > 128 ||
249 (EIT->getNumBits() > 64 &&
250 !getContext().getTargetInfo().hasInt128Type()))
251 return getNaturalAlignIndirect(Ty);
252
253 // All integral types are promoted to the GPR width.
255 return extendType(Ty);
256
258 nullptr, 0, IsO32 ? nullptr : getPaddingType(OrigOffset, CurrOffset));
259}
260
261llvm::Type*
262MipsABIInfo::returnAggregateInRegs(QualType RetTy, uint64_t Size) const {
263 const RecordType *RT = RetTy->getAs<RecordType>();
265
266 if (RT && RT->isStructureOrClassType()) {
267 const RecordDecl *RD = RT->getDecl();
268 const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
269 unsigned FieldCnt = Layout.getFieldCount();
270
271 // N32/64 returns struct/classes in floating point registers if the
272 // following conditions are met:
273 // 1. The size of the struct/class is no larger than 128-bit.
274 // 2. The struct/class has one or two fields all of which are floating
275 // point types.
276 // 3. The offset of the first field is zero (this follows what gcc does).
277 //
278 // Any other composite results are returned in integer registers.
279 //
280 if (FieldCnt && (FieldCnt <= 2) && !Layout.getFieldOffset(0)) {
282 for (; b != e; ++b) {
283 const BuiltinType *BT = b->getType()->getAs<BuiltinType>();
284
285 if (!BT || !BT->isFloatingPoint())
286 break;
287
288 RTList.push_back(CGT.ConvertType(b->getType()));
289 }
290
291 if (b == e)
292 return llvm::StructType::get(getVMContext(), RTList,
293 RD->hasAttr<PackedAttr>());
294
295 RTList.clear();
296 }
297 }
298
299 CoerceToIntArgs(Size, RTList);
300 return llvm::StructType::get(getVMContext(), RTList);
301}
302
303ABIArgInfo MipsABIInfo::classifyReturnType(QualType RetTy) const {
304 uint64_t Size = getContext().getTypeSize(RetTy);
305
306 if (RetTy->isVoidType())
307 return ABIArgInfo::getIgnore();
308
309 // O32 doesn't treat zero-sized structs differently from other structs.
310 // However, N32/N64 ignores zero sized return values.
311 if (!IsO32 && Size == 0)
312 return ABIArgInfo::getIgnore();
313
314 if (isAggregateTypeForABI(RetTy) || RetTy->isVectorType()) {
315 if (Size <= 128) {
316 if (RetTy->isAnyComplexType())
317 return ABIArgInfo::getDirect();
318
319 // O32 returns integer vectors in registers and N32/N64 returns all small
320 // aggregates in registers.
321 if (!IsO32 ||
322 (RetTy->