return const_cast<Value *>(this)->getSingleUndroppableUse();
}
+ /// Return true if there is exactly one unique user of this value that cannot be
+ /// dropped (that user can have multiple uses of this value).
+ User *getUniqueUndroppableUser();
+ const User *getUniqueUndroppableUser() const {
+ return const_cast<Value *>(this)->getUniqueUndroppableUser();
+ }
+
/// Return true if there this value.
///
/// This is specialized because it is a common request and does not require
return Result;
}
+User *Value::getUniqueUndroppableUser() {
+ User *Result = nullptr;
+ for (auto *U : users()) {
+ if (!U->isDroppable()) {
+ if (Result && Result != U)
+ return nullptr;
+ Result = U;
+ }
+ }
+ return Result;
+}
+
bool Value::hasNUndroppableUses(unsigned int N) const {
return hasNItems(user_begin(), user_end(), N, isUnDroppableUser);
}
/// instruction past all of the instructions between it and the end of its
/// block.
static bool TryToSinkInstruction(Instruction *I, BasicBlock *DestBlock) {
- assert(I->getSingleUndroppableUse() && "Invariants didn't hold!");
+ assert(I->getUniqueUndroppableUser() && "Invariants didn't hold!");
BasicBlock *SrcBlock = I->getParent();
// Cannot move control-flow-involving, volatile loads, vaarg, etc.
[this](Instruction *I) -> Optional<BasicBlock *> {
if (!EnableCodeSinking)
return None;
- Use *SingleUse = I->getSingleUndroppableUse();
- if (!SingleUse)
+ auto *UserInst = cast_or_null<Instruction>(I->getUniqueUndroppableUser());
+ if (!UserInst)
return None;
BasicBlock *BB = I->getParent();
- Instruction *UserInst = cast<Instruction>(SingleUse->getUser());
- BasicBlock *UserParent;
-
- // Get the block the use occurs in.
- if (PHINode *PN = dyn_cast<PHINode>(UserInst))
- UserParent = PN->getIncomingBlock(*SingleUse);
- else
+ BasicBlock *UserParent = nullptr;
+
+ // Special handling for Phi nodes - get the block the use occurs in.
+ if (PHINode *PN = dyn_cast<PHINode>(UserInst)) {
+ for (unsigned i = 0; i < PN->getNumIncomingValues(); i++) {
+ if (PN->getIncomingValue(i) == I) {
+ // Bail out if we have uses in different blocks. We don't do any
+ // sophisticated analysis (i.e finding NearestCommonDominator of these
+ // use blocks).
+ if (UserParent && UserParent != PN->getIncomingBlock(i))
+ return None;
+ UserParent = PN->getIncomingBlock(i);
+ }
+ }
+ assert(UserParent && "expected to find user block!");
+ } else
UserParent = UserInst->getParent();
// Try sinking to another block. If that block is unreachable, then do
define void @PR33765(i8 %beth) {
; CHECK-LABEL: @PR33765(
-; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[BETH:%.*]] to i32
; CHECK-NEXT: br i1 false, label [[IF_THEN9:%.*]], label [[IF_THEN9]]
; CHECK: if.then9:
+; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[BETH:%.*]] to i32
; CHECK-NEXT: [[MUL:%.*]] = mul nuw nsw i32 [[CONV]], [[CONV]]
; CHECK-NEXT: [[TINKY:%.*]] = load i16, i16* @glob, align 2
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[MUL]] to i16
}
declare i32 @foo(i32, i32)
-; TODO: Two uses in a single user. We can still sink the instruction (tmp.9).
+; Two uses in a single user. We can still sink the instruction (tmp.9).
define i32 @test4(i32 %A, i32 %B, i1 %C) {
; CHECK-LABEL: @test4(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[TMP_9:%.*]] = add i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[ENDIF:%.*]]
; CHECK: then:
+; CHECK-NEXT: [[TMP_9:%.*]] = add i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT: [[RES:%.*]] = call i32 @foo(i32 [[TMP_9]], i32 [[TMP_9]])
; CHECK-NEXT: ret i32 [[RES]]
; CHECK: endif:
ret i32 %sum.0
}
-; TODO: Multiple uses but from same BB. We can sink.
+; Multiple uses but from same BB. We can sink.
define i32 @test6(i32* nocapture readonly %P, i32 %i, i1 %cond) {
; CHECK-LABEL: @test6(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I:%.*]] to i64
-; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[P:%.*]], i64 [[IDXPROM]]
-; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[ARRAYIDX]], align 4
; CHECK-NEXT: [[ADD:%.*]] = shl nsw i32 [[I]], 1
; CHECK-NEXT: br label [[DISPATCHBB:%.*]]
; CHECK: dispatchBB:
+; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I:%.*]] to i64
+; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[P:%.*]], i64 [[IDXPROM]]
+; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[ARRAYIDX]], align 4
; CHECK-NEXT: switch i32 [[I]], label [[SW_BB:%.*]] [
; CHECK-NEXT: i32 5, label [[SW_EPILOG:%.*]]
; CHECK-NEXT: i32 2, label [[SW_EPILOG]]
define i8 @k_bb(<4 x i8> %x) {
; CHECK-LABEL: @k_bb(
-; CHECK-NEXT: [[X0:%.*]] = extractelement <4 x i8> [[X:%.*]], i32 0
; CHECK-NEXT: br label [[BB1:%.*]]
; CHECK: bb1:
+; CHECK-NEXT: [[X0:%.*]] = extractelement <4 x i8> [[X:%.*]], i32 0
; CHECK-NEXT: [[X3:%.*]] = extractelement <4 x i8> [[X]], i32 3
; CHECK-NEXT: [[X1:%.*]] = extractelement <4 x i8> [[X]], i32 1
; CHECK-NEXT: [[X2:%.*]] = extractelement <4 x i8> [[X]], i32 2
define i8 @k_bb(<4 x i8> %x) {
; CHECK-LABEL: @k_bb(
-; CHECK-NEXT: [[X0:%.*]] = extractelement <4 x i8> [[X:%.*]], i32 0
; CHECK-NEXT: br label [[BB1:%.*]]
; CHECK: bb1:
+; CHECK-NEXT: [[X0:%.*]] = extractelement <4 x i8> [[X:%.*]], i32 0
; CHECK-NEXT: [[X3:%.*]] = extractelement <4 x i8> [[X]], i32 3
; CHECK-NEXT: [[X1:%.*]] = extractelement <4 x i8> [[X]], i32 1
; CHECK-NEXT: [[X2:%.*]] = extractelement <4 x i8> [[X]], i32 2