LLVM  13.0.0git
AutoInitRemark.cpp
Go to the documentation of this file.
1 //===-- AutoInitRemark.cpp - Auto-init remark analysis---------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Implementation of the analysis for the "auto-init" remark.
10 //
11 //===----------------------------------------------------------------------===//
12 
17 #include "llvm/IR/Instructions.h"
18 #include "llvm/IR/IntrinsicInst.h"
20 
21 using namespace llvm;
22 using namespace llvm::ore;
23 
24 static void volatileOrAtomicWithExtraArgs(bool Volatile, bool Atomic,
26  if (Volatile)
27  R << " Volatile: " << NV("StoreVolatile", true) << ".";
28  if (Atomic)
29  R << " Atomic: " << NV("StoreAtomic", true) << ".";
30  // Emit StoreVolatile: false and StoreAtomic: false under ExtraArgs. This
31  // won't show them in the remark message but will end up in the serialized
32  // remarks.
33  if (!Volatile || !Atomic)
34  R << setExtraArgs();
35  if (!Volatile)
36  R << " Volatile: " << NV("StoreVolatile", false) << ".";
37  if (!Atomic)
38  R << " Atomic: " << NV("StoreAtomic", false) << ".";
39 }
40 
42  if (!SizeInBits || *SizeInBits % 8 != 0)
43  return None;
44  return *SizeInBits / 8;
45 }
46 
48  bool Volatile = SI.isVolatile();
49  bool Atomic = SI.isAtomic();
50  int64_t Size = DL.getTypeStoreSize(SI.getOperand(0)->getType());
51 
52  OptimizationRemarkMissed R(RemarkPass.data(), "AutoInitStore", &SI);
53  R << "Store inserted by -ftrivial-auto-var-init.\nStore size: "
54  << NV("StoreSize", Size) << " bytes.";
55  inspectDst(SI.getOperand(1), R);
56  volatileOrAtomicWithExtraArgs(Volatile, Atomic, R);
57  ORE.emit(R);
58 }
59 
61  ORE.emit(OptimizationRemarkMissed(RemarkPass.data(),
62  "AutoInitUnknownInstruction", &I)
63  << "Initialization inserted by -ftrivial-auto-var-init.");
64 }
65 
67  SmallString<32> CallTo;
68  bool Atomic = false;
69  switch (II.getIntrinsicID()) {
70  case Intrinsic::memcpy:
71  CallTo = "memcpy";
72  break;
73  case Intrinsic::memmove:
74  CallTo = "memmove";
75  break;
76  case Intrinsic::memset:
77  CallTo = "memset";
78  break;
79  case Intrinsic::memcpy_element_unordered_atomic:
80  CallTo = "memcpy";
81  Atomic = true;
82  break;
83  case Intrinsic::memmove_element_unordered_atomic:
84  CallTo = "memmove";
85  Atomic = true;
86  break;
87  case Intrinsic::memset_element_unordered_atomic:
88  CallTo = "memset";
89  Atomic = true;
90  break;
91  default:
92  return inspectUnknown(II);
93  }
94 
95  OptimizationRemarkMissed R(RemarkPass.data(), "AutoInitIntrinsic", &II);
96  inspectCallee(StringRef(CallTo), /*KnownLibCall=*/true, R);
97  inspectSizeOperand(II.getOperand(2), R);
98 
99  auto *CIVolatile = dyn_cast<ConstantInt>(II.getOperand(3));
100  // No such thing as a memory intrinsic that is both atomic and volatile.
101  bool Volatile = !Atomic && CIVolatile && CIVolatile->getZExtValue();
102  inspectDst(II.getOperand(0), R);
103  volatileOrAtomicWithExtraArgs(Volatile, Atomic, R);
104  ORE.emit(R);
105 }
106 
108  Function *F = CI.getCalledFunction();
109  if (!F)
110  return inspectUnknown(CI);
111 
112  LibFunc LF;
113  bool KnownLibCall = TLI.getLibFunc(*F, LF) && TLI.has(LF);
114  OptimizationRemarkMissed R(RemarkPass.data(), "AutoInitCall", &CI);
115  inspectCallee(F, KnownLibCall, R);
116  inspectKnownLibCall(CI, LF, R);
117  ORE.emit(R);
118 }
119 
120 template <typename FTy>
121 void AutoInitRemark::inspectCallee(FTy F, bool KnownLibCall,
123  R << "Call to ";
124  if (!KnownLibCall)
125  R << NV("UnknownLibCall", "unknown") << " function ";
126  R << NV("Callee", F) << " inserted by -ftrivial-auto-var-init.";
127 }
128 
129 void AutoInitRemark::inspectKnownLibCall(CallInst &CI, LibFunc LF,
131  switch (LF) {
132  default:
133  return;
134  case LibFunc_bzero:
135  inspectSizeOperand(CI.getOperand(1), R);
136  inspectDst(CI.getOperand(0), R);
137  break;
138  }
139 }
140 
141 void AutoInitRemark::inspectSizeOperand(Value *V, OptimizationRemarkMissed &R) {
142  if (auto *Len = dyn_cast<ConstantInt>(V)) {
143  uint64_t Size = Len->getZExtValue();
144  R << " Memory operation size: " << NV("StoreSize", Size) << " bytes.";
145  }
146 }
147 
148 void AutoInitRemark::inspectVariable(const Value *V,
150  // If we find some information in the debug info, take that.
151  bool FoundDI = false;
152  // Try to get an llvm.dbg.declare, which has a DILocalVariable giving us the
153  // real debug info name and size of the variable.
154  for (const DbgVariableIntrinsic *DVI :
155  FindDbgAddrUses(const_cast<Value *>(V))) {
156  if (DILocalVariable *DILV = DVI->getVariable()) {
157  Optional<uint64_t> DISize = getSizeInBytes(DILV->getSizeInBits());
158  VariableInfo Var{DILV->getName(), DISize};
159  if (!Var.isEmpty()) {
160  Result.push_back(std::move(Var));
161  FoundDI = true;
162  }
163  }
164  }
165  if (FoundDI) {
166  assert(!Result.empty());
167  return;
168  }
169 
170  const auto *AI = dyn_cast<AllocaInst>(V);
171  if (!AI)
172  return;
173 
174  // If not, get it from the alloca.
175  Optional<StringRef> Name = AI->hasName()
176  ? Optional<StringRef>(AI->getName())
177  : Optional<StringRef>(None);
178  Optional<TypeSize> TySize = AI->getAllocationSizeInBits(DL);
180  TySize ? getSizeInBytes(TySize->getFixedSize()) : None;
181  VariableInfo Var{Name, Size};
182  if (!Var.isEmpty())
183  Result.push_back(std::move(Var));
184 }
185 
186 void AutoInitRemark::inspectDst(Value *Dst, OptimizationRemarkMissed &R) {
187  // Find if Dst is a known variable we can give more information on.
189  getUnderlyingObjects(Dst, Objects);
191  for (const Value *V : Objects)
192  inspectVariable(V, VIs);
193 
194  if (VIs.empty())
195  return;
196 
197  R << "\nVariables: ";
198  for (unsigned i = 0; i < VIs.size(); ++i) {
199  const VariableInfo &VI = VIs[i];
200  assert(!VI.isEmpty() && "No extra content to display.");
201  if (i != 0)
202  R << ", ";
203  if (VI.Name)
204  R << NV("VarName", *VI.Name);
205  else
206  R << NV("VarName", "<unknown>");
207  if (VI.Size)
208  R << " (" << NV("VarSize", *VI.Size) << " bytes)";
209  }
210  R << ".";
211 }
llvm::Check::Size
@ Size
Definition: FileCheck.h:73
i
i
Definition: README.txt:29
llvm::OptimizationRemarkMissed
Diagnostic information for missed-optimization remarks.
Definition: DiagnosticInfo.h:729
getSizeInBytes
static Optional< uint64_t > getSizeInBytes(Optional< uint64_t > SizeInBits)
Definition: AutoInitRemark.cpp:41
llvm
Definition: AllocatorList.h:23
AutoInitRemark.h
IntrinsicInst.h
DebugInfoMetadata.h
llvm::TypeSize::getFixedSize
ScalarTy getFixedSize() const
Definition: TypeSize.h:426
llvm::Function
Definition: Function.h:61
llvm::IntrinsicInst::getIntrinsicID
Intrinsic::ID getIntrinsicID() const
Return the intrinsic ID of this intrinsic.
Definition: IntrinsicInst.h:52
llvm::SmallVector
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1168
ValueTracking.h
Local.h
OptimizationRemarkEmitter.h
llvm::AutoInitRemark::inspectUnknown
void inspectUnknown(Instruction &I)
Emit a generic auto-init remark.
Definition: AutoInitRemark.cpp:60
llvm::Optional< uint64_t >
llvm::AutoInitRemark::inspectStore
void inspectStore(StoreInst &SI)
Emit a remark using information from the store's destination, size, etc.
Definition: AutoInitRemark.cpp:47
llvm::ore::NV
DiagnosticInfoOptimizationBase::Argument NV
Definition: OptimizationRemarkEmitter.h:128
llvm::FindDbgAddrUses
TinyPtrVector< DbgVariableIntrinsic * > FindDbgAddrUses(Value *V)
Finds all intrinsics declaring local variables as living in the memory that 'V' points to.
Definition: Local.cpp:1664
F
#define F(x, y, z)
Definition: MD5.cpp:56
llvm::RISCVFenceField::R
@ R
Definition: RISCVBaseInfo.h:129
llvm::DILocalVariable
Local variable.
Definition: DebugInfoMetadata.h:3041
llvm::LibFunc
LibFunc
Definition: TargetLibraryInfo.h:34
llvm::CallBase::getCalledFunction
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation.
Definition: InstrTypes.h:1396
SI
@ SI
Definition: SIInstrInfo.cpp:7342
llvm::ms_demangle::QualifierMangleMode::Result
@ Result
llvm::Instruction
Definition: Instruction.h:45
llvm::AutoInitRemark::inspectIntrinsicCall
void inspectIntrinsicCall(IntrinsicInst &II)
Emit a remark using information from known intrinsic calls.
Definition: AutoInitRemark.cpp:66
llvm::None
const NoneType None
Definition: None.h:23
llvm::SmallString< 32 >
llvm::DbgVariableIntrinsic
This is the common base class for debug info intrinsics for variables.
Definition: IntrinsicInst.h:148
llvm::StoreInst
An instruction for storing to memory.
Definition: Instructions.h:303
VI
@ VI
Definition: SIInstrInfo.cpp:7343
llvm::getUnderlyingObjects
void getUnderlyingObjects(const Value *V, SmallVectorImpl< const Value * > &Objects, LoopInfo *LI=nullptr, unsigned MaxLookup=6)
This method is similar to getUnderlyingObject except that it can look through phi and select instruct...
Definition: ValueTracking.cpp:4317
move
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
Definition: README.txt:546
I
#define I(x, y, z)
Definition: MD5.cpp:59
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
memcpy
<%struct.s * > cast struct s *S to sbyte *< sbyte * > sbyte uint cast struct s *agg result to sbyte *< sbyte * > sbyte uint cast struct s *memtmp to sbyte *< sbyte * > sbyte uint ret void llc ends up issuing two memcpy or custom lower memcpy(of small size) to be ldmia/stmia. I think option 2 is better but the current register allocator cannot allocate a chunk of registers at a time. A feasible temporary solution is to use specific physical registers at the lowering time for small(<
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:57
DL
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Definition: AArch64SLSHardening.cpp:76
llvm::GraphProgram::Name
Name
Definition: GraphWriter.h:52
llvm::ore::setExtraArgs
DiagnosticInfoOptimizationBase::setExtraArgs setExtraArgs
Definition: OptimizationRemarkEmitter.h:130
llvm::AutoInitRemark::inspectCall
void inspectCall(CallInst &CI)
Emit a remark using information from known function calls.
Definition: AutoInitRemark.cpp:107
llvm::IntrinsicInst
A wrapper class for inspecting calls to intrinsic functions.
Definition: IntrinsicInst.h:45
Instructions.h
volatileOrAtomicWithExtraArgs
static void volatileOrAtomicWithExtraArgs(bool Volatile, bool Atomic, OptimizationRemarkMissed &R)
Definition: AutoInitRemark.cpp:24
llvm::SmallVectorImpl
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: APFloat.h:43
llvm::CallInst
This class represents a function call, abstracting a target machine's calling convention.
Definition: Instructions.h:1450
llvm::ore
Add a small namespace to avoid name clashes with the classes used in the streaming interface.
Definition: OptimizationRemarkEmitter.h:127
llvm::User::getOperand
Value * getOperand(unsigned i) const
Definition: User.h:169
llvm::Value
LLVM Value Representation.
Definition: Value.h:75