Skip to content

Commit b79169b

Browse files
lizhengxinggithub-actions[bot]adam-yang
authored
[llc/opt] Add an option to run all passes twice (microsoft#6666)
This PR pulls the following upstream changes into DXC: [llc/opt] Add an option to run all passes twice (llvm/llvm-project@04464cf) > Lately, I have submitted a number of patches to fix bugs that only occurred when using the same pass manager to compile > multiple modules (generally these bugs are failure to reset some persistent state). > > Unfortunately I don't think there is currently a way to test that from the command line. This adds a very simple flag to both > llc and opt, under which the tools will simply re-run their respective > pass pipelines using the same pass manager on (a clone of the same module). Additionally, we verify that both outputs are > bitwise the same. > > Reviewers: yaron.keren [opt] Fix sanitizer complaints about r254774 (llvm/llvm-project@38707c4) > `Out` can be null if no output is requested, so move any access > to it inside the conditional. Thanks to Justin Bogner for finding > this. This is for the test of this change (llvm/llvm-project@ef8761f) to fix microsoft#6659. --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Adam Yang <[email protected]>
1 parent b197bec commit b79169b

File tree

4 files changed

+115
-10
lines changed

4 files changed

+115
-10
lines changed

test/MC/ELF/empty-twice.ll

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
; Check that there is no persistent state in the ELF emitter that crashes us
2+
; when we try to reuse the pass manager
3+
; RUN: llc -compile-twice -filetype=obj %s -o -
4+
5+
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32"
6+
target triple = "i386-pc-linux-gnu"

test/Object/opt-twice.ll

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
; The pass here doesn't matter (we use deadargelim), but test
2+
; that the -run-twice options exists, generates output, and
3+
; doesn't crash
4+
; RUN: opt -run-twice -deadargelim -S < %s | FileCheck %s
5+
6+
; CHECK: define internal void @test
7+
define internal {} @test() {
8+
ret {} undef
9+
}
10+
11+
define void @caller() {
12+
call {} @test()
13+
ret void
14+
}

tools/llc/llc.cpp

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include "llvm/Support/ToolOutputFile.h"
4545
#include "llvm/Target/TargetMachine.h"
4646
#include "llvm/Target/TargetSubtargetInfo.h"
47+
#include "llvm/Transforms/Utils/Cloning.h"
4748
#include <memory>
4849
using namespace llvm;
4950

@@ -95,6 +96,12 @@ static cl::opt<bool> AsmVerbose("asm-verbose",
9596
cl::desc("Add comments to directives."),
9697
cl::init(true));
9798

99+
static cl::opt<bool>
100+
CompileTwice("compile-twice", cl::Hidden,
101+
cl::desc("Run everything twice, re-using the same pass "
102+
"manager and verify the the result is the same."),
103+
cl::init(false));
104+
98105
static int compileModule(char **, LLVMContext &);
99106

100107
static std::unique_ptr<tool_output_file>
@@ -326,10 +333,15 @@ static int compileModule(char **argv, LLVMContext &Context) {
326333

327334
{
328335
raw_pwrite_stream *OS = &Out->os();
329-
std::unique_ptr<buffer_ostream> BOS;
330-
if (FileType != TargetMachine::CGFT_AssemblyFile &&
331-
!Out->os().supportsSeeking()) {
332-
BOS = make_unique<buffer_ostream>(*OS);
336+
337+
// Manually do the buffering rather than using buffer_ostream,
338+
// so we can memcmp the contents in CompileTwice mode
339+
SmallVector<char, 0> Buffer;
340+
std::unique_ptr<raw_svector_ostream> BOS;
341+
if ((FileType != TargetMachine::CGFT_AssemblyFile &&
342+
!Out->os().supportsSeeking()) ||
343+
CompileTwice) {
344+
BOS = make_unique<raw_svector_ostream>(Buffer);
333345
OS = BOS.get();
334346
}
335347

@@ -379,7 +391,39 @@ static int compileModule(char **argv, LLVMContext &Context) {
379391
// Before executing passes, print the final values of the LLVM options.
380392
cl::PrintOptionValues();
381393

394+
// If requested, run the pass manager over the same module again,
395+
// to catch any bugs due to persistent state in the passes. Note that
396+
// opt has the same functionality, so it may be worth abstracting this out
397+
// in the future.
398+
SmallVector<char, 0> CompileTwiceBuffer;
399+
if (CompileTwice) {
400+
std::unique_ptr<Module> M2(llvm::CloneModule(M.get()));
401+
PM.run(*M2);
402+
CompileTwiceBuffer = Buffer;
403+
Buffer.clear();
404+
}
405+
382406
PM.run(*M);
407+
408+
// Compare the two outputs and make sure they're the same
409+
if (CompileTwice) {
410+
if (Buffer.size() != CompileTwiceBuffer.size() ||
411+
(memcmp(Buffer.data(), CompileTwiceBuffer.data(), Buffer.size()) !=
412+
0)) {
413+
errs()
414+
<< "Running the pass manager twice changed the output.\n"
415+
"Writing the result of the second run to the specified output\n"
416+
"To generate the one-run comparison binary, just run without\n"
417+
"the compile-twice option\n";
418+
Out->os() << Buffer;
419+
Out->keep();
420+
return 1;
421+
}
422+
}
423+
424+
if (BOS) {
425+
Out->os() << Buffer;
426+
}
383427
}
384428

385429
// Declare success.

tools/opt/opt.cpp

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515
#include "BreakpointPrinter.h"
1616
#include "NewPMDriver.h"
17-
#include "llvm/PassPrinters/PassPrinters.h"
1817
#include "llvm/ADT/Triple.h"
1918
#include "llvm/Analysis/CallGraph.h"
2019
#include "llvm/Analysis/CallGraphSCCPass.h"
@@ -28,6 +27,7 @@
2827
#include "llvm/IR/DebugInfo.h"
2928
#include "llvm/IR/IRPrintingPasses.h"
3029
#include "llvm/IR/LLVMContext.h"
30+
#include "llvm/IR/LegacyPassManager.h"
3131
#include "llvm/IR/LegacyPassNameParser.h"
3232
#include "llvm/IR/Module.h"
3333
#include "llvm/IR/Verifier.h"
@@ -36,7 +36,7 @@
3636
#include "llvm/LinkAllIR.h"
3737
#include "llvm/LinkAllPasses.h"
3838
#include "llvm/MC/SubtargetFeature.h"
39-
#include "llvm/IR/LegacyPassManager.h"
39+
#include "llvm/PassPrinters/PassPrinters.h"
4040
#include "llvm/Support/Debug.h"
4141
#include "llvm/Support/FileSystem.h"
4242
#include "llvm/Support/Host.h"
@@ -51,6 +51,7 @@
5151
#include "llvm/Support/ToolOutputFile.h"
5252
#include "llvm/Target/TargetMachine.h"
5353
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
54+
#include "llvm/Transforms/Utils/Cloning.h"
5455

5556
// HLSL Change Starts
5657
#include "dxc/HLSL/ComputeViewIdState.h"
@@ -202,6 +203,11 @@ static cl::opt<bool> PreserveAssemblyUseListOrder(
202203
cl::desc("Preserve use-list order when writing LLVM assembly."),
203204
cl::init(false), cl::Hidden);
204205

206+
static cl::opt<bool>
207+
RunTwice("run-twice",
208+
cl::desc("Run all passes twice, re-using the same pass manager."),
209+
cl::init(false), cl::Hidden);
210+
205211
static inline void addPass(legacy::PassManagerBase &PM, Pass *P) {
206212
// Add the pass to the pass manager...
207213
PM.add(P);
@@ -632,14 +638,27 @@ int __cdecl main(int argc, char **argv) {
632638
if (!NoVerify && !VerifyEach)
633639
Passes.add(createVerifierPass());
634640

641+
// In run twice mode, we want to make sure the output is bit-by-bit
642+
// equivalent if we run the pass manager again, so setup two buffers and
643+
// a stream to write to them. Note that llc does something similar and it
644+
// may be worth to abstract this out in the future.
645+
SmallVector<char, 0> Buffer;
646+
SmallVector<char, 0> CompileTwiceBuffer;
647+
std::unique_ptr<raw_svector_ostream> BOS;
648+
raw_ostream *OS = nullptr;
649+
635650
// Write bitcode or assembly to the output as the last step...
636651
if (!NoOutput && !AnalyzeOnly) {
652+
assert(Out);
653+
OS = &Out->os();
654+
if (RunTwice) {
655+
BOS = make_unique<raw_svector_ostream>(Buffer);
656+
OS = BOS.get();
657+
}
637658
if (OutputAssembly)
638-
Passes.add(
639-
createPrintModulePass(Out->os(), "", PreserveAssemblyUseListOrder));
659+
Passes.add(createPrintModulePass(*OS, "", PreserveAssemblyUseListOrder));
640660
else
641-
Passes.add(
642-
createBitcodeWriterPass(Out->os(), PreserveBitcodeUseListOrder));
661+
Passes.add(createBitcodeWriterPass(*OS, PreserveBitcodeUseListOrder));
643662
}
644663

645664
// Before executing passes, print the final values of the LLVM options.
@@ -655,6 +674,28 @@ int __cdecl main(int argc, char **argv) {
655674
}
656675
// HLSL Change Ends
657676

677+
// If requested, run all passes again with the same pass manager to catch
678+
// bugs caused by persistent state in the passes
679+
if (RunTwice) {
680+
assert(Out);
681+
CompileTwiceBuffer = Buffer;
682+
Buffer.clear();
683+
std::unique_ptr<Module> M2(CloneModule(M.get()));
684+
Passes.run(*M2);
685+
if (Buffer.size() != CompileTwiceBuffer.size() ||
686+
(memcmp(Buffer.data(), CompileTwiceBuffer.data(), Buffer.size()) !=
687+
0)) {
688+
errs() << "Running the pass manager twice changed the output.\n"
689+
"Writing the result of the second run to the specified output."
690+
"To generate the one-run comparison binary, just run without\n"
691+
"the compile-twice option\n";
692+
Out->os() << BOS->str();
693+
Out->keep();
694+
return 1;
695+
}
696+
Out->os() << BOS->str();
697+
}
698+
658699
// Declare success.
659700
if (!NoOutput || PrintBreakpoints)
660701
Out->keep();

0 commit comments

Comments
 (0)