[llvm] 75de92d - [DSE] Seperate malloc+memset -> calloc transform from noop store dedection [NFC]

Philip Reames via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 11 12:56:09 PST 2022


Author: Philip Reames
Date: 2022-01-11T12:55:59-08:00
New Revision: 75de92d3e25c4de3b208925d23f7304cc630f588

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

LOG: [DSE] Seperate malloc+memset -> calloc transform from noop store dedection [NFC]

This transformation has nothing to do with whether the store is a noop.  The memset becomes a noop, but only after we replace the malloc with a calloc.

Added: 
    

Modified: 
    llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
index f029c00840ea..04b13188e932 100644
--- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
@@ -1691,6 +1691,84 @@ struct DSEState {
     return MadeChange;
   }
 
+  /// If we have a zero initializing memset following a call to malloc,
+  /// try folding it into a call to calloc.
+  bool tryFoldIntoCalloc(MemoryDef *Def, const Value *DefUO) {
+    Instruction *DefI = Def->getMemoryInst();
+    MemSetInst *MemSet = dyn_cast<MemSetInst>(DefI);
+    if (!MemSet)
+      // TODO: Could handle zero store to small allocation as well.
+      return false;
+    Constant *StoredConstant = dyn_cast<Constant>(MemSet->getValue());
+    if (!StoredConstant || !StoredConstant->isNullValue())
+      return false;
+
+    if (!isRemovable(DefI))
+      // The memset might be volatile..
+      return false;
+
+    if (F.hasFnAttribute(Attribute::SanitizeMemory) ||
+        F.hasFnAttribute(Attribute::SanitizeAddress) ||
+        F.hasFnAttribute(Attribute::SanitizeHWAddress) ||
+        F.getName() == "calloc")
+      return false;
+    auto *Malloc = const_cast<CallInst *>(dyn_cast<CallInst>(DefUO));
+    if (!Malloc)
+      return false;
+    auto *InnerCallee = Malloc->getCalledFunction();
+    if (!InnerCallee)
+      return false;
+    LibFunc Func;
+    if (!TLI.getLibFunc(*InnerCallee, Func) || !TLI.has(Func) ||
+        Func != LibFunc_malloc)
+      return false;
+
+    auto shouldCreateCalloc = [](CallInst *Malloc, CallInst *Memset) {
+      // Check for br(icmp ptr, null), truebb, falsebb) pattern at the end
+      // of malloc block
+      auto *MallocBB = Malloc->getParent(),
+        *MemsetBB = Memset->getParent();
+      if (MallocBB == MemsetBB)
+        return true;
+      auto *Ptr = Memset->getArgOperand(0);
+      auto *TI = MallocBB->getTerminator();
+      ICmpInst::Predicate Pred;
+      BasicBlock *TrueBB, *FalseBB;
+      if (!match(TI, m_Br(m_ICmp(Pred, m_Specific(Ptr), m_Zero()), TrueBB,
+                          FalseBB)))
+        return false;
+      if (Pred != ICmpInst::ICMP_EQ || MemsetBB != FalseBB)
+        return false;
+      return true;
+    };
+
+    if (Malloc->getOperand(0) != MemSet->getLength())
+      return false;
+    if (!shouldCreateCalloc(Malloc, MemSet) ||
+        !DT.dominates(Malloc, MemSet) ||
+        !memoryIsNotModifiedBetween(Malloc, MemSet, BatchAA, DL, &DT))
+      return false;
+    IRBuilder<> IRB(Malloc);
+    const auto &DL = Malloc->getModule()->getDataLayout();
+    auto *Calloc =
+      emitCalloc(ConstantInt::get(IRB.getIntPtrTy(DL), 1),
+                 Malloc->getArgOperand(0), IRB, TLI);
+    if (!Calloc)
+      return false;
+    MemorySSAUpdater Updater(&MSSA);
+    auto *LastDef =
+      cast<MemoryDef>(Updater.getMemorySSA()->getMemoryAccess(Malloc));
+    auto *NewAccess =
+      Updater.createMemoryAccessAfter(cast<Instruction>(Calloc), LastDef,
+                                      LastDef);
+    auto *NewAccessMD = cast<MemoryDef>(NewAccess);
+    Updater.insertDef(NewAccessMD, /*RenameUses=*/true);
+    Updater.removeMemoryAccess(Malloc);
+    Malloc->replaceAllUsesWith(Calloc);
+    Malloc->eraseFromParent();
+    return true;
+  }
+
   /// \returns true if \p Def is a no-op store, either because it
   /// directly stores back a loaded value or stores zero to a calloced object.
   bool storeIsNoop(MemoryDef *Def, const Value *DefUO) {
@@ -1722,68 +1800,6 @@ struct DSEState {
       }
     }
 
-    if (StoredConstant && StoredConstant->isNullValue() && MemSet) {
-      if (F.hasFnAttribute(Attribute::SanitizeMemory) ||
-          F.hasFnAttribute(Attribute::SanitizeAddress) ||
-          F.hasFnAttribute(Attribute::SanitizeHWAddress) ||
-          F.getName() == "calloc")
-        return false;
-      auto *Malloc = const_cast<CallInst *>(dyn_cast<CallInst>(DefUO));
-      if (!Malloc)
-        return false;
-      auto *InnerCallee = Malloc->getCalledFunction();
-      if (!InnerCallee)
-        return false;
-      LibFunc Func;
-      if (!TLI.getLibFunc(*InnerCallee, Func) || !TLI.has(Func) ||
-          Func != LibFunc_malloc)
-        return false;
-
-      auto shouldCreateCalloc = [](CallInst *Malloc, CallInst *Memset) {
-        // Check for br(icmp ptr, null), truebb, falsebb) pattern at the end
-        // of malloc block
-        auto *MallocBB = Malloc->getParent(),
-          *MemsetBB = Memset->getParent();
-        if (MallocBB == MemsetBB)
-          return true;
-        auto *Ptr = Memset->getArgOperand(0);
-        auto *TI = MallocBB->getTerminator();
-        ICmpInst::Predicate Pred;
-        BasicBlock *TrueBB, *FalseBB;
-        if (!match(TI, m_Br(m_ICmp(Pred, m_Specific(Ptr), m_Zero()), TrueBB,
-                            FalseBB)))
-          return false;
-        if (Pred != ICmpInst::ICMP_EQ || MemsetBB != FalseBB)
-          return false;
-        return true;
-      };
-
-      if (Malloc->getOperand(0) == MemSet->getLength()) {
-        if (shouldCreateCalloc(Malloc, MemSet) &&
-            DT.dominates(Malloc, MemSet) &&
-            memoryIsNotModifiedBetween(Malloc, MemSet, BatchAA, DL, &DT)) {
-          IRBuilder<> IRB(Malloc);
-          const auto &DL = Malloc->getModule()->getDataLayout();
-          if (auto *Calloc =
-              emitCalloc(ConstantInt::get(IRB.getIntPtrTy(DL), 1),
-                         Malloc->getArgOperand(0), IRB, TLI)) {
-            MemorySSAUpdater Updater(&MSSA);
-            auto *LastDef = cast<MemoryDef>(
-                                            Updater.getMemorySSA()->getMemoryAccess(Malloc));
-            auto *NewAccess = Updater.createMemoryAccessAfter(
-                                                              cast<Instruction>(Calloc), LastDef, LastDef);
-            auto *NewAccessMD = cast<MemoryDef>(NewAccess);
-            Updater.insertDef(NewAccessMD, /*RenameUses=*/true);
-            Updater.removeMemoryAccess(Malloc);
-            Malloc->replaceAllUsesWith(Calloc);
-            Malloc->eraseFromParent();
-            return true;
-          }
-          return false;
-        }
-      }
-    }
-
     if (!Store)
       return false;
 
@@ -2068,6 +2084,15 @@ static bool eliminateDeadStores(Function &F, AliasAnalysis &AA, MemorySSA &MSSA,
       MadeChange = true;
       continue;
     }
+
+    // Can we form a calloc from a memset/malloc pair?
+    if (!Shortend && State.tryFoldIntoCalloc(KillingDef, KillingUndObj)) {
+      LLVM_DEBUG(dbgs() << "DSE: Remove memset after forming calloc:\n"
+                        << "  DEAD: " << *KillingI << '\n');
+      State.deleteDeadInstruction(KillingI);
+      MadeChange = true;
+      continue;
+    }
   }
 
   if (EnablePartialOverwriteTracking)


        


More information about the llvm-commits mailing list