mod align;
mod integer;
mod size;
use crate::spec::Target;
pub use align::Align;
pub use integer::Integer;
pub use size::Size;
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct TargetDataLayout {
pub endian: Endian,
pub i1_align: AbiAndPrefAlign,
pub i8_align: AbiAndPrefAlign,
pub i16_align: AbiAndPrefAlign,
pub i32_align: AbiAndPrefAlign,
pub i64_align: AbiAndPrefAlign,
pub i128_align: AbiAndPrefAlign,
pub f32_align: AbiAndPrefAlign,
pub f64_align: AbiAndPrefAlign,
pub pointer_size: Size,
pub pointer_align: AbiAndPrefAlign,
pub aggregate_align: AbiAndPrefAlign,
pub vector_align: Vec<(Size, AbiAndPrefAlign)>,
pub instruction_address_space: u32,
}
impl Default for TargetDataLayout {
fn default() -> TargetDataLayout {
let align = |bits| Align::from_bits(bits).unwrap();
TargetDataLayout {
endian: Endian::Big,
i1_align: AbiAndPrefAlign::new(align(8)),
i8_align: AbiAndPrefAlign::new(align(8)),
i16_align: AbiAndPrefAlign::new(align(16)),
i32_align: AbiAndPrefAlign::new(align(32)),
i64_align: AbiAndPrefAlign {
abi: align(32),
pref: align(64),
},
i128_align: AbiAndPrefAlign {
abi: align(32),
pref: align(64),
},
f32_align: AbiAndPrefAlign::new(align(32)),
f64_align: AbiAndPrefAlign::new(align(64)),
pointer_size: Size::from_bits(64),
pointer_align: AbiAndPrefAlign::new(align(64)),
aggregate_align: AbiAndPrefAlign {
abi: align(0),
pref: align(64),
},
vector_align: vec![
(Size::from_bits(64), AbiAndPrefAlign::new(align(64))),
(Size::from_bits(128), AbiAndPrefAlign::new(align(128))),
],
instruction_address_space: 0,
}
}
}
impl TargetDataLayout {
pub fn parse(target: &Target) -> Result<TargetDataLayout, String> {
let parse_address_space = |s: &str, cause: &str| {
s.parse::<u32>().map_err(|err| {
format!(
"invalid address space `{}` for `{}` in \"data-layout\": {}",
s, cause, err
)
})
};
let parse_bits = |s: &str, kind: &str, cause: &str| {
s.parse::<u64>().map_err(|err| {
format!(
"invalid {} `{}` for `{}` in \"data-layout\": {}",
kind, s, cause, err
)
})
};
let size = |s: &str, cause: &str| parse_bits(s, "size", cause).map(Size::from_bits);
let align = |s: &[&str], cause: &str| {
if s.is_empty() {
return Err(format!(
"missing alignment for `{}` in \"data-layout\"",
cause
));
}
let align_from_bits = |bits| {
Align::from_bits(bits).map_err(|err| {
format!(
"invalid alignment for `{}` in \"data-layout\": {}",
cause, err
)
})
};
let abi = parse_bits(s[0], "alignment", cause)?;
let pref = s
.get(1)
.map_or(Ok(abi), |pref| parse_bits(pref, "alignment", cause))?;
Ok(AbiAndPrefAlign {
abi: align_from_bits(abi)?,
pref: align_from_bits(pref)?,
})
};
let mut dl = TargetDataLayout::default();
let mut i128_align_src = 64;
for spec in target.data_layout.split('-') {
let spec_parts = spec.split(':').collect::<Vec<_>>();
match &*spec_parts {
["e"] => dl.endian = Endian::Little,
["E"] => dl.endian = Endian::Big,
[p] if p.starts_with('P') => {
dl.instruction_address_space = parse_address_space(&p[1..], "P")?
}
["a", ref a @ ..] => dl.aggregate_align = align(a, "a")?,
["f32", ref a @ ..] => dl.f32_align = align(a, "f32")?,
["f64", ref a @ ..] => dl.f64_align = align(a, "f64")?,
[p @ "p", s, ref a @ ..] | [p @ "p0", s, ref a @ ..] => {
dl.pointer_size = size(s, p)?;
dl.pointer_align = align(a, p)?;
}
[s, ref a @ ..] if s.starts_with('i') => {
let bits = match s[1..].parse::<u64>() {
Ok(bits) => bits,
Err(_) => {
size(&s[1..], "i")?;
continue;
}
};
let a = align(a, s)?;
match bits {
1 => dl.i1_align = a,
8 => dl.i8_align = a,
16 => dl.i16_align = a,
32 => dl.i32_align = a,
64 => dl.i64_align = a,
_ => {}
}
if bits >= i128_align_src && bits <= 128 {
i128_align_src = bits;
dl.i128_align = a;
}
}
[s, ref a @ ..] if s.starts_with('v') => {
let v_size = size(&s[1..], "v")?;
let a = align(a, s)?;
if let Some(v) = dl.vector_align.iter_mut().find(|v| v.0 == v_size) {
v.1 = a;
continue;
}
dl.vector_align.push((v_size, a));
}
_ => {}
}
}
let endian_str = match dl.endian {
Endian::Little => "little",
Endian::Big => "big",
};
if endian_str != target.target_endian {
return Err(format!(
"inconsistent target specification: \"data-layout\" claims \
architecture is {}-endian, while \"target-endian\" is `{}`",
endian_str, target.target_endian
));
}
if dl.pointer_size.bits().to_string() != target.target_pointer_width {
return Err(format!(
"inconsistent target specification: \"data-layout\" claims \
pointers are {}-bit, while \"target-pointer-width\" is `{}`",
dl.pointer_size.bits(),
target.target_pointer_width
));
}
Ok(dl)
}
pub fn ptr_sized_integer(&self) -> Integer {
use Integer::*;
match self.pointer_size.bits() {
16 => I16,
32 => I32,
64 => I64,
bits => panic!("ptr_sized_integer: unknown pointer bit size {}", bits),
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub enum Endian {
Little,
Big,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct AbiAndPrefAlign {
pub abi: Align,
pub pref: Align,
}
impl AbiAndPrefAlign {
pub fn new(align: Align) -> AbiAndPrefAlign {
AbiAndPrefAlign {
abi: align,
pref: align,
}
}
}