Revert "Revert "moved BinaryExpression's data into IRNode""
This reverts commit b61c3a9a01
.
Change-Id: I4689e1f4977fab3233ff492cee06fbc301b5c689
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/317386
Reviewed-by: John Stiles <johnstiles@google.com>
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
This commit is contained in:
parent
b23ea385d4
commit
1d3e0e0054
@ -68,6 +68,7 @@ skia_sksl_sources = [
|
||||
"$_src/sksl/ir/SkSLFunctionCall.h",
|
||||
"$_src/sksl/ir/SkSLFunctionDefinition.h",
|
||||
"$_src/sksl/ir/SkSLFunctionReference.h",
|
||||
"$_src/sksl/ir/SkSLIRNode.cpp",
|
||||
"$_src/sksl/ir/SkSLIRNode.h",
|
||||
"$_src/sksl/ir/SkSLIfStatement.h",
|
||||
"$_src/sksl/ir/SkSLIndexExpression.h",
|
||||
|
@ -12,15 +12,11 @@
|
||||
#include "src/sksl/SkSLString.h"
|
||||
#include "src/sksl/ir/SkSLModifiers.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
// std::max isn't constexpr in some compilers
|
||||
static constexpr size_t Max(size_t a, size_t b) {
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a node in the abstract syntax tree (AST). The AST is based directly on the parse tree;
|
||||
* it is a parsed-but-not-yet-analyzed version of the program.
|
||||
@ -267,18 +263,18 @@ struct ASTNode {
|
||||
};
|
||||
|
||||
struct NodeData {
|
||||
char fBytes[Max(sizeof(Token),
|
||||
Max(sizeof(StringFragment),
|
||||
Max(sizeof(bool),
|
||||
Max(sizeof(SKSL_INT),
|
||||
Max(sizeof(SKSL_FLOAT),
|
||||
Max(sizeof(Modifiers),
|
||||
Max(sizeof(TypeData),
|
||||
Max(sizeof(FunctionData),
|
||||
Max(sizeof(ParameterData),
|
||||
Max(sizeof(VarData),
|
||||
Max(sizeof(InterfaceBlockData),
|
||||
sizeof(SectionData))))))))))))];
|
||||
char fBytes[std::max(sizeof(Token),
|
||||
std::max(sizeof(StringFragment),
|
||||
std::max(sizeof(bool),
|
||||
std::max(sizeof(SKSL_INT),
|
||||
std::max(sizeof(SKSL_FLOAT),
|
||||
std::max(sizeof(Modifiers),
|
||||
std::max(sizeof(TypeData),
|
||||
std::max(sizeof(FunctionData),
|
||||
std::max(sizeof(ParameterData),
|
||||
std::max(sizeof(VarData),
|
||||
std::max(sizeof(InterfaceBlockData),
|
||||
sizeof(SectionData))))))))))))];
|
||||
|
||||
enum class Kind {
|
||||
kToken,
|
||||
|
@ -266,7 +266,7 @@ bool ProgramVisitor::visitExpression(const Expression& e) {
|
||||
return false;
|
||||
case Expression::Kind::kBinary: {
|
||||
const BinaryExpression& b = e.as<BinaryExpression>();
|
||||
return this->visitExpression(*b.fLeft) || this->visitExpression(*b.fRight); }
|
||||
return this->visitExpression(b.left()) || this->visitExpression(b.right()); }
|
||||
case Expression::Kind::kConstructor: {
|
||||
const Constructor& c = e.as<Constructor>();
|
||||
for (const auto& arg : c.fArguments) {
|
||||
|
@ -681,28 +681,29 @@ void ByteCodeGenerator::writeTypedInstruction(const Type& type,
|
||||
}
|
||||
|
||||
bool ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b, bool discard) {
|
||||
if (b.fOperator == Token::Kind::TK_EQ) {
|
||||
std::unique_ptr<LValue> lvalue = this->getLValue(*b.fLeft);
|
||||
this->writeExpression(*b.fRight);
|
||||
const Expression& left = b.left();
|
||||
const Expression& right = b.right();
|
||||
Token::Kind op = b.getOperator();
|
||||
if (op == Token::Kind::TK_EQ) {
|
||||
std::unique_ptr<LValue> lvalue = this->getLValue(left);
|
||||
this->writeExpression(right);
|
||||
lvalue->store(discard);
|
||||
discard = false;
|
||||
return discard;
|
||||
}
|
||||
const Type& lType = b.fLeft->type();
|
||||
const Type& rType = b.fRight->type();
|
||||
const Type& lType = left.type();
|
||||
const Type& rType = right.type();
|
||||
bool lVecOrMtx = (lType.typeKind() == Type::TypeKind::kVector ||
|
||||
lType.typeKind() == Type::TypeKind::kMatrix);
|
||||
bool rVecOrMtx = (rType.typeKind() == Type::TypeKind::kVector ||
|
||||
rType.typeKind() == Type::TypeKind::kMatrix);
|
||||
Token::Kind op;
|
||||
std::unique_ptr<LValue> lvalue;
|
||||
if (Compiler::IsAssignment(b.fOperator)) {
|
||||
lvalue = this->getLValue(*b.fLeft);
|
||||
if (Compiler::IsAssignment(op)) {
|
||||
lvalue = this->getLValue(left);
|
||||
lvalue->load();
|
||||
op = Compiler::RemoveAssignment(b.fOperator);
|
||||
op = Compiler::RemoveAssignment(op);
|
||||
} else {
|
||||
this->writeExpression(*b.fLeft);
|
||||
op = b.fOperator;
|
||||
this->writeExpression(left);
|
||||
if (!lVecOrMtx && rVecOrMtx) {
|
||||
for (int i = SlotCount(rType); i > 1; --i) {
|
||||
this->write(ByteCodeInstruction::kDup, 1);
|
||||
@ -718,7 +719,7 @@ bool ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b, bool di
|
||||
this->write(ByteCodeInstruction::kMaskPush);
|
||||
this->write(ByteCodeInstruction::kBranchIfAllFalse);
|
||||
DeferredLocation falseLocation(this);
|
||||
this->writeExpression(*b.fRight);
|
||||
this->writeExpression(right);
|
||||
this->write(ByteCodeInstruction::kAndB, 1);
|
||||
falseLocation.set();
|
||||
this->write(ByteCodeInstruction::kMaskPop);
|
||||
@ -731,7 +732,7 @@ bool ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b, bool di
|
||||
this->write(ByteCodeInstruction::kMaskPush);
|
||||
this->write(ByteCodeInstruction::kBranchIfAllFalse);
|
||||
DeferredLocation falseLocation(this);
|
||||
this->writeExpression(*b.fRight);
|
||||
this->writeExpression(right);
|
||||
this->write(ByteCodeInstruction::kOrB, 1);
|
||||
falseLocation.set();
|
||||
this->write(ByteCodeInstruction::kMaskPop);
|
||||
@ -741,13 +742,13 @@ bool ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b, bool di
|
||||
case Token::Kind::TK_SHR: {
|
||||
SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
|
||||
tc == SkSL::TypeCategory::kUnsigned));
|
||||
if (!b.fRight->isCompileTimeConstant()) {
|
||||
fErrors.error(b.fRight->fOffset, "Shift amounts must be constant");
|
||||
if (!right.isCompileTimeConstant()) {
|
||||
fErrors.error(right.fOffset, "Shift amounts must be constant");
|
||||
return false;
|
||||
}
|
||||
int64_t shift = b.fRight->getConstantInt();
|
||||
int64_t shift = right.getConstantInt();
|
||||
if (shift < 0 || shift > 31) {
|
||||
fErrors.error(b.fRight->fOffset, "Shift amount out of range");
|
||||
fErrors.error(right.fOffset, "Shift amount out of range");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -765,7 +766,7 @@ bool ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b, bool di
|
||||
default:
|
||||
break;
|
||||
}
|
||||
this->writeExpression(*b.fRight);
|
||||
this->writeExpression(right);
|
||||
if (lVecOrMtx && !rVecOrMtx) {
|
||||
for (int i = SlotCount(lType); i > 1; --i) {
|
||||
this->write(ByteCodeInstruction::kDup, 1);
|
||||
|
@ -166,14 +166,14 @@ bool BasicBlock::tryRemoveExpression(std::vector<BasicBlock::Node>::iterator* it
|
||||
switch (expr->kind()) {
|
||||
case Expression::Kind::kBinary: {
|
||||
BinaryExpression& b = expr->as<BinaryExpression>();
|
||||
if (b.fOperator == Token::Kind::TK_EQ) {
|
||||
if (!this->tryRemoveLValueBefore(iter, b.fLeft.get())) {
|
||||
if (b.getOperator() == Token::Kind::TK_EQ) {
|
||||
if (!this->tryRemoveLValueBefore(iter, &b.left())) {
|
||||
return false;
|
||||
}
|
||||
} else if (!this->tryRemoveExpressionBefore(iter, b.fLeft.get())) {
|
||||
} else if (!this->tryRemoveExpressionBefore(iter, &b.left())) {
|
||||
return false;
|
||||
}
|
||||
if (!this->tryRemoveExpressionBefore(iter, b.fRight.get())) {
|
||||
if (!this->tryRemoveExpressionBefore(iter, &b.right())) {
|
||||
return false;
|
||||
}
|
||||
SkASSERT((*iter)->expression()->get() == expr);
|
||||
@ -267,11 +267,12 @@ bool BasicBlock::tryInsertExpression(std::vector<BasicBlock::Node>::iterator* it
|
||||
switch ((*expr)->kind()) {
|
||||
case Expression::Kind::kBinary: {
|
||||
BinaryExpression& b = expr->get()->as<BinaryExpression>();
|
||||
if (!this->tryInsertExpression(iter, &b.fRight)) {
|
||||
if (!this->tryInsertExpression(iter, &b.rightPointer())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
++(*iter);
|
||||
if (!this->tryInsertExpression(iter, &b.fLeft)) {
|
||||
if (!this->tryInsertExpression(iter, &b.leftPointer())) {
|
||||
return false;
|
||||
}
|
||||
++(*iter);
|
||||
@ -319,16 +320,17 @@ void CFGGenerator::addExpression(CFG& cfg, std::unique_ptr<Expression>* e, bool
|
||||
switch ((*e)->kind()) {
|
||||
case Expression::Kind::kBinary: {
|
||||
BinaryExpression& b = e->get()->as<BinaryExpression>();
|
||||
switch (b.fOperator) {
|
||||
Token::Kind op = b.getOperator();
|
||||
switch (op) {
|
||||
case Token::Kind::TK_LOGICALAND: // fall through
|
||||
case Token::Kind::TK_LOGICALOR: {
|
||||
// this isn't as precise as it could be -- we don't bother to track that if we
|
||||
// early exit from a logical and/or, we know which branch of an 'if' we're going
|
||||
// to hit -- but it won't make much difference in practice.
|
||||
this->addExpression(cfg, &b.fLeft, constantPropagate);
|
||||
this->addExpression(cfg, &b.leftPointer(), constantPropagate);
|
||||
BlockId start = cfg.fCurrent;
|
||||
cfg.newBlock();
|
||||
this->addExpression(cfg, &b.fRight, constantPropagate);
|
||||
this->addExpression(cfg, &b.rightPointer(), constantPropagate);
|
||||
cfg.newBlock();
|
||||
cfg.addExit(start, cfg.fCurrent);
|
||||
cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
|
||||
@ -340,8 +342,8 @@ void CFGGenerator::addExpression(CFG& cfg, std::unique_ptr<Expression>* e, bool
|
||||
break;
|
||||
}
|
||||
case Token::Kind::TK_EQ: {
|
||||
this->addExpression(cfg, &b.fRight, constantPropagate);
|
||||
this->addLValue(cfg, &b.fLeft);
|
||||
this->addExpression(cfg, &b.rightPointer(), constantPropagate);
|
||||
this->addLValue(cfg, &b.leftPointer());
|
||||
cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
|
||||
BasicBlock::Node::kExpression_Kind,
|
||||
constantPropagate,
|
||||
@ -351,8 +353,8 @@ void CFGGenerator::addExpression(CFG& cfg, std::unique_ptr<Expression>* e, bool
|
||||
break;
|
||||
}
|
||||
default:
|
||||
this->addExpression(cfg, &b.fLeft, !Compiler::IsAssignment(b.fOperator));
|
||||
this->addExpression(cfg, &b.fRight, constantPropagate);
|
||||
this->addExpression(cfg, &b.leftPointer(), !Compiler::IsAssignment(op));
|
||||
this->addExpression(cfg, &b.rightPointer(), constantPropagate);
|
||||
cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
|
||||
BasicBlock::Node::kExpression_Kind,
|
||||
constantPropagate,
|
||||
|
@ -70,42 +70,45 @@ String CPPCodeGenerator::getTypeName(const Type& type) {
|
||||
|
||||
void CPPCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
|
||||
Precedence parentPrecedence) {
|
||||
if (b.fOperator == Token::Kind::TK_PERCENT) {
|
||||
const Expression& left = b.left();
|
||||
const Expression& right = b.right();
|
||||
Token::Kind op = b.getOperator();
|
||||
if (op == Token::Kind::TK_PERCENT) {
|
||||
// need to use "%%" instead of "%" b/c the code will be inside of a printf
|
||||
Precedence precedence = GetBinaryPrecedence(b.fOperator);
|
||||
Precedence precedence = GetBinaryPrecedence(op);
|
||||
if (precedence >= parentPrecedence) {
|
||||
this->write("(");
|
||||
}
|
||||
this->writeExpression(*b.fLeft, precedence);
|
||||
this->writeExpression(left, precedence);
|
||||
this->write(" %% ");
|
||||
this->writeExpression(*b.fRight, precedence);
|
||||
this->writeExpression(right, precedence);
|
||||
if (precedence >= parentPrecedence) {
|
||||
this->write(")");
|
||||
}
|
||||
} else if (b.fLeft->kind() == Expression::Kind::kNullLiteral ||
|
||||
b.fRight->kind() == Expression::Kind::kNullLiteral) {
|
||||
} else if (left.kind() == Expression::Kind::kNullLiteral ||
|
||||
right.kind() == Expression::Kind::kNullLiteral) {
|
||||
const Variable* var;
|
||||
if (b.fLeft->kind() != Expression::Kind::kNullLiteral) {
|
||||
var = &b.fLeft->as<VariableReference>().fVariable;
|
||||
if (left.kind() != Expression::Kind::kNullLiteral) {
|
||||
var = &left.as<VariableReference>().fVariable;
|
||||
} else {
|
||||
var = &b.fRight->as<VariableReference>().fVariable;
|
||||
var = &right.as<VariableReference>().fVariable;
|
||||
}
|
||||
SkASSERT(var->type().typeKind() == Type::TypeKind::kNullable &&
|
||||
var->type().componentType() == *fContext.fFragmentProcessor_Type);
|
||||
this->write("%s");
|
||||
const char* op = "";
|
||||
switch (b.fOperator) {
|
||||
const char* prefix = "";
|
||||
switch (op) {
|
||||
case Token::Kind::TK_EQEQ:
|
||||
op = "!";
|
||||
prefix = "!";
|
||||
break;
|
||||
case Token::Kind::TK_NEQ:
|
||||
op = "";
|
||||
prefix = "";
|
||||
break;
|
||||
default:
|
||||
SkASSERT(false);
|
||||
}
|
||||
int childIndex = this->getChildFPIndex(*var);
|
||||
fFormatArgs.push_back(String(op) + "_outer.childProcessor(" + to_string(childIndex) +
|
||||
fFormatArgs.push_back(String(prefix) + "_outer.childProcessor(" + to_string(childIndex) +
|
||||
") ? \"true\" : \"false\"");
|
||||
} else {
|
||||
INHERITED::writeBinaryExpression(b, parentPrecedence);
|
||||
|
@ -436,11 +436,11 @@ void Compiler::addDefinitions(const BasicBlock::Node& node,
|
||||
switch (expr->kind()) {
|
||||
case Expression::Kind::kBinary: {
|
||||
BinaryExpression* b = &expr->as<BinaryExpression>();
|
||||
if (b->fOperator == Token::Kind::TK_EQ) {
|
||||
this->addDefinition(b->fLeft.get(), &b->fRight, definitions);
|
||||
} else if (Compiler::IsAssignment(b->fOperator)) {
|
||||
if (b->getOperator() == Token::Kind::TK_EQ) {
|
||||
this->addDefinition(&b->left(), &b->rightPointer(), definitions);
|
||||
} else if (Compiler::IsAssignment(b->getOperator())) {
|
||||
this->addDefinition(
|
||||
b->fLeft.get(),
|
||||
&b->left(),
|
||||
(std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
|
||||
definitions);
|
||||
|
||||
@ -607,10 +607,10 @@ static bool is_dead(const Expression& lvalue) {
|
||||
* to a dead target and lack of side effects on the left hand side.
|
||||
*/
|
||||
static bool dead_assignment(const BinaryExpression& b) {
|
||||
if (!Compiler::IsAssignment(b.fOperator)) {
|
||||
if (!Compiler::IsAssignment(b.getOperator())) {
|
||||
return false;
|
||||
}
|
||||
return is_dead(*b.fLeft);
|
||||
return is_dead(b.left());
|
||||
}
|
||||
|
||||
void Compiler::computeDataFlow(CFG* cfg) {
|
||||
@ -705,14 +705,16 @@ static void delete_left(BasicBlock* b,
|
||||
*outUpdated = true;
|
||||
std::unique_ptr<Expression>* target = (*iter)->expression();
|
||||
BinaryExpression& bin = (*target)->as<BinaryExpression>();
|
||||
SkASSERT(!bin.fLeft->hasSideEffects());
|
||||
Expression& left = bin.left();
|
||||
std::unique_ptr<Expression>& rightPointer = bin.rightPointer();
|
||||
SkASSERT(!left.hasSideEffects());
|
||||
bool result;
|
||||
if (bin.fOperator == Token::Kind::TK_EQ) {
|
||||
result = b->tryRemoveLValueBefore(iter, bin.fLeft.get());
|
||||
if (bin.getOperator() == Token::Kind::TK_EQ) {
|
||||
result = b->tryRemoveLValueBefore(iter, &left);
|
||||
} else {
|
||||
result = b->tryRemoveExpressionBefore(iter, bin.fLeft.get());
|
||||
result = b->tryRemoveExpressionBefore(iter, &left);
|
||||
}
|
||||
*target = std::move(bin.fRight);
|
||||
*target = std::move(rightPointer);
|
||||
if (!result) {
|
||||
*outNeedsRescan = true;
|
||||
return;
|
||||
@ -723,7 +725,7 @@ static void delete_left(BasicBlock* b,
|
||||
}
|
||||
--(*iter);
|
||||
if ((*iter)->fKind != BasicBlock::Node::kExpression_Kind ||
|
||||
(*iter)->expression() != &bin.fRight) {
|
||||
(*iter)->expression() != &rightPointer) {
|
||||
*outNeedsRescan = true;
|
||||
return;
|
||||
}
|
||||
@ -742,20 +744,22 @@ static void delete_right(BasicBlock* b,
|
||||
*outUpdated = true;
|
||||
std::unique_ptr<Expression>* target = (*iter)->expression();
|
||||
BinaryExpression& bin = (*target)->as<BinaryExpression>();
|
||||
SkASSERT(!bin.fRight->hasSideEffects());
|
||||
if (!b->tryRemoveExpressionBefore(iter, bin.fRight.get())) {
|
||||
*target = std::move(bin.fLeft);
|
||||
std::unique_ptr<Expression>& leftPointer = bin.leftPointer();
|
||||
Expression& right = bin.right();
|
||||
SkASSERT(!right.hasSideEffects());
|
||||
if (!b->tryRemoveExpressionBefore(iter, &right)) {
|
||||
*target = std::move(leftPointer);
|
||||
*outNeedsRescan = true;
|
||||
return;
|
||||
}
|
||||
*target = std::move(bin.fLeft);
|
||||
*target = std::move(leftPointer);
|
||||
if (*iter == b->fNodes.begin()) {
|
||||
*outNeedsRescan = true;
|
||||
return;
|
||||
}
|
||||
--(*iter);
|
||||
if (((*iter)->fKind != BasicBlock::Node::kExpression_Kind ||
|
||||
(*iter)->expression() != &bin.fLeft)) {
|
||||
(*iter)->expression() != &leftPointer)) {
|
||||
*outNeedsRescan = true;
|
||||
return;
|
||||
}
|
||||
@ -808,7 +812,7 @@ static void vectorize_left(BasicBlock* b,
|
||||
bool* outUpdated,
|
||||
bool* outNeedsRescan) {
|
||||
BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
|
||||
vectorize(b, iter, bin.fRight->type(), &bin.fLeft, outUpdated, outNeedsRescan);
|
||||
vectorize(b, iter, bin.right().type(), &bin.leftPointer(), outUpdated, outNeedsRescan);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -820,7 +824,7 @@ static void vectorize_right(BasicBlock* b,
|
||||
bool* outUpdated,
|
||||
bool* outNeedsRescan) {
|
||||
BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
|
||||
vectorize(b, iter, bin.fLeft->type(), &bin.fRight, outUpdated, outNeedsRescan);
|
||||
vectorize(b, iter, bin.left().type(), &bin.rightPointer(), outUpdated, outNeedsRescan);
|
||||
}
|
||||
|
||||
// Mark that an expression which we were writing to is no longer being written to
|
||||
@ -902,8 +906,10 @@ void Compiler::simplifyExpression(DefinitionMap& definitions,
|
||||
delete_left(&b, iter, outUpdated, outNeedsRescan);
|
||||
break;
|
||||
}
|
||||
const Type& leftType = bin->fLeft->type();
|
||||
const Type& rightType = bin->fRight->type();
|
||||
Expression& left = bin->left();
|
||||
Expression& right = bin->right();
|
||||
const Type& leftType = left.type();
|
||||
const Type& rightType = right.type();
|
||||
// collapse useless expressions like x * 1 or x + 0
|
||||
if (((leftType.typeKind() != Type::TypeKind::kScalar) &&
|
||||
(leftType.typeKind() != Type::TypeKind::kVector)) ||
|
||||
@ -911,9 +917,9 @@ void Compiler::simplifyExpression(DefinitionMap& definitions,
|
||||
(rightType.typeKind() != Type::TypeKind::kVector))) {
|
||||
break;
|
||||
}
|
||||
switch (bin->fOperator) {
|
||||
switch (bin->getOperator()) {
|
||||
case Token::Kind::TK_STAR:
|
||||
if (is_constant(*bin->fLeft, 1)) {
|
||||
if (is_constant(left, 1)) {
|
||||
if (leftType.typeKind() == Type::TypeKind::kVector &&
|
||||
rightType.typeKind() == Type::TypeKind::kScalar) {
|
||||
// float4(1) * x -> float4(x)
|
||||
@ -925,22 +931,22 @@ void Compiler::simplifyExpression(DefinitionMap& definitions,
|
||||
delete_left(&b, iter, outUpdated, outNeedsRescan);
|
||||
}
|
||||
}
|
||||
else if (is_constant(*bin->fLeft, 0)) {
|
||||
else if (is_constant(left, 0)) {
|
||||
if (leftType.typeKind() == Type::TypeKind::kScalar &&
|
||||
rightType.typeKind() == Type::TypeKind::kVector &&
|
||||
!bin->fRight->hasSideEffects()) {
|
||||
!right.hasSideEffects()) {
|
||||
// 0 * float4(x) -> float4(0)
|
||||
vectorize_left(&b, iter, outUpdated, outNeedsRescan);
|
||||
} else {
|
||||
// 0 * x -> 0
|
||||
// float4(0) * x -> float4(0)
|
||||
// float4(0) * float4(x) -> float4(0)
|
||||
if (!bin->fRight->hasSideEffects()) {
|
||||
if (!right.hasSideEffects()) {
|
||||
delete_right(&b, iter, outUpdated, outNeedsRescan);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (is_constant(*bin->fRight, 1)) {
|
||||
else if (is_constant(right, 1)) {
|
||||
if (leftType.typeKind() == Type::TypeKind::kScalar &&
|
||||
rightType.typeKind() == Type::TypeKind::kVector) {
|
||||
// x * float4(1) -> float4(x)
|
||||
@ -952,24 +958,24 @@ void Compiler::simplifyExpression(DefinitionMap& definitions,
|
||||
delete_right(&b, iter, outUpdated, outNeedsRescan);
|
||||
}
|
||||
}
|
||||
else if (is_constant(*bin->fRight, 0)) {
|
||||
else if (is_constant(right, 0)) {
|
||||
if (leftType.typeKind() == Type::TypeKind::kVector &&
|
||||
rightType.typeKind() == Type::TypeKind::kScalar &&
|
||||
!bin->fLeft->hasSideEffects()) {
|
||||
!left.hasSideEffects()) {
|
||||
// float4(x) * 0 -> float4(0)
|
||||
vectorize_right(&b, iter, outUpdated, outNeedsRescan);
|
||||
} else {
|
||||
// x * 0 -> 0
|
||||
// x * float4(0) -> float4(0)
|
||||
// float4(x) * float4(0) -> float4(0)
|
||||
if (!bin->fLeft->hasSideEffects()) {
|
||||
if (!left.hasSideEffects()) {
|
||||
delete_left(&b, iter, outUpdated, outNeedsRescan);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Token::Kind::TK_PLUS:
|
||||
if (is_constant(*bin->fLeft, 0)) {
|
||||
if (is_constant(left, 0)) {
|
||||
if (leftType.typeKind() == Type::TypeKind::kVector &&
|
||||
rightType.typeKind() == Type::TypeKind::kScalar) {
|
||||
// float4(0) + x -> float4(x)
|
||||
@ -980,7 +986,7 @@ void Compiler::simplifyExpression(DefinitionMap& definitions,
|
||||
// float4(0) + float4(x) -> float4(x)
|
||||
delete_left(&b, iter, outUpdated, outNeedsRescan);
|
||||
}
|
||||
} else if (is_constant(*bin->fRight, 0)) {
|
||||
} else if (is_constant(right, 0)) {
|
||||
if (leftType.typeKind() == Type::TypeKind::kScalar &&
|
||||
rightType.typeKind() == Type::TypeKind::kVector) {
|
||||
// x + float4(0) -> float4(x)
|
||||
@ -994,7 +1000,7 @@ void Compiler::simplifyExpression(DefinitionMap& definitions,
|
||||
}
|
||||
break;
|
||||
case Token::Kind::TK_MINUS:
|
||||
if (is_constant(*bin->fRight, 0)) {
|
||||
if (is_constant(right, 0)) {
|
||||
if (leftType.typeKind() == Type::TypeKind::kScalar &&
|
||||
rightType.typeKind() == Type::TypeKind::kVector) {
|
||||
// x - float4(0) -> float4(x)
|
||||
@ -1008,7 +1014,7 @@ void Compiler::simplifyExpression(DefinitionMap& definitions,
|
||||
}
|
||||
break;
|
||||
case Token::Kind::TK_SLASH:
|
||||
if (is_constant(*bin->fRight, 1)) {
|
||||
if (is_constant(right, 1)) {
|
||||
if (leftType.typeKind() == Type::TypeKind::kScalar &&
|
||||
rightType.typeKind() == Type::TypeKind::kVector) {
|
||||
// x / float4(1) -> float4(x)
|
||||
@ -1019,43 +1025,43 @@ void Compiler::simplifyExpression(DefinitionMap& definitions,
|
||||
// float4(x) / float4(1) -> float4(x)
|
||||
delete_right(&b, iter, outUpdated, outNeedsRescan);
|
||||
}
|
||||
} else if (is_constant(*bin->fLeft, 0)) {
|
||||
} else if (is_constant(left, 0)) {
|
||||
if (leftType.typeKind() == Type::TypeKind::kScalar &&
|
||||
rightType.typeKind() == Type::TypeKind::kVector &&
|
||||
!bin->fRight->hasSideEffects()) {
|
||||
!right.hasSideEffects()) {
|
||||
// 0 / float4(x) -> float4(0)
|
||||
vectorize_left(&b, iter, outUpdated, outNeedsRescan);
|
||||
} else {
|
||||
// 0 / x -> 0
|
||||
// float4(0) / x -> float4(0)
|
||||
// float4(0) / float4(x) -> float4(0)
|
||||
if (!bin->fRight->hasSideEffects()) {
|
||||
if (!right.hasSideEffects()) {
|
||||
delete_right(&b, iter, outUpdated, outNeedsRescan);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Token::Kind::TK_PLUSEQ:
|
||||
if (is_constant(*bin->fRight, 0)) {
|
||||
clear_write(*bin->fLeft);
|
||||
if (is_constant(right, 0)) {
|
||||
clear_write(left);
|
||||
delete_right(&b, iter, outUpdated, outNeedsRescan);
|
||||
}
|
||||
break;
|
||||
case Token::Kind::TK_MINUSEQ:
|
||||
if (is_constant(*bin->fRight, 0)) {
|
||||
clear_write(*bin->fLeft);
|
||||
if (is_constant(right, 0)) {
|
||||
clear_write(left);
|
||||
delete_right(&b, iter, outUpdated, outNeedsRescan);
|
||||
}
|
||||
break;
|
||||
case Token::Kind::TK_STAREQ:
|
||||
if (is_constant(*bin->fRight, 1)) {
|
||||
clear_write(*bin->fLeft);
|
||||
if (is_constant(right, 1)) {
|
||||
clear_write(left);
|
||||
delete_right(&b, iter, outUpdated, outNeedsRescan);
|
||||
}
|
||||
break;
|
||||
case Token::Kind::TK_SLASHEQ:
|
||||
if (is_constant(*bin->fRight, 1)) {
|
||||
clear_write(*bin->fLeft);
|
||||
if (is_constant(right, 1)) {
|
||||
clear_write(left);
|
||||
delete_right(&b, iter, outUpdated, outNeedsRescan);
|
||||
}
|
||||
break;
|
||||
|
@ -258,9 +258,9 @@ void Dehydrator::write(const Expression* e) {
|
||||
case Expression::Kind::kBinary: {
|
||||
const BinaryExpression& b = e->as<BinaryExpression>();
|
||||
this->writeU8(Rehydrator::kBinary_Command);
|
||||
this->write(b.fLeft.get());
|
||||
this->writeU8((int) b.fOperator);
|
||||
this->write(b.fRight.get());
|
||||
this->write(&b.left());
|
||||
this->writeU8((int) b.getOperator());
|
||||
this->write(&b.right());
|
||||
this->write(b.type());
|
||||
break;
|
||||
}
|
||||
|
@ -913,31 +913,33 @@ GLSLCodeGenerator::Precedence GLSLCodeGenerator::GetBinaryPrecedence(Token::Kind
|
||||
|
||||
void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
|
||||
Precedence parentPrecedence) {
|
||||
const Expression& left = b.left();
|
||||
const Expression& right = b.right();
|
||||
Token::Kind op = b.getOperator();
|
||||
if (fProgram.fSettings.fCaps->unfoldShortCircuitAsTernary() &&
|
||||
(b.fOperator == Token::Kind::TK_LOGICALAND ||
|
||||
b.fOperator == Token::Kind::TK_LOGICALOR)) {
|
||||
(op == Token::Kind::TK_LOGICALAND || op == Token::Kind::TK_LOGICALOR)) {
|
||||
this->writeShortCircuitWorkaroundExpression(b, parentPrecedence);
|
||||
return;
|
||||
}
|
||||
|
||||
Precedence precedence = GetBinaryPrecedence(b.fOperator);
|
||||
Precedence precedence = GetBinaryPrecedence(op);
|
||||
if (precedence >= parentPrecedence) {
|
||||
this->write("(");
|
||||
}
|
||||
bool positionWorkaround = fProgramKind == Program::Kind::kVertex_Kind &&
|
||||
Compiler::IsAssignment(b.fOperator) &&
|
||||
b.fLeft->kind() == Expression::Kind::kFieldAccess &&
|
||||
is_sk_position((FieldAccess&) *b.fLeft) &&
|
||||
!b.fRight->containsRTAdjust() &&
|
||||
Compiler::IsAssignment(op) &&
|
||||
left.kind() == Expression::Kind::kFieldAccess &&
|
||||
is_sk_position((FieldAccess&) left) &&
|
||||
!right.containsRTAdjust() &&
|
||||
!fProgram.fSettings.fCaps->canUseFragCoord();
|
||||
if (positionWorkaround) {
|
||||
this->write("sk_FragCoord_Workaround = (");
|
||||
}
|
||||
this->writeExpression(*b.fLeft, precedence);
|
||||
this->writeExpression(left, precedence);
|
||||
this->write(" ");
|
||||
this->write(Compiler::OperatorName(b.fOperator));
|
||||
this->write(Compiler::OperatorName(op));
|
||||
this->write(" ");
|
||||
this->writeExpression(*b.fRight, precedence);
|
||||
this->writeExpression(right, precedence);
|
||||
if (positionWorkaround) {
|
||||
this->write(")");
|
||||
}
|
||||
@ -955,20 +957,20 @@ void GLSLCodeGenerator::writeShortCircuitWorkaroundExpression(const BinaryExpres
|
||||
// Transform:
|
||||
// a && b => a ? b : false
|
||||
// a || b => a ? true : b
|
||||
this->writeExpression(*b.fLeft, kTernary_Precedence);
|
||||
this->writeExpression(b.left(), kTernary_Precedence);
|
||||
this->write(" ? ");
|
||||
if (b.fOperator == Token::Kind::TK_LOGICALAND) {
|
||||
this->writeExpression(*b.fRight, kTernary_Precedence);
|
||||
if (b.getOperator() == Token::Kind::TK_LOGICALAND) {
|
||||
this->writeExpression(b.right(), kTernary_Precedence);
|
||||
} else {
|
||||
BoolLiteral boolTrue(fContext, -1, true);
|
||||
this->writeBoolLiteral(boolTrue);
|
||||
}
|
||||
this->write(" : ");
|
||||
if (b.fOperator == Token::Kind::TK_LOGICALAND) {
|
||||
if (b.getOperator() == Token::Kind::TK_LOGICALAND) {
|
||||
BoolLiteral boolFalse(fContext, -1, false);
|
||||
this->writeBoolLiteral(boolFalse);
|
||||
} else {
|
||||
this->writeExpression(*b.fRight, kTernary_Precedence);
|
||||
this->writeExpression(b.right(), kTernary_Precedence);
|
||||
}
|
||||
if (kTernary_Precedence >= parentPrecedence) {
|
||||
this->write(")");
|
||||
|
@ -308,9 +308,9 @@ std::unique_ptr<Expression> Inliner::inlineExpression(int offset,
|
||||
case Expression::Kind::kBinary: {
|
||||
const BinaryExpression& b = expression.as<BinaryExpression>();
|
||||
return std::make_unique<BinaryExpression>(offset,
|
||||
expr(b.fLeft),
|
||||
b.fOperator,
|
||||
expr(b.fRight),
|
||||
expr(b.leftPointer()),
|
||||
b.getOperator(),
|
||||
expr(b.rightPointer()),
|
||||
&b.type());
|
||||
}
|
||||
case Expression::Kind::kBoolLiteral:
|
||||
@ -938,7 +938,7 @@ bool Inliner::analyze(Program& program) {
|
||||
|
||||
case Expression::Kind::kBinary: {
|
||||
BinaryExpression& binaryExpr = (*expr)->as<BinaryExpression>();
|
||||
this->visitExpression(&binaryExpr.fLeft);
|
||||
this->visitExpression(&binaryExpr.leftPointer());
|
||||
|
||||
// Logical-and and logical-or binary expressions do not inline the right side,
|
||||
// because that would invalidate short-circuiting. That is, when evaluating
|
||||
@ -948,10 +948,11 @@ bool Inliner::analyze(Program& program) {
|
||||
// It is illegal for side-effects from x() or y() to occur. The simplest way to
|
||||
// enforce that rule is to avoid inlining the right side entirely. However, it
|
||||
// is safe for other types of binary expression to inline both sides.
|
||||
bool shortCircuitable = (binaryExpr.fOperator == Token::Kind::TK_LOGICALAND ||
|
||||
binaryExpr.fOperator == Token::Kind::TK_LOGICALOR);
|
||||
Token::Kind op = binaryExpr.getOperator();
|
||||
bool shortCircuitable = (op == Token::Kind::TK_LOGICALAND ||
|
||||
op == Token::Kind::TK_LOGICALOR);
|
||||
if (!shortCircuitable) {
|
||||
this->visitExpression(&binaryExpr.fRight);
|
||||
this->visitExpression(&binaryExpr.rightPointer());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -808,11 +808,14 @@ void MetalCodeGenerator::writeMatrixTimesEqualHelper(const Type& left, const Typ
|
||||
|
||||
void MetalCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
|
||||
Precedence parentPrecedence) {
|
||||
const Type& leftType = b.fLeft->type();
|
||||
const Type& rightType = b.fRight->type();
|
||||
Precedence precedence = GetBinaryPrecedence(b.fOperator);
|
||||
const Expression& left = b.left();
|
||||
const Expression& right = b.right();
|
||||
const Type& leftType = left.type();
|
||||
const Type& rightType = right.type();
|
||||
Token::Kind op = b.getOperator();
|
||||
Precedence precedence = GetBinaryPrecedence(b.getOperator());
|
||||
bool needParens = precedence >= parentPrecedence;
|
||||
switch (b.fOperator) {
|
||||
switch (op) {
|
||||
case Token::Kind::TK_EQEQ:
|
||||
if (leftType.typeKind() == Type::TypeKind::kVector) {
|
||||
this->write("all");
|
||||
@ -831,22 +834,21 @@ void MetalCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
|
||||
if (needParens) {
|
||||
this->write("(");
|
||||
}
|
||||
if (Compiler::IsAssignment(b.fOperator) &&
|
||||
Expression::Kind::kVariableReference == b.fLeft->kind() &&
|
||||
Variable::kParameter_Storage == ((VariableReference&) *b.fLeft).fVariable.fStorage &&
|
||||
(((VariableReference&) *b.fLeft).fVariable.fModifiers.fFlags & Modifiers::kOut_Flag)) {
|
||||
if (Compiler::IsAssignment(op) &&
|
||||
Expression::Kind::kVariableReference == left.kind() &&
|
||||
Variable::kParameter_Storage == left.as<VariableReference>().fVariable.fStorage &&
|
||||
left.as<VariableReference>().fVariable.fModifiers.fFlags & Modifiers::kOut_Flag) {
|
||||
// writing to an out parameter. Since we have to turn those into pointers, we have to
|
||||
// dereference it here.
|
||||
this->write("*");
|
||||
}
|
||||
if (b.fOperator == Token::Kind::TK_STAREQ &&
|
||||
leftType.typeKind() == Type::TypeKind::kMatrix &&
|
||||
if (op == Token::Kind::TK_STAREQ && leftType.typeKind() == Type::TypeKind::kMatrix &&
|
||||
rightType.typeKind() == Type::TypeKind::kMatrix) {
|
||||
this->writeMatrixTimesEqualHelper(leftType, rightType, b.type());
|
||||
}
|
||||
this->writeExpression(*b.fLeft, precedence);
|
||||
if (b.fOperator != Token::Kind::TK_EQ && Compiler::IsAssignment(b.fOperator) &&
|
||||
b.fLeft->kind() == Expression::Kind::kSwizzle && !b.fLeft->hasSideEffects()) {
|
||||
this->writeExpression(left, precedence);
|
||||
if (op != Token::Kind::TK_EQ && Compiler::IsAssignment(op) &&
|
||||
left.kind() == Expression::Kind::kSwizzle && !left.hasSideEffects()) {
|
||||
// This doesn't compile in Metal:
|
||||
// float4 x = float4(1);
|
||||
// x.xy *= float2x2(...);
|
||||
@ -854,16 +856,16 @@ void MetalCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
|
||||
// but switching it to x.xy = x.xy * float2x2(...) fixes it. We perform this tranformation
|
||||
// as long as the LHS has no side effects, and hope for the best otherwise.
|
||||
this->write(" = ");
|
||||
this->writeExpression(*b.fLeft, kAssignment_Precedence);
|
||||
this->writeExpression(left, kAssignment_Precedence);
|
||||
this->write(" ");
|
||||
String op = Compiler::OperatorName(b.fOperator);
|
||||
SkASSERT(op.endsWith("="));
|
||||
this->write(op.substr(0, op.size() - 1).c_str());
|
||||
String opName = Compiler::OperatorName(op);
|
||||
SkASSERT(opName.endsWith("="));
|
||||
this->write(opName.substr(0, opName.size() - 1).c_str());
|
||||
this->write(" ");
|
||||
} else {
|
||||
this->write(String(" ") + Compiler::OperatorName(b.fOperator) + " ");
|
||||
this->write(String(" ") + Compiler::OperatorName(op) + " ");
|
||||
}
|
||||
this->writeExpression(*b.fRight, precedence);
|
||||
this->writeExpression(right, precedence);
|
||||
if (needParens) {
|
||||
this->write(")");
|
||||
}
|
||||
@ -1730,8 +1732,8 @@ MetalCodeGenerator::Requirements MetalCodeGenerator::requirements(const Expressi
|
||||
return this->requirements(e->as<Swizzle>().fBase.get());
|
||||
case Expression::Kind::kBinary: {
|
||||
const BinaryExpression& bin = e->as<BinaryExpression>();
|
||||
return this->requirements(bin.fLeft.get()) |
|
||||
this->requirements(bin.fRight.get());
|
||||
return this->requirements(&bin.left()) |
|
||||
this->requirements(&bin.right());
|
||||
}
|
||||
case Expression::Kind::kIndex: {
|
||||
const IndexExpression& idx = e->as<IndexExpression>();
|
||||
|
@ -2302,11 +2302,14 @@ SpvId SPIRVCodeGenerator::writeBinaryExpression(const Type& leftType, SpvId lhs,
|
||||
}
|
||||
|
||||
SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, OutputStream& out) {
|
||||
const Expression& left = b.left();
|
||||
const Expression& right = b.right();
|
||||
Token::Kind op = b.getOperator();
|
||||
// handle cases where we don't necessarily evaluate both LHS and RHS
|
||||
switch (b.fOperator) {
|
||||
switch (op) {
|
||||
case Token::Kind::TK_EQ: {
|
||||
SpvId rhs = this->writeExpression(*b.fRight, out);
|
||||
this->getLValue(*b.fLeft, out)->store(rhs, out);
|
||||
SpvId rhs = this->writeExpression(right, out);
|
||||
this->getLValue(left, out)->store(rhs, out);
|
||||
return rhs;
|
||||
}
|
||||
case Token::Kind::TK_LOGICALAND:
|
||||
@ -2319,17 +2322,16 @@ SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, Outpu
|
||||
|
||||
std::unique_ptr<LValue> lvalue;
|
||||
SpvId lhs;
|
||||
if (Compiler::IsAssignment(b.fOperator)) {
|
||||
lvalue = this->getLValue(*b.fLeft, out);
|
||||
if (Compiler::IsAssignment(op)) {
|
||||
lvalue = this->getLValue(left, out);
|
||||
lhs = lvalue->load(out);
|
||||
} else {
|
||||
lvalue = nullptr;
|
||||
lhs = this->writeExpression(*b.fLeft, out);
|
||||
lhs = this->writeExpression(left, out);
|
||||
}
|
||||
SpvId rhs = this->writeExpression(*b.fRight, out);
|
||||
SpvId result = this->writeBinaryExpression(b.fLeft->type(), lhs,
|
||||
Compiler::RemoveAssignment(b.fOperator),
|
||||
b.fRight->type(), rhs, b.type(), out);
|
||||
SpvId rhs = this->writeExpression(right, out);
|
||||
SpvId result = this->writeBinaryExpression(left.type(), lhs, Compiler::RemoveAssignment(op),
|
||||
right.type(), rhs, b.type(), out);
|
||||
if (lvalue) {
|
||||
lvalue->store(result, out);
|
||||
}
|
||||
@ -2337,17 +2339,17 @@ SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, Outpu
|
||||
}
|
||||
|
||||
SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStream& out) {
|
||||
SkASSERT(a.fOperator == Token::Kind::TK_LOGICALAND);
|
||||
SkASSERT(a.getOperator() == Token::Kind::TK_LOGICALAND);
|
||||
BoolLiteral falseLiteral(fContext, -1, false);
|
||||
SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
|
||||
SpvId lhs = this->writeExpression(*a.fLeft, out);
|
||||
SpvId lhs = this->writeExpression(a.left(), out);
|
||||
SpvId rhsLabel = this->nextId();
|
||||
SpvId end = this->nextId();
|
||||
SpvId lhsBlock = fCurrentBlock;
|
||||
this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
|
||||
this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
|
||||
this->writeLabel(rhsLabel, out);
|
||||
SpvId rhs = this->writeExpression(*a.fRight, out);
|
||||
SpvId rhs = this->writeExpression(a.right(), out);
|
||||
SpvId rhsBlock = fCurrentBlock;
|
||||
this->writeInstruction(SpvOpBranch, end, out);
|
||||
this->writeLabel(end, out);
|
||||
@ -2358,17 +2360,17 @@ SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStrea
|
||||
}
|
||||
|
||||
SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, OutputStream& out) {
|
||||
SkASSERT(o.fOperator == Token::Kind::TK_LOGICALOR);
|
||||
SkASSERT(o.getOperator() == Token::Kind::TK_LOGICALOR);
|
||||
BoolLiteral trueLiteral(fContext, -1, true);
|
||||
SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
|
||||
SpvId lhs = this->writeExpression(*o.fLeft, out);
|
||||
SpvId lhs = this->writeExpression(o.left(), out);
|
||||
SpvId rhsLabel = this->nextId();
|
||||
SpvId end = this->nextId();
|
||||
SpvId lhsBlock = fCurrentBlock;
|
||||
this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
|
||||
this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
|
||||
this->writeLabel(rhsLabel, out);
|
||||
SpvId rhs = this->writeExpression(*o.fRight, out);
|
||||
SpvId rhs = this->writeExpression(o.right(), out);
|
||||
SpvId rhsBlock = fCurrentBlock;
|
||||
this->writeInstruction(SpvOpBranch, end, out);
|
||||
this->writeLabel(end, out);
|
||||
|
@ -19,24 +19,24 @@
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
static inline bool check_ref(Expression* expr) {
|
||||
switch (expr->kind()) {
|
||||
static inline bool check_ref(const Expression& expr) {
|
||||
switch (expr.kind()) {
|
||||
case Expression::Kind::kExternalValue:
|
||||
return true;
|
||||
case Expression::Kind::kFieldAccess:
|
||||
return check_ref(((FieldAccess*) expr)->fBase.get());
|
||||
return check_ref(*expr.as<FieldAccess>().fBase);
|
||||
case Expression::Kind::kIndex:
|
||||
return check_ref(((IndexExpression*) expr)->fBase.get());
|
||||
return check_ref(*expr.as<IndexExpression>().fBase);
|
||||
case Expression::Kind::kSwizzle:
|
||||
return check_ref(((Swizzle*) expr)->fBase.get());
|
||||
return check_ref(*expr.as<Swizzle>().fBase);
|
||||
case Expression::Kind::kTernary: {
|
||||
TernaryExpression* t = (TernaryExpression*) expr;
|
||||
return check_ref(t->fIfTrue.get()) && check_ref(t->fIfFalse.get());
|
||||
const TernaryExpression& t = expr.as<TernaryExpression>();
|
||||
return check_ref(*t.fIfTrue) && check_ref(*t.fIfFalse);
|
||||
}
|
||||
case Expression::Kind::kVariableReference: {
|
||||
VariableReference* ref = (VariableReference*) expr;
|
||||
return ref->fRefKind == VariableReference::kWrite_RefKind ||
|
||||
ref->fRefKind == VariableReference::kReadWrite_RefKind;
|
||||
const VariableReference& ref = expr.as<VariableReference>();
|
||||
return ref.fRefKind == VariableReference::kWrite_RefKind ||
|
||||
ref.fRefKind == VariableReference::kReadWrite_RefKind;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
@ -51,46 +51,75 @@ struct BinaryExpression : public Expression {
|
||||
|
||||
BinaryExpression(int offset, std::unique_ptr<Expression> left, Token::Kind op,
|
||||
std::unique_ptr<Expression> right, const Type* type)
|
||||
: INHERITED(offset, kExpressionKind, type)
|
||||
, fLeft(std::move(left))
|
||||
, fOperator(op)
|
||||
, fRight(std::move(right)) {
|
||||
: INHERITED(offset, kExpressionKind, { type, op }) {
|
||||
fExpressionChildren.reserve(2);
|
||||
fExpressionChildren.push_back(std::move(left));
|
||||
fExpressionChildren.push_back(std::move(right));
|
||||
// If we are assigning to a VariableReference, ensure that it is set to Write or ReadWrite
|
||||
SkASSERT(!Compiler::IsAssignment(op) || check_ref(fLeft.get()));
|
||||
SkASSERT(!Compiler::IsAssignment(op) || check_ref(this->left()));
|
||||
}
|
||||
|
||||
Expression& left() const {
|
||||
return this->expressionChild(0);
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression>& leftPointer() {
|
||||
return this->expressionPointer(0);
|
||||
}
|
||||
|
||||
const std::unique_ptr<Expression>& leftPointer() const {
|
||||
return this->expressionPointer(0);
|
||||
}
|
||||
|
||||
Expression& right() const {
|
||||
return this->expressionChild(1);
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression>& rightPointer() {
|
||||
return this->expressionPointer(1);
|
||||
}
|
||||
|
||||
const std::unique_ptr<Expression>& rightPointer() const {
|
||||
return this->expressionPointer(1);
|
||||
}
|
||||
|
||||
Token::Kind getOperator() const {
|
||||
return this->typeTokenData().fToken;
|
||||
}
|
||||
|
||||
bool isConstantOrUniform() const override {
|
||||
return fLeft->isConstantOrUniform() && fRight->isConstantOrUniform();
|
||||
return this->left().isConstantOrUniform() && this->right().isConstantOrUniform();
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> constantPropagate(const IRGenerator& irGenerator,
|
||||
const DefinitionMap& definitions) override {
|
||||
return irGenerator.constantFold(*fLeft,
|
||||
fOperator,
|
||||
*fRight);
|
||||
return irGenerator.constantFold(this->left(),
|
||||
this->getOperator(),
|
||||
this->right());
|
||||
}
|
||||
|
||||
bool hasProperty(Property property) const override {
|
||||
if (property == Property::kSideEffects && Compiler::IsAssignment(fOperator)) {
|
||||
if (property == Property::kSideEffects && Compiler::IsAssignment(this->getOperator())) {
|
||||
return true;
|
||||
}
|
||||
return fLeft->hasProperty(property) || fRight->hasProperty(property);
|
||||
return this->left().hasProperty(property) || this->right().hasProperty(property);
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> clone() const override {
|
||||
return std::unique_ptr<Expression>(new BinaryExpression(fOffset, fLeft->clone(), fOperator,
|
||||
fRight->clone(), &this->type()));
|
||||
return std::unique_ptr<Expression>(new BinaryExpression(fOffset,
|
||||
this->left().clone(),
|
||||
this->getOperator(),
|
||||
this->right().clone(),
|
||||
&this->type()));
|
||||
}
|
||||
|
||||
String description() const override {
|
||||
return "(" + fLeft->description() + " " + Compiler::OperatorName(fOperator) + " " +
|
||||
fRight->description() + ")";
|
||||
return "(" + this->left().description() + " " +
|
||||
Compiler::OperatorName(this->getOperator()) + " " + this->right().description() +
|
||||
")";
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> fLeft;
|
||||
const Token::Kind fOperator;
|
||||
std::unique_ptr<Expression> fRight;
|
||||
|
||||
private:
|
||||
using INHERITED = Expression;
|
||||
};
|
||||
|
||||
|
@ -57,7 +57,12 @@ struct Expression : public IRNode {
|
||||
};
|
||||
|
||||
Expression(int offset, Kind kind, const Type* type)
|
||||
: INHERITED(offset, (int) kind, type) {
|
||||
: INHERITED(offset, (int) kind, type) {
|
||||
SkASSERT(kind >= Kind::kFirst && kind <= Kind::kLast);
|
||||
}
|
||||
|
||||
Expression(int offset, Kind kind, TypeTokenData data)
|
||||
: INHERITED(offset, (int) kind, data) {
|
||||
SkASSERT(kind >= Kind::kFirst && kind <= Kind::kLast);
|
||||
}
|
||||
|
||||
|
36
src/sksl/ir/SkSLIRNode.cpp
Normal file
36
src/sksl/ir/SkSLIRNode.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2020 Google LLC.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "src/sksl/ir/SkSLIRNode.h"
|
||||
|
||||
#include "src/sksl/ir/SkSLExpression.h"
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
IRNode::IRNode(int offset, int kind, const Type* data)
|
||||
: fOffset(offset)
|
||||
, fKind(kind)
|
||||
, fData(data) {}
|
||||
|
||||
IRNode::IRNode(int offset, int kind, TypeTokenData data)
|
||||
: fOffset(offset)
|
||||
, fKind(kind)
|
||||
, fData(data) {}
|
||||
|
||||
IRNode::IRNode(const IRNode& other)
|
||||
: fOffset(other.fOffset)
|
||||
, fKind(other.fKind)
|
||||
, fData(other.fData) {
|
||||
// For now, we can't use a default copy constructor because of the std::unique_ptr children.
|
||||
// Since we never copy nodes containing children, it's easiest just to assert we don't have any
|
||||
// than bother with cloning them.
|
||||
SkASSERT(other.fExpressionChildren.empty());
|
||||
}
|
||||
|
||||
IRNode::~IRNode() {}
|
||||
|
||||
} // namespace SkSL
|
@ -8,11 +8,16 @@
|
||||
#ifndef SKSL_IRNODE
|
||||
#define SKSL_IRNODE
|
||||
|
||||
#include "src/sksl/SkSLASTNode.h"
|
||||
#include "src/sksl/SkSLLexer.h"
|
||||
#include "src/sksl/SkSLString.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
struct Expression;
|
||||
class Type;
|
||||
|
||||
/**
|
||||
@ -21,12 +26,19 @@ class Type;
|
||||
*/
|
||||
class IRNode {
|
||||
public:
|
||||
IRNode(int offset, int kind, const Type* type = nullptr)
|
||||
: fOffset(offset)
|
||||
, fKind(kind)
|
||||
, fType(type) {}
|
||||
virtual ~IRNode();
|
||||
|
||||
virtual ~IRNode() {}
|
||||
IRNode& operator=(const IRNode& other) {
|
||||
// Need to have a copy assignment operator because Type requires it, but can't use the
|
||||
// default version until we finish migrating away from std::unique_ptr children. For now,
|
||||
// just assert that there are no children (we could theoretically clone them, but we never
|
||||
// actually copy nodes containing children).
|
||||
SkASSERT(other.fExpressionChildren.empty());
|
||||
fKind = other.fKind;
|
||||
fOffset = other.fOffset;
|
||||
fData = other.fData;
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual String description() const = 0;
|
||||
|
||||
@ -35,15 +47,81 @@ public:
|
||||
int fOffset;
|
||||
|
||||
const Type& type() const {
|
||||
SkASSERT(fType);
|
||||
return *fType;
|
||||
switch (fData.fKind) {
|
||||
case NodeData::Kind::kType:
|
||||
return *this->typeData();
|
||||
case NodeData::Kind::kTypeToken:
|
||||
return *this->typeTokenData().fType;
|
||||
default:
|
||||
SkUNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
struct TypeTokenData {
|
||||
const Type* fType;
|
||||
Token::Kind fToken;
|
||||
};
|
||||
|
||||
struct NodeData {
|
||||
char fBytes[std::max(sizeof(Type*),
|
||||
sizeof(TypeTokenData))];
|
||||
|
||||
enum class Kind {
|
||||
kType,
|
||||
kTypeToken,
|
||||
} fKind;
|
||||
|
||||
NodeData() = default;
|
||||
|
||||
NodeData(const Type* data)
|
||||
: fKind(Kind::kType) {
|
||||
memcpy(fBytes, &data, sizeof(data));
|
||||
}
|
||||
|
||||
NodeData(TypeTokenData data)
|
||||
: fKind(Kind::kTypeToken) {
|
||||
memcpy(fBytes, &data, sizeof(data));
|
||||
}
|
||||
};
|
||||
|
||||
IRNode(int offset, int kind, const Type* data = nullptr);
|
||||
|
||||
IRNode(int offset, int kind, TypeTokenData data);
|
||||
|
||||
IRNode(const IRNode& other);
|
||||
|
||||
Expression& expressionChild(int index) const {
|
||||
return *fExpressionChildren[index];
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression>& expressionPointer(int index) {
|
||||
return fExpressionChildren[index];
|
||||
}
|
||||
|
||||
const std::unique_ptr<Expression>& expressionPointer(int index) const {
|
||||
return fExpressionChildren[index];
|
||||
}
|
||||
|
||||
Type* typeData() const {
|
||||
SkASSERT(fData.fKind == NodeData::Kind::kType);
|
||||
Type* result;
|
||||
memcpy(&result, fData.fBytes, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
TypeTokenData typeTokenData() const {
|
||||
SkASSERT(fData.fKind == NodeData::Kind::kTypeToken);
|
||||
TypeTokenData result;
|
||||
memcpy(&result, fData.fBytes, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
int fKind;
|
||||
std::vector<std::unique_ptr<Expression>> fExpressionChildren;
|
||||
|
||||
private:
|
||||
const Type* fType;
|
||||
NodeData fData;
|
||||
};
|
||||
|
||||
} // namespace SkSL
|
||||
|
Loading…
Reference in New Issue
Block a user