use std::fmt;
use lamina_platform::PointerWidth;
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub enum AddressSpace {
#[default]
Generic,
Global,
Region,
Local,
Constant,
Private,
Parameter,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
pub enum Signedness {
#[default]
Signed,
Unsigned,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum AggregateClass {
Integer,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
pub enum AggregateShape {
#[default]
Composite,
WideScalar,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Aggregate {
pub size: usize,
pub align: usize,
pub class: AggregateClass,
pub shape: AggregateShape,
}
impl Aggregate {
pub fn is_composite(&self) -> bool {
self.shape == AggregateShape::Composite
}
pub fn is_wide_scalar(&self) -> bool {
self.shape == AggregateShape::WideScalar
}
pub fn words(&self) -> usize {
self.size.div_ceil(8)
}
pub fn words_of(&self, pointer: PointerWidth) -> usize {
self.size.div_ceil(pointer.bytes())
}
pub fn max_in_registers(pointer: PointerWidth) -> u64 {
2 * pointer.bytes() as u64
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ScalarType {
I8,
I16,
I32,
I64,
F32,
F64,
Ptr,
PtrIn(AddressSpace),
I1,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum VectorLane {
I8,
I16,
I32,
I64,
F32,
F64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum VectorType {
V128(VectorLane),
V256(VectorLane),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MirType {
Scalar(ScalarType),
Vector(VectorType),
}
impl MirType {
pub fn signed_integer(self, value: i64, pointer: PointerWidth) -> i64 {
let shift = 64 - self.size_bytes(pointer) * 8;
(value << shift) >> shift
}
pub fn unsigned_integer(self, value: i64, pointer: PointerWidth) -> u64 {
let shift = 64 - self.size_bytes(pointer) * 8;
((value as u64) << shift) >> shift
}
pub fn size_bytes(&self, pointer: PointerWidth) -> usize {
match self {
MirType::Scalar(s) => match s {
ScalarType::I1 | ScalarType::I8 => 1,
ScalarType::I16 => 2,
ScalarType::I32 | ScalarType::F32 => 4,
ScalarType::I64 | ScalarType::F64 => 8,
ScalarType::Ptr | ScalarType::PtrIn(_) => pointer.bytes(),
},
MirType::Vector(v) => match v {
VectorType::V128(_) => 16,
VectorType::V256(_) => 32,
},
}
}
pub fn alignment(&self, pointer: PointerWidth) -> usize {
match self {
MirType::Scalar(s) => match s {
ScalarType::I1 | ScalarType::I8 => 1,
ScalarType::I16 => 2,
ScalarType::I32 | ScalarType::F32 => 4,
ScalarType::I64 | ScalarType::F64 => 8,
ScalarType::Ptr | ScalarType::PtrIn(_) => pointer.bytes(),
},
MirType::Vector(v) => match v {
VectorType::V128(_) => 16,
VectorType::V256(_) => 32,
},
}
}
pub fn is_float(&self) -> bool {
matches!(
self,
MirType::Scalar(ScalarType::F32 | ScalarType::F64)
| MirType::Vector(VectorType::V128(VectorLane::F32 | VectorLane::F64))
| MirType::Vector(VectorType::V256(VectorLane::F32 | VectorLane::F64))
)
}
pub fn is_vector(&self) -> bool {
matches!(self, MirType::Vector(_))
}
pub fn ptr_in(space: AddressSpace) -> Self {
Self::Scalar(ScalarType::PtrIn(space))
}
}
impl fmt::Display for ScalarType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ScalarType::I1 => write!(f, "i1"),
ScalarType::I8 => write!(f, "i8"),
ScalarType::I16 => write!(f, "i16"),
ScalarType::I32 => write!(f, "i32"),
ScalarType::I64 => write!(f, "i64"),
ScalarType::F32 => write!(f, "f32"),
ScalarType::F64 => write!(f, "f64"),
ScalarType::Ptr => write!(f, "ptr"),
ScalarType::PtrIn(space) => write!(f, "ptr<{space:?}>"),
}
}
}
impl fmt::Display for VectorLane {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
VectorLane::I8 => write!(f, "i8"),
VectorLane::I16 => write!(f, "i16"),
VectorLane::I32 => write!(f, "i32"),
VectorLane::I64 => write!(f, "i64"),
VectorLane::F32 => write!(f, "f32"),
VectorLane::F64 => write!(f, "f64"),
}
}
}
impl fmt::Display for VectorType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
VectorType::V128(lane) => write!(f, "v128<{lane}>"),
VectorType::V256(lane) => write!(f, "v256<{lane}>"),
}
}
}
impl fmt::Display for MirType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MirType::Scalar(s) => write!(f, "{s}"),
MirType::Vector(v) => write!(f, "{v}"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pointer_spaces_preserve_layout() {
for space in [
AddressSpace::Generic,
AddressSpace::Global,
AddressSpace::Region,
AddressSpace::Local,
AddressSpace::Constant,
AddressSpace::Private,
AddressSpace::Parameter,
] {
let ty = MirType::ptr_in(space);
assert_eq!(
ty.size_bytes(PointerWidth::Bits64),
MirType::Scalar(ScalarType::Ptr).size_bytes(PointerWidth::Bits64)
);
assert_eq!(
ty.alignment(PointerWidth::Bits64),
MirType::Scalar(ScalarType::Ptr).alignment(PointerWidth::Bits64)
);
}
assert_ne!(
MirType::ptr_in(AddressSpace::Global),
MirType::ptr_in(AddressSpace::Local)
);
}
#[test]
fn test_scalar_sizes() {
let w = PointerWidth::Bits64;
assert_eq!(MirType::Scalar(ScalarType::I8).size_bytes(w), 1);
assert_eq!(MirType::Scalar(ScalarType::I32).size_bytes(w), 4);
assert_eq!(MirType::Scalar(ScalarType::I64).size_bytes(w), 8);
}
#[test]
fn pointer_size_and_alignment_follow_pointer_width() {
for ty in [
MirType::Scalar(ScalarType::Ptr),
MirType::ptr_in(AddressSpace::Local),
] {
assert_eq!(ty.size_bytes(PointerWidth::Bits32), 4);
assert_eq!(ty.alignment(PointerWidth::Bits32), 4);
assert_eq!(ty.size_bytes(PointerWidth::Bits64), 8);
assert_eq!(ty.alignment(PointerWidth::Bits64), 8);
}
assert_eq!(
MirType::Scalar(ScalarType::I64).size_bytes(PointerWidth::Bits32),
8
);
assert_eq!(
MirType::Scalar(ScalarType::I64).alignment(PointerWidth::Bits32),
8
);
}
#[test]
fn test_vector_sizes() {
assert_eq!(
MirType::Vector(VectorType::V128(VectorLane::I32)).size_bytes(PointerWidth::Bits64),
16
);
assert_eq!(
MirType::Vector(VectorType::V256(VectorLane::F64)).size_bytes(PointerWidth::Bits64),
32
);
}
#[test]
fn test_float_detection() {
assert!(MirType::Scalar(ScalarType::F32).is_float());
assert!(MirType::Scalar(ScalarType::F64).is_float());
assert!(!MirType::Scalar(ScalarType::I32).is_float());
}
}