llvm.org GIT mirror llvm / fe51c81
[SCEV] Be careful with nuw/nsw/exact in InsertBinop InsertBinop tries to find an appropriate instruction instead of creating a new instruction. When it checks whether instruction is the same as we need to create it ignores nuw/nsw/exact flags. It leads to invalid behavior when poison instruction can be used when it was not expected. Specifically, for example Expander expands the SCEV built for instruction %a = add i32 %v, 1 It is possible that InsertBinop can find an instruction % b = add nuw nsw i32 %v, 1 and will use it instead of version w/o nuw nsw. It is incorrect. The patch conservatively ignores all instructions with any of poison flags installed. Reviewers: sanjoy, mkazantsev, sebpop, jbhateja Reviewed By: sanjoy Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D41576 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@321475 91177308-0d34-0410-b5e6-96231b3b80d8 Serguei Katkov 2 years ago
2 changed file(s) with 118 addition(s) and 1 deletion(s). Raw diff Collapse all Expand all
186186 // generated code.
187187 if (isa(IP))
188188 ScanLimit++;
189
190 // Conservatively, do not use any instruction which has any of wrap/exact
191 // flags installed.
192 // TODO: Instead of simply disable poison instructions we can be clever
193 // here and match SCEV to this instruction.
194 auto canGeneratePoison = [](Instruction *I) {
195 if (isa(I) &&
196 (I->hasNoSignedWrap() || I->hasNoUnsignedWrap()))
197 return true;
198 if (isa(I) && I->isExact())
199 return true;
200 return false;
201 };
189202 if (IP->getOpcode() == (unsigned)Opcode && IP->getOperand(0) == LHS &&
190 IP->getOperand(1) == RHS)
203 IP->getOperand(1) == RHS && !canGeneratePoison(&*IP))
191204 return &*IP;
192205 if (IP == BlockBegin) break;
193206 }
11831183 EXPECT_TRUE(isSafeToExpandAt(AR, Post->getTerminator(), SE));
11841184 }
11851185
1186 // Check that SCEV expander does not use the nuw instruction
1187 // for expansion.
1188 TEST_F(ScalarEvolutionsTest, SCEVExpanderNUW) {
1189 /*
1190 * Create the following code:
1191 * func(i64 %a)
1192 * entry:
1193 * br false, label %exit, label %body
1194 * body:
1195 * %s1 = add i64 %a, -1
1196 * br label %exit
1197 * exit:
1198 * %s = add nuw i64 %a, -1
1199 * ret %s
1200 */
1201
1202 // Create a module.
1203 Module M("SCEVExpanderNUW", Context);
1204
1205 Type *T_int64 = Type::getInt64Ty(Context);
1206
1207 FunctionType *FTy =
1208 FunctionType::get(Type::getVoidTy(Context), { T_int64 }, false);
1209 Function *F = cast(M.getOrInsertFunction("func", FTy));
1210 Argument *Arg = &*F->arg_begin();
1211 ConstantInt *C = ConstantInt::get(Context, APInt(64, -1));
1212
1213 BasicBlock *Entry = BasicBlock::Create(Context, "entry", F);
1214 BasicBlock *Body = BasicBlock::Create(Context, "body", F);
1215 BasicBlock *Exit = BasicBlock::Create(Context, "exit", F);
1216
1217 IRBuilder<> Builder(Entry);
1218 ConstantInt *Cond = ConstantInt::get(Context, APInt(1, 0));
1219 Builder.CreateCondBr(Cond, Exit, Body);
1220
1221 Builder.SetInsertPoint(Body);
1222 auto *S1 = cast(Builder.CreateAdd(Arg, C, "add"));
1223 Builder.CreateBr(Exit);
1224
1225 Builder.SetInsertPoint(Exit);
1226 auto *S2 = cast(Builder.CreateAdd(Arg, C, "add"));
1227 S2->setHasNoUnsignedWrap(true);
1228 auto *R = cast(Builder.CreateRetVoid());
1229
1230 ScalarEvolution SE = buildSE(*F);
1231 const SCEV *S = SE.getSCEV(S1);
1232 EXPECT_TRUE(isa(S));
1233 SCEVExpander Exp(SE, M.getDataLayout(), "expander");
1234 auto *I = cast(Exp.expandCodeFor(S, nullptr, R));
1235 EXPECT_FALSE(I->hasNoUnsignedWrap());
1236 }
1237
1238 // Check that SCEV expander does not use the nsw instruction
1239 // for expansion.
1240 TEST_F(ScalarEvolutionsTest, SCEVExpanderNSW) {
1241 /*
1242 * Create the following code:
1243 * func(i64 %a)
1244 * entry:
1245 * br false, label %exit, label %body
1246 * body:
1247 * %s1 = add i64 %a, -1
1248 * br label %exit
1249 * exit:
1250 * %s = add nsw i64 %a, -1
1251 * ret %s
1252 */
1253
1254 // Create a module.
1255 Module M("SCEVExpanderNSW", Context);
1256
1257 Type *T_int64 = Type::getInt64Ty(Context);
1258
1259 FunctionType *FTy =
1260 FunctionType::get(Type::getVoidTy(Context), { T_int64 }, false);
1261 Function *F = cast(M.getOrInsertFunction("func", FTy));
1262 Argument *Arg = &*F->arg_begin();
1263 ConstantInt *C = ConstantInt::get(Context, APInt(64, -1));
1264
1265 BasicBlock *Entry = BasicBlock::Create(Context, "entry", F);
1266 BasicBlock *Body = BasicBlock::Create(Context, "body", F);
1267 BasicBlock *Exit = BasicBlock::Create(Context, "exit", F);
1268
1269 IRBuilder<> Builder(Entry);
1270 ConstantInt *Cond = ConstantInt::get(Context, APInt(1, 0));
1271 Builder.CreateCondBr(Cond, Exit, Body);
1272
1273 Builder.SetInsertPoint(Body);
1274 auto *S1 = cast(Builder.CreateAdd(Arg, C, "add"));
1275 Builder.CreateBr(Exit);
1276
1277 Builder.SetInsertPoint(Exit);
1278 auto *S2 = cast(Builder.CreateAdd(Arg, C, "add"));
1279 S2->setHasNoSignedWrap(true);
1280 auto *R = cast(Builder.CreateRetVoid());
1281
1282 ScalarEvolution SE = buildSE(*F);
1283 const SCEV *S = SE.getSCEV(S1);
1284 EXPECT_TRUE(isa(S));
1285 SCEVExpander Exp(SE, M.getDataLayout(), "expander");
1286 auto *I = cast(Exp.expandCodeFor(S, nullptr, R));
1287 EXPECT_FALSE(I->hasNoSignedWrap());
1288 }
1289
11861290 } // end anonymous namespace
11871291 } // end namespace llvm