rustc_trans: use a predictable layout for constant ADTs.
This commit is contained in:
parent
f44b099187
commit
386d59dc89
10 changed files with 68 additions and 100 deletions
|
@ -611,10 +611,7 @@ extern "C" {
|
||||||
pub fn LLVMConstNull(Ty: TypeRef) -> ValueRef;
|
pub fn LLVMConstNull(Ty: TypeRef) -> ValueRef;
|
||||||
pub fn LLVMConstICmp(Pred: IntPredicate, V1: ValueRef, V2: ValueRef) -> ValueRef;
|
pub fn LLVMConstICmp(Pred: IntPredicate, V1: ValueRef, V2: ValueRef) -> ValueRef;
|
||||||
pub fn LLVMConstFCmp(Pred: RealPredicate, 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 LLVMGetUndef(Ty: TypeRef) -> ValueRef;
|
||||||
pub fn LLVMIsNull(Val: ValueRef) -> Bool;
|
|
||||||
pub fn LLVMIsUndef(Val: ValueRef) -> Bool;
|
|
||||||
|
|
||||||
// Operations on metadata
|
// Operations on metadata
|
||||||
pub fn LLVMMDStringInContext(C: ContextRef, Str: *const c_char, SLen: c_uint) -> ValueRef;
|
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)
|
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 {
|
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>,
|
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) {
|
pub fn add_case(&self, s: ValueRef, on_val: ValueRef, dest: BasicBlockRef) {
|
||||||
unsafe {
|
unsafe {
|
||||||
if llvm::LLVMIsUndef(s) == llvm::True { return; }
|
|
||||||
llvm::LLVMAddCase(s, on_val, dest)
|
llvm::LLVMAddCase(s, on_val, dest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_incoming_to_phi(&self, phi: ValueRef, val: ValueRef, bb: BasicBlockRef) {
|
pub fn add_incoming_to_phi(&self, phi: ValueRef, val: ValueRef, bb: BasicBlockRef) {
|
||||||
unsafe {
|
unsafe {
|
||||||
if llvm::LLVMIsUndef(phi) == llvm::True { return; }
|
|
||||||
llvm::LLVMAddIncoming(phi, &val, &bb, 1 as c_uint);
|
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])
|
pub fn const_get_elt(v: ValueRef, i: usize) -> ValueRef {
|
||||||
-> ValueRef {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
let us = &[i as c_uint];
|
||||||
let r = llvm::LLVMConstExtractValue(v, us.as_ptr(), us.len() as c_uint);
|
let r = llvm::LLVMConstExtractValue(v, us.as_ptr(), us.len() as c_uint);
|
||||||
|
|
||||||
debug!("const_get_elt(v={:?}, us={:?}, r={:?})",
|
debug!("const_get_elt(v={:?}, i={}, r={:?})",
|
||||||
Value(v), us, Value(r));
|
Value(v), i, Value(r));
|
||||||
|
|
||||||
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,
|
pub fn langcall(tcx: TyCtxt,
|
||||||
span: Option<Span>,
|
span: Option<Span>,
|
||||||
msg: &str,
|
msg: &str,
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
#![allow(non_upper_case_globals)]
|
#![allow(non_upper_case_globals)]
|
||||||
|
|
||||||
use intrinsics::{self, Intrinsic};
|
use intrinsics::{self, Intrinsic};
|
||||||
use libc;
|
|
||||||
use llvm;
|
use llvm;
|
||||||
use llvm::{ValueRef};
|
use llvm::{ValueRef};
|
||||||
use abi::{Abi, FnType};
|
use abi::{Abi, FnType};
|
||||||
|
@ -1072,7 +1071,7 @@ fn generic_simd_intrinsic<'a, 'tcx>(
|
||||||
let indices: Option<Vec<_>> = (0..n)
|
let indices: Option<Vec<_>> = (0..n)
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
let arg_idx = 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) {
|
match const_to_opt_u128(val, true) {
|
||||||
None => {
|
None => {
|
||||||
emit_error!("shuffle index #{} is not a constant", arg_idx);
|
emit_error!("shuffle index #{} is not a constant", arg_idx);
|
||||||
|
|
|
@ -29,7 +29,7 @@ use callee;
|
||||||
use builder::Builder;
|
use builder::Builder;
|
||||||
use common::{self, CrateContext, const_get_elt, val_ty};
|
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_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 common::const_to_opt_u128;
|
||||||
use consts;
|
use consts;
|
||||||
use type_of;
|
use type_of;
|
||||||
|
@ -55,7 +55,7 @@ pub struct Const<'tcx> {
|
||||||
pub ty: Ty<'tcx>
|
pub ty: Ty<'tcx>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Const<'tcx> {
|
impl<'a, 'tcx> Const<'tcx> {
|
||||||
pub fn new(llval: ValueRef, ty: Ty<'tcx>) -> Const<'tcx> {
|
pub fn new(llval: ValueRef, ty: Ty<'tcx>) -> Const<'tcx> {
|
||||||
Const {
|
Const {
|
||||||
llval,
|
llval,
|
||||||
|
@ -63,8 +63,7 @@ impl<'tcx> Const<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_constint<'a>(ccx: &CrateContext<'a, 'tcx>, ci: &ConstInt)
|
pub fn from_constint(ccx: &CrateContext<'a, 'tcx>, ci: &ConstInt) -> Const<'tcx> {
|
||||||
-> Const<'tcx> {
|
|
||||||
let tcx = ccx.tcx();
|
let tcx = ccx.tcx();
|
||||||
let (llval, ty) = match *ci {
|
let (llval, ty) = match *ci {
|
||||||
I8(v) => (C_int(Type::i8(ccx), v as i64), tcx.types.i8),
|
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.
|
/// Translate ConstVal into a LLVM constant value.
|
||||||
pub fn from_constval<'a>(ccx: &CrateContext<'a, 'tcx>,
|
pub fn from_constval(ccx: &CrateContext<'a, 'tcx>,
|
||||||
cv: &ConstVal,
|
cv: &ConstVal,
|
||||||
ty: Ty<'tcx>)
|
ty: Ty<'tcx>)
|
||||||
-> Const<'tcx> {
|
-> Const<'tcx> {
|
||||||
let llty = type_of::type_of(ccx, ty);
|
let llty = type_of::type_of(ccx, ty);
|
||||||
let val = match *cv {
|
let val = match *cv {
|
||||||
ConstVal::Float(v) => {
|
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")
|
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::Char(c) => C_uint(Type::char(ccx), c as u64),
|
||||||
ConstVal::Function(..) => C_null(llty),
|
ConstVal::Function(..) => C_undef(llty),
|
||||||
ConstVal::Variant(_) |
|
ConstVal::Variant(_) |
|
||||||
ConstVal::Aggregate(..) |
|
ConstVal::Aggregate(..) |
|
||||||
ConstVal::Unevaluated(..) => {
|
ConstVal::Unevaluated(..) => {
|
||||||
|
@ -117,15 +116,25 @@ impl<'tcx> Const<'tcx> {
|
||||||
Const::new(val, ty)
|
Const::new(val, ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_pair(&self) -> (ValueRef, ValueRef) {
|
fn get_field(&self, ccx: &CrateContext<'a, 'tcx>, i: usize) -> ValueRef {
|
||||||
(const_get_elt(self.llval, &[0]),
|
let layout = ccx.layout_of(self.ty);
|
||||||
const_get_elt(self.llval, &[1]))
|
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_ADDR, 0);
|
||||||
assert_eq!(abi::FAT_PTR_EXTRA, 1);
|
assert_eq!(abi::FAT_PTR_EXTRA, 1);
|
||||||
self.get_pair()
|
self.get_pair(ccx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_lvalue(&self) -> ConstLvalue<'tcx> {
|
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 llty = type_of::immediate_type_of(ccx, self.ty);
|
||||||
let llvalty = val_ty(self.llval);
|
let llvalty = val_ty(self.llval);
|
||||||
|
|
||||||
let val = if llty == llvalty && common::type_is_imm_pair(ccx, self.ty) {
|
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)
|
OperandValue::Pair(a, b)
|
||||||
} else if llty == llvalty && common::type_is_immediate(ccx, self.ty) {
|
} else if llty == llvalty && common::type_is_immediate(ccx, self.ty) {
|
||||||
// If the types match, we can use the value directly.
|
// 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 {
|
let (base, extra) = if !has_metadata {
|
||||||
(base.llval, ptr::null_mut())
|
(base.llval, ptr::null_mut())
|
||||||
} else {
|
} else {
|
||||||
base.get_fat_ptr()
|
base.get_fat_ptr(self.ccx)
|
||||||
};
|
};
|
||||||
if self.ccx.statics().borrow().contains_key(&base) {
|
if self.ccx.statics().borrow().contains_key(&base) {
|
||||||
(Base::Static(base), extra)
|
(Base::Static(base), extra)
|
||||||
|
@ -464,32 +473,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mir::ProjectionElem::Field(ref field, _) => {
|
mir::ProjectionElem::Field(ref field, _) => {
|
||||||
// Extract field of struct-like const, skipping our alignment padding.
|
let llprojected = base.get_field(self.ccx, field.index());
|
||||||
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 llextra = if !has_metadata {
|
let llextra = if !has_metadata {
|
||||||
ptr::null_mut()
|
ptr::null_mut()
|
||||||
} else {
|
} else {
|
||||||
|
@ -510,7 +494,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
||||||
// Produce an undef instead of a LLVM assertion on OOB.
|
// Produce an undef instead of a LLVM assertion on OOB.
|
||||||
let len = common::const_to_uint(tr_base.len(self.ccx));
|
let len = common::const_to_uint(tr_base.len(self.ccx));
|
||||||
let llelem = if iv < len as u128 {
|
let llelem = if iv < len as u128 {
|
||||||
const_get_elt(base.llval, &[iv as u32])
|
const_get_elt(base.llval, iv as usize)
|
||||||
} else {
|
} else {
|
||||||
C_undef(type_of::type_of(self.ccx, projected_ty))
|
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
|
// to use a different vtable. In that case, we want to
|
||||||
// load out the original data pointer so we can repackage
|
// load out the original data pointer so we can repackage
|
||||||
// it.
|
// it.
|
||||||
let (base, extra) = operand.get_fat_ptr();
|
let (base, extra) = operand.get_fat_ptr(self.ccx);
|
||||||
(base, Some(extra))
|
(base, Some(extra))
|
||||||
} else {
|
} else {
|
||||||
(operand.llval, None)
|
(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_cast_ty = type_of::immediate_type_of(self.ccx, cast_ty);
|
||||||
let ll_from_ty = type_of::immediate_type_of(self.ccx, operand.ty);
|
let ll_from_ty = type_of::immediate_type_of(self.ccx, operand.ty);
|
||||||
if common::type_is_fat_ptr(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) {
|
if common::type_is_fat_ptr(self.ccx, cast_ty) {
|
||||||
let ll_cft = ll_cast_ty.field_types();
|
let ll_cft = ll_cast_ty.field_types();
|
||||||
let ll_fft = ll_from_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) {
|
match const_scalar_checked_binop(tcx, op, lhs, rhs, ty) {
|
||||||
Some((llval, of)) => {
|
Some((llval, of)) => {
|
||||||
let llof = C_bool(self.ccx, of);
|
trans_const_adt(self.ccx, binop_ty, &mir::AggregateKind::Tuple, &[
|
||||||
Const::new(C_struct(self.ccx, &[llval, llof], false), binop_ty)
|
Const::new(llval, val_ty),
|
||||||
|
Const::new(C_bool(self.ccx, of), tcx.types.bool)
|
||||||
|
])
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
span_bug!(span, "{:?} got non-integer operands: {:?} and {:?}",
|
span_bug!(span, "{:?} got non-integer operands: {:?} and {:?}",
|
||||||
|
@ -1142,13 +1128,10 @@ fn trans_const_adt<'a, 'tcx>(
|
||||||
}
|
}
|
||||||
layout::UntaggedUnion { ref variants, .. }=> {
|
layout::UntaggedUnion { ref variants, .. }=> {
|
||||||
assert_eq!(variant_index, 0);
|
assert_eq!(variant_index, 0);
|
||||||
let mut contents = vec![vals[0].llval];
|
let contents = [
|
||||||
|
vals[0].llval,
|
||||||
let offset = ccx.size_of(vals[0].ty);
|
padding(ccx, variants.stride() - ccx.size_of(vals[0].ty))
|
||||||
let size = variants.stride();
|
];
|
||||||
if offset != size {
|
|
||||||
contents.push(padding(ccx, size - offset));
|
|
||||||
}
|
|
||||||
|
|
||||||
Const::new(C_struct(ccx, &contents, variants.packed), t)
|
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| {
|
let parts = st.field_index_by_increasing_offset().map(|i| {
|
||||||
(vals[i], st.offsets[i])
|
(vals[i], st.offsets[i])
|
||||||
});
|
});
|
||||||
|
let mut first_field = true;
|
||||||
for (val, target_offset) in parts {
|
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));
|
cfields.push(padding(ccx, target_offset - offset));
|
||||||
}
|
}
|
||||||
assert!(!is_undef(val.llval));
|
|
||||||
cfields.push(val.llval);
|
cfields.push(val.llval);
|
||||||
offset = target_offset + ccx.size_of(val.ty);
|
offset = target_offset + ccx.size_of(val.ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
let size = layout.size(ccx);
|
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)
|
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`)
|
// Double index to account for padding (FieldPath already uses `Struct::memory_index`)
|
||||||
fn gepi_struct_llfields_path(self, bcx: &Builder, discrfield: &layout::FieldPath) -> ValueRef {
|
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)
|
bcx.gepi(self.llval, &path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ use rustc_data_structures::indexed_vec::Idx;
|
||||||
|
|
||||||
use adt;
|
use adt;
|
||||||
use base;
|
use base;
|
||||||
use common::{self, CrateContext, C_null};
|
use common::{self, CrateContext, C_undef};
|
||||||
use builder::Builder;
|
use builder::Builder;
|
||||||
use value::Value;
|
use value::Value;
|
||||||
use type_of;
|
use type_of;
|
||||||
|
@ -93,9 +93,9 @@ impl<'a, 'tcx> OperandRef<'tcx> {
|
||||||
(0, 1)
|
(0, 1)
|
||||||
};
|
};
|
||||||
let fields = llty.field_types();
|
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 {
|
} else {
|
||||||
OperandValue::Immediate(C_null(llty))
|
OperandValue::Immediate(C_undef(llty))
|
||||||
};
|
};
|
||||||
OperandRef {
|
OperandRef {
|
||||||
val,
|
val,
|
||||||
|
@ -134,14 +134,10 @@ impl<'a, 'tcx> OperandRef<'tcx> {
|
||||||
if let OperandValue::Pair(a, b) = self.val {
|
if let OperandValue::Pair(a, b) = self.val {
|
||||||
// Reconstruct the immediate aggregate.
|
// Reconstruct the immediate aggregate.
|
||||||
let llty = type_of::type_of(bcx.ccx, self.ty);
|
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];
|
let elems = [a, b];
|
||||||
for i in 0..2 {
|
for i in 0..2 {
|
||||||
let mut elem = elems[i];
|
let elem = base::from_immediate(bcx, 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 layout = bcx.ccx.layout_of(self.ty);
|
let layout = bcx.ccx.layout_of(self.ty);
|
||||||
let i = if let Layout::Univariant { ref variant, .. } = *layout {
|
let i = if let Layout::Univariant { ref variant, .. } = *layout {
|
||||||
adt::struct_llfields_index(variant, i)
|
adt::struct_llfields_index(variant, i)
|
||||||
|
|
|
@ -54,7 +54,7 @@ pub fn inline_enum_const() -> E<i8, i16> {
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn low_align_const() -> E<i16, [i16; 3]> {
|
pub fn low_align_const() -> E<i16, [i16; 3]> {
|
||||||
// Check that low_align_const and high_align_const use the same constant
|
// 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)
|
*&E::A(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,6 +62,6 @@ pub fn low_align_const() -> E<i16, [i16; 3]> {
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn high_align_const() -> E<i16, i32> {
|
pub fn high_align_const() -> E<i16, i32> {
|
||||||
// Check that low_align_const and high_align_const use the same constant
|
// 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)
|
*&E::A(0)
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,12 +22,12 @@ pub enum E {
|
||||||
B(f32)
|
B(f32)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CHECK: @VAR2 = constant {{.*}} { i32 0, i32 666 }, section ".test_two"
|
// CHECK: @VAR2 = constant {{.*}}, section ".test_two"
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[link_section = ".test_two"]
|
#[link_section = ".test_two"]
|
||||||
pub static VAR2: E = E::A(666);
|
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]
|
#[no_mangle]
|
||||||
#[link_section = ".test_three"]
|
#[link_section = ".test_three"]
|
||||||
pub static VAR3: E = E::B(1.);
|
pub static VAR3: E = E::B(1.);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue