}
return false;
}
+
+ bool contains(const Instruction *I) const { return EphValues.contains(I); }
};
} // namespace
unsigned SpeculatedInstructions = 0;
Value *SpeculatedStoreValue = nullptr;
StoreInst *SpeculatedStore = nullptr;
- for (Instruction &I : drop_end(*ThenBB)) {
+ EphemeralValueTracker EphTracker;
+ for (Instruction &I : reverse(drop_end(*ThenBB))) {
// Skip debug info.
if (isa<DbgInfoIntrinsic>(I)) {
SpeculatedDbgIntrinsics.push_back(&I);
continue;
}
+ // Ignore ephemeral values, they will be dropped by the transform.
+ if (EphTracker.track(&I))
+ continue;
+
// Only speculatively execute a single instruction (not counting the
// terminator) for now.
++SpeculatedInstructions;
// be misleading while debugging.
// Similarly strip attributes that maybe dependent on condition we are
// hoisting above.
- for (auto &I : *ThenBB) {
+ for (auto &I : make_early_inc_range(*ThenBB)) {
if (!SpeculatedStoreValue || &I != SpeculatedStore)
I.setDebugLoc(DebugLoc());
I.dropUndefImplyingAttrsAndUnknownMetadata();
+
+ // Drop ephemeral values.
+ if (EphTracker.contains(&I)) {
+ I.replaceAllUsesWith(PoisonValue::get(I.getType()));
+ I.eraseFromParent();
+ }
}
// Hoist the instructions.
define i32 @speculate_block_with_assume_basic(i1 %c, i32 %x) {
; CHECK-LABEL: @speculate_block_with_assume_basic(
; CHECK-NEXT: entry:
-; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[JOIN:%.*]]
-; CHECK: if:
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[X:%.*]], 0
-; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT: br label [[JOIN]]
-; CHECK: join:
-; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ 1, [[IF]] ]
-; CHECK-NEXT: ret i32 [[PHI]]
+; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[C:%.*]], i32 1, i32 0
+; CHECK-NEXT: ret i32 [[SPEC_SELECT]]
;
entry:
br i1 %c, label %if, label %join
define i32 @speculate_block_with_assume_extra_instr(i1 %c, i32 %x) {
; CHECK-LABEL: @speculate_block_with_assume_extra_instr(
; CHECK-NEXT: entry:
-; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[JOIN:%.*]]
-; CHECK: if:
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X:%.*]], 1
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[ADD]], 0
-; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT: br label [[JOIN]]
-; CHECK: join:
-; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[ADD]], [[IF]] ]
-; CHECK-NEXT: ret i32 [[PHI]]
+; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[C:%.*]], i32 [[ADD]], i32 0
+; CHECK-NEXT: ret i32 [[SPEC_SELECT]]
;
entry:
br i1 %c, label %if, label %join
ret i32 %phi
}
+; We only allow speculating one instruction. Here %add and %add2 are used by
+; the assume, but not ephemeral, because they are also used by %phi.
define i32 @speculate_block_with_assume_extra_instrs_too_many(i1 %c, i32 %x) {
; CHECK-LABEL: @speculate_block_with_assume_extra_instrs_too_many(
; CHECK-NEXT: entry:
define i32 @speculate_block_with_assume_extra_instrs_okay(i1 %c, i32 %x) {
; CHECK-LABEL: @speculate_block_with_assume_extra_instrs_okay(
; CHECK-NEXT: entry:
-; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[JOIN:%.*]]
-; CHECK: if:
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X:%.*]], 1
-; CHECK-NEXT: [[ADD2:%.*]] = add i32 [[ADD]], 1
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[ADD2]], 0
-; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT: br label [[JOIN]]
-; CHECK: join:
-; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[ADD]], [[IF]] ]
-; CHECK-NEXT: ret i32 [[PHI]]
+; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[C:%.*]], i32 [[ADD]], i32 0
+; CHECK-NEXT: ret i32 [[SPEC_SELECT]]
;
entry:
br i1 %c, label %if, label %join
define i32 @speculate_block_with_assume_operand_bundle(i1 %c, ptr %p) {
; CHECK-LABEL: @speculate_block_with_assume_operand_bundle(
; CHECK-NEXT: entry:
-; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[JOIN:%.*]]
-; CHECK: if:
-; CHECK-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(ptr [[P:%.*]]) ]
-; CHECK-NEXT: br label [[JOIN]]
-; CHECK: join:
-; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ 1, [[IF]] ]
-; CHECK-NEXT: ret i32 [[PHI]]
+; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[C:%.*]], i32 1, i32 0
+; CHECK-NEXT: ret i32 [[SPEC_SELECT]]
;
entry:
br i1 %c, label %if, label %join
; CHECK-NEXT: bb:
; CHECK-NEXT: br label [[BB2:%.*]]
; CHECK: bb2:
-; CHECK-NEXT: [[BORG:%.*]] = phi i32 [ 0, [[BB:%.*]] ], [ [[BORG]], [[BB8:%.*]] ]
-; CHECK-NEXT: [[BORG3:%.*]] = phi i32 [ 8, [[BB]] ], [ [[BORG10:%.*]], [[BB8]] ]
+; CHECK-NEXT: [[BORG:%.*]] = phi i32 [ 0, [[BB:%.*]] ], [ [[BORG]], [[BB2]] ]
+; CHECK-NEXT: [[BORG3:%.*]] = phi i32 [ 8, [[BB]] ], [ [[SPEC_SELECT:%.*]], [[BB2]] ]
; CHECK-NEXT: [[BORG4:%.*]] = tail call i32 @blam(i8* [[ARG:%.*]], i32 [[BORG]])
; CHECK-NEXT: [[BORG5:%.*]] = icmp eq i32 [[BORG4]], 0
-; CHECK-NEXT: br i1 [[BORG5]], label [[BB8]], label [[BB6:%.*]]
-; CHECK: bb6:
-; CHECK-NEXT: [[BORG7:%.*]] = load i8*, i8** [[ARG1:%.*]], align 4
-; CHECK-NEXT: br label [[BB8]]
-; CHECK: bb8:
-; CHECK-NEXT: [[BORG10]] = phi i32 [ [[BORG4]], [[BB6]] ], [ [[BORG3]], [[BB2]] ]
+; CHECK-NEXT: [[SPEC_SELECT]] = select i1 [[BORG5]], i32 [[BORG3]], i32 [[BORG4]]
; CHECK-NEXT: [[BORG11:%.*]] = icmp ult i32 [[BORG]], 2
; CHECK-NEXT: br i1 [[BORG11]], label [[BB2]], label [[BB12:%.*]]
; CHECK: bb12: