@@ -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 ( ) ;
@@ -553,7 +742,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> {
553742 } ;
554743 let inst_class = inst_name
555744 . strip_prefix ( "Op" )
556- . and_then ( |n| self . cx . instruction_table . table . get ( n) ) ;
745+ . and_then ( |n| self . instruction_table . table . get ( n) ) ;
557746 let inst_class = if let Some ( inst) = inst_class {
558747 inst
559748 } else {
@@ -577,13 +766,12 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> {
577766 }
578767 self . insert_inst ( id_map, defined_ids, asm_block, instruction) ;
579768 if let Some ( OutRegister :: Place ( place) ) = out_register {
769+ let place = match self {
770+ Self :: Global ( ..) => unreachable ! ( ) ,
771+ Self :: Local ( bx) => place. val . llval . def ( bx) ,
772+ } ;
580773 self . emit ( )
581- . store (
582- place. val . llval . def ( self ) ,
583- result_id. unwrap ( ) ,
584- None ,
585- std:: iter:: empty ( ) ,
586- )
774+ . store ( place, result_id. unwrap ( ) , None , std:: iter:: empty ( ) )
587775 . unwrap ( ) ;
588776 }
589777 }
@@ -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