1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "aarch64_args.h"
17 #include <fstream>
18 #include "aarch64_cgfunc.h"
19 #include "aarch64_cg.h"
20
21 namespace maplebe {
22 using namespace maple;
23
Run()24 void AArch64MoveRegArgs::Run()
25 {
26 BB *formerCurBB = aarFunc->GetCurBB();
27 MoveVRegisterArgs();
28 MoveRegisterArgs();
29 aarFunc->SetCurBB(*formerCurBB);
30 }
31
MoveRegisterArgs() const32 void AArch64MoveRegArgs::MoveRegisterArgs() const
33 {
34 aarFunc->GetDummyBB()->ClearInsns();
35 aarFunc->SetCurBB(*aarFunc->GetDummyBB());
36
37 auto &mirFunc = aarFunc->GetFunction();
38 CCImpl &parmlocator =
39 *static_cast<AArch64CGFunc *>(cgFunc)->GetOrCreateLocator(CCImpl::GetCallConvKind(cgFunc->GetFunction()));
40 CCLocInfo ploc;
41 for (uint32 i = 0; i < mirFunc.GetFormalCount(); ++i) {
42 MIRType *ty = mirFunc.GetNthParamType(i);
43 parmlocator.LocateNextParm(*ty, ploc, i == 0, mirFunc.GetMIRFuncType());
44 if (ploc.reg0 == kRinvalid) {
45 continue;
46 }
47 auto *sym = mirFunc.GetFormal(i);
48 if (sym->IsPreg()) {
49 continue;
50 }
51 auto *symLoc = aarFunc->GetMemlayout()->GetSymAllocInfo(sym->GetStIndex());
52 auto *baseOpnd = aarFunc->GetBaseReg(*symLoc);
53 auto offset = aarFunc->GetBaseOffset(*symLoc);
54 auto generateStrInsn = [this, baseOpnd, &offset, sym, symLoc](AArch64reg reg, PrimType primType) {
55 RegOperand ®Opnd = aarFunc->GetOrCreatePhysicalRegisterOperand(reg, GetPrimTypeBitSize(primType),
56 aarFunc->GetRegTyFromPrimTy(primType));
57 OfstOperand &ofstOpnd =
58 aarFunc->CreateOfstOpnd(static_cast<uint64>(static_cast<int64>(offset)), k32BitSize);
59 AArch64MemLayout *memLayout = static_cast<AArch64MemLayout *>(aarFunc->GetMemlayout());
60 if (memLayout->IsSegMentVaried(symLoc->GetMemSegment())) {
61 ofstOpnd.SetVary(kUnAdjustVary);
62 }
63 auto *memOpnd = aarFunc->CreateMemOperand(GetPrimTypeBitSize(primType), *baseOpnd, ofstOpnd, false);
64
65 MOperator mOp = aarFunc->PickStInsn(GetPrimTypeBitSize(primType), primType);
66 Insn &insn = aarFunc->GetInsnBuilder()->BuildInsn(mOp, regOpnd, *memOpnd);
67 if (aarFunc->GetCG()->GenerateVerboseCG()) {
68 insn.SetComment(std::string("store param: ").append(sym->GetName()));
69 }
70 aarFunc->GetCurBB()->AppendInsn(insn);
71 offset += static_cast<int32>(GetPrimTypeSize(primType));
72 };
73 generateStrInsn(static_cast<AArch64reg>(ploc.GetReg0()), ploc.GetPrimTypeOfReg0());
74 if (ploc.GetReg1() != kRinvalid) {
75 generateStrInsn(static_cast<AArch64reg>(ploc.GetReg1()), ploc.GetPrimTypeOfReg1());
76 }
77 if (ploc.GetReg2() != kRinvalid) {
78 generateStrInsn(static_cast<AArch64reg>(ploc.GetReg2()), ploc.GetPrimTypeOfReg2());
79 }
80 if (ploc.GetReg3() != kRinvalid) {
81 generateStrInsn(static_cast<AArch64reg>(ploc.GetReg3()), ploc.GetPrimTypeOfReg3());
82 }
83 }
84
85 if (cgFunc->GetCG()->IsLmbc() && (cgFunc->GetSpSaveReg() != 0)) {
86 /* lmbc uses vreg act as SP when alloca is present due to usage of FP for - offset */
87 aarFunc->GetFirstBB()->InsertAtEnd(*aarFunc->GetDummyBB());
88 } else {
89 aarFunc->GetFirstBB()->InsertAtBeginning(*aarFunc->GetDummyBB());
90 }
91 }
92
MoveLocalRefVarToRefLocals(MIRSymbol & mirSym) const93 void AArch64MoveRegArgs::MoveLocalRefVarToRefLocals(MIRSymbol &mirSym) const
94 {
95 AArch64CGFunc *aarFunc = static_cast<AArch64CGFunc *>(cgFunc);
96 PrimType stype = mirSym.GetType()->GetPrimType();
97 uint32 byteSize = GetPrimTypeSize(stype);
98 uint32 bitSize = byteSize * kBitsPerByte;
99 MemOperand &memOpnd = aarFunc->GetOrCreateMemOpnd(mirSym, 0, bitSize, true);
100 RegOperand *regOpnd = nullptr;
101 if (mirSym.IsPreg()) {
102 PregIdx pregIdx = aarFunc->GetFunction().GetPregTab()->GetPregIdxFromPregno(
103 static_cast<uint32>(mirSym.GetPreg()->GetPregNo()));
104 regOpnd = &aarFunc->GetOrCreateVirtualRegisterOperand(aarFunc->GetVirtualRegNOFromPseudoRegIdx(pregIdx));
105 } else {
106 regOpnd = &aarFunc->GetOrCreateVirtualRegisterOperand(aarFunc->NewVReg(kRegTyInt, k8ByteSize));
107 }
108 Insn &insn =
109 aarFunc->GetInsnBuilder()->BuildInsn(aarFunc->PickLdInsn(GetPrimTypeBitSize(stype), stype), *regOpnd, memOpnd);
110 MemOperand &memOpnd1 = aarFunc->GetOrCreateMemOpnd(mirSym, 0, bitSize, false);
111 Insn &insn1 =
112 aarFunc->GetInsnBuilder()->BuildInsn(aarFunc->PickStInsn(GetPrimTypeBitSize(stype), stype), *regOpnd, memOpnd1);
113 aarFunc->GetCurBB()->InsertInsnBegin(insn1);
114 aarFunc->GetCurBB()->InsertInsnBegin(insn);
115 }
116
LoadStackArgsToVReg(MIRSymbol & mirSym) const117 void AArch64MoveRegArgs::LoadStackArgsToVReg(MIRSymbol &mirSym) const
118 {
119 AArch64CGFunc *aarFunc = static_cast<AArch64CGFunc *>(cgFunc);
120 PrimType stype = mirSym.GetType()->GetPrimType();
121 uint32 byteSize = GetPrimTypeSize(stype);
122 uint32 bitSize = byteSize * kBitsPerByte;
123 MemOperand &memOpnd = aarFunc->GetOrCreateMemOpnd(mirSym, 0, bitSize);
124 PregIdx pregIdx =
125 aarFunc->GetFunction().GetPregTab()->GetPregIdxFromPregno(static_cast<uint32>(mirSym.GetPreg()->GetPregNo()));
126 RegOperand &dstRegOpnd =
127 aarFunc->GetOrCreateVirtualRegisterOperand(aarFunc->GetVirtualRegNOFromPseudoRegIdx(pregIdx));
128 Insn &insn = aarFunc->GetInsnBuilder()->BuildInsn(aarFunc->PickLdInsn(GetPrimTypeBitSize(stype), stype), dstRegOpnd,
129 memOpnd);
130
131 if (aarFunc->GetCG()->GenerateVerboseCG()) {
132 std::string key = "param: %%";
133 key += std::to_string(mirSym.GetPreg()->GetPregNo());
134 DEBUG_ASSERT(mirSym.GetStorageClass() == kScFormal, "vreg parameters should be kScFormal type.");
135 insn.SetComment(key);
136 }
137
138 aarFunc->GetCurBB()->InsertInsnBegin(insn);
139 }
140
MoveArgsToVReg(const CCLocInfo & ploc,MIRSymbol & mirSym) const141 void AArch64MoveRegArgs::MoveArgsToVReg(const CCLocInfo &ploc, MIRSymbol &mirSym) const
142 {
143 // when args parameter type i128, reg1 will be used.
144 // but, i128 is not supported in back-end
145 CHECK_FATAL(ploc.reg2 == kRinvalid, "NIY");
146 RegType regType = (ploc.reg0 < V0) ? kRegTyInt : kRegTyFloat;
147 PrimType sType = mirSym.GetType()->GetPrimType();
148 uint32 byteSize = GetPrimTypeSize(sType);
149 uint32 srcBitSize = ((byteSize < k4ByteSize) ? k4ByteSize : byteSize) * kBitsPerByte;
150 PregIdx pregIdx =
151 aarFunc->GetFunction().GetPregTab()->GetPregIdxFromPregno(static_cast<uint32>(mirSym.GetPreg()->GetPregNo()));
152 RegOperand &dstRegOpnd =
153 aarFunc->GetOrCreateVirtualRegisterOperand(aarFunc->GetVirtualRegNOFromPseudoRegIdx(pregIdx));
154 dstRegOpnd.SetSize(srcBitSize);
155 RegOperand &srcRegOpnd =
156 aarFunc->GetOrCreatePhysicalRegisterOperand(static_cast<AArch64reg>(ploc.reg0), srcBitSize, regType);
157 DEBUG_ASSERT(mirSym.GetStorageClass() == kScFormal, "should be args");
158 MOperator mOp = aarFunc->PickMovBetweenRegs(sType, sType);
159 if (mOp == MOP_vmovvv || mOp == MOP_vmovuu) {
160 auto &vInsn = aarFunc->GetInsnBuilder()->BuildVectorInsn(mOp, AArch64CG::kMd[mOp]);
161 (void)vInsn.AddOpndChain(dstRegOpnd).AddOpndChain(srcRegOpnd);
162 auto *vecSpec1 = aarFunc->GetMemoryPool()->New<VectorRegSpec>(srcBitSize >> k3ByteSize, k8BitSize);
163 auto *vecSpec2 = aarFunc->GetMemoryPool()->New<VectorRegSpec>(srcBitSize >> k3ByteSize, k8BitSize);
164 (void)vInsn.PushRegSpecEntry(vecSpec1).PushRegSpecEntry(vecSpec2);
165 aarFunc->GetCurBB()->InsertInsnBegin(vInsn);
166 return;
167 }
168 Insn &insn = CreateMoveArgsToVRegInsn(mOp, dstRegOpnd, srcRegOpnd, sType);
169 if (aarFunc->GetCG()->GenerateVerboseCG()) {
170 std::string str = "param: %%";
171 str += std::to_string(mirSym.GetPreg()->GetPregNo());
172 insn.SetComment(str);
173 }
174 aarFunc->GetCurBB()->InsertInsnBegin(insn);
175 }
176
CreateMoveArgsToVRegInsn(MOperator mOp,RegOperand & destOpnd,RegOperand & srcOpnd,PrimType primType) const177 Insn &AArch64MoveRegArgs::CreateMoveArgsToVRegInsn(MOperator mOp, RegOperand &destOpnd, RegOperand &srcOpnd,
178 PrimType primType) const
179 {
180 if (mOp == MOP_wmovrr || mOp == MOP_xmovrr) {
181 /* callee ensure the validbit of parameters of function */
182 switch (primType) {
183 case PTY_u1: {
184 ImmOperand &lsbOpnd = aarFunc->CreateImmOperand(maplebe::k0BitSize, srcOpnd.GetSize(), false);
185 ImmOperand &widthOpnd = aarFunc->CreateImmOperand(maplebe::k1BitSize, srcOpnd.GetSize(), false);
186 bool is64Bit = (srcOpnd.GetSize() == maplebe::k64BitSize);
187 return aarFunc->GetInsnBuilder()->BuildInsn(is64Bit ? MOP_xubfxrri6i6 : MOP_wubfxrri5i5, destOpnd,
188 srcOpnd, lsbOpnd, widthOpnd);
189 }
190 case PTY_u8:
191 case PTY_i8:
192 return aarFunc->GetInsnBuilder()->BuildInsn(MOP_xuxtb32, destOpnd, srcOpnd);
193 case PTY_u16:
194 case PTY_i16:
195 return aarFunc->GetInsnBuilder()->BuildInsn(MOP_xuxth32, destOpnd, srcOpnd);
196 case PTY_u32:
197 case PTY_i32: {
198 destOpnd.SetValidBitsNum(maplebe::k64BitSize);
199 return aarFunc->GetInsnBuilder()->BuildInsn(MOP_xuxtw64, destOpnd, srcOpnd);
200 }
201 default:
202 return aarFunc->GetInsnBuilder()->BuildInsn(mOp, destOpnd, srcOpnd);
203 }
204 } else {
205 return aarFunc->GetInsnBuilder()->BuildInsn(mOp, destOpnd, srcOpnd);
206 }
207 }
208
MoveVRegisterArgs()209 void AArch64MoveRegArgs::MoveVRegisterArgs()
210 {
211 aarFunc->GetDummyBB()->ClearInsns();
212 aarFunc->SetCurBB(*aarFunc->GetDummyBB());
213 CCImpl &parmlocator =
214 *static_cast<AArch64CGFunc *>(cgFunc)->GetOrCreateLocator(CCImpl::GetCallConvKind(cgFunc->GetFunction()));
215 CCLocInfo ploc;
216
217 auto &mirFunc = aarFunc->GetFunction();
218 for (size_t i = 0; i < mirFunc.GetFormalCount(); ++i) {
219 MIRType *ty = mirFunc.GetNthParamType(i);
220 parmlocator.LocateNextParm(*ty, ploc, (i == 0), mirFunc.GetMIRFuncType());
221 MIRSymbol *sym = mirFunc.GetFormal(i);
222
223 /* load locarefvar formals to store in the reflocals. */
224 if (mirFunc.GetNthParamAttr(i).GetAttr(ATTR_localrefvar) && ploc.reg0 == kRinvalid) {
225 MoveLocalRefVarToRefLocals(*sym);
226 }
227
228 if (!sym->IsPreg()) {
229 continue;
230 }
231
232 if (ploc.reg0 == kRinvalid) {
233 /* load stack parameters to the vreg. */
234 LoadStackArgsToVReg(*sym);
235 } else {
236 MoveArgsToVReg(ploc, *sym);
237 }
238 }
239
240 if (cgFunc->GetCG()->IsLmbc() && (cgFunc->GetSpSaveReg() != 0)) {
241 /* lmbc uses vreg act as SP when alloca is present due to usage of FP for - offset */
242 aarFunc->GetFirstBB()->InsertAtEnd(*aarFunc->GetDummyBB());
243 } else {
244 aarFunc->GetFirstBB()->InsertAtBeginning(*aarFunc->GetDummyBB());
245 }
246 }
247 } /* namespace maplebe */
248