1+ use  rustc_abi:: { BackendRepr ,  Float ,  Integer ,  Primitive ,  RegKind } ; 
12use  rustc_attr_parsing:: InstructionSetAttr ; 
3+ use  rustc_hir:: def_id:: DefId ; 
24use  rustc_middle:: mir:: mono:: { Linkage ,  MonoItem ,  MonoItemData ,  Visibility } ; 
35use  rustc_middle:: mir:: { Body ,  InlineAsmOperand } ; 
4- use  rustc_middle:: ty:: layout:: { HasTyCtxt ,  HasTypingEnv ,  LayoutOf } ; 
5- use  rustc_middle:: ty:: { Instance ,  TyCtxt } ; 
6- use  rustc_middle:: { bug,  ty} ; 
6+ use  rustc_middle:: ty:: layout:: { FnAbiOf ,   HasTyCtxt ,  HasTypingEnv ,  LayoutOf } ; 
7+ use  rustc_middle:: ty:: { Instance ,  Ty ,   TyCtxt } ; 
8+ use  rustc_middle:: { bug,  span_bug ,   ty} ; 
79use  rustc_span:: sym; 
10+ use  rustc_target:: callconv:: { ArgAbi ,  FnAbi ,  PassMode } ; 
11+ use  rustc_target:: spec:: WasmCAbi ; 
812
913use  crate :: common; 
1014use  crate :: traits:: { AsmCodegenMethods ,  BuilderMethods ,  GlobalAsmOperandRef ,  MiscCodegenMethods } ; 
@@ -32,7 +36,8 @@ pub(crate) fn codegen_naked_asm<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
3236
3337    let  item_data = cx. codegen_unit ( ) . items ( ) . get ( & MonoItem :: Fn ( instance) ) . unwrap ( ) ; 
3438    let  name = cx. mangled_name ( instance) ; 
35-     let  ( begin,  end)  = prefix_and_suffix ( cx. tcx ( ) ,  instance,  & name,  item_data) ; 
39+     let  fn_abi = cx. fn_abi_of_instance ( instance,  ty:: List :: empty ( ) ) ; 
40+     let  ( begin,  end)  = prefix_and_suffix ( cx. tcx ( ) ,  instance,  & name,  item_data,  fn_abi) ; 
3641
3742    let  mut  template_vec = Vec :: new ( ) ; 
3843    template_vec. push ( rustc_ast:: ast:: InlineAsmTemplatePiece :: String ( begin. into ( ) ) ) ; 
@@ -103,6 +108,7 @@ enum AsmBinaryFormat {
103108    Elf , 
104109    Macho , 
105110    Coff , 
111+     Wasm , 
106112} 
107113
108114impl  AsmBinaryFormat  { 
@@ -111,6 +117,8 @@ impl AsmBinaryFormat {
111117            Self :: Coff 
112118        }  else  if  target. is_like_osx  { 
113119            Self :: Macho 
120+         }  else  if  target. is_like_wasm  { 
121+             Self :: Wasm 
114122        }  else  { 
115123            Self :: Elf 
116124        } 
@@ -122,6 +130,7 @@ fn prefix_and_suffix<'tcx>(
122130    instance :  Instance < ' tcx > , 
123131    asm_name :  & str , 
124132    item_data :  & MonoItemData , 
133+     fn_abi :  & FnAbi < ' tcx ,  Ty < ' tcx > > , 
125134)  -> ( String ,  String )  { 
126135    use  std:: fmt:: Write ; 
127136
@@ -169,7 +178,7 @@ fn prefix_and_suffix<'tcx>(
169178            } 
170179            Linkage :: LinkOnceAny  | Linkage :: LinkOnceODR  | Linkage :: WeakAny  | Linkage :: WeakODR  => { 
171180                match  asm_binary_format { 
172-                     AsmBinaryFormat :: Elf  | AsmBinaryFormat :: Coff  => { 
181+                     AsmBinaryFormat :: Elf  | AsmBinaryFormat :: Coff  |  AsmBinaryFormat :: Wasm   => { 
173182                        writeln ! ( w,  ".weak {asm_name}" ) ?; 
174183                    } 
175184                    AsmBinaryFormat :: Macho  => { 
@@ -264,7 +273,161 @@ fn prefix_and_suffix<'tcx>(
264273                writeln ! ( end,  "{}" ,  arch_suffix) . unwrap ( ) ; 
265274            } 
266275        } 
276+         AsmBinaryFormat :: Wasm  => { 
277+             let  section = link_section. unwrap_or ( format ! ( ".text.{asm_name}" ) ) ; 
278+ 
279+             writeln ! ( begin,  ".section {section},\" \" ,@" ) . unwrap ( ) ; 
280+             // wasm functions cannot be aligned, so skip 
281+             write_linkage ( & mut  begin) . unwrap ( ) ; 
282+             if  let  Visibility :: Hidden  = item_data. visibility  { 
283+                 writeln ! ( begin,  ".hidden {asm_name}" ) . unwrap ( ) ; 
284+             } 
285+             writeln ! ( begin,  ".type {asm_name}, @function" ) . unwrap ( ) ; 
286+             if  !arch_prefix. is_empty ( )  { 
287+                 writeln ! ( begin,  "{}" ,  arch_prefix) . unwrap ( ) ; 
288+             } 
289+             writeln ! ( begin,  "{asm_name}:" ) . unwrap ( ) ; 
290+             writeln ! ( 
291+                 begin, 
292+                 ".functype {asm_name} {}" , 
293+                 wasm_functype( tcx,  fn_abi,  instance. def_id( ) ) 
294+             ) 
295+             . unwrap ( ) ; 
296+ 
297+             writeln ! ( end) . unwrap ( ) ; 
298+             // .size is ignored for function symbols, so we can skip it 
299+             writeln ! ( end,  "end_function" ) . unwrap ( ) ; 
300+         } 
267301    } 
268302
269303    ( begin,  end) 
270304} 
305+ 
306+ /// The webassembly type signature for the given function. 
307+ /// 
308+ /// Used by the `.functype` directive on wasm targets. 
309+ fn  wasm_functype < ' tcx > ( tcx :  TyCtxt < ' tcx > ,  fn_abi :  & FnAbi < ' tcx ,  Ty < ' tcx > > ,  def_id :  DefId )  -> String  { 
310+     let  mut  signature = String :: with_capacity ( 64 ) ; 
311+ 
312+     let  ptr_type = match  tcx. data_layout . pointer_size . bits ( )  { 
313+         32  => "i32" , 
314+         64  => "i64" , 
315+         other => bug ! ( "wasm pointer size cannot be {other} bits" ) , 
316+     } ; 
317+ 
318+     // FIXME: remove this once the wasm32-unknown-unknown ABI is fixed 
319+     // please also add `wasm32-unknown-unknown` back in `tests/assembly/wasm32-naked-fn.rs` 
320+     // basically the commit introducing this comment should be reverted 
321+     if  let  PassMode :: Pair  {  .. }  = fn_abi. ret . mode  { 
322+         let  _ = WasmCAbi :: Legacy ; 
323+         span_bug ! ( 
324+             tcx. def_span( def_id) , 
325+             "cannot return a pair (the wasm32-unknown-unknown ABI is broken, see https://github.com/rust-lang/rust/issues/115666" 
326+         ) ; 
327+     } 
328+ 
329+     let  hidden_return = matches ! ( fn_abi. ret. mode,  PassMode :: Indirect  {  .. } ) ; 
330+ 
331+     signature. push ( '(' ) ; 
332+ 
333+     if  hidden_return { 
334+         signature. push_str ( ptr_type) ; 
335+         if  !fn_abi. args . is_empty ( )  { 
336+             signature. push_str ( ", " ) ; 
337+         } 
338+     } 
339+ 
340+     let  mut  it = fn_abi. args . iter ( ) . peekable ( ) ; 
341+     while  let  Some ( arg_abi)  = it. next ( )  { 
342+         wasm_type ( tcx,  & mut  signature,  arg_abi,  ptr_type,  def_id) ; 
343+         if  it. peek ( ) . is_some ( )  { 
344+             signature. push_str ( ", " ) ; 
345+         } 
346+     } 
347+ 
348+     signature. push_str ( ") -> (" ) ; 
349+ 
350+     if  !hidden_return { 
351+         wasm_type ( tcx,  & mut  signature,  & fn_abi. ret ,  ptr_type,  def_id) ; 
352+     } 
353+ 
354+     signature. push ( ')' ) ; 
355+ 
356+     signature
357+ } 
358+ 
359+ fn  wasm_type < ' tcx > ( 
360+     tcx :  TyCtxt < ' tcx > , 
361+     signature :  & mut  String , 
362+     arg_abi :  & ArgAbi < ' _ ,  Ty < ' tcx > > , 
363+     ptr_type :  & ' static  str , 
364+     def_id :  DefId , 
365+ )  { 
366+     match  arg_abi. mode  { 
367+         PassMode :: Ignore  => {  /* do nothing */  } 
368+         PassMode :: Direct ( _)  => { 
369+             let  direct_type = match  arg_abi. layout . backend_repr  { 
370+                 BackendRepr :: Scalar ( scalar)  => wasm_primitive ( scalar. primitive ( ) ,  ptr_type) , 
371+                 BackendRepr :: Vector  {  .. }  => "v128" , 
372+                 BackendRepr :: Memory  {  .. }  => { 
373+                     // FIXME: remove this branch once the wasm32-unknown-unknown ABI is fixed 
374+                     let  _ = WasmCAbi :: Legacy ; 
375+                     span_bug ! ( 
376+                         tcx. def_span( def_id) , 
377+                         "cannot use memory args (the wasm32-unknown-unknown ABI is broken, see https://github.com/rust-lang/rust/issues/115666" 
378+                     ) ; 
379+                 } 
380+                 other => unreachable ! ( "unexpected BackendRepr: {:?}" ,  other) , 
381+             } ; 
382+ 
383+             signature. push_str ( direct_type) ; 
384+         } 
385+         PassMode :: Pair ( _,  _)  => match  arg_abi. layout . backend_repr  { 
386+             BackendRepr :: ScalarPair ( a,  b)  => { 
387+                 signature. push_str ( wasm_primitive ( a. primitive ( ) ,  ptr_type) ) ; 
388+                 signature. push_str ( ", " ) ; 
389+                 signature. push_str ( wasm_primitive ( b. primitive ( ) ,  ptr_type) ) ; 
390+             } 
391+             other => unreachable ! ( "{other:?}" ) , 
392+         } , 
393+         PassMode :: Cast  {  pad_i32,  ref  cast }  => { 
394+             // For wasm, Cast is used for single-field primitive wrappers like `struct Wrapper(i64);` 
395+             assert ! ( !pad_i32,  "not currently used by wasm calling convention" ) ; 
396+             assert ! ( cast. prefix[ 0 ] . is_none( ) ,  "no prefix" ) ; 
397+             assert_eq ! ( cast. rest. total,  arg_abi. layout. size,  "single item" ) ; 
398+ 
399+             let  wrapped_wasm_type = match  cast. rest . unit . kind  { 
400+                 RegKind :: Integer  => match  cast. rest . unit . size . bytes ( )  { 
401+                     ..=4  => "i32" , 
402+                     ..=8  => "i64" , 
403+                     _ => ptr_type, 
404+                 } , 
405+                 RegKind :: Float  => match  cast. rest . unit . size . bytes ( )  { 
406+                     ..=4  => "f32" , 
407+                     ..=8  => "f64" , 
408+                     _ => ptr_type, 
409+                 } , 
410+                 RegKind :: Vector  => "v128" , 
411+             } ; 
412+ 
413+             signature. push_str ( wrapped_wasm_type) ; 
414+         } 
415+         PassMode :: Indirect  {  .. }  => signature. push_str ( ptr_type) , 
416+     } 
417+ } 
418+ 
419+ fn  wasm_primitive ( primitive :  Primitive ,  ptr_type :  & ' static  str )  -> & ' static  str  { 
420+     match  primitive { 
421+         Primitive :: Int ( integer,  _)  => match  integer { 
422+             Integer :: I8  | Integer :: I16  | Integer :: I32  => "i32" , 
423+             Integer :: I64  => "i64" , 
424+             Integer :: I128  => "i64, i64" , 
425+         } , 
426+         Primitive :: Float ( float)  => match  float { 
427+             Float :: F16  | Float :: F32  => "f32" , 
428+             Float :: F64  => "f64" , 
429+             Float :: F128  => "i64, i64" , 
430+         } , 
431+         Primitive :: Pointer ( _)  => ptr_type, 
432+     } 
433+ } 
0 commit comments