move instruction analysis programs to correct location
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sun, 29 Nov 2020 17:07:09 +0000 (17:07 +0000)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sun, 29 Nov 2020 17:07:09 +0000 (17:07 +0000)
lxo/532/comp16-v1-skel.py [deleted file]
lxo/532/comp16-v2-skel.py [deleted file]
lxo/532/insn-histogram.py [deleted file]
openpower/sv/comp16-v1-skel.py [new file with mode: 0644]
openpower/sv/comp16-v2-skel.py [new file with mode: 0644]

diff --git a/lxo/532/comp16-v1-skel.py b/lxo/532/comp16-v1-skel.py
deleted file mode 100644 (file)
index d4a6852..0000000
+++ /dev/null
@@ -1,260 +0,0 @@
-#! /bin/env python3
-
-# Feed this script the output of objdump -M raw --no-show-raw-insn ppc-prog
-
-# It will look for insns that can be represented in compressed mode,
-# according to the encoding rules in the copcond dictionary below.
-
-# Nothing is assumed as to the actual bit-encoding of the insns, this
-# is just to experiment with insn selection and get a quick feedback
-# loop for the encoding options in compressed mode.
-
-# In this script, the computations of encoding modes and transitions
-# are those for attempt 1 encoding, that encompasses:
-
-# - a 16-bit insn (with 10-bit payload) that may switch to compressed
-# mode or return to 32-bit mode;
-
-# - 16-bit insns in compressed mode, each with 2 bits devoted to
-# encoding one of the following possibilities:
-
-# -- switch back to uncompressed mode at the next insn
-
-# -- interpret the next insn in uncompressed mode, then return to
-# compressed mode
-
-# -- remain in 16-bit mode for the next insn
-
-# -- take the 16 bits that would be the next compressed insn as an
-# extension to the present 16-bit insn, and remain in 16-bit mode for
-# the subsequent 16-bits
-
-# At (visible) entry points, mode is forced to return to uncompressed
-# mode.
-
-# The entire code stream is printed, without any attempt to modify the
-# addresses that go along with or in them; we only insert markers for
-# the transition points, and for the compressed instructions.
-
-# The really useful information is printed at the end: a summary of
-# transition and compressed-insn counts, and the achieved compression
-# rate.
-
-import sys
-import re
-
-insn = re.compile('\s+(?P<addr>[0-9a-f]+):\s+(?P<opcode>[^ ]+) *(?P<operands>.*)')
-
-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]+)\)')
-
-def mapop(op):
-    match = opkind.fullmatch(op)
-
-    if match is None:
-        op = ('other', op)
-    elif match['reg'] is not None:
-        op = (match['regkind'], int(match['regnum']), op)
-    elif match['immediate'] is not None:
-        op = ('imm', int (op).bit_length (), op)
-    elif match['branch'] is not None:
-        op = ('pcoff', (int (match['branch'], 16)
-                        - int (addr, 16)).bit_length (), op, addr)
-    elif match['offset'] is not None:
-        op = ('ofst', mapop(match['offset']), mapop(match['basereg']), op)
-    else:
-        raise "unrecognized operand kind"
-
-    return op
-
-def opclass(mop):
-    return mop[0]
-def regno(mop):
-    if mop[0] in { 'r', 'fr', 'cr' }:
-        return mop[1]
-    else:
-        raise "operand is not a register"
-
-def immbits(mop):
-    if mop[0] is 'imm':
-        return mop[1]
-    else:
-        raise "operand is not an immediate"
-
-# Following are predicates to be used in copcond, to tell the mode in
-# which opcode with ops as operands is to be represented
-
-# Any occurrence of the opcode can be compressed.
-def anyops(opcode, ops):
-    return 1
-
-# Compress iff first and second operands are the same.
-def same01(opcode, ops):
-    if ops[0] == ops[1]:
-        return 1
-    else:
-        return 0
-
-# Registers representable in a made-up 3-bit mapping.
-cregs2 = { 1, 2, 3, 4, 5, 6, 7, 31 }
-
-# Return true iff mop is a regular register present in cregs2
-def bin2regs3(mop):
-    return opclass(mop) is 'r' and regno(mop) in cregs2
-
-# Return true iff mop is an immediate of at most 8 bits.
-def imm8(mop):
-    return opclass(mop) is 'imm' and immbits(mop) <= 8
-
-# Compress binary opcodes iff the first two operands (output and first
-# input operand) are registers representable in 3 bits in compressed
-# mode, and the immediate operand can be represented in 8 bits.
-def bin2regs3imm8(opcode, ops):
-    if bin2regs3(ops[0]) and bin2regs3(ops[1]) and imm8(ops[2]):
-        return 1
-    else:
-        return 0
-
-# Map opcodes that might be compressed to a function that returns the
-# best potential encoding kind for the insn, per the numeric coding
-# below.
-copcond = {
-    
-}
-
-# We have 4 kinds of insns:
-
-# 0: uncompressed; leave input insn unchanged
-# 1: 16-bit compressed, only in compressed mode
-# 2: 16-bit extended by another 16-bit, only in compressed mode
-# 3: 10-bit compressed, may switch to compressed mode
-
-# count[0:3] count the occurrences of the base kinds.
-# count[4] counts extra 10-bit nop-switches to compressed mode,
-# tentatively introduced before insns that can be 16-bit encoded.
-count = [0,0,0,0,0]
-# Default comments for the insn kinds above.  2 is always tentative.
-comments = ['', '\t; 16-bit', '\t; tentative 16+16-bit', '\t; 10-bit']
-
-# cur stands for the insn kind that we read and processed in the
-# previous iteration of the loop, and prev is the one before it.  the
-# one we're processing in the current iteration will be stored in
-# next until we make it cur at the very end of the loop.
-prev = cur = 0
-
-for line in sys.stdin:
-    if line[-1] is '\n':
-        line = line[:-1]
-
-    match = insn.fullmatch(line)
-    if match is None:
-        print(line)
-        # Switch to uncompressed mode at function boundaries
-        prev = prev2 = 0
-        continue
-
-    addr = match['addr']
-    opcode = match['opcode']
-    operands = match['operands']
-
-    if opcode in copcond:
-        next = copcond[opcode](opcode,
-                               [mapop(op) for op in operands.split(',')])
-    else:
-        next = 0
-
-    comment = None
-
-    if cur is 0:
-        if next is 0:
-            True # Uncompressed mode for good.
-        elif next is 1:
-            # If cur was not a single uncompressed mode insn,
-            # tentatively encode a 10-bit nop to enter compressed
-            # mode, and then 16-bit.  It takes as much space as
-            # encoding as 32-bit, but offers more possibilities for
-            # subsequent compressed encodings.  A compressor proper
-            # would have to go back and change the encoding
-            # afterwards, but wé re just counting.
-            if prev is not 1:
-                print('\t\th.nop\t\t; tentatively switch to compressed mode')
-                count[4] += 1
-                comment = 'tentatively compressed to 16-bit'
-        elif next is 2:
-            # We can use compressed encoding for next after an
-            # uncompressed insn only if it's the single-insn
-            # uncompressed mode slot.  For anything else, we're better
-            # off using uncompressed encoding for next, since it makes
-            # no sense to spend a 10-bit nop to switch to compressed
-            # mode for a 16+16-bit insn.  If subsequent insns would
-            # benefit from compressed encoding, we can switch then.
-            if prev is not 1:
-                next = 0
-                comment = 'not worth a nop for 16+16-bit'
-        elif next is 3:
-            # If prev was 16-bit compressed, cur would be in the
-            # single-insn uncompressed slot, so next could be encoded
-            # as 16-bit, enabling another 1-insn uncompressed slot
-            # after next that a 10-bit insn wouldn't, so make it so.
-            if prev is 1:
-                next = 1
-                comment = '16-bit, could be 10-bit'
-    elif cur is 1:
-        # After a 16-bit insn, anything goes.  If it remains in 16-bit
-        # mode, we can have 1 or 2 as next; if it returns to 32-bit
-        # mode, we can have 0 or 3.  Using 1 instead of 3 makes room
-        # for a subsequent single-insn compressed mode, so prefer
-        # that.
-        if next is 3:
-            next = 1
-            comment = '16-bit, could be 10-bit'
-    elif cur is 2:
-        # After a 16+16-bit insn, we can't switch directly to 32-bit
-        # mode.  However, cur could have been encoded as 32-bit, since
-        # any 16+16-bit insn can.  Indeed, we may have an arbitrary
-        # long sequence of 16+16-bit insns before next, and if next
-        # can only be encoded in 32-bit mode, we can "resolve" all
-        # previous adjacent 16+16-bit insns to the corresponding
-        # 32-bit insns in the encoding, and "adjust" the 16-bit or
-        # 10-bit insn that enabled the potential 16+16-bit encoding to
-        # switch to 32-bit mode then instead.
-        if next is 0:
-            prev = cur = 0
-            comment = '32-bit, like tentative 16+16-bit insns above'
-    elif cur is 3:
-        # After a 10-bit insn, another insn that could be encoded as
-        # 10-bit might as well be encoded as 16-bit, to make room for
-        # a single-insn uncompressed insn afterwards.
-        if next is 3:
-            next = 1
-            comment = '16-bit, could be 10-bit'
-    else:
-        raise "unknown mode for previous insn"
-
-    count[next] += 1
-
-    if comment is None:
-        comment = comments[next]
-    else:
-        comment = '\t; ' + comment
-    
-    print(line + comment)
-
-    prev = cur
-    cur = next
-
-transition_bytes = 2 * count[4]
-compressed_bytes = 2 * (count[1] + count[3])
-uncompressed_bytes = 4 * (count[0] + count[2])
-total_bytes = transition_bytes + compressed_bytes + uncompressed_bytes
-original_bytes = 2 * compressed_bytes + uncompressed_bytes
-
-print()
-print('Summary')
-print('32-bit uncompressed instructions: %i' % count[0])
-print('16-bit compressed instructions: %i' % count[1])
-print('16+16-bit (tentative) compressed-mode instructions: %i' % count[2])
-print('10-bit compressed instructions: %i' % count[3])
-print('10-bit (tentative) mode-switching nops: %i' % count[4])
-print('Compressed size estimate: %i' % total_bytes)
-print('Original size: %i' % original_bytes)
-print('Compressed/original ratio: %f' % (total_bytes / original_bytes))
diff --git a/lxo/532/comp16-v2-skel.py b/lxo/532/comp16-v2-skel.py
deleted file mode 100644 (file)
index fcf7122..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-#! /bin/env python3
-
-# Feed this script the output of objdump -M raw --no-show-raw-insn ppc-prog
-
-# It will look for insns that can be represented in compressed mode,
-# according to the encoding rules in the copcond dictionary below.
-# It's just a skeleton for testing of the logic,
-# the encoding rules are yet to be filled in.
-
-# Nothing is assumed as to the actual bit-encoding of the insns, this
-# is just to experiment with insn selection and get a quick feedback
-# loop for the encoding options in compressed mode.
-
-# In this script, the computations of encoding modes and transitions
-# are tuned for the simpler model that uses 1-byte nops for
-# transitions in and out of compressed mode, placing compressed-mode
-# insns at odd addresses.  At (visible) entry points, mode is forced
-# to return to uncompressed mode.
-
-# The entire code stream is printed, without any attempt to modify the
-# addresses that go along with or in them; we only insert markers for
-# the transition points, and for the compressed instructions.
-
-# The really useful information is printed at the end: a summary of
-# transition and compressed-insn counts, and the achieved compression
-# rate.
-
-import sys
-import re
-
-insn = re.compile('\s+(?P<addr>[0-9a-f]+):\s+(?P<opcode>[^ ]+) *(?P<operands>.*)')
-
-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]+)\)')
-
-def mapop(op):
-    match = opkind.fullmatch(op)
-
-    if match is None:
-        op = ('other', op)
-    elif match['reg'] is not None:
-        op = (match['regkind'], int(match['regnum']))
-    elif match['immediate'] is not None:
-        op = ('imm', int (op).bit_length ())
-    elif match['branch'] is not None:
-        op = ('pcoff', (int (match['branch'], 16)
-                        - int (addr, 16)).bit_length ())
-    elif match['offset'] is not None:
-        op = ('ofst', mapop(match['offset']), mapop(match['basereg']))
-    else:
-        raise "unrecognized operand kind"
-
-    return op
-
-def opclass(mop):
-    return mop[0]
-def regno(mop):
-    if mop[0] in { 'r', 'fr', 'cr' }:
-        return mop[1]
-    else:
-        raise "operand is not a register"
-
-def immbits(mop):
-    if mop[0] is 'imm':
-        return mop[1]
-    else:
-        raise "operand is not an immediate"
-
-# Following are predicates to be used in copcond, to tell the mode in
-# which opcode with ops as operands is to be represented
-
-# Any occurrence of the opcode can be compressed.
-def anyops(opcode, ops):
-    return 1
-
-# Compress iff first and second operands are the same.
-def same01(opcode, ops):
-    if ops[0] == ops[1]:
-        return 1
-    else:
-        return 0
-
-# Registers representable in a made-up 3-bit mapping.
-cregs2 = { 1, 2, 3, 4, 5, 6, 7, 31 }
-
-# Return true iff mop is a regular register present in cregs2
-def bin2regs3(mop):
-    return opclass(mop) is 'r' and regno(mop) in cregs2
-
-# Return true iff mop is an immediate of at most 8 bits.
-def imm8(mop):
-    return opclass(mop) is 'imm' and immbits(mop) <= 8
-
-# Compress binary opcodes iff the first two operands (output and first
-# input operand) are registers representable in 3 bits in compressed
-# mode, and the immediate operand can be represented in 8 bits.
-def bin2regs3imm8(opcode, ops):
-    if bin2regs3(ops[0]) and bin2regs3(ops[1]) and imm8(ops[2]):
-        return 1
-    else:
-        return 0
-
-# Map opcodes that might be compressed to a function that returns the
-# mode (index into mode_list below) in which the insn is to be
-# represented.  Those not mentioned in copcond are assumed
-# Uncomopressed.
-copcond = {
-    # Pretending anything goes, just for demonstration purposes.
-    'mr': anyops,
-    'ld': anyops,
-    'std': anyops,
-    # Output and first input operand must coincide for these.
-    'add': same01,
-    'sub': same01,
-    # Limiting register and operand range:
-    'addi': bin2regs3imm8
-    # Anything else is uncompressed.
-}
-
-enter_compressed = 0
-leave_compressed = 0
-count_compressed = 0
-count_uncompressed = 0
-current_mode = 0
-mode_list = ['Uncompressed', 'Compressed'] # for documentation purposes only
-
-for line in sys.stdin:
-    if line[-1] is '\n':
-        line = line[:-1]
-
-    match = insn.fullmatch(line)
-    if match is None:
-        print(line)
-        # Switch to uncompressed mode at function boundaries
-        if current_mode is not 0:
-            print('<leave compressed mode>')
-            current_mode = 0
-            leave_compressed += 1
-        continue
-
-    addr = match['addr']
-    opcode = match['opcode']
-    operands = match['operands']
-
-    if opcode in copcond:
-        this_mode = copcond[opcode](opcode,
-                                    [mapop(op) for op in operands.split(',')])
-    else:
-        this_mode = 0
-
-    if this_mode is 1:
-        if current_mode is not 1:
-            print('\t\tcin.nop')
-            current_mode = 1
-            enter_compressed += 1
-        print(line + ' (c)')
-        count_compressed += 1
-    else:
-        if current_mode is not 0:
-            print('\t\tcout.nop')
-            current_mode = 0
-            leave_compressed += 1
-        print(line)
-        count_uncompressed += 1
-
-transition_bytes = 1 * enter_compressed + 1 * leave_compressed
-compressed_bytes = 2 * count_compressed
-uncompressed_bytes = 4 * count_uncompressed
-total_bytes = transition_bytes + compressed_bytes + uncompressed_bytes
-original_bytes = 2 * compressed_bytes + uncompressed_bytes
-
-print()
-print('Summary')
-print('Compressed instructions: %i' % count_compressed)
-print('Uncompressed instructions: %i' % count_uncompressed)
-print('Transitions into compressed mode: %i' % enter_compressed)
-print('Transitions out of compressed mode: %i' % leave_compressed)
-print('Compressed size estimate: %i' % total_bytes)
-print('Original size: %i' % original_bytes)
-print('Compressed/original ratio: %f' % (total_bytes / original_bytes))
diff --git a/lxo/532/insn-histogram.py b/lxo/532/insn-histogram.py
deleted file mode 100644 (file)
index 9d66023..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-#! /bin/env python3
-
-# Feed this script the output of objdump -M raw --no-show-raw-insn ppc-prog
-
-# It will print the occurrence count of each opcode,
-# and under it, indented by one character,
-# the occurrence count of each operand.
-
-# Registers used as operands or as base addresses are counted
-# separately; immediates and offsets are grouped per bit length;
-# branch target offsets are grouped by range bit length.
-
-import sys
-import re
-
-insn = re.compile('\s+(?P<addr>[0-9a-f]+):\s+(?P<opcode>[^ \n]+) *(?P<operands>.*)[\n]?')
-
-opkind = re.compile('(?P<immediate>-?[0-9]+)|(?P<branch>[0-9a-f]+)(?: <.*>)?|(?P<offset>-?[0-9]+)\((?P<basereg>r[0-9]+)\)')
-
-histogram = {}
-
-def count(ops, op):
-    match = opkind.fullmatch(op)
-
-    if match is None:
-        op = op
-    elif match['immediate'] is not None:
-        op = "%i-bit" % int (op).bit_length ()
-    elif match['branch'] is not None:
-        op = "%i-bit range" % (int (match['branch'], 16) - int (addr, 16)).bit_length ()
-    elif match['offset'] is not None:
-        count(ops, match['offset'])
-        op = match['basereg']
-    else:
-        raise "unrecognized operand kind"
-
-    if op not in ops:
-        ops[op] = 1
-    else:
-        ops[op] += 1
-
-for line in sys.stdin:
-    match = insn.fullmatch(line)
-    if match is None:
-        continue
-
-    addr = match['addr']
-    opcode = match['opcode']
-    operands = match['operands']
-
-    if opcode not in histogram:
-        ops = {}
-        histogram[opcode] = [1,ops]
-    else:
-        histogram[opcode][0] += 1
-        ops = histogram[opcode][1]
-
-    if len(operands) > 0:
-        for operand in operands.split(','):
-            count(ops, operand)
-
-hist = list(histogram.items())
-hist.sort(key = (lambda x : x[1][0]))
-for x in hist:
-    print('%6i %s:' % (x[1][0], x[0]))
-    ops = list(x[1][1].items())
-    ops.sort(key = (lambda x : x[1]))
-    for x in ops:
-        print(' %6i %s' % (x[1], x[0]))
diff --git a/openpower/sv/comp16-v1-skel.py b/openpower/sv/comp16-v1-skel.py
new file mode 100644 (file)
index 0000000..d4a6852
--- /dev/null
@@ -0,0 +1,260 @@
+#! /bin/env python3
+
+# Feed this script the output of objdump -M raw --no-show-raw-insn ppc-prog
+
+# It will look for insns that can be represented in compressed mode,
+# according to the encoding rules in the copcond dictionary below.
+
+# Nothing is assumed as to the actual bit-encoding of the insns, this
+# is just to experiment with insn selection and get a quick feedback
+# loop for the encoding options in compressed mode.
+
+# In this script, the computations of encoding modes and transitions
+# are those for attempt 1 encoding, that encompasses:
+
+# - a 16-bit insn (with 10-bit payload) that may switch to compressed
+# mode or return to 32-bit mode;
+
+# - 16-bit insns in compressed mode, each with 2 bits devoted to
+# encoding one of the following possibilities:
+
+# -- switch back to uncompressed mode at the next insn
+
+# -- interpret the next insn in uncompressed mode, then return to
+# compressed mode
+
+# -- remain in 16-bit mode for the next insn
+
+# -- take the 16 bits that would be the next compressed insn as an
+# extension to the present 16-bit insn, and remain in 16-bit mode for
+# the subsequent 16-bits
+
+# At (visible) entry points, mode is forced to return to uncompressed
+# mode.
+
+# The entire code stream is printed, without any attempt to modify the
+# addresses that go along with or in them; we only insert markers for
+# the transition points, and for the compressed instructions.
+
+# The really useful information is printed at the end: a summary of
+# transition and compressed-insn counts, and the achieved compression
+# rate.
+
+import sys
+import re
+
+insn = re.compile('\s+(?P<addr>[0-9a-f]+):\s+(?P<opcode>[^ ]+) *(?P<operands>.*)')
+
+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]+)\)')
+
+def mapop(op):
+    match = opkind.fullmatch(op)
+
+    if match is None:
+        op = ('other', op)
+    elif match['reg'] is not None:
+        op = (match['regkind'], int(match['regnum']), op)
+    elif match['immediate'] is not None:
+        op = ('imm', int (op).bit_length (), op)
+    elif match['branch'] is not None:
+        op = ('pcoff', (int (match['branch'], 16)
+                        - int (addr, 16)).bit_length (), op, addr)
+    elif match['offset'] is not None:
+        op = ('ofst', mapop(match['offset']), mapop(match['basereg']), op)
+    else:
+        raise "unrecognized operand kind"
+
+    return op
+
+def opclass(mop):
+    return mop[0]
+def regno(mop):
+    if mop[0] in { 'r', 'fr', 'cr' }:
+        return mop[1]
+    else:
+        raise "operand is not a register"
+
+def immbits(mop):
+    if mop[0] is 'imm':
+        return mop[1]
+    else:
+        raise "operand is not an immediate"
+
+# Following are predicates to be used in copcond, to tell the mode in
+# which opcode with ops as operands is to be represented
+
+# Any occurrence of the opcode can be compressed.
+def anyops(opcode, ops):
+    return 1
+
+# Compress iff first and second operands are the same.
+def same01(opcode, ops):
+    if ops[0] == ops[1]:
+        return 1
+    else:
+        return 0
+
+# Registers representable in a made-up 3-bit mapping.
+cregs2 = { 1, 2, 3, 4, 5, 6, 7, 31 }
+
+# Return true iff mop is a regular register present in cregs2
+def bin2regs3(mop):
+    return opclass(mop) is 'r' and regno(mop) in cregs2
+
+# Return true iff mop is an immediate of at most 8 bits.
+def imm8(mop):
+    return opclass(mop) is 'imm' and immbits(mop) <= 8
+
+# Compress binary opcodes iff the first two operands (output and first
+# input operand) are registers representable in 3 bits in compressed
+# mode, and the immediate operand can be represented in 8 bits.
+def bin2regs3imm8(opcode, ops):
+    if bin2regs3(ops[0]) and bin2regs3(ops[1]) and imm8(ops[2]):
+        return 1
+    else:
+        return 0
+
+# Map opcodes that might be compressed to a function that returns the
+# best potential encoding kind for the insn, per the numeric coding
+# below.
+copcond = {
+    
+}
+
+# We have 4 kinds of insns:
+
+# 0: uncompressed; leave input insn unchanged
+# 1: 16-bit compressed, only in compressed mode
+# 2: 16-bit extended by another 16-bit, only in compressed mode
+# 3: 10-bit compressed, may switch to compressed mode
+
+# count[0:3] count the occurrences of the base kinds.
+# count[4] counts extra 10-bit nop-switches to compressed mode,
+# tentatively introduced before insns that can be 16-bit encoded.
+count = [0,0,0,0,0]
+# Default comments for the insn kinds above.  2 is always tentative.
+comments = ['', '\t; 16-bit', '\t; tentative 16+16-bit', '\t; 10-bit']
+
+# cur stands for the insn kind that we read and processed in the
+# previous iteration of the loop, and prev is the one before it.  the
+# one we're processing in the current iteration will be stored in
+# next until we make it cur at the very end of the loop.
+prev = cur = 0
+
+for line in sys.stdin:
+    if line[-1] is '\n':
+        line = line[:-1]
+
+    match = insn.fullmatch(line)
+    if match is None:
+        print(line)
+        # Switch to uncompressed mode at function boundaries
+        prev = prev2 = 0
+        continue
+
+    addr = match['addr']
+    opcode = match['opcode']
+    operands = match['operands']
+
+    if opcode in copcond:
+        next = copcond[opcode](opcode,
+                               [mapop(op) for op in operands.split(',')])
+    else:
+        next = 0
+
+    comment = None
+
+    if cur is 0:
+        if next is 0:
+            True # Uncompressed mode for good.
+        elif next is 1:
+            # If cur was not a single uncompressed mode insn,
+            # tentatively encode a 10-bit nop to enter compressed
+            # mode, and then 16-bit.  It takes as much space as
+            # encoding as 32-bit, but offers more possibilities for
+            # subsequent compressed encodings.  A compressor proper
+            # would have to go back and change the encoding
+            # afterwards, but wé re just counting.
+            if prev is not 1:
+                print('\t\th.nop\t\t; tentatively switch to compressed mode')
+                count[4] += 1
+                comment = 'tentatively compressed to 16-bit'
+        elif next is 2:
+            # We can use compressed encoding for next after an
+            # uncompressed insn only if it's the single-insn
+            # uncompressed mode slot.  For anything else, we're better
+            # off using uncompressed encoding for next, since it makes
+            # no sense to spend a 10-bit nop to switch to compressed
+            # mode for a 16+16-bit insn.  If subsequent insns would
+            # benefit from compressed encoding, we can switch then.
+            if prev is not 1:
+                next = 0
+                comment = 'not worth a nop for 16+16-bit'
+        elif next is 3:
+            # If prev was 16-bit compressed, cur would be in the
+            # single-insn uncompressed slot, so next could be encoded
+            # as 16-bit, enabling another 1-insn uncompressed slot
+            # after next that a 10-bit insn wouldn't, so make it so.
+            if prev is 1:
+                next = 1
+                comment = '16-bit, could be 10-bit'
+    elif cur is 1:
+        # After a 16-bit insn, anything goes.  If it remains in 16-bit
+        # mode, we can have 1 or 2 as next; if it returns to 32-bit
+        # mode, we can have 0 or 3.  Using 1 instead of 3 makes room
+        # for a subsequent single-insn compressed mode, so prefer
+        # that.
+        if next is 3:
+            next = 1
+            comment = '16-bit, could be 10-bit'
+    elif cur is 2:
+        # After a 16+16-bit insn, we can't switch directly to 32-bit
+        # mode.  However, cur could have been encoded as 32-bit, since
+        # any 16+16-bit insn can.  Indeed, we may have an arbitrary
+        # long sequence of 16+16-bit insns before next, and if next
+        # can only be encoded in 32-bit mode, we can "resolve" all
+        # previous adjacent 16+16-bit insns to the corresponding
+        # 32-bit insns in the encoding, and "adjust" the 16-bit or
+        # 10-bit insn that enabled the potential 16+16-bit encoding to
+        # switch to 32-bit mode then instead.
+        if next is 0:
+            prev = cur = 0
+            comment = '32-bit, like tentative 16+16-bit insns above'
+    elif cur is 3:
+        # After a 10-bit insn, another insn that could be encoded as
+        # 10-bit might as well be encoded as 16-bit, to make room for
+        # a single-insn uncompressed insn afterwards.
+        if next is 3:
+            next = 1
+            comment = '16-bit, could be 10-bit'
+    else:
+        raise "unknown mode for previous insn"
+
+    count[next] += 1
+
+    if comment is None:
+        comment = comments[next]
+    else:
+        comment = '\t; ' + comment
+    
+    print(line + comment)
+
+    prev = cur
+    cur = next
+
+transition_bytes = 2 * count[4]
+compressed_bytes = 2 * (count[1] + count[3])
+uncompressed_bytes = 4 * (count[0] + count[2])
+total_bytes = transition_bytes + compressed_bytes + uncompressed_bytes
+original_bytes = 2 * compressed_bytes + uncompressed_bytes
+
+print()
+print('Summary')
+print('32-bit uncompressed instructions: %i' % count[0])
+print('16-bit compressed instructions: %i' % count[1])
+print('16+16-bit (tentative) compressed-mode instructions: %i' % count[2])
+print('10-bit compressed instructions: %i' % count[3])
+print('10-bit (tentative) mode-switching nops: %i' % count[4])
+print('Compressed size estimate: %i' % total_bytes)
+print('Original size: %i' % original_bytes)
+print('Compressed/original ratio: %f' % (total_bytes / original_bytes))
diff --git a/openpower/sv/comp16-v2-skel.py b/openpower/sv/comp16-v2-skel.py
new file mode 100644 (file)
index 0000000..fcf7122
--- /dev/null
@@ -0,0 +1,179 @@
+#! /bin/env python3
+
+# Feed this script the output of objdump -M raw --no-show-raw-insn ppc-prog
+
+# It will look for insns that can be represented in compressed mode,
+# according to the encoding rules in the copcond dictionary below.
+# It's just a skeleton for testing of the logic,
+# the encoding rules are yet to be filled in.
+
+# Nothing is assumed as to the actual bit-encoding of the insns, this
+# is just to experiment with insn selection and get a quick feedback
+# loop for the encoding options in compressed mode.
+
+# In this script, the computations of encoding modes and transitions
+# are tuned for the simpler model that uses 1-byte nops for
+# transitions in and out of compressed mode, placing compressed-mode
+# insns at odd addresses.  At (visible) entry points, mode is forced
+# to return to uncompressed mode.
+
+# The entire code stream is printed, without any attempt to modify the
+# addresses that go along with or in them; we only insert markers for
+# the transition points, and for the compressed instructions.
+
+# The really useful information is printed at the end: a summary of
+# transition and compressed-insn counts, and the achieved compression
+# rate.
+
+import sys
+import re
+
+insn = re.compile('\s+(?P<addr>[0-9a-f]+):\s+(?P<opcode>[^ ]+) *(?P<operands>.*)')
+
+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]+)\)')
+
+def mapop(op):
+    match = opkind.fullmatch(op)
+
+    if match is None:
+        op = ('other', op)
+    elif match['reg'] is not None:
+        op = (match['regkind'], int(match['regnum']))
+    elif match['immediate'] is not None:
+        op = ('imm', int (op).bit_length ())
+    elif match['branch'] is not None:
+        op = ('pcoff', (int (match['branch'], 16)
+                        - int (addr, 16)).bit_length ())
+    elif match['offset'] is not None:
+        op = ('ofst', mapop(match['offset']), mapop(match['basereg']))
+    else:
+        raise "unrecognized operand kind"
+
+    return op
+
+def opclass(mop):
+    return mop[0]
+def regno(mop):
+    if mop[0] in { 'r', 'fr', 'cr' }:
+        return mop[1]
+    else:
+        raise "operand is not a register"
+
+def immbits(mop):
+    if mop[0] is 'imm':
+        return mop[1]
+    else:
+        raise "operand is not an immediate"
+
+# Following are predicates to be used in copcond, to tell the mode in
+# which opcode with ops as operands is to be represented
+
+# Any occurrence of the opcode can be compressed.
+def anyops(opcode, ops):
+    return 1
+
+# Compress iff first and second operands are the same.
+def same01(opcode, ops):
+    if ops[0] == ops[1]:
+        return 1
+    else:
+        return 0
+
+# Registers representable in a made-up 3-bit mapping.
+cregs2 = { 1, 2, 3, 4, 5, 6, 7, 31 }
+
+# Return true iff mop is a regular register present in cregs2
+def bin2regs3(mop):
+    return opclass(mop) is 'r' and regno(mop) in cregs2
+
+# Return true iff mop is an immediate of at most 8 bits.
+def imm8(mop):
+    return opclass(mop) is 'imm' and immbits(mop) <= 8
+
+# Compress binary opcodes iff the first two operands (output and first
+# input operand) are registers representable in 3 bits in compressed
+# mode, and the immediate operand can be represented in 8 bits.
+def bin2regs3imm8(opcode, ops):
+    if bin2regs3(ops[0]) and bin2regs3(ops[1]) and imm8(ops[2]):
+        return 1
+    else:
+        return 0
+
+# Map opcodes that might be compressed to a function that returns the
+# mode (index into mode_list below) in which the insn is to be
+# represented.  Those not mentioned in copcond are assumed
+# Uncomopressed.
+copcond = {
+    # Pretending anything goes, just for demonstration purposes.
+    'mr': anyops,
+    'ld': anyops,
+    'std': anyops,
+    # Output and first input operand must coincide for these.
+    'add': same01,
+    'sub': same01,
+    # Limiting register and operand range:
+    'addi': bin2regs3imm8
+    # Anything else is uncompressed.
+}
+
+enter_compressed = 0
+leave_compressed = 0
+count_compressed = 0
+count_uncompressed = 0
+current_mode = 0
+mode_list = ['Uncompressed', 'Compressed'] # for documentation purposes only
+
+for line in sys.stdin:
+    if line[-1] is '\n':
+        line = line[:-1]
+
+    match = insn.fullmatch(line)
+    if match is None:
+        print(line)
+        # Switch to uncompressed mode at function boundaries
+        if current_mode is not 0:
+            print('<leave compressed mode>')
+            current_mode = 0
+            leave_compressed += 1
+        continue
+
+    addr = match['addr']
+    opcode = match['opcode']
+    operands = match['operands']
+
+    if opcode in copcond:
+        this_mode = copcond[opcode](opcode,
+                                    [mapop(op) for op in operands.split(',')])
+    else:
+        this_mode = 0
+
+    if this_mode is 1:
+        if current_mode is not 1:
+            print('\t\tcin.nop')
+            current_mode = 1
+            enter_compressed += 1
+        print(line + ' (c)')
+        count_compressed += 1
+    else:
+        if current_mode is not 0:
+            print('\t\tcout.nop')
+            current_mode = 0
+            leave_compressed += 1
+        print(line)
+        count_uncompressed += 1
+
+transition_bytes = 1 * enter_compressed + 1 * leave_compressed
+compressed_bytes = 2 * count_compressed
+uncompressed_bytes = 4 * count_uncompressed
+total_bytes = transition_bytes + compressed_bytes + uncompressed_bytes
+original_bytes = 2 * compressed_bytes + uncompressed_bytes
+
+print()
+print('Summary')
+print('Compressed instructions: %i' % count_compressed)
+print('Uncompressed instructions: %i' % count_uncompressed)
+print('Transitions into compressed mode: %i' % enter_compressed)
+print('Transitions out of compressed mode: %i' % leave_compressed)
+print('Compressed size estimate: %i' % total_bytes)
+print('Original size: %i' % original_bytes)
+print('Compressed/original ratio: %f' % (total_bytes / original_bytes))