SkSLCompiler.cpp revision 5af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64
1b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas/*
2b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas * Copyright 2016 Google Inc.
3b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas *
4b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas * Use of this source code is governed by a BSD-style license that can be
5b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas * found in the LICENSE file.
6b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas */
76ad9909fb7ccc973f35bbd222b0f424b8c3df0d2Mike Klein
8b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#include "SkSLCompiler.h"
9b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
1022f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas#include "SkSLCFGGenerator.h"
11762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas#include "SkSLCPPCodeGenerator.h"
12941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas#include "SkSLGLSLCodeGenerator.h"
13762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas#include "SkSLHCodeGenerator.h"
14b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#include "SkSLIRGenerator.h"
15b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#include "SkSLSPIRVCodeGenerator.h"
16b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#include "ir/SkSLExpression.h"
17cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas#include "ir/SkSLExpressionStatement.h"
18b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#include "ir/SkSLIntLiteral.h"
195961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas#include "ir/SkSLModifiersDeclaration.h"
20cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas#include "ir/SkSLNop.h"
21b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#include "ir/SkSLSymbolTable.h"
22cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas#include "ir/SkSLTernaryExpression.h"
23ddb37d67ba4db42fa5c6012b58d0f4985b454dc0ethannicholas#include "ir/SkSLUnresolvedFunction.h"
2422f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas#include "ir/SkSLVarDeclarations.h"
25b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
26a6ae1f7cda072ff814a838e2d9013a017552cc35Ethan Nicholas#ifdef SK_ENABLE_SPIRV_VALIDATION
27a6ae1f7cda072ff814a838e2d9013a017552cc35Ethan Nicholas#include "spirv-tools/libspirv.hpp"
28a6ae1f7cda072ff814a838e2d9013a017552cc35Ethan Nicholas#endif
29a6ae1f7cda072ff814a838e2d9013a017552cc35Ethan Nicholas
30b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#define STRINGIFY(x) #x
31b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
32b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas// include the built-in shader symbols as static strings
33b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
345961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholasstatic const char* SKSL_INCLUDE =
35b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#include "sksl.include"
36b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas;
37b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
385961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholasstatic const char* SKSL_VERT_INCLUDE =
39b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#include "sksl_vert.include"
40b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas;
41b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
425961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholasstatic const char* SKSL_FRAG_INCLUDE =
43b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas#include "sksl_frag.include"
44b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas;
45b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
4652cad15d0b4443b763a7d41ec8d1131a7638f866Ethan Nicholasstatic const char* SKSL_GEOM_INCLUDE =
4752cad15d0b4443b763a7d41ec8d1131a7638f866Ethan Nicholas#include "sksl_geom.include"
4852cad15d0b4443b763a7d41ec8d1131a7638f866Ethan Nicholas;
4952cad15d0b4443b763a7d41ec8d1131a7638f866Ethan Nicholas
50762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholasstatic const char* SKSL_FP_INCLUDE =
51762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas#include "sksl_fp.include"
52762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas;
53762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas
54762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas
55b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholasnamespace SkSL {
56b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
576e1cbc012b10e99d9caed19eef43939778d1d8ffEthan NicholasCompiler::Compiler(Flags flags)
586e1cbc012b10e99d9caed19eef43939778d1d8ffEthan Nicholas: fFlags(flags)
596e1cbc012b10e99d9caed19eef43939778d1d8ffEthan Nicholas, fErrorCount(0) {
608feeff929e57ea63914213f3b14d8f00b287a0adEthan Nicholas    auto types = std::shared_ptr<SymbolTable>(new SymbolTable(this));
618feeff929e57ea63914213f3b14d8f00b287a0adEthan Nicholas    auto symbols = std::shared_ptr<SymbolTable>(new SymbolTable(types, this));
62d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    fIRGenerator = new IRGenerator(&fContext, symbols, *this);
63b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    fTypes = types;
64d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    #define ADD_TYPE(t) types->addWithoutOwnership(fContext.f ## t ## _Type->fName, \
65d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas                                                   fContext.f ## t ## _Type.get())
66b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(Void);
67b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(Float);
685af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas    ADD_TYPE(Float2);
695af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas    ADD_TYPE(Float3);
705af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas    ADD_TYPE(Float4);
71b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(Double);
725af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas    ADD_TYPE(Double2);
735af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas    ADD_TYPE(Double3);
745af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas    ADD_TYPE(Double4);
75b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(Int);
765af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas    ADD_TYPE(Int2);
775af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas    ADD_TYPE(Int3);
785af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas    ADD_TYPE(Int4);
79b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(UInt);
805af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas    ADD_TYPE(UInt2);
815af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas    ADD_TYPE(UInt3);
825af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas    ADD_TYPE(UInt4);
83b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(Bool);
845af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas    ADD_TYPE(Bool2);
855af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas    ADD_TYPE(Bool3);
865af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas    ADD_TYPE(Bool4);
875af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas    ADD_TYPE(Float2x2);
885af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas    ADD_TYPE(Float2x3);
895af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas    ADD_TYPE(Float2x4);
905af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas    ADD_TYPE(Float3x2);
915af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas    ADD_TYPE(Float3x3);
925af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas    ADD_TYPE(Float3x4);
935af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas    ADD_TYPE(Float4x2);
945af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas    ADD_TYPE(Float4x3);
955af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas    ADD_TYPE(Float4x4);
96b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(GenType);
97b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(GenDType);
98b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(GenIType);
99b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(GenUType);
100b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(GenBType);
101b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(Mat);
102b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(Vec);
103b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(GVec);
104b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(GVec2);
105b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(GVec3);
106b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(GVec4);
107b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(DVec);
108b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(IVec);
109b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(UVec);
110b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(BVec);
111b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
112b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(Sampler1D);
113b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(Sampler2D);
114b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(Sampler3D);
1155961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    ADD_TYPE(SamplerExternalOES);
116b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(SamplerCube);
117b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(Sampler2DRect);
118b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(Sampler1DArray);
119b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(Sampler2DArray);
120b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(SamplerCubeArray);
121b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(SamplerBuffer);
122b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(Sampler2DMS);
123b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(Sampler2DMSArray);
124b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
125bf7b620b1e44985b164a8bd68031a7613fe0bb9bBrian Salomon    ADD_TYPE(ISampler2D);
126bf7b620b1e44985b164a8bd68031a7613fe0bb9bBrian Salomon
1272a51de82ceb6790f329b9f4cc85e61f34fc2d0d4Brian Salomon    ADD_TYPE(Image2D);
1282a51de82ceb6790f329b9f4cc85e61f34fc2d0d4Brian Salomon    ADD_TYPE(IImage2D);
1292a51de82ceb6790f329b9f4cc85e61f34fc2d0d4Brian Salomon
13064773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel    ADD_TYPE(SubpassInput);
13164773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel    ADD_TYPE(SubpassInputMS);
13264773e6c9f61fb319f597a8d7dd7ee377d51a43aGreg Daniel
133b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(GSampler1D);
134b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(GSampler2D);
135b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(GSampler3D);
136b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(GSamplerCube);
137b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(GSampler2DRect);
138b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(GSampler1DArray);
139b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(GSampler2DArray);
140b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(GSamplerCubeArray);
141b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(GSamplerBuffer);
142b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(GSampler2DMS);
143b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(GSampler2DMSArray);
144b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
145b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(Sampler1DShadow);
146b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(Sampler2DShadow);
147b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(SamplerCubeShadow);
148b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(Sampler2DRectShadow);
149b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(Sampler1DArrayShadow);
150b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(Sampler2DArrayShadow);
151b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(SamplerCubeArrayShadow);
152b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(GSampler2DArrayShadow);
153b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ADD_TYPE(GSamplerCubeArrayShadow);
154762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    ADD_TYPE(ColorSpaceXform);
155b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
1560df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholas    String skCapsName("sk_Caps");
1570df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholas    Variable* skCaps = new Variable(Position(), Modifiers(), skCapsName,
1583605ace7ddaf0b576bf6df1c7a550ab4f44d22a8Ethan Nicholas                                    *fContext.fSkCaps_Type, Variable::kGlobal_Storage);
1593605ace7ddaf0b576bf6df1c7a550ab4f44d22a8Ethan Nicholas    fIRGenerator->fSymbolTable->add(skCapsName, std::unique_ptr<Symbol>(skCaps));
1603605ace7ddaf0b576bf6df1c7a550ab4f44d22a8Ethan Nicholas
161762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    String skArgsName("sk_Args");
162762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    Variable* skArgs = new Variable(Position(), Modifiers(), skArgsName,
163762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas                                    *fContext.fSkArgs_Type, Variable::kGlobal_Storage);
164762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    fIRGenerator->fSymbolTable->add(skArgsName, std::unique_ptr<Symbol>(skArgs));
165762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas
1665961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    Modifiers::Flag ignored1;
1675961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    std::vector<std::unique_ptr<ProgramElement>> ignored2;
1687da6dfabc44891c51dedcb4754477b662d8c8a0aEthan Nicholas    fIRGenerator->convertProgram(String(SKSL_INCLUDE), *fTypes, &ignored1, &ignored2);
169ddb37d67ba4db42fa5c6012b58d0f4985b454dc0ethannicholas    fIRGenerator->fSymbolTable->markAllFunctionsBuiltin();
170b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    ASSERT(!fErrorCount);
171b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
172b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
173b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholasCompiler::~Compiler() {
174b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    delete fIRGenerator;
175b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
176b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
17722f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas// add the definition created by assigning to the lvalue to the definition set
17886a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholasvoid Compiler::addDefinition(const Expression* lvalue, std::unique_ptr<Expression>* expr,
17986a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                             DefinitionMap* definitions) {
18022f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas    switch (lvalue->fKind) {
18122f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas        case Expression::kVariableReference_Kind: {
18222f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas            const Variable& var = ((VariableReference*) lvalue)->fVariable;
18322f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas            if (var.fStorage == Variable::kLocal_Storage) {
18422f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas                (*definitions)[&var] = expr;
18522f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas            }
18622f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas            break;
18722f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas        }
18822f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas        case Expression::kSwizzle_Kind:
18922f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas            // We consider the variable written to as long as at least some of its components have
19022f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas            // been written to. This will lead to some false negatives (we won't catch it if you
19122f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas            // write to foo.x and then read foo.y), but being stricter could lead to false positives
1926ad9909fb7ccc973f35bbd222b0f424b8c3df0d2Mike Klein            // (we write to foo.x, and then pass foo to a function which happens to only read foo.x,
1936ad9909fb7ccc973f35bbd222b0f424b8c3df0d2Mike Klein            // but since we pass foo as a whole it is flagged as an error) unless we perform a much
19422f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas            // more complicated whole-program analysis. This is probably good enough.
1956ad9909fb7ccc973f35bbd222b0f424b8c3df0d2Mike Klein            this->addDefinition(((Swizzle*) lvalue)->fBase.get(),
19686a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                                (std::unique_ptr<Expression>*) &fContext.fDefined_Expression,
19722f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas                                definitions);
19822f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas            break;
19922f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas        case Expression::kIndex_Kind:
20022f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas            // see comments in Swizzle
2016ad9909fb7ccc973f35bbd222b0f424b8c3df0d2Mike Klein            this->addDefinition(((IndexExpression*) lvalue)->fBase.get(),
20286a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                                (std::unique_ptr<Expression>*) &fContext.fDefined_Expression,
20322f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas                                definitions);
20422f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas            break;
20522f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas        case Expression::kFieldAccess_Kind:
20622f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas            // see comments in Swizzle
2076ad9909fb7ccc973f35bbd222b0f424b8c3df0d2Mike Klein            this->addDefinition(((FieldAccess*) lvalue)->fBase.get(),
20886a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                                (std::unique_ptr<Expression>*) &fContext.fDefined_Expression,
20922f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas                                definitions);
21022f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas            break;
21122f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas        default:
21222f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas            // not an lvalue, can't happen
21322f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas            ASSERT(false);
21422f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas    }
21522f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas}
21622f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas
21722f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas// add local variables defined by this node to the set
2186ad9909fb7ccc973f35bbd222b0f424b8c3df0d2Mike Kleinvoid Compiler::addDefinitions(const BasicBlock::Node& node,
21986a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                              DefinitionMap* definitions) {
22022f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas    switch (node.fKind) {
22122f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas        case BasicBlock::Node::kExpression_Kind: {
222cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            ASSERT(node.expression());
223cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            const Expression* expr = (Expression*) node.expression()->get();
22486a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas            switch (expr->fKind) {
22586a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                case Expression::kBinary_Kind: {
22686a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                    BinaryExpression* b = (BinaryExpression*) expr;
22786a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                    if (b->fOperator == Token::EQ) {
22886a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                        this->addDefinition(b->fLeft.get(), &b->fRight, definitions);
22986a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                    } else if (Token::IsAssignment(b->fOperator)) {
23086a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                        this->addDefinition(
23186a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                                       b->fLeft.get(),
23286a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                                       (std::unique_ptr<Expression>*) &fContext.fDefined_Expression,
23386a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                                       definitions);
23486a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas
23586a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                    }
23686a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                    break;
23786a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                }
23886a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                case Expression::kPrefix_Kind: {
23986a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                    const PrefixExpression* p = (PrefixExpression*) expr;
24086a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                    if (p->fOperator == Token::MINUSMINUS || p->fOperator == Token::PLUSPLUS) {
24186a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                        this->addDefinition(
24286a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                                       p->fOperand.get(),
24386a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                                       (std::unique_ptr<Expression>*) &fContext.fDefined_Expression,
24486a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                                       definitions);
24586a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                    }
24686a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                    break;
24722f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas                }
24886a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                case Expression::kPostfix_Kind: {
24986a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                    const PostfixExpression* p = (PostfixExpression*) expr;
25086a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                    if (p->fOperator == Token::MINUSMINUS || p->fOperator == Token::PLUSPLUS) {
25186a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                        this->addDefinition(
25286a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                                       p->fOperand.get(),
25386a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                                       (std::unique_ptr<Expression>*) &fContext.fDefined_Expression,
25486a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                                       definitions);
25586a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                    }
25686a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                    break;
25786a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                }
258cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                case Expression::kVariableReference_Kind: {
259cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    const VariableReference* v = (VariableReference*) expr;
260cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    if (v->fRefKind != VariableReference::kRead_RefKind) {
261cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                        this->addDefinition(
262cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                                       v,
263cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                                       (std::unique_ptr<Expression>*) &fContext.fDefined_Expression,
264cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                                       definitions);
265cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    }
266cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                }
26786a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                default:
26886a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                    break;
26922f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas            }
27022f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas            break;
27122f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas        }
27222f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas        case BasicBlock::Node::kStatement_Kind: {
273cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            const Statement* stmt = (Statement*) node.statement()->get();
274b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas            if (stmt->fKind == Statement::kVarDeclaration_Kind) {
275b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas                VarDeclaration& vd = (VarDeclaration&) *stmt;
276b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas                if (vd.fValue) {
277b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas                    (*definitions)[vd.fVar] = &vd.fValue;
27822f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas                }
27922f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas            }
28022f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas            break;
28122f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas        }
28222f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas    }
28322f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas}
28422f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas
28522f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholasvoid Compiler::scanCFG(CFG* cfg, BlockId blockId, std::set<BlockId>* workList) {
28622f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas    BasicBlock& block = cfg->fBlocks[blockId];
28722f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas
28822f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas    // compute definitions after this block
28986a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas    DefinitionMap after = block.fBefore;
29022f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas    for (const BasicBlock::Node& n : block.fNodes) {
29122f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas        this->addDefinitions(n, &after);
29222f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas    }
29322f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas
29422f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas    // propagate definitions to exits
29522f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas    for (BlockId exitId : block.fExits) {
29622f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas        BasicBlock& exit = cfg->fBlocks[exitId];
29722f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas        for (const auto& pair : after) {
29886a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas            std::unique_ptr<Expression>* e1 = pair.second;
29986a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas            auto found = exit.fBefore.find(pair.first);
30086a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas            if (found == exit.fBefore.end()) {
30186a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                // exit has no definition for it, just copy it
30286a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                workList->insert(exitId);
30322f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas                exit.fBefore[pair.first] = e1;
30422f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas            } else {
30586a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                // exit has a (possibly different) value already defined
30686a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                std::unique_ptr<Expression>* e2 = exit.fBefore[pair.first];
30722f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas                if (e1 != e2) {
30822f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas                    // definition has changed, merge and add exit block to worklist
30922f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas                    workList->insert(exitId);
310af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas                    if (e1 && e2) {
311af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas                        exit.fBefore[pair.first] =
31286a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                                       (std::unique_ptr<Expression>*) &fContext.fDefined_Expression;
313af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas                    } else {
314af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas                        exit.fBefore[pair.first] = nullptr;
315af19769831f1c4c3b90c85aa9f8851cd8bbf86d5Ethan Nicholas                    }
31622f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas                }
31722f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas            }
31822f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas        }
31922f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas    }
32022f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas}
32122f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas
32222f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas// returns a map which maps all local variables in the function to null, indicating that their value
32322f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas// is initially unknown
32486a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholasstatic DefinitionMap compute_start_state(const CFG& cfg) {
32586a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas    DefinitionMap result;
3266ad9909fb7ccc973f35bbd222b0f424b8c3df0d2Mike Klein    for (const auto& block : cfg.fBlocks) {
3276ad9909fb7ccc973f35bbd222b0f424b8c3df0d2Mike Klein        for (const auto& node : block.fNodes) {
32822f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas            if (node.fKind == BasicBlock::Node::kStatement_Kind) {
329cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                ASSERT(node.statement());
330cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                const Statement* s = node.statement()->get();
33122f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas                if (s->fKind == Statement::kVarDeclarations_Kind) {
33222f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas                    const VarDeclarationsStatement* vd = (const VarDeclarationsStatement*) s;
333cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    for (const auto& decl : vd->fDeclaration->fVars) {
33491a1053f2d4f7be31d7f3a14f718d0e457e49710Ethan Nicholas                        if (decl->fKind == Statement::kVarDeclaration_Kind) {
33591a1053f2d4f7be31d7f3a14f718d0e457e49710Ethan Nicholas                            result[((VarDeclaration&) *decl).fVar] = nullptr;
33691a1053f2d4f7be31d7f3a14f718d0e457e49710Ethan Nicholas                        }
3376ad9909fb7ccc973f35bbd222b0f424b8c3df0d2Mike Klein                    }
33822f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas                }
33922f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas            }
34022f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas        }
34122f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas    }
34222f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas    return result;
34322f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas}
34422f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas
345cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas/**
346cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas * Returns true if assigning to this lvalue has no effect.
347cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas */
348cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholasstatic bool is_dead(const Expression& lvalue) {
349cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    switch (lvalue.fKind) {
350cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        case Expression::kVariableReference_Kind:
351cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            return ((VariableReference&) lvalue).fVariable.dead();
352cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        case Expression::kSwizzle_Kind:
353cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            return is_dead(*((Swizzle&) lvalue).fBase);
354cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        case Expression::kFieldAccess_Kind:
355cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            return is_dead(*((FieldAccess&) lvalue).fBase);
356cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        case Expression::kIndex_Kind: {
357cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            const IndexExpression& idx = (IndexExpression&) lvalue;
358cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            return is_dead(*idx.fBase) && !idx.fIndex->hasSideEffects();
359cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        }
360cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        default:
361cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            ABORT("invalid lvalue: %s\n", lvalue.description().c_str());
362cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    }
363cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas}
364cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas
365cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas/**
366cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas * Returns true if this is an assignment which can be collapsed down to just the right hand side due
367cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas * to a dead target and lack of side effects on the left hand side.
368cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas */
369cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholasstatic bool dead_assignment(const BinaryExpression& b) {
370cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    if (!Token::IsAssignment(b.fOperator)) {
371cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        return false;
372cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    }
373cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    return is_dead(*b.fLeft);
374cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas}
37522f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas
376cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholasvoid Compiler::computeDataFlow(CFG* cfg) {
377cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    cfg->fBlocks[cfg->fStart].fBefore = compute_start_state(*cfg);
37822f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas    std::set<BlockId> workList;
379cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    for (BlockId i = 0; i < cfg->fBlocks.size(); i++) {
38022f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas        workList.insert(i);
38122f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas    }
38222f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas    while (workList.size()) {
38322f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas        BlockId next = *workList.begin();
38422f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas        workList.erase(workList.begin());
385cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        this->scanCFG(cfg, next, &workList);
386cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    }
387cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas}
388cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas
389cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas/**
390cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
391cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
392cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
393cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas * need to be regenerated).
394cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas */
395cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholasbool try_replace_expression(BasicBlock* b,
396cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                            std::vector<BasicBlock::Node>::iterator* iter,
397cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                            std::unique_ptr<Expression>* newExpression) {
398cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    std::unique_ptr<Expression>* target = (*iter)->expression();
399cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    if (!b->tryRemoveExpression(iter)) {
400cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        *target = std::move(*newExpression);
401cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        return false;
402cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    }
403cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    *target = std::move(*newExpression);
404cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    return b->tryInsertExpression(iter, target);
405cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas}
406cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas
407cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas/**
408fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas * Returns true if the expression is a constant numeric literal with the specified value, or a
409fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas * constant vector with all elements equal to the specified value.
410cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas */
411fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholasbool is_constant(const Expression& expr, double value) {
412cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    switch (expr.fKind) {
413cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        case Expression::kIntLiteral_Kind:
414cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            return ((IntLiteral&) expr).fValue == value;
415cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        case Expression::kFloatLiteral_Kind:
416cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            return ((FloatLiteral&) expr).fValue == value;
417fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas        case Expression::kConstructor_Kind: {
418fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas            Constructor& c = (Constructor&) expr;
419fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas            if (c.fType.kind() == Type::kVector_Kind && c.isConstant()) {
420fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                for (int i = 0; i < c.fType.columns(); ++i) {
421fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                    if (!is_constant(c.getVecComponent(i), value)) {
422fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        return false;
423fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                    }
424fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                }
425fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                return true;
426fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas            }
427fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas            return false;
428fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas        }
429cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        default:
430cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            return false;
431cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    }
432cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas}
433cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas
434cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas/**
435cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
436cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas * and CFG structures).
437cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas */
438cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholasvoid delete_left(BasicBlock* b,
439cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                 std::vector<BasicBlock::Node>::iterator* iter,
440cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                 bool* outUpdated,
441cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                 bool* outNeedsRescan) {
442cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    *outUpdated = true;
443c2371a4e325fd123f2d47a9b85d3c8405e8d5e29Ethan Nicholas    std::unique_ptr<Expression>* target = (*iter)->expression();
444c2371a4e325fd123f2d47a9b85d3c8405e8d5e29Ethan Nicholas    ASSERT((*target)->fKind == Expression::kBinary_Kind);
445c2371a4e325fd123f2d47a9b85d3c8405e8d5e29Ethan Nicholas    BinaryExpression& bin = (BinaryExpression&) **target;
446c2371a4e325fd123f2d47a9b85d3c8405e8d5e29Ethan Nicholas    bool result;
447c2371a4e325fd123f2d47a9b85d3c8405e8d5e29Ethan Nicholas    if (bin.fOperator == Token::EQ) {
4484b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas        result = b->tryRemoveLValueBefore(iter, bin.fLeft.get());
449c2371a4e325fd123f2d47a9b85d3c8405e8d5e29Ethan Nicholas    } else {
4504b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas        result = b->tryRemoveExpressionBefore(iter, bin.fLeft.get());
451c2371a4e325fd123f2d47a9b85d3c8405e8d5e29Ethan Nicholas    }
4524b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas    *target = std::move(bin.fRight);
453c2371a4e325fd123f2d47a9b85d3c8405e8d5e29Ethan Nicholas    if (!result) {
4544b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas        *outNeedsRescan = true;
4554b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas        return;
4564b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas    }
4574b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas    if (*iter == b->fNodes.begin()) {
458cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        *outNeedsRescan = true;
459c2371a4e325fd123f2d47a9b85d3c8405e8d5e29Ethan Nicholas        return;
460cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    }
461c2371a4e325fd123f2d47a9b85d3c8405e8d5e29Ethan Nicholas    --(*iter);
4624b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas    if ((*iter)->fKind != BasicBlock::Node::kExpression_Kind ||
4634b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas        (*iter)->expression() != &bin.fRight) {
4644b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas        *outNeedsRescan = true;
4654b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas        return;
4664b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas    }
467c2371a4e325fd123f2d47a9b85d3c8405e8d5e29Ethan Nicholas    *iter = b->fNodes.erase(*iter);
468c2371a4e325fd123f2d47a9b85d3c8405e8d5e29Ethan Nicholas    ASSERT((*iter)->expression() == target);
469cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas}
470cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas
471cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas/**
472cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
473cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas * CFG structures).
474cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas */
475cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholasvoid delete_right(BasicBlock* b,
476cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                  std::vector<BasicBlock::Node>::iterator* iter,
477cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                  bool* outUpdated,
478cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                  bool* outNeedsRescan) {
479cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    *outUpdated = true;
480c2371a4e325fd123f2d47a9b85d3c8405e8d5e29Ethan Nicholas    std::unique_ptr<Expression>* target = (*iter)->expression();
481c2371a4e325fd123f2d47a9b85d3c8405e8d5e29Ethan Nicholas    ASSERT((*target)->fKind == Expression::kBinary_Kind);
482c2371a4e325fd123f2d47a9b85d3c8405e8d5e29Ethan Nicholas    BinaryExpression& bin = (BinaryExpression&) **target;
483c2371a4e325fd123f2d47a9b85d3c8405e8d5e29Ethan Nicholas    if (!b->tryRemoveExpressionBefore(iter, bin.fRight.get())) {
484c2371a4e325fd123f2d47a9b85d3c8405e8d5e29Ethan Nicholas        *target = std::move(bin.fLeft);
485cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        *outNeedsRescan = true;
486c2371a4e325fd123f2d47a9b85d3c8405e8d5e29Ethan Nicholas        return;
487cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    }
4884b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas    *target = std::move(bin.fLeft);
4894b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas    if (*iter == b->fNodes.begin()) {
4904b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas        *outNeedsRescan = true;
4914b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas        return;
4924b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas    }
493c2371a4e325fd123f2d47a9b85d3c8405e8d5e29Ethan Nicholas    --(*iter);
4944b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas    if (((*iter)->fKind != BasicBlock::Node::kExpression_Kind ||
4954b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas        (*iter)->expression() != &bin.fLeft)) {
4964b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas        *outNeedsRescan = true;
4974b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas        return;
4984b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas    }
499c2371a4e325fd123f2d47a9b85d3c8405e8d5e29Ethan Nicholas    *iter = b->fNodes.erase(*iter);
500c2371a4e325fd123f2d47a9b85d3c8405e8d5e29Ethan Nicholas    ASSERT((*iter)->expression() == target);
501cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas}
502cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas
503fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas/**
504fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas * Constructs the specified type using a single argument.
505fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas */
506fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholasstatic std::unique_ptr<Expression> construct(const Type& type, std::unique_ptr<Expression> v) {
507fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas    std::vector<std::unique_ptr<Expression>> args;
508fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas    args.push_back(std::move(v));
509fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas    auto result = std::unique_ptr<Expression>(new Constructor(Position(), type, std::move(args)));
510fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas    return result;
511fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas}
512fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas
513fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas/**
514fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
515fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
516fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas */
517fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholasstatic void vectorize(BasicBlock* b,
518fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                      std::vector<BasicBlock::Node>::iterator* iter,
519fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                      const Type& type,
520fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                      std::unique_ptr<Expression>* otherExpression,
521fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                      bool* outUpdated,
522fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                      bool* outNeedsRescan) {
523fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas    ASSERT((*(*iter)->expression())->fKind == Expression::kBinary_Kind);
524fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas    ASSERT(type.kind() == Type::kVector_Kind);
525fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas    ASSERT((*otherExpression)->fType.kind() == Type::kScalar_Kind);
526fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas    *outUpdated = true;
527fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas    std::unique_ptr<Expression>* target = (*iter)->expression();
528fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas    if (!b->tryRemoveExpression(iter)) {
529fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas        *target = construct(type, std::move(*otherExpression));
530fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas        *outNeedsRescan = true;
531fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas    } else {
532fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas        *target = construct(type, std::move(*otherExpression));
533fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas        if (!b->tryInsertExpression(iter, target)) {
534fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas            *outNeedsRescan = true;
535fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas        }
536fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas    }
537fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas}
538fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas
539fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas/**
540fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
541fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas * left to yield vec<n>(x).
542fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas */
543fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholasstatic void vectorize_left(BasicBlock* b,
544fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                           std::vector<BasicBlock::Node>::iterator* iter,
545fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                           bool* outUpdated,
546fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                           bool* outNeedsRescan) {
547fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas    BinaryExpression& bin = (BinaryExpression&) **(*iter)->expression();
548fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas    vectorize(b, iter, bin.fRight->fType, &bin.fLeft, outUpdated, outNeedsRescan);
549fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas}
550fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas
551fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas/**
552fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
553fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas * right to yield vec<n>(y).
554fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas */
555fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholasstatic void vectorize_right(BasicBlock* b,
556fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            std::vector<BasicBlock::Node>::iterator* iter,
557fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            bool* outUpdated,
558fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            bool* outNeedsRescan) {
559fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas    BinaryExpression& bin = (BinaryExpression&) **(*iter)->expression();
560fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas    vectorize(b, iter, bin.fLeft->fType, &bin.fRight, outUpdated, outNeedsRescan);
561fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas}
562fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas
563fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas// Mark that an expression which we were writing to is no longer being written to
564fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholasvoid clear_write(const Expression& expr) {
565fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas    switch (expr.fKind) {
566fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas        case Expression::kVariableReference_Kind: {
567fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas            ((VariableReference&) expr).setRefKind(VariableReference::kRead_RefKind);
568fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas            break;
569fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas        }
570fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas        case Expression::kFieldAccess_Kind:
571fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas            clear_write(*((FieldAccess&) expr).fBase);
572fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas            break;
573fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas        case Expression::kSwizzle_Kind:
574fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas            clear_write(*((Swizzle&) expr).fBase);
575fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas            break;
576fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas        case Expression::kIndex_Kind:
577fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas            clear_write(*((IndexExpression&) expr).fBase);
578fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas            break;
579fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas        default:
580fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas            ABORT("shouldn't be writing to this kind of expression\n");
581fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas            break;
582fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas    }
583fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas}
584fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas
585cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholasvoid Compiler::simplifyExpression(DefinitionMap& definitions,
586cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                                  BasicBlock& b,
587cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                                  std::vector<BasicBlock::Node>::iterator* iter,
588cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                                  std::unordered_set<const Variable*>* undefinedVariables,
589cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                                  bool* outUpdated,
590cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                                  bool* outNeedsRescan) {
591cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    Expression* expr = (*iter)->expression()->get();
592cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    ASSERT(expr);
593cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    if ((*iter)->fConstantPropagation) {
594cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator, definitions);
595cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        if (optimized) {
5964b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas            *outUpdated = true;
597cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            if (!try_replace_expression(&b, iter, &optimized)) {
598cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                *outNeedsRescan = true;
5994b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas                return;
600cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            }
601cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            ASSERT((*iter)->fKind == BasicBlock::Node::kExpression_Kind);
602cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            expr = (*iter)->expression()->get();
603cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        }
604cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    }
605cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    switch (expr->fKind) {
606cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        case Expression::kVariableReference_Kind: {
607cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            const Variable& var = ((VariableReference*) expr)->fVariable;
608cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            if (var.fStorage == Variable::kLocal_Storage && !definitions[&var] &&
609cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                (*undefinedVariables).find(&var) == (*undefinedVariables).end()) {
610cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                (*undefinedVariables).insert(&var);
611cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                this->error(expr->fPosition,
612cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                            "'" + var.fName + "' has not been assigned");
613cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            }
614cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            break;
615cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        }
616cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        case Expression::kTernary_Kind: {
617cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            TernaryExpression* t = (TernaryExpression*) expr;
618cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            if (t->fTest->fKind == Expression::kBoolLiteral_Kind) {
619cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                // ternary has a constant test, replace it with either the true or
620cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                // false branch
621cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                if (((BoolLiteral&) *t->fTest).fValue) {
622cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    (*iter)->setExpression(std::move(t->fIfTrue));
623cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                } else {
624cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    (*iter)->setExpression(std::move(t->fIfFalse));
625cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                }
626cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                *outUpdated = true;
627cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                *outNeedsRescan = true;
628cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            }
629cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            break;
630cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        }
631cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        case Expression::kBinary_Kind: {
632cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            BinaryExpression* bin = (BinaryExpression*) expr;
633c2371a4e325fd123f2d47a9b85d3c8405e8d5e29Ethan Nicholas            if (dead_assignment(*bin)) {
634c2371a4e325fd123f2d47a9b85d3c8405e8d5e29Ethan Nicholas                delete_left(&b, iter, outUpdated, outNeedsRescan);
635c2371a4e325fd123f2d47a9b85d3c8405e8d5e29Ethan Nicholas                break;
636c2371a4e325fd123f2d47a9b85d3c8405e8d5e29Ethan Nicholas            }
637c2371a4e325fd123f2d47a9b85d3c8405e8d5e29Ethan Nicholas            // collapse useless expressions like x * 1 or x + 0
638fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas            if (((bin->fLeft->fType.kind()  != Type::kScalar_Kind) &&
639fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                 (bin->fLeft->fType.kind()  != Type::kVector_Kind)) ||
640fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                ((bin->fRight->fType.kind() != Type::kScalar_Kind) &&
641fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                 (bin->fRight->fType.kind() != Type::kVector_Kind))) {
642fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                break;
643fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas            }
644cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            switch (bin->fOperator) {
645cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                case Token::STAR:
646cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    if (is_constant(*bin->fLeft, 1)) {
647fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        if (bin->fLeft->fType.kind() == Type::kVector_Kind &&
648fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            bin->fRight->fType.kind() == Type::kScalar_Kind) {
6495af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas                            // float4(1) * x -> float4(x)
650fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            vectorize_right(&b, iter, outUpdated, outNeedsRescan);
651fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        } else {
652fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            // 1 * x -> x
6535af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas                            // 1 * float4(x) -> float4(x)
6545af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas                            // float4(1) * float4(x) -> float4(x)
655fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            delete_left(&b, iter, outUpdated, outNeedsRescan);
656fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        }
657fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                    }
658fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                    else if (is_constant(*bin->fLeft, 0)) {
659fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        if (bin->fLeft->fType.kind() == Type::kScalar_Kind &&
660fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            bin->fRight->fType.kind() == Type::kVector_Kind) {
6615af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas                            // 0 * float4(x) -> float4(0)
662fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            vectorize_left(&b, iter, outUpdated, outNeedsRescan);
663fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        } else {
664fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            // 0 * x -> 0
6655af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas                            // float4(0) * x -> float4(0)
6665af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas                            // float4(0) * float4(x) -> float4(0)
667fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            delete_right(&b, iter, outUpdated, outNeedsRescan);
668fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        }
669cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    }
670cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    else if (is_constant(*bin->fRight, 1)) {
671fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        if (bin->fLeft->fType.kind() == Type::kScalar_Kind &&
672fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            bin->fRight->fType.kind() == Type::kVector_Kind) {
6735af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas                            // x * float4(1) -> float4(x)
674fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            vectorize_left(&b, iter, outUpdated, outNeedsRescan);
675fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        } else {
676fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            // x * 1 -> x
6775af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas                            // float4(x) * 1 -> float4(x)
6785af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas                            // float4(x) * float4(1) -> float4(x)
679fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            delete_right(&b, iter, outUpdated, outNeedsRescan);
680fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        }
681fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                    }
682fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                    else if (is_constant(*bin->fRight, 0)) {
683fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        if (bin->fLeft->fType.kind() == Type::kVector_Kind &&
684fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            bin->fRight->fType.kind() == Type::kScalar_Kind) {
6855af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas                            // float4(x) * 0 -> float4(0)
686fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            vectorize_right(&b, iter, outUpdated, outNeedsRescan);
687fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        } else {
688fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            // x * 0 -> 0
6895af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas                            // x * float4(0) -> float4(0)
6905af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas                            // float4(x) * float4(0) -> float4(0)
691fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            delete_left(&b, iter, outUpdated, outNeedsRescan);
692fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        }
693cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    }
694cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    break;
69556e42714d351f8ecb662136076166904b9934b71Ethan Nicholas                case Token::PLUS:
696cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    if (is_constant(*bin->fLeft, 0)) {
697fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        if (bin->fLeft->fType.kind() == Type::kVector_Kind &&
698fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            bin->fRight->fType.kind() == Type::kScalar_Kind) {
6995af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas                            // float4(0) + x -> float4(x)
700fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            vectorize_right(&b, iter, outUpdated, outNeedsRescan);
701fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        } else {
702fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            // 0 + x -> x
7035af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas                            // 0 + float4(x) -> float4(x)
7045af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas                            // float4(0) + float4(x) -> float4(x)
705fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            delete_left(&b, iter, outUpdated, outNeedsRescan);
706fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        }
707fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                    } else if (is_constant(*bin->fRight, 0)) {
708fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        if (bin->fLeft->fType.kind() == Type::kScalar_Kind &&
709fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            bin->fRight->fType.kind() == Type::kVector_Kind) {
7105af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas                            // x + float4(0) -> float4(x)
711fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            vectorize_left(&b, iter, outUpdated, outNeedsRescan);
712fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        } else {
713fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            // x + 0 -> x
7145af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas                            // float4(x) + 0 -> float4(x)
7155af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas                            // float4(x) + float4(0) -> float4(x)
716fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            delete_right(&b, iter, outUpdated, outNeedsRescan);
717fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        }
718cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    }
719fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                    break;
720fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                case Token::MINUS:
72156e42714d351f8ecb662136076166904b9934b71Ethan Nicholas                    if (is_constant(*bin->fRight, 0)) {
722fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        if (bin->fLeft->fType.kind() == Type::kScalar_Kind &&
723fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            bin->fRight->fType.kind() == Type::kVector_Kind) {
7245af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas                            // x - float4(0) -> float4(x)
725fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            vectorize_left(&b, iter, outUpdated, outNeedsRescan);
726fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        } else {
727fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            // x - 0 -> x
7285af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas                            // float4(x) - 0 -> float4(x)
7295af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas                            // float4(x) - float4(0) -> float4(x)
730fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            delete_right(&b, iter, outUpdated, outNeedsRescan);
731fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        }
732fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                    }
733fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                    break;
734fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                case Token::SLASH:
735fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                    if (is_constant(*bin->fRight, 1)) {
736fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        if (bin->fLeft->fType.kind() == Type::kScalar_Kind &&
737fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            bin->fRight->fType.kind() == Type::kVector_Kind) {
7385af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas                            // x / float4(1) -> float4(x)
739fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            vectorize_left(&b, iter, outUpdated, outNeedsRescan);
740fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        } else {
741fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            // x / 1 -> x
7425af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas                            // float4(x) / 1 -> float4(x)
7435af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas                            // float4(x) / float4(1) -> float4(x)
744fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            delete_right(&b, iter, outUpdated, outNeedsRescan);
745fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        }
746fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                    } else if (is_constant(*bin->fLeft, 0)) {
747fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        if (bin->fLeft->fType.kind() == Type::kScalar_Kind &&
748fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            bin->fRight->fType.kind() == Type::kVector_Kind) {
7495af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas                            // 0 / float4(x) -> float4(0)
750fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            vectorize_left(&b, iter, outUpdated, outNeedsRescan);
751fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        } else {
752fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            // 0 / x -> 0
7535af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas                            // float4(0) / x -> float4(0)
7545af9ea399d5e0344cc4b7da4e97b5dc5b3c74f64Ethan Nicholas                            // float4(0) / float4(x) -> float4(0)
755fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                            delete_right(&b, iter, outUpdated, outNeedsRescan);
756fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        }
757fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                    }
758fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                    break;
759fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                case Token::PLUSEQ:
760fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                    if (is_constant(*bin->fRight, 0)) {
761fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        clear_write(*bin->fLeft);
76256e42714d351f8ecb662136076166904b9934b71Ethan Nicholas                        delete_right(&b, iter, outUpdated, outNeedsRescan);
76356e42714d351f8ecb662136076166904b9934b71Ethan Nicholas                    }
76456e42714d351f8ecb662136076166904b9934b71Ethan Nicholas                    break;
765fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                case Token::MINUSEQ:
76656e42714d351f8ecb662136076166904b9934b71Ethan Nicholas                    if (is_constant(*bin->fRight, 0)) {
767fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        clear_write(*bin->fLeft);
768cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                        delete_right(&b, iter, outUpdated, outNeedsRescan);
769cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    }
770cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    break;
771fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                case Token::STAREQ:
772fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                    if (is_constant(*bin->fRight, 1)) {
773fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        clear_write(*bin->fLeft);
774fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        delete_right(&b, iter, outUpdated, outNeedsRescan);
775fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                    }
776fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                    break;
777fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                case Token::SLASHEQ:
778cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    if (is_constant(*bin->fRight, 1)) {
779fe53e5828fd31326cdc4594ca06435eb0af50afeEthan Nicholas                        clear_write(*bin->fLeft);
780cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                        delete_right(&b, iter, outUpdated, outNeedsRescan);
781cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    }
782cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    break;
783cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                default:
784cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    break;
785cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            }
786cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        }
787cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        default:
788cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            break;
78922f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas    }
790cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas}
791cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas
7925ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas// returns true if this statement could potentially execute a break at the current level (we ignore
7935ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas// nested loops and switches, since any breaks inside of them will merely break the loop / switch)
7945ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholasstatic bool contains_break(Statement& s) {
7955ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas    switch (s.fKind) {
7965ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas        case Statement::kBlock_Kind:
7975ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas            for (const auto& sub : ((Block&) s).fStatements) {
7985ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                if (contains_break(*sub)) {
7995ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                    return true;
8005ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                }
8015ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas            }
8025ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas            return false;
8035ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas        case Statement::kBreak_Kind:
8045ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas            return true;
8055ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas        case Statement::kIf_Kind: {
8065ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas            const IfStatement& i = (IfStatement&) s;
8075ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas            return contains_break(*i.fIfTrue) || (i.fIfFalse && contains_break(*i.fIfFalse));
8085ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas        }
8095ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas        default:
8105ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas            return false;
8115ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas    }
8125ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas}
8135ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas
8145ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas// Returns a block containing all of the statements that will be run if the given case matches
8155ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas// (which, owing to the statements being owned by unique_ptrs, means the switch itself will be
8165ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas// broken by this call and must then be discarded).
8175ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas// Returns null (and leaves the switch unmodified) if no such simple reduction is possible, such as
8185ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas// when break statements appear inside conditionals.
8195ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholasstatic std::unique_ptr<Statement> block_for_case(SwitchStatement* s, SwitchCase* c) {
8205ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas    bool capturing = false;
8215ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas    std::vector<std::unique_ptr<Statement>*> statementPtrs;
8225ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas    for (const auto& current : s->fCases) {
8235ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas        if (current.get() == c) {
8245ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas            capturing = true;
8255ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas        }
8265ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas        if (capturing) {
8275ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas            for (auto& stmt : current->fStatements) {
8285ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                if (stmt->fKind == Statement::kBreak_Kind) {
8295ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                    capturing = false;
8305ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                    break;
8315ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                }
8325ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                if (contains_break(*stmt)) {
8335ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                    return nullptr;
8345ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                }
8355ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                statementPtrs.push_back(&stmt);
8365ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas            }
8375ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas            if (!capturing) {
8385ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                break;
8395ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas            }
8405ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas        }
8415ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas    }
8425ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas    std::vector<std::unique_ptr<Statement>> statements;
8435ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas    for (const auto& s : statementPtrs) {
8445ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas        statements.push_back(std::move(*s));
8455ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas    }
846c432b0ca8a5022d86f0ccf2efd1064ed9fce2e53Ethan Nicholas    return std::unique_ptr<Statement>(new Block(Position(), std::move(statements), s->fSymbols));
8475ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas}
8485ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas
849cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholasvoid Compiler::simplifyStatement(DefinitionMap& definitions,
8505ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                                 BasicBlock& b,
8515ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                                 std::vector<BasicBlock::Node>::iterator* iter,
8525ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                                 std::unordered_set<const Variable*>* undefinedVariables,
8535ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                                 bool* outUpdated,
8545ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                                 bool* outNeedsRescan) {
855cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    Statement* stmt = (*iter)->statement()->get();
856cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    switch (stmt->fKind) {
857b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas        case Statement::kVarDeclaration_Kind: {
858b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas            const auto& varDecl = (VarDeclaration&) *stmt;
859b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas            if (varDecl.fVar->dead() &&
860b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas                (!varDecl.fValue ||
861b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas                 !varDecl.fValue->hasSideEffects())) {
862b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas                if (varDecl.fValue) {
863b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas                    ASSERT((*iter)->statement()->get() == stmt);
864b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas                    if (!b.tryRemoveExpressionBefore(iter, varDecl.fValue.get())) {
865b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas                        *outNeedsRescan = true;
866cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    }
867cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                }
868cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                (*iter)->setStatement(std::unique_ptr<Statement>(new Nop()));
869b4dc419f0bc3140cb4e0f5a2fe4db46c4306df86Ethan Nicholas                *outUpdated = true;
870cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            }
871cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            break;
872cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        }
873cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        case Statement::kIf_Kind: {
874cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            IfStatement& i = (IfStatement&) *stmt;
8755ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas            if (i.fTest->fKind == Expression::kBoolLiteral_Kind) {
8765ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                // constant if, collapse down to a single branch
8775ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                if (((BoolLiteral&) *i.fTest).fValue) {
8785ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                    ASSERT(i.fIfTrue);
8795ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                    (*iter)->setStatement(std::move(i.fIfTrue));
8805ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                } else {
8815ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                    if (i.fIfFalse) {
8825ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                        (*iter)->setStatement(std::move(i.fIfFalse));
8835ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                    } else {
8845ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                        (*iter)->setStatement(std::unique_ptr<Statement>(new Nop()));
8855ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                    }
8865ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                }
8875ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                *outUpdated = true;
8885ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                *outNeedsRescan = true;
8895ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                break;
8905ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas            }
891cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            if (i.fIfFalse && i.fIfFalse->isEmpty()) {
892cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                // else block doesn't do anything, remove it
893cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                i.fIfFalse.reset();
894cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                *outUpdated = true;
895cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                *outNeedsRescan = true;
896cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            }
897cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            if (!i.fIfFalse && i.fIfTrue->isEmpty()) {
898cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                // if block doesn't do anything, no else block
899cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                if (i.fTest->hasSideEffects()) {
900cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    // test has side effects, keep it
901cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    (*iter)->setStatement(std::unique_ptr<Statement>(
902cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                                                      new ExpressionStatement(std::move(i.fTest))));
903cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                } else {
904cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    // no if, no else, no test side effects, kill the whole if
905cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    // statement
906cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    (*iter)->setStatement(std::unique_ptr<Statement>(new Nop()));
907cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                }
908cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                *outUpdated = true;
909cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                *outNeedsRescan = true;
910cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            }
911cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            break;
912cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        }
9135ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas        case Statement::kSwitch_Kind: {
9145ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas            SwitchStatement& s = (SwitchStatement&) *stmt;
9155ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas            if (s.fValue->isConstant()) {
9165ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                // switch is constant, replace it with the case that matches
9175ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                bool found = false;
9185ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                SwitchCase* defaultCase = nullptr;
9195ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                for (const auto& c : s.fCases) {
9205ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                    if (!c->fValue) {
9215ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                        defaultCase = c.get();
9225ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                        continue;
9235ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                    }
9245ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                    ASSERT(c->fValue->fKind == s.fValue->fKind);
9255ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                    found = c->fValue->compareConstant(fContext, *s.fValue);
9265ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                    if (found) {
9275ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                        std::unique_ptr<Statement> newBlock = block_for_case(&s, c.get());
9285ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                        if (newBlock) {
9295ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                            (*iter)->setStatement(std::move(newBlock));
9305ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                            break;
9315ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                        } else {
9326e1cbc012b10e99d9caed19eef43939778d1d8ffEthan Nicholas                            if (s.fIsStatic && !(fFlags & kPermitInvalidStaticTests_Flag)) {
9335ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                                this->error(s.fPosition,
9345ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                                            "static switch contains non-static conditional break");
9355ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                                s.fIsStatic = false;
9365ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                            }
9375ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                            return; // can't simplify
9385ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                        }
9395ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                    }
9405ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                }
9415ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                if (!found) {
9425ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                    // no matching case. use default if it exists, or kill the whole thing
9435ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                    if (defaultCase) {
9445ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                        std::unique_ptr<Statement> newBlock = block_for_case(&s, defaultCase);
9455ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                        if (newBlock) {
9465ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                            (*iter)->setStatement(std::move(newBlock));
9475ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                        } else {
9486e1cbc012b10e99d9caed19eef43939778d1d8ffEthan Nicholas                            if (s.fIsStatic && !(fFlags & kPermitInvalidStaticTests_Flag)) {
9495ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                                this->error(s.fPosition,
9505ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                                            "static switch contains non-static conditional break");
9515ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                                s.fIsStatic = false;
9525ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                            }
9535ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                            return; // can't simplify
9545ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                        }
9555ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                    } else {
9565ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                        (*iter)->setStatement(std::unique_ptr<Statement>(new Nop()));
9575ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                    }
9585ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                }
9595ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                *outUpdated = true;
9605ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                *outNeedsRescan = true;
9615ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas            }
9625ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas            break;
9635ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas        }
964cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        case Statement::kExpression_Kind: {
965cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            ExpressionStatement& e = (ExpressionStatement&) *stmt;
966cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            ASSERT((*iter)->statement()->get() == &e);
967cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            if (!e.fExpression->hasSideEffects()) {
968cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                // Expression statement with no side effects, kill it
969cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                if (!b.tryRemoveExpressionBefore(iter, e.fExpression.get())) {
970cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    *outNeedsRescan = true;
971cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                }
972cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                ASSERT((*iter)->statement()->get() == stmt);
973cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                (*iter)->setStatement(std::unique_ptr<Statement>(new Nop()));
974cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                *outUpdated = true;
975cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            }
976cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            break;
977cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        }
978cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        default:
979cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            break;
980cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    }
981cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas}
982cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas
983cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholasvoid Compiler::scanCFG(FunctionDefinition& f) {
984cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    CFG cfg = CFGGenerator().getCFG(f);
985cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    this->computeDataFlow(&cfg);
98622f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas
98722f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas    // check for unreachable code
98822f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas    for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
9896ad9909fb7ccc973f35bbd222b0f424b8c3df0d2Mike Klein        if (i != cfg.fStart && !cfg.fBlocks[i].fEntrances.size() &&
99022f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas            cfg.fBlocks[i].fNodes.size()) {
99186a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas            Position p;
99286a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas            switch (cfg.fBlocks[i].fNodes[0].fKind) {
99386a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                case BasicBlock::Node::kStatement_Kind:
994cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    p = (*cfg.fBlocks[i].fNodes[0].statement())->fPosition;
99586a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                    break;
99686a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                case BasicBlock::Node::kExpression_Kind:
997cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    p = (*cfg.fBlocks[i].fNodes[0].expression())->fPosition;
99886a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas                    break;
99986a43405fb3f83f6d45581959df5f7321487ae7eEthan Nicholas            }
10000df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholas            this->error(p, String("unreachable"));
100122f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas        }
100222f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas    }
100322f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas    if (fErrorCount) {
100422f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas        return;
100522f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas    }
100622f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas
1007cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    // check for dead code & undefined variables, perform constant propagation
1008cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    std::unordered_set<const Variable*> undefinedVariables;
1009cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    bool updated;
1010cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    bool needsRescan = false;
1011cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    do {
1012cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        if (needsRescan) {
1013cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            cfg = CFGGenerator().getCFG(f);
1014cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            this->computeDataFlow(&cfg);
1015cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            needsRescan = false;
1016cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        }
1017cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas
1018cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        updated = false;
1019cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas        for (BasicBlock& b : cfg.fBlocks) {
1020cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            DefinitionMap definitions = b.fBefore;
1021cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas
1022cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas            for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() && !needsRescan; ++iter) {
1023cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                if (iter->fKind == BasicBlock::Node::kExpression_Kind) {
1024cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    this->simplifyExpression(definitions, b, &iter, &undefinedVariables, &updated,
1025cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                                             &needsRescan);
1026cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                } else {
1027cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                    this->simplifyStatement(definitions, b, &iter, &undefinedVariables, &updated,
1028cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                                             &needsRescan);
102922f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas                }
10304b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas                if (needsRescan) {
10314b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas                    break;
10324b330dfd3334bf24bf93043acfcd31590a3cdbbfEthan Nicholas                }
1033cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas                this->addDefinitions(*iter, &definitions);
103422f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas            }
103522f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas        }
1036cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    } while (updated);
1037cb67096b61f699b047fe8635984db1ac708a7b99Ethan Nicholas    ASSERT(!needsRescan);
103822f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas
103991a1053f2d4f7be31d7f3a14f718d0e457e49710Ethan Nicholas    // verify static ifs & switches, clean up dead variable decls
10405ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas    for (BasicBlock& b : cfg.fBlocks) {
10415ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas        DefinitionMap definitions = b.fBefore;
10425ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas
104391a1053f2d4f7be31d7f3a14f718d0e457e49710Ethan Nicholas        for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() && !needsRescan;) {
10445ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas            if (iter->fKind == BasicBlock::Node::kStatement_Kind) {
10455ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                const Statement& s = **iter->statement();
10465ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                switch (s.fKind) {
10475ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                    case Statement::kIf_Kind:
10486e1cbc012b10e99d9caed19eef43939778d1d8ffEthan Nicholas                        if (((const IfStatement&) s).fIsStatic &&
10496e1cbc012b10e99d9caed19eef43939778d1d8ffEthan Nicholas                            !(fFlags & kPermitInvalidStaticTests_Flag)) {
10505ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                            this->error(s.fPosition, "static if has non-static test");
10515ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                        }
105291a1053f2d4f7be31d7f3a14f718d0e457e49710Ethan Nicholas                        ++iter;
10535ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                        break;
10545ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                    case Statement::kSwitch_Kind:
10556e1cbc012b10e99d9caed19eef43939778d1d8ffEthan Nicholas                        if (((const SwitchStatement&) s).fIsStatic &&
10566e1cbc012b10e99d9caed19eef43939778d1d8ffEthan Nicholas                             !(fFlags & kPermitInvalidStaticTests_Flag)) {
10575ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                            this->error(s.fPosition, "static switch has non-static test");
10585ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                        }
105991a1053f2d4f7be31d7f3a14f718d0e457e49710Ethan Nicholas                        ++iter;
106091a1053f2d4f7be31d7f3a14f718d0e457e49710Ethan Nicholas                        break;
106191a1053f2d4f7be31d7f3a14f718d0e457e49710Ethan Nicholas                    case Statement::kVarDeclarations_Kind: {
106291a1053f2d4f7be31d7f3a14f718d0e457e49710Ethan Nicholas                        VarDeclarations& decls = *((VarDeclarationsStatement&) s).fDeclaration;
106391a1053f2d4f7be31d7f3a14f718d0e457e49710Ethan Nicholas                        for (auto varIter = decls.fVars.begin(); varIter != decls.fVars.end();) {
106491a1053f2d4f7be31d7f3a14f718d0e457e49710Ethan Nicholas                            if ((*varIter)->fKind == Statement::kNop_Kind) {
106591a1053f2d4f7be31d7f3a14f718d0e457e49710Ethan Nicholas                                varIter = decls.fVars.erase(varIter);
106691a1053f2d4f7be31d7f3a14f718d0e457e49710Ethan Nicholas                            } else {
106791a1053f2d4f7be31d7f3a14f718d0e457e49710Ethan Nicholas                                ++varIter;
106891a1053f2d4f7be31d7f3a14f718d0e457e49710Ethan Nicholas                            }
106991a1053f2d4f7be31d7f3a14f718d0e457e49710Ethan Nicholas                        }
107091a1053f2d4f7be31d7f3a14f718d0e457e49710Ethan Nicholas                        if (!decls.fVars.size()) {
107191a1053f2d4f7be31d7f3a14f718d0e457e49710Ethan Nicholas                            iter = b.fNodes.erase(iter);
107291a1053f2d4f7be31d7f3a14f718d0e457e49710Ethan Nicholas                        } else {
107391a1053f2d4f7be31d7f3a14f718d0e457e49710Ethan Nicholas                            ++iter;
107491a1053f2d4f7be31d7f3a14f718d0e457e49710Ethan Nicholas                        }
10755ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                        break;
107691a1053f2d4f7be31d7f3a14f718d0e457e49710Ethan Nicholas                    }
10775ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                    default:
107891a1053f2d4f7be31d7f3a14f718d0e457e49710Ethan Nicholas                        ++iter;
10795ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                        break;
10805ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas                }
108191a1053f2d4f7be31d7f3a14f718d0e457e49710Ethan Nicholas            } else {
108291a1053f2d4f7be31d7f3a14f718d0e457e49710Ethan Nicholas                ++iter;
10835ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas            }
10845ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas        }
10855ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas    }
10865ac13c23628c6ee8c3f6056f38527706b403e502Ethan Nicholas
108722f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas    // check for missing return
108822f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas    if (f.fDeclaration.fReturnType != *fContext.fVoid_Type) {
108922f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas        if (cfg.fBlocks[cfg.fExit].fEntrances.size()) {
10900df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholas            this->error(f.fPosition, String("function can exit without returning a value"));
109122f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas        }
109222f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas    }
109322f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas}
109422f939e849013b7fc51374c289b5bf37e63dfdb1ethannicholas
10950df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholasstd::unique_ptr<Program> Compiler::convertProgram(Program::Kind kind, String text,
1096941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                                                  const Program::Settings& settings) {
1097b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    fErrorText = "";
1098b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    fErrorCount = 0;
1099941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    fIRGenerator->start(&settings);
1100d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    std::vector<std::unique_ptr<ProgramElement>> elements;
11015961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    Modifiers::Flag ignored;
1102b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    switch (kind) {
1103b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Program::kVertex_Kind:
11047da6dfabc44891c51dedcb4754477b662d8c8a0aEthan Nicholas            fIRGenerator->convertProgram(String(SKSL_VERT_INCLUDE), *fTypes, &ignored, &elements);
1105b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            break;
1106b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas        case Program::kFragment_Kind:
11077da6dfabc44891c51dedcb4754477b662d8c8a0aEthan Nicholas            fIRGenerator->convertProgram(String(SKSL_FRAG_INCLUDE), *fTypes, &ignored, &elements);
1108b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas            break;
110952cad15d0b4443b763a7d41ec8d1131a7638f866Ethan Nicholas        case Program::kGeometry_Kind:
11107da6dfabc44891c51dedcb4754477b662d8c8a0aEthan Nicholas            fIRGenerator->convertProgram(String(SKSL_GEOM_INCLUDE), *fTypes, &ignored, &elements);
111152cad15d0b4443b763a7d41ec8d1131a7638f866Ethan Nicholas            break;
1112762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas        case Program::kFragmentProcessor_Kind:
1113762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas            fIRGenerator->convertProgram(String(SKSL_FP_INCLUDE), *fTypes, &ignored, &elements);
1114762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas            break;
1115b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1116ddb37d67ba4db42fa5c6012b58d0f4985b454dc0ethannicholas    fIRGenerator->fSymbolTable->markAllFunctionsBuiltin();
11175961bc9278a00e56dacdd9408d0744b5a0a3b493ethannicholas    Modifiers::Flag defaultPrecision;
11187da6dfabc44891c51dedcb4754477b662d8c8a0aEthan Nicholas    fIRGenerator->convertProgram(text, *fTypes, &defaultPrecision, &elements);
11197da6dfabc44891c51dedcb4754477b662d8c8a0aEthan Nicholas    if (!fErrorCount) {
11207da6dfabc44891c51dedcb4754477b662d8c8a0aEthan Nicholas        for (auto& element : elements) {
11217da6dfabc44891c51dedcb4754477b662d8c8a0aEthan Nicholas            if (element->fKind == ProgramElement::kFunction_Kind) {
11227da6dfabc44891c51dedcb4754477b662d8c8a0aEthan Nicholas                this->scanCFG((FunctionDefinition&) *element);
11237da6dfabc44891c51dedcb4754477b662d8c8a0aEthan Nicholas            }
11247da6dfabc44891c51dedcb4754477b662d8c8a0aEthan Nicholas        }
11257da6dfabc44891c51dedcb4754477b662d8c8a0aEthan Nicholas    }
1126941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    auto result = std::unique_ptr<Program>(new Program(kind, settings, defaultPrecision, &fContext,
1127941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                                                       std::move(elements),
1128941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                                                       fIRGenerator->fSymbolTable,
1129941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas                                                       fIRGenerator->fInputs));
11303605ace7ddaf0b576bf6df1c7a550ab4f44d22a8Ethan Nicholas    fIRGenerator->finish();
1131b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    this->writeErrorCount();
1132941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    if (fErrorCount) {
1133941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        return nullptr;
1134941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    }
1135d598f7981f34811e6f2a949207dc13638852f3f7ethannicholas    return result;
1136b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1137b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
11380df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholasbool Compiler::toSPIRV(const Program& program, OutputStream& out) {
1139a6ae1f7cda072ff814a838e2d9013a017552cc35Ethan Nicholas#ifdef SK_ENABLE_SPIRV_VALIDATION
11400df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholas    StringStream buffer;
1141a6ae1f7cda072ff814a838e2d9013a017552cc35Ethan Nicholas    SPIRVCodeGenerator cg(&fContext, &program, this, &buffer);
1142a6ae1f7cda072ff814a838e2d9013a017552cc35Ethan Nicholas    bool result = cg.generateCode();
1143a6ae1f7cda072ff814a838e2d9013a017552cc35Ethan Nicholas    if (result) {
1144a6ae1f7cda072ff814a838e2d9013a017552cc35Ethan Nicholas        spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
1145762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas        const String& data = buffer.str();
1146762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas        ASSERT(0 == data.size() % 4);
1147a6ae1f7cda072ff814a838e2d9013a017552cc35Ethan Nicholas        auto dumpmsg = [](spv_message_level_t, const char*, const spv_position_t&, const char* m) {
1148a6ae1f7cda072ff814a838e2d9013a017552cc35Ethan Nicholas            SkDebugf("SPIR-V validation error: %s\n", m);
1149a6ae1f7cda072ff814a838e2d9013a017552cc35Ethan Nicholas        };
1150a6ae1f7cda072ff814a838e2d9013a017552cc35Ethan Nicholas        tools.SetMessageConsumer(dumpmsg);
1151a6ae1f7cda072ff814a838e2d9013a017552cc35Ethan Nicholas        // Verify that the SPIR-V we produced is valid. If this assert fails, check the logs prior
1152a6ae1f7cda072ff814a838e2d9013a017552cc35Ethan Nicholas        // to the failure to see the validation errors.
1153762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas        ASSERT_RESULT(tools.Validate((const uint32_t*) data.c_str(), data.size() / 4));
1154762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas        out.write(data.c_str(), data.size());
1155a6ae1f7cda072ff814a838e2d9013a017552cc35Ethan Nicholas    }
1156a6ae1f7cda072ff814a838e2d9013a017552cc35Ethan Nicholas#else
1157941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    SPIRVCodeGenerator cg(&fContext, &program, this, &out);
1158941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    bool result = cg.generateCode();
1159a6ae1f7cda072ff814a838e2d9013a017552cc35Ethan Nicholas#endif
1160941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    this->writeErrorCount();
1161b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    return result;
1162b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1163b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
11640df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholasbool Compiler::toSPIRV(const Program& program, String* out) {
11650df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholas    StringStream buffer;
1166941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    bool result = this->toSPIRV(program, buffer);
1167941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    if (result) {
1168762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas        *out = buffer.str();
1169b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1170941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    return result;
1171b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1172b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
11730df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholasbool Compiler::toGLSL(const Program& program, OutputStream& out) {
1174941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    GLSLCodeGenerator cg(&fContext, &program, this, &out);
1175941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    bool result = cg.generateCode();
1176941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    this->writeErrorCount();
1177941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    return result;
1178b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1179b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
11800df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholasbool Compiler::toGLSL(const Program& program, String* out) {
11810df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholas    StringStream buffer;
1182941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    bool result = this->toGLSL(program, buffer);
1183b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    if (result) {
1184762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas        *out = buffer.str();
1185b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas    }
1186f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    return result;
1187f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
1188f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
1189762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholasbool Compiler::toCPP(const Program& program, String name, OutputStream& out) {
1190762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    CPPCodeGenerator cg(&fContext, &program, this, name, &out);
1191762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    bool result = cg.generateCode();
1192762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    this->writeErrorCount();
1193762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    return result;
1194762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas}
1195762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas
1196762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholasbool Compiler::toH(const Program& program, String name, OutputStream& out) {
1197762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    HCodeGenerator cg(&program, this, name, &out);
1198762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    bool result = cg.generateCode();
1199762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    this->writeErrorCount();
1200762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas    return result;
1201762466e9fe0478bcf11fba532998e81e33b3069eEthan Nicholas}
1202941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas
12030df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholasvoid Compiler::error(Position position, String msg) {
1204941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    fErrorCount++;
1205941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    fErrorText += "error: " + position.description() + ": " + msg.c_str() + "\n";
12063605ace7ddaf0b576bf6df1c7a550ab4f44d22a8Ethan Nicholas}
12073605ace7ddaf0b576bf6df1c7a550ab4f44d22a8Ethan Nicholas
12080df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan NicholasString Compiler::errorText() {
12090df1b04db87c3d86ee0b0bd6aa2cb5b6be32cac2Ethan Nicholas    String result = fErrorText;
1210941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    return result;
1211b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas}
1212b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas
1213941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholasvoid Compiler::writeErrorCount() {
1214941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas    if (fErrorCount) {
1215941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        fErrorText += to_string(fErrorCount) + " error";
1216941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        if (fErrorCount > 1) {
1217941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas            fErrorText += "s";
1218941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        }
1219941e7e2c9567ab1d8a3b2d1b0e3db71ee5eb75c9Ethan Nicholas        fErrorText += "\n";
1220f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas    }
1221f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas}
1222f789b3893579b773bb4d7be6c2c65311500b53bbethannicholas
1223b3058bdb1049ca75d526eb9f11e1a42a49e63585ethannicholas} // namespace
1224