use crate::builder::common::{
apply_alignment_override, builtin_type_layout, compute_builtin_type_layout,
compute_opaque_type_layout, pack_all_enums,
};
use crate::builder::sysv_like::mingw::OngoingBitfield;
use crate::layout::{
Annotation, Array, BuiltinType, Record, RecordField, RecordKind, Type, TypeLayout, TypeVariant,
};
use crate::result::Result;
use crate::target::{system_compiler, Compiler, Target};
use crate::util::{
align_to, annotation_alignment, is_attr_packed, pragma_pack_value, size_mul, BITS_PER_BYTE,
};
pub mod mingw;
pub mod sysv;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum Dialect {
Sysv,
Mingw,
}
fn compute_layout(target: Target, ty: &Type<()>, dialect: Dialect) -> Result<Type<TypeLayout>> {
match &ty.variant {
TypeVariant::Builtin(bi) => compute_builtin_type_layout(target, *bi),
TypeVariant::Opaque(layout) => compute_opaque_type_layout(*layout),
TypeVariant::Record(r) => {
compute_record_layout(dialect, target, r.kind, &ty.annotations, &r.fields)
}
TypeVariant::Enum(v) => compute_enum_layout(target, v, &ty.annotations),
TypeVariant::Typedef(dst) => {
let dst_ty = compute_layout(target, dst, dialect)?;
let max_alignment = annotation_alignment(target, &ty.annotations);
Ok(Type {
layout: apply_alignment_override(dst_ty.layout, max_alignment),
annotations: ty.annotations.clone(),
variant: TypeVariant::Typedef(Box::new(dst_ty)),
})
}
TypeVariant::Array(a) => {
let ety = compute_layout(target, &a.element_type, dialect)?;
Ok(Type {
layout: TypeLayout {
size_bits: align_to(
size_mul(ety.layout.size_bits, a.num_elements.unwrap_or(0))?,
ety.layout.field_alignment_bits,
)?,
pointer_alignment_bits: ety.layout.field_alignment_bits,
..ety.layout
},
annotations: vec![],
variant: TypeVariant::Array(Array {
element_type: Box::new(ety),
num_elements: a.num_elements,
}),
})
}
}
}
struct RecordLayoutBuilder {
target: Target,
alignment_bits: u64,
size_bits: u64,
attr_packed: bool,
max_field_alignment_bits: Option<u64>,
record_fields: Vec<RecordField<TypeLayout>>,
kind: RecordKind,
ongoing_bitfield: Option<OngoingBitfield>,
}
fn compute_record_layout(
dialect: Dialect,
target: Target,
kind: RecordKind,
annotations: &[Annotation],
fields: &[RecordField<()>],
) -> Result<Type<TypeLayout>> {
let attr_packed = is_attr_packed(annotations);
let pragma_pack_value = pragma_pack_value(annotations);
let max_field_alignment_bits = match pragma_pack_value {
Some(8) | Some(16) | Some(32) | Some(64) | Some(128) => pragma_pack_value,
_ => None,
};
let alignment_bits = annotation_alignment(target, annotations).unwrap_or(BITS_PER_BYTE);
let mut rlb = RecordLayoutBuilder {
target,
alignment_bits,
size_bits: 0,
attr_packed,
max_field_alignment_bits,
record_fields: vec![],
kind,
ongoing_bitfield: None,
};
match dialect {
Dialect::Mingw => mingw::layout_fields(&mut rlb, fields)?,
Dialect::Sysv => sysv::layout_fields(&mut rlb, fields)?,
}
rlb.size_bits = align_to(rlb.size_bits, rlb.alignment_bits)?;
Ok(Type {
layout: TypeLayout {
size_bits: rlb.size_bits,
field_alignment_bits: rlb.alignment_bits,
pointer_alignment_bits: rlb.alignment_bits,
required_alignment_bits: BITS_PER_BYTE,
},
annotations: annotations.to_vec(),
variant: TypeVariant::Record(Record {
kind,
fields: rlb.record_fields,
}),
})
}
fn compute_enum_layout(
target: Target,
v: &[i128],
annotations: &[Annotation],
) -> Result<Type<TypeLayout>> {
let mut required_size = match is_attr_packed(annotations) || pack_all_enums(target) {
true => BITS_PER_BYTE,
false => builtin_type_layout(target, BuiltinType::Int).size_bits,
};
for &v in v {
let (v, offset) = if v < 0 { (!v, 1) } else { (v, 0) };
let required = 128 - v.leading_zeros() as u64 + offset;
while required > required_size {
required_size *= 2;
}
}
let candidates = [
BuiltinType::Char,
BuiltinType::Short,
BuiltinType::Int,
BuiltinType::Long,
BuiltinType::LongLong,
];
let layout = candidates
.iter()
.map(|ty| builtin_type_layout(target, *ty))
.find(|l| l.size_bits >= required_size)
.unwrap_or_else(|| builtin_type_layout(target, BuiltinType::I128));
let max_alignment = match system_compiler(target) {
Compiler::Clang => annotation_alignment(target, annotations),
_ => None,
};
Ok(Type {
layout: apply_alignment_override(layout, max_alignment),
annotations: annotations.to_vec(),
variant: TypeVariant::Enum(v.to_vec()),
})
}