Skip to content

Commit 485965d

Browse files
authored
Unrolled build for #148533
Rollup merge of #148533 - bjorn3:split_llvm_intrinsic_abi_handling, r=WaffleLapkin Split LLVM intrinsic abi handling from the rest of the abi handling LLVM intrinsics have weird requirements like requiring the fake "unadjusted" abi, not being callable through function pointers and for all codegen backends other than cg_llvm requiring special cases to redirect them to the correct backend specific intrinsic (or directly codegen their implementation inline without any intrinsic call). By splitting the LLVM intrinsic handling it becomes easier for backends to special case them and should in the future allow getting rid of the abi calculation for `extern "unadjusted"` in favor of computing the correct abi directly in the backend without depending on the exact way cg_ssa lowers types.
2 parents 7b5cde7 + aeac6cb commit 485965d

File tree

9 files changed

+269
-42
lines changed

9 files changed

+269
-42
lines changed

compiler/rustc_codegen_gcc/src/builder.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -314,14 +314,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
314314
self.block.get_function()
315315
}
316316

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

327325
// gccjit requires to use the result of functions, even when it's not used.
@@ -514,6 +512,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
514512
type CodegenCx = CodegenCx<'gcc, 'tcx>;
515513

516514
fn build(cx: &'a CodegenCx<'gcc, 'tcx>, block: Block<'gcc>) -> Builder<'a, 'gcc, 'tcx> {
515+
*cx.current_func.borrow_mut() = Some(block.get_function());
517516
Builder::with_cx(cx, block)
518517
}
519518

@@ -1765,6 +1764,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
17651764
// FIXME(antoyo): remove when having a proper API.
17661765
let gcc_func = unsafe { std::mem::transmute::<RValue<'gcc>, Function<'gcc>>(func) };
17671766
let call = if self.functions.borrow().values().any(|value| *value == gcc_func) {
1767+
// TODO(antoyo): remove when the API supports a different type for functions.
1768+
let func: Function<'gcc> = self.cx.rvalue_as_function(func);
17681769
self.function_call(func, args, funclet)
17691770
} else {
17701771
// If it's a not function that was defined, it's a function pointer.

compiler/rustc_codegen_gcc/src/context.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ pub struct CodegenCx<'gcc, 'tcx> {
9292
pub instances: RefCell<FxHashMap<Instance<'tcx>, LValue<'gcc>>>,
9393
/// Cache function instances of monomorphic and polymorphic items
9494
pub function_instances: RefCell<FxHashMap<Instance<'tcx>, Function<'gcc>>>,
95+
/// Cache function instances of intrinsics
96+
pub intrinsic_instances: RefCell<FxHashMap<Instance<'tcx>, Function<'gcc>>>,
9597
/// Cache generated vtables
9698
pub vtables:
9799
RefCell<FxHashMap<(Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>), RValue<'gcc>>>,
@@ -280,6 +282,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
280282
linkage: Cell::new(FunctionType::Internal),
281283
instances: Default::default(),
282284
function_instances: Default::default(),
285+
intrinsic_instances: Default::default(),
283286
on_stack_params: Default::default(),
284287
on_stack_function_params: Default::default(),
285288
vtables: Default::default(),
@@ -391,17 +394,13 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
391394
}
392395

393396
fn get_fn(&self, instance: Instance<'tcx>) -> Function<'gcc> {
394-
let func = get_fn(self, instance);
395-
*self.current_func.borrow_mut() = Some(func);
396-
func
397+
get_fn(self, instance)
397398
}
398399

399400
fn get_fn_addr(&self, instance: Instance<'tcx>) -> RValue<'gcc> {
400401
let func_name = self.tcx.symbol_name(instance).name;
401402

402-
let func = if self.intrinsics.borrow().contains_key(func_name) {
403-
self.intrinsics.borrow()[func_name]
404-
} else if let Some(variable) = self.get_declared_value(func_name) {
403+
let func = if let Some(variable) = self.get_declared_value(func_name) {
405404
return variable;
406405
} else {
407406
get_fn(self, instance)

compiler/rustc_codegen_gcc/src/declare.rs

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use rustc_target::callconv::FnAbi;
88

99
use crate::abi::{FnAbiGcc, FnAbiGccExt};
1010
use crate::context::CodegenCx;
11-
use crate::intrinsic::llvm;
1211

1312
impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
1413
pub fn get_or_insert_global(
@@ -100,18 +99,14 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
10099
let return_type = self.type_i32();
101100
let variadic = false;
102101
self.linkage.set(FunctionType::Exported);
103-
let func = declare_raw_fn(
102+
declare_raw_fn(
104103
self,
105104
name,
106105
callconv,
107106
return_type,
108107
&[self.type_i32(), const_string],
109108
variadic,
110-
);
111-
// NOTE: it is needed to set the current_func here as well, because get_fn() is not called
112-
// for the main function.
113-
*self.current_func.borrow_mut() = Some(func);
114-
func
109+
)
115110
}
116111

117112
pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Function<'gcc> {
@@ -166,19 +161,6 @@ fn declare_raw_fn<'gcc>(
166161
param_types: &[Type<'gcc>],
167162
variadic: bool,
168163
) -> Function<'gcc> {
169-
if name.starts_with("llvm.") {
170-
let intrinsic = match name {
171-
"llvm.fma.f16" => {
172-
// fma is not a target builtin, but a normal builtin, so we handle it differently
173-
// here.
174-
cx.context.get_builtin_function("fma")
175-
}
176-
_ => llvm::intrinsic(name, cx),
177-
};
178-
179-
cx.intrinsics.borrow_mut().insert(name.to_string(), intrinsic);
180-
return intrinsic;
181-
}
182164
let func = if cx.functions.borrow().contains_key(name) {
183165
cx.functions.borrow()[name]
184166
} else {

compiler/rustc_codegen_gcc/src/intrinsic/mod.rs

Lines changed: 92 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use gccjit::Type;
99
use gccjit::{ComparisonOp, Function, FunctionType, RValue, ToRValue, UnaryOp};
1010
#[cfg(feature = "master")]
1111
use rustc_abi::ExternAbi;
12-
use rustc_abi::{BackendRepr, HasDataLayout};
12+
use rustc_abi::{BackendRepr, HasDataLayout, WrappingRange};
1313
use rustc_codegen_ssa::MemFlags;
1414
use rustc_codegen_ssa::base::wants_msvc_seh;
1515
use rustc_codegen_ssa::common::IntPredicate;
@@ -20,19 +20,15 @@ use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue};
2020
use rustc_codegen_ssa::traits::MiscCodegenMethods;
2121
use rustc_codegen_ssa::traits::{
2222
ArgAbiBuilderMethods, BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods,
23-
IntrinsicCallBuilderMethods,
23+
IntrinsicCallBuilderMethods, LayoutTypeCodegenMethods,
2424
};
2525
use rustc_middle::bug;
26-
#[cfg(feature = "master")]
27-
use rustc_middle::ty::layout::FnAbiOf;
28-
use rustc_middle::ty::layout::LayoutOf;
26+
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
2927
use rustc_middle::ty::{self, Instance, Ty};
3028
use rustc_span::{Span, Symbol, sym};
3129
use rustc_target::callconv::{ArgAbi, PassMode};
3230

33-
#[cfg(feature = "master")]
34-
use crate::abi::FnAbiGccExt;
35-
use crate::abi::GccType;
31+
use crate::abi::{FnAbiGccExt, GccType};
3632
use crate::builder::Builder;
3733
use crate::common::{SignType, TypeReflection};
3834
use crate::context::CodegenCx;
@@ -609,6 +605,94 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
609605
Ok(())
610606
}
611607

608+
fn codegen_llvm_intrinsic_call(
609+
&mut self,
610+
instance: ty::Instance<'tcx>,
611+
args: &[OperandRef<'tcx, Self::Value>],
612+
is_cleanup: bool,
613+
) -> Self::Value {
614+
let func = if let Some(&func) = self.intrinsic_instances.borrow().get(&instance) {
615+
func
616+
} else {
617+
let sym = self.tcx.symbol_name(instance).name;
618+
619+
let func = if let Some(func) = self.intrinsics.borrow().get(sym) {
620+
*func
621+
} else {
622+
self.linkage.set(FunctionType::Extern);
623+
let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
624+
let fn_ty = fn_abi.gcc_type(self);
625+
626+
let func = match sym {
627+
"llvm.fma.f16" => {
628+
// fma is not a target builtin, but a normal builtin, so we handle it differently
629+
// here.
630+
self.context.get_builtin_function("fma")
631+
}
632+
_ => llvm::intrinsic(sym, self),
633+
};
634+
635+
self.intrinsics.borrow_mut().insert(sym.to_string(), func);
636+
637+
self.on_stack_function_params
638+
.borrow_mut()
639+
.insert(func, fn_ty.on_stack_param_indices);
640+
#[cfg(feature = "master")]
641+
for fn_attr in fn_ty.fn_attributes {
642+
func.add_attribute(fn_attr);
643+
}
644+
645+
crate::attributes::from_fn_attrs(self, func, instance);
646+
647+
func
648+
};
649+
650+
self.intrinsic_instances.borrow_mut().insert(instance, func);
651+
652+
func
653+
};
654+
let fn_ptr = func.get_address(None);
655+
let fn_ty = fn_ptr.get_type();
656+
657+
let mut llargs = vec![];
658+
659+
for arg in args {
660+
match arg.val {
661+
OperandValue::ZeroSized => {}
662+
OperandValue::Immediate(_) => llargs.push(arg.immediate()),
663+
OperandValue::Pair(a, b) => {
664+
llargs.push(a);
665+
llargs.push(b);
666+
}
667+
OperandValue::Ref(op_place_val) => {
668+
let mut llval = op_place_val.llval;
669+
// We can't use `PlaceRef::load` here because the argument
670+
// may have a type we don't treat as immediate, but the ABI
671+
// used for this call is passing it by-value. In that case,
672+
// the load would just produce `OperandValue::Ref` instead
673+
// of the `OperandValue::Immediate` we need for the call.
674+
llval = self.load(self.backend_type(arg.layout), llval, op_place_val.align);
675+
if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr {
676+
if scalar.is_bool() {
677+
self.range_metadata(llval, WrappingRange { start: 0, end: 1 });
678+
}
679+
// We store bools as `i8` so we need to truncate to `i1`.
680+
llval = self.to_immediate_scalar(llval, scalar);
681+
}
682+
llargs.push(llval);
683+
}
684+
}
685+
}
686+
687+
// FIXME directly use the llvm intrinsic adjustment functions here
688+
let llret = self.call(fn_ty, None, None, fn_ptr, &llargs, None, None);
689+
if is_cleanup {
690+
self.apply_attrs_to_cleanup_callsite(llret);
691+
}
692+
693+
llret
694+
}
695+
612696
fn abort(&mut self) {
613697
let func = self.context.get_builtin_function("abort");
614698
let func: RValue<'gcc> = unsafe { std::mem::transmute(func) };

compiler/rustc_codegen_llvm/src/builder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1705,7 +1705,7 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
17051705
ret.expect("LLVM does not have support for catchret")
17061706
}
17071707

1708-
fn check_call<'b>(
1708+
pub(crate) fn check_call<'b>(
17091709
&mut self,
17101710
typ: &str,
17111711
fn_ty: &'ll Type,

compiler/rustc_codegen_llvm/src/context.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ pub(crate) struct FullCx<'ll, 'tcx> {
101101

102102
/// Cache instances of monomorphic and polymorphic items
103103
pub instances: RefCell<FxHashMap<Instance<'tcx>, &'ll Value>>,
104+
/// Cache instances of intrinsics
105+
pub intrinsic_instances: RefCell<FxHashMap<Instance<'tcx>, &'ll Value>>,
104106
/// Cache generated vtables
105107
pub vtables: RefCell<FxHashMap<(Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>), &'ll Value>>,
106108
/// Cache of constant strings,
@@ -627,6 +629,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
627629
tls_model,
628630
codegen_unit,
629631
instances: Default::default(),
632+
intrinsic_instances: Default::default(),
630633
vtables: Default::default(),
631634
const_str_cache: Default::default(),
632635
const_globals: Default::default(),

compiler/rustc_codegen_llvm/src/intrinsic.rs

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
use std::assert_matches::assert_matches;
22
use std::cmp::Ordering;
3+
use std::ffi::c_uint;
4+
use std::ptr;
35

4-
use rustc_abi::{Align, BackendRepr, ExternAbi, Float, HasDataLayout, Primitive, Size};
6+
use rustc_abi::{
7+
Align, BackendRepr, ExternAbi, Float, HasDataLayout, Primitive, Size, WrappingRange,
8+
};
59
use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh, wants_wasm_eh};
610
use rustc_codegen_ssa::codegen_attrs::autodiff_attrs;
711
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
@@ -28,6 +32,7 @@ use crate::builder::Builder;
2832
use crate::builder::autodiff::{adjust_activity_to_abi, generate_enzyme_call};
2933
use crate::builder::gpu_offload::{gen_call_handling, gen_define_handling};
3034
use crate::context::CodegenCx;
35+
use crate::declare::declare_raw_fn;
3136
use crate::errors::{
3237
AutoDiffWithoutEnable, AutoDiffWithoutLto, OffloadWithoutEnable, OffloadWithoutFatLTO,
3338
};
@@ -633,6 +638,99 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
633638
Ok(())
634639
}
635640

641+
fn codegen_llvm_intrinsic_call(
642+
&mut self,
643+
instance: ty::Instance<'tcx>,
644+
args: &[OperandRef<'tcx, Self::Value>],
645+
is_cleanup: bool,
646+
) -> Self::Value {
647+
let tcx = self.tcx();
648+
649+
// FIXME remove usage of fn_abi
650+
let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
651+
assert!(!fn_abi.ret.is_indirect());
652+
let fn_ty = fn_abi.llvm_type(self);
653+
654+
let fn_ptr = if let Some(&llfn) = self.intrinsic_instances.borrow().get(&instance) {
655+
llfn
656+
} else {
657+
let sym = tcx.symbol_name(instance).name;
658+
659+
// FIXME use get_intrinsic
660+
let llfn = if let Some(llfn) = self.get_declared_value(sym) {
661+
llfn
662+
} else {
663+
// Function addresses in Rust are never significant, allowing functions to
664+
// be merged.
665+
let llfn = declare_raw_fn(
666+
self,
667+
sym,
668+
fn_abi.llvm_cconv(self),
669+
llvm::UnnamedAddr::Global,
670+
llvm::Visibility::Default,
671+
fn_ty,
672+
);
673+
fn_abi.apply_attrs_llfn(self, llfn, Some(instance));
674+
675+
llfn
676+
};
677+
678+
self.intrinsic_instances.borrow_mut().insert(instance, llfn);
679+
680+
llfn
681+
};
682+
683+
let mut llargs = vec![];
684+
685+
for arg in args {
686+
match arg.val {
687+
OperandValue::ZeroSized => {}
688+
OperandValue::Immediate(_) => llargs.push(arg.immediate()),
689+
OperandValue::Pair(a, b) => {
690+
llargs.push(a);
691+
llargs.push(b);
692+
}
693+
OperandValue::Ref(op_place_val) => {
694+
let mut llval = op_place_val.llval;
695+
// We can't use `PlaceRef::load` here because the argument
696+
// may have a type we don't treat as immediate, but the ABI
697+
// used for this call is passing it by-value. In that case,
698+
// the load would just produce `OperandValue::Ref` instead
699+
// of the `OperandValue::Immediate` we need for the call.
700+
llval = self.load(self.backend_type(arg.layout), llval, op_place_val.align);
701+
if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr {
702+
if scalar.is_bool() {
703+
self.range_metadata(llval, WrappingRange { start: 0, end: 1 });
704+
}
705+
// We store bools as `i8` so we need to truncate to `i1`.
706+
llval = self.to_immediate_scalar(llval, scalar);
707+
}
708+
llargs.push(llval);
709+
}
710+
}
711+
}
712+
713+
debug!("call intrinsic {:?} with args ({:?})", instance, llargs);
714+
let args = self.check_call("call", fn_ty, fn_ptr, &llargs);
715+
let llret = unsafe {
716+
llvm::LLVMBuildCallWithOperandBundles(
717+
self.llbuilder,
718+
fn_ty,
719+
fn_ptr,
720+
args.as_ptr() as *const &llvm::Value,
721+
args.len() as c_uint,
722+
ptr::dangling(),
723+
0,
724+
c"".as_ptr(),
725+
)
726+
};
727+
if is_cleanup {
728+
self.apply_attrs_to_cleanup_callsite(llret);
729+
}
730+
731+
llret
732+
}
733+
636734
fn abort(&mut self) {
637735
self.call_intrinsic("llvm.trap", &[], &[]);
638736
}

0 commit comments

Comments
 (0)