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