testJitFoldsTo.cpp (7054B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 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 19 BEGIN_TEST(testJitFoldsTo_DivReciprocal) { 20 MinimalFunc func; 21 MBasicBlock* block = func.createEntryBlock(); 22 23 // return p / 4.0 24 MParameter* p = func.createParameter(); 25 block->add(p); 26 MConstant* c = MConstant::NewDouble(func.alloc, 4.0); 27 block->add(c); 28 MDiv* div = MDiv::New(func.alloc, p, c, MIRType::Double); 29 block->add(div); 30 if (!div->typePolicy()->adjustInputs(func.alloc, div)) { 31 return false; 32 } 33 MDefinition* left = div->getOperand(0); 34 MReturn* ret = MReturn::New(func.alloc, div); 35 block->end(ret); 36 37 if (!func.runGVN()) { 38 return false; 39 } 40 41 // Test that the div got folded to p * 0.25. 42 MDefinition* op = ret->getOperand(0); 43 CHECK(op->isMul()); 44 CHECK(op->getOperand(0) == left); 45 CHECK(op->getOperand(1)->isConstant()); 46 CHECK(op->getOperand(1)->toConstant()->numberToDouble() == 0.25); 47 return true; 48 } 49 END_TEST(testJitFoldsTo_DivReciprocal) 50 51 BEGIN_TEST(testJitFoldsTo_NoDivReciprocal) { 52 MinimalFunc func; 53 MBasicBlock* block = func.createEntryBlock(); 54 55 // return p / 5.0 56 MParameter* p = func.createParameter(); 57 block->add(p); 58 MConstant* c = MConstant::NewDouble(func.alloc, 5.0); 59 block->add(c); 60 MDiv* div = MDiv::New(func.alloc, p, c, MIRType::Double); 61 block->add(div); 62 if (!div->typePolicy()->adjustInputs(func.alloc, div)) { 63 return false; 64 } 65 MDefinition* left = div->getOperand(0); 66 MDefinition* right = div->getOperand(1); 67 MReturn* ret = MReturn::New(func.alloc, div); 68 block->end(ret); 69 70 if (!func.runGVN()) { 71 return false; 72 } 73 74 // Test that the div didn't get folded. 75 MDefinition* op = ret->getOperand(0); 76 CHECK(op->isDiv()); 77 CHECK(op->getOperand(0) == left); 78 CHECK(op->getOperand(1) == right); 79 return true; 80 } 81 END_TEST(testJitFoldsTo_NoDivReciprocal) 82 83 BEGIN_TEST(testJitNotNot) { 84 MinimalFunc func; 85 MBasicBlock* block = func.createEntryBlock(); 86 87 // return Not(Not(p)) 88 MParameter* p = func.createParameter(); 89 block->add(p); 90 MNot* not0 = MNot::New(func.alloc, p); 91 block->add(not0); 92 MNot* not1 = MNot::New(func.alloc, not0); 93 block->add(not1); 94 MReturn* ret = MReturn::New(func.alloc, not1); 95 block->end(ret); 96 97 if (!func.runGVN()) { 98 return false; 99 } 100 101 // Test that the nots did not get folded. 102 MDefinition* op = ret->getOperand(0); 103 CHECK(op->isNot()); 104 CHECK(op->getOperand(0)->isNot()); 105 CHECK(op->getOperand(0)->getOperand(0) == p); 106 return true; 107 } 108 END_TEST(testJitNotNot) 109 110 BEGIN_TEST(testJitNotNotNot) { 111 MinimalFunc func; 112 MBasicBlock* block = func.createEntryBlock(); 113 114 // return Not(Not(Not(p))) 115 MParameter* p = func.createParameter(); 116 block->add(p); 117 MNot* not0 = MNot::New(func.alloc, p); 118 block->add(not0); 119 MNot* not1 = MNot::New(func.alloc, not0); 120 block->add(not1); 121 MNot* not2 = MNot::New(func.alloc, not1); 122 block->add(not2); 123 MReturn* ret = MReturn::New(func.alloc, not2); 124 block->end(ret); 125 126 if (!func.runGVN()) { 127 return false; 128 } 129 130 // Test that the nots got folded. 131 MDefinition* op = ret->getOperand(0); 132 CHECK(op->isNot()); 133 CHECK(op->getOperand(0) == p); 134 return true; 135 } 136 END_TEST(testJitNotNotNot) 137 138 BEGIN_TEST(testJitNotTest) { 139 MinimalFunc func; 140 MBasicBlock* block = func.createEntryBlock(); 141 MBasicBlock* then = func.createBlock(block); 142 MBasicBlock* else_ = func.createBlock(block); 143 MBasicBlock* exit = func.createBlock(block); 144 145 // MTest(Not(p)) 146 MParameter* p = func.createParameter(); 147 block->add(p); 148 MNot* not0 = MNot::New(func.alloc, p); 149 block->add(not0); 150 MTest* test = MTest::New(func.alloc, not0, then, else_); 151 block->end(test); 152 153 then->end(MGoto::New(func.alloc, exit)); 154 155 else_->end(MGoto::New(func.alloc, exit)); 156 157 MReturn* ret = MReturn::New(func.alloc, p); 158 exit->end(ret); 159 160 MOZ_ALWAYS_TRUE(exit->addPredecessorWithoutPhis(then)); 161 162 if (!func.runGVN()) { 163 return false; 164 } 165 166 // Test that the not got folded. 167 test = block->lastIns()->toTest(); 168 CHECK(test->getOperand(0) == p); 169 CHECK(test->getSuccessor(0) == else_); 170 CHECK(test->getSuccessor(1) == then); 171 return true; 172 } 173 END_TEST(testJitNotTest) 174 175 BEGIN_TEST(testJitNotNotTest) { 176 MinimalFunc func; 177 MBasicBlock* block = func.createEntryBlock(); 178 MBasicBlock* then = func.createBlock(block); 179 MBasicBlock* else_ = func.createBlock(block); 180 MBasicBlock* exit = func.createBlock(block); 181 182 // MTest(Not(Not(p))) 183 MParameter* p = func.createParameter(); 184 block->add(p); 185 MNot* not0 = MNot::New(func.alloc, p); 186 block->add(not0); 187 MNot* not1 = MNot::New(func.alloc, not0); 188 block->add(not1); 189 MTest* test = MTest::New(func.alloc, not1, then, else_); 190 block->end(test); 191 192 then->end(MGoto::New(func.alloc, exit)); 193 194 else_->end(MGoto::New(func.alloc, exit)); 195 196 MReturn* ret = MReturn::New(func.alloc, p); 197 exit->end(ret); 198 199 MOZ_ALWAYS_TRUE(exit->addPredecessorWithoutPhis(then)); 200 201 if (!func.runGVN()) { 202 return false; 203 } 204 205 // Test that the nots got folded. 206 test = block->lastIns()->toTest(); 207 CHECK(test->getOperand(0) == p); 208 CHECK(test->getSuccessor(0) == then); 209 CHECK(test->getSuccessor(1) == else_); 210 return true; 211 } 212 END_TEST(testJitNotNotTest) 213 214 BEGIN_TEST(testJitFoldsTo_UnsignedDiv) { 215 MinimalFunc func; 216 MBasicBlock* block = func.createEntryBlock(); 217 218 // return 1.0 / 0xffffffff 219 MConstant* c0 = MConstant::NewInt32(func.alloc, 1); 220 block->add(c0); 221 MConstant* c1 = MConstant::NewInt32(func.alloc, 0xffffffff); 222 block->add(c1); 223 MDiv* div = MDiv::New(func.alloc, c0, c1, MIRType::Int32, /*unsignd=*/true); 224 block->add(div); 225 MReturn* ret = MReturn::New(func.alloc, div); 226 block->end(ret); 227 228 if (!func.runGVN()) { 229 return false; 230 } 231 232 // Test that the div got folded to 0. 233 MConstant* op = ret->getOperand(0)->toConstant(); 234 CHECK(mozilla::NumbersAreIdentical(op->numberToDouble(), 0.0)); 235 return true; 236 } 237 END_TEST(testJitFoldsTo_UnsignedDiv) 238 239 BEGIN_TEST(testJitFoldsTo_UnsignedMod) { 240 MinimalFunc func; 241 MBasicBlock* block = func.createEntryBlock(); 242 243 // return 1.0 % 0xffffffff 244 MConstant* c0 = MConstant::NewInt32(func.alloc, 1); 245 block->add(c0); 246 MConstant* c1 = MConstant::NewInt32(func.alloc, 0xffffffff); 247 block->add(c1); 248 MMod* mod = MMod::New(func.alloc, c0, c1, MIRType::Int32, /*unsignd=*/true); 249 block->add(mod); 250 MReturn* ret = MReturn::New(func.alloc, mod); 251 block->end(ret); 252 253 if (!func.runGVN()) { 254 return false; 255 } 256 257 // Test that the mod got folded to 1. 258 MConstant* op = ret->getOperand(0)->toConstant(); 259 CHECK(mozilla::NumbersAreIdentical(op->numberToDouble(), 1.0)); 260 return true; 261 } 262 END_TEST(testJitFoldsTo_UnsignedMod)