1 //===- AttributorTest.cpp - Attributor 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-exception 6 // 7 //===---------------------------------------------------------------------===// 8 9 #include "llvm/Transforms/IPO/Attributor.h" 10 #include "AttributorTestBase.h" 11 #include "llvm/ADT/StringRef.h" 12 #include "llvm/Analysis/CGSCCPassManager.h" 13 #include "llvm/Analysis/CallGraphSCCPass.h" 14 #include "llvm/Analysis/LoopAnalysisManager.h" 15 #include "llvm/AsmParser/Parser.h" 16 #include "llvm/Support/Allocator.h" 17 #include "llvm/Testing/Support/Error.h" 18 #include "llvm/Transforms/Utils/CallGraphUpdater.h" 19 #include "gtest/gtest.h" 20 #include <memory> 21 22 namespace llvm { 23 24 TEST_F(AttributorTestBase, IRPPositionCallBaseContext) { 25 const char *ModuleString = R"( 26 define i32 @foo(i32 %a) { 27 entry: 28 ret i32 %a 29 } 30 )"; 31 32 parseModule(ModuleString); 33 34 Function *F = M->getFunction("foo"); 35 IRPosition Pos = 36 IRPosition::function(*F, (const llvm::CallBase *)(uintptr_t)0xDEADBEEF); 37 EXPECT_TRUE(Pos.hasCallBaseContext()); 38 EXPECT_FALSE(Pos.stripCallBaseContext().hasCallBaseContext()); 39 } 40 41 TEST_F(AttributorTestBase, TestCast) { 42 const char *ModuleString = R"( 43 define i32 @foo(i32 %a, i32 %b) { 44 entry: 45 %c = add i32 %a, %b 46 ret i32 %c 47 } 48 )"; 49 50 Module &M = parseModule(ModuleString); 51 52 SetVector<Function *> Functions; 53 AnalysisGetter AG; 54 for (Function &F : M) 55 Functions.insert(&F); 56 57 CallGraphUpdater CGUpdater; 58 BumpPtrAllocator Allocator; 59 InformationCache InfoCache(M, AG, Allocator, nullptr); 60 Attributor A(Functions, InfoCache, CGUpdater); 61 62 Function *F = M.getFunction("foo"); 63 64 const AbstractAttribute *AA = 65 &A.getOrCreateAAFor<AAIsDead>(IRPosition::function(*F)); 66 67 EXPECT_TRUE(AA); 68 69 const auto *SFail = dyn_cast<AAAlign>(AA); 70 const auto *SSucc = dyn_cast<AAIsDead>(AA); 71 72 ASSERT_EQ(SFail, nullptr); 73 ASSERT_TRUE(SSucc); 74 } 75 76 TEST_F(AttributorTestBase, AAReachabilityTest) { 77 const char *ModuleString = R"( 78 @x = external global i32 79 define internal void @func4() { 80 store i32 0, i32* @x 81 ret void 82 } 83 84 define internal void @func3() { 85 store i32 0, i32* @x 86 ret void 87 } 88 89 define internal void @func8() { 90 store i32 0, i32* @x 91 ret void 92 } 93 94 define internal void @func2() { 95 entry: 96 call void @func3() 97 ret void 98 } 99 100 define internal void @func1() { 101 entry: 102 call void @func2() 103 ret void 104 } 105 106 declare void @unknown() 107 define internal void @func5(void ()* %ptr) { 108 entry: 109 call void %ptr() 110 call void @unknown() 111 ret void 112 } 113 114 define internal void @func6() { 115 entry: 116 call void @func5(void ()* @func3) 117 ret void 118 } 119 120 define internal void @func7() { 121 entry: 122 call void @func2() 123 call void @func4() 124 ret void 125 } 126 127 define internal void @func9() { 128 entry: 129 call void @func2() 130 call void @func8() 131 ret void 132 } 133 134 define void @func10() { 135 entry: 136 call void @func9() 137 call void @func4() 138 ret void 139 } 140 141 )"; 142 143 Module &M = parseModule(ModuleString); 144 145 SetVector<Function *> Functions; 146 AnalysisGetter AG; 147 for (Function &F : M) 148 Functions.insert(&F); 149 150 CallGraphUpdater CGUpdater; 151 BumpPtrAllocator Allocator; 152 InformationCache InfoCache(M, AG, Allocator, nullptr); 153 Attributor A(Functions, InfoCache, CGUpdater, /* Allowed */ nullptr, 154 /*DeleteFns*/ false); 155 156 Function &F1 = *M.getFunction("func1"); 157 Function &F3 = *M.getFunction("func3"); 158 Function &F4 = *M.getFunction("func4"); 159 Function &F6 = *M.getFunction("func6"); 160 Function &F7 = *M.getFunction("func7"); 161 Function &F9 = *M.getFunction("func9"); 162 163 // call void @func2() 164 CallBase &F7FirstCB = static_cast<CallBase &>(*F7.getEntryBlock().begin()); 165 // call void @func2() 166 Instruction &F9FirstInst = *F9.getEntryBlock().begin(); 167 // call void @func8 168 Instruction &F9SecondInst = *++(F9.getEntryBlock().begin()); 169 170 const AAFunctionReachability &F1AA = 171 A.getOrCreateAAFor<AAFunctionReachability>(IRPosition::function(F1)); 172 173 const AAFunctionReachability &F6AA = 174 A.getOrCreateAAFor<AAFunctionReachability>(IRPosition::function(F6)); 175 176 const AAFunctionReachability &F7AA = 177 A.getOrCreateAAFor<AAFunctionReachability>(IRPosition::function(F7)); 178 179 const AAFunctionReachability &F9AA = 180 A.getOrCreateAAFor<AAFunctionReachability>(IRPosition::function(F9)); 181 182 F1AA.canReach(A, F3); 183 F1AA.canReach(A, F4); 184 F6AA.canReach(A, F4); 185 F7AA.canReach(A, F7FirstCB, F3); 186 F7AA.canReach(A, F7FirstCB, F4); 187 F9AA.instructionCanReach(A, F9FirstInst, F3); 188 F9AA.instructionCanReach(A, F9SecondInst, F3, false); 189 F9AA.instructionCanReach(A, F9FirstInst, F4); 190 191 A.run(); 192 193 ASSERT_TRUE(F1AA.canReach(A, F3)); 194 ASSERT_FALSE(F1AA.canReach(A, F4)); 195 196 ASSERT_TRUE(F7AA.canReach(A, F7FirstCB, F3)); 197 ASSERT_FALSE(F7AA.canReach(A, F7FirstCB, F4)); 198 199 // Assumed to be reacahable, since F6 can reach a function with 200 // a unknown callee. 201 ASSERT_TRUE(F6AA.canReach(A, F4)); 202 203 // The second instruction of F9 can't reach the first call. 204 ASSERT_FALSE(F9AA.instructionCanReach(A, F9SecondInst, F3, false)); 205 // TODO: Without lifetime limiting callback this query does actually not make 206 // much sense. "Anything" is reachable from the caller of func10. 207 ASSERT_TRUE(F9AA.instructionCanReach(A, F9SecondInst, F3, true)); 208 209 // The first instruction of F9 can reach the first call. 210 ASSERT_TRUE(F9AA.instructionCanReach(A, F9FirstInst, F3)); 211 // Because func10 calls the func4 after the call to func9 it is reachable. 212 ASSERT_TRUE(F9AA.instructionCanReach(A, F9FirstInst, F4)); 213 } 214 215 } // namespace llvm 216