John Bauman | 8940182 | 2014-05-06 15:04:28 -0400 | [diff] [blame] | 1 | #!/bin/bash
|
| 2 | #
|
| 3 | # findmisopt
|
| 4 | #
|
| 5 | # This is a quick and dirty hack to potentially find a misoptimization
|
| 6 | # problem. Mostly its to work around problems in bugpoint that prevent
|
| 7 | # it from finding a problem unless the set of failing optimizations are
|
| 8 | # known and given to it on the command line.
|
| 9 | #
|
John Bauman | 19bac1e | 2014-05-06 15:23:49 -0400 | [diff] [blame] | 10 | # Given a bitcode file that produces correct output (or return code),
|
John Bauman | 8940182 | 2014-05-06 15:04:28 -0400 | [diff] [blame] | 11 | # this script will run through all the optimizations passes that gccas
|
| 12 | # uses (in the same order) and will narrow down which optimizations
|
| 13 | # cause the program either generate different output or return a
|
| 14 | # different result code. When the passes have been narrowed down,
|
| 15 | # bugpoint is invoked to further refine the problem to its origin. If a
|
| 16 | # release version of bugpoint is available it will be used, otherwise
|
| 17 | # debug.
|
| 18 | #
|
| 19 | # Usage:
|
| 20 | # findmisopt bcfile outdir progargs [match]
|
| 21 | #
|
| 22 | # Where:
|
| 23 | # bcfile
|
John Bauman | 19bac1e | 2014-05-06 15:23:49 -0400 | [diff] [blame] | 24 | # is the bitcode file input (the unoptimized working case)
|
John Bauman | 8940182 | 2014-05-06 15:04:28 -0400 | [diff] [blame] | 25 | # outdir
|
| 26 | # is a directory into which intermediate results are placed
|
| 27 | # progargs
|
| 28 | # is a single argument containing all the arguments the program needs
|
| 29 | # proginput
|
| 30 | # is a file name from which stdin should be directed
|
| 31 | # match
|
| 32 | # if specified to any value causes the result code of the program to
|
| 33 | # be used to determine success/fail. If not specified success/fail is
|
| 34 | # determined by diffing the program's output with the non-optimized
|
| 35 | # output.
|
| 36 | #
|
| 37 | if [ "$#" -lt 3 ] ; then
|
| 38 | echo "usage: findmisopt bcfile outdir progargs [match]"
|
| 39 | exit 1
|
| 40 | fi
|
| 41 |
|
| 42 | dir="${0%%/utils/findmisopt}"
|
| 43 | if [ -x "$dir/Release/bin/bugpoint" ] ; then
|
| 44 | bugpoint="$dir/Release/bin/bugpoint"
|
| 45 | elif [ -x "$dir/Debug/bin/bugpoint" ] ; then
|
| 46 | bugpoint="$dir/Debug/bin/bugpoint"
|
| 47 | else
|
| 48 | echo "findmisopt: bugpoint not found"
|
| 49 | exit 1
|
| 50 | fi
|
| 51 |
|
| 52 | bcfile="$1"
|
| 53 | outdir="$2"
|
| 54 | args="$3"
|
| 55 | input="$4"
|
| 56 | if [ ! -f "$input" ] ; then
|
| 57 | input="/dev/null"
|
| 58 | fi
|
| 59 | match="$5"
|
| 60 | name=`basename $bcfile .bc`
|
| 61 | ll="$outdir/${name}.ll"
|
| 62 | s="$outdir/${name}.s"
|
| 63 | prog="$outdir/${name}"
|
| 64 | out="$outdir/${name}.out"
|
| 65 | optbc="$outdir/${name}.opt.bc"
|
| 66 | optll="$outdir/${name}.opt.ll"
|
| 67 | opts="$outdir/${name}.opt.s"
|
| 68 | optprog="$outdir/${name}.opt"
|
| 69 | optout="$outdir/${name}.opt.out"
|
| 70 | ldflags="-lstdc++ -lm -ldl -lc"
|
| 71 |
|
| 72 | echo "Test Name: $name"
|
| 73 | echo "Unoptimized program: $prog"
|
| 74 | echo " Optimized program: $optprog"
|
| 75 |
|
| 76 | # Define the list of optimizations to run. This comprises the same set of
|
| 77 | # optimizations that opt -std-compile-opts and gccld run, in the same order.
|
| 78 | opt_switches=`llvm-as < /dev/null -o - | opt -std-compile-opts -disable-output -debug-pass=Arguments 2>&1 | sed 's/Pass Arguments: //'`
|
| 79 | ld_switches=`llvm-as < /dev/null -o - | llvm-ld - -debug-pass=Arguments 2>&1 | sed 's/Pass Arguments: //'`
|
| 80 | all_switches="$opt_switches $ld_switches"
|
| 81 | echo "Passes : $all_switches"
|
| 82 |
|
| 83 | # Create output directory if it doesn't exist
|
| 84 | if [ -f "$outdir" ] ; then
|
| 85 | echo "$outdir is not a directory"
|
| 86 | exit 1
|
| 87 | fi
|
| 88 |
|
| 89 | if [ ! -d "$outdir" ] ; then
|
| 90 | mkdir "$outdir" || exit 1
|
| 91 | fi
|
| 92 |
|
| 93 | # Generate the disassembly
|
| 94 | llvm-dis "$bcfile" -o "$ll" -f || exit 1
|
| 95 |
|
| 96 | # Generate the non-optimized program and its output
|
| 97 | llc "$bcfile" -o "$s" -f || exit 1
|
| 98 | gcc "$s" -o "$prog" $ldflags || exit 1
|
| 99 | "$prog" $args > "$out" 2>&1 <$input
|
| 100 | ex1=$?
|
| 101 |
|
| 102 | # Current set of switches is empty
|
| 103 | function tryit {
|
| 104 | switches_to_use="$1"
|
| 105 | opt $switches_to_use "$bcfile" -o "$optbc" -f || exit
|
| 106 | llvm-dis "$optbc" -o "$optll" -f || exit
|
| 107 | llc "$optbc" -o "$opts" -f || exit
|
| 108 | gcc "$opts" -o "$optprog" $ldflags || exit
|
| 109 | "$optprog" $args > "$optout" 2>&1 <"$input"
|
| 110 | ex2=$?
|
| 111 |
|
| 112 | if [ -n "$match" ] ; then
|
| 113 | if [ "$ex1" -ne "$ex2" ] ; then
|
| 114 | echo "Return code not the same with these switches:"
|
| 115 | echo $switches
|
| 116 | echo "Unoptimized returned: $ex1"
|
| 117 | echo "Optimized returned: $ex2"
|
| 118 | return 0
|
| 119 | fi
|
| 120 | else
|
| 121 | diff "$out" "$optout" > /dev/null
|
| 122 | if [ $? -ne 0 ] ; then
|
| 123 | echo "Diff fails with these switches:"
|
| 124 | echo $switches
|
| 125 | echo "Differences:"
|
| 126 | diff "$out" "$optout" | head
|
| 127 | return 0;
|
| 128 | fi
|
| 129 | fi
|
| 130 | return 1
|
| 131 | }
|
| 132 |
|
| 133 | echo "Trying to find optimization that breaks program:"
|
| 134 | for sw in $all_switches ; do
|
| 135 | echo -n " $sw"
|
| 136 | switches="$switches $sw"
|
| 137 | if tryit "$switches" ; then
|
| 138 | break;
|
| 139 | fi
|
| 140 | done
|
| 141 |
|
| 142 | # Terminate the previous output with a newline
|
| 143 | echo ""
|
| 144 |
|
| 145 | # Determine if we're done because none of the optimizations broke the program
|
| 146 | if [ "$switches" == " $all_switches" ] ; then
|
| 147 | echo "The program did not miscompile"
|
| 148 | exit 0
|
| 149 | fi
|
| 150 |
|
| 151 | final=""
|
| 152 | while [ ! -z "$switches" ] ; do
|
| 153 | trimmed=`echo "$switches" | sed -e 's/^ *\(-[^ ]*\).*/\1/'`
|
| 154 | switches=`echo "$switches" | sed -e 's/^ *-[^ ]* *//'`
|
| 155 | echo "Trimmed $trimmed from left"
|
| 156 | tryit "$final $switches"
|
| 157 | if [ "$?" -eq "0" ] ; then
|
| 158 | echo "Still Failing .. continuing ..."
|
| 159 | continue
|
| 160 | else
|
| 161 | echo "Found required early pass: $trimmed"
|
| 162 | final="$final $trimmed"
|
| 163 | continue
|
| 164 | fi
|
| 165 | echo "Next Loop"
|
| 166 | done
|
| 167 |
|
| 168 | if [ "$final" == " $all_switches" ] ; then
|
| 169 | echo "findmisopt: All optimizations pass. Perhaps this isn't a misopt?"
|
| 170 | exit 0
|
| 171 | fi
|
| 172 | echo "Smallest Optimization list=$final"
|
| 173 |
|
| 174 | bpcmd="$bugpoint -run-llc -disable-loop-extraction --output "$out" --input /dev/null $bcfile $final --args $args"
|
| 175 |
|
| 176 | echo "Running: $bpcmd"
|
| 177 | $bpcmd
|
| 178 | echo "findmisopt finished."
|