[llvm] 095e91c - [Remarks] Add analysis remarks for memset/memcpy/memmove lengths

Jon Roelofs via llvm-commits llvm-commits at lists.llvm.org
Mon May 24 10:10:54 PDT 2021


Author: Jon Roelofs
Date: 2021-05-24T10:10:44-07:00
New Revision: 095e91c9737b4f67c1cb192be3fb45bee925ad8e

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

LOG: [Remarks] Add analysis remarks for memset/memcpy/memmove lengths

Re-landing now that the crasher this patch previously uncovered has been fixed
in: https://reviews.llvm.org/D102935

Differential revision: https://reviews.llvm.org/D102452

Added: 
    llvm/include/llvm/Transforms/Utils/MemoryOpRemark.h
    llvm/lib/Transforms/Utils/MemoryOpRemark.cpp
    llvm/test/CodeGen/AArch64/memsize-remarks.ll

Modified: 
    llvm/include/llvm/Analysis/OptimizationRemarkEmitter.h
    llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
    llvm/lib/Transforms/Scalar/AnnotationRemarks.cpp
    llvm/lib/Transforms/Utils/CMakeLists.txt
    llvm/test/Transforms/Util/trivial-auto-var-init-call.ll
    llvm/test/Transforms/Util/trivial-auto-var-init-store.ll

Removed: 
    llvm/include/llvm/Transforms/Utils/AutoInitRemark.h
    llvm/lib/Transforms/Utils/AutoInitRemark.cpp


################################################################################
diff  --git a/llvm/include/llvm/Analysis/OptimizationRemarkEmitter.h b/llvm/include/llvm/Analysis/OptimizationRemarkEmitter.h
index 7b34b97950403..ff706e91f3c45 100644
--- a/llvm/include/llvm/Analysis/OptimizationRemarkEmitter.h
+++ b/llvm/include/llvm/Analysis/OptimizationRemarkEmitter.h
@@ -61,6 +61,12 @@ class OptimizationRemarkEmitter {
   bool invalidate(Function &F, const PreservedAnalyses &PA,
                   FunctionAnalysisManager::Invalidator &Inv);
 
+  /// Return true iff at least *some* remarks are enabled.
+  bool enabled() const {
+    return F->getContext().getLLVMRemarkStreamer() ||
+           F->getContext().getDiagHandlerPtr()->isAnyRemarkEnabled();
+  }
+
   /// Output the remark via the diagnostic handler and to the
   /// optimization record file.
   void emit(DiagnosticInfoOptimizationBase &OptDiag);
@@ -73,9 +79,11 @@ class OptimizationRemarkEmitter {
     // remarks enabled. We can't currently check whether remarks are requested
     // for the calling pass since that requires actually building the remark.
 
-    if (F->getContext().getLLVMRemarkStreamer() ||
-        F->getContext().getDiagHandlerPtr()->isAnyRemarkEnabled()) {
+    if (enabled()) {
       auto R = RemarkBuilder();
+      static_assert(
+          std::is_base_of<DiagnosticInfoOptimizationBase, decltype(R)>::value,
+          "the lambda passed to emit() must return a remark");
       emit((DiagnosticInfoOptimizationBase &)R);
     }
   }

diff  --git a/llvm/include/llvm/Transforms/Utils/AutoInitRemark.h b/llvm/include/llvm/Transforms/Utils/MemoryOpRemark.h
similarity index 51%
rename from llvm/include/llvm/Transforms/Utils/AutoInitRemark.h
rename to llvm/include/llvm/Transforms/Utils/MemoryOpRemark.h
index 61be76f289d4b..54ec87c820736 100644
--- a/llvm/include/llvm/Transforms/Utils/AutoInitRemark.h
+++ b/llvm/include/llvm/Transforms/Utils/MemoryOpRemark.h
@@ -1,4 +1,4 @@
-//===- AutoInitRemark.h - Auto-init remark analysis -*- C++ -------------*-===//
+//===- MemoryOpRemark.h - Memory operation remark analysis -*- C++ ------*-===//
 //
 //                      The LLVM Compiler Infrastructure
 //
@@ -7,13 +7,13 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// Provide more information about instructions with a "auto-init"
-// !annotation metadata.
+// Provide more information about instructions that copy, move, or initialize
+// memory, including those with a "auto-init" !annotation metadata.
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLVM_TRANSFORMS_UTILS_AUTOINITREMARK_H
-#define LLVM_TRANSFORMS_UTILS_AUTOINITREMARK_H
+#ifndef LLVM_TRANSFORMS_UTILS_MEMORYOPREMARK_H
+#define LLVM_TRANSFORMS_UTILS_MEMORYOPREMARK_H
 
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Analysis/TargetLibraryInfo.h"
@@ -22,6 +22,7 @@ namespace llvm {
 
 class CallInst;
 class DataLayout;
+class DiagnosticInfoIROptimization;
 class Instruction;
 class IntrinsicInst;
 class Value;
@@ -31,36 +32,49 @@ class StoreInst;
 
 // FIXME: Once we get to more remarks like this one, we need to re-evaluate how
 // much of this logic should actually go into the remark emitter.
-struct AutoInitRemark {
+struct MemoryOpRemark {
   OptimizationRemarkEmitter &ORE;
   StringRef RemarkPass;
   const DataLayout &DL;
   const TargetLibraryInfo &TLI;
 
-  AutoInitRemark(OptimizationRemarkEmitter &ORE, StringRef RemarkPass,
+  MemoryOpRemark(OptimizationRemarkEmitter &ORE, StringRef RemarkPass,
                  const DataLayout &DL, const TargetLibraryInfo &TLI)
       : ORE(ORE), RemarkPass(RemarkPass), DL(DL), TLI(TLI) {}
 
+  virtual ~MemoryOpRemark();
+
+  /// \return true iff the instruction is understood by MemoryOpRemark.
+  static bool canHandle(const Instruction *I, const TargetLibraryInfo &TLI);
+
+  void visit(const Instruction *I);
+
+protected:
+  virtual std::string explainSource(StringRef Type);
+
+  enum RemarkKind { RK_Store, RK_Unknown, RK_IntrinsicCall, RK_Call };
+  virtual StringRef remarkName(RemarkKind RK);
+
+private:
   /// Emit a remark using information from the store's destination, size, etc.
-  void inspectStore(StoreInst &SI);
+  void visitStore(const StoreInst &SI);
   /// Emit a generic auto-init remark.
-  void inspectUnknown(Instruction &I);
+  void visitUnknown(const Instruction &I);
   /// Emit a remark using information from known intrinsic calls.
-  void inspectIntrinsicCall(IntrinsicInst &II);
+  void visitIntrinsicCall(const IntrinsicInst &II);
   /// Emit a remark using information from known function calls.
-  void inspectCall(CallInst &CI);
+  void visitCall(const CallInst &CI);
 
-private:
   /// Add callee information to a remark: whether it's known, the function name,
   /// etc.
   template <typename FTy>
-  void inspectCallee(FTy F, bool KnownLibCall, OptimizationRemarkMissed &R);
+  void visitCallee(FTy F, bool KnownLibCall, OptimizationRemarkMissed &R);
   /// Add operand information to a remark based on knowledge we have for known
   /// libcalls.
-  void inspectKnownLibCall(CallInst &CI, LibFunc LF,
-                           OptimizationRemarkMissed &R);
+  void visitKnownLibCall(const CallInst &CI, LibFunc LF,
+                         OptimizationRemarkMissed &R);
   /// Add the memory operation size to a remark.
-  void inspectSizeOperand(Value *V, OptimizationRemarkMissed &R);
+  void visitSizeOperand(Value *V, OptimizationRemarkMissed &R);
 
   struct VariableInfo {
     Optional<StringRef> Name;
@@ -70,8 +84,22 @@ struct AutoInitRemark {
   /// Gather more information about \p V as a variable. This can be debug info,
   /// information from the alloca, etc. Since \p V can represent more than a
   /// single variable, they will all be added to the remark.
-  void inspectDst(Value *Dst, OptimizationRemarkMissed &R);
-  void inspectVariable(const Value *V, SmallVectorImpl<VariableInfo> &Result);
+  void visitPtr(Value *V, bool IsSrc, OptimizationRemarkMissed &R);
+  void visitVariable(const Value *V, SmallVectorImpl<VariableInfo> &Result);
+};
+
+/// Special case for -ftrivial-auto-var-init remarks.
+struct AutoInitRemark : public MemoryOpRemark {
+  AutoInitRemark(OptimizationRemarkEmitter &ORE, StringRef RemarkPass,
+                 const DataLayout &DL, const TargetLibraryInfo &TLI)
+      : MemoryOpRemark(ORE, RemarkPass, DL, TLI) {}
+
+  /// \return true iff the instruction is understood by AutoInitRemark.
+  static bool canHandle(const Instruction *I);
+
+protected:
+  virtual std::string explainSource(StringRef Type) override;
+  virtual StringRef remarkName(RemarkKind RK) override;
 };
 
 } // namespace llvm

diff  --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
index cfddc06a7cdfa..7cb015b26f073 100644
--- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
@@ -72,6 +72,7 @@
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Target/TargetIntrinsicInfo.h"
 #include "llvm/Target/TargetMachine.h"
+#include "llvm/Transforms/Utils/MemoryOpRemark.h"
 #include <algorithm>
 #include <cassert>
 #include <cstddef>
@@ -97,6 +98,7 @@ INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
 INITIALIZE_PASS_DEPENDENCY(GISelCSEAnalysisWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(BlockFrequencyInfoWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(StackProtector)
+INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
 INITIALIZE_PASS_END(IRTranslator, DEBUG_TYPE, "IRTranslator LLVM IR -> MI",
                 false, false)
 
@@ -164,6 +166,8 @@ void IRTranslator::getAnalysisUsage(AnalysisUsage &AU) const {
   AU.addRequired<GISelCSEAnalysisWrapperPass>();
   if (OptLevel != CodeGenOpt::None)
     AU.addRequired<BranchProbabilityInfoWrapperPass>();
+  AU.addRequired<TargetLibraryInfoWrapperPass>();
+  AU.addPreserved<TargetLibraryInfoWrapperPass>();
   getSelectionDAGFallbackAnalysisUsage(AU);
   MachineFunctionPass::getAnalysisUsage(AU);
 }
@@ -1815,6 +1819,16 @@ bool IRTranslator::translateConstrainedFPIntrinsic(
 
 bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID,
                                            MachineIRBuilder &MIRBuilder) {
+  if (auto *MI = dyn_cast<AnyMemIntrinsic>(&CI)) {
+    if (ORE->enabled()) {
+      const Function &F = *MI->getParent()->getParent();
+      auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
+      if (MemoryOpRemark::canHandle(MI, TLI)) {
+        MemoryOpRemark R(*ORE, "memsize", *DL, TLI);
+        R.visit(MI);
+      }
+    }
+  }
 
   // If this is a simple intrinsic (that is, we just need to add a def of
   // a vreg, and uses for each arg operand, then translate it.
@@ -2244,6 +2258,17 @@ bool IRTranslator::translateCallBase(const CallBase &CB,
     Args.push_back(getOrCreateVRegs(*Arg));
   }
 
+  if (auto *CI = dyn_cast<CallInst>(&CB)) {
+    if (ORE->enabled()) {
+      const Function &F = *CI->getParent()->getParent();
+      auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
+      if (MemoryOpRemark::canHandle(CI, TLI)) {
+        MemoryOpRemark R(*ORE, "memsize", *DL, TLI);
+        R.visit(CI);
+      }
+    }
+  }
+
   // We don't set HasCalls on MFI here yet because call lowering may decide to
   // optimize into tail calls. Instead, we defer that to selection where a final
   // scan is done to check if any instructions are calls.

diff  --git a/llvm/lib/Transforms/Scalar/AnnotationRemarks.cpp b/llvm/lib/Transforms/Scalar/AnnotationRemarks.cpp
index c5bdfb4d8f6ad..a5e65ffc45fec 100644
--- a/llvm/lib/Transforms/Scalar/AnnotationRemarks.cpp
+++ b/llvm/lib/Transforms/Scalar/AnnotationRemarks.cpp
@@ -22,7 +22,7 @@
 #include "llvm/Pass.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Transforms/Scalar.h"
-#include "llvm/Transforms/Utils/AutoInitRemark.h"
+#include "llvm/Transforms/Utils/MemoryOpRemark.h"
 
 using namespace llvm;
 using namespace llvm::ore;
@@ -35,45 +35,13 @@ static void tryEmitAutoInitRemark(ArrayRef<Instruction *> Instructions,
                                   const TargetLibraryInfo &TLI) {
   // For every auto-init annotation generate a separate remark.
   for (Instruction *I : Instructions) {
-    if (!I->hasMetadata(LLVMContext::MD_annotation))
+    if (!AutoInitRemark::canHandle(I))
       continue;
-    for (const MDOperand &Op :
-         I->getMetadata(LLVMContext::MD_annotation)->operands()) {
-      if (cast<MDString>(Op.get())->getString() != "auto-init")
-        continue;
-
-      Function &F = *I->getParent()->getParent();
-      const DataLayout &DL = F.getParent()->getDataLayout();
-      AutoInitRemark Remark(ORE, REMARK_PASS, DL, TLI);
-      // For some of them, we can provide more information:
-
-      // For stores:
-      // * size
-      // * volatile / atomic
-      if (auto *SI = dyn_cast<StoreInst>(I)) {
-        Remark.inspectStore(*SI);
-        continue;
-      }
-
-      // For intrinsics:
-      // * user-friendly name
-      // * size
-      if (auto *II = dyn_cast<IntrinsicInst>(I)) {
-        Remark.inspectIntrinsicCall(*II);
-        continue;
-      }
-
-      // For calls:
-      // * known/unknown function (e.g. the compiler knows bzero, but it doesn't
-      //                                know my_bzero)
-      // * memory operation size
-      if (auto *CI = dyn_cast<CallInst>(I)) {
-        Remark.inspectCall(*CI);
-        continue;
-      }
-
-      Remark.inspectUnknown(*I);
-    }
+
+    Function &F = *I->getParent()->getParent();
+    const DataLayout &DL = F.getParent()->getDataLayout();
+    AutoInitRemark Remark(ORE, REMARK_PASS, DL, TLI);
+    Remark.visit(I);
   }
 }
 

diff  --git a/llvm/lib/Transforms/Utils/AutoInitRemark.cpp b/llvm/lib/Transforms/Utils/AutoInitRemark.cpp
deleted file mode 100644
index 209f1310c162c..0000000000000
--- a/llvm/lib/Transforms/Utils/AutoInitRemark.cpp
+++ /dev/null
@@ -1,210 +0,0 @@
-//===-- AutoInitRemark.cpp - Auto-init remark analysis---------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// Implementation of the analysis for the "auto-init" remark.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Transforms/Utils/AutoInitRemark.h"
-#include "llvm/Analysis/OptimizationRemarkEmitter.h"
-#include "llvm/Analysis/ValueTracking.h"
-#include "llvm/IR/DebugInfo.h"
-#include "llvm/IR/Instructions.h"
-#include "llvm/IR/IntrinsicInst.h"
-
-using namespace llvm;
-using namespace llvm::ore;
-
-static void volatileOrAtomicWithExtraArgs(bool Volatile, bool Atomic,
-                                          OptimizationRemarkMissed &R) {
-  if (Volatile)
-    R << " Volatile: " << NV("StoreVolatile", true) << ".";
-  if (Atomic)
-    R << " Atomic: " << NV("StoreAtomic", true) << ".";
-  // Emit StoreVolatile: false and StoreAtomic: false under ExtraArgs. This
-  // won't show them in the remark message but will end up in the serialized
-  // remarks.
-  if (!Volatile || !Atomic)
-    R << setExtraArgs();
-  if (!Volatile)
-    R << " Volatile: " << NV("StoreVolatile", false) << ".";
-  if (!Atomic)
-    R << " Atomic: " << NV("StoreAtomic", false) << ".";
-}
-
-static Optional<uint64_t> getSizeInBytes(Optional<uint64_t> SizeInBits) {
-  if (!SizeInBits || *SizeInBits % 8 != 0)
-    return None;
-  return *SizeInBits / 8;
-}
-
-void AutoInitRemark::inspectStore(StoreInst &SI) {
-  bool Volatile = SI.isVolatile();
-  bool Atomic = SI.isAtomic();
-  int64_t Size = DL.getTypeStoreSize(SI.getOperand(0)->getType());
-
-  OptimizationRemarkMissed R(RemarkPass.data(), "AutoInitStore", &SI);
-  R << "Store inserted by -ftrivial-auto-var-init.\nStore size: "
-    << NV("StoreSize", Size) << " bytes.";
-  inspectDst(SI.getOperand(1), R);
-  volatileOrAtomicWithExtraArgs(Volatile, Atomic, R);
-  ORE.emit(R);
-}
-
-void AutoInitRemark::inspectUnknown(Instruction &I) {
-  ORE.emit(OptimizationRemarkMissed(RemarkPass.data(),
-                                    "AutoInitUnknownInstruction", &I)
-           << "Initialization inserted by -ftrivial-auto-var-init.");
-}
-
-void AutoInitRemark::inspectIntrinsicCall(IntrinsicInst &II) {
-  SmallString<32> CallTo;
-  bool Atomic = false;
-  switch (II.getIntrinsicID()) {
-  case Intrinsic::memcpy:
-    CallTo = "memcpy";
-    break;
-  case Intrinsic::memmove:
-    CallTo = "memmove";
-    break;
-  case Intrinsic::memset:
-    CallTo = "memset";
-    break;
-  case Intrinsic::memcpy_element_unordered_atomic:
-    CallTo = "memcpy";
-    Atomic = true;
-    break;
-  case Intrinsic::memmove_element_unordered_atomic:
-    CallTo = "memmove";
-    Atomic = true;
-    break;
-  case Intrinsic::memset_element_unordered_atomic:
-    CallTo = "memset";
-    Atomic = true;
-    break;
-  default:
-    return inspectUnknown(II);
-  }
-
-  OptimizationRemarkMissed R(RemarkPass.data(), "AutoInitIntrinsic", &II);
-  inspectCallee(StringRef(CallTo), /*KnownLibCall=*/true, R);
-  inspectSizeOperand(II.getOperand(2), R);
-
-  auto *CIVolatile = dyn_cast<ConstantInt>(II.getOperand(3));
-  // No such thing as a memory intrinsic that is both atomic and volatile.
-  bool Volatile = !Atomic && CIVolatile && CIVolatile->getZExtValue();
-  inspectDst(II.getOperand(0), R);
-  volatileOrAtomicWithExtraArgs(Volatile, Atomic, R);
-  ORE.emit(R);
-}
-
-void AutoInitRemark::inspectCall(CallInst &CI) {
-  Function *F = CI.getCalledFunction();
-  if (!F)
-    return inspectUnknown(CI);
-
-  LibFunc LF;
-  bool KnownLibCall = TLI.getLibFunc(*F, LF) && TLI.has(LF);
-  OptimizationRemarkMissed R(RemarkPass.data(), "AutoInitCall", &CI);
-  inspectCallee(F, KnownLibCall, R);
-  inspectKnownLibCall(CI, LF, R);
-  ORE.emit(R);
-}
-
-template <typename FTy>
-void AutoInitRemark::inspectCallee(FTy F, bool KnownLibCall,
-                                   OptimizationRemarkMissed &R) {
-  R << "Call to ";
-  if (!KnownLibCall)
-    R << NV("UnknownLibCall", "unknown") << " function ";
-  R << NV("Callee", F) << " inserted by -ftrivial-auto-var-init.";
-}
-
-void AutoInitRemark::inspectKnownLibCall(CallInst &CI, LibFunc LF,
-                                         OptimizationRemarkMissed &R) {
-  switch (LF) {
-  default:
-    return;
-  case LibFunc_bzero:
-    inspectSizeOperand(CI.getOperand(1), R);
-    inspectDst(CI.getOperand(0), R);
-    break;
-  }
-}
-
-void AutoInitRemark::inspectSizeOperand(Value *V, OptimizationRemarkMissed &R) {
-  if (auto *Len = dyn_cast<ConstantInt>(V)) {
-    uint64_t Size = Len->getZExtValue();
-    R << " Memory operation size: " << NV("StoreSize", Size) << " bytes.";
-  }
-}
-
-void AutoInitRemark::inspectVariable(const Value *V,
-                                     SmallVectorImpl<VariableInfo> &Result) {
-  // If we find some information in the debug info, take that.
-  bool FoundDI = false;
-  // Try to get an llvm.dbg.declare, which has a DILocalVariable giving us the
-  // real debug info name and size of the variable.
-  for (const DbgVariableIntrinsic *DVI :
-       FindDbgAddrUses(const_cast<Value *>(V))) {
-    if (DILocalVariable *DILV = DVI->getVariable()) {
-      Optional<uint64_t> DISize = getSizeInBytes(DILV->getSizeInBits());
-      VariableInfo Var{DILV->getName(), DISize};
-      if (!Var.isEmpty()) {
-        Result.push_back(std::move(Var));
-        FoundDI = true;
-      }
-    }
-  }
-  if (FoundDI) {
-    assert(!Result.empty());
-    return;
-  }
-
-  const auto *AI = dyn_cast<AllocaInst>(V);
-  if (!AI)
-    return;
-
-  // If not, get it from the alloca.
-  Optional<StringRef> Name = AI->hasName()
-                                 ? Optional<StringRef>(AI->getName())
-                                 : Optional<StringRef>(None);
-  Optional<TypeSize> TySize = AI->getAllocationSizeInBits(DL);
-  Optional<uint64_t> Size =
-      TySize ? getSizeInBytes(TySize->getFixedSize()) : None;
-  VariableInfo Var{Name, Size};
-  if (!Var.isEmpty())
-    Result.push_back(std::move(Var));
-}
-
-void AutoInitRemark::inspectDst(Value *Dst, OptimizationRemarkMissed &R) {
-  // Find if Dst is a known variable we can give more information on.
-  SmallVector<Value *, 2> Objects;
-  getUnderlyingObjectsForCodeGen(Dst, Objects);
-  SmallVector<VariableInfo, 2> VIs;
-  for (const Value *V : Objects)
-    inspectVariable(V, VIs);
-
-  if (VIs.empty())
-    return;
-
-  R << "\nVariables: ";
-  for (unsigned i = 0; i < VIs.size(); ++i) {
-    const VariableInfo &VI = VIs[i];
-    assert(!VI.isEmpty() && "No extra content to display.");
-    if (i != 0)
-      R << ", ";
-    if (VI.Name)
-      R << NV("VarName", *VI.Name);
-    else
-      R << NV("VarName", "<unknown>");
-    if (VI.Size)
-      R << " (" << NV("VarSize", *VI.Size) << " bytes)";
-  }
-  R << ".";
-}

diff  --git a/llvm/lib/Transforms/Utils/CMakeLists.txt b/llvm/lib/Transforms/Utils/CMakeLists.txt
index 2e100310e6fc4..be4f7125eb853 100644
--- a/llvm/lib/Transforms/Utils/CMakeLists.txt
+++ b/llvm/lib/Transforms/Utils/CMakeLists.txt
@@ -3,7 +3,6 @@ add_llvm_component_library(LLVMTransformUtils
   AMDGPUEmitPrintf.cpp
   ASanStackFrameLayout.cpp
   AssumeBundleBuilder.cpp
-  AutoInitRemark.cpp
   BasicBlockUtils.cpp
   BreakCriticalEdges.cpp
   BuildLibCalls.cpp
@@ -48,6 +47,7 @@ add_llvm_component_library(LLVMTransformUtils
   LowerMemIntrinsics.cpp
   LowerSwitch.cpp
   MatrixUtils.cpp
+  MemoryOpRemark.cpp
   Mem2Reg.cpp
   MetaRenamer.cpp
   ModuleUtils.cpp

diff  --git a/llvm/lib/Transforms/Utils/MemoryOpRemark.cpp b/llvm/lib/Transforms/Utils/MemoryOpRemark.cpp
new file mode 100644
index 0000000000000..1ad75f716abc8
--- /dev/null
+++ b/llvm/lib/Transforms/Utils/MemoryOpRemark.cpp
@@ -0,0 +1,383 @@
+//===-- MemoryOpRemark.cpp - Auto-init remark analysis---------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementation of the analysis for the "auto-init" remark.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Utils/MemoryOpRemark.h"
+#include "llvm/Analysis/OptimizationRemarkEmitter.h"
+#include "llvm/Analysis/ValueTracking.h"
+#include "llvm/IR/DebugInfo.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
+
+using namespace llvm;
+using namespace llvm::ore;
+
+MemoryOpRemark::~MemoryOpRemark() = default;
+
+bool MemoryOpRemark::canHandle(const Instruction *I, const TargetLibraryInfo &TLI) {
+  if (isa<StoreInst>(I))
+    return true;
+
+  if (auto *II = dyn_cast<IntrinsicInst>(I)) {
+    switch (II->getIntrinsicID()) {
+    case Intrinsic::memcpy_inline:
+    case Intrinsic::memcpy:
+    case Intrinsic::memmove:
+    case Intrinsic::memset:
+    case Intrinsic::memcpy_element_unordered_atomic:
+    case Intrinsic::memmove_element_unordered_atomic:
+    case Intrinsic::memset_element_unordered_atomic:
+      return true;
+    default:
+      return false;
+    }
+  }
+
+  if (auto *CI = dyn_cast<CallInst>(I)) {
+    auto *CF = CI->getCalledFunction();
+    if (!CF)
+      return false;
+
+    if (!CF->hasName())
+      return false;
+
+    LibFunc LF;
+    bool KnownLibCall = TLI.getLibFunc(*CF, LF) && TLI.has(LF);
+    if (!KnownLibCall)
+      return false;
+
+    switch (LF) {
+    case LibFunc_memcpy_chk:
+    case LibFunc_mempcpy_chk:
+    case LibFunc_memset_chk:
+    case LibFunc_memmove_chk:
+    case LibFunc_memcpy:
+    case LibFunc_mempcpy:
+    case LibFunc_memset:
+    case LibFunc_memmove:
+    case LibFunc_bzero:
+    case LibFunc_bcopy:
+      return true;
+    default:
+      return false;
+    }
+  }
+
+  return false;
+}
+
+void MemoryOpRemark::visit(const Instruction *I) {
+  // For some of them, we can provide more information:
+
+  // For stores:
+  // * size
+  // * volatile / atomic
+  if (auto *SI = dyn_cast<StoreInst>(I)) {
+    visitStore(*SI);
+    return;
+  }
+
+  // For intrinsics:
+  // * user-friendly name
+  // * size
+  if (auto *II = dyn_cast<IntrinsicInst>(I)) {
+    visitIntrinsicCall(*II);
+    return;
+  }
+
+  // For calls:
+  // * known/unknown function (e.g. the compiler knows bzero, but it doesn't
+  //                                know my_bzero)
+  // * memory operation size
+  if (auto *CI = dyn_cast<CallInst>(I)) {
+    visitCall(*CI);
+    return;
+  }
+
+  visitUnknown(*I);
+}
+
+std::string MemoryOpRemark::explainSource(StringRef Type) {
+  return (Type + ".").str();
+}
+
+StringRef MemoryOpRemark::remarkName(RemarkKind RK) {
+  switch (RK) {
+  case RK_Store:
+    return "MemoryOpStore";
+  case RK_Unknown:
+    return "MemoryOpUnknown";
+  case RK_IntrinsicCall:
+    return "MemoryOpIntrinsicCall";
+  case RK_Call:
+    return "MemoryOpCall";
+  }
+  llvm_unreachable("missing RemarkKind case");
+}
+
+static void inlineVolatileOrAtomicWithExtraArgs(bool *Inline, bool Volatile,
+                                                bool Atomic,
+                                                OptimizationRemarkMissed &R) {
+  if (Inline && *Inline)
+    R << " Inlined: " << NV("StoreInlined", true) << ".";
+  if (Volatile)
+    R << " Volatile: " << NV("StoreVolatile", true) << ".";
+  if (Atomic)
+    R << " Atomic: " << NV("StoreAtomic", true) << ".";
+  // Emit the false cases under ExtraArgs. This won't show them in the remark
+  // message but will end up in the serialized remarks.
+  if ((Inline && !*Inline) || !Volatile || !Atomic)
+    R << setExtraArgs();
+  if (Inline && !*Inline)
+    R << " Inlined: " << NV("StoreInlined", false) << ".";
+  if (!Volatile)
+    R << " Volatile: " << NV("StoreVolatile", false) << ".";
+  if (!Atomic)
+    R << " Atomic: " << NV("StoreAtomic", false) << ".";
+}
+
+static Optional<uint64_t> getSizeInBytes(Optional<uint64_t> SizeInBits) {
+  if (!SizeInBits || *SizeInBits % 8 != 0)
+    return None;
+  return *SizeInBits / 8;
+}
+
+void MemoryOpRemark::visitStore(const StoreInst &SI) {
+  bool Volatile = SI.isVolatile();
+  bool Atomic = SI.isAtomic();
+  int64_t Size = DL.getTypeStoreSize(SI.getOperand(0)->getType());
+
+  OptimizationRemarkMissed R(RemarkPass.data(), remarkName(RK_Store), &SI);
+  R << explainSource("Store") << "\nStore size: " << NV("StoreSize", Size)
+    << " bytes.";
+  visitPtr(SI.getOperand(1), /*IsRead=*/false, R);
+  inlineVolatileOrAtomicWithExtraArgs(nullptr, Volatile, Atomic, R);
+  ORE.emit(R);
+}
+
+void MemoryOpRemark::visitUnknown(const Instruction &I) {
+  OptimizationRemarkMissed R(RemarkPass.data(), remarkName(RK_Unknown), &I);
+  R << explainSource("Initialization");
+  ORE.emit(R);
+}
+
+void MemoryOpRemark::visitIntrinsicCall(const IntrinsicInst &II) {
+  SmallString<32> CallTo;
+  bool Atomic = false;
+  bool Inline = false;
+  switch (II.getIntrinsicID()) {
+  case Intrinsic::memcpy_inline:
+    CallTo = "memcpy";
+    Inline = true;
+    break;
+  case Intrinsic::memcpy:
+    CallTo = "memcpy";
+    break;
+  case Intrinsic::memmove:
+    CallTo = "memmove";
+    break;
+  case Intrinsic::memset:
+    CallTo = "memset";
+    break;
+  case Intrinsic::memcpy_element_unordered_atomic:
+    CallTo = "memcpy";
+    Atomic = true;
+    break;
+  case Intrinsic::memmove_element_unordered_atomic:
+    CallTo = "memmove";
+    Atomic = true;
+    break;
+  case Intrinsic::memset_element_unordered_atomic:
+    CallTo = "memset";
+    Atomic = true;
+    break;
+  default:
+    return visitUnknown(II);
+  }
+
+  OptimizationRemarkMissed R(RemarkPass.data(), remarkName(RK_IntrinsicCall),
+                             &II);
+  visitCallee(StringRef(CallTo), /*KnownLibCall=*/true, R);
+  visitSizeOperand(II.getOperand(2), R);
+
+  auto *CIVolatile = dyn_cast<ConstantInt>(II.getOperand(3));
+  // No such thing as a memory intrinsic that is both atomic and volatile.
+  bool Volatile = !Atomic && CIVolatile && CIVolatile->getZExtValue();
+  switch (II.getIntrinsicID()) {
+  case Intrinsic::memcpy_inline:
+  case Intrinsic::memcpy:
+  case Intrinsic::memmove:
+  case Intrinsic::memcpy_element_unordered_atomic:
+    visitPtr(II.getOperand(1), /*IsRead=*/true, R);
+    visitPtr(II.getOperand(0), /*IsRead=*/false, R);
+    break;
+  case Intrinsic::memset:
+  case Intrinsic::memset_element_unordered_atomic:
+    visitPtr(II.getOperand(0), /*IsRead=*/false, R);
+    break;
+  }
+  inlineVolatileOrAtomicWithExtraArgs(&Inline, Volatile, Atomic, R);
+  ORE.emit(R);
+}
+
+void MemoryOpRemark::visitCall(const CallInst &CI) {
+  Function *F = CI.getCalledFunction();
+  if (!F)
+    return visitUnknown(CI);
+
+  LibFunc LF;
+  bool KnownLibCall = TLI.getLibFunc(*F, LF) && TLI.has(LF);
+  OptimizationRemarkMissed R(RemarkPass.data(), remarkName(RK_Call), &CI);
+  visitCallee(F, KnownLibCall, R);
+  visitKnownLibCall(CI, LF, R);
+  ORE.emit(R);
+}
+
+template <typename FTy>
+void MemoryOpRemark::visitCallee(FTy F, bool KnownLibCall,
+                                 OptimizationRemarkMissed &R) {
+  R << "Call to ";
+  if (!KnownLibCall)
+    R << NV("UnknownLibCall", "unknown") << " function ";
+  R << NV("Callee", F) << explainSource("");
+}
+
+void MemoryOpRemark::visitKnownLibCall(const CallInst &CI, LibFunc LF,
+                                       OptimizationRemarkMissed &R) {
+  switch (LF) {
+  default:
+    return;
+  case LibFunc_memset_chk:
+  case LibFunc_memset:
+    visitSizeOperand(CI.getOperand(2), R);
+    visitPtr(CI.getOperand(0), /*IsRead=*/false, R);
+    break;
+  case LibFunc_bzero:
+    visitSizeOperand(CI.getOperand(1), R);
+    visitPtr(CI.getOperand(0), /*IsRead=*/false, R);
+    break;
+  case LibFunc_memcpy_chk:
+  case LibFunc_mempcpy_chk:
+  case LibFunc_memmove_chk:
+  case LibFunc_memcpy:
+  case LibFunc_mempcpy:
+  case LibFunc_memmove:
+  case LibFunc_bcopy:
+    visitSizeOperand(CI.getOperand(2), R);
+    visitPtr(CI.getOperand(1), /*IsRead=*/true, R);
+    visitPtr(CI.getOperand(0), /*IsRead=*/false, R);
+    break;
+  }
+}
+
+void MemoryOpRemark::visitSizeOperand(Value *V, OptimizationRemarkMissed &R) {
+  if (auto *Len = dyn_cast<ConstantInt>(V)) {
+    uint64_t Size = Len->getZExtValue();
+    R << " Memory operation size: " << NV("StoreSize", Size) << " bytes.";
+  }
+}
+
+void MemoryOpRemark::visitVariable(const Value *V,
+                                   SmallVectorImpl<VariableInfo> &Result) {
+  // If we find some information in the debug info, take that.
+  bool FoundDI = false;
+  // Try to get an llvm.dbg.declare, which has a DILocalVariable giving us the
+  // real debug info name and size of the variable.
+  for (const DbgVariableIntrinsic *DVI :
+       FindDbgAddrUses(const_cast<Value *>(V))) {
+    if (DILocalVariable *DILV = DVI->getVariable()) {
+      Optional<uint64_t> DISize = getSizeInBytes(DILV->getSizeInBits());
+      VariableInfo Var{DILV->getName(), DISize};
+      if (!Var.isEmpty()) {
+        Result.push_back(std::move(Var));
+        FoundDI = true;
+      }
+    }
+  }
+  if (FoundDI) {
+    assert(!Result.empty());
+    return;
+  }
+
+  const auto *AI = dyn_cast<AllocaInst>(V);
+  if (!AI)
+    return;
+
+  // If not, get it from the alloca.
+  Optional<StringRef> Name = AI->hasName() ? Optional<StringRef>(AI->getName())
+                                           : Optional<StringRef>(None);
+  Optional<TypeSize> TySize = AI->getAllocationSizeInBits(DL);
+  Optional<uint64_t> Size =
+      TySize ? getSizeInBytes(TySize->getFixedSize()) : None;
+  VariableInfo Var{Name, Size};
+  if (!Var.isEmpty())
+    Result.push_back(std::move(Var));
+}
+
+void MemoryOpRemark::visitPtr(Value *Ptr, bool IsRead, OptimizationRemarkMissed &R) {
+  // Find if Ptr is a known variable we can give more information on.
+  SmallVector<Value *, 2> Objects;
+  getUnderlyingObjectsForCodeGen(Ptr, Objects);
+  SmallVector<VariableInfo, 2> VIs;
+  for (const Value *V : Objects)
+    visitVariable(V, VIs);
+
+  if (VIs.empty()) {
+    bool CanBeNull;
+    bool CanBeFreed;
+    uint64_t Size = Ptr->getPointerDereferenceableBytes(DL, CanBeNull, CanBeFreed);
+    if (!Size)
+      return;
+    VIs.push_back({None, Size});
+  }
+
+  R << (IsRead ? "\n Read Variables: " : "\n Written Variables: ");
+  for (unsigned i = 0; i < VIs.size(); ++i) {
+    const VariableInfo &VI = VIs[i];
+    assert(!VI.isEmpty() && "No extra content to display.");
+    if (i != 0)
+      R << ", ";
+    if (VI.Name)
+      R << NV(IsRead ? "RVarName" : "WVarName", *VI.Name);
+    else
+      R << NV(IsRead ? "RVarName" : "WVarName", "<unknown>");
+    if (VI.Size)
+      R << " (" << NV(IsRead ? "RVarSize" : "WVarSize", *VI.Size) << " bytes)";
+  }
+  R << ".";
+}
+
+bool AutoInitRemark::canHandle(const Instruction *I) {
+  if (!I->hasMetadata(LLVMContext::MD_annotation))
+    return false;
+  return any_of(I->getMetadata(LLVMContext::MD_annotation)->operands(),
+                [](const MDOperand &Op) {
+                  return cast<MDString>(Op.get())->getString() == "auto-init";
+                });
+}
+
+std::string AutoInitRemark::explainSource(StringRef Type) {
+  return (Type + " inserted by -ftrivial-auto-var-init.").str();
+}
+
+StringRef AutoInitRemark::remarkName(RemarkKind RK) {
+  switch (RK) {
+  case RK_Store:
+    return "AutoInitStore";
+  case RK_Unknown:
+    return "AutoInitUnknownInstruction";
+  case RK_IntrinsicCall:
+    return "AutoInitIntrinsicCall";
+  case RK_Call:
+    return "AutoInitCall";
+  }
+  llvm_unreachable("missing RemarkKind case");
+}

diff  --git a/llvm/test/CodeGen/AArch64/memsize-remarks.ll b/llvm/test/CodeGen/AArch64/memsize-remarks.ll
new file mode 100644
index 0000000000000..10af36c01d1e5
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/memsize-remarks.ll
@@ -0,0 +1,373 @@
+; RUN: llc %s -pass-remarks-missed=memsize -pass-remarks-output=%t.opt.yaml -pass-remarks-filter=memsize -global-isel -o /dev/null 2>&1 | FileCheck %s --check-prefix=GISEL --implicit-check-not=GISEL
+; RUN: cat %t.opt.yaml | FileCheck -check-prefix=YAML %s
+
+source_filename = "memsize.c"
+target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
+target triple = "arm64-apple-ios7.0.0"
+
+declare i8* @__memmove_chk(i8*, i8*, i64, i64) #1
+declare i8* @__memcpy_chk(i8*, i8*, i64, i64) #1
+declare i8* @__memset_chk(i8*, i32, i64, i64) #1
+declare i64 @llvm.objectsize.i64.p0i8(i8*, i1 immarg, i1 immarg, i1 immarg) #2
+declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1 immarg) argmemonly nounwind willreturn writeonly
+declare void @llvm.memmove.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i1 immarg) argmemonly nounwind willreturn
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) argmemonly nounwind willreturn
+declare void @bzero(i8* nocapture, i64) nofree nounwind
+declare void @bcopy(i8* nocapture, i8* nocapture, i64) nofree nounwind
+declare i8* @memset(i8*, i32, i64)
+
+define void @memcpy_dynamic(i8* %d, i8* %s, i64 %l) #0 !dbg !14 {
+entry:
+  %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false), !dbg !16
+; GISEL: remark: memsize.c:4:3: Call to memcpy.{{$}}
+  %call = call i8* @__memcpy_chk(i8* %d, i8* %s, i64 %l, i64 %0) #4, !dbg !17
+  ret void, !dbg !18
+}
+
+define void @memcpy_single(i8* %d, i8* %s, i64 %l) #0 !dbg !23 {
+entry:
+  %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false), !dbg !24
+; GISEL: remark: memsize.c:10:3: Call to memcpy. Memory operation size: 1 bytes.
+  %call = call i8* @__memcpy_chk(i8* %d, i8* %s, i64 1, i64 %0) #4, !dbg !25
+  ret void, !dbg !26
+}
+
+define void @memcpy_intrinsic(i8* %d, i8* %s, i64 %l) #0 {
+entry:
+  %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false)
+; GISEL: remark: <unknown>:0:0: Call to memcpy. Memory operation size: 1 bytes.
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %d, i8* %s, i64 1, i1 false)
+  ret void
+}
+
+define void @memcpy_static(i8* %d, i8* %s, i64 %l) #0 !dbg !27 {
+entry:
+  %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false), !dbg !28
+; GISEL: remark: memsize.c:13:3: Call to memcpy. Memory operation size: 100 bytes.
+  %call = call i8* @__memcpy_chk(i8* %d, i8* %s, i64 100, i64 %0) #4, !dbg !29
+  ret void, !dbg !30
+}
+
+define void @memcpy_huge(i8* %d, i8* %s, i64 %l) #0 !dbg !31 {
+entry:
+  %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false), !dbg !32
+; GISEL: remark: memsize.c:16:3: Call to memcpy. Memory operation size: 100000 bytes.
+  %call = call i8* @__memcpy_chk(i8* %d, i8* %s, i64 100000, i64 %0) #4, !dbg !33
+  ret void, !dbg !34
+}
+
+define void @memmove_dynamic(i8* %d, i8* %s, i64 %l) #0 {
+entry:
+  %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false)
+; GISEL: remark: <unknown>:0:0: Call to memmove.{{$}}
+  %call = call i8* @__memmove_chk(i8* %d, i8* %s, i64 %l, i64 %0) #4
+  ret void
+}
+
+define void @memmove_single(i8* %d, i8* %s, i64 %l) #0 {
+entry:
+  %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false)
+; GISEL: remark: <unknown>:0:0: Call to memmove. Memory operation size: 1 bytes.
+  %call = call i8* @__memmove_chk(i8* %d, i8* %s, i64 1, i64 %0) #4
+  ret void
+}
+
+define void @memmove_static(i8* %d, i8* %s, i64 %l) #0 {
+entry:
+  %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false)
+; GISEL: remark: <unknown>:0:0: Call to memmove. Memory operation size: 100 bytes.
+  %call = call i8* @__memmove_chk(i8* %d, i8* %s, i64 100, i64 %0) #4
+  ret void
+}
+
+define void @memmove_huge(i8* %d, i8* %s, i64 %l) #0 {
+entry:
+  %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false)
+; GISEL: remark: <unknown>:0:0: Call to memmove. Memory operation size: 100000 bytes.
+  %call = call i8* @__memmove_chk(i8* %d, i8* %s, i64 100000, i64 %0) #4
+  ret void
+}
+
+define void @memset_dynamic(i8* %d, i64 %l) #0 !dbg !38 {
+entry:
+  %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false), !dbg !39
+; GISEL: remark: memsize.c:22:3: Call to memset.{{$}}
+  %call = call i8* @__memset_chk(i8* %d, i32 0, i64 %l, i64 %0) #4, !dbg !40
+  ret void, !dbg !41
+}
+
+define void @memset_single(i8* %d, i64 %l) #0 !dbg !46 {
+entry:
+  %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false), !dbg !47
+; GISEL: remark: memsize.c:28:3: Call to memset. Memory operation size: 1 bytes.
+  %call = call i8* @__memset_chk(i8* %d, i32 0, i64 1, i64 %0) #4, !dbg !48
+  ret void, !dbg !49
+}
+
+define void @memset_static(i8* %d, i64 %l) #0 !dbg !50 {
+entry:
+  %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false), !dbg !51
+; GISEL: remark: memsize.c:31:3: Call to memset. Memory operation size: 100 bytes.
+  %call = call i8* @__memset_chk(i8* %d, i32 0, i64 100, i64 %0) #4, !dbg !52
+  ret void, !dbg !53
+}
+
+define void @memset_huge(i8* %d, i64 %l) #0 !dbg !54 {
+entry:
+  %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false), !dbg !55
+; GISEL: remark: memsize.c:34:3: Call to memset. Memory operation size: 100000 bytes.
+  %call = call i8* @__memset_chk(i8* %d, i32 0, i64 100000, i64 %0) #4, !dbg !56
+  ret void, !dbg !57
+}
+
+define void @memset_empty(i8* %d, i64 %l) #0 !dbg !42 {
+entry:
+  %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false), !dbg !43
+; GISEL: remark: memsize.c:25:3: Call to memset. Memory operation size: 0 bytes.
+  %call = call i8* @__memset_chk(i8* %d, i32 0, i64 0, i64 %0) #4, !dbg !44
+  ret void, !dbg !45
+}
+
+; YAML-LABEL: Function:        memcpy_empty
+define void @memcpy_empty(i8* %d, i8* %s, i64 %l) #0 !dbg !19 {
+entry:
+  %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false), !dbg !20
+; GISEL: remark: memsize.c:7:3: Call to memcpy. Memory operation size: 0 bytes.
+  %call = call i8* @__memcpy_chk(i8* %d, i8* %s, i64 0, i64 %0) #4, !dbg !21
+  ret void, !dbg !22
+}
+
+; Emit remarks for memcpy, memmove, memset, bzero, bcopy with known constant
+; sizes to an object of known size.
+define void @known_call_with_dereferenceable_bytes(i8* dereferenceable(42) %dst, i8* dereferenceable(314) %src) {
+; GISEL: Call to memset. Memory operation size: 1 bytes.
+; GISEL-NOT:  Read Variables:
+; GISEL-NEXT:  Written Variables: <unknown> (42 bytes).
+; YAML:       --- !Missed
+; YAML:       Pass:            memsize
+; YAML:       Name:            MemoryOpIntrinsicCall
+; YAML-LABEL: Function:        known_call_with_dereferenceable_bytes
+; YAML-NEXT:  Args:
+; YAML-NEXT:    - String:          'Call to '
+; YAML-NEXT:    - Callee:          memset
+; YAML-NEXT:    - String:          .
+; YAML-NEXT:    - String:          ' Memory operation size: '
+; YAML-NEXT:    - StoreSize:       '1'
+; YAML-NEXT:    - String:          ' bytes.'
+; YAML-NEXT:    - String:          "\n Written Variables: "
+; YAML-NEXT:    - WVarName:        '<unknown>'
+; YAML-NEXT:    - String:          ' ('
+; YAML-NEXT:    - WVarSize:        '42'
+; YAML-NEXT:    - String:          ' bytes)'
+; YAML-NEXT:    - String:          .
+; YAML-NEXT:    - String:          ' Inlined: '
+; YAML-NEXT:    - StoreInlined:    'false'
+; YAML-NEXT:    - String:          .
+; YAML-NEXT:    - String:          ' Volatile: '
+; YAML-NEXT:    - StoreVolatile:   'false'
+; YAML-NEXT:    - String:          .
+; YAML-NEXT:    - String:          ' Atomic: '
+; YAML-NEXT:    - StoreAtomic:     'false'
+; YAML-NEXT:    - String:          .
+; YAML-NEXT:  ...
+  call void @llvm.memset.p0i8.i64(i8* %dst, i8 0, i64 1, i1 false)
+
+; GISEL: Call to memcpy. Memory operation size: 1 bytes.
+; GISEL-NEXT:  Read Variables: <unknown> (314 bytes).
+; GISEL-NEXT:  Written Variables: <unknown> (42 bytes).
+; YAML:       --- !Missed
+; YAML:       Pass:            memsize
+; YAML:       Name:            MemoryOpIntrinsicCall
+; YAML-LABEL: Function:        known_call_with_dereferenceable_bytes
+; YAML-NEXT:  Args:
+; YAML-NEXT:    - String:          'Call to '
+; YAML-NEXT:    - Callee:          memcpy
+; YAML-NEXT:    - String:          .
+; YAML-NEXT:    - String:          ' Memory operation size: '
+; YAML-NEXT:    - StoreSize:       '1'
+; YAML-NEXT:    - String:          ' bytes.'
+; YAML-NEXT:    - String:          "\n Read Variables: "
+; YAML-NEXT:    - RVarName:        '<unknown>'
+; YAML-NEXT:    - String:          ' ('
+; YAML-NEXT:    - RVarSize:        '314'
+; YAML-NEXT:    - String:          ' bytes)'
+; YAML-NEXT:    - String:          .
+; YAML-NEXT:    - String:          "\n Written Variables: "
+; YAML-NEXT:    - WVarName:        '<unknown>'
+; YAML-NEXT:    - String:          ' ('
+; YAML-NEXT:    - WVarSize:        '42'
+; YAML-NEXT:    - String:          ' bytes)'
+; YAML-NEXT:    - String:          .
+; YAML-NEXT:    - String:          ' Inlined: '
+; YAML-NEXT:    - StoreInlined:    'false'
+; YAML-NEXT:    - String:          .
+; YAML-NEXT:    - String:          ' Volatile: '
+; YAML-NEXT:    - StoreVolatile:   'false'
+; YAML-NEXT:    - String:          .
+; YAML-NEXT:    - String:          ' Atomic: '
+; YAML-NEXT:    - StoreAtomic:     'false'
+; YAML-NEXT:    - String:          .
+; YAML-NEXT:  ...
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 1, i1 false)
+
+; GISEL: Call to memmove. Memory operation size: 1 bytes.
+; GISEL-NEXT:  Read Variables: <unknown> (314 bytes).
+; GISEL-NEXT:  Written Variables: <unknown> (42 bytes).
+; YAML:       --- !Missed
+; YAML:       Pass:            memsize
+; YAML:       Name:            MemoryOpIntrinsicCall
+; YAML-LABEL: Function:        known_call_with_dereferenceable_bytes
+; YAML-NEXT:  Args:
+; YAML-NEXT:    - String:          'Call to '
+; YAML-NEXT:    - Callee:          memmove
+; YAML-NEXT:    - String:          .
+; YAML-NEXT:    - String:          ' Memory operation size: '
+; YAML-NEXT:    - StoreSize:       '1'
+; YAML-NEXT:    - String:          ' bytes.'
+; YAML-NEXT:    - String:          "\n Read Variables: "
+; YAML-NEXT:    - RVarName:        '<unknown>'
+; YAML-NEXT:    - String:          ' ('
+; YAML-NEXT:    - RVarSize:        '314'
+; YAML-NEXT:    - String:          ' bytes)'
+; YAML-NEXT:    - String:          .
+; YAML-NEXT:    - String:          "\n Written Variables: "
+; YAML-NEXT:    - WVarName:        '<unknown>'
+; YAML-NEXT:    - String:          ' ('
+; YAML-NEXT:    - WVarSize:        '42'
+; YAML-NEXT:    - String:          ' bytes)'
+; YAML-NEXT:    - String:          .
+; YAML-NEXT:    - String:          ' Inlined: '
+; YAML-NEXT:    - StoreInlined:    'false'
+; YAML-NEXT:    - String:          .
+; YAML-NEXT:    - String:          ' Volatile: '
+; YAML-NEXT:    - StoreVolatile:   'false'
+; YAML-NEXT:    - String:          .
+; YAML-NEXT:    - String:          ' Atomic: '
+; YAML-NEXT:    - StoreAtomic:     'false'
+; YAML-NEXT:    - String:          .
+; YAML-NEXT:  ...
+  call void @llvm.memmove.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 1, i1 false)
+
+; GISEL: Call to bzero. Memory operation size: 1 bytes.
+; GISEL-NOT:  Read Variables:
+; GISEL-NEXT:  Written Variables: <unknown> (42 bytes).
+; YAML:       --- !Missed
+; YAML:       Pass:            memsize
+; YAML:       Name:            MemoryOpCall
+; YAML-LABEL: Function:        known_call_with_dereferenceable_bytes
+; YAML-NEXT:  Args:
+; YAML-NEXT:    - String:          'Call to '
+; YAML-NEXT:    - Callee:          bzero
+; YAML-NEXT:    - String:          .
+; YAML-NEXT:    - String:          ' Memory operation size: '
+; YAML-NEXT:    - StoreSize:       '1'
+; YAML-NEXT:    - String:          ' bytes.'
+; YAML-NEXT:    - String:          "\n Written Variables: "
+; YAML-NEXT:    - WVarName:        '<unknown>'
+; YAML-NEXT:    - String:          ' ('
+; YAML-NEXT:    - WVarSize:        '42'
+; YAML-NEXT:    - String:          ' bytes)'
+; YAML-NEXT:    - String:          .
+; YAML-NEXT:  ...
+  call void @bzero(i8* %dst, i64 1)
+
+; GISEL: Call to bcopy. Memory operation size: 1 bytes.
+; GISEL-NEXT:  Read Variables: <unknown> (314 bytes).
+; GISEL-NEXT:  Written Variables: <unknown> (42 bytes).
+; YAML:       --- !Missed
+; YAML:       Pass:            memsize
+; YAML:       Name:            MemoryOpCall
+; YAML-LABEL: Function:        known_call_with_dereferenceable_bytes
+; YAML-NEXT:  Args:
+; YAML-NEXT:    - String:          'Call to '
+; YAML-NEXT:    - Callee:          bcopy
+; YAML-NEXT:    - String:          .
+; YAML-NEXT:    - String:          ' Memory operation size: '
+; YAML-NEXT:    - StoreSize:       '1'
+; YAML-NEXT:    - String:          ' bytes.'
+; YAML-NEXT:    - String:          "\n Read Variables: "
+; YAML-NEXT:    - RVarName:        '<unknown>'
+; YAML-NEXT:    - String:          ' ('
+; YAML-NEXT:    - RVarSize:        '314'
+; YAML-NEXT:    - String:          ' bytes)'
+; YAML-NEXT:    - String:          .
+; YAML-NEXT:    - String:          "\n Written Variables: "
+; YAML-NEXT:    - WVarName:        '<unknown>'
+; YAML-NEXT:    - String:          ' ('
+; YAML-NEXT:    - WVarSize:        '42'
+; YAML-NEXT:    - String:          ' bytes)'
+; YAML-NEXT:    - String:          .
+; YAML-NEXT:  ...
+  call void @bcopy(i8* %dst, i8* %src, i64 1)
+  ret void
+}
+
+attributes #0 = { noinline nounwind ssp uwtable "frame-pointer"="non-leaf" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-a7" "target-features"="+aes,+crypto,+fp-armv8,+neon,+sha2,+zcm,+zcz" }
+attributes #1 = { nounwind "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-a7" "target-features"="+aes,+crypto,+fp-armv8,+neon,+sha2,+zcm,+zcz" }
+attributes #2 = { nofree nosync nounwind readnone speculatable willreturn }
+attributes #3 = { argmemonly nofree nosync nounwind willreturn }
+attributes #4 = { nounwind }
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
+!llvm.dbg.cu = !{!10}
+!llvm.ident = !{!13}
+
+!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 12, i32 0]}
+!1 = !{i32 2, !"Debug Info Version", i32 3}
+!2 = !{i32 1, !"wchar_size", i32 4}
+!3 = !{i32 1, !"branch-target-enforcement", i32 0}
+!4 = !{i32 1, !"sign-return-address", i32 0}
+!5 = !{i32 1, !"sign-return-address-all", i32 0}
+!6 = !{i32 1, !"sign-return-address-with-bkey", i32 0}
+!7 = !{i32 7, !"PIC Level", i32 2}
+!8 = !{i32 7, !"uwtable", i32 1}
+!9 = !{i32 7, !"frame-pointer", i32 1}
+!10 = distinct !DICompileUnit(language: DW_LANG_C99, file: !11, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: NoDebug, enums: !12, splitDebugInlining: false, nameTableKind: None, sysroot: "/")
+!11 = !DIFile(filename: "memsize.c", directory: "")
+!12 = !{}
+!13 = !{!"clang"}
+!14 = distinct !DISubprogram(name: "memcpy_dynamic", scope: !11, file: !11, line: 3, type: !15, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !10, retainedNodes: !12)
+!15 = !DISubroutineType(types: !12)
+!16 = !DILocation(line: 4, column: 36, scope: !14)
+!17 = !DILocation(line: 4, column: 3, scope: !14)
+!18 = !DILocation(line: 5, column: 1, scope: !14)
+!19 = distinct !DISubprogram(name: "memcpy_empty", scope: !11, file: !11, line: 6, type: !15, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !10, retainedNodes: !12)
+!20 = !DILocation(line: 7, column: 36, scope: !19)
+!21 = !DILocation(line: 7, column: 3, scope: !19)
+!22 = !DILocation(line: 8, column: 1, scope: !19)
+!23 = distinct !DISubprogram(name: "memcpy_single", scope: !11, file: !11, line: 9, type: !15, scopeLine: 9, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !10, retainedNodes: !12)
+!24 = !DILocation(line: 10, column: 36, scope: !23)
+!25 = !DILocation(line: 10, column: 3, scope: !23)
+!26 = !DILocation(line: 11, column: 1, scope: !23)
+!27 = distinct !DISubprogram(name: "memcpy_static", scope: !11, file: !11, line: 12, type: !15, scopeLine: 12, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !10, retainedNodes: !12)
+!28 = !DILocation(line: 13, column: 38, scope: !27)
+!29 = !DILocation(line: 13, column: 3, scope: !27)
+!30 = !DILocation(line: 14, column: 1, scope: !27)
+!31 = distinct !DISubprogram(name: "memcpy_huge", scope: !11, file: !11, line: 15, type: !15, scopeLine: 15, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !10, retainedNodes: !12)
+!32 = !DILocation(line: 16, column: 41, scope: !31)
+!33 = !DILocation(line: 16, column: 3, scope: !31)
+!34 = !DILocation(line: 17, column: 1, scope: !31)
+!35 = distinct !DISubprogram(name: "memcpy_inline", scope: !11, file: !11, line: 18, type: !15, scopeLine: 18, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !10, retainedNodes: !12)
+!36 = !DILocation(line: 19, column: 3, scope: !35)
+!37 = !DILocation(line: 20, column: 1, scope: !35)
+!38 = distinct !DISubprogram(name: "memset_dynamic", scope: !11, file: !11, line: 21, type: !15, scopeLine: 21, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !10, retainedNodes: !12)
+!39 = !DILocation(line: 22, column: 36, scope: !38)
+!40 = !DILocation(line: 22, column: 3, scope: !38)
+!41 = !DILocation(line: 23, column: 1, scope: !38)
+!42 = distinct !DISubprogram(name: "memset_empty", scope: !11, file: !11, line: 24, type: !15, scopeLine: 24, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !10, retainedNodes: !12)
+!43 = !DILocation(line: 25, column: 36, scope: !42)
+!44 = !DILocation(line: 25, column: 3, scope: !42)
+!45 = !DILocation(line: 26, column: 1, scope: !42)
+!46 = distinct !DISubprogram(name: "memset_single", scope: !11, file: !11, line: 27, type: !15, scopeLine: 27, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !10, retainedNodes: !12)
+!47 = !DILocation(line: 28, column: 36, scope: !46)
+!48 = !DILocation(line: 28, column: 3, scope: !46)
+!49 = !DILocation(line: 29, column: 1, scope: !46)
+!50 = distinct !DISubprogram(name: "memset_static", scope: !11, file: !11, line: 30, type: !15, scopeLine: 30, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !10, retainedNodes: !12)
+!51 = !DILocation(line: 31, column: 38, scope: !50)
+!52 = !DILocation(line: 31, column: 3, scope: !50)
+!53 = !DILocation(line: 32, column: 1, scope: !50)
+!54 = distinct !DISubprogram(name: "memset_huge", scope: !11, file: !11, line: 33, type: !15, scopeLine: 33, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !10, retainedNodes: !12)
+!55 = !DILocation(line: 34, column: 41, scope: !54)
+!56 = !DILocation(line: 34, column: 3, scope: !54)
+!57 = !DILocation(line: 35, column: 1, scope: !54)
+!58 = distinct !DISubprogram(name: "auto_init", scope: !11, file: !11, line: 37, type: !15, scopeLine: 37, spFlags: DISPFlagDefinition, unit: !10, retainedNodes: !12)

diff  --git a/llvm/test/Transforms/Util/trivial-auto-var-init-call.ll b/llvm/test/Transforms/Util/trivial-auto-var-init-call.ll
index 79c69bd440828..1097a751af9df 100644
--- a/llvm/test/Transforms/Util/trivial-auto-var-init-call.ll
+++ b/llvm/test/Transforms/Util/trivial-auto-var-init-call.ll
@@ -13,6 +13,9 @@ define void @known_call(i8* %src, i8* %dst, i64 %size) {
 ; YAML-NEXT:   - String:          'Call to '
 ; YAML-NEXT:   - Callee:          memset
 ; YAML-NEXT:   - String:          ' inserted by -ftrivial-auto-var-init.'
+; YAML-NEXT:   - String:          ' Inlined: '
+; YAML-NEXT:   - StoreInlined:     'false'
+; YAML-NEXT:   - String:          .
 ; YAML-NEXT:   - String:          ' Volatile: '
 ; YAML-NEXT:   - StoreVolatile:   'false'
 ; YAML-NEXT:   - String:          .
@@ -31,6 +34,9 @@ define void @known_call(i8* %src, i8* %dst, i64 %size) {
 ; YAML-NEXT:   - String:          'Call to '
 ; YAML-NEXT:   - Callee:          memcpy
 ; YAML-NEXT:   - String:          ' inserted by -ftrivial-auto-var-init.'
+; YAML-NEXT:   - String:          ' Inlined: '
+; YAML-NEXT:   - StoreInlined:     'false'
+; YAML-NEXT:   - String:          .
 ; YAML-NEXT:   - String:          ' Volatile: '
 ; YAML-NEXT:   - StoreVolatile:   'false'
 ; YAML-NEXT:   - String:          .
@@ -49,6 +55,9 @@ define void @known_call(i8* %src, i8* %dst, i64 %size) {
 ; YAML-NEXT:   - String:          'Call to '
 ; YAML-NEXT:   - Callee:          memmove
 ; YAML-NEXT:   - String:          ' inserted by -ftrivial-auto-var-init.'
+; YAML-NEXT:   - String:          ' Inlined: '
+; YAML-NEXT:   - StoreInlined:     'false'
+; YAML-NEXT:   - String:          .
 ; YAML-NEXT:   - String:          ' Volatile: '
 ; YAML-NEXT:   - StoreVolatile:   'false'
 ; YAML-NEXT:   - String:          .
@@ -79,6 +88,9 @@ define void @known_call(i8* %src, i8* %dst, i64 %size) {
 ; YAML-NEXT:   - String:          'Call to '
 ; YAML-NEXT:   - Callee:          memset
 ; YAML-NEXT:   - String:          ' inserted by -ftrivial-auto-var-init.'
+; YAML-NEXT:   - String:          ' Memory operation size: '
+; YAML-NEXT:   - StoreSize:       '32'
+; YAML-NEXT:   - String:          ' bytes.'
 ; YAML-NEXT: ...
   call i8* @memset(i8* %dst, i32 0, i64 32), !annotation !0, !dbg !DILocation(scope: !4)
   ret void
@@ -99,6 +111,9 @@ define void @known_call_with_size(i8* %src, i8* %dst) {
 ; YAML-NEXT:   - String:          ' Memory operation size: '
 ; YAML-NEXT:   - StoreSize:       '32'
 ; YAML-NEXT:   - String:          ' bytes.'
+; YAML-NEXT:   - String:          ' Inlined: '
+; YAML-NEXT:   - StoreInlined:     'false'
+; YAML-NEXT:   - String:          .
 ; YAML-NEXT:   - String:          ' Volatile: '
 ; YAML-NEXT:   - StoreVolatile:   'false'
 ; YAML-NEXT:   - String:          .
@@ -120,6 +135,9 @@ define void @known_call_with_size(i8* %src, i8* %dst) {
 ; YAML-NEXT:   - String:          ' Memory operation size: '
 ; YAML-NEXT:   - StoreSize:       '32'
 ; YAML-NEXT:   - String:          ' bytes.'
+; YAML-NEXT:   - String:          ' Inlined: '
+; YAML-NEXT:   - StoreInlined:     'false'
+; YAML-NEXT:   - String:          .
 ; YAML-NEXT:   - String:          ' Volatile: '
 ; YAML-NEXT:   - StoreVolatile:   'false'
 ; YAML-NEXT:   - String:          .
@@ -141,6 +159,9 @@ define void @known_call_with_size(i8* %src, i8* %dst) {
 ; YAML-NEXT:   - String:          ' Memory operation size: '
 ; YAML-NEXT:   - StoreSize:       '32'
 ; YAML-NEXT:   - String:          ' bytes.'
+; YAML-NEXT:   - String:          ' Inlined: '
+; YAML-NEXT:   - StoreInlined:     'false'
+; YAML-NEXT:   - String:          .
 ; YAML-NEXT:   - String:          ' Volatile: '
 ; YAML-NEXT:   - StoreVolatile:   'false'
 ; YAML-NEXT:   - String:          .
@@ -183,6 +204,9 @@ define void @known_call_volatile(i8* %src, i8* %dst, i64 %size) {
 ; YAML-NEXT:   - String:          ' Volatile: '
 ; YAML-NEXT:   - StoreVolatile:   'true'
 ; YAML-NEXT:   - String:          .
+; YAML-NEXT:   - String:          ' Inlined: '
+; YAML-NEXT:   - StoreInlined:     'false'
+; YAML-NEXT:   - String:          .
 ; YAML-NEXT:   - String:          ' Atomic: '
 ; YAML-NEXT:   - StoreAtomic:     'false'
 ; YAML-NEXT:   - String:          .
@@ -201,6 +225,9 @@ define void @known_call_volatile(i8* %src, i8* %dst, i64 %size) {
 ; YAML-NEXT:   - String:          ' Volatile: '
 ; YAML-NEXT:   - StoreVolatile:   'true'
 ; YAML-NEXT:   - String:          .
+; YAML-NEXT:   - String:          ' Inlined: '
+; YAML-NEXT:   - StoreInlined:     'false'
+; YAML-NEXT:   - String:          .
 ; YAML-NEXT:   - String:          ' Atomic: '
 ; YAML-NEXT:   - StoreAtomic:     'false'
 ; YAML-NEXT:   - String:          .
@@ -219,6 +246,9 @@ define void @known_call_volatile(i8* %src, i8* %dst, i64 %size) {
 ; YAML-NEXT:   - String:          ' Volatile: '
 ; YAML-NEXT:   - StoreVolatile:   'true'
 ; YAML-NEXT:   - String:          .
+; YAML-NEXT:   - String:          ' Inlined: '
+; YAML-NEXT:   - StoreInlined:     'false'
+; YAML-NEXT:   - String:          .
 ; YAML-NEXT:   - String:          ' Atomic: '
 ; YAML-NEXT:   - StoreAtomic:     'false'
 ; YAML-NEXT:   - String:          .
@@ -242,6 +272,9 @@ define void @known_call_atomic(i8* %src, i8* %dst, i64 %size) {
 ; YAML-NEXT:   - String:          ' Atomic: '
 ; YAML-NEXT:   - StoreAtomic:     'true'
 ; YAML-NEXT:   - String:          .
+; YAML-NEXT:   - String:          ' Inlined: '
+; YAML-NEXT:   - StoreInlined:     'false'
+; YAML-NEXT:   - String:          .
 ; YAML-NEXT:   - String:          ' Volatile: '
 ; YAML-NEXT:   - StoreVolatile:   'false'
 ; YAML-NEXT:   - String:          .
@@ -260,6 +293,9 @@ define void @known_call_atomic(i8* %src, i8* %dst, i64 %size) {
 ; YAML-NEXT:   - String:          ' Atomic: '
 ; YAML-NEXT:   - StoreAtomic:     'true'
 ; YAML-NEXT:   - String:          .
+; YAML-NEXT:   - String:          ' Inlined: '
+; YAML-NEXT:   - StoreInlined:     'false'
+; YAML-NEXT:   - String:          .
 ; YAML-NEXT:   - String:          ' Volatile: '
 ; YAML-NEXT:   - StoreVolatile:   'false'
 ; YAML-NEXT:   - String:          .
@@ -278,6 +314,9 @@ define void @known_call_atomic(i8* %src, i8* %dst, i64 %size) {
 ; YAML-NEXT:   - String:          ' Atomic: '
 ; YAML-NEXT:   - StoreAtomic:     'true'
 ; YAML-NEXT:   - String:          .
+; YAML-NEXT:   - String:          ' Inlined: '
+; YAML-NEXT:   - StoreInlined:     'false'
+; YAML-NEXT:   - String:          .
 ; YAML-NEXT:   - String:          ' Volatile: '
 ; YAML-NEXT:   - StoreVolatile:   'false'
 ; YAML-NEXT:   - String:          .
@@ -303,12 +342,15 @@ define void @known_call_with_size_alloca(i8* %src) {
 ; YAML-NEXT:   - String:          ' Memory operation size: '
 ; YAML-NEXT:   - StoreSize:       '1'
 ; YAML-NEXT:   - String:          ' bytes.'
-; YAML-NEXT:   - String:          "\nVariables: "
-; YAML-NEXT:   - VarName:         dst
+; YAML-NEXT:   - String:          "\n Written Variables: "
+; YAML-NEXT:   - WVarName:        dst
 ; YAML-NEXT:   - String:          ' ('
-; YAML-NEXT:   - VarSize:         '1'
+; YAML-NEXT:   - WVarSize:        '1'
 ; YAML-NEXT:   - String:          ' bytes)'
 ; YAML-NEXT:   - String:          .
+; YAML-NEXT:   - String:          ' Inlined: '
+; YAML-NEXT:   - StoreInlined:     'false'
+; YAML-NEXT:   - String:          .
 ; YAML-NEXT:   - String:          ' Volatile: '
 ; YAML-NEXT:   - StoreVolatile:   'false'
 ; YAML-NEXT:   - String:          .
@@ -332,12 +374,15 @@ define void @known_call_with_size_alloca(i8* %src) {
 ; YAML-NEXT:   - String:          ' Memory operation size: '
 ; YAML-NEXT:   - StoreSize:       '1'
 ; YAML-NEXT:   - String:          ' bytes.'
-; YAML-NEXT:   - String:          "\nVariables: "
-; YAML-NEXT:   - VarName:         dst
+; YAML-NEXT:   - String:          "\n Written Variables: "
+; YAML-NEXT:   - WVarName:        dst
 ; YAML-NEXT:   - String:          ' ('
-; YAML-NEXT:   - VarSize:         '1'
+; YAML-NEXT:   - WVarSize:        '1'
 ; YAML-NEXT:   - String:          ' bytes)'
 ; YAML-NEXT:   - String:          .
+; YAML-NEXT:   - String:          ' Inlined: '
+; YAML-NEXT:   - StoreInlined:     'false'
+; YAML-NEXT:   - String:          .
 ; YAML-NEXT:   - String:          ' Volatile: '
 ; YAML-NEXT:   - StoreVolatile:   'false'
 ; YAML-NEXT:   - String:          .
@@ -360,12 +405,15 @@ define void @known_call_with_size_alloca(i8* %src) {
 ; YAML-NEXT:   - String:          ' Memory operation size: '
 ; YAML-NEXT:   - StoreSize:       '1'
 ; YAML-NEXT:   - String:          ' bytes.'
-; YAML-NEXT:   - String:          "\nVariables: "
-; YAML-NEXT:   - VarName:         dst
+; YAML-NEXT:   - String:          "\n Written Variables: "
+; YAML-NEXT:   - WVarName:        dst
 ; YAML-NEXT:   - String:          ' ('
-; YAML-NEXT:   - VarSize:         '1'
+; YAML-NEXT:   - WVarSize:        '1'
 ; YAML-NEXT:   - String:          ' bytes)'
 ; YAML-NEXT:   - String:          .
+; YAML-NEXT:   - String:          ' Inlined: '
+; YAML-NEXT:   - StoreInlined:     'false'
+; YAML-NEXT:   - String:          .
 ; YAML-NEXT:   - String:          ' Volatile: '
 ; YAML-NEXT:   - StoreVolatile:   'false'
 ; YAML-NEXT:   - String:          .
@@ -388,10 +436,10 @@ define void @known_call_with_size_alloca(i8* %src) {
 ; YAML-NEXT:   - String:          ' Memory operation size: '
 ; YAML-NEXT:   - StoreSize:       '1'
 ; YAML-NEXT:   - String:          ' bytes.'
-; YAML-NEXT:   - String:          "\nVariables: "
-; YAML-NEXT:   - VarName:         dst
+; YAML-NEXT:   - String:          "\n Written Variables: "
+; YAML-NEXT:   - WVarName:        dst
 ; YAML-NEXT:   - String:          ' ('
-; YAML-NEXT:   - VarSize:         '1'
+; YAML-NEXT:   - WVarSize:        '1'
 ; YAML-NEXT:   - String:          ' bytes)'
 ; YAML-NEXT:   - String:          .
 ; YAML-NEXT: ...

diff  --git a/llvm/test/Transforms/Util/trivial-auto-var-init-store.ll b/llvm/test/Transforms/Util/trivial-auto-var-init-store.ll
index a80c43d18f0a4..abdaba5e2e67a 100644
--- a/llvm/test/Transforms/Util/trivial-auto-var-init-store.ll
+++ b/llvm/test/Transforms/Util/trivial-auto-var-init-store.ll
@@ -11,7 +11,8 @@ define void @store(i32* %dst) {
 ; YAML-NEXT: DebugLoc:
 ; YAML-NEXT: Function:        store
 ; YAML-NEXT: Args:
-; YAML-NEXT:   - String:          "Store inserted by -ftrivial-auto-var-init.\nStore size: "
+; YAML-NEXT:   - String:          Store inserted by -ftrivial-auto-var-init.
+; YAML-NEXT:   - String:          "\nStore size: "
 ; YAML-NEXT:   - StoreSize:       '4'
 ; YAML-NEXT:   - String:          ' bytes.'
 ; YAML-NEXT:   - String:          ' Volatile: '
@@ -35,7 +36,8 @@ define void @volatile_store(i32* %dst) {
 ; YAML-NEXT: DebugLoc:
 ; YAML-NEXT: Function:        volatile_store
 ; YAML-NEXT: Args:
-; YAML-NEXT:   - String:          "Store inserted by -ftrivial-auto-var-init.\nStore size: "
+; YAML-NEXT:   - String:          Store inserted by -ftrivial-auto-var-init.
+; YAML-NEXT:   - String:          "\nStore size: "
 ; YAML-NEXT:   - StoreSize:       '4'
 ; YAML-NEXT:   - String:          ' bytes.'
 ; YAML-NEXT:   - String:          ' Volatile: '
@@ -59,7 +61,8 @@ define void @atomic_store(i32* %dst) {
 ; YAML-NEXT: DebugLoc:
 ; YAML-NEXT: Function:        atomic_store
 ; YAML-NEXT: Args:
-; YAML-NEXT:   - String:          "Store inserted by -ftrivial-auto-var-init.\nStore size: "
+; YAML-NEXT:   - String:          Store inserted by -ftrivial-auto-var-init.
+; YAML-NEXT:   - String:          "\nStore size: "
 ; YAML-NEXT:   - StoreSize:       '4'
 ; YAML-NEXT:   - String:          ' bytes.'
 ; YAML-NEXT:   - String:          ' Atomic: '
@@ -84,13 +87,14 @@ define void @store_alloca() {
 ; YAML-NEXT: DebugLoc:
 ; YAML-NEXT: Function:        store_alloca
 ; YAML-NEXT: Args:
-; YAML-NEXT:   - String:          "Store inserted by -ftrivial-auto-var-init.\nStore size: "
+; YAML-NEXT:   - String:          Store inserted by -ftrivial-auto-var-init.
+; YAML-NEXT:   - String:          "\nStore size: "
 ; YAML-NEXT:   - StoreSize:       '4'
 ; YAML-NEXT:   - String:          ' bytes.'
-; YAML-NEXT:   - String:          "\nVariables: "
-; YAML-NEXT:   - VarName:         dst
+; YAML-NEXT:   - String:          "\n Written Variables: "
+; YAML-NEXT:   - WVarName:        dst
 ; YAML-NEXT:   - String:          ' ('
-; YAML-NEXT:   - VarSize:         '4'
+; YAML-NEXT:   - WVarSize:        '4'
 ; YAML-NEXT:   - String:          ' bytes)'
 ; YAML-NEXT:   - String:          .
 ; YAML-NEXT:   - String:          ' Volatile: '


        


More information about the llvm-commits mailing list