|
14 | 14 | #include "llvm/IR/Instructions.h"
|
15 | 15 | #include "llvm/IR/LLVMContext.h"
|
16 | 16 | #include "llvm/IR/Module.h"
|
| 17 | +#include "llvm/Support/SourceMgr.h" |
| 18 | +#include "gtest/gtest-spi.h" |
17 | 19 | #include "gtest/gtest.h"
|
18 | 20 |
|
19 | 21 | using namespace llvm;
|
@@ -192,3 +194,120 @@ TEST(SSAUpdaterBulk, Irreducible) {
|
192 | 194 | EXPECT_EQ(UpdatePhi->getIncomingValueForBlock(LoopStartBB), AddOp2);
|
193 | 195 | EXPECT_EQ(UpdatePhi->getIncomingValueForBlock(IfBB), UndefValue::get(I32Ty));
|
194 | 196 | }
|
| 197 | + |
| 198 | +TEST(SSAUpdaterBulk, SingleBBLoop) { |
| 199 | + const char *IR = R"( |
| 200 | + define void @main() { |
| 201 | + entry: |
| 202 | + br label %loop |
| 203 | + loop: |
| 204 | + %i = add i32 0, 1 |
| 205 | + %cmp = icmp slt i32 %i, 42 |
| 206 | + br i1 %cmp, label %loop, label %exit |
| 207 | + exit: |
| 208 | + ret void |
| 209 | + } |
| 210 | + )"; |
| 211 | + |
| 212 | + llvm::LLVMContext Context; |
| 213 | + llvm::SMDiagnostic Err; |
| 214 | + std::unique_ptr<llvm::Module> M = llvm::parseAssemblyString(IR, Err, Context); |
| 215 | + ASSERT_NE(M, nullptr) << "Failed to parse IR: " << Err.getMessage(); |
| 216 | + |
| 217 | + Function *F = M->getFunction("main"); |
| 218 | + auto *Entry = &F->getEntryBlock(); |
| 219 | + auto *Loop = Entry->getSingleSuccessor(); |
| 220 | + auto *I = &Loop->front(); |
| 221 | + |
| 222 | + // Rewrite first operand of "%i = add i32 0, 1" to use incoming values entry:0 |
| 223 | + // or loop:%i (that is the value of %i from the previous iteration). |
| 224 | + SSAUpdaterBulk Updater; |
| 225 | + Type *I32Ty = Type::getInt32Ty(Context); |
| 226 | + unsigned PrevI = Updater.AddVariable("i.prev", I32Ty); |
| 227 | + Updater.AddAvailableValue(PrevI, Entry, ConstantInt::get(I32Ty, 0)); |
| 228 | + Updater.AddAvailableValue(PrevI, Loop, I); |
| 229 | + Updater.AddUse(PrevI, &I->getOperandUse(0)); |
| 230 | + |
| 231 | + SmallVector<PHINode *, 1> Inserted; |
| 232 | + DominatorTree DT(*F); |
| 233 | + Updater.RewriteAllUses(&DT, &Inserted); |
| 234 | + |
| 235 | +#if 0 // Enable for debugging. |
| 236 | + Loop->dump(); |
| 237 | + // Output: |
| 238 | + // loop: ; preds = %loop, %entry |
| 239 | + // %i.prev = phi i32 [ %i.prev, %loop ], [ 0, %entry ] |
| 240 | + // %i = add i32 %i.prev, 1 |
| 241 | + // %cmp = icmp slt i32 %i, 42 |
| 242 | + // br i1 %cmp, label %loop, label %exit |
| 243 | +#endif |
| 244 | + |
| 245 | + ASSERT_EQ(Inserted.size(), 1u); |
| 246 | + PHINode *Phi = Inserted[0]; |
| 247 | + EXPECT_EQ(Phi, dyn_cast<PHINode>(I->getOperand(0))); |
| 248 | + EXPECT_EQ(Phi->getIncomingValueForBlock(Entry), ConstantInt::get(I32Ty, 0)); |
| 249 | + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(Phi->getIncomingValueForBlock(Loop), I), |
| 250 | + "Expected equality of these values"); |
| 251 | +} |
| 252 | + |
| 253 | +TEST(SSAUpdaterBulk, TwoBBLoop) { |
| 254 | + const char *IR = R"( |
| 255 | + define void @main() { |
| 256 | + entry: |
| 257 | + br label %loop_header |
| 258 | + loop_header: |
| 259 | + br label %loop |
| 260 | + loop: |
| 261 | + %i = add i32 0, 1 |
| 262 | + %cmp = icmp slt i32 %i, 42 |
| 263 | + br i1 %cmp, label %loop_header, label %exit |
| 264 | + exit: |
| 265 | + ret void |
| 266 | + } |
| 267 | + )"; |
| 268 | + |
| 269 | + llvm::LLVMContext Context; |
| 270 | + llvm::SMDiagnostic Err; |
| 271 | + std::unique_ptr<llvm::Module> M = llvm::parseAssemblyString(IR, Err, Context); |
| 272 | + ASSERT_NE(M, nullptr) << "Failed to parse IR: " << Err.getMessage(); |
| 273 | + |
| 274 | + Function *F = M->getFunction("main"); |
| 275 | + auto *Entry = &F->getEntryBlock(); |
| 276 | + auto *LoopHdr = Entry->getSingleSuccessor(); |
| 277 | + auto *Loop = LoopHdr->getSingleSuccessor(); |
| 278 | + auto *I = &Loop->front(); |
| 279 | + |
| 280 | + // Rewrite first operand of "%i = add i32 0, 1" to use incoming values entry:0 |
| 281 | + // or loop:%i (that is the value of %i from the previous iteration). |
| 282 | + SSAUpdaterBulk Updater; |
| 283 | + Type *I32Ty = Type::getInt32Ty(Context); |
| 284 | + unsigned PrevI = Updater.AddVariable("i.prev", I32Ty); |
| 285 | + Updater.AddAvailableValue(PrevI, Entry, ConstantInt::get(I32Ty, 0)); |
| 286 | + Updater.AddAvailableValue(PrevI, Loop, I); |
| 287 | + Updater.AddUse(PrevI, &I->getOperandUse(0)); |
| 288 | + |
| 289 | + SmallVector<PHINode *, 1> Inserted; |
| 290 | + DominatorTree DT(*F); |
| 291 | + Updater.RewriteAllUses(&DT, &Inserted); |
| 292 | + |
| 293 | +#if 0 // Enable for debugging. |
| 294 | + LoopHdr->dump(); |
| 295 | + Loop->dump(); |
| 296 | + // Output: |
| 297 | + // loop_header: ; preds = %loop, %entry |
| 298 | + // %i.prev = phi i32 [ %i, %loop ], [ 0, %entry ] |
| 299 | + // br label %loop |
| 300 | + // loop: ; preds = %loop_header |
| 301 | + // %i = add i32 %i, 1 |
| 302 | + // %cmp = icmp slt i32 %i, 42 |
| 303 | + // br i1 %cmp, label %loop_header, label %exit |
| 304 | +#endif |
| 305 | + |
| 306 | + ASSERT_EQ(Inserted.size(), 1u); |
| 307 | + PHINode *Phi = Inserted[0]; |
| 308 | + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(Phi, dyn_cast<PHINode>(I->getOperand(0))), |
| 309 | + "Expected equality of these values"); |
| 310 | + EXPECT_EQ(Phi->getParent(), LoopHdr); |
| 311 | + EXPECT_EQ(Phi->getIncomingValueForBlock(Entry), ConstantInt::get(I32Ty, 0)); |
| 312 | + EXPECT_EQ(Phi->getIncomingValueForBlock(Loop), I); |
| 313 | +} |
0 commit comments