/src/WasmEdge/include/ast/instruction.h
Line | Count | Source |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // SPDX-FileCopyrightText: Copyright The WasmEdge Authors |
3 | | |
4 | | //===-- wasmedge/ast/instruction.h - Instruction class definition ---------===// |
5 | | // |
6 | | // Part of the WasmEdge Project. |
7 | | // |
8 | | //===----------------------------------------------------------------------===// |
9 | | /// |
10 | | /// \file |
11 | | /// This file contains the declaration of the Instruction node class. |
12 | | /// |
13 | | //===----------------------------------------------------------------------===// |
14 | | #pragma once |
15 | | |
16 | | #include "common/enum_ast.hpp" |
17 | | #include "common/span.h" |
18 | | #include "common/types.h" |
19 | | |
20 | | #include <algorithm> |
21 | | #include <vector> |
22 | | |
23 | | namespace WasmEdge { |
24 | | namespace AST { |
25 | | |
26 | | /// Instruction node class. |
27 | | class Instruction { |
28 | | public: |
29 | | struct JumpDescriptor { |
30 | | uint32_t TargetIndex; |
31 | | uint32_t StackEraseBegin; |
32 | | uint32_t StackEraseEnd; |
33 | | int32_t PCOffset; |
34 | | }; |
35 | | struct BrCastDescriptor { |
36 | | struct JumpDescriptor Jump; |
37 | | ValType RType1, RType2; |
38 | | }; |
39 | | struct CatchDescriptor { |
40 | | bool IsAll : 1; |
41 | | bool IsRef : 1; |
42 | | uint32_t TagIndex; |
43 | | uint32_t LabelIndex; |
44 | | struct JumpDescriptor Jump; |
45 | | }; |
46 | | struct TryDescriptor { |
47 | | BlockType ResType; |
48 | | uint32_t BlockParamNum; |
49 | | uint32_t JumpEnd; |
50 | | std::vector<CatchDescriptor> Catch; |
51 | | }; |
52 | | |
53 | | public: |
54 | | /// Constructor assigns the OpCode and the Offset. |
55 | | Instruction(OpCode Byte, uint32_t Off = 0) noexcept |
56 | 11.0M | : Offset(Off), Code(Byte) { |
57 | 11.0M | #if defined(__x86_64__) || defined(__aarch64__) || \ |
58 | 11.0M | (defined(__riscv) && __riscv_xlen == 64) || defined(__s390x__) |
59 | 11.0M | Data.Num = static_cast<uint128_t>(0); |
60 | | #else |
61 | | Data.Num.Low = static_cast<uint64_t>(0); |
62 | | Data.Num.High = static_cast<uint64_t>(0); |
63 | | #endif |
64 | 11.0M | Flags.IsAllocLabelList = false; |
65 | 11.0M | Flags.IsAllocValTypeList = false; |
66 | 11.0M | Flags.IsAllocBrCast = false; |
67 | 11.0M | Flags.IsAllocTryCatch = false; |
68 | 11.0M | } |
69 | | |
70 | | /// Copy constructor. |
71 | | Instruction(const Instruction &Instr) noexcept |
72 | 3.00M | : Data(Instr.Data), Offset(Instr.Offset), Code(Instr.Code), |
73 | 3.00M | Flags(Instr.Flags) { |
74 | 3.00M | if (Flags.IsAllocLabelList) { |
75 | 4.99k | Data.BrTable.LabelList = new JumpDescriptor[Data.BrTable.LabelListSize]; |
76 | 4.99k | std::copy_n(Instr.Data.BrTable.LabelList, Data.BrTable.LabelListSize, |
77 | 4.99k | Data.BrTable.LabelList); |
78 | 2.99M | } else if (Flags.IsAllocValTypeList) { |
79 | 606 | Data.SelectT.ValTypeList = new ValType[Data.SelectT.ValTypeListSize]; |
80 | 606 | std::copy_n(Instr.Data.SelectT.ValTypeList, Data.SelectT.ValTypeListSize, |
81 | 606 | Data.SelectT.ValTypeList); |
82 | 2.99M | } else if (Flags.IsAllocBrCast) { |
83 | 751 | Data.BrCast = new BrCastDescriptor(*Instr.Data.BrCast); |
84 | 2.99M | } else if (Flags.IsAllocTryCatch) { |
85 | 12.2k | Data.TryCatch = new TryDescriptor(*Instr.Data.TryCatch); |
86 | 12.2k | } |
87 | 3.00M | } |
88 | | |
89 | | /// Move constructor. |
90 | | Instruction(Instruction &&Instr) noexcept |
91 | 15.9M | : Data(Instr.Data), Offset(Instr.Offset), Code(Instr.Code), |
92 | 15.9M | Flags(Instr.Flags) { |
93 | 15.9M | Instr.Flags.IsAllocLabelList = false; |
94 | 15.9M | Instr.Flags.IsAllocValTypeList = false; |
95 | 15.9M | Instr.Flags.IsAllocBrCast = false; |
96 | 15.9M | Instr.Flags.IsAllocTryCatch = false; |
97 | 15.9M | } |
98 | | |
99 | | /// Destructor. |
100 | 29.9M | ~Instruction() { reset(); } |
101 | | |
102 | | /// Copy assignment. |
103 | 0 | Instruction &operator=(const Instruction &Instr) { |
104 | 0 | if (this != &Instr) { |
105 | 0 | Instruction Tmp(Instr); |
106 | 0 | Tmp.swap(*this); |
107 | 0 | } |
108 | 0 | return *this; |
109 | 0 | } |
110 | | |
111 | | /// Getter for OpCode. |
112 | 16.1M | OpCode getOpCode() const noexcept { return Code; } |
113 | | |
114 | | /// Getter for Offset. |
115 | 1.73k | uint32_t getOffset() const noexcept { return Offset; } |
116 | | |
117 | | /// Getter and setter for block type. |
118 | 18.3k | const BlockType &getBlockType() const noexcept { return Data.Blocks.ResType; } |
119 | 828k | BlockType &getBlockType() noexcept { return Data.Blocks.ResType; } |
120 | | |
121 | | /// Getter and setter for jump count to End instruction. |
122 | 10.9k | uint32_t getJumpEnd() const noexcept { return Data.Blocks.JumpEnd; } |
123 | 34.1k | void setJumpEnd(const uint32_t Cnt) noexcept { Data.Blocks.JumpEnd = Cnt; } |
124 | | |
125 | | /// Getter and setter for jump count to Else instruction. |
126 | 21.2k | uint32_t getJumpElse() const noexcept { return Data.Blocks.JumpElse; } |
127 | 12.0k | void setJumpElse(const uint32_t Cnt) noexcept { Data.Blocks.JumpElse = Cnt; } |
128 | | |
129 | | /// Getter and setter for value type. |
130 | 46.0k | const ValType &getValType() const noexcept { return Data.VType; } |
131 | 37.4k | void setValType(const ValType &VType) noexcept { Data.VType = VType; } |
132 | | |
133 | | /// Getter and setter for label list. |
134 | 11.1k | void setLabelListSize(uint32_t Size) { |
135 | 11.1k | reset(); |
136 | 11.1k | if (Size > 0) { |
137 | 11.1k | Data.BrTable.LabelListSize = Size; |
138 | 11.1k | Data.BrTable.LabelList = new JumpDescriptor[Size]; |
139 | 11.1k | Flags.IsAllocLabelList = true; |
140 | 11.1k | } |
141 | 11.1k | } |
142 | 954 | Span<const JumpDescriptor> getLabelList() const noexcept { |
143 | 954 | return Span<const JumpDescriptor>( |
144 | 954 | Data.BrTable.LabelList, |
145 | 954 | Flags.IsAllocLabelList ? Data.BrTable.LabelListSize : 0); |
146 | 954 | } |
147 | 92.8k | Span<JumpDescriptor> getLabelList() noexcept { |
148 | 92.8k | return Span<JumpDescriptor>( |
149 | 92.8k | Data.BrTable.LabelList, |
150 | 92.8k | Flags.IsAllocLabelList ? Data.BrTable.LabelListSize : 0); |
151 | 92.8k | } |
152 | | |
153 | | /// Getter and setter for expression end for End instruction. |
154 | 0 | bool isExprLast() const noexcept { return Data.EndFlags.IsExprLast; } |
155 | 76.7k | void setExprLast(bool Last = true) noexcept { |
156 | 76.7k | Data.EndFlags.IsExprLast = Last; |
157 | 76.7k | } |
158 | | |
159 | | /// Getter and setter for the try block end for End instruction. |
160 | 0 | bool isTryBlockLast() const noexcept { return Data.EndFlags.IsTryBlockLast; } |
161 | 45.6k | void setTryBlockLast(bool Last = true) noexcept { |
162 | 45.6k | Data.EndFlags.IsTryBlockLast = Last; |
163 | 45.6k | } |
164 | | |
165 | | /// Getter and setter for Jump for Br* instructions. |
166 | 5.67k | const JumpDescriptor &getJump() const noexcept { return Data.Jump; } |
167 | 20.7k | JumpDescriptor &getJump() noexcept { return Data.Jump; } |
168 | | |
169 | | /// Getter and setter for the selected value type list. |
170 | 1.65k | void setValTypeListSize(uint32_t Size) { |
171 | 1.65k | reset(); |
172 | 1.65k | if (Size > 0) { |
173 | 1.27k | Data.SelectT.ValTypeListSize = Size; |
174 | 1.27k | Data.SelectT.ValTypeList = new ValType[Size]; |
175 | 1.27k | Flags.IsAllocValTypeList = true; |
176 | 1.27k | } |
177 | 1.65k | } |
178 | 1.12k | Span<const ValType> getValTypeList() const noexcept { |
179 | 1.12k | return Span<const ValType>(Data.SelectT.ValTypeList, |
180 | 1.12k | Data.SelectT.ValTypeListSize); |
181 | 1.12k | } |
182 | 59.2k | Span<ValType> getValTypeList() noexcept { |
183 | 59.2k | return Span<ValType>(Data.SelectT.ValTypeList, |
184 | 59.2k | Data.SelectT.ValTypeListSize); |
185 | 59.2k | } |
186 | | |
187 | | /// Getter and setter for target index. |
188 | 267k | uint32_t getTargetIndex() const noexcept { return Data.Indices.TargetIdx; } |
189 | 331k | uint32_t &getTargetIndex() noexcept { return Data.Indices.TargetIdx; } |
190 | | |
191 | | /// Getter and setter for source index. |
192 | 5.39k | uint32_t getSourceIndex() const noexcept { return Data.Indices.SourceIdx; } |
193 | 51.1k | uint32_t &getSourceIndex() noexcept { return Data.Indices.SourceIdx; } |
194 | | |
195 | | /// Getter and setter for stack offset. |
196 | 0 | uint32_t getStackOffset() const noexcept { return Data.Indices.StackOffset; } |
197 | 23.5k | uint32_t &getStackOffset() noexcept { return Data.Indices.StackOffset; } |
198 | | |
199 | | /// Getter and setter for memory alignment. |
200 | 124k | uint32_t getMemoryAlign() const noexcept { return Data.Memories.MemAlign; } |
201 | 503k | uint32_t &getMemoryAlign() noexcept { return Data.Memories.MemAlign; } |
202 | | |
203 | | /// Getter for memory offset. |
204 | 73.6k | uint64_t getMemoryOffset() const noexcept { return Data.Memories.MemOffset; } |
205 | 167k | uint64_t &getMemoryOffset() noexcept { return Data.Memories.MemOffset; } |
206 | | |
207 | | /// Getter for memory lane. |
208 | 15.6k | uint8_t getMemoryLane() const noexcept { return Flags.MemLane; } |
209 | 53.8k | uint8_t &getMemoryLane() noexcept { return Flags.MemLane; } |
210 | | |
211 | | /// Getter and setter for the constant value. |
212 | 716k | ValVariant getNum() const noexcept { |
213 | 716k | #if defined(__x86_64__) || defined(__aarch64__) || \ |
214 | 716k | (defined(__riscv) && __riscv_xlen == 64) || defined(__s390x__) |
215 | 716k | return ValVariant(Data.Num); |
216 | | #else |
217 | | uint128_t N{Data.Num.High, Data.Num.Low}; |
218 | | return ValVariant(N); |
219 | | #endif |
220 | 716k | } |
221 | 5.45M | void setNum(ValVariant N) noexcept { |
222 | 5.45M | #if defined(__x86_64__) || defined(__aarch64__) || \ |
223 | 5.45M | (defined(__riscv) && __riscv_xlen == 64) || defined(__s390x__) |
224 | 5.45M | Data.Num = N.get<uint128_t>(); |
225 | | #else |
226 | | uint128_t V = N.get<uint128_t>(); |
227 | | Data.Num.Low = V.low(); |
228 | | Data.Num.High = V.high(); |
229 | | #endif |
230 | 5.45M | } |
231 | | |
232 | | /// Getter and setter for BrCast info for Br_cast instructions. |
233 | 1.65k | void setBrCast(uint32_t LabelIdx) { |
234 | 1.65k | reset(); |
235 | 1.65k | Data.BrCast = new BrCastDescriptor(); |
236 | 1.65k | Data.BrCast->Jump.TargetIndex = LabelIdx; |
237 | 1.65k | Flags.IsAllocBrCast = true; |
238 | 1.65k | } |
239 | 157 | const BrCastDescriptor &getBrCast() const noexcept { return *Data.BrCast; } |
240 | 3.31k | BrCastDescriptor &getBrCast() noexcept { return *Data.BrCast; } |
241 | | |
242 | | /// Getter and setter for try block info for try_table instruction. |
243 | 14.5k | void setTryCatch() { |
244 | 14.5k | reset(); |
245 | 14.5k | Data.TryCatch = new TryDescriptor(); |
246 | 14.5k | Flags.IsAllocTryCatch = true; |
247 | 14.5k | } |
248 | 297 | const TryDescriptor &getTryCatch() const noexcept { return *Data.TryCatch; } |
249 | 46.4k | TryDescriptor &getTryCatch() noexcept { return *Data.TryCatch; } |
250 | | |
251 | | private: |
252 | | /// Release allocated resources. |
253 | 30.0M | void reset() noexcept { |
254 | 30.0M | if (Flags.IsAllocLabelList) { |
255 | 16.1k | Data.BrTable.LabelListSize = 0; |
256 | 16.1k | delete[] Data.BrTable.LabelList; |
257 | 30.0M | } else if (Flags.IsAllocValTypeList) { |
258 | 1.88k | Data.SelectT.ValTypeListSize = 0; |
259 | 1.88k | delete[] Data.SelectT.ValTypeList; |
260 | 30.0M | } else if (Flags.IsAllocBrCast) { |
261 | 2.40k | delete Data.BrCast; |
262 | 30.0M | } else if (Flags.IsAllocTryCatch) { |
263 | 26.7k | delete Data.TryCatch; |
264 | 26.7k | } |
265 | 30.0M | Flags.IsAllocLabelList = false; |
266 | 30.0M | Flags.IsAllocValTypeList = false; |
267 | 30.0M | Flags.IsAllocBrCast = false; |
268 | 30.0M | Flags.IsAllocTryCatch = false; |
269 | 30.0M | } |
270 | | |
271 | | /// Swap function. |
272 | 0 | void swap(Instruction &Instr) noexcept { |
273 | 0 | std::swap(Data, Instr.Data); |
274 | 0 | std::swap(Offset, Instr.Offset); |
275 | 0 | std::swap(Code, Instr.Code); |
276 | 0 | std::swap(Flags, Instr.Flags); |
277 | 0 | } |
278 | | |
279 | | /// \name Data of instructions. |
280 | | /// @{ |
281 | | union Inner { |
282 | | // Type 1: BlockType, JumpEnd, and JumpElse. |
283 | | struct { |
284 | | uint32_t JumpEnd; |
285 | | uint32_t JumpElse; |
286 | | BlockType ResType; |
287 | | } Blocks; |
288 | | // Type 2: TargetIdx, SourceIdx and StackOffset. |
289 | | struct { |
290 | | uint32_t TargetIdx; |
291 | | uint32_t SourceIdx; |
292 | | uint32_t StackOffset; |
293 | | } Indices; |
294 | | // Type 3: Jump. |
295 | | JumpDescriptor Jump; |
296 | | // Type 4: LabelList. |
297 | | struct { |
298 | | uint32_t LabelListSize; |
299 | | JumpDescriptor *LabelList; |
300 | | } BrTable; |
301 | | // Type 5: ValType. |
302 | | ValType VType; |
303 | | // Type 6: ValTypeList. |
304 | | struct { |
305 | | uint32_t ValTypeListSize; |
306 | | ValType *ValTypeList; |
307 | | } SelectT; |
308 | | // Type 7: TargetIdx, MemAlign, MemOffset. |
309 | | struct { |
310 | | uint32_t TargetIdx; |
311 | | uint32_t MemAlign; |
312 | | uint64_t MemOffset; |
313 | | // To keep the inner data union at 16 bytes and avoid allocating this |
314 | | // struct (memory instructions may have high density in instruction |
315 | | // sequences), the `MemLane` member is kept outside this struct. |
316 | | } Memories; |
317 | | // Type 8: Num. |
318 | | #if defined(__x86_64__) || defined(__aarch64__) || \ |
319 | | (defined(__riscv) && __riscv_xlen == 64) || defined(__s390x__) |
320 | | uint128_t Num; |
321 | | #else |
322 | | struct { |
323 | | uint64_t Low; |
324 | | uint64_t High; |
325 | | } Num; |
326 | | #endif |
327 | | // Type 9: End flags. |
328 | | struct { |
329 | | bool IsExprLast : 1; |
330 | | bool IsTryBlockLast : 1; |
331 | | } EndFlags; |
332 | | // Type 10: TypeCastBranch. |
333 | | BrCastDescriptor *BrCast; |
334 | | // Type 11: Try Block. |
335 | | TryDescriptor *TryCatch; |
336 | | } Data; |
337 | | uint32_t Offset = 0; |
338 | | OpCode Code = OpCode::End; |
339 | | struct { |
340 | | // Memory lane data for memory instructions. |
341 | | uint8_t MemLane; |
342 | | // Flags of if allocating something in this instance. |
343 | | bool IsAllocLabelList : 1; |
344 | | bool IsAllocValTypeList : 1; |
345 | | bool IsAllocBrCast : 1; |
346 | | bool IsAllocTryCatch : 1; |
347 | | } Flags; |
348 | | /// @} |
349 | | }; |
350 | | |
351 | | // Type aliasing |
352 | | using InstrVec = std::vector<Instruction>; |
353 | | using InstrView = Span<const Instruction>; |
354 | | |
355 | | } // namespace AST |
356 | | } // namespace WasmEdge |