diff --git a/llvm/include/llvm/Analysis/OptimizationRemarkEmitter.h b/llvm/include/llvm/Analysis/OptimizationRemarkEmitter.h --- a/llvm/include/llvm/Analysis/OptimizationRemarkEmitter.h +++ b/llvm/include/llvm/Analysis/OptimizationRemarkEmitter.h @@ -76,6 +76,8 @@ if (F->getContext().getLLVMRemarkStreamer() || F->getContext().getDiagHandlerPtr()->isAnyRemarkEnabled()) { auto R = RemarkBuilder(); + static_assert(std::is_base_of::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 rename from llvm/include/llvm/Transforms/Utils/AutoInitRemark.h rename to llvm/include/llvm/Transforms/Utils/MemoryOpRemark.h --- 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 @@ class CallInst; class DataLayout; +class DiagnosticInfoIROptimization; class Instruction; class IntrinsicInst; class Value; @@ -31,33 +32,51 @@ // 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 MemoryOpRemark can describe this instruction. + static bool describes(const Instruction *I); + + void describe(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 inspectStore(const StoreInst &SI); /// Emit a generic auto-init remark. - void inspectUnknown(Instruction &I); + void inspectUnknown(const Instruction &I); /// Emit a remark using information from known intrinsic calls. - void inspectIntrinsicCall(IntrinsicInst &II); + void inspectIntrinsicCall(const IntrinsicInst &II); /// Emit a remark using information from known function calls. - void inspectCall(CallInst &CI); + void inspectCall(const CallInst &CI); -private: /// Add callee information to a remark: whether it's known, the function name, /// etc. template void inspectCallee(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, + void inspectKnownLibCall(const CallInst &CI, LibFunc LF, OptimizationRemarkMissed &R); /// Add the memory operation size to a remark. void inspectSizeOperand(Value *V, OptimizationRemarkMissed &R); @@ -74,6 +93,20 @@ void inspectVariable(const Value *V, SmallVectorImpl &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 AutoInitRemark can describe the instruction. + static bool describes(const Instruction *I); + +protected: + virtual std::string explainSource(StringRef Type) override; + virtual StringRef remarkName(RemarkKind RK) override; +}; + } // namespace llvm #endif diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp --- 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 #include #include @@ -97,6 +98,7 @@ 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 @@ AU.addRequired(); if (OptLevel != CodeGenOpt::None) AU.addRequired(); + AU.addRequired(); + AU.addPreserved(); getSelectionDAGFallbackAnalysisUsage(AU); MachineFunctionPass::getAnalysisUsage(AU); } @@ -1815,6 +1819,14 @@ bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID, MachineIRBuilder &MIRBuilder) { + if (auto *MI = dyn_cast(&CI)) { + if (MemoryOpRemark::describes(MI)) { + const Function &F = *MI->getParent()->getParent(); + auto &TLI = getAnalysis().getTLI(F); + MemoryOpRemark R(*ORE, "memsize", *DL, TLI); + R.describe(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 +2256,15 @@ Args.push_back(getOrCreateVRegs(*Arg)); } + if (auto *CI = dyn_cast(&CB)) { + if (MemoryOpRemark::describes(CI)) { + const Function &F = *CI->getParent()->getParent(); + auto &TLI = getAnalysis().getTLI(F); + MemoryOpRemark R(*ORE, "memsize", *DL, TLI); + R.describe(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 --- 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 @@ const TargetLibraryInfo &TLI) { // For every auto-init annotation generate a separate remark. for (Instruction *I : Instructions) { - if (!I->hasMetadata(LLVMContext::MD_annotation)) + if (!AutoInitRemark::describes(I)) continue; - for (const MDOperand &Op : - I->getMetadata(LLVMContext::MD_annotation)->operands()) { - if (cast(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(I)) { - Remark.inspectStore(*SI); - continue; - } - - // For intrinsics: - // * user-friendly name - // * size - if (auto *II = dyn_cast(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(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.describe(I); } } diff --git a/llvm/lib/Transforms/Utils/CMakeLists.txt b/llvm/lib/Transforms/Utils/CMakeLists.txt --- a/llvm/lib/Transforms/Utils/CMakeLists.txt +++ b/llvm/lib/Transforms/Utils/CMakeLists.txt @@ -3,7 +3,6 @@ AMDGPUEmitPrintf.cpp ASanStackFrameLayout.cpp AssumeBundleBuilder.cpp - AutoInitRemark.cpp BasicBlockUtils.cpp BreakCriticalEdges.cpp BuildLibCalls.cpp @@ -48,6 +47,7 @@ LowerMemIntrinsics.cpp LowerSwitch.cpp MatrixUtils.cpp + MemoryOpRemark.cpp Mem2Reg.cpp MetaRenamer.cpp ModuleUtils.cpp diff --git a/llvm/lib/Transforms/Utils/AutoInitRemark.cpp b/llvm/lib/Transforms/Utils/MemoryOpRemark.cpp rename from llvm/lib/Transforms/Utils/AutoInitRemark.cpp rename to llvm/lib/Transforms/Utils/MemoryOpRemark.cpp --- a/llvm/lib/Transforms/Utils/AutoInitRemark.cpp +++ b/llvm/lib/Transforms/Utils/MemoryOpRemark.cpp @@ -1,4 +1,4 @@ -//===-- AutoInitRemark.cpp - Auto-init remark analysis---------------------===// +//===-- 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. @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Transforms/Utils/AutoInitRemark.h" +#include "llvm/Transforms/Utils/MemoryOpRemark.h" #include "llvm/Analysis/OptimizationRemarkEmitter.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/DebugInfo.h" @@ -20,17 +20,109 @@ using namespace llvm; using namespace llvm::ore; -static void volatileOrAtomicWithExtraArgs(bool Volatile, bool Atomic, - OptimizationRemarkMissed &R) { +MemoryOpRemark::~MemoryOpRemark() = default; + +void MemoryOpRemark::describe(const Instruction *I) { + // For some of them, we can provide more information: + + // For stores: + // * size + // * volatile / atomic + if (auto *SI = dyn_cast(I)) { + inspectStore(*SI); + return; + } + + // For intrinsics: + // * user-friendly name + // * size + if (auto *II = dyn_cast(I)) { + inspectIntrinsicCall(*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(I)) { + inspectCall(*CI); + return; + } + + inspectUnknown(*I); +} + +bool MemoryOpRemark::describes(const Instruction *I) { + if (isa(I)) + return true; + + if (auto *II = dyn_cast(I)) { + auto ID = II->getIntrinsicID(); + 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(I)) { + auto *CF = CI->getCalledFunction(); + if (!CF) + return false; + + if (!CF->hasName()) + return false; + + return llvm::StringSwitch(CF->getName()) + .Cases("__memcpy_chk", "memcpy", true) + .Cases("__mempcpy_chk", "mempcpy", true) + .Cases("__memset_chk", "memset", true) + .Cases("__memmove_chk", "memmove", true) + .Default(false); + } + + return false; +} + +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"; + } +} + +static void inlineVolatileOrAtomicWithExtraArgs(bool *Inline, bool Volatile, bool Atomic, + OptimizationRemarkMissed &R) { + if (Inline && *Inline) + R << " Inline: " << NV("StoreInline", true) << "."; 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) + // 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 << " Inline: " << NV("StoreInline", false) << "."; if (!Volatile) R << " Volatile: " << NV("StoreVolatile", false) << "."; if (!Atomic) @@ -43,29 +135,36 @@ return *SizeInBits / 8; } -void AutoInitRemark::inspectStore(StoreInst &SI) { +void MemoryOpRemark::inspectStore(const 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: " + OptimizationRemarkMissed R(RemarkPass.data(), remarkName(RK_Store), &SI); + R << explainSource("Store") + << "\nStore size: " << NV("StoreSize", Size) << " bytes."; inspectDst(SI.getOperand(1), R); - volatileOrAtomicWithExtraArgs(Volatile, Atomic, R); + inlineVolatileOrAtomicWithExtraArgs(nullptr, 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 MemoryOpRemark::inspectUnknown(const Instruction &I) { + OptimizationRemarkMissed R(RemarkPass.data(), + remarkName(RK_Unknown), &I); + R << explainSource("Initialization"); + ORE.emit(R); } -void AutoInitRemark::inspectIntrinsicCall(IntrinsicInst &II) { +void MemoryOpRemark::inspectIntrinsicCall(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; @@ -91,7 +190,7 @@ return inspectUnknown(II); } - OptimizationRemarkMissed R(RemarkPass.data(), "AutoInitIntrinsic", &II); + OptimizationRemarkMissed R(RemarkPass.data(), remarkName(RK_IntrinsicCall), &II); inspectCallee(StringRef(CallTo), /*KnownLibCall=*/true, R); inspectSizeOperand(II.getOperand(2), R); @@ -99,33 +198,33 @@ // 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); + inlineVolatileOrAtomicWithExtraArgs(&Inline, Volatile, Atomic, R); ORE.emit(R); } -void AutoInitRemark::inspectCall(CallInst &CI) { +void MemoryOpRemark::inspectCall(const 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); + OptimizationRemarkMissed R(RemarkPass.data(), remarkName(RK_Call), &CI); inspectCallee(F, KnownLibCall, R); inspectKnownLibCall(CI, LF, R); ORE.emit(R); } template -void AutoInitRemark::inspectCallee(FTy F, bool KnownLibCall, +void MemoryOpRemark::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."; + R << NV("Callee", F) << explainSource(""); } -void AutoInitRemark::inspectKnownLibCall(CallInst &CI, LibFunc LF, +void MemoryOpRemark::inspectKnownLibCall(const CallInst &CI, LibFunc LF, OptimizationRemarkMissed &R) { switch (LF) { default: @@ -137,14 +236,14 @@ } } -void AutoInitRemark::inspectSizeOperand(Value *V, OptimizationRemarkMissed &R) { +void MemoryOpRemark::inspectSizeOperand(Value *V, OptimizationRemarkMissed &R) { if (auto *Len = dyn_cast(V)) { uint64_t Size = Len->getZExtValue(); R << " Memory operation size: " << NV("StoreSize", Size) << " bytes."; } } -void AutoInitRemark::inspectVariable(const Value *V, +void MemoryOpRemark::inspectVariable(const Value *V, SmallVectorImpl &Result) { // If we find some information in the debug info, take that. bool FoundDI = false; @@ -182,7 +281,7 @@ Result.push_back(std::move(Var)); } -void AutoInitRemark::inspectDst(Value *Dst, OptimizationRemarkMissed &R) { +void MemoryOpRemark::inspectDst(Value *Dst, OptimizationRemarkMissed &R) { // Find if Dst is a known variable we can give more information on. SmallVector Objects; getUnderlyingObjects(Dst, Objects); @@ -208,3 +307,27 @@ } R << "."; } + +bool AutoInitRemark::describes(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(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"; + } +} diff --git a/llvm/test/CodeGen/AArch64/memsize-remarks.ll b/llvm/test/CodeGen/AArch64/memsize-remarks.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/memsize-remarks.ll @@ -0,0 +1,205 @@ +; RUN: llc %s -pass-remarks-missed=memsize -global-isel -o /dev/null 2>&1 | FileCheck %s --check-prefix=GISEL --implicit-check-not=GISEL + +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.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) argmemonly nounwind willreturn + +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: :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: :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: :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: :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: :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 +} + +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 +} + +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 --- 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 @@ ; YAML-NEXT: - String: 'Call to ' ; YAML-NEXT: - Callee: memset ; YAML-NEXT: - String: ' inserted by -ftrivial-auto-var-init.' +; YAML-NEXT: - String: ' Inline: ' +; YAML-NEXT: - StoreInline: 'false' +; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Volatile: ' ; YAML-NEXT: - StoreVolatile: 'false' ; YAML-NEXT: - String: . @@ -31,6 +34,9 @@ ; YAML-NEXT: - String: 'Call to ' ; YAML-NEXT: - Callee: memcpy ; YAML-NEXT: - String: ' inserted by -ftrivial-auto-var-init.' +; YAML-NEXT: - String: ' Inline: ' +; YAML-NEXT: - StoreInline: 'false' +; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Volatile: ' ; YAML-NEXT: - StoreVolatile: 'false' ; YAML-NEXT: - String: . @@ -49,6 +55,9 @@ ; YAML-NEXT: - String: 'Call to ' ; YAML-NEXT: - Callee: memmove ; YAML-NEXT: - String: ' inserted by -ftrivial-auto-var-init.' +; YAML-NEXT: - String: ' Inline: ' +; YAML-NEXT: - StoreInline: 'false' +; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Volatile: ' ; YAML-NEXT: - StoreVolatile: 'false' ; YAML-NEXT: - String: . @@ -99,6 +108,9 @@ ; YAML-NEXT: - String: ' Memory operation size: ' ; YAML-NEXT: - StoreSize: '32' ; YAML-NEXT: - String: ' bytes.' +; YAML-NEXT: - String: ' Inline: ' +; YAML-NEXT: - StoreInline: 'false' +; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Volatile: ' ; YAML-NEXT: - StoreVolatile: 'false' ; YAML-NEXT: - String: . @@ -120,6 +132,9 @@ ; YAML-NEXT: - String: ' Memory operation size: ' ; YAML-NEXT: - StoreSize: '32' ; YAML-NEXT: - String: ' bytes.' +; YAML-NEXT: - String: ' Inline: ' +; YAML-NEXT: - StoreInline: 'false' +; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Volatile: ' ; YAML-NEXT: - StoreVolatile: 'false' ; YAML-NEXT: - String: . @@ -141,6 +156,9 @@ ; YAML-NEXT: - String: ' Memory operation size: ' ; YAML-NEXT: - StoreSize: '32' ; YAML-NEXT: - String: ' bytes.' +; YAML-NEXT: - String: ' Inline: ' +; YAML-NEXT: - StoreInline: 'false' +; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Volatile: ' ; YAML-NEXT: - StoreVolatile: 'false' ; YAML-NEXT: - String: . @@ -183,6 +201,9 @@ ; YAML-NEXT: - String: ' Volatile: ' ; YAML-NEXT: - StoreVolatile: 'true' ; YAML-NEXT: - String: . +; YAML-NEXT: - String: ' Inline: ' +; YAML-NEXT: - StoreInline: 'false' +; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Atomic: ' ; YAML-NEXT: - StoreAtomic: 'false' ; YAML-NEXT: - String: . @@ -201,6 +222,9 @@ ; YAML-NEXT: - String: ' Volatile: ' ; YAML-NEXT: - StoreVolatile: 'true' ; YAML-NEXT: - String: . +; YAML-NEXT: - String: ' Inline: ' +; YAML-NEXT: - StoreInline: 'false' +; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Atomic: ' ; YAML-NEXT: - StoreAtomic: 'false' ; YAML-NEXT: - String: . @@ -219,6 +243,9 @@ ; YAML-NEXT: - String: ' Volatile: ' ; YAML-NEXT: - StoreVolatile: 'true' ; YAML-NEXT: - String: . +; YAML-NEXT: - String: ' Inline: ' +; YAML-NEXT: - StoreInline: 'false' +; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Atomic: ' ; YAML-NEXT: - StoreAtomic: 'false' ; YAML-NEXT: - String: . @@ -242,6 +269,9 @@ ; YAML-NEXT: - String: ' Atomic: ' ; YAML-NEXT: - StoreAtomic: 'true' ; YAML-NEXT: - String: . +; YAML-NEXT: - String: ' Inline: ' +; YAML-NEXT: - StoreInline: 'false' +; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Volatile: ' ; YAML-NEXT: - StoreVolatile: 'false' ; YAML-NEXT: - String: . @@ -260,6 +290,9 @@ ; YAML-NEXT: - String: ' Atomic: ' ; YAML-NEXT: - StoreAtomic: 'true' ; YAML-NEXT: - String: . +; YAML-NEXT: - String: ' Inline: ' +; YAML-NEXT: - StoreInline: 'false' +; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Volatile: ' ; YAML-NEXT: - StoreVolatile: 'false' ; YAML-NEXT: - String: . @@ -278,6 +311,9 @@ ; YAML-NEXT: - String: ' Atomic: ' ; YAML-NEXT: - StoreAtomic: 'true' ; YAML-NEXT: - String: . +; YAML-NEXT: - String: ' Inline: ' +; YAML-NEXT: - StoreInline: 'false' +; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Volatile: ' ; YAML-NEXT: - StoreVolatile: 'false' ; YAML-NEXT: - String: . @@ -309,6 +345,9 @@ ; YAML-NEXT: - VarSize: '1' ; YAML-NEXT: - String: ' bytes)' ; YAML-NEXT: - String: . +; YAML-NEXT: - String: ' Inline: ' +; YAML-NEXT: - StoreInline: 'false' +; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Volatile: ' ; YAML-NEXT: - StoreVolatile: 'false' ; YAML-NEXT: - String: . @@ -338,6 +377,9 @@ ; YAML-NEXT: - VarSize: '1' ; YAML-NEXT: - String: ' bytes)' ; YAML-NEXT: - String: . +; YAML-NEXT: - String: ' Inline: ' +; YAML-NEXT: - StoreInline: 'false' +; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Volatile: ' ; YAML-NEXT: - StoreVolatile: 'false' ; YAML-NEXT: - String: . @@ -366,6 +408,9 @@ ; YAML-NEXT: - VarSize: '1' ; YAML-NEXT: - String: ' bytes)' ; YAML-NEXT: - String: . +; YAML-NEXT: - String: ' Inline: ' +; YAML-NEXT: - StoreInline: 'false' +; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Volatile: ' ; YAML-NEXT: - StoreVolatile: 'false' ; YAML-NEXT: - String: . diff --git a/llvm/test/Transforms/Util/trivial-auto-var-init-store.ll b/llvm/test/Transforms/Util/trivial-auto-var-init-store.ll --- 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 @@ ; 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 @@ ; 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 @@ ; 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,7 +87,8 @@ ; 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: "