Home | History | Annotate | Download | only in utils
      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 #
     10 #      Given a bitcode file that produces correct output (or return code), 
     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 
     24 #          is the bitcode file input (the unoptimized working case)
     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 -O3 runs, in the same order.
     78 opt_switches=`llvm-as < /dev/null -o - | opt -O3 -disable-output -debug-pass=Arguments 2>&1 | sed 's/Pass Arguments: //'`
     79 all_switches="$opt_switches"
     80 echo "Passes : $all_switches"
     81 
     82 # Create output directory if it doesn't exist
     83 if [ -f "$outdir" ] ; then
     84   echo "$outdir is not a directory"
     85   exit 1
     86 fi
     87 
     88 if [ ! -d "$outdir" ] ; then
     89   mkdir "$outdir" || exit 1
     90 fi
     91 
     92 # Generate the disassembly
     93 llvm-dis "$bcfile" -o "$ll" -f || exit 1
     94 
     95 # Generate the non-optimized program and its output
     96 llc "$bcfile" -o "$s" -f || exit 1
     97 gcc "$s" -o "$prog" $ldflags || exit 1
     98 "$prog" $args > "$out" 2>&1 <$input
     99 ex1=$?
    100 
    101 # Current set of switches is empty
    102 function tryit {
    103   switches_to_use="$1"
    104   opt $switches_to_use "$bcfile" -o "$optbc" -f || exit
    105   llvm-dis "$optbc" -o "$optll" -f || exit
    106   llc "$optbc" -o "$opts" -f || exit
    107   gcc "$opts" -o "$optprog" $ldflags || exit
    108   "$optprog" $args > "$optout" 2>&1 <"$input"
    109   ex2=$?
    110 
    111   if [ -n "$match" ] ; then
    112     if [ "$ex1" -ne "$ex2" ] ; then
    113       echo "Return code not the same with these switches:"
    114       echo $switches
    115       echo "Unoptimized returned: $ex1"
    116       echo "Optimized   returned: $ex2"
    117       return 0
    118     fi
    119   else
    120     diff "$out" "$optout" > /dev/null
    121     if [ $? -ne 0 ] ; then
    122       echo "Diff fails with these switches:"
    123       echo $switches
    124       echo "Differences:"
    125       diff "$out" "$optout" | head
    126       return 0;
    127     fi
    128   fi
    129   return 1
    130 }
    131 
    132 echo "Trying to find optimization that breaks program:"
    133 for sw in $all_switches ; do
    134   echo -n " $sw"
    135   switches="$switches $sw"
    136   if tryit "$switches" ; then
    137     break;
    138   fi
    139 done
    140 
    141 # Terminate the previous output with a newline
    142 echo ""
    143 
    144 # Determine if we're done because none of the optimizations broke the program
    145 if [ "$switches" == " $all_switches" ] ; then
    146   echo "The program did not miscompile"
    147   exit 0
    148 fi
    149 
    150 final=""
    151 while [ ! -z "$switches" ] ; do
    152   trimmed=`echo "$switches" | sed -e 's/^ *\(-[^ ]*\).*/\1/'`
    153   switches=`echo "$switches" | sed -e 's/^ *-[^ ]* *//'`
    154   echo "Trimmed $trimmed from left"
    155   tryit "$final $switches"
    156   if [ "$?" -eq "0" ] ; then
    157     echo "Still Failing .. continuing ..."
    158     continue
    159   else
    160     echo "Found required early pass: $trimmed"
    161     final="$final $trimmed"
    162     continue
    163   fi
    164   echo "Next Loop"
    165 done
    166 
    167 if [ "$final" == " $all_switches" ] ; then
    168   echo "findmisopt: All optimizations pass. Perhaps this isn't a misopt?"
    169   exit 0
    170 fi
    171 echo "Smallest Optimization list=$final"
    172 
    173 bpcmd="$bugpoint -run-llc -disable-loop-extraction --output "$out" --input /dev/null $bcfile $final --args $args"
    174 
    175 echo "Running: $bpcmd"
    176 $bpcmd
    177 echo "findmisopt finished."
    178