Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 13 additions & 7 deletions mlir/include/mlir/Dialect/SCF/IR/SCFOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,13 @@ def ForOp : SCF_Op<"for",
region capturing the loop body. The induction variable is represented as an
argument of this region. This SSA value is a signless integer or index.
The step is a value of same type but required to be positive, the lower and
upper bounds can be also negative or zero. The lower and upper bounds specify
a half-open range: the iteration is executed iff the signed comparison of induction
variable value is less than the upper bound and bigger or equal to the lower bound.
upper bounds can be also negative or zero. The lower and upper bounds
specify a half-open range: the iteration is executed iff the comparison of
induction variable value is less than the upper bound and bigger or equal
to the lower bound.

By default, the integer comparison is signed. If the `unsignedCmp` unit
attribute is specified, the integer comparison is unsigned.

The body region must contain exactly one block that terminates with
`scf.yield`. Calling ForOp::build will create such a region and insert
Expand All @@ -184,8 +188,8 @@ def ForOp : SCF_Op<"for",
... // body
}
...
// Integer case.
scf.for %iv_32 = %lb_32 to %ub_32 step %step_32 : i32 {
// Unsigned integer case.
scf.for unsigned %iv_32 = %lb_32 to %ub_32 step %step_32 : i32 {
... // body
}
```
Expand Down Expand Up @@ -258,15 +262,17 @@ def ForOp : SCF_Op<"for",
let arguments = (ins AnySignlessIntegerOrIndex:$lowerBound,
AnySignlessIntegerOrIndex:$upperBound,
AnySignlessIntegerOrIndex:$step,
Variadic<AnyType>:$initArgs);
Variadic<AnyType>:$initArgs,
UnitAttr:$unsignedCmp);
let results = (outs Variadic<AnyType>:$results);
let regions = (region SizedRegion<1>:$region);

let skipDefaultBuilders = 1;
let builders = [OpBuilder<(ins "Value":$lowerBound, "Value":$upperBound,
"Value":$step, CArg<"ValueRange", "{}">:$initArgs,
CArg<"function_ref<void(OpBuilder &, Location, Value, ValueRange)>",
"nullptr">)>];
"nullptr">,
CArg<"bool", "false">:$unsignedCmp)>];

let extraClassDeclaration = [{
using BodyBuilderFn =
Expand Down
7 changes: 5 additions & 2 deletions mlir/lib/Conversion/SCFToControlFlow/SCFToControlFlow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -382,8 +382,11 @@ LogicalResult ForLowering::matchAndRewrite(ForOp forOp,

// With the body block done, we can fill in the condition block.
rewriter.setInsertionPointToEnd(conditionBlock);
auto comparison = arith::CmpIOp::create(
rewriter, loc, arith::CmpIPredicate::slt, iv, upperBound);
arith::CmpIPredicate predicate = forOp.getUnsignedCmp()
? arith::CmpIPredicate::ult
: arith::CmpIPredicate::slt;
auto comparison =
arith::CmpIOp::create(rewriter, loc, predicate, iv, upperBound);

cf::CondBranchOp::create(rewriter, loc, comparison, firstBodyBlock,
ArrayRef<Value>(), endBlock, ArrayRef<Value>());
Expand Down
4 changes: 4 additions & 0 deletions mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ ForLowering::matchAndRewrite(ForOp forOp, OpAdaptor adaptor,
ConversionPatternRewriter &rewriter) const {
Location loc = forOp.getLoc();

if (forOp.getUnsignedCmp())
return rewriter.notifyMatchFailure(forOp,
"unsigned loops are not supported");

// Create an emitc::variable op for each result. These variables will be
// assigned to by emitc::assign ops within the loop body.
SmallVector<Value> resultVariables;
Expand Down
10 changes: 8 additions & 2 deletions mlir/lib/Conversion/SCFToSPIRV/SCFToSPIRV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,14 @@ struct ForOpConversion final : SCFToSPIRVPattern<scf::ForOp> {
// Generate the rest of the loop header.
rewriter.setInsertionPointToEnd(header);
auto *mergeBlock = loopOp.getMergeBlock();
auto cmpOp = spirv::SLessThanOp::create(rewriter, loc, rewriter.getI1Type(),
newIndVar, adaptor.getUpperBound());
Value cmpOp;
if (forOp.getUnsignedCmp()) {
cmpOp = spirv::ULessThanOp::create(rewriter, loc, rewriter.getI1Type(),
newIndVar, adaptor.getUpperBound());
} else {
cmpOp = spirv::SLessThanOp::create(rewriter, loc, rewriter.getI1Type(),
newIndVar, adaptor.getUpperBound());
}

spirv::BranchConditionalOp::create(rewriter, loc, cmpOp, body,
ArrayRef<Value>(), mergeBlock,
Expand Down
3 changes: 2 additions & 1 deletion mlir/lib/Dialect/Linalg/Transforms/HoistPadding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,8 @@ static FailureOr<PackingResult> buildPackingLoopNestImpl(
auto clonedForOp = scf::ForOp::create(
rewriter, loc, bvm.lookupOrDefault(forOp.getLowerBound()),
bvm.lookupOrDefault(forOp.getUpperBound()),
bvm.lookupOrDefault(forOp.getStep()), hoistedPackedTensor);
bvm.lookupOrDefault(forOp.getStep()), hoistedPackedTensor,
/*bodyBuilder=*/nullptr, forOp.getUnsignedCmp());

// Map the induction var, region args and results to the `clonedForOp`.
bvm.map(forOp.getInductionVar(), clonedForOp.getInductionVar());
Expand Down
3 changes: 2 additions & 1 deletion mlir/lib/Dialect/Linalg/Transforms/Hoisting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ static scf::ForOp replaceWithDifferentYield(RewriterBase &rewriter,

scf::ForOp newLoop = scf::ForOp::create(
rewriter, loop.getLoc(), loop.getLowerBound(), loop.getUpperBound(),
loop.getStep(), inits, [](OpBuilder &, Location, Value, ValueRange) {});
loop.getStep(), inits, [](OpBuilder &, Location, Value, ValueRange) {},
loop.getUnsignedCmp());

// Generate the new yield with the replaced operand.
auto yieldOp = cast<scf::YieldOp>(loop.getBody()->getTerminator());
Expand Down
40 changes: 27 additions & 13 deletions mlir/lib/Dialect/SCF/IR/SCF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -318,9 +318,12 @@ void ConditionOp::getSuccessorRegions(

void ForOp::build(OpBuilder &builder, OperationState &result, Value lb,
Value ub, Value step, ValueRange initArgs,
BodyBuilderFn bodyBuilder) {
BodyBuilderFn bodyBuilder, bool unsignedCmp) {
OpBuilder::InsertionGuard guard(builder);

if (unsignedCmp)
result.addAttribute(getUnsignedCmpAttrName(result.name),
builder.getUnitAttr());
result.addOperands({lb, ub, step});
result.addOperands(initArgs);
for (Value v : initArgs)
Expand Down Expand Up @@ -450,6 +453,9 @@ static void printInitializationList(OpAsmPrinter &p,
}

void ForOp::print(OpAsmPrinter &p) {
if (getUnsignedCmp())
p << " unsigned";

p << " " << getInductionVar() << " = " << getLowerBound() << " to "
<< getUpperBound() << " step " << getStep();

Expand All @@ -462,7 +468,8 @@ void ForOp::print(OpAsmPrinter &p) {
p.printRegion(getRegion(),
/*printEntryBlockArgs=*/false,
/*printBlockTerminators=*/!getInitArgs().empty());
p.printOptionalAttrDict((*this)->getAttrs());
p.printOptionalAttrDict((*this)->getAttrs(),
/*elidedAttrs=*/getUnsignedCmpAttrName().strref());
}

ParseResult ForOp::parse(OpAsmParser &parser, OperationState &result) {
Expand All @@ -472,6 +479,10 @@ ParseResult ForOp::parse(OpAsmParser &parser, OperationState &result) {
OpAsmParser::Argument inductionVariable;
OpAsmParser::UnresolvedOperand lb, ub, step;

if (succeeded(parser.parseOptionalKeyword("unsigned")))
result.addAttribute(getUnsignedCmpAttrName(result.name),
builder.getUnitAttr());

// Parse the induction variable followed by '='.
if (parser.parseOperand(inductionVariable.ssaName) || parser.parseEqual() ||
// Parse loop bounds.
Expand Down Expand Up @@ -562,7 +573,7 @@ ForOp::replaceWithAdditionalYields(RewriterBase &rewriter,
inits.append(newInitOperands.begin(), newInitOperands.end());
scf::ForOp newLoop = scf::ForOp::create(
rewriter, getLoc(), getLowerBound(), getUpperBound(), getStep(), inits,
[](OpBuilder &, Location, Value, ValueRange) {});
[](OpBuilder &, Location, Value, ValueRange) {}, getUnsignedCmp());
newLoop->setAttrs(getPrunedAttributeList(getOperation(), {}));

// Generate the new yield values and append them to the scf.yield operation.
Expand Down Expand Up @@ -806,7 +817,8 @@ mlir::scf::replaceAndCastForOpIterArg(RewriterBase &rewriter, scf::ForOp forOp,
// 2. Create the new forOp shell.
scf::ForOp newForOp = scf::ForOp::create(
rewriter, forOp.getLoc(), forOp.getLowerBound(), forOp.getUpperBound(),
forOp.getStep(), newIterOperands);
forOp.getStep(), newIterOperands, /*bodyBuilder=*/nullptr,
forOp.getUnsignedCmp());
newForOp->setAttrs(forOp->getAttrs());
Block &newBlock = newForOp.getRegion().front();
SmallVector<Value, 4> newBlockTransferArgs(newBlock.getArguments().begin(),
Expand Down Expand Up @@ -931,7 +943,8 @@ struct ForOpIterArgsFolder : public OpRewritePattern<scf::ForOp> {

scf::ForOp newForOp =
scf::ForOp::create(rewriter, forOp.getLoc(), forOp.getLowerBound(),
forOp.getUpperBound(), forOp.getStep(), newIterArgs);
forOp.getUpperBound(), forOp.getStep(), newIterArgs,
/*bodyBuilder=*/nullptr, forOp.getUnsignedCmp());
newForOp->setAttrs(forOp->getAttrs());
Block &newBlock = newForOp.getRegion().front();

Expand Down Expand Up @@ -989,12 +1002,12 @@ struct ForOpIterArgsFolder : public OpRewritePattern<scf::ForOp> {
/// Util function that tries to compute a constant diff between u and l.
/// Returns std::nullopt when the difference between two AffineValueMap is
/// dynamic.
static std::optional<int64_t> computeConstDiff(Value l, Value u) {
static std::optional<APInt> computeConstDiff(Value l, Value u) {
IntegerAttr clb, cub;
if (matchPattern(l, m_Constant(&clb)) && matchPattern(u, m_Constant(&cub))) {
llvm::APInt lbValue = clb.getValue();
llvm::APInt ubValue = cub.getValue();
return (ubValue - lbValue).getSExtValue();
return ubValue - lbValue;
}

// Else a simple pattern match for x + c or c + x
Expand All @@ -1003,7 +1016,7 @@ static std::optional<int64_t> computeConstDiff(Value l, Value u) {
u, m_Op<arith::AddIOp>(matchers::m_Val(l), m_ConstantInt(&diff))) ||
matchPattern(
u, m_Op<arith::AddIOp>(m_ConstantInt(&diff), matchers::m_Val(l))))
return diff.getSExtValue();
return diff;
return std::nullopt;
}

Expand All @@ -1022,13 +1035,15 @@ struct SimplifyTrivialLoops : public OpRewritePattern<ForOp> {
return success();
}

std::optional<int64_t> diff =
std::optional<APInt> diff =
computeConstDiff(op.getLowerBound(), op.getUpperBound());
if (!diff)
return failure();

// If the loop is known to have 0 iterations, remove it.
if (*diff <= 0) {
bool zeroOrLessIterations =
diff->isZero() || (!op.getUnsignedCmp() && diff->isNegative());
if (zeroOrLessIterations) {
rewriter.replaceOp(op, op.getInitArgs());
return success();
}
Expand Down Expand Up @@ -3384,9 +3399,8 @@ ParseResult scf::WhileOp::parse(OpAsmParser &parser, OperationState &result) {

if (functionType.getNumInputs() != operands.size()) {
return parser.emitError(typeLoc)
<< "expected as many input types as operands "
<< "(expected " << operands.size() << " got "
<< functionType.getNumInputs() << ")";
<< "expected as many input types as operands " << "(expected "
<< operands.size() << " got " << functionType.getNumInputs() << ")";
}

// Resolve input operands.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,8 @@ struct ForOpInterface
// Construct a new scf.for op with memref instead of tensor values.
auto newForOp = scf::ForOp::create(
rewriter, forOp.getLoc(), forOp.getLowerBound(), forOp.getUpperBound(),
forOp.getStep(), castedInitArgs);
forOp.getStep(), castedInitArgs, /*bodyBuilder=*/nullptr,
forOp.getUnsignedCmp());
newForOp->setAttrs(forOp->getAttrs());
Block *loopBody = newForOp.getBody();

Expand Down
9 changes: 6 additions & 3 deletions mlir/lib/Dialect/SCF/Transforms/ForToWhile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,12 @@ struct ForLoopLoweringPattern : public OpRewritePattern<ForOp> {
auto *beforeBlock = rewriter.createBlock(
&whileOp.getBefore(), whileOp.getBefore().begin(), lcvTypes, lcvLocs);
rewriter.setInsertionPointToStart(whileOp.getBeforeBody());
auto cmpOp = arith::CmpIOp::create(
rewriter, whileOp.getLoc(), arith::CmpIPredicate::slt,
beforeBlock->getArgument(0), forOp.getUpperBound());
arith::CmpIPredicate predicate = forOp.getUnsignedCmp()
? arith::CmpIPredicate::ult
: arith::CmpIPredicate::slt;
auto cmpOp = arith::CmpIOp::create(rewriter, whileOp.getLoc(), predicate,
beforeBlock->getArgument(0),
forOp.getUpperBound());
scf::ConditionOp::create(rewriter, whileOp.getLoc(), cmpOp.getResult(),
beforeBlock->getArguments());

Expand Down
5 changes: 5 additions & 0 deletions mlir/lib/Dialect/SCF/Transforms/LoopPipelining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -791,6 +791,11 @@ FailureOr<ForOp> mlir::scf::pipelineForLoop(RewriterBase &rewriter, ForOp forOp,
bool *modifiedIR) {
if (modifiedIR)
*modifiedIR = false;

// TODO: Add support for unsigned loops.
if (forOp.getUnsignedCmp())
return failure();

LoopPipelinerInternal pipeliner;
if (!pipeliner.initializeLoopInfo(forOp, options))
return failure();
Expand Down
4 changes: 4 additions & 0 deletions mlir/lib/Dialect/SCF/Transforms/LoopSpecialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,10 @@ struct ForLoopPeelingPattern : public OpRewritePattern<ForOp> {

LogicalResult matchAndRewrite(ForOp forOp,
PatternRewriter &rewriter) const override {
if (forOp.getUnsignedCmp())
return rewriter.notifyMatchFailure(forOp,
"unsigned loops are not supported");

// Do not peel already peeled loops.
if (forOp->hasAttr(kPeeledLoopLabel))
return failure();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ class ConvertForOpTypes
llvm::getSingleElement(adaptor.getLowerBound()),
llvm::getSingleElement(adaptor.getUpperBound()),
llvm::getSingleElement(adaptor.getStep()),
flattenValues(adaptor.getInitArgs()));
flattenValues(adaptor.getInitArgs()),
/*bodyBuilder=*/nullptr, op.getUnsignedCmp());

// Reserve whatever attributes in the original op.
newOp->setAttrs(op->getAttrs());
Expand Down
6 changes: 4 additions & 2 deletions mlir/lib/Dialect/SCF/Transforms/TileUsingInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -797,7 +797,8 @@ FailureOr<LoopLikeOpInterface> yieldTiledValuesAndReplaceLoop<scf::ForOp>(
inits.append(newInitOperands.begin(), newInitOperands.end());
auto newLoop = scf::ForOp::create(
rewriter, loc, loopOp.getLowerBound(), loopOp.getUpperBound(),
loopOp.getStep(), inits, [](OpBuilder &, Location, Value, ValueRange) {});
loopOp.getStep(), inits, [](OpBuilder &, Location, Value, ValueRange) {},
loopOp.getUnsignedCmp());

// Move the loop body to the new op.
Block *loopBody = loopOp.getBody();
Expand Down Expand Up @@ -935,7 +936,8 @@ static LogicalResult addInitOperandsToLoopNest(
auto newLoop = scf::ForOp::create(
rewriter, forLoop.getLoc(), forLoop.getLowerBound(),
forLoop.getUpperBound(), forLoop.getStep(), newInits,
[&](OpBuilder &b, Location loc, Value iv, ValueRange iterArgs) {});
[&](OpBuilder &b, Location loc, Value iv, ValueRange iterArgs) {},
forLoop.getUnsignedCmp());

// Merge the body of the new loop with the body of the old loops.
SmallVector<Value> sourceBlockArgs;
Expand Down
8 changes: 7 additions & 1 deletion mlir/lib/Dialect/SCF/Utils/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1233,6 +1233,7 @@ static void getPerfectlyNestedLoopsImpl(

static Loops stripmineSink(scf::ForOp forOp, Value factor,
ArrayRef<scf::ForOp> targets) {
assert(!forOp.getUnsignedCmp() && "unsigned loops are not supported");
auto originalStep = forOp.getStep();
auto iv = forOp.getInductionVar();

Expand All @@ -1241,6 +1242,8 @@ static Loops stripmineSink(scf::ForOp forOp, Value factor,

Loops innerLoops;
for (auto t : targets) {
assert(!t.getUnsignedCmp() && "unsigned loops are not supported");

// Save information for splicing ops out of t when done
auto begin = t.getBody()->begin();
auto nOps = t.getBody()->getOperations().size();
Expand Down Expand Up @@ -1415,6 +1418,8 @@ scf::ForallOp mlir::fuseIndependentSiblingForallLoops(scf::ForallOp target,
scf::ForOp mlir::fuseIndependentSiblingForLoops(scf::ForOp target,
scf::ForOp source,
RewriterBase &rewriter) {
assert(source.getUnsignedCmp() == target.getUnsignedCmp() &&
"incompatible signedness");
unsigned numTargetOuts = target.getNumResults();
unsigned numSourceOuts = source.getNumResults();

Expand All @@ -1428,7 +1433,8 @@ scf::ForOp mlir::fuseIndependentSiblingForLoops(scf::ForOp target,
rewriter.setInsertionPointAfter(source);
scf::ForOp fusedLoop = scf::ForOp::create(
rewriter, source.getLoc(), source.getLowerBound(), source.getUpperBound(),
source.getStep(), fusedInitArgs);
source.getStep(), fusedInitArgs, /*bodyBuilder=*/nullptr,
source.getUnsignedCmp());

// Map original induction variables and operands to those of the fused loop.
IRMapping mapping;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -533,8 +533,10 @@ static bool vectorizeStmt(PatternRewriter &rewriter, scf::ForOp forOp, VL vl,
VectorType vtp = vectorType(vl, init.getType());
Value vinit = genVectorReducInit(rewriter, loc, yield->getOperand(0),
forOp.getRegionIterArg(0), init, vtp);
forOpNew = scf::ForOp::create(rewriter, loc, forOp.getLowerBound(),
forOp.getUpperBound(), step, vinit);
forOpNew =
scf::ForOp::create(rewriter, loc, forOp.getLowerBound(),
forOp.getUpperBound(), step, vinit,
/*bodyBuilder=*/nullptr, forOp.getUnsignedCmp());
forOpNew->setAttr(
LoopEmitter::getLoopEmitterLoopAttrName(),
forOp->getAttr(LoopEmitter::getLoopEmitterLoopAttrName()));
Expand Down Expand Up @@ -605,8 +607,8 @@ struct ForOpRewriter : public OpRewritePattern<scf::ForOp> {

ForOpRewriter(MLIRContext *context, unsigned vectorLength,
bool enableVLAVectorization, bool enableSIMDIndex32)
: OpRewritePattern(context), vl{vectorLength, enableVLAVectorization,
enableSIMDIndex32} {}
: OpRewritePattern(context),
vl{vectorLength, enableVLAVectorization, enableSIMDIndex32} {}

LogicalResult matchAndRewrite(scf::ForOp op,
PatternRewriter &rewriter) const override {
Expand Down
3 changes: 2 additions & 1 deletion mlir/lib/Dialect/Vector/Transforms/VectorDistribute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1826,7 +1826,8 @@ struct WarpOpScfForOp : public WarpDistributionPattern {
rewriter.setInsertionPointAfter(newWarpOp);
auto newForOp = scf::ForOp::create(
rewriter, forOp.getLoc(), forOp.getLowerBound(), forOp.getUpperBound(),
forOp.getStep(), newForOpOperands);
forOp.getStep(), newForOpOperands, /*bodyBuilder=*/nullptr,
forOp.getUnsignedCmp());
// Next, we insert a new `WarpOp` (called inner `WarpOp`) inside the
// newly created `ForOp`. This `WarpOp` will contain all ops that were
// contained within the original `ForOp` body.
Expand Down
Loading