Skip to content

Commit 1d7b6e2

Browse files
committed
c-variadic: make va_arg match on Arch exhaustive
1 parent b9778ed commit 1d7b6e2

File tree

1 file changed

+60
-17
lines changed

1 file changed

+60
-17
lines changed

compiler/rustc_codegen_llvm/src/va_arg.rs

Lines changed: 60 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,6 +1007,8 @@ fn emit_xtensa_va_arg<'ll, 'tcx>(
10071007

10081008
/// Determine the va_arg implementation to use. The LLVM va_arg instruction
10091009
/// is lacking in some instances, so we should only use it as a fallback.
1010+
///
1011+
/// <https://llvm.org/docs/LangRef.html#va-arg-instruction>
10101012
pub(super) fn emit_va_arg<'ll, 'tcx>(
10111013
bx: &mut Builder<'_, 'll, 'tcx>,
10121014
addr: OperandRef<'tcx, &'ll Value>,
@@ -1015,6 +1017,10 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
10151017
let layout = bx.cx.layout_of(target_ty);
10161018
let target_ty_size = layout.layout.size().bytes();
10171019

1020+
// Some ABIs have special behavior for zero-sized types. currently `VaArgSafe` is not
1021+
// implemented for any zero-sized types, so this assert should always hold.
1022+
assert!(!bx.layout_of(target_ty).is_zst());
1023+
10181024
let target = &bx.cx.tcx.sess.target;
10191025
match target.arch {
10201026
Arch::X86 => emit_ptr_va_arg(
@@ -1026,17 +1032,24 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
10261032
if target.is_like_windows { AllowHigherAlign::No } else { AllowHigherAlign::Yes },
10271033
ForceRightAdjust::No,
10281034
),
1029-
Arch::AArch64 | Arch::Arm64EC if target.is_like_windows || target.is_like_darwin => {
1030-
emit_ptr_va_arg(
1031-
bx,
1032-
addr,
1033-
target_ty,
1034-
PassMode::Direct,
1035-
SlotSize::Bytes8,
1036-
if target.is_like_windows { AllowHigherAlign::No } else { AllowHigherAlign::Yes },
1037-
ForceRightAdjust::No,
1038-
)
1039-
}
1035+
Arch::Arm64EC => emit_ptr_va_arg(
1036+
bx,
1037+
addr,
1038+
target_ty,
1039+
PassMode::Direct,
1040+
SlotSize::Bytes8,
1041+
if target.is_like_windows { AllowHigherAlign::No } else { AllowHigherAlign::Yes },
1042+
ForceRightAdjust::No,
1043+
),
1044+
Arch::AArch64 if target.is_like_windows || target.is_like_darwin => emit_ptr_va_arg(
1045+
bx,
1046+
addr,
1047+
target_ty,
1048+
PassMode::Direct,
1049+
SlotSize::Bytes8,
1050+
if target.is_like_windows { AllowHigherAlign::No } else { AllowHigherAlign::Yes },
1051+
ForceRightAdjust::No,
1052+
),
10401053
Arch::AArch64 => emit_aapcs_va_arg(bx, addr, target_ty),
10411054
Arch::Arm => {
10421055
// Types wider than 16 bytes are not currently supported. Clang has special logic for
@@ -1064,7 +1077,16 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
10641077
AllowHigherAlign::Yes,
10651078
ForceRightAdjust::Yes,
10661079
),
1067-
Arch::LoongArch32 => emit_ptr_va_arg(
1080+
Arch::RiscV32 if target.abi == Abi::Ilp32e => {
1081+
// FIXME: clang manually adjusts the alignment for this ABI. It notes:
1082+
//
1083+
// > To be compatible with GCC's behaviors, we force arguments with
1084+
// > 2×XLEN-bit alignment and size at most 2×XLEN bits like `long long`,
1085+
// > `unsigned long long` and `double` to have 4-byte alignment. This
1086+
// > behavior may be changed when RV32E/ILP32E is ratified.
1087+
bx.va_arg(addr.immediate(), bx.cx.layout_of(target_ty).llvm_type(bx.cx))
1088+
}
1089+
Arch::RiscV32 | Arch::LoongArch32 => emit_ptr_va_arg(
10681090
bx,
10691091
addr,
10701092
target_ty,
@@ -1073,7 +1095,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
10731095
AllowHigherAlign::Yes,
10741096
ForceRightAdjust::No,
10751097
),
1076-
Arch::LoongArch64 => emit_ptr_va_arg(
1098+
Arch::RiscV64 | Arch::LoongArch64 => emit_ptr_va_arg(
10771099
bx,
10781100
addr,
10791101
target_ty,
@@ -1144,9 +1166,30 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
11441166
Env::Musl => emit_hexagon_va_arg_musl(bx, addr, target_ty),
11451167
_ => emit_hexagon_va_arg_bare_metal(bx, addr, target_ty),
11461168
},
1147-
// For all other architecture/OS combinations fall back to using
1148-
// the LLVM va_arg instruction.
1149-
// https://llvm.org/docs/LangRef.html#va-arg-instruction
1150-
_ => bx.va_arg(addr.immediate(), bx.cx.layout_of(target_ty).llvm_type(bx.cx)),
1169+
Arch::Sparc64 => emit_ptr_va_arg(
1170+
bx,
1171+
addr,
1172+
target_ty,
1173+
if target_ty_size > 2 * 8 { PassMode::Indirect } else { PassMode::Direct },
1174+
SlotSize::Bytes8,
1175+
AllowHigherAlign::Yes,
1176+
ForceRightAdjust::No,
1177+
),
1178+
1179+
Arch::Bpf => bug!("bpf does not support c-variadic functions"),
1180+
Arch::SpirV => bug!("spirv does not support c-variadic functions"),
1181+
1182+
Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => {
1183+
// FIXME: port MipsTargetLowering::lowerVAARG.
1184+
bx.va_arg(addr.immediate(), bx.cx.layout_of(target_ty).llvm_type(bx.cx))
1185+
}
1186+
Arch::Sparc | Arch::Avr | Arch::M68k | Arch::Msp430 => {
1187+
// Clang uses the LLVM implementation for these architectures.
1188+
bx.va_arg(addr.immediate(), bx.cx.layout_of(target_ty).llvm_type(bx.cx))
1189+
}
1190+
Arch::Other(_) => {
1191+
// For custom targets, use the LLVM va_arg instruction as a fallback.
1192+
bx.va_arg(addr.immediate(), bx.cx.layout_of(target_ty).llvm_type(bx.cx))
1193+
}
11511194
}
11521195
}

0 commit comments

Comments
 (0)