#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/ConstraintSystem.h"
#include "llvm/Analysis/GlobalsModRef.h"
+#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
continue;
WorkList.emplace_back(DT.getNode(&BB));
+ // True as long as long as the current instruction is guaranteed to execute.
+ bool GuaranteedToExecute = true;
+ // Scan BB for assume calls.
+ // TODO: also use this scan to queue conditions to simplify, so we can
+ // interleave facts from assumes and conditions to simplify in a single
+ // basic block. And to skip another traversal of each basic block when
+ // simplifying.
+ for (Instruction &I : BB) {
+ Value *Cond;
+ // For now, just handle assumes with a single compare as condition.
+ if (match(&I, m_Intrinsic<Intrinsic::assume>(m_Value(Cond))) &&
+ isa<CmpInst>(Cond)) {
+ if (GuaranteedToExecute) {
+ // The assume is guaranteed to execute when BB is entered, hence Cond
+ // holds on entry to BB.
+ WorkList.emplace_back(DT.getNode(&BB), cast<CmpInst>(Cond), false);
+ } else {
+ // Otherwise the condition only holds in the successors.
+ for (BasicBlock *Succ : successors(&BB))
+ WorkList.emplace_back(DT.getNode(Succ), cast<CmpInst>(Cond), false);
+ }
+ }
+ GuaranteedToExecute &= isGuaranteedToTransferExecutionToSuccessor(&I);
+ }
+
auto *Br = dyn_cast<BranchInst>(BB.getTerminator());
if (!Br || !Br->isConditional())
continue;
for (auto &E : reverse(DFSInStack))
dbgs() << " C " << *E.Condition << " " << E.IsNot << "\n";
});
- Cmp->replaceAllUsesWith(
- ConstantInt::getTrue(F.getParent()->getContext()));
+ Cmp->replaceUsesWithIf(
+ ConstantInt::getTrue(F.getParent()->getContext()), [](Use &U) {
+ // Conditions in an assume trivially simplify to true. Skip uses
+ // in assume calls to not destroy the available information.
+ auto *II = dyn_cast<IntrinsicInst>(U.getUser());
+ return !II || II->getIntrinsicID() != Intrinsic::assume;
+ });
NumCondsRemoved++;
Changed = true;
}
; CHECK: then:
; CHECK-NEXT: [[T_1:%.*]] = icmp ule i8 [[ADD_1]], [[B]]
; CHECK-NEXT: [[T_2:%.*]] = icmp ule i8 [[A]], [[B]]
-; CHECK-NEXT: [[RES_1:%.*]] = xor i1 [[T_1]], [[T_2]]
+; CHECK-NEXT: [[RES_1:%.*]] = xor i1 true, true
; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2
; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_2]], [[B]]
; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]]
; CHECK: else:
; CHECK-NEXT: [[T_3:%.*]] = icmp ule i8 [[ADD_1]], [[B]]
; CHECK-NEXT: [[T_4:%.*]] = icmp ule i8 [[A]], [[B]]
-; CHECK-NEXT: [[RES_3:%.*]] = xor i1 [[T_3]], [[T_4]]
+; CHECK-NEXT: [[RES_3:%.*]] = xor i1 true, true
; CHECK-NEXT: [[ADD_2_1:%.*]] = add nuw nsw i8 [[A]], 2
; CHECK-NEXT: [[C_2:%.*]] = icmp ule i8 [[ADD_2_1]], [[B]]
; CHECK-NEXT: [[RES_4:%.*]] = xor i1 [[RES_3]], [[C_2]]
; CHECK: then:
; CHECK-NEXT: [[T_1:%.*]] = icmp ule i8 [[ADD_1]], [[B]]
; CHECK-NEXT: [[T_2:%.*]] = icmp ule i8 [[A]], [[B]]
-; CHECK-NEXT: [[RES_1:%.*]] = xor i1 [[T_1]], [[T_2]]
+; CHECK-NEXT: [[RES_1:%.*]] = xor i1 true, true
; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2
; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_2]], [[B]]
; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]]
; CHECK: else:
; CHECK-NEXT: [[T_3:%.*]] = icmp ule i8 [[ADD_1]], [[B]]
; CHECK-NEXT: [[T_4:%.*]] = icmp ule i8 [[A]], [[B]]
-; CHECK-NEXT: [[RES_3:%.*]] = xor i1 [[T_3]], [[T_4]]
+; CHECK-NEXT: [[RES_3:%.*]] = xor i1 true, true
; CHECK-NEXT: [[ADD_2_1:%.*]] = add nuw nsw i8 [[A]], 2
; CHECK-NEXT: [[C_2:%.*]] = icmp ule i8 [[ADD_2_1]], [[B]]
; CHECK-NEXT: [[RES_4:%.*]] = xor i1 [[RES_3]], [[C_2]]
; CHECK: then:
; CHECK-NEXT: [[T_1:%.*]] = icmp ule i8 [[ADD_1]], [[B]]
; CHECK-NEXT: [[T_2:%.*]] = icmp ule i8 [[A]], [[B]]
-; CHECK-NEXT: [[RES_1:%.*]] = xor i1 [[T_1]], [[T_2]]
+; CHECK-NEXT: [[RES_1:%.*]] = xor i1 true, true
; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2
; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_2]], [[B]]
; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]]
; CHECK: else:
; CHECK-NEXT: [[T_3:%.*]] = icmp ule i8 [[ADD_1]], [[B]]
; CHECK-NEXT: [[T_4:%.*]] = icmp ule i8 [[A]], [[B]]
-; CHECK-NEXT: [[RES_3:%.*]] = xor i1 [[T_3]], [[T_4]]
+; CHECK-NEXT: [[RES_3:%.*]] = xor i1 true, true
; CHECK-NEXT: [[ADD_2_1:%.*]] = add nuw nsw i8 [[A]], 2
; CHECK-NEXT: [[C_2:%.*]] = icmp ule i8 [[ADD_2_1]], [[B]]
; CHECK-NEXT: [[RES_4:%.*]] = xor i1 [[RES_3]], [[C_2]]
; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_1]])
; CHECK-NEXT: [[T_1:%.*]] = icmp ule i8 [[ADD_1]], [[B]]
; CHECK-NEXT: [[T_2:%.*]] = icmp ule i8 [[A]], [[B]]
-; CHECK-NEXT: [[RES_1:%.*]] = xor i1 [[T_1]], [[T_2]]
+; CHECK-NEXT: [[RES_1:%.*]] = xor i1 true, true
; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2
; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_2]], [[B]]
; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]]
; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_1]])
; CHECK-NEXT: [[T_1:%.*]] = icmp ule i8 [[ADD_1]], [[B]]
; CHECK-NEXT: [[T_2:%.*]] = icmp ule i8 [[A]], [[B]]
-; CHECK-NEXT: [[RES_1:%.*]] = xor i1 [[T_1]], [[T_2]]
+; CHECK-NEXT: [[RES_1:%.*]] = xor i1 true, true
; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2
; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_2]], [[B]]
; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]]
; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_1]])
; CHECK-NEXT: [[T_1:%.*]] = icmp ule i8 [[ADD_1]], [[B]]
; CHECK-NEXT: [[T_2:%.*]] = icmp ule i8 [[A]], [[B]]
-; CHECK-NEXT: [[RES_1:%.*]] = xor i1 [[T_1]], [[T_2]]
+; CHECK-NEXT: [[RES_1:%.*]] = xor i1 true, true
; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2
; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_2]], [[B]]
; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]]
; CHECK-NEXT: call void @may_unwind()
; CHECK-NEXT: [[T_1:%.*]] = icmp ule i8 [[ADD_1]], [[B]]
; CHECK-NEXT: [[T_2:%.*]] = icmp ule i8 [[A]], [[B]]
-; CHECK-NEXT: [[RES_1:%.*]] = xor i1 [[T_1]], [[T_2]]
+; CHECK-NEXT: [[RES_1:%.*]] = xor i1 true, true
; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2
; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_2]], [[B]]
; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]]
; CHECK-NEXT: [[ADD_1:%.*]] = add nuw nsw i8 [[A:%.*]], 1
; CHECK-NEXT: [[T_1:%.*]] = icmp ule i8 [[ADD_1]], [[B:%.*]]
; CHECK-NEXT: [[T_2:%.*]] = icmp ule i8 [[A]], [[B]]
-; CHECK-NEXT: [[RES_1:%.*]] = xor i1 [[T_1]], [[T_2]]
+; CHECK-NEXT: [[RES_1:%.*]] = xor i1 true, true
; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2
; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_2]], [[B]]
; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]]
}
; The information of from the assume can be used to simplify %t.2.
+; TODO
define i1 @assume_single_bb_conditions_after_assume(i8 %a, i8 %b, i1 %c) {
; CHECK-LABEL: @assume_single_bb_conditions_after_assume(
; CHECK-NEXT: [[ADD_1:%.*]] = add nuw nsw i8 [[A:%.*]], 1
}
; The information of from the assume can be used to simplify %t.2.
+; TODO
define i1 @assume_single_bb_assume_at_end_after_may_unwind(i8 %a, i8 %b, i1 %c) {
; CHECK-LABEL: @assume_single_bb_assume_at_end_after_may_unwind(
; CHECK-NEXT: [[ADD_1:%.*]] = add nuw nsw i8 [[A:%.*]], 1
; The definition of %t.2 is before the @llvm.assume call, but all uses are
; after the call. %t.2 can be simplified.
+; TODO
define i1 @all_uses_after_assume(i8 %a, i8 %b, i1 %c) {
; CHECK-LABEL: @all_uses_after_assume(
; CHECK-NEXT: [[ADD_1:%.*]] = add nuw nsw i8 [[A:%.*]], 1