Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/tests/IrCallWrapperX64.test.cpp
2723 views
1
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
2
#include "Luau/IrCallWrapperX64.h"
3
#include "Luau/IrRegAllocX64.h"
4
5
#include "doctest.h"
6
7
using namespace Luau::CodeGen;
8
using namespace Luau::CodeGen::X64;
9
10
class IrCallWrapperX64Fixture
11
{
12
public:
13
IrCallWrapperX64Fixture(ABIX64 abi = ABIX64::Windows)
14
: build(/* logText */ true, abi)
15
, regs(build, function, nullptr)
16
, callWrap(regs, build, ~0u)
17
{
18
}
19
20
void checkMatch(std::string expected)
21
{
22
regs.assertAllFree();
23
24
build.finalize();
25
26
CHECK("\n" + build.text == expected);
27
}
28
29
AssemblyBuilderX64 build;
30
IrFunction function;
31
IrRegAllocX64 regs;
32
IrCallWrapperX64 callWrap;
33
34
// Tests rely on these to force interference between registers
35
static constexpr RegisterX64 rArg1 = rcx;
36
static constexpr RegisterX64 rArg1d = ecx;
37
static constexpr RegisterX64 rArg2 = rdx;
38
static constexpr RegisterX64 rArg2d = edx;
39
static constexpr RegisterX64 rArg3 = r8;
40
static constexpr RegisterX64 rArg3d = r8d;
41
static constexpr RegisterX64 rArg4 = r9;
42
static constexpr RegisterX64 rArg4d = r9d;
43
};
44
45
class IrCallWrapperX64FixtureSystemV : public IrCallWrapperX64Fixture
46
{
47
public:
48
IrCallWrapperX64FixtureSystemV()
49
: IrCallWrapperX64Fixture(ABIX64::SystemV)
50
{
51
}
52
};
53
54
TEST_SUITE_BEGIN("IrCallWrapperX64");
55
56
TEST_CASE_FIXTURE(IrCallWrapperX64Fixture, "SimpleRegs")
57
{
58
ScopedRegX64 tmp1{regs, regs.takeReg(rax, kInvalidInstIdx)};
59
ScopedRegX64 tmp2{regs, regs.takeReg(rArg2, kInvalidInstIdx)};
60
callWrap.addArgument(SizeX64::qword, tmp1);
61
callWrap.addArgument(SizeX64::qword, tmp2); // Already in its place
62
callWrap.call(qword[r12]);
63
64
checkMatch(R"(
65
mov rcx,rax
66
call qword ptr [r12]
67
)");
68
}
69
70
TEST_CASE_FIXTURE(IrCallWrapperX64Fixture, "TrickyUse1")
71
{
72
ScopedRegX64 tmp1{regs, regs.takeReg(rArg1, kInvalidInstIdx)};
73
callWrap.addArgument(SizeX64::qword, tmp1.reg); // Already in its place
74
callWrap.addArgument(SizeX64::qword, tmp1.release());
75
callWrap.call(qword[r12]);
76
77
checkMatch(R"(
78
mov rdx,rcx
79
call qword ptr [r12]
80
)");
81
}
82
83
TEST_CASE_FIXTURE(IrCallWrapperX64Fixture, "TrickyUse2")
84
{
85
ScopedRegX64 tmp1{regs, regs.takeReg(rArg1, kInvalidInstIdx)};
86
callWrap.addArgument(SizeX64::qword, qword[tmp1.reg]);
87
callWrap.addArgument(SizeX64::qword, tmp1.release());
88
callWrap.call(qword[r12]);
89
90
checkMatch(R"(
91
mov rdx,rcx
92
mov rcx,qword ptr [rcx]
93
call qword ptr [r12]
94
)");
95
}
96
97
TEST_CASE_FIXTURE(IrCallWrapperX64Fixture, "SimpleMemImm")
98
{
99
ScopedRegX64 tmp1{regs, regs.takeReg(rax, kInvalidInstIdx)};
100
ScopedRegX64 tmp2{regs, regs.takeReg(rsi, kInvalidInstIdx)};
101
callWrap.addArgument(SizeX64::dword, 32);
102
callWrap.addArgument(SizeX64::dword, -1);
103
callWrap.addArgument(SizeX64::qword, qword[r14 + 32]);
104
callWrap.addArgument(SizeX64::qword, qword[tmp1.release() + tmp2.release()]);
105
callWrap.call(qword[r12]);
106
107
checkMatch(R"(
108
mov r8,qword ptr [r14+020h]
109
mov r9,qword ptr [rax+rsi]
110
mov ecx,20h
111
mov edx,FFFFFFFFh
112
call qword ptr [r12]
113
)");
114
}
115
116
TEST_CASE_FIXTURE(IrCallWrapperX64Fixture, "SimpleStackArgs")
117
{
118
ScopedRegX64 tmp{regs, regs.takeReg(rax, kInvalidInstIdx)};
119
callWrap.addArgument(SizeX64::qword, tmp);
120
callWrap.addArgument(SizeX64::qword, qword[r14 + 16]);
121
callWrap.addArgument(SizeX64::qword, qword[r14 + 32]);
122
callWrap.addArgument(SizeX64::qword, qword[r14 + 48]);
123
callWrap.addArgument(SizeX64::dword, 1);
124
callWrap.addArgument(SizeX64::qword, qword[r13]);
125
callWrap.call(qword[r12]);
126
127
checkMatch(R"(
128
mov rdx,qword ptr [r13]
129
mov qword ptr [rsp+028h],rdx
130
mov rcx,rax
131
mov rdx,qword ptr [r14+010h]
132
mov r8,qword ptr [r14+020h]
133
mov r9,qword ptr [r14+030h]
134
mov dword ptr [rsp+020h],1
135
call qword ptr [r12]
136
)");
137
}
138
139
TEST_CASE_FIXTURE(IrCallWrapperX64Fixture, "FixedRegisters")
140
{
141
callWrap.addArgument(SizeX64::dword, 1);
142
callWrap.addArgument(SizeX64::qword, 2);
143
callWrap.addArgument(SizeX64::qword, 3);
144
callWrap.addArgument(SizeX64::qword, 4);
145
callWrap.addArgument(SizeX64::qword, r14);
146
callWrap.call(qword[r12]);
147
148
checkMatch(R"(
149
mov qword ptr [rsp+020h],r14
150
mov ecx,1
151
mov rdx,2
152
mov r8,3
153
mov r9,4
154
call qword ptr [r12]
155
)");
156
}
157
158
TEST_CASE_FIXTURE(IrCallWrapperX64Fixture, "EasyInterference")
159
{
160
ScopedRegX64 tmp1{regs, regs.takeReg(rdi, kInvalidInstIdx)};
161
ScopedRegX64 tmp2{regs, regs.takeReg(rsi, kInvalidInstIdx)};
162
ScopedRegX64 tmp3{regs, regs.takeReg(rArg2, kInvalidInstIdx)};
163
ScopedRegX64 tmp4{regs, regs.takeReg(rArg1, kInvalidInstIdx)};
164
callWrap.addArgument(SizeX64::qword, tmp1);
165
callWrap.addArgument(SizeX64::qword, tmp2);
166
callWrap.addArgument(SizeX64::qword, tmp3);
167
callWrap.addArgument(SizeX64::qword, tmp4);
168
callWrap.call(qword[r12]);
169
170
checkMatch(R"(
171
mov r8,rdx
172
mov rdx,rsi
173
mov r9,rcx
174
mov rcx,rdi
175
call qword ptr [r12]
176
)");
177
}
178
179
TEST_CASE_FIXTURE(IrCallWrapperX64Fixture, "FakeInterference")
180
{
181
ScopedRegX64 tmp1{regs, regs.takeReg(rArg1, kInvalidInstIdx)};
182
ScopedRegX64 tmp2{regs, regs.takeReg(rArg2, kInvalidInstIdx)};
183
callWrap.addArgument(SizeX64::qword, qword[tmp1.release() + 8]);
184
callWrap.addArgument(SizeX64::qword, qword[tmp2.release() + 8]);
185
callWrap.call(qword[r12]);
186
187
checkMatch(R"(
188
mov rcx,qword ptr [rcx+8]
189
mov rdx,qword ptr [rdx+8]
190
call qword ptr [r12]
191
)");
192
}
193
194
TEST_CASE_FIXTURE(IrCallWrapperX64Fixture, "HardInterferenceInt")
195
{
196
ScopedRegX64 tmp1{regs, regs.takeReg(rArg4, kInvalidInstIdx)};
197
ScopedRegX64 tmp2{regs, regs.takeReg(rArg3, kInvalidInstIdx)};
198
ScopedRegX64 tmp3{regs, regs.takeReg(rArg2, kInvalidInstIdx)};
199
ScopedRegX64 tmp4{regs, regs.takeReg(rArg1, kInvalidInstIdx)};
200
callWrap.addArgument(SizeX64::qword, tmp1);
201
callWrap.addArgument(SizeX64::qword, tmp2);
202
callWrap.addArgument(SizeX64::qword, tmp3);
203
callWrap.addArgument(SizeX64::qword, tmp4);
204
callWrap.call(qword[r12]);
205
206
checkMatch(R"(
207
mov rax,r9
208
mov r9,rcx
209
mov rcx,rax
210
mov rax,r8
211
mov r8,rdx
212
mov rdx,rax
213
call qword ptr [r12]
214
)");
215
}
216
217
TEST_CASE_FIXTURE(IrCallWrapperX64Fixture, "HardInterferenceInt2")
218
{
219
ScopedRegX64 tmp1{regs, regs.takeReg(rArg4d, kInvalidInstIdx)};
220
ScopedRegX64 tmp2{regs, regs.takeReg(rArg3d, kInvalidInstIdx)};
221
ScopedRegX64 tmp3{regs, regs.takeReg(rArg2d, kInvalidInstIdx)};
222
ScopedRegX64 tmp4{regs, regs.takeReg(rArg1d, kInvalidInstIdx)};
223
callWrap.addArgument(SizeX64::dword, tmp1);
224
callWrap.addArgument(SizeX64::dword, tmp2);
225
callWrap.addArgument(SizeX64::dword, tmp3);
226
callWrap.addArgument(SizeX64::dword, tmp4);
227
callWrap.call(qword[r12]);
228
229
checkMatch(R"(
230
mov eax,r9d
231
mov r9d,ecx
232
mov ecx,eax
233
mov eax,r8d
234
mov r8d,edx
235
mov edx,eax
236
call qword ptr [r12]
237
)");
238
}
239
240
TEST_CASE_FIXTURE(IrCallWrapperX64Fixture, "HardInterferenceFp")
241
{
242
ScopedRegX64 tmp1{regs, regs.takeReg(xmm1, kInvalidInstIdx)};
243
ScopedRegX64 tmp2{regs, regs.takeReg(xmm0, kInvalidInstIdx)};
244
callWrap.addArgument(SizeX64::xmmword, tmp1);
245
callWrap.addArgument(SizeX64::xmmword, tmp2);
246
callWrap.call(qword[r12]);
247
248
checkMatch(R"(
249
vmovsd xmm2,xmm1,xmm1
250
vmovsd xmm1,xmm0,xmm0
251
vmovsd xmm0,xmm2,xmm2
252
call qword ptr [r12]
253
)");
254
}
255
256
TEST_CASE_FIXTURE(IrCallWrapperX64Fixture, "HardInterferenceBoth")
257
{
258
ScopedRegX64 int1{regs, regs.takeReg(rArg2, kInvalidInstIdx)};
259
ScopedRegX64 int2{regs, regs.takeReg(rArg1, kInvalidInstIdx)};
260
ScopedRegX64 fp1{regs, regs.takeReg(xmm3, kInvalidInstIdx)};
261
ScopedRegX64 fp2{regs, regs.takeReg(xmm2, kInvalidInstIdx)};
262
callWrap.addArgument(SizeX64::qword, int1);
263
callWrap.addArgument(SizeX64::qword, int2);
264
callWrap.addArgument(SizeX64::xmmword, fp1);
265
callWrap.addArgument(SizeX64::xmmword, fp2);
266
callWrap.call(qword[r12]);
267
268
checkMatch(R"(
269
mov rax,rdx
270
mov rdx,rcx
271
mov rcx,rax
272
vmovsd xmm0,xmm3,xmm3
273
vmovsd xmm3,xmm2,xmm2
274
vmovsd xmm2,xmm0,xmm0
275
call qword ptr [r12]
276
)");
277
}
278
279
TEST_CASE_FIXTURE(IrCallWrapperX64Fixture, "FakeMultiuseInterferenceMem")
280
{
281
ScopedRegX64 tmp1{regs, regs.takeReg(rArg1, kInvalidInstIdx)};
282
ScopedRegX64 tmp2{regs, regs.takeReg(rArg2, kInvalidInstIdx)};
283
callWrap.addArgument(SizeX64::qword, qword[tmp1.reg + tmp2.reg + 8]);
284
callWrap.addArgument(SizeX64::qword, qword[tmp2.reg + 16]);
285
tmp1.release();
286
tmp2.release();
287
callWrap.call(qword[r12]);
288
289
checkMatch(R"(
290
mov rcx,qword ptr [rcx+rdx+8]
291
mov rdx,qword ptr [rdx+010h]
292
call qword ptr [r12]
293
)");
294
}
295
296
TEST_CASE_FIXTURE(IrCallWrapperX64Fixture, "HardMultiuseInterferenceMem1")
297
{
298
ScopedRegX64 tmp1{regs, regs.takeReg(rArg1, kInvalidInstIdx)};
299
ScopedRegX64 tmp2{regs, regs.takeReg(rArg2, kInvalidInstIdx)};
300
callWrap.addArgument(SizeX64::qword, qword[tmp1.reg + tmp2.reg + 8]);
301
callWrap.addArgument(SizeX64::qword, qword[tmp1.reg + 16]);
302
tmp1.release();
303
tmp2.release();
304
callWrap.call(qword[r12]);
305
306
checkMatch(R"(
307
mov rax,rcx
308
mov rcx,qword ptr [rax+rdx+8]
309
mov rdx,qword ptr [rax+010h]
310
call qword ptr [r12]
311
)");
312
}
313
314
TEST_CASE_FIXTURE(IrCallWrapperX64Fixture, "HardMultiuseInterferenceMem2")
315
{
316
ScopedRegX64 tmp1{regs, regs.takeReg(rArg1, kInvalidInstIdx)};
317
ScopedRegX64 tmp2{regs, regs.takeReg(rArg2, kInvalidInstIdx)};
318
callWrap.addArgument(SizeX64::qword, qword[tmp1.reg + tmp2.reg + 8]);
319
callWrap.addArgument(SizeX64::qword, qword[tmp1.reg + tmp2.reg + 16]);
320
tmp1.release();
321
tmp2.release();
322
callWrap.call(qword[r12]);
323
324
checkMatch(R"(
325
mov rax,rcx
326
mov rcx,qword ptr [rax+rdx+8]
327
mov rdx,qword ptr [rax+rdx+010h]
328
call qword ptr [r12]
329
)");
330
}
331
332
TEST_CASE_FIXTURE(IrCallWrapperX64Fixture, "HardMultiuseInterferenceMem3")
333
{
334
ScopedRegX64 tmp1{regs, regs.takeReg(rArg3, kInvalidInstIdx)};
335
ScopedRegX64 tmp2{regs, regs.takeReg(rArg2, kInvalidInstIdx)};
336
ScopedRegX64 tmp3{regs, regs.takeReg(rArg1, kInvalidInstIdx)};
337
callWrap.addArgument(SizeX64::qword, qword[tmp1.reg + tmp2.reg + 8]);
338
callWrap.addArgument(SizeX64::qword, qword[tmp2.reg + tmp3.reg + 16]);
339
callWrap.addArgument(SizeX64::qword, qword[tmp3.reg + tmp1.reg + 16]);
340
tmp1.release();
341
tmp2.release();
342
tmp3.release();
343
callWrap.call(qword[r12]);
344
345
checkMatch(R"(
346
mov rax,r8
347
mov r8,qword ptr [rcx+rax+010h]
348
mov rbx,rdx
349
mov rdx,qword ptr [rbx+rcx+010h]
350
mov rcx,qword ptr [rax+rbx+8]
351
call qword ptr [r12]
352
)");
353
}
354
355
TEST_CASE_FIXTURE(IrCallWrapperX64Fixture, "InterferenceWithCallArg1")
356
{
357
ScopedRegX64 tmp1{regs, regs.takeReg(rArg1, kInvalidInstIdx)};
358
callWrap.addArgument(SizeX64::qword, qword[tmp1.reg + 8]);
359
callWrap.call(qword[tmp1.release() + 16]);
360
361
checkMatch(R"(
362
mov rax,rcx
363
mov rcx,qword ptr [rax+8]
364
call qword ptr [rax+010h]
365
)");
366
}
367
368
TEST_CASE_FIXTURE(IrCallWrapperX64Fixture, "InterferenceWithCallArg2")
369
{
370
ScopedRegX64 tmp1{regs, regs.takeReg(rArg1, kInvalidInstIdx)};
371
ScopedRegX64 tmp2{regs, regs.takeReg(rArg2, kInvalidInstIdx)};
372
callWrap.addArgument(SizeX64::qword, tmp2);
373
callWrap.call(qword[tmp1.release() + 16]);
374
375
checkMatch(R"(
376
mov rax,rcx
377
mov rcx,rdx
378
call qword ptr [rax+010h]
379
)");
380
}
381
382
TEST_CASE_FIXTURE(IrCallWrapperX64Fixture, "InterferenceWithCallArg3")
383
{
384
ScopedRegX64 tmp1{regs, regs.takeReg(rArg1, kInvalidInstIdx)};
385
callWrap.addArgument(SizeX64::qword, tmp1.reg);
386
callWrap.call(qword[tmp1.release() + 16]);
387
388
checkMatch(R"(
389
call qword ptr [rcx+010h]
390
)");
391
}
392
393
TEST_CASE_FIXTURE(IrCallWrapperX64Fixture, "WithLastIrInstUse1")
394
{
395
IrInst irInst1;
396
IrOp irOp1 = {IrOpKind::Inst, 0};
397
irInst1.regX64 = regs.takeReg(xmm0, irOp1.index);
398
irInst1.lastUse = 1;
399
function.instructions.push_back(irInst1);
400
callWrap.instIdx = irInst1.lastUse;
401
402
callWrap.addArgument(SizeX64::xmmword, irInst1.regX64, irOp1); // Already in its place
403
callWrap.addArgument(SizeX64::xmmword, qword[r12 + 8]);
404
callWrap.call(qword[r12]);
405
406
checkMatch(R"(
407
vmovsd xmm1,qword ptr [r12+8]
408
call qword ptr [r12]
409
)");
410
}
411
412
TEST_CASE_FIXTURE(IrCallWrapperX64Fixture, "WithLastIrInstUse2")
413
{
414
IrInst irInst1;
415
IrOp irOp1 = {IrOpKind::Inst, 0};
416
irInst1.regX64 = regs.takeReg(xmm0, irOp1.index);
417
irInst1.lastUse = 1;
418
function.instructions.push_back(irInst1);
419
callWrap.instIdx = irInst1.lastUse;
420
421
callWrap.addArgument(SizeX64::xmmword, qword[r12 + 8]);
422
callWrap.addArgument(SizeX64::xmmword, irInst1.regX64, irOp1);
423
callWrap.call(qword[r12]);
424
425
checkMatch(R"(
426
vmovsd xmm1,xmm0,xmm0
427
vmovsd xmm0,qword ptr [r12+8]
428
call qword ptr [r12]
429
)");
430
}
431
432
TEST_CASE_FIXTURE(IrCallWrapperX64Fixture, "WithLastIrInstUse3")
433
{
434
IrInst irInst1;
435
IrOp irOp1 = {IrOpKind::Inst, 0};
436
irInst1.regX64 = regs.takeReg(xmm0, irOp1.index);
437
irInst1.lastUse = 1;
438
function.instructions.push_back(irInst1);
439
callWrap.instIdx = irInst1.lastUse;
440
441
callWrap.addArgument(SizeX64::xmmword, irInst1.regX64, irOp1);
442
callWrap.addArgument(SizeX64::xmmword, irInst1.regX64, irOp1);
443
callWrap.call(qword[r12]);
444
445
checkMatch(R"(
446
vmovsd xmm1,xmm0,xmm0
447
call qword ptr [r12]
448
)");
449
}
450
451
TEST_CASE_FIXTURE(IrCallWrapperX64Fixture, "WithLastIrInstUse4")
452
{
453
IrInst irInst1;
454
IrOp irOp1 = {IrOpKind::Inst, 0};
455
irInst1.regX64 = regs.takeReg(rax, irOp1.index);
456
irInst1.lastUse = 1;
457
function.instructions.push_back(irInst1);
458
callWrap.instIdx = irInst1.lastUse;
459
460
ScopedRegX64 tmp{regs, regs.takeReg(rdx, kInvalidInstIdx)};
461
callWrap.addArgument(SizeX64::qword, r15);
462
callWrap.addArgument(SizeX64::qword, irInst1.regX64, irOp1);
463
callWrap.addArgument(SizeX64::qword, tmp);
464
callWrap.call(qword[r12]);
465
466
checkMatch(R"(
467
mov rcx,r15
468
mov r8,rdx
469
mov rdx,rax
470
call qword ptr [r12]
471
)");
472
}
473
474
TEST_CASE_FIXTURE(IrCallWrapperX64Fixture, "ExtraCoverage")
475
{
476
ScopedRegX64 tmp1{regs, regs.takeReg(rArg1, kInvalidInstIdx)};
477
ScopedRegX64 tmp2{regs, regs.takeReg(rArg2, kInvalidInstIdx)};
478
callWrap.addArgument(SizeX64::qword, addr[r12 + 8]);
479
callWrap.addArgument(SizeX64::qword, addr[r12 + 16]);
480
callWrap.addArgument(SizeX64::xmmword, xmmword[r13]);
481
callWrap.call(qword[tmp1.release() + tmp2.release()]);
482
483
checkMatch(R"(
484
vmovups xmm2,xmmword ptr [r13]
485
mov rax,rcx
486
lea rcx,[r12+8]
487
mov rbx,rdx
488
lea rdx,[r12+010h]
489
call qword ptr [rax+rbx]
490
)");
491
}
492
493
TEST_CASE_FIXTURE(IrCallWrapperX64Fixture, "AddressInStackArguments")
494
{
495
callWrap.addArgument(SizeX64::dword, 1);
496
callWrap.addArgument(SizeX64::dword, 2);
497
callWrap.addArgument(SizeX64::dword, 3);
498
callWrap.addArgument(SizeX64::dword, 4);
499
callWrap.addArgument(SizeX64::qword, addr[r12 + 16]);
500
callWrap.call(qword[r14]);
501
502
checkMatch(R"(
503
lea rax,[r12+010h]
504
mov qword ptr [rsp+020h],rax
505
mov ecx,1
506
mov edx,2
507
mov r8d,3
508
mov r9d,4
509
call qword ptr [r14]
510
)");
511
}
512
513
TEST_CASE_FIXTURE(IrCallWrapperX64Fixture, "ImmediateConflictWithFunction")
514
{
515
ScopedRegX64 tmp1{regs, regs.takeReg(rArg1, kInvalidInstIdx)};
516
ScopedRegX64 tmp2{regs, regs.takeReg(rArg2, kInvalidInstIdx)};
517
518
callWrap.addArgument(SizeX64::dword, 1);
519
callWrap.addArgument(SizeX64::dword, 2);
520
callWrap.call(qword[tmp1.release() + tmp2.release()]);
521
522
checkMatch(R"(
523
mov rax,rcx
524
mov ecx,1
525
mov rbx,rdx
526
mov edx,2
527
call qword ptr [rax+rbx]
528
)");
529
}
530
531
TEST_CASE_FIXTURE(IrCallWrapperX64FixtureSystemV, "SuggestedConflictWithReserved")
532
{
533
ScopedRegX64 tmp{regs, regs.takeReg(r9, kInvalidInstIdx)};
534
535
IrCallWrapperX64 callWrap(regs, build);
536
callWrap.addArgument(SizeX64::qword, r12);
537
callWrap.addArgument(SizeX64::qword, r13);
538
callWrap.addArgument(SizeX64::qword, r14);
539
callWrap.addArgument(SizeX64::dword, 2);
540
callWrap.addArgument(SizeX64::qword, 1);
541
542
RegisterX64 reg = callWrap.suggestNextArgumentRegister(SizeX64::dword);
543
build.mov(reg, 10);
544
callWrap.addArgument(SizeX64::dword, reg);
545
546
callWrap.call(tmp.release());
547
548
checkMatch(R"(
549
mov eax,Ah
550
mov rdi,r12
551
mov rsi,r13
552
mov rdx,r14
553
mov rcx,r9
554
mov r9d,eax
555
mov rax,rcx
556
mov ecx,2
557
mov r8,1
558
call rax
559
)");
560
}
561
562
TEST_SUITE_END();
563
564