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