forked from OSchip/llvm-project
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:
parent
884b94e038
commit
cab671d166
|
@ -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_
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -19,6 +19,7 @@ target_link_libraries(Linalg3
|
|||
PUBLIC
|
||||
MLIRAffineOps
|
||||
MLIRAnalysis
|
||||
MLIRControlFlowToCFG
|
||||
MLIRDialect
|
||||
MLIREDSC
|
||||
MLIRIR
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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_
|
|
@ -28,7 +28,9 @@ class Module;
|
|||
|
||||
namespace mlir {
|
||||
class DialectConversion;
|
||||
class FuncOp;
|
||||
class LLVMTypeConverter;
|
||||
class LogicalResult;
|
||||
class MLIRContext;
|
||||
class ModuleOp;
|
||||
class ModulePassBase;
|
||||
|
|
|
@ -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 ®ion().front(); }
|
||||
Value *getInductionVar() { return body()->getArgument(0); }
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
add_subdirectory(LoopsToGPU)
|
||||
add_subdirectory(ControlFlowToCFG)
|
||||
add_subdirectory(GPUToCUDA)
|
||||
add_subdirectory(GPUToNVVM)
|
||||
add_subdirectory(StandardToLLVM)
|
||||
|
|
|
@ -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
|
||||
)
|
|
@ -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 ");
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1656,6 +1656,14 @@ void mlir::ensureStdTerminator(Region ®ion, 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 ®ion : op.getOperation()->getRegions()) {
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -6,6 +6,7 @@ set(LLVM_OPTIONAL_SOURCES
|
|||
set(LIBS
|
||||
MLIRAffineOps
|
||||
MLIRAnalysis
|
||||
MLIRControlFlowToCFG
|
||||
MLIREDSC
|
||||
MLIRExecutionEngine
|
||||
MLIRIR
|
||||
|
|
|
@ -37,6 +37,7 @@ if(MLIR_CUDA_RUNNER_ENABLED)
|
|||
|
||||
set(FULL_LINK_LIBS
|
||||
MLIRAffineOps
|
||||
MLIRControlFlowToCFG
|
||||
MLIRGPU
|
||||
MLIRGPUtoCUDATransforms
|
||||
MLIRGPUtoNVVMTransforms
|
||||
|
|
|
@ -19,6 +19,7 @@ set(LIBS
|
|||
MLIRAffineOps
|
||||
MLIRLoopsToGPU
|
||||
MLIRAnalysis
|
||||
MLIRControlFlowToCFG
|
||||
MLIREDSC
|
||||
MLIRFxpMathOps
|
||||
MLIRGPU
|
||||
|
|
Loading…
Reference in New Issue