mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-23 05:03:47 +00:00
Parse data-layout specifications.
This commit is contained in:
parent
0776399eac
commit
efd0ea5b20
@ -31,6 +31,7 @@ use hir::FreevarMap;
|
||||
use ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, TraitTy};
|
||||
use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
|
||||
use ty::TypeVariants::*;
|
||||
use ty::layout::TargetDataLayout;
|
||||
use ty::maps;
|
||||
use util::common::MemoizationMap;
|
||||
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
|
||||
/// attributes, commandline parameters, etc.
|
||||
pub crate_name: token::InternedString,
|
||||
|
||||
/// Data layout specification for the current target.
|
||||
pub data_layout: TargetDataLayout,
|
||||
}
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
@ -531,6 +535,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
f: F) -> R
|
||||
where F: FnOnce(&TyCtxt<'tcx>) -> R
|
||||
{
|
||||
let data_layout = TargetDataLayout::parse(s);
|
||||
let interner = RefCell::new(FnvHashMap());
|
||||
let common_types = CommonTypes::new(&arenas.type_, &interner);
|
||||
let dep_graph = map.dep_graph.clone();
|
||||
@ -589,6 +594,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
cast_kinds: RefCell::new(NodeMap()),
|
||||
fragment_infos: RefCell::new(DefIdMap()),
|
||||
crate_name: token::intern_and_get_ident(crate_name),
|
||||
data_layout: data_layout,
|
||||
}, f)
|
||||
}
|
||||
}
|
||||
|
248
src/librustc/ty/layout.rs
Normal file
248
src/librustc/ty/layout.rs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
@ -84,6 +84,7 @@ pub mod error;
|
||||
pub mod fast_reject;
|
||||
pub mod fold;
|
||||
pub mod item_path;
|
||||
pub mod layout;
|
||||
pub mod _match;
|
||||
pub mod maps;
|
||||
pub mod outlives;
|
||||
|
Loading…
Reference in New Issue
Block a user