1 //! Shared ISLE prelude implementation for optimization (mid-end) and
2 //! lowering (backend) ISLE environments.
3 
4 /// Helper macro to define methods in `prelude.isle` within `impl Context for
5 /// ...` for each backend. These methods are shared amongst all backends.
6 #[macro_export]
7 #[doc(hidden)]
8 macro_rules! isle_common_prelude_methods {
9     () => {
10         /// We don't have a way of making a `()` value in isle directly.
11         #[inline]
12         fn unit(&mut self) -> Unit {
13             ()
14         }
15 
16         #[inline]
17         fn u8_as_u32(&mut self, x: u8) -> u32 {
18             x.into()
19         }
20 
21         #[inline]
22         fn u8_as_u64(&mut self, x: u8) -> u64 {
23             x.into()
24         }
25 
26         #[inline]
27         fn u16_as_i16(&mut self, x: u16) -> i16 {
28             x as i16
29         }
30 
31         #[inline]
32         fn u16_as_u32(&mut self, x: u16) -> u32 {
33             x.into()
34         }
35 
36         #[inline]
37         fn u16_as_u64(&mut self, x: u16) -> u64 {
38             x.into()
39         }
40 
41         #[inline]
42         fn u32_as_u64(&mut self, x: u32) -> u64 {
43             x.into()
44         }
45 
46         #[inline]
47         fn i64_as_u64(&mut self, x: i64) -> u64 {
48             x as u64
49         }
50 
51         #[inline]
52         fn u64_as_i32(&mut self, x: u64) -> i32 {
53             x as i32
54         }
55 
56         #[inline]
57         fn u64_as_i64(&mut self, x: u64) -> i64 {
58             x as i64
59         }
60 
61         #[inline]
62         fn i32_as_u32(&mut self, x: i32) -> u32 {
63             x as u32
64         }
65 
66         #[inline]
67         fn i32_as_i64(&mut self, x: i32) -> i64 {
68             x.into()
69         }
70 
71         #[inline]
72         fn i64_neg(&mut self, x: i64) -> i64 {
73             x.wrapping_neg()
74         }
75 
76         #[inline]
77         fn i8_neg(&mut self, x: i8) -> i8 {
78             x.wrapping_neg()
79         }
80 
81         #[inline]
82         fn checked_add_with_type(&mut self, ty: Type, a: u64, b: u64) -> Option<u64> {
83             let c = a.checked_add(b)?;
84             let ty_mask = self.ty_mask(ty);
85             if (c & !ty_mask) == 0 { Some(c) } else { None }
86         }
87 
88         #[inline]
89         fn add_overflows_with_type(&mut self, ty: Type, a: u64, b: u64) -> bool {
90             self.checked_add_with_type(ty, a, b).is_none()
91         }
92 
93         #[inline]
94         fn u64_add(&mut self, x: u64, y: u64) -> u64 {
95             x.wrapping_add(y)
96         }
97 
98         #[inline]
99         fn u64_sub(&mut self, x: u64, y: u64) -> u64 {
100             x.wrapping_sub(y)
101         }
102 
103         #[inline]
104         fn u64_mul(&mut self, x: u64, y: u64) -> u64 {
105             x.wrapping_mul(y)
106         }
107 
108         #[inline]
109         fn imm64_sdiv(&mut self, ty: Type, x: Imm64, y: Imm64) -> Option<Imm64> {
110             // Sign extend `x` and `y`.
111             let shift = u32::checked_sub(64, ty.bits()).unwrap_or(0);
112             let x = (x.bits() << shift) >> shift;
113             let y = (y.bits() << shift) >> shift;
114 
115             // NB: We can't rely on `checked_div` to detect `ty::MIN / -1`
116             // (which overflows and should trap) because we are working with
117             // `i64` values here, and `i32::MIN != i64::MIN`, for
118             // example. Therefore, we have to explicitly check for this case
119             // ourselves.
120             let min = ((self.ty_smin(ty) as i64) << shift) >> shift;
121             if x == min && y == -1 {
122                 return None;
123             }
124 
125             let ty_mask = self.ty_mask(ty) as i64;
126             let result = x.checked_div(y)? & ty_mask;
127             Some(Imm64::new(result))
128         }
129 
130         #[inline]
131         fn u64_udiv(&mut self, x: u64, y: u64) -> Option<u64> {
132             x.checked_div(y)
133         }
134 
135         #[inline]
136         fn u64_and(&mut self, x: u64, y: u64) -> u64 {
137             x & y
138         }
139 
140         #[inline]
141         fn u64_or(&mut self, x: u64, y: u64) -> u64 {
142             x | y
143         }
144 
145         #[inline]
146         fn u64_xor(&mut self, x: u64, y: u64) -> u64 {
147             x ^ y
148         }
149 
150         #[inline]
151         fn u64_shl(&mut self, x: u64, y: u64) -> u64 {
152             x << y
153         }
154 
155         #[inline]
156         fn imm64_shl(&mut self, ty: Type, x: Imm64, y: Imm64) -> Imm64 {
157             // Mask off any excess shift bits.
158             let shift_mask = (ty.bits() - 1) as u64;
159             let y = (y.bits() as u64) & shift_mask;
160 
161             // Mask the result to `ty` bits.
162             let ty_mask = self.ty_mask(ty) as i64;
163             Imm64::new((x.bits() << y) & ty_mask)
164         }
165 
166         #[inline]
167         fn imm64_ushr(&mut self, ty: Type, x: Imm64, y: Imm64) -> Imm64 {
168             let ty_mask = self.ty_mask(ty);
169             let x = (x.bits() as u64) & ty_mask;
170 
171             // Mask off any excess shift bits.
172             let shift_mask = (ty.bits() - 1) as u64;
173             let y = (y.bits() as u64) & shift_mask;
174 
175             // NB: No need to mask off high bits because they are already zero.
176             Imm64::new((x >> y) as i64)
177         }
178 
179         #[inline]
180         fn imm64_sshr(&mut self, ty: Type, x: Imm64, y: Imm64) -> Imm64 {
181             // Sign extend `x` from `ty.bits()`-width to the full 64 bits.
182             let shift = u32::checked_sub(64, ty.bits()).unwrap_or(0);
183             let x = (x.bits() << shift) >> shift;
184 
185             // Mask off any excess shift bits.
186             let shift_mask = (ty.bits() - 1) as i64;
187             let y = y.bits() & shift_mask;
188 
189             // Mask off sign bits that aren't part of `ty`.
190             let ty_mask = self.ty_mask(ty) as i64;
191             Imm64::new((x >> y) & ty_mask)
192         }
193 
194         #[inline]
195         fn u64_not(&mut self, x: u64) -> u64 {
196             !x
197         }
198 
199         #[inline]
200         fn i64_not(&mut self, x: i64) -> i64 {
201             !x
202         }
203 
204         #[inline]
205         fn u64_eq(&mut self, x: u64, y: u64) -> bool {
206             x == y
207         }
208 
209         #[inline]
210         fn u64_le(&mut self, x: u64, y: u64) -> bool {
211             x <= y
212         }
213 
214         #[inline]
215         fn u64_lt(&mut self, x: u64, y: u64) -> bool {
216             x < y
217         }
218 
219         #[inline]
220         fn u64_is_zero(&mut self, value: u64) -> bool {
221             0 == value
222         }
223 
224         fn i64_is_zero(&mut self, value: i64) -> bool {
225             0 == value
226         }
227 
228         #[inline]
229         fn u64_is_odd(&mut self, x: u64) -> bool {
230             x & 1 == 1
231         }
232 
233         fn i64_shr(&mut self, a: i64, b: i64) -> i64 {
234             a >> b
235         }
236 
237         fn i64_ctz(&mut self, a: i64) -> i64 {
238             a.trailing_zeros().into()
239         }
240 
241         #[inline]
242         fn i64_sextend_u64(&mut self, ty: Type, x: u64) -> i64 {
243             let shift_amt = std::cmp::max(0, 64 - ty.bits());
244             ((x as i64) << shift_amt) >> shift_amt
245         }
246 
247         #[inline]
248         fn i64_sextend_imm64(&mut self, ty: Type, x: Imm64) -> i64 {
249             x.sign_extend_from_width(ty.bits()).bits()
250         }
251 
252         #[inline]
253         fn u64_uextend_imm64(&mut self, ty: Type, x: Imm64) -> u64 {
254             (x.bits() as u64) & self.ty_mask(ty)
255         }
256 
257         #[inline]
258         fn imm64_icmp(&mut self, ty: Type, cc: &IntCC, x: Imm64, y: Imm64) -> Imm64 {
259             let ux = self.u64_uextend_imm64(ty, x);
260             let uy = self.u64_uextend_imm64(ty, y);
261             let sx = self.i64_sextend_imm64(ty, x);
262             let sy = self.i64_sextend_imm64(ty, y);
263             let result = match cc {
264                 IntCC::Equal => ux == uy,
265                 IntCC::NotEqual => ux != uy,
266                 IntCC::UnsignedGreaterThanOrEqual => ux >= uy,
267                 IntCC::UnsignedGreaterThan => ux > uy,
268                 IntCC::UnsignedLessThanOrEqual => ux <= uy,
269                 IntCC::UnsignedLessThan => ux < uy,
270                 IntCC::SignedGreaterThanOrEqual => sx >= sy,
271                 IntCC::SignedGreaterThan => sx > sy,
272                 IntCC::SignedLessThanOrEqual => sx <= sy,
273                 IntCC::SignedLessThan => sx < sy,
274             };
275             Imm64::new(result.into())
276         }
277 
278         #[inline]
279         fn ty_bits(&mut self, ty: Type) -> u8 {
280             use std::convert::TryInto;
281             ty.bits().try_into().unwrap()
282         }
283 
284         #[inline]
285         fn ty_bits_u16(&mut self, ty: Type) -> u16 {
286             ty.bits() as u16
287         }
288 
289         #[inline]
290         fn ty_bits_u64(&mut self, ty: Type) -> u64 {
291             ty.bits() as u64
292         }
293 
294         #[inline]
295         fn ty_bytes(&mut self, ty: Type) -> u16 {
296             u16::try_from(ty.bytes()).unwrap()
297         }
298 
299         #[inline]
300         fn ty_mask(&mut self, ty: Type) -> u64 {
301             let ty_bits = ty.bits();
302             debug_assert_ne!(ty_bits, 0);
303             let shift = 64_u64
304                 .checked_sub(ty_bits.into())
305                 .expect("unimplemented for > 64 bits");
306             u64::MAX >> shift
307         }
308 
309         #[inline]
310         fn ty_lane_mask(&mut self, ty: Type) -> u64 {
311             let ty_lane_count = ty.lane_count();
312             debug_assert_ne!(ty_lane_count, 0);
313             let shift = 64_u64
314                 .checked_sub(ty_lane_count.into())
315                 .expect("unimplemented for > 64 bits");
316             u64::MAX >> shift
317         }
318 
319         #[inline]
320         fn ty_lane_count(&mut self, ty: Type) -> u64 {
321             ty.lane_count() as u64
322         }
323 
324         #[inline]
325         fn ty_umin(&mut self, _ty: Type) -> u64 {
326             0
327         }
328 
329         #[inline]
330         fn ty_umax(&mut self, ty: Type) -> u64 {
331             self.ty_mask(ty)
332         }
333 
334         #[inline]
335         fn ty_smin(&mut self, ty: Type) -> u64 {
336             let ty_bits = ty.bits();
337             debug_assert_ne!(ty_bits, 0);
338             let shift = 64_u64
339                 .checked_sub(ty_bits.into())
340                 .expect("unimplemented for > 64 bits");
341             (i64::MIN as u64) >> shift
342         }
343 
344         #[inline]
345         fn ty_smax(&mut self, ty: Type) -> u64 {
346             let ty_bits = ty.bits();
347             debug_assert_ne!(ty_bits, 0);
348             let shift = 64_u64
349                 .checked_sub(ty_bits.into())
350                 .expect("unimplemented for > 64 bits");
351             (i64::MAX as u64) >> shift
352         }
353 
354         fn fits_in_16(&mut self, ty: Type) -> Option<Type> {
355             if ty.bits() <= 16 && !ty.is_dynamic_vector() {
356                 Some(ty)
357             } else {
358                 None
359             }
360         }
361 
362         #[inline]
363         fn fits_in_32(&mut self, ty: Type) -> Option<Type> {
364             if ty.bits() <= 32 && !ty.is_dynamic_vector() {
365                 Some(ty)
366             } else {
367                 None
368             }
369         }
370 
371         #[inline]
372         fn lane_fits_in_32(&mut self, ty: Type) -> Option<Type> {
373             if !ty.is_vector() && !ty.is_dynamic_vector() {
374                 None
375             } else if ty.lane_type().bits() <= 32 {
376                 Some(ty)
377             } else {
378                 None
379             }
380         }
381 
382         #[inline]
383         fn fits_in_64(&mut self, ty: Type) -> Option<Type> {
384             if ty.bits() <= 64 && !ty.is_dynamic_vector() {
385                 Some(ty)
386             } else {
387                 None
388             }
389         }
390 
391         #[inline]
392         fn ty_int_ref_scalar_64(&mut self, ty: Type) -> Option<Type> {
393             if ty.bits() <= 64 && !ty.is_float() && !ty.is_vector() {
394                 Some(ty)
395             } else {
396                 None
397             }
398         }
399 
400         #[inline]
401         fn ty_int_ref_scalar_64_extract(&mut self, ty: Type) -> Option<Type> {
402             self.ty_int_ref_scalar_64(ty)
403         }
404 
405         #[inline]
406         fn ty_16(&mut self, ty: Type) -> Option<Type> {
407             if ty.bits() == 16 { Some(ty) } else { None }
408         }
409 
410         #[inline]
411         fn ty_32(&mut self, ty: Type) -> Option<Type> {
412             if ty.bits() == 32 { Some(ty) } else { None }
413         }
414 
415         #[inline]
416         fn ty_64(&mut self, ty: Type) -> Option<Type> {
417             if ty.bits() == 64 { Some(ty) } else { None }
418         }
419 
420         #[inline]
421         fn ty_128(&mut self, ty: Type) -> Option<Type> {
422             if ty.bits() == 128 { Some(ty) } else { None }
423         }
424 
425         #[inline]
426         fn ty_32_or_64(&mut self, ty: Type) -> Option<Type> {
427             if ty.bits() == 32 || ty.bits() == 64 {
428                 Some(ty)
429             } else {
430                 None
431             }
432         }
433 
434         #[inline]
435         fn ty_8_or_16(&mut self, ty: Type) -> Option<Type> {
436             if ty.bits() == 8 || ty.bits() == 16 {
437                 Some(ty)
438             } else {
439                 None
440             }
441         }
442 
443         #[inline]
444         fn ty_16_or_32(&mut self, ty: Type) -> Option<Type> {
445             if ty.bits() == 16 || ty.bits() == 32 {
446                 Some(ty)
447             } else {
448                 None
449             }
450         }
451 
452         #[inline]
453         fn int_fits_in_32(&mut self, ty: Type) -> Option<Type> {
454             match ty {
455                 I8 | I16 | I32 => Some(ty),
456                 _ => None,
457             }
458         }
459 
460         #[inline]
461         fn ty_int_ref_64(&mut self, ty: Type) -> Option<Type> {
462             match ty {
463                 I64 => Some(ty),
464                 _ => None,
465             }
466         }
467 
468         #[inline]
469         fn ty_int_ref_16_to_64(&mut self, ty: Type) -> Option<Type> {
470             match ty {
471                 I16 | I32 | I64 => Some(ty),
472                 _ => None,
473             }
474         }
475 
476         #[inline]
477         fn ty_int(&mut self, ty: Type) -> Option<Type> {
478             ty.is_int().then(|| ty)
479         }
480 
481         #[inline]
482         fn ty_scalar(&mut self, ty: Type) -> Option<Type> {
483             if ty.lane_count() == 1 { Some(ty) } else { None }
484         }
485 
486         #[inline]
487         fn ty_scalar_float(&mut self, ty: Type) -> Option<Type> {
488             if ty.is_float() { Some(ty) } else { None }
489         }
490 
491         #[inline]
492         fn ty_float_or_vec(&mut self, ty: Type) -> Option<Type> {
493             if ty.is_float() || ty.is_vector() {
494                 Some(ty)
495             } else {
496                 None
497             }
498         }
499 
500         fn ty_vector_float(&mut self, ty: Type) -> Option<Type> {
501             if ty.is_vector() && ty.lane_type().is_float() {
502                 Some(ty)
503             } else {
504                 None
505             }
506         }
507 
508         #[inline]
509         fn ty_vector_not_float(&mut self, ty: Type) -> Option<Type> {
510             if ty.is_vector() && !ty.lane_type().is_float() {
511                 Some(ty)
512             } else {
513                 None
514             }
515         }
516 
517         #[inline]
518         fn ty_vec64_ctor(&mut self, ty: Type) -> Option<Type> {
519             if ty.is_vector() && ty.bits() == 64 {
520                 Some(ty)
521             } else {
522                 None
523             }
524         }
525 
526         #[inline]
527         fn ty_vec64(&mut self, ty: Type) -> Option<Type> {
528             if ty.is_vector() && ty.bits() == 64 {
529                 Some(ty)
530             } else {
531                 None
532             }
533         }
534 
535         #[inline]
536         fn ty_vec128(&mut self, ty: Type) -> Option<Type> {
537             if ty.is_vector() && ty.bits() == 128 {
538                 Some(ty)
539             } else {
540                 None
541             }
542         }
543 
544         #[inline]
545         fn ty_dyn_vec64(&mut self, ty: Type) -> Option<Type> {
546             if ty.is_dynamic_vector() && dynamic_to_fixed(ty).bits() == 64 {
547                 Some(ty)
548             } else {
549                 None
550             }
551         }
552 
553         #[inline]
554         fn ty_dyn_vec128(&mut self, ty: Type) -> Option<Type> {
555             if ty.is_dynamic_vector() && dynamic_to_fixed(ty).bits() == 128 {
556                 Some(ty)
557             } else {
558                 None
559             }
560         }
561 
562         #[inline]
563         fn ty_vec64_int(&mut self, ty: Type) -> Option<Type> {
564             if ty.is_vector() && ty.bits() == 64 && ty.lane_type().is_int() {
565                 Some(ty)
566             } else {
567                 None
568             }
569         }
570 
571         #[inline]
572         fn ty_vec128_int(&mut self, ty: Type) -> Option<Type> {
573             if ty.is_vector() && ty.bits() == 128 && ty.lane_type().is_int() {
574                 Some(ty)
575             } else {
576                 None
577             }
578         }
579 
580         #[inline]
581         fn ty_addr64(&mut self, ty: Type) -> Option<Type> {
582             match ty {
583                 I64 => Some(ty),
584                 _ => None,
585             }
586         }
587 
588         #[inline]
589         fn u64_from_imm64(&mut self, imm: Imm64) -> u64 {
590             imm.bits() as u64
591         }
592 
593         #[inline]
594         fn imm64_power_of_two(&mut self, x: Imm64) -> Option<u64> {
595             let x = i64::from(x);
596             let x = u64::try_from(x).ok()?;
597             if x.is_power_of_two() {
598                 Some(x.trailing_zeros().into())
599             } else {
600                 None
601             }
602         }
603 
604         #[inline]
605         fn u64_from_bool(&mut self, b: bool) -> u64 {
606             if b { u64::MAX } else { 0 }
607         }
608 
609         #[inline]
610         fn multi_lane(&mut self, ty: Type) -> Option<(u32, u32)> {
611             if ty.lane_count() > 1 {
612                 Some((ty.lane_bits(), ty.lane_count()))
613             } else {
614                 None
615             }
616         }
617 
618         #[inline]
619         fn dynamic_lane(&mut self, ty: Type) -> Option<(u32, u32)> {
620             if ty.is_dynamic_vector() {
621                 Some((ty.lane_bits(), ty.min_lane_count()))
622             } else {
623                 None
624             }
625         }
626 
627         #[inline]
628         fn ty_dyn64_int(&mut self, ty: Type) -> Option<Type> {
629             if ty.is_dynamic_vector() && ty.min_bits() == 64 && ty.lane_type().is_int() {
630                 Some(ty)
631             } else {
632                 None
633             }
634         }
635 
636         #[inline]
637         fn ty_dyn128_int(&mut self, ty: Type) -> Option<Type> {
638             if ty.is_dynamic_vector() && ty.min_bits() == 128 && ty.lane_type().is_int() {
639                 Some(ty)
640             } else {
641                 None
642             }
643         }
644 
645         fn u16_from_ieee16(&mut self, val: Ieee16) -> u16 {
646             val.bits()
647         }
648 
649         fn u32_from_ieee32(&mut self, val: Ieee32) -> u32 {
650             val.bits()
651         }
652 
653         fn u64_from_ieee64(&mut self, val: Ieee64) -> u64 {
654             val.bits()
655         }
656 
657         fn u8_from_uimm8(&mut self, val: Uimm8) -> u8 {
658             val
659         }
660 
661         fn not_vec32x2(&mut self, ty: Type) -> Option<Type> {
662             if ty.lane_bits() == 32 && ty.lane_count() == 2 {
663                 None
664             } else {
665                 Some(ty)
666             }
667         }
668 
669         fn not_i64x2(&mut self, ty: Type) -> Option<()> {
670             if ty == I64X2 { None } else { Some(()) }
671         }
672 
673         fn trap_code_division_by_zero(&mut self) -> TrapCode {
674             TrapCode::INTEGER_DIVISION_BY_ZERO
675         }
676 
677         fn trap_code_integer_overflow(&mut self) -> TrapCode {
678             TrapCode::INTEGER_OVERFLOW
679         }
680 
681         fn trap_code_bad_conversion_to_integer(&mut self) -> TrapCode {
682             TrapCode::BAD_CONVERSION_TO_INTEGER
683         }
684 
685         fn nonzero_u64_from_imm64(&mut self, val: Imm64) -> Option<u64> {
686             match val.bits() {
687                 0 => None,
688                 n => Some(n as u64),
689             }
690         }
691 
692         #[inline]
693         fn u32_add(&mut self, a: u32, b: u32) -> u32 {
694             a.wrapping_add(b)
695         }
696 
697         #[inline]
698         fn u32_sub(&mut self, a: u32, b: u32) -> u32 {
699             a.wrapping_sub(b)
700         }
701 
702         #[inline]
703         fn u32_and(&mut self, a: u32, b: u32) -> u32 {
704             a & b
705         }
706 
707         #[inline]
708         fn u32_shl(&mut self, x: u32, y: u32) -> u32 {
709             x << y
710         }
711 
712         #[inline]
713         fn s32_add_fallible(&mut self, a: i32, b: i32) -> Option<i32> {
714             a.checked_add(b)
715         }
716 
717         #[inline]
718         fn u32_nonnegative(&mut self, x: u32) -> Option<u32> {
719             if (x as i32) >= 0 { Some(x) } else { None }
720         }
721 
722         #[inline]
723         fn u32_lteq(&mut self, a: u32, b: u32) -> Option<()> {
724             if a <= b { Some(()) } else { None }
725         }
726 
727         #[inline]
728         fn u8_lteq(&mut self, a: u8, b: u8) -> Option<()> {
729             if a <= b { Some(()) } else { None }
730         }
731 
732         #[inline]
733         fn u8_lt(&mut self, a: u8, b: u8) -> Option<()> {
734             if a < b { Some(()) } else { None }
735         }
736 
737         #[inline]
738         fn imm64(&mut self, x: u64) -> Imm64 {
739             Imm64::new(x as i64)
740         }
741 
742         #[inline]
743         fn imm64_masked(&mut self, ty: Type, x: u64) -> Imm64 {
744             Imm64::new((x & self.ty_mask(ty)) as i64)
745         }
746 
747         #[inline]
748         fn offset32(&mut self, x: Offset32) -> i32 {
749             x.into()
750         }
751 
752         #[inline]
753         fn u8_and(&mut self, a: u8, b: u8) -> u8 {
754             a & b
755         }
756 
757         #[inline]
758         fn u8_shl(&mut self, a: u8, b: u8) -> u8 {
759             a << b
760         }
761 
762         #[inline]
763         fn u8_shr(&mut self, a: u8, b: u8) -> u8 {
764             a >> b
765         }
766 
767         #[inline]
768         fn u8_sub(&mut self, a: u8, b: u8) -> u8 {
769             a.wrapping_sub(b)
770         }
771 
772         #[inline]
773         fn lane_type(&mut self, ty: Type) -> Type {
774             ty.lane_type()
775         }
776 
777         #[inline]
778         fn ty_half_lanes(&mut self, ty: Type) -> Option<Type> {
779             if ty.lane_count() == 1 {
780                 None
781             } else {
782                 ty.lane_type().by(ty.lane_count() / 2)
783             }
784         }
785 
786         #[inline]
787         fn ty_half_width(&mut self, ty: Type) -> Option<Type> {
788             ty.half_width()
789         }
790 
791         #[inline]
792         fn ty_equal(&mut self, lhs: Type, rhs: Type) -> bool {
793             lhs == rhs
794         }
795 
796         #[inline]
797         fn offset32_to_i32(&mut self, offset: Offset32) -> i32 {
798             offset.into()
799         }
800 
801         #[inline]
802         fn i32_to_offset32(&mut self, offset: i32) -> Offset32 {
803             Offset32::new(offset)
804         }
805 
806         #[inline]
807         fn mem_flags_trusted(&mut self) -> MemFlags {
808             MemFlags::trusted()
809         }
810 
811         #[inline]
812         fn little_or_native_endian(&mut self, flags: MemFlags) -> Option<MemFlags> {
813             match flags.explicit_endianness() {
814                 Some(crate::ir::Endianness::Little) | None => Some(flags),
815                 Some(crate::ir::Endianness::Big) => None,
816             }
817         }
818 
819         #[inline]
820         fn intcc_unsigned(&mut self, x: &IntCC) -> IntCC {
821             x.unsigned()
822         }
823 
824         #[inline]
825         fn signed_cond_code(&mut self, cc: &IntCC) -> Option<IntCC> {
826             match cc {
827                 IntCC::Equal
828                 | IntCC::UnsignedGreaterThanOrEqual
829                 | IntCC::UnsignedGreaterThan
830                 | IntCC::UnsignedLessThanOrEqual
831                 | IntCC::UnsignedLessThan
832                 | IntCC::NotEqual => None,
833                 IntCC::SignedGreaterThanOrEqual
834                 | IntCC::SignedGreaterThan
835                 | IntCC::SignedLessThanOrEqual
836                 | IntCC::SignedLessThan => Some(*cc),
837             }
838         }
839 
840         #[inline]
841         fn intcc_swap_args(&mut self, cc: &IntCC) -> IntCC {
842             cc.swap_args()
843         }
844 
845         #[inline]
846         fn intcc_complement(&mut self, cc: &IntCC) -> IntCC {
847             cc.complement()
848         }
849 
850         #[inline]
851         fn intcc_without_eq(&mut self, x: &IntCC) -> IntCC {
852             x.without_equal()
853         }
854 
855         #[inline]
856         fn floatcc_swap_args(&mut self, cc: &FloatCC) -> FloatCC {
857             cc.swap_args()
858         }
859 
860         #[inline]
861         fn floatcc_complement(&mut self, cc: &FloatCC) -> FloatCC {
862             cc.complement()
863         }
864 
865         fn floatcc_unordered(&mut self, cc: &FloatCC) -> bool {
866             match *cc {
867                 FloatCC::Unordered
868                 | FloatCC::UnorderedOrEqual
869                 | FloatCC::UnorderedOrLessThan
870                 | FloatCC::UnorderedOrLessThanOrEqual
871                 | FloatCC::UnorderedOrGreaterThan
872                 | FloatCC::UnorderedOrGreaterThanOrEqual => true,
873                 _ => false,
874             }
875         }
876 
877         #[inline]
878         fn unpack_value_array_2(&mut self, arr: &ValueArray2) -> (Value, Value) {
879             let [a, b] = *arr;
880             (a, b)
881         }
882 
883         #[inline]
884         fn pack_value_array_2(&mut self, a: Value, b: Value) -> ValueArray2 {
885             [a, b]
886         }
887 
888         #[inline]
889         fn unpack_value_array_3(&mut self, arr: &ValueArray3) -> (Value, Value, Value) {
890             let [a, b, c] = *arr;
891             (a, b, c)
892         }
893 
894         #[inline]
895         fn pack_value_array_3(&mut self, a: Value, b: Value, c: Value) -> ValueArray3 {
896             [a, b, c]
897         }
898 
899         #[inline]
900         fn unpack_block_array_2(&mut self, arr: &BlockArray2) -> (BlockCall, BlockCall) {
901             let [a, b] = *arr;
902             (a, b)
903         }
904 
905         #[inline]
906         fn pack_block_array_2(&mut self, a: BlockCall, b: BlockCall) -> BlockArray2 {
907             [a, b]
908         }
909 
910         fn u128_as_u64(&mut self, val: u128) -> Option<u64> {
911             u64::try_from(val).ok()
912         }
913 
914         fn u64_as_u32(&mut self, val: u64) -> Option<u32> {
915             u32::try_from(val).ok()
916         }
917 
918         fn u32_as_u16(&mut self, val: u32) -> Option<u16> {
919             val.try_into().ok()
920         }
921 
922         fn i32_as_i8(&mut self, val: i32) -> Option<i8> {
923             val.try_into().ok()
924         }
925 
926         fn u8_as_i8(&mut self, val: u8) -> i8 {
927             val as i8
928         }
929 
930         fn u64_as_u8(&mut self, val: u64) -> u8 {
931             val as u8
932         }
933 
934         fn u64_as_u16(&mut self, val: u64) -> u16 {
935             val as u16
936         }
937 
938         fn u64_as_u16_extractor(&mut self, val: u64) -> Option<u16> {
939             Some(val as u16)
940         }
941 
942         fn u8_try_from_u64(&mut self, val: u64) -> Option<u8> {
943             u8::try_from(val).ok()
944         }
945 
946         fn u8_try_from_u16(&mut self, val: u16) -> Option<u8> {
947             u8::try_from(val).ok()
948         }
949 
950         fn u8_try_from_i32(&mut self, val: i32) -> Option<u8> {
951             u8::try_from(val).ok()
952         }
953 
954         fn i32_try_from_i64(&mut self, val: i64) -> Option<i32> {
955             i32::try_from(val).ok()
956         }
957 
958         fn u64_try_from_i64(&mut self, val: i64) -> Option<u64> {
959             u64::try_from(val).ok()
960         }
961 
962         fn u16_try_from_i32(&mut self, val: i32) -> Option<u16> {
963             u16::try_from(val).ok()
964         }
965 
966         fn u16_try_from_u64(&mut self, val: u64) -> Option<u16> {
967             u16::try_from(val).ok()
968         }
969 
970         fn u32_try_from_u64(&mut self, val: u64) -> Option<u32> {
971             u32::try_from(val).ok()
972         }
973 
974         fn i8_try_from_i32(&mut self, val: i32) -> Option<i8> {
975             i8::try_from(val).ok()
976         }
977 
978         fn i8_try_from_i64(&mut self, val: i64) -> Option<i8> {
979             i8::try_from(val).ok()
980         }
981 
982         fn i8_try_from_u64(&mut self, val: u64) -> Option<i8> {
983             i8::try_from(val).ok()
984         }
985 
986         fn i8_as_u8(&mut self, val: i8) -> u8 {
987             val as u8
988         }
989 
990         fn i16_as_u16(&mut self, val: i16) -> u16 {
991             val as u16
992         }
993 
994         fn i16_try_from_i32(&mut self, val: i32) -> Option<i16> {
995             i16::try_from(val).ok()
996         }
997 
998         fn i16_try_from_u64(&mut self, val: u64) -> Option<i16> {
999             i16::try_from(val).ok()
1000         }
1001 
1002         fn i32_try_from_u64(&mut self, val: u64) -> Option<i32> {
1003             i32::try_from(val).ok()
1004         }
1005 
1006         fn u128_replicated_u64(&mut self, val: u128) -> Option<u64> {
1007             let low64 = val as u64 as u128;
1008             if (low64 | (low64 << 64)) == val {
1009                 Some(low64 as u64)
1010             } else {
1011                 None
1012             }
1013         }
1014 
1015         fn u64_replicated_u32(&mut self, val: u64) -> Option<u64> {
1016             let low32 = val as u32 as u64;
1017             if (low32 | (low32 << 32)) == val {
1018                 Some(low32)
1019             } else {
1020                 None
1021             }
1022         }
1023 
1024         fn u32_replicated_u16(&mut self, val: u64) -> Option<u64> {
1025             let val = val as u32;
1026             let low16 = val as u16 as u32;
1027             if (low16 | (low16 << 16)) == val {
1028                 Some(low16.into())
1029             } else {
1030                 None
1031             }
1032         }
1033 
1034         fn u16_replicated_u8(&mut self, val: u64) -> Option<u8> {
1035             let val = val as u16;
1036             let low8 = val as u8 as u16;
1037             if (low8 | (low8 << 8)) == val {
1038                 Some(low8 as u8)
1039             } else {
1040                 None
1041             }
1042         }
1043 
1044         fn u128_low_bits(&mut self, val: u128) -> u64 {
1045             val as u64
1046         }
1047 
1048         fn u128_high_bits(&mut self, val: u128) -> u64 {
1049             (val >> 64) as u64
1050         }
1051 
1052         fn f16_min(&mut self, a: Ieee16, b: Ieee16) -> Option<Ieee16> {
1053             a.minimum(b).non_nan()
1054         }
1055 
1056         fn f16_max(&mut self, a: Ieee16, b: Ieee16) -> Option<Ieee16> {
1057             a.maximum(b).non_nan()
1058         }
1059 
1060         fn f16_neg(&mut self, n: Ieee16) -> Ieee16 {
1061             -n
1062         }
1063 
1064         fn f16_abs(&mut self, n: Ieee16) -> Ieee16 {
1065             n.abs()
1066         }
1067 
1068         fn f16_copysign(&mut self, a: Ieee16, b: Ieee16) -> Ieee16 {
1069             a.copysign(b)
1070         }
1071 
1072         fn f32_add(&mut self, lhs: Ieee32, rhs: Ieee32) -> Option<Ieee32> {
1073             (lhs + rhs).non_nan()
1074         }
1075 
1076         fn f32_sub(&mut self, lhs: Ieee32, rhs: Ieee32) -> Option<Ieee32> {
1077             (lhs - rhs).non_nan()
1078         }
1079 
1080         fn f32_mul(&mut self, lhs: Ieee32, rhs: Ieee32) -> Option<Ieee32> {
1081             (lhs * rhs).non_nan()
1082         }
1083 
1084         fn f32_div(&mut self, lhs: Ieee32, rhs: Ieee32) -> Option<Ieee32> {
1085             (lhs / rhs).non_nan()
1086         }
1087 
1088         fn f32_sqrt(&mut self, n: Ieee32) -> Option<Ieee32> {
1089             n.sqrt().non_nan()
1090         }
1091 
1092         fn f32_ceil(&mut self, n: Ieee32) -> Option<Ieee32> {
1093             n.ceil().non_nan()
1094         }
1095 
1096         fn f32_floor(&mut self, n: Ieee32) -> Option<Ieee32> {
1097             n.floor().non_nan()
1098         }
1099 
1100         fn f32_trunc(&mut self, n: Ieee32) -> Option<Ieee32> {
1101             n.trunc().non_nan()
1102         }
1103 
1104         fn f32_nearest(&mut self, n: Ieee32) -> Option<Ieee32> {
1105             n.round_ties_even().non_nan()
1106         }
1107 
1108         fn f32_min(&mut self, a: Ieee32, b: Ieee32) -> Option<Ieee32> {
1109             a.minimum(b).non_nan()
1110         }
1111 
1112         fn f32_max(&mut self, a: Ieee32, b: Ieee32) -> Option<Ieee32> {
1113             a.maximum(b).non_nan()
1114         }
1115 
1116         fn f32_neg(&mut self, n: Ieee32) -> Ieee32 {
1117             -n
1118         }
1119 
1120         fn f32_abs(&mut self, n: Ieee32) -> Ieee32 {
1121             n.abs()
1122         }
1123 
1124         fn f32_copysign(&mut self, a: Ieee32, b: Ieee32) -> Ieee32 {
1125             a.copysign(b)
1126         }
1127 
1128         fn f64_add(&mut self, lhs: Ieee64, rhs: Ieee64) -> Option<Ieee64> {
1129             (lhs + rhs).non_nan()
1130         }
1131 
1132         fn f64_sub(&mut self, lhs: Ieee64, rhs: Ieee64) -> Option<Ieee64> {
1133             (lhs - rhs).non_nan()
1134         }
1135 
1136         fn f64_mul(&mut self, lhs: Ieee64, rhs: Ieee64) -> Option<Ieee64> {
1137             (lhs * rhs).non_nan()
1138         }
1139 
1140         fn f64_div(&mut self, lhs: Ieee64, rhs: Ieee64) -> Option<Ieee64> {
1141             (lhs / rhs).non_nan()
1142         }
1143 
1144         fn f64_sqrt(&mut self, n: Ieee64) -> Option<Ieee64> {
1145             n.sqrt().non_nan()
1146         }
1147 
1148         fn f64_ceil(&mut self, n: Ieee64) -> Option<Ieee64> {
1149             n.ceil().non_nan()
1150         }
1151 
1152         fn f64_floor(&mut self, n: Ieee64) -> Option<Ieee64> {
1153             n.floor().non_nan()
1154         }
1155 
1156         fn f64_trunc(&mut self, n: Ieee64) -> Option<Ieee64> {
1157             n.trunc().non_nan()
1158         }
1159 
1160         fn f64_nearest(&mut self, n: Ieee64) -> Option<Ieee64> {
1161             n.round_ties_even().non_nan()
1162         }
1163 
1164         fn f64_min(&mut self, a: Ieee64, b: Ieee64) -> Option<Ieee64> {
1165             a.minimum(b).non_nan()
1166         }
1167 
1168         fn f64_max(&mut self, a: Ieee64, b: Ieee64) -> Option<Ieee64> {
1169             a.maximum(b).non_nan()
1170         }
1171 
1172         fn f64_neg(&mut self, n: Ieee64) -> Ieee64 {
1173             -n
1174         }
1175 
1176         fn f64_abs(&mut self, n: Ieee64) -> Ieee64 {
1177             n.abs()
1178         }
1179 
1180         fn f64_copysign(&mut self, a: Ieee64, b: Ieee64) -> Ieee64 {
1181             a.copysign(b)
1182         }
1183 
1184         fn f128_min(&mut self, a: Ieee128, b: Ieee128) -> Option<Ieee128> {
1185             a.minimum(b).non_nan()
1186         }
1187 
1188         fn f128_max(&mut self, a: Ieee128, b: Ieee128) -> Option<Ieee128> {
1189             a.maximum(b).non_nan()
1190         }
1191 
1192         fn f128_neg(&mut self, n: Ieee128) -> Ieee128 {
1193             -n
1194         }
1195 
1196         fn f128_abs(&mut self, n: Ieee128) -> Ieee128 {
1197             n.abs()
1198         }
1199 
1200         fn f128_copysign(&mut self, a: Ieee128, b: Ieee128) -> Ieee128 {
1201             a.copysign(b)
1202         }
1203 
1204         #[inline]
1205         fn def_inst(&mut self, val: Value) -> Option<Inst> {
1206             self.dfg().value_def(val).inst()
1207         }
1208     };
1209 }
1210