Skip to content

Commit 3f4a3b5

Browse files
committed
avoid casting
1 parent 60a532d commit 3f4a3b5

2 files changed

Lines changed: 92 additions & 12 deletions

File tree

lib/Utils/Layout/Codegen.cpp

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -292,19 +292,26 @@ Value buildIslExpr(isl_ast_expr* expr, std::map<std::string, Value> ivToValue,
292292
args = extendToCommonWidth(b, args, createdOpCallback);
293293
}
294294

295+
// Keep the comparison result as an i1. ISL keeps boolean and integer
296+
// AST expressions distinct -- a comparison only ever feeds and/or
297+
// (logical), select, or an `if` guard, never integer arithmetic -- so
298+
// there is no need to widen it to an index 0/1.
295299
auto op =
296300
arith::CmpIOp::create(b, islCmpToMlirAttr[type], args[0], args[1]);
297301
createdOpCallback(op);
298-
auto indexCastOp = arith::IndexCastOp::create(b, b.getIndexType(), op);
299-
createdOpCallback(indexCastOp);
300-
return indexCastOp->getResult(0);
302+
return op->getResult(0);
301303
} else if (type == isl_ast_op_select) {
302-
// Select op
304+
// Select op. The condition is a boolean expression, so it is already an
305+
// i1; an index-typed condition from another path is still cast.
303306
SmallVector<Value> args = getArgs(expr);
304-
auto condI1 = arith::IndexCastOp::create(b, b.getI1Type(), args[0]);
305-
auto op = arith::SelectOp::create(b, condI1, args[1], args[2]);
307+
Value cond = args[0];
308+
if (!cond.getType().isInteger(1)) {
309+
auto condI1 = arith::IndexCastOp::create(b, b.getI1Type(), cond);
310+
createdOpCallback(condI1);
311+
cond = condI1->getResult(0);
312+
}
313+
auto op = arith::SelectOp::create(b, cond, args[1], args[2]);
306314
createdOpCallback(op);
307-
createdOpCallback(condI1);
308315
return op->getResult(0);
309316
}
310317

@@ -494,15 +501,17 @@ FailureOr<scf::ValueVector> MLIRLoopNestGenerator::visitAstNodeIf(
494501
SmallVector<Value> incomingIterArgs(currentIterArgs_.begin(),
495502
currentIterArgs_.end());
496503

497-
// Build scf if operation with the result types of the iter args
498-
// Convert condVal to an i1
499-
auto condValI1 =
500-
arith::IndexCastOp::create(builder_, builder_.getI1Type(), condVal);
504+
Value condValI1 = condVal;
505+
if (!condValI1.getType().isInteger(1)) {
506+
auto cast =
507+
arith::IndexCastOp::create(builder_, builder_.getI1Type(), condVal);
508+
createdOpCallback_(cast);
509+
condValI1 = cast->getResult(0);
510+
}
501511
auto ifOp = scf::IfOp::create(builder_, currentLoc_,
502512
TypeRange(incomingIterArgs), condValI1,
503513
/*addThenBlock=*/true, /*addElseBlock=*/true);
504514
createdOpCallback_(ifOp);
505-
createdOpCallback_(condValI1);
506515

507516
isl_ast_node* thenNode = isl_ast_node_if_get_then_node(node);
508517
builder_.setInsertionPointToStart(&ifOp.getThenRegion().front());

lib/Utils/Layout/CodegenTest.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,77 @@ TEST(CodegenTest, IfWithNestedForElseYieldDominance) {
307307
moduleOp.erase();
308308
}
309309

310+
TEST(CodegenTest, BooleanExprsStayI1) {
311+
MLIRContext context;
312+
context
313+
.loadDialect<scf::SCFDialect, arith::ArithDialect, func::FuncDialect>();
314+
315+
// Same relation as IfWithNestedForElseYieldDominance: its floor-div
316+
// structure makes ISL emit `if` guards inside the loop nest.
317+
auto relation = getIntegerRelationFromIslStr(
318+
"{ [i0, i1, i2] -> [ct, slot] : (30i0 - 32i1 - i2 + ct) mod 1024 = 0 and "
319+
"0 <= i0 <= 63 and 0 <= i1 <= 16 and 0 <= i2 <= 2 and 0 <= ct <= 1023 "
320+
"and 0 <= slot <= 4095 and 2048*floor((-30 - 30i0 + slot)/2048) >= -3967 "
321+
"+ slot and 2048*floor((-30 - 30i0 + slot)/2048) >= -2079 - 30i0 + i2 + "
322+
"slot and 2048*floor((-30 - 30i0 + slot)/2048) <= -2048 - 30i0 + slot "
323+
"and 2048*floor((-30 - 30i0 + slot)/2048) <= -2048 - 30i0 + i2 + slot "
324+
"and 2048*floor((-30 - 30i0 + slot)/2048) <= -2048 + slot }");
325+
ASSERT_TRUE(succeeded(relation));
326+
327+
OpBuilder builder(&context);
328+
auto moduleOp = ModuleOp::create(builder.getUnknownLoc());
329+
builder.setInsertionPointToEnd(moduleOp.getBody());
330+
331+
auto funcType = builder.getFunctionType({}, {});
332+
auto funcOp = func::FuncOp::create(builder, builder.getUnknownLoc(),
333+
"test_func", funcType);
334+
auto* block = funcOp.addEntryBlock();
335+
builder.setInsertionPointToStart(block);
336+
337+
ImplicitLocOpBuilder locBuilder(builder.getUnknownLoc(), builder);
338+
auto init = arith::ConstantIntOp::create(locBuilder, 0, 32);
339+
340+
MLIRLoopNestGenerator generator(locBuilder);
341+
auto bodyBuilder = [](OpBuilder& b, Location loc, ValueRange ivs,
342+
ValueRange iterArgs) {
343+
return scf::ValueVector(iterArgs.begin(), iterArgs.end());
344+
};
345+
346+
SmallVector<int> domainIndicesToSchedule = {0, 1};
347+
auto result = generator.generateForLoop(relation.value(), {init.getResult()},
348+
bodyBuilder, domainIndicesToSchedule);
349+
ASSERT_TRUE(succeeded(result));
350+
351+
func::ReturnOp::create(locBuilder, ValueRange{});
352+
353+
ASSERT_TRUE(succeeded(verify(moduleOp)));
354+
355+
// Each guard is an i1 taken straight from the comparison logic.
356+
int numIfs = 0;
357+
funcOp.walk([&](scf::IfOp ifOp) {
358+
++numIfs;
359+
Value cond = ifOp.getCondition();
360+
EXPECT_TRUE(cond.getType().isInteger(1));
361+
Operation* condOp = cond.getDefiningOp();
362+
EXPECT_TRUE(condOp != nullptr &&
363+
(isa<arith::CmpIOp, arith::AndIOp, arith::OrIOp>(condOp)))
364+
<< "scf.if guard should come from comparison logic, got "
365+
<< (condOp ? condOp->getName().getStringRef().str() : "block argument");
366+
});
367+
// Guard against the checks above going vacuous if ISL stops emitting `if`s.
368+
EXPECT_GT(numIfs, 0) << "relation generated no scf.if guards";
369+
370+
// No boolean is round-tripped through index.
371+
funcOp.walk([&](arith::IndexCastOp castOp) {
372+
EXPECT_FALSE(castOp->getOperand(0).getType().isInteger(1))
373+
<< "index_cast widens an i1 boolean to index";
374+
EXPECT_FALSE(castOp->getResult(0).getType().isInteger(1))
375+
<< "index_cast narrows an index back to an i1 boolean";
376+
});
377+
378+
moduleOp.erase();
379+
}
380+
310381
TEST(CodegenTest, Conv2dChwFchwAsSequenceTest) {
311382
MLIRContext context;
312383
RankedTensorType filterType =

0 commit comments

Comments
 (0)