"src/compiler/common-operator.h",
"src/compiler/control-builders.cc",
"src/compiler/control-builders.h",
+ "src/compiler/control-reducer.cc",
+ "src/compiler/control-reducer.h",
"src/compiler/frame.h",
"src/compiler/gap-resolver.cc",
"src/compiler/gap-resolver.h",
--- /dev/null
+// 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/common-operator.h"
+#include "src/compiler/control-reducer.h"
+#include "src/compiler/graph.h"
+#include "src/compiler/js-graph.h"
+#include "src/compiler/node-matchers.h"
+#include "src/compiler/node-properties-inl.h"
+#include "src/zone-containers.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+enum VisitState { kUnvisited, kOnStack, kRevisit, kVisited };
+
+#define TRACE(x) \
+ if (FLAG_trace_turbo) PrintF x
+
+class ControlReducerImpl {
+ public:
+ ControlReducerImpl(JSGraph* jsgraph, CommonOperatorBuilder* common)
+ : zone_(jsgraph->zone()->isolate()),
+ jsgraph_(jsgraph),
+ common_(common),
+ state_(jsgraph->graph()->NodeCount(), kUnvisited, &zone_),
+ stack_(&zone_),
+ revisit_(&zone_),
+ dead_(NULL) {}
+
+ Zone zone_;
+ JSGraph* jsgraph_;
+ CommonOperatorBuilder* common_;
+ ZoneVector<VisitState> state_;
+ ZoneDeque<Node*> stack_;
+ ZoneDeque<Node*> revisit_;
+ Node* dead_;
+
+ void Trim() {
+ // Mark all nodes reachable from end.
+ NodeVector nodes(&zone_);
+ state_.assign(jsgraph_->graph()->NodeCount(), kUnvisited);
+ Push(jsgraph_->graph()->end());
+ while (!stack_.empty()) {
+ Node* node = stack_[stack_.size() - 1];
+ stack_.pop_back();
+ state_[node->id()] = kVisited;
+ nodes.push_back(node);
+ for (InputIter i = node->inputs().begin(); i != node->inputs().end();
+ ++i) {
+ Recurse(*i); // pushes node onto the stack if necessary.
+ }
+ }
+ // Process cached nodes in the JSGraph too.
+ jsgraph_->GetCachedNodes(&nodes);
+ // Remove dead->live edges.
+ for (size_t j = 0; j < nodes.size(); j++) {
+ Node* node = nodes[j];
+ for (UseIter i = node->uses().begin(); i != node->uses().end();) {
+ size_t id = static_cast<size_t>((*i)->id());
+ if (state_[id] != kVisited) {
+ TRACE(("DeadLink: #%d:%s(%d) -> #%d:%s\n", (*i)->id(),
+ (*i)->op()->mnemonic(), i.index(), node->id(),
+ node->op()->mnemonic()));
+ i.UpdateToAndIncrement(NULL);
+ } else {
+ ++i;
+ }
+ }
+ }
+#if DEBUG
+ // Verify that no inputs to live nodes are NULL.
+ for (size_t j = 0; j < nodes.size(); j++) {
+ Node* node = nodes[j];
+ for (InputIter i = node->inputs().begin(); i != node->inputs().end();
+ ++i) {
+ CHECK_NE(NULL, *i);
+ }
+ for (UseIter i = node->uses().begin(); i != node->uses().end(); ++i) {
+ size_t id = static_cast<size_t>((*i)->id());
+ CHECK_EQ(kVisited, state_[id]);
+ }
+ }
+#endif
+ }
+
+ // Push a node onto the stack if its state is {kUnvisited} or {kRevisit}.
+ bool Recurse(Node* node) {
+ size_t id = static_cast<size_t>(node->id());
+ if (id < state_.size()) {
+ if (state_[id] != kRevisit && state_[id] != kUnvisited) return false;
+ } else {
+ state_.resize((3 * id) / 2, kUnvisited);
+ }
+ Push(node);
+ return true;
+ }
+
+ void Push(Node* node) {
+ state_[node->id()] = kOnStack;
+ stack_.push_back(node);
+ }
+};
+
+void ControlReducer::ReduceGraph(JSGraph* jsgraph,
+ CommonOperatorBuilder* common) {
+ ControlReducerImpl impl(jsgraph, NULL);
+ // Only trim the graph for now. Control reduction can reduce non-terminating
+ // loops to graphs that are unschedulable at the moment.
+ impl.Trim();
+}
+
+
+void ControlReducer::TrimGraph(JSGraph* jsgraph) {
+ ControlReducerImpl impl(jsgraph, NULL);
+ impl.Trim();
+}
+}
+}
+} // namespace v8::internal::compiler
--- /dev/null
+// 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_CONTROL_REDUCER_H_
+#define V8_COMPILER_CONTROL_REDUCER_H_
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class JSGraph;
+class CommonOperatorBuilder;
+
+class ControlReducer {
+ public:
+ // Perform branch folding and dead code elimination on the graph.
+ static void ReduceGraph(JSGraph* graph, CommonOperatorBuilder* builder);
+
+ // Trim nodes in the graph that are not reachable from end.
+ static void TrimGraph(JSGraph* graph);
+};
+}
+}
+} // namespace v8::internal::compiler
+
+#endif // V8_COMPILER_CONTROL_REDUCER_H_
#include "src/compiler/basic-block-instrumentor.h"
#include "src/compiler/change-lowering.h"
#include "src/compiler/code-generator.h"
+#include "src/compiler/control-reducer.h"
#include "src/compiler/graph-replay.h"
#include "src/compiler/graph-visualizer.h"
#include "src/compiler/instruction.h"
// TODO(jarin, rossberg): Remove UNTYPED once machine typing works.
VerifyAndPrintGraph(&graph, "Lowered changes", true);
}
+
+ {
+ SourcePositionTable::Scope pos(&source_positions,
+ SourcePosition::Unknown());
+ PhaseStats control_reducer_stats(info(), PhaseStats::CREATE_GRAPH,
+ "control reduction");
+ ControlReducer::ReduceGraph(&jsgraph, &common);
+
+ VerifyAndPrintGraph(&graph, "Control reduced");
+ }
}
{
'compiler/test-branch-combine.cc',
'compiler/test-changes-lowering.cc',
'compiler/test-codegen-deopt.cc',
+ 'compiler/test-control-reducer.cc',
'compiler/test-gap-resolver.cc',
'compiler/test-graph-reducer.cc',
'compiler/test-instruction.cc',
'test-debug/DebugEventContext': [PASS, NO_VARIANTS],
'test-debug/DebugBreakInline': [PASS, NO_VARIANTS],
+ # Scheduling and verifying of empty for loops is broken.
+ 'test-run-jsbranches/EmptyFor': [SKIP],
+
############################################################################
# Slow tests.
'test-api/Threading1': [PASS, ['mode == debug', SLOW]],
--- /dev/null
+// 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/v8.h"
+#include "test/cctest/cctest.h"
+
+#include "src/compiler/common-operator.h"
+#include "src/compiler/control-reducer.h"
+#include "src/compiler/graph-inl.h"
+#include "src/compiler/js-graph.h"
+
+using namespace v8::internal;
+using namespace v8::internal::compiler;
+
+class CTrimTester : HandleAndZoneScope {
+ public:
+ CTrimTester()
+ : isolate(main_isolate()),
+ common(main_zone()),
+ graph(main_zone()),
+ jsgraph(&graph, &common, NULL, NULL),
+ start(graph.NewNode(common.Start(1))),
+ p0(graph.NewNode(common.Parameter(0), start)),
+ one(jsgraph.OneConstant()),
+ half(jsgraph.Constant(0.5)) {
+ graph.SetEnd(start);
+ graph.SetStart(start);
+ }
+
+ Isolate* isolate;
+ CommonOperatorBuilder common;
+ Graph graph;
+ JSGraph jsgraph;
+ Node* start;
+ Node* p0;
+ Node* one;
+ Node* half;
+
+ void Trim() { ControlReducer::TrimGraph(&jsgraph); }
+};
+
+
+bool IsUsedBy(Node* a, Node* b) {
+ for (UseIter i = a->uses().begin(); i != a->uses().end(); ++i) {
+ if (b == *i) return true;
+ }
+ return false;
+}
+
+
+TEST(Trim1_live) {
+ CTrimTester T;
+ CHECK(IsUsedBy(T.start, T.p0));
+ T.graph.SetEnd(T.p0);
+ T.Trim();
+ CHECK(IsUsedBy(T.start, T.p0));
+ CHECK_EQ(T.start, T.p0->InputAt(0));
+}
+
+
+TEST(Trim1_dead) {
+ CTrimTester T;
+ CHECK(IsUsedBy(T.start, T.p0));
+ T.Trim();
+ CHECK(!IsUsedBy(T.start, T.p0));
+ CHECK_EQ(NULL, T.p0->InputAt(0));
+}
+
+
+TEST(Trim2_live) {
+ CTrimTester T;
+ Node* phi =
+ T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, T.start);
+ CHECK(IsUsedBy(T.one, phi));
+ CHECK(IsUsedBy(T.half, phi));
+ CHECK(IsUsedBy(T.start, phi));
+ T.graph.SetEnd(phi);
+ T.Trim();
+ CHECK(IsUsedBy(T.one, phi));
+ CHECK(IsUsedBy(T.half, phi));
+ CHECK(IsUsedBy(T.start, phi));
+ CHECK_EQ(T.one, phi->InputAt(0));
+ CHECK_EQ(T.half, phi->InputAt(1));
+ CHECK_EQ(T.start, phi->InputAt(2));
+}
+
+
+TEST(Trim2_dead) {
+ CTrimTester T;
+ Node* phi =
+ T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, T.start);
+ CHECK(IsUsedBy(T.one, phi));
+ CHECK(IsUsedBy(T.half, phi));
+ CHECK(IsUsedBy(T.start, phi));
+ T.Trim();
+ CHECK(!IsUsedBy(T.one, phi));
+ CHECK(!IsUsedBy(T.half, phi));
+ CHECK(!IsUsedBy(T.start, phi));
+ CHECK_EQ(NULL, phi->InputAt(0));
+ CHECK_EQ(NULL, phi->InputAt(1));
+ CHECK_EQ(NULL, phi->InputAt(2));
+}
+
+
+TEST(Trim_chain1) {
+ CTrimTester T;
+ const int kDepth = 15;
+ Node* live[kDepth];
+ Node* dead[kDepth];
+ Node* end = T.start;
+ for (int i = 0; i < kDepth; i++) {
+ live[i] = end = T.graph.NewNode(T.common.Merge(1), end);
+ dead[i] = T.graph.NewNode(T.common.Merge(1), end);
+ }
+ // end -> live[last] -> live[last-1] -> ... -> start
+ // dead[last] ^ dead[last-1] ^ ... ^
+ T.graph.SetEnd(end);
+ T.Trim();
+ for (int i = 0; i < kDepth; i++) {
+ CHECK(!IsUsedBy(live[i], dead[i]));
+ CHECK_EQ(NULL, dead[i]->InputAt(0));
+ CHECK_EQ(i == 0 ? T.start : live[i - 1], live[i]->InputAt(0));
+ }
+}
+
+
+TEST(Trim_chain2) {
+ CTrimTester T;
+ const int kDepth = 15;
+ Node* live[kDepth];
+ Node* dead[kDepth];
+ Node* l = T.start;
+ Node* d = T.start;
+ for (int i = 0; i < kDepth; i++) {
+ live[i] = l = T.graph.NewNode(T.common.Merge(1), l);
+ dead[i] = d = T.graph.NewNode(T.common.Merge(1), d);
+ }
+ // end -> live[last] -> live[last-1] -> ... -> start
+ // dead[last] -> dead[last-1] -> ... -> start
+ T.graph.SetEnd(l);
+ T.Trim();
+ CHECK(!IsUsedBy(T.start, dead[0]));
+ for (int i = 0; i < kDepth; i++) {
+ CHECK_EQ(i == 0 ? NULL : dead[i - 1], dead[i]->InputAt(0));
+ CHECK_EQ(i == 0 ? T.start : live[i - 1], live[i]->InputAt(0));
+ }
+}
+
+
+TEST(Trim_cycle1) {
+ CTrimTester T;
+ Node* loop = T.graph.NewNode(T.common.Loop(1), T.start, T.start);
+ loop->ReplaceInput(1, loop);
+ Node* end = T.graph.NewNode(T.common.End(), loop);
+ T.graph.SetEnd(end);
+
+ CHECK(IsUsedBy(T.start, loop));
+ CHECK(IsUsedBy(loop, end));
+ CHECK(IsUsedBy(loop, loop));
+
+ T.Trim();
+
+ // nothing should have happened to the loop itself.
+ CHECK(IsUsedBy(T.start, loop));
+ CHECK(IsUsedBy(loop, end));
+ CHECK(IsUsedBy(loop, loop));
+ CHECK_EQ(T.start, loop->InputAt(0));
+ CHECK_EQ(loop, loop->InputAt(1));
+ CHECK_EQ(loop, end->InputAt(0));
+}
+
+
+TEST(Trim_cycle2) {
+ CTrimTester T;
+ Node* loop = T.graph.NewNode(T.common.Loop(2), T.start, T.start);
+ loop->ReplaceInput(1, loop);
+ Node* end = T.graph.NewNode(T.common.End(), loop);
+ Node* phi =
+ T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, loop);
+ T.graph.SetEnd(end);
+
+ CHECK(IsUsedBy(T.start, loop));
+ CHECK(IsUsedBy(loop, end));
+ CHECK(IsUsedBy(loop, loop));
+ CHECK(IsUsedBy(loop, phi));
+ CHECK(IsUsedBy(T.one, phi));
+ CHECK(IsUsedBy(T.half, phi));
+
+ T.Trim();
+
+ // nothing should have happened to the loop itself.
+ CHECK(IsUsedBy(T.start, loop));
+ CHECK(IsUsedBy(loop, end));
+ CHECK(IsUsedBy(loop, loop));
+ CHECK_EQ(T.start, loop->InputAt(0));
+ CHECK_EQ(loop, loop->InputAt(1));
+ CHECK_EQ(loop, end->InputAt(0));
+
+ // phi should have been trimmed away.
+ CHECK(!IsUsedBy(loop, phi));
+ CHECK(!IsUsedBy(T.one, phi));
+ CHECK(!IsUsedBy(T.half, phi));
+ CHECK_EQ(NULL, phi->InputAt(0));
+ CHECK_EQ(NULL, phi->InputAt(1));
+ CHECK_EQ(NULL, phi->InputAt(2));
+}
+
+
+void CheckTrimConstant(CTrimTester* T, Node* k) {
+ Node* phi = T->graph.NewNode(T->common.Phi(kMachInt32, 1), k, T->start);
+ CHECK(IsUsedBy(k, phi));
+ T->Trim();
+ CHECK(!IsUsedBy(k, phi));
+ CHECK_EQ(NULL, phi->InputAt(0));
+ CHECK_EQ(NULL, phi->InputAt(1));
+}
+
+
+TEST(Trim_constants) {
+ CTrimTester T;
+ int32_t int32_constants[] = {
+ 0, -1, -2, 2, 2, 3, 3, 4, 4, 5, 5, 4, 5, 6, 6, 7, 8, 7, 8, 9,
+ 0, -11, -12, 12, 12, 13, 13, 14, 14, 15, 15, 14, 15, 6, 6, 7, 8, 7, 8, 9};
+
+ for (size_t i = 0; i < arraysize(int32_constants); i++) {
+ CheckTrimConstant(&T, T.jsgraph.Int32Constant(int32_constants[i]));
+ CheckTrimConstant(&T, T.jsgraph.Float64Constant(int32_constants[i]));
+ CheckTrimConstant(&T, T.jsgraph.Constant(int32_constants[i]));
+ }
+
+ Node* other_constants[] = {
+ T.jsgraph.UndefinedConstant(), T.jsgraph.TheHoleConstant(),
+ T.jsgraph.TrueConstant(), T.jsgraph.FalseConstant(),
+ T.jsgraph.NullConstant(), T.jsgraph.ZeroConstant(),
+ T.jsgraph.OneConstant(), T.jsgraph.NaNConstant(),
+ T.jsgraph.Constant(21), T.jsgraph.Constant(22.2)};
+
+ for (size_t i = 0; i < arraysize(other_constants); i++) {
+ CheckTrimConstant(&T, other_constants[i]);
+ }
+}
T.CheckCall(T.Val(2), T.Val(2), T.false_value());
T.CheckCall(T.undefined(), T.Val(1), T.null());
}
+
+
+TEST(IfTrue) {
+ FunctionTester T("(function(a,b) { if (true) return a; return b; })");
+
+ T.CheckCall(T.Val(55), T.Val(55), T.Val(11));
+ T.CheckCall(T.Val(666), T.Val(666), T.Val(-444));
+}
+
+
+TEST(TernaryTrue) {
+ FunctionTester T("(function(a,b) { return true ? a : b; })");
+
+ T.CheckCall(T.Val(77), T.Val(77), T.Val(11));
+ T.CheckCall(T.Val(111), T.Val(111), T.Val(-444));
+}
+
+
+TEST(IfFalse) {
+ FunctionTester T("(function(a,b) { if (false) return a; return b; })");
+
+ T.CheckCall(T.Val(11), T.Val(22), T.Val(11));
+ T.CheckCall(T.Val(-555), T.Val(333), T.Val(-555));
+}
+
+
+TEST(TernaryFalse) {
+ FunctionTester T("(function(a,b) { return false ? a : b; })");
+
+ T.CheckCall(T.Val(99), T.Val(33), T.Val(99));
+ T.CheckCall(T.Val(-99), T.Val(-33), T.Val(-99));
+}
+
+
+TEST(WhileTrue) {
+ FunctionTester T("(function(a,b) { while (true) return a; return b; })");
+
+ T.CheckCall(T.Val(551), T.Val(551), T.Val(111));
+ T.CheckCall(T.Val(661), T.Val(661), T.Val(-444));
+}
+
+
+TEST(WhileFalse) {
+ FunctionTester T("(function(a,b) { while (false) return a; return b; })");
+
+ T.CheckCall(T.Val(115), T.Val(551), T.Val(115));
+ T.CheckCall(T.Val(-445), T.Val(661), T.Val(-445));
+}
+
+
+TEST(DoWhileTrue) {
+ FunctionTester T(
+ "(function(a,b) { do { return a; } while (true); return b; })");
+
+ T.CheckCall(T.Val(7551), T.Val(7551), T.Val(7111));
+ T.CheckCall(T.Val(7661), T.Val(7661), T.Val(-7444));
+}
+
+
+TEST(DoWhileFalse) {
+ FunctionTester T(
+ "(function(a,b) { do { "
+ "; } while (false); return b; })");
+
+ T.CheckCall(T.Val(8115), T.Val(8551), T.Val(8115));
+ T.CheckCall(T.Val(-8445), T.Val(8661), T.Val(-8445));
+}
+
+
+TEST(EmptyFor) {
+ FunctionTester T("(function(a,b) { if (a) for(;;) ; return b; })");
+
+ T.CheckCall(T.Val(8126.1), T.Val(0.0), T.Val(8126.1));
+ T.CheckCall(T.Val(1123.1), T.Val(0.0), T.Val(1123.1));
+}
--- /dev/null
+// 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.
+
+function Module() {
+ "use asm";
+
+ function d0() {
+ do { } while(false);
+ return 110;
+ }
+
+ function d1() {
+ do { return 111; } while(false);
+ return 112;
+ }
+
+ function d2() {
+ do { break; } while(false);
+ return 113;
+ }
+
+ function d3(a) {
+ a = a | 0;
+ do { if (a) return 114; } while(false);
+ return 115;
+ }
+
+ function d4(a) {
+ a = a | 0;
+ do { if (a) return 116; else break; } while(false);
+ return 117;
+ }
+
+ function d5(a) {
+ a = a | 0;
+ do { if (a) return 118; } while(false);
+ return 119;
+ }
+
+ function d6(a) {
+ a = a | 0;
+ do {
+ if (a == 0) return 120;
+ if (a == 1) break;
+ if (a == 2) return 122;
+ if (a == 3) continue;
+ if (a == 4) return 124;
+ } while(false);
+ return 125;
+ }
+
+ return {d0: d0, d1: d1, d2: d2, d3: d3, d4: d4, d5: d5, d6: d6};
+}
+
+var m = Module();
+
+assertEquals(110, m.d0());
+
+assertEquals(111, m.d1());
+
+assertEquals(113, m.d2());
+
+assertEquals(114, m.d3(1));
+assertEquals(115, m.d3(0));
+
+assertEquals(116, m.d4(1));
+assertEquals(117, m.d4(0));
+
+assertEquals(118, m.d5(1));
+assertEquals(119, m.d5(0));
+
+assertEquals(120, m.d6(0));
+assertEquals(125, m.d6(1));
+assertEquals(122, m.d6(2));
+assertEquals(125, m.d6(3));
+assertEquals(124, m.d6(4));
+assertEquals(125, m.d6(5));
--- /dev/null
+// 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.
+
+function Module() {
+ "use asm";
+
+ function if0() {
+ if (0) return 11;
+ return 12;
+ }
+
+ function if1() {
+ if (1) return 13;
+ return 14;
+ }
+
+ function if2() {
+ if (0) return 15;
+ else return 16;
+ }
+
+ function if3() {
+ if (1) return 17;
+ else return 18;
+ }
+
+ function if4() {
+ return 1 ? 19 : 20;
+ }
+
+ function if5() {
+ return 0 ? 21 : 22;
+ }
+
+ function if6() {
+ var x = 0 ? 23 : 24;
+ return x;
+ }
+
+ function if7() {
+ if (0) { var x = 0 ? 25 : 26; }
+ else { var x = 0 ? 27 : 28; }
+ return x;
+ }
+
+ function if8() {
+ if (0) {
+ if (0) { var x = 0 ? 29 : 30; }
+ else { var x = 0 ? 31 : 32; }
+ } else {
+ if (0) { var x = 0 ? 33 : 34; }
+ else { var x = 0 ? 35 : 36; }
+ }
+ return x;
+ }
+
+ return {if0: if0, if1: if1, if2: if2, if3: if3, if4: if4, if5: if5, if6: if6, if7: if7, if8: if8 };
+}
+
+var m = Module();
+assertEquals(12, m.if0());
+assertEquals(13, m.if1());
+assertEquals(16, m.if2());
+assertEquals(17, m.if3());
+assertEquals(19, m.if4());
+assertEquals(22, m.if5());
+assertEquals(24, m.if6());
+assertEquals(28, m.if7());
+assertEquals(36, m.if8());
+
+
+function Spec(a,b,c) {
+ "use asm";
+
+ var xx = a | 0;
+ var yy = b | 0;
+ var zz = c | 0;
+
+ function f() {
+ if (xx) {
+ if (yy) { var x = zz ? 29 : 30; }
+ else { var x = zz ? 31 : 32; }
+ } else {
+ if (yy) { var x = zz ? 33 : 34; }
+ else { var x = zz ? 35 : 36; }
+ }
+ return x;
+ }
+ return {f: f};
+}
+
+assertEquals(36, Spec(0,0,0).f());
+assertEquals(35, Spec(0,0,1).f());
+assertEquals(34, Spec(0,1,0).f());
+assertEquals(33, Spec(0,1,1).f());
+assertEquals(32, Spec(1,0,0).f());
+assertEquals(31, Spec(1,0,1).f());
+assertEquals(30, Spec(1,1,0).f());
+assertEquals(29, Spec(1,1,1).f());
--- /dev/null
+// 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.
+
+function Module() {
+ "use asm";
+
+ function if0() {
+ var x = 0 ? 11 : 12;
+ return (x == 11) | 0;
+ }
+
+ function if1() {
+ var x = 1 ? 13 : 14;
+ return (x == 13) | 0;
+ }
+
+ function if2() {
+ var x = 0 ? 15 : 16;
+ return (x != 15) | 0;
+ }
+
+ function if3() {
+ var x = 1 ? 17 : 18;
+ return (x != 17) | 0;
+ }
+
+ function if4() {
+ var x = 0 ? 19 : 20;
+ var y = (x == 19) ? 21 : 22;
+ return y;
+ }
+
+ function if5() {
+ var x = 1 ? 23 : 24;
+ var y = (x == 23) ? 25 : 26;
+ return y;
+ }
+
+ function if6() {
+ var x = 0 ? 27 : 28;
+ var y = (x == 27) ? 29 : 30;
+ var z = (y == 29) ? 31 : 32;
+ return z;
+ }
+
+ function if7() {
+ var x = 1 ? 33 : 34;
+ var y = (x == 33) ? 35 : 36;
+ var z = (y == 35) ? 37 : 38;
+ var w = (z == 37) ? 39 : 40;
+ return w;
+ }
+
+ function if8() {
+ if (0) {
+ var x = 0 ? 43 : 44;
+ var y = (x == 43) ? 45 : 46;
+ var z = (y == 45) ? 47 : 48;
+ var w = (z == 47) ? 49 : 50;
+ } else {
+ var x = 1 ? 53 : 54;
+ var y = (x == 53) ? 55 : 56;
+ var z = (y == 55) ? 57 : 58;
+ var w = (z == 57) ? 59 : 60;
+ }
+ return w;
+ }
+
+ return {if0: if0, if1: if1, if2: if2, if3: if3, if4: if4, if5: if5, if6: if6, if7: if7, if8: if8 };
+}
+
+var m = Module();
+assertEquals(0, m.if0());
+assertEquals(1, m.if1());
+assertEquals(1, m.if2());
+assertEquals(0, m.if3());
+assertEquals(22, m.if4());
+assertEquals(25, m.if5());
+assertEquals(32, m.if6());
+assertEquals(39, m.if7());
+assertEquals(59, m.if8());
+
+
+function Spec(a,b) {
+ "use asm";
+
+ var xx = a | 0;
+ var yy = b | 0;
+
+ function f() {
+ if (xx) {
+ var x = yy ? 43 : 44;
+ var y = (x == 43) ? 45 : 46;
+ var z = (y == 45) ? 47 : 48;
+ var w = (z == 47) ? 49 : 50;
+ } else {
+ var x = yy ? 53 : 54;
+ var y = (x == 53) ? 55 : 56;
+ var z = (y == 55) ? 57 : 58;
+ var w = (z == 57) ? 59 : 60;
+ }
+ return w;
+ }
+ return {f: f};
+}
+
+assertEquals(60, Spec(0,0).f());
+assertEquals(59, Spec(0,1).f());
+assertEquals(50, Spec(1,0).f());
+assertEquals(49, Spec(1,1).f());
--- /dev/null
+// 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.
+
+var error = "error";
+function counter(x) {
+ return (function() { if (x-- == 0) throw error;});
+}
+
+function Module() {
+ "use asm";
+
+ function w0(f) {
+ while (1) f();
+ return 108;
+ }
+
+ function w1(f) {
+ if (1) while (1) f();
+ return 109;
+ }
+
+ function w2(f) {
+ if (1) while (1) f();
+ else while (1) f();
+ return 110;
+ }
+
+ function w3(f) {
+ if (0) while (1) f();
+ return 111;
+ }
+
+ return { w0: w0, w1: w1, w2: w2, w3: w3 };
+}
+
+var m = Module();
+assertThrows(function() { m.w0(counter(5)) }, error);
+assertThrows(function() { m.w1(counter(5)) }, error);
+assertThrows(function() { m.w2(counter(5)) }, error);
+assertEquals(111, m.w3(counter(5)));
--- /dev/null
+// 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.
+
+function Module() {
+ "use asm";
+
+ function w0(a) {
+ a = a | 0;
+ if (a) while (1);
+ return 42;
+ }
+
+ function w1(a) {
+ a = a | 0;
+ while (1) return 42;
+ return 106;
+ }
+
+ function d0(a) {
+ a = a | 0;
+ if (a) do ; while(1);
+ return 42;
+ }
+
+ function d1(a) {
+ a = a | 0;
+ do return 42; while(1);
+ return 107;
+ }
+
+ function f0(a) {
+ a = a | 0;
+ if (a) for (;;) ;
+ return 42;
+ }
+
+ function f1(a) {
+ a = a | 0;
+ for(;;) return 42;
+ return 108;
+ }
+
+ return { w0: w0, w1: w1, d0: d0, d1: d1, f0: f0, f1: f1 };
+}
+
+var m = Module();
+assertEquals(42, m.w0(0));
+assertEquals(42, m.w1(0));
+assertEquals(42, m.d0(0));
+assertEquals(42, m.d1(0));
+assertEquals(42, m.f0(0));
+assertEquals(42, m.f1(0));
'regress/regress-crbug-259300': [PASS, NO_VARIANTS],
'regress/regress-frame-details-null-receiver': [PASS, NO_VARIANTS],
+ # Infinite loops of the form "for(;;) ;" don't schedule or crash in verifier.
+ 'asm/infinite-loops': [PASS, NO_VARIANTS],
+
##############################################################################
# Too slow in debug mode with --stress-opt mode.
'compiler/regress-stacktrace-methods': [PASS, ['mode == debug', SKIP]],
'../../src/compiler/common-operator.h',
'../../src/compiler/control-builders.cc',
'../../src/compiler/control-builders.h',
+ '../../src/compiler/control-reducer.cc',
+ '../../src/compiler/control-reducer.h',
'../../src/compiler/frame.h',
'../../src/compiler/gap-resolver.cc',
'../../src/compiler/gap-resolver.h',