|
14 | 14 | #include "llvm/ADT/APSInt.h"
|
15 | 15 | #include "llvm/ADT/SetVector.h"
|
16 | 16 | #include "llvm/ADT/Statistic.h"
|
| 17 | +#include "llvm/Analysis/CaptureTracking.h" |
17 | 18 | #include "llvm/Analysis/CmpInstAnalysis.h"
|
18 | 19 | #include "llvm/Analysis/ConstantFolding.h"
|
19 | 20 | #include "llvm/Analysis/InstructionSimplify.h"
|
@@ -915,57 +916,27 @@ Instruction *InstCombinerImpl::foldAllocaCmp(ICmpInst &ICI,
|
915 | 916 | // comparisons against the alloca consistently, and avoids the risk of
|
916 | 917 | // erroneously folding a comparison of the pointer with itself.
|
917 | 918 |
|
918 |
| - unsigned MaxIter = 32; // Break cycles and bound to constant-time. |
| 919 | + struct CmpCaptureTracker : public CaptureTracker { |
| 920 | + bool Captured = false; |
| 921 | + unsigned NumCmps = 0; |
919 | 922 |
|
920 |
| - SmallVector<const Use *, 32> Worklist; |
921 |
| - for (const Use &U : Alloca->uses()) { |
922 |
| - if (Worklist.size() >= MaxIter) |
923 |
| - return nullptr; |
924 |
| - Worklist.push_back(&U); |
925 |
| - } |
926 |
| - |
927 |
| - unsigned NumCmps = 0; |
928 |
| - while (!Worklist.empty()) { |
929 |
| - assert(Worklist.size() <= MaxIter); |
930 |
| - const Use *U = Worklist.pop_back_val(); |
931 |
| - const Value *V = U->getUser(); |
932 |
| - --MaxIter; |
| 923 | + void tooManyUses() override { Captured = true; } |
933 | 924 |
|
934 |
| - if (isa<BitCastInst>(V) || isa<GetElementPtrInst>(V) || isa<PHINode>(V) || |
935 |
| - isa<SelectInst>(V)) { |
936 |
| - // Track the uses. |
937 |
| - } else if (isa<LoadInst>(V)) { |
938 |
| - // Loading from the pointer doesn't escape it. |
939 |
| - continue; |
940 |
| - } else if (const auto *SI = dyn_cast<StoreInst>(V)) { |
941 |
| - // Storing *to* the pointer is fine, but storing the pointer escapes it. |
942 |
| - if (SI->getValueOperand() == U->get()) |
943 |
| - return nullptr; |
944 |
| - continue; |
945 |
| - } else if (isa<ICmpInst>(V)) { |
946 |
| - if (NumCmps++) |
947 |
| - return nullptr; // Found more than one cmp. |
948 |
| - continue; |
949 |
| - } else if (const auto *Intrin = dyn_cast<IntrinsicInst>(V)) { |
950 |
| - switch (Intrin->getIntrinsicID()) { |
951 |
| - // These intrinsics don't escape or compare the pointer. Memset is safe |
952 |
| - // because we don't allow ptrtoint. Memcpy and memmove are safe because |
953 |
| - // we don't allow stores, so src cannot point to V. |
954 |
| - case Intrinsic::lifetime_start: case Intrinsic::lifetime_end: |
955 |
| - case Intrinsic::memcpy: case Intrinsic::memmove: case Intrinsic::memset: |
956 |
| - continue; |
957 |
| - default: |
958 |
| - return nullptr; |
| 925 | + bool captured(const Use *U) override { |
| 926 | + if (isa<ICmpInst>(U->getUser()) && ++NumCmps == 1) { |
| 927 | + // Ignore one icmp capture. |
| 928 | + return false; |
959 | 929 | }
|
960 |
| - } else { |
961 |
| - return nullptr; |
962 |
| - } |
963 |
| - for (const Use &U : V->uses()) { |
964 |
| - if (Worklist.size() >= MaxIter) |
965 |
| - return nullptr; |
966 |
| - Worklist.push_back(&U); |
| 930 | + |
| 931 | + Captured = true; |
| 932 | + return true; |
967 | 933 | }
|
968 |
| - } |
| 934 | + }; |
| 935 | + |
| 936 | + CmpCaptureTracker Tracker; |
| 937 | + PointerMayBeCaptured(Alloca, &Tracker); |
| 938 | + if (Tracker.Captured) |
| 939 | + return nullptr; |
969 | 940 |
|
970 | 941 | auto *Res = ConstantInt::get(ICI.getType(),
|
971 | 942 | !CmpInst::isTrueWhenEqual(ICI.getPredicate()));
|
|
0 commit comments