diff --git a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp @@ -1316,6 +1316,24 @@ if (Instruction *Result = foldPHIArgOpIntoPHI(PN)) return Result; + // If the incoming values are pointer casts of the same original value, + // replace the phi with a single cast. + if (PN.getType()->isPointerTy()) { + Value *IV0 = PN.getIncomingValue(0); + Value *IV0Stripped = IV0->stripPointerCasts(); + // Set to keep track of values known to be equal to IV0Stripped after + // stripping pointer casts. + SmallPtrSet CheckedIVs; + CheckedIVs.insert(IV0); + if (IV0 != IV0Stripped && + all_of(PN.incoming_values(), [&CheckedIVs, IV0Stripped](Value *IV) { + return !CheckedIVs.insert(IV).second || + IV0Stripped == IV->stripPointerCasts(); + })) { + return CastInst::CreatePointerCast(IV0Stripped, PN.getType()); + } + } + // If this is a trivial cycle in the PHI node graph, remove it. Basically, if // this PHI only has a single use (a PHI), and if that PHI only has one use (a // PHI)... break the cycle. diff --git a/llvm/test/Transforms/InstCombine/phi-pointercasts.ll b/llvm/test/Transforms/InstCombine/phi-pointercasts.ll --- a/llvm/test/Transforms/InstCombine/phi-pointercasts.ll +++ b/llvm/test/Transforms/InstCombine/phi-pointercasts.ll @@ -4,16 +4,15 @@ define void @test_bitcast_1(i1 %c, i32* %ptr) { ; CHECK-LABEL: @test_bitcast_1( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[CAST_0:%.*]] = bitcast i32* [[PTR:%.*]] to i8* ; CHECK-NEXT: br i1 [[C:%.*]], label [[B0:%.*]], label [[B1:%.*]] ; CHECK: b0: +; CHECK-NEXT: [[CAST_0:%.*]] = bitcast i32* [[PTR:%.*]] to i8* ; CHECK-NEXT: call void @use(i8* [[CAST_0]]) ; CHECK-NEXT: br label [[END:%.*]] ; CHECK: b1: -; CHECK-NEXT: [[CAST_1:%.*]] = bitcast i32* [[PTR]] to i8* ; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[P:%.*]] = phi i8* [ [[CAST_0]], [[B0]] ], [ [[CAST_1]], [[B1]] ] +; CHECK-NEXT: [[P:%.*]] = bitcast i32* [[PTR]] to i8* ; CHECK-NEXT: store i8 0, i8* [[P]], align 1 ; CHECK-NEXT: ret void ; @@ -40,14 +39,13 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: br i1 [[C:%.*]], label [[B0:%.*]], label [[B1:%.*]] ; CHECK: b0: -; CHECK-NEXT: [[CAST_0:%.*]] = bitcast i32* [[PTR:%.*]] to i8* ; CHECK-NEXT: br label [[END:%.*]] ; CHECK: b1: -; CHECK-NEXT: [[CAST_1:%.*]] = bitcast i32* [[PTR]] to i8* +; CHECK-NEXT: [[CAST_1:%.*]] = bitcast i32* [[PTR:%.*]] to i8* ; CHECK-NEXT: call void @use(i8* [[CAST_1]]) ; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[P:%.*]] = phi i8* [ [[CAST_0]], [[B0]] ], [ [[CAST_1]], [[B1]] ] +; CHECK-NEXT: [[P:%.*]] = bitcast i32* [[PTR]] to i8* ; CHECK-NEXT: store i8 0, i8* [[P]], align 1 ; CHECK-NEXT: ret void ; @@ -76,14 +74,13 @@ ; CHECK-NEXT: [[LOAD_PTR:%.*]] = load i32*, i32** [[PTR:%.*]], align 8 ; CHECK-NEXT: br i1 [[C:%.*]], label [[B0:%.*]], label [[B1:%.*]] ; CHECK: b0: -; CHECK-NEXT: [[CAST_0:%.*]] = bitcast i32* [[LOAD_PTR]] to i8* ; CHECK-NEXT: br label [[END:%.*]] ; CHECK: b1: ; CHECK-NEXT: [[CAST_1:%.*]] = bitcast i32* [[LOAD_PTR]] to i8* ; CHECK-NEXT: call void @use(i8* [[CAST_1]]) ; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[P:%.*]] = phi i8* [ [[CAST_0]], [[B0]] ], [ [[CAST_1]], [[B1]] ] +; CHECK-NEXT: [[P:%.*]] = bitcast i32* [[LOAD_PTR]] to i8* ; CHECK-NEXT: store i8 0, i8* [[P]], align 1 ; CHECK-NEXT: ret void ; @@ -218,10 +215,9 @@ ; CHECK-NEXT: call void @use(i8* [[CAST_0]]) ; CHECK-NEXT: br label [[END:%.*]] ; CHECK: b1: -; CHECK-NEXT: [[CAST_1:%.*]] = bitcast i32* [[PTR]] to i8* ; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[P:%.*]] = phi i8* [ [[CAST_0]], [[B0]] ], [ [[CAST_1]], [[B1]] ] +; CHECK-NEXT: [[P:%.*]] = bitcast i32* [[PTR]] to i8* ; CHECK-NEXT: store i8 0, i8* [[P]], align 1 ; CHECK-NEXT: ret void ; @@ -287,10 +283,9 @@ ; CHECK-NEXT: br label [[END:%.*]] ; CHECK: b1: ; CHECK-NEXT: call void @use.i32(i32* [[PTR]]) -; CHECK-NEXT: [[CAST_3:%.*]] = bitcast i32* [[PTR]] to i8* ; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[P:%.*]] = phi i8* [ [[CAST_0]], [[B0]] ], [ [[CAST_3]], [[B1]] ] +; CHECK-NEXT: [[P:%.*]] = bitcast i32* [[PTR]] to i8* ; CHECK-NEXT: store i8 0, i8* [[P]], align 1 ; CHECK-NEXT: ret void ; @@ -509,18 +504,17 @@ define void @test_addrspacecast_1(i1 %c, i32* %ptr) { ; CHECK-LABEL: @test_addrspacecast_1( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[TMP0:%.*]] = bitcast i32* [[PTR:%.*]] to i8* -; CHECK-NEXT: [[CAST_1:%.*]] = addrspacecast i8* [[TMP0]] to i8 addrspace(1)* ; CHECK-NEXT: br i1 [[C:%.*]], label [[B0:%.*]], label [[B1:%.*]] ; CHECK: b0: -; CHECK-NEXT: [[TMP1:%.*]] = bitcast i32* [[PTR]] to i8* -; CHECK-NEXT: [[CAST_0:%.*]] = addrspacecast i8* [[TMP1]] to i8 addrspace(1)* ; CHECK-NEXT: br label [[END:%.*]] ; CHECK: b1: +; CHECK-NEXT: [[TMP0:%.*]] = bitcast i32* [[PTR:%.*]] to i8* +; CHECK-NEXT: [[CAST_1:%.*]] = addrspacecast i8* [[TMP0]] to i8 addrspace(1)* ; CHECK-NEXT: call void @use.i8.addrspace1(i8 addrspace(1)* [[CAST_1]]) ; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[P:%.*]] = phi i8 addrspace(1)* [ [[CAST_0]], [[B0]] ], [ [[CAST_1]], [[B1]] ] +; CHECK-NEXT: [[TMP1:%.*]] = bitcast i32* [[PTR]] to i8* +; CHECK-NEXT: [[P:%.*]] = addrspacecast i8* [[TMP1]] to i8 addrspace(1)* ; CHECK-NEXT: store i8 0, i8 addrspace(1)* [[P]], align 1 ; CHECK-NEXT: ret void ;