1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2016 Google Inc.
3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be
5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file.
6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkSLCFGGenerator.h"
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "ir/SkSLConstructor.h"
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "ir/SkSLBinaryExpression.h"
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "ir/SkSLDoStatement.h"
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "ir/SkSLExpressionStatement.h"
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "ir/SkSLFieldAccess.h"
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "ir/SkSLForStatement.h"
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "ir/SkSLFunctionCall.h"
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "ir/SkSLIfStatement.h"
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "ir/SkSLIndexExpression.h"
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "ir/SkSLPostfixExpression.h"
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "ir/SkSLPrefixExpression.h"
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "ir/SkSLReturnStatement.h"
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "ir/SkSLSwizzle.h"
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "ir/SkSLSwitchStatement.h"
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "ir/SkSLTernaryExpression.h"
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "ir/SkSLVarDeclarationsStatement.h"
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "ir/SkSLWhileStatement.h"
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotnamespace SkSL {
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotBlockId CFG::newBlock() {
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    BlockId result = fBlocks.size();
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fBlocks.emplace_back();
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fBlocks.size() > 1) {
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->addExit(fCurrent, result);
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fCurrent = result;
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return result;
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotBlockId CFG::newIsolatedBlock() {
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    BlockId result = fBlocks.size();
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fBlocks.emplace_back();
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return result;
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid CFG::addExit(BlockId from, BlockId to) {
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (from == 0 || fBlocks[from].fEntrances.size()) {
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fBlocks[from].fExits.insert(to);
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fBlocks[to].fEntrances.insert(from);
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid CFG::dump() {
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (size_t i = 0; i < fBlocks.size(); i++) {
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        printf("Block %d\n-------\nBefore: ", (int) i);
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const char* separator = "";
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (auto iter = fBlocks[i].fBefore.begin(); iter != fBlocks[i].fBefore.end(); iter++) {
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            printf("%s%s = %s", separator, iter->first->description().c_str(),
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                   iter->second ? (*iter->second)->description().c_str() : "<undefined>");
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            separator = ", ";
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        printf("\nEntrances: ");
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        separator = "";
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (BlockId b : fBlocks[i].fEntrances) {
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            printf("%s%d", separator, (int) b);
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            separator = ", ";
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        printf("\n");
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (size_t j = 0; j < fBlocks[i].fNodes.size(); j++) {
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            BasicBlock::Node& n = fBlocks[i].fNodes[j];
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            printf("Node %d (%p): %s\n", (int) j, &n, n.fKind == BasicBlock::Node::kExpression_Kind
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                         ? (*n.expression())->description().c_str()
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                         : (*n.statement())->description().c_str());
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        printf("Exits: ");
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        separator = "";
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (BlockId b : fBlocks[i].fExits) {
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            printf("%s%d", separator, (int) b);
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            separator = ", ";
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        printf("\n\n");
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool BasicBlock::tryRemoveExpressionBefore(std::vector<BasicBlock::Node>::iterator* iter,
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                           Expression* e) {
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (e->fKind == Expression::kTernary_Kind) {
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return false;
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool result;
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if ((*iter)->fKind == BasicBlock::Node::kExpression_Kind) {
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ASSERT((*iter)->expression()->get() != e);
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        Expression* old = (*iter)->expression()->get();
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        do {
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if ((*iter) == fNodes.begin()) {
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return false;
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            --(*iter);
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } while ((*iter)->fKind != BasicBlock::Node::kExpression_Kind ||
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                 (*iter)->expression()->get() != e);
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        result = this->tryRemoveExpression(iter);
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        while ((*iter)->fKind != BasicBlock::Node::kExpression_Kind ||
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot               (*iter)->expression()->get() != old) {
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ASSERT(*iter != fNodes.end());
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ++(*iter);
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        Statement* old = (*iter)->statement()->get();
109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        do {
110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if ((*iter) == fNodes.begin()) {
111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return false;
112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            --(*iter);
114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } while ((*iter)->fKind != BasicBlock::Node::kExpression_Kind ||
115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                 (*iter)->expression()->get() != e);
116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        result = this->tryRemoveExpression(iter);
117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        while ((*iter)->fKind != BasicBlock::Node::kStatement_Kind ||
118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot               (*iter)->statement()->get() != old) {
119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ASSERT(*iter != fNodes.end());
120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ++(*iter);
121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return result;
124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool BasicBlock::tryRemoveLValueBefore(std::vector<BasicBlock::Node>::iterator* iter,
127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                       Expression* lvalue) {
128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    switch (lvalue->fKind) {
129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kVariableReference_Kind:
130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return true;
131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kSwizzle_Kind:
132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return this->tryRemoveLValueBefore(iter, ((Swizzle*) lvalue)->fBase.get());
133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kFieldAccess_Kind:
134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return this->tryRemoveLValueBefore(iter, ((FieldAccess*) lvalue)->fBase.get());
135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kIndex_Kind:
136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!this->tryRemoveLValueBefore(iter, ((IndexExpression*) lvalue)->fBase.get())) {
137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return false;
138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return this->tryRemoveExpressionBefore(iter, ((IndexExpression*) lvalue)->fIndex.get());
140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kTernary_Kind:
141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!this->tryRemoveExpressionBefore(iter,
142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                 ((TernaryExpression*) lvalue)->fTest.get())) {
143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return false;
144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!this->tryRemoveLValueBefore(iter, ((TernaryExpression*) lvalue)->fIfTrue.get())) {
146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return false;
147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return this->tryRemoveLValueBefore(iter, ((TernaryExpression*) lvalue)->fIfFalse.get());
149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        default:
150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ABORT("invalid lvalue: %s\n", lvalue->description().c_str());
151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool BasicBlock::tryRemoveExpression(std::vector<BasicBlock::Node>::iterator* iter) {
155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    Expression* expr = (*iter)->expression()->get();
156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    switch (expr->fKind) {
157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kBinary_Kind: {
158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            BinaryExpression* b = (BinaryExpression*) expr;
159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (b->fOperator == Token::EQ) {
160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (!this->tryRemoveLValueBefore(iter, b->fLeft.get())) {
161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    return false;
162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } else if (!this->tryRemoveExpressionBefore(iter, b->fLeft.get())) {
164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return false;
165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!this->tryRemoveExpressionBefore(iter, b->fRight.get())) {
167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return false;
168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ASSERT((*iter)->expression()->get() == expr);
170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            *iter = fNodes.erase(*iter);
171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return true;
172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kTernary_Kind: {
174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // ternaries cross basic block boundaries, must regenerate the CFG to remove it
175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return false;
176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kFieldAccess_Kind: {
178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            FieldAccess* f = (FieldAccess*) expr;
179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!this->tryRemoveExpressionBefore(iter, f->fBase.get())) {
180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return false;
181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            *iter = fNodes.erase(*iter);
183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return true;
184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kSwizzle_Kind: {
186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            Swizzle* s = (Swizzle*) expr;
187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!this->tryRemoveExpressionBefore(iter, s->fBase.get())) {
188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return false;
189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            *iter = fNodes.erase(*iter);
191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return true;
192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kIndex_Kind: {
194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            IndexExpression* idx = (IndexExpression*) expr;
195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!this->tryRemoveExpressionBefore(iter, idx->fBase.get())) {
196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return false;
197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
198fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!this->tryRemoveExpressionBefore(iter, idx->fIndex.get())) {
199fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return false;
200fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
201fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            *iter = fNodes.erase(*iter);
202fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return true;
203fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
204fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kConstructor_Kind: {
205fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            Constructor* c = (Constructor*) expr;
206fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (auto& arg : c->fArguments) {
207fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (!this->tryRemoveExpressionBefore(iter, arg.get())) {
208fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    return false;
209fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
210fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                ASSERT((*iter)->expression()->get() == expr);
211fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
212fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            *iter = fNodes.erase(*iter);
213fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return true;
214fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
215fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kFunctionCall_Kind: {
216fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            FunctionCall* f = (FunctionCall*) expr;
217fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (auto& arg : f->fArguments) {
218fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (!this->tryRemoveExpressionBefore(iter, arg.get())) {
219fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    return false;
220fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
221fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                ASSERT((*iter)->expression()->get() == expr);
222fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
223fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            *iter = fNodes.erase(*iter);
224fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return true;
225fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
226fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kPrefix_Kind:
227fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!this->tryRemoveExpressionBefore(iter,
228fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                 ((PrefixExpression*) expr)->fOperand.get())) {
229fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return false;
230fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
231fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            *iter = fNodes.erase(*iter);
232fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return true;
233fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kPostfix_Kind:
234fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!this->tryRemoveExpressionBefore(iter,
235fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                 ((PrefixExpression*) expr)->fOperand.get())) {
236fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return false;
237fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
238fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            *iter = fNodes.erase(*iter);
239fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return true;
240fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kBoolLiteral_Kind:  // fall through
241fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kFloatLiteral_Kind: // fall through
242fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kIntLiteral_Kind:   // fall through
243fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kSetting_Kind:      // fall through
244fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kVariableReference_Kind:
245fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            *iter = fNodes.erase(*iter);
246fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return true;
247fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        default:
248fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ABORT("unhandled expression: %s\n", expr->description().c_str());
249fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
250fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
251fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
252fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool BasicBlock::tryInsertExpression(std::vector<BasicBlock::Node>::iterator* iter,
253fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                     std::unique_ptr<Expression>* expr) {
254fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    switch ((*expr)->fKind) {
255fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kBinary_Kind: {
256fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            BinaryExpression* b = (BinaryExpression*) expr->get();
257fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!this->tryInsertExpression(iter, &b->fRight)) {
258fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return false;
259fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
260fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ++(*iter);
261fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!this->tryInsertExpression(iter, &b->fLeft)) {
262fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return false;
263fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
264fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ++(*iter);
265fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            BasicBlock::Node node = { BasicBlock::Node::kExpression_Kind, true, expr, nullptr };
266fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            *iter = fNodes.insert(*iter, node);
267fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return true;
268fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
269fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kBoolLiteral_Kind:  // fall through
270fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kFloatLiteral_Kind: // fall through
271fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kIntLiteral_Kind:   // fall through
272fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kVariableReference_Kind: {
273fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            BasicBlock::Node node = { BasicBlock::Node::kExpression_Kind, true, expr, nullptr };
274fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            *iter = fNodes.insert(*iter, node);
275fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return true;
276fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
277fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kConstructor_Kind: {
278fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            Constructor* c = (Constructor*) expr->get();
279fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (auto& arg : c->fArguments) {
280fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (!this->tryInsertExpression(iter, &arg)) {
281fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    return false;
282fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
283fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                ++(*iter);
284fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
285fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            BasicBlock::Node node = { BasicBlock::Node::kExpression_Kind, true, expr, nullptr };
286fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            *iter = fNodes.insert(*iter, node);
287fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return true;
288fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
289fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        default:
290fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return false;
291fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
292fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
293fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
294fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid CFGGenerator::addExpression(CFG& cfg, std::unique_ptr<Expression>* e, bool constantPropagate) {
295fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ASSERT(e);
296fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    switch ((*e)->fKind) {
297fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kBinary_Kind: {
298fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            BinaryExpression* b = (BinaryExpression*) e->get();
299fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            switch (b->fOperator) {
300fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                case Token::LOGICALAND: // fall through
301fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                case Token::LOGICALOR: {
302fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    // this isn't as precise as it could be -- we don't bother to track that if we
303fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    // early exit from a logical and/or, we know which branch of an 'if' we're going
304fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    // to hit -- but it won't make much difference in practice.
305fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    this->addExpression(cfg, &b->fLeft, constantPropagate);
306fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    BlockId start = cfg.fCurrent;
307fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    cfg.newBlock();
308fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    this->addExpression(cfg, &b->fRight, constantPropagate);
309fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    cfg.newBlock();
310fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    cfg.addExit(start, cfg.fCurrent);
311fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
312fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        BasicBlock::Node::kExpression_Kind,
313fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        constantPropagate,
314fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        e,
315fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        nullptr
316fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    });
317fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    break;
318fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
319fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                case Token::EQ: {
320fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    this->addExpression(cfg, &b->fRight, constantPropagate);
321fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    this->addLValue(cfg, &b->fLeft);
322fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
323fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        BasicBlock::Node::kExpression_Kind,
324fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        constantPropagate,
325fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        e,
326fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        nullptr
327fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    });
328fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    break;
329fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
330fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                default:
331fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    this->addExpression(cfg, &b->fLeft, !Compiler::IsAssignment(b->fOperator));
332fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    this->addExpression(cfg, &b->fRight, constantPropagate);
333fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
334fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        BasicBlock::Node::kExpression_Kind,
335fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        constantPropagate,
336fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        e,
337fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        nullptr
338fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    });
339fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
340fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
341fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
342fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kConstructor_Kind: {
343fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            Constructor* c = (Constructor*) e->get();
344fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (auto& arg : c->fArguments) {
345fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                this->addExpression(cfg, &arg, constantPropagate);
346fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
347fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
348fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                         constantPropagate, e, nullptr });
349fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
350fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
351fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kFunctionCall_Kind: {
352fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            FunctionCall* c = (FunctionCall*) e->get();
353fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (auto& arg : c->fArguments) {
354fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                this->addExpression(cfg, &arg, constantPropagate);
355fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
356fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
357fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                         constantPropagate, e, nullptr });
358fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
359fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
360fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kFieldAccess_Kind:
361fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->addExpression(cfg, &((FieldAccess*) e->get())->fBase, constantPropagate);
362fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
363fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                         constantPropagate, e, nullptr });
364fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
365fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kIndex_Kind:
366fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->addExpression(cfg, &((IndexExpression*) e->get())->fBase, constantPropagate);
367fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->addExpression(cfg, &((IndexExpression*) e->get())->fIndex, constantPropagate);
368fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
369fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                         constantPropagate, e, nullptr });
370fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
371fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kPrefix_Kind: {
372fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            PrefixExpression* p = (PrefixExpression*) e->get();
373fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->addExpression(cfg, &p->fOperand, constantPropagate &&
374fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                   p->fOperator != Token::PLUSPLUS &&
375fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                   p->fOperator != Token::MINUSMINUS);
376fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
377fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                         constantPropagate, e, nullptr });
378fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
379fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
380fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kPostfix_Kind:
381fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->addExpression(cfg, &((PostfixExpression*) e->get())->fOperand, false);
382fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
383fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                         constantPropagate, e, nullptr });
384fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
385fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kSwizzle_Kind:
386fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->addExpression(cfg, &((Swizzle*) e->get())->fBase, constantPropagate);
387fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
388fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                         constantPropagate, e, nullptr });
389fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
390fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kBoolLiteral_Kind:  // fall through
391fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kFloatLiteral_Kind: // fall through
392fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kIntLiteral_Kind:   // fall through
393fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kSetting_Kind:      // fall through
394fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kVariableReference_Kind:
395fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
396fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                         constantPropagate, e, nullptr });
397fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
398fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kTernary_Kind: {
399fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            TernaryExpression* t = (TernaryExpression*) e->get();
400fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->addExpression(cfg, &t->fTest, constantPropagate);
401fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
402fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                         constantPropagate, e, nullptr });
403fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            BlockId start = cfg.fCurrent;
404fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.newBlock();
405fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->addExpression(cfg, &t->fIfTrue, constantPropagate);
406fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            BlockId next = cfg.newBlock();
407fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fCurrent = start;
408fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.newBlock();
409fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->addExpression(cfg, &t->fIfFalse, constantPropagate);
410fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.addExit(cfg.fCurrent, next);
411fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fCurrent = next;
412fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
413fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
414fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kFunctionReference_Kind: // fall through
415fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kTypeReference_Kind:     // fall through
416fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kDefined_Kind:
417fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ASSERT(false);
418fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
419fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
420fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
421fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
422fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// adds expressions that are evaluated as part of resolving an lvalue
423fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid CFGGenerator::addLValue(CFG& cfg, std::unique_ptr<Expression>* e) {
424fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    switch ((*e)->fKind) {
425fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kFieldAccess_Kind:
426fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->addLValue(cfg, &((FieldAccess&) **e).fBase);
427fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
428fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kIndex_Kind:
429fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->addLValue(cfg, &((IndexExpression&) **e).fBase);
430fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->addExpression(cfg, &((IndexExpression&) **e).fIndex, true);
431fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
432fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kSwizzle_Kind:
433fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->addLValue(cfg, &((Swizzle&) **e).fBase);
434fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
435fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kVariableReference_Kind:
436fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
437fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Expression::kTernary_Kind:
438fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->addExpression(cfg, &((TernaryExpression&) **e).fTest, true);
439fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // Technically we will of course only evaluate one or the other, but if the test turns
440fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // out to be constant, the ternary will get collapsed down to just one branch anyway. So
441fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // it should be ok to pretend that we always evaluate both branches here.
442fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->addLValue(cfg, &((TernaryExpression&) **e).fIfTrue);
443fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->addLValue(cfg, &((TernaryExpression&) **e).fIfFalse);
444fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
445fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        default:
446fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // not an lvalue, can't happen
447fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ASSERT(false);
448fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
449fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
450fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
451fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
452fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid CFGGenerator::addStatement(CFG& cfg, std::unique_ptr<Statement>* s) {
453fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    switch ((*s)->fKind) {
454fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Statement::kBlock_Kind:
455fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (auto& child : ((Block&) **s).fStatements) {
456fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                addStatement(cfg, &child);
457fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
458fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
459fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Statement::kIf_Kind: {
460fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            IfStatement& ifs = (IfStatement&) **s;
461fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->addExpression(cfg, &ifs.fTest, true);
462fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
463fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                         nullptr, s });
464fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            BlockId start = cfg.fCurrent;
465fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.newBlock();
466fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->addStatement(cfg, &ifs.fIfTrue);
467fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            BlockId next = cfg.newBlock();
468fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (ifs.fIfFalse) {
469fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                cfg.fCurrent = start;
470fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                cfg.newBlock();
471fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                this->addStatement(cfg, &ifs.fIfFalse);
472fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                cfg.addExit(cfg.fCurrent, next);
473fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                cfg.fCurrent = next;
474fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } else {
475fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                cfg.addExit(start, next);
476fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
477fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
478fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
479fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Statement::kExpression_Kind: {
480fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->addExpression(cfg, &((ExpressionStatement&) **s).fExpression, true);
481fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
482fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                         nullptr, s });
483fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
484fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
485fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Statement::kVarDeclarations_Kind: {
486fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            VarDeclarationsStatement& decls = ((VarDeclarationsStatement&) **s);
487fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (auto& stmt : decls.fDeclaration->fVars) {
488fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (stmt->fKind == Statement::kNop_Kind) {
489fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    continue;
490fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
491fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                VarDeclaration& vd = (VarDeclaration&) *stmt;
492fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (vd.fValue) {
493fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    this->addExpression(cfg, &vd.fValue, true);
494fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
495fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind,
496fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                             false, nullptr, &stmt });
497fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
498fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
499fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                         nullptr, s });
500fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
501fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
502fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Statement::kDiscard_Kind:
503fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
504fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                         nullptr, s });
505fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fCurrent = cfg.newIsolatedBlock();
506fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
507fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Statement::kReturn_Kind: {
508fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ReturnStatement& r = ((ReturnStatement&) **s);
509fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (r.fExpression) {
510fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                this->addExpression(cfg, &r.fExpression, true);
511fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
512fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
513fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                         nullptr, s });
514fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fCurrent = cfg.newIsolatedBlock();
515fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
516fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
517fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Statement::kBreak_Kind:
518fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
519fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                         nullptr, s });
520fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.addExit(cfg.fCurrent, fLoopExits.top());
521fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fCurrent = cfg.newIsolatedBlock();
522fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
523fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Statement::kContinue_Kind:
524fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
525fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                         nullptr, s });
526fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.addExit(cfg.fCurrent, fLoopContinues.top());
527fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fCurrent = cfg.newIsolatedBlock();
528fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
529fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Statement::kWhile_Kind: {
530fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            WhileStatement& w = (WhileStatement&) **s;
531fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            BlockId loopStart = cfg.newBlock();
532fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fLoopContinues.push(loopStart);
533fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            BlockId loopExit = cfg.newIsolatedBlock();
534fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fLoopExits.push(loopExit);
535fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->addExpression(cfg, &w.fTest, true);
536fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            BlockId test = cfg.fCurrent;
537fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.addExit(test, loopExit);
538fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.newBlock();
539fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->addStatement(cfg, &w.fStatement);
540fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.addExit(cfg.fCurrent, loopStart);
541fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fLoopContinues.pop();
542fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fLoopExits.pop();
543fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fCurrent = loopExit;
544fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
545fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
546fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Statement::kDo_Kind: {
547fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            DoStatement& d = (DoStatement&) **s;
548fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            BlockId loopStart = cfg.newBlock();
549fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fLoopContinues.push(loopStart);
550fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            BlockId loopExit = cfg.newIsolatedBlock();
551fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fLoopExits.push(loopExit);
552fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->addStatement(cfg, &d.fStatement);
553fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->addExpression(cfg, &d.fTest, true);
554fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.addExit(cfg.fCurrent, loopExit);
555fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.addExit(cfg.fCurrent, loopStart);
556fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fLoopContinues.pop();
557fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fLoopExits.pop();
558fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fCurrent = loopExit;
559fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
560fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
561fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Statement::kFor_Kind: {
562fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ForStatement& f = (ForStatement&) **s;
563fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (f.fInitializer) {
564fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                this->addStatement(cfg, &f.fInitializer);
565fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
566fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            BlockId loopStart = cfg.newBlock();
567fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            BlockId next = cfg.newIsolatedBlock();
568fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fLoopContinues.push(next);
569fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            BlockId loopExit = cfg.newIsolatedBlock();
570fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fLoopExits.push(loopExit);
571fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (f.fTest) {
572fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                this->addExpression(cfg, &f.fTest, true);
573fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // this isn't quite right; we should have an exit from here to the loop exit, and
574fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // remove the exit from the loop body to the loop exit. Structuring it like this
575fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // forces the optimizer to believe that the loop body is always executed at least
576fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // once. While not strictly correct, this avoids incorrect "variable not assigned"
577fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // errors on variables which are assigned within the loop. The correct solution to
578fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // this is to analyze the loop to see whether or not at least one iteration is
579fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // guaranteed to happen, but for the time being we take the easy way out.
580fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
581fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.newBlock();
582fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->addStatement(cfg, &f.fStatement);
583fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.addExit(cfg.fCurrent, next);
584fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fCurrent = next;
585fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (f.fNext) {
586fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                this->addExpression(cfg, &f.fNext, true);
587fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
588fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.addExit(cfg.fCurrent, loopStart);
589fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.addExit(cfg.fCurrent, loopExit);
590fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fLoopContinues.pop();
591fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fLoopExits.pop();
592fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fCurrent = loopExit;
593fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
594fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
595fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Statement::kSwitch_Kind: {
596fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SwitchStatement& ss = (SwitchStatement&) **s;
597fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->addExpression(cfg, &ss.fValue, true);
598fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
599fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                         nullptr, s });
600fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            BlockId start = cfg.fCurrent;
601fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            BlockId switchExit = cfg.newIsolatedBlock();
602fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fLoopExits.push(switchExit);
603fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (const auto& c : ss.fCases) {
604fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                cfg.newBlock();
605fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                cfg.addExit(start, cfg.fCurrent);
606fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (c->fValue) {
607fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    // technically this should go in the start block, but it doesn't actually matter
608fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    // because it must be constant. Not worth running two loops for.
609fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    this->addExpression(cfg, &c->fValue, true);
610fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
611fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                for (auto& caseStatement : c->fStatements) {
612fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    this->addStatement(cfg, &caseStatement);
613fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
614fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
615fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.addExit(cfg.fCurrent, switchExit);
616fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // note that unlike GLSL, our grammar requires the default case to be last
617fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (0 == ss.fCases.size() || ss.fCases[ss.fCases.size() - 1]->fValue) {
618fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // switch does not have a default clause, mark that it can skip straight to the end
619fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                cfg.addExit(start, switchExit);
620fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
621fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fLoopExits.pop();
622fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cfg.fCurrent = switchExit;
623fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
624fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
625fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case Statement::kNop_Kind:
626fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
627fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        default:
628fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            printf("statement: %s\n", (*s)->description().c_str());
629fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ABORT("unsupported statement kind");
630fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
631fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
632fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
633fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotCFG CFGGenerator::getCFG(FunctionDefinition& f) {
634fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    CFG result;
635fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    result.fStart = result.newBlock();
636fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    result.fCurrent = result.fStart;
637fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->addStatement(result, &f.fBody);
638fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    result.newBlock();
639fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    result.fExit = result.fCurrent;
640fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return result;
641fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
642fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
643fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} // namespace
644