178 lines · plain
1#!/bin/bash2#3# findmisopt4#5# This is a quick and dirty hack to potentially find a misoptimization6# problem. Mostly its to work around problems in bugpoint that prevent7# it from finding a problem unless the set of failing optimizations are8# 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 gccas12# uses (in the same order) and will narrow down which optimizations13# 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 a16# 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# outdir26# is a directory into which intermediate results are placed27# progargs28# is a single argument containing all the arguments the program needs29# proginput30# is a file name from which stdin should be directed31# match32# if specified to any value causes the result code of the program to33# be used to determine success/fail. If not specified success/fail is34# determined by diffing the program's output with the non-optimized35# output.36# 37if [ "$#" -lt 3 ] ; then38 echo "usage: findmisopt bcfile outdir progargs [match]"39 exit 140fi41 42dir="${0%%/utils/findmisopt}"43if [ -x "$dir/Release/bin/bugpoint" ] ; then44 bugpoint="$dir/Release/bin/bugpoint"45elif [ -x "$dir/Debug/bin/bugpoint" ] ; then46 bugpoint="$dir/Debug/bin/bugpoint"47else48 echo "findmisopt: bugpoint not found"49 exit 150fi51 52bcfile="$1"53outdir="$2"54args="$3"55input="$4"56if [ ! -f "$input" ] ; then57 input="/dev/null"58fi59match="$5"60name=`basename $bcfile .bc`61ll="$outdir/${name}.ll"62s="$outdir/${name}.s"63prog="$outdir/${name}"64out="$outdir/${name}.out"65optbc="$outdir/${name}.opt.bc"66optll="$outdir/${name}.opt.ll"67opts="$outdir/${name}.opt.s"68optprog="$outdir/${name}.opt"69optout="$outdir/${name}.opt.out"70ldflags="-lstdc++ -lm -ldl -lc"71 72echo "Test Name: $name"73echo "Unoptimized program: $prog"74echo " 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.78opt_switches=`llvm-as < /dev/null -o - | opt -O3 -disable-output -debug-pass=Arguments 2>&1 | sed 's/Pass Arguments: //'`79all_switches="$opt_switches"80echo "Passes : $all_switches"81 82# Create output directory if it doesn't exist83if [ -f "$outdir" ] ; then84 echo "$outdir is not a directory"85 exit 186fi87 88if [ ! -d "$outdir" ] ; then89 mkdir "$outdir" || exit 190fi91 92# Generate the disassembly93llvm-dis "$bcfile" -o "$ll" -f || exit 194 95# Generate the non-optimized program and its output96llc "$bcfile" -o "$s" -f || exit 197gcc "$s" -o "$prog" $ldflags || exit 198"$prog" $args > "$out" 2>&1 <$input99ex1=$?100 101# Current set of switches is empty102function tryit {103 switches_to_use="$1"104 opt $switches_to_use "$bcfile" -o "$optbc" -f || exit105 llvm-dis "$optbc" -o "$optll" -f || exit106 llc "$optbc" -o "$opts" -f || exit107 gcc "$opts" -o "$optprog" $ldflags || exit108 "$optprog" $args > "$optout" 2>&1 <"$input"109 ex2=$?110 111 if [ -n "$match" ] ; then112 if [ "$ex1" -ne "$ex2" ] ; then113 echo "Return code not the same with these switches:"114 echo $switches115 echo "Unoptimized returned: $ex1"116 echo "Optimized returned: $ex2"117 return 0118 fi119 else120 diff "$out" "$optout" > /dev/null121 if [ $? -ne 0 ] ; then122 echo "Diff fails with these switches:"123 echo $switches124 echo "Differences:"125 diff "$out" "$optout" | head126 return 0;127 fi128 fi129 return 1130}131 132echo "Trying to find optimization that breaks program:"133for sw in $all_switches ; do134 echo -n " $sw"135 switches="$switches $sw"136 if tryit "$switches" ; then137 break;138 fi139done140 141# Terminate the previous output with a newline142echo ""143 144# Determine if we're done because none of the optimizations broke the program145if [ "$switches" == " $all_switches" ] ; then146 echo "The program did not miscompile"147 exit 0148fi149 150final=""151while [ ! -z "$switches" ] ; do152 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" ] ; then157 echo "Still Failing .. continuing ..."158 continue159 else160 echo "Found required early pass: $trimmed"161 final="$final $trimmed"162 continue163 fi164 echo "Next Loop"165done166 167if [ "$final" == " $all_switches" ] ; then168 echo "findmisopt: All optimizations pass. Perhaps this isn't a misopt?"169 exit 0170fi171echo "Smallest Optimization list=$final"172 173bpcmd="$bugpoint -run-llc -disable-loop-extraction --output "$out" --input /dev/null $bcfile $final --args $args"174 175echo "Running: $bpcmd"176$bpcmd177echo "findmisopt finished."178