@@ -54,7 +54,9 @@ def __init__(self, extra_permutable_ops: set | None = None) -> None:
5454 exir_ops .edge .aten .hardtanh .default ,
5555 exir_ops .edge .aten .clamp .default ,
5656 exir_ops .edge .aten .cat .default ,
57+ exir_ops .edge .aten .constant_pad_nd .default ,
5758 exir_ops .edge .aten .mean .dim ,
59+ exir_ops .edge .aten .pad .default ,
5860 exir_ops .edge .aten .sum .dim_IntList ,
5961 exir_ops .edge .aten .slice_copy .Tensor ,
6062 }
@@ -80,6 +82,11 @@ def __init__(self, extra_permutable_ops: set | None = None) -> None:
8082
8183 _SQUEEZE_OPS = (exir_ops .edge .aten .squeeze_copy .dim ,)
8284
85+ _PAD_OPS = (
86+ exir_ops .edge .aten .constant_pad_nd .default ,
87+ exir_ops .edge .aten .pad .default ,
88+ )
89+
8390 @staticmethod
8491 def _find_extra_one (longer : list [int ], shorter : list [int ]) -> int :
8592 """If longer has exactly one more element of value 1, return its index. Else -1."""
@@ -450,6 +457,8 @@ def _is_pointwise(target) -> bool:
450457 return False
451458
452459 def is_node_permutable (self , node : torch .fx .Node ) -> bool :
460+ if node .target in self ._PAD_OPS and not self ._is_constant_pad (node ):
461+ return False
453462 if node .target in self ._permutable_ops :
454463 if node .target in (
455464 exir_ops .edge .aten .mean .dim ,
@@ -462,6 +471,24 @@ def is_node_permutable(self, node: torch.fx.Node) -> bool:
462471 return True
463472 return self ._is_pointwise (node .target )
464473
474+ def _is_constant_pad (self , node : torch .fx .Node ) -> bool :
475+ if len (node .args ) < 2 :
476+ return False
477+
478+ pad = node .args [1 ]
479+ if not isinstance (pad , (list , tuple )):
480+ return False
481+
482+ if len (pad ) % 2 != 0 :
483+ return False
484+
485+ if node .target == exir_ops .edge .aten .pad .default :
486+ mode = node .args [2 ] if len (node .args ) > 2 else node .kwargs .get ("mode" )
487+ if mode not in (None , "constant" ):
488+ return False
489+
490+ return True
491+
465492 def permute_subgraph (self , subgraph : Subgraph ) -> bool : # noqa: C901
466493 # Ensure that the subgraph's edges have not been modified by an earlier rewrite before applying changes.
467494 if not self ._subgraph_edges_are_current (subgraph ):
@@ -495,6 +522,8 @@ def permute_subgraph(self, subgraph: Subgraph) -> bool: # noqa: C901
495522 self .update_mean_dim (node , node_start_perm )
496523 elif node .target == exir_ops .edge .aten .slice_copy .Tensor :
497524 self .update_slice_copy (node , node_start_perm )
525+ elif node .target in self ._PAD_OPS :
526+ self .update_pad (node , node_start_perm )
498527 elif node .target in self ._VIEW_OPS :
499528 self .update_view_copy (node , node_start_perm )
500529 elif node .target in self ._UNSQUEEZE_OPS :
@@ -596,6 +625,24 @@ def update_slice_copy(self, node: torch.fx.Node, start_permute: list[int]) -> No
596625 dim = get_arg (node , "dim" , int )
597626 set_arg (node , "dim" , start_permute [dim ])
598627
628+ def update_pad (self , node : torch .fx .Node , start_permute : list [int ]) -> None :
629+ pad = list (cast (list [int ], node .args [1 ]))
630+ rank = len (start_permute )
631+ pad_pairs = [[0 , 0 ] for _ in range (rank )]
632+ for pair_idx , pair_start in enumerate (range (0 , len (pad ), 2 )):
633+ dim = rank - 1 - pair_idx
634+ pad_pairs [dim ] = [pad [pair_start ], pad [pair_start + 1 ]]
635+
636+ remapped_pairs = [pad_pairs [start_permute .index (dim )] for dim in range (rank )]
637+ remapped_pad = []
638+ for pair in reversed (remapped_pairs ):
639+ remapped_pad .extend (pair )
640+
641+ while len (remapped_pad ) > 2 and remapped_pad [- 2 :] == [0 , 0 ]:
642+ remapped_pad = remapped_pad [:- 2 ]
643+
644+ node .update_arg (1 , remapped_pad )
645+
599646 def update_view_copy (self , node : torch .fx .Node , start_permute : list [int ]) -> None :
600647 """Adjust view_copy shape arg after permute removal.
601648
0 commit comments