1use crate::cdsl::formats::InstructionFormat;
2use crate::cdsl::instructions::AllInstructions;
3use crate::error;
4use cranelift_srcgen::{Formatter, Language, fmtln};
5use std::{borrow::Cow, cmp::Ordering, rc::Rc};
6
7#[derive(Clone, Copy, PartialEq, Eq)]
9enum IsleTarget {
10 Lower,
12 Opt,
14}
15
16fn gen_common_isle(
17 formats: &[Rc<InstructionFormat>],
18 instructions: &AllInstructions,
19 fmt: &mut Formatter,
20 isle_target: IsleTarget,
21) {
22 use std::collections::{BTreeMap, BTreeSet};
23 use std::fmt::Write;
24
25 use crate::cdsl::formats::FormatField;
26
27 fmt.multi_line(
28 r#"
29;; GENERATED BY `gen_isle`. DO NOT EDIT!!!
30;;
31;; This ISLE file defines all the external type declarations for Cranelift's
32;; data structures that ISLE will process, such as `InstructionData` and
33;; `Opcode`.
34 "#,
35 );
36 fmt.empty_line();
37
38 let rust_name = |f: &FormatField| f.kind.rust_type.rsplit("::").next().unwrap();
40 let fields = |f: &FormatField| f.kind.fields.clone();
41 let immediate_types: BTreeMap<_, _> = formats
42 .iter()
43 .flat_map(|f| {
44 f.imm_fields
45 .iter()
46 .map(|i| (rust_name(i), fields(i)))
47 .collect::<Vec<_>>()
48 })
49 .collect();
50
51 let (enums, others): (BTreeMap<_, _>, BTreeMap<_, _>) = immediate_types
54 .iter()
55 .partition(|(_, field)| field.enum_values().is_some());
56
57 fmt.line(";;;; Extern type declarations for immediates ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;");
60 fmt.empty_line();
61 for ty in others.keys() {
62 fmtln!(fmt, "(type {} (primitive {}))", ty, ty);
63 }
64 fmt.empty_line();
65
66 for (name, field) in enums {
69 let field = field.enum_values().expect("only enums considered here");
70 let variants = field.values().cloned().collect();
71 gen_isle_enum(name, variants, fmt)
72 }
73
74 fmt.line(";;;; Value Arrays ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;");
77 fmt.empty_line();
78 let value_array_arities: BTreeSet<_> = formats
79 .iter()
80 .filter(|f| f.typevar_operand.is_some() && !f.has_value_list && f.num_value_operands != 1)
81 .map(|f| f.num_value_operands)
82 .collect();
83 for n in value_array_arities {
84 fmtln!(fmt, ";; ISLE representation of `[Value; {}]`.", n);
85 fmtln!(fmt, "(type ValueArray{} extern (enum))", n);
86 fmt.empty_line();
87
88 fmtln!(
89 fmt,
90 "(decl value_array_{} ({}) ValueArray{})",
91 n,
92 (0..n).map(|_| "Value").collect::<Vec<_>>().join(" "),
93 n
94 );
95 fmtln!(
96 fmt,
97 "(extern constructor value_array_{} pack_value_array_{})",
98 n,
99 n
100 );
101 fmtln!(
102 fmt,
103 "(extern extractor infallible value_array_{} unpack_value_array_{})",
104 n,
105 n
106 );
107 fmt.empty_line();
108 }
109
110 fmt.line(";;;; Block Arrays ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;");
113 fmt.empty_line();
114 let block_array_arities: BTreeSet<_> = formats
115 .iter()
116 .filter(|f| f.num_block_operands > 1)
117 .map(|f| f.num_block_operands)
118 .collect();
119 for n in block_array_arities {
120 fmtln!(fmt, ";; ISLE representation of `[BlockCall; {}]`.", n);
121 fmtln!(fmt, "(type BlockArray{} extern (enum))", n);
122 fmt.empty_line();
123
124 fmtln!(
125 fmt,
126 "(decl block_array_{0} ({1}) BlockArray{0})",
127 n,
128 (0..n).map(|_| "BlockCall").collect::<Vec<_>>().join(" ")
129 );
130
131 fmtln!(
132 fmt,
133 "(extern constructor block_array_{0} pack_block_array_{0})",
134 n
135 );
136
137 fmtln!(
138 fmt,
139 "(extern extractor infallible block_array_{0} unpack_block_array_{0})",
140 n
141 );
142 fmt.empty_line();
143 }
144
145 fmtln!(fmt, "(type Block extern (enum))");
147 fmt.empty_line();
148
149 fmt.line(";;;; `Opcode` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;");
151 fmt.empty_line();
152 fmt.line("(type Opcode extern");
153 fmt.indent(|fmt| {
154 fmt.line("(enum");
155 fmt.indent(|fmt| {
156 for inst in instructions {
157 fmtln!(fmt, "{}", inst.camel_name);
158 }
159 });
160 fmt.line(")");
161 });
162 fmt.line(")");
163 fmt.empty_line();
164
165 fmtln!(
167 fmt,
168 ";;;; `InstructionData` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;",
169 );
170 fmt.empty_line();
171 fmtln!(fmt, "(type InstructionData extern");
172 fmt.indent(|fmt| {
173 fmt.line("(enum");
174 fmt.indent(|fmt| {
175 for format in formats {
176 let mut s = format!("({} (opcode Opcode)", format.name);
177 if format.has_value_list {
178 s.push_str(" (args ValueList)");
179 } else if format.num_value_operands == 1 {
180 s.push_str(" (arg Value)");
181 } else if format.num_value_operands > 1 {
182 write!(&mut s, " (args ValueArray{})", format.num_value_operands).unwrap();
183 }
184
185 match format.num_block_operands {
186 0 => (),
187 1 => write!(&mut s, " (destination BlockCall)").unwrap(),
188 n => write!(&mut s, " (blocks BlockArray{n})").unwrap(),
189 }
190
191 match format.num_raw_block_operands {
192 0 => (),
193 1 => write!(&mut s, "(block Block)").unwrap(),
194 _ => panic!("Too many raw block arguments"),
195 }
196
197 for field in &format.imm_fields {
198 write!(
199 &mut s,
200 " ({} {})",
201 field.member,
202 field.kind.rust_type.rsplit("::").next().unwrap()
203 )
204 .unwrap();
205 }
206 s.push(')');
207 fmt.line(&s);
208 }
209 });
210 fmt.line(")");
211 });
212 fmt.line(")");
213 fmt.empty_line();
214
215 fmtln!(
217 fmt,
218 ";;;; Extracting Opcode, Operands, and Immediates from `InstructionData` ;;;;;;;;",
219 );
220 fmt.empty_line();
221 for inst in instructions {
222 let results_len = inst.value_results.len();
223 let is_var_args = inst.format.has_value_list;
224 let has_side_effects = inst.can_trap || inst.other_side_effects;
225
226 let (ret_ty, ty_in_decl, make_inst_ctor, inst_data_etor) =
227 match (isle_target, is_var_args, results_len, has_side_effects) {
228 (IsleTarget::Opt, true, _, _) => continue,
230
231 (IsleTarget::Opt, _, 1, false) => ("Value", true, "make_inst", "inst_data_value"),
232 (IsleTarget::Opt, _, _, _) => ("Inst", false, "make_skeleton_inst", "inst_data"),
233 (IsleTarget::Lower, false, r, _) if r >= 1 => {
234 ("Inst", true, "make_inst", "inst_data_value")
235 }
236 (IsleTarget::Lower, _, _, _) => ("Inst", false, "make_inst", "inst_data_value"),
237 };
238
239 fmtln!(
240 fmt,
241 "(decl {} ({}{}) {})",
242 inst.name,
243 if ty_in_decl { "Type " } else { "" },
244 inst.operands_in
245 .iter()
246 .map(|o| {
247 let ty = o.kind.rust_type;
248 if ty == "&[Value]" {
249 "ValueSlice"
250 } else {
251 ty.rsplit("::").next().unwrap()
252 }
253 })
254 .collect::<Vec<_>>()
255 .join(" "),
256 ret_ty
257 );
258 fmtln!(fmt, "(extractor");
259 fmt.indent(|fmt| {
260 fmtln!(
261 fmt,
262 "({} {}{})",
263 inst.name,
264 if ty_in_decl { "ty " } else { "" },
265 inst.operands_in
266 .iter()
267 .map(|o| { o.name })
268 .collect::<Vec<_>>()
269 .join(" ")
270 );
271
272 let mut s = format!(
273 "({inst_data_etor} {}(InstructionData.{} (Opcode.{})",
274 if ty_in_decl {
275 "ty "
276 } else if isle_target == IsleTarget::Lower {
277 "_ "
278 } else {
279 ""
280 },
281 inst.format.name,
282 inst.camel_name
283 );
284
285 if inst.format.has_value_list {
287 let values: Vec<_> = inst
293 .operands_in
294 .iter()
295 .filter(|o| o.is_value())
296 .map(|o| o.name)
297 .collect();
298 let varargs = inst
299 .operands_in
300 .iter()
301 .find(|o| o.is_varargs())
302 .unwrap()
303 .name;
304 if values.is_empty() {
305 write!(&mut s, " (value_list_slice {varargs})").unwrap();
306 } else {
307 write!(
308 &mut s,
309 " (unwrap_head_value_list_{} {} {})",
310 values.len(),
311 values.join(" "),
312 varargs
313 )
314 .unwrap();
315 }
316 } else if inst.format.num_value_operands == 1 {
317 write!(
318 &mut s,
319 " {}",
320 inst.operands_in.iter().find(|o| o.is_value()).unwrap().name
321 )
322 .unwrap();
323 } else if inst.format.num_value_operands > 1 {
324 let values = inst
325 .operands_in
326 .iter()
327 .filter(|o| o.is_value())
328 .map(|o| o.name)
329 .collect::<Vec<_>>();
330 assert_eq!(values.len(), inst.format.num_value_operands);
331 let values = values.join(" ");
332 write!(
333 &mut s,
334 " (value_array_{} {})",
335 inst.format.num_value_operands, values,
336 )
337 .unwrap();
338 }
339
340 let imm_operands: Vec<_> = inst
342 .operands_in
343 .iter()
344 .filter(|o| {
345 !o.is_value() && !o.is_varargs() && !o.kind.is_block() && !o.kind.is_raw_block()
346 })
347 .collect();
348 assert_eq!(imm_operands.len(), inst.format.imm_fields.len(),);
349 for op in imm_operands {
350 write!(&mut s, " {}", op.name).unwrap();
351 }
352
353 let block_operands: Vec<_> = inst
355 .operands_in
356 .iter()
357 .filter(|o| o.kind.is_block())
358 .collect();
359 assert_eq!(block_operands.len(), inst.format.num_block_operands);
360 assert!(block_operands.len() <= 2);
361
362 if !block_operands.is_empty() {
363 if block_operands.len() == 1 {
364 write!(&mut s, " {}", block_operands[0].name).unwrap();
365 } else {
366 let blocks: Vec<_> = block_operands.iter().map(|o| o.name).collect();
367 let blocks = blocks.join(" ");
368 write!(
369 &mut s,
370 " (block_array_{} {})",
371 inst.format.num_block_operands, blocks,
372 )
373 .unwrap();
374 }
375 }
376
377 match inst.format.num_raw_block_operands {
379 0 => {}
380 1 => {
381 write!(&mut s, " block").unwrap();
382 }
383 _ => panic!("Too many raw block arguments"),
384 }
385
386 s.push_str("))");
387 fmt.line(&s);
388 });
389 fmt.line(")");
390
391 if isle_target == IsleTarget::Opt {
393 fmtln!(
394 fmt,
395 "(rule ({}{} {})",
396 inst.name,
397 if ty_in_decl { " ty" } else { "" },
398 inst.operands_in
399 .iter()
400 .map(|o| o.name)
401 .collect::<Vec<_>>()
402 .join(" ")
403 );
404 fmt.indent(|fmt| {
405 let mut s = format!(
406 "({make_inst_ctor}{} (InstructionData.{} (Opcode.{})",
407 if ty_in_decl { " ty" } else { "" },
408 inst.format.name,
409 inst.camel_name
410 );
411
412 assert!(!inst.format.has_value_list);
427 if inst.format.num_value_operands == 1 {
428 write!(
429 &mut s,
430 " {}",
431 inst.operands_in.iter().find(|o| o.is_value()).unwrap().name
432 )
433 .unwrap();
434 } else if inst.format.num_value_operands > 1 {
435 let values = inst
439 .operands_in
440 .iter()
441 .filter(|o| o.is_value())
442 .map(|o| o.name)
443 .collect::<Vec<_>>();
444 assert_eq!(values.len(), inst.format.num_value_operands);
445 let values = values.join(" ");
446 write!(
447 &mut s,
448 " (value_array_{}_ctor {})",
449 inst.format.num_value_operands, values
450 )
451 .unwrap();
452 }
453
454 if inst.format.num_block_operands > 0 {
455 let blocks: Vec<_> = inst
456 .operands_in
457 .iter()
458 .filter(|o| o.kind.is_block())
459 .map(|o| o.name)
460 .collect();
461 if inst.format.num_block_operands == 1 {
462 write!(&mut s, " {}", blocks.first().unwrap(),).unwrap();
463 } else {
464 write!(
465 &mut s,
466 " (block_array_{} {})",
467 inst.format.num_block_operands,
468 blocks.join(" ")
469 )
470 .unwrap();
471 }
472 }
473
474 match inst.format.num_raw_block_operands {
475 0 => {}
476 1 => {
477 write!(&mut s, " block").unwrap();
478 }
479 _ => panic!("Too many raw block arguments"),
480 }
481
482 for o in inst.operands_in.iter().filter(|o| {
484 !o.is_value() && !o.is_varargs() && !o.kind.is_block() && !o.kind.is_raw_block()
485 }) {
486 write!(&mut s, " {}", o.name).unwrap();
487 }
488 s.push_str("))");
489 fmt.line(&s);
490 });
491 fmt.line(")");
492 }
493
494 fmt.empty_line();
495 }
496}
497
498fn gen_opt_isle(
499 formats: &[Rc<InstructionFormat>],
500 instructions: &AllInstructions,
501 fmt: &mut Formatter,
502) {
503 gen_common_isle(formats, instructions, fmt, IsleTarget::Opt);
504}
505
506fn gen_lower_isle(
507 formats: &[Rc<InstructionFormat>],
508 instructions: &AllInstructions,
509 fmt: &mut Formatter,
510) {
511 gen_common_isle(formats, instructions, fmt, IsleTarget::Lower);
512}
513
514fn gen_isle_enum(name: &str, mut variants: Vec<&str>, fmt: &mut Formatter) {
516 variants.sort();
517 let prefix = format!(";;;; Enumerated Immediate: {name} ");
518 fmtln!(fmt, "{:;<80}", prefix);
519 fmt.empty_line();
520 fmtln!(fmt, "(type {} extern", name);
521 fmt.indent(|fmt| {
522 fmt.line("(enum");
523 fmt.indent(|fmt| {
524 for variant in variants {
525 fmtln!(fmt, "{}", variant);
526 }
527 });
528 fmt.line(")");
529 });
530 fmt.line(")");
531 fmt.empty_line();
532}
533
534#[derive(Clone, Copy, PartialEq, Eq)]
535struct NumericType {
536 signed: bool,
537 byte_width: u8,
538}
539
540impl NumericType {
541 fn all() -> impl Iterator<Item = NumericType> {
542 [1, 2, 4, 8, 16].into_iter().flat_map(|byte_width| {
543 [true, false]
544 .into_iter()
545 .map(move |signed| NumericType { signed, byte_width })
546 })
547 }
548
549 fn name(&self) -> &'static str {
550 let idx = self.byte_width.ilog2();
551 let idx = usize::try_from(idx).unwrap();
552 if self.signed {
553 ["i8", "i16", "i32", "i64", "i128"][idx]
554 } else {
555 ["u8", "u16", "u32", "u64", "u128"][idx]
556 }
557 }
558}
559
560#[derive(Clone, Default, PartialEq, Eq)]
561struct NumericOp<'a> {
562 name: &'a str,
564 ret: &'a str,
566 partial: bool,
568 args: Rc<[(&'a str, &'a str)]>,
570 body: &'a str,
572 etors: bool,
576}
577
578impl NumericOp<'_> {
579 fn ops_for_type(ty: &NumericType) -> impl Iterator<Item = NumericOp<'_>> {
580 let arity1 = NumericOp {
581 args: [("a", ty.name())].into(),
582 ..NumericOp::default()
583 };
584
585 let arity2 = NumericOp {
586 args: [("a", ty.name()), ("b", ty.name())].into(),
587 ..NumericOp::default()
588 };
589
590 let comparison = NumericOp {
591 ret: "bool",
592 ..arity2.clone()
593 };
594
595 let predicate = NumericOp {
596 ret: "bool",
597 etors: true,
598 ..arity1.clone()
599 };
600
601 let binop = NumericOp {
602 ret: ty.name(),
603 ..arity2.clone()
604 };
605
606 let partial_binop = NumericOp {
607 ret: ty.name(),
608 partial: true,
609 ..binop.clone()
610 };
611
612 let unop = NumericOp {
613 ret: ty.name(),
614 ..arity1.clone()
615 };
616
617 let partial_unop = NumericOp {
618 ret: ty.name(),
619 partial: true,
620 ..unop.clone()
621 };
622
623 let shift = NumericOp {
624 args: [("a", ty.name()), ("b", "u32")].into(),
625 ..binop.clone()
626 };
627
628 let partial_shift = NumericOp {
629 args: [("a", ty.name()), ("b", "u32")].into(),
630 ..partial_binop.clone()
631 };
632
633 let ops = [
635 NumericOp {
637 name: "eq",
638 body: "a == b",
639 ..comparison.clone()
640 },
641 NumericOp {
642 name: "ne",
643 body: "a != b",
644 ..comparison.clone()
645 },
646 NumericOp {
647 name: "lt",
648 body: "a < b",
649 ..comparison.clone()
650 },
651 NumericOp {
652 name: "lt_eq",
653 body: "a <= b",
654 ..comparison.clone()
655 },
656 NumericOp {
657 name: "gt",
658 body: "a > b",
659 ..comparison.clone()
660 },
661 NumericOp {
662 name: "gt_eq",
663 body: "a >= b",
664 ..comparison.clone()
665 },
666 NumericOp {
674 name: "checked_add",
675 body: "a.checked_add(b)",
676 ..partial_binop.clone()
677 },
678 NumericOp {
679 name: "wrapping_add",
680 body: "a.wrapping_add(b)",
681 ..binop.clone()
682 },
683 NumericOp {
684 name: "add",
685 body: r#"a.checked_add(b).unwrap_or_else(|| panic!("addition overflow: {a} + {b}"))"#,
686 ..binop.clone()
687 },
688 NumericOp {
689 name: "checked_sub",
690 body: "a.checked_sub(b)",
691 ..partial_binop.clone()
692 },
693 NumericOp {
694 name: "wrapping_sub",
695 body: "a.wrapping_sub(b)",
696 ..binop.clone()
697 },
698 NumericOp {
699 name: "sub",
700 body: r#"a.checked_sub(b).unwrap_or_else(|| panic!("subtraction overflow: {a} - {b}"))"#,
701 ..binop.clone()
702 },
703 NumericOp {
704 name: "checked_mul",
705 body: "a.checked_mul(b)",
706 ..partial_binop.clone()
707 },
708 NumericOp {
709 name: "wrapping_mul",
710 body: "a.wrapping_mul(b)",
711 ..binop.clone()
712 },
713 NumericOp {
714 name: "mul",
715 body: r#"a.checked_mul(b).unwrap_or_else(|| panic!("multiplication overflow: {a} * {b}"))"#,
716 ..binop.clone()
717 },
718 NumericOp {
719 name: "checked_div",
720 body: "a.checked_div(b)",
721 ..partial_binop.clone()
722 },
723 NumericOp {
724 name: "wrapping_div",
725 body: "a.wrapping_div(b)",
726 ..binop.clone()
727 },
728 NumericOp {
729 name: "div",
730 body: r#"a.checked_div(b).unwrap_or_else(|| panic!("div failure: {a} / {b}"))"#,
731 ..binop.clone()
732 },
733 NumericOp {
734 name: "checked_rem",
735 body: "a.checked_rem(b)",
736 ..partial_binop.clone()
737 },
738 NumericOp {
739 name: "rem",
740 body: r#"a.checked_rem(b).unwrap_or_else(|| panic!("rem failure: {a} % {b}"))"#,
741 ..binop.clone()
742 },
743 NumericOp {
748 name: "and",
749 body: "a & b",
750 ..binop.clone()
751 },
752 NumericOp {
753 name: "or",
754 body: "a | b",
755 ..binop.clone()
756 },
757 NumericOp {
758 name: "xor",
759 body: "a ^ b",
760 ..binop.clone()
761 },
762 NumericOp {
763 name: "not",
764 body: "!a",
765 ..unop.clone()
766 },
767 NumericOp {
768 name: "checked_shl",
769 body: "a.checked_shl(b)",
770 ..partial_shift.clone()
771 },
772 NumericOp {
773 name: "wrapping_shl",
774 body: "a.wrapping_shl(b)",
775 ..shift.clone()
776 },
777 NumericOp {
778 name: "shl",
779 body: r#"a.checked_shl(b).unwrap_or_else(|| panic!("shl overflow: {a} << {b}"))"#,
780 ..shift.clone()
781 },
782 NumericOp {
783 name: "checked_shr",
784 body: "a.checked_shr(b)",
785 ..partial_shift.clone()
786 },
787 NumericOp {
788 name: "wrapping_shr",
789 body: "a.wrapping_shr(b)",
790 ..shift.clone()
791 },
792 NumericOp {
793 name: "shr",
794 body: r#"a.checked_shr(b).unwrap_or_else(|| panic!("shr overflow: {a} >> {b}"))"#,
795 ..shift.clone()
796 },
797 NumericOp {
798 name: "rotl",
799 body: "a.rotate_left(b)",
800 ..shift.clone()
801 },
802 NumericOp {
803 name: "rotr",
804 body: "a.rotate_right(b)",
805 ..shift.clone()
806 },
807 NumericOp {
813 name: "is_zero",
814 body: "a == 0",
815 ..predicate.clone()
816 },
817 NumericOp {
818 name: "is_non_zero",
819 body: "a != 0",
820 ..predicate.clone()
821 },
822 NumericOp {
823 name: "is_odd",
824 body: "a & 1 == 1",
825 ..predicate.clone()
826 },
827 NumericOp {
828 name: "is_even",
829 body: "a & 1 == 0",
830 ..predicate.clone()
831 },
832 NumericOp {
834 name: "checked_ilog2",
835 body: "a.checked_ilog2()",
836 ret: "u32",
837 ..partial_unop.clone()
838 },
839 NumericOp {
840 name: "ilog2",
841 body: r#"a.checked_ilog2().unwrap_or_else(|| panic!("ilog2 overflow: {a}"))"#,
842 ret: "u32",
843 ..unop.clone()
844 },
845 NumericOp {
846 name: "trailing_zeros",
847 body: "a.trailing_zeros()",
848 ret: "u32",
849 ..unop.clone()
850 },
851 NumericOp {
852 name: "trailing_ones",
853 body: "a.trailing_ones()",
854 ret: "u32",
855 ..unop.clone()
856 },
857 NumericOp {
858 name: "leading_zeros",
859 body: "a.leading_zeros()",
860 ret: "u32",
861 ..unop.clone()
862 },
863 NumericOp {
864 name: "leading_ones",
865 body: "a.leading_ones()",
866 ret: "u32",
867 ..unop.clone()
868 },
869 ];
870
871 let signed_ops = [
873 NumericOp {
874 name: "checked_neg",
875 body: "a.checked_neg()",
876 ..partial_unop.clone()
877 },
878 NumericOp {
879 name: "wrapping_neg",
880 body: "a.wrapping_neg()",
881 ..unop.clone()
882 },
883 NumericOp {
884 name: "neg",
885 body: r#"a.checked_neg().unwrap_or_else(|| panic!("negation overflow: {a}"))"#,
886 ..unop.clone()
887 },
888 ];
889
890 let unsigned_ops = [NumericOp {
892 name: "is_power_of_two",
893 body: "a.is_power_of_two()",
894 ..predicate.clone()
895 }];
896
897 struct IterIf<I> {
898 condition: bool,
899 iter: I,
900 }
901
902 impl<I: Iterator> Iterator for IterIf<I> {
903 type Item = I::Item;
904
905 fn next(&mut self) -> Option<Self::Item> {
906 if self.condition {
907 self.iter.next()
908 } else {
909 None
910 }
911 }
912 }
913
914 ops.into_iter()
915 .chain(IterIf {
916 condition: ty.signed,
917 iter: signed_ops.into_iter(),
918 })
919 .chain(IterIf {
920 condition: !ty.signed,
921 iter: unsigned_ops.into_iter(),
922 })
923 }
924}
925
926fn gen_numerics_isle(isle: &mut Formatter, rust: &mut Formatter) {
927 fmtln!(rust, "#[macro_export]");
928 fmtln!(rust, "#[doc(hidden)]");
929 fmtln!(rust, "macro_rules! isle_numerics_methods {{");
930 rust.indent_push();
931 fmtln!(rust, "() => {{");
932 rust.indent_push();
933
934 for ty in NumericType::all() {
935 for op in NumericOp::ops_for_type(&ty) {
936 let ty = ty.name();
937 let op_name = format!("{ty}_{}", op.name);
938 let partial = if op.partial { " partial" } else { "" };
939 let ret = op.ret;
940 fmtln!(isle, "(decl pure{partial} {op_name} (");
941 isle.indent(|isle| {
942 for (_arg_name, arg_ty) in op.args.iter() {
943 fmtln!(isle, "{arg_ty}");
944 }
945 });
946 fmtln!(isle, ") {ret})");
947 fmtln!(isle, "(extern constructor {op_name} {op_name})");
948
949 let ret = if op.partial {
950 Cow::from(format!("Option<{ret}>"))
951 } else {
952 Cow::from(ret)
953 };
954 let body = op.body;
955 fmtln!(rust, "#[inline]");
956 fmtln!(rust, "fn {op_name}(");
957 rust.indent(|rust| {
958 fmtln!(rust, "&mut self,");
959 for (arg_name, arg_ty) in op.args.iter() {
960 fmtln!(rust, "{arg_name}: {arg_ty},");
961 }
962 });
963 fmtln!(rust, ") -> {ret} {{");
964 rust.indent(|rust| {
965 fmtln!(rust, "{body}");
966 });
967 fmtln!(rust, "}}");
968
969 if op.etors {
981 debug_assert_eq!(op.args.len(), 1);
982 debug_assert_eq!(op.args[0].1, ty);
983 debug_assert_eq!(op.ret, "bool");
984 debug_assert!(op.name.starts_with("is_"));
985
986 let base_name = &op.name[3..];
988 debug_assert!(base_name.len() > 0);
989
990 fmtln!(isle, "(decl pure {ty}_matches_{base_name} (bool) {ty})");
991 fmtln!(
992 isle,
993 "(extern extractor {ty}_matches_{base_name} {ty}_matches_{base_name})"
994 );
995 fmtln!(rust, "#[inline]");
996 fmtln!(
997 rust,
998 "fn {ty}_matches_{base_name}(&mut self, a: {ty}) -> Option<bool> {{"
999 );
1000 rust.indent(|rust| {
1001 fmtln!(rust, "Some({body})");
1002 });
1003 fmtln!(rust, "}}");
1004
1005 fmtln!(isle, "(decl pure {ty}_extract_{base_name} ({ty}) {ty})");
1006 fmtln!(
1007 isle,
1008 "(extractor ({ty}_extract_{base_name} x) (and ({ty}_matches_{base_name} true) x))"
1009 );
1010
1011 fmtln!(isle, "(decl pure {ty}_when_{base_name} () {ty})");
1012 fmtln!(
1013 isle,
1014 "(extractor ({ty}_when_{base_name}) ({ty}_matches_{base_name} true))"
1015 );
1016
1017 fmtln!(isle, "(decl pure {ty}_when_not_{base_name} () {ty})");
1018 fmtln!(
1019 isle,
1020 "(extractor ({ty}_when_not_{base_name}) ({ty}_matches_{base_name} false))"
1021 );
1022 }
1023
1024 isle.empty_line();
1025 rust.empty_line();
1026 }
1027 }
1028
1029 for from in NumericType::all() {
1049 for to in NumericType::all() {
1050 if from == to {
1051 continue;
1052 }
1053
1054 let from_name = from.name();
1055 let to_name = to.name();
1056
1057 let lossy = match (from.byte_width.cmp(&to.byte_width), from.signed, to.signed) {
1058 (Ordering::Less, true, true) | (Ordering::Less, false, false) => false,
1060 (Ordering::Less, false, true) => false,
1062 (Ordering::Less, true, false) => true,
1064 (Ordering::Equal, _, _) => {
1067 debug_assert_ne!(from.signed, to.signed);
1068 true
1069 }
1070 (Ordering::Greater, _, _) => true,
1072 };
1073
1074 let (ctor, partial, rust_ret) = if lossy {
1075 (
1076 "try_into",
1077 " partial",
1078 Cow::from(format!("Option<{to_name}>")),
1079 )
1080 } else {
1081 ("into", "", Cow::from(to_name))
1082 };
1083
1084 fmtln!(
1086 isle,
1087 "(decl pure{partial} {from_name}_{ctor}_{to_name} ({from_name}) {to_name})"
1088 );
1089 fmtln!(
1090 isle,
1091 "(extern constructor {from_name}_{ctor}_{to_name} {from_name}_{ctor}_{to_name})"
1092 );
1093 if !lossy {
1094 fmtln!(
1095 isle,
1096 "(convert {from_name} {to_name} {from_name}_{ctor}_{to_name})"
1097 );
1098 }
1099 fmtln!(rust, "#[inline]");
1100 fmtln!(
1101 rust,
1102 "fn {from_name}_{ctor}_{to_name}(&mut self, x: {from_name}) -> {rust_ret} {{"
1103 );
1104 rust.indent(|rust| {
1105 if lossy {
1106 fmtln!(rust, "{to_name}::try_from(x).ok()");
1107 } else {
1108 fmtln!(rust, "{to_name}::from(x)");
1109 }
1110 });
1111 fmtln!(rust, "}}");
1112
1113 if lossy {
1115 fmtln!(
1116 isle,
1117 "(decl pure {from_name}_unwrap_into_{to_name} ({from_name}) {to_name})"
1118 );
1119 fmtln!(
1120 isle,
1121 "(extern constructor {from_name}_unwrap_into_{to_name} {from_name}_unwrap_into_{to_name})"
1122 );
1123 fmtln!(rust, "#[inline]");
1124 fmtln!(
1125 rust,
1126 "fn {from_name}_unwrap_into_{to_name}(&mut self, x: {from_name}) -> {to_name} {{"
1127 );
1128 rust.indent(|rust| {
1129 fmtln!(rust, "{to_name}::try_from(x).unwrap()");
1130 });
1131 fmtln!(rust, "}}");
1132 }
1133
1134 if lossy && from.signed == to.signed {
1136 fmtln!(
1137 isle,
1138 "(decl pure {from_name}_truncate_into_{to_name} ({from_name}) {to_name})"
1139 );
1140 fmtln!(
1141 isle,
1142 "(extern constructor {from_name}_truncate_into_{to_name} {from_name}_truncate_into_{to_name})"
1143 );
1144 fmtln!(rust, "#[inline]");
1145 fmtln!(
1146 rust,
1147 "fn {from_name}_truncate_into_{to_name}(&mut self, x: {from_name}) -> {to_name} {{"
1148 );
1149 rust.indent(|rust| {
1150 fmtln!(rust, "x as {to_name}");
1151 });
1152 fmtln!(rust, "}}");
1153 }
1154
1155 if from.byte_width == to.byte_width {
1157 debug_assert_ne!(from.signed, to.signed);
1158 let cast_name = if to.signed {
1159 "cast_signed"
1160 } else {
1161 "cast_unsigned"
1162 };
1163 fmtln!(
1164 isle,
1165 "(decl pure {from_name}_{cast_name} ({from_name}) {to_name})"
1166 );
1167 fmtln!(
1168 isle,
1169 "(extern constructor {from_name}_{cast_name} {from_name}_{cast_name})"
1170 );
1171 fmtln!(rust, "#[inline]");
1172 fmtln!(
1173 rust,
1174 "fn {from_name}_{cast_name}(&mut self, x: {from_name}) -> {to_name} {{"
1175 );
1176 rust.indent(|rust| {
1177 fmtln!(rust, "x as {to_name}");
1180 });
1181 fmtln!(rust, "}}");
1182 }
1183
1184 fmtln!(
1186 isle,
1187 "(decl pure {to_name}_from_{from_name} ({to_name}) {from_name})"
1188 );
1189 fmtln!(
1190 isle,
1191 "(extern extractor {to_name}_from_{from_name} {from_name}_from_{to_name})"
1192 );
1193 fmtln!(rust, "#[inline]");
1194 fmtln!(
1195 rust,
1196 "fn {from_name}_from_{to_name}(&mut self, x: {from_name}) -> Option<{to_name}> {{"
1197 );
1198 rust.indent(|rust| {
1199 if lossy {
1200 fmtln!(rust, "x.try_into().ok()");
1201 } else {
1202 fmtln!(rust, "Some(x.into())");
1203 }
1204 });
1205 fmtln!(rust, "}}");
1206
1207 isle.empty_line();
1208 rust.empty_line();
1209 }
1210 }
1211
1212 rust.indent_pop();
1213 fmtln!(rust, "}}");
1214 rust.indent_pop();
1215 fmtln!(rust, "}}");
1216}
1217
1218pub(crate) fn generate(
1219 formats: &[Rc<InstructionFormat>],
1220 all_inst: &AllInstructions,
1221 isle_numerics_filename: &str,
1222 rust_numerics_filename: &str,
1223 isle_opt_filename: &str,
1224 isle_lower_filename: &str,
1225 isle_dir: &std::path::Path,
1226) -> Result<(), error::Error> {
1227 let mut isle_fmt = Formatter::new(Language::Isle);
1229 let mut rust_fmt = Formatter::new(Language::Rust);
1230 gen_numerics_isle(&mut isle_fmt, &mut rust_fmt);
1231 isle_fmt.write(isle_numerics_filename, isle_dir)?;
1232 rust_fmt.write(rust_numerics_filename, isle_dir)?;
1233
1234 let mut fmt = Formatter::new(Language::Isle);
1236 gen_opt_isle(&formats, all_inst, &mut fmt);
1237 fmt.write(isle_opt_filename, isle_dir)?;
1238
1239 let mut fmt = Formatter::new(Language::Isle);
1241 gen_lower_isle(&formats, all_inst, &mut fmt);
1242 fmt.write(isle_lower_filename, isle_dir)?;
1243
1244 Ok(())
1245}