xref: /llvm-project/llvm/utils/findmisopt (revision 11aaaeebe0c7823d2b541504e83ebfb364bbebf2)
1e7355130SReid Spencer#!/bin/bash
2e7355130SReid Spencer#
3e7355130SReid Spencer#  findmisopt
4e7355130SReid Spencer#
5e7355130SReid Spencer#      This is a quick and dirty hack to potentially find a misoptimization
6e7355130SReid Spencer#      problem. Mostly its to work around problems in bugpoint that prevent
7e7355130SReid Spencer#      it from finding a problem unless the set of failing optimizations are
8e7355130SReid Spencer#      known and given to it on the command line.
9e7355130SReid Spencer#
10e9da6db6SDuncan Sands#      Given a bitcode file that produces correct output (or return code),
11e7355130SReid Spencer#      this script will run through all the optimizations passes that gccas
12e7355130SReid Spencer#      uses (in the same order) and will narrow down which optimizations
13e7355130SReid Spencer#      cause the program either generate different output or return a
14e7355130SReid Spencer#      different result code. When the passes have been narrowed down,
15b3030c42SReid Spencer#      bugpoint is invoked to further refine the problem to its origin. If a
16b3030c42SReid Spencer#      release version of bugpoint is available it will be used, otherwise
17b3030c42SReid Spencer#      debug.
18e7355130SReid Spencer#
19e7355130SReid Spencer#   Usage:
20e7355130SReid Spencer#      findmisopt bcfile outdir progargs [match]
21e7355130SReid Spencer#
22e7355130SReid Spencer#   Where:
23e7355130SReid Spencer#      bcfile
24e9da6db6SDuncan Sands#          is the bitcode file input (the unoptimized working case)
25e7355130SReid Spencer#      outdir
26e7355130SReid Spencer#          is a directory into which intermediate results are placed
27e7355130SReid Spencer#      progargs
28e7355130SReid Spencer#          is a single argument containing all the arguments the program needs
2968acb200SReid Spencer#      proginput
3068acb200SReid Spencer#          is a file name from which stdin should be directed
31e7355130SReid Spencer#      match
32e7355130SReid Spencer#          if specified to any value causes the result code of the program to
33e7355130SReid Spencer#          be used to determine success/fail. If not specified success/fail is
34e7355130SReid Spencer#          determined by diffing the program's output with the non-optimized
35e7355130SReid Spencer#          output.
36e7355130SReid Spencer#
37206d609cSReid Spencerif [ "$#" -lt 3 ] ; then
38206d609cSReid Spencer  echo "usage: findmisopt bcfile outdir progargs [match]"
39206d609cSReid Spencer  exit 1
40206d609cSReid Spencerfi
41206d609cSReid Spencer
42b3030c42SReid Spencerdir="${0%%/utils/findmisopt}"
43b3030c42SReid Spencerif [ -x "$dir/Release/bin/bugpoint" ] ; then
44b3030c42SReid Spencer  bugpoint="$dir/Release/bin/bugpoint"
45b3030c42SReid Spencerelif [ -x "$dir/Debug/bin/bugpoint" ] ; then
46b3030c42SReid Spencer  bugpoint="$dir/Debug/bin/bugpoint"
47b3030c42SReid Spencerelse
48b3030c42SReid Spencer  echo "findmisopt: bugpoint not found"
49b3030c42SReid Spencer  exit 1
50b3030c42SReid Spencerfi
51b3030c42SReid Spencer
52e7355130SReid Spencerbcfile="$1"
53e7355130SReid Spenceroutdir="$2"
54e7355130SReid Spencerargs="$3"
5568acb200SReid Spencerinput="$4"
5668acb200SReid Spencerif [ ! -f "$input" ] ; then
5768acb200SReid Spencer  input="/dev/null"
5868acb200SReid Spencerfi
5968acb200SReid Spencermatch="$5"
60e7355130SReid Spencername=`basename $bcfile .bc`
61e7355130SReid Spencerll="$outdir/${name}.ll"
62e7355130SReid Spencers="$outdir/${name}.s"
63e7355130SReid Spencerprog="$outdir/${name}"
64e7355130SReid Spencerout="$outdir/${name}.out"
65e7355130SReid Spenceroptbc="$outdir/${name}.opt.bc"
66e7355130SReid Spenceroptll="$outdir/${name}.opt.ll"
67e7355130SReid Spenceropts="$outdir/${name}.opt.s"
68e7355130SReid Spenceroptprog="$outdir/${name}.opt"
69e7355130SReid Spenceroptout="$outdir/${name}.opt.out"
705c09dd74SReid Spencerldflags="-lstdc++ -lm -ldl -lc"
71e7355130SReid Spencer
72e7355130SReid Spencerecho "Test Name: $name"
73e7355130SReid Spencerecho "Unoptimized program: $prog"
74e7355130SReid Spencerecho "  Optimized program: $optprog"
75e7355130SReid Spencer
76ab131789SReid Spencer# Define the list of optimizations to run. This comprises the same set of
77*11aaaeebSRafael Espindola# optimizations that opt -O3 runs, in the same order.
78*11aaaeebSRafael Espindolaopt_switches=`llvm-as < /dev/null -o - | opt -O3 -disable-output -debug-pass=Arguments 2>&1 | sed 's/Pass Arguments: //'`
799125493eSMichael J. Spencerall_switches="$opt_switches"
80ab131789SReid Spencerecho "Passes : $all_switches"
81ab131789SReid Spencer
82cac60e8eSReid Spencer# Create output directory if it doesn't exist
83cac60e8eSReid Spencerif [ -f "$outdir" ] ; then
84cac60e8eSReid Spencer  echo "$outdir is not a directory"
85cac60e8eSReid Spencer  exit 1
86cac60e8eSReid Spencerfi
87cac60e8eSReid Spencer
88cac60e8eSReid Spencerif [ ! -d "$outdir" ] ; then
89cac60e8eSReid Spencer  mkdir "$outdir" || exit 1
90cac60e8eSReid Spencerfi
91e7355130SReid Spencer
92e7355130SReid Spencer# Generate the disassembly
93e7355130SReid Spencerllvm-dis "$bcfile" -o "$ll" -f || exit 1
94e7355130SReid Spencer
9568acb200SReid Spencer# Generate the non-optimized program and its output
96e7355130SReid Spencerllc "$bcfile" -o "$s" -f || exit 1
975c09dd74SReid Spencergcc "$s" -o "$prog" $ldflags || exit 1
9868acb200SReid Spencer"$prog" $args > "$out" 2>&1 <$input
9968acb200SReid Spencerex1=$?
100e7355130SReid Spencer
101e7355130SReid Spencer# Current set of switches is empty
102e7355130SReid Spencerfunction tryit {
103e7355130SReid Spencer  switches_to_use="$1"
104e7355130SReid Spencer  opt $switches_to_use "$bcfile" -o "$optbc" -f || exit
105e7355130SReid Spencer  llvm-dis "$optbc" -o "$optll" -f || exit
106e7355130SReid Spencer  llc "$optbc" -o "$opts" -f || exit
1075c09dd74SReid Spencer  gcc "$opts" -o "$optprog" $ldflags || exit
10868acb200SReid Spencer  "$optprog" $args > "$optout" 2>&1 <"$input"
109e7355130SReid Spencer  ex2=$?
110e7355130SReid Spencer
111e7355130SReid Spencer  if [ -n "$match" ] ; then
112e7355130SReid Spencer    if [ "$ex1" -ne "$ex2" ] ; then
113e7355130SReid Spencer      echo "Return code not the same with these switches:"
114e7355130SReid Spencer      echo $switches
115e7355130SReid Spencer      echo "Unoptimized returned: $ex1"
116e7355130SReid Spencer      echo "Optimized   returned: $ex2"
117e7355130SReid Spencer      return 0
118e7355130SReid Spencer    fi
119e7355130SReid Spencer  else
120e7355130SReid Spencer    diff "$out" "$optout" > /dev/null
121e7355130SReid Spencer    if [ $? -ne 0 ] ; then
122e7355130SReid Spencer      echo "Diff fails with these switches:"
123e7355130SReid Spencer      echo $switches
124e7355130SReid Spencer      echo "Differences:"
1256984a156SReid Spencer      diff "$out" "$optout" | head
126e7355130SReid Spencer      return 0;
127e7355130SReid Spencer    fi
128e7355130SReid Spencer  fi
129e7355130SReid Spencer  return 1
130e7355130SReid Spencer}
131e7355130SReid Spencer
132cac60e8eSReid Spencerecho "Trying to find optimization that breaks program:"
133e7355130SReid Spencerfor sw in $all_switches ; do
134cac60e8eSReid Spencer  echo -n " $sw"
135e7355130SReid Spencer  switches="$switches $sw"
136e7355130SReid Spencer  if tryit "$switches" ; then
137e7355130SReid Spencer    break;
138e7355130SReid Spencer  fi
139e7355130SReid Spencerdone
140e7355130SReid Spencer
141fff57ce9SReid Spencer# Terminate the previous output with a newline
142fff57ce9SReid Spencerecho ""
143fff57ce9SReid Spencer
144fff57ce9SReid Spencer# Determine if we're done because none of the optimizations broke the program
145fff57ce9SReid Spencerif [ "$switches" == " $all_switches" ] ; then
146fff57ce9SReid Spencer  echo "The program did not miscompile"
147fff57ce9SReid Spencer  exit 0
148fff57ce9SReid Spencerfi
149fff57ce9SReid Spencer
150e7355130SReid Spencerfinal=""
151e7355130SReid Spencerwhile [ ! -z "$switches" ] ; do
152e7355130SReid Spencer  trimmed=`echo "$switches" | sed -e 's/^ *\(-[^ ]*\).*/\1/'`
153e7355130SReid Spencer  switches=`echo "$switches" | sed -e 's/^ *-[^ ]* *//'`
154e7355130SReid Spencer  echo "Trimmed $trimmed from left"
155e7355130SReid Spencer  tryit "$final $switches"
156e7355130SReid Spencer  if [ "$?" -eq "0" ] ; then
157e7355130SReid Spencer    echo "Still Failing .. continuing ..."
158e7355130SReid Spencer    continue
159e7355130SReid Spencer  else
160e7355130SReid Spencer    echo "Found required early pass: $trimmed"
161e7355130SReid Spencer    final="$final $trimmed"
162e7355130SReid Spencer    continue
163e7355130SReid Spencer  fi
164e7355130SReid Spencer  echo "Next Loop"
165e7355130SReid Spencerdone
166e7355130SReid Spencer
167c6389c10SReid Spencerif [ "$final" == " $all_switches" ] ; then
168cac60e8eSReid Spencer  echo "findmisopt: All optimizations pass. Perhaps this isn't a misopt?"
169c6389c10SReid Spencer  exit 0
170c6389c10SReid Spencerfi
171e7355130SReid Spencerecho "Smallest Optimization list=$final"
172b3030c42SReid Spencer
173b3030c42SReid Spencerbpcmd="$bugpoint -run-llc -disable-loop-extraction --output "$out" --input /dev/null $bcfile $final --args $args"
174e7355130SReid Spencer
175e7355130SReid Spencerecho "Running: $bpcmd"
176e7355130SReid Spencer$bpcmd
177c6389c10SReid Spencerecho "findmisopt finished."
178