009cd1406f6c270243dd5b193cd549061eb22862
2 # see https://bugs.libre-soc.org/show_bug.cgi?id=532
4 # Estimate ppc code compression with Libre-SOC encoding attempt v2.
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)
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.
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/>.
21 # Skeleton originally by Alexandre Oliva <oliva@gnu.org>.
24 # Feed this script the output of objdump -M raw --no-show-raw-insn ppc-prog
26 # It will look for insns that can be represented in compressed mode,
27 # according to the encoding rules in the copcond dictionary below.
28 # Nothing is assumed as to the actual bit-encoding of the insns, this
29 # is just to experiment with insn selection and get a quick feedback
30 # loop for the encoding options in compressed mode.
32 # In this script, the computations of encoding modes and transitions
33 # are tuned for the simpler model that uses 1-byte nops for
34 # transitions in and out of compressed mode, placing compressed-mode
35 # insns at odd addresses. At (visible) entry points, mode is forced
36 # to return to uncompressed mode.
38 # The entire code stream is printed, without any attempt to modify the
39 # addresses that go along with or in them; we only insert markers for
40 # the transition points, and for the compressed instructions.
42 # The really useful information is printed at the end: a summary of
43 # transition and compressed-insn counts, and the achieved compression
49 insn
= re
.compile('\s+(?P<addr>[0-9a-f]+):\s+(?P<opcode>[^ ]+) *(?P<operands>.*)')
51 opkind
= re
.compile('(?P<reg>(?P<regkind>[cf]?r)(?P<regnum>[0-9]+))|(?P<immediate>-?[0-9]+)|(?P<branch>[0-9a-f]+)(?: <.*>)?|(?P<offset>-?[0-9]+)\((?P<basereg>r[0-9]+)\)')
54 match
= opkind
.fullmatch(op
)
58 elif match
['reg'] is not None:
59 op
= (match
['regkind'], int(match
['regnum']))
60 elif match
['immediate'] is not None:
61 op
= ('imm', int (op
).bit_length ())
62 elif match
['branch'] is not None:
63 op
= ('pcoff', (int (match
['branch'], 16)
64 - int (addr
, 16)).bit_length ())
65 elif match
['offset'] is not None:
66 op
= ('ofst', mapop(match
['offset']), mapop(match
['basereg']))
68 raise "unrecognized operand kind"
75 if mop
[0] in { 'r', 'fr', 'cr' }:
78 raise "operand is not a register"
84 raise "operand is not an immediate"
86 # Following are predicates to be used in copcond, to tell the mode in
87 # which opcode with ops as operands is to be represented
89 # Any occurrence of the opcode can be compressed.
90 def anyops(opcode
, ops
):
93 # Compress iff first and second operands are the same.
94 def same01(opcode
, ops
):
100 # Registers representable in a made-up 3-bit mapping.
101 cregs2
= { 1, 2, 3, 4, 5, 6, 7, 31 }
103 # Return true iff mop is a regular register present in cregs2
105 return opclass(mop
) is 'r' and regno(mop
) in cregs2
107 # Return true iff mop is an immediate of at most 8 bits.
109 return opclass(mop
) is 'imm' and immbits(mop
) <= 8
111 # Compress binary opcodes iff the first two operands (output and first
112 # input operand) are registers representable in 3 bits in compressed
113 # mode, and the immediate operand can be represented in 8 bits.
114 def bin2regs3imm8(opcode
, ops
):
115 if bin2regs3(ops
[0]) and bin2regs3(ops
[1]) and imm8(ops
[2]):
120 # Map opcodes that might be compressed to a function that returns the
121 # mode (index into mode_list below) in which the insn is to be
122 # represented. Those not mentioned in copcond are assumed
125 # Pretending anything goes, just for demonstration purposes.
129 # Output and first input operand must coincide for these.
132 # Limiting register and operand range:
133 'addi': bin2regs3imm8
134 # Anything else is uncompressed.
140 count_uncompressed
= 0
142 mode_list
= ['Uncompressed', 'Compressed'] # for documentation purposes only
144 for line
in sys
.stdin
:
148 match
= insn
.fullmatch(line
)
151 # Switch to uncompressed mode at function boundaries
152 if current_mode
is not 0:
153 print('<leave compressed mode>')
155 leave_compressed
+= 1
159 opcode
= match
['opcode']
160 operands
= match
['operands']
162 if opcode
in copcond
:
163 this_mode
= copcond
[opcode
](opcode
,
164 [mapop(op
) for op
in operands
.split(',')])
169 if current_mode
is not 1:
172 enter_compressed
+= 1
174 count_compressed
+= 1
176 if current_mode
is not 0:
177 print('\t\tcout.nop')
179 leave_compressed
+= 1
181 count_uncompressed
+= 1
183 transition_bytes
= 1 * enter_compressed
+ 1 * leave_compressed
184 compressed_bytes
= 2 * count_compressed
185 uncompressed_bytes
= 4 * count_uncompressed
186 total_bytes
= transition_bytes
+ compressed_bytes
+ uncompressed_bytes
187 original_bytes
= 2 * compressed_bytes
+ uncompressed_bytes
191 print('Compressed instructions: %i' % count_compressed
)
192 print('Uncompressed instructions: %i' % count_uncompressed
)
193 print('Transitions into compressed mode: %i' % enter_compressed
)
194 print('Transitions out of compressed mode: %i' % leave_compressed
)
195 print('Compressed size estimate: %i' % total_bytes
)
196 print('Original size: %i' % original_bytes
)
197 print('Compressed/original ratio: %f' % (total_bytes
/ original_bytes
))