Skip to content

Commit

Permalink
SkSL interpreter intrinsics
Browse files Browse the repository at this point in the history
Bug: skia:
Change-Id: I418fb05444f9c1ee076ace41a24072c4a5e7ef6c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/214691
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
  • Loading branch information
Ethan Nicholas authored and Skia Commit-Bot committed May 21, 2019
1 parent 201491e commit 82162ee
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 32 deletions.
10 changes: 7 additions & 3 deletions src/sksl/SkSLByteCode.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,17 @@ 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),
VECTOR(kDivideS),
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),
Expand All @@ -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),
Expand All @@ -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
Expand Down
41 changes: 38 additions & 3 deletions src/sksl/SkSLByteCodeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
}
Expand Down
9 changes: 5 additions & 4 deletions src/sksl/SkSLByteCodeGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,7 @@ class ByteCodeGenerator : public CodeGenerator {
};

ByteCodeGenerator(const Context* context, const Program* program, ErrorReporter* errors,
ByteCode* output)
: INHERITED(program, errors, nullptr)
, fContext(*context)
, fOutput(output) {}
ByteCode* output);

bool generateCode() override;

Expand Down Expand Up @@ -188,6 +185,8 @@ class ByteCodeGenerator : public CodeGenerator {
*/
std::unique_ptr<LValue> getLValue(const Expression& expr);

void writeIntrinsicCall(const FunctionCall& c);

void writeFunctionCall(const FunctionCall& c);

void writeConstructor(const Constructor& c);
Expand Down Expand Up @@ -266,6 +265,8 @@ class ByteCodeGenerator : public CodeGenerator {

int fParameterCount;

std::unordered_map<String, ByteCodeInstruction> fIntrinsics;

friend class DeferredLocation;
friend class ByteCodeVariableLValue;
friend class ByteCodeSwizzleLValue;
Expand Down
80 changes: 58 additions & 22 deletions src/sksl/SkSLInterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -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();
Expand All @@ -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, !=)
Expand All @@ -344,18 +359,41 @@ 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) {
ip = code + target;
}
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, /)
Expand All @@ -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];
Expand All @@ -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());
Expand All @@ -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;
Expand All @@ -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
Expand All @@ -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()) {
Expand All @@ -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();
Expand All @@ -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();
Expand All @@ -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) {
Expand All @@ -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
Expand All @@ -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");
Expand Down
14 changes: 14 additions & 0 deletions tests/SkSLInterpreterTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

0 comments on commit 82162ee

Please sign in to comment.