diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -13,6 +13,7 @@ #include "InstCombineInternal.h" #include "llvm/ADT/SetVector.h" #include "llvm/Analysis/ConstantFolding.h" +#include "llvm/Analysis/Loads.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/IR/DIBuilder.h" #include "llvm/IR/DataLayout.h" @@ -337,6 +338,42 @@ } } + // Replace Int2Ptr/Ptr2Int RoundTrip Cast with bitcast if the pointer + // is dereferenceable. + Value *Ptr = isIntToPtrRoundTripCast(&CI); + if (Ptr) { + if (isDereferenceableAndAlignedPointer(Ptr, Align(1), APInt(64, 1), DL)) { + return new BitCastInst(Ptr, CI.getDestTy()); + } + // Vector to find out all target users of roundtrip (int2ptr/ptr2int) cast + // which are dominated by load/store instruction of same address as of + // roundtripcast. + SmallVector TargetUsers; + Instruction *I; + for (auto *CU : CI.users()) { + if (!(I = dyn_cast(CU))) + continue; + int NumIterations = 0; + for (auto *U : Ptr->users()) { + if (NumIterations == 10) + goto DoneWithUsers; + NumIterations++; + if ((isa(U) || isa(U)) && + DT.dominates(cast(U), I)) { + TargetUsers.push_back(CU); + break; + } + } + } + DoneWithUsers: + if (!TargetUsers.empty()) { + Value *BitCast = Builder.CreateBitCast(Ptr, CI.getDestTy()); + for (auto *U : TargetUsers) { + U->replaceUsesOfWith(&CI, BitCast); + } + return &CI; + } + } return nullptr; } diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h --- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h +++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h @@ -343,6 +343,7 @@ Instruction::CastOps isEliminableCastPair(const CastInst *CI1, const CastInst *CI2); Value *simplifyIntToPtrRoundTripCast(Value *Val); + Value *isIntToPtrRoundTripCast(Value *Val); Value *foldAndOfICmps(ICmpInst *LHS, ICmpInst *RHS, BinaryOperator &And); Value *foldOrOfICmps(ICmpInst *LHS, ICmpInst *RHS, BinaryOperator &Or); 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 @@ -349,6 +349,14 @@ // Simplifies IntToPtr/PtrToInt RoundTrip Cast To BitCast. // inttoptr ( ptrtoint (x) ) --> x Value *InstCombinerImpl::simplifyIntToPtrRoundTripCast(Value *Val) { + if (Value *Ptr = isIntToPtrRoundTripCast(Val)) { + return CastInst::CreateBitOrPointerCast(Ptr, Val->getType(), "", + cast(Val)); + } + return nullptr; +} + +Value *InstCombinerImpl::isIntToPtrRoundTripCast(Value *Val) { auto *IntToPtr = dyn_cast(Val); if (IntToPtr && DL.getPointerTypeSizeInBits(IntToPtr->getDestTy()) == DL.getTypeSizeInBits(IntToPtr->getSrcTy())) { @@ -359,8 +367,7 @@ PtrToInt->getSrcTy()->getPointerAddressSpace() && DL.getPointerTypeSizeInBits(PtrToInt->getSrcTy()) == DL.getTypeSizeInBits(PtrToInt->getDestTy())) { - return CastInst::CreateBitOrPointerCast(PtrToInt->getOperand(0), CastTy, - "", PtrToInt); + return PtrToInt->getOperand(0); } } return nullptr; diff --git a/llvm/test/Transforms/InstCombine/load-int2ptr-fold.ll b/llvm/test/Transforms/InstCombine/load-int2ptr-fold.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/load-int2ptr-fold.ll @@ -0,0 +1,147 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -instcombine -S -disable-i2p-p2i-opt < %s | FileCheck %s + +target datalayout = "e-p:64:64-p1:16:16-p2:32:32:32-p3:64:64:64" +target triple = "x86_64-unknown-linux-gnu" + +define void @test(i8* %X, i8* %Y, i8* %Z) { +; CHECK-LABEL: @test( +; CHECK-NEXT: [[XVAL:%.*]] = load i8, i8* [[X:%.*]], align 1 +; CHECK-NEXT: [[YVAL:%.*]] = load i8, i8* [[Y:%.*]], align 1 +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[XVAL]], [[YVAL]] +; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: br label [[CALL:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[Z_I:%.*]] = ptrtoint i8* [[Z:%.*]] to i64 +; CHECK-NEXT: [[Z_P:%.*]] = inttoptr i64 [[Z_I]] to i8* +; CHECK-NEXT: br label [[CALL]] +; CHECK: call: +; CHECK-NEXT: [[PHI_1:%.*]] = phi i8* [ [[Z_P]], [[IF_ELSE]] ], [ [[Y]], [[IF_THEN]] ] +; CHECK-NEXT: [[PHI_2:%.*]] = phi i8* [ [[Z_P]], [[IF_ELSE]] ], [ [[X]], [[IF_THEN]] ] +; CHECK-NEXT: tail call void @foo(i8* [[PHI_1]], i8* [[PHI_2]]) +; CHECK-NEXT: ret void +; + %Xval = load i8, i8* %X + %Yval = load i8, i8* %Y + %cmp = icmp slt i8 %Xval, %Yval + br i1 %cmp, label %if.then, label %if.else + +if.then: + %Y.i = ptrtoint i8* %Y to i64 + %Y.p = inttoptr i64 %Y.i to i8* + %X.i = ptrtoint i8* %X to i64 + %X.p = inttoptr i64 %X.i to i8* + br label %call + +if.else: + %Z.i = ptrtoint i8* %Z to i64 + %Z.p = inttoptr i64 %Z.i to i8* + br label %call + +call: + %phi.1 = phi i8* [ %Z.p, %if.else ], [ %Y.p, %if.then ] + %phi.2 = phi i8* [ %Z.p, %if.else ], [ %X.p, %if.then ] + tail call void @foo(i8* %phi.1, i8* %phi.2) + ret void +} + +declare void @foo (i8* %a, i8* %b) + +define i8* @test1(i8* %X, i8* %Y, i8* %Z, i1 %cmp) { +; CHECK-LABEL: @test1( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[XVAL:%.*]] = load i8, i8* [[X:%.*]], align 1 +; CHECK-NEXT: br i1 [[CMP:%.*]], label [[FOR_BODY_PREHEADER:%.*]], label [[FOR_END:%.*]] +; CHECK: for.body.preheader: +; CHECK-NEXT: [[YVAL:%.*]] = load i8, i8* [[Y:%.*]], align 1 +; CHECK-NEXT: br label [[FOR_BODY:%.*]] +; CHECK: for.body: +; CHECK-NEXT: [[PHI:%.*]] = phi i8* [ [[X]], [[FOR_BODY]] ], [ [[Y]], [[FOR_BODY_PREHEADER]] ] +; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 [[XVAL]], [[YVAL]] +; CHECK-NEXT: br i1 [[CMP1]], label [[FOR_BODY]], label [[FOR_END]] +; CHECK: for.end: +; CHECK-NEXT: [[PHI1:%.*]] = phi i8* [ [[PHI]], [[FOR_BODY]] ], [ [[Z:%.*]], [[ENTRY:%.*]] ] +; CHECK-NEXT: ret i8* [[PHI1]] +; +entry: + %Xval = load i8, i8* %X + br i1 %cmp, label %for.body.preheader, label %for.end + +for.body.preheader: ; preds = %entry + %Yval = load i8, i8* %Y + br label %for.body + +for.body: ; preds = %for.body, %for.body.preheader + %phi = phi i8* [ %X.p, %for.body ], [ %Y, %for.body.preheader ] + %X.i = ptrtoint i8* %X to i64 + %X.p = inttoptr i64 %X.i to i8* + %cmp1 = icmp slt i8 %Xval, %Yval + br i1 %cmp1, label %for.body, label %for.end + +for.end: ; preds = %for.body, %entry + %phi1 = phi i8* [%phi, %for.body], [%Z, %entry] + ret i8* %phi1 +} + +define void @test_dereferenceable(i8* %X, i8* dereferenceable(1) %Z, i1 %cmp) { +; CHECK-LABEL: @test_dereferenceable( +; CHECK-NEXT: br i1 [[CMP:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[X_I:%.*]] = ptrtoint i8* [[X:%.*]] to i64 +; CHECK-NEXT: [[X_P:%.*]] = inttoptr i64 [[X_I]] to i8* +; CHECK-NEXT: br label [[CALL:%.*]] +; CHECK: if.else: +; CHECK-NEXT: br label [[CALL]] +; CHECK: call: +; CHECK-NEXT: [[PHI_1:%.*]] = phi i8* [ [[Z:%.*]], [[IF_ELSE]] ], [ [[X_P]], [[IF_THEN]] ] +; CHECK-NEXT: tail call void @foo(i8* [[PHI_1]], i8* [[PHI_1]]) +; CHECK-NEXT: ret void +; + br i1 %cmp, label %if.then, label %if.else + +if.then: + %X.i = ptrtoint i8* %X to i64 + %X.p = inttoptr i64 %X.i to i8* + br label %call + +if.else: + %Z.i = ptrtoint i8* %Z to i64 + %Z.p = inttoptr i64 %Z.i to i8* + br label %call + +call: + %phi.1 = phi i8* [ %Z.p, %if.else ], [ %X.p, %if.then ] + tail call void @foo(i8* %phi.1, i8* %phi.1) + ret void +} + +define void @test_dereferenceable_2(i8* dereferenceable(16) %X, i8* dereferenceable(16) %Z, i1 %cmp) { +; CHECK-LABEL: @test_dereferenceable_2( +; CHECK-NEXT: br i1 [[CMP:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: br label [[CALL:%.*]] +; CHECK: if.else: +; CHECK-NEXT: br label [[CALL]] +; CHECK: call: +; CHECK-NEXT: [[PHI_1:%.*]] = phi i8* [ [[Z:%.*]], [[IF_ELSE]] ], [ [[X:%.*]], [[IF_THEN]] ] +; CHECK-NEXT: tail call void @foo(i8* nonnull [[PHI_1]], i8* nonnull [[PHI_1]]) +; CHECK-NEXT: ret void +; + br i1 %cmp, label %if.then, label %if.else + +if.then: + %X.i = ptrtoint i8* %X to i64 + %X.p = inttoptr i64 %X.i to i8* + br label %call + +if.else: + %Z.i = ptrtoint i8* %Z to i64 + %Z.p = inttoptr i64 %Z.i to i8* + br label %call + +call: + %phi.1 = phi i8* [ %Z.p, %if.else ], [ %X.p, %if.then ] + tail call void @foo(i8* %phi.1, i8* %phi.1) + ret void +}