LLVM: lib/Transforms/Utils/MemoryOpRemark.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

20#include

21

22using namespace llvm;

24

26

28 if (isa(I))

29 return true;

30

31 if (auto *II = dyn_cast(I)) {

32 switch (II->getIntrinsicID()) {

33 case Intrinsic::memcpy_inline:

34 case Intrinsic::memcpy:

35 case Intrinsic::memmove:

36 case Intrinsic::memset:

37 case Intrinsic::memcpy_element_unordered_atomic:

38 case Intrinsic::memmove_element_unordered_atomic:

39 case Intrinsic::memset_element_unordered_atomic:

40 return true;

41 default:

42 return false;

43 }

44 }

45

46 if (auto *CI = dyn_cast(I)) {

47 auto *CF = CI->getCalledFunction();

48 if (!CF)

49 return false;

50

51 if (!CF->hasName())

52 return false;

53

56 if (!KnownLibCall)

57 return false;

58

59 switch (LF) {

60 case LibFunc_memcpy_chk:

61 case LibFunc_mempcpy_chk:

62 case LibFunc_memset_chk:

63 case LibFunc_memmove_chk:

64 case LibFunc_memcpy:

65 case LibFunc_mempcpy:

66 case LibFunc_memset:

67 case LibFunc_memmove:

68 case LibFunc_bzero:

69 case LibFunc_bcopy:

70 return true;

71 default:

72 return false;

73 }

74 }

75

76 return false;

77}

78

80

81

82

83

84

85 if (auto *SI = dyn_cast(I)) {

86 visitStore(*SI);

87 return;

88 }

89

90

91

92

93 if (auto *II = dyn_cast(I)) {

94 visitIntrinsicCall(*II);

95 return;

96 }

97

98

99

100

101

102 if (auto *CI = dyn_cast(I)) {

103 visitCall(*CI);

104 return;

105 }

106

107 visitUnknown(*I);

108}

109

111 return (Type + ".").str();

112}

113

115 switch (RK) {

117 return "MemoryOpStore";

119 return "MemoryOpUnknown";

121 return "MemoryOpIntrinsicCall";

123 return "MemoryOpCall";

124 }

126}

127

129 bool Atomic,

131 if (Inline && *Inline)

132 R << " Inlined: " << NV("StoreInlined", true) << ".";

133 if (Volatile)

134 R << " Volatile: " << NV("StoreVolatile", true) << ".";

135 if (Atomic)

136 R << " Atomic: " << NV("StoreAtomic", true) << ".";

137

138

139 if ((Inline && !*Inline) || !Volatile || !Atomic)

141 if (Inline && !*Inline)

142 R << " Inlined: " << NV("StoreInlined", false) << ".";

143 if (!Volatile)

144 R << " Volatile: " << NV("StoreVolatile", false) << ".";

145 if (!Atomic)

146 R << " Atomic: " << NV("StoreAtomic", false) << ".";

147}

148

149static std::optional<uint64_t>

151 if (!SizeInBits || *SizeInBits % 8 != 0)

152 return std::nullopt;

153 return *SizeInBits / 8;

154}

155

156template<typename ...Ts>

157std::unique_ptr

158MemoryOpRemark::makeRemark(Ts... Args) {

161 return std::make_unique(Args...);

163 return std::make_unique(Args...);

164 default:

166 }

167}

168

169void MemoryOpRemark::visitStore(const StoreInst &SI) {

171 bool Atomic = SI.isAtomic();

173

176 << " bytes.";

177 visitPtr(SI.getOperand(1), false, *R);

180}

181

182void MemoryOpRemark::visitUnknown(const Instruction &I) {

186}

187

188void MemoryOpRemark::visitIntrinsicCall(const IntrinsicInst &II) {

190 bool Atomic = false;

192 switch (II.getIntrinsicID()) {

193 case Intrinsic::memcpy_inline:

194 CallTo = "memcpy";

196 break;

197 case Intrinsic::memcpy:

198 CallTo = "memcpy";

199 break;

200 case Intrinsic::memmove:

201 CallTo = "memmove";

202 break;

203 case Intrinsic::memset:

204 CallTo = "memset";

205 break;

206 case Intrinsic::memcpy_element_unordered_atomic:

207 CallTo = "memcpy";

208 Atomic = true;

209 break;

210 case Intrinsic::memmove_element_unordered_atomic:

211 CallTo = "memmove";

212 Atomic = true;

213 break;

214 case Intrinsic::memset_element_unordered_atomic:

215 CallTo = "memset";

216 Atomic = true;

217 break;

218 default:

219 return visitUnknown(II);

220 }

221

223 visitCallee(CallTo.str(), true, *R);

224 visitSizeOperand(II.getOperand(2), *R);

225

226 auto *CIVolatile = dyn_cast(II.getOperand(3));

227

228 bool Volatile = !Atomic && CIVolatile && CIVolatile->getZExtValue();

229 switch (II.getIntrinsicID()) {

230 case Intrinsic::memcpy_inline:

231 case Intrinsic::memcpy:

232 case Intrinsic::memmove:

233 case Intrinsic::memcpy_element_unordered_atomic:

234 visitPtr(II.getOperand(1), true, *R);

235 visitPtr(II.getOperand(0), false, *R);

236 break;

237 case Intrinsic::memset:

238 case Intrinsic::memset_element_unordered_atomic:

239 visitPtr(II.getOperand(0), false, *R);

240 break;

241 }

244}

245

246void MemoryOpRemark::visitCall(const CallInst &CI) {

248 if (F)

249 return visitUnknown(CI);

250

254 visitCallee(F, KnownLibCall, *R);

255 visitKnownLibCall(CI, LF, *R);

257}

258

259template

260void MemoryOpRemark::visitCallee(FTy F, bool KnownLibCall,

262 R << "Call to ";

263 if (!KnownLibCall)

264 R << NV("UnknownLibCall", "unknown") << " function ";

266}

267

268void MemoryOpRemark::visitKnownLibCall(const CallInst &CI, LibFunc LF,

270 switch (LF) {

271 default:

272 return;

273 case LibFunc_memset_chk:

274 case LibFunc_memset:

275 visitSizeOperand(CI.getOperand(2), R);

276 visitPtr(CI.getOperand(0), false, R);

277 break;

278 case LibFunc_bzero:

279 visitSizeOperand(CI.getOperand(1), R);

280 visitPtr(CI.getOperand(0), false, R);

281 break;

282 case LibFunc_memcpy_chk:

283 case LibFunc_mempcpy_chk:

284 case LibFunc_memmove_chk:

285 case LibFunc_memcpy:

286 case LibFunc_mempcpy:

287 case LibFunc_memmove:

288 case LibFunc_bcopy:

289 visitSizeOperand(CI.getOperand(2), R);

290 visitPtr(CI.getOperand(1), true, R);

291 visitPtr(CI.getOperand(0), false, R);

292 break;

293 }

294}

295

297 if (auto *Len = dyn_cast(V)) {

299 R << " Memory operation size: " << NV("StoreSize", Size) << " bytes.";

300 }

301}

302

304 if (V->hasName())

305 return V->getName();

306 return std::nullopt;

307}

308

309void MemoryOpRemark::visitVariable(const Value *V,

311 if (auto *GV = dyn_cast(V)) {

312 auto *Ty = GV->getValueType();

315 if (!Var.isEmpty())

316 Result.push_back(std::move(Var));

317 return;

318 }

319

320

321 bool FoundDI = false;

322

323

324 auto FindDI = [&](const auto *DVI) {

326 std::optional<uint64_t> DISize = getSizeInBytes(DILV->getSizeInBits());

327 VariableInfo Var{DILV->getName(), DISize};

328 if (!Var.isEmpty()) {

329 Result.push_back(std::move(Var));

330 FoundDI = true;

331 }

332 }

333 };

336

337 if (FoundDI) {

339 return;

340 }

341

342 const auto *AI = dyn_cast(V);

343 if (!AI)

344 return;

345

346

347 std::optional TySize = AI->getAllocationSize(DL);

348 std::optional<uint64_t> Size =

349 TySize ? std::optional(TySize->getFixedValue()) : std::nullopt;

351 if (!Var.isEmpty())

352 Result.push_back(std::move(Var));

353}

354

356

360 for (const Value *V : Objects)

361 visitVariable(V, VIs);

362

363 if (VIs.empty()) {

364 bool CanBeNull;

365 bool CanBeFreed;

366 uint64_t Size = Ptr->getPointerDereferenceableBytes(DL, CanBeNull, CanBeFreed);

368 return;

370 }

371

372 R << (IsRead ? "\n Read Variables: " : "\n Written Variables: ");

373 for (unsigned i = 0; i < VIs.size(); ++i) {

374 const VariableInfo &VI = VIs[i];

375 assert(VI.isEmpty() && "No extra content to display.");

376 if (i != 0)

377 R << ", ";

378 if (VI.Name)

379 R << NV(IsRead ? "RVarName" : "WVarName", *VI.Name);

380 else

381 R << NV(IsRead ? "RVarName" : "WVarName", "");

382 if (VI.Size)

383 R << " (" << NV(IsRead ? "RVarSize" : "WVarSize", *VI.Size) << " bytes)";

384 }

385 R << ".";

386}

387

389 if (I->hasMetadata(LLVMContext::MD_annotation))

390 return false;

391 return any_of(I->getMetadata(LLVMContext::MD_annotation)->operands(),

393 return isa(Op.get()) &&

394 cast(Op.get())->getString() == "auto-init";

395 });

396}

397

399 return (Type + " inserted by -ftrivial-auto-var-init.").str();

400}

401

403 switch (RK) {

405 return "AutoInitStore";

407 return "AutoInitUnknownInstruction";

409 return "AutoInitIntrinsicCall";

411 return "AutoInitCall";

412 }

414}

uint64_t IntrinsicInst * II

assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())

This file defines the SmallString class.

Function * getCalledFunction() const

Returns the function called, or null if this is an indirect function invocation or the function signa...

This class represents a function call, abstracting a target machine's calling convention.

This class represents an Operation in the Expression.

TypeSize getTypeSizeInBits(Type *Ty) const

Size examples:

TypeSize getTypeStoreSize(Type *Ty) const

Returns the maximum number of bytes that may be overwritten by storing the specified type.

Common features for diagnostics dealing with optimization remarks that are used by IR passes.

A wrapper class for inspecting calls to intrinsic functions.

Tracking metadata reference owned by Metadata.

SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...

StringRef str() const

Explicit conversion to StringRef.

This class consists of common code factored out of the SmallVector class to reduce code duplication b...

void push_back(const T &Elt)

This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.

An instruction for storing to memory.

StringRef - Represent a constant reference to a string, i.e.

constexpr const char * data() const

data - Get a pointer to the start of the string (which may not be null terminated).

Provides information about what library functions are available for the current target.

bool has(LibFunc F) const

Tests whether a library function is available.

bool getLibFunc(StringRef funcName, LibFunc &F) const

Searches for a particular function name.

The instances of the Type class are immutable: once they are created, they are never changed.

Value * getOperand(unsigned i) const

LLVM Value Representation.

constexpr ScalarTy getFixedValue() const

#define llvm_unreachable(msg)

Marks that the current location is not supposed to be reachable.

constexpr char Args[]

Key for Kernel::Metadata::mArgs.

Add a small namespace to avoid name clashes with the classes used in the streaming interface.

DiagnosticInfoOptimizationBase::setExtraArgs setExtraArgs

DiagnosticInfoOptimizationBase::Argument NV

This is an optimization pass for GlobalISel generic memory operations.

UnaryFunction for_each(R &&Range, UnaryFunction F)

Provide wrappers to std::for_each which take ranges instead of having to pass begin/end explicitly.

TinyPtrVector< DbgDeclareInst * > findDbgDeclares(Value *V)

Finds dbg.declare intrinsics declaring local variables as living in the memory that 'V' points to.

bool getUnderlyingObjectsForCodeGen(const Value *V, SmallVectorImpl< Value * > &Objects)

This is a wrapper around getUnderlyingObjects and adds support for basic ptrtoint+arithmetic+inttoptr...

@ DK_OptimizationRemarkAnalysis

@ DK_OptimizationRemarkMissed

bool any_of(R &&range, UnaryPredicate P)

Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.

TinyPtrVector< DbgVariableRecord * > findDVRDeclares(Value *V)

As above, for DVRDeclares.

Implement std::hash so that hash_code can be used in STL containers.