[llvm] 92da5b7 - [InstCombine] Simplify phis with incoming pointer-casts.

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 9 03:40:38 PST 2021


Author: Florian Hahn
Date: 2021-03-09T11:40:18Z
New Revision: 92da5b711970610a2246cfa1baff5c2a63559e1b

URL: https://github.com/llvm/llvm-project/commit/92da5b711970610a2246cfa1baff5c2a63559e1b
DIFF: https://github.com/llvm/llvm-project/commit/92da5b711970610a2246cfa1baff5c2a63559e1b.diff

LOG: [InstCombine] Simplify phis with incoming pointer-casts.

If the incoming values of a phi are pointer casts of the same original
value, replace the phi with a single cast. Such redundant phis are
somewhat common after loop-rotate and removing them can avoid some
unnecessary code bloat, e.g. because an iteration of a loop is peeled
off to make the phi invariant. It should also simplify further analysis
on its own.

InstCombine already uses stripPointerCasts in a couple of places and
also simplifies phis based on the incoming values, so the patch should
fit in the existing scope.

The patch causes binary changes in 47 out of 237 benchmarks in
MultiSource/SPEC2000/SPEC2006 with -O3 -flto on X86.

Reviewed By: lebedev.ri

Differential Revision: https://reviews.llvm.org/D98058

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
    llvm/test/Transforms/InstCombine/phi-pointercasts.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
index b211b0813611..1c99844df08e 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
@@ -1316,6 +1316,24 @@ Instruction *InstCombinerImpl::visitPHINode(PHINode &PN) {
     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<Value *, 4> 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
index 791caac22995..67ca195cf9c0 100644
--- 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 @@ define void @test_bitcast_2(i1 %c, i32* %ptr) {
 ; 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 @@ define void @test_bitcast_3(i1 %c, i32** %ptr) {
 ; 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 @@ define void @test_bitcast_with_extra_use(i1 %c, i32* %ptr) {
 ; 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 @@ define void @test_bitcast_gep_chains(i1 %c, i32* %ptr) {
 ; 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 @@ end.2:
 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
 ;


        


More information about the llvm-commits mailing list