@@ -353,15 +353,17 @@ def _constraint_tload_mat_nd2nz(src, dst) -> bool:
353353 # COL_MAJOR + ROW_MAJOR corresponds to NZ format
354354 if b_layout_value not in {"col_major" , "COL_MAJOR" } or s_layout_value not in {"row_major" , "ROW_MAJOR" }:
355355 return False
356- # ND2NZ: source is in ND (row-major) format where the inner dimension (g4)
357- # corresponds to the tile column count. Disambiguates from DN format where
358- # g4 corresponds to the tile row count.
359- if hasattr (src , 'rank' ) and src .rank == 5 :
360- dst_valid_cols = dst .valid_shape [1 ] if hasattr (dst , 'valid_shape' ) and dst .valid_shape is not None else None
361- if dst_valid_cols is not None and hasattr (src , 'shape' ) and src .shape is not None :
362- src_inner = src .shape [4 ] if len (src .shape ) >= 5 else None
363- if src_inner is not None :
364- if not _known_eq (dst_valid_cols , src_inner ):
356+ # Disambiguate ND vs DN via the source view layout attribute
357+ # (e.g. layout = #pto.layout<nd>). When the layout is not annotated the
358+ # constraint conservatively returns True to avoid false rejections.
359+ # src.config is always a ViewConfig for view operands — never None.
360+ if hasattr (src , 'config' ) and src .config is not None :
361+ view_config = src .config
362+ if hasattr (view_config , 'layout' ):
363+ layout = view_config .layout
364+ if layout is not None :
365+ layout_val = layout .value
366+ if layout_val .upper () not in {'ND' , 'NZ' }:
365367 return False
366368 return True
367369
@@ -381,15 +383,17 @@ def _constraint_tload_mat_dn2nz(src, dst) -> bool:
381383 s_layout_value = s_layout .value if hasattr (s_layout , "value" ) else s_layout
382384 if b_layout_value not in {"col_major" , "COL_MAJOR" } or s_layout_value not in {"row_major" , "ROW_MAJOR" }:
383385 return False
384- # DN2NZ: source is in DN (col-major) format where the inner dimension (g4)
385- # corresponds to the tile row count. Disambiguates from ND format where
386- # g4 corresponds to the tile column count.
387- if hasattr (src , 'rank' ) and src .rank == 5 :
388- dst_valid_rows = dst .valid_shape [0 ] if hasattr (dst , 'valid_shape' ) and dst .valid_shape is not None else None
389- if dst_valid_rows is not None and hasattr (src , 'shape' ) and src .shape is not None :
390- src_inner = src .shape [4 ] if len (src .shape ) >= 5 else None
391- if src_inner is not None :
392- if not _known_eq (dst_valid_rows , src_inner ):
386+ # Disambiguate DN vs ND via the source view layout attribute
387+ # (e.g. layout = #pto.layout<dn>). When the layout is not annotated the
388+ # constraint conservatively returns True to avoid false rejections.
389+ # src.config is always a ViewConfig for view operands — never None.
390+ if hasattr (src , 'config' ) and src .config is not None :
391+ view_config = src .config
392+ if hasattr (view_config , 'layout' ):
393+ layout = view_config .layout
394+ if layout is not None :
395+ layout_val = layout .value
396+ if layout_val .upper () not in {'DN' , 'NZ' }:
393397 return False
394398 return True
395399
@@ -501,3 +505,84 @@ def template_tload_gm_to_mat_dn2nz(src: pto.PartitionTensorView, dst: pto.Tile):
501505 ctrl = (0 , False )
502506 )
503507 return
508+
509+
510+ def _constraint_tload_mat_dn2zn (src , dst ) -> bool :
511+ """TLOAD.MAT DN2ZN fractal load constraint (transposed DN→ZN)
512+
513+ DN2ZN loads col-major (DN) data from GM into L1 MAT in ZN format
514+ (blayout=row_major, slayout=col_major). Internally reuses the nd2nz
515+ hardware path with transposed parameters — see TLoadCubeDN2ZN.
516+ """
517+ if not _constraint_tload_mat_base (src , dst ):
518+ return False
519+ config = dst .config
520+ if config is None :
521+ return False
522+ b_layout = config .b_layout
523+ s_layout = config .s_layout
524+ if b_layout is None or s_layout is None :
525+ return False
526+ b_layout_value = b_layout .value if hasattr (b_layout , "value" ) else b_layout
527+ s_layout_value = s_layout .value if hasattr (s_layout , "value" ) else s_layout
528+ # ZN format: blayout=row_major, slayout=col_major
529+ if b_layout_value not in {"row_major" , "ROW_MAJOR" } or s_layout_value not in {"col_major" , "COL_MAJOR" }:
530+ return False
531+ # Use the view layout to disambiguate: DN2ZN only matches DN or NZ sources.
532+ # src.config is always a ViewConfig for view operands — never None.
533+ if hasattr (src , 'config' ) and src .config is not None :
534+ view_config = src .config
535+ if hasattr (view_config , 'layout' ):
536+ layout = view_config .layout
537+ if layout is not None :
538+ layout_val = layout .value
539+ if layout_val .upper () not in {'DN' , 'NZ' }:
540+ return False
541+ return True
542+
543+
544+ @pto .ckernel (
545+ target = "a5" ,
546+ op = "pto.tload" ,
547+ priority = 1 ,
548+ dtypes = [
549+ (pto .f16 , pto .f16 ),
550+ (pto .bf16 , pto .bf16 ),
551+ (pto .f32 , pto .f32 ),
552+ ],
553+ constraints = [_constraint_tload_mat_dn2zn ],
554+ name = "tload_gm_to_mat_dn2zn" ,
555+ )
556+ def template_tload_gm_to_mat_dn2zn (src : pto .PartitionTensorView , dst : pto .Tile ):
557+ """GM -> MAT DN2ZN fractal load template (transposed DN → ZN)
558+
559+ Load Col-Major (DN) format data from GM into L1 MAT Buffer in ZN format
560+ (transposed NZ: blayout=row_major, slayout=col_major).
561+
562+ Reuses the ND2NZ hardware mode with transposed parameter mapping, matching
563+ the C++ ISA TLoadCubeDN2ZN (TLoad.hpp:472) which calls
564+ TLoadCubeInstr<Layout::ND> with nValue=gShape4, dValue=validRow.
565+ """
566+ m , k = dst .valid_shape
567+ g0 , g1 , g2 , g3 , g4 = src .shape
568+ s0 , s1 , s2 , s3 , s4 = src .strides
569+
570+ gm_ptr = src .as_ptr ()
571+ mat_ptr = dst .as_ptr ()
572+ elem_bytes = pto .bytewidth (dst .element_type )
573+
574+ # TLoadCubeDN2ZN: nValue = gShape4, dValue = validRow
575+ n_value = g4
576+ d_value = m
577+
578+ # TLoadCubeDN2ZN: loop1SrcStride = GetByteSize(gStride4)
579+ src_inner_stride = s4 * elem_bytes
580+
581+ pto .mte_gm_l1_frac (
582+ gm_ptr , mat_ptr , pto .FractalMode .ND2NZ ,
583+ shape = (n_value , d_value ),
584+ src_layout = (src_inner_stride ,),
585+ dst_group = (1 , 1 , k , 0 ),
586+ ctrl = (0 , False )
587+ )
588+ return
0 commit comments