Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/CodeGen/include/Luau/AssemblyBuilderX64.h
2727 views
1
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
2
#pragma once
3
4
#include "Luau/Common.h"
5
#include "Luau/DenseHash.h"
6
#include "Luau/Label.h"
7
#include "Luau/ConditionX64.h"
8
#include "Luau/OperandX64.h"
9
#include "Luau/RegisterX64.h"
10
11
#include <string>
12
#include <vector>
13
14
namespace Luau
15
{
16
namespace CodeGen
17
{
18
namespace X64
19
{
20
21
enum FeaturesX64
22
{
23
Feature_FMA3 = 1 << 0,
24
Feature_AVX = 1 << 1
25
};
26
27
enum class RoundingModeX64
28
{
29
RoundToNearestEven = 0b00,
30
RoundToNegativeInfinity = 0b01,
31
RoundToPositiveInfinity = 0b10,
32
RoundToZero = 0b11,
33
};
34
35
enum class AlignmentDataX64
36
{
37
Nop,
38
Int3,
39
Ud2, // int3 will be used as a fall-back if it doesn't fit
40
};
41
42
enum class ABIX64
43
{
44
Windows,
45
SystemV,
46
};
47
48
class AssemblyBuilderX64
49
{
50
public:
51
explicit AssemblyBuilderX64(bool logText, ABIX64 abi, unsigned int features = 0);
52
explicit AssemblyBuilderX64(bool logText, unsigned int features = 0);
53
~AssemblyBuilderX64();
54
55
// Base two operand instructions with 9 opcode selection
56
void add(OperandX64 lhs, OperandX64 rhs);
57
void sub(OperandX64 lhs, OperandX64 rhs);
58
void cmp(OperandX64 lhs, OperandX64 rhs);
59
void and_(OperandX64 lhs, OperandX64 rhs);
60
void or_(OperandX64 lhs, OperandX64 rhs);
61
void xor_(OperandX64 lhs, OperandX64 rhs);
62
63
// Binary shift instructions with special rhs handling
64
void sal(OperandX64 lhs, OperandX64 rhs);
65
void sar(OperandX64 lhs, OperandX64 rhs);
66
void shl(OperandX64 lhs, OperandX64 rhs);
67
void shr(OperandX64 lhs, OperandX64 rhs);
68
void rol(OperandX64 lhs, OperandX64 rhs);
69
void ror(OperandX64 lhs, OperandX64 rhs);
70
71
// Two operand mov instruction has additional specialized encodings
72
void mov(OperandX64 lhs, OperandX64 rhs);
73
void mov64(RegisterX64 lhs, int64_t imm);
74
void movsx(RegisterX64 lhs, OperandX64 rhs);
75
void movzx(RegisterX64 lhs, OperandX64 rhs);
76
77
// Base one operand instruction with 2 opcode selection
78
void div(OperandX64 op);
79
void idiv(OperandX64 op);
80
void mul(OperandX64 op);
81
void imul(OperandX64 op);
82
void neg(OperandX64 op);
83
void not_(OperandX64 op);
84
void dec(OperandX64 op);
85
void inc(OperandX64 op);
86
87
// Additional forms of imul
88
void imul(OperandX64 lhs, OperandX64 rhs);
89
void imul(OperandX64 dst, OperandX64 lhs, int32_t rhs);
90
91
void test(OperandX64 lhs, OperandX64 rhs);
92
void lea(OperandX64 lhs, OperandX64 rhs);
93
void setcc(ConditionX64 cond, OperandX64 op);
94
void cmov(ConditionX64 cond, RegisterX64 lhs, OperandX64 rhs);
95
96
void push(OperandX64 op);
97
void pop(OperandX64 op);
98
void ret();
99
100
// Control flow
101
void jcc(ConditionX64 cond, Label& label);
102
void jmp(Label& label);
103
void jmp(OperandX64 op);
104
105
void call(Label& label);
106
void call(OperandX64 op);
107
108
void lea(RegisterX64 lhs, Label& label);
109
110
void int3();
111
void ud2();
112
113
void bsr(RegisterX64 dst, OperandX64 src);
114
void bsf(RegisterX64 dst, OperandX64 src);
115
void bswap(RegisterX64 dst);
116
117
// Code alignment
118
void nop(uint32_t length = 1);
119
void align(uint32_t alignment, AlignmentDataX64 data = AlignmentDataX64::Nop);
120
121
// AVX
122
void vaddpd(OperandX64 dst, OperandX64 src1, OperandX64 src2);
123
void vaddps(OperandX64 dst, OperandX64 src1, OperandX64 src2);
124
void vaddsd(OperandX64 dst, OperandX64 src1, OperandX64 src2);
125
void vaddss(OperandX64 dst, OperandX64 src1, OperandX64 src2);
126
127
void vsubsd(OperandX64 dst, OperandX64 src1, OperandX64 src2);
128
void vsubss(OperandX64 dst, OperandX64 src1, OperandX64 src2);
129
void vsubps(OperandX64 dst, OperandX64 src1, OperandX64 src2);
130
void vmulsd(OperandX64 dst, OperandX64 src1, OperandX64 src2);
131
void vmulss(OperandX64 dst, OperandX64 src1, OperandX64 src2);
132
void vmulps(OperandX64 dst, OperandX64 src1, OperandX64 src2);
133
void vdivsd(OperandX64 dst, OperandX64 src1, OperandX64 src2);
134
void vdivss(OperandX64 dst, OperandX64 src1, OperandX64 src2);
135
void vdivps(OperandX64 dst, OperandX64 src1, OperandX64 src2);
136
137
void vandps(OperandX64 dst, OperandX64 src1, OperandX64 src2);
138
void vandpd(OperandX64 dst, OperandX64 src1, OperandX64 src2);
139
void vandnpd(OperandX64 dst, OperandX64 src1, OperandX64 src2);
140
141
void vxorps(OperandX64 dst, OperandX64 src1, OperandX64 src2);
142
void vxorpd(OperandX64 dst, OperandX64 src1, OperandX64 src2);
143
void vorps(OperandX64 dst, OperandX64 src1, OperandX64 src2);
144
void vorpd(OperandX64 dst, OperandX64 src1, OperandX64 src2);
145
146
void vucomisd(OperandX64 src1, OperandX64 src2);
147
void vucomiss(OperandX64 src1, OperandX64 src2);
148
149
void vcvttsd2si(OperandX64 dst, OperandX64 src);
150
void vcvtsi2sd(OperandX64 dst, OperandX64 src1, OperandX64 src2);
151
void vcvtsi2ss(OperandX64 dst, OperandX64 src1, OperandX64 src2);
152
void vcvtsd2ss(OperandX64 dst, OperandX64 src1, OperandX64 src2);
153
void vcvtss2sd(OperandX64 dst, OperandX64 src1, OperandX64 src2);
154
155
void vroundsd(OperandX64 dst, OperandX64 src1, OperandX64 src2, RoundingModeX64 roundingMode); // inexact
156
void vroundss(OperandX64 dst, OperandX64 src1, OperandX64 src2, RoundingModeX64 roundingMode); // inexact
157
void vroundps(OperandX64 dst, OperandX64 src, RoundingModeX64 roundingMode); // inexact
158
159
void vsqrtpd(OperandX64 dst, OperandX64 src);
160
void vsqrtps(OperandX64 dst, OperandX64 src);
161
void vsqrtsd(OperandX64 dst, OperandX64 src1, OperandX64 src2);
162
void vsqrtss(OperandX64 dst, OperandX64 src1, OperandX64 src2);
163
164
void vmovsd(OperandX64 dst, OperandX64 src);
165
void vmovsd(OperandX64 dst, OperandX64 src1, OperandX64 src2);
166
void vmovss(OperandX64 dst, OperandX64 src);
167
void vmovss(OperandX64 dst, OperandX64 src1, OperandX64 src2);
168
void vmovapd(OperandX64 dst, OperandX64 src);
169
void vmovaps(OperandX64 dst, OperandX64 src);
170
void vmovupd(OperandX64 dst, OperandX64 src);
171
void vmovups(OperandX64 dst, OperandX64 src);
172
void vmovq(OperandX64 lhs, OperandX64 rhs);
173
174
void vmaxps(OperandX64 dst, OperandX64 src1, OperandX64 src2);
175
void vmaxsd(OperandX64 dst, OperandX64 src1, OperandX64 src2);
176
void vmaxss(OperandX64 dst, OperandX64 src1, OperandX64 src2);
177
void vminps(OperandX64 dst, OperandX64 src1, OperandX64 src2);
178
void vminsd(OperandX64 dst, OperandX64 src1, OperandX64 src2);
179
void vminss(OperandX64 dst, OperandX64 src1, OperandX64 src2);
180
181
void vcmpeqsd(OperandX64 dst, OperandX64 src1, OperandX64 src2);
182
void vcmpltsd(OperandX64 dst, OperandX64 src1, OperandX64 src2);
183
void vcmpltss(OperandX64 dst, OperandX64 src1, OperandX64 src2);
184
void vcmpeqps(OperandX64 dst, OperandX64 src1, OperandX64 src2);
185
186
void vblendvps(RegisterX64 dst, RegisterX64 src1, OperandX64 src2, RegisterX64 mask);
187
void vblendvpd(RegisterX64 dst, RegisterX64 src1, OperandX64 src2, RegisterX64 mask);
188
189
void vpshufps(RegisterX64 dst, RegisterX64 src1, OperandX64 src2, uint8_t shuffle);
190
void vpinsrd(RegisterX64 dst, RegisterX64 src1, OperandX64 src2, uint8_t offset);
191
void vpextrd(RegisterX64 dst, RegisterX64 src, uint8_t offset);
192
193
void vdpps(OperandX64 dst, OperandX64 src1, OperandX64 src2, uint8_t mask);
194
void vfmadd213ps(OperandX64 dst, OperandX64 src1, OperandX64 src2);
195
void vfmadd213pd(OperandX64 dst, OperandX64 src1, OperandX64 src2);
196
197
// Run final checks
198
bool finalize();
199
200
// Places a label at current location and returns it
201
Label setLabel();
202
203
// Assigns label position to the current location
204
void setLabel(Label& label);
205
206
// Extracts code offset (in bytes) from label
207
uint32_t getLabelOffset(const Label& label)
208
{
209
CODEGEN_ASSERT(label.location != ~0u);
210
return label.location;
211
}
212
213
// Constant allocation (uses rip-relative addressing)
214
OperandX64 i32(int32_t value);
215
OperandX64 i64(int64_t value);
216
OperandX64 f32(float value);
217
OperandX64 f64(double value);
218
OperandX64 u32x4(uint32_t x, uint32_t y, uint32_t z, uint32_t w);
219
OperandX64 f32x4(float x, float y, float z, float w);
220
OperandX64 f64x2(double x, double y);
221
OperandX64 bytes(const void* ptr, size_t size, size_t align = 8);
222
223
void logAppend(const char* fmt, ...) LUAU_PRINTF_ATTR(2, 3);
224
225
// Code size is measured in 'code' array units - uint8_t on x64 and uint32_t on arm64
226
uint32_t getCodeSize() const;
227
228
unsigned getInstructionCount() const;
229
230
// Resulting data and code that need to be copied over one after the other
231
// The *end* of 'data' has to be aligned to 16 bytes, this will also align 'code'
232
std::vector<uint8_t> data;
233
std::vector<uint8_t> code;
234
235
std::string text;
236
237
const bool logText = false;
238
239
const ABIX64 abi;
240
241
const unsigned int features = 0;
242
243
private:
244
// Instruction archetypes
245
void placeBinary(
246
const char* name,
247
OperandX64 lhs,
248
OperandX64 rhs,
249
uint8_t codeimm8,
250
uint8_t codeimm,
251
uint8_t codeimmImm8,
252
uint8_t code8rev,
253
uint8_t coderev,
254
uint8_t code8,
255
uint8_t code,
256
uint8_t opreg
257
);
258
void placeBinaryRegMemAndImm(OperandX64 lhs, OperandX64 rhs, uint8_t code8, uint8_t code, uint8_t codeImm8, uint8_t opreg);
259
void placeBinaryRegAndRegMem(OperandX64 lhs, OperandX64 rhs, uint8_t code8, uint8_t code);
260
void placeBinaryRegMemAndReg(OperandX64 lhs, OperandX64 rhs, uint8_t code8, uint8_t code);
261
262
void placeUnaryModRegMem(const char* name, OperandX64 op, uint8_t code8, uint8_t code, uint8_t opreg);
263
264
void placeShift(const char* name, OperandX64 lhs, OperandX64 rhs, uint8_t opreg);
265
266
void placeJcc(const char* name, Label& label, uint8_t cc);
267
268
void placeAvx(const char* name, OperandX64 dst, OperandX64 src, uint8_t code, bool setW, uint8_t mode, uint8_t prefix);
269
void placeAvx(const char* name, OperandX64 dst, OperandX64 src, uint8_t code, uint8_t coderev, bool setW, uint8_t mode, uint8_t prefix);
270
void placeAvx(const char* name, OperandX64 dst, OperandX64 src1, OperandX64 src2, uint8_t code, bool setW, uint8_t mode, uint8_t prefix);
271
void placeAvx(
272
const char* name,
273
OperandX64 dst,
274
OperandX64 src1,
275
OperandX64 src2,
276
uint8_t imm8,
277
uint8_t code,
278
bool setW,
279
uint8_t mode,
280
uint8_t prefix
281
);
282
283
// Instruction components
284
void placeRegAndModRegMem(OperandX64 lhs, OperandX64 rhs, int32_t extraCodeBytes = 0);
285
void placeModRegMem(OperandX64 rhs, uint8_t regop, int32_t extraCodeBytes = 0);
286
void placeRex(RegisterX64 op);
287
void placeRex(OperandX64 op);
288
void placeRexNoW(OperandX64 op);
289
void placeRex(RegisterX64 lhs, OperandX64 rhs);
290
void placeVex(OperandX64 dst, OperandX64 src1, OperandX64 src2, bool setW, uint8_t mode, uint8_t prefix);
291
void placeImm8Or32(int32_t imm);
292
void placeImm8(int32_t imm);
293
void placeImm16(int16_t imm);
294
void placeImm32(int32_t imm);
295
void placeImm64(int64_t imm);
296
void placeLabel(Label& label);
297
void place(uint8_t byte);
298
299
void commit();
300
LUAU_NOINLINE void extend();
301
302
// Data
303
size_t allocateData(size_t size, size_t align);
304
305
// Logging of assembly in text form (Intel asm with VS disassembly formatting)
306
LUAU_NOINLINE void log(const char* opcode);
307
LUAU_NOINLINE void log(const char* opcode, OperandX64 op);
308
LUAU_NOINLINE void log(const char* opcode, OperandX64 op1, OperandX64 op2);
309
LUAU_NOINLINE void log(const char* opcode, OperandX64 op1, OperandX64 op2, OperandX64 op3);
310
LUAU_NOINLINE void log(const char* opcode, OperandX64 op1, OperandX64 op2, OperandX64 op3, OperandX64 op4);
311
LUAU_NOINLINE void log(Label label);
312
LUAU_NOINLINE void log(const char* opcode, Label label);
313
LUAU_NOINLINE void log(const char* opcode, RegisterX64 reg, Label label);
314
void log(OperandX64 op);
315
316
const char* getSizeName(SizeX64 size) const;
317
const char* getRegisterName(RegisterX64 reg) const;
318
319
uint32_t nextLabel = 1;
320
std::vector<Label> pendingLabels;
321
std::vector<uint32_t> labelLocations;
322
323
DenseHashMap<uint32_t, int32_t> constCache32;
324
DenseHashMap<uint64_t, int32_t> constCache64;
325
326
bool finalized = false;
327
328
size_t dataPos = 0;
329
330
uint8_t* codePos = nullptr;
331
uint8_t* codeEnd = nullptr;
332
333
unsigned instructionCount = 0;
334
};
335
336
} // namespace X64
337
} // namespace CodeGen
338
} // namespace Luau
339
340