SkSL IR normalization: Convert while loops to for loops
Bug: skia:11095 Change-Id: Icd69df40675e5ecde5004e04a7dcd78eedf8343c Reviewed-on: https://skia-review.googlesource.com/c/skia/+/344765 Commit-Queue: Brian Osman <brianosman@google.com> Reviewed-by: John Stiles <johnstiles@google.com> Reviewed-by: Ethan Nicholas <ethannicholas@google.com> Reviewed-by: Mike Klein <mtklein@google.com>
This commit is contained in:
parent
ba158b9daf
commit
d6f2338ab1
@ -116,7 +116,6 @@ skia_sksl_sources = [
|
||||
"$_src/sksl/ir/SkSLVariable.h",
|
||||
"$_src/sksl/ir/SkSLVariableReference.cpp",
|
||||
"$_src/sksl/ir/SkSLVariableReference.h",
|
||||
"$_src/sksl/ir/SkSLWhileStatement.h",
|
||||
]
|
||||
|
||||
skia_sksl_gpu_sources = [
|
||||
|
@ -35,7 +35,6 @@
|
||||
#include "src/sksl/ir/SkSLNop.h"
|
||||
#include "src/sksl/ir/SkSLReturnStatement.h"
|
||||
#include "src/sksl/ir/SkSLSwitchStatement.h"
|
||||
#include "src/sksl/ir/SkSLWhileStatement.h"
|
||||
|
||||
// Expressions
|
||||
#include "src/sksl/ir/SkSLBinaryExpression.h"
|
||||
@ -616,10 +615,6 @@ bool TProgramVisitor<PROG, EXPR, STMT, ELEM>::visitStatement(STMT s) {
|
||||
auto& v = s.template as<VarDeclaration>();
|
||||
return v.value() && this->visitExpression(*v.value());
|
||||
}
|
||||
case Statement::Kind::kWhile: {
|
||||
auto& w = s.template as<WhileStatement>();
|
||||
return this->visitExpression(*w.test()) || this->visitStatement(*w.statement());
|
||||
}
|
||||
default:
|
||||
SkUNREACHABLE;
|
||||
}
|
||||
|
@ -1912,21 +1912,6 @@ void ByteCodeGenerator::writeVarDeclaration(const VarDeclaration& decl) {
|
||||
}
|
||||
}
|
||||
|
||||
void ByteCodeGenerator::writeWhileStatement(const WhileStatement& w) {
|
||||
this->write(ByteCodeInstruction::kLoopBegin);
|
||||
size_t cond = fCode->size();
|
||||
this->writeExpression(*w.test());
|
||||
this->write(ByteCodeInstruction::kLoopMask);
|
||||
this->write(ByteCodeInstruction::kBranchIfAllFalse);
|
||||
DeferredLocation endLocation(this);
|
||||
this->writeStatement(*w.statement());
|
||||
this->write(ByteCodeInstruction::kLoopNext);
|
||||
this->write(ByteCodeInstruction::kBranch);
|
||||
this->write16(cond);
|
||||
endLocation.set();
|
||||
this->write(ByteCodeInstruction::kLoopEnd);
|
||||
}
|
||||
|
||||
void ByteCodeGenerator::writeStatement(const Statement& s) {
|
||||
switch (s.kind()) {
|
||||
case Statement::Kind::kBlock:
|
||||
@ -1962,9 +1947,6 @@ void ByteCodeGenerator::writeStatement(const Statement& s) {
|
||||
case Statement::Kind::kVarDeclaration:
|
||||
this->writeVarDeclaration(s.as<VarDeclaration>());
|
||||
break;
|
||||
case Statement::Kind::kWhile:
|
||||
this->writeWhileStatement(s.as<WhileStatement>());
|
||||
break;
|
||||
case Statement::Kind::kInlineMarker:
|
||||
case Statement::Kind::kNop:
|
||||
break;
|
||||
|
@ -45,7 +45,6 @@
|
||||
#include "src/sksl/ir/SkSLTernaryExpression.h"
|
||||
#include "src/sksl/ir/SkSLVarDeclarations.h"
|
||||
#include "src/sksl/ir/SkSLVariableReference.h"
|
||||
#include "src/sksl/ir/SkSLWhileStatement.h"
|
||||
#include "src/sksl/spirv.h"
|
||||
|
||||
namespace SkSL {
|
||||
@ -282,7 +281,6 @@ private:
|
||||
void writeContinueStatement(const ContinueStatement& c);
|
||||
void writeIfStatement(const IfStatement& stmt);
|
||||
void writeForStatement(const ForStatement& f);
|
||||
void writeWhileStatement(const WhileStatement& w);
|
||||
void writeDoStatement(const DoStatement& d);
|
||||
void writeSwitchStatement(const SwitchStatement& s);
|
||||
void writeReturnStatement(const ReturnStatement& r);
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include "src/sksl/ir/SkSLSwitchStatement.h"
|
||||
#include "src/sksl/ir/SkSLSwizzle.h"
|
||||
#include "src/sksl/ir/SkSLTernaryExpression.h"
|
||||
#include "src/sksl/ir/SkSLWhileStatement.h"
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
@ -487,10 +486,6 @@ void CFGGenerator::addLValue(CFG& cfg, std::unique_ptr<Expression>* e) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_true(Expression& expr) {
|
||||
return expr.is<BoolLiteral>() && expr.as<BoolLiteral>().value();
|
||||
}
|
||||
|
||||
void CFGGenerator::addStatement(CFG& cfg, std::unique_ptr<Statement>* s) {
|
||||
switch ((*s)->kind()) {
|
||||
case Statement::Kind::kBlock: {
|
||||
@ -556,25 +551,6 @@ void CFGGenerator::addStatement(CFG& cfg, std::unique_ptr<Statement>* s) {
|
||||
cfg.addExit(cfg.fCurrent, fLoopContinues.top());
|
||||
cfg.fCurrent = cfg.newIsolatedBlock();
|
||||
break;
|
||||
case Statement::Kind::kWhile: {
|
||||
WhileStatement& w = (*s)->as<WhileStatement>();
|
||||
BlockId loopStart = cfg.newBlock();
|
||||
fLoopContinues.push(loopStart);
|
||||
BlockId loopExit = cfg.newIsolatedBlock();
|
||||
fLoopExits.push(loopExit);
|
||||
this->addExpression(cfg, &w.test(), /*constantPropagate=*/true);
|
||||
BlockId test = cfg.fCurrent;
|
||||
if (!is_true(*w.test())) {
|
||||
cfg.addExit(test, loopExit);
|
||||
}
|
||||
cfg.newBlock();
|
||||
this->addStatement(cfg, &w.statement());
|
||||
cfg.addExit(cfg.fCurrent, loopStart);
|
||||
fLoopContinues.pop();
|
||||
fLoopExits.pop();
|
||||
cfg.fCurrent = loopExit;
|
||||
break;
|
||||
}
|
||||
case Statement::Kind::kDo: {
|
||||
DoStatement& d = (*s)->as<DoStatement>();
|
||||
BlockId loopStart = cfg.newBlock();
|
||||
|
@ -47,7 +47,6 @@
|
||||
#include "src/sksl/ir/SkSLUnresolvedFunction.h"
|
||||
#include "src/sksl/ir/SkSLVarDeclarations.h"
|
||||
#include "src/sksl/ir/SkSLVariable.h"
|
||||
#include "src/sksl/ir/SkSLWhileStatement.h"
|
||||
|
||||
#ifdef SKSL_STANDALONE
|
||||
|
||||
@ -494,13 +493,6 @@ void Dehydrator::write(const Statement* s) {
|
||||
this->write(v.value().get());
|
||||
break;
|
||||
}
|
||||
case Statement::Kind::kWhile: {
|
||||
const WhileStatement& w = s->as<WhileStatement>();
|
||||
this->writeCommand(Rehydrator::kWhile_Command);
|
||||
this->write(w.test().get());
|
||||
this->write(w.statement().get());
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this->writeCommand(Rehydrator::kVoid_Command);
|
||||
|
@ -1308,9 +1308,6 @@ void GLSLCodeGenerator::writeStatement(const Statement& s) {
|
||||
case Statement::Kind::kFor:
|
||||
this->writeForStatement(s.as<ForStatement>());
|
||||
break;
|
||||
case Statement::Kind::kWhile:
|
||||
this->writeWhileStatement(s.as<WhileStatement>());
|
||||
break;
|
||||
case Statement::Kind::kDo:
|
||||
this->writeDoStatement(s.as<DoStatement>());
|
||||
break;
|
||||
@ -1368,6 +1365,15 @@ void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
|
||||
}
|
||||
|
||||
void GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
|
||||
// Emit loops of the form 'for(;test;)' as 'while(test)', which is probably how they started
|
||||
if (!f.initializer() && f.test() && !f.next()) {
|
||||
this->write("while (");
|
||||
this->writeExpression(*f.test(), kTopLevel_Precedence);
|
||||
this->write(") ");
|
||||
this->writeStatement(*f.statement());
|
||||
return;
|
||||
}
|
||||
|
||||
this->write("for (");
|
||||
if (f.initializer() && !f.initializer()->isEmpty()) {
|
||||
this->writeStatement(*f.initializer());
|
||||
@ -1393,13 +1399,6 @@ void GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
|
||||
this->writeStatement(*f.statement());
|
||||
}
|
||||
|
||||
void GLSLCodeGenerator::writeWhileStatement(const WhileStatement& w) {
|
||||
this->write("while (");
|
||||
this->writeExpression(*w.test(), kTopLevel_Precedence);
|
||||
this->write(") ");
|
||||
this->writeStatement(*w.statement());
|
||||
}
|
||||
|
||||
void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
|
||||
if (!fProgram.fCaps->rewriteDoWhileLoops()) {
|
||||
this->write("do ");
|
||||
|
@ -41,7 +41,6 @@
|
||||
#include "src/sksl/ir/SkSLTernaryExpression.h"
|
||||
#include "src/sksl/ir/SkSLVarDeclarations.h"
|
||||
#include "src/sksl/ir/SkSLVariableReference.h"
|
||||
#include "src/sksl/ir/SkSLWhileStatement.h"
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
@ -189,8 +188,6 @@ protected:
|
||||
|
||||
void writeForStatement(const ForStatement& f);
|
||||
|
||||
void writeWhileStatement(const WhileStatement& w);
|
||||
|
||||
void writeDoStatement(const DoStatement& d);
|
||||
|
||||
virtual void writeSwitchStatement(const SwitchStatement& s);
|
||||
|
@ -57,7 +57,6 @@
|
||||
#include "src/sksl/ir/SkSLVarDeclarations.h"
|
||||
#include "src/sksl/ir/SkSLVariable.h"
|
||||
#include "src/sksl/ir/SkSLVariableReference.h"
|
||||
#include "src/sksl/ir/SkSLWhileStatement.h"
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
@ -559,7 +558,8 @@ std::unique_ptr<Statement> IRGenerator::convertWhile(const ASTNode& w) {
|
||||
if (!statement) {
|
||||
return nullptr;
|
||||
}
|
||||
return std::make_unique<WhileStatement>(w.fOffset, std::move(test), std::move(statement));
|
||||
return std::make_unique<ForStatement>(w.fOffset, /*initializer=*/nullptr, std::move(test),
|
||||
/*next=*/nullptr, std::move(statement), fSymbolTable);
|
||||
}
|
||||
|
||||
std::unique_ptr<Statement> IRGenerator::convertDo(const ASTNode& d) {
|
||||
|
@ -51,7 +51,6 @@
|
||||
#include "src/sksl/ir/SkSLVarDeclarations.h"
|
||||
#include "src/sksl/ir/SkSLVariable.h"
|
||||
#include "src/sksl/ir/SkSLVariableReference.h"
|
||||
#include "src/sksl/ir/SkSLWhileStatement.h"
|
||||
|
||||
namespace SkSL {
|
||||
namespace {
|
||||
@ -100,7 +99,6 @@ static int count_returns_at_end_of_control_flow(const FunctionDefinition& funcDe
|
||||
this->visitStatement(*block.children().back());
|
||||
}
|
||||
case Statement::Kind::kSwitch:
|
||||
case Statement::Kind::kWhile:
|
||||
case Statement::Kind::kDo:
|
||||
case Statement::Kind::kFor:
|
||||
// Don't introspect switches or loop structures at all.
|
||||
@ -132,7 +130,6 @@ static int count_returns_in_breakable_constructs(const FunctionDefinition& funcD
|
||||
bool visitStatement(const Statement& stmt) override {
|
||||
switch (stmt.kind()) {
|
||||
case Statement::Kind::kSwitch:
|
||||
case Statement::Kind::kWhile:
|
||||
case Statement::Kind::kDo:
|
||||
case Statement::Kind::kFor: {
|
||||
++fInsideBreakableConstruct;
|
||||
@ -257,7 +254,7 @@ void Inliner::ensureScopedBlocks(Statement* inlinedBody, Statement* parentStmt)
|
||||
|
||||
// No changes necessary if the parent statement doesn't require a scope.
|
||||
if (!parentStmt || !(parentStmt->is<IfStatement>() || parentStmt->is<ForStatement>() ||
|
||||
parentStmt->is<DoStatement>() || parentStmt->is<WhileStatement>())) {
|
||||
parentStmt->is<DoStatement>())) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -574,10 +571,6 @@ std::unique_ptr<Statement> Inliner::inlineStatement(int offset,
|
||||
return std::make_unique<VarDeclaration>(clone, baseTypePtr, arraySize,
|
||||
std::move(initialValue));
|
||||
}
|
||||
case Statement::Kind::kWhile: {
|
||||
const WhileStatement& w = statement.as<WhileStatement>();
|
||||
return std::make_unique<WhileStatement>(offset, expr(w.test()), stmt(w.statement()));
|
||||
}
|
||||
default:
|
||||
SkASSERT(false);
|
||||
return nullptr;
|
||||
@ -956,20 +949,6 @@ public:
|
||||
this->visitExpression(&varDeclStmt.value());
|
||||
break;
|
||||
}
|
||||
case Statement::Kind::kWhile: {
|
||||
WhileStatement& whileStmt = (*stmt)->as<WhileStatement>();
|
||||
// The loop body is a candidate for inlining.
|
||||
this->visitStatement(&whileStmt.statement());
|
||||
// The inliner isn't smart enough to inline the test-expression for a while loop at
|
||||
// this time. There are two limitations:
|
||||
// - We would need to insert the inlined-body block at the very beginning of the
|
||||
// while loop's inner fStatement. We don't support that today, but it's doable.
|
||||
// - The while-loop's built-in test-expression would need to be replaced with a
|
||||
// `true` BoolLiteral, and the loop would be halted via a break statement at the
|
||||
// end of the inlined test-expression. This is again something we don't support
|
||||
// today, but it could be implemented.
|
||||
break;
|
||||
}
|
||||
default:
|
||||
SkUNREACHABLE;
|
||||
}
|
||||
|
@ -1670,9 +1670,6 @@ void MetalCodeGenerator::writeStatement(const Statement& s) {
|
||||
case Statement::Kind::kFor:
|
||||
this->writeForStatement(s.as<ForStatement>());
|
||||
break;
|
||||
case Statement::Kind::kWhile:
|
||||
this->writeWhileStatement(s.as<WhileStatement>());
|
||||
break;
|
||||
case Statement::Kind::kDo:
|
||||
this->writeDoStatement(s.as<DoStatement>());
|
||||
break;
|
||||
@ -1730,6 +1727,15 @@ void MetalCodeGenerator::writeIfStatement(const IfStatement& stmt) {
|
||||
}
|
||||
|
||||
void MetalCodeGenerator::writeForStatement(const ForStatement& f) {
|
||||
// Emit loops of the form 'for(;test;)' as 'while(test)', which is probably how they started
|
||||
if (!f.initializer() && f.test() && !f.next()) {
|
||||
this->write("while (");
|
||||
this->writeExpression(*f.test(), kTopLevel_Precedence);
|
||||
this->write(") ");
|
||||
this->writeStatement(*f.statement());
|
||||
return;
|
||||
}
|
||||
|
||||
this->write("for (");
|
||||
if (f.initializer() && !f.initializer()->isEmpty()) {
|
||||
this->writeStatement(*f.initializer());
|
||||
@ -1747,13 +1753,6 @@ void MetalCodeGenerator::writeForStatement(const ForStatement& f) {
|
||||
this->writeStatement(*f.statement());
|
||||
}
|
||||
|
||||
void MetalCodeGenerator::writeWhileStatement(const WhileStatement& w) {
|
||||
this->write("while (");
|
||||
this->writeExpression(*w.test(), kTopLevel_Precedence);
|
||||
this->write(") ");
|
||||
this->writeStatement(*w.statement());
|
||||
}
|
||||
|
||||
void MetalCodeGenerator::writeDoStatement(const DoStatement& d) {
|
||||
this->write("do ");
|
||||
this->writeStatement(*d.statement());
|
||||
@ -2247,11 +2246,6 @@ MetalCodeGenerator::Requirements MetalCodeGenerator::requirements(const Statemen
|
||||
this->requirements(f.next().get()) |
|
||||
this->requirements(f.statement().get());
|
||||
}
|
||||
case Statement::Kind::kWhile: {
|
||||
const WhileStatement& w = s->as<WhileStatement>();
|
||||
return this->requirements(w.test().get()) |
|
||||
this->requirements(w.statement().get());
|
||||
}
|
||||
case Statement::Kind::kDo: {
|
||||
const DoStatement& d = s->as<DoStatement>();
|
||||
return this->requirements(d.test().get()) |
|
||||
|
@ -43,7 +43,6 @@
|
||||
#include "src/sksl/ir/SkSLTernaryExpression.h"
|
||||
#include "src/sksl/ir/SkSLVarDeclarations.h"
|
||||
#include "src/sksl/ir/SkSLVariableReference.h"
|
||||
#include "src/sksl/ir/SkSLWhileStatement.h"
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
@ -274,8 +273,6 @@ protected:
|
||||
|
||||
void writeForStatement(const ForStatement& f);
|
||||
|
||||
void writeWhileStatement(const WhileStatement& w);
|
||||
|
||||
void writeDoStatement(const DoStatement& d);
|
||||
|
||||
void writeSwitchStatement(const SwitchStatement& s);
|
||||
|
@ -49,7 +49,6 @@
|
||||
#include "src/sksl/ir/SkSLUnresolvedFunction.h"
|
||||
#include "src/sksl/ir/SkSLVarDeclarations.h"
|
||||
#include "src/sksl/ir/SkSLVariable.h"
|
||||
#include "src/sksl/ir/SkSLWhileStatement.h"
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
@ -445,12 +444,6 @@ std::unique_ptr<Statement> Rehydrator::statement() {
|
||||
}
|
||||
case Rehydrator::kVoid_Command:
|
||||
return nullptr;
|
||||
case Rehydrator::kWhile_Command: {
|
||||
std::unique_ptr<Expression> expr = this->expression();
|
||||
std::unique_ptr<Statement> stmt = this->statement();
|
||||
return std::unique_ptr<Statement>(new WhileStatement(-1, std::move(expr),
|
||||
std::move(stmt)));
|
||||
}
|
||||
default:
|
||||
printf("unsupported statement %d\n", kind);
|
||||
SkASSERT(false);
|
||||
|
@ -144,8 +144,6 @@ public:
|
||||
// uint16 varId, uint8 refKind
|
||||
kVariableReference_Command,
|
||||
kVoid_Command,
|
||||
// Expression test, Statement body
|
||||
kWhile_Command,
|
||||
};
|
||||
|
||||
// src must remain in memory as long as the objects created from it do
|
||||
|
@ -2927,9 +2927,6 @@ void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) {
|
||||
case Statement::Kind::kFor:
|
||||
this->writeForStatement(s.as<ForStatement>(), out);
|
||||
break;
|
||||
case Statement::Kind::kWhile:
|
||||
this->writeWhileStatement(s.as<WhileStatement>(), out);
|
||||
break;
|
||||
case Statement::Kind::kDo:
|
||||
this->writeDoStatement(s.as<DoStatement>(), out);
|
||||
break;
|
||||
@ -3027,33 +3024,6 @@ void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream&
|
||||
fContinueTarget.pop();
|
||||
}
|
||||
|
||||
void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStream& out) {
|
||||
SpvId header = this->nextId();
|
||||
SpvId start = this->nextId();
|
||||
SpvId body = this->nextId();
|
||||
SpvId continueTarget = this->nextId();
|
||||
fContinueTarget.push(continueTarget);
|
||||
SpvId end = this->nextId();
|
||||
fBreakTarget.push(end);
|
||||
this->writeInstruction(SpvOpBranch, header, out);
|
||||
this->writeLabel(header, out);
|
||||
this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
|
||||
this->writeInstruction(SpvOpBranch, start, out);
|
||||
this->writeLabel(start, out);
|
||||
SpvId test = this->writeExpression(*w.test(), out);
|
||||
this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
|
||||
this->writeLabel(body, out);
|
||||
this->writeStatement(*w.statement(), out);
|
||||
if (fCurrentBlock) {
|
||||
this->writeInstruction(SpvOpBranch, continueTarget, out);
|
||||
}
|
||||
this->writeLabel(continueTarget, out);
|
||||
this->writeInstruction(SpvOpBranch, header, out);
|
||||
this->writeLabel(end, out);
|
||||
fBreakTarget.pop();
|
||||
fContinueTarget.pop();
|
||||
}
|
||||
|
||||
void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
|
||||
SpvId header = this->nextId();
|
||||
SpvId start = this->nextId();
|
||||
|
@ -39,7 +39,6 @@
|
||||
#include "src/sksl/ir/SkSLTernaryExpression.h"
|
||||
#include "src/sksl/ir/SkSLVarDeclarations.h"
|
||||
#include "src/sksl/ir/SkSLVariableReference.h"
|
||||
#include "src/sksl/ir/SkSLWhileStatement.h"
|
||||
#include "src/sksl/spirv.h"
|
||||
|
||||
union ConstantValue {
|
||||
@ -314,8 +313,6 @@ private:
|
||||
|
||||
void writeForStatement(const ForStatement& f, OutputStream& out);
|
||||
|
||||
void writeWhileStatement(const WhileStatement& w, OutputStream& out);
|
||||
|
||||
void writeDoStatement(const DoStatement& d, OutputStream& out);
|
||||
|
||||
void writeSwitchStatement(const SwitchStatement& s, OutputStream& out);
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include "src/sksl/ir/SkSLSwizzle.h"
|
||||
#include "src/sksl/ir/SkSLTernaryExpression.h"
|
||||
#include "src/sksl/ir/SkSLVariable.h"
|
||||
#include "src/sksl/ir/SkSLWhileStatement.h"
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include "src/sksl/ir/SkSLSwitchStatement.h"
|
||||
#include "src/sksl/ir/SkSLSwizzle.h"
|
||||
#include "src/sksl/ir/SkSLTernaryExpression.h"
|
||||
#include "src/sksl/ir/SkSLWhileStatement.h"
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
|
@ -33,10 +33,9 @@ public:
|
||||
kSwitch,
|
||||
kSwitchCase,
|
||||
kVarDeclaration,
|
||||
kWhile,
|
||||
|
||||
kFirst = kBlock,
|
||||
kLast = kWhile
|
||||
kLast = kVarDeclaration,
|
||||
};
|
||||
|
||||
Statement(int offset, Kind kind)
|
||||
|
@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SKSL_WHILESTATEMENT
|
||||
#define SKSL_WHILESTATEMENT
|
||||
|
||||
#include "src/sksl/ir/SkSLExpression.h"
|
||||
#include "src/sksl/ir/SkSLStatement.h"
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
/**
|
||||
* A 'while' loop.
|
||||
*/
|
||||
struct WhileStatement final : public Statement {
|
||||
static constexpr Kind kStatementKind = Kind::kWhile;
|
||||
|
||||
WhileStatement(int offset, std::unique_ptr<Expression> test,
|
||||
std::unique_ptr<Statement> statement)
|
||||
: INHERITED(offset, kStatementKind)
|
||||
, fTest(std::move(test))
|
||||
, fStatement(std::move(statement)) {}
|
||||
|
||||
std::unique_ptr<Expression>& test() {
|
||||
return fTest;
|
||||
}
|
||||
|
||||
const std::unique_ptr<Expression>& test() const {
|
||||
return fTest;
|
||||
}
|
||||
|
||||
std::unique_ptr<Statement>& statement() {
|
||||
return fStatement;
|
||||
}
|
||||
|
||||
const std::unique_ptr<Statement>& statement() const {
|
||||
return fStatement;
|
||||
}
|
||||
|
||||
std::unique_ptr<Statement> clone() const override {
|
||||
return std::unique_ptr<Statement>(new WhileStatement(fOffset, this->test()->clone(),
|
||||
this->statement()->clone()));
|
||||
}
|
||||
|
||||
String description() const override {
|
||||
return "while (" + this->test()->description() + ") " + this->statement()->description();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<Expression> fTest;
|
||||
std::unique_ptr<Statement> fStatement;
|
||||
|
||||
using INHERITED = Statement;
|
||||
};
|
||||
|
||||
} // namespace SkSL
|
||||
|
||||
#endif
|
@ -733,7 +733,8 @@ DEF_TEST(SkSLInterpreterRestrictFunctionCalls, r) {
|
||||
expect_failure(r, "float foo(); float bar() { return foo(); } float foo() { return bar(); }");
|
||||
|
||||
// returns are not allowed inside loops
|
||||
expect_failure(r, "float main(float x) { while (x > 1) { return x; } return 0; }");
|
||||
expect_failure(r, "float main(float x)"
|
||||
"{ while (x > 1) { if (x > 2) { return x; } } return 0; }");
|
||||
}
|
||||
|
||||
DEF_TEST(SkSLInterpreterEarlyReturn, r) {
|
||||
|
Loading…
Reference in New Issue
Block a user