findmisopt 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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. dir="${0%%/utils/findmisopt}"
  42. if [ -x "$dir/Release/bin/bugpoint" ] ; then
  43. bugpoint="$dir/Release/bin/bugpoint"
  44. elif [ -x "$dir/Debug/bin/bugpoint" ] ; then
  45. bugpoint="$dir/Debug/bin/bugpoint"
  46. else
  47. echo "findmisopt: bugpoint not found"
  48. exit 1
  49. fi
  50. bcfile="$1"
  51. outdir="$2"
  52. args="$3"
  53. input="$4"
  54. if [ ! -f "$input" ] ; then
  55. input="/dev/null"
  56. fi
  57. match="$5"
  58. name=`basename $bcfile .bc`
  59. ll="$outdir/${name}.ll"
  60. s="$outdir/${name}.s"
  61. prog="$outdir/${name}"
  62. out="$outdir/${name}.out"
  63. optbc="$outdir/${name}.opt.bc"
  64. optll="$outdir/${name}.opt.ll"
  65. opts="$outdir/${name}.opt.s"
  66. optprog="$outdir/${name}.opt"
  67. optout="$outdir/${name}.opt.out"
  68. ldflags="-lstdc++ -lm -ldl -lc"
  69. echo "Test Name: $name"
  70. echo "Unoptimized program: $prog"
  71. echo " Optimized program: $optprog"
  72. # Define the list of optimizations to run. This comprises the same set of
  73. # optimizations that opt -O3 runs, in the same order.
  74. opt_switches=`llvm-as < /dev/null -o - | opt -O3 -disable-output -debug-pass=Arguments 2>&1 | sed 's/Pass Arguments: //'`
  75. all_switches="$opt_switches"
  76. echo "Passes : $all_switches"
  77. # Create output directory if it doesn't exist
  78. if [ -f "$outdir" ] ; then
  79. echo "$outdir is not a directory"
  80. exit 1
  81. fi
  82. if [ ! -d "$outdir" ] ; then
  83. mkdir "$outdir" || exit 1
  84. fi
  85. # Generate the disassembly
  86. llvm-dis "$bcfile" -o "$ll" -f || exit 1
  87. # Generate the non-optimized program and its output
  88. llc "$bcfile" -o "$s" -f || exit 1
  89. gcc "$s" -o "$prog" $ldflags || exit 1
  90. "$prog" $args > "$out" 2>&1 <$input
  91. ex1=$?
  92. # Current set of switches is empty
  93. function tryit {
  94. switches_to_use="$1"
  95. opt $switches_to_use "$bcfile" -o "$optbc" -f || exit
  96. llvm-dis "$optbc" -o "$optll" -f || exit
  97. llc "$optbc" -o "$opts" -f || exit
  98. gcc "$opts" -o "$optprog" $ldflags || exit
  99. "$optprog" $args > "$optout" 2>&1 <"$input"
  100. ex2=$?
  101. if [ -n "$match" ] ; then
  102. if [ "$ex1" -ne "$ex2" ] ; then
  103. echo "Return code not the same with these switches:"
  104. echo $switches
  105. echo "Unoptimized returned: $ex1"
  106. echo "Optimized returned: $ex2"
  107. return 0
  108. fi
  109. else
  110. diff "$out" "$optout" > /dev/null
  111. if [ $? -ne 0 ] ; then
  112. echo "Diff fails with these switches:"
  113. echo $switches
  114. echo "Differences:"
  115. diff "$out" "$optout" | head
  116. return 0;
  117. fi
  118. fi
  119. return 1
  120. }
  121. echo "Trying to find optimization that breaks program:"
  122. for sw in $all_switches ; do
  123. echo -n " $sw"
  124. switches="$switches $sw"
  125. if tryit "$switches" ; then
  126. break;
  127. fi
  128. done
  129. # Terminate the previous output with a newline
  130. echo ""
  131. # Determine if we're done because none of the optimizations broke the program
  132. if [ "$switches" == " $all_switches" ] ; then
  133. echo "The program did not miscompile"
  134. exit 0
  135. fi
  136. final=""
  137. while [ ! -z "$switches" ] ; do
  138. trimmed=`echo "$switches" | sed -e 's/^ *\(-[^ ]*\).*/\1/'`
  139. switches=`echo "$switches" | sed -e 's/^ *-[^ ]* *//'`
  140. echo "Trimmed $trimmed from left"
  141. tryit "$final $switches"
  142. if [ "$?" -eq "0" ] ; then
  143. echo "Still Failing .. continuing ..."
  144. continue
  145. else
  146. echo "Found required early pass: $trimmed"
  147. final="$final $trimmed"
  148. continue
  149. fi
  150. echo "Next Loop"
  151. done
  152. if [ "$final" == " $all_switches" ] ; then
  153. echo "findmisopt: All optimizations pass. Perhaps this isn't a misopt?"
  154. exit 0
  155. fi
  156. echo "Smallest Optimization list=$final"
  157. bpcmd="$bugpoint -run-llc -disable-loop-extraction --output "$out" --input /dev/null $bcfile $final --args $args"
  158. echo "Running: $bpcmd"
  159. $bpcmd
  160. echo "findmisopt finished."