//! int) and rec(x=int, y=int, z=int) will have the same llvm::Type.
use super::ModuleLlvm;
-use super::ModuleCodegen;
-use super::ModuleKind;
-use super::CachedModuleCodegen;
+use rustc_codegen_ssa::{ModuleCodegen, ModuleKind, CachedModuleCodegen};
+use super::LlvmCodegenBackend;
use abi;
-use back::write::{self, OngoingCodegen};
-use llvm::{self, TypeKind, get_param};
+use back::write;
+use llvm;
use metadata;
use rustc::dep_graph::cgu_reuse_tracker::CguReuse;
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc::mir::mono::{Linkage, Visibility, Stats, CodegenUnitNameBuilder};
use rustc::middle::cstore::{EncodedMetadata};
use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::layout::{self, Align, TyLayout, LayoutOf};
+use rustc::ty::layout::{self, Align, TyLayout, LayoutOf, VariantIdx, HasTyCtxt};
use rustc::ty::query::Providers;
use rustc::middle::cstore::{self, LinkagePreference};
use rustc::middle::exported_symbols;
use rustc::session::config::{self, DebugInfo, EntryFnType, Lto};
use rustc::session::Session;
use rustc_incremental;
-use allocator;
use mir::place::PlaceRef;
-use attributes;
use builder::{Builder, MemFlags};
use callee;
-use common::{C_bool, C_bytes_in_context, C_usize};
use rustc_mir::monomorphize::item::DefPathBasedNames;
-use common::{C_struct_in_context, C_array, val_ty};
-use consts;
-use context::CodegenCx;
-use debuginfo;
-use declare;
+use common;
+use rustc_codegen_ssa::common::{RealPredicate, TypeKind, IntPredicate};
use meth;
use mir;
+use context::CodegenCx;
use monomorphize::Instance;
use monomorphize::partitioning::{CodegenUnit, CodegenUnitExt};
use rustc_codegen_utils::symbol_names_test;
use time_graph;
use mono_item::{MonoItem, MonoItemExt};
-use type_::Type;
-use type_of::LayoutLlvmExt;
+
use rustc::util::nodemap::FxHashMap;
use CrateInfo;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::indexed_vec::Idx;
+
+use interfaces::*;
use std::any::Any;
use std::cmp;
use std::ffi::CString;
+use std::marker;
use std::ops::{Deref, DerefMut};
use std::sync::mpsc;
use std::time::{Instant, Duration};
use rustc_codegen_utils::check_for_rustc_errors_attr;
-pub struct StatRecorder<'a, 'll: 'a, 'tcx: 'll> {
- cx: &'a CodegenCx<'ll, 'tcx>,
+pub struct StatRecorder<'a, 'tcx, Cx: 'a + CodegenMethods<'tcx>> {
+ cx: &'a Cx,
name: Option<String>,
istart: usize,
+ _marker: marker::PhantomData<&'tcx ()>,
}
-impl StatRecorder<'a, 'll, 'tcx> {
- pub fn new(cx: &'a CodegenCx<'ll, 'tcx>, name: String) -> Self {
- let istart = cx.stats.borrow().n_llvm_insns;
+impl<'a, 'tcx, Cx: CodegenMethods<'tcx>> StatRecorder<'a, 'tcx, Cx> {
+ pub fn new(cx: &'a Cx, name: String) -> Self {
+ let istart = cx.stats().borrow().n_llvm_insns;
StatRecorder {
cx,
name: Some(name),
istart,
+ _marker: marker::PhantomData,
}
}
}
-impl Drop for StatRecorder<'a, 'll, 'tcx> {
+impl<'a, 'tcx, Cx: CodegenMethods<'tcx>> Drop for StatRecorder<'a, 'tcx, Cx> {
fn drop(&mut self) {
if self.cx.sess().codegen_stats() {
- let mut stats = self.cx.stats.borrow_mut();
+ let mut stats = self.cx.stats().borrow_mut();
let iend = stats.n_llvm_insns;
stats.fn_stats.push((self.name.take().unwrap(), iend - self.istart));
stats.n_fns += 1;
pub fn bin_op_to_icmp_predicate(op: hir::BinOpKind,
signed: bool)
- -> llvm::IntPredicate {
+ -> IntPredicate {
match op {
- hir::BinOpKind::Eq => llvm::IntEQ,
- hir::BinOpKind::Ne => llvm::IntNE,
- hir::BinOpKind::Lt => if signed { llvm::IntSLT } else { llvm::IntULT },
- hir::BinOpKind::Le => if signed { llvm::IntSLE } else { llvm::IntULE },
- hir::BinOpKind::Gt => if signed { llvm::IntSGT } else { llvm::IntUGT },
- hir::BinOpKind::Ge => if signed { llvm::IntSGE } else { llvm::IntUGE },
+ hir::BinOpKind::Eq => IntPredicate::IntEQ,
+ hir::BinOpKind::Ne => IntPredicate::IntNE,
+ hir::BinOpKind::Lt => if signed { IntPredicate::IntSLT } else { IntPredicate::IntULT },
+ hir::BinOpKind::Le => if signed { IntPredicate::IntSLE } else { IntPredicate::IntULE },
+ hir::BinOpKind::Gt => if signed { IntPredicate::IntSGT } else { IntPredicate::IntUGT },
+ hir::BinOpKind::Ge => if signed { IntPredicate::IntSGE } else { IntPredicate::IntUGE },
op => {
bug!("comparison_op_to_icmp_predicate: expected comparison operator, \
found {:?}",
}
}
-pub fn bin_op_to_fcmp_predicate(op: hir::BinOpKind) -> llvm::RealPredicate {
+pub fn bin_op_to_fcmp_predicate(op: hir::BinOpKind) -> RealPredicate {
match op {
- hir::BinOpKind::Eq => llvm::RealOEQ,
- hir::BinOpKind::Ne => llvm::RealUNE,
- hir::BinOpKind::Lt => llvm::RealOLT,
- hir::BinOpKind::Le => llvm::RealOLE,
- hir::BinOpKind::Gt => llvm::RealOGT,
- hir::BinOpKind::Ge => llvm::RealOGE,
+ hir::BinOpKind::Eq => RealPredicate::RealOEQ,
+ hir::BinOpKind::Ne => RealPredicate::RealUNE,
+ hir::BinOpKind::Lt => RealPredicate::RealOLT,
+ hir::BinOpKind::Le => RealPredicate::RealOLE,
+ hir::BinOpKind::Gt => RealPredicate::RealOGT,
+ hir::BinOpKind::Ge => RealPredicate::RealOGE,
op => {
bug!("comparison_op_to_fcmp_predicate: expected comparison operator, \
found {:?}",
}
}
-pub fn compare_simd_types(
- bx: &Builder<'a, 'll, 'tcx>,
- lhs: &'ll Value,
- rhs: &'ll Value,
+pub fn compare_simd_types<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
+ bx: &Bx,
+ lhs: Bx::Value,
+ rhs: Bx::Value,
t: Ty<'tcx>,
- ret_ty: &'ll Type,
+ ret_ty: Bx::Type,
op: hir::BinOpKind
-) -> &'ll Value {
+) -> Bx::Value {
let signed = match t.sty {
ty::Float(_) => {
let cmp = bin_op_to_fcmp_predicate(op);
/// The `old_info` argument is a bit funny. It is intended for use
/// in an upcast, where the new vtable for an object will be derived
/// from the old one.
-pub fn unsized_info(
- cx: &CodegenCx<'ll, 'tcx>,
+pub fn unsized_info<'tcx, Cx: CodegenMethods<'tcx>>(
+ cx: &Cx,
source: Ty<'tcx>,
target: Ty<'tcx>,
- old_info: Option<&'ll Value>,
-) -> &'ll Value {
- let (source, target) = cx.tcx.struct_lockstep_tails(source, target);
+ old_info: Option<Cx::Value>,
+) -> Cx::Value {
+ let (source, target) = cx.tcx().struct_lockstep_tails(source, target);
match (&source.sty, &target.sty) {
(&ty::Array(_, len), &ty::Slice(_)) => {
- C_usize(cx, len.unwrap_usize(cx.tcx))
+ cx.const_usize(len.unwrap_usize(cx.tcx()))
}
(&ty::Dynamic(..), &ty::Dynamic(..)) => {
// For now, upcasts are limited to changes in marker
old_info.expect("unsized_info: missing old info for trait upcast")
}
(_, &ty::Dynamic(ref data, ..)) => {
- let vtable_ptr = cx.layout_of(cx.tcx.mk_mut_ptr(target))
+ let vtable_ptr = cx.layout_of(cx.tcx().mk_mut_ptr(target))
.field(cx, abi::FAT_PTR_EXTRA);
- consts::ptrcast(meth::get_vtable(cx, source, data.principal()),
- vtable_ptr.llvm_type(cx))
+ cx.static_ptrcast(meth::get_vtable(cx, source, data.principal()),
+ cx.backend_type(vtable_ptr))
}
_ => bug!("unsized_info: invalid unsizing {:?} -> {:?}",
source,
}
/// Coerce `src` to `dst_ty`. `src_ty` must be a thin pointer.
-pub fn unsize_thin_ptr(
- bx: &Builder<'a, 'll, 'tcx>,
- src: &'ll Value,
+pub fn unsize_thin_ptr<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
+ bx: &Bx,
+ src: Bx::Value,
src_ty: Ty<'tcx>,
dst_ty: Ty<'tcx>
-) -> (&'ll Value, &'ll Value) {
+) -> (Bx::Value, Bx::Value) {
debug!("unsize_thin_ptr: {:?} => {:?}", src_ty, dst_ty);
match (&src_ty.sty, &dst_ty.sty) {
(&ty::Ref(_, a, _),
&ty::RawPtr(ty::TypeAndMut { ty: b, .. })) |
(&ty::RawPtr(ty::TypeAndMut { ty: a, .. }),
&ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => {
- assert!(bx.cx.type_is_sized(a));
- let ptr_ty = bx.cx.layout_of(b).llvm_type(bx.cx).ptr_to();
- (bx.pointercast(src, ptr_ty), unsized_info(bx.cx, a, b, None))
+ assert!(bx.cx().type_is_sized(a));
+ let ptr_ty = bx.cx().type_ptr_to(bx.cx().backend_type(bx.cx().layout_of(b)));
+ (bx.pointercast(src, ptr_ty), unsized_info(bx.cx(), a, b, None))
}
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) if def_a.is_box() && def_b.is_box() => {
let (a, b) = (src_ty.boxed_ty(), dst_ty.boxed_ty());
- assert!(bx.cx.type_is_sized(a));
- let ptr_ty = bx.cx.layout_of(b).llvm_type(bx.cx).ptr_to();
- (bx.pointercast(src, ptr_ty), unsized_info(bx.cx, a, b, None))
+ assert!(bx.cx().type_is_sized(a));
+ let ptr_ty = bx.cx().type_ptr_to(bx.cx().backend_type(bx.cx().layout_of(b)));
+ (bx.pointercast(src, ptr_ty), unsized_info(bx.cx(), a, b, None))
}
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
assert_eq!(def_a, def_b);
- let src_layout = bx.cx.layout_of(src_ty);
- let dst_layout = bx.cx.layout_of(dst_ty);
+ let src_layout = bx.cx().layout_of(src_ty);
+ let dst_layout = bx.cx().layout_of(dst_ty);
let mut result = None;
for i in 0..src_layout.fields.count() {
- let src_f = src_layout.field(bx.cx, i);
+ let src_f = src_layout.field(bx.cx(), i);
assert_eq!(src_layout.fields.offset(i).bytes(), 0);
assert_eq!(dst_layout.fields.offset(i).bytes(), 0);
if src_f.is_zst() {
}
assert_eq!(src_layout.size, src_f.size);
- let dst_f = dst_layout.field(bx.cx, i);
+ let dst_f = dst_layout.field(bx.cx(), i);
assert_ne!(src_f.ty, dst_f.ty);
assert_eq!(result, None);
result = Some(unsize_thin_ptr(bx, src, src_f.ty, dst_f.ty));
}
let (lldata, llextra) = result.unwrap();
// HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
- (bx.bitcast(lldata, dst_layout.scalar_pair_element_llvm_type(bx.cx, 0, true)),
- bx.bitcast(llextra, dst_layout.scalar_pair_element_llvm_type(bx.cx, 1, true)))
+ (bx.bitcast(lldata, bx.cx().scalar_pair_element_backend_type(dst_layout, 0, true)),
+ bx.bitcast(llextra, bx.cx().scalar_pair_element_backend_type(dst_layout, 1, true)))
}
_ => bug!("unsize_thin_ptr: called on bad types"),
}
/// Coerce `src`, which is a reference to a value of type `src_ty`,
/// to a value of type `dst_ty` and store the result in `dst`
-pub fn coerce_unsized_into(
- bx: &Builder<'a, 'll, 'tcx>,
- src: PlaceRef<'ll, 'tcx>,
- dst: PlaceRef<'ll, 'tcx>
-) {
+pub fn coerce_unsized_into<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
+ bx: &Bx,
+ src: PlaceRef<'tcx, Bx::Value>,
+ dst: PlaceRef<'tcx, Bx::Value>
+) {
let src_ty = src.layout.ty;
let dst_ty = dst.layout.ty;
let coerce_ptr = || {
- let (base, info) = match src.load(bx).val {
+ let (base, info) = match bx.load_operand(src).val {
OperandValue::Pair(base, info) => {
// fat-ptr to fat-ptr unsize preserves the vtable
// i.e. &'a fmt::Debug+Send => &'a fmt::Debug
// So we need to pointercast the base to ensure
// the types match up.
- let thin_ptr = dst.layout.field(bx.cx, abi::FAT_PTR_ADDR);
- (bx.pointercast(base, thin_ptr.llvm_type(bx.cx)), info)
+ let thin_ptr = dst.layout.field(bx.cx(), abi::FAT_PTR_ADDR);
+ (bx.pointercast(base, bx.cx().backend_type(thin_ptr)), info)
}
OperandValue::Immediate(base) => {
unsize_thin_ptr(bx, base, src_ty, dst_ty)
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
assert_eq!(def_a, def_b);
- for i in 0..def_a.variants[0].fields.len() {
+ for i in 0..def_a.variants[VariantIdx::new(0)].fields.len() {
let src_f = src.project_field(bx, i);
let dst_f = dst.project_field(bx, i);
}
}
-pub fn cast_shift_expr_rhs(
- cx: &Builder<'_, 'll, '_>, op: hir::BinOpKind, lhs: &'ll Value, rhs: &'ll Value
-) -> &'ll Value {
- cast_shift_rhs(op, lhs, rhs, |a, b| cx.trunc(a, b), |a, b| cx.zext(a, b))
+pub fn cast_shift_expr_rhs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
+ bx: &Bx,
+ op: hir::BinOpKind,
+ lhs: Bx::Value,
+ rhs: Bx::Value
+) -> Bx::Value {
+ cast_shift_rhs(bx, op, lhs, rhs, |a, b| bx.trunc(a, b), |a, b| bx.zext(a, b))
}
-fn cast_shift_rhs<'ll, F, G>(op: hir::BinOpKind,
- lhs: &'ll Value,
- rhs: &'ll Value,
- trunc: F,
- zext: G)
- -> &'ll Value
- where F: FnOnce(&'ll Value, &'ll Type) -> &'ll Value,
- G: FnOnce(&'ll Value, &'ll Type) -> &'ll Value
+fn cast_shift_rhs<'a, 'tcx: 'a, F, G, Bx: BuilderMethods<'a, 'tcx>>(
+ bx: &Bx,
+ op: hir::BinOpKind,
+ lhs: Bx::Value,
+ rhs: Bx::Value,
+ trunc: F,
+ zext: G
+) -> Bx::Value
+ where F: FnOnce(
+ Bx::Value,
+ Bx::Type
+ ) -> Bx::Value,
+ G: FnOnce(
+ Bx::Value,
+ Bx::Type
+ ) -> Bx::Value
{
// Shifts may have any size int on the rhs
if op.is_shift() {
- let mut rhs_llty = val_ty(rhs);
- let mut lhs_llty = val_ty(lhs);
- if rhs_llty.kind() == TypeKind::Vector {
- rhs_llty = rhs_llty.element_type()
+ let mut rhs_llty = bx.cx().val_ty(rhs);
+ let mut lhs_llty = bx.cx().val_ty(lhs);
+ if bx.cx().type_kind(rhs_llty) == TypeKind::Vector {
+ rhs_llty = bx.cx().element_type(rhs_llty)
}
- if lhs_llty.kind() == TypeKind::Vector {
- lhs_llty = lhs_llty.element_type()
+ if bx.cx().type_kind(lhs_llty) == TypeKind::Vector {
+ lhs_llty = bx.cx().element_type(lhs_llty)
}
- let rhs_sz = rhs_llty.int_width();
- let lhs_sz = lhs_llty.int_width();
+ let rhs_sz = bx.cx().int_width(rhs_llty);
+ let lhs_sz = bx.cx().int_width(lhs_llty);
if lhs_sz < rhs_sz {
trunc(rhs, lhs_llty)
} else if lhs_sz > rhs_sz {
sess.target.target.options.is_like_msvc
}
-pub fn call_assume(bx: &Builder<'_, 'll, '_>, val: &'ll Value) {
- let assume_intrinsic = bx.cx.get_intrinsic("llvm.assume");
+pub fn call_assume<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
+ bx: &Bx,
+ val: Bx::Value
+) {
+ let assume_intrinsic = bx.cx().get_intrinsic("llvm.assume");
bx.call(assume_intrinsic, &[val], None);
}
-pub fn from_immediate(bx: &Builder<'_, 'll, '_>, val: &'ll Value) -> &'ll Value {
- if val_ty(val) == Type::i1(bx.cx) {
- bx.zext(val, Type::i8(bx.cx))
+pub fn from_immediate<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
+ bx: &Bx,
+ val: Bx::Value
+) -> Bx::Value {
+ if bx.cx().val_ty(val) == bx.cx().type_i1() {
+ bx.zext(val, bx.cx().type_i8())
} else {
val
}
}
-pub fn to_immediate(
- bx: &Builder<'_, 'll, '_>,
- val: &'ll Value,
+pub fn to_immediate<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
+ bx: &Bx,
+ val: Bx::Value,
layout: layout::TyLayout,
-) -> &'ll Value {
+) -> Bx::Value {
if let layout::Abi::Scalar(ref scalar) = layout.abi {
return to_immediate_scalar(bx, val, scalar);
}
val
}
-pub fn to_immediate_scalar(
- bx: &Builder<'_, 'll, '_>,
- val: &'ll Value,
+pub fn to_immediate_scalar<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
+ bx: &Bx,
+ val: Bx::Value,
scalar: &layout::Scalar,
-) -> &'ll Value {
+) -> Bx::Value {
if scalar.is_bool() {
- return bx.trunc(val, Type::i1(bx.cx));
+ return bx.trunc(val, bx.cx().type_i1());
}
val
}
-pub fn call_memcpy(
- bx: &Builder<'_, 'll, '_>,
- dst: &'ll Value,
- dst_align: Align,
- src: &'ll Value,
- src_align: Align,
- n_bytes: &'ll Value,
- flags: MemFlags,
-) {
- if flags.contains(MemFlags::NONTEMPORAL) {
- // HACK(nox): This is inefficient but there is no nontemporal memcpy.
- let val = bx.load(src, src_align);
- let ptr = bx.pointercast(dst, val_ty(val).ptr_to());
- bx.store_with_flags(val, ptr, dst_align, flags);
- return;
- }
- let cx = bx.cx;
- let src_ptr = bx.pointercast(src, Type::i8p(cx));
- let dst_ptr = bx.pointercast(dst, Type::i8p(cx));
- let size = bx.intcast(n_bytes, cx.isize_ty, false);
- let volatile = flags.contains(MemFlags::VOLATILE);
- bx.memcpy(dst_ptr, dst_align.abi(), src_ptr, src_align.abi(), size, volatile);
-}
-
-pub fn memcpy_ty(
- bx: &Builder<'_, 'll, 'tcx>,
- dst: &'ll Value,
+pub fn memcpy_ty<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
+ bx: &Bx,
+ dst: Bx::Value,
dst_align: Align,
- src: &'ll Value,
+ src: Bx::Value,
src_align: Align,
layout: TyLayout<'tcx>,
flags: MemFlags,
return;
}
- call_memcpy(bx, dst, dst_align, src, src_align, C_usize(bx.cx, size), flags);
+ bx.memcpy(dst, dst_align, src, src_align, bx.cx().const_usize(size), flags);
}
-pub fn call_memset(
- bx: &Builder<'_, 'll, '_>,
- ptr: &'ll Value,
- fill_byte: &'ll Value,
- size: &'ll Value,
- align: &'ll Value,
- volatile: bool,
-) -> &'ll Value {
- let ptr_width = &bx.cx.sess().target.target.target_pointer_width;
- let intrinsic_key = format!("llvm.memset.p0i8.i{}", ptr_width);
- let llintrinsicfn = bx.cx.get_intrinsic(&intrinsic_key);
- let volatile = C_bool(bx.cx, volatile);
- bx.call(llintrinsicfn, &[ptr, fill_byte, size, align, volatile], None)
-}
-
-pub fn codegen_instance<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, instance: Instance<'tcx>) {
+pub fn codegen_instance<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
+ cx: &'a Bx::CodegenCx,
+ instance: Instance<'tcx>,
+) {
let _s = if cx.sess().codegen_stats() {
let mut instance_name = String::new();
- DefPathBasedNames::new(cx.tcx, true, true)
+ DefPathBasedNames::new(cx.tcx(), true, true)
.push_def_path(instance.def_id(), &mut instance_name);
Some(StatRecorder::new(cx, instance_name))
} else {
// release builds.
info!("codegen_instance({})", instance);
- let sig = instance.fn_sig(cx.tcx);
- let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
+ let sig = instance.fn_sig(cx.tcx());
+ let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
- let lldecl = cx.instances.borrow().get(&instance).cloned().unwrap_or_else(||
+ let lldecl = cx.instances().borrow().get(&instance).cloned().unwrap_or_else(||
bug!("Instance `{:?}` not already declared", instance));
- cx.stats.borrow_mut().n_closures += 1;
+ cx.stats().borrow_mut().n_closures += 1;
- let mir = cx.tcx.instance_mir(instance.def);
- mir::codegen_mir(cx, lldecl, &mir, instance, sig);
+ let mir = cx.tcx().instance_mir(instance.def);
+ mir::codegen_mir::<Bx>(cx, lldecl, &mir, instance, sig);
}
pub fn set_link_section(llval: &Value, attrs: &CodegenFnAttrs) {
/// Create the `main` function which will initialize the rust runtime and call
/// users main function.
-fn maybe_create_entry_wrapper(cx: &CodegenCx) {
+fn maybe_create_entry_wrapper<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
+ cx: &'a Bx::CodegenCx
+) {
let (main_def_id, span) = match *cx.sess().entry_fn.borrow() {
Some((id, span, _)) => {
- (cx.tcx.hir.local_def_id(id), span)
+ (cx.tcx().hir.local_def_id(id), span)
}
None => return,
};
- let instance = Instance::mono(cx.tcx, main_def_id);
+ let instance = Instance::mono(cx.tcx(), main_def_id);
- if !cx.codegen_unit.contains_item(&MonoItem::Fn(instance)) {
+ if !cx.codegen_unit().contains_item(&MonoItem::Fn(instance)) {
// We want to create the wrapper in the same codegen unit as Rust's main
// function.
return;
}
- let main_llfn = callee::get_fn(cx, instance);
+ let main_llfn = cx.get_fn(instance);
let et = cx.sess().entry_fn.get().map(|e| e.2);
match et {
- Some(EntryFnType::Main) => create_entry_fn(cx, span, main_llfn, main_def_id, true),
- Some(EntryFnType::Start) => create_entry_fn(cx, span, main_llfn, main_def_id, false),
+ Some(EntryFnType::Main) => create_entry_fn::<Bx>(cx, span, main_llfn, main_def_id, true),
+ Some(EntryFnType::Start) => create_entry_fn::<Bx>(cx, span, main_llfn, main_def_id, false),
None => {} // Do nothing.
}
- fn create_entry_fn(
- cx: &CodegenCx<'ll, '_>,
+ fn create_entry_fn<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
+ cx: &'a Bx::CodegenCx,
sp: Span,
- rust_main: &'ll Value,
+ rust_main: Bx::Value,
rust_main_def_id: DefId,
use_start_lang_item: bool,
) {
- let llfty = Type::func(&[Type::c_int(cx), Type::i8p(cx).ptr_to()], Type::c_int(cx));
+ let llfty =
+ cx.type_func(&[cx.type_int(), cx.type_ptr_to(cx.type_i8p())], cx.type_int());
- let main_ret_ty = cx.tcx.fn_sig(rust_main_def_id).output();
+ let main_ret_ty = cx.tcx().fn_sig(rust_main_def_id).output();
// Given that `main()` has no arguments,
// then its return type cannot have
// late-bound regions, since late-bound
// regions must appear in the argument
// listing.
- let main_ret_ty = cx.tcx.erase_regions(
+ let main_ret_ty = cx.tcx().erase_regions(
&main_ret_ty.no_bound_vars().unwrap(),
);
- if declare::get_defined_value(cx, "main").is_some() {
+ if cx.get_defined_value("main").is_some() {
// FIXME: We should be smart and show a better diagnostic here.
cx.sess().struct_span_err(sp, "entry symbol `main` defined multiple times")
.help("did you use #[no_mangle] on `fn main`? Use #[start] instead")
cx.sess().abort_if_errors();
bug!();
}
- let llfn = declare::declare_cfn(cx, "main", llfty);
+ let llfn = cx.declare_cfn("main", llfty);
// `main` should respect same config for frame pointer elimination as rest of code
- attributes::set_frame_pointer_elimination(cx, llfn);
- attributes::apply_target_cpu_attr(cx, llfn);
+ cx.set_frame_pointer_elimination(llfn);
+ cx.apply_target_cpu_attr(llfn);
- let bx = Builder::new_block(cx, llfn, "top");
+ let bx = Bx::new_block(&cx, llfn, "top");
- debuginfo::gdb::insert_reference_to_gdb_debug_scripts_section_global(&bx);
+ bx.insert_reference_to_gdb_debug_scripts_section_global();
// Params from native main() used as args for rust start function
- let param_argc = get_param(llfn, 0);
- let param_argv = get_param(llfn, 1);
- let arg_argc = bx.intcast(param_argc, cx.isize_ty, true);
+ let param_argc = cx.get_param(llfn, 0);
+ let param_argv = cx.get_param(llfn, 1);
+ let arg_argc = bx.intcast(param_argc, cx.type_isize(), true);
let arg_argv = param_argv;
let (start_fn, args) = if use_start_lang_item {
- let start_def_id = cx.tcx.require_lang_item(StartFnLangItem);
+ let start_def_id = cx.tcx().require_lang_item(StartFnLangItem);
let start_fn = callee::resolve_and_get_fn(
cx,
start_def_id,
- cx.tcx.intern_substs(&[main_ret_ty.into()]),
+ cx.tcx().intern_substs(&[main_ret_ty.into()]),
);
- (start_fn, vec![bx.pointercast(rust_main, Type::i8p(cx).ptr_to()),
+ (start_fn, vec![bx.pointercast(rust_main, cx.type_ptr_to(cx.type_i8p())),
arg_argc, arg_argv])
} else {
debug!("using user-defined start fn");
};
let result = bx.call(start_fn, &args, None);
- bx.ret(bx.intcast(result, Type::c_int(cx), true));
+ bx.ret(bx.intcast(result, cx.type_int(), true));
}
}
-fn write_metadata<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
- llvm_module: &ModuleLlvm)
- -> EncodedMetadata {
+pub(crate) fn write_metadata<'a, 'gcx>(
+ tcx: TyCtxt<'a, 'gcx, 'gcx>,
+ llvm_module: &ModuleLlvm
+) -> EncodedMetadata {
use std::io::Write;
use flate2::Compression;
use flate2::write::DeflateEncoder;
DeflateEncoder::new(&mut compressed, Compression::fast())
.write_all(&metadata.raw_data).unwrap();
- let llmeta = C_bytes_in_context(metadata_llcx, &compressed);
- let llconst = C_struct_in_context(metadata_llcx, &[llmeta], false);
+ let llmeta = common::bytes_in_context(metadata_llcx, &compressed);
+ let llconst = common::struct_in_context(metadata_llcx, &[llmeta], false);
let name = exported_symbols::metadata_symbol_name(tcx);
let buf = CString::new(name).unwrap();
let llglobal = unsafe {
- llvm::LLVMAddGlobal(metadata_llmod, val_ty(llconst), buf.as_ptr())
+ llvm::LLVMAddGlobal(metadata_llmod, common::val_ty(llconst), buf.as_ptr())
};
unsafe {
llvm::LLVMSetInitializer(llglobal, llconst);
}
}
-pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- rx: mpsc::Receiver<Box<dyn Any + Send>>)
- -> OngoingCodegen
-{
+pub fn codegen_crate<B: BackendMethods>(
+ backend: B,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ rx: mpsc::Receiver<Box<dyn Any + Send>>
+) -> B::OngoingCodegen {
+
check_for_rustc_errors_attr(tcx);
let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
&["crate"],
Some("metadata")).as_str()
.to_string();
- let metadata_llvm_module = ModuleLlvm::new(tcx.sess, &metadata_cgu_name);
+ let metadata_llvm_module = backend.new_metadata(tcx.sess, &metadata_cgu_name);
let metadata = time(tcx.sess, "write metadata", || {
- write_metadata(tcx, &metadata_llvm_module)
+ backend.write_metadata(tcx, &metadata_llvm_module)
});
tcx.sess.profiler(|p| p.end_activity(ProfileCategory::Codegen));
// Skip crate items and just output metadata in -Z no-codegen mode.
if tcx.sess.opts.debugging_opts.no_codegen ||
!tcx.sess.opts.output_types.should_codegen() {
- let ongoing_codegen = write::start_async_codegen(
+ let ongoing_codegen = backend.start_async_codegen(
tcx,
time_graph,
metadata,
rx,
1);
- ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, metadata_module);
- ongoing_codegen.codegen_finished(tcx);
+ backend.submit_pre_codegened_module_to_llvm(&ongoing_codegen, tcx, metadata_module);
+ backend.codegen_finished(&ongoing_codegen, tcx);
assert_and_save_dep_graph(tcx);
- ongoing_codegen.check_for_errors(tcx.sess);
+ backend.check_for_errors(&ongoing_codegen, tcx.sess);
return ongoing_codegen;
}
}
}
- let ongoing_codegen = write::start_async_codegen(
+ let ongoing_codegen = backend.start_async_codegen(
tcx,
time_graph.clone(),
metadata,
rx,
codegen_units.len());
- let ongoing_codegen = AbortCodegenOnDrop(Some(ongoing_codegen));
+ let ongoing_codegen = AbortCodegenOnDrop::<B>(Some(ongoing_codegen));
// Codegen an allocator shim, if necessary.
//
&["crate"],
Some("allocator")).as_str()
.to_string();
- let modules = ModuleLlvm::new(tcx.sess, &llmod_id);
+ let modules = backend.new_metadata(tcx.sess, &llmod_id);
time(tcx.sess, "write allocator module", || {
- unsafe {
- allocator::codegen(tcx, &modules, kind)
- }
+ backend.codegen_allocator(tcx, &modules, kind)
});
Some(ModuleCodegen {
};
if let Some(allocator_module) = allocator_module {
- ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, allocator_module);
+ backend.submit_pre_codegened_module_to_llvm(&ongoing_codegen, tcx, allocator_module);
}
- ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, metadata_module);
+ backend.submit_pre_codegened_module_to_llvm(&ongoing_codegen, tcx, metadata_module);
// We sort the codegen units by size. This way we can schedule work for LLVM
// a bit more efficiently.
let mut all_stats = Stats::default();
for cgu in codegen_units.into_iter() {
- ongoing_codegen.wait_for_signal_to_codegen_item();
- ongoing_codegen.check_for_errors(tcx.sess);
+ backend.wait_for_signal_to_codegen_item(&ongoing_codegen);
+ backend.check_for_errors(&ongoing_codegen, tcx.sess);
let cgu_reuse = determine_cgu_reuse(tcx, &cgu);
tcx.sess.cgu_reuse_tracker.set_actual_reuse(&cgu.name().as_str(), cgu_reuse);
&format!("codegen {}", cgu.name()))
});
let start_time = Instant::now();
- let stats = compile_codegen_unit(tcx, *cgu.name());
+ let stats = backend.compile_codegen_unit(tcx, *cgu.name());
all_stats.extend(stats);
total_codegen_time += start_time.elapsed();
false
};
}
- ongoing_codegen.codegen_finished(tcx);
+ backend.codegen_finished(&ongoing_codegen, tcx);
// Since the main thread is sometimes blocked during codegen, we keep track
// -Ztime-passes output manually.
}
}
- ongoing_codegen.check_for_errors(tcx.sess);
+ backend.check_for_errors(&ongoing_codegen, tcx.sess);
assert_and_save_dep_graph(tcx);
ongoing_codegen.into_inner()
///
/// In the process of working on rust-lang/rust#55238 a mysterious segfault was
/// stumbled upon. The segfault was never reproduced locally, but it was
-/// suspected to be releated to the fact that codegen worker threads were
+/// suspected to be related to the fact that codegen worker threads were
/// sticking around by the time the main thread was exiting, causing issues.
///
/// This structure is an attempt to fix that issue where the `codegen_aborted`
/// If you see this comment in the code, then it means that this workaround
/// worked! We may yet one day track down the mysterious cause of that
/// segfault...
-struct AbortCodegenOnDrop(Option<OngoingCodegen>);
+struct AbortCodegenOnDrop<B: BackendMethods>(Option<B::OngoingCodegen>);
-impl AbortCodegenOnDrop {
- fn into_inner(mut self) -> OngoingCodegen {
+impl<B: BackendMethods> AbortCodegenOnDrop<B> {
+ fn into_inner(mut self) -> B::OngoingCodegen {
self.0.take().unwrap()
}
}
-impl Deref for AbortCodegenOnDrop {
- type Target = OngoingCodegen;
+impl<B: BackendMethods> Deref for AbortCodegenOnDrop<B> {
+ type Target = B::OngoingCodegen;
- fn deref(&self) -> &OngoingCodegen {
+ fn deref(&self) -> &B::OngoingCodegen {
self.0.as_ref().unwrap()
}
}
-impl DerefMut for AbortCodegenOnDrop {
- fn deref_mut(&mut self) -> &mut OngoingCodegen {
+impl<B: BackendMethods> DerefMut for AbortCodegenOnDrop<B> {
+ fn deref_mut(&mut self) -> &mut B::OngoingCodegen {
self.0.as_mut().unwrap()
}
}
-impl Drop for AbortCodegenOnDrop {
+impl<B: BackendMethods> Drop for AbortCodegenOnDrop<B> {
fn drop(&mut self) {
if let Some(codegen) = self.0.take() {
- codegen.codegen_aborted();
+ B::codegen_aborted(codegen);
}
}
}
-fn assert_and_save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+fn assert_and_save_dep_graph<'ll, 'tcx>(tcx: TyCtxt<'ll, 'tcx, 'tcx>) {
time(tcx.sess,
"assert dep graph",
|| rustc_incremental::assert_dep_graph(tcx));
}
}
-fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+pub fn compile_codegen_unit<'ll, 'tcx>(tcx: TyCtxt<'ll, 'tcx, 'tcx>,
cgu_name: InternedString)
-> Stats {
let start_time = Instant::now();
cost);
return stats;
- fn module_codegen<'a, 'tcx>(
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ fn module_codegen<'ll, 'tcx>(
+ tcx: TyCtxt<'ll, 'tcx, 'tcx>,
cgu_name: InternedString)
- -> (Stats, ModuleCodegen)
+ -> (Stats, ModuleCodegen<ModuleLlvm>)
{
+ let backend = LlvmCodegenBackend(());
let cgu = tcx.codegen_unit(cgu_name);
-
// Instantiate monomorphizations without filling out definitions yet...
- let llvm_module = ModuleLlvm::new(tcx.sess, &cgu_name.as_str());
+ let llvm_module = backend.new_metadata(tcx.sess, &cgu_name.as_str());
let stats = {
let cx = CodegenCx::new(tcx, cgu, &llvm_module);
let mono_items = cx.codegen_unit
.items_in_deterministic_order(cx.tcx);
for &(mono_item, (linkage, visibility)) in &mono_items {
- mono_item.predefine(&cx, linkage, visibility);
+ mono_item.predefine::<Builder<&Value>>(&cx, linkage, visibility);
}
// ... and now that we have everything pre-defined, fill out those definitions.
for &(mono_item, _) in &mono_items {
- mono_item.define(&cx);
+ mono_item.define::<Builder<&Value>>(&cx);
}
// If this codegen unit contains the main function, also create the
// wrapper here
- maybe_create_entry_wrapper(&cx);
+ maybe_create_entry_wrapper::<Builder<&Value>>(&cx);
// Run replace-all-uses-with for statics that need it
- for &(old_g, new_g) in cx.statics_to_rauw.borrow().iter() {
- unsafe {
- let bitcast = llvm::LLVMConstPointerCast(new_g, val_ty(old_g));
- llvm::LLVMReplaceAllUsesWith(old_g, bitcast);
- llvm::LLVMDeleteGlobal(old_g);
- }
+ for &(old_g, new_g) in cx.statics_to_rauw().borrow().iter() {
+ cx.static_replace_all_uses(old_g, new_g)
}
// Create the llvm.used variable
// This variable has type [N x i8*] and is stored in the llvm.metadata section
- if !cx.used_statics.borrow().is_empty() {
- let name = const_cstr!("llvm.used");
- let section = const_cstr!("llvm.metadata");
- let array = C_array(Type::i8(&cx).ptr_to(), &*cx.used_statics.borrow());
-
- unsafe {
- let g = llvm::LLVMAddGlobal(cx.llmod,
- val_ty(array),
- name.as_ptr());
- llvm::LLVMSetInitializer(g, array);
- llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage);
- llvm::LLVMSetSection(g, section.as_ptr());
- }
+ if !cx.used_statics().borrow().is_empty() {
+ cx.create_used_variable()
}
// Finalize debuginfo
if cx.sess().opts.debuginfo != DebugInfo::None {
- debuginfo::finalize(&cx);
+ cx.debuginfo_finalize();
}
- cx.stats.into_inner()
+ cx.consume_stats().into_inner()
};
(stats, ModuleCodegen {
Visibility::Protected => llvm::Visibility::Protected,
}
}
-
-// FIXME(mw): Anything that is produced via DepGraph::with_task() must implement
-// the HashStable trait. Normally DepGraph::with_task() calls are
-// hidden behind queries, but CGU creation is a special case in two
-// ways: (1) it's not a query and (2) CGU are output nodes, so their
-// Fingerprints are not actually needed. It remains to be clarified
-// how exactly this case will be handled in the red/green system but
-// for now we content ourselves with providing a no-op HashStable
-// implementation for CGUs.
-mod temp_stable_hash_impls {
- use rustc_data_structures::stable_hasher::{StableHasherResult, StableHasher,
- HashStable};
- use ModuleCodegen;
-
- impl<HCX> HashStable<HCX> for ModuleCodegen {
- fn hash_stable<W: StableHasherResult>(&self,
- _: &mut HCX,
- _: &mut StableHasher<W>) {
- // do nothing
- }
- }
-}