Index: lib/Transforms/InstCombine/InstCombineCalls.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCalls.cpp +++ lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -3624,8 +3624,16 @@ } case Intrinsic::experimental_guard: { - // Is this guard followed by another guard? + // Is this guard followed by another guard? We scan forward over a small + // fixed window of instructions to handle common cases with conditions + // computed between guards. Instruction *NextInst = II->getNextNode(); + for (int i = 0; i < 3; i++) { + // Note: Using context-free form to avoid compile time blow up + if (!isSafeToSpeculativelyExecute(NextInst)) + break; + NextInst = NextInst->getNextNode(); + } Value *NextCond = nullptr; if (match(NextInst, m_Intrinsic(m_Value(NextCond)))) { @@ -3636,6 +3644,12 @@ return eraseInstFromFunction(*NextInst); // Otherwise canonicalize guard(a); guard(b) -> guard(a & b). + Instruction* MoveI = II->getNextNode(); + while (MoveI != NextInst) { + auto *Temp = MoveI; + MoveI = MoveI->getNextNode(); + Temp->moveBefore(II); + } II->setArgOperand(0, Builder.CreateAnd(CurrCond, NextCond)); return eraseInstFromFunction(*NextInst); } Index: test/Transforms/InstCombine/call-guard.ll =================================================================== --- test/Transforms/InstCombine/call-guard.ll +++ test/Transforms/InstCombine/call-guard.ll @@ -30,3 +30,25 @@ call void(i1, ...) @llvm.experimental.guard( i1 %C, i32 789 )[ "deopt"() ] ret void } + +; This version tests for the common form where the conditions are +; between the guards +define void @test_guard_adjacent_diff_cond2(i32 %V1, i32 %V2) { +; CHECK-LABEL: @test_guard_adjacent_diff_cond2( +; CHECK-NEXT: %1 = and i32 %V1, %V2 +; CHECK-NEXT: %2 = icmp slt i32 %1, 0 +; CHECK-NEXT: %and = and i32 %V1, 255 +; CHECK-NEXT: %C = icmp ult i32 %and, 129 +; CHECK-NEXT: %3 = and i1 %2, %C +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %3, i32 123) [ "deopt"() ] +; CHECK-NEXT: ret void + %A = icmp slt i32 %V1, 0 + call void(i1, ...) @llvm.experimental.guard( i1 %A, i32 123 )[ "deopt"() ] + %B = icmp slt i32 %V2, 0 + call void(i1, ...) @llvm.experimental.guard( i1 %B, i32 456 )[ "deopt"() ] + %and = and i32 %V1, 255 + %C = icmp sle i32 %and, 128 + call void(i1, ...) @llvm.experimental.guard( i1 %C, i32 789 )[ "deopt"() ] + ret void +} +