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