pytorch

Форк
0
/
gen_lazy_tensor.py 
605 строк · 22.7 Кб
1
import argparse
2
import os
3
import pathlib
4
import re
5
from collections import Counter, namedtuple
6
from typing import (
7
    Any,
8
    Callable,
9
    Dict,
10
    Iterable,
11
    Iterator,
12
    List,
13
    Optional,
14
    Sequence,
15
    Tuple,
16
    Type,
17
    Union,
18
)
19

20
import yaml
21

22
import torchgen.dest as dest
23

24
from torchgen.api.lazy import setValueT
25
from torchgen.api.types import BaseCppType
26
from torchgen.dest.lazy_ir import GenLazyIR, GenLazyNativeFuncDefinition, GenTSLazyIR
27
from torchgen.gen import get_grouped_native_functions, parse_native_yaml
28

29
from torchgen.model import NativeFunction, NativeFunctionsGroup, OperatorName
30
from torchgen.selective_build.selector import SelectiveBuilder
31
from torchgen.utils import concatMap, FileManager, NamespaceHelper
32
from torchgen.yaml_utils import YamlLoader
33
from .gen_backend_stubs import (
34
    error_on_missing_kernels,
35
    gen_dispatcher_registrations,
36
    gen_dispatchkey_nativefunc_headers,
37
    parse_backend_yaml,
38
)
39

40
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
41
#
42
#                        Lazy Tensor Codegen
43
#
44
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
45
# Overview
46
# ~~~~~~~~
47
#
48
# This codegen script builds on existing data models and helpers used
49
# by all ATen backends, and adds new functionality specific to lazy
50
# tensor backends.
51
#
52
# Inputs:
53
# - <backend>_native_functions.yaml: controls which operators are
54
#   supported by the backend.
55
#
56
# Outputs:
57
# (for all backends)
58
# <DispatchKey>Ir.h defines Lazy IR classes to be constructed during tracing
59
# - opt-in: also generate 'lowering' methods for the TorchScript backend only
60
# <DispatchKey>NativeFunctions.cpp defines implementations of native functions which perform lazy tracing
61
# - opt-in: 'full_codegen' section of backend yaml; 'supported' section omits these implementations
62
# <DispatchKey>NativeFunctions.h declares implementations of native functions for both 'supported' and 'full_codegen'
63
# ops
64
#
65
# Register<DispatchKey>.cpp registers all op implementations with the dispatcher
66
# RegisterAutograd<DispatchKey>.cpp registers all autograd implementations with the dispatcher
67
#
68
# Validation Helpers:
69
# - Shape Inference: errs if any ops in backend yaml require shape inference not provided by meta kernels or
70
#   implementations in torch/csrc/lazy/core/shape_inference.*
71
# - native function impls: errs if any 'supported' ops do not have an implementation defined in the backend
72
#   (non-codegen) implementation file
73
#
74
#
75
# About the Data Model
76
# ~~~~~~~~~~~~~~~~~~~~
77
#
78
# Modeled after ATen codegen, the first step is to parse yaml and build a data model for the operators
79
# we care about.  In this case, the <backend>_native_functions yaml defines a subset of the core operators
80
# (defined in more detail in the main native_functions.yaml), which will be supported by your backend.
81
# Backends can list ops in two categories:
82
#  - `supported` ops require hand-implementations but still get codegenned declarations and registrations
83
#  - `full_codegen` ops get implementations (and IR classes) generated too
84
#
85
# Each native function is modeled as an object with a schema, and each schema has objects representing their
86
# arguments.  Much of the codegen is manipulation of the arguments and their types.  For example, lazy tensor
87
# backends need to transform 'at::Tensor' arguments into 'lazy::Value' objects, as well as replacing reference
88
# types (stringref) with actual string objects, and this is done by manipulating the data model objects.
89
# - see api/lazy.py for the lazy data model
90
#
91
# Once the data model is set up, the rest of this script processes a number of templates for output CPP file
92
# and fills in the template values using helpers in `dest/lazy_ir.py` and `dest/lazy_ts_lowering.py`.  These
93
# helpers mostly iterate over functions and their arguments, outputting different c++ snippets.
94
#
95
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
96

97

98
# Parses the external backend's yaml, and adds a new BackendIndex for the backend's dispatch key.
99
# Returns a Tuple of (backend_key, autograd_key, cpp_namespace, updated BackendIndex mapping, full_codegen)
100
ParsedExternalYaml = namedtuple(
101
    "ParsedExternalYaml",
102
    ["backend_key", "autograd_key", "cpp_namespace", "backend_indices", "full_codegen"],
103
)
104

105

106
def parse_native_functions_keys(
107
    backend_yaml_path: str,
108
    grouped_native_functions: Sequence[Union[NativeFunction, NativeFunctionsGroup]],
109
) -> Tuple[List[OperatorName], List[Any], List[OperatorName]]:
110
    native_functions_map: Dict[OperatorName, NativeFunction] = {
111
        f.func.name: f
112
        for f in concatMap(
113
            lambda f: [f] if isinstance(f, NativeFunction) else list(f.functions()),
114
            grouped_native_functions,
115
        )
116
    }
117

118
    with open(backend_yaml_path) as f:
119
        yaml_values = yaml.load(f, Loader=YamlLoader)
120
    assert isinstance(yaml_values, dict)
121

122
    full_codegen = yaml_values.pop("full_codegen", [])
123
    non_native = yaml_values.pop("non_native", [])
124
    ir_gen = yaml_values.pop("ir_gen", [])
125
    assert isinstance(full_codegen, list)
126
    assert isinstance(non_native, list)
127
    assert isinstance(ir_gen, list)
128
    full_codegen_opnames = [OperatorName.parse(name) for name in full_codegen]
129
    ir_gen_opnames = [OperatorName.parse(name) for name in ir_gen]
130
    return full_codegen_opnames, non_native, ir_gen_opnames
131

132

133
def validate_shape_inference_header(
134
    shape_inference_hdr: str, expected_shape_infr_decls: List[str]
135
) -> None:
136
    try:
137
        with open(shape_inference_hdr) as f:
138
            shape_infr_decls = f.read()
139
            shape_infr_decl_lines = set(shape_infr_decls.split("\n"))
140
    except OSError as e:
141
        raise AssertionError(
142
            f"Unable to read from the specified shape_inference_hdr file: {shape_inference_hdr}"
143
        ) from e
144

145
    shape_infr_regex = r"compute_shape_(\w+)"
146
    actual_shape_infr_name_counts = Counter(
147
        re.findall(shape_infr_regex, shape_infr_decls)
148
    )
149
    # TODO(whc) add a check for shape inference functions that have meta kernels implement and should be retired.
150

151
    missing_decls = [
152
        decl for decl in expected_shape_infr_decls if decl not in shape_infr_decl_lines
153
    ]
154
    if missing_decls:
155
        raise Exception(
156
            f"""Missing shape inference function.\n
157
Please add declare this function in {shape_inference_hdr}:\n
158
and implement it in the corresponding shape_inference.cpp file.\n
159
{os.linesep.join(missing_decls)}"""
160
        )
161

162

163
# Some helper functions for the codegen.
164
def get_ltc_helper_fns() -> str:
165
    return """\
166
at::Tensor to_meta(const at::Tensor& tensor) {
167
  // undefined tensors can't be converted to the meta device, since they don't have sizes/strides
168
  if (!tensor.defined()) return tensor;
169
  auto out = at::native::empty_strided_meta_symint(tensor.sym_sizes(), tensor.sym_strides(), \
170
/*dtype=*/c10::make_optional(tensor.scalar_type()), /*layout=*/c10::make_optional(tensor.layout()), \
171
/*device=*/c10::make_optional(c10::Device(c10::kMeta)), /*pin_memory=*/c10::nullopt);
172
  // needs to handle wrapped numbers, so dtype promotion works properly.
173
  if (tensor.unsafeGetTensorImpl()->is_wrapped_number()) {
174
    out.unsafeGetTensorImpl()->set_wrapped_number(true);
175
  }
176
  return out;
177
}
178
c10::optional<at::Tensor> to_meta(const c10::optional<at::Tensor>& tensor) {
179
  if (tensor.has_value()) {
180
    return to_meta(*tensor);
181
  }
182
  return c10::nullopt;
183
}
184

185
std::vector<at::Tensor> to_meta(at::ITensorListRef t_list) {
186
  std::vector<at::Tensor> outs;
187
  outs.reserve(t_list.size());
188
  for (const auto& tensor : t_list) {
189
    outs.push_back(to_meta(tensor));
190
  }
191
  return outs;
192
}
193
"""
194

195

196
class default_args:
197
    node_base: str = "Node"
198
    node_base_hdr: Optional[str] = None
199
    shape_inference_hdr: str = "torch/csrc/lazy/core/shape_inference.h"
200
    tensor_class: str = "torch::lazy::LazyTensor"
201
    tensor_class_hdr: str = "torch/csrc/lazy/core/tensor.h"
202
    lazy_ir_generator: Type[GenLazyIR] = GenLazyIR
203
    native_func_definition_generator: Type[
204
        GenLazyNativeFuncDefinition
205
    ] = GenLazyNativeFuncDefinition
206
    backend_name: str = "TorchScript"
207

208

209
def main() -> None:
210
    parser = argparse.ArgumentParser(description="Generate Lazy Tensor backend files")
211
    parser.add_argument(
212
        "-s",
213
        "--source-yaml",
214
        "--source_yaml",
215
        help="path to source yaml file containing operator external definitions",
216
    )
217
    parser.add_argument("-o", "--output-dir", "--output_dir", help="output directory")
218
    parser.add_argument(
219
        "--dry-run", "--dry_run", type=bool, default=False, help="output directory"
220
    )
221
    parser.add_argument(
222
        "--impl-path",
223
        "--impl_path",
224
        type=str,
225
        default=None,
226
        help="path to the source C++ file containing kernel definitions",
227
    )
228
    parser.add_argument(
229
        "--gen-ts-lowerings",
230
        "--gen_ts_lowerings",
231
        action="store_true",
232
        help="Generate TorchScript lowerings in addition to Lazy IR and NativeFunctions",
233
    )
234
    parser.add_argument(
235
        "--node-base",
236
        "--node_base",
237
        type=str,
238
        default=default_args.node_base,
239
        help="Name of backend specific custom Lazy IR Node base class",
240
    )
241
    parser.add_argument(
242
        "--node-base-hdr",
243
        "--node_base_hdr",
244
        type=str,
245
        default=default_args.node_base_hdr,
246
        help="Path to header file defining custom Lazy IR Node base class",
247
    )
248
    parser.add_argument(
249
        "--shape-inference-hdr",
250
        "--shape_inference_hdr",
251
        type=str,
252
        default=default_args.shape_inference_hdr,
253
        help="Path to header file defining custom Lazy shape inference functions",
254
    )
255
    parser.add_argument(
256
        "--tensor-class",
257
        "--tensor_class",
258
        type=str,
259
        default=default_args.tensor_class,
260
        help="Name of backend specific custom Lazy Tensor class",
261
    )
262
    parser.add_argument(
263
        "--tensor-class-hdr",
264
        "--tensor_class_hdr",
265
        type=str,
266
        default=default_args.tensor_class_hdr,
267
        help="Path to header file defining custom Lazy Tensor class",
268
    )
269
    parser.add_argument(
270
        "--backend-name",
271
        "--backend_name",
272
        type=str,
273
        default=default_args.backend_name,
274
        help="Name of the backend to generate",
275
    )
276
    options = parser.parse_args()
277

278
    # Assumes that this file lives at PYTORCH_ROOT/torchgen/gen_backend_stubs.py
279
    torch_root = pathlib.Path(__file__).parent.parent.parent.absolute()
280
    aten_path = str(torch_root / "aten" / "src" / "ATen")
281
    lazy_ir_generator: Type[GenLazyIR] = default_args.lazy_ir_generator
282
    if options.gen_ts_lowerings:
283
        lazy_ir_generator = GenTSLazyIR
284
    native_func_definition_generator: Type[
285
        GenLazyNativeFuncDefinition
286
    ] = default_args.native_func_definition_generator
287

288
    run_gen_lazy_tensor(
289
        aten_path,
290
        options.source_yaml,
291
        options.output_dir,
292
        options.dry_run,
293
        options.impl_path,
294
        options.node_base,
295
        options.node_base_hdr,
296
        options.tensor_class,
297
        options.tensor_class_hdr,
298
        options.shape_inference_hdr,
299
        lazy_ir_generator,
300
        native_func_definition_generator,
301
        options.backend_name,
302
    )
303

304

305
def run_gen_lazy_tensor(
306
    aten_path: str,
307
    source_yaml: str,
308
    output_dir: str,
309
    dry_run: bool,
310
    impl_path: Optional[str],
311
    node_base: str = default_args.node_base,
312
    node_base_hdr: Optional[str] = default_args.node_base_hdr,
313
    tensor_class: str = default_args.tensor_class,
314
    tensor_class_hdr: str = default_args.tensor_class_hdr,
315
    shape_inference_hdr: str = default_args.shape_inference_hdr,
316
    lazy_ir_generator: Type[GenLazyIR] = default_args.lazy_ir_generator,
317
    native_func_definition_generator: Type[
318
        GenLazyNativeFuncDefinition
319
    ] = default_args.native_func_definition_generator,
320
    # build_in_tree is true for TS backend and affects include paths
321
    build_in_tree: bool = False,
322
    # per_operator_headers changes whether ATen/Functions.h or individual operator headers are used
323
    # it must match how ATen was built
324
    per_operator_headers: bool = False,
325
    backend_name: str = default_args.backend_name,
326
    gen_forced_fallback_code: bool = False,
327
    use_lazy_shape: bool = True,
328
    # the following arguments are temporary customization points for xla backend migration.
329
    # do not rely on them otherwise, they should be removed once migration is complete
330
    backend_namespace: str = "torch::lazy",
331
    get_tensorlist: str = "GetTensorList",
332
    get_tensor_or_wrap_number: str = "GetLtcTensorOrCreateForWrappedNumber",
333
    try_get_tensor: str = "TryGetLtcTensor",
334
    metrics_counter: str = 'TORCH_LAZY_FN_COUNTER("lazy::")',
335
    create_tensor: str = "LazyTensor::Create",
336
    create_from_first_tensor: bool = False,
337
    create_aten_from_ltc_tensor: str = "torch::lazy::CreateAtenFromLtcTensor",
338
    tuple_aten_from_ltc_tensors: str = "torch::lazy::TupleAtenFromLtcTensors",
339
    lazy_value_class: str = "torch::lazy::Value",
340
    lazy_tensor_ptr: str = "LazyTensorPtr",
341
    get_device_fn: str = "torch::lazy::GetBackendDevice",
342
) -> None:
343
    lv_tokens = lazy_value_class.split("::")
344
    lv_class = lv_tokens[-1]
345
    lv_ns = "::".join(lv_tokens[:-1])
346
    setValueT(BaseCppType(lv_ns, lv_class))
347
    template_dir = os.path.join(aten_path, "templates")
348

349
    def make_file_manager(install_dir: str) -> FileManager:
350
        return FileManager(
351
            install_dir=install_dir, template_dir=template_dir, dry_run=dry_run
352
        )
353

354
    fm = make_file_manager(output_dir)
355

356
    native_yaml_path = os.path.join(aten_path, "native/native_functions.yaml")
357
    tags_yaml_path = os.path.join(aten_path, "native/tags.yaml")
358
    parsed_yaml = parse_native_yaml(native_yaml_path, tags_yaml_path)
359
    native_functions, backend_indices = (
360
        parsed_yaml.native_functions,
361
        parsed_yaml.backend_indices,
362
    )
363
    grouped_native_functions = get_grouped_native_functions(native_functions)
364

365
    def sort_native_function(f: Union[NativeFunctionsGroup, NativeFunction]) -> str:
366
        """
367
        We sort the native function because of the note in concat_map_codegen.
368
        TODO(alanwaketan): Remove this sorting hack once all ops are grouped properly.
369
        """
370
        func = f.functional.func if isinstance(f, NativeFunctionsGroup) else f.func
371
        return str(func.name.name)
372

373
    grouped_native_functions = sorted(
374
        grouped_native_functions, key=sort_native_function
375
    )
376

377
    parsed_backend_yaml = parse_backend_yaml(
378
        source_yaml, grouped_native_functions, backend_indices
379
    )
380
    backend_key = parsed_backend_yaml.backend_key
381
    autograd_key = parsed_backend_yaml.autograd_key
382
    cpp_namespace = parsed_backend_yaml.cpp_namespace
383
    backend_indices = parsed_backend_yaml.backend_indices
384
    # the following 3 keys are all processed differently
385
    # for full_codegen, we generate IR, kernels, etc
386
    # for ir_gen, we generate only IR
387
    # non_native is used to register kernels not declared in
388
    # native_functions.yaml
389
    full_codegen, non_native, ir_gen = parse_native_functions_keys(
390
        source_yaml, grouped_native_functions
391
    )
392

393
    def concat_map_codegen(
394
        func: Callable[[NativeFunction], Sequence[str]],
395
        xs: Iterable[Union[NativeFunctionsGroup, NativeFunction]],
396
        ops_list: List[OperatorName] = full_codegen,
397
    ) -> Iterator[str]:
398
        """
399
        We code-gen for the functional variant, which is all we need for IR classes/lowerings/shape inferences, but we
400
        only code-gen additional entries for the inplace variant for the native functions.
401
        """
402

403
        for x in xs:
404
            fs = list(x.functions()) if isinstance(x, NativeFunctionsGroup) else [x]
405
            for f in fs:
406
                if f.func.name in ops_list:
407
                    yield from func(f)
408

409
    selector = SelectiveBuilder.get_nop_selector()
410

411
    assert backend_key is not None
412
    class_name = backend_indices[backend_key].native_function_class_name()
413

414
    if impl_path is not None:
415
        error_on_missing_kernels(
416
            native_functions,
417
            backend_indices,
418
            backend_key,
419
            autograd_key,
420
            class_name,
421
            impl_path,
422
            full_codegen,
423
        )
424

425
    """ Validate Shape Inference Definitions
426

427
    Generated lazy native functions all perform shape inference, by first using a meta:: kernel
428
    if available for that op, and otherwise using a 'compute_shape_{op}' function instead.  The generator
429
    knows the call signature for compute_shape_{op} because it matches the nativefunction (and meta::) signature,
430
    so it just has to check whether the op is structured and generate a call for one or the other.  It's up to the dev
431
    to supply the missing compute_shape_{op} function, but the codegen at least warns you about this and provides
432
    the expected signature which can be copy-pasted into shape_inference.h.
433

434
    compute_shape_{op} functions are handwritten and should be replaced over time as ops get ported
435
    to structured kernels.
436

437
    See torch/csrc/lazy/core/shape_inference.cpp #READ THIS! for more information.
438
    """
439
    if shape_inference_hdr is not None:
440
        expected_shape_infr_decls = list(
441
            concat_map_codegen(
442
                dest.GenLazyShapeInferenceDefinition(
443
                    backend_indices[backend_key], tensor_class
444
                ),
445
                grouped_native_functions,
446
            )
447
        )
448

449
        validate_shape_inference_header(shape_inference_hdr, expected_shape_infr_decls)
450
    assert class_name is not None
451

452
    # Generate nativefunction declarations
453
    # Note, eager registrations is set to False for the lazy TS backend as another LTC backend
454
    # may want to register their own lazy kernels instead of registering the TS ones.
455
    # The registration will lazily happen when init_ts_backend is called.
456
    gen_dispatchkey_nativefunc_headers(
457
        fm,
458
        class_name,
459
        cpp_namespace,
460
        backend_indices,
461
        grouped_native_functions,
462
        backend_key,
463
        autograd_key,
464
        backend_name,
465
    )
466

467
    # Generate Dispatcher registrations which hook up the nativefunctions
468
    for dispatch_key in (
469
        [backend_key] if autograd_key is None else [backend_key, autograd_key]
470
    ):
471
        gen_dispatcher_registrations(
472
            fm,
473
            output_dir,
474
            class_name,
475
            backend_indices,
476
            grouped_native_functions,
477
            backend_key,
478
            dispatch_key,
479
            selector,
480
            build_in_tree=build_in_tree,
481
            per_operator_headers=per_operator_headers,
482
            backend_name=backend_name,
483
            eager_registration=False,
484
        )
485

486
    # Generate native function impls that build IR nodes
487
    ns_helper = NamespaceHelper(cpp_namespace)
488
    fm.write_with_template(
489
        f"{backend_key}NativeFunctions.cpp",
490
        "DispatchKeyNativeFunctions.cpp",
491
        lambda: {
492
            "includes": [
493
                f"#include <{path}>"
494
                for path in [
495
                    tensor_class_hdr,
496
                    shape_inference_hdr,
497
                    "ATen/Functions.h",
498
                    "ATen/native/TensorConversions.h",
499
                    "ATen/NativeFunctions.h",
500
                    "ATen/CompositeExplicitAutogradNonFunctionalFunctions.h",
501
                    "ATen/MetaFunctions.h",
502
                    "ATen/Operators.h",
503
                    "ATen/native/CPUFallback.h",
504
                    "torch/csrc/lazy/core/ir_builder.h",
505
                    "torch/csrc/lazy/core/lazy_graph_executor.h",
506
                    "torch/csrc/lazy/core/metrics.h",
507
                    "torch/csrc/lazy/core/shape.h",
508
                    f"{output_dir}/{backend_key}NativeFunctions.h",
509
                    f"{output_dir}/LazyIr.h",
510
                ]
511
                + (
512
                    ["torch/csrc/lazy/ts_backend/ts_eager_fallback.h"]
513
                    if gen_forced_fallback_code
514
                    else []
515
                )
516
            ],
517
            "helper_fns": get_ltc_helper_fns(),
518
            "native_functions_include": "",
519
            "namespace_prologue": ns_helper.prologue,
520
            "namespace_epilogue": ns_helper.epilogue,
521
            "native_function_definitions": list(
522
                concat_map_codegen(
523
                    native_func_definition_generator(
524
                        f"{backend_key}NativeFunctions",
525
                        backend_indices[backend_key],
526
                        tensor_class,
527
                        gen_forced_fallback_code,
528
                        backend_namespace,
529
                        get_tensorlist,
530
                        get_tensor_or_wrap_number,
531
                        try_get_tensor,
532
                        metrics_counter,
533
                        create_tensor,
534
                        create_from_first_tensor,
535
                        create_aten_from_ltc_tensor,
536
                        tuple_aten_from_ltc_tensors,
537
                        lazy_tensor_ptr,
538
                        get_device_fn,
539
                    ),
540
                    grouped_native_functions,
541
                )
542
            ),
543
        },
544
    )
545
    # Generate IR node classes
546
    lazy_ir_obj = lazy_ir_generator(
547
        backend_indices[backend_key], backend_name, node_base, use_lazy_shape
548
    )
549

550
    fm.write_with_template(
551
        "LazyIr.h",
552
        "LazyIr.h",
553
        lambda: {
554
            "lazy_ir_sysinc": [
555
                f"#include <{path}>"
556
                for path in [
557
                    "ATen/core/Formatting.h",
558
                    "c10/core/ScalarType.h",
559
                    "c10/util/Optional.h",
560
                    "torch/csrc/lazy/core/hash.h",
561
                    "torch/csrc/lazy/core/ir.h",
562
                    "torch/csrc/lazy/core/shape.h",
563
                    "vector",
564
                ]
565
            ],
566
            "lazy_ir_inc": [f'#include "{node_base_hdr}"']
567
            if node_base_hdr is not None
568
            else [],
569
            "ir_declarations": list(
570
                concat_map_codegen(
571
                    lazy_ir_obj, grouped_native_functions, full_codegen + ir_gen
572
                )
573
            ),
574
            "namespace_prologue": ns_helper.prologue,
575
            "namespace_epilogue": ns_helper.epilogue,
576
        },
577
    )
578

579
    # Generate Non Native IR Node classes
580
    fm.write_with_template(
581
        "LazyNonNativeIr.h",
582
        "LazyNonNativeIr.h",
583
        lambda: {
584
            "lazy_non_native_ir_inc": [
585
                f"#include <{path}>"
586
                for path in [
587
                    "torch/csrc/lazy/core/ir.h",
588
                    "torch/csrc/lazy/core/ir_builder.h",
589
                    "torch/csrc/lazy/core/internal_ops/ltc_ops.h",
590
                    "torch/csrc/lazy/core/shape_inference.h",
591
                ]
592
                + ([node_base_hdr] if node_base_hdr else [])
593
                if path
594
            ],
595
            "non_native_ir_nodes": dest.generate_non_native_lazy_ir_nodes(
596
                non_native, lazy_ir_obj
597
            ),
598
            "namespace_prologue": ns_helper.prologue,
599
            "namespace_epilogue": ns_helper.epilogue,
600
        },
601
    )
602

603

604
if __name__ == "__main__":
605
    main()
606

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.