diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -2224,6 +2224,37 @@ if (Instruction *R = foldSelectGEP(GEP, Builder)) return R; + // The definition of llvm.ptrmask(Ptr, Mask) is: + // (getelementptr i8, Ptr, (sub (and (ptrtoint Ptr), Mask), (ptrtoint Ptr))) + // or + // (getelementptr i8, null, (and (ptrtoint Ptr), Mask)) + // + // llvm.ptrmask is preferable as it doesn't require transitioning from ptr -> + // int (and is generally easier to analyze). + // Don't do this for for vector of pointers, as llvm.ptrmask has weird + // definition for vectors. + if (GEPEltType->isIntegerTy(8) && GEP.getNumIndices() == 1) { + Value *Ptr, *Index; + // (getelementptr i8, Ptr, (sub Index, (ptrtoint Ptr))) + // -> (getelementptr i8, null, Index) + if (match(GEP.idx_begin()->get(), + m_Sub(m_Value(Index), + m_PtrToInt(m_Specific(GEP.getPointerOperand()))))) + return replaceInstUsesWith( + GEP, Builder.CreateGEP( + GEP.getSourceElementType(), + Constant::getNullValue(GEP.getPointerOperand()->getType()), + Index)); + Value *Mask; + // (getelementptr i8, null, (and (ptrtoint Ptr), Mask)) + // -> llvm.ptrmask(Ptr, Mask) + if (!GEPType->isVectorTy() && match(GEP.getPointerOperand(), m_Zero()) && + match(GEP.idx_begin()->get(), + m_OneUse(m_c_And(m_PtrToInt(m_Value(Ptr)), m_Value(Mask))))) + return replaceInstUsesWith( + GEP, Builder.CreateIntrinsic(Ptr->getType(), Intrinsic::ptrmask, + {Ptr, Mask})); + } return nullptr; } diff --git a/llvm/test/Transforms/InstCombine/to-ptrmask.ll b/llvm/test/Transforms/InstCombine/to-ptrmask.ll --- a/llvm/test/Transforms/InstCombine/to-ptrmask.ll +++ b/llvm/test/Transforms/InstCombine/to-ptrmask.ll @@ -94,8 +94,7 @@ ; CHECK-SAME: (ptr [[P:%.*]], i64 [[M:%.*]]) { ; CHECK-NEXT: [[PI:%.*]] = ptrtoint ptr [[P]] to i64 ; CHECK-NEXT: [[PI_M:%.*]] = xor i64 [[PI]], [[M]] -; CHECK-NEXT: [[PI_OFF:%.*]] = sub i64 [[PI_M]], [[PI]] -; CHECK-NEXT: [[PM:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 [[PI_OFF]] +; CHECK-NEXT: [[PM:%.*]] = getelementptr i8, ptr null, i64 [[PI_M]] ; CHECK-NEXT: ret ptr [[PM]] ; %pi = ptrtoint ptr %p to i64 @@ -108,10 +107,7 @@ define ptr @GEP_inttoptr_complex_pattern(ptr %p, i64 %m) { ; CHECK-LABEL: define ptr @GEP_inttoptr_complex_pattern ; CHECK-SAME: (ptr [[P:%.*]], i64 [[M:%.*]]) { -; CHECK-NEXT: [[PI:%.*]] = ptrtoint ptr [[P]] to i64 -; CHECK-NEXT: [[PI_M:%.*]] = and i64 [[PI]], [[M]] -; CHECK-NEXT: [[PI_OFF:%.*]] = sub i64 [[PI_M]], [[PI]] -; CHECK-NEXT: [[PM:%.*]] = getelementptr i8, ptr [[P]], i64 [[PI_OFF]] +; CHECK-NEXT: [[PM:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 [[M]]) ; CHECK-NEXT: ret ptr [[PM]] ; %pi = ptrtoint ptr %p to i64 @@ -144,7 +140,7 @@ ; CHECK-NEXT: [[PI_M:%.*]] = and i64 [[PI]], [[M]] ; CHECK-NEXT: [[PI_OFF:%.*]] = sub i64 [[PI_M]], [[PI]] ; CHECK-NEXT: call void @use.i64(i64 [[PI_OFF]]) -; CHECK-NEXT: [[PM:%.*]] = getelementptr i8, ptr [[P]], i64 [[PI_OFF]] +; CHECK-NEXT: [[PM:%.*]] = getelementptr i8, ptr null, i64 [[PI_M]] ; CHECK-NEXT: ret ptr [[PM]] ; %pi = ptrtoint ptr %p to i64 @@ -176,9 +172,7 @@ define ptr @GEP_inttoptr_simple_pattern(ptr %p, i64 %m) { ; CHECK-LABEL: define ptr @GEP_inttoptr_simple_pattern ; CHECK-SAME: (ptr [[P:%.*]], i64 [[M:%.*]]) { -; CHECK-NEXT: [[PI:%.*]] = ptrtoint ptr [[P]] to i64 -; CHECK-NEXT: [[PI_M:%.*]] = and i64 [[PI]], [[M]] -; CHECK-NEXT: [[PM:%.*]] = getelementptr i8, ptr null, i64 [[PI_M]] +; CHECK-NEXT: [[PM:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 [[M]]) ; CHECK-NEXT: ret ptr [[PM]] ; %pi = ptrtoint ptr %p to i64