add license to scripts I wrote
[libreriscv.git] / openpower / sv / insn-histogram.py
1 #! /bin/env python3
2 # see https://bugs.libre-soc.org/show_bug.cgi?id=532
3
4 # Print a per-opcode histogram for ppc asm.
5
6
7 # This script is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3, or (at your option)
10 # any later version.
11
12 # This script is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 # General Public License for more details.
16
17 # You should have received a copy of the GNU General Public License
18 # along with this script; see the file COPYING3. If not see
19 # <http://www.gnu.org/licenses/>.
20
21 # Originally by Alexandre Oliva <oliva@gnu.org>.
22
23
24 # Feed this script the output of:
25 # powerpc64le-gnu-objdump -d -M raw --no-show-raw-insn ppc-prog
26
27 # It will print the occurrence count of each opcode,
28 # and under it, indented by one character,
29 # the occurrence count of each operand.
30
31 # Registers used as operands or as base addresses are counted
32 # separately; immediates and offsets are grouped per bit length;
33 # branch target offsets are grouped by range bit length.
34
35 import sys
36 import re
37
38 insn = re.compile('\s+(?P<addr>[0-9a-f]+):\s+(?P<opcode>[^ \n]+) *(?P<operands>.*)[\n]?')
39
40 opkind = re.compile('(?P<immediate>-?[0-9]+)|(?P<branch>[0-9a-f]+)(?: <.*>)?|(?P<offset>-?[0-9]+)\((?P<basereg>r[0-9]+)\)')
41
42 histogram = {}
43
44 def count(ops, op):
45 match = opkind.fullmatch(op)
46
47 if match is None:
48 op = op
49 elif match['immediate'] is not None:
50 op = "%i-bit" % int (op).bit_length ()
51 elif match['branch'] is not None:
52 op = "%i-bit range" % (int (match['branch'], 16) -
53 int(addr, 16)).bit_length ()
54 elif match['offset'] is not None:
55 count(ops, match['offset'])
56 op = match['basereg']
57 else:
58 raise "unrecognized operand kind"
59
60 if op not in ops:
61 ops[op] = 1
62 else:
63 ops[op] += 1
64
65 for line in sys.stdin:
66 match = insn.fullmatch(line)
67 if match is None:
68 continue
69
70 addr = match['addr']
71 opcode = match['opcode']
72 operands = match['operands']
73
74 if opcode not in histogram:
75 ops = {}
76 histogram[opcode] = [1,ops]
77 else:
78 histogram[opcode][0] += 1
79 ops = histogram[opcode][1]
80
81 if len(operands) > 0:
82 for operand in operands.split(','):
83 count(ops, operand)
84
85 intregcounts = {}
86 crregcounts = {}
87
88 # for each instruction print out a regcount. first, sort by instr count
89 hist = list(histogram.items())
90 hist.sort(key = (lambda x : x[1][0]))
91
92 # now print each instruction and its register usage
93 for x in hist:
94 print('%6i %s:' % (x[1][0], x[0]))
95 ops = list(x[1][1].items())
96 ops.sort(key = (lambda x : x[1]))
97
98 # split out "-bit" from "-bit range" from "regs"
99
100 # first "rNs" or "anything-weird"
101 for x in ops:
102 if '-bit' in x[0]:
103 continue
104 if x[0].startswith('cr'):
105 continue
106 print('\t%6i %s' % (x[1], x[0]))
107 # total up integer register counts
108 if not x[0].startswith('r'):
109 continue
110 if not x[0] in intregcounts:
111 intregcounts[x[0]] = 0
112 intregcounts[x[0]] += x[1]
113 print()
114 # TODO: FP regs.
115 # ...
116
117 # now Condition Registers
118 for x in ops:
119 if '-bit' in x[0]:
120 continue
121 if x[0].startswith('cr'):
122 print('\t%6i %s' % (x[1], x[0]))
123 if not x[0] in crregcounts:
124 crregcounts[x[0]] = 0
125 crregcounts[x[0]] += x[1]
126 print()
127
128 # now "N-bit immediates"
129 for x in ops:
130 if x[0].endswith('-bit'):
131 print('\t%6i %s' % (x[1], x[0]))
132 print()
133
134 # finally "bit-range" immediates
135 for x in ops:
136 if '-bit range' in x[0]:
137 print('\t%6i %s' % (x[1], x[0]))
138 print()
139
140 # print out regs usage totals (TODO: FP)
141 for regcounts in [intregcounts, crregcounts]:
142 regnums = list(regcounts.items())
143 regnums.sort(key = (lambda x : x[1]))
144 for x in regnums:
145 print('%6i %s' % (x[1], x[0]))
146 print()