This patch makes FoldBranchToCommonDest merge branch conditions into `select i1` rather than `and/or i1` when it is called by SimplifyCFG.
It is known that merging conditions into and/or is poison-unsafe, and this is towards making things *more* correct by removing possible miscompilations.
Currently, InstCombine simply consumes these selects into and/or of i1 (which is also unsafe), so the visible effect would be very small. The unsafe select -> and/or transformation will be removed in the future.
There has been efforts for updating optimizations to support the select form as well, and they are linked to D93065.
The safe transformation is fired when it is called by SimplifyCFG only. This is done by setting the new `PoisonSafe` argument as true.
Another place that calls FoldBranchToCommonDest is LoopSimplify. `PoisonSafe` flag is set to false in this case because enabling it has a nontrivial impact in performance because SCEV is more conservative with select form and InductiveRangeCheckElimination isn't aware of select form of and/or i1.
Reviewed By: nikic
Differential Revision: https://reviews.llvm.org/D95026
return Insert(BinOp, Name);
}
+ Value *CreateLogicalAnd(Value *Cond1, Value *Cond2, const Twine &Name = "") {
+ assert(Cond2->getType()->isIntOrIntVectorTy(1));
+ return CreateSelect(Cond1, Cond2,
+ ConstantInt::getNullValue(Cond2->getType()), Name);
+ }
+
+ Value *CreateLogicalOr(Value *Cond1, Value *Cond2, const Twine &Name = "") {
+ assert(Cond2->getType()->isIntOrIntVectorTy(1));
+ return CreateSelect(Cond1, ConstantInt::getAllOnesValue(Cond2->getType()),
+ Cond2, Name);
+ }
+
CallInst *CreateConstrainedFPBinOp(
Intrinsic::ID ID, Value *L, Value *R, Instruction *FMFSource = nullptr,
const Twine &Name = "", MDNode *FPMathTag = nullptr,
/// If this basic block is ONLY a setcc and a branch, and if a predecessor
/// branches to us and one of our successors, fold the setcc into the
/// predecessor and use logical operations to pick the right destination.
+/// If PoisonSafe is true, use select i1 rather than and/or i1 to successfully
+/// block unexpected propagation of poison when merging the branches. This is
+/// set to false by default when used by LoopSimplify for performance, but this
+/// should be turned on by default.
bool FoldBranchToCommonDest(BranchInst *BI, llvm::DomTreeUpdater *DTU = nullptr,
MemorySSAUpdater *MSSAU = nullptr,
const TargetTransformInfo *TTI = nullptr,
- unsigned BonusInstThreshold = 1);
+ unsigned BonusInstThreshold = 1,
+ bool PoisonSafe = false);
/// This function takes a virtual register computed by an Instruction and
/// replaces it with a slot in the stack frame, allocated via alloca.
static bool PerformBranchToCommonDestFolding(BranchInst *BI, BranchInst *PBI,
DomTreeUpdater *DTU,
- MemorySSAUpdater *MSSAU) {
+ MemorySSAUpdater *MSSAU,
+ bool PoisonSafe) {
BasicBlock *BB = BI->getParent();
BasicBlock *PredBlock = PBI->getParent();
// Now that the Cond was cloned into the predecessor basic block,
// or/and the two conditions together.
- Instruction *NewCond = cast<Instruction>(Builder.CreateBinOp(
- Opc, PBI->getCondition(), VMap[BI->getCondition()], "or.cond"));
+ Value *NewCond = nullptr;
+ Value *BICond = VMap[BI->getCondition()];
+ bool UseBinOp = !PoisonSafe || impliesPoison(BICond, PBI->getCondition());
+
+ if (UseBinOp)
+ NewCond = Builder.CreateBinOp(Opc, PBI->getCondition(), BICond, "or.cond");
+ else
+ NewCond =
+ Opc == Instruction::And
+ ? Builder.CreateLogicalAnd(PBI->getCondition(), BICond, "or.cond")
+ : Builder.CreateLogicalOr(PBI->getCondition(), BICond, "or.cond");
PBI->setCondition(NewCond);
// Copy any debug value intrinsics into the end of PredBlock.
bool llvm::FoldBranchToCommonDest(BranchInst *BI, DomTreeUpdater *DTU,
MemorySSAUpdater *MSSAU,
const TargetTransformInfo *TTI,
- unsigned BonusInstThreshold) {
+ unsigned BonusInstThreshold,
+ bool PoisonSafe) {
// If this block ends with an unconditional branch,
// let SpeculativelyExecuteBB() deal with it.
if (!BI->isConditional())
continue;
}
- return PerformBranchToCommonDestFolding(BI, PBI, DTU, MSSAU);
+ return PerformBranchToCommonDestFolding(BI, PBI, DTU, MSSAU, PoisonSafe);
}
return Changed;
}
// predecessor and use logical operations to update the incoming value
// for PHI nodes in common successor.
if (FoldBranchToCommonDest(BI, DTU, /*MSSAU=*/nullptr, &TTI,
- Options.BonusInstThreshold))
+ Options.BonusInstThreshold, true))
return requestResimplify();
return false;
}
// branches to us and one of our successors, fold the comparison into the
// predecessor and use logical operations to pick the right destination.
if (FoldBranchToCommonDest(BI, DTU, /*MSSAU=*/nullptr, &TTI,
- Options.BonusInstThreshold))
+ Options.BonusInstThreshold, true))
return requestResimplify();
// We have a conditional branch to two blocks that are only reachable
; CHECK-NEXT: [[V1:%.*]] = icmp ne i32 [[Z:%.*]], 1
; CHECK-NEXT: [[V0:%.*]] = icmp eq i32 [[Z]], 0
; CHECK-NEXT: [[V3_NONCHR:%.*]] = and i1 [[V0]], [[PRED:%.*]]
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[V1]], [[V3_NONCHR]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[V1]], i1 [[V3_NONCHR]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[BB0_NONCHR:%.*]], label [[BB1:%.*]], !prof !19
; CHECK: bb0.nonchr:
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[D:%.*]], 3
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[C:%.*]], [[A:%.*]]
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[ADD]], [[B:%.*]]
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[CMP]], [[CMP1]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[CMP]], i1 [[CMP1]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[COND_FALSE:%.*]], label [[COND_END:%.*]]
; CHECK: cond.false:
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[INPUT:%.*]], align 4
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[D:%.*]], 3
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[C:%.*]], [[A:%.*]]
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[ADD]], [[B:%.*]]
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[CMP]], [[CMP1]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[CMP]], i1 [[CMP1]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[COND_FALSE:%.*]], label [[COND_END:%.*]]
; CHECK: cond.false:
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[INPUT:%.*]], align 4
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i64 [[D:%.*]], 3
; CHECK-NEXT: [[ADD:%.*]] = add nsw i64 [[C:%.*]], [[A:%.*]]
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i64 [[ADD]], [[B:%.*]]
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[CMP]], [[CMP1]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[CMP]], i1 [[CMP1]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[COND_FALSE:%.*]], label [[COND_END:%.*]]
; CHECK: cond.false:
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[INPUT:%.*]], align 4
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[D:%.*]], 3
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[C:%.*]], [[A:%.*]]
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[ADD]], [[B:%.*]]
-; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[CMP]], [[CMP1]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[CMP]], i1 true, i1 [[CMP1]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[COND_END:%.*]], label [[COND_FALSE:%.*]]
; CHECK: cond.false:
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[INPUT:%.*]], align 4
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[D:%.*]], 3
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[C:%.*]], [[A:%.*]]
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[ADD]], [[B:%.*]]
-; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[CMP]], [[CMP1]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[CMP]], i1 true, i1 [[CMP1]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[COND_END:%.*]], label [[COND_FALSE:%.*]]
; CHECK: cond.false:
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[INPUT:%.*]], align 4
; ARM-NEXT: [[CMP:%.*]] = icmp sgt i32 [[D:%.*]], 3
; ARM-NEXT: [[ADD:%.*]] = add nsw i32 [[C:%.*]], [[A:%.*]]
; ARM-NEXT: [[CMP1:%.*]] = icmp slt i32 [[ADD]], [[B:%.*]]
-; ARM-NEXT: [[OR_COND:%.*]] = or i1 [[CMP]], [[CMP1]]
+; ARM-NEXT: [[OR_COND:%.*]] = select i1 [[CMP]], i1 true, i1 [[CMP1]]
; ARM-NEXT: br i1 [[OR_COND]], label [[COND_END:%.*]], label [[COND_FALSE:%.*]]
; ARM: cond.false:
; ARM-NEXT: [[TMP0:%.*]] = load i32, i32* [[INPUT:%.*]], align 4
; ARM-NEXT: [[CMP:%.*]] = icmp sle i32 [[D:%.*]], 3
; ARM-NEXT: [[ADD:%.*]] = add nsw i32 [[C:%.*]], [[A:%.*]]
; ARM-NEXT: [[CMP1:%.*]] = icmp slt i32 [[ADD]], [[B:%.*]]
-; ARM-NEXT: [[OR_COND:%.*]] = or i1 [[CMP]], [[CMP1]]
+; ARM-NEXT: [[OR_COND:%.*]] = select i1 [[CMP]], i1 true, i1 [[CMP1]]
; ARM-NEXT: br i1 [[OR_COND]], label [[COND_END:%.*]], label [[COND_FALSE:%.*]]
; ARM: cond.false:
; ARM-NEXT: [[TMP0:%.*]] = load i32, i32* [[INPUT:%.*]], align 4
; CHECK-NEXT: [[CMP_NOT:%.*]] = xor i1 [[CMP:%.*]], true
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[C:%.*]], [[A:%.*]]
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[ADD]], [[B:%.*]]
-; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[CMP_NOT]], [[CMP1]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[CMP_NOT]], i1 true, i1 [[CMP1]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[COND_END:%.*]], label [[COND_FALSE:%.*]]
; CHECK: cond.false:
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[INPUT:%.*]], align 4
; ARM-NEXT: [[CMP_NOT:%.*]] = xor i1 [[CMP:%.*]], true
; ARM-NEXT: [[ADD:%.*]] = add nsw i32 [[C:%.*]], [[A:%.*]]
; ARM-NEXT: [[CMP1:%.*]] = icmp slt i32 [[ADD]], [[B:%.*]]
-; ARM-NEXT: [[OR_COND:%.*]] = or i1 [[CMP_NOT]], [[CMP1]]
+; ARM-NEXT: [[OR_COND:%.*]] = select i1 [[CMP_NOT]], i1 true, i1 [[CMP1]]
; ARM-NEXT: br i1 [[OR_COND]], label [[COND_END:%.*]], label [[COND_FALSE:%.*]]
; ARM: cond.false:
; ARM-NEXT: [[TMP0:%.*]] = load i32, i32* [[INPUT:%.*]], align 4
; CHECK-NEXT: [[CMP_NOT:%.*]] = xor i1 [[CMP:%.*]], true
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[C:%.*]], [[A:%.*]]
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[ADD]], [[B:%.*]]
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[CMP_NOT]], [[CMP1]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[CMP_NOT]], i1 [[CMP1]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[COND_FALSE:%.*]], label [[COND_END:%.*]]
; CHECK: cond.false:
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[INPUT:%.*]], align 4
; ARM-NEXT: [[CMP_NOT:%.*]] = xor i1 [[CMP:%.*]], true
; ARM-NEXT: [[ADD:%.*]] = add nsw i32 [[C:%.*]], [[A:%.*]]
; ARM-NEXT: [[CMP1:%.*]] = icmp slt i32 [[ADD]], [[B:%.*]]
-; ARM-NEXT: [[OR_COND:%.*]] = and i1 [[CMP_NOT]], [[CMP1]]
+; ARM-NEXT: [[OR_COND:%.*]] = select i1 [[CMP_NOT]], i1 [[CMP1]], i1 false
; ARM-NEXT: br i1 [[OR_COND]], label [[COND_FALSE:%.*]], label [[COND_END:%.*]]
; ARM: cond.false:
; ARM-NEXT: [[TMP0:%.*]] = load i32, i32* [[INPUT:%.*]], align 4
; CHECK-NEXT: entry:
; CHECK-NEXT: [[C_1:%.*]] = icmp ult i8* [[A:%.*]], [[B:%.*]], !annotation !0
; CHECK-NEXT: [[C_2:%.*]] = icmp uge i8* [[C:%.*]], [[D:%.*]], !annotation !0
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C_1]], [[C_2]], !annotation !0
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[C_1]], i1 [[C_2]], i1 false, !annotation !0
; CHECK-NEXT: br i1 [[OR_COND]], label [[CONT1:%.*]], label [[TRAP:%.*]], !annotation !0
; CHECK: trap: ; preds = %entry
; CHECK-NEXT: call void @fn1()
; CHECK-NEXT: entry:
; CHECK-NEXT: [[C_1:%.*]] = icmp uge i8* [[A:%.*]], [[B:%.*]], !annotation !0
; CHECK-NEXT: [[C_2:%.*]] = icmp uge i8* [[C:%.*]], [[D:%.*]], !annotation !0
-; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[C_1]], [[C_2]], !annotation !0
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[C_1]], i1 true, i1 [[C_2]], !annotation !0
; CHECK-NEXT: br i1 [[OR_COND]], label [[TRAP:%.*]], label [[CONT1:%.*]], !annotation !0
; CHECK: trap: ; preds = %entry
; CHECK-NEXT: call void @fn1()
; CHECK-NEXT: [[C_2:%.*]] = xor i1 [[C_1]], true
; CHECK-NEXT: [[C_2_NOT:%.*]] = xor i1 [[C_2]], true, !annotation !0
; CHECK-NEXT: [[C_3:%.*]] = icmp uge i8* [[C:%.*]], [[D:%.*]], !annotation !0
-; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[C_2_NOT]], [[C_3]], !annotation !0
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[C_2_NOT]], i1 true, i1 [[C_3]], !annotation !0
; CHECK-NEXT: br i1 [[OR_COND]], label [[TRAP:%.*]], label [[CONT1:%.*]], !annotation !0
; CHECK: trap: ; preds = %entry
; CHECK-NEXT: call void @fn1()
; CHECK-NEXT: [[C_2:%.*]] = xor i1 [[C_1]], true
; CHECK-NEXT: [[C_2_NOT:%.*]] = xor i1 [[C_2]], true
; CHECK-NEXT: [[C_3:%.*]] = icmp uge i8* [[C:%.*]], [[D:%.*]], !annotation !0
-; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[C_2_NOT]], [[C_3]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[C_2_NOT]], i1 true, i1 [[C_3]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[TRAP:%.*]], label [[CONT1:%.*]], !annotation !0
; CHECK: trap: ; preds = %entry
; CHECK-NEXT: call void @fn1()
;CHECK: icmp eq i32
;CHECK: and i32 %c2, %k
;CHECK: icmp eq i32
-;CHECK: or i1
+;CHECK: select i1 {{.*}}, i1 true,
;CHECK: ret
define i32 @foo(i32 %k, i32 %c1, i32 %c2) {
%1 = and i32 %c1, %k
; CHECK-NEXT: pred:
; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C0]], [[C1]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[C0]], i1 [[C1]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
; CHECK: final_left:
; CHECK-NEXT: call void @sideeffect0()
; CHECK: pred0:
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0
; CHECK-NEXT: [[C3_OLD:%.*]] = icmp eq i8 [[V3:%.*]], 0
-; CHECK-NEXT: [[OR_COND1:%.*]] = or i1 [[C1]], [[C3_OLD]]
+; CHECK-NEXT: [[OR_COND1:%.*]] = select i1 [[C1]], i1 true, i1 [[C3_OLD]]
; CHECK-NEXT: br i1 [[OR_COND1]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
; CHECK: pred1:
; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[V2:%.*]], 0
; CHECK-NEXT: [[C3:%.*]] = icmp eq i8 [[V3]], 0
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C2]], [[C3]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[C2]], i1 [[C3]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]]
; CHECK: final_left:
; CHECK-NEXT: call void @sideeffect0()
; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
; CHECK-NEXT: [[V1_ADJ:%.*]] = add i8 [[V0]], [[V1:%.*]]
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1_ADJ]], 0
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C0]], [[C1]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[C0]], i1 [[C1]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
; CHECK: final_left:
; CHECK-NEXT: call void @sideeffect0()
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0
; CHECK-NEXT: [[V3_ADJ_OLD:%.*]] = add i8 [[V1]], [[V2:%.*]]
; CHECK-NEXT: [[C3_OLD:%.*]] = icmp eq i8 [[V3_ADJ_OLD]], 0
-; CHECK-NEXT: [[OR_COND1:%.*]] = or i1 [[C1]], [[C3_OLD]]
+; CHECK-NEXT: [[OR_COND1:%.*]] = select i1 [[C1]], i1 true, i1 [[C3_OLD]]
; CHECK-NEXT: br i1 [[OR_COND1]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
; CHECK: pred1:
; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[V2]], 0
; CHECK-NEXT: [[V3_ADJ:%.*]] = add i8 [[V1]], [[V2]]
; CHECK-NEXT: [[C3:%.*]] = icmp eq i8 [[V3_ADJ]], 0
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C2]], [[C3]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[C2]], i1 [[C3]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]]
; CHECK: final_left:
; CHECK-NEXT: call void @sideeffect0()
; CHECK-NEXT: [[V1_ADJ:%.*]] = add i8 [[V0]], [[V1:%.*]]
; CHECK-NEXT: [[V1_ADJ_ADJ:%.*]] = add i8 [[V1_ADJ]], [[V1_ADJ]]
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1_ADJ_ADJ]], 0
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C0]], [[C1]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[C0]], i1 [[C1]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
; CHECK: final_left:
; CHECK-NEXT: call void @sideeffect0()
; CHECK-NEXT: [[V3_ADJ_OLD:%.*]] = add i8 [[V1]], [[V2:%.*]]
; CHECK-NEXT: [[V3_ADJ_ADJ_OLD:%.*]] = add i8 [[V3_ADJ_OLD]], [[V3_ADJ_OLD]]
; CHECK-NEXT: [[C3_OLD:%.*]] = icmp eq i8 [[V3_ADJ_ADJ_OLD]], 0
-; CHECK-NEXT: [[OR_COND1:%.*]] = or i1 [[C1]], [[C3_OLD]]
+; CHECK-NEXT: [[OR_COND1:%.*]] = select i1 [[C1]], i1 true, i1 [[C3_OLD]]
; CHECK-NEXT: br i1 [[OR_COND1]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
; CHECK: pred1:
; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[V2]], 0
; CHECK-NEXT: [[V3_ADJ:%.*]] = add i8 [[V1]], [[V2]]
; CHECK-NEXT: [[V3_ADJ_ADJ:%.*]] = add i8 [[V3_ADJ]], [[V3_ADJ]]
; CHECK-NEXT: [[C3:%.*]] = icmp eq i8 [[V3_ADJ_ADJ]], 0
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C2]], [[C3]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[C2]], i1 [[C3]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT]]
; CHECK: final_left:
; CHECK-NEXT: call void @sideeffect0()
; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
; CHECK-NEXT: [[V1_ADJ:%.*]] = add i8 [[V0]], [[V1:%.*]]
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1_ADJ]], 0
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C0]], [[C1]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[C0]], i1 [[C1]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
; CHECK: final_left:
; CHECK-NEXT: call void @sideeffect0()
; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
; CHECK-NEXT: [[V1_ADJ:%.*]] = add i8 [[V0]], [[V1:%.*]]
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1_ADJ]], 0
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C0]], [[C1]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[C0]], i1 [[C1]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
; CHECK: final_left:
; CHECK-NEXT: call void @sideeffect0()
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0
; CHECK-NEXT: [[V2_ADJ:%.*]] = add i8 [[V0]], [[V1]]
; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[V2_ADJ]], 0
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C1]], [[C2]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[C1]], i1 [[C2]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
; CHECK: final_left:
; CHECK-NEXT: call void @sideeffect0()
; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[V2:%.*]], 0
; CHECK-NEXT: [[V3_ADJ:%.*]] = add i8 [[V1]], [[V2]]
; CHECK-NEXT: [[C3:%.*]] = icmp eq i8 [[V3_ADJ]], 0
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C2]], [[C3]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[C2]], i1 [[C3]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT:%.*]]
; CHECK: dispatch:
; CHECK-NEXT: [[V3_ADJ_OLD:%.*]] = add i8 [[V1]], [[V2]]
; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[V2:%.*]], 0
; CHECK-NEXT: [[V3_ADJ:%.*]] = add i8 [[V1]], [[V2]]
; CHECK-NEXT: [[C3:%.*]] = icmp eq i8 [[V3_ADJ]], 0
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C2]], [[C3]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[C2]], i1 [[C3]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT:%.*]]
; CHECK: dispatch:
; CHECK-NEXT: [[V3_ADJ_OLD:%.*]] = add i8 [[V1]], [[V2]]
; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
; CHECK-NEXT: [[V1_ADJ:%.*]] = add i8 [[V0]], [[V1:%.*]]
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1]], 0
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C0]], [[C1]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[C0]], i1 [[C1]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
; CHECK: final_left:
; CHECK-NEXT: call void @sideeffect0()
; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[V0:%.*]], 0
; CHECK-NEXT: [[V1_ADJ:%.*]] = add i8 [[V0]], [[V1:%.*]]
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1]], 0
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C0]], [[C1]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[C0]], i1 [[C1]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
; CHECK: final_left:
; CHECK-NEXT: call void @sideeffect0()
; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[V2:%.*]], 0
; CHECK-NEXT: [[V3_ADJ:%.*]] = add i8 [[V1]], [[V2]]
; CHECK-NEXT: [[C3:%.*]] = icmp eq i8 [[V3:%.*]], 0
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C2]], [[C3]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[C2]], i1 [[C3]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT:%.*]]
; CHECK: dispatch:
; CHECK-NEXT: [[V3_ADJ_OLD:%.*]] = add i8 [[V1]], [[V2]]
; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[V2:%.*]], 0
; CHECK-NEXT: [[V3_ADJ:%.*]] = add i8 [[V1]], [[V2]]
; CHECK-NEXT: [[C3:%.*]] = icmp eq i8 [[V3:%.*]], 0
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C2]], [[C3]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[C2]], i1 [[C3]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT:%.*]]
; CHECK: dispatch:
; CHECK-NEXT: [[V3_ADJ_OLD:%.*]] = add i8 [[V1]], [[V2]]
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V1:%.*]], 0
; CHECK-NEXT: [[C3:%.*]] = icmp eq i8 [[V3:%.*]], 0
; CHECK-NEXT: [[V2_ADJ:%.*]] = add i8 [[V4:%.*]], [[V5:%.*]]
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C1]], [[C3]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[C1]], i1 [[C3]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT:%.*]], label [[FINAL_RIGHT:%.*]]
; CHECK: final_left:
; CHECK-NEXT: call void @sideeffect0()
; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[V2:%.*]], 0
; CHECK-NEXT: [[C3:%.*]] = icmp eq i8 [[V3:%.*]], 0
; CHECK-NEXT: [[V3_ADJ:%.*]] = add i8 [[V4:%.*]], [[V5:%.*]]
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[C2]], [[C3]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[C2]], i1 [[C3]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[FINAL_LEFT]], label [[FINAL_RIGHT:%.*]]
; CHECK: dispatch:
; CHECK-NEXT: [[C3_OLD:%.*]] = icmp eq i8 [[V3]], 0
; CHECK-NEXT: [[C2_NOT:%.*]] = xor i1 [[C2]], true
; CHECK-NEXT: [[DEC:%.*]] = add i8 [[COUNTDOWN]], -1
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i8 [[COUNTDOWN]], 0
-; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[C2_NOT]], [[CMP_NOT]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[C2_NOT]], i1 true, i1 [[CMP_NOT]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[IF_END_LOOPEXIT]], label [[FOR_BODYTHREAD_PRE_SPLIT]]
; CHECK: for.bodythread-pre-split:
; CHECK-NEXT: [[DEC_MERGE]] = phi i8 [ [[DEC]], [[IF_THEN]] ], [ [[DEC_OLD]], [[FOR_INC]] ]
; CHECK-NEXT: [[C2_NOT:%.*]] = xor i1 [[C2]], true
; CHECK-NEXT: [[DEC:%.*]] = add i8 [[COUNTDOWN]], -1
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i8 [[COUNTDOWN]], 0
-; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[C2_NOT]], [[CMP_NOT]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[C2_NOT]], i1 true, i1 [[CMP_NOT]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[IF_END_LOOPEXIT]], label [[FOR_BODYTHREAD_PRE_SPLIT]]
; CHECK: for.bodythread-pre-split:
; CHECK-NEXT: [[DEC_MERGE]] = phi i8 [ [[DEC_OLD]], [[FOR_INC]] ], [ [[DEC_MERGE]], [[FOR_BODYTHREAD_PRE_SPLIT_LOOPBACK:%.*]] ], [ [[DEC]], [[IF_THEN]] ]
; CHECK-NEXT: [[C1:%[a-z0-9]+]] = icmp eq i32 [[A1]], 0, !dbg [[DBG]]
; CHECK-NEXT: [[A2:%[a-z0-9]+]] = and i32 %c2, %k, !dbg [[DBG]]
; CHECK-NEXT: [[C2:%[a-z0-9]+]] = icmp eq i32 [[A2]], 0, !dbg [[DBG]]
-; CHECK-NEXT: [[OR:%[.a-z0-9]+]] = or i1 [[C1]], [[C2]], !dbg [[DBG]]
+; CHECK-NEXT: [[OR:%[.a-z0-9]+]] = select i1 [[C1]], i1 true, i1 [[C2]], !dbg [[DBG]]
; CHECK-NEXT: br i1 [[OR]], label {{.+}}, label {{.+}}, !dbg [[DBG]]
;
%1 = and i32 %c1, %k, !dbg !18
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A_NOT:%.*]] = xor i1 [[A:%.*]], true
; CHECK-NEXT: [[C:%.*]] = or i1 [[B:%.*]], false
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[A_NOT]], [[C]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[A_NOT]], i1 [[C]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[Z:%.*]], label [[Y:%.*]], !prof !0
; CHECK: Y:
; CHECK-NEXT: call void @helper(i32 0)
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A_NOT:%.*]] = xor i1 [[A:%.*]], true
; CHECK-NEXT: [[C:%.*]] = or i1 [[B:%.*]], false
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[A_NOT]], [[C]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[A_NOT]], i1 [[C]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[Z:%.*]], label [[Y:%.*]], !prof !1
; CHECK: Y:
; CHECK-NEXT: call void @helper(i32 0)
; CHECK-LABEL: @test2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[C:%.*]] = or i1 [[B:%.*]], false
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[A:%.*]], [[C]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[A:%.*]], i1 [[C]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[Z:%.*]], label [[Y:%.*]], !prof !2
; CHECK: Y:
; CHECK-NEXT: call void @helper(i32 0)
; CHECK-LABEL: @test3(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[C:%.*]] = or i1 [[B:%.*]], false
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[A:%.*]], [[C]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[A:%.*]], i1 [[C]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[Z:%.*]], label [[Y:%.*]], !prof !1
; CHECK: Y:
; CHECK-NEXT: call void @helper(i32 0)
; CHECK-LABEL: @test4(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[C:%.*]] = or i1 [[B:%.*]], false
-; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[A:%.*]], [[C]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[A:%.*]], i1 [[C]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[Z:%.*]], label [[Y:%.*]], !prof !1
; CHECK: Y:
; CHECK-NEXT: call void @helper(i32 0)
; CHECK-LABEL: @test1_swap(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[C:%.*]] = or i1 [[B:%.*]], false
-; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[A:%.*]], [[C]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[C]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[Y:%.*]], label [[Z:%.*]], !prof !5
; CHECK: Y:
; CHECK-NEXT: call void @helper(i32 0)
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[BIT_0]], 0
; CHECK-NEXT: [[V3:%.*]] = load i32, i32* @max_regno, align 4
; CHECK-NEXT: [[CMP4:%.*]] = icmp eq i32 [[I_1]], [[V3]]
-; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[TOBOOL]], [[CMP4]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[TOBOOL]], i1 true, i1 [[CMP4]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[FOR_EXIT:%.*]], label [[FOR_INC]], !prof !11
; CHECK: for.inc:
; CHECK-NEXT: [[SHL]] = shl i32 [[BIT_0]], 1
define void @test12() nounwind {
; CHECK-LABEL: @test12(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[DOTOLD:%.*]] = icmp eq i32 undef, undef
-; CHECK-NEXT: br i1 [[DOTOLD]], label [[BB55_US_US:%.*]], label [[MALFORMED:%.*]]
+; CHECK-NEXT: [[A_OLD:%.*]] = icmp eq i32 undef, undef
+; CHECK-NEXT: br i1 [[A_OLD]], label [[BB55_US_US:%.*]], label [[MALFORMED:%.*]]
; CHECK: bb55.us.us:
; CHECK-NEXT: [[B:%.*]] = icmp ugt i32 undef, undef
; CHECK-NEXT: [[A:%.*]] = icmp eq i32 undef, undef