diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index fb0d2d9c88219..f902a8b8d7ce1 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1401,4 +1401,22 @@ extern "rust-intrinsic" { /// Emits a `!nontemporal` store according to LLVM (see their docs). /// Probably will never become stable. pub fn nontemporal_store(ptr: *mut T, val: T); + + /// Initialize the arglist `ap` for processing via `va_arg`. + #[cfg(not(stage0))] + pub fn va_start(ap: *mut i8); + + /// Destroy the arglist `ap` after initialization with `va_start` or + /// `va_copy`. + #[cfg(not(stage0))] + pub fn va_end(ap: *mut i8); + + /// Copy the current location of arglist `ap0` to the arglist `ap1`. + #[cfg(not(stage0))] + pub fn va_copy(ap0: *const i8, ap1: *mut i8); + + /// Loads an argument of type `T` from the `va_list` `ap` and increment the + /// argument `ap` points to. + #[cfg(not(stage0))] + pub fn va_arg(ap: *mut i8) -> T; } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 90b2fb4b59a70..441d1e63bf954 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -658,6 +658,11 @@ fn declare_intrinsic(cx: &CodegenCx, key: &str) -> Option { ifn!("llvm.assume", fn(i1) -> void); ifn!("llvm.prefetch", fn(i8p, t_i32, t_i32, t_i32) -> void); + // variadic intrinsics + ifn!("llvm.va_start", fn(i8p) -> void); + ifn!("llvm.va_end", fn(i8p) -> void); + ifn!("llvm.va_copy", fn(i8p, i8p) -> void); + if cx.sess().opts.debuginfo != NoDebugInfo { ifn!("llvm.dbg.declare", fn(Type::metadata(cx), Type::metadata(cx)) -> void); ifn!("llvm.dbg.value", fn(Type::metadata(cx), t_i64, Type::metadata(cx)) -> void); diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 49a207a2d8ab5..32dba2eb65f5d 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -77,6 +77,9 @@ fn get_simple_intrinsic(cx: &CodegenCx, name: &str) -> Option { "roundf64" => "llvm.round.f64", "assume" => "llvm.assume", "abort" => "llvm.trap", + "va_start" => "llvm.va_start", + "va_copy" => "llvm.va_copy", + "va_end" => "llvm.va_end", _ => return None }; Some(cx.get_intrinsic(&llvm_name)) @@ -138,6 +141,9 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, let llfn = cx.get_intrinsic(&("llvm.debugtrap")); bx.call(llfn, &[], None) } + "va_arg" => { + bx.va_arg(args[0].immediate(), llret_ty) + } "size_of" => { let tp_ty = substs.type_at(0); C_usize(cx, cx.size_of(tp_ty).bytes()) diff --git a/src/librustc_trans/type_.rs b/src/librustc_trans/type_.rs index a77acc4f1756f..83ed809bb1da4 100644 --- a/src/librustc_trans/type_.rs +++ b/src/librustc_trans/type_.rs @@ -18,6 +18,7 @@ use context::CodegenCx; use syntax::ast; use rustc::ty::layout::{self, Align, Size}; +use rustc_target::spec::VaListKind; use std::ffi::CString; use std::fmt; @@ -297,4 +298,34 @@ impl Type { pub fn x86_mmx(cx: &CodegenCx) -> Type { ty!(llvm::LLVMX86MMXTypeInContext(cx.llcx)) } + + pub fn va_list(cx: &CodegenCx, name: &str) -> Type { + let int_t = Type::c_int(cx); + let voidp_t = Type::i8p(cx); + match cx.tcx.sess.target.target.options.va_list_kind { + VaListKind::CharPtr => { + Type::i8p(cx) + }, + VaListKind::VoidPtr => { + voidp_t + }, + VaListKind::X86_64Abi => { + let mut va_list_t = Type::named_struct(cx, name); + va_list_t.set_struct_body(&[int_t, int_t, voidp_t, voidp_t], false); + va_list_t + }, + VaListKind::AArch64Abi => { + let mut va_list_t = Type::named_struct(cx, name); + va_list_t.set_struct_body(&[voidp_t, voidp_t, voidp_t, int_t, int_t], false); + va_list_t + }, + VaListKind::PowerPcAbi => { + let i8_t = Type::i8(cx); + let i16_t = Type::i16(cx); + let mut va_list_t = Type::named_struct(cx, name); + va_list_t.set_struct_body(&[i8_t, i8_t, i16_t, voidp_t, voidp_t], false); + va_list_t + }, + } + } } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index fcf7541a159b0..95df8078d396d 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -319,6 +319,14 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (0, vec![ptr_ty, tcx.types.usize], tcx.types.usize) }, + "va_start" | "va_end" => (0, vec![tcx.mk_mut_ptr(tcx.types.i8)], tcx.mk_nil()), + + "va_copy" => { + (0, vec![tcx.mk_imm_ptr(tcx.types.i8), tcx.mk_mut_ptr(tcx.types.i8)], tcx.mk_nil()) + } + + "va_arg" => (1, vec![tcx.mk_mut_ptr(tcx.types.i8)], param(0)), + "nontemporal_store" => { (1, vec![ tcx.mk_mut_ptr(param(0)), param(0) ], tcx.mk_nil()) }