cranelift_codegen_meta/shared/
mod.rs

1//! Shared definitions for the Cranelift intermediate language.
2
3pub mod entities;
4pub mod formats;
5pub mod immediates;
6pub mod instructions;
7pub mod settings;
8pub mod types;
9
10use crate::cdsl::formats::{FormatStructure, InstructionFormat};
11use crate::cdsl::instructions::AllInstructions;
12use crate::cdsl::settings::SettingGroup;
13
14use crate::shared::entities::EntityRefs;
15use crate::shared::formats::Formats;
16use crate::shared::immediates::Immediates;
17
18use std::collections::HashMap;
19use std::rc::Rc;
20
21pub(crate) struct Definitions {
22    pub settings: SettingGroup,
23    pub all_instructions: AllInstructions,
24    pub all_formats: Vec<Rc<InstructionFormat>>,
25}
26
27pub(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.
51fn 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}