Skip to content
Permalink
Browse files

Intial implementation of repr struct alignment.

  • Loading branch information...
bitshifter committed Jan 14, 2017
1 parent 7789881 commit 19007861eff40a326f951e6b6159f9a2d7e8b0e3
@@ -22,6 +22,7 @@ use syntax::attr;
use syntax_pos::DUMMY_SP;
use rustc_i128::u128;
use rustc_const_math::ConstInt;
pub use rustc_data_structures::align::Align;

use std::cmp;
use std::fmt;
@@ -267,71 +268,6 @@ impl Size {
}
}

/// 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, PartialEq, Eq, Hash, Debug)]
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
}
}
}

/// Integers, also used for enum discriminants.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Integer {
@@ -477,6 +413,9 @@ impl Integer {
}
attr::ReprSimd => {
bug!("Integer::repr_discr: found #[repr(simd)] on enum `{}", ty);
},
attr::ReprAlign(_) => {
bug!("Integer::repr_discr: found #[repr(align)] on enum `{}", ty);
}
}
}
@@ -572,8 +511,20 @@ impl<'a, 'gcx, 'tcx> Struct {
reprs: &[attr::ReprAttr], kind: StructKind,
scapegoat: Ty<'gcx>) -> Result<Struct, LayoutError<'gcx>> {
let packed = reprs.contains(&attr::ReprPacked);
let align = if packed {
dl.i8_align
} else {
// TODO: bug if aligned used with packed
let mut max_align = dl.aggregate_align;
for r in reprs {
if let attr::ReprAlign(align) = *r {
max_align = max_align.max(align);
}
}
max_align
};
let mut ret = Struct {
align: if packed { dl.i8_align } else { dl.aggregate_align },
align: align,
packed: packed,
sized: true,
offsets: vec![],
@@ -593,7 +544,7 @@ impl<'a, 'gcx, 'tcx> Struct {
can_optimize = !reprs.iter().any(|r| {
match *r {
attr::ReprAny | attr::ReprInt(_) => false,
attr::ReprExtern | attr::ReprPacked => true,
attr::ReprExtern | attr::ReprPacked | attr::ReprAlign(_) => true,
attr::ReprSimd => bug!("Simd vectors should be represented as layout::Vector")
}
});
@@ -0,0 +1,77 @@
// 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 std::cmp;

/// 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, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
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
}
}
}

@@ -50,6 +50,7 @@ extern crate rustc_i128;

pub use rustc_serialize::hex::ToHex;

pub mod align;
pub mod array_vec;
pub mod accumulate_vec;
pub mod small_vec;
@@ -25,6 +25,7 @@ use feature_gate::{Features, GatedCfg};
use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
use parse::ParseSess;
use ptr::P;
use rustc_data_structures::align::Align;
use symbol::Symbol;
use util::ThinVec;

@@ -143,6 +144,16 @@ impl NestedMetaItem {
self.meta_item().and_then(|meta_item| meta_item.value_str())
}

/// Returns the name and value of the meta item as strings.
pub fn name_value_str(&self) -> Option<(Name, Symbol)> {
self.meta_item().and_then(|meta_item| if meta_item.is_value_str() {
Some((meta_item.name(), meta_item.value_str().unwrap()))
}
else {
None
})
}

/// Returns a MetaItem if self is a MetaItem with Kind Word.
pub fn word(&self) -> Option<&MetaItem> {
self.meta_item().and_then(|meta_item| if meta_item.is_word() {
@@ -877,7 +888,26 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr>
if let Some(h) = hint {
acc.push(h);
}
} else if let Some((name, value)) = item.name_value_str() {
if name == "align" {
use core::str::FromStr;
if let Ok(align) = u64::from_str(&*value.as_str()) {
if let Ok(align) = Align::from_bytes(align, align) {
acc.push(ReprAlign(align));
} else {
span_err!(diagnostic, item.span, E0561,
"alignment representation hint is not a power of two");
}
} else {
span_err!(diagnostic, item.span, E0560,
"alignment representation hint is not a u64");
}
} else {
span_err!(diagnostic, item.span, E0559,
"unrecognized representation hint name value");
}
} else {
println!("{:?}", item);
span_err!(diagnostic, item.span, E0553,
"unrecognized enum representation hint");
}
@@ -914,6 +944,7 @@ pub enum ReprAttr {
ReprExtern,
ReprPacked,
ReprSimd,
ReprAlign(Align),
}

impl ReprAttr {
@@ -924,6 +955,7 @@ impl ReprAttr {
ReprExtern => true,
ReprPacked => false,
ReprSimd => true,
ReprAlign(_) => false, // TODO: revisit this
}
}
}
@@ -202,4 +202,7 @@ register_diagnostics! {
E0555, // malformed feature attribute, expected #![feature(...)]
E0556, // malformed feature, expected just one word
E0557, // feature has been removed
E0559, // unrecognised representation hint name value
E0560, // align representation hint is not a u64
E0561, // align representation hint is not a power of two
}
@@ -774,7 +774,7 @@ fn find_repr_type_name(diagnostic: &Handler, type_attrs: &[ast::Attribute]) -> &
for a in type_attrs {
for r in &attr::find_repr_attrs(diagnostic, a) {
repr_type_name = match *r {
attr::ReprAny | attr::ReprPacked | attr::ReprSimd => continue,
attr::ReprAny | attr::ReprPacked | attr::ReprSimd | attr::ReprAlign(_) => continue,
attr::ReprExtern => "i32",

attr::ReprInt(attr::SignedInt(ast::IntTy::Is)) => "isize",

0 comments on commit 1900786

Please sign in to comment.
You can’t perform that action at this time.