@@ -18,9 +18,11 @@ use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece};
1818use  rustc_codegen_ssa:: mir:: operand:: OperandValue ; 
1919use  rustc_codegen_ssa:: mir:: place:: PlaceRef ; 
2020use  rustc_codegen_ssa:: traits:: { 
21-     AsmBuilderMethods ,  BackendTypes ,  BuilderMethods ,  InlineAsmOperandRef , 
21+     AsmBuilderMethods ,  AsmCodegenMethods ,  BackendTypes ,  BuilderMethods ,  GlobalAsmOperandRef , 
22+     InlineAsmOperandRef , 
2223} ; 
2324use  rustc_data_structures:: fx:: { FxHashMap ,  FxHashSet } ; 
25+ use  rustc_errors:: { Diag ,  DiagMessage } ; 
2426use  rustc_middle:: { bug,  ty:: Instance } ; 
2527use  rustc_span:: { DUMMY_SP ,  Span } ; 
2628use  rustc_target:: asm:: { InlineAsmRegClass ,  InlineAsmRegOrRegClass ,  SpirVInlineAsmRegClass } ; 
@@ -68,6 +70,153 @@ fn inline_asm_operand_ref_clone<'tcx, B: BackendTypes + ?Sized>(
6870    } 
6971} 
7072
73+ impl < ' tcx >  AsmCodegenMethods < ' tcx >  for  CodegenCx < ' tcx >  { 
74+     fn  codegen_global_asm ( 
75+         & mut  self , 
76+         template :  & [ InlineAsmTemplatePiece ] , 
77+         operands :  & [ GlobalAsmOperandRef < ' tcx > ] , 
78+         options :  InlineAsmOptions , 
79+         line_spans :  & [ Span ] , 
80+     )  { 
81+         const  SUPPORTED_OPTIONS :  InlineAsmOptions  = InlineAsmOptions :: empty ( ) ; 
82+         let  unsupported_options = options &  !SUPPORTED_OPTIONS ; 
83+         if  !unsupported_options. is_empty ( )  { 
84+             self . tcx . dcx ( ) . span_err ( 
85+                 line_spans. first ( ) . copied ( ) . unwrap_or_default ( ) , 
86+                 format ! ( "global_asm! flags not supported: {unsupported_options:?}" ) , 
87+             ) ; 
88+         } 
89+ 
90+         // vec of lines, and each line is vec of tokens 
91+         let  mut  tokens = vec ! [ vec![ ] ] ; 
92+         for  piece in  template { 
93+             match  piece { 
94+                 InlineAsmTemplatePiece :: String ( asm)  => { 
95+                     // We cannot use str::lines() here because we don't want the behavior of "the 
96+                     // last newline is optional", we want an empty string for the last line if 
97+                     // there is no newline terminator. 
98+                     // Lambda copied from std LinesAnyMap 
99+                     let  lines = asm. split ( '\n' ) . map ( |line| { 
100+                         let  l = line. len ( ) ; 
101+                         if  l > 0  && line. as_bytes ( ) [ l - 1 ]  == b'\r'  { 
102+                             & line[ 0 ..l - 1 ] 
103+                         }  else  { 
104+                             line
105+                         } 
106+                     } ) ; 
107+                     for  ( index,  line)  in  lines. enumerate ( )  { 
108+                         if  index != 0  { 
109+                             // There was a newline, add a new line. 
110+                             tokens. push ( vec ! [ ] ) ; 
111+                         } 
112+                         let  mut  chars = line. chars ( ) ; 
113+ 
114+                         let  span = line_spans
115+                             . get ( tokens. len ( )  - 1 ) 
116+                             . copied ( ) 
117+                             . unwrap_or_default ( ) ; 
118+                         while  let  Some ( token)  = InlineAsmCx :: Global ( self ,  span) . lex_word ( & mut  chars) 
119+                         { 
120+                             tokens. last_mut ( ) . unwrap ( ) . push ( token) ; 
121+                         } 
122+                     } 
123+                 } 
124+                 & InlineAsmTemplatePiece :: Placeholder  { 
125+                     operand_idx, 
126+                     modifier, 
127+                     span, 
128+                 }  => { 
129+                     if  let  Some ( modifier)  = modifier { 
130+                         self . tcx 
131+                             . dcx ( ) 
132+                             . span_err ( span,  format ! ( "asm modifiers are not supported: {modifier}" ) ) ; 
133+                     } 
134+                     let  span = line_spans
135+                         . get ( tokens. len ( )  - 1 ) 
136+                         . copied ( ) 
137+                         . unwrap_or_default ( ) ; 
138+                     let  line = tokens. last_mut ( ) . unwrap ( ) ; 
139+                     let  typeof_kind = line. last ( ) . and_then ( |prev| match  prev { 
140+                         Token :: Word ( "typeof" )  => Some ( TypeofKind :: Plain ) , 
141+                         Token :: Word ( "typeof*" )  => Some ( TypeofKind :: Dereference ) , 
142+                         _ => None , 
143+                     } ) ; 
144+                     let  operand = & operands[ operand_idx] ; 
145+                     match  typeof_kind { 
146+                         Some ( _)  => match  operand { 
147+                             GlobalAsmOperandRef :: Const  {  string :  _ }  => { 
148+                                 self . tcx 
149+                                     . dcx ( ) 
150+                                     . span_err ( span,  "cannot take the type of a const asm argument" ) ; 
151+                             } 
152+                             GlobalAsmOperandRef :: SymFn  {  instance :  _ }  => { 
153+                                 self . tcx . dcx ( ) . span_err ( 
154+                                     span, 
155+                                     "cannot take the type of a function asm argument" , 
156+                                 ) ; 
157+                             } 
158+                             GlobalAsmOperandRef :: SymStatic  {  def_id :  _ }  => { 
159+                                 self . tcx . dcx ( ) . span_err ( 
160+                                     span, 
161+                                     "cannot take the type of a static variable asm argument" , 
162+                                 ) ; 
163+                             } 
164+                         } , 
165+                         None  => match  operand { 
166+                             GlobalAsmOperandRef :: Const  {  string }  => line. push ( Token :: Word ( string) ) , 
167+                             GlobalAsmOperandRef :: SymFn  {  instance :  _ }  => { 
168+                                 self . tcx 
169+                                     . dcx ( ) 
170+                                     . span_err ( span,  "function asm argument not supported yet" ) ; 
171+                             } 
172+                             GlobalAsmOperandRef :: SymStatic  {  def_id :  _ }  => { 
173+                                 self . tcx . dcx ( ) . span_err ( 
174+                                     span, 
175+                                     "static variable asm argument not supported yet" , 
176+                                 ) ; 
177+                             } 
178+                         } , 
179+                     } 
180+                 } 
181+             } 
182+         } 
183+ 
184+         let  mut  id_map = FxHashMap :: default ( ) ; 
185+         let  mut  defined_ids = FxHashSet :: default ( ) ; 
186+         let  mut  id_to_type_map = FxHashMap :: default ( ) ; 
187+ 
188+         let  mut  asm_block = AsmBlock :: Open ; 
189+         for  ( line_idx,  line)  in  tokens. into_iter ( ) . enumerate ( )  { 
190+             let  span = line_spans. get ( line_idx) . copied ( ) . unwrap_or_default ( ) ; 
191+             InlineAsmCx :: Global ( self ,  span) . codegen_asm ( 
192+                 & mut  id_map, 
193+                 & mut  defined_ids, 
194+                 & mut  id_to_type_map, 
195+                 & mut  asm_block, 
196+                 line. into_iter ( ) , 
197+             ) ; 
198+         } 
199+ 
200+         for  ( id,  num)  in  id_map { 
201+             if  !defined_ids. contains ( & num)  { 
202+                 self . tcx . dcx ( ) . span_err ( 
203+                     line_spans. first ( ) . copied ( ) . unwrap_or_default ( ) , 
204+                     format ! ( "%{id} is used but not defined" ) , 
205+                 ) ; 
206+             } 
207+         } 
208+     } 
209+ 
210+     // FIXME(eddyb) should this method be implemented as just symbol mangling, 
211+     // or renamed upstream into something much more specific? 
212+     fn  mangled_name ( & self ,  instance :  Instance < ' tcx > )  -> String  { 
213+         self . tcx . dcx ( ) . span_bug ( 
214+             self . tcx . def_span ( instance. def_id ( ) ) , 
215+             "[Rust-GPU] `#[naked] fn` not yet supported" , 
216+         ) 
217+     } 
218+ } 
219+ 
71220impl < ' a ,  ' tcx >  AsmBuilderMethods < ' tcx >  for  Builder < ' a ,  ' tcx >  { 
72221    /* Example asm and the template it compiles to: 
73222    asm!( 
@@ -103,7 +252,7 @@ impl<'a, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'tcx> {
103252        const  SUPPORTED_OPTIONS :  InlineAsmOptions  = InlineAsmOptions :: NORETURN ; 
104253        let  unsupported_options = options &  !SUPPORTED_OPTIONS ; 
105254        if  !unsupported_options. is_empty ( )  { 
106-             self . err ( format ! ( "asm flags not supported: {unsupported_options:?}" ) ) ; 
255+             self . err ( format ! ( "asm!  flags not supported: {unsupported_options:?}" ) ) ; 
107256        } 
108257
109258        // HACK(eddyb) get more accurate pointers types, for pointer operands, 
@@ -165,7 +314,7 @@ impl<'a, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'tcx> {
165314                            tokens. push ( vec ! [ ] ) ; 
166315                        } 
167316                        let  mut  chars = line. chars ( ) ; 
168-                         while  let  Some ( token)  = self . lex_word ( & mut  chars)  { 
317+                         while  let  Some ( token)  = InlineAsmCx :: Local ( self ) . lex_word ( & mut  chars)  { 
169318                            tokens. last_mut ( ) . unwrap ( ) . push ( token) ; 
170319                        } 
171320                    } 
@@ -222,7 +371,7 @@ impl<'a, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'tcx> {
222371                // which is an unfortunate interaction, but perhaps avoidable? 
223372                AsmBlock :: End ( _)  => { } 
224373            } 
225-             self . codegen_asm ( 
374+             InlineAsmCx :: Local ( self ) . codegen_asm ( 
226375                & mut  id_map, 
227376                & mut  defined_ids, 
228377                & mut  id_to_type_map, 
@@ -287,7 +436,47 @@ enum AsmBlock {
287436    End ( Op ) , 
288437} 
289438
290- impl < ' cx ,  ' tcx >  Builder < ' cx ,  ' tcx >  { 
439+ enum  InlineAsmCx < ' a ,  ' cx ,  ' tcx >  { 
440+     Global ( & ' cx  CodegenCx < ' tcx > ,  Span ) , 
441+     Local ( & ' a  mut  Builder < ' cx ,  ' tcx > ) , 
442+ } 
443+ 
444+ impl < ' cx ,  ' tcx >  std:: ops:: Deref  for  InlineAsmCx < ' _ ,  ' cx ,  ' tcx >  { 
445+     type  Target  = & ' cx  CodegenCx < ' tcx > ; 
446+     fn  deref ( & self )  -> & Self :: Target  { 
447+         match  self  { 
448+             Self :: Global ( cx,  _)  | Self :: Local ( Builder  {  cx,  .. } )  => cx, 
449+         } 
450+     } 
451+ } 
452+ 
453+ impl  InlineAsmCx < ' _ ,  ' _ ,  ' _ >  { 
454+     fn  span ( & self )  -> Span  { 
455+         match  self  { 
456+             & Self :: Global ( _,  span)  => span, 
457+             Self :: Local ( bx)  => bx. span ( ) , 
458+         } 
459+     } 
460+ 
461+     #[ track_caller]  
462+     fn  struct_err ( & self ,  msg :  impl  Into < DiagMessage > )  -> Diag < ' _ >  { 
463+         self . tcx . dcx ( ) . struct_span_err ( self . span ( ) ,  msg) 
464+     } 
465+ 
466+     #[ track_caller]  
467+     fn  err ( & self ,  msg :  impl  Into < DiagMessage > )  { 
468+         self . tcx . dcx ( ) . span_err ( self . span ( ) ,  msg) ; 
469+     } 
470+ 
471+     fn  emit ( & mut  self )  -> std:: cell:: RefMut < ' _ ,  rspirv:: dr:: Builder >  { 
472+         match  self  { 
473+             Self :: Global ( cx,  _)  => cx. emit_global ( ) , 
474+             Self :: Local ( bx)  => bx. emit ( ) , 
475+         } 
476+     } 
477+ } 
478+ 
479+ impl < ' cx ,  ' tcx >  InlineAsmCx < ' _ ,  ' cx ,  ' tcx >  { 
291480    fn  lex_word < ' a > ( & self ,  line :  & mut  std:: str:: Chars < ' a > )  -> Option < Token < ' a ,  ' cx ,  ' tcx > >  { 
292481        loop  { 
293482            let  start = line. as_str ( ) ; 
@@ -547,7 +736,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> {
547736        } ; 
548737        let  inst_class = inst_name
549738            . strip_prefix ( "Op" ) 
550-             . and_then ( |n| self . cx . instruction_table . table . get ( n) ) ; 
739+             . and_then ( |n| self . instruction_table . table . get ( n) ) ; 
551740        let  inst_class = if  let  Some ( inst)  = inst_class { 
552741            inst
553742        }  else  { 
@@ -571,13 +760,12 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> {
571760        } 
572761        self . insert_inst ( id_map,  defined_ids,  asm_block,  instruction) ; 
573762        if  let  Some ( OutRegister :: Place ( place) )  = out_register { 
763+             let  place = match  self  { 
764+                 Self :: Global ( ..)  => unreachable ! ( ) , 
765+                 Self :: Local ( bx)  => place. val . llval . def ( bx) , 
766+             } ; 
574767            self . emit ( ) 
575-                 . store ( 
576-                     place. val . llval . def ( self ) , 
577-                     result_id. unwrap ( ) , 
578-                     None , 
579-                     std:: iter:: empty ( ) , 
580-                 ) 
768+                 . store ( place,  result_id. unwrap ( ) ,  None ,  std:: iter:: empty ( ) ) 
581769                . unwrap ( ) ; 
582770        } 
583771    } 
@@ -1093,7 +1281,10 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> {
10931281            Token :: Placeholder ( hole,  span)  => match  hole { 
10941282                InlineAsmOperandRef :: In  {  reg,  value }  => { 
10951283                    self . check_reg ( span,  reg) ; 
1096-                     Some ( value. immediate ( ) . def ( self ) ) 
1284+                     match  self  { 
1285+                         Self :: Global ( ..)  => unreachable ! ( ) , 
1286+                         Self :: Local ( bx)  => Some ( value. immediate ( ) . def ( bx) ) , 
1287+                     } 
10971288                } 
10981289                InlineAsmOperandRef :: Out  { 
10991290                    reg, 
@@ -1113,7 +1304,10 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> {
11131304                    out_place :  _, 
11141305                }  => { 
11151306                    self . check_reg ( span,  reg) ; 
1116-                     Some ( in_value. immediate ( ) . def ( self ) ) 
1307+                     match  self  { 
1308+                         Self :: Global ( ..)  => unreachable ! ( ) , 
1309+                         Self :: Local ( bx)  => Some ( in_value. immediate ( ) . def ( bx) ) , 
1310+                     } 
11171311                } 
11181312                InlineAsmOperandRef :: Const  {  string :  _ }  => { 
11191313                    self . tcx 
0 commit comments