@@ -11,7 +11,7 @@ use stable_mir::ty::{ConstantKind, IndexedVal, MirConst, Ty};
1111
1212use crate :: printer:: SmirJson ;
1313
14- use super :: index:: { AllocIndex , TypeIndex } ;
14+ use super :: index:: { AllocIndex , LayoutInfo , TypeEntry , TypeIndex , TypeKind } ;
1515use super :: util:: { function_string, short_fn_name, GraphLabelString } ;
1616
1717// =============================================================================
@@ -255,4 +255,151 @@ impl GraphContext {
255255 InlineAsm { .. } => "InlineAsm" . to_string ( ) ,
256256 }
257257 }
258+
259+ // =========================================================================
260+ // Type and Layout Rendering
261+ // =========================================================================
262+
263+ /// Get detailed type information for a type
264+ pub fn get_type_entry ( & self , ty : Ty ) -> Option < & TypeEntry > {
265+ self . types . get ( ty)
266+ }
267+
268+ /// Get layout information for a type
269+ pub fn get_layout ( & self , ty : Ty ) -> Option < & LayoutInfo > {
270+ self . types . get_layout ( ty)
271+ }
272+
273+ /// Render a type with its size and alignment
274+ pub fn render_type_with_layout ( & self , ty : Ty ) -> String {
275+ let name = self . types . get_name ( ty) ;
276+ match self . types . get_layout ( ty) {
277+ Some ( layout) => format ! ( "{} ({} bytes, align {})" , name, layout. size, layout. align) ,
278+ None => name,
279+ }
280+ }
281+
282+ /// Render a type with detailed field layout (for structs/unions)
283+ pub fn render_type_detailed ( & self , ty : Ty ) -> String {
284+ match self . types . get ( ty) {
285+ Some ( entry) => entry. detailed_description ( & self . types ) ,
286+ None => format ! ( "{}" , ty) ,
287+ }
288+ }
289+
290+ /// Generate lines describing a type's memory layout
291+ pub fn render_type_layout_lines ( & self , ty : Ty ) -> Vec < String > {
292+ let mut lines = Vec :: new ( ) ;
293+ let entry = match self . types . get ( ty) {
294+ Some ( e) => e,
295+ None => {
296+ lines. push ( format ! ( "{}" , ty) ) ;
297+ return lines;
298+ }
299+ } ;
300+
301+ // Header with size/align
302+ let header = match & entry. layout {
303+ Some ( layout) => format ! (
304+ "{} ({} bytes, align {})" ,
305+ entry. name, layout. size, layout. align
306+ ) ,
307+ None => entry. name . clone ( ) ,
308+ } ;
309+ lines. push ( header) ;
310+
311+ // Field details for composite types
312+ match & entry. kind {
313+ TypeKind :: Struct { fields } => {
314+ for ( i, field) in fields. iter ( ) . enumerate ( ) {
315+ let field_ty_name = self . types . get_name ( field. ty ) ;
316+ let field_layout = self . types . get_layout ( field. ty ) ;
317+ let size_str = field_layout
318+ . map ( |l| format ! ( " ({} bytes)" , l. size) )
319+ . unwrap_or_default ( ) ;
320+ match field. offset {
321+ Some ( off) => lines. push ( format ! (
322+ " @{:3}: field{}: {}{}" ,
323+ off, i, field_ty_name, size_str
324+ ) ) ,
325+ None => lines. push ( format ! ( " field{}: {}{}" , i, field_ty_name, size_str) ) ,
326+ }
327+ }
328+ }
329+ TypeKind :: Union { fields } => {
330+ lines. push ( " (all fields at offset 0)" . to_string ( ) ) ;
331+ for ( i, field) in fields. iter ( ) . enumerate ( ) {
332+ let field_ty_name = self . types . get_name ( field. ty ) ;
333+ let field_layout = self . types . get_layout ( field. ty ) ;
334+ let size_str = field_layout
335+ . map ( |l| format ! ( " ({} bytes)" , l. size) )
336+ . unwrap_or_default ( ) ;
337+ lines. push ( format ! ( " field{}: {}{}" , i, field_ty_name, size_str) ) ;
338+ }
339+ }
340+ TypeKind :: Enum { variants } => {
341+ for ( i, variant) in variants. iter ( ) . enumerate ( ) {
342+ lines. push ( format ! (
343+ " variant {} (discriminant {}):" ,
344+ i, variant. discriminant
345+ ) ) ;
346+ for ( j, field) in variant. fields . iter ( ) . enumerate ( ) {
347+ let field_ty_name = self . types . get_name ( field. ty ) ;
348+ lines. push ( format ! ( " field{}: {}" , j, field_ty_name) ) ;
349+ }
350+ }
351+ }
352+ TypeKind :: Tuple { fields } => {
353+ for ( i, & field_ty) in fields. iter ( ) . enumerate ( ) {
354+ let field_ty_name = self . types . get_name ( field_ty) ;
355+ let offset = entry. layout . as_ref ( ) . and_then ( |l| l. field_offset ( i) ) ;
356+ match offset {
357+ Some ( off) => lines. push ( format ! ( " @{:3}: .{}: {}" , off, i, field_ty_name) ) ,
358+ None => lines. push ( format ! ( " .{}: {}" , i, field_ty_name) ) ,
359+ }
360+ }
361+ }
362+ TypeKind :: Array { elem_ty, len } => {
363+ let elem_name = self . types . get_name ( * elem_ty) ;
364+ let len_str = len. map ( |l| l. to_string ( ) ) . unwrap_or ( "?" . to_string ( ) ) ;
365+ lines. push ( format ! ( " [{}; {}]" , elem_name, len_str) ) ;
366+ }
367+ _ => { }
368+ }
369+
370+ lines
371+ }
372+
373+ /// Generate the types legend as lines for display (types with layout info)
374+ pub fn types_legend_lines ( & self ) -> Vec < String > {
375+ let mut lines = vec ! [ "TYPES" . to_string( ) ] ;
376+
377+ // Collect and sort types that have interesting layout info
378+ let mut entries: Vec < _ > = self
379+ . types
380+ . iter ( )
381+ . filter ( |( _, entry) | {
382+ // Only include composite types with layout
383+ matches ! (
384+ entry. kind,
385+ TypeKind :: Struct { .. }
386+ | TypeKind :: Union { .. }
387+ | TypeKind :: Enum { .. }
388+ | TypeKind :: Tuple { .. }
389+ )
390+ } )
391+ . collect ( ) ;
392+ entries. sort_by ( |a, b| a. 1 . name . cmp ( & b. 1 . name ) ) ;
393+
394+ for ( _ty_id, entry) in entries {
395+ let layout_str = entry
396+ . layout
397+ . as_ref ( )
398+ . map ( |l| format ! ( " ({} bytes)" , l. size) )
399+ . unwrap_or_default ( ) ;
400+ lines. push ( format ! ( "{}{}" , entry. name, layout_str) ) ;
401+ }
402+
403+ lines
404+ }
258405}
0 commit comments