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
updateState(const ABIArgInfo & Info,QualType Ty,CCState & State) const30 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(Ty) + 31) / 32;
37 if (sz < State.FreeRegs)
38 State.FreeRegs -= sz;
39 else
40 State.FreeRegs = 0;
41 }
42 }
43
computeInfo(CGFunctionInfo & FI) const44 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(FI.getReturnType());
51 updateState(FI.getReturnInfo(), FI.getReturnType(), State);
52 for (auto &I : FI.arguments()) {
53 I.info = classifyArgumentType(I.type, State.FreeRegs);
54 updateState(I.info, 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:
ARCTargetCodeGenInfo(CodeGenTypes & CGT)66 ARCTargetCodeGenInfo(CodeGenTypes &CGT)
67 : TargetCodeGenInfo(std::make_unique<ARCABIInfo>(CGT)) {}
68 };
69
70
getIndirectByRef(QualType Ty,bool HasFreeRegs) const71 ABIArgInfo ARCABIInfo::getIndirectByRef(QualType Ty, bool HasFreeRegs) const {
72 return HasFreeRegs ? getNaturalAlignIndirectInReg(Ty)
73 : getNaturalAlignIndirect(
74 Ty, getDataLayout().getAllocaAddrSpace(), false);
75 }
76
getIndirectByValue(QualType Ty) const77 ABIArgInfo ARCABIInfo::getIndirectByValue(QualType Ty) const {
78 // Compute the byval alignment.
79 const unsigned MinABIStackAlignInBytes = 4;
80 unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8;
81 return ABIArgInfo::getIndirect(
82 CharUnits::fromQuantity(4),
83 /*AddrSpace=*/getDataLayout().getAllocaAddrSpace(),
84 /*ByVal=*/true, TypeAlign > MinABIStackAlignInBytes);
85 }
86
EmitVAArg(CodeGenFunction & CGF,Address VAListAddr,QualType Ty,AggValueSlot Slot) const87 RValue ARCABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
88 QualType Ty, AggValueSlot Slot) const {
89 return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false,
90 getContext().getTypeInfoInChars(Ty),
91 CharUnits::fromQuantity(4), true, Slot);
92 }
93
classifyArgumentType(QualType Ty,uint8_t FreeRegs) const94 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, getCXXABI());
100 if (RAA == CGCXXABI::RAA_Indirect)
101 return getIndirectByRef(Ty, 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(getContext().getTypeSize(Ty), 32) / 32;
112
113 if (isAggregateTypeForABI(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(getContext(), Ty, true))
120 return ABIArgInfo::getIgnore();
121
122 llvm::LLVMContext &LLVMContext = getVMContext();
123
124 llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext);
125 SmallVector<llvm::Type *, 3> Elements(SizeInRegs, Int32);
126 llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements);
127
128 return FreeRegs >= SizeInRegs ?
129 ABIArgInfo::getDirectInReg(Result) :
130 ABIArgInfo::getDirect(Result, 0, nullptr, 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
classifyReturnType(QualType RetTy) const144 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(getContext().getTypeSize(RetTy), 32) / 32;
150 if (RetSize > 4)
151 return getIndirectByRef(RetTy, /*HasFreeRegs*/ true);
152
153 return DefaultABIInfo::classifyReturnType(RetTy);
154 }
155
156 } // End anonymous namespace.
157
158 std::unique_ptr<TargetCodeGenInfo>
createARCTargetCodeGenInfo(CodeGenModule & CGM)159 CodeGen::createARCTargetCodeGenInfo(CodeGenModule &CGM) {
160 return std::make_unique<ARCTargetCodeGenInfo>(CGM.getTypes());
161 }
162