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( |
74 | Ty, AddrSpace: getDataLayout().getAllocaAddrSpace(), ByVal: false); |
75 | } |
76 | |
77 | ABIArgInfo ARCABIInfo::getIndirectByValue(QualType Ty) const { |
78 | // Compute the byval alignment. |
79 | const unsigned MinABIStackAlignInBytes = 4; |
80 | unsigned TypeAlign = getContext().getTypeAlign(T: Ty) / 8; |
81 | return ABIArgInfo::getIndirect( |
82 | Alignment: CharUnits::fromQuantity(Quantity: 4), |
83 | /*AddrSpace=*/getDataLayout().getAllocaAddrSpace(), |
84 | /*ByVal=*/true, Realign: TypeAlign > MinABIStackAlignInBytes); |
85 | } |
86 | |
87 | RValue ARCABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, |
88 | QualType Ty, AggValueSlot Slot) const { |
89 | return emitVoidPtrVAArg(CGF, VAListAddr, ValueTy: Ty, /*indirect*/ IsIndirect: false, |
90 | ValueInfo: getContext().getTypeInfoInChars(T: Ty), |
91 | SlotSizeAndAlign: CharUnits::fromQuantity(Quantity: 4), AllowHigherAlign: true, Slot); |
92 | } |
93 | |
94 | ABIArgInfo ARCABIInfo::classifyArgumentType(QualType Ty, |
95 | uint8_t FreeRegs) const { |
96 | // Handle the generic C++ ABI. |
97 | const RecordType *RT = Ty->getAs<RecordType>(); |
98 | if (RT) { |
99 | CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, CXXABI&: getCXXABI()); |
100 | if (RAA == CGCXXABI::RAA_Indirect) |
101 | return getIndirectByRef(Ty, HasFreeRegs: FreeRegs > 0); |
102 | |
103 | if (RAA == CGCXXABI::RAA_DirectInMemory) |
104 | return getIndirectByValue(Ty); |
105 | } |
106 | |
107 | // Treat an enum type as its underlying type. |
108 | if (const EnumType *EnumTy = Ty->getAs<EnumType>()) |
109 | Ty = EnumTy->getDecl()->getIntegerType(); |
110 | |
111 | auto SizeInRegs = llvm::alignTo(Value: getContext().getTypeSize(T: Ty), Align: 32) / 32; |
112 | |
113 | if (isAggregateTypeForABI(T: Ty)) { |
114 | // Structures with flexible arrays are always indirect. |
115 | if (RT && RT->getDecl()->hasFlexibleArrayMember()) |
116 | return getIndirectByValue(Ty); |
117 | |
118 | // Ignore empty structs/unions. |
119 | if (isEmptyRecord(Context&: getContext(), T: Ty, AllowArrays: true)) |
120 | return ABIArgInfo::getIgnore(); |
121 | |
122 | llvm::LLVMContext &LLVMContext = getVMContext(); |
123 | |
124 | llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(C&: LLVMContext); |
125 | SmallVector<llvm::Type *, 3> Elements(SizeInRegs, Int32); |
126 | llvm::Type *Result = llvm::StructType::get(Context&: LLVMContext, Elements); |
127 | |
128 | return FreeRegs >= SizeInRegs ? |
129 | ABIArgInfo::getDirectInReg(T: Result) : |
130 | ABIArgInfo::getDirect(T: Result, Offset: 0, Padding: nullptr, CanBeFlattened: false); |
131 | } |
132 | |
133 | if (const auto *EIT = Ty->getAs<BitIntType>()) |
134 | if (EIT->getNumBits() > 64) |
135 | return getIndirectByValue(Ty); |
136 | |
137 | return isPromotableIntegerTypeForABI(Ty) |
138 | ? (FreeRegs >= SizeInRegs ? ABIArgInfo::getExtendInReg(Ty) |
139 | : ABIArgInfo::getExtend(Ty)) |
140 | : (FreeRegs >= SizeInRegs ? ABIArgInfo::getDirectInReg() |
141 | : ABIArgInfo::getDirect()); |
142 | } |
143 | |
144 | ABIArgInfo ARCABIInfo::classifyReturnType(QualType RetTy) const { |
145 | if (RetTy->isAnyComplexType()) |
146 | return ABIArgInfo::getDirectInReg(); |
147 | |
148 | // Arguments of size > 4 registers are indirect. |
149 | auto RetSize = llvm::alignTo(Value: getContext().getTypeSize(T: RetTy), Align: 32) / 32; |
150 | if (RetSize > 4) |
151 | return getIndirectByRef(Ty: RetTy, /*HasFreeRegs*/ true); |
152 | |
153 | return DefaultABIInfo::classifyReturnType(RetTy); |
154 | } |
155 | |
156 | } // End anonymous namespace. |
157 | |
158 | std::unique_ptr<TargetCodeGenInfo> |
159 | CodeGen::createARCTargetCodeGenInfo(CodeGenModule &CGM) { |
160 | return std::make_unique<ARCTargetCodeGenInfo>(args&: CGM.getTypes()); |
161 | } |
162 | |