diff --git a/src/sksl/SkSLByteCode.h b/src/sksl/SkSLByteCode.h index b28fd57fbe..852b4772ff 100644 --- a/src/sksl/SkSLByteCode.h +++ b/src/sksl/SkSLByteCode.h @@ -50,6 +50,10 @@ enum class ByteCodeInstruction : uint16_t { VECTOR(kCompareULTEQ), // Followed by a 16 bit address kConditionalBranch, + VECTOR(kConvertFtoI), + VECTOR(kConvertStoF), + VECTOR(kConvertUtoF), + VECTOR(kCos), // Pops and prints the top value from the stack kDebugPrint, VECTOR(kDivideF), @@ -57,9 +61,6 @@ enum class ByteCodeInstruction : uint16_t { VECTOR(kDivideU), // Duplicates the top stack value VECTOR(kDup), - VECTOR(kFloatToInt), - VECTOR(kSignedToFloat), - VECTOR(kUnsignedToFloat), // All kLoad* are followed by a byte indicating the local/global slot to load VECTOR(kLoad), VECTOR(kLoadGlobal), @@ -83,6 +84,8 @@ enum class ByteCodeInstruction : uint16_t { VECTOR(kRemainderU), // Followed by a byte indicating the number of slots being returned kReturn, + VECTOR(kSin), + VECTOR(kSqrt), // All kStore* are followed by a byte indicating the local/global slot to store VECTOR(kStore), VECTOR(kStoreGlobal), @@ -97,6 +100,7 @@ enum class ByteCodeInstruction : uint16_t { kSwizzle, VECTOR(kSubtractF), VECTOR(kSubtractI), + VECTOR(kTan), VECTOR(kXorB), VECTOR(kXorI), // Followed by a byte indicating external value to write diff --git a/src/sksl/SkSLByteCodeGenerator.cpp b/src/sksl/SkSLByteCodeGenerator.cpp index e213594ed7..b53fe47774 100644 --- a/src/sksl/SkSLByteCodeGenerator.cpp +++ b/src/sksl/SkSLByteCodeGenerator.cpp @@ -10,6 +10,17 @@ namespace SkSL { +ByteCodeGenerator::ByteCodeGenerator(const Context* context, const Program* program, ErrorReporter* errors, + ByteCode* output) + : INHERITED(program, errors, nullptr) + , fContext(*context) + , fOutput(output) { + fIntrinsics["cos"] = ByteCodeInstruction::kCos; + fIntrinsics["sin"] = ByteCodeInstruction::kSin; + fIntrinsics["sqrt"] = ByteCodeInstruction::kSqrt; + fIntrinsics["tan"] = ByteCodeInstruction::kTan; +} + static int slot_count(const Type& type) { return type.columns() * type.rows(); } @@ -331,15 +342,15 @@ void ByteCodeGenerator::writeConstructor(const Constructor& c) { if (inCategory == TypeCategory::kFloat) { SkASSERT(outCategory == TypeCategory::kSigned || outCategory == TypeCategory::kUnsigned); - this->write(vector_instruction(ByteCodeInstruction::kFloatToInt, + this->write(vector_instruction(ByteCodeInstruction::kConvertFtoI, c.fType.columns())); } else if (outCategory == TypeCategory::kFloat) { if (inCategory == TypeCategory::kSigned) { - this->write(vector_instruction(ByteCodeInstruction::kSignedToFloat, + this->write(vector_instruction(ByteCodeInstruction::kConvertStoF, c.fType.columns())); } else { SkASSERT(inCategory == TypeCategory::kUnsigned); - this->write(vector_instruction(ByteCodeInstruction::kUnsignedToFloat, + this->write(vector_instruction(ByteCodeInstruction::kConvertUtoF, c.fType.columns())); } } else { @@ -384,7 +395,31 @@ void ByteCodeGenerator::writeFloatLiteral(const FloatLiteral& f) { this->write32(Interpreter::Value((float) f.fValue).fUnsigned); } +void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) { + auto found = fIntrinsics.find(c.fFunction.fName); + if (found == fIntrinsics.end()) { + fErrors.error(c.fOffset, "unsupported intrinsic function"); + return; + } + switch (found->second) { + case ByteCodeInstruction::kCos: // fall through + case ByteCodeInstruction::kSin: // fall through + case ByteCodeInstruction::kSqrt: // fall through + case ByteCodeInstruction::kTan: + SkASSERT(c.fArguments.size() == 1); + this->write((ByteCodeInstruction) ((int) found->second + + slot_count(c.fArguments[0]->fType) - 1)); + break; + default: + SkASSERT(false); + } +} + void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) { + if (f.fFunction.fBuiltin) { + this->writeIntrinsicCall(f); + return; + } for (const auto& arg : f.fArguments) { this->writeExpression(*arg); } diff --git a/src/sksl/SkSLByteCodeGenerator.h b/src/sksl/SkSLByteCodeGenerator.h index 0eac73a7dd..3a2306c6ae 100644 --- a/src/sksl/SkSLByteCodeGenerator.h +++ b/src/sksl/SkSLByteCodeGenerator.h @@ -78,10 +78,7 @@ public: }; ByteCodeGenerator(const Context* context, const Program* program, ErrorReporter* errors, - ByteCode* output) - : INHERITED(program, errors, nullptr) - , fContext(*context) - , fOutput(output) {} + ByteCode* output); bool generateCode() override; @@ -188,6 +185,8 @@ private: */ std::unique_ptr getLValue(const Expression& expr); + void writeIntrinsicCall(const FunctionCall& c); + void writeFunctionCall(const FunctionCall& c); void writeConstructor(const Constructor& c); @@ -266,6 +265,8 @@ private: int fParameterCount; + std::unordered_map fIntrinsics; + friend class DeferredLocation; friend class ByteCodeVariableLValue; friend class ByteCodeSwizzleLValue; diff --git a/src/sksl/SkSLInterpreter.cpp b/src/sksl/SkSLInterpreter.cpp index 234a14334a..9118c97d64 100644 --- a/src/sksl/SkSLInterpreter.cpp +++ b/src/sksl/SkSLInterpreter.cpp @@ -128,12 +128,15 @@ void Interpreter::disassemble(const ByteCodeFunction& f) { case ByteCodeInstruction::kConditionalBranch: printf("conditionalbranch %d", READ16()); break; + VECTOR_DISASSEMBLE(kConvertFtoI, "convertftoi") + VECTOR_DISASSEMBLE(kConvertStoF, "convertstof") + VECTOR_DISASSEMBLE(kConvertUtoF, "convertutof") + VECTOR_DISASSEMBLE(kCos, "cos") case ByteCodeInstruction::kDebugPrint: printf("debugprint"); break; VECTOR_DISASSEMBLE(kDivideF, "dividef") VECTOR_DISASSEMBLE(kDivideS, "divideS") VECTOR_DISASSEMBLE(kDivideU, "divideu") VECTOR_DISASSEMBLE(kDup, "dup") - VECTOR_DISASSEMBLE(kFloatToInt, "floattoint") case ByteCodeInstruction::kLoad: printf("load %d", READ8()); break; case ByteCodeInstruction::kLoad2: printf("load2 %d", READ8()); break; case ByteCodeInstruction::kLoad3: printf("load3 %d", READ8()); break; @@ -182,7 +185,8 @@ void Interpreter::disassemble(const ByteCodeFunction& f) { VECTOR_DISASSEMBLE(kRemainderS, "remainders") VECTOR_DISASSEMBLE(kRemainderU, "remainderu") case ByteCodeInstruction::kReturn: printf("return %d", READ8()); break; - VECTOR_DISASSEMBLE(kSignedToFloat, "signedtofloat") + VECTOR_DISASSEMBLE(kSin, "sin") + VECTOR_DISASSEMBLE(kSqrt, "sqrt") case ByteCodeInstruction::kStore: printf("store %d", READ8()); break; case ByteCodeInstruction::kStore2: printf("store2 %d", READ8()); break; case ByteCodeInstruction::kStore3: printf("store3 %d", READ8()); break; @@ -220,7 +224,7 @@ void Interpreter::disassemble(const ByteCodeFunction& f) { } break; } - VECTOR_DISASSEMBLE(kUnsignedToFloat, "unsignedtofloat") + VECTOR_DISASSEMBLE(kTan, "tan") case ByteCodeInstruction::kWriteExternal: printf("writeexternal %d", READ8()); break; case ByteCodeInstruction::kWriteExternal2: printf("writeexternal2 %d", READ8()); break; case ByteCodeInstruction::kWriteExternal3: printf("writeexternal3 %d", READ8()); break; @@ -275,6 +279,13 @@ void Interpreter::disassemble(const ByteCodeFunction& f) { break; \ } +#define VECTOR_UNARY_FN(base, fn, field) \ + case ByteCodeInstruction::base ## 4: sp[-3].field = fn(sp[-3].field); \ + case ByteCodeInstruction::base ## 3: sp[-2].field = fn(sp[-2].field); \ + case ByteCodeInstruction::base ## 2: sp[-1].field = fn(sp[-1].field); \ + case ByteCodeInstruction::base: sp[ 0].field = fn(sp[ 0].field); \ + break; + struct StackFrame { const uint8_t* fCode; const uint8_t* fIP; @@ -299,9 +310,11 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe switch (inst) { VECTOR_BINARY_OP(kAddI, fSigned, +) VECTOR_BINARY_OP(kAddF, fFloat, +) + case ByteCodeInstruction::kBranch: ip = code + READ16(); break; + case ByteCodeInstruction::kCall: { // Precursor code has pushed all parameters to the stack. Update our bottom of // stack to point at the first parameter, and our sp to point past those parameters @@ -314,6 +327,7 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe sp = stack + fun->fParameterCount + fun->fLocalCount - 1; break; } + case ByteCodeInstruction::kCallExternal: { int argumentCount = READ8(); int returnCount = READ8(); @@ -328,6 +342,7 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe sp += returnCount - 1; break; } + VECTOR_BINARY_OP(kCompareIEQ, fSigned, ==) VECTOR_BINARY_OP(kCompareFEQ, fFloat, ==) VECTOR_BINARY_OP(kCompareINEQ, fSigned, !=) @@ -344,6 +359,7 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe VECTOR_BINARY_OP(kCompareSLTEQ, fSigned, <=) VECTOR_BINARY_OP(kCompareULTEQ, fUnsigned, <=) VECTOR_BINARY_OP(kCompareFLTEQ, fFloat, <=) + case ByteCodeInstruction::kConditionalBranch: { int target = READ16(); if (POP().fBool) { @@ -351,11 +367,33 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe } break; } + + case ByteCodeInstruction::kConvertFtoI4: sp[-3].fSigned = (int)sp[-3].fFloat; + case ByteCodeInstruction::kConvertFtoI3: sp[-2].fSigned = (int)sp[-2].fFloat; + case ByteCodeInstruction::kConvertFtoI2: sp[-1].fSigned = (int)sp[-1].fFloat; + case ByteCodeInstruction::kConvertFtoI: sp[ 0].fSigned = (int)sp[ 0].fFloat; + break; + + case ByteCodeInstruction::kConvertStoF4: sp[-3].fFloat = sp[-3].fSigned; + case ByteCodeInstruction::kConvertStoF3: sp[-2].fFloat = sp[-2].fSigned; + case ByteCodeInstruction::kConvertStoF2: sp[-1].fFloat = sp[-1].fSigned; + case ByteCodeInstruction::kConvertStoF : sp[ 0].fFloat = sp[ 0].fSigned; + break; + + case ByteCodeInstruction::kConvertUtoF4: sp[-3].fFloat = sp[-3].fUnsigned; + case ByteCodeInstruction::kConvertUtoF3: sp[-2].fFloat = sp[-2].fUnsigned; + case ByteCodeInstruction::kConvertUtoF2: sp[-1].fFloat = sp[-1].fUnsigned; + case ByteCodeInstruction::kConvertUtoF : sp[ 0].fFloat = sp[ 0].fUnsigned; + break; + + VECTOR_UNARY_FN(kCos, cos, fFloat) + case ByteCodeInstruction::kDebugPrint: { Value v = POP(); printf("Debug: %d(int), %d(uint), %f(float)\n", v.fSigned, v.fUnsigned, v.fFloat); break; } + VECTOR_BINARY_OP(kDivideS, fSigned, /) VECTOR_BINARY_OP(kDivideU, fUnsigned, /) VECTOR_BINARY_OP(kDivideF, fFloat, /) @@ -366,24 +404,6 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe case ByteCodeInstruction::kDup : PUSH(sp[(int)ByteCodeInstruction::kDup - (int)inst]); break; - case ByteCodeInstruction::kFloatToInt4: sp[-3].fSigned = (int)sp[-3].fFloat; - case ByteCodeInstruction::kFloatToInt3: sp[-2].fSigned = (int)sp[-2].fFloat; - case ByteCodeInstruction::kFloatToInt2: sp[-1].fSigned = (int)sp[-1].fFloat; - case ByteCodeInstruction::kFloatToInt: sp[ 0].fSigned = (int)sp[ 0].fFloat; - break; - - case ByteCodeInstruction::kSignedToFloat4: sp[-3].fFloat = sp[-3].fSigned; - case ByteCodeInstruction::kSignedToFloat3: sp[-2].fFloat = sp[-2].fSigned; - case ByteCodeInstruction::kSignedToFloat2: sp[-1].fFloat = sp[-1].fSigned; - case ByteCodeInstruction::kSignedToFloat : sp[ 0].fFloat = sp[ 0].fSigned; - break; - - case ByteCodeInstruction::kUnsignedToFloat4: sp[-3].fFloat = sp[-3].fUnsigned; - case ByteCodeInstruction::kUnsignedToFloat3: sp[-2].fFloat = sp[-2].fUnsigned; - case ByteCodeInstruction::kUnsignedToFloat2: sp[-1].fFloat = sp[-1].fUnsigned; - case ByteCodeInstruction::kUnsignedToFloat : sp[ 0].fFloat = sp[ 0].fUnsigned; - 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]; @@ -409,6 +429,7 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe ip += count; break; } + case ByteCodeInstruction::kLoadSwizzleGlobal: { int src = READ8(); SkASSERT(src < (int) fGlobals.size()); @@ -419,8 +440,10 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe ip += count; break; } + VECTOR_BINARY_OP(kMultiplyI, fSigned, *) VECTOR_BINARY_OP(kMultiplyF, fFloat, *) + case ByteCodeInstruction::kNot: sp[0].fBool = !sp[0].fBool; break; @@ -446,6 +469,7 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe case ByteCodeInstruction::kPushImmediate: PUSH(READ32()); break; + case ByteCodeInstruction::kReadExternal: // fall through case ByteCodeInstruction::kReadExternal2: // fall through case ByteCodeInstruction::kReadExternal3: // fall through @@ -455,9 +479,11 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe sp += (int) inst - (int) ByteCodeInstruction::kReadExternal + 1; break; } + VECTOR_BINARY_FN(kRemainderF, fFloat, fmodf) VECTOR_BINARY_OP(kRemainderS, fSigned, %) VECTOR_BINARY_OP(kRemainderU, fUnsigned, %) + case ByteCodeInstruction::kReturn: { int count = READ8(); if (frames.empty()) { @@ -482,6 +508,9 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe } } + VECTOR_UNARY_FN(kSin, sin, fFloat) + VECTOR_UNARY_FN(kSqrt, sqrt, fFloat) + case ByteCodeInstruction::kStore4: stack[*ip + 3] = POP(); case ByteCodeInstruction::kStore3: stack[*ip + 2] = POP(); case ByteCodeInstruction::kStore2: stack[*ip + 1] = POP(); @@ -505,6 +534,7 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe ip += count; break; } + case ByteCodeInstruction::kStoreSwizzleGlobal: { int target = READ8(); int count = READ8(); @@ -514,8 +544,10 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe ip += count; break; } + VECTOR_BINARY_OP(kSubtractI, fSigned, -) VECTOR_BINARY_OP(kSubtractF, fFloat, -) + case ByteCodeInstruction::kSwizzle: { Value tmp[4]; for (int i = READ8() - 1; i >= 0; --i) { @@ -526,6 +558,9 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe } break; } + + VECTOR_UNARY_FN(kTan, tan, fFloat) + case ByteCodeInstruction::kWriteExternal: // fall through case ByteCodeInstruction::kWriteExternal2: // fall through case ByteCodeInstruction::kWriteExternal3: // fall through @@ -536,13 +571,14 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe sp -= count; break; } + default: SkDEBUGFAILF("unsupported instruction %d\n", (int) inst); } #ifdef TRACE int stackSize = (int) (sp - stack + 1); printf("STACK(%d):", stackSize); - for (int i = 0; i < stackSize(); ++i) { + for (int i = 0; i < stackSize; ++i) { printf(" %d(%f)", stack[i].fSigned, stack[i].fFloat); } printf("\n"); diff --git a/tests/SkSLInterpreterTest.cpp b/tests/SkSLInterpreterTest.cpp index 8fa9f63b27..6bcff4328d 100644 --- a/tests/SkSLInterpreterTest.cpp +++ b/tests/SkSLInterpreterTest.cpp @@ -701,3 +701,17 @@ DEF_TEST(SkSLInterpreterExternalValuesVectorCall, r) { printf("%s\n%s", src, compiler.errorText().c_str()); } } + +DEF_TEST(SkSLInterpreterIntrinsics, r) { + SkSL::Interpreter::Value value, expected; + + value = 0.0f; expected = 0.0f; + test(r, "float main(float x) { return sin(x); }", &value, 1, &expected); + test(r, "float main(float x) { return tan(x); }", &value, 1, &expected); + + value = 0.0f; expected = 1.0f; + test(r, "float main(float x) { return cos(x); }", &value, 1, &expected); + + value = 25.0f; expected = 5.0f; + test(r, "float main(float x) { return sqrt(x); }", &value, 1, &expected); +}