Skip to content

Commit c0dd06d

Browse files
johnstiles-googleSkia Commit-Bot
authored andcommitted
Ensure that inlined statements are properly scoped.
Change-Id: I43479d8543ea4860be45614a65cf8ad4cec307d8 Bug: skia:10687 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/314877 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: Brian Osman <brianosman@google.com> Auto-Submit: John Stiles <johnstiles@google.com>
1 parent 5bdba1a commit c0dd06d

File tree

3 files changed

+61
-25
lines changed

3 files changed

+61
-25
lines changed

src/sksl/SkSLCompiler.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1642,7 +1642,7 @@ bool Compiler::optimize(Program& program) {
16421642
fIRGenerator->fKind = program.fKind;
16431643
fIRGenerator->fSettings = &program.fSettings;
16441644

1645-
// Build the control-flow graph for each function.
1645+
// Scan and optimize based on the control-flow graph for each function.
16461646
for (ProgramElement& element : program) {
16471647
if (element.fKind == ProgramElement::kFunction_Kind) {
16481648
this->scanCFG(element.as<FunctionDefinition>());

src/sksl/SkSLIRGenerator.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,42 @@ std::unique_ptr<Statement> IRGenerator::convertIf(const ASTNode& n) {
534534
std::move(ifTrue), std::move(ifFalse)));
535535
}
536536

537+
static void ensure_scoped_blocks(Statement* stmt) {
538+
// No changes necessary if this statement isn't actually a block.
539+
if (stmt->fKind != Statement::kBlock_Kind) {
540+
return;
541+
}
542+
543+
Block& block = stmt->as<Block>();
544+
545+
// Occasionally, IR generation can lead to Blocks containing multiple statements, but no scope.
546+
// If this block is used as the statement for a while/if/for, this isn't actually possible to
547+
// represent textually; a scope must be added for the generated code to match the intent. In the
548+
// case of Blocks nested inside other Blocks, we add the scope to the outermost block if needed.
549+
// Zero-statement blocks have similar issues--if we don't represent the Block textually somehow,
550+
// we run the risk of accidentally absorbing the following statement into our loop--so we also
551+
// add a scope to these.
552+
for (Block* nestedBlock = &block;; ) {
553+
if (nestedBlock->fIsScope) {
554+
// We found an explicit scope; all is well.
555+
return;
556+
}
557+
if (nestedBlock->fStatements.size() != 1) {
558+
// We found a block with multiple (or zero) statements, but no scope? Let's add a scope
559+
// to the outermost block.
560+
block.fIsScope = true;
561+
return;
562+
}
563+
if (nestedBlock->fStatements[0]->fKind != Statement::kBlock_Kind) {
564+
// This block has exactly one thing inside, and it's not another block. No need to scope
565+
// it.
566+
return;
567+
}
568+
// We have to go deeper.
569+
nestedBlock = &nestedBlock->fStatements[0]->as<Block>();
570+
}
571+
}
572+
537573
std::unique_ptr<Statement> IRGenerator::convertFor(const ASTNode& f) {
538574
SkASSERT(f.fKind == ASTNode::Kind::kFor);
539575
AutoLoopLevel level(this);
@@ -571,6 +607,7 @@ std::unique_ptr<Statement> IRGenerator::convertFor(const ASTNode& f) {
571607
if (!statement) {
572608
return nullptr;
573609
}
610+
ensure_scoped_blocks(statement.get());
574611
return std::make_unique<ForStatement>(f.fOffset, std::move(initializer), std::move(test),
575612
std::move(next), std::move(statement), fSymbolTable);
576613
}
@@ -591,6 +628,7 @@ std::unique_ptr<Statement> IRGenerator::convertWhile(const ASTNode& w) {
591628
if (!statement) {
592629
return nullptr;
593630
}
631+
ensure_scoped_blocks(statement.get());
594632
return std::make_unique<WhileStatement>(w.fOffset, std::move(test), std::move(statement));
595633
}
596634

@@ -602,6 +640,7 @@ std::unique_ptr<Statement> IRGenerator::convertDo(const ASTNode& d) {
602640
if (!statement) {
603641
return nullptr;
604642
}
643+
ensure_scoped_blocks(statement.get());
605644
std::unique_ptr<Expression> test;
606645
{
607646
AutoDisableInline disableInline(this);

tests/SkSLFPTest.cpp

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1228,8 +1228,6 @@ while (%s(%s)) {
12281228
}
12291229

12301230
DEF_TEST(SkSLFPInlinedWhileBodyMustBeInAScope, r) {
1231-
// NOTE: this test exposes a bug with the inliner. The inlined function body is not wrapped in a
1232-
// scope, so the inlined code is emitted outside of the while loop.
12331231
test(r,
12341232
*SkSL::ShaderCapsFactory::Default(),
12351233
R"__SkSL__(
@@ -1249,13 +1247,14 @@ R"SkSL(return v + half4(0.125);
12491247
)SkSL", &adjust_name);
12501248
fragBuilder->codeAppendf(
12511249
R"SkSL(%s = half4(0.0);
1252-
while (%s.x < 0.5) half4 _0_adjust;
1253-
{
1254-
_0_adjust = %s + half4(0.125);
1255-
}
1256-
1257-
%s = _0_adjust;
1250+
while (%s.x < 0.5) {
1251+
half4 _0_adjust;
1252+
{
1253+
_0_adjust = %s + half4(0.125);
1254+
}
12581255
1256+
%s = _0_adjust;
1257+
}
12591258
)SkSL"
12601259
, args.fOutputColor, args.fOutputColor, args.fOutputColor, args.fOutputColor);
12611260
)__Cpp__"});
@@ -1293,8 +1292,6 @@ do {
12931292
}
12941293

12951294
DEF_TEST(SkSLFPInlinedDoWhileBodyMustBeInAScope, r) {
1296-
// NOTE: this test exposes a bug with the inliner. The inlined function body is not wrapped in a
1297-
// scope, so the emitted inlined code is just invalid.
12981295
test(r,
12991296
*SkSL::ShaderCapsFactory::Default(),
13001297
R"__SkSL__(
@@ -1315,13 +1312,14 @@ R"SkSL(return v + half4(0.125);
13151312
)SkSL", &adjust_name);
13161313
fragBuilder->codeAppendf(
13171314
R"SkSL(%s = half4(0.0);
1318-
do half4 _0_adjust;
1319-
{
1320-
_0_adjust = %s + half4(0.125);
1321-
}
1315+
do {
1316+
half4 _0_adjust;
1317+
{
1318+
_0_adjust = %s + half4(0.125);
1319+
}
13221320
1323-
%s = _0_adjust;
1324-
while (%s.x < 0.5);
1321+
%s = _0_adjust;
1322+
} while (%s.x < 0.5);
13251323
)SkSL"
13261324
, args.fOutputColor, args.fOutputColor, args.fOutputColor, args.fOutputColor);
13271325
)__Cpp__"});
@@ -1374,8 +1372,6 @@ R"SkSL(for (%s = half4(0.0625);
13741372
}
13751373

13761374
DEF_TEST(SkSLFPInlinedForBodyMustBeInAScope, r) {
1377-
// NOTE: this test exposes a bug with the inliner. The inlined function body is not wrapped in a
1378-
// scope, so the inlined code is emitted outside of the for loop.
13791375
test(r,
13801376
*SkSL::ShaderCapsFactory::Default(),
13811377
R"__SkSL__(
@@ -1392,13 +1388,14 @@ DEF_TEST(SkSLFPInlinedForBodyMustBeInAScope, r) {
13921388
/*expectedCPP=*/{
13931389
R"__Cpp__(fragBuilder->codeAppendf(
13941390
R"SkSL(%s = half4(0.0);
1395-
for (int x = 0;x < 4; ++x) half4 _0_adjust;
1396-
{
1397-
_0_adjust = %s + half4(0.125);
1398-
}
1399-
1400-
%s = _0_adjust;
1391+
for (int x = 0;x < 4; ++x) {
1392+
half4 _0_adjust;
1393+
{
1394+
_0_adjust = %s + half4(0.125);
1395+
}
14011396
1397+
%s = _0_adjust;
1398+
}
14021399
)SkSL"
14031400
, args.fOutputColor, args.fOutputColor, args.fOutputColor);
14041401
)__Cpp__"});

0 commit comments

Comments
 (0)