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 | |
12 | using namespace clang; |
13 | using namespace clang::CodeGen; |
14 | |
15 | // ARC ABI implementation. |
16 | namespace { |
17 | |
18 | class ARCABIInfo : public DefaultABIInfo { |
19 | struct CCState { |
20 | unsigned FreeRegs; |
21 | }; |
22 | |
23 | public: |
24 | using DefaultABIInfo::DefaultABIInfo; |
25 | |
26 | private: |
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 | |
64 | class ARCTargetCodeGenInfo : public TargetCodeGenInfo { |
65 | public: |
66 | ARCTargetCodeGenInfo(CodeGenTypes &CGT) |
67 | : TargetCodeGenInfo(std::make_unique<ARCABIInfo>(args&: CGT)) {} |
68 | }; |
69 | |
70 | |
71 | ABIArgInfo ARCABIInfo::getIndirectByRef(QualType Ty, bool HasFreeRegs) const { |
72 | return HasFreeRegs ? getNaturalAlignIndirectInReg(Ty) : |
73 | getNaturalAlignIndirect(Ty, ByVal: false); |
74 | } |
75 | |
76 | ABIArgInfo 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 | |
84 | RValue 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 | |
91 | ABIArgInfo 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 | |
141 | ABIArgInfo 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 | |
155 | std::unique_ptr<TargetCodeGenInfo> |
156 | CodeGen::createARCTargetCodeGenInfo(CodeGenModule &CGM) { |
157 | return std::make_unique<ARCTargetCodeGenInfo>(args&: CGM.getTypes()); |
158 | } |
159 | |