Skip to content

Commit

Permalink
librustc: implement a #[packed] attribute for structs.
Browse files Browse the repository at this point in the history
A struct (inc. tuple struct) can be annotated with #[packed], so that there
is no padding between its elements, like GCC's `__attribute__((packed))`.

Closes rust-lang#1704
  • Loading branch information
huonw committed Apr 10, 2013
1 parent 7222801 commit cad2260
Show file tree
Hide file tree
Showing 11 changed files with 150 additions and 71 deletions.
20 changes: 12 additions & 8 deletions src/librustc/middle/trans/adt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ pub enum Repr {
struct Struct {
size: u64,
align: u64,
packed: bool,
fields: ~[ty::t]
}

Expand All @@ -109,17 +110,18 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr {
}
let repr = @match ty::get(t).sty {
ty::ty_tup(ref elems) => {
Univariant(mk_struct(cx, *elems), false)
Univariant(mk_struct(cx, *elems, false), false)
}
ty::ty_struct(def_id, ref substs) => {
let fields = ty::lookup_struct_fields(cx.tcx, def_id);
let ftys = do fields.map |field| {
ty::lookup_field_type(cx.tcx, def_id, field.id, substs)
};
let packed = ty::lookup_packed(cx.tcx, def_id);
let dtor = ty::ty_dtor(cx.tcx, def_id).is_present();
let ftys =
if dtor { ftys + [ty::mk_bool(cx.tcx)] } else { ftys };
Univariant(mk_struct(cx, ftys), dtor)
Univariant(mk_struct(cx, ftys, packed), dtor)
}
ty::ty_enum(def_id, ref substs) => {
struct Case { discr: int, tys: ~[ty::t] };
Expand All @@ -132,15 +134,15 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr {
};
if cases.len() == 0 {
// Uninhabitable; represent as unit
Univariant(mk_struct(cx, ~[]), false)
Univariant(mk_struct(cx, ~[], false), false)
} else if cases.all(|c| c.tys.len() == 0) {
// All bodies empty -> intlike
let discrs = cases.map(|c| c.discr);
CEnum(discrs.min(), discrs.max())
} else if cases.len() == 1 {
// Equivalent to a struct/tuple/newtype.
assert!(cases[0].discr == 0);
Univariant(mk_struct(cx, cases[0].tys), false)
Univariant(mk_struct(cx, cases[0].tys, false), false)
} else {
// The general case. Since there's at least one
// non-empty body, explicit discriminants should have
Expand All @@ -151,7 +153,7 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr {
ty::item_path_str(cx.tcx, def_id)))
}
let discr = ~[ty::mk_int(cx.tcx)];
General(cases.map(|c| mk_struct(cx, discr + c.tys)))
General(cases.map(|c| mk_struct(cx, discr + c.tys, false)))
}
}
_ => cx.sess.bug(~"adt::represent_type called on non-ADT type")
Expand All @@ -160,12 +162,13 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr {
return repr;
}

fn mk_struct(cx: @CrateContext, tys: &[ty::t]) -> Struct {
fn mk_struct(cx: @CrateContext, tys: &[ty::t], packed: bool) -> Struct {
let lltys = tys.map(|&ty| type_of::sizing_type_of(cx, ty));
let llty_rec = T_struct(lltys);
let llty_rec = T_struct(lltys, packed);
Struct {
size: machine::llsize_of_alloc(cx, llty_rec) /*bad*/as u64,
align: machine::llalign_of_min(cx, llty_rec) /*bad*/as u64,
packed: packed,
fields: vec::from_slice(tys)
}
}
Expand Down Expand Up @@ -358,7 +361,8 @@ fn struct_field_ptr(bcx: block, st: &Struct, val: ValueRef, ix: uint,

let val = if needs_cast {
let real_llty = T_struct(st.fields.map(
|&ty| type_of::type_of(ccx, ty)));
|&ty| type_of::type_of(ccx, ty)),
st.packed);
PointerCast(bcx, val, T_ptr(real_llty))
} else {
val
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/trans/asm.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
Expand Down Expand Up @@ -108,7 +108,7 @@ pub fn trans_inline_asm(bcx: block, ia: &ast::inline_asm) -> block {
} else if numOutputs == 1 {
val_ty(outputs[0])
} else {
T_struct(outputs.map(|o| val_ty(*o)))
T_struct(outputs.map(|o| val_ty(*o)), false)
};
let dialect = match ia.dialect {
Expand Down
8 changes: 4 additions & 4 deletions src/librustc/middle/trans/base.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
Expand Down Expand Up @@ -938,7 +938,7 @@ pub fn get_landing_pad(bcx: block) -> BasicBlockRef {
// The landing pad return type (the type being propagated). Not sure what
// this represents but it's determined by the personality function and
// this is what the EH proposal example uses.
let llretty = T_struct(~[T_ptr(T_i8()), T_i32()]);
let llretty = T_struct(~[T_ptr(T_i8()), T_i32()], false);
// The exception handling personality function. This is the C++
// personality function __gxx_personality_v0, wrapped in our naming
// convention.
Expand Down Expand Up @@ -2837,7 +2837,7 @@ pub fn decl_gc_metadata(ccx: @CrateContext, llmod_id: &str) {
}
pub fn create_module_map(ccx: @CrateContext) -> ValueRef {
let elttype = T_struct(~[ccx.int_type, ccx.int_type]);
let elttype = T_struct(~[ccx.int_type, ccx.int_type], false);
let maptype = T_array(elttype, ccx.module_data.len() + 1);
let map = str::as_c_str(~"_rust_mod_map", |buf| {
unsafe {
Expand Down Expand Up @@ -2877,7 +2877,7 @@ pub fn decl_crate_map(sess: session::Session, mapmeta: LinkMeta,
};
let sym_name = ~"_rust_crate_map_" + mapname;
let arrtype = T_array(int_type, n_subcrates as uint);
let maptype = T_struct(~[T_i32(), T_ptr(T_i8()), int_type, arrtype]);
let maptype = T_struct(~[T_i32(), T_ptr(T_i8()), int_type, arrtype], false);
let map = str::as_c_str(sym_name, |buf| {
unsafe {
llvm::LLVMAddGlobal(llmod, maptype, buf)
Expand Down
23 changes: 17 additions & 6 deletions src/librustc/middle/trans/cabi_arm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use lib::llvm::{llvm, Integer, Pointer, Float, Double, Struct, Array};
use lib::llvm::struct_tys;
use lib::llvm::TypeRef;
use lib::llvm::{Attribute, StructRetAttribute};
use lib::llvm::True;
use middle::trans::cabi::{ABIInfo, FnType, LLVMType};
use middle::trans::common::{T_i8, T_i16, T_i32, T_i64};
use middle::trans::common::{T_array, T_ptr, T_void};
Expand Down Expand Up @@ -39,8 +40,12 @@ fn ty_align(ty: TypeRef) -> uint {
Float => 4,
Double => 8,
Struct => {
do vec::foldl(1, struct_tys(ty)) |a, t| {
uint::max(a, ty_align(*t))
if llvm::LLVMIsPackedStruct(ty) == True {
1
} else {
do vec::foldl(1, struct_tys(ty)) |a, t| {
uint::max(a, ty_align(*t))
}
}
}
Array => {
Expand All @@ -62,10 +67,16 @@ fn ty_size(ty: TypeRef) -> uint {
Float => 4,
Double => 8,
Struct => {
let size = do vec::foldl(0, struct_tys(ty)) |s, t| {
align(s, *t) + ty_size(*t)
};
align(size, ty)
if llvm::LLVMIsPackedStruct(ty) == True {
do vec::foldl(0, struct_tys(ty)) |s, t| {
s + ty_size(*t)
}
} else {
let size = do vec::foldl(0, struct_tys(ty)) |s, t| {
align(s, *t) + ty_size(*t)
};
align(size, ty)
}
}
Array => {
let len = llvm::LLVMGetArrayLength(ty) as uint;
Expand Down
27 changes: 19 additions & 8 deletions src/librustc/middle/trans/cabi_mips.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
Expand All @@ -14,6 +14,7 @@ use core::libc::c_uint;
use lib::llvm::{llvm, TypeRef, Integer, Pointer, Float, Double};
use lib::llvm::{Struct, Array, Attribute};
use lib::llvm::{StructRetAttribute};
use lib::llvm::True;
use middle::trans::common::*;
use middle::trans::cabi::*;

Expand Down Expand Up @@ -49,8 +50,12 @@ fn ty_align(ty: TypeRef) -> uint {
Float => 4,
Double => 8,
Struct => {
do vec::foldl(1, struct_tys(ty)) |a, t| {
uint::max(a, ty_align(*t))
if llvm::LLVMIsPackedStruct(ty) == True {
1
} else {
do vec::foldl(1, struct_tys(ty)) |a, t| {
uint::max(a, ty_align(*t))
}
}
}
Array => {
Expand All @@ -72,10 +77,16 @@ fn ty_size(ty: TypeRef) -> uint {
Float => 4,
Double => 8,
Struct => {
let size = do vec::foldl(0, struct_tys(ty)) |s, t| {
align(s, *t) + ty_size(*t)
};
align(size, ty)
if llvm::LLVMIsPackedStruct(ty) == True {
do vec::foldl(0, struct_tys(ty)) |s, t| {
s + ty_size(*t)
}
} else {
let size = do vec::foldl(0, struct_tys(ty)) |s, t| {
align(s, *t) + ty_size(*t)
};
align(size, ty)
}
}
Array => {
let len = llvm::LLVMGetArrayLength(ty) as uint;
Expand Down Expand Up @@ -174,7 +185,7 @@ fn struct_ty(ty: TypeRef,
fields.push(ty);
}

return T_struct(fields);
return T_struct(fields, false);
}

enum MIPS_ABIInfo { MIPS_ABIInfo }
Expand Down
23 changes: 17 additions & 6 deletions src/librustc/middle/trans/cabi_x86_64.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
Expand All @@ -15,6 +15,7 @@ use lib::llvm::{llvm, TypeRef, Integer, Pointer, Float, Double};
use lib::llvm::{Struct, Array, Attribute};
use lib::llvm::{StructRetAttribute, ByValAttribute};
use lib::llvm::struct_tys;
use lib::llvm::True;
use middle::trans::common::*;
use middle::trans::cabi::*;

Expand Down Expand Up @@ -76,8 +77,12 @@ fn classify_ty(ty: TypeRef) -> ~[x86_64_reg_class] {
Float => 4,
Double => 8,
Struct => {
do vec::foldl(1, struct_tys(ty)) |a, t| {
if llvm::LLVMIsPackedStruct(ty) == True {
1
} else {
do vec::foldl(1, struct_tys(ty)) |a, t| {
uint::max(a, ty_align(*t))
}
}
}
Array => {
Expand All @@ -99,10 +104,16 @@ fn classify_ty(ty: TypeRef) -> ~[x86_64_reg_class] {
Float => 4,
Double => 8,
Struct => {
let size = do vec::foldl(0, struct_tys(ty)) |s, t| {
if llvm::LLVMIsPackedStruct(ty) == True {
do vec::foldl(0, struct_tys(ty)) |s, t| {
s + ty_size(*t)
}
} else {
let size = do vec::foldl(0, struct_tys(ty)) |s, t| {
align(s, *t) + ty_size(*t)
};
align(size, ty)
};
align(size, ty)
}
}
Array => {
let len = llvm::LLVMGetArrayLength(ty) as uint;
Expand Down Expand Up @@ -308,7 +319,7 @@ fn llreg_ty(cls: &[x86_64_reg_class]) -> TypeRef {
}
i += 1u;
}
return T_struct(tys);
return T_struct(tys, false);
}
}

Expand Down
Loading

0 comments on commit cad2260

Please sign in to comment.