Skip to content

Commit 982b8f4

Browse files
Move trans_const to mir::constant
1 parent ea0ebe4 commit 982b8f4

File tree

2 files changed

+164
-161
lines changed

2 files changed

+164
-161
lines changed

src/librustc_trans/adt.rs

Lines changed: 5 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,9 @@ pub enum BranchKind {
7070
/// Treats closures as a struct with one variant.
7171
/// `empty_if_no_variants` is a switch to deal with empty enums.
7272
/// If true, `variant_index` is disregarded and an empty Vec returned in this case.
73-
fn compute_fields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>,
74-
variant_index: usize,
75-
empty_if_no_variants: bool) -> Vec<Ty<'tcx>> {
73+
pub fn compute_fields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>,
74+
variant_index: usize,
75+
empty_if_no_variants: bool) -> Vec<Ty<'tcx>> {
7676
match t.sty {
7777
ty::TyAdt(ref def, _) if def.variants.len() == 0 && empty_if_no_variants => {
7878
Vec::default()
@@ -412,9 +412,7 @@ pub fn trans_case<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, value: Disr) -
412412

413413
/// Set the discriminant for a new value of the given case of the given
414414
/// representation.
415-
pub fn trans_set_discr<'a, 'tcx>(
416-
bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: ValueRef, to: Disr
417-
) {
415+
pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: ValueRef, to: Disr) {
418416
let l = bcx.ccx.layout_of(t);
419417
match *l {
420418
layout::CEnum{ discr, min, max, .. } => {
@@ -465,7 +463,7 @@ fn target_sets_discr_via_memset<'a, 'tcx>(bcx: &Builder<'a, 'tcx>) -> bool {
465463
bcx.sess().target.target.arch == "arm" || bcx.sess().target.target.arch == "aarch64"
466464
}
467465

468-
fn assert_discr_in_range(min: Disr, max: Disr, discr: Disr) {
466+
pub fn assert_discr_in_range(min: Disr, max: Disr, discr: Disr) {
469467
if min <= max {
470468
assert!(min <= discr && discr <= max)
471469
} else {
@@ -630,148 +628,6 @@ fn struct_field_ptr<'a, 'tcx>(
630628
bcx.pointercast(byte_ptr, ll_fty.ptr_to())
631629
}
632630

633-
/// Construct a constant value, suitable for initializing a
634-
/// GlobalVariable, given a case and constant values for its fields.
635-
/// Note that this may have a different LLVM type (and different
636-
/// alignment!) from the representation's `type_of`, so it needs a
637-
/// pointer cast before use.
638-
///
639-
/// The LLVM type system does not directly support unions, and only
640-
/// pointers can be bitcast, so a constant (and, by extension, the
641-
/// GlobalVariable initialized by it) will have a type that can vary
642-
/// depending on which case of an enum it is.
643-
///
644-
/// To understand the alignment situation, consider `enum E { V64(u64),
645-
/// V32(u32, u32) }` on Windows. The type has 8-byte alignment to
646-
/// accommodate the u64, but `V32(x, y)` would have LLVM type `{i32,
647-
/// i32, i32}`, which is 4-byte aligned.
648-
///
649-
/// Currently the returned value has the same size as the type, but
650-
/// this could be changed in the future to avoid allocating unnecessary
651-
/// space after values of shorter-than-maximum cases.
652-
pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: Disr,
653-
vals: &[ValueRef]) -> ValueRef {
654-
let l = ccx.layout_of(t);
655-
let dl = &ccx.tcx().data_layout;
656-
match *l {
657-
layout::CEnum { discr: d, min, max, .. } => {
658-
assert_eq!(vals.len(), 0);
659-
assert_discr_in_range(Disr(min), Disr(max), discr);
660-
C_integral(Type::from_integer(ccx, d), discr.0, true)
661-
}
662-
layout::General { discr: d, ref variants, .. } => {
663-
let variant = &variants[discr.0 as usize];
664-
let lldiscr = C_integral(Type::from_integer(ccx, d), discr.0 as u64, true);
665-
let mut vals_with_discr = vec![lldiscr];
666-
vals_with_discr.extend_from_slice(vals);
667-
let mut contents = build_const_struct(ccx, &variant, &vals_with_discr[..]);
668-
let needed_padding = l.size(dl).bytes() - variant.stride().bytes();
669-
if needed_padding > 0 {
670-
contents.push(padding(ccx, needed_padding));
671-
}
672-
C_struct(ccx, &contents[..], false)
673-
}
674-
layout::UntaggedUnion { ref variants, .. }=> {
675-
assert_eq!(discr, Disr(0));
676-
let contents = build_const_union(ccx, variants, vals[0]);
677-
C_struct(ccx, &contents, variants.packed)
678-
}
679-
layout::Univariant { ref variant, .. } => {
680-
assert_eq!(discr, Disr(0));
681-
let contents = build_const_struct(ccx, &variant, vals);
682-
C_struct(ccx, &contents[..], variant.packed)
683-
}
684-
layout::Vector { .. } => {
685-
C_vector(vals)
686-
}
687-
layout::RawNullablePointer { nndiscr, .. } => {
688-
let nnty = compute_fields(ccx, t, nndiscr as usize, false)[0];
689-
if discr.0 == nndiscr {
690-
assert_eq!(vals.len(), 1);
691-
vals[0]
692-
} else {
693-
C_null(type_of::sizing_type_of(ccx, nnty))
694-
}
695-
}
696-
layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
697-
if discr.0 == nndiscr {
698-
C_struct(ccx, &build_const_struct(ccx, &nonnull, vals), false)
699-
} else {
700-
let fields = compute_fields(ccx, t, nndiscr as usize, false);
701-
let vals = fields.iter().map(|&ty| {
702-
// Always use null even if it's not the `discrfield`th
703-
// field; see #8506.
704-
C_null(type_of::sizing_type_of(ccx, ty))
705-
}).collect::<Vec<ValueRef>>();
706-
C_struct(ccx, &build_const_struct(ccx, &nonnull, &vals[..]), false)
707-
}
708-
}
709-
_ => bug!("trans_const: cannot handle type {} repreented as {:#?}", t, l)
710-
}
711-
}
712-
713-
/// Building structs is a little complicated, because we might need to
714-
/// insert padding if a field's value is less aligned than its type.
715-
///
716-
/// Continuing the example from `trans_const`, a value of type `(u32,
717-
/// E)` should have the `E` at offset 8, but if that field's
718-
/// initializer is 4-byte aligned then simply translating the tuple as
719-
/// a two-element struct will locate it at offset 4, and accesses to it
720-
/// will read the wrong memory.
721-
fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
722-
st: &layout::Struct,
723-
vals: &[ValueRef])
724-
-> Vec<ValueRef> {
725-
assert_eq!(vals.len(), st.offsets.len());
726-
727-
if vals.len() == 0 {
728-
return Vec::new();
729-
}
730-
731-
// offset of current value
732-
let mut offset = 0;
733-
let mut cfields = Vec::new();
734-
cfields.reserve(st.offsets.len()*2);
735-
736-
let parts = st.field_index_by_increasing_offset().map(|i| {
737-
(&vals[i], st.offsets[i].bytes())
738-
});
739-
for (&val, target_offset) in parts {
740-
if offset < target_offset {
741-
cfields.push(padding(ccx, target_offset - offset));
742-
offset = target_offset;
743-
}
744-
assert!(!is_undef(val));
745-
cfields.push(val);
746-
offset += machine::llsize_of_alloc(ccx, val_ty(val));
747-
}
748-
749-
if offset < st.stride().bytes() {
750-
cfields.push(padding(ccx, st.stride().bytes() - offset));
751-
}
752-
753-
cfields
754-
}
755-
756-
fn build_const_union<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
757-
un: &layout::Union,
758-
field_val: ValueRef)
759-
-> Vec<ValueRef> {
760-
let mut cfields = vec![field_val];
761-
762-
let offset = machine::llsize_of_alloc(ccx, val_ty(field_val));
763-
let size = un.stride().bytes();
764-
if offset != size {
765-
cfields.push(padding(ccx, size - offset));
766-
}
767-
768-
cfields
769-
}
770-
771-
fn padding(ccx: &CrateContext, size: u64) -> ValueRef {
772-
C_undef(Type::array(&Type::i8(ccx), size))
773-
}
774-
775631
// FIXME this utility routine should be somewhere more general
776632
#[inline]
777633
fn roundup(x: u64, a: u32) -> u64 { let a = a as u64; ((x + (a - 1)) / a) * a }

src/librustc_trans/mir/constant.rs

Lines changed: 159 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use rustc::hir::def_id::DefId;
1818
use rustc::infer::TransNormalize;
1919
use rustc::mir;
2020
use rustc::mir::tcx::LvalueTy;
21-
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
21+
use rustc::ty::{self, layout, Ty, TyCtxt, TypeFoldable};
2222
use rustc::ty::cast::{CastTy, IntTy};
2323
use rustc::ty::subst::Substs;
2424
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
@@ -27,7 +27,7 @@ use callee::Callee;
2727
use builder::Builder;
2828
use common::{self, CrateContext, const_get_elt, val_ty};
2929
use common::{C_array, C_bool, C_bytes, C_floating_f64, C_integral, C_big_integral};
30-
use common::{C_null, C_struct, C_str_slice, C_undef, C_uint};
30+
use common::{C_null, C_struct, C_str_slice, C_undef, C_uint, C_vector, is_undef};
3131
use common::const_to_opt_u128;
3232
use consts;
3333
use monomorphize::{self, Instance};
@@ -549,16 +549,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
549549
mir::AggregateKind::Adt(..) |
550550
mir::AggregateKind::Closure(..) |
551551
mir::AggregateKind::Tuple => {
552-
let disr = match *kind {
553-
mir::AggregateKind::Adt(adt_def, index, _, _) => {
554-
Disr::from(adt_def.variants[index].disr_val)
555-
}
556-
_ => Disr(0)
557-
};
558-
Const::new(
559-
adt::trans_const(self.ccx, dest_ty, disr, &fields),
560-
dest_ty
561-
)
552+
Const::new(trans_const(self.ccx, dest_ty, kind, &fields), dest_ty)
562553
}
563554
}
564555
}
@@ -946,3 +937,159 @@ pub fn trans_static_initializer(ccx: &CrateContext, def_id: DefId)
946937
let instance = Instance::mono(ccx.shared(), def_id);
947938
MirConstContext::trans_def(ccx, instance, IndexVec::new()).map(|c| c.llval)
948939
}
940+
941+
/// Construct a constant value, suitable for initializing a
942+
/// GlobalVariable, given a case and constant values for its fields.
943+
/// Note that this may have a different LLVM type (and different
944+
/// alignment!) from the representation's `type_of`, so it needs a
945+
/// pointer cast before use.
946+
///
947+
/// The LLVM type system does not directly support unions, and only
948+
/// pointers can be bitcast, so a constant (and, by extension, the
949+
/// GlobalVariable initialized by it) will have a type that can vary
950+
/// depending on which case of an enum it is.
951+
///
952+
/// To understand the alignment situation, consider `enum E { V64(u64),
953+
/// V32(u32, u32) }` on Windows. The type has 8-byte alignment to
954+
/// accommodate the u64, but `V32(x, y)` would have LLVM type `{i32,
955+
/// i32, i32}`, which is 4-byte aligned.
956+
///
957+
/// Currently the returned value has the same size as the type, but
958+
/// this could be changed in the future to avoid allocating unnecessary
959+
/// space after values of shorter-than-maximum cases.
960+
fn trans_const<'a, 'tcx>(
961+
ccx: &CrateContext<'a, 'tcx>,
962+
t: Ty<'tcx>,
963+
kind: &mir::AggregateKind,
964+
vals: &[ValueRef]
965+
) -> ValueRef {
966+
let l = ccx.layout_of(t);
967+
let dl = &ccx.tcx().data_layout;
968+
let variant_index = match *kind {
969+
mir::AggregateKind::Adt(_, index, _, _) => index,
970+
_ => 0,
971+
};
972+
match *l {
973+
layout::CEnum { discr: d, min, max, .. } => {
974+
let discr = match *kind {
975+
mir::AggregateKind::Adt(adt_def, _, _, _) => {
976+
Disr::from(adt_def.variants[variant_index].disr_val)
977+
},
978+
_ => Disr(0),
979+
};
980+
assert_eq!(vals.len(), 0);
981+
adt::assert_discr_in_range(Disr(min), Disr(max), discr);
982+
C_integral(Type::from_integer(ccx, d), discr.0, true)
983+
}
984+
layout::General { discr: d, ref variants, .. } => {
985+
let variant = &variants[variant_index];
986+
let lldiscr = C_integral(Type::from_integer(ccx, d), variant_index as u64, true);
987+
let mut vals_with_discr = vec![lldiscr];
988+
vals_with_discr.extend_from_slice(vals);
989+
let mut contents = build_const_struct(ccx, &variant, &vals_with_discr[..]);
990+
let needed_padding = l.size(dl).bytes() - variant.stride().bytes();
991+
if needed_padding > 0 {
992+
contents.push(padding(ccx, needed_padding));
993+
}
994+
C_struct(ccx, &contents[..], false)
995+
}
996+
layout::UntaggedUnion { ref variants, .. }=> {
997+
assert_eq!(variant_index, 0);
998+
let contents = build_const_union(ccx, variants, vals[0]);
999+
C_struct(ccx, &contents, variants.packed)
1000+
}
1001+
layout::Univariant { ref variant, .. } => {
1002+
assert_eq!(variant_index, 0);
1003+
let contents = build_const_struct(ccx, &variant, vals);
1004+
C_struct(ccx, &contents[..], variant.packed)
1005+
}
1006+
layout::Vector { .. } => {
1007+
C_vector(vals)
1008+
}
1009+
layout::RawNullablePointer { nndiscr, .. } => {
1010+
let nnty = adt::compute_fields(ccx, t, nndiscr as usize, false)[0];
1011+
if variant_index as u64 == nndiscr {
1012+
assert_eq!(vals.len(), 1);
1013+
vals[0]
1014+
} else {
1015+
C_null(type_of::sizing_type_of(ccx, nnty))
1016+
}
1017+
}
1018+
layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
1019+
if variant_index as u64 == nndiscr {
1020+
C_struct(ccx, &build_const_struct(ccx, &nonnull, vals), false)
1021+
} else {
1022+
let fields = adt::compute_fields(ccx, t, nndiscr as usize, false);
1023+
let vals = fields.iter().map(|&ty| {
1024+
// Always use null even if it's not the `discrfield`th
1025+
// field; see #8506.
1026+
C_null(type_of::sizing_type_of(ccx, ty))
1027+
}).collect::<Vec<ValueRef>>();
1028+
C_struct(ccx, &build_const_struct(ccx, &nonnull, &vals[..]), false)
1029+
}
1030+
}
1031+
_ => bug!("trans_const: cannot handle type {} repreented as {:#?}", t, l)
1032+
}
1033+
}
1034+
1035+
/// Building structs is a little complicated, because we might need to
1036+
/// insert padding if a field's value is less aligned than its type.
1037+
///
1038+
/// Continuing the example from `trans_const`, a value of type `(u32,
1039+
/// E)` should have the `E` at offset 8, but if that field's
1040+
/// initializer is 4-byte aligned then simply translating the tuple as
1041+
/// a two-element struct will locate it at offset 4, and accesses to it
1042+
/// will read the wrong memory.
1043+
fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
1044+
st: &layout::Struct,
1045+
vals: &[ValueRef])
1046+
-> Vec<ValueRef> {
1047+
assert_eq!(vals.len(), st.offsets.len());
1048+
1049+
if vals.len() == 0 {
1050+
return Vec::new();
1051+
}
1052+
1053+
// offset of current value
1054+
let mut offset = 0;
1055+
let mut cfields = Vec::new();
1056+
cfields.reserve(st.offsets.len()*2);
1057+
1058+
let parts = st.field_index_by_increasing_offset().map(|i| {
1059+
(&vals[i], st.offsets[i].bytes())
1060+
});
1061+
for (&val, target_offset) in parts {
1062+
if offset < target_offset {
1063+
cfields.push(padding(ccx, target_offset - offset));
1064+
offset = target_offset;
1065+
}
1066+
assert!(!is_undef(val));
1067+
cfields.push(val);
1068+
offset += machine::llsize_of_alloc(ccx, val_ty(val));
1069+
}
1070+
1071+
if offset < st.stride().bytes() {
1072+
cfields.push(padding(ccx, st.stride().bytes() - offset));
1073+
}
1074+
1075+
cfields
1076+
}
1077+
1078+
fn build_const_union<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
1079+
un: &layout::Union,
1080+
field_val: ValueRef)
1081+
-> Vec<ValueRef> {
1082+
let mut cfields = vec![field_val];
1083+
1084+
let offset = machine::llsize_of_alloc(ccx, val_ty(field_val));
1085+
let size = un.stride().bytes();
1086+
if offset != size {
1087+
cfields.push(padding(ccx, size - offset));
1088+
}
1089+
1090+
cfields
1091+
}
1092+
1093+
fn padding(ccx: &CrateContext, size: u64) -> ValueRef {
1094+
C_undef(Type::array(&Type::i8(ccx), size))
1095+
}

0 commit comments

Comments
 (0)