|
| 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 | +} |
0 commit comments