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