Coverage Report

Created: 2026-07-16 07:09

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
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