From 99780486c6395e469a4183376c0d1ee925f03de5 Mon Sep 17 00:00:00 2001 From: Noah Goldstein Date: Tue, 17 Sep 2024 09:40:49 -0500 Subject: [PATCH] [SimplifyCFG] Deduce paths unreachable if they cause div/rem UB 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. --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 23 +++++++++-- .../SimplifyCFG/UnreachableEliminate.ll | 38 ++++--------------- 2 files changed, 28 insertions(+), 33 deletions(-) diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index 5a694b5e7f204b..99970b2a9ead45 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -7864,10 +7864,10 @@ static bool passingValueIsAlwaysUndefined(Value *V, Instruction *I, bool PtrValu if (I->use_empty()) return false; - if (C->isNullValue() || isa(C)) { + if (C->isNullValue() || isa(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(U); // Change this list when we want to add new instructions. switch (Use->getOpcode()) { @@ -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(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()) @@ -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; } diff --git a/llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll b/llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll index c299f8fabe003b..f3315c31919978 100644 --- a/llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll +++ b/llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll @@ -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]] ; @@ -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]] ; @@ -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: @@ -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]] ; @@ -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: