1#!/usr/bin/env python2.7
2#
3# Copyright 2017 Google Inc.
4#
5# Use of this source code is governed by a BSD-style license that can be
6# found in the LICENSE file.
7
8import re
9import subprocess
10import sys
11
12#clang = ['clang++']
13clang = ['ccache', 'clang-4.0', '-x', 'c++']
14
15ndk = '/Users/mtklein/brew/opt/android-ndk/'
16objdump = 'gobjdump'
17
18#ndk = '/home/mtklein/ndk/'
19#objdump = '/home/mtklein/binutils-2.27/binutils/objdump'
20
21cflags = ['-std=c++11', '-Os', '-DJUMPER',
22          '-fomit-frame-pointer', '-ffp-contract=fast' ]
23
24sse2 = '-mno-red-zone -msse2 -mno-sse3 -mno-ssse3 -mno-sse4.1'.split()
25subprocess.check_call(clang + cflags + sse2 +
26                      ['-c', 'src/jumper/SkJumper_stages.cpp'] +
27                      ['-o', 'sse2.o'])
28subprocess.check_call(clang + cflags + sse2 + ['-DWIN'] +
29                      ['-c', 'src/jumper/SkJumper_stages.cpp'] +
30                      ['-o', 'win_sse2.o'])
31
32sse41 = '-mno-red-zone -msse4.1'.split()
33subprocess.check_call(clang + cflags + sse41 +
34                      ['-c', 'src/jumper/SkJumper_stages.cpp'] +
35                      ['-o', 'sse41.o'])
36subprocess.check_call(clang + cflags + sse41 + ['-DWIN'] +
37                      ['-c', 'src/jumper/SkJumper_stages.cpp'] +
38                      ['-o', 'win_sse41.o'])
39
40avx = '-mno-red-zone -mavx'.split()
41subprocess.check_call(clang + cflags + avx +
42                      ['-c', 'src/jumper/SkJumper_stages.cpp'] +
43                      ['-o', 'avx.o'])
44subprocess.check_call(clang + cflags + avx + ['-DWIN'] +
45                      ['-c', 'src/jumper/SkJumper_stages.cpp'] +
46                      ['-o', 'win_avx.o'])
47
48hsw = '-mno-red-zone -mavx2 -mfma -mf16c'.split()
49subprocess.check_call(clang + cflags + hsw +
50                      ['-c', 'src/jumper/SkJumper_stages.cpp'] +
51                      ['-o', 'hsw.o'])
52subprocess.check_call(clang + cflags + hsw + ['-DWIN'] +
53                      ['-c', 'src/jumper/SkJumper_stages.cpp'] +
54                      ['-o', 'win_hsw.o'])
55
56aarch64 = [
57    '--target=aarch64-linux-android',
58    '--sysroot=' + ndk + 'platforms/android-21/arch-arm64',
59]
60subprocess.check_call(clang + cflags + aarch64 +
61                      ['-c', 'src/jumper/SkJumper_stages.cpp'] +
62                      ['-o', 'aarch64.o'])
63
64vfp4 = [
65    '--target=armv7a-linux-android',
66    '--sysroot=' + ndk + 'platforms/android-18/arch-arm',
67    '-mfpu=neon-vfpv4',
68    '-mfloat-abi=hard',
69]
70subprocess.check_call(clang + cflags + vfp4 +
71                      ['-c', 'src/jumper/SkJumper_stages.cpp'] +
72                      ['-o', 'vfp4.o'])
73
74def parse_object_file(dot_o, array_type, target=None):
75  cmd = [objdump]
76  if target:
77    cmd += ['--target', target]
78
79  # Look for sections we know we can't handle.
80  section_headers = subprocess.check_output(cmd + ['-h', dot_o])
81  for snippet in ['.literal', '.const', '.rodata']:
82    if snippet in section_headers:
83      print >>sys.stderr, 'Found %s in section.' % snippet
84      assert snippet not in section_headers
85
86  # Ok.  Let's disassemble.
87  active = False
88  disassemble = ['-d', '--insn-width=10', dot_o]
89  for line in subprocess.check_output(cmd + disassemble).split('\n'):
90    line = line.strip()
91
92    if not line or line.startswith(dot_o) or line.startswith('Disassembly'):
93      continue
94
95    # E.g. 00000000000003a4 <_load_f16>:
96    m = re.match('''[0-9a-f]+ <_?(.*)>:''', line)
97    if m:
98      if active:
99        print '};'
100      print
101      print 'CODE const', array_type, m.group(1) + '[] = {'
102      active = True
103      continue
104
105    columns = line.split('\t')
106    code = columns[1]
107    if len(columns) >= 4:
108      inst = columns[2]
109      args = columns[3]
110    else:
111      inst, args = columns[2], ''
112      if ' ' in columns[2]:
113        inst, args = columns[2].split(' ', 1)
114    code, inst, args = code.strip(), inst.strip(), args.strip()
115
116    dehex = lambda x: '0x'+x
117    if array_type == 'uint8_t':
118      dehex = lambda x: str(int(x, 16))
119
120    hexed = ''.join(dehex(x) + ',' for x in code.split(' '))
121    print '  ' + hexed + ' '*(40-len(hexed)) + \
122          '//' + inst  + (' '*(14-len(inst)) + args if args else '')
123  print '};'
124
125sys.stdout = open('src/jumper/SkJumper_generated.cpp', 'w')
126
127print '''/*
128 * Copyright 2017 Google Inc.
129 *
130 * Use of this source code is governed by a BSD-style license that can be
131 * found in the LICENSE file.
132 */
133
134// This file is generated semi-automatically with this command:
135//   $ src/jumper/build_stages.py
136
137#include <stdint.h>
138
139#if defined(_MSC_VER)
140    #pragma section("code", read,execute)
141    #define CODE extern "C" __declspec(allocate("code"))
142#elif defined(__MACH__)
143    #define CODE extern "C" __attribute__((section("__TEXT,__text")))
144#else
145    #define CODE extern "C" __attribute__((section(".text")))
146#endif
147'''
148print '#if defined(__aarch64__)'
149parse_object_file('aarch64.o', 'uint32_t')
150
151print '#elif defined(__arm__)'
152parse_object_file('vfp4.o', 'uint32_t', target='elf32-littlearm')
153
154print '#elif defined(__x86_64__)'
155parse_object_file('hsw.o',   'uint8_t')
156parse_object_file('avx.o',   'uint8_t')
157parse_object_file('sse41.o', 'uint8_t')
158parse_object_file('sse2.o',  'uint8_t')
159
160print '#elif defined(_M_X64)'
161parse_object_file('win_hsw.o',   'uint8_t')
162parse_object_file('win_avx.o',   'uint8_t')
163parse_object_file('win_sse41.o', 'uint8_t')
164parse_object_file('win_sse2.o',  'uint8_t')
165
166print '#endif'
167