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/threadInstr.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
238
FunctionCompiler::compileAtomicOp(const AST::Instruction &Instr) noexcept {
10
238
  switch (Instr.getOpCode()) {
11
192
  case OpCode::Atomic__fence:
12
192
    compileMemoryFence();
13
192
    break;
14
39
  case OpCode::Memory__atomic__notify:
15
39
    compileAtomicNotify(Instr.getTargetIndex(), Instr.getMemoryOffset());
16
39
    break;
17
5
  case OpCode::Memory__atomic__wait32:
18
5
    compileAtomicWait(Instr.getTargetIndex(), Instr.getMemoryOffset(),
19
5
                      Context.Int32Ty, 32);
20
5
    break;
21
2
  case OpCode::Memory__atomic__wait64:
22
2
    compileAtomicWait(Instr.getTargetIndex(), Instr.getMemoryOffset(),
23
2
                      Context.Int64Ty, 64);
24
2
    break;
25
0
  case OpCode::I32__atomic__load:
26
0
    compileAtomicLoad(Instr.getTargetIndex(), Instr.getMemoryOffset(),
27
0
                      Instr.getMemoryAlign(), Context.Int32Ty, Context.Int32Ty,
28
0
                      true);
29
0
    break;
30
0
  case OpCode::I64__atomic__load:
31
0
    compileAtomicLoad(Instr.getTargetIndex(), Instr.getMemoryOffset(),
32
0
                      Instr.getMemoryAlign(), Context.Int64Ty, Context.Int64Ty,
33
0
                      true);
34
0
    break;
35
0
  case OpCode::I32__atomic__load8_u:
36
0
    compileAtomicLoad(Instr.getTargetIndex(), Instr.getMemoryOffset(),
37
0
                      Instr.getMemoryAlign(), Context.Int32Ty, Context.Int8Ty);
38
0
    break;
39
0
  case OpCode::I32__atomic__load16_u:
40
0
    compileAtomicLoad(Instr.getTargetIndex(), Instr.getMemoryOffset(),
41
0
                      Instr.getMemoryAlign(), Context.Int32Ty, Context.Int16Ty);
42
0
    break;
43
0
  case OpCode::I64__atomic__load8_u:
44
0
    compileAtomicLoad(Instr.getTargetIndex(), Instr.getMemoryOffset(),
45
0
                      Instr.getMemoryAlign(), Context.Int64Ty, Context.Int8Ty);
46
0
    break;
47
0
  case OpCode::I64__atomic__load16_u:
48
0
    compileAtomicLoad(Instr.getTargetIndex(), Instr.getMemoryOffset(),
49
0
                      Instr.getMemoryAlign(), Context.Int64Ty, Context.Int16Ty);
50
0
    break;
51
0
  case OpCode::I64__atomic__load32_u:
52
0
    compileAtomicLoad(Instr.getTargetIndex(), Instr.getMemoryOffset(),
53
0
                      Instr.getMemoryAlign(), Context.Int64Ty, Context.Int32Ty);
54
0
    break;
55
0
  case OpCode::I32__atomic__store:
56
0
    compileAtomicStore(Instr.getTargetIndex(), Instr.getMemoryOffset(),
57
0
                       Instr.getMemoryAlign(), Context.Int32Ty, Context.Int32Ty,
58
0
                       true);
59
0
    break;
60
0
  case OpCode::I64__atomic__store:
61
0
    compileAtomicStore(Instr.getTargetIndex(), Instr.getMemoryOffset(),
62
0
                       Instr.getMemoryAlign(), Context.Int64Ty, Context.Int64Ty,
63
0
                       true);
64
0
    break;
65
0
  case OpCode::I32__atomic__store8:
66
0
    compileAtomicStore(Instr.getTargetIndex(), Instr.getMemoryOffset(),
67
0
                       Instr.getMemoryAlign(), Context.Int32Ty, Context.Int8Ty,
68
0
                       true);
69
0
    break;
70
0
  case OpCode::I32__atomic__store16:
71
0
    compileAtomicStore(Instr.getTargetIndex(), Instr.getMemoryOffset(),
72
0
                       Instr.getMemoryAlign(), Context.Int32Ty, Context.Int16Ty,
73
0
                       true);
74
0
    break;
75
0
  case OpCode::I64__atomic__store8:
76
0
    compileAtomicStore(Instr.getTargetIndex(), Instr.getMemoryOffset(),
77
0
                       Instr.getMemoryAlign(), Context.Int64Ty, Context.Int8Ty,
78
0
                       true);
79
0
    break;
80
0
  case OpCode::I64__atomic__store16:
81
0
    compileAtomicStore(Instr.getTargetIndex(), Instr.getMemoryOffset(),
82
0
                       Instr.getMemoryAlign(), Context.Int64Ty, Context.Int16Ty,
83
0
                       true);
84
0
    break;
85
0
  case OpCode::I64__atomic__store32:
86
0
    compileAtomicStore(Instr.getTargetIndex(), Instr.getMemoryOffset(),
87
0
                       Instr.getMemoryAlign(), Context.Int64Ty, Context.Int32Ty,
88
0
                       true);
89
0
    break;
90
0
  case OpCode::I32__atomic__rmw__add:
91
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
92
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAdd,
93
0
                       Context.Int32Ty, Context.Int32Ty, true);
94
0
    break;
95
0
  case OpCode::I64__atomic__rmw__add:
96
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
97
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAdd,
98
0
                       Context.Int64Ty, Context.Int64Ty, true);
99
0
    break;
100
0
  case OpCode::I32__atomic__rmw8__add_u:
101
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
102
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAdd,
103
0
                       Context.Int32Ty, Context.Int8Ty);
104
0
    break;
105
0
  case OpCode::I32__atomic__rmw16__add_u:
106
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
107
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAdd,
108
0
                       Context.Int32Ty, Context.Int16Ty);
109
0
    break;
110
0
  case OpCode::I64__atomic__rmw8__add_u:
111
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
112
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAdd,
113
0
                       Context.Int64Ty, Context.Int8Ty);
114
0
    break;
115
0
  case OpCode::I64__atomic__rmw16__add_u:
116
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
117
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAdd,
118
0
                       Context.Int64Ty, Context.Int16Ty);
119
0
    break;
120
0
  case OpCode::I64__atomic__rmw32__add_u:
121
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
122
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAdd,
123
0
                       Context.Int64Ty, Context.Int32Ty);
124
0
    break;
125
0
  case OpCode::I32__atomic__rmw__sub:
126
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
127
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpSub,
128
0
                       Context.Int32Ty, Context.Int32Ty, true);
129
0
    break;
130
0
  case OpCode::I64__atomic__rmw__sub:
131
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
132
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpSub,
133
0
                       Context.Int64Ty, Context.Int64Ty, true);
134
0
    break;
135
0
  case OpCode::I32__atomic__rmw8__sub_u:
136
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
137
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpSub,
138
0
                       Context.Int32Ty, Context.Int8Ty);
139
0
    break;
140
0
  case OpCode::I32__atomic__rmw16__sub_u:
141
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
142
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpSub,
143
0
                       Context.Int32Ty, Context.Int16Ty);
144
0
    break;
145
0
  case OpCode::I64__atomic__rmw8__sub_u:
146
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
147
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpSub,
148
0
                       Context.Int64Ty, Context.Int8Ty);
149
0
    break;
150
0
  case OpCode::I64__atomic__rmw16__sub_u:
151
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
152
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpSub,
153
0
                       Context.Int64Ty, Context.Int16Ty);
154
0
    break;
155
0
  case OpCode::I64__atomic__rmw32__sub_u:
156
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
157
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpSub,
158
0
                       Context.Int64Ty, Context.Int32Ty);
159
0
    break;
160
0
  case OpCode::I32__atomic__rmw__and:
161
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
162
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAnd,
163
0
                       Context.Int32Ty, Context.Int32Ty, true);
164
0
    break;
165
0
  case OpCode::I64__atomic__rmw__and:
166
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
167
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAnd,
168
0
                       Context.Int64Ty, Context.Int64Ty, true);
169
0
    break;
170
0
  case OpCode::I32__atomic__rmw8__and_u:
171
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
172
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAnd,
173
0
                       Context.Int32Ty, Context.Int8Ty);
174
0
    break;
175
0
  case OpCode::I32__atomic__rmw16__and_u:
176
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
177
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAnd,
178
0
                       Context.Int32Ty, Context.Int16Ty);
179
0
    break;
180
0
  case OpCode::I64__atomic__rmw8__and_u:
181
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
182
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAnd,
183
0
                       Context.Int64Ty, Context.Int8Ty);
184
0
    break;
185
0
  case OpCode::I64__atomic__rmw16__and_u:
186
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
187
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAnd,
188
0
                       Context.Int64Ty, Context.Int16Ty);
189
0
    break;
190
0
  case OpCode::I64__atomic__rmw32__and_u:
191
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
192
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAnd,
193
0
                       Context.Int64Ty, Context.Int32Ty);
194
0
    break;
195
0
  case OpCode::I32__atomic__rmw__or:
196
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
197
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpOr,
198
0
                       Context.Int32Ty, Context.Int32Ty, true);
199
0
    break;
200
0
  case OpCode::I64__atomic__rmw__or:
201
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
202
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpOr,
203
0
                       Context.Int64Ty, Context.Int64Ty, true);
204
0
    break;
205
0
  case OpCode::I32__atomic__rmw8__or_u:
206
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
207
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpOr,
208
0
                       Context.Int32Ty, Context.Int8Ty);
209
0
    break;
210
0
  case OpCode::I32__atomic__rmw16__or_u:
211
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
212
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpOr,
213
0
                       Context.Int32Ty, Context.Int16Ty);
214
0
    break;
215
0
  case OpCode::I64__atomic__rmw8__or_u:
216
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
217
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpOr,
218
0
                       Context.Int64Ty, Context.Int8Ty);
219
0
    break;
220
0
  case OpCode::I64__atomic__rmw16__or_u:
221
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
222
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpOr,
223
0
                       Context.Int64Ty, Context.Int16Ty);
224
0
    break;
225
0
  case OpCode::I64__atomic__rmw32__or_u:
226
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
227
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpOr,
228
0
                       Context.Int64Ty, Context.Int32Ty);
229
0
    break;
230
0
  case OpCode::I32__atomic__rmw__xor:
231
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
232
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXor,
233
0
                       Context.Int32Ty, Context.Int32Ty, true);
234
0
    break;
235
0
  case OpCode::I64__atomic__rmw__xor:
236
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
237
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXor,
238
0
                       Context.Int64Ty, Context.Int64Ty, true);
239
0
    break;
240
0
  case OpCode::I32__atomic__rmw8__xor_u:
241
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
242
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXor,
243
0
                       Context.Int32Ty, Context.Int8Ty);
244
0
    break;
245
0
  case OpCode::I32__atomic__rmw16__xor_u:
246
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
247
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXor,
248
0
                       Context.Int32Ty, Context.Int16Ty);
249
0
    break;
250
0
  case OpCode::I64__atomic__rmw8__xor_u:
251
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
252
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXor,
253
0
                       Context.Int64Ty, Context.Int8Ty);
254
0
    break;
255
0
  case OpCode::I64__atomic__rmw16__xor_u:
256
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
257
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXor,
258
0
                       Context.Int64Ty, Context.Int16Ty);
259
0
    break;
260
0
  case OpCode::I64__atomic__rmw32__xor_u:
261
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
262
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXor,
263
0
                       Context.Int64Ty, Context.Int32Ty);
264
0
    break;
265
0
  case OpCode::I32__atomic__rmw__xchg:
266
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
267
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXchg,
268
0
                       Context.Int32Ty, Context.Int32Ty, true);
269
0
    break;
270
0
  case OpCode::I64__atomic__rmw__xchg:
271
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
272
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXchg,
273
0
                       Context.Int64Ty, Context.Int64Ty, true);
274
0
    break;
275
0
  case OpCode::I32__atomic__rmw8__xchg_u:
276
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
277
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXchg,
278
0
                       Context.Int32Ty, Context.Int8Ty);
279
0
    break;
280
0
  case OpCode::I32__atomic__rmw16__xchg_u:
281
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
282
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXchg,
283
0
                       Context.Int32Ty, Context.Int16Ty);
284
0
    break;
285
0
  case OpCode::I64__atomic__rmw8__xchg_u:
286
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
287
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXchg,
288
0
                       Context.Int64Ty, Context.Int8Ty);
289
0
    break;
290
0
  case OpCode::I64__atomic__rmw16__xchg_u:
291
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
292
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXchg,
293
0
                       Context.Int64Ty, Context.Int16Ty);
294
0
    break;
295
0
  case OpCode::I64__atomic__rmw32__xchg_u:
296
0
    compileAtomicRMWOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
297
0
                       Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXchg,
298
0
                       Context.Int64Ty, Context.Int32Ty);
299
0
    break;
300
0
  case OpCode::I32__atomic__rmw__cmpxchg:
301
0
    compileAtomicCompareExchange(
302
0
        Instr.getTargetIndex(), Instr.getMemoryOffset(), Instr.getMemoryAlign(),
303
0
        Context.Int32Ty, Context.Int32Ty, true);
304
0
    break;
305
0
  case OpCode::I64__atomic__rmw__cmpxchg:
306
0
    compileAtomicCompareExchange(
307
0
        Instr.getTargetIndex(), Instr.getMemoryOffset(), Instr.getMemoryAlign(),
308
0
        Context.Int64Ty, Context.Int64Ty, true);
309
0
    break;
310
0
  case OpCode::I32__atomic__rmw8__cmpxchg_u:
311
0
    compileAtomicCompareExchange(
312
0
        Instr.getTargetIndex(), Instr.getMemoryOffset(), Instr.getMemoryAlign(),
313
0
        Context.Int32Ty, Context.Int8Ty);
314
0
    break;
315
0
  case OpCode::I32__atomic__rmw16__cmpxchg_u:
316
0
    compileAtomicCompareExchange(
317
0
        Instr.getTargetIndex(), Instr.getMemoryOffset(), Instr.getMemoryAlign(),
318
0
        Context.Int32Ty, Context.Int16Ty);
319
0
    break;
320
0
  case OpCode::I64__atomic__rmw8__cmpxchg_u:
321
0
    compileAtomicCompareExchange(
322
0
        Instr.getTargetIndex(), Instr.getMemoryOffset(), Instr.getMemoryAlign(),
323
0
        Context.Int64Ty, Context.Int8Ty);
324
0
    break;
325
0
  case OpCode::I64__atomic__rmw16__cmpxchg_u:
326
0
    compileAtomicCompareExchange(
327
0
        Instr.getTargetIndex(), Instr.getMemoryOffset(), Instr.getMemoryAlign(),
328
0
        Context.Int64Ty, Context.Int16Ty);
329
0
    break;
330
0
  case OpCode::I64__atomic__rmw32__cmpxchg_u:
331
0
    compileAtomicCompareExchange(
332
0
        Instr.getTargetIndex(), Instr.getMemoryOffset(), Instr.getMemoryAlign(),
333
0
        Context.Int64Ty, Context.Int32Ty);
334
0
    break;
335
336
0
  default:
337
0
    assumingUnreachable();
338
238
  }
339
238
  return {};
340
238
}
341
342
void FunctionCompiler::compileAtomicCheckOffsetAlignment(
343
46
    LLVM::Value Offset, LLVM::Type IntType) noexcept {
344
46
  const auto BitWidth = IntType.getIntegerBitWidth();
345
46
  auto BWMask = LLContext.getInt64((BitWidth >> 3) - 1);
346
46
  auto Value = Builder.createAnd(Offset, BWMask);
347
46
  auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "address_align_ok");
348
46
  auto IsAddressAligned =
349
46
      Builder.createLikely(Builder.createICmpEQ(Value, LLContext.getInt64(0)));
350
46
  Builder.createCondBr(IsAddressAligned, OkBB,
351
46
                       getTrapBB(ErrCode::Value::UnalignedAtomicAccess));
352
353
46
  Builder.positionAtEnd(OkBB);
354
46
}
355
356
192
void FunctionCompiler::compileMemoryFence() noexcept {
357
192
  Builder.createFence(LLVMAtomicOrderingSequentiallyConsistent);
358
192
}
359
360
void FunctionCompiler::compileAtomicNotify(unsigned MemoryIndex,
361
39
                                           uint64_t MemoryOffset) noexcept {
362
39
  auto Count = Builder.createZExt(stackPop(), Context.Int64Ty);
363
39
  auto Offset = Builder.createZExt(stackPop(), Context.Int64Ty);
364
39
  if (MemoryOffset != 0) {
365
32
    Offset = Builder.createAdd(Offset, LLContext.getInt64(MemoryOffset));
366
32
  }
367
39
  compileAtomicCheckOffsetAlignment(Offset, Context.Int32Ty);
368
39
  stackPush(Builder.createTrunc(
369
39
      Builder.createCall(
370
39
          Context.getIntrinsic(
371
39
              Builder, Executable::Intrinsics::kMemAtomicNotify,
372
39
              LLVM::Type::getFunctionType(
373
39
                  Context.Int64Ty,
374
39
                  {Context.Int32Ty, Context.Int64Ty, Context.Int64Ty}, false)),
375
39
          {LLContext.getInt32(MemoryIndex), Offset, Count}),
376
39
      Context.MemoryAddrTypes[MemoryIndex]));
377
39
}
378
379
void FunctionCompiler::compileAtomicWait(unsigned MemoryIndex,
380
                                         uint64_t MemoryOffset,
381
                                         LLVM::Type TargetType,
382
7
                                         uint32_t BitWidth) noexcept {
383
7
  auto Timeout = stackPop();
384
7
  auto ExpectedValue = Builder.createZExtOrTrunc(stackPop(), Context.Int64Ty);
385
7
  auto Offset = Builder.createZExt(stackPop(), Context.Int64Ty);
386
7
  if (MemoryOffset != 0) {
387
3
    Offset = Builder.createAdd(Offset, LLContext.getInt64(MemoryOffset));
388
3
  }
389
7
  compileAtomicCheckOffsetAlignment(Offset, TargetType);
390
7
  stackPush(Builder.createTrunc(
391
7
      Builder.createCall(
392
7
          Context.getIntrinsic(
393
7
              Builder, Executable::Intrinsics::kMemAtomicWait,
394
7
              LLVM::Type::getFunctionType(Context.Int64Ty,
395
7
                                          {Context.Int32Ty, Context.Int64Ty,
396
7
                                           Context.Int64Ty, Context.Int64Ty,
397
7
                                           Context.Int32Ty},
398
7
                                          false)),
399
7
          {LLContext.getInt32(MemoryIndex), Offset, ExpectedValue, Timeout,
400
7
           LLContext.getInt32(BitWidth)}),
401
7
      Context.MemoryAddrTypes[MemoryIndex]));
402
7
}
403
404
void FunctionCompiler::compileAtomicLoad(unsigned MemoryIndex,
405
                                         uint64_t MemoryOffset,
406
                                         unsigned Alignment, LLVM::Type IntType,
407
                                         LLVM::Type TargetType,
408
0
                                         bool Signed) noexcept {
409
410
0
  auto Offset = Builder.createZExt(Stack.back(), Context.Int64Ty);
411
0
  if (MemoryOffset != 0) {
412
0
    Offset = Builder.createAdd(Offset, LLContext.getInt64(MemoryOffset));
413
0
  }
414
0
  compileAtomicCheckOffsetAlignment(Offset, TargetType);
415
0
  auto VPtr = Builder.createInBoundsGEP1(
416
0
      Context.Int8Ty, Context.getMemory(Builder, ExecCtx, MemoryIndex), Offset);
417
418
0
  auto Ptr = Builder.createBitCast(VPtr, TargetType.getPointerTo());
419
0
  auto Load = switchEndian(Builder.createLoad(TargetType, Ptr, true));
420
0
  Load.setAlignment(1 << Alignment);
421
0
  Load.setOrdering(LLVMAtomicOrderingSequentiallyConsistent);
422
423
0
  if (Signed) {
424
0
    Stack.back() = Builder.createSExt(Load, IntType);
425
0
  } else {
426
0
    Stack.back() = Builder.createZExt(Load, IntType);
427
0
  }
428
0
}
429
430
void FunctionCompiler::compileAtomicStore(unsigned MemoryIndex,
431
                                          uint64_t MemoryOffset,
432
                                          unsigned Alignment, LLVM::Type,
433
                                          LLVM::Type TargetType,
434
0
                                          bool Signed) noexcept {
435
0
  auto V = stackPop();
436
437
0
  if (Signed) {
438
0
    V = Builder.createSExtOrTrunc(V, TargetType);
439
0
  } else {
440
0
    V = Builder.createZExtOrTrunc(V, TargetType);
441
0
  }
442
0
  V = switchEndian(V);
443
0
  auto Offset = Builder.createZExt(Stack.back(), Context.Int64Ty);
444
0
  if (MemoryOffset != 0) {
445
0
    Offset = Builder.createAdd(Offset, LLContext.getInt64(MemoryOffset));
446
0
  }
447
0
  compileAtomicCheckOffsetAlignment(Offset, TargetType);
448
0
  auto VPtr = Builder.createInBoundsGEP1(
449
0
      Context.Int8Ty, Context.getMemory(Builder, ExecCtx, MemoryIndex), Offset);
450
0
  auto Ptr = Builder.createBitCast(VPtr, TargetType.getPointerTo());
451
0
  auto Store = Builder.createStore(V, Ptr, true);
452
0
  Store.setAlignment(1 << Alignment);
453
0
  Store.setOrdering(LLVMAtomicOrderingSequentiallyConsistent);
454
0
}
455
456
void FunctionCompiler::compileAtomicRMWOp(
457
    unsigned MemoryIndex, uint64_t MemoryOffset,
458
    [[maybe_unused]] unsigned Alignment, LLVMAtomicRMWBinOp BinOp,
459
0
    LLVM::Type IntType, LLVM::Type TargetType, bool Signed) noexcept {
460
0
  auto Value = Builder.createSExtOrTrunc(stackPop(), TargetType);
461
0
  auto Offset = Builder.createZExt(Stack.back(), Context.Int64Ty);
462
0
  if (MemoryOffset != 0) {
463
0
    Offset = Builder.createAdd(Offset, LLContext.getInt64(MemoryOffset));
464
0
  }
465
0
  compileAtomicCheckOffsetAlignment(Offset, TargetType);
466
0
  auto VPtr = Builder.createInBoundsGEP1(
467
0
      Context.Int8Ty, Context.getMemory(Builder, ExecCtx, MemoryIndex), Offset);
468
0
  auto Ptr = Builder.createBitCast(VPtr, TargetType.getPointerTo());
469
470
0
  LLVM::Value Ret;
471
  if constexpr (Endian::native == Endian::big) {
472
    if (BinOp == LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpAdd ||
473
        BinOp == LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpSub) {
474
      auto AtomicBB = LLVM::BasicBlock::create(LLContext, F.Fn, "atomic.rmw");
475
      auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "atomic.rmw.ok");
476
      Builder.createBr(AtomicBB);
477
      Builder.positionAtEnd(AtomicBB);
478
479
      auto Load = Builder.createLoad(TargetType, Ptr, true);
480
      Load.setOrdering(LLVMAtomicOrderingMonotonic);
481
      Load.setAlignment(1 << Alignment);
482
483
      LLVM::Value New;
484
      if (BinOp == LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpAdd)
485
        New = Builder.createAdd(switchEndian(Load), Value);
486
      else if (BinOp == LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpSub) {
487
        New = Builder.createSub(switchEndian(Load), Value);
488
      } else {
489
        assumingUnreachable();
490
      }
491
      New = switchEndian(New);
492
493
      auto Exchange = Builder.createAtomicCmpXchg(
494
          Ptr, Load, New, LLVMAtomicOrderingSequentiallyConsistent,
495
          LLVMAtomicOrderingSequentiallyConsistent);
496
497
      Ret = Builder.createExtractValue(Exchange, 0);
498
      auto Success = Builder.createExtractValue(Exchange, 1);
499
      Builder.createCondBr(Success, OkBB, AtomicBB);
500
      Builder.positionAtEnd(OkBB);
501
    } else {
502
      Ret = Builder.createAtomicRMW(BinOp, Ptr, switchEndian(Value),
503
                                    LLVMAtomicOrderingSequentiallyConsistent);
504
    }
505
0
  } else {
506
0
    Ret = Builder.createAtomicRMW(BinOp, Ptr, switchEndian(Value),
507
0
                                  LLVMAtomicOrderingSequentiallyConsistent);
508
0
  }
509
0
  Ret = switchEndian(Ret);
510
#if LLVM_VERSION_MAJOR >= 13
511
  Ret.setAlignment(1 << Alignment);
512
#endif
513
0
  if (Signed) {
514
0
    Stack.back() = Builder.createSExt(Ret, IntType);
515
0
  } else {
516
0
    Stack.back() = Builder.createZExt(Ret, IntType);
517
0
  }
518
0
}
519
520
void FunctionCompiler::compileAtomicCompareExchange(
521
    unsigned MemoryIndex, uint64_t MemoryOffset,
522
    [[maybe_unused]] unsigned Alignment, LLVM::Type IntType,
523
0
    LLVM::Type TargetType, bool Signed) noexcept {
524
525
0
  auto Replacement = Builder.createSExtOrTrunc(stackPop(), TargetType);
526
0
  auto Expected = Builder.createSExtOrTrunc(stackPop(), TargetType);
527
0
  auto Offset = Builder.createZExt(Stack.back(), Context.Int64Ty);
528
0
  if (MemoryOffset != 0) {
529
0
    Offset = Builder.createAdd(Offset, LLContext.getInt64(MemoryOffset));
530
0
  }
531
0
  compileAtomicCheckOffsetAlignment(Offset, TargetType);
532
0
  auto VPtr = Builder.createInBoundsGEP1(
533
0
      Context.Int8Ty, Context.getMemory(Builder, ExecCtx, MemoryIndex), Offset);
534
0
  auto Ptr = Builder.createBitCast(VPtr, TargetType.getPointerTo());
535
536
0
  auto Ret = Builder.createAtomicCmpXchg(
537
0
      Ptr, switchEndian(Expected), switchEndian(Replacement),
538
0
      LLVMAtomicOrderingSequentiallyConsistent,
539
0
      LLVMAtomicOrderingSequentiallyConsistent);
540
#if LLVM_VERSION_MAJOR >= 13
541
  Ret.setAlignment(1 << Alignment);
542
#endif
543
0
  auto OldVal = Builder.createExtractValue(Ret, 0);
544
0
  OldVal = switchEndian(OldVal);
545
0
  if (Signed) {
546
0
    Stack.back() = Builder.createSExt(OldVal, IntType);
547
0
  } else {
548
0
    Stack.back() = Builder.createZExt(OldVal, IntType);
549
0
  }
550
0
}
551
552
} // namespace WasmEdge