| # Copyright 2018 The gemmlowp Authors. All Rights Reserved. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # ============================================================================== |
| """Encodes ARM asm code for certain instructions into the corresponding machine code encoding, as a .word directive in the asm code, preserving the original code in a comment. |
| |
| Reads from stdin, writes to stdout. |
| |
| Example diff: |
| - "udot v16.4s, v4.16b, v0.16b\n" |
| + ".word 0x6e809490 // udot v16.4s, v4.16b, v0.16b\n" |
| |
| The intended use case is to make asm code easier to compile on toolchains that |
| do not support certain new instructions. |
| """ |
| |
| import sys |
| import re |
| import argparse |
| |
| |
| def encode_udot_sdot_vector(line): |
| m = re.search( |
| r'\b([us])dot[ ]+v([0-9]+)[ ]*\.[ ]*4s[ ]*\,[ ]*v([0-9]+)[ ]*\.[ ]*16b[ ]*\,[ ]*v([0-9]+)[ ]*\.[ ]*16b', |
| line) |
| if not m: |
| return 0, line |
| |
| match = m.group(0) |
| unsigned = 1 if m.group(1) == 'u' else 0 |
| accum = int(m.group(2)) |
| lhs = int(m.group(3)) |
| rhs = int(m.group(4)) |
| assert accum >= 0 and accum <= 31 |
| assert lhs >= 0 and lhs <= 31 |
| assert rhs >= 0 and rhs <= 31 |
| mcode = 0x4e809400 | (accum << 0) | (lhs << 5) | (rhs << 16) | ( |
| unsigned << 29) |
| return mcode, match |
| |
| |
| def encode_udot_sdot_element(line): |
| m = re.search( |
| r'\b([us])dot[ ]+v([0-9]+)[ ]*\.[ ]*4s[ ]*\,[ ]*v([0-9]+)[ ]*\.[ ]*16b[ ]*\,[ ]*v([0-9]+)[ ]*\.[ ]*4b[ ]*\[([0-9])\]', |
| line) |
| if not m: |
| return 0, line |
| |
| match = m.group(0) |
| unsigned = 1 if m.group(1) == 'u' else 0 |
| accum = int(m.group(2)) |
| lhs = int(m.group(3)) |
| rhs = int(m.group(4)) |
| lanegroup = int(m.group(5)) |
| assert accum >= 0 and accum <= 31 |
| assert lhs >= 0 and lhs <= 31 |
| assert rhs >= 0 and rhs <= 31 |
| assert lanegroup >= 0 and lanegroup <= 3 |
| l = 1 if lanegroup & 1 else 0 |
| h = 1 if lanegroup & 2 else 0 |
| mcode = 0x4f80e000 | (accum << 0) | (lhs << 5) | (rhs << 16) | (l << 21) | ( |
| h << 11) | ( |
| unsigned << 29) |
| return mcode, match |
| |
| |
| def encode(line): |
| for encode_func in [encode_udot_sdot_vector, encode_udot_sdot_element]: |
| mcode, match = encode_func(line) |
| if mcode: |
| return mcode, match |
| return 0, line |
| |
| |
| def read_existing_encoding(line): |
| m = re.search(r'\.word\ (0x[0-9a-f]+)', line) |
| if m: |
| return int(m.group(1), 16) |
| return 0 |
| |
| |
| parser = argparse.ArgumentParser(description='Encode some A64 instructions.') |
| parser.add_argument( |
| '-f', |
| '--fix', |
| help='fix existing wrong encodings in-place and continue', |
| action='store_true') |
| args = parser.parse_args() |
| |
| lineno = 0 |
| found_existing_encodings = False |
| found_error = False |
| found_fixes = False |
| for line in sys.stdin: |
| lineno = lineno + 1 |
| mcode, match = encode(line) |
| if mcode: |
| existing_encoding = read_existing_encoding(line) |
| if existing_encoding: |
| found_existing_encodings = True |
| if mcode != existing_encoding: |
| if args.fix: |
| line = line.replace('.word 0x%x // %s' % (existing_encoding, match), |
| '.word 0x%x // %s' % (mcode, match)) |
| found_fixes = True |
| else: |
| sys.stderr.write( |
| "Error at line %d: existing encoding 0x%x differs from encoding 0x%x for instruction '%s':\n\n%s\n\n" |
| % (lineno, existing_encoding, mcode, match, line)) |
| found_error = True |
| else: |
| line = line.replace(match, '.word 0x%x // %s' % (mcode, match)) |
| sys.stdout.write(line) |
| if found_error: |
| sys.exit(1) |
| if found_existing_encodings: |
| if found_fixes: |
| sys.stderr.write( |
| 'Note: some instructions that this program is able to encode, were already encoded and their existing encodings didn\'t match the specified asm instructions. Since --fix was passed, these were fixed in-place.\n' |
| ) |
| else: |
| sys.stderr.write( |
| 'Note: some instructions that this program is able to encode, were already encoded. These encodings have been checked.\n' |
| ) |