Convert newtype "dereference" to trans::adt.

Note that in the ByValue case (which can't happen? yet?) we're still
effectively bitcasting, I think.  So this change adds a way to assert
that that's safe.

Note also, for future reference, that LLVM's instcombine pass will turn
a bitcast into a GEP(0, 0, ...) if possible.
This commit is contained in:
Jed Davis 2013-02-24 14:01:43 -08:00
parent 80844f993d
commit 2a028c5ab8
2 changed files with 18 additions and 3 deletions

View File

@ -378,3 +378,12 @@ fn const_struct_field(ccx: @CrateContext, val: ValueRef, ix: uint)
real_ix = real_ix + 1;
}
}
/// Is it safe to bitcast a value to the one field of its one variant?
pub fn is_newtypeish(r: &Repr) -> bool {
match *r {
Univariant(ref st, DtorAbsent)
| Univariant(ref st, NoDtor) => st.fields.len() == 1,
_ => false
}
}

View File

@ -90,6 +90,7 @@ use core::prelude::*;
use lib;
use lib::llvm::ValueRef;
use middle::borrowck::{RootInfo, root_map_key};
use middle::trans::adt;
use middle::trans::base::*;
use middle::trans::build::*;
use middle::trans::callee;
@ -677,15 +678,17 @@ pub impl Datum {
return (None, bcx);
}
let repr = adt::represent_type(ccx, self.ty);
assert adt::is_newtypeish(&repr);
let ty = ty::subst(ccx.tcx, substs, variants[0].args[0]);
return match self.mode {
ByRef => {
// Recast lv.val as a pointer to the newtype
// rather than a ptr to the enum type.
let llty = T_ptr(type_of::type_of(ccx, ty));
(
Some(Datum {
val: PointerCast(bcx, self.val, llty),
val: adt::trans_GEP(bcx, &repr, self.val,
0, 0),
ty: ty,
mode: ByRef,
source: ZeroMem
@ -715,6 +718,8 @@ pub impl Datum {
return (None, bcx);
}
let repr = adt::represent_type(ccx, self.ty);
assert adt::is_newtypeish(&repr);
let ty = fields[0].mt.ty;
return match self.mode {
ByRef => {
@ -724,7 +729,8 @@ pub impl Datum {
// destructors.
(
Some(Datum {
val: GEPi(bcx, self.val, [0, 0, 0]),
val: adt::trans_GEP(bcx, &repr, self.val,
0, 0),
ty: ty,
mode: ByRef,
source: ZeroMem