mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-02 15:32:06 +00:00
rustc_trans: use a predictable layout for constant ADTs.
This commit is contained in:
parent
f44b099187
commit
386d59dc89
@ -611,10 +611,7 @@ extern "C" {
|
||||
pub fn LLVMConstNull(Ty: TypeRef) -> ValueRef;
|
||||
pub fn LLVMConstICmp(Pred: IntPredicate, V1: ValueRef, V2: ValueRef) -> ValueRef;
|
||||
pub fn LLVMConstFCmp(Pred: RealPredicate, V1: ValueRef, V2: ValueRef) -> ValueRef;
|
||||
// only for isize/vector
|
||||
pub fn LLVMGetUndef(Ty: TypeRef) -> ValueRef;
|
||||
pub fn LLVMIsNull(Val: ValueRef) -> Bool;
|
||||
pub fn LLVMIsUndef(Val: ValueRef) -> Bool;
|
||||
|
||||
// Operations on metadata
|
||||
pub fn LLVMMDStringInContext(C: ContextRef, Str: *const c_char, SLen: c_uint) -> ValueRef;
|
||||
|
@ -198,9 +198,14 @@ fn union_fill(cx: &CrateContext, size: Size, align: Align) -> Type {
|
||||
Type::array(&elem_ty, size / abi_align)
|
||||
}
|
||||
|
||||
// Lookup `Struct::memory_index` and double it to account for padding
|
||||
/// Double an index to account for padding.
|
||||
pub fn memory_index_to_gep(index: usize) -> usize {
|
||||
index * 2
|
||||
}
|
||||
|
||||
/// Lookup `Struct::memory_index`, double it to account for padding.
|
||||
pub fn struct_llfields_index(variant: &layout::Struct, index: usize) -> usize {
|
||||
(variant.memory_index[index] as usize) << 1
|
||||
memory_index_to_gep(variant.memory_index[index] as usize)
|
||||
}
|
||||
|
||||
pub fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
|
@ -1150,14 +1150,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
|
||||
pub fn add_case(&self, s: ValueRef, on_val: ValueRef, dest: BasicBlockRef) {
|
||||
unsafe {
|
||||
if llvm::LLVMIsUndef(s) == llvm::True { return; }
|
||||
llvm::LLVMAddCase(s, on_val, dest)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_incoming_to_phi(&self, phi: ValueRef, val: ValueRef, bb: BasicBlockRef) {
|
||||
unsafe {
|
||||
if llvm::LLVMIsUndef(phi) == llvm::True { return; }
|
||||
llvm::LLVMAddIncoming(phi, &val, &bb, 1 as c_uint);
|
||||
}
|
||||
}
|
||||
|
@ -356,13 +356,13 @@ pub fn C_bytes_in_context(llcx: ContextRef, bytes: &[u8]) -> ValueRef {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn const_get_elt(v: ValueRef, us: &[c_uint])
|
||||
-> ValueRef {
|
||||
pub fn const_get_elt(v: ValueRef, i: usize) -> ValueRef {
|
||||
unsafe {
|
||||
let us = &[i as c_uint];
|
||||
let r = llvm::LLVMConstExtractValue(v, us.as_ptr(), us.len() as c_uint);
|
||||
|
||||
debug!("const_get_elt(v={:?}, us={:?}, r={:?})",
|
||||
Value(v), us, Value(r));
|
||||
debug!("const_get_elt(v={:?}, i={}, r={:?})",
|
||||
Value(v), i, Value(r));
|
||||
|
||||
r
|
||||
}
|
||||
@ -402,19 +402,6 @@ pub fn const_to_opt_u128(v: ValueRef, sign_ext: bool) -> Option<u128> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_undef(val: ValueRef) -> bool {
|
||||
unsafe {
|
||||
llvm::LLVMIsUndef(val) != False
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // potentially useful
|
||||
pub fn is_null(val: ValueRef) -> bool {
|
||||
unsafe {
|
||||
llvm::LLVMIsNull(val) != False
|
||||
}
|
||||
}
|
||||
|
||||
pub fn langcall(tcx: TyCtxt,
|
||||
span: Option<Span>,
|
||||
msg: &str,
|
||||
|
@ -11,7 +11,6 @@
|
||||
#![allow(non_upper_case_globals)]
|
||||
|
||||
use intrinsics::{self, Intrinsic};
|
||||
use libc;
|
||||
use llvm;
|
||||
use llvm::{ValueRef};
|
||||
use abi::{Abi, FnType};
|
||||
@ -1072,7 +1071,7 @@ fn generic_simd_intrinsic<'a, 'tcx>(
|
||||
let indices: Option<Vec<_>> = (0..n)
|
||||
.map(|i| {
|
||||
let arg_idx = i;
|
||||
let val = const_get_elt(vector, &[i as libc::c_uint]);
|
||||
let val = const_get_elt(vector, i);
|
||||
match const_to_opt_u128(val, true) {
|
||||
None => {
|
||||
emit_error!("shuffle index #{} is not a constant", arg_idx);
|
||||
|
@ -29,7 +29,7 @@ use callee;
|
||||
use builder::Builder;
|
||||
use common::{self, CrateContext, const_get_elt, val_ty};
|
||||
use common::{C_array, C_bool, C_bytes, C_int, C_uint, C_big_integral, C_u32, C_u64};
|
||||
use common::{C_null, C_struct, C_str_slice, C_undef, C_usize, C_vector, is_undef};
|
||||
use common::{C_null, C_struct, C_str_slice, C_undef, C_usize, C_vector};
|
||||
use common::const_to_opt_u128;
|
||||
use consts;
|
||||
use type_of;
|
||||
@ -55,7 +55,7 @@ pub struct Const<'tcx> {
|
||||
pub ty: Ty<'tcx>
|
||||
}
|
||||
|
||||
impl<'tcx> Const<'tcx> {
|
||||
impl<'a, 'tcx> Const<'tcx> {
|
||||
pub fn new(llval: ValueRef, ty: Ty<'tcx>) -> Const<'tcx> {
|
||||
Const {
|
||||
llval,
|
||||
@ -63,8 +63,7 @@ impl<'tcx> Const<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_constint<'a>(ccx: &CrateContext<'a, 'tcx>, ci: &ConstInt)
|
||||
-> Const<'tcx> {
|
||||
pub fn from_constint(ccx: &CrateContext<'a, 'tcx>, ci: &ConstInt) -> Const<'tcx> {
|
||||
let tcx = ccx.tcx();
|
||||
let (llval, ty) = match *ci {
|
||||
I8(v) => (C_int(Type::i8(ccx), v as i64), tcx.types.i8),
|
||||
@ -84,10 +83,10 @@ impl<'tcx> Const<'tcx> {
|
||||
}
|
||||
|
||||
/// Translate ConstVal into a LLVM constant value.
|
||||
pub fn from_constval<'a>(ccx: &CrateContext<'a, 'tcx>,
|
||||
cv: &ConstVal,
|
||||
ty: Ty<'tcx>)
|
||||
-> Const<'tcx> {
|
||||
pub fn from_constval(ccx: &CrateContext<'a, 'tcx>,
|
||||
cv: &ConstVal,
|
||||
ty: Ty<'tcx>)
|
||||
-> Const<'tcx> {
|
||||
let llty = type_of::type_of(ccx, ty);
|
||||
let val = match *cv {
|
||||
ConstVal::Float(v) => {
|
||||
@ -104,7 +103,7 @@ impl<'tcx> Const<'tcx> {
|
||||
consts::addr_of(ccx, C_bytes(ccx, v.data), ccx.align_of(ty), "byte_str")
|
||||
}
|
||||
ConstVal::Char(c) => C_uint(Type::char(ccx), c as u64),
|
||||
ConstVal::Function(..) => C_null(llty),
|
||||
ConstVal::Function(..) => C_undef(llty),
|
||||
ConstVal::Variant(_) |
|
||||
ConstVal::Aggregate(..) |
|
||||
ConstVal::Unevaluated(..) => {
|
||||
@ -117,15 +116,25 @@ impl<'tcx> Const<'tcx> {
|
||||
Const::new(val, ty)
|
||||
}
|
||||
|
||||
fn get_pair(&self) -> (ValueRef, ValueRef) {
|
||||
(const_get_elt(self.llval, &[0]),
|
||||
const_get_elt(self.llval, &[1]))
|
||||
fn get_field(&self, ccx: &CrateContext<'a, 'tcx>, i: usize) -> ValueRef {
|
||||
let layout = ccx.layout_of(self.ty);
|
||||
let ix = if let layout::Univariant { ref variant, .. } = *layout {
|
||||
adt::struct_llfields_index(variant, i)
|
||||
} else {
|
||||
i
|
||||
};
|
||||
|
||||
const_get_elt(self.llval, ix)
|
||||
}
|
||||
|
||||
fn get_fat_ptr(&self) -> (ValueRef, ValueRef) {
|
||||
fn get_pair(&self, ccx: &CrateContext<'a, 'tcx>) -> (ValueRef, ValueRef) {
|
||||
(self.get_field(ccx, 0), self.get_field(ccx, 1))
|
||||
}
|
||||
|
||||
fn get_fat_ptr(&self, ccx: &CrateContext<'a, 'tcx>) -> (ValueRef, ValueRef) {
|
||||
assert_eq!(abi::FAT_PTR_ADDR, 0);
|
||||
assert_eq!(abi::FAT_PTR_EXTRA, 1);
|
||||
self.get_pair()
|
||||
self.get_pair(ccx)
|
||||
}
|
||||
|
||||
fn as_lvalue(&self) -> ConstLvalue<'tcx> {
|
||||
@ -136,12 +145,12 @@ impl<'tcx> Const<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_operand<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> OperandRef<'tcx> {
|
||||
pub fn to_operand(&self, ccx: &CrateContext<'a, 'tcx>) -> OperandRef<'tcx> {
|
||||
let llty = type_of::immediate_type_of(ccx, self.ty);
|
||||
let llvalty = val_ty(self.llval);
|
||||
|
||||
let val = if llty == llvalty && common::type_is_imm_pair(ccx, self.ty) {
|
||||
let (a, b) = self.get_pair();
|
||||
let (a, b) = self.get_pair(ccx);
|
||||
OperandValue::Pair(a, b)
|
||||
} else if llty == llvalty && common::type_is_immediate(ccx, self.ty) {
|
||||
// If the types match, we can use the value directly.
|
||||
@ -438,7 +447,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
||||
let (base, extra) = if !has_metadata {
|
||||
(base.llval, ptr::null_mut())
|
||||
} else {
|
||||
base.get_fat_ptr()
|
||||
base.get_fat_ptr(self.ccx)
|
||||
};
|
||||
if self.ccx.statics().borrow().contains_key(&base) {
|
||||
(Base::Static(base), extra)
|
||||
@ -464,32 +473,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
mir::ProjectionElem::Field(ref field, _) => {
|
||||
// Extract field of struct-like const, skipping our alignment padding.
|
||||
let mut ix = field.index();
|
||||
let layout = self.ccx.layout_of(tr_base.ty);
|
||||
if let layout::Univariant { ref variant, .. } = *layout {
|
||||
ix = variant.memory_index[ix] as usize;
|
||||
}
|
||||
|
||||
// Get the ix-th non-undef element of the struct.
|
||||
let mut real_ix = 0; // actual position in the struct
|
||||
let mut ix = ix; // logical index relative to real_ix
|
||||
let mut llprojected;
|
||||
loop {
|
||||
loop {
|
||||
llprojected = const_get_elt(base.llval, &[real_ix]);
|
||||
if !is_undef(llprojected) {
|
||||
break;
|
||||
}
|
||||
real_ix = real_ix + 1;
|
||||
}
|
||||
if ix == 0 {
|
||||
break;
|
||||
}
|
||||
ix = ix - 1;
|
||||
real_ix = real_ix + 1;
|
||||
}
|
||||
|
||||
let llprojected = base.get_field(self.ccx, field.index());
|
||||
let llextra = if !has_metadata {
|
||||
ptr::null_mut()
|
||||
} else {
|
||||
@ -510,7 +494,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
||||
// Produce an undef instead of a LLVM assertion on OOB.
|
||||
let len = common::const_to_uint(tr_base.len(self.ccx));
|
||||
let llelem = if iv < len as u128 {
|
||||
const_get_elt(base.llval, &[iv as u32])
|
||||
const_get_elt(base.llval, iv as usize)
|
||||
} else {
|
||||
C_undef(type_of::type_of(self.ccx, projected_ty))
|
||||
};
|
||||
@ -680,7 +664,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
||||
// to use a different vtable. In that case, we want to
|
||||
// load out the original data pointer so we can repackage
|
||||
// it.
|
||||
let (base, extra) = operand.get_fat_ptr();
|
||||
let (base, extra) = operand.get_fat_ptr(self.ccx);
|
||||
(base, Some(extra))
|
||||
} else {
|
||||
(operand.llval, None)
|
||||
@ -755,7 +739,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
||||
let ll_cast_ty = type_of::immediate_type_of(self.ccx, cast_ty);
|
||||
let ll_from_ty = type_of::immediate_type_of(self.ccx, operand.ty);
|
||||
if common::type_is_fat_ptr(self.ccx, operand.ty) {
|
||||
let (data_ptr, meta_ptr) = operand.get_fat_ptr();
|
||||
let (data_ptr, meta_ptr) = operand.get_fat_ptr(self.ccx);
|
||||
if common::type_is_fat_ptr(self.ccx, cast_ty) {
|
||||
let ll_cft = ll_cast_ty.field_types();
|
||||
let ll_fft = ll_from_ty.field_types();
|
||||
@ -833,8 +817,10 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
||||
|
||||
match const_scalar_checked_binop(tcx, op, lhs, rhs, ty) {
|
||||
Some((llval, of)) => {
|
||||
let llof = C_bool(self.ccx, of);
|
||||
Const::new(C_struct(self.ccx, &[llval, llof], false), binop_ty)
|
||||
trans_const_adt(self.ccx, binop_ty, &mir::AggregateKind::Tuple, &[
|
||||
Const::new(llval, val_ty),
|
||||
Const::new(C_bool(self.ccx, of), tcx.types.bool)
|
||||
])
|
||||
}
|
||||
None => {
|
||||
span_bug!(span, "{:?} got non-integer operands: {:?} and {:?}",
|
||||
@ -1142,13 +1128,10 @@ fn trans_const_adt<'a, 'tcx>(
|
||||
}
|
||||
layout::UntaggedUnion { ref variants, .. }=> {
|
||||
assert_eq!(variant_index, 0);
|
||||
let mut contents = vec![vals[0].llval];
|
||||
|
||||
let offset = ccx.size_of(vals[0].ty);
|
||||
let size = variants.stride();
|
||||
if offset != size {
|
||||
contents.push(padding(ccx, size - offset));
|
||||
}
|
||||
let contents = [
|
||||
vals[0].llval,
|
||||
padding(ccx, variants.stride() - ccx.size_of(vals[0].ty))
|
||||
];
|
||||
|
||||
Const::new(C_struct(ccx, &contents, variants.packed), t)
|
||||
}
|
||||
@ -1203,19 +1186,20 @@ fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
let parts = st.field_index_by_increasing_offset().map(|i| {
|
||||
(vals[i], st.offsets[i])
|
||||
});
|
||||
let mut first_field = true;
|
||||
for (val, target_offset) in parts {
|
||||
if offset < target_offset {
|
||||
if first_field {
|
||||
first_field = false;
|
||||
assert_eq!(target_offset.bytes(), 0);
|
||||
} else {
|
||||
cfields.push(padding(ccx, target_offset - offset));
|
||||
}
|
||||
assert!(!is_undef(val.llval));
|
||||
cfields.push(val.llval);
|
||||
offset = target_offset + ccx.size_of(val.ty);
|
||||
}
|
||||
|
||||
let size = layout.size(ccx);
|
||||
if offset < size {
|
||||
cfields.push(padding(ccx, size - offset));
|
||||
}
|
||||
cfields.push(padding(ccx, size - offset));
|
||||
|
||||
Const::new(C_struct(ccx, &cfields, st.packed), layout.ty)
|
||||
}
|
||||
|
@ -252,7 +252,9 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
||||
|
||||
// Double index to account for padding (FieldPath already uses `Struct::memory_index`)
|
||||
fn gepi_struct_llfields_path(self, bcx: &Builder, discrfield: &layout::FieldPath) -> ValueRef {
|
||||
let path = discrfield.iter().map(|&i| (i as usize) << 1).collect::<Vec<_>>();
|
||||
let path = discrfield.iter().map(|&i| {
|
||||
adt::memory_index_to_gep(i as usize)
|
||||
}).collect::<Vec<_>>();
|
||||
bcx.gepi(self.llval, &path)
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ use rustc_data_structures::indexed_vec::Idx;
|
||||
|
||||
use adt;
|
||||
use base;
|
||||
use common::{self, CrateContext, C_null};
|
||||
use common::{self, CrateContext, C_undef};
|
||||
use builder::Builder;
|
||||
use value::Value;
|
||||
use type_of;
|
||||
@ -93,9 +93,9 @@ impl<'a, 'tcx> OperandRef<'tcx> {
|
||||
(0, 1)
|
||||
};
|
||||
let fields = llty.field_types();
|
||||
OperandValue::Pair(C_null(fields[ix0]), C_null(fields[ix1]))
|
||||
OperandValue::Pair(C_undef(fields[ix0]), C_undef(fields[ix1]))
|
||||
} else {
|
||||
OperandValue::Immediate(C_null(llty))
|
||||
OperandValue::Immediate(C_undef(llty))
|
||||
};
|
||||
OperandRef {
|
||||
val,
|
||||
@ -134,14 +134,10 @@ impl<'a, 'tcx> OperandRef<'tcx> {
|
||||
if let OperandValue::Pair(a, b) = self.val {
|
||||
// Reconstruct the immediate aggregate.
|
||||
let llty = type_of::type_of(bcx.ccx, self.ty);
|
||||
let mut llpair = common::C_undef(llty);
|
||||
let mut llpair = C_undef(llty);
|
||||
let elems = [a, b];
|
||||
for i in 0..2 {
|
||||
let mut elem = elems[i];
|
||||
// Extend boolean i1's to i8.
|
||||
if common::val_ty(elem) == Type::i1(bcx.ccx) {
|
||||
elem = bcx.zext(elem, Type::i8(bcx.ccx));
|
||||
}
|
||||
let elem = base::from_immediate(bcx, elems[i]);
|
||||
let layout = bcx.ccx.layout_of(self.ty);
|
||||
let i = if let Layout::Univariant { ref variant, .. } = *layout {
|
||||
adt::struct_llfields_index(variant, i)
|
||||
|
@ -54,7 +54,7 @@ pub fn inline_enum_const() -> E<i8, i16> {
|
||||
#[no_mangle]
|
||||
pub fn low_align_const() -> E<i16, [i16; 3]> {
|
||||
// Check that low_align_const and high_align_const use the same constant
|
||||
// CHECK: load {{.*}} bitcast ({ i16, i16, [4 x i8] }** [[LOW_HIGH_REF]]
|
||||
// CHECK: load {{.*}} bitcast ({ i16, [0 x i8], i16, [4 x i8] }** [[LOW_HIGH_REF]]
|
||||
*&E::A(0)
|
||||
}
|
||||
|
||||
@ -62,6 +62,6 @@ pub fn low_align_const() -> E<i16, [i16; 3]> {
|
||||
#[no_mangle]
|
||||
pub fn high_align_const() -> E<i16, i32> {
|
||||
// Check that low_align_const and high_align_const use the same constant
|
||||
// CHECK: load {{.*}} bitcast ({ i16, i16, [4 x i8] }** [[LOW_HIGH_REF]]
|
||||
// CHECK: load {{.*}} bitcast ({ i16, [0 x i8], i16, [4 x i8] }** [[LOW_HIGH_REF]]
|
||||
*&E::A(0)
|
||||
}
|
||||
|
@ -22,12 +22,12 @@ pub enum E {
|
||||
B(f32)
|
||||
}
|
||||
|
||||
// CHECK: @VAR2 = constant {{.*}} { i32 0, i32 666 }, section ".test_two"
|
||||
// CHECK: @VAR2 = constant {{.*}}, section ".test_two"
|
||||
#[no_mangle]
|
||||
#[link_section = ".test_two"]
|
||||
pub static VAR2: E = E::A(666);
|
||||
|
||||
// CHECK: @VAR3 = constant {{.*}} { i32 1, float 1.000000e+00 }, section ".test_three"
|
||||
// CHECK: @VAR3 = constant {{.*}}, section ".test_three"
|
||||
#[no_mangle]
|
||||
#[link_section = ".test_three"]
|
||||
pub static VAR3: E = E::B(1.);
|
||||
|
Loading…
Reference in New Issue
Block a user