• 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 // This define the lowest level MAPLE IR data structures that are compatible
17 // with both the C++ and C coding environments of MAPLE
18 #ifndef MAPLE_INCLUDE_VM_CMPL_V2
19 #define MAPLE_INCLUDE_VM_CMPL_V2
20 // Still need constant value from MIR
21 #include <cstdint>
22 #include "mir_config.h"
23 #include "types_def.h"
24 #include "opcodes.h"
25 #include "prim_types.h"
26 #include "intrinsics.h"
27 #include "mir_module.h"
28 
29 namespace maple {
30 extern char appArray[];
31 constexpr uint32 kTwoBitVectors = 2;
32 struct MirFuncT {  // 28B
33     uint16 frameSize;
34     uint16 upFormalSize;
35     uint16 moduleID;
36     uint32 funcSize;               // size of code in words
37     uint8 *formalWordsTypetagged;  // bit vector where the Nth bit tells whether
38     // the Nth word in the formal parameters area
39     // addressed upward from %%FP (that means
40     // the word at location (%%FP + N*4)) has
41     // typetag; if yes, the typetag is the word
42     // at (%%FP + N*4 + 4); the bitvector's size
43     // is given by BlockSize2BitvectorSize(upFormalSize)
44     uint8 *localWordsTypetagged;  // bit vector where the Nth bit tells whether
45     // the Nth word in the local stack frame
46     // addressed downward from %%FP (that means
47     // the word at location (%%FP - N*4)) has
48     // typetag; if yes, the typetag is the word
49     // at (%%FP - N*4 + 4); the bitvector's size
50     // is given by BlockSize2BitvectorSize(frameSize)
51     uint8 *formalWordsRefCounted;  // bit vector where the Nth bit tells whether
52     // the Nth word in the formal parameters area
53     // addressed upward from %%FP (that means
54     // the word at location (%%FP + N*4)) points to
55     // a dynamic memory block that needs reference
56     // count; the bitvector's size is given by
57     // BlockSize2BitvectorSize(upFormalSize)
58     uint8 *localWordsRefCounted;  // bit vector where the Nth bit tells whether
59     // the Nth word in the local stack frame
60     // addressed downward from %%FP (that means
61     // the word at location (%%FP - N*4)) points to
62     // a dynamic memory block that needs reference
63     // count; the bitvector's size is given by
64     // BlockSize2BitvectorSize(frameSize)
65     // uint16 numlabels; // removed. label table size
66     // StmtNode **lbl2stmt; // lbl2stmt table, removed
67     // the first statement immediately follow MirFuncT
68     // since it starts with expression, BaseNodeT* is returned
FirstInstMirFuncT69     void *FirstInst() const
70     {
71         return reinterpret_cast<uint8 *>(const_cast<MirFuncT *>(this)) + sizeof(MirFuncT);
72     }
73 
74     // there are 4 bitvectors that follow the function code
FuncCodeSizeMirFuncT75     uint32 FuncCodeSize() const
76     {
77         return funcSize - (kTwoBitVectors * BlockSize2BitVectorSize(upFormalSize)) -
78                (kTwoBitVectors * BlockSize2BitVectorSize(frameSize));
79     }
80 };
81 
82 struct MirModuleT {
83 public:
84     MIRFlavor flavor;    // should be kCmpl
85     MIRSrcLang srcLang;  // the source language
86     uint16 id;
87     uint32 globalMemSize;  // size of storage space for all global variables
88     uint8 *globalBlkMap;   // the memory map of the block containing all the
89     // globals, for specifying static initializations
90     uint8 *globalWordsTypetagged;  // bit vector where the Nth bit tells whether
91     // the Nth word in globalBlkMap has typetag;
92     // if yes, the typetag is the N+1th word; the
93     // bitvector's size is given by
94     // BlockSize2BitvectorSize(globalMemSize)
95     uint8 *globalWordsRefCounted;  // bit vector where the Nth bit tells whether
96     // the Nth word points to a reference-counted
97     // dynamic memory block; the bitvector's size
98     // is given by BlockSize2BitvectorSize(globalMemSize)
99     PUIdx mainFuncID;          // the entry function; 0 if no main function
100     uint32 numFuncs;           // because puIdx 0 is reserved, numFuncs is also the highest puIdx
101     MirFuncT **funcs;          // list of all funcs in the module.
102 #if 1                          // the js2mpl buld always set HAVE_MMAP to 1 // binmir file mmap info
103     int binMirImageFd;         // file handle for mmap
104 #endif                         // HAVE_MMAP
105     void *binMirImageStart;    // binimage memory start
106     uint32 binMirImageLength;  // binimage memory size
FuncFromPuIdxMirModuleT107     MirFuncT *FuncFromPuIdx(PUIdx puIdx) const
108     {
109         MIR_ASSERT(puIdx <= numFuncs);  // puIdx starts from 1
110         return funcs[puIdx - 1];
111     }
112 
113     MirModuleT() = default;
114     ~MirModuleT() = default;
MainFuncMirModuleT115     MirFuncT *MainFunc() const
116     {
117         return (mainFuncID == 0) ? static_cast<MirFuncT *>(nullptr) : FuncFromPuIdx(mainFuncID);
118     }
119 
SetCurFunctionMirModuleT120     void SetCurFunction(MirFuncT *f)
121     {
122         curFunction = f;
123     }
124 
GetCurFunctionMirModuleT125     MirFuncT *GetCurFunction() const
126     {
127         return curFunction;
128     }
129 
GetSrcLangMirModuleT130     MIRSrcLang GetSrcLang() const
131     {
132         return srcLang;
133     }
134 
135 private:
136     MirFuncT *curFunction = nullptr;
137 };
138 
139 // At this stage, MirConstT don't need all information in MIRConst
140 // Note: only be used within Constval node:
141 // Warning: it's different from full feature MIR.
142 // only support 32bit int const (lower 32bit). higher 32bit are tags
143 union MirIntConstT {
144     int64 value;
145     uint32 val[2];  // ARM target load/store 2 32bit val instead of 1 64bit
146 };
147 
148 // currently in VM, only intconst are used.
149 using MirConstT = MirIntConstT;
150 //
151 // It's a stacking of POD data structure to allow precise memory layout
152 // control and emulate the inheritance relationship of corresponding C++
153 // data structures to keep the interface consistent (as much as possible).
154 //
155 // Rule:
156 // 1. base struct should be the first member (to allow safe pointer casting)
157 // 2. each node (just ops, no data) should be of either 4B or 8B.
158 // 3. casting the node to proper base type to access base type's fields.
159 //
160 // Current memory layout of nodes follows the postfix notation:
161 // Each operand instruction is positioned immediately before its parent or
162 // next operand. Memory layout of sub-expressions tree is done recursively.
163 // E.g. the code for (a + b) contains 3 instructions, starting with the READ a,
164 // READ b, and then followed by ADD.
165 // For (a + (b - c)), it is:
166 //
167 // READ a
168 // READ b
169 // READ c
170 // SUB
171 // ADD
172 //
173 // BaseNodeT is an abstraction of expression.
174 struct BaseNodeT {  // 4B
175     Opcode op;
176     PrimType ptyp;
177     uint8 typeFlag;  // a flag to speed up type related operations in the VM
178     uint8 numOpnds;  // only used for N-ary operators, switch and rangegoto
179     // operands immediately before each node
NumOpndsBaseNodeT180     virtual size_t NumOpnds() const
181     {
182         if (op == OP_switch || op == OP_rangegoto) {
183             return 1;
184         }
185         return numOpnds;
186     }
187 
GetNumOpndsBaseNodeT188     virtual uint8 GetNumOpnds() const
189     {
190         return numOpnds;
191     }
SetNumOpndsBaseNodeT192     virtual void SetNumOpnds(uint8 num)
193     {
194         numOpnds = num;
195     }
196 
GetOpCodeBaseNodeT197     virtual Opcode GetOpCode() const
198     {
199         return op;
200     }
201 
SetOpCodeBaseNodeT202     virtual void SetOpCode(Opcode o)
203     {
204         op = o;
205     }
206 
GetPrimTypeBaseNodeT207     virtual PrimType GetPrimType() const
208     {
209         return ptyp;
210     }
211 
SetPrimTypeBaseNodeT212     virtual void SetPrimType(PrimType type)
213     {
214         ptyp = type;
215     }
216 
BaseNodeTBaseNodeT217     BaseNodeT() : op(OP_undef), ptyp(kPtyInvalid), typeFlag(0), numOpnds(0) {}
218 
219     virtual ~BaseNodeT() = default;
220 };
221 
222 // typeFlag is a 8bit flag to provide short-cut information for its
223 // associated PrimType, because many type related information extraction
224 // is not very lightweight.
225 // Here is the convention:
226 // |  7  |  6  |  5  |  4  |  3  |  2  |  1  |  0  |
227 //   dyn    f     i     sc    c     (log2(size))
228 //
229 // bit 0 - bit 3 is for type size information. (now not used in VM?)
230 //   bit 0-2 represents the size of concrete types (not void/aggregate)
231 //   it's the result of log2 operation on the real size to fit in 3 bits.
232 //   which has the following correspondence:
233 //   | 2 | 1 | 0 |              type size (in Bytes)
234 //     0   0   0                      1
235 //     0   0   1                      2
236 //     0   1   0                      4
237 //     0   1   1                      8
238 //     1   0   0                     16
239 //
240 // bit 3 is the flag of "concrete types", i.e., types we know the type
241 // details.
242 // when it's 1, the bit0-2 size are valid
243 // when it's 0, the size of the type is 0, and bit0-2 are meaningless.
244 //
245 // bit 4 is for scalar types (1 if it's a scalar type)
246 // bit 5 is for integer types (1 if it's an integer type)
247 // bit 6 is for floating types (1 if it's a floating type)
248 // bit 7 is for dynamic types (1 if it's a dynamic type)
249 //
250 // refer to mirtypes.h/mirtypes.cpp in maple_ir directory for more information.
251 const int32 kTypeflagZero = 0x00;
252 const int32 kTypeflagDynMask = 0x80;
253 const int32 kTypeflagFloatMask = 0x40;
254 const int32 kTypeflagIntergerMask = 0x20;
255 const int32 kTypeflagScalarMask = 0x10;
256 const int32 kTypeflagConcreteMask = 0x08;
257 const int32 kTypeflagSizeMask = 0x07;
258 const int32 kTypeflagDynFloatMask = (kTypeflagDynMask | kTypeflagFloatMask);
259 const int32 kTypeflagDynIntergerMask = (kTypeflagDynMask | kTypeflagIntergerMask);
IsDynType(uint8 typeFlag)260 inline bool IsDynType(uint8 typeFlag)
261 {
262     return ((typeFlag & kTypeflagDynMask) != kTypeflagZero);
263 }
264 
IsDynFloat(uint8 typeFlag)265 inline bool IsDynFloat(uint8 typeFlag)
266 {
267     return ((typeFlag & kTypeflagDynFloatMask) == kTypeflagDynFloatMask);
268 }
269 
IsDynInteger(uint8 typeFlag)270 inline bool IsDynInteger(uint8 typeFlag)
271 {
272     return ((typeFlag & kTypeflagDynIntergerMask) == kTypeflagDynIntergerMask);
273 }
274 
275 // IsFloat means "is statically floating types", i.e., float, but not dynamic
IsFloat(uint8 typeFlag)276 inline bool IsFloat(uint8 typeFlag)
277 {
278     return ((typeFlag & kTypeflagDynFloatMask) == kTypeflagFloatMask);
279 }
280 
IsScalarType(uint8 typeFlag)281 inline bool IsScalarType(uint8 typeFlag)
282 {
283     return ((typeFlag & kTypeflagScalarMask) != kTypeflagZero);
284 }
285 
GetOpcode(const BaseNodeT & nodePtr)286 inline Opcode GetOpcode(const BaseNodeT &nodePtr)
287 {
288     return nodePtr.op;
289 }
290 
GetPrimType(const BaseNodeT & nodePtr)291 inline PrimType GetPrimType(const BaseNodeT &nodePtr)
292 {
293     return nodePtr.ptyp;
294 }
295 
GetOperandsNum(const BaseNodeT & nodePtr)296 inline uint32 GetOperandsNum(const BaseNodeT &nodePtr)
297 {
298     return nodePtr.numOpnds;
299 }
300 
301 using UnaryNodeT = BaseNodeT;             // alias
302 struct TypecvtNodeT : public BaseNodeT {  // 8B
303     PrimType fromPTyp;
304     uint8 fromTypeFlag;  // a flag to speed up type related operations
305     uint8 padding[2];
FromTypeTypecvtNodeT306     PrimType FromType() const
307     {
308         return fromPTyp;
309     }
310 };
311 
312 struct ExtractbitsNodeT : public BaseNodeT {  // 8B
313     uint8 bOffset;
314     uint8 bSize;
315     uint16 padding;
316 };
317 
318 using BinaryNodeT = BaseNodeT;
319 // Add expression types to compare node, to
320 // facilitate the evaluation of postorder stored kCmpl
321 // Note: the two operands should have the same type if they're
322 //       not dynamic types
323 struct CompareNodeT : public BaseNodeT {  // 8B
324     PrimType opndType;                    // type of operands.
325     uint8 opndTypeFlag;                   // typeFlag of opntype.
326     uint8 padding[2];                     // every compare node has two opnds.
327 };
328 
329 using NaryNodeT = BaseNodeT;
330 // need to guarantee MIRIntrinsicID is 4B
331 // Note: this is not supported by c++0x
332 struct IntrinsicopNodeT : public BaseNodeT {  // 8B
333     MIRIntrinsicID intrinsic;
334 };
335 
336 struct ConstvalNodeT : public BaseNodeT {  // 4B + 8B const value
ConstvalConstvalNodeT337     MirConstT *Constval() const
338     {
339         auto *tempPtr = const_cast<ConstvalNodeT *>(this);
340         return (reinterpret_cast<MirConstT *>(reinterpret_cast<uint8 *>(tempPtr) + sizeof(ConstvalNodeT)));
341     }
342 };
343 
344 // full MIR exported a pointer to MirConstT
GetConstval(const ConstvalNodeT & node)345 inline MirConstT *GetConstval(const ConstvalNodeT &node)
346 {
347     return node.Constval();
348 }
349 
350 // SizeoftypeNode shouldn't be seen here
351 struct AddrofNodeT : public BaseNodeT {  // 12B
352     StIdx stIdx;
353     FieldID fieldID;
354 };
355 
356 using DreadNodeT = AddrofNodeT;              // same shape.
357 
358 struct RegreadNodeT : public BaseNodeT {  // 8B
359     PregIdx regIdx;                       // 32bit, negative if special register
360 };
361 
362 }  // namespace maple
363 #endif  // MAPLE_INCLUDE_VM_CMPL_V2
364