forked from OSchip/llvm-project
Revert "[DSE] Track earliest escape, use for loads in isReadClobber."
This reverts commit 5ce89279c0
.
Makes clang crash, see comments on https://reviews.llvm.org/D109844
This commit is contained in:
parent
626e2a6c62
commit
df56fc6ebb
|
@ -23,7 +23,6 @@ namespace llvm {
|
|||
class Instruction;
|
||||
class DominatorTree;
|
||||
class LoopInfo;
|
||||
class Function;
|
||||
|
||||
/// getDefaultMaxUsesToExploreForCaptureTracking - Return default value of
|
||||
/// the maximal number of uses to explore before giving up. It is used by
|
||||
|
@ -64,19 +63,6 @@ namespace llvm {
|
|||
unsigned MaxUsesToExplore = 0,
|
||||
const LoopInfo *LI = nullptr);
|
||||
|
||||
// Returns the 'earliest' instruction that captures \p V in \F. An instruction
|
||||
// A is considered earlier than instruction B, if A dominates B. If 2 escapes
|
||||
// do not dominate each other, the terminator of the common dominator is
|
||||
// chosen. If not all uses can be analyzed, the earliest escape is set to
|
||||
// the first instruction in the function entry block. If \p V does not escape,
|
||||
// nullptr is returned. Note that the caller of the function has to ensure
|
||||
// that the instruction the result value is compared against is not in a
|
||||
// cycle.
|
||||
Instruction *FindEarliestCapture(const Value *V, Function &F,
|
||||
bool ReturnCaptures, bool StoreCaptures,
|
||||
const DominatorTree &DT,
|
||||
unsigned MaxUsesToExplore = 0);
|
||||
|
||||
/// This callback is used in conjunction with PointerMayBeCaptured. In
|
||||
/// addition to the interface here, you'll need to provide your own getters
|
||||
/// to see whether anything was captured.
|
||||
|
|
|
@ -143,66 +143,6 @@ namespace {
|
|||
|
||||
const LoopInfo *LI;
|
||||
};
|
||||
|
||||
/// Find the 'earliest' instruction before which the pointer is known not to
|
||||
/// be captured. Here an instruction A is considered earlier than instruction
|
||||
/// B, if A dominates B. If 2 escapes do not dominate each other, the
|
||||
/// terminator of the common dominator is chosen. If not all uses cannot be
|
||||
/// analyzed, the earliest escape is set to the first instruction in the
|
||||
/// function entry block.
|
||||
// NOTE: Users have to make sure instructions compared against the earliest
|
||||
// escape are not in a cycle.
|
||||
struct EarliestCaptures : public CaptureTracker {
|
||||
|
||||
EarliestCaptures(bool ReturnCaptures, Function &F, const DominatorTree &DT)
|
||||
: DT(DT), ReturnCaptures(ReturnCaptures), Captured(false), F(F) {}
|
||||
|
||||
void tooManyUses() override {
|
||||
Captured = true;
|
||||
EarliestCapture = &*F.getEntryBlock().begin();
|
||||
}
|
||||
|
||||
bool captured(const Use *U) override {
|
||||
Instruction *I = cast<Instruction>(U->getUser());
|
||||
if (isa<ReturnInst>(I) && !ReturnCaptures)
|
||||
return false;
|
||||
|
||||
if (!EarliestCapture) {
|
||||
EarliestCapture = I;
|
||||
} else if (EarliestCapture->getParent() == I->getParent()) {
|
||||
if (I->comesBefore(EarliestCapture))
|
||||
EarliestCapture = I;
|
||||
} else {
|
||||
BasicBlock *CurrentBB = I->getParent();
|
||||
BasicBlock *EarliestBB = EarliestCapture->getParent();
|
||||
if (DT.dominates(EarliestBB, CurrentBB)) {
|
||||
// EarliestCapture already comes before the current use.
|
||||
} else if (DT.dominates(CurrentBB, EarliestBB)) {
|
||||
EarliestCapture = I;
|
||||
} else {
|
||||
// Otherwise find the nearest common dominator and use its terminator.
|
||||
auto *NearestCommonDom =
|
||||
DT.findNearestCommonDominator(CurrentBB, EarliestBB);
|
||||
EarliestCapture = NearestCommonDom->getTerminator();
|
||||
}
|
||||
}
|
||||
Captured = true;
|
||||
|
||||
// Return false to continue analysis; we need to see all potential
|
||||
// captures.
|
||||
return false;
|
||||
}
|
||||
|
||||
Instruction *EarliestCapture = nullptr;
|
||||
|
||||
const DominatorTree &DT;
|
||||
|
||||
bool ReturnCaptures;
|
||||
|
||||
bool Captured;
|
||||
|
||||
Function &F;
|
||||
};
|
||||
}
|
||||
|
||||
/// PointerMayBeCaptured - Return true if this pointer value may be captured
|
||||
|
@ -266,22 +206,6 @@ bool llvm::PointerMayBeCapturedBefore(const Value *V, bool ReturnCaptures,
|
|||
return CB.Captured;
|
||||
}
|
||||
|
||||
Instruction *llvm::FindEarliestCapture(const Value *V, Function &F,
|
||||
bool ReturnCaptures, bool StoreCaptures,
|
||||
const DominatorTree &DT,
|
||||
unsigned MaxUsesToExplore) {
|
||||
assert(!isa<GlobalValue>(V) &&
|
||||
"It doesn't make sense to ask whether a global is captured.");
|
||||
|
||||
EarliestCaptures CB(ReturnCaptures, F, DT);
|
||||
PointerMayBeCaptured(V, &CB, MaxUsesToExplore);
|
||||
if (CB.Captured)
|
||||
++NumCapturedBefore;
|
||||
else
|
||||
++NumNotCapturedBefore;
|
||||
return CB.EarliestCapture;
|
||||
}
|
||||
|
||||
void llvm::PointerMayBeCaptured(const Value *V, CaptureTracker *Tracker,
|
||||
unsigned MaxUsesToExplore) {
|
||||
assert(V->getType()->isPointerTy() && "Capture is for pointers only!");
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/Analysis/CFG.h"
|
||||
#include "llvm/Analysis/CaptureTracking.h"
|
||||
#include "llvm/Analysis/GlobalsModRef.h"
|
||||
#include "llvm/Analysis/LoopInfo.h"
|
||||
|
@ -898,9 +897,6 @@ struct DSEState {
|
|||
/// basic block.
|
||||
DenseMap<BasicBlock *, InstOverlapIntervalsTy> IOLs;
|
||||
|
||||
DenseMap<const Value *, Instruction *> EarliestEscapes;
|
||||
DenseMap<Instruction *, TinyPtrVector<const Value *>> Inst2Obj;
|
||||
|
||||
DSEState(Function &F, AliasAnalysis &AA, MemorySSA &MSSA, DominatorTree &DT,
|
||||
PostDominatorTree &PDT, const TargetLibraryInfo &TLI,
|
||||
const LoopInfo &LI)
|
||||
|
@ -1268,30 +1264,6 @@ struct DSEState {
|
|||
DepWriteOffset) == OW_Complete;
|
||||
}
|
||||
|
||||
/// Returns true if \p Object is not captured before or by \p I.
|
||||
bool notCapturedBeforeOrAt(const Value *Object, Instruction *I) {
|
||||
if (!isIdentifiedFunctionLocal(Object))
|
||||
return false;
|
||||
|
||||
auto Iter = EarliestEscapes.insert({Object, nullptr});
|
||||
if (Iter.second) {
|
||||
Instruction *EarliestCapture = FindEarliestCapture(
|
||||
Object, F, /*ReturnCaptures=*/false, /*StoreCaptures=*/true, DT);
|
||||
if (EarliestCapture) {
|
||||
auto Ins = Inst2Obj.insert({EarliestCapture, {}});
|
||||
Ins.first->second.push_back(Object);
|
||||
}
|
||||
Iter.first->second = EarliestCapture;
|
||||
}
|
||||
|
||||
// No capturing instruction.
|
||||
if (!Iter.first->second)
|
||||
return true;
|
||||
|
||||
return I != Iter.first->second &&
|
||||
!isPotentiallyReachable(Iter.first->second, I, nullptr, &DT, &LI);
|
||||
}
|
||||
|
||||
// Returns true if \p Use may read from \p DefLoc.
|
||||
bool isReadClobber(const MemoryLocation &DefLoc, Instruction *UseInst) {
|
||||
if (isNoopIntrinsic(UseInst))
|
||||
|
@ -1309,25 +1281,6 @@ struct DSEState {
|
|||
if (CB->onlyAccessesInaccessibleMemory())
|
||||
return false;
|
||||
|
||||
// BasicAA does not spend linear time to check whether local objects escape
|
||||
// before potentially aliasing accesses. To improve DSE results, compute and
|
||||
// cache escape info for local objects in certain circumstances.
|
||||
if (auto *LI = dyn_cast<LoadInst>(UseInst)) {
|
||||
// If the loads reads from a loaded underlying object accesses the load
|
||||
// cannot alias DefLoc, if DefUO is a local object that has not escaped
|
||||
// before the load.
|
||||
auto *ReadUO = getUnderlyingObject(LI->getPointerOperand());
|
||||
auto *DefUO = getUnderlyingObject(DefLoc.Ptr);
|
||||
if (DefUO && ReadUO && isa<LoadInst>(ReadUO) &&
|
||||
notCapturedBeforeOrAt(DefUO, UseInst)) {
|
||||
assert(
|
||||
!PointerMayBeCapturedBefore(DefLoc.Ptr, false, true, UseInst, &DT,
|
||||
false, 0, &this->LI) &&
|
||||
"cached analysis disagrees with fresh PointerMayBeCapturedBefore");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: For calls, the number of stores removed could be slightly improved
|
||||
// by using AA.callCapturesBefore(UseInst, DefLoc, &DT), but that showed to
|
||||
// be expensive compared to the benefits in practice. For now, avoid more
|
||||
|
@ -1753,17 +1706,7 @@ struct DSEState {
|
|||
if (MemoryAccess *MA = MSSA.getMemoryAccess(DeadInst)) {
|
||||
if (MemoryDef *MD = dyn_cast<MemoryDef>(MA)) {
|
||||
SkipStores.insert(MD);
|
||||
|
||||
// Clear any cached escape info for objects associated with the
|
||||
// removed instructions.
|
||||
auto Iter = Inst2Obj.find(DeadInst);
|
||||
if (Iter != Inst2Obj.end()) {
|
||||
for (const Value *Obj : Iter->second)
|
||||
EarliestEscapes.erase(Obj);
|
||||
Inst2Obj.erase(DeadInst);
|
||||
}
|
||||
}
|
||||
|
||||
Updater.removeMemoryAccess(MA);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ declare void @clobber()
|
|||
define i32 @test_not_captured_before_load_same_bb(i32** %in.ptr) {
|
||||
; CHECK-LABEL: @test_not_captured_before_load_same_bb(
|
||||
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
|
||||
; CHECK-NEXT: store i32 55, i32* [[A]], align 4
|
||||
; CHECK-NEXT: [[IN_LV_1:%.*]] = load i32*, i32** [[IN_PTR:%.*]], align 2
|
||||
; CHECK-NEXT: [[IN_LV_2:%.*]] = load i32, i32* [[IN_LV_1]], align 2
|
||||
; CHECK-NEXT: store i32 99, i32* [[A]], align 4
|
||||
|
@ -26,6 +27,7 @@ define i32 @test_not_captured_before_load_same_bb(i32** %in.ptr) {
|
|||
define i32 @test_not_captured_before_load_same_bb_escape_unreachable_block(i32** %in.ptr) {
|
||||
; CHECK-LABEL: @test_not_captured_before_load_same_bb_escape_unreachable_block(
|
||||
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
|
||||
; CHECK-NEXT: store i32 55, i32* [[A]], align 4
|
||||
; CHECK-NEXT: [[IN_LV_1:%.*]] = load i32*, i32** [[IN_PTR:%.*]], align 2
|
||||
; CHECK-NEXT: [[IN_LV_2:%.*]] = load i32, i32* [[IN_LV_1]], align 2
|
||||
; CHECK-NEXT: store i32 99, i32* [[A]], align 4
|
||||
|
@ -72,6 +74,7 @@ define i32 @test_captured_and_clobbered_after_load_same_bb_2(i32** %in.ptr) {
|
|||
define i32 @test_captured_after_load_same_bb_2_clobbered_later(i32** %in.ptr) {
|
||||
; CHECK-LABEL: @test_captured_after_load_same_bb_2_clobbered_later(
|
||||
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
|
||||
; CHECK-NEXT: store i32 55, i32* [[A]], align 4
|
||||
; CHECK-NEXT: [[IN_LV_1:%.*]] = load i32*, i32** [[IN_PTR:%.*]], align 2
|
||||
; CHECK-NEXT: [[IN_LV_2:%.*]] = load i32, i32* [[IN_LV_1]], align 2
|
||||
; CHECK-NEXT: call void @escape_writeonly(i32* [[A]])
|
||||
|
@ -135,8 +138,8 @@ define i32 @test_captured_before_load_same_bb_2(i32** %in.ptr) {
|
|||
; CHECK-LABEL: @test_captured_before_load_same_bb_2(
|
||||
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
|
||||
; CHECK-NEXT: store i32 55, i32* [[A]], align 4
|
||||
; CHECK-NEXT: call void @escape_writeonly(i32* [[A]])
|
||||
; CHECK-NEXT: [[IN_LV_1:%.*]] = load i32*, i32** [[IN_PTR:%.*]], align 2
|
||||
; CHECK-NEXT: call void @escape_and_clobber(i32* [[A]])
|
||||
; CHECK-NEXT: [[IN_LV_2:%.*]] = load i32, i32* [[IN_LV_1]], align 2
|
||||
; CHECK-NEXT: store i32 99, i32* [[A]], align 4
|
||||
; CHECK-NEXT: call void @clobber()
|
||||
|
@ -144,8 +147,8 @@ define i32 @test_captured_before_load_same_bb_2(i32** %in.ptr) {
|
|||
;
|
||||
%a = alloca i32, align 4
|
||||
store i32 55, i32* %a
|
||||
call void @escape_writeonly(i32* %a)
|
||||
%in.lv.1 = load i32* , i32** %in.ptr, align 2
|
||||
call void @escape_and_clobber(i32* %a)
|
||||
%in.lv.2 = load i32 , i32* %in.lv.1, align 2
|
||||
store i32 99, i32* %a, align 4
|
||||
call void @clobber()
|
||||
|
@ -197,6 +200,7 @@ define i32 @test_captured_before_load_same_bb(i32** %in.ptr) {
|
|||
define i32 @test_captured_sibling_path_to_load_other_blocks_1(i32** %in.ptr, i1 %c.1) {
|
||||
; CHECK-LABEL: @test_captured_sibling_path_to_load_other_blocks_1(
|
||||
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
|
||||
; CHECK-NEXT: store i32 55, i32* [[A]], align 4
|
||||
; CHECK-NEXT: br i1 [[C_1:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]]
|
||||
; CHECK: then:
|
||||
; CHECK-NEXT: call void @escape_writeonly(i32* [[A]])
|
||||
|
@ -234,6 +238,7 @@ exit:
|
|||
define i32 @test_only_captured_sibling_path_with_ret_to_load_other_blocks(i32** %in.ptr, i1 %c.1) {
|
||||
; CHECK-LABEL: @test_only_captured_sibling_path_with_ret_to_load_other_blocks(
|
||||
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
|
||||
; CHECK-NEXT: store i32 55, i32* [[A]], align 4
|
||||
; CHECK-NEXT: br i1 [[C_1:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]]
|
||||
; CHECK: then:
|
||||
; CHECK-NEXT: call void @escape_writeonly(i32* [[A]])
|
||||
|
@ -412,6 +417,7 @@ exit:
|
|||
define i32 @test_not_captured_before_load_other_blocks_1(i32** %in.ptr, i1 %c.1) {
|
||||
; CHECK-LABEL: @test_not_captured_before_load_other_blocks_1(
|
||||
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
|
||||
; CHECK-NEXT: store i32 55, i32* [[A]], align 4
|
||||
; CHECK-NEXT: [[IN_LV_1:%.*]] = load i32*, i32** [[IN_PTR:%.*]], align 2
|
||||
; CHECK-NEXT: [[IN_LV_2:%.*]] = load i32, i32* [[IN_LV_1]], align 2
|
||||
; CHECK-NEXT: store i32 99, i32* [[A]], align 4
|
||||
|
@ -445,6 +451,7 @@ exit:
|
|||
define i32 @test_not_captured_before_load_other_blocks_2(i32** %in.ptr, i1 %c.1) {
|
||||
; CHECK-LABEL: @test_not_captured_before_load_other_blocks_2(
|
||||
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
|
||||
; CHECK-NEXT: store i32 55, i32* [[A]], align 4
|
||||
; CHECK-NEXT: [[IN_LV_1:%.*]] = load i32*, i32** [[IN_PTR:%.*]], align 2
|
||||
; CHECK-NEXT: [[IN_LV_2:%.*]] = load i32, i32* [[IN_LV_1]], align 2
|
||||
; CHECK-NEXT: store i32 99, i32* [[A]], align 4
|
||||
|
@ -480,6 +487,7 @@ exit:
|
|||
define i32 @test_not_captured_before_load_other_blocks_3(i32** %in.ptr, i1 %c.1) {
|
||||
; CHECK-LABEL: @test_not_captured_before_load_other_blocks_3(
|
||||
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
|
||||
; CHECK-NEXT: store i32 55, i32* [[A]], align 4
|
||||
; CHECK-NEXT: [[IN_LV_1:%.*]] = load i32*, i32** [[IN_PTR:%.*]], align 2
|
||||
; CHECK-NEXT: [[IN_LV_2:%.*]] = load i32, i32* [[IN_LV_1]], align 2
|
||||
; CHECK-NEXT: store i32 99, i32* [[A]], align 4
|
||||
|
@ -513,6 +521,7 @@ exit:
|
|||
define i32 @test_not_captured_before_load_other_blocks_4(i32** %in.ptr, i1 %c.1) {
|
||||
; CHECK-LABEL: @test_not_captured_before_load_other_blocks_4(
|
||||
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
|
||||
; CHECK-NEXT: store i32 55, i32* [[A]], align 4
|
||||
; CHECK-NEXT: br i1 [[C_1:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]]
|
||||
; CHECK: then:
|
||||
; CHECK-NEXT: br label [[EXIT:%.*]]
|
||||
|
@ -551,6 +560,7 @@ define i32 @test_not_captured_before_load_other_blocks_5(i32** %in.ptr, i1 %c.1)
|
|||
; CHECK-LABEL: @test_not_captured_before_load_other_blocks_5(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
|
||||
; CHECK-NEXT: store i32 55, i32* [[A]], align 4
|
||||
; CHECK-NEXT: br i1 [[C_1:%.*]], label [[THEN:%.*]], label [[EXIT:%.*]]
|
||||
; CHECK: then:
|
||||
; CHECK-NEXT: [[IN_LV_1:%.*]] = load i32*, i32** [[IN_PTR:%.*]], align 2
|
||||
|
@ -622,6 +632,7 @@ define i32 @test_not_captured_before_load_other_blocks_7(i32** %in.ptr, i1 %c.1)
|
|||
; CHECK-LABEL: @test_not_captured_before_load_other_blocks_7(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
|
||||
; CHECK-NEXT: store i32 55, i32* [[A]], align 4
|
||||
; CHECK-NEXT: [[IN_LV_1:%.*]] = load i32*, i32** [[IN_PTR:%.*]], align 2
|
||||
; CHECK-NEXT: [[IN_LV_2:%.*]] = load i32, i32* [[IN_LV_1]], align 2
|
||||
; CHECK-NEXT: call void @escape_writeonly(i32* [[A]])
|
||||
|
@ -705,6 +716,7 @@ define i32 @test_not_captured_before_load_may_alias_same_bb_but_read(i32** %in.p
|
|||
define i32 @test_captured_after_loop(i32** %in.ptr, i1 %c.1) {
|
||||
; CHECK-LABEL: @test_captured_after_loop(
|
||||
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
|
||||
; CHECK-NEXT: store i32 55, i32* [[A]], align 4
|
||||
; CHECK-NEXT: br label [[LOOP:%.*]]
|
||||
; CHECK: loop:
|
||||
; CHECK-NEXT: [[IN_LV_1:%.*]] = load i32*, i32** [[IN_PTR:%.*]], align 2
|
||||
|
@ -768,6 +780,9 @@ declare void @llvm.memset.p0i8.i32(i8* nocapture writeonly, i8, i32, i1 immarg)
|
|||
define void @test_memset_not_captured_before_load() {
|
||||
; CHECK-LABEL: @test_memset_not_captured_before_load(
|
||||
; CHECK-NEXT: [[A:%.*]] = alloca [2 x i32], align 4
|
||||
; CHECK-NEXT: [[CAST_A:%.*]] = bitcast [2 x i32]* [[A]] to i8*
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, i8* [[CAST_A]], i32 4
|
||||
; CHECK-NEXT: call void @llvm.memset.p0i8.i32(i8* align 1 [[TMP1]], i8 0, i32 4, i1 false)
|
||||
; CHECK-NEXT: [[LV_1:%.*]] = load [10 x i16]*, [10 x i16]** @global, align 8
|
||||
; CHECK-NEXT: [[GEP_A_0:%.*]] = getelementptr inbounds [2 x i32], [2 x i32]* [[A]], i32 0, i32 0
|
||||
; CHECK-NEXT: store i32 1, i32* [[GEP_A_0]], align 4
|
||||
|
@ -799,8 +814,7 @@ define void @test_test_not_captured_before_load(i1 %c.1) {
|
|||
; CHECK-NEXT: bb:
|
||||
; CHECK-NEXT: [[A:%.*]] = alloca [2 x i32], align 4
|
||||
; CHECK-NEXT: [[CAST_A:%.*]] = bitcast [2 x i32]* [[A]] to i8*
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, i8* [[CAST_A]], i32 4
|
||||
; CHECK-NEXT: call void @llvm.memset.p0i8.i32(i8* align 1 [[TMP0]], i8 0, i32 4, i1 false)
|
||||
; CHECK-NEXT: call void @llvm.memset.p0i8.i32(i8* [[CAST_A]], i8 0, i32 8, i1 false)
|
||||
; CHECK-NEXT: [[LV_1:%.*]] = load [10 x i16]*, [10 x i16]** @global, align 8
|
||||
; CHECK-NEXT: [[GEP_LV:%.*]] = getelementptr inbounds [10 x i16], [10 x i16]* [[LV_1]], i64 0, i32 1
|
||||
; CHECK-NEXT: [[LV_2:%.*]] = load i16, i16* [[GEP_LV]], align 2
|
||||
|
@ -1024,6 +1038,7 @@ declare noalias i32* @alloc() nounwind
|
|||
define i32 @test_not_captured_before_load_same_bb_noalias_call(i32** %in.ptr) {
|
||||
; CHECK-LABEL: @test_not_captured_before_load_same_bb_noalias_call(
|
||||
; CHECK-NEXT: [[A:%.*]] = call i32* @alloc()
|
||||
; CHECK-NEXT: store i32 55, i32* [[A]], align 4
|
||||
; CHECK-NEXT: [[IN_LV_1:%.*]] = load i32*, i32** [[IN_PTR:%.*]], align 2
|
||||
; CHECK-NEXT: [[IN_LV_2:%.*]] = load i32, i32* [[IN_LV_1]], align 2
|
||||
; CHECK-NEXT: store i32 99, i32* [[A]], align 4
|
||||
|
@ -1041,9 +1056,10 @@ define i32 @test_not_captured_before_load_same_bb_noalias_call(i32** %in.ptr) {
|
|||
|
||||
define i32 @test_not_captured_before_load_same_bb_noalias_arg(i32** %in.ptr, i32* noalias %a) {
|
||||
; CHECK-LABEL: @test_not_captured_before_load_same_bb_noalias_arg(
|
||||
; CHECK-NEXT: store i32 55, i32* [[A:%.*]], align 4
|
||||
; CHECK-NEXT: [[IN_LV_1:%.*]] = load i32*, i32** [[IN_PTR:%.*]], align 2
|
||||
; CHECK-NEXT: [[IN_LV_2:%.*]] = load i32, i32* [[IN_LV_1]], align 2
|
||||
; CHECK-NEXT: store i32 99, i32* [[A:%.*]], align 4
|
||||
; CHECK-NEXT: store i32 99, i32* [[A]], align 4
|
||||
; CHECK-NEXT: call void @escape_and_clobber(i32* [[A]])
|
||||
; CHECK-NEXT: ret i32 [[IN_LV_2]]
|
||||
;
|
||||
|
@ -1054,42 +1070,3 @@ define i32 @test_not_captured_before_load_same_bb_noalias_arg(i32** %in.ptr, i32
|
|||
call void @escape_and_clobber(i32* %a)
|
||||
ret i32 %in.lv.2
|
||||
}
|
||||
|
||||
define i32 @instruction_captures_multiple_objects(i32* %p.1, i32** %p.2, i32** %p.3, i1 %c) {
|
||||
; CHECK-LABEL: @instruction_captures_multiple_objects(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[A_1:%.*]] = alloca i32, align 4
|
||||
; CHECK-NEXT: [[A_2:%.*]] = alloca i32, align 4
|
||||
; CHECK-NEXT: store i32 0, i32* [[P_1:%.*]], align 8
|
||||
; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]]
|
||||
; CHECK: then:
|
||||
; CHECK-NEXT: [[LV_2:%.*]] = load i32*, i32** [[P_2:%.*]], align 8
|
||||
; CHECK-NEXT: [[LV_2_2:%.*]] = load i32, i32* [[LV_2]], align 4
|
||||
; CHECK-NEXT: ret i32 [[LV_2_2]]
|
||||
; CHECK: else:
|
||||
; CHECK-NEXT: [[LV_3:%.*]] = load i32*, i32** [[P_3:%.*]], align 8
|
||||
; CHECK-NEXT: [[LV_3_2:%.*]] = load i32, i32* [[LV_3]], align 4
|
||||
; CHECK-NEXT: call void @capture_and_clobber_multiple(i32* [[A_1]], i32* [[A_2]])
|
||||
; CHECK-NEXT: ret i32 [[LV_3_2]]
|
||||
;
|
||||
entry:
|
||||
%a.1 = alloca i32
|
||||
%a.2 = alloca i32
|
||||
store i32 0, i32* %p.1, align 8
|
||||
br i1 %c, label %then, label %else
|
||||
|
||||
then:
|
||||
store i32 99, i32* %a.2, align 4
|
||||
%lv.2 = load i32*, i32** %p.2
|
||||
%lv.2.2 = load i32, i32* %lv.2
|
||||
store i32 0, i32* %a.1, align 8
|
||||
ret i32 %lv.2.2
|
||||
|
||||
else:
|
||||
%lv.3 = load i32*, i32** %p.3
|
||||
%lv.3.2 = load i32, i32* %lv.3
|
||||
call void @capture_and_clobber_multiple(i32* %a.1, i32* %a.2)
|
||||
ret i32 %lv.3.2
|
||||
}
|
||||
|
||||
declare void @capture_and_clobber_multiple(i32*, i32*)
|
||||
|
|
Loading…
Reference in New Issue