Skip to content

Commit

Permalink
[SimplifyCFG] Deduce paths unreachable if they cause div/rem UB
Browse files Browse the repository at this point in the history
Same we way mark a path unreachable if it may cause a nullptr
dereference, div/rem by zero or signed div/rem of INT_MIN by -1 cause
immediate UB.
  • Loading branch information
goldsteinn committed Sep 17, 2024
1 parent f3e4ff0 commit 9978048
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 33 deletions.
23 changes: 20 additions & 3 deletions llvm/lib/Transforms/Utils/SimplifyCFG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7864,10 +7864,10 @@ static bool passingValueIsAlwaysUndefined(Value *V, Instruction *I, bool PtrValu
if (I->use_empty())
return false;

if (C->isNullValue() || isa<UndefValue>(C)) {
if (C->isNullValue() || isa<UndefValue>(C) || C->isAllOnesValue()) {
// Only look at the first use we can handle, avoid hurting compile time with
// long uselists
auto FindUse = llvm::find_if(I->users(), [](auto *U) {
auto FindUse = llvm::find_if(I->users(), [C](auto *U) {
auto *Use = cast<Instruction>(U);
// Change this list when we want to add new instructions.
switch (Use->getOpcode()) {
Expand All @@ -7881,7 +7881,13 @@ static bool passingValueIsAlwaysUndefined(Value *V, Instruction *I, bool PtrValu
case Instruction::Call:
case Instruction::CallBr:
case Instruction::Invoke:
return true;
return C->isNullValue() || isa<UndefValue>(C);
case Instruction::UDiv:
case Instruction::URem:
return C->isNullValue();
case Instruction::SDiv:
case Instruction::SRem:
return C->isNullValue() || C->isAllOnesValue();
}
});
if (FindUse == I->user_end())
Expand Down Expand Up @@ -7982,6 +7988,17 @@ static bool passingValueIsAlwaysUndefined(Value *V, Instruction *I, bool PtrValu
}
}
}
if (match(Use, m_BinOp(m_Value(), m_Specific(I)))) {
// Immediate UB to divide by zero
if (Use->getOpcode() == Instruction::UDiv ||
Use->getOpcode() == Instruction::URem)
return C->isNullValue();
// Immediate UB to signed-divide INT_MIN by -1
if (Use->getOpcode() == Instruction::SDiv ||
Use->getOpcode() == Instruction::SRem)
return C->isNullValue() ||
(C->isAllOnesValue() && match(Use->getOperand(0), m_SignMask()));
}
}
return false;
}
Expand Down
38 changes: 8 additions & 30 deletions llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll
Original file line number Diff line number Diff line change
Expand Up @@ -925,18 +925,15 @@ define i8 @udiv_by_zero(i8 noundef %x, i8 noundef %i, i8 noundef %v) {
; CHECK-LABEL: @udiv_by_zero(
; CHECK-NEXT: entry:
; CHECK-NEXT: switch i8 [[I:%.*]], label [[SW_DEFAULT:%.*]] [
; CHECK-NEXT: i8 0, label [[RETURN:%.*]]
; CHECK-NEXT: i8 2, label [[SW_BB1:%.*]]
; CHECK-NEXT: i8 9, label [[SW_BB2:%.*]]
; CHECK-NEXT: i8 2, label [[RETURN:%.*]]
; CHECK-NEXT: ]
; CHECK: sw.bb1:
; CHECK-NEXT: br label [[RETURN]]
; CHECK: sw.bb2:
; CHECK-NEXT: br label [[RETURN]]
; CHECK: sw.default:
; CHECK-NEXT: br label [[RETURN]]
; CHECK: return:
; CHECK-NEXT: [[Y:%.*]] = phi i8 [ 2, [[SW_BB1]] ], [ 9, [[SW_BB2]] ], [ [[V:%.*]], [[SW_DEFAULT]] ], [ 0, [[ENTRY:%.*]] ]
; CHECK-NEXT: [[Y:%.*]] = phi i8 [ 9, [[SW_BB2]] ], [ [[V:%.*]], [[SW_DEFAULT]] ], [ 2, [[ENTRY:%.*]] ]
; CHECK-NEXT: [[R:%.*]] = udiv i8 [[X:%.*]], [[Y]]
; CHECK-NEXT: ret i8 [[R]]
;
Expand Down Expand Up @@ -976,9 +973,9 @@ define i8 @urem_by_zero(i8 noundef %x, i8 noundef %i, i8 noundef %v) {
; CHECK: sw.bb2:
; CHECK-NEXT: br label [[RETURN]]
; CHECK: sw.default:
; CHECK-NEXT: br label [[RETURN]]
; CHECK-NEXT: unreachable
; CHECK: return:
; CHECK-NEXT: [[Y:%.*]] = phi i8 [ 2, [[SW_BB1]] ], [ 9, [[SW_BB2]] ], [ 0, [[SW_DEFAULT]] ], [ [[V:%.*]], [[ENTRY:%.*]] ]
; CHECK-NEXT: [[Y:%.*]] = phi i8 [ 2, [[SW_BB1]] ], [ 9, [[SW_BB2]] ], [ [[V:%.*]], [[ENTRY:%.*]] ]
; CHECK-NEXT: [[R:%.*]] = urem i8 [[X:%.*]], [[Y]]
; CHECK-NEXT: ret i8 [[R]]
;
Expand Down Expand Up @@ -1054,13 +1051,10 @@ define i8 @srem_by_zero(i8 noundef %x, i8 noundef %i) {
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
; CHECK-NEXT: call void @side.effect()
; CHECK-NEXT: br label [[IF_END:%.*]]
; CHECK-NEXT: unreachable
; CHECK: if.else:
; CHECK-NEXT: [[V:%.*]] = call i8 @get.i8()
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[Y:%.*]] = phi i8 [ 0, [[IF_THEN]] ], [ [[V]], [[IF_ELSE]] ]
; CHECK-NEXT: [[R:%.*]] = srem i8 [[X:%.*]], [[Y]]
; CHECK-NEXT: [[R:%.*]] = srem i8 [[X:%.*]], [[V]]
; CHECK-NEXT: ret i8 [[R]]
;
entry:
Expand Down Expand Up @@ -1121,17 +1115,14 @@ define i8 @sdiv_overflow_ub(i8 noundef %i) {
; CHECK-NEXT: switch i8 [[I:%.*]], label [[SW_DEFAULT:%.*]] [
; CHECK-NEXT: i8 0, label [[RETURN:%.*]]
; CHECK-NEXT: i8 2, label [[SW_BB1:%.*]]
; CHECK-NEXT: i8 9, label [[SW_BB2:%.*]]
; CHECK-NEXT: ]
; CHECK: sw.bb1:
; CHECK-NEXT: [[V:%.*]] = call i8 @get.i8()
; CHECK-NEXT: br label [[RETURN]]
; CHECK: sw.bb2:
; CHECK-NEXT: br label [[RETURN]]
; CHECK: sw.default:
; CHECK-NEXT: unreachable
; CHECK: return:
; CHECK-NEXT: [[Y:%.*]] = phi i8 [ [[V]], [[SW_BB1]] ], [ -1, [[SW_BB2]] ], [ 4, [[ENTRY:%.*]] ]
; CHECK-NEXT: [[Y:%.*]] = phi i8 [ [[V]], [[SW_BB1]] ], [ 4, [[ENTRY:%.*]] ]
; CHECK-NEXT: [[R:%.*]] = sdiv i8 -128, [[Y]]
; CHECK-NEXT: ret i8 [[R]]
;
Expand Down Expand Up @@ -1161,21 +1152,8 @@ return:
define i8 @sdiv_overflow_ub_2x(i8 noundef %i) {
; CHECK-LABEL: @sdiv_overflow_ub_2x(
; CHECK-NEXT: entry:
; CHECK-NEXT: switch i8 [[I:%.*]], label [[SW_DEFAULT:%.*]] [
; CHECK-NEXT: i8 0, label [[RETURN:%.*]]
; CHECK-NEXT: i8 2, label [[SW_BB1:%.*]]
; CHECK-NEXT: i8 9, label [[SW_BB2:%.*]]
; CHECK-NEXT: ]
; CHECK: sw.bb1:
; CHECK-NEXT: [[V:%.*]] = call i8 @get.i8()
; CHECK-NEXT: br label [[RETURN]]
; CHECK: sw.bb2:
; CHECK-NEXT: br label [[RETURN]]
; CHECK: sw.default:
; CHECK-NEXT: unreachable
; CHECK: return:
; CHECK-NEXT: [[Y:%.*]] = phi i8 [ [[V]], [[SW_BB1]] ], [ -1, [[SW_BB2]] ], [ 0, [[ENTRY:%.*]] ]
; CHECK-NEXT: [[R:%.*]] = sdiv i8 -128, [[Y]]
; CHECK-NEXT: [[R:%.*]] = sdiv i8 -128, [[V]]
; CHECK-NEXT: ret i8 [[R]]
;
entry:
Expand Down

0 comments on commit 9978048

Please sign in to comment.