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 <ethannicholas@google.com> Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
parent
9d4b788807
commit
1b0124fec6
@ -8,6 +8,7 @@ _src = get_path_info("../src", "abspath")
|
||||
|
||||
skia_sksl_sources = [
|
||||
"$_src/sksl/SkSLASTNode.cpp",
|
||||
"$_src/sksl/SkSLByteCode.cpp",
|
||||
"$_src/sksl/SkSLByteCodeGenerator.cpp",
|
||||
"$_src/sksl/SkSLCFGGenerator.cpp",
|
||||
"$_src/sksl/SkSLCompiler.cpp",
|
||||
|
323
src/sksl/SkSLByteCode.cpp
Normal file
323
src/sksl/SkSLByteCode.cpp
Normal file
@ -0,0 +1,323 @@
|
||||
/*
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "src/core/SkUtils.h"
|
||||
#include "src/sksl/SkSLByteCode.h"
|
||||
#include "src/sksl/SkSLExternalValue.h"
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
template <typename T>
|
||||
static T read(const uint8_t** ip) {
|
||||
*ip += sizeof(T);
|
||||
return sk_unaligned_load<T>(*ip - sizeof(T));
|
||||
}
|
||||
|
||||
#define DISASSEMBLE_0(inst, name) \
|
||||
case Instruction::inst: \
|
||||
return String(name);
|
||||
|
||||
#define DISASSEMBLE_1(inst, name) \
|
||||
case Instruction::inst: \
|
||||
return String::printf(name " $%d", read<Register>(ip).fIndex);
|
||||
|
||||
#define DISASSEMBLE_UNARY(inst, name) \
|
||||
case Instruction::inst: { \
|
||||
Register target = read<Register>(ip); \
|
||||
Register src = read<Register>(ip); \
|
||||
return String::printf(name " $%d -> $%d", src.fIndex, target.fIndex); \
|
||||
}
|
||||
|
||||
#define DISASSEMBLE_VECTOR_UNARY(inst, name) \
|
||||
case Instruction::inst: { \
|
||||
Register target = read<Register>(ip); \
|
||||
Register src = read<Register>(ip); \
|
||||
return String::printf(name " $%d -> $%d", src.fIndex, target.fIndex); \
|
||||
} \
|
||||
case Instruction::inst##N: { \
|
||||
uint8_t count = read<uint8_t>(ip); \
|
||||
Register target = read<Register>(ip); \
|
||||
Register src = read<Register>(ip); \
|
||||
return String::printf(name "%d $%d -> $%d", count, src.fIndex, target.fIndex); \
|
||||
}
|
||||
|
||||
#define DISASSEMBLE_BINARY(inst, name) \
|
||||
case Instruction::inst: { \
|
||||
Register target = read<Register>(ip); \
|
||||
Register src1 = read<Register>(ip); \
|
||||
Register src2 = read<Register>(ip); \
|
||||
return String::printf(name " $%d, $%d -> $%d", src1.fIndex, src2.fIndex, target.fIndex); \
|
||||
}
|
||||
|
||||
#define DISASSEMBLE_VECTOR_BINARY(inst, name) \
|
||||
case Instruction::inst: { \
|
||||
Register target = read<Register>(ip); \
|
||||
Register src1 = read<Register>(ip); \
|
||||
Register src2 = read<Register>(ip); \
|
||||
return String::printf(name " $%d, $%d -> $%d", src1.fIndex, src2.fIndex, target.fIndex); \
|
||||
} \
|
||||
case Instruction::inst##N: { \
|
||||
uint8_t count = read<uint8_t>(ip); \
|
||||
Register target = read<Register>(ip); \
|
||||
Register src1 = read<Register>(ip); \
|
||||
Register src2 = read<Register>(ip); \
|
||||
return String::printf(name "%d $%d, $%d -> $%d", count, src1.fIndex, src2.fIndex, \
|
||||
target.fIndex); \
|
||||
}
|
||||
|
||||
// $x = register
|
||||
// @x = memory cell
|
||||
// &x = parameter
|
||||
String ByteCode::disassemble(const uint8_t** ip) const {
|
||||
Instruction inst = read<Instruction>(ip);
|
||||
switch (inst) {
|
||||
DISASSEMBLE_VECTOR_BINARY(kAddF, "addF")
|
||||
DISASSEMBLE_VECTOR_BINARY(kAddI, "addI")
|
||||
DISASSEMBLE_BINARY(kAnd, "and")
|
||||
DISASSEMBLE_BINARY(kCompareEQF, "compare eqF")
|
||||
DISASSEMBLE_BINARY(kCompareEQI, "compare eqI")
|
||||
DISASSEMBLE_BINARY(kCompareNEQF, "compare neqF")
|
||||
DISASSEMBLE_BINARY(kCompareNEQI, "compare neqI")
|
||||
DISASSEMBLE_BINARY(kCompareGTF, "compare gtF")
|
||||
DISASSEMBLE_BINARY(kCompareGTS, "compare gtS")
|
||||
DISASSEMBLE_BINARY(kCompareGTU, "compare gtU")
|
||||
DISASSEMBLE_BINARY(kCompareGTEQF, "compare gteqF")
|
||||
DISASSEMBLE_BINARY(kCompareGTEQS, "compare gteqS")
|
||||
DISASSEMBLE_BINARY(kCompareGTEQU, "compare gteqU")
|
||||
DISASSEMBLE_BINARY(kCompareLTF, "compare ltF")
|
||||
DISASSEMBLE_BINARY(kCompareLTS, "compare ltS")
|
||||
DISASSEMBLE_BINARY(kCompareLTU, "compare ltU")
|
||||
DISASSEMBLE_BINARY(kCompareLTEQF, "compare lteqF")
|
||||
DISASSEMBLE_BINARY(kCompareLTEQS, "compare lteqS")
|
||||
DISASSEMBLE_BINARY(kCompareLTEQU, "compare lteqU")
|
||||
DISASSEMBLE_VECTOR_BINARY(kSubtractF, "subF")
|
||||
DISASSEMBLE_VECTOR_BINARY(kSubtractI, "subI")
|
||||
DISASSEMBLE_VECTOR_BINARY(kDivideF, "divF")
|
||||
DISASSEMBLE_VECTOR_BINARY(kDivideS, "divS")
|
||||
DISASSEMBLE_VECTOR_BINARY(kDivideU, "divU")
|
||||
DISASSEMBLE_VECTOR_BINARY(kRemainderS, "remS")
|
||||
DISASSEMBLE_VECTOR_BINARY(kRemainderU, "remU")
|
||||
DISASSEMBLE_VECTOR_BINARY(kRemainderF, "remF")
|
||||
DISASSEMBLE_VECTOR_BINARY(kMultiplyF, "mulF")
|
||||
DISASSEMBLE_VECTOR_BINARY(kMultiplyI, "mulI")
|
||||
DISASSEMBLE_BINARY(kOr, "or")
|
||||
DISASSEMBLE_BINARY(kXor, "xor")
|
||||
DISASSEMBLE_0(kNop, "nop")
|
||||
DISASSEMBLE_0(kAbort, "abort")
|
||||
case Instruction::kBoundsCheck: {
|
||||
Register r = read<Register>(ip);
|
||||
int length = read<int>(ip);
|
||||
return String::printf("boundsCheck 0 <= $%d < %d", r.fIndex, length);
|
||||
}
|
||||
case Instruction::kBranch:
|
||||
return String::printf("branch %d", read<Pointer>(ip).fAddress);
|
||||
case Instruction::kBranchIfAllFalse:
|
||||
return String::printf("branchIfAllFalse %d", read<Pointer>(ip).fAddress);
|
||||
DISASSEMBLE_0(kBreak, "break")
|
||||
case Instruction::kCall: {
|
||||
Register target = read<Register>(ip);
|
||||
uint8_t idx = read<uint8_t>(ip);
|
||||
Register args = read<Register>(ip);
|
||||
ByteCodeFunction* f = fFunctions[idx].get();
|
||||
return String::printf("call %s($%d...) -> $%d", f->fName.c_str(), args.fIndex,
|
||||
target.fIndex);
|
||||
}
|
||||
case Instruction::kCallExternal: {
|
||||
Register target = read<Register>(ip);
|
||||
uint8_t idx = read<uint8_t>(ip);
|
||||
uint8_t targetCount = read<uint8_t>(ip);
|
||||
Register args = read<Register>(ip);
|
||||
uint8_t argCount = read<uint8_t>(ip);
|
||||
ExternalValue* ev = fExternalValues[idx];
|
||||
return String::printf("callExternal %s($%d(%d)...) -> $%d(%d)",
|
||||
String(ev->fName).c_str(), args.fIndex, argCount, target.fIndex,
|
||||
targetCount);
|
||||
}
|
||||
DISASSEMBLE_0(kContinue, "continue")
|
||||
DISASSEMBLE_UNARY(kCopy, "copy")
|
||||
DISASSEMBLE_UNARY(kCos, "cos")
|
||||
DISASSEMBLE_UNARY(kFloatToSigned, "FtoS")
|
||||
DISASSEMBLE_UNARY(kFloatToUnsigned, "FtoU")
|
||||
case Instruction::kImmediate: {
|
||||
Register target = read<Register>(ip);
|
||||
Immediate src = read<Immediate>(ip);
|
||||
return String::printf("immediate (%d | %f) -> $%d", src.fInt, src.fFloat,
|
||||
target.fIndex);
|
||||
}
|
||||
DISASSEMBLE_UNARY(kInverse2x2, "inverse2x2")
|
||||
DISASSEMBLE_UNARY(kInverse3x3, "inverse3x3")
|
||||
DISASSEMBLE_UNARY(kInverse4x4, "inverse4x4")
|
||||
DISASSEMBLE_VECTOR_UNARY(kLoad, "load")
|
||||
case Instruction::kLoadDirect: {
|
||||
Register target = read<Register>(ip);
|
||||
Pointer src = read<Pointer>(ip);
|
||||
return String::printf("loadDirect @%d -> $%d", src.fAddress, target.fIndex);
|
||||
}
|
||||
case Instruction::kLoadDirectN: {
|
||||
uint8_t count = read<uint8_t>(ip);
|
||||
Register target = read<Register>(ip);
|
||||
Pointer src = read<Pointer>(ip);
|
||||
return String::printf("loadDirect%d @%d -> $%d", count, src.fAddress, target.fIndex);
|
||||
}
|
||||
DISASSEMBLE_VECTOR_UNARY(kLoadParameter, "loadParameter")
|
||||
case Instruction::kLoadParameterDirect: {
|
||||
Register target = read<Register>(ip);
|
||||
Pointer src = read<Pointer>(ip);
|
||||
return String::printf("loadParameterDirect &%d -> $%d", src.fAddress, target.fIndex);
|
||||
}
|
||||
case Instruction::kLoadParameterDirectN: {
|
||||
uint8_t count = read<uint8_t>(ip);
|
||||
Register target = read<Register>(ip);
|
||||
Pointer src = read<Pointer>(ip);
|
||||
return String::printf("loadParameterDirect%d &%d -> $%d", count, src.fAddress,
|
||||
target.fIndex);
|
||||
}
|
||||
DISASSEMBLE_VECTOR_UNARY(kLoadStack, "loadStack")
|
||||
case Instruction::kLoadStackDirect: {
|
||||
Register target = read<Register>(ip);
|
||||
Pointer src = read<Pointer>(ip);
|
||||
return String::printf("loadStackDirect @%d -> $%d", src.fAddress, target.fIndex);
|
||||
}
|
||||
case Instruction::kLoadStackDirectN: {
|
||||
uint8_t count = read<uint8_t>(ip);
|
||||
Register target = read<Register>(ip);
|
||||
Pointer src = read<Pointer>(ip);
|
||||
return String::printf("loadStackDirect%d @%d -> $%d", count, src.fAddress,
|
||||
target.fIndex);
|
||||
}
|
||||
DISASSEMBLE_0(kLoopBegin, "loopBegin")
|
||||
DISASSEMBLE_0(kLoopEnd, "loopEnd")
|
||||
DISASSEMBLE_1(kLoopMask, "loopMask")
|
||||
DISASSEMBLE_0(kLoopNext, "loopNext")
|
||||
DISASSEMBLE_0(kMaskNegate, "maskNegate")
|
||||
DISASSEMBLE_0(kMaskPop, "maskPop")
|
||||
DISASSEMBLE_1(kMaskPush, "maskPush")
|
||||
case Instruction::kMatrixMultiply: {
|
||||
Register target = read<Register>(ip);
|
||||
Register left = read<Register>(ip);
|
||||
Register right = read<Register>(ip);
|
||||
uint8_t leftColsAndRightRows = read<uint8_t>(ip);
|
||||
uint8_t leftRows = read<uint8_t>(ip);
|
||||
uint8_t rightColumns = read<uint8_t>(ip);
|
||||
return String::printf("matrixMultiply $%d, $%d, %d, %d, %d -> $%d", left.fIndex,
|
||||
right.fIndex, leftColsAndRightRows, leftRows, rightColumns,
|
||||
target.fIndex);
|
||||
}
|
||||
case Instruction::kMatrixToMatrix: {
|
||||
Register target = read<Register>(ip);
|
||||
Register src = read<Register>(ip);
|
||||
uint8_t srcColumns = read<uint8_t>(ip);
|
||||
uint8_t srcRows = read<uint8_t>(ip);
|
||||
uint8_t dstColumns = read<uint8_t>(ip);
|
||||
uint8_t dstRows = read<uint8_t>(ip);
|
||||
return String::printf("matrixToMatrix $%d, %dx%d to %dx%d -> $%d", src.fIndex,
|
||||
srcColumns, srcRows, dstColumns, dstRows, target.fIndex);
|
||||
}
|
||||
DISASSEMBLE_UNARY(kNegateF, "negateF")
|
||||
DISASSEMBLE_UNARY(kNegateS, "negateS")
|
||||
DISASSEMBLE_UNARY(kNot, "not")
|
||||
case Instruction::kReadExternal: {
|
||||
Register target = read<Register>(ip);
|
||||
uint8_t count = read<uint8_t>(ip);
|
||||
uint8_t index = read<uint8_t>(ip);
|
||||
return String::printf("readExternal %d, %d -> $%d", count, index, target.fIndex);
|
||||
}
|
||||
DISASSEMBLE_1(kPrint, "print")
|
||||
DISASSEMBLE_0(kReturn, "return")
|
||||
DISASSEMBLE_1(kReturnValue, "returnValue")
|
||||
case Instruction::kScalarToMatrix: {
|
||||
Register target = read<Register>(ip);
|
||||
Register src = read<Register>(ip);
|
||||
uint8_t columns = read<uint8_t>(ip);
|
||||
uint8_t rows = read<uint8_t>(ip);
|
||||
return String::printf("scalarToMatrix $%d, %dx%d -> $%d", src.fIndex, columns, rows,
|
||||
target.fIndex);
|
||||
}
|
||||
case Instruction::kSelect: {
|
||||
Register target = read<Register>(ip);
|
||||
Register test = read<Register>(ip);
|
||||
Register src1 = read<Register>(ip);
|
||||
Register src2 = read<Register>(ip);
|
||||
return String::printf("select $%d, $%d, $%d -> %d", test.fIndex, src1.fIndex,
|
||||
src2.fIndex, target.fIndex);
|
||||
}
|
||||
DISASSEMBLE_BINARY(kShiftLeft, "shiftLeft")
|
||||
DISASSEMBLE_BINARY(kShiftRightS, "shiftRightS")
|
||||
DISASSEMBLE_BINARY(kShiftRightU, "shiftRightU")
|
||||
DISASSEMBLE_UNARY(kSignedToFloat, "signedToFloat")
|
||||
DISASSEMBLE_UNARY(kSin, "sin")
|
||||
case Instruction::kSplat: {
|
||||
uint8_t count = read<uint8_t>(ip);
|
||||
Pointer target = read<Pointer>(ip);
|
||||
Register src = read<Register>(ip);
|
||||
return String::printf("splat%d $%d -> @%d", count, src.fIndex, target.fAddress);
|
||||
}
|
||||
DISASSEMBLE_UNARY(kSqrt, "sqrt")
|
||||
DISASSEMBLE_VECTOR_UNARY(kStore, "store")
|
||||
case Instruction::kStoreDirect: {
|
||||
Pointer target = read<Pointer>(ip);
|
||||
Register src = read<Register>(ip);
|
||||
return String::printf("store $%d -> @%d", src.fIndex, target.fAddress);
|
||||
}
|
||||
case Instruction::kStoreDirectN: {
|
||||
uint8_t count = read<uint8_t>(ip);
|
||||
Pointer target = read<Pointer>(ip);
|
||||
Register src = read<Register>(ip);
|
||||
return String::printf("store%d $%d -> @%d", count, src.fIndex, target.fAddress);
|
||||
}
|
||||
DISASSEMBLE_VECTOR_UNARY(kStoreParameter, "storeParameter")
|
||||
case Instruction::kStoreParameterDirect: {
|
||||
Pointer target = read<Pointer>(ip);
|
||||
Register src = read<Register>(ip);
|
||||
return String::printf("storeParameterDirect $%d -> &%d", src.fIndex, target.fAddress);
|
||||
}
|
||||
case Instruction::kStoreParameterDirectN: {
|
||||
uint8_t count = read<uint8_t>(ip);
|
||||
Pointer target = read<Pointer>(ip);
|
||||
Register src = read<Register>(ip);
|
||||
return String::printf("storeParameterDirect%d $%d -> &%d", count, src.fIndex,
|
||||
target.fAddress);
|
||||
}
|
||||
DISASSEMBLE_VECTOR_UNARY(kStoreStack, "storeStack")
|
||||
case Instruction::kStoreStackDirect: {
|
||||
Pointer target = read<Pointer>(ip);
|
||||
Register src = read<Register>(ip);
|
||||
return String::printf("storeStackDirect $%d -> @%d", src.fIndex, target.fAddress);
|
||||
}
|
||||
case Instruction::kStoreStackDirectN: {
|
||||
uint8_t count = read<uint8_t>(ip);
|
||||
Pointer target = read<Pointer>(ip);
|
||||
Register src = read<Register>(ip);
|
||||
return String::printf("storeStackDirect%d $%d -> @%d", count, src.fIndex,
|
||||
target.fAddress);
|
||||
}
|
||||
DISASSEMBLE_UNARY(kTan, "tan")
|
||||
DISASSEMBLE_UNARY(kUnsignedToFloat, "unsignedToFloat")
|
||||
case Instruction::kWriteExternal: {
|
||||
uint8_t index = read<uint8_t>(ip);
|
||||
uint8_t count = read<uint8_t>(ip);
|
||||
Register src = read<Register>(ip);
|
||||
return String::printf("writeExternal $%d, %d -> %d", src.fIndex, count, index);
|
||||
}
|
||||
default:
|
||||
SkASSERT(false);
|
||||
return String::printf("unsupported: %d", (int)inst);
|
||||
}
|
||||
}
|
||||
|
||||
String ByteCode::disassembleFunction(const ByteCodeFunction* f) const {
|
||||
String result;
|
||||
const uint8_t* ip = f->fCode.data();
|
||||
const uint8_t* codeEnd = f->fCode.data() + f->fCode.size();
|
||||
while (ip < codeEnd) {
|
||||
result.append(this->disassemble(&ip));
|
||||
result.append("\n");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace SkSL
|
@ -33,14 +33,10 @@ public:
|
||||
* Note that this is the actual number of parameters, not the number of parameter slots.
|
||||
*/
|
||||
int getParameterCount() const { return fParameters.size(); }
|
||||
|
||||
Parameter getParameter(int idx) const { return fParameters[idx]; }
|
||||
|
||||
int getParameterSlotCount() const { return fParameterSlotCount; }
|
||||
|
||||
int getReturnSlotCount() const { return fReturnSlotCount; }
|
||||
|
||||
void disassemble() const { }
|
||||
const String& name() const { return fName; }
|
||||
|
||||
private:
|
||||
ByteCodeFunction(const FunctionDeclaration* declaration)
|
||||
@ -340,6 +336,8 @@ public:
|
||||
static constexpr int kPointerMax = 65535;
|
||||
static constexpr int kRegisterMax = 65535;
|
||||
|
||||
int getFunctionCount() const { return fFunctions.size(); }
|
||||
const ByteCodeFunction* getFunction(int i) const { return fFunctions[i].get(); }
|
||||
const ByteCodeFunction* getFunction(const char* name) const {
|
||||
for (const auto& f : fFunctions) {
|
||||
if (f->fName == name) {
|
||||
@ -373,10 +371,14 @@ public:
|
||||
}
|
||||
const Uniform& getUniform(int i) const { return fUniforms[i]; }
|
||||
|
||||
String disassembleFunction(const ByteCodeFunction*) const;
|
||||
|
||||
private:
|
||||
ByteCode(const ByteCode&) = delete;
|
||||
ByteCode& operator=(const ByteCode&) = delete;
|
||||
|
||||
String disassemble(const uint8_t** ip) const;
|
||||
|
||||
std::vector<std::unique_ptr<ByteCodeFunction>> fFunctions;
|
||||
std::vector<ExternalValue*> fExternalValues;
|
||||
|
||||
|
@ -27,12 +27,12 @@ namespace SkSL {
|
||||
using instruction = void*;
|
||||
#define LABEL(name) name:
|
||||
#ifdef TRACE
|
||||
#define NEXT() \
|
||||
{ \
|
||||
const uint8_t* trace_ip = ip; \
|
||||
printf("%d: ", (int) (trace_ip - code)); \
|
||||
disassemble(&trace_ip); \
|
||||
} \
|
||||
#define NEXT() \
|
||||
{ \
|
||||
const uint8_t* trace_ip = ip; \
|
||||
printf("%d: ", (int) (trace_ip - code)); \
|
||||
printf("%s\n", fCode->disassemble(&trace_ip).c_str()); \
|
||||
} \
|
||||
goto *labels[(int) read<ByteCode::Instruction>(&ip)]
|
||||
#else
|
||||
#define NEXT() goto *labels[(int) read<ByteCode::Instruction>(&ip)]
|
||||
@ -141,63 +141,6 @@ static T read(const uint8_t** ip) {
|
||||
NEXT(); \
|
||||
}
|
||||
|
||||
#define DISASSEMBLE_0(inst, name) \
|
||||
case ByteCode::Instruction::inst: printf(name "\n"); break;
|
||||
|
||||
#define DISASSEMBLE_1(inst, name) \
|
||||
case ByteCode::Instruction::inst: \
|
||||
printf(name " $%d\n", read<ByteCode::Register>(ip).fIndex); \
|
||||
break;
|
||||
|
||||
#define DISASSEMBLE_UNARY(inst, name) \
|
||||
case ByteCode::Instruction::inst: { \
|
||||
ByteCode::Register target = read<ByteCode::Register>(ip); \
|
||||
ByteCode::Register src = read<ByteCode::Register>(ip); \
|
||||
printf(name " $%d -> $%d\n", src.fIndex, target.fIndex); \
|
||||
break; \
|
||||
}
|
||||
|
||||
#define DISASSEMBLE_VECTOR_UNARY(inst, name) \
|
||||
case ByteCode::Instruction::inst: { \
|
||||
ByteCode::Register target = read<ByteCode::Register>(ip); \
|
||||
ByteCode::Register src = read<ByteCode::Register>(ip); \
|
||||
printf(name " $%d -> $%d\n", src.fIndex, target.fIndex); \
|
||||
break; \
|
||||
} \
|
||||
case ByteCode::Instruction::inst ## N: { \
|
||||
uint8_t count = read<uint8_t>(ip); \
|
||||
ByteCode::Register target = read<ByteCode::Register>(ip); \
|
||||
ByteCode::Register src = read<ByteCode::Register>(ip); \
|
||||
printf(name "%d $%d -> $%d\n", count, src.fIndex, target.fIndex); \
|
||||
break; \
|
||||
}
|
||||
|
||||
#define DISASSEMBLE_BINARY(inst, name) \
|
||||
case ByteCode::Instruction::inst: { \
|
||||
ByteCode::Register target = read<ByteCode::Register>(ip); \
|
||||
ByteCode::Register src1 = read<ByteCode::Register>(ip); \
|
||||
ByteCode::Register src2 = read<ByteCode::Register>(ip); \
|
||||
printf(name " $%d, $%d -> $%d\n", src1.fIndex, src2.fIndex, target.fIndex); \
|
||||
break; \
|
||||
}
|
||||
|
||||
#define DISASSEMBLE_VECTOR_BINARY(inst, name) \
|
||||
case ByteCode::Instruction::inst: { \
|
||||
ByteCode::Register target = read<ByteCode::Register>(ip); \
|
||||
ByteCode::Register src1 = read<ByteCode::Register>(ip); \
|
||||
ByteCode::Register src2 = read<ByteCode::Register>(ip); \
|
||||
printf(name " $%d, $%d -> $%d\n", src1.fIndex, src2.fIndex, target.fIndex); \
|
||||
break; \
|
||||
} \
|
||||
case ByteCode::Instruction::inst ## N: { \
|
||||
uint8_t count = read<uint8_t>(ip); \
|
||||
ByteCode::Register target = read<ByteCode::Register>(ip); \
|
||||
ByteCode::Register src1 = read<ByteCode::Register>(ip); \
|
||||
ByteCode::Register src2 = read<ByteCode::Register>(ip); \
|
||||
printf(name "%d $%d, $%d -> $%d\n", count, src1.fIndex, src2.fIndex, target.fIndex); \
|
||||
break; \
|
||||
}
|
||||
|
||||
/**
|
||||
* Operates on vectors of the specified width, so creating an Interpreter<16> means that all inputs,
|
||||
* outputs, and internal calculations will be 16-wide vectors.
|
||||
@ -372,264 +315,6 @@ private:
|
||||
std::stack<StackFrame> fCallStack;
|
||||
};
|
||||
|
||||
// $x = register
|
||||
// @x = memory cell
|
||||
// &x = parameter
|
||||
void disassemble(const uint8_t** ip) {
|
||||
ByteCode::Instruction inst = read<ByteCode::Instruction>(ip);
|
||||
switch (inst) {
|
||||
DISASSEMBLE_VECTOR_BINARY(kAddF, "addF")
|
||||
DISASSEMBLE_VECTOR_BINARY(kAddI, "addI")
|
||||
DISASSEMBLE_BINARY(kAnd, "and")
|
||||
DISASSEMBLE_BINARY(kCompareEQF, "compare eqF")
|
||||
DISASSEMBLE_BINARY(kCompareEQI, "compare eqI")
|
||||
DISASSEMBLE_BINARY(kCompareNEQF, "compare neqF")
|
||||
DISASSEMBLE_BINARY(kCompareNEQI, "compare neqI")
|
||||
DISASSEMBLE_BINARY(kCompareGTF, "compare gtF")
|
||||
DISASSEMBLE_BINARY(kCompareGTS, "compare gtS")
|
||||
DISASSEMBLE_BINARY(kCompareGTU, "compare gtU")
|
||||
DISASSEMBLE_BINARY(kCompareGTEQF, "compare gteqF")
|
||||
DISASSEMBLE_BINARY(kCompareGTEQS, "compare gteqS")
|
||||
DISASSEMBLE_BINARY(kCompareGTEQU, "compare gteqU")
|
||||
DISASSEMBLE_BINARY(kCompareLTF, "compare ltF")
|
||||
DISASSEMBLE_BINARY(kCompareLTS, "compare ltS")
|
||||
DISASSEMBLE_BINARY(kCompareLTU, "compare ltU")
|
||||
DISASSEMBLE_BINARY(kCompareLTEQF, "compare lteqF")
|
||||
DISASSEMBLE_BINARY(kCompareLTEQS, "compare lteqS")
|
||||
DISASSEMBLE_BINARY(kCompareLTEQU, "compare lteqU")
|
||||
DISASSEMBLE_VECTOR_BINARY(kSubtractF, "subF")
|
||||
DISASSEMBLE_VECTOR_BINARY(kSubtractI, "subI")
|
||||
DISASSEMBLE_VECTOR_BINARY(kDivideF, "divF")
|
||||
DISASSEMBLE_VECTOR_BINARY(kDivideS, "divS")
|
||||
DISASSEMBLE_VECTOR_BINARY(kDivideU, "divU")
|
||||
DISASSEMBLE_VECTOR_BINARY(kRemainderS, "remS")
|
||||
DISASSEMBLE_VECTOR_BINARY(kRemainderU, "remU")
|
||||
DISASSEMBLE_VECTOR_BINARY(kRemainderF, "remF")
|
||||
DISASSEMBLE_VECTOR_BINARY(kMultiplyF, "mulF")
|
||||
DISASSEMBLE_VECTOR_BINARY(kMultiplyI, "mulI")
|
||||
DISASSEMBLE_BINARY(kOr, "or")
|
||||
DISASSEMBLE_BINARY(kXor, "xor")
|
||||
DISASSEMBLE_0(kNop, "nop")
|
||||
case ByteCode::Instruction::kBoundsCheck: {
|
||||
ByteCode::Register r = read<ByteCode::Register>(ip);
|
||||
int length = read<int>(ip);
|
||||
printf("boundsCheck 0 <= $%d < %d\n", r.fIndex, length);
|
||||
break;
|
||||
}
|
||||
case ByteCode::Instruction::kBranch:
|
||||
printf("branch %d\n", read<ByteCode::Pointer>(ip).fAddress);
|
||||
break;
|
||||
case ByteCode::Instruction::kBranchIfAllFalse:
|
||||
printf("branchIfAllFalse %d\n", read<ByteCode::Pointer>(ip).fAddress);
|
||||
break;
|
||||
DISASSEMBLE_0(kBreak, "break")
|
||||
case ByteCode::Instruction::kCall: {
|
||||
ByteCode::Register target = read<ByteCode::Register>(ip);
|
||||
uint8_t idx = read<uint8_t>(ip);
|
||||
ByteCode::Register args = read<ByteCode::Register>(ip);
|
||||
ByteCodeFunction* f = fCode->fFunctions[idx].get();
|
||||
printf("call %s($%d...) -> $%d", f->fName.c_str(), args.fIndex, target.fIndex);
|
||||
printf("\n");
|
||||
break;
|
||||
}
|
||||
case ByteCode::Instruction::kCallExternal: {
|
||||
ByteCode::Register target = read<ByteCode::Register>(ip);
|
||||
uint8_t idx = read<uint8_t>(ip);
|
||||
uint8_t targetCount = read<uint8_t>(ip);
|
||||
ByteCode::Register args = read<ByteCode::Register>(ip);
|
||||
uint8_t argCount = read<uint8_t>(ip);
|
||||
ExternalValue* ev = fCode->fExternalValues[idx];
|
||||
printf("callExternal %s($%d(%d)...) -> $%d(%d)", String(ev->fName).c_str(),
|
||||
args.fIndex, argCount, target.fIndex, targetCount);
|
||||
printf("\n");
|
||||
break;
|
||||
}
|
||||
DISASSEMBLE_0(kContinue, "continue")
|
||||
DISASSEMBLE_UNARY(kCopy, "copy")
|
||||
DISASSEMBLE_UNARY(kCos, "cos")
|
||||
DISASSEMBLE_UNARY(kFloatToSigned, "FtoS")
|
||||
DISASSEMBLE_UNARY(kFloatToUnsigned, "FtoU")
|
||||
case ByteCode::Instruction::kImmediate: {
|
||||
ByteCode::Register target = read<ByteCode::Register>(ip);
|
||||
ByteCode::Immediate src = read<ByteCode::Immediate>(ip);
|
||||
printf("immediate (%d | %f) -> $%d\n", src.fInt, src.fFloat, target.fIndex);
|
||||
break;
|
||||
}
|
||||
DISASSEMBLE_UNARY(kInverse2x2, "inverse2x2")
|
||||
DISASSEMBLE_UNARY(kInverse3x3, "inverse3x3")
|
||||
DISASSEMBLE_UNARY(kInverse4x4, "inverse4x4")
|
||||
DISASSEMBLE_VECTOR_UNARY(kLoad, "load")
|
||||
case ByteCode::Instruction::kLoadDirect: {
|
||||
ByteCode::Register target = read<ByteCode::Register>(ip);
|
||||
ByteCode::Pointer src = read<ByteCode::Pointer>(ip);
|
||||
printf("loadDirect @%d -> $%d\n", src.fAddress, target.fIndex);
|
||||
break;
|
||||
}
|
||||
case ByteCode::Instruction::kLoadDirectN: {
|
||||
uint8_t count = read<uint8_t>(ip);
|
||||
ByteCode::Register target = read<ByteCode::Register>(ip);
|
||||
ByteCode::Pointer src = read<ByteCode::Pointer>(ip);
|
||||
printf("loadDirect%d @%d -> $%d\n", count, src.fAddress, target.fIndex);
|
||||
break;
|
||||
}
|
||||
DISASSEMBLE_VECTOR_UNARY(kLoadParameter, "loadParameter")
|
||||
case ByteCode::Instruction::kLoadParameterDirect: {
|
||||
ByteCode::Register target = read<ByteCode::Register>(ip);
|
||||
ByteCode::Pointer src = read<ByteCode::Pointer>(ip);
|
||||
printf("loadParameterDirect &%d -> $%d\n", src.fAddress, target.fIndex);
|
||||
break;
|
||||
}
|
||||
case ByteCode::Instruction::kLoadParameterDirectN: {
|
||||
uint8_t count = read<uint8_t>(ip);
|
||||
ByteCode::Register target = read<ByteCode::Register>(ip);
|
||||
ByteCode::Pointer src = read<ByteCode::Pointer>(ip);
|
||||
printf("loadParameterDirect%d &%d -> $%d\n", count, src.fAddress, target.fIndex);
|
||||
break;
|
||||
}
|
||||
DISASSEMBLE_VECTOR_UNARY(kLoadStack, "loadStack")
|
||||
case ByteCode::Instruction::kLoadStackDirect: {
|
||||
ByteCode::Register target = read<ByteCode::Register>(ip);
|
||||
ByteCode::Pointer src = read<ByteCode::Pointer>(ip);
|
||||
printf("loadStackDirect @%d -> $%d\n", src.fAddress, target.fIndex);
|
||||
break;
|
||||
}
|
||||
case ByteCode::Instruction::kLoadStackDirectN: {
|
||||
uint8_t count = read<uint8_t>(ip);
|
||||
ByteCode::Register target = read<ByteCode::Register>(ip);
|
||||
ByteCode::Pointer src = read<ByteCode::Pointer>(ip);
|
||||
printf("loadStackDirect%d @%d -> $%d\n", count, src.fAddress, target.fIndex);
|
||||
break;
|
||||
}
|
||||
DISASSEMBLE_0(kLoopBegin, "loopBegin")
|
||||
DISASSEMBLE_0(kLoopEnd, "loopEnd")
|
||||
DISASSEMBLE_1(kLoopMask, "loopMask")
|
||||
DISASSEMBLE_0(kLoopNext, "loopNext")
|
||||
DISASSEMBLE_0(kMaskNegate, "maskNegate")
|
||||
DISASSEMBLE_0(kMaskPop, "maskPop")
|
||||
DISASSEMBLE_1(kMaskPush, "maskPush")
|
||||
case ByteCode::Instruction::kMatrixMultiply: {
|
||||
ByteCode::Register target = read<ByteCode::Register>(ip);
|
||||
ByteCode::Register left = read<ByteCode::Register>(ip);
|
||||
ByteCode::Register right = read<ByteCode::Register>(ip);
|
||||
uint8_t leftColsAndRightRows = read<uint8_t>(ip);
|
||||
uint8_t leftRows = read<uint8_t>(ip);
|
||||
uint8_t rightColumns = read<uint8_t>(ip);
|
||||
printf("matrixMultiply $%d, $%d, %d, %d, %d -> $%d\n", left.fIndex, right.fIndex,
|
||||
leftColsAndRightRows, leftRows, rightColumns, target.fIndex);
|
||||
break;
|
||||
}
|
||||
case ByteCode::Instruction::kMatrixToMatrix: {
|
||||
ByteCode::Register target = read<ByteCode::Register>(ip);
|
||||
ByteCode::Register src = read<ByteCode::Register>(ip);
|
||||
uint8_t srcColumns = read<uint8_t>(ip);
|
||||
uint8_t srcRows = read<uint8_t>(ip);
|
||||
uint8_t dstColumns = read<uint8_t>(ip);
|
||||
uint8_t dstRows = read<uint8_t>(ip);
|
||||
printf("matrixToMatrix $%d, %dx%d to %dx%d -> $%d\n", src.fIndex, srcColumns,
|
||||
srcRows, dstColumns, dstRows, target.fIndex);
|
||||
break;
|
||||
}
|
||||
DISASSEMBLE_UNARY(kNegateF, "negateF")
|
||||
DISASSEMBLE_UNARY(kNegateS, "negateS")
|
||||
DISASSEMBLE_UNARY(kNot, "not")
|
||||
case ByteCode::Instruction::kReadExternal: {
|
||||
ByteCode::Register target = read<ByteCode::Register>(ip);
|
||||
uint8_t count = read<uint8_t>(ip);
|
||||
uint8_t index = read<uint8_t>(ip);
|
||||
printf("readExternal %d, %d -> $%d\n", count, index, target.fIndex);
|
||||
break;
|
||||
}
|
||||
DISASSEMBLE_1(kPrint, "print")
|
||||
DISASSEMBLE_0(kReturn, "return")
|
||||
DISASSEMBLE_1(kReturnValue, "returnValue")
|
||||
case ByteCode::Instruction::kScalarToMatrix: {
|
||||
ByteCode::Register target = read<ByteCode::Register>(ip);
|
||||
ByteCode::Register src = read<ByteCode::Register>(ip);
|
||||
uint8_t columns = read<uint8_t>(ip);
|
||||
uint8_t rows = read<uint8_t>(ip);
|
||||
printf("scalarToMatrix $%d, %dx%d -> $%d\n", src.fIndex, columns, rows,
|
||||
target.fIndex);
|
||||
break;
|
||||
}
|
||||
case ByteCode::Instruction::kSelect: {
|
||||
ByteCode::Register target = read<ByteCode::Register>(ip);
|
||||
ByteCode::Register test = read<ByteCode::Register>(ip);
|
||||
ByteCode::Register src1 = read<ByteCode::Register>(ip);
|
||||
ByteCode::Register src2 = read<ByteCode::Register>(ip);
|
||||
printf("select $%d, $%d, $%d -> %d\n", test.fIndex, src1.fIndex, src2.fIndex,
|
||||
target.fIndex);
|
||||
break;
|
||||
}
|
||||
DISASSEMBLE_BINARY(kShiftLeft, "shiftLeft")
|
||||
DISASSEMBLE_BINARY(kShiftRightS, "shiftRightS")
|
||||
DISASSEMBLE_BINARY(kShiftRightU, "shiftRightU")
|
||||
DISASSEMBLE_UNARY(kSignedToFloat, "signedToFloat")
|
||||
DISASSEMBLE_UNARY(kSin, "sin")
|
||||
case ByteCode::Instruction::kSplat: {
|
||||
uint8_t count = read<uint8_t>(ip);
|
||||
ByteCode::Pointer target = read<ByteCode::Pointer>(ip);
|
||||
ByteCode::Register src = read<ByteCode::Register>(ip);
|
||||
printf("splat%d $%d -> @%d\n", count, src.fIndex, target.fAddress);
|
||||
break;
|
||||
}
|
||||
DISASSEMBLE_UNARY(kSqrt, "sqrt")
|
||||
DISASSEMBLE_VECTOR_UNARY(kStore, "store")
|
||||
case ByteCode::Instruction::kStoreDirect: {
|
||||
ByteCode::Pointer target = read<ByteCode::Pointer>(ip);
|
||||
ByteCode::Register src = read<ByteCode::Register>(ip);
|
||||
printf("store $%d -> @%d\n", src.fIndex, target.fAddress);
|
||||
break;
|
||||
}
|
||||
case ByteCode::Instruction::kStoreDirectN: {
|
||||
uint8_t count = read<uint8_t>(ip);
|
||||
ByteCode::Pointer target = read<ByteCode::Pointer>(ip);
|
||||
ByteCode::Register src = read<ByteCode::Register>(ip);
|
||||
printf("store%d $%d -> @%d\n", count, src.fIndex, target.fAddress);
|
||||
break;
|
||||
}
|
||||
DISASSEMBLE_VECTOR_UNARY(kStoreParameter, "storeParameter")
|
||||
case ByteCode::Instruction::kStoreParameterDirect: {
|
||||
ByteCode::Pointer target = read<ByteCode::Pointer>(ip);
|
||||
ByteCode::Register src = read<ByteCode::Register>(ip);
|
||||
printf("storeParameterDirect $%d -> &%d\n", src.fIndex, target.fAddress);
|
||||
break;
|
||||
}
|
||||
case ByteCode::Instruction::kStoreParameterDirectN: {
|
||||
uint8_t count = read<uint8_t>(ip);
|
||||
ByteCode::Pointer target = read<ByteCode::Pointer>(ip);
|
||||
ByteCode::Register src = read<ByteCode::Register>(ip);
|
||||
printf("storeParameterDirect%d $%d -> &%d\n", count, src.fIndex, target.fAddress);
|
||||
break;
|
||||
}
|
||||
DISASSEMBLE_VECTOR_UNARY(kStoreStack, "storeStack")
|
||||
case ByteCode::Instruction::kStoreStackDirect: {
|
||||
ByteCode::Pointer target = read<ByteCode::Pointer>(ip);
|
||||
ByteCode::Register src = read<ByteCode::Register>(ip);
|
||||
printf("storeStackDirect $%d -> @%d\n", src.fIndex, target.fAddress);
|
||||
break;
|
||||
}
|
||||
case ByteCode::Instruction::kStoreStackDirectN: {
|
||||
uint8_t count = read<uint8_t>(ip);
|
||||
ByteCode::Pointer target = read<ByteCode::Pointer>(ip);
|
||||
ByteCode::Register src = read<ByteCode::Register>(ip);
|
||||
printf("storeStackDirect%d $%d -> @%d\n", count, src.fIndex, target.fAddress);
|
||||
break;
|
||||
}
|
||||
DISASSEMBLE_UNARY(kTan, "tan")
|
||||
DISASSEMBLE_UNARY(kUnsignedToFloat, "unsignedToFloat")
|
||||
case ByteCode::Instruction::kWriteExternal: {
|
||||
uint8_t index = read<uint8_t>(ip);
|
||||
uint8_t count = read<uint8_t>(ip);
|
||||
ByteCode::Register src = read<ByteCode::Register>(ip);
|
||||
printf("writeExternal $%d, %d -> %d\n", src.fIndex, count, index);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("unsupported: %d\n", (int) inst);
|
||||
SkASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
static Vector VecMod(Vector x, Vector y) {
|
||||
return Vector(x.fFloat - skvx::trunc(x.fFloat / y.fFloat) * y.fFloat);
|
||||
}
|
||||
@ -965,15 +650,14 @@ private:
|
||||
#ifdef SKSL_THREADED_CODE
|
||||
#ifdef TRACE
|
||||
const uint8_t* trace_ip = ip;
|
||||
printf("0: ");
|
||||
disassemble(&trace_ip);
|
||||
printf("0: %s\n", fCode->disassemble(&trace_ip).c_str());
|
||||
#endif
|
||||
goto *labels[(int) read<ByteCode::Instruction>(&ip)];
|
||||
#else
|
||||
for (;;) {
|
||||
#ifdef TRACE
|
||||
const uint8_t* trace_ip = ip;
|
||||
disassemble(&trace_ip);
|
||||
printf("%s\n", fCode->disassemble(&trace_ip).c_str());
|
||||
#endif
|
||||
ByteCode::Instruction inst = read<ByteCode::Instruction>(&ip);
|
||||
switch (inst) {
|
||||
|
@ -112,7 +112,7 @@ void vec_test(skiatest::Reporter* r, const char* src) {
|
||||
out_v[4*i + 0], out_v[4*i + 1], out_v[4*i + 2], out_v[4*i + 3],
|
||||
out_s[4*i + 0], out_s[4*i + 1], out_s[4*i + 2], out_s[4*i + 3]);
|
||||
}
|
||||
main4->disassemble();
|
||||
printf("%s", interpreter4.getCode().disassembleFunction(main4).c_str());
|
||||
REPORT_FAILURE(r, "VecInterpreter mismatch", SkString());
|
||||
}
|
||||
}
|
||||
@ -148,7 +148,7 @@ void test(skiatest::Reporter* r, const char* src, float inR, float inG, float in
|
||||
printf(" expected (%f, %f, %f, %f), but received (%f, %f, %f, %f)\n", expectedR,
|
||||
expectedG, expectedB, expectedA, inoutColor[0].fFloat[0],
|
||||
inoutColor[1].fFloat[0], inoutColor[2].fFloat[0], inoutColor[3].fFloat[0]);
|
||||
main->disassemble();
|
||||
printf("%s", interpreter.getCode().disassembleFunction(main).c_str());
|
||||
}
|
||||
REPORTER_ASSERT(r, inoutColor[0].fFloat[0] == expectedR);
|
||||
REPORTER_ASSERT(r, inoutColor[1].fFloat[0] == expectedG);
|
||||
|
@ -340,6 +340,29 @@ void ParticlesSlide::draw(SkCanvas* canvas) {
|
||||
};
|
||||
uniformsGui(effect->effectCode(), effect->effectUniforms());
|
||||
uniformsGui(effect->particleCode(), effect->particleUniforms());
|
||||
|
||||
auto showDisassembly = [](const SkSL::ByteCode* code) {
|
||||
if (!code) {
|
||||
return;
|
||||
}
|
||||
|
||||
SkSL::String result;
|
||||
for (int i = 0; i < code->getFunctionCount(); ++i) {
|
||||
if (i != 0) {
|
||||
result.append("\n");
|
||||
}
|
||||
const SkSL::ByteCodeFunction* f = code->getFunction(i);
|
||||
result.appendf("%s\n%s", f->name().c_str(),
|
||||
code->disassembleFunction(f).c_str());
|
||||
}
|
||||
ImGui::TextUnformatted(result.c_str());
|
||||
};
|
||||
if (ImGui::TreeNode("Disassembly")) {
|
||||
showDisassembly(effect->effectCode());
|
||||
showDisassembly(effect->particleCode());
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if (remove) {
|
||||
fRunning.removeShuffle(i);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user