[Remarks] Add analysis remarks for memset/memcpy/memmove lengths
Differential revision: https://reviews.llvm.org/D102452
This commit is contained in:
parent
65d0264ba2
commit
4bf69fb52b
|
@ -76,6 +76,9 @@ public:
|
|||
if (F->getContext().getLLVMRemarkStreamer() ||
|
||||
F->getContext().getDiagHandlerPtr()->isAnyRemarkEnabled()) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {}
|
||||
|
||||
/// Emit a remark using information from the store's destination, size, etc.
|
||||
void inspectStore(StoreInst &SI);
|
||||
/// Emit a generic auto-init remark.
|
||||
void inspectUnknown(Instruction &I);
|
||||
/// Emit a remark using information from known intrinsic calls.
|
||||
void inspectIntrinsicCall(IntrinsicInst &II);
|
||||
/// Emit a remark using information from known function calls.
|
||||
void inspectCall(CallInst &CI);
|
||||
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 visitStore(const StoreInst &SI);
|
||||
/// Emit a generic auto-init remark.
|
||||
void visitUnknown(const Instruction &I);
|
||||
/// Emit a remark using information from known intrinsic calls.
|
||||
void visitIntrinsicCall(const IntrinsicInst &II);
|
||||
/// Emit a remark using information from known function calls.
|
||||
void visitCall(const CallInst &CI);
|
||||
|
||||
/// 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 @@ private:
|
|||
/// 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
|
|
@ -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,14 @@ bool IRTranslator::translateConstrainedFPIntrinsic(
|
|||
|
||||
bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID,
|
||||
MachineIRBuilder &MIRBuilder) {
|
||||
if (auto *MI = dyn_cast<AnyMemIntrinsic>(&CI)) {
|
||||
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 +2256,15 @@ bool IRTranslator::translateCallBase(const CallBase &CB,
|
|||
Args.push_back(getOrCreateVRegs(*Arg));
|
||||
}
|
||||
|
||||
if (auto *CI = dyn_cast<CallInst>(&CB)) {
|
||||
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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<const Value *, 2> Objects;
|
||||
getUnderlyingObjects(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 << ".";
|
||||
}
|
|
@ -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
|
||||
|
|
381
llvm/lib/Transforms/Utils/MemoryOpRemark.cpp
Normal file
381
llvm/lib/Transforms/Utils/MemoryOpRemark.cpp
Normal file
|
@ -0,0 +1,381 @@
|
|||
//===-- 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";
|
||||
}
|
||||
}
|
||||
|
||||
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<const Value *, 2> Objects;
|
||||
getUnderlyingObjects(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 ? "\nRead Variables: " : "\nWritten 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";
|
||||
}
|
||||
}
|
373
llvm/test/CodeGen/AArch64/memsize-remarks.ll
Normal file
373
llvm/test/CodeGen/AArch64/memsize-remarks.ll
Normal file
|
@ -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: "\nWritten 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: "\nRead Variables: "
|
||||
; YAML-NEXT: - RVarName: '<unknown>'
|
||||
; YAML-NEXT: - String: ' ('
|
||||
; YAML-NEXT: - RVarSize: '314'
|
||||
; YAML-NEXT: - String: ' bytes)'
|
||||
; YAML-NEXT: - String: .
|
||||
; YAML-NEXT: - String: "\nWritten 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: "\nRead Variables: "
|
||||
; YAML-NEXT: - RVarName: '<unknown>'
|
||||
; YAML-NEXT: - String: ' ('
|
||||
; YAML-NEXT: - RVarSize: '314'
|
||||
; YAML-NEXT: - String: ' bytes)'
|
||||
; YAML-NEXT: - String: .
|
||||
; YAML-NEXT: - String: "\nWritten 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: "\nWritten 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: "\nRead Variables: "
|
||||
; YAML-NEXT: - RVarName: '<unknown>'
|
||||
; YAML-NEXT: - String: ' ('
|
||||
; YAML-NEXT: - RVarSize: '314'
|
||||
; YAML-NEXT: - String: ' bytes)'
|
||||
; YAML-NEXT: - String: .
|
||||
; YAML-NEXT: - String: "\nWritten 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)
|
|
@ -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: "\nWritten 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: "\nWritten 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: "\nWritten 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: "\nWritten 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: ...
|
||||
|
|
|
@ -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: "\nWritten 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: '
|
||||
|
|
Loading…
Reference in New Issue
Block a user