2019-02-18 03:58:58 +09:00
|
|
|
use crate::attributes;
|
2017-06-03 14:54:08 -07:00
|
|
|
use libc::c_uint;
|
2020-03-29 17:19:48 +02:00
|
|
|
use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
|
2020-03-29 16:41:09 +02:00
|
|
|
use rustc_middle::bug;
|
|
|
|
use rustc_middle::ty::TyCtxt;
|
2021-10-06 15:52:54 +01:00
|
|
|
use rustc_session::config::{DebugInfo, OomStrategy};
|
2020-09-07 10:45:20 +02:00
|
|
|
use rustc_span::symbol::sym;
|
2017-06-03 14:54:08 -07:00
|
|
|
|
2021-08-31 11:16:10 -07:00
|
|
|
use crate::debuginfo;
|
2019-02-18 03:58:58 +09:00
|
|
|
use crate::llvm::{self, False, True};
|
|
|
|
use crate::ModuleLlvm;
|
2017-06-03 14:54:08 -07:00
|
|
|
|
2020-09-07 10:45:20 +02:00
|
|
|
pub(crate) unsafe fn codegen(
|
|
|
|
tcx: TyCtxt<'_>,
|
2021-08-31 11:16:10 -07:00
|
|
|
module_llvm: &mut ModuleLlvm,
|
|
|
|
module_name: &str,
|
2020-09-07 10:45:20 +02:00
|
|
|
kind: AllocatorKind,
|
|
|
|
has_alloc_error_handler: bool,
|
|
|
|
) {
|
2021-08-31 11:16:10 -07:00
|
|
|
let llcx = &*module_llvm.llcx;
|
|
|
|
let llmod = module_llvm.llmod();
|
2020-10-15 11:44:00 +02:00
|
|
|
let usize = match tcx.sess.target.pointer_width {
|
2020-10-14 18:22:10 +02:00
|
|
|
16 => llvm::LLVMInt16TypeInContext(llcx),
|
|
|
|
32 => llvm::LLVMInt32TypeInContext(llcx),
|
|
|
|
64 => llvm::LLVMInt64TypeInContext(llcx),
|
2017-06-03 14:54:08 -07:00
|
|
|
tws => bug!("Unsupported target word size for int: {}", tws),
|
|
|
|
};
|
|
|
|
let i8 = llvm::LLVMInt8TypeInContext(llcx);
|
|
|
|
let i8p = llvm::LLVMPointerType(i8, 0);
|
|
|
|
let void = llvm::LLVMVoidTypeInContext(llcx);
|
|
|
|
|
|
|
|
for method in ALLOCATOR_METHODS {
|
2018-10-08 16:55:04 +02:00
|
|
|
let mut args = Vec::with_capacity(method.inputs.len());
|
2017-06-03 14:54:08 -07:00
|
|
|
for ty in method.inputs.iter() {
|
|
|
|
match *ty {
|
|
|
|
AllocatorTy::Layout => {
|
|
|
|
args.push(usize); // size
|
|
|
|
args.push(usize); // align
|
|
|
|
}
|
|
|
|
AllocatorTy::Ptr => args.push(i8p),
|
2018-04-03 17:12:57 +02:00
|
|
|
AllocatorTy::Usize => args.push(usize),
|
2017-06-03 14:54:08 -07:00
|
|
|
|
|
|
|
AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let output = match method.output {
|
2018-04-03 17:12:57 +02:00
|
|
|
AllocatorTy::ResultPtr => Some(i8p),
|
2017-06-03 14:54:08 -07:00
|
|
|
AllocatorTy::Unit => None,
|
|
|
|
|
|
|
|
AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
|
|
|
|
panic!("invalid allocator output")
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2017-06-03 14:54:08 -07:00
|
|
|
};
|
|
|
|
let ty = llvm::LLVMFunctionType(
|
|
|
|
output.unwrap_or(void),
|
|
|
|
args.as_ptr(),
|
|
|
|
args.len() as c_uint,
|
|
|
|
False,
|
|
|
|
);
|
2020-03-10 00:00:00 +00:00
|
|
|
let name = format!("__rust_{}", method.name);
|
|
|
|
let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty);
|
2017-06-03 14:54:08 -07:00
|
|
|
|
2020-11-08 14:27:51 +03:00
|
|
|
if tcx.sess.target.default_hidden_visibility {
|
2018-01-30 11:54:07 -08:00
|
|
|
llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
|
|
|
|
}
|
Add Option to Force Unwind Tables
When panic != unwind, `nounwind` is added to all functions for a target.
This can cause issues when a panic happens with RUST_BACKTRACE=1, as
there needs to be a way to reconstruct the backtrace. There are three
possible sources of this information: forcing frame pointers (for which
an option exists already), debug info (for which an option exists), or
unwind tables.
Especially for embedded devices, forcing frame pointers can have code
size overheads (RISC-V sees ~10% overheads, ARM sees ~2-3% overheads).
In code, it can be the case that debug info is not kept, so it is useful
to provide this third option, unwind tables, that users can use to
reconstruct the call stack. Reconstructing this stack is harder than
with frame pointers, but it is still possible.
This commit adds a compiler option which allows a user to force the
addition of unwind tables. Unwind tables cannot be disabled on targets
that require them for correctness, or when using `-C panic=unwind`.
2020-05-04 12:08:35 +01:00
|
|
|
if tcx.sess.must_emit_unwind_tables() {
|
2022-02-21 11:19:16 -05:00
|
|
|
let uwtable = attributes::uwtable_attr(llcx);
|
|
|
|
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
|
2018-08-02 12:30:43 -07:00
|
|
|
}
|
2018-01-30 11:54:07 -08:00
|
|
|
|
2020-03-10 00:00:00 +00:00
|
|
|
let callee = kind.fn_name(method.name);
|
|
|
|
let callee =
|
|
|
|
llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
|
2018-08-02 12:30:43 -07:00
|
|
|
llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
|
2017-06-03 14:54:08 -07:00
|
|
|
|
|
|
|
let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
|
|
|
|
|
|
|
|
let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
|
|
|
|
llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
|
|
|
|
let args = args
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
|
|
|
|
.collect::<Vec<_>>();
|
2021-08-03 15:09:57 -07:00
|
|
|
let ret = llvm::LLVMRustBuildCall(
|
|
|
|
llbuilder,
|
|
|
|
ty,
|
|
|
|
callee,
|
|
|
|
args.as_ptr(),
|
|
|
|
args.len() as c_uint,
|
|
|
|
None,
|
|
|
|
);
|
2017-06-03 14:54:08 -07:00
|
|
|
llvm::LLVMSetTailCall(ret, True);
|
|
|
|
if output.is_some() {
|
|
|
|
llvm::LLVMBuildRet(llbuilder, ret);
|
|
|
|
} else {
|
|
|
|
llvm::LLVMBuildRetVoid(llbuilder);
|
|
|
|
}
|
|
|
|
llvm::LLVMDisposeBuilder(llbuilder);
|
|
|
|
}
|
2020-09-07 10:45:20 +02:00
|
|
|
|
|
|
|
// rust alloc error handler
|
|
|
|
let args = [usize, usize]; // size, align
|
|
|
|
|
|
|
|
let ty = llvm::LLVMFunctionType(void, args.as_ptr(), args.len() as c_uint, False);
|
2021-02-17 10:46:35 +01:00
|
|
|
let name = "__rust_alloc_error_handler";
|
2020-09-07 10:45:20 +02:00
|
|
|
let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty);
|
|
|
|
// -> ! DIFlagNoReturn
|
2022-02-21 11:19:16 -05:00
|
|
|
let no_return = llvm::AttributeKind::NoReturn.create_attr(llcx);
|
|
|
|
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[no_return]);
|
2020-09-07 10:45:20 +02:00
|
|
|
|
2020-11-08 14:27:51 +03:00
|
|
|
if tcx.sess.target.default_hidden_visibility {
|
2020-09-07 10:45:20 +02:00
|
|
|
llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
|
|
|
|
}
|
|
|
|
if tcx.sess.must_emit_unwind_tables() {
|
2022-02-21 11:19:16 -05:00
|
|
|
let uwtable = attributes::uwtable_attr(llcx);
|
|
|
|
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
|
2020-09-07 10:45:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
let kind = if has_alloc_error_handler { AllocatorKind::Global } else { AllocatorKind::Default };
|
|
|
|
let callee = kind.fn_name(sym::oom);
|
|
|
|
let callee = llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
|
|
|
|
// -> ! DIFlagNoReturn
|
2022-02-21 11:19:16 -05:00
|
|
|
attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]);
|
2020-09-07 10:45:20 +02:00
|
|
|
llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
|
|
|
|
|
|
|
|
let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
|
|
|
|
|
|
|
|
let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
|
|
|
|
llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
|
|
|
|
let args = args
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
|
|
|
|
.collect::<Vec<_>>();
|
2021-08-03 15:09:57 -07:00
|
|
|
let ret =
|
|
|
|
llvm::LLVMRustBuildCall(llbuilder, ty, callee, args.as_ptr(), args.len() as c_uint, None);
|
2020-09-07 10:45:20 +02:00
|
|
|
llvm::LLVMSetTailCall(ret, True);
|
|
|
|
llvm::LLVMBuildRetVoid(llbuilder);
|
|
|
|
llvm::LLVMDisposeBuilder(llbuilder);
|
2021-08-31 11:16:10 -07:00
|
|
|
|
2021-10-06 15:52:54 +01:00
|
|
|
// __rust_alloc_error_handler_should_panic
|
|
|
|
let name = OomStrategy::SYMBOL;
|
|
|
|
let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8);
|
|
|
|
if tcx.sess.target.default_hidden_visibility {
|
|
|
|
llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden);
|
|
|
|
}
|
2022-07-06 07:44:47 -05:00
|
|
|
let val = tcx.sess.opts.unstable_opts.oom.should_panic();
|
2021-10-06 15:52:54 +01:00
|
|
|
let llval = llvm::LLVMConstInt(i8, val as u64, False);
|
|
|
|
llvm::LLVMSetInitializer(ll_g, llval);
|
|
|
|
|
2021-08-31 11:16:10 -07:00
|
|
|
if tcx.sess.opts.debuginfo != DebugInfo::None {
|
2022-03-03 11:15:25 +01:00
|
|
|
let dbg_cx = debuginfo::CodegenUnitDebugContext::new(llmod);
|
|
|
|
debuginfo::metadata::build_compile_unit_di_node(tcx, module_name, &dbg_cx);
|
2021-08-31 11:16:10 -07:00
|
|
|
dbg_cx.finalize(tcx.sess);
|
|
|
|
}
|
2017-06-03 14:54:08 -07:00
|
|
|
}
|