findmisopt revision f8463a38bf04b822d009e9e4eaae2e4a3c930da4
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 bytecode 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 bytecode 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# match 30# if specified to any value causes the result code of the program to 31# be used to determine success/fail. If not specified success/fail is 32# determined by diffing the program's output with the non-optimized 33# output. 34# 35if [ "$#" -lt 3 ] ; then 36 echo "usage: findmisopt bcfile outdir progargs [match]" 37 exit 1 38fi 39 40dir="${0%%/utils/findmisopt}" 41if [ -x "$dir/Release/bin/bugpoint" ] ; then 42 bugpoint="$dir/Release/bin/bugpoint" 43elif [ -x "$dir/Debug/bin/bugpoint" ] ; then 44 bugpoint="$dir/Debug/bin/bugpoint" 45else 46 echo "findmisopt: bugpoint not found" 47 exit 1 48fi 49 50bcfile="$1" 51outdir="$2" 52args="$3" 53match="$4" 54name=`basename $bcfile .bc` 55ll="$outdir/${name}.ll" 56s="$outdir/${name}.s" 57prog="$outdir/${name}" 58out="$outdir/${name}.out" 59optbc="$outdir/${name}.opt.bc" 60optll="$outdir/${name}.opt.ll" 61opts="$outdir/${name}.opt.s" 62optprog="$outdir/${name}.opt" 63optout="$outdir/${name}.opt.out" 64ldflags="-lstdc++ -lm -ldl -lc" 65 66echo "Test Name: $name" 67echo "Unoptimized program: $prog" 68echo " Optimized program: $optprog" 69 70# Create output directory if it doesn't exist 71if [ -f "$outdir" ] ; then 72 echo "$outdir is not a directory" 73 exit 1 74fi 75 76if [ ! -d "$outdir" ] ; then 77 mkdir "$outdir" || exit 1 78fi 79 80# Generate the disassembly 81llvm-dis "$bcfile" -o "$ll" -f || exit 1 82 83# Generate the non-optimized program 84llc "$bcfile" -o "$s" -f || exit 1 85gcc "$s" -o "$prog" $ldflags || exit 1 86 87# Define the list of optimizations to run. This comprises the same set of 88# optimizations that gccas and gccld run, in the same order. 89all_switches="-verify -lowersetjmp -funcresolve -raiseallocs -simplifycfg -mem2reg -globalopt -globaldce -ipconstprop -deadargelim -instcombine -simplifycfg -prune-eh -inline -simplify-libcalls -argpromotion -raise -tailduplicate -simplifycfg -scalarrepl -instcombine -predsimplify -condprop -tailcallelim -simplifycfg -reassociate -licm -loop-unswitch -instcombine -indvars -loop-unroll -instcombine -load-vn -gcse -sccp -instcombine -condprop -dse -dce -simplifycfg -deadtypeelim -constmerge -funcresolve -internalize -ipsccp -globalopt -constmerge -deadargelim -inline -prune-eh -globalopt -globaldce -argpromotion -instcombine -predsimplify -scalarrepl -globalsmodref-aa -licm -load-vn -gcse -dse -instcombine -simplifycfg -verify" 90# Here's an alternative list of optimizations comprising just the ones that 91# gccld uses. To use, just comment out the line above, and uncomment this one 92#all_switches="-funcresolve -internalize -ipsccp -globalopt -constmerge -deadargelim -inline -prune-eh -globalopt -globaldce -argpromotion -instcombine -predsimplify -scalarrepl -globalsmodref-aa -licm -load-vn -gcse -dse -instcombine -simplifycfg -verify" 93 94# Current set of switches is empty 95function tryit { 96 switches_to_use="$1" 97 opt $switches_to_use "$bcfile" -o "$optbc" -f || exit 98 llvm-dis "$optbc" -o "$optll" -f || exit 99 llc "$optbc" -o "$opts" -f || exit 100 gcc "$opts" -o "$optprog" $ldflags || exit 101 "$prog" $args > "$out" 2>&1 102 ex1=$? 103 "$optprog" $args > "$optout" 2>&1 104 ex2=$? 105 106 if [ -n "$match" ] ; then 107 if [ "$ex1" -ne "$ex2" ] ; then 108 echo "Return code not the same with these switches:" 109 echo $switches 110 echo "Unoptimized returned: $ex1" 111 echo "Optimized returned: $ex2" 112 return 0 113 fi 114 else 115 diff "$out" "$optout" > /dev/null 116 if [ $? -ne 0 ] ; then 117 echo "Diff fails with these switches:" 118 echo $switches 119 echo "Differences:" 120 diff "$out" "$optout" | head 121 return 0; 122 fi 123 fi 124 return 1 125} 126 127echo "Trying to find optimization that breaks program:" 128for sw in $all_switches ; do 129 echo -n " $sw" 130 switches="$switches $sw" 131 if tryit "$switches" ; then 132 break; 133 fi 134done 135 136# Terminate the previous output with a newline 137echo "" 138 139# Determine if we're done because none of the optimizations broke the program 140if [ "$switches" == " $all_switches" ] ; then 141 echo "The program did not miscompile" 142 exit 0 143fi 144 145final="" 146while [ ! -z "$switches" ] ; do 147 trimmed=`echo "$switches" | sed -e 's/^ *\(-[^ ]*\).*/\1/'` 148 switches=`echo "$switches" | sed -e 's/^ *-[^ ]* *//'` 149 echo "Trimmed $trimmed from left" 150 tryit "$final $switches" 151 if [ "$?" -eq "0" ] ; then 152 echo "Still Failing .. continuing ..." 153 continue 154 else 155 echo "Found required early pass: $trimmed" 156 final="$final $trimmed" 157 continue 158 fi 159 echo "Next Loop" 160done 161 162if [ "$final" == " $all_switches" ] ; then 163 echo "findmisopt: All optimizations pass. Perhaps this isn't a misopt?" 164 exit 0 165fi 166echo "Smallest Optimization list=$final" 167 168bpcmd="$bugpoint -run-llc -disable-loop-extraction --output "$out" --input /dev/null $bcfile $final --args $args" 169 170echo "Running: $bpcmd" 171$bpcmd 172echo "findmisopt finished." 173