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