[llvm] 87ff340 - Stabilize alloca slices sort in SROA

Stanislav Mekhanoshin via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 8 14:25:37 PDT 2020


Author: Stanislav Mekhanoshin
Date: 2020-06-08T14:25:27-07:00
New Revision: 87ff3401eb103d8dbb632466fd9a9762d698f223

URL: https://github.com/llvm/llvm-project/commit/87ff3401eb103d8dbb632466fd9a9762d698f223
DIFF: https://github.com/llvm/llvm-project/commit/87ff3401eb103d8dbb632466fd9a9762d698f223.diff

LOG: Stabilize alloca slices sort in SROA

Slice::operator<() has a non-deterministic behavior. If we have
identical slices comparison will depend on the order or operands.
Normally that does not result in unstable compilation results
because the order in which slices are inserted into the vector
is deterministic and llvm::sort() normally behaves as a stable
sort, although that is not guaranteed.

However, there is test option -sroa-random-shuffle-slices which
is used to check exactly this aspect. The vector is first randomly
shuffled and then sorted. The same shuffling happens without this
option under expensive llvm checks.

I have managed to write a test which has hit this problem.

There are no fields in the Slice class to resolve the instability.
We only have offsets, IsSplittable and Use, but neither Use nor
User have anything suitable for predictable comparison.

I have switched to stable_sort which has to be sufficient and
removed that randon shuffle option.

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

Added: 
    

Modified: 
    llvm/lib/Transforms/Scalar/SROA.cpp
    llvm/test/Transforms/SROA/phi-gep.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Scalar/SROA.cpp b/llvm/lib/Transforms/Scalar/SROA.cpp
index 9b3c77eae120..ee3bb6705c25 100644
--- a/llvm/lib/Transforms/Scalar/SROA.cpp
+++ b/llvm/lib/Transforms/Scalar/SROA.cpp
@@ -94,11 +94,6 @@
 #include <utility>
 #include <vector>
 
-#ifndef NDEBUG
-// We only use this for a debug check.
-#include <random>
-#endif
-
 using namespace llvm;
 using namespace llvm::sroa;
 
@@ -115,11 +110,6 @@ STATISTIC(NumLoadsSpeculated, "Number of loads speculated to allow promotion");
 STATISTIC(NumDeleted, "Number of instructions deleted");
 STATISTIC(NumVectorized, "Number of vectorized aggregates");
 
-/// Hidden option to enable randomly shuffling the slices to help uncover
-/// instability in their order.
-static cl::opt<bool> SROARandomShuffleSlices("sroa-random-shuffle-slices",
-                                             cl::init(false), cl::Hidden);
-
 /// Hidden option to experiment with completely strict handling of inbounds
 /// GEPs.
 static cl::opt<bool> SROAStrictInbounds("sroa-strict-inbounds", cl::init(false),
@@ -1071,17 +1061,9 @@ AllocaSlices::AllocaSlices(const DataLayout &DL, AllocaInst &AI)
       llvm::remove_if(Slices, [](const Slice &S) { return S.isDead(); }),
       Slices.end());
 
-#ifndef NDEBUG
-  if (SROARandomShuffleSlices) {
-    std::mt19937 MT(static_cast<unsigned>(
-        std::chrono::system_clock::now().time_since_epoch().count()));
-    std::shuffle(Slices.begin(), Slices.end(), MT);
-  }
-#endif
-
   // Sort the uses. This arranges for the offsets to be in ascending order,
   // and the sizes to be in descending order.
-  llvm::sort(Slices);
+  std::stable_sort(Slices.begin(), Slices.end());
 }
 
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)

diff  --git a/llvm/test/Transforms/SROA/phi-gep.ll b/llvm/test/Transforms/SROA/phi-gep.ll
index 2763c71d401b..a7bc6319fc91 100644
--- a/llvm/test/Transforms/SROA/phi-gep.ll
+++ b/llvm/test/Transforms/SROA/phi-gep.ll
@@ -367,6 +367,55 @@ exit:
   unreachable
 }
 
+define i32 @test_sroa_gep_cast_phi_gep(i1 %cond) {
+; CHECK-LABEL: @test_sroa_gep_cast_phi_gep(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[A_SROA_0:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    [[A_SROA_0_0_GEP_A_CAST_TO_I32_SROA_CAST:%.*]] = bitcast i32* [[A_SROA_0]] to float*
+; CHECK-NEXT:    [[A_SROA_0_0_GEP_A_CAST_TO_I32_SROA_CAST2:%.*]] = bitcast i32* [[A_SROA_0]] to float*
+; CHECK-NEXT:    [[A_SROA_0_0_GEP_SROA_CAST:%.*]] = bitcast i32* [[A_SROA_0]] to float*
+; CHECK-NEXT:    store i32 1065353216, i32* [[A_SROA_0]], align 4
+; CHECK-NEXT:    br i1 [[COND:%.*]], label [[FOR:%.*]], label [[END:%.*]]
+; CHECK:       for:
+; CHECK-NEXT:    [[PHI_I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I:%.*]], [[FOR]] ]
+; CHECK-NEXT:    [[PHI:%.*]] = phi float* [ [[A_SROA_0_0_GEP_A_CAST_TO_I32_SROA_CAST]], [[ENTRY]] ], [ [[GEP_FOR_CAST_TO_I32:%.*]], [[FOR]] ]
+; CHECK-NEXT:    [[PHI_SROA_PHI:%.*]] = phi float* [ [[A_SROA_0_0_GEP_SROA_CAST]], [[ENTRY]] ], [ [[GEP_FOR_CAST_TO_I32_SROA_GEP:%.*]], [[FOR]] ]
+; CHECK-NEXT:    [[I]] = add i32 [[PHI_I]], 1
+; CHECK-NEXT:    [[GEP_FOR_CAST:%.*]] = bitcast float* [[PHI_SROA_PHI]] to i32*
+; CHECK-NEXT:    [[GEP_FOR_CAST_TO_I32]] = bitcast i32* [[GEP_FOR_CAST]] to float*
+; CHECK-NEXT:    [[GEP_FOR_CAST_TO_I32_SROA_GEP]] = getelementptr inbounds float, float* [[GEP_FOR_CAST_TO_I32]], i32 0
+; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp ult i32 [[I]], 10
+; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[FOR]], label [[END]]
+; CHECK:       end:
+; CHECK-NEXT:    [[PHI_END:%.*]] = phi float* [ [[A_SROA_0_0_GEP_A_CAST_TO_I32_SROA_CAST2]], [[ENTRY]] ], [ [[PHI]], [[FOR]] ]
+; CHECK-NEXT:    [[PHI_END_1:%.*]] = bitcast float* [[PHI_END]] to i32*
+; CHECK-NEXT:    [[LOAD:%.*]] = load i32, i32* [[PHI_END_1]], align 4
+; CHECK-NEXT:    ret i32 [[LOAD]]
+;
+entry:
+  %a = alloca %pair, align 4
+  %gep_a = getelementptr inbounds %pair, %pair* %a, i32 0, i32 1
+  %gep_a_cast_to_float = bitcast i32* %gep_a to float*
+  store float 1.0, float* %gep_a_cast_to_float, align 4
+  br i1 %cond, label %for, label %end
+
+for:
+  %phi_i = phi i32 [ 0, %entry ], [ %i, %for ]
+  %phi = phi float* [ %gep_a_cast_to_float, %entry], [ %gep_for_cast_to_float, %for ]
+  %i = add i32 %phi_i, 1
+  %gep_for = getelementptr inbounds float, float* %phi, i32 0
+  %gep_for_cast = bitcast float* %gep_for to i32*
+  %gep_for_cast_to_float = bitcast i32* %gep_for_cast to float*
+  %loop.cond = icmp ult i32 %i, 10
+  br i1 %loop.cond, label %for, label %end
+
+end:
+  %phi_end = phi float* [ %gep_a_cast_to_float, %entry], [ %phi, %for ]
+  %phi_end.1 = bitcast float* %phi_end to i32*
+  %load = load i32, i32* %phi_end.1, align 4
+  ret i32 %load
+}
+
 declare %pair* @foo()
 
 declare i32 @__gxx_personality_v0(...)


        


More information about the llvm-commits mailing list