1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=8 sts=4 et sw=4 tw=99:
3  */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 
8 #include "jit/IonAnalysis.h"
9 #include "jit/MIRGenerator.h"
10 #include "jit/MIRGraph.h"
11 #include "jit/ValueNumbering.h"
12 
13 #include "jsapi-tests/testJitMinimalFunc.h"
14 #include "jsapi-tests/tests.h"
15 
16 using namespace js;
17 using namespace js::jit;
18 
BEGIN_TEST(testJitDCEinGVN_ins)19 BEGIN_TEST(testJitDCEinGVN_ins) {
20   MinimalFunc func;
21   MBasicBlock* block = func.createEntryBlock();
22 
23   // mul0 = p * p
24   // mul1 = mul0 * mul0
25   // return p
26   MParameter* p = func.createParameter();
27   block->add(p);
28   MMul* mul0 = MMul::New(func.alloc, p, p, MIRType::Double);
29   block->add(mul0);
30   if (!mul0->typePolicy()->adjustInputs(func.alloc, mul0)) return false;
31   MMul* mul1 = MMul::New(func.alloc, mul0, mul0, MIRType::Double);
32   block->add(mul1);
33   if (!mul1->typePolicy()->adjustInputs(func.alloc, mul1)) return false;
34   MReturn* ret = MReturn::New(func.alloc, p);
35   block->end(ret);
36 
37   if (!func.runGVN()) return false;
38 
39   // mul0 and mul1 should be deleted.
40   for (MInstructionIterator ins = block->begin(); ins != block->end(); ins++) {
41     CHECK(!ins->isMul() ||
42           (ins->getOperand(0) != p && ins->getOperand(1) != p));
43     CHECK(!ins->isMul() ||
44           (ins->getOperand(0) != mul0 && ins->getOperand(1) != mul0));
45   }
46   return true;
47 }
48 END_TEST(testJitDCEinGVN_ins)
49 
BEGIN_TEST(testJitDCEinGVN_phi)50 BEGIN_TEST(testJitDCEinGVN_phi) {
51   MinimalFunc func;
52   MBasicBlock* block = func.createEntryBlock();
53   MBasicBlock* thenBlock1 = func.createBlock(block);
54   MBasicBlock* thenBlock2 = func.createBlock(block);
55   MBasicBlock* elifBlock = func.createBlock(block);
56   MBasicBlock* elseBlock = func.createBlock(block);
57   MBasicBlock* joinBlock = func.createBlock(block);
58 
59   // if (p) {
60   //   x = 1.0;
61   //   y = 3.0;
62   // } else if (q) {
63   //   x = 2.0;
64   //   y = 4.0;
65   // } else {
66   //   x = 1.0;
67   //   y = 5.0;
68   // }
69   // x = phi(1.0, 2.0, 1.0);
70   // y = phi(3.0, 4.0, 5.0);
71   // z = x * y;
72   // return y;
73 
74   MConstant* c1 = MConstant::New(func.alloc, DoubleValue(1.0));
75   block->add(c1);
76   MPhi* x = MPhi::New(func.alloc);
77   MPhi* y = MPhi::New(func.alloc);
78 
79   // if (p) {
80   MParameter* p = func.createParameter();
81   block->add(p);
82   block->end(MTest::New(func.alloc, p, thenBlock1, elifBlock));
83 
84   //   x = 1.0
85   //   y = 3.0;
86   MOZ_RELEASE_ASSERT(x->addInputSlow(c1));
87   MConstant* c3 = MConstant::New(func.alloc, DoubleValue(3.0));
88   thenBlock1->add(c3);
89   MOZ_RELEASE_ASSERT(y->addInputSlow(c3));
90   thenBlock1->end(MGoto::New(func.alloc, joinBlock));
91   MOZ_ALWAYS_TRUE(joinBlock->addPredecessor(func.alloc, thenBlock1));
92 
93   // } else if (q) {
94   MParameter* q = func.createParameter();
95   elifBlock->add(q);
96   elifBlock->end(MTest::New(func.alloc, q, thenBlock2, elseBlock));
97 
98   //   x = 2.0
99   //   y = 4.0;
100   MConstant* c2 = MConstant::New(func.alloc, DoubleValue(2.0));
101   thenBlock2->add(c2);
102   MOZ_RELEASE_ASSERT(x->addInputSlow(c2));
103   MConstant* c4 = MConstant::New(func.alloc, DoubleValue(4.0));
104   thenBlock2->add(c4);
105   MOZ_RELEASE_ASSERT(y->addInputSlow(c4));
106   thenBlock2->end(MGoto::New(func.alloc, joinBlock));
107   MOZ_ALWAYS_TRUE(joinBlock->addPredecessor(func.alloc, thenBlock2));
108 
109   // } else {
110   //   x = 1.0
111   //   y = 5.0;
112   // }
113   MOZ_RELEASE_ASSERT(x->addInputSlow(c1));
114   MConstant* c5 = MConstant::New(func.alloc, DoubleValue(5.0));
115   elseBlock->add(c5);
116   MOZ_RELEASE_ASSERT(y->addInputSlow(c5));
117   elseBlock->end(MGoto::New(func.alloc, joinBlock));
118   MOZ_ALWAYS_TRUE(joinBlock->addPredecessor(func.alloc, elseBlock));
119 
120   // x = phi(1.0, 2.0, 1.0)
121   // y = phi(3.0, 4.0, 5.0)
122   // z = x * y
123   // return y
124   joinBlock->addPhi(x);
125   joinBlock->addPhi(y);
126   MMul* z = MMul::New(func.alloc, x, y, MIRType::Double);
127   joinBlock->add(z);
128   MReturn* ret = MReturn::New(func.alloc, y);
129   joinBlock->end(ret);
130 
131   if (!func.runGVN()) return false;
132 
133   // c1 should be deleted.
134   for (MInstructionIterator ins = block->begin(); ins != block->end(); ins++) {
135     CHECK(!ins->isConstant() || (ins->toConstant()->numberToDouble() != 1.0));
136   }
137   return true;
138 }
139 END_TEST(testJitDCEinGVN_phi)
140