Skip to content

Commit 2b45a9a

Browse files
committed
Support bitcasts in platform intrinsic generator.
1 parent 62e346a commit 2b45a9a

File tree

4 files changed

+120
-38
lines changed

4 files changed

+120
-38
lines changed

src/etc/platform-intrinsics/generator.py

+105-34
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
SPEC = re.compile(
2020
r'^(?:(?P<void>V)|(?P<id>[iusfIUSF])(?:\((?P<start>\d+)-(?P<end>\d+)\)|'
2121
r'(?P<width>\d+)(:?/(?P<llvm_width>\d+))?)'
22-
r'|(?P<reference>\d+)(?P<modifiers>[vShdnwusDMC]*)(?P<force_width>x\d+)?)'
23-
r'(?:(?P<pointer>Pm|Pc)(?P<llvm_pointer>/.*)?)?$'
22+
r'|(?P<reference>\d+))(?P<modifiers>[vShdnwusDMC]*)(?P<force_width>x\d+)?'
23+
r'(?:(?P<pointer>Pm|Pc)(?P<llvm_pointer>/.*)?|(?P<bitcast>->.*))?$'
2424
)
2525

2626
class PlatformInfo(object):
@@ -74,6 +74,9 @@ def __init__(self, llvm_name, properties):
7474
self.properties = properties
7575
self.llvm_name = llvm_name
7676

77+
def __repr__(self):
78+
return '<PlatformTypeInfo {}, {}>'.format(self.llvm_name, self.properties)
79+
7780
def __getattr__(self, name):
7881
return self.properties[name]
7982

@@ -94,9 +97,12 @@ def __init__(self, bitwidth):
9497
def bitwidth(self):
9598
return self._bitwidth
9699

97-
def modify(self, spec, width):
100+
def modify(self, spec, width, previous):
98101
raise NotImplementedError()
99102

103+
def __ne__(self, other):
104+
return not (self == other)
105+
100106
class Void(Type):
101107
def __init__(self):
102108
Type.__init__(self, 0)
@@ -110,11 +116,14 @@ def rust_name(self):
110116
def type_info(self, platform_info):
111117
return None
112118

119+
def __eq__(self, other):
120+
return isinstance(other, Void)
121+
113122
class Number(Type):
114123
def __init__(self, bitwidth):
115124
Type.__init__(self, bitwidth)
116125

117-
def modify(self, spec, width):
126+
def modify(self, spec, width, previous):
118127
if spec == 'u':
119128
return Unsigned(self.bitwidth())
120129
elif spec == 's':
@@ -131,11 +140,16 @@ def modify(self, spec, width):
131140
def type_info(self, platform_info):
132141
return platform_info.number_type_info(self)
133142

143+
def __eq__(self, other):
144+
# print(self, other)
145+
return self.__class__ == other.__class__ and self.bitwidth() == other.bitwidth()
146+
134147
class Signed(Number):
135148
def __init__(self, bitwidth, llvm_bitwidth = None):
136149
Number.__init__(self, bitwidth)
137150
self._llvm_bitwidth = llvm_bitwidth
138151

152+
139153
def compiler_ctor(self):
140154
if self._llvm_bitwidth is None:
141155
return 'i({})'.format(self.bitwidth())
@@ -184,26 +198,47 @@ def rust_name(self):
184198
return 'f{}'.format(self.bitwidth())
185199

186200
class Vector(Type):
187-
def __init__(self, elem, length):
201+
def __init__(self, elem, length, bitcast = None):
188202
assert isinstance(elem, Type) and not isinstance(elem, Vector)
189203
Type.__init__(self,
190204
elem.bitwidth() * length)
191205
self._length = length
192206
self._elem = elem
207+
assert bitcast is None or (isinstance(bitcast, Vector) and
208+
bitcast._bitcast is None and
209+
bitcast._elem.bitwidth() == elem.bitwidth())
210+
if bitcast is not None and bitcast._elem != elem:
211+
self._bitcast = bitcast._elem
212+
else:
213+
self._bitcast = None
193214

194-
def modify(self, spec, width):
195-
if spec == 'h':
215+
def modify(self, spec, width, previous):
216+
if spec == 'S':
217+
return self._elem
218+
elif spec == 'h':
196219
return Vector(self._elem, self._length // 2)
197220
elif spec == 'd':
198221
return Vector(self._elem, self._length * 2)
199222
elif spec.startswith('x'):
200223
new_bitwidth = int(spec[1:])
201224
return Vector(self._elem, new_bitwidth // self._elem.bitwidth())
225+
elif spec.startswith('->'):
226+
bitcast_to = TypeSpec(spec[2:])
227+
choices = list(bitcast_to.enumerate(width, previous))
228+
assert len(choices) == 1
229+
bitcast_to = choices[0]
230+
return Vector(self._elem, self._length, bitcast_to)
202231
else:
203-
return Vector(self._elem.modify(spec, width), self._length)
232+
return Vector(self._elem.modify(spec, width, previous), self._length)
204233

205234
def compiler_ctor(self):
206-
return 'v({}, {})'.format(self._elem.compiler_ctor(), self._length)
235+
if self._bitcast is None:
236+
return 'v({}, {})'.format(self._elem.compiler_ctor(),
237+
self._length)
238+
else:
239+
return 'v_({}, {}, {})'.format(self._elem.compiler_ctor(),
240+
self._bitcast.compiler_ctor(),
241+
self._length)
207242

208243
def rust_name(self):
209244
return '{}x{}'.format(self._elem.rust_name(), self._length)
@@ -213,22 +248,26 @@ def type_info(self, platform_info):
213248
return elem_info.vectorize(self._length,
214249
platform_info.width_info(self.bitwidth()))
215250

251+
def __eq__(self, other):
252+
return isinstance(other, Vector) and self._length == other._length and \
253+
self._elem == other._elem and self._bitcast == other._bitcast
254+
216255
class Pointer(Type):
217256
def __init__(self, elem, llvm_elem, const):
218257
self._elem = elem;
219258
self._llvm_elem = llvm_elem
220259
self._const = const
221260
Type.__init__(self, BITWIDTH_POINTER)
222261

223-
def modify(self, spec, width):
262+
def modify(self, spec, width, previous):
224263
if spec == 'D':
225264
return self._elem
226265
elif spec == 'M':
227266
return Pointer(self._elem, self._llvm_elem, False)
228267
elif spec == 'C':
229268
return Pointer(self._elem, self._llvm_elem, True)
230269
else:
231-
return Pointer(self._elem.modify(spec, width), self._llvm_elem, self._const)
270+
return Pointer(self._elem.modify(spec, width, previous), self._llvm_elem, self._const)
232271

233272
def compiler_ctor(self):
234273
if self._llvm_elem is None:
@@ -246,6 +285,10 @@ def rust_name(self):
246285
def type_info(self, platform_info):
247286
return self._elem.type_info(platform_info).pointer()
248287

288+
def __eq__(self, other):
289+
return isinstance(other, Pointer) and self._const == other._const \
290+
and self._elem == other._elem and self._llvm_elem == other._llvm_elem
291+
249292
class Aggregate(Type):
250293
def __init__(self, flatten, elems):
251294
self._flatten = flatten
@@ -266,6 +309,10 @@ def type_info(self, platform_info):
266309
#return PlatformTypeInfo(None, None, self._llvm_name)
267310
return None
268311

312+
def __eq__(self, other):
313+
return isinstance(other, Aggregate) and self._flatten == other._flatten and \
314+
self._elems == other._elems
315+
269316

270317
TYPE_ID_LOOKUP = {'i': [Signed, Unsigned],
271318
's': [Signed],
@@ -302,6 +349,14 @@ def enumerate(self, width, previous):
302349
id = match.group('id')
303350
reference = match.group('reference')
304351

352+
modifiers = list(match.group('modifiers') or '')
353+
force = match.group('force_width')
354+
if force is not None:
355+
modifiers.append(force)
356+
bitcast = match.group('bitcast')
357+
if bitcast is not None:
358+
modifiers.append(bitcast)
359+
305360
if match.group('void') is not None:
306361
assert spec == 'V'
307362
yield Void()
@@ -333,7 +388,11 @@ def enumerate(self, width, previous):
333388
if is_vector:
334389
elem = Vector(scalar, width // bitwidth)
335390
else:
391+
assert bitcast is None
336392
elem = scalar
393+
394+
for x in modifiers:
395+
elem = elem.modify(x, width, previous)
337396
yield ptrify(match, elem, width, previous)
338397
bitwidth *= 2
339398
elif reference is not None:
@@ -342,15 +401,13 @@ def enumerate(self, width, previous):
342401
'referring to argument {}, but only {} are known'.format(reference,
343402
len(previous))
344403
ret = previous[reference]
345-
for x in match.group('modifiers') or []:
346-
ret = ret.modify(x, width)
347-
force = match.group('force_width')
348-
if force is not None:
349-
ret = ret.modify(force, width)
404+
for x in modifiers:
405+
ret = ret.modify(x, width, previous)
350406
yield ptrify(match, ret, width, previous)
351407
else:
352408
assert False, 'matched `{}`, but didn\'t understand it?'.format(spec)
353409
elif spec.startswith('('):
410+
assert bitcast is None
354411
if spec.endswith(')'):
355412
raise NotImplementedError()
356413
elif spec.endswith(')f'):
@@ -452,12 +509,16 @@ def parse_args():
452509
## Type specifier grammar
453510
454511
```
455-
type := core_type pointer?
512+
type := core_type modifier* suffix?
456513
457514
core_type := void | vector | scalar | aggregate | reference
458515
516+
modifier := 'v' | 'h' | 'd' | 'n' | 'w' | 'u' | 's' |
517+
'x' number
518+
suffix := pointer | bitcast
459519
pointer := 'Pm' llvm_pointer? | 'Pc' llvm_pointer?
460520
llvm_pointer := '/' type
521+
bitcast := '->' type
461522
462523
void := 'V'
463524
@@ -470,28 +531,13 @@ def parse_args():
470531
471532
aggregate := '(' (type),* ')' 'f'?
472533
473-
reference := number modifiers*
474-
modifiers := 'v' | 'h' | 'd' | 'n' | 'w' | 'u' | 's' |
475-
'x' number
476-
534+
reference := number
477535
478536
width = number | '(' number '-' number ')'
479537
480538
number = [0-9]+
481539
```
482540
483-
## Pointers
484-
485-
Pointers can be created to any type. The `m` vs. `c` chooses
486-
mut vs. const. e.g. `S32Pm` corresponds to `*mut i32`, and
487-
`i32Pc` corresponds (with width 128) to `*const i8x16`,
488-
`*const u32x4`, etc.
489-
490-
The type after the `/` (optional) represents the type used
491-
internally to LLVM, e.g. `S32pm/S8` is exposed as `*mut i32`
492-
in Rust, but is `i8*` in LLVM. (This defaults to the main
493-
type).
494-
495541
## Void
496542
497543
The `V` type corresponds to `void` in LLVM (`()` in
@@ -550,6 +596,11 @@ def parse_args():
550596
with 0 == return value, 1 == first argument, 2 == second
551597
argument, etc.
552598
599+
## Affixes
600+
601+
The `modifier` and `suffix` adaptors change the precise
602+
representation.
603+
553604
### Modifiers
554605
555606
- 'v': put a scalar into a vector of the current width (u32 -> u32x4, when width == 128)
@@ -563,6 +614,26 @@ def parse_args():
563614
- 'D': dereference a pointer (*mut u32 -> u32)
564615
- 'C': make a pointer const (*mut u32 -> *const u32)
565616
- 'M': make a pointer mut (*const u32 -> *mut u32)
617+
618+
### Pointers
619+
620+
Pointers can be created of any type by appending a `P*`
621+
suffix. The `m` vs. `c` chooses mut vs. const. e.g. `S32Pm`
622+
corresponds to `*mut i32`, and `i32Pc` corresponds (with width
623+
128) to `*const i8x16`, `*const u32x4`, etc.
624+
625+
The type after the `/` (optional) represents the type used
626+
internally to LLVM, e.g. `S32pm/S8` is exposed as `*mut i32`
627+
in Rust, but is `i8*` in LLVM. (This defaults to the main
628+
type).
629+
630+
### Bitcast
631+
632+
The `'->' type` bitcast suffix will cause the value to be
633+
bitcast to the right-hand type when calling the intrinsic,
634+
e.g. `s32->f32` will expose the intrinsic as `i32x4` at the
635+
Rust level, but will cast that vector to `f32x4` when calling
636+
the LLVM intrinsic.
566637
'''))
567638
parser.add_argument('--format', choices=FORMATS, required=True,
568639
help = 'Output format.')
@@ -611,7 +682,7 @@ def open(self, platform):
611682
612683
#![allow(unused_imports)]
613684
614-
use {{Intrinsic, i, i_, u, u_, f, v, agg, p, void}};
685+
use {{Intrinsic, i, i_, u, u_, f, v, v_, agg, p, void}};
615686
use IntrinsicDef::Named;
616687
use rustc::middle::ty;
617688

src/librustc_platform_intrinsics/lib.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub enum Type {
3434
Integer(/* signed */ bool, u8, /* llvm width */ u8),
3535
Float(u8),
3636
Pointer(Box<Type>, Option<Box<Type>>, /* const */ bool),
37-
Vector(Box<Type>, u8),
37+
Vector(Box<Type>, Option<Box<Type>>, u8),
3838
Aggregate(bool, Vec<Type>),
3939
}
4040

@@ -48,7 +48,10 @@ fn u(width: u8) -> Type { Type::Integer(false, width, width) }
4848
#[allow(dead_code)]
4949
fn u_(width: u8, llvm_width: u8) -> Type { Type::Integer(false, width, llvm_width) }
5050
fn f(width: u8) -> Type { Type::Float(width) }
51-
fn v(x: Type, length: u8) -> Type { Type::Vector(Box::new(x), length) }
51+
fn v(x: Type, length: u8) -> Type { Type::Vector(Box::new(x), None, length) }
52+
fn v_(x: Type, bitcast: Type, length: u8) -> Type {
53+
Type::Vector(Box::new(x), Some(Box::new(bitcast)), length)
54+
}
5255
fn agg(flatten: bool, types: Vec<Type>) -> Type {
5356
Type::Aggregate(flatten, types)
5457
}

src/librustc_trans/trans/intrinsic.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -956,7 +956,10 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
956956
any_changes_needed));
957957
vec![elem.ptr_to()]
958958
}
959-
Vector(ref t, length) => {
959+
Vector(ref t, ref llvm_elem, length) => {
960+
*any_changes_needed |= llvm_elem.is_some();
961+
962+
let t = llvm_elem.as_ref().unwrap_or(t);
960963
let elem = one(ty_to_type(ccx, t,
961964
any_changes_needed));
962965
vec![Type::vector(&elem,
@@ -1005,6 +1008,11 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
10051008
vec![PointerCast(bcx, llarg,
10061009
llvm_elem.ptr_to())]
10071010
}
1011+
intrinsics::Type::Vector(_, Some(ref llvm_elem), length) => {
1012+
let llvm_elem = one(ty_to_type(bcx.ccx(), llvm_elem, &mut false));
1013+
vec![BitCast(bcx, llarg,
1014+
Type::vector(&llvm_elem, length as u64))]
1015+
}
10081016
intrinsics::Type::Integer(_, width, llvm_width) if width != llvm_width => {
10091017
// the LLVM intrinsic uses a smaller integer
10101018
// size than the C intrinsic's signature, so

src/librustc_typeck/check/intrinsic.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,7 @@ fn match_intrinsic_type_to_type<'tcx, 'a>(
503503
&format!("raw pointer")),
504504
}
505505
}
506-
Vector(ref inner_expected, len) => {
506+
Vector(ref inner_expected, ref _llvm_type, len) => {
507507
if !t.is_simd() {
508508
simple_error(&format!("non-simd type `{}`", t),
509509
"simd type");

0 commit comments

Comments
 (0)