1use crate::cdsl::formats::InstructionFormat;
2use crate::cdsl::instructions::AllInstructions;
3use crate::error;
4use cranelift_srcgen::{fmtln, Formatter, Language};
5use std::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 fmt.line(";;;; `Opcode` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;");
147 fmt.empty_line();
148 fmt.line("(type Opcode extern");
149 fmt.indent(|fmt| {
150 fmt.line("(enum");
151 fmt.indent(|fmt| {
152 for inst in instructions {
153 fmtln!(fmt, "{}", inst.camel_name);
154 }
155 });
156 fmt.line(")");
157 });
158 fmt.line(")");
159 fmt.empty_line();
160
161 fmtln!(
163 fmt,
164 ";;;; `InstructionData` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;",
165 );
166 fmt.empty_line();
167 fmtln!(fmt, "(type InstructionData extern");
168 fmt.indent(|fmt| {
169 fmt.line("(enum");
170 fmt.indent(|fmt| {
171 for format in formats {
172 let mut s = format!("({} (opcode Opcode)", format.name);
173 if format.has_value_list {
174 s.push_str(" (args ValueList)");
175 } else if format.num_value_operands == 1 {
176 s.push_str(" (arg Value)");
177 } else if format.num_value_operands > 1 {
178 write!(&mut s, " (args ValueArray{})", format.num_value_operands).unwrap();
179 }
180
181 match format.num_block_operands {
182 0 => (),
183 1 => write!(&mut s, " (destination BlockCall)").unwrap(),
184 n => write!(&mut s, " (blocks BlockArray{n})").unwrap(),
185 }
186
187 for field in &format.imm_fields {
188 write!(
189 &mut s,
190 " ({} {})",
191 field.member,
192 field.kind.rust_type.rsplit("::").next().unwrap()
193 )
194 .unwrap();
195 }
196 s.push(')');
197 fmt.line(&s);
198 }
199 });
200 fmt.line(")");
201 });
202 fmt.line(")");
203 fmt.empty_line();
204
205 fmtln!(
207 fmt,
208 ";;;; Extracting Opcode, Operands, and Immediates from `InstructionData` ;;;;;;;;",
209 );
210 fmt.empty_line();
211 let ret_ty = match isle_target {
212 IsleTarget::Lower => "Inst",
213 IsleTarget::Opt => "Value",
214 };
215 for inst in instructions {
216 if isle_target == IsleTarget::Opt
217 && (inst.format.has_value_list || inst.value_results.len() != 1)
218 {
219 continue;
220 }
221
222 fmtln!(
223 fmt,
224 "(decl {} ({}{}) {})",
225 inst.name,
226 match isle_target {
227 IsleTarget::Lower => "",
228 IsleTarget::Opt => "Type ",
229 },
230 inst.operands_in
231 .iter()
232 .map(|o| {
233 let ty = o.kind.rust_type;
234 if ty == "&[Value]" {
235 "ValueSlice"
236 } else {
237 ty.rsplit("::").next().unwrap()
238 }
239 })
240 .collect::<Vec<_>>()
241 .join(" "),
242 ret_ty
243 );
244 fmtln!(fmt, "(extractor");
245 fmt.indent(|fmt| {
246 fmtln!(
247 fmt,
248 "({} {}{})",
249 inst.name,
250 match isle_target {
251 IsleTarget::Lower => "",
252 IsleTarget::Opt => "ty ",
253 },
254 inst.operands_in
255 .iter()
256 .map(|o| { o.name })
257 .collect::<Vec<_>>()
258 .join(" ")
259 );
260
261 let mut s = format!(
262 "(inst_data{} (InstructionData.{} (Opcode.{})",
263 match isle_target {
264 IsleTarget::Lower => "",
265 IsleTarget::Opt => " ty",
266 },
267 inst.format.name,
268 inst.camel_name
269 );
270
271 if inst.format.has_value_list {
273 let values: Vec<_> = inst
279 .operands_in
280 .iter()
281 .filter(|o| o.is_value())
282 .map(|o| o.name)
283 .collect();
284 let varargs = inst
285 .operands_in
286 .iter()
287 .find(|o| o.is_varargs())
288 .unwrap()
289 .name;
290 if values.is_empty() {
291 write!(&mut s, " (value_list_slice {varargs})").unwrap();
292 } else {
293 write!(
294 &mut s,
295 " (unwrap_head_value_list_{} {} {})",
296 values.len(),
297 values.join(" "),
298 varargs
299 )
300 .unwrap();
301 }
302 } else if inst.format.num_value_operands == 1 {
303 write!(
304 &mut s,
305 " {}",
306 inst.operands_in.iter().find(|o| o.is_value()).unwrap().name
307 )
308 .unwrap();
309 } else if inst.format.num_value_operands > 1 {
310 let values = inst
311 .operands_in
312 .iter()
313 .filter(|o| o.is_value())
314 .map(|o| o.name)
315 .collect::<Vec<_>>();
316 assert_eq!(values.len(), inst.format.num_value_operands);
317 let values = values.join(" ");
318 write!(
319 &mut s,
320 " (value_array_{} {})",
321 inst.format.num_value_operands, values,
322 )
323 .unwrap();
324 }
325
326 let imm_operands: Vec<_> = inst
328 .operands_in
329 .iter()
330 .filter(|o| !o.is_value() && !o.is_varargs() && !o.kind.is_block())
331 .collect();
332 assert_eq!(imm_operands.len(), inst.format.imm_fields.len(),);
333 for op in imm_operands {
334 write!(&mut s, " {}", op.name).unwrap();
335 }
336
337 let block_operands: Vec<_> = inst
339 .operands_in
340 .iter()
341 .filter(|o| o.kind.is_block())
342 .collect();
343 assert_eq!(block_operands.len(), inst.format.num_block_operands);
344 assert!(block_operands.len() <= 2);
345
346 if !block_operands.is_empty() {
347 if block_operands.len() == 1 {
348 write!(&mut s, " {}", block_operands[0].name).unwrap();
349 } else {
350 let blocks: Vec<_> = block_operands.iter().map(|o| o.name).collect();
351 let blocks = blocks.join(" ");
352 write!(
353 &mut s,
354 " (block_array_{} {})",
355 inst.format.num_block_operands, blocks,
356 )
357 .unwrap();
358 }
359 }
360
361 s.push_str("))");
362 fmt.line(&s);
363 });
364 fmt.line(")");
365
366 if isle_target == IsleTarget::Opt {
368 fmtln!(
369 fmt,
370 "(rule ({} ty {})",
371 inst.name,
372 inst.operands_in
373 .iter()
374 .map(|o| o.name)
375 .collect::<Vec<_>>()
376 .join(" ")
377 );
378 fmt.indent(|fmt| {
379 let mut s = format!(
380 "(make_inst ty (InstructionData.{} (Opcode.{})",
381 inst.format.name, inst.camel_name
382 );
383
384 assert!(!inst.format.has_value_list);
399 if inst.format.num_value_operands == 1 {
400 write!(
401 &mut s,
402 " {}",
403 inst.operands_in.iter().find(|o| o.is_value()).unwrap().name
404 )
405 .unwrap();
406 } else if inst.format.num_value_operands > 1 {
407 let values = inst
411 .operands_in
412 .iter()
413 .filter(|o| o.is_value())
414 .map(|o| o.name)
415 .collect::<Vec<_>>();
416 assert_eq!(values.len(), inst.format.num_value_operands);
417 let values = values.join(" ");
418 write!(
419 &mut s,
420 " (value_array_{}_ctor {})",
421 inst.format.num_value_operands, values
422 )
423 .unwrap();
424 }
425
426 if inst.format.num_block_operands > 0 {
427 let blocks: Vec<_> = inst
428 .operands_in
429 .iter()
430 .filter(|o| o.kind.is_block())
431 .map(|o| o.name)
432 .collect();
433 if inst.format.num_block_operands == 1 {
434 write!(&mut s, " {}", blocks.first().unwrap(),).unwrap();
435 } else {
436 write!(
437 &mut s,
438 " (block_array_{} {})",
439 inst.format.num_block_operands,
440 blocks.join(" ")
441 )
442 .unwrap();
443 }
444 }
445
446 for o in inst
448 .operands_in
449 .iter()
450 .filter(|o| !o.is_value() && !o.is_varargs() && !o.kind.is_block())
451 {
452 write!(&mut s, " {}", o.name).unwrap();
453 }
454 s.push_str("))");
455 fmt.line(&s);
456 });
457 fmt.line(")");
458 }
459
460 fmt.empty_line();
461 }
462}
463
464fn gen_opt_isle(
465 formats: &[Rc<InstructionFormat>],
466 instructions: &AllInstructions,
467 fmt: &mut Formatter,
468) {
469 gen_common_isle(formats, instructions, fmt, IsleTarget::Opt);
470}
471
472fn gen_lower_isle(
473 formats: &[Rc<InstructionFormat>],
474 instructions: &AllInstructions,
475 fmt: &mut Formatter,
476) {
477 gen_common_isle(formats, instructions, fmt, IsleTarget::Lower);
478}
479
480fn gen_isle_enum(name: &str, mut variants: Vec<&str>, fmt: &mut Formatter) {
482 variants.sort();
483 let prefix = format!(";;;; Enumerated Immediate: {name} ");
484 fmtln!(fmt, "{:;<80}", prefix);
485 fmt.empty_line();
486 fmtln!(fmt, "(type {} extern", name);
487 fmt.indent(|fmt| {
488 fmt.line("(enum");
489 fmt.indent(|fmt| {
490 for variant in variants {
491 fmtln!(fmt, "{}", variant);
492 }
493 });
494 fmt.line(")");
495 });
496 fmt.line(")");
497 fmt.empty_line();
498}
499
500pub(crate) fn generate(
501 formats: &[Rc<InstructionFormat>],
502 all_inst: &AllInstructions,
503 isle_opt_filename: &str,
504 isle_lower_filename: &str,
505 isle_dir: &std::path::Path,
506) -> Result<(), error::Error> {
507 let mut fmt = Formatter::new(Language::Isle);
509 gen_opt_isle(&formats, all_inst, &mut fmt);
510 fmt.write(isle_opt_filename, isle_dir)?;
511
512 let mut fmt = Formatter::new(Language::Isle);
514 gen_lower_isle(&formats, all_inst, &mut fmt);
515 fmt.write(isle_lower_filename, isle_dir)?;
516
517 Ok(())
518}