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