-use rustc::ty::adjustment::PointerCast;
+use rustc_middle::ty::adjustment::PointerCast;
+use rustc_index::vec::IndexVec;
use crate::prelude::*;
-pub fn trans_fn<'clif, 'tcx, B: Backend + 'static>(
- cx: &mut crate::CodegenCx<'clif, 'tcx, B>,
+pub(crate) fn trans_fn<'tcx, B: Backend + 'static>(
+ cx: &mut crate::CodegenCx<'tcx, B>,
instance: Instance<'tcx>,
linkage: Linkage,
) {
let tcx = cx.tcx;
- let mir = *tcx.instance_mir(instance.def);
+ let mir = tcx.instance_mir(instance.def);
// Declare function
let (name, sig) = get_function_name_and_sig(tcx, cx.module.isa().triple(), instance, false);
let func_id = cx.module.declare_function(&name, linkage, &sig).unwrap();
- let mut debug_context = cx
- .debug_context
- .as_mut()
- .map(|debug_context| FunctionDebugContext::new(debug_context, instance, func_id, &name));
// Make FunctionBuilder
- let mut func = Function::with_name_signature(ExternalName::user(0, 0), sig);
- func.collect_debug_info();
+ let context = &mut cx.cached_context;
+ context.clear();
+ context.func.name = ExternalName::user(0, func_id.as_u32());
+ context.func.signature = sig;
+ context.func.collect_debug_info();
let mut func_ctx = FunctionBuilderContext::new();
- let mut bcx = FunctionBuilder::new(&mut func, &mut func_ctx);
+ let mut bcx = FunctionBuilder::new(&mut context.func, &mut func_ctx);
- // Predefine ebb's
- let start_ebb = bcx.create_ebb();
- let mut ebb_map: HashMap<BasicBlock, Ebb> = HashMap::new();
- for (bb, _bb_data) in mir.basic_blocks().iter_enumerated() {
- ebb_map.insert(bb, bcx.create_ebb());
- }
+ // Predefine blocks
+ let start_block = bcx.create_block();
+ let block_map: IndexVec<BasicBlock, Block> = (0..mir.basic_blocks().len()).map(|_| bcx.create_block()).collect();
// Make FunctionCx
let pointer_type = cx.module.target_config().pointer_type();
let mut fx = FunctionCx {
tcx,
- module: cx.module,
+ module: &mut cx.module,
pointer_type,
instance,
mir,
bcx,
- ebb_map,
- local_map: HashMap::new(),
+ block_map,
+ local_map: FxHashMap::with_capacity_and_hasher(mir.local_decls.len(), Default::default()),
+ caller_location: None, // set by `codegen_fn_prelude`
+ cold_blocks: EntitySet::new(),
clif_comments,
constants_cx: &mut cx.constants_cx,
- caches: &mut cx.caches,
+ vtables: &mut cx.vtables,
source_info_set: indexmap::IndexSet::new(),
};
- crate::abi::codegen_fn_prelude(&mut fx, start_ebb);
- codegen_fn_content(&mut fx);
+ let arg_uninhabited = fx.mir.args_iter().any(|arg| fx.layout_of(fx.monomorphize(&fx.mir.local_decls[arg].ty)).abi.is_uninhabited());
+
+ if arg_uninhabited {
+ fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]);
+ fx.bcx.switch_to_block(fx.block_map[START_BLOCK]);
+ crate::trap::trap_unreachable(&mut fx, "function has uninhabited argument");
+ } else {
+ tcx.sess.time("codegen clif ir", || {
+ tcx.sess.time("codegen prelude", || crate::abi::codegen_fn_prelude(&mut fx, start_block));
+ codegen_fn_content(&mut fx);
+ });
+ }
// Recover all necessary data from fx, before accessing func will prevent future access to it.
let instance = fx.instance;
- let clif_comments = fx.clif_comments;
+ let mut clif_comments = fx.clif_comments;
let source_info_set = fx.source_info_set;
let local_map = fx.local_map;
+ let cold_blocks = fx.cold_blocks;
- #[cfg(debug_assertions)]
- crate::pretty_clif::write_clif_file(cx.tcx, "unopt", instance, &func, &clif_comments, None);
+ crate::pretty_clif::write_clif_file(
+ cx.tcx,
+ "unopt",
+ None,
+ instance,
+ &context,
+ &clif_comments,
+ );
// Verify function
- verify_func(tcx, &clif_comments, &func);
+ verify_func(tcx, &clif_comments, &context.func);
+
+ // Perform rust specific optimizations
+ tcx.sess.time("optimize clif ir", || {
+ crate::optimize::optimize_function(tcx, instance, context, &cold_blocks, &mut clif_comments);
+ });
+
+ // If the return block is not reachable, then the SSA builder may have inserted a `iconst.i128`
+ // instruction, which doesn't have an encoding.
+ context.compute_cfg();
+ context.compute_domtree();
+ context.eliminate_unreachable_code(cx.module.isa()).unwrap();
// Define function
- let context = &mut cx.caches.context;
- context.func = func;
- cx.module.define_function(func_id, context).unwrap();
+ let module = &mut cx.module;
+ tcx.sess.time(
+ "define function",
+ || module.define_function(
+ func_id,
+ context,
+ &mut cranelift_codegen::binemit::NullTrapSink {},
+ ).unwrap(),
+ );
// Write optimized function to file for debugging
- #[cfg(debug_assertions)]
- {
- let value_ranges = context
- .build_value_labels_ranges(cx.module.isa())
- .expect("value location ranges");
-
- crate::pretty_clif::write_clif_file(
- cx.tcx,
- "opt",
- instance,
- &context.func,
- &clif_comments,
- Some(&value_ranges),
- );
- }
+ crate::pretty_clif::write_clif_file(
+ cx.tcx,
+ "opt",
+ Some(cx.module.isa()),
+ instance,
+ &context,
+ &clif_comments,
+ );
// Define debuginfo for function
let isa = cx.module.isa();
- debug_context
- .as_mut()
- .map(|x| x.define(context, isa, &source_info_set, local_map));
+ let debug_context = &mut cx.debug_context;
+ let unwind_context = &mut cx.unwind_context;
+ tcx.sess.time("generate debug info", || {
+ if let Some(debug_context) = debug_context {
+ debug_context.define_function(instance, func_id, &name, isa, context, &source_info_set, local_map);
+ }
+ unwind_context.add_function(func_id, &context, isa);
+ });
// Clear context to make it usable for the next function
context.clear();
}
-fn verify_func(tcx: TyCtxt, writer: &crate::pretty_clif::CommentWriter, func: &Function) {
- let flags = settings::Flags::new(settings::builder());
- match ::cranelift::codegen::verify_function(&func, &flags) {
- Ok(_) => {}
- Err(err) => {
- tcx.sess.err(&format!("{:?}", err));
- let pretty_error = ::cranelift::codegen::print_errors::pretty_verifier_error(
- &func,
- None,
- Some(Box::new(writer)),
- err,
- );
- tcx.sess
- .fatal(&format!("cranelift verify error:\n{}", pretty_error));
+pub(crate) fn verify_func(tcx: TyCtxt<'_>, writer: &crate::pretty_clif::CommentWriter, func: &Function) {
+ tcx.sess.time("verify clif ir", || {
+ let flags = cranelift_codegen::settings::Flags::new(cranelift_codegen::settings::builder());
+ match cranelift_codegen::verify_function(&func, &flags) {
+ Ok(_) => {}
+ Err(err) => {
+ tcx.sess.err(&format!("{:?}", err));
+ let pretty_error = cranelift_codegen::print_errors::pretty_verifier_error(
+ &func,
+ None,
+ Some(Box::new(writer)),
+ err,
+ );
+ tcx.sess
+ .fatal(&format!("cranelift verify error:\n{}", pretty_error));
+ }
}
- }
+ });
}
fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, impl Backend>) {
for (bb, bb_data) in fx.mir.basic_blocks().iter_enumerated() {
+ let block = fx.get_block(bb);
+ fx.bcx.switch_to_block(block);
+
if bb_data.is_cleanup {
// Unwinding after panicking is not supported
continue;
- }
- let ebb = fx.get_ebb(bb);
- fx.bcx.switch_to_block(ebb);
+ // FIXME once unwinding is supported uncomment next lines
+ // // Unwinding is unlikely to happen, so mark cleanup block's as cold.
+ // fx.cold_blocks.insert(block);
+ }
fx.bcx.ins().nop();
for stmt in &bb_data.statements {
fx.set_debug_loc(stmt.source_info);
- trans_stmt(fx, ebb, stmt);
+ trans_stmt(fx, block, stmt);
}
#[cfg(debug_assertions)]
.kind
.fmt_head(&mut terminator_head)
.unwrap();
- let inst = fx.bcx.func.layout.last_inst(ebb).unwrap();
+ let inst = fx.bcx.func.layout.last_inst(block).unwrap();
fx.add_comment(inst, terminator_head);
}
match &bb_data.terminator().kind {
TerminatorKind::Goto { target } => {
- let ebb = fx.get_ebb(*target);
- fx.bcx.ins().jump(ebb, &[]);
+ if let TerminatorKind::Return = fx.mir[*target].terminator().kind {
+ let mut can_immediately_return = true;
+ for stmt in &fx.mir[*target].statements {
+ if let StatementKind::StorageDead(_) = stmt.kind {
+ } else {
+ // FIXME Can sometimes happen, see rust-lang/rust#70531
+ can_immediately_return = false;
+ break;
+ }
+ }
+
+ if can_immediately_return {
+ crate::abi::codegen_return(fx);
+ continue;
+ }
+ }
+
+ let block = fx.get_block(*target);
+ fx.bcx.ins().jump(block, &[]);
}
TerminatorKind::Return => {
crate::abi::codegen_return(fx);
cleanup: _,
} => {
if !fx.tcx.sess.overflow_checks() {
- if let mir::interpret::PanicInfo::OverflowNeg = *msg {
- let target = fx.get_ebb(*target);
+ if let mir::AssertKind::OverflowNeg(_) = *msg {
+ let target = fx.get_block(*target);
fx.bcx.ins().jump(target, &[]);
continue;
}
}
let cond = trans_operand(fx, cond).load_scalar(fx);
- let target = fx.get_ebb(*target);
+
+ let target = fx.get_block(*target);
+ let failure = fx.bcx.create_block();
+ fx.cold_blocks.insert(failure);
+
if *expected {
- fx.bcx.ins().brnz(cond, target, &[]);
+ fx.bcx.ins().brz(cond, failure, &[]);
} else {
- fx.bcx.ins().brz(cond, target, &[]);
+ fx.bcx.ins().brnz(cond, failure, &[]);
};
- trap_panic(
- fx,
- format!(
- "[panic] Assert {:?} at {:?} failed.",
- msg,
- bb_data.terminator().source_info.span
- ),
- );
+ fx.bcx.ins().jump(target, &[]);
+
+ fx.bcx.switch_to_block(failure);
+
+ let location = fx.get_caller_location(bb_data.terminator().source_info.span).load_scalar(fx);
+
+ let args;
+ let lang_item = match msg {
+ AssertKind::BoundsCheck { ref len, ref index } => {
+ let len = trans_operand(fx, len).load_scalar(fx);
+ let index = trans_operand(fx, index).load_scalar(fx);
+ args = [index, len, location];
+ rustc_hir::lang_items::PanicBoundsCheckFnLangItem
+ }
+ _ => {
+ let msg_str = msg.description();
+ let msg_ptr = fx.anonymous_str("assert", msg_str);
+ let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap());
+ args = [msg_ptr, msg_len, location];
+ rustc_hir::lang_items::PanicFnLangItem
+ }
+ };
+
+ let def_id = fx.tcx.lang_items().require(lang_item).unwrap_or_else(|s| {
+ fx.tcx.sess.span_fatal(bb_data.terminator().source_info.span, &s)
+ });
+
+ let instance = Instance::mono(fx.tcx, def_id);
+ let symbol_name = fx.tcx.symbol_name(instance).name.as_str();
+
+ fx.lib_call(&*symbol_name, vec![fx.pointer_type, fx.pointer_type, fx.pointer_type], vec![], &args);
+
+ crate::trap::trap_unreachable(fx, "panic lang item returned");
}
TerminatorKind::SwitchInt {
targets,
} => {
let discr = trans_operand(fx, discr).load_scalar(fx);
- let mut switch = ::cranelift::frontend::Switch::new();
+ let mut switch = ::cranelift_frontend::Switch::new();
for (i, value) in values.iter().enumerate() {
- let ebb = fx.get_ebb(targets[i]);
- switch.set_entry(*value as u64, ebb);
+ let block = fx.get_block(targets[i]);
+ switch.set_entry(*value as u64, block);
}
- let otherwise_ebb = fx.get_ebb(targets[targets.len() - 1]);
- switch.emit(&mut fx.bcx, discr, otherwise_ebb);
+ let otherwise_block = fx.get_block(targets[targets.len() - 1]);
+ switch.emit(&mut fx.bcx, discr, otherwise_block);
}
TerminatorKind::Call {
func,
args,
destination,
+ fn_span,
cleanup: _,
from_hir_call: _,
} => {
- crate::abi::codegen_terminator_call(
+ fx.tcx.sess.time("codegen call", || crate::abi::codegen_terminator_call(
fx,
+ *fn_span,
+ block,
func,
args,
- destination,
- bb_data.terminator().source_info.span,
- );
+ *destination,
+ ));
+ }
+ TerminatorKind::InlineAsm {
+ template,
+ operands,
+ options: _,
+ destination,
+ line_spans: _,
+ } => {
+ match template {
+ &[] => {
+ assert_eq!(operands, &[]);
+ match *destination {
+ Some(destination) => {
+ let destination_block = fx.get_block(destination);
+ fx.bcx.ins().jump(destination_block, &[]);
+ }
+ None => bug!(),
+ }
+
+ // Black box
+ }
+ _ => fx.tcx.sess.span_fatal(bb_data.terminator().source_info.span, "Inline assembly is not supported"),
+ }
}
TerminatorKind::Resume | TerminatorKind::Abort => {
trap_unreachable(fx, "[corruption] Unwinding bb reached.");
trap_unreachable(fx, "[corruption] Hit unreachable code.");
}
TerminatorKind::Yield { .. }
- | TerminatorKind::FalseEdges { .. }
+ | TerminatorKind::FalseEdge { .. }
| TerminatorKind::FalseUnwind { .. }
| TerminatorKind::DropAndReplace { .. }
| TerminatorKind::GeneratorDrop => {
bug!("shouldn't exist at trans {:?}", bb_data.terminator());
}
TerminatorKind::Drop {
- location,
+ place,
target,
unwind: _,
} => {
- let drop_place = trans_place(fx, location);
- crate::abi::codegen_drop(fx, drop_place);
+ let drop_place = trans_place(fx, *place);
+ crate::abi::codegen_drop(fx, bb_data.terminator().source_info.span, drop_place);
- let target_ebb = fx.get_ebb(*target);
- fx.bcx.ins().jump(target_ebb, &[]);
+ let target_block = fx.get_block(*target);
+ fx.bcx.ins().jump(target_block, &[]);
}
};
}
fn trans_stmt<'tcx>(
fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
- cur_ebb: Ebb,
+ #[allow(unused_variables)]
+ cur_block: Block,
stmt: &Statement<'tcx>,
) {
- let _print_guard = PrintOnPanic(|| format!("stmt {:?}", stmt));
+ let _print_guard = crate::PrintOnPanic(|| format!("stmt {:?}", stmt));
fx.set_debug_loc(stmt.source_info);
- #[cfg(debug_assertions)]
+ #[cfg(false_debug_assertions)]
match &stmt.kind {
StatementKind::StorageLive(..) | StatementKind::StorageDead(..) => {} // Those are not very useful
_ => {
- let inst = fx.bcx.func.layout.last_inst(cur_ebb).unwrap();
+ let inst = fx.bcx.func.layout.last_inst(cur_block).unwrap();
fx.add_comment(inst, format!("{:?}", stmt));
}
}
place,
variant_index,
} => {
- let place = trans_place(fx, place);
+ let place = trans_place(fx, **place);
crate::discriminant::codegen_set_discriminant(fx, place, *variant_index);
}
StatementKind::Assign(to_place_and_rval) => {
- let lval = trans_place(fx, &to_place_and_rval.0);
+ let lval = trans_place(fx, to_place_and_rval.0);
let dest_layout = lval.layout();
match &to_place_and_rval.1 {
Rvalue::Use(operand) => {
let val = trans_operand(fx, operand);
lval.write_cvalue(fx, val);
}
- Rvalue::Ref(_, _, place) => {
- let place = trans_place(fx, place);
+ Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
+ let place = trans_place(fx, *place);
place.write_place_ref(fx, lval);
}
+ Rvalue::ThreadLocalRef(def_id) => {
+ let val = crate::constant::codegen_tls_ref(fx, *def_id, lval.layout());
+ lval.write_cvalue(fx, val);
+ }
Rvalue::BinaryOp(bin_op, lhs, rhs) => {
let lhs = trans_operand(fx, lhs);
let rhs = trans_operand(fx, rhs);
UnOp::Not => {
match layout.ty.kind {
ty::Bool => {
- let val = fx.bcx.ins().uextend(types::I32, val); // WORKAROUND for CraneStation/cranelift#466
let res = fx.bcx.ins().icmp_imm(IntCC::Equal, val, 0);
CValue::by_val(fx.bcx.ins().bint(types::I8, res), layout)
}
ty::Uint(_) | ty::Int(_) => {
CValue::by_val(fx.bcx.ins().bnot(val), layout)
}
- _ => unimplemented!("un op Not for {:?}", layout.ty),
+ _ => unreachable!("un op Not for {:?}", layout.ty),
}
}
UnOp::Neg => match layout.ty.kind {
- ty::Int(_) => {
- let zero = CValue::const_val(fx, layout.ty, 0);
+ ty::Int(IntTy::I128) => {
+ // FIXME remove this case once ineg.i128 works
+ let zero = CValue::const_val(fx, layout, 0);
crate::num::trans_int_binop(fx, BinOp::Sub, zero, operand)
}
+ ty::Int(_) => {
+ CValue::by_val(fx.bcx.ins().ineg(val), layout)
+ }
ty::Float(_) => {
CValue::by_val(fx.bcx.ins().fneg(val), layout)
}
- _ => unimplemented!("un op Neg for {:?}", layout.ty),
+ _ => unreachable!("un op Neg for {:?}", layout.ty),
},
};
lval.write_cvalue(fx, res);
match from_ty.kind {
ty::FnDef(def_id, substs) => {
let func_ref = fx.get_function_ref(
- Instance::resolve(fx.tcx, ParamEnv::reveal_all(), def_id, substs)
+ Instance::resolve_for_fn_ptr(fx.tcx, ParamEnv::reveal_all(), def_id, substs)
.unwrap(),
);
let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref);
| Rvalue::Cast(CastKind::Pointer(PointerCast::ArrayToPointer), operand, to_ty) => {
let to_layout = fx.layout_of(fx.monomorphize(to_ty));
let operand = trans_operand(fx, operand);
- lval.write_cvalue(fx, operand.unchecked_cast_to(to_layout));
+ lval.write_cvalue(fx, operand.cast_pointer_to(to_layout));
}
Rvalue::Cast(CastKind::Misc, operand, to_ty) => {
let operand = trans_operand(fx, operand);
if is_fat_ptr(fx, from_ty) {
if is_fat_ptr(fx, to_ty) {
// fat-ptr -> fat-ptr
- lval.write_cvalue(fx, operand.unchecked_cast_to(dest_layout));
+ lval.write_cvalue(fx, operand.cast_pointer_to(dest_layout));
} else {
// fat-ptr -> thin-ptr
let (ptr, _extra) = operand.load_scalar_pair(fx);
operand.unsize_value(fx, lval);
}
Rvalue::Discriminant(place) => {
- let place = trans_place(fx, place);
+ let place = trans_place(fx, *place);
let value = place.to_cvalue(fx);
let discr =
crate::discriminant::codegen_get_discriminant(fx, value, dest_layout);
}
Rvalue::Repeat(operand, times) => {
let operand = trans_operand(fx, operand);
- for i in 0..*times {
+ let times = fx
+ .monomorphize(times)
+ .eval(fx.tcx, ParamEnv::reveal_all())
+ .val
+ .try_to_bits(fx.tcx.data_layout.pointer_size)
+ .unwrap();
+ for i in 0..times {
let index = fx.bcx.ins().iconst(fx.pointer_type, i as i64);
let to = lval.place_index(fx, index);
to.write_cvalue(fx, operand);
}
}
Rvalue::Len(place) => {
- let place = trans_place(fx, place);
+ let place = trans_place(fx, *place);
let usize_layout = fx.layout_of(fx.tcx.types.usize);
let len = codegen_array_len(fx, place);
lval.write_cvalue(fx, CValue::by_val(len, usize_layout));
}
Rvalue::NullaryOp(NullOp::Box, content_ty) => {
- use rustc::middle::lang_items::ExchangeMallocFnLangItem;
+ use rustc_hir::lang_items::ExchangeMallocFnLangItem;
let usize_type = fx.clif_type(fx.tcx.types.usize).unwrap();
let content_ty = fx.monomorphize(content_ty);
assert!(lval
.layout()
.ty
- .is_sized(fx.tcx.at(DUMMY_SP), ParamEnv::reveal_all()));
+ .is_sized(fx.tcx.at(stmt.source_info.span), ParamEnv::reveal_all()));
let ty_size = fx.layout_of(fx.monomorphize(ty)).size.bytes();
- let val = CValue::const_val(fx, fx.tcx.types.usize, ty_size.into());
+ let val = CValue::const_val(fx, fx.layout_of(fx.tcx.types.usize), ty_size.into());
lval.write_cvalue(fx, val);
}
Rvalue::Aggregate(kind, operands) => match **kind {
| StatementKind::Retag { .. }
| StatementKind::AscribeUserType(..) => {}
- StatementKind::InlineAsm(asm) => {
- use syntax::ast::Name;
- let InlineAsm {
+ StatementKind::LlvmInlineAsm(asm) => {
+ use rustc_span::symbol::Symbol;
+ let LlvmInlineAsm {
asm,
outputs: _,
inputs: _,
} = &**asm;
- let rustc::hir::InlineAsmInner {
+ let rustc_hir::LlvmInlineAsmInner {
asm: asm_code, // Name
outputs, // Vec<Name>
inputs, // Vec<Name>
clobbers, // Vec<Name>
volatile, // bool
alignstack, // bool
- dialect: _, // syntax::ast::AsmDialect
+ dialect: _, // rustc_ast::ast::AsmDialect
asm_str_style: _,
} = asm;
match &*asm_code.as_str() {
- "" => {
- assert_eq!(inputs, &[Name::intern("r")]);
- assert!(outputs.is_empty(), "{:?}", outputs);
-
- // Black box
- }
- "cpuid" | "cpuid\n" => {
- assert_eq!(inputs, &[Name::intern("{eax}"), Name::intern("{ecx}")]);
-
- assert_eq!(outputs.len(), 4);
- for (i, c) in (&["={eax}", "={ebx}", "={ecx}", "={edx}"])
- .iter()
- .enumerate()
- {
- assert_eq!(&outputs[i].constraint.as_str(), c);
- assert!(!outputs[i].is_rw);
- assert!(!outputs[i].is_indirect);
- }
-
- assert_eq!(clobbers, &[Name::intern("rbx")]);
-
- assert!(!volatile);
- assert!(!alignstack);
-
+ cpuid if cpuid.contains("cpuid") => {
crate::trap::trap_unimplemented(
fx,
"__cpuid_count arch intrinsic is not supported",
);
}
"xgetbv" => {
- assert_eq!(inputs, &[Name::intern("{ecx}")]);
+ assert_eq!(inputs, &[Symbol::intern("{ecx}")]);
assert_eq!(outputs.len(), 2);
for (i, c) in (&["={eax}", "={edx}"]).iter().enumerate() {
crate::trap::trap_unimplemented(fx, "_xgetbv arch intrinsic is not supported");
}
- _ if fx.tcx.symbol_name(fx.instance).name.as_str() == "__rust_probestack" => {
- crate::trap::trap_unimplemented(fx, "__rust_probestack is not supported");
+ // ___chkstk, ___chkstk_ms and __alloca are only used on Windows
+ _ if fx.tcx.symbol_name(fx.instance).name.as_str().starts_with("___chkstk") => {
+ crate::trap::trap_unimplemented(fx, "Stack probes are not supported");
+ }
+ _ if fx.tcx.symbol_name(fx.instance).name.as_str() == "__alloca" => {
+ crate::trap::trap_unimplemented(fx, "Alloca is not supported");
}
- _ => unimpl!("Inline assembly is not supported"),
+ // Used in sys::windows::abort_internal
+ "int $$0x29" => {
+ crate::trap::trap_unimplemented(fx, "Windows abort");
+ }
+ _ => fx.tcx.sess.span_fatal(stmt.source_info.span, "Inline assembly is not supported"),
}
}
}
) -> Value {
match place.layout().ty.kind {
ty::Array(_elem_ty, len) => {
- let len = crate::constant::force_eval_const(fx, len)
+ let len = fx.monomorphize(&len)
+ .eval(fx.tcx, ParamEnv::reveal_all())
.eval_usize(fx.tcx, ParamEnv::reveal_all()) as i64;
fx.bcx.ins().iconst(fx.pointer_type, len)
}
ty::Slice(_elem_ty) => place
- .to_ptr_maybe_unsized(fx)
+ .to_ptr_maybe_unsized()
.1
.expect("Length metadata for slice place"),
_ => bug!("Rvalue::Len({:?})", place),
}
}
-pub fn trans_place<'tcx>(
+pub(crate) fn trans_place<'tcx>(
fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
- place: &Place<'tcx>,
+ place: Place<'tcx>,
) -> CPlace<'tcx> {
- let mut cplace = match &place.base {
- PlaceBase::Local(local) => fx.get_local_place(*local),
- PlaceBase::Static(static_) => match static_.kind {
- StaticKind::Static => {
- // Statics can't be generic, so `static_.ty` doesn't need to be monomorphized.
- crate::constant::codegen_static_ref(fx, static_.def_id, static_.ty)
- }
- StaticKind::Promoted(promoted, substs) => {
- let instance = Instance::new(static_.def_id, fx.monomorphize(&substs));
- let ty = fx.monomorphize(&static_.ty);
- crate::constant::trans_promoted(fx, instance, promoted, ty)
- }
- },
- };
+ let mut cplace = fx.get_local_place(place.local);
- for elem in &*place.projection {
- match *elem {
+ for elem in place.projection {
+ match elem {
PlaceElem::Deref => {
cplace = cplace.place_deref(fx);
}
// slice[from:-to] in Python terms.
match cplace.layout().ty.kind {
- ty::Array(elem_ty, len) => {
+ ty::Array(elem_ty, _len) => {
+ assert!(!from_end, "array subslices are never `from_end`");
let elem_layout = fx.layout_of(elem_ty);
- let ptr = cplace.to_ptr(fx);
- let len = crate::constant::force_eval_const(fx, len)
- .eval_usize(fx.tcx, ParamEnv::reveal_all());
+ let ptr = cplace.to_ptr();
cplace = CPlace::for_ptr(
ptr.offset_i64(fx, elem_layout.size.bytes() as i64 * from as i64),
- fx.layout_of(fx.tcx.mk_array(elem_ty, len - from as u64 - to as u64)),
+ fx.layout_of(fx.tcx.mk_array(elem_ty, to as u64 - from as u64)),
);
}
ty::Slice(elem_ty) => {
assert!(from_end, "slice subslices should be `from_end`");
let elem_layout = fx.layout_of(elem_ty);
- let (ptr, len) = cplace.to_ptr_maybe_unsized(fx);
+ let (ptr, len) = cplace.to_ptr_maybe_unsized();
let len = len.unwrap();
cplace = CPlace::for_ptr_with_extra(
ptr.offset_i64(fx, elem_layout.size.bytes() as i64 * from as i64),
cplace
}
-pub fn trans_operand<'tcx>(
+pub(crate) fn trans_operand<'tcx>(
fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
operand: &Operand<'tcx>,
) -> CValue<'tcx> {
match operand {
Operand::Move(place) | Operand::Copy(place) => {
- let cplace = trans_place(fx, place);
+ let cplace = trans_place(fx, *place);
cplace.to_cvalue(fx)
}
Operand::Constant(const_) => crate::constant::trans_constant(fx, const_),