Parse data-layout specifications.

This commit is contained in:
Eduard Burtescu 2016-04-18 16:03:16 +03:00
parent 0776399eac
commit efd0ea5b20
3 changed files with 255 additions and 0 deletions

View File

@ -31,6 +31,7 @@ use hir::FreevarMap;
use ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, TraitTy}; use ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, TraitTy};
use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid}; use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
use ty::TypeVariants::*; use ty::TypeVariants::*;
use ty::layout::TargetDataLayout;
use ty::maps; use ty::maps;
use util::common::MemoizationMap; use util::common::MemoizationMap;
use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet}; use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
@ -419,6 +420,9 @@ pub struct TyCtxt<'tcx> {
/// The definite name of the current crate after taking into account /// The definite name of the current crate after taking into account
/// attributes, commandline parameters, etc. /// attributes, commandline parameters, etc.
pub crate_name: token::InternedString, pub crate_name: token::InternedString,
/// Data layout specification for the current target.
pub data_layout: TargetDataLayout,
} }
impl<'tcx> TyCtxt<'tcx> { impl<'tcx> TyCtxt<'tcx> {
@ -531,6 +535,7 @@ impl<'tcx> TyCtxt<'tcx> {
f: F) -> R f: F) -> R
where F: FnOnce(&TyCtxt<'tcx>) -> R where F: FnOnce(&TyCtxt<'tcx>) -> R
{ {
let data_layout = TargetDataLayout::parse(s);
let interner = RefCell::new(FnvHashMap()); let interner = RefCell::new(FnvHashMap());
let common_types = CommonTypes::new(&arenas.type_, &interner); let common_types = CommonTypes::new(&arenas.type_, &interner);
let dep_graph = map.dep_graph.clone(); let dep_graph = map.dep_graph.clone();
@ -589,6 +594,7 @@ impl<'tcx> TyCtxt<'tcx> {
cast_kinds: RefCell::new(NodeMap()), cast_kinds: RefCell::new(NodeMap()),
fragment_infos: RefCell::new(DefIdMap()), fragment_infos: RefCell::new(DefIdMap()),
crate_name: token::intern_and_get_ident(crate_name), crate_name: token::intern_and_get_ident(crate_name),
data_layout: data_layout,
}, f) }, f)
} }
} }

248
src/librustc/ty/layout.rs Normal file
View File

@ -0,0 +1,248 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use session::Session;
use std::cmp;
/// Parsed [Data layout](http://llvm.org/docs/LangRef.html#data-layout)
/// for a target, which contains everything needed to compute layouts.
pub struct TargetDataLayout {
pub endian: Endian,
pub i1_align: Align,
pub i8_align: Align,
pub i16_align: Align,
pub i32_align: Align,
pub i64_align: Align,
pub f32_align: Align,
pub f64_align: Align,
pub pointer_size: Size,
pub pointer_align: Align,
pub aggregate_align: Align,
/// Alignments for vector types, sorted by size.
pub vector_align: Vec<(Size, Align)>
}
impl Default for TargetDataLayout {
fn default() -> TargetDataLayout {
TargetDataLayout {
endian: Endian::Big,
i1_align: Align::from_bits(8, 8).unwrap(),
i8_align: Align::from_bits(8, 8).unwrap(),
i16_align: Align::from_bits(16, 16).unwrap(),
i32_align: Align::from_bits(32, 32).unwrap(),
i64_align: Align::from_bits(32, 64).unwrap(),
f32_align: Align::from_bits(32, 32).unwrap(),
f64_align: Align::from_bits(64, 64).unwrap(),
pointer_size: Size::from_bits(64),
pointer_align: Align::from_bits(64, 64).unwrap(),
aggregate_align: Align::from_bits(0, 64).unwrap(),
vector_align: vec![(Size::from_bits(128),
Align::from_bits(128, 128).unwrap())]
}
}
}
impl TargetDataLayout {
pub fn parse(sess: &Session) -> TargetDataLayout {
// Parse a bit count from a string.
let parse_bits = |s: &str, kind: &str, cause: &str| {
s.parse::<u64>().unwrap_or_else(|err| {
sess.err(&format!("invalid {} `{}` for `{}` in \"data-layout\": {}",
kind, s, cause, err));
0
})
};
// Parse a size string.
let size = |s: &str, cause: &str| {
Size::from_bits(parse_bits(s, "size", cause))
};
// Parse an alignment string.
let align = |s: &[&str], cause: &str| {
if s.is_empty() {
sess.err(&format!("missing alignment for `{}` in \"data-layout\"", cause));
}
let abi = parse_bits(s[0], "alignment", cause);
let pref = s.get(1).map_or(abi, |pref| parse_bits(pref, "alignment", cause));
Align::from_bits(abi, pref).unwrap_or_else(|err| {
sess.err(&format!("invalid alignment for `{}` in \"data-layout\": {}",
cause, err));
Align::from_bits(8, 8).unwrap()
})
};
let mut dl = TargetDataLayout::default();
for spec in sess.target.target.data_layout.split("-") {
match &spec.split(":").collect::<Vec<_>>()[..] {
["e"] => dl.endian = Endian::Little,
["E"] => dl.endian = Endian::Big,
["a", a..] => dl.aggregate_align = align(a, "a"),
["f32", a..] => dl.f32_align = align(a, "f32"),
["f64", a..] => dl.f64_align = align(a, "f64"),
[p @ "p", s, a..] | [p @ "p0", s, a..] => {
dl.pointer_size = size(s, p);
dl.pointer_align = align(a, p);
}
[s, a..] if s.starts_with("i") => {
let ty_align = match s[1..].parse::<u64>() {
Ok(1) => &mut dl.i8_align,
Ok(8) => &mut dl.i8_align,
Ok(16) => &mut dl.i16_align,
Ok(32) => &mut dl.i32_align,
Ok(64) => &mut dl.i64_align,
Ok(_) => continue,
Err(_) => {
size(&s[1..], "i"); // For the user error.
continue;
}
};
*ty_align = align(a, s);
}
[s, 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.
}
}
// Sort vector alignments by size.
dl.vector_align.sort_by_key(|&(s, _)| s);
// Perform consistency checks against the Target information.
let endian_str = match dl.endian {
Endian::Little => "little",
Endian::Big => "big"
};
if endian_str != sess.target.target.target_endian {
sess.err(&format!("inconsistent target specification: \"data-layout\" claims \
architecture is {}-endian, while \"target-endian\" is `{}`",
endian_str, sess.target.target.target_endian));
}
if dl.pointer_size.bits().to_string() != sess.target.target.target_pointer_width {
sess.err(&format!("inconsistent target specification: \"data-layout\" claims \
pointers are {}-bit, while \"target-pointer-width\" is `{}`",
dl.pointer_size.bits(), sess.target.target.target_pointer_width));
}
dl
}
}
/// Endianness of the target, which must match cfg(target-endian).
#[derive(Copy, Clone)]
pub enum Endian {
Little,
Big
}
/// Size of a type in bytes.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Size {
raw: u64
}
impl Size {
pub fn from_bits(bits: u64) -> Size {
Size::from_bytes((bits + 7) / 8)
}
pub fn from_bytes(bytes: u64) -> Size {
if bytes >= (1 << 61) {
bug!("Size::from_bytes: {} bytes in bits doesn't fit in u64", bytes)
}
Size {
raw: bytes
}
}
pub fn bytes(self) -> u64 {
self.raw
}
pub fn bits(self) -> u64 {
self.bytes() * 8
}
}
/// Alignment of a type in bytes, both ABI-mandated and preferred.
/// Since alignments are always powers of 2, we can pack both in one byte,
/// giving each a nibble (4 bits) for a maximum alignment of 2^15 = 32768.
#[derive(Copy, Clone)]
pub struct Align {
raw: u8
}
impl Align {
pub fn from_bits(abi: u64, pref: u64) -> Result<Align, String> {
Align::from_bytes((abi + 7) / 8, (pref + 7) / 8)
}
pub fn from_bytes(abi: u64, pref: u64) -> Result<Align, String> {
let pack = |align: u64| {
// Treat an alignment of 0 bytes like 1-byte alignment.
if align == 0 {
return Ok(0);
}
let mut bytes = align;
let mut pow: u8 = 0;
while (bytes & 1) == 0 {
pow += 1;
bytes >>= 1;
}
if bytes != 1 {
Err(format!("`{}` is not a power of 2", align))
} else if pow > 0x0f {
Err(format!("`{}` is too large", align))
} else {
Ok(pow)
}
};
Ok(Align {
raw: pack(abi)? | (pack(pref)? << 4)
})
}
pub fn abi(self) -> u64 {
1 << (self.raw & 0xf)
}
pub fn pref(self) -> u64 {
1 << (self.raw >> 4)
}
pub fn min(self, other: Align) -> Align {
let abi = cmp::min(self.raw & 0x0f, other.raw & 0x0f);
let pref = cmp::min(self.raw & 0xf0, other.raw & 0xf0);
Align {
raw: abi | pref
}
}
pub fn max(self, other: Align) -> Align {
let abi = cmp::max(self.raw & 0x0f, other.raw & 0x0f);
let pref = cmp::max(self.raw & 0xf0, other.raw & 0xf0);
Align {
raw: abi | pref
}
}
}

View File

@ -84,6 +84,7 @@ pub mod error;
pub mod fast_reject; pub mod fast_reject;
pub mod fold; pub mod fold;
pub mod item_path; pub mod item_path;
pub mod layout;
pub mod _match; pub mod _match;
pub mod maps; pub mod maps;
pub mod outlives; pub mod outlives;