@@ -494,6 +494,64 @@ private module Cached {
494494 explicitWrite ( false , storeNode .getStoreInstruction ( ) , def )
495495 )
496496 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
497555 operand = getSourceAddressOperand ( nodeTo .asInstruction ( ) )
498556 or
499557 exists ( ReturnIndirectionInstruction ret |
0 commit comments