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 AttributorConfig AC(CGUpdater); 61 Attributor A(Functions, InfoCache, AC); 62 63 Function *F = M.getFunction("foo"); 64 65 const AbstractAttribute *AA = 66 &A.getOrCreateAAFor<AAIsDead>(IRPosition::function(*F)); 67 68 EXPECT_TRUE(AA); 69 70 const auto *SFail = dyn_cast<AAAlign>(AA); 71 const auto *SSucc = dyn_cast<AAIsDead>(AA); 72 73 ASSERT_EQ(SFail, nullptr); 74 ASSERT_TRUE(SSucc); 75 } 76 77 TEST_F(AttributorTestBase, AAReachabilityTest) { 78 const char *ModuleString = R"( 79 @x = external global i32 80 define internal void @func4() { 81 store i32 0, i32* @x 82 ret void 83 } 84 85 define internal void @func3() { 86 store i32 0, i32* @x 87 ret void 88 } 89 90 define internal void @func8() { 91 store i32 0, i32* @x 92 ret void 93 } 94 95 define internal void @func2() { 96 entry: 97 call void @func3() 98 ret void 99 } 100 101 define internal void @func1() { 102 entry: 103 call void @func2() 104 ret void 105 } 106 107 declare void @unknown() 108 define internal void @func5(void ()* %ptr) { 109 entry: 110 call void %ptr() 111 call void @unknown() 112 ret void 113 } 114 115 define internal void @func6() { 116 entry: 117 call void @func5(void ()* @func3) 118 ret void 119 } 120 121 define internal void @func7() { 122 entry: 123 call void @func2() 124 call void @func4() 125 ret void 126 } 127 128 define internal void @func9() { 129 entry: 130 call void @func2() 131 call void @func8() 132 ret void 133 } 134 135 define void @func10() { 136 entry: 137 call void @func9() 138 call void @func4() 139 ret void 140 } 141 142 )"; 143 144 Module &M = parseModule(ModuleString); 145 146 SetVector<Function *> Functions; 147 AnalysisGetter AG; 148 for (Function &F : M) 149 Functions.insert(&F); 150 151 CallGraphUpdater CGUpdater; 152 BumpPtrAllocator Allocator; 153 InformationCache InfoCache(M, AG, Allocator, nullptr); 154 AttributorConfig AC(CGUpdater); 155 AC.DeleteFns = false; 156 Attributor A(Functions, InfoCache, AC); 157 158 Function &F1 = *M.getFunction("func1"); 159 Function &F3 = *M.getFunction("func3"); 160 Function &F4 = *M.getFunction("func4"); 161 Function &F6 = *M.getFunction("func6"); 162 Function &F7 = *M.getFunction("func7"); 163 Function &F9 = *M.getFunction("func9"); 164 165 // call void @func2() 166 CallBase &F7FirstCB = static_cast<CallBase &>(*F7.getEntryBlock().begin()); 167 // call void @func2() 168 Instruction &F9FirstInst = *F9.getEntryBlock().begin(); 169 // call void @func8 170 Instruction &F9SecondInst = *++(F9.getEntryBlock().begin()); 171 172 const AAFunctionReachability &F1AA = 173 A.getOrCreateAAFor<AAFunctionReachability>(IRPosition::function(F1)); 174 175 const AAFunctionReachability &F6AA = 176 A.getOrCreateAAFor<AAFunctionReachability>(IRPosition::function(F6)); 177 178 const AAFunctionReachability &F7AA = 179 A.getOrCreateAAFor<AAFunctionReachability>(IRPosition::function(F7)); 180 181 const AAFunctionReachability &F9AA = 182 A.getOrCreateAAFor<AAFunctionReachability>(IRPosition::function(F9)); 183 184 F1AA.canReach(A, F3); 185 F1AA.canReach(A, F4); 186 F6AA.canReach(A, F4); 187 F7AA.canReach(A, F7FirstCB, F3); 188 F7AA.canReach(A, F7FirstCB, F4); 189 F9AA.instructionCanReach(A, F9FirstInst, F3); 190 F9AA.instructionCanReach(A, F9SecondInst, F3, false); 191 F9AA.instructionCanReach(A, F9FirstInst, F4); 192 193 A.run(); 194 195 ASSERT_TRUE(F1AA.canReach(A, F3)); 196 ASSERT_FALSE(F1AA.canReach(A, F4)); 197 198 ASSERT_TRUE(F7AA.canReach(A, F7FirstCB, F3)); 199 ASSERT_FALSE(F7AA.canReach(A, F7FirstCB, F4)); 200 201 // Assumed to be reacahable, since F6 can reach a function with 202 // a unknown callee. 203 ASSERT_TRUE(F6AA.canReach(A, F4)); 204 205 // The second instruction of F9 can't reach the first call. 206 ASSERT_FALSE(F9AA.instructionCanReach(A, F9SecondInst, F3, false)); 207 // TODO: Without lifetime limiting callback this query does actually not make 208 // much sense. "Anything" is reachable from the caller of func10. 209 ASSERT_TRUE(F9AA.instructionCanReach(A, F9SecondInst, F3, true)); 210 211 // The first instruction of F9 can reach the first call. 212 ASSERT_TRUE(F9AA.instructionCanReach(A, F9FirstInst, F3)); 213 // Because func10 calls the func4 after the call to func9 it is reachable. 214 ASSERT_TRUE(F9AA.instructionCanReach(A, F9FirstInst, F4)); 215 } 216 217 } // namespace llvm 218