@@ -287,6 +287,7 @@ pub use context::AttrSet;
287287/// Definition for an [`AttrSet`]: a set of [`Attr`]s.
288288#[ derive( Default , PartialEq , Eq , Hash ) ]
289289pub struct AttrSetDef {
290+ // FIXME(eddyb) consider "persistent datastructures" (e.g. the `im` crate).
290291 // FIXME(eddyb) use `BTreeMap<Attr, AttrValue>` and split some of the params
291292 // between the `Attr` and `AttrValue` based on specified uniquness.
292293 // FIXME(eddyb) don't put debuginfo in here, but rather at use sites
@@ -298,7 +299,34 @@ pub struct AttrSetDef {
298299}
299300
300301impl AttrSetDef {
301- pub fn push_diag ( & mut self , diag : Diag ) {
302+ pub fn dbg_src_loc ( & self ) -> Option < DbgSrcLoc > {
303+ // FIXME(eddyb) seriously consider moving to `BTreeMap` (see above).
304+ // HACK(eddyb) this assumes `Attr::DbgSrcLoc` is the first of `Attr`!
305+ match self . attrs . first ( ) {
306+ Some ( & Attr :: DbgSrcLoc ( OrdAssertEq ( dbg_src_loc) ) ) => Some ( dbg_src_loc) ,
307+ _ => None ,
308+ }
309+ }
310+
311+ pub fn set_dbg_src_loc ( & mut self , dbg_src_loc : DbgSrcLoc ) {
312+ // FIXME(eddyb) seriously consider moving to `BTreeMap` (see above).
313+ // HACK(eddyb) this assumes `Attr::DbgSrcLoc` is the first of `Attr`!
314+ if let Some ( Attr :: DbgSrcLoc ( _) ) = self . attrs . first ( ) {
315+ self . attrs . pop_first ( ) . unwrap ( ) ;
316+ }
317+ self . attrs . insert ( Attr :: DbgSrcLoc ( OrdAssertEq ( dbg_src_loc) ) ) ;
318+ }
319+
320+ pub fn diags ( & self ) -> & [ Diag ] {
321+ // FIXME(eddyb) seriously consider moving to `BTreeMap` (see above).
322+ // HACK(eddyb) this assumes `Attr::Diagnostics` is the last of `Attr`!
323+ match self . attrs . last ( ) {
324+ Some ( Attr :: Diagnostics ( OrdAssertEq ( diags) ) ) => diags,
325+ _ => & [ ] ,
326+ }
327+ }
328+
329+ pub fn mutate_diags ( & mut self , f : impl FnOnce ( & mut Vec < Diag > ) ) {
302330 // FIXME(eddyb) seriously consider moving to `BTreeMap` (see above).
303331 // HACK(eddyb) this assumes `Attr::Diagnostics` is the last of `Attr`!
304332 let mut attr = if let Some ( Attr :: Diagnostics ( _) ) = self . attrs . last ( ) {
@@ -307,30 +335,54 @@ impl AttrSetDef {
307335 Attr :: Diagnostics ( OrdAssertEq ( vec ! [ ] ) )
308336 } ;
309337 match & mut attr {
310- Attr :: Diagnostics ( OrdAssertEq ( diags) ) => diags . push ( diag ) ,
338+ Attr :: Diagnostics ( OrdAssertEq ( diags) ) => f ( diags ) ,
311339 _ => unreachable ! ( ) ,
312340 }
313341 self . attrs . insert ( attr) ;
314342 }
315343
316- // FIXME(eddyb) should this be hidden in favor of `AttrSet::append_diag`?
317- pub fn append_diag ( & self , diag : Diag ) -> Self {
318- let mut new_attrs = Self { attrs : self . attrs . clone ( ) } ;
319- new_attrs. push_diag ( diag) ;
320- new_attrs
344+ // HACK(eddyb) these only exist to avoid changing code working with `AttrSetDef`s.
345+ pub fn push_diags ( & mut self , new_diags : impl IntoIterator < Item = Diag > ) {
346+ self . mutate_diags ( |diags| diags. extend ( new_diags) ) ;
347+ }
348+ pub fn push_diag ( & mut self , diag : Diag ) {
349+ self . push_diags ( [ diag] ) ;
321350 }
322351}
323352
324353// FIXME(eddyb) should these methods be elsewhere?
325354impl AttrSet {
326- // FIXME(eddyb) should this be hidden in favor of `push_diag`?
327- // FIXME(eddyb) should these methods always take multiple values?
328- pub fn append_diag ( self , cx : & Context , diag : Diag ) -> Self {
329- cx. intern ( cx[ self ] . append_diag ( diag) )
355+ // FIXME(eddyb) could these two methods have a better name?
356+ pub fn reintern_with ( self , cx : & Context , f : impl FnOnce ( & mut AttrSetDef ) ) -> Self {
357+ let mut new_attrs = AttrSetDef { attrs : cx[ self ] . attrs . clone ( ) } ;
358+ f ( & mut new_attrs) ;
359+ cx. intern ( new_attrs)
360+ }
361+ pub fn mutate ( & mut self , cx : & Context , f : impl FnOnce ( & mut AttrSetDef ) ) {
362+ * self = self . reintern_with ( cx, f) ;
363+ }
364+
365+ pub fn dbg_src_loc ( self , cx : & Context ) -> Option < DbgSrcLoc > {
366+ if self == AttrSet :: default ( ) {
367+ return None ;
368+ }
369+ cx[ self ] . dbg_src_loc ( )
370+ }
371+
372+ pub fn set_dbg_src_loc ( & mut self , cx : & Context , dbg_src_loc : DbgSrcLoc ) {
373+ self . mutate ( cx, |attrs| attrs. set_dbg_src_loc ( dbg_src_loc) ) ;
374+ }
375+
376+ pub fn diags ( self , cx : & Context ) -> & [ Diag ] {
377+ cx[ self ] . diags ( )
378+ }
379+
380+ pub fn push_diags ( & mut self , cx : & Context , diags : impl IntoIterator < Item = Diag > ) {
381+ self . mutate ( cx, |attrs| attrs. push_diags ( diags) ) ;
330382 }
331383
332384 pub fn push_diag ( & mut self , cx : & Context , diag : Diag ) {
333- * self = self . append_diag ( cx, diag) ;
385+ self . push_diags ( cx, [ diag] ) ;
334386 }
335387}
336388
@@ -342,18 +394,16 @@ impl AttrSet {
342394// FIXME(eddyb) consider interning individual attrs, not just `AttrSet`s.
343395#[ derive( Clone , PartialEq , Eq , PartialOrd , Ord , Hash , derive_more:: From ) ]
344396pub enum Attr {
397+ // HACK(eddyb) this must be the first variant of `Attr` for the correctness
398+ // of `AttrSetDef::{dbg_src_loc,set_dbg_src_loc}`.
399+ DbgSrcLoc ( OrdAssertEq < DbgSrcLoc > ) ,
400+
345401 /// `QPtr`-specific attributes (see [`qptr::QPtrAttr`]).
346402 #[ from]
347403 QPtr ( qptr:: QPtrAttr ) ,
348404
349405 SpvAnnotation ( spv:: Inst ) ,
350406
351- SpvDebugLine {
352- file_path : OrdAssertEq < InternedStr > ,
353- line : u32 ,
354- col : u32 ,
355- } ,
356-
357407 /// Some SPIR-V instructions, like `OpFunction`, take a bitflags operand
358408 /// that is effectively an optimization over using `OpDecorate`.
359409 //
@@ -363,11 +413,29 @@ pub enum Attr {
363413 /// Can be used anywhere to record [`Diag`]nostics produced during a pass,
364414 /// while allowing the pass to continue (and its output to be pretty-printed).
365415 //
366- // HACK(eddyb) this is the last variant to control printing order, but also
367- // to make `push_diag`/`append_diag` above work correctly!
416+ // HACK(eddyb) this must be the last variant of `Attr` for the correctness
417+ // of`AttrSetDef::{diags,mutate_diags}` (this also helps with printing order).
368418 Diagnostics ( OrdAssertEq < Vec < Diag > > ) ,
369419}
370420
421+ /// Simple `file:line:column`-style debuginfo, similar to SPIR-V `OpLine`,
422+ /// but also supporting `(line, column)` ranges, and inlined locations.
423+ #[ derive( Copy , Clone , PartialEq , Eq , Hash ) ]
424+ pub struct DbgSrcLoc {
425+ pub file_path : InternedStr ,
426+
427+ // FIXME(eddyb) `Range` might make sense here but these are inclusive,
428+ // and `range::RangeInclusive` (the non-`Iterator` version of `a..=b`)
429+ // isn't stable (nor the type of `a..=b` expressions), yet.
430+ pub start_line_col : ( u32 , u32 ) ,
431+ pub end_line_col : ( u32 , u32 ) ,
432+
433+ /// To describe locations originally in the callee of a call that was inlined,
434+ /// the name of the callee and attributes describing the callsite are used,
435+ /// where callsite attributes are expected to contain an [`Attr::DbgSrcLoc`].
436+ pub inlined_callee_name_and_call_site : Option < ( InternedStr , AttrSet ) > ,
437+ }
438+
371439/// Diagnostics produced by SPIR-T passes, and recorded in [`Attr::Diagnostics`].
372440#[ derive( Clone , PartialEq , Eq , Hash ) ]
373441pub struct Diag {
0 commit comments