211 lines · cpp
1//===- PhiValuesTest.cpp - PhiValues unit tests ---------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/Analysis/PhiValues.h"10#include "llvm/IR/BasicBlock.h"11#include "llvm/IR/Constants.h"12#include "llvm/IR/Function.h"13#include "llvm/IR/Instructions.h"14#include "llvm/IR/Module.h"15#include "llvm/IR/Type.h"16#include "gtest/gtest.h"17 18using namespace llvm;19 20TEST(PhiValuesTest, SimplePhi) {21 LLVMContext C;22 Module M("PhiValuesTest", C);23 24 Type *VoidTy = Type::getVoidTy(C);25 Type *I1Ty = Type::getInt1Ty(C);26 Type *I32Ty = Type::getInt32Ty(C);27 Type *PtrTy = PointerType::get(C, 0);28 29 // Create a function with phis that do not have other phis as incoming values30 Function *F = Function::Create(FunctionType::get(VoidTy, false),31 Function::ExternalLinkage, "f", M);32 33 BasicBlock *Entry = BasicBlock::Create(C, "entry", F);34 BasicBlock *If = BasicBlock::Create(C, "if", F);35 BasicBlock *Else = BasicBlock::Create(C, "else", F);36 BasicBlock *Then = BasicBlock::Create(C, "then", F);37 BranchInst::Create(If, Else, PoisonValue::get(I1Ty), Entry);38 BranchInst::Create(Then, If);39 BranchInst::Create(Then, Else);40 41 Value *Val1 = new LoadInst(I32Ty, PoisonValue::get(PtrTy), "val1", Entry);42 Value *Val2 = new LoadInst(I32Ty, PoisonValue::get(PtrTy), "val2", Entry);43 Value *Val3 = new LoadInst(I32Ty, PoisonValue::get(PtrTy), "val3", Entry);44 Value *Val4 = new LoadInst(I32Ty, PoisonValue::get(PtrTy), "val4", Entry);45 46 PHINode *Phi1 = PHINode::Create(I32Ty, 2, "phi1", Then);47 Phi1->addIncoming(Val1, If);48 Phi1->addIncoming(Val2, Else);49 PHINode *Phi2 = PHINode::Create(I32Ty, 2, "phi2", Then);50 Phi2->addIncoming(Val1, If);51 Phi2->addIncoming(Val3, Else);52 53 PhiValues PV(*F);54 PhiValues::ValueSet Vals;55 56 // Check that simple usage works57 Vals = PV.getValuesForPhi(Phi1);58 EXPECT_EQ(Vals.size(), 2u);59 EXPECT_TRUE(Vals.count(Val1));60 EXPECT_TRUE(Vals.count(Val2));61 Vals = PV.getValuesForPhi(Phi2);62 EXPECT_EQ(Vals.size(), 2u);63 EXPECT_TRUE(Vals.count(Val1));64 EXPECT_TRUE(Vals.count(Val3));65 66 // Check that values are updated when one value is replaced with another67 Val1->replaceAllUsesWith(Val4);68 PV.invalidateValue(Val1);69 Vals = PV.getValuesForPhi(Phi1);70 EXPECT_EQ(Vals.size(), 2u);71 EXPECT_TRUE(Vals.count(Val4));72 EXPECT_TRUE(Vals.count(Val2));73 Vals = PV.getValuesForPhi(Phi2);74 EXPECT_EQ(Vals.size(), 2u);75 EXPECT_TRUE(Vals.count(Val4));76 EXPECT_TRUE(Vals.count(Val3));77 78 // Check that setting in incoming value directly updates the values79 Phi1->setIncomingValue(0, Val1);80 PV.invalidateValue(Phi1);81 Vals = PV.getValuesForPhi(Phi1);82 EXPECT_EQ(Vals.size(), 2u);83 EXPECT_TRUE(Vals.count(Val1));84 EXPECT_TRUE(Vals.count(Val2));85}86 87TEST(PhiValuesTest, DependentPhi) {88 LLVMContext C;89 Module M("PhiValuesTest", C);90 91 Type *VoidTy = Type::getVoidTy(C);92 Type *I1Ty = Type::getInt1Ty(C);93 Type *I32Ty = Type::getInt32Ty(C);94 Type *PtrTy = PointerType::get(C, 0);95 96 // Create a function with a phi that has another phi as an incoming value97 Function *F = Function::Create(FunctionType::get(VoidTy, false),98 Function::ExternalLinkage, "f", M);99 100 BasicBlock *Entry = BasicBlock::Create(C, "entry", F);101 BasicBlock *If1 = BasicBlock::Create(C, "if1", F);102 BasicBlock *Else1 = BasicBlock::Create(C, "else1", F);103 BasicBlock *Then = BasicBlock::Create(C, "then", F);104 BasicBlock *If2 = BasicBlock::Create(C, "if2", F);105 BasicBlock *Else2 = BasicBlock::Create(C, "else2", F);106 BasicBlock *End = BasicBlock::Create(C, "then", F);107 BranchInst::Create(If1, Else1, PoisonValue::get(I1Ty), Entry);108 BranchInst::Create(Then, If1);109 BranchInst::Create(Then, Else1);110 BranchInst::Create(If2, Else2, PoisonValue::get(I1Ty), Then);111 BranchInst::Create(End, If2);112 BranchInst::Create(End, Else2);113 114 Value *Val1 = new LoadInst(I32Ty, PoisonValue::get(PtrTy), "val1", Entry);115 Value *Val2 = new LoadInst(I32Ty, PoisonValue::get(PtrTy), "val2", Entry);116 Value *Val3 = new LoadInst(I32Ty, PoisonValue::get(PtrTy), "val3", Entry);117 Value *Val4 = new LoadInst(I32Ty, PoisonValue::get(PtrTy), "val4", Entry);118 119 PHINode *Phi1 = PHINode::Create(I32Ty, 2, "phi1", Then);120 Phi1->addIncoming(Val1, If1);121 Phi1->addIncoming(Val2, Else1);122 PHINode *Phi2 = PHINode::Create(I32Ty, 2, "phi2", Then);123 Phi2->addIncoming(Val2, If1);124 Phi2->addIncoming(Val3, Else1);125 PHINode *Phi3 = PHINode::Create(I32Ty, 2, "phi3", End);126 Phi3->addIncoming(Phi1, If2);127 Phi3->addIncoming(Val3, Else2);128 129 PhiValues PV(*F);130 PhiValues::ValueSet Vals;131 132 // Check that simple usage works133 Vals = PV.getValuesForPhi(Phi1);134 EXPECT_EQ(Vals.size(), 2u);135 EXPECT_TRUE(Vals.count(Val1));136 EXPECT_TRUE(Vals.count(Val2));137 Vals = PV.getValuesForPhi(Phi2);138 EXPECT_EQ(Vals.size(), 2u);139 EXPECT_TRUE(Vals.count(Val2));140 EXPECT_TRUE(Vals.count(Val3));141 Vals = PV.getValuesForPhi(Phi3);142 EXPECT_EQ(Vals.size(), 3u);143 EXPECT_TRUE(Vals.count(Val1));144 EXPECT_TRUE(Vals.count(Val2));145 EXPECT_TRUE(Vals.count(Val3));146 147 // Check that changing an incoming value in the dependent phi changes the depending phi148 Phi1->setIncomingValue(0, Val4);149 PV.invalidateValue(Phi1);150 Vals = PV.getValuesForPhi(Phi1);151 EXPECT_EQ(Vals.size(), 2u);152 EXPECT_TRUE(Vals.count(Val4));153 EXPECT_TRUE(Vals.count(Val2));154 Vals = PV.getValuesForPhi(Phi2);155 EXPECT_EQ(Vals.size(), 2u);156 EXPECT_TRUE(Vals.count(Val2));157 EXPECT_TRUE(Vals.count(Val3));158 Vals = PV.getValuesForPhi(Phi3);159 EXPECT_EQ(Vals.size(), 3u);160 EXPECT_TRUE(Vals.count(Val4));161 EXPECT_TRUE(Vals.count(Val2));162 EXPECT_TRUE(Vals.count(Val3));163 164 // Check that replacing an incoming phi with a value works165 Phi3->setIncomingValue(0, Val1);166 PV.invalidateValue(Phi3);167 Vals = PV.getValuesForPhi(Phi1);168 EXPECT_EQ(Vals.size(), 2u);169 EXPECT_TRUE(Vals.count(Val4));170 EXPECT_TRUE(Vals.count(Val2));171 Vals = PV.getValuesForPhi(Phi2);172 EXPECT_EQ(Vals.size(), 2u);173 EXPECT_TRUE(Vals.count(Val2));174 EXPECT_TRUE(Vals.count(Val3));175 Vals = PV.getValuesForPhi(Phi3);176 EXPECT_EQ(Vals.size(), 2u);177 EXPECT_TRUE(Vals.count(Val1));178 EXPECT_TRUE(Vals.count(Val3));179 180 // Check that adding a phi as an incoming value works181 Phi3->setIncomingValue(1, Phi2);182 PV.invalidateValue(Phi3);183 Vals = PV.getValuesForPhi(Phi1);184 EXPECT_EQ(Vals.size(), 2u);185 EXPECT_TRUE(Vals.count(Val4));186 EXPECT_TRUE(Vals.count(Val2));187 Vals = PV.getValuesForPhi(Phi2);188 EXPECT_EQ(Vals.size(), 2u);189 EXPECT_TRUE(Vals.count(Val2));190 EXPECT_TRUE(Vals.count(Val3));191 Vals = PV.getValuesForPhi(Phi3);192 EXPECT_EQ(Vals.size(), 3u);193 EXPECT_TRUE(Vals.count(Val1));194 EXPECT_TRUE(Vals.count(Val2));195 EXPECT_TRUE(Vals.count(Val3));196 197 // Check that replacing an incoming phi then deleting it works198 Phi3->setIncomingValue(1, Val2);199 PV.invalidateValue(Phi2);200 Phi2->eraseFromParent();201 PV.invalidateValue(Phi3);202 Vals = PV.getValuesForPhi(Phi1);203 EXPECT_EQ(Vals.size(), 2u);204 EXPECT_TRUE(Vals.count(Val4));205 EXPECT_TRUE(Vals.count(Val2));206 Vals = PV.getValuesForPhi(Phi3);207 EXPECT_EQ(Vals.size(), 2u);208 EXPECT_TRUE(Vals.count(Val1));209 EXPECT_TRUE(Vals.count(Val2));210}211