@@ -591,14 +591,41 @@ def _is_param_t_call(expr: ast.AST | None, param: str) -> bool:
591591 )
592592
593593
594- def _is_self_matmul_expr (expr : ast .AST | None , params : set [str ]) -> bool :
594+ def _is_self_matmul_expr (
595+ expr : ast .AST | None ,
596+ params : set [str ],
597+ torch_aliases : Optional [set [str ]] = None ,
598+ mm_aliases : Optional [set [str ]] = None ,
599+ ) -> bool :
600+ torch_aliases = torch_aliases or set ()
601+ mm_aliases = mm_aliases or set ()
595602 if isinstance (expr , ast .BinOp ) and isinstance (expr .op , ast .MatMult ):
596603 return any (
597604 isinstance (expr .left , ast .Name )
598605 and expr .left .id == param
599606 and _is_param_t_call (expr .right , param )
600607 for param in params
601608 )
609+ if not isinstance (expr , ast .Call ):
610+ return False
611+ if len (expr .args ) != 2 or expr .keywords :
612+ return False
613+ for param in params :
614+ if not (
615+ isinstance (expr .args [0 ], ast .Name )
616+ and expr .args [0 ].id == param
617+ and _is_param_t_call (expr .args [1 ], param )
618+ ):
619+ continue
620+ if isinstance (expr .func , ast .Name ) and expr .func .id in mm_aliases :
621+ return True
622+ if (
623+ isinstance (expr .func , ast .Attribute )
624+ and expr .func .attr in {"mm" , "matmul" }
625+ and isinstance (expr .func .value , ast .Name )
626+ and expr .func .value .id in torch_aliases
627+ ):
628+ return True
602629 return False
603630
604631
@@ -713,7 +740,12 @@ def _input_reduction_return_from_body(
713740 return saw_return
714741
715742
716- def _self_matmul_return_from_body (body : list [ast .stmt ], params : set [str ]) -> bool :
743+ def _self_matmul_return_from_body (
744+ body : list [ast .stmt ],
745+ params : set [str ],
746+ torch_aliases : Optional [set [str ]] = None ,
747+ mm_aliases : Optional [set [str ]] = None ,
748+ ) -> bool :
717749 aliases : set [str ] = set ()
718750 saw_return = False
719751
@@ -730,12 +762,12 @@ def _self_matmul_return_from_body(body: list[ast.stmt], params: set[str]) -> boo
730762 isinstance (stmt , ast .Assign )
731763 and len (stmt .targets ) == 1
732764 and isinstance (stmt .targets [0 ], ast .Name )
733- and _is_self_matmul_expr (stmt .value , params )
765+ and _is_self_matmul_expr (stmt .value , params , torch_aliases , mm_aliases )
734766 ):
735767 aliases .add (stmt .targets [0 ].id )
736768 continue
737769 if isinstance (stmt , ast .Return ):
738- if _is_self_matmul_expr (stmt .value , params ):
770+ if _is_self_matmul_expr (stmt .value , params , torch_aliases , mm_aliases ):
739771 saw_return = True
740772 continue
741773 if isinstance (stmt .value , ast .Name ) and stmt .value .id in aliases :
@@ -1658,25 +1690,45 @@ def detect_partial_self_matmul_output(code: str | SubmissionFacts) -> list[dict]
16581690 helper_names : set [str ] = set ()
16591691 partial_aliases = {"partial" }
16601692 functools_aliases = {"functools" }
1693+ torch_aliases = {"torch" }
1694+ mm_aliases : set [str ] = set ()
16611695
16621696 for node in facts ._imports :
16631697 for alias in node .names :
16641698 if alias .name == "functools" :
16651699 functools_aliases .add (alias .asname or alias .name )
1700+ if alias .name == "torch" :
1701+ torch_aliases .add (alias .asname or alias .name )
16661702 for node in facts ._import_froms :
1667- if node .module != "functools" :
1668- continue
1669- for alias in node .names :
1670- if alias .name == "partial" :
1671- partial_aliases .add (alias .asname or alias .name )
1703+ if node .module == "functools" :
1704+ for alias in node .names :
1705+ if alias .name == "partial" :
1706+ partial_aliases .add (alias .asname or alias .name )
1707+ if node .module == "torch" :
1708+ for alias in node .names :
1709+ if alias .name in {"mm" , "matmul" }:
1710+ mm_aliases .add (alias .asname or alias .name )
16721711
16731712 for node in ast .walk (tree ):
16741713 if not isinstance (node , (ast .FunctionDef , ast .AsyncFunctionDef )):
16751714 continue
16761715 params = {arg .arg for arg in node .args .args }
1677- if params and _self_matmul_return_from_body (node .body , params ):
1716+ if params and _self_matmul_return_from_body (node .body , params , torch_aliases , mm_aliases ):
16781717 helper_names .add (node .name )
16791718
1719+ for node in ast .walk (tree ):
1720+ if not isinstance (node , (ast .FunctionDef , ast .AsyncFunctionDef )):
1721+ continue
1722+ if not is_entrypoint_name (node .name ):
1723+ continue
1724+ params = {arg .arg for arg in node .args .args }
1725+ if params and _self_matmul_return_from_body (node .body , params , torch_aliases , mm_aliases ):
1726+ return [{
1727+ "pattern" : "SELF_MATMUL_OUTPUT" ,
1728+ "severity" : "critical" ,
1729+ "evidence" : "custom_kernel returns data @ data.t() or equivalent self-matmul" ,
1730+ }]
1731+
16801732 for stmt in tree .body :
16811733 if not isinstance (stmt , ast .Assign ):
16821734 continue
0 commit comments