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 #include "src/sksl/ir/SkSLSymbolTable.h"
12
13 #include <type_traits>
14
15 namespace SkSL {
16
Make(Position pos,StatementArray statements,Kind kind,std::shared_ptr<SymbolTable> symbols)17 std::unique_ptr<Statement> Block::Make(Position pos,
18 StatementArray statements,
19 Kind kind,
20 std::shared_ptr<SymbolTable> symbols) {
21 // We can't simplify away braces or populated symbol tables.
22 if (kind == Kind::kBracedScope || (symbols && symbols->count())) {
23 return std::make_unique<Block>(pos, std::move(statements), kind, std::move(symbols));
24 }
25
26 // If the Block is completely empty, synthesize a Nop.
27 if (statements.empty()) {
28 return Nop::Make();
29 }
30
31 if (statements.size() > 1) {
32 // The statement array contains multiple statements, but some of those might be no-ops.
33 // If the statement array only contains one real statement, we can return that directly and
34 // avoid creating an additional Block node.
35 std::unique_ptr<Statement>* foundStatement = nullptr;
36 for (std::unique_ptr<Statement>& stmt : statements) {
37 if (!stmt->isEmpty()) {
38 if (!foundStatement) {
39 // We found a single non-empty statement. Remember it and keep looking.
40 foundStatement = &stmt;
41 continue;
42 }
43 // We found more than one non-empty statement. We actually do need a Block.
44 return std::make_unique<Block>(pos, std::move(statements), kind,
45 /*symbols=*/nullptr);
46 }
47 }
48
49 // The array wrapped one valid Statement. Avoid allocating a Block by returning it directly.
50 if (foundStatement) {
51 return std::move(*foundStatement);
52 }
53
54 // The statement array contained nothing but empty statements!
55 // In this case, we don't actually need to allocate a Block.
56 // We can just return one of those empty statements. Fall through to...
57 }
58
59 return std::move(statements.front());
60 }
61
MakeBlock(Position pos,StatementArray statements,Kind kind,std::shared_ptr<SymbolTable> symbols)62 std::unique_ptr<Block> Block::MakeBlock(Position pos,
63 StatementArray statements,
64 Kind kind,
65 std::shared_ptr<SymbolTable> symbols) {
66 // Nothing to optimize here--eliminating empty statements doesn't actually improve the generated
67 // code, and we promise to return a Block.
68 return std::make_unique<Block>(pos, std::move(statements), kind, std::move(symbols));
69 }
70
clone() const71 std::unique_ptr<Statement> Block::clone() const {
72 StatementArray cloned;
73 cloned.reserve_back(this->children().size());
74 for (const std::unique_ptr<Statement>& stmt : this->children()) {
75 cloned.push_back(stmt->clone());
76 }
77 return std::make_unique<Block>(fPosition,
78 std::move(cloned),
79 fBlockKind,
80 SymbolTable::WrapIfBuiltin(this->symbolTable()));
81 }
82
description() const83 std::string Block::description() const {
84 std::string result;
85
86 // Write scope markers if this block is a scope, or if the block is empty (since we need to emit
87 // something here to make the code valid).
88 bool isScope = this->isScope() || this->isEmpty();
89 if (isScope) {
90 result += "{";
91 }
92 for (const std::unique_ptr<Statement>& stmt : this->children()) {
93 result += "\n";
94 result += stmt->description();
95 }
96 result += isScope ? "\n}\n" : "\n";
97 return result;
98 }
99
100 } // namespace SkSL
101