diff --git a/llvm/include/llvm/Passes/StandardInstrumentations.h b/llvm/include/llvm/Passes/StandardInstrumentations.h --- a/llvm/include/llvm/Passes/StandardInstrumentations.h +++ b/llvm/include/llvm/Passes/StandardInstrumentations.h @@ -269,6 +269,32 @@ Any) override; }; +class IRChangedTester : public IRChangedPrinter { +public: + IRChangedTester() : IRChangedPrinter(true) {} + ~IRChangedTester() override; + void registerCallbacks(PassInstrumentationCallbacks &PIC); + +protected: + void handleIR(const std::string &IR, StringRef PassID); + + // Check initial IR + void handleInitialIR(Any IR) override; + // Do nothing. + void omitAfter(StringRef PassID, std::string &Name) override; + // Do nothing. + void handleInvalidated(StringRef PassID) override; + // Do nothing. + void handleFiltered(StringRef PassID, std::string &Name) override; + // Do nothing. + void handleIgnored(StringRef PassID, std::string &Name) override; + + // Call test as interesting IR has changed. + void handleAfter(StringRef PassID, std::string &Name, + const std::string &Before, const std::string &After, + Any) override; +}; + // Information that needs to be saved for a basic block in order to compare // before and after the pass to determine if it was changed by a pass. template class BlockDataT { @@ -504,6 +530,7 @@ PseudoProbeVerifier PseudoProbeVerification; InLineChangePrinter PrintChangedDiff; DotCfgChangeReporter WebsiteChangeReporter; + IRChangedTester ChangeTester; VerifyInstrumentation Verify; bool VerifyEach; diff --git a/llvm/lib/Passes/StandardInstrumentations.cpp b/llvm/lib/Passes/StandardInstrumentations.cpp --- a/llvm/lib/Passes/StandardInstrumentations.cpp +++ b/llvm/lib/Passes/StandardInstrumentations.cpp @@ -164,22 +164,30 @@ cl::desc("Generate dot files into specified directory for changed IRs"), cl::Hidden, cl::init("./")); +// An option for specifying an executable that will be called with the IR +// everytime it changes in the opt pipeline. It will also be called on +// the initial IR as it enters the pipeline. The executable will be passed +// the name of a temporary file containing the IR and the PassID. This may +// be used, for example, to call llc on the IR and run a test to determine +// which pass makes a change that changes the functioning of the IR. +// The usual modifier options work as expected. +static cl::opt + TestChanged("test-changed", cl::Hidden, cl::init(""), + cl::desc("exe called with module IR after each pass that " + "changes it")); + namespace { -// Perform a system based diff between \p Before and \p After, using -// \p OldLineFormat, \p NewLineFormat, and \p UnchangedLineFormat -// to control the formatting of the output. Return an error message -// for any failures instead of the diff. -std::string doSystemDiff(StringRef Before, StringRef After, - StringRef OldLineFormat, StringRef NewLineFormat, - StringRef UnchangedLineFormat) { - StringRef SR[2]{Before, After}; - // Store the 2 bodies into temporary files and call diff on them - // to get the body of the node. - const unsigned NumFiles = 3; - static std::string FileName[NumFiles]; - static int FD[NumFiles]{-1, -1, -1}; - for (unsigned I = 0; I < NumFiles; ++I) { +// Ensure temporary files exist, creating or re-using them. \p FD contains +// file descriptors (-1 indicates that the file should be created) and +// \p SR contains the corresponding initial content. \p FileName will have +// the filenames filled in when creating files. Return any error message +// or "" if none. +std::string prepareTempFiles(SmallVector &FD, ArrayRef SR, + SmallVector &FileName) { + assert(FD.size() >= SR.size() && FileName.size() == FD.size() && + "Unexpected array sizes"); + for (unsigned I = 0; I < FD.size(); ++I) { if (FD[I] == -1) { SmallVector SV; std::error_code EC = @@ -188,19 +196,44 @@ return "Unable to create temporary file."; FileName[I] = Twine(SV).str(); } - // The third file is used as the result of the diff. - if (I == NumFiles - 1) - break; + // Only the first M files have initial content. + if (I < SR.size()) { + std::error_code EC = sys::fs::openFileForWrite(FileName[I], FD[I]); + if (EC) + return "Unable to open temporary file for writing."; + raw_fd_ostream OutStream(FD[I], /*shouldClose=*/true); + if (FD[I] == -1) + return "Error opening file for writing."; + OutStream << SR[I]; + } + } + return ""; +} - std::error_code EC = sys::fs::openFileForWrite(FileName[I], FD[I]); +std::string cleanUpTempFiles(ArrayRef FileName) { + for (unsigned I = 0; I < FileName.size(); ++I) { + std::error_code EC = sys::fs::remove(FileName[I]); if (EC) - return "Unable to open temporary file for writing."; - - raw_fd_ostream OutStream(FD[I], /*shouldClose=*/true); - if (FD[I] == -1) - return "Error opening file for writing."; - OutStream << SR[I]; + return "Unable to remove temporary file."; } + return ""; +} + +// Perform a system based diff between \p Before and \p After, using +// \p OldLineFormat, \p NewLineFormat, and \p UnchangedLineFormat +// to control the formatting of the output. Return an error message +// for any failures instead of the diff. +std::string doSystemDiff(StringRef Before, StringRef After, + StringRef OldLineFormat, StringRef NewLineFormat, + StringRef UnchangedLineFormat) { + // Store the 2 bodies into temporary files and call diff on them + // to get the body of the node. + static SmallVector FD{-1, -1, -1}; + SmallVector SR{Before, After}; + static SmallVector FileName{"", "", ""}; + std::string Err = prepareTempFiles(FD, SR, FileName); + if (Err != "") + return Err; static ErrorOr DiffExe = sys::findProgramByName(DiffBinary); if (!DiffExe) @@ -224,12 +257,10 @@ else return "Unable to read result."; - // Clean up. - for (const std::string &I : FileName) { - std::error_code EC = sys::fs::remove(I); - if (EC) - return "Unable to remove temporary file."; - } + Err = cleanUpTempFiles(FileName); + if (Err != "") + return Err; + return Diff; } @@ -620,6 +651,59 @@ Out << "*** IR Dump After " << PassID << " on " << Name << " ***\n" << After; } +IRChangedTester::~IRChangedTester() {} + +void IRChangedTester::registerCallbacks(PassInstrumentationCallbacks &PIC) { + if (TestChanged != "") + TextChangeReporter::registerRequiredCallbacks(PIC); +} + +void IRChangedTester::handleIR(const std::string &S, StringRef PassID) { + // Store the body into a temporary file + static SmallVector FD{-1}; + SmallVector SR{S}; + static SmallVector FileName{""}; + std::string Err = prepareTempFiles(FD, SR, FileName); + if (Err != "") { + dbgs() << Err; + return; + } + static ErrorOr Exe = sys::findProgramByName(TestChanged); + if (!Exe) { + dbgs() << "Unable to find test-changed executable."; + return; + } + + StringRef Args[] = {TestChanged, FileName[0], PassID}; + int Result = sys::ExecuteAndWait(*Exe, Args); + if (Result < 0) { + dbgs() << "Error executing test-changed executable."; + return; + } + + Err = cleanUpTempFiles(FileName); + if (Err != "") + dbgs() << Err; +} + +void IRChangedTester::handleInitialIR(Any IR) { + // Always test the initial module. + // Unwrap and print directly to avoid filtering problems in general routines. + std::string S; + generateIRRepresentation(IR, "Initial IR", S); + handleIR(S, "Initial IR"); +} + +void IRChangedTester::omitAfter(StringRef PassID, std::string &Name) {} +void IRChangedTester::handleInvalidated(StringRef PassID) {} +void IRChangedTester::handleFiltered(StringRef PassID, std::string &Name) {} +void IRChangedTester::handleIgnored(StringRef PassID, std::string &Name) {} +void IRChangedTester::handleAfter(StringRef PassID, std::string &Name, + const std::string &Before, + const std::string &After, Any) { + handleIR(After, PassID); +} + template void OrderedChangedData::report( const OrderedChangedData &Before, const OrderedChangedData &After, @@ -2132,6 +2216,7 @@ Verify.registerCallbacks(PIC); PrintChangedDiff.registerCallbacks(PIC); WebsiteChangeReporter.registerCallbacks(PIC); + ChangeTester.registerCallbacks(PIC); } template class ChangeReporter; diff --git a/llvm/test/Other/test-changed-script.sh b/llvm/test/Other/test-changed-script.sh new file mode 100755 --- /dev/null +++ b/llvm/test/Other/test-changed-script.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +echo "***" $2 "***" +cat $1 diff --git a/llvm/test/Other/test-changed.ll b/llvm/test/Other/test-changed.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Other/test-changed.ll @@ -0,0 +1,103 @@ +; Simple checks of -test-changed=%S/test-changed-script.sh functionality +; +; Simple functionality check. +; RUN: opt -S -test-changed=%S/test-changed-script.sh -passes=instsimplify 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-SIMPLE +; +; Check that only the passes that change the IR are printed and that the +; others (including g) are filtered out. +; RUN: opt -S -test-changed=%S/test-changed-script.sh -passes=instsimplify -filter-print-funcs=f 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-FUNC-FILTER +; +; Check that the reporting of IRs respects -print-module-scope +; RUN: opt -S -test-changed=%S/test-changed-script.sh -passes=instsimplify -print-module-scope 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-PRINT-MOD-SCOPE +; +; Check that the reporting of IRs respects -print-module-scope +; RUN: opt -S -test-changed=%S/test-changed-script.sh -passes=instsimplify -filter-print-funcs=f -print-module-scope 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-FUNC-FILTER-MOD-SCOPE +; +; Check that reporting of multiple functions happens +; RUN: opt -S -test-changed=%S/test-changed-script.sh -passes=instsimplify -filter-print-funcs="f,g" 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-FILTER-MULT-FUNC +; +; Check that the reporting of IRs respects -filter-passes +; RUN: opt -S -test-changed=%S/test-changed-script.sh -passes="instsimplify,no-op-function" -filter-passes="NoOpFunctionPass" 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-FILTER-PASSES +; +; Check that the reporting of IRs respects -filter-passes with multiple passes +; RUN: opt -S -test-changed=%S/test-changed-script.sh -passes="instsimplify,no-op-function" -filter-passes="NoOpFunctionPass,InstSimplifyPass" 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-FILTER-MULT-PASSES +; +; Check that the reporting of IRs respects both -filter-passes and -filter-print-funcs +; RUN: opt -S -test-changed=%S/test-changed-script.sh -passes="instsimplify,no-op-function" -filter-passes="NoOpFunctionPass,InstSimplifyPass" -filter-print-funcs=f 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-FILTER-FUNC-PASSES +; +; Check that the reporting of IRs respects -filter-passes, -filter-print-funcs and -print-module-scope +; RUN: opt -S -test-changed=%S/test-changed-script.sh -passes="instsimplify,no-op-function" -filter-passes="NoOpFunctionPass,InstSimplifyPass" -filter-print-funcs=f -print-module-scope 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-FILTER-FUNC-PASSES-MOD-SCOPE +; +; Check that repeated passes that change the IR are printed and that the +; others (including g) are filtered out. Note that the second time +; instsimplify is run on f, it does not change the IR +; RUN: opt -S -test-changed=%S/test-changed-script.sh -passes="instsimplify,instsimplify" -filter-print-funcs=f 2>&1 -o /dev/null < %s | FileCheck %s --check-prefix=CHECK-MULT-PASSES-FILTER-FUNC +; + +define i32 @g() { +entry: + %a = add i32 2, 3 + ret i32 %a +} + +define i32 @f() { +entry: + %a = add i32 2, 3 + ret i32 %a +} + +; CHECK-SIMPLE: *** Initial IR *** +; CHECK-SIMPLE-NEXT: ; ModuleID = {{.+}} +; CHECK-SIMPLE: *** InstSimplifyPass *** +; CHECK-SIMPLE-NEXT: define i32 @g() +; CHECK-SIMPLE: *** InstSimplifyPass *** +; CHECK-SIMPLE-NEXT: define i32 @f() + +; CHECK-FUNC-FILTER: *** Initial IR *** +; CHECK-FUNC-FILTER-NEXT: define i32 @f() +; CHECK-FUNC-FILTER: *** InstSimplifyPass *** +; CHECK-FUNC-FILTER-NEXT: define i32 @f() + +; CHECK-PRINT-MOD-SCOPE: *** Initial IR *** +; CHECK-PRINT-MOD-SCOPE-NEXT: ModuleID = {{.+}} +; CHECK-PRINT-MOD-SCOPE: *** InstSimplifyPass *** +; CHECK-PRINT-MOD-SCOPE-NEXT: ModuleID = {{.+}} +; CHECK-PRINT-MOD-SCOPE: *** InstSimplifyPass *** +; CHECK-PRINT-MOD-SCOPE-NEXT: ModuleID = {{.+}} + +; CHECK-FUNC-FILTER-MOD-SCOPE: *** Initial IR *** +; CHECK-FUNC-FILTER-MOD-SCOPE-NEXT: ; ModuleID = {{.+}} +; CHECK-FUNC-FILTER-MOD-SCOPE: *** InstSimplifyPass *** +; CHECK-FUNC-FILTER-MOD-SCOPE-NEXT: ModuleID = {{.+}} + +; CHECK-FILTER-MULT-FUNC: *** Initial IR *** +; CHECK-FILTER-MULT-FUNC-NEXT: define i32 @g() +; CHECK-FILTER-MULT-FUNC: *** InstSimplifyPass *** +; CHECK-FILTER-MULT-FUNC-NEXT: define i32 @g() +; CHECK-FILTER-MULT-FUNC: *** InstSimplifyPass *** +; CHECK-FILTER-MULT-FUNC-NEXT: define i32 @f() + +; CHECK-FILTER-PASSES: *** Initial IR *** +; CHECK-FILTER-PASSES-NEXT: define i32 @g() + +; CHECK-FILTER-MULT-PASSES: *** Initial IR *** +; CHECK-FILTER-MULT-PASSES-NEXT: define i32 @g() +; CHECK-FILTER-MULT-PASSES: *** InstSimplifyPass *** +; CHECK-FILTER-MULT-PASSES-NEXT: define i32 @g() +; CHECK-FILTER-MULT-PASSES: *** InstSimplifyPass *** +; CHECK-FILTER-MULT-PASSES-NEXT: define i32 @f() + +; CHECK-FILTER-FUNC-PASSES: *** Initial IR *** +; CHECK-FILTER-FUNC-PASSES-NEXT: define i32 @f() +; CHECK-FILTER-FUNC-PASSES: *** InstSimplifyPass *** +; CHECK-FILTER-FUNC-PASSES-NEXT: define i32 @f() + +; CHECK-FILTER-FUNC-PASSES-MOD-SCOPE: *** Initial IR *** +; CHECK-FILTER-FUNC-PASSES-MOD-SCOPE-NEXT: ; ModuleID = {{.+}} +; CHECK-FILTER-FUNC-PASSES-MOD-SCOPE: *** InstSimplifyPass *** +; CHECK-FILTER-FUNC-PASSES-MOD-SCOPE-NEXT: ModuleID = {{.+}} + +; CHECK-MULT-PASSES-FILTER-FUNC: *** Initial IR *** +; CHECK-MULT-PASSES-FILTER-FUNC-NEXT: define i32 @f() +; CHECK-MULT-PASSES-FILTER-FUNC: *** InstSimplifyPass *** +; CHECK-MULT-PASSES-FILTER-FUNC-NEXT: define i32 @f() diff --git a/llvm/test/Transforms/NewGVN/pr35074-phi-of-ops.ll b/llvm/test/Transforms/NewGVN/pr35074-phi-of-ops.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/NewGVN/pr35074-phi-of-ops.ll @@ -0,0 +1,55 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -newgvn -S %s | FileCheck %s + +define void @crash1_pr35074(i32 %this, i1 %c) { +; CHECK-LABEL: @crash1_pr35074( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[FOR_COND:%.*]] +; CHECK: for.cond: +; CHECK-NEXT: [[PHIOFOPS:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[Y_0:%.*]], [[FOR_INC6:%.*]] ] +; CHECK-NEXT: [[Y_0]] = phi i32 [ 1, [[ENTRY]] ], [ [[INC7:%.*]], [[FOR_INC6]] ] +; CHECK-NEXT: br i1 [[C:%.*]], label [[FOR_INC6]], label [[FOR_BODY_LR_PH:%.*]] +; CHECK: for.body.lr.ph: +; CHECK-NEXT: br label [[FOR_BODY4:%.*]] +; CHECK: for.body4: +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[PHIOFOPS]], [[Y_0]] +; CHECK-NEXT: br i1 [[CMP]], label [[FOR_END:%.*]], label [[FOR_BODY4_1:%.*]] +; CHECK: for.end: +; CHECK-NEXT: ret void +; CHECK: for.inc6: +; CHECK-NEXT: [[INC7]] = add nuw nsw i32 [[Y_0]], 1 +; CHECK-NEXT: br label [[FOR_COND]] +; CHECK: for.body4.1: +; CHECK-NEXT: [[INC_1:%.*]] = add nuw nsw i32 [[Y_0]], 1 +; CHECK-NEXT: tail call void @_blah(i32 [[INC_1]]) +; CHECK-NEXT: br label [[FOR_END]] +; +entry: + br label %for.cond + +for.cond: ; preds = %for.inc6, %entry + %y.0 = phi i32 [ 1, %entry ], [ %inc7, %for.inc6 ] + br i1 %c, label %for.inc6, label %for.body.lr.ph + +for.body.lr.ph: ; preds = %for.cond + %sub = add nsw i32 %y.0, -1 + br label %for.body4 + +for.body4: ; preds = %for.body.lr.ph + %cmp = icmp ugt i32 %sub, %y.0 + br i1 %cmp, label %for.end, label %for.body4.1 + +for.end: ; preds = %for.body4.1, %for.body4 + ret void + +for.inc6: ; preds = %for.cond + %inc7 = add nuw nsw i32 %y.0, 1 + br label %for.cond + +for.body4.1: ; preds = %for.body4 + %inc.1 = add nuw nsw i32 %y.0, 1 + tail call void @_blah(i32 %inc.1) + br label %for.end +} + +declare void @_blah(i32) diff --git a/llvm/test/Transforms/NewGVN/todo-pr37121-seens-this-value-a-lot.ll b/llvm/test/Transforms/NewGVN/pr37121-seens-this-value-a-lot.ll rename from llvm/test/Transforms/NewGVN/todo-pr37121-seens-this-value-a-lot.ll rename to llvm/test/Transforms/NewGVN/pr37121-seens-this-value-a-lot.ll --- a/llvm/test/Transforms/NewGVN/todo-pr37121-seens-this-value-a-lot.ll +++ b/llvm/test/Transforms/NewGVN/pr37121-seens-this-value-a-lot.ll @@ -1,12 +1,18 @@ -; REQUIRES: asserts - +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -newgvn -S %s | FileCheck %s -; XFAIL: * - -; TODO: Current NewGVN crashes on the function below. See PR37121. - define hidden void @foo() { +; CHECK-LABEL: @foo( +; CHECK-NEXT: top: +; CHECK-NEXT: br label [[IF:%.*]] +; CHECK: if: +; CHECK-NEXT: [[TMP0:%.*]] = phi i8 [ [[TMP1:%.*]], [[IF]] ], [ undef, [[TOP:%.*]] ] +; CHECK-NEXT: [[TMP1]] = xor i8 [[TMP0]], undef +; CHECK-NEXT: br i1 false, label [[L50:%.*]], label [[IF]] +; CHECK: L50: +; CHECK-NEXT: store i8 undef, i8* null, align 1 +; CHECK-NEXT: ret void +; top: %.promoted = load i8, i8* undef, align 8 br label %if diff --git a/llvm/test/Transforms/NewGVN/pr42422-phi-of-ops.ll b/llvm/test/Transforms/NewGVN/pr42422-phi-of-ops.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/NewGVN/pr42422-phi-of-ops.ll @@ -0,0 +1,140 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -newgvn -S %s | FileCheck %s + +define void @d() { +; CHECK-LABEL: @d( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[FOR_COND:%.*]] +; CHECK: for.cond: +; CHECK-NEXT: br label [[FOR_COND1:%.*]] +; CHECK: for.cond1: +; CHECK-NEXT: [[TMP0:%.*]] = phi i32 [ [[INC18:%.*]], [[FOR_INC17:%.*]] ], [ 0, [[FOR_COND]] ] +; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[TMP0]], 1 +; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END19:%.*]] +; CHECK: for.body: +; CHECK-NEXT: br i1 undef, label [[FOR_BODY3:%.*]], label [[FOR_BODY_FOR_COND4_CRIT_EDGE:%.*]] +; CHECK: for.body.for.cond4_crit_edge: +; CHECK-NEXT: br label [[FOR_COND4:%.*]] +; CHECK: for.body3: +; CHECK-NEXT: br label [[CLEANUP14:%.*]] +; CHECK: for.cond4: +; CHECK-NEXT: br i1 undef, label [[IF_THEN:%.*]], label [[IF_END:%.*]] +; CHECK: if.then: +; CHECK-NEXT: br label [[CLEANUP:%.*]] +; CHECK: if.end: +; CHECK-NEXT: br label [[FOR_COND6:%.*]] +; CHECK: for.cond6: +; CHECK-NEXT: [[TMP1:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[IF_END]] ] +; CHECK-NEXT: [[CMP7:%.*]] = icmp sle i64 [[TMP1]], 1 +; CHECK-NEXT: br i1 [[CMP7]], label [[FOR_INC]], label [[FOR_END9:%.*]] +; CHECK: for.inc: +; CHECK-NEXT: [[INC]] = add nsw i64 [[TMP1]], 1 +; CHECK-NEXT: br label [[FOR_COND6]] +; CHECK: for.end9: +; CHECK-NEXT: br i1 true, label [[IF_THEN11:%.*]], label [[IF_END12:%.*]] +; CHECK: if.then11: +; CHECK-NEXT: br label [[CLEANUP]] +; CHECK: if.end12: +; CHECK-NEXT: store i8 undef, i8* null, align 1 +; CHECK-NEXT: br label [[CLEANUP]] +; CHECK: cleanup: +; CHECK-NEXT: [[CLEANUP_DEST:%.*]] = phi i32 [ undef, [[IF_END12]] ], [ 1, [[IF_THEN11]] ], [ 9, [[IF_THEN]] ] +; CHECK-NEXT: switch i32 [[CLEANUP_DEST]], label [[CLEANUP14]] [ +; CHECK-NEXT: i32 0, label [[FOR_COND4]] +; CHECK-NEXT: i32 9, label [[FOR_END13:%.*]] +; CHECK-NEXT: ] +; CHECK: for.end13: +; CHECK-NEXT: br label [[CLEANUP14]] +; CHECK: cleanup14: +; CHECK-NEXT: [[CLEANUP_DEST15:%.*]] = phi i32 [ 0, [[FOR_END13]] ], [ [[CLEANUP_DEST]], [[CLEANUP]] ], [ 1, [[FOR_BODY3]] ] +; CHECK-NEXT: [[COND1:%.*]] = icmp eq i32 [[CLEANUP_DEST15]], 0 +; CHECK-NEXT: br i1 [[COND1]], label [[FOR_INC17]], label [[CLEANUP20:%.*]] +; CHECK: for.inc17: +; CHECK-NEXT: [[INC18]] = add nsw i32 [[TMP0]], 1 +; CHECK-NEXT: br label [[FOR_COND1]] +; CHECK: for.end19: +; CHECK-NEXT: br label [[CLEANUP20]] +; CHECK: cleanup20: +; CHECK-NEXT: [[PHIOFOPS:%.*]] = phi i1 [ true, [[FOR_END19]] ], [ [[COND1]], [[CLEANUP14]] ] +; CHECK-NEXT: [[CLEANUP_DEST21:%.*]] = phi i32 [ [[CLEANUP_DEST15]], [[CLEANUP14]] ], [ 0, [[FOR_END19]] ] +; CHECK-NEXT: br i1 [[PHIOFOPS]], label [[FOR_COND]], label [[CLEANUP23:%.*]] +; CHECK: cleanup23: +; CHECK-NEXT: ret void +; +entry: + br label %for.cond + +for.cond: ; preds = %cleanup20, %entry + br label %for.cond1 + +for.cond1: ; preds = %for.inc17, %for.cond + %0 = phi i32 [ %inc18, %for.inc17 ], [ 0, %for.cond ] + %cmp = icmp sle i32 %0, 1 + br i1 %cmp, label %for.body, label %for.end19 + +for.body: ; preds = %for.cond1 + br i1 undef, label %for.body3, label %for.body.for.cond4_crit_edge + +for.body.for.cond4_crit_edge: ; preds = %for.body + br label %for.cond4 + +for.body3: ; preds = %for.body + br label %cleanup14 + +for.cond4: ; preds = %cleanup, %for.body.for.cond4_crit_edge + br i1 undef, label %if.then, label %if.end + +if.then: ; preds = %for.cond4 + br label %cleanup + +if.end: ; preds = %for.cond4 + br label %for.cond6 + +for.cond6: ; preds = %for.inc, %if.end + %1 = phi i64 [ %inc, %for.inc ], [ 0, %if.end ] + %cmp7 = icmp sle i64 %1, 1 + br i1 %cmp7, label %for.inc, label %for.end9 + +for.inc: ; preds = %for.cond6 + %inc = add nsw i64 %1, 1 + br label %for.cond6 + +for.end9: ; preds = %for.cond6 + br i1 true, label %if.then11, label %if.end12 + +if.then11: ; preds = %for.end9 + br label %cleanup + +if.end12: ; preds = %for.end9 + br label %cleanup + +cleanup: ; preds = %if.end12, %if.then11, %if.then + %cleanup.dest = phi i32 [ undef, %if.end12 ], [ 1, %if.then11 ], [ 9, %if.then ] + switch i32 %cleanup.dest, label %cleanup14 [ + i32 0, label %for.cond4 + i32 9, label %for.end13 + ] + +for.end13: ; preds = %cleanup + br label %cleanup14 + +cleanup14: ; preds = %for.end13, %cleanup, %for.body3 + %cleanup.dest15 = phi i32 [ 0, %for.end13 ], [ %cleanup.dest, %cleanup ], [ 1, %for.body3 ] + %cond1 = icmp eq i32 %cleanup.dest15, 0 + br i1 %cond1, label %for.inc17, label %cleanup20 + +for.inc17: ; preds = %cleanup14 + %inc18 = add nsw i32 %0, 1 + br label %for.cond1 + +for.end19: ; preds = %for.cond1 + br label %cleanup20 + +cleanup20: ; preds = %for.end19, %cleanup14 + %cleanup.dest21 = phi i32 [ %cleanup.dest15, %cleanup14 ], [ 0, %for.end19 ] + %cond = icmp eq i32 %cleanup.dest21, 0 + br i1 %cond, label %for.cond, label %cleanup23 + +cleanup23: ; preds = %cleanup20 + ret void +} diff --git a/llvm/test/Transforms/NewGVN/todo-pr35074-phi-of-ops.ll b/llvm/test/Transforms/NewGVN/todo-pr35074-phi-of-ops.ll deleted file mode 100644 --- a/llvm/test/Transforms/NewGVN/todo-pr35074-phi-of-ops.ll +++ /dev/null @@ -1,37 +0,0 @@ -; REQUIRES: asserts - -; RUN: opt -newgvn -S %s | FileCheck %s - -XFAIL: * - -; TODO: Test case for PR35074. Crashes caused by phi-of-ops. -define void @crash1_pr35074(i32 %this, i1 %c) { -entry: - br label %for.cond - -for.cond: ; preds = %for.inc6, %entry - %y.0 = phi i32 [ 1, %entry ], [ %inc7, %for.inc6 ] - br i1 %c, label %for.inc6, label %for.body.lr.ph - -for.body.lr.ph: ; preds = %for.cond - %sub = add nsw i32 %y.0, -1 - br label %for.body4 - -for.body4: ; preds = %for.body.lr.ph - %cmp = icmp ugt i32 %sub, %y.0 - br i1 %cmp, label %for.end, label %for.body4.1 - -for.end: ; preds = %for.body4.1, %for.body4 - ret void - -for.inc6: ; preds = %for.cond - %inc7 = add nuw nsw i32 %y.0, 1 - br label %for.cond - -for.body4.1: ; preds = %for.body4 - %inc.1 = add nuw nsw i32 %y.0, 1 - tail call void @_blah(i32 %inc.1) - br label %for.end -} - -declare void @_blah(i32) diff --git a/llvm/test/Transforms/NewGVN/todo-pr42422-phi-of-ops.ll b/llvm/test/Transforms/NewGVN/todo-pr42422-phi-of-ops.ll deleted file mode 100644 --- a/llvm/test/Transforms/NewGVN/todo-pr42422-phi-of-ops.ll +++ /dev/null @@ -1,86 +0,0 @@ -; REQUIRES: asserts - -; RUN: opt -newgvn -S %s | FileCheck %s - -; XFAIL: * - -; TODO: Currently NewGVN crashes on the function below, see PR42422. - -define void @d() { -entry: - br label %for.cond - -for.cond: ; preds = %cleanup20, %entry - br label %for.cond1 - -for.cond1: ; preds = %for.inc17, %for.cond - %0 = phi i32 [ %inc18, %for.inc17 ], [ 0, %for.cond ] - %cmp = icmp sle i32 %0, 1 - br i1 %cmp, label %for.body, label %for.end19 - -for.body: ; preds = %for.cond1 - br i1 undef, label %for.body3, label %for.body.for.cond4_crit_edge - -for.body.for.cond4_crit_edge: ; preds = %for.body - br label %for.cond4 - -for.body3: ; preds = %for.body - br label %cleanup14 - -for.cond4: ; preds = %cleanup, %for.body.for.cond4_crit_edge - br i1 undef, label %if.then, label %if.end - -if.then: ; preds = %for.cond4 - br label %cleanup - -if.end: ; preds = %for.cond4 - br label %for.cond6 - -for.cond6: ; preds = %for.inc, %if.end - %1 = phi i64 [ %inc, %for.inc ], [ 0, %if.end ] - %cmp7 = icmp sle i64 %1, 1 - br i1 %cmp7, label %for.inc, label %for.end9 - -for.inc: ; preds = %for.cond6 - %inc = add nsw i64 %1, 1 - br label %for.cond6 - -for.end9: ; preds = %for.cond6 - br i1 true, label %if.then11, label %if.end12 - -if.then11: ; preds = %for.end9 - br label %cleanup - -if.end12: ; preds = %for.end9 - br label %cleanup - -cleanup: ; preds = %if.end12, %if.then11, %if.then - %cleanup.dest = phi i32 [ undef, %if.end12 ], [ 1, %if.then11 ], [ 9, %if.then ] - switch i32 %cleanup.dest, label %cleanup14 [ - i32 0, label %for.cond4 - i32 9, label %for.end13 - ] - -for.end13: ; preds = %cleanup - br label %cleanup14 - -cleanup14: ; preds = %for.end13, %cleanup, %for.body3 - %cleanup.dest15 = phi i32 [ 0, %for.end13 ], [ %cleanup.dest, %cleanup ], [ 1, %for.body3 ] - %cond1 = icmp eq i32 %cleanup.dest15, 0 - br i1 %cond1, label %for.inc17, label %cleanup20 - -for.inc17: ; preds = %cleanup14 - %inc18 = add nsw i32 %0, 1 - br label %for.cond1 - -for.end19: ; preds = %for.cond1 - br label %cleanup20 - -cleanup20: ; preds = %for.end19, %cleanup14 - %cleanup.dest21 = phi i32 [ %cleanup.dest15, %cleanup14 ], [ 0, %for.end19 ] - %cond = icmp eq i32 %cleanup.dest21, 0 - br i1 %cond, label %for.cond, label %cleanup23 - -cleanup23: ; preds = %cleanup20 - ret void -}