mirror of
https://github.com/intel/llvm.git
synced 2026-02-01 08:56:15 +08:00
Expose the result types of edsc::Expr, which are now stored for all types of
Exprs and not only for the variadic ones. Require return types when an Expr is
constructed, if it will ever have some. An empty return type list is
interpreted as an Expr that does not create a value (e.g. `return` or `store`).
Conceptually, all edss::Exprs are now typed, with the type being a (potentially
empty) tuple of return types. Unbound expressions and Bindables must now be
constructed with a specific type they will take. This makes EDSC less
evidently type-polymorphic, but we can still write generic code such as
Expr sumOfSquares(Expr lhs, Expr rhs) { return lhs * lhs + rhs * rhs; }
and use it to construct different typed expressions as
sumOfSquares(Bindable(IndexType::get(ctx)), Bindable(IndexType::get(ctx)));
sumOfSquares(Bindable(FloatType::getF32(ctx)),
Bindable(FloatType::getF32(ctx)));
On the positive side, we get the following.
1. We can now perform type checking when constructing Exprs rather than during
MLIR emission. Nevertheless, this is still duplicates the Op::verify()
until we can factor out type checking from that.
2. MLIREmitter is significantly simplified.
3. ExprKind enum is only used for actual kinds of expressions. Data structures
are converging with AbstractOperation, and the users can now create a
VariadicExpr("canonical_op_name", {types}, {exprs}) for any operation, even
an unregistered one without having to extend the enum and make pervasive
changes to EDSCs.
On the negative side, we get the following.
1. Typed bindables are more verbose, even in Python.
2. We lose the ability to do print debugging for higher-level EDSC abstractions
that are implemented as multiple MLIR Ops, for example logical disjunction.
This is the step 2/n towards making EDSC extensible.
***
Move MLIR Op construction from MLIREmitter::emitExpr to Expr::build since Expr
now has sufficient information to build itself.
This is the step 3/n towards making EDSC extensible.
Both of these strive to minimize the amount of irrelevant changes. In
particular, this introduces more complex pretty-printing for affine and binary
expression to make sure tests continue to pass. It also relies on string
comparison to identify specific operations that an Expr produces.
PiperOrigin-RevId: 234609882
51 lines
1.5 KiB
Python
51 lines
1.5 KiB
Python
"""Python3 test for the MLIR EDSC C API and Python bindings"""
|
|
|
|
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import print_function
|
|
|
|
import unittest
|
|
|
|
import google_mlir.bindings.python.pybind as E
|
|
|
|
|
|
class EdscTest(unittest.TestCase):
|
|
|
|
def testSugaredMLIREmission(self):
|
|
shape = [3, 4, 5, 6, 7]
|
|
shape_t = [7, 4, 5, 6, 3]
|
|
module = E.MLIRModule()
|
|
t = module.make_scalar_type("f32")
|
|
m = module.make_memref_type(t, shape)
|
|
m_t = module.make_memref_type(t, shape_t)
|
|
f = module.make_function("copy", [m, m_t], [])
|
|
|
|
with E.ContextManager():
|
|
emitter = E.MLIRFunctionEmitter(f)
|
|
input, output = list(map(E.Indexed, emitter.bind_function_arguments()))
|
|
lbs, ubs, steps = emitter.bind_indexed_view(input)
|
|
i, *ivs, j = list(
|
|
map(E.Expr,
|
|
[E.Bindable(module.make_index_type()) for _ in range(len(shape))
|
|
]))
|
|
|
|
# n-D type and rank agnostic copy-transpose-first-last (where n >= 2).
|
|
loop = E.Block([
|
|
E.For([i, *ivs, j], lbs, ubs, steps,
|
|
[output.store([i, *ivs, j], input.load([j, *ivs, i]))]),
|
|
E.Return()
|
|
])
|
|
emitter.emit_inplace(loop)
|
|
|
|
# print(f) # uncomment to see the emitted IR
|
|
str = f.__str__()
|
|
self.assertIn("load %arg0[%i4, %i1, %i2, %i3, %i0]", str)
|
|
self.assertIn("store %0, %arg1[%i0, %i1, %i2, %i3, %i4]", str)
|
|
|
|
module.compile()
|
|
self.assertNotEqual(module.get_engine_address(), 0)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|