1+ use rustc_abi:: { BackendRepr , Float , Integer , Primitive , RegKind } ;
12use rustc_attr_parsing:: InstructionSetAttr ;
23use rustc_middle:: mir:: mono:: { Linkage , MonoItem , MonoItemData , Visibility } ;
34use rustc_middle:: mir:: { Body , InlineAsmOperand } ;
4- use rustc_middle:: ty:: layout:: { HasTyCtxt , HasTypingEnv , LayoutOf } ;
5- use rustc_middle:: ty:: { Instance , TyCtxt } ;
5+ use rustc_middle:: ty:: layout:: { FnAbiOf , HasTyCtxt , HasTypingEnv , LayoutOf } ;
6+ use rustc_middle:: ty:: { Instance , Ty , TyCtxt } ;
67use rustc_middle:: { bug, ty} ;
78use rustc_span:: sym;
9+ use rustc_target:: callconv:: { ArgAbi , FnAbi , PassMode } ;
810
911use crate :: common;
1012use crate :: traits:: { AsmCodegenMethods , BuilderMethods , GlobalAsmOperandRef , MiscCodegenMethods } ;
@@ -32,7 +34,8 @@ pub(crate) fn codegen_naked_asm<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
3234
3335 let item_data = cx. codegen_unit ( ) . items ( ) . get ( & MonoItem :: Fn ( instance) ) . unwrap ( ) ;
3436 let name = cx. mangled_name ( instance) ;
35- let ( begin, end) = prefix_and_suffix ( cx. tcx ( ) , instance, & name, item_data) ;
37+ let fn_abi = cx. fn_abi_of_instance ( instance, ty:: List :: empty ( ) ) ;
38+ let ( begin, end) = prefix_and_suffix ( cx. tcx ( ) , instance, & name, item_data, fn_abi) ;
3639
3740 let mut template_vec = Vec :: new ( ) ;
3841 template_vec. push ( rustc_ast:: ast:: InlineAsmTemplatePiece :: String ( begin. into ( ) ) ) ;
@@ -103,6 +106,7 @@ enum AsmBinaryFormat {
103106 Elf ,
104107 Macho ,
105108 Coff ,
109+ Wasm ,
106110}
107111
108112impl AsmBinaryFormat {
@@ -111,6 +115,8 @@ impl AsmBinaryFormat {
111115 Self :: Coff
112116 } else if target. is_like_osx {
113117 Self :: Macho
118+ } else if target. is_like_wasm {
119+ Self :: Wasm
114120 } else {
115121 Self :: Elf
116122 }
@@ -122,6 +128,7 @@ fn prefix_and_suffix<'tcx>(
122128 instance : Instance < ' tcx > ,
123129 asm_name : & str ,
124130 item_data : & MonoItemData ,
131+ fn_abi : & FnAbi < ' tcx , Ty < ' tcx > > ,
125132) -> ( String , String ) {
126133 use std:: fmt:: Write ;
127134
@@ -169,7 +176,7 @@ fn prefix_and_suffix<'tcx>(
169176 }
170177 Linkage :: LinkOnceAny | Linkage :: LinkOnceODR | Linkage :: WeakAny | Linkage :: WeakODR => {
171178 match asm_binary_format {
172- AsmBinaryFormat :: Elf | AsmBinaryFormat :: Coff => {
179+ AsmBinaryFormat :: Elf | AsmBinaryFormat :: Coff | AsmBinaryFormat :: Wasm => {
173180 writeln ! ( w, ".weak {asm_name}" ) ?;
174181 }
175182 AsmBinaryFormat :: Macho => {
@@ -264,7 +271,132 @@ fn prefix_and_suffix<'tcx>(
264271 writeln ! ( end, "{}" , arch_suffix) . unwrap ( ) ;
265272 }
266273 }
274+ AsmBinaryFormat :: Wasm => {
275+ let section = link_section. unwrap_or ( format ! ( ".text.{asm_name}" ) ) ;
276+
277+ writeln ! ( begin, ".section {section},\" \" ,@" ) . unwrap ( ) ;
278+ writeln ! ( begin, ".balign {align}" ) . unwrap ( ) ;
279+ write_linkage ( & mut begin) . unwrap ( ) ;
280+ if let Visibility :: Hidden = item_data. visibility {
281+ writeln ! ( begin, ".hidden {asm_name}" ) . unwrap ( ) ;
282+ }
283+ writeln ! ( begin, ".type {asm_name}, @function" ) . unwrap ( ) ;
284+ if !arch_prefix. is_empty ( ) {
285+ writeln ! ( begin, "{}" , arch_prefix) . unwrap ( ) ;
286+ }
287+ writeln ! ( begin, "{asm_name}:" ) . unwrap ( ) ;
288+ writeln ! ( begin, ".functype {asm_name} {}" , wasm_functype( tcx, fn_abi) ) . unwrap ( ) ;
289+
290+ writeln ! ( end) . unwrap ( ) ;
291+ // .size is ignored for function symbols, so we can skip it
292+ writeln ! ( end, "end_function" ) . unwrap ( ) ;
293+ }
267294 }
268295
269296 ( begin, end)
270297}
298+
299+ /// The webassembly type signature for the given function.
300+ ///
301+ /// Used by the `.functype` directive on wasm targets.
302+ fn wasm_functype < ' tcx > ( tcx : TyCtxt < ' tcx > , fn_abi : & FnAbi < ' tcx , Ty < ' tcx > > ) -> String {
303+ let mut signature = String :: with_capacity ( 64 ) ;
304+
305+ let ptr_type = match tcx. data_layout . pointer_size . bits ( ) {
306+ 32 => "i32" ,
307+ 64 => "i64" ,
308+ other => bug ! ( "wasm pointer size cannot be {other} bits" ) ,
309+ } ;
310+
311+ let hidden_return =
312+ matches ! ( fn_abi. ret. mode, PassMode :: Indirect { .. } | PassMode :: Pair { .. } ) ;
313+
314+ signature. push ( '(' ) ;
315+
316+ if hidden_return {
317+ signature. push_str ( ptr_type) ;
318+ if !fn_abi. args . is_empty ( ) {
319+ signature. push_str ( ", " ) ;
320+ }
321+ }
322+
323+ let mut it = fn_abi. args . iter ( ) . peekable ( ) ;
324+ while let Some ( arg_abi) = it. next ( ) {
325+ wasm_type ( & mut signature, arg_abi, ptr_type) ;
326+ if it. peek ( ) . is_some ( ) {
327+ signature. push_str ( ", " ) ;
328+ }
329+ }
330+
331+ signature. push_str ( ") -> (" ) ;
332+
333+ if !hidden_return {
334+ wasm_type ( & mut signature, & fn_abi. ret , ptr_type) ;
335+ }
336+
337+ signature. push ( ')' ) ;
338+
339+ signature
340+ }
341+
342+ fn wasm_type < ' tcx > ( signature : & mut String , arg_abi : & ArgAbi < ' _ , Ty < ' tcx > > , ptr_type : & ' static str ) {
343+ match arg_abi. mode {
344+ PassMode :: Ignore => { /* do nothing */ }
345+ PassMode :: Direct ( _) => {
346+ let direct_type = match arg_abi. layout . backend_repr {
347+ BackendRepr :: Scalar ( scalar) => wasm_primitive ( scalar. primitive ( ) , ptr_type) ,
348+ BackendRepr :: Vector { .. } => "v128" ,
349+ other => unreachable ! ( "unexpected BackendRepr: {:?}" , other) ,
350+ } ;
351+
352+ signature. push_str ( direct_type) ;
353+ }
354+ PassMode :: Pair ( _, _) => match arg_abi. layout . backend_repr {
355+ BackendRepr :: ScalarPair ( a, b) => {
356+ signature. push_str ( wasm_primitive ( a. primitive ( ) , ptr_type) ) ;
357+ signature. push_str ( ", " ) ;
358+ signature. push_str ( wasm_primitive ( b. primitive ( ) , ptr_type) ) ;
359+ }
360+ other => unreachable ! ( "{other:?}" ) ,
361+ } ,
362+ PassMode :: Cast { pad_i32, ref cast } => {
363+ // For wasm, Cast is used for single-field primitive wrappers like `struct Wrapper(i64);`
364+ assert ! ( !pad_i32, "not currently used by wasm calling convention" ) ;
365+ assert ! ( cast. prefix[ 0 ] . is_none( ) , "no prefix" ) ;
366+ assert_eq ! ( cast. rest. total, arg_abi. layout. size, "single item" ) ;
367+
368+ let wrapped_wasm_type = match cast. rest . unit . kind {
369+ RegKind :: Integer => match cast. rest . unit . size . bytes ( ) {
370+ ..=4 => "i32" ,
371+ ..=8 => "i64" ,
372+ _ => ptr_type,
373+ } ,
374+ RegKind :: Float => match cast. rest . unit . size . bytes ( ) {
375+ ..=4 => "f32" ,
376+ ..=8 => "f64" ,
377+ _ => ptr_type,
378+ } ,
379+ RegKind :: Vector => "v128" ,
380+ } ;
381+
382+ signature. push_str ( wrapped_wasm_type) ;
383+ }
384+ PassMode :: Indirect { .. } => signature. push_str ( ptr_type) ,
385+ }
386+ }
387+
388+ fn wasm_primitive ( primitive : Primitive , ptr_type : & ' static str ) -> & ' static str {
389+ match primitive {
390+ Primitive :: Int ( integer, _) => match integer {
391+ Integer :: I8 | Integer :: I16 | Integer :: I32 => "i32" ,
392+ Integer :: I64 => "i64" ,
393+ Integer :: I128 => "i64, i64" ,
394+ } ,
395+ Primitive :: Float ( float) => match float {
396+ Float :: F16 | Float :: F32 => "f32" ,
397+ Float :: F64 => "f64" ,
398+ Float :: F128 => "i64, i64" ,
399+ } ,
400+ Primitive :: Pointer ( _) => ptr_type,
401+ }
402+ }
0 commit comments