(
f: NativeFunction, k: SchemaKind
)
| 261 | # we will generate kernels for, for the new NativeFunction. |
| 262 | # Details are in the function, but we only generate composite kernels (in some cases) today. |
| 263 | def generate_function( |
| 264 | f: NativeFunction, k: SchemaKind |
| 265 | ) -> Tuple[NativeFunction, Dict[DispatchKey, Dict["OperatorName", "BackendMetadata"]]]: |
| 266 | from torchgen.api import cpp |
| 267 | |
| 268 | if k == SchemaKind.functional: |
| 269 | assert f.func.kind() != SchemaKind.functional |
| 270 | # The new "functional" NativeFunction has: |
| 271 | # - any mutable arguments have been converted into (immutable) returns. |
| 272 | # (if a mutable argument was not also a return, it gets converted to one) |
| 273 | # - "_functional" appended to the base name, ONLY IF this op has a mutable variant. |
| 274 | # See Note [Overload Ambiguity With Functional Variants] |
| 275 | # The default grouping logic in signature() actually already does this, |
| 276 | # so we can piggy-back off it (but we still want return names) |
| 277 | func = f.func.signature(keep_return_names=True).with_name( |
| 278 | OperatorName( |
| 279 | name=BaseOperatorName( |
| 280 | base=f.func.name.name.base, |
| 281 | inplace=False, |
| 282 | dunder_method=f.func.name.name.dunder_method, |
| 283 | # See Note [Overload Ambiguity With Functional Variants] |
| 284 | functional_overload=f.func.kind() == SchemaKind.mutable, |
| 285 | ), |
| 286 | overload_name=f.func.name.overload_name, |
| 287 | ) |
| 288 | ) |
| 289 | elif k == SchemaKind.out: |
| 290 | # We generate out= ops mostly just so that we can pair up NativeFunctions into groups easily, |
| 291 | # but at least today, there is no good reason to actually use them. |
| 292 | # we'll generate a dispatcher entry for them, but won't actually register any kernels for them. |
| 293 | if f.func.kind() == SchemaKind.inplace: |
| 294 | func = self_to_out_signature(f.func) |
| 295 | elif f.func.kind() == SchemaKind.mutable: |
| 296 | func = mutable_to_out_signature(f.func) |
| 297 | elif f.func.kind() == SchemaKind.functional: |
| 298 | func = functional_to_out_signature(f.func) |
| 299 | else: |
| 300 | raise AssertionError( |
| 301 | "We only bother generating out= functions from either inplace or mutable or functional variants" |
| 302 | ) |
| 303 | else: |
| 304 | raise AssertionError( |
| 305 | "We currently only generate either functional or out= NativeFunctions" |
| 306 | ) |
| 307 | |
| 308 | # Generated kernel naming convention for out: <op_name>_<overload_name>. The reason for this is to |
| 309 | # disambiguate operator with the same name but different overload name, e.g., `randn.names_out` and |
| 310 | # `randn.generator_with_names_out`. |
| 311 | kernel_name = ( |
| 312 | func.name.unambiguous_name() |
| 313 | if func.kind() == SchemaKind.out |
| 314 | else cpp.name(func) |
| 315 | ) |
| 316 | if f.func.has_symint(): |
| 317 | kernel_name += "_symint" |
| 318 | backend_metadata = { |
| 319 | DispatchKey.CompositeExplicitAutograd: { |
| 320 | func.name: BackendMetadata( |
no test coverage detected
searching dependent graphs…