From d12135a70de99e1cf86e3147379f4eb0678cd97c Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 2 Sep 2015 13:59:35 -0700 Subject: [PATCH] Add support for pointers to generator.py. --- src/etc/platform-intrinsics/generator.py | 97 +++++++++++++++++++-- src/librustc_platform_intrinsics/aarch64.rs | 2 +- src/librustc_platform_intrinsics/arm.rs | 2 +- src/librustc_platform_intrinsics/lib.rs | 5 +- src/librustc_platform_intrinsics/x86.rs | 2 +- src/librustc_trans/trans/intrinsic.rs | 19 +++- src/librustc_typeck/check/intrinsic.rs | 15 +++- 7 files changed, 125 insertions(+), 17 deletions(-) diff --git a/src/etc/platform-intrinsics/generator.py b/src/etc/platform-intrinsics/generator.py index 97b2f57010b..bc1d428fee8 100644 --- a/src/etc/platform-intrinsics/generator.py +++ b/src/etc/platform-intrinsics/generator.py @@ -18,7 +18,8 @@ import textwrap SPEC = re.compile( r'^(?:(?P[iusfIUSF])(?:\((?P\d+)-(?P\d+)\)|' r'(?P\d+)(:?/(?P\d+))?)' - r'|(?P\d+)(?P[vShdnwus]*)(?Px\d+)?)$' + r'|(?P\d+)(?P[vShdnwusDMC]*)(?Px\d+)?)' + r'(?:(?PPm|Pc)(?P/.*)?)?$' ) class PlatformInfo(object): @@ -80,6 +81,11 @@ class PlatformTypeInfo(object): props.update(width_info) return PlatformTypeInfo('v{}{}'.format(length, self.llvm_name), props) + def pointer(self): + return PlatformTypeInfo('p0{}'.format(self.llvm_name), self.properties) + +BITWIDTH_POINTER = '' + class Type(object): def __init__(self, bitwidth): self._bitwidth = bitwidth @@ -193,6 +199,39 @@ class Vector(Type): return elem_info.vectorize(self._length, platform_info.width_info(self.bitwidth())) +class Pointer(Type): + def __init__(self, elem, llvm_elem, const): + self._elem = elem; + self._llvm_elem = llvm_elem + self._const = const + Type.__init__(self, BITWIDTH_POINTER) + + def modify(self, spec, width): + if spec == 'D': + return self._elem + elif spec == 'M': + return Pointer(self._elem, self._llvm_elem, False) + elif spec == 'C': + return Pointer(self._elem, self._llvm_elem, True) + else: + return Pointer(self._elem.modify(spec, width), self._llvm_elem, self._const) + + def compiler_ctor(self): + if self._llvm_elem is None: + llvm_elem = 'None' + else: + llvm_elem = 'Some({})'.format(self._llvm_elem.compiler_ctor()) + return 'p({}, {}, {})'.format('true' if self._const else 'false', + self._elem.compiler_ctor(), + llvm_elem) + + def rust_name(self): + return '*{} {}'.format('const' if self._const else 'mut', + self._elem.rust_name()) + + def type_info(self, platform_info): + return self._elem.type_info(platform_info).pointer() + class Aggregate(Type): def __init__(self, flatten, elems): self._flatten = flatten @@ -219,6 +258,22 @@ TYPE_ID_LOOKUP = {'i': [Signed, Unsigned], 'u': [Unsigned], 'f': [Float]} +def ptrify(match, elem, width): + ptr = match.group('pointer') + if ptr is None: + return elem + else: + llvm_ptr = match.group('llvm_pointer') + if llvm_ptr is None: + llvm_elem = None + else: + assert llvm_ptr.startswith('/') + options = list(TypeSpec(llvm_ptr[1:]).enumerate(width)) + assert len(options) == 1 + llvm_elem = options[0] + assert ptr in ('Pc', 'Pm') + return Pointer(elem, llvm_elem, ptr == 'Pc') + class TypeSpec(object): def __init__(self, spec): if not isinstance(spec, list): @@ -229,8 +284,10 @@ class TypeSpec(object): def enumerate(self, width): for spec in self.spec: match = SPEC.match(spec) - if match: + assert match is not None + if True: id = match.group('id') + assert id is not None is_vector = id.islower() type_ctors = TYPE_ID_LOOKUP[id.lower()] @@ -256,19 +313,21 @@ class TypeSpec(object): scalar = ctor(bitwidth) if is_vector: - yield Vector(scalar, width // bitwidth) + elem = Vector(scalar, width // bitwidth) else: - yield scalar + elem = scalar + yield ptrify(match, elem, width) bitwidth *= 2 else: - print('Failed to parse: `{}`'.format(spec), file=sys.stderr) + 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') + id = match.group('id') if id is not None: options = list(self.enumerate(width)) assert len(options) == 1 @@ -282,7 +341,7 @@ class TypeSpec(object): force = match.group('force_width') if force is not None: ret = ret.modify(force, width) - return ret + return ptrify(match, ret, width) elif spec.startswith('('): if spec.endswith(')'): raise NotImplementedError() @@ -291,6 +350,8 @@ class TypeSpec(object): 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) class GenericIntrinsic(object): def __init__(self, platform, intrinsic, widths, llvm_name, ret, args): @@ -369,7 +430,10 @@ def parse_args(): ## Type specifier grammar ``` - type := vector | scalar | aggregate | reference + type := ( vector | scalar | aggregate | reference ) pointer? + + pointer := 'Pm' llvm_pointer? | 'Pc' llvm_pointer? + llvm_pointer := '/' type vector := vector_elem width | vector_elem := 'i' | 'u' | 's' | 'f' @@ -390,6 +454,18 @@ def parse_args(): 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). + ## Vectors The vector grammar is a pattern describing many possibilities @@ -454,6 +530,9 @@ def parse_args(): - 'u': force an integer (vector or scalar) to be unsigned (i32x4 -> u32x4) - 's': force an integer (vector or scalar) to be signed (u32x4 -> i32x4) - 'x' number: force the type to be a vector of bitwidth `number`. + - '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) ''')) parser.add_argument('--format', choices=FORMATS, required=True, help = 'Output format.') @@ -502,7 +581,7 @@ class CompilerDefs(object): #![allow(unused_imports)] -use {{Intrinsic, i, i_, u, u_, f, v, agg}}; +use {{Intrinsic, i, i_, u, u_, f, v, agg, p}}; use IntrinsicDef::Named; use rustc::middle::ty; diff --git a/src/librustc_platform_intrinsics/aarch64.rs b/src/librustc_platform_intrinsics/aarch64.rs index 1f581d8ce85..c90d6b3816a 100644 --- a/src/librustc_platform_intrinsics/aarch64.rs +++ b/src/librustc_platform_intrinsics/aarch64.rs @@ -13,7 +13,7 @@ #![allow(unused_imports)] -use {Intrinsic, i, u, f, v, agg}; +use {Intrinsic, i, i_, u, u_, f, v, agg, p}; use IntrinsicDef::Named; use rustc::middle::ty; diff --git a/src/librustc_platform_intrinsics/arm.rs b/src/librustc_platform_intrinsics/arm.rs index 8ea725ee95d..89b147027b5 100644 --- a/src/librustc_platform_intrinsics/arm.rs +++ b/src/librustc_platform_intrinsics/arm.rs @@ -13,7 +13,7 @@ #![allow(unused_imports)] -use {Intrinsic, i, u, f, v, agg}; +use {Intrinsic, i, i_, u, u_, f, v, agg, p}; use IntrinsicDef::Named; use rustc::middle::ty; diff --git a/src/librustc_platform_intrinsics/lib.rs b/src/librustc_platform_intrinsics/lib.rs index 1727347ef7b..8c8beb031eb 100755 --- a/src/librustc_platform_intrinsics/lib.rs +++ b/src/librustc_platform_intrinsics/lib.rs @@ -32,7 +32,7 @@ pub struct Intrinsic { pub enum Type { Integer(/* signed */ bool, u8, /* llvm width */ u8), Float(u8), - Pointer(Box), + Pointer(Box, Option>, /* const */ bool), Vector(Box, u8), Aggregate(bool, Vec), } @@ -51,6 +51,9 @@ fn v(x: Type, length: u8) -> Type { Type::Vector(Box::new(x), length) } fn agg(flatten: bool, types: Vec) -> Type { Type::Aggregate(flatten, types) } +fn p(const_: bool, elem: Type, llvm_elem: Option) -> Type { + Type::Pointer(Box::new(elem), llvm_elem.map(Box::new), const_) +} mod x86; mod arm; diff --git a/src/librustc_platform_intrinsics/x86.rs b/src/librustc_platform_intrinsics/x86.rs index 64c31ccb50d..661603866ae 100644 --- a/src/librustc_platform_intrinsics/x86.rs +++ b/src/librustc_platform_intrinsics/x86.rs @@ -13,7 +13,7 @@ #![allow(unused_imports)] -use {Intrinsic, i, i_, u, u_, f, v, agg}; +use {Intrinsic, i, i_, u, u_, f, v, agg, p}; use IntrinsicDef::Named; use rustc::middle::ty; diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index abe72aed323..c2dee20b3bb 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -947,7 +947,14 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, _ => unreachable!() } } - Pointer(_) => unimplemented!(), + Pointer(ref t, ref llvm_elem, _const) => { + *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![elem.ptr_to()] + } Vector(ref t, length) => { let elem = one(ty_to_type(ccx, t, any_changes_needed)); @@ -965,8 +972,9 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } // This allows an argument list like `foo, (bar, baz), - // qux` to be converted into `foo, bar, baz, qux`, and - // integer arguments to be truncated as needed. + // qux` to be converted into `foo, bar, baz, qux`, integer + // arguments to be truncated as needed and pointers to be + // cast. fn modify_as_needed<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: &intrinsics::Type, arg_type: Ty<'tcx>, @@ -991,6 +999,11 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, }) .collect() } + intrinsics::Type::Pointer(_, Some(ref llvm_elem), _) => { + let llvm_elem = one(ty_to_type(bcx.ccx(), llvm_elem, &mut false)); + vec![PointerCast(bcx, llarg, + llvm_elem.ptr_to())] + } 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 0c8bdc0ee04..54f6ec0f0ed 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -485,7 +485,20 @@ fn match_intrinsic_type_to_type<'tcx, 'a>( _ => simple_error(&format!("`{}`", t), &format!("`f{n}`", n = bits)), }, - Pointer(_) => unimplemented!(), + Pointer(ref inner_expected, ref _llvm_type, const_) => { + match t.sty { + ty::TyRawPtr(ty::TypeAndMut { ty, mutbl }) => { + if (mutbl == hir::MutImmutable) != const_ { + simple_error(&format!("`{}`", t), + if const_ {"const pointer"} else {"mut pointer"}) + } + match_intrinsic_type_to_type(tcx, position, span, structural_to_nominal, + inner_expected, ty) + } + _ => simple_error(&format!("`{}`", t), + &format!("raw pointer")), + } + } Vector(ref inner_expected, len) => { if !t.is_simd() { simple_error(&format!("non-simd type `{}`", t),