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