Created
December 18, 2015 22:04
-
-
Save luqmana/51ac1add2432a258d870 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs | |
index 049063f..38fb55f 100644 | |
--- a/src/librustc/mir/repr.rs | |
+++ b/src/librustc/mir/repr.rs | |
@@ -294,7 +294,7 @@ impl<'tcx> Terminator<'tcx> { | |
} | |
} | |
-#[derive(Debug, RustcEncodable, RustcDecodable)] | |
+#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] | |
pub struct CallData<'tcx> { | |
/// where the return value is written to | |
pub destination: Lvalue<'tcx>, | |
@@ -609,6 +609,8 @@ pub enum CastKind { | |
/// `&[i32;N]` to a `&[i32]`, or a `Box<T>` to a `Box<Trait>` | |
/// (presuming `T: Trait`). | |
Unsize, | |
+ | |
+ Transmute, | |
} | |
#[derive(Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] | |
diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs | |
index 39a315f..39a94e2 100644 | |
--- a/src/librustc_mir/mir_map.rs | |
+++ b/src/librustc_mir/mir_map.rs | |
@@ -145,6 +145,7 @@ impl<'a, 'm, 'tcx> Visitor<'tcx> for InnerDump<'a,'m,'tcx> { | |
match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) { | |
Ok(mut mir) => { | |
+ lower_intrinsics::LowerIntrinsics::new(self.tcx).run_on_mir(&mut mir); | |
simplify_cfg::SimplifyCfg::new().run_on_mir(&mut mir); | |
let meta_item_list = self.attr | |
diff --git a/src/librustc_mir/transform/lower_intrinsics.rs b/src/librustc_mir/transform/lower_intrinsics.rs | |
new file mode 100644 | |
index 0000000..45da514 | |
--- /dev/null | |
+++ b/src/librustc_mir/transform/lower_intrinsics.rs | |
@@ -0,0 +1,133 @@ | |
+// Copyright 2015 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. | |
+ | |
+//! This pass lowers any Call terminators which are intrinsics | |
+//! to whatever statements or other calls as necessary. | |
+ | |
+use transform::MirPass; | |
+ | |
+use rustc::middle::infer; | |
+use rustc::middle::ty; | |
+use rustc::mir::repr::*; | |
+use rustc::mir::repr::Terminator::Call; | |
+ | |
+use syntax::abi; | |
+ | |
+ | |
+pub struct LowerIntrinsics<'a, 'tcx: 'a> { | |
+ tcx: &'a ty::ctxt<'tcx> | |
+} | |
+ | |
+impl<'a, 'tcx: 'a> LowerIntrinsics<'a, 'tcx> { | |
+ pub fn new(tcx: &'a ty::ctxt<'tcx>) -> LowerIntrinsics<'a, 'tcx> { | |
+ LowerIntrinsics { tcx: tcx } | |
+ } | |
+} | |
+ | |
+impl<'a, 'tcx> MirPass<'tcx> for LowerIntrinsics<'a, 'tcx> { | |
+ fn run_on_mir(&mut self, mir: &mut Mir<'tcx>) { | |
+ let mut bbs = vec![]; | |
+ | |
+ for (i, basic_block) in mir.basic_blocks.iter_mut().enumerate() { | |
+ match basic_block.terminator { | |
+ Call { ref data, .. } if is_intrinsic_call(data) => bbs.push(BasicBlock::new(i)), | |
+ _ => {} | |
+ } | |
+ } | |
+ | |
+ for bb in bbs { | |
+ lower_intrinsic_in_basic_block(self.tcx, mir, bb); | |
+ } | |
+ } | |
+} | |
+ | |
+fn is_intrinsic_call<'tcx>(call_data: &CallData<'tcx>) -> bool { | |
+ if let Operand::Constant(Constant { ty, .. }) = call_data.func { | |
+ match ty.sty { | |
+ ty::TyBareFn(_, fty) if fty.abi == abi::RustIntrinsic => true, | |
+ _ => false | |
+ } | |
+ } else { | |
+ false | |
+ } | |
+} | |
+ | |
+fn lower_intrinsic_in_basic_block<'tcx>(tcx: &ty::ctxt<'tcx>, | |
+ mir: &mut Mir<'tcx>, | |
+ bb: BasicBlock) { | |
+ | |
+ let basic_block = mir.basic_block_data_mut(bb); | |
+ | |
+ let (call_data, targets) = | |
+ if let Call { ref data, targets } = basic_block.terminator { | |
+ ((*data).clone(), targets) | |
+ } else { | |
+ tcx.sess.bug("expected `Call` terminator to lower intrinsic") | |
+ }; | |
+ let (def_id, span, fty) = if let Operand::Constant(Constant { | |
+ span, ty, literal: Literal::Item { def_id, .. } | |
+ }) = call_data.func { | |
+ (def_id, span, ty) | |
+ } else { | |
+ tcx.sess.bug("could not get literal item to lower intrinsic") | |
+ }; | |
+ | |
+ let sig = tcx.erase_late_bound_regions(&fty.fn_sig()); | |
+ let sig = infer::normalize_associated_type(tcx, &sig); | |
+ let ret_ty = sig.output.unwrap_or(tcx.mk_nil()); | |
+ | |
+ let name = &*tcx.item_name(def_id).as_str(); | |
+ | |
+ if name == "transmute" { | |
+ | |
+ assert_eq!(call_data.args.len(), 1); | |
+ | |
+ // dest = transmute(foo) | |
+ // => | |
+ // Assign(dest, Cast(foo)) | |
+ basic_block.statements.push(Statement { | |
+ span: span, | |
+ kind: StatementKind::Assign( | |
+ call_data.destination.clone(), | |
+ Rvalue::Cast(CastKind::Transmute, | |
+ call_data.args[0].clone(), | |
+ ret_ty) | |
+ ) | |
+ }); | |
+ | |
+ // Since this is no longer a function call, replace the | |
+ // terminator with a simple Goto | |
+ basic_block.terminator = Terminator::Goto { target: targets.0 }; | |
+ | |
+ } else if name == "move_val_init" { | |
+ | |
+ assert_eq!(call_data.args.len(), 2); | |
+ | |
+ if let Operand::Consume(dest) = call_data.args[0].clone() { | |
+ // move_val_init(dest, src) | |
+ // => | |
+ // Assign(dest, src) | |
+ basic_block.statements.push(Statement { | |
+ span: span, | |
+ kind: StatementKind::Assign( | |
+ dest, | |
+ Rvalue::Use(call_data.args[1].clone()) | |
+ ) | |
+ }); | |
+ } else { | |
+ tcx.sess.span_bug(span, "destination argument not lvalue?"); | |
+ } | |
+ | |
+ // Since this is no longer a function call, replace the | |
+ // terminator with a simple Goto | |
+ basic_block.terminator = Terminator::Goto { target: targets.0 }; | |
+ | |
+ } | |
+} | |
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs | |
index 174718f..6b37e01 100644 | |
--- a/src/librustc_mir/transform/mod.rs | |
+++ b/src/librustc_mir/transform/mod.rs | |
@@ -10,6 +10,7 @@ | |
pub mod simplify_cfg; | |
pub mod erase_regions; | |
+pub mod lower_intrinsics; | |
mod util; | |
use rustc::mir::repr::Mir; | |
diff --git a/src/librustc_trans/trans/mir/rvalue.rs b/src/librustc_trans/trans/mir/rvalue.rs | |
index 529e65d..1dc14f2 100644 | |
--- a/src/librustc_trans/trans/mir/rvalue.rs | |
+++ b/src/librustc_trans/trans/mir/rvalue.rs | |
@@ -8,13 +8,13 @@ | |
// option. This file may not be copied, modified, or distributed | |
// except according to those terms. | |
-use llvm::ValueRef; | |
+use llvm::{TypeKind, ValueRef}; | |
use rustc::middle::ty::{self, Ty}; | |
use rustc::mir::repr as mir; | |
use trans::asm; | |
use trans::base; | |
-use trans::build; | |
+use trans::build::{self, BitCast, IntToPtr, PointerCast, PtrToInt}; | |
use trans::common::{self, Block, Result}; | |
use trans::debuginfo::DebugLoc; | |
use trans::declare; | |
@@ -140,6 +140,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { | |
{ | |
assert!(rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue); | |
+ let ccx = bcx.ccx(); | |
+ let tcx = bcx.tcx(); | |
match *rvalue { | |
mir::Rvalue::Use(ref operand) => { | |
let operand = self.trans_operand(bcx, operand); | |
@@ -185,7 +187,86 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { | |
} | |
} | |
} | |
- mir::CastKind::Misc => unimplemented!() | |
+ mir::CastKind::Misc => unimplemented!(), | |
+ mir::CastKind::Transmute => { | |
+ use trans::common::{type_is_fat_ptr, type_is_immediate}; | |
+ | |
+ let llval_ty = type_of::type_of(bcx.ccx(), operand.ty); | |
+ let llcast_ty = type_of::type_of(bcx.ccx(), cast_ty); | |
+ | |
+ assert_eq!(machine::llbitsize_of_real(bcx.ccx(), llval_ty), | |
+ machine::llbitsize_of_real(bcx.ccx(), llcast_ty)); | |
+ | |
+ let nonpointer_nonaggregate = |llkind: TypeKind| -> bool { | |
+ use llvm::TypeKind::*; | |
+ match llkind { | |
+ Half | Float | Double | X86_FP80 | FP128 | | |
+ PPC_FP128 | Integer | Vector | X86_MMX => true, | |
+ _ => false | |
+ } | |
+ }; | |
+ | |
+ let val_kind = llval_ty.kind(); | |
+ let cast_kind = llcast_ty.kind(); | |
+ | |
+ match operand.val { | |
+ // Cast Ref => Fat Ptr | |
+ // ex: (*const T, usize) => &[T] | |
+ OperandValue::Ref(r) if type_is_fat_ptr(tcx, cast_ty) => { | |
+ let (data, extra) = base::load_fat_ptr(bcx, r, cast_ty); | |
+ OperandValue::FatPtr(data, extra) | |
+ }, | |
+ | |
+ // Cast Ref => Ref | |
+ // ex: &StructA => &StructB | |
+ OperandValue::Ref(r) => { | |
+ assert!(!type_is_immediate(ccx, cast_ty)); | |
+ OperandValue::Ref(PointerCast(bcx, r, llcast_ty.ptr_to())) | |
+ }, | |
+ | |
+ // Cast Immediate => Immediate | |
+ OperandValue::Immediate(i) => { | |
+ assert!(type_is_immediate(ccx, cast_ty)); | |
+ let val = match (val_kind, cast_kind) { | |
+ (TypeKind::Pointer, TypeKind::Integer) => | |
+ PtrToInt(bcx, i, llcast_ty), | |
+ | |
+ (TypeKind::Integer, TypeKind::Pointer) => | |
+ IntToPtr(bcx, i, llcast_ty), | |
+ | |
+ (TypeKind::Pointer, TypeKind::Pointer) => | |
+ PointerCast(bcx, i, llcast_ty), | |
+ | |
+ _ if nonpointer_nonaggregate(val_kind) && | |
+ nonpointer_nonaggregate(cast_kind) => { | |
+ BitCast(bcx, i, llcast_ty) | |
+ }, | |
+ | |
+ _ => { | |
+ let lltemp = base::alloc_ty(bcx, cast_ty, "__transmute_temp"); | |
+ let lldest = PointerCast(bcx, lltemp, llval_ty.ptr_to()); | |
+ base::store_ty(bcx, i, lldest, operand.ty); | |
+ base::load_ty(bcx, lltemp, cast_ty) | |
+ } | |
+ }; | |
+ OperandValue::Immediate(val) | |
+ }, | |
+ | |
+ // Fat Ptr => Fat Ptr | |
+ OperandValue::FatPtr(_, _) if type_is_fat_ptr(tcx, cast_ty) | |
+ => operand.val, | |
+ | |
+ // Fat Ptr => Ref | |
+ // ex: &[T] => (*const T, usize) | |
+ OperandValue::FatPtr(d, e) => { | |
+ assert!(!type_is_immediate(ccx, cast_ty)); | |
+ let lltemp = base::alloc_ty(bcx, cast_ty, "__transmute_temp"); | |
+ let lldest = PointerCast(bcx, lltemp, llval_ty.ptr_to()); | |
+ base::store_fat_ptr(bcx, d, e, lldest, operand.ty); | |
+ OperandValue::Ref(lltemp) | |
+ } | |
+ } | |
+ } | |
}; | |
(bcx, OperandRef { | |
val: val, |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment