Changeset 232075 in webkit for trunk/Source/JavaScriptCore/dfg/DFGLICMPhase.cpp
- Timestamp:
- May 22, 2018, 12:47:39 PM (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/dfg/DFGLICMPhase.cpp
r232000 r232075 211 211 for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { 212 212 Node*& nodeRef = block->at(nodeIndex); 213 if (doesWrites(m_graph, nodeRef)) {214 if (verbose)215 dataLog(" Not hoisting ", nodeRef, " because it writes things.\n");216 continue;217 }218 219 213 for (unsigned stackIndex = loopStack.size(); stackIndex--;) 220 214 changed |= attemptHoist(block, nodeRef, loopStack[stackIndex]); … … 243 237 } 244 238 239 m_state.initializeTo(data.preHeader); 240 NodeOrigin originalOrigin = node->origin; 241 bool canSpeculateBlindly = !m_graph.hasGlobalExitSite(originalOrigin.semantic, HoistingFailed); 242 243 // NOTE: We could just use BackwardsDominators here directly, since we already know that the 244 // preHeader dominates fromBlock. But we wouldn't get anything from being so clever, since 245 // dominance checks are O(1) and only a few integer compares. 246 bool isControlEquivalent = m_graph.m_controlEquivalenceAnalysis->dominatesEquivalently(data.preHeader, fromBlock); 247 248 bool addsBlindSpeculation = !isControlEquivalent; 249 NodeOrigin terminalOrigin = data.preHeader->terminal()->origin; 250 Vector<Node*, 2> hoistedNodes; // This is sorted in the program order they will appear in the basic block we're hoisting to. 251 252 auto insertHoistedNode = [&] (Node* node) { 253 data.preHeader->insertBeforeTerminal(node); 254 node->owner = data.preHeader; 255 node->origin = terminalOrigin.withSemantic(node->origin.semantic); 256 node->origin.wasHoisted |= addsBlindSpeculation; 257 hoistedNodes.append(node); 258 }; 259 260 auto updateAbstractState = [&] { 261 // We can trust what AI proves about edge proof statuses when hoisting to the preheader. 262 m_state.trustEdgeProofs(); 263 for (unsigned i = 0; i < hoistedNodes.size(); ++i) 264 m_interpreter.execute(hoistedNodes[i]); 265 // However, when walking various inner loops below, the proof status of 266 // an edge may be trivially true, even if it's not true in the preheader 267 // we hoist to. We don't allow the below node executions to change the 268 // state of edge proofs. An example of where a proof is trivially true 269 // is if we have two loops, L1 and L2, where L2 is nested inside L1. The 270 // header for L1 dominates L2. We hoist a Check from L1's header into L1's 271 // preheader. However, inside L2's preheader, we can't trust that AI will 272 // tell us this edge is proven. It's proven in L2's preheader because L2 273 // is dominated by L1's header. However, the edge is not guaranteed to be 274 // proven inside L1's preheader. 275 m_state.dontTrustEdgeProofs(); 276 277 // Modify the states at the end of the preHeader of the loop we hoisted to, 278 // and all pre-headers inside the loop. This isn't a stability bottleneck right now 279 // because most loops are small and most blocks belong to few loops. 280 for (unsigned bodyIndex = loop->size(); bodyIndex--;) { 281 BasicBlock* subBlock = loop->at(bodyIndex); 282 const NaturalLoop* subLoop = m_graph.m_ssaNaturalLoops->headerOf(subBlock); 283 if (!subLoop) 284 continue; 285 BasicBlock* subPreHeader = m_data[subLoop->index()].preHeader; 286 // We may not have given this loop a pre-header because either it didn't have exitOK 287 // or the header had multiple predecessors that it did not dominate. In that case the 288 // loop wouldn't be a hoisting candidate anyway, so we don't have to do anything. 289 if (!subPreHeader) 290 continue; 291 // The pre-header's tail may be unreachable, in which case we have nothing to do. 292 if (!subPreHeader->cfaDidFinish) 293 continue; 294 // We handled this above. 295 if (subPreHeader == data.preHeader) 296 continue; 297 m_state.initializeTo(subPreHeader); 298 for (unsigned i = 0; i < hoistedNodes.size(); ++i) 299 m_interpreter.execute(hoistedNodes[i]); 300 } 301 }; 302 303 auto tryHoistChecks = [&] { 304 if (addsBlindSpeculation && !canSpeculateBlindly) 305 return false; 306 307 ASSERT(hoistedNodes.isEmpty()); 308 309 Vector<Edge, 3> checks; 310 m_graph.doToChildren(node, [&] (Edge edge) { 311 if (!m_graph.m_ssaDominators->dominates(edge.node()->owner, data.preHeader)) 312 return; 313 314 if (!edge.willHaveCheck()) 315 return; 316 317 if ((m_state.forNode(edge).m_type & SpecEmpty) && checkMayCrashIfInputIsEmpty(edge.useKind())) { 318 if (!canSpeculateBlindly) 319 return; 320 Node* checkNotEmpty = m_graph.addNode(CheckNotEmpty, originalOrigin, Edge(edge.node(), UntypedUse)); 321 insertHoistedNode(checkNotEmpty); 322 } 323 324 checks.append(edge); 325 }); 326 327 if (checks.isEmpty()) 328 return false; 329 330 AdjacencyList children; 331 NodeType checkOp = Check; 332 if (checks.size() <= AdjacencyList::Size) { 333 children = AdjacencyList(AdjacencyList::Fixed); 334 for (unsigned i = 0; i < checks.size(); ++i) 335 children.setChild(i, checks[i]); 336 } else { 337 checkOp = CheckVarargs; 338 unsigned firstChild = m_graph.m_varArgChildren.size(); 339 for (Edge edge : checks) 340 m_graph.m_varArgChildren.append(edge); 341 children = AdjacencyList(AdjacencyList::Variable, firstChild, checks.size()); 342 } 343 344 Node* check = m_graph.addNode(checkOp, originalOrigin, children); 345 insertHoistedNode(check); 346 updateAbstractState(); 347 348 if (verbose) 349 dataLogLn(" Hoisted some checks from ", node, " and created a new Check ", check, ". Hoisted from ", *fromBlock, " to ", *data.preHeader); 350 351 return true; 352 }; 353 245 354 if (!edgesDominate(m_graph, node, data.preHeader)) { 246 355 if (verbose) { … … 248 357 " Not hoisting ", node, " because it isn't loop invariant.\n"); 249 358 } 250 return false; 251 } 252 253 // FIXME: At this point if the hoisting of the full node fails but the node has type checks, 254 // we could still hoist just the checks. 255 // https://bugs.webkit.org/show_bug.cgi?id=144525 256 359 return tryHoistChecks(); 360 } 361 362 if (doesWrites(m_graph, node)) { 363 if (verbose) 364 dataLog(" Not hoisting ", node, " because it writes things.\n"); 365 return tryHoistChecks(); 366 } 367 368 // It's not safe to consult the AbstractState inside mayExit until we prove all edges 369 // dominate the pre-header we're hoisting to. We are more conservative above when assigning 370 // to this variable since we hadn't yet proven all edges dominate the pre-header. Above, we 371 // just assume mayExit is true. We refine that here since we can now consult the AbstractState. 372 addsBlindSpeculation = mayExit(m_graph, node, m_state) && !isControlEquivalent; 373 257 374 if (readsOverlap(m_graph, node, data.writes)) { 258 375 if (verbose) { … … 261 378 " because it reads things that the loop writes.\n"); 262 379 } 263 return false; 264 } 265 266 m_state.initializeTo(data.preHeader); 267 268 NodeOrigin originalOrigin = node->origin; 269 bool canSpeculateBlindly = !m_graph.hasGlobalExitSite(originalOrigin.semantic, HoistingFailed); 270 271 // NOTE: We could just use BackwardsDominators here directly, since we already know that the 272 // preHeader dominates fromBlock. But we wouldn't get anything from being so clever, since 273 // dominance checks are O(1) and only a few integer compares. 274 bool addsBlindSpeculation = mayExit(m_graph, node, m_state) 275 && !m_graph.m_controlEquivalenceAnalysis->dominatesEquivalently(data.preHeader, fromBlock); 380 return tryHoistChecks(); 381 } 276 382 277 383 if (addsBlindSpeculation && !canSpeculateBlindly) { … … 282 388 *fromBlock, ") and hoisting had previously failed.\n"); 283 389 } 284 return false; 285 } 286 287 // For abstract interpretation, these are in the reverse order that they appear in this 288 // vector. 289 Vector<Node*, 2> hoistedNodesReverse; 290 hoistedNodesReverse.append(node); 291 292 NodeOrigin terminalOrigin = data.preHeader->terminal()->origin; 293 294 auto insertHoistedNode = [&] (Node* node) { 295 data.preHeader->insertBeforeTerminal(node); 296 node->owner = data.preHeader; 297 node->origin = terminalOrigin.withSemantic(node->origin.semantic); 298 node->origin.wasHoisted |= addsBlindSpeculation; 299 }; 390 return tryHoistChecks(); 391 } 300 392 301 393 if (!safeToExecute(m_state, m_graph, node)) { … … 316 408 Node* check = m_graph.addNode(CheckNotEmpty, originalOrigin, Edge(edge.node(), UntypedUse)); 317 409 insertHoistedNode(check); 318 hoistedNodesReverse.append(check);319 410 }); 320 411 } else { … … 323 414 " Not hoisting ", node, " because it isn't safe to execute.\n"); 324 415 } 325 return false;416 return tryHoistChecks(); 326 417 } 327 418 } … … 334 425 335 426 insertHoistedNode(node); 336 337 // We can trust what AI proves about edge proof statuses when hoisting to the preheader. 338 m_state.trustEdgeProofs(); 339 m_state.initializeTo(data.preHeader); 340 for (unsigned i = hoistedNodesReverse.size(); i--;) 341 m_interpreter.execute(hoistedNodesReverse[i]); 342 // However, when walking various inner loops below, the proof status of 343 // an edge may be trivially true, even if it's not true in the preheader 344 // we hoist to. We don't allow the below node executions to change the 345 // state of edge proofs. An example of where a proof is trivially true 346 // is if we have two loops, L1 and L2, where L2 is nested inside L1. The 347 // header for L1 dominates L2. We hoist a Check from L1's header into L1's 348 // preheader. However, inside L2's preheader, we can't trust that AI will 349 // tell us this edge is proven. It's proven in L2's preheader because L2 350 // is dominated by L1's header. However, the edge is not guaranteed to be 351 // proven inside L1's preheader. 352 m_state.dontTrustEdgeProofs(); 353 354 // Modify the states at the end of the preHeader of the loop we hoisted to, 355 // and all pre-headers inside the loop. This isn't a stability bottleneck right now 356 // because most loops are small and most blocks belong to few loops. 357 for (unsigned bodyIndex = loop->size(); bodyIndex--;) { 358 BasicBlock* subBlock = loop->at(bodyIndex); 359 const NaturalLoop* subLoop = m_graph.m_ssaNaturalLoops->headerOf(subBlock); 360 if (!subLoop) 361 continue; 362 BasicBlock* subPreHeader = m_data[subLoop->index()].preHeader; 363 // We may not have given this loop a pre-header because either it didn't have exitOK 364 // or the header had multiple predecessors that it did not dominate. In that case the 365 // loop wouldn't be a hoisting candidate anyway, so we don't have to do anything. 366 if (!subPreHeader) 367 continue; 368 // The pre-header's tail may be unreachable, in which case we have nothing to do. 369 if (!subPreHeader->cfaDidFinish) 370 continue; 371 // We handled this above. 372 if (subPreHeader == data.preHeader) 373 continue; 374 m_state.initializeTo(subPreHeader); 375 for (unsigned i = hoistedNodesReverse.size(); i--;) 376 m_interpreter.execute(hoistedNodesReverse[i]); 377 } 427 updateAbstractState(); 378 428 379 429 if (node->flags() & NodeHasVarArgs)
Note:
See TracChangeset
for help on using the changeset viewer.