Project Ne10
An Open Optimized Software Library Project for the ARM Architecture
gas2ios_convert.py
1 #!/usr/bin/python
2 '''
3  Copyright 2013-15 ARM Limited and Contributors.
4  All rights reserved.
5 
6  Redistribution and use in source and binary forms, with or without
7  modification, are permitted provided that the following conditions are met:
8  * Redistributions of source code must retain the above copyright
9  notice, this list of conditions and the following disclaimer.
10  * Redistributions in binary form must reproduce the above copyright
11  notice, this list of conditions and the following disclaimer in the
12  documentation and/or other materials provided with the distribution.
13  * Neither the name of ARM Limited nor the
14  names of its contributors may be used to endorse or promote products
15  derived from this software without specific prior written permission.
16 
17  THIS SOFTWARE IS PROVIDED BY ARM LIMITED AND CONTRIBUTORS "AS IS" AND
18  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  DISCLAIMED. IN NO EVENT SHALL ARM LIMITED AND CONTRIBUTORS BE LIABLE FOR ANY
21  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.'''
27 
28 '''convert GAS arm assembly to Clang's integrated-as'''
29 import re,sys,os
30 
31 ''' parse .qn .dn .req directive for arm assembly
32  input is string list
33 '''
34 def parse_alias(inlines):
35  #the value name doesn't include .F32 suffix, but include [0], such as d0[0]
36  alias_exp = re.compile(r" *"
37  r"(?P<alias>[_a-zA-Z0-9]+)"
38  " +\.(req|qn|dn) +"
39  r"(?P<value>[a-zA-Z0-9\[\]]+)"
40  )
41  global_exp = re.compile(r"\.global")
42  #store aliases in different function in different dictionary
43  #use .global to label different function
44  alias_dics = []
45  alias_dics.append({})
46  func_count = 0
47  for line in inlines:
48  if global_exp.search(line):
49  alias_dics.append({})
50  func_count += 1
51  result = alias_exp.search(line)
52  if result != None:
53  alias = result.group('alias')
54  value = result.group('value')
55  alias_dics[func_count][alias] = value
56  #print alias_dics
57 
58  #replace alias
59  func_count = 0
60  line_result1 = []
61  for line in inlines:
62  if global_exp.search(line):
63  func_count += 1
64  for alias in alias_dics[func_count]:
65  alias_str = "\\b"+alias+"\\b"
66  alias_exp = re.compile(alias_str)
67  line = alias_exp.sub(alias_dics[func_count][alias], line)
68  line_result1.append(line)
69 
70  #remove .qn .dn .req line
71  line_result2 = []
72  alias_exp = re.compile(r"\.(qn|dn|req|unreq)")
73  for line in line_result1:
74  if not alias_exp.search(line):
75  line_result2.append(line)
76 
77  return line_result2
78 
79 ''' parse .qn .dn .req directive for arm assembly
80  input is string list.
81  this is for fft module's new format: in the new format,
82  all aliases are defined at the begin of files and all functions
83  share one set of defines.
84 '''
85 def parse_alias_fft(inlines):
86  #the value name doesn't include .F32 suffix, but include [0], such as d0[0]
87  alias_exp = re.compile(r" *"
88  r"(?P<alias>[_a-zA-Z0-9]+)"
89  " +\.(req|qn|dn) +"
90  r"(?P<value>[a-zA-Z0-9\[\]]+)"
91  )
92  aliases = {}
93  for line in inlines:
94  result = alias_exp.search(line)
95  if result != None:
96  alias = result.group('alias')
97  value = result.group('value')
98  aliases[alias] = value
99  #print aliases
100 
101  #replace alias
102  line_result1 = []
103  for line in inlines:
104  for alias in aliases:
105  alias_str = "\\b"+alias+"\\b"
106  alias_exp = re.compile(alias_str)
107  line = alias_exp.sub(aliases[alias], line)
108  line_result1.append(line)
109 
110  #remove .qn .dn .req line
111  line_result2 = []
112  alias_exp = re.compile(r"\.(qn|dn|req|unreq)")
113  for line in line_result1:
114  if not alias_exp.search(line):
115  line_result2.append(line)
116 
117  return line_result2
118 
119 '''add .F32 to some instructions for Clang's as doesn't support register with
120  datatype, such as VADD Q0.F32, Q1.F32, Q2.F32'''
121 def add_f32(inlines):
122  instructions = ['VADD', 'VSUB', 'VLD1', 'VLD2', 'VMUL', 'VMLA', 'VMLS',
123  'VZIP', 'VST1', 'VST2', 'VPADD', 'VEXT', 'VREV64',
124  'VDUP', 'VMOV']
125  line_result = []
126  for line in inlines:
127  for instruction in instructions:
128  instruction_exp = re.compile(instruction)
129  instruction_f32_exp = re.compile(instruction + "\\.[Ff]32")
130  #only add .F32 to instruction without .F32(or .f32)
131  if instruction_exp.search(line) and \
132  not instruction_f32_exp.search(line):
133  line = instruction_exp.sub(instruction + ".F32", line)
134  line_result.append(line)
135  return line_result
136 
137 '''remove .end instruction'''
138 def remove_end(inlines):
139  end_exp = re.compile(r"\.end\b")
140  line_result = []
141  for line in inlines:
142  if not end_exp.search(line):
143  line_result.append(line)
144  return line_result
145 
146 '''expan ldr rx, =label for Clang, this method has *not* been used in current
147 assembly convertion, Clang doesn't support this pseudo-instruction'''
148 def expan_ldr1(inlines):
149  #search ldr rx, =label
150  labels = []
151  ldr_exp = re.compile(r"\s*LDR.*="
152  r"(?P<label>[_a-zA-Z0-9]+)")
153  for line in inlines:
154  result = ldr_exp.search(line)
155  if result != None:
156  label = result.group('label')
157  if label not in labels:
158  labels.append(label)
159  #print labels
160 
161  if labels:
162  #change ldr rx, =label to ldr rx, Llabel
163  lines_result1 = []
164  for line in inlines:
165  result_line = line
166  for label in labels:
167  ldr_exp = re.compile("=" + label)
168  if ldr_exp.search(line):
169  result_line = ldr_exp.sub("L" + label, line)
170  break
171  lines_result1.append(result_line)
172 
173  #append a .text section to file and also add local label
174  lines_result1.append(" .text\n")
175  lines_result1.append(" .align 2\n")
176  for label in labels:
177  lines_result1.append("L" + label + ":\n")
178  lines_result1.append(" .long " + label + "\n")
179 
180  #remove .extern directive which is only used in GNU as
181  lines_result2 = []
182  for line in lines_result1:
183  del_line = False
184  for label in labels:
185  extern_exp = re.compile(r"\s*\.extern\s*" + label)
186  if extern_exp.search(line):
187  del_line = True
188  if not del_line:
189  lines_result2.append(line)
190  return lines_result2
191  return inlines
192 
193 '''expan ldr rx, =label for Clang, Clang doesn't support this
194 pseudo-instruction'''
195 def expan_ldr2(inlines):
196  #search "ldr rx, =label" line, save the label
197  labels = []
198  ldr_exp = re.compile(r"\s*(LDR|ldr)\s*(?P<reg>[a-zA-Z0-9]+),\s*="
199  r"(?P<label>[_a-zA-Z0-9]+)")
200  for line in inlines:
201  result = ldr_exp.search(line)
202  if result != None:
203  label = result.group('label')
204  if label not in labels:
205  labels.append(label)
206  #print labels
207 
208  if labels:
209  #change ldr rx, =label to ldr rx, Llabel
210  lines_result1 = []
211  count = 0
212  for line in inlines:
213  result_line = line
214  for label in labels:
215  result = ldr_exp.search(line)
216  if result:
217  reg = result.group('reg')
218  result_line = " MOVW "\
219  + reg + ",:lower16:(L" + label +\
220  "$non_lazy_ptr - (LPC0_" + str(count) + " + 4))\n" +\
221  " MOVT " + reg +\
222  ",:upper16:(L" + label + "$non_lazy_ptr - (LPC0_" +\
223  str(count) + " + 4))\n" + "LPC0_" + str(count) + ":\n"\
224  + " ADD " + reg + \
225  ",PC\n" + " LDR " +\
226  reg + ",[" + reg + "]\n"
227  count += 1
228  break
229  lines_result1.append(result_line)
230 
231  #append a .text section to file and also add local label
232  lines_result1.append(" .section __DATA,__nl_symbol_ptr,\
233  non_lazy_symbol_pointers\n")
234  lines_result1.append(" .align 2\n")
235  for label in labels:
236  lines_result1.append("L" + label + "$non_lazy_ptr:\n")
237  lines_result1.append(" .indirect_symbol " + label + "\n")
238  lines_result1.append(" .long 0\n")
239  lines_result1.append("\n .subsections_via_symbols\n")
240 
241  #remove .extern directive which is only used in GNU as
242  lines_result2 = []
243  for line in lines_result1:
244  del_line = False
245  for label in labels:
246  extern_exp = re.compile(r"\s*\.extern\s*" + label)
247  if extern_exp.search(line):
248  del_line = True
249  if not del_line:
250  lines_result2.append(line)
251  return lines_result2
252  return inlines
253 
254 '''add prefix 'L' to local label '''
255 def add_Llabel(inlines):
256  #get global label
257  glabels = []
258  for line in inlines:
259  glabel_exp = re.compile(r"\s*\.globa?l\s*"
260  r"(?P<glabel>\b[_a-zA-Z0-9]+\b)")
261  result = glabel_exp.search(line)
262  if result:
263  glabels.append(result.group('glabel'))
264  #print glabels
265 
266  #get non-leading L local label
267  llabels = []
268  for line in inlines:
269  llabel_exp = re.compile(r"(?P<llabel>^[._a-zA-Z0-9]+):")
270  result = llabel_exp.search(line)
271  if result:
272  llabel = result.group('llabel')
273  leading_L_exp = re.compile(r"^L.*")
274  if llabel not in glabels and not leading_L_exp.search(llabel):
275  llabels.append(llabel)
276 
277  #print llabels
278  #add leading L to local label
279  result_lines = []
280  for line in inlines:
281  result_line = line
282  for llabel in llabels:
283  new_llabel = llabel.replace('.L','')
284  #apply different change to label with .L or not
285  if new_llabel != llabel:
286  llabel_exp = re.compile(llabel.replace('.','\\.'))
287  else:
288  llabel_exp = re.compile("\\b" + llabel + "\\b")
289  #print "\\b" + re.escape(llabel) + "\\b"
290  if llabel_exp.search(line):
291  result_line = llabel_exp.sub("L" + new_llabel, line)
292  break
293  result_lines.append(result_line)
294 
295  return result_lines
296 
297 def main ():
298  fft_file_names = ['NE10_fft_float32.neon.s',
299  'NE10_fft_int16.neon.s',
300  'NE10_fft_int32.neon.s']
301  if len(sys.argv) < 3:
302  print "Usage: convert.py <input file> <output file>"
303  return
304  else:
305  infilename = sys.argv[1]
306  outfilename = sys.argv[2]
307  infile = open(infilename, 'r')
308  lines = []
309  for line in infile.readlines():
310  lines.append(line)
311  infile.close()
312 
313  #the fft file processing is hard coded.
314  if os.path.basename(infilename) in fft_file_names:
315  result = parse_alias_fft(lines)
316  else:
317  result = parse_alias(lines)
318  result = add_f32(result)
319  result = remove_end(result)
320  result = add_Llabel(result)
321  result = expan_ldr2(result)
322 
323  outfile = open(outfilename, 'w')
324  for line in result:
325  outfile.write(line)
326  outfile.close()
327 
328 main()