Skip to content
Closed
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
15 changes: 13 additions & 2 deletions compiler/rustc_codegen_llvm/src/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use std::ffi::c_uint;
use std::{assert_matches, iter, ptr};

use rustc_abi::{
AddressSpace, Align, BackendRepr, Float, HasDataLayout, Integer, NumScalableVectors, Primitive,
Size, WrappingRange,
AddressSpace, Align, BackendRepr, CVariadicStatus, Float, HasDataLayout, Integer,
NumScalableVectors, Primitive, Size, WrappingRange,
};
use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh, wants_wasm_eh};
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
Expand All @@ -23,6 +23,7 @@ use rustc_middle::ty::{
};
use rustc_middle::{bug, span_bug};
use rustc_session::config::CrateType;
use rustc_session::errors::feature_err;
use rustc_session::lint::builtin::DEPRECATED_LLVM_INTRINSIC;
use rustc_span::{Span, Symbol, sym};
use rustc_symbol_mangling::{mangle_internal_symbol, symbol_name_for_instance_in_crate};
Expand Down Expand Up @@ -288,6 +289,16 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
}
sym::breakpoint => self.call_intrinsic("llvm.debugtrap", &[], &[]),
sym::va_arg => {
let target = &self.cx.tcx.sess.target;
let stability = target.supports_c_variadic_definitions();
if let CVariadicStatus::Unstable { feature } = stability
&& !self.tcx.features().enabled(feature)
{
let msg =
format!("C-variadic function definitions on this target are unstable");
feature_err(&*self.sess(), feature, span, msg).emit();
}

let BackendRepr::Scalar(scalar) = result.layout.backend_repr else {
bug!("the va_arg intrinsic does not support non-scalar types")
};
Expand Down
220 changes: 220 additions & 0 deletions tests/assembly-llvm/c-variadic/avr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
//@ add-minicore
//@ assembly-output: emit-asm
//
//@ revisions: AVR
//@ [AVR] compile-flags: --target=avr-none -Ctarget-cpu=atmega328p
//@ [AVR] needs-llvm-components: avr
#![feature(c_variadic, c_variadic_experimental_arch, no_core, lang_items, intrinsics, rustc_attrs)]
#![no_core]
#![crate_type = "lib"]

// Check that rustc and clang output match, see https://godbolt.org/z/1MvxoceeT.

extern crate minicore;
use minicore::*;

#[lang = "va_arg_safe"]
pub unsafe trait VaArgSafe {}

unsafe impl VaArgSafe for i16 {}
unsafe impl VaArgSafe for i32 {}
unsafe impl VaArgSafe for i64 {}
unsafe impl VaArgSafe for f32 {}
unsafe impl VaArgSafe for f64 {}
unsafe impl<T> VaArgSafe for *const T {}

#[repr(transparent)]
struct VaListInner {
ptr: *const c_void,
}

#[repr(transparent)]
#[lang = "va_list"]
pub struct VaList<'a> {
inner: VaListInner,
_marker: PhantomData<&'a mut ()>,
}

#[rustc_intrinsic]
#[rustc_nounwind]
pub const unsafe fn va_arg<T: VaArgSafe>(ap: &mut VaList<'_>) -> T;

#[unsafe(no_mangle)]
unsafe extern "C" fn read_f32(ap: &mut VaList<'_>) -> f32 {
// CHECK-LABEL: read_f32
//
// AVR: movw r30, r24
// AVR-NEXT: ld r24, Z
// AVR-NEXT: ldd r25, Z+1
// AVR-NEXT: movw r26, r24
// AVR-NEXT: adiw r26, 2
// AVR-NEXT: std Z+1, r27
// AVR-NEXT: st Z, r26
// AVR-NEXT: movw r20, r30
// AVR-NEXT: movw r18, r24
// AVR-NEXT: movw r30, r18
// AVR-NEXT: ld r22, Z
// AVR-NEXT: ldd r23, Z+1
// AVR-NEXT: adiw r24, 4
// AVR-NEXT: movw r30, r20
// AVR-NEXT: std Z+1, r25
// AVR-NEXT: st Z, r24
// AVR-NEXT: movw r30, r18
// AVR-NEXT: ldd r24, Z+2
// AVR-NEXT: ldd r25, Z+3
// AVR-NEXT: ret
va_arg(ap)
}

#[unsafe(no_mangle)]
unsafe extern "C" fn read_f64(ap: &mut VaList<'_>) -> f64 {
// CHECK-LABEL: read_f64
//
// AVR: push r14
// AVR-NEXT: push r15
// AVR-NEXT: push r16
// AVR-NEXT: push r17
// AVR-NEXT: movw r30, r24
// AVR-NEXT: ld r24, Z
// AVR-NEXT: ldd r25, Z+1
// AVR-NEXT: movw r26, r24
// AVR-NEXT: adiw r26, 2
// AVR-NEXT: std Z+1, r27
// AVR-NEXT: st Z, r26
// AVR-NEXT: movw r14, r30
// AVR-NEXT: movw r16, r24
// AVR-NEXT: movw r30, r16
// AVR-NEXT: ld r18, Z
// AVR-NEXT: ldd r19, Z+1
// AVR-NEXT: movw r26, r24
// AVR-NEXT: adiw r26, 4
// AVR-NEXT: movw r30, r14
// AVR-NEXT: std Z+1, r27
// AVR-NEXT: st Z, r26
// AVR-NEXT: movw r30, r16
// AVR-NEXT: ldd r20, Z+2
// AVR-NEXT: ldd r21, Z+3
// AVR-NEXT: movw r26, r24
// AVR-NEXT: adiw r26, 6
// AVR-NEXT: movw r30, r14
// AVR-NEXT: std Z+1, r27
// AVR-NEXT: st Z, r26
// AVR-NEXT: movw r30, r16
// AVR-NEXT: ldd r22, Z+4
// AVR-NEXT: ldd r23, Z+5
// AVR-NEXT: adiw r24, 8
// AVR-NEXT: movw r30, r14
// AVR-NEXT: std Z+1, r25
// AVR-NEXT: st Z, r24
// AVR-NEXT: movw r30, r16
// AVR-NEXT: ldd r24, Z+6
// AVR-NEXT: ldd r25, Z+7
// AVR-NEXT: pop r17
// AVR-NEXT: pop r16
// AVR-NEXT: pop r15
// AVR-NEXT: pop r14
// AVR-NEXT: ret
va_arg(ap)
}

#[unsafe(no_mangle)]
unsafe extern "C" fn read_i16(ap: &mut VaList<'_>) -> i16 {
// CHECK-LABEL: read_i16
//
// AVR: movw r30, r24
// AVR-NEXT: ld r24, Z
// AVR-NEXT: ldd r25, Z+1
// AVR-NEXT: movw r26, r24
// AVR-NEXT: adiw r26, 2
// AVR-NEXT: std Z+1, r27
// AVR-NEXT: st Z, r26
// AVR-NEXT: movw r30, r24
// AVR-NEXT: ld r24, Z
// AVR-NEXT: ldd r25, Z+1
// AVR-NEXT: ret
va_arg(ap)
}

#[unsafe(no_mangle)]
unsafe extern "C" fn read_i32(ap: &mut VaList<'_>) -> i32 {
// CHECK-LABEL: read_i32
//
// AVR: movw r30, r24
// AVR-NEXT: ld r24, Z
// AVR-NEXT: ldd r25, Z+1
// AVR-NEXT: movw r26, r24
// AVR-NEXT: adiw r26, 2
// AVR-NEXT: std Z+1, r27
// AVR-NEXT: st Z, r26
// AVR-NEXT: movw r20, r30
// AVR-NEXT: movw r18, r24
// AVR-NEXT: movw r30, r18
// AVR-NEXT: ld r22, Z
// AVR-NEXT: ldd r23, Z+1
// AVR-NEXT: adiw r24, 4
// AVR-NEXT: movw r30, r20
// AVR-NEXT: std Z+1, r25
// AVR-NEXT: st Z, r24
// AVR-NEXT: movw r30, r18
// AVR-NEXT: ldd r24, Z+2
// AVR-NEXT: ldd r25, Z+3
// AVR-NEXT: ret
va_arg(ap)
}

#[unsafe(no_mangle)]
unsafe extern "C" fn read_i64(ap: &mut VaList<'_>) -> i64 {
// CHECK-LABEL: read_i64
//
// AVR: push r14
// AVR-NEXT: push r15
// AVR-NEXT: push r16
// AVR-NEXT: push r17
// AVR-NEXT: movw r30, r24
// AVR-NEXT: ld r24, Z
// AVR-NEXT: ldd r25, Z+1
// AVR-NEXT: movw r26, r24
// AVR-NEXT: adiw r26, 2
// AVR-NEXT: std Z+1, r27
// AVR-NEXT: st Z, r26
// AVR-NEXT: movw r14, r30
// AVR-NEXT: movw r16, r24
// AVR-NEXT: movw r30, r16
// AVR-NEXT: ld r18, Z
// AVR-NEXT: ldd r19, Z+1
// AVR-NEXT: movw r26, r24
// AVR-NEXT: adiw r26, 4
// AVR-NEXT: movw r30, r14
// AVR-NEXT: std Z+1, r27
// AVR-NEXT: st Z, r26
// AVR-NEXT: movw r30, r16
// AVR-NEXT: ldd r20, Z+2
// AVR-NEXT: ldd r21, Z+3
// AVR-NEXT: movw r26, r24
// AVR-NEXT: adiw r26, 6
// AVR-NEXT: movw r30, r14
// AVR-NEXT: std Z+1, r27
// AVR-NEXT: st Z, r26
// AVR-NEXT: movw r30, r16
// AVR-NEXT: ldd r22, Z+4
// AVR-NEXT: ldd r23, Z+5
// AVR-NEXT: adiw r24, 8
// AVR-NEXT: movw r30, r14
// AVR-NEXT: std Z+1, r25
// AVR-NEXT: st Z, r24
// AVR-NEXT: movw r30, r16
// AVR-NEXT: ldd r24, Z+6
// AVR-NEXT: ldd r25, Z+7
// AVR-NEXT: pop r17
// AVR-NEXT: pop r16
// AVR-NEXT: pop r15
// AVR-NEXT: pop r14
// AVR-NEXT: ret
va_arg(ap)
}

#[unsafe(no_mangle)]
unsafe extern "C" fn read_ptr(ap: &mut VaList<'_>) -> *const u8 {
// AVR: read_ptr = pm(read_i16)
va_arg(ap)
}
1 change: 1 addition & 0 deletions tests/assembly-llvm/c-variadic/sparc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//@ [SPARC64] compile-flags: -Copt-level=3 --target sparc64-unknown-linux-gnu
//@ [SPARC64] needs-llvm-components: sparc
#![feature(c_variadic, no_core, lang_items, intrinsics, rustc_attrs, asm_experimental_arch)]
#![cfg_attr(target_arch = "sparc", feature(c_variadic_experimental_arch))]
#![no_core]
#![crate_type = "lib"]

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Regression test for https://github.com/rust-lang/rust/issues/3888
//@ check-pass
#![allow(dead_code)]

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Regression test for https://github.com/rust-lang/rust/issues/4464
//@ check-pass
#![allow(dead_code)]

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Regression test for https://github.com/rust-lang/rust/issues/2470
//@ run-fail
//@ error-pattern:index out of bounds
//@ needs-subprocess
Expand Down
Loading