diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp --- a/llvm/lib/CodeGen/CodeGenPrepare.cpp +++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp @@ -7191,6 +7191,25 @@ return false; } + if (FreezeInst *FI = dyn_cast(I)) { + // br(freeze(icmp a, const)) -> br(icmp (freeze a), const) + // This helps generate efficient conditional jumps. + if (ICmpInst *II = dyn_cast(FI->getOperand(0))) { + auto Op0 = II->getOperand(0), Op1 = II->getOperand(1); + bool Const0 = isa(Op0), Const1 = isa(Op1); + if (II->hasOneUse() && (Const0 || Const1)) { + if (!Const0 || !Const1) { + auto F = new FreezeInst(Const0 ? Op1 : Op0, FI->getName(), II); + II->setOperand(Const0 ? 1 : 0, F); + } + FI->replaceAllUsesWith(II); + FI->eraseFromParent(); + return true; + } + } + return false; + } + if (tryToSinkFreeOperands(I)) return true; diff --git a/llvm/test/Transforms/CodeGenPrepare/X86/freeze-icmp.ll b/llvm/test/Transforms/CodeGenPrepare/X86/freeze-icmp.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/CodeGenPrepare/X86/freeze-icmp.ll @@ -0,0 +1,75 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -codegenprepare < %s | FileCheck %s + +target triple = "x86_64-unknown-linux-gnu" + +define void @f1(i32 %a) { +; CHECK-LABEL: @f1( +; CHECK-NEXT: [[FR1:%.*]] = freeze i32 [[A:%.*]] +; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[FR1]], 0 +; CHECK-NEXT: br i1 [[C]], label [[A:%.*]], label [[B:%.*]] +; CHECK: A: +; CHECK-NEXT: call void @g1() +; CHECK-NEXT: ret void +; CHECK: B: +; CHECK-NEXT: call void @g2() +; CHECK-NEXT: ret void +; + %c = icmp eq i32 %a, 0 + %fr = freeze i1 %c + br i1 %fr, label %A, label %B +A: + call void @g1() + ret void +B: + call void @g2() + ret void +} + +define void @f2(i32 %a) { +; CHECK-LABEL: @f2( +; CHECK-NEXT: [[FR1:%.*]] = freeze i32 [[A:%.*]] +; CHECK-NEXT: [[C:%.*]] = icmp eq i32 0, [[FR1]] +; CHECK-NEXT: br i1 [[C]], label [[A:%.*]], label [[B:%.*]] +; CHECK: A: +; CHECK-NEXT: call void @g1() +; CHECK-NEXT: ret void +; CHECK: B: +; CHECK-NEXT: call void @g2() +; CHECK-NEXT: ret void +; + %c = icmp eq i32 0, %a + %fr = freeze i1 %c + br i1 %fr, label %A, label %B +A: + call void @g1() + ret void +B: + call void @g2() + ret void +} + +define void @f3(i32 %a) { +; CHECK-LABEL: @f3( +; CHECK-NEXT: [[C:%.*]] = icmp eq i32 0, 1 +; CHECK-NEXT: br i1 [[C]], label [[A:%.*]], label [[B:%.*]] +; CHECK: A: +; CHECK-NEXT: call void @g1() +; CHECK-NEXT: ret void +; CHECK: B: +; CHECK-NEXT: call void @g2() +; CHECK-NEXT: ret void +; + %c = icmp eq i32 0, 1 + %fr = freeze i1 %c + br i1 %fr, label %A, label %B +A: + call void @g1() + ret void +B: + call void @g2() + ret void +} + +declare void @g1() +declare void @g2()