| /* |
| * 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->fElements) { |
| if (ProgramElement::kFunction_Kind == e->fKind) { |
| const FunctionDefinition& f = (const FunctionDefinition&) *e; |
| if ("appendStages" == f.fDeclaration.fName) { |
| this->run(f); |
| return; |
| } |
| } |
| } |
| ASSERT(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; |
| } |
| ASSERT(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: |
| ASSERT(index == 0); |
| abort(); |
| case Statement::kContinue_Kind: |
| ASSERT(index == 0); |
| abort(); |
| case Statement::kDiscard_Kind: |
| ASSERT(index == 0); |
| abort(); |
| case Statement::kDo_Kind: |
| abort(); |
| case Statement::kExpression_Kind: |
| ASSERT(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: |
| ASSERT(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: |
| ASSERT(index == 0); |
| break; |
| case Statement::kReturn_Kind: |
| ASSERT(index == 0); |
| abort(); |
| case Statement::kSwitch_Kind: |
| abort(); |
| case Statement::kVarDeclarations_Kind: |
| ASSERT(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: |
| ASSERT(fVars.size()); |
| ASSERT(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: { |
| ASSERT(a.fArguments.size() == 1); |
| StackIndex transpose = evaluate(*a.fArguments[0]).fInt; |
| fPipeline.append(SkRasterPipeline::matrix_4x5, &fStack[transpose]); |
| break; |
| } |
| case SkRasterPipeline::callback: { |
| ASSERT(a.fArguments.size() == 1); |
| CallbackCtx* ctx = new CallbackCtx(); |
| ctx->fInterpreter = this; |
| ctx->fn = do_callback; |
| for (const auto& e : fProgram->fElements) { |
| 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 { |
| ASSERT(Token::MINUSMINUS == p.fOperator); |
| --fStack[lvalue].fFloat; |
| } |
| break; |
| case kInt_TypeKind: |
| if (Token::PLUSPLUS == p.fOperator) { |
| ++fStack[lvalue].fInt; |
| } else { |
| ASSERT(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: |
| ASSERT(fVars.size()); |
| ASSERT(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 |