2013-02-18 16:16:21 -06:00
|
|
|
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2014-11-25 20:17:11 -06:00
|
|
|
//! # Representation of Algebraic Data Types
|
|
|
|
//!
|
|
|
|
//! This module determines how to represent enums, structs, and tuples
|
|
|
|
//! based on their monomorphized types; it is responsible both for
|
|
|
|
//! choosing a representation and translating basic operations on
|
|
|
|
//! values of those types. (Note: exporting the representations for
|
|
|
|
//! debuggers is handled in debuginfo.rs, not here.)
|
|
|
|
//!
|
|
|
|
//! Note that the interface treats everything as a general case of an
|
|
|
|
//! enum, so structs/tuples/etc. have one pseudo-variant with
|
|
|
|
//! discriminant 0; i.e., as if they were a univariant enum.
|
|
|
|
//!
|
|
|
|
//! Having everything in one place will enable improvements to data
|
|
|
|
//! structure representation; possibilities include:
|
|
|
|
//!
|
|
|
|
//! - User-specified alignment (e.g., cacheline-aligning parts of
|
|
|
|
//! concurrently accessed data structures); LLVM can't represent this
|
|
|
|
//! directly, so we'd have to insert padding fields in any structure
|
|
|
|
//! that might contain one and adjust GEP indices accordingly. See
|
|
|
|
//! issue #4578.
|
|
|
|
//!
|
|
|
|
//! - Store nested enums' discriminants in the same word. Rather, if
|
|
|
|
//! some variants start with enums, and those enums representations
|
|
|
|
//! have unused alignment padding between discriminant and body, the
|
|
|
|
//! outer enum's discriminant can be stored there and those variants
|
|
|
|
//! can start at offset 0. Kind of fancy, and might need work to
|
|
|
|
//! make copies of the inner enum type cooperate, but it could help
|
|
|
|
//! with `Option` or `Result` wrapped around another enum.
|
|
|
|
//!
|
|
|
|
//! - Tagged pointers would be neat, but given that any type can be
|
|
|
|
//! used unboxed and any field can have pointers (including mutable)
|
|
|
|
//! taken to it, implementing them for Rust seems difficult.
|
2013-02-28 01:08:52 -06:00
|
|
|
|
2016-01-16 09:03:09 -06:00
|
|
|
use super::Disr;
|
2014-11-06 02:05:53 -06:00
|
|
|
|
2015-12-06 07:38:29 -06:00
|
|
|
use std;
|
2013-02-28 01:08:52 -06:00
|
|
|
|
2014-07-07 19:58:01 -05:00
|
|
|
use llvm::{ValueRef, True, IntEQ, IntNE};
|
2016-08-28 19:44:19 -05:00
|
|
|
use rustc::ty::layout;
|
|
|
|
use rustc::ty::{self, Ty, AdtKind};
|
2015-09-14 04:58:20 -05:00
|
|
|
use syntax::attr;
|
2016-03-22 12:23:36 -05:00
|
|
|
use build::*;
|
|
|
|
use common::*;
|
|
|
|
use debuginfo::DebugLoc;
|
|
|
|
use glue;
|
2016-08-28 19:44:19 -05:00
|
|
|
use base;
|
2016-03-22 12:23:36 -05:00
|
|
|
use machine;
|
|
|
|
use monomorphize;
|
|
|
|
use type_::Type;
|
|
|
|
use type_of;
|
|
|
|
use value::Value;
|
2013-02-18 16:16:21 -06:00
|
|
|
|
2016-08-16 09:41:38 -05:00
|
|
|
#[derive(Copy, Clone, PartialEq)]
|
|
|
|
pub enum BranchKind {
|
|
|
|
Switch,
|
|
|
|
Single
|
|
|
|
}
|
|
|
|
|
2013-07-01 00:42:30 -05:00
|
|
|
type Hint = attr::ReprAttr;
|
|
|
|
|
2015-12-06 07:38:29 -06:00
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
pub struct MaybeSizedValue {
|
|
|
|
pub value: ValueRef,
|
|
|
|
pub meta: ValueRef,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl MaybeSizedValue {
|
|
|
|
pub fn sized(value: ValueRef) -> MaybeSizedValue {
|
|
|
|
MaybeSizedValue {
|
|
|
|
value: value,
|
|
|
|
meta: std::ptr::null_mut()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn unsized_(value: ValueRef, meta: ValueRef) -> MaybeSizedValue {
|
|
|
|
MaybeSizedValue {
|
|
|
|
value: value,
|
|
|
|
meta: meta
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn has_meta(&self) -> bool {
|
|
|
|
!self.meta.is_null()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-28 19:44:19 -05:00
|
|
|
//Given an enum, struct, closure, or tuple, extracts fields.
|
|
|
|
//treats closures as a struct with one variant.
|
|
|
|
//`empty_if_no_variants` is a switch to deal with empty enums.
|
|
|
|
//if true, `variant_index` is disregarded and an empty Vec returned in this case.
|
|
|
|
fn compute_fields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>,
|
|
|
|
variant_index: usize,
|
|
|
|
empty_if_no_variants: bool) -> Vec<Ty<'tcx>> {
|
2014-10-31 03:51:16 -05:00
|
|
|
match t.sty {
|
2016-08-28 19:44:19 -05:00
|
|
|
ty::TyAdt(ref def, _) if def.variants.len() == 0 && empty_if_no_variants => {
|
|
|
|
Vec::default()
|
2014-12-04 15:44:51 -06:00
|
|
|
},
|
2016-08-28 19:44:19 -05:00
|
|
|
ty::TyAdt(ref def, ref substs) => {
|
|
|
|
def.variants[variant_index].fields.iter().map(|f| {
|
|
|
|
monomorphize::field_ty(cx.tcx(), substs, f)
|
|
|
|
}).collect::<Vec<_>>()
|
2015-04-28 18:24:16 -05:00
|
|
|
},
|
2016-08-28 19:44:19 -05:00
|
|
|
ty::TyTuple(fields) => fields.to_vec(),
|
|
|
|
ty::TyClosure(_, substs) => {
|
|
|
|
if variant_index > 0 { bug!("{} is a closure, which only has one variant", t);}
|
|
|
|
substs.upvar_tys.to_vec()
|
2014-12-04 15:56:26 -06:00
|
|
|
},
|
2016-08-28 19:44:19 -05:00
|
|
|
_ => bug!("{} is not a type that can have fields.", t)
|
2014-10-14 15:40:21 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-28 19:44:19 -05:00
|
|
|
/// This represents the (GEP) indices to follow to get to the discriminant field
|
|
|
|
pub type DiscrField = Vec<usize>;
|
2013-08-30 01:45:06 -05:00
|
|
|
|
2014-11-24 19:06:06 -06:00
|
|
|
/// LLVM-level types are a little complicated.
|
|
|
|
///
|
|
|
|
/// C-like enums need to be actual ints, not wrapped in a struct,
|
|
|
|
/// because that changes the ABI on some platforms (see issue #10308).
|
|
|
|
///
|
|
|
|
/// For nominal types, in some cases, we need to use LLVM named structs
|
|
|
|
/// and fill in the actual contents in a second pass to prevent
|
|
|
|
/// unbounded recursion; see also the comments in `trans::type_of`.
|
2016-08-28 19:44:19 -05:00
|
|
|
pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
|
|
|
|
generic_type_of(cx, t, None, false, false)
|
2013-11-22 03:16:17 -06:00
|
|
|
}
|
2015-07-27 07:45:20 -05:00
|
|
|
|
|
|
|
|
2014-08-06 04:59:40 -05:00
|
|
|
// Pass dst=true if the type you are passing is a DST. Yes, we could figure
|
|
|
|
// this out, but if you call this on an unsized type without realising it, you
|
|
|
|
// are going to get the wrong type (it will not include the unsized parts of it).
|
2014-09-29 14:11:30 -05:00
|
|
|
pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
2016-08-28 19:44:19 -05:00
|
|
|
t: Ty<'tcx>, dst: bool) -> Type {
|
|
|
|
generic_type_of(cx, t, None, true, dst)
|
2013-02-18 16:16:21 -06:00
|
|
|
}
|
2016-08-23 02:39:30 -05:00
|
|
|
|
2014-09-29 14:11:30 -05:00
|
|
|
pub fn incomplete_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
2016-08-28 19:44:19 -05:00
|
|
|
t: Ty<'tcx>, name: &str) -> Type {
|
|
|
|
generic_type_of(cx, t, Some(name), false, false)
|
2013-11-22 03:16:17 -06:00
|
|
|
}
|
2016-08-23 02:39:30 -05:00
|
|
|
|
2014-09-29 14:11:30 -05:00
|
|
|
pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
2016-08-28 19:44:19 -05:00
|
|
|
t: Ty<'tcx>, llty: &mut Type) {
|
|
|
|
let l = cx.layout_of(t);
|
|
|
|
debug!("finish_type_of: {} with layout {:#?}", t, l);
|
|
|
|
match *l {
|
|
|
|
layout::CEnum { .. } | layout::General { .. }
|
|
|
|
| layout::UntaggedUnion { .. } | layout::RawNullablePointer { .. } => { }
|
|
|
|
layout::Univariant { ..}
|
|
|
|
| layout::StructWrappedNullablePointer { .. }
|
|
|
|
| layout::Vector { .. } => {
|
|
|
|
let (nonnull_variant, packed) = match *l {
|
|
|
|
layout::Univariant { ref variant, .. } => (0, variant.packed),
|
|
|
|
layout::Vector { .. } => (0, true),
|
|
|
|
layout::StructWrappedNullablePointer { nndiscr, ref nonnull, .. } =>
|
|
|
|
(nndiscr, nonnull.packed),
|
|
|
|
_ => unreachable!()
|
|
|
|
};
|
|
|
|
let fields = compute_fields(cx, t, nonnull_variant as usize, true);
|
|
|
|
llty.set_struct_body(&struct_llfields(cx, &fields, false, false),
|
|
|
|
packed)
|
|
|
|
},
|
|
|
|
_ => bug!("This function cannot handle {} with layout {:#?}", t, l)
|
2013-11-22 03:16:17 -06:00
|
|
|
}
|
2013-02-28 01:08:52 -06:00
|
|
|
}
|
2013-11-22 03:16:17 -06:00
|
|
|
|
2014-09-29 14:11:30 -05:00
|
|
|
fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
2016-08-28 19:44:19 -05:00
|
|
|
t: Ty<'tcx>,
|
2014-09-29 14:11:30 -05:00
|
|
|
name: Option<&str>,
|
|
|
|
sizing: bool,
|
2016-08-23 02:39:30 -05:00
|
|
|
dst: bool) -> Type {
|
2016-08-28 19:44:19 -05:00
|
|
|
let l = cx.layout_of(t);
|
|
|
|
debug!("adt::generic_type_of t: {:?} name: {:?} sizing: {} dst: {}",
|
|
|
|
t, name, sizing, dst);
|
|
|
|
match *l {
|
|
|
|
layout::CEnum { discr, .. } => Type::from_integer(cx, discr),
|
|
|
|
layout::RawNullablePointer { nndiscr, .. } => {
|
|
|
|
let (def, substs) = match t.sty {
|
|
|
|
ty::TyAdt(d, s) => (d, s),
|
|
|
|
_ => bug!("{} is not an ADT", t)
|
|
|
|
};
|
|
|
|
let nnty = monomorphize::field_ty(cx.tcx(), substs,
|
|
|
|
&def.variants[nndiscr as usize].fields[0]);
|
|
|
|
type_of::sizing_type_of(cx, nnty)
|
|
|
|
}
|
|
|
|
layout::StructWrappedNullablePointer { nndiscr, ref nonnull, .. } => {
|
|
|
|
let fields = compute_fields(cx, t, nndiscr as usize, false);
|
2015-07-27 07:45:20 -05:00
|
|
|
match name {
|
|
|
|
None => {
|
2016-08-28 19:44:19 -05:00
|
|
|
Type::struct_(cx, &struct_llfields(cx, &fields, sizing, dst),
|
|
|
|
nonnull.packed)
|
2015-07-27 07:45:20 -05:00
|
|
|
}
|
|
|
|
Some(name) => {
|
|
|
|
assert_eq!(sizing, false);
|
2016-08-23 02:39:30 -05:00
|
|
|
Type::named_struct(cx, name)
|
2015-07-27 07:45:20 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-08-28 19:44:19 -05:00
|
|
|
layout::Univariant { ref variant, .. } => {
|
|
|
|
//note that this case also handles empty enums.
|
|
|
|
//Thus the true as the final parameter here.
|
|
|
|
let fields = compute_fields(cx, t, 0, true);
|
2013-11-22 03:16:17 -06:00
|
|
|
match name {
|
2014-03-08 14:36:22 -06:00
|
|
|
None => {
|
2016-08-28 19:44:19 -05:00
|
|
|
let fields = struct_llfields(cx, &fields, sizing, dst);
|
|
|
|
Type::struct_(cx, &fields, variant.packed)
|
2015-07-27 07:45:20 -05:00
|
|
|
}
|
|
|
|
Some(name) => {
|
|
|
|
// Hypothesis: named_struct's can never need a
|
|
|
|
// drop flag. (... needs validation.)
|
|
|
|
assert_eq!(sizing, false);
|
2016-08-23 02:39:30 -05:00
|
|
|
Type::named_struct(cx, name)
|
2014-03-08 14:36:22 -06:00
|
|
|
}
|
2013-11-22 03:16:17 -06:00
|
|
|
}
|
|
|
|
}
|
2016-08-28 19:44:19 -05:00
|
|
|
layout::Vector { element, count } => {
|
|
|
|
let elem_ty = Type::from_primitive(cx, element);
|
|
|
|
Type::vector(&elem_ty, count)
|
|
|
|
}
|
|
|
|
layout::UntaggedUnion { ref variants, .. }=> {
|
2016-08-18 07:44:00 -05:00
|
|
|
// Use alignment-sized ints to fill all the union storage.
|
2016-08-28 19:44:19 -05:00
|
|
|
let size = variants.stride().bytes();
|
|
|
|
let align = variants.align.abi();
|
|
|
|
let fill = union_fill(cx, size, align);
|
2016-08-18 07:44:00 -05:00
|
|
|
match name {
|
|
|
|
None => {
|
2016-08-28 19:44:19 -05:00
|
|
|
Type::struct_(cx, &[fill], variants.packed)
|
2016-08-18 07:44:00 -05:00
|
|
|
}
|
|
|
|
Some(name) => {
|
|
|
|
let mut llty = Type::named_struct(cx, name);
|
2016-08-28 19:44:19 -05:00
|
|
|
llty.set_struct_body(&[fill], variants.packed);
|
2016-08-26 11:23:42 -05:00
|
|
|
llty
|
2016-08-18 07:44:00 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-08-28 19:44:19 -05:00
|
|
|
layout::General { discr, size, align, .. } => {
|
2013-10-26 14:12:53 -05:00
|
|
|
// We need a representation that has:
|
|
|
|
// * The alignment of the most-aligned field
|
|
|
|
// * The size of the largest variant (rounded up to that alignment)
|
|
|
|
// * No alignment padding anywhere any variant has actual data
|
|
|
|
// (currently matters only for enums small enough to be immediate)
|
|
|
|
// * The discriminant in an obvious place.
|
|
|
|
//
|
|
|
|
// So we start with the discriminant, pad it up to the alignment with
|
|
|
|
// more of its own type, then use alignment-sized ints to get the rest
|
|
|
|
// of the size.
|
|
|
|
//
|
2013-11-22 03:16:17 -06:00
|
|
|
// FIXME #10604: this breaks when vector types are present.
|
2016-08-28 19:44:19 -05:00
|
|
|
let size = size.bytes();
|
|
|
|
let align = align.abi();
|
|
|
|
let discr_ty = Type::from_integer(cx, discr);
|
|
|
|
let discr_size = discr.size().bytes();
|
|
|
|
let padded_discr_size = roundup(discr_size, align as u32);
|
|
|
|
let variant_part_size = size-padded_discr_size;
|
|
|
|
let variant_fill = union_fill(cx, variant_part_size, align);
|
|
|
|
|
|
|
|
assert_eq!(machine::llalign_of_min(cx, variant_fill), align as u32);
|
2016-03-02 13:57:00 -06:00
|
|
|
assert_eq!(padded_discr_size % discr_size, 0); // Ensure discr_ty can fill pad evenly
|
2016-08-23 02:39:30 -05:00
|
|
|
let fields: Vec<Type> =
|
2015-07-27 07:45:20 -05:00
|
|
|
[discr_ty,
|
2016-03-02 13:57:00 -06:00
|
|
|
Type::array(&discr_ty, (padded_discr_size - discr_size)/discr_size),
|
2016-08-28 19:44:19 -05:00
|
|
|
variant_fill].iter().cloned().collect();
|
2013-11-22 03:16:17 -06:00
|
|
|
match name {
|
2015-07-27 07:45:20 -05:00
|
|
|
None => {
|
2016-08-23 02:39:30 -05:00
|
|
|
Type::struct_(cx, &fields[..], false)
|
2015-07-27 07:45:20 -05:00
|
|
|
}
|
2013-11-22 03:16:17 -06:00
|
|
|
Some(name) => {
|
2014-03-15 15:29:34 -05:00
|
|
|
let mut llty = Type::named_struct(cx, name);
|
2015-02-18 13:48:57 -06:00
|
|
|
llty.set_struct_body(&fields[..], false);
|
2016-08-23 02:39:30 -05:00
|
|
|
llty
|
2013-11-22 03:16:17 -06:00
|
|
|
}
|
|
|
|
}
|
2013-02-18 16:16:21 -06:00
|
|
|
}
|
2016-08-28 19:44:19 -05:00
|
|
|
_ => bug!("Unsupported type {} represented as {:#?}", t, l)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn union_fill(cx: &CrateContext, size: u64, align: u64) -> Type {
|
|
|
|
assert_eq!(size%align, 0);
|
2016-09-24 16:37:24 -05:00
|
|
|
assert_eq!(align.count_ones(), 1, "Alignment must be a power fof 2. Got {}", align);
|
2016-08-28 19:44:19 -05:00
|
|
|
let align_units = size/align;
|
2016-09-24 16:37:24 -05:00
|
|
|
let dl = &cx.tcx().data_layout;
|
|
|
|
let layout_align = layout::Align::from_bytes(align, align).unwrap();
|
|
|
|
if let Some(ity) = layout::Integer::for_abi_align(dl, layout_align) {
|
|
|
|
Type::array(&Type::from_integer(cx, ity), align_units)
|
|
|
|
} else {
|
|
|
|
Type::array(&Type::vector(&Type::i32(cx), align/4),
|
|
|
|
align_units)
|
2013-02-18 16:16:21 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-28 19:44:19 -05:00
|
|
|
|
|
|
|
fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fields: &Vec<Ty<'tcx>>,
|
2014-09-29 14:11:30 -05:00
|
|
|
sizing: bool, dst: bool) -> Vec<Type> {
|
2013-03-11 03:04:08 -05:00
|
|
|
if sizing {
|
2016-08-28 19:44:19 -05:00
|
|
|
fields.iter().filter(|&ty| !dst || type_is_sized(cx.tcx(), *ty))
|
2014-08-06 04:59:40 -05:00
|
|
|
.map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
|
2013-03-11 03:04:08 -05:00
|
|
|
} else {
|
2016-08-28 19:44:19 -05:00
|
|
|
fields.iter().map(|&ty| type_of::in_memory_type_of(cx, ty)).collect()
|
2013-03-11 03:04:08 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-24 19:06:06 -06:00
|
|
|
/// Obtain a representation of the discriminant sufficient to translate
|
|
|
|
/// destructuring; this may or may not involve the actual discriminant.
|
2014-09-29 14:11:30 -05:00
|
|
|
pub fn trans_switch<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
2016-08-28 19:44:19 -05:00
|
|
|
t: Ty<'tcx>,
|
2015-10-23 00:07:19 -05:00
|
|
|
scrutinee: ValueRef,
|
|
|
|
range_assert: bool)
|
2016-08-16 09:41:38 -05:00
|
|
|
-> (BranchKind, Option<ValueRef>) {
|
2016-08-28 19:44:19 -05:00
|
|
|
let l = bcx.ccx().layout_of(t);
|
|
|
|
match *l {
|
|
|
|
layout::CEnum { .. } | layout::General { .. } |
|
|
|
|
layout::RawNullablePointer { .. } | layout::StructWrappedNullablePointer { .. } => {
|
|
|
|
(BranchKind::Switch, Some(trans_get_discr(bcx, t, scrutinee, None, range_assert)))
|
2013-02-18 16:16:21 -06:00
|
|
|
}
|
2016-08-28 19:44:19 -05:00
|
|
|
layout::Univariant { .. } | layout::UntaggedUnion { .. } => {
|
2015-04-23 15:45:03 -05:00
|
|
|
// N.B.: Univariant means <= 1 enum variants (*not* == 1 variants).
|
2016-08-16 09:41:38 -05:00
|
|
|
(BranchKind::Single, None)
|
2016-08-28 19:44:19 -05:00
|
|
|
},
|
|
|
|
_ => bug!("{} is not an enum.", t)
|
2013-02-28 13:43:20 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-28 19:44:19 -05:00
|
|
|
pub fn is_discr_signed<'tcx>(l: &layout::Layout) -> bool {
|
|
|
|
match *l {
|
|
|
|
layout::CEnum { signed, .. }=> signed,
|
|
|
|
_ => false,
|
2015-05-05 11:34:37 -05:00
|
|
|
}
|
|
|
|
}
|
2013-03-31 17:55:30 -05:00
|
|
|
|
2013-02-28 14:13:00 -06:00
|
|
|
/// Obtain the actual discriminant of a value.
|
2016-08-28 19:44:19 -05:00
|
|
|
pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>,
|
2015-10-23 00:07:19 -05:00
|
|
|
scrutinee: ValueRef, cast_to: Option<Type>,
|
|
|
|
range_assert: bool)
|
2013-02-28 13:43:20 -06:00
|
|
|
-> ValueRef {
|
2016-08-28 19:44:19 -05:00
|
|
|
let (def, substs) = match t.sty {
|
|
|
|
ty::TyAdt(ref def, substs) if def.adt_kind() == AdtKind::Enum => (def, substs),
|
|
|
|
_ => bug!("{} is not an enum", t)
|
|
|
|
};
|
|
|
|
|
|
|
|
debug!("trans_get_discr t: {:?}", t);
|
|
|
|
let l = bcx.ccx().layout_of(t);
|
|
|
|
|
|
|
|
let val = match *l {
|
|
|
|
layout::CEnum { discr, min, max, .. } => {
|
|
|
|
load_discr(bcx, discr, scrutinee, min, max, range_assert)
|
2015-10-23 00:07:19 -05:00
|
|
|
}
|
2016-08-28 19:44:19 -05:00
|
|
|
layout::General { discr, .. } => {
|
2015-08-24 15:51:57 -05:00
|
|
|
let ptr = StructGEP(bcx, scrutinee, 0);
|
2016-08-28 19:44:19 -05:00
|
|
|
load_discr(bcx, discr, ptr, 0, def.variants.len() as u64 - 1,
|
2015-10-23 00:07:19 -05:00
|
|
|
range_assert)
|
2013-07-01 00:42:30 -05:00
|
|
|
}
|
2016-08-28 19:44:19 -05:00
|
|
|
layout::Univariant { .. } | layout::UntaggedUnion { .. } => C_u8(bcx.ccx(), 0),
|
|
|
|
layout::RawNullablePointer { nndiscr, .. } => {
|
|
|
|
let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
|
|
|
|
let llptrty = type_of::sizing_type_of(bcx.ccx(),
|
|
|
|
monomorphize::field_ty(bcx.ccx().tcx(), substs,
|
|
|
|
&def.variants[nndiscr as usize].fields[0]));
|
2015-05-05 11:34:37 -05:00
|
|
|
ICmp(bcx, cmp, Load(bcx, scrutinee), C_null(llptrty), DebugLoc::None)
|
2014-05-15 19:55:23 -05:00
|
|
|
}
|
2016-08-28 19:44:19 -05:00
|
|
|
layout::StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
|
2015-05-05 11:34:37 -05:00
|
|
|
struct_wrapped_nullable_bitdiscr(bcx, nndiscr, discrfield, scrutinee)
|
2016-08-28 19:44:19 -05:00
|
|
|
},
|
|
|
|
_ => bug!("{} is not an enum", t)
|
2015-05-05 11:34:37 -05:00
|
|
|
};
|
2013-07-01 00:42:30 -05:00
|
|
|
match cast_to {
|
|
|
|
None => val,
|
2016-08-28 19:44:19 -05:00
|
|
|
Some(llty) => if is_discr_signed(&l) { SExt(bcx, val, llty) } else { ZExt(bcx, val, llty) }
|
2013-07-01 00:42:30 -05:00
|
|
|
}
|
2013-02-18 16:16:21 -06:00
|
|
|
}
|
|
|
|
|
2016-08-28 19:44:19 -05:00
|
|
|
fn struct_wrapped_nullable_bitdiscr(bcx: Block, nndiscr: u64, discrfield: &layout::FieldPath,
|
2014-05-15 19:55:23 -05:00
|
|
|
scrutinee: ValueRef) -> ValueRef {
|
2016-08-28 19:44:19 -05:00
|
|
|
let llptrptr = GEPi(bcx, scrutinee,
|
|
|
|
&discrfield.iter().map(|f| *f as usize).collect::<Vec<_>>()[..]);
|
2014-07-03 21:26:38 -05:00
|
|
|
let llptr = Load(bcx, llptrptr);
|
2016-08-28 19:44:19 -05:00
|
|
|
let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
|
2015-02-04 10:42:32 -06:00
|
|
|
ICmp(bcx, cmp, llptr, C_null(val_ty(llptr)), DebugLoc::None)
|
2013-03-31 17:55:30 -05:00
|
|
|
}
|
|
|
|
|
2013-02-28 14:13:00 -06:00
|
|
|
/// Helper for cases where the discriminant is simply loaded.
|
2016-08-28 19:44:19 -05:00
|
|
|
fn load_discr(bcx: Block, ity: layout::Integer, ptr: ValueRef, min: u64, max: u64,
|
2015-10-23 00:07:19 -05:00
|
|
|
range_assert: bool)
|
2013-02-28 13:24:30 -06:00
|
|
|
-> ValueRef {
|
2016-08-28 19:44:19 -05:00
|
|
|
let llty = Type::from_integer(bcx.ccx(), ity);
|
2013-07-01 00:42:30 -05:00
|
|
|
assert_eq!(val_ty(ptr), llty.ptr_to());
|
2016-08-28 19:44:19 -05:00
|
|
|
let bits = ity.size().bits();
|
2013-07-01 00:42:30 -05:00
|
|
|
assert!(bits <= 64);
|
2016-01-18 04:30:52 -06:00
|
|
|
let bits = bits as usize;
|
2016-08-28 19:44:19 -05:00
|
|
|
let mask = !0u64 >> (64 - bits);
|
2015-02-20 06:10:54 -06:00
|
|
|
// For a (max) discr of -1, max will be `-1 as usize`, which overflows.
|
|
|
|
// However, that is fine here (it would still represent the full range),
|
2016-08-28 19:44:19 -05:00
|
|
|
if max.wrapping_add(1) & mask == min & mask || !range_assert {
|
2013-02-28 13:24:30 -06:00
|
|
|
// i.e., if the range is everything. The lo==hi case would be
|
|
|
|
// rejected by the LLVM verifier (it would mean either an
|
|
|
|
// empty set, which is impossible, or the entire range of the
|
|
|
|
// type, which is pointless).
|
|
|
|
Load(bcx, ptr)
|
|
|
|
} else {
|
|
|
|
// llvm::ConstantRange can deal with ranges that wrap around,
|
|
|
|
// so an overflow on (max + 1) is fine.
|
2016-08-28 19:44:19 -05:00
|
|
|
LoadRangeAssert(bcx, ptr, min, max.wrapping_add(1), /* signed: */ True)
|
2013-02-28 13:24:30 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-24 19:06:06 -06:00
|
|
|
/// Yield information about how to dispatch a case of the
|
|
|
|
/// discriminant-like value returned by `trans_switch`.
|
|
|
|
///
|
|
|
|
/// This should ideally be less tightly tied to `_match`.
|
2016-08-28 19:44:19 -05:00
|
|
|
pub fn trans_case<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, value: Disr)
|
2015-10-21 16:33:08 -05:00
|
|
|
-> ValueRef {
|
2016-08-28 19:44:19 -05:00
|
|
|
let l = bcx.ccx().layout_of(t);
|
|
|
|
match *l {
|
|
|
|
layout::CEnum { discr, .. }
|
|
|
|
| layout::General { discr, .. }=> {
|
|
|
|
C_integral(Type::from_integer(bcx.ccx(), discr), value.0, true)
|
2013-02-18 16:16:21 -06:00
|
|
|
}
|
2016-08-28 19:44:19 -05:00
|
|
|
layout::RawNullablePointer { .. } |
|
|
|
|
layout::StructWrappedNullablePointer { .. } => {
|
|
|
|
assert!(value == Disr(0) || value == Disr(1));
|
|
|
|
C_bool(bcx.ccx(), value != Disr(0))
|
2013-02-18 16:16:21 -06:00
|
|
|
}
|
2016-08-28 19:44:19 -05:00
|
|
|
_ => {
|
|
|
|
bug!("{} does not have a discriminant. Represented as {:#?}", t, l);
|
2013-03-31 17:55:30 -05:00
|
|
|
}
|
2013-02-18 16:16:21 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-24 19:06:06 -06:00
|
|
|
/// Set the discriminant for a new value of the given case of the given
|
|
|
|
/// representation.
|
2016-08-28 19:44:19 -05:00
|
|
|
pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>,
|
|
|
|
val: ValueRef, to: Disr) {
|
|
|
|
let l = bcx.ccx().layout_of(t);
|
|
|
|
match *l {
|
|
|
|
layout::CEnum{ discr, min, max, .. } => {
|
|
|
|
assert_discr_in_range(Disr(min), Disr(max), to);
|
|
|
|
Store(bcx, C_integral(Type::from_integer(bcx.ccx(), discr), to.0, true),
|
2015-04-15 13:14:54 -05:00
|
|
|
val);
|
2013-07-01 00:42:30 -05:00
|
|
|
}
|
2016-08-28 19:44:19 -05:00
|
|
|
layout::General{ discr, .. } => {
|
|
|
|
Store(bcx, C_integral(Type::from_integer(bcx.ccx(), discr), to.0, true),
|
2015-08-24 15:51:57 -05:00
|
|
|
StructGEP(bcx, val, 0));
|
2013-02-18 16:16:21 -06:00
|
|
|
}
|
2016-08-28 19:44:19 -05:00
|
|
|
layout::Univariant { .. }
|
|
|
|
| layout::UntaggedUnion { .. }
|
|
|
|
| layout::Vector { .. } => {
|
|
|
|
assert_eq!(to, Disr(0));
|
2016-08-18 07:44:00 -05:00
|
|
|
}
|
2016-08-28 19:44:19 -05:00
|
|
|
layout::RawNullablePointer { nndiscr, .. } => {
|
|
|
|
let nnty = compute_fields(bcx.ccx(), t, nndiscr as usize, false)[0];
|
|
|
|
if to.0 != nndiscr {
|
2014-05-15 19:55:23 -05:00
|
|
|
let llptrty = type_of::sizing_type_of(bcx.ccx(), nnty);
|
2015-04-15 13:14:54 -05:00
|
|
|
Store(bcx, C_null(llptrty), val);
|
2014-05-15 19:55:23 -05:00
|
|
|
}
|
|
|
|
}
|
2016-08-28 19:44:19 -05:00
|
|
|
layout::StructWrappedNullablePointer { nndiscr, ref discrfield, ref nonnull, .. } => {
|
|
|
|
if to.0 != nndiscr {
|
2016-09-15 12:02:10 -05:00
|
|
|
if target_sets_discr_via_memset(bcx) {
|
|
|
|
// Issue #34427: As workaround for LLVM bug on
|
|
|
|
// ARM, use memset of 0 on whole struct rather
|
|
|
|
// than storing null to single target field.
|
|
|
|
let b = B(bcx);
|
|
|
|
let llptr = b.pointercast(val, Type::i8(b.ccx).ptr_to());
|
|
|
|
let fill_byte = C_u8(b.ccx, 0);
|
2016-08-28 19:44:19 -05:00
|
|
|
let size = C_uint(b.ccx, nonnull.stride().bytes());
|
|
|
|
let align = C_i32(b.ccx, nonnull.align.abi() as i32);
|
2016-09-15 12:02:10 -05:00
|
|
|
base::call_memset(&b, llptr, fill_byte, size, align, false);
|
|
|
|
} else {
|
2016-08-28 19:44:19 -05:00
|
|
|
let path = discrfield.iter().map(|&i| i as usize).collect::<Vec<_>>();
|
|
|
|
let llptrptr = GEPi(bcx, val, &path[..]);
|
2016-09-15 12:02:10 -05:00
|
|
|
let llptrty = val_ty(llptrptr).element_type();
|
|
|
|
Store(bcx, C_null(llptrty), llptrptr);
|
|
|
|
}
|
2013-03-31 17:55:30 -05:00
|
|
|
}
|
|
|
|
}
|
2016-08-28 19:44:19 -05:00
|
|
|
_ => bug!("Cannot handle {} represented as {:#?}", t, l)
|
2013-02-18 16:16:21 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-15 12:02:10 -05:00
|
|
|
fn target_sets_discr_via_memset<'blk, 'tcx>(bcx: Block<'blk, 'tcx>) -> bool {
|
|
|
|
bcx.sess().target.target.arch == "arm" || bcx.sess().target.target.arch == "aarch64"
|
|
|
|
}
|
|
|
|
|
2016-08-28 19:44:19 -05:00
|
|
|
fn assert_discr_in_range(min: Disr, max: Disr, discr: Disr) {
|
|
|
|
if min <= max {
|
|
|
|
assert!(min <= discr && discr <= max)
|
|
|
|
} else {
|
|
|
|
assert!(min <= discr || discr <= max)
|
2013-07-01 00:42:30 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-28 01:08:52 -06:00
|
|
|
/// Access a field, at a point when the value's case is known.
|
2016-08-28 19:44:19 -05:00
|
|
|
pub fn trans_field_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>,
|
2015-12-06 07:38:29 -06:00
|
|
|
val: MaybeSizedValue, discr: Disr, ix: usize) -> ValueRef {
|
2016-08-28 19:44:19 -05:00
|
|
|
trans_field_ptr_builder(&bcx.build(), t, val, discr, ix)
|
2016-03-09 06:20:22 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Access a field, at a point when the value's case is known.
|
|
|
|
pub fn trans_field_ptr_builder<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
|
2016-08-28 19:44:19 -05:00
|
|
|
t: Ty<'tcx>,
|
2016-03-09 06:20:22 -06:00
|
|
|
val: MaybeSizedValue,
|
|
|
|
discr: Disr, ix: usize)
|
|
|
|
-> ValueRef {
|
2016-08-28 19:44:19 -05:00
|
|
|
let l = bcx.ccx().layout_of(t);
|
|
|
|
debug!("trans_field_ptr_builder on {} represented as {:#?}", t, l);
|
2013-02-18 16:16:21 -06:00
|
|
|
// Note: if this ever needs to generate conditionals (e.g., if we
|
|
|
|
// decide to do some kind of cdr-coding-like non-unique repr
|
2013-02-28 01:08:52 -06:00
|
|
|
// someday), it will need to return a possibly-new bcx as well.
|
2016-08-28 19:44:19 -05:00
|
|
|
match *l {
|
|
|
|
layout::Univariant { ref variant, .. } => {
|
2016-01-16 09:03:09 -06:00
|
|
|
assert_eq!(discr, Disr(0));
|
2016-08-28 19:44:19 -05:00
|
|
|
struct_field_ptr(bcx, &variant,
|
|
|
|
&compute_fields(bcx.ccx(), t, 0, false),
|
|
|
|
val, ix, false)
|
|
|
|
}
|
|
|
|
layout::Vector { count, .. } => {
|
|
|
|
assert_eq!(discr.0, 0);
|
|
|
|
assert!((ix as u64) < count);
|
|
|
|
bcx.struct_gep(val.value, ix)
|
|
|
|
}
|
|
|
|
layout::General { discr: d, ref variants, .. } => {
|
|
|
|
let mut fields = compute_fields(bcx.ccx(), t, discr.0 as usize, false);
|
|
|
|
fields.insert(0, d.to_ty(&bcx.ccx().tcx(), false));
|
|
|
|
struct_field_ptr(bcx, &variants[discr.0 as usize],
|
|
|
|
&fields,
|
|
|
|
val, ix + 1, true)
|
|
|
|
}
|
|
|
|
layout::UntaggedUnion { .. } => {
|
|
|
|
let fields = compute_fields(bcx.ccx(), t, 0, false);
|
|
|
|
let ty = type_of::in_memory_type_of(bcx.ccx(), fields[ix]);
|
2016-08-18 07:44:00 -05:00
|
|
|
if bcx.is_unreachable() { return C_undef(ty.ptr_to()); }
|
|
|
|
bcx.pointercast(val.value, ty.ptr_to())
|
|
|
|
}
|
2016-08-28 19:44:19 -05:00
|
|
|
layout::RawNullablePointer { nndiscr, .. } |
|
|
|
|
layout::StructWrappedNullablePointer { nndiscr, .. } if discr.0 != nndiscr => {
|
|
|
|
let nullfields = compute_fields(bcx.ccx(), t, (1-nndiscr) as usize, false);
|
2014-05-15 19:55:23 -05:00
|
|
|
// The unit-like case might have a nonzero number of unit-like fields.
|
|
|
|
// (e.d., Result of Either with (), as one side.)
|
2014-10-15 01:05:01 -05:00
|
|
|
let ty = type_of::type_of(bcx.ccx(), nullfields[ix]);
|
2014-05-15 19:55:23 -05:00
|
|
|
assert_eq!(machine::llsize_of_alloc(bcx.ccx(), ty), 0);
|
|
|
|
// The contents of memory at this pointer can't matter, but use
|
2014-06-08 23:00:52 -05:00
|
|
|
// the value that's "reasonable" in case of pointer comparison.
|
2016-03-09 06:20:22 -06:00
|
|
|
if bcx.is_unreachable() { return C_undef(ty.ptr_to()); }
|
|
|
|
bcx.pointercast(val.value, ty.ptr_to())
|
2014-05-15 19:55:23 -05:00
|
|
|
}
|
2016-08-28 19:44:19 -05:00
|
|
|
layout::RawNullablePointer { nndiscr, .. } => {
|
|
|
|
let nnty = compute_fields(bcx.ccx(), t, nndiscr as usize, false)[0];
|
2014-05-15 19:55:23 -05:00
|
|
|
assert_eq!(ix, 0);
|
2016-08-28 19:44:19 -05:00
|
|
|
assert_eq!(discr.0, nndiscr);
|
2014-05-15 19:55:23 -05:00
|
|
|
let ty = type_of::type_of(bcx.ccx(), nnty);
|
2016-03-09 06:20:22 -06:00
|
|
|
if bcx.is_unreachable() { return C_undef(ty.ptr_to()); }
|
|
|
|
bcx.pointercast(val.value, ty.ptr_to())
|
2014-05-15 19:55:23 -05:00
|
|
|
}
|
2016-08-28 19:44:19 -05:00
|
|
|
layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
|
|
|
|
assert_eq!(discr.0, nndiscr);
|
|
|
|
struct_field_ptr(bcx, &nonnull,
|
|
|
|
&compute_fields(bcx.ccx(), t, discr.0 as usize, false),
|
|
|
|
val, ix, false)
|
2013-03-31 17:55:30 -05:00
|
|
|
}
|
2016-08-28 19:44:19 -05:00
|
|
|
_ => bug!("element access in type without elements: {} represented as {:#?}", t, l)
|
2013-02-18 16:16:21 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-09 06:20:22 -06:00
|
|
|
fn struct_field_ptr<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
|
2016-08-28 19:44:19 -05:00
|
|
|
st: &layout::Struct, fields: &Vec<Ty<'tcx>>, val: MaybeSizedValue,
|
2016-03-09 06:20:22 -06:00
|
|
|
ix: usize, needs_cast: bool) -> ValueRef {
|
2015-12-07 20:40:25 -06:00
|
|
|
let ccx = bcx.ccx();
|
2016-08-28 19:44:19 -05:00
|
|
|
let fty = fields[ix];
|
2016-03-09 06:20:22 -06:00
|
|
|
let ll_fty = type_of::in_memory_type_of(bcx.ccx(), fty);
|
|
|
|
if bcx.is_unreachable() {
|
|
|
|
return C_undef(ll_fty.ptr_to());
|
|
|
|
}
|
|
|
|
|
2015-12-06 07:38:29 -06:00
|
|
|
let ptr_val = if needs_cast {
|
2016-08-28 19:44:19 -05:00
|
|
|
let fields = fields.iter().map(|&ty| {
|
2015-12-06 07:38:29 -06:00
|
|
|
type_of::in_memory_type_of(ccx, ty)
|
|
|
|
}).collect::<Vec<_>>();
|
2015-02-18 13:48:57 -06:00
|
|
|
let real_ty = Type::struct_(ccx, &fields[..], st.packed);
|
2016-03-09 06:20:22 -06:00
|
|
|
bcx.pointercast(val.value, real_ty.ptr_to())
|
2013-02-23 00:03:59 -06:00
|
|
|
} else {
|
2015-12-06 07:38:29 -06:00
|
|
|
val.value
|
2013-02-23 00:03:59 -06:00
|
|
|
};
|
2013-02-18 16:16:21 -06:00
|
|
|
|
2015-12-06 07:38:29 -06:00
|
|
|
// Simple case - we can just GEP the field
|
|
|
|
// * First field - Always aligned properly
|
|
|
|
// * Packed struct - There is no alignment padding
|
|
|
|
// * Field is sized - pointer is properly aligned already
|
|
|
|
if ix == 0 || st.packed || type_is_sized(bcx.tcx(), fty) {
|
2016-03-09 06:20:22 -06:00
|
|
|
return bcx.struct_gep(ptr_val, ix);
|
2015-12-06 07:38:29 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// If the type of the last field is [T] or str, then we don't need to do
|
|
|
|
// any adjusments
|
|
|
|
match fty.sty {
|
|
|
|
ty::TySlice(..) | ty::TyStr => {
|
2016-03-09 06:20:22 -06:00
|
|
|
return bcx.struct_gep(ptr_val, ix);
|
2015-12-06 07:38:29 -06:00
|
|
|
}
|
|
|
|
_ => ()
|
|
|
|
}
|
|
|
|
|
|
|
|
// There's no metadata available, log the case and just do the GEP.
|
|
|
|
if !val.has_meta() {
|
2016-02-18 11:49:45 -06:00
|
|
|
debug!("Unsized field `{}`, of `{:?}` has no metadata for adjustment",
|
|
|
|
ix, Value(ptr_val));
|
2016-03-09 06:20:22 -06:00
|
|
|
return bcx.struct_gep(ptr_val, ix);
|
2015-12-06 07:38:29 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
let dbloc = DebugLoc::None;
|
|
|
|
|
|
|
|
// We need to get the pointer manually now.
|
|
|
|
// We do this by casting to a *i8, then offsetting it by the appropriate amount.
|
|
|
|
// We do this instead of, say, simply adjusting the pointer from the result of a GEP
|
2015-12-07 20:40:25 -06:00
|
|
|
// because the field may have an arbitrary alignment in the LLVM representation
|
2015-12-06 07:38:29 -06:00
|
|
|
// anyway.
|
|
|
|
//
|
|
|
|
// To demonstrate:
|
|
|
|
// struct Foo<T: ?Sized> {
|
|
|
|
// x: u16,
|
|
|
|
// y: T
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// The type Foo<Foo<Trait>> is represented in LLVM as { u16, { u16, u8 }}, meaning that
|
|
|
|
// the `y` field has 16-bit alignment.
|
|
|
|
|
|
|
|
let meta = val.meta;
|
|
|
|
|
2016-09-24 15:06:38 -05:00
|
|
|
|
|
|
|
let offset = st.offset_of_field(ix).bytes();
|
2015-12-07 20:40:25 -06:00
|
|
|
let unaligned_offset = C_uint(bcx.ccx(), offset);
|
2015-12-06 07:38:29 -06:00
|
|
|
|
|
|
|
// Get the alignment of the field
|
|
|
|
let (_, align) = glue::size_and_align_of_dst(bcx, fty, meta);
|
|
|
|
|
|
|
|
// Bump the unaligned offset up to the appropriate alignment using the
|
|
|
|
// following expression:
|
|
|
|
//
|
|
|
|
// (unaligned offset + (align - 1)) & -align
|
|
|
|
|
|
|
|
// Calculate offset
|
2016-03-09 06:20:22 -06:00
|
|
|
dbloc.apply(bcx.fcx());
|
|
|
|
let align_sub_1 = bcx.sub(align, C_uint(bcx.ccx(), 1u64));
|
|
|
|
let offset = bcx.and(bcx.add(unaligned_offset, align_sub_1),
|
|
|
|
bcx.neg(align));
|
2015-12-06 07:38:29 -06:00
|
|
|
|
2016-02-18 11:49:45 -06:00
|
|
|
debug!("struct_field_ptr: DST field offset: {:?}", Value(offset));
|
2015-12-06 07:38:29 -06:00
|
|
|
|
|
|
|
// Cast and adjust pointer
|
2016-03-09 06:20:22 -06:00
|
|
|
let byte_ptr = bcx.pointercast(ptr_val, Type::i8p(bcx.ccx()));
|
|
|
|
let byte_ptr = bcx.gep(byte_ptr, &[offset]);
|
2015-12-06 07:38:29 -06:00
|
|
|
|
|
|
|
// Finally, cast back to the type expected
|
|
|
|
let ll_fty = type_of::in_memory_type_of(bcx.ccx(), fty);
|
2016-02-18 11:49:45 -06:00
|
|
|
debug!("struct_field_ptr: Field type is {:?}", ll_fty);
|
2016-03-09 06:20:22 -06:00
|
|
|
bcx.pointercast(byte_ptr, ll_fty.ptr_to())
|
2013-02-18 16:16:21 -06:00
|
|
|
}
|
|
|
|
|
2014-11-24 19:06:06 -06:00
|
|
|
/// Construct a constant value, suitable for initializing a
|
|
|
|
/// GlobalVariable, given a case and constant values for its fields.
|
|
|
|
/// Note that this may have a different LLVM type (and different
|
|
|
|
/// alignment!) from the representation's `type_of`, so it needs a
|
|
|
|
/// pointer cast before use.
|
|
|
|
///
|
|
|
|
/// The LLVM type system does not directly support unions, and only
|
|
|
|
/// pointers can be bitcast, so a constant (and, by extension, the
|
|
|
|
/// GlobalVariable initialized by it) will have a type that can vary
|
|
|
|
/// depending on which case of an enum it is.
|
|
|
|
///
|
|
|
|
/// To understand the alignment situation, consider `enum E { V64(u64),
|
|
|
|
/// V32(u32, u32) }` on Windows. The type has 8-byte alignment to
|
|
|
|
/// accommodate the u64, but `V32(x, y)` would have LLVM type `{i32,
|
|
|
|
/// i32, i32}`, which is 4-byte aligned.
|
|
|
|
///
|
|
|
|
/// Currently the returned value has the same size as the type, but
|
|
|
|
/// this could be changed in the future to avoid allocating unnecessary
|
|
|
|
/// space after values of shorter-than-maximum cases.
|
2016-08-28 19:44:19 -05:00
|
|
|
pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: Disr,
|
2014-09-29 14:11:30 -05:00
|
|
|
vals: &[ValueRef]) -> ValueRef {
|
2016-08-28 19:44:19 -05:00
|
|
|
let l = ccx.layout_of(t);
|
|
|
|
let dl = &ccx.tcx().data_layout;
|
|
|
|
match *l {
|
|
|
|
layout::CEnum { discr: d, min, max, .. } => {
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!(vals.len(), 0);
|
2016-08-28 19:44:19 -05:00
|
|
|
assert_discr_in_range(Disr(min), Disr(max), discr);
|
|
|
|
C_integral(Type::from_integer(ccx, d), discr.0, true)
|
|
|
|
}
|
|
|
|
layout::General { discr: d, ref variants, .. } => {
|
|
|
|
let variant = &variants[discr.0 as usize];
|
|
|
|
let lldiscr = C_integral(Type::from_integer(ccx, d), discr.0 as u64, true);
|
|
|
|
let mut vals_with_discr = vec![lldiscr];
|
|
|
|
vals_with_discr.extend_from_slice(vals);
|
|
|
|
let mut contents = build_const_struct(ccx, &variant.offset_after_field[..],
|
|
|
|
&vals_with_discr[..], variant.packed);
|
|
|
|
let needed_padding = l.size(dl).bytes() - variant.min_size().bytes();
|
|
|
|
if needed_padding > 0 {
|
|
|
|
contents.push(padding(ccx, needed_padding));
|
|
|
|
}
|
2015-02-18 13:48:57 -06:00
|
|
|
C_struct(ccx, &contents[..], false)
|
2013-02-18 16:16:21 -06:00
|
|
|
}
|
2016-08-28 19:44:19 -05:00
|
|
|
layout::UntaggedUnion { ref variants, .. }=> {
|
2016-08-22 11:56:14 -05:00
|
|
|
assert_eq!(discr, Disr(0));
|
2016-08-28 19:44:19 -05:00
|
|
|
let contents = build_const_union(ccx, variants, vals[0]);
|
|
|
|
C_struct(ccx, &contents, variants.packed)
|
2016-08-18 07:44:00 -05:00
|
|
|
}
|
2016-08-28 19:44:19 -05:00
|
|
|
layout::Univariant { ref variant, .. } => {
|
2016-01-16 09:03:09 -06:00
|
|
|
assert_eq!(discr, Disr(0));
|
2016-08-28 19:44:19 -05:00
|
|
|
let contents = build_const_struct(ccx,
|
|
|
|
&variant.offset_after_field[..], vals, variant.packed);
|
|
|
|
C_struct(ccx, &contents[..], variant.packed)
|
|
|
|
}
|
|
|
|
layout::Vector { .. } => {
|
|
|
|
C_vector(vals)
|
2013-07-01 00:42:30 -05:00
|
|
|
}
|
2016-08-28 19:44:19 -05:00
|
|
|
layout::RawNullablePointer { nndiscr, .. } => {
|
|
|
|
let nnty = compute_fields(ccx, t, nndiscr as usize, false)[0];
|
|
|
|
if discr.0 == nndiscr {
|
2014-05-11 20:56:53 -05:00
|
|
|
assert_eq!(vals.len(), 1);
|
|
|
|
vals[0]
|
|
|
|
} else {
|
2014-05-15 19:55:23 -05:00
|
|
|
C_null(type_of::sizing_type_of(ccx, nnty))
|
2014-05-11 20:56:53 -05:00
|
|
|
}
|
|
|
|
}
|
2016-08-28 19:44:19 -05:00
|
|
|
layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
|
|
|
|
if discr.0 == nndiscr {
|
2015-01-07 10:58:31 -06:00
|
|
|
C_struct(ccx, &build_const_struct(ccx,
|
2016-08-28 19:44:19 -05:00
|
|
|
&nonnull.offset_after_field[..],
|
|
|
|
vals, nonnull.packed),
|
2014-03-08 14:36:22 -06:00
|
|
|
false)
|
2013-03-31 17:55:30 -05:00
|
|
|
} else {
|
2016-08-28 19:44:19 -05:00
|
|
|
let fields = compute_fields(ccx, t, nndiscr as usize, false);
|
|
|
|
let vals = fields.iter().map(|&ty| {
|
2014-12-04 15:44:51 -06:00
|
|
|
// Always use null even if it's not the `discrfield`th
|
2014-03-04 22:41:21 -06:00
|
|
|
// field; see #8506.
|
|
|
|
C_null(type_of::sizing_type_of(ccx, ty))
|
2014-03-28 14:42:34 -05:00
|
|
|
}).collect::<Vec<ValueRef>>();
|
2015-01-07 10:58:31 -06:00
|
|
|
C_struct(ccx, &build_const_struct(ccx,
|
2016-08-28 19:44:19 -05:00
|
|
|
&nonnull.offset_after_field[..],
|
|
|
|
&vals[..],
|
|
|
|
false),
|
2014-03-08 14:36:22 -06:00
|
|
|
false)
|
2013-03-31 17:55:30 -05:00
|
|
|
}
|
|
|
|
}
|
2016-08-28 19:44:19 -05:00
|
|
|
_ => bug!("trans_const: cannot handle type {} repreented as {:#?}", t, l)
|
2013-02-18 16:16:21 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-24 19:06:06 -06:00
|
|
|
/// Building structs is a little complicated, because we might need to
|
|
|
|
/// insert padding if a field's value is less aligned than its type.
|
|
|
|
///
|
|
|
|
/// Continuing the example from `trans_const`, a value of type `(u32,
|
|
|
|
/// E)` should have the `E` at offset 8, but if that field's
|
|
|
|
/// initializer is 4-byte aligned then simply translating the tuple as
|
|
|
|
/// a two-element struct will locate it at offset 4, and accesses to it
|
|
|
|
/// will read the wrong memory.
|
2014-09-29 14:11:30 -05:00
|
|
|
fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
2016-08-28 19:44:19 -05:00
|
|
|
offset_after_field: &[layout::Size],
|
|
|
|
vals: &[ValueRef],
|
|
|
|
packed: bool)
|
2014-09-29 14:11:30 -05:00
|
|
|
-> Vec<ValueRef> {
|
2016-08-28 19:44:19 -05:00
|
|
|
assert_eq!(vals.len(), offset_after_field.len());
|
2013-02-18 16:16:21 -06:00
|
|
|
|
2016-08-28 19:44:19 -05:00
|
|
|
if vals.len() == 0 {
|
|
|
|
return Vec::new();
|
|
|
|
}
|
2014-04-12 13:56:34 -05:00
|
|
|
|
|
|
|
// offset of current value
|
2013-02-18 16:16:21 -06:00
|
|
|
let mut offset = 0;
|
2014-03-04 12:02:49 -06:00
|
|
|
let mut cfields = Vec::new();
|
2016-08-28 19:44:19 -05:00
|
|
|
for (&val, target_offset) in
|
|
|
|
vals.iter().zip(
|
|
|
|
offset_after_field.iter().map(|i| i.bytes())
|
|
|
|
) {
|
|
|
|
assert!(!is_undef(val));
|
|
|
|
cfields.push(val);
|
|
|
|
offset += machine::llsize_of_alloc(ccx, val_ty(val));
|
|
|
|
if !packed {
|
2014-10-14 15:36:11 -05:00
|
|
|
let val_align = machine::llalign_of_min(ccx, val_ty(val));
|
2014-04-12 13:56:34 -05:00
|
|
|
offset = roundup(offset, val_align);
|
|
|
|
}
|
2014-01-19 02:21:14 -06:00
|
|
|
if offset != target_offset {
|
2014-03-15 15:29:34 -05:00
|
|
|
cfields.push(padding(ccx, target_offset - offset));
|
2013-02-18 16:16:21 -06:00
|
|
|
offset = target_offset;
|
|
|
|
}
|
2014-04-12 13:56:34 -05:00
|
|
|
}
|
|
|
|
|
2016-08-28 19:44:19 -05:00
|
|
|
let size = offset_after_field.last().unwrap();
|
|
|
|
if offset < size.bytes() {
|
|
|
|
cfields.push(padding(ccx, size.bytes() - offset));
|
2013-02-18 16:16:21 -06:00
|
|
|
}
|
|
|
|
|
2014-04-12 13:56:34 -05:00
|
|
|
cfields
|
2013-02-18 16:16:21 -06:00
|
|
|
}
|
|
|
|
|
2016-08-22 11:56:14 -05:00
|
|
|
fn build_const_union<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
2016-08-28 19:44:19 -05:00
|
|
|
un: &layout::Union,
|
2016-08-22 11:56:14 -05:00
|
|
|
field_val: ValueRef)
|
|
|
|
-> Vec<ValueRef> {
|
|
|
|
let mut cfields = vec![field_val];
|
|
|
|
|
|
|
|
let offset = machine::llsize_of_alloc(ccx, val_ty(field_val));
|
2016-08-28 19:44:19 -05:00
|
|
|
let size = un.stride().bytes();
|
2016-08-22 11:56:14 -05:00
|
|
|
if offset != size {
|
|
|
|
cfields.push(padding(ccx, size - offset));
|
|
|
|
}
|
|
|
|
|
|
|
|
cfields
|
|
|
|
}
|
|
|
|
|
2014-03-15 15:29:34 -05:00
|
|
|
fn padding(ccx: &CrateContext, size: u64) -> ValueRef {
|
|
|
|
C_undef(Type::array(&Type::i8(ccx), size))
|
2013-02-28 13:24:30 -06:00
|
|
|
}
|
|
|
|
|
2014-01-26 02:43:42 -06:00
|
|
|
// FIXME this utility routine should be somewhere more general
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2014-10-14 15:36:11 -05:00
|
|
|
fn roundup(x: u64, a: u32) -> u64 { let a = a as u64; ((x + (a - 1)) / a) * a }
|
2013-02-18 16:16:21 -06:00
|
|
|
|
2014-11-24 19:06:06 -06:00
|
|
|
/// Extract a field of a constant value, as appropriate for its
|
|
|
|
/// representation.
|
|
|
|
///
|
|
|
|
/// (Not to be confused with `common::const_get_elt`, which operates on
|
|
|
|
/// raw LLVM-level structs and arrays.)
|
2016-08-28 19:44:19 -05:00
|
|
|
pub fn const_get_field<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>,
|
|
|
|
val: ValueRef, _discr: Disr,
|
2016-03-28 18:46:02 -05:00
|
|
|
ix: usize) -> ValueRef {
|
2016-08-28 19:44:19 -05:00
|
|
|
let l = ccx.layout_of(t);
|
|
|
|
match *l {
|
|
|
|
layout::CEnum { .. } => bug!("element access in C-like enum const"),
|
|
|
|
layout::Univariant { .. } | layout::Vector { .. } => const_struct_field(val, ix),
|
|
|
|
layout::UntaggedUnion { .. } => const_struct_field(val, 0),
|
|
|
|
layout::General { .. } => const_struct_field(val, ix + 1),
|
|
|
|
layout::RawNullablePointer { .. } => {
|
2014-05-11 20:56:53 -05:00
|
|
|
assert_eq!(ix, 0);
|
|
|
|
val
|
2014-12-04 15:44:51 -06:00
|
|
|
},
|
2016-08-28 19:44:19 -05:00
|
|
|
layout::StructWrappedNullablePointer{ .. } => const_struct_field(val, ix),
|
|
|
|
_ => bug!("{} does not have fields.", t)
|
2013-02-18 16:16:21 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-28 13:24:30 -06:00
|
|
|
/// Extract field of struct-like const, skipping our alignment padding.
|
2016-02-18 11:49:45 -06:00
|
|
|
fn const_struct_field(val: ValueRef, ix: usize) -> ValueRef {
|
2013-02-18 16:16:21 -06:00
|
|
|
// 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 field;
|
|
|
|
loop {
|
|
|
|
loop {
|
2016-02-18 11:49:45 -06:00
|
|
|
field = const_get_elt(val, &[real_ix]);
|
2013-02-18 16:16:21 -06:00
|
|
|
if !is_undef(field) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
real_ix = real_ix + 1;
|
|
|
|
}
|
|
|
|
if ix == 0 {
|
|
|
|
return field;
|
|
|
|
}
|
|
|
|
ix = ix - 1;
|
|
|
|
real_ix = real_ix + 1;
|
|
|
|
}
|
|
|
|
}
|