Coverage Report

Created: 2026-08-14 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
670k
FunctionCompiler::compileMemoryOp(const AST::Instruction &Instr) noexcept {
10
670k
  switch (Instr.getOpCode()) {
11
1.22k
  case OpCode::I32__load:
12
1.22k
    compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
13
1.22k
                  Instr.getMemoryAlign(), Context.Int32Ty);
14
1.22k
    break;
15
3.13k
  case OpCode::I64__load:
16
3.13k
    compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
17
3.13k
                  Instr.getMemoryAlign(), Context.Int64Ty);
18
3.13k
    break;
19
107
  case OpCode::F32__load:
20
107
    compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
21
107
                  Instr.getMemoryAlign(), Context.FloatTy);
22
107
    break;
23
224
  case OpCode::F64__load:
24
224
    compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
25
224
                  Instr.getMemoryAlign(), Context.DoubleTy);
26
224
    break;
27
685
  case OpCode::I32__load8_s:
28
685
    compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
29
685
                  Instr.getMemoryAlign(), Context.Int8Ty, Context.Int32Ty,
30
685
                  true);
31
685
    break;
32
419
  case OpCode::I32__load8_u:
33
419
    compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
34
419
                  Instr.getMemoryAlign(), Context.Int8Ty, Context.Int32Ty,
35
419
                  false);
36
419
    break;
37
306
  case OpCode::I32__load16_s:
38
306
    compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
39
306
                  Instr.getMemoryAlign(), Context.Int16Ty, Context.Int32Ty,
40
306
                  true);
41
306
    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
774
  case OpCode::I64__load8_s:
48
774
    compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
49
774
                  Instr.getMemoryAlign(), Context.Int8Ty, Context.Int64Ty,
50
774
                  true);
51
774
    break;
52
475
  case OpCode::I64__load8_u:
53
475
    compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
54
475
                  Instr.getMemoryAlign(), Context.Int8Ty, Context.Int64Ty,
55
475
                  false);
56
475
    break;
57
382
  case OpCode::I64__load16_s:
58
382
    compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
59
382
                  Instr.getMemoryAlign(), Context.Int16Ty, Context.Int64Ty,
60
382
                  true);
61
382
    break;
62
621
  case OpCode::I64__load16_u:
63
621
    compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
64
621
                  Instr.getMemoryAlign(), Context.Int16Ty, Context.Int64Ty,
65
621
                  false);
66
621
    break;
67
408
  case OpCode::I64__load32_s:
68
408
    compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
69
408
                  Instr.getMemoryAlign(), Context.Int32Ty, Context.Int64Ty,
70
408
                  true);
71
408
    break;
72
489
  case OpCode::I64__load32_u:
73
489
    compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
74
489
                  Instr.getMemoryAlign(), Context.Int32Ty, Context.Int64Ty,
75
489
                  false);
76
489
    break;
77
388
  case OpCode::I32__store:
78
388
    compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
79
388
                   Instr.getMemoryAlign(), Context.Int32Ty);
80
388
    break;
81
1.54k
  case OpCode::I64__store:
82
1.54k
    compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
83
1.54k
                   Instr.getMemoryAlign(), Context.Int64Ty);
84
1.54k
    break;
85
59
  case OpCode::F32__store:
86
59
    compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
87
59
                   Instr.getMemoryAlign(), Context.FloatTy);
88
59
    break;
89
43
  case OpCode::F64__store:
90
43
    compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
91
43
                   Instr.getMemoryAlign(), Context.DoubleTy);
92
43
    break;
93
288
  case OpCode::I32__store8:
94
304
  case OpCode::I64__store8:
95
304
    compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
96
304
                   Instr.getMemoryAlign(), Context.Int8Ty, true);
97
304
    break;
98
231
  case OpCode::I32__store16:
99
302
  case OpCode::I64__store16:
100
302
    compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
101
302
                   Instr.getMemoryAlign(), Context.Int16Ty, true);
102
302
    break;
103
27
  case OpCode::I64__store32:
104
27
    compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
105
27
                   Instr.getMemoryAlign(), Context.Int32Ty, true);
106
27
    break;
107
767
  case OpCode::Memory__size:
108
767
    stackPush(Builder.createTrunc(
109
767
        Context.getMemorySize(Builder, ExecCtx, Instr.getTargetIndex()),
110
767
        Context.MemoryAddrTypes[Instr.getTargetIndex()]));
111
767
    break;
112
849
  case OpCode::Memory__grow: {
113
849
    auto NewPageSize = Builder.createZExt(stackPop(), Context.Int64Ty);
114
849
    stackPush(Builder.createTrunc(
115
849
        Builder.createCall(
116
849
            Context.getIntrinsic(
117
849
                Builder, Executable::Intrinsics::kMemGrow,
118
849
                LLVM::Type::getFunctionType(Context.Int64Ty,
119
849
                                            {Context.Int32Ty, Context.Int64Ty},
120
849
                                            false)),
121
849
            {LLContext.getInt32(Instr.getTargetIndex()), NewPageSize}),
122
849
        Context.MemoryAddrTypes[Instr.getTargetIndex()]));
123
849
    break;
124
231
  }
125
24
  case OpCode::Memory__init: {
126
24
    auto Len = stackPop();
127
24
    auto Src = stackPop();
128
24
    auto Dst = Builder.createZExt(stackPop(), Context.Int64Ty);
129
24
    Builder.createCall(
130
24
        Context.getIntrinsic(
131
24
            Builder, Executable::Intrinsics::kMemInit,
132
24
            LLVM::Type::getFunctionType(Context.VoidTy,
133
24
                                        {Context.Int32Ty, Context.Int32Ty,
134
24
                                         Context.Int64Ty, Context.Int32Ty,
135
24
                                         Context.Int32Ty},
136
24
                                        false)),
137
24
        {LLContext.getInt32(Instr.getTargetIndex()),
138
24
         LLContext.getInt32(Instr.getSourceIndex()), Dst, Src, Len});
139
24
    break;
140
231
  }
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
231
  }
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
231
  }
165
637
  case OpCode::Memory__fill: {
166
637
    auto Len = Builder.createZExt(stackPop(), Context.Int64Ty);
167
637
    auto Val = Builder.createTrunc(stackPop(), Context.Int8Ty);
168
637
    auto Off = Builder.createZExt(stackPop(), Context.Int64Ty);
169
637
    Builder.createCall(
170
637
        Context.getIntrinsic(
171
637
            Builder, Executable::Intrinsics::kMemFill,
172
637
            LLVM::Type::getFunctionType(Context.VoidTy,
173
637
                                        {Context.Int32Ty, Context.Int64Ty,
174
637
                                         Context.Int8Ty, Context.Int64Ty},
175
637
                                        false)),
176
637
        {LLContext.getInt32(Instr.getTargetIndex()), Off, Val, Len});
177
637
    break;
178
231
  }
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
73.3k
  case OpCode::I64__const:
185
73.3k
    stackPush(LLContext.getInt64(Instr.getNum().get<uint64_t>()));
186
73.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.70k
  case OpCode::F64__const:
191
6.70k
    stackPush(LLContext.getDouble(Instr.getNum().get<double>()));
192
6.70k
    break;
193
194
0
  default:
195
0
    assumingUnreachable();
196
670k
  }
197
670k
  return {};
198
670k
}
199
200
void FunctionCompiler::compileLoadOp(unsigned MemoryIndex, uint64_t Offset,
201
                                     unsigned Alignment,
202
18.5k
                                     LLVM::Type LoadTy) noexcept {
203
18.5k
  if constexpr (LLVM::kForceUnalignment) {
204
18.5k
    Alignment = 0;
205
18.5k
  }
206
18.5k
  auto Off = Builder.createZExt(stackPop(), Context.Int64Ty);
207
18.5k
  if (Offset != 0) {
208
11.9k
    Off = Builder.createAdd(Off, LLContext.getInt64(Offset));
209
11.9k
  }
210
211
18.5k
  auto VPtr = Builder.createInBoundsGEP1(
212
18.5k
      Context.Int8Ty, Context.getMemory(Builder, ExecCtx, MemoryIndex), Off);
213
18.5k
  auto Ptr = Builder.createBitCast(VPtr, LoadTy.getPointerTo());
214
18.5k
  auto LoadInst = Builder.createLoad(LoadTy, Ptr, true);
215
18.5k
  LoadInst.setAlignment(1 << Alignment);
216
18.5k
  stackPush(switchEndian(LoadInst));
217
18.5k
}
218
219
void FunctionCompiler::compileLoadOp(unsigned MemoryIndex, uint64_t Offset,
220
                                     unsigned Alignment, LLVM::Type LoadTy,
221
                                     LLVM::Type ExtendTy,
222
7.81k
                                     bool Signed) noexcept {
223
7.81k
  compileLoadOp(MemoryIndex, Offset, Alignment, LoadTy);
224
7.81k
  if (Signed) {
225
3.24k
    Stack.back() = Builder.createSExt(Stack.back(), ExtendTy);
226
4.56k
  } else {
227
4.56k
    Stack.back() = Builder.createZExt(Stack.back(), ExtendTy);
228
4.56k
  }
229
7.81k
}
230
231
void FunctionCompiler::compileStoreOp(uint32_t MemoryIndex, uint64_t Offset,
232
                                      uint32_t Alignment, LLVM::Type LoadTy,
233
3.27k
                                      bool Trunc, bool BitCast) noexcept {
234
3.27k
  if constexpr (LLVM::kForceUnalignment) {
235
3.27k
    Alignment = 0;
236
3.27k
  }
237
3.27k
  auto V = stackPop();
238
3.27k
  auto Off = Builder.createZExt(stackPop(), Context.Int64Ty);
239
3.27k
  if (Offset != 0) {
240
2.49k
    Off = Builder.createAdd(Off, LLContext.getInt64(Offset));
241
2.49k
  }
242
243
3.27k
  if (Trunc) {
244
633
    V = Builder.createTrunc(V, LoadTy);
245
633
  }
246
3.27k
  if (BitCast) {
247
235
    V = Builder.createBitCast(V, LoadTy);
248
235
  }
249
3.27k
  V = switchEndian(V);
250
3.27k
  auto VPtr = Builder.createInBoundsGEP1(
251
3.27k
      Context.Int8Ty, Context.getMemory(Builder, ExecCtx, MemoryIndex), Off);
252
3.27k
  auto Ptr = Builder.createBitCast(VPtr, LoadTy.getPointerTo());
253
3.27k
  auto StoreInst = Builder.createStore(V, Ptr, true);
254
3.27k
  StoreInst.setAlignment(1 << Alignment);
255
3.27k
}
256
257
} // namespace WasmEdge