Index: lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp +++ lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp @@ -876,6 +876,38 @@ Constant::getNullValue(Op->getType()), &LI); return replaceInstUsesWith(LI, UndefValue::get(LI.getType())); } + + // load(gep(A, select(Cond, I1, I2))) --> + // select(Cond, load(gep(A, I1)), load(gep(A, I2)). + // It helps alias analysis and load elimination. But we need to make sure + // load(gep(A, I1)) and load(gep(A, I2)) will never trap. + unsigned LastIdx = GEPI->getNumIndices(); + Value *LastOp = GEPI->getOperand(LastIdx); + if (SelectInst *SI = dyn_cast(LastOp)) { + GetElementPtrInst *NewGEP1 = cast(GEPI->clone()); + GetElementPtrInst *NewGEP2 = cast(GEPI->clone()); + NewGEP1->setOperand(LastIdx, SI->getOperand(1)); + NewGEP2->setOperand(LastIdx, SI->getOperand(2)); + unsigned Align = LI.getAlignment(); + if (isSafeToLoadUnconditionally(NewGEP1, Align, DL, GEPI) && + isSafeToLoadUnconditionally(NewGEP2, Align, DL, GEPI)) { + Builder->Insert(NewGEP1, "newgep1"); + Builder->Insert(NewGEP2, "newgep2"); + LoadInst *V1 = + Builder->CreateLoad(NewGEP1, NewGEP1->getName() + ".val"); + LoadInst *V2 = + Builder->CreateLoad(NewGEP2, NewGEP2->getName() + ".val"); + assert(LI.isUnordered() && "implied by above"); + V1->setAlignment(Align); + V1->setAtomic(LI.getOrdering(), LI.getSynchScope()); + V2->setAlignment(Align); + V2->setAtomic(LI.getOrdering(), LI.getSynchScope()); + return SelectInst::Create(SI->getCondition(), V1, V2); + } else { + delete NewGEP1; + delete NewGEP2; + } + } } // load null/undef -> unreachable Index: test/Transforms/InstCombine/load-gep-select.ll =================================================================== --- test/Transforms/InstCombine/load-gep-select.ll +++ test/Transforms/InstCombine/load-gep-select.ll @@ -0,0 +1,26 @@ +; RUN: opt -instcombine -gvn -S < %s | FileCheck %s +; PR30950. Check instcombine supports the transformation of load(gep(A, select(I1, I2))) ==> select(load(gep(A, I1)), load(gep(A, I2))), so that global value numbering can remove the redundent loads. + +; CHECK-LABEL: @foo +; CHECK: [[AIDX0:%[^ ]+]] = getelementptr inbounds i64, i64* %maxarray, i64 %k +; CHECK: [[TMP0:%[^ ]+]] = load i64, i64* [[AIDX0]], align 8 +; CHECK: [[AIDX1:%[^ ]+]] = getelementptr inbounds i64, i64* %maxarray, i64 {{.*}} +; CHECK: [[TMP1:%[^ ]+]] = load i64, i64* [[AIDX1]], align 8 +; CHECK: [[CMP:%[^ ]+]] = icmp sgt i64 [[TMP0]], [[TMP1]] +; CHECK: [[SEL:%[^ ]+]] = select i1 [[CMP]], i64 [[TMP0]], i64 [[TMP1]] +; CHECK: ret i64 [[SEL]] + +define i64 @foo(i64* nocapture readonly %maxarray, i64 %k, i64 %size) { +entry: + %arrayidx = getelementptr inbounds i64, i64* %maxarray, i64 %k + %t0 = load i64, i64* %arrayidx, align 8 + %add = add nsw i64 %k, %size + %add1 = add nsw i64 %add, 1 + %arrayidx2 = getelementptr inbounds i64, i64* %maxarray, i64 %add1 + %t1 = load i64, i64* %arrayidx2, align 8 + %cmp = icmp sgt i64 %t0, %t1 + %k.add1 = select i1 %cmp, i64 %k, i64 %add1 + %arrayidx6 = getelementptr inbounds i64, i64* %maxarray, i64 %k.add1 + %t2 = load i64, i64* %arrayidx6, align 8 + ret i64 %t2 +}