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