]> git.lizzy.rs Git - rust.git/commitdiff
Support non-return value references in platform intrinsic generator.
authorHuon Wilson <dbau.pp+github@gmail.com>
Wed, 2 Sep 2015 23:46:41 +0000 (16:46 -0700)
committerHuon Wilson <dbau.pp+github@gmail.com>
Fri, 4 Sep 2015 16:14:13 +0000 (09:14 -0700)
src/etc/platform-intrinsics/generator.py

index bc1d428fee85696cfaf33cc296d7512fe222badc..2102bd9c488ba3fe8b69d0eed8a4f6212a043026 100644 (file)
@@ -14,6 +14,7 @@ import argparse
 import sys
 import re
 import textwrap
+import itertools
 
 SPEC = re.compile(
     r'^(?:(?P<id>[iusfIUSF])(?:\((?P<start>\d+)-(?P<end>\d+)\)|'
@@ -258,7 +259,7 @@ TYPE_ID_LOOKUP = {'i': [Signed, Unsigned],
                   'u': [Unsigned],
                   'f': [Float]}
 
-def ptrify(match, elem, width):
+def ptrify(match, elem, width, previous):
     ptr = match.group('pointer')
     if ptr is None:
         return elem
@@ -268,7 +269,7 @@ def ptrify(match, elem, width):
             llvm_elem = None
         else:
             assert llvm_ptr.startswith('/')
-            options = list(TypeSpec(llvm_ptr[1:]).enumerate(width))
+            options = list(TypeSpec(llvm_ptr[1:]).enumerate(width, previous))
             assert len(options) == 1
             llvm_elem = options[0]
         assert ptr in ('Pc', 'Pm')
@@ -281,77 +282,70 @@ class TypeSpec(object):
 
         self.spec = spec
 
-    def enumerate(self, width):
+    def enumerate(self, width, previous):
         for spec in self.spec:
             match = SPEC.match(spec)
-            assert match is not None
-            if True:
+            if match is not None:
                 id = match.group('id')
-                assert id is not None
-                is_vector = id.islower()
-                type_ctors = TYPE_ID_LOOKUP[id.lower()]
-
-                start = match.group('start')
-                if start is not None:
-                    end = match.group('end')
-                    llvm_width = None
+                reference = match.group('reference')
+
+                if id is not None:
+                    is_vector = id.islower()
+                    type_ctors = TYPE_ID_LOOKUP[id.lower()]
+
+                    start = match.group('start')
+                    if start is not None:
+                        end = match.group('end')
+                        llvm_width = None
+                    else:
+                        start = end = match.group('width')
+                        llvm_width = match.group('llvm_width')
+                    start = int(start)
+                    end = int(end)
+
+                    bitwidth = start
+                    while bitwidth <= end:
+                        for ctor in type_ctors:
+                            if llvm_width is not None:
+                                assert not is_vector
+                                llvm_width = int(llvm_width)
+                                assert llvm_width < bitwidth
+                                scalar = ctor(bitwidth, llvm_width)
+                            else:
+                                scalar = ctor(bitwidth)
+
+                            if is_vector:
+                                elem = Vector(scalar, width // bitwidth)
+                            else:
+                                elem = scalar
+                            yield ptrify(match, elem, width, previous)
+                        bitwidth *= 2
+                elif reference is not None:
+                    reference = int(reference)
+                    assert reference < len(previous), \
+                        'referring to argument {}, but only {} are known'.format(reference,
+                                                                                 len(previous))
+                    ret = previous[reference]
+                    for x in match.group('modifiers') or []:
+                        ret = ret.modify(x, width)
+                    force = match.group('force_width')
+                    if force is not None:
+                        ret = ret.modify(force, width)
+                    yield ptrify(match, ret, width, previous)
                 else:
-                    start = end = match.group('width')
-                    llvm_width = match.group('llvm_width')
-                start = int(start)
-                end = int(end)
-
-                bitwidth = start
-                while bitwidth <= end:
-                    for ctor in type_ctors:
-                        if llvm_width is not None:
-                            assert not is_vector
-                            llvm_width = int(llvm_width)
-                            assert llvm_width < bitwidth
-                            scalar = ctor(bitwidth, llvm_width)
-                        else:
-                            scalar = ctor(bitwidth)
-
-                        if is_vector:
-                            elem = Vector(scalar, width // bitwidth)
-                        else:
-                            elem = scalar
-                        yield ptrify(match, elem, width)
-                    bitwidth *= 2
+                    assert False, 'matched `{}`, but didn\'t understand it?'.format(spec)
+            elif spec.startswith('('):
+                if spec.endswith(')'):
+                    raise NotImplementedError()
+                elif spec.endswith(')f'):
+                    true_spec = spec[1:-2]
+                    flatten = True
+
+                for elems in itertools.product(*(TypeSpec(subspec).enumerate(width, previous)
+                                                 for subspec in true_spec.split(','))):
+                    yield Aggregate(flatten, elems)
             else:
-                pass
-                #print('Failed to parse: `{}`'.format(spec), file=sys.stderr)
-
-    def resolve(self, width, zero):
-        assert len(self.spec) == 1
-        spec = self.spec[0]
-        match = SPEC.match(spec)
-        if match:
-            id = match.group('id')
-            if id is not None:
-                options = list(self.enumerate(width))
-                assert len(options) == 1
-                return options[0]
-            reference = match.group('reference')
-            if reference != '0':
-                raise NotImplementedError('only argument 0 (return value) references are supported')
-            ret = zero
-            for x in match.group('modifiers') or []:
-                ret = ret.modify(x, width)
-            force = match.group('force_width')
-            if force is not None:
-                ret = ret.modify(force, width)
-            return ptrify(match, ret, width)
-        elif spec.startswith('('):
-            if spec.endswith(')'):
-                raise NotImplementedError()
-            elif spec.endswith(')f'):
-                true_spec = spec[1:-2]
-                flatten = True
-            elems = [TypeSpec(subspec).resolve(width, zero) for subspec in true_spec.split(',')]
-            return Aggregate(flatten, elems)
-        else:
-            assert False, 'Failed to resolve: {}'.format(spec)
+                assert False, 'Failed to parse `{}`'.format(spec)
 
 class GenericIntrinsic(object):
     def __init__(self, platform, intrinsic, widths, llvm_name, ret, args):
@@ -366,10 +360,22 @@ class GenericIntrinsic(object):
         for width in self.widths:
             # must be a power of two
             assert width & (width - 1) == 0
-            for ret in self.ret.enumerate(width):
-                args = [arg.resolve(width, ret) for arg in self.args]
-                yield MonomorphicIntrinsic(self._platform, self.intrinsic, width, self.llvm_name,
-                                           ret, args)
+            def recur(processed, untouched):
+                if untouched == []:
+                    ret = processed[0]
+                    args = processed[1:]
+                    yield MonomorphicIntrinsic(self._platform, self.intrinsic, width,
+                                               self.llvm_name,
+                                               ret, args)
+                else:
+                    raw_arg = untouched[0]
+                    rest = untouched[1:]
+                    for arg in raw_arg.enumerate(width, processed):
+                        for intr in recur(processed + [arg], rest):
+                            yield intr
+
+            for x in recur([], [self.ret] + self.args):
+                yield x
 
 class MonomorphicIntrinsic(object):
     def __init__(self, platform, intrinsic, width, llvm_name, ret, args):
@@ -517,8 +523,7 @@ def parse_args():
         A reference uses the type of another argument, with possible
         modifications. The number refers to the type to use, starting
         with 0 == return value, 1 == first argument, 2 == second
-        argument, etc. (Currently only referencing 0, the return
-        value, is supported.)
+        argument, etc.
 
         ### Modifiers