• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //=======- CaptureTrackingTest.cpp - Unit test for the Capture Tracking ---===//
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/Analysis/CaptureTracking.h"
10 #include "llvm/AsmParser/Parser.h"
11 #include "llvm/IR/Dominators.h"
12 #include "llvm/IR/Instructions.h"
13 #include "llvm/IR/LLVMContext.h"
14 #include "llvm/IR/Module.h"
15 #include "llvm/Support/SourceMgr.h"
16 #include "gtest/gtest.h"
17 
18 using namespace llvm;
19 
TEST(CaptureTracking,MaxUsesToExplore)20 TEST(CaptureTracking, MaxUsesToExplore) {
21   StringRef Assembly = R"(
22     ; Function Attrs: nounwind ssp uwtable
23     declare void @doesnt_capture(i8* nocapture, i8* nocapture, i8* nocapture,
24                                  i8* nocapture, i8* nocapture)
25 
26     ; %arg has 5 uses
27     define void @test_few_uses(i8* %arg) {
28       call void @doesnt_capture(i8* %arg, i8* %arg, i8* %arg, i8* %arg, i8* %arg)
29       ret void
30     }
31 
32     ; %arg has 50 uses
33     define void @test_many_uses(i8* %arg) {
34       call void @doesnt_capture(i8* %arg, i8* %arg, i8* %arg, i8* %arg, i8* %arg)
35       call void @doesnt_capture(i8* %arg, i8* %arg, i8* %arg, i8* %arg, i8* %arg)
36       call void @doesnt_capture(i8* %arg, i8* %arg, i8* %arg, i8* %arg, i8* %arg)
37       call void @doesnt_capture(i8* %arg, i8* %arg, i8* %arg, i8* %arg, i8* %arg)
38       call void @doesnt_capture(i8* %arg, i8* %arg, i8* %arg, i8* %arg, i8* %arg)
39       call void @doesnt_capture(i8* %arg, i8* %arg, i8* %arg, i8* %arg, i8* %arg)
40       call void @doesnt_capture(i8* %arg, i8* %arg, i8* %arg, i8* %arg, i8* %arg)
41       call void @doesnt_capture(i8* %arg, i8* %arg, i8* %arg, i8* %arg, i8* %arg)
42       call void @doesnt_capture(i8* %arg, i8* %arg, i8* %arg, i8* %arg, i8* %arg)
43       call void @doesnt_capture(i8* %arg, i8* %arg, i8* %arg, i8* %arg, i8* %arg)
44       ret void
45     }
46   )";
47 
48   LLVMContext Context;
49   SMDiagnostic Error;
50   auto M = parseAssemblyString(Assembly, Error, Context);
51   ASSERT_TRUE(M) << "Bad assembly?";
52 
53   auto Test = [&M](const char *FName, unsigned FalseMaxUsesLimit,
54                    unsigned TrueMaxUsesLimit) {
55     Function *F = M->getFunction(FName);
56     ASSERT_NE(F, nullptr);
57     Value *Arg = &*F->arg_begin();
58     ASSERT_NE(Arg, nullptr);
59     ASSERT_FALSE(PointerMayBeCaptured(Arg, true, true, FalseMaxUsesLimit));
60     ASSERT_TRUE(PointerMayBeCaptured(Arg, true, true, TrueMaxUsesLimit));
61 
62     BasicBlock *EntryBB = &F->getEntryBlock();
63     DominatorTree DT(*F);
64 
65     Instruction *Ret = EntryBB->getTerminator();
66     ASSERT_TRUE(isa<ReturnInst>(Ret));
67     ASSERT_FALSE(PointerMayBeCapturedBefore(Arg, true, true, Ret, &DT, false,
68                                             FalseMaxUsesLimit));
69     ASSERT_TRUE(PointerMayBeCapturedBefore(Arg, true, true, Ret, &DT, false,
70                                            TrueMaxUsesLimit));
71   };
72 
73   Test("test_few_uses", 6, 4);
74   Test("test_many_uses", 50, 30);
75 }
76 
77 struct CollectingCaptureTracker : public CaptureTracker {
78   SmallVector<const Use *, 4> Captures;
tooManyUsesCollectingCaptureTracker79   void tooManyUses() override { }
capturedCollectingCaptureTracker80   bool captured(const Use *U) override {
81     Captures.push_back(U);
82     return false;
83   }
84 };
85 
TEST(CaptureTracking,MultipleUsesInSameInstruction)86 TEST(CaptureTracking, MultipleUsesInSameInstruction) {
87   StringRef Assembly = R"(
88     declare void @call(i8*, i8*, i8*)
89 
90     define void @test(i8* %arg, i8** %ptr) {
91       call void @call(i8* %arg, i8* nocapture %arg, i8* %arg) [ "bundle"(i8* %arg) ]
92       cmpxchg i8** %ptr, i8* %arg, i8* %arg acq_rel monotonic
93       icmp eq i8* %arg, %arg
94       ret void
95     }
96   )";
97 
98   LLVMContext Context;
99   SMDiagnostic Error;
100   auto M = parseAssemblyString(Assembly, Error, Context);
101   ASSERT_TRUE(M) << "Bad assembly?";
102 
103   Function *F = M->getFunction("test");
104   Value *Arg = &*F->arg_begin();
105   BasicBlock *BB = &F->getEntryBlock();
106   Instruction *Call = &*BB->begin();
107   Instruction *CmpXChg = Call->getNextNode();
108   Instruction *ICmp = CmpXChg->getNextNode();
109 
110   CollectingCaptureTracker CT;
111   PointerMayBeCaptured(Arg, &CT);
112   EXPECT_EQ(7u, CT.Captures.size());
113   // Call arg 1
114   EXPECT_EQ(Call, CT.Captures[0]->getUser());
115   EXPECT_EQ(0u, CT.Captures[0]->getOperandNo());
116   // Call arg 3
117   EXPECT_EQ(Call, CT.Captures[1]->getUser());
118   EXPECT_EQ(2u, CT.Captures[1]->getOperandNo());
119   // Operand bundle arg
120   EXPECT_EQ(Call, CT.Captures[2]->getUser());
121   EXPECT_EQ(3u, CT.Captures[2]->getOperandNo());
122   // Cmpxchg compare operand
123   EXPECT_EQ(CmpXChg, CT.Captures[3]->getUser());
124   EXPECT_EQ(1u, CT.Captures[3]->getOperandNo());
125   // Cmpxchg new value operand
126   EXPECT_EQ(CmpXChg, CT.Captures[4]->getUser());
127   EXPECT_EQ(2u, CT.Captures[4]->getOperandNo());
128   // ICmp first operand
129   EXPECT_EQ(ICmp, CT.Captures[5]->getUser());
130   EXPECT_EQ(0u, CT.Captures[5]->getOperandNo());
131   // ICmp second operand
132   EXPECT_EQ(ICmp, CT.Captures[6]->getUser());
133   EXPECT_EQ(1u, CT.Captures[6]->getOperandNo());
134 }
135