Extract common code from getAffineSymbolExpr and getAffineConstantExpr into a
utility function safeGetOrCreate, similarly to the existing overloads for sets
and maps. The position in the vector is used as indexing key. NFC.
--
PiperOrigin-RevId: 244820859
LLVM Orc JIT changed the API for DynamicLibrarySearchGenerator::
GetForCurrentProcess to only take one value of the DataLayout that it actually
uses instead of the whole data layout. Update MLIR ExecutionEngine call to
this function accordingly.
--
PiperOrigin-RevId: 244820235
Note that I broke this out as a separate pass because intermediate transformations often produce qcast/dcast ops that are integral to the transformation, and it is typical to want to lower any remaining, unmatched casts at the end of quantization. If this flexibility ends up not being needed, they can be collapsed into the same pass. This is included in the same cpp file because all of the math ops will need to defer to emitting quantize/dequantize logic for cases that they cannot be fully lowered to fixed-point math.
Also, the new convertistof op needs to be evaluated for inclusion in StandardOps.
--
PiperOrigin-RevId: 244768679
During the pattern rewrite, if the function is changed, i.e. ops created,
deleted or swapped, the pattern rewriter needs to re-scan the function entirely
and apply the patterns again, so the patterns whose root ops have been popped
out from the working list nor an immediate users of the changed ops can be
reconsidered.
A command line flag is added to set the max number of iterations rescanning the
function for pattern match. If the rewrite doesn' converge after this number,
this compiling will continue and the result can be sub-optimal.
One unit test is updated because this change fixed the missing optimization opportunities.
--
PiperOrigin-RevId: 244754190
An op can have multiple results. Being explicit that we are binding to the
whole op instead of one of the results. A way to bind to a specific result
is yet to come.
--
PiperOrigin-RevId: 244741137
Both cOp and tAttr were used to perform some native C++ code expression.
Unifying them simplifies the concepts and reduces cognitive burden.
--
PiperOrigin-RevId: 244731946
This allows accessing those bound source ops in result patterns, which can be
useful for invoking native C++ op creation.
We bind the op entirely here because ops can have multiple results. Design a
approach to bind to a specific result is not the concern of this commit.
--
PiperOrigin-RevId: 244724750
The per-layer format is now like:
!quant.uniform<i8<-8:7>:f32, 9.987200e-01:127>
and per-axis is:
!quant.uniform<i8:f32:1, {2.0e+2,0.99872:120}>
I used the following sed script to update the unit tests (invoked with commands like `sed -i -r -f fix_quant.sed $(find . -name '*.mlir')`).
---
# Per-layer
s|\!quant<"uniform\[([iu][0-9]+):([fb]+[0-9]+)\]\{([^\}]+)\}\s*">|!quant.uniform<\1:\2, \3>|g
s|\!quant<"uniform\[([iu][0-9]+)\(([^\)]+)\):([fb]+[0-9]+)\]\{([^\}]+)\}\s*">|!quant.uniform<\1<\2>:\3, \4>|g
# Per-axis
s|\!quant<"uniform\[([iu][0-9]+):([fb]+[0-9]+)(:[0-9]+)?\]\{([^\}]+)\}\s*">|!quant.uniform<\1:\2\3, {\4}>|g
s|\!quant<"uniform\[([iu][0-9]+)\(([^\)]+)\):([fb]+[0-9]+)(:[0-9]+)?\]\{([^\}]+)\}\s*">|!quant.uniform<\1<\2>:\3\4, {\5}>|g
---
I fixed up the one file of error cases manually.
Since this is a one time syntax fix, I am not persisting the script anywhere.
--
PiperOrigin-RevId: 244425331
This CL adds a linalg.slice op with the proper roundtripping test.
A slice op allows taking subviews that may be rank-reducing (if some indexing is of index type) or not (if all indexings are of linalg.range type).
A slice must be constructed directly from a base view (no chains of slices may exist in the IR). Helper functions that fold will be provided for construction if/when necessary.
This also renames base_view to view.
--
PiperOrigin-RevId: 244406827
This CL adds a linalg.view<?x?xf32> type and base_view op with the proper roundtripping test. The parser will be improved in a subsequent CL once portions of the mlir::Parser are exposed.
For now this only supports dynamic views, static views will be introduced at a later time when they are needed.
--
PiperOrigin-RevId: 244374180
This also does the following:
- Removes the poc POT add implementation in favor of a version that does not rescale.
- Adds a handful of FxpMathOps which are needed (these are for comment and we may want to move them to the StandardOps dialect).
- Adds a canonicalizer to the StorageCastOp, which removes some cruft once conversions have been done.
- Adds a couple of predicates to OpBase.
--
PiperOrigin-RevId: 244287706
This CL starts implementing a Linalg dialect with the objective of supporting
optimizing compilation of loops and library calls for a subset of common linear
algebra operations.
This CL starts by simply adding a linalg.range type and an operation with the
proper roundtripping test.
--
PiperOrigin-RevId: 244189468
This CL also moved the UniformSupport.cpp and FakeQuantSupport.cpp into utils because they are not really the core of the IR.
--
PiperOrigin-RevId: 244001666
The description of the backward slice analysis behavior describes what would happen when creating a backward slice from node 9, not 8.
--
PiperOrigin-RevId: 243876599
For ops with the SameValueType trait, we generate a builder without requiring
result type; we get the result type from the operand. However, if the operand
is variadic, we need to index into the first value in the pack.
--
PiperOrigin-RevId: 243866647
other characters within the <>'s now that we can. This will allow quantized
types to use the pretty syntax (among others) after a few changes.
--
PiperOrigin-RevId: 243521268
There are no empty lines in output for three of these directives so removed
them and replaced the remaining one with 'CHECK-NOT:' as otherwise it is
failing with the following error.
error: found 'CHECK-EMPTY' without previous 'CHECK: line
TESTED = n/a
PiperOrigin-RevId: 243288605
Now, op attribute names don't have '.' in their names so the special handling for it
can be removed. Attributes for functions still have dialect prefix with '.' as separator but TableGen does not deal with functions.
TESTED with existing unit tests
--
PiperOrigin-RevId: 243287462
Iterators for a `llvm::DenseMap` can be invalidated when an insertion occurs.
In Pattern's `collectBoundArguments()`, we recursively handle all nested DAG
nodes and grow the the `RecordOperatorMap`, while retaining a reference.
This can cause the reference to be invalid and the program to behave randomly.
Allocate each `Operator` object specifically to solve this issue.
Also, `llvm::DenseMap` is a great way to map pointers to pointers, or map
other small types to each other. This avoids placing the `Operator` object
directly into the map.
--
PiperOrigin-RevId: 243281486
This CL changes various predicates and rewrite rules to use $-placeholders and
`tgfmt` as the driver for substitution. This will make the predicates and rewrite
rules more consistent regarding their arguments and more readable.
--
PiperOrigin-RevId: 243250739
Currently predicates are written with positional placeholders `{N}` and rely on
`formatv` as the engine to do substitution. The problem with this approach is that
the definitions of those positional placeholders are not consistent; they are
entirely up to the defining predicate of question. For example, `{0}` in various
attribute constraints is used to mean the attribute, while it is used to main the
builder for certain attribute transformations. This can become very confusing.
This CL introduces `tgfmt` as a new mechanism to better support for predicate and
rewrite rule specification. Instead of entirely relying on positional placeholders,
`tgfmt` support both positional and special placeholders. The former is used for
DAG operands. The latter, including $_builder, $_op, $_self, are used as special
"hooks" to entities in the context. With this, the predicate and rewrite rules
specification can be more consistent is more readable.
--
PiperOrigin-RevId: 243249671
Recently a default implementation for `match()` was provided (cl/242285885), but the class documentation wasn't updated appropriately.
--
PiperOrigin-RevId: 243128738
This allows client to be able to reuse the same logic to setup a module
for the ExecutionEngine without instanciating one. One use case is running
the optimization pipeline but not JIT-ing.
--
PiperOrigin-RevId: 242614380
When an op in the source pattern specifies more arguments than its definition, we
will have out-of-bound query for op arguments from the definition. That will cause
crashes. This change fixes it.
--
PiperOrigin-RevId: 242548415
TensorContractionBase has become too unwieldy with all the CRTP manipulation once less trivial transformations are implemented.
This CL drops CRTP for inheritance and uses the same name comparison trick to figure out what to cast into.
As a byproduct, all the -inl.h files disappear.
To maintain the separation between directories, a LINALG_STEP variable is introduced
--
PiperOrigin-RevId: 242546977
This adds parsing, printing and some folding/canonicalization.
Also extends rewriting of subi %0, %0 to handle vectors and tensors.
--
PiperOrigin-RevId: 242448164
This dialect does not have a global constructor and has to be registered
manually in `main`. Also fix the way it is exercised in the test.
--
PiperOrigin-RevId: 242434886
For some reason, the OSS build on macOS was not happy with the initialization
syntax and was attempting to call a copy constructor. Hotfix it to use a
different syntax pending further investigation.
--
PiperOrigin-RevId: 242432634
This is only teaching the LLVM converter to propagate the attribute onto
the function type. MLIR will not recognize this arguments, so it would only
be useful when calling for example `printf` with the same arguments across
a module. Since varargs is part of the ABI lowering, this is not NFC.
--
PiperOrigin-RevId: 242382427
making the IR dumps much nicer.
This is part 2/3 of the path to making dialect types more nice. Part 3/3 will
slightly generalize the set of characters allowed in pretty types and make it
more principled.
--
PiperOrigin-RevId: 242249955
restricted grammar. This will make certain common types much easier to read.
This is part tensorflow/mlir#1 of 2, which allows us to accept the new syntax. Part 2 will
change the asmprinter to automatically use it when appropriate, which will
require updating a bunch of tests.
This is motivated by the EuroLLVM tutorial and cleaning up the LLVM dialect aesthetics a bit more.
--
PiperOrigin-RevId: 242234821
Remove undesigned/unimplemented operations: reshape and view.
Add new LangRefDeletions.md file in /experimental to store things removed from public LangRef.md
PiperOrigin-RevId: 242230200
* dyn_cast_or_null
- This will first check if the operation is null before trying to 'dyn_cast':
Value *v = ...;
if (auto forOp = dyn_cast_or_null<AffineForOp>(v->getDefiningOp()))
...
* isa_nonnull
- This will first check if the pointer is null before trying to 'isa':
Value *v = ...;
if (isa_nonnull<AffineForOp>(v->getDefiningOp());
...
--
PiperOrigin-RevId: 242171343
Use MLIR's ExecutionEngine to demonstrate how one can implement a simple
JIT-compiler and executor after fully lowering the Linalg dialect to the LLVM
IR dialect, using the direct conversion (not going through standard
loads/stores).
--
PiperOrigin-RevId: 242127690
The existing implementation of the ExecutionEngine unconditionally runs a list
of "default" MLIR passes on the module upon creation. These passes include,
among others, dialect conversions from affine to standard and from standard to
LLVM IR dialects. In some cases, these conversions might have been performed
before ExecutionEngine is created. More advanced use cases may be performing
additional transformations that the "default" passes will conflict with.
Provide an overload for ExecutionEngine::create that takes a PassManager
configured with the passes to run on the module. If it is not provided, do not
run any passes. The engine will not be created if the input module, after the
pass manager, has any other dialect than the LLVM IR dialect.
--
PiperOrigin-RevId: 242127393
To support automatically constraint composition of ArrayAttr, a new
predicate combiner, Concat, is introduced. It prepends a prefix and
appends a postfix to a child predicate's final predicate string.
--
PiperOrigin-RevId: 242121186
This CL adds declarative tiling support in the linalg dialect by providing:
1. loop tiling on linalg ops by simply calling into mlir::tile
2. view tiling on linalg ops by:
a. computing the subview between for each tile dimension based on the loop tile size and the mapping of loops to operand ranges.
b. declaring that the tiled form of a tensorcontraction is the same tensorcontraction on subviews, which essentially gives us a recursive form.
Point 2.b is potentially subject to change in the future.
--
PiperOrigin-RevId: 242058658
This CL adds the last bit to convert from linalg.LoadOp and linalg.StoreOp to the affine dialect, as well as a unit test to exercise the conversion.
--
PiperOrigin-RevId: 242045826
As part of this cleanup, NOperands<0>::Impl and NOperands<1>::Impl are typedef'd to ZeroOperands and OneOperand respectively.
--
PiperOrigin-RevId: 242027189
Note: This now means that we cannot fold chains of operations, i.e. where constant foldable operations feed into each other. Given that this is a testing pass solely for constant folding, this isn't really something that we want anyways. Constant fold tests should be simple and direct, with more advanced folding/feeding being tested with the canonicalizer.
--
PiperOrigin-RevId: 242011744
There are two places containing constant folding logic right now: the ConstantFold
pass and the GreedyPatternRewriteDriver. The logic was not shared and started to
drift apart. We were testing constant folding logic using the ConstantFold pass,
but lagged behind the GreedyPatternRewriteDriver, where we really want the constant
folding to happen.
This CL pulled the logic into utility functions and classes for sharing between
these two places. A new ConstantFoldHelper class is created to help constant fold
and de-duplication.
Also, renamed the ConstantFold pass to TestConstantFold to make it clear that it is
intended for testing purpose.
--
PiperOrigin-RevId: 241971681
Previously, attribute constraints are basically unused: we set true for almost
anything. This CL refactors common attribute kinds and sets constraints on
them properly. And fixed verification failures found by this change.
A noticeable one is that certain TF ops' attributes are required to be 64-bit
integer, but the corresponding TFLite ops expect 32-bit integer attributes.
Added bitwidth converters to handle this difference.
--
PiperOrigin-RevId: 241944008
We can bind symbols to op arguments/results in source pattern and op results in
result pattern. Previously resolving these symbols is scattered across
RewriterGen.cpp. This CL aggregated them into a `PatternSymbolResolver` class.
While we are here, this CL also cleans up tests for patterns to make them more
focused. Specifically, one-op-one-result.td is superseded by pattern.td;
pattern-tAttr.td is simplified; pattern-bound-symbol.td is added for the change
in this CL.
--
PiperOrigin-RevId: 241913973
Previously we bundle the existence check and the MLIR attribute kind check
in one call. Further constraints (like element bitwidth) have to be split
into following checks. That is not a nice separation given that we have more
checks for constraints. Instead, this CL changes to generate a local variable
for every attribute, check its existence first, then check the constraints.
Creating a local variable for each attribute also avoids querying it multiple
times using the raw getAttr() API. This is a win for both performance the
readability of the generated code.
This CL also changed the error message to be more greppable by delimiting
the error message from constraints with boilerplate part with colon.
--
PiperOrigin-RevId: 241906132
Load and Store Linalg operations are converter to their LLVM IR counterparts
preceded by a sequence of operations that recover the effective address of the
accessed element. The address is computed given the subscripts and the view
descriptor as
base_pointer + base_offset + SUM_i subscript_i * stride_i.
Manual testing shows that the resulting LLVM IR for the matrix multiplication
example can be compiled and executed, producing correct results.
--
PiperOrigin-RevId: 241889003
Mainly a missing dependency caused the tests to pass if one already built
the repo, but not from a clean (or incremental) build.
--
PiperOrigin-RevId: 241852313
- Retains Quantization types and predicates.
- Retains utilities and example (testable) passes/ops.
- Retains unit tests for example passes/ops.
- Moves fixed point ops (and corresponding real ops) to FxpMathOps.
- Moves real -> fixed point pass to FxpMathOps.
- Sever the dependency on the TF dialect from Quantization. These dialects should now be open-sourcable.
--
PiperOrigin-RevId: 241825598
Currently, we only make the initial address aligned with 64-bit address but
allocate the buffer with the real size. This can cause issue when we extract
the value by the `readBits` method, which needs to read the memory in the
granularity of APINT_WORD_SIZE. In this CL, we rounded the allocation size to
the multiplies of APINT_WORD_SIZE to fix the issue.
--
PiperOrigin-RevId: 241816656
This CL adds support for lowering tensor contractions to loops declaratively.
This is done thanks to two properties of the such operations:
1. the definition of an AffineMap getLoopsToOperandRangesMap for each op which maps iteration space dimensions to ranges of the view operands, in their order of occurrence;
2. the definition of a scalar implementation for each op which creates the computation inside the loops given enclosing parallel and reduction loops,
All the other properties are derived in a generic fashion from these 2 properties and a few analyses.
A lowerToLoops transformation is added as well as a test that exercises it.
--
PiperOrigin-RevId: 241783992
This CL looses the requirement that all result patterns in a rewrite rule must
replace a result of the root op in the source pattern. Now only the last N
result pattern-generated ops are used to replace a N-result source op.
This allows to generate additional ops to aid building up final ops used to
replace the source op.
--
PiperOrigin-RevId: 241783192
Includes a draft of documentation for the quantization setup.
Given how many comments such docs have garnered in the past, I've biased towards a lightly edited first-draft so that people can argue about terminology, approach and structure without having spent too much time on it.
Note that the sections under "Uniform quantization" were cribbed nearly verbatim from internal documentation that Daniel wrote.
PiperOrigin-RevId: 241768668
OptionalAttr is just wrapping around the actual attribute; so it should just use
the actual attribute's `convertFromStorage` to read the value and wrap it around
with `Optional<>` to return. Previously it was mandating how the actual attribute
reads the value with `{0}.getValue()`.
--
PiperOrigin-RevId: 241762355
Implement conversion from the Linalg dialect to the LLVM dialect using a simple
set of DialectOpConverters and by plugging them into the dialect conversion
infrastructure. View and Range Linalg types are converted into descriptors
that store the dynamic values in an LLVM aggregate type, similarly to memrefs.
Slice operations create new descriptors based on the original descriptors and
thus remove the constraint on ViewTypes not being acceptable as function
arguments.
--
PiperOrigin-RevId: 241760189
Attributes can have default values or be optional. Checking the validity of
attributes in aggregate builder should consider that. And to be accurate,
we should check all required attributes are indeed provided in the list.
This is actually duplicating the work done by verifier. Checking the validity
of attributes should be the responsiblity of verifiers. This CL removes
the assertion for attributes in aggregate builders for the above reason.
(Assertions for operands/results are still kept since they are trivial.)
Also added more tests for aggregate builders.
--
PiperOrigin-RevId: 241746059
Some files were not built anymore internally but still referenced
from CMake. Delete them and unreference them in the CMake files.
--
PiperOrigin-RevId: 241744718
This version has been deprecated and can now be removed completely since the
last remaining user (Python bindings) migrated to declarative builders.
Several functions in lib/EDSC/Types.cpp construct core IR objects for the C
bindings. Move these functions into lib/EDSC/CoreAPIs.cpp until we decide
where they should live.
This completes the migration from the delayed-construction EDSC to Declarative
Builders.
--
PiperOrigin-RevId: 241716729
This completes the transition of Python bindings to use the declarative
builders infrastructure instead of the now-deprecated EDSC emitter
infrastructure. The relevant unit tests have been replicated using the new
functionality and the remaining end-to-end compilation tests have been updated
accordingly. The latter show an improvement in brevity and readability.
--
PiperOrigin-RevId: 241713489
The original reimplementation of EDSC as declarative builders and the
subsequent rework of Python bindings forbade to use the (true) division
operator for values of the index types without providing an alternative. Index
types only support floor and ceil division through affine maps. Expose this to
Python bindings through a `__floordiv__` function on `ValueHandle`s.
--
PiperOrigin-RevId: 241713093
This CL fixes the non-determinism across compilers in an edsc::select expression used in LowerVectorTransfers. This is achieved by factoring the expression out of the function call to ensure a deterministic order of evaluation.
Since the expression is now factored out, fewer IR is generated and the test is updated accordingly.
--
PiperOrigin-RevId: 241679962
Historically, the LLVM IR dialect has been using the generic form of MLIR
operation syntax. It is verbose and often redundant. Introduce the custom
printing and parsing for all existing operations in the LLVM IR dialect.
Update the relevant documentation and tests.
--
PiperOrigin-RevId: 241617393
This CL starts the third part of the Linalg tutorial by adding support for ops to declare how they lower themselves to other ops.
Tests are added that demonstrate matmul lowering to a loop over matvec and matvec lowering to a loop over dot.
This is part of a list of CLs that add new Transforms and Analyses to Linalg3: it iseasier to integrate in small chunks.
As part of working with the TensorContractionBase template class and in an effort to add pieces incrementally without copying code, it is easiest to define operations ahead of time in Linalg2/TensorOps.h and gradually implement them as needed. This CL performs the necessary refactoring for this to happen.
--
PiperOrigin-RevId: 241605869
The second part of the Linalg tutorial introduces:
1. the TensorContractionBase type from which all tensor contractions derive;
2. a basic set of operations DotOp, MatvecOp and MatmulOp;
3. a helper function `createFullyComposedView` that walks the producers of a SliceOp up until the root ViewOp and returns a single ViewOp;
4. programmatic examples to test MLIR construction involving these types.
This CL also refactors file organization so that:
1. clients only need to include Ops.h and Types.h while keeping independent small files separate for the purpose of the tutorial;
2. each step of the tutorial has its own linalgxxx include directory and each include explicitly states in which part of the tutorial a particular concept was introduced.
Lastly the following cleanups are applied:
1. ValueOrSliceOp is removed in favor of simpler helper function.
2. methods that walk back the chain of ops are removed from the core ops and added to a separate Analysis.
3. various additional cleanups.
--
PiperOrigin-RevId: 241555769
This CL introduces Confined as a general mechanism to compose complex attribute
constraints out of more primitive ones. It's particularly useful for automatically
generating op definitions from some external source, where we can have random
combinations of primitive constraints and it would be impractical to define a case
for each of such combination.
Two primitive attribute constraints, IntMinValue and ArrayMinCount, are added to be
used together with Confined.
--
PiperOrigin-RevId: 241435955
The first part of the Linalg tutorial introduces:
1. the RangeType and ViewType;
2. operations on those, namely RangeOp, ViewOp and SliceOp;
3. programmatic examples to test MLIR construction involving these types, ops and affine.for loops (with a mock custom op called "some_consumer").
--
PiperOrigin-RevId: 241409949
This is making up for some differences in standard library and linker flags.
It also get rid of the requirement to build with RTTI.
--
PiperOrigin-RevId: 241348845
This CL adds EnumAttr as a general mechanism for modelling enum attributes. Right now
it is using StringAttr under the hood since MLIR does not have native support for enum
attributes.
--
PiperOrigin-RevId: 241334043
Example:
func @unknown_std_op() {
%0 = "std.foo_bar_op"() : () -> index
return
}
Will result in:
error: unregistered operation 'std.foo_bar_op' found in dialect ('std') that does not allow unknown operations
--
PiperOrigin-RevId: 241266009
have no standard ops for working with these yet, this is simply enough to
represent and round trip them in the printer and parser.
--
PiperOrigin-RevId: 241102728
This CL allows the programmatic control of the target hardware vector size when creating a MaterializeVectorsPass.
This is useful for registering passes for the tutorial.
PiperOrigin-RevId: 240996136
A integer number can be specified in the pattern definition and used as the
adjustment to the default benefit score in the generated rewrite pattern C++
definition.
PiperOrigin-RevId: 240994192
This CL removes the reliance of the vectorize pass on the specification of a `fastestVaryingDim` parameter. This parameter is a restriction meant to more easily target a particular loop/memref combination for vectorization and is mainly used for testing.
This also had the side-effect of restricting vectorization patterns to only the ones in which all memrefs were contiguous along the same loop dimension. This simple restriction prevented matmul to vectorize in 2-D.
this CL removes the restriction and adds the matmul test which vectorizes in 2-D along the parallel loops. Support for reduction loops is left for future work.
PiperOrigin-RevId: 240993827
These fail with:
could not convert ‘module’ from ‘llvm::orc::ThreadSafeModule’ to
‘llvm::Expected<llvm::orc::ThreadSafeModule>’
PiperOrigin-RevId: 240892583
Most of the tests have been ported to be unit-tests and this pass is problematic in the way it depends on TableGen-generated files. This pass is also non-deterministic during multi-threading and a blocker to turning it on by default.
PiperOrigin-RevId: 240889154
Originally, the conversion to the LLVM IR dialect had been implemented as pass.
The common conversion infrastructure was factored into DialectConversion from
which the conversion pass inherited. The conversion being a pass is
undesirable for callers that only need the conversion done, for example as a
part of sequence of conversions or outside the pass manager infrastructure.
Split the LLVM IR Dialect conversion into the conversion proper and the
conversion pass, where the latter contains the former instead of inheriting.
NFC.
PiperOrigin-RevId: 240874740
Dialect conversion currently clones the operations that did not match any
pattern. This includes cloning any regions that belong to these operations.
Instead, apply conversion recursively to the nested regions.
Note that if an operation matched one of the conversion patterns, it is up to
the pattern rewriter to fill in the regions of the converted operation. This
may require calling back to the converter and is left for future work.
PiperOrigin-RevId: 240872410
Implicit conversion don't play nicely in expressions such as:
`C() = A(i) * B(i)`.
Make `C()` return an IndexedValue instead of casting to ValueHandle.
This prevents double capture errors and is useful for the tutorial.
PiperOrigin-RevId: 240863223
Example:
%call:2 = call @multi_return() : () -> (f32, i32)
use(%calltensorflow/mlir#0, %calltensorflow/mlir#1)
This cl also adds parser support for uniquely named result values. This means that a test writer can now write something like:
%foo, %bar = call @multi_return() : () -> (f32, i32)
use(%foo, %bar)
Note: The printer will still print the collapsed form.
PiperOrigin-RevId: 240860058