Skip to content

Commit c5cdf21

Browse files
committed
Lower x86-interrupt byval first arg as pointer
1 parent 0a3beda commit c5cdf21

7 files changed

Lines changed: 49 additions & 86 deletions

File tree

src/abi.rs

Lines changed: 26 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ use rustc_target::callconv::{ArgAttributes, CastTarget, FnAbi, PassMode};
1616
use rustc_target::spec::Arch;
1717

1818
use crate::builder::Builder;
19-
#[cfg(feature = "master")]
20-
use crate::common::type_is_pointer;
2119
use crate::context::CodegenCx;
2220
use crate::type_of::LayoutGccExt;
2321

@@ -153,7 +151,10 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
153151
#[cfg(not(feature = "master"))]
154152
let apply_attrs = |ty: Type<'gcc>, _attrs: &ArgAttributes, _arg_index: usize| ty;
155153

156-
for arg in self.args.iter() {
154+
for (source_arg_index, arg) in self.args.iter().enumerate() {
155+
#[cfg(not(feature = "master"))]
156+
let _ = source_arg_index;
157+
157158
let arg_ty = match arg.mode {
158159
PassMode::Ignore => continue,
159160
PassMode::Pair(a, b) => {
@@ -179,9 +180,28 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
179180
apply_attrs(ty, &cast.attrs, argument_tys.len())
180181
}
181182
PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: true } => {
182-
// This is a "byval" argument, so we don't apply the `restrict` attribute on it.
183-
on_stack_param_indices.insert(argument_tys.len());
184-
arg.layout.gcc_type(cx)
183+
let x86_interrupt_first_arg = {
184+
#[cfg(feature = "master")]
185+
{
186+
source_arg_index == 0
187+
&& matches!(self.conv, CanonAbi::Interrupt(InterruptKind::X86))
188+
}
189+
#[cfg(not(feature = "master"))]
190+
{
191+
false
192+
}
193+
};
194+
195+
if x86_interrupt_first_arg {
196+
// Rust lowers the first `x86-interrupt` argument as a byval stack slot.
197+
// LLVM represents that as a pointer parameter with `byval`; GCC's
198+
// interrupt attribute likewise requires a pointer-shaped first parameter.
199+
cx.type_ptr_to(arg.layout.gcc_type(cx))
200+
} else {
201+
// This is a "byval" argument, so we don't apply the `restrict` attribute on it.
202+
on_stack_param_indices.insert(argument_tys.len());
203+
arg.layout.gcc_type(cx)
204+
}
185205
}
186206
PassMode::Direct(attrs) => {
187207
apply_attrs(arg.layout.immediate_gcc_type(cx), &attrs, argument_tys.len())
@@ -279,33 +299,3 @@ pub fn conv_to_fn_attribute<'gcc>(conv: CanonAbi, arch: &Arch) -> Option<FnAttri
279299
};
280300
Some(attribute)
281301
}
282-
283-
/// GCC's `interrupt` attribute requires the first parameter of an `x86-interrupt`
284-
/// function to be a pointer. When it is not, libgccjit aborts codegen with an internal
285-
/// error and leaves no object file behind. Detect that case so the backend can emit a
286-
/// clean diagnostic and skip the attribute instead of crashing (issue #833).
287-
///
288-
/// This works on the already-lowered GCC argument types so callers that have them (e.g.
289-
/// `declare_fn`) avoid a redundant ABI lowering. `x86-interrupt` functions return `()`,
290-
/// so there is no struct-return pointer prepended and `arguments_type[0]` is the frame
291-
/// argument.
292-
#[cfg(feature = "master")]
293-
pub fn x86_interrupt_first_arg_is_invalid<'gcc>(
294-
conv: CanonAbi,
295-
arguments_type: &[Type<'gcc>],
296-
) -> bool {
297-
matches!(conv, CanonAbi::Interrupt(InterruptKind::X86))
298-
&& arguments_type.first().is_none_or(|ty| !type_is_pointer(*ty))
299-
}
300-
301-
/// Convenience wrapper around [`x86_interrupt_first_arg_is_invalid`] for callers that only
302-
/// hold the `FnAbi` and must lower it themselves. Short-circuits before lowering for the
303-
/// common non-`x86-interrupt` case.
304-
#[cfg(feature = "master")]
305-
pub fn x86_interrupt_has_invalid_first_arg<'gcc, 'tcx>(
306-
cx: &CodegenCx<'gcc, 'tcx>,
307-
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
308-
) -> bool {
309-
matches!(fn_abi.conv, CanonAbi::Interrupt(InterruptKind::X86))
310-
&& x86_interrupt_first_arg_is_invalid(fn_abi.conv, &fn_abi.gcc_type(cx).arguments_type)
311-
}

src/declare.rs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ use rustc_span::Symbol;
77
use rustc_target::callconv::FnAbi;
88

99
use crate::abi::FnAbiGccExt;
10-
#[cfg(feature = "master")]
11-
use crate::abi::x86_interrupt_first_arg_is_invalid;
1210
use crate::context::CodegenCx;
1311

1412
impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
@@ -112,18 +110,9 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
112110
}
113111

114112
pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Function<'gcc> {
115-
// Lower the ABI once and reuse it below, including for the `x86-interrupt` check,
116-
// instead of lowering it a second time inside a helper.
117113
let fn_abi_gcc = fn_abi.gcc_type(self);
118114
#[cfg(feature = "master")]
119-
let conv = if x86_interrupt_first_arg_is_invalid(fn_abi.conv, &fn_abi_gcc.arguments_type) {
120-
// GCC rejects an `x86-interrupt` function whose first argument is not a
121-
// pointer. Drop the calling-convention attribute so libgccjit does not abort;
122-
// a clean error is emitted in `predefine_fn` instead (issue #833).
123-
None
124-
} else {
125-
fn_abi.gcc_cconv(self)
126-
};
115+
let conv = fn_abi.gcc_cconv(self);
127116
#[cfg(not(feature = "master"))]
128117
let conv = None;
129118
let func = declare_raw_fn(

src/errors.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,3 @@ pub(crate) struct NulBytesInAsm {
3030
#[primary_span]
3131
pub span: Span,
3232
}
33-
34-
#[cfg(feature = "master")]
35-
#[derive(Diagnostic)]
36-
#[diag(
37-
"the GCC backend requires the first argument of an `x86-interrupt` function to be a pointer"
38-
)]
39-
pub(crate) struct X86InterruptBadFirstArg {
40-
#[primary_span]
41-
pub span: Span,
42-
}

src/mono_item.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,7 @@ use rustc_middle::mono::Visibility;
1010
use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv, LayoutOf};
1111
use rustc_middle::ty::{self, Instance, TypeVisitableExt};
1212

13-
#[cfg(feature = "master")]
14-
use crate::abi::x86_interrupt_has_invalid_first_arg;
1513
use crate::context::CodegenCx;
16-
#[cfg(feature = "master")]
17-
use crate::errors::X86InterruptBadFirstArg;
1814
use crate::type_of::LayoutGccExt;
1915
use crate::{attributes, base};
2016

@@ -55,12 +51,6 @@ impl<'gcc, 'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
5551
assert!(!instance.args.has_infer());
5652

5753
let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
58-
#[cfg(feature = "master")]
59-
if x86_interrupt_has_invalid_first_arg(self, fn_abi) {
60-
self.tcx
61-
.dcx()
62-
.emit_err(X86InterruptBadFirstArg { span: self.tcx.def_span(instance.def_id()) });
63-
}
6454
self.linkage.set(base::linkage_to_gcc(linkage));
6555
let decl = self.declare_fn(symbol_name, fn_abi);
6656
//let attrs = self.tcx.codegen_instance_attrs(instance.def);

tests/compile/x86_interrupt_bad_first_arg.rs

Lines changed: 0 additions & 17 deletions
This file was deleted.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Compiler:
2+
3+
// Test that an `x86-interrupt` function whose first argument is passed by value
4+
// emits a pointer-shaped GCC parameter instead of tripping libgccjit (issue #833).
5+
6+
#![feature(abi_x86_interrupt)]
7+
8+
#[repr(C)]
9+
pub struct Frame {
10+
ip: u64,
11+
}
12+
13+
pub extern "x86-interrupt" fn scalar(_a: i64) {}
14+
15+
pub extern "x86-interrupt" fn aggregate(_frame: Frame) {}
16+
17+
fn main() {
18+
// Take the functions' addresses so that they are codegened.
19+
let _scalar: extern "x86-interrupt" fn(i64) = scalar;
20+
let _aggregate: extern "x86-interrupt" fn(Frame) = aggregate;
21+
}

tests/lang_tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ fn compile_tests(tempdir: PathBuf, current_dir: String) {
216216
"asm_nul_byte.rs",
217217
"global_asm_nul_byte.rs",
218218
"naked_asm_nul_byte.rs",
219-
"x86_interrupt_bad_first_arg.rs",
219+
"x86_interrupt_first_arg_byval.rs",
220220
],
221221
);
222222
}

0 commit comments

Comments
 (0)