blob: cdc7900d324bab81e7a3064743cd249ea3d098d1 [file] [log] [blame]
# Lint-as: python3
"""Core compiler interface."""
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from enum import Enum
import subprocess
from typing import Any, Dict, List, Optional, Sequence, Union
from .tools import *
__all__ = [
"DEFAULT_TESTING_BACKENDS",
"compile_file",
"compile_str",
"CompilerOptions",
"OutputFormat",
]
# Default testing backend for invoking the compiler.
DEFAULT_TESTING_BACKENDS = ["vmla"]
class OutputFormat(Enum):
"""The output format of the compiler."""
FLATBUFFER_BINARY = "flatbuffer-binary"
FLATBUFFER_TEXT = "flatbuffer-text"
MLIR_TEXT = "mlir-text"
@staticmethod
def parse(spec: Union[str, "OutputFormat"]) -> "OutputFormat":
"""Parses or returns an OutputFormat.
Args:
spec: An OutputFormat instance or the case-insensitive name of one of
the enum values.
Returns:
An OutputFormat instance.
"""
if isinstance(spec, OutputFormat):
return spec
spec = spec.upper()
if spec not in OutputFormat.__members__:
raise ValueError(f"For output_format= argument, expected one of: "
f"{', '.join(OutputFormat.__members__.keys())}")
return OutputFormat[spec]
class CompilerOptions:
"""Options to the compiler backend.
Keyword options:
output_file: Optionally save the compiled binary to a file instead of
returning it.
target_backends: List of str names of target backends to compile into
the binary. The resulting binary will run on targets that match one
or more of the compiled backends.
output_format: Override the output format. See the OutputFormat enum.
Values can either be an enum value or a case-insensitive name of
the option. Typically used for debugging
extra_args: Optional list of additional arguments to pass to the compiler.
Example: ["--print-ir-after-all"]
optimize: Whether to apply some default high level optimizations (default
True).
strip_debug_ops: Whether to strip high level operations used to aid
debugging.
strip_source_map: Whether to strip source map information (used to generate
better errors).
strip_symbols: Whether to strip extra symbols not needed for execution
(but which may aid debugging).
crash_reproducer_path: File name to output an MLIR crash dump to if there
is a compiler failure.
enable_benchmark: Whether to generate instrumented binaries suitable
for benchmarking.
"""
def __init__(self,
*,
output_file: Optional[str] = None,
target_backends: Sequence[str] = (),
output_format: Union[OutputFormat,
str] = OutputFormat.FLATBUFFER_BINARY,
extra_args: Sequence[str] = (),
optimize: bool = True,
strip_debug_ops: bool = False,
strip_source_map: bool = False,
strip_symbols: bool = False,
crash_reproducer_path: Optional[str] = None,
enable_benchmark: bool = False):
self.output_file = output_file
self.target_backends = target_backends
self.output_format = OutputFormat.parse(output_format)
self.extra_args = extra_args
self.optimize = optimize
self.strip_debug_ops = strip_debug_ops
self.strip_source_map = strip_source_map
self.strip_symbols = strip_symbols
self.crash_reproducer_path = crash_reproducer_path
self.enable_benchmark = enable_benchmark
def build_compile_command_line(input_file: str,
options: CompilerOptions) -> List[str]:
"""Builds a command line for invoking the compiler.
Args:
input_file: The input file name.
options: Compiler options.
Returns:
List of strings of command line.
"""
iree_translate = find_tool("iree-translate")
if not options.target_backends:
raise ValueError("Expected a non-empty list for 'target_backends'")
cl = [
iree_translate,
input_file,
f"--iree-vm-bytecode-module-output-format={options.output_format.value}",
f"--iree-hal-target-backends={','.join(options.target_backends)}",
]
# Output file.
if options.output_file:
cl.append(f"-o={options.output_file}")
# Translation to perform.
cl.append("--iree-mlir-to-vm-bytecode-module" if not options.enable_benchmark
else "--iree-mlir-to-executable-benchmark-vm-module")
# Other options to set if specified.
if options.strip_debug_ops:
cl.append("--iree-vm-bytecode-module-strip-debug-ops")
if options.strip_source_map:
cl.append("--iree-vm-bytecode-module-strip-source-map")
if options.strip_symbols:
cl.append("--iree-vm-bytecode-module-strip-symbols")
if options.crash_reproducer_path:
cl.append(
f"--pass-pipeline-crash-reproducer={options.crash_reproducer_path}")
cl.extend(options.extra_args)
return cl
def compile_file(input_file: str, **kwargs):
"""Invokes the IREE compiler on an input file.
Args:
input_file: File containing MLIR assembly to compile.
**kwargs: Keyword arguments corresponding to CompilerOptions.
Returns:
Either a byte buffer of the compiled content or None if output_file
was specified in the options.
"""
options = CompilerOptions(**kwargs)
cl = build_compile_command_line(input_file, options)
result = invoke_immediate(cl)
if options.output_file:
return None
return result
def compile_str(input_str: str, **kwargs):
"""Invokes the IREE compiler with an input string.
Args:
input_str: MLIR assembly to parse/compile.
**kwargs: Keyword arguments corresponding to CompilerOptions.
Returns:
Either a byte buffer of the compiled content or None if output_file
was specified in the options.
"""
options = CompilerOptions(**kwargs)
cl = build_compile_command_line("-", options)
result = invoke_immediate(cl, immediate_input=input_str.encode("utf-8"))
if options.output_file:
return None
return result