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_memlayout.h"
17 #include "aarch64_cgfunc.h"
18 #include "becommon.h"
19 #include "mir_nodes.h"
20
21 namespace maplebe {
22 using namespace maple;
23
24 /*
25 * Returns stack space required for a call
26 * which is used to pass arguments that cannot be
27 * passed through registers
28 */
ComputeStackSpaceRequirementForCall(StmtNode & stmt,int32 & aggCopySize,bool isIcall)29 uint32 AArch64MemLayout::ComputeStackSpaceRequirementForCall(StmtNode &stmt, int32 &aggCopySize, bool isIcall)
30 {
31 /* instantiate a parm locator */
32 CCImpl &parmLocator = *static_cast<AArch64CGFunc *>(cgFunc)->GetOrCreateLocator(CCImpl::GetCallConvKind(stmt));
33 uint32 sizeOfArgsToStkPass = 0;
34 uint32 i = 0;
35 /* An indirect call's first operand is the invocation target */
36 if (isIcall) {
37 ++i;
38 }
39
40 if (stmt.GetOpCode() == OP_call) {
41 CallNode *callNode = static_cast<CallNode *>(&stmt);
42 MIRFunction *fn = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(callNode->GetPUIdx());
43 CHECK_FATAL(fn != nullptr, "get MIRFunction failed");
44 CHECK_NULL_FATAL(be.GetMIRModule().CurFunction());
45 MIRSymbol *symbol = be.GetMIRModule().CurFunction()->GetLocalOrGlobalSymbol(fn->GetStIdx(), false);
46 if (symbol->GetName() == "MCC_CallFastNative" || symbol->GetName() == "MCC_CallFastNativeExt" ||
47 symbol->GetName() == "MCC_CallSlowNative0" || symbol->GetName() == "MCC_CallSlowNative1" ||
48 symbol->GetName() == "MCC_CallSlowNative2" || symbol->GetName() == "MCC_CallSlowNative3" ||
49 symbol->GetName() == "MCC_CallSlowNative4" || symbol->GetName() == "MCC_CallSlowNative5" ||
50 symbol->GetName() == "MCC_CallSlowNative6" || symbol->GetName() == "MCC_CallSlowNative7" ||
51 symbol->GetName() == "MCC_CallSlowNative8" || symbol->GetName() == "MCC_CallSlowNativeExt") {
52 ++i;
53 }
54 }
55
56 aggCopySize = 0;
57 for (uint32 anum = 0; i < stmt.NumOpnds(); ++i, ++anum) {
58 BaseNode *opnd = stmt.Opnd(i);
59 MIRType *ty = nullptr;
60 if (opnd->GetPrimType() != PTY_agg) {
61 ty = GlobalTables::GetTypeTable().GetTypeTable()[static_cast<uint32>(opnd->GetPrimType())];
62 } else {
63 Opcode opndOpcode = opnd->GetOpCode();
64 if (be.GetMIRModule().GetFlavor() != kFlavorLmbc) {
65 DEBUG_ASSERT(opndOpcode == OP_dread || opndOpcode == OP_iread,
66 "opndOpcode should be OP_dread or OP_iread");
67 }
68 if (opndOpcode == OP_dread) {
69 DreadNode *dread = static_cast<DreadNode *>(opnd);
70 CHECK_NULL_FATAL(be.GetMIRModule().CurFunction());
71 MIRSymbol *sym = be.GetMIRModule().CurFunction()->GetLocalOrGlobalSymbol(dread->GetStIdx());
72 ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(sym->GetTyIdx());
73 if (dread->GetFieldID() != 0) {
74 DEBUG_ASSERT(ty->GetKind() == kTypeStruct || ty->GetKind() == kTypeClass ||
75 ty->GetKind() == kTypeUnion,
76 "expect struct or class");
77 if (ty->GetKind() == kTypeStruct || ty->GetKind() == kTypeUnion) {
78 ty = static_cast<MIRStructType *>(ty)->GetFieldType(dread->GetFieldID());
79 } else {
80 ty = static_cast<MIRClassType *>(ty)->GetFieldType(dread->GetFieldID());
81 }
82 }
83 } else if (opndOpcode == OP_iread) {
84 IreadNode *iread = static_cast<IreadNode *>(opnd);
85 ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(iread->GetTyIdx());
86 DEBUG_ASSERT(ty->GetKind() == kTypePointer, "expect pointer");
87 ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(static_cast<MIRPtrType *>(ty)->GetPointedTyIdx());
88 if (iread->GetFieldID() != 0) {
89 DEBUG_ASSERT(ty->GetKind() == kTypeStruct || ty->GetKind() == kTypeClass ||
90 ty->GetKind() == kTypeUnion,
91 "expect struct or class");
92 CHECK_NULL_FATAL(ty);
93 if (ty->GetKind() == kTypeStruct || ty->GetKind() == kTypeUnion) {
94 ty = static_cast<MIRStructType *>(ty)->GetFieldType(iread->GetFieldID());
95 } else {
96 ty = static_cast<MIRClassType *>(ty)->GetFieldType(iread->GetFieldID());
97 }
98 }
99 } else if ((opndOpcode == OP_ireadfpoff || opndOpcode == OP_ireadoff || opndOpcode == OP_dreadoff) &&
100 opnd->GetPrimType() == PTY_agg) {
101 ty = static_cast<AArch64CGFunc *>(cgFunc)->GetLmbcStructArgType(stmt, i);
102 }
103 if (ty == nullptr) { /* type mismatch */
104 continue;
105 }
106 }
107 CCLocInfo ploc;
108 aggCopySize += static_cast<int32>(parmLocator.LocateNextParm(*ty, ploc));
109 if (ploc.reg0 != 0) {
110 continue; /* passed in register, so no effect on actual area */
111 }
112 sizeOfArgsToStkPass = static_cast<uint32>(
113 RoundUp(static_cast<uint32>(ploc.memOffset + ploc.memSize), static_cast<uint64>(GetPointerSize())));
114 }
115 return sizeOfArgsToStkPass;
116 }
117
SetSizeAlignForTypeIdx(uint32 typeIdx,uint32 & size,uint32 & align) const118 void AArch64MemLayout::SetSizeAlignForTypeIdx(uint32 typeIdx, uint32 &size, uint32 &align) const
119 {
120 auto *mirType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(typeIdx);
121 if (IsParamStructCopyToMemory(*mirType)) {
122 /* size > 16 is passed on stack, the formal is just a pointer to the copy on stack. */
123 if (CGOptions::IsArm64ilp32()) {
124 align = k8ByteSize;
125 size = k8ByteSize;
126 } else {
127 align = GetPointerSize();
128 size = GetPointerSize();
129 }
130 } else {
131 align = mirType->GetAlign();
132 size = static_cast<uint32>(mirType->GetSize());
133 }
134 }
135
SetSegmentSize(AArch64SymbolAlloc & symbolAlloc,MemSegment & segment,uint32 typeIdx) const136 void AArch64MemLayout::SetSegmentSize(AArch64SymbolAlloc &symbolAlloc, MemSegment &segment, uint32 typeIdx) const
137 {
138 uint32 size;
139 uint32 align;
140 SetSizeAlignForTypeIdx(typeIdx, size, align);
141 segment.SetSize(static_cast<uint32>(RoundUp(static_cast<uint64>(segment.GetSize()), align)));
142 symbolAlloc.SetOffset(segment.GetSize());
143 segment.SetSize(segment.GetSize() + size);
144 segment.SetSize(static_cast<uint32>(RoundUp(static_cast<uint64>(segment.GetSize()), GetPointerSize())));
145 }
146
LayoutVarargParams()147 void AArch64MemLayout::LayoutVarargParams()
148 {
149 uint32 nIntRegs = 0;
150 uint32 nFpRegs = 0;
151 AArch64CallConvImpl parmlocator(be);
152 CCLocInfo ploc;
153 MIRFunction *func = mirFunction;
154 if (be.GetMIRModule().IsCModule() && func->GetAttr(FUNCATTR_varargs)) {
155 for (uint32 i = 0; i < func->GetFormalCount(); i++) {
156 if (i == 0) {
157 if (func->IsFirstArgReturn() && func->GetReturnType()->GetPrimType() != PTY_void) {
158 TyIdx tyIdx = func->GetFuncRetStructTyIdx();
159 if (be.GetTypeSize(tyIdx.GetIdx()) <= k16ByteSize) {
160 continue;
161 }
162 }
163 }
164 MIRType *ty = func->GetNthParamType(i);
165 parmlocator.LocateNextParm(*ty, ploc, i == 0, func->GetMIRFuncType());
166 if (ploc.reg0 != kRinvalid) {
167 if (ploc.reg0 >= R0 && ploc.reg0 <= R7) {
168 nIntRegs++;
169 } else if (ploc.reg0 >= V0 && ploc.reg0 <= V7) {
170 nFpRegs++;
171 }
172 }
173 if (ploc.reg1 != kRinvalid) {
174 if (ploc.reg1 >= R0 && ploc.reg1 <= R7) {
175 nIntRegs++;
176 } else if (ploc.reg1 >= V0 && ploc.reg1 <= V7) {
177 nFpRegs++;
178 }
179 }
180 if (ploc.reg2 != kRinvalid) {
181 if (ploc.reg2 >= R0 && ploc.reg2 <= R7) {
182 nIntRegs++;
183 } else if (ploc.reg2 >= V0 && ploc.reg2 <= V7) {
184 nFpRegs++;
185 }
186 }
187 if (ploc.reg3 != kRinvalid) {
188 if (ploc.reg3 >= R0 && ploc.reg3 <= R7) {
189 nIntRegs++;
190 } else if (ploc.reg2 >= V0 && ploc.reg2 <= V7) {
191 nFpRegs++;
192 }
193 }
194 }
195 if (CGOptions::IsArm64ilp32()) {
196 SetSizeOfGRSaveArea((k8BitSize - nIntRegs) * k8ByteSize);
197 } else {
198 SetSizeOfGRSaveArea((k8BitSize - nIntRegs) * GetPointerSize());
199 }
200 if (CGOptions::UseGeneralRegOnly()) {
201 SetSizeOfVRSaveArea(0);
202 } else {
203 if (CGOptions::IsArm64ilp32()) {
204 SetSizeOfVRSaveArea((k8BitSize - nFpRegs) * k8ByteSize * k2ByteSize);
205 } else {
206 SetSizeOfVRSaveArea((k8BitSize - nFpRegs) * GetPointerSize() * k2ByteSize);
207 }
208 }
209 }
210 }
211
LayoutFormalParams()212 void AArch64MemLayout::LayoutFormalParams()
213 {
214 bool isLmbc = (be.GetMIRModule().GetFlavor() == kFlavorLmbc);
215 if (isLmbc && mirFunction->GetFormalCount() == 0) {
216 /*
217 * lmbc : upformalsize - size of formals passed from caller's frame into current function
218 * framesize - total frame size of current function used by Maple IR
219 * outparmsize - portion of frame size of current function used by call parameters
220 */
221 segArgsStkPassed.SetSize(mirFunction->GetOutParmSize());
222 segArgsRegPassed.SetSize(mirFunction->GetOutParmSize());
223 return;
224 }
225
226 CCImpl &parmLocator = *static_cast<AArch64CGFunc *>(cgFunc)->GetOrCreateLocator(cgFunc->GetCurCallConvKind());
227 CCLocInfo ploc;
228 for (size_t i = 0; i < mirFunction->GetFormalCount(); ++i) {
229 MIRSymbol *sym = mirFunction->GetFormal(i);
230 uint32 stIndex = sym->GetStIndex();
231 AArch64SymbolAlloc *symLoc = memAllocator->GetMemPool()->New<AArch64SymbolAlloc>();
232 SetSymAllocInfo(stIndex, *symLoc);
233 if (i == 0) {
234 if (mirFunction->IsReturnStruct() && mirFunction->IsFirstArgReturn()) {
235 symLoc->SetMemSegment(GetSegArgsRegPassed());
236 symLoc->SetOffset(GetSegArgsRegPassed().GetSize());
237 if (CGOptions::IsArm64ilp32()) {
238 segArgsRegPassed.SetSize(segArgsRegPassed.GetSize() + k8ByteSize);
239 } else {
240 segArgsRegPassed.SetSize(segArgsRegPassed.GetSize() + GetPointerSize());
241 }
242 continue;
243 }
244 }
245 MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(mirFunction->GetFormalDefVec()[i].formalTyIdx);
246 uint32 ptyIdx = ty->GetTypeIndex();
247 parmLocator.LocateNextParm(*ty, ploc, i == 0, mirFunction->GetMIRFuncType());
248 if (ploc.reg0 != kRinvalid) { /* register */
249 symLoc->SetRegisters(static_cast<AArch64reg>(ploc.reg0), static_cast<AArch64reg>(ploc.reg1),
250 static_cast<AArch64reg>(ploc.reg2), static_cast<AArch64reg>(ploc.reg3));
251 if (!cgFunc->GetMirModule().IsCModule() && mirFunction->GetNthParamAttr(i).GetAttr(ATTR_localrefvar)) {
252 symLoc->SetMemSegment(segRefLocals);
253 SetSegmentSize(*symLoc, segRefLocals, ptyIdx);
254 } else if (!sym->IsPreg()) {
255 uint32 size;
256 uint32 align;
257 SetSizeAlignForTypeIdx(ptyIdx, size, align);
258 symLoc->SetMemSegment(GetSegArgsRegPassed());
259 /* the type's alignment requirement may be smaller than a registser's byte size */
260 if (ty->GetPrimType() == PTY_agg) {
261 /* struct param aligned on 8 byte boundary unless it is small enough */
262 if (CGOptions::IsArm64ilp32()) {
263 align = k8ByteSize;
264 } else {
265 align = GetPointerSize();
266 }
267 }
268 uint32 tSize = 0;
269 if ((IsPrimitiveVector(ty->GetPrimType()) && GetPrimTypeSize(ty->GetPrimType()) > k8ByteSize) ||
270 AArch64Abi::IsVectorArrayType(ty, tSize) != PTY_void) {
271 align = k16ByteSize;
272 }
273 segArgsRegPassed.SetSize(static_cast<uint32>(RoundUp(segArgsRegPassed.GetSize(), align)));
274 symLoc->SetOffset(segArgsRegPassed.GetSize());
275 segArgsRegPassed.SetSize(segArgsRegPassed.GetSize() + size);
276 } else if (isLmbc) {
277 segArgsRegPassed.SetSize(segArgsRegPassed.GetSize() + k8ByteSize);
278 }
279 } else { /* stack */
280 uint32 size;
281 uint32 align;
282 SetSizeAlignForTypeIdx(ptyIdx, size, align);
283 symLoc->SetMemSegment(GetSegArgsStkPassed());
284 segArgsStkPassed.SetSize(static_cast<uint32>(RoundUp(segArgsStkPassed.GetSize(), align)));
285 symLoc->SetOffset(segArgsStkPassed.GetSize());
286 segArgsStkPassed.SetSize(segArgsStkPassed.GetSize() + size);
287 /* We need it as dictated by the AArch64 ABI $5.4.2 C12 */
288 if (CGOptions::IsArm64ilp32()) {
289 segArgsStkPassed.SetSize(static_cast<uint32>(RoundUp(segArgsStkPassed.GetSize(), k8ByteSize)));
290 } else {
291 segArgsStkPassed.SetSize(static_cast<uint32>(RoundUp(segArgsStkPassed.GetSize(), GetPointerSize())));
292 }
293 if (!cgFunc->GetMirModule().IsCModule() && mirFunction->GetNthParamAttr(i).GetAttr(ATTR_localrefvar)) {
294 SetLocalRegLocInfo(sym->GetStIdx(), *symLoc);
295 AArch64SymbolAlloc *symLoc1 = memAllocator->GetMemPool()->New<AArch64SymbolAlloc>();
296 symLoc1->SetMemSegment(segRefLocals);
297 SetSegmentSize(*symLoc1, segRefLocals, ptyIdx);
298 SetSymAllocInfo(stIndex, *symLoc1);
299 }
300 }
301 if (cgFunc->GetCG()->GetCGOptions().WithDwarf() && cgFunc->GetWithSrc() &&
302 (symLoc->GetMemSegment() != nullptr)) {
303 cgFunc->AddDIESymbolLocation(sym, symLoc, true);
304 }
305 }
306 }
307
308 // stack frame layout V2.1
309 // stack frame -> layout out some local variable on cold zone
310 // 1. layout small variables near sp
311 // 2. layout cold variables in cold area
312 // ||----------------------------|
313 // | args passed on the stack |
314 // ||----------------------------|
315 // | GR saved area | 16 byte align|
316 // ||---------------------------|
317 // | VR saved area | 16 byte align |
318 // ||---------------------------- |
319 // | stack protect area | total 16 byte|
320 // ||----------------------------|
321 // | cold area | 16 byte align |
322 // ||----------------------------| <- unadjustvary base
323 // | callee saved |
324 // ||----------------------------|
325 // | spill |
326 // ||----------------------------|
327 // | reg saved |
328 // ||----------------------------|
329 // | local variables |
330 // ||----------------------------|
331 // | PREV_FP, PREV_LR |
332 // ||----------------------------|<- Frame Pointer
333 // | variable-sized local vars |
334 // | (VLAs) |
335 // ||----------------------------|
336 // | args to pass through stack |
337 // ||----------------------------|
338 static const uint64 kLocalAreaSizeThreshold = 0;
LayoutLocalsInSize(const MIRSymbol & mirSym)339 void AArch64MemLayout::LayoutLocalsInSize(const MIRSymbol &mirSym)
340 {
341 TyIdx tyIdx = mirSym.GetTyIdx();
342 SymbolAlloc *symLoc = symAllocTable[mirSym.GetStIndex()];
343 MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx);
344 uint32 align = ty->GetAlign();
345 uint32 tSize = 0;
346 MemSegment *currentSeg = &segLocals;
347 if (segLocals.GetSize() < kLocalAreaSizeThreshold) {
348 symLoc->SetMemSegment(segLocals);
349 } else {
350 symLoc->SetMemSegment(segCold);
351 currentSeg = &segCold;
352 }
353 if ((IsPrimitiveVector(ty->GetPrimType()) && GetPrimTypeSize(ty->GetPrimType()) > k8ByteSize) ||
354 AArch64Abi::IsVectorArrayType(ty, tSize) != PTY_void) {
355 align = k16ByteSize;
356 }
357 if (ty->GetPrimType() == PTY_agg && align < k8BitSize) {
358 currentSeg->SetSize(static_cast<uint32>(RoundUp(currentSeg->GetSize(), k8BitSize)));
359 } else {
360 currentSeg->SetSize(static_cast<uint32>(RoundUp(currentSeg->GetSize(), align)));
361 }
362 symLoc->SetOffset(currentSeg->GetSize());
363 currentSeg->SetSize(currentSeg->GetSize() + static_cast<uint32>(ty->GetSize()));
364 }
365
LayoutLocalVariables(std::vector<MIRSymbol * > & tempVar,std::vector<MIRSymbol * > & returnDelays)366 void AArch64MemLayout::LayoutLocalVariables(std::vector<MIRSymbol *> &tempVar, std::vector<MIRSymbol *> &returnDelays)
367 {
368 if (be.GetMIRModule().GetFlavor() == kFlavorLmbc) {
369 segLocals.SetSize(mirFunction->GetFrameSize() - mirFunction->GetOutParmSize());
370 return;
371 }
372 auto symSzCmp = [](const MIRSymbol *left, const MIRSymbol *right) {
373 TyIdx lTyIdx = left->GetTyIdx();
374 TyIdx rTyIdx = right->GetTyIdx();
375 MIRType *lty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(lTyIdx);
376 MIRType *rty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(rTyIdx);
377 uint64 lSz = lty->GetSize();
378 uint64 rSz = rty->GetSize();
379 return lSz <= rSz;
380 };
381 std::set<MIRSymbol *, decltype(symSzCmp)> localSyms(symSzCmp);
382 uint32 symTabSize = mirFunction->GetSymTab()->GetSymbolTableSize();
383 for (uint32 i = 0; i < symTabSize; ++i) {
384 MIRSymbol *sym = mirFunction->GetSymTab()->GetSymbolFromStIdx(i);
385 if (sym == nullptr || sym->GetStorageClass() != kScAuto || sym->IsDeleted()) {
386 continue;
387 }
388 uint32 stIndex = sym->GetStIndex();
389 TyIdx tyIdx = sym->GetTyIdx();
390 auto *symLoc = memAllocator->GetMemPool()->New<AArch64SymbolAlloc>();
391 SetSymAllocInfo(stIndex, *symLoc);
392 CHECK_FATAL(!symLoc->IsRegister(), "expect not register");
393 if (sym->IsRefType()) {
394 if (mirFunction->GetRetRefSym().find(sym) != mirFunction->GetRetRefSym().end()) {
395 /* try to put ret_ref at the end of segRefLocals */
396 returnDelays.emplace_back(sym);
397 continue;
398 }
399 symLoc->SetMemSegment(segRefLocals);
400 segRefLocals.SetSize(static_cast<uint32>(
401 RoundUp(segRefLocals.GetSize(), GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx)->GetAlign())));
402 symLoc->SetOffset(segRefLocals.GetSize());
403 segRefLocals.SetSize(segRefLocals.GetSize() +
404 static_cast<uint32>(GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx)->GetSize()));
405 } else {
406 auto result = localSyms.insert(sym);
407 CHECK_FATAL(result.second, "insert failed");
408 // when O2 && !ilp32 && C module -> disable normal layout
409 if (CGOptions::DoOptimizedFrameLayout() && !CGOptions::IsArm64ilp32() &&
410 Globals::GetInstance()->GetOptimLevel() == CGOptions::kLevel2 && cgFunc->GetMirModule().IsCModule()) {
411 continue;
412 }
413 if (sym->GetName() == "__EARetTemp__" || sym->GetName().substr(0, kEARetTempNameSize) == "__EATemp__") {
414 tempVar.emplace_back(sym);
415 continue;
416 }
417 symLoc->SetMemSegment(segLocals);
418 MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx);
419 uint32 align = ty->GetAlign();
420 uint32 tSize = 0;
421 if ((IsPrimitiveVector(ty->GetPrimType()) && GetPrimTypeSize(ty->GetPrimType()) > k8ByteSize) ||
422 AArch64Abi::IsVectorArrayType(ty, tSize) != PTY_void) {
423 align = k16ByteSize;
424 }
425 if (ty->GetPrimType() == PTY_agg && align < k8BitSize) {
426 segLocals.SetSize(static_cast<uint32>(RoundUp(segLocals.GetSize(), k8BitSize)));
427 } else {
428 segLocals.SetSize(static_cast<uint32>(RoundUp(segLocals.GetSize(), align)));
429 }
430 symLoc->SetOffset(segLocals.GetSize());
431 segLocals.SetSize(segLocals.GetSize() +
432 static_cast<uint32>(GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx)->GetSize()));
433 }
434 if (cgFunc->GetCG()->GetCGOptions().WithDwarf() && cgFunc->GetWithSrc()) {
435 cgFunc->AddDIESymbolLocation(sym, symLoc, false);
436 }
437 }
438 // when O2 && !ilp32 && C module -> enable code layout
439 if (!CGOptions::DoOptimizedFrameLayout() || CGOptions::IsArm64ilp32() ||
440 Globals::GetInstance()->GetOptimLevel() != CGOptions::kLevel2 || !cgFunc->GetMirModule().IsCModule()) {
441 return;
442 }
443 for (auto lSymIt : localSyms) {
444 MIRSymbol *lSym = lSymIt;
445 uint32 stIndex = lSym->GetStIndex();
446 LayoutLocalsInSize(*lSym);
447 if (cgFunc->GetCG()->GetCGOptions().WithDwarf()) {
448 cgFunc->AddDIESymbolLocation(lSym, GetSymAllocInfo(stIndex), false);
449 }
450 }
451 }
452
LayoutEAVariales(std::vector<MIRSymbol * > & tempVar)453 void AArch64MemLayout::LayoutEAVariales(std::vector<MIRSymbol *> &tempVar)
454 {
455 for (auto sym : tempVar) {
456 uint32 stIndex = sym->GetStIndex();
457 TyIdx tyIdx = sym->GetTyIdx();
458 AArch64SymbolAlloc *symLoc = memAllocator->GetMemPool()->New<AArch64SymbolAlloc>();
459 SetSymAllocInfo(stIndex, *symLoc);
460 DEBUG_ASSERT(!symLoc->IsRegister(), "expect not register");
461 symLoc->SetMemSegment(segRefLocals);
462 segRefLocals.SetSize(static_cast<uint32>(
463 RoundUp(segRefLocals.GetSize(), GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx)->GetAlign())));
464 symLoc->SetOffset(segRefLocals.GetSize());
465 segRefLocals.SetSize(segRefLocals.GetSize() +
466 static_cast<uint32>(GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx)->GetSize()));
467 }
468 }
469
LayoutReturnRef(std::vector<MIRSymbol * > & returnDelays,int32 & structCopySize,int32 & maxParmStackSize)470 void AArch64MemLayout::LayoutReturnRef(std::vector<MIRSymbol *> &returnDelays, int32 &structCopySize,
471 int32 &maxParmStackSize)
472 {
473 for (auto sym : returnDelays) {
474 uint32 stIndex = sym->GetStIndex();
475 TyIdx tyIdx = sym->GetTyIdx();
476 AArch64SymbolAlloc *symLoc = memAllocator->GetMemPool()->New<AArch64SymbolAlloc>();
477 SetSymAllocInfo(stIndex, *symLoc);
478 DEBUG_ASSERT(!symLoc->IsRegister(), "expect not register");
479
480 DEBUG_ASSERT(sym->IsRefType(), "expect reftype ");
481 symLoc->SetMemSegment(segRefLocals);
482 segRefLocals.SetSize(static_cast<uint32>(
483 RoundUp(segRefLocals.GetSize(), GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx)->GetAlign())));
484 symLoc->SetOffset(segRefLocals.GetSize());
485 segRefLocals.SetSize(segRefLocals.GetSize() +
486 static_cast<uint32>(GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx)->GetSize()));
487 }
488 if (be.GetMIRModule().GetFlavor() == kFlavorLmbc) {
489 segArgsToStkPass.SetSize(mirFunction->GetOutParmSize() + kDivide2 * k8ByteSize);
490 } else {
491 segArgsToStkPass.SetSize(FindLargestActualArea(structCopySize));
492 }
493 maxParmStackSize = static_cast<int32>(segArgsToStkPass.GetSize());
494 if (Globals::GetInstance()->GetOptimLevel() == CGOptions::kLevel0) {
495 AssignSpillLocationsToPseudoRegisters();
496 } else {
497 AArch64CGFunc *aarchCGFunc = static_cast<AArch64CGFunc *>(cgFunc);
498 /* 8-VirtualRegNode occupy byte number */
499 aarchCGFunc->SetCatchRegno(cgFunc->NewVReg(kRegTyInt, 8));
500 }
501 segRefLocals.SetSize(static_cast<uint32>(RoundUp(segRefLocals.GetSize(), GetPointerSize())));
502 if (CGOptions::IsArm64ilp32()) {
503 segLocals.SetSize(static_cast<uint32>(RoundUp(segLocals.GetSize(), k8ByteSize)));
504 } else {
505 segLocals.SetSize(static_cast<uint32>(RoundUp(segLocals.GetSize(), GetPointerSize())));
506 }
507 }
508
LayoutActualParams()509 void AArch64MemLayout::LayoutActualParams()
510 {
511 for (size_t i = 0; i < mirFunction->GetFormalCount(); ++i) {
512 if (i == 0) {
513 if (mirFunction->IsReturnStruct() && mirFunction->IsFirstArgReturn()) {
514 continue;
515 }
516 }
517 MIRSymbol *sym = mirFunction->GetFormal(i);
518 if (sym->IsPreg()) {
519 continue;
520 }
521 uint32 stIndex = sym->GetStIndex();
522 AArch64SymbolAlloc *symLoc = static_cast<AArch64SymbolAlloc *>(GetSymAllocInfo(stIndex));
523 if (symLoc->GetMemSegment() == &GetSegArgsRegPassed()) { /* register */
524 /*
525 * In O0, we store parameters passed via registers into memory.
526 * So, each of such parameter needs to get assigned storage in stack.
527 * If a function parameter is never accessed in the function body,
528 * and if we don't create its memory operand here, its offset gets
529 * computed when the instruction to store its value into stack
530 * is generated in the prologue when its memory operand is created.
531 * But, the parameter would see a different StackFrameSize than
532 * the parameters that are accessed in the body, because
533 * the size of the storage for FP/LR is added to the stack frame
534 * size in between.
535 * To make offset assignment easier, we create a memory operand
536 * for each of function parameters in advance.
537 * This has to be done after all of formal parameters and local
538 * variables get assigned their respecitve storage, i.e.
539 * CallFrameSize (discounting callee-saved and FP/LR) is known.
540 */
541 MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(mirFunction->GetFormalDefVec()[i].formalTyIdx);
542 uint32 ptyIdx = ty->GetTypeIndex();
543 static_cast<AArch64CGFunc *>(cgFunc)->GetOrCreateMemOpnd(
544 *sym, 0, GlobalTables::GetTypeTable().GetTypeFromTyIdx(ptyIdx)->GetAlign() * kBitsPerByte);
545 }
546 }
547 }
548
LayoutStackFrame(int32 & structCopySize,int32 & maxParmStackSize)549 void AArch64MemLayout::LayoutStackFrame(int32 &structCopySize, int32 &maxParmStackSize)
550 {
551 LayoutVarargParams();
552 LayoutFormalParams();
553 /*
554 * We do need this as LDR/STR with immediate
555 * requires imm be aligned at a 8/4-byte boundary,
556 * and local varirables may need 8-byte alignment.
557 */
558 if (CGOptions::IsArm64ilp32()) {
559 segArgsRegPassed.SetSize(RoundUp(segArgsRegPassed.GetSize(), k8ByteSize));
560 /* we do need this as SP has to be aligned at a 16-bytes bounardy */
561 segArgsStkPassed.SetSize(RoundUp(segArgsStkPassed.GetSize(), k8ByteSize + k8ByteSize));
562 } else {
563 segArgsRegPassed.SetSize(static_cast<uint32>(RoundUp(segArgsRegPassed.GetSize(), GetPointerSize())));
564 segArgsStkPassed.SetSize(
565 static_cast<uint32>(RoundUp(segArgsStkPassed.GetSize(), GetPointerSize() + GetPointerSize())));
566 }
567 /* allocate the local variables in the stack */
568 std::vector<MIRSymbol *> eaTempVar;
569 std::vector<MIRSymbol *> retDelays;
570 LayoutLocalVariables(eaTempVar, retDelays);
571 LayoutEAVariales(eaTempVar);
572
573 /* handle ret_ref sym now */
574 LayoutReturnRef(retDelays, structCopySize, maxParmStackSize);
575
576 /*
577 * for the actual arguments that cannot be pass through registers
578 * need to allocate space for caller-save registers
579 */
580 LayoutActualParams();
581
582 fixStackSize = static_cast<int32>(RealStackFrameSize());
583 cgFunc->SetUseFP(cgFunc->UseFP() || fixStackSize > kMaxPimm32);
584 }
585 // from cold area to bottom of stk
586 // [cold,16] + [GR, 16] + [VR, 16] + stack protect (if has)
GetSizeOfColdToStk() const587 uint64 AArch64MemLayout::GetSizeOfColdToStk() const
588 {
589 uint64 total = 0;
590 auto coldsize = RoundUp(GetSizeOfSegCold(), k16BitSize);
591 total += coldsize;
592 if (GetSizeOfGRSaveArea() > 0) {
593 total += RoundUp(GetSizeOfGRSaveArea(), kAarch64StackPtrAlignment);
594 }
595 if (GetSizeOfVRSaveArea() > 0) {
596 total += RoundUp(GetSizeOfVRSaveArea(), kAarch64StackPtrAlignment);
597 }
598 if (cgFunc->GetCG()->IsStackProtectorStrong() || cgFunc->GetCG()->IsStackProtectorAll()) {
599 total += static_cast<uint32>(kAarch64StackPtrAlignment);
600 }
601 return total;
602 }
603
IsSegMentVaried(const MemSegment * seg) const604 bool AArch64MemLayout::IsSegMentVaried(const MemSegment *seg) const
605 {
606 if (seg->GetMemSegmentKind() == kMsArgsStkPassed || seg->GetMemSegmentKind() == kMsCold) {
607 return true;
608 }
609 return false;
610 }
611
AssignSpillLocationsToPseudoRegisters()612 void AArch64MemLayout::AssignSpillLocationsToPseudoRegisters()
613 {
614 MIRPregTable *pregTab = cgFunc->GetFunction().GetPregTab();
615
616 /* BUG: n_regs include index 0 which is not a valid preg index. */
617 size_t nRegs = pregTab->Size();
618 spillLocTable.resize(nRegs);
619 for (size_t i = 1; i < nRegs; ++i) {
620 PrimType pType = pregTab->PregFromPregIdx(i)->GetPrimType();
621 AArch64SymbolAlloc *symLoc = memAllocator->GetMemPool()->New<AArch64SymbolAlloc>();
622 symLoc->SetMemSegment(segLocals);
623 segLocals.SetSize(RoundUp(segLocals.GetSize(), GetPrimTypeSize(pType)));
624 symLoc->SetOffset(segLocals.GetSize());
625 MIRType *mirTy = GlobalTables::GetTypeTable().GetTypeTable()[pType];
626 segLocals.SetSize(segLocals.GetSize() + static_cast<uint32>(mirTy->GetSize()));
627 spillLocTable[i] = symLoc;
628 }
629 }
630
StackFrameSize() const631 uint64 AArch64MemLayout::StackFrameSize() const
632 {
633 // regpassed + calleesaved + reflocals + locals + spill + cold + args to callee
634 uint64 total = segArgsRegPassed.GetSize() + static_cast<AArch64CGFunc *>(cgFunc)->SizeOfCalleeSaved() +
635 GetSizeOfRefLocals() + Locals().GetSize() + GetSizeOfSpillReg() +
636 cgFunc->GetFunction().GetFrameReseverdSlot();
637
638 auto coldsize = RoundUp(GetSizeOfSegCold(), k16BitSize);
639 total += coldsize;
640 if (cgFunc->GetMirModule().GetFlavor() != MIRFlavor::kFlavorLmbc) {
641 if (GetSizeOfGRSaveArea() > 0) {
642 total += RoundUp(GetSizeOfGRSaveArea(), kAarch64StackPtrAlignment);
643 }
644 if (GetSizeOfVRSaveArea() > 0) {
645 total += RoundUp(GetSizeOfVRSaveArea(), kAarch64StackPtrAlignment);
646 }
647 }
648
649 /*
650 * if the function does not have VLA nor alloca,
651 * we allocate space for arguments to stack-pass
652 * in the call frame; otherwise, it has to be allocated for each call and reclaimed afterward.
653 */
654 total += segArgsToStkPass.GetSize();
655 return RoundUp(total, kAarch64StackPtrAlignment);
656 }
657
658 // [regpass] + [callee save] + [reflocal] + [local] + [spill] + [cold,16] + [GR,16] + [VR,16] + stack protect (if has)
RealStackFrameSize() const659 uint32 AArch64MemLayout::RealStackFrameSize() const
660 {
661 auto size = StackFrameSize();
662 if (cgFunc->GetCG()->IsStackProtectorStrong() || cgFunc->GetCG()->IsStackProtectorAll()) {
663 size += static_cast<uint32>(kAarch64StackPtrAlignment);
664 }
665 return static_cast<uint32>(size);
666 }
667
GetRefLocBaseLoc() const668 int32 AArch64MemLayout::GetRefLocBaseLoc() const
669 {
670 AArch64CGFunc *aarchCGFunc = static_cast<AArch64CGFunc *>(cgFunc);
671 auto beforeSize = GetSizeOfLocals();
672 if (aarchCGFunc->UsedStpSubPairForCallFrameAllocation()) {
673 return static_cast<int32>(beforeSize);
674 }
675 return static_cast<int32>(beforeSize + kAarch64SizeOfFplr);
676 }
677
GetGRSaveAreaBaseLoc() const678 int32 AArch64MemLayout::GetGRSaveAreaBaseLoc() const
679 {
680 int32 total = static_cast<int32>(RealStackFrameSize() - RoundUp(GetSizeOfGRSaveArea(), kAarch64StackPtrAlignment));
681 total -= static_cast<int32>(SizeOfArgsToStackPass()) + cgFunc->GetFunction().GetFrameReseverdSlot();
682 return total;
683 }
684
GetVRSaveAreaBaseLoc() const685 int32 AArch64MemLayout::GetVRSaveAreaBaseLoc() const
686 {
687 int32 total =
688 static_cast<int32>((RealStackFrameSize() - RoundUp(GetSizeOfGRSaveArea(), kAarch64StackPtrAlignment)) -
689 RoundUp(GetSizeOfVRSaveArea(), kAarch64StackPtrAlignment));
690 total -= static_cast<int32>(SizeOfArgsToStackPass()) + cgFunc->GetFunction().GetFrameReseverdSlot();
691 return total;
692 }
693
694 // fp - callee base =
695 // RealStackFrameSize - [GR,16] - [VR,16] - [cold,16] - ([callee] - 16(fplr)) - stack protect - stkpass
696 // callsave area size includes fp lr, real callee save area size is callee save size - fplr
697 // fp lr located on top of args pass area.
GetCalleeSaveBaseLoc() const698 int32 AArch64MemLayout::GetCalleeSaveBaseLoc() const
699 {
700 uint32 offset = RealStackFrameSize() - static_cast<AArch64CGFunc *>(cgFunc)->SizeOfCalleeSaved();
701 offset = (offset - SizeOfArgsToStackPass()) + kAarch64SizeOfFplr - cgFunc->GetFunction().GetFrameReseverdSlot();
702 if (cgFunc->GetMirModule().IsCModule() && cgFunc->GetFunction().GetAttr(FUNCATTR_varargs)) {
703 /* GR/VR save areas are above the callee save area */
704 // According to AAPCS64 document:
705 // __gr_top: set to the address of the byte immediately following the general register argument save area, the
706 // end of the save area being aligned to a 16 byte boundary.
707 // __vr_top: set to the address of the byte immediately following the FP/SIMD register argument save area, the
708 // end of the save area being aligned to a 16 byte boundary.
709 auto saveareasize = RoundUp(GetSizeOfGRSaveArea(), kAarch64StackPtrAlignment) +
710 RoundUp(GetSizeOfVRSaveArea(), kAarch64StackPtrAlignment);
711 offset = static_cast<uint32>(offset - saveareasize);
712 }
713 offset -= static_cast<uint32>(RoundUp(GetSizeOfSegCold(), k16BitSize));
714
715 if (cgFunc->GetCG()->IsStackProtectorStrong() || cgFunc->GetCG()->IsStackProtectorAll()) {
716 offset -= static_cast<uint32>(kAarch64StackPtrAlignment);
717 }
718 return static_cast<int32>(offset);
719 }
720 } /* namespace maplebe */
721