moved BinaryExpression's data into IRNode

This is another step in the process of merging the various IRNodes' data
into the base class.

Change-Id: Ide39c240e6178e23bb6fe317dd56addf2ffefcbb
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/317102
Commit-Queue: John Stiles <johnstiles@google.com>
Reviewed-by: John Stiles <johnstiles@google.com>
This commit is contained in:
Ethan Nicholas 2020-09-16 12:04:39 -04:00 committed by Skia Commit-Bot
parent f6e0f58b2e
commit efc8797880
16 changed files with 370 additions and 208 deletions

View File

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

View File

@ -16,11 +16,6 @@
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 +262,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),
sizeof(StringFragment),
sizeof(bool),
sizeof(SKSL_INT),
sizeof(SKSL_FLOAT),
sizeof(Modifiers),
sizeof(TypeData),
sizeof(FunctionData),
sizeof(ParameterData),
sizeof(VarData),
sizeof(InterfaceBlockData),
sizeof(SectionData)})];
enum class Kind {
kToken,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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

View File

@ -8,11 +8,15 @@
#ifndef SKSL_IRNODE
#define SKSL_IRNODE
#include "src/sksl/SkSLASTNode.h"
#include "src/sksl/SkSLLexer.h"
#include "src/sksl/SkSLString.h"
#include <vector>
namespace SkSL {
struct Expression;
class Type;
/**
@ -21,12 +25,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 +46,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