Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 1b0124f

Browse files
brianosmanSkia Commit-Bot
authored andcommitted
Move interpreter disassemble to out-of-line member of ByteCode
Now it returns a string (rather than just calling printf). Adds GUI view of particle effect byte code (for fun), and fixes the unit tests that called ByteCodeFunction::disassemble, which wasn't doing anything. Change-Id: Ide3fd933cf14832feae7ff9e0fdc1ae8f24a28d4 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/273878 Reviewed-by: Ethan Nicholas <[email protected]> Commit-Queue: Brian Osman <[email protected]>
1 parent 9d4b788 commit 1b0124f

File tree

6 files changed

+364
-331
lines changed

6 files changed

+364
-331
lines changed

gn/sksl.gni

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ _src = get_path_info("../src", "abspath")
88

99
skia_sksl_sources = [
1010
"$_src/sksl/SkSLASTNode.cpp",
11+
"$_src/sksl/SkSLByteCode.cpp",
1112
"$_src/sksl/SkSLByteCodeGenerator.cpp",
1213
"$_src/sksl/SkSLCFGGenerator.cpp",
1314
"$_src/sksl/SkSLCompiler.cpp",

src/sksl/SkSLByteCode.cpp

Lines changed: 323 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,323 @@
1+
/*
2+
* Copyright 2020 Google LLC
3+
*
4+
* Use of this source code is governed by a BSD-style license that can be
5+
* found in the LICENSE file.
6+
*/
7+
8+
#include "src/core/SkUtils.h"
9+
#include "src/sksl/SkSLByteCode.h"
10+
#include "src/sksl/SkSLExternalValue.h"
11+
12+
namespace SkSL {
13+
14+
template <typename T>
15+
static T read(const uint8_t** ip) {
16+
*ip += sizeof(T);
17+
return sk_unaligned_load<T>(*ip - sizeof(T));
18+
}
19+
20+
#define DISASSEMBLE_0(inst, name) \
21+
case Instruction::inst: \
22+
return String(name);
23+
24+
#define DISASSEMBLE_1(inst, name) \
25+
case Instruction::inst: \
26+
return String::printf(name " $%d", read<Register>(ip).fIndex);
27+
28+
#define DISASSEMBLE_UNARY(inst, name) \
29+
case Instruction::inst: { \
30+
Register target = read<Register>(ip); \
31+
Register src = read<Register>(ip); \
32+
return String::printf(name " $%d -> $%d", src.fIndex, target.fIndex); \
33+
}
34+
35+
#define DISASSEMBLE_VECTOR_UNARY(inst, name) \
36+
case Instruction::inst: { \
37+
Register target = read<Register>(ip); \
38+
Register src = read<Register>(ip); \
39+
return String::printf(name " $%d -> $%d", src.fIndex, target.fIndex); \
40+
} \
41+
case Instruction::inst##N: { \
42+
uint8_t count = read<uint8_t>(ip); \
43+
Register target = read<Register>(ip); \
44+
Register src = read<Register>(ip); \
45+
return String::printf(name "%d $%d -> $%d", count, src.fIndex, target.fIndex); \
46+
}
47+
48+
#define DISASSEMBLE_BINARY(inst, name) \
49+
case Instruction::inst: { \
50+
Register target = read<Register>(ip); \
51+
Register src1 = read<Register>(ip); \
52+
Register src2 = read<Register>(ip); \
53+
return String::printf(name " $%d, $%d -> $%d", src1.fIndex, src2.fIndex, target.fIndex); \
54+
}
55+
56+
#define DISASSEMBLE_VECTOR_BINARY(inst, name) \
57+
case Instruction::inst: { \
58+
Register target = read<Register>(ip); \
59+
Register src1 = read<Register>(ip); \
60+
Register src2 = read<Register>(ip); \
61+
return String::printf(name " $%d, $%d -> $%d", src1.fIndex, src2.fIndex, target.fIndex); \
62+
} \
63+
case Instruction::inst##N: { \
64+
uint8_t count = read<uint8_t>(ip); \
65+
Register target = read<Register>(ip); \
66+
Register src1 = read<Register>(ip); \
67+
Register src2 = read<Register>(ip); \
68+
return String::printf(name "%d $%d, $%d -> $%d", count, src1.fIndex, src2.fIndex, \
69+
target.fIndex); \
70+
}
71+
72+
// $x = register
73+
// @x = memory cell
74+
// &x = parameter
75+
String ByteCode::disassemble(const uint8_t** ip) const {
76+
Instruction inst = read<Instruction>(ip);
77+
switch (inst) {
78+
DISASSEMBLE_VECTOR_BINARY(kAddF, "addF")
79+
DISASSEMBLE_VECTOR_BINARY(kAddI, "addI")
80+
DISASSEMBLE_BINARY(kAnd, "and")
81+
DISASSEMBLE_BINARY(kCompareEQF, "compare eqF")
82+
DISASSEMBLE_BINARY(kCompareEQI, "compare eqI")
83+
DISASSEMBLE_BINARY(kCompareNEQF, "compare neqF")
84+
DISASSEMBLE_BINARY(kCompareNEQI, "compare neqI")
85+
DISASSEMBLE_BINARY(kCompareGTF, "compare gtF")
86+
DISASSEMBLE_BINARY(kCompareGTS, "compare gtS")
87+
DISASSEMBLE_BINARY(kCompareGTU, "compare gtU")
88+
DISASSEMBLE_BINARY(kCompareGTEQF, "compare gteqF")
89+
DISASSEMBLE_BINARY(kCompareGTEQS, "compare gteqS")
90+
DISASSEMBLE_BINARY(kCompareGTEQU, "compare gteqU")
91+
DISASSEMBLE_BINARY(kCompareLTF, "compare ltF")
92+
DISASSEMBLE_BINARY(kCompareLTS, "compare ltS")
93+
DISASSEMBLE_BINARY(kCompareLTU, "compare ltU")
94+
DISASSEMBLE_BINARY(kCompareLTEQF, "compare lteqF")
95+
DISASSEMBLE_BINARY(kCompareLTEQS, "compare lteqS")
96+
DISASSEMBLE_BINARY(kCompareLTEQU, "compare lteqU")
97+
DISASSEMBLE_VECTOR_BINARY(kSubtractF, "subF")
98+
DISASSEMBLE_VECTOR_BINARY(kSubtractI, "subI")
99+
DISASSEMBLE_VECTOR_BINARY(kDivideF, "divF")
100+
DISASSEMBLE_VECTOR_BINARY(kDivideS, "divS")
101+
DISASSEMBLE_VECTOR_BINARY(kDivideU, "divU")
102+
DISASSEMBLE_VECTOR_BINARY(kRemainderS, "remS")
103+
DISASSEMBLE_VECTOR_BINARY(kRemainderU, "remU")
104+
DISASSEMBLE_VECTOR_BINARY(kRemainderF, "remF")
105+
DISASSEMBLE_VECTOR_BINARY(kMultiplyF, "mulF")
106+
DISASSEMBLE_VECTOR_BINARY(kMultiplyI, "mulI")
107+
DISASSEMBLE_BINARY(kOr, "or")
108+
DISASSEMBLE_BINARY(kXor, "xor")
109+
DISASSEMBLE_0(kNop, "nop")
110+
DISASSEMBLE_0(kAbort, "abort")
111+
case Instruction::kBoundsCheck: {
112+
Register r = read<Register>(ip);
113+
int length = read<int>(ip);
114+
return String::printf("boundsCheck 0 <= $%d < %d", r.fIndex, length);
115+
}
116+
case Instruction::kBranch:
117+
return String::printf("branch %d", read<Pointer>(ip).fAddress);
118+
case Instruction::kBranchIfAllFalse:
119+
return String::printf("branchIfAllFalse %d", read<Pointer>(ip).fAddress);
120+
DISASSEMBLE_0(kBreak, "break")
121+
case Instruction::kCall: {
122+
Register target = read<Register>(ip);
123+
uint8_t idx = read<uint8_t>(ip);
124+
Register args = read<Register>(ip);
125+
ByteCodeFunction* f = fFunctions[idx].get();
126+
return String::printf("call %s($%d...) -> $%d", f->fName.c_str(), args.fIndex,
127+
target.fIndex);
128+
}
129+
case Instruction::kCallExternal: {
130+
Register target = read<Register>(ip);
131+
uint8_t idx = read<uint8_t>(ip);
132+
uint8_t targetCount = read<uint8_t>(ip);
133+
Register args = read<Register>(ip);
134+
uint8_t argCount = read<uint8_t>(ip);
135+
ExternalValue* ev = fExternalValues[idx];
136+
return String::printf("callExternal %s($%d(%d)...) -> $%d(%d)",
137+
String(ev->fName).c_str(), args.fIndex, argCount, target.fIndex,
138+
targetCount);
139+
}
140+
DISASSEMBLE_0(kContinue, "continue")
141+
DISASSEMBLE_UNARY(kCopy, "copy")
142+
DISASSEMBLE_UNARY(kCos, "cos")
143+
DISASSEMBLE_UNARY(kFloatToSigned, "FtoS")
144+
DISASSEMBLE_UNARY(kFloatToUnsigned, "FtoU")
145+
case Instruction::kImmediate: {
146+
Register target = read<Register>(ip);
147+
Immediate src = read<Immediate>(ip);
148+
return String::printf("immediate (%d | %f) -> $%d", src.fInt, src.fFloat,
149+
target.fIndex);
150+
}
151+
DISASSEMBLE_UNARY(kInverse2x2, "inverse2x2")
152+
DISASSEMBLE_UNARY(kInverse3x3, "inverse3x3")
153+
DISASSEMBLE_UNARY(kInverse4x4, "inverse4x4")
154+
DISASSEMBLE_VECTOR_UNARY(kLoad, "load")
155+
case Instruction::kLoadDirect: {
156+
Register target = read<Register>(ip);
157+
Pointer src = read<Pointer>(ip);
158+
return String::printf("loadDirect @%d -> $%d", src.fAddress, target.fIndex);
159+
}
160+
case Instruction::kLoadDirectN: {
161+
uint8_t count = read<uint8_t>(ip);
162+
Register target = read<Register>(ip);
163+
Pointer src = read<Pointer>(ip);
164+
return String::printf("loadDirect%d @%d -> $%d", count, src.fAddress, target.fIndex);
165+
}
166+
DISASSEMBLE_VECTOR_UNARY(kLoadParameter, "loadParameter")
167+
case Instruction::kLoadParameterDirect: {
168+
Register target = read<Register>(ip);
169+
Pointer src = read<Pointer>(ip);
170+
return String::printf("loadParameterDirect &%d -> $%d", src.fAddress, target.fIndex);
171+
}
172+
case Instruction::kLoadParameterDirectN: {
173+
uint8_t count = read<uint8_t>(ip);
174+
Register target = read<Register>(ip);
175+
Pointer src = read<Pointer>(ip);
176+
return String::printf("loadParameterDirect%d &%d -> $%d", count, src.fAddress,
177+
target.fIndex);
178+
}
179+
DISASSEMBLE_VECTOR_UNARY(kLoadStack, "loadStack")
180+
case Instruction::kLoadStackDirect: {
181+
Register target = read<Register>(ip);
182+
Pointer src = read<Pointer>(ip);
183+
return String::printf("loadStackDirect @%d -> $%d", src.fAddress, target.fIndex);
184+
}
185+
case Instruction::kLoadStackDirectN: {
186+
uint8_t count = read<uint8_t>(ip);
187+
Register target = read<Register>(ip);
188+
Pointer src = read<Pointer>(ip);
189+
return String::printf("loadStackDirect%d @%d -> $%d", count, src.fAddress,
190+
target.fIndex);
191+
}
192+
DISASSEMBLE_0(kLoopBegin, "loopBegin")
193+
DISASSEMBLE_0(kLoopEnd, "loopEnd")
194+
DISASSEMBLE_1(kLoopMask, "loopMask")
195+
DISASSEMBLE_0(kLoopNext, "loopNext")
196+
DISASSEMBLE_0(kMaskNegate, "maskNegate")
197+
DISASSEMBLE_0(kMaskPop, "maskPop")
198+
DISASSEMBLE_1(kMaskPush, "maskPush")
199+
case Instruction::kMatrixMultiply: {
200+
Register target = read<Register>(ip);
201+
Register left = read<Register>(ip);
202+
Register right = read<Register>(ip);
203+
uint8_t leftColsAndRightRows = read<uint8_t>(ip);
204+
uint8_t leftRows = read<uint8_t>(ip);
205+
uint8_t rightColumns = read<uint8_t>(ip);
206+
return String::printf("matrixMultiply $%d, $%d, %d, %d, %d -> $%d", left.fIndex,
207+
right.fIndex, leftColsAndRightRows, leftRows, rightColumns,
208+
target.fIndex);
209+
}
210+
case Instruction::kMatrixToMatrix: {
211+
Register target = read<Register>(ip);
212+
Register src = read<Register>(ip);
213+
uint8_t srcColumns = read<uint8_t>(ip);
214+
uint8_t srcRows = read<uint8_t>(ip);
215+
uint8_t dstColumns = read<uint8_t>(ip);
216+
uint8_t dstRows = read<uint8_t>(ip);
217+
return String::printf("matrixToMatrix $%d, %dx%d to %dx%d -> $%d", src.fIndex,
218+
srcColumns, srcRows, dstColumns, dstRows, target.fIndex);
219+
}
220+
DISASSEMBLE_UNARY(kNegateF, "negateF")
221+
DISASSEMBLE_UNARY(kNegateS, "negateS")
222+
DISASSEMBLE_UNARY(kNot, "not")
223+
case Instruction::kReadExternal: {
224+
Register target = read<Register>(ip);
225+
uint8_t count = read<uint8_t>(ip);
226+
uint8_t index = read<uint8_t>(ip);
227+
return String::printf("readExternal %d, %d -> $%d", count, index, target.fIndex);
228+
}
229+
DISASSEMBLE_1(kPrint, "print")
230+
DISASSEMBLE_0(kReturn, "return")
231+
DISASSEMBLE_1(kReturnValue, "returnValue")
232+
case Instruction::kScalarToMatrix: {
233+
Register target = read<Register>(ip);
234+
Register src = read<Register>(ip);
235+
uint8_t columns = read<uint8_t>(ip);
236+
uint8_t rows = read<uint8_t>(ip);
237+
return String::printf("scalarToMatrix $%d, %dx%d -> $%d", src.fIndex, columns, rows,
238+
target.fIndex);
239+
}
240+
case Instruction::kSelect: {
241+
Register target = read<Register>(ip);
242+
Register test = read<Register>(ip);
243+
Register src1 = read<Register>(ip);
244+
Register src2 = read<Register>(ip);
245+
return String::printf("select $%d, $%d, $%d -> %d", test.fIndex, src1.fIndex,
246+
src2.fIndex, target.fIndex);
247+
}
248+
DISASSEMBLE_BINARY(kShiftLeft, "shiftLeft")
249+
DISASSEMBLE_BINARY(kShiftRightS, "shiftRightS")
250+
DISASSEMBLE_BINARY(kShiftRightU, "shiftRightU")
251+
DISASSEMBLE_UNARY(kSignedToFloat, "signedToFloat")
252+
DISASSEMBLE_UNARY(kSin, "sin")
253+
case Instruction::kSplat: {
254+
uint8_t count = read<uint8_t>(ip);
255+
Pointer target = read<Pointer>(ip);
256+
Register src = read<Register>(ip);
257+
return String::printf("splat%d $%d -> @%d", count, src.fIndex, target.fAddress);
258+
}
259+
DISASSEMBLE_UNARY(kSqrt, "sqrt")
260+
DISASSEMBLE_VECTOR_UNARY(kStore, "store")
261+
case Instruction::kStoreDirect: {
262+
Pointer target = read<Pointer>(ip);
263+
Register src = read<Register>(ip);
264+
return String::printf("store $%d -> @%d", src.fIndex, target.fAddress);
265+
}
266+
case Instruction::kStoreDirectN: {
267+
uint8_t count = read<uint8_t>(ip);
268+
Pointer target = read<Pointer>(ip);
269+
Register src = read<Register>(ip);
270+
return String::printf("store%d $%d -> @%d", count, src.fIndex, target.fAddress);
271+
}
272+
DISASSEMBLE_VECTOR_UNARY(kStoreParameter, "storeParameter")
273+
case Instruction::kStoreParameterDirect: {
274+
Pointer target = read<Pointer>(ip);
275+
Register src = read<Register>(ip);
276+
return String::printf("storeParameterDirect $%d -> &%d", src.fIndex, target.fAddress);
277+
}
278+
case Instruction::kStoreParameterDirectN: {
279+
uint8_t count = read<uint8_t>(ip);
280+
Pointer target = read<Pointer>(ip);
281+
Register src = read<Register>(ip);
282+
return String::printf("storeParameterDirect%d $%d -> &%d", count, src.fIndex,
283+
target.fAddress);
284+
}
285+
DISASSEMBLE_VECTOR_UNARY(kStoreStack, "storeStack")
286+
case Instruction::kStoreStackDirect: {
287+
Pointer target = read<Pointer>(ip);
288+
Register src = read<Register>(ip);
289+
return String::printf("storeStackDirect $%d -> @%d", src.fIndex, target.fAddress);
290+
}
291+
case Instruction::kStoreStackDirectN: {
292+
uint8_t count = read<uint8_t>(ip);
293+
Pointer target = read<Pointer>(ip);
294+
Register src = read<Register>(ip);
295+
return String::printf("storeStackDirect%d $%d -> @%d", count, src.fIndex,
296+
target.fAddress);
297+
}
298+
DISASSEMBLE_UNARY(kTan, "tan")
299+
DISASSEMBLE_UNARY(kUnsignedToFloat, "unsignedToFloat")
300+
case Instruction::kWriteExternal: {
301+
uint8_t index = read<uint8_t>(ip);
302+
uint8_t count = read<uint8_t>(ip);
303+
Register src = read<Register>(ip);
304+
return String::printf("writeExternal $%d, %d -> %d", src.fIndex, count, index);
305+
}
306+
default:
307+
SkASSERT(false);
308+
return String::printf("unsupported: %d", (int)inst);
309+
}
310+
}
311+
312+
String ByteCode::disassembleFunction(const ByteCodeFunction* f) const {
313+
String result;
314+
const uint8_t* ip = f->fCode.data();
315+
const uint8_t* codeEnd = f->fCode.data() + f->fCode.size();
316+
while (ip < codeEnd) {
317+
result.append(this->disassemble(&ip));
318+
result.append("\n");
319+
}
320+
return result;
321+
}
322+
323+
} // namespace SkSL

src/sksl/SkSLByteCode.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,10 @@ class ByteCodeFunction {
3333
* Note that this is the actual number of parameters, not the number of parameter slots.
3434
*/
3535
int getParameterCount() const { return fParameters.size(); }
36-
3736
Parameter getParameter(int idx) const { return fParameters[idx]; }
38-
3937
int getParameterSlotCount() const { return fParameterSlotCount; }
40-
4138
int getReturnSlotCount() const { return fReturnSlotCount; }
42-
43-
void disassemble() const { }
39+
const String& name() const { return fName; }
4440

4541
private:
4642
ByteCodeFunction(const FunctionDeclaration* declaration)
@@ -340,6 +336,8 @@ class SK_API ByteCode {
340336
static constexpr int kPointerMax = 65535;
341337
static constexpr int kRegisterMax = 65535;
342338

339+
int getFunctionCount() const { return fFunctions.size(); }
340+
const ByteCodeFunction* getFunction(int i) const { return fFunctions[i].get(); }
343341
const ByteCodeFunction* getFunction(const char* name) const {
344342
for (const auto& f : fFunctions) {
345343
if (f->fName == name) {
@@ -373,10 +371,14 @@ class SK_API ByteCode {
373371
}
374372
const Uniform& getUniform(int i) const { return fUniforms[i]; }
375373

374+
String disassembleFunction(const ByteCodeFunction*) const;
375+
376376
private:
377377
ByteCode(const ByteCode&) = delete;
378378
ByteCode& operator=(const ByteCode&) = delete;
379379

380+
String disassemble(const uint8_t** ip) const;
381+
380382
std::vector<std::unique_ptr<ByteCodeFunction>> fFunctions;
381383
std::vector<ExternalValue*> fExternalValues;
382384

0 commit comments

Comments
 (0)