@@ -804,6 +804,97 @@ void DataflowState::init() {
804804 }
805805}
806806
807+ // Returns true if we emitted a diagnostic and handled the single block
808+ // case. Returns false if we visited all of the uses and seeded the UseState
809+ // struct with the information needed to perform our interprocedural dataflow.
810+ static bool performSingleBasicBlockAnalysis (DataflowState &dataflowState,
811+ SILValue address,
812+ MarkUnresolvedMoveAddrInst *mvi) {
813+ // First scan downwards to make sure we are move out of this block.
814+ auto &useState = dataflowState.useState ;
815+ SILInstruction *interestingUser = nullptr ;
816+ switch (downwardScanForMoveOut (mvi, useState, &interestingUser)) {
817+ case DownwardScanResult::Invalid:
818+ llvm_unreachable (" invalid" );
819+ case DownwardScanResult::Destroy: {
820+ // If we found a destroy, then we found a single block case that we can
821+ // handle. Remove the destroy and convert the mark_unresolved_move_addr
822+ // into a true move.
823+ auto *dvi = cast<DestroyAddrInst>(interestingUser);
824+ SILBuilderWithScope builder (mvi);
825+ builder.createCopyAddr (mvi->getLoc (), mvi->getSrc (), mvi->getDest (), IsTake,
826+ IsInitialization);
827+ useState.destroys .erase (dvi);
828+ mvi->eraseFromParent ();
829+ dvi->eraseFromParent ();
830+ return false ;
831+ }
832+ case DownwardScanResult::UseForDiagnostic: {
833+ // Then check if we found a user that violated our dataflow rules. In such
834+ // a case, emit an error, cleanup our mark_unresolved_move_addr, and
835+ // finally continue.
836+ auto &astCtx = mvi->getFunction ()->getASTContext ();
837+ {
838+ auto diag =
839+ diag::sil_movekillscopyablevalue_value_consumed_more_than_once;
840+ StringRef name = getDebugVarName (address);
841+ diagnose (astCtx, getSourceLocFromValue (address), diag, name);
842+ }
843+
844+ {
845+ auto diag = diag::sil_movekillscopyablevalue_move_here;
846+ diagnose (astCtx, mvi->getLoc ().getSourceLoc (), diag);
847+ }
848+
849+ {
850+ auto diag = diag::sil_movekillscopyablevalue_use_here;
851+ diagnose (astCtx, interestingUser->getLoc ().getSourceLoc (), diag);
852+ }
853+
854+ // We purposely continue to see if at least in simple cases, we can flag
855+ // mistakes from other moves. Since we are setting emittedDiagnostic to
856+ // true, we will not perform the actual dataflow due to a check after
857+ // the loop.
858+ //
859+ // We also clean up mvi by converting it to a copy_addr init so we do not
860+ // emit fail errors later.
861+ //
862+ // TODO: Can we handle multiple errors in the same block for a single
863+ // move?
864+ SILBuilderWithScope builder (mvi);
865+ builder.createCopyAddr (mvi->getLoc (), mvi->getSrc (), mvi->getDest (),
866+ IsNotTake, IsInitialization);
867+ mvi->eraseFromParent ();
868+ return true ;
869+ }
870+ case DownwardScanResult::Reinit: {
871+ convertMemoryReinitToInitForm (interestingUser);
872+ useState.reinits .erase (interestingUser);
873+ SILBuilderWithScope builder (mvi);
874+ builder.createCopyAddr (mvi->getLoc (), mvi->getSrc (), mvi->getDest (), IsTake,
875+ IsInitialization);
876+ mvi->eraseFromParent ();
877+ return false ;
878+ }
879+ case DownwardScanResult::MoveOut:
880+ break ;
881+ }
882+
883+ // If we did not found any uses later in the block that was an interesting
884+ // use, we need to perform dataflow.
885+ LLVM_DEBUG (llvm::dbgs () << " Our move is live out, so we need to process "
886+ " it with the dataflow.\n " );
887+ dataflowState.markMovesToDataflow .emplace_back (mvi);
888+
889+ // Now scan up to see if mvi is also a use to seed the dataflow. This could
890+ // happen if we have an earlier move.
891+ if (upwardScanForUseOut (mvi, dataflowState.useState )) {
892+ LLVM_DEBUG (llvm::dbgs () << " MVI projects a use up" );
893+ dataflowState.useBlocks [mvi->getParent ()] = mvi;
894+ }
895+ return false ;
896+ }
897+
807898// ===----------------------------------------------------------------------===//
808899// Address Checker
809900// ===----------------------------------------------------------------------===//
@@ -817,7 +908,6 @@ struct MoveKillsCopyableAddressesObjectChecker {
817908
818909 MoveKillsCopyableAddressesObjectChecker (SILFunction *fn)
819910 : fn(fn), useState(), dataflowState(useState) {}
820- bool performSingleBasicBlockAnalysisForAllMarkMoves (SILValue address);
821911
822912 bool check (SILValue address);
823913
@@ -829,102 +919,6 @@ struct MoveKillsCopyableAddressesObjectChecker {
829919
830920} // namespace
831921
832- // Returns true if we emitted a diagnostic and handled the single block
833- // case. Returns false if we visited all of the uses and seeded the UseState
834- // struct with the information needed to perform our interprocedural dataflow.
835- bool MoveKillsCopyableAddressesObjectChecker::
836- performSingleBasicBlockAnalysisForAllMarkMoves (SILValue address) {
837- bool didEmitSingleBlockDiagnostic = false ;
838- for (auto *mvi : useState.markMoves ) {
839- // First scan downwards to make sure we are move out of this block.
840-
841- SILInstruction *interestingUser = nullptr ;
842- switch (downwardScanForMoveOut (mvi, useState, &interestingUser)) {
843- case DownwardScanResult::Invalid:
844- llvm_unreachable (" invalid" );
845- case DownwardScanResult::Destroy: {
846- // If we found a destroy, then we found a single block case that we can
847- // handle. Remove the destroy and convert the mark_unresolved_move_addr
848- // into a true move.
849- auto *dvi = cast<DestroyAddrInst>(interestingUser);
850- SILBuilderWithScope builder (mvi);
851- builder.createCopyAddr (mvi->getLoc (), mvi->getSrc (), mvi->getDest (),
852- IsTake, IsInitialization);
853- useState.destroys .erase (dvi);
854- mvi->eraseFromParent ();
855- dvi->eraseFromParent ();
856- continue ;
857- }
858- case DownwardScanResult::UseForDiagnostic: {
859- // Then check if we found a user that violated our dataflow rules. In such
860- // a case, emit an error, cleanup our mark_unresolved_move_addr, and
861- // finally continue.
862- didEmitSingleBlockDiagnostic = true ;
863-
864- {
865- auto diag =
866- diag::sil_movekillscopyablevalue_value_consumed_more_than_once;
867- StringRef name = getDebugVarName (address);
868- diagnose (getASTContext (), getSourceLocFromValue (address), diag, name);
869- }
870-
871- {
872- auto diag = diag::sil_movekillscopyablevalue_move_here;
873- diagnose (getASTContext (), mvi->getLoc ().getSourceLoc (), diag);
874- }
875-
876- {
877- auto diag = diag::sil_movekillscopyablevalue_use_here;
878- diagnose (getASTContext (), interestingUser->getLoc ().getSourceLoc (),
879- diag);
880- }
881-
882- // We purposely continue to see if at least in simple cases, we can flag
883- // mistakes from other moves. Since we are setting emittedDiagnostic to
884- // true, we will not perform the actual dataflow due to a check after
885- // the loop.
886- //
887- // We also clean up mvi by converting it to a copy_addr init so we do not
888- // emit fail errors later.
889- //
890- // TODO: Can we handle multiple errors in the same block for a single
891- // move?
892- SILBuilderWithScope builder (mvi);
893- builder.createCopyAddr (mvi->getLoc (), mvi->getSrc (), mvi->getDest (),
894- IsNotTake, IsInitialization);
895- mvi->eraseFromParent ();
896- continue ;
897- }
898- case DownwardScanResult::Reinit: {
899- convertMemoryReinitToInitForm (interestingUser);
900- useState.reinits .erase (interestingUser);
901- SILBuilderWithScope builder (mvi);
902- builder.createCopyAddr (mvi->getLoc (), mvi->getSrc (), mvi->getDest (),
903- IsTake, IsInitialization);
904- mvi->eraseFromParent ();
905- continue ;
906- }
907- case DownwardScanResult::MoveOut:
908- break ;
909- }
910-
911- // If we did not found any uses later in the block that was an interesting
912- // use, we need to perform dataflow.
913- LLVM_DEBUG (llvm::dbgs () << " Our move is live out, so we need to process "
914- " it with the dataflow.\n " );
915- dataflowState.markMovesToDataflow .emplace_back (mvi);
916-
917- // Now scan up to see if mvi is also a use to seed the dataflow. This could
918- // happen if we have an earlier move.
919- if (upwardScanForUseOut (mvi, useState)) {
920- LLVM_DEBUG (llvm::dbgs () << " MVI projects a use up" );
921- dataflowState.useBlocks [mvi->getParent ()] = mvi;
922- }
923- }
924-
925- return didEmitSingleBlockDiagnostic;
926- }
927-
928922bool MoveKillsCopyableAddressesObjectChecker::check (SILValue address) {
929923 auto accessPathWithBase = AccessPathWithBase::compute (address);
930924 auto accessPath = accessPathWithBase.accessPath ;
@@ -968,7 +962,12 @@ bool MoveKillsCopyableAddressesObjectChecker::check(SILValue address) {
968962 // mark_move that propagates its state out of the current block, this
969963 // routine also prepares the pass for running the multi-basic block
970964 // diagnostic.
971- if (performSingleBasicBlockAnalysisForAllMarkMoves (address)) {
965+ bool emittedSingleBBDiagnostic = false ;
966+ for (auto *mvi : useState.markMoves ) {
967+ emittedSingleBBDiagnostic |=
968+ performSingleBasicBlockAnalysis (dataflowState, address, mvi);
969+ }
970+ if (emittedSingleBBDiagnostic) {
972971 LLVM_DEBUG (llvm::dbgs () << " Performed single block analysis!\n " );
973972 return true ;
974973 }
0 commit comments