/src/WasmEdge/lib/llvm/compiler/memoryInstr.cpp
Line | Count | Source |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // SPDX-FileCopyrightText: Copyright The WasmEdge Authors |
3 | | |
4 | | #include "compiler/function_compiler.h" |
5 | | |
6 | | namespace WasmEdge { |
7 | | |
8 | | Expect<void> |
9 | 647k | FunctionCompiler::compileMemoryOp(const AST::Instruction &Instr) noexcept { |
10 | 647k | switch (Instr.getOpCode()) { |
11 | 1.18k | case OpCode::I32__load: |
12 | 1.18k | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
13 | 1.18k | Instr.getMemoryAlign(), Context.Int32Ty); |
14 | 1.18k | break; |
15 | 3.23k | case OpCode::I64__load: |
16 | 3.23k | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
17 | 3.23k | Instr.getMemoryAlign(), Context.Int64Ty); |
18 | 3.23k | break; |
19 | 108 | case OpCode::F32__load: |
20 | 108 | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
21 | 108 | Instr.getMemoryAlign(), Context.FloatTy); |
22 | 108 | break; |
23 | 223 | case OpCode::F64__load: |
24 | 223 | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
25 | 223 | Instr.getMemoryAlign(), Context.DoubleTy); |
26 | 223 | break; |
27 | 666 | case OpCode::I32__load8_s: |
28 | 666 | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
29 | 666 | Instr.getMemoryAlign(), Context.Int8Ty, Context.Int32Ty, |
30 | 666 | true); |
31 | 666 | break; |
32 | 398 | case OpCode::I32__load8_u: |
33 | 398 | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
34 | 398 | Instr.getMemoryAlign(), Context.Int8Ty, Context.Int32Ty, |
35 | 398 | false); |
36 | 398 | break; |
37 | 293 | case OpCode::I32__load16_s: |
38 | 293 | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
39 | 293 | Instr.getMemoryAlign(), Context.Int16Ty, Context.Int32Ty, |
40 | 293 | true); |
41 | 293 | break; |
42 | 1.55k | case OpCode::I32__load16_u: |
43 | 1.55k | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
44 | 1.55k | Instr.getMemoryAlign(), Context.Int16Ty, Context.Int32Ty, |
45 | 1.55k | false); |
46 | 1.55k | break; |
47 | 749 | case OpCode::I64__load8_s: |
48 | 749 | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
49 | 749 | Instr.getMemoryAlign(), Context.Int8Ty, Context.Int64Ty, |
50 | 749 | true); |
51 | 749 | break; |
52 | 435 | case OpCode::I64__load8_u: |
53 | 435 | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
54 | 435 | Instr.getMemoryAlign(), Context.Int8Ty, Context.Int64Ty, |
55 | 435 | false); |
56 | 435 | break; |
57 | 402 | case OpCode::I64__load16_s: |
58 | 402 | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
59 | 402 | Instr.getMemoryAlign(), Context.Int16Ty, Context.Int64Ty, |
60 | 402 | true); |
61 | 402 | break; |
62 | 554 | case OpCode::I64__load16_u: |
63 | 554 | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
64 | 554 | Instr.getMemoryAlign(), Context.Int16Ty, Context.Int64Ty, |
65 | 554 | false); |
66 | 554 | break; |
67 | 403 | case OpCode::I64__load32_s: |
68 | 403 | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
69 | 403 | Instr.getMemoryAlign(), Context.Int32Ty, Context.Int64Ty, |
70 | 403 | true); |
71 | 403 | break; |
72 | 477 | case OpCode::I64__load32_u: |
73 | 477 | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
74 | 477 | Instr.getMemoryAlign(), Context.Int32Ty, Context.Int64Ty, |
75 | 477 | false); |
76 | 477 | break; |
77 | 387 | case OpCode::I32__store: |
78 | 387 | compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
79 | 387 | Instr.getMemoryAlign(), Context.Int32Ty); |
80 | 387 | break; |
81 | 1.55k | case OpCode::I64__store: |
82 | 1.55k | compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
83 | 1.55k | Instr.getMemoryAlign(), Context.Int64Ty); |
84 | 1.55k | break; |
85 | 60 | case OpCode::F32__store: |
86 | 60 | compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
87 | 60 | Instr.getMemoryAlign(), Context.FloatTy); |
88 | 60 | break; |
89 | 42 | case OpCode::F64__store: |
90 | 42 | compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
91 | 42 | Instr.getMemoryAlign(), Context.DoubleTy); |
92 | 42 | break; |
93 | 278 | case OpCode::I32__store8: |
94 | 295 | case OpCode::I64__store8: |
95 | 295 | compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
96 | 295 | Instr.getMemoryAlign(), Context.Int8Ty, true); |
97 | 295 | break; |
98 | 233 | case OpCode::I32__store16: |
99 | 300 | case OpCode::I64__store16: |
100 | 300 | compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
101 | 300 | Instr.getMemoryAlign(), Context.Int16Ty, true); |
102 | 300 | break; |
103 | 28 | case OpCode::I64__store32: |
104 | 28 | compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
105 | 28 | Instr.getMemoryAlign(), Context.Int32Ty, true); |
106 | 28 | break; |
107 | 698 | case OpCode::Memory__size: |
108 | 698 | stackPush(Builder.createTrunc( |
109 | 698 | Context.getMemorySize(Builder, ExecCtx, Instr.getTargetIndex()), |
110 | 698 | Context.MemoryAddrTypes[Instr.getTargetIndex()])); |
111 | 698 | break; |
112 | 819 | case OpCode::Memory__grow: { |
113 | 819 | auto NewPageSize = Builder.createZExt(stackPop(), Context.Int64Ty); |
114 | 819 | stackPush(Builder.createTrunc( |
115 | 819 | Builder.createCall( |
116 | 819 | Context.getIntrinsic( |
117 | 819 | Builder, Executable::Intrinsics::kMemGrow, |
118 | 819 | LLVM::Type::getFunctionType(Context.Int64Ty, |
119 | 819 | {Context.Int32Ty, Context.Int64Ty}, |
120 | 819 | false)), |
121 | 819 | {LLContext.getInt32(Instr.getTargetIndex()), NewPageSize}), |
122 | 819 | Context.MemoryAddrTypes[Instr.getTargetIndex()])); |
123 | 819 | break; |
124 | 233 | } |
125 | 23 | case OpCode::Memory__init: { |
126 | 23 | auto Len = stackPop(); |
127 | 23 | auto Src = stackPop(); |
128 | 23 | auto Dst = Builder.createZExt(stackPop(), Context.Int64Ty); |
129 | 23 | Builder.createCall( |
130 | 23 | Context.getIntrinsic( |
131 | 23 | Builder, Executable::Intrinsics::kMemInit, |
132 | 23 | LLVM::Type::getFunctionType(Context.VoidTy, |
133 | 23 | {Context.Int32Ty, Context.Int32Ty, |
134 | 23 | Context.Int64Ty, Context.Int32Ty, |
135 | 23 | Context.Int32Ty}, |
136 | 23 | false)), |
137 | 23 | {LLContext.getInt32(Instr.getTargetIndex()), |
138 | 23 | LLContext.getInt32(Instr.getSourceIndex()), Dst, Src, Len}); |
139 | 23 | break; |
140 | 233 | } |
141 | 22 | case OpCode::Data__drop: { |
142 | 22 | Builder.createCall( |
143 | 22 | Context.getIntrinsic(Builder, Executable::Intrinsics::kDataDrop, |
144 | 22 | LLVM::Type::getFunctionType( |
145 | 22 | Context.VoidTy, {Context.Int32Ty}, false)), |
146 | 22 | {LLContext.getInt32(Instr.getTargetIndex())}); |
147 | 22 | break; |
148 | 233 | } |
149 | 248 | case OpCode::Memory__copy: { |
150 | 248 | auto Len = Builder.createZExt(stackPop(), Context.Int64Ty); |
151 | 248 | auto Src = Builder.createZExt(stackPop(), Context.Int64Ty); |
152 | 248 | auto Dst = Builder.createZExt(stackPop(), Context.Int64Ty); |
153 | 248 | Builder.createCall( |
154 | 248 | Context.getIntrinsic( |
155 | 248 | Builder, Executable::Intrinsics::kMemCopy, |
156 | 248 | LLVM::Type::getFunctionType(Context.VoidTy, |
157 | 248 | {Context.Int32Ty, Context.Int32Ty, |
158 | 248 | Context.Int64Ty, Context.Int64Ty, |
159 | 248 | Context.Int64Ty}, |
160 | 248 | false)), |
161 | 248 | {LLContext.getInt32(Instr.getTargetIndex()), |
162 | 248 | LLContext.getInt32(Instr.getSourceIndex()), Dst, Src, Len}); |
163 | 248 | break; |
164 | 233 | } |
165 | 632 | case OpCode::Memory__fill: { |
166 | 632 | auto Len = Builder.createZExt(stackPop(), Context.Int64Ty); |
167 | 632 | auto Val = Builder.createTrunc(stackPop(), Context.Int8Ty); |
168 | 632 | auto Off = Builder.createZExt(stackPop(), Context.Int64Ty); |
169 | 632 | Builder.createCall( |
170 | 632 | Context.getIntrinsic( |
171 | 632 | Builder, Executable::Intrinsics::kMemFill, |
172 | 632 | LLVM::Type::getFunctionType(Context.VoidTy, |
173 | 632 | {Context.Int32Ty, Context.Int64Ty, |
174 | 632 | Context.Int8Ty, Context.Int64Ty}, |
175 | 632 | false)), |
176 | 632 | {LLContext.getInt32(Instr.getTargetIndex()), Off, Val, Len}); |
177 | 632 | break; |
178 | 233 | } |
179 | | |
180 | | // Const Numeric Instructions |
181 | 542k | case OpCode::I32__const: |
182 | 542k | stackPush(LLContext.getInt32(Instr.getNum().get<uint32_t>())); |
183 | 542k | break; |
184 | 69.1k | case OpCode::I64__const: |
185 | 69.1k | stackPush(LLContext.getInt64(Instr.getNum().get<uint64_t>())); |
186 | 69.1k | break; |
187 | 13.8k | case OpCode::F32__const: |
188 | 13.8k | stackPush(LLContext.getFloat(Instr.getNum().get<float>())); |
189 | 13.8k | break; |
190 | 6.56k | case OpCode::F64__const: |
191 | 6.56k | stackPush(LLContext.getDouble(Instr.getNum().get<double>())); |
192 | 6.56k | break; |
193 | | |
194 | 0 | default: |
195 | 0 | assumingUnreachable(); |
196 | 647k | } |
197 | 647k | return {}; |
198 | 647k | } |
199 | | |
200 | | void FunctionCompiler::compileLoadOp(unsigned MemoryIndex, uint64_t Offset, |
201 | | unsigned Alignment, |
202 | 18.2k | LLVM::Type LoadTy) noexcept { |
203 | 18.2k | if constexpr (LLVM::kForceUnalignment) { |
204 | 18.2k | Alignment = 0; |
205 | 18.2k | } |
206 | 18.2k | auto Off = Builder.createZExt(stackPop(), Context.Int64Ty); |
207 | 18.2k | if (Offset != 0) { |
208 | 11.7k | Off = Builder.createAdd(Off, LLContext.getInt64(Offset)); |
209 | 11.7k | } |
210 | | |
211 | 18.2k | auto VPtr = Builder.createInBoundsGEP1( |
212 | 18.2k | Context.Int8Ty, Context.getMemory(Builder, ExecCtx, MemoryIndex), Off); |
213 | 18.2k | auto Ptr = Builder.createBitCast(VPtr, LoadTy.getPointerTo()); |
214 | 18.2k | auto LoadInst = Builder.createLoad(LoadTy, Ptr, true); |
215 | 18.2k | LoadInst.setAlignment(1 << Alignment); |
216 | 18.2k | stackPush(switchEndian(LoadInst)); |
217 | 18.2k | } |
218 | | |
219 | | void FunctionCompiler::compileLoadOp(unsigned MemoryIndex, uint64_t Offset, |
220 | | unsigned Alignment, LLVM::Type LoadTy, |
221 | | LLVM::Type ExtendTy, |
222 | 7.55k | bool Signed) noexcept { |
223 | 7.55k | compileLoadOp(MemoryIndex, Offset, Alignment, LoadTy); |
224 | 7.55k | if (Signed) { |
225 | 3.18k | Stack.back() = Builder.createSExt(Stack.back(), ExtendTy); |
226 | 4.37k | } else { |
227 | 4.37k | Stack.back() = Builder.createZExt(Stack.back(), ExtendTy); |
228 | 4.37k | } |
229 | 7.55k | } |
230 | | |
231 | | void FunctionCompiler::compileStoreOp(uint32_t MemoryIndex, uint64_t Offset, |
232 | | uint32_t Alignment, LLVM::Type LoadTy, |
233 | 3.28k | bool Trunc, bool BitCast) noexcept { |
234 | 3.28k | if constexpr (LLVM::kForceUnalignment) { |
235 | 3.28k | Alignment = 0; |
236 | 3.28k | } |
237 | 3.28k | auto V = stackPop(); |
238 | 3.28k | auto Off = Builder.createZExt(stackPop(), Context.Int64Ty); |
239 | 3.28k | if (Offset != 0) { |
240 | 2.46k | Off = Builder.createAdd(Off, LLContext.getInt64(Offset)); |
241 | 2.46k | } |
242 | | |
243 | 3.28k | if (Trunc) { |
244 | 623 | V = Builder.createTrunc(V, LoadTy); |
245 | 623 | } |
246 | 3.28k | if (BitCast) { |
247 | 235 | V = Builder.createBitCast(V, LoadTy); |
248 | 235 | } |
249 | 3.28k | V = switchEndian(V); |
250 | 3.28k | auto VPtr = Builder.createInBoundsGEP1( |
251 | 3.28k | Context.Int8Ty, Context.getMemory(Builder, ExecCtx, MemoryIndex), Off); |
252 | 3.28k | auto Ptr = Builder.createBitCast(VPtr, LoadTy.getPointerTo()); |
253 | 3.28k | auto StoreInst = Builder.createStore(V, Ptr, true); |
254 | 3.28k | StoreInst.setAlignment(1 << Alignment); |
255 | 3.28k | } |
256 | | |
257 | | } // namespace WasmEdge |