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