Skip to content

Commit b74f1c3

Browse files
Rollup merge of rust-lang#156043 - folkertdev:c-variadic-avr-assembly-test, r=joshtriplett
c-variadic: gate `va_arg` on `c_variadic_experimental_arch` tracking issue: rust-lang#44930 Just gating `...` is insufficient because we make the types available everywhere, and you could still define and export functions that used va_arg for targets where we don't want to stably support it. r? joshtriplett
2 parents 818811b + ddf2233 commit b74f1c3

3 files changed

Lines changed: 234 additions & 2 deletions

File tree

compiler/rustc_codegen_llvm/src/intrinsic.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use std::ffi::c_uint;
33
use std::{assert_matches, iter, ptr};
44

55
use rustc_abi::{
6-
AddressSpace, Align, BackendRepr, Float, HasDataLayout, Integer, NumScalableVectors, Primitive,
7-
Size, WrappingRange,
6+
AddressSpace, Align, BackendRepr, CVariadicStatus, Float, HasDataLayout, Integer,
7+
NumScalableVectors, Primitive, Size, WrappingRange,
88
};
99
use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh, wants_wasm_eh};
1010
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
@@ -23,6 +23,7 @@ use rustc_middle::ty::{
2323
};
2424
use rustc_middle::{bug, span_bug};
2525
use rustc_session::config::CrateType;
26+
use rustc_session::errors::feature_err;
2627
use rustc_session::lint::builtin::DEPRECATED_LLVM_INTRINSIC;
2728
use rustc_span::{Span, Symbol, sym};
2829
use rustc_symbol_mangling::{mangle_internal_symbol, symbol_name_for_instance_in_crate};
@@ -288,6 +289,16 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
288289
}
289290
sym::breakpoint => self.call_intrinsic("llvm.debugtrap", &[], &[]),
290291
sym::va_arg => {
292+
let target = &self.cx.tcx.sess.target;
293+
let stability = target.supports_c_variadic_definitions();
294+
if let CVariadicStatus::Unstable { feature } = stability
295+
&& !self.tcx.features().enabled(feature)
296+
{
297+
let msg =
298+
format!("C-variadic function definitions on this target are unstable");
299+
feature_err(&*self.sess(), feature, span, msg).emit();
300+
}
301+
291302
let BackendRepr::Scalar(scalar) = result.layout.backend_repr else {
292303
bug!("the va_arg intrinsic does not support non-scalar types")
293304
};
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
//@ add-minicore
2+
//@ assembly-output: emit-asm
3+
//
4+
//@ revisions: AVR
5+
//@ [AVR] compile-flags: --target=avr-none -Ctarget-cpu=atmega328p
6+
//@ [AVR] needs-llvm-components: avr
7+
#![feature(c_variadic, c_variadic_experimental_arch, no_core, lang_items, intrinsics, rustc_attrs)]
8+
#![no_core]
9+
#![crate_type = "lib"]
10+
11+
// Check that rustc and clang output match, see https://godbolt.org/z/1MvxoceeT.
12+
13+
extern crate minicore;
14+
use minicore::*;
15+
16+
#[lang = "va_arg_safe"]
17+
pub unsafe trait VaArgSafe {}
18+
19+
unsafe impl VaArgSafe for i16 {}
20+
unsafe impl VaArgSafe for i32 {}
21+
unsafe impl VaArgSafe for i64 {}
22+
unsafe impl VaArgSafe for f32 {}
23+
unsafe impl VaArgSafe for f64 {}
24+
unsafe impl<T> VaArgSafe for *const T {}
25+
26+
#[repr(transparent)]
27+
struct VaListInner {
28+
ptr: *const c_void,
29+
}
30+
31+
#[repr(transparent)]
32+
#[lang = "va_list"]
33+
pub struct VaList<'a> {
34+
inner: VaListInner,
35+
_marker: PhantomData<&'a mut ()>,
36+
}
37+
38+
#[rustc_intrinsic]
39+
#[rustc_nounwind]
40+
pub const unsafe fn va_arg<T: VaArgSafe>(ap: &mut VaList<'_>) -> T;
41+
42+
#[unsafe(no_mangle)]
43+
unsafe extern "C" fn read_f32(ap: &mut VaList<'_>) -> f32 {
44+
// CHECK-LABEL: read_f32
45+
//
46+
// AVR: movw r30, r24
47+
// AVR-NEXT: ld r24, Z
48+
// AVR-NEXT: ldd r25, Z+1
49+
// AVR-NEXT: movw r26, r24
50+
// AVR-NEXT: adiw r26, 2
51+
// AVR-NEXT: std Z+1, r27
52+
// AVR-NEXT: st Z, r26
53+
// AVR-NEXT: movw r20, r30
54+
// AVR-NEXT: movw r18, r24
55+
// AVR-NEXT: movw r30, r18
56+
// AVR-NEXT: ld r22, Z
57+
// AVR-NEXT: ldd r23, Z+1
58+
// AVR-NEXT: adiw r24, 4
59+
// AVR-NEXT: movw r30, r20
60+
// AVR-NEXT: std Z+1, r25
61+
// AVR-NEXT: st Z, r24
62+
// AVR-NEXT: movw r30, r18
63+
// AVR-NEXT: ldd r24, Z+2
64+
// AVR-NEXT: ldd r25, Z+3
65+
// AVR-NEXT: ret
66+
va_arg(ap)
67+
}
68+
69+
#[unsafe(no_mangle)]
70+
unsafe extern "C" fn read_f64(ap: &mut VaList<'_>) -> f64 {
71+
// CHECK-LABEL: read_f64
72+
//
73+
// AVR: push r14
74+
// AVR-NEXT: push r15
75+
// AVR-NEXT: push r16
76+
// AVR-NEXT: push r17
77+
// AVR-NEXT: movw r30, r24
78+
// AVR-NEXT: ld r24, Z
79+
// AVR-NEXT: ldd r25, Z+1
80+
// AVR-NEXT: movw r26, r24
81+
// AVR-NEXT: adiw r26, 2
82+
// AVR-NEXT: std Z+1, r27
83+
// AVR-NEXT: st Z, r26
84+
// AVR-NEXT: movw r14, r30
85+
// AVR-NEXT: movw r16, r24
86+
// AVR-NEXT: movw r30, r16
87+
// AVR-NEXT: ld r18, Z
88+
// AVR-NEXT: ldd r19, Z+1
89+
// AVR-NEXT: movw r26, r24
90+
// AVR-NEXT: adiw r26, 4
91+
// AVR-NEXT: movw r30, r14
92+
// AVR-NEXT: std Z+1, r27
93+
// AVR-NEXT: st Z, r26
94+
// AVR-NEXT: movw r30, r16
95+
// AVR-NEXT: ldd r20, Z+2
96+
// AVR-NEXT: ldd r21, Z+3
97+
// AVR-NEXT: movw r26, r24
98+
// AVR-NEXT: adiw r26, 6
99+
// AVR-NEXT: movw r30, r14
100+
// AVR-NEXT: std Z+1, r27
101+
// AVR-NEXT: st Z, r26
102+
// AVR-NEXT: movw r30, r16
103+
// AVR-NEXT: ldd r22, Z+4
104+
// AVR-NEXT: ldd r23, Z+5
105+
// AVR-NEXT: adiw r24, 8
106+
// AVR-NEXT: movw r30, r14
107+
// AVR-NEXT: std Z+1, r25
108+
// AVR-NEXT: st Z, r24
109+
// AVR-NEXT: movw r30, r16
110+
// AVR-NEXT: ldd r24, Z+6
111+
// AVR-NEXT: ldd r25, Z+7
112+
// AVR-NEXT: pop r17
113+
// AVR-NEXT: pop r16
114+
// AVR-NEXT: pop r15
115+
// AVR-NEXT: pop r14
116+
// AVR-NEXT: ret
117+
va_arg(ap)
118+
}
119+
120+
#[unsafe(no_mangle)]
121+
unsafe extern "C" fn read_i16(ap: &mut VaList<'_>) -> i16 {
122+
// CHECK-LABEL: read_i16
123+
//
124+
// AVR: movw r30, r24
125+
// AVR-NEXT: ld r24, Z
126+
// AVR-NEXT: ldd r25, Z+1
127+
// AVR-NEXT: movw r26, r24
128+
// AVR-NEXT: adiw r26, 2
129+
// AVR-NEXT: std Z+1, r27
130+
// AVR-NEXT: st Z, r26
131+
// AVR-NEXT: movw r30, r24
132+
// AVR-NEXT: ld r24, Z
133+
// AVR-NEXT: ldd r25, Z+1
134+
// AVR-NEXT: ret
135+
va_arg(ap)
136+
}
137+
138+
#[unsafe(no_mangle)]
139+
unsafe extern "C" fn read_i32(ap: &mut VaList<'_>) -> i32 {
140+
// CHECK-LABEL: read_i32
141+
//
142+
// AVR: movw r30, r24
143+
// AVR-NEXT: ld r24, Z
144+
// AVR-NEXT: ldd r25, Z+1
145+
// AVR-NEXT: movw r26, r24
146+
// AVR-NEXT: adiw r26, 2
147+
// AVR-NEXT: std Z+1, r27
148+
// AVR-NEXT: st Z, r26
149+
// AVR-NEXT: movw r20, r30
150+
// AVR-NEXT: movw r18, r24
151+
// AVR-NEXT: movw r30, r18
152+
// AVR-NEXT: ld r22, Z
153+
// AVR-NEXT: ldd r23, Z+1
154+
// AVR-NEXT: adiw r24, 4
155+
// AVR-NEXT: movw r30, r20
156+
// AVR-NEXT: std Z+1, r25
157+
// AVR-NEXT: st Z, r24
158+
// AVR-NEXT: movw r30, r18
159+
// AVR-NEXT: ldd r24, Z+2
160+
// AVR-NEXT: ldd r25, Z+3
161+
// AVR-NEXT: ret
162+
va_arg(ap)
163+
}
164+
165+
#[unsafe(no_mangle)]
166+
unsafe extern "C" fn read_i64(ap: &mut VaList<'_>) -> i64 {
167+
// CHECK-LABEL: read_i64
168+
//
169+
// AVR: push r14
170+
// AVR-NEXT: push r15
171+
// AVR-NEXT: push r16
172+
// AVR-NEXT: push r17
173+
// AVR-NEXT: movw r30, r24
174+
// AVR-NEXT: ld r24, Z
175+
// AVR-NEXT: ldd r25, Z+1
176+
// AVR-NEXT: movw r26, r24
177+
// AVR-NEXT: adiw r26, 2
178+
// AVR-NEXT: std Z+1, r27
179+
// AVR-NEXT: st Z, r26
180+
// AVR-NEXT: movw r14, r30
181+
// AVR-NEXT: movw r16, r24
182+
// AVR-NEXT: movw r30, r16
183+
// AVR-NEXT: ld r18, Z
184+
// AVR-NEXT: ldd r19, Z+1
185+
// AVR-NEXT: movw r26, r24
186+
// AVR-NEXT: adiw r26, 4
187+
// AVR-NEXT: movw r30, r14
188+
// AVR-NEXT: std Z+1, r27
189+
// AVR-NEXT: st Z, r26
190+
// AVR-NEXT: movw r30, r16
191+
// AVR-NEXT: ldd r20, Z+2
192+
// AVR-NEXT: ldd r21, Z+3
193+
// AVR-NEXT: movw r26, r24
194+
// AVR-NEXT: adiw r26, 6
195+
// AVR-NEXT: movw r30, r14
196+
// AVR-NEXT: std Z+1, r27
197+
// AVR-NEXT: st Z, r26
198+
// AVR-NEXT: movw r30, r16
199+
// AVR-NEXT: ldd r22, Z+4
200+
// AVR-NEXT: ldd r23, Z+5
201+
// AVR-NEXT: adiw r24, 8
202+
// AVR-NEXT: movw r30, r14
203+
// AVR-NEXT: std Z+1, r25
204+
// AVR-NEXT: st Z, r24
205+
// AVR-NEXT: movw r30, r16
206+
// AVR-NEXT: ldd r24, Z+6
207+
// AVR-NEXT: ldd r25, Z+7
208+
// AVR-NEXT: pop r17
209+
// AVR-NEXT: pop r16
210+
// AVR-NEXT: pop r15
211+
// AVR-NEXT: pop r14
212+
// AVR-NEXT: ret
213+
va_arg(ap)
214+
}
215+
216+
#[unsafe(no_mangle)]
217+
unsafe extern "C" fn read_ptr(ap: &mut VaList<'_>) -> *const u8 {
218+
// AVR: read_ptr = pm(read_i16)
219+
va_arg(ap)
220+
}

tests/assembly-llvm/c-variadic/sparc.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//@ [SPARC64] compile-flags: -Copt-level=3 --target sparc64-unknown-linux-gnu
88
//@ [SPARC64] needs-llvm-components: sparc
99
#![feature(c_variadic, no_core, lang_items, intrinsics, rustc_attrs, asm_experimental_arch)]
10+
#![cfg_attr(target_arch = "sparc", feature(c_variadic_experimental_arch))]
1011
#![no_core]
1112
#![crate_type = "lib"]
1213

0 commit comments

Comments
 (0)