diff --git a/llvm/lib/Transforms/Scalar/MergeICmps.cpp b/llvm/lib/Transforms/Scalar/MergeICmps.cpp --- a/llvm/lib/Transforms/Scalar/MergeICmps.cpp +++ b/llvm/lib/Transforms/Scalar/MergeICmps.cpp @@ -155,9 +155,13 @@ } Value *const Addr = LoadI->getOperand(0); auto *const GEP = dyn_cast(Addr); - if (!GEP) + if (!GEP) { + LLVM_DEBUG(dbgs() << "does not reference an argument\n"); return {}; + } LLVM_DEBUG(dbgs() << "GEP\n"); + if (!isa(GEP->getPointerOperand())) + return {}; if (GEP->isUsedOutsideOfBlock(LoadI->getParent())) { LLVM_DEBUG(dbgs() << "used outside of block\n"); return {}; diff --git a/llvm/test/Transforms/MergeICmps/X86/gep-references-bb.ll b/llvm/test/Transforms/MergeICmps/X86/gep-references-bb.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/MergeICmps/X86/gep-references-bb.ll @@ -0,0 +1,51 @@ +; RUN: opt < %s -S -mergeicmps -verify-dom-info | FileCheck %s +target triple = "x86_64" + +%Triple = type { %Elem0, %Elem1, %Elem2 } +%Elem0 = type { i32 } +%Elem1 = type { i32 } +%Elem2 = type { i32 } + +;; %gep does not reference an argument. Disable the optimization because +;; otherwise the newly created gep may reference undef (after the basic block +;; defining the pointer operand is deleted). +;; TODO Optimize with a memcmp. +; CHECK-LABEL: bb0: +; CHECK: load i32, i32* %l0_addr, align 4 +; CHECK: load i32, i32* %r0_addr, align 4 +; CHECK-LABEL: bb1: +; CHECK: load i32, i32* %l1_addr, align 4 +; CHECK: load i32, i32* %r1_addr, align 4 +; CHECK-LABEL: bb2: +; CHECK: load i32, i32* %l2_addr, align 4 +; CHECK: load i32, i32* %r2_addr, align 4 +define i1 @bug(%Triple* nonnull dereferenceable(12) %lhs, %Triple* nonnull dereferenceable(12) %rhs) { +bb0: + %gep = getelementptr %Triple, %Triple* %rhs, i64 0, i32 0 + %l0_addr = getelementptr inbounds %Triple, %Triple* %lhs, i64 0, i32 0, i32 0 + %l0 = load i32, i32* %l0_addr, align 4 + %r0_addr = getelementptr inbounds %Triple, %Triple* %rhs, i64 0, i32 0, i32 0 + %r0 = load i32, i32* %r0_addr, align 4 + %cmp0 = icmp eq i32 %l0, %r0 + br i1 %cmp0, label %bb1, label %final + +bb1: ; preds = %bb0 + %l1_addr = getelementptr inbounds %Triple, %Triple* %lhs, i64 0, i32 1, i32 0 + %l1 = load i32, i32* %l1_addr, align 4 + %r1_addr = getelementptr inbounds %Elem0, %Elem0* %gep, i64 1, i32 0 + %r1 = load i32, i32* %r1_addr, align 4 + %cmp1 = icmp eq i32 %l1, %r1 + br i1 %cmp1, label %bb2, label %final + +bb2: ; preds = %bb1 + %l2_addr = getelementptr inbounds %Triple, %Triple* %lhs, i64 0, i32 2, i32 0 + %l2 = load i32, i32* %l2_addr, align 4 + %r2_addr = getelementptr inbounds %Elem0, %Elem0* %gep, i64 2, i32 0 + %r2 = load i32, i32* %r2_addr, align 4 + %cmp2 = icmp eq i32 %l2, %r2 + br label %final + +final: ; preds = %bb2, %bb1, %bb0 + %ret = phi i1 [ false, %bb0 ], [ false, %bb1 ], [ %cmp2, %bb2 ] + ret i1 %ret +}