1use rustc_abi::{
2 Align, BackendRepr, CVariadicStatus, Endian, Float, HasDataLayout, Integer, Primitive, Size,
3};
4use rustc_codegen_ssa::common::IntPredicate;
5use rustc_codegen_ssa::mir::operand::OperandRef;
6use rustc_codegen_ssa::traits::{
7 BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods, LayoutTypeCodegenMethods,
8};
9use rustc_middle::ty::Ty;
10use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
11use rustc_span::bug;
12use rustc_target::spec::{Arch, Env, LlvmAbi, RustcAbi, Target};
13
14use crate::builder::Builder;
15use crate::llvm::Value;
16use crate::type_of::LayoutLlvmExt;
17
18fn round_up_to_alignment<'ll>(
19 bx: &mut Builder<'_, 'll, '_>,
20 mut value: Value<'ll>,
21 align: Align,
22) -> Value<'ll> {
23 value = bx.add(value, bx.cx().const_i32(align.bytes() as i32 - 1));
24 bx.and(value, bx.cx().const_i32(-(align.bytes() as i32)))
25}
26
27fn round_pointer_up_to_alignment<'ll>(
28 bx: &mut Builder<'_, 'll, '_>,
29 addr: Value<'ll>,
30 align: Align,
31) -> Value<'ll> {
32 let ptr = bx.inbounds_ptradd(addr, bx.const_i32(align.bytes() as i32 - 1));
33 let pointer_width = bx.tcx().sess.target.pointer_width;
34 let mask = align.bytes().wrapping_neg() & (u64::MAX >> (64 - pointer_width));
35 bx.call_intrinsic(
36 "llvm.ptrmask",
37 &[bx.type_ptr(), bx.type_isize()],
38 &[ptr, bx.const_usize(mask)],
39 )
40}
41
42fn emit_direct_ptr_va_arg<'ll, 'tcx>(
43 bx: &mut Builder<'_, 'll, 'tcx>,
44 list: OperandRef<'tcx, Value<'ll>>,
45 size: Size,
46 align: Align,
47 slot_size: Align,
48 allow_higher_align: bool,
49 force_right_adjust: bool,
50) -> (Value<'ll>, Align) {
51 let va_list_ty = bx.type_ptr();
52 let va_list_addr = list.immediate();
53
54 let ptr_align_abi = bx.tcx().data_layout.pointer_align();
55 let ptr = bx.load(va_list_ty, va_list_addr, ptr_align_abi);
56
57 let (addr, addr_align) = if allow_higher_align && align > slot_size {
58 (round_pointer_up_to_alignment(bx, ptr, align), align)
59 } else {
60 (ptr, slot_size)
61 };
62
63 let aligned_size = size.align_to(slot_size).bytes() as i32;
64 let full_direct_size = bx.cx().const_i32(aligned_size);
65 let next = bx.inbounds_ptradd(addr, full_direct_size);
66 bx.store(next, va_list_addr, ptr_align_abi);
67
68 if size.bytes() < slot_size.bytes()
69 && bx.tcx().sess.target.endian == Endian::Big
70 && force_right_adjust
71 {
72 let adjusted_size = bx.cx().const_i32((slot_size.bytes() - size.bytes()) as i32);
73 let adjusted = bx.inbounds_ptradd(addr, adjusted_size);
74 (adjusted, align)
76 } else {
77 (addr, addr_align)
78 }
79}
80
81fn get_param_type_alignment<'ll, 'tcx>(
83 bx: &mut Builder<'_, 'll, 'tcx>,
84 layout: TyAndLayout<'tcx>,
85) -> Align {
86 let BackendRepr::Scalar(scalar) = layout.backend_repr else {
87 ::rustc_span::macros::bug_impl(None,
format_args!("unexpected backend repr {0:?}", layout.backend_repr),
Location::caller());bug!("unexpected backend repr {:?}", layout.backend_repr);
88 };
89
90 match bx.cx.tcx.sess.target.arch {
91 Arch::PowerPC | Arch::PowerPC64 => match scalar.primitive() {
92 Primitive::Int(integer, _) => match integer {
93 Integer::I8 | Integer::I16 => ::core::panicking::unreachable_default_msg()unreachable!(),
94 Integer::I32 | Integer::I64 => { }
95 Integer::I128 => return Align::EIGHT,
96 },
97 Primitive::Float(float) => match float {
98 Float::F16 | Float::F16B | Float::F32 | Float::X87F80 => ::core::panicking::unreachable_default_msg()unreachable!(),
99 Float::F64 | Float::F128 => { }
100 Float::PpcF128 => {
101 return if is_powerpc_softfloat_abi(&bx.cx.tcx.sess.target) {
102 Align::FOUR
103 } else {
104 Align::EIGHT
105 };
106 }
107 },
108 Primitive::Pointer(_) => { }
109 },
110 _ => { }
111 }
112
113 layout.align
114}
115
116enum PassMode {
117 Direct,
118 Indirect,
119}
120
121enum SlotSize {
122 Bytes8 = 8,
123 Bytes4 = 4,
124 Bytes1 = 1,
125}
126
127enum AllowHigherAlign {
132 No,
133 Yes,
134}
135
136enum ForceRightAdjust {
152 No,
153 Yes,
154}
155
156fn emit_ptr_va_arg<'ll, 'tcx>(
157 bx: &mut Builder<'_, 'll, 'tcx>,
158 list: OperandRef<'tcx, Value<'ll>>,
159 layout: TyAndLayout<'tcx>,
160 pass_mode: PassMode,
161 slot_size: SlotSize,
162 allow_higher_align: AllowHigherAlign,
163 force_right_adjust: ForceRightAdjust,
164) -> Value<'ll> {
165 let indirect = #[allow(non_exhaustive_omitted_patterns)] match pass_mode {
PassMode::Indirect => true,
_ => false,
}matches!(pass_mode, PassMode::Indirect);
166 let allow_higher_align = #[allow(non_exhaustive_omitted_patterns)] match allow_higher_align {
AllowHigherAlign::Yes => true,
_ => false,
}matches!(allow_higher_align, AllowHigherAlign::Yes);
167 let force_right_adjust = #[allow(non_exhaustive_omitted_patterns)] match force_right_adjust {
ForceRightAdjust::Yes => true,
_ => false,
}matches!(force_right_adjust, ForceRightAdjust::Yes);
168 let slot_size = Align::from_bytes(slot_size as u64).unwrap();
169
170 let (llty, size, align) = if indirect {
171 (
172 bx.cx.layout_of(Ty::new_imm_ptr(bx.cx.tcx, layout.ty)).llvm_type(bx.cx),
173 bx.cx.data_layout().pointer_size(),
174 bx.cx.data_layout().pointer_align(),
175 )
176 } else {
177 (layout.llvm_type(bx.cx), layout.size, get_param_type_alignment(bx, layout))
178 };
179 let (addr, addr_align) = emit_direct_ptr_va_arg(
180 bx,
181 list,
182 size,
183 align,
184 slot_size,
185 allow_higher_align,
186 force_right_adjust,
187 );
188 if indirect {
189 let tmp_ret = bx.load(llty, addr, addr_align);
190 bx.load(layout.llvm_type(bx.cx), tmp_ret, align)
191 } else {
192 bx.load(llty, addr, addr_align)
193 }
194}
195
196fn emit_aapcs_va_arg<'ll, 'tcx>(
197 bx: &mut Builder<'_, 'll, 'tcx>,
198 list: OperandRef<'tcx, Value<'ll>>,
199 layout: TyAndLayout<'tcx>,
200) -> Value<'ll> {
201 let dl = bx.cx.data_layout();
202
203 let va_list_addr = list.immediate();
214
215 let ptr_offset = 8;
220 let i32_offset = 4;
221 let gr_top = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(ptr_offset));
222 let vr_top = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(2 * ptr_offset));
223 let gr_offs = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(3 * ptr_offset));
224 let vr_offs = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(3 * ptr_offset + i32_offset));
225
226 let maybe_reg = bx.append_sibling_block("va_arg.maybe_reg");
227 let in_reg = bx.append_sibling_block("va_arg.in_reg");
228 let on_stack = bx.append_sibling_block("va_arg.on_stack");
229 let end = bx.append_sibling_block("va_arg.end");
230 let zero = bx.const_i32(0);
231 let offset_align = Align::FOUR;
232
233 let gr_type = layout.ty.is_any_ptr() || layout.ty.is_integral();
234 let (reg_off, reg_top, slot_size) = if gr_type {
235 let nreg = layout.size.bytes().div_ceil(8);
236 (gr_offs, gr_top, nreg * 8)
237 } else {
238 let nreg = layout.size.bytes().div_ceil(16);
239 (vr_offs, vr_top, nreg * 16)
240 };
241
242 let mut reg_off_v = bx.load(bx.type_i32(), reg_off, offset_align);
244 let use_stack = bx.icmp(IntPredicate::IntSGE, reg_off_v, zero);
245 bx.cond_br(use_stack, on_stack, maybe_reg);
246
247 bx.switch_to_block(maybe_reg);
252 if gr_type && layout.align.bytes() > 8 {
253 reg_off_v = bx.add(reg_off_v, bx.const_i32(15));
254 reg_off_v = bx.and(reg_off_v, bx.const_i32(-16));
255 }
256 let new_reg_off_v = bx.add(reg_off_v, bx.const_i32(slot_size as i32));
257
258 bx.store(new_reg_off_v, reg_off, offset_align);
259
260 let use_stack = bx.icmp(IntPredicate::IntSGT, new_reg_off_v, zero);
263 bx.cond_br(use_stack, on_stack, in_reg);
264
265 bx.switch_to_block(in_reg);
266 let top_type = bx.type_ptr();
267 let top = bx.load(top_type, reg_top, dl.pointer_align());
268
269 let mut reg_addr = bx.ptradd(top, reg_off_v);
271 if bx.tcx().sess.target.endian == Endian::Big && layout.size.bytes() != slot_size {
272 let offset = bx.const_i32((slot_size - layout.size.bytes()) as i32);
274 reg_addr = bx.ptradd(reg_addr, offset);
275 }
276 let reg_type = layout.llvm_type(bx);
277 let reg_value = bx.load(reg_type, reg_addr, layout.align);
278 bx.br(end);
279
280 bx.switch_to_block(on_stack);
282 let stack_value = emit_ptr_va_arg(
283 bx,
284 list,
285 layout,
286 PassMode::Direct,
287 SlotSize::Bytes8,
288 AllowHigherAlign::Yes,
289 match bx.tcx().sess.target.endian {
290 Endian::Big => ForceRightAdjust::Yes,
291 Endian::Little => ForceRightAdjust::No,
292 },
293 );
294 bx.br(end);
295
296 bx.switch_to_block(end);
297 bx.phi(layout.immediate_llvm_type(bx), &[reg_value, stack_value], &[in_reg, on_stack])
298}
299
300fn is_powerpc_softfloat_abi(target: &Target) -> bool {
301 if target.arch != Arch::PowerPC {
302 return false;
303 }
304
305 match target.rustc_abi {
306 Some(RustcAbi::Softfloat) => ::rustc_span::macros::bug_impl(None,
format_args!("there are currently no powerpc softfloat targets"),
Location::caller())bug!("there are currently no powerpc softfloat targets"),
307 Some(RustcAbi::PowerPcSpe) => true, None => false,
309 Some(other) => ::rustc_span::macros::bug_impl(None,
format_args!("unexpected powerpc abi {0:?}", other), Location::caller())bug!("unexpected powerpc abi {other:?}"),
310 }
311}
312
313fn emit_powerpc_va_arg<'ll, 'tcx>(
314 bx: &mut Builder<'_, 'll, 'tcx>,
315 list: OperandRef<'tcx, Value<'ll>>,
316 layout: TyAndLayout<'tcx>,
317) -> Value<'ll> {
318 let dl = bx.cx.data_layout();
319
320 let va_list_addr = list.immediate();
328
329 let layout = layout.peel_transparent_wrappers_from_non_1zst(bx.cx);
331
332 let is_indirect = false;
334
335 let is_int = match layout.layout.backend_repr() {
336 BackendRepr::Scalar(scalar) => match scalar.primitive() {
337 rustc_abi::Primitive::Int(_, _) | rustc_abi::Primitive::Pointer(_) => true,
338 rustc_abi::Primitive::Float(_) => false,
339 },
340 _ => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("all instances of VaArgSafe are represented as scalars")));
}unreachable!("all instances of VaArgSafe are represented as scalars"),
341 };
342
343 let is_passed_in_fprs = !(is_int || is_powerpc_softfloat_abi(&bx.cx.tcx.sess.target));
344
345 let num_regs_addr = if !is_passed_in_fprs {
346 va_list_addr } else {
348 bx.inbounds_ptradd(va_list_addr, bx.const_usize(1)) };
350
351 let mut num_regs = bx.load(bx.type_i8(), num_regs_addr, dl.i8_align);
352
353 if layout.size.bytes() == 8 && !is_passed_in_fprs {
355 num_regs = bx.add(num_regs, bx.const_u8(1));
356 num_regs = bx.and(num_regs, bx.const_u8(0b1111_1110));
357 }
358
359 let max_regs = 8u8;
360 let reg_size = if is_passed_in_fprs { 8 } else { 4 };
361 let reg_incr = layout.size.bytes().div_ceil(u64::from(reg_size)) as u8;
362 let use_regs = bx.icmp(IntPredicate::IntULE, num_regs, bx.const_u8(max_regs - reg_incr));
363
364 let ptr_align_abi = bx.tcx().data_layout.pointer_align();
365
366 let in_reg = bx.append_sibling_block("va_arg.in_reg");
367 let in_mem = bx.append_sibling_block("va_arg.in_mem");
368 let end = bx.append_sibling_block("va_arg.end");
369
370 bx.cond_br(use_regs, in_reg, in_mem);
371
372 let reg_addr = {
373 bx.switch_to_block(in_reg);
374
375 let reg_save_area_ptr = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(1 + 1 + 2 + 4));
376 let mut reg_addr = bx.load(bx.type_ptr(), reg_save_area_ptr, ptr_align_abi);
377
378 if is_passed_in_fprs {
380 reg_addr = bx.inbounds_ptradd(reg_addr, bx.cx.const_usize(32))
381 }
382
383 let reg_offset = bx.mul(num_regs, bx.cx().const_u8(reg_size));
386 let reg_addr = bx.inbounds_ptradd(reg_addr, reg_offset);
387
388 let new_num_regs = bx.add(num_regs, bx.cx.const_u8(reg_incr));
390 bx.store(new_num_regs, num_regs_addr, dl.i8_align);
391
392 bx.br(end);
393
394 reg_addr
395 };
396
397 let mem_addr = {
398 bx.switch_to_block(in_mem);
399
400 bx.store(bx.const_u8(max_regs), num_regs_addr, dl.i8_align);
401
402 let overflow_area_align = Align::FOUR;
404
405 let size = if !is_indirect {
406 layout.layout.size.align_to(overflow_area_align)
407 } else {
408 dl.pointer_size()
409 };
410
411 let overflow_area_ptr = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(1 + 1 + 2));
412 let mut overflow_area = bx.load(bx.type_ptr(), overflow_area_ptr, ptr_align_abi);
413
414 let align = get_param_type_alignment(bx, layout);
416 if align > overflow_area_align {
417 overflow_area = round_pointer_up_to_alignment(bx, overflow_area, align);
418 }
419
420 let mem_addr = overflow_area;
421
422 overflow_area = bx.inbounds_ptradd(overflow_area, bx.const_usize(size.bytes()));
424 bx.store(overflow_area, overflow_area_ptr, ptr_align_abi);
425
426 bx.br(end);
427
428 mem_addr
429 };
430
431 bx.switch_to_block(end);
433 let val_addr = bx.phi(bx.type_ptr(), &[reg_addr, mem_addr], &[in_reg, in_mem]);
434 let val_type = layout.llvm_type(bx);
435 let val_addr =
436 if is_indirect { bx.load(bx.cx.type_ptr(), val_addr, ptr_align_abi) } else { val_addr };
437 let align = get_param_type_alignment(bx, layout);
438 bx.load(val_type, val_addr, align)
439}
440
441fn emit_s390x_va_arg<'ll, 'tcx>(
442 bx: &mut Builder<'_, 'll, 'tcx>,
443 list: OperandRef<'tcx, Value<'ll>>,
444 layout: TyAndLayout<'tcx>,
445) -> Value<'ll> {
446 let dl = bx.cx.data_layout();
447
448 let va_list_addr = list.immediate();
458
459 let i64_offset = 8;
462 let ptr_offset = 8;
463 let gpr = va_list_addr;
464 let fpr = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(i64_offset));
465 let overflow_arg_area = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(2 * i64_offset));
466 let reg_save_area =
467 bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(2 * i64_offset + ptr_offset));
468
469 let in_reg = bx.append_sibling_block("va_arg.in_reg");
470 let in_mem = bx.append_sibling_block("va_arg.in_mem");
471 let end = bx.append_sibling_block("va_arg.end");
472 let ptr_align_abi = dl.pointer_align();
473
474 let target_ty_size = layout.size.bytes();
476 let indirect: bool = target_ty_size > 8 || !target_ty_size.is_power_of_two();
477 let unpadded_size = if indirect { 8 } else { target_ty_size };
478 let padded_size = 8;
479 let padding = padded_size - unpadded_size;
480
481 let is_single_fp_element = |layout: TyAndLayout<'_>| -> bool {
483 match layout.layout.backend_repr() {
484 BackendRepr::Scalar(scalar) => match scalar.primitive() {
485 Primitive::Float(Float::F16 | Float::F32 | Float::F64) => true,
486 Primitive::Float(Float::F128) => false,
487 Primitive::Int(_, _) | Primitive::Pointer(_) => false,
488 Primitive::Float(Float::F16B) => {
489 ::rustc_span::macros::bug_impl(None,
format_args!("`f16b` use in varadics unsupported on s390x"),
Location::caller())bug!("`f16b` use in varadics unsupported on s390x")
490 }
491 Primitive::Float(Float::PpcF128) => {
492 ::rustc_span::macros::bug_impl(None,
format_args!("`ppcf128` use in varadics unsupported on s390x"),
Location::caller())bug!("`ppcf128` use in varadics unsupported on s390x")
493 }
494 Primitive::Float(Float::X87F80) => {
495 ::rustc_span::macros::bug_impl(None,
format_args!("`x87_f80` use in varadics unsupported on s390x"),
Location::caller())bug!("`x87_f80` use in varadics unsupported on s390x")
496 }
497 },
498
499 _ => false,
500 }
501 };
502
503 let gpr_type = indirect || !is_single_fp_element(layout);
504 let (max_regs, reg_count, reg_save_index, reg_padding) =
505 if gpr_type { (5, gpr, 2, padding) } else { (4, fpr, 16, 0) };
506
507 let reg_count_v = bx.load(bx.type_i64(), reg_count, Align::from_bytes(8).unwrap());
509 let use_regs = bx.icmp(IntPredicate::IntULT, reg_count_v, bx.const_u64(max_regs));
510 bx.cond_br(use_regs, in_reg, in_mem);
511
512 bx.switch_to_block(in_reg);
514
515 let reg_ptr_v = bx.load(bx.type_ptr(), reg_save_area, ptr_align_abi);
517 let scaled_reg_count = bx.mul(reg_count_v, bx.const_u64(8));
518 let reg_off = bx.add(scaled_reg_count, bx.const_u64(reg_save_index * 8 + reg_padding));
519 let reg_addr = bx.ptradd(reg_ptr_v, reg_off);
520
521 let new_reg_count_v = bx.add(reg_count_v, bx.const_u64(1));
523 bx.store(new_reg_count_v, reg_count, Align::from_bytes(8).unwrap());
524 bx.br(end);
525
526 bx.switch_to_block(in_mem);
528
529 let arg_ptr_v = bx.load(bx.type_ptr(), overflow_arg_area, ptr_align_abi);
531 let arg_off = bx.const_u64(padding);
532 let mem_addr = bx.ptradd(arg_ptr_v, arg_off);
533
534 let arg_size = bx.cx().const_u64(padded_size);
536 let new_arg_ptr_v = bx.inbounds_ptradd(arg_ptr_v, arg_size);
537 bx.store(new_arg_ptr_v, overflow_arg_area, ptr_align_abi);
538 bx.br(end);
539
540 bx.switch_to_block(end);
542 let val_addr = bx.phi(bx.type_ptr(), &[reg_addr, mem_addr], &[in_reg, in_mem]);
543 let val_type = layout.llvm_type(bx);
544 let val_addr =
545 if indirect { bx.load(bx.cx.type_ptr(), val_addr, ptr_align_abi) } else { val_addr };
546 bx.load(val_type, val_addr, layout.align)
547}
548
549fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>(
550 bx: &mut Builder<'_, 'll, 'tcx>,
551 list: OperandRef<'tcx, Value<'ll>>,
552 layout: TyAndLayout<'tcx>,
553) -> Value<'ll> {
554 let dl = bx.cx.data_layout();
555
556 let va_list_addr = list.immediate();
570
571 let layout = layout.peel_transparent_wrappers_from_non_1zst(bx.cx);
588
589 let mut num_gp_registers = 0;
597 let mut num_fp_registers = 0;
598
599 let mut registers_for_primitive = |p| match p {
600 Primitive::Int(integer, _is_signed) => {
601 num_gp_registers += integer.size().bytes().div_ceil(8) as u32;
602 }
603 Primitive::Float(float) => {
604 num_fp_registers += float.size().bytes().div_ceil(16) as u32;
605 }
606 Primitive::Pointer(_) => {
607 num_gp_registers += 1;
608 }
609 };
610
611 match layout.layout.backend_repr() {
612 BackendRepr::Scalar(scalar) => {
613 registers_for_primitive(scalar.primitive());
614 }
615 BackendRepr::ScalarPair { a: scalar1, b: scalar2, b_offset: _ } => {
616 registers_for_primitive(scalar1.primitive());
617 registers_for_primitive(scalar2.primitive());
618 }
619 BackendRepr::SimdVector { .. } | BackendRepr::SimdScalableVector { .. } => {
620 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("No x86-64 SysV va_arg implementation for {0:?}",
layout.layout.backend_repr())));
}unreachable!(
622 "No x86-64 SysV va_arg implementation for {:?}",
623 layout.layout.backend_repr()
624 )
625 }
626 BackendRepr::Memory { .. } => {
627 let mem_addr = x86_64_sysv64_va_arg_from_memory(bx, va_list_addr, layout);
628 return bx.load(layout.llvm_type(bx), mem_addr, layout.align);
629 }
630 };
631
632 let unsigned_int_offset = 4;
638 let ptr_offset = bx.tcx().data_layout.pointer_size().bytes();
639
640 let gp_offset_ptr = va_list_addr;
641 let fp_offset_ptr = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(unsigned_int_offset));
642
643 let gp_offset_v = bx.load(bx.type_i32(), gp_offset_ptr, Align::EIGHT);
644 let fp_offset_v = bx.load(bx.type_i32(), fp_offset_ptr, Align::FOUR);
645
646 let mut use_regs = bx.const_bool(false);
647
648 if num_gp_registers > 0 {
649 let max_offset_val = 48u32 - num_gp_registers * 8;
650 let fits_in_gp = bx.icmp(IntPredicate::IntULE, gp_offset_v, bx.const_u32(max_offset_val));
651 use_regs = fits_in_gp;
652 }
653
654 if num_fp_registers > 0 {
655 let max_offset_val = 176u32 - num_fp_registers * 16;
656 let fits_in_fp = bx.icmp(IntPredicate::IntULE, fp_offset_v, bx.const_u32(max_offset_val));
657 use_regs = if num_gp_registers > 0 { bx.and(use_regs, fits_in_fp) } else { fits_in_fp };
658 }
659
660 let in_reg = bx.append_sibling_block("va_arg.in_reg");
661 let in_mem = bx.append_sibling_block("va_arg.in_mem");
662 let end = bx.append_sibling_block("va_arg.end");
663
664 bx.cond_br(use_regs, in_reg, in_mem);
665
666 bx.switch_to_block(in_reg);
668
669 let reg_save_area_ptr =
680 bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(2 * unsigned_int_offset + ptr_offset));
681 let reg_save_area_v = bx.load(bx.type_ptr(), reg_save_area_ptr, dl.pointer_align());
682
683 let reg_addr = match layout.layout.backend_repr() {
684 BackendRepr::Scalar(scalar) => match scalar.primitive() {
685 Primitive::Int(_, _) | Primitive::Pointer(_) => {
686 let reg_addr = bx.inbounds_ptradd(reg_save_area_v, gp_offset_v);
687
688 let gp_align = Align::from_bytes(8).unwrap();
690 copy_to_temporary_if_more_aligned(bx, reg_addr, layout, gp_align)
691 }
692 Primitive::Float(_) => bx.inbounds_ptradd(reg_save_area_v, fp_offset_v),
693 },
694 BackendRepr::ScalarPair { a: scalar1, b: scalar2, b_offset: offset } => {
695 let ty_lo = bx.cx().scalar_pair_element_backend_type(layout, 0, false);
696 let ty_hi = bx.cx().scalar_pair_element_backend_type(layout, 1, false);
697
698 let align_lo = layout.field(bx.cx, 0).layout.align();
699 let align_hi = layout.field(bx.cx, 1).layout.align();
700
701 match (scalar1.primitive(), scalar2.primitive()) {
702 (Primitive::Float(_), Primitive::Float(_)) => {
703 let reg_lo_addr = bx.inbounds_ptradd(reg_save_area_v, fp_offset_v);
710 let reg_hi_addr = bx.inbounds_ptradd(reg_lo_addr, bx.const_i32(16));
711
712 let align = layout.layout.align();
713 let tmp = bx.alloca(layout.size, layout.align);
714
715 let reg_lo = bx.load(ty_lo, reg_lo_addr, align_lo);
716 let reg_hi = bx.load(ty_hi, reg_hi_addr, align_hi);
717
718 let field0 = tmp;
719 let field1 = bx.inbounds_ptradd(tmp, bx.const_u32(offset.bytes() as u32));
720
721 bx.store(reg_lo, field0, align);
722 bx.store(reg_hi, field1, align);
723
724 tmp
725 }
726 (Primitive::Float(_), _) | (_, Primitive::Float(_)) => {
727 let gp_addr = bx.inbounds_ptradd(reg_save_area_v, gp_offset_v);
728 let fp_addr = bx.inbounds_ptradd(reg_save_area_v, fp_offset_v);
729
730 let (reg_lo_addr, reg_hi_addr) = match scalar1.primitive() {
731 Primitive::Float(_) => (fp_addr, gp_addr),
732 Primitive::Int(_, _) | Primitive::Pointer(_) => (gp_addr, fp_addr),
733 };
734
735 let tmp = bx.alloca(layout.size, layout.align);
736
737 let reg_lo = bx.load(ty_lo, reg_lo_addr, align_lo);
738 let reg_hi = bx.load(ty_hi, reg_hi_addr, align_hi);
739
740 let field0 = tmp;
741 let field1 = bx.inbounds_ptradd(tmp, bx.const_u32(offset.bytes() as u32));
742
743 bx.store(reg_lo, field0, align_lo);
744 bx.store(reg_hi, field1, align_hi);
745
746 tmp
747 }
748 (_, _) => {
749 let reg_addr = bx.inbounds_ptradd(reg_save_area_v, gp_offset_v);
751
752 let gp_align = Align::from_bytes(8).unwrap();
754 copy_to_temporary_if_more_aligned(bx, reg_addr, layout, gp_align)
755 }
756 }
757 }
758 BackendRepr::SimdVector { .. }
760 | BackendRepr::SimdScalableVector { .. }
761 | BackendRepr::Memory { .. } => ::core::panicking::unreachable_default_msg()unreachable!(),
762 };
763
764 if num_gp_registers > 0 {
767 let offset = bx.const_u32(num_gp_registers * 8);
768 let sum = bx.add(gp_offset_v, offset);
769 bx.store(sum, gp_offset_ptr, Align::from_bytes(8).unwrap());
771 }
772
773 if num_fp_registers > 0 {
775 let offset = bx.const_u32(num_fp_registers * 16);
776 let sum = bx.add(fp_offset_v, offset);
777 bx.store(sum, fp_offset_ptr, Align::FOUR);
778 }
779
780 bx.br(end);
781
782 bx.switch_to_block(in_mem);
783 let mem_addr = x86_64_sysv64_va_arg_from_memory(bx, va_list_addr, layout);
784 bx.br(end);
785
786 bx.switch_to_block(end);
787
788 let val_type = layout.llvm_type(bx);
789 let val_addr = bx.phi(bx.type_ptr(), &[reg_addr, mem_addr], &[in_reg, in_mem]);
790
791 bx.load(val_type, val_addr, layout.align)
792}
793
794fn copy_to_temporary_if_more_aligned<'ll, 'tcx>(
796 bx: &mut Builder<'_, 'll, 'tcx>,
797 reg_addr: Value<'ll>,
798 layout: TyAndLayout<'tcx>,
799 src_align: Align,
800) -> Value<'ll> {
801 if layout.layout.align > src_align {
802 if !layout.ty.is_integral() {
::core::panicking::panic("assertion failed: layout.ty.is_integral()")
};assert!(layout.ty.is_integral());
803
804 let tmp = bx.alloca(layout.size, layout.align);
806 let val = bx.load(layout.llvm_type(bx), reg_addr, src_align);
807 bx.store(val, tmp, layout.align);
808 tmp
809 } else {
810 reg_addr
811 }
812}
813
814fn x86_64_sysv64_va_arg_from_memory<'ll, 'tcx>(
815 bx: &mut Builder<'_, 'll, 'tcx>,
816 va_list_addr: Value<'ll>,
817 layout: TyAndLayout<'tcx>,
818) -> Value<'ll> {
819 let dl = bx.cx.data_layout();
820 let ptr_align_abi = dl.data_layout().pointer_align();
821
822 let overflow_arg_area_ptr = bx.inbounds_ptradd(va_list_addr, bx.const_usize(8));
823
824 let overflow_arg_area_v = bx.load(bx.type_ptr(), overflow_arg_area_ptr, ptr_align_abi);
825 let overflow_arg_area_v = if layout.layout.align.bytes() > 8 {
833 round_pointer_up_to_alignment(bx, overflow_arg_area_v, layout.layout.align)
834 } else {
835 overflow_arg_area_v
836 };
837
838 let mem_addr = overflow_arg_area_v;
840
841 let size_in_bytes = layout.layout.size().bytes();
846 let offset = bx.const_i32(size_in_bytes.next_multiple_of(8) as i32);
847 let overflow_arg_area = bx.inbounds_ptradd(overflow_arg_area_v, offset);
848 bx.store(overflow_arg_area, overflow_arg_area_ptr, ptr_align_abi);
849
850 mem_addr
851}
852
853fn emit_hexagon_va_arg_musl<'ll, 'tcx>(
854 bx: &mut Builder<'_, 'll, 'tcx>,
855 list: OperandRef<'tcx, Value<'ll>>,
856 layout: TyAndLayout<'tcx>,
857) -> Value<'ll> {
858 let va_list_addr = list.immediate();
870 let ptr_align_abi = bx.tcx().data_layout.pointer_align();
871 let ptr_size = bx.tcx().data_layout.pointer_size().bytes();
872
873 let maybe_reg = bx.append_sibling_block("va_arg.maybe_reg");
875 let from_overflow = bx.append_sibling_block("va_arg.from_overflow");
876 let end = bx.append_sibling_block("va_arg.end");
877
878 let current_ptr_addr = va_list_addr;
880 let end_ptr_addr = bx.inbounds_ptradd(va_list_addr, bx.const_usize(ptr_size));
881 let overflow_ptr_addr = bx.inbounds_ptradd(va_list_addr, bx.const_usize(2 * ptr_size));
882
883 let current_ptr = bx.load(bx.type_ptr(), current_ptr_addr, ptr_align_abi);
884 let end_ptr = bx.load(bx.type_ptr(), end_ptr_addr, ptr_align_abi);
885 let overflow_ptr = bx.load(bx.type_ptr(), overflow_ptr_addr, ptr_align_abi);
886
887 let type_size_bits = layout.size.bits();
890 let arg_align = if type_size_bits > 32 { Align::EIGHT } else { Align::FOUR };
891 let aligned_current = round_pointer_up_to_alignment(bx, current_ptr, arg_align);
892
893 let arg_size = if type_size_bits > 32 { 8 } else { 4 };
896 let next_ptr = bx.inbounds_ptradd(aligned_current, bx.const_usize(arg_size));
897
898 let fits_in_regs = bx.icmp(IntPredicate::IntULE, next_ptr, end_ptr);
900 bx.cond_br(fits_in_regs, maybe_reg, from_overflow);
901
902 bx.switch_to_block(maybe_reg);
904 let reg_value_addr = aligned_current;
905 bx.store(next_ptr, current_ptr_addr, ptr_align_abi);
907 bx.br(end);
908
909 bx.switch_to_block(from_overflow);
911
912 let aligned_overflow = round_pointer_up_to_alignment(bx, overflow_ptr, arg_align);
914
915 let overflow_value_addr = aligned_overflow;
916 let next_overflow = bx.inbounds_ptradd(aligned_overflow, bx.const_usize(arg_size));
918 bx.store(next_overflow, overflow_ptr_addr, ptr_align_abi);
919
920 bx.store(next_overflow, current_ptr_addr, ptr_align_abi);
923 bx.br(end);
924
925 bx.switch_to_block(end);
927 let value_addr =
928 bx.phi(bx.type_ptr(), &[reg_value_addr, overflow_value_addr], &[maybe_reg, from_overflow]);
929 bx.load(layout.llvm_type(bx), value_addr, layout.align)
930}
931
932fn emit_hexagon_va_arg_bare_metal<'ll, 'tcx>(
933 bx: &mut Builder<'_, 'll, 'tcx>,
934 list: OperandRef<'tcx, Value<'ll>>,
935 layout: TyAndLayout<'tcx>,
936) -> Value<'ll> {
937 let va_list_addr = list.immediate();
942 let ptr_align_abi = bx.tcx().data_layout.pointer_align();
943
944 let current_ptr = bx.load(bx.type_ptr(), va_list_addr, ptr_align_abi);
946
947 let ty_align = layout.align;
949 let aligned_ptr = if ty_align.bytes() > 4 {
950 if true {
if !ty_align.bytes().is_power_of_two() {
{
::core::panicking::panic_fmt(format_args!("Alignment is not power of 2!"));
}
};
};debug_assert!(ty_align.bytes().is_power_of_two(), "Alignment is not power of 2!");
952 round_pointer_up_to_alignment(bx, current_ptr, ty_align)
953 } else {
954 current_ptr
955 };
956
957 let type_size = layout.size.bytes();
959 let offset = type_size.next_multiple_of(4); let next_ptr = bx.inbounds_ptradd(aligned_ptr, bx.const_usize(offset));
963 bx.store(next_ptr, va_list_addr, ptr_align_abi);
964
965 bx.load(layout.llvm_type(bx), aligned_ptr, layout.align)
967}
968
969fn emit_xtensa_va_arg<'ll, 'tcx>(
970 bx: &mut Builder<'_, 'll, 'tcx>,
971 list: OperandRef<'tcx, Value<'ll>>,
972 layout: TyAndLayout<'tcx>,
973) -> Value<'ll> {
974 let va_list_addr = list.immediate();
991 let from_stack = bx.append_sibling_block("va_arg.from_stack");
993 let from_regsave = bx.append_sibling_block("va_arg.from_regsave");
994 let end = bx.append_sibling_block("va_arg.end");
995 let ptr_align_abi = bx.tcx().data_layout.pointer_align();
996
997 let va_reg_offset = 4;
999 let va_ndx_offset = va_reg_offset + 4;
1000 let offset_ptr = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(va_ndx_offset));
1001
1002 let offset = bx.load(bx.type_i32(), offset_ptr, bx.tcx().data_layout.i32_align);
1003 let offset = round_up_to_alignment(bx, offset, layout.align);
1004
1005 let slot_size = layout.size.align_to(Align::FOUR).bytes() as i32;
1006
1007 let offset_next = bx.add(offset, bx.const_i32(slot_size));
1009
1010 let regsave_size = bx.const_i32(24);
1013 let use_regsave = bx.icmp(IntPredicate::IntULE, offset_next, regsave_size);
1014 bx.cond_br(use_regsave, from_regsave, from_stack);
1015
1016 bx.switch_to_block(from_regsave);
1017 bx.store(offset_next, offset_ptr, ptr_align_abi);
1019
1020 let regsave_area_ptr = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(va_reg_offset));
1022 let regsave_area = bx.load(bx.type_ptr(), regsave_area_ptr, ptr_align_abi);
1023 let regsave_value_ptr = bx.inbounds_ptradd(regsave_area, offset);
1024 bx.br(end);
1025
1026 bx.switch_to_block(from_stack);
1027
1028 let stack_offset_start = bx.const_i32(32);
1034 let needs_correction = bx.icmp(IntPredicate::IntULE, offset, stack_offset_start);
1035 let offset_corrected = bx.select(needs_correction, stack_offset_start, offset);
1036
1037 let offset_next_corrected = bx.add(offset_corrected, bx.const_i32(slot_size));
1040 bx.store(offset_next_corrected, offset_ptr, ptr_align_abi);
1042
1043 let stack_area_ptr = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(0));
1045 let stack_area = bx.load(bx.type_ptr(), stack_area_ptr, ptr_align_abi);
1046 let stack_value_ptr = bx.inbounds_ptradd(stack_area, offset_corrected);
1047 bx.br(end);
1048
1049 bx.switch_to_block(end);
1050
1051 if !(bx.tcx().sess.target.endian == Endian::Little) {
::core::panicking::panic("assertion failed: bx.tcx().sess.target.endian == Endian::Little")
};assert!(bx.tcx().sess.target.endian == Endian::Little);
1061 let value_ptr =
1062 bx.phi(bx.type_ptr(), &[regsave_value_ptr, stack_value_ptr], &[from_regsave, from_stack]);
1063 bx.load(layout.llvm_type(bx), value_ptr, layout.align)
1064}
1065
1066pub(super) fn emit_va_arg<'ll, 'tcx>(
1071 bx: &mut Builder<'_, 'll, 'tcx>,
1072 addr: OperandRef<'tcx, Value<'ll>>,
1073 layout: TyAndLayout<'tcx>,
1074) -> Value<'ll> {
1075 if !!layout.is_zst() {
::core::panicking::panic("assertion failed: !layout.is_zst()")
};assert!(!layout.is_zst());
1078
1079 let target = &bx.cx.tcx.sess.target;
1080 let stability = target.supports_c_variadic_definitions();
1081
1082 match target.arch {
1083 Arch::X86 => {
1084 let allow_higher_align = if layout.ty == bx.tcx().types.f128 {
1090 AllowHigherAlign::Yes
1091 } else {
1092 AllowHigherAlign::No
1093 };
1094
1095 emit_ptr_va_arg(
1096 bx,
1097 addr,
1098 layout,
1099 PassMode::Direct,
1100 SlotSize::Bytes4,
1101 allow_higher_align,
1102 ForceRightAdjust::No,
1103 )
1104 }
1105 Arch::Arm64EC => emit_ptr_va_arg(
1106 bx,
1107 addr,
1108 layout,
1109 if layout.size.bytes() > 8 || !layout.size.bytes().is_power_of_two() {
1112 PassMode::Indirect
1113 } else {
1114 PassMode::Direct
1115 },
1116 SlotSize::Bytes8,
1117 AllowHigherAlign::No,
1118 ForceRightAdjust::No,
1119 ),
1120 Arch::AArch64 if target.is_like_windows || target.is_like_darwin => emit_ptr_va_arg(
1121 bx,
1122 addr,
1123 layout,
1124 PassMode::Direct,
1125 SlotSize::Bytes8,
1126 AllowHigherAlign::Yes,
1127 ForceRightAdjust::No,
1128 ),
1129 Arch::AArch64 => emit_aapcs_va_arg(bx, addr, layout),
1130 Arch::Arm => {
1131 if !(layout.size.bytes() <= 16) {
::core::panicking::panic("assertion failed: layout.size.bytes() <= 16")
};assert!(layout.size.bytes() <= 16);
1135
1136 emit_ptr_va_arg(
1137 bx,
1138 addr,
1139 layout,
1140 PassMode::Direct,
1141 SlotSize::Bytes4,
1142 AllowHigherAlign::Yes,
1143 ForceRightAdjust::No,
1144 )
1145 }
1146 Arch::S390x => emit_s390x_va_arg(bx, addr, layout),
1147 Arch::PowerPC => emit_powerpc_va_arg(bx, addr, layout),
1148 Arch::PowerPC64 => emit_ptr_va_arg(
1149 bx,
1150 addr,
1151 layout,
1152 PassMode::Direct,
1153 SlotSize::Bytes8,
1154 AllowHigherAlign::Yes,
1155 ForceRightAdjust::Yes,
1157 ),
1158 Arch::RiscV32 if target.llvm_abiname == LlvmAbi::Ilp32e => {
1159 {
match stability {
CVariadicStatus::Unstable { .. } => {}
ref left_val => {
::core::panicking::assert_matches_failed(left_val,
"CVariadicStatus::Unstable { .. }",
::core::option::Option::None);
}
}
};std::assert_matches!(stability, CVariadicStatus::Unstable { .. });
1160 ::rustc_span::macros::bug_impl(None,
format_args!("c-variadic calls with ilp32e use a custom ABI and are not currently implemented"),
Location::caller());bug!("c-variadic calls with ilp32e use a custom ABI and are not currently implemented");
1167 }
1168 Arch::RiscV32 | Arch::LoongArch32 => emit_ptr_va_arg(
1169 bx,
1170 addr,
1171 layout,
1172 if layout.size.bytes() > 2 * 4 { PassMode::Indirect } else { PassMode::Direct },
1173 SlotSize::Bytes4,
1174 AllowHigherAlign::Yes,
1175 ForceRightAdjust::No,
1176 ),
1177 Arch::RiscV64 | Arch::LoongArch64 => emit_ptr_va_arg(
1178 bx,
1179 addr,
1180 layout,
1181 if layout.size.bytes() > 2 * 8 { PassMode::Indirect } else { PassMode::Direct },
1182 SlotSize::Bytes8,
1183 AllowHigherAlign::Yes,
1184 ForceRightAdjust::No,
1185 ),
1186 Arch::AmdGpu => emit_ptr_va_arg(
1187 bx,
1188 addr,
1189 layout,
1190 PassMode::Direct,
1191 SlotSize::Bytes4,
1192 AllowHigherAlign::No,
1193 ForceRightAdjust::No,
1194 ),
1195 Arch::Nvptx64 => emit_ptr_va_arg(
1196 bx,
1197 addr,
1198 layout,
1199 PassMode::Direct,
1200 SlotSize::Bytes1,
1201 AllowHigherAlign::Yes,
1202 ForceRightAdjust::No,
1203 ),
1204 Arch::Wasm32 | Arch::Wasm64 => emit_ptr_va_arg(
1205 bx,
1206 addr,
1207 layout,
1208 if layout.is_aggregate() || layout.is_zst() || layout.is_1zst() {
1209 PassMode::Indirect
1210 } else {
1211 PassMode::Direct
1212 },
1213 SlotSize::Bytes4,
1214 AllowHigherAlign::Yes,
1215 ForceRightAdjust::No,
1216 ),
1217 Arch::CSky => emit_ptr_va_arg(
1218 bx,
1219 addr,
1220 layout,
1221 PassMode::Direct,
1222 SlotSize::Bytes4,
1223 AllowHigherAlign::Yes,
1224 ForceRightAdjust::No,
1225 ),
1226 Arch::X86_64 if target.is_like_windows => emit_ptr_va_arg(
1228 bx,
1229 addr,
1230 layout,
1231 if layout.size.bytes() > 8 || !layout.size.bytes().is_power_of_two() {
1232 PassMode::Indirect
1233 } else {
1234 PassMode::Direct
1235 },
1236 SlotSize::Bytes8,
1237 AllowHigherAlign::No,
1238 ForceRightAdjust::No,
1239 ),
1240 Arch::X86_64 => emit_x86_64_sysv64_va_arg(bx, addr, layout),
1242 Arch::Xtensa => emit_xtensa_va_arg(bx, addr, layout),
1243 Arch::Hexagon => match target.env {
1244 Env::Musl => emit_hexagon_va_arg_musl(bx, addr, layout),
1245 _ => emit_hexagon_va_arg_bare_metal(bx, addr, layout),
1246 },
1247 Arch::Sparc64 => emit_ptr_va_arg(
1248 bx,
1249 addr,
1250 layout,
1251 if layout.size.bytes() > 2 * 8 { PassMode::Indirect } else { PassMode::Direct },
1252 SlotSize::Bytes8,
1253 AllowHigherAlign::Yes,
1254 ForceRightAdjust::Yes,
1256 ),
1257 Arch::Sparc => {
1258 {
match stability {
CVariadicStatus::Unstable { .. } => {}
ref left_val => {
::core::panicking::assert_matches_failed(left_val,
"CVariadicStatus::Unstable { .. }",
::core::option::Option::None);
}
}
};std::assert_matches!(stability, CVariadicStatus::Unstable { .. });
1259
1260 let pass_mode = match layout.layout.backend_repr() {
1262 BackendRepr::Scalar(scalar) => match scalar.primitive() {
1263 Primitive::Float(Float::F128) => PassMode::Indirect,
1264 _ => PassMode::Direct,
1265 },
1266 _ => PassMode::Direct,
1267 };
1268
1269 emit_ptr_va_arg(
1270 bx,
1271 addr,
1272 layout,
1273 pass_mode,
1274 SlotSize::Bytes4,
1275 AllowHigherAlign::No,
1276 ForceRightAdjust::Yes,
1277 )
1278 }
1279 Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => emit_ptr_va_arg(
1280 bx,
1281 addr,
1282 layout,
1283 PassMode::Direct,
1284 match &target.llvm_abiname {
1285 LlvmAbi::N32 | LlvmAbi::N64 => SlotSize::Bytes8,
1286 LlvmAbi::O32 => SlotSize::Bytes4,
1287 other => ::rustc_span::macros::bug_impl(None,
format_args!("unexpected LLVM ABI {0}", other), Location::caller())bug!("unexpected LLVM ABI {other}"),
1288 },
1289 AllowHigherAlign::Yes,
1290 match bx.tcx().sess.target.endian {
1294 Endian::Big => ForceRightAdjust::Yes,
1295 Endian::Little => ForceRightAdjust::No,
1296 },
1297 ),
1298 Arch::Msp430 => emit_ptr_va_arg(
1299 bx,
1300 addr,
1301 layout,
1302 PassMode::Direct,
1303 SlotSize::Bytes1,
1304 AllowHigherAlign::Yes,
1305 ForceRightAdjust::No,
1306 ),
1307 Arch::Avr => emit_ptr_va_arg(
1308 bx,
1309 addr,
1310 layout,
1311 PassMode::Direct,
1312 SlotSize::Bytes1,
1313 AllowHigherAlign::No,
1314 ForceRightAdjust::No,
1315 ),
1316
1317 Arch::Bpf => ::rustc_span::macros::bug_impl(None,
format_args!("bpf does not support c-variadic functions"),
Location::caller())bug!("bpf does not support c-variadic functions"),
1318 Arch::SpirV => ::rustc_span::macros::bug_impl(None,
format_args!("spirv does not support c-variadic functions"),
Location::caller())bug!("spirv does not support c-variadic functions"),
1319
1320 Arch::M68k => {
1321 {
match stability {
CVariadicStatus::Unstable { .. } => {}
ref left_val => {
::core::panicking::assert_matches_failed(left_val,
"CVariadicStatus::Unstable { .. }",
::core::option::Option::None);
}
}
};std::assert_matches!(stability, CVariadicStatus::Unstable { .. });
1322
1323 bx.va_arg(addr.immediate(), layout.llvm_type(bx.cx))
1325 }
1326
1327 Arch::Other(ref arch) => {
1328 {
match stability {
CVariadicStatus::Unstable { .. } => {}
ref left_val => {
::core::panicking::assert_matches_failed(left_val,
"CVariadicStatus::Unstable { .. }",
::core::option::Option::None);
}
}
};std::assert_matches!(stability, CVariadicStatus::Unstable { .. });
1329
1330 ::rustc_span::macros::bug_impl(None,
format_args!("c-variadic functions are not currently implemented for custom target {0}",
arch), Location::caller())bug!("c-variadic functions are not currently implemented for custom target {arch}")
1333 }
1334 }
1335}