1 // Copyright 2015 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/compiler/common-operator.h" 6 #include "src/compiler/dead-code-elimination.h" 7 #include "test/unittests/compiler/graph-reducer-unittest.h" 8 #include "test/unittests/compiler/graph-unittest.h" 9 #include "test/unittests/compiler/node-test-utils.h" 10 #include "testing/gmock-support.h" 11 12 using testing::StrictMock; 13 14 namespace v8 { 15 namespace internal { 16 namespace compiler { 17 18 class DeadCodeEliminationTest : public GraphTest { 19 public: 20 explicit DeadCodeEliminationTest(int num_parameters = 4) 21 : GraphTest(num_parameters) {} 22 ~DeadCodeEliminationTest() override {} 23 24 protected: 25 Reduction Reduce(AdvancedReducer::Editor* editor, Node* node) { 26 DeadCodeElimination reducer(editor, graph(), common()); 27 return reducer.Reduce(node); 28 } 29 30 Reduction Reduce(Node* node) { 31 StrictMock<MockAdvancedReducerEditor> editor; 32 return Reduce(&editor, node); 33 } 34 }; 35 36 37 namespace { 38 39 const MachineRepresentation kMachineRepresentations[] = { 40 MachineRepresentation::kBit, MachineRepresentation::kWord8, 41 MachineRepresentation::kWord16, MachineRepresentation::kWord32, 42 MachineRepresentation::kWord64, MachineRepresentation::kFloat32, 43 MachineRepresentation::kFloat64, MachineRepresentation::kTagged}; 44 45 46 const int kMaxInputs = 16; 47 48 49 const Operator kOp0(0, Operator::kNoProperties, "Op0", 1, 1, 1, 1, 1, 1); 50 51 } // namespace 52 53 54 // ----------------------------------------------------------------------------- 55 // General dead propagation 56 57 58 TEST_F(DeadCodeEliminationTest, GeneralDeadPropagation) { 59 Node* const value = Parameter(0); 60 Node* const effect = graph()->start(); 61 Node* const dead = graph()->NewNode(common()->Dead()); 62 Node* const node = graph()->NewNode(&kOp0, value, effect, dead); 63 Reduction const r = Reduce(node); 64 ASSERT_TRUE(r.Changed()); 65 EXPECT_THAT(r.replacement(), IsDead()); 66 } 67 68 69 // ----------------------------------------------------------------------------- 70 // Branch 71 72 73 TEST_F(DeadCodeEliminationTest, BranchWithDeadControlInput) { 74 BranchHint const kHints[] = {BranchHint::kNone, BranchHint::kTrue, 75 BranchHint::kFalse}; 76 TRACED_FOREACH(BranchHint, hint, kHints) { 77 Reduction const r = 78 Reduce(graph()->NewNode(common()->Branch(hint), Parameter(0), 79 graph()->NewNode(common()->Dead()))); 80 ASSERT_TRUE(r.Changed()); 81 EXPECT_THAT(r.replacement(), IsDead()); 82 } 83 } 84 85 86 // ----------------------------------------------------------------------------- 87 // IfTrue 88 89 90 TEST_F(DeadCodeEliminationTest, IfTrueWithDeadInput) { 91 Reduction const r = Reduce( 92 graph()->NewNode(common()->IfTrue(), graph()->NewNode(common()->Dead()))); 93 ASSERT_TRUE(r.Changed()); 94 EXPECT_THAT(r.replacement(), IsDead()); 95 } 96 97 98 // ----------------------------------------------------------------------------- 99 // IfFalse 100 101 102 TEST_F(DeadCodeEliminationTest, IfFalseWithDeadInput) { 103 Reduction const r = Reduce(graph()->NewNode( 104 common()->IfFalse(), graph()->NewNode(common()->Dead()))); 105 ASSERT_TRUE(r.Changed()); 106 EXPECT_THAT(r.replacement(), IsDead()); 107 } 108 109 110 // ----------------------------------------------------------------------------- 111 // IfSuccess 112 113 114 TEST_F(DeadCodeEliminationTest, IfSuccessWithDeadInput) { 115 Reduction const r = Reduce(graph()->NewNode( 116 common()->IfSuccess(), graph()->NewNode(common()->Dead()))); 117 ASSERT_TRUE(r.Changed()); 118 EXPECT_THAT(r.replacement(), IsDead()); 119 } 120 121 122 // ----------------------------------------------------------------------------- 123 // IfException 124 125 126 TEST_F(DeadCodeEliminationTest, IfExceptionWithDeadControlInput) { 127 IfExceptionHint const kHints[] = {IfExceptionHint::kLocallyCaught, 128 IfExceptionHint::kLocallyUncaught}; 129 TRACED_FOREACH(IfExceptionHint, hint, kHints) { 130 Reduction const r = 131 Reduce(graph()->NewNode(common()->IfException(hint), graph()->start(), 132 graph()->NewNode(common()->Dead()))); 133 ASSERT_TRUE(r.Changed()); 134 EXPECT_THAT(r.replacement(), IsDead()); 135 } 136 } 137 138 139 // ----------------------------------------------------------------------------- 140 // End 141 142 143 TEST_F(DeadCodeEliminationTest, EndWithDeadAndStart) { 144 Node* const dead = graph()->NewNode(common()->Dead()); 145 Node* const start = graph()->start(); 146 Reduction const r = Reduce(graph()->NewNode(common()->End(2), dead, start)); 147 ASSERT_TRUE(r.Changed()); 148 EXPECT_THAT(r.replacement(), IsEnd(start)); 149 } 150 151 152 TEST_F(DeadCodeEliminationTest, EndWithOnlyDeadInputs) { 153 Node* inputs[kMaxInputs]; 154 TRACED_FORRANGE(int, input_count, 1, kMaxInputs - 1) { 155 for (int i = 0; i < input_count; ++i) { 156 inputs[i] = graph()->NewNode(common()->Dead()); 157 } 158 Reduction const r = Reduce( 159 graph()->NewNode(common()->End(input_count), input_count, inputs)); 160 ASSERT_TRUE(r.Changed()); 161 EXPECT_THAT(r.replacement(), IsDead()); 162 } 163 } 164 165 166 // ----------------------------------------------------------------------------- 167 // Merge 168 169 170 TEST_F(DeadCodeEliminationTest, MergeWithOnlyDeadInputs) { 171 Node* inputs[kMaxInputs + 1]; 172 TRACED_FORRANGE(int, input_count, 1, kMaxInputs - 1) { 173 for (int i = 0; i < input_count; ++i) { 174 inputs[i] = graph()->NewNode(common()->Dead()); 175 } 176 Reduction const r = Reduce( 177 graph()->NewNode(common()->Merge(input_count), input_count, inputs)); 178 ASSERT_TRUE(r.Changed()); 179 EXPECT_THAT(r.replacement(), IsDead()); 180 } 181 } 182 183 184 TEST_F(DeadCodeEliminationTest, MergeWithOneLiveAndOneDeadInput) { 185 Node* const v0 = Parameter(0); 186 Node* const v1 = Parameter(1); 187 Node* const c0 = 188 graph()->NewNode(&kOp0, v0, graph()->start(), graph()->start()); 189 Node* const c1 = graph()->NewNode(common()->Dead()); 190 Node* const e0 = graph()->NewNode(&kOp0, v0, graph()->start(), c0); 191 Node* const e1 = graph()->NewNode(&kOp0, v1, graph()->start(), c1); 192 Node* const merge = graph()->NewNode(common()->Merge(2), c0, c1); 193 Node* const phi = graph()->NewNode( 194 common()->Phi(MachineRepresentation::kTagged, 2), v0, v1, merge); 195 Node* const ephi = graph()->NewNode(common()->EffectPhi(2), e0, e1, merge); 196 StrictMock<MockAdvancedReducerEditor> editor; 197 EXPECT_CALL(editor, Replace(phi, v0)); 198 EXPECT_CALL(editor, Replace(ephi, e0)); 199 Reduction const r = Reduce(&editor, merge); 200 ASSERT_TRUE(r.Changed()); 201 EXPECT_EQ(c0, r.replacement()); 202 } 203 204 205 TEST_F(DeadCodeEliminationTest, MergeWithTwoLiveAndTwoDeadInputs) { 206 Node* const v0 = Parameter(0); 207 Node* const v1 = Parameter(1); 208 Node* const v2 = Parameter(2); 209 Node* const v3 = Parameter(3); 210 Node* const c0 = 211 graph()->NewNode(&kOp0, v0, graph()->start(), graph()->start()); 212 Node* const c1 = graph()->NewNode(common()->Dead()); 213 Node* const c2 = graph()->NewNode(common()->Dead()); 214 Node* const c3 = graph()->NewNode(&kOp0, v3, graph()->start(), c0); 215 Node* const e0 = graph()->start(); 216 Node* const e1 = graph()->NewNode(&kOp0, v1, e0, c0); 217 Node* const e2 = graph()->NewNode(&kOp0, v2, e1, c0); 218 Node* const e3 = graph()->NewNode(&kOp0, v3, graph()->start(), c3); 219 Node* const merge = graph()->NewNode(common()->Merge(4), c0, c1, c2, c3); 220 Node* const phi = graph()->NewNode( 221 common()->Phi(MachineRepresentation::kTagged, 4), v0, v1, v2, v3, merge); 222 Node* const ephi = 223 graph()->NewNode(common()->EffectPhi(4), e0, e1, e2, e3, merge); 224 StrictMock<MockAdvancedReducerEditor> editor; 225 EXPECT_CALL(editor, Revisit(phi)); 226 EXPECT_CALL(editor, Revisit(ephi)); 227 Reduction const r = Reduce(&editor, merge); 228 ASSERT_TRUE(r.Changed()); 229 EXPECT_THAT(r.replacement(), IsMerge(c0, c3)); 230 EXPECT_THAT(phi, 231 IsPhi(MachineRepresentation::kTagged, v0, v3, r.replacement())); 232 EXPECT_THAT(ephi, IsEffectPhi(e0, e3, r.replacement())); 233 } 234 235 236 // ----------------------------------------------------------------------------- 237 // Loop 238 239 240 TEST_F(DeadCodeEliminationTest, LoopWithDeadFirstInput) { 241 Node* inputs[kMaxInputs + 1]; 242 TRACED_FORRANGE(int, input_count, 1, kMaxInputs - 1) { 243 inputs[0] = graph()->NewNode(common()->Dead()); 244 for (int i = 1; i < input_count; ++i) { 245 inputs[i] = graph()->start(); 246 } 247 Reduction const r = Reduce( 248 graph()->NewNode(common()->Loop(input_count), input_count, inputs)); 249 ASSERT_TRUE(r.Changed()); 250 EXPECT_THAT(r.replacement(), IsDead()); 251 } 252 } 253 254 255 TEST_F(DeadCodeEliminationTest, LoopWithOnlyDeadInputs) { 256 Node* inputs[kMaxInputs + 1]; 257 TRACED_FORRANGE(int, input_count, 1, kMaxInputs - 1) { 258 for (int i = 0; i < input_count; ++i) { 259 inputs[i] = graph()->NewNode(common()->Dead()); 260 } 261 Reduction const r = Reduce( 262 graph()->NewNode(common()->Loop(input_count), input_count, inputs)); 263 ASSERT_TRUE(r.Changed()); 264 EXPECT_THAT(r.replacement(), IsDead()); 265 } 266 } 267 268 269 TEST_F(DeadCodeEliminationTest, LoopWithOneLiveAndOneDeadInput) { 270 Node* const v0 = Parameter(0); 271 Node* const v1 = Parameter(1); 272 Node* const c0 = 273 graph()->NewNode(&kOp0, v0, graph()->start(), graph()->start()); 274 Node* const c1 = graph()->NewNode(common()->Dead()); 275 Node* const e0 = graph()->NewNode(&kOp0, v0, graph()->start(), c0); 276 Node* const e1 = graph()->NewNode(&kOp0, v1, graph()->start(), c1); 277 Node* const loop = graph()->NewNode(common()->Loop(2), c0, c1); 278 Node* const phi = graph()->NewNode( 279 common()->Phi(MachineRepresentation::kTagged, 2), v0, v1, loop); 280 Node* const ephi = graph()->NewNode(common()->EffectPhi(2), e0, e1, loop); 281 Node* const terminate = graph()->NewNode(common()->Terminate(), ephi, loop); 282 StrictMock<MockAdvancedReducerEditor> editor; 283 EXPECT_CALL(editor, Replace(phi, v0)); 284 EXPECT_CALL(editor, Replace(ephi, e0)); 285 EXPECT_CALL(editor, Replace(terminate, IsDead())); 286 Reduction const r = Reduce(&editor, loop); 287 ASSERT_TRUE(r.Changed()); 288 EXPECT_EQ(c0, r.replacement()); 289 } 290 291 292 TEST_F(DeadCodeEliminationTest, LoopWithTwoLiveAndTwoDeadInputs) { 293 Node* const v0 = Parameter(0); 294 Node* const v1 = Parameter(1); 295 Node* const v2 = Parameter(2); 296 Node* const v3 = Parameter(3); 297 Node* const c0 = 298 graph()->NewNode(&kOp0, v0, graph()->start(), graph()->start()); 299 Node* const c1 = graph()->NewNode(common()->Dead()); 300 Node* const c2 = graph()->NewNode(common()->Dead()); 301 Node* const c3 = graph()->NewNode(&kOp0, v3, graph()->start(), c0); 302 Node* const e0 = graph()->start(); 303 Node* const e1 = graph()->NewNode(&kOp0, v1, e0, c0); 304 Node* const e2 = graph()->NewNode(&kOp0, v2, e1, c0); 305 Node* const e3 = graph()->NewNode(&kOp0, v3, graph()->start(), c3); 306 Node* const loop = graph()->NewNode(common()->Loop(4), c0, c1, c2, c3); 307 Node* const phi = graph()->NewNode( 308 common()->Phi(MachineRepresentation::kTagged, 4), v0, v1, v2, v3, loop); 309 Node* const ephi = 310 graph()->NewNode(common()->EffectPhi(4), e0, e1, e2, e3, loop); 311 StrictMock<MockAdvancedReducerEditor> editor; 312 EXPECT_CALL(editor, Revisit(phi)); 313 EXPECT_CALL(editor, Revisit(ephi)); 314 Reduction const r = Reduce(&editor, loop); 315 ASSERT_TRUE(r.Changed()); 316 EXPECT_THAT(r.replacement(), IsLoop(c0, c3)); 317 EXPECT_THAT(phi, 318 IsPhi(MachineRepresentation::kTagged, v0, v3, r.replacement())); 319 EXPECT_THAT(ephi, IsEffectPhi(e0, e3, r.replacement())); 320 } 321 322 323 // ----------------------------------------------------------------------------- 324 // Phi 325 326 327 TEST_F(DeadCodeEliminationTest, PhiWithDeadControlInput) { 328 Node* inputs[kMaxInputs + 1]; 329 TRACED_FOREACH(MachineRepresentation, rep, kMachineRepresentations) { 330 TRACED_FORRANGE(int, input_count, 1, kMaxInputs) { 331 for (int i = 0; i < input_count; ++i) { 332 inputs[i] = Parameter(i); 333 } 334 inputs[input_count] = graph()->NewNode(common()->Dead()); 335 Reduction const r = Reduce(graph()->NewNode( 336 common()->Phi(rep, input_count), input_count + 1, inputs)); 337 ASSERT_TRUE(r.Changed()); 338 EXPECT_THAT(r.replacement(), IsDead()); 339 } 340 } 341 } 342 343 344 // ----------------------------------------------------------------------------- 345 // EffectPhi 346 347 348 TEST_F(DeadCodeEliminationTest, EffectPhiWithDeadControlInput) { 349 Node* inputs[kMaxInputs + 1]; 350 TRACED_FORRANGE(int, input_count, 1, kMaxInputs) { 351 for (int i = 0; i < input_count; ++i) { 352 inputs[i] = graph()->start(); 353 } 354 inputs[input_count] = graph()->NewNode(common()->Dead()); 355 Reduction const r = Reduce(graph()->NewNode( 356 common()->EffectPhi(input_count), input_count + 1, inputs)); 357 ASSERT_TRUE(r.Changed()); 358 EXPECT_THAT(r.replacement(), IsDead()); 359 } 360 } 361 362 363 // ----------------------------------------------------------------------------- 364 // Terminate 365 366 367 TEST_F(DeadCodeEliminationTest, TerminateWithDeadControlInput) { 368 Reduction const r = 369 Reduce(graph()->NewNode(common()->Terminate(), graph()->start(), 370 graph()->NewNode(common()->Dead()))); 371 ASSERT_TRUE(r.Changed()); 372 EXPECT_THAT(r.replacement(), IsDead()); 373 } 374 375 } // namespace compiler 376 } // namespace internal 377 } // namespace v8 378