@@ -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>
10101012pub ( 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