1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
//! Shared definitions for the Cranelift intermediate language.

pub mod entities;
pub mod formats;
pub mod immediates;
pub mod instructions;
pub mod legalize;
pub mod settings;
pub mod types;

use crate::cdsl::formats::{FormatStructure, InstructionFormat};
use crate::cdsl::instructions::{AllInstructions, InstructionGroup};
use crate::cdsl::settings::SettingGroup;
use crate::cdsl::xform::TransformGroups;

use crate::shared::entities::EntityRefs;
use crate::shared::formats::Formats;
use crate::shared::immediates::Immediates;

use std::collections::HashMap;
use std::iter::FromIterator;
use std::rc::Rc;

pub(crate) struct Definitions {
    pub settings: SettingGroup,
    pub all_instructions: AllInstructions,
    pub instructions: InstructionGroup,
    pub imm: Immediates,
    pub formats: Formats,
    pub transform_groups: TransformGroups,
    pub entities: EntityRefs,
}

pub(crate) fn define() -> Definitions {
    let mut all_instructions = AllInstructions::new();

    let immediates = Immediates::new();
    let entities = EntityRefs::new();
    let formats = Formats::new(&immediates, &entities);
    let instructions =
        instructions::define(&mut all_instructions, &formats, &immediates, &entities);
    let transform_groups = legalize::define(&instructions, &immediates);

    Definitions {
        settings: settings::define(),
        all_instructions,
        instructions,
        imm: immediates,
        formats,
        transform_groups,
        entities,
    }
}

impl Definitions {
    /// Verifies certain properties of formats.
    ///
    /// - Formats must be uniquely named: if two formats have the same name, they must refer to the
    /// same data. Otherwise, two format variants in the codegen crate would have the same name.
    /// - Formats must be structurally different from each other. Otherwise, this would lead to
    /// code duplicate in the codegen crate.
    ///
    /// Returns a list of all the instruction formats effectively used.
    pub fn verify_instruction_formats(&self) -> Vec<&InstructionFormat> {
        let mut format_names: HashMap<&'static str, &Rc<InstructionFormat>> = HashMap::new();

        // A structure is: number of input value operands / whether there's varargs or not / names
        // of immediate fields.
        let mut format_structures: HashMap<FormatStructure, &InstructionFormat> = HashMap::new();

        for inst in self.all_instructions.values() {
            // Check name.
            if let Some(existing_format) = format_names.get(&inst.format.name) {
                assert!(
                    Rc::ptr_eq(&existing_format, &inst.format),
                    "formats must uniquely named; there's a\
                     conflict on the name '{}', please make sure it is used only once.",
                    existing_format.name
                );
            } else {
                format_names.insert(inst.format.name, &inst.format);
            }

            // Check structure.
            let key = inst.format.structure();
            if let Some(existing_format) = format_structures.get(&key) {
                assert_eq!(
                    existing_format.name, inst.format.name,
                    "duplicate instruction formats {} and {}; please remove one.",
                    existing_format.name, inst.format.name
                );
            } else {
                format_structures.insert(key, &inst.format);
            }
        }

        let mut result = Vec::from_iter(format_structures.into_iter().map(|(_, v)| v));
        result.sort_by_key(|format| format.name);
        result
    }
}