Commit 90a7f074 authored by titzer@chromium.org's avatar titzer@chromium.org

Implement loop variable assignment analysis.

This analysis computes the set of variables that are assigned in each loop. This is useful to avoid creating redundant loop phis when building an SSA graph, which just waste memory and require analysis to get rid of.

This CL implements an AST walk for the analysis and plugs the result into the TurboFan graph builder. I left this analysis under a flag for A/B testing and until sufficient unit tests can be developed.

R=danno@chromium.org, mstarzinger@chromium.org
BUG=

Review URL: https://codereview.chromium.org/656123005

Cr-Commit-Position: refs/heads/master@{#24957}
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24957 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent f900cf2e
......@@ -5,10 +5,11 @@
#include "src/compiler/ast-graph-builder.h"
#include "src/compiler.h"
#include "src/compiler/ast-loop-assignment-analyzer.h"
#include "src/compiler/control-builders.h"
#include "src/compiler/machine-operator.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/node-properties-inl.h"
#include "src/compiler/node-properties.h"
#include "src/full-codegen.h"
#include "src/parser.h"
#include "src/scopes.h"
......@@ -24,7 +25,8 @@ AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info,
jsgraph_(jsgraph),
globals_(0, local_zone),
breakable_(NULL),
execution_context_(NULL) {
execution_context_(NULL),
loop_assignment_analysis_(NULL) {
InitializeAstVisitor(local_zone);
}
......@@ -59,6 +61,12 @@ bool AstGraphBuilder::CreateGraph() {
int parameter_count = info()->num_parameters();
graph()->SetStart(graph()->NewNode(common()->Start(parameter_count)));
if (FLAG_loop_assignment_analysis) {
// TODO(turbofan): use a temporary zone for the loop assignment analysis.
AstLoopAssignmentAnalyzer analyzer(zone(), info());
loop_assignment_analysis_ = analyzer.Analyze();
}
// Initialize the top-level environment.
Environment env(this, scope, graph()->start());
set_environment(&env);
......@@ -579,9 +587,16 @@ void AstGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
}
BitVector* AstGraphBuilder::GetVariablesAssignedInLoop(
IterationStatement* stmt) {
if (loop_assignment_analysis_ == NULL) return NULL;
return loop_assignment_analysis_->GetVariablesAssignedInLoop(stmt);
}
void AstGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
LoopBuilder while_loop(this);
while_loop.BeginLoop();
while_loop.BeginLoop(GetVariablesAssignedInLoop(stmt));
VisitIterationBody(stmt, &while_loop, 0);
while_loop.EndBody();
VisitForTest(stmt->cond());
......@@ -593,7 +608,7 @@ void AstGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
void AstGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
LoopBuilder while_loop(this);
while_loop.BeginLoop();
while_loop.BeginLoop(GetVariablesAssignedInLoop(stmt));
VisitForTest(stmt->cond());
Node* condition = environment()->Pop();
while_loop.BreakUnless(condition);
......@@ -606,7 +621,7 @@ void AstGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
void AstGraphBuilder::VisitForStatement(ForStatement* stmt) {
LoopBuilder for_loop(this);
VisitIfNotNull(stmt->init());
for_loop.BeginLoop();
for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt));
if (stmt->cond() != NULL) {
VisitForTest(stmt->cond());
Node* condition = environment()->Pop();
......@@ -682,7 +697,7 @@ void AstGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
environment()->Push(jsgraph()->ZeroConstant());
// PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
LoopBuilder for_loop(this);
for_loop.BeginLoop();
for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt));
// Check loop termination condition.
Node* index = environment()->Peek(0);
Node* exit_cond =
......
......@@ -16,8 +16,9 @@ namespace internal {
namespace compiler {
class ControlBuilder;
class LoopBuilder;
class Graph;
class LoopAssignmentAnalysis;
class LoopBuilder;
// The AstGraphBuilder produces a high-level IR graph, based on an
// underlying AST. The produced graph can either be compiled into a
......@@ -135,6 +136,8 @@ class AstGraphBuilder : public StructuredGraphBuilder, public AstVisitor {
SetOncePointer<Node> function_closure_;
SetOncePointer<Node> function_context_;
LoopAssignmentAnalysis* loop_assignment_analysis_;
CompilationInfo* info() const { return info_; }
inline StrictMode strict_mode() const;
JSGraph* jsgraph() { return jsgraph_; }
......@@ -188,6 +191,8 @@ class AstGraphBuilder : public StructuredGraphBuilder, public AstVisitor {
OutputFrameStateCombine StateCombineFromAstContext();
BitVector* GetVariablesAssignedInLoop(IterationStatement* stmt);
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
DISALLOW_COPY_AND_ASSIGN(AstGraphBuilder);
};
......
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/compiler/ast-loop-assignment-analyzer.h"
#include "src/parser.h"
namespace v8 {
namespace internal {
namespace compiler {
typedef class AstLoopAssignmentAnalyzer ALAA; // for code shortitude.
ALAA::AstLoopAssignmentAnalyzer(Zone* zone, CompilationInfo* info)
: info_(info), loop_stack_(zone) {
InitializeAstVisitor(zone);
}
LoopAssignmentAnalysis* ALAA::Analyze() {
LoopAssignmentAnalysis* a = new (zone()) LoopAssignmentAnalysis(zone());
result_ = a;
VisitStatements(info()->function()->body());
result_ = NULL;
return a;
}
void ALAA::Enter(IterationStatement* loop) {
int num_variables = 1 + info()->scope()->num_parameters() +
info()->scope()->num_stack_slots();
BitVector* bits = new (zone()) BitVector(num_variables, zone());
loop_stack_.push_back(bits);
}
void ALAA::Exit(IterationStatement* loop) {
DCHECK(loop_stack_.size() > 0);
BitVector* bits = loop_stack_.back();
loop_stack_.pop_back();
if (!loop_stack_.empty()) {
loop_stack_.back()->Union(*bits);
}
result_->list_.push_back(
std::pair<IterationStatement*, BitVector*>(loop, bits));
}
// ---------------------------------------------------------------------------
// -- Leaf nodes -------------------------------------------------------------
// ---------------------------------------------------------------------------
void ALAA::VisitVariableDeclaration(VariableDeclaration* leaf) {}
void ALAA::VisitFunctionDeclaration(FunctionDeclaration* leaf) {}
void ALAA::VisitModuleDeclaration(ModuleDeclaration* leaf) {}
void ALAA::VisitImportDeclaration(ImportDeclaration* leaf) {}
void ALAA::VisitExportDeclaration(ExportDeclaration* leaf) {}
void ALAA::VisitModuleVariable(ModuleVariable* leaf) {}
void ALAA::VisitModulePath(ModulePath* leaf) {}
void ALAA::VisitModuleUrl(ModuleUrl* leaf) {}
void ALAA::VisitEmptyStatement(EmptyStatement* leaf) {}
void ALAA::VisitContinueStatement(ContinueStatement* leaf) {}
void ALAA::VisitBreakStatement(BreakStatement* leaf) {}
void ALAA::VisitDebuggerStatement(DebuggerStatement* leaf) {}
void ALAA::VisitFunctionLiteral(FunctionLiteral* leaf) {}
void ALAA::VisitNativeFunctionLiteral(NativeFunctionLiteral* leaf) {}
void ALAA::VisitVariableProxy(VariableProxy* leaf) {}
void ALAA::VisitLiteral(Literal* leaf) {}
void ALAA::VisitRegExpLiteral(RegExpLiteral* leaf) {}
void ALAA::VisitThisFunction(ThisFunction* leaf) {}
void ALAA::VisitSuperReference(SuperReference* leaf) {}
// ---------------------------------------------------------------------------
// -- Pass-through nodes------------------------------------------------------
// ---------------------------------------------------------------------------
void ALAA::VisitModuleLiteral(ModuleLiteral* e) { Visit(e->body()); }
void ALAA::VisitBlock(Block* stmt) { VisitStatements(stmt->statements()); }
void ALAA::VisitExpressionStatement(ExpressionStatement* stmt) {
Visit(stmt->expression());
}
void ALAA::VisitIfStatement(IfStatement* stmt) {
Visit(stmt->condition());
Visit(stmt->then_statement());
Visit(stmt->else_statement());
}
void ALAA::VisitReturnStatement(ReturnStatement* stmt) {
Visit(stmt->expression());
}
void ALAA::VisitWithStatement(WithStatement* stmt) {
Visit(stmt->expression());
Visit(stmt->statement());
}
void ALAA::VisitSwitchStatement(SwitchStatement* stmt) {
Visit(stmt->tag());
ZoneList<CaseClause*>* clauses = stmt->cases();
for (int i = 0; i < clauses->length(); i++) {
Visit(clauses->at(i));
}
}
void ALAA::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
Visit(stmt->try_block());
Visit(stmt->finally_block());
}
void ALAA::VisitClassLiteral(ClassLiteral* e) {
VisitIfNotNull(e->extends());
VisitIfNotNull(e->constructor());
ZoneList<ObjectLiteralProperty*>* properties = e->properties();
for (int i = 0; i < properties->length(); i++) {
Visit(properties->at(i)->value());
}
}
void ALAA::VisitConditional(Conditional* e) {
Visit(e->condition());
Visit(e->then_expression());
Visit(e->else_expression());
}
void ALAA::VisitObjectLiteral(ObjectLiteral* e) {
ZoneList<ObjectLiteralProperty*>* properties = e->properties();
for (int i = 0; i < properties->length(); i++) {
Visit(properties->at(i)->value());
}
}
void ALAA::VisitArrayLiteral(ArrayLiteral* e) { VisitExpressions(e->values()); }
void ALAA::VisitYield(Yield* stmt) {
Visit(stmt->generator_object());
Visit(stmt->expression());
}
void ALAA::VisitThrow(Throw* stmt) { Visit(stmt->exception()); }
void ALAA::VisitProperty(Property* e) {
Visit(e->obj());
Visit(e->key());
}
void ALAA::VisitCall(Call* e) {
Visit(e->expression());
VisitExpressions(e->arguments());
}
void ALAA::VisitCallNew(CallNew* e) {
Visit(e->expression());
VisitExpressions(e->arguments());
}
void ALAA::VisitCallRuntime(CallRuntime* e) {
VisitExpressions(e->arguments());
}
void ALAA::VisitUnaryOperation(UnaryOperation* e) { Visit(e->expression()); }
void ALAA::VisitBinaryOperation(BinaryOperation* e) {
Visit(e->left());
Visit(e->right());
}
void ALAA::VisitCompareOperation(CompareOperation* e) {
Visit(e->left());
Visit(e->right());
}
void ALAA::VisitCaseClause(CaseClause* cc) {
if (!cc->is_default()) Visit(cc->label());
VisitStatements(cc->statements());
}
// ---------------------------------------------------------------------------
// -- Interesting nodes-------------------------------------------------------
// ---------------------------------------------------------------------------
void ALAA::VisitModuleStatement(ModuleStatement* stmt) {
Visit(stmt->body());
// TODO(turbofan): can a module appear in a loop?
AnalyzeAssignment(stmt->proxy()->var());
}
void ALAA::VisitTryCatchStatement(TryCatchStatement* stmt) {
Visit(stmt->try_block());
Visit(stmt->catch_block());
// TODO(turbofan): are catch variables well-scoped?
AnalyzeAssignment(stmt->variable());
}
void ALAA::VisitDoWhileStatement(DoWhileStatement* loop) {
Enter(loop);
Visit(loop->body());
Visit(loop->cond());
Exit(loop);
}
void ALAA::VisitWhileStatement(WhileStatement* loop) {
Enter(loop);
Visit(loop->cond());
Visit(loop->body());
Exit(loop);
}
void ALAA::VisitForStatement(ForStatement* loop) {
VisitIfNotNull(loop->init());
Enter(loop);
VisitIfNotNull(loop->cond());
Visit(loop->body());
VisitIfNotNull(loop->next());
Exit(loop);
}
void ALAA::VisitForInStatement(ForInStatement* loop) {
Enter(loop);
Visit(loop->each());
Visit(loop->subject());
Visit(loop->body());
Exit(loop);
}
void ALAA::VisitForOfStatement(ForOfStatement* loop) {
Enter(loop);
Visit(loop->each());
Visit(loop->subject());
Visit(loop->body());
Exit(loop);
}
void ALAA::VisitAssignment(Assignment* stmt) {
Expression* l = stmt->target();
Visit(l);
Visit(stmt->value());
if (l->IsVariableProxy()) AnalyzeAssignment(l->AsVariableProxy()->var());
}
void ALAA::VisitCountOperation(CountOperation* e) {
Expression* l = e->expression();
Visit(l);
if (l->IsVariableProxy()) AnalyzeAssignment(l->AsVariableProxy()->var());
}
void ALAA::AnalyzeAssignment(Variable* var) {
if (!loop_stack_.empty() && var->IsStackAllocated()) {
loop_stack_.back()->Add(GetVariableIndex(info()->scope(), var));
}
}
int ALAA::GetVariableIndex(Scope* scope, Variable* var) {
CHECK(var->IsStackAllocated());
if (var->is_this()) return 0;
if (var->IsParameter()) return 1 + var->index();
return 1 + scope->num_parameters() + var->index();
}
int LoopAssignmentAnalysis::GetAssignmentCountForTesting(Scope* scope,
Variable* var) {
int count = 0;
int var_index = AstLoopAssignmentAnalyzer::GetVariableIndex(scope, var);
for (size_t i = 0; i < list_.size(); i++) {
if (list_[i].second->Contains(var_index)) count++;
}
return count;
}
}
}
} // namespace v8::internal::compiler
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_COMPILER_AST_LOOP_ASSIGNMENT_ANALYZER_H_
#define V8_COMPILER_AST_LOOP_ASSIGNMENT_ANALYZER_H_
#include "src/ast.h"
#include "src/data-flow.h"
#include "src/v8.h"
#include "src/zone-containers.h"
namespace v8 {
namespace internal {
class Variable;
class Scope;
namespace compiler {
// The result of analyzing loop assignments.
class LoopAssignmentAnalysis : public ZoneObject {
public:
BitVector* GetVariablesAssignedInLoop(IterationStatement* loop) {
for (size_t i = 0; i < list_.size(); i++) {
// TODO(turbofan): hashmap or binary search for loop assignments.
if (list_[i].first == loop) return list_[i].second;
}
UNREACHABLE(); // should never ask for loops that aren't here!
return NULL;
}
int GetAssignmentCountForTesting(Scope* scope, Variable* var);
private:
friend class AstLoopAssignmentAnalyzer;
explicit LoopAssignmentAnalysis(Zone* zone) : list_(zone) {}
ZoneVector<std::pair<IterationStatement*, BitVector*>> list_;
};
// The class that performs loop assignment analysis by walking the AST.
class AstLoopAssignmentAnalyzer : public AstVisitor {
public:
AstLoopAssignmentAnalyzer(Zone* zone, CompilationInfo* info);
LoopAssignmentAnalysis* Analyze();
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
static int GetVariableIndex(Scope* scope, Variable* var);
private:
CompilationInfo* info_;
ZoneDeque<BitVector*> loop_stack_;
LoopAssignmentAnalysis* result_;
CompilationInfo* info() { return info_; }
void Enter(IterationStatement* loop);
void Exit(IterationStatement* loop);
void VisitIfNotNull(AstNode* node) {
if (node != NULL) Visit(node);
}
void AnalyzeAssignment(Variable* var);
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
DISALLOW_COPY_AND_ASSIGN(AstLoopAssignmentAnalyzer);
};
}
}
} // namespace v8::internal::compiler
#endif // V8_COMPILER_AST_LOOP_ASSIGNMENT_ANALYZER_H_
......@@ -32,9 +32,9 @@ void IfBuilder::End() {
}
void LoopBuilder::BeginLoop() {
void LoopBuilder::BeginLoop(BitVector* assigned) {
builder_->NewLoop();
loop_environment_ = environment()->CopyForLoop();
loop_environment_ = environment()->CopyForLoop(assigned);
continue_environment_ = environment()->CopyAsUnreachable();
break_environment_ = environment()->CopyAsUnreachable();
}
......
......@@ -69,7 +69,7 @@ class LoopBuilder : public ControlBuilder {
break_environment_(NULL) {}
// Primitive control commands.
void BeginLoop();
void BeginLoop(BitVector* assigned);
void EndBody();
void EndLoop();
......
......@@ -166,11 +166,22 @@ void StructuredGraphBuilder::Environment::Merge(Environment* other) {
}
void StructuredGraphBuilder::Environment::PrepareForLoop() {
void StructuredGraphBuilder::Environment::PrepareForLoop(BitVector* assigned) {
Node* control = GetControlDependency();
for (int i = 0; i < static_cast<int>(values()->size()); ++i) {
Node* phi = builder_->NewPhi(1, values()->at(i), control);
values()->at(i) = phi;
int size = static_cast<int>(values()->size());
if (assigned == NULL) {
// Assume that everything is updated in the loop.
for (int i = 0; i < size; ++i) {
Node* phi = builder_->NewPhi(1, values()->at(i), control);
values()->at(i) = phi;
}
} else {
// Only build phis for those locals assigned in this loop.
for (int i = 0; i < size; ++i) {
if (i < assigned->length() && !assigned->Contains(i)) continue;
Node* phi = builder_->NewPhi(1, values()->at(i), control);
values()->at(i) = phi;
}
}
Node* effect = builder_->NewEffectPhi(1, GetEffectDependency(), control);
UpdateEffectDependency(effect);
......
......@@ -14,6 +14,9 @@
namespace v8 {
namespace internal {
class BitVector;
namespace compiler {
class Node;
......@@ -215,8 +218,8 @@ class StructuredGraphBuilder::Environment : public ZoneObject {
}
// Copies this environment at a loop header control-flow point.
Environment* CopyForLoop() {
PrepareForLoop();
Environment* CopyForLoop(BitVector* assigned) {
PrepareForLoop(assigned);
return builder()->CopyEnvironment(this);
}
......@@ -230,7 +233,7 @@ class StructuredGraphBuilder::Environment : public ZoneObject {
NodeVector* values() { return &values_; }
// Prepare environment to be used as loop header.
void PrepareForLoop();
void PrepareForLoop(BitVector* assigned);
private:
StructuredGraphBuilder* builder_;
......
......@@ -374,6 +374,7 @@ DEFINE_BOOL(turbo_inlining, false, "enable inlining in TurboFan")
DEFINE_BOOL(turbo_inlining_intrinsics, false,
"enable inlining of intrinsics in TurboFan")
DEFINE_BOOL(trace_turbo_inlining, false, "trace TurboFan inlining")
DEFINE_BOOL(loop_assignment_analysis, true, "perform loop assignment analysis")
DEFINE_IMPLICATION(turbo_inlining_intrinsics, turbo_inlining)
DEFINE_IMPLICATION(turbo_inlining, turbo_types)
DEFINE_BOOL(turbo_profiling, false, "enable profiling in TurboFan")
......
......@@ -65,6 +65,7 @@
'compiler/test-js-constant-cache.cc',
'compiler/test-js-typed-lowering.cc',
'compiler/test-linkage.cc',
'compiler/test-loop-assignment-analysis.cc',
'compiler/test-machine-operator-reducer.cc',
'compiler/test-node-algorithm.cc',
'compiler/test-node-cache.cc',
......
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/compiler/ast-loop-assignment-analyzer.h"
#include "src/parser.h"
#include "src/rewriter.h"
#include "src/scopes.h"
#include "test/cctest/cctest.h"
using namespace v8::internal;
using namespace v8::internal::compiler;
namespace {
const int kBufferSize = 1024;
struct TestHelper : public HandleAndZoneScope {
char buffer[kBufferSize];
Handle<JSFunction> function;
LoopAssignmentAnalysis* result;
explicit TestHelper(const char* body)
: function(Handle<JSFunction>::null()), result(NULL) {
snprintf(buffer, kBufferSize, "function f(a,b,c) { %s; } f;", body);
v8::Local<v8::Value> v = CompileRun(buffer);
Handle<Object> obj = v8::Utils::OpenHandle(*v);
function = Handle<JSFunction>::cast(obj);
}
void CheckLoopAssignedCount(int expected, const char* var_name) {
// TODO(titzer): don't scope analyze every single time.
CompilationInfo info(function, main_zone());
CHECK(Parser::Parse(&info));
CHECK(Rewriter::Rewrite(&info));
CHECK(Scope::Analyze(&info));
Scope* scope = info.function()->scope();
AstValueFactory* factory = info.ast_value_factory();
CHECK_NE(NULL, scope);
if (result == NULL) {
AstLoopAssignmentAnalyzer analyzer(main_zone(), &info);
result = analyzer.Analyze();
CHECK_NE(NULL, result);
}
const i::AstRawString* name = factory->GetOneByteString(var_name);
i::Variable* var = scope->Lookup(name);
CHECK_NE(NULL, var);
if (var->location() == Variable::UNALLOCATED) {
CHECK_EQ(0, expected);
} else {
CHECK(var->IsStackAllocated());
CHECK_EQ(expected, result->GetAssignmentCountForTesting(scope, var));
}
}
};
}
TEST(SimpleLoop1) {
TestHelper f("var x = 0; while (x) ;");
f.CheckLoopAssignedCount(0, "x");
}
TEST(SimpleLoop2) {
const char* loops[] = {
"while (x) { var x = 0; }", "for(;;) { var x = 0; }",
"for(;x;) { var x = 0; }", "for(;x;x) { var x = 0; }",
"for(var i = x; x; x) { var x = 0; }", "for(y in 0) { var x = 0; }",
"for(y of 0) { var x = 0; }", "for(var x = 0; x; x++) { }",
"for(var x = 0; x++;) { }", "var x; for(;x;x++) { }",
"var x; do { x = 1; } while (0);", "do { var x = 1; } while (0);"};
for (size_t i = 0; i < arraysize(loops); i++) {
TestHelper f(loops[i]);
f.CheckLoopAssignedCount(1, "x");
}
}
TEST(ForInOf1) {
const char* loops[] = {
"for(x in 0) { }", "for(x of 0) { }",
};
for (size_t i = 0; i < arraysize(loops); i++) {
TestHelper f(loops[i]);
f.CheckLoopAssignedCount(0, "x");
}
}
TEST(Param1) {
TestHelper f("while (1) a = 0;");
f.CheckLoopAssignedCount(1, "a");
f.CheckLoopAssignedCount(0, "b");
f.CheckLoopAssignedCount(0, "c");
}
TEST(Param2) {
TestHelper f("for (;;) b = 0;");
f.CheckLoopAssignedCount(0, "a");
f.CheckLoopAssignedCount(1, "b");
f.CheckLoopAssignedCount(0, "c");
}
TEST(Param2b) {
TestHelper f("a; b; c; for (;;) b = 0;");
f.CheckLoopAssignedCount(0, "a");
f.CheckLoopAssignedCount(1, "b");
f.CheckLoopAssignedCount(0, "c");
}
TEST(Param3) {
TestHelper f("for(x in 0) c = 0;");
f.CheckLoopAssignedCount(0, "a");
f.CheckLoopAssignedCount(0, "b");
f.CheckLoopAssignedCount(1, "c");
}
TEST(Param3b) {
TestHelper f("a; b; c; for(x in 0) c = 0;");
f.CheckLoopAssignedCount(0, "a");
f.CheckLoopAssignedCount(0, "b");
f.CheckLoopAssignedCount(1, "c");
}
TEST(NestedLoop1) {
TestHelper f("while (x) { while (x) { var x = 0; } }");
f.CheckLoopAssignedCount(2, "x");
}
TEST(NestedLoop2) {
TestHelper f("while (0) { while (0) { var x = 0; } }");
f.CheckLoopAssignedCount(2, "x");
}
TEST(NestedLoop3) {
TestHelper f("while (0) { var y = 1; while (0) { var x = 0; } }");
f.CheckLoopAssignedCount(2, "x");
f.CheckLoopAssignedCount(1, "y");
}
TEST(NestedInc1) {
const char* loops[] = {
"while (1) a(b++);",
"while (1) a(0, b++);",
"while (1) a(0, 0, b++);",
"while (1) a(b++, 1, 1);",
"while (1) a(++b);",
"while (1) a + (b++);",
"while (1) (b++) + a;",
"while (1) a + c(b++);",
"while (1) throw b++;",
"while (1) switch (b++) {} ;",
"while (1) switch (a) {case (b++): 0; } ;",
"while (1) switch (a) {case b: b++; } ;",
"while (1) a == (b++);",
"while (1) a === (b++);",
"while (1) +(b++);",
"while (1) ~(b++);",
"while (1) new a(b++);",
"while (1) (b++).f;",
"while (1) a[b++];",
"while (1) (b++)();",
"while (1) [b++];",
"while (1) [0,b++];",
"while (1) var y = [11,b++,12];",
"while (1) var y = {f:11,g:(b++),h:12};",
"while (1) try {b++;} finally {};",
"while (1) try {} finally {b++};",
"while (1) try {b++;} catch (e) {};",
"while (1) try {} catch (e) {b++};",
"while (1) return b++;",
"while (1) (b++) ? b : b;",
"while (1) b ? (b++) : b;",
"while (1) b ? b : (b++);",
};
for (size_t i = 0; i < arraysize(loops); i++) {
TestHelper f(loops[i]);
f.CheckLoopAssignedCount(1, "b");
}
}
TEST(NestedAssign1) {
const char* loops[] = {
"while (1) a(b=1);",
"while (1) a(0, b=1);",
"while (1) a(0, 0, b=1);",
"while (1) a(b=1, 1, 1);",
"while (1) a + (b=1);",
"while (1) (b=1) + a;",
"while (1) a + c(b=1);",
"while (1) throw b=1;",
"while (1) switch (b=1) {} ;",
"while (1) switch (a) {case b=1: 0; } ;",
"while (1) switch (a) {case b: b=1; } ;",
"while (1) a == (b=1);",
"while (1) a === (b=1);",
"while (1) +(b=1);",
"while (1) ~(b=1);",
"while (1) new a(b=1);",
"while (1) (b=1).f;",
"while (1) a[b=1];",
"while (1) (b=1)();",
"while (1) [b=1];",
"while (1) [0,b=1];",
"while (1) var z = [11,b=1,12];",
"while (1) var y = {f:11,g:(b=1),h:12};",
"while (1) try {b=1;} finally {};",
"while (1) try {} finally {b=1};",
"while (1) try {b=1;} catch (e) {};",
"while (1) try {} catch (e) {b=1};",
"while (1) return b=1;",
"while (1) (b=1) ? b : b;",
"while (1) b ? (b=1) : b;",
"while (1) b ? b : (b=1);",
};
for (size_t i = 0; i < arraysize(loops); i++) {
TestHelper f(loops[i]);
f.CheckLoopAssignedCount(1, "b");
}
}
TEST(NestedLoops3) {
TestHelper f("var x, y, z, w; while (x++) while (y++) while (z++) ; w;");
f.CheckLoopAssignedCount(1, "x");
f.CheckLoopAssignedCount(2, "y");
f.CheckLoopAssignedCount(3, "z");
f.CheckLoopAssignedCount(0, "w");
}
TEST(NestedLoops3b) {
TestHelper f(
"var x, y, z, w;"
"while (1) { x=1; while (1) { y=1; while (1) z=1; } }"
"w;");
f.CheckLoopAssignedCount(1, "x");
f.CheckLoopAssignedCount(2, "y");
f.CheckLoopAssignedCount(3, "z");
f.CheckLoopAssignedCount(0, "w");
}
TEST(NestedLoops3c) {
TestHelper f(
"var x, y, z, w;"
"while (1) {"
" x++;"
" while (1) {"
" y++;"
" while (1) z++;"
" }"
" while (1) {"
" y++;"
" while (1) z++;"
" }"
"}"
"w;");
f.CheckLoopAssignedCount(1, "x");
f.CheckLoopAssignedCount(3, "y");
f.CheckLoopAssignedCount(5, "z");
f.CheckLoopAssignedCount(0, "w");
}
......@@ -393,6 +393,8 @@
'../../src/compiler/access-builder.h',
'../../src/compiler/ast-graph-builder.cc',
'../../src/compiler/ast-graph-builder.h',
'../../src/compiler/ast-loop-assignment-analyzer.cc',
'../../src/compiler/ast-loop-assignment-analyzer.h',
'../../src/compiler/basic-block-instrumentor.cc',
'../../src/compiler/basic-block-instrumentor.h',
'../../src/compiler/change-lowering.cc',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment