Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/CodeGen/include/Luau/IrVisitUseDef.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/IrData.h"
6
7
namespace Luau
8
{
9
namespace CodeGen
10
{
11
12
template<typename T>
13
static void visitVmRegDefsUses(T& visitor, IrFunction& function, IrInst& inst)
14
{
15
// For correct analysis, all instruction uses must be handled before handling the definitions
16
switch (inst.cmd)
17
{
18
case IrCmd::LOAD_TAG:
19
case IrCmd::LOAD_POINTER:
20
case IrCmd::LOAD_DOUBLE:
21
case IrCmd::LOAD_INT:
22
case IrCmd::LOAD_FLOAT:
23
case IrCmd::LOAD_TVALUE:
24
visitor.maybeUse(OP_A(inst)); // Argument can also be a VmConst
25
break;
26
case IrCmd::STORE_TAG:
27
case IrCmd::STORE_EXTRA:
28
case IrCmd::STORE_POINTER:
29
case IrCmd::STORE_DOUBLE:
30
case IrCmd::STORE_INT:
31
case IrCmd::STORE_VECTOR:
32
case IrCmd::STORE_TVALUE:
33
case IrCmd::STORE_SPLIT_TVALUE:
34
visitor.maybeDef(OP_A(inst)); // Argument can also be a pointer value
35
break;
36
case IrCmd::CMP_ANY:
37
visitor.use(OP_A(inst));
38
visitor.use(OP_B(inst));
39
break;
40
case IrCmd::CMP_TAG:
41
visitor.maybeUse(OP_A(inst));
42
break;
43
case IrCmd::JUMP_IF_TRUTHY:
44
case IrCmd::JUMP_IF_FALSY:
45
visitor.use(OP_A(inst));
46
break;
47
case IrCmd::JUMP_EQ_TAG:
48
visitor.maybeUse(OP_A(inst));
49
break;
50
// A <- B, C
51
case IrCmd::DO_ARITH:
52
visitor.maybeUse(OP_B(inst)); // Argument can also be a VmConst
53
visitor.maybeUse(OP_C(inst)); // Argument can also be a VmConst
54
55
visitor.def(OP_A(inst));
56
break;
57
case IrCmd::GET_TABLE:
58
visitor.use(OP_B(inst));
59
visitor.maybeUse(OP_C(inst)); // Argument can also be a VmConst
60
61
visitor.def(OP_A(inst));
62
break;
63
case IrCmd::SET_TABLE:
64
visitor.use(OP_A(inst));
65
visitor.use(OP_B(inst));
66
visitor.maybeUse(OP_C(inst)); // Argument can also be a VmConst
67
break;
68
// A <- B
69
case IrCmd::DO_LEN:
70
visitor.use(OP_B(inst));
71
72
visitor.def(OP_A(inst));
73
break;
74
case IrCmd::GET_CACHED_IMPORT:
75
visitor.def(OP_A(inst));
76
break;
77
case IrCmd::CONCAT:
78
visitor.useRange(vmRegOp(OP_A(inst)), function.uintOp(OP_B(inst)));
79
80
visitor.defRange(vmRegOp(OP_A(inst)), function.uintOp(OP_B(inst)));
81
break;
82
case IrCmd::GET_UPVALUE:
83
break;
84
case IrCmd::SET_UPVALUE:
85
break;
86
case IrCmd::INTERRUPT:
87
break;
88
case IrCmd::BARRIER_OBJ:
89
case IrCmd::BARRIER_TABLE_FORWARD:
90
visitor.maybeUse(OP_B(inst));
91
break;
92
case IrCmd::CLOSE_UPVALS:
93
// Closing an upvalue should be counted as a register use (it copies the fresh register value)
94
// But we lack the required information about the specific set of registers that are affected
95
// Because we don't plan to optimize captured registers atm, we skip full dataflow analysis for them right now
96
break;
97
case IrCmd::CAPTURE:
98
visitor.maybeUse(OP_A(inst));
99
100
if (function.uintOp(OP_B(inst)) == 1)
101
visitor.capture(vmRegOp(OP_A(inst)));
102
break;
103
case IrCmd::SETLIST:
104
visitor.use(OP_B(inst));
105
visitor.useRange(vmRegOp(OP_C(inst)), function.intOp(OP_D(inst)));
106
break;
107
case IrCmd::CALL:
108
visitor.use(OP_A(inst));
109
visitor.useRange(vmRegOp(OP_A(inst)) + 1, function.intOp(OP_B(inst)));
110
111
visitor.defRange(vmRegOp(OP_A(inst)), function.intOp(OP_C(inst)));
112
break;
113
case IrCmd::RETURN:
114
visitor.useRange(vmRegOp(OP_A(inst)), function.intOp(OP_B(inst)));
115
break;
116
117
case IrCmd::FASTCALL:
118
visitor.use(OP_C(inst));
119
120
if (int nresults = function.intOp(OP_D(inst)); nresults != -1)
121
visitor.defRange(vmRegOp(OP_B(inst)), nresults);
122
break;
123
case IrCmd::INVOKE_FASTCALL:
124
if (int count = function.intOp(OP_F(inst)); count != -1)
125
{
126
// Only LOP_FASTCALL3 lowering is allowed to have third optional argument
127
if (count >= 3 && OP_E(inst).kind == IrOpKind::Undef)
128
{
129
CODEGEN_ASSERT(OP_D(inst).kind == IrOpKind::VmReg && vmRegOp(OP_D(inst)) == vmRegOp(OP_C(inst)) + 1);
130
131
visitor.useRange(vmRegOp(OP_C(inst)), count);
132
}
133
else
134
{
135
if (count >= 1)
136
visitor.use(OP_C(inst));
137
138
if (count >= 2)
139
visitor.maybeUse(OP_D(inst)); // Argument can also be a VmConst
140
141
if (count >= 3)
142
visitor.maybeUse(OP_E(inst)); // Argument can also be a VmConst
143
}
144
}
145
else
146
{
147
visitor.useVarargs(vmRegOp(OP_C(inst)));
148
}
149
150
// Multiple return sequences (count == -1) are defined by ADJUST_STACK_TO_REG
151
if (int count = function.intOp(OP_G(inst)); count != -1)
152
visitor.defRange(vmRegOp(OP_B(inst)), count);
153
break;
154
case IrCmd::FORGLOOP:
155
// First register is not used by instruction, we check that it's still 'nil' with CHECK_TAG
156
visitor.use(OP_A(inst), 1);
157
visitor.use(OP_A(inst), 2);
158
159
visitor.def(OP_A(inst), 2);
160
visitor.defRange(vmRegOp(OP_A(inst)) + 3, function.intOp(OP_B(inst)));
161
break;
162
case IrCmd::FORGLOOP_FALLBACK:
163
visitor.useRange(vmRegOp(OP_A(inst)), 3);
164
165
visitor.def(OP_A(inst), 2);
166
visitor.defRange(vmRegOp(OP_A(inst)) + 3, uint8_t(function.intOp(OP_B(inst)))); // ignore most significant bit
167
break;
168
case IrCmd::FORGPREP_XNEXT_FALLBACK:
169
visitor.use(OP_B(inst));
170
break;
171
case IrCmd::FALLBACK_GETGLOBAL:
172
visitor.def(OP_B(inst));
173
break;
174
case IrCmd::FALLBACK_SETGLOBAL:
175
visitor.use(OP_B(inst));
176
break;
177
case IrCmd::FALLBACK_GETTABLEKS:
178
visitor.use(OP_C(inst));
179
180
visitor.def(OP_B(inst));
181
break;
182
case IrCmd::FALLBACK_SETTABLEKS:
183
visitor.use(OP_B(inst));
184
visitor.use(OP_C(inst));
185
break;
186
case IrCmd::FALLBACK_NAMECALL:
187
visitor.use(OP_C(inst));
188
189
visitor.defRange(vmRegOp(OP_B(inst)), 2);
190
break;
191
case IrCmd::FALLBACK_PREPVARARGS:
192
// No effect on explicitly referenced registers
193
break;
194
case IrCmd::FALLBACK_GETVARARGS:
195
visitor.defRange(vmRegOp(OP_B(inst)), function.intOp(OP_C(inst)));
196
break;
197
case IrCmd::FALLBACK_DUPCLOSURE:
198
visitor.def(OP_B(inst));
199
break;
200
case IrCmd::FALLBACK_FORGPREP:
201
// This instruction doesn't always redefine Rn, Rn+1, Rn+2, so we have to mark it as implicit use
202
visitor.useRange(vmRegOp(OP_B(inst)), 3);
203
204
visitor.defRange(vmRegOp(OP_B(inst)), 3);
205
break;
206
case IrCmd::ADJUST_STACK_TO_REG:
207
visitor.defRange(vmRegOp(OP_A(inst)), -1);
208
break;
209
case IrCmd::ADJUST_STACK_TO_TOP:
210
// While this can be considered to be a vararg consumer, it is already handled in fastcall instructions
211
break;
212
case IrCmd::GET_TYPEOF:
213
visitor.use(OP_A(inst));
214
break;
215
216
case IrCmd::FINDUPVAL:
217
visitor.use(OP_A(inst));
218
break;
219
220
case IrCmd::MARK_USED:
221
visitor.useRange(vmRegOp(OP_A(inst)), function.intOp(OP_B(inst)));
222
break;
223
case IrCmd::MARK_DEAD:
224
// Does not affect VM def/use info
225
break;
226
227
default:
228
// All instructions which reference registers have to be handled explicitly
229
for (auto& op : inst.ops)
230
CODEGEN_ASSERT(op.kind != IrOpKind::VmReg);
231
break;
232
}
233
}
234
235
template<typename T>
236
static void visitVmRegDefsUses(T& visitor, IrFunction& function, const IrBlock& block)
237
{
238
for (uint32_t instIdx = block.start; instIdx <= block.finish; instIdx++)
239
{
240
IrInst& inst = function.instructions[instIdx];
241
242
visitVmRegDefsUses(visitor, function, inst);
243
}
244
}
245
246
} // namespace CodeGen
247
} // namespace Luau
248
249