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