mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 02:57:37 +00:00
Support bitcasts in platform intrinsic generator.
This commit is contained in:
parent
62e346af4b
commit
2b45a9ab54
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user