22import concurrent .futures
33import dataclasses
44import functools
5- import json
65import os
76import pathlib
87import re
98import shutil
109import subprocess
10+ import sys
1111import textwrap
1212
13+ sys .path .insert (0 , str (pathlib .Path (__file__ ).resolve ().parent ))
14+ import ops_config # noqa: E402
15+
1316try :
1417 import clang .cindex
1518 from clang .cindex import CursorKind
@@ -1848,6 +1851,52 @@ def _filter_ops(ops, op_allowlist, *, strict=False):
18481851 return {op_name : ops [op_name ] for op_name in op_allowlist if op_name in ops }
18491852
18501853
1854+ def _select_ops_from_config (ops , config , config_path ):
1855+ selected = {}
1856+
1857+ for op_name , selection in config .items ():
1858+ headers = selection ["headers" ]
1859+
1860+ if headers is not None :
1861+ selected [op_name ] = [
1862+ _implementation_from_json (header ) for header in headers
1863+ ]
1864+ continue
1865+
1866+ if op_name not in ops :
1867+ raise ValueError (
1868+ f"{ config_path } : operator { op_name !r} is not available for "
1869+ "the active devices"
1870+ )
1871+
1872+ slots = selection ["implementations" ]
1873+
1874+ if slots is None :
1875+ selected [op_name ] = ops [op_name ]
1876+ continue
1877+
1878+ headers_by_slot = {}
1879+
1880+ for implementation in ops [op_name ]:
1881+ slot = ops_config .implementation_slot (implementation .path )
1882+ headers_by_slot .setdefault (slot , []).append (implementation )
1883+
1884+ missing = [slot for slot in slots if slot not in headers_by_slot ]
1885+
1886+ if missing :
1887+ formatted = ", " .join (str (slot ) for slot in missing )
1888+ raise ValueError (
1889+ f"{ config_path } : operator { op_name !r} has no active "
1890+ f"implementation at slot(s) { formatted } "
1891+ )
1892+
1893+ selected [op_name ] = [
1894+ implementation for slot in slots for implementation in headers_by_slot [slot ]
1895+ ]
1896+
1897+ return selected
1898+
1899+
18511900def _get_all_ops (
18521901 devices ,
18531902 with_torch = False ,
@@ -2084,6 +2133,11 @@ def _dispatch_gen_batch_size():
20842133 type = str ,
20852134 help = "Operator allowlist to generate. Accepts names separated by spaces or commas." ,
20862135 )
2136+ parser .add_argument (
2137+ "--ops-config" ,
2138+ type = pathlib .Path ,
2139+ help = "Path to an `ops.json` operator and implementation selection." ,
2140+ )
20872141 parser .add_argument (
20882142 "--strict-ops" ,
20892143 action = "store_true" ,
@@ -2101,25 +2155,18 @@ def _dispatch_gen_batch_size():
21012155 for directory in (_BINDINGS_DIR , _GENERATED_SRC_DIR , _INCLUDE_DIR ):
21022156 directory .mkdir (parents = True , exist_ok = True )
21032157
2104- ops_json = pathlib .Path ("ops.json" )
2158+ config_path = args .ops_config
2159+ ops = _get_all_ops (
2160+ args .devices ,
2161+ with_torch = args .with_torch ,
2162+ with_ninetoothed = args .with_ninetoothed ,
2163+ with_linked = args .with_linked ,
2164+ with_triton = args .with_triton ,
2165+ )
21052166
2106- if ops_json .exists ():
2107- raw_ops = json .loads (ops_json .read_text ())
2108- ops = {
2109- op_name : [
2110- _implementation_from_json (implementation )
2111- for implementation in implementations
2112- ]
2113- for op_name , implementations in raw_ops .items ()
2114- }
2115- else :
2116- ops = _get_all_ops (
2117- args .devices ,
2118- with_torch = args .with_torch ,
2119- with_ninetoothed = args .with_ninetoothed ,
2120- with_linked = args .with_linked ,
2121- with_triton = args .with_triton ,
2122- )
2167+ if config_path is not None :
2168+ config = ops_config .load_ops_config (config_path )
2169+ ops = _select_ops_from_config (ops , config , config_path )
21232170
21242171 ops = _filter_ops (
21252172 ops ,
0 commit comments