diff options
| author | Rusty Wagner <rusty.wagner@gmail.com> | 2024-03-05 19:50:13 -0500 |
|---|---|---|
| committer | Rusty Wagner <rusty.wagner@gmail.com> | 2024-03-05 20:34:34 -0500 |
| commit | e093c21ed880ac3eb72119be15093ee04f8ce299 (patch) | |
| tree | 9f720ebdc0ae415734b1199ed341668c69710a94 /arch/arm64/misc/neon_intrins.py | |
| parent | 0609276712622908254065546102381466033141 (diff) | |
Move architecture modules into the API repo
Diffstat (limited to 'arch/arm64/misc/neon_intrins.py')
| -rwxr-xr-x | arch/arm64/misc/neon_intrins.py | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/arch/arm64/misc/neon_intrins.py b/arch/arm64/misc/neon_intrins.py new file mode 100755 index 00000000..6d9c03c5 --- /dev/null +++ b/arch/arm64/misc/neon_intrins.py @@ -0,0 +1,261 @@ +#!/usr/bin/env python +# read neon_intrins.c and generate code for the architecture + +import re +import sys + +from collections import OrderedDict + +# SMMLA Vd.4S,Vn.16B,Vm.16B -> Vd.4S +def get_destination_reg(asig): + try: + (mnem, regs) = re.match(r'^(\w+) (.*)', asig).group(1,2) + except AttributeError: + print('couldn\'t get destination register from -%s-' % asig) + sys.exit(-1) + return regs.split(',')[0] + +def get_reg_size(reg): + if reg in ['Qd', 'Qt']: return 16 + if reg in ['Dd', 'Dm']: return 8 + if reg=='Sd': return 4 + if reg=='Hd': return 2 + if reg=='Bd': return 1 + + if reg in ['Wd', 'Wn', 'Wm']: return 4 + + reg = reg.lower() + if '.1q' in reg: return 16 + if '.2d' in reg: return 16 + if '.4s' in reg: return 16 + if '.8h' in reg: return 16 + if '.16b' in reg: return 16 + if '.d' in reg: return 8 + if '.1d' in reg: return 8 + if '.2s' in reg: return 8 + if '.4h' in reg: return 8 + if '.8b' in reg: return 8 + if '.s' in reg: return 4 + if '.2h' in reg: return 4 + if '.4b' in reg: return 4 + if '.h' in reg: return 2 + if '.b' in reg: return 1 + + print('couldn\'t get size of register -%s-' % reg) + sys.exit(-1) + +def get_write_size(asig): + (mnem, regs) = re.match(r'^(\w+) (.*)', asig).group(1,2) + regs = regs.split(',') + reg0 = regs[0] + + if reg0=='Rd': + # eg: UMOV Rd,Vn.B[lane] means Rd is 1 byte + assert len(regs)==2 + return get_reg_size(regs[1]) + + if reg0.startswith('{') and reg0.endswith('}') and ' - ' in reg0: + # eg: ST2 {Vt.16B - Vt2.16B},[Xn] + m = re.match('^.* - (Vt(\d)\..*)}', reg0) + (reg0, num) = m.group(1,2) + return (int(num)+1) * get_reg_size(reg0) + + return get_reg_size(reg0) + +def type_to_binja_types(ntype): + # remove pointer + if ntype.endswith(' const *'): + ntype = ntype[0:-8] + if ntype.endswith(' *'): + ntype = ntype[0:-2] + + binja_type = 'Float' if 'float' in ntype else 'Int' + + # int (for lane or immediate) + if ntype == 'int': + return ['Type::IntegerType(4)'] + + # multiple packed, eg: "uint8x8x2_t" + m = re.match(r'^(\w+?)(\d+)x(\d+)x(\d+)_t$', ntype) + if m: + (base, bit_width, npacked, nregs) = m.group(1,2,3, 4) + return ['Type::%sType(%d)' % (binja_type, int(bit_width)*int(npacked)/8)]*int(nregs) + + # packed in registers, eg: "int8x8_t" + m = re.match(r'^(\w+?)(\d+)x(\d+)_t$', ntype) + if m: + (base, bit_width, npacked) = m.group(1,2,3) + return ['Type::%sType(%d)' % (binja_type, int(bit_width)*int(npacked)/8)] + + # simple, eg: "int8_t" + m = re.match(r'^(\w+?)(\d+)_t$', ntype) + if m: + (base, bit_width) = m.group(1,2) + return ['Type::%sType(%d)' % (binja_type, int(bit_width)/8)] + + print('cannot convert neon type %s into binja type' % ntype) + sys.exit(-1) + +# given an intrinsic's name, argument types, and return type, compute +# the binja intrinsic input types +def resolve_input_types(name, arg_types, return_type): + result = [] + + for at in arg_types: + if at.endswith(' *'): + # eg: int32x4x2_t vld2q_s32(int32_t const * ptr); + assert ('ld' in name) or ('st' in name) + result.extend(neon_type_to_binja_types(return_type)) + else: + result.extend(neon_type_to_binja_types(at)) + + return result + +if __name__ == '__main__': + # parse neon_intrins.c into a "database" + with open('neon_intrins.c') as fp: + lines = [l.strip() for l in fp.readlines()] + + db = OrderedDict() + + for l in lines: + if 'reinterpret' in l: continue + if 'RESULT[' in l: continue + (fsig, asig) = l.split('; // ') + + # function name + m = re.match(r'^(\w+) (\w+)\((.*)\)$', fsig) + fname = m.group(2) + if fname in db: continue + if asig.startswith('RESULT['): continue + + # function arguments + fargs = [m.group(1)] + m.group(3).split(', ') + fargs = [x.replace('const ', '') for x in fargs] + + (operation, operands) = re.match(r'^(\w+?) (.*)$', asig).group(1, 2) + operands = operands.split(',') + + db[fname] = OrderedDict({ + 'fsig': fsig, + 'asig': asig, + 'define': 'ARM64_INTRIN_%s' % fname.upper(), + 'operation': 'ARM64_' + operation, + 'fargs': fargs, + 'operands': operands, + }) + + cmd = sys.argv[1] + + if cmd in ['dump']: + import pprint + pp = pprint.PrettyPrinter() + pp.pprint(db) + + elif cmd in ['enum', 'enumeration']: + # for enum NeonIntrinsic : uint32_t ... + first = True + for fname in db: + extra = '=ARM64_INTRIN_NORMAL_END' if first else '' + print('\t%s%s,' % (db[fname]['define'], extra)) + first = False + + elif cmd in ['name', 'names']: + # for GetIntrinsicName(uint32_t intrinsic) + for fname in db: + print('\t\tcase %s: return "%s";' % (db[fname]['define'], fname)) + + elif cmd in ['all', 'define', 'defines']: + # for GetAllIntrinsics() + collection = [db[fname]['define'] for fname in db] + i = 0 + while i<len(collection): + print('\t\t' + ', '.join(collection[i:i+3]) + ',') + i += 3 + + elif cmd in ['input', 'inputs']: + # for GetIntrinsicInputs() + + # collect all unique write types + rtstrs = set(str(db[x]['binja_input_types']) for x in db) + + # for each write type + for rtstr in sorted(rtstrs): + fnames = [x for x in db if str(db[x]['binja_input_types']) == rtstr] + + # print cases in the db that have the same type + for fname in fnames: + print('\t\tcase %s:' % (db[fname]['define'])) + + print('\t\t\treturn {%s};' % (', '.join(db[fnames[0]]['binja_input_types']))) + + elif cmd in ['output', 'outputs']: + # for GetIntrinsicOutputs() + + # collect all unique write types + wtstrs = set(str(db[x]['binja_output_types']) for x in db) + + # for each write type + for wtstr in sorted(wtstrs): + fnames = [x for x in db if str(db[x]['binja_output_types']) == wtstr] + + # print cases in the db that have the same type + for fname in fnames: + print('\t\tcase %s:' % (db[fname]['define'])) + + print('\t\t\treturn {%s};' % (', '.join(db[fnames[0]]['binja_output_types']))) + + elif cmd in ['implementation', 'code']: + # expects: + # std::vector<RegisterOrFlag> outputs + # std::vector<ExprId> inputs + for fname in db: + entry = db[fname] + + print('\t\tcase %s:' % entry['operation']) + print('\t\t{') + print('\t\t\t// fsig: %s' % entry['fsig']) + print('\t\t\t// asig: %s' % entry['asig']) + print('\t\t\t// operands_n: %d' % entry['operands_n']) + print('\t\t\tadd_output(outputs, oper0, inst, INTRIN_TYPE_HINT_%s);' % (' '.join(entry['binja_output_types']).upper())) + for i in range(0, len(entry['binja_input_types'])): + print('\t\t\tadd_input(inputs, oper%d, inst, INTRIN_TYPE_HINT_%s);' % (i+1, entry['binja_input_types'][i].upper())) + print('\t\t\til.AddInstruction(il.Intrinsic(outputs, %s, inputs));' % entry['define']) + print('\t\t}') + print('\t\tbreak;') + + elif cmd in ['test']: + for fname in db: + entry = db[fname] + fargs = entry['fargs'] + operands = entry['operands'] + + print(entry['operation']) + print('fsig: %s' % entry['fsig']) + print('asig: %s' % entry['asig']) + print('fargs: %s' % fargs) + print('operands: %s' % operands) + + # convert OPERATION X,Y,Z[lane] -> + # OPERATION X,Y,Z,Z[lane] +# tmp = [] +# for o in operands: +# m = re.match(r'^(.*)\[lane\d*\]$', o) +# if m: +# tmp.append(m.group(1)) +# tmp.append('lane(%s)' % m.group(1)) +# else: +# tmp.append(o) +# operands = tmp + # convert OPERATION X,Y,#0 -> + # OPERATION X,Y + if re.match(r'^#\d+$', operands[-1]): + operands = operands[:-1] + # + if len(fargs) == len(operands)+1: + operands = [operands[0]] + operands + + if len(operands) != len(fargs): + print('cant reconcile fargs and operands') + if not 'vcopy' in entry['fsig']: + sys.exit(-1) |
