Skip to content

Commit

Permalink
Add support for pointers to generator.py.
Browse files Browse the repository at this point in the history
  • Loading branch information
huonw committed Sep 4, 2015
1 parent 2f77a59 commit d12135a
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 17 deletions.
97 changes: 88 additions & 9 deletions src/etc/platform-intrinsics/generator.py
Expand Up @@ -18,7 +18,8 @@
SPEC = re.compile(
r'^(?:(?P<id>[iusfIUSF])(?:\((?P<start>\d+)-(?P<end>\d+)\)|'
r'(?P<width>\d+)(:?/(?P<llvm_width>\d+))?)'
r'|(?P<reference>\d+)(?P<modifiers>[vShdnwus]*)(?P<force_width>x\d+)?)$'
r'|(?P<reference>\d+)(?P<modifiers>[vShdnwusDMC]*)(?P<force_width>x\d+)?)'
r'(?:(?P<pointer>Pm|Pc)(?P<llvm_pointer>/.*)?)?$'
)

class PlatformInfo(object):
Expand Down Expand Up @@ -80,6 +81,11 @@ def vectorize(self, length, width_info):
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 = '<pointer>'

class Type(object):
def __init__(self, bitwidth):
self._bitwidth = bitwidth
Expand Down Expand Up @@ -193,6 +199,39 @@ def type_info(self, platform_info):
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
Expand All @@ -219,6 +258,22 @@ def type_info(self, platform_info):
'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):
Expand All @@ -229,8 +284,10 @@ def __init__(self, spec):
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()]

Expand All @@ -256,19 +313,21 @@ def enumerate(self, width):
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
Expand All @@ -282,7 +341,7 @@ def resolve(self, width, zero):
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()
Expand All @@ -291,6 +350,8 @@ def resolve(self, width, zero):
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):
Expand Down Expand Up @@ -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'
Expand All @@ -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
Expand Down Expand Up @@ -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.')
Expand Down Expand Up @@ -502,7 +581,7 @@ def open(self, platform):
#![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;
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_platform_intrinsics/aarch64.rs
Expand Up @@ -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;

Expand Down
2 changes: 1 addition & 1 deletion src/librustc_platform_intrinsics/arm.rs
Expand Up @@ -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;

Expand Down
5 changes: 4 additions & 1 deletion src/librustc_platform_intrinsics/lib.rs
Expand Up @@ -32,7 +32,7 @@ pub struct Intrinsic {
pub enum Type {
Integer(/* signed */ bool, u8, /* llvm width */ u8),
Float(u8),
Pointer(Box<Type>),
Pointer(Box<Type>, Option<Box<Type>>, /* const */ bool),
Vector(Box<Type>, u8),
Aggregate(bool, Vec<Type>),
}
Expand All @@ -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 {
Type::Aggregate(flatten, types)
}
fn p(const_: bool, elem: Type, llvm_elem: Option<Type>) -> Type {
Type::Pointer(Box::new(elem), llvm_elem.map(Box::new), const_)
}

mod x86;
mod arm;
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_platform_intrinsics/x86.rs
Expand Up @@ -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;

Expand Down
19 changes: 16 additions & 3 deletions src/librustc_trans/trans/intrinsic.rs
Expand Up @@ -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));
Expand All @@ -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>,
Expand All @@ -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
Expand Down
15 changes: 14 additions & 1 deletion src/librustc_typeck/check/intrinsic.rs
Expand Up @@ -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),
Expand Down

0 comments on commit d12135a

Please sign in to comment.