1 | //===- Lanai.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 | // Lanai ABI Implementation |
17 | //===----------------------------------------------------------------------===// |
18 | |
19 | namespace { |
20 | class LanaiABIInfo : public DefaultABIInfo { |
21 | struct CCState { |
22 | unsigned FreeRegs; |
23 | }; |
24 | |
25 | public: |
26 | LanaiABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {} |
27 | |
28 | bool shouldUseInReg(QualType Ty, CCState &State) const; |
29 | |
30 | void computeInfo(CGFunctionInfo &FI) const override { |
31 | CCState State; |
32 | // Lanai uses 4 registers to pass arguments unless the function has the |
33 | // regparm attribute set. |
34 | if (FI.getHasRegParm()) { |
35 | State.FreeRegs = FI.getRegParm(); |
36 | } else { |
37 | State.FreeRegs = 4; |
38 | } |
39 | |
40 | if (!getCXXABI().classifyReturnType(FI)) |
41 | FI.getReturnInfo() = classifyReturnType(RetTy: FI.getReturnType()); |
42 | for (auto &I : FI.arguments()) |
43 | I.info = classifyArgumentType(RetTy: I.type, State); |
44 | } |
45 | |
46 | ABIArgInfo getIndirectResult(QualType Ty, bool ByVal, CCState &State) const; |
47 | ABIArgInfo classifyArgumentType(QualType RetTy, CCState &State) const; |
48 | }; |
49 | } // end anonymous namespace |
50 | |
51 | bool LanaiABIInfo::shouldUseInReg(QualType Ty, CCState &State) const { |
52 | unsigned Size = getContext().getTypeSize(T: Ty); |
53 | unsigned SizeInRegs = llvm::alignTo(Value: Size, Align: 32U) / 32U; |
54 | |
55 | if (SizeInRegs == 0) |
56 | return false; |
57 | |
58 | if (SizeInRegs > State.FreeRegs) { |
59 | State.FreeRegs = 0; |
60 | return false; |
61 | } |
62 | |
63 | State.FreeRegs -= SizeInRegs; |
64 | |
65 | return true; |
66 | } |
67 | |
68 | ABIArgInfo LanaiABIInfo::getIndirectResult(QualType Ty, bool ByVal, |
69 | CCState &State) const { |
70 | if (!ByVal) { |
71 | if (State.FreeRegs) { |
72 | --State.FreeRegs; // Non-byval indirects just use one pointer. |
73 | return getNaturalAlignIndirectInReg(Ty); |
74 | } |
75 | return getNaturalAlignIndirect(Ty, ByVal: false); |
76 | } |
77 | |
78 | // Compute the byval alignment. |
79 | const unsigned MinABIStackAlignInBytes = 4; |
80 | unsigned TypeAlign = getContext().getTypeAlign(T: Ty) / 8; |
81 | return ABIArgInfo::getIndirect(Alignment: CharUnits::fromQuantity(Quantity: 4), /*ByVal=*/true, |
82 | /*Realign=*/TypeAlign > |
83 | MinABIStackAlignInBytes); |
84 | } |
85 | |
86 | ABIArgInfo LanaiABIInfo::classifyArgumentType(QualType Ty, |
87 | CCState &State) const { |
88 | // Check with the C++ ABI first. |
89 | const RecordType *RT = Ty->getAs<RecordType>(); |
90 | if (RT) { |
91 | CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, CXXABI&: getCXXABI()); |
92 | if (RAA == CGCXXABI::RAA_Indirect) { |
93 | return getIndirectResult(Ty, /*ByVal=*/false, State); |
94 | } else if (RAA == CGCXXABI::RAA_DirectInMemory) { |
95 | return getNaturalAlignIndirect(Ty, /*ByVal=*/true); |
96 | } |
97 | } |
98 | |
99 | if (isAggregateTypeForABI(T: Ty)) { |
100 | // Structures with flexible arrays are always indirect. |
101 | if (RT && RT->getDecl()->hasFlexibleArrayMember()) |
102 | return getIndirectResult(Ty, /*ByVal=*/true, State); |
103 | |
104 | // Ignore empty structs/unions. |
105 | if (isEmptyRecord(Context&: getContext(), T: Ty, AllowArrays: true)) |
106 | return ABIArgInfo::getIgnore(); |
107 | |
108 | llvm::LLVMContext &LLVMContext = getVMContext(); |
109 | unsigned SizeInRegs = (getContext().getTypeSize(T: Ty) + 31) / 32; |
110 | if (SizeInRegs <= State.FreeRegs) { |
111 | llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(C&: LLVMContext); |
112 | SmallVector<llvm::Type *, 3> Elements(SizeInRegs, Int32); |
113 | llvm::Type *Result = llvm::StructType::get(Context&: LLVMContext, Elements); |
114 | State.FreeRegs -= SizeInRegs; |
115 | return ABIArgInfo::getDirectInReg(T: Result); |
116 | } else { |
117 | State.FreeRegs = 0; |
118 | } |
119 | return getIndirectResult(Ty, ByVal: true, State); |
120 | } |
121 | |
122 | // Treat an enum type as its underlying type. |
123 | if (const auto *EnumTy = Ty->getAs<EnumType>()) |
124 | Ty = EnumTy->getDecl()->getIntegerType(); |
125 | |
126 | bool InReg = shouldUseInReg(Ty, State); |
127 | |
128 | // Don't pass >64 bit integers in registers. |
129 | if (const auto *EIT = Ty->getAs<BitIntType>()) |
130 | if (EIT->getNumBits() > 64) |
131 | return getIndirectResult(Ty, /*ByVal=*/true, State); |
132 | |
133 | if (isPromotableIntegerTypeForABI(Ty)) { |
134 | if (InReg) |
135 | return ABIArgInfo::getDirectInReg(); |
136 | return ABIArgInfo::getExtend(Ty); |
137 | } |
138 | if (InReg) |
139 | return ABIArgInfo::getDirectInReg(); |
140 | return ABIArgInfo::getDirect(); |
141 | } |
142 | |
143 | namespace { |
144 | class LanaiTargetCodeGenInfo : public TargetCodeGenInfo { |
145 | public: |
146 | LanaiTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) |
147 | : TargetCodeGenInfo(std::make_unique<LanaiABIInfo>(args&: CGT)) {} |
148 | }; |
149 | } |
150 | |
151 | std::unique_ptr<TargetCodeGenInfo> |
152 | CodeGen::createLanaiTargetCodeGenInfo(CodeGenModule &CGM) { |
153 | return std::make_unique<LanaiTargetCodeGenInfo>(args&: CGM.getTypes()); |
154 | } |
155 | |