}
///
-/// Check if 2 stores can be sunk, optionally together with corresponding GEPs.
+/// Check if 2 stores can be sunk together with corresponding GEPs
///
bool MergedLoadStoreMotion::canSinkStoresAndGEPs(StoreInst *S0,
StoreInst *S1) const {
- if (S0->getPointerOperand() == S1->getPointerOperand())
- return true;
- auto *GEP0 = dyn_cast<GetElementPtrInst>(S0->getPointerOperand());
- auto *GEP1 = dyn_cast<GetElementPtrInst>(S1->getPointerOperand());
- return GEP0 && GEP1 && GEP0->isIdenticalTo(GEP1) && GEP0->hasOneUse() &&
- (GEP0->getParent() == S0->getParent()) && GEP1->hasOneUse() &&
- (GEP1->getParent() == S1->getParent());
+ auto *A0 = dyn_cast<Instruction>(S0->getPointerOperand());
+ auto *A1 = dyn_cast<Instruction>(S1->getPointerOperand());
+ return A0 && A1 && A0->isIdenticalTo(A1) && A0->hasOneUse() &&
+ (A0->getParent() == S0->getParent()) && A1->hasOneUse() &&
+ (A1->getParent() == S1->getParent()) && isa<GetElementPtrInst>(A0);
}
///
/// Merge two stores to same address and sink into \p BB
///
-/// Optionally also sinks GEP instruction computing the store address
+/// Also sinks GEP instruction computing the store address
///
void MergedLoadStoreMotion::sinkStoresAndGEPs(BasicBlock *BB, StoreInst *S0,
StoreInst *S1) {
- Value *Ptr0 = S0->getPointerOperand();
- Value *Ptr1 = S1->getPointerOperand();
// Only one definition?
+ auto *A0 = dyn_cast<Instruction>(S0->getPointerOperand());
+ auto *A1 = dyn_cast<Instruction>(S1->getPointerOperand());
LLVM_DEBUG(dbgs() << "Sink Instruction into BB \n"; BB->dump();
dbgs() << "Instruction Left\n"; S0->dump(); dbgs() << "\n";
dbgs() << "Instruction Right\n"; S1->dump(); dbgs() << "\n");
// Create the new store to be inserted at the join point.
StoreInst *SNew = cast<StoreInst>(S0->clone());
+ Instruction *ANew = A0->clone();
SNew->insertBefore(&*InsertPt);
+ ANew->insertBefore(SNew);
+ ANew->applyMergedLocation(A0->getDebugLoc(), A1->getDebugLoc());
+
+ assert(S0->getParent() == A0->getParent());
+ assert(S1->getParent() == A1->getParent());
+
// New PHI operand? Use it.
if (PHINode *NewPN = getPHIOperand(BB, S0, S1))
SNew->setOperand(0, NewPN);
S0->eraseFromParent();
S1->eraseFromParent();
-
- if (Ptr0 != Ptr1) {
- auto *GEP0 = cast<GetElementPtrInst>(Ptr0);
- auto *GEP1 = cast<GetElementPtrInst>(Ptr1);
- Instruction *GEPNew = GEP0->clone();
- GEPNew->insertBefore(SNew);
- GEPNew->applyMergedLocation(GEP0->getDebugLoc(), GEP1->getDebugLoc());
- SNew->setOperand(1, GEPNew);
- GEP0->eraseFromParent();
- GEP1->eraseFromParent();
- }
+ A0->replaceAllUsesWith(ANew);
+ A0->eraseFromParent();
+ A1->replaceAllUsesWith(ANew);
+ A1->eraseFromParent();
}
///
%struct.S = type { i32 }
-define dso_local void @foo(ptr %this, i32 %bar) {
+define dso_local void @foo(%struct.S* %this, i32 %bar) {
entry:
- %this.addr = alloca ptr, align 8
+ %this.addr = alloca %struct.S*, align 8
%bar.addr = alloca i32, align 4
- store ptr %this, ptr %this.addr, align 8
- store i32 %bar, ptr %bar.addr, align 4
- %this1 = load ptr, ptr %this.addr, align 8
- %0 = load i32, ptr %bar.addr, align 4
+ store %struct.S* %this, %struct.S** %this.addr, align 8
+ store i32 %bar, i32* %bar.addr, align 4
+ %this1 = load %struct.S*, %struct.S** %this.addr, align 8
+ %0 = load i32, i32* %bar.addr, align 4
%tobool = icmp ne i32 %0, 0
br i1 %tobool, label %if.then, label %if.else
if.then: ; preds = %entry
- store i32 1, ptr %this1, align 4
+ %foo = getelementptr inbounds %struct.S, %struct.S* %this1, i32 0, i32 0
+ store i32 1, i32* %foo, align 4
br label %if.end
if.else: ; preds = %entry
- store i32 0, ptr %this1, align 4
+ %foo2 = getelementptr inbounds %struct.S, %struct.S* %this1, i32 0, i32 0
+ store i32 0, i32* %foo2, align 4
br label %if.end
if.end: ; preds = %if.else, %if.then
; CHECK-LABEL: return:
; CHECK-NEXT: %.sink = phi i16 [ 5, %if.end ], [ 6, %if.then ]
-; CHECK-NEXT: store i16 %.sink, ptr %agg.result
-; CHECK-NEXT: %0 = getelementptr inbounds %struct.S0, ptr %agg.result, i16 0, i32 1
-; CHECK-NEXT: store i16 0, ptr %0
+; CHECK-NEXT: %0 = getelementptr inbounds %struct.S0, %struct.S0* %agg.result, i16 0, i32 0
+; CHECK-NEXT: store i16 %.sink, i16* %0
+; CHECK-NEXT: %1 = getelementptr inbounds %struct.S0, %struct.S0* %agg.result, i16 0, i32 1
+; CHECK-NEXT: store i16 0, i16* %1
; CHECK-NEXT: ret void
%struct.S0 = type { i16, i16 }
@g_173 = dso_local local_unnamed_addr global i16 0, !dbg !0
; Function Attrs: noinline norecurse nounwind
-define dso_local void @func_34(ptr noalias sret(%struct.S0) %agg.result) local_unnamed_addr #0 !dbg !11 {
+define dso_local void @func_34(%struct.S0* noalias sret(%struct.S0) %agg.result) local_unnamed_addr #0 !dbg !11 {
entry:
br i1 undef, label %if.end, label %if.then, !dbg !18
call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
call void @llvm.dbg.value(metadata i16 5, metadata !19, metadata !DIExpression()), !dbg !22
- store i16 6, ptr %agg.result, !dbg !23
- %l_303.sroa.2.0..sroa_idx1 = getelementptr inbounds %struct.S0, ptr %agg.result, i16 0, i32 1, !dbg !23
- store i16 0, ptr %l_303.sroa.2.0..sroa_idx1, !dbg !23
+ %l_303.sroa.0.0..sroa_idx = getelementptr inbounds %struct.S0, %struct.S0* %agg.result, i16 0, i32 0, !dbg !23
+ store i16 6, i16* %l_303.sroa.0.0..sroa_idx, !dbg !23
+ %l_303.sroa.2.0..sroa_idx1 = getelementptr inbounds %struct.S0, %struct.S0* %agg.result, i16 0, i32 1, !dbg !23
+ store i16 0, i16* %l_303.sroa.2.0..sroa_idx1, !dbg !23
br label %return, !dbg !24
if.end: ; preds = %entry
- store i16 5, ptr %agg.result, !dbg !25
- %f138 = getelementptr inbounds %struct.S0, ptr %agg.result, i16 0, i32 1, !dbg !25
- store i16 0, ptr %f138, !dbg !25
- store i16 0, ptr @g_173, !dbg !27
+ %f037 = getelementptr inbounds %struct.S0, %struct.S0* %agg.result, i16 0, i32 0, !dbg !25
+ store i16 5, i16* %f037, !dbg !25
+ %f138 = getelementptr inbounds %struct.S0, %struct.S0* %agg.result, i16 0, i32 1, !dbg !25
+ store i16 0, i16* %f138, !dbg !25
+ store i16 0, i16* @g_173, !dbg !27
br label %return, !dbg !28
return: ; preds = %if.end, %if.then
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
+; CHECK-NEXT: store i32 [[X:%.*]], ptr [[P:%.*]], align 4
; CHECK-NEXT: br label [[IF_END:%.*]]
; CHECK: if.else:
+; CHECK-NEXT: store i32 [[Y:%.*]], ptr [[P]], align 4
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
-; CHECK-NEXT: [[Y_SINK:%.*]] = phi i32 [ [[X:%.*]], [[IF_THEN]] ], [ [[Y:%.*]], [[IF_ELSE]] ]
-; CHECK-NEXT: store i32 [[Y_SINK]], ptr [[P:%.*]], align 4
; CHECK-NEXT: ret void
;
entry:
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 1
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
+; CHECK-NEXT: store i32 [[X:%.*]], ptr [[GEP]], align 4
; CHECK-NEXT: br label [[IF_END:%.*]]
; CHECK: if.else:
+; CHECK-NEXT: store i32 [[Y:%.*]], ptr [[GEP]], align 4
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
-; CHECK-NEXT: [[Y_SINK:%.*]] = phi i32 [ [[X:%.*]], [[IF_THEN]] ], [ [[Y:%.*]], [[IF_ELSE]] ]
-; CHECK-NEXT: store i32 [[Y_SINK]], ptr [[GEP]], align 4
; CHECK-NEXT: ret void
;
entry:
; CHECK-YES: bb5:
; CHECK-YES-NEXT: br i1 [[ARG3:%.*]], label [[BB6:%.*]], label [[BB7:%.*]]
; CHECK-YES: bb6:
+; CHECK-YES-NEXT: store i32 2, ptr [[ARG]], align 4
; CHECK-YES-NEXT: br label [[BB9_SINK_SPLIT:%.*]]
; CHECK-YES: bb7:
+; CHECK-YES-NEXT: store i32 3, ptr [[ARG]], align 4
; CHECK-YES-NEXT: br label [[BB9_SINK_SPLIT]]
; CHECK-YES: bb9.sink.split:
-; CHECK-YES-NEXT: [[DOTSINK:%.*]] = phi i32 [ 2, [[BB6]] ], [ 3, [[BB7]] ]
-; CHECK-YES-NEXT: store i32 [[DOTSINK]], ptr [[ARG]], align 4
; CHECK-YES-NEXT: [[TMP0:%.*]] = getelementptr inbounds i32, ptr [[ARG1:%.*]], i64 1
; CHECK-YES-NEXT: store i32 3, ptr [[TMP0]], align 4
; CHECK-YES-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[ARG1]], i64 2