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