Home | History | Annotate | Download | only in compiler
      1 // Copyright 2014 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/bit-vector.h"
      6 #include "src/compiler/control-equivalence.h"
      7 #include "src/compiler/graph-visualizer.h"
      8 #include "src/compiler/node-properties.h"
      9 #include "src/compiler/source-position.h"
     10 #include "src/zone-containers.h"
     11 #include "test/unittests/compiler/graph-unittest.h"
     12 
     13 namespace v8 {
     14 namespace internal {
     15 namespace compiler {
     16 
     17 #define ASSERT_EQUIVALENCE(...)                           \
     18   do {                                                    \
     19     Node* __n[] = {__VA_ARGS__};                          \
     20     ASSERT_TRUE(IsEquivalenceClass(arraysize(__n), __n)); \
     21   } while (false)
     22 
     23 class ControlEquivalenceTest : public GraphTest {
     24  public:
     25   ControlEquivalenceTest() : all_nodes_(zone()), classes_(zone()) {
     26     Store(graph()->start());
     27   }
     28 
     29  protected:
     30   void ComputeEquivalence(Node* node) {
     31     graph()->SetEnd(graph()->NewNode(common()->End(1), node));
     32     if (FLAG_trace_turbo) {
     33       OFStream os(stdout);
     34       SourcePositionTable table(graph());
     35       os << AsJSON(*graph(), &table);
     36     }
     37     ControlEquivalence equivalence(zone(), graph());
     38     equivalence.Run(node);
     39     classes_.resize(graph()->NodeCount());
     40     for (Node* node : all_nodes_) {
     41       classes_[node->id()] = equivalence.ClassOf(node);
     42     }
     43   }
     44 
     45   bool IsEquivalenceClass(size_t length, Node** nodes) {
     46     BitVector in_class(static_cast<int>(graph()->NodeCount()), zone());
     47     size_t expected_class = classes_[nodes[0]->id()];
     48     for (size_t i = 0; i < length; ++i) {
     49       in_class.Add(nodes[i]->id());
     50     }
     51     for (Node* node : all_nodes_) {
     52       if (in_class.Contains(node->id())) {
     53         if (classes_[node->id()] != expected_class) return false;
     54       } else {
     55         if (classes_[node->id()] == expected_class) return false;
     56       }
     57     }
     58     return true;
     59   }
     60 
     61   Node* Value() { return NumberConstant(0.0); }
     62 
     63   Node* Branch(Node* control) {
     64     return Store(graph()->NewNode(common()->Branch(), Value(), control));
     65   }
     66 
     67   Node* IfTrue(Node* control) {
     68     return Store(graph()->NewNode(common()->IfTrue(), control));
     69   }
     70 
     71   Node* IfFalse(Node* control) {
     72     return Store(graph()->NewNode(common()->IfFalse(), control));
     73   }
     74 
     75   Node* Merge1(Node* control) {
     76     return Store(graph()->NewNode(common()->Merge(1), control));
     77   }
     78 
     79   Node* Merge2(Node* control1, Node* control2) {
     80     return Store(graph()->NewNode(common()->Merge(2), control1, control2));
     81   }
     82 
     83   Node* Loop2(Node* control) {
     84     return Store(graph()->NewNode(common()->Loop(2), control, control));
     85   }
     86 
     87   Node* End(Node* control) {
     88     return Store(graph()->NewNode(common()->End(1), control));
     89   }
     90 
     91  private:
     92   Node* Store(Node* node) {
     93     all_nodes_.push_back(node);
     94     return node;
     95   }
     96 
     97   ZoneVector<Node*> all_nodes_;
     98   ZoneVector<size_t> classes_;
     99 };
    100 
    101 
    102 // -----------------------------------------------------------------------------
    103 // Test cases.
    104 
    105 
    106 TEST_F(ControlEquivalenceTest, Empty1) {
    107   Node* start = graph()->start();
    108   ComputeEquivalence(start);
    109 
    110   ASSERT_EQUIVALENCE(start);
    111 }
    112 
    113 
    114 TEST_F(ControlEquivalenceTest, Empty2) {
    115   Node* start = graph()->start();
    116   Node* merge1 = Merge1(start);
    117   ComputeEquivalence(merge1);
    118 
    119   ASSERT_EQUIVALENCE(start, merge1);
    120 }
    121 
    122 
    123 TEST_F(ControlEquivalenceTest, Diamond1) {
    124   Node* start = graph()->start();
    125   Node* b = Branch(start);
    126   Node* t = IfTrue(b);
    127   Node* f = IfFalse(b);
    128   Node* m = Merge2(t, f);
    129   ComputeEquivalence(m);
    130 
    131   ASSERT_EQUIVALENCE(b, m, start);
    132   ASSERT_EQUIVALENCE(f);
    133   ASSERT_EQUIVALENCE(t);
    134 }
    135 
    136 
    137 TEST_F(ControlEquivalenceTest, Diamond2) {
    138   Node* start = graph()->start();
    139   Node* b1 = Branch(start);
    140   Node* t1 = IfTrue(b1);
    141   Node* f1 = IfFalse(b1);
    142   Node* b2 = Branch(f1);
    143   Node* t2 = IfTrue(b2);
    144   Node* f2 = IfFalse(b2);
    145   Node* m2 = Merge2(t2, f2);
    146   Node* m1 = Merge2(t1, m2);
    147   ComputeEquivalence(m1);
    148 
    149   ASSERT_EQUIVALENCE(b1, m1, start);
    150   ASSERT_EQUIVALENCE(t1);
    151   ASSERT_EQUIVALENCE(f1, b2, m2);
    152   ASSERT_EQUIVALENCE(t2);
    153   ASSERT_EQUIVALENCE(f2);
    154 }
    155 
    156 
    157 TEST_F(ControlEquivalenceTest, Diamond3) {
    158   Node* start = graph()->start();
    159   Node* b1 = Branch(start);
    160   Node* t1 = IfTrue(b1);
    161   Node* f1 = IfFalse(b1);
    162   Node* m1 = Merge2(t1, f1);
    163   Node* b2 = Branch(m1);
    164   Node* t2 = IfTrue(b2);
    165   Node* f2 = IfFalse(b2);
    166   Node* m2 = Merge2(t2, f2);
    167   ComputeEquivalence(m2);
    168 
    169   ASSERT_EQUIVALENCE(b1, m1, b2, m2, start);
    170   ASSERT_EQUIVALENCE(t1);
    171   ASSERT_EQUIVALENCE(f1);
    172   ASSERT_EQUIVALENCE(t2);
    173   ASSERT_EQUIVALENCE(f2);
    174 }
    175 
    176 
    177 TEST_F(ControlEquivalenceTest, Switch1) {
    178   Node* start = graph()->start();
    179   Node* b1 = Branch(start);
    180   Node* t1 = IfTrue(b1);
    181   Node* f1 = IfFalse(b1);
    182   Node* b2 = Branch(f1);
    183   Node* t2 = IfTrue(b2);
    184   Node* f2 = IfFalse(b2);
    185   Node* b3 = Branch(f2);
    186   Node* t3 = IfTrue(b3);
    187   Node* f3 = IfFalse(b3);
    188   Node* m1 = Merge2(t1, t2);
    189   Node* m2 = Merge2(m1, t3);
    190   Node* m3 = Merge2(m2, f3);
    191   ComputeEquivalence(m3);
    192 
    193   ASSERT_EQUIVALENCE(b1, m3, start);
    194   ASSERT_EQUIVALENCE(t1);
    195   ASSERT_EQUIVALENCE(f1, b2);
    196   ASSERT_EQUIVALENCE(t2);
    197   ASSERT_EQUIVALENCE(f2, b3);
    198   ASSERT_EQUIVALENCE(t3);
    199   ASSERT_EQUIVALENCE(f3);
    200   ASSERT_EQUIVALENCE(m1);
    201   ASSERT_EQUIVALENCE(m2);
    202 }
    203 
    204 
    205 TEST_F(ControlEquivalenceTest, Loop1) {
    206   Node* start = graph()->start();
    207   Node* l = Loop2(start);
    208   l->ReplaceInput(1, l);
    209   ComputeEquivalence(l);
    210 
    211   ASSERT_EQUIVALENCE(start);
    212   ASSERT_EQUIVALENCE(l);
    213 }
    214 
    215 
    216 TEST_F(ControlEquivalenceTest, Loop2) {
    217   Node* start = graph()->start();
    218   Node* l = Loop2(start);
    219   Node* b = Branch(l);
    220   Node* t = IfTrue(b);
    221   Node* f = IfFalse(b);
    222   l->ReplaceInput(1, t);
    223   ComputeEquivalence(f);
    224 
    225   ASSERT_EQUIVALENCE(f, start);
    226   ASSERT_EQUIVALENCE(t);
    227   ASSERT_EQUIVALENCE(l, b);
    228 }
    229 
    230 
    231 TEST_F(ControlEquivalenceTest, Irreducible) {
    232   Node* start = graph()->start();
    233   Node* b1 = Branch(start);
    234   Node* t1 = IfTrue(b1);
    235   Node* f1 = IfFalse(b1);
    236   Node* lp = Loop2(f1);
    237   Node* m1 = Merge2(t1, lp);
    238   Node* b2 = Branch(m1);
    239   Node* t2 = IfTrue(b2);
    240   Node* f2 = IfFalse(b2);
    241   Node* m2 = Merge2(t2, f2);
    242   Node* b3 = Branch(m2);
    243   Node* t3 = IfTrue(b3);
    244   Node* f3 = IfFalse(b3);
    245   lp->ReplaceInput(1, f3);
    246   ComputeEquivalence(t3);
    247 
    248   ASSERT_EQUIVALENCE(b1, t3, start);
    249   ASSERT_EQUIVALENCE(t1);
    250   ASSERT_EQUIVALENCE(f1);
    251   ASSERT_EQUIVALENCE(m1, b2, m2, b3);
    252   ASSERT_EQUIVALENCE(t2);
    253   ASSERT_EQUIVALENCE(f2);
    254   ASSERT_EQUIVALENCE(f3);
    255   ASSERT_EQUIVALENCE(lp);
    256 }
    257 
    258 
    259 }  // namespace compiler
    260 }  // namespace internal
    261 }  // namespace v8
    262