/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 | 669k | FunctionCompiler::compileMemoryOp(const AST::Instruction &Instr) noexcept { |
10 | 669k | switch (Instr.getOpCode()) { |
11 | 1.20k | case OpCode::I32__load: |
12 | 1.20k | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
13 | 1.20k | Instr.getMemoryAlign(), Context.Int32Ty); |
14 | 1.20k | break; |
15 | 3.04k | case OpCode::I64__load: |
16 | 3.04k | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
17 | 3.04k | Instr.getMemoryAlign(), Context.Int64Ty); |
18 | 3.04k | break; |
19 | 106 | case OpCode::F32__load: |
20 | 106 | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
21 | 106 | Instr.getMemoryAlign(), Context.FloatTy); |
22 | 106 | break; |
23 | 223 | case OpCode::F64__load: |
24 | 223 | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
25 | 223 | Instr.getMemoryAlign(), Context.DoubleTy); |
26 | 223 | break; |
27 | 693 | case OpCode::I32__load8_s: |
28 | 693 | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
29 | 693 | Instr.getMemoryAlign(), Context.Int8Ty, Context.Int32Ty, |
30 | 693 | true); |
31 | 693 | break; |
32 | 527 | case OpCode::I32__load8_u: |
33 | 527 | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
34 | 527 | Instr.getMemoryAlign(), Context.Int8Ty, Context.Int32Ty, |
35 | 527 | false); |
36 | 527 | break; |
37 | 292 | case OpCode::I32__load16_s: |
38 | 292 | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
39 | 292 | Instr.getMemoryAlign(), Context.Int16Ty, Context.Int32Ty, |
40 | 292 | true); |
41 | 292 | break; |
42 | 1.58k | case OpCode::I32__load16_u: |
43 | 1.58k | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
44 | 1.58k | Instr.getMemoryAlign(), Context.Int16Ty, Context.Int32Ty, |
45 | 1.58k | false); |
46 | 1.58k | break; |
47 | 759 | case OpCode::I64__load8_s: |
48 | 759 | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
49 | 759 | Instr.getMemoryAlign(), Context.Int8Ty, Context.Int64Ty, |
50 | 759 | true); |
51 | 759 | break; |
52 | 470 | case OpCode::I64__load8_u: |
53 | 470 | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
54 | 470 | Instr.getMemoryAlign(), Context.Int8Ty, Context.Int64Ty, |
55 | 470 | false); |
56 | 470 | break; |
57 | 380 | case OpCode::I64__load16_s: |
58 | 380 | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
59 | 380 | Instr.getMemoryAlign(), Context.Int16Ty, Context.Int64Ty, |
60 | 380 | true); |
61 | 380 | break; |
62 | 616 | case OpCode::I64__load16_u: |
63 | 616 | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
64 | 616 | Instr.getMemoryAlign(), Context.Int16Ty, Context.Int64Ty, |
65 | 616 | false); |
66 | 616 | break; |
67 | 406 | case OpCode::I64__load32_s: |
68 | 406 | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
69 | 406 | Instr.getMemoryAlign(), Context.Int32Ty, Context.Int64Ty, |
70 | 406 | true); |
71 | 406 | break; |
72 | 523 | case OpCode::I64__load32_u: |
73 | 523 | compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
74 | 523 | Instr.getMemoryAlign(), Context.Int32Ty, Context.Int64Ty, |
75 | 523 | false); |
76 | 523 | break; |
77 | 433 | case OpCode::I32__store: |
78 | 433 | compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
79 | 433 | Instr.getMemoryAlign(), Context.Int32Ty); |
80 | 433 | break; |
81 | 1.56k | case OpCode::I64__store: |
82 | 1.56k | compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
83 | 1.56k | Instr.getMemoryAlign(), Context.Int64Ty); |
84 | 1.56k | break; |
85 | 59 | case OpCode::F32__store: |
86 | 59 | compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
87 | 59 | Instr.getMemoryAlign(), Context.FloatTy); |
88 | 59 | break; |
89 | 41 | case OpCode::F64__store: |
90 | 41 | compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
91 | 41 | Instr.getMemoryAlign(), Context.DoubleTy); |
92 | 41 | break; |
93 | 282 | case OpCode::I32__store8: |
94 | 298 | case OpCode::I64__store8: |
95 | 298 | compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
96 | 298 | Instr.getMemoryAlign(), Context.Int8Ty, true); |
97 | 298 | break; |
98 | 229 | case OpCode::I32__store16: |
99 | 314 | case OpCode::I64__store16: |
100 | 314 | compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
101 | 314 | Instr.getMemoryAlign(), Context.Int16Ty, true); |
102 | 314 | 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 | 719 | case OpCode::Memory__size: |
108 | 719 | stackPush(Builder.createTrunc( |
109 | 719 | Context.getMemorySize(Builder, ExecCtx, Instr.getTargetIndex()), |
110 | 719 | Context.MemoryAddrTypes[Instr.getTargetIndex()])); |
111 | 719 | break; |
112 | 976 | case OpCode::Memory__grow: { |
113 | 976 | auto NewPageSize = Builder.createZExt(stackPop(), Context.Int64Ty); |
114 | 976 | stackPush(Builder.createTrunc( |
115 | 976 | Builder.createCall( |
116 | 976 | Context.getIntrinsic( |
117 | 976 | Builder, Executable::Intrinsics::kMemGrow, |
118 | 976 | LLVM::Type::getFunctionType(Context.Int64Ty, |
119 | 976 | {Context.Int32Ty, Context.Int64Ty}, |
120 | 976 | false)), |
121 | 976 | {LLContext.getInt32(Instr.getTargetIndex()), NewPageSize}), |
122 | 976 | Context.MemoryAddrTypes[Instr.getTargetIndex()])); |
123 | 976 | break; |
124 | 229 | } |
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 | 229 | } |
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 | 229 | } |
149 | 251 | case OpCode::Memory__copy: { |
150 | 251 | auto Len = Builder.createZExt(stackPop(), Context.Int64Ty); |
151 | 251 | auto Src = Builder.createZExt(stackPop(), Context.Int64Ty); |
152 | 251 | auto Dst = Builder.createZExt(stackPop(), Context.Int64Ty); |
153 | 251 | Builder.createCall( |
154 | 251 | Context.getIntrinsic( |
155 | 251 | Builder, Executable::Intrinsics::kMemCopy, |
156 | 251 | LLVM::Type::getFunctionType(Context.VoidTy, |
157 | 251 | {Context.Int32Ty, Context.Int32Ty, |
158 | 251 | Context.Int64Ty, Context.Int64Ty, |
159 | 251 | Context.Int64Ty}, |
160 | 251 | false)), |
161 | 251 | {LLContext.getInt32(Instr.getTargetIndex()), |
162 | 251 | LLContext.getInt32(Instr.getSourceIndex()), Dst, Src, Len}); |
163 | 251 | break; |
164 | 229 | } |
165 | 634 | case OpCode::Memory__fill: { |
166 | 634 | auto Len = Builder.createZExt(stackPop(), Context.Int64Ty); |
167 | 634 | auto Val = Builder.createTrunc(stackPop(), Context.Int8Ty); |
168 | 634 | auto Off = Builder.createZExt(stackPop(), Context.Int64Ty); |
169 | 634 | Builder.createCall( |
170 | 634 | Context.getIntrinsic( |
171 | 634 | Builder, Executable::Intrinsics::kMemFill, |
172 | 634 | LLVM::Type::getFunctionType(Context.VoidTy, |
173 | 634 | {Context.Int32Ty, Context.Int64Ty, |
174 | 634 | Context.Int8Ty, Context.Int64Ty}, |
175 | 634 | false)), |
176 | 634 | {LLContext.getInt32(Instr.getTargetIndex()), Off, Val, Len}); |
177 | 634 | break; |
178 | 229 | } |
179 | | |
180 | | // Const Numeric Instructions |
181 | 560k | case OpCode::I32__const: |
182 | 560k | stackPush(LLContext.getInt32(Instr.getNum().get<uint32_t>())); |
183 | 560k | break; |
184 | 72.3k | case OpCode::I64__const: |
185 | 72.3k | stackPush(LLContext.getInt64(Instr.getNum().get<uint64_t>())); |
186 | 72.3k | break; |
187 | 13.8k | case OpCode::F32__const: |
188 | 13.8k | stackPush(LLContext.getFloat(Instr.getNum().get<float>())); |
189 | 13.8k | break; |
190 | 6.64k | case OpCode::F64__const: |
191 | 6.64k | stackPush(LLContext.getDouble(Instr.getNum().get<double>())); |
192 | 6.64k | break; |
193 | | |
194 | 0 | default: |
195 | 0 | assumingUnreachable(); |
196 | 669k | } |
197 | 669k | return {}; |
198 | 669k | } |
199 | | |
200 | | void FunctionCompiler::compileLoadOp(unsigned MemoryIndex, uint64_t Offset, |
201 | | unsigned Alignment, |
202 | 18.3k | LLVM::Type LoadTy) noexcept { |
203 | 18.3k | if constexpr (LLVM::kForceUnalignment) { |
204 | 18.3k | Alignment = 0; |
205 | 18.3k | } |
206 | 18.3k | auto Off = Builder.createZExt(stackPop(), Context.Int64Ty); |
207 | 18.3k | if (Offset != 0) { |
208 | 11.7k | Off = Builder.createAdd(Off, LLContext.getInt64(Offset)); |
209 | 11.7k | } |
210 | | |
211 | 18.3k | auto VPtr = Builder.createInBoundsGEP1( |
212 | 18.3k | Context.Int8Ty, Context.getMemory(Builder, ExecCtx, MemoryIndex), Off); |
213 | 18.3k | auto Ptr = Builder.createBitCast(VPtr, LoadTy.getPointerTo()); |
214 | 18.3k | auto LoadInst = Builder.createLoad(LoadTy, Ptr, true); |
215 | 18.3k | LoadInst.setAlignment(1 << Alignment); |
216 | 18.3k | stackPush(switchEndian(LoadInst)); |
217 | 18.3k | } |
218 | | |
219 | | void FunctionCompiler::compileLoadOp(unsigned MemoryIndex, uint64_t Offset, |
220 | | unsigned Alignment, LLVM::Type LoadTy, |
221 | | LLVM::Type ExtendTy, |
222 | 7.89k | bool Signed) noexcept { |
223 | 7.89k | compileLoadOp(MemoryIndex, Offset, Alignment, LoadTy); |
224 | 7.89k | if (Signed) { |
225 | 3.21k | Stack.back() = Builder.createSExt(Stack.back(), ExtendTy); |
226 | 4.68k | } else { |
227 | 4.68k | Stack.back() = Builder.createZExt(Stack.back(), ExtendTy); |
228 | 4.68k | } |
229 | 7.89k | } |
230 | | |
231 | | void FunctionCompiler::compileStoreOp(uint32_t MemoryIndex, uint64_t Offset, |
232 | | uint32_t Alignment, LLVM::Type LoadTy, |
233 | 3.33k | bool Trunc, bool BitCast) noexcept { |
234 | 3.33k | if constexpr (LLVM::kForceUnalignment) { |
235 | 3.33k | Alignment = 0; |
236 | 3.33k | } |
237 | 3.33k | auto V = stackPop(); |
238 | 3.33k | auto Off = Builder.createZExt(stackPop(), Context.Int64Ty); |
239 | 3.33k | if (Offset != 0) { |
240 | 2.56k | Off = Builder.createAdd(Off, LLContext.getInt64(Offset)); |
241 | 2.56k | } |
242 | | |
243 | 3.33k | if (Trunc) { |
244 | 640 | V = Builder.createTrunc(V, LoadTy); |
245 | 640 | } |
246 | 3.33k | if (BitCast) { |
247 | 235 | V = Builder.createBitCast(V, LoadTy); |
248 | 235 | } |
249 | 3.33k | V = switchEndian(V); |
250 | 3.33k | auto VPtr = Builder.createInBoundsGEP1( |
251 | 3.33k | Context.Int8Ty, Context.getMemory(Builder, ExecCtx, MemoryIndex), Off); |
252 | 3.33k | auto Ptr = Builder.createBitCast(VPtr, LoadTy.getPointerTo()); |
253 | 3.33k | auto StoreInst = Builder.createStore(V, Ptr, true); |
254 | 3.33k | StoreInst.setAlignment(1 << Alignment); |
255 | 3.33k | } |
256 | | |
257 | | } // namespace WasmEdge |