[llvm] a722e23 - [GlobalOpt] Don't evaluate large memset (PR62191)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 18 09:24:27 PDT 2023


Author: Nikita Popov
Date: 2023-04-18T18:24:17+02:00
New Revision: a722e2366bede3d476c5bf3ff11428102aa4891f

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

LOG: [GlobalOpt] Don't evaluate large memset (PR62191)

If the memset is large, checking every single byte of the global
may be very slow. Add an upper bound on the size of memset we
handle.

For the common special case of memset zeroinitializer to zero,
add a fastpath that checks just that and is not length limited.

Fixes https://github.com/llvm/llvm-project/issues/62191.

Added: 
    

Modified: 
    llvm/lib/Transforms/Utils/Evaluator.cpp
    llvm/test/Transforms/GlobalOpt/ctor-memset.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Utils/Evaluator.cpp b/llvm/lib/Transforms/Utils/Evaluator.cpp
index 52e4c9e5edde5..23c1ca366a445 100644
--- a/llvm/lib/Transforms/Utils/Evaluator.cpp
+++ b/llvm/lib/Transforms/Utils/Evaluator.cpp
@@ -413,16 +413,28 @@ bool Evaluator::EvaluateBlock(BasicBlock::iterator CurInst, BasicBlock *&NextBB,
           }
 
           Constant *Val = getVal(MSI->getValue());
-          APInt Len = LenC->getValue();
-          while (Len != 0) {
-            Constant *DestVal = ComputeLoadResult(GV, Val->getType(), Offset);
-            if (DestVal != Val) {
-              LLVM_DEBUG(dbgs() << "Memset is not a no-op at offset "
-                                << Offset << " of " << *GV << ".\n");
+          // Avoid the byte-per-byte scan if we're memseting a zeroinitializer
+          // to zero.
+          if (!Val->isNullValue() || MutatedMemory.contains(GV) ||
+              !GV->hasDefinitiveInitializer() ||
+              !GV->getInitializer()->isNullValue()) {
+            APInt Len = LenC->getValue();
+            if (Len.ugt(64 * 1024)) {
+              LLVM_DEBUG(dbgs() << "Not evaluating large memset of size "
+                                << Len << "\n");
               return false;
             }
-            ++Offset;
-            --Len;
+
+            while (Len != 0) {
+              Constant *DestVal = ComputeLoadResult(GV, Val->getType(), Offset);
+              if (DestVal != Val) {
+                LLVM_DEBUG(dbgs() << "Memset is not a no-op at offset "
+                                  << Offset << " of " << *GV << ".\n");
+                return false;
+              }
+              ++Offset;
+              --Len;
+            }
           }
 
           LLVM_DEBUG(dbgs() << "Ignoring no-op memset.\n");

diff  --git a/llvm/test/Transforms/GlobalOpt/ctor-memset.ll b/llvm/test/Transforms/GlobalOpt/ctor-memset.ll
index 92b4a7d21d4f7..b1163580971fe 100644
--- a/llvm/test/Transforms/GlobalOpt/ctor-memset.ll
+++ b/llvm/test/Transforms/GlobalOpt/ctor-memset.ll
@@ -3,7 +3,7 @@
 
 target datalayout = "p1:32:32"
 
- at llvm.global_ctors = appending global [9 x { i32, ptr, ptr }] [
+ at llvm.global_ctors = appending global [11 x { i32, ptr, ptr }] [
   { i32, ptr, ptr } { i32 65535, ptr @ctor0, ptr null },
   { i32, ptr, ptr } { i32 65535, ptr @ctor1, ptr null },
   { i32, ptr, ptr } { i32 65535, ptr @ctor2, ptr null },
@@ -12,11 +12,16 @@ target datalayout = "p1:32:32"
   { i32, ptr, ptr } { i32 65535, ptr @ctor5, ptr null },
   { i32, ptr, ptr } { i32 65535, ptr @ctor6, ptr null },
   { i32, ptr, ptr } { i32 65535, ptr @ctor7, ptr null },
-  { i32, ptr, ptr } { i32 65535, ptr @ctor8, ptr null }
+  { i32, ptr, ptr } { i32 65535, ptr @ctor8, ptr null },
+  { i32, ptr, ptr } { i32 65535, ptr @ctor9, ptr null },
+  { i32, ptr, ptr } { i32 65535, ptr @ctor10, ptr null }
 ]
 
+
+; memset of all-zero global
+ at g0 = global { i32, i32 } zeroinitializer
 ;.
-; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [3 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @ctor3, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @ctor4, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @ctor7, ptr null }]
+; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [4 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @ctor3, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @ctor4, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @ctor7, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @ctor10, ptr null }]
 ; CHECK: @[[G0:[a-zA-Z0-9_$"\\.-]+]] = local_unnamed_addr global { i32, i32 } zeroinitializer
 ; CHECK: @[[G1:[a-zA-Z0-9_$"\\.-]+]] = local_unnamed_addr global { i32, i32, i32 } { i32 0, i32 0, i32 1 }
 ; CHECK: @[[G2:[a-zA-Z0-9_$"\\.-]+]] = local_unnamed_addr global { i32, i32, i32 } { i32 1, i32 0, i32 0 }
@@ -26,10 +31,9 @@ target datalayout = "p1:32:32"
 ; CHECK: @[[G6:[a-zA-Z0-9_$"\\.-]+]] = local_unnamed_addr global { i32, i32 } { i32 -1, i32 -1 }
 ; CHECK: @[[G7:[a-zA-Z0-9_$"\\.-]+]] = local_unnamed_addr global { i32, i32 } { i32 -1, i32 1 }
 ; CHECK: @[[G8:[a-zA-Z0-9_$"\\.-]+]] = local_unnamed_addr addrspace(1) global { i32, i32 } zeroinitializer
+; CHECK: @[[G9:[a-zA-Z0-9_$"\\.-]+]] = local_unnamed_addr global [100000000 x i32] zeroinitializer
+; CHECK: @[[G10:[a-zA-Z0-9_$"\\.-]+]] = local_unnamed_addr global { [99999999 x i32], i32 } { [99999999 x i32] zeroinitializer, i32 1 }
 ;.
-
-; memset of all-zero global
- at g0 = global { i32, i32 } zeroinitializer
 define internal void @ctor0() {
   call void @llvm.memset.p0.i64(ptr @g0, i8 0, i64 8, i1 false)
   ret void
@@ -113,6 +117,24 @@ define internal void @ctor8() {
   ret void
 }
 
+ at g9 = global [100000000 x i32] zeroinitializer
+
+define internal void @ctor9() {
+  call void @llvm.memset.p0.i64(ptr @g9, i8 0, i64 100000000, i1 false)
+  ret void
+}
+
+ at g10 = global { [99999999 x i32], i32 } { [99999999 x i32 ] zeroinitializer, i32 1 }
+
+define internal void @ctor10() {
+; CHECK-LABEL: @ctor10(
+; CHECK-NEXT:    call void @llvm.memset.p0.i64(ptr @g10, i8 0, i64 100000000, i1 false)
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.memset.p0.i64(ptr @g10, i8 0, i64 100000000, i1 false)
+  ret void
+}
+
 declare void @llvm.memset.p0.i64(ptr, i8, i64, i1)
 ;.
 ; CHECK: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: write) }


        


More information about the llvm-commits mailing list