Skip to content

Commit efd0ea5

Browse files
committed
Parse data-layout specifications.
1 parent 0776399 commit efd0ea5

File tree

3 files changed

+255
-0
lines changed

3 files changed

+255
-0
lines changed

src/librustc/ty/context.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use hir::FreevarMap;
3131
use ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, TraitTy};
3232
use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
3333
use ty::TypeVariants::*;
34+
use ty::layout::TargetDataLayout;
3435
use ty::maps;
3536
use util::common::MemoizationMap;
3637
use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
@@ -419,6 +420,9 @@ pub struct TyCtxt<'tcx> {
419420
/// The definite name of the current crate after taking into account
420421
/// attributes, commandline parameters, etc.
421422
pub crate_name: token::InternedString,
423+
424+
/// Data layout specification for the current target.
425+
pub data_layout: TargetDataLayout,
422426
}
423427

424428
impl<'tcx> TyCtxt<'tcx> {
@@ -531,6 +535,7 @@ impl<'tcx> TyCtxt<'tcx> {
531535
f: F) -> R
532536
where F: FnOnce(&TyCtxt<'tcx>) -> R
533537
{
538+
let data_layout = TargetDataLayout::parse(s);
534539
let interner = RefCell::new(FnvHashMap());
535540
let common_types = CommonTypes::new(&arenas.type_, &interner);
536541
let dep_graph = map.dep_graph.clone();
@@ -589,6 +594,7 @@ impl<'tcx> TyCtxt<'tcx> {
589594
cast_kinds: RefCell::new(NodeMap()),
590595
fragment_infos: RefCell::new(DefIdMap()),
591596
crate_name: token::intern_and_get_ident(crate_name),
597+
data_layout: data_layout,
592598
}, f)
593599
}
594600
}

src/librustc/ty/layout.rs

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use session::Session;
12+
13+
use std::cmp;
14+
15+
/// Parsed [Data layout](http://llvm.org/docs/LangRef.html#data-layout)
16+
/// for a target, which contains everything needed to compute layouts.
17+
pub struct TargetDataLayout {
18+
pub endian: Endian,
19+
pub i1_align: Align,
20+
pub i8_align: Align,
21+
pub i16_align: Align,
22+
pub i32_align: Align,
23+
pub i64_align: Align,
24+
pub f32_align: Align,
25+
pub f64_align: Align,
26+
pub pointer_size: Size,
27+
pub pointer_align: Align,
28+
pub aggregate_align: Align,
29+
30+
/// Alignments for vector types, sorted by size.
31+
pub vector_align: Vec<(Size, Align)>
32+
}
33+
34+
impl Default for TargetDataLayout {
35+
fn default() -> TargetDataLayout {
36+
TargetDataLayout {
37+
endian: Endian::Big,
38+
i1_align: Align::from_bits(8, 8).unwrap(),
39+
i8_align: Align::from_bits(8, 8).unwrap(),
40+
i16_align: Align::from_bits(16, 16).unwrap(),
41+
i32_align: Align::from_bits(32, 32).unwrap(),
42+
i64_align: Align::from_bits(32, 64).unwrap(),
43+
f32_align: Align::from_bits(32, 32).unwrap(),
44+
f64_align: Align::from_bits(64, 64).unwrap(),
45+
pointer_size: Size::from_bits(64),
46+
pointer_align: Align::from_bits(64, 64).unwrap(),
47+
aggregate_align: Align::from_bits(0, 64).unwrap(),
48+
vector_align: vec![(Size::from_bits(128),
49+
Align::from_bits(128, 128).unwrap())]
50+
}
51+
}
52+
}
53+
54+
impl TargetDataLayout {
55+
pub fn parse(sess: &Session) -> TargetDataLayout {
56+
// Parse a bit count from a string.
57+
let parse_bits = |s: &str, kind: &str, cause: &str| {
58+
s.parse::<u64>().unwrap_or_else(|err| {
59+
sess.err(&format!("invalid {} `{}` for `{}` in \"data-layout\": {}",
60+
kind, s, cause, err));
61+
0
62+
})
63+
};
64+
65+
// Parse a size string.
66+
let size = |s: &str, cause: &str| {
67+
Size::from_bits(parse_bits(s, "size", cause))
68+
};
69+
70+
// Parse an alignment string.
71+
let align = |s: &[&str], cause: &str| {
72+
if s.is_empty() {
73+
sess.err(&format!("missing alignment for `{}` in \"data-layout\"", cause));
74+
}
75+
let abi = parse_bits(s[0], "alignment", cause);
76+
let pref = s.get(1).map_or(abi, |pref| parse_bits(pref, "alignment", cause));
77+
Align::from_bits(abi, pref).unwrap_or_else(|err| {
78+
sess.err(&format!("invalid alignment for `{}` in \"data-layout\": {}",
79+
cause, err));
80+
Align::from_bits(8, 8).unwrap()
81+
})
82+
};
83+
84+
let mut dl = TargetDataLayout::default();
85+
for spec in sess.target.target.data_layout.split("-") {
86+
match &spec.split(":").collect::<Vec<_>>()[..] {
87+
["e"] => dl.endian = Endian::Little,
88+
["E"] => dl.endian = Endian::Big,
89+
["a", a..] => dl.aggregate_align = align(a, "a"),
90+
["f32", a..] => dl.f32_align = align(a, "f32"),
91+
["f64", a..] => dl.f64_align = align(a, "f64"),
92+
[p @ "p", s, a..] | [p @ "p0", s, a..] => {
93+
dl.pointer_size = size(s, p);
94+
dl.pointer_align = align(a, p);
95+
}
96+
[s, a..] if s.starts_with("i") => {
97+
let ty_align = match s[1..].parse::<u64>() {
98+
Ok(1) => &mut dl.i8_align,
99+
Ok(8) => &mut dl.i8_align,
100+
Ok(16) => &mut dl.i16_align,
101+
Ok(32) => &mut dl.i32_align,
102+
Ok(64) => &mut dl.i64_align,
103+
Ok(_) => continue,
104+
Err(_) => {
105+
size(&s[1..], "i"); // For the user error.
106+
continue;
107+
}
108+
};
109+
*ty_align = align(a, s);
110+
}
111+
[s, a..] if s.starts_with("v") => {
112+
let v_size = size(&s[1..], "v");
113+
let a = align(a, s);
114+
if let Some(v) = dl.vector_align.iter_mut().find(|v| v.0 == v_size) {
115+
v.1 = a;
116+
continue;
117+
}
118+
// No existing entry, add a new one.
119+
dl.vector_align.push((v_size, a));
120+
}
121+
_ => {} // Ignore everything else.
122+
}
123+
}
124+
125+
// Sort vector alignments by size.
126+
dl.vector_align.sort_by_key(|&(s, _)| s);
127+
128+
// Perform consistency checks against the Target information.
129+
let endian_str = match dl.endian {
130+
Endian::Little => "little",
131+
Endian::Big => "big"
132+
};
133+
if endian_str != sess.target.target.target_endian {
134+
sess.err(&format!("inconsistent target specification: \"data-layout\" claims \
135+
architecture is {}-endian, while \"target-endian\" is `{}`",
136+
endian_str, sess.target.target.target_endian));
137+
}
138+
139+
if dl.pointer_size.bits().to_string() != sess.target.target.target_pointer_width {
140+
sess.err(&format!("inconsistent target specification: \"data-layout\" claims \
141+
pointers are {}-bit, while \"target-pointer-width\" is `{}`",
142+
dl.pointer_size.bits(), sess.target.target.target_pointer_width));
143+
}
144+
145+
dl
146+
}
147+
}
148+
149+
/// Endianness of the target, which must match cfg(target-endian).
150+
#[derive(Copy, Clone)]
151+
pub enum Endian {
152+
Little,
153+
Big
154+
}
155+
156+
/// Size of a type in bytes.
157+
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
158+
pub struct Size {
159+
raw: u64
160+
}
161+
162+
impl Size {
163+
pub fn from_bits(bits: u64) -> Size {
164+
Size::from_bytes((bits + 7) / 8)
165+
}
166+
167+
pub fn from_bytes(bytes: u64) -> Size {
168+
if bytes >= (1 << 61) {
169+
bug!("Size::from_bytes: {} bytes in bits doesn't fit in u64", bytes)
170+
}
171+
Size {
172+
raw: bytes
173+
}
174+
}
175+
176+
pub fn bytes(self) -> u64 {
177+
self.raw
178+
}
179+
180+
pub fn bits(self) -> u64 {
181+
self.bytes() * 8
182+
}
183+
}
184+
185+
/// Alignment of a type in bytes, both ABI-mandated and preferred.
186+
/// Since alignments are always powers of 2, we can pack both in one byte,
187+
/// giving each a nibble (4 bits) for a maximum alignment of 2^15 = 32768.
188+
#[derive(Copy, Clone)]
189+
pub struct Align {
190+
raw: u8
191+
}
192+
193+
impl Align {
194+
pub fn from_bits(abi: u64, pref: u64) -> Result<Align, String> {
195+
Align::from_bytes((abi + 7) / 8, (pref + 7) / 8)
196+
}
197+
198+
pub fn from_bytes(abi: u64, pref: u64) -> Result<Align, String> {
199+
let pack = |align: u64| {
200+
// Treat an alignment of 0 bytes like 1-byte alignment.
201+
if align == 0 {
202+
return Ok(0);
203+
}
204+
205+
let mut bytes = align;
206+
let mut pow: u8 = 0;
207+
while (bytes & 1) == 0 {
208+
pow += 1;
209+
bytes >>= 1;
210+
}
211+
if bytes != 1 {
212+
Err(format!("`{}` is not a power of 2", align))
213+
} else if pow > 0x0f {
214+
Err(format!("`{}` is too large", align))
215+
} else {
216+
Ok(pow)
217+
}
218+
};
219+
220+
Ok(Align {
221+
raw: pack(abi)? | (pack(pref)? << 4)
222+
})
223+
}
224+
225+
pub fn abi(self) -> u64 {
226+
1 << (self.raw & 0xf)
227+
}
228+
229+
pub fn pref(self) -> u64 {
230+
1 << (self.raw >> 4)
231+
}
232+
233+
pub fn min(self, other: Align) -> Align {
234+
let abi = cmp::min(self.raw & 0x0f, other.raw & 0x0f);
235+
let pref = cmp::min(self.raw & 0xf0, other.raw & 0xf0);
236+
Align {
237+
raw: abi | pref
238+
}
239+
}
240+
241+
pub fn max(self, other: Align) -> Align {
242+
let abi = cmp::max(self.raw & 0x0f, other.raw & 0x0f);
243+
let pref = cmp::max(self.raw & 0xf0, other.raw & 0xf0);
244+
Align {
245+
raw: abi | pref
246+
}
247+
}
248+
}

src/librustc/ty/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ pub mod error;
8484
pub mod fast_reject;
8585
pub mod fold;
8686
pub mod item_path;
87+
pub mod layout;
8788
pub mod _match;
8889
pub mod maps;
8990
pub mod outlives;

0 commit comments

Comments
 (0)