use std::collections::BTreeMap;
use std::collections::HashMap;
use llvmkit_ir::{
Brand, Dyn, FunctionValue, GlobalAlias, GlobalIFunc, GlobalVariable, ModuleBrand, Type,
attributes::AttributeStorage, metadata::MetadataId,
};
use crate::numbered_values::NumberedValues;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum GlobalRef<'ctx, B: ModuleBrand = Brand<'ctx>> {
Function(FunctionValue<'ctx, Dyn, B>),
Variable(GlobalVariable<'ctx, B>),
Alias(GlobalAlias<'ctx, B>),
IFunc(GlobalIFunc<'ctx, B>),
}
impl<'ctx, B: ModuleBrand> From<FunctionValue<'ctx, Dyn, B>> for GlobalRef<'ctx, B> {
#[inline]
fn from(v: FunctionValue<'ctx, Dyn, B>) -> Self {
GlobalRef::Function(v)
}
}
impl<'ctx, B: ModuleBrand> From<GlobalVariable<'ctx, B>> for GlobalRef<'ctx, B> {
#[inline]
fn from(v: GlobalVariable<'ctx, B>) -> Self {
GlobalRef::Variable(v)
}
}
impl<'ctx, B: ModuleBrand> From<GlobalAlias<'ctx, B>> for GlobalRef<'ctx, B> {
#[inline]
fn from(v: GlobalAlias<'ctx, B>) -> Self {
GlobalRef::Alias(v)
}
}
impl<'ctx, B: ModuleBrand> From<GlobalIFunc<'ctx, B>> for GlobalRef<'ctx, B> {
#[inline]
fn from(v: GlobalIFunc<'ctx, B>) -> Self {
GlobalRef::IFunc(v)
}
}
#[derive(Debug)]
pub struct SlotMapping<'ctx, B: ModuleBrand = Brand<'ctx>> {
pub global_values: NumberedValues<GlobalRef<'ctx, B>>,
pub named_types: HashMap<String, Type<'ctx, B>>,
pub numbered_types: BTreeMap<u32, Type<'ctx, B>>,
pub attribute_groups: NumberedValues<AttributeStorage>,
pub metadata_nodes: NumberedValues<MetadataId>,
}
impl<'ctx, B: ModuleBrand> Default for SlotMapping<'ctx, B> {
#[inline]
fn default() -> Self {
Self {
global_values: NumberedValues::new(),
named_types: HashMap::new(),
numbered_types: BTreeMap::new(),
metadata_nodes: NumberedValues::new(),
attribute_groups: NumberedValues::new(),
}
}
}
impl<'ctx, B: ModuleBrand> SlotMapping<'ctx, B> {
#[inline]
pub fn new() -> Self {
Self::default()
}
}
#[cfg(test)]
mod tests {
use super::*;
use llvmkit_ir::Module;
#[test]
fn fresh_mapping_is_empty() {
let m: SlotMapping<'_> = SlotMapping::new();
assert_eq!(m.global_values.get_next(), 0);
assert!(m.global_values.is_empty());
assert!(m.named_types.is_empty());
assert!(m.numbered_types.is_empty());
assert!(m.metadata_nodes.is_empty());
}
#[test]
fn slot_mapping_records_typed_globals() {
Module::with_new("slot_mapping_records_typed_globals", |m| {
let i32_ty = m.i32_type();
let g = m
.add_external_global("g", i32_ty.as_type())
.expect("fresh global");
let mut mapping: SlotMapping<'_> = SlotMapping::new();
mapping
.global_values
.add(0, GlobalRef::Variable(g))
.expect("first slot");
assert_eq!(mapping.global_values.get_next(), 1);
match mapping.global_values.get(0) {
Some(GlobalRef::Variable(stored)) => assert_eq!(*stored, g),
other => panic!("unexpected entry: {other:?}"),
}
});
}
}