xref: /aosp_15_r20/external/skia/src/sksl/ir/SkSLBlock.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2021 Google LLC
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "src/sksl/ir/SkSLBlock.h"
9 
10 #include "src/sksl/ir/SkSLNop.h"
11 
12 namespace SkSL {
13 
Make(Position pos,StatementArray statements,Kind kind,std::unique_ptr<SymbolTable> symbols)14 std::unique_ptr<Statement> Block::Make(Position pos,
15                                        StatementArray statements,
16                                        Kind kind,
17                                        std::unique_ptr<SymbolTable> symbols) {
18     // We can't simplify away braces or populated symbol tables.
19     if (kind == Kind::kBracedScope || (symbols && symbols->count())) {
20         return std::make_unique<Block>(pos, std::move(statements), kind, std::move(symbols));
21     }
22 
23     // If the Block is completely empty, synthesize a Nop.
24     if (statements.empty()) {
25         return Nop::Make();
26     }
27 
28     if (statements.size() > 1) {
29         // The statement array contains multiple statements, but some of those might be no-ops.
30         // If the statement array only contains one real statement, we can return that directly and
31         // avoid creating an additional Block node.
32         std::unique_ptr<Statement>* foundStatement = nullptr;
33         for (std::unique_ptr<Statement>& stmt : statements) {
34             if (!stmt->isEmpty()) {
35                 if (!foundStatement) {
36                     // We found a single non-empty statement. Remember it and keep looking.
37                     foundStatement = &stmt;
38                     continue;
39                 }
40                 // We found more than one non-empty statement. We actually do need a Block.
41                 return std::make_unique<Block>(pos, std::move(statements), kind,
42                                                /*symbols=*/nullptr);
43             }
44         }
45 
46         // The array wrapped one valid Statement. Avoid allocating a Block by returning it directly.
47         if (foundStatement) {
48             return std::move(*foundStatement);
49         }
50 
51         // The statement array contained nothing but empty statements!
52         // In this case, we don't actually need to allocate a Block.
53         // We can just return one of those empty statements. Fall through to...
54     }
55 
56     return std::move(statements.front());
57 }
58 
MakeBlock(Position pos,StatementArray statements,Kind kind,std::unique_ptr<SymbolTable> symbols)59 std::unique_ptr<Block> Block::MakeBlock(Position pos,
60                                         StatementArray statements,
61                                         Kind kind,
62                                         std::unique_ptr<SymbolTable> symbols) {
63     // Nothing to optimize here--eliminating empty statements doesn't actually improve the generated
64     // code, and we promise to return a Block.
65     return std::make_unique<Block>(pos, std::move(statements), kind, std::move(symbols));
66 }
67 
MakeCompoundStatement(std::unique_ptr<Statement> existing,std::unique_ptr<Statement> additional)68 std::unique_ptr<Statement> Block::MakeCompoundStatement(std::unique_ptr<Statement> existing,
69                                                         std::unique_ptr<Statement> additional) {
70     // If either of the two Statements is empty, return the other.
71     if (!existing || existing->isEmpty()) {
72         return additional;
73     }
74     if (!additional || additional->isEmpty()) {
75         return existing;
76     }
77 
78     // If the existing statement is a compound-statement Block, append the additional statement.
79     if (existing->is<Block>()) {
80         SkSL::Block& block = existing->as<Block>();
81         if (block.blockKind() == Block::Kind::kCompoundStatement) {
82             block.children().push_back(std::move(additional));
83             return existing;
84         }
85     }
86 
87     // The existing statement was not a compound-statement Block; create one, and put both
88     // statements inside of it.
89     Position pos = existing->fPosition.rangeThrough(additional->fPosition);
90     StatementArray stmts;
91     stmts.reserve_exact(2);
92     stmts.push_back(std::move(existing));
93     stmts.push_back(std::move(additional));
94     return Block::Make(pos, std::move(stmts), Block::Kind::kCompoundStatement);
95 }
96 
description() const97 std::string Block::description() const {
98     std::string result;
99 
100     // Write scope markers if this block is a scope, or if the block is empty (since we need to emit
101     // something here to make the code valid).
102     bool isScope = this->isScope() || this->isEmpty();
103     if (isScope) {
104         result += "{";
105     }
106     for (const std::unique_ptr<Statement>& stmt : this->children()) {
107         result += "\n";
108         result += stmt->description();
109     }
110     result += isScope ? "\n}\n" : "\n";
111     return result;
112 }
113 
114 }  // namespace SkSL
115