Skip to content

Commit 82b5849

Browse files
Rollup merge of #150831 - folkertdev:more-va-arg-2, r=workingjubilee
c-variadic: make `va_arg` match on `Arch` exhaustive tracking issue: #44930 Continuing from #150094, the more annoying cases remain. These are mostly very niche targets without Clang `va_arg` implementations, and so it might just be easier to defer to LLVM instead of us getting the ABI subtly wrong. That does mean we cannot stabilize c-variadic on those targets I think. Alternatively we could ask target maintainers to contribute an implementation. I'd honestly prefer they make that change to LVM though (likely by just using `CodeGen::emitVoidPtrVAArg`) that we can mirror. r? @workingjubilee
2 parents 0a13b43 + d2b5ba2 commit 82b5849

1 file changed

Lines changed: 64 additions & 24 deletions

File tree

compiler/rustc_codegen_llvm/src/va_arg.rs

Lines changed: 64 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ fn emit_ptr_va_arg<'ll, 'tcx>(
131131
);
132132
if indirect {
133133
let tmp_ret = bx.load(llty, addr, addr_align);
134-
bx.load(bx.cx.layout_of(target_ty).llvm_type(bx.cx), tmp_ret, align.abi)
134+
bx.load(layout.llvm_type(bx.cx), tmp_ret, align.abi)
135135
} else {
136136
bx.load(llty, addr, addr_align)
137137
}
@@ -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+
bug!("c-variadic calls with ilp32e use a custom ABI and are not currently implemented");
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,
@@ -1140,16 +1162,34 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
11401162
// This includes `target.is_like_darwin`, which on x86_64 targets is like sysv64.
11411163
Arch::X86_64 => emit_x86_64_sysv64_va_arg(bx, addr, target_ty),
11421164
Arch::Xtensa => emit_xtensa_va_arg(bx, addr, target_ty),
1143-
Arch::Hexagon => {
1144-
if target.env == Env::Musl {
1145-
emit_hexagon_va_arg_musl(bx, addr, target_ty)
1146-
} else {
1147-
emit_hexagon_va_arg_bare_metal(bx, addr, target_ty)
1148-
}
1165+
Arch::Hexagon => match target.env {
1166+
Env::Musl => emit_hexagon_va_arg_musl(bx, addr, target_ty),
1167+
_ => emit_hexagon_va_arg_bare_metal(bx, addr, target_ty),
1168+
},
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))
11491193
}
1150-
// For all other architecture/OS combinations fall back to using
1151-
// the LLVM va_arg instruction.
1152-
// https://llvm.org/docs/LangRef.html#va-arg-instruction
1153-
_ => bx.va_arg(addr.immediate(), bx.cx.layout_of(target_ty).llvm_type(bx.cx)),
11541194
}
11551195
}

0 commit comments

Comments
 (0)