Lower affine control flow to std control flow to LLVM dialect

This CL splits the lowering of affine to LLVM into 2 parts:
1. affine -> std
2. std -> LLVM

The conversions mostly consists of splitting concerns between the affine and non-affine worlds from existing conversions.
Short-circuiting of affine `if` conditions was never tested or exercised and is removed in the process, it can be reintroduced later if needed.

LoopParametricTiling.cpp is updated to reflect the newly added ForOp::build.

PiperOrigin-RevId: 257794436
This commit is contained in:
Nicolas Vasilache 2019-07-12 06:48:45 -07:00 committed by jpienaar
parent 884b94e038
commit cab671d166
24 changed files with 887 additions and 646 deletions

View File

@ -26,6 +26,7 @@
namespace mlir {
class ConversionPattern;
class DialectConversion;
struct LogicalResult;
class MLIRContext;
class ModuleOp;
class RewritePattern;
@ -51,7 +52,7 @@ void populateLinalg1ToLLVMConversionPatterns(
/// Convert the Linalg dialect types and RangeOp, ViewOp and SliceOp operations
/// to the LLVM IR dialect types and operations in the given `module`. This is
/// the main entry point to the conversion.
void convertToLLVM(mlir::ModuleOp module);
mlir::LogicalResult convertToLLVM(mlir::ModuleOp module);
} // end namespace linalg
#endif // LINALG1_CONVERTTOLLVMDIALECT_H_

View File

@ -15,6 +15,7 @@ set(LLVM_OPTIONAL_SOURCES
set(LIBS
MLIRAffineOps
MLIRAnalysis
MLIRControlFlowToCFG
MLIREDSC
MLIRLLVMIR
MLIRParser
@ -28,7 +29,8 @@ set(LIBS
add_llvm_library(Linalg1LLVMConversion
ConvertToLLVMDialect.cpp
)
target_link_libraries(Linalg1LLVMConversion PUBLIC MLIRLLVMIR MLIRStandardOps)
target_link_libraries(Linalg1LLVMConversion PUBLIC MLIRLLVMIR
MLIRControlFlowToCFG MLIRStandardOps)
add_llvm_library(Linalg1
Analysis.cpp

View File

@ -15,6 +15,7 @@
// limitations under the License.
// =============================================================================
#include "mlir/Conversion/ControlFlowToCFG/ConvertControlFlowToCFG.h"
#include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h"
#include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVMPass.h"
#include "mlir/EDSC/Builders.h"
@ -28,9 +29,11 @@
#include "mlir/IR/StandardTypes.h"
#include "mlir/IR/Types.h"
#include "mlir/LLVMIR/LLVMDialect.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Pass/PassManager.h"
#include "mlir/Support/LogicalResult.h"
#include "mlir/Transforms/DialectConversion.h"
#include "mlir/Transforms/LowerAffine.h"
#include "mlir/Transforms/Passes.h"
#include "llvm/IR/DerivedTypes.h"
@ -406,13 +409,13 @@ struct LinalgTypeConverter : public LLVMTypeConverter {
};
} // end anonymous namespace
void linalg::convertToLLVM(mlir::ModuleOp module) {
// Remove affine constructs if any by using an existing pass.
PassManager pm;
pm.addPass(createLowerAffinePass());
auto rr = pm.run(module);
(void)rr;
assert(succeeded(rr) && "affine loop lowering failed");
LogicalResult linalg::convertToLLVM(mlir::ModuleOp module) {
for (auto func : module.getOps<FuncOp>()) {
if (failed(mlir::lowerAffineConstructs(func)))
return failure();
if (failed(mlir::lowerControlFlow(func)))
return failure();
}
// Convert Linalg ops to the LLVM IR dialect using the converter defined
// above.
@ -423,15 +426,19 @@ void linalg::convertToLLVM(mlir::ModuleOp module) {
ConversionTarget target(*module.getContext());
target.addLegalDialect<LLVM::LLVMDialect>();
auto r =
applyConversionPatterns(module, target, converter, std::move(patterns));
(void)r;
assert(succeeded(r) && "conversion failed");
if (failed(applyConversionPatterns(module, target, converter,
std::move(patterns))))
return failure();
return success();
}
namespace {
struct LowerLinalgToLLVMPass : public ModulePass<LowerLinalgToLLVMPass> {
void runOnModule() { linalg::convertToLLVM(getModule()); }
void runOnModule() {
if (failed(linalg::convertToLLVM(getModule())))
signalPassFailure();
}
};
} // namespace

View File

@ -93,7 +93,8 @@ TEST_FUNC(foo) {
// CHECK-NEXT: {{.*}} = llvm.extractvalue {{.*}}[0] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }">
// CHECK-NEXT: {{.*}} = llvm.getelementptr {{.*}}[{{.*}}] : (!llvm<"float*">, !llvm.i64) -> !llvm<"float*">
// CHECK-NEXT: {{.*}} = llvm.load {{.*}} : !llvm<"float*">
// CHECK: %159 = llvm.extractvalue {{.*}}[1] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }">
// CHECK: {{.*}} = llvm.extractvalue {{.*}}[1] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }">
// CHECK: {{.*}} = llvm.extractvalue {{.*}}[1] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }">
// CHECK-NEXT: {{.*}} = llvm.extractvalue {{.*}}[3, 0] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }">
// CHECK-NEXT: {{.*}} = llvm.mul {{.*}}, {{.*}} : !llvm.i64
// CHECK-NEXT: {{.*}} = llvm.add {{.*}}, {{.*}} : !llvm.i64

View File

@ -19,11 +19,12 @@
#define LINALG3_CONVERTTOLLVMDIALECT_H_
namespace mlir {
struct LogicalResult;
class ModuleOp;
} // end namespace mlir
namespace linalg {
void convertLinalg3ToLLVM(mlir::ModuleOp module);
mlir::LogicalResult convertLinalg3ToLLVM(mlir::ModuleOp module);
} // end namespace linalg
#endif // LINALG3_CONVERTTOLLVMDIALECT_H_

View File

@ -19,6 +19,7 @@ target_link_libraries(Linalg3
PUBLIC
MLIRAffineOps
MLIRAnalysis
MLIRControlFlowToCFG
MLIRDialect
MLIREDSC
MLIRIR

View File

@ -15,6 +15,7 @@
// limitations under the License.
// =============================================================================
#include "mlir/Conversion/ControlFlowToCFG/ConvertControlFlowToCFG.h"
#include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h"
#include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVMPass.h"
#include "mlir/EDSC/Builders.h"
@ -146,12 +147,13 @@ static void populateLinalg3ToLLVMConversionPatterns(
context);
}
void linalg::convertLinalg3ToLLVM(ModuleOp module) {
LogicalResult linalg::convertLinalg3ToLLVM(ModuleOp module) {
// Remove affine constructs.
for (auto func : module.getOps<FuncOp>()) {
auto rr = lowerAffineConstructs(func);
(void)rr;
assert(succeeded(rr) && "affine loop lowering failed");
if (failed(lowerAffineConstructs(func)))
return failure();
if (failed(mlir::lowerControlFlow(func)))
return failure();
}
// Convert Linalg ops to the LLVM IR dialect using the converter defined
@ -164,8 +166,9 @@ void linalg::convertLinalg3ToLLVM(ModuleOp module) {
ConversionTarget target(*module.getContext());
target.addLegalDialect<LLVM::LLVMDialect>();
auto r =
applyConversionPatterns(module, target, converter, std::move(patterns));
(void)r;
assert(succeeded(r) && "conversion failed");
if (failed(applyConversionPatterns(module, target, converter,
std::move(patterns))))
return failure();
return success();
}

View File

@ -0,0 +1,34 @@
//===- ConvertControlFlowToCFG.h - Pass entrypoint --------------*- C++ -*-===//
//
// Copyright 2019 The MLIR Authors.
//
// 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
//
// http://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.
// =============================================================================
#ifndef MLIR_CONVERSION_CONTROLFLOWTOCFG_CONVERTCONTROLFLOWTOCFG_H_
#define MLIR_CONVERSION_CONTROLFLOWTOCFG_CONVERTCONTROLFLOWTOCFG_H_
namespace mlir {
class FuncOp;
struct LogicalResult;
class ModulePassBase;
/// Lowers std.for, std.if and std.terminator ops to CFG.
LogicalResult lowerControlFlow(FuncOp func);
/// Creates a pass to convert std.for, std.if and std.terminator ops to CFG.
ModulePassBase *createConvertToCFGPass();
} // namespace mlir
#endif // MLIR_CONVERSION_CONTROLFLOWTOCFG_CONVERTCONTROLFLOWTOCFG_H_

View File

@ -28,7 +28,9 @@ class Module;
namespace mlir {
class DialectConversion;
class FuncOp;
class LLVMTypeConverter;
class LogicalResult;
class MLIRContext;
class ModuleOp;
class ModulePassBase;

View File

@ -635,6 +635,12 @@ def IfOp : Std_Op<"if"> {
let arguments = (ins I1:$condition);
let regions = (region SizedRegion<1>:$thenRegion, AnyRegion:$elseRegion);
let skipDefaultBuilders = 1;
let builders = [
OpBuilder<"Builder *builder, OperationState *result, "
"Value *cond, bool withElseRegion">
];
let extraClassDeclaration = [{
OpBuilder getThenBodyBuilder() {
assert(!thenRegion().empty() && "Unexpected empty 'then' region.");
@ -680,9 +686,9 @@ def ForOp : Std_Op<"for"> {
lower bound but does not include the upper bound.
The body region must contain exactly one block that terminates with
"std.terminator". Calling ForOp::build will create such region and
insert the terminator, so will the parsing even in cases when it is absent
from the custom format. For example:
"std.terminator". Calling ForOp::build will create such region and insert
the terminator, so will the parsing even in cases when it is absent from the
custom format. For example:
for %iv = %lb to %ub step %step {
... // body
@ -691,6 +697,12 @@ def ForOp : Std_Op<"for"> {
let arguments = (ins Index:$lowerBound, Index:$upperBound, Index:$step);
let regions = (region SizedRegion<1>:$region);
let skipDefaultBuilders = 1;
let builders = [
OpBuilder<"Builder *builder, OperationState *result, "
"Value *lowerBound, Value *upperBound, Value *step">
];
let extraClassDeclaration = [{
Block *body() { return &region().front(); }
Value *getInductionVar() { return body()->getArgument(0); }

View File

@ -1,4 +1,5 @@
add_subdirectory(LoopsToGPU)
add_subdirectory(ControlFlowToCFG)
add_subdirectory(GPUToCUDA)
add_subdirectory(GPUToNVVM)
add_subdirectory(StandardToLLVM)

View File

@ -0,0 +1,20 @@
add_llvm_library(MLIRControlFlowToCFG
ConvertControlFlowToCFG.cpp
ADDITIONAL_HEADER_DIRS
${MLIR_MAIN_INCLUDE_DIR}/mlir/Conversion/ControlFlowToCFG
)
add_dependencies(
MLIRControlFlowToCFG
MLIRTransforms
LLVMCore
LLVMSupport
)
target_link_libraries(
MLIRControlFlowToCFG
MLIRTransforms
LLVMCore
LLVMSupport
)

View File

@ -0,0 +1,297 @@
//===- ConvertControlFlowToCFG.cpp - ControlFlow to CFG conversion --------===//
//
// Copyright 2019 The MLIR Authors.
//
// 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
//
// http://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.
// =============================================================================
//
// This file implements a pass to convert std.for, std.if and std.terminator ops
// into standard CFG ops.
//
//===----------------------------------------------------------------------===//
#include "mlir/Conversion/ControlFlowToCFG/ConvertControlFlowToCFG.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/MLIRContext.h"
#include "mlir/IR/Module.h"
#include "mlir/IR/PatternMatch.h"
#include "mlir/LLVMIR/LLVMDialect.h"
#include "mlir/Pass/Pass.h"
#include "mlir/StandardOps/Ops.h"
#include "mlir/Support/Functional.h"
#include "mlir/Transforms/DialectConversion.h"
#include "mlir/Transforms/Passes.h"
#include "mlir/Transforms/Utils.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Type.h"
using namespace mlir;
namespace {
struct ControlFlowToCFGPass : public ModulePass<ControlFlowToCFGPass> {
void runOnModule() override;
};
// Create a CFG subgraph for the loop around its body blocks (if the body
// contained other loops, they have been already lowered to a flow of blocks).
// Maintain the invariants that a CFG subgraph created for any loop has a single
// entry and a single exit, and that the entry/exit blocks are respectively
// first/last blocks in the parent region. The original loop operation is
// replaced by the initialization operations that set up the initial value of
// the loop induction variable (%iv) and computes the loop bounds that are loop-
// invariant for affine loops. The operations following the original std.for
// are split out into a separate continuation (exit) block. A condition block is
// created before the continuation block. It checks the exit condition of the
// loop and branches either to the continuation block, or to the first block of
// the body. Induction variable modification is appended to the last block of
// the body (which is the exit block from the body subgraph thanks to the
// invariant we maintain) along with a branch that loops back to the condition
// block.
//
// +---------------------------------+
// | <code before the ForOp> |
// | <compute initial %iv value> |
// | br cond(%iv) |
// +---------------------------------+
// |
// -------| |
// | v v
// | +--------------------------------+
// | | cond(%iv): |
// | | <compare %iv to upper bound> |
// | | cond_br %r, body, end |
// | +--------------------------------+
// | | |
// | | -------------|
// | v |
// | +--------------------------------+ |
// | | body-first: | |
// | | <body contents> | |
// | +--------------------------------+ |
// | | |
// | ... |
// | | |
// | +--------------------------------+ |
// | | body-last: | |
// | | <body contents> | |
// | | %new_iv =<add step to %iv> | |
// | | br cond(%new_iv) | |
// | +--------------------------------+ |
// | | |
// |----------- |--------------------
// v
// +--------------------------------+
// | end: |
// | <code after the ForOp> |
// +--------------------------------+
//
struct ForLowering : public ConversionPattern {
ForLowering(MLIRContext *ctx)
: ConversionPattern(ForOp::getOperationName(), 1, ctx) {}
PatternMatchResult matchAndRewrite(Operation *op, ArrayRef<Value *> operands,
PatternRewriter &rewriter) const override;
};
// Create a CFG subgraph for the std.if operation (including its "then" and
// optional "else" operation blocks). We maintain the invariants that the
// subgraph has a single entry and a single exit point, and that the entry/exit
// blocks are respectively the first/last block of the enclosing region. The
// operations following the std.if are split into a continuation (subgraph
// exit) block. The condition is lowered to a chain of blocks that implement the
// short-circuit scheme. Condition blocks are created by splitting out an empty
// block from the block that contains the std.if operation. They
// conditionally branch to either the first block of the "then" region, or to
// the first block of the "else" region. If the latter is absent, they branch
// to the continuation block instead. The last blocks of "then" and "else"
// regions (which are known to be exit blocks thanks to the invariant we
// maintain).
//
// +--------------------------------+
// | <code before the IfOp> |
// | cond_br %cond, %then, %else |
// +--------------------------------+
// | |
// | --------------|
// v |
// +--------------------------------+ |
// | then: | |
// | <then contents> | |
// | br continue | |
// +--------------------------------+ |
// | |
// |---------- |-------------
// | V
// | +--------------------------------+
// | | else: |
// | | <else contents> |
// | | br continue |
// | +--------------------------------+
// | |
// ------| |
// v v
// +--------------------------------+
// | continue: |
// | <code after the IfOp> |
// +--------------------------------+
//
struct IfLowering : public ConversionPattern {
IfLowering(MLIRContext *ctx)
: ConversionPattern(IfOp::getOperationName(), 1, ctx) {}
PatternMatchResult matchAndRewrite(Operation *op, ArrayRef<Value *> operands,
PatternRewriter &rewriter) const override;
};
struct TerminatorLowering : public ConversionPattern {
TerminatorLowering(MLIRContext *ctx)
: ConversionPattern(TerminatorOp::getOperationName(), 1, ctx) {}
PatternMatchResult matchAndRewrite(Operation *op, ArrayRef<Value *> operands,
PatternRewriter &rewriter) const override {
rewriter.replaceOp(op, {});
return matchSuccess();
}
};
} // namespace
PatternMatchResult
ForLowering::matchAndRewrite(Operation *op, ArrayRef<Value *> operands,
PatternRewriter &rewriter) const {
auto forOp = cast<ForOp>(op);
Location loc = op->getLoc();
// Start by splitting the block containing the 'affine.for' into two parts.
// The part before will get the init code, the part after will be the end
// point.
auto *initBlock = rewriter.getInsertionBlock();
auto initPosition = rewriter.getInsertionPoint();
auto *endBlock = rewriter.splitBlock(initBlock, initPosition);
// Use the first block of the loop body as the condition block since it is
// the block that has the induction variable as its argument. Split out
// all operations from the first block into a new block. Move all body
// blocks from the loop body region to the region containing the loop.
auto *conditionBlock = &forOp.region().front();
auto *firstBodyBlock =
rewriter.splitBlock(conditionBlock, conditionBlock->begin());
auto *lastBodyBlock = &forOp.region().back();
rewriter.inlineRegionBefore(forOp.region(), endBlock);
auto *iv = conditionBlock->getArgument(0);
// Append the induction variable stepping logic to the last body block and
// branch back to the condition block. Construct an expression f :
// (x -> x+step) and apply this expression to the induction variable.
rewriter.setInsertionPointToEnd(lastBodyBlock);
ForOpOperandAdaptor newOperands(operands);
auto *step = newOperands.step();
auto *stepped = rewriter.create<AddIOp>(loc, iv, step).getResult();
if (!stepped)
return matchFailure();
rewriter.create<BranchOp>(loc, conditionBlock, stepped);
// Compute loop bounds before branching to the condition.
rewriter.setInsertionPointToEnd(initBlock);
Value *lowerBound = operands[0];
Value *upperBound = operands[1];
if (!lowerBound || !upperBound)
return matchFailure();
rewriter.create<BranchOp>(loc, conditionBlock, lowerBound);
// With the body block done, we can fill in the condition block.
rewriter.setInsertionPointToEnd(conditionBlock);
auto comparison =
rewriter.create<CmpIOp>(loc, CmpIPredicate::SLT, iv, upperBound);
rewriter.create<CondBranchOp>(loc, comparison, firstBodyBlock,
ArrayRef<Value *>(), endBlock,
ArrayRef<Value *>());
// Ok, we're done!
rewriter.replaceOp(op, {});
return matchSuccess();
}
PatternMatchResult
IfLowering::matchAndRewrite(Operation *op, ArrayRef<Value *> operands,
PatternRewriter &rewriter) const {
auto ifOp = cast<IfOp>(op);
auto loc = op->getLoc();
// Start by splitting the block containing the 'std.if' into two parts.
// The part before will contain the condition, the part after will be the
// continuation point.
auto *condBlock = rewriter.getInsertionBlock();
auto opPosition = rewriter.getInsertionPoint();
auto *continueBlock = rewriter.splitBlock(condBlock, opPosition);
// Move blocks from the "then" region to the region containing 'std.if',
// place it before the continuation block, and branch to it.
auto &thenRegion = ifOp.thenRegion();
auto *thenBlock = &thenRegion.front();
rewriter.setInsertionPointToEnd(&thenRegion.back());
rewriter.create<BranchOp>(loc, continueBlock);
rewriter.inlineRegionBefore(thenRegion, continueBlock);
// Move blocks from the "else" region (if present) to the region containing
// 'std.if', place it before the continuation block and branch to it. It
// will be placed after the "then" regions.
auto *elseBlock = continueBlock;
auto &elseRegion = ifOp.elseRegion();
if (!elseRegion.empty()) {
elseBlock = &elseRegion.front();
rewriter.setInsertionPointToEnd(&elseRegion.back());
rewriter.create<BranchOp>(loc, continueBlock);
rewriter.inlineRegionBefore(elseRegion, continueBlock);
}
rewriter.setInsertionPointToEnd(condBlock);
IfOpOperandAdaptor newOperands(operands);
rewriter.create<CondBranchOp>(loc, newOperands.condition(), thenBlock,
/*trueArgs=*/ArrayRef<Value *>(), elseBlock,
/*falseArgs=*/ArrayRef<Value *>());
// Ok, we're done!
rewriter.replaceOp(op, {});
return matchSuccess();
}
LogicalResult mlir::lowerControlFlow(FuncOp func) {
OwningRewritePatternList patterns;
RewriteListBuilder<ForLowering, IfLowering, TerminatorLowering>::build(
patterns, func.getContext());
struct PartialConversionTarget : public ConversionTarget {
PartialConversionTarget(MLIRContext &context) : ConversionTarget(context) {}
bool isDynamicallyLegal(Operation *op) const override {
return !isa<ForOp>(op) && !isa<IfOp>(op) && !isa<TerminatorOp>(op);
}
};
PartialConversionTarget target(*func.getContext());
target.addDynamicallyLegalDialect<StandardOpsDialect>();
return applyConversionPatterns(func, target, std::move(patterns));
}
void ControlFlowToCFGPass::runOnModule() {
for (auto func : getModule().getOps<FuncOp>())
if (failed(mlir::lowerControlFlow(func)))
return signalPassFailure();
}
ModulePassBase *mlir::createConvertToCFGPass() {
return new ControlFlowToCFGPass();
}
static PassRegistration<ControlFlowToCFGPass>
pass("lower-to-cfg", "Convert control flow operations to ");

View File

@ -7,6 +7,7 @@ add_llvm_library(MLIRStandardToLLVM
add_dependencies(
MLIRStandardToLLVM
MLIRControlFlowToCFG
MLIRLLVMIR
MLIRTransforms
LLVMCore
@ -15,6 +16,7 @@ add_dependencies(
target_link_libraries(
MLIRStandardToLLVM
MLIRControlFlowToCFG
MLIRLLVMIR
MLIRTransforms
LLVMCore

View File

@ -21,6 +21,7 @@
//===----------------------------------------------------------------------===//
#include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h"
#include "mlir/Conversion/ControlFlowToCFG/ConvertControlFlowToCFG.h"
#include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVMPass.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/MLIRContext.h"
@ -1030,8 +1031,11 @@ struct LLVMLoweringPass : public ModulePass<LLVMLoweringPass> {
return signalPassFailure();
ModuleOp m = getModule();
LLVM::ensureDistinctSuccessors(m);
for (auto func : m.getOps<FuncOp>())
if (failed(mlir::lowerControlFlow(func)))
signalPassFailure();
LLVM::ensureDistinctSuccessors(m);
std::unique_ptr<LLVMTypeConverter> typeConverter =
typeConverterMaker(&getContext());
if (!typeConverter)

View File

@ -1656,6 +1656,14 @@ void mlir::ensureStdTerminator(Region &region, Builder &builder, Location loc) {
impl::ensureRegionTerminator<TerminatorOp>(region, builder, loc);
}
void ForOp::build(Builder *builder, OperationState *result, Value *lb,
Value *ub, Value *step) {
result->addOperands({lb, ub, step});
Region *bodyRegion = result->addRegion();
ensureStdTerminator(*bodyRegion, *builder, result->location);
bodyRegion->front().addArgument(builder->getIndexType());
}
LogicalResult verify(ForOp op) {
if (auto cst = dyn_cast_or_null<ConstantIndexOp>(op.step()->getDefiningOp()))
if (cst.getValue() <= 0)
@ -1727,6 +1735,16 @@ ForOp getForOpInductionVarOwner(Value *val) {
// IfOp
//===----------------------------------------------------------------------===//
void IfOp::build(Builder *builder, OperationState *result, Value *cond,
bool withElseRegion) {
result->addOperands(cond);
Region *thenRegion = result->addRegion();
Region *elseRegion = result->addRegion();
ensureStdTerminator(*thenRegion, *builder, result->location);
if (withElseRegion)
ensureStdTerminator(*elseRegion, *builder, result->location);
}
static LogicalResult verify(IfOp op) {
// Verify that the entry of each child region does not have arguments.
for (auto &region : op.getOperation()->getRegions()) {

View File

@ -16,7 +16,7 @@
// =============================================================================
//
// This file lowers affine constructs (If and For statements, AffineApply
// operations) within a function into their lower level CFG equivalent blocks.
// operations) within a function into their standard If and For equivalent ops.
//
//===----------------------------------------------------------------------===//
@ -302,68 +302,11 @@ public:
virtual PatternMatchResult
matchAndRewrite(Operation *op, ArrayRef<Value *> operands,
PatternRewriter &rewriter) const override {
rewriter.replaceOp(op, {});
rewriter.replaceOpWithNewOp<TerminatorOp>(op);
return matchSuccess();
}
};
// Create a CFG subgraph for the loop around its body blocks (if the body
// contained other loops, they have been already lowered to a flow of blocks).
// Maintain the invariants that a CFG subgraph created for any loop has a single
// entry and a single exit, and that the entry/exit blocks are respectively
// first/last blocks in the parent region. The original loop operation is
// replaced by the initialization operations that set up the initial value of
// the loop induction variable (%iv) and computes the loop bounds that are loop-
// invariant for affine loops. The operations following the original affine.for
// are split out into a separate continuation (exit) block. A condition block is
// created before the continuation block. It checks the exit condition of the
// loop and branches either to the continuation block, or to the first block of
// the body. Induction variable modification is appended to the last block of
// the body (which is the exit block from the body subgraph thanks to the
// invariant we maintain) along with a branch that loops back to the condition
// block.
//
// NOTE: this relies on the DialectConversion infrastructure knowing how to undo
// the creation of operations if the conversion fails. In particular, lowering
// of the affine maps may insert operations and then fail on a semi-affine map.
//
// +---------------------------------+
// | <code before the AffineForOp> |
// | <compute initial %iv value> |
// | br cond(%iv) |
// +---------------------------------+
// |
// -------| |
// | v v
// | +--------------------------------+
// | | cond(%iv): |
// | | <compare %iv to upper bound> |
// | | cond_br %r, body, end |
// | +--------------------------------+
// | | |
// | | -------------|
// | v |
// | +--------------------------------+ |
// | | body-first: | |
// | | <body contents> | |
// | +--------------------------------+ |
// | | |
// | ... |
// | | |
// | +--------------------------------+ |
// | | body-last: | |
// | | <body contents> | |
// | | %new_iv =<add step to %iv> | |
// | | br cond(%new_iv) | |
// | +--------------------------------+ |
// | | |
// |----------- |--------------------
// v
// +--------------------------------+
// | end: |
// | <code after the AffineForOp> |
// +--------------------------------+
//
class AffineForLowering : public ConversionPattern {
public:
AffineForLowering(MLIRContext *ctx)
@ -372,125 +315,20 @@ public:
virtual PatternMatchResult
matchAndRewrite(Operation *op, ArrayRef<Value *> operands,
PatternRewriter &rewriter) const override {
auto forOp = cast<AffineForOp>(op);
auto affineForOp = cast<AffineForOp>(op);
Location loc = op->getLoc();
// Start by splitting the block containing the 'affine.for' into two parts.
// The part before will get the init code, the part after will be the end
// point.
auto *initBlock = rewriter.getInsertionBlock();
auto initPosition = rewriter.getInsertionPoint();
auto *endBlock = rewriter.splitBlock(initBlock, initPosition);
// Use the first block of the loop body as the condition block since it is
// the block that has the induction variable as its argument. Split out
// all operations from the first block into a new block. Move all body
// blocks from the loop body region to the region containing the loop.
auto *conditionBlock = &forOp.getRegion().front();
auto *firstBodyBlock =
rewriter.splitBlock(conditionBlock, conditionBlock->begin());
auto *lastBodyBlock = &forOp.getRegion().back();
rewriter.inlineRegionBefore(forOp.getRegion(), endBlock);
auto *iv = conditionBlock->getArgument(0);
// Append the induction variable stepping logic to the last body block and
// branch back to the condition block. Construct an affine expression f :
// (x -> x+step) and apply this expression to the induction variable.
rewriter.setInsertionPointToEnd(lastBodyBlock);
auto affStep = rewriter.getAffineConstantExpr(forOp.getStep());
auto affDim = rewriter.getAffineDimExpr(0);
auto stepped = expandAffineExpr(rewriter, loc, affDim + affStep, iv, {});
if (!stepped)
return matchFailure();
rewriter.create<BranchOp>(loc, conditionBlock, stepped);
// Compute loop bounds before branching to the condition.
rewriter.setInsertionPointToEnd(initBlock);
Value *lowerBound = lowerAffineLowerBound(forOp, rewriter);
Value *upperBound = lowerAffineUpperBound(forOp, rewriter);
if (!lowerBound || !upperBound)
return matchFailure();
rewriter.create<BranchOp>(loc, conditionBlock, lowerBound);
// With the body block done, we can fill in the condition block.
rewriter.setInsertionPointToEnd(conditionBlock);
auto comparison =
rewriter.create<CmpIOp>(loc, CmpIPredicate::SLT, iv, upperBound);
rewriter.create<CondBranchOp>(loc, comparison, firstBodyBlock,
ArrayRef<Value *>(), endBlock,
ArrayRef<Value *>());
// Ok, we're done!
Value *lowerBound = lowerAffineLowerBound(affineForOp, rewriter);
Value *upperBound = lowerAffineUpperBound(affineForOp, rewriter);
Value *step = rewriter.create<ConstantIndexOp>(loc, affineForOp.getStep());
auto f = rewriter.create<ForOp>(loc, lowerBound, upperBound, step);
f.region().getBlocks().clear();
rewriter.inlineRegionBefore(affineForOp.getRegion(), f.region(),
f.region().end());
rewriter.replaceOp(op, {});
return matchSuccess();
}
};
// Create a CFG subgraph for the affine.if operation (including its "then" and
// optional "else" operation blocks). We maintain the invariants that the
// subgraph has a single entry and a single exit point, and that the entry/exit
// blocks are respectively the first/last block of the enclosing region. The
// operations following the affine.if are split into a continuation (subgraph
// exit) block. The condition is lowered to a chain of blocks that implement the
// short-circuit scheme. Condition blocks are created by splitting out an empty
// block from the block that contains the affine.if operation. They
// conditionally branch to either the first block of the "then" region, or to
// the first block of the "else" region. If the latter is absent, they branch
// to the continuation block instead. The last blocks of "then" and "else"
// regions (which are known to be exit blocks thanks to the invariant we
// maintain).
//
// NOTE: this relies on the DialectConversion infrastructure knowing how to undo
// the creation of operations if the conversion fails. In particular, lowering
// of the affine maps may insert operations and then fail on a semi-affine map.
//
// +--------------------------------+
// | <code before the AffineIfOp> |
// | %zero = constant 0 : index |
// | %v = affine.apply #expr1(%ops) |
// | %c = cmpi "sge" %v, %zero |
// | cond_br %c, %next, %else |
// +--------------------------------+
// | |
// | --------------|
// v |
// +--------------------------------+ |
// | next: | |
// | <repeat the check for expr2> | |
// | cond_br %c, %next2, %else | |
// +--------------------------------+ |
// | | |
// ... --------------|
// | <Per-expression checks> |
// v |
// +--------------------------------+ |
// | last: | |
// | <repeat the check for exprN> | |
// | cond_br %c, %then, %else | |
// +--------------------------------+ |
// | | |
// | --------------|
// v |
// +--------------------------------+ |
// | then: | |
// | <then contents> | |
// | br continue | |
// +--------------------------------+ |
// | |
// |---------- |-------------
// | V
// | +--------------------------------+
// | | else: |
// | | <else contents> |
// | | br continue |
// | +--------------------------------+
// | |
// ------| |
// v v
// +--------------------------------+
// | continue: |
// | <code after the AffineIfOp> |
// +--------------------------------+
//
class AffineIfLowering : public ConversionPattern {
public:
AffineIfLowering(MLIRContext *ctx)
@ -499,62 +337,19 @@ public:
virtual PatternMatchResult
matchAndRewrite(Operation *op, ArrayRef<Value *> operands,
PatternRewriter &rewriter) const override {
auto ifOp = cast<AffineIfOp>(op);
auto affineIfOp = cast<AffineIfOp>(op);
auto loc = op->getLoc();
// 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 = rewriter.getInsertionBlock();
auto opPosition = rewriter.getInsertionPoint();
auto *continueBlock = rewriter.splitBlock(condBlock, opPosition);
// Move blocks from the "then" region to the region containing 'affine.if',
// place it before the continuation block, and branch to it.
auto *thenBlock = &ifOp.getThenBlocks().front();
rewriter.setInsertionPointToEnd(&ifOp.getThenBlocks().back());
rewriter.create<BranchOp>(loc, continueBlock);
rewriter.inlineRegionBefore(ifOp.getThenBlocks(), continueBlock);
// Move blocks from the "else" region (if present) to the region containing
// 'affine.if', place it before the continuation block and branch to it. It
// will be placed after the "then" regions.
auto *elseBlock = continueBlock;
if (!ifOp.getElseBlocks().empty()) {
elseBlock = &ifOp.getElseBlocks().front();
rewriter.setInsertionPointToEnd(&ifOp.getElseBlocks().back());
rewriter.create<BranchOp>(loc, continueBlock);
rewriter.inlineRegionBefore(ifOp.getElseBlocks(), continueBlock);
}
// Now we just have to handle the condition logic.
auto integerSet = ifOp.getIntegerSet();
// 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.
rewriter.setInsertionPointToEnd(condBlock);
auto integerSet = affineIfOp.getIntegerSet();
Value *zeroConstant = rewriter.create<ConstantIndexOp>(loc, 0);
// Calculate cond as a conjunction without short-circuiting.
Value *cond = nullptr;
for (unsigned i = 0, e = integerSet.getNumConstraints(); i < e; ++i) {
AffineExpr constraintExpr = integerSet.getConstraint(i);
bool isEquality = integerSet.isEq(i);
// Create the fall-through block for the next condition, if present, by
// splitting an empty block out of an existing block. Otherwise treat the
// first "then" block as the block we should branch to if the (last)
// condition is true.
auto *nextBlock = (i == e - 1)
? thenBlock
: rewriter.splitBlock(condBlock, condBlock->end());
// Build and apply an affine expression
auto numDims = integerSet.getNumDims();
Value *affResult = expandAffineExpr(rewriter, loc, constraintExpr,
@ -562,14 +357,24 @@ public:
operands.drop_front(numDims));
if (!affResult)
return matchFailure();
auto comparisonOp = rewriter.create<CmpIOp>(
loc, isEquality ? CmpIPredicate::EQ : CmpIPredicate::SGE, affResult,
zeroConstant);
rewriter.create<CondBranchOp>(loc, comparisonOp.getResult(), nextBlock,
/*trueArgs=*/ArrayRef<Value *>(), elseBlock,
/*falseArgs=*/ArrayRef<Value *>());
rewriter.setInsertionPointToEnd(nextBlock);
condBlock = nextBlock;
auto pred = isEquality ? CmpIPredicate::EQ : CmpIPredicate::SGE;
Value *cmpVal =
rewriter.create<CmpIOp>(loc, pred, affResult, zeroConstant);
cond =
cond ? rewriter.create<AndOp>(loc, cond, cmpVal).getResult() : cmpVal;
}
cond = cond ? cond
: rewriter.create<ConstantIntOp>(loc, /*value=*/1, /*width=*/1);
bool hasElseRegion = !affineIfOp.getElseBlocks().empty();
auto ifOp = rewriter.create<IfOp>(loc, cond, hasElseRegion);
rewriter.inlineRegionBefore(affineIfOp.getThenBlocks(),
&ifOp.thenRegion().back());
ifOp.thenRegion().back().erase();
if (hasElseRegion) {
rewriter.inlineRegionBefore(affineIfOp.getElseBlocks(),
&ifOp.elseRegion().back());
ifOp.elseRegion().back().erase();
}
// Ok, we're done!

View File

@ -815,13 +815,7 @@ static void tile(MutableArrayRef<ForOp> forOps, ArrayRef<Value *> sizes) {
auto outerForOp =
builder.create<ForOp>(forOps[i].getLoc(), forOps[i].lowerBound(),
forOps[i].upperBound(), newSteps[i]);
// FIXME: builder should do this for us.
ensureStdTerminator(outerForOp.getOperation()->getRegion(0), builder,
forOps[i].getLoc());
outerForOp.body()->addArgument(builder.getIndexType());
builder.setInsertionPointToStart(outerForOp.body());
outerForOps.push_back(outerForOp);
}

View File

@ -0,0 +1,149 @@
// RUN: mlir-opt -lower-to-cfg %s | FileCheck %s
// CHECK-LABEL: func @simple_std_for_loop(%{{.*}}: index, %{{.*}}: index, %{{.*}}: index) {
// CHECK-NEXT: br ^bb1(%{{.*}} : index)
// CHECK-NEXT: ^bb1(%{{.*}}: index): // 2 preds: ^bb0, ^bb2
// CHECK-NEXT: %{{.*}} = cmpi "slt", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{.*}}, ^bb2, ^bb3
// CHECK-NEXT: ^bb2: // pred: ^bb1
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: %[[iv:.*]] = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: br ^bb1(%[[iv]] : index)
// CHECK-NEXT: ^bb3: // pred: ^bb1
// CHECK-NEXT: return
func @simple_std_for_loop(%arg0 : index, %arg1 : index, %arg2 : index) {
for %i0 = %arg0 to %arg1 step %arg2 {
%c1 = constant 1 : index
}
return
}
// CHECK-LABEL: func @simple_std_2_for_loops(%{{.*}}: index, %{{.*}}: index, %{{.*}}: index) {
// CHECK-NEXT: br ^bb1(%{{.*}} : index)
// CHECK-NEXT: ^bb1(%[[ub0:.*]]: index): // 2 preds: ^bb0, ^bb5
// CHECK-NEXT: %[[cond0:.*]] = cmpi "slt", %[[ub0]], %{{.*}} : index
// CHECK-NEXT: cond_br %[[cond0]], ^bb2, ^bb6
// CHECK-NEXT: ^bb2: // pred: ^bb1
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: br ^bb3(%{{.*}} : index)
// CHECK-NEXT: ^bb3(%[[ub1:.*]]: index): // 2 preds: ^bb2, ^bb4
// CHECK-NEXT: %[[cond1:.*]] = cmpi "slt", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %[[cond1]], ^bb4, ^bb5
// CHECK-NEXT: ^bb4: // pred: ^bb3
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: %[[iv1:.*]] = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: br ^bb3(%[[iv1]] : index)
// CHECK-NEXT: ^bb5: // pred: ^bb3
// CHECK-NEXT: %[[iv0:.*]] = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: br ^bb1(%[[iv0]] : index)
// CHECK-NEXT: ^bb6: // pred: ^bb1
// CHECK-NEXT: return
func @simple_std_2_for_loops(%arg0 : index, %arg1 : index, %arg2 : index) {
for %i0 = %arg0 to %arg1 step %arg2 {
%c1 = constant 1 : index
for %i1 = %arg0 to %arg1 step %arg2 {
%c1_0 = constant 1 : index
}
}
return
}
// CHECK-LABEL: func @simple_std_if(%{{.*}}: i1) {
// CHECK-NEXT: cond_br %{{.*}}, ^bb1, ^bb2
// CHECK-NEXT: ^bb1: // pred: ^bb0
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: br ^bb2
// CHECK-NEXT: ^bb2: // 2 preds: ^bb0, ^bb1
// CHECK-NEXT: return
func @simple_std_if(%arg0: i1) {
if %arg0 {
%c1 = constant 1 : index
}
return
}
// CHECK-LABEL: func @simple_std_if_else(%{{.*}}: i1) {
// CHECK-NEXT: cond_br %{{.*}}, ^bb1, ^bb2
// CHECK-NEXT: ^bb1: // pred: ^bb0
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: br ^bb3
// CHECK-NEXT: ^bb2: // pred: ^bb0
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: br ^bb3
// CHECK-NEXT: ^bb3: // 2 preds: ^bb1, ^bb2
// CHECK-NEXT: return
func @simple_std_if_else(%arg0: i1) {
if %arg0 {
%c1 = constant 1 : index
} else {
%c1_0 = constant 1 : index
}
return
}
// CHECK-LABEL: func @simple_std_2_ifs(%{{.*}}: i1) {
// CHECK-NEXT: cond_br %{{.*}}, ^bb1, ^bb5
// CHECK-NEXT: ^bb1: // pred: ^bb0
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: cond_br %{{.*}}, ^bb2, ^bb3
// CHECK-NEXT: ^bb2: // pred: ^bb1
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: br ^bb4
// CHECK-NEXT: ^bb3: // pred: ^bb1
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: br ^bb4
// CHECK-NEXT: ^bb4: // 2 preds: ^bb2, ^bb3
// CHECK-NEXT: br ^bb5
// CHECK-NEXT: ^bb5: // 2 preds: ^bb0, ^bb4
// CHECK-NEXT: return
func @simple_std_2_ifs(%arg0: i1) {
if %arg0 {
%c1 = constant 1 : index
if %arg0 {
%c1_0 = constant 1 : index
} else {
%c1_1 = constant 1 : index
}
}
return
}
// CHECK-LABEL: func @simple_std_for_loop_with_2_ifs(%{{.*}}: index, %{{.*}}: index, %{{.*}}: index, %{{.*}}: i1) {
// CHECK-NEXT: br ^bb1(%{{.*}} : index)
// CHECK-NEXT: ^bb1(%{{.*}}: index): // 2 preds: ^bb0, ^bb7
// CHECK-NEXT: %{{.*}} = cmpi "slt", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{.*}}, ^bb2, ^bb8
// CHECK-NEXT: ^bb2: // pred: ^bb1
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: cond_br %{{.*}}, ^bb3, ^bb7
// CHECK-NEXT: ^bb3: // pred: ^bb2
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: cond_br %{{.*}}, ^bb4, ^bb5
// CHECK-NEXT: ^bb4: // pred: ^bb3
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: br ^bb6
// CHECK-NEXT: ^bb5: // pred: ^bb3
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: br ^bb6
// CHECK-NEXT: ^bb6: // 2 preds: ^bb4, ^bb5
// CHECK-NEXT: br ^bb7
// CHECK-NEXT: ^bb7: // 2 preds: ^bb2, ^bb6
// CHECK-NEXT: %[[iv0:.*]] = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: br ^bb1(%[[iv0]] : index)
// CHECK-NEXT: ^bb8: // pred: ^bb1
// CHECK-NEXT: return
// CHECK-NEXT: }
func @simple_std_for_loop_with_2_ifs(%arg0 : index, %arg1 : index, %arg2 : index, %arg3 : i1) {
for %i0 = %arg0 to %arg1 step %arg2 {
%c1 = constant 1 : index
if %arg3 {
%c1_0 = constant 1 : index
if %arg3 {
%c1_1 = constant 1 : index
} else {
%c1_2 = constant 1 : index
}
}
}
return
}

View File

@ -8,19 +8,13 @@ func @empty() {
func @body(index) -> ()
// Simple loops are properly converted.
// CHECK-LABEL: func @simple_loop() {
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: %{{.*}} = constant 42 : index
// CHECK-NEXT: br ^bb1(%{{.*}} : index)
// CHECK-NEXT: ^bb1(%{{.*}}: index): // 2 preds: ^bb0, ^bb2
// CHECK-NEXT: %{{.*}} = cmpi "slt", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{.*}}, ^bb2, ^bb3
// CHECK-NEXT: ^bb2: // pred: ^bb1
// CHECK-NEXT: call @body(%{{.*}}) : (index) -> ()
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: br ^bb1(%{{.*}} : index)
// CHECK-NEXT: ^bb3: // pred: ^bb1
// CHECK-LABEL: func @simple_loop
// CHECK-NEXT: %[[c1:.*]] = constant 1 : index
// CHECK-NEXT: %[[c42:.*]] = constant 42 : index
// CHECK-NEXT: %[[c1_0:.*]] = constant 1 : index
// CHECK-NEXT: for %{{.*}} = %[[c1]] to %[[c42]] step %[[c1_0]] {
// CHECK-NEXT: call @body(%{{.*}}) : (index) -> ()
// CHECK-NEXT: }
// CHECK-NEXT: return
// CHECK-NEXT: }
func @simple_loop() {
@ -36,32 +30,20 @@ func @pre(index) -> ()
func @body2(index, index) -> ()
func @post(index) -> ()
// CHECK-LABEL: func @imperfectly_nested_loops() {
// CHECK-NEXT: %{{.*}} = constant 0 : index
// CHECK-NEXT: %{{.*}} = constant 42 : index
// CHECK-NEXT: br ^bb1(%{{.*}} : index)
// CHECK-NEXT: ^bb1(%{{.*}}: index): // 2 preds: ^bb0, ^bb5
// CHECK-NEXT: %{{.*}} = cmpi "slt", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{.*}}, ^bb2, ^bb6
// CHECK-NEXT: ^bb2: // pred: ^bb1
// CHECK-NEXT: call @pre(%{{.*}}) : (index) -> ()
// CHECK-NEXT: %{{.*}} = constant 7 : index
// CHECK-NEXT: %{{.*}} = constant 56 : index
// CHECK-NEXT: br ^bb3(%{{.*}} : index)
// CHECK-NEXT: ^bb3(%{{.*}}: index): // 2 preds: ^bb2, ^bb4
// CHECK-NEXT: %{{.*}} = cmpi "slt", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{.*}}, ^bb4, ^bb5
// CHECK-NEXT: ^bb4: // pred: ^bb3
// CHECK-NEXT: call @body2(%{{.*}}, %{{.*}}) : (index, index) -> ()
// CHECK-NEXT: %{{.*}} = constant 2 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: br ^bb3(%{{.*}} : index)
// CHECK-NEXT: ^bb5: // pred: ^bb3
// CHECK-NEXT: call @post(%{{.*}}) : (index) -> ()
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: br ^bb1(%{{.*}} : index)
// CHECK-NEXT: ^bb6: // pred: ^bb1
// CHECK-LABEL: func @imperfectly_nested_loops
// CHECK-NEXT: %[[c0:.*]] = constant 0 : index
// CHECK-NEXT: %[[c42:.*]] = constant 42 : index
// CHECK-NEXT: %[[c1:.*]] = constant 1 : index
// CHECK-NEXT: for %{{.*}} = %[[c0]] to %[[c42]] step %[[c1]] {
// CHECK-NEXT: call @pre(%{{.*}}) : (index) -> ()
// CHECK-NEXT: %[[c7:.*]] = constant 7 : index
// CHECK-NEXT: %[[c56:.*]] = constant 56 : index
// CHECK-NEXT: %[[c2:.*]] = constant 2 : index
// CHECK-NEXT: for %{{.*}} = %[[c7]] to %[[c56]] step %[[c2]] {
// CHECK-NEXT: call @body2(%{{.*}}, %{{.*}}) : (index, index) -> ()
// CHECK-NEXT: }
// CHECK-NEXT: call @post(%{{.*}}) : (index) -> ()
// CHECK-NEXT: }
// CHECK-NEXT: return
// CHECK-NEXT: }
func @imperfectly_nested_loops() {
@ -80,45 +62,27 @@ func @imperfectly_nested_loops() {
func @mid(index) -> ()
func @body3(index, index) -> ()
// CHECK-LABEL: func @more_imperfectly_nested_loops() {
// CHECK-NEXT: %{{.*}} = constant 0 : index
// CHECK-NEXT: %{{.*}} = constant 42 : index
// CHECK-NEXT: br ^bb1(%{{.*}} : index)
// CHECK-NEXT: ^bb1(%{{.*}}: index): // 2 preds: ^bb0, ^bb8
// CHECK-NEXT: %{{.*}} = cmpi "slt", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{.*}}, ^bb2, ^bb9
// CHECK-NEXT: ^bb2: // pred: ^bb1
// CHECK-NEXT: call @pre(%{{.*}}) : (index) -> ()
// CHECK-NEXT: %{{.*}} = constant 7 : index
// CHECK-NEXT: %{{.*}} = constant 56 : index
// CHECK-NEXT: br ^bb3(%{{.*}} : index)
// CHECK-NEXT: ^bb3(%{{.*}}: index): // 2 preds: ^bb2, ^bb4
// CHECK-NEXT: %{{.*}} = cmpi "slt", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{.*}}, ^bb4, ^bb5
// CHECK-NEXT: ^bb4: // pred: ^bb3
// CHECK-NEXT: call @body2(%{{.*}}, %{{.*}}) : (index, index) -> ()
// CHECK-NEXT: %{{.*}} = constant 2 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: br ^bb3(%{{.*}} : index)
// CHECK-NEXT: ^bb5: // pred: ^bb3
// CHECK-NEXT: call @mid(%{{.*}}) : (index) -> ()
// CHECK-NEXT: %{{.*}} = constant 18 : index
// CHECK-NEXT: %{{.*}} = constant 37 : index
// CHECK-NEXT: br ^bb6(%{{.*}} : index)
// CHECK-NEXT: ^bb6(%{{.*}}: index): // 2 preds: ^bb5, ^bb7
// CHECK-NEXT: %{{.*}} = cmpi "slt", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{.*}}, ^bb7, ^bb8
// CHECK-NEXT: ^bb7: // pred: ^bb6
// CHECK-NEXT: call @body3(%{{.*}}, %{{.*}}) : (index, index) -> ()
// CHECK-NEXT: %{{.*}} = constant 3 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: br ^bb6(%{{.*}} : index)
// CHECK-NEXT: ^bb8: // pred: ^bb6
// CHECK-NEXT: call @post(%{{.*}}) : (index) -> ()
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: br ^bb1(%{{.*}} : index)
// CHECK-NEXT: ^bb9: // pred: ^bb1
// CHECK-LABEL: func @more_imperfectly_nested_loops
// CHECK-NEXT: %[[c0:.*]] = constant 0 : index
// CHECK-NEXT: %[[c42:.*]] = constant 42 : index
// CHECK-NEXT: %[[c1:.*]] = constant 1 : index
// CHECK-NEXT: for %{{.*}} = %[[c0]] to %[[c42]] step %[[c1]] {
// CHECK-NEXT: call @pre(%{{.*}}) : (index) -> ()
// CHECK-NEXT: %[[c7:.*]] = constant 7 : index
// CHECK-NEXT: %[[c56:.*]] = constant 56 : index
// CHECK-NEXT: %[[c2:.*]] = constant 2 : index
// CHECK-NEXT: for %{{.*}} = %[[c7]] to %[[c56]] step %[[c2]] {
// CHECK-NEXT: call @body2(%{{.*}}, %{{.*}}) : (index, index) -> ()
// CHECK-NEXT: }
// CHECK-NEXT: call @mid(%{{.*}}) : (index) -> ()
// CHECK-NEXT: %[[c18:.*]] = constant 18 : index
// CHECK-NEXT: %[[c37:.*]] = constant 37 : index
// CHECK-NEXT: %[[c3:.*]] = constant 3 : index
// CHECK-NEXT: for %{{.*}} = %[[c18]] to %[[c37]] step %[[c3]] {
// CHECK-NEXT: call @body3(%{{.*}}, %{{.*}}) : (index, index) -> ()
// CHECK-NEXT: }
// CHECK-NEXT: call @post(%{{.*}}) : (index) -> ()
// CHECK-NEXT: }
// CHECK-NEXT: return
// CHECK-NEXT: }
func @more_imperfectly_nested_loops() {
@ -136,28 +100,16 @@ func @more_imperfectly_nested_loops() {
return
}
// CHECK-LABEL: func @affine_apply_loops_shorthand(%{{.*}}: index) {
// CHECK-NEXT: %{{.*}} = constant 0 : index
// CHECK-NEXT: br ^bb1(%{{.*}} : index)
// CHECK-NEXT: ^bb1(%{{.*}}: index): // 2 preds: ^bb0, ^bb5
// CHECK-NEXT: %{{.*}} = cmpi "slt", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{.*}}, ^bb2, ^bb6
// CHECK-NEXT: ^bb2: // pred: ^bb1
// CHECK-NEXT: %{{.*}} = constant 42 : index
// CHECK-NEXT: br ^bb3(%{{.*}} : index)
// CHECK-NEXT: ^bb3(%{{.*}}: index): // 2 preds: ^bb2, ^bb4
// CHECK-NEXT: %{{.*}} = cmpi "slt", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{.*}}, ^bb4, ^bb5
// CHECK-NEXT: ^bb4: // pred: ^bb3
// CHECK-NEXT: call @body2(%{{.*}}, %{{.*}}) : (index, index) -> ()
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: br ^bb3(%{{.*}} : index)
// CHECK-NEXT: ^bb5: // pred: ^bb3
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: br ^bb1(%{{.*}} : index)
// CHECK-NEXT: ^bb6: // pred: ^bb1
// CHECK-LABEL: func @affine_apply_loops_shorthand
// CHECK-NEXT: %[[c0:.*]] = constant 0 : index
// CHECK-NEXT: %[[c1:.*]] = constant 1 : index
// CHECK-NEXT: for %{{.*}} = %[[c0]] to %{{.*}} step %[[c1]] {
// CHECK-NEXT: %[[c42:.*]] = constant 42 : index
// CHECK-NEXT: %[[c1_0:.*]] = constant 1 : index
// CHECK-NEXT: for %{{.*}} = %{{.*}} to %[[c42]] step %[[c1_0]] {
// CHECK-NEXT: call @body2(%{{.*}}, %{{.*}}) : (index, index) -> ()
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: return
// CHECK-NEXT: }
func @affine_apply_loops_shorthand(%N : index) {
@ -176,19 +128,17 @@ func @get_idx() -> (index)
#set1 = (d0) : (20 - d0 >= 0)
#set2 = (d0) : (d0 - 10 >= 0)
// CHECK-LABEL: func @if_only() {
// CHECK-NEXT: %{{.*}} = call @get_idx() : () -> index
// CHECK-NEXT: %{{.*}} = constant 0 : index
// CHECK-NEXT: %{{.*}}-1 = constant -1 : index
// CHECK-NEXT: %{{.*}} = muli %{{.*}}, %{{.*}}-1 : index
// CHECK-NEXT: %{{.*}} = constant 20 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = cmpi "sge", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{.*}}, [[thenBB:\^bb[0-9]+]], [[endBB:\^bb[0-9]+]]
// CHECK-NEXT: [[thenBB]]:
// CHECK-NEXT: call @body(%{{.*}}) : (index) -> ()
// CHECK-NEXT: br [[endBB]]
// CHECK-NEXT: [[endBB]]:
// CHECK-LABEL: func @if_only
// CHECK-NEXT: %[[v0:.*]] = call @get_idx() : () -> index
// CHECK-NEXT: %[[c0:.*]] = constant 0 : index
// CHECK-NEXT: %[[cm1:.*]] = constant -1 : index
// CHECK-NEXT: %[[v1:.*]] = muli %[[v0]], %[[cm1]] : index
// CHECK-NEXT: %[[c20:.*]] = constant 20 : index
// CHECK-NEXT: %[[v2:.*]] = addi %[[v1]], %[[c20]] : index
// CHECK-NEXT: %[[v3:.*]] = cmpi "sge", %[[v2]], %[[c0]] : index
// CHECK-NEXT: if %[[v3]] {
// CHECK-NEXT: call @body(%[[v0:.*]]) : (index) -> ()
// CHECK-NEXT: }
// CHECK-NEXT: return
// CHECK-NEXT: }
func @if_only() {
@ -199,22 +149,19 @@ func @if_only() {
return
}
// CHECK-LABEL: func @if_else() {
// CHECK-NEXT: %{{.*}} = call @get_idx() : () -> index
// CHECK-NEXT: %{{.*}} = constant 0 : index
// CHECK-NEXT: %{{.*}}-1 = constant -1 : index
// CHECK-NEXT: %{{.*}} = muli %{{.*}}, %{{.*}}-1 : index
// CHECK-NEXT: %{{.*}} = constant 20 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = cmpi "sge", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{.*}}, [[thenBB:\^bb[0-9]+]], [[elseBB:\^bb[0-9]+]]
// CHECK-NEXT: [[thenBB]]:
// CHECK-NEXT: call @body(%{{.*}}) : (index) -> ()
// CHECK-NEXT: br [[endBB:\^bb[0-9]+]]
// CHECK-NEXT: [[elseBB]]:
// CHECK-NEXT: call @mid(%{{.*}}) : (index) -> ()
// CHECK-NEXT: br [[endBB]]
// CHECK-NEXT: [[endBB]]:
// CHECK-LABEL: func @if_else
// CHECK-NEXT: %[[v0:.*]] = call @get_idx() : () -> index
// CHECK-NEXT: %[[c0:.*]] = constant 0 : index
// CHECK-NEXT: %[[cm1:.*]] = constant -1 : index
// CHECK-NEXT: %[[v1:.*]] = muli %[[v0]], %[[cm1]] : index
// CHECK-NEXT: %[[c20:.*]] = constant 20 : index
// CHECK-NEXT: %[[v2:.*]] = addi %[[v1]], %[[c20]] : index
// CHECK-NEXT: %[[v3:.*]] = cmpi "sge", %[[v2]], %[[c0]] : index
// CHECK-NEXT: if %[[v3]] {
// CHECK-NEXT: call @body(%[[v0:.*]]) : (index) -> ()
// CHECK-NEXT: } else {
// CHECK-NEXT: call @mid(%[[v0:.*]]) : (index) -> ()
// CHECK-NEXT: }
// CHECK-NEXT: return
// CHECK-NEXT: }
func @if_else() {
@ -227,38 +174,31 @@ func @if_else() {
return
}
// CHECK-LABEL: func @nested_ifs() {
// CHECK-NEXT: %{{.*}} = call @get_idx() : () -> index
// CHECK-NEXT: %{{.*}} = constant 0 : index
// CHECK-NEXT: %{{.*}}-1 = constant -1 : index
// CHECK-NEXT: %{{.*}} = muli %{{.*}}, %{{.*}}-1 : index
// CHECK-NEXT: %{{.*}} = constant 20 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = cmpi "sge", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{.*}}, ^bb1, ^bb4
// CHECK-NEXT: ^bb1: // pred: ^bb0
// CHECK-NEXT: %{{.*}} = constant 0 : index
// CHECK-NEXT: %{{.*}}-10 = constant -10 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}}-10 : index
// CHECK-NEXT: %{{.*}} = cmpi "sge", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{.*}}, ^bb2, ^bb3
// CHECK-NEXT: ^bb2: // pred: ^bb1
// CHECK-NEXT: call @body(%{{.*}}) : (index) -> ()
// CHECK-NEXT: br ^bb3
// CHECK-NEXT: ^bb3: // 2 preds: ^bb1, ^bb2
// CHECK-NEXT: br ^bb7
// CHECK-NEXT: ^bb4: // pred: ^bb0
// CHECK-NEXT: %{{.*}} = constant 0 : index
// CHECK-NEXT: %{{.*}}-10_2 = constant -10 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}}-10_2 : index
// CHECK-NEXT: %{{.*}} = cmpi "sge", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{.*}}, ^bb5, ^bb6
// CHECK-NEXT: ^bb5: // pred: ^bb4
// CHECK-NEXT: call @mid(%{{.*}}) : (index) -> ()
// CHECK-NEXT: br ^bb6
// CHECK-NEXT: ^bb6: // 2 preds: ^bb4, ^bb5
// CHECK-NEXT: br ^bb7
// CHECK-NEXT: ^bb7: // 2 preds: ^bb3, ^bb6
// CHECK-LABEL: func @nested_ifs
// CHECK-NEXT: %[[v0:.*]] = call @get_idx() : () -> index
// CHECK-NEXT: %[[c0:.*]] = constant 0 : index
// CHECK-NEXT: %[[cm1:.*]] = constant -1 : index
// CHECK-NEXT: %[[v1:.*]] = muli %[[v0]], %[[cm1]] : index
// CHECK-NEXT: %[[c20:.*]] = constant 20 : index
// CHECK-NEXT: %[[v2:.*]] = addi %[[v1]], %[[c20]] : index
// CHECK-NEXT: %[[v3:.*]] = cmpi "sge", %[[v2]], %[[c0]] : index
// CHECK-NEXT: if %[[v3]] {
// CHECK-NEXT: %[[c0_0:.*]] = constant 0 : index
// CHECK-NEXT: %[[cm10:.*]] = constant -10 : index
// CHECK-NEXT: %[[v4:.*]] = addi %[[v0]], %[[cm10]] : index
// CHECK-NEXT: %[[v5:.*]] = cmpi "sge", %[[v4]], %[[c0_0]] : index
// CHECK-NEXT: if %[[v5]] {
// CHECK-NEXT: call @body(%[[v0:.*]]) : (index) -> ()
// CHECK-NEXT: }
// CHECK-NEXT: } else {
// CHECK-NEXT: %[[c0_0:.*]] = constant 0 : index
// CHECK-NEXT: %[[cm10:.*]] = constant -10 : index
// CHECK-NEXT: %{{.*}} = addi %[[v0]], %[[cm10]] : index
// CHECK-NEXT: %{{.*}} = cmpi "sge", %{{.*}}, %[[c0_0]] : index
// CHECK-NEXT: if %{{.*}} {
// CHECK-NEXT: call @mid(%[[v0:.*]]) : (index) -> ()
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: return
// CHECK-NEXT: }
func @nested_ifs() {
@ -277,43 +217,36 @@ func @nested_ifs() {
#setN = (d0)[N,M,K,L] : (N - d0 + 1 >= 0, N - 1 >= 0, M - 1 >= 0, K - 1 >= 0, L - 42 == 0)
// CHECK-LABEL: func @multi_cond(%{{.*}}: index, %{{.*}}: index, %{{.*}}: index, %{{.*}}: index) {
// CHECK-NEXT: %{{.*}} = call @get_idx() : () -> index
// CHECK-NEXT: %{{.*}} = constant 0 : index
// CHECK-NEXT: %{{.*}}-1 = constant -1 : index
// CHECK-NEXT: %{{.*}} = muli %{{.*}}, %{{.*}}-1 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = cmpi "sge", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{.*}}, [[cond2BB:\^bb[0-9]+]], [[elseBB:\^bb[0-9]+]]
// CHECK-NEXT: [[cond2BB]]:
// CHECK-NEXT: %{{.*}}-1_0 = constant -1 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}}-1_0 : index
// CHECK-NEXT: %{{.*}} = cmpi "sge", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{.*}}, [[cond3BB:\^bb[0-9]+]], [[elseBB]]
// CHECK-NEXT: [[cond3BB]]:
// CHECK-NEXT: %{{.*}}-1_1 = constant -1 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}}-1_1 : index
// CHECK-NEXT: %{{.*}} = cmpi "sge", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{.*}}, [[cond4BB:\^bb[0-9]+]], [[elseBB]]
// CHECK-NEXT: [[cond4BB]]:
// CHECK-NEXT: %{{.*}}-1_2 = constant -1 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}}-1_2 : index
// CHECK-NEXT: %{{.*}} = cmpi "sge", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{.*}}, [[cond5BB:\^bb[0-9]+]], [[elseBB]]
// CHECK-NEXT: [[cond5BB]]:
// CHECK-NEXT: %{{.*}}-42 = constant -42 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}}-42 : index
// CHECK-NEXT: %{{.*}} = cmpi "eq", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{.*}}, [[thenBB:\^bb[0-9]+]], [[elseBB]]
// CHECK-NEXT: [[thenBB]]:
// CHECK-NEXT: call @body(%{{.*}}) : (index) -> ()
// CHECK-NEXT: br [[endBB:\^bb[0-9]+]]
// CHECK-NEXT: [[elseBB]]:
// CHECK-NEXT: call @mid(%{{.*}}) : (index) -> ()
// CHECK-NEXT: br [[endBB]]
// CHECK-NEXT: [[endBB]]:
// CHECK-LABEL: func @multi_cond
// CHECK-NEXT: %[[v0:.*]] = call @get_idx() : () -> index
// CHECK-NEXT: %[[c0:.*]] = constant 0 : index
// CHECK-NEXT: %[[cm1:.*]] = constant -1 : index
// CHECK-NEXT: %[[v1:.*]] = muli %[[v0]], %[[cm1]] : index
// CHECK-NEXT: %[[v2:.*]] = addi %[[v1]], %{{.*}} : index
// CHECK-NEXT: %[[c1:.*]] = constant 1 : index
// CHECK-NEXT: %[[v3:.*]] = addi %[[v2]], %[[c1]] : index
// CHECK-NEXT: %[[v4:.*]] = cmpi "sge", %[[v3]], %[[c0]] : index
// CHECK-NEXT: %[[cm1_0:.*]] = constant -1 : index
// CHECK-NEXT: %[[v5:.*]] = addi %{{.*}}, %[[cm1_0]] : index
// CHECK-NEXT: %[[v6:.*]] = cmpi "sge", %[[v5]], %[[c0]] : index
// CHECK-NEXT: %[[v7:.*]] = and %[[v4]], %[[v6]] : i1
// CHECK-NEXT: %[[cm1_1:.*]] = constant -1 : index
// CHECK-NEXT: %[[v8:.*]] = addi %{{.*}}, %[[cm1_1]] : index
// CHECK-NEXT: %[[v9:.*]] = cmpi "sge", %[[v8]], %[[c0]] : index
// CHECK-NEXT: %[[v10:.*]] = and %[[v7]], %[[v9]] : i1
// CHECK-NEXT: %[[cm1_2:.*]] = constant -1 : index
// CHECK-NEXT: %[[v11:.*]] = addi %{{.*}}, %[[cm1_2]] : index
// CHECK-NEXT: %[[v12:.*]] = cmpi "sge", %[[v11]], %[[c0]] : index
// CHECK-NEXT: %[[v13:.*]] = and %[[v10]], %[[v12]] : i1
// CHECK-NEXT: %[[cm42:.*]] = constant -42 : index
// CHECK-NEXT: %[[v14:.*]] = addi %{{.*}}, %[[cm42]] : index
// CHECK-NEXT: %[[v15:.*]] = cmpi "eq", %[[v14]], %[[c0]] : index
// CHECK-NEXT: %[[v16:.*]] = and %[[v13]], %[[v15]] : i1
// CHECK-NEXT: if %[[v16]] {
// CHECK-NEXT: call @body(%[[v0:.*]]) : (index) -> ()
// CHECK-NEXT: } else {
// CHECK-NEXT: call @mid(%[[v0:.*]]) : (index) -> ()
// CHECK-NEXT: }
// CHECK-NEXT: return
// CHECK-NEXT: }
func @multi_cond(%N : index, %M : index, %K : index, %L : index) {
@ -326,39 +259,27 @@ func @multi_cond(%N : index, %M : index, %K : index, %L : index) {
return
}
// CHECK-LABEL: func @if_for() {
// CHECK-LABEL: func @if_for
func @if_for() {
// CHECK-NEXT: %{{.*}} = call @get_idx() : () -> index
// CHECK-NEXT: %[[v0:.*]] = call @get_idx() : () -> index
%i = call @get_idx() : () -> (index)
// CHECK-NEXT: %{{.*}} = constant 0 : index
// CHECK-NEXT: %{{.*}}-1 = constant -1 : index
// CHECK-NEXT: %{{.*}} = muli %{{.*}}, %{{.*}}-1 : index
// CHECK-NEXT: %{{.*}} = constant 20 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = cmpi "sge", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{.*}}, [[midLoopInitBB:\^bb[0-9]+]], [[outerEndBB:\^bb[0-9]+]]
// CHECK-NEXT: [[midLoopInitBB]]:
// CHECK-NEXT: %{{.*}} = constant 0 : index
// CHECK-NEXT: %{{.*}} = constant 42 : index
// CHECK-NEXT: br [[midLoopCondBB:\^bb[0-9]+]](%{{.*}} : index)
// CHECK-NEXT: [[midLoopCondBB]](%{{.*}}: index):
// CHECK-NEXT: %{{.*}} = cmpi "slt", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{.*}}, [[midLoopBodyBB:\^bb[0-9]+]], [[outerEndBB:\^bb[0-9]+]]
// CHECK-NEXT: [[midLoopBodyBB]]:
// CHECK-NEXT: %{{.*}} = constant 0 : index
// CHECK-NEXT: %{{.*}}-10 = constant -10 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}}-10 : index
// CHECK-NEXT: %{{.*}} = cmpi "sge", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{.*}}, [[innerThenBB:\^bb[0-9]+]], [[innerEndBB:\^bb[0-9]+]]
// CHECK-NEXT: [[innerThenBB:\^bb[0-9]+]]:
// CHECK-NEXT: call @body2(%{{.*}}, %{{.*}}) : (index, index) -> ()
// CHECK-NEXT: br [[innerEndBB]]
// CHECK-NEXT: [[innerEndBB]]:
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: br [[midLoopCondBB]](%{{.*}} : index)
// CHECK-NEXT: [[outerEndBB]]:
// CHECK-NEXT: br [[outerLoopInit:\^bb[0-9]+]]
// CHECK-NEXT: %[[c0:.*]] = constant 0 : index
// CHECK-NEXT: %[[cm1:.*]] = constant -1 : index
// CHECK-NEXT: %[[v1:.*]] = muli %[[v0]], %[[cm1]] : index
// CHECK-NEXT: %[[c20:.*]] = constant 20 : index
// CHECK-NEXT: %[[v2:.*]] = addi %[[v1]], %[[c20]] : index
// CHECK-NEXT: %[[v3:.*]] = cmpi "sge", %[[v2]], %[[c0]] : index
// CHECK-NEXT: if %[[v3]] {
// CHECK-NEXT: %[[c0:.*]]{{.*}} = constant 0 : index
// CHECK-NEXT: %[[c42:.*]]{{.*}} = constant 42 : index
// CHECK-NEXT: %[[c1:.*]]{{.*}} = constant 1 : index
// CHECK-NEXT: for %{{.*}} = %[[c0:.*]]{{.*}} to %[[c42:.*]]{{.*}} step %[[c1:.*]]{{.*}} {
// CHECK-NEXT: %[[c0_:.*]]{{.*}} = constant 0 : index
// CHECK-NEXT: %[[cm10:.*]] = constant -10 : index
// CHECK-NEXT: %[[v4:.*]] = addi %{{.*}}, %[[cm10]] : index
// CHECK-NEXT: %[[v5:.*]] = cmpi "sge", %[[v4]], %[[c0_:.*]]{{.*}} : index
// CHECK-NEXT: if %[[v5]] {
// CHECK-NEXT: call @body2(%[[v0]], %{{.*}}) : (index, index) -> ()
affine.if #set1(%i) {
affine.for %j = 0 to 42 {
affine.if #set2(%j) {
@ -366,37 +287,19 @@ func @if_for() {
}
}
}
// CHECK-NEXT: [[outerLoopInit]]:
// CHECK-NEXT: %{{.*}} = constant 0 : index
// CHECK-NEXT: %{{.*}} = constant 42 : index
// CHECK-NEXT: br [[outerLoopCond:\^bb[0-9]+]](%{{.*}} : index)
// CHECK-NEXT: [[outerLoopCond]](%{{.*}}: index):
// CHECK-NEXT: %{{.*}} = cmpi "slt", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{.*}}, [[outerLoopBody:\^bb[0-9]+]], [[outerLoopEnd:\^bb[0-9]+]]
// CHECK-NEXT: [[outerLoopBody]]:
// CHECK-NEXT: %{{.*}} = constant 0 : index
// CHECK-NEXT: %{{.*}}-10_5 = constant -10 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}}-10_5 : index
// CHECK-NEXT: %{{.*}} = cmpi "sge", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{.*}}, [[innerLoopInitBB:\^bb[0-9]+]], [[midEndBB:\^bb[0-9]+]]
// CHECK-NEXT: [[innerLoopInitBB:\^bb[0-9]+]]:
// CHECK-NEXT: %{{.*}} = constant 0 : index
// CHECK-NEXT: %{{.*}} = constant 42 : index
// CHECK-NEXT: br [[innerLoopCondBB:\^bb[0-9]+]](%{{.*}} : index)
// CHECK-NEXT: [[innerLoopCondBB]](%{{.*}}: index):
// CHECK-NEXT: %{{.*}} = cmpi "slt", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{.*}}, [[innerLoopBodyBB:\^bb[0-9]+]], [[innerLoopEndBB:\^bb[0-9]+]]
// CHECK-NEXT: [[innerLoopBodyBB]]:
// CHECK-NEXT: call @body3(%{{.*}}, %{{.*}}) : (index, index) -> ()
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: br [[innerLoopCondBB]](%{{.*}} : index)
// CHECK-NEXT: [[innerLoopEndBB]]:
// CHECK-NEXT: br [[midEndBB]]
// CHECK-NEXT: [[midEndBB]]:
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: br [[outerLoopCond]](%{{.*}} : index)
// CHECK: %[[c0:.*]]{{.*}} = constant 0 : index
// CHECK-NEXT: %[[c42:.*]]{{.*}} = constant 42 : index
// CHECK-NEXT: %[[c1:.*]]{{.*}} = constant 1 : index
// CHECK-NEXT: for %{{.*}} = %[[c0:.*]]{{.*}} to %[[c42:.*]]{{.*}} step %[[c1:.*]]{{.*}} {
// CHECK-NEXT: %[[c0:.*]]{{.*}} = constant 0 : index
// CHECK-NEXT: %[[cm10:.*]]{{.*}} = constant -10 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %[[cm10:.*]]{{.*}} : index
// CHECK-NEXT: %{{.*}} = cmpi "sge", %{{.*}}, %[[c0:.*]]{{.*}} : index
// CHECK-NEXT: if %{{.*}} {
// CHECK-NEXT: %[[c0_:.*]]{{.*}} = constant 0 : index
// CHECK-NEXT: %[[c42_:.*]]{{.*}} = constant 42 : index
// CHECK-NEXT: %[[c1_:.*]]{{.*}} = constant 1 : index
// CHECK-NEXT: for %{{.*}} = %[[c0_:.*]]{{.*}} to %[[c42_:.*]]{{.*}} step %[[c1_:.*]]{{.*}} {
affine.for %k = 0 to 42 {
affine.if #set2(%k) {
affine.for %l = 0 to 42 {
@ -404,45 +307,32 @@ func @if_for() {
}
}
}
// CHECK-NEXT: [[outerLoopEnd]]:
// CHECK-NEXT: return
// CHECK: return
return
}
#lbMultiMap = (d0)[s0] -> (d0, s0 - d0)
#ubMultiMap = (d0)[s0] -> (s0, d0 + 10)
// CHECK-LABEL: func @loop_min_max(%{{.*}}: index) {
// CHECK-NEXT: %{{.*}} = constant 0 : index
// CHECK-NEXT: %{{.*}} = constant 42 : index
// CHECK-NEXT: br ^bb1(%{{.*}} : index)
// CHECK-NEXT: ^bb1(%{{[0-9]+}}: index): // 2 preds: ^bb0, ^bb5
// CHECK-NEXT: %{{.*}} = cmpi "slt", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{[0-9]+}}, ^bb2, ^bb6
// CHECK-NEXT: ^bb2: // pred: ^bb1
// CHECK-NEXT: %{{.*}}-1 = constant -1 : index
// CHECK-NEXT: %{{.*}} = muli %{{.*}}, %{{.*}}-1 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = cmpi "sgt", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = select %{{.*}}, %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = constant 10 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = cmpi "slt", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = select %{{.*}}, %{{.*}}, %{{.*}} : index
// CHECK-NEXT: br ^bb3(%{{.*}} : index)
// CHECK-NEXT: ^bb3(%{{.*}}: index): // 2 preds: ^bb2, ^bb4
// CHECK-NEXT: %{{.*}} = cmpi "slt", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: cond_br %{{.*}}, ^bb4, ^bb5
// CHECK-NEXT: ^bb4: // pred: ^bb3
// CHECK-NEXT: call @body2(%{{.*}}, %{{.*}}) : (index, index) -> ()
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: br ^bb3(%{{.*}} : index)
// CHECK-NEXT: ^bb5: // pred: ^bb3
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: br ^bb1(%{{.*}} : index)
// CHECK-NEXT: ^bb6: // pred: ^bb1
// CHECK-LABEL: func @loop_min_max
// CHECK-NEXT: %[[c0:.*]] = constant 0 : index
// CHECK-NEXT: %[[c42:.*]] = constant 42 : index
// CHECK-NEXT: %[[c1:.*]] = constant 1 : index
// CHECK-NEXT: for %{{.*}} = %[[c0]] to %[[c42]] step %[[c1]] {
// CHECK-NEXT: %[[cm1:.*]] = constant -1 : index
// CHECK-NEXT: %[[a:.*]] = muli %{{.*}}, %[[cm1]] : index
// CHECK-NEXT: %[[b:.*]] = addi %[[a]], %{{.*}} : index
// CHECK-NEXT: %[[c:.*]] = cmpi "sgt", %{{.*}}, %[[b]] : index
// CHECK-NEXT: %[[d:.*]] = select %[[c]], %{{.*}}, %[[b]] : index
// CHECK-NEXT: %[[c10:.*]] = constant 10 : index
// CHECK-NEXT: %[[e:.*]] = addi %{{.*}}, %[[c10]] : index
// CHECK-NEXT: %[[f:.*]] = cmpi "slt", %{{.*}}, %[[e]] : index
// CHECK-NEXT: %[[g:.*]] = select %[[f]], %{{.*}}, %[[e]] : index
// CHECK-NEXT: %[[c1_0:.*]] = constant 1 : index
// CHECK-NEXT: for %{{.*}} = %[[v3]] to %[[v6]] step %[[c1_0]] {
// CHECK-NEXT: call @body2(%{{.*}}, %{{.*}}) : (index, index) -> ()
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: return
// CHECK-NEXT: }
func @loop_min_max(%N : index) {
@ -459,8 +349,8 @@ func @loop_min_max(%N : index) {
// Check that the "min" (cmpi "slt" + select) reduction sequence is emitted
// correctly for a an affine map with 7 results.
// CHECK-LABEL: func @min_reduction_tree(%{{.*}}: index) {
// CHECK-NEXT: %{{.*}} = constant 0 : index
// CHECK-LABEL: func @min_reduction_tree
// CHECK-NEXT: %[[c0:.*]] = constant 0 : index
// CHECK-NEXT: %[[c01:.+]] = cmpi "slt", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %[[r01:.+]] = select %[[c01]], %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %[[c012:.+]] = cmpi "slt", %[[r01]], %{{.*}} : index
@ -473,16 +363,10 @@ func @loop_min_max(%N : index) {
// CHECK-NEXT: %[[r012345:.+]] = select %[[c012345]], %[[r01234]], %{{.*}} : index
// CHECK-NEXT: %[[c0123456:.+]] = cmpi "slt", %[[r012345]], %{{.*}} : index
// CHECK-NEXT: %[[r0123456:.+]] = select %[[c0123456]], %[[r012345]], %{{.*}} : index
// CHECK-NEXT: br ^bb1(%{{.*}} : index)
// CHECK-NEXT: ^bb1(%{{[0-9]+}}: index): // 2 preds: ^bb0, ^bb2
// CHECK-NEXT: %{{[0-9]+}} = cmpi "slt", %{{[0-9]+}}, %[[r0123456]] : index
// CHECK-NEXT: cond_br %{{[0-9]+}}, ^bb2, ^bb3
// CHECK-NEXT: ^bb2: // pred: ^bb1
// CHECK-NEXT: call @body(%{{[0-9]+}}) : (index) -> ()
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: br ^bb1(%{{[0-9]+}} : index)
// CHECK-NEXT: ^bb3: // pred: ^bb1
// CHECK-NEXT: %[[c1:.*]] = constant 1 : index
// CHECK-NEXT: for %{{.*}} = %[[c0]] to %[[v11]] step %[[c1]] {
// CHECK-NEXT: call @body(%{{.*}}) : (index) -> ()
// CHECK-NEXT: }
// CHECK-NEXT: return
// CHECK-NEXT: }
func @min_reduction_tree(%v : index) {
@ -502,32 +386,32 @@ func @min_reduction_tree(%v : index) {
#map5 = (d0,d1,d2) -> (d0,d1,d2)
#map6 = (d0,d1,d2) -> (d0 + d1 + d2)
// CHECK-LABEL: func @affine_applies()
// CHECK-LABEL: func @affine_applies(
func @affine_applies() {
^bb0:
// CHECK: %{{.*}} = constant 0 : index
// CHECK: %[[c0:.*]] = constant 0 : index
%zero = affine.apply #map0()
// Identity maps are just discarded.
// CHECK-NEXT: %{{.*}} = constant 101 : index
// CHECK-NEXT: %[[c101:.*]] = constant 101 : index
%101 = constant 101 : index
%symbZero = affine.apply #map1()[%zero]
// CHECK-NEXT: %{{.*}} = constant 102 : index
// CHECK-NEXT: %[[c102:.*]] = constant 102 : index
%102 = constant 102 : index
%copy = affine.apply #map2(%zero)
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %[[v0:.*]] = addi %[[c0]], %[[c0]] : index
// CHECK-NEXT: %[[c1:.*]] = constant 1 : index
// CHECK-NEXT: %[[v1:.*]] = addi %[[v0]], %[[c1]] : index
%one = affine.apply #map3(%symbZero)[%zero]
// CHECK-NEXT: %{{.*}} = constant 103 : index
// CHECK-NEXT: %{{.*}} = constant 104 : index
// CHECK-NEXT: %{{.*}} = constant 105 : index
// CHECK-NEXT: %{{.*}} = constant 106 : index
// CHECK-NEXT: %{{.*}} = constant 107 : index
// CHECK-NEXT: %{{.*}} = constant 108 : index
// CHECK-NEXT: %{{.*}} = constant 109 : index
// CHECK-NEXT: %[[c103:.*]] = constant 103 : index
// CHECK-NEXT: %[[c104:.*]] = constant 104 : index
// CHECK-NEXT: %[[c105:.*]] = constant 105 : index
// CHECK-NEXT: %[[c106:.*]] = constant 106 : index
// CHECK-NEXT: %[[c107:.*]] = constant 107 : index
// CHECK-NEXT: %[[c108:.*]] = constant 108 : index
// CHECK-NEXT: %[[c109:.*]] = constant 109 : index
%103 = constant 103 : index
%104 = constant 104 : index
%105 = constant 105 : index
@ -535,29 +419,29 @@ func @affine_applies() {
%107 = constant 107 : index
%108 = constant 108 : index
%109 = constant 109 : index
// CHECK-NEXT: %{{.*}} = constant 2 : index
// CHECK-NEXT: %{{.*}} = muli %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = constant 3 : index
// CHECK-NEXT: %{{.*}} = muli %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = constant 4 : index
// CHECK-NEXT: %{{.*}} = muli %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = constant 5 : index
// CHECK-NEXT: %{{.*}} = muli %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = constant 6 : index
// CHECK-NEXT: %{{.*}} = muli %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = constant 7 : index
// CHECK-NEXT: %{{.*}} = muli %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %[[c2:.*]] = constant 2 : index
// CHECK-NEXT: %[[v2:.*]] = muli %[[c104]], %[[c2]] : index
// CHECK-NEXT: %[[v3:.*]] = addi %[[c103]], %[[v2]] : index
// CHECK-NEXT: %[[c3:.*]] = constant 3 : index
// CHECK-NEXT: %[[v4:.*]] = muli %[[c105]], %[[c3]] : index
// CHECK-NEXT: %[[v5:.*]] = addi %[[v3]], %[[v4]] : index
// CHECK-NEXT: %[[c4:.*]] = constant 4 : index
// CHECK-NEXT: %[[v6:.*]] = muli %[[c106]], %[[c4]] : index
// CHECK-NEXT: %[[v7:.*]] = addi %[[v5]], %[[v6]] : index
// CHECK-NEXT: %[[c5:.*]] = constant 5 : index
// CHECK-NEXT: %[[v8:.*]] = muli %[[c107]], %[[c5]] : index
// CHECK-NEXT: %[[v9:.*]] = addi %[[v7]], %[[v8]] : index
// CHECK-NEXT: %[[c6:.*]] = constant 6 : index
// CHECK-NEXT: %[[v10:.*]] = muli %[[c108]], %[[c6]] : index
// CHECK-NEXT: %[[v11:.*]] = addi %[[v9]], %[[v10]] : index
// CHECK-NEXT: %[[c7:.*]] = constant 7 : index
// CHECK-NEXT: %[[v12:.*]] = muli %[[c109]], %[[c7]] : index
// CHECK-NEXT: %[[v13:.*]] = addi %[[v11]], %[[v12]] : index
%four = affine.apply #map4(%103,%104,%105,%106)[%107,%108,%109]
return
}
// CHECK-LABEL: func @args_ret_affine_apply(%{{.*}}: index, %{{.*}}: index)
// CHECK-LABEL: func @args_ret_affine_apply(
func @args_ret_affine_apply(index, index) -> (index, index) {
^bb0(%0 : index, %1 : index):
// CHECK-NEXT: return %{{.*}}, %{{.*}} : index, index
@ -582,12 +466,12 @@ func @args_ret_affine_apply(index, index) -> (index, index) {
// --------------------------------------------------------------------------//
// CHECK-LABEL: func @affine_apply_mod
func @affine_apply_mod(%arg0 : index) -> (index) {
// CHECK-NEXT: %{{.*}} = constant 42 : index
// CHECK-NEXT: %{{.*}} = remis %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = constant 0 : index
// CHECK-NEXT: %{{.*}} = cmpi "slt", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = select %{{.*}}, %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %[[c42:.*]] = constant 42 : index
// CHECK-NEXT: %[[v0:.*]] = remis %{{.*}}, %[[c42]] : index
// CHECK-NEXT: %[[c0:.*]] = constant 0 : index
// CHECK-NEXT: %[[v1:.*]] = cmpi "slt", %[[v0]], %[[c0]] : index
// CHECK-NEXT: %[[v2:.*]] = addi %[[v0]], %[[c42]] : index
// CHECK-NEXT: %[[v3:.*]] = select %[[v1]], %[[v2]], %[[v0]] : index
%0 = affine.apply #mapmod (%arg0)
return %0 : index
}
@ -601,15 +485,15 @@ func @affine_apply_mod(%arg0 : index) -> (index) {
// --------------------------------------------------------------------------//
// CHECK-LABEL: func @affine_apply_floordiv
func @affine_apply_floordiv(%arg0 : index) -> (index) {
// CHECK-NEXT: %{{.*}} = constant 42 : index
// CHECK-NEXT: %{{.*}} = constant 0 : index
// CHECK-NEXT: %{{.*}}-1 = constant -1 : index
// CHECK-NEXT: %{{.*}} = cmpi "slt", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = subi %{{.*}}-1, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = select %{{.*}}, %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = divis %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = subi %{{.*}}-1, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = select %{{.*}}, %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %[[c42:.*]] = constant 42 : index
// CHECK-NEXT: %[[c0:.*]] = constant 0 : index
// CHECK-NEXT: %[[cm1:.*]] = constant -1 : index
// CHECK-NEXT: %[[v0:.*]] = cmpi "slt", %{{.*}}, %[[c0]] : index
// CHECK-NEXT: %[[v1:.*]] = subi %[[cm1]], %{{.*}} : index
// CHECK-NEXT: %[[v2:.*]] = select %[[v0]], %[[v1]], %{{.*}} : index
// CHECK-NEXT: %[[v3:.*]] = divis %[[v2]], %[[c42]] : index
// CHECK-NEXT: %[[v4:.*]] = subi %[[cm1]], %[[v3]] : index
// CHECK-NEXT: %[[v5:.*]] = select %[[v0]], %[[v4]], %[[v3]] : index
%0 = affine.apply #mapfloordiv (%arg0)
return %0 : index
}
@ -623,17 +507,17 @@ func @affine_apply_floordiv(%arg0 : index) -> (index) {
// --------------------------------------------------------------------------//
// CHECK-LABEL: func @affine_apply_ceildiv
func @affine_apply_ceildiv(%arg0 : index) -> (index) {
// CHECK-NEXT: %{{.*}} = constant 42 : index
// CHECK-NEXT: %{{.*}} = constant 0 : index
// CHECK-NEXT: %{{.*}} = constant 1 : index
// CHECK-NEXT: %{{.*}} = cmpi "sle", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = subi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = subi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = select %{{.*}}, %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = divis %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = subi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = select %{{.*}}, %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %[[c42:.*]] = constant 42 : index
// CHECK-NEXT: %[[c0:.*]] = constant 0 : index
// CHECK-NEXT: %[[c1:.*]] = constant 1 : index
// CHECK-NEXT: %[[v0:.*]] = cmpi "sle", %{{.*}}, %[[c0]] : index
// CHECK-NEXT: %[[v1:.*]] = subi %[[c0]], %{{.*}} : index
// CHECK-NEXT: %[[v2:.*]] = subi %{{.*}}, %[[c1]] : index
// CHECK-NEXT: %[[v3:.*]] = select %[[v0]], %[[v1]], %[[v2]] : index
// CHECK-NEXT: %[[v4:.*]] = divis %[[v3]], %[[c42]] : index
// CHECK-NEXT: %[[v5:.*]] = subi %[[c0]], %[[v4]] : index
// CHECK-NEXT: %[[v6:.*]] = addi %[[v4]], %[[c1]] : index
// CHECK-NEXT: %[[v7:.*]] = select %[[v0]], %[[v5]], %[[v6]] : index
%0 = affine.apply #mapceildiv (%arg0)
return %0 : index
}
@ -644,26 +528,26 @@ func @affine_load(%arg0 : index) {
affine.for %i0 = 0 to 10 {
%1 = affine.load %0[%i0 + symbol(%arg0) + 7] : memref<10xf32>
}
// CHECK: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = constant 7 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = load %{{.*}}[%{{.*}}] : memref<10xf32>
// CHECK: %[[a:.*]] = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %[[c7:.*]] = constant 7 : index
// CHECK-NEXT: %[[b:.*]] = addi %[[a]], %[[c7]] : index
// CHECK-NEXT: %{{.*}} = load %[[v0:.*]][%[[b]]] : memref<10xf32>
return
}
// CHECK-LABEL: func @affine_store
func @affine_store(%arg0 : index) {
%0 = alloc() : memref<10xf32>
%1 = constant 11.0 : f32
%1 = constant 11.0 : f32
affine.for %i0 = 0 to 10 {
affine.store %1, %0[%i0 - symbol(%arg0) + 7] : memref<10xf32>
}
// CHECK: %{{.*}}-1 = constant -1 : index
// CHECK-NEXT: %{{.*}} = muli %{{.*}}, %{{.*}}-1 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = constant 7 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>
// CHECK: %c-1 = constant -1 : index
// CHECK-NEXT: %[[a:.*]] = muli %arg0, %c-1 : index
// CHECK-NEXT: %[[b:.*]] = addi %{{.*}}, %[[a]] : index
// CHECK-NEXT: %c7 = constant 7 : index
// CHECK-NEXT: %[[c:.*]] = addi %[[b]], %c7 : index
// CHECK-NEXT: store %cst, %0[%[[c]]] : memref<10xf32>
return
}
@ -678,11 +562,11 @@ func @affine_dma_start(%arg0 : index) {
affine.dma_start %0[%i0 + 7], %1[%arg0 + 11], %2[%c0], %c64
: memref<100xf32>, memref<100xf32, 2>, memref<1xi32>
}
// CHECK: %{{.*}} = constant 7 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = constant 11 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: dma_start %{{.*}}[%{{.*}}], %{{.*}}[%{{.*}}], %{{.*}}, %{{.*}}[%{{.*}}] : memref<100xf32>, memref<100xf32, 2>, memref<1xi32>
// CHECK: %c7 = constant 7 : index
// CHECK-NEXT: %[[a:.*]] = addi %{{.*}}, %c7 : index
// CHECK-NEXT: %c11 = constant 11 : index
// CHECK-NEXT: %[[b:.*]] = addi %arg0, %c11 : index
// CHECK-NEXT: dma_start %0[%[[a]]], %1[%[[b]]], %c64, %2[%c0] : memref<100xf32>, memref<100xf32, 2>, memref<1xi32>
return
}
@ -693,9 +577,9 @@ func @affine_dma_wait(%arg0 : index) {
affine.for %i0 = 0 to 10 {
affine.dma_wait %2[%i0 + %arg0 + 17], %c64 : memref<1xi32>
}
// CHECK: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: %{{.*}} = constant 17 : index
// CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : index
// CHECK-NEXT: dma_wait %{{.*}}[%{{.*}}], %{{.*}} : memref<1xi32>
// CHECK: %[[a:.*]] = addi %{{.*}}, %arg0 : index
// CHECK-NEXT: %c17 = constant 17 : index
// CHECK-NEXT: %[[b:.*]] = addi %[[a]], %c17 : index
// CHECK-NEXT: dma_wait %0[%[[b]]], %c64 : memref<1xi32>
return
}

View File

@ -9,7 +9,7 @@ func @fill_f32(%arg0 : !linalg.buffer<?xf32>, %f : f32) {
%s = linalg.buffer_size %arg0 : !linalg.buffer<?xf32>
%R = linalg.range %c0:%s:%c1 : !linalg.range
%V = linalg.view %arg0[%R] : !linalg.buffer<?xf32> -> !linalg.view<?xf32>
affine.for %i0 = 0 to %s {
linalg.for %i0 = %c0 to %s step %c1 {
linalg.store %f, %V[%i0] : !linalg.view<?xf32>
}
return

View File

@ -6,6 +6,7 @@ set(LLVM_OPTIONAL_SOURCES
set(LIBS
MLIRAffineOps
MLIRAnalysis
MLIRControlFlowToCFG
MLIREDSC
MLIRExecutionEngine
MLIRIR

View File

@ -37,6 +37,7 @@ if(MLIR_CUDA_RUNNER_ENABLED)
set(FULL_LINK_LIBS
MLIRAffineOps
MLIRControlFlowToCFG
MLIRGPU
MLIRGPUtoCUDATransforms
MLIRGPUtoNVVMTransforms

View File

@ -19,6 +19,7 @@ set(LIBS
MLIRAffineOps
MLIRLoopsToGPU
MLIRAnalysis
MLIRControlFlowToCFG
MLIREDSC
MLIRFxpMathOps
MLIRGPU