MemoryOpRemark.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. //===-- MemoryOpRemark.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. #include "llvm/Transforms/Utils/MemoryOpRemark.h"
  13. #include "llvm/Analysis/OptimizationRemarkEmitter.h"
  14. #include "llvm/Analysis/ValueTracking.h"
  15. #include "llvm/IR/DebugInfo.h"
  16. #include "llvm/IR/Instructions.h"
  17. #include "llvm/IR/IntrinsicInst.h"
  18. using namespace llvm;
  19. using namespace llvm::ore;
  20. MemoryOpRemark::~MemoryOpRemark() = default;
  21. bool MemoryOpRemark::canHandle(const Instruction *I, const TargetLibraryInfo &TLI) {
  22. if (isa<StoreInst>(I))
  23. return true;
  24. if (auto *II = dyn_cast<IntrinsicInst>(I)) {
  25. switch (II->getIntrinsicID()) {
  26. case Intrinsic::memcpy_inline:
  27. case Intrinsic::memcpy:
  28. case Intrinsic::memmove:
  29. case Intrinsic::memset:
  30. case Intrinsic::memcpy_element_unordered_atomic:
  31. case Intrinsic::memmove_element_unordered_atomic:
  32. case Intrinsic::memset_element_unordered_atomic:
  33. return true;
  34. default:
  35. return false;
  36. }
  37. }
  38. if (auto *CI = dyn_cast<CallInst>(I)) {
  39. auto *CF = CI->getCalledFunction();
  40. if (!CF)
  41. return false;
  42. if (!CF->hasName())
  43. return false;
  44. LibFunc LF;
  45. bool KnownLibCall = TLI.getLibFunc(*CF, LF) && TLI.has(LF);
  46. if (!KnownLibCall)
  47. return false;
  48. switch (LF) {
  49. case LibFunc_memcpy_chk:
  50. case LibFunc_mempcpy_chk:
  51. case LibFunc_memset_chk:
  52. case LibFunc_memmove_chk:
  53. case LibFunc_memcpy:
  54. case LibFunc_mempcpy:
  55. case LibFunc_memset:
  56. case LibFunc_memmove:
  57. case LibFunc_bzero:
  58. case LibFunc_bcopy:
  59. return true;
  60. default:
  61. return false;
  62. }
  63. }
  64. return false;
  65. }
  66. void MemoryOpRemark::visit(const Instruction *I) {
  67. // For some of them, we can provide more information:
  68. // For stores:
  69. // * size
  70. // * volatile / atomic
  71. if (auto *SI = dyn_cast<StoreInst>(I)) {
  72. visitStore(*SI);
  73. return;
  74. }
  75. // For intrinsics:
  76. // * user-friendly name
  77. // * size
  78. if (auto *II = dyn_cast<IntrinsicInst>(I)) {
  79. visitIntrinsicCall(*II);
  80. return;
  81. }
  82. // For calls:
  83. // * known/unknown function (e.g. the compiler knows bzero, but it doesn't
  84. // know my_bzero)
  85. // * memory operation size
  86. if (auto *CI = dyn_cast<CallInst>(I)) {
  87. visitCall(*CI);
  88. return;
  89. }
  90. visitUnknown(*I);
  91. }
  92. std::string MemoryOpRemark::explainSource(StringRef Type) const {
  93. return (Type + ".").str();
  94. }
  95. StringRef MemoryOpRemark::remarkName(RemarkKind RK) const {
  96. switch (RK) {
  97. case RK_Store:
  98. return "MemoryOpStore";
  99. case RK_Unknown:
  100. return "MemoryOpUnknown";
  101. case RK_IntrinsicCall:
  102. return "MemoryOpIntrinsicCall";
  103. case RK_Call:
  104. return "MemoryOpCall";
  105. }
  106. llvm_unreachable("missing RemarkKind case");
  107. }
  108. static void inlineVolatileOrAtomicWithExtraArgs(bool *Inline, bool Volatile,
  109. bool Atomic,
  110. DiagnosticInfoIROptimization &R) {
  111. if (Inline && *Inline)
  112. R << " Inlined: " << NV("StoreInlined", true) << ".";
  113. if (Volatile)
  114. R << " Volatile: " << NV("StoreVolatile", true) << ".";
  115. if (Atomic)
  116. R << " Atomic: " << NV("StoreAtomic", true) << ".";
  117. // Emit the false cases under ExtraArgs. This won't show them in the remark
  118. // message but will end up in the serialized remarks.
  119. if ((Inline && !*Inline) || !Volatile || !Atomic)
  120. R << setExtraArgs();
  121. if (Inline && !*Inline)
  122. R << " Inlined: " << NV("StoreInlined", false) << ".";
  123. if (!Volatile)
  124. R << " Volatile: " << NV("StoreVolatile", false) << ".";
  125. if (!Atomic)
  126. R << " Atomic: " << NV("StoreAtomic", false) << ".";
  127. }
  128. static Optional<uint64_t> getSizeInBytes(Optional<uint64_t> SizeInBits) {
  129. if (!SizeInBits || *SizeInBits % 8 != 0)
  130. return None;
  131. return *SizeInBits / 8;
  132. }
  133. template<typename ...Ts>
  134. std::unique_ptr<DiagnosticInfoIROptimization>
  135. MemoryOpRemark::makeRemark(Ts... Args) {
  136. switch (diagnosticKind()) {
  137. case DK_OptimizationRemarkAnalysis:
  138. return std::make_unique<OptimizationRemarkAnalysis>(Args...);
  139. case DK_OptimizationRemarkMissed:
  140. return std::make_unique<OptimizationRemarkMissed>(Args...);
  141. default:
  142. llvm_unreachable("unexpected DiagnosticKind");
  143. }
  144. }
  145. void MemoryOpRemark::visitStore(const StoreInst &SI) {
  146. bool Volatile = SI.isVolatile();
  147. bool Atomic = SI.isAtomic();
  148. int64_t Size = DL.getTypeStoreSize(SI.getOperand(0)->getType());
  149. auto R = makeRemark(RemarkPass.data(), remarkName(RK_Store), &SI);
  150. *R << explainSource("Store") << "\nStore size: " << NV("StoreSize", Size)
  151. << " bytes.";
  152. visitPtr(SI.getOperand(1), /*IsRead=*/false, *R);
  153. inlineVolatileOrAtomicWithExtraArgs(nullptr, Volatile, Atomic, *R);
  154. ORE.emit(*R);
  155. }
  156. void MemoryOpRemark::visitUnknown(const Instruction &I) {
  157. auto R = makeRemark(RemarkPass.data(), remarkName(RK_Unknown), &I);
  158. *R << explainSource("Initialization");
  159. ORE.emit(*R);
  160. }
  161. void MemoryOpRemark::visitIntrinsicCall(const IntrinsicInst &II) {
  162. SmallString<32> CallTo;
  163. bool Atomic = false;
  164. bool Inline = false;
  165. switch (II.getIntrinsicID()) {
  166. case Intrinsic::memcpy_inline:
  167. CallTo = "memcpy";
  168. Inline = true;
  169. break;
  170. case Intrinsic::memcpy:
  171. CallTo = "memcpy";
  172. break;
  173. case Intrinsic::memmove:
  174. CallTo = "memmove";
  175. break;
  176. case Intrinsic::memset:
  177. CallTo = "memset";
  178. break;
  179. case Intrinsic::memcpy_element_unordered_atomic:
  180. CallTo = "memcpy";
  181. Atomic = true;
  182. break;
  183. case Intrinsic::memmove_element_unordered_atomic:
  184. CallTo = "memmove";
  185. Atomic = true;
  186. break;
  187. case Intrinsic::memset_element_unordered_atomic:
  188. CallTo = "memset";
  189. Atomic = true;
  190. break;
  191. default:
  192. return visitUnknown(II);
  193. }
  194. auto R = makeRemark(RemarkPass.data(), remarkName(RK_IntrinsicCall), &II);
  195. visitCallee(CallTo.str(), /*KnownLibCall=*/true, *R);
  196. visitSizeOperand(II.getOperand(2), *R);
  197. auto *CIVolatile = dyn_cast<ConstantInt>(II.getOperand(3));
  198. // No such thing as a memory intrinsic that is both atomic and volatile.
  199. bool Volatile = !Atomic && CIVolatile && CIVolatile->getZExtValue();
  200. switch (II.getIntrinsicID()) {
  201. case Intrinsic::memcpy_inline:
  202. case Intrinsic::memcpy:
  203. case Intrinsic::memmove:
  204. case Intrinsic::memcpy_element_unordered_atomic:
  205. visitPtr(II.getOperand(1), /*IsRead=*/true, *R);
  206. visitPtr(II.getOperand(0), /*IsRead=*/false, *R);
  207. break;
  208. case Intrinsic::memset:
  209. case Intrinsic::memset_element_unordered_atomic:
  210. visitPtr(II.getOperand(0), /*IsRead=*/false, *R);
  211. break;
  212. }
  213. inlineVolatileOrAtomicWithExtraArgs(&Inline, Volatile, Atomic, *R);
  214. ORE.emit(*R);
  215. }
  216. void MemoryOpRemark::visitCall(const CallInst &CI) {
  217. Function *F = CI.getCalledFunction();
  218. if (!F)
  219. return visitUnknown(CI);
  220. LibFunc LF;
  221. bool KnownLibCall = TLI.getLibFunc(*F, LF) && TLI.has(LF);
  222. auto R = makeRemark(RemarkPass.data(), remarkName(RK_Call), &CI);
  223. visitCallee(F, KnownLibCall, *R);
  224. visitKnownLibCall(CI, LF, *R);
  225. ORE.emit(*R);
  226. }
  227. template <typename FTy>
  228. void MemoryOpRemark::visitCallee(FTy F, bool KnownLibCall,
  229. DiagnosticInfoIROptimization &R) {
  230. R << "Call to ";
  231. if (!KnownLibCall)
  232. R << NV("UnknownLibCall", "unknown") << " function ";
  233. R << NV("Callee", F) << explainSource("");
  234. }
  235. void MemoryOpRemark::visitKnownLibCall(const CallInst &CI, LibFunc LF,
  236. DiagnosticInfoIROptimization &R) {
  237. switch (LF) {
  238. default:
  239. return;
  240. case LibFunc_memset_chk:
  241. case LibFunc_memset:
  242. visitSizeOperand(CI.getOperand(2), R);
  243. visitPtr(CI.getOperand(0), /*IsRead=*/false, R);
  244. break;
  245. case LibFunc_bzero:
  246. visitSizeOperand(CI.getOperand(1), R);
  247. visitPtr(CI.getOperand(0), /*IsRead=*/false, R);
  248. break;
  249. case LibFunc_memcpy_chk:
  250. case LibFunc_mempcpy_chk:
  251. case LibFunc_memmove_chk:
  252. case LibFunc_memcpy:
  253. case LibFunc_mempcpy:
  254. case LibFunc_memmove:
  255. case LibFunc_bcopy:
  256. visitSizeOperand(CI.getOperand(2), R);
  257. visitPtr(CI.getOperand(1), /*IsRead=*/true, R);
  258. visitPtr(CI.getOperand(0), /*IsRead=*/false, R);
  259. break;
  260. }
  261. }
  262. void MemoryOpRemark::visitSizeOperand(Value *V, DiagnosticInfoIROptimization &R) {
  263. if (auto *Len = dyn_cast<ConstantInt>(V)) {
  264. uint64_t Size = Len->getZExtValue();
  265. R << " Memory operation size: " << NV("StoreSize", Size) << " bytes.";
  266. }
  267. }
  268. static Optional<StringRef> nameOrNone(const Value *V) {
  269. if (V->hasName())
  270. return V->getName();
  271. return None;
  272. }
  273. void MemoryOpRemark::visitVariable(const Value *V,
  274. SmallVectorImpl<VariableInfo> &Result) {
  275. if (auto *GV = dyn_cast<GlobalVariable>(V)) {
  276. auto *Ty = GV->getValueType();
  277. uint64_t Size = DL.getTypeSizeInBits(Ty).getFixedSize();
  278. VariableInfo Var{nameOrNone(GV), Size};
  279. if (!Var.isEmpty())
  280. Result.push_back(std::move(Var));
  281. return;
  282. }
  283. // If we find some information in the debug info, take that.
  284. bool FoundDI = false;
  285. // Try to get an llvm.dbg.declare, which has a DILocalVariable giving us the
  286. // real debug info name and size of the variable.
  287. for (const DbgVariableIntrinsic *DVI :
  288. FindDbgAddrUses(const_cast<Value *>(V))) {
  289. if (DILocalVariable *DILV = DVI->getVariable()) {
  290. Optional<uint64_t> DISize = getSizeInBytes(DILV->getSizeInBits());
  291. VariableInfo Var{DILV->getName(), DISize};
  292. if (!Var.isEmpty()) {
  293. Result.push_back(std::move(Var));
  294. FoundDI = true;
  295. }
  296. }
  297. }
  298. if (FoundDI) {
  299. assert(!Result.empty());
  300. return;
  301. }
  302. const auto *AI = dyn_cast<AllocaInst>(V);
  303. if (!AI)
  304. return;
  305. // If not, get it from the alloca.
  306. Optional<TypeSize> TySize = AI->getAllocationSizeInBits(DL);
  307. Optional<uint64_t> Size =
  308. TySize ? getSizeInBytes(TySize->getFixedSize()) : None;
  309. VariableInfo Var{nameOrNone(AI), Size};
  310. if (!Var.isEmpty())
  311. Result.push_back(std::move(Var));
  312. }
  313. void MemoryOpRemark::visitPtr(Value *Ptr, bool IsRead, DiagnosticInfoIROptimization &R) {
  314. // Find if Ptr is a known variable we can give more information on.
  315. SmallVector<Value *, 2> Objects;
  316. getUnderlyingObjectsForCodeGen(Ptr, Objects);
  317. SmallVector<VariableInfo, 2> VIs;
  318. for (const Value *V : Objects)
  319. visitVariable(V, VIs);
  320. if (VIs.empty()) {
  321. bool CanBeNull;
  322. bool CanBeFreed;
  323. uint64_t Size = Ptr->getPointerDereferenceableBytes(DL, CanBeNull, CanBeFreed);
  324. if (!Size)
  325. return;
  326. VIs.push_back({None, Size});
  327. }
  328. R << (IsRead ? "\n Read Variables: " : "\n Written Variables: ");
  329. for (unsigned i = 0; i < VIs.size(); ++i) {
  330. const VariableInfo &VI = VIs[i];
  331. assert(!VI.isEmpty() && "No extra content to display.");
  332. if (i != 0)
  333. R << ", ";
  334. if (VI.Name)
  335. R << NV(IsRead ? "RVarName" : "WVarName", *VI.Name);
  336. else
  337. R << NV(IsRead ? "RVarName" : "WVarName", "<unknown>");
  338. if (VI.Size)
  339. R << " (" << NV(IsRead ? "RVarSize" : "WVarSize", *VI.Size) << " bytes)";
  340. }
  341. R << ".";
  342. }
  343. bool AutoInitRemark::canHandle(const Instruction *I) {
  344. if (!I->hasMetadata(LLVMContext::MD_annotation))
  345. return false;
  346. return any_of(I->getMetadata(LLVMContext::MD_annotation)->operands(),
  347. [](const MDOperand &Op) {
  348. return cast<MDString>(Op.get())->getString() == "auto-init";
  349. });
  350. }
  351. std::string AutoInitRemark::explainSource(StringRef Type) const {
  352. return (Type + " inserted by -ftrivial-auto-var-init.").str();
  353. }
  354. StringRef AutoInitRemark::remarkName(RemarkKind RK) const {
  355. switch (RK) {
  356. case RK_Store:
  357. return "AutoInitStore";
  358. case RK_Unknown:
  359. return "AutoInitUnknownInstruction";
  360. case RK_IntrinsicCall:
  361. return "AutoInitIntrinsicCall";
  362. case RK_Call:
  363. return "AutoInitCall";
  364. }
  365. llvm_unreachable("missing RemarkKind case");
  366. }