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