Rename the 'if' operation in the AffineOps dialect to 'affine.if' and namespace

the AffineOps dialect with 'affine'.

PiperOrigin-RevId: 232728977
This commit is contained in:
River Riddle 2019-02-06 12:59:50 -08:00 committed by jpienaar
parent 888b9fa8a6
commit fd2d7c857b
26 changed files with 139 additions and 138 deletions

View File

@ -15,7 +15,7 @@ loops and if instructions), the result of a
[`affine.apply` operation](#'affine.apply'-operation) that recursively takes as
arguments any symbolic identifiers. Dimensions may be bound not only to anything
that a symbol is bound to, but also to induction variables of enclosing
['affine.for' operations](#'affine.for'-operation), and the result of an
[`affine.for` operations](#'affine.for'-operation), and the result of an
[`affine.apply` operation](#'affine.apply'-operation) (which recursively may use
other dimensions and symbols).
@ -105,20 +105,20 @@ func @simple_example(%A: memref<?x?xf32>, %B: memref<?x?xf32>) {
}
```
#### 'if' operation {#'if'-operation}
#### 'affine.if' operation {#'affine.if'-operation}
Syntax:
``` {.ebnf}
operation ::= `if` if-inst-cond `{` inst* `}` (`else` `{` inst* `}`)?
operation ::= `affine.if` if-inst-cond `{` inst* `}` (`else` `{` inst* `}`)?
if-inst-cond ::= integer-set dim-and-symbol-use-list
```
The `if` operation restricts execution to a subset of the loop iteration space
defined by an integer set (a conjunction of affine constraints). A single `if`
may end with an optional `else` clause.
The `affine.if` operation restricts execution to a subset of the loop iteration
space defined by an integer set (a conjunction of affine constraints). A single
`affine.if` may end with an optional `else` clause.
The condition of the `if` is represented by an
The condition of the `affine.if` is represented by an
[integer set](LangRef.md#integer-sets) (a conjunction of affine constraints),
and the SSA values bound to the dimensions and symbols in the integer set. The
[same restrictions](#restrictions-on-dimensions-and-symbols) hold for these SSA
@ -134,7 +134,7 @@ func @reduced_domain_example(%A, %X, %N) : (memref<10xi32>, i32, i32) {
affine.for %j = 0 to %N {
%0 = affine.apply #map42(%j)
%tmp = call @S1(%X, %i, %0)
if #set(%i, %j)[%N] {
affine.if #set(%i, %j)[%N] {
%1 = affine.apply #map43(%i, %j)
call @S2(%tmp, %A, %i, %1)
}

View File

@ -40,10 +40,10 @@ which means that values are defined before use and have scope defined by their
dominance relations. Operations may produce zero or more results, and each is a
distinct SSA value with its own type defined by the [type system](#type-system).
MLIR incorporates polyhedral compiler concepts, including `affine.for` and `if`
operations defined by the [affine dialect](Dialects/Affine.md), which model
affine loops and affine conditionals. It also includes affine maps integrated
into the type system - they are key to the representation of data and
MLIR incorporates polyhedral compiler concepts, including `affine.for` and
`affine.if` operations defined by the [affine dialect](Dialects/Affine.md),
which model affine loops and affine conditionals. It also includes affine maps
integrated into the type system - they are key to the representation of data and
[MemRefs](#memref-type), which are the representation for tensors in addressable
memory. MLIR also supports a first-class Tensor type allowing it to concisely
represent operations on N-dimensional arrays.
@ -473,7 +473,7 @@ Example:
: d0 >= 0, -d0 + s0 - 1 >= 0, d1 >= 0, -d1 + s1 - 1 >= 0
// Inside a Function
if #set42(%i, %j)[%M, %N] {
affine.if #set42(%i, %j)[%M, %N] {
...
}
```
@ -1434,8 +1434,8 @@ The arity of indices is the rank of the memref (i.e., if the memref loaded from
is of rank 3, then 3 indices are required for the load following the memref
identifier).
In an `if` or `affine.for` body, the indices of a load are restricted to SSA
values bound to surrounding loop induction variables,
In an `affine.if` or `affine.for` body, the indices of a load are restricted to
SSA values bound to surrounding loop induction variables,
[symbols](#dimensions-and-symbols), results of a
[`constant` operation](#'constant'-operation), or the result of an
`affine.apply` operation that can in turn take as arguments all of the
@ -1455,11 +1455,11 @@ Example:
```
**Context:** The `load` and `store` instructions are specifically crafted to
fully resolve a reference to an element of a memref, and (in affine `if` and
`affine.for` instructions) the compiler can follow use-def chains (e.g. through
[`affine.apply`](Dialects/Affine.md#'affine.apply'-operation) operations) to
precisely analyze references at compile-time using polyhedral techniques. This
is possible because of the
fully resolve a reference to an element of a memref, and (in affine `affine.if`
and `affine.for` instructions) the compiler can follow use-def chains (e.g.
through [`affine.apply`](Dialects/Affine.md#'affine.apply'-operation)
operations) to precisely analyze references at compile-time using polyhedral
techniques. This is possible because of the
[restrictions on dimensions and symbols](Dialects/Affine.md#restrictions-on-dimensions-and-symbols)
in these contexts.
@ -1491,8 +1491,9 @@ store %100, %A[%1, 1023] : memref<4x?xf32, #layout, hbm>
```
**Context:** The `load` and `store` instructions are specifically crafted to
fully resolve a reference to an element of a memref, and (in polyhedral `if` and
`affine.for` instructions) the compiler can follow use-def chains (e.g. through
fully resolve a reference to an element of a memref, and (in polyhedral
`affine.if` and `affine.for` instructions) the compiler can follow use-def
chains (e.g. through
[`affine.apply`](Dialects/Affine.md#'affine.apply'-operation) operations) to
precisely analyze references at compile-time using polyhedral techniques. This
is possible because of the

View File

@ -39,9 +39,9 @@ These restrictions may be lifted in the future.
### Output IR
Functions with `affine.for` and `if` instructions eliminated. These functions
may contain operations from the Standard dialect in addition to those already
present before the pass.
Functions with `affine.for` and `affine.if` instructions eliminated. These
functions may contain operations from the Standard dialect in addition to those
already present before the pass.
### Invariants

View File

@ -568,9 +568,9 @@ func @search_body(%A: memref<?x?xi32>, %S: memref<?xi32>, %key: i32) {
As per the [MLIR spec](LangRef.md), the restrictions on dimensions and symbol
identifiers to be used with the affine.apply instruction only apply to accesses
inside `affine.for` and `if` instructions. However, an analysis of accesses
inside the called function (`@search_body`) is necessary to determine if the
`%i` loop could be parallelized: such function access analysis is calling
inside `affine.for` and `affine.if` instructions. However, an analysis of
accesses inside the called function (`@search_body`) is necessary to determine
if the `%i` loop could be parallelized: such function access analysis is calling
context sensitive.
### Non-affine loop bounds {#non-affine-loop-bounds}
@ -665,7 +665,7 @@ func @conv2d(memref<16x1024x1024x3xf32, #lm0, vmem> %input,
%h_pad_low, %w_pad_low]
// Check if access is not in padding.
if #domain(%1_0, %1_1)
affine.if #domain(%1_0, %1_1)
[%h_base_dilation, %w_kernel_dilation, %h_bound, %w_bound] {
%2_0 = affine.apply #map2 (%1_0, %1_1)
%2_1 = affine.apply #map2 (%1_0, %1_1)
@ -899,10 +899,10 @@ func @dma_hbm_to_vmem(memref<1024 x f32, #layout_map0, hbm> %a,
representation. 2(b) requires no change, but impacts how cost models look at
index and layout maps.
### `if` and `affine.for` Extensions for "Escaping Scalars" {#extensions-for-"escaping-scalars"}
### `affine.if` and `affine.for` Extensions for "Escaping Scalars" {#extensions-for-"escaping-scalars"}
We considered providing a representation for SSA values that are live out of
`if/else` conditional bodies and loop carried in `affine.for` loops. We
`affine.if/else` conditional bodies and loop carried in `affine.for` loops. We
ultimately abandoned this approach due to its complexity. In the current design
of MLIR, scalar variables cannot escape for loops or if instructions. In
situations, where escaping is necessary, we use zero-dimensional tensors and
@ -948,7 +948,7 @@ func int32 @sum(%A : memref<?xi32>, %N : i32) -> (i32) {
Syntax:
``` {.ebnf}
<out-var-list> = if (<cond-list>) {...} [else {...}]
<out-var-list> = affine.if (<cond-list>) {...} [else {...}]
```
Out-var-list is a list of SSA values defined by the if-instruction. The values
@ -965,7 +965,7 @@ Example:
func int32 @sum_half(%A, %N) {
%s0 = 0
%s1 = affine.for %i = 1 ... N step 1 with %s2 (%s0) {
%s3 = if (%i >= %N / 2) {
%s3 = affine.if (%i >= %N / 2) {
%v0 = load %A[%i]
%s4 = %s2 + %v0
yield %s4

View File

@ -210,7 +210,7 @@ The example with the reduced domain would be represented with an if instruction:
%tmp = call @S1(%X, %0, %1)
if (10 <= %i < %N-10), (10 <= %j < %N-10) {
affine.if (10 <= %i < %N-10), (10 <= %j < %N-10) {
%2,%3 = affine.apply(%i, %j) // identity noop in this case
@ -269,8 +269,8 @@ representation helps solve this inherently hard problem.
In the cases that are most relevant to us (hyper rectangular spaces) these forms
are directly equivalent: a traditional instruction with a limited domain (e.g.
the "reduced_domain_example" above) ends up having one level of ML 'if' inside
its loops. The simplified form pays for this by eliminating schedules and
the "reduced_domain_example" above) ends up having one level of ML 'affine.if'
inside its loops. The simplified form pays for this by eliminating schedules and
domains from the IR. Both forms allow code duplication to reduce dynamic
branches in the IR: the traditional approach allows instruction splitting, the
simplified form supports instruction duplication.

View File

@ -312,12 +312,12 @@ private:
friend class AffineForOp;
};
/// The "if" operation represents an if-then-else construct for conditionally
/// executing two regions of code. The operands to an if operation are an
/// IntegerSet condition and a set of symbol/dimension operands to the
/// The "affine.if" operation represents an if-then-else construct for
/// conditionally executing two regions of code. The operands to an if operation
/// are an IntegerSet condition and a set of symbol/dimension operands to the
/// condition set. The operation produces no results. For example:
///
/// if #set(%i) {
/// affine.if #set(%i) {
/// ...
/// } else {
/// ...
@ -326,7 +326,7 @@ private:
/// The 'else' blocks to the if operation are optional, and may be omitted. For
/// example:
///
/// if #set(%i) {
/// affine.if #set(%i) {
/// ...
/// }
///
@ -337,7 +337,7 @@ public:
static void build(Builder *builder, OperationState *result,
IntegerSet condition, ArrayRef<Value *> conditionOperands);
static StringRef getOperationName() { return "if"; }
static StringRef getOperationName() { return "affine.if"; }
static StringRef getConditionAttrName() { return "condition"; }
IntegerSet getIntegerSet() const;

View File

@ -53,7 +53,7 @@ bool properlyDominates(const Instruction &a, const Instruction &b);
/// Populates 'loops' with IVs of the loops surrounding 'inst' ordered from
/// the outermost 'affine.for' instruction to the innermost one.
// TODO(bondhugula): handle 'if' inst's.
// TODO(bondhugula): handle 'affine.if' inst's.
void getLoopIVs(const Instruction &inst,
SmallVectorImpl<OpPointer<AffineForOp>> *loops);

View File

@ -17,9 +17,9 @@
//
// Integer sets are sets of points from the integer lattice constrained by
// affine equality/inequality constraints. This class is meant to represent
// integer sets in the IR - for 'if' instructions and as attributes of other
// instructions. It is typically expected to contain only a handful of affine
// constraints, and is immutable like an affine map. Integer sets are not
// integer sets in the IR - for 'affine.if' instructions and as attributes of
// other instructions. It is typically expected to contain only a handful of
// affine constraints, and is immutable like an affine map. Integer sets are not
// unique'd - although affine expressions that make up its equalities and
// inequalites are themselves unique.

View File

@ -35,7 +35,7 @@ using llvm::dbgs;
//===----------------------------------------------------------------------===//
AffineOpsDialect::AffineOpsDialect(MLIRContext *context)
: Dialect(/*namePrefix=*/"", context) {
: Dialect(/*namePrefix=*/"affine", context) {
addOperations<AffineApplyOp, AffineForOp, AffineIfOp>();
}
@ -1102,7 +1102,7 @@ bool AffineIfOp::verify() const {
// block lists.
if (std::next(blockList.begin()) != blockList.end())
return emitOpError(
"expects only one block per 'if' or 'else' block list");
"expects only one block per 'affine.if' or 'else' block list");
if (blockList.front().getTerminator())
return emitOpError("expects region block to not have a terminator");
@ -1151,7 +1151,7 @@ bool AffineIfOp::parse(OpAsmParser *parser, OperationState *result) {
void AffineIfOp::print(OpAsmPrinter *p) const {
auto conditionAttr = getAttrOfType<IntegerSetAttr>(getConditionAttrName());
*p << "if " << conditionAttr;
*p << "affine.if " << conditionAttr;
printDimAndSymbolList(operand_begin(), operand_end(),
conditionAttr.getValue().getNumDims(), p);
p->printBlockList(getInstruction()->getBlockList(0));

View File

@ -42,7 +42,7 @@ void mlir::getLoopIVs(const Instruction &inst,
auto *currInst = inst.getParentInst();
OpPointer<AffineForOp> currAffineForOp;
// Traverse up the hierarchy collecing all 'affine.for' instruction while
// skipping over 'if' instructions.
// skipping over 'affine.if' instructions.
while (currInst && ((currAffineForOp = currInst->dyn_cast<AffineForOp>()) ||
currInst->isa<AffineIfOp>())) {
if (currAffineForOp)

View File

@ -189,7 +189,7 @@ unsigned Block::getNumSuccessors() const {
return terminator->getNumSuccessors();
}
assert(getParent() && "top-level block with no terminator");
// Blocks inside 'affine.for'/'if' instructions don't have successors.
// Blocks inside 'affine.for'/'affine.if' instructions don't have successors.
return 0;
}

View File

@ -456,9 +456,9 @@ bool DmaGeneration::runOnBlock(Block *block, uint64_t consumedCapacityBytes) {
// instructions) are always assumed to not exhaust memory. As a result, this
// approach is conservative in some cases at the moment, we do a check later
// and report an error with location info.
// TODO(bondhugula): An 'if' instruction is being treated similar to an
// operation instruction. 'if''s could have 'affine.for's in them; treat them
// separately.
// TODO(bondhugula): An 'affine.if' instruction is being treated similar to an
// operation instruction. 'affine.if''s could have 'affine.for's in them;
// treat them separately.
// Get to the first load, store, or for op.
auto curBegin =

View File

@ -402,16 +402,16 @@ bool LowerAffinePass::lowerAffineFor(OpPointer<AffineForOp> forOp) {
return false;
}
// Convert an "if" instruction into a flow of basic blocks.
// Convert an "affine.if" instruction into a flow of basic blocks.
//
// Create an SESE region for the if instruction (including its "then" and
// optional "else" instruction blocks) and append it to the end of the current
// region. The conditional region consists of a sequence of condition-checking
// blocks that implement the short-circuit scheme, followed by a "then" SESE
// region and an "else" SESE region, and the continuation block that
// post-dominates all blocks of the "if" instruction. The flow of blocks that
// correspond to the "then" and "else" clauses are constructed recursively,
// enabling easy nesting of "if" instructions and if-then-else-if chains.
// post-dominates all blocks of the "affine.if" instruction. The flow of blocks
// that correspond to the "then" and "else" clauses are constructed recursively,
// enabling easy nesting of "affine.if" instructions and if-then-else-if chains.
//
// +--------------------------------+
// | <code before the AffineIfOp> |
@ -465,9 +465,9 @@ bool LowerAffinePass::lowerAffineIf(AffineIfOp *ifOp) {
auto *ifInst = ifOp->getInstruction();
auto loc = ifInst->getLoc();
// Start by splitting the block containing the 'if' into two parts. The part
// before will contain the condition, the part after will be the continuation
// point.
// Start by splitting the block containing the 'affine.if' into two parts. The
// part before will contain the condition, the part after will be the
// continuation point.
auto *condBlock = ifInst->getBlock();
auto *continueBlock = condBlock->splitBlock(ifInst);
@ -517,15 +517,15 @@ bool LowerAffinePass::lowerAffineIf(AffineIfOp *ifOp) {
// Ok, now we just have to handle the condition logic.
auto integerSet = ifOp->getIntegerSet();
// Implement short-circuit logic. For each affine expression in the 'if'
// condition, convert it into an affine map and call `affine.apply` to obtain
// the resulting value. Perform the equality or the greater-than-or-equality
// test between this value and zero depending on the equality flag of the
// condition. If the test fails, jump immediately to the false branch, which
// may be the else block if it is present or the continuation block otherwise.
// If the test succeeds, jump to the next block testing the next conjunct of
// the condition in the similar way. When all conjuncts have been handled,
// jump to the 'then' block instead.
// Implement short-circuit logic. For each affine expression in the
// 'affine.if' condition, convert it into an affine map and call
// `affine.apply` to obtain the resulting value. Perform the equality or the
// greater-than-or-equality test between this value and zero depending on the
// equality flag of the condition. If the test fails, jump immediately to the
// false branch, which may be the else block if it is present or the
// continuation block otherwise. If the test succeeds, jump to the next block
// testing the next conjunct of the condition in the similar way. When all
// conjuncts have been handled, jump to the 'then' block instead.
builder.setInsertionPointToEnd(condBlock);
Value *zeroConstant = builder.create<ConstantIndexOp>(loc, 0);

View File

@ -19,7 +19,7 @@
// potentially getting rid of intermediate memref's entirely.
// TODO(mlir-team): In the future, similar techniques could be used to eliminate
// dead memref store's and perform more complex forwarding when support for
// SSA scalars live out of 'affine.for'/'if' statements is available.
// SSA scalars live out of 'affine.for'/'affine.if' statements is available.
//===----------------------------------------------------------------------===//
#include "mlir/Analysis/AffineAnalysis.h"

View File

@ -245,7 +245,7 @@ func @non_instruction() {
func @invalid_if_conditional2() {
affine.for %i = 1 to 10 {
if (i)[N] : (i >= ) // expected-error {{expected '== 0' or '>= 0' at end of affine constraint}}
affine.if (i)[N] : (i >= ) // expected-error {{expected '== 0' or '>= 0' at end of affine constraint}}
}
}
@ -253,7 +253,7 @@ func @invalid_if_conditional2() {
func @invalid_if_conditional3() {
affine.for %i = 1 to 10 {
if (i)[N] : (i == 1) // expected-error {{expected '0' after '=='}}
affine.if (i)[N] : (i == 1) // expected-error {{expected '0' after '=='}}
}
}
@ -261,7 +261,7 @@ func @invalid_if_conditional3() {
func @invalid_if_conditional4() {
affine.for %i = 1 to 10 {
if (i)[N] : (i >= 2) // expected-error {{expected '0' after '>='}}
affine.if (i)[N] : (i >= 2) // expected-error {{expected '0' after '>='}}
}
}
@ -269,7 +269,7 @@ func @invalid_if_conditional4() {
func @invalid_if_conditional5() {
affine.for %i = 1 to 10 {
if (i)[N] : (i <= 0 ) // expected-error {{expected '== 0' or '>= 0' at end of affine constraint}}
affine.if (i)[N] : (i <= 0 ) // expected-error {{expected '== 0' or '>= 0' at end of affine constraint}}
}
}
@ -277,15 +277,15 @@ func @invalid_if_conditional5() {
func @invalid_if_conditional6() {
affine.for %i = 1 to 10 {
if (i) : (i) // expected-error {{expected '== 0' or '>= 0' at end of affine constraint}}
affine.if (i) : (i) // expected-error {{expected '== 0' or '>= 0' at end of affine constraint}}
}
}
// -----
// TODO (support if (1)?
// TODO (support affine.if (1)?
func @invalid_if_conditional7() {
affine.for %i = 1 to 10 {
if (i) : (1) // expected-error {{expected '== 0' or '>= 0' at end of affine constraint}}
affine.if (i) : (1) // expected-error {{expected '== 0' or '>= 0' at end of affine constraint}}
}
}
@ -580,7 +580,7 @@ func @invalid_bound_map(%N : i32) {
func @invalid_if_operands1(%N : index) {
affine.for %i = 1 to 10 {
if #set0(%i) {
affine.if #set0(%i) {
// expected-error@-1 {{symbol operand count and integer set symbol count must match}}
// -----
@ -588,7 +588,7 @@ func @invalid_if_operands1(%N : index) {
func @invalid_if_operands2(%N : index) {
affine.for %i = 1 to 10 {
if #set0()[%N] {
affine.if #set0()[%N] {
// expected-error@-1 {{dim operand count and integer set dim count must match}}
// -----
@ -596,7 +596,7 @@ func @invalid_if_operands2(%N : index) {
func @invalid_if_operands3(%N : index) {
affine.for %i = 1 to 10 {
if #set0(%i)[%i] {
affine.if #set0(%i)[%i] {
// expected-error@-1 {{operand cannot be used as a symbol}}
}
}

View File

@ -17,7 +17,7 @@ func @inline_notation() -> i32 loc("mysource.cc":10:8) {
} loc(fused["foo", "mysource.cc":10:8])
// CHECK: } loc(fused<"myPass">["foo", "foo2"])
if #set0(%2) {
affine.if #set0(%2) {
} loc(fused<"myPass">["foo", "foo2"])
// CHECK: return %0 : i32 loc(unknown)

View File

@ -306,13 +306,13 @@ func @loop_bounds(%N : index) {
func @ifinst(%N: index) {
%c = constant 200 : index // CHECK %c200 = constant 200
affine.for %i = 1 to 10 { // CHECK affine.for %i0 = 1 to 10 {
if #set0(%i)[%N, %c] { // CHECK if #set0(%i0)[%arg0, %c200] {
affine.if #set0(%i)[%N, %c] { // CHECK affine.if #set0(%i0)[%arg0, %c200] {
%x = constant 1 : i32
// CHECK: %c1_i32 = constant 1 : i32
%y = "add"(%x, %i) : (i32, index) -> i32 // CHECK: %0 = "add"(%c1_i32, %i0) : (i32, index) -> i32
%z = "mul"(%y, %y) : (i32, i32) -> i32 // CHECK: %1 = "mul"(%0, %0) : (i32, i32) -> i32
} else { // CHECK } else {
if (i)[N] : (i - 2 >= 0, 4 - i >= 0)(%i)[%N] { // CHECK if (#set1(%i0)[%arg0]) {
affine.if (i)[N] : (i - 2 >= 0, 4 - i >= 0)(%i)[%N] { // CHECK affine.if (#set1(%i0)[%arg0]) {
// CHECK: %c1 = constant 1 : index
%u = constant 1 : index
// CHECK: %2 = affine.apply #map{{.*}}(%i0, %i0)[%c1]
@ -329,7 +329,7 @@ func @ifinst(%N: index) {
func @simple_ifinst(%N: index) {
%c = constant 200 : index // CHECK %c200 = constant 200
affine.for %i = 1 to 10 { // CHECK affine.for %i0 = 1 to 10 {
if #set0(%i)[%N, %c] { // CHECK if #set0(%i0)[%arg0, %c200] {
affine.if #set0(%i)[%N, %c] { // CHECK affine.if #set0(%i0)[%arg0, %c200] {
%x = constant 1 : i32
// CHECK: %c1_i32 = constant 1 : i32
%y = "add"(%x, %i) : (i32, index) -> i32 // CHECK: %0 = "add"(%c1_i32, %i0) : (i32, index) -> i32
@ -781,8 +781,8 @@ func @type_alias() -> !i32_type_alias {
// CHECK-LABEL: func @no_integer_set_constraints(
func @no_integer_set_constraints() {
// CHECK: if [[SET_TRUE]]() {
if () : () () {
// CHECK: affine.if [[SET_TRUE]]() {
affine.if () : () () {
}
return
}
@ -791,8 +791,8 @@ func @no_integer_set_constraints() {
func @verbose_if(%N: index) {
%c = constant 200 : index
// CHECK: if #set0(%c200)[%arg0, %c200] {
"if"(%c, %N, %c) { condition: #set0 } : (index, index, index) -> () {
// CHECK: affine.if #set0(%c200)[%arg0, %c200] {
"affine.if"(%c, %N, %c) { condition: #set0 } : (index, index, index) -> () {
// CHECK-NEXT: "add"
%y = "add"(%c, %N) : (index, index) -> index
// CHECK-NEXT: } else {

View File

@ -22,7 +22,7 @@ func @inline_notation() -> i32 loc("mysource.cc":10:8) {
} loc(fused["foo", "mysource.cc":10:8])
// CHECK: } <"myPass">["foo", "foo2"]
if #set0(%2) {
affine.if #set0(%2) {
} loc(fused<"myPass">["foo", "foo2"])
// CHECK: return %0 : i32 [unknown]

View File

@ -111,7 +111,7 @@ func @vec1d(%A : memref<?x?xf32>, %B : memref<?x?x?xf32>) {
//
// CHECK: affine.for %i{{[0-9]*}} = 0 to %{{[0-9]*}} {
affine.for %i15 = 0 to %M { // not vectorized due to condition below
if #set0(%i15) {
affine.if #set0(%i15) {
%a15 = load %A[%cst0, %cst0] : memref<?x?xf32>
}
}

View File

@ -478,7 +478,7 @@ func @should_not_fuse_if_inst_at_top_level() {
%v0 = load %m[%i1] : memref<10xf32>
}
%c0 = constant 4 : index
if #set0(%c0) {
affine.if #set0(%c0) {
}
// Top-level IfOp should prevent fusion.
// CHECK: affine.for %i0 = 0 to 10 {
@ -504,7 +504,7 @@ func @should_not_fuse_if_inst_in_loop_nest() {
store %cf7, %m[%i0] : memref<10xf32>
}
affine.for %i1 = 0 to 10 {
if #set0(%c4) {
affine.if #set0(%c4) {
}
%v0 = load %m[%i1] : memref<10xf32>
}
@ -514,7 +514,7 @@ func @should_not_fuse_if_inst_in_loop_nest() {
// CHECK-NEXT: store %cst, %0[%i0] : memref<10xf32>
// CHECK-NEXT: }
// CHECK: affine.for %i1 = 0 to 10 {
// CHECK-NEXT: if #set0(%c4) {
// CHECK-NEXT: affine.if #set0(%c4) {
// CHECK-NEXT: }
// CHECK-NEXT: %1 = load %0[%i1] : memref<10xf32>
// CHECK-NEXT: }

View File

@ -193,7 +193,7 @@ func @get_idx() -> (index)
// CHECK-NEXT: }
func @if_only() {
%i = call @get_idx() : () -> (index)
if #set1(%i) {
affine.if #set1(%i) {
call @body(%i) : (index) -> ()
}
return
@ -219,7 +219,7 @@ func @if_only() {
// CHECK-NEXT: }
func @if_else() {
%i = call @get_idx() : () -> (index)
if #set1(%i) {
affine.if #set1(%i) {
call @body(%i) : (index) -> ()
} else {
call @mid(%i) : (index) -> ()
@ -263,12 +263,12 @@ func @if_else() {
// CHECK-NEXT: }
func @nested_ifs() {
%i = call @get_idx() : () -> (index)
if #set1(%i) {
if #set2(%i) {
affine.if #set1(%i) {
affine.if #set2(%i) {
call @body(%i) : (index) -> ()
}
} else {
if #set2(%i) {
affine.if #set2(%i) {
call @mid(%i) : (index) -> ()
}
}
@ -318,7 +318,7 @@ func @nested_ifs() {
// CHECK-NEXT: }
func @multi_cond(%N : index, %M : index, %K : index, %L : index) {
%i = call @get_idx() : () -> (index)
if #setN(%i)[%N,%M,%K,%L] {
affine.if #setN(%i)[%N,%M,%K,%L] {
call @body(%i) : (index) -> ()
} else {
call @mid(%i) : (index) -> ()
@ -359,9 +359,9 @@ func @if_for() {
// CHECK-NEXT: br [[midLoopCondBB]](%8 : index)
// CHECK-NEXT: [[outerEndBB]]:
// CHECK-NEXT: br [[outerLoopInit:\^bb[0-9]+]]
if #set1(%i) {
affine.if #set1(%i) {
affine.for %j = 0 to 42 {
if #set2(%j) {
affine.if #set2(%j) {
call @body2(%i, %j) : (index, index) -> ()
}
}
@ -398,7 +398,7 @@ func @if_for() {
// CHECK-NEXT: %16 = addi %9, %c1_9 : index
// CHECK-NEXT: br [[outerLoopCond]](%16 : index)
affine.for %k = 0 to 42 {
if #set2(%k) {
affine.if #set2(%k) {
affine.for %l = 0 to 42 {
call @body3(%k, %l) : (index, index) -> ()
}

View File

@ -12,7 +12,7 @@ func @store_may_execute_before_load() {
// There is a dependence from store 0 to load 1 at depth 1 because the
// ancestor IfOp of the store, dominates the ancestor ForSmt of the load,
// and thus the store "may" conditionally execute before the load.
if #set0(%c0) {
affine.if #set0(%c0) {
affine.for %i0 = 0 to 10 {
store %cf7, %m[%i0] : memref<10xf32>
// expected-note@-1 {{dependence from 0 to 0 at depth 1 = false}}

View File

@ -76,7 +76,7 @@ func @test_gaussian_elimination_empty_set0() {
affine.for %i0 = 1 to 10 {
affine.for %i1 = 1 to 100 {
// CHECK: [[SET_EMPTY_2D]](%i0, %i1)
if (d0, d1) : (2 == 0)(%i0, %i1) {
affine.if (d0, d1) : (2 == 0)(%i0, %i1) {
}
}
}
@ -88,7 +88,7 @@ func @test_gaussian_elimination_empty_set1() {
affine.for %i0 = 1 to 10 {
affine.for %i1 = 1 to 100 {
// CHECK: [[SET_EMPTY_2D]](%i0, %i1)
if (d0, d1) : (1 >= 0, -1 >= 0) (%i0, %i1) {
affine.if (d0, d1) : (1 >= 0, -1 >= 0) (%i0, %i1) {
}
}
}
@ -100,7 +100,7 @@ func @test_gaussian_elimination_non_empty_set2() {
affine.for %i0 = 1 to 10 {
affine.for %i1 = 1 to 100 {
// CHECK: #set1(%i0, %i1)
if #set2(%i0, %i1) {
affine.if #set2(%i0, %i1) {
}
}
}
@ -114,7 +114,7 @@ func @test_gaussian_elimination_empty_set3() {
affine.for %i0 = 1 to 10 {
affine.for %i1 = 1 to 100 {
// CHECK: #set2(%i0, %i1)[%c7, %c11]
if #set3(%i0, %i1)[%c7, %c11] {
affine.if #set3(%i0, %i1)[%c7, %c11] {
}
}
}
@ -128,7 +128,7 @@ func @test_gaussian_elimination_non_empty_set4() {
affine.for %i0 = 1 to 10 {
affine.for %i1 = 1 to 100 {
// CHECK: #set3(%i0, %i1)[%c7, %c11]
if #set4(%i0, %i1)[%c7, %c11] {
affine.if #set4(%i0, %i1)[%c7, %c11] {
}
}
}
@ -142,7 +142,7 @@ func @test_gaussian_elimination_empty_set5() {
affine.for %i0 = 1 to 10 {
affine.for %i1 = 1 to 100 {
// CHECK: #set2(%i0, %i1)[%c7, %c11]
if #set5(%i0, %i1)[%c7, %c11] {
affine.if #set5(%i0, %i1)[%c7, %c11] {
}
}
}
@ -153,7 +153,7 @@ func @test_gaussian_elimination_empty_set5() {
func @test_fuzz_explosion(%arg0 : index, %arg1 : index, %arg2 : index, %arg3 : index) {
affine.for %i0 = 1 to 10 {
affine.for %i1 = 1 to 100 {
if #set_fuzz_virus(%i0, %i1, %arg0, %arg1, %arg2, %arg3) {
affine.if #set_fuzz_virus(%i0, %i1, %arg0, %arg1, %arg2, %arg3) {
}
}
}
@ -165,34 +165,34 @@ func @test_fuzz_explosion(%arg0 : index, %arg1 : index, %arg2 : index, %arg3 : i
func @test_empty_set(%N : index) {
affine.for %i = 0 to 10 {
affine.for %j = 0 to 10 {
// CHECK: if [[SET_EMPTY_2D]](%i0, %i1)
if (d0, d1) : (d0 - d1 >= 0, d1 - d0 - 1 >= 0)(%i, %j) {
// CHECK: affine.if [[SET_EMPTY_2D]](%i0, %i1)
affine.if (d0, d1) : (d0 - d1 >= 0, d1 - d0 - 1 >= 0)(%i, %j) {
"foo"() : () -> ()
}
// CHECK: if [[SET_EMPTY_1D]](%i0)
if (d0) : (d0 >= 0, -d0 - 1 >= 0)(%i) {
// CHECK: affine.if [[SET_EMPTY_1D]](%i0)
affine.if (d0) : (d0 >= 0, -d0 - 1 >= 0)(%i) {
"bar"() : () -> ()
}
// CHECK: if [[SET_EMPTY_1D]](%i0)
if (d0) : (d0 >= 0, -d0 - 1 >= 0)(%i) {
// CHECK: affine.if [[SET_EMPTY_1D]](%i0)
affine.if (d0) : (d0 >= 0, -d0 - 1 >= 0)(%i) {
"foo"() : () -> ()
}
// CHECK: if [[SET_EMPTY_1D_2S]](%i0)[%arg0, %arg0]
if (d0)[s0, s1] : (d0 >= 0, -d0 + s0 - 1 >= 0, -s0 >= 0)(%i)[%N, %N] {
// CHECK: affine.if [[SET_EMPTY_1D_2S]](%i0)[%arg0, %arg0]
affine.if (d0)[s0, s1] : (d0 >= 0, -d0 + s0 - 1 >= 0, -s0 >= 0)(%i)[%N, %N] {
"bar"() : () -> ()
}
// CHECK: if [[SET_EMPTY_3D]](%i0, %i1, %arg0)
// CHECK: affine.if [[SET_EMPTY_3D]](%i0, %i1, %arg0)
// The set below implies d0 = d1; so d1 >= d0, but d0 >= d1 + 1.
if (d0, d1, d2) : (d0 - d1 == 0, d2 - d0 >= 0, d0 - d1 - 1 >= 0)(%i, %j, %N) {
affine.if (d0, d1, d2) : (d0 - d1 == 0, d2 - d0 >= 0, d0 - d1 - 1 >= 0)(%i, %j, %N) {
"foo"() : () -> ()
}
// CHECK: if [[SET_EMPTY_2D]](%i0, %i1)
// CHECK: affine.if [[SET_EMPTY_2D]](%i0, %i1)
// The set below has rational solutions but no integer solutions; GCD test catches it.
if (d0, d1) : (d0*2 -d1*2 - 1 == 0, d0 >= 0, -d0 + 100 >= 0, d1 >= 0, -d1 + 100 >= 0)(%i, %j) {
affine.if (d0, d1) : (d0*2 -d1*2 - 1 == 0, d0 >= 0, -d0 + 100 >= 0, d1 >= 0, -d1 + 100 >= 0)(%i, %j) {
"foo"() : () -> ()
}
// CHECK: if [[SET_EMPTY_2D]](%i0, %i1)
if (d0, d1) : (d1 == 0, d0 - 1 >= 0, - d0 - 1 >= 0)(%i, %j) {
// CHECK: affine.if [[SET_EMPTY_2D]](%i0, %i1)
affine.if (d0, d1) : (d1 == 0, d0 - 1 >= 0, - d0 - 1 >= 0)(%i, %j) {
"foo"() : () -> ()
}
}
@ -201,34 +201,34 @@ func @test_empty_set(%N : index) {
affine.for %k = 0 to 10 {
affine.for %l = 0 to 10 {
// Empty because no multiple of 8 lies between 4 and 7.
// CHECK: if [[SET_EMPTY_1D]](%i2)
if (d0) : (8*d0 - 4 >= 0, -8*d0 + 7 >= 0)(%k) {
// CHECK: affine.if [[SET_EMPTY_1D]](%i2)
affine.if (d0) : (8*d0 - 4 >= 0, -8*d0 + 7 >= 0)(%k) {
"foo"() : () -> ()
}
// Same as above but with equalities and inequalities.
// CHECK: if [[SET_EMPTY_2D]](%i2, %i3)
if (d0, d1) : (d0 - 4*d1 == 0, 4*d1 - 5 >= 0, -4*d1 + 7 >= 0)(%k, %l) {
// CHECK: affine.if [[SET_EMPTY_2D]](%i2, %i3)
affine.if (d0, d1) : (d0 - 4*d1 == 0, 4*d1 - 5 >= 0, -4*d1 + 7 >= 0)(%k, %l) {
"foo"() : () -> ()
}
// Same as above but with a combination of multiple identifiers. 4*d0 +
// 8*d1 here is a multiple of 4, and so can't lie between 9 and 11. GCD
// tightening will tighten constraints to 4*d0 + 8*d1 >= 12 and 4*d0 +
// 8*d1 <= 8; hence infeasible.
// CHECK: if [[SET_EMPTY_2D]](%i2, %i3)
if (d0, d1) : (4*d0 + 8*d1 - 9 >= 0, -4*d0 - 8*d1 + 11 >= 0)(%k, %l) {
// CHECK: affine.if [[SET_EMPTY_2D]](%i2, %i3)
affine.if (d0, d1) : (4*d0 + 8*d1 - 9 >= 0, -4*d0 - 8*d1 + 11 >= 0)(%k, %l) {
"foo"() : () -> ()
}
// Same as above but with equalities added into the mix.
// CHECK: if [[SET_EMPTY_3D]](%i2, %i2, %i3)
if (d0, d1, d2) : (d0 - 4*d2 == 0, d0 + 8*d1 - 9 >= 0, -d0 - 8*d1 + 11 >= 0)(%k, %k, %l) {
// CHECK: affine.if [[SET_EMPTY_3D]](%i2, %i2, %i3)
affine.if (d0, d1, d2) : (d0 - 4*d2 == 0, d0 + 8*d1 - 9 >= 0, -d0 - 8*d1 + 11 >= 0)(%k, %k, %l) {
"foo"() : () -> ()
}
}
}
affine.for %m = 0 to 10 {
// CHECK: if [[SET_EMPTY_1D]](%i{{[0-9]+}})
if (d0) : (d0 mod 2 - 3 == 0) (%m) {
// CHECK: affine.if [[SET_EMPTY_1D]](%i{{[0-9]+}})
affine.if (d0) : (d0 mod 2 - 3 == 0) (%m) {
"foo"() : () -> ()
}
}

View File

@ -15,7 +15,7 @@ func @inline_notation() -> i32 loc("mysource.cc":10:8) {
// CHECK: } loc(unknown)
%2 = constant 4 : index
if #set0(%2) {
affine.if #set0(%2) {
} loc(fused<"myPass">["foo", "foo2"])
// CHECK: return %0 : i32 loc(unknown)

View File

@ -42,7 +42,7 @@
;; Keywords
`(,(regexp-opt
'(;; Toplevel entities
"br" "ceildiv" "func" "cond_br" "else" "extfunc" "false" "floordiv" "affine.for" "if" "mod" "return" "size" "step" "to" "true" "??" ) 'symbols) . font-lock-keyword-face))
"br" "ceildiv" "func" "cond_br" "else" "extfunc" "false" "floordiv" "affine.for" "affine.if" "mod" "return" "size" "step" "to" "true" "??" ) 'symbols) . font-lock-keyword-face))
"Syntax highlighting for MLIR.")
;; Emacs 23 compatibility.

View File

@ -11,7 +11,7 @@ syn keyword mlirType index i1 i2 i4 i8 i13 i16 i32 i64
syn keyword mlirType memref tensor vector
syntax keyword mlirKeywords extfunc func to step return
syntax keyword mlirConditional if else
syntax keyword mlirConditional affine.if else
syntax keyword mlirCoreOps dim addf addi subf subi mulf muli cmpi select constant affine.apply affine.for call call_indirect extract_element getTensor memref_cast tensor_cast load store alloc dealloc dma_start dma_wait
syn match mlirInt "-\=\<\d\+\>"