Merge commit '6ba33f5e1189a5ae58fb96ce3546e76b13d090f5' into subtree-update_cg_gcc_2025-05-14
This commit is contained in:
@@ -9,9 +9,9 @@ use rustc_middle::ty::Ty;
|
||||
use rustc_middle::ty::layout::LayoutOf;
|
||||
#[cfg(feature = "master")]
|
||||
use rustc_session::config;
|
||||
#[cfg(feature = "master")]
|
||||
use rustc_target::callconv::Conv;
|
||||
use rustc_target::callconv::{ArgAttributes, CastTarget, FnAbi, PassMode};
|
||||
#[cfg(feature = "master")]
|
||||
use rustc_target::callconv::{Conv, RiscvInterruptKind};
|
||||
|
||||
use crate::builder::Builder;
|
||||
use crate::context::CodegenCx;
|
||||
@@ -240,38 +240,57 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
||||
|
||||
#[cfg(feature = "master")]
|
||||
pub fn conv_to_fn_attribute<'gcc>(conv: Conv, arch: &str) -> Option<FnAttribute<'gcc>> {
|
||||
// TODO: handle the calling conventions returning None.
|
||||
let attribute = match conv {
|
||||
Conv::C
|
||||
| Conv::Rust
|
||||
| Conv::CCmseNonSecureCall
|
||||
| Conv::CCmseNonSecureEntry
|
||||
| Conv::RiscvInterrupt { .. } => return None,
|
||||
Conv::Cold => return None,
|
||||
Conv::C | Conv::Rust => return None,
|
||||
Conv::CCmseNonSecureCall => {
|
||||
if arch == "arm" {
|
||||
FnAttribute::ArmCmseNonsecureCall
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Conv::CCmseNonSecureEntry => {
|
||||
if arch == "arm" {
|
||||
FnAttribute::ArmCmseNonsecureEntry
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Conv::Cold => FnAttribute::Cold,
|
||||
// NOTE: the preserve attributes are not yet implemented in GCC:
|
||||
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110899
|
||||
Conv::PreserveMost => return None,
|
||||
Conv::PreserveAll => return None,
|
||||
Conv::GpuKernel => {
|
||||
// TODO(antoyo): remove clippy allow attribute when this is implemented.
|
||||
#[allow(clippy::if_same_then_else)]
|
||||
if arch == "amdgpu" {
|
||||
return None;
|
||||
FnAttribute::GcnAmdGpuHsaKernel
|
||||
} else if arch == "nvptx64" {
|
||||
return None;
|
||||
FnAttribute::NvptxKernel
|
||||
} else {
|
||||
panic!("Architecture {} does not support GpuKernel calling convention", arch);
|
||||
}
|
||||
}
|
||||
Conv::AvrInterrupt => return None,
|
||||
Conv::AvrNonBlockingInterrupt => return None,
|
||||
Conv::ArmAapcs => return None,
|
||||
Conv::Msp430Intr => return None,
|
||||
Conv::X86Fastcall => return None,
|
||||
Conv::X86Intr => return None,
|
||||
Conv::X86Stdcall => return None,
|
||||
Conv::X86ThisCall => return None,
|
||||
// TODO(antoyo): check if those AVR attributes are mapped correctly.
|
||||
Conv::AvrInterrupt => FnAttribute::AvrSignal,
|
||||
Conv::AvrNonBlockingInterrupt => FnAttribute::AvrInterrupt,
|
||||
Conv::ArmAapcs => FnAttribute::ArmPcs("aapcs"),
|
||||
Conv::Msp430Intr => FnAttribute::Msp430Interrupt,
|
||||
Conv::RiscvInterrupt { kind } => {
|
||||
let kind = match kind {
|
||||
RiscvInterruptKind::Machine => "machine",
|
||||
RiscvInterruptKind::Supervisor => "supervisor",
|
||||
};
|
||||
FnAttribute::RiscvInterrupt(kind)
|
||||
}
|
||||
Conv::X86Fastcall => FnAttribute::X86FastCall,
|
||||
Conv::X86Intr => FnAttribute::X86Interrupt,
|
||||
Conv::X86Stdcall => FnAttribute::X86Stdcall,
|
||||
Conv::X86ThisCall => FnAttribute::X86ThisCall,
|
||||
// NOTE: the vectorcall calling convention is not yet implemented in GCC:
|
||||
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89485
|
||||
Conv::X86VectorCall => return None,
|
||||
Conv::X86_64SysV => FnAttribute::SysvAbi,
|
||||
Conv::X86_64Win64 => FnAttribute::MsAbi,
|
||||
Conv::X86_64SysV => FnAttribute::X86SysvAbi,
|
||||
Conv::X86_64Win64 => FnAttribute::X86MsAbi,
|
||||
};
|
||||
Some(attribute)
|
||||
}
|
||||
|
||||
@@ -6,21 +6,69 @@ use rustc_attr_parsing::InlineAttr;
|
||||
use rustc_attr_parsing::InstructionSetAttr;
|
||||
#[cfg(feature = "master")]
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
#[cfg(feature = "master")]
|
||||
use rustc_middle::mir::TerminatorKind;
|
||||
use rustc_middle::ty;
|
||||
|
||||
use crate::context::CodegenCx;
|
||||
use crate::gcc_util::to_gcc_features;
|
||||
|
||||
/// Get GCC attribute for the provided inline heuristic.
|
||||
/// Checks if the function `instance` is recursively inline.
|
||||
/// Returns `false` if a functions is guaranteed to be non-recursive, and `true` if it *might* be recursive.
|
||||
#[cfg(feature = "master")]
|
||||
fn resursively_inline<'gcc, 'tcx>(
|
||||
cx: &CodegenCx<'gcc, 'tcx>,
|
||||
instance: ty::Instance<'tcx>,
|
||||
) -> bool {
|
||||
// No body, so we can't check if this is recursively inline, so we assume it is.
|
||||
if !cx.tcx.is_mir_available(instance.def_id()) {
|
||||
return true;
|
||||
}
|
||||
// `expect_local` ought to never fail: we should be checking a function within this codegen unit.
|
||||
let body = cx.tcx.optimized_mir(instance.def_id());
|
||||
for block in body.basic_blocks.iter() {
|
||||
let Some(ref terminator) = block.terminator else { continue };
|
||||
// I assume that the recursive-inline issue applies only to functions, and not to drops.
|
||||
// In principle, a recursive, `#[inline(always)]` drop could(?) exist, but I don't think it does.
|
||||
let TerminatorKind::Call { ref func, .. } = terminator.kind else { continue };
|
||||
let Some((def, _args)) = func.const_fn_def() else { continue };
|
||||
// Check if the called function is recursively inline.
|
||||
if matches!(
|
||||
cx.tcx.codegen_fn_attrs(def).inline,
|
||||
InlineAttr::Always | InlineAttr::Force { .. }
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Get GCC attribute for the provided inline heuristic, attached to `instance`.
|
||||
#[cfg(feature = "master")]
|
||||
#[inline]
|
||||
fn inline_attr<'gcc, 'tcx>(
|
||||
cx: &CodegenCx<'gcc, 'tcx>,
|
||||
inline: InlineAttr,
|
||||
instance: ty::Instance<'tcx>,
|
||||
) -> Option<FnAttribute<'gcc>> {
|
||||
match inline {
|
||||
InlineAttr::Always => {
|
||||
// We can't simply always return `always_inline` unconditionally.
|
||||
// It is *NOT A HINT* and does not work for recursive functions.
|
||||
//
|
||||
// So, it can only be applied *if*:
|
||||
// The current function does not call any functions marked `#[inline(always)]`.
|
||||
//
|
||||
// That prevents issues steming from recursive `#[inline(always)]` at a *relatively* small cost.
|
||||
// We *only* need to check all the terminators of a function marked with this attribute.
|
||||
if resursively_inline(cx, instance) {
|
||||
Some(FnAttribute::Inline)
|
||||
} else {
|
||||
Some(FnAttribute::AlwaysInline)
|
||||
}
|
||||
}
|
||||
InlineAttr::Hint => Some(FnAttribute::Inline),
|
||||
InlineAttr::Always | InlineAttr::Force { .. } => Some(FnAttribute::AlwaysInline),
|
||||
InlineAttr::Force { .. } => Some(FnAttribute::AlwaysInline),
|
||||
InlineAttr::Never => {
|
||||
if cx.sess().target.arch != "amdgpu" {
|
||||
Some(FnAttribute::NoInline)
|
||||
@@ -52,7 +100,7 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
|
||||
} else {
|
||||
codegen_fn_attrs.inline
|
||||
};
|
||||
if let Some(attr) = inline_attr(cx, inline) {
|
||||
if let Some(attr) = inline_attr(cx, inline, instance) {
|
||||
if let FnAttribute::AlwaysInline = attr {
|
||||
func.add_attribute(FnAttribute::Inline);
|
||||
}
|
||||
@@ -88,14 +136,8 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
|
||||
let target_features = function_features
|
||||
.iter()
|
||||
.filter_map(|feature| {
|
||||
// FIXME(antoyo): for some reasons, disabling SSE results in the following error when
|
||||
// compiling Rust for Linux:
|
||||
// SSE register return with SSE disabled
|
||||
// TODO(antoyo): support soft-float and retpoline-external-thunk.
|
||||
if feature.contains("soft-float")
|
||||
|| feature.contains("retpoline-external-thunk")
|
||||
|| *feature == "-sse"
|
||||
{
|
||||
// TODO(antoyo): support soft-float.
|
||||
if feature.contains("soft-float") {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
||||
@@ -593,7 +593,7 @@ fn thin_lto(
|
||||
Ok((opt_jobs, copy_jobs))
|
||||
}
|
||||
|
||||
pub unsafe fn optimize_thin_module(
|
||||
pub fn optimize_thin_module(
|
||||
thin_module: ThinModule<GccCodegenBackend>,
|
||||
_cgcx: &CodegenContext<GccCodegenBackend>,
|
||||
) -> Result<ModuleCodegen<GccContext>, FatalError> {
|
||||
|
||||
@@ -14,7 +14,7 @@ use crate::base::add_pic_option;
|
||||
use crate::errors::CopyBitcode;
|
||||
use crate::{GccCodegenBackend, GccContext};
|
||||
|
||||
pub(crate) unsafe fn codegen(
|
||||
pub(crate) fn codegen(
|
||||
cgcx: &CodegenContext<GccCodegenBackend>,
|
||||
dcx: DiagCtxtHandle<'_>,
|
||||
module: ModuleCodegen<GccContext>,
|
||||
|
||||
@@ -568,11 +568,28 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||
) {
|
||||
let mut gcc_cases = vec![];
|
||||
let typ = self.val_ty(value);
|
||||
for (on_val, dest) in cases {
|
||||
let on_val = self.const_uint_big(typ, on_val);
|
||||
gcc_cases.push(self.context.new_case(on_val, on_val, dest));
|
||||
// FIXME(FractalFir): This is a workaround for a libgccjit limitation.
|
||||
// Currently, libgccjit can't directly create 128 bit integers.
|
||||
// Since switch cases must be values, and casts are not constant, we can't use 128 bit switch cases.
|
||||
// In such a case, we will simply fall back to an if-ladder.
|
||||
// This *may* be slower than a native switch, but a slow working solution is better than none at all.
|
||||
if typ.is_i128(self) || typ.is_u128(self) {
|
||||
for (on_val, dest) in cases {
|
||||
let on_val = self.const_uint_big(typ, on_val);
|
||||
let is_case =
|
||||
self.context.new_comparison(self.location, ComparisonOp::Equals, value, on_val);
|
||||
let next_block = self.current_func().new_block("case");
|
||||
self.block.end_with_conditional(self.location, is_case, dest, next_block);
|
||||
self.block = next_block;
|
||||
}
|
||||
self.block.end_with_jump(self.location, default_block);
|
||||
} else {
|
||||
for (on_val, dest) in cases {
|
||||
let on_val = self.const_uint_big(typ, on_val);
|
||||
gcc_cases.push(self.context.new_case(on_val, on_val, dest));
|
||||
}
|
||||
self.block.end_with_switch(self.location, value, default_block, &gcc_cases);
|
||||
}
|
||||
self.block.end_with_switch(self.location, value, default_block, &gcc_cases);
|
||||
}
|
||||
|
||||
#[cfg(feature = "master")]
|
||||
|
||||
@@ -191,13 +191,11 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
||||
// TODO(antoyo): check if it's okay that no link_section is set.
|
||||
|
||||
let typ = self.val_ty(cv).get_aligned(align.bytes());
|
||||
let global = self.declare_private_global(&name[..], typ);
|
||||
global
|
||||
self.declare_private_global(&name[..], typ)
|
||||
}
|
||||
_ => {
|
||||
let typ = self.val_ty(cv).get_aligned(align.bytes());
|
||||
let global = self.declare_unnamed_global(typ);
|
||||
global
|
||||
self.declare_unnamed_global(typ)
|
||||
}
|
||||
};
|
||||
global.global_set_initializer_rvalue(cv);
|
||||
|
||||
@@ -289,7 +289,7 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
||||
) -> Self::DILocation {
|
||||
let pos = span.lo();
|
||||
let DebugLoc { file, line, col } = self.lookup_debug_loc(pos);
|
||||
let loc = match file.name {
|
||||
match file.name {
|
||||
rustc_span::FileName::Real(ref name) => match *name {
|
||||
rustc_span::RealFileName::LocalPath(ref name) => {
|
||||
if let Some(name) = name.to_str() {
|
||||
@@ -314,7 +314,6 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
||||
}
|
||||
},
|
||||
_ => Location::null(),
|
||||
};
|
||||
loc
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,6 +157,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
||||
///
|
||||
/// If there’s a value with the same name already declared, the function will
|
||||
/// update the declaration and return existing Value instead.
|
||||
#[allow(clippy::let_and_return)]
|
||||
fn declare_raw_fn<'gcc>(
|
||||
cx: &CodegenCx<'gcc, '_>,
|
||||
name: &str,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,9 +4,7 @@ mod simd;
|
||||
#[cfg(feature = "master")]
|
||||
use std::iter;
|
||||
|
||||
#[cfg(feature = "master")]
|
||||
use gccjit::FunctionType;
|
||||
use gccjit::{ComparisonOp, Function, RValue, ToRValue, Type, UnaryOp};
|
||||
use gccjit::{ComparisonOp, Function, FunctionType, RValue, ToRValue, Type, UnaryOp};
|
||||
#[cfg(feature = "master")]
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_abi::{BackendRepr, HasDataLayout};
|
||||
@@ -132,6 +130,72 @@ fn get_simple_intrinsic<'gcc, 'tcx>(
|
||||
Some(cx.context.get_builtin_function(gcc_name))
|
||||
}
|
||||
|
||||
// TODO(antoyo): We can probably remove these and use the fallback intrinsic implementation.
|
||||
fn get_simple_function<'gcc, 'tcx>(
|
||||
cx: &CodegenCx<'gcc, 'tcx>,
|
||||
name: Symbol,
|
||||
) -> Option<Function<'gcc>> {
|
||||
let (return_type, parameters, func_name) = match name {
|
||||
sym::minimumf32 => {
|
||||
let parameters = [
|
||||
cx.context.new_parameter(None, cx.float_type, "a"),
|
||||
cx.context.new_parameter(None, cx.float_type, "b"),
|
||||
];
|
||||
(cx.float_type, parameters, "fminimumf")
|
||||
}
|
||||
sym::minimumf64 => {
|
||||
let parameters = [
|
||||
cx.context.new_parameter(None, cx.double_type, "a"),
|
||||
cx.context.new_parameter(None, cx.double_type, "b"),
|
||||
];
|
||||
(cx.double_type, parameters, "fminimum")
|
||||
}
|
||||
sym::minimumf128 => {
|
||||
let f128_type = cx.type_f128();
|
||||
// GCC doesn't have the intrinsic we want so we use the compiler-builtins one
|
||||
// https://docs.rs/compiler_builtins/latest/compiler_builtins/math/full_availability/fn.fminimumf128.html
|
||||
let parameters = [
|
||||
cx.context.new_parameter(None, f128_type, "a"),
|
||||
cx.context.new_parameter(None, f128_type, "b"),
|
||||
];
|
||||
(f128_type, parameters, "fminimumf128")
|
||||
}
|
||||
sym::maximumf32 => {
|
||||
let parameters = [
|
||||
cx.context.new_parameter(None, cx.float_type, "a"),
|
||||
cx.context.new_parameter(None, cx.float_type, "b"),
|
||||
];
|
||||
(cx.float_type, parameters, "fmaximumf")
|
||||
}
|
||||
sym::maximumf64 => {
|
||||
let parameters = [
|
||||
cx.context.new_parameter(None, cx.double_type, "a"),
|
||||
cx.context.new_parameter(None, cx.double_type, "b"),
|
||||
];
|
||||
(cx.double_type, parameters, "fmaximum")
|
||||
}
|
||||
sym::maximumf128 => {
|
||||
let f128_type = cx.type_f128();
|
||||
// GCC doesn't have the intrinsic we want so we use the compiler-builtins one
|
||||
// https://docs.rs/compiler_builtins/latest/compiler_builtins/math/full_availability/fn.fmaximumf128.html
|
||||
let parameters = [
|
||||
cx.context.new_parameter(None, f128_type, "a"),
|
||||
cx.context.new_parameter(None, f128_type, "b"),
|
||||
];
|
||||
(f128_type, parameters, "fmaximumf128")
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
Some(cx.context.new_function(
|
||||
None,
|
||||
FunctionType::Extern,
|
||||
return_type,
|
||||
¶meters,
|
||||
func_name,
|
||||
false,
|
||||
))
|
||||
}
|
||||
|
||||
impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||
fn codegen_intrinsic_call(
|
||||
&mut self,
|
||||
@@ -160,6 +224,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
|
||||
let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout);
|
||||
|
||||
let simple = get_simple_intrinsic(self, name);
|
||||
let simple_func = get_simple_function(self, name);
|
||||
|
||||
// FIXME(tempdragon): Re-enable `clippy::suspicious_else_formatting` if the following issue is solved:
|
||||
// https://github.com/rust-lang/rust-clippy/issues/12497
|
||||
@@ -167,7 +232,15 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
|
||||
#[allow(clippy::suspicious_else_formatting)]
|
||||
let value = match name {
|
||||
_ if simple.is_some() => {
|
||||
let func = simple.expect("simple function");
|
||||
let func = simple.expect("simple intrinsic function");
|
||||
self.cx.context.new_call(
|
||||
self.location,
|
||||
func,
|
||||
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
|
||||
)
|
||||
}
|
||||
_ if simple_func.is_some() => {
|
||||
let func = simple_func.expect("simple function");
|
||||
self.cx.context.new_call(
|
||||
self.location,
|
||||
func,
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#![allow(internal_features)]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(rustc_private, decl_macro, never_type, trusted_len, let_chains)]
|
||||
#![feature(rustc_private, decl_macro, never_type, trusted_len)]
|
||||
#![allow(broken_intra_doc_links)]
|
||||
#![recursion_limit = "256"]
|
||||
#![warn(rust_2018_idioms)]
|
||||
@@ -454,7 +454,7 @@ impl WriteBackendMethods for GccCodegenBackend {
|
||||
}
|
||||
|
||||
/// This is the entrypoint for a hot plugged rustc_codegen_gccjit
|
||||
#[no_mangle]
|
||||
#[unsafe(no_mangle)]
|
||||
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
|
||||
#[cfg(feature = "master")]
|
||||
let info = {
|
||||
|
||||
Reference in New Issue
Block a user