Skip to content

Commit 8a26e04

Browse files
committed
rustc_trans: approximate ABI alignment for padding/union fillers.
1 parent 84feab3 commit 8a26e04

File tree

4 files changed

+58
-13
lines changed

4 files changed

+58
-13
lines changed

src/librustc/ty/layout.rs

+15-2
Original file line numberDiff line numberDiff line change
@@ -489,14 +489,27 @@ impl<'a, 'tcx> Integer {
489489

490490
let wanted = align.abi();
491491
for &candidate in &[I8, I16, I32, I64, I128] {
492-
let ty = Int(candidate, false);
493-
if wanted == ty.align(dl).abi() && wanted == ty.size(dl).bytes() {
492+
if wanted == candidate.align(dl).abi() && wanted == candidate.size().bytes() {
494493
return Some(candidate);
495494
}
496495
}
497496
None
498497
}
499498

499+
/// Find the largest integer with the given alignment or less.
500+
pub fn approximate_abi_align<C: HasDataLayout>(cx: C, align: Align) -> Integer {
501+
let dl = cx.data_layout();
502+
503+
let wanted = align.abi();
504+
// FIXME(eddyb) maybe include I128 in the future, when it works everywhere.
505+
for &candidate in &[I64, I32, I16] {
506+
if wanted >= candidate.align(dl).abi() && wanted >= candidate.size().bytes() {
507+
return candidate;
508+
}
509+
}
510+
I8
511+
}
512+
500513
/// Get the Integer type from an attr::IntType.
501514
pub fn from_attr<C: HasDataLayout>(cx: C, ity: attr::IntType) -> Integer {
502515
let dl = cx.data_layout();

src/librustc_trans/type_.rs

+14-7
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use llvm::{Float, Double, X86_FP80, PPC_FP128, FP128};
1717
use context::CrateContext;
1818

1919
use syntax::ast;
20-
use rustc::ty::layout::{self, Align};
20+
use rustc::ty::layout::{self, Align, Size};
2121

2222
use std::ffi::CString;
2323
use std::fmt;
@@ -279,12 +279,19 @@ impl Type {
279279
/// Return a LLVM type that has at most the required alignment,
280280
/// as a conservative approximation for unknown pointee types.
281281
pub fn pointee_for_abi_align(ccx: &CrateContext, align: Align) -> Type {
282-
if let Some(ity) = layout::Integer::for_abi_align(ccx, align) {
283-
Type::from_integer(ccx, ity)
284-
} else {
285-
// FIXME(eddyb) We could find a better approximation here.
286-
Type::i8(ccx)
287-
}
282+
// FIXME(eddyb) We could find a better approximation if ity.align < align.
283+
let ity = layout::Integer::approximate_abi_align(ccx, align);
284+
Type::from_integer(ccx, ity)
285+
}
286+
287+
/// Return a LLVM type that has at most the required alignment,
288+
/// and exactly the required size, as a best-effort padding array.
289+
pub fn padding_filler(ccx: &CrateContext, size: Size, align: Align) -> Type {
290+
let unit = layout::Integer::approximate_abi_align(ccx, align);
291+
let size = size.bytes();
292+
let unit_size = unit.size().bytes();
293+
assert_eq!(size % unit_size, 0);
294+
Type::array(&Type::from_integer(ccx, unit), size / unit_size)
288295
}
289296

290297
pub fn x86_mmx(ccx: &CrateContext) -> Type {

src/librustc_trans/type_of.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,7 @@ fn uncached_llvm_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
7878

7979
match layout.fields {
8080
layout::FieldPlacement::Union(_) => {
81-
let size = layout.size.bytes();
82-
let fill = Type::array(&Type::i8(ccx), size);
81+
let fill = Type::padding_filler(ccx, layout.size, layout.align);
8382
match name {
8483
None => {
8584
Type::struct_(ccx, &[fill], layout.is_packed())
@@ -115,6 +114,7 @@ fn struct_llfields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
115114
let field_count = layout.fields.count();
116115

117116
let mut offset = Size::from_bytes(0);
117+
let mut prev_align = layout.align;
118118
let mut result: Vec<Type> = Vec::with_capacity(1 + field_count * 2);
119119
for i in layout.fields.index_by_increasing_offset() {
120120
let field = layout.field(ccx, i);
@@ -123,7 +123,9 @@ fn struct_llfields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
123123
i, field, offset, target_offset);
124124
assert!(target_offset >= offset);
125125
let padding = target_offset - offset;
126-
result.push(Type::array(&Type::i8(ccx), padding.bytes()));
126+
let padding_align = layout.align.min(prev_align).min(field.align);
127+
assert_eq!(offset.abi_align(padding_align) + padding, target_offset);
128+
result.push(Type::padding_filler(ccx, padding, padding_align));
127129
debug!(" padding before: {:?}", padding);
128130

129131
result.push(field.llvm_type(ccx));
@@ -137,16 +139,19 @@ fn struct_llfields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
137139
}
138140

139141
offset = target_offset + field.size;
142+
prev_align = field.align;
140143
}
141144
if !layout.is_unsized() && field_count > 0 {
142145
if offset > layout.size {
143146
bug!("layout: {:#?} stride: {:?} offset: {:?}",
144147
layout, layout.size, offset);
145148
}
146149
let padding = layout.size - offset;
150+
let padding_align = layout.align.min(prev_align);
151+
assert_eq!(offset.abi_align(padding_align) + padding, layout.size);
147152
debug!("struct_llfields: pad_bytes: {:?} offset: {:?} stride: {:?}",
148153
padding, offset, layout.size);
149-
result.push(Type::array(&Type::i8(ccx), padding.bytes()));
154+
result.push(Type::padding_filler(ccx, padding, padding_align));
150155
assert!(result.len() == 1 + field_count * 2);
151156
} else {
152157
debug!("struct_llfields: offset: {:?} stride: {:?}",

src/test/codegen/align-struct.rs

+20
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,37 @@
99
// except according to those terms.
1010

1111
// compile-flags: -C no-prepopulate-passes
12+
// ignore-tidy-linelength
13+
1214
#![crate_type = "lib"]
1315

1416
#![feature(attr_literals)]
1517
#![feature(repr_align)]
1618

1719
#[repr(align(64))]
1820
pub struct Align64(i32);
21+
// CHECK: %Align64 = type { [0 x i32], i32, [15 x i32] }
1922

2023
pub struct Nested64 {
2124
a: Align64,
2225
b: i32,
2326
c: i32,
2427
d: i8,
2528
}
29+
// CHECK: %Nested64 = type { [0 x i64], %Align64, [0 x i32], i32, [0 x i32], i32, [0 x i8], i8, [55 x i8] }
30+
31+
pub enum Enum4 {
32+
A(i32),
33+
B(i32),
34+
}
35+
// CHECK: %Enum4 = type { [2 x i32] }
2636

2737
pub enum Enum64 {
2838
A(Align64),
2939
B(i32),
3040
}
41+
// CHECK: %Enum64 = type { [16 x i64] }
42+
// CHECK: %"Enum64::A" = type { [8 x i64], %Align64, [0 x i64] }
3143

3244
// CHECK-LABEL: @align64
3345
#[no_mangle]
@@ -46,6 +58,14 @@ pub fn nested64(a: Align64, b: i32, c: i32, d: i8) -> Nested64 {
4658
n64
4759
}
4860

61+
// CHECK-LABEL: @enum4
62+
#[no_mangle]
63+
pub fn enum4(a: i32) -> Enum4 {
64+
// CHECK: %e4 = alloca %Enum4, align 4
65+
let e4 = Enum4::A(a);
66+
e4
67+
}
68+
4969
// CHECK-LABEL: @enum64
5070
#[no_mangle]
5171
pub fn enum64(a: Align64) -> Enum64 {

0 commit comments

Comments
 (0)