Index: lib/Transforms/Utils/Local.cpp =================================================================== --- lib/Transforms/Utils/Local.cpp +++ lib/Transforms/Utils/Local.cpp @@ -1310,7 +1310,7 @@ // Assumptions that are known to be false are equivalent to unreachable. // Also, if the condition is undefined, then we make the choice most // beneficial to the optimizer, and choose that to also be unreachable. - if (IntrinsicInst *II = dyn_cast(BBI)) + if (IntrinsicInst *II = dyn_cast(BBI)) { if (II->getIntrinsicID() == Intrinsic::assume) { bool MakeUnreachable = false; if (isa(II->getArgOperand(0))) @@ -1327,6 +1327,18 @@ } } + if (II->getIntrinsicID() == Intrinsic::experimental_guard) + // Unlike in llvm.assume, it is not "obviously profitable" for guards + // to treat `undef` as `false` since a guard on `undef` can still be + // useful for widening. + if (auto *CI = dyn_cast(II->getArgOperand(0))) + if (CI->isZero()) { + changeToUnreachable(II, /* UseLLVMTrap = */ false); + Changed = true; + break; + } + } + if (CallInst *CI = dyn_cast(BBI)) { if (CI->doesNotReturn()) { // If we found a call to a no-return function, insert an unreachable Index: test/Transforms/SimplifyCFG/guards.ll =================================================================== --- /dev/null +++ test/Transforms/SimplifyCFG/guards.ll @@ -0,0 +1,36 @@ +; RUN: opt -S -simplifycfg < %s | FileCheck %s + +declare void @llvm.experimental.guard(i1, ...) + +define i32 @f_0(i1 %c) { +; CHECK-LABEL: @f_0( +; CHECK-NEXT: entry: +; CHECK-NEXT: ret i32 20 +entry: + br i1 %c, label %true, label %false + +true: + call void(i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"() ] + ret i32 10 + +false: + ret i32 20 +} + +define i32 @f_1(i1 %c) { +; Demonstrate that we do not yet simplify a guard on undef + +; CHECK-LABEL: @f_1( +; CHECK: ret i32 10 +; CHECK: ret i32 20 + +entry: + br i1 %c, label %true, label %false + +true: + call void(i1, ...) @llvm.experimental.guard(i1 undef) [ "deopt"() ] + ret i32 10 + +false: + ret i32 20 +}