1 //! Shared definitions for the Cranelift intermediate language.
2 
3 pub mod entities;
4 pub mod formats;
5 pub mod immediates;
6 pub mod instructions;
7 pub mod settings;
8 pub mod types;
9 
10 use crate::cdsl::formats::{FormatStructure, InstructionFormat};
11 use crate::cdsl::instructions::AllInstructions;
12 use crate::cdsl::settings::SettingGroup;
13 
14 use crate::shared::entities::EntityRefs;
15 use crate::shared::formats::Formats;
16 use crate::shared::immediates::Immediates;
17 
18 use std::collections::HashMap;
19 use std::rc::Rc;
20 
21 pub(crate) struct Definitions {
22     pub settings: SettingGroup,
23     pub all_instructions: AllInstructions,
24     pub all_formats: Vec<Rc<InstructionFormat>>,
25 }
26 
27 pub(crate) fn define() -> Definitions {
28     let mut all_instructions = AllInstructions::new();
29 
30     let immediates = Immediates::new();
31     let entities = EntityRefs::new();
32     let formats = Formats::new(&immediates, &entities);
33     instructions::define(&mut all_instructions, &formats, &immediates, &entities);
34     let all_formats = verify_instruction_formats(&all_instructions);
35 
36     Definitions {
37         settings: settings::define(),
38         all_instructions,
39         all_formats,
40     }
41 }
42 
43 /// Verifies certain properties of formats.
44 ///
45 /// - Formats must be uniquely named: if two formats have the same name, they must refer to the
46 ///   same data. Otherwise, two format variants in the codegen crate would have the same name.
47 /// - Formats must be structurally different from each other. Otherwise, this would lead to
48 ///   code duplicate in the codegen crate.
49 ///
50 /// Returns a list of all the instruction formats effectively used.
51 fn verify_instruction_formats(all_instructions: &AllInstructions) -> Vec<Rc<InstructionFormat>> {
52     let mut format_names: HashMap<&'static str, &Rc<InstructionFormat>> = HashMap::new();
53 
54     // A structure is: number of input value operands / whether there's varargs or not / names
55     // of immediate fields.
56     let mut format_structures: HashMap<FormatStructure, Rc<InstructionFormat>> = HashMap::new();
57 
58     for inst in all_instructions {
59         // Check name.
60         if let Some(existing_format) = format_names.get(&inst.format.name) {
61             assert!(
62                 Rc::ptr_eq(existing_format, &inst.format),
63                 "formats must uniquely named; there's a\
64                      conflict on the name '{}', please make sure it is used only once.",
65                 existing_format.name
66             );
67         } else {
68             format_names.insert(inst.format.name, &inst.format);
69         }
70 
71         // Check structure.
72         let key = inst.format.structure();
73         if let Some(existing_format) = format_structures.get(&key) {
74             assert_eq!(
75                 existing_format.name, inst.format.name,
76                 "duplicate instruction formats {} and {}; please remove one.",
77                 existing_format.name, inst.format.name
78             );
79         } else {
80             format_structures.insert(key, inst.format.clone());
81         }
82     }
83 
84     let mut result = Vec::from_iter(format_structures.into_values());
85     result.sort_by_key(|format| format.name);
86     result
87 }
88