]> git.proxmox.com Git - rustc.git/blob - src/etc/platform-intrinsics/generator.py
a21194962f9b061663203c969ce6c115b4bc097b
[rustc.git] / src / etc / platform-intrinsics / generator.py
1 # Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 # file at the top-level directory of this distribution and at
3 # http://rust-lang.org/COPYRIGHT.
4 #
5 # Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 # http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 # <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 # option. This file may not be copied, modified, or distributed
9 # except according to those terms.
10
11 from __future__ import division, print_function
12 import json
13 import argparse
14 import sys
15 import re
16 import textwrap
17 import itertools
18
19 SPEC = re.compile(
20 r'^(?:(?P<void>V)|(?P<id>[iusfIUSF])(?:\((?P<start>\d+)-(?P<end>\d+)\)|'
21 r'(?P<width>\d+)(:?/(?P<llvm_width>\d+))?)'
22 r'|(?P<reference>\d+))(?P<index>\.\d+)?(?P<modifiers>[vShdnwusfDMC]*)(?P<force_width>x\d+)?'
23 r'(?:(?P<pointer>Pm|Pc)(?P<llvm_pointer>/.*)?|(?P<bitcast>->.*))?$'
24 )
25
26 class PlatformInfo(object):
27 def __init__(self, json):
28 self._platform = json['platform']
29 self._intrinsic_prefix = json['intrinsic_prefix']
30
31 def intrinsic_prefix(self):
32 return self._intrinsic_prefix
33
34 class IntrinsicSet(object):
35 def __init__(self, platform, json):
36 self._llvm_prefix = json['llvm_prefix']
37 self._type_info = json['number_info']
38 self._intrinsics = json['intrinsics']
39 self._widths = json['width_info']
40 self._platform = platform
41
42 def intrinsics(self):
43 for raw in self._intrinsics:
44 yield GenericIntrinsic(self,
45 raw['intrinsic'], raw['width'], raw['llvm'],
46 raw['ret'], raw['args'])
47
48 def platform(self):
49 return self._platform
50
51 def llvm_prefix(self):
52 return self._llvm_prefix
53
54 def width_info(self, bitwidth):
55 return self._widths[str(bitwidth)]
56
57 def number_type_info(self, value):
58 data = self._type_info[value.__class__.__name__.lower()]
59 bitwidth = value.bitwidth()
60 def lookup(raw):
61 if not isinstance(raw, dict):
62 return raw
63
64 try:
65 return raw[str(bitwidth)]
66 except KeyError:
67 return raw['pattern'].format(bitwidth = bitwidth)
68
69 return PlatformTypeInfo(value.llvm_name(),
70 {k: lookup(v) for k, v in data.items()})
71
72 class PlatformTypeInfo(object):
73 def __init__(self, llvm_name, properties, elems = None):
74 if elems is None:
75 self.properties = properties
76 self.llvm_name = llvm_name
77 else:
78 assert properties is None and llvm_name is None
79 self.properties = {}
80 self.elems = elems
81
82 def __repr__(self):
83 return '<PlatformTypeInfo {}, {}>'.format(self.llvm_name, self.properties)
84
85 def __getattr__(self, name):
86 return self.properties[name]
87
88 def __getitem__(self, idx):
89 return self.elems[idx]
90
91 def vectorize(self, length, width_info):
92 props = self.properties.copy()
93 props.update(width_info)
94 return PlatformTypeInfo('v{}{}'.format(length, self.llvm_name), props)
95
96 def pointer(self, llvm_elem):
97 name = self.llvm_name if llvm_elem is None else llvm_elem.llvm_name
98 return PlatformTypeInfo('p0{}'.format(name), self.properties)
99
100 BITWIDTH_POINTER = '<pointer>'
101
102 class Type(object):
103 def __init__(self, bitwidth):
104 self._bitwidth = bitwidth
105
106 def bitwidth(self):
107 return self._bitwidth
108
109 def modify(self, spec, width, previous):
110 raise NotImplementedError()
111
112 def __ne__(self, other):
113 return not (self == other)
114
115 class Void(Type):
116 def __init__(self):
117 Type.__init__(self, 0)
118
119 def compiler_ctor(self):
120 return '::VOID'
121
122 def compiler_ctor_ref(self):
123 return '&' + self.compiler_ctor()
124
125 def rust_name(self):
126 return '()'
127
128 def type_info(self, platform_info):
129 return None
130
131 def __eq__(self, other):
132 return isinstance(other, Void)
133
134 class Number(Type):
135 def __init__(self, bitwidth):
136 Type.__init__(self, bitwidth)
137
138 def modify(self, spec, width, previous):
139 if spec == 'u':
140 return Unsigned(self.bitwidth())
141 elif spec == 's':
142 return Signed(self.bitwidth())
143 elif spec == 'f':
144 return Float(self.bitwidth())
145 elif spec == 'w':
146 return self.__class__(self.bitwidth() * 2)
147 elif spec == 'n':
148 return self.__class__(self.bitwidth() // 2)
149 elif spec == 'v':
150 return Vector(self, width // self.bitwidth())
151 else:
152 raise ValueError('unknown modification spec {}', spec)
153
154 def type_info(self, platform_info):
155 return platform_info.number_type_info(self)
156
157 def __eq__(self, other):
158 # print(self, other)
159 return self.__class__ == other.__class__ and self.bitwidth() == other.bitwidth()
160
161 class Signed(Number):
162 def __init__(self, bitwidth, llvm_bitwidth = None):
163 Number.__init__(self, bitwidth)
164 self._llvm_bitwidth = llvm_bitwidth
165
166
167 def compiler_ctor(self):
168 if self._llvm_bitwidth is None:
169 return '::I{}'.format(self.bitwidth())
170 else:
171 return '::I{}_{}'.format(self.bitwidth(), self._llvm_bitwidth)
172
173 def compiler_ctor_ref(self):
174 return '&' + self.compiler_ctor()
175
176 def llvm_name(self):
177 bw = self._llvm_bitwidth or self.bitwidth()
178 return 'i{}'.format(bw)
179
180 def rust_name(self):
181 return 'i{}'.format(self.bitwidth())
182
183 class Unsigned(Number):
184 def __init__(self, bitwidth, llvm_bitwidth = None):
185 Number.__init__(self, bitwidth)
186 self._llvm_bitwidth = llvm_bitwidth
187
188 def compiler_ctor(self):
189 if self._llvm_bitwidth is None:
190 return '::U{}'.format(self.bitwidth())
191 else:
192 return '::U{}_{}'.format(self.bitwidth(), self._llvm_bitwidth)
193
194 def compiler_ctor_ref(self):
195 return '&' + self.compiler_ctor()
196
197 def llvm_name(self):
198 bw = self._llvm_bitwidth or self.bitwidth()
199 return 'i{}'.format(bw)
200
201 def rust_name(self):
202 return 'u{}'.format(self.bitwidth())
203
204 class Float(Number):
205 def __init__(self, bitwidth):
206 assert bitwidth in (32, 64)
207 Number.__init__(self, bitwidth)
208
209 def compiler_ctor(self):
210 return '::F{}'.format(self.bitwidth())
211
212 def compiler_ctor_ref(self):
213 return '&' + self.compiler_ctor()
214
215 def llvm_name(self):
216 return 'f{}'.format(self.bitwidth())
217
218 def rust_name(self):
219 return 'f{}'.format(self.bitwidth())
220
221 class Vector(Type):
222 def __init__(self, elem, length, bitcast = None):
223 assert isinstance(elem, Type) and not isinstance(elem, Vector)
224 Type.__init__(self,
225 elem.bitwidth() * length)
226 self._length = length
227 self._elem = elem
228 assert bitcast is None or (isinstance(bitcast, Vector) and
229 bitcast._bitcast is None and
230 bitcast._elem.bitwidth() == elem.bitwidth())
231 if bitcast is not None and bitcast._elem != elem:
232 self._bitcast = bitcast._elem
233 else:
234 self._bitcast = None
235
236 def modify(self, spec, width, previous):
237 if spec == 'S':
238 return self._elem
239 elif spec == 'h':
240 return Vector(self._elem, self._length // 2)
241 elif spec == 'd':
242 return Vector(self._elem, self._length * 2)
243 elif spec.startswith('x'):
244 new_bitwidth = int(spec[1:])
245 return Vector(self._elem, new_bitwidth // self._elem.bitwidth())
246 elif spec.startswith('->'):
247 bitcast_to = TypeSpec(spec[2:])
248 choices = list(bitcast_to.enumerate(width, previous))
249 assert len(choices) == 1
250 bitcast_to = choices[0]
251 return Vector(self._elem, self._length, bitcast_to)
252 else:
253 return Vector(self._elem.modify(spec, width, previous), self._length)
254
255 def compiler_ctor(self):
256 if self._bitcast is None:
257 return '{}x{}'.format(self._elem.compiler_ctor(),
258 self._length)
259 else:
260 return '{}x{}_{}'.format(self._elem.compiler_ctor(),
261 self._length,
262 self._bitcast.compiler_ctor()
263 .replace('::', ''))
264
265 def compiler_ctor_ref(self):
266 return '&' + self.compiler_ctor()
267
268 def rust_name(self):
269 return '{}x{}'.format(self._elem.rust_name(), self._length)
270
271 def type_info(self, platform_info):
272 elem_info = self._elem.type_info(platform_info)
273 return elem_info.vectorize(self._length,
274 platform_info.width_info(self.bitwidth()))
275
276 def __eq__(self, other):
277 return isinstance(other, Vector) and self._length == other._length and \
278 self._elem == other._elem and self._bitcast == other._bitcast
279
280 class Pointer(Type):
281 def __init__(self, elem, llvm_elem, const):
282 self._elem = elem;
283 self._llvm_elem = llvm_elem
284 self._const = const
285 Type.__init__(self, BITWIDTH_POINTER)
286
287 def modify(self, spec, width, previous):
288 if spec == 'D':
289 return self._elem
290 elif spec == 'M':
291 return Pointer(self._elem, self._llvm_elem, False)
292 elif spec == 'C':
293 return Pointer(self._elem, self._llvm_elem, True)
294 else:
295 return Pointer(self._elem.modify(spec, width, previous), self._llvm_elem, self._const)
296
297 def compiler_ctor(self):
298 if self._llvm_elem is None:
299 llvm_elem = 'None'
300 else:
301 llvm_elem = 'Some({})'.format(self._llvm_elem.compiler_ctor_ref())
302 return 'Type::Pointer({}, {}, {})'.format(self._elem.compiler_ctor_ref(),
303 llvm_elem,
304 'true' if self._const else 'false')
305
306 def compiler_ctor_ref(self):
307 return "{{ static PTR: Type = {}; &PTR }}".format(self.compiler_ctor())
308
309
310 def rust_name(self):
311 return '*{} {}'.format('const' if self._const else 'mut',
312 self._elem.rust_name())
313
314 def type_info(self, platform_info):
315 if self._llvm_elem is None:
316 llvm_elem = None
317 else:
318 llvm_elem = self._llvm_elem.type_info(platform_info)
319 return self._elem.type_info(platform_info).pointer(llvm_elem)
320
321 def __eq__(self, other):
322 return isinstance(other, Pointer) and self._const == other._const \
323 and self._elem == other._elem and self._llvm_elem == other._llvm_elem
324
325 class Aggregate(Type):
326 def __init__(self, flatten, elems):
327 self._flatten = flatten
328 self._elems = elems
329 Type.__init__(self, sum(elem.bitwidth() for elem in elems))
330
331 def __repr__(self):
332 return '<Aggregate {}>'.format(self._elems)
333
334 def modify(self, spec, width, previous):
335 if spec.startswith('.'):
336 num = int(spec[1:])
337 return self._elems[num]
338 else:
339 print(spec)
340 raise NotImplementedError()
341
342 def compiler_ctor(self):
343 parts = "{{ static PARTS: [&'static Type; {}] = [{}]; &PARTS }}"
344 elems = ', '.join(elem.compiler_ctor_ref() for elem in self._elems)
345 parts = parts.format(len(self._elems), elems)
346 return 'Type::Aggregate({}, {})'.format('true' if self._flatten else 'false',
347 parts)
348
349 def compiler_ctor_ref(self):
350 return "{{ static AGG: Type = {}; &AGG }}".format(self.compiler_ctor())
351
352 def rust_name(self):
353 return '({})'.format(', '.join(elem.rust_name() for elem in self._elems))
354
355 def type_info(self, platform_info):
356 return PlatformTypeInfo(None, None, [elem.type_info(platform_info) for elem in self._elems])
357
358 def __eq__(self, other):
359 return isinstance(other, Aggregate) and self._flatten == other._flatten and \
360 self._elems == other._elems
361
362
363 TYPE_ID_LOOKUP = {'i': [Signed, Unsigned],
364 's': [Signed],
365 'u': [Unsigned],
366 'f': [Float]}
367
368 def ptrify(match, elem, width, previous):
369 ptr = match.group('pointer')
370 if ptr is None:
371 return elem
372 else:
373 llvm_ptr = match.group('llvm_pointer')
374 if llvm_ptr is None:
375 llvm_elem = None
376 else:
377 assert llvm_ptr.startswith('/')
378 options = list(TypeSpec(llvm_ptr[1:]).enumerate(width, previous))
379 assert len(options) == 1
380 llvm_elem = options[0]
381 assert ptr in ('Pc', 'Pm')
382 return Pointer(elem, llvm_elem, ptr == 'Pc')
383
384 class TypeSpec(object):
385 def __init__(self, spec):
386 if not isinstance(spec, list):
387 spec = [spec]
388
389 self.spec = spec
390
391 def enumerate(self, width, previous):
392 for spec in self.spec:
393 match = SPEC.match(spec)
394 if match is not None:
395 id = match.group('id')
396 reference = match.group('reference')
397
398 modifiers = []
399 index = match.group('index')
400 if index is not None:
401 modifiers.append(index)
402 modifiers += list(match.group('modifiers') or '')
403 force = match.group('force_width')
404 if force is not None:
405 modifiers.append(force)
406 bitcast = match.group('bitcast')
407 if bitcast is not None:
408 modifiers.append(bitcast)
409
410 if match.group('void') is not None:
411 assert spec == 'V'
412 yield Void()
413 elif id is not None:
414 is_vector = id.islower()
415 type_ctors = TYPE_ID_LOOKUP[id.lower()]
416
417 start = match.group('start')
418 if start is not None:
419 end = match.group('end')
420 llvm_width = None
421 else:
422 start = end = match.group('width')
423 llvm_width = match.group('llvm_width')
424 start = int(start)
425 end = int(end)
426
427 bitwidth = start
428 while bitwidth <= end:
429 for ctor in type_ctors:
430 if llvm_width is not None:
431 assert not is_vector
432 llvm_width = int(llvm_width)
433 assert llvm_width < bitwidth
434 scalar = ctor(bitwidth, llvm_width)
435 else:
436 scalar = ctor(bitwidth)
437
438 if is_vector:
439 elem = Vector(scalar, width // bitwidth)
440 else:
441 assert bitcast is None
442 elem = scalar
443
444 for x in modifiers:
445 elem = elem.modify(x, width, previous)
446 yield ptrify(match, elem, width, previous)
447 bitwidth *= 2
448 elif reference is not None:
449 reference = int(reference)
450 assert reference < len(previous), \
451 'referring to argument {}, but only {} are known'.format(reference,
452 len(previous))
453 ret = previous[reference]
454 for x in modifiers:
455 ret = ret.modify(x, width, previous)
456 yield ptrify(match, ret, width, previous)
457 else:
458 assert False, 'matched `{}`, but didn\'t understand it?'.format(spec)
459 elif spec.startswith('('):
460 if spec.endswith(')'):
461 true_spec = spec[1:-1]
462 flatten = False
463 elif spec.endswith(')f'):
464 true_spec = spec[1:-2]
465 flatten = True
466 else:
467 assert False, 'found unclosed aggregate `{}`'.format(spec)
468
469 for elems in itertools.product(*(TypeSpec(subspec).enumerate(width, previous)
470 for subspec in true_spec.split(','))):
471 yield Aggregate(flatten, elems)
472 elif spec.startswith('['):
473 if spec.endswith(']'):
474 true_spec = spec[1:-1]
475 flatten = False
476 elif spec.endswith(']f'):
477 true_spec = spec[1:-2]
478 flatten = True
479 else:
480 assert False, 'found unclosed aggregate `{}`'.format(spec)
481 elem_spec, count = true_spec.split(';')
482
483 count = int(count)
484 for elem in TypeSpec(elem_spec).enumerate(width, previous):
485 yield Aggregate(flatten, [elem] * count)
486 else:
487 assert False, 'Failed to parse `{}`'.format(spec)
488
489 class GenericIntrinsic(object):
490 def __init__(self, platform, intrinsic, widths, llvm_name, ret, args):
491 self._platform = platform
492 self.intrinsic = intrinsic
493 self.widths = map(int, widths)
494 self.llvm_name = llvm_name
495 self.ret = TypeSpec(ret)
496 self.args = list(map(TypeSpec, args))
497
498 def monomorphise(self):
499 for width in self.widths:
500 # must be a power of two
501 assert width & (width - 1) == 0
502 def recur(processed, untouched):
503 if untouched == []:
504 ret = processed[0]
505 args = processed[1:]
506 yield MonomorphicIntrinsic(self._platform, self.intrinsic, width,
507 self.llvm_name,
508 ret, args)
509 else:
510 raw_arg = untouched[0]
511 rest = untouched[1:]
512 for arg in raw_arg.enumerate(width, processed):
513 for intr in recur(processed + [arg], rest):
514 yield intr
515
516 for x in recur([], [self.ret] + self.args):
517 yield x
518
519 class MonomorphicIntrinsic(object):
520 def __init__(self, platform, intrinsic, width, llvm_name, ret, args):
521 self._platform = platform
522 self._intrinsic = intrinsic
523 self._width = '' if width == 64 else 'q'
524 self._llvm_name = llvm_name
525 self._ret_raw = ret
526 self._ret = ret.type_info(platform)
527 self._args_raw = args
528 self._args = [arg.type_info(platform) for arg in args]
529
530 def llvm_name(self):
531 if self._llvm_name.startswith('!'):
532 return self._llvm_name[1:].format(self._ret, *self._args)
533 else:
534 return self._platform.llvm_prefix() + self._llvm_name.format(self._ret, *self._args)
535
536 def intrinsic_suffix(self):
537 return self._intrinsic.format(self._ret,
538 *self._args,
539 width = self._width)
540
541 def intrinsic_name(self):
542 return self._platform.platform().intrinsic_prefix() + self.intrinsic_suffix()
543
544 def compiler_args(self):
545 return ', '.join(arg.compiler_ctor_ref() for arg in self._args_raw)
546
547 def compiler_ret(self):
548 return self._ret_raw.compiler_ctor_ref()
549
550 def compiler_signature(self):
551 return '({}) -> {}'.format(self.compiler_args(), self.compiler_ret())
552
553 def intrinsic_signature(self):
554 names = 'xyzwabcdef'
555 return '({}) -> {}'.format(', '.join('{}: {}'.format(name, arg.rust_name())
556 for name, arg in zip(names, self._args_raw)),
557 self._ret_raw.rust_name())
558
559 def parse_args():
560 parser = argparse.ArgumentParser(
561 formatter_class = argparse.RawDescriptionHelpFormatter,
562 description = 'Render an intrinsic definition JSON to various formats.',
563 epilog = textwrap.dedent('''\
564 An intrinsic definition consists of a map with fields:
565 - intrinsic: pattern for the name(s) of the vendor's C intrinsic(s)
566 - llvm: pattern for the name(s) of the internal llvm intrinsic(s)
567 - width: a vector of vector bit-widths the pattern works with
568 - ret: type specifier for the return value
569 - arguments: vector of type specifiers for arguments
570
571 The width and types describe a range of possible intrinsics,
572 and these are fed back into the intrinsic and llvm patterns to
573 create the appropriate definitions.
574
575 ## Type specifier grammar
576
577 ```
578 type := core_type modifier* suffix?
579
580 core_type := void | vector | scalar | aggregate | reference
581
582 modifier := 'v' | 'h' | 'd' | 'n' | 'w' | 'u' | 's' |
583 'x' number | '.' number
584 suffix := pointer | bitcast
585 pointer := 'Pm' llvm_pointer? | 'Pc' llvm_pointer?
586 llvm_pointer := '/' type
587 bitcast := '->' type
588
589 void := 'V'
590
591 vector := vector_elem width |
592 vector_elem := 'i' | 'u' | 's' | 'f'
593
594 scalar := scalar_type number llvm_width?
595 scalar_type := 'U' | 'S' | 'F'
596 llvm_width := '/' number
597
598 aggregate := '(' (type),* ')' 'f'? | '[' type ';' number ']' 'f'?
599
600 reference := number
601
602 width = number | '(' number '-' number ')'
603
604 number = [0-9]+
605 ```
606
607 ## Void
608
609 The `V` type corresponds to `void` in LLVM (`()` in
610 Rust). It's likely to only work in return position.
611
612 ## Vectors
613
614 The vector grammar is a pattern describing many possibilities
615 for arguments/return value. The `vector_elem` describes the
616 types of elements to use, and the `width` describes the (range
617 of) widths for those elements, which are then placed into a
618 vector with the `width` bitwidth. E.g. if an intrinsic has a
619 `width` that includes 128, and the return value is `i(8-32)`,
620 then some instantiation of that intrinsic will be `u8x16`,
621 `u32x4`, `i32x4`, etc.
622
623 ### Elements
624
625 - i: integer, both signed and unsigned
626 - u: unsigned integer
627 - s: signed integer
628 - f: float
629
630 ## Scalars
631
632 Similar to vectors, but these describe a single concrete type,
633 not a range. The number is the bitwidth. The optional
634 `llvm_width` is the bitwidth of the integer that should be
635 passed to LLVM (by truncating the Rust argument): this only
636 works with scalar integers and the LLVM width must be smaller
637 than the Rust width.
638
639 ### Types
640
641 - U: unsigned integer
642 - S: signed integer
643 - F: float
644
645 ## Aggregates
646
647 An aggregate is a collection of multiple types; a tuple in
648 Rust terms, or an unnamed struct in LLVM. The `f` modifiers
649 forces the tuple to be flattened in the LLVM
650 intrinsic. E.g. if `llvm.foo` takes `(F32,S32)`:
651
652 - no `f` corresponds to `declare ... @llvm.foo({float, i32})`.
653 - having an `f` corresponds to `declare ... @llvm.foo(float, i32)`.
654
655 The `[type;number]` form is a just shorter way to write
656 `(...)`, except avoids doing a cartesian product of generic
657 types, e.g. `[S32;2]` is the same as `(S32, S32)`, while
658 `[I32;2]` is describing just the two types `(S32,S32)` and
659 `(U32,U32)` (i.e. doesn't include `(S32,U32)`, `(U32,S32)` as
660 `(I32,I32)` would).
661
662 (Currently aggregates can not contain other aggregates.)
663
664 ## References
665
666 A reference uses the type of another argument, with possible
667 modifications. The number refers to the type to use, starting
668 with 0 == return value, 1 == first argument, 2 == second
669 argument, etc.
670
671 ## Affixes
672
673 The `modifier` and `suffix` adaptors change the precise
674 representation.
675
676 ### Modifiers
677
678 - 'v': put a scalar into a vector of the current width (u32 -> u32x4, when width == 128)
679 - 'S': get the scalar element of a vector (u32x4 -> u32)
680 - 'h': half the length of the vector (u32x4 -> u32x2)
681 - 'd': double the length of the vector (u32x2 -> u32x4)
682 - 'n': narrow the element of the vector (u32x4 -> u16x4)
683 - 'w': widen the element of the vector (u16x4 -> u32x4)
684 - 'u': force a number (vector or scalar) to be unsigned int (f32x4 -> u32x4)
685 - 's': force a number (vector or scalar) to be signed int (u32x4 -> i32x4)
686 - 'f': force a number (vector or scalar) to be float (u32x4 -> f32x4)
687 - 'x' number: force the type to be a vector of bitwidth `number`.
688 - '.' number: get the `number`th element of an aggregate
689 - 'D': dereference a pointer (*mut u32 -> u32)
690 - 'C': make a pointer const (*mut u32 -> *const u32)
691 - 'M': make a pointer mut (*const u32 -> *mut u32)
692
693 ### Pointers
694
695 Pointers can be created of any type by appending a `P*`
696 suffix. The `m` vs. `c` chooses mut vs. const. e.g. `S32Pm`
697 corresponds to `*mut i32`, and `i32Pc` corresponds (with width
698 128) to `*const i8x16`, `*const u32x4`, etc.
699
700 The type after the `/` (optional) represents the type used
701 internally to LLVM, e.g. `S32pm/S8` is exposed as `*mut i32`
702 in Rust, but is `i8*` in LLVM. (This defaults to the main
703 type).
704
705 ### Bitcast
706
707 The `'->' type` bitcast suffix will cause the value to be
708 bitcast to the right-hand type when calling the intrinsic,
709 e.g. `s32->f32` will expose the intrinsic as `i32x4` at the
710 Rust level, but will cast that vector to `f32x4` when calling
711 the LLVM intrinsic.
712 '''))
713 parser.add_argument('--format', choices=FORMATS, required=True,
714 help = 'Output format.')
715 parser.add_argument('-o', '--out', type=argparse.FileType('w'), default=sys.stdout,
716 help = 'File to output to (default stdout).')
717 parser.add_argument('-i', '--info', type=argparse.FileType('r'),
718 help = 'File containing platform specific information to merge into '
719 'the input files\' header.')
720 parser.add_argument('in_', metavar="FILE", type=argparse.FileType('r'), nargs='+',
721 help = 'JSON files to load')
722 return parser.parse_args()
723
724
725 class ExternBlock(object):
726 def __init__(self):
727 pass
728
729 def open(self, platform):
730 return 'extern "platform-intrinsic" {'
731
732 def render(self, mono):
733 return ' fn {}{};'.format(mono.intrinsic_name(),
734 mono.intrinsic_signature())
735
736 def close(self):
737 return '}'
738
739 class CompilerDefs(object):
740 def __init__(self):
741 pass
742
743 def open(self, platform):
744 return '''\
745 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
746 // file at the top-level directory of this distribution and at
747 // http://rust-lang.org/COPYRIGHT.
748 //
749 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
750 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
751 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
752 // option. This file may not be copied, modified, or distributed
753 // except according to those terms.
754
755 // DO NOT EDIT: autogenerated by etc/platform-intrinsics/generator.py
756 // ignore-tidy-linelength
757
758 #![allow(unused_imports)]
759
760 use {{Intrinsic, Type}};
761 use IntrinsicDef::Named;
762
763 // The default inlining settings trigger a pathological behaviour in
764 // LLVM, which causes makes compilation very slow. See #28273.
765 #[inline(never)]
766 pub fn find(name: &str) -> Option<Intrinsic> {{
767 if !name.starts_with("{0}") {{ return None }}
768 Some(match &name["{0}".len()..] {{'''.format(platform.intrinsic_prefix())
769
770 def render(self, mono):
771 return '''\
772 "{}" => Intrinsic {{
773 inputs: {{ static INPUTS: [&'static Type; {}] = [{}]; &INPUTS }},
774 output: {},
775 definition: Named("{}")
776 }},'''.format(mono.intrinsic_suffix(),
777 len(mono._args_raw),
778 mono.compiler_args(),
779 mono.compiler_ret(),
780 mono.llvm_name())
781
782 def close(self):
783 return '''\
784 _ => return None,
785 })
786 }'''
787
788 FORMATS = {
789 'extern-block': ExternBlock(),
790 'compiler-defs': CompilerDefs(),
791 }
792
793
794 def main():
795 args = parse_args()
796 ins = args.in_
797 out = args.out
798 out_format = FORMATS[args.format]
799 info = args.info
800 one_file_no_info = False
801 if len(ins) > 1 and info is None:
802 print('error: cannot have multiple inputs without an info header.', file=sys.stderr)
803 sys.exit(1)
804
805 elif info is None:
806 info = ins[0]
807 one_file_no_info = True
808 info_json = json.load(info)
809 platform = PlatformInfo(info_json)
810
811 print(out_format.open(platform), file=out)
812
813 for in_ in ins:
814
815 if one_file_no_info:
816 data = info_json
817 else:
818 data = json.load(in_)
819 data.update(info_json)
820
821 intrinsics = IntrinsicSet(platform, data)
822 for intr in intrinsics.intrinsics():
823 for mono in intr.monomorphise():
824 print(out_format.render(mono), file=out)
825
826 print(out_format.close(), file=out)
827
828 if __name__ == '__main__':
829 main()