@@ -494,6 +494,64 @@ private module Cached {
494
494
explicitWrite ( false , storeNode .getStoreInstruction ( ) , def )
495
495
)
496
496
or
497
+ // The destination of a store operation has undergone lvalue-to-rvalue conversion and is now a
498
+ // right-hand-side of a store operation.
499
+ // Find the next use of the variable in that store operation, and recursively find the load of that
500
+ // pointer. For example, consider this case:
501
+ //
502
+ // ```cpp
503
+ // int x = source();
504
+ // int* p = &x;
505
+ // sink(*p);
506
+ // ```
507
+ //
508
+ // if we want to find the load of the address of `x`, we see that the pointer is stored into `p`,
509
+ // and we then need to recursively look for the load of `p`.
510
+ exists (
511
+ Def def , StoreInstruction store , IRBlock block1 , int rnk1 , Use use , IRBlock block2 , int rnk2
512
+ |
513
+ store = def .getInstruction ( ) and
514
+ store .getSourceValueOperand ( ) = operand and
515
+ def .hasRankInBlock ( block1 , rnk1 ) and
516
+ use .hasRankInBlock ( block2 , rnk2 ) and
517
+ adjacentDefRead ( _, block1 , rnk1 , block2 , rnk2 )
518
+ |
519
+ // The shared SSA library has determined that `use` is the next use of the operand
520
+ // so we find the next load of that use (but only if there is no `PostUpdateNode`) we
521
+ // need to flow into first.
522
+ not StoreNodeFlow:: flowInto ( store , _) and
523
+ flowOutOfAddressStep ( use .getOperand ( ) , nodeTo )
524
+ or
525
+ // It may also be the case that `store` gives rise to another store step. So let's make sure that
526
+ // we also take those into account.
527
+ StoreNodeFlow:: flowInto ( store , nodeTo )
528
+ )
529
+ or
530
+ // As we find the next load of an address, we might come across another use of the same variable.
531
+ // In that case, we recursively find the next use of _that_ operand, and continue searching for
532
+ // the next load of that operand. For example, consider this case:
533
+ //
534
+ // ```cpp
535
+ // int x = source();
536
+ // use(&x);
537
+ // int* p = &x;
538
+ // sink(*p);
539
+ // ```
540
+ //
541
+ // The next use of `x` after its definition is `use(&x)`, but there is a later load of the address
542
+ // of `x` that we want to flow to. So we use the shared SSA library to find the next load.
543
+ not operand = getSourceAddressOperand ( _) and
544
+ exists ( Use use1 , Use use2 , IRBlock block1 , int rnk1 , IRBlock block2 , int rnk2 |
545
+ use1 .getOperand ( ) = operand and
546
+ use1 .hasRankInBlock ( block1 , rnk1 ) and
547
+ // Don't flow to the next use if this use is part of a store operation that totally
548
+ // overrides a variable.
549
+ not explicitWrite ( true , _, use1 .getOperand ( ) .getDef ( ) ) and
550
+ adjacentDefRead ( _, block1 , rnk1 , block2 , rnk2 ) and
551
+ use2 .hasRankInBlock ( block2 , rnk2 ) and
552
+ flowOutOfAddressStep ( use2 .getOperand ( ) , nodeTo )
553
+ )
554
+ or
497
555
operand = getSourceAddressOperand ( nodeTo .asInstruction ( ) )
498
556
or
499
557
exists ( ReturnIndirectionInstruction ret |
0 commit comments