• 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 #ifndef MAPLEBE_INCLUDE_CG_MEMLAYOUT_H
17 #define MAPLEBE_INCLUDE_CG_MEMLAYOUT_H
18 
19 /* C++ headers. */
20 #include <utility>
21 #include "becommon.h"
22 #include "mir_function.h"
23 #include "mir_nodes.h" /* StmtNode */
24 
25 namespace maplebe {
26 using regno_t = uint32;
27 enum MemSegmentKind : uint8 {
28     kMsUnknown,
29     /*
30      * Function arguments that are not passed through registers
31      * are passed to the callee through stack.
32      */
33     kMsArgsStkPassed,
34     /*
35      * In between MS_args_stackpassed and kMsArgsRegpassed,
36      * we store call-saved registers if any.
37      */
38     /*
39      * Args passed via registers according to the architecture-specific ABI
40      * may need be stored in stack.
41      * 1) In the unoptimized version, we implement a model (similar to GCC -O0)
42      *    where all the values are initially stored in the memory and
43      *    loaded into registers when needed, and stored back to the memory when
44      *    their uses are done.
45      * 2) In an optimized version, some register-passed values may need to be
46      *    spilled into memory. We allocate the space in this Memory segment.
47      *    (or we may allocate them in caller-saved; may be this is better...)
48      */
49     kMsArgsRegPassed,
50     /*
51      * GR/VR Save areas for unnamed arguments under vararg functions
52      */
53     kMsGrSaveArea,
54     kMsVrSaveArea,
55     /* local (auto) variables */
56     kMsRefLocals,
57     kMsLocals,
58     // segment which is accessed rarely
59     kMsCold,
60     kMsSpillReg,
61     /*
62      * In between kMsLocals and MS_args_to_stackpass, we allocate
63      * a register-spill area and space for caller-saved registers
64      */
65     /*
66      * When a function calls another which takes some arguments
67      * that cannot be passed through registers, it is the caller's
68      * responsibility to allocate space for those arguments in memory.
69      */
70     kMsArgsToStkPass,
71     /* The red zone stack area will not be modified by the exception signal. */
72     kMsRedZone,
73 };
74 
75 enum StackProtectKind : uint8 {
76     kNone = 0,
77     kAddrofStack = 0x1,
78     /* if a callee has return agg type which size over 16bytes */
79     kRetureStackSlot = 0x2,
80 };
81 
82 class CGFunc;
83 
84 /* keeps track of the allocation of a memory segment */
85 class MemSegment {
86 public:
MemSegment(MemSegmentKind memSegKind)87     explicit MemSegment(MemSegmentKind memSegKind) : kind(memSegKind), size(0) {}
88 
89     ~MemSegment() = default;
90 
GetSize()91     uint32 GetSize() const
92     {
93         return size;
94     }
95 
SetSize(uint32 memSize)96     void SetSize(uint32 memSize)
97     {
98         size = memSize;
99     }
100 
GetMemSegmentKind()101     MemSegmentKind GetMemSegmentKind() const
102     {
103         return kind;
104     }
105 
106 private:
107     MemSegmentKind kind;
108     uint32 size; /* size is negative if allocated offsets are negative */
109 };               /* class MemSegment */
110 
111 /* describes where a symbol is allocated */
112 class SymbolAlloc {
113 public:
114     SymbolAlloc() = default;
115 
116     ~SymbolAlloc() = default;
117 
GetMemSegment()118     const MemSegment *GetMemSegment() const
119     {
120         return memSegment;
121     }
122 
SetMemSegment(const MemSegment & memSeg)123     void SetMemSegment(const MemSegment &memSeg)
124     {
125         memSegment = &memSeg;
126     }
127 
GetOffset()128     int64 GetOffset() const
129     {
130         return offset;
131     }
132 
SetOffset(int64 off)133     void SetOffset(int64 off)
134     {
135         offset = off;
136     }
137 
138 protected:
139     const MemSegment *memSegment = nullptr;
140     int64 offset = 0;
141 }; /* class SymbolAlloc */
142 
143 class MemLayout {
144 public:
MemLayout(BECommon & beCommon,MIRFunction & mirFunc,MapleAllocator & mallocator,uint32 kStackPtrAlignment)145     MemLayout(BECommon &beCommon, MIRFunction &mirFunc, MapleAllocator &mallocator, uint32 kStackPtrAlignment)
146         : be(beCommon),
147           mirFunction(&mirFunc),
148           segArgsStkPassed(kMsArgsStkPassed),
149           segArgsRegPassed(kMsArgsRegPassed),
150           segArgsToStkPass(kMsArgsToStkPass),
151           symAllocTable(mallocator.Adapter()),
152           spillLocTable(mallocator.Adapter()),
153           spillRegLocMap(mallocator.Adapter()),
154           localRefLocMap(std::less<StIdx>(), mallocator.Adapter()),
155           memAllocator(&mallocator),
156           stackPtrAlignment(kStackPtrAlignment)
157     {
158         symAllocTable.resize(mirFunc.GetSymTab()->GetSymbolTableSize());
159     }
160 
161     virtual ~MemLayout() = default;
162 
SetCurrFunction(CGFunc & func)163     void SetCurrFunction(CGFunc &func)
164     {
165         cgFunc = &func;
166     }
167 
168     /*
169      * Returns stack space required for a call
170      * which is used to pass arguments that cannot be
171      * passed through registers
172      */
173     virtual uint32 ComputeStackSpaceRequirementForCall(StmtNode &stmtNode, int32 &aggCopySize, bool isIcall) = 0;
174 
175     /*
176      * Go over all outgoing calls in the function body and get the maximum space
177      * needed for storing the actuals based on the actual parameters and the ABI.
178      * These are usually those arguments that cannot be passed
179      * through registers because a call passes more than 8 arguments, or
180      * they cannot be fit in a pair of registers.
181      */
182     uint32 FindLargestActualArea(int32 &aggCopySize);
183 
184     virtual void LayoutStackFrame(int32 &structCopySize, int32 &maxParmStackSize) = 0;
185 
186     /*
187      * "Pseudo-registers can be regarded as local variables of a
188      * primitive type whose addresses are never taken"
189      */
190     virtual void AssignSpillLocationsToPseudoRegisters() = 0;
191 
GetCalleeSaveBaseLoc()192     virtual int32 GetCalleeSaveBaseLoc() const
193     {
194         return 0;
195     }
196 
GetSymAllocInfo(uint32 stIdx)197     SymbolAlloc *GetSymAllocInfo(uint32 stIdx)
198     {
199         DEBUG_ASSERT(stIdx < symAllocTable.size(), "out of symAllocTable's range");
200         return symAllocTable[stIdx];
201     }
202 
SetSymAllocInfo(uint32 stIdx,SymbolAlloc & symAlloc)203     void SetSymAllocInfo(uint32 stIdx, SymbolAlloc &symAlloc)
204     {
205         DEBUG_ASSERT(stIdx < symAllocTable.size(), "out of symAllocTable's range");
206         symAllocTable[stIdx] = &symAlloc;
207     }
208 
GetSpillLocOfPseduoRegister(PregIdx index)209     const SymbolAlloc *GetSpillLocOfPseduoRegister(PregIdx index) const
210     {
211         return spillLocTable.at(index);
212     }
213 
AssignLocationToSpillReg(regno_t vrNum,uint32 memByteSize)214     SymbolAlloc *AssignLocationToSpillReg(regno_t vrNum, uint32 memByteSize)
215     {
216         auto *symLoc = CreateSymbolAlloc();
217         symLoc->SetMemSegment(segSpillReg);
218         segSpillReg.SetSize(static_cast<uint32>(RoundUp(segSpillReg.GetSize(), memByteSize)));
219         symLoc->SetOffset(segSpillReg.GetSize());
220         segSpillReg.SetSize(segSpillReg.GetSize() + memByteSize);
221         SetSpillRegLocInfo(vrNum, *symLoc);
222         return symLoc;
223     }
224 
GetLocOfSpillRegister(regno_t vrNum,uint32 memByteSize)225     SymbolAlloc *GetLocOfSpillRegister(regno_t vrNum, uint32 memByteSize)
226     {
227         SymbolAlloc *loc = nullptr;
228         auto pos = spillRegLocMap.find(vrNum);
229         if (pos == spillRegLocMap.end()) {
230             loc = AssignLocationToSpillReg(vrNum, memByteSize);
231         } else {
232             loc = pos->second;
233         }
234         return loc;
235     }
236 
SizeOfArgsToStackPass()237     uint32 SizeOfArgsToStackPass() const
238     {
239         return segArgsToStkPass.GetSize();
240     }
241 
SizeOfArgsRegisterPassed()242     uint32 SizeOfArgsRegisterPassed() const
243     {
244         return segArgsRegPassed.GetSize();
245     }
246 
GetSizeOfSegCold()247     uint32 GetSizeOfSegCold() const
248     {
249         return segCold.GetSize();
250     }
251 
GetBECommon()252     BECommon &GetBECommon()
253     {
254         return be;
255     }
256 
GetMIRFunction()257     MIRFunction *GetMIRFunction()
258     {
259         return mirFunction;
260     }
261 
GetSegArgsStkPassed()262     const MemSegment &GetSegArgsStkPassed() const
263     {
264         return segArgsStkPassed;
265     }
266 
GetSegArgsRegPassed()267     const MemSegment &GetSegArgsRegPassed() const
268     {
269         return segArgsRegPassed;
270     }
271 
GetSegArgsToStkPass()272     const MemSegment &GetSegArgsToStkPass() const
273     {
274         return segArgsToStkPass;
275     }
276 
GetSymAllocTable()277     const MapleVector<SymbolAlloc *> &GetSymAllocTable() const
278     {
279         return symAllocTable;
280     }
281 
SetSpillRegLocInfo(regno_t regNum,SymbolAlloc & symAlloc)282     void SetSpillRegLocInfo(regno_t regNum, SymbolAlloc &symAlloc)
283     {
284         spillRegLocMap[regNum] = &symAlloc;
285     }
286 
GetLocalRefLocMap()287     const MapleMap<StIdx, SymbolAlloc *> &GetLocalRefLocMap() const
288     {
289         return localRefLocMap;
290     }
291 
SetLocalRegLocInfo(StIdx idx,SymbolAlloc & symAlloc)292     void SetLocalRegLocInfo(StIdx idx, SymbolAlloc &symAlloc)
293     {
294         localRefLocMap[idx] = &symAlloc;
295     }
296 
IsLocalRefLoc(const MIRSymbol & symbol)297     bool IsLocalRefLoc(const MIRSymbol &symbol) const
298     {
299         return localRefLocMap.find(symbol.GetStIdx()) != localRefLocMap.end();
300     }
301 
GetStackPtrAlignment()302     uint32 GetStackPtrAlignment() const
303     {
304         return stackPtrAlignment;
305     }
306 
307 protected:
308     BECommon &be;
309     MIRFunction *mirFunction;
310     MemSegment segArgsStkPassed;
311     MemSegment segArgsRegPassed;
312     MemSegment segArgsToStkPass;
313     MemSegment segCold = MemSegment(kMsCold);
314     MemSegment segSpillReg = MemSegment(kMsSpillReg);
315     MapleVector<SymbolAlloc *> symAllocTable; /* index is stindex from StIdx */
316     MapleVector<SymbolAlloc *> spillLocTable; /* index is preg idx */
317     MapleUnorderedMap<regno_t, SymbolAlloc *> spillRegLocMap;
318     MapleMap<StIdx, SymbolAlloc *> localRefLocMap; /* localrefvar formals. real address passed in stack. */
319     MapleAllocator *memAllocator;
320     CGFunc *cgFunc = nullptr;
321     const uint32 stackPtrAlignment;
322     virtual SymbolAlloc *CreateSymbolAlloc() const = 0;
323 };
324 } /* namespace maplebe */
325 
326 #endif /* MAPLEBE_INCLUDE_CG_MEMLAYOUT_H */
327