mirror of https://github.com/llvm/torch-mlir
Wire up IREE compilation and runtime in a new backend test.
* Adds python bindings for invoking flow, HAL, and VM lowering pipelines. * Adds pythong bindings for translating to VM module flatbuffer. * Adds a new backend_test/iree directory and configure lit to find the IREE python rt bindings. * Open code a simple_invoke.py that exercises the whole pipeline (need real APIs for a lot of this). * Fails when invoking the function because I never implemented argument marshaling for scalars :( * Plenty of stuff to do tomorrow.pull/1/head
parent
373878f31f
commit
529873d13c
|
@ -58,8 +58,9 @@ if(NPCOMP_ENABLE_IREE)
|
||||||
string(APPEND NPCOMP_TABLEGEN_ARGS "-DNPCOMP_ENABLE_IREE")
|
string(APPEND NPCOMP_TABLEGEN_ARGS "-DNPCOMP_ENABLE_IREE")
|
||||||
if(NPCOMP_IREE_SRCDIR)
|
if(NPCOMP_IREE_SRCDIR)
|
||||||
message(STATUS "Depending on IREE source: ${NPCOMP_IREE_SRCDIR}")
|
message(STATUS "Depending on IREE source: ${NPCOMP_IREE_SRCDIR}")
|
||||||
set(IREE_BUILD_TESTS OFF CACHE BOOL "Override IREE setting")
|
set(IREE_BUILD_TESTS OFF CACHE BOOL "Override IREE setting" FORCE)
|
||||||
set(IREE_BUILD_SAMPLES OFF CACHE BOOL "Override IREE setting")
|
set(IREE_BUILD_SAMPLES OFF CACHE BOOL "Override IREE setting" FORCE)
|
||||||
|
set(IREE_BUILD_PYTHON_BINDINGS ON CACHE BOOL "Override IREE setting" FORCE)
|
||||||
set(IREE_MLIR_DEP_MODE "DISABLED" CACHE STRING "Override IREE setting")
|
set(IREE_MLIR_DEP_MODE "DISABLED" CACHE STRING "Override IREE setting")
|
||||||
add_subdirectory("${NPCOMP_IREE_SRCDIR}" "iree" EXCLUDE_FROM_ALL)
|
add_subdirectory("${NPCOMP_IREE_SRCDIR}" "iree" EXCLUDE_FROM_ALL)
|
||||||
else()
|
else()
|
||||||
|
@ -99,3 +100,7 @@ add_subdirectory(pytest)
|
||||||
add_subdirectory(runtime)
|
add_subdirectory(runtime)
|
||||||
add_subdirectory(tools)
|
add_subdirectory(tools)
|
||||||
add_subdirectory(test)
|
add_subdirectory(test)
|
||||||
|
|
||||||
|
if(NPCOMP_ENABLE_IREE)
|
||||||
|
add_subdirectory(backend_test/iree)
|
||||||
|
endif()
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
configure_lit_site_cfg(
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py
|
||||||
|
MAIN_CONFIG
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/lit.cfg.py
|
||||||
|
)
|
||||||
|
|
||||||
|
set(NPCOMP_TEST_DEPENDS
|
||||||
|
FileCheck count not
|
||||||
|
npcomp-opt
|
||||||
|
NPCOMPNativePyExt
|
||||||
|
# TODO: Fix this so it has an IREE prefix
|
||||||
|
bindings_python_pyiree_rt_rt
|
||||||
|
# TODO: Why is this separate?
|
||||||
|
bindings_python_pyiree_rt_system_api
|
||||||
|
)
|
||||||
|
|
||||||
|
add_lit_testsuite(check-npcomp-backend-iree-lit "Running npcomp IREE tests"
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
DEPENDS ${NPCOMP_TEST_DEPENDS}
|
||||||
|
)
|
||||||
|
set_target_properties(check-npcomp-backend-iree-lit PROPERTIES FOLDER "Tests")
|
||||||
|
|
||||||
|
add_lit_testsuites(NPCOMP_PYTEST ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${NPCOMP_TEST_DEPENDS})
|
||||||
|
|
||||||
|
add_dependencies(check-npcomp check-npcomp-backend-iree-lit)
|
|
@ -0,0 +1,53 @@
|
||||||
|
# XFAIL: *
|
||||||
|
# RUN: %PYTHON %s
|
||||||
|
|
||||||
|
from npcomp.compiler.frontend import *
|
||||||
|
from npcomp.compiler.target import *
|
||||||
|
|
||||||
|
# TODO: This should all exist in a high level API somewhere.
|
||||||
|
from _npcomp import mlir
|
||||||
|
from _npcomp.backend import iree as ireec
|
||||||
|
|
||||||
|
from pyiree import rt
|
||||||
|
|
||||||
|
|
||||||
|
def compile_function(f):
|
||||||
|
fe = ImportFrontend(target_factory=GenericTarget32)
|
||||||
|
ir_f = fe.import_global_function(f)
|
||||||
|
|
||||||
|
input_m = fe.ir_module
|
||||||
|
# For easier debugging, split into to pass manager invocations.
|
||||||
|
pm = mlir.passes.PassManager(input_m.context)
|
||||||
|
# TOOD: Have an API for this
|
||||||
|
pm.addPassPipelines(
|
||||||
|
"basicpy-type-inference", "convert-basicpy-to-std", "canonicalize")
|
||||||
|
pm.run(input_m)
|
||||||
|
print("INPUT MODULE:")
|
||||||
|
print(input_m.to_asm())
|
||||||
|
|
||||||
|
# Main IREE compiler.
|
||||||
|
pm = mlir.passes.PassManager(input_m.context)
|
||||||
|
ireec.build_flow_transform_pass_pipeline(pm)
|
||||||
|
ireec.build_hal_transform_pass_pipeline(pm)
|
||||||
|
ireec.build_vm_transform_pass_pipeline(pm)
|
||||||
|
pm.run(input_m)
|
||||||
|
print("VM MODULE:")
|
||||||
|
print(input_m.to_asm())
|
||||||
|
|
||||||
|
# Translate to VM bytecode flatbuffer.
|
||||||
|
vm_blob = ireec.translate_to_vm_bytecode(input_m)
|
||||||
|
print("VM BLOB: len =", len(vm_blob))
|
||||||
|
return vm_blob
|
||||||
|
|
||||||
|
|
||||||
|
def int_add(a: int, b: int):
|
||||||
|
return a + b
|
||||||
|
|
||||||
|
vm_blob = compile_function(int_add)
|
||||||
|
m = rt.VmModule.from_flatbuffer(vm_blob)
|
||||||
|
config = rt.Config("vmla")
|
||||||
|
ctx = rt.SystemContext(config=config)
|
||||||
|
ctx.add_module(m)
|
||||||
|
|
||||||
|
f = ctx.modules.module.int_add
|
||||||
|
print(f(5, 6))
|
|
@ -0,0 +1,80 @@
|
||||||
|
# -*- Python -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
import lit.formats
|
||||||
|
import lit.util
|
||||||
|
|
||||||
|
from lit.llvm import llvm_config
|
||||||
|
from lit.llvm.subst import ToolSubst
|
||||||
|
from lit.llvm.subst import FindTool
|
||||||
|
|
||||||
|
# Configuration file for the 'lit' test runner.
|
||||||
|
|
||||||
|
# name: The name of this test suite.
|
||||||
|
config.name = 'NPCOMP_BACKEND_IREE'
|
||||||
|
|
||||||
|
config.test_format = lit.formats.ShTest(not llvm_config.use_lit_shell)
|
||||||
|
|
||||||
|
# suffixes: A list of file extensions to treat as test files.
|
||||||
|
config.suffixes = ['.mlir', '.py']
|
||||||
|
|
||||||
|
# test_source_root: The root path where tests are located.
|
||||||
|
config.test_source_root = os.path.dirname(__file__)
|
||||||
|
|
||||||
|
# test_exec_root: The root path where tests should be run.
|
||||||
|
config.test_exec_root = os.path.join(config.npcomp_obj_root, 'backend_test', 'iree')
|
||||||
|
|
||||||
|
config.substitutions.append(('%PATH%', config.environment['PATH']))
|
||||||
|
config.substitutions.append(('%shlibext', config.llvm_shlib_ext))
|
||||||
|
config.substitutions.append(('%PYTHON', config.python_executable))
|
||||||
|
|
||||||
|
llvm_config.with_system_environment(
|
||||||
|
['HOME', 'INCLUDE', 'LIB', 'NPCOMP_DEBUG', 'TMP', 'TEMP'])
|
||||||
|
|
||||||
|
llvm_config.use_default_substitutions()
|
||||||
|
|
||||||
|
# excludes: A list of files/directories to exclude from the testsuite. The
|
||||||
|
# 'Inputs'subdirectories contain auxiliary inputs for various tests in their
|
||||||
|
# parent directories.
|
||||||
|
config.excludes = [
|
||||||
|
'Inputs', 'Examples', 'lit.cfg.py', 'CMakeLists.txt', 'README.txt',
|
||||||
|
'LICENSE.txt'
|
||||||
|
]
|
||||||
|
|
||||||
|
# test_source_root: The root path where tests are located.
|
||||||
|
config.test_source_root = os.path.dirname(__file__)
|
||||||
|
|
||||||
|
# test_exec_root: The root path where tests should be run.
|
||||||
|
config.test_exec_root = os.path.join(config.npcomp_obj_root, 'backend_test', 'iree')
|
||||||
|
config.npcomp_tools_dir = os.path.join(config.npcomp_obj_root, 'tools')
|
||||||
|
config.npcomp_runtime_shlib = os.path.join(
|
||||||
|
config.npcomp_obj_root, 'runtime',
|
||||||
|
'libNPCOMPRuntime' + config.llvm_shlib_ext)
|
||||||
|
|
||||||
|
# Tweak the PATH and PYTHONPATH to include the tools dir.
|
||||||
|
llvm_config.with_environment('PATH', config.llvm_tools_dir, append_path=True)
|
||||||
|
llvm_config.with_environment('PYTHONPATH', [
|
||||||
|
os.path.join(config.npcomp_obj_root, "python"),
|
||||||
|
os.path.join(config.npcomp_obj_root, "python_native"),
|
||||||
|
os.path.join(config.npcomp_obj_root, "iree", "bindings", "python"),
|
||||||
|
],
|
||||||
|
append_path=True)
|
||||||
|
|
||||||
|
tool_dirs = [
|
||||||
|
os.path.join(config.npcomp_tools_dir, 'npcomp-opt'),
|
||||||
|
os.path.join(config.npcomp_tools_dir, 'npcomp-run-mlir'),
|
||||||
|
config.llvm_tools_dir,
|
||||||
|
]
|
||||||
|
tools = [
|
||||||
|
'npcomp-opt',
|
||||||
|
'npcomp-run-mlir',
|
||||||
|
ToolSubst('%npcomp_runtime_shlib', config.npcomp_runtime_shlib),
|
||||||
|
]
|
||||||
|
|
||||||
|
llvm_config.add_tool_substitutions(tools, tool_dirs)
|
|
@ -0,0 +1,49 @@
|
||||||
|
@LIT_SITE_CFG_IN_HEADER@
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
config.host_triple = "@LLVM_HOST_TRIPLE@"
|
||||||
|
config.target_triple = "@TARGET_TRIPLE@"
|
||||||
|
config.llvm_src_root = "@LLVM_SOURCE_DIR@"
|
||||||
|
config.llvm_obj_root = "@LLVM_BINARY_DIR@"
|
||||||
|
config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
|
||||||
|
config.llvm_lib_dir = "@LLVM_LIBRARY_DIR@"
|
||||||
|
config.llvm_shlib_dir = "@SHLIBDIR@"
|
||||||
|
config.llvm_shlib_ext = "@SHLIBEXT@"
|
||||||
|
config.llvm_exe_ext = "@EXEEXT@"
|
||||||
|
config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@"
|
||||||
|
config.python_executable = "@PYTHON_EXECUTABLE@"
|
||||||
|
config.gold_executable = "@GOLD_EXECUTABLE@"
|
||||||
|
config.ld64_executable = "@LD64_EXECUTABLE@"
|
||||||
|
config.enable_shared = @ENABLE_SHARED@
|
||||||
|
config.enable_assertions = @ENABLE_ASSERTIONS@
|
||||||
|
config.targets_to_build = "@TARGETS_TO_BUILD@"
|
||||||
|
config.native_target = "@LLVM_NATIVE_ARCH@"
|
||||||
|
config.llvm_bindings = "@LLVM_BINDINGS@".split(' ')
|
||||||
|
config.host_os = "@HOST_OS@"
|
||||||
|
config.host_cc = "@HOST_CC@"
|
||||||
|
config.host_cxx = "@HOST_CXX@"
|
||||||
|
# Note: ldflags can contain double-quoted paths, so must use single quotes here.
|
||||||
|
config.host_ldflags = '@HOST_LDFLAGS@'
|
||||||
|
config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@"
|
||||||
|
config.llvm_host_triple = '@LLVM_HOST_TRIPLE@'
|
||||||
|
config.host_arch = "@HOST_ARCH@"
|
||||||
|
config.npcomp_src_root = "@CMAKE_SOURCE_DIR@"
|
||||||
|
config.npcomp_obj_root = "@CMAKE_BINARY_DIR@"
|
||||||
|
|
||||||
|
# Support substitution of the tools_dir with user parameters. This is
|
||||||
|
# used when we can't determine the tool dir at configuration time.
|
||||||
|
try:
|
||||||
|
config.llvm_tools_dir = config.llvm_tools_dir % lit_config.params
|
||||||
|
config.llvm_shlib_dir = config.llvm_shlib_dir % lit_config.params
|
||||||
|
except KeyError:
|
||||||
|
e = sys.exc_info()[1]
|
||||||
|
key, = e.args
|
||||||
|
lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key))
|
||||||
|
|
||||||
|
|
||||||
|
import lit.llvm
|
||||||
|
lit.llvm.initialize(lit_config, config)
|
||||||
|
|
||||||
|
# Let the main config do the real work.
|
||||||
|
lit_config.load_config(config, "@CMAKE_SOURCE_DIR@/backend_test/iree/lit.cfg.py")
|
|
@ -295,6 +295,8 @@ def Basicpy_UnknownCastOp : Basicpy_Op<"unknown_cast", [NoSideEffect]> {
|
||||||
let arguments = (ins AnyType:$operand);
|
let arguments = (ins AnyType:$operand);
|
||||||
let results = (outs AnyType:$result);
|
let results = (outs AnyType:$result);
|
||||||
let assemblyFormat = "operands attr-dict `:` type(operands) `->` type(results)";
|
let assemblyFormat = "operands attr-dict `:` type(operands) `->` type(results)";
|
||||||
|
|
||||||
|
let hasCanonicalizer = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // NPCOMP_DIALECT_BASICPY_IR_BASICPY_OPS
|
#endif // NPCOMP_DIALECT_BASICPY_IR_BASICPY_OPS
|
||||||
|
|
|
@ -31,6 +31,7 @@ public:
|
||||||
/// Defines an "iree" module with backend support definitions.
|
/// Defines an "iree" module with backend support definitions.
|
||||||
void mlir::npcomp::python::defineBackendIREEModule(py::module m) {
|
void mlir::npcomp::python::defineBackendIREEModule(py::module m) {
|
||||||
py::class_<Blob>(m, "Blob", py::buffer_protocol())
|
py::class_<Blob>(m, "Blob", py::buffer_protocol())
|
||||||
|
.def("__len__", [](Blob &self) { return self.contents.size(); })
|
||||||
.def_buffer([](Blob &self) -> py::buffer_info {
|
.def_buffer([](Blob &self) -> py::buffer_info {
|
||||||
return py::buffer_info(
|
return py::buffer_info(
|
||||||
static_cast<void *>(&self.contents.front()), // Pointer to buffer
|
static_cast<void *>(&self.contents.front()), // Pointer to buffer
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "mlir/IR/Builders.h"
|
#include "mlir/IR/Builders.h"
|
||||||
#include "mlir/IR/FunctionImplementation.h"
|
#include "mlir/IR/FunctionImplementation.h"
|
||||||
#include "mlir/IR/OpImplementation.h"
|
#include "mlir/IR/OpImplementation.h"
|
||||||
|
#include "mlir/IR/PatternMatch.h"
|
||||||
#include "npcomp/Dialect/Basicpy/IR/BasicpyDialect.h"
|
#include "npcomp/Dialect/Basicpy/IR/BasicpyDialect.h"
|
||||||
|
|
||||||
#include "npcomp/Dialect/Basicpy/IR/BasicpyOpsEnums.cpp.inc"
|
#include "npcomp/Dialect/Basicpy/IR/BasicpyOpsEnums.cpp.inc"
|
||||||
|
@ -192,6 +193,31 @@ OpFoldResult StrConstantOp::fold(ArrayRef<Attribute> operands) {
|
||||||
return valueAttr();
|
return valueAttr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// UnknownCastOp
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class ElideIdentityUnknownCast : public OpRewritePattern<UnknownCastOp> {
|
||||||
|
public:
|
||||||
|
using OpRewritePattern::OpRewritePattern;
|
||||||
|
LogicalResult matchAndRewrite(UnknownCastOp op,
|
||||||
|
PatternRewriter &rewriter) const {
|
||||||
|
if (op.operand().getType() != op.result().getType())
|
||||||
|
return failure();
|
||||||
|
rewriter.replaceOp(op, op.operand());
|
||||||
|
return success();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void UnknownCastOp::getCanonicalizationPatterns(
|
||||||
|
OwningRewritePatternList &patterns, MLIRContext *context) {
|
||||||
|
patterns.insert<ElideIdentityUnknownCast>(context);
|
||||||
|
}
|
||||||
|
|
||||||
#define GET_OP_CLASSES
|
#define GET_OP_CLASSES
|
||||||
#include "npcomp/Dialect/Basicpy/IR/BasicpyOps.cpp.inc"
|
#include "npcomp/Dialect/Basicpy/IR/BasicpyOps.cpp.inc"
|
||||||
} // namespace Basicpy
|
} // namespace Basicpy
|
||||||
|
|
|
@ -224,17 +224,26 @@ void PyDialectHelper::bind(py::module m) {
|
||||||
py::arg("attrs") = llvm::Optional<PyAttribute>())
|
py::arg("attrs") = llvm::Optional<PyAttribute>())
|
||||||
.def("func_op",
|
.def("func_op",
|
||||||
[](PyDialectHelper &self, const std::string &name, PyType type,
|
[](PyDialectHelper &self, const std::string &name, PyType type,
|
||||||
bool createEntryBlock) {
|
bool createEntryBlock, llvm::Optional<PyAttribute> attrs) {
|
||||||
auto functionType = type.type.dyn_cast_or_null<FunctionType>();
|
auto functionType = type.type.dyn_cast_or_null<FunctionType>();
|
||||||
if (!functionType) {
|
if (!functionType) {
|
||||||
throw py::raiseValueError("Illegal function type");
|
throw py::raiseValueError("Illegal function type");
|
||||||
}
|
}
|
||||||
OpBuilder &opBuilder = self.pyOpBuilder.getBuilder(true);
|
OpBuilder &opBuilder = self.pyOpBuilder.getBuilder(true);
|
||||||
Location loc = self.pyOpBuilder.getCurrentLoc();
|
Location loc = self.pyOpBuilder.getCurrentLoc();
|
||||||
// TODO: Add function and arg/result attributes.
|
// TODO: Dedup attr creation from op().
|
||||||
|
MutableDictionaryAttr attrList;
|
||||||
|
if (attrs) {
|
||||||
|
auto dictAttrs = attrs->attr.dyn_cast<DictionaryAttr>();
|
||||||
|
if (!dictAttrs) {
|
||||||
|
throw py::raiseValueError(
|
||||||
|
"Expected `attrs` to be a DictionaryAttr");
|
||||||
|
}
|
||||||
|
attrList = MutableDictionaryAttr(dictAttrs);
|
||||||
|
}
|
||||||
FuncOp op =
|
FuncOp op =
|
||||||
opBuilder.create<FuncOp>(loc, StringRef(name), functionType,
|
opBuilder.create<FuncOp>(loc, StringRef(name), functionType,
|
||||||
/*attrs=*/ArrayRef<NamedAttribute>());
|
/*attrs=*/attrList.getAttrs());
|
||||||
if (createEntryBlock) {
|
if (createEntryBlock) {
|
||||||
Block *entryBlock = new Block();
|
Block *entryBlock = new Block();
|
||||||
entryBlock->addArguments(functionType.getInputs());
|
entryBlock->addArguments(functionType.getInputs());
|
||||||
|
@ -245,6 +254,7 @@ void PyDialectHelper::bind(py::module m) {
|
||||||
},
|
},
|
||||||
py::arg("name"), py::arg("type"),
|
py::arg("name"), py::arg("type"),
|
||||||
py::arg("create_entry_block") = false,
|
py::arg("create_entry_block") = false,
|
||||||
|
py::arg("attrs") = llvm::Optional<PyAttribute>(),
|
||||||
R"(Creates a new `func` op, optionally creating an entry block.
|
R"(Creates a new `func` op, optionally creating an entry block.
|
||||||
If an entry block is created, the builder will be positioned
|
If an entry block is created, the builder will be positioned
|
||||||
to its start.)")
|
to its start.)")
|
||||||
|
@ -507,7 +517,10 @@ void PyContext::bind(py::module m) {
|
||||||
return createDenseElementsAttrFromBuffer(&self.context,
|
return createDenseElementsAttrFromBuffer(&self.context,
|
||||||
array_info);
|
array_info);
|
||||||
},
|
},
|
||||||
py::arg("array"));
|
py::arg("array"))
|
||||||
|
.def_property_readonly("unit_attr", [](PyContext &self) -> PyAttribute {
|
||||||
|
return UnitAttr::get(&self.context);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
PyModuleOp PyContext::parseAsm(const std::string &asm_text) {
|
PyModuleOp PyContext::parseAsm(const std::string &asm_text) {
|
||||||
|
|
|
@ -105,7 +105,12 @@ class ImportFrontend:
|
||||||
h.builder.set_file_line_col(filename_ident, ast_fd.lineno,
|
h.builder.set_file_line_col(filename_ident, ast_fd.lineno,
|
||||||
ast_fd.col_offset)
|
ast_fd.col_offset)
|
||||||
h.builder.insert_before_terminator(ir_m.first_block)
|
h.builder.insert_before_terminator(ir_m.first_block)
|
||||||
ir_f = h.func_op(ast_fd.name, ir_f_type, create_entry_block=True)
|
# TODO: Do not hardcode this IREE attribute.
|
||||||
|
attrs = ir_c.dictionary_attr({"iree.module.export": ir_c.unit_attr})
|
||||||
|
ir_f = h.func_op(ast_fd.name,
|
||||||
|
ir_f_type,
|
||||||
|
create_entry_block=True,
|
||||||
|
attrs=attrs)
|
||||||
fctx = FunctionContext(ir_c=ir_c,
|
fctx = FunctionContext(ir_c=ir_c,
|
||||||
ir_f=ir_f,
|
ir_f=ir_f,
|
||||||
ir_h=h,
|
ir_h=h,
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
// RUN: npcomp-opt -split-input-file %s | npcomp-opt -canonicalize | FileCheck --dump-input=fail %s
|
||||||
|
|
||||||
|
// CHECK-LABEL: func @unknown_cast_elide
|
||||||
|
func @unknown_cast_elide(%arg0 : i32) -> i32 {
|
||||||
|
// CHECK-NOT: basicpy.unknown_cast
|
||||||
|
%0 = basicpy.unknown_cast %arg0 : i32 -> i32
|
||||||
|
return %0 : i32
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: func @unknown_cast_preserve
|
||||||
|
func @unknown_cast_preserve(%arg0 : i32) -> !basicpy.UnknownType {
|
||||||
|
// CHECK: basicpy.unknown_cast
|
||||||
|
%0 = basicpy.unknown_cast %arg0 : i32 -> !basicpy.UnknownType
|
||||||
|
return %0 : !basicpy.UnknownType
|
||||||
|
}
|
Loading…
Reference in New Issue