1313from numba .cuda .types import GridGroup
1414
1515
16+ # Check if CUDA Toolkit and llvmlite support polymorphic debug info
17+ def _get_llvmlite_version ():
18+ """Get llvmlite version as tuple (major, minor, patch)."""
19+ try :
20+ import llvmlite
21+ version_str = llvmlite .__version__
22+ # Parse version string like "0.46.0" or "0.46.0dev"
23+ parts = version_str .split ('.' )
24+ major = int (parts [0 ])
25+ minor = int (parts [1 ])
26+ return (major , minor )
27+ except Exception :
28+ return (0 , 0 )
29+
30+ def _check_polymorphic_debug_info_support ():
31+ """Check if CTK and llvmlite support polymorphic debug info.
32+
33+ Returns:
34+ tuple: (supported: bool, use_typed_const: bool)
35+ - supported: Whether feature is supported at all
36+ - use_typed_const: True for typed constant,
37+ False for node reference
38+ """
39+ try :
40+ from numba .cuda .cudadrv import runtime
41+ ctk_version = runtime .get_version ()
42+ llvmlite_version = _get_llvmlite_version ()
43+
44+ # Support should be available with CTK newer than 13.1
45+ if ctk_version <= (13 , 1 ):
46+ return (False , False )
47+
48+ # llvmlite > 0.45: use typed constant
49+ # llvmlite <= 0.45: use node reference
50+ use_typed_const = llvmlite_version > (0 , 45 )
51+ return (True , use_typed_const )
52+
53+ except Exception :
54+ return (False , False )
55+
56+ # Check support and determine mode
57+ (DEBUG_POLY_SUPPORTED ,
58+ DEBUG_POLY_USE_TYPED_CONST ) = _check_polymorphic_debug_info_support ()
59+
60+ # Set config based on polymorphic debug info support
61+ if not hasattr (config , "CUDA_DEBUG_POLY" ):
62+ config .CUDA_DEBUG_POLY = DEBUG_POLY_SUPPORTED
63+ if not hasattr (config , "CUDA_DEBUG_POLY_USE_TYPED_CONST" ):
64+ config .CUDA_DEBUG_POLY_USE_TYPED_CONST = (
65+ DEBUG_POLY_USE_TYPED_CONST
66+ )
67+
1668@contextmanager
1769def suspend_emission (builder ):
1870 """Suspends the emission of debug_metadata for the duration of the context
@@ -619,7 +671,10 @@ def _var_type(self, lltype, size, datamodel=None):
619671 # Ignore the "tag" field, focus on the "payload" field which
620672 # contains the data types in memory
621673 if field == "payload" :
622- for mod in model .inner_models ():
674+ # Store metadata dictionaries to create members later
675+ member_metadata_dicts = []
676+
677+ for index , mod in enumerate (model .inner_models ()):
623678 dtype = mod .get_value_type ()
624679 membersize = self .cgctx .get_abi_sizeof (dtype )
625680 basetype = self ._var_type (
@@ -632,33 +687,103 @@ def _var_type(self, lltype, size, datamodel=None):
632687 # Use a prefix "_" on type names as field names
633688 membername = "_" + typename
634689 memberwidth = _BYTE_SIZE * membersize
690+ # Build the metadata dictionary
691+ metadata_dict = {
692+ "tag" : ir .DIToken ("DW_TAG_member" ),
693+ "name" : membername ,
694+ "baseType" : basetype ,
695+ # DW_TAG_member size is in bits
696+ "size" : memberwidth ,
697+ }
698+ if config .CUDA_DEBUG_POLY :
699+ # Polymorphic debug info with DW_TAG_variant
700+ # extraData depends on llvmlite version
701+ if config .CUDA_DEBUG_POLY_USE_TYPED_CONST :
702+ metadata_dict ["extraData" ] = (
703+ ir .IntType (8 )(index )
704+ )
705+ else :
706+ # Use metadata node reference
707+ metadata_dict ["extraData" ] = (
708+ m .add_metadata ([ir .IntType (8 )(index )])
709+ )
710+ # Add offset to each variant member
711+ # Offset equals the element's own width
712+ metadata_dict ["offset" ] = memberwidth
713+ member_metadata_dicts .append (metadata_dict )
714+ if memberwidth > maxwidth :
715+ maxwidth = memberwidth
716+
717+ # Create the member DIDerivedTypes
718+ for metadata_dict in member_metadata_dicts :
635719 derived_type = m .add_debug_info (
636- "DIDerivedType" ,
637- {
638- "tag" : ir .DIToken ("DW_TAG_member" ),
639- "name" : membername ,
640- "baseType" : basetype ,
641- # DW_TAG_member size is in bits
642- "size" : memberwidth ,
643- },
720+ "DIDerivedType" , metadata_dict
644721 )
645722 meta .append (derived_type )
646- if memberwidth > maxwidth :
647- maxwidth = memberwidth
648723
649- fake_union_name = "dbg_poly_union"
650- return m .add_debug_info (
651- "DICompositeType" ,
652- {
653- "file" : self .difile ,
654- "tag" : ir .DIToken ("DW_TAG_union_type" ),
655- "name" : fake_union_name ,
656- "identifier" : str (lltype ),
657- "elements" : m .add_metadata (meta ),
658- "size" : maxwidth ,
659- },
660- is_distinct = True ,
661- )
724+ if config .CUDA_DEBUG_POLY :
725+ # Polymorphic variable debug info generation
726+ wrapper_struct_size = 2 * maxwidth
727+ discriminator = m .add_debug_info (
728+ "DIDerivedType" ,
729+ {
730+ "tag" : ir .DIToken ("DW_TAG_member" ),
731+ "name" : "discriminator" ,
732+ "baseType" : m .add_debug_info ("DIBasicType" , {
733+ "name" : "int" ,
734+ "size" : _BYTE_SIZE ,
735+ "encoding" : ir .DIToken ("DW_ATE_unsigned" )
736+ }),
737+ "size" : _BYTE_SIZE ,
738+ "flags" : ir .DIToken ("DIFlagArtificial" ),
739+ },
740+ )
741+ # Create the final variant_part with actual members
742+ variant_elements_metadata = m .add_metadata (meta )
743+ variant_unique_identifier = str (id (variant_elements_metadata ))
744+ variant_part_type = m .add_debug_info (
745+ "DICompositeType" ,
746+ {
747+ "file" : self .difile ,
748+ "tag" : ir .DIToken ("DW_TAG_variant_part" ),
749+ "name" : "variant_part" ,
750+ "identifier" : variant_unique_identifier ,
751+ "elements" : variant_elements_metadata ,
752+ "size" : maxwidth ,
753+ "discriminator" : discriminator ,
754+ },
755+ )
756+ # Create elements metadata for wrapper struct
757+ elements_metadata = m .add_metadata (
758+ [discriminator , variant_part_type ]
759+ )
760+ unique_identifier = str (id (elements_metadata ))
761+ wrapper_struct = m .add_debug_info (
762+ "DICompositeType" ,
763+ {
764+ "file" : self .difile ,
765+ "tag" : ir .DIToken ("DW_TAG_structure_type" ),
766+ "name" : "variant_wrapper_struct" ,
767+ "identifier" : unique_identifier ,
768+ "elements" : elements_metadata ,
769+ "size" : wrapper_struct_size ,
770+ },
771+ )
772+ return wrapper_struct
773+ else :
774+ fake_union_name = "dbg_poly_union"
775+ return m .add_debug_info (
776+ "DICompositeType" ,
777+ {
778+ "file" : self .difile ,
779+ "tag" : ir .DIToken ("DW_TAG_union_type" ),
780+ "name" : fake_union_name ,
781+ "identifier" : str (lltype ),
782+ "elements" : m .add_metadata (meta ),
783+ "size" : maxwidth ,
784+ },
785+ is_distinct = True ,
786+ )
662787 # For other cases, use upstream Numba implementation
663788 return super ()._var_type (lltype , size , datamodel = datamodel )
664789
0 commit comments