Extract llvm datalayout parsing out of spec module
This commit is contained in:
parent
90711a86e5
commit
56126fb149
@ -211,6 +211,102 @@ pub enum TargetDataLayoutErrors<'a> {
|
||||
}
|
||||
|
||||
impl TargetDataLayout {
|
||||
/// Parse data layout from an [llvm data layout string](https://llvm.org/docs/LangRef.html#data-layout)
|
||||
///
|
||||
/// This function doesn't fill `c_enum_min_size` and it will always be `I32` since it can not be
|
||||
/// determined from llvm string.
|
||||
pub fn parse_from_llvm_datalayout_string<'a>(
|
||||
input: &'a str,
|
||||
) -> Result<TargetDataLayout, TargetDataLayoutErrors<'a>> {
|
||||
// Parse an address space index from a string.
|
||||
let parse_address_space = |s: &'a str, cause: &'a str| {
|
||||
s.parse::<u32>().map(AddressSpace).map_err(|err| {
|
||||
TargetDataLayoutErrors::InvalidAddressSpace { addr_space: s, cause, err }
|
||||
})
|
||||
};
|
||||
|
||||
// Parse a bit count from a string.
|
||||
let parse_bits = |s: &'a str, kind: &'a str, cause: &'a str| {
|
||||
s.parse::<u64>().map_err(|err| TargetDataLayoutErrors::InvalidBits {
|
||||
kind,
|
||||
bit: s,
|
||||
cause,
|
||||
err,
|
||||
})
|
||||
};
|
||||
|
||||
// Parse a size string.
|
||||
let size = |s: &'a str, cause: &'a str| parse_bits(s, "size", cause).map(Size::from_bits);
|
||||
|
||||
// Parse an alignment string.
|
||||
let align = |s: &[&'a str], cause: &'a str| {
|
||||
if s.is_empty() {
|
||||
return Err(TargetDataLayoutErrors::MissingAlignment { cause });
|
||||
}
|
||||
let align_from_bits = |bits| {
|
||||
Align::from_bits(bits)
|
||||
.map_err(|err| TargetDataLayoutErrors::InvalidAlignment { 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 input.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 Ok(bits) = s[1..].parse::<u64>() else {
|
||||
size(&s[1..], "i")?; // For the user error.
|
||||
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 {
|
||||
// Default alignment for i128 is decided by taking the alignment of
|
||||
// largest-sized i{64..=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;
|
||||
}
|
||||
// No existing entry, add a new one.
|
||||
dl.vector_align.push((v_size, a));
|
||||
}
|
||||
_ => {} // Ignore everything else.
|
||||
}
|
||||
}
|
||||
Ok(dl)
|
||||
}
|
||||
|
||||
/// Returns exclusive upper bound on object size.
|
||||
///
|
||||
/// The theoretical maximum object size is defined as the maximum positive `isize` value.
|
||||
|
@ -35,10 +35,7 @@
|
||||
//! to the list specified by the target, rather than replace.
|
||||
|
||||
use crate::abi::call::Conv;
|
||||
use crate::abi::{
|
||||
AbiAndPrefAlign, AddressSpace, Align, Endian, Integer, Size, TargetDataLayout,
|
||||
TargetDataLayoutErrors,
|
||||
};
|
||||
use crate::abi::{Endian, Integer, Size, TargetDataLayout, TargetDataLayoutErrors};
|
||||
use crate::json::{Json, ToJson};
|
||||
use crate::spec::abi::{lookup as lookup_abi, Abi};
|
||||
use crate::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault};
|
||||
@ -1322,92 +1319,7 @@ pub struct Target {
|
||||
|
||||
impl Target {
|
||||
pub fn parse_data_layout<'a>(&'a self) -> Result<TargetDataLayout, TargetDataLayoutErrors<'a>> {
|
||||
// Parse an address space index from a string.
|
||||
let parse_address_space = |s: &'a str, cause: &'a str| {
|
||||
s.parse::<u32>().map(AddressSpace).map_err(|err| {
|
||||
TargetDataLayoutErrors::InvalidAddressSpace { addr_space: s, cause, err }
|
||||
})
|
||||
};
|
||||
|
||||
// Parse a bit count from a string.
|
||||
let parse_bits = |s: &'a str, kind: &'a str, cause: &'a str| {
|
||||
s.parse::<u64>().map_err(|err| TargetDataLayoutErrors::InvalidBits {
|
||||
kind,
|
||||
bit: s,
|
||||
cause,
|
||||
err,
|
||||
})
|
||||
};
|
||||
|
||||
// Parse a size string.
|
||||
let size = |s: &'a str, cause: &'a str| parse_bits(s, "size", cause).map(Size::from_bits);
|
||||
|
||||
// Parse an alignment string.
|
||||
let align = |s: &[&'a str], cause: &'a str| {
|
||||
if s.is_empty() {
|
||||
return Err(TargetDataLayoutErrors::MissingAlignment { cause });
|
||||
}
|
||||
let align_from_bits = |bits| {
|
||||
Align::from_bits(bits)
|
||||
.map_err(|err| TargetDataLayoutErrors::InvalidAlignment { 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 self.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 Ok(bits) = s[1..].parse::<u64>() else {
|
||||
size(&s[1..], "i")?; // For the user error.
|
||||
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 {
|
||||
// Default alignment for i128 is decided by taking the alignment of
|
||||
// largest-sized i{64..=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;
|
||||
}
|
||||
// No existing entry, add a new one.
|
||||
dl.vector_align.push((v_size, a));
|
||||
}
|
||||
_ => {} // Ignore everything else.
|
||||
}
|
||||
}
|
||||
let mut dl = TargetDataLayout::parse_from_llvm_datalayout_string(&self.data_layout)?;
|
||||
|
||||
// Perform consistency checks against the Target information.
|
||||
if dl.endian != self.endian {
|
||||
|
Loading…
x
Reference in New Issue
Block a user