clang 22.0.0git
Hexagon.cpp
Go to the documentation of this file.
1//===- Hexagon.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// Hexagon ABI Implementation
17//===----------------------------------------------------------------------===//
18
19namespace {
20
21class HexagonABIInfo : public DefaultABIInfo {
22public:
23 HexagonABIInfo(CodeGenTypes &CGT) : DefaultABIInfo(CGT) {}
24
25private:
26 ABIArgInfo classifyReturnType(QualType RetTy) const;
27 ABIArgInfo classifyArgumentType(QualType RetTy) const;
28 ABIArgInfo classifyArgumentType(QualType RetTy, unsigned *RegsLeft) const;
29
30 void computeInfo(CGFunctionInfo &FI) const override;
31
32 RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
33 AggValueSlot Slot) const override;
34 Address EmitVAArgFromMemory(CodeGenFunction &CFG, Address VAListAddr,
35 QualType Ty) const;
36 Address EmitVAArgForHexagon(CodeGenFunction &CFG, Address VAListAddr,
37 QualType Ty) const;
38 Address EmitVAArgForHexagonLinux(CodeGenFunction &CFG, Address VAListAddr,
39 QualType Ty) const;
40};
41
42class HexagonTargetCodeGenInfo : public TargetCodeGenInfo {
43public:
44 HexagonTargetCodeGenInfo(CodeGenTypes &CGT)
45 : TargetCodeGenInfo(std::make_unique<HexagonABIInfo>(CGT)) {}
46
47 int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override {
48 return 29;
49 }
50
51 void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
52 CodeGen::CodeGenModule &GCM) const override {
53 if (GV->isDeclaration())
54 return;
55 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
56 if (!FD)
57 return;
58 }
59};
60
61} // namespace
62
63void HexagonABIInfo::computeInfo(CGFunctionInfo &FI) const {
64 unsigned RegsLeft = 6;
65 if (!getCXXABI().classifyReturnType(FI))
67 for (auto &I : FI.arguments())
68 I.info = classifyArgumentType(I.type, &RegsLeft);
69}
70
71static bool HexagonAdjustRegsLeft(uint64_t Size, unsigned *RegsLeft) {
72 assert(Size <= 64 && "Not expecting to pass arguments larger than 64 bits"
73 " through registers");
74
75 if (*RegsLeft == 0)
76 return false;
77
78 if (Size <= 32) {
79 (*RegsLeft)--;
80 return true;
81 }
82
83 if (2 <= (*RegsLeft & (~1U))) {
84 *RegsLeft = (*RegsLeft & (~1U)) - 2;
85 return true;
86 }
87
88 // Next available register was r5 but candidate was greater than 32-bits so it
89 // has to go on the stack. However we still consume r5
90 if (*RegsLeft == 1)
91 *RegsLeft = 0;
92
93 return false;
94}
95
96ABIArgInfo HexagonABIInfo::classifyArgumentType(QualType Ty,
97 unsigned *RegsLeft) const {
98 if (!isAggregateTypeForABI(Ty)) {
99 // Treat an enum type as its underlying type.
100 if (const auto *ED = Ty->getAsEnumDecl())
101 Ty = ED->getIntegerType();
102
103 uint64_t Size = getContext().getTypeSize(Ty);
104 if (Size <= 64)
105 HexagonAdjustRegsLeft(Size, RegsLeft);
106
107 if (Size > 64 && Ty->isBitIntType())
108 return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(),
109 /*ByVal=*/true);
110
111 return isPromotableIntegerTypeForABI(Ty) ? ABIArgInfo::getExtend(Ty)
112 : ABIArgInfo::getDirect();
113 }
114
115 if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
116 return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(),
118
119 // Ignore empty records.
120 if (isEmptyRecord(getContext(), Ty, true))
121 return ABIArgInfo::getIgnore();
122
123 uint64_t Size = getContext().getTypeSize(Ty);
124 unsigned Align = getContext().getTypeAlign(Ty);
125
126 if (Size > 64)
127 return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(),
128 /*ByVal=*/true);
129
130 if (HexagonAdjustRegsLeft(Size, RegsLeft))
131 Align = Size <= 32 ? 32 : 64;
132 if (Size <= Align) {
133 // Pass in the smallest viable integer type.
134 Size = llvm::bit_ceil(Size);
135 return ABIArgInfo::getDirect(llvm::Type::getIntNTy(getVMContext(), Size));
136 }
138}
139
140ABIArgInfo HexagonABIInfo::classifyReturnType(QualType RetTy) const {
141 if (RetTy->isVoidType())
142 return ABIArgInfo::getIgnore();
143
144 const TargetInfo &T = CGT.getTarget();
145 uint64_t Size = getContext().getTypeSize(RetTy);
146
147 if (RetTy->getAs<VectorType>()) {
148 // HVX vectors are returned in vector registers or register pairs.
149 if (T.hasFeature("hvx")) {
150 assert(T.hasFeature("hvx-length64b") || T.hasFeature("hvx-length128b"));
151 uint64_t VecSize = T.hasFeature("hvx-length64b") ? 64*8 : 128*8;
152 if (Size == VecSize || Size == 2*VecSize)
154 }
155 // Large vector types should be returned via memory.
156 if (Size > 64)
157 return getNaturalAlignIndirect(RetTy,
158 getDataLayout().getAllocaAddrSpace());
159 }
160
161 if (!isAggregateTypeForABI(RetTy)) {
162 // Treat an enum type as its underlying type.
163 if (const auto *ED = RetTy->getAsEnumDecl())
164 RetTy = ED->getIntegerType();
165
166 if (Size > 64 && RetTy->isBitIntType())
167 return getNaturalAlignIndirect(
168 RetTy, getDataLayout().getAllocaAddrSpace(), /*ByVal=*/false);
169
170 return isPromotableIntegerTypeForABI(RetTy) ? ABIArgInfo::getExtend(RetTy)
171 : ABIArgInfo::getDirect();
172 }
173
174 if (isEmptyRecord(getContext(), RetTy, true))
175 return ABIArgInfo::getIgnore();
176
177 // Aggregates <= 8 bytes are returned in registers, other aggregates
178 // are returned indirectly.
179 if (Size <= 64) {
180 // Return in the smallest viable integer type.
181 Size = llvm::bit_ceil(Size);
182 return ABIArgInfo::getDirect(llvm::Type::getIntNTy(getVMContext(), Size));
183 }
184 return getNaturalAlignIndirect(RetTy, getDataLayout().getAllocaAddrSpace(),
185 /*ByVal=*/true);
186}
187
188Address HexagonABIInfo::EmitVAArgFromMemory(CodeGenFunction &CGF,
189 Address VAListAddr,
190 QualType Ty) const {
191 // Load the overflow area pointer.
192 Address __overflow_area_pointer_p =
193 CGF.Builder.CreateStructGEP(VAListAddr, 2, "__overflow_area_pointer_p");
194 llvm::Value *__overflow_area_pointer = CGF.Builder.CreateLoad(
195 __overflow_area_pointer_p, "__overflow_area_pointer");
196
197 uint64_t Align = CGF.getContext().getTypeAlign(Ty) / 8;
198 if (Align > 4) {
199 // Alignment should be a power of 2.
200 assert((Align & (Align - 1)) == 0 && "Alignment is not power of 2!");
201
202 // overflow_arg_area = (overflow_arg_area + align - 1) & -align;
203 llvm::Value *Offset = llvm::ConstantInt::get(CGF.Int64Ty, Align - 1);
204
205 // Add offset to the current pointer to access the argument.
206 __overflow_area_pointer =
207 CGF.Builder.CreateGEP(CGF.Int8Ty, __overflow_area_pointer, Offset);
208 llvm::Value *AsInt =
209 CGF.Builder.CreatePtrToInt(__overflow_area_pointer, CGF.Int32Ty);
210
211 // Create a mask which should be "AND"ed
212 // with (overflow_arg_area + align - 1)
213 llvm::Value *Mask = llvm::ConstantInt::get(CGF.Int32Ty, -(int)Align);
214 __overflow_area_pointer = CGF.Builder.CreateIntToPtr(
215 CGF.Builder.CreateAnd(AsInt, Mask), __overflow_area_pointer->getType(),
216 "__overflow_area_pointer.align");
217 }
218
219 // Get the type of the argument from memory and bitcast
220 // overflow area pointer to the argument type.
221 llvm::Type *PTy = CGF.ConvertTypeForMem(Ty);
222 Address AddrTyped =
223 Address(__overflow_area_pointer, PTy, CharUnits::fromQuantity(Align));
224
225 // Round up to the minimum stack alignment for varargs which is 4 bytes.
226 uint64_t Offset = llvm::alignTo(CGF.getContext().getTypeSize(Ty) / 8, 4);
227
228 __overflow_area_pointer = CGF.Builder.CreateGEP(
229 CGF.Int8Ty, __overflow_area_pointer,
230 llvm::ConstantInt::get(CGF.Int32Ty, Offset),
231 "__overflow_area_pointer.next");
232 CGF.Builder.CreateStore(__overflow_area_pointer, __overflow_area_pointer_p);
233
234 return AddrTyped;
235}
236
237Address HexagonABIInfo::EmitVAArgForHexagon(CodeGenFunction &CGF,
238 Address VAListAddr,
239 QualType Ty) const {
240 // FIXME: Need to handle alignment
241 llvm::Type *BP = CGF.Int8PtrTy;
242 CGBuilderTy &Builder = CGF.Builder;
243 Address VAListAddrAsBPP = VAListAddr.withElementType(BP);
244 llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur");
245 // Handle address alignment for type alignment > 32 bits
246 uint64_t TyAlign = CGF.getContext().getTypeAlign(Ty) / 8;
247 if (TyAlign > 4) {
248 assert((TyAlign & (TyAlign - 1)) == 0 && "Alignment is not power of 2!");
249 llvm::Value *AddrAsInt = Builder.CreatePtrToInt(Addr, CGF.Int32Ty);
250 AddrAsInt = Builder.CreateAdd(AddrAsInt, Builder.getInt32(TyAlign - 1));
251 AddrAsInt = Builder.CreateAnd(AddrAsInt, Builder.getInt32(~(TyAlign - 1)));
252 Addr = Builder.CreateIntToPtr(AddrAsInt, BP);
253 }
254 Address AddrTyped =
255 Address(Addr, CGF.ConvertType(Ty), CharUnits::fromQuantity(TyAlign));
256
257 uint64_t Offset = llvm::alignTo(CGF.getContext().getTypeSize(Ty) / 8, 4);
258 llvm::Value *NextAddr = Builder.CreateGEP(
259 CGF.Int8Ty, Addr, llvm::ConstantInt::get(CGF.Int32Ty, Offset), "ap.next");
260 Builder.CreateStore(NextAddr, VAListAddrAsBPP);
261
262 return AddrTyped;
263}
264
265Address HexagonABIInfo::EmitVAArgForHexagonLinux(CodeGenFunction &CGF,
266 Address VAListAddr,
267 QualType Ty) const {
268 int ArgSize = CGF.getContext().getTypeSize(Ty) / 8;
269
270 if (ArgSize > 8)
271 return EmitVAArgFromMemory(CGF, VAListAddr, Ty);
272
273 // Here we have check if the argument is in register area or
274 // in overflow area.
275 // If the saved register area pointer + argsize rounded up to alignment >
276 // saved register area end pointer, argument is in overflow area.
277 unsigned RegsLeft = 6;
278 Ty = CGF.getContext().getCanonicalType(Ty);
279 (void)classifyArgumentType(Ty, &RegsLeft);
280
281 llvm::BasicBlock *MaybeRegBlock = CGF.createBasicBlock("vaarg.maybe_reg");
282 llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg");
283 llvm::BasicBlock *OnStackBlock = CGF.createBasicBlock("vaarg.on_stack");
284 llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end");
285
286 // Get rounded size of the argument.GCC does not allow vararg of
287 // size < 4 bytes. We follow the same logic here.
288 ArgSize = (CGF.getContext().getTypeSize(Ty) <= 32) ? 4 : 8;
289 int ArgAlign = (CGF.getContext().getTypeSize(Ty) <= 32) ? 4 : 8;
290
291 // Argument may be in saved register area
292 CGF.EmitBlock(MaybeRegBlock);
293
294 // Load the current saved register area pointer.
295 Address __current_saved_reg_area_pointer_p = CGF.Builder.CreateStructGEP(
296 VAListAddr, 0, "__current_saved_reg_area_pointer_p");
297 llvm::Value *__current_saved_reg_area_pointer = CGF.Builder.CreateLoad(
298 __current_saved_reg_area_pointer_p, "__current_saved_reg_area_pointer");
299
300 // Load the saved register area end pointer.
301 Address __saved_reg_area_end_pointer_p = CGF.Builder.CreateStructGEP(
302 VAListAddr, 1, "__saved_reg_area_end_pointer_p");
303 llvm::Value *__saved_reg_area_end_pointer = CGF.Builder.CreateLoad(
304 __saved_reg_area_end_pointer_p, "__saved_reg_area_end_pointer");
305
306 // If the size of argument is > 4 bytes, check if the stack
307 // location is aligned to 8 bytes
308 if (ArgAlign > 4) {
309
310 llvm::Value *__current_saved_reg_area_pointer_int =
311 CGF.Builder.CreatePtrToInt(__current_saved_reg_area_pointer,
312 CGF.Int32Ty);
313
314 __current_saved_reg_area_pointer_int = CGF.Builder.CreateAdd(
315 __current_saved_reg_area_pointer_int,
316 llvm::ConstantInt::get(CGF.Int32Ty, (ArgAlign - 1)),
317 "align_current_saved_reg_area_pointer");
318
319 __current_saved_reg_area_pointer_int =
320 CGF.Builder.CreateAnd(__current_saved_reg_area_pointer_int,
321 llvm::ConstantInt::get(CGF.Int32Ty, -ArgAlign),
322 "align_current_saved_reg_area_pointer");
323
324 __current_saved_reg_area_pointer =
325 CGF.Builder.CreateIntToPtr(__current_saved_reg_area_pointer_int,
326 __current_saved_reg_area_pointer->getType(),
327 "align_current_saved_reg_area_pointer");
328 }
329
330 llvm::Value *__new_saved_reg_area_pointer =
331 CGF.Builder.CreateGEP(CGF.Int8Ty, __current_saved_reg_area_pointer,
332 llvm::ConstantInt::get(CGF.Int32Ty, ArgSize),
333 "__new_saved_reg_area_pointer");
334
335 llvm::Value *UsingStack = nullptr;
336 UsingStack = CGF.Builder.CreateICmpSGT(__new_saved_reg_area_pointer,
337 __saved_reg_area_end_pointer);
338
339 CGF.Builder.CreateCondBr(UsingStack, OnStackBlock, InRegBlock);
340
341 // Argument in saved register area
342 // Implement the block where argument is in register saved area
343 CGF.EmitBlock(InRegBlock);
344
345 CGF.Builder.CreateStore(__new_saved_reg_area_pointer,
346 __current_saved_reg_area_pointer_p);
347
348 CGF.EmitBranch(ContBlock);
349
350 // Argument in overflow area
351 // Implement the block where the argument is in overflow area.
352 CGF.EmitBlock(OnStackBlock);
353
354 // Load the overflow area pointer
355 Address __overflow_area_pointer_p =
356 CGF.Builder.CreateStructGEP(VAListAddr, 2, "__overflow_area_pointer_p");
357 llvm::Value *__overflow_area_pointer = CGF.Builder.CreateLoad(
358 __overflow_area_pointer_p, "__overflow_area_pointer");
359
360 // Align the overflow area pointer according to the alignment of the argument
361 if (ArgAlign > 4) {
362 llvm::Value *__overflow_area_pointer_int =
363 CGF.Builder.CreatePtrToInt(__overflow_area_pointer, CGF.Int32Ty);
364
365 __overflow_area_pointer_int =
366 CGF.Builder.CreateAdd(__overflow_area_pointer_int,
367 llvm::ConstantInt::get(CGF.Int32Ty, ArgAlign - 1),
368 "align_overflow_area_pointer");
369
370 __overflow_area_pointer_int =
371 CGF.Builder.CreateAnd(__overflow_area_pointer_int,
372 llvm::ConstantInt::get(CGF.Int32Ty, -ArgAlign),
373 "align_overflow_area_pointer");
374
375 __overflow_area_pointer = CGF.Builder.CreateIntToPtr(
376 __overflow_area_pointer_int, __overflow_area_pointer->getType(),
377 "align_overflow_area_pointer");
378 }
379
380 // Get the pointer for next argument in overflow area and store it
381 // to overflow area pointer.
382 llvm::Value *__new_overflow_area_pointer = CGF.Builder.CreateGEP(
383 CGF.Int8Ty, __overflow_area_pointer,
384 llvm::ConstantInt::get(CGF.Int32Ty, ArgSize),
385 "__overflow_area_pointer.next");
386
387 CGF.Builder.CreateStore(__new_overflow_area_pointer,
388 __overflow_area_pointer_p);
389
390 CGF.Builder.CreateStore(__new_overflow_area_pointer,
391 __current_saved_reg_area_pointer_p);
392
393 CGF.EmitBranch(ContBlock);
394 // Get the correct pointer to load the variable argument
395 // Implement the ContBlock
396 CGF.EmitBlock(ContBlock);
397
398 llvm::Type *MemTy = CGF.ConvertTypeForMem(Ty);
399 llvm::PHINode *ArgAddr = CGF.Builder.CreatePHI(
400 llvm::PointerType::getUnqual(MemTy->getContext()), 2, "vaarg.addr");
401 ArgAddr->addIncoming(__current_saved_reg_area_pointer, InRegBlock);
402 ArgAddr->addIncoming(__overflow_area_pointer, OnStackBlock);
403
404 return Address(ArgAddr, MemTy, CharUnits::fromQuantity(ArgAlign));
405}
406
407RValue HexagonABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
408 QualType Ty, AggValueSlot Slot) const {
409
410 if (getTarget().getTriple().isMusl())
411 return CGF.EmitLoadOfAnyValue(
412 CGF.MakeAddrLValue(EmitVAArgForHexagonLinux(CGF, VAListAddr, Ty), Ty),
413 Slot);
414
415 return CGF.EmitLoadOfAnyValue(
416 CGF.MakeAddrLValue(EmitVAArgForHexagon(CGF, VAListAddr, Ty), Ty), Slot);
417}
418
419std::unique_ptr<TargetCodeGenInfo>
421 return std::make_unique<HexagonTargetCodeGenInfo>(CGM.getTypes());
422}
static bool HexagonAdjustRegsLeft(uint64_t Size, unsigned *RegsLeft)
Definition Hexagon.cpp:71
CanQualType getCanonicalType(QualType T) const
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
unsigned getTypeAlign(QualType T) const
Return the ABI-specified alignment of a (complete) type T, in bits.
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
Definition CharUnits.h:63
static ABIArgInfo getIgnore()
static ABIArgInfo getDirect(llvm::Type *T=nullptr, unsigned Offset=0, llvm::Type *Padding=nullptr, bool CanBeFlattened=true, unsigned Align=0)
static ABIArgInfo getExtend(QualType Ty, llvm::Type *T=nullptr)
static ABIArgInfo getDirectInReg(llvm::Type *T=nullptr)
Address withElementType(llvm::Type *ElemTy) const
Return address with different element type, but same pointer and alignment.
Definition Address.h:276
llvm::StoreInst * CreateStore(llvm::Value *Val, Address Addr, bool IsVolatile=false)
Definition CGBuilder.h:140
Address CreateGEP(CodeGenFunction &CGF, Address Addr, llvm::Value *Index, const llvm::Twine &Name="")
Definition CGBuilder.h:296
Address CreateStructGEP(Address Addr, unsigned Index, const llvm::Twine &Name="")
Definition CGBuilder.h:223
llvm::LoadInst * CreateLoad(Address Addr, const llvm::Twine &Name="")
Definition CGBuilder.h:112
RecordArgABI
Specify how one should pass an argument of a record type.
Definition CGCXXABI.h:150
@ RAA_DirectInMemory
Pass it on the stack using its defined layout.
Definition CGCXXABI.h:158
CGFunctionInfo - Class to encapsulate the information about a function definition.
CanQualType getReturnType() const
MutableArrayRef< ArgInfo > arguments()
llvm::Type * ConvertType(QualType T)
llvm::BasicBlock * createBasicBlock(const Twine &name="", llvm::Function *parent=nullptr, llvm::BasicBlock *before=nullptr)
createBasicBlock - Create an LLVM basic block.
RValue EmitLoadOfAnyValue(LValue V, AggValueSlot Slot=AggValueSlot::ignored(), SourceLocation Loc={})
Like EmitLoadOfLValue but also handles complex and aggregate types.
Definition CGExpr.cpp:2318
llvm::Type * ConvertTypeForMem(QualType T)
void EmitBranch(llvm::BasicBlock *Block)
EmitBranch - Emit a branch to the specified basic block from the current insert block,...
Definition CGStmt.cpp:672
LValue MakeAddrLValue(Address Addr, QualType T, AlignmentSource Source=AlignmentSource::Type)
void EmitBlock(llvm::BasicBlock *BB, bool IsFinished=false)
EmitBlock - Emit the given block.
Definition CGStmt.cpp:652
This class organizes the cross-function state that is used while generating LLVM code.
DefaultABIInfo - The default implementation for ABI specific details.
Definition ABIInfoImpl.h:21
ABIArgInfo classifyArgumentType(QualType RetTy) const
TargetCodeGenInfo - This class organizes various target-specific codegeneration issues,...
Definition TargetInfo.h:47
bool isVoidType() const
Definition TypeBase.h:8878
bool isBitIntType() const
Definition TypeBase.h:8787
EnumDecl * getAsEnumDecl() const
Retrieves the EnumDecl this type refers to.
Definition Type.h:53
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9098
ABIArgInfo classifyArgumentType(CodeGenModule &CGM, CanQualType type)
Classify the rules for how to pass a particular type.
@ Decl
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
Definition CGValue.h:145
CGCXXABI::RecordArgABI getRecordArgABI(const RecordType *RT, CGCXXABI &CXXABI)
bool classifyReturnType(const CGCXXABI &CXXABI, CGFunctionInfo &FI, const ABIInfo &Info)
std::unique_ptr< TargetCodeGenInfo > createHexagonTargetCodeGenInfo(CodeGenModule &CGM)
Definition Hexagon.cpp:420
bool isAggregateTypeForABI(QualType T)
bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays, bool AsIfNoUniqueAddr=false)
isEmptyRecord - Return true iff a structure contains only empty fields.
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T
unsigned long uint64_t
llvm::IntegerType * Int8Ty
i8, i16, i32, and i64