comp16-v2-skel: add comments to the effect that it's a skeleton
[libreriscv.git] / lxo / 532 / comp16-v2-skel.py
1 #! /bin/env python3
2
3 # Feed this script the output of objdump -M raw --no-show-raw-insn ppc-prog
4
5 # It will look for insns that can be represented in compressed mode,
6 # according to the encoding rules in the copcond dictionary below.
7 # It's just a skeleton for testing of the logic,
8 # the encoding rules are yet to be filled in.
9
10 # Nothing is assumed as to the actual bit-encoding of the insns, this
11 # is just to experiment with insn selection and get a quick feedback
12 # loop for the encoding options in compressed mode.
13
14 # In this script, the computations of encoding modes and transitions
15 # are tuned for the simpler model that uses 1-byte nops for
16 # transitions in and out of compressed mode, placing compressed-mode
17 # insns at odd addresses. At (visible) entry points, mode is forced
18 # to return to uncompressed mode.
19
20 # The entire code stream is printed, without any attempt to modify the
21 # addresses that go along with or in them; we only insert markers for
22 # the transition points, and for the compressed instructions.
23
24 # The really useful information is printed at the end: a summary of
25 # transition and compressed-insn counts, and the achieved compression
26 # rate.
27
28 import sys
29 import re
30
31 insn = re.compile('\s+(?P<addr>[0-9a-f]+):\s+(?P<opcode>[^ ]+) *(?P<operands>.*)')
32
33 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]+)\)')
34
35 def mapop(op):
36 match = opkind.fullmatch(op)
37
38 if match is None:
39 op = ('other', op)
40 elif match['reg'] is not None:
41 op = (match['regkind'], int(match['regnum']))
42 elif match['immediate'] is not None:
43 op = ('imm', int (op).bit_length ())
44 elif match['branch'] is not None:
45 op = ('pcoff', (int (match['branch'], 16)
46 - int (addr, 16)).bit_length ())
47 elif match['offset'] is not None:
48 op = ('ofst', mapop(match['offset']), mapop(match['basereg']))
49 else:
50 raise "unrecognized operand kind"
51
52 return op
53
54 def opclass(mop):
55 return mop[0]
56 def regno(mop):
57 if mop[0] in { 'r', 'fr', 'cr' }:
58 return mop[1]
59 else:
60 raise "operand is not a register"
61
62 def immbits(mop):
63 if mop[0] is 'imm':
64 return mop[1]
65 else:
66 raise "operand is not an immediate"
67
68 # Following are predicates to be used in copcond, to tell the mode in
69 # which opcode with ops as operands is to be represented
70
71 # Any occurrence of the opcode can be compressed.
72 def anyops(opcode, ops):
73 return 1
74
75 # Compress iff first and second operands are the same.
76 def same01(opcode, ops):
77 if ops[0] == ops[1]:
78 return 1
79 else:
80 return 0
81
82 # Registers representable in a made-up 3-bit mapping.
83 cregs2 = { 1, 2, 3, 4, 5, 6, 7, 31 }
84
85 # Return true iff mop is a regular register present in cregs2
86 def bin2regs3(mop):
87 return opclass(mop) is 'r' and regno(mop) in cregs2
88
89 # Return true iff mop is an immediate of at most 8 bits.
90 def imm8(mop):
91 return opclass(mop) is 'imm' and immbits(mop) <= 8
92
93 # Compress binary opcodes iff the first two operands (output and first
94 # input operand) are registers representable in 3 bits in compressed
95 # mode, and the immediate operand can be represented in 8 bits.
96 def bin2regs3imm8(opcode, ops):
97 if bin2regs3(ops[0]) and bin2regs3(ops[1]) and imm8(ops[2]):
98 return 1
99 else:
100 return 0
101
102 # Map opcodes that might be compressed to a function that returns the
103 # mode (index into mode_list below) in which the insn is to be
104 # represented. Those not mentioned in copcond are assumed
105 # Uncomopressed.
106 copcond = {
107 # Pretending anything goes, just for demonstration purposes.
108 'mr': anyops,
109 'ld': anyops,
110 'std': anyops,
111 # Output and first input operand must coincide for these.
112 'add': same01,
113 'sub': same01,
114 # Limiting register and operand range:
115 'addi': bin2regs3imm8
116 # Anything else is uncompressed.
117 }
118
119 enter_compressed = 0
120 leave_compressed = 0
121 count_compressed = 0
122 count_uncompressed = 0
123 current_mode = 0
124 mode_list = ['Uncompressed', 'Compressed'] # for documentation purposes only
125
126 for line in sys.stdin:
127 if line[-1] is '\n':
128 line = line[:-1]
129
130 match = insn.fullmatch(line)
131 if match is None:
132 print(line)
133 # Switch to uncompressed mode at function boundaries
134 if current_mode is not 0:
135 print('<leave compressed mode>')
136 current_mode = 0
137 leave_compressed += 1
138 continue
139
140 addr = match['addr']
141 opcode = match['opcode']
142 operands = match['operands']
143
144 if opcode in copcond:
145 this_mode = copcond[opcode](opcode,
146 [mapop(op) for op in operands.split(',')])
147 else:
148 this_mode = 0
149
150 if this_mode is 1:
151 if current_mode is not 1:
152 print('\t\tcin.nop')
153 current_mode = 1
154 enter_compressed += 1
155 print(line + ' (c)')
156 count_compressed += 1
157 else:
158 if current_mode is not 0:
159 print('\t\tcout.nop')
160 current_mode = 0
161 leave_compressed += 1
162 print(line)
163 count_uncompressed += 1
164
165 transition_bytes = 1 * enter_compressed + 1 * leave_compressed
166 compressed_bytes = 2 * count_compressed
167 uncompressed_bytes = 4 * count_uncompressed
168 total_bytes = transition_bytes + compressed_bytes + uncompressed_bytes
169 original_bytes = 2 * compressed_bytes + uncompressed_bytes
170
171 print()
172 print('Summary')
173 print('Compressed instructions: %i' % count_compressed)
174 print('Uncompressed instructions: %i' % count_uncompressed)
175 print('Transitions into compressed mode: %i' % enter_compressed)
176 print('Transitions out of compressed mode: %i' % leave_compressed)
177 print('Compressed size estimate: %i' % total_bytes)
178 print('Original size: %i' % original_bytes)
179 print('Compressed/original ratio: %f' % (total_bytes / original_bytes))