@@ -340,15 +340,53 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
340340 } ;
341341
342342 for arg in args {
343+ // Note that the exact number of arguments pushed here is carefully synchronized with
344+ // code all over the place, both in the codegen_llvm and codegen_ssa crates. That's how
345+ // other code then knows which LLVM argument(s) correspond to the n-th Rust argument.
343346 let llarg_ty = match & arg. mode {
344347 PassMode :: Ignore => continue ,
345- PassMode :: Direct ( _) => arg. layout . immediate_llvm_type ( cx) ,
348+ PassMode :: Direct ( _) => {
349+ // ABI-compatible Rust types have the same `layout.abi` (up to validity ranges),
350+ // and for Scalar ABIs the LLVM type is fully determined by `layout.abi`,
351+ // guarnateeing that we generate ABI-compatible LLVM IR. Things get tricky for
352+ // aggregates...
353+ if matches ! ( arg. layout. abi, abi:: Abi :: Aggregate { .. } ) {
354+ // This is the most critical case for ABI compatibility, since
355+ // `immediate_llvm_type` will use `layout.fields` to turn this Rust type
356+ // into an LLVM type. ABI-compatible Rust types can have different `fields`,
357+ // so we need to be very sure that LLVM wil treat those different types in
358+ // an ABI-compatible way. Mostly we do this by disallowing
359+ // `PassMode::Direct` for aggregates, but we actually do use that mode on
360+ // wasm. wasm doesn't have aggregate types so we are fairly sure that LLVM
361+ // will treat `{ i32, i32, i32 }` and `{ { i32, i32, i32 } }` the same way
362+ // for ABI purposes.
363+ assert ! (
364+ matches!( & * cx. tcx. sess. target. arch, "wasm32" | "wasm64" ) ,
365+ "`PassMode::Direct` for aggregates only allowed on wasm targets\n Problematic type: {:#?}" ,
366+ arg. layout,
367+ ) ;
368+ }
369+ arg. layout . immediate_llvm_type ( cx)
370+ }
346371 PassMode :: Pair ( ..) => {
372+ // ABI-compatible Rust types have the same `layout.abi` (up to validity ranges),
373+ // so for ScalarPair we can easily be sure that we are generating ABI-compatible
374+ // LLVM IR.
375+ assert ! (
376+ matches!( arg. layout. abi, abi:: Abi :: ScalarPair ( ..) ) ,
377+ "PassMode::Pair for type {}" ,
378+ arg. layout. ty
379+ ) ;
347380 llargument_tys. push ( arg. layout . scalar_pair_element_llvm_type ( cx, 0 , true ) ) ;
348381 llargument_tys. push ( arg. layout . scalar_pair_element_llvm_type ( cx, 1 , true ) ) ;
349382 continue ;
350383 }
351384 PassMode :: Indirect { attrs : _, extra_attrs : Some ( _) , on_stack : _ } => {
385+ assert ! ( arg. layout. is_unsized( ) ) ;
386+ // Construct the type of a (wide) pointer to `ty`, and pass its two fields.
387+ // Any two ABI-compatible unsized types have the same metadata type and
388+ // moreover the same metadata value leads to the same dynamic size and
389+ // alignment, so this respects ABI compatibility.
352390 let ptr_ty = Ty :: new_mut_ptr ( cx. tcx , arg. layout . ty ) ;
353391 let ptr_layout = cx. layout_of ( ptr_ty) ;
354392 llargument_tys. push ( ptr_layout. scalar_pair_element_llvm_type ( cx, 0 , true ) ) ;
@@ -360,6 +398,8 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
360398 if * pad_i32 {
361399 llargument_tys. push ( Reg :: i32 ( ) . llvm_type ( cx) ) ;
362400 }
401+ // Compute the LLVM type we use for this function from the cast type.
402+ // We assume here that ABI-compatible Rust types have the same cast type.
363403 cast. llvm_type ( cx)
364404 }
365405 PassMode :: Indirect { attrs : _, extra_attrs : None , on_stack : _ } => cx. type_ptr ( ) ,
0 commit comments