/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 | 39.5M | : Offset(Off), Code(Byte) { |
57 | 39.5M | #if defined(__x86_64__) || defined(__aarch64__) || \ |
58 | 39.5M | (defined(__riscv) && __riscv_xlen == 64) || defined(__s390x__) |
59 | 39.5M | 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 | 39.5M | Flags.IsAllocLabelList = false; |
65 | 39.5M | Flags.IsAllocValTypeList = false; |
66 | 39.5M | Flags.IsAllocBrCast = false; |
67 | 39.5M | Flags.IsAllocTryCatch = false; |
68 | 39.5M | } |
69 | | |
70 | | /// Copy constructor. |
71 | | Instruction(const Instruction &Instr) noexcept |
72 | 12.1M | : Data(Instr.Data), Offset(Instr.Offset), Code(Instr.Code), |
73 | 12.1M | Flags(Instr.Flags) { |
74 | 12.1M | if (Flags.IsAllocLabelList) { |
75 | 6.70k | Data.BrTable.LabelList = new JumpDescriptor[Data.BrTable.LabelListSize]; |
76 | 6.70k | std::copy_n(Instr.Data.BrTable.LabelList, Data.BrTable.LabelListSize, |
77 | 6.70k | Data.BrTable.LabelList); |
78 | 12.1M | } else if (Flags.IsAllocValTypeList) { |
79 | 903 | Data.SelectT.ValTypeList = new ValType[Data.SelectT.ValTypeListSize]; |
80 | 903 | std::copy_n(Instr.Data.SelectT.ValTypeList, Data.SelectT.ValTypeListSize, |
81 | 903 | Data.SelectT.ValTypeList); |
82 | 12.1M | } else if (Flags.IsAllocBrCast) { |
83 | 1.13k | Data.BrCast = new BrCastDescriptor(*Instr.Data.BrCast); |
84 | 12.1M | } else if (Flags.IsAllocTryCatch) { |
85 | 1.31k | Data.TryCatch = new TryDescriptor(*Instr.Data.TryCatch); |
86 | 1.31k | } |
87 | 12.1M | } |
88 | | |
89 | | /// Move constructor. |
90 | | Instruction(Instruction &&Instr) noexcept |
91 | 55.0M | : Data(Instr.Data), Offset(Instr.Offset), Code(Instr.Code), |
92 | 55.0M | Flags(Instr.Flags) { |
93 | 55.0M | Instr.Flags.IsAllocLabelList = false; |
94 | 55.0M | Instr.Flags.IsAllocValTypeList = false; |
95 | 55.0M | Instr.Flags.IsAllocBrCast = false; |
96 | 55.0M | Instr.Flags.IsAllocTryCatch = false; |
97 | 55.0M | } |
98 | | |
99 | | /// Destructor. |
100 | 106M | ~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 | 44.5M | OpCode getOpCode() const noexcept { return Code; } |
113 | | |
114 | | /// Getter for Offset. |
115 | 1.90k | uint32_t getOffset() const noexcept { return Offset; } |
116 | | |
117 | | /// Getter and setter for block type. |
118 | 17.5k | const BlockType &getBlockType() const noexcept { return Data.Blocks.ResType; } |
119 | 1.60M | BlockType &getBlockType() noexcept { return Data.Blocks.ResType; } |
120 | | |
121 | | /// Getter and setter for jump count to End instruction. |
122 | 10.3k | uint32_t getJumpEnd() const noexcept { return Data.Blocks.JumpEnd; } |
123 | 48.5k | void setJumpEnd(const uint32_t Cnt) noexcept { Data.Blocks.JumpEnd = Cnt; } |
124 | | |
125 | | /// Getter and setter for jump count to Else instruction. |
126 | 34.2k | uint32_t getJumpElse() const noexcept { return Data.Blocks.JumpElse; } |
127 | 24.5k | void setJumpElse(const uint32_t Cnt) noexcept { Data.Blocks.JumpElse = Cnt; } |
128 | | |
129 | | /// Getter and setter for value type. |
130 | 36.1k | const ValType &getValType() const noexcept { return Data.VType; } |
131 | 33.9k | void setValType(const ValType &VType) noexcept { Data.VType = VType; } |
132 | | |
133 | | /// Getter and setter for label list. |
134 | 24.5k | void setLabelListSize(uint32_t Size) { |
135 | 24.5k | reset(); |
136 | 24.5k | if (Size > 0) { |
137 | 24.5k | Data.BrTable.LabelListSize = Size; |
138 | 24.5k | Data.BrTable.LabelList = new JumpDescriptor[Size]; |
139 | 24.5k | Flags.IsAllocLabelList = true; |
140 | 24.5k | } |
141 | 24.5k | } |
142 | 929 | Span<const JumpDescriptor> getLabelList() const noexcept { |
143 | 929 | return Span<const JumpDescriptor>( |
144 | 929 | Data.BrTable.LabelList, |
145 | 929 | Flags.IsAllocLabelList ? Data.BrTable.LabelListSize : 0); |
146 | 929 | } |
147 | 237k | Span<JumpDescriptor> getLabelList() noexcept { |
148 | 237k | return Span<JumpDescriptor>( |
149 | 237k | Data.BrTable.LabelList, |
150 | 237k | Flags.IsAllocLabelList ? Data.BrTable.LabelListSize : 0); |
151 | 237k | } |
152 | | |
153 | | /// Getter and setter for expression end for End instruction. |
154 | 0 | bool isExprLast() const noexcept { return Data.EndFlags.IsExprLast; } |
155 | 79.4k | void setExprLast(bool Last = true) noexcept { |
156 | 79.4k | Data.EndFlags.IsExprLast = Last; |
157 | 79.4k | } |
158 | | |
159 | | /// Getter and setter for the try block end for End instruction. |
160 | 0 | bool isTryBlockLast() const noexcept { return Data.EndFlags.IsTryBlockLast; } |
161 | 47.1k | void setTryBlockLast(bool Last = true) noexcept { |
162 | 47.1k | Data.EndFlags.IsTryBlockLast = Last; |
163 | 47.1k | } |
164 | | |
165 | | /// Getter and setter for Jump for Br* instructions. |
166 | 5.51k | const JumpDescriptor &getJump() const noexcept { return Data.Jump; } |
167 | 252k | JumpDescriptor &getJump() noexcept { return Data.Jump; } |
168 | | |
169 | | /// Getter and setter for the selected value type list. |
170 | 6.05k | void setValTypeListSize(uint32_t Size) { |
171 | 6.05k | reset(); |
172 | 6.05k | if (Size > 0) { |
173 | 3.29k | Data.SelectT.ValTypeListSize = Size; |
174 | 3.29k | Data.SelectT.ValTypeList = new ValType[Size]; |
175 | 3.29k | Flags.IsAllocValTypeList = true; |
176 | 3.29k | } |
177 | 6.05k | } |
178 | 1.13k | Span<const ValType> getValTypeList() const noexcept { |
179 | 1.13k | return Span<const ValType>(Data.SelectT.ValTypeList, |
180 | 1.13k | Data.SelectT.ValTypeListSize); |
181 | 1.13k | } |
182 | 90.8k | Span<ValType> getValTypeList() noexcept { |
183 | 90.8k | return Span<ValType>(Data.SelectT.ValTypeList, |
184 | 90.8k | Data.SelectT.ValTypeListSize); |
185 | 90.8k | } |
186 | | |
187 | | /// Getter and setter for target index. |
188 | 255k | uint32_t getTargetIndex() const noexcept { return Data.Indices.TargetIdx; } |
189 | 2.14M | uint32_t &getTargetIndex() noexcept { return Data.Indices.TargetIdx; } |
190 | | |
191 | | /// Getter and setter for source index. |
192 | 4.19k | uint32_t getSourceIndex() const noexcept { return Data.Indices.SourceIdx; } |
193 | 122k | 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 | 22.7k | uint32_t &getStackOffset() noexcept { return Data.Indices.StackOffset; } |
198 | | |
199 | | /// Getter and setter for memory alignment. |
200 | 118k | uint32_t getMemoryAlign() const noexcept { return Data.Memories.MemAlign; } |
201 | 2.52M | uint32_t &getMemoryAlign() noexcept { return Data.Memories.MemAlign; } |
202 | | |
203 | | /// Getter for memory offset. |
204 | 70.0k | uint64_t getMemoryOffset() const noexcept { return Data.Memories.MemOffset; } |
205 | 794k | uint64_t &getMemoryOffset() noexcept { return Data.Memories.MemOffset; } |
206 | | |
207 | | /// Getter for memory lane. |
208 | 15.2k | uint8_t getMemoryLane() const noexcept { return Flags.MemLane; } |
209 | 80.0k | uint8_t &getMemoryLane() noexcept { return Flags.MemLane; } |
210 | | |
211 | | /// Getter and setter for the constant value. |
212 | 632k | ValVariant getNum() const noexcept { |
213 | 632k | #if defined(__x86_64__) || defined(__aarch64__) || \ |
214 | 632k | (defined(__riscv) && __riscv_xlen == 64) || defined(__s390x__) |
215 | 632k | return ValVariant(Data.Num); |
216 | | #else |
217 | | uint128_t N{Data.Num.High, Data.Num.Low}; |
218 | | return ValVariant(N); |
219 | | #endif |
220 | 632k | } |
221 | 8.77M | void setNum(ValVariant N) noexcept { |
222 | 8.77M | #if defined(__x86_64__) || defined(__aarch64__) || \ |
223 | 8.77M | (defined(__riscv) && __riscv_xlen == 64) || defined(__s390x__) |
224 | 8.77M | 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 | 8.77M | } |
231 | | |
232 | | /// Getter and setter for BrCast info for Br_cast instructions. |
233 | 2.80k | void setBrCast(uint32_t LabelIdx) { |
234 | 2.80k | reset(); |
235 | 2.80k | Data.BrCast = new BrCastDescriptor(); |
236 | 2.80k | Data.BrCast->Jump.TargetIndex = LabelIdx; |
237 | 2.80k | Flags.IsAllocBrCast = true; |
238 | 2.80k | } |
239 | 108 | const BrCastDescriptor &getBrCast() const noexcept { return *Data.BrCast; } |
240 | 5.58k | BrCastDescriptor &getBrCast() noexcept { return *Data.BrCast; } |
241 | | |
242 | | /// Getter and setter for try block info for try_table instruction. |
243 | 5.92k | void setTryCatch() { |
244 | 5.92k | reset(); |
245 | 5.92k | Data.TryCatch = new TryDescriptor(); |
246 | 5.92k | Flags.IsAllocTryCatch = true; |
247 | 5.92k | } |
248 | 188 | const TryDescriptor &getTryCatch() const noexcept { return *Data.TryCatch; } |
249 | 20.0k | TryDescriptor &getTryCatch() noexcept { return *Data.TryCatch; } |
250 | | |
251 | | private: |
252 | | /// Release allocated resources. |
253 | 106M | void reset() noexcept { |
254 | 106M | if (Flags.IsAllocLabelList) { |
255 | 31.2k | Data.BrTable.LabelListSize = 0; |
256 | 31.2k | delete[] Data.BrTable.LabelList; |
257 | 106M | } else if (Flags.IsAllocValTypeList) { |
258 | 4.19k | Data.SelectT.ValTypeListSize = 0; |
259 | 4.19k | delete[] Data.SelectT.ValTypeList; |
260 | 106M | } else if (Flags.IsAllocBrCast) { |
261 | 3.93k | delete Data.BrCast; |
262 | 106M | } else if (Flags.IsAllocTryCatch) { |
263 | 7.23k | delete Data.TryCatch; |
264 | 7.23k | } |
265 | 106M | Flags.IsAllocLabelList = false; |
266 | 106M | Flags.IsAllocValTypeList = false; |
267 | 106M | Flags.IsAllocBrCast = false; |
268 | 106M | Flags.IsAllocTryCatch = false; |
269 | 106M | } |
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 |