Skip to content

Instantly share code, notes, and snippets.

@jmorse
Last active December 7, 2023 17:52
Show Gist options
  • Save jmorse/2749e0654f7a06d86f10f0601954abc3 to your computer and use it in GitHub Desktop.
Save jmorse/2749e0654f7a06d86f10f0601954abc3 to your computer and use it in GitHub Desktop.
Example script for reducing problems with RemoveDIs.
### This is a script of me (jmorse) building and testing the "RemoveDIs"
### non-instruction based debug-info compiler, doing a stage2 clang build
### and comparing the object files to make sure they're identical. This
### includes a demo of how to reduce the differences if you find one.
### Comments all start with '###'.
###
### Note that to assure equivalence, you need to apply the series of patches
### at https://github.com/jmorse/llvm-project/tree/removedis-comparison-patches
### to match what dbg.value mode does bug-for-bug, and turn off three or four
### transformations that are too fiddly to get correct right now.
###
### To begin, build a compiler with the LLVM_EXPERIMENTAL_DEBUGINFO_ITERATORS
### cmake flag set to "ON".
% pwd
/fast/fs/llvm-stage
% mkdir build
% cd build
% /fast/fs/CMake/build/bin/cmake ../llvm -G Ninja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS=clang -DLLVM_EXPERIMENTAL_DEBUGINFO_ITERATORS=On
### Many lines of configuration removed.
% ninja clang
### Many lines of building removed.
### You now have a compiler and tooling with the extra debug-info bit built in.
### We'll use this compiler to do two stage2 RelWithDebInfo builds and compare them.
### First, we'll do one with the new debug-info mode turned off. Both builds
### with also have assignment tracking turned off as that's still being worked
### on.
% mkdir stage2-build
% cd stage2-build
% /fast/fs/CMake/build/bin/cmake ../llvm -G Ninja -DCMAKE_CXX_COMPILER=/fast/fs/llvm-stage/build/bin/clang++ -DCMAKE_C_COMPILER=/fast/fs/llvm-stage/build/bin/clang -DCMAKE_BUILD_TYPE=RelWithDebInfo -DLLVM_ENABLE_PROJECTS=clang -DCMAKE_CXX_FLAGS="-fno-ident -Xclang -fexperimental-assignment-tracking=disabled -mllvm -experimental-debuginfo-iterators=false" -DCMAKE_C_FLAGS="-fno-ident -Xclang -fexperimental-assignment-tracking=disabled -mllvm -experimental-debuginfo-iterators=false"
-- The CXX compiler identification is Clang 18.0.0
-- The ASM compiler identification is Clang
-- Found assembler: /fast/fs/llvm-stage/build/bin/clang
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /fast/fs/llvm-stage/build/bin/clang - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /fast/fs/llvm-stage/build/bin/clang++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- bolt project is disabled
-- clang project is enabled
### lots of configurating removed from here
-- Registering ExampleIRTransforms as a pass plugin (static build: OFF)
-- Registering Bye as a pass plugin (static build: OFF)
-- Configuring done
-- Generating done
-- Build files have been written to: /fast/fs/llvm-stage/stage2-build
% ninja clang
### removed lots of build lines...
[3879/3880] Linking CXX executable bin/clang-18
[3879/3880] Creating executable symlink bin/clang
[3880/3880] Creating executable symlink bin/clang
### We've successfully built a stage2 clang in normal dbg.value mode. Let's save
### a copy and then do it again in RemoveDIs mode, by setting the command line
### flag to true.
% cd ..
% cp -r stage2-build REF-stage2-build
% cd stage2-build
% ninja clean
[0/1] Cleaning all built files...
[1/1] Cleaning all built files...
Cleaning... 4214 files.
### Re-configure the build to be in RemoveDIs mode by setting the command line
### flag, -experimental-debuginfo-iterators, to true.
% /fast/fs/CMake/build/bin/cmake ../llvm -G Ninja -DCMAKE_CXX_COMPILER=/fast/fs/llvm-stage/build/bin/clang++ -DCMAKE_C_COMPILER=/fast/fs/llvm-stage/build/bin/clang -DTEST_SUITE_RUN_BENCHMARKS=0 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DLLVM_ENABLE_PROJECTS=clang -DCMAKE_CXX_FLAGS="-fno-ident -Xclang -fexperimental-assignment-tracking=disabled -mllvm -experimental-debuginfo-iterators=true" -DCMAKE_C_FLAGS="-fno-ident -Xclang -fexperimental-assignment-tracking=disabled -mllvm -experimental-debuginfo-iterators=true"
-- clang project is enabled
-- clang-tools-extra project is disabled
-- compiler-rt project is disabled
-- cross-project-tests project is disabled
-- libc project is disabled
-- libclc project is disabled
-- lld project is disabled
-- lldb project is disabled
-- mlir project is disabled
-- openmp project is disabled
-- polly project is disabled
-- pstl project is disabled
-- flang project is disabled
### removed lots of configurating
-- Targeting X86
-- Targeting XCore
-- Clang version: 18.0.0git
-- Registering ExampleIRTransforms as a pass plugin (static build: OFF)
-- Registering Bye as a pass plugin (static build: OFF)
-- Configuring done
-- Generating done
-- Build files have been written to: /fast/fs/llvm-stage/stage2-build
% ninja clang
### removed many build lines
[3879/3880] Creating executable symlink bin/clang
[3880/3880] Creating executable symlink bin/clang
### We now have two builds -- let's compare whether or not they have identical
### object files. We're going to list all the files in one build dir, filter for
### object files, pick out the common name component. Then for each object file
### compare the copy in REF-stage2-build (which we built in dbg.value mode) with
### the copy in stage2-build, which we just built in RemoveDIs mode.
% cd ..
% find stage2-build | grep \\.cpp\.o$ | sed s_stage2-build/__g | while read x; do cmp stage2-build/$x REF-stage2-build/$x; done
stage2-build/lib/Target/Hexagon/CMakeFiles/LLVMHexagonCodeGen.dir/HexagonISelDAGToDAG.cpp.o REF-stage2-build/lib/Target/Hexagon/CMakeFiles/LLVMHexagonCodeGen.dir/HexagonISelDAGToDAG.cpp.o differ: byte 41, line 1
stage2-build/lib/CodeGen/CMakeFiles/LLVMCodeGen.dir/CFIInstrInserter.cpp.o REF-stage2-build/lib/CodeGen/CMakeFiles/LLVMCodeGen.dir/CFIInstrInserter.cpp.o differ: byte 41, line 1
### There are two files that are different unfortunately. Let's examine one,
### first by rebuilding it to collect it's build command line:
% cd stage2-build
% rm lib/CodeGen/CMakeFiles/LLVMCodeGen.dir/CFIInstrInserter.cpp.o
% ninja -v lib/CodeGen/CMakeFiles/LLVMCodeGen.dir/CFIInstrInserter.cpp.o
ninja[1/1] /fast/fs/llvm-stage/build/bin/clang++ -DEXPERIMENTAL_DEBUGINFO_ITERATORS -DGTEST_HAS_RTTI=0 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Ilib/CodeGen -I/fast/fs/llvm-stage/llvm/lib/CodeGen -Iinclude -I/fast/fs/llvm-stage/llvm/include -fno-ident -Xclang -fexperimental-assignment-tracking=disabled -mllvm -experimental-debuginfo-iterators=true -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wno-comment -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -O2 -g -DNDEBUG -fno-exceptions -funwind-tables -fno-rtti -std=c++17 -MD -MT lib/CodeGen/CMakeFiles/LLVMCodeGen.dir/CFIInstrInserter.cpp.o -MF lib/CodeGen/CMakeFiles/LLVMCodeGen.dir/CFIInstrInserter.cpp.o.d -o lib/CodeGen/CMakeFiles/LLVMCodeGen.dir/CFIInstrInserter.cpp.o -c /fast/fs/llvm-stage/llvm/lib/CodeGen/CFIInstrInserter.cpp
### Now, we'll remove the normal output object file, and instead emit LLVM
### bitcode. We'll also turn off the LLVM optimisation passes (don't use -O0!)
### so that we get the untransformed output of clang (disable-llvm-passes).
% /fast/fs/llvm-stage/build/bin/clang++ -DEXPERIMENTAL_DEBUGINFO_ITERATORS -DGTEST_HAS_RTTI=0 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Ilib/CodeGen -I/fast/fs/llvm-stage/llvm/lib/CodeGen -Iinclude -I/fast/fs/llvm-stage/llvm/include -fno-ident -Xclang -fexperimental-assignment-tracking=disabled -mllvm -experimental-debuginfo-iterators=true -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wno-comment -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -O2 -g -DNDEBUG -fno-exceptions -funwind-tables -fno-rtti -std=c++17 -MD -MT lib/CodeGen/CMakeFiles/LLVMCodeGen.dir/CFIInstrInserter.cpp.o -MF lib/CodeGen/CMakeFiles/LLVMCodeGen.dir/CFIInstrInserter.cpp.o.d -c /fast/fs/llvm-stage/llvm/lib/CodeGen/CFIInstrInserter.cpp -o out.bc -emit-llvm -Xclang -disable-llvm-passes
### We'll use llvm-reduce to narrow down what the problem is. An example test
### script is below: it uses opt on the bitcode file, with the O2 optimisation
### pipeline, and compares whether the output in dbg.value mode is different
### to the output in RemoveDIs mode.
% cat diff.sh
#!/bin/sh
/fast/fs/llvm-stage/build/bin/opt --experimental-debuginfo-iterators=false $1 -O2 -o optgood.ll -S $2
if test $? != 0; then
exit 1;
fi
/fast/fs/llvm-stage/build/bin/opt --experimental-debuginfo-iterators=true $1 -O2 -o optbad.ll -S $2
if test $? != 0; then
exit 1;
fi
cmp optgood.ll optbad.ll
if test $? = 0; then
exit 1;
fi
exit 0
% /fast/fs/llvm-stage/build/bin/llvm-reduce --test ./diff.sh out.bc --write-tmp-files-as-bitcode
*** Stripping Debug Info...
optgood.ll optbad.ll differ: byte 34961, line 332
----------------------------
*** Reducing Functions...
optgood.ll optbad.ll differ: byte 34961, line 332
optgood.ll optbad.ll differ: byte 23368, line 222
optgood.ll optbad.ll differ: byte 15573, line 148
optgood.ll optbad.ll differ: byte 6904, line 72
optgood.ll optbad.ll differ: byte 5775, line 59
optgood.ll optbad.ll differ: byte 5610, line 58
optgood.ll optbad.ll differ: byte 4549, line 51
optgood.ll optbad.ll differ: byte 4549, line 51
optgood.ll optbad.ll differ: byte 4549, line 51
optgood.ll optbad.ll differ: byte 4549, line 51
optgood.ll optbad.ll differ: byte 4350, line 48
optgood.ll optbad.ll differ: byte 2353, line 34
**** SUCCESS | Saved new best reduction to reduced.bc
### lots of reducing removed
**** SUCCESS | Saved new best reduction to reduced.bc
----------------------------
done reducing! reduced testcase: reduced.bc
### Now that we've reduced down to a small bitcode file, we can use bisect and
### opt-bisect-limit to narrow down which optimisation pass the problem is in.
% cat diff-bisect.sh
#!/bin/sh
count=$1
file=reduced.bc
/fast/fs/llvm-stage/build/bin/opt --experimental-debuginfo-iterators=false $file -o2 -o optgood.ll -s --opt-bisect-limit=$count
if test $? != 0; then
exit 1;
fi
/fast/fs/llvm-stage/build/bin/opt --experimental-debuginfo-iterators=true $file -o2 -o optbad.ll -s --opt-bisect-limit=$count
if test $? != 0; then
exit 1;
fi
cmp optgood.ll optbad.ll
if test $? = 0; then
exit 0;
fi
exit 1
% python3 /fast/fs/llvm-stage/llvm/utils/bisect --start 0 --end 1000 ./diff-bisect.sh "%(count)s"
bisect starting!
start: 0
end: 1000
visiting count: 500 with (start, end) = (0,1000)
['./diff-bisect.sh', '500']
bisect: running pass (1) annotation2metadatapass on [module]
bisect: running pass (2) forcefunctionattrspass on [module]
bisect: running pass (3) inferfunctionattrspass on [module]
bisect: running pass (4) lowerexpectintrinsicpass on _zn12_global__n_116cfiinstrinserterc2ev
bisect: running pass (5) simplifycfgpass on _zn12_global__n_116cfiinstrinserterc2ev
bisect: running pass (6) sroapass on _zn12_global__n_116cfiinstrinserterc2ev
bisect: running pass (7) earlycsepass on _zn12_global__n_116cfiinstrinserterc2ev
bisect: running pass (8) openmpoptpass on [module]
bisect: running pass (9) ipsccppass on [module]
bisect: running pass (10) calledvaluepropagationpass on [module]
bisect: running pass (11) globaloptpass on [module]
### skipped a load of bisection messages
last good count: 10
%
### We now have reduced.bc that contains the reduced LLVM-IR reproducer for the
### difference, and we know it's pass 10 that's causing the difference. Now to
### file an issue and CC the relevant people on it (not shown!)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment