1 //===- SparsePropagation.cpp - Unit tests for the generic solver ----------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "llvm/Analysis/SparsePropagation.h"
11 #include "llvm/ADT/PointerIntPair.h"
12 #include "llvm/IR/CallSite.h"
13 #include "llvm/IR/IRBuilder.h"
14 #include "gtest/gtest.h"
15 using namespace llvm;
16 
17 namespace {
18 /// To enable interprocedural analysis, we assign LLVM values to the following
19 /// groups. The register group represents SSA registers, the return group
20 /// represents the return values of functions, and the memory group represents
21 /// in-memory values. An LLVM Value can technically be in more than one group.
22 /// It's necessary to distinguish these groups so we can, for example, track a
23 /// global variable separately from the value stored at its location.
24 enum class IPOGrouping { Register, Return, Memory };
25 
26 /// Our LatticeKeys are PointerIntPairs composed of LLVM values and groupings.
27 /// The PointerIntPair header provides a DenseMapInfo specialization, so using
28 /// these as LatticeKeys is fine.
29 using TestLatticeKey = PointerIntPair<Value *, 2, IPOGrouping>;
30 } // namespace
31 
32 namespace llvm {
33 /// A specialization of LatticeKeyInfo for TestLatticeKeys. The generic solver
34 /// must translate between LatticeKeys and LLVM Values when adding Values to
35 /// its work list and inspecting the state of control-flow related values.
36 template <> struct LatticeKeyInfo<TestLatticeKey> {
37   static inline Value *getValueFromLatticeKey(TestLatticeKey Key) {
38     return Key.getPointer();
39   }
40   static inline TestLatticeKey getLatticeKeyFromValue(Value *V) {
41     return TestLatticeKey(V, IPOGrouping::Register);
42   }
43 };
44 } // namespace llvm
45 
46 namespace {
47 /// This class defines a simple test lattice value that could be used for
48 /// solving problems similar to constant propagation. The value is maintained
49 /// as a PointerIntPair.
50 class TestLatticeVal {
51 public:
52   /// The states of the lattices value. Only the ConstantVal state is
53   /// interesting; the rest are special states used by the generic solver. The
54   /// UntrackedVal state differs from the other three in that the generic
55   /// solver uses it to avoid doing unnecessary work. In particular, when a
56   /// value moves to the UntrackedVal state, it's users are not notified.
57   enum TestLatticeStateTy {
58     UndefinedVal,
59     ConstantVal,
60     OverdefinedVal,
61     UntrackedVal
62   };
63 
64   TestLatticeVal() : LatticeVal(nullptr, UndefinedVal) {}
65   TestLatticeVal(Constant *C, TestLatticeStateTy State)
66       : LatticeVal(C, State) {}
67 
68   /// Return true if this lattice value is in the Constant state. This is used
69   /// for checking the solver results.
70   bool isConstant() const { return LatticeVal.getInt() == ConstantVal; }
71 
72   /// Return true if this lattice value is in the Overdefined state. This is
73   /// used for checking the solver results.
74   bool isOverdefined() const { return LatticeVal.getInt() == OverdefinedVal; }
75 
76   bool operator==(const TestLatticeVal &RHS) const {
77     return LatticeVal == RHS.LatticeVal;
78   }
79 
80   bool operator!=(const TestLatticeVal &RHS) const {
81     return LatticeVal != RHS.LatticeVal;
82   }
83 
84 private:
85   /// A simple lattice value type for problems similar to constant propagation.
86   /// It holds the constant value and the lattice state.
87   PointerIntPair<const Constant *, 2, TestLatticeStateTy> LatticeVal;
88 };
89 
90 /// This class defines a simple test lattice function that could be used for
91 /// solving problems similar to constant propagation. The test lattice differs
92 /// from a "real" lattice in a few ways. First, it initializes all return
93 /// values, values stored in global variables, and arguments in the undefined
94 /// state. This means that there are no limitations on what we can track
95 /// interprocedurally. For simplicity, all global values in the tests will be
96 /// given internal linkage, since this is not something this lattice function
97 /// tracks. Second, it only handles the few instructions necessary for the
98 /// tests.
99 class TestLatticeFunc
100     : public AbstractLatticeFunction<TestLatticeKey, TestLatticeVal> {
101 public:
102   /// Construct a new test lattice function with special values for the
103   /// Undefined, Overdefined, and Untracked states.
104   TestLatticeFunc()
105       : AbstractLatticeFunction(
106             TestLatticeVal(nullptr, TestLatticeVal::UndefinedVal),
107             TestLatticeVal(nullptr, TestLatticeVal::OverdefinedVal),
108             TestLatticeVal(nullptr, TestLatticeVal::UntrackedVal)) {}
109 
110   /// Compute and return a TestLatticeVal for the given TestLatticeKey. For the
111   /// test analysis, a LatticeKey will begin in the undefined state, unless it
112   /// represents an LLVM Constant in the register grouping.
113   TestLatticeVal ComputeLatticeVal(TestLatticeKey Key) override {
114     if (Key.getInt() == IPOGrouping::Register)
115       if (auto *C = dyn_cast<Constant>(Key.getPointer()))
116         return TestLatticeVal(C, TestLatticeVal::ConstantVal);
117     return getUndefVal();
118   }
119 
120   /// Merge the two given lattice values. This merge should be equivalent to
121   /// what is done for constant propagation. That is, the resulting lattice
122   /// value is constant only if the two given lattice values are constant and
123   /// hold the same value.
124   TestLatticeVal MergeValues(TestLatticeVal X, TestLatticeVal Y) override {
125     if (X == getUntrackedVal() || Y == getUntrackedVal())
126       return getUntrackedVal();
127     if (X == getOverdefinedVal() || Y == getOverdefinedVal())
128       return getOverdefinedVal();
129     if (X == getUndefVal() && Y == getUndefVal())
130       return getUndefVal();
131     if (X == getUndefVal())
132       return Y;
133     if (Y == getUndefVal())
134       return X;
135     if (X == Y)
136       return X;
137     return getOverdefinedVal();
138   }
139 
140   /// Compute the lattice values that change as a result of executing the given
141   /// instruction. We only handle the few instructions needed for the tests.
142   void ComputeInstructionState(
143       Instruction &I, DenseMap<TestLatticeKey, TestLatticeVal> &ChangedValues,
144       SparseSolver<TestLatticeKey, TestLatticeVal> &SS) override {
145     switch (I.getOpcode()) {
146     case Instruction::Call:
147       return visitCallSite(cast<CallInst>(&I), ChangedValues, SS);
148     case Instruction::Ret:
149       return visitReturn(*cast<ReturnInst>(&I), ChangedValues, SS);
150     case Instruction::Store:
151       return visitStore(*cast<StoreInst>(&I), ChangedValues, SS);
152     default:
153       return visitInst(I, ChangedValues, SS);
154     }
155   }
156 
157 private:
158   /// Handle call sites. The state of a called function's argument is the merge
159   /// of the current formal argument state with the call site's corresponding
160   /// actual argument state. The call site state is the merge of the call site
161   /// state with the returned value state of the called function.
162   void visitCallSite(CallSite CS,
163                      DenseMap<TestLatticeKey, TestLatticeVal> &ChangedValues,
164                      SparseSolver<TestLatticeKey, TestLatticeVal> &SS) {
165     Function *F = CS.getCalledFunction();
166     Instruction *I = CS.getInstruction();
167     auto RegI = TestLatticeKey(I, IPOGrouping::Register);
168     if (!F) {
169       ChangedValues[RegI] = getOverdefinedVal();
170       return;
171     }
172     SS.MarkBlockExecutable(&F->front());
173     for (Argument &A : F->args()) {
174       auto RegFormal = TestLatticeKey(&A, IPOGrouping::Register);
175       auto RegActual =
176           TestLatticeKey(CS.getArgument(A.getArgNo()), IPOGrouping::Register);
177       ChangedValues[RegFormal] =
178           MergeValues(SS.getValueState(RegFormal), SS.getValueState(RegActual));
179     }
180     auto RetF = TestLatticeKey(F, IPOGrouping::Return);
181     ChangedValues[RegI] =
182         MergeValues(SS.getValueState(RegI), SS.getValueState(RetF));
183   }
184 
185   /// Handle return instructions. The function's return state is the merge of
186   /// the returned value state and the function's current return state.
187   void visitReturn(ReturnInst &I,
188                    DenseMap<TestLatticeKey, TestLatticeVal> &ChangedValues,
189                    SparseSolver<TestLatticeKey, TestLatticeVal> &SS) {
190     Function *F = I.getParent()->getParent();
191     if (F->getReturnType()->isVoidTy())
192       return;
193     auto RegR = TestLatticeKey(I.getReturnValue(), IPOGrouping::Register);
194     auto RetF = TestLatticeKey(F, IPOGrouping::Return);
195     ChangedValues[RetF] =
196         MergeValues(SS.getValueState(RegR), SS.getValueState(RetF));
197   }
198 
199   /// Handle store instructions. If the pointer operand of the store is a
200   /// global variable, we attempt to track the value. The global variable state
201   /// is the merge of the stored value state with the current global variable
202   /// state.
203   void visitStore(StoreInst &I,
204                   DenseMap<TestLatticeKey, TestLatticeVal> &ChangedValues,
205                   SparseSolver<TestLatticeKey, TestLatticeVal> &SS) {
206     auto *GV = dyn_cast<GlobalVariable>(I.getPointerOperand());
207     if (!GV)
208       return;
209     auto RegVal = TestLatticeKey(I.getValueOperand(), IPOGrouping::Register);
210     auto MemPtr = TestLatticeKey(GV, IPOGrouping::Memory);
211     ChangedValues[MemPtr] =
212         MergeValues(SS.getValueState(RegVal), SS.getValueState(MemPtr));
213   }
214 
215   /// Handle all other instructions. All other instructions are marked
216   /// overdefined.
217   void visitInst(Instruction &I,
218                  DenseMap<TestLatticeKey, TestLatticeVal> &ChangedValues,
219                  SparseSolver<TestLatticeKey, TestLatticeVal> &SS) {
220     auto RegI = TestLatticeKey(&I, IPOGrouping::Register);
221     ChangedValues[RegI] = getOverdefinedVal();
222   }
223 };
224 
225 /// This class defines the common data used for all of the tests. The tests
226 /// should add code to the module and then run the solver.
227 class SparsePropagationTest : public testing::Test {
228 protected:
229   LLVMContext Context;
230   Module M;
231   IRBuilder<> Builder;
232   TestLatticeFunc Lattice;
233   SparseSolver<TestLatticeKey, TestLatticeVal> Solver;
234 
235 public:
236   SparsePropagationTest()
237       : M("", Context), Builder(Context), Solver(&Lattice) {}
238 };
239 } // namespace
240 
241 /// Test that we mark discovered functions executable.
242 ///
243 /// define internal void @f() {
244 ///   call void @g()
245 ///   ret void
246 /// }
247 ///
248 /// define internal void @g() {
249 ///   call void @f()
250 ///   ret void
251 /// }
252 ///
253 /// For this test, we initially mark "f" executable, and the solver discovers
254 /// "g" because of the call in "f". The mutually recursive call in "g" also
255 /// tests that we don't add a block to the basic block work list if it is
256 /// already executable. Doing so would put the solver into an infinite loop.
257 TEST_F(SparsePropagationTest, MarkBlockExecutable) {
258   Function *F = Function::Create(FunctionType::get(Builder.getVoidTy(), false),
259                                  GlobalValue::InternalLinkage, "f", &M);
260   Function *G = Function::Create(FunctionType::get(Builder.getVoidTy(), false),
261                                  GlobalValue::InternalLinkage, "g", &M);
262   BasicBlock *FEntry = BasicBlock::Create(Context, "", F);
263   BasicBlock *GEntry = BasicBlock::Create(Context, "", G);
264   Builder.SetInsertPoint(FEntry);
265   Builder.CreateCall(G);
266   Builder.CreateRetVoid();
267   Builder.SetInsertPoint(GEntry);
268   Builder.CreateCall(F);
269   Builder.CreateRetVoid();
270 
271   Solver.MarkBlockExecutable(FEntry);
272   Solver.Solve();
273 
274   EXPECT_TRUE(Solver.isBlockExecutable(GEntry));
275 }
276 
277 /// Test that we propagate information through global variables.
278 ///
279 /// @gv = internal global i64
280 ///
281 /// define internal void @f() {
282 ///   store i64 1, i64* @gv
283 ///   ret void
284 /// }
285 ///
286 /// define internal void @g() {
287 ///   store i64 1, i64* @gv
288 ///   ret void
289 /// }
290 ///
291 /// For this test, we initially mark both "f" and "g" executable, and the
292 /// solver computes the lattice state of the global variable as constant.
293 TEST_F(SparsePropagationTest, GlobalVariableConstant) {
294   Function *F = Function::Create(FunctionType::get(Builder.getVoidTy(), false),
295                                  GlobalValue::InternalLinkage, "f", &M);
296   Function *G = Function::Create(FunctionType::get(Builder.getVoidTy(), false),
297                                  GlobalValue::InternalLinkage, "g", &M);
298   GlobalVariable *GV =
299       new GlobalVariable(M, Builder.getInt64Ty(), false,
300                          GlobalValue::InternalLinkage, nullptr, "gv");
301   BasicBlock *FEntry = BasicBlock::Create(Context, "", F);
302   BasicBlock *GEntry = BasicBlock::Create(Context, "", G);
303   Builder.SetInsertPoint(FEntry);
304   Builder.CreateStore(Builder.getInt64(1), GV);
305   Builder.CreateRetVoid();
306   Builder.SetInsertPoint(GEntry);
307   Builder.CreateStore(Builder.getInt64(1), GV);
308   Builder.CreateRetVoid();
309 
310   Solver.MarkBlockExecutable(FEntry);
311   Solver.MarkBlockExecutable(GEntry);
312   Solver.Solve();
313 
314   auto MemGV = TestLatticeKey(GV, IPOGrouping::Memory);
315   EXPECT_TRUE(Solver.getExistingValueState(MemGV).isConstant());
316 }
317 
318 /// Test that we propagate information through global variables.
319 ///
320 /// @gv = internal global i64
321 ///
322 /// define internal void @f() {
323 ///   store i64 0, i64* @gv
324 ///   ret void
325 /// }
326 ///
327 /// define internal void @g() {
328 ///   store i64 1, i64* @gv
329 ///   ret void
330 /// }
331 ///
332 /// For this test, we initially mark both "f" and "g" executable, and the
333 /// solver computes the lattice state of the global variable as overdefined.
334 TEST_F(SparsePropagationTest, GlobalVariableOverDefined) {
335   Function *F = Function::Create(FunctionType::get(Builder.getVoidTy(), false),
336                                  GlobalValue::InternalLinkage, "f", &M);
337   Function *G = Function::Create(FunctionType::get(Builder.getVoidTy(), false),
338                                  GlobalValue::InternalLinkage, "g", &M);
339   GlobalVariable *GV =
340       new GlobalVariable(M, Builder.getInt64Ty(), false,
341                          GlobalValue::InternalLinkage, nullptr, "gv");
342   BasicBlock *FEntry = BasicBlock::Create(Context, "", F);
343   BasicBlock *GEntry = BasicBlock::Create(Context, "", G);
344   Builder.SetInsertPoint(FEntry);
345   Builder.CreateStore(Builder.getInt64(0), GV);
346   Builder.CreateRetVoid();
347   Builder.SetInsertPoint(GEntry);
348   Builder.CreateStore(Builder.getInt64(1), GV);
349   Builder.CreateRetVoid();
350 
351   Solver.MarkBlockExecutable(FEntry);
352   Solver.MarkBlockExecutable(GEntry);
353   Solver.Solve();
354 
355   auto MemGV = TestLatticeKey(GV, IPOGrouping::Memory);
356   EXPECT_TRUE(Solver.getExistingValueState(MemGV).isOverdefined());
357 }
358 
359 /// Test that we propagate information through function returns.
360 ///
361 /// define internal i64 @f(i1* %cond) {
362 /// if:
363 ///   %0 = load i1, i1* %cond
364 ///   br i1 %0, label %then, label %else
365 ///
366 /// then:
367 ///   ret i64 1
368 ///
369 /// else:
370 ///   ret i64 1
371 /// }
372 ///
373 /// For this test, we initially mark "f" executable, and the solver computes
374 /// the return value of the function as constant.
375 TEST_F(SparsePropagationTest, FunctionDefined) {
376   Function *F =
377       Function::Create(FunctionType::get(Builder.getInt64Ty(),
378                                          {Type::getInt1PtrTy(Context)}, false),
379                        GlobalValue::InternalLinkage, "f", &M);
380   BasicBlock *If = BasicBlock::Create(Context, "if", F);
381   BasicBlock *Then = BasicBlock::Create(Context, "then", F);
382   BasicBlock *Else = BasicBlock::Create(Context, "else", F);
383   F->arg_begin()->setName("cond");
384   Builder.SetInsertPoint(If);
385   LoadInst *Cond = Builder.CreateLoad(F->arg_begin());
386   Builder.CreateCondBr(Cond, Then, Else);
387   Builder.SetInsertPoint(Then);
388   Builder.CreateRet(Builder.getInt64(1));
389   Builder.SetInsertPoint(Else);
390   Builder.CreateRet(Builder.getInt64(1));
391 
392   Solver.MarkBlockExecutable(If);
393   Solver.Solve();
394 
395   auto RetF = TestLatticeKey(F, IPOGrouping::Return);
396   EXPECT_TRUE(Solver.getExistingValueState(RetF).isConstant());
397 }
398 
399 /// Test that we propagate information through function returns.
400 ///
401 /// define internal i64 @f(i1* %cond) {
402 /// if:
403 ///   %0 = load i1, i1* %cond
404 ///   br i1 %0, label %then, label %else
405 ///
406 /// then:
407 ///   ret i64 0
408 ///
409 /// else:
410 ///   ret i64 1
411 /// }
412 ///
413 /// For this test, we initially mark "f" executable, and the solver computes
414 /// the return value of the function as overdefined.
415 TEST_F(SparsePropagationTest, FunctionOverDefined) {
416   Function *F =
417       Function::Create(FunctionType::get(Builder.getInt64Ty(),
418                                          {Type::getInt1PtrTy(Context)}, false),
419                        GlobalValue::InternalLinkage, "f", &M);
420   BasicBlock *If = BasicBlock::Create(Context, "if", F);
421   BasicBlock *Then = BasicBlock::Create(Context, "then", F);
422   BasicBlock *Else = BasicBlock::Create(Context, "else", F);
423   F->arg_begin()->setName("cond");
424   Builder.SetInsertPoint(If);
425   LoadInst *Cond = Builder.CreateLoad(F->arg_begin());
426   Builder.CreateCondBr(Cond, Then, Else);
427   Builder.SetInsertPoint(Then);
428   Builder.CreateRet(Builder.getInt64(0));
429   Builder.SetInsertPoint(Else);
430   Builder.CreateRet(Builder.getInt64(1));
431 
432   Solver.MarkBlockExecutable(If);
433   Solver.Solve();
434 
435   auto RetF = TestLatticeKey(F, IPOGrouping::Return);
436   EXPECT_TRUE(Solver.getExistingValueState(RetF).isOverdefined());
437 }
438 
439 /// Test that we propagate information through arguments.
440 ///
441 /// define internal void @f() {
442 ///   call void @g(i64 0, i64 1)
443 ///   call void @g(i64 1, i64 1)
444 ///   ret void
445 /// }
446 ///
447 /// define internal void @g(i64 %a, i64 %b) {
448 ///   ret void
449 /// }
450 ///
451 /// For this test, we initially mark "f" executable, and the solver discovers
452 /// "g" because of the calls in "f". The solver computes the state of argument
453 /// "a" as overdefined and the state of "b" as constant.
454 ///
455 /// In addition, this test demonstrates that ComputeInstructionState can alter
456 /// the state of multiple lattice values, in addition to the one associated
457 /// with the instruction definition. Each call instruction in this test updates
458 /// the state of arguments "a" and "b".
459 TEST_F(SparsePropagationTest, ComputeInstructionState) {
460   Function *F = Function::Create(FunctionType::get(Builder.getVoidTy(), false),
461                                  GlobalValue::InternalLinkage, "f", &M);
462   Function *G = Function::Create(
463       FunctionType::get(Builder.getVoidTy(),
464                         {Builder.getInt64Ty(), Builder.getInt64Ty()}, false),
465       GlobalValue::InternalLinkage, "g", &M);
466   Argument *A = G->arg_begin();
467   Argument *B = std::next(G->arg_begin());
468   A->setName("a");
469   B->setName("b");
470   BasicBlock *FEntry = BasicBlock::Create(Context, "", F);
471   BasicBlock *GEntry = BasicBlock::Create(Context, "", G);
472   Builder.SetInsertPoint(FEntry);
473   Builder.CreateCall(G, {Builder.getInt64(0), Builder.getInt64(1)});
474   Builder.CreateCall(G, {Builder.getInt64(1), Builder.getInt64(1)});
475   Builder.CreateRetVoid();
476   Builder.SetInsertPoint(GEntry);
477   Builder.CreateRetVoid();
478 
479   Solver.MarkBlockExecutable(FEntry);
480   Solver.Solve();
481 
482   auto RegA = TestLatticeKey(A, IPOGrouping::Register);
483   auto RegB = TestLatticeKey(B, IPOGrouping::Register);
484   EXPECT_TRUE(Solver.getExistingValueState(RegA).isOverdefined());
485   EXPECT_TRUE(Solver.getExistingValueState(RegB).isConstant());
486 }
487 
488 /// Test that we can handle exceptional terminator instructions.
489 ///
490 /// declare internal void @p()
491 ///
492 /// declare internal void @g()
493 ///
494 /// define internal void @f() personality i8* bitcast (void ()* @p to i8*) {
495 /// entry:
496 ///   invoke void @g()
497 ///           to label %exit unwind label %catch.pad
498 ///
499 /// catch.pad:
500 ///   %0 = catchswitch within none [label %catch.body] unwind to caller
501 ///
502 /// catch.body:
503 ///   %1 = catchpad within %0 []
504 ///   catchret from %1 to label %exit
505 ///
506 /// exit:
507 ///   ret void
508 /// }
509 ///
510 /// For this test, we initially mark the entry block executable. The solver
511 /// then discovers the rest of the blocks in the function are executable.
512 TEST_F(SparsePropagationTest, ExceptionalTerminatorInsts) {
513   Function *P = Function::Create(FunctionType::get(Builder.getVoidTy(), false),
514                                  GlobalValue::InternalLinkage, "p", &M);
515   Function *G = Function::Create(FunctionType::get(Builder.getVoidTy(), false),
516                                  GlobalValue::InternalLinkage, "g", &M);
517   Function *F = Function::Create(FunctionType::get(Builder.getVoidTy(), false),
518                                  GlobalValue::InternalLinkage, "f", &M);
519   Constant *C =
520       ConstantExpr::getCast(Instruction::BitCast, P, Builder.getInt8PtrTy());
521   F->setPersonalityFn(C);
522   BasicBlock *Entry = BasicBlock::Create(Context, "entry", F);
523   BasicBlock *Pad = BasicBlock::Create(Context, "catch.pad", F);
524   BasicBlock *Body = BasicBlock::Create(Context, "catch.body", F);
525   BasicBlock *Exit = BasicBlock::Create(Context, "exit", F);
526   Builder.SetInsertPoint(Entry);
527   Builder.CreateInvoke(G, Exit, Pad);
528   Builder.SetInsertPoint(Pad);
529   CatchSwitchInst *CatchSwitch =
530       Builder.CreateCatchSwitch(ConstantTokenNone::get(Context), nullptr, 1);
531   CatchSwitch->addHandler(Body);
532   Builder.SetInsertPoint(Body);
533   CatchPadInst *CatchPad = Builder.CreateCatchPad(CatchSwitch, {});
534   Builder.CreateCatchRet(CatchPad, Exit);
535   Builder.SetInsertPoint(Exit);
536   Builder.CreateRetVoid();
537 
538   Solver.MarkBlockExecutable(Entry);
539   Solver.Solve();
540 
541   EXPECT_TRUE(Solver.isBlockExecutable(Pad));
542   EXPECT_TRUE(Solver.isBlockExecutable(Body));
543   EXPECT_TRUE(Solver.isBlockExecutable(Exit));
544 }
545