1414import sys
1515import re
1616import textwrap
17+ import itertools
1718
1819SPEC = re .compile (
1920 r'^(?:(?P<id>[iusfIUSF])(?:\((?P<start>\d+)-(?P<end>\d+)\)|'
@@ -258,7 +259,7 @@ def type_info(self, platform_info):
258259 'u' : [Unsigned ],
259260 'f' : [Float ]}
260261
261- def ptrify (match , elem , width ):
262+ def ptrify (match , elem , width , previous ):
262263 ptr = match .group ('pointer' )
263264 if ptr is None :
264265 return elem
@@ -268,7 +269,7 @@ def ptrify(match, elem, width):
268269 llvm_elem = None
269270 else :
270271 assert llvm_ptr .startswith ('/' )
271- options = list (TypeSpec (llvm_ptr [1 :]).enumerate (width ))
272+ options = list (TypeSpec (llvm_ptr [1 :]).enumerate (width , previous ))
272273 assert len (options ) == 1
273274 llvm_elem = options [0 ]
274275 assert ptr in ('Pc' , 'Pm' )
@@ -281,77 +282,70 @@ def __init__(self, spec):
281282
282283 self .spec = spec
283284
284- def enumerate (self , width ):
285+ def enumerate (self , width , previous ):
285286 for spec in self .spec :
286287 match = SPEC .match (spec )
287- assert match is not None
288- if True :
288+ if match is not None :
289289 id = match .group ('id' )
290- assert id is not None
291- is_vector = id .islower ()
292- type_ctors = TYPE_ID_LOOKUP [id .lower ()]
293-
294- start = match .group ('start' )
295- if start is not None :
296- end = match .group ('end' )
297- llvm_width = None
290+ reference = match .group ('reference' )
291+
292+ if id is not None :
293+ is_vector = id .islower ()
294+ type_ctors = TYPE_ID_LOOKUP [id .lower ()]
295+
296+ start = match .group ('start' )
297+ if start is not None :
298+ end = match .group ('end' )
299+ llvm_width = None
300+ else :
301+ start = end = match .group ('width' )
302+ llvm_width = match .group ('llvm_width' )
303+ start = int (start )
304+ end = int (end )
305+
306+ bitwidth = start
307+ while bitwidth <= end :
308+ for ctor in type_ctors :
309+ if llvm_width is not None :
310+ assert not is_vector
311+ llvm_width = int (llvm_width )
312+ assert llvm_width < bitwidth
313+ scalar = ctor (bitwidth , llvm_width )
314+ else :
315+ scalar = ctor (bitwidth )
316+
317+ if is_vector :
318+ elem = Vector (scalar , width // bitwidth )
319+ else :
320+ elem = scalar
321+ yield ptrify (match , elem , width , previous )
322+ bitwidth *= 2
323+ elif reference is not None :
324+ reference = int (reference )
325+ assert reference < len (previous ), \
326+ 'referring to argument {}, but only {} are known' .format (reference ,
327+ len (previous ))
328+ ret = previous [reference ]
329+ for x in match .group ('modifiers' ) or []:
330+ ret = ret .modify (x , width )
331+ force = match .group ('force_width' )
332+ if force is not None :
333+ ret = ret .modify (force , width )
334+ yield ptrify (match , ret , width , previous )
298335 else :
299- start = end = match .group ('width' )
300- llvm_width = match .group ('llvm_width' )
301- start = int (start )
302- end = int (end )
303-
304- bitwidth = start
305- while bitwidth <= end :
306- for ctor in type_ctors :
307- if llvm_width is not None :
308- assert not is_vector
309- llvm_width = int (llvm_width )
310- assert llvm_width < bitwidth
311- scalar = ctor (bitwidth , llvm_width )
312- else :
313- scalar = ctor (bitwidth )
314-
315- if is_vector :
316- elem = Vector (scalar , width // bitwidth )
317- else :
318- elem = scalar
319- yield ptrify (match , elem , width )
320- bitwidth *= 2
336+ assert False , 'matched `{}`, but didn\' t understand it?' .format (spec )
337+ elif spec .startswith ('(' ):
338+ if spec .endswith (')' ):
339+ raise NotImplementedError ()
340+ elif spec .endswith (')f' ):
341+ true_spec = spec [1 :- 2 ]
342+ flatten = True
343+
344+ for elems in itertools .product (* (TypeSpec (subspec ).enumerate (width , previous )
345+ for subspec in true_spec .split (',' ))):
346+ yield Aggregate (flatten , elems )
321347 else :
322- pass
323- #print('Failed to parse: `{}`'.format(spec), file=sys.stderr)
324-
325- def resolve (self , width , zero ):
326- assert len (self .spec ) == 1
327- spec = self .spec [0 ]
328- match = SPEC .match (spec )
329- if match :
330- id = match .group ('id' )
331- if id is not None :
332- options = list (self .enumerate (width ))
333- assert len (options ) == 1
334- return options [0 ]
335- reference = match .group ('reference' )
336- if reference != '0' :
337- raise NotImplementedError ('only argument 0 (return value) references are supported' )
338- ret = zero
339- for x in match .group ('modifiers' ) or []:
340- ret = ret .modify (x , width )
341- force = match .group ('force_width' )
342- if force is not None :
343- ret = ret .modify (force , width )
344- return ptrify (match , ret , width )
345- elif spec .startswith ('(' ):
346- if spec .endswith (')' ):
347- raise NotImplementedError ()
348- elif spec .endswith (')f' ):
349- true_spec = spec [1 :- 2 ]
350- flatten = True
351- elems = [TypeSpec (subspec ).resolve (width , zero ) for subspec in true_spec .split (',' )]
352- return Aggregate (flatten , elems )
353- else :
354- assert False , 'Failed to resolve: {}' .format (spec )
348+ assert False , 'Failed to parse `{}`' .format (spec )
355349
356350class GenericIntrinsic (object ):
357351 def __init__ (self , platform , intrinsic , widths , llvm_name , ret , args ):
@@ -366,10 +360,22 @@ def monomorphise(self):
366360 for width in self .widths :
367361 # must be a power of two
368362 assert width & (width - 1 ) == 0
369- for ret in self .ret .enumerate (width ):
370- args = [arg .resolve (width , ret ) for arg in self .args ]
371- yield MonomorphicIntrinsic (self ._platform , self .intrinsic , width , self .llvm_name ,
372- ret , args )
363+ def recur (processed , untouched ):
364+ if untouched == []:
365+ ret = processed [0 ]
366+ args = processed [1 :]
367+ yield MonomorphicIntrinsic (self ._platform , self .intrinsic , width ,
368+ self .llvm_name ,
369+ ret , args )
370+ else :
371+ raw_arg = untouched [0 ]
372+ rest = untouched [1 :]
373+ for arg in raw_arg .enumerate (width , processed ):
374+ for intr in recur (processed + [arg ], rest ):
375+ yield intr
376+
377+ for x in recur ([], [self .ret ] + self .args ):
378+ yield x
373379
374380class MonomorphicIntrinsic (object ):
375381 def __init__ (self , platform , intrinsic , width , llvm_name , ret , args ):
@@ -517,8 +523,7 @@ def parse_args():
517523 A reference uses the type of another argument, with possible
518524 modifications. The number refers to the type to use, starting
519525 with 0 == return value, 1 == first argument, 2 == second
520- argument, etc. (Currently only referencing 0, the return
521- value, is supported.)
526+ argument, etc.
522527
523528 ### Modifiers
524529
0 commit comments