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