Index: lib/Transforms/InstCombine/InstCombineCalls.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCalls.cpp +++ lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -3255,12 +3255,30 @@ } case Intrinsic::experimental_guard: { - Value *IIOperand = II->getArgOperand(0); + // Is this guard followed by another guard? + Value *NextInst = II->getNextNode(); + Value *NextCond = nullptr; + if (match(NextInst, + m_Intrinsic(m_Value(NextCond)))) { + Value *CurrCond = II->getArgOperand(0); + + // Remove a guard if it is immediately followed by an identical guard. + if (CurrCond == NextCond) + return eraseInstFromFunction(*II); + + // Otherwise we try to widen the next guard and remove the current. + Value *A, *B, *NewCond; + if (match(CurrCond, m_Not(m_Value(A))) && + match(NextCond, m_Not(m_Value(B)))) + // Canonicalize guard(!a); guard(!b) -> guard(!(a | b)). + NewCond = Builder->CreateNot(Builder->CreateOr(A, B)); + else + // Otherwise canonicalize guard(a); guard(b) -> guard(a & b). + NewCond = Builder->CreateAnd(CurrCond, NextCond); - // Remove a guard if it is immediately followed by an identical guard. - if (match(II->getNextNode(), - m_Intrinsic(m_Specific(IIOperand)))) + cast(NextInst)->setArgOperand(0, NewCond); return eraseInstFromFunction(*II); + } break; } } Index: test/Transforms/InstCombine/call-guard.ll =================================================================== --- test/Transforms/InstCombine/call-guard.ll +++ test/Transforms/InstCombine/call-guard.ll @@ -2,8 +2,8 @@ declare void @llvm.experimental.guard(i1, ...) -define void @test_guard_adjacent(i1 %A) { -; CHECK-LABEL: @test_guard_adjacent( +define void @test_guard_adjacent_same_cond(i1 %A) { +; CHECK-LABEL: @test_guard_adjacent_same_cond( ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %A) [ "deopt"() ] ; CHECK-NEXT: ret void call void(i1, ...) @llvm.experimental.guard( i1 %A )[ "deopt"() ] @@ -19,12 +19,27 @@ ret void } -define void @test_guard_adjacent_neg(i1 %A, i1 %B) { -; CHECK-LABEL: @test_guard_adjacent_neg( -; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %A) [ "deopt"() ] -; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %B) [ "deopt"() ] +define void @test_guard_adjacent_diff_cond(i1 %A, i1 %B, i1 %C) { +; CHECK-LABEL: @test_guard_adjacent_diff_cond( +; CHECK-NEXT: %1 = and i1 %A, %B +; CHECK-NEXT: %2 = and i1 %1, %C +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %2, i32 789) [ "deopt"() ] ; CHECK-NEXT: ret void - call void(i1, ...) @llvm.experimental.guard( i1 %A )[ "deopt"() ] - call void(i1, ...) @llvm.experimental.guard( i1 %B )[ "deopt"() ] + call void(i1, ...) @llvm.experimental.guard( i1 %A, i32 123 )[ "deopt"() ] + call void(i1, ...) @llvm.experimental.guard( i1 %B, i32 456 )[ "deopt"() ] + call void(i1, ...) @llvm.experimental.guard( i1 %C, i32 789 )[ "deopt"() ] + ret void +} + +define void @test_guard_adjacent_not_cond(i1 %A, i1 %B) { +; CHECK-LABEL: @test_guard_adjacent_not_cond( +; CHECK-NEXT: %1 = or i1 %A, %B +; CHECK-NEXT: %2 = xor i1 %1, true +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %2, i32 456) [ "deopt"() ] +; CHECK-NEXT: ret void + %C = xor i1 %A, true + %D = xor i1 %B, true + call void(i1, ...) @llvm.experimental.guard( i1 %C, i32 123 )[ "deopt"() ] + call void(i1, ...) @llvm.experimental.guard( i1 %D, i32 456 )[ "deopt"() ] ret void }