Support larger compound types in the interpreter
Field access and array indexing are supported, including dynamic indices. Larger types (> 4 slots) can be used as lvalues, rvalues, etc. Change-Id: I9bb4ed850be4259c05c8952c6c0a17b71f813772 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/214443 Commit-Queue: Brian Osman <brianosman@google.com> Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
This commit is contained in:
parent
bd83231a3a
commit
07c117b6f8
@ -61,12 +61,18 @@ enum class ByteCodeInstruction : uint16_t {
|
|||||||
VECTOR(kDivideU),
|
VECTOR(kDivideU),
|
||||||
// Duplicates the top stack value
|
// Duplicates the top stack value
|
||||||
VECTOR(kDup),
|
VECTOR(kDup),
|
||||||
// All kLoad* are followed by a byte indicating the local/global slot to load
|
// Followed by count byte. Duplicates that many values
|
||||||
|
kDupN,
|
||||||
|
// kLoad/kLoadGlobal are followed by a byte indicating the local/global slot to load
|
||||||
VECTOR(kLoad),
|
VECTOR(kLoad),
|
||||||
VECTOR(kLoadGlobal),
|
VECTOR(kLoadGlobal),
|
||||||
// As above, then a count byte (1-4), and then one byte per swizzle component (0-3).
|
// As kLoad/kLoadGlobal, then a count byte (1-4), and then one byte per swizzle component (0-3).
|
||||||
kLoadSwizzle,
|
kLoadSwizzle,
|
||||||
kLoadSwizzleGlobal,
|
kLoadSwizzleGlobal,
|
||||||
|
// kLoadExtended* are fallback load ops when we lack a specialization. They are followed by a
|
||||||
|
// count byte, and get the slot to load from the top of the stack.
|
||||||
|
kLoadExtended,
|
||||||
|
kLoadExtendedGlobal,
|
||||||
VECTOR(kNegateF),
|
VECTOR(kNegateF),
|
||||||
VECTOR(kNegateI),
|
VECTOR(kNegateI),
|
||||||
VECTOR(kMultiplyF),
|
VECTOR(kMultiplyF),
|
||||||
@ -75,6 +81,8 @@ enum class ByteCodeInstruction : uint16_t {
|
|||||||
VECTOR(kOrB),
|
VECTOR(kOrB),
|
||||||
VECTOR(kOrI),
|
VECTOR(kOrI),
|
||||||
VECTOR(kPop),
|
VECTOR(kPop),
|
||||||
|
// Followed by count byte
|
||||||
|
kPopN,
|
||||||
// Followed by a 32 bit value containing the value to push
|
// Followed by a 32 bit value containing the value to push
|
||||||
kPushImmediate,
|
kPushImmediate,
|
||||||
// Followed by a byte indicating external value to read
|
// Followed by a byte indicating external value to read
|
||||||
@ -86,14 +94,20 @@ enum class ByteCodeInstruction : uint16_t {
|
|||||||
kReturn,
|
kReturn,
|
||||||
VECTOR(kSin),
|
VECTOR(kSin),
|
||||||
VECTOR(kSqrt),
|
VECTOR(kSqrt),
|
||||||
// All kStore* are followed by a byte indicating the local/global slot to store
|
// kStore/kStoreGlobal are followed by a byte indicating the local/global slot to store
|
||||||
VECTOR(kStore),
|
VECTOR(kStore),
|
||||||
VECTOR(kStoreGlobal),
|
VECTOR(kStoreGlobal),
|
||||||
// As above, then a count byte (1-4), and then one byte per swizzle component (0-3).
|
// Fallback stores. Followed by count byte, and get the slot to store from the top of the stack
|
||||||
|
kStoreExtended,
|
||||||
|
kStoreExtendedGlobal,
|
||||||
|
// As kStore/kStoreGlobal, then a count byte (1-4), then one byte per swizzle component (0-3).
|
||||||
// Expects the stack to look like: ... v1 v2 v3 v4, where the number of 'v's is equal to the
|
// Expects the stack to look like: ... v1 v2 v3 v4, where the number of 'v's is equal to the
|
||||||
// number of swizzle components. After the store, all v's are popped from the stack.
|
// number of swizzle components. After the store, all v's are popped from the stack.
|
||||||
kStoreSwizzle,
|
kStoreSwizzle,
|
||||||
kStoreSwizzleGlobal,
|
kStoreSwizzleGlobal,
|
||||||
|
// As above, but gets the store slot from the top of the stack (before values to be stored)
|
||||||
|
kStoreSwizzleIndirect,
|
||||||
|
kStoreSwizzleIndirectGlobal,
|
||||||
// Followed by two count bytes (1-4), and then one byte per swizzle component (0-3). The first
|
// Followed by two count bytes (1-4), and then one byte per swizzle component (0-3). The first
|
||||||
// count byte provides the current vector size (the vector is the top n stack elements), and the
|
// count byte provides the current vector size (the vector is the top n stack elements), and the
|
||||||
// second count byte provides the swizzle component count.
|
// second count byte provides the swizzle component count.
|
||||||
|
@ -21,8 +21,23 @@ ByteCodeGenerator::ByteCodeGenerator(const Context* context, const Program* prog
|
|||||||
fIntrinsics["tan"] = ByteCodeInstruction::kTan;
|
fIntrinsics["tan"] = ByteCodeInstruction::kTan;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int slot_count(const Type& type) {
|
int ByteCodeGenerator::SlotCount(const Type& type) {
|
||||||
return type.columns() * type.rows();
|
if (type.kind() == Type::kStruct_Kind) {
|
||||||
|
int slots = 0;
|
||||||
|
for (const auto& f : type.fields()) {
|
||||||
|
slots += SlotCount(*f.fType);
|
||||||
|
}
|
||||||
|
SkASSERT(slots <= 255);
|
||||||
|
return slots;
|
||||||
|
} else if (type.kind() == Type::kArray_Kind) {
|
||||||
|
int columns = type.columns();
|
||||||
|
SkASSERT(columns >= 0);
|
||||||
|
int slots = columns * SlotCount(type.componentType());
|
||||||
|
SkASSERT(slots <= 255);
|
||||||
|
return slots;
|
||||||
|
} else {
|
||||||
|
return type.columns() * type.rows();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ByteCodeGenerator::generateCode() {
|
bool ByteCodeGenerator::generateCode() {
|
||||||
@ -44,11 +59,11 @@ bool ByteCodeGenerator::generateCode() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (declVar->fModifiers.fFlags & Modifiers::kIn_Flag) {
|
if (declVar->fModifiers.fFlags & Modifiers::kIn_Flag) {
|
||||||
for (int i = slot_count(declVar->fType); i > 0; --i) {
|
for (int i = SlotCount(declVar->fType); i > 0; --i) {
|
||||||
fOutput->fInputSlots.push_back(fOutput->fGlobalCount++);
|
fOutput->fInputSlots.push_back(fOutput->fGlobalCount++);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fOutput->fGlobalCount += slot_count(declVar->fType);
|
fOutput->fGlobalCount += SlotCount(declVar->fType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -70,7 +85,7 @@ std::unique_ptr<ByteCodeFunction> ByteCodeGenerator::writeFunction(const Functio
|
|||||||
std::unique_ptr<ByteCodeFunction> result(new ByteCodeFunction(&f.fDeclaration));
|
std::unique_ptr<ByteCodeFunction> result(new ByteCodeFunction(&f.fDeclaration));
|
||||||
fParameterCount = 0;
|
fParameterCount = 0;
|
||||||
for (const auto& p : f.fDeclaration.fParameters) {
|
for (const auto& p : f.fDeclaration.fParameters) {
|
||||||
fParameterCount += p->fType.columns() * p->fType.rows();
|
fParameterCount += SlotCount(p->fType);
|
||||||
}
|
}
|
||||||
fCode = &result->fCode;
|
fCode = &result->fCode;
|
||||||
this->writeStatement(*f.fBody);
|
this->writeStatement(*f.fBody);
|
||||||
@ -80,7 +95,7 @@ std::unique_ptr<ByteCodeFunction> ByteCodeGenerator::writeFunction(const Functio
|
|||||||
result->fLocalCount = fLocals.size();
|
result->fLocalCount = fLocals.size();
|
||||||
const Type& returnType = f.fDeclaration.fReturnType;
|
const Type& returnType = f.fDeclaration.fReturnType;
|
||||||
if (returnType != *fContext.fVoid_Type) {
|
if (returnType != *fContext.fVoid_Type) {
|
||||||
result->fReturnCount = returnType.columns() * returnType.rows();
|
result->fReturnCount = SlotCount(returnType);
|
||||||
}
|
}
|
||||||
fLocals.clear();
|
fLocals.clear();
|
||||||
fFunction = nullptr;
|
fFunction = nullptr;
|
||||||
@ -127,7 +142,7 @@ int ByteCodeGenerator::getLocation(const Variable& var) {
|
|||||||
}
|
}
|
||||||
int result = fParameterCount + fLocals.size();
|
int result = fParameterCount + fLocals.size();
|
||||||
fLocals.push_back(&var);
|
fLocals.push_back(&var);
|
||||||
for (int i = 0; i < slot_count(var.fType) - 1; ++i) {
|
for (int i = 0; i < SlotCount(var.fType) - 1; ++i) {
|
||||||
fLocals.push_back(nullptr);
|
fLocals.push_back(nullptr);
|
||||||
}
|
}
|
||||||
SkASSERT(result <= 255);
|
SkASSERT(result <= 255);
|
||||||
@ -140,7 +155,7 @@ int ByteCodeGenerator::getLocation(const Variable& var) {
|
|||||||
SkASSERT(offset <= 255);
|
SkASSERT(offset <= 255);
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
offset += slot_count(p->fType);
|
offset += SlotCount(p->fType);
|
||||||
}
|
}
|
||||||
SkASSERT(false);
|
SkASSERT(false);
|
||||||
return 0;
|
return 0;
|
||||||
@ -159,7 +174,7 @@ int ByteCodeGenerator::getLocation(const Variable& var) {
|
|||||||
SkASSERT(offset <= 255);
|
SkASSERT(offset <= 255);
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
offset += slot_count(declVar->fType);
|
offset += SlotCount(declVar->fType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -172,6 +187,62 @@ int ByteCodeGenerator::getLocation(const Variable& var) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ByteCodeGenerator::getLocation(const Expression& expr, Variable::Storage* storage) {
|
||||||
|
switch (expr.fKind) {
|
||||||
|
case Expression::kFieldAccess_Kind: {
|
||||||
|
const FieldAccess& f = (const FieldAccess&)expr;
|
||||||
|
int baseAddr = this->getLocation(*f.fBase, storage);
|
||||||
|
int offset = 0;
|
||||||
|
for (int i = 0; i < f.fFieldIndex; ++i) {
|
||||||
|
offset += SlotCount(*f.fBase->fType.fields()[i].fType);
|
||||||
|
}
|
||||||
|
if (baseAddr < 0) {
|
||||||
|
this->write(ByteCodeInstruction::kPushImmediate);
|
||||||
|
this->write32(offset);
|
||||||
|
this->write(ByteCodeInstruction::kAddI);
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return baseAddr + offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case Expression::kIndex_Kind: {
|
||||||
|
const IndexExpression& i = (const IndexExpression&)expr;
|
||||||
|
int stride = SlotCount(i.fType);
|
||||||
|
int offset = -1;
|
||||||
|
if (i.fIndex->isConstant()) {
|
||||||
|
offset = i.fIndex->getConstantInt() * stride;
|
||||||
|
} else {
|
||||||
|
this->writeExpression(*i.fIndex);
|
||||||
|
this->write(ByteCodeInstruction::kPushImmediate);
|
||||||
|
this->write32(stride);
|
||||||
|
this->write(ByteCodeInstruction::kMultiplyI);
|
||||||
|
}
|
||||||
|
int baseAddr = this->getLocation(*i.fBase, storage);
|
||||||
|
if (baseAddr >= 0 && offset >= 0) {
|
||||||
|
return baseAddr + offset;
|
||||||
|
}
|
||||||
|
if (baseAddr >= 0) {
|
||||||
|
this->write(ByteCodeInstruction::kPushImmediate);
|
||||||
|
this->write32(baseAddr);
|
||||||
|
}
|
||||||
|
if (offset >= 0) {
|
||||||
|
this->write(ByteCodeInstruction::kPushImmediate);
|
||||||
|
this->write32(offset);
|
||||||
|
}
|
||||||
|
this->write(ByteCodeInstruction::kAddI);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
case Expression::kVariableReference_Kind: {
|
||||||
|
const Variable& var = ((const VariableReference&)expr).fVariable;
|
||||||
|
*storage = var.fStorage;
|
||||||
|
return this->getLocation(var);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
SkASSERT(false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ByteCodeGenerator::write8(uint8_t b) {
|
void ByteCodeGenerator::write8(uint8_t b) {
|
||||||
fCode->push_back(b);
|
fCode->push_back(b);
|
||||||
}
|
}
|
||||||
@ -193,6 +264,7 @@ void ByteCodeGenerator::write(ByteCodeInstruction i) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static ByteCodeInstruction vector_instruction(ByteCodeInstruction base, int count) {
|
static ByteCodeInstruction vector_instruction(ByteCodeInstruction base, int count) {
|
||||||
|
SkASSERT(count >= 1 && count <= 4);
|
||||||
return ((ByteCodeInstruction) ((int) base + count - 1));
|
return ((ByteCodeInstruction) ((int) base + count - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,7 +316,7 @@ void ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b) {
|
|||||||
this->write(ByteCodeInstruction::kDup);
|
this->write(ByteCodeInstruction::kDup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int count = slot_count(b.fType);
|
int count = SlotCount(b.fType);
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case Token::Kind::EQEQ:
|
case Token::Kind::EQEQ:
|
||||||
this->writeTypedInstruction(b.fLeft->fType, ByteCodeInstruction::kCompareIEQ,
|
this->writeTypedInstruction(b.fLeft->fType, ByteCodeInstruction::kCompareIEQ,
|
||||||
@ -364,12 +436,12 @@ void ByteCodeGenerator::writeExternalFunctionCall(const ExternalFunctionCall& f)
|
|||||||
int argumentCount = 0;
|
int argumentCount = 0;
|
||||||
for (const auto& arg : f.fArguments) {
|
for (const auto& arg : f.fArguments) {
|
||||||
this->writeExpression(*arg);
|
this->writeExpression(*arg);
|
||||||
argumentCount += slot_count(arg->fType);
|
argumentCount += SlotCount(arg->fType);
|
||||||
}
|
}
|
||||||
this->write(ByteCodeInstruction::kCallExternal);
|
this->write(ByteCodeInstruction::kCallExternal);
|
||||||
SkASSERT(argumentCount <= 255);
|
SkASSERT(argumentCount <= 255);
|
||||||
this->write8(argumentCount);
|
this->write8(argumentCount);
|
||||||
this->write8(slot_count(f.fType));
|
this->write8(SlotCount(f.fType));
|
||||||
int index = fOutput->fExternalValues.size();
|
int index = fOutput->fExternalValues.size();
|
||||||
fOutput->fExternalValues.push_back(f.fFunction);
|
fOutput->fExternalValues.push_back(f.fFunction);
|
||||||
SkASSERT(index <= 255);
|
SkASSERT(index <= 255);
|
||||||
@ -378,16 +450,32 @@ void ByteCodeGenerator::writeExternalFunctionCall(const ExternalFunctionCall& f)
|
|||||||
|
|
||||||
void ByteCodeGenerator::writeExternalValue(const ExternalValueReference& e) {
|
void ByteCodeGenerator::writeExternalValue(const ExternalValueReference& e) {
|
||||||
this->write(vector_instruction(ByteCodeInstruction::kReadExternal,
|
this->write(vector_instruction(ByteCodeInstruction::kReadExternal,
|
||||||
slot_count(e.fValue->type())));
|
SlotCount(e.fValue->type())));
|
||||||
int index = fOutput->fExternalValues.size();
|
int index = fOutput->fExternalValues.size();
|
||||||
fOutput->fExternalValues.push_back(e.fValue);
|
fOutput->fExternalValues.push_back(e.fValue);
|
||||||
SkASSERT(index <= 255);
|
SkASSERT(index <= 255);
|
||||||
this->write8(index);
|
this->write8(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ByteCodeGenerator::writeFieldAccess(const FieldAccess& f) {
|
void ByteCodeGenerator::writeVariableExpression(const Expression& expr) {
|
||||||
// not yet implemented
|
Variable::Storage storage;
|
||||||
abort();
|
int location = this->getLocation(expr, &storage);
|
||||||
|
bool isGlobal = storage == Variable::kGlobal_Storage;
|
||||||
|
int count = SlotCount(expr.fType);
|
||||||
|
if (location < 0 || count > 4) {
|
||||||
|
if (location >= 0) {
|
||||||
|
this->write(ByteCodeInstruction::kPushImmediate);
|
||||||
|
this->write32(location);
|
||||||
|
}
|
||||||
|
this->write(isGlobal ? ByteCodeInstruction::kLoadExtendedGlobal
|
||||||
|
: ByteCodeInstruction::kLoadExtended);
|
||||||
|
this->write8(count);
|
||||||
|
} else {
|
||||||
|
this->write(vector_instruction(isGlobal ? ByteCodeInstruction::kLoadGlobal
|
||||||
|
: ByteCodeInstruction::kLoad,
|
||||||
|
count));
|
||||||
|
this->write8(location);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ByteCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
|
void ByteCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
|
||||||
@ -408,7 +496,7 @@ void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
|
|||||||
case ByteCodeInstruction::kTan:
|
case ByteCodeInstruction::kTan:
|
||||||
SkASSERT(c.fArguments.size() == 1);
|
SkASSERT(c.fArguments.size() == 1);
|
||||||
this->write((ByteCodeInstruction) ((int) found->second +
|
this->write((ByteCodeInstruction) ((int) found->second +
|
||||||
slot_count(c.fArguments[0]->fType) - 1));
|
SlotCount(c.fArguments[0]->fType) - 1));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
SkASSERT(false);
|
SkASSERT(false);
|
||||||
@ -427,11 +515,6 @@ void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
|
|||||||
fCallTargets.emplace_back(this, f.fFunction);
|
fCallTargets.emplace_back(this, f.fFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ByteCodeGenerator::writeIndexExpression(const IndexExpression& i) {
|
|
||||||
// not yet implemented
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ByteCodeGenerator::writeIntLiteral(const IntLiteral& i) {
|
void ByteCodeGenerator::writeIntLiteral(const IntLiteral& i) {
|
||||||
this->write(ByteCodeInstruction::kPushImmediate);
|
this->write(ByteCodeInstruction::kPushImmediate);
|
||||||
this->write32(i.fValue);
|
this->write32(i.fValue);
|
||||||
@ -446,7 +529,7 @@ void ByteCodeGenerator::writePrefixExpression(const PrefixExpression& p) {
|
|||||||
switch (p.fOperator) {
|
switch (p.fOperator) {
|
||||||
case Token::Kind::PLUSPLUS: // fall through
|
case Token::Kind::PLUSPLUS: // fall through
|
||||||
case Token::Kind::MINUSMINUS: {
|
case Token::Kind::MINUSMINUS: {
|
||||||
SkASSERT(slot_count(p.fOperand->fType) == 1);
|
SkASSERT(SlotCount(p.fOperand->fType) == 1);
|
||||||
std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
|
std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
|
||||||
lvalue->load();
|
lvalue->load();
|
||||||
this->write(ByteCodeInstruction::kPushImmediate);
|
this->write(ByteCodeInstruction::kPushImmediate);
|
||||||
@ -474,7 +557,7 @@ void ByteCodeGenerator::writePrefixExpression(const PrefixExpression& p) {
|
|||||||
ByteCodeInstruction::kNegateI,
|
ByteCodeInstruction::kNegateI,
|
||||||
ByteCodeInstruction::kNegateI,
|
ByteCodeInstruction::kNegateI,
|
||||||
ByteCodeInstruction::kNegateF,
|
ByteCodeInstruction::kNegateF,
|
||||||
slot_count(p.fOperand->fType));
|
SlotCount(p.fOperand->fType));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -486,7 +569,7 @@ void ByteCodeGenerator::writePostfixExpression(const PostfixExpression& p) {
|
|||||||
switch (p.fOperator) {
|
switch (p.fOperator) {
|
||||||
case Token::Kind::PLUSPLUS: // fall through
|
case Token::Kind::PLUSPLUS: // fall through
|
||||||
case Token::Kind::MINUSMINUS: {
|
case Token::Kind::MINUSMINUS: {
|
||||||
SkASSERT(slot_count(p.fOperand->fType) == 1);
|
SkASSERT(SlotCount(p.fOperand->fType) == 1);
|
||||||
std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
|
std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
|
||||||
lvalue->load();
|
lvalue->load();
|
||||||
this->write(ByteCodeInstruction::kDup);
|
this->write(ByteCodeInstruction::kDup);
|
||||||
@ -540,14 +623,6 @@ void ByteCodeGenerator::writeSwizzle(const Swizzle& s) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ByteCodeGenerator::writeVariableReference(const VariableReference& v) {
|
|
||||||
this->write(vector_instruction(v.fVariable.fStorage == Variable::kGlobal_Storage
|
|
||||||
? ByteCodeInstruction::kLoadGlobal
|
|
||||||
: ByteCodeInstruction::kLoad,
|
|
||||||
slot_count(v.fType)));
|
|
||||||
this->write8(this->getLocation(v.fVariable));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ByteCodeGenerator::writeTernaryExpression(const TernaryExpression& t) {
|
void ByteCodeGenerator::writeTernaryExpression(const TernaryExpression& t) {
|
||||||
this->writeExpression(*t.fTest);
|
this->writeExpression(*t.fTest);
|
||||||
this->write(ByteCodeInstruction::kConditionalBranch);
|
this->write(ByteCodeInstruction::kConditionalBranch);
|
||||||
@ -578,7 +653,9 @@ void ByteCodeGenerator::writeExpression(const Expression& e) {
|
|||||||
this->writeExternalValue((ExternalValueReference&) e);
|
this->writeExternalValue((ExternalValueReference&) e);
|
||||||
break;
|
break;
|
||||||
case Expression::kFieldAccess_Kind:
|
case Expression::kFieldAccess_Kind:
|
||||||
this->writeFieldAccess((FieldAccess&) e);
|
case Expression::kIndex_Kind:
|
||||||
|
case Expression::kVariableReference_Kind:
|
||||||
|
this->writeVariableExpression(e);
|
||||||
break;
|
break;
|
||||||
case Expression::kFloatLiteral_Kind:
|
case Expression::kFloatLiteral_Kind:
|
||||||
this->writeFloatLiteral((FloatLiteral&) e);
|
this->writeFloatLiteral((FloatLiteral&) e);
|
||||||
@ -586,9 +663,6 @@ void ByteCodeGenerator::writeExpression(const Expression& e) {
|
|||||||
case Expression::kFunctionCall_Kind:
|
case Expression::kFunctionCall_Kind:
|
||||||
this->writeFunctionCall((FunctionCall&) e);
|
this->writeFunctionCall((FunctionCall&) e);
|
||||||
break;
|
break;
|
||||||
case Expression::kIndex_Kind:
|
|
||||||
this->writeIndexExpression((IndexExpression&) e);
|
|
||||||
break;
|
|
||||||
case Expression::kIntLiteral_Kind:
|
case Expression::kIntLiteral_Kind:
|
||||||
this->writeIntLiteral((IntLiteral&) e);
|
this->writeIntLiteral((IntLiteral&) e);
|
||||||
break;
|
break;
|
||||||
@ -604,9 +678,6 @@ void ByteCodeGenerator::writeExpression(const Expression& e) {
|
|||||||
case Expression::kSwizzle_Kind:
|
case Expression::kSwizzle_Kind:
|
||||||
this->writeSwizzle((Swizzle&) e);
|
this->writeSwizzle((Swizzle&) e);
|
||||||
break;
|
break;
|
||||||
case Expression::kVariableReference_Kind:
|
|
||||||
this->writeVariableReference((VariableReference&) e);
|
|
||||||
break;
|
|
||||||
case Expression::kTernary_Kind:
|
case Expression::kTernary_Kind:
|
||||||
this->writeTernaryExpression((TernaryExpression&) e);
|
this->writeTernaryExpression((TernaryExpression&) e);
|
||||||
break;
|
break;
|
||||||
@ -620,7 +691,7 @@ class ByteCodeExternalValueLValue : public ByteCodeGenerator::LValue {
|
|||||||
public:
|
public:
|
||||||
ByteCodeExternalValueLValue(ByteCodeGenerator* generator, ExternalValue& value, int index)
|
ByteCodeExternalValueLValue(ByteCodeGenerator* generator, ExternalValue& value, int index)
|
||||||
: INHERITED(*generator)
|
: INHERITED(*generator)
|
||||||
, fCount(slot_count(value.type()))
|
, fCount(ByteCodeGenerator::SlotCount(value.type()))
|
||||||
, fIndex(index) {}
|
, fIndex(index) {}
|
||||||
|
|
||||||
void load() override {
|
void load() override {
|
||||||
@ -646,22 +717,26 @@ class ByteCodeSwizzleLValue : public ByteCodeGenerator::LValue {
|
|||||||
public:
|
public:
|
||||||
ByteCodeSwizzleLValue(ByteCodeGenerator* generator, const Swizzle& swizzle)
|
ByteCodeSwizzleLValue(ByteCodeGenerator* generator, const Swizzle& swizzle)
|
||||||
: INHERITED(*generator)
|
: INHERITED(*generator)
|
||||||
, fSwizzle(swizzle) {
|
, fSwizzle(swizzle) {}
|
||||||
SkASSERT(fSwizzle.fBase->fKind == Expression::kVariableReference_Kind);
|
|
||||||
}
|
|
||||||
|
|
||||||
void load() override {
|
void load() override {
|
||||||
fGenerator.writeSwizzle(fSwizzle);
|
fGenerator.writeSwizzle(fSwizzle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void store() override {
|
void store() override {
|
||||||
const Variable& var = ((VariableReference&)*fSwizzle.fBase).fVariable;
|
|
||||||
fGenerator.write(vector_instruction(ByteCodeInstruction::kDup,
|
fGenerator.write(vector_instruction(ByteCodeInstruction::kDup,
|
||||||
fSwizzle.fComponents.size()));
|
fSwizzle.fComponents.size()));
|
||||||
fGenerator.write(var.fStorage == Variable::kGlobal_Storage
|
Variable::Storage storage;
|
||||||
? ByteCodeInstruction::kStoreSwizzleGlobal
|
int location = fGenerator.getLocation(*fSwizzle.fBase, &storage);
|
||||||
: ByteCodeInstruction::kStoreSwizzle);
|
bool isGlobal = storage == Variable::kGlobal_Storage;
|
||||||
fGenerator.write8(fGenerator.getLocation(var));
|
if (location < 0) {
|
||||||
|
fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleIndirectGlobal
|
||||||
|
: ByteCodeInstruction::kStoreSwizzleIndirect);
|
||||||
|
} else {
|
||||||
|
fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleGlobal
|
||||||
|
: ByteCodeInstruction::kStoreSwizzle);
|
||||||
|
fGenerator.write8(location);
|
||||||
|
}
|
||||||
fGenerator.write8(fSwizzle.fComponents.size());
|
fGenerator.write8(fSwizzle.fComponents.size());
|
||||||
for (int c : fSwizzle.fComponents) {
|
for (int c : fSwizzle.fComponents) {
|
||||||
fGenerator.write8(c);
|
fGenerator.write8(c);
|
||||||
@ -674,36 +749,47 @@ private:
|
|||||||
typedef LValue INHERITED;
|
typedef LValue INHERITED;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ByteCodeVariableLValue : public ByteCodeGenerator::LValue {
|
class ByteCodeExpressionLValue : public ByteCodeGenerator::LValue {
|
||||||
public:
|
public:
|
||||||
ByteCodeVariableLValue(ByteCodeGenerator* generator, const Variable& var)
|
ByteCodeExpressionLValue(ByteCodeGenerator* generator, const Expression& expr)
|
||||||
: INHERITED(*generator)
|
: INHERITED(*generator)
|
||||||
, fCount(slot_count(var.fType))
|
, fExpression(expr) {}
|
||||||
, fLocation(generator->getLocation(var))
|
|
||||||
, fIsGlobal(var.fStorage == Variable::kGlobal_Storage) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void load() override {
|
void load() override {
|
||||||
fGenerator.write(vector_instruction(fIsGlobal ? ByteCodeInstruction::kLoadGlobal
|
fGenerator.writeVariableExpression(fExpression);
|
||||||
: ByteCodeInstruction::kLoad,
|
|
||||||
fCount));
|
|
||||||
fGenerator.write8(fLocation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void store() override {
|
void store() override {
|
||||||
fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, fCount));
|
int count = ByteCodeGenerator::SlotCount(fExpression.fType);
|
||||||
fGenerator.write(vector_instruction(fIsGlobal ? ByteCodeInstruction::kStoreGlobal
|
if (count > 4) {
|
||||||
: ByteCodeInstruction::kStore,
|
fGenerator.write(ByteCodeInstruction::kDupN);
|
||||||
fCount));
|
fGenerator.write8(count);
|
||||||
fGenerator.write8(fLocation);
|
} else {
|
||||||
|
fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
|
||||||
|
}
|
||||||
|
Variable::Storage storage;
|
||||||
|
int location = fGenerator.getLocation(fExpression, &storage);
|
||||||
|
bool isGlobal = storage == Variable::kGlobal_Storage;
|
||||||
|
if (location < 0 || count > 4) {
|
||||||
|
if (location >= 0) {
|
||||||
|
fGenerator.write(ByteCodeInstruction::kPushImmediate);
|
||||||
|
fGenerator.write32(location);
|
||||||
|
}
|
||||||
|
fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreExtendedGlobal
|
||||||
|
: ByteCodeInstruction::kStoreExtended);
|
||||||
|
fGenerator.write8(count);
|
||||||
|
} else {
|
||||||
|
fGenerator.write(vector_instruction(isGlobal ? ByteCodeInstruction::kStoreGlobal
|
||||||
|
: ByteCodeInstruction::kStore,
|
||||||
|
count));
|
||||||
|
fGenerator.write8(location);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef LValue INHERITED;
|
typedef LValue INHERITED;
|
||||||
|
|
||||||
int fCount;
|
const Expression& fExpression;
|
||||||
int fLocation;
|
|
||||||
bool fIsGlobal;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<ByteCodeGenerator::LValue> ByteCodeGenerator::getLValue(const Expression& e) {
|
std::unique_ptr<ByteCodeGenerator::LValue> ByteCodeGenerator::getLValue(const Expression& e) {
|
||||||
@ -715,12 +801,10 @@ std::unique_ptr<ByteCodeGenerator::LValue> ByteCodeGenerator::getLValue(const Ex
|
|||||||
SkASSERT(index <= 255);
|
SkASSERT(index <= 255);
|
||||||
return std::unique_ptr<LValue>(new ByteCodeExternalValueLValue(this, *value, index));
|
return std::unique_ptr<LValue>(new ByteCodeExternalValueLValue(this, *value, index));
|
||||||
}
|
}
|
||||||
|
case Expression::kFieldAccess_Kind:
|
||||||
case Expression::kIndex_Kind:
|
case Expression::kIndex_Kind:
|
||||||
// not yet implemented
|
|
||||||
abort();
|
|
||||||
case Expression::kVariableReference_Kind:
|
case Expression::kVariableReference_Kind:
|
||||||
return std::unique_ptr<LValue>(new ByteCodeVariableLValue(this,
|
return std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e));
|
||||||
((VariableReference&) e).fVariable));
|
|
||||||
case Expression::kSwizzle_Kind:
|
case Expression::kSwizzle_Kind:
|
||||||
return std::unique_ptr<LValue>(new ByteCodeSwizzleLValue(this, (Swizzle&) e));
|
return std::unique_ptr<LValue>(new ByteCodeSwizzleLValue(this, (Swizzle&) e));
|
||||||
case Expression::kTernary_Kind:
|
case Expression::kTernary_Kind:
|
||||||
@ -790,7 +874,7 @@ void ByteCodeGenerator::writeForStatement(const ForStatement& f) {
|
|||||||
this->setContinueTargets();
|
this->setContinueTargets();
|
||||||
if (f.fNext) {
|
if (f.fNext) {
|
||||||
this->writeExpression(*f.fNext);
|
this->writeExpression(*f.fNext);
|
||||||
this->write(vector_instruction(ByteCodeInstruction::kPop, slot_count(f.fNext->fType)));
|
this->write(vector_instruction(ByteCodeInstruction::kPop, SlotCount(f.fNext->fType)));
|
||||||
}
|
}
|
||||||
this->write(ByteCodeInstruction::kBranch);
|
this->write(ByteCodeInstruction::kBranch);
|
||||||
this->write16(start);
|
this->write16(start);
|
||||||
@ -800,7 +884,7 @@ void ByteCodeGenerator::writeForStatement(const ForStatement& f) {
|
|||||||
this->setContinueTargets();
|
this->setContinueTargets();
|
||||||
if (f.fNext) {
|
if (f.fNext) {
|
||||||
this->writeExpression(*f.fNext);
|
this->writeExpression(*f.fNext);
|
||||||
this->write(vector_instruction(ByteCodeInstruction::kPop, slot_count(f.fNext->fType)));
|
this->write(vector_instruction(ByteCodeInstruction::kPop, SlotCount(f.fNext->fType)));
|
||||||
}
|
}
|
||||||
this->write(ByteCodeInstruction::kBranch);
|
this->write(ByteCodeInstruction::kBranch);
|
||||||
this->write16(start);
|
this->write16(start);
|
||||||
@ -834,7 +918,7 @@ void ByteCodeGenerator::writeIfStatement(const IfStatement& i) {
|
|||||||
void ByteCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
|
void ByteCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
|
||||||
this->writeExpression(*r.fExpression);
|
this->writeExpression(*r.fExpression);
|
||||||
this->write(ByteCodeInstruction::kReturn);
|
this->write(ByteCodeInstruction::kReturn);
|
||||||
this->write8(r.fExpression->fType.columns() * r.fExpression->fType.rows());
|
this->write8(SlotCount(r.fExpression->fType));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ByteCodeGenerator::writeSwitchStatement(const SwitchStatement& r) {
|
void ByteCodeGenerator::writeSwitchStatement(const SwitchStatement& r) {
|
||||||
@ -850,9 +934,16 @@ void ByteCodeGenerator::writeVarDeclarations(const VarDeclarations& v) {
|
|||||||
int location = getLocation(*decl.fVar);
|
int location = getLocation(*decl.fVar);
|
||||||
if (decl.fValue) {
|
if (decl.fValue) {
|
||||||
this->writeExpression(*decl.fValue);
|
this->writeExpression(*decl.fValue);
|
||||||
this->write(vector_instruction(ByteCodeInstruction::kStore,
|
int count = SlotCount(decl.fValue->fType);
|
||||||
slot_count(decl.fValue->fType)));
|
if (count > 4) {
|
||||||
this->write8(location);
|
this->write(ByteCodeInstruction::kPushImmediate);
|
||||||
|
this->write32(location);
|
||||||
|
this->write(ByteCodeInstruction::kStoreExtended);
|
||||||
|
this->write8(count);
|
||||||
|
} else {
|
||||||
|
this->write(vector_instruction(ByteCodeInstruction::kStore, count));
|
||||||
|
this->write8(location);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -893,7 +984,13 @@ void ByteCodeGenerator::writeStatement(const Statement& s) {
|
|||||||
case Statement::kExpression_Kind: {
|
case Statement::kExpression_Kind: {
|
||||||
const Expression& expr = *((ExpressionStatement&) s).fExpression;
|
const Expression& expr = *((ExpressionStatement&) s).fExpression;
|
||||||
this->writeExpression(expr);
|
this->writeExpression(expr);
|
||||||
this->write(vector_instruction(ByteCodeInstruction::kPop, slot_count(expr.fType)));
|
int count = SlotCount(expr.fType);
|
||||||
|
if (count > 4) {
|
||||||
|
this->write(ByteCodeInstruction::kPopN);
|
||||||
|
this->write8(count);
|
||||||
|
} else {
|
||||||
|
this->write(vector_instruction(ByteCodeInstruction::kPop, count));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Statement::kFor_Kind:
|
case Statement::kFor_Kind:
|
||||||
|
@ -96,6 +96,8 @@ public:
|
|||||||
void writeTypedInstruction(const Type& type, ByteCodeInstruction s, ByteCodeInstruction u,
|
void writeTypedInstruction(const Type& type, ByteCodeInstruction s, ByteCodeInstruction u,
|
||||||
ByteCodeInstruction f, int count);
|
ByteCodeInstruction f, int count);
|
||||||
|
|
||||||
|
static int SlotCount(const Type& type);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// reserves 16 bits in the output code, to be filled in later with an address once we determine
|
// reserves 16 bits in the output code, to be filled in later with an address once we determine
|
||||||
// it
|
// it
|
||||||
@ -171,11 +173,18 @@ private:
|
|||||||
*/
|
*/
|
||||||
int getLocation(const Variable& var);
|
int getLocation(const Variable& var);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* As above, but computes the (possibly dynamic) address of an expression involving indexing &
|
||||||
|
* field access. If the address is known, it's returned. If not, -1 is returned, and the
|
||||||
|
* location will be left on the top of the stack.
|
||||||
|
*/
|
||||||
|
int getLocation(const Expression& expr, Variable::Storage* storage);
|
||||||
|
|
||||||
std::unique_ptr<ByteCodeFunction> writeFunction(const FunctionDefinition& f);
|
std::unique_ptr<ByteCodeFunction> writeFunction(const FunctionDefinition& f);
|
||||||
|
|
||||||
void writeVarDeclarations(const VarDeclarations& decl);
|
void writeVarDeclarations(const VarDeclarations& decl);
|
||||||
|
|
||||||
void writeVariableReference(const VariableReference& ref);
|
void writeVariableExpression(const Expression& expr);
|
||||||
|
|
||||||
void writeExpression(const Expression& expr);
|
void writeExpression(const Expression& expr);
|
||||||
|
|
||||||
@ -195,16 +204,12 @@ private:
|
|||||||
|
|
||||||
void writeExternalValue(const ExternalValueReference& r);
|
void writeExternalValue(const ExternalValueReference& r);
|
||||||
|
|
||||||
void writeFieldAccess(const FieldAccess& f);
|
|
||||||
|
|
||||||
void writeSwizzle(const Swizzle& swizzle);
|
void writeSwizzle(const Swizzle& swizzle);
|
||||||
|
|
||||||
void writeBinaryExpression(const BinaryExpression& b);
|
void writeBinaryExpression(const BinaryExpression& b);
|
||||||
|
|
||||||
void writeTernaryExpression(const TernaryExpression& t);
|
void writeTernaryExpression(const TernaryExpression& t);
|
||||||
|
|
||||||
void writeIndexExpression(const IndexExpression& expr);
|
|
||||||
|
|
||||||
void writeLogicalAnd(const BinaryExpression& b);
|
void writeLogicalAnd(const BinaryExpression& b);
|
||||||
|
|
||||||
void writeLogicalOr(const BinaryExpression& o);
|
void writeLogicalOr(const BinaryExpression& o);
|
||||||
@ -268,7 +273,7 @@ private:
|
|||||||
std::unordered_map<String, ByteCodeInstruction> fIntrinsics;
|
std::unordered_map<String, ByteCodeInstruction> fIntrinsics;
|
||||||
|
|
||||||
friend class DeferredLocation;
|
friend class DeferredLocation;
|
||||||
friend class ByteCodeVariableLValue;
|
friend class ByteCodeExpressionLValue;
|
||||||
friend class ByteCodeSwizzleLValue;
|
friend class ByteCodeSwizzleLValue;
|
||||||
|
|
||||||
typedef CodeGenerator INHERITED;
|
typedef CodeGenerator INHERITED;
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#ifndef SKSL_STANDALONE
|
#ifndef SKSL_STANDALONE
|
||||||
|
|
||||||
#include "src/core/SkRasterPipeline.h"
|
#include "src/core/SkRasterPipeline.h"
|
||||||
|
#include "src/sksl/SkSLByteCodeGenerator.h"
|
||||||
#include "src/sksl/SkSLExternalValue.h"
|
#include "src/sksl/SkSLExternalValue.h"
|
||||||
#include "src/sksl/SkSLInterpreter.h"
|
#include "src/sksl/SkSLInterpreter.h"
|
||||||
#include "src/sksl/ir/SkSLBinaryExpression.h"
|
#include "src/sksl/ir/SkSLBinaryExpression.h"
|
||||||
@ -64,8 +65,7 @@ void Interpreter::run(const ByteCodeFunction& f, Interpreter::Value args[],
|
|||||||
this->innerRun(f, stack, outReturn);
|
this->innerRun(f, stack, outReturn);
|
||||||
|
|
||||||
for (const Variable* p : f.fDeclaration.fParameters) {
|
for (const Variable* p : f.fDeclaration.fParameters) {
|
||||||
const int nvalues = p->fType.columns()
|
const int nvalues = ByteCodeGenerator::SlotCount(p->fType);
|
||||||
* p->fType.rows();
|
|
||||||
if (p->fModifiers.fFlags & Modifiers::kOut_Flag) {
|
if (p->fModifiers.fFlags & Modifiers::kOut_Flag) {
|
||||||
memcpy(args, stack, nvalues * sizeof(Value));
|
memcpy(args, stack, nvalues * sizeof(Value));
|
||||||
}
|
}
|
||||||
@ -137,6 +137,7 @@ void Interpreter::disassemble(const ByteCodeFunction& f) {
|
|||||||
VECTOR_DISASSEMBLE(kDivideS, "divideS")
|
VECTOR_DISASSEMBLE(kDivideS, "divideS")
|
||||||
VECTOR_DISASSEMBLE(kDivideU, "divideu")
|
VECTOR_DISASSEMBLE(kDivideU, "divideu")
|
||||||
VECTOR_DISASSEMBLE(kDup, "dup")
|
VECTOR_DISASSEMBLE(kDup, "dup")
|
||||||
|
case ByteCodeInstruction::kDupN: printf("dupN %d", READ8()); break;
|
||||||
case ByteCodeInstruction::kLoad: printf("load %d", READ8()); break;
|
case ByteCodeInstruction::kLoad: printf("load %d", READ8()); break;
|
||||||
case ByteCodeInstruction::kLoad2: printf("load2 %d", READ8()); break;
|
case ByteCodeInstruction::kLoad2: printf("load2 %d", READ8()); break;
|
||||||
case ByteCodeInstruction::kLoad3: printf("load3 %d", READ8()); break;
|
case ByteCodeInstruction::kLoad3: printf("load3 %d", READ8()); break;
|
||||||
@ -163,6 +164,9 @@ void Interpreter::disassemble(const ByteCodeFunction& f) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ByteCodeInstruction::kLoadExtended: printf("loadextended %d", READ8()); break;
|
||||||
|
case ByteCodeInstruction::kLoadExtendedGlobal: printf("loadextendedglobal %d", READ8());
|
||||||
|
break;
|
||||||
VECTOR_DISASSEMBLE(kMultiplyF, "multiplyf")
|
VECTOR_DISASSEMBLE(kMultiplyF, "multiplyf")
|
||||||
VECTOR_DISASSEMBLE(kMultiplyI, "multiplyi")
|
VECTOR_DISASSEMBLE(kMultiplyI, "multiplyi")
|
||||||
VECTOR_DISASSEMBLE(kNegateF, "negatef")
|
VECTOR_DISASSEMBLE(kNegateF, "negatef")
|
||||||
@ -171,6 +175,7 @@ void Interpreter::disassemble(const ByteCodeFunction& f) {
|
|||||||
VECTOR_DISASSEMBLE(kOrB, "orb")
|
VECTOR_DISASSEMBLE(kOrB, "orb")
|
||||||
VECTOR_DISASSEMBLE(kOrI, "ori")
|
VECTOR_DISASSEMBLE(kOrI, "ori")
|
||||||
VECTOR_DISASSEMBLE(kPop, "pop")
|
VECTOR_DISASSEMBLE(kPop, "pop")
|
||||||
|
case ByteCodeInstruction::kPopN: printf("popN %d", READ8()); break;
|
||||||
case ByteCodeInstruction::kPushImmediate: {
|
case ByteCodeInstruction::kPushImmediate: {
|
||||||
uint32_t v = READ32();
|
uint32_t v = READ32();
|
||||||
union { uint32_t u; float f; } pun = { v };
|
union { uint32_t u; float f; } pun = { v };
|
||||||
@ -213,6 +218,26 @@ void Interpreter::disassemble(const ByteCodeFunction& f) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ByteCodeInstruction::kStoreSwizzleIndirect: {
|
||||||
|
int count = READ8();
|
||||||
|
printf("storeswizzleindirect %d", count);
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
printf(", %d", READ8());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ByteCodeInstruction::kStoreSwizzleIndirectGlobal: {
|
||||||
|
int count = READ8();
|
||||||
|
printf("storeswizzleindirectglobal %d", count);
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
printf(", %d", READ8());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ByteCodeInstruction::kStoreExtended: printf("storeextended %d", READ8()); break;
|
||||||
|
case ByteCodeInstruction::kStoreExtendedGlobal:
|
||||||
|
printf("storeextendedglobal %d", READ8());
|
||||||
|
break;
|
||||||
VECTOR_DISASSEMBLE(kSubtractF, "subtractf")
|
VECTOR_DISASSEMBLE(kSubtractF, "subtractf")
|
||||||
VECTOR_DISASSEMBLE(kSubtractI, "subtracti")
|
VECTOR_DISASSEMBLE(kSubtractI, "subtracti")
|
||||||
case ByteCodeInstruction::kSwizzle: {
|
case ByteCodeInstruction::kSwizzle: {
|
||||||
@ -404,6 +429,13 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe
|
|||||||
case ByteCodeInstruction::kDup : PUSH(sp[(int)ByteCodeInstruction::kDup - (int)inst]);
|
case ByteCodeInstruction::kDup : PUSH(sp[(int)ByteCodeInstruction::kDup - (int)inst]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ByteCodeInstruction::kDupN: {
|
||||||
|
int count = READ8();
|
||||||
|
memcpy(sp + 1, sp - count + 1, count * sizeof(Value));
|
||||||
|
sp += count;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ByteCodeInstruction::kLoad4: sp[4] = stack[*ip + 3];
|
case ByteCodeInstruction::kLoad4: sp[4] = stack[*ip + 3];
|
||||||
case ByteCodeInstruction::kLoad3: sp[3] = stack[*ip + 2];
|
case ByteCodeInstruction::kLoad3: sp[3] = stack[*ip + 2];
|
||||||
case ByteCodeInstruction::kLoad2: sp[2] = stack[*ip + 1];
|
case ByteCodeInstruction::kLoad2: sp[2] = stack[*ip + 1];
|
||||||
@ -417,9 +449,27 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe
|
|||||||
case ByteCodeInstruction::kLoadGlobal2: sp[2] = fGlobals[*ip + 1];
|
case ByteCodeInstruction::kLoadGlobal2: sp[2] = fGlobals[*ip + 1];
|
||||||
case ByteCodeInstruction::kLoadGlobal : sp[1] = fGlobals[*ip + 0];
|
case ByteCodeInstruction::kLoadGlobal : sp[1] = fGlobals[*ip + 0];
|
||||||
++ip;
|
++ip;
|
||||||
sp += (int)inst - (int)ByteCodeInstruction::kLoadGlobal + 1;
|
sp += (int)inst -
|
||||||
|
(int)ByteCodeInstruction::kLoadGlobal + 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ByteCodeInstruction::kLoadExtended: {
|
||||||
|
int count = READ8();
|
||||||
|
int src = POP().fSigned;
|
||||||
|
memcpy(sp + 1, &stack[src], count * sizeof(Value));
|
||||||
|
sp += count;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ByteCodeInstruction::kLoadExtendedGlobal: {
|
||||||
|
int count = READ8();
|
||||||
|
int src = POP().fSigned;
|
||||||
|
SkASSERT(src + count <= (int) fGlobals.size());
|
||||||
|
memcpy(sp + 1, &fGlobals[src], count * sizeof(Value));
|
||||||
|
sp += count;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ByteCodeInstruction::kLoadSwizzle: {
|
case ByteCodeInstruction::kLoadSwizzle: {
|
||||||
int src = READ8();
|
int src = READ8();
|
||||||
int count = READ8();
|
int count = READ8();
|
||||||
@ -466,6 +516,10 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe
|
|||||||
case ByteCodeInstruction::kPop : POP();
|
case ByteCodeInstruction::kPop : POP();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ByteCodeInstruction::kPopN:
|
||||||
|
sp -= READ8();
|
||||||
|
break;
|
||||||
|
|
||||||
case ByteCodeInstruction::kPushImmediate:
|
case ByteCodeInstruction::kPushImmediate:
|
||||||
PUSH(READ32());
|
PUSH(READ32());
|
||||||
break;
|
break;
|
||||||
@ -525,6 +579,22 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe
|
|||||||
++ip;
|
++ip;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ByteCodeInstruction::kStoreExtended: {
|
||||||
|
int count = READ8();
|
||||||
|
int target = POP().fSigned;
|
||||||
|
memcpy(&stack[target], sp - count + 1, count * sizeof(Value));
|
||||||
|
sp -= count;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ByteCodeInstruction::kStoreExtendedGlobal: {
|
||||||
|
int count = READ8();
|
||||||
|
int target = POP().fSigned;
|
||||||
|
SkASSERT(target + count <= (int) fGlobals.size());
|
||||||
|
memcpy(&fGlobals[target], sp - count + 1, count * sizeof(Value));
|
||||||
|
sp -= count;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ByteCodeInstruction::kStoreSwizzle: {
|
case ByteCodeInstruction::kStoreSwizzle: {
|
||||||
int target = READ8();
|
int target = READ8();
|
||||||
int count = READ8();
|
int count = READ8();
|
||||||
@ -544,6 +614,24 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe
|
|||||||
ip += count;
|
ip += count;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ByteCodeInstruction::kStoreSwizzleIndirect: {
|
||||||
|
int target = POP().fSigned;
|
||||||
|
int count = READ8();
|
||||||
|
for (int i = count - 1; i >= 0; --i) {
|
||||||
|
stack[target + *(ip + i)] = POP();
|
||||||
|
}
|
||||||
|
ip += count;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ByteCodeInstruction::kStoreSwizzleIndirectGlobal: {
|
||||||
|
int target = POP().fSigned;
|
||||||
|
int count = READ8();
|
||||||
|
for (int i = count - 1; i >= 0; --i) {
|
||||||
|
fGlobals[target + *(ip + i)] = POP();
|
||||||
|
}
|
||||||
|
ip += count;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
VECTOR_BINARY_OP(kSubtractI, fSigned, -)
|
VECTOR_BINARY_OP(kSubtractI, fSigned, -)
|
||||||
VECTOR_BINARY_OP(kSubtractF, fFloat, -)
|
VECTOR_BINARY_OP(kSubtractF, fFloat, -)
|
||||||
|
@ -348,6 +348,144 @@ DEF_TEST(SkSLInterpreterSetInputs, r) {
|
|||||||
REPORTER_ASSERT(r, out == 5.0f);
|
REPORTER_ASSERT(r, out == 5.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEF_TEST(SkSLInterpreterCompound, r) {
|
||||||
|
struct RectAndColor { SkIRect fRect; SkColor4f fColor; };
|
||||||
|
struct ManyRects { int fNumRects; RectAndColor fRects[4]; };
|
||||||
|
|
||||||
|
const char* src =
|
||||||
|
// Some struct definitions
|
||||||
|
"struct Point { int x; int y; };\n"
|
||||||
|
"struct Rect { Point p0; Point p1; };\n"
|
||||||
|
"struct RectAndColor { Rect r; float4 color; };\n"
|
||||||
|
|
||||||
|
// Structs as globals, parameters, return values
|
||||||
|
"RectAndColor temp;\n"
|
||||||
|
"int rect_height(Rect r) { return r.p1.y - r.p0.y; }\n"
|
||||||
|
"RectAndColor make_blue_rect(int w, int h) {\n"
|
||||||
|
" temp.r.p0.x = temp.r.p0.y = 0;\n"
|
||||||
|
" temp.r.p1.x = w; temp.r.p1.y = h;\n"
|
||||||
|
" temp.color = float4(0, 1, 0, 1);\n"
|
||||||
|
" return temp;\n"
|
||||||
|
"}\n"
|
||||||
|
|
||||||
|
// Initialization and assignment of types larger than 4 slots
|
||||||
|
"RectAndColor init_big(RectAndColor r) { RectAndColor s = r; return s; }\n"
|
||||||
|
"RectAndColor copy_big(RectAndColor r) { RectAndColor s; s = r; return s; }\n"
|
||||||
|
|
||||||
|
// Same for arrays, including some non-constant indexing
|
||||||
|
"float tempFloats[8];\n"
|
||||||
|
"int median(int a[15]) { return a[7]; }\n"
|
||||||
|
"float[8] sums(float a[8]) {\n"
|
||||||
|
" float tempFloats[8];\n"
|
||||||
|
" tempFloats[0] = a[0];\n"
|
||||||
|
" for (int i = 1; i < 8; ++i) { tempFloats[i] = tempFloats[i - 1] + a[i]; }\n"
|
||||||
|
" return tempFloats;\n"
|
||||||
|
"}\n"
|
||||||
|
|
||||||
|
// Uniforms, array-of-structs, dynamic indices
|
||||||
|
"in uniform Rect gRects[4];\n"
|
||||||
|
"Rect get_rect(int i) { return gRects[i]; }\n"
|
||||||
|
|
||||||
|
// Kitchen sink (swizzles, inout, SoAoS)
|
||||||
|
"struct ManyRects { int numRects; RectAndColor rects[4]; };\n"
|
||||||
|
"void fill_rects(inout ManyRects mr) {\n"
|
||||||
|
" for (int i = 0; i < mr.numRects; ++i) {\n"
|
||||||
|
" mr.rects[i].r = gRects[i];\n"
|
||||||
|
" float b = mr.rects[i].r.p1.y;\n"
|
||||||
|
" mr.rects[i].color = float4(b, b, b, b);\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
SkSL::Compiler compiler;
|
||||||
|
SkSL::Program::Settings settings;
|
||||||
|
std::unique_ptr<SkSL::Program> program = compiler.convertProgram(
|
||||||
|
SkSL::Program::kGeneric_Kind,
|
||||||
|
SkSL::String(src), settings);
|
||||||
|
REPORTER_ASSERT(r, program);
|
||||||
|
|
||||||
|
std::unique_ptr<SkSL::ByteCode> byteCode = compiler.toByteCode(*program);
|
||||||
|
REPORTER_ASSERT(r, !compiler.errorCount());
|
||||||
|
|
||||||
|
auto rect_height = byteCode->getFunction("rect_height"),
|
||||||
|
make_blue_rect = byteCode->getFunction("make_blue_rect"),
|
||||||
|
median = byteCode->getFunction("median"),
|
||||||
|
sums = byteCode->getFunction("sums"),
|
||||||
|
get_rect = byteCode->getFunction("get_rect"),
|
||||||
|
fill_rects = byteCode->getFunction("fill_rects");
|
||||||
|
|
||||||
|
SkIRect gRects[4] = { { 1,2,3,4 }, { 5,6,7,8 }, { 9,10,11,12 }, { 13,14,15,16 } };
|
||||||
|
|
||||||
|
SkSL::Interpreter interpreter(std::move(program), std::move(byteCode),
|
||||||
|
(SkSL::Interpreter::Value*)gRects);
|
||||||
|
|
||||||
|
{
|
||||||
|
SkIRect in = SkIRect::MakeXYWH(10, 10, 20, 30);
|
||||||
|
int out = 0;
|
||||||
|
interpreter.run(*rect_height,
|
||||||
|
(SkSL::Interpreter::Value*)&in,
|
||||||
|
(SkSL::Interpreter::Value*)&out);
|
||||||
|
REPORTER_ASSERT(r, out == 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int in[2] = { 15, 25 };
|
||||||
|
RectAndColor out;
|
||||||
|
interpreter.run(*make_blue_rect,
|
||||||
|
(SkSL::Interpreter::Value*)in,
|
||||||
|
(SkSL::Interpreter::Value*)&out);
|
||||||
|
REPORTER_ASSERT(r, out.fRect.width() == 15);
|
||||||
|
REPORTER_ASSERT(r, out.fRect.height() == 25);
|
||||||
|
SkColor4f blue = { 0.0f, 1.0f, 0.0f, 1.0f };
|
||||||
|
REPORTER_ASSERT(r, out.fColor == blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int in[15] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
|
||||||
|
int out = 0;
|
||||||
|
interpreter.run(*median,
|
||||||
|
(SkSL::Interpreter::Value*)in,
|
||||||
|
(SkSL::Interpreter::Value*)&out);
|
||||||
|
REPORTER_ASSERT(r, out == 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
float in[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
|
||||||
|
float out[8] = { 0 };
|
||||||
|
interpreter.run(*sums,
|
||||||
|
(SkSL::Interpreter::Value*)in,
|
||||||
|
(SkSL::Interpreter::Value*)out);
|
||||||
|
for (int i = 0; i < 8; ++i) {
|
||||||
|
REPORTER_ASSERT(r, out[i] == static_cast<float>((i + 1) * (i + 2) / 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int in = 2;
|
||||||
|
SkIRect out = SkIRect::MakeEmpty();
|
||||||
|
interpreter.run(*get_rect,
|
||||||
|
(SkSL::Interpreter::Value*)&in,
|
||||||
|
(SkSL::Interpreter::Value*)&out);
|
||||||
|
REPORTER_ASSERT(r, out == gRects[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ManyRects in;
|
||||||
|
memset(&in, 0, sizeof(in));
|
||||||
|
in.fNumRects = 2;
|
||||||
|
interpreter.run(*fill_rects,
|
||||||
|
(SkSL::Interpreter::Value*)&in,
|
||||||
|
nullptr);
|
||||||
|
ManyRects expected;
|
||||||
|
memset(&expected, 0, sizeof(expected));
|
||||||
|
expected.fNumRects = 2;
|
||||||
|
for (int i = 0; i < 2; ++i) {
|
||||||
|
expected.fRects[i].fRect = gRects[i];
|
||||||
|
float c = gRects[i].fBottom;
|
||||||
|
expected.fRects[i].fColor = { c, c, c, c };
|
||||||
|
}
|
||||||
|
REPORTER_ASSERT(r, memcmp(&in, &expected, sizeof(in)) == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DEF_TEST(SkSLInterpreterFunctions, r) {
|
DEF_TEST(SkSLInterpreterFunctions, r) {
|
||||||
const char* src =
|
const char* src =
|
||||||
|
Loading…
Reference in New Issue
Block a user