@@ -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+
310381TEST (CodegenTest, Conv2dChwFchwAsSequenceTest) {
311382 MLIRContext context;
312383 RankedTensorType filterType =
0 commit comments