14
14
import sys
15
15
import re
16
16
import textwrap
17
+ import itertools
17
18
18
19
SPEC = re .compile (
19
20
r'^(?:(?P<id>[iusfIUSF])(?:\((?P<start>\d+)-(?P<end>\d+)\)|'
@@ -258,7 +259,7 @@ def type_info(self, platform_info):
258
259
'u' : [Unsigned ],
259
260
'f' : [Float ]}
260
261
261
- def ptrify (match , elem , width ):
262
+ def ptrify (match , elem , width , previous ):
262
263
ptr = match .group ('pointer' )
263
264
if ptr is None :
264
265
return elem
@@ -268,7 +269,7 @@ def ptrify(match, elem, width):
268
269
llvm_elem = None
269
270
else :
270
271
assert llvm_ptr .startswith ('/' )
271
- options = list (TypeSpec (llvm_ptr [1 :]).enumerate (width ))
272
+ options = list (TypeSpec (llvm_ptr [1 :]).enumerate (width , previous ))
272
273
assert len (options ) == 1
273
274
llvm_elem = options [0 ]
274
275
assert ptr in ('Pc' , 'Pm' )
@@ -281,77 +282,70 @@ def __init__(self, spec):
281
282
282
283
self .spec = spec
283
284
284
- def enumerate (self , width ):
285
+ def enumerate (self , width , previous ):
285
286
for spec in self .spec :
286
287
match = SPEC .match (spec )
287
- assert match is not None
288
- if True :
288
+ if match is not None :
289
289
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 )
298
335
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 )
321
347
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 )
355
349
356
350
class GenericIntrinsic (object ):
357
351
def __init__ (self , platform , intrinsic , widths , llvm_name , ret , args ):
@@ -366,10 +360,22 @@ def monomorphise(self):
366
360
for width in self .widths :
367
361
# must be a power of two
368
362
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
373
379
374
380
class MonomorphicIntrinsic (object ):
375
381
def __init__ (self , platform , intrinsic , width , llvm_name , ret , args ):
@@ -517,8 +523,7 @@ def parse_args():
517
523
A reference uses the type of another argument, with possible
518
524
modifications. The number refers to the type to use, starting
519
525
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.
522
527
523
528
### Modifiers
524
529
0 commit comments