1use std::rc::Rc;
2
3use crate::cdsl::formats::InstructionFormat;
4use crate::cdsl::instructions::AllInstructions;
5use crate::error;
6use crate::srcgen::Formatter;
7
8#[derive(Clone, Copy, PartialEq, Eq)]
10enum IsleTarget {
11 Lower,
13 Opt,
15}
16
17fn gen_common_isle(
18 formats: &[Rc<InstructionFormat>],
19 instructions: &AllInstructions,
20 fmt: &mut Formatter,
21 isle_target: IsleTarget,
22) {
23 use std::collections::{BTreeMap, BTreeSet};
24 use std::fmt::Write;
25
26 use crate::cdsl::formats::FormatField;
27
28 fmt.multi_line(
29 r#"
30;; GENERATED BY `gen_isle`. DO NOT EDIT!!!
31;;
32;; This ISLE file defines all the external type declarations for Cranelift's
33;; data structures that ISLE will process, such as `InstructionData` and
34;; `Opcode`.
35 "#,
36 );
37 fmt.empty_line();
38
39 let rust_name = |f: &FormatField| f.kind.rust_type.rsplit("::").next().unwrap();
41 let fields = |f: &FormatField| f.kind.fields.clone();
42 let immediate_types: BTreeMap<_, _> = formats
43 .iter()
44 .flat_map(|f| {
45 f.imm_fields
46 .iter()
47 .map(|i| (rust_name(i), fields(i)))
48 .collect::<Vec<_>>()
49 })
50 .collect();
51
52 let (enums, others): (BTreeMap<_, _>, BTreeMap<_, _>) = immediate_types
55 .iter()
56 .partition(|(_, field)| field.enum_values().is_some());
57
58 fmt.line(";;;; Extern type declarations for immediates ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;");
61 fmt.empty_line();
62 for ty in others.keys() {
63 fmtln!(fmt, "(type {} (primitive {}))", ty, ty);
64 }
65 fmt.empty_line();
66
67 for (name, field) in enums {
70 let field = field.enum_values().expect("only enums considered here");
71 let variants = field.values().cloned().collect();
72 gen_isle_enum(name, variants, fmt)
73 }
74
75 fmt.line(";;;; Value Arrays ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;");
78 fmt.empty_line();
79 let value_array_arities: BTreeSet<_> = formats
80 .iter()
81 .filter(|f| f.typevar_operand.is_some() && !f.has_value_list && f.num_value_operands != 1)
82 .map(|f| f.num_value_operands)
83 .collect();
84 for n in value_array_arities {
85 fmtln!(fmt, ";; ISLE representation of `[Value; {}]`.", n);
86 fmtln!(fmt, "(type ValueArray{} extern (enum))", n);
87 fmt.empty_line();
88
89 fmtln!(
90 fmt,
91 "(decl value_array_{} ({}) ValueArray{})",
92 n,
93 (0..n).map(|_| "Value").collect::<Vec<_>>().join(" "),
94 n
95 );
96 fmtln!(
97 fmt,
98 "(extern constructor value_array_{} pack_value_array_{})",
99 n,
100 n
101 );
102 fmtln!(
103 fmt,
104 "(extern extractor infallible value_array_{} unpack_value_array_{})",
105 n,
106 n
107 );
108 fmt.empty_line();
109 }
110
111 fmt.line(";;;; Block Arrays ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;");
114 fmt.empty_line();
115 let block_array_arities: BTreeSet<_> = formats
116 .iter()
117 .filter(|f| f.num_block_operands > 1)
118 .map(|f| f.num_block_operands)
119 .collect();
120 for n in block_array_arities {
121 fmtln!(fmt, ";; ISLE representation of `[BlockCall; {}]`.", n);
122 fmtln!(fmt, "(type BlockArray{} extern (enum))", n);
123 fmt.empty_line();
124
125 fmtln!(
126 fmt,
127 "(decl block_array_{0} ({1}) BlockArray{0})",
128 n,
129 (0..n).map(|_| "BlockCall").collect::<Vec<_>>().join(" ")
130 );
131
132 fmtln!(
133 fmt,
134 "(extern constructor block_array_{0} pack_block_array_{0})",
135 n
136 );
137
138 fmtln!(
139 fmt,
140 "(extern extractor infallible block_array_{0} unpack_block_array_{0})",
141 n
142 );
143 fmt.empty_line();
144 }
145
146 fmt.line(";;;; `Opcode` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;");
148 fmt.empty_line();
149 fmt.line("(type Opcode extern");
150 fmt.indent(|fmt| {
151 fmt.line("(enum");
152 fmt.indent(|fmt| {
153 for inst in instructions {
154 fmtln!(fmt, "{}", inst.camel_name);
155 }
156 });
157 fmt.line(")");
158 });
159 fmt.line(")");
160 fmt.empty_line();
161
162 fmtln!(
164 fmt,
165 ";;;; `InstructionData` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;",
166 );
167 fmt.empty_line();
168 fmtln!(fmt, "(type InstructionData extern");
169 fmt.indent(|fmt| {
170 fmt.line("(enum");
171 fmt.indent(|fmt| {
172 for format in formats {
173 let mut s = format!("({} (opcode Opcode)", format.name);
174 if format.has_value_list {
175 s.push_str(" (args ValueList)");
176 } else if format.num_value_operands == 1 {
177 s.push_str(" (arg Value)");
178 } else if format.num_value_operands > 1 {
179 write!(&mut s, " (args ValueArray{})", format.num_value_operands).unwrap();
180 }
181
182 match format.num_block_operands {
183 0 => (),
184 1 => write!(&mut s, " (destination BlockCall)").unwrap(),
185 n => write!(&mut s, " (blocks BlockArray{n})").unwrap(),
186 }
187
188 for field in &format.imm_fields {
189 write!(
190 &mut s,
191 " ({} {})",
192 field.member,
193 field.kind.rust_type.rsplit("::").next().unwrap()
194 )
195 .unwrap();
196 }
197 s.push(')');
198 fmt.line(&s);
199 }
200 });
201 fmt.line(")");
202 });
203 fmt.line(")");
204 fmt.empty_line();
205
206 fmtln!(
208 fmt,
209 ";;;; Extracting Opcode, Operands, and Immediates from `InstructionData` ;;;;;;;;",
210 );
211 fmt.empty_line();
212 let ret_ty = match isle_target {
213 IsleTarget::Lower => "Inst",
214 IsleTarget::Opt => "Value",
215 };
216 for inst in instructions {
217 if isle_target == IsleTarget::Opt
218 && (inst.format.has_value_list || inst.value_results.len() != 1)
219 {
220 continue;
221 }
222
223 fmtln!(
224 fmt,
225 "(decl {} ({}{}) {})",
226 inst.name,
227 match isle_target {
228 IsleTarget::Lower => "",
229 IsleTarget::Opt => "Type ",
230 },
231 inst.operands_in
232 .iter()
233 .map(|o| {
234 let ty = o.kind.rust_type;
235 if ty == "&[Value]" {
236 "ValueSlice"
237 } else {
238 ty.rsplit("::").next().unwrap()
239 }
240 })
241 .collect::<Vec<_>>()
242 .join(" "),
243 ret_ty
244 );
245 fmtln!(fmt, "(extractor");
246 fmt.indent(|fmt| {
247 fmtln!(
248 fmt,
249 "({} {}{})",
250 inst.name,
251 match isle_target {
252 IsleTarget::Lower => "",
253 IsleTarget::Opt => "ty ",
254 },
255 inst.operands_in
256 .iter()
257 .map(|o| { o.name })
258 .collect::<Vec<_>>()
259 .join(" ")
260 );
261
262 let mut s = format!(
263 "(inst_data{} (InstructionData.{} (Opcode.{})",
264 match isle_target {
265 IsleTarget::Lower => "",
266 IsleTarget::Opt => " ty",
267 },
268 inst.format.name,
269 inst.camel_name
270 );
271
272 if inst.format.has_value_list {
274 let values: Vec<_> = inst
280 .operands_in
281 .iter()
282 .filter(|o| o.is_value())
283 .map(|o| o.name)
284 .collect();
285 let varargs = inst
286 .operands_in
287 .iter()
288 .find(|o| o.is_varargs())
289 .unwrap()
290 .name;
291 if values.is_empty() {
292 write!(&mut s, " (value_list_slice {varargs})").unwrap();
293 } else {
294 write!(
295 &mut s,
296 " (unwrap_head_value_list_{} {} {})",
297 values.len(),
298 values.join(" "),
299 varargs
300 )
301 .unwrap();
302 }
303 } else if inst.format.num_value_operands == 1 {
304 write!(
305 &mut s,
306 " {}",
307 inst.operands_in.iter().find(|o| o.is_value()).unwrap().name
308 )
309 .unwrap();
310 } else if inst.format.num_value_operands > 1 {
311 let values = inst
312 .operands_in
313 .iter()
314 .filter(|o| o.is_value())
315 .map(|o| o.name)
316 .collect::<Vec<_>>();
317 assert_eq!(values.len(), inst.format.num_value_operands);
318 let values = values.join(" ");
319 write!(
320 &mut s,
321 " (value_array_{} {})",
322 inst.format.num_value_operands, values,
323 )
324 .unwrap();
325 }
326
327 let imm_operands: Vec<_> = inst
329 .operands_in
330 .iter()
331 .filter(|o| !o.is_value() && !o.is_varargs() && !o.kind.is_block())
332 .collect();
333 assert_eq!(imm_operands.len(), inst.format.imm_fields.len(),);
334 for op in imm_operands {
335 write!(&mut s, " {}", op.name).unwrap();
336 }
337
338 let block_operands: Vec<_> = inst
340 .operands_in
341 .iter()
342 .filter(|o| o.kind.is_block())
343 .collect();
344 assert_eq!(block_operands.len(), inst.format.num_block_operands);
345 assert!(block_operands.len() <= 2);
346
347 if !block_operands.is_empty() {
348 if block_operands.len() == 1 {
349 write!(&mut s, " {}", block_operands[0].name).unwrap();
350 } else {
351 let blocks: Vec<_> = block_operands.iter().map(|o| o.name).collect();
352 let blocks = blocks.join(" ");
353 write!(
354 &mut s,
355 " (block_array_{} {})",
356 inst.format.num_block_operands, blocks,
357 )
358 .unwrap();
359 }
360 }
361
362 s.push_str("))");
363 fmt.line(&s);
364 });
365 fmt.line(")");
366
367 if isle_target == IsleTarget::Opt {
369 fmtln!(
370 fmt,
371 "(rule ({} ty {})",
372 inst.name,
373 inst.operands_in
374 .iter()
375 .map(|o| o.name)
376 .collect::<Vec<_>>()
377 .join(" ")
378 );
379 fmt.indent(|fmt| {
380 let mut s = format!(
381 "(make_inst ty (InstructionData.{} (Opcode.{})",
382 inst.format.name, inst.camel_name
383 );
384
385 assert!(!inst.format.has_value_list);
400 if inst.format.num_value_operands == 1 {
401 write!(
402 &mut s,
403 " {}",
404 inst.operands_in.iter().find(|o| o.is_value()).unwrap().name
405 )
406 .unwrap();
407 } else if inst.format.num_value_operands > 1 {
408 let values = inst
412 .operands_in
413 .iter()
414 .filter(|o| o.is_value())
415 .map(|o| o.name)
416 .collect::<Vec<_>>();
417 assert_eq!(values.len(), inst.format.num_value_operands);
418 let values = values.join(" ");
419 write!(
420 &mut s,
421 " (value_array_{}_ctor {})",
422 inst.format.num_value_operands, values
423 )
424 .unwrap();
425 }
426
427 if inst.format.num_block_operands > 0 {
428 let blocks: Vec<_> = inst
429 .operands_in
430 .iter()
431 .filter(|o| o.kind.is_block())
432 .map(|o| o.name)
433 .collect();
434 if inst.format.num_block_operands == 1 {
435 write!(&mut s, " {}", blocks.first().unwrap(),).unwrap();
436 } else {
437 write!(
438 &mut s,
439 " (block_array_{} {})",
440 inst.format.num_block_operands,
441 blocks.join(" ")
442 )
443 .unwrap();
444 }
445 }
446
447 for o in inst
449 .operands_in
450 .iter()
451 .filter(|o| !o.is_value() && !o.is_varargs() && !o.kind.is_block())
452 {
453 write!(&mut s, " {}", o.name).unwrap();
454 }
455 s.push_str("))");
456 fmt.line(&s);
457 });
458 fmt.line(")");
459 }
460
461 fmt.empty_line();
462 }
463}
464
465fn gen_opt_isle(
466 formats: &[Rc<InstructionFormat>],
467 instructions: &AllInstructions,
468 fmt: &mut Formatter,
469) {
470 gen_common_isle(formats, instructions, fmt, IsleTarget::Opt);
471}
472
473fn gen_lower_isle(
474 formats: &[Rc<InstructionFormat>],
475 instructions: &AllInstructions,
476 fmt: &mut Formatter,
477) {
478 gen_common_isle(formats, instructions, fmt, IsleTarget::Lower);
479}
480
481fn gen_isle_enum(name: &str, mut variants: Vec<&str>, fmt: &mut Formatter) {
483 variants.sort();
484 let prefix = format!(";;;; Enumerated Immediate: {name} ");
485 fmtln!(fmt, "{:;<80}", prefix);
486 fmt.empty_line();
487 fmtln!(fmt, "(type {} extern", name);
488 fmt.indent(|fmt| {
489 fmt.line("(enum");
490 fmt.indent(|fmt| {
491 for variant in variants {
492 fmtln!(fmt, "{}", variant);
493 }
494 });
495 fmt.line(")");
496 });
497 fmt.line(")");
498 fmt.empty_line();
499}
500
501pub(crate) fn generate(
502 formats: &[Rc<InstructionFormat>],
503 all_inst: &AllInstructions,
504 isle_opt_filename: &str,
505 isle_lower_filename: &str,
506 isle_dir: &std::path::Path,
507) -> Result<(), error::Error> {
508 let mut fmt = Formatter::new();
510 gen_opt_isle(&formats, all_inst, &mut fmt);
511 fmt.update_file(isle_opt_filename, isle_dir)?;
512
513 let mut fmt = Formatter::new();
515 gen_lower_isle(&formats, all_inst, &mut fmt);
516 fmt.update_file(isle_lower_filename, isle_dir)?;
517
518 Ok(())
519}