• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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