diff --git a/src/base.rs b/src/base.rs index c7f07542b0e..5301656cf24 100644 --- a/src/base.rs +++ b/src/base.rs @@ -85,6 +85,7 @@ pub fn trans_fn<'a, 'tcx: 'a>(cx: &mut CodegenCx<'a, 'tcx, CurrentBackend>, f: & ebb_map, local_map: HashMap::new(), comments: HashMap::new(), + constants: &mut cx.constants, }; let fx = &mut fx; @@ -458,6 +459,8 @@ fn trans_int_binop<'a, 'tcx: 'a>(fx: &mut FunctionCx<'a, 'tcx>, bin_op: BinOp, l (BinOp::Shl, _) => fx.bcx.ins().ishl(lhs, rhs), (BinOp::Shr, false) => fx.bcx.ins().ushr(lhs, rhs), (BinOp::Shr, true) => fx.bcx.ins().sshr(lhs, rhs), + + // TODO: cast b1 to u8 (BinOp::Eq, _) => fx.bcx.ins().icmp(IntCC::Equal , lhs, rhs), (BinOp::Lt, false) => fx.bcx.ins().icmp(IntCC::UnsignedLessThan , lhs, rhs), (BinOp::Lt, true) => fx.bcx.ins().icmp(IntCC::SignedLessThan , lhs, rhs), @@ -468,6 +471,7 @@ fn trans_int_binop<'a, 'tcx: 'a>(fx: &mut FunctionCx<'a, 'tcx>, bin_op: BinOp, l (BinOp::Ge, true) => fx.bcx.ins().icmp(IntCC::SignedGreaterThanOrEqual , lhs, rhs), (BinOp::Gt, false) => fx.bcx.ins().icmp(IntCC::UnsignedGreaterThan , lhs, rhs), (BinOp::Gt, true) => fx.bcx.ins().icmp(IntCC::SignedGreaterThan , lhs, rhs), + (BinOp::Offset, _) => bug!("bin op Offset on non ptr lhs: {:?} rhs: {:?}", lhs, rhs), }; // TODO: return correct value for checked binops diff --git a/src/common.rs b/src/common.rs index 83f992380c0..5e3433410ee 100644 --- a/src/common.rs +++ b/src/common.rs @@ -6,7 +6,7 @@ use std::fmt; use syntax::ast::{IntTy, UintTy}; use self::rustc_target::spec::{HasTargetSpec, Target}; -use cranelift_module::{Module, Linkage, FuncId}; +use cranelift_module::{Module, Linkage, FuncId, DataId}; use prelude::*; @@ -56,7 +56,7 @@ fn cton_type_from_ty<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> return None; } } - TypeVariants::TyParam(_) => bug!("{:?}", ty), + TypeVariants::TyParam(_) => bug!("{:?}: {:?}", ty, ty.sty), _ => return None, }) } @@ -288,6 +288,7 @@ pub fn cton_sig_from_instance<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, inst: I pub fn cton_sig_from_mono_fn_sig<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sig: PolyFnSig<'tcx>) -> Signature { // TODO: monomorphize signature + // TODO: this should likely not use skip_binder() let sig = sig.skip_binder(); let inputs = sig.inputs(); @@ -334,6 +335,7 @@ pub struct FunctionCx<'a, 'tcx: 'a> { pub ebb_map: HashMap, pub local_map: HashMap>, pub comments: HashMap, + pub constants: &'a mut HashMap, } impl<'a, 'tcx: 'a> fmt::Debug for FunctionCx<'a, 'tcx> { diff --git a/src/constant.rs b/src/constant.rs index ab3e4376a82..a4f5032fb32 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -1,8 +1,9 @@ use prelude::*; +use rustc::mir::interpret::{GlobalId, AllocId, read_target_uint}; +use rustc_mir::interpret::{CompileTimeEvaluator, Memory, MemoryKind}; +use cranelift_module::*; pub fn trans_constant<'a, 'tcx: 'a>(fx: &mut FunctionCx<'a, 'tcx>, const_: &Constant<'tcx>) -> CValue<'tcx> { - use rustc::mir::interpret::{Scalar, ConstValue, GlobalId}; - let value = match const_.literal { Literal::Value { value } => value, Literal::Promoted { index } => fx @@ -32,6 +33,74 @@ pub fn trans_constant<'a, 'tcx: 'a>(fx: &mut FunctionCx<'a, 'tcx>, const_: &Cons let func_ref = fx.get_function_ref(Instance::new(def_id, substs)); CValue::Func(func_ref, fx.layout_of(const_.ty)) } - _ => unimplemented!("value {:?} ty {:?}", value, const_.ty), + _ => { + let mut memory = Memory::::new(fx.tcx.at(DUMMY_SP), ()); + let alloc = fx.tcx.const_value_to_allocation(value); + //println!("const value: {:?} allocation: {:?}", value, alloc); + let alloc_id = memory.allocate_value(alloc.clone(), MemoryKind::Stack).unwrap(); + let data_id = get_global_for_alloc_id(fx, &memory, alloc_id); + let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); + // TODO: does global_value return a ptr of a val? + let global_ptr = fx.bcx.ins().global_value(types::I64, local_data_id); + CValue::ByRef(global_ptr, layout) + } } -} \ No newline at end of file +} + +// If ret.1 is true, then the global didn't exist before +fn define_global_for_alloc_id(fx: &mut FunctionCx, alloc_id: AllocId, todo: &mut HashMap) -> (DataId, bool) { + use std::collections::hash_map::Entry; + match fx.constants.entry(alloc_id) { + Entry::Occupied(mut occ) => { + (*occ.get_mut(), false) + } + Entry::Vacant(vac) => { + let data_id = fx.module.declare_data(&alloc_id.0.to_string(), Linkage::Local, false).unwrap(); + todo.insert(alloc_id, data_id); + vac.insert(data_id); + (data_id, true) + } + } +} + +fn get_global_for_alloc_id(fx: &mut FunctionCx, memory: &Memory, alloc_id: AllocId) -> DataId { + if let Some(data_id) = fx.constants.get(&alloc_id) { + return *data_id; + } + + let mut todo = HashMap::new(); + let mut done = HashSet::new(); + define_global_for_alloc_id(fx, alloc_id, &mut todo); + + while let Some((alloc_id, data_id)) = { let next = todo.drain().next(); next } { + println!("cur: {:?}:{:?} todo: {:?} done: {:?}", alloc_id, data_id, todo, done); + + let alloc = memory.get(alloc_id).unwrap(); + let mut data_ctx = DataContext::new(); + + data_ctx.define(alloc.bytes.to_vec().into_boxed_slice(), Writability::Readonly); + + for &(offset, reloc) in alloc.relocations.iter() { + let data_id = define_global_for_alloc_id(fx, reloc, &mut todo).0; + + let reloc_offset = { + let endianness = memory.endianness(); + let offset = offset.bytes() as usize; + let ptr_size = fx.tcx.data_layout.pointer_size; + let bytes = &alloc.bytes[offset..offset + ptr_size.bytes() as usize]; + read_target_uint(endianness, bytes).unwrap() + }; + + // TODO: is this a correct usage of the api + let global_value = fx.module.declare_data_in_data(data_id, &mut data_ctx); + data_ctx.write_data_addr(reloc_offset as u32, global_value, 0); + } + + fx.module.define_data(data_id, &data_ctx).unwrap(); + done.insert(data_id); + } + for data_id in done.drain() { + fx.module.finalize_data(data_id); + } + *fx.constants.get(&alloc_id).unwrap() +} diff --git a/src/lib.rs b/src/lib.rs index e8cab41d810..dc640838b6b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,12 +40,13 @@ mod pretty_clif; mod prelude { pub use std::any::Any; - pub use std::collections::HashMap; + pub use std::collections::{HashMap, HashSet}; pub use syntax::codemap::DUMMY_SP; pub use rustc::hir::def_id::{DefId, LOCAL_CRATE}; pub use rustc::mir; pub use rustc::mir::*; + pub use rustc::mir::interpret::AllocId; pub use rustc::session::Session; pub use rustc::ty::layout::{self, LayoutOf, TyLayout, Size}; pub use rustc::ty::{ @@ -60,7 +61,7 @@ mod prelude { }; pub use cranelift::codegen::Context; pub use cranelift::prelude::*; - pub use cranelift_module::{Module, Backend, FuncId, Linkage}; + pub use cranelift_module::{Module, Backend, FuncId, DataId, Linkage}; pub use cranelift_simplejit::{SimpleJITBuilder, SimpleJITBackend}; pub use common::Variable; @@ -75,6 +76,7 @@ pub struct CodegenCx<'a, 'tcx: 'a, B: Backend + 'a> { pub tcx: TyCtxt<'a, 'tcx, 'tcx>, pub module: &'a mut Module, pub def_id_fn_id_map: &'a mut HashMap, FuncId>, + pub constants: HashMap, } struct CraneliftCodegenBackend(()); @@ -176,6 +178,7 @@ impl CodegenBackend for CraneliftCodegenBackend { tcx, module: &mut module, def_id_fn_id_map: &mut def_id_fn_id_map, + constants: HashMap::new(), }; for mono_item in