forked from OSchip/llvm-project
212 lines
6.7 KiB
C++
212 lines
6.7 KiB
C++
//===-- 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/DebugInfoMetadata.h"
|
|
#include "llvm/IR/Instructions.h"
|
|
#include "llvm/IR/IntrinsicInst.h"
|
|
#include "llvm/Transforms/Utils/Local.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 << ".";
|
|
}
|