From 07c117b6f895af096e74fe44dcab3d9375e12f4c Mon Sep 17 00:00:00 2001 From: Brian Osman Date: Thu, 23 May 2019 12:51:06 -0700 Subject: [PATCH] Support larger compound types in the interpreter Field access and array indexing are supported, including dynamic indices. Larger types (> 4 slots) can be used as lvalues, rvalues, etc. Change-Id: I9bb4ed850be4259c05c8952c6c0a17b71f813772 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/214443 Commit-Queue: Brian Osman Reviewed-by: Ethan Nicholas --- src/sksl/SkSLByteCode.h | 22 ++- src/sksl/SkSLByteCodeGenerator.cpp | 253 ++++++++++++++++++++--------- src/sksl/SkSLByteCodeGenerator.h | 17 +- src/sksl/SkSLInterpreter.cpp | 94 ++++++++++- tests/SkSLInterpreterTest.cpp | 138 ++++++++++++++++ 5 files changed, 433 insertions(+), 91 deletions(-) diff --git a/src/sksl/SkSLByteCode.h b/src/sksl/SkSLByteCode.h index 852b4772ff..fe1474ef2d 100644 --- a/src/sksl/SkSLByteCode.h +++ b/src/sksl/SkSLByteCode.h @@ -61,12 +61,18 @@ enum class ByteCodeInstruction : uint16_t { VECTOR(kDivideU), // Duplicates the top stack value VECTOR(kDup), - // All kLoad* are followed by a byte indicating the local/global slot to load + // Followed by count byte. Duplicates that many values + kDupN, + // kLoad/kLoadGlobal are followed by a byte indicating the local/global slot to load VECTOR(kLoad), VECTOR(kLoadGlobal), - // As above, then a count byte (1-4), and then one byte per swizzle component (0-3). + // As kLoad/kLoadGlobal, then a count byte (1-4), and then one byte per swizzle component (0-3). kLoadSwizzle, kLoadSwizzleGlobal, + // kLoadExtended* are fallback load ops when we lack a specialization. They are followed by a + // count byte, and get the slot to load from the top of the stack. + kLoadExtended, + kLoadExtendedGlobal, VECTOR(kNegateF), VECTOR(kNegateI), VECTOR(kMultiplyF), @@ -75,6 +81,8 @@ enum class ByteCodeInstruction : uint16_t { VECTOR(kOrB), VECTOR(kOrI), VECTOR(kPop), + // Followed by count byte + kPopN, // Followed by a 32 bit value containing the value to push kPushImmediate, // Followed by a byte indicating external value to read @@ -86,14 +94,20 @@ enum class ByteCodeInstruction : uint16_t { kReturn, VECTOR(kSin), VECTOR(kSqrt), - // All kStore* are followed by a byte indicating the local/global slot to store + // kStore/kStoreGlobal are followed by a byte indicating the local/global slot to store VECTOR(kStore), VECTOR(kStoreGlobal), - // As above, then a count byte (1-4), and then one byte per swizzle component (0-3). + // Fallback stores. Followed by count byte, and get the slot to store from the top of the stack + kStoreExtended, + kStoreExtendedGlobal, + // As kStore/kStoreGlobal, then a count byte (1-4), then one byte per swizzle component (0-3). // Expects the stack to look like: ... v1 v2 v3 v4, where the number of 'v's is equal to the // number of swizzle components. After the store, all v's are popped from the stack. kStoreSwizzle, kStoreSwizzleGlobal, + // As above, but gets the store slot from the top of the stack (before values to be stored) + kStoreSwizzleIndirect, + kStoreSwizzleIndirectGlobal, // Followed by two count bytes (1-4), and then one byte per swizzle component (0-3). The first // count byte provides the current vector size (the vector is the top n stack elements), and the // second count byte provides the swizzle component count. diff --git a/src/sksl/SkSLByteCodeGenerator.cpp b/src/sksl/SkSLByteCodeGenerator.cpp index bc3aaea56f..0070674003 100644 --- a/src/sksl/SkSLByteCodeGenerator.cpp +++ b/src/sksl/SkSLByteCodeGenerator.cpp @@ -21,8 +21,23 @@ ByteCodeGenerator::ByteCodeGenerator(const Context* context, const Program* prog fIntrinsics["tan"] = ByteCodeInstruction::kTan; } -static int slot_count(const Type& type) { - return type.columns() * type.rows(); +int ByteCodeGenerator::SlotCount(const Type& type) { + if (type.kind() == Type::kStruct_Kind) { + int slots = 0; + for (const auto& f : type.fields()) { + slots += SlotCount(*f.fType); + } + SkASSERT(slots <= 255); + return slots; + } else if (type.kind() == Type::kArray_Kind) { + int columns = type.columns(); + SkASSERT(columns >= 0); + int slots = columns * SlotCount(type.componentType()); + SkASSERT(slots <= 255); + return slots; + } else { + return type.columns() * type.rows(); + } } bool ByteCodeGenerator::generateCode() { @@ -44,11 +59,11 @@ bool ByteCodeGenerator::generateCode() { continue; } if (declVar->fModifiers.fFlags & Modifiers::kIn_Flag) { - for (int i = slot_count(declVar->fType); i > 0; --i) { + for (int i = SlotCount(declVar->fType); i > 0; --i) { fOutput->fInputSlots.push_back(fOutput->fGlobalCount++); } } else { - fOutput->fGlobalCount += slot_count(declVar->fType); + fOutput->fGlobalCount += SlotCount(declVar->fType); } } break; @@ -70,7 +85,7 @@ std::unique_ptr ByteCodeGenerator::writeFunction(const Functio std::unique_ptr result(new ByteCodeFunction(&f.fDeclaration)); fParameterCount = 0; for (const auto& p : f.fDeclaration.fParameters) { - fParameterCount += p->fType.columns() * p->fType.rows(); + fParameterCount += SlotCount(p->fType); } fCode = &result->fCode; this->writeStatement(*f.fBody); @@ -80,7 +95,7 @@ std::unique_ptr ByteCodeGenerator::writeFunction(const Functio result->fLocalCount = fLocals.size(); const Type& returnType = f.fDeclaration.fReturnType; if (returnType != *fContext.fVoid_Type) { - result->fReturnCount = returnType.columns() * returnType.rows(); + result->fReturnCount = SlotCount(returnType); } fLocals.clear(); fFunction = nullptr; @@ -127,7 +142,7 @@ int ByteCodeGenerator::getLocation(const Variable& var) { } int result = fParameterCount + fLocals.size(); fLocals.push_back(&var); - for (int i = 0; i < slot_count(var.fType) - 1; ++i) { + for (int i = 0; i < SlotCount(var.fType) - 1; ++i) { fLocals.push_back(nullptr); } SkASSERT(result <= 255); @@ -140,7 +155,7 @@ int ByteCodeGenerator::getLocation(const Variable& var) { SkASSERT(offset <= 255); return offset; } - offset += slot_count(p->fType); + offset += SlotCount(p->fType); } SkASSERT(false); return 0; @@ -159,7 +174,7 @@ int ByteCodeGenerator::getLocation(const Variable& var) { SkASSERT(offset <= 255); return offset; } - offset += slot_count(declVar->fType); + offset += SlotCount(declVar->fType); } } } @@ -172,6 +187,62 @@ int ByteCodeGenerator::getLocation(const Variable& var) { } } +int ByteCodeGenerator::getLocation(const Expression& expr, Variable::Storage* storage) { + switch (expr.fKind) { + case Expression::kFieldAccess_Kind: { + const FieldAccess& f = (const FieldAccess&)expr; + int baseAddr = this->getLocation(*f.fBase, storage); + int offset = 0; + for (int i = 0; i < f.fFieldIndex; ++i) { + offset += SlotCount(*f.fBase->fType.fields()[i].fType); + } + if (baseAddr < 0) { + this->write(ByteCodeInstruction::kPushImmediate); + this->write32(offset); + this->write(ByteCodeInstruction::kAddI); + return -1; + } else { + return baseAddr + offset; + } + } + case Expression::kIndex_Kind: { + const IndexExpression& i = (const IndexExpression&)expr; + int stride = SlotCount(i.fType); + int offset = -1; + if (i.fIndex->isConstant()) { + offset = i.fIndex->getConstantInt() * stride; + } else { + this->writeExpression(*i.fIndex); + this->write(ByteCodeInstruction::kPushImmediate); + this->write32(stride); + this->write(ByteCodeInstruction::kMultiplyI); + } + int baseAddr = this->getLocation(*i.fBase, storage); + if (baseAddr >= 0 && offset >= 0) { + return baseAddr + offset; + } + if (baseAddr >= 0) { + this->write(ByteCodeInstruction::kPushImmediate); + this->write32(baseAddr); + } + if (offset >= 0) { + this->write(ByteCodeInstruction::kPushImmediate); + this->write32(offset); + } + this->write(ByteCodeInstruction::kAddI); + return -1; + } + case Expression::kVariableReference_Kind: { + const Variable& var = ((const VariableReference&)expr).fVariable; + *storage = var.fStorage; + return this->getLocation(var); + } + default: + SkASSERT(false); + return 0; + } +} + void ByteCodeGenerator::write8(uint8_t b) { fCode->push_back(b); } @@ -193,6 +264,7 @@ void ByteCodeGenerator::write(ByteCodeInstruction i) { } static ByteCodeInstruction vector_instruction(ByteCodeInstruction base, int count) { + SkASSERT(count >= 1 && count <= 4); return ((ByteCodeInstruction) ((int) base + count - 1)); } @@ -244,7 +316,7 @@ void ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b) { this->write(ByteCodeInstruction::kDup); } } - int count = slot_count(b.fType); + int count = SlotCount(b.fType); switch (op) { case Token::Kind::EQEQ: this->writeTypedInstruction(b.fLeft->fType, ByteCodeInstruction::kCompareIEQ, @@ -364,12 +436,12 @@ void ByteCodeGenerator::writeExternalFunctionCall(const ExternalFunctionCall& f) int argumentCount = 0; for (const auto& arg : f.fArguments) { this->writeExpression(*arg); - argumentCount += slot_count(arg->fType); + argumentCount += SlotCount(arg->fType); } this->write(ByteCodeInstruction::kCallExternal); SkASSERT(argumentCount <= 255); this->write8(argumentCount); - this->write8(slot_count(f.fType)); + this->write8(SlotCount(f.fType)); int index = fOutput->fExternalValues.size(); fOutput->fExternalValues.push_back(f.fFunction); SkASSERT(index <= 255); @@ -378,16 +450,32 @@ void ByteCodeGenerator::writeExternalFunctionCall(const ExternalFunctionCall& f) void ByteCodeGenerator::writeExternalValue(const ExternalValueReference& e) { this->write(vector_instruction(ByteCodeInstruction::kReadExternal, - slot_count(e.fValue->type()))); + SlotCount(e.fValue->type()))); int index = fOutput->fExternalValues.size(); fOutput->fExternalValues.push_back(e.fValue); SkASSERT(index <= 255); this->write8(index); } -void ByteCodeGenerator::writeFieldAccess(const FieldAccess& f) { - // not yet implemented - abort(); +void ByteCodeGenerator::writeVariableExpression(const Expression& expr) { + Variable::Storage storage; + int location = this->getLocation(expr, &storage); + bool isGlobal = storage == Variable::kGlobal_Storage; + int count = SlotCount(expr.fType); + if (location < 0 || count > 4) { + if (location >= 0) { + this->write(ByteCodeInstruction::kPushImmediate); + this->write32(location); + } + this->write(isGlobal ? ByteCodeInstruction::kLoadExtendedGlobal + : ByteCodeInstruction::kLoadExtended); + this->write8(count); + } else { + this->write(vector_instruction(isGlobal ? ByteCodeInstruction::kLoadGlobal + : ByteCodeInstruction::kLoad, + count)); + this->write8(location); + } } void ByteCodeGenerator::writeFloatLiteral(const FloatLiteral& f) { @@ -408,7 +496,7 @@ void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) { case ByteCodeInstruction::kTan: SkASSERT(c.fArguments.size() == 1); this->write((ByteCodeInstruction) ((int) found->second + - slot_count(c.fArguments[0]->fType) - 1)); + SlotCount(c.fArguments[0]->fType) - 1)); break; default: SkASSERT(false); @@ -427,11 +515,6 @@ void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) { fCallTargets.emplace_back(this, f.fFunction); } -void ByteCodeGenerator::writeIndexExpression(const IndexExpression& i) { - // not yet implemented - abort(); -} - void ByteCodeGenerator::writeIntLiteral(const IntLiteral& i) { this->write(ByteCodeInstruction::kPushImmediate); this->write32(i.fValue); @@ -446,7 +529,7 @@ void ByteCodeGenerator::writePrefixExpression(const PrefixExpression& p) { switch (p.fOperator) { case Token::Kind::PLUSPLUS: // fall through case Token::Kind::MINUSMINUS: { - SkASSERT(slot_count(p.fOperand->fType) == 1); + SkASSERT(SlotCount(p.fOperand->fType) == 1); std::unique_ptr lvalue = this->getLValue(*p.fOperand); lvalue->load(); this->write(ByteCodeInstruction::kPushImmediate); @@ -474,7 +557,7 @@ void ByteCodeGenerator::writePrefixExpression(const PrefixExpression& p) { ByteCodeInstruction::kNegateI, ByteCodeInstruction::kNegateI, ByteCodeInstruction::kNegateF, - slot_count(p.fOperand->fType)); + SlotCount(p.fOperand->fType)); break; } default: @@ -486,7 +569,7 @@ void ByteCodeGenerator::writePostfixExpression(const PostfixExpression& p) { switch (p.fOperator) { case Token::Kind::PLUSPLUS: // fall through case Token::Kind::MINUSMINUS: { - SkASSERT(slot_count(p.fOperand->fType) == 1); + SkASSERT(SlotCount(p.fOperand->fType) == 1); std::unique_ptr lvalue = this->getLValue(*p.fOperand); lvalue->load(); this->write(ByteCodeInstruction::kDup); @@ -540,14 +623,6 @@ void ByteCodeGenerator::writeSwizzle(const Swizzle& s) { } } -void ByteCodeGenerator::writeVariableReference(const VariableReference& v) { - this->write(vector_instruction(v.fVariable.fStorage == Variable::kGlobal_Storage - ? ByteCodeInstruction::kLoadGlobal - : ByteCodeInstruction::kLoad, - slot_count(v.fType))); - this->write8(this->getLocation(v.fVariable)); -} - void ByteCodeGenerator::writeTernaryExpression(const TernaryExpression& t) { this->writeExpression(*t.fTest); this->write(ByteCodeInstruction::kConditionalBranch); @@ -578,7 +653,9 @@ void ByteCodeGenerator::writeExpression(const Expression& e) { this->writeExternalValue((ExternalValueReference&) e); break; case Expression::kFieldAccess_Kind: - this->writeFieldAccess((FieldAccess&) e); + case Expression::kIndex_Kind: + case Expression::kVariableReference_Kind: + this->writeVariableExpression(e); break; case Expression::kFloatLiteral_Kind: this->writeFloatLiteral((FloatLiteral&) e); @@ -586,9 +663,6 @@ void ByteCodeGenerator::writeExpression(const Expression& e) { case Expression::kFunctionCall_Kind: this->writeFunctionCall((FunctionCall&) e); break; - case Expression::kIndex_Kind: - this->writeIndexExpression((IndexExpression&) e); - break; case Expression::kIntLiteral_Kind: this->writeIntLiteral((IntLiteral&) e); break; @@ -604,9 +678,6 @@ void ByteCodeGenerator::writeExpression(const Expression& e) { case Expression::kSwizzle_Kind: this->writeSwizzle((Swizzle&) e); break; - case Expression::kVariableReference_Kind: - this->writeVariableReference((VariableReference&) e); - break; case Expression::kTernary_Kind: this->writeTernaryExpression((TernaryExpression&) e); break; @@ -620,7 +691,7 @@ class ByteCodeExternalValueLValue : public ByteCodeGenerator::LValue { public: ByteCodeExternalValueLValue(ByteCodeGenerator* generator, ExternalValue& value, int index) : INHERITED(*generator) - , fCount(slot_count(value.type())) + , fCount(ByteCodeGenerator::SlotCount(value.type())) , fIndex(index) {} void load() override { @@ -646,22 +717,26 @@ class ByteCodeSwizzleLValue : public ByteCodeGenerator::LValue { public: ByteCodeSwizzleLValue(ByteCodeGenerator* generator, const Swizzle& swizzle) : INHERITED(*generator) - , fSwizzle(swizzle) { - SkASSERT(fSwizzle.fBase->fKind == Expression::kVariableReference_Kind); - } + , fSwizzle(swizzle) {} void load() override { fGenerator.writeSwizzle(fSwizzle); } void store() override { - const Variable& var = ((VariableReference&)*fSwizzle.fBase).fVariable; fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, fSwizzle.fComponents.size())); - fGenerator.write(var.fStorage == Variable::kGlobal_Storage - ? ByteCodeInstruction::kStoreSwizzleGlobal - : ByteCodeInstruction::kStoreSwizzle); - fGenerator.write8(fGenerator.getLocation(var)); + Variable::Storage storage; + int location = fGenerator.getLocation(*fSwizzle.fBase, &storage); + bool isGlobal = storage == Variable::kGlobal_Storage; + if (location < 0) { + fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleIndirectGlobal + : ByteCodeInstruction::kStoreSwizzleIndirect); + } else { + fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleGlobal + : ByteCodeInstruction::kStoreSwizzle); + fGenerator.write8(location); + } fGenerator.write8(fSwizzle.fComponents.size()); for (int c : fSwizzle.fComponents) { fGenerator.write8(c); @@ -674,36 +749,47 @@ private: typedef LValue INHERITED; }; -class ByteCodeVariableLValue : public ByteCodeGenerator::LValue { +class ByteCodeExpressionLValue : public ByteCodeGenerator::LValue { public: - ByteCodeVariableLValue(ByteCodeGenerator* generator, const Variable& var) + ByteCodeExpressionLValue(ByteCodeGenerator* generator, const Expression& expr) : INHERITED(*generator) - , fCount(slot_count(var.fType)) - , fLocation(generator->getLocation(var)) - , fIsGlobal(var.fStorage == Variable::kGlobal_Storage) { - } + , fExpression(expr) {} void load() override { - fGenerator.write(vector_instruction(fIsGlobal ? ByteCodeInstruction::kLoadGlobal - : ByteCodeInstruction::kLoad, - fCount)); - fGenerator.write8(fLocation); + fGenerator.writeVariableExpression(fExpression); } void store() override { - fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, fCount)); - fGenerator.write(vector_instruction(fIsGlobal ? ByteCodeInstruction::kStoreGlobal - : ByteCodeInstruction::kStore, - fCount)); - fGenerator.write8(fLocation); + int count = ByteCodeGenerator::SlotCount(fExpression.fType); + if (count > 4) { + fGenerator.write(ByteCodeInstruction::kDupN); + fGenerator.write8(count); + } else { + fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count)); + } + Variable::Storage storage; + int location = fGenerator.getLocation(fExpression, &storage); + bool isGlobal = storage == Variable::kGlobal_Storage; + if (location < 0 || count > 4) { + if (location >= 0) { + fGenerator.write(ByteCodeInstruction::kPushImmediate); + fGenerator.write32(location); + } + fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreExtendedGlobal + : ByteCodeInstruction::kStoreExtended); + fGenerator.write8(count); + } else { + fGenerator.write(vector_instruction(isGlobal ? ByteCodeInstruction::kStoreGlobal + : ByteCodeInstruction::kStore, + count)); + fGenerator.write8(location); + } } private: typedef LValue INHERITED; - int fCount; - int fLocation; - bool fIsGlobal; + const Expression& fExpression; }; std::unique_ptr ByteCodeGenerator::getLValue(const Expression& e) { @@ -715,12 +801,10 @@ std::unique_ptr ByteCodeGenerator::getLValue(const Ex SkASSERT(index <= 255); return std::unique_ptr(new ByteCodeExternalValueLValue(this, *value, index)); } + case Expression::kFieldAccess_Kind: case Expression::kIndex_Kind: - // not yet implemented - abort(); case Expression::kVariableReference_Kind: - return std::unique_ptr(new ByteCodeVariableLValue(this, - ((VariableReference&) e).fVariable)); + return std::unique_ptr(new ByteCodeExpressionLValue(this, e)); case Expression::kSwizzle_Kind: return std::unique_ptr(new ByteCodeSwizzleLValue(this, (Swizzle&) e)); case Expression::kTernary_Kind: @@ -790,7 +874,7 @@ void ByteCodeGenerator::writeForStatement(const ForStatement& f) { this->setContinueTargets(); if (f.fNext) { this->writeExpression(*f.fNext); - this->write(vector_instruction(ByteCodeInstruction::kPop, slot_count(f.fNext->fType))); + this->write(vector_instruction(ByteCodeInstruction::kPop, SlotCount(f.fNext->fType))); } this->write(ByteCodeInstruction::kBranch); this->write16(start); @@ -800,7 +884,7 @@ void ByteCodeGenerator::writeForStatement(const ForStatement& f) { this->setContinueTargets(); if (f.fNext) { this->writeExpression(*f.fNext); - this->write(vector_instruction(ByteCodeInstruction::kPop, slot_count(f.fNext->fType))); + this->write(vector_instruction(ByteCodeInstruction::kPop, SlotCount(f.fNext->fType))); } this->write(ByteCodeInstruction::kBranch); this->write16(start); @@ -834,7 +918,7 @@ void ByteCodeGenerator::writeIfStatement(const IfStatement& i) { void ByteCodeGenerator::writeReturnStatement(const ReturnStatement& r) { this->writeExpression(*r.fExpression); this->write(ByteCodeInstruction::kReturn); - this->write8(r.fExpression->fType.columns() * r.fExpression->fType.rows()); + this->write8(SlotCount(r.fExpression->fType)); } void ByteCodeGenerator::writeSwitchStatement(const SwitchStatement& r) { @@ -850,9 +934,16 @@ void ByteCodeGenerator::writeVarDeclarations(const VarDeclarations& v) { int location = getLocation(*decl.fVar); if (decl.fValue) { this->writeExpression(*decl.fValue); - this->write(vector_instruction(ByteCodeInstruction::kStore, - slot_count(decl.fValue->fType))); - this->write8(location); + int count = SlotCount(decl.fValue->fType); + if (count > 4) { + this->write(ByteCodeInstruction::kPushImmediate); + this->write32(location); + this->write(ByteCodeInstruction::kStoreExtended); + this->write8(count); + } else { + this->write(vector_instruction(ByteCodeInstruction::kStore, count)); + this->write8(location); + } } } } @@ -893,7 +984,13 @@ void ByteCodeGenerator::writeStatement(const Statement& s) { case Statement::kExpression_Kind: { const Expression& expr = *((ExpressionStatement&) s).fExpression; this->writeExpression(expr); - this->write(vector_instruction(ByteCodeInstruction::kPop, slot_count(expr.fType))); + int count = SlotCount(expr.fType); + if (count > 4) { + this->write(ByteCodeInstruction::kPopN); + this->write8(count); + } else { + this->write(vector_instruction(ByteCodeInstruction::kPop, count)); + } break; } case Statement::kFor_Kind: diff --git a/src/sksl/SkSLByteCodeGenerator.h b/src/sksl/SkSLByteCodeGenerator.h index 3a2306c6ae..4d16997c47 100644 --- a/src/sksl/SkSLByteCodeGenerator.h +++ b/src/sksl/SkSLByteCodeGenerator.h @@ -96,6 +96,8 @@ public: void writeTypedInstruction(const Type& type, ByteCodeInstruction s, ByteCodeInstruction u, ByteCodeInstruction f, int count); + static int SlotCount(const Type& type); + private: // reserves 16 bits in the output code, to be filled in later with an address once we determine // it @@ -171,11 +173,18 @@ private: */ int getLocation(const Variable& var); + /** + * As above, but computes the (possibly dynamic) address of an expression involving indexing & + * field access. If the address is known, it's returned. If not, -1 is returned, and the + * location will be left on the top of the stack. + */ + int getLocation(const Expression& expr, Variable::Storage* storage); + std::unique_ptr writeFunction(const FunctionDefinition& f); void writeVarDeclarations(const VarDeclarations& decl); - void writeVariableReference(const VariableReference& ref); + void writeVariableExpression(const Expression& expr); void writeExpression(const Expression& expr); @@ -195,16 +204,12 @@ private: void writeExternalValue(const ExternalValueReference& r); - void writeFieldAccess(const FieldAccess& f); - void writeSwizzle(const Swizzle& swizzle); void writeBinaryExpression(const BinaryExpression& b); void writeTernaryExpression(const TernaryExpression& t); - void writeIndexExpression(const IndexExpression& expr); - void writeLogicalAnd(const BinaryExpression& b); void writeLogicalOr(const BinaryExpression& o); @@ -268,7 +273,7 @@ private: std::unordered_map fIntrinsics; friend class DeferredLocation; - friend class ByteCodeVariableLValue; + friend class ByteCodeExpressionLValue; friend class ByteCodeSwizzleLValue; typedef CodeGenerator INHERITED; diff --git a/src/sksl/SkSLInterpreter.cpp b/src/sksl/SkSLInterpreter.cpp index 13a62b62c4..805c65a300 100644 --- a/src/sksl/SkSLInterpreter.cpp +++ b/src/sksl/SkSLInterpreter.cpp @@ -8,6 +8,7 @@ #ifndef SKSL_STANDALONE #include "src/core/SkRasterPipeline.h" +#include "src/sksl/SkSLByteCodeGenerator.h" #include "src/sksl/SkSLExternalValue.h" #include "src/sksl/SkSLInterpreter.h" #include "src/sksl/ir/SkSLBinaryExpression.h" @@ -64,8 +65,7 @@ void Interpreter::run(const ByteCodeFunction& f, Interpreter::Value args[], this->innerRun(f, stack, outReturn); for (const Variable* p : f.fDeclaration.fParameters) { - const int nvalues = p->fType.columns() - * p->fType.rows(); + const int nvalues = ByteCodeGenerator::SlotCount(p->fType); if (p->fModifiers.fFlags & Modifiers::kOut_Flag) { memcpy(args, stack, nvalues * sizeof(Value)); } @@ -137,6 +137,7 @@ void Interpreter::disassemble(const ByteCodeFunction& f) { VECTOR_DISASSEMBLE(kDivideS, "divideS") VECTOR_DISASSEMBLE(kDivideU, "divideu") VECTOR_DISASSEMBLE(kDup, "dup") + case ByteCodeInstruction::kDupN: printf("dupN %d", READ8()); break; case ByteCodeInstruction::kLoad: printf("load %d", READ8()); break; case ByteCodeInstruction::kLoad2: printf("load2 %d", READ8()); break; case ByteCodeInstruction::kLoad3: printf("load3 %d", READ8()); break; @@ -163,6 +164,9 @@ void Interpreter::disassemble(const ByteCodeFunction& f) { } break; } + case ByteCodeInstruction::kLoadExtended: printf("loadextended %d", READ8()); break; + case ByteCodeInstruction::kLoadExtendedGlobal: printf("loadextendedglobal %d", READ8()); + break; VECTOR_DISASSEMBLE(kMultiplyF, "multiplyf") VECTOR_DISASSEMBLE(kMultiplyI, "multiplyi") VECTOR_DISASSEMBLE(kNegateF, "negatef") @@ -171,6 +175,7 @@ void Interpreter::disassemble(const ByteCodeFunction& f) { VECTOR_DISASSEMBLE(kOrB, "orb") VECTOR_DISASSEMBLE(kOrI, "ori") VECTOR_DISASSEMBLE(kPop, "pop") + case ByteCodeInstruction::kPopN: printf("popN %d", READ8()); break; case ByteCodeInstruction::kPushImmediate: { uint32_t v = READ32(); union { uint32_t u; float f; } pun = { v }; @@ -213,6 +218,26 @@ void Interpreter::disassemble(const ByteCodeFunction& f) { } break; } + case ByteCodeInstruction::kStoreSwizzleIndirect: { + int count = READ8(); + printf("storeswizzleindirect %d", count); + for (int i = 0; i < count; ++i) { + printf(", %d", READ8()); + } + break; + } + case ByteCodeInstruction::kStoreSwizzleIndirectGlobal: { + int count = READ8(); + printf("storeswizzleindirectglobal %d", count); + for (int i = 0; i < count; ++i) { + printf(", %d", READ8()); + } + break; + } + case ByteCodeInstruction::kStoreExtended: printf("storeextended %d", READ8()); break; + case ByteCodeInstruction::kStoreExtendedGlobal: + printf("storeextendedglobal %d", READ8()); + break; VECTOR_DISASSEMBLE(kSubtractF, "subtractf") VECTOR_DISASSEMBLE(kSubtractI, "subtracti") case ByteCodeInstruction::kSwizzle: { @@ -404,6 +429,13 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe case ByteCodeInstruction::kDup : PUSH(sp[(int)ByteCodeInstruction::kDup - (int)inst]); break; + case ByteCodeInstruction::kDupN: { + int count = READ8(); + memcpy(sp + 1, sp - count + 1, count * sizeof(Value)); + sp += count; + break; + } + case ByteCodeInstruction::kLoad4: sp[4] = stack[*ip + 3]; case ByteCodeInstruction::kLoad3: sp[3] = stack[*ip + 2]; case ByteCodeInstruction::kLoad2: sp[2] = stack[*ip + 1]; @@ -417,9 +449,27 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe case ByteCodeInstruction::kLoadGlobal2: sp[2] = fGlobals[*ip + 1]; case ByteCodeInstruction::kLoadGlobal : sp[1] = fGlobals[*ip + 0]; ++ip; - sp += (int)inst - (int)ByteCodeInstruction::kLoadGlobal + 1; + sp += (int)inst - + (int)ByteCodeInstruction::kLoadGlobal + 1; break; + case ByteCodeInstruction::kLoadExtended: { + int count = READ8(); + int src = POP().fSigned; + memcpy(sp + 1, &stack[src], count * sizeof(Value)); + sp += count; + break; + } + + case ByteCodeInstruction::kLoadExtendedGlobal: { + int count = READ8(); + int src = POP().fSigned; + SkASSERT(src + count <= (int) fGlobals.size()); + memcpy(sp + 1, &fGlobals[src], count * sizeof(Value)); + sp += count; + break; + } + case ByteCodeInstruction::kLoadSwizzle: { int src = READ8(); int count = READ8(); @@ -466,6 +516,10 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe case ByteCodeInstruction::kPop : POP(); break; + case ByteCodeInstruction::kPopN: + sp -= READ8(); + break; + case ByteCodeInstruction::kPushImmediate: PUSH(READ32()); break; @@ -525,6 +579,22 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe ++ip; break; + case ByteCodeInstruction::kStoreExtended: { + int count = READ8(); + int target = POP().fSigned; + memcpy(&stack[target], sp - count + 1, count * sizeof(Value)); + sp -= count; + break; + } + case ByteCodeInstruction::kStoreExtendedGlobal: { + int count = READ8(); + int target = POP().fSigned; + SkASSERT(target + count <= (int) fGlobals.size()); + memcpy(&fGlobals[target], sp - count + 1, count * sizeof(Value)); + sp -= count; + break; + } + case ByteCodeInstruction::kStoreSwizzle: { int target = READ8(); int count = READ8(); @@ -544,6 +614,24 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe ip += count; break; } + case ByteCodeInstruction::kStoreSwizzleIndirect: { + int target = POP().fSigned; + int count = READ8(); + for (int i = count - 1; i >= 0; --i) { + stack[target + *(ip + i)] = POP(); + } + ip += count; + break; + } + case ByteCodeInstruction::kStoreSwizzleIndirectGlobal: { + int target = POP().fSigned; + int count = READ8(); + for (int i = count - 1; i >= 0; --i) { + fGlobals[target + *(ip + i)] = POP(); + } + ip += count; + break; + } VECTOR_BINARY_OP(kSubtractI, fSigned, -) VECTOR_BINARY_OP(kSubtractF, fFloat, -) diff --git a/tests/SkSLInterpreterTest.cpp b/tests/SkSLInterpreterTest.cpp index 2bcd82946e..26db0bc148 100644 --- a/tests/SkSLInterpreterTest.cpp +++ b/tests/SkSLInterpreterTest.cpp @@ -348,6 +348,144 @@ DEF_TEST(SkSLInterpreterSetInputs, r) { REPORTER_ASSERT(r, out == 5.0f); } +DEF_TEST(SkSLInterpreterCompound, r) { + struct RectAndColor { SkIRect fRect; SkColor4f fColor; }; + struct ManyRects { int fNumRects; RectAndColor fRects[4]; }; + + const char* src = + // Some struct definitions + "struct Point { int x; int y; };\n" + "struct Rect { Point p0; Point p1; };\n" + "struct RectAndColor { Rect r; float4 color; };\n" + + // Structs as globals, parameters, return values + "RectAndColor temp;\n" + "int rect_height(Rect r) { return r.p1.y - r.p0.y; }\n" + "RectAndColor make_blue_rect(int w, int h) {\n" + " temp.r.p0.x = temp.r.p0.y = 0;\n" + " temp.r.p1.x = w; temp.r.p1.y = h;\n" + " temp.color = float4(0, 1, 0, 1);\n" + " return temp;\n" + "}\n" + + // Initialization and assignment of types larger than 4 slots + "RectAndColor init_big(RectAndColor r) { RectAndColor s = r; return s; }\n" + "RectAndColor copy_big(RectAndColor r) { RectAndColor s; s = r; return s; }\n" + + // Same for arrays, including some non-constant indexing + "float tempFloats[8];\n" + "int median(int a[15]) { return a[7]; }\n" + "float[8] sums(float a[8]) {\n" + " float tempFloats[8];\n" + " tempFloats[0] = a[0];\n" + " for (int i = 1; i < 8; ++i) { tempFloats[i] = tempFloats[i - 1] + a[i]; }\n" + " return tempFloats;\n" + "}\n" + + // Uniforms, array-of-structs, dynamic indices + "in uniform Rect gRects[4];\n" + "Rect get_rect(int i) { return gRects[i]; }\n" + + // Kitchen sink (swizzles, inout, SoAoS) + "struct ManyRects { int numRects; RectAndColor rects[4]; };\n" + "void fill_rects(inout ManyRects mr) {\n" + " for (int i = 0; i < mr.numRects; ++i) {\n" + " mr.rects[i].r = gRects[i];\n" + " float b = mr.rects[i].r.p1.y;\n" + " mr.rects[i].color = float4(b, b, b, b);\n" + " }\n" + "}\n"; + + SkSL::Compiler compiler; + SkSL::Program::Settings settings; + std::unique_ptr program = compiler.convertProgram( + SkSL::Program::kGeneric_Kind, + SkSL::String(src), settings); + REPORTER_ASSERT(r, program); + + std::unique_ptr byteCode = compiler.toByteCode(*program); + REPORTER_ASSERT(r, !compiler.errorCount()); + + auto rect_height = byteCode->getFunction("rect_height"), + make_blue_rect = byteCode->getFunction("make_blue_rect"), + median = byteCode->getFunction("median"), + sums = byteCode->getFunction("sums"), + get_rect = byteCode->getFunction("get_rect"), + fill_rects = byteCode->getFunction("fill_rects"); + + SkIRect gRects[4] = { { 1,2,3,4 }, { 5,6,7,8 }, { 9,10,11,12 }, { 13,14,15,16 } }; + + SkSL::Interpreter interpreter(std::move(program), std::move(byteCode), + (SkSL::Interpreter::Value*)gRects); + + { + SkIRect in = SkIRect::MakeXYWH(10, 10, 20, 30); + int out = 0; + interpreter.run(*rect_height, + (SkSL::Interpreter::Value*)&in, + (SkSL::Interpreter::Value*)&out); + REPORTER_ASSERT(r, out == 30); + } + + { + int in[2] = { 15, 25 }; + RectAndColor out; + interpreter.run(*make_blue_rect, + (SkSL::Interpreter::Value*)in, + (SkSL::Interpreter::Value*)&out); + REPORTER_ASSERT(r, out.fRect.width() == 15); + REPORTER_ASSERT(r, out.fRect.height() == 25); + SkColor4f blue = { 0.0f, 1.0f, 0.0f, 1.0f }; + REPORTER_ASSERT(r, out.fColor == blue); + } + + { + int in[15] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; + int out = 0; + interpreter.run(*median, + (SkSL::Interpreter::Value*)in, + (SkSL::Interpreter::Value*)&out); + REPORTER_ASSERT(r, out == 8); + } + + { + float in[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + float out[8] = { 0 }; + interpreter.run(*sums, + (SkSL::Interpreter::Value*)in, + (SkSL::Interpreter::Value*)out); + for (int i = 0; i < 8; ++i) { + REPORTER_ASSERT(r, out[i] == static_cast((i + 1) * (i + 2) / 2)); + } + } + + { + int in = 2; + SkIRect out = SkIRect::MakeEmpty(); + interpreter.run(*get_rect, + (SkSL::Interpreter::Value*)&in, + (SkSL::Interpreter::Value*)&out); + REPORTER_ASSERT(r, out == gRects[2]); + } + + { + ManyRects in; + memset(&in, 0, sizeof(in)); + in.fNumRects = 2; + interpreter.run(*fill_rects, + (SkSL::Interpreter::Value*)&in, + nullptr); + ManyRects expected; + memset(&expected, 0, sizeof(expected)); + expected.fNumRects = 2; + for (int i = 0; i < 2; ++i) { + expected.fRects[i].fRect = gRects[i]; + float c = gRects[i].fBottom; + expected.fRects[i].fColor = { c, c, c, c }; + } + REPORTER_ASSERT(r, memcmp(&in, &expected, sizeof(in)) == 0); + } +} DEF_TEST(SkSLInterpreterFunctions, r) { const char* src =