@@ -645,7 +645,8 @@ namespace {
645
645
// / reproducers when a signal is raised, such as a segfault.
646
646
struct RecoveryReproducerContext {
647
647
RecoveryReproducerContext (MutableArrayRef<std::unique_ptr<Pass>> passes,
648
- Operation *op, StringRef filename,
648
+ Operation *op,
649
+ PassManager::ReproducerStreamFactory &crashStream,
649
650
bool disableThreads, bool verifyPasses);
650
651
~RecoveryReproducerContext ();
651
652
@@ -665,8 +666,9 @@ struct RecoveryReproducerContext {
665
666
// / The MLIR operation representing the IR before the crash.
666
667
Operation *preCrashOperation;
667
668
668
- // / The filename to use when generating the reproducer.
669
- StringRef filename;
669
+ // / The factory for the reproducer output stream to use when generating the
670
+ // / reproducer.
671
+ PassManager::ReproducerStreamFactory &crashStreamFactory;
670
672
671
673
// / Various pass manager and context flags.
672
674
bool disableThreads;
@@ -681,6 +683,24 @@ struct RecoveryReproducerContext {
681
683
llvm::SmallSetVector<RecoveryReproducerContext *, 1 >>
682
684
reproducerSet;
683
685
};
686
+
687
+ // / Instance of ReproducerStream backed by file.
688
+ struct FileReproducerStream : public PassManager ::ReproducerStream {
689
+ FileReproducerStream (std::unique_ptr<llvm::ToolOutputFile> outputFile)
690
+ : outputFile(std::move(outputFile)) {}
691
+ ~FileReproducerStream () override ;
692
+
693
+ // / Description of the reproducer stream.
694
+ StringRef description () override ;
695
+
696
+ // / Stream on which to output reprooducer.
697
+ raw_ostream &os () override ;
698
+
699
+ private:
700
+ // / ToolOutputFile corresponding to opened `filename`.
701
+ std::unique_ptr<llvm::ToolOutputFile> outputFile = nullptr ;
702
+ };
703
+
684
704
} // end anonymous namespace
685
705
686
706
llvm::ManagedStatic<llvm::sys::SmartMutex<true >>
@@ -690,8 +710,9 @@ llvm::ManagedStatic<llvm::SmallSetVector<RecoveryReproducerContext *, 1>>
690
710
691
711
RecoveryReproducerContext::RecoveryReproducerContext (
692
712
MutableArrayRef<std::unique_ptr<Pass>> passes, Operation *op,
693
- StringRef filename, bool disableThreads, bool verifyPasses)
694
- : preCrashOperation(op->clone ()), filename(filename),
713
+ PassManager::ReproducerStreamFactory &crashStreamFactory,
714
+ bool disableThreads, bool verifyPasses)
715
+ : preCrashOperation(op->clone ()), crashStreamFactory(crashStreamFactory),
695
716
disableThreads(disableThreads), verifyPasses(verifyPasses) {
696
717
// Grab the textual pipeline being executed..
697
718
{
@@ -717,25 +738,42 @@ RecoveryReproducerContext::~RecoveryReproducerContext() {
717
738
llvm::CrashRecoveryContext::Disable ();
718
739
}
719
740
741
+ // / Description of the reproducer stream.
742
+ StringRef FileReproducerStream::description () {
743
+ return outputFile->getFilename ();
744
+ }
745
+
746
+ // / Stream on which to output reproducer.
747
+ raw_ostream &FileReproducerStream::os () { return outputFile->os (); }
748
+
749
+ FileReproducerStream::~FileReproducerStream () { outputFile->keep (); }
750
+
720
751
LogicalResult RecoveryReproducerContext::generate (std::string &error) {
721
- std::unique_ptr<llvm::ToolOutputFile> outputFile =
722
- mlir::openOutputFile (filename, & error);
723
- if (!outputFile )
752
+ std::unique_ptr<PassManager::ReproducerStream> crashStream =
753
+ crashStreamFactory ( error);
754
+ if (!crashStream )
724
755
return failure ();
725
- auto &outputOS = outputFile->os ();
726
756
727
757
// Output the current pass manager configuration.
728
- outputOS << " // configuration: -pass-pipeline='" << pipeline << " '" ;
758
+ auto &os = crashStream->os ();
759
+ os << " // configuration: -pass-pipeline='" << pipeline << " '" ;
729
760
if (disableThreads)
730
- outputOS << " -mlir-disable-threading" ;
731
-
732
- // TODO: Should this also be configured with a pass manager flag?
733
- outputOS << " \n // note: verifyPasses=" << (verifyPasses ? " true" : " false" )
734
- << " \n " ;
761
+ os << " -mlir-disable-threading" ;
762
+ if (verifyPasses)
763
+ os << " -verify-each" ;
764
+ os << ' \n ' ;
735
765
736
766
// Output the .mlir module.
737
- preCrashOperation->print (outputOS);
738
- outputFile->keep ();
767
+ preCrashOperation->print (os);
768
+
769
+ bool shouldPrintOnOp =
770
+ preCrashOperation->getContext ()->shouldPrintOpOnDiagnostic ();
771
+ preCrashOperation->getContext ()->printOpOnDiagnostic (false );
772
+ preCrashOperation->emitError ()
773
+ << " A failure has been detected while processing the MLIR module, a "
774
+ " reproducer has been generated in '"
775
+ << crashStream->description () << " '" ;
776
+ preCrashOperation->getContext ()->printOpOnDiagnostic (shouldPrintOnOp);
739
777
return success ();
740
778
}
741
779
@@ -778,7 +816,7 @@ LogicalResult PassManager::runWithCrashRecovery(Operation *op,
778
816
LogicalResult
779
817
PassManager::runWithCrashRecovery (MutableArrayRef<std::unique_ptr<Pass>> passes,
780
818
Operation *op, AnalysisManager am) {
781
- RecoveryReproducerContext context (passes, op, *crashReproducerFileName ,
819
+ RecoveryReproducerContext context (passes, op, crashReproducerStreamFactory ,
782
820
!getContext ()->isMultithreadingEnabled (),
783
821
verifyPasses);
784
822
@@ -798,13 +836,6 @@ PassManager::runWithCrashRecovery(MutableArrayRef<std::unique_ptr<Pass>> passes,
798
836
std::string error;
799
837
if (failed (context.generate (error)))
800
838
return op->emitError (" <MLIR-PassManager-Crash-Reproducer>: " ) << error;
801
- bool shouldPrintOnOp = op->getContext ()->shouldPrintOpOnDiagnostic ();
802
- op->getContext ()->printOpOnDiagnostic (false );
803
- op->emitError ()
804
- << " A failure has been detected while processing the MLIR module, a "
805
- " reproducer has been generated in '"
806
- << *crashReproducerFileName << " '" ;
807
- op->getContext ()->printOpOnDiagnostic (shouldPrintOnOp);
808
839
return failure ();
809
840
}
810
841
@@ -848,7 +879,7 @@ LogicalResult PassManager::run(Operation *op) {
848
879
// If reproducer generation is enabled, run the pass manager with crash
849
880
// handling enabled.
850
881
LogicalResult result =
851
- crashReproducerFileName
882
+ crashReproducerStreamFactory
852
883
? runWithCrashRecovery (op, am)
853
884
: OpToOpPassAdaptor::runPipeline (getPasses (), op, am, verifyPasses,
854
885
impl->initializationGeneration );
@@ -869,7 +900,30 @@ LogicalResult PassManager::run(Operation *op) {
869
900
// / pipeline.
870
901
void PassManager::enableCrashReproducerGeneration (StringRef outputFile,
871
902
bool genLocalReproducer) {
872
- crashReproducerFileName = std::string (outputFile);
903
+ // Capture the filename by value in case outputFile is out of scope when
904
+ // invoked.
905
+ std::string filename = outputFile.str ();
906
+ enableCrashReproducerGeneration (
907
+ [filename](std::string &error) -> std::unique_ptr<ReproducerStream> {
908
+ std::unique_ptr<llvm::ToolOutputFile> outputFile =
909
+ mlir::openOutputFile (filename, &error);
910
+ if (!outputFile) {
911
+ error = " Failed to create reproducer stream: " + error;
912
+ return nullptr ;
913
+ }
914
+ return std::make_unique<FileReproducerStream>(std::move (outputFile));
915
+ },
916
+ genLocalReproducer);
917
+ }
918
+
919
+ // / Enable support for the pass manager to generate a reproducer on the event
920
+ // / of a crash or a pass failure. `factory` is used to construct the streams
921
+ // / to write the generated reproducer to. If `genLocalReproducer` is true, the
922
+ // / pass manager will attempt to generate a local reproducer that contains the
923
+ // / smallest pipeline.
924
+ void PassManager::enableCrashReproducerGeneration (
925
+ ReproducerStreamFactory factory, bool genLocalReproducer) {
926
+ crashReproducerStreamFactory = factory;
873
927
localReproducer = genLocalReproducer;
874
928
}
875
929
0 commit comments