diff options
| author | Huon Wilson <dbau.pp+github@gmail.com> | 2015-09-03 11:25:52 -0700 |
|---|---|---|
| committer | Huon Wilson <dbau.pp+github@gmail.com> | 2015-09-04 09:14:13 -0700 |
| commit | 2b45a9ab54fbf593c6df84e8852fc1b3f1f0810a (patch) | |
| tree | 8eee2a96776bc088dbef628185b58d4afea0482e | |
| parent | 62e346af4b7a1aac43db627f19d2511d5649e5d7 (diff) | |
| download | rust-2b45a9ab54fbf593c6df84e8852fc1b3f1f0810a.tar.gz rust-2b45a9ab54fbf593c6df84e8852fc1b3f1f0810a.zip | |
Support bitcasts in platform intrinsic generator.
| -rw-r--r-- | src/etc/platform-intrinsics/generator.py | 139 | ||||
| -rwxr-xr-x | src/librustc_platform_intrinsics/lib.rs | 7 | ||||
| -rw-r--r-- | src/librustc_trans/trans/intrinsic.rs | 10 | ||||
| -rw-r--r-- | src/librustc_typeck/check/intrinsic.rs | 2 |
4 files changed, 120 insertions, 38 deletions
diff --git a/src/etc/platform-intrinsics/generator.py b/src/etc/platform-intrinsics/generator.py index b62c35246ca..8708e7c2f0f 100644 --- a/src/etc/platform-intrinsics/generator.py +++ b/src/etc/platform-intrinsics/generator.py @@ -19,8 +19,8 @@ import itertools SPEC = re.compile( r'^(?:(?P<void>V)|(?P<id>[iusfIUSF])(?:\((?P<start>\d+)-(?P<end>\d+)\)|' r'(?P<width>\d+)(:?/(?P<llvm_width>\d+))?)' - r'|(?P<reference>\d+)(?P<modifiers>[vShdnwusDMC]*)(?P<force_width>x\d+)?)' - r'(?:(?P<pointer>Pm|Pc)(?P<llvm_pointer>/.*)?)?$' + r'|(?P<reference>\d+))(?P<modifiers>[vShdnwusDMC]*)(?P<force_width>x\d+)?' + r'(?:(?P<pointer>Pm|Pc)(?P<llvm_pointer>/.*)?|(?P<bitcast>->.*))?$' ) class PlatformInfo(object): @@ -74,6 +74,9 @@ class PlatformTypeInfo(object): self.properties = properties self.llvm_name = llvm_name + def __repr__(self): + return '<PlatformTypeInfo {}, {}>'.format(self.llvm_name, self.properties) + def __getattr__(self, name): return self.properties[name] @@ -94,9 +97,12 @@ class Type(object): def bitwidth(self): return self._bitwidth - def modify(self, spec, width): + def modify(self, spec, width, previous): raise NotImplementedError() + def __ne__(self, other): + return not (self == other) + class Void(Type): def __init__(self): Type.__init__(self, 0) @@ -110,11 +116,14 @@ class Void(Type): def type_info(self, platform_info): return None + def __eq__(self, other): + return isinstance(other, Void) + class Number(Type): def __init__(self, bitwidth): Type.__init__(self, bitwidth) - def modify(self, spec, width): + def modify(self, spec, width, previous): if spec == 'u': return Unsigned(self.bitwidth()) elif spec == 's': @@ -131,11 +140,16 @@ class Number(Type): def type_info(self, platform_info): return platform_info.number_type_info(self) + def __eq__(self, other): + # print(self, other) + return self.__class__ == other.__class__ and self.bitwidth() == other.bitwidth() + class Signed(Number): def __init__(self, bitwidth, llvm_bitwidth = None): Number.__init__(self, bitwidth) self._llvm_bitwidth = llvm_bitwidth + def compiler_ctor(self): if self._llvm_bitwidth is None: return 'i({})'.format(self.bitwidth()) @@ -184,26 +198,47 @@ class Float(Number): return 'f{}'.format(self.bitwidth()) class Vector(Type): - def __init__(self, elem, length): + def __init__(self, elem, length, bitcast = None): assert isinstance(elem, Type) and not isinstance(elem, Vector) Type.__init__(self, elem.bitwidth() * length) self._length = length self._elem = elem + assert bitcast is None or (isinstance(bitcast, Vector) and + bitcast._bitcast is None and + bitcast._elem.bitwidth() == elem.bitwidth()) + if bitcast is not None and bitcast._elem != elem: + self._bitcast = bitcast._elem + else: + self._bitcast = None - def modify(self, spec, width): - if spec == 'h': + def modify(self, spec, width, previous): + if spec == 'S': + return self._elem + elif spec == 'h': return Vector(self._elem, self._length // 2) elif spec == 'd': return Vector(self._elem, self._length * 2) elif spec.startswith('x'): new_bitwidth = int(spec[1:]) return Vector(self._elem, new_bitwidth // self._elem.bitwidth()) + elif spec.startswith('->'): + bitcast_to = TypeSpec(spec[2:]) + choices = list(bitcast_to.enumerate(width, previous)) + assert len(choices) == 1 + bitcast_to = choices[0] + return Vector(self._elem, self._length, bitcast_to) else: - return Vector(self._elem.modify(spec, width), self._length) + return Vector(self._elem.modify(spec, width, previous), self._length) def compiler_ctor(self): - return 'v({}, {})'.format(self._elem.compiler_ctor(), self._length) + if self._bitcast is None: + return 'v({}, {})'.format(self._elem.compiler_ctor(), + self._length) + else: + return 'v_({}, {}, {})'.format(self._elem.compiler_ctor(), + self._bitcast.compiler_ctor(), + self._length) def rust_name(self): return '{}x{}'.format(self._elem.rust_name(), self._length) @@ -213,6 +248,10 @@ class Vector(Type): return elem_info.vectorize(self._length, platform_info.width_info(self.bitwidth())) + def __eq__(self, other): + return isinstance(other, Vector) and self._length == other._length and \ + self._elem == other._elem and self._bitcast == other._bitcast + class Pointer(Type): def __init__(self, elem, llvm_elem, const): self._elem = elem; @@ -220,7 +259,7 @@ class Pointer(Type): self._const = const Type.__init__(self, BITWIDTH_POINTER) - def modify(self, spec, width): + def modify(self, spec, width, previous): if spec == 'D': return self._elem elif spec == 'M': @@ -228,7 +267,7 @@ class Pointer(Type): elif spec == 'C': return Pointer(self._elem, self._llvm_elem, True) else: - return Pointer(self._elem.modify(spec, width), self._llvm_elem, self._const) + return Pointer(self._elem.modify(spec, width, previous), self._llvm_elem, self._const) def compiler_ctor(self): if self._llvm_elem is None: @@ -246,6 +285,10 @@ class Pointer(Type): def type_info(self, platform_info): return self._elem.type_info(platform_info).pointer() + def __eq__(self, other): + return isinstance(other, Pointer) and self._const == other._const \ + and self._elem == other._elem and self._llvm_elem == other._llvm_elem + class Aggregate(Type): def __init__(self, flatten, elems): self._flatten = flatten @@ -266,6 +309,10 @@ class Aggregate(Type): #return PlatformTypeInfo(None, None, self._llvm_name) return None + def __eq__(self, other): + return isinstance(other, Aggregate) and self._flatten == other._flatten and \ + self._elems == other._elems + TYPE_ID_LOOKUP = {'i': [Signed, Unsigned], 's': [Signed], @@ -302,6 +349,14 @@ class TypeSpec(object): id = match.group('id') reference = match.group('reference') + modifiers = list(match.group('modifiers') or '') + force = match.group('force_width') + if force is not None: + modifiers.append(force) + bitcast = match.group('bitcast') + if bitcast is not None: + modifiers.append(bitcast) + if match.group('void') is not None: assert spec == 'V' yield Void() @@ -333,7 +388,11 @@ class TypeSpec(object): if is_vector: elem = Vector(scalar, width // bitwidth) else: + assert bitcast is None elem = scalar + + for x in modifiers: + elem = elem.modify(x, width, previous) yield ptrify(match, elem, width, previous) bitwidth *= 2 elif reference is not None: @@ -342,15 +401,13 @@ class TypeSpec(object): '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) + for x in modifiers: + ret = ret.modify(x, width, previous) yield ptrify(match, ret, width, previous) else: assert False, 'matched `{}`, but didn\'t understand it?'.format(spec) elif spec.startswith('('): + assert bitcast is None if spec.endswith(')'): raise NotImplementedError() elif spec.endswith(')f'): @@ -452,12 +509,16 @@ def parse_args(): ## Type specifier grammar ``` - type := core_type pointer? + type := core_type modifier* suffix? core_type := void | vector | scalar | aggregate | reference + modifier := 'v' | 'h' | 'd' | 'n' | 'w' | 'u' | 's' | + 'x' number + suffix := pointer | bitcast pointer := 'Pm' llvm_pointer? | 'Pc' llvm_pointer? llvm_pointer := '/' type + bitcast := '->' type void := 'V' @@ -470,28 +531,13 @@ def parse_args(): aggregate := '(' (type),* ')' 'f'? - reference := number modifiers* - modifiers := 'v' | 'h' | 'd' | 'n' | 'w' | 'u' | 's' | - 'x' number - + reference := number width = number | '(' number '-' number ')' number = [0-9]+ ``` - ## Pointers - - Pointers can be created to any type. The `m` vs. `c` chooses - mut vs. const. e.g. `S32Pm` corresponds to `*mut i32`, and - `i32Pc` corresponds (with width 128) to `*const i8x16`, - `*const u32x4`, etc. - - The type after the `/` (optional) represents the type used - internally to LLVM, e.g. `S32pm/S8` is exposed as `*mut i32` - in Rust, but is `i8*` in LLVM. (This defaults to the main - type). - ## Void The `V` type corresponds to `void` in LLVM (`()` in @@ -550,6 +596,11 @@ def parse_args(): with 0 == return value, 1 == first argument, 2 == second argument, etc. + ## Affixes + + The `modifier` and `suffix` adaptors change the precise + representation. + ### Modifiers - 'v': put a scalar into a vector of the current width (u32 -> u32x4, when width == 128) @@ -563,6 +614,26 @@ def parse_args(): - 'D': dereference a pointer (*mut u32 -> u32) - 'C': make a pointer const (*mut u32 -> *const u32) - 'M': make a pointer mut (*const u32 -> *mut u32) + + ### Pointers + + Pointers can be created of any type by appending a `P*` + suffix. The `m` vs. `c` chooses mut vs. const. e.g. `S32Pm` + corresponds to `*mut i32`, and `i32Pc` corresponds (with width + 128) to `*const i8x16`, `*const u32x4`, etc. + + The type after the `/` (optional) represents the type used + internally to LLVM, e.g. `S32pm/S8` is exposed as `*mut i32` + in Rust, but is `i8*` in LLVM. (This defaults to the main + type). + + ### Bitcast + + The `'->' type` bitcast suffix will cause the value to be + bitcast to the right-hand type when calling the intrinsic, + e.g. `s32->f32` will expose the intrinsic as `i32x4` at the + Rust level, but will cast that vector to `f32x4` when calling + the LLVM intrinsic. ''')) parser.add_argument('--format', choices=FORMATS, required=True, help = 'Output format.') @@ -611,7 +682,7 @@ class CompilerDefs(object): #![allow(unused_imports)] -use {{Intrinsic, i, i_, u, u_, f, v, agg, p, void}}; +use {{Intrinsic, i, i_, u, u_, f, v, v_, agg, p, void}}; use IntrinsicDef::Named; use rustc::middle::ty; diff --git a/src/librustc_platform_intrinsics/lib.rs b/src/librustc_platform_intrinsics/lib.rs index 95da12a2378..9aee15b05df 100755 --- a/src/librustc_platform_intrinsics/lib.rs +++ b/src/librustc_platform_intrinsics/lib.rs @@ -34,7 +34,7 @@ pub enum Type { Integer(/* signed */ bool, u8, /* llvm width */ u8), Float(u8), Pointer(Box<Type>, Option<Box<Type>>, /* const */ bool), - Vector(Box<Type>, u8), + Vector(Box<Type>, Option<Box<Type>>, u8), Aggregate(bool, Vec<Type>), } @@ -48,7 +48,10 @@ fn u(width: u8) -> Type { Type::Integer(false, width, width) } #[allow(dead_code)] fn u_(width: u8, llvm_width: u8) -> Type { Type::Integer(false, width, llvm_width) } fn f(width: u8) -> Type { Type::Float(width) } -fn v(x: Type, length: u8) -> Type { Type::Vector(Box::new(x), length) } +fn v(x: Type, length: u8) -> Type { Type::Vector(Box::new(x), None, length) } +fn v_(x: Type, bitcast: Type, length: u8) -> Type { + Type::Vector(Box::new(x), Some(Box::new(bitcast)), length) +} fn agg(flatten: bool, types: Vec<Type>) -> Type { Type::Aggregate(flatten, types) } diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index a6816a99d28..becdd71f1d3 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -956,7 +956,10 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, any_changes_needed)); vec![elem.ptr_to()] } - Vector(ref t, length) => { + Vector(ref t, ref llvm_elem, length) => { + *any_changes_needed |= llvm_elem.is_some(); + + let t = llvm_elem.as_ref().unwrap_or(t); let elem = one(ty_to_type(ccx, t, any_changes_needed)); vec![Type::vector(&elem, @@ -1005,6 +1008,11 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, vec![PointerCast(bcx, llarg, llvm_elem.ptr_to())] } + intrinsics::Type::Vector(_, Some(ref llvm_elem), length) => { + let llvm_elem = one(ty_to_type(bcx.ccx(), llvm_elem, &mut false)); + vec![BitCast(bcx, llarg, + Type::vector(&llvm_elem, length as u64))] + } intrinsics::Type::Integer(_, width, llvm_width) if width != llvm_width => { // the LLVM intrinsic uses a smaller integer // size than the C intrinsic's signature, so diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 4501d1c618a..d1f898d82fd 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -503,7 +503,7 @@ fn match_intrinsic_type_to_type<'tcx, 'a>( &format!("raw pointer")), } } - Vector(ref inner_expected, len) => { + Vector(ref inner_expected, ref _llvm_type, len) => { if !t.is_simd() { simple_error(&format!("non-simd type `{}`", t), "simd type"); |
