Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/tests/AssemblyBuilderX64.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/AssemblyBuilderX64.h"
3
#include "Luau/StringUtils.h"
4
5
#include "doctest.h"
6
#include "ScopedFlags.h"
7
8
#include <string.h>
9
10
using namespace Luau::CodeGen;
11
using namespace Luau::CodeGen::X64;
12
13
static std::string bytecodeAsArray(const std::vector<uint8_t>& bytecode)
14
{
15
std::string result = "{";
16
17
for (size_t i = 0; i < bytecode.size(); i++)
18
Luau::formatAppend(result, "%s0x%02x", i == 0 ? "" : ", ", bytecode[i]);
19
20
return result.append("}");
21
}
22
23
class AssemblyBuilderX64Fixture
24
{
25
public:
26
bool check(void (*f)(AssemblyBuilderX64& build), std::vector<uint8_t> code, std::vector<uint8_t> data = {})
27
{
28
AssemblyBuilderX64 build(/* logText= */ false);
29
30
f(build);
31
32
build.finalize();
33
34
if (build.code != code)
35
{
36
printf("Expected code: %s\nReceived code: %s\n", bytecodeAsArray(code).c_str(), bytecodeAsArray(build.code).c_str());
37
return false;
38
}
39
40
if (build.data != data)
41
{
42
printf("Expected data: %s\nReceived data: %s\n", bytecodeAsArray(data).c_str(), bytecodeAsArray(build.data).c_str());
43
return false;
44
}
45
46
return true;
47
}
48
};
49
50
TEST_SUITE_BEGIN("x64Assembly");
51
52
#define SINGLE_COMPARE(inst, ...) \
53
CHECK(check( \
54
[](AssemblyBuilderX64& build) \
55
{ \
56
build.inst; \
57
}, \
58
{__VA_ARGS__} \
59
))
60
61
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "BaseBinaryInstructionForms")
62
{
63
// reg, reg
64
SINGLE_COMPARE(add(rax, rcx), 0x48, 0x03, 0xc1);
65
SINGLE_COMPARE(add(rsp, r12), 0x49, 0x03, 0xe4);
66
SINGLE_COMPARE(add(r14, r10), 0x4d, 0x03, 0xf2);
67
68
// reg, imm
69
SINGLE_COMPARE(add(rax, 0), 0x48, 0x83, 0xc0, 0x00);
70
SINGLE_COMPARE(add(rax, 0x7f), 0x48, 0x83, 0xc0, 0x7f);
71
SINGLE_COMPARE(add(rax, 0x80), 0x48, 0x81, 0xc0, 0x80, 0x00, 0x00, 0x00);
72
SINGLE_COMPARE(add(r10, 0x7fffffff), 0x49, 0x81, 0xc2, 0xff, 0xff, 0xff, 0x7f);
73
SINGLE_COMPARE(add(al, 3), 0x80, 0xc0, 0x03);
74
SINGLE_COMPARE(add(sil, 3), 0x40, 0x80, 0xc6, 0x03);
75
SINGLE_COMPARE(add(r11b, 3), 0x41, 0x80, 0xc3, 0x03);
76
77
// reg, [reg]
78
SINGLE_COMPARE(add(rax, qword[rax]), 0x48, 0x03, 0x00);
79
SINGLE_COMPARE(add(rax, qword[rbx]), 0x48, 0x03, 0x03);
80
SINGLE_COMPARE(add(rax, qword[rsp]), 0x48, 0x03, 0x04, 0x24);
81
SINGLE_COMPARE(add(rax, qword[rbp]), 0x48, 0x03, 0x45, 0x00);
82
SINGLE_COMPARE(add(rax, qword[r10]), 0x49, 0x03, 0x02);
83
SINGLE_COMPARE(add(rax, qword[r12]), 0x49, 0x03, 0x04, 0x24);
84
SINGLE_COMPARE(add(rax, qword[r13]), 0x49, 0x03, 0x45, 0x00);
85
86
SINGLE_COMPARE(add(r12, qword[rax]), 0x4c, 0x03, 0x20);
87
SINGLE_COMPARE(add(r12, qword[rbx]), 0x4c, 0x03, 0x23);
88
SINGLE_COMPARE(add(r12, qword[rsp]), 0x4c, 0x03, 0x24, 0x24);
89
SINGLE_COMPARE(add(r12, qword[rbp]), 0x4c, 0x03, 0x65, 0x00);
90
SINGLE_COMPARE(add(r12, qword[r10]), 0x4d, 0x03, 0x22);
91
SINGLE_COMPARE(add(r12, qword[r12]), 0x4d, 0x03, 0x24, 0x24);
92
SINGLE_COMPARE(add(r12, qword[r13]), 0x4d, 0x03, 0x65, 0x00);
93
94
// reg, [base+imm8]
95
SINGLE_COMPARE(add(rax, qword[rax + 0x1b]), 0x48, 0x03, 0x40, 0x1b);
96
SINGLE_COMPARE(add(rax, qword[rbx + 0x1b]), 0x48, 0x03, 0x43, 0x1b);
97
SINGLE_COMPARE(add(rax, qword[rsp + 0x1b]), 0x48, 0x03, 0x44, 0x24, 0x1b);
98
SINGLE_COMPARE(add(rax, qword[rbp + 0x1b]), 0x48, 0x03, 0x45, 0x1b);
99
SINGLE_COMPARE(add(rax, qword[r10 + 0x1b]), 0x49, 0x03, 0x42, 0x1b);
100
SINGLE_COMPARE(add(rax, qword[r12 + 0x1b]), 0x49, 0x03, 0x44, 0x24, 0x1b);
101
SINGLE_COMPARE(add(rax, qword[r13 + 0x1b]), 0x49, 0x03, 0x45, 0x1b);
102
103
SINGLE_COMPARE(add(r12, qword[rax + 0x1b]), 0x4c, 0x03, 0x60, 0x1b);
104
SINGLE_COMPARE(add(r12, qword[rbx + 0x1b]), 0x4c, 0x03, 0x63, 0x1b);
105
SINGLE_COMPARE(add(r12, qword[rsp + 0x1b]), 0x4c, 0x03, 0x64, 0x24, 0x1b);
106
SINGLE_COMPARE(add(r12, qword[rbp + 0x1b]), 0x4c, 0x03, 0x65, 0x1b);
107
SINGLE_COMPARE(add(r12, qword[r10 + 0x1b]), 0x4d, 0x03, 0x62, 0x1b);
108
SINGLE_COMPARE(add(r12, qword[r12 + 0x1b]), 0x4d, 0x03, 0x64, 0x24, 0x1b);
109
SINGLE_COMPARE(add(r12, qword[r13 + 0x1b]), 0x4d, 0x03, 0x65, 0x1b);
110
111
// reg, [base+imm32]
112
SINGLE_COMPARE(add(rax, qword[rax + 0xabab]), 0x48, 0x03, 0x80, 0xab, 0xab, 0x00, 0x00);
113
SINGLE_COMPARE(add(rax, qword[rbx + 0xabab]), 0x48, 0x03, 0x83, 0xab, 0xab, 0x00, 0x00);
114
SINGLE_COMPARE(add(rax, qword[rsp + 0xabab]), 0x48, 0x03, 0x84, 0x24, 0xab, 0xab, 0x00, 0x00);
115
SINGLE_COMPARE(add(rax, qword[rbp + 0xabab]), 0x48, 0x03, 0x85, 0xab, 0xab, 0x00, 0x00);
116
SINGLE_COMPARE(add(rax, qword[r10 + 0xabab]), 0x49, 0x03, 0x82, 0xab, 0xab, 0x00, 0x00);
117
SINGLE_COMPARE(add(rax, qword[r12 + 0xabab]), 0x49, 0x03, 0x84, 0x24, 0xab, 0xab, 0x00, 0x00);
118
SINGLE_COMPARE(add(rax, qword[r13 + 0xabab]), 0x49, 0x03, 0x85, 0xab, 0xab, 0x00, 0x00);
119
120
SINGLE_COMPARE(add(r12, qword[rax + 0xabab]), 0x4c, 0x03, 0xa0, 0xab, 0xab, 0x00, 0x00);
121
SINGLE_COMPARE(add(r12, qword[rbx + 0xabab]), 0x4c, 0x03, 0xa3, 0xab, 0xab, 0x00, 0x00);
122
SINGLE_COMPARE(add(r12, qword[rsp + 0xabab]), 0x4c, 0x03, 0xa4, 0x24, 0xab, 0xab, 0x00, 0x00);
123
SINGLE_COMPARE(add(r12, qword[rbp + 0xabab]), 0x4c, 0x03, 0xa5, 0xab, 0xab, 0x00, 0x00);
124
SINGLE_COMPARE(add(r12, qword[r10 + 0xabab]), 0x4d, 0x03, 0xa2, 0xab, 0xab, 0x00, 0x00);
125
SINGLE_COMPARE(add(r12, qword[r12 + 0xabab]), 0x4d, 0x03, 0xa4, 0x24, 0xab, 0xab, 0x00, 0x00);
126
SINGLE_COMPARE(add(r12, qword[r13 + 0xabab]), 0x4d, 0x03, 0xa5, 0xab, 0xab, 0x00, 0x00);
127
128
// reg, [index*scale]
129
SINGLE_COMPARE(add(rax, qword[rax * 2]), 0x48, 0x03, 0x04, 0x45, 0x00, 0x00, 0x00, 0x00);
130
SINGLE_COMPARE(add(rax, qword[rbx * 2]), 0x48, 0x03, 0x04, 0x5d, 0x00, 0x00, 0x00, 0x00);
131
SINGLE_COMPARE(add(rax, qword[rbp * 2]), 0x48, 0x03, 0x04, 0x6d, 0x00, 0x00, 0x00, 0x00);
132
SINGLE_COMPARE(add(rax, qword[r10 * 2]), 0x4a, 0x03, 0x04, 0x55, 0x00, 0x00, 0x00, 0x00);
133
SINGLE_COMPARE(add(rax, qword[r12 * 2]), 0x4a, 0x03, 0x04, 0x65, 0x00, 0x00, 0x00, 0x00);
134
SINGLE_COMPARE(add(rax, qword[r13 * 2]), 0x4a, 0x03, 0x04, 0x6d, 0x00, 0x00, 0x00, 0x00);
135
136
SINGLE_COMPARE(add(r12, qword[rax * 2]), 0x4c, 0x03, 0x24, 0x45, 0x00, 0x00, 0x00, 0x00);
137
SINGLE_COMPARE(add(r12, qword[rbx * 2]), 0x4c, 0x03, 0x24, 0x5d, 0x00, 0x00, 0x00, 0x00);
138
SINGLE_COMPARE(add(r12, qword[rbp * 2]), 0x4c, 0x03, 0x24, 0x6d, 0x00, 0x00, 0x00, 0x00);
139
SINGLE_COMPARE(add(r12, qword[r10 * 2]), 0x4e, 0x03, 0x24, 0x55, 0x00, 0x00, 0x00, 0x00);
140
SINGLE_COMPARE(add(r12, qword[r12 * 2]), 0x4e, 0x03, 0x24, 0x65, 0x00, 0x00, 0x00, 0x00);
141
SINGLE_COMPARE(add(r12, qword[r13 * 2]), 0x4e, 0x03, 0x24, 0x6d, 0x00, 0x00, 0x00, 0x00);
142
143
// reg, [base+index*scale+imm]
144
SINGLE_COMPARE(add(rax, qword[rax + rax * 2]), 0x48, 0x03, 0x04, 0x40);
145
SINGLE_COMPARE(add(rax, qword[rax + rbx * 2 + 0x1b]), 0x48, 0x03, 0x44, 0x58, 0x1b);
146
SINGLE_COMPARE(add(rax, qword[rax + rbp * 2]), 0x48, 0x03, 0x04, 0x68);
147
SINGLE_COMPARE(add(rax, qword[rax + rbp + 0xabab]), 0x48, 0x03, 0x84, 0x28, 0xAB, 0xab, 0x00, 0x00);
148
SINGLE_COMPARE(add(rax, qword[rax + r12 + 0x1b]), 0x4a, 0x03, 0x44, 0x20, 0x1b);
149
SINGLE_COMPARE(add(rax, qword[rax + r12 * 4 + 0xabab]), 0x4a, 0x03, 0x84, 0xa0, 0xab, 0xab, 0x00, 0x00);
150
SINGLE_COMPARE(add(rax, qword[rax + r13 * 2 + 0x1b]), 0x4a, 0x03, 0x44, 0x68, 0x1b);
151
SINGLE_COMPARE(add(rax, qword[rax + r13 + 0xabab]), 0x4a, 0x03, 0x84, 0x28, 0xab, 0xab, 0x00, 0x00);
152
SINGLE_COMPARE(add(r12, qword[rax + r12 * 2]), 0x4e, 0x03, 0x24, 0x60);
153
SINGLE_COMPARE(add(r12, qword[rax + r13 + 0xabab]), 0x4e, 0x03, 0xA4, 0x28, 0xab, 0xab, 0x00, 0x00);
154
SINGLE_COMPARE(add(r12, qword[rax + rbp * 2 + 0x1b]), 0x4c, 0x03, 0x64, 0x68, 0x1b);
155
156
// reg, [imm32]
157
SINGLE_COMPARE(add(rax, qword[0]), 0x48, 0x03, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00);
158
SINGLE_COMPARE(add(rax, qword[0xabab]), 0x48, 0x03, 0x04, 0x25, 0xab, 0xab, 0x00, 0x00);
159
160
// [addr], reg
161
SINGLE_COMPARE(add(qword[rax], rax), 0x48, 0x01, 0x00);
162
SINGLE_COMPARE(add(qword[rax + rax * 4 + 0xabab], rax), 0x48, 0x01, 0x84, 0x80, 0xab, 0xab, 0x00, 0x00);
163
SINGLE_COMPARE(add(qword[rbx + rax * 2 + 0x1b], rax), 0x48, 0x01, 0x44, 0x43, 0x1b);
164
SINGLE_COMPARE(add(qword[rbx + rbp * 2 + 0x1b], rax), 0x48, 0x01, 0x44, 0x6b, 0x1b);
165
SINGLE_COMPARE(add(qword[rbp + rbp * 4 + 0xabab], rax), 0x48, 0x01, 0x84, 0xad, 0xab, 0xab, 0x00, 0x00);
166
SINGLE_COMPARE(add(qword[rbp + r12 + 0x1b], rax), 0x4a, 0x01, 0x44, 0x25, 0x1b);
167
SINGLE_COMPARE(add(qword[r12], rax), 0x49, 0x01, 0x04, 0x24);
168
SINGLE_COMPARE(add(qword[r13 + rbx + 0xabab], rax), 0x49, 0x01, 0x84, 0x1d, 0xab, 0xab, 0x00, 0x00);
169
SINGLE_COMPARE(add(qword[rax + r13 * 2 + 0x1b], rsi), 0x4a, 0x01, 0x74, 0x68, 0x1b);
170
SINGLE_COMPARE(add(qword[rbp + rbx * 2], rsi), 0x48, 0x01, 0x74, 0x5d, 0x00);
171
SINGLE_COMPARE(add(qword[rsp + r10 * 2 + 0x1b], r10), 0x4e, 0x01, 0x54, 0x54, 0x1b);
172
173
// [addr], imm
174
SINGLE_COMPARE(add(byte[rax], 2), 0x80, 0x00, 0x02);
175
SINGLE_COMPARE(add(dword[rax], 2), 0x83, 0x00, 0x02);
176
SINGLE_COMPARE(add(dword[rax], 0xabcd), 0x81, 0x00, 0xcd, 0xab, 0x00, 0x00);
177
SINGLE_COMPARE(add(qword[rax], 2), 0x48, 0x83, 0x00, 0x02);
178
SINGLE_COMPARE(add(qword[rax], 0xabcd), 0x48, 0x81, 0x00, 0xcd, 0xab, 0x00, 0x00);
179
}
180
181
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "BaseUnaryInstructionForms")
182
{
183
SINGLE_COMPARE(div(rcx), 0x48, 0xf7, 0xf1);
184
SINGLE_COMPARE(idiv(qword[rax]), 0x48, 0xf7, 0x38);
185
SINGLE_COMPARE(mul(qword[rax + rbx]), 0x48, 0xf7, 0x24, 0x18);
186
SINGLE_COMPARE(imul(r9), 0x49, 0xf7, 0xe9);
187
SINGLE_COMPARE(neg(r9), 0x49, 0xf7, 0xd9);
188
SINGLE_COMPARE(not_(r12), 0x49, 0xf7, 0xd4);
189
SINGLE_COMPARE(inc(r12), 0x49, 0xff, 0xc4);
190
SINGLE_COMPARE(dec(ecx), 0xff, 0xc9);
191
SINGLE_COMPARE(dec(byte[rdx]), 0xfe, 0x0a);
192
}
193
194
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "FormsOfMov")
195
{
196
SINGLE_COMPARE(mov(rcx, 1), 0x48, 0xb9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
197
SINGLE_COMPARE(mov64(rcx, 0x1234567812345678ll), 0x48, 0xb9, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12);
198
SINGLE_COMPARE(mov(ecx, 2), 0xb9, 0x02, 0x00, 0x00, 0x00);
199
SINGLE_COMPARE(mov(cl, 2), 0xb1, 0x02);
200
SINGLE_COMPARE(mov(sil, 2), 0x40, 0xb6, 0x02);
201
SINGLE_COMPARE(mov(r9b, 2), 0x41, 0xb1, 0x02);
202
SINGLE_COMPARE(mov(rcx, qword[rdi]), 0x48, 0x8b, 0x0f);
203
SINGLE_COMPARE(mov(dword[rax], 0xabcd), 0xc7, 0x00, 0xcd, 0xab, 0x00, 0x00);
204
SINGLE_COMPARE(mov(r13, 1), 0x49, 0xbd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
205
SINGLE_COMPARE(mov64(r13, 0x1234567812345678ll), 0x49, 0xbd, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12);
206
SINGLE_COMPARE(mov(r13d, 2), 0x41, 0xbd, 0x02, 0x00, 0x00, 0x00);
207
SINGLE_COMPARE(mov(r13, qword[r12]), 0x4d, 0x8b, 0x2c, 0x24);
208
SINGLE_COMPARE(mov(dword[r13], 0xabcd), 0x41, 0xc7, 0x45, 0x00, 0xcd, 0xab, 0x00, 0x00);
209
SINGLE_COMPARE(mov(qword[rdx], r9), 0x4c, 0x89, 0x0a);
210
SINGLE_COMPARE(mov(byte[rsi], 0x3), 0xc6, 0x06, 0x03);
211
SINGLE_COMPARE(mov(byte[rsi], al), 0x88, 0x06);
212
SINGLE_COMPARE(mov(byte[rsi], dil), 0x40, 0x88, 0x3e);
213
SINGLE_COMPARE(mov(byte[rsi], r10b), 0x44, 0x88, 0x16);
214
SINGLE_COMPARE(mov(wordReg(ebx), 0x3a3d), 0x66, 0xbb, 0x3d, 0x3a);
215
SINGLE_COMPARE(mov(word[rsi], 0x3a3d), 0x66, 0xc7, 0x06, 0x3d, 0x3a);
216
SINGLE_COMPARE(mov(word[rsi], wordReg(eax)), 0x66, 0x89, 0x06);
217
SINGLE_COMPARE(mov(word[rsi], wordReg(edi)), 0x66, 0x89, 0x3e);
218
SINGLE_COMPARE(mov(word[rsi], wordReg(r10)), 0x66, 0x44, 0x89, 0x16);
219
}
220
221
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "FormsOfMovExtended")
222
{
223
SINGLE_COMPARE(movsx(eax, byte[rcx]), 0x0f, 0xbe, 0x01);
224
SINGLE_COMPARE(movsx(r12, byte[r10]), 0x4d, 0x0f, 0xbe, 0x22);
225
SINGLE_COMPARE(movsx(ebx, word[r11]), 0x41, 0x0f, 0xbf, 0x1b);
226
SINGLE_COMPARE(movsx(rdx, word[rcx]), 0x48, 0x0f, 0xbf, 0x11);
227
SINGLE_COMPARE(movsx(edx, cl), 0x0f, 0xbe, 0xd1);
228
SINGLE_COMPARE(movsx(edx, r12b), 0x41, 0x0f, 0xbe, 0xd4);
229
SINGLE_COMPARE(movsx(edx, wordReg(ecx)), 0x0f, 0xbf, 0xd1);
230
SINGLE_COMPARE(movsx(edx, wordReg(r12d)), 0x41, 0x0f, 0xbf, 0xd4);
231
SINGLE_COMPARE(movzx(eax, byte[rcx]), 0x0f, 0xb6, 0x01);
232
SINGLE_COMPARE(movzx(r12, byte[r10]), 0x4d, 0x0f, 0xb6, 0x22);
233
SINGLE_COMPARE(movzx(ebx, word[r11]), 0x41, 0x0f, 0xb7, 0x1b);
234
SINGLE_COMPARE(movzx(rdx, word[rcx]), 0x48, 0x0f, 0xb7, 0x11);
235
SINGLE_COMPARE(movzx(edx, cl), 0x0f, 0xb6, 0xd1);
236
SINGLE_COMPARE(movzx(edx, r12b), 0x41, 0x0f, 0xb6, 0xd4);
237
SINGLE_COMPARE(movzx(edx, wordReg(ecx)), 0x0f, 0xb7, 0xd1);
238
SINGLE_COMPARE(movzx(edx, wordReg(r12d)), 0x41, 0x0f, 0xb7, 0xd4);
239
}
240
241
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "FormsOfTest")
242
{
243
SINGLE_COMPARE(test(al, 8), 0xf6, 0xc0, 0x08);
244
SINGLE_COMPARE(test(eax, 8), 0xf7, 0xc0, 0x08, 0x00, 0x00, 0x00);
245
SINGLE_COMPARE(test(rax, 8), 0x48, 0xf7, 0xc0, 0x08, 0x00, 0x00, 0x00);
246
SINGLE_COMPARE(test(rcx, 0xabab), 0x48, 0xf7, 0xc1, 0xab, 0xab, 0x00, 0x00);
247
SINGLE_COMPARE(test(rcx, rax), 0x48, 0x85, 0xc8);
248
SINGLE_COMPARE(test(rax, qword[rcx]), 0x48, 0x85, 0x01);
249
SINGLE_COMPARE(test(al, cl), 0x84, 0xc1);
250
SINGLE_COMPARE(test(al, sil), 0x40, 0x84, 0xc6);
251
SINGLE_COMPARE(test(cl, r12b), 0x41, 0x84, 0xcc);
252
SINGLE_COMPARE(test(sil, dil), 0x40, 0x84, 0xf7);
253
}
254
255
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "FormsOfShift")
256
{
257
SINGLE_COMPARE(shl(al, 1), 0xd0, 0xe0);
258
SINGLE_COMPARE(shl(al, cl), 0xd2, 0xe0);
259
SINGLE_COMPARE(shl(sil, cl), 0x40, 0xd2, 0xe6);
260
SINGLE_COMPARE(shl(r10b, cl), 0x41, 0xd2, 0xe2);
261
SINGLE_COMPARE(shr(al, 4), 0xc0, 0xe8, 0x04);
262
SINGLE_COMPARE(shr(eax, 1), 0xd1, 0xe8);
263
SINGLE_COMPARE(sal(eax, cl), 0xd3, 0xe0);
264
SINGLE_COMPARE(sal(eax, 4), 0xc1, 0xe0, 0x04);
265
SINGLE_COMPARE(sar(rax, 4), 0x48, 0xc1, 0xf8, 0x04);
266
SINGLE_COMPARE(sar(r11, 1), 0x49, 0xd1, 0xfb);
267
SINGLE_COMPARE(rol(eax, 1), 0xd1, 0xc0);
268
SINGLE_COMPARE(rol(eax, cl), 0xd3, 0xc0);
269
SINGLE_COMPARE(ror(eax, 1), 0xd1, 0xc8);
270
SINGLE_COMPARE(ror(eax, cl), 0xd3, 0xc8);
271
}
272
273
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "FormsOfLea")
274
{
275
SINGLE_COMPARE(lea(rax, addr[rdx + rcx]), 0x48, 0x8d, 0x04, 0x0a);
276
SINGLE_COMPARE(lea(rax, addr[rdx + rax * 4]), 0x48, 0x8d, 0x04, 0x82);
277
SINGLE_COMPARE(lea(rax, addr[r13 + r12 * 4 + 4]), 0x4b, 0x8d, 0x44, 0xa5, 0x04);
278
}
279
280
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "FormsOfSetcc")
281
{
282
SINGLE_COMPARE(setcc(ConditionX64::NotEqual, bl), 0x0f, 0x95, 0xc3);
283
SINGLE_COMPARE(setcc(ConditionX64::NotEqual, dil), 0x40, 0x0f, 0x95, 0xc7);
284
SINGLE_COMPARE(setcc(ConditionX64::BelowEqual, byte[rcx]), 0x0f, 0x96, 0x01);
285
}
286
287
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "FormsOfCmov")
288
{
289
SINGLE_COMPARE(cmov(ConditionX64::LessEqual, ebx, eax), 0x0f, 0x4e, 0xd8);
290
SINGLE_COMPARE(cmov(ConditionX64::NotZero, rbx, qword[rax]), 0x48, 0x0f, 0x45, 0x18);
291
SINGLE_COMPARE(cmov(ConditionX64::Zero, rbx, qword[rax + rcx]), 0x48, 0x0f, 0x44, 0x1c, 0x08);
292
SINGLE_COMPARE(cmov(ConditionX64::BelowEqual, r14d, r15d), 0x45, 0x0f, 0x46, 0xf7);
293
}
294
295
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "FormsOfAbsoluteJumps")
296
{
297
SINGLE_COMPARE(jmp(rax), 0xff, 0xe0);
298
SINGLE_COMPARE(jmp(r14), 0x41, 0xff, 0xe6);
299
SINGLE_COMPARE(jmp(qword[r14 + rdx * 4]), 0x41, 0xff, 0x24, 0x96);
300
SINGLE_COMPARE(call(rax), 0xff, 0xd0);
301
SINGLE_COMPARE(call(r14), 0x41, 0xff, 0xd6);
302
SINGLE_COMPARE(call(qword[r14 + rdx * 4]), 0x41, 0xff, 0x14, 0x96);
303
}
304
305
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "FormsOfImul")
306
{
307
SINGLE_COMPARE(imul(ecx, esi), 0x0f, 0xaf, 0xce);
308
SINGLE_COMPARE(imul(r12, rax), 0x4c, 0x0f, 0xaf, 0xe0);
309
SINGLE_COMPARE(imul(r12, qword[rdx + rdi]), 0x4c, 0x0f, 0xaf, 0x24, 0x3a);
310
SINGLE_COMPARE(imul(ecx, edx, 8), 0x6b, 0xca, 0x08);
311
SINGLE_COMPARE(imul(ecx, r9d, 0xabcd), 0x41, 0x69, 0xc9, 0xcd, 0xab, 0x00, 0x00);
312
SINGLE_COMPARE(imul(r8d, eax, -9), 0x44, 0x6b, 0xc0, 0xf7);
313
SINGLE_COMPARE(imul(rcx, rdx, 17), 0x48, 0x6b, 0xca, 0x11);
314
SINGLE_COMPARE(imul(rcx, r12, 0xabcd), 0x49, 0x69, 0xcc, 0xcd, 0xab, 0x00, 0x00);
315
SINGLE_COMPARE(imul(r12, rax, -13), 0x4c, 0x6b, 0xe0, 0xf3);
316
}
317
318
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "NopForms")
319
{
320
SINGLE_COMPARE(nop(), 0x90);
321
SINGLE_COMPARE(nop(2), 0x66, 0x90);
322
SINGLE_COMPARE(nop(3), 0x0f, 0x1f, 0x00);
323
SINGLE_COMPARE(nop(4), 0x0f, 0x1f, 0x40, 0x00);
324
SINGLE_COMPARE(nop(5), 0x0f, 0x1f, 0x44, 0x00, 0x00);
325
SINGLE_COMPARE(nop(6), 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00);
326
SINGLE_COMPARE(nop(7), 0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00);
327
SINGLE_COMPARE(nop(8), 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00);
328
SINGLE_COMPARE(nop(9), 0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00);
329
SINGLE_COMPARE(nop(15), 0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00); // 9+6
330
}
331
332
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "AlignmentForms")
333
{
334
CHECK(check(
335
[](AssemblyBuilderX64& build)
336
{
337
build.ret();
338
build.align(8, AlignmentDataX64::Nop);
339
},
340
{0xc3, 0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00}
341
));
342
343
CHECK(check(
344
[](AssemblyBuilderX64& build)
345
{
346
build.ret();
347
build.align(32, AlignmentDataX64::Nop);
348
},
349
{0xc3, 0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00,
350
0x00, 0x00, 0x00, 0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x1f, 0x40, 0x00}
351
));
352
353
CHECK(check(
354
[](AssemblyBuilderX64& build)
355
{
356
build.ret();
357
build.align(8, AlignmentDataX64::Int3);
358
},
359
{0xc3, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc}
360
));
361
362
CHECK(check(
363
[](AssemblyBuilderX64& build)
364
{
365
build.ret();
366
build.align(8, AlignmentDataX64::Ud2);
367
},
368
{0xc3, 0x0f, 0x0b, 0x0f, 0x0b, 0x0f, 0x0b, 0xcc}
369
));
370
}
371
372
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "AlignmentOverflow")
373
{
374
// Test that alignment correctly resizes the code buffer
375
{
376
AssemblyBuilderX64 build(/* logText */ false);
377
378
build.ret();
379
build.align(8192, AlignmentDataX64::Nop);
380
build.finalize();
381
}
382
383
{
384
AssemblyBuilderX64 build(/* logText */ false);
385
386
build.ret();
387
build.align(8192, AlignmentDataX64::Int3);
388
build.finalize();
389
}
390
391
{
392
AssemblyBuilderX64 build(/* logText */ false);
393
394
for (int i = 0; i < 8192; i++)
395
build.int3();
396
build.finalize();
397
}
398
399
{
400
AssemblyBuilderX64 build(/* logText */ false);
401
402
build.ret();
403
build.align(8192, AlignmentDataX64::Ud2);
404
build.finalize();
405
}
406
}
407
408
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "ControlFlow")
409
{
410
// Jump back
411
CHECK(check(
412
[](AssemblyBuilderX64& build)
413
{
414
Label start = build.setLabel();
415
build.add(rsi, 1);
416
build.cmp(rsi, rdi);
417
build.jcc(ConditionX64::Equal, start);
418
},
419
{0x48, 0x83, 0xc6, 0x01, 0x48, 0x3b, 0xf7, 0x0f, 0x84, 0xf3, 0xff, 0xff, 0xff}
420
));
421
422
// Jump back, but the label is set before use
423
CHECK(check(
424
[](AssemblyBuilderX64& build)
425
{
426
Label start;
427
build.add(rsi, 1);
428
build.setLabel(start);
429
build.cmp(rsi, rdi);
430
build.jcc(ConditionX64::Equal, start);
431
},
432
{0x48, 0x83, 0xc6, 0x01, 0x48, 0x3b, 0xf7, 0x0f, 0x84, 0xf7, 0xff, 0xff, 0xff}
433
));
434
435
// Jump forward
436
CHECK(check(
437
[](AssemblyBuilderX64& build)
438
{
439
Label skip;
440
441
build.cmp(rsi, rdi);
442
build.jcc(ConditionX64::Greater, skip);
443
build.or_(rdi, 0x3e);
444
build.setLabel(skip);
445
},
446
{0x48, 0x3b, 0xf7, 0x0f, 0x8f, 0x04, 0x00, 0x00, 0x00, 0x48, 0x83, 0xcf, 0x3e}
447
));
448
449
// Regular jump
450
CHECK(check(
451
[](AssemblyBuilderX64& build)
452
{
453
Label skip;
454
455
build.jmp(skip);
456
build.and_(rdi, 0x3e);
457
build.setLabel(skip);
458
},
459
{0xe9, 0x04, 0x00, 0x00, 0x00, 0x48, 0x83, 0xe7, 0x3e}
460
));
461
}
462
463
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "LabelCall")
464
{
465
CHECK(check(
466
[](AssemblyBuilderX64& build)
467
{
468
Label fnB;
469
470
build.and_(rcx, 0x3e);
471
build.call(fnB);
472
build.ret();
473
474
build.setLabel(fnB);
475
build.lea(rax, addr[rcx + 0x1f]);
476
build.ret();
477
},
478
{0x48, 0x83, 0xe1, 0x3e, 0xe8, 0x01, 0x00, 0x00, 0x00, 0xc3, 0x48, 0x8d, 0x41, 0x1f, 0xc3}
479
));
480
}
481
482
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "AVXBinaryInstructionForms")
483
{
484
SINGLE_COMPARE(vaddpd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x29, 0x58, 0xc6);
485
SINGLE_COMPARE(vaddpd(xmm8, xmm10, xmmword[r9]), 0xc4, 0x41, 0x29, 0x58, 0x01);
486
SINGLE_COMPARE(vaddpd(ymm8, ymm10, ymm14), 0xc4, 0x41, 0x2d, 0x58, 0xc6);
487
SINGLE_COMPARE(vaddpd(ymm8, ymm10, ymmword[r9]), 0xc4, 0x41, 0x2d, 0x58, 0x01);
488
SINGLE_COMPARE(vaddps(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x28, 0x58, 0xc6);
489
SINGLE_COMPARE(vaddps(xmm8, xmm10, xmmword[r9]), 0xc4, 0x41, 0x28, 0x58, 0x01);
490
SINGLE_COMPARE(vaddsd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x2b, 0x58, 0xc6);
491
SINGLE_COMPARE(vaddsd(xmm8, xmm10, qword[r9]), 0xc4, 0x41, 0x2b, 0x58, 0x01);
492
SINGLE_COMPARE(vaddss(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x2a, 0x58, 0xc6);
493
SINGLE_COMPARE(vaddss(xmm8, xmm10, dword[r9]), 0xc4, 0x41, 0x2a, 0x58, 0x01);
494
495
SINGLE_COMPARE(vaddps(xmm1, xmm2, xmm3), 0xc4, 0xe1, 0x68, 0x58, 0xcb);
496
SINGLE_COMPARE(vaddps(xmm9, xmm12, xmmword[r9 + r14 * 2 + 0x1c]), 0xc4, 0x01, 0x18, 0x58, 0x4c, 0x71, 0x1c);
497
SINGLE_COMPARE(vaddps(ymm1, ymm2, ymm3), 0xc4, 0xe1, 0x6c, 0x58, 0xcb);
498
SINGLE_COMPARE(vaddps(ymm9, ymm12, ymmword[r9 + r14 * 2 + 0x1c]), 0xc4, 0x01, 0x1c, 0x58, 0x4c, 0x71, 0x1c);
499
500
// Coverage for other instructions that follow the same pattern
501
SINGLE_COMPARE(vsubsd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x2b, 0x5c, 0xc6);
502
SINGLE_COMPARE(vmulsd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x2b, 0x59, 0xc6);
503
SINGLE_COMPARE(vdivsd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x2b, 0x5e, 0xc6);
504
505
SINGLE_COMPARE(vsubps(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x28, 0x5c, 0xc6);
506
SINGLE_COMPARE(vmulps(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x28, 0x59, 0xc6);
507
SINGLE_COMPARE(vdivps(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x28, 0x5e, 0xc6);
508
509
SINGLE_COMPARE(vorpd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x29, 0x56, 0xc6);
510
SINGLE_COMPARE(vxorpd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x29, 0x57, 0xc6);
511
SINGLE_COMPARE(vorps(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x28, 0x56, 0xc6);
512
513
SINGLE_COMPARE(vandpd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x29, 0x54, 0xc6);
514
SINGLE_COMPARE(vandnpd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x29, 0x55, 0xc6);
515
516
SINGLE_COMPARE(vmaxsd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x2b, 0x5f, 0xc6);
517
SINGLE_COMPARE(vminsd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x2b, 0x5d, 0xc6);
518
519
SINGLE_COMPARE(vmaxss(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x2a, 0x5f, 0xc6);
520
SINGLE_COMPARE(vminss(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x2a, 0x5d, 0xc6);
521
522
SINGLE_COMPARE(vmaxps(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x28, 0x5f, 0xc6);
523
SINGLE_COMPARE(vminps(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x28, 0x5d, 0xc6);
524
525
SINGLE_COMPARE(vcmpeqsd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x2b, 0xc2, 0xc6, 0x00);
526
SINGLE_COMPARE(vcmpltsd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x2b, 0xc2, 0xc6, 0x01);
527
}
528
529
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "AVXUnaryMergeInstructionForms")
530
{
531
SINGLE_COMPARE(vsqrtpd(xmm8, xmm10), 0xc4, 0x41, 0x79, 0x51, 0xc2);
532
SINGLE_COMPARE(vsqrtpd(xmm8, xmmword[r9]), 0xc4, 0x41, 0x79, 0x51, 0x01);
533
SINGLE_COMPARE(vsqrtpd(ymm8, ymm10), 0xc4, 0x41, 0x7d, 0x51, 0xc2);
534
SINGLE_COMPARE(vsqrtpd(ymm8, ymmword[r9]), 0xc4, 0x41, 0x7d, 0x51, 0x01);
535
SINGLE_COMPARE(vsqrtps(xmm8, xmm10), 0xc4, 0x41, 0x78, 0x51, 0xc2);
536
SINGLE_COMPARE(vsqrtps(xmm8, xmmword[r9]), 0xc4, 0x41, 0x78, 0x51, 0x01);
537
SINGLE_COMPARE(vsqrtsd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x2b, 0x51, 0xc6);
538
SINGLE_COMPARE(vsqrtsd(xmm8, xmm10, qword[r9]), 0xc4, 0x41, 0x2b, 0x51, 0x01);
539
SINGLE_COMPARE(vsqrtss(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x2a, 0x51, 0xc6);
540
SINGLE_COMPARE(vsqrtss(xmm8, xmm10, dword[r9]), 0xc4, 0x41, 0x2a, 0x51, 0x01);
541
542
// Coverage for other instructions that follow the same pattern
543
SINGLE_COMPARE(vucomisd(xmm1, xmm4), 0xc4, 0xe1, 0x79, 0x2e, 0xcc);
544
}
545
546
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "AVXMoveInstructionForms")
547
{
548
SINGLE_COMPARE(vmovsd(qword[r9], xmm10), 0xc4, 0x41, 0x7b, 0x11, 0x11);
549
SINGLE_COMPARE(vmovsd(xmm8, qword[r9]), 0xc4, 0x41, 0x7b, 0x10, 0x01);
550
SINGLE_COMPARE(vmovsd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x2b, 0x10, 0xc6);
551
SINGLE_COMPARE(vmovss(dword[r9], xmm10), 0xc4, 0x41, 0x7a, 0x11, 0x11);
552
SINGLE_COMPARE(vmovss(xmm8, dword[r9]), 0xc4, 0x41, 0x7a, 0x10, 0x01);
553
SINGLE_COMPARE(vmovss(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x2a, 0x10, 0xc6);
554
SINGLE_COMPARE(vmovapd(xmm8, xmmword[r9]), 0xc4, 0x41, 0x79, 0x28, 0x01);
555
SINGLE_COMPARE(vmovapd(xmmword[r9], xmm10), 0xc4, 0x41, 0x79, 0x29, 0x11);
556
SINGLE_COMPARE(vmovapd(ymm8, ymmword[r9]), 0xc4, 0x41, 0x7d, 0x28, 0x01);
557
SINGLE_COMPARE(vmovaps(xmm8, xmmword[r9]), 0xc4, 0x41, 0x78, 0x28, 0x01);
558
SINGLE_COMPARE(vmovaps(xmmword[r9], xmm10), 0xc4, 0x41, 0x78, 0x29, 0x11);
559
SINGLE_COMPARE(vmovaps(ymm8, ymmword[r9]), 0xc4, 0x41, 0x7c, 0x28, 0x01);
560
SINGLE_COMPARE(vmovupd(xmm8, xmmword[r9]), 0xc4, 0x41, 0x79, 0x10, 0x01);
561
SINGLE_COMPARE(vmovupd(xmmword[r9], xmm10), 0xc4, 0x41, 0x79, 0x11, 0x11);
562
SINGLE_COMPARE(vmovupd(ymm8, ymmword[r9]), 0xc4, 0x41, 0x7d, 0x10, 0x01);
563
SINGLE_COMPARE(vmovups(xmm8, xmmword[r9]), 0xc4, 0x41, 0x78, 0x10, 0x01);
564
SINGLE_COMPARE(vmovups(xmmword[r9], xmm10), 0xc4, 0x41, 0x78, 0x11, 0x11);
565
SINGLE_COMPARE(vmovups(ymm8, ymmword[r9]), 0xc4, 0x41, 0x7c, 0x10, 0x01);
566
SINGLE_COMPARE(vmovq(xmm1, rbx), 0xc4, 0xe1, 0xf9, 0x6e, 0xcb);
567
SINGLE_COMPARE(vmovq(rbx, xmm1), 0xc4, 0xe1, 0xf9, 0x7e, 0xcb);
568
SINGLE_COMPARE(vmovq(xmm1, qword[r9]), 0xc4, 0xc1, 0xf9, 0x6e, 0x09);
569
SINGLE_COMPARE(vmovq(qword[r9], xmm1), 0xc4, 0xc1, 0xf9, 0x7e, 0x09);
570
}
571
572
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "AVXConversionInstructionForms")
573
{
574
SINGLE_COMPARE(vcvttsd2si(ecx, xmm0), 0xc4, 0xe1, 0x7b, 0x2c, 0xc8);
575
SINGLE_COMPARE(vcvttsd2si(r9d, xmmword[rcx + rdx]), 0xc4, 0x61, 0x7b, 0x2c, 0x0c, 0x11);
576
SINGLE_COMPARE(vcvttsd2si(rdx, xmm0), 0xc4, 0xe1, 0xfb, 0x2c, 0xd0);
577
SINGLE_COMPARE(vcvttsd2si(r13, xmmword[rcx + rdx]), 0xc4, 0x61, 0xfb, 0x2c, 0x2c, 0x11);
578
SINGLE_COMPARE(vcvtsi2sd(xmm5, xmm10, ecx), 0xc4, 0xe1, 0x2b, 0x2a, 0xe9);
579
SINGLE_COMPARE(vcvtsi2sd(xmm6, xmm11, dword[rcx + rdx]), 0xc4, 0xe1, 0x23, 0x2a, 0x34, 0x11);
580
SINGLE_COMPARE(vcvtsi2sd(xmm5, xmm10, r13), 0xc4, 0xc1, 0xab, 0x2a, 0xed);
581
SINGLE_COMPARE(vcvtsi2sd(xmm6, xmm11, qword[rcx + rdx]), 0xc4, 0xe1, 0xa3, 0x2a, 0x34, 0x11);
582
SINGLE_COMPARE(vcvtsd2ss(xmm5, xmm10, xmm11), 0xc4, 0xc1, 0x2b, 0x5a, 0xeb);
583
SINGLE_COMPARE(vcvtsd2ss(xmm6, xmm11, qword[rcx + rdx]), 0xc4, 0xe1, 0xa3, 0x5a, 0x34, 0x11);
584
SINGLE_COMPARE(vcvtss2sd(xmm3, xmm8, xmm12), 0xc4, 0xc1, 0x3a, 0x5a, 0xdc);
585
SINGLE_COMPARE(vcvtss2sd(xmm4, xmm9, dword[rcx + rsi]), 0xc4, 0xe1, 0x32, 0x5a, 0x24, 0x31);
586
}
587
588
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "AVXTernaryInstructionForms")
589
{
590
SINGLE_COMPARE(vroundsd(xmm7, xmm12, xmm3, RoundingModeX64::RoundToNegativeInfinity), 0xc4, 0xe3, 0x19, 0x0b, 0xfb, 0x09);
591
SINGLE_COMPARE(
592
vroundsd(xmm8, xmm13, xmmword[r13 + rdx], RoundingModeX64::RoundToPositiveInfinity), 0xc4, 0x43, 0x11, 0x0b, 0x44, 0x15, 0x00, 0x0a
593
);
594
SINGLE_COMPARE(vroundsd(xmm9, xmm14, xmmword[rcx + r10], RoundingModeX64::RoundToZero), 0xc4, 0x23, 0x09, 0x0b, 0x0c, 0x11, 0x0b);
595
596
SINGLE_COMPARE(vroundps(xmm1, xmm3, RoundingModeX64::RoundToNegativeInfinity), 0xc4, 0xe3, 0x79, 0x08, 0xcb, 0x09);
597
SINGLE_COMPARE(vroundps(xmm12, xmm14, RoundingModeX64::RoundToNegativeInfinity), 0xc4, 0x43, 0x79, 0x08, 0xe6, 0x09);
598
SINGLE_COMPARE(vroundps(xmm12, xmmword[rax + r13], RoundingModeX64::RoundToNegativeInfinity), 0xc4, 0x23, 0x79, 0x08, 0x24, 0x28, 0x09);
599
600
SINGLE_COMPARE(vblendvpd(xmm7, xmm12, xmmword[rcx + r10], xmm5), 0xc4, 0xa3, 0x19, 0x4b, 0x3c, 0x11, 0x50);
601
602
SINGLE_COMPARE(vpshufps(xmm7, xmm12, xmmword[rcx + r10], 0b11010100), 0xc4, 0xa1, 0x18, 0xc6, 0x3c, 0x11, 0xd4);
603
SINGLE_COMPARE(vpinsrd(xmm7, xmm12, xmmword[rcx + r10], 2), 0xc4, 0xa3, 0x19, 0x22, 0x3c, 0x11, 0x02);
604
605
SINGLE_COMPARE(vpextrd(ecx, xmm5, 2), 0xc4, 0xe3, 0x79, 0x16, 0xe9, 0x02);
606
SINGLE_COMPARE(vpextrd(r10d, xmm9, 1), 0xc4, 0x43, 0x79, 0x16, 0xca, 0x01);
607
608
SINGLE_COMPARE(vdpps(xmm7, xmm12, xmmword[rcx + r10], 2), 0xc4, 0xa3, 0x19, 0x40, 0x3c, 0x11, 0x02);
609
}
610
611
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "MiscInstructions")
612
{
613
SINGLE_COMPARE(int3(), 0xcc);
614
SINGLE_COMPARE(ud2(), 0x0f, 0x0b);
615
SINGLE_COMPARE(bsr(eax, edx), 0x0f, 0xbd, 0xc2);
616
SINGLE_COMPARE(bsf(eax, edx), 0x0f, 0xbc, 0xc2);
617
SINGLE_COMPARE(bswap(eax), 0x0f, 0xc8);
618
SINGLE_COMPARE(bswap(r12d), 0x41, 0x0f, 0xcc);
619
SINGLE_COMPARE(bswap(rax), 0x48, 0x0f, 0xc8);
620
SINGLE_COMPARE(bswap(r12), 0x49, 0x0f, 0xcc);
621
}
622
623
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "LabelLea")
624
{
625
CHECK(check(
626
[](AssemblyBuilderX64& build)
627
{
628
Label fn;
629
build.lea(rax, fn);
630
build.ret();
631
632
build.setLabel(fn);
633
build.ret();
634
},
635
{0x48, 0x8d, 0x05, 0x01, 0x00, 0x00, 0x00, 0xc3, 0xc3}
636
));
637
}
638
639
TEST_CASE("LogTest")
640
{
641
AssemblyBuilderX64 build(/* logText= */ true);
642
643
build.push(r12);
644
build.align(8);
645
build.align(8, AlignmentDataX64::Int3);
646
build.align(8, AlignmentDataX64::Ud2);
647
648
build.add(rax, rdi);
649
build.add(rcx, 8);
650
build.sub(dword[rax], 0x1fdc);
651
build.and_(dword[rcx], 0x37);
652
build.mov(rdi, qword[rax + rsi * 2]);
653
build.vaddss(xmm0, xmm0, dword[rax + r14 * 2 + 0x1c]);
654
655
Label start = build.setLabel();
656
build.cmp(rsi, rdi);
657
build.jcc(ConditionX64::Equal, start);
658
build.lea(rcx, start);
659
build.lea(rcx, addr[rdx]);
660
661
build.jmp(qword[rdx]);
662
build.vaddps(ymm9, ymm12, ymmword[rbp + 0xc]);
663
build.vaddpd(ymm2, ymm7, build.f64(2.5));
664
build.neg(qword[rbp + r12 * 2]);
665
build.mov64(r10, 0x1234567812345678ll);
666
build.vmovapd(xmmword[rax], xmm11);
667
build.movzx(eax, byte[rcx]);
668
build.movsx(rsi, word[r12]);
669
build.imul(rcx, rdx);
670
build.imul(rcx, rdx, 8);
671
build.vroundsd(xmm1, xmm2, xmm3, RoundingModeX64::RoundToNearestEven);
672
build.vroundps(xmm1, xmm12, RoundingModeX64::RoundToNegativeInfinity);
673
build.add(rdx, qword[rcx - 12]);
674
build.pop(r12);
675
build.cmov(ConditionX64::AboveEqual, rax, rbx);
676
build.vpextrd(ecx, xmm5, 2);
677
build.ret();
678
build.int3();
679
680
build.nop();
681
build.nop(2);
682
build.nop(3);
683
build.nop(4);
684
build.nop(5);
685
build.nop(6);
686
build.nop(7);
687
build.nop(8);
688
build.nop(9);
689
690
build.finalize();
691
692
std::string expected = R"(
693
push r12
694
; align 8
695
nop word ptr[rax+rax] ; 6-byte nop
696
; align 8 using int3
697
; align 8 using ud2
698
add rax,rdi
699
add rcx,8
700
sub dword ptr [rax],1FDCh
701
and dword ptr [rcx],37h
702
mov rdi,qword ptr [rax+rsi*2]
703
vaddss xmm0,xmm0,dword ptr [rax+r14*2+01Ch]
704
.L1:
705
cmp rsi,rdi
706
je .L1
707
lea rcx,.L1
708
lea rcx,[rdx]
709
jmp qword ptr [rdx]
710
vaddps ymm9,ymm12,ymmword ptr [rbp+0Ch]
711
vaddpd ymm2,ymm7,qword ptr [.start-8]
712
neg qword ptr [rbp+r12*2]
713
mov r10,1234567812345678h
714
vmovapd xmmword ptr [rax],xmm11
715
movzx eax,byte ptr [rcx]
716
movsx rsi,word ptr [r12]
717
imul rcx,rdx
718
imul rcx,rdx,8
719
vroundsd xmm1,xmm2,xmm3,8
720
vroundps xmm1,xmm12,9
721
add rdx,qword ptr [rcx-0Ch]
722
pop r12
723
cmovae rax,rbx
724
vpextrd ecx,xmm5,2
725
ret
726
int3
727
nop
728
xchg ax, ax ; 2-byte nop
729
nop dword ptr[rax] ; 3-byte nop
730
nop dword ptr[rax] ; 4-byte nop
731
nop dword ptr[rax+rax] ; 5-byte nop
732
nop word ptr[rax+rax] ; 6-byte nop
733
nop dword ptr[rax] ; 7-byte nop
734
nop dword ptr[rax+rax] ; 8-byte nop
735
nop word ptr[rax+rax] ; 9-byte nop
736
)";
737
738
CHECK("\n" + build.text == expected);
739
}
740
741
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "Constants")
742
{
743
// clang-format off
744
CHECK(check(
745
[](AssemblyBuilderX64& build) {
746
build.xor_(rax, rax);
747
build.add(rax, build.i64(0x1234567887654321));
748
build.vmovss(xmm2, build.f32(1.0f));
749
build.vmovsd(xmm3, build.f64(1.0));
750
build.vmovaps(xmm4, build.f32x4(1.0f, 2.0f, 4.0f, 8.0f));
751
char arr[16] = "hello world!123";
752
build.vmovupd(xmm5, build.bytes(arr, 16, 8));
753
build.vmovapd(xmm5, build.f64x2(5.0, 6.0));
754
build.ret();
755
},
756
{
757
0x48, 0x33, 0xc0,
758
0x48, 0x03, 0x05, 0xee, 0xff, 0xff, 0xff,
759
0xc4, 0xe1, 0x7a, 0x10, 0x15, 0xe1, 0xff, 0xff, 0xff,
760
0xc4, 0xe1, 0x7b, 0x10, 0x1d, 0xcc, 0xff, 0xff, 0xff,
761
0xc4, 0xe1, 0x78, 0x28, 0x25, 0xab, 0xff, 0xff, 0xff,
762
0xc4, 0xe1, 0x79, 0x10, 0x2d, 0x92, 0xff, 0xff, 0xff,
763
0xc4, 0xe1, 0x79, 0x28, 0x2d, 0x79, 0xff, 0xff, 0xff,
764
0xc3
765
},
766
{
767
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x40,
768
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x40,
769
'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', '1', '2', '3', 0x0,
770
0x00, 0x00, 0x80, 0x3f,
771
0x00, 0x00, 0x00, 0x40,
772
0x00, 0x00, 0x80, 0x40,
773
0x00, 0x00, 0x00, 0x41,
774
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // padding to align f32x4
775
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f,
776
0x00, 0x00, 0x00, 0x00, // padding to align f64
777
0x00, 0x00, 0x80, 0x3f,
778
0x21, 0x43, 0x65, 0x87, 0x78, 0x56, 0x34, 0x12,
779
}));
780
// clang-format on
781
}
782
783
TEST_CASE("ConstantStorage")
784
{
785
AssemblyBuilderX64 build(/* logText= */ false);
786
787
for (int i = 0; i <= 3000; i++)
788
build.vaddss(xmm0, xmm0, build.i32(i));
789
790
build.finalize();
791
792
CHECK(build.data.size() == 12004);
793
794
for (int i = 0; i <= 3000; i++)
795
{
796
CHECK(build.data[i * 4 + 0] == ((3000 - i) & 0xff));
797
CHECK(build.data[i * 4 + 1] == ((3000 - i) >> 8));
798
CHECK(build.data[i * 4 + 2] == 0x00);
799
CHECK(build.data[i * 4 + 3] == 0x00);
800
}
801
}
802
803
TEST_CASE("ConstantStorageDedup")
804
{
805
AssemblyBuilderX64 build(/* logText= */ false);
806
807
for (int i = 0; i <= 3000; i++)
808
build.vaddss(xmm0, xmm0, build.f32(1.0f));
809
810
build.finalize();
811
812
CHECK(build.data.size() == 4);
813
814
CHECK(build.data[0] == 0x00);
815
CHECK(build.data[1] == 0x00);
816
CHECK(build.data[2] == 0x80);
817
CHECK(build.data[3] == 0x3f);
818
}
819
820
TEST_CASE("ConstantCaching")
821
{
822
AssemblyBuilderX64 build(/* logText= */ false);
823
824
OperandX64 two = build.f64(2);
825
826
// Force data relocation
827
for (int i = 0; i < 4096; i++)
828
build.f64(i);
829
830
CHECK(build.f64(2).imm == two.imm);
831
832
build.finalize();
833
}
834
835
TEST_SUITE_END();
836
837