Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / clang / utils / check_cfc / obj_diff.py
blob99ed19e522be20c3e37e1f69b2f8721c4c72ef47
1 #!/usr/bin/env python
3 from __future__ import absolute_import, division, print_function
5 import argparse
6 import difflib
7 import filecmp
8 import os
9 import subprocess
10 import sys
12 disassembler = "objdump"
15 def keep_line(line):
16 """Returns true for lines that should be compared in the disassembly
17 output."""
18 return "file format" not in line
21 def disassemble(objfile):
22 """Disassemble object to a file."""
23 p = subprocess.Popen(
24 [disassembler, "-d", objfile], stdout=subprocess.PIPE, stderr=subprocess.PIPE
26 (out, err) = p.communicate()
27 if p.returncode or err:
28 print("Disassemble failed: {}".format(objfile))
29 sys.exit(1)
30 return [line for line in out.split(os.linesep) if keep_line(line)]
33 def dump_debug(objfile):
34 """Dump all of the debug info from a file."""
35 p = subprocess.Popen(
36 [disassembler, "-WliaprmfsoRt", objfile],
37 stdout=subprocess.PIPE,
38 stderr=subprocess.PIPE,
40 (out, err) = p.communicate()
41 if p.returncode or err:
42 print("Dump debug failed: {}".format(objfile))
43 sys.exit(1)
44 return [line for line in out.split(os.linesep) if keep_line(line)]
47 def first_diff(a, b, fromfile, tofile):
48 """Returns the first few lines of a difference, if there is one. Python
49 diff can be very slow with large objects and the most interesting changes
50 are the first ones. Truncate data before sending to difflib. Returns None
51 is there is no difference."""
53 # Find first diff
54 first_diff_idx = None
55 for idx, val in enumerate(a):
56 if val != b[idx]:
57 first_diff_idx = idx
58 break
60 if first_diff_idx == None:
61 # No difference
62 return None
64 # Diff to first line of diff plus some lines
65 context = 3
66 diff = difflib.unified_diff(
67 a[: first_diff_idx + context], b[: first_diff_idx + context], fromfile, tofile
69 difference = "\n".join(diff)
70 if first_diff_idx + context < len(a):
71 difference += "\n*** Diff truncated ***"
72 return difference
75 def compare_object_files(objfilea, objfileb):
76 """Compare disassembly of two different files.
77 Allowing unavoidable differences, such as filenames.
78 Return the first difference if the disassembly differs, or None.
79 """
80 disa = disassemble(objfilea)
81 disb = disassemble(objfileb)
82 return first_diff(disa, disb, objfilea, objfileb)
85 def compare_debug_info(objfilea, objfileb):
86 """Compare debug info of two different files.
87 Allowing unavoidable differences, such as filenames.
88 Return the first difference if the debug info differs, or None.
89 If there are differences in the code, there will almost certainly be differences in the debug info too.
90 """
91 dbga = dump_debug(objfilea)
92 dbgb = dump_debug(objfileb)
93 return first_diff(dbga, dbgb, objfilea, objfileb)
96 def compare_exact(objfilea, objfileb):
97 """Byte for byte comparison between object files.
98 Returns True if equal, False otherwise.
99 """
100 return filecmp.cmp(objfilea, objfileb)
103 if __name__ == "__main__":
104 parser = argparse.ArgumentParser()
105 parser.add_argument("objfilea", nargs=1)
106 parser.add_argument("objfileb", nargs=1)
107 parser.add_argument("-v", "--verbose", action="store_true")
108 args = parser.parse_args()
109 diff = compare_object_files(args.objfilea[0], args.objfileb[0])
110 if diff:
111 print("Difference detected")
112 if args.verbose:
113 print(diff)
114 sys.exit(1)
115 else:
116 print("The same")