Skip to content

Commit b388d92

Browse files
committed
c-variadic: make va_arg match on Arch exhaustive
1 parent 09864b6 commit b388d92

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
@@ -1073,7 +1086,16 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
10731086
AllowHigherAlign::Yes,
10741087
ForceRightAdjust::No,
10751088
),
1076-
Arch::LoongArch32 => emit_ptr_va_arg(
1089+
Arch::RiscV32 if target.abi == Abi::Ilp32e => {
1090+
// FIXME: clang manually adjusts the alignment for this ABI. It notes:
1091+
//
1092+
// > To be compatible with GCC's behaviors, we force arguments with
1093+
// > 2×XLEN-bit alignment and size at most 2×XLEN bits like `long long`,
1094+
// > `unsigned long long` and `double` to have 4-byte alignment. This
1095+
// > behavior may be changed when RV32E/ILP32E is ratified.
1096+
bx.va_arg(addr.immediate(), bx.cx.layout_of(target_ty).llvm_type(bx.cx))
1097+
}
1098+
Arch::RiscV32 | Arch::LoongArch32 => emit_ptr_va_arg(
10771099
bx,
10781100
addr,
10791101
target_ty,
@@ -1082,7 +1104,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
10821104
AllowHigherAlign::Yes,
10831105
ForceRightAdjust::No,
10841106
),
1085-
Arch::LoongArch64 => emit_ptr_va_arg(
1107+
Arch::RiscV64 | Arch::LoongArch64 => emit_ptr_va_arg(
10861108
bx,
10871109
addr,
10881110
target_ty,
@@ -1153,9 +1175,30 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
11531175
Env::Musl => emit_hexagon_va_arg_musl(bx, addr, target_ty),
11541176
_ => emit_hexagon_va_arg_bare_metal(bx, addr, target_ty),
11551177
},
1156-
// For all other architecture/OS combinations fall back to using
1157-
// the LLVM va_arg instruction.
1158-
// https://llvm.org/docs/LangRef.html#va-arg-instruction
1159-
_ => bx.va_arg(addr.immediate(), bx.cx.layout_of(target_ty).llvm_type(bx.cx)),
1178+
Arch::Sparc64 => emit_ptr_va_arg(
1179+
bx,
1180+
addr,
1181+
target_ty,
1182+
if target_ty_size > 2 * 8 { PassMode::Indirect } else { PassMode::Direct },
1183+
SlotSize::Bytes8,
1184+
AllowHigherAlign::Yes,
1185+
ForceRightAdjust::No,
1186+
),
1187+
1188+
Arch::Bpf => bug!("bpf does not support c-variadic functions"),
1189+
Arch::SpirV => bug!("spirv does not support c-variadic functions"),
1190+
1191+
Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => {
1192+
// FIXME: port MipsTargetLowering::lowerVAARG.
1193+
bx.va_arg(addr.immediate(), bx.cx.layout_of(target_ty).llvm_type(bx.cx))
1194+
}
1195+
Arch::Sparc | Arch::Avr | Arch::M68k | Arch::Msp430 => {
1196+
// Clang uses the LLVM implementation for these architectures.
1197+
bx.va_arg(addr.immediate(), bx.cx.layout_of(target_ty).llvm_type(bx.cx))
1198+
}
1199+
Arch::Other(_) => {
1200+
// For custom targets, use the LLVM va_arg instruction as a fallback.
1201+
bx.va_arg(addr.immediate(), bx.cx.layout_of(target_ty).llvm_type(bx.cx))
1202+
}
11601203
}
11611204
}

0 commit comments

Comments
 (0)