1//===- ARC.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// ARC ABI implementation.
16namespace {
17
18class ARCABIInfo : public DefaultABIInfo {
19 struct CCState {
20 unsigned FreeRegs;
21 };
22
23public:
24 using DefaultABIInfo::DefaultABIInfo;
25
26private:
27 RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
28 AggValueSlot Slot) const override;
29
30 void updateState(const ABIArgInfo &Info, QualType Ty, CCState &State) const {
31 if (!State.FreeRegs)
32 return;
33 if (Info.isIndirect() && Info.getInReg())
34 State.FreeRegs--;
35 else if (Info.isDirect() && Info.getInReg()) {
36 unsigned sz = (getContext().getTypeSize(T: Ty) + 31) / 32;
37 if (sz < State.FreeRegs)
38 State.FreeRegs -= sz;
39 else
40 State.FreeRegs = 0;
41 }
42 }
43
44 void computeInfo(CGFunctionInfo &FI) const override {
45 CCState State;
46 // ARC uses 8 registers to pass arguments.
47 State.FreeRegs = 8;
48
49 if (!getCXXABI().classifyReturnType(FI))
50 FI.getReturnInfo() = classifyReturnType(RetTy: FI.getReturnType());
51 updateState(Info: FI.getReturnInfo(), Ty: FI.getReturnType(), State);
52 for (auto &I : FI.arguments()) {
53 I.info = classifyArgumentType(Ty: I.type, FreeRegs: State.FreeRegs);
54 updateState(Info: I.info, Ty: I.type, State);
55 }
56 }
57
58 ABIArgInfo getIndirectByRef(QualType Ty, bool HasFreeRegs) const;
59 ABIArgInfo getIndirectByValue(QualType Ty) const;
60 ABIArgInfo classifyArgumentType(QualType Ty, uint8_t FreeRegs) const;
61 ABIArgInfo classifyReturnType(QualType RetTy) const;
62};
63
64class ARCTargetCodeGenInfo : public TargetCodeGenInfo {
65public:
66 ARCTargetCodeGenInfo(CodeGenTypes &CGT)
67 : TargetCodeGenInfo(std::make_unique<ARCABIInfo>(args&: CGT)) {}
68};
69
70
71ABIArgInfo ARCABIInfo::getIndirectByRef(QualType Ty, bool HasFreeRegs) const {
72 return HasFreeRegs ? getNaturalAlignIndirectInReg(Ty) :
73 getNaturalAlignIndirect(Ty, ByVal: false);
74}
75
76ABIArgInfo ARCABIInfo::getIndirectByValue(QualType Ty) const {
77 // Compute the byval alignment.
78 const unsigned MinABIStackAlignInBytes = 4;
79 unsigned TypeAlign = getContext().getTypeAlign(T: Ty) / 8;
80 return ABIArgInfo::getIndirect(Alignment: CharUnits::fromQuantity(Quantity: 4), /*ByVal=*/true,
81 Realign: TypeAlign > MinABIStackAlignInBytes);
82}
83
84RValue ARCABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
85 QualType Ty, AggValueSlot Slot) const {
86 return emitVoidPtrVAArg(CGF, VAListAddr, ValueTy: Ty, /*indirect*/ IsIndirect: false,
87 ValueInfo: getContext().getTypeInfoInChars(T: Ty),
88 SlotSizeAndAlign: CharUnits::fromQuantity(Quantity: 4), AllowHigherAlign: true, Slot);
89}
90
91ABIArgInfo ARCABIInfo::classifyArgumentType(QualType Ty,
92 uint8_t FreeRegs) const {
93 // Handle the generic C++ ABI.
94 const RecordType *RT = Ty->getAs<RecordType>();
95 if (RT) {
96 CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, CXXABI&: getCXXABI());
97 if (RAA == CGCXXABI::RAA_Indirect)
98 return getIndirectByRef(Ty, HasFreeRegs: FreeRegs > 0);
99
100 if (RAA == CGCXXABI::RAA_DirectInMemory)
101 return getIndirectByValue(Ty);
102 }
103
104 // Treat an enum type as its underlying type.
105 if (const EnumType *EnumTy = Ty->getAs<EnumType>())
106 Ty = EnumTy->getDecl()->getIntegerType();
107
108 auto SizeInRegs = llvm::alignTo(Value: getContext().getTypeSize(T: Ty), Align: 32) / 32;
109
110 if (isAggregateTypeForABI(T: Ty)) {
111 // Structures with flexible arrays are always indirect.
112 if (RT && RT->getDecl()->hasFlexibleArrayMember())
113 return getIndirectByValue(Ty);
114
115 // Ignore empty structs/unions.
116 if (isEmptyRecord(Context&: getContext(), T: Ty, AllowArrays: true))
117 return ABIArgInfo::getIgnore();
118
119 llvm::LLVMContext &LLVMContext = getVMContext();
120
121 llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(C&: LLVMContext);
122 SmallVector<llvm::Type *, 3> Elements(SizeInRegs, Int32);
123 llvm::Type *Result = llvm::StructType::get(Context&: LLVMContext, Elements);
124
125 return FreeRegs >= SizeInRegs ?
126 ABIArgInfo::getDirectInReg(T: Result) :
127 ABIArgInfo::getDirect(T: Result, Offset: 0, Padding: nullptr, CanBeFlattened: false);
128 }
129
130 if (const auto *EIT = Ty->getAs<BitIntType>())
131 if (EIT->getNumBits() > 64)
132 return getIndirectByValue(Ty);
133
134 return isPromotableIntegerTypeForABI(Ty)
135 ? (FreeRegs >= SizeInRegs ? ABIArgInfo::getExtendInReg(Ty)
136 : ABIArgInfo::getExtend(Ty))
137 : (FreeRegs >= SizeInRegs ? ABIArgInfo::getDirectInReg()
138 : ABIArgInfo::getDirect());
139}
140
141ABIArgInfo ARCABIInfo::classifyReturnType(QualType RetTy) const {
142 if (RetTy->isAnyComplexType())
143 return ABIArgInfo::getDirectInReg();
144
145 // Arguments of size > 4 registers are indirect.
146 auto RetSize = llvm::alignTo(Value: getContext().getTypeSize(T: RetTy), Align: 32) / 32;
147 if (RetSize > 4)
148 return getIndirectByRef(Ty: RetTy, /*HasFreeRegs*/ true);
149
150 return DefaultABIInfo::classifyReturnType(RetTy);
151}
152
153} // End anonymous namespace.
154
155std::unique_ptr<TargetCodeGenInfo>
156CodeGen::createARCTargetCodeGenInfo(CodeGenModule &CGM) {
157 return std::make_unique<ARCTargetCodeGenInfo>(args&: CGM.getTypes());
158}
159