SkSL interpreter intrinsics

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>
This commit is contained in:
Ethan Nicholas 2019-05-21 16:05:08 -04:00 committed by Skia Commit-Bot
parent 201491e734
commit 82162eead5
5 changed files with 122 additions and 32 deletions

View File

@ -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

View File

@ -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);
}

View File

@ -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<LValue> 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<String, ByteCodeInstruction> fIntrinsics;
friend class DeferredLocation;
friend class ByteCodeVariableLValue;
friend class ByteCodeSwizzleLValue;

View File

@ -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");

View File

@ -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);
}