rustc_trans: approximate ABI alignment for padding/union fillers.
This commit is contained in:
parent
84feab34e4
commit
8a26e0422d
|
@ -489,14 +489,27 @@ impl<'a, 'tcx> Integer {
|
||||||
|
|
||||||
let wanted = align.abi();
|
let wanted = align.abi();
|
||||||
for &candidate in &[I8, I16, I32, I64, I128] {
|
for &candidate in &[I8, I16, I32, I64, I128] {
|
||||||
let ty = Int(candidate, false);
|
if wanted == candidate.align(dl).abi() && wanted == candidate.size().bytes() {
|
||||||
if wanted == ty.align(dl).abi() && wanted == ty.size(dl).bytes() {
|
|
||||||
return Some(candidate);
|
return Some(candidate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Find the largest integer with the given alignment or less.
|
||||||
|
pub fn approximate_abi_align<C: HasDataLayout>(cx: C, align: Align) -> Integer {
|
||||||
|
let dl = cx.data_layout();
|
||||||
|
|
||||||
|
let wanted = align.abi();
|
||||||
|
// FIXME(eddyb) maybe include I128 in the future, when it works everywhere.
|
||||||
|
for &candidate in &[I64, I32, I16] {
|
||||||
|
if wanted >= candidate.align(dl).abi() && wanted >= candidate.size().bytes() {
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
I8
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the Integer type from an attr::IntType.
|
/// Get the Integer type from an attr::IntType.
|
||||||
pub fn from_attr<C: HasDataLayout>(cx: C, ity: attr::IntType) -> Integer {
|
pub fn from_attr<C: HasDataLayout>(cx: C, ity: attr::IntType) -> Integer {
|
||||||
let dl = cx.data_layout();
|
let dl = cx.data_layout();
|
||||||
|
|
|
@ -17,7 +17,7 @@ use llvm::{Float, Double, X86_FP80, PPC_FP128, FP128};
|
||||||
use context::CrateContext;
|
use context::CrateContext;
|
||||||
|
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use rustc::ty::layout::{self, Align};
|
use rustc::ty::layout::{self, Align, Size};
|
||||||
|
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -279,12 +279,19 @@ impl Type {
|
||||||
/// Return a LLVM type that has at most the required alignment,
|
/// Return a LLVM type that has at most the required alignment,
|
||||||
/// as a conservative approximation for unknown pointee types.
|
/// as a conservative approximation for unknown pointee types.
|
||||||
pub fn pointee_for_abi_align(ccx: &CrateContext, align: Align) -> Type {
|
pub fn pointee_for_abi_align(ccx: &CrateContext, align: Align) -> Type {
|
||||||
if let Some(ity) = layout::Integer::for_abi_align(ccx, align) {
|
// FIXME(eddyb) We could find a better approximation if ity.align < align.
|
||||||
Type::from_integer(ccx, ity)
|
let ity = layout::Integer::approximate_abi_align(ccx, align);
|
||||||
} else {
|
Type::from_integer(ccx, ity)
|
||||||
// FIXME(eddyb) We could find a better approximation here.
|
}
|
||||||
Type::i8(ccx)
|
|
||||||
}
|
/// Return a LLVM type that has at most the required alignment,
|
||||||
|
/// and exactly the required size, as a best-effort padding array.
|
||||||
|
pub fn padding_filler(ccx: &CrateContext, size: Size, align: Align) -> Type {
|
||||||
|
let unit = layout::Integer::approximate_abi_align(ccx, align);
|
||||||
|
let size = size.bytes();
|
||||||
|
let unit_size = unit.size().bytes();
|
||||||
|
assert_eq!(size % unit_size, 0);
|
||||||
|
Type::array(&Type::from_integer(ccx, unit), size / unit_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn x86_mmx(ccx: &CrateContext) -> Type {
|
pub fn x86_mmx(ccx: &CrateContext) -> Type {
|
||||||
|
|
|
@ -78,8 +78,7 @@ fn uncached_llvm_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||||
|
|
||||||
match layout.fields {
|
match layout.fields {
|
||||||
layout::FieldPlacement::Union(_) => {
|
layout::FieldPlacement::Union(_) => {
|
||||||
let size = layout.size.bytes();
|
let fill = Type::padding_filler(ccx, layout.size, layout.align);
|
||||||
let fill = Type::array(&Type::i8(ccx), size);
|
|
||||||
match name {
|
match name {
|
||||||
None => {
|
None => {
|
||||||
Type::struct_(ccx, &[fill], layout.is_packed())
|
Type::struct_(ccx, &[fill], layout.is_packed())
|
||||||
|
@ -115,6 +114,7 @@ fn struct_llfields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||||
let field_count = layout.fields.count();
|
let field_count = layout.fields.count();
|
||||||
|
|
||||||
let mut offset = Size::from_bytes(0);
|
let mut offset = Size::from_bytes(0);
|
||||||
|
let mut prev_align = layout.align;
|
||||||
let mut result: Vec<Type> = Vec::with_capacity(1 + field_count * 2);
|
let mut result: Vec<Type> = Vec::with_capacity(1 + field_count * 2);
|
||||||
for i in layout.fields.index_by_increasing_offset() {
|
for i in layout.fields.index_by_increasing_offset() {
|
||||||
let field = layout.field(ccx, i);
|
let field = layout.field(ccx, i);
|
||||||
|
@ -123,7 +123,9 @@ fn struct_llfields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||||
i, field, offset, target_offset);
|
i, field, offset, target_offset);
|
||||||
assert!(target_offset >= offset);
|
assert!(target_offset >= offset);
|
||||||
let padding = target_offset - offset;
|
let padding = target_offset - offset;
|
||||||
result.push(Type::array(&Type::i8(ccx), padding.bytes()));
|
let padding_align = layout.align.min(prev_align).min(field.align);
|
||||||
|
assert_eq!(offset.abi_align(padding_align) + padding, target_offset);
|
||||||
|
result.push(Type::padding_filler(ccx, padding, padding_align));
|
||||||
debug!(" padding before: {:?}", padding);
|
debug!(" padding before: {:?}", padding);
|
||||||
|
|
||||||
result.push(field.llvm_type(ccx));
|
result.push(field.llvm_type(ccx));
|
||||||
|
@ -137,6 +139,7 @@ fn struct_llfields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
offset = target_offset + field.size;
|
offset = target_offset + field.size;
|
||||||
|
prev_align = field.align;
|
||||||
}
|
}
|
||||||
if !layout.is_unsized() && field_count > 0 {
|
if !layout.is_unsized() && field_count > 0 {
|
||||||
if offset > layout.size {
|
if offset > layout.size {
|
||||||
|
@ -144,9 +147,11 @@ fn struct_llfields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||||
layout, layout.size, offset);
|
layout, layout.size, offset);
|
||||||
}
|
}
|
||||||
let padding = layout.size - offset;
|
let padding = layout.size - offset;
|
||||||
|
let padding_align = layout.align.min(prev_align);
|
||||||
|
assert_eq!(offset.abi_align(padding_align) + padding, layout.size);
|
||||||
debug!("struct_llfields: pad_bytes: {:?} offset: {:?} stride: {:?}",
|
debug!("struct_llfields: pad_bytes: {:?} offset: {:?} stride: {:?}",
|
||||||
padding, offset, layout.size);
|
padding, offset, layout.size);
|
||||||
result.push(Type::array(&Type::i8(ccx), padding.bytes()));
|
result.push(Type::padding_filler(ccx, padding, padding_align));
|
||||||
assert!(result.len() == 1 + field_count * 2);
|
assert!(result.len() == 1 + field_count * 2);
|
||||||
} else {
|
} else {
|
||||||
debug!("struct_llfields: offset: {:?} stride: {:?}",
|
debug!("struct_llfields: offset: {:?} stride: {:?}",
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// compile-flags: -C no-prepopulate-passes
|
// compile-flags: -C no-prepopulate-passes
|
||||||
|
// ignore-tidy-linelength
|
||||||
|
|
||||||
#![crate_type = "lib"]
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
#![feature(attr_literals)]
|
#![feature(attr_literals)]
|
||||||
|
@ -16,6 +18,7 @@
|
||||||
|
|
||||||
#[repr(align(64))]
|
#[repr(align(64))]
|
||||||
pub struct Align64(i32);
|
pub struct Align64(i32);
|
||||||
|
// CHECK: %Align64 = type { [0 x i32], i32, [15 x i32] }
|
||||||
|
|
||||||
pub struct Nested64 {
|
pub struct Nested64 {
|
||||||
a: Align64,
|
a: Align64,
|
||||||
|
@ -23,11 +26,20 @@ pub struct Nested64 {
|
||||||
c: i32,
|
c: i32,
|
||||||
d: i8,
|
d: i8,
|
||||||
}
|
}
|
||||||
|
// CHECK: %Nested64 = type { [0 x i64], %Align64, [0 x i32], i32, [0 x i32], i32, [0 x i8], i8, [55 x i8] }
|
||||||
|
|
||||||
|
pub enum Enum4 {
|
||||||
|
A(i32),
|
||||||
|
B(i32),
|
||||||
|
}
|
||||||
|
// CHECK: %Enum4 = type { [2 x i32] }
|
||||||
|
|
||||||
pub enum Enum64 {
|
pub enum Enum64 {
|
||||||
A(Align64),
|
A(Align64),
|
||||||
B(i32),
|
B(i32),
|
||||||
}
|
}
|
||||||
|
// CHECK: %Enum64 = type { [16 x i64] }
|
||||||
|
// CHECK: %"Enum64::A" = type { [8 x i64], %Align64, [0 x i64] }
|
||||||
|
|
||||||
// CHECK-LABEL: @align64
|
// CHECK-LABEL: @align64
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -46,6 +58,14 @@ pub fn nested64(a: Align64, b: i32, c: i32, d: i8) -> Nested64 {
|
||||||
n64
|
n64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @enum4
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn enum4(a: i32) -> Enum4 {
|
||||||
|
// CHECK: %e4 = alloca %Enum4, align 4
|
||||||
|
let e4 = Enum4::A(a);
|
||||||
|
e4
|
||||||
|
}
|
||||||
|
|
||||||
// CHECK-LABEL: @enum64
|
// CHECK-LABEL: @enum64
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn enum64(a: Align64) -> Enum64 {
|
pub fn enum64(a: Align64) -> Enum64 {
|
||||||
|
|
Loading…
Reference in New Issue