xref: /freebsd/contrib/llvm-project/clang/lib/CodeGen/Targets/Hexagon.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
12 using namespace clang;
13 using namespace clang::CodeGen;
14 
15 //===----------------------------------------------------------------------===//
16 // Hexagon ABI Implementation
17 //===----------------------------------------------------------------------===//
18 
19 namespace {
20 
21 class HexagonABIInfo : public DefaultABIInfo {
22 public:
HexagonABIInfo(CodeGenTypes & CGT)23   HexagonABIInfo(CodeGenTypes &CGT) : DefaultABIInfo(CGT) {}
24 
25 private:
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 
42 class HexagonTargetCodeGenInfo : public TargetCodeGenInfo {
43 public:
HexagonTargetCodeGenInfo(CodeGenTypes & CGT)44   HexagonTargetCodeGenInfo(CodeGenTypes &CGT)
45       : TargetCodeGenInfo(std::make_unique<HexagonABIInfo>(CGT)) {}
46 
getDwarfEHStackPointer(CodeGen::CodeGenModule & M) const47   int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override {
48     return 29;
49   }
50 
setTargetAttributes(const Decl * D,llvm::GlobalValue * GV,CodeGen::CodeGenModule & GCM) const51   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 
computeInfo(CGFunctionInfo & FI) const63 void HexagonABIInfo::computeInfo(CGFunctionInfo &FI) const {
64   unsigned RegsLeft = 6;
65   if (!getCXXABI().classifyReturnType(FI))
66     FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
67   for (auto &I : FI.arguments())
68     I.info = classifyArgumentType(I.type, &RegsLeft);
69 }
70 
HexagonAdjustRegsLeft(uint64_t Size,unsigned * RegsLeft)71 static 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 
classifyArgumentType(QualType Ty,unsigned * RegsLeft) const96 ABIArgInfo HexagonABIInfo::classifyArgumentType(QualType Ty,
97                                                 unsigned *RegsLeft) const {
98   if (!isAggregateTypeForABI(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(Ty);
104     if (Size <= 64)
105       HexagonAdjustRegsLeft(Size, RegsLeft);
106 
107     if (Size > 64 && Ty->isBitIntType())
108       return getNaturalAlignIndirect(Ty, /*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, RAA == CGCXXABI::RAA_DirectInMemory);
116 
117   // Ignore empty records.
118   if (isEmptyRecord(getContext(), Ty, true))
119     return ABIArgInfo::getIgnore();
120 
121   uint64_t Size = getContext().getTypeSize(Ty);
122   unsigned Align = getContext().getTypeAlign(Ty);
123 
124   if (Size > 64)
125     return getNaturalAlignIndirect(Ty, /*ByVal=*/true);
126 
127   if (HexagonAdjustRegsLeft(Size, RegsLeft))
128     Align = Size <= 32 ? 32 : 64;
129   if (Size <= Align) {
130     // Pass in the smallest viable integer type.
131     Size = llvm::bit_ceil(Size);
132     return ABIArgInfo::getDirect(llvm::Type::getIntNTy(getVMContext(), Size));
133   }
134   return DefaultABIInfo::classifyArgumentType(Ty);
135 }
136 
classifyReturnType(QualType RetTy) const137 ABIArgInfo HexagonABIInfo::classifyReturnType(QualType RetTy) const {
138   if (RetTy->isVoidType())
139     return ABIArgInfo::getIgnore();
140 
141   const TargetInfo &T = CGT.getTarget();
142   uint64_t Size = getContext().getTypeSize(RetTy);
143 
144   if (RetTy->getAs<VectorType>()) {
145     // HVX vectors are returned in vector registers or register pairs.
146     if (T.hasFeature("hvx")) {
147       assert(T.hasFeature("hvx-length64b") || T.hasFeature("hvx-length128b"));
148       uint64_t VecSize = T.hasFeature("hvx-length64b") ? 64*8 : 128*8;
149       if (Size == VecSize || Size == 2*VecSize)
150         return ABIArgInfo::getDirectInReg();
151     }
152     // Large vector types should be returned via memory.
153     if (Size > 64)
154       return getNaturalAlignIndirect(RetTy);
155   }
156 
157   if (!isAggregateTypeForABI(RetTy)) {
158     // Treat an enum type as its underlying type.
159     if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
160       RetTy = EnumTy->getDecl()->getIntegerType();
161 
162     if (Size > 64 && RetTy->isBitIntType())
163       return getNaturalAlignIndirect(RetTy, /*ByVal=*/false);
164 
165     return isPromotableIntegerTypeForABI(RetTy) ? ABIArgInfo::getExtend(RetTy)
166                                                 : ABIArgInfo::getDirect();
167   }
168 
169   if (isEmptyRecord(getContext(), RetTy, true))
170     return ABIArgInfo::getIgnore();
171 
172   // Aggregates <= 8 bytes are returned in registers, other aggregates
173   // are returned indirectly.
174   if (Size <= 64) {
175     // Return in the smallest viable integer type.
176     Size = llvm::bit_ceil(Size);
177     return ABIArgInfo::getDirect(llvm::Type::getIntNTy(getVMContext(), Size));
178   }
179   return getNaturalAlignIndirect(RetTy, /*ByVal=*/true);
180 }
181 
EmitVAArgFromMemory(CodeGenFunction & CGF,Address VAListAddr,QualType Ty) const182 Address HexagonABIInfo::EmitVAArgFromMemory(CodeGenFunction &CGF,
183                                             Address VAListAddr,
184                                             QualType Ty) const {
185   // Load the overflow area pointer.
186   Address __overflow_area_pointer_p =
187       CGF.Builder.CreateStructGEP(VAListAddr, 2, "__overflow_area_pointer_p");
188   llvm::Value *__overflow_area_pointer = CGF.Builder.CreateLoad(
189       __overflow_area_pointer_p, "__overflow_area_pointer");
190 
191   uint64_t Align = CGF.getContext().getTypeAlign(Ty) / 8;
192   if (Align > 4) {
193     // Alignment should be a power of 2.
194     assert((Align & (Align - 1)) == 0 && "Alignment is not power of 2!");
195 
196     // overflow_arg_area = (overflow_arg_area + align - 1) & -align;
197     llvm::Value *Offset = llvm::ConstantInt::get(CGF.Int64Ty, Align - 1);
198 
199     // Add offset to the current pointer to access the argument.
200     __overflow_area_pointer =
201         CGF.Builder.CreateGEP(CGF.Int8Ty, __overflow_area_pointer, Offset);
202     llvm::Value *AsInt =
203         CGF.Builder.CreatePtrToInt(__overflow_area_pointer, CGF.Int32Ty);
204 
205     // Create a mask which should be "AND"ed
206     // with (overflow_arg_area + align - 1)
207     llvm::Value *Mask = llvm::ConstantInt::get(CGF.Int32Ty, -(int)Align);
208     __overflow_area_pointer = CGF.Builder.CreateIntToPtr(
209         CGF.Builder.CreateAnd(AsInt, Mask), __overflow_area_pointer->getType(),
210         "__overflow_area_pointer.align");
211   }
212 
213   // Get the type of the argument from memory and bitcast
214   // overflow area pointer to the argument type.
215   llvm::Type *PTy = CGF.ConvertTypeForMem(Ty);
216   Address AddrTyped =
217       Address(__overflow_area_pointer, PTy, CharUnits::fromQuantity(Align));
218 
219   // Round up to the minimum stack alignment for varargs which is 4 bytes.
220   uint64_t Offset = llvm::alignTo(CGF.getContext().getTypeSize(Ty) / 8, 4);
221 
222   __overflow_area_pointer = CGF.Builder.CreateGEP(
223       CGF.Int8Ty, __overflow_area_pointer,
224       llvm::ConstantInt::get(CGF.Int32Ty, Offset),
225       "__overflow_area_pointer.next");
226   CGF.Builder.CreateStore(__overflow_area_pointer, __overflow_area_pointer_p);
227 
228   return AddrTyped;
229 }
230 
EmitVAArgForHexagon(CodeGenFunction & CGF,Address VAListAddr,QualType Ty) const231 Address HexagonABIInfo::EmitVAArgForHexagon(CodeGenFunction &CGF,
232                                             Address VAListAddr,
233                                             QualType Ty) const {
234   // FIXME: Need to handle alignment
235   llvm::Type *BP = CGF.Int8PtrTy;
236   CGBuilderTy &Builder = CGF.Builder;
237   Address VAListAddrAsBPP = VAListAddr.withElementType(BP);
238   llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur");
239   // Handle address alignment for type alignment > 32 bits
240   uint64_t TyAlign = CGF.getContext().getTypeAlign(Ty) / 8;
241   if (TyAlign > 4) {
242     assert((TyAlign & (TyAlign - 1)) == 0 && "Alignment is not power of 2!");
243     llvm::Value *AddrAsInt = Builder.CreatePtrToInt(Addr, CGF.Int32Ty);
244     AddrAsInt = Builder.CreateAdd(AddrAsInt, Builder.getInt32(TyAlign - 1));
245     AddrAsInt = Builder.CreateAnd(AddrAsInt, Builder.getInt32(~(TyAlign - 1)));
246     Addr = Builder.CreateIntToPtr(AddrAsInt, BP);
247   }
248   Address AddrTyped =
249       Address(Addr, CGF.ConvertType(Ty), CharUnits::fromQuantity(TyAlign));
250 
251   uint64_t Offset = llvm::alignTo(CGF.getContext().getTypeSize(Ty) / 8, 4);
252   llvm::Value *NextAddr = Builder.CreateGEP(
253       CGF.Int8Ty, Addr, llvm::ConstantInt::get(CGF.Int32Ty, Offset), "ap.next");
254   Builder.CreateStore(NextAddr, VAListAddrAsBPP);
255 
256   return AddrTyped;
257 }
258 
EmitVAArgForHexagonLinux(CodeGenFunction & CGF,Address VAListAddr,QualType Ty) const259 Address HexagonABIInfo::EmitVAArgForHexagonLinux(CodeGenFunction &CGF,
260                                                  Address VAListAddr,
261                                                  QualType Ty) const {
262   int ArgSize = CGF.getContext().getTypeSize(Ty) / 8;
263 
264   if (ArgSize > 8)
265     return EmitVAArgFromMemory(CGF, VAListAddr, Ty);
266 
267   // Here we have check if the argument is in register area or
268   // in overflow area.
269   // If the saved register area pointer + argsize rounded up to alignment >
270   // saved register area end pointer, argument is in overflow area.
271   unsigned RegsLeft = 6;
272   Ty = CGF.getContext().getCanonicalType(Ty);
273   (void)classifyArgumentType(Ty, &RegsLeft);
274 
275   llvm::BasicBlock *MaybeRegBlock = CGF.createBasicBlock("vaarg.maybe_reg");
276   llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg");
277   llvm::BasicBlock *OnStackBlock = CGF.createBasicBlock("vaarg.on_stack");
278   llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end");
279 
280   // Get rounded size of the argument.GCC does not allow vararg of
281   // size < 4 bytes. We follow the same logic here.
282   ArgSize = (CGF.getContext().getTypeSize(Ty) <= 32) ? 4 : 8;
283   int ArgAlign = (CGF.getContext().getTypeSize(Ty) <= 32) ? 4 : 8;
284 
285   // Argument may be in saved register area
286   CGF.EmitBlock(MaybeRegBlock);
287 
288   // Load the current saved register area pointer.
289   Address __current_saved_reg_area_pointer_p = CGF.Builder.CreateStructGEP(
290       VAListAddr, 0, "__current_saved_reg_area_pointer_p");
291   llvm::Value *__current_saved_reg_area_pointer = CGF.Builder.CreateLoad(
292       __current_saved_reg_area_pointer_p, "__current_saved_reg_area_pointer");
293 
294   // Load the saved register area end pointer.
295   Address __saved_reg_area_end_pointer_p = CGF.Builder.CreateStructGEP(
296       VAListAddr, 1, "__saved_reg_area_end_pointer_p");
297   llvm::Value *__saved_reg_area_end_pointer = CGF.Builder.CreateLoad(
298       __saved_reg_area_end_pointer_p, "__saved_reg_area_end_pointer");
299 
300   // If the size of argument is > 4 bytes, check if the stack
301   // location is aligned to 8 bytes
302   if (ArgAlign > 4) {
303 
304     llvm::Value *__current_saved_reg_area_pointer_int =
305         CGF.Builder.CreatePtrToInt(__current_saved_reg_area_pointer,
306                                    CGF.Int32Ty);
307 
308     __current_saved_reg_area_pointer_int = CGF.Builder.CreateAdd(
309         __current_saved_reg_area_pointer_int,
310         llvm::ConstantInt::get(CGF.Int32Ty, (ArgAlign - 1)),
311         "align_current_saved_reg_area_pointer");
312 
313     __current_saved_reg_area_pointer_int =
314         CGF.Builder.CreateAnd(__current_saved_reg_area_pointer_int,
315                               llvm::ConstantInt::get(CGF.Int32Ty, -ArgAlign),
316                               "align_current_saved_reg_area_pointer");
317 
318     __current_saved_reg_area_pointer =
319         CGF.Builder.CreateIntToPtr(__current_saved_reg_area_pointer_int,
320                                    __current_saved_reg_area_pointer->getType(),
321                                    "align_current_saved_reg_area_pointer");
322   }
323 
324   llvm::Value *__new_saved_reg_area_pointer =
325       CGF.Builder.CreateGEP(CGF.Int8Ty, __current_saved_reg_area_pointer,
326                             llvm::ConstantInt::get(CGF.Int32Ty, ArgSize),
327                             "__new_saved_reg_area_pointer");
328 
329   llvm::Value *UsingStack = nullptr;
330   UsingStack = CGF.Builder.CreateICmpSGT(__new_saved_reg_area_pointer,
331                                          __saved_reg_area_end_pointer);
332 
333   CGF.Builder.CreateCondBr(UsingStack, OnStackBlock, InRegBlock);
334 
335   // Argument in saved register area
336   // Implement the block where argument is in register saved area
337   CGF.EmitBlock(InRegBlock);
338 
339   llvm::Type *PTy = CGF.ConvertType(Ty);
340   llvm::Value *__saved_reg_area_p = CGF.Builder.CreateBitCast(
341       __current_saved_reg_area_pointer, llvm::PointerType::getUnqual(PTy));
342 
343   CGF.Builder.CreateStore(__new_saved_reg_area_pointer,
344                           __current_saved_reg_area_pointer_p);
345 
346   CGF.EmitBranch(ContBlock);
347 
348   // Argument in overflow area
349   // Implement the block where the argument is in overflow area.
350   CGF.EmitBlock(OnStackBlock);
351 
352   // Load the overflow area pointer
353   Address __overflow_area_pointer_p =
354       CGF.Builder.CreateStructGEP(VAListAddr, 2, "__overflow_area_pointer_p");
355   llvm::Value *__overflow_area_pointer = CGF.Builder.CreateLoad(
356       __overflow_area_pointer_p, "__overflow_area_pointer");
357 
358   // Align the overflow area pointer according to the alignment of the argument
359   if (ArgAlign > 4) {
360     llvm::Value *__overflow_area_pointer_int =
361         CGF.Builder.CreatePtrToInt(__overflow_area_pointer, CGF.Int32Ty);
362 
363     __overflow_area_pointer_int =
364         CGF.Builder.CreateAdd(__overflow_area_pointer_int,
365                               llvm::ConstantInt::get(CGF.Int32Ty, ArgAlign - 1),
366                               "align_overflow_area_pointer");
367 
368     __overflow_area_pointer_int =
369         CGF.Builder.CreateAnd(__overflow_area_pointer_int,
370                               llvm::ConstantInt::get(CGF.Int32Ty, -ArgAlign),
371                               "align_overflow_area_pointer");
372 
373     __overflow_area_pointer = CGF.Builder.CreateIntToPtr(
374         __overflow_area_pointer_int, __overflow_area_pointer->getType(),
375         "align_overflow_area_pointer");
376   }
377 
378   // Get the pointer for next argument in overflow area and store it
379   // to overflow area pointer.
380   llvm::Value *__new_overflow_area_pointer = CGF.Builder.CreateGEP(
381       CGF.Int8Ty, __overflow_area_pointer,
382       llvm::ConstantInt::get(CGF.Int32Ty, ArgSize),
383       "__overflow_area_pointer.next");
384 
385   CGF.Builder.CreateStore(__new_overflow_area_pointer,
386                           __overflow_area_pointer_p);
387 
388   CGF.Builder.CreateStore(__new_overflow_area_pointer,
389                           __current_saved_reg_area_pointer_p);
390 
391   // Bitcast the overflow area pointer to the type of argument.
392   llvm::Type *OverflowPTy = CGF.ConvertTypeForMem(Ty);
393   llvm::Value *__overflow_area_p = CGF.Builder.CreateBitCast(
394       __overflow_area_pointer, llvm::PointerType::getUnqual(OverflowPTy));
395 
396   CGF.EmitBranch(ContBlock);
397 
398   // Get the correct pointer to load the variable argument
399   // Implement the ContBlock
400   CGF.EmitBlock(ContBlock);
401 
402   llvm::Type *MemTy = CGF.ConvertTypeForMem(Ty);
403   llvm::Type *MemPTy = llvm::PointerType::getUnqual(MemTy);
404   llvm::PHINode *ArgAddr = CGF.Builder.CreatePHI(MemPTy, 2, "vaarg.addr");
405   ArgAddr->addIncoming(__saved_reg_area_p, InRegBlock);
406   ArgAddr->addIncoming(__overflow_area_p, OnStackBlock);
407 
408   return Address(ArgAddr, MemTy, CharUnits::fromQuantity(ArgAlign));
409 }
410 
EmitVAArg(CodeGenFunction & CGF,Address VAListAddr,QualType Ty,AggValueSlot Slot) const411 RValue HexagonABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
412                                  QualType Ty, AggValueSlot Slot) const {
413 
414   if (getTarget().getTriple().isMusl())
415     return CGF.EmitLoadOfAnyValue(
416         CGF.MakeAddrLValue(EmitVAArgForHexagonLinux(CGF, VAListAddr, Ty), Ty),
417         Slot);
418 
419   return CGF.EmitLoadOfAnyValue(
420       CGF.MakeAddrLValue(EmitVAArgForHexagon(CGF, VAListAddr, Ty), Ty), Slot);
421 }
422 
423 std::unique_ptr<TargetCodeGenInfo>
createHexagonTargetCodeGenInfo(CodeGenModule & CGM)424 CodeGen::createHexagonTargetCodeGenInfo(CodeGenModule &CGM) {
425   return std::make_unique<HexagonTargetCodeGenInfo>(CGM.getTypes());
426 }
427