]> git.proxmox.com Git - rustc.git/blame - src/etc/platform-intrinsics/generator.py
New upstream version 1.13.0+dfsg1
[rustc.git] / src / etc / platform-intrinsics / generator.py
CommitLineData
e9174d1e
SL
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
11from __future__ import division, print_function
12import json
13import argparse
14import sys
15import re
16import textwrap
17import itertools
18
19SPEC = 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
26class PlatformInfo(object):
27 def __init__(self, json):
28 self._platform = json['platform']
e9174d1e 29
5bcae85e
SL
30 def platform_prefix(self):
31 return self._platform
e9174d1e
SL
32
33class 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
5bcae85e 40 self._intrinsic_prefix = json['intrinsic_prefix']
e9174d1e
SL
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
5bcae85e
SL
51 def intrinsic_prefix(self):
52 return self._intrinsic_prefix
53
e9174d1e
SL
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
75class 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
103BITWIDTH_POINTER = '<pointer>'
104
105class 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
118class Void(Type):
119 def __init__(self):
120 Type.__init__(self, 0)
121
9e0c209e
SL
122 @staticmethod
123 def compiler_ctor():
54a0048b
SL
124 return '::VOID'
125
126 def compiler_ctor_ref(self):
127 return '&' + self.compiler_ctor()
e9174d1e 128
9e0c209e
SL
129 @staticmethod
130 def rust_name():
e9174d1e
SL
131 return '()'
132
9e0c209e
SL
133 @staticmethod
134 def type_info(platform_info):
e9174d1e
SL
135 return None
136
137 def __eq__(self, other):
138 return isinstance(other, Void)
139
140class 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
167class 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:
54a0048b 175 return '::I{}'.format(self.bitwidth())
e9174d1e 176 else:
54a0048b
SL
177 return '::I{}_{}'.format(self.bitwidth(), self._llvm_bitwidth)
178
179 def compiler_ctor_ref(self):
180 return '&' + self.compiler_ctor()
e9174d1e
SL
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
189class 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:
54a0048b 196 return '::U{}'.format(self.bitwidth())
e9174d1e 197 else:
54a0048b
SL
198 return '::U{}_{}'.format(self.bitwidth(), self._llvm_bitwidth)
199
200 def compiler_ctor_ref(self):
201 return '&' + self.compiler_ctor()
e9174d1e
SL
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
210class Float(Number):
211 def __init__(self, bitwidth):
212 assert bitwidth in (32, 64)
213 Number.__init__(self, bitwidth)
214
215 def compiler_ctor(self):
54a0048b
SL
216 return '::F{}'.format(self.bitwidth())
217
218 def compiler_ctor_ref(self):
219 return '&' + self.compiler_ctor()
e9174d1e
SL
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
227class 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:
54a0048b
SL
263 return '{}x{}'.format(self._elem.compiler_ctor(),
264 self._length)
e9174d1e 265 else:
54a0048b
SL
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()
e9174d1e
SL
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
286class Pointer(Type):
287 def __init__(self, elem, llvm_elem, const):
9e0c209e 288 self._elem = elem
e9174d1e
SL
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:
54a0048b
SL
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
e9174d1e
SL
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
331class 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):
54a0048b
SL
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())
e9174d1e
SL
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
369TYPE_ID_LOOKUP = {'i': [Signed, Unsigned],
370 's': [Signed],
371 'u': [Unsigned],
372 'f': [Float]}
373
374def 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
390class 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
495class 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):
9e0c209e 509 if not untouched:
e9174d1e
SL
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
525class 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
5bcae85e
SL
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
e9174d1e 553 def intrinsic_name(self):
5bcae85e 554 return self._platform.intrinsic_prefix() + self.intrinsic_suffix()
e9174d1e
SL
555
556 def compiler_args(self):
54a0048b 557 return ', '.join(arg.compiler_ctor_ref() for arg in self._args_raw)
e9174d1e
SL
558
559 def compiler_ret(self):
54a0048b 560 return self._ret_raw.compiler_ctor_ref()
e9174d1e
SL
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
571def 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('''\
5bcae85e
SL
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
e9174d1e
SL
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'),
54a0048b 751 help = 'File containing platform specific information to merge into '
e9174d1e
SL
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
758class ExternBlock(object):
759 def __init__(self):
760 pass
761
9e0c209e
SL
762 @staticmethod
763 def open(platform):
e9174d1e
SL
764 return 'extern "platform-intrinsic" {'
765
9e0c209e
SL
766 @staticmethod
767 def render(mono):
5bcae85e
SL
768 return ' fn {}{}{};'.format(mono.platform_prefix(),
769 mono.intrinsic_name(),
770 mono.intrinsic_signature())
e9174d1e 771
9e0c209e
SL
772 @staticmethod
773 def close():
e9174d1e
SL
774 return '}'
775
776class CompilerDefs(object):
777 def __init__(self):
778 pass
779
9e0c209e
SL
780 @staticmethod
781 def open(platform):
e9174d1e
SL
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
54a0048b 798use {{Intrinsic, Type}};
e9174d1e 799use IntrinsicDef::Named;
e9174d1e
SL
800
801// The default inlining settings trigger a pathological behaviour in
802// LLVM, which causes makes compilation very slow. See #28273.
803#[inline(never)]
54a0048b 804pub fn find(name: &str) -> Option<Intrinsic> {{
e9174d1e 805 if !name.starts_with("{0}") {{ return None }}
5bcae85e 806 Some(match &name["{0}".len()..] {{'''.format(platform.platform_prefix())
e9174d1e 807
9e0c209e
SL
808 @staticmethod
809 def render(mono):
e9174d1e
SL
810 return '''\
811 "{}" => Intrinsic {{
54a0048b 812 inputs: {{ static INPUTS: [&'static Type; {}] = [{}]; &INPUTS }},
e9174d1e
SL
813 output: {},
814 definition: Named("{}")
5bcae85e 815 }},'''.format(mono.intrinsic_set_name() + mono.intrinsic_suffix(),
54a0048b 816 len(mono._args_raw),
e9174d1e
SL
817 mono.compiler_args(),
818 mono.compiler_ret(),
819 mono.llvm_name())
820
9e0c209e
SL
821 @staticmethod
822 def close():
e9174d1e
SL
823 return '''\
824 _ => return None,
825 })
826}'''
827
828FORMATS = {
829 'extern-block': ExternBlock(),
830 'compiler-defs': CompilerDefs(),
831}
832
833
834def 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
868if __name__ == '__main__':
869 main()