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>(args&: 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>(Val: 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))
66 FI.getReturnInfo() = classifyReturnType(RetTy: FI.getReturnType());
67 for (auto &I : FI.arguments())
68 I.info = classifyArgumentType(RetTy: I.type, RegsLeft: &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(T: Ty)) {
99 // Treat an enum type as its underlying type.
100 if (const EnumType *EnumTy = Ty->getAs<EnumType>())
101 Ty = EnumTy->getDecl()->getIntegerType();
102
103 uint64_t Size = getContext().getTypeSize(T: Ty);
104 if (Size <= 64)
105 HexagonAdjustRegsLeft(Size, RegsLeft);
106
107 if (Size > 64 && Ty->isBitIntType())
108 return getNaturalAlignIndirect(Ty, AddrSpace: getDataLayout().getAllocaAddrSpace(),
109 /*ByVal=*/true);
110
111 return isPromotableIntegerTypeForABI(Ty) ? ABIArgInfo::getExtend(Ty)
112 : ABIArgInfo::getDirect();
113 }
114
115 if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(T: Ty, CXXABI&: getCXXABI()))
116 return getNaturalAlignIndirect(Ty, AddrSpace: getDataLayout().getAllocaAddrSpace(),
117 ByVal: RAA == CGCXXABI::RAA_DirectInMemory);
118
119 // Ignore empty records.
120 if (isEmptyRecord(Context&: getContext(), T: Ty, AllowArrays: true))
121 return ABIArgInfo::getIgnore();
122
123 uint64_t Size = getContext().getTypeSize(T: Ty);
124 unsigned Align = getContext().getTypeAlign(T: Ty);
125
126 if (Size > 64)
127 return getNaturalAlignIndirect(Ty, AddrSpace: 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(Value: Size);
135 return ABIArgInfo::getDirect(T: llvm::Type::getIntNTy(C&: getVMContext(), N: Size));
136 }
137 return DefaultABIInfo::classifyArgumentType(RetTy: Ty);
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(T: RetTy);
146
147 if (RetTy->getAs<VectorType>()) {
148 // HVX vectors are returned in vector registers or register pairs.
149 if (T.hasFeature(Feature: "hvx")) {
150 assert(T.hasFeature("hvx-length64b") || T.hasFeature("hvx-length128b"));
151 uint64_t VecSize = T.hasFeature(Feature: "hvx-length64b") ? 64*8 : 128*8;
152 if (Size == VecSize || Size == 2*VecSize)
153 return ABIArgInfo::getDirectInReg();
154 }
155 // Large vector types should be returned via memory.
156 if (Size > 64)
157 return getNaturalAlignIndirect(Ty: RetTy,
158 AddrSpace: getDataLayout().getAllocaAddrSpace());
159 }
160
161 if (!isAggregateTypeForABI(T: RetTy)) {
162 // Treat an enum type as its underlying type.
163 if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
164 RetTy = EnumTy->getDecl()->getIntegerType();
165
166 if (Size > 64 && RetTy->isBitIntType())
167 return getNaturalAlignIndirect(
168 Ty: RetTy, AddrSpace: getDataLayout().getAllocaAddrSpace(), /*ByVal=*/false);
169
170 return isPromotableIntegerTypeForABI(Ty: RetTy) ? ABIArgInfo::getExtend(Ty: RetTy)
171 : ABIArgInfo::getDirect();
172 }
173
174 if (isEmptyRecord(Context&: getContext(), T: RetTy, AllowArrays: 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(Value: Size);
182 return ABIArgInfo::getDirect(T: llvm::Type::getIntNTy(C&: getVMContext(), N: Size));
183 }
184 return getNaturalAlignIndirect(Ty: RetTy, AddrSpace: 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(Addr: VAListAddr, Index: 2, Name: "__overflow_area_pointer_p");
194 llvm::Value *__overflow_area_pointer = CGF.Builder.CreateLoad(
195 Addr: __overflow_area_pointer_p, Name: "__overflow_area_pointer");
196
197 uint64_t Align = CGF.getContext().getTypeAlign(T: 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(Ty: CGF.Int64Ty, V: Align - 1);
204
205 // Add offset to the current pointer to access the argument.
206 __overflow_area_pointer =
207 CGF.Builder.CreateGEP(Ty: CGF.Int8Ty, Ptr: __overflow_area_pointer, IdxList: Offset);
208 llvm::Value *AsInt =
209 CGF.Builder.CreatePtrToInt(V: __overflow_area_pointer, DestTy: 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(Ty: CGF.Int32Ty, V: -(int)Align);
214 __overflow_area_pointer = CGF.Builder.CreateIntToPtr(
215 V: CGF.Builder.CreateAnd(LHS: AsInt, RHS: Mask), DestTy: __overflow_area_pointer->getType(),
216 Name: "__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(T: Ty);
222 Address AddrTyped =
223 Address(__overflow_area_pointer, PTy, CharUnits::fromQuantity(Quantity: Align));
224
225 // Round up to the minimum stack alignment for varargs which is 4 bytes.
226 uint64_t Offset = llvm::alignTo(Value: CGF.getContext().getTypeSize(T: Ty) / 8, Align: 4);
227
228 __overflow_area_pointer = CGF.Builder.CreateGEP(
229 Ty: CGF.Int8Ty, Ptr: __overflow_area_pointer,
230 IdxList: llvm::ConstantInt::get(Ty: CGF.Int32Ty, V: Offset),
231 Name: "__overflow_area_pointer.next");
232 CGF.Builder.CreateStore(Val: __overflow_area_pointer, Addr: __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(ElemTy: BP);
244 llvm::Value *Addr = Builder.CreateLoad(Addr: VAListAddrAsBPP, Name: "ap.cur");
245 // Handle address alignment for type alignment > 32 bits
246 uint64_t TyAlign = CGF.getContext().getTypeAlign(T: Ty) / 8;
247 if (TyAlign > 4) {
248 assert((TyAlign & (TyAlign - 1)) == 0 && "Alignment is not power of 2!");
249 llvm::Value *AddrAsInt = Builder.CreatePtrToInt(V: Addr, DestTy: CGF.Int32Ty);
250 AddrAsInt = Builder.CreateAdd(LHS: AddrAsInt, RHS: Builder.getInt32(C: TyAlign - 1));
251 AddrAsInt = Builder.CreateAnd(LHS: AddrAsInt, RHS: Builder.getInt32(C: ~(TyAlign - 1)));
252 Addr = Builder.CreateIntToPtr(V: AddrAsInt, DestTy: BP);
253 }
254 Address AddrTyped =
255 Address(Addr, CGF.ConvertType(T: Ty), CharUnits::fromQuantity(Quantity: TyAlign));
256
257 uint64_t Offset = llvm::alignTo(Value: CGF.getContext().getTypeSize(T: Ty) / 8, Align: 4);
258 llvm::Value *NextAddr = Builder.CreateGEP(
259 Ty: CGF.Int8Ty, Ptr: Addr, IdxList: llvm::ConstantInt::get(Ty: CGF.Int32Ty, V: Offset), Name: "ap.next");
260 Builder.CreateStore(Val: NextAddr, Addr: 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(T: 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(T: Ty);
279 (void)classifyArgumentType(Ty, RegsLeft: &RegsLeft);
280
281 llvm::BasicBlock *MaybeRegBlock = CGF.createBasicBlock(name: "vaarg.maybe_reg");
282 llvm::BasicBlock *InRegBlock = CGF.createBasicBlock(name: "vaarg.in_reg");
283 llvm::BasicBlock *OnStackBlock = CGF.createBasicBlock(name: "vaarg.on_stack");
284 llvm::BasicBlock *ContBlock = CGF.createBasicBlock(name: "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(T: Ty) <= 32) ? 4 : 8;
289 int ArgAlign = (CGF.getContext().getTypeSize(T: Ty) <= 32) ? 4 : 8;
290
291 // Argument may be in saved register area
292 CGF.EmitBlock(BB: MaybeRegBlock);
293
294 // Load the current saved register area pointer.
295 Address __current_saved_reg_area_pointer_p = CGF.Builder.CreateStructGEP(
296 Addr: VAListAddr, Index: 0, Name: "__current_saved_reg_area_pointer_p");
297 llvm::Value *__current_saved_reg_area_pointer = CGF.Builder.CreateLoad(
298 Addr: __current_saved_reg_area_pointer_p, Name: "__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 Addr: VAListAddr, Index: 1, Name: "__saved_reg_area_end_pointer_p");
303 llvm::Value *__saved_reg_area_end_pointer = CGF.Builder.CreateLoad(
304 Addr: __saved_reg_area_end_pointer_p, Name: "__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(V: __current_saved_reg_area_pointer,
312 DestTy: CGF.Int32Ty);
313
314 __current_saved_reg_area_pointer_int = CGF.Builder.CreateAdd(
315 LHS: __current_saved_reg_area_pointer_int,
316 RHS: llvm::ConstantInt::get(Ty: CGF.Int32Ty, V: (ArgAlign - 1)),
317 Name: "align_current_saved_reg_area_pointer");
318
319 __current_saved_reg_area_pointer_int =
320 CGF.Builder.CreateAnd(LHS: __current_saved_reg_area_pointer_int,
321 RHS: llvm::ConstantInt::get(Ty: CGF.Int32Ty, V: -ArgAlign),
322 Name: "align_current_saved_reg_area_pointer");
323
324 __current_saved_reg_area_pointer =
325 CGF.Builder.CreateIntToPtr(V: __current_saved_reg_area_pointer_int,
326 DestTy: __current_saved_reg_area_pointer->getType(),
327 Name: "align_current_saved_reg_area_pointer");
328 }
329
330 llvm::Value *__new_saved_reg_area_pointer =
331 CGF.Builder.CreateGEP(Ty: CGF.Int8Ty, Ptr: __current_saved_reg_area_pointer,
332 IdxList: llvm::ConstantInt::get(Ty: CGF.Int32Ty, V: ArgSize),
333 Name: "__new_saved_reg_area_pointer");
334
335 llvm::Value *UsingStack = nullptr;
336 UsingStack = CGF.Builder.CreateICmpSGT(LHS: __new_saved_reg_area_pointer,
337 RHS: __saved_reg_area_end_pointer);
338
339 CGF.Builder.CreateCondBr(Cond: UsingStack, True: OnStackBlock, False: InRegBlock);
340
341 // Argument in saved register area
342 // Implement the block where argument is in register saved area
343 CGF.EmitBlock(BB: InRegBlock);
344
345 CGF.Builder.CreateStore(Val: __new_saved_reg_area_pointer,
346 Addr: __current_saved_reg_area_pointer_p);
347
348 CGF.EmitBranch(Block: ContBlock);
349
350 // Argument in overflow area
351 // Implement the block where the argument is in overflow area.
352 CGF.EmitBlock(BB: OnStackBlock);
353
354 // Load the overflow area pointer
355 Address __overflow_area_pointer_p =
356 CGF.Builder.CreateStructGEP(Addr: VAListAddr, Index: 2, Name: "__overflow_area_pointer_p");
357 llvm::Value *__overflow_area_pointer = CGF.Builder.CreateLoad(
358 Addr: __overflow_area_pointer_p, Name: "__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(V: __overflow_area_pointer, DestTy: CGF.Int32Ty);
364
365 __overflow_area_pointer_int =
366 CGF.Builder.CreateAdd(LHS: __overflow_area_pointer_int,
367 RHS: llvm::ConstantInt::get(Ty: CGF.Int32Ty, V: ArgAlign - 1),
368 Name: "align_overflow_area_pointer");
369
370 __overflow_area_pointer_int =
371 CGF.Builder.CreateAnd(LHS: __overflow_area_pointer_int,
372 RHS: llvm::ConstantInt::get(Ty: CGF.Int32Ty, V: -ArgAlign),
373 Name: "align_overflow_area_pointer");
374
375 __overflow_area_pointer = CGF.Builder.CreateIntToPtr(
376 V: __overflow_area_pointer_int, DestTy: __overflow_area_pointer->getType(),
377 Name: "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 Ty: CGF.Int8Ty, Ptr: __overflow_area_pointer,
384 IdxList: llvm::ConstantInt::get(Ty: CGF.Int32Ty, V: ArgSize),
385 Name: "__overflow_area_pointer.next");
386
387 CGF.Builder.CreateStore(Val: __new_overflow_area_pointer,
388 Addr: __overflow_area_pointer_p);
389
390 CGF.Builder.CreateStore(Val: __new_overflow_area_pointer,
391 Addr: __current_saved_reg_area_pointer_p);
392
393 CGF.EmitBranch(Block: ContBlock);
394 // Get the correct pointer to load the variable argument
395 // Implement the ContBlock
396 CGF.EmitBlock(BB: ContBlock);
397
398 llvm::Type *MemTy = CGF.ConvertTypeForMem(T: Ty);
399 llvm::PHINode *ArgAddr = CGF.Builder.CreatePHI(
400 Ty: llvm::PointerType::getUnqual(C&: MemTy->getContext()), NumReservedValues: 2, Name: "vaarg.addr");
401 ArgAddr->addIncoming(V: __current_saved_reg_area_pointer, BB: InRegBlock);
402 ArgAddr->addIncoming(V: __overflow_area_pointer, BB: OnStackBlock);
403
404 return Address(ArgAddr, MemTy, CharUnits::fromQuantity(Quantity: 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 V: CGF.MakeAddrLValue(Addr: EmitVAArgForHexagonLinux(CGF, VAListAddr, Ty), T: Ty),
413 Slot);
414
415 return CGF.EmitLoadOfAnyValue(
416 V: CGF.MakeAddrLValue(Addr: EmitVAArgForHexagon(CGF, VAListAddr, Ty), T: Ty), Slot);
417}
418
419std::unique_ptr<TargetCodeGenInfo>
420CodeGen::createHexagonTargetCodeGenInfo(CodeGenModule &CGM) {
421 return std::make_unique<HexagonTargetCodeGenInfo>(args&: CGM.getTypes());
422}
423