/* * Copyright 2018 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SKSL_STANDALONE #include "SkSLInterpreter.h" #include "ir/SkSLBinaryExpression.h" #include "ir/SkSLExpressionStatement.h" #include "ir/SkSLForStatement.h" #include "ir/SkSLFunctionCall.h" #include "ir/SkSLFunctionReference.h" #include "ir/SkSLIfStatement.h" #include "ir/SkSLIndexExpression.h" #include "ir/SkSLPostfixExpression.h" #include "ir/SkSLPrefixExpression.h" #include "ir/SkSLProgram.h" #include "ir/SkSLStatement.h" #include "ir/SkSLTernaryExpression.h" #include "ir/SkSLVarDeclarations.h" #include "ir/SkSLVarDeclarationsStatement.h" #include "ir/SkSLVariableReference.h" #include "SkRasterPipeline.h" #include "../jumper/SkJumper.h" namespace SkSL { void Interpreter::run() { for (const auto& e : *fProgram) { if (ProgramElement::kFunction_Kind == e.fKind) { const FunctionDefinition& f = (const FunctionDefinition&) e; if ("appendStages" == f.fDeclaration.fName) { this->run(f); return; } } } SkASSERT(false); } static int SizeOf(const Type& type) { return 1; } void Interpreter::run(const FunctionDefinition& f) { fVars.emplace_back(); StackIndex current = (StackIndex) fStack.size(); for (int i = f.fDeclaration.fParameters.size() - 1; i >= 0; --i) { current -= SizeOf(f.fDeclaration.fParameters[i]->fType); fVars.back()[f.fDeclaration.fParameters[i]] = current; } fCurrentIndex.push_back({ f.fBody.get(), 0 }); while (fCurrentIndex.size()) { this->runStatement(); } } void Interpreter::push(Value value) { fStack.push_back(value); } Interpreter::Value Interpreter::pop() { auto iter = fStack.end() - 1; Value result = *iter; fStack.erase(iter); return result; } Interpreter::StackIndex Interpreter::stackAlloc(int count) { int result = fStack.size(); for (int i = 0; i < count; ++i) { fStack.push_back(Value((int) 0xDEADBEEF)); } return result; } void Interpreter::runStatement() { const Statement& stmt = *fCurrentIndex.back().fStatement; const size_t index = fCurrentIndex.back().fIndex; fCurrentIndex.pop_back(); switch (stmt.fKind) { case Statement::kBlock_Kind: { const Block& b = (const Block&) stmt; if (!b.fStatements.size()) { break; } SkASSERT(index < b.fStatements.size()); if (index < b.fStatements.size() - 1) { fCurrentIndex.push_back({ &b, index + 1 }); } fCurrentIndex.push_back({ b.fStatements[index].get(), 0 }); break; } case Statement::kBreak_Kind: SkASSERT(index == 0); abort(); case Statement::kContinue_Kind: SkASSERT(index == 0); abort(); case Statement::kDiscard_Kind: SkASSERT(index == 0); abort(); case Statement::kDo_Kind: abort(); case Statement::kExpression_Kind: SkASSERT(index == 0); this->evaluate(*((const ExpressionStatement&) stmt).fExpression); break; case Statement::kFor_Kind: { ForStatement& f = (ForStatement&) stmt; switch (index) { case 0: // initializer fCurrentIndex.push_back({ &f, 1 }); if (f.fInitializer) { fCurrentIndex.push_back({ f.fInitializer.get(), 0 }); } break; case 1: // test & body if (f.fTest && !evaluate(*f.fTest).fBool) { break; } else { fCurrentIndex.push_back({ &f, 2 }); fCurrentIndex.push_back({ f.fStatement.get(), 0 }); } break; case 2: // next if (f.fNext) { this->evaluate(*f.fNext); } fCurrentIndex.push_back({ &f, 1 }); break; default: SkASSERT(false); } break; } case Statement::kGroup_Kind: abort(); case Statement::kIf_Kind: { IfStatement& i = (IfStatement&) stmt; if (evaluate(*i.fTest).fBool) { fCurrentIndex.push_back({ i.fIfTrue.get(), 0 }); } else if (i.fIfFalse) { fCurrentIndex.push_back({ i.fIfFalse.get(), 0 }); } break; } case Statement::kNop_Kind: SkASSERT(index == 0); break; case Statement::kReturn_Kind: SkASSERT(index == 0); abort(); case Statement::kSwitch_Kind: abort(); case Statement::kVarDeclarations_Kind: SkASSERT(index == 0); for (const auto& decl :((const VarDeclarationsStatement&) stmt).fDeclaration->fVars) { const Variable* var = ((VarDeclaration&) *decl).fVar; StackIndex pos = this->stackAlloc(SizeOf(var->fType)); fVars.back()[var] = pos; if (var->fInitialValue) { fStack[pos] = this->evaluate(*var->fInitialValue); } } break; case Statement::kWhile_Kind: abort(); default: abort(); } } static Interpreter::TypeKind type_kind(const Type& type) { if (type.fName == "int") { return Interpreter::kInt_TypeKind; } else if (type.fName == "float") { return Interpreter::kFloat_TypeKind; } ABORT("unsupported type: %s\n", type.description().c_str()); } Interpreter::StackIndex Interpreter::getLValue(const Expression& expr) { switch (expr.fKind) { case Expression::kFieldAccess_Kind: break; case Expression::kIndex_Kind: { const IndexExpression& idx = (const IndexExpression&) expr; return this->evaluate(*idx.fBase).fInt + this->evaluate(*idx.fIndex).fInt; } case Expression::kSwizzle_Kind: break; case Expression::kVariableReference_Kind: SkASSERT(fVars.size()); SkASSERT(fVars.back().find(&((VariableReference&) expr).fVariable) != fVars.back().end()); return fVars.back()[&((VariableReference&) expr).fVariable]; case Expression::kTernary_Kind: { const TernaryExpression& t = (const TernaryExpression&) expr; return this->getLValue(this->evaluate(*t.fTest).fBool ? *t.fIfTrue : *t.fIfFalse); } case Expression::kTypeReference_Kind: break; default: break; } ABORT("unsupported lvalue"); } struct CallbackCtx : public SkJumper_CallbackCtx { Interpreter* fInterpreter; const FunctionDefinition* fFunction; }; static void do_callback(SkJumper_CallbackCtx* raw, int activePixels) { CallbackCtx& ctx = (CallbackCtx&) *raw; for (int i = 0; i < activePixels; ++i) { ctx.fInterpreter->push(Interpreter::Value(ctx.rgba[i * 4 + 0])); ctx.fInterpreter->push(Interpreter::Value(ctx.rgba[i * 4 + 1])); ctx.fInterpreter->push(Interpreter::Value(ctx.rgba[i * 4 + 2])); ctx.fInterpreter->run(*ctx.fFunction); ctx.read_from[i * 4 + 2] = ctx.fInterpreter->pop().fFloat; ctx.read_from[i * 4 + 1] = ctx.fInterpreter->pop().fFloat; ctx.read_from[i * 4 + 0] = ctx.fInterpreter->pop().fFloat; } } void Interpreter::appendStage(const AppendStage& a) { switch (a.fStage) { case SkRasterPipeline::matrix_4x5: { SkASSERT(a.fArguments.size() == 1); StackIndex transpose = evaluate(*a.fArguments[0]).fInt; fPipeline.append(SkRasterPipeline::matrix_4x5, &fStack[transpose]); break; } case SkRasterPipeline::callback: { SkASSERT(a.fArguments.size() == 1); CallbackCtx* ctx = new CallbackCtx(); ctx->fInterpreter = this; ctx->fn = do_callback; for (const auto& e : *fProgram) { if (ProgramElement::kFunction_Kind == e.fKind) { const FunctionDefinition& f = (const FunctionDefinition&) e; if (&f.fDeclaration == ((const FunctionReference&) *a.fArguments[0]).fFunctions[0]) { ctx->fFunction = &f; } } } fPipeline.append(SkRasterPipeline::callback, ctx); break; } default: fPipeline.append(a.fStage); } } Interpreter::Value Interpreter::call(const FunctionCall& c) { abort(); } Interpreter::Value Interpreter::evaluate(const Expression& expr) { switch (expr.fKind) { case Expression::kAppendStage_Kind: this->appendStage((const AppendStage&) expr); return Value((int) 0xDEADBEEF); case Expression::kBinary_Kind: { #define ARITHMETIC(op) { \ Value left = this->evaluate(*b.fLeft); \ Value right = this->evaluate(*b.fRight); \ switch (type_kind(b.fLeft->fType)) { \ case kFloat_TypeKind: \ return Value(left.fFloat op right.fFloat); \ case kInt_TypeKind: \ return Value(left.fInt op right.fInt); \ default: \ abort(); \ } \ } #define BITWISE(op) { \ Value left = this->evaluate(*b.fLeft); \ Value right = this->evaluate(*b.fRight); \ switch (type_kind(b.fLeft->fType)) { \ case kInt_TypeKind: \ return Value(left.fInt op right.fInt); \ default: \ abort(); \ } \ } #define LOGIC(op) { \ Value left = this->evaluate(*b.fLeft); \ Value right = this->evaluate(*b.fRight); \ switch (type_kind(b.fLeft->fType)) { \ case kFloat_TypeKind: \ return Value(left.fFloat op right.fFloat); \ case kInt_TypeKind: \ return Value(left.fInt op right.fInt); \ default: \ abort(); \ } \ } #define COMPOUND_ARITHMETIC(op) { \ StackIndex left = this->getLValue(*b.fLeft); \ Value right = this->evaluate(*b.fRight); \ Value result = fStack[left]; \ switch (type_kind(b.fLeft->fType)) { \ case kFloat_TypeKind: \ result.fFloat op right.fFloat; \ break; \ case kInt_TypeKind: \ result.fInt op right.fInt; \ break; \ default: \ abort(); \ } \ fStack[left] = result; \ return result; \ } #define COMPOUND_BITWISE(op) { \ StackIndex left = this->getLValue(*b.fLeft); \ Value right = this->evaluate(*b.fRight); \ Value result = fStack[left]; \ switch (type_kind(b.fLeft->fType)) { \ case kInt_TypeKind: \ result.fInt op right.fInt; \ break; \ default: \ abort(); \ } \ fStack[left] = result; \ return result; \ } const BinaryExpression& b = (const BinaryExpression&) expr; switch (b.fOperator) { case Token::PLUS: ARITHMETIC(+) case Token::MINUS: ARITHMETIC(-) case Token::STAR: ARITHMETIC(*) case Token::SLASH: ARITHMETIC(/) case Token::BITWISEAND: BITWISE(&) case Token::BITWISEOR: BITWISE(|) case Token::BITWISEXOR: BITWISE(^) case Token::LT: LOGIC(<) case Token::GT: LOGIC(>) case Token::LTEQ: LOGIC(<=) case Token::GTEQ: LOGIC(>=) case Token::LOGICALAND: { Value result = this->evaluate(*b.fLeft); if (result.fBool) { result = this->evaluate(*b.fRight); } return result; } case Token::LOGICALOR: { Value result = this->evaluate(*b.fLeft); if (!result.fBool) { result = this->evaluate(*b.fRight); } return result; } case Token::EQ: { StackIndex left = this->getLValue(*b.fLeft); Value right = this->evaluate(*b.fRight); fStack[left] = right; return right; } case Token::PLUSEQ: COMPOUND_ARITHMETIC(+=) case Token::MINUSEQ: COMPOUND_ARITHMETIC(-=) case Token::STAREQ: COMPOUND_ARITHMETIC(*=) case Token::SLASHEQ: COMPOUND_ARITHMETIC(/=) case Token::BITWISEANDEQ: COMPOUND_BITWISE(&=) case Token::BITWISEOREQ: COMPOUND_BITWISE(|=) case Token::BITWISEXOREQ: COMPOUND_BITWISE(^=) default: ABORT("unsupported operator: %s\n", expr.description().c_str()); } break; } case Expression::kBoolLiteral_Kind: return Value(((const BoolLiteral&) expr).fValue); case Expression::kConstructor_Kind: break; case Expression::kIntLiteral_Kind: return Value((int) ((const IntLiteral&) expr).fValue); case Expression::kFieldAccess_Kind: break; case Expression::kFloatLiteral_Kind: return Value((float) ((const FloatLiteral&) expr).fValue); case Expression::kFunctionCall_Kind: return this->call((const FunctionCall&) expr); case Expression::kIndex_Kind: { const IndexExpression& idx = (const IndexExpression&) expr; StackIndex pos = this->evaluate(*idx.fBase).fInt + this->evaluate(*idx.fIndex).fInt; return fStack[pos]; } case Expression::kPrefix_Kind: { const PrefixExpression& p = (const PrefixExpression&) expr; switch (p.fOperator) { case Token::MINUS: { Value base = this->evaluate(*p.fOperand); switch (type_kind(p.fType)) { case kFloat_TypeKind: return Value(-base.fFloat); case kInt_TypeKind: return Value(-base.fInt); default: abort(); } } case Token::LOGICALNOT: { Value base = this->evaluate(*p.fOperand); return Value(!base.fBool); } default: abort(); } } case Expression::kPostfix_Kind: { const PostfixExpression& p = (const PostfixExpression&) expr; StackIndex lvalue = this->getLValue(*p.fOperand); Value result = fStack[lvalue]; switch (type_kind(p.fType)) { case kFloat_TypeKind: if (Token::PLUSPLUS == p.fOperator) { ++fStack[lvalue].fFloat; } else { SkASSERT(Token::MINUSMINUS == p.fOperator); --fStack[lvalue].fFloat; } break; case kInt_TypeKind: if (Token::PLUSPLUS == p.fOperator) { ++fStack[lvalue].fInt; } else { SkASSERT(Token::MINUSMINUS == p.fOperator); --fStack[lvalue].fInt; } break; default: abort(); } return result; } case Expression::kSetting_Kind: break; case Expression::kSwizzle_Kind: break; case Expression::kVariableReference_Kind: SkASSERT(fVars.size()); SkASSERT(fVars.back().find(&((VariableReference&) expr).fVariable) != fVars.back().end()); return fStack[fVars.back()[&((VariableReference&) expr).fVariable]]; case Expression::kTernary_Kind: { const TernaryExpression& t = (const TernaryExpression&) expr; return this->evaluate(this->evaluate(*t.fTest).fBool ? *t.fIfTrue : *t.fIfFalse); } case Expression::kTypeReference_Kind: break; default: break; } ABORT("unsupported expression: %s\n", expr.description().c_str()); } } // namespace #endif