Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions compiler/rustc_codegen_gcc/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,14 +314,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
self.block.get_function()
}

fn function_call(
pub fn function_call(
&mut self,
func: RValue<'gcc>,
func: Function<'gcc>,
args: &[RValue<'gcc>],
_funclet: Option<&Funclet>,
) -> RValue<'gcc> {
// TODO(antoyo): remove when the API supports a different type for functions.
let func: Function<'gcc> = self.cx.rvalue_as_function(func);
let args = self.check_call("call", func, args);

// gccjit requires to use the result of functions, even when it's not used.
Expand Down Expand Up @@ -1752,6 +1750,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
// FIXME(antoyo): remove when having a proper API.
let gcc_func = unsafe { std::mem::transmute::<RValue<'gcc>, Function<'gcc>>(func) };
let call = if self.functions.borrow().values().any(|value| *value == gcc_func) {
// TODO(antoyo): remove when the API supports a different type for functions.
let func: Function<'gcc> = self.cx.rvalue_as_function(func);
self.function_call(func, args, funclet)
} else {
// If it's a not function that was defined, it's a function pointer.
Expand Down
51 changes: 49 additions & 2 deletions compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use gccjit::Type;
use gccjit::{ComparisonOp, Function, FunctionType, RValue, ToRValue, UnaryOp};
#[cfg(feature = "master")]
use rustc_abi::ExternAbi;
use rustc_abi::{BackendRepr, HasDataLayout};
use rustc_abi::{BackendRepr, HasDataLayout, WrappingRange};
use rustc_codegen_ssa::MemFlags;
use rustc_codegen_ssa::base::wants_msvc_seh;
use rustc_codegen_ssa::common::IntPredicate;
Expand All @@ -20,7 +20,7 @@ use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue};
use rustc_codegen_ssa::traits::MiscCodegenMethods;
use rustc_codegen_ssa::traits::{
ArgAbiBuilderMethods, BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods,
IntrinsicCallBuilderMethods,
IntrinsicCallBuilderMethods, LayoutTypeCodegenMethods,
};
use rustc_middle::bug;
#[cfg(feature = "master")]
Expand Down Expand Up @@ -640,6 +640,53 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
Ok(())
}

fn codegen_llvm_intrinsic_call(
&mut self,
instance: ty::Instance<'tcx>,
args: &[OperandRef<'tcx, Self::Value>],
is_cleanup: bool,
) -> Self::Value {
let fn_val = self.get_fn(instance);

let mut llargs = vec![];

for arg in args {
match arg.val {
OperandValue::ZeroSized => {}
OperandValue::Immediate(_) => llargs.push(arg.immediate()),
OperandValue::Pair(a, b) => {
llargs.push(a);
llargs.push(b);
}
OperandValue::Ref(op_place_val) => {
let mut llval = op_place_val.llval;
// We can't use `PlaceRef::load` here because the argument
// may have a type we don't treat as immediate, but the ABI
// used for this call is passing it by-value. In that case,
// the load would just produce `OperandValue::Ref` instead
// of the `OperandValue::Immediate` we need for the call.
llval = self.load(self.backend_type(arg.layout), llval, op_place_val.align);
if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr {
if scalar.is_bool() {
self.range_metadata(llval, WrappingRange { start: 0, end: 1 });
}
// We store bools as `i8` so we need to truncate to `i1`.
llval = self.to_immediate_scalar(llval, scalar);
}
llargs.push(llval);
}
}
}

// FIXME directly use the llvm intrinsic adjustment functions here
let llret = self.function_call(fn_val, &llargs, None);
if is_cleanup {
self.apply_attrs_to_cleanup_callsite(llret);
}

llret
}

fn abort(&mut self) {
let func = self.context.get_builtin_function("abort");
let func: RValue<'gcc> = unsafe { std::mem::transmute(func) };
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1622,7 +1622,7 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
ret.expect("LLVM does not have support for catchret")
}

fn check_call<'b>(
pub(crate) fn check_call<'b>(
&mut self,
typ: &str,
fn_ty: &'ll Type,
Expand Down
69 changes: 68 additions & 1 deletion compiler/rustc_codegen_llvm/src/intrinsic.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
use std::assert_matches::assert_matches;
use std::cmp::Ordering;
use std::ffi::c_uint;
use std::ptr;

use rustc_abi::{Align, BackendRepr, ExternAbi, Float, HasDataLayout, Primitive, Size};
use rustc_abi::{
Align, BackendRepr, ExternAbi, Float, HasDataLayout, Primitive, Size, WrappingRange,
};
use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh, wants_wasm_eh};
use rustc_codegen_ssa::codegen_attrs::autodiff_attrs;
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
Expand Down Expand Up @@ -617,6 +621,69 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
Ok(())
}

fn codegen_llvm_intrinsic_call(
&mut self,
instance: ty::Instance<'tcx>,
args: &[OperandRef<'tcx, Self::Value>],
is_cleanup: bool,
) -> Self::Value {
let fn_ptr = self.get_fn_addr(instance);
// FIXME remove usage of fn_abi
let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
assert!(!fn_abi.ret.is_indirect());
let fn_ty = self.fn_decl_backend_type(fn_abi);

let mut llargs = vec![];

for arg in args {
match arg.val {
OperandValue::ZeroSized => {}
OperandValue::Immediate(_) => llargs.push(arg.immediate()),
OperandValue::Pair(a, b) => {
llargs.push(a);
llargs.push(b);
}
OperandValue::Ref(op_place_val) => {
let mut llval = op_place_val.llval;
// We can't use `PlaceRef::load` here because the argument
// may have a type we don't treat as immediate, but the ABI
// used for this call is passing it by-value. In that case,
// the load would just produce `OperandValue::Ref` instead
// of the `OperandValue::Immediate` we need for the call.
llval = self.load(self.backend_type(arg.layout), llval, op_place_val.align);
if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr {
if scalar.is_bool() {
self.range_metadata(llval, WrappingRange { start: 0, end: 1 });
}
// We store bools as `i8` so we need to truncate to `i1`.
llval = self.to_immediate_scalar(llval, scalar);
}
llargs.push(llval);
}
}
}

debug!("call intrinsic {:?} with args ({:?})", instance, llargs);
let args = self.check_call("call", fn_ty, fn_ptr, &llargs);
let llret = unsafe {
llvm::LLVMBuildCallWithOperandBundles(
self.llbuilder,
fn_ty,
fn_ptr,
args.as_ptr() as *const &llvm::Value,
args.len() as c_uint,
ptr::dangling(),
0,
c"".as_ptr(),
)
};
if is_cleanup {
self.apply_attrs_to_cleanup_callsite(llret);
}

llret
}

fn abort(&mut self) {
self.call_intrinsic("llvm.trap", &[], &[]);
}
Expand Down
49 changes: 48 additions & 1 deletion compiler/rustc_codegen_ssa/src/mir/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use rustc_middle::{bug, span_bug};
use rustc_session::config::OptLevel;
use rustc_span::Span;
use rustc_span::source_map::Spanned;
use rustc_target::callconv::{ArgAbi, CastTarget, FnAbi, PassMode};
use rustc_target::callconv::{ArgAbi, ArgAttributes, CastTarget, FnAbi, PassMode};
use tracing::{debug, info};

use super::operand::OperandRef;
Expand Down Expand Up @@ -1034,6 +1034,53 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
_ => bug!("{} is not callable", callee.layout.ty),
};

if let Some(instance) = instance
&& let Some(name) = bx.tcx().codegen_fn_attrs(instance.def_id()).symbol_name
&& name.as_str().starts_with("llvm.")
{
let dest_ty = destination.ty(&self.mir.local_decls, bx.tcx()).ty;
let return_dest = if dest_ty.is_unit() {
ReturnDest::Nothing
} else if let Some(index) = destination.as_local() {
match self.locals[index] {
LocalRef::Place(dest) => ReturnDest::Store(dest),
LocalRef::UnsizedPlace(_) => bug!("return type must be sized"),
LocalRef::PendingOperand => {
// Handle temporary places, specifically `Operand` ones, as
// they don't have `alloca`s.
ReturnDest::DirectOperand(index)
}
LocalRef::Operand(_) => bug!("place local already assigned to"),
}
} else {
ReturnDest::Store(self.codegen_place(bx, destination.as_ref()))
};

let args =
args.into_iter().map(|arg| self.codegen_operand(bx, &arg.node)).collect::<Vec<_>>();

self.set_debug_loc(bx, source_info);

let llret =
bx.codegen_llvm_intrinsic_call(instance, &args, self.mir[helper.bb].is_cleanup);

if let Some(target) = target {
self.store_return(
bx,
return_dest,
&ArgAbi {
layout: bx.layout_of(dest_ty),
mode: PassMode::Direct(ArgAttributes::new()),
},
llret,
);
return helper.funclet_br(self, bx, target, mergeable_succ);
} else {
bx.unreachable();
return MergingSucc::False;
}
}

// FIXME(eddyb) avoid computing this if possible, when `instance` is
// available - right now `sig` is only needed for getting the `abi`
// and figuring out how many extra args were passed to a C-variadic `fn`.
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_codegen_ssa/src/traits/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ pub trait IntrinsicCallBuilderMethods<'tcx>: BackendTypes {
span: Span,
) -> Result<(), ty::Instance<'tcx>>;

fn codegen_llvm_intrinsic_call(
&mut self,
instance: ty::Instance<'tcx>,
args: &[OperandRef<'tcx, Self::Value>],
is_cleanup: bool,
) -> Self::Value;

fn abort(&mut self);
fn assume(&mut self, val: Self::Value);
fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value;
Expand Down
Loading