mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-30 02:33:55 +00:00
Auto merge of #87743 - cuviper:opaque-calls, r=nikic
Prepare call/invoke for opaque pointers Rather than relying on `getPointerElementType()` from LLVM function pointers, we now pass the function type explicitly when building `call` or `invoke` instructions.
This commit is contained in:
commit
574d375680
@ -353,7 +353,11 @@ pub trait FnAbiLlvmExt<'tcx> {
|
|||||||
|
|
||||||
impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
||||||
fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type {
|
fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type {
|
||||||
let args_capacity: usize = self.args.iter().map(|arg|
|
// Ignore "extra" args from the call site for C variadic functions.
|
||||||
|
// Only the "fixed" args are part of the LLVM function signature.
|
||||||
|
let args = if self.c_variadic { &self.args[..self.fixed_count] } else { &self.args };
|
||||||
|
|
||||||
|
let args_capacity: usize = args.iter().map(|arg|
|
||||||
if arg.pad.is_some() { 1 } else { 0 } +
|
if arg.pad.is_some() { 1 } else { 0 } +
|
||||||
if let PassMode::Pair(_, _) = arg.mode { 2 } else { 1 }
|
if let PassMode::Pair(_, _) = arg.mode { 2 } else { 1 }
|
||||||
).sum();
|
).sum();
|
||||||
@ -371,7 +375,7 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for arg in &self.args {
|
for arg in args {
|
||||||
// add padding
|
// add padding
|
||||||
if let Some(ty) = arg.pad {
|
if let Some(ty) = arg.pad {
|
||||||
llargument_tys.push(ty.llvm_type(cx));
|
llargument_tys.push(ty.llvm_type(cx));
|
||||||
|
@ -78,8 +78,14 @@ pub(crate) unsafe fn codegen(
|
|||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
|
.map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let ret =
|
let ret = llvm::LLVMRustBuildCall(
|
||||||
llvm::LLVMRustBuildCall(llbuilder, callee, args.as_ptr(), args.len() as c_uint, None);
|
llbuilder,
|
||||||
|
ty,
|
||||||
|
callee,
|
||||||
|
args.as_ptr(),
|
||||||
|
args.len() as c_uint,
|
||||||
|
None,
|
||||||
|
);
|
||||||
llvm::LLVMSetTailCall(ret, True);
|
llvm::LLVMSetTailCall(ret, True);
|
||||||
if output.is_some() {
|
if output.is_some() {
|
||||||
llvm::LLVMBuildRet(llbuilder, ret);
|
llvm::LLVMBuildRet(llbuilder, ret);
|
||||||
@ -121,7 +127,8 @@ pub(crate) unsafe fn codegen(
|
|||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
|
.map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let ret = llvm::LLVMRustBuildCall(llbuilder, callee, args.as_ptr(), args.len() as c_uint, None);
|
let ret =
|
||||||
|
llvm::LLVMRustBuildCall(llbuilder, ty, callee, args.as_ptr(), args.len() as c_uint, None);
|
||||||
llvm::LLVMSetTailCall(ret, True);
|
llvm::LLVMSetTailCall(ret, True);
|
||||||
llvm::LLVMBuildRetVoid(llbuilder);
|
llvm::LLVMBuildRetVoid(llbuilder);
|
||||||
llvm::LLVMDisposeBuilder(llbuilder);
|
llvm::LLVMDisposeBuilder(llbuilder);
|
||||||
|
@ -464,7 +464,7 @@ fn inline_asm_call(
|
|||||||
alignstack,
|
alignstack,
|
||||||
llvm::AsmDialect::from_generic(dia),
|
llvm::AsmDialect::from_generic(dia),
|
||||||
);
|
);
|
||||||
let call = bx.call(v, inputs, None);
|
let call = bx.call(fty, v, inputs, None);
|
||||||
|
|
||||||
// Store mark in a metadata node so we can map LLVM errors
|
// Store mark in a metadata node so we can map LLVM errors
|
||||||
// back to source locations. See #17552.
|
// back to source locations. See #17552.
|
||||||
|
@ -200,6 +200,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||||||
|
|
||||||
fn invoke(
|
fn invoke(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
llty: &'ll Type,
|
||||||
llfn: &'ll Value,
|
llfn: &'ll Value,
|
||||||
args: &[&'ll Value],
|
args: &[&'ll Value],
|
||||||
then: &'ll BasicBlock,
|
then: &'ll BasicBlock,
|
||||||
@ -208,13 +209,14 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||||||
) -> &'ll Value {
|
) -> &'ll Value {
|
||||||
debug!("invoke {:?} with args ({:?})", llfn, args);
|
debug!("invoke {:?} with args ({:?})", llfn, args);
|
||||||
|
|
||||||
let args = self.check_call("invoke", llfn, args);
|
let args = self.check_call("invoke", llty, llfn, args);
|
||||||
let bundle = funclet.map(|funclet| funclet.bundle());
|
let bundle = funclet.map(|funclet| funclet.bundle());
|
||||||
let bundle = bundle.as_ref().map(|b| &*b.raw);
|
let bundle = bundle.as_ref().map(|b| &*b.raw);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm::LLVMRustBuildInvoke(
|
llvm::LLVMRustBuildInvoke(
|
||||||
self.llbuilder,
|
self.llbuilder,
|
||||||
|
llty,
|
||||||
llfn,
|
llfn,
|
||||||
args.as_ptr(),
|
args.as_ptr(),
|
||||||
args.len() as c_uint,
|
args.len() as c_uint,
|
||||||
@ -369,8 +371,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let intrinsic = self.get_intrinsic(&name);
|
let res = self.call_intrinsic(name, &[lhs, rhs]);
|
||||||
let res = self.call(intrinsic, &[lhs, rhs], None);
|
|
||||||
(self.extract_value(res, 0), self.extract_value(res, 1))
|
(self.extract_value(res, 0), self.extract_value(res, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -695,8 +696,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||||||
let float_width = self.cx.float_width(src_ty);
|
let float_width = self.cx.float_width(src_ty);
|
||||||
let int_width = self.cx.int_width(dest_ty);
|
let int_width = self.cx.int_width(dest_ty);
|
||||||
let name = format!("llvm.fptoui.sat.i{}.f{}", int_width, float_width);
|
let name = format!("llvm.fptoui.sat.i{}.f{}", int_width, float_width);
|
||||||
let intrinsic = self.get_intrinsic(&name);
|
return Some(self.call_intrinsic(&name, &[val]));
|
||||||
return Some(self.call(intrinsic, &[val], None));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
@ -708,8 +708,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||||||
let float_width = self.cx.float_width(src_ty);
|
let float_width = self.cx.float_width(src_ty);
|
||||||
let int_width = self.cx.int_width(dest_ty);
|
let int_width = self.cx.int_width(dest_ty);
|
||||||
let name = format!("llvm.fptosi.sat.i{}.f{}", int_width, float_width);
|
let name = format!("llvm.fptosi.sat.i{}.f{}", int_width, float_width);
|
||||||
let intrinsic = self.get_intrinsic(&name);
|
return Some(self.call_intrinsic(&name, &[val]));
|
||||||
return Some(self.call(intrinsic, &[val], None));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
@ -743,8 +742,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
if let Some(name) = name {
|
if let Some(name) = name {
|
||||||
let intrinsic = self.get_intrinsic(name);
|
return self.call_intrinsic(name, &[val]);
|
||||||
return self.call(intrinsic, &[val], None);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -766,8 +764,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
if let Some(name) = name {
|
if let Some(name) = name {
|
||||||
let intrinsic = self.get_intrinsic(name);
|
return self.call_intrinsic(name, &[val]);
|
||||||
return self.call(intrinsic, &[val], None);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1115,12 +1112,17 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let llfn = unsafe { llvm::LLVMRustGetInstrProfIncrementIntrinsic(self.cx().llmod) };
|
let llfn = unsafe { llvm::LLVMRustGetInstrProfIncrementIntrinsic(self.cx().llmod) };
|
||||||
|
let llty = self.cx.type_func(
|
||||||
|
&[self.cx.type_i8p(), self.cx.type_i64(), self.cx.type_i32(), self.cx.type_i32()],
|
||||||
|
self.cx.type_void(),
|
||||||
|
);
|
||||||
let args = &[fn_name, hash, num_counters, index];
|
let args = &[fn_name, hash, num_counters, index];
|
||||||
let args = self.check_call("call", llfn, args);
|
let args = self.check_call("call", llty, llfn, args);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let _ = llvm::LLVMRustBuildCall(
|
let _ = llvm::LLVMRustBuildCall(
|
||||||
self.llbuilder,
|
self.llbuilder,
|
||||||
|
llty,
|
||||||
llfn,
|
llfn,
|
||||||
args.as_ptr() as *const &llvm::Value,
|
args.as_ptr() as *const &llvm::Value,
|
||||||
args.len() as c_uint,
|
args.len() as c_uint,
|
||||||
@ -1131,19 +1133,21 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||||||
|
|
||||||
fn call(
|
fn call(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
llty: &'ll Type,
|
||||||
llfn: &'ll Value,
|
llfn: &'ll Value,
|
||||||
args: &[&'ll Value],
|
args: &[&'ll Value],
|
||||||
funclet: Option<&Funclet<'ll>>,
|
funclet: Option<&Funclet<'ll>>,
|
||||||
) -> &'ll Value {
|
) -> &'ll Value {
|
||||||
debug!("call {:?} with args ({:?})", llfn, args);
|
debug!("call {:?} with args ({:?})", llfn, args);
|
||||||
|
|
||||||
let args = self.check_call("call", llfn, args);
|
let args = self.check_call("call", llty, llfn, args);
|
||||||
let bundle = funclet.map(|funclet| funclet.bundle());
|
let bundle = funclet.map(|funclet| funclet.bundle());
|
||||||
let bundle = bundle.as_ref().map(|b| &*b.raw);
|
let bundle = bundle.as_ref().map(|b| &*b.raw);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm::LLVMRustBuildCall(
|
llvm::LLVMRustBuildCall(
|
||||||
self.llbuilder,
|
self.llbuilder,
|
||||||
|
llty,
|
||||||
llfn,
|
llfn,
|
||||||
args.as_ptr() as *const &llvm::Value,
|
args.as_ptr() as *const &llvm::Value,
|
||||||
args.len() as c_uint,
|
args.len() as c_uint,
|
||||||
@ -1313,15 +1317,10 @@ impl Builder<'a, 'll, 'tcx> {
|
|||||||
fn check_call<'b>(
|
fn check_call<'b>(
|
||||||
&mut self,
|
&mut self,
|
||||||
typ: &str,
|
typ: &str,
|
||||||
|
fn_ty: &'ll Type,
|
||||||
llfn: &'ll Value,
|
llfn: &'ll Value,
|
||||||
args: &'b [&'ll Value],
|
args: &'b [&'ll Value],
|
||||||
) -> Cow<'b, [&'ll Value]> {
|
) -> Cow<'b, [&'ll Value]> {
|
||||||
let mut fn_ty = self.cx.val_ty(llfn);
|
|
||||||
// Strip off pointers
|
|
||||||
while self.cx.type_kind(fn_ty) == TypeKind::Pointer {
|
|
||||||
fn_ty = self.cx.element_type(fn_ty);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
self.cx.type_kind(fn_ty) == TypeKind::Function,
|
self.cx.type_kind(fn_ty) == TypeKind::Function,
|
||||||
"builder::{} not passed a function, but {:?}",
|
"builder::{} not passed a function, but {:?}",
|
||||||
@ -1362,6 +1361,11 @@ impl Builder<'a, 'll, 'tcx> {
|
|||||||
unsafe { llvm::LLVMBuildVAArg(self.llbuilder, list, ty, UNNAMED) }
|
unsafe { llvm::LLVMBuildVAArg(self.llbuilder, list, ty, UNNAMED) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
crate fn call_intrinsic(&mut self, intrinsic: &str, args: &[&'ll Value]) -> &'ll Value {
|
||||||
|
let (ty, f) = self.cx.get_intrinsic(intrinsic);
|
||||||
|
self.call(ty, f, args, None)
|
||||||
|
}
|
||||||
|
|
||||||
fn call_lifetime_intrinsic(&mut self, intrinsic: &str, ptr: &'ll Value, size: Size) {
|
fn call_lifetime_intrinsic(&mut self, intrinsic: &str, ptr: &'ll Value, size: Size) {
|
||||||
let size = size.bytes();
|
let size = size.bytes();
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
@ -1372,10 +1376,8 @@ impl Builder<'a, 'll, 'tcx> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let lifetime_intrinsic = self.cx.get_intrinsic(intrinsic);
|
|
||||||
|
|
||||||
let ptr = self.pointercast(ptr, self.cx.type_i8p());
|
let ptr = self.pointercast(ptr, self.cx.type_i8p());
|
||||||
self.call(lifetime_intrinsic, &[self.cx.const_u64(size), ptr], None);
|
self.call_intrinsic(intrinsic, &[self.cx.const_u64(size), ptr]);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn phi(
|
pub(crate) fn phi(
|
||||||
|
@ -84,9 +84,9 @@ pub struct CodegenCx<'ll, 'tcx> {
|
|||||||
|
|
||||||
eh_personality: Cell<Option<&'ll Value>>,
|
eh_personality: Cell<Option<&'ll Value>>,
|
||||||
eh_catch_typeinfo: Cell<Option<&'ll Value>>,
|
eh_catch_typeinfo: Cell<Option<&'ll Value>>,
|
||||||
pub rust_try_fn: Cell<Option<&'ll Value>>,
|
pub rust_try_fn: Cell<Option<(&'ll Type, &'ll Value)>>,
|
||||||
|
|
||||||
intrinsics: RefCell<FxHashMap<&'static str, &'ll Value>>,
|
intrinsics: RefCell<FxHashMap<&'static str, (&'ll Type, &'ll Value)>>,
|
||||||
|
|
||||||
/// A counter that is used for generating local symbol names
|
/// A counter that is used for generating local symbol names
|
||||||
local_gen_sym_counter: Cell<usize>,
|
local_gen_sym_counter: Cell<usize>,
|
||||||
@ -452,7 +452,7 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CodegenCx<'b, 'tcx> {
|
impl CodegenCx<'b, 'tcx> {
|
||||||
crate fn get_intrinsic(&self, key: &str) -> &'b Value {
|
crate fn get_intrinsic(&self, key: &str) -> (&'b Type, &'b Value) {
|
||||||
if let Some(v) = self.intrinsics.borrow().get(key).cloned() {
|
if let Some(v) = self.intrinsics.borrow().get(key).cloned() {
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
@ -465,18 +465,18 @@ impl CodegenCx<'b, 'tcx> {
|
|||||||
name: &'static str,
|
name: &'static str,
|
||||||
args: Option<&[&'b llvm::Type]>,
|
args: Option<&[&'b llvm::Type]>,
|
||||||
ret: &'b llvm::Type,
|
ret: &'b llvm::Type,
|
||||||
) -> &'b llvm::Value {
|
) -> (&'b llvm::Type, &'b llvm::Value) {
|
||||||
let fn_ty = if let Some(args) = args {
|
let fn_ty = if let Some(args) = args {
|
||||||
self.type_func(args, ret)
|
self.type_func(args, ret)
|
||||||
} else {
|
} else {
|
||||||
self.type_variadic_func(&[], ret)
|
self.type_variadic_func(&[], ret)
|
||||||
};
|
};
|
||||||
let f = self.declare_cfn(name, llvm::UnnamedAddr::No, fn_ty);
|
let f = self.declare_cfn(name, llvm::UnnamedAddr::No, fn_ty);
|
||||||
self.intrinsics.borrow_mut().insert(name, f);
|
self.intrinsics.borrow_mut().insert(name, (fn_ty, f));
|
||||||
f
|
(fn_ty, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declare_intrinsic(&self, key: &str) -> Option<&'b Value> {
|
fn declare_intrinsic(&self, key: &str) -> Option<(&'b Type, &'b Value)> {
|
||||||
macro_rules! ifn {
|
macro_rules! ifn {
|
||||||
($name:expr, fn() -> $ret:expr) => (
|
($name:expr, fn() -> $ret:expr) => (
|
||||||
if key == $name {
|
if key == $name {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::abi::{Abi, FnAbi, LlvmType, PassMode};
|
use crate::abi::{Abi, FnAbi, FnAbiLlvmExt, LlvmType, PassMode};
|
||||||
use crate::builder::Builder;
|
use crate::builder::Builder;
|
||||||
use crate::context::CodegenCx;
|
use crate::context::CodegenCx;
|
||||||
use crate::llvm;
|
use crate::llvm;
|
||||||
@ -24,7 +24,7 @@ use rustc_target::spec::PanicStrategy;
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: Symbol) -> Option<&'ll Value> {
|
fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: Symbol) -> Option<(&'ll Type, &'ll Value)> {
|
||||||
let llvm_name = match name {
|
let llvm_name = match name {
|
||||||
sym::sqrtf32 => "llvm.sqrt.f32",
|
sym::sqrtf32 => "llvm.sqrt.f32",
|
||||||
sym::sqrtf64 => "llvm.sqrt.f64",
|
sym::sqrtf64 => "llvm.sqrt.f64",
|
||||||
@ -102,19 +102,20 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
|||||||
|
|
||||||
let simple = get_simple_intrinsic(self, name);
|
let simple = get_simple_intrinsic(self, name);
|
||||||
let llval = match name {
|
let llval = match name {
|
||||||
_ if simple.is_some() => self.call(
|
_ if simple.is_some() => {
|
||||||
simple.unwrap(),
|
let (simple_ty, simple_fn) = simple.unwrap();
|
||||||
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
|
self.call(
|
||||||
None,
|
simple_ty,
|
||||||
),
|
simple_fn,
|
||||||
|
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
}
|
||||||
sym::likely => {
|
sym::likely => {
|
||||||
let expect = self.get_intrinsic(&("llvm.expect.i1"));
|
self.call_intrinsic("llvm.expect.i1", &[args[0].immediate(), self.const_bool(true)])
|
||||||
self.call(expect, &[args[0].immediate(), self.const_bool(true)], None)
|
|
||||||
}
|
|
||||||
sym::unlikely => {
|
|
||||||
let expect = self.get_intrinsic(&("llvm.expect.i1"));
|
|
||||||
self.call(expect, &[args[0].immediate(), self.const_bool(false)], None)
|
|
||||||
}
|
}
|
||||||
|
sym::unlikely => self
|
||||||
|
.call_intrinsic("llvm.expect.i1", &[args[0].immediate(), self.const_bool(false)]),
|
||||||
kw::Try => {
|
kw::Try => {
|
||||||
try_intrinsic(
|
try_intrinsic(
|
||||||
self,
|
self,
|
||||||
@ -125,13 +126,9 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sym::breakpoint => {
|
sym::breakpoint => self.call_intrinsic("llvm.debugtrap", &[]),
|
||||||
let llfn = self.get_intrinsic(&("llvm.debugtrap"));
|
|
||||||
self.call(llfn, &[], None)
|
|
||||||
}
|
|
||||||
sym::va_copy => {
|
sym::va_copy => {
|
||||||
let intrinsic = self.cx().get_intrinsic(&("llvm.va_copy"));
|
self.call_intrinsic("llvm.va_copy", &[args[0].immediate(), args[1].immediate()])
|
||||||
self.call(intrinsic, &[args[0].immediate(), args[1].immediate()], None)
|
|
||||||
}
|
}
|
||||||
sym::va_arg => {
|
sym::va_arg => {
|
||||||
match fn_abi.ret.layout.abi {
|
match fn_abi.ret.layout.abi {
|
||||||
@ -194,7 +191,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
|||||||
| sym::prefetch_write_data
|
| sym::prefetch_write_data
|
||||||
| sym::prefetch_read_instruction
|
| sym::prefetch_read_instruction
|
||||||
| sym::prefetch_write_instruction => {
|
| sym::prefetch_write_instruction => {
|
||||||
let expect = self.get_intrinsic(&("llvm.prefetch"));
|
|
||||||
let (rw, cache_type) = match name {
|
let (rw, cache_type) = match name {
|
||||||
sym::prefetch_read_data => (0, 1),
|
sym::prefetch_read_data => (0, 1),
|
||||||
sym::prefetch_write_data => (1, 1),
|
sym::prefetch_write_data => (1, 1),
|
||||||
@ -202,15 +198,14 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
|||||||
sym::prefetch_write_instruction => (1, 0),
|
sym::prefetch_write_instruction => (1, 0),
|
||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
};
|
};
|
||||||
self.call(
|
self.call_intrinsic(
|
||||||
expect,
|
"llvm.prefetch",
|
||||||
&[
|
&[
|
||||||
args[0].immediate(),
|
args[0].immediate(),
|
||||||
self.const_i32(rw),
|
self.const_i32(rw),
|
||||||
args[1].immediate(),
|
args[1].immediate(),
|
||||||
self.const_i32(cache_type),
|
self.const_i32(cache_type),
|
||||||
],
|
],
|
||||||
None,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
sym::ctlz
|
sym::ctlz
|
||||||
@ -229,35 +224,33 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
|||||||
Some((width, signed)) => match name {
|
Some((width, signed)) => match name {
|
||||||
sym::ctlz | sym::cttz => {
|
sym::ctlz | sym::cttz => {
|
||||||
let y = self.const_bool(false);
|
let y = self.const_bool(false);
|
||||||
let llfn = self.get_intrinsic(&format!("llvm.{}.i{}", name, width));
|
self.call_intrinsic(
|
||||||
self.call(llfn, &[args[0].immediate(), y], None)
|
&format!("llvm.{}.i{}", name, width),
|
||||||
|
&[args[0].immediate(), y],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
sym::ctlz_nonzero | sym::cttz_nonzero => {
|
sym::ctlz_nonzero | sym::cttz_nonzero => {
|
||||||
let y = self.const_bool(true);
|
let y = self.const_bool(true);
|
||||||
let llvm_name = &format!("llvm.{}.i{}", &name_str[..4], width);
|
let llvm_name = &format!("llvm.{}.i{}", &name_str[..4], width);
|
||||||
let llfn = self.get_intrinsic(llvm_name);
|
self.call_intrinsic(llvm_name, &[args[0].immediate(), y])
|
||||||
self.call(llfn, &[args[0].immediate(), y], None)
|
|
||||||
}
|
}
|
||||||
sym::ctpop => self.call(
|
sym::ctpop => self.call_intrinsic(
|
||||||
self.get_intrinsic(&format!("llvm.ctpop.i{}", width)),
|
&format!("llvm.ctpop.i{}", width),
|
||||||
&[args[0].immediate()],
|
&[args[0].immediate()],
|
||||||
None,
|
|
||||||
),
|
),
|
||||||
sym::bswap => {
|
sym::bswap => {
|
||||||
if width == 8 {
|
if width == 8 {
|
||||||
args[0].immediate() // byte swap a u8/i8 is just a no-op
|
args[0].immediate() // byte swap a u8/i8 is just a no-op
|
||||||
} else {
|
} else {
|
||||||
self.call(
|
self.call_intrinsic(
|
||||||
self.get_intrinsic(&format!("llvm.bswap.i{}", width)),
|
&format!("llvm.bswap.i{}", width),
|
||||||
&[args[0].immediate()],
|
&[args[0].immediate()],
|
||||||
None,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sym::bitreverse => self.call(
|
sym::bitreverse => self.call_intrinsic(
|
||||||
self.get_intrinsic(&format!("llvm.bitreverse.i{}", width)),
|
&format!("llvm.bitreverse.i{}", width),
|
||||||
&[args[0].immediate()],
|
&[args[0].immediate()],
|
||||||
None,
|
|
||||||
),
|
),
|
||||||
sym::rotate_left | sym::rotate_right => {
|
sym::rotate_left | sym::rotate_right => {
|
||||||
let is_left = name == sym::rotate_left;
|
let is_left = name == sym::rotate_left;
|
||||||
@ -266,8 +259,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
|||||||
// rotate = funnel shift with first two args the same
|
// rotate = funnel shift with first two args the same
|
||||||
let llvm_name =
|
let llvm_name =
|
||||||
&format!("llvm.fsh{}.i{}", if is_left { 'l' } else { 'r' }, width);
|
&format!("llvm.fsh{}.i{}", if is_left { 'l' } else { 'r' }, width);
|
||||||
let llfn = self.get_intrinsic(llvm_name);
|
self.call_intrinsic(llvm_name, &[val, val, raw_shift])
|
||||||
self.call(llfn, &[val, val, raw_shift], None)
|
|
||||||
}
|
}
|
||||||
sym::saturating_add | sym::saturating_sub => {
|
sym::saturating_add | sym::saturating_sub => {
|
||||||
let is_add = name == sym::saturating_add;
|
let is_add = name == sym::saturating_add;
|
||||||
@ -279,8 +271,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
|||||||
if is_add { "add" } else { "sub" },
|
if is_add { "add" } else { "sub" },
|
||||||
width
|
width
|
||||||
);
|
);
|
||||||
let llfn = self.get_intrinsic(llvm_name);
|
self.call_intrinsic(llvm_name, &[lhs, rhs])
|
||||||
self.call(llfn, &[lhs, rhs], None)
|
|
||||||
}
|
}
|
||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
},
|
},
|
||||||
@ -331,8 +322,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
|||||||
let a_ptr = self.bitcast(a, i8p_ty);
|
let a_ptr = self.bitcast(a, i8p_ty);
|
||||||
let b_ptr = self.bitcast(b, i8p_ty);
|
let b_ptr = self.bitcast(b, i8p_ty);
|
||||||
let n = self.const_usize(layout.size.bytes());
|
let n = self.const_usize(layout.size.bytes());
|
||||||
let llfn = self.get_intrinsic("memcmp");
|
let cmp = self.call_intrinsic("memcmp", &[a_ptr, b_ptr, n]);
|
||||||
let cmp = self.call(llfn, &[a_ptr, b_ptr, n], None);
|
|
||||||
self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0))
|
self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -361,18 +351,15 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn abort(&mut self) {
|
fn abort(&mut self) {
|
||||||
let fnname = self.get_intrinsic(&("llvm.trap"));
|
self.call_intrinsic("llvm.trap", &[]);
|
||||||
self.call(fnname, &[], None);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assume(&mut self, val: Self::Value) {
|
fn assume(&mut self, val: Self::Value) {
|
||||||
let assume_intrinsic = self.get_intrinsic("llvm.assume");
|
self.call_intrinsic("llvm.assume", &[val]);
|
||||||
self.call(assume_intrinsic, &[val], None);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value {
|
fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value {
|
||||||
let expect = self.get_intrinsic(&"llvm.expect.i1");
|
self.call_intrinsic("llvm.expect.i1", &[cond, self.const_bool(expected)])
|
||||||
self.call(expect, &[cond, self.const_bool(expected)], None)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sideeffect(&mut self) {
|
fn sideeffect(&mut self) {
|
||||||
@ -380,19 +367,16 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
|||||||
// caller of this function is in `rustc_codegen_ssa`, which is agnostic to whether LLVM
|
// caller of this function is in `rustc_codegen_ssa`, which is agnostic to whether LLVM
|
||||||
// codegen backend being used, and so is unable to check the LLVM version.
|
// codegen backend being used, and so is unable to check the LLVM version.
|
||||||
if unsafe { llvm::LLVMRustVersionMajor() } < 12 {
|
if unsafe { llvm::LLVMRustVersionMajor() } < 12 {
|
||||||
let fnname = self.get_intrinsic(&("llvm.sideeffect"));
|
self.call_intrinsic("llvm.sideeffect", &[]);
|
||||||
self.call(fnname, &[], None);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn va_start(&mut self, va_list: &'ll Value) -> &'ll Value {
|
fn va_start(&mut self, va_list: &'ll Value) -> &'ll Value {
|
||||||
let intrinsic = self.cx().get_intrinsic("llvm.va_start");
|
self.call_intrinsic("llvm.va_start", &[va_list])
|
||||||
self.call(intrinsic, &[va_list], None)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn va_end(&mut self, va_list: &'ll Value) -> &'ll Value {
|
fn va_end(&mut self, va_list: &'ll Value) -> &'ll Value {
|
||||||
let intrinsic = self.cx().get_intrinsic("llvm.va_end");
|
self.call_intrinsic("llvm.va_end", &[va_list])
|
||||||
self.call(intrinsic, &[va_list], None)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -404,7 +388,8 @@ fn try_intrinsic(
|
|||||||
dest: &'ll Value,
|
dest: &'ll Value,
|
||||||
) {
|
) {
|
||||||
if bx.sess().panic_strategy() == PanicStrategy::Abort {
|
if bx.sess().panic_strategy() == PanicStrategy::Abort {
|
||||||
bx.call(try_func, &[data], None);
|
let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
|
||||||
|
bx.call(try_func_ty, try_func, &[data], None);
|
||||||
// Return 0 unconditionally from the intrinsic call;
|
// Return 0 unconditionally from the intrinsic call;
|
||||||
// we can never unwind.
|
// we can never unwind.
|
||||||
let ret_align = bx.tcx().data_layout.i32_align.abi;
|
let ret_align = bx.tcx().data_layout.i32_align.abi;
|
||||||
@ -432,7 +417,7 @@ fn codegen_msvc_try(
|
|||||||
catch_func: &'ll Value,
|
catch_func: &'ll Value,
|
||||||
dest: &'ll Value,
|
dest: &'ll Value,
|
||||||
) {
|
) {
|
||||||
let llfn = get_rust_try_fn(bx, &mut |mut bx| {
|
let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| {
|
||||||
bx.set_personality_fn(bx.eh_personality());
|
bx.set_personality_fn(bx.eh_personality());
|
||||||
|
|
||||||
let mut normal = bx.build_sibling_block("normal");
|
let mut normal = bx.build_sibling_block("normal");
|
||||||
@ -502,7 +487,8 @@ fn codegen_msvc_try(
|
|||||||
// More information can be found in libstd's seh.rs implementation.
|
// More information can be found in libstd's seh.rs implementation.
|
||||||
let ptr_align = bx.tcx().data_layout.pointer_align.abi;
|
let ptr_align = bx.tcx().data_layout.pointer_align.abi;
|
||||||
let slot = bx.alloca(bx.type_i8p(), ptr_align);
|
let slot = bx.alloca(bx.type_i8p(), ptr_align);
|
||||||
bx.invoke(try_func, &[data], normal.llbb(), catchswitch.llbb(), None);
|
let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
|
||||||
|
bx.invoke(try_func_ty, try_func, &[data], normal.llbb(), catchswitch.llbb(), None);
|
||||||
|
|
||||||
normal.ret(bx.const_i32(0));
|
normal.ret(bx.const_i32(0));
|
||||||
|
|
||||||
@ -544,14 +530,15 @@ fn codegen_msvc_try(
|
|||||||
let flags = bx.const_i32(8);
|
let flags = bx.const_i32(8);
|
||||||
let funclet = catchpad_rust.catch_pad(cs, &[tydesc, flags, slot]);
|
let funclet = catchpad_rust.catch_pad(cs, &[tydesc, flags, slot]);
|
||||||
let ptr = catchpad_rust.load(bx.type_i8p(), slot, ptr_align);
|
let ptr = catchpad_rust.load(bx.type_i8p(), slot, ptr_align);
|
||||||
catchpad_rust.call(catch_func, &[data, ptr], Some(&funclet));
|
let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
|
||||||
|
catchpad_rust.call(catch_ty, catch_func, &[data, ptr], Some(&funclet));
|
||||||
catchpad_rust.catch_ret(&funclet, caught.llbb());
|
catchpad_rust.catch_ret(&funclet, caught.llbb());
|
||||||
|
|
||||||
// The flag value of 64 indicates a "catch-all".
|
// The flag value of 64 indicates a "catch-all".
|
||||||
let flags = bx.const_i32(64);
|
let flags = bx.const_i32(64);
|
||||||
let null = bx.const_null(bx.type_i8p());
|
let null = bx.const_null(bx.type_i8p());
|
||||||
let funclet = catchpad_foreign.catch_pad(cs, &[null, flags, null]);
|
let funclet = catchpad_foreign.catch_pad(cs, &[null, flags, null]);
|
||||||
catchpad_foreign.call(catch_func, &[data, null], Some(&funclet));
|
catchpad_foreign.call(catch_ty, catch_func, &[data, null], Some(&funclet));
|
||||||
catchpad_foreign.catch_ret(&funclet, caught.llbb());
|
catchpad_foreign.catch_ret(&funclet, caught.llbb());
|
||||||
|
|
||||||
caught.ret(bx.const_i32(1));
|
caught.ret(bx.const_i32(1));
|
||||||
@ -559,7 +546,7 @@ fn codegen_msvc_try(
|
|||||||
|
|
||||||
// Note that no invoke is used here because by definition this function
|
// Note that no invoke is used here because by definition this function
|
||||||
// can't panic (that's what it's catching).
|
// can't panic (that's what it's catching).
|
||||||
let ret = bx.call(llfn, &[try_func, data, catch_func], None);
|
let ret = bx.call(llty, llfn, &[try_func, data, catch_func], None);
|
||||||
let i32_align = bx.tcx().data_layout.i32_align.abi;
|
let i32_align = bx.tcx().data_layout.i32_align.abi;
|
||||||
bx.store(ret, dest, i32_align);
|
bx.store(ret, dest, i32_align);
|
||||||
}
|
}
|
||||||
@ -582,7 +569,7 @@ fn codegen_gnu_try(
|
|||||||
catch_func: &'ll Value,
|
catch_func: &'ll Value,
|
||||||
dest: &'ll Value,
|
dest: &'ll Value,
|
||||||
) {
|
) {
|
||||||
let llfn = get_rust_try_fn(bx, &mut |mut bx| {
|
let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| {
|
||||||
// Codegens the shims described above:
|
// Codegens the shims described above:
|
||||||
//
|
//
|
||||||
// bx:
|
// bx:
|
||||||
@ -601,7 +588,8 @@ fn codegen_gnu_try(
|
|||||||
let try_func = llvm::get_param(bx.llfn(), 0);
|
let try_func = llvm::get_param(bx.llfn(), 0);
|
||||||
let data = llvm::get_param(bx.llfn(), 1);
|
let data = llvm::get_param(bx.llfn(), 1);
|
||||||
let catch_func = llvm::get_param(bx.llfn(), 2);
|
let catch_func = llvm::get_param(bx.llfn(), 2);
|
||||||
bx.invoke(try_func, &[data], then.llbb(), catch.llbb(), None);
|
let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
|
||||||
|
bx.invoke(try_func_ty, try_func, &[data], then.llbb(), catch.llbb(), None);
|
||||||
then.ret(bx.const_i32(0));
|
then.ret(bx.const_i32(0));
|
||||||
|
|
||||||
// Type indicator for the exception being thrown.
|
// Type indicator for the exception being thrown.
|
||||||
@ -615,13 +603,14 @@ fn codegen_gnu_try(
|
|||||||
let tydesc = bx.const_null(bx.type_i8p());
|
let tydesc = bx.const_null(bx.type_i8p());
|
||||||
catch.add_clause(vals, tydesc);
|
catch.add_clause(vals, tydesc);
|
||||||
let ptr = catch.extract_value(vals, 0);
|
let ptr = catch.extract_value(vals, 0);
|
||||||
catch.call(catch_func, &[data, ptr], None);
|
let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
|
||||||
|
catch.call(catch_ty, catch_func, &[data, ptr], None);
|
||||||
catch.ret(bx.const_i32(1));
|
catch.ret(bx.const_i32(1));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Note that no invoke is used here because by definition this function
|
// Note that no invoke is used here because by definition this function
|
||||||
// can't panic (that's what it's catching).
|
// can't panic (that's what it's catching).
|
||||||
let ret = bx.call(llfn, &[try_func, data, catch_func], None);
|
let ret = bx.call(llty, llfn, &[try_func, data, catch_func], None);
|
||||||
let i32_align = bx.tcx().data_layout.i32_align.abi;
|
let i32_align = bx.tcx().data_layout.i32_align.abi;
|
||||||
bx.store(ret, dest, i32_align);
|
bx.store(ret, dest, i32_align);
|
||||||
}
|
}
|
||||||
@ -636,7 +625,7 @@ fn codegen_emcc_try(
|
|||||||
catch_func: &'ll Value,
|
catch_func: &'ll Value,
|
||||||
dest: &'ll Value,
|
dest: &'ll Value,
|
||||||
) {
|
) {
|
||||||
let llfn = get_rust_try_fn(bx, &mut |mut bx| {
|
let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| {
|
||||||
// Codegens the shims described above:
|
// Codegens the shims described above:
|
||||||
//
|
//
|
||||||
// bx:
|
// bx:
|
||||||
@ -660,7 +649,8 @@ fn codegen_emcc_try(
|
|||||||
let try_func = llvm::get_param(bx.llfn(), 0);
|
let try_func = llvm::get_param(bx.llfn(), 0);
|
||||||
let data = llvm::get_param(bx.llfn(), 1);
|
let data = llvm::get_param(bx.llfn(), 1);
|
||||||
let catch_func = llvm::get_param(bx.llfn(), 2);
|
let catch_func = llvm::get_param(bx.llfn(), 2);
|
||||||
bx.invoke(try_func, &[data], then.llbb(), catch.llbb(), None);
|
let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
|
||||||
|
bx.invoke(try_func_ty, try_func, &[data], then.llbb(), catch.llbb(), None);
|
||||||
then.ret(bx.const_i32(0));
|
then.ret(bx.const_i32(0));
|
||||||
|
|
||||||
// Type indicator for the exception being thrown.
|
// Type indicator for the exception being thrown.
|
||||||
@ -677,8 +667,7 @@ fn codegen_emcc_try(
|
|||||||
let selector = catch.extract_value(vals, 1);
|
let selector = catch.extract_value(vals, 1);
|
||||||
|
|
||||||
// Check if the typeid we got is the one for a Rust panic.
|
// Check if the typeid we got is the one for a Rust panic.
|
||||||
let llvm_eh_typeid_for = bx.get_intrinsic("llvm.eh.typeid.for");
|
let rust_typeid = catch.call_intrinsic("llvm.eh.typeid.for", &[tydesc]);
|
||||||
let rust_typeid = catch.call(llvm_eh_typeid_for, &[tydesc], None);
|
|
||||||
let is_rust_panic = catch.icmp(IntPredicate::IntEQ, selector, rust_typeid);
|
let is_rust_panic = catch.icmp(IntPredicate::IntEQ, selector, rust_typeid);
|
||||||
let is_rust_panic = catch.zext(is_rust_panic, bx.type_bool());
|
let is_rust_panic = catch.zext(is_rust_panic, bx.type_bool());
|
||||||
|
|
||||||
@ -702,13 +691,14 @@ fn codegen_emcc_try(
|
|||||||
catch.store(is_rust_panic, catch_data_1, i8_align);
|
catch.store(is_rust_panic, catch_data_1, i8_align);
|
||||||
let catch_data = catch.bitcast(catch_data, bx.type_i8p());
|
let catch_data = catch.bitcast(catch_data, bx.type_i8p());
|
||||||
|
|
||||||
catch.call(catch_func, &[data, catch_data], None);
|
let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
|
||||||
|
catch.call(catch_ty, catch_func, &[data, catch_data], None);
|
||||||
catch.ret(bx.const_i32(1));
|
catch.ret(bx.const_i32(1));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Note that no invoke is used here because by definition this function
|
// Note that no invoke is used here because by definition this function
|
||||||
// can't panic (that's what it's catching).
|
// can't panic (that's what it's catching).
|
||||||
let ret = bx.call(llfn, &[try_func, data, catch_func], None);
|
let ret = bx.call(llty, llfn, &[try_func, data, catch_func], None);
|
||||||
let i32_align = bx.tcx().data_layout.i32_align.abi;
|
let i32_align = bx.tcx().data_layout.i32_align.abi;
|
||||||
bx.store(ret, dest, i32_align);
|
bx.store(ret, dest, i32_align);
|
||||||
}
|
}
|
||||||
@ -720,8 +710,9 @@ fn gen_fn<'ll, 'tcx>(
|
|||||||
name: &str,
|
name: &str,
|
||||||
rust_fn_sig: ty::PolyFnSig<'tcx>,
|
rust_fn_sig: ty::PolyFnSig<'tcx>,
|
||||||
codegen: &mut dyn FnMut(Builder<'_, 'll, 'tcx>),
|
codegen: &mut dyn FnMut(Builder<'_, 'll, 'tcx>),
|
||||||
) -> &'ll Value {
|
) -> (&'ll Type, &'ll Value) {
|
||||||
let fn_abi = FnAbi::of_fn_ptr(cx, rust_fn_sig, &[]);
|
let fn_abi = FnAbi::of_fn_ptr(cx, rust_fn_sig, &[]);
|
||||||
|
let llty = fn_abi.llvm_type(cx);
|
||||||
let llfn = cx.declare_fn(name, &fn_abi);
|
let llfn = cx.declare_fn(name, &fn_abi);
|
||||||
cx.set_frame_pointer_type(llfn);
|
cx.set_frame_pointer_type(llfn);
|
||||||
cx.apply_target_cpu_attr(llfn);
|
cx.apply_target_cpu_attr(llfn);
|
||||||
@ -730,7 +721,7 @@ fn gen_fn<'ll, 'tcx>(
|
|||||||
let llbb = Builder::append_block(cx, llfn, "entry-block");
|
let llbb = Builder::append_block(cx, llfn, "entry-block");
|
||||||
let bx = Builder::build(cx, llbb);
|
let bx = Builder::build(cx, llbb);
|
||||||
codegen(bx);
|
codegen(bx);
|
||||||
llfn
|
(llty, llfn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function used to get a handle to the `__rust_try` function used to
|
// Helper function used to get a handle to the `__rust_try` function used to
|
||||||
@ -740,7 +731,7 @@ fn gen_fn<'ll, 'tcx>(
|
|||||||
fn get_rust_try_fn<'ll, 'tcx>(
|
fn get_rust_try_fn<'ll, 'tcx>(
|
||||||
cx: &CodegenCx<'ll, 'tcx>,
|
cx: &CodegenCx<'ll, 'tcx>,
|
||||||
codegen: &mut dyn FnMut(Builder<'_, 'll, 'tcx>),
|
codegen: &mut dyn FnMut(Builder<'_, 'll, 'tcx>),
|
||||||
) -> &'ll Value {
|
) -> (&'ll Type, &'ll Value) {
|
||||||
if let Some(llfn) = cx.rust_try_fn.get() {
|
if let Some(llfn) = cx.rust_try_fn.get() {
|
||||||
return llfn;
|
return llfn;
|
||||||
}
|
}
|
||||||
@ -1123,7 +1114,8 @@ fn generic_simd_intrinsic(
|
|||||||
};
|
};
|
||||||
let llvm_name = &format!("llvm.{0}.v{1}{2}", intr_name, in_len, elem_ty_str);
|
let llvm_name = &format!("llvm.{0}.v{1}{2}", intr_name, in_len, elem_ty_str);
|
||||||
let f = bx.declare_cfn(&llvm_name, llvm::UnnamedAddr::No, fn_ty);
|
let f = bx.declare_cfn(&llvm_name, llvm::UnnamedAddr::No, fn_ty);
|
||||||
let c = bx.call(f, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None);
|
let c =
|
||||||
|
bx.call(fn_ty, f, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None);
|
||||||
Ok(c)
|
Ok(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1300,15 +1292,13 @@ fn generic_simd_intrinsic(
|
|||||||
|
|
||||||
let llvm_intrinsic =
|
let llvm_intrinsic =
|
||||||
format!("llvm.masked.gather.{}.{}", llvm_elem_vec_str, llvm_pointer_vec_str);
|
format!("llvm.masked.gather.{}.{}", llvm_elem_vec_str, llvm_pointer_vec_str);
|
||||||
let f = bx.declare_cfn(
|
let fn_ty = bx.type_func(
|
||||||
&llvm_intrinsic,
|
&[llvm_pointer_vec_ty, alignment_ty, mask_ty, llvm_elem_vec_ty],
|
||||||
llvm::UnnamedAddr::No,
|
llvm_elem_vec_ty,
|
||||||
bx.type_func(
|
|
||||||
&[llvm_pointer_vec_ty, alignment_ty, mask_ty, llvm_elem_vec_ty],
|
|
||||||
llvm_elem_vec_ty,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
let v = bx.call(f, &[args[1].immediate(), alignment, mask, args[0].immediate()], None);
|
let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
|
||||||
|
let v =
|
||||||
|
bx.call(fn_ty, f, &[args[1].immediate(), alignment, mask, args[0].immediate()], None);
|
||||||
return Ok(v);
|
return Ok(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1430,12 +1420,11 @@ fn generic_simd_intrinsic(
|
|||||||
|
|
||||||
let llvm_intrinsic =
|
let llvm_intrinsic =
|
||||||
format!("llvm.masked.scatter.{}.{}", llvm_elem_vec_str, llvm_pointer_vec_str);
|
format!("llvm.masked.scatter.{}.{}", llvm_elem_vec_str, llvm_pointer_vec_str);
|
||||||
let f = bx.declare_cfn(
|
let fn_ty =
|
||||||
&llvm_intrinsic,
|
bx.type_func(&[llvm_elem_vec_ty, llvm_pointer_vec_ty, alignment_ty, mask_ty], ret_t);
|
||||||
llvm::UnnamedAddr::No,
|
let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
|
||||||
bx.type_func(&[llvm_elem_vec_ty, llvm_pointer_vec_ty, alignment_ty, mask_ty], ret_t),
|
let v =
|
||||||
);
|
bx.call(fn_ty, f, &[args[0].immediate(), args[1].immediate(), alignment, mask], None);
|
||||||
let v = bx.call(f, &[args[0].immediate(), args[1].immediate(), alignment, mask], None);
|
|
||||||
return Ok(v);
|
return Ok(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1757,12 +1746,9 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
|
|||||||
);
|
);
|
||||||
let vec_ty = bx.cx.type_vector(elem_ty, in_len as u64);
|
let vec_ty = bx.cx.type_vector(elem_ty, in_len as u64);
|
||||||
|
|
||||||
let f = bx.declare_cfn(
|
let fn_ty = bx.type_func(&[vec_ty, vec_ty], vec_ty);
|
||||||
&llvm_intrinsic,
|
let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
|
||||||
llvm::UnnamedAddr::No,
|
let v = bx.call(fn_ty, f, &[lhs, rhs], None);
|
||||||
bx.type_func(&[vec_ty, vec_ty], vec_ty),
|
|
||||||
);
|
|
||||||
let v = bx.call(f, &[lhs, rhs], None);
|
|
||||||
return Ok(v);
|
return Ok(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1155,6 +1155,7 @@ extern "C" {
|
|||||||
) -> &'a Value;
|
) -> &'a Value;
|
||||||
pub fn LLVMRustBuildInvoke(
|
pub fn LLVMRustBuildInvoke(
|
||||||
B: &Builder<'a>,
|
B: &Builder<'a>,
|
||||||
|
Ty: &'a Type,
|
||||||
Fn: &'a Value,
|
Fn: &'a Value,
|
||||||
Args: *const &'a Value,
|
Args: *const &'a Value,
|
||||||
NumArgs: c_uint,
|
NumArgs: c_uint,
|
||||||
@ -1526,6 +1527,7 @@ extern "C" {
|
|||||||
pub fn LLVMRustGetInstrProfIncrementIntrinsic(M: &Module) -> &'a Value;
|
pub fn LLVMRustGetInstrProfIncrementIntrinsic(M: &Module) -> &'a Value;
|
||||||
pub fn LLVMRustBuildCall(
|
pub fn LLVMRustBuildCall(
|
||||||
B: &Builder<'a>,
|
B: &Builder<'a>,
|
||||||
|
Ty: &'a Type,
|
||||||
Fn: &'a Value,
|
Fn: &'a Value,
|
||||||
Args: *const &'a Value,
|
Args: *const &'a Value,
|
||||||
NumArgs: c_uint,
|
NumArgs: c_uint,
|
||||||
|
@ -203,7 +203,11 @@ impl BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn element_type(&self, ty: &'ll Type) -> &'ll Type {
|
fn element_type(&self, ty: &'ll Type) -> &'ll Type {
|
||||||
unsafe { llvm::LLVMGetElementType(ty) }
|
match self.type_kind(ty) {
|
||||||
|
TypeKind::Array | TypeKind::Vector => unsafe { llvm::LLVMGetElementType(ty) },
|
||||||
|
TypeKind::Pointer => bug!("element_type is not supported for opaque pointers"),
|
||||||
|
other => bug!("element_type called on unsupported type {:?}", other),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vector_length(&self, ty: &'ll Type) -> usize {
|
fn vector_length(&self, ty: &'ll Type) -> usize {
|
||||||
@ -275,6 +279,9 @@ impl LayoutTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||||||
fn cast_backend_type(&self, ty: &CastTarget) -> &'ll Type {
|
fn cast_backend_type(&self, ty: &CastTarget) -> &'ll Type {
|
||||||
ty.llvm_type(self)
|
ty.llvm_type(self)
|
||||||
}
|
}
|
||||||
|
fn fn_decl_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> &'ll Type {
|
||||||
|
fn_abi.llvm_type(self)
|
||||||
|
}
|
||||||
fn fn_ptr_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> &'ll Type {
|
fn fn_ptr_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> &'ll Type {
|
||||||
fn_abi.ptr_to_llvm_type(self)
|
fn_abi.ptr_to_llvm_type(self)
|
||||||
}
|
}
|
||||||
|
@ -441,9 +441,11 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||||||
|
|
||||||
bx.insert_reference_to_gdb_debug_scripts_section_global();
|
bx.insert_reference_to_gdb_debug_scripts_section_global();
|
||||||
|
|
||||||
|
let isize_ty = cx.type_isize();
|
||||||
|
let i8pp_ty = cx.type_ptr_to(cx.type_i8p());
|
||||||
let (arg_argc, arg_argv) = get_argc_argv(cx, &mut bx);
|
let (arg_argc, arg_argv) = get_argc_argv(cx, &mut bx);
|
||||||
|
|
||||||
let (start_fn, args) = if use_start_lang_item {
|
let (start_fn, start_ty, args) = if use_start_lang_item {
|
||||||
let start_def_id = cx.tcx().require_lang_item(LangItem::Start, None);
|
let start_def_id = cx.tcx().require_lang_item(LangItem::Start, None);
|
||||||
let start_fn = cx.get_fn_addr(
|
let start_fn = cx.get_fn_addr(
|
||||||
ty::Instance::resolve(
|
ty::Instance::resolve(
|
||||||
@ -455,16 +457,15 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
(
|
let start_ty = cx.type_func(&[cx.val_ty(rust_main), isize_ty, i8pp_ty], isize_ty);
|
||||||
start_fn,
|
(start_fn, start_ty, vec![rust_main, arg_argc, arg_argv])
|
||||||
vec![bx.pointercast(rust_main, cx.type_ptr_to(cx.type_i8p())), arg_argc, arg_argv],
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
debug!("using user-defined start fn");
|
debug!("using user-defined start fn");
|
||||||
(rust_main, vec![arg_argc, arg_argv])
|
let start_ty = cx.type_func(&[isize_ty, i8pp_ty], isize_ty);
|
||||||
|
(rust_main, start_ty, vec![arg_argc, arg_argv])
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = bx.call(start_fn, &args, None);
|
let result = bx.call(start_ty, start_fn, &args, None);
|
||||||
let cast = bx.intcast(result, cx.type_int(), true);
|
let cast = bx.intcast(result, cx.type_int(), true);
|
||||||
bx.ret(cast);
|
bx.ret(cast);
|
||||||
|
|
||||||
|
@ -132,14 +132,21 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
|||||||
) {
|
) {
|
||||||
// If there is a cleanup block and the function we're calling can unwind, then
|
// If there is a cleanup block and the function we're calling can unwind, then
|
||||||
// do an invoke, otherwise do a call.
|
// do an invoke, otherwise do a call.
|
||||||
|
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
|
||||||
if let Some(cleanup) = cleanup.filter(|_| fn_abi.can_unwind) {
|
if let Some(cleanup) = cleanup.filter(|_| fn_abi.can_unwind) {
|
||||||
let ret_llbb = if let Some((_, target)) = destination {
|
let ret_llbb = if let Some((_, target)) = destination {
|
||||||
fx.llbb(target)
|
fx.llbb(target)
|
||||||
} else {
|
} else {
|
||||||
fx.unreachable_block()
|
fx.unreachable_block()
|
||||||
};
|
};
|
||||||
let invokeret =
|
let invokeret = bx.invoke(
|
||||||
bx.invoke(fn_ptr, &llargs, ret_llbb, self.llblock(fx, cleanup), self.funclet(fx));
|
fn_ty,
|
||||||
|
fn_ptr,
|
||||||
|
&llargs,
|
||||||
|
ret_llbb,
|
||||||
|
self.llblock(fx, cleanup),
|
||||||
|
self.funclet(fx),
|
||||||
|
);
|
||||||
bx.apply_attrs_callsite(&fn_abi, invokeret);
|
bx.apply_attrs_callsite(&fn_abi, invokeret);
|
||||||
|
|
||||||
if let Some((ret_dest, target)) = destination {
|
if let Some((ret_dest, target)) = destination {
|
||||||
@ -148,7 +155,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
|||||||
fx.store_return(&mut ret_bx, ret_dest, &fn_abi.ret, invokeret);
|
fx.store_return(&mut ret_bx, ret_dest, &fn_abi.ret, invokeret);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let llret = bx.call(fn_ptr, &llargs, self.funclet(fx));
|
let llret = bx.call(fn_ty, fn_ptr, &llargs, self.funclet(fx));
|
||||||
bx.apply_attrs_callsite(&fn_abi, llret);
|
bx.apply_attrs_callsite(&fn_abi, llret);
|
||||||
if fx.mir[self.bb].is_cleanup {
|
if fx.mir[self.bb].is_cleanup {
|
||||||
// Cleanup is always the cold path. Don't inline
|
// Cleanup is always the cold path. Don't inline
|
||||||
|
@ -518,7 +518,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
};
|
};
|
||||||
let instance = ty::Instance::mono(bx.tcx(), def_id);
|
let instance = ty::Instance::mono(bx.tcx(), def_id);
|
||||||
let r = bx.cx().get_fn_addr(instance);
|
let r = bx.cx().get_fn_addr(instance);
|
||||||
let call = bx.call(r, &[llsize, llalign], None);
|
let ty = bx.type_func(&[bx.type_isize(), bx.type_isize()], bx.type_i8p());
|
||||||
|
let call = bx.call(ty, r, &[llsize, llalign], None);
|
||||||
let val = bx.pointercast(call, llty_ptr);
|
let val = bx.pointercast(call, llty_ptr);
|
||||||
|
|
||||||
let operand = OperandRef { val: OperandValue::Immediate(val), layout: box_layout };
|
let operand = OperandRef { val: OperandValue::Immediate(val), layout: box_layout };
|
||||||
|
@ -72,6 +72,7 @@ pub trait BuilderMethods<'a, 'tcx>:
|
|||||||
);
|
);
|
||||||
fn invoke(
|
fn invoke(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
llty: Self::Type,
|
||||||
llfn: Self::Value,
|
llfn: Self::Value,
|
||||||
args: &[Self::Value],
|
args: &[Self::Value],
|
||||||
then: Self::BasicBlock,
|
then: Self::BasicBlock,
|
||||||
@ -303,6 +304,7 @@ pub trait BuilderMethods<'a, 'tcx>:
|
|||||||
|
|
||||||
fn call(
|
fn call(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
llty: Self::Type,
|
||||||
llfn: Self::Value,
|
llfn: Self::Value,
|
||||||
args: &[Self::Value],
|
args: &[Self::Value],
|
||||||
funclet: Option<&Self::Funclet>,
|
funclet: Option<&Self::Funclet>,
|
||||||
|
@ -102,6 +102,7 @@ impl<T> DerivedTypeMethods<'tcx> for T where Self: BaseTypeMethods<'tcx> + MiscM
|
|||||||
pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> {
|
pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> {
|
||||||
fn backend_type(&self, layout: TyAndLayout<'tcx>) -> Self::Type;
|
fn backend_type(&self, layout: TyAndLayout<'tcx>) -> Self::Type;
|
||||||
fn cast_backend_type(&self, ty: &CastTarget) -> Self::Type;
|
fn cast_backend_type(&self, ty: &CastTarget) -> Self::Type;
|
||||||
|
fn fn_decl_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Self::Type;
|
||||||
fn fn_ptr_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Self::Type;
|
fn fn_ptr_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Self::Type;
|
||||||
fn reg_backend_type(&self, ty: &Reg) -> Self::Type;
|
fn reg_backend_type(&self, ty: &Reg) -> Self::Type;
|
||||||
fn immediate_backend_type(&self, layout: TyAndLayout<'tcx>) -> Self::Type;
|
fn immediate_backend_type(&self, layout: TyAndLayout<'tcx>) -> Self::Type;
|
||||||
|
@ -1392,11 +1392,11 @@ extern "C" void LLVMRustFreeOperandBundleDef(OperandBundleDef *Bundle) {
|
|||||||
delete Bundle;
|
delete Bundle;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMValueRef Fn,
|
extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
|
||||||
LLVMValueRef *Args, unsigned NumArgs,
|
LLVMValueRef *Args, unsigned NumArgs,
|
||||||
OperandBundleDef *Bundle) {
|
OperandBundleDef *Bundle) {
|
||||||
Value *Callee = unwrap(Fn);
|
Value *Callee = unwrap(Fn);
|
||||||
FunctionType *FTy = cast<FunctionType>(Callee->getType()->getPointerElementType());
|
FunctionType *FTy = unwrap<FunctionType>(Ty);
|
||||||
unsigned Len = Bundle ? 1 : 0;
|
unsigned Len = Bundle ? 1 : 0;
|
||||||
ArrayRef<OperandBundleDef> Bundles = makeArrayRef(Bundle, Len);
|
ArrayRef<OperandBundleDef> Bundles = makeArrayRef(Bundle, Len);
|
||||||
return wrap(unwrap(B)->CreateCall(
|
return wrap(unwrap(B)->CreateCall(
|
||||||
@ -1437,12 +1437,12 @@ extern "C" LLVMValueRef LLVMRustBuildMemSet(LLVMBuilderRef B,
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" LLVMValueRef
|
extern "C" LLVMValueRef
|
||||||
LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,
|
LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
|
||||||
unsigned NumArgs, LLVMBasicBlockRef Then,
|
LLVMValueRef *Args, unsigned NumArgs,
|
||||||
LLVMBasicBlockRef Catch, OperandBundleDef *Bundle,
|
LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch,
|
||||||
const char *Name) {
|
OperandBundleDef *Bundle, const char *Name) {
|
||||||
Value *Callee = unwrap(Fn);
|
Value *Callee = unwrap(Fn);
|
||||||
FunctionType *FTy = cast<FunctionType>(Callee->getType()->getPointerElementType());
|
FunctionType *FTy = unwrap<FunctionType>(Ty);
|
||||||
unsigned Len = Bundle ? 1 : 0;
|
unsigned Len = Bundle ? 1 : 0;
|
||||||
ArrayRef<OperandBundleDef> Bundles = makeArrayRef(Bundle, Len);
|
ArrayRef<OperandBundleDef> Bundles = makeArrayRef(Bundle, Len);
|
||||||
return wrap(unwrap(B)->CreateInvoke(FTy, Callee, unwrap(Then), unwrap(Catch),
|
return wrap(unwrap(B)->CreateInvoke(FTy, Callee, unwrap(Then), unwrap(Catch),
|
||||||
|
Loading…
Reference in New Issue
Block a user