Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -16066,6 +16066,43 @@ On the other hand, if constant folding is not run, it will never evaluate to true, even in simple cases. +'``llvm.psub``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +:: + + declare iN @llvm.psub.iN.pty.pty(pty, pty) nounwind readnone speculatable + +Overview: +""""""""" + +The '``llvm.psub(p1, p2)``' intrinsic returns the result of subtraction +of two pointers `p1 - p2` in bytes. + +Arguments: +"""""""""" +The two arguments are pointers of the same type to subtract. +The return value is the result of subtraction. + +Semantics: +"""""""""" +If p1 and p2 point to different objects(global variable, alloca, etc) +and neither of them is based on a pointer casted from an integer, +``llvm.psub(p1, p2)`` returns poison. Otherwise, the result is equivalent to +``sub (ptrtoint p1 to iN) (ptrtoint p2 to iN)``. +``null`` is regarded as a pointer casted from an integer because +it is equivalent to ``inttoptr 0``. +Therefore, ``llvm.psub(p1, null)`` is equivalent to +``ptrtoint p1``. + +The goal of this intrinsics is to allow more aggressive escape analysis on +pointers. Given ``i = llvm.psub(p1, p2)``, if neither of p1 and p2 +is based on a pointer casted from an integer, this ``llvm.psub`` +does not make p1 or p2 escape. + Stack Map Intrinsics -------------------- Index: include/llvm/CodeGen/BasicTTIImpl.h =================================================================== --- include/llvm/CodeGen/BasicTTIImpl.h +++ include/llvm/CodeGen/BasicTTIImpl.h @@ -1265,6 +1265,14 @@ return static_cast(this)->getMinMaxReductionCost( Tys[0], CmpInst::makeCmpResultType(Tys[0]), /*IsPairwiseForm=*/false, /*IsSigned=*/false); + case Intrinsic::psub: { + // Two ptrtoints followed by sub. + unsigned p2i_cost = static_cast(this) + ->getOperationCost(Instruction::PtrToInt, Tys[0], RetTy); + unsigned sub_cost = static_cast(this) + ->getOperationCost(Instruction::Sub, RetTy, RetTy); + return p2i_cost * 2 + sub_cost; + } case Intrinsic::ctpop: ISDs.push_back(ISD::CTPOP); // In case of legalization use TCC_Expensive. This is cheaper than a Index: include/llvm/IR/IRBuilder.h =================================================================== --- include/llvm/IR/IRBuilder.h +++ include/llvm/IR/IRBuilder.h @@ -2019,10 +2019,13 @@ Value *CreatePtrDiff(Value *LHS, Value *RHS, const Twine &Name = "") { assert(LHS->getType() == RHS->getType() && "Pointer subtraction operand types must match!"); - auto *ArgType = cast(LHS->getType()); - Value *LHS_int = CreatePtrToInt(LHS, Type::getInt64Ty(Context)); - Value *RHS_int = CreatePtrToInt(RHS, Type::getInt64Ty(Context)); - Value *Difference = CreateSub(LHS_int, RHS_int); + PointerType *ArgType = cast(LHS->getType()); + Type *psubTys[] = { Type::getInt64Ty(Context), ArgType, ArgType }; + Value *psubArgs[] = { LHS, RHS }; + Module *M = BB->getParent()->getParent(); + Value *Difference = CreateCall(Intrinsic::getDeclaration(M, + llvm::Intrinsic::psub, ArrayRef(psubTys, 3)), + psubArgs); return CreateExactSDiv(Difference, ConstantExpr::getSizeOf(ArgType->getElementType()), Name); Index: include/llvm/IR/Intrinsics.td =================================================================== --- include/llvm/IR/Intrinsics.td +++ include/llvm/IR/Intrinsics.td @@ -989,6 +989,9 @@ // Intrinsic to detect whether its argument is a constant. def int_is_constant : Intrinsic<[llvm_i1_ty], [llvm_any_ty], [IntrNoMem], "llvm.is.constant">; +let IntrProperties = [IntrNoMem, IntrSpeculatable] in { +def int_psub : Intrinsic<[llvm_anyint_ty], [llvm_anyptr_ty, llvm_anyptr_ty]>; +} //===-------------------------- Masked Intrinsics -------------------------===// // Index: lib/Analysis/InstructionSimplify.cpp =================================================================== --- lib/Analysis/InstructionSimplify.cpp +++ lib/Analysis/InstructionSimplify.cpp @@ -5078,6 +5078,10 @@ // TODO: maxnum(nnan ninf x, -flt_max) -> x break; } + case Intrinsic::psub: + if (Constant *Result = computePointerDifference(Q.DL, Op0, Op1)) + return ConstantExpr::getIntegerCast(Result, F->getReturnType(), true); + break; default: break; } Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -6373,6 +6373,16 @@ // MachineFunction in SelectionDAGISel::PrepareEHLandingPad. We can safely // delete it now. return nullptr; + case Intrinsic::psub: + // pointer to integer casting + EVT DestVT = DAG.getTargetLoweringInfo().getValueType(DAG.getDataLayout(), + I.getType()); + SDValue Op1 = DAG.getZExtOrTrunc(getValue(I.getArgOperand(0)), getCurSDLoc(), DestVT); + SDValue Op2 = DAG.getZExtOrTrunc(getValue(I.getArgOperand(1)), getCurSDLoc(), DestVT); + SDValue BinNodeValue = DAG.getNode(ISD::SUB, getCurSDLoc(), Op1.getValueType(), + Op1, Op2); + setValue(&I, BinNodeValue); + return nullptr; } } Index: lib/Transforms/InstCombine/InstCombineCalls.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCalls.cpp +++ lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -4013,6 +4013,31 @@ } break; } + + case Intrinsic::psub: { + Value *Op1 = II->getArgOperand(0); + Value *Op2 = II->getArgOperand(1); + if (Value *Res = OptimizePointerDifference(Op1, Op2, II->getType())) { + return replaceInstUsesWith(*II, Res); + } + // psub(inttoptr(i1), p2) + // => + // sub (ptrtoint(inttoptr i1), ptrtoint(p2)) + // Note that ptrtoint(inttoptr i1) can be optimized to i1. + if (Operator::getOpcode(Op1) == Instruction::IntToPtr || + Operator::getOpcode(Op2) == Instruction::IntToPtr || + isa(Op1) || isa(Op2)) { + Type *Op1Ty = Op1->getType(); + IntegerType *ITy = IntegerType::get(Op1->getContext(), + DL.getPointerTypeSizeInBits(Op1Ty)); + Value *I1 = Builder.CreatePtrToInt(Op1, ITy); + Value *I2 = Builder.CreatePtrToInt(Op2, ITy); + Value *Sub = Builder.CreateSub(I1, I2); + Value *Cast = Builder.CreateIntCast(Sub, II->getType(), true, II->getName()); + return replaceInstUsesWith(*II, Cast); + } + break; + } } return visitCallSite(II); } Index: lib/Transforms/InstCombine/InstCombineCompares.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCompares.cpp +++ lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -2816,6 +2816,25 @@ } break; } + case Intrinsic::psub: { + // psub(a, b) == 0 -> a == b + if (C.isNullValue()) { + Value *Op0 = II->getArgOperand(0); + Value *Op1 = II->getArgOperand(1); + Value *NewCmp = nullptr; + if (Cmp.getPredicate() == CmpInst::ICMP_EQ) { + NewCmp = Builder.CreateICmpEQ(Op0, Op1); + } else if (Cmp.getPredicate() == CmpInst::ICMP_NE) { + NewCmp = Builder.CreateICmpNE(Op0, Op1); + } // There's no other case because this function starts with + // Cmp.isEquality(). + NewCmp->takeName(&Cmp); + replaceInstUsesWith(Cmp, NewCmp); + Worklist.Add(II); + return &Cmp; + } + break; + } default: break; }