Revert "Revert "moved BinaryExpression's data into IRNode""
This reverts commit b61c3a9a01c44840eaa35b28cae0a4b358727f3c.
Change-Id: I42d93bdc6455c8ef941a6cbe1339df2ba916bb3c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/318697
Auto-Submit: Ethan Nicholas <ethannicholas@google.com>
Reviewed-by: John Stiles <johnstiles@google.com>
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
diff --git a/gn/sksl.gni b/gn/sksl.gni
index 3bfa0c6..9a6c286 100644
--- a/gn/sksl.gni
+++ b/gn/sksl.gni
@@ -68,6 +68,7 @@
"$_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",
diff --git a/src/sksl/SkSLASTNode.h b/src/sksl/SkSLASTNode.h
index c65429c..795acbb 100644
--- a/src/sksl/SkSLASTNode.h
+++ b/src/sksl/SkSLASTNode.h
@@ -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 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,
diff --git a/src/sksl/SkSLAnalysis.cpp b/src/sksl/SkSLAnalysis.cpp
index 6496965..82ac423 100644
--- a/src/sksl/SkSLAnalysis.cpp
+++ b/src/sksl/SkSLAnalysis.cpp
@@ -266,7 +266,7 @@
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) {
diff --git a/src/sksl/SkSLByteCodeGenerator.cpp b/src/sksl/SkSLByteCodeGenerator.cpp
index a213ca4..1e9dab0 100644
--- a/src/sksl/SkSLByteCodeGenerator.cpp
+++ b/src/sksl/SkSLByteCodeGenerator.cpp
@@ -681,28 +681,29 @@
}
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 @@
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 @@
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 @@
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 @@
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);
diff --git a/src/sksl/SkSLByteCodeGenerator.h b/src/sksl/SkSLByteCodeGenerator.h
index 9e8b080..f69bbb9 100644
--- a/src/sksl/SkSLByteCodeGenerator.h
+++ b/src/sksl/SkSLByteCodeGenerator.h
@@ -154,9 +154,18 @@
struct Intrinsic {
Intrinsic(SpecialIntrinsic s) : is_special(true), special(s) {}
Intrinsic(ByteCodeInstruction i) : Intrinsic(i, i, i) {}
+ // Workaround: We should be able to leave special uninitialized here, and were for a long
+ // time. Unrelated changes have made valgrind suddenly start complaining about us accessing
+ // uninitialized memory in the code:
+ // if (intrin.is_special && intrin.special == SpecialIntrinsic::kSample)
+ // despite intrin.is_special being false at the time and therefore, one would think, not
+ // actually accessing intrin.special. I'm not sure whether this is a buggy optimization on
+ // clang's part or a false positive on valgrind's part, but either way initializing the
+ // field works around it.
Intrinsic(ByteCodeInstruction f,
ByteCodeInstruction s,
- ByteCodeInstruction u) : is_special(false), inst_f(f), inst_s(s), inst_u(u) {}
+ ByteCodeInstruction u) : is_special(false), special((SpecialIntrinsic) -1),
+ inst_f(f), inst_s(s), inst_u(u) {}
bool is_special;
SpecialIntrinsic special;
diff --git a/src/sksl/SkSLCFGGenerator.cpp b/src/sksl/SkSLCFGGenerator.cpp
index 009784c..3dd75e9 100644
--- a/src/sksl/SkSLCFGGenerator.cpp
+++ b/src/sksl/SkSLCFGGenerator.cpp
@@ -171,14 +171,14 @@
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);
@@ -272,11 +272,12 @@
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);
@@ -324,16 +325,17 @@
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.currentBlock().fNodes.push_back(
@@ -341,15 +343,16 @@
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.currentBlock().fNodes.push_back(
BasicBlock::MakeExpression(e, constantPropagate));
break;
}
default:
- this->addExpression(cfg, &b.fLeft, !Compiler::IsAssignment(b.fOperator));
- this->addExpression(cfg, &b.fRight, constantPropagate);
+ this->addExpression(cfg, &b.leftPointer(),
+ !Compiler::IsAssignment(b.getOperator()));
+ this->addExpression(cfg, &b.rightPointer(), constantPropagate);
cfg.currentBlock().fNodes.push_back(
BasicBlock::MakeExpression(e, constantPropagate));
}
diff --git a/src/sksl/SkSLCPPCodeGenerator.cpp b/src/sksl/SkSLCPPCodeGenerator.cpp
index 3eacb80..a62374e 100644
--- a/src/sksl/SkSLCPPCodeGenerator.cpp
+++ b/src/sksl/SkSLCPPCodeGenerator.cpp
@@ -70,42 +70,45 @@
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);
diff --git a/src/sksl/SkSLCompiler.cpp b/src/sksl/SkSLCompiler.cpp
index ffe6811..8ade97f 100644
--- a/src/sksl/SkSLCompiler.cpp
+++ b/src/sksl/SkSLCompiler.cpp
@@ -427,11 +427,11 @@
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);
@@ -598,10 +598,10 @@
* 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) {
@@ -696,14 +696,16 @@
*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;
@@ -714,7 +716,7 @@
}
--(*iter);
if ((*iter)->fKind != BasicBlock::Node::kExpression_Kind ||
- (*iter)->expression() != &bin.fRight) {
+ (*iter)->expression() != &rightPointer) {
*outNeedsRescan = true;
return;
}
@@ -733,20 +735,22 @@
*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;
}
@@ -799,7 +803,7 @@
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);
}
/**
@@ -811,7 +815,7 @@
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
@@ -893,8 +897,10 @@
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)) ||
@@ -902,9 +908,9 @@
(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)
@@ -916,22 +922,22 @@
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)
@@ -943,24 +949,24 @@
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)
@@ -971,7 +977,7 @@
// 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)
@@ -985,7 +991,7 @@
}
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)
@@ -999,7 +1005,7 @@
}
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)
@@ -1010,43 +1016,43 @@
// 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;
diff --git a/src/sksl/SkSLDehydrator.cpp b/src/sksl/SkSLDehydrator.cpp
index 4f93647..b320343 100644
--- a/src/sksl/SkSLDehydrator.cpp
+++ b/src/sksl/SkSLDehydrator.cpp
@@ -258,9 +258,9 @@
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;
}
diff --git a/src/sksl/SkSLGLSLCodeGenerator.cpp b/src/sksl/SkSLGLSLCodeGenerator.cpp
index 433b11b..6ef3b9b 100644
--- a/src/sksl/SkSLGLSLCodeGenerator.cpp
+++ b/src/sksl/SkSLGLSLCodeGenerator.cpp
@@ -913,31 +913,33 @@
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 @@
// 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(")");
diff --git a/src/sksl/SkSLInliner.cpp b/src/sksl/SkSLInliner.cpp
index f17b9fe..f197481 100644
--- a/src/sksl/SkSLInliner.cpp
+++ b/src/sksl/SkSLInliner.cpp
@@ -314,9 +314,9 @@
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:
@@ -948,7 +948,7 @@
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
@@ -958,10 +958,11 @@
// 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;
}
diff --git a/src/sksl/SkSLMetalCodeGenerator.cpp b/src/sksl/SkSLMetalCodeGenerator.cpp
index d573c38..1ee05a4 100644
--- a/src/sksl/SkSLMetalCodeGenerator.cpp
+++ b/src/sksl/SkSLMetalCodeGenerator.cpp
@@ -808,11 +808,14 @@
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 @@
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 @@
// 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 @@
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>();
diff --git a/src/sksl/SkSLSPIRVCodeGenerator.cpp b/src/sksl/SkSLSPIRVCodeGenerator.cpp
index ab3d709..6e07dfb 100644
--- a/src/sksl/SkSLSPIRVCodeGenerator.cpp
+++ b/src/sksl/SkSLSPIRVCodeGenerator.cpp
@@ -2302,11 +2302,14 @@
}
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 @@
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::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::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);
diff --git a/src/sksl/ir/SkSLBinaryExpression.h b/src/sksl/ir/SkSLBinaryExpression.h
index 18ce2b7..47ccd7a 100644
--- a/src/sksl/ir/SkSLBinaryExpression.h
+++ b/src/sksl/ir/SkSLBinaryExpression.h
@@ -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 @@
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;
};
diff --git a/src/sksl/ir/SkSLExpression.h b/src/sksl/ir/SkSLExpression.h
index 7beb341..14c9708 100644
--- a/src/sksl/ir/SkSLExpression.h
+++ b/src/sksl/ir/SkSLExpression.h
@@ -57,7 +57,12 @@
};
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);
}
diff --git a/src/sksl/ir/SkSLIRNode.cpp b/src/sksl/ir/SkSLIRNode.cpp
new file mode 100644
index 0000000..19eaf8b
--- /dev/null
+++ b/src/sksl/ir/SkSLIRNode.cpp
@@ -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
diff --git a/src/sksl/ir/SkSLIRNode.h b/src/sksl/ir/SkSLIRNode.h
index 4a6aa90..d50afbe 100644
--- a/src/sksl/ir/SkSLIRNode.h
+++ b/src/sksl/ir/SkSLIRNode.h
@@ -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 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 @@
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