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