llvm/unittests/Transforms/Utils/SSAUpdaterBulk.cpp
Michael Zolotukhin 1efc1f1838 Revert "Revert r330403 and r330413."
Reapply the patches with a fix. Thanks Ilya and Hans for the reproducer!
This reverts commit r330416.

The issue was that removing predecessors invalidated uses that we stored
for rewrite. The fix is to finish manipulating with CFG before we select
uses for rewrite.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@330431 91177308-0d34-0410-b5e6-96231b3b80d8
2018-04-20 13:34:32 +00:00

196 lines
7.1 KiB
C++

//===- SSAUpdaterBulk.cpp - Unit tests for SSAUpdaterBulk -----------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/Utils/SSAUpdaterBulk.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "gtest/gtest.h"
using namespace llvm;
TEST(SSAUpdaterBulk, SimpleMerge) {
SSAUpdaterBulk Updater;
LLVMContext C;
Module M("SSAUpdaterTest", C);
IRBuilder<> B(C);
Type *I32Ty = B.getInt32Ty();
auto *F = Function::Create(FunctionType::get(B.getVoidTy(), {I32Ty}, false),
GlobalValue::ExternalLinkage, "F", &M);
// Generate a simple program:
// if:
// br i1 true, label %true, label %false
// true:
// %1 = add i32 %0, 1
// %2 = sub i32 %0, 2
// br label %merge
// false:
// %3 = add i32 %0, 3
// %4 = sub i32 %0, 4
// br label %merge
// merge:
// %5 = add i32 %1, 5
// %6 = add i32 %3, 6
// %7 = add i32 %2, %4
// %8 = sub i32 %2, %4
Argument *FirstArg = &*(F->arg_begin());
BasicBlock *IfBB = BasicBlock::Create(C, "if", F);
BasicBlock *TrueBB = BasicBlock::Create(C, "true", F);
BasicBlock *FalseBB = BasicBlock::Create(C, "false", F);
BasicBlock *MergeBB = BasicBlock::Create(C, "merge", F);
B.SetInsertPoint(IfBB);
B.CreateCondBr(B.getTrue(), TrueBB, FalseBB);
B.SetInsertPoint(TrueBB);
Value *AddOp1 = B.CreateAdd(FirstArg, ConstantInt::get(I32Ty, 1));
Value *SubOp1 = B.CreateSub(FirstArg, ConstantInt::get(I32Ty, 2));
B.CreateBr(MergeBB);
B.SetInsertPoint(FalseBB);
Value *AddOp2 = B.CreateAdd(FirstArg, ConstantInt::get(I32Ty, 3));
Value *SubOp2 = B.CreateSub(FirstArg, ConstantInt::get(I32Ty, 4));
B.CreateBr(MergeBB);
B.SetInsertPoint(MergeBB, MergeBB->begin());
auto *I1 = cast<Instruction>(B.CreateAdd(AddOp1, ConstantInt::get(I32Ty, 5)));
auto *I2 = cast<Instruction>(B.CreateAdd(AddOp2, ConstantInt::get(I32Ty, 6)));
auto *I3 = cast<Instruction>(B.CreateAdd(SubOp1, SubOp2));
auto *I4 = cast<Instruction>(B.CreateSub(SubOp1, SubOp2));
// Now rewrite uses in instructions %5, %6, %7. They need to use a phi, which
// SSAUpdater should insert into %merge.
// Intentionally don't touch %8 to see that SSAUpdater only changes
// instructions that were explicitly specified.
unsigned VarNum = Updater.AddVariable("a", I32Ty);
Updater.AddAvailableValue(VarNum, TrueBB, AddOp1);
Updater.AddAvailableValue(VarNum, FalseBB, AddOp2);
Updater.AddUse(VarNum, &I1->getOperandUse(0));
Updater.AddUse(VarNum, &I2->getOperandUse(0));
VarNum = Updater.AddVariable("b", I32Ty);
Updater.AddAvailableValue(VarNum, TrueBB, SubOp1);
Updater.AddAvailableValue(VarNum, FalseBB, SubOp2);
Updater.AddUse(VarNum, &I3->getOperandUse(0));
Updater.AddUse(VarNum, &I3->getOperandUse(1));
DominatorTree DT(*F);
Updater.RewriteAllUses(&DT);
// Check how %5 and %6 were rewritten.
PHINode *UpdatePhiA = dyn_cast_or_null<PHINode>(I1->getOperand(0));
EXPECT_NE(UpdatePhiA, nullptr);
EXPECT_EQ(UpdatePhiA->getIncomingValueForBlock(TrueBB), AddOp1);
EXPECT_EQ(UpdatePhiA->getIncomingValueForBlock(FalseBB), AddOp2);
EXPECT_EQ(UpdatePhiA, dyn_cast_or_null<PHINode>(I1->getOperand(0)));
// Check how %7 was rewritten.
PHINode *UpdatePhiB = dyn_cast_or_null<PHINode>(I3->getOperand(0));
EXPECT_EQ(UpdatePhiB->getIncomingValueForBlock(TrueBB), SubOp1);
EXPECT_EQ(UpdatePhiB->getIncomingValueForBlock(FalseBB), SubOp2);
EXPECT_EQ(UpdatePhiB, dyn_cast_or_null<PHINode>(I3->getOperand(1)));
// Check that %8 was kept untouched.
EXPECT_EQ(I4->getOperand(0), SubOp1);
EXPECT_EQ(I4->getOperand(1), SubOp2);
}
TEST(SSAUpdaterBulk, Irreducible) {
SSAUpdaterBulk Updater;
LLVMContext C;
Module M("SSAUpdaterTest", C);
IRBuilder<> B(C);
Type *I32Ty = B.getInt32Ty();
auto *F = Function::Create(FunctionType::get(B.getVoidTy(), {I32Ty}, false),
GlobalValue::ExternalLinkage, "F", &M);
// Generate a small program with a multi-entry loop:
// if:
// %1 = add i32 %0, 1
// br i1 true, label %loopmain, label %loopstart
//
// loopstart:
// %2 = add i32 %0, 2
// br label %loopmain
//
// loopmain:
// %3 = add i32 %1, 3
// br i1 true, label %loopstart, label %afterloop
//
// afterloop:
// %4 = add i32 %2, 4
// ret i32 %0
Argument *FirstArg = &*F->arg_begin();
BasicBlock *IfBB = BasicBlock::Create(C, "if", F);
BasicBlock *LoopStartBB = BasicBlock::Create(C, "loopstart", F);
BasicBlock *LoopMainBB = BasicBlock::Create(C, "loopmain", F);
BasicBlock *AfterLoopBB = BasicBlock::Create(C, "afterloop", F);
B.SetInsertPoint(IfBB);
Value *AddOp1 = B.CreateAdd(FirstArg, ConstantInt::get(I32Ty, 1));
B.CreateCondBr(B.getTrue(), LoopMainBB, LoopStartBB);
B.SetInsertPoint(LoopStartBB);
Value *AddOp2 = B.CreateAdd(FirstArg, ConstantInt::get(I32Ty, 2));
B.CreateBr(LoopMainBB);
B.SetInsertPoint(LoopMainBB);
auto *I1 = cast<Instruction>(B.CreateAdd(AddOp1, ConstantInt::get(I32Ty, 3)));
B.CreateCondBr(B.getTrue(), LoopStartBB, AfterLoopBB);
B.SetInsertPoint(AfterLoopBB);
auto *I2 = cast<Instruction>(B.CreateAdd(AddOp2, ConstantInt::get(I32Ty, 4)));
ReturnInst *Return = B.CreateRet(FirstArg);
// Now rewrite uses in instructions %3, %4, and 'ret i32 %0'. Only %4 needs a
// new phi, others should be able to work with existing values.
// The phi for %4 should be inserted into LoopMainBB and should look like
// this:
// %b = phi i32 [ %2, %loopstart ], [ undef, %if ]
// No other rewrites should be made.
// Add use in %3.
unsigned VarNum = Updater.AddVariable("c", I32Ty);
Updater.AddAvailableValue(VarNum, IfBB, AddOp1);
Updater.AddUse(VarNum, &I1->getOperandUse(0));
// Add use in %4.
VarNum = Updater.AddVariable("b", I32Ty);
Updater.AddAvailableValue(VarNum, LoopStartBB, AddOp2);
Updater.AddUse(VarNum, &I2->getOperandUse(0));
// Add use in the return instruction.
VarNum = Updater.AddVariable("a", I32Ty);
Updater.AddAvailableValue(VarNum, &F->getEntryBlock(), FirstArg);
Updater.AddUse(VarNum, &Return->getOperandUse(0));
// Save all inserted phis into a vector.
SmallVector<PHINode *, 8> Inserted;
DominatorTree DT(*F);
Updater.RewriteAllUses(&DT, &Inserted);
// Only one phi should have been inserted.
EXPECT_EQ(Inserted.size(), 1u);
// I1 and Return should use the same values as they used before.
EXPECT_EQ(I1->getOperand(0), AddOp1);
EXPECT_EQ(Return->getOperand(0), FirstArg);
// I2 should use the new phi.
PHINode *UpdatePhi = dyn_cast_or_null<PHINode>(I2->getOperand(0));
EXPECT_NE(UpdatePhi, nullptr);
EXPECT_EQ(UpdatePhi->getIncomingValueForBlock(LoopStartBB), AddOp2);
EXPECT_EQ(UpdatePhi->getIncomingValueForBlock(IfBB), UndefValue::get(I32Ty));
}