LLVM: lib/Analysis/MemoryBuiltins.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

42#include

43#include

44#include

45#include

46#include

47#include

48

49using namespace llvm;

50

51#define DEBUG_TYPE "memory-builtins"

52

54 "object-size-offset-visitor-max-visit-instructions",

55 cl::desc("Maximum number of instructions for ObjectSizeOffsetVisitor to "

56 "look at"),

58

60 OpNewLike = 1<<0,

61 MallocLike = 1<<1,

67

70 CPPNew,

74 MSVCNew,

78};

79

81 switch (Family) {

83 return "malloc";

85 return "_Znwm";

87 return "_ZnwmSt11align_val_t";

89 return "_Znam";

91 return "_ZnamSt11align_val_t";

93 return "??2@YAPAXI@Z";

95 return "??_U@YAPAXI@Z";

97 return "vec_malloc";

99 return "__kmpc_alloc_shared";

100 }

102}

103

107

109

111

113};

114

115

116

117

124 {LibFunc_Znwm12__hot_cold_t, {OpNewLike, 2, 0, -1, -1, MallocFamily::CPPNew}},

126 {LibFunc_ZnwmRKSt9nothrow_t12__hot_cold_t, {MallocLike, 3, 0, -1, -1, MallocFamily::CPPNew}},

128 {LibFunc_ZnwmSt11align_val_t12__hot_cold_t, {OpNewLike, 3, 0, -1, 1, MallocFamily::CPPNewAligned}},

130 {LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t12__hot_cold_t, {MallocLike, 4, 0, -1, 1, MallocFamily::CPPNewAligned}},

136 {LibFunc_Znam12__hot_cold_t, {OpNewLike, 2, 0, -1, -1, MallocFamily::CPPNew}},

138 {LibFunc_ZnamRKSt9nothrow_t12__hot_cold_t, {MallocLike, 3, 0, -1, -1, MallocFamily::CPPNew}},

140 {LibFunc_ZnamSt11align_val_t12__hot_cold_t, {OpNewLike, 3, 0, -1, 1, MallocFamily::CPPNewAligned}},

142 {LibFunc_ZnamSt11align_val_tRKSt9nothrow_t12__hot_cold_t, {MallocLike, 4, 0, -1, 1, MallocFamily::CPPNewAligned}},

146 {LibFunc_msvc_new_longlong_nothrow, {MallocLike, 2, 0, -1, -1, MallocFamily::MSVCNew}},

156};

157

158

160

161 if (isa(V))

162 return nullptr;

163

164 const auto *CB = dyn_cast(V);

165 if (!CB)

166 return nullptr;

167

168 if (CB->isNoBuiltin())

169 return nullptr;

170

171 return CB->getCalledFunction();

172}

173

174

175

176static std::optional

179

180

181 if (!Callee->getReturnType()->isPointerTy())

182 return std::nullopt;

183

184

186 if (!TLI || !TLI->getLibFunc(*Callee, TLIFn) || !TLI->has(TLIFn))

187 return std::nullopt;

188

189 const auto *Iter = find_if(

190 AllocationFnData, [TLIFn](const std::pair<LibFunc, AllocFnsTy> &P) {

191 return P.first == TLIFn;

192 });

193

195 return std::nullopt;

196

197 const AllocFnsTy *FnData = &Iter->second;

199 return std::nullopt;

200

201

202 int FstParam = FnData->FstParam;

203 int SndParam = FnData->SndParam;

204 FunctionType *FTy = Callee->getFunctionType();

205

206 if (FTy->getReturnType()->isPointerTy() &&

207 FTy->getNumParams() == FnData->NumParams &&

208 (FstParam < 0 ||

209 (FTy->getParamType(FstParam)->isIntegerTy(32) ||

210 FTy->getParamType(FstParam)->isIntegerTy(64))) &&

211 (SndParam < 0 ||

212 FTy->getParamType(SndParam)->isIntegerTy(32) ||

213 FTy->getParamType(SndParam)->isIntegerTy(64)))

214 return *FnData;

215 return std::nullopt;

216}

217

218static std::optional

223 return std::nullopt;

224}

225

226static std::optional

231 Callee, AllocTy, &GetTLI(const_cast<Function &>(*Callee)));

232 return std::nullopt;

233}

234

235static std::optional

238

239

240 if (std::optional Data =

242 return Data;

243 }

244

247 return std::nullopt;

248

249 std::pair<unsigned, std::optional> Args = Attr.getAllocSizeArgs();

250

252

253

255 Result.NumParams = CB->arg_size();

256 Result.FstParam = Args.first;

257 Result.SndParam = Args.second.value_or(-1);

258

259 Result.AlignParam = -1;

260 return Result;

261}

262

264 if (const auto *CB = dyn_cast(V)) {

265 Attribute Attr = CB->getFnAttr(Attribute::AllocKind);

268 }

269 return AllocFnKind::Unknown;

270}

271

273 return F->getAttributes().getAllocKind();

274}

275

277 return (getAllocFnKind(V) & Wanted) != AllocFnKind::Unknown;

278}

279

281 return (getAllocFnKind(F) & Wanted) != AllocFnKind::Unknown;

282}

283

284

285

286

289 checkFnAllocKind(V, AllocFnKind::Alloc | AllocFnKind::Realloc);

290}

295 checkFnAllocKind(V, AllocFnKind::Alloc | AllocFnKind::Realloc);

296}

297

298

299

302}

303

304

305

307

309}

310

311

312

316}

317

318

319

322}

323

327 return nullptr;

328}

329

331

332

333

334

335

336

337

339}

340

344 if (FnData && FnData->AlignParam >= 0) {

345 return V->getOperand(FnData->AlignParam);

346 }

347 return V->getArgOperandWithAttribute(Attribute::AllocAlign);

348}

349

350

351

352

353

354

356

357

358

359 if (I.getBitWidth() > IntTyBits && I.getActiveBits() > IntTyBits)

360 return false;

361 if (I.getBitWidth() != IntTyBits)

362 I = I.zextOrTrunc(IntTyBits);

363 return true;

364}

365

366std::optional

369

370

372 if (!FnData)

373 return std::nullopt;

374

375

376

378 const unsigned IntTyBits = DL.getIndexTypeSizeInBits(CB->getType());

379

380

384 return std::nullopt;

385

386

387 if (FnData->FstParam > 0) {

389 dyn_cast(Mapper(CB->getArgOperand(FnData->FstParam)));

390 if (!Arg)

391 return std::nullopt;

392

394 if (Size.ugt(MaxSize))

395 Size = MaxSize + 1;

396 }

398 }

399

401 dyn_cast(Mapper(CB->getArgOperand(FnData->FstParam)));

402 if (!Arg)

403 return std::nullopt;

404

407 return std::nullopt;

408

409

410 if (FnData->SndParam < 0)

412

413 Arg = dyn_cast(Mapper(CB->getArgOperand(FnData->SndParam)));

414 if (!Arg)

415 return std::nullopt;

416

419 return std::nullopt;

420

421 bool Overflow;

422 Size = Size.umul_ov(NumElems, Overflow);

423 if (Overflow)

424 return std::nullopt;

426}

427

431 auto *Alloc = dyn_cast(V);

432 if (!Alloc)

433 return nullptr;

434

435

438

440 if ((AK & AllocFnKind::Uninitialized) != AllocFnKind::Unknown)

442 if ((AK & AllocFnKind::Zeroed) != AllocFnKind::Unknown)

444

445 return nullptr;

446}

447

450

452};

453

454

455static const std::pair<LibFunc, FreeFnsTy> FreeFnData[] = {

458 {LibFunc_msvc_delete_ptr32, {1, MallocFamily::MSVCNew}},

459 {LibFunc_msvc_delete_ptr64, {1, MallocFamily::MSVCNew}},

464 {LibFunc_ZdlPvRKSt9nothrow_t, {2, MallocFamily::CPPNew}},

470 {LibFunc_msvc_delete_ptr32_int, {2, MallocFamily::MSVCNew}},

471 {LibFunc_msvc_delete_ptr64_longlong, {2, MallocFamily::MSVCNew}},

472 {LibFunc_msvc_delete_ptr32_nothrow, {2, MallocFamily::MSVCNew}},

473 {LibFunc_msvc_delete_ptr64_nothrow, {2, MallocFamily::MSVCNew}},

475 {LibFunc_msvc_delete_array_ptr64_longlong, {2, MallocFamily::MSVCArrayNew}},

476 {LibFunc_msvc_delete_array_ptr32_nothrow, {2, MallocFamily::MSVCArrayNew}},

477 {LibFunc_msvc_delete_array_ptr64_nothrow, {2, MallocFamily::MSVCArrayNew}},

479 {LibFunc_ZdlPvSt11align_val_tRKSt9nothrow_t, {3, MallocFamily::CPPNewAligned}},

480 {LibFunc_ZdaPvSt11align_val_tRKSt9nothrow_t, {3, MallocFamily::CPPNewArrayAligned}},

481 {LibFunc_ZdlPvjSt11align_val_t, {3, MallocFamily::CPPNewAligned}},

482 {LibFunc_ZdlPvmSt11align_val_t, {3, MallocFamily::CPPNewAligned}},

485};

486

487

490 const auto *Iter =

491 find_if(FreeFnData, [TLIFn](const std::pair<LibFunc, FreeFnsTy> &P) {

492 return P.first == TLIFn;

493 });

495 return std::nullopt;

496 return Iter->second;

497}

498

499std::optional

503 if (TLI && TLI->getLibFunc(*Callee, TLIFn) && TLI->has(TLIFn)) {

504

505 const auto AllocData =

507 if (AllocData)

510 if (FreeData)

512 }

513 }

514

515

517 AllocFnKind::Realloc)) {

518 Attribute Attr = cast(I)->getFnAttr("alloc-family");

521 }

522 return std::nullopt;

523}

524

525

528 if (!FnData)

530

531

532

533

536 return false;

537 if (FTy->getNumParams() != FnData->NumParams)

538 return false;

540 return false;

541

542 return true;

543}

544

548 if (TLI && TLI->getLibFunc(*Callee, TLIFn) && TLI->has(TLIFn) &&

550

552 }

553 }

554

557

558 return nullptr;

559}

560

561

562

563

567

570

572}

573

574

575

576

577

582 if (!Data.bothKnown())

583 return false;

584

586 return true;

587}

588

592 bool MustSucceed) {

594 MustSucceed);

595}

596

602 "ObjectSize must be a call to llvm.objectsize!");

603

604 bool MaxVal = cast(ObjectSize->getArgOperand(1))->isZero();

606 EvalOptions.AA = AA;

607

608

609

610 if (MustSucceed)

612 MaxVal ? ObjectSizeOpts::Mode::Max : ObjectSizeOpts::Mode::Min;

613 else

614 EvalOptions.EvalMode = ObjectSizeOpts::Mode::ExactSizeFromOffset;

615

617 cast(ObjectSize->getArgOperand(2))->isOne();

618

619 auto *ResultType = cast(ObjectSize->getType());

620 bool StaticOnly = cast(ObjectSize->getArgOperand(3))->isZero();

621 if (StaticOnly) {

622

623

626 isUIntN(ResultType->getBitWidth(), Size))

627 return ConstantInt::get(ResultType, Size);

628 } else {

632

636 if (InsertedInstructions)

638 }));

640

643

644

645

650 UseZero, ConstantInt::get(ResultType, 0), ResultSize);

651

652

653 if (!isa(Size) || !isa(Offset))

655 Builder.CreateICmpNE(Ret, ConstantInt::get(ResultType, -1)));

656

657 return Ret;

658 }

659 }

660

661 if (!MustSucceed)

662 return nullptr;

663

666}

667

669 "Number of arguments with unsolved size and offset");

671 "Number of load instructions with unsolved size and offset");

672

673static std::optional

675 std::optional RHS,

678 return std::nullopt;

679 if (EvalMode == ObjectSizeOpts::Mode::Max)

681 else

683}

684

687 constexpr unsigned maxRecursionDepth = 4;

688 if (recursionDepth == maxRecursionDepth)

689 return std::nullopt;

690

691 if (const auto *CI = dyn_cast(V)) {

692 return CI->getValue();

693 } else if (const auto *SI = dyn_cast(V)) {

696 recursionDepth + 1),

698 recursionDepth + 1),

699 EvalMode);

700 } else if (const auto *PN = dyn_cast(V)) {

701 unsigned Count = PN->getNumIncomingValues();

702 if (Count == 0)

703 return std::nullopt;

705 PN->getIncomingValue(0), EvalMode, recursionDepth + 1);

706 for (unsigned I = 1; Acc && I < Count; ++I) {

708 PN->getIncomingValue(I), EvalMode, recursionDepth + 1);

710 }

711 return Acc;

712 }

713

714 return std::nullopt;

715}

716

717static std::optional

719 if (auto *CI = dyn_cast(V))

720 return CI->getValue();

721

722 if (EvalMode != ObjectSizeOpts::Mode::Min &&

723 EvalMode != ObjectSizeOpts::Mode::Max)

724 return std::nullopt;

725

726

727

728

730}

731

732

733

734

738

740}

741

747

748

749}

750

752 InstructionsVisited = 0;

754

755

756

760

762 return {};

763

765}

766

767OffsetSpan ObjectSizeOffsetVisitor::computeImpl(Value *V) {

769

770

771

772

773

774

776 V = V->stripAndAccumulateConstantOffsets(

777 DL, Offset, true, true);

778

779

780

781

784 isa(V)) {

785

786

791 auto OffsetRangeAnalysis = [EvalMode](Value &VOffset, APInt &Offset) {

792 if (auto PossibleOffset =

794 Offset = *PossibleOffset;

795 return true;

796 }

797 return false;

798 };

799

800 V = V->stripAndAccumulateConstantOffsets(

801 DL, Offset, true, true,

802 OffsetRangeAnalysis);

803 }

804

805

806

810

811 bool IndexTypeSizeChanged = InitialIntTyBits != IntTyBits;

812 if (!IndexTypeSizeChanged && Offset.isZero())

813 return ORT;

814

815

816

817

818 if (IndexTypeSizeChanged) {

820 !::CheckedZextOrTrunc(ORT.Before, InitialIntTyBits))

822 if (ORT.knownAfter() && !::CheckedZextOrTrunc(ORT.After, InitialIntTyBits))

824 }

825

827 bool Overflow;

829 if (Overflow)

831 }

833 bool Overflow;

835 if (Overflow)

837 }

838

839

841

842

843

844

845

848 return ObjectSizeOffsetVisitor::unknown();

849 }

850

851 }

852 return ORT;

853}

854

855OffsetSpan ObjectSizeOffsetVisitor::computeValue(Value *V) {

856 if (Instruction *I = dyn_cast(V)) {

857

858

859 auto P = SeenInsts.try_emplace(I, ObjectSizeOffsetVisitor::unknown());

860 if (P.second)

861 return P.first->second;

862 ++InstructionsVisited;

864 return ObjectSizeOffsetVisitor::unknown();

866

867

868 SeenInsts[I] = Res;

869 return Res;

870 }

871 if (Argument *A = dyn_cast(V))

875 if (GlobalAlias *GA = dyn_cast(V))

877 if (GlobalVariable *GV = dyn_cast(V))

879 if (UndefValue *UV = dyn_cast(V))

881

882 LLVM_DEBUG(dbgs() << "ObjectSizeOffsetVisitor::compute() unhandled value: "

883 << *V << '\n');

884 return ObjectSizeOffsetVisitor::unknown();

885}

886

887bool ObjectSizeOffsetVisitor::CheckedZextOrTrunc(APInt &I) {

888 return ::CheckedZextOrTrunc(I, IntTyBits);

889}

890

894 return ObjectSizeOffsetVisitor::unknown();

896 return ObjectSizeOffsetVisitor::unknown();

898

899 if (I.isArrayAllocation())

901

902 Value *ArraySize = I.getArraySize();

903 if (auto PossibleSize =

905 APInt NumElems = *PossibleSize;

906 if (!CheckedZextOrTrunc(NumElems))

907 return ObjectSizeOffsetVisitor::unknown();

908

909 bool Overflow;

910 Size = Size.umul_ov(NumElems, Overflow);

911

912 return Overflow ? ObjectSizeOffsetVisitor::unknown()

914 }

915 return ObjectSizeOffsetVisitor::unknown();

916}

917

919 Type *MemoryTy = A.getPointeeInMemoryValueType();

920

921 if (!MemoryTy|| !MemoryTy->isSized()) {

922 ++ObjectVisitorArgument;

923 return ObjectSizeOffsetVisitor::unknown();

924 }

925

928}

929

931 auto Mapper = [this](const Value *V) -> const Value * {

932 if (!V->getType()->isIntegerTy())

933 return V;

934

935 if (auto PossibleBound =

937 return ConstantInt::get(V->getType(), *PossibleBound);

938

939 return V;

940 };

941

942 if (std::optional Size = getAllocSize(&CB, TLI, Mapper)) {

943

944 if (Size->isNegative())

945 return ObjectSizeOffsetVisitor::unknown();

947 }

948 return ObjectSizeOffsetVisitor::unknown();

949}

950

953

954

955

956

957

958

959

961 return ObjectSizeOffsetVisitor::unknown();

963}

964

967 return ObjectSizeOffsetVisitor::unknown();

968}

969

971

972 return ObjectSizeOffsetVisitor::unknown();

973}

974

977 return ObjectSizeOffsetVisitor::unknown();

979}

980

985 return ObjectSizeOffsetVisitor::unknown();

986

989}

990

992

993 return ObjectSizeOffsetVisitor::unknown();

994}

995

996OffsetSpan ObjectSizeOffsetVisitor::findLoadOffsetRange(

999 unsigned &ScannedInstCount) {

1000 constexpr unsigned MaxInstsToScan = 128;

1001

1002 auto Where = VisitedBlocks.find(&BB);

1003 if (Where != VisitedBlocks.end())

1004 return Where->second;

1005

1006 auto Unknown = [&BB, &VisitedBlocks]() {

1007 return VisitedBlocks[&BB] = ObjectSizeOffsetVisitor::unknown();

1008 };

1009 auto Known = [&BB, &VisitedBlocks](OffsetSpan SO) {

1010 return VisitedBlocks[&BB] = SO;

1011 };

1012

1013 do {

1015

1016 if (I.isDebugOrPseudoInst())

1017 continue;

1018

1019 if (++ScannedInstCount > MaxInstsToScan)

1021

1022 if (I.mayWriteToMemory())

1023 continue;

1024

1025 if (auto *SI = dyn_cast(&I)) {

1027 Options.AA->alias(SI->getPointerOperand(), Load.getPointerOperand());

1030 continue;

1032 if (SI->getValueOperand()->getType()->isPointerTy())

1033 return Known(computeImpl(SI->getValueOperand()));

1034 else

1035 return Unknown();

1036 default:

1038 }

1039 }

1040

1041 if (auto *CB = dyn_cast(&I)) {

1043

1044 if (!Callee)

1046

1049 !TLI->has(TLIFn))

1051

1052

1053 if (TLIFn != LibFunc_posix_memalign)

1055

1060 continue;

1062 break;

1063 default:

1065 }

1066

1067

1068

1069

1072 if (!Checked || !*Checked)

1074

1076 auto *C = dyn_cast(Size);

1077 if (C)

1079

1080 APInt CSize = C->getValue();

1083

1085 }

1086

1089

1092 PredecessorSizeOffsets.push_back(findLoadOffsetRange(

1094 VisitedBlocks, ScannedInstCount));

1095 if (!PredecessorSizeOffsets.back().bothKnown())

1097 }

1098

1099 if (PredecessorSizeOffsets.empty())

1101

1102 return Known(std::accumulate(

1103 PredecessorSizeOffsets.begin() + 1, PredecessorSizeOffsets.end(),

1105 return combineOffsetRange(LHS, RHS);

1106 }));

1107}

1108

1110 if (!Options.AA) {

1111 ++ObjectVisitorLoad;

1112 return ObjectSizeOffsetVisitor::unknown();

1113 }

1114

1116 unsigned ScannedInstCount = 0;

1119 VisitedBlocks, ScannedInstCount);

1121 ++ObjectVisitorLoad;

1122 return SO;

1123}

1124

1127 if (LHS.bothKnown() || RHS.bothKnown())

1128 return ObjectSizeOffsetVisitor::unknown();

1129

1132 return {LHS.Before.slt(RHS.Before) ? LHS.Before : RHS.Before,

1133 LHS.After.slt(RHS.After) ? LHS.After : RHS.After};

1135 return {LHS.Before.sgt(RHS.Before) ? LHS.Before : RHS.Before,

1136 LHS.After.sgt(RHS.After) ? LHS.After : RHS.After};

1137 }

1139 return {LHS.Before.eq(RHS.Before) ? LHS.Before : APInt(),

1142 return (LHS == RHS) ? LHS : ObjectSizeOffsetVisitor::unknown();

1143 }

1145}

1146

1149 return ObjectSizeOffsetVisitor::unknown();

1151 return std::accumulate(IncomingValues.begin() + 1, IncomingValues.end(),

1152 computeImpl(*IncomingValues.begin()),

1154 return combineOffsetRange(LHS, computeImpl(VRHS));

1155 });

1156}

1157

1159 return combineOffsetRange(computeImpl(I.getTrueValue()),

1160 computeImpl(I.getFalseValue()));

1161}

1162

1165}

1166

1168 LLVM_DEBUG(dbgs() << "ObjectSizeOffsetVisitor unknown instruction:" << I

1169 << '\n');

1170 return ObjectSizeOffsetVisitor::unknown();

1171}

1172

1173

1176

1180 : DL(DL), TLI(TLI), Context(Context),

1183 [&](Instruction *I) { InsertedInstructions.insert(I); })),

1184 EvalOpts(EvalOpts) {

1185

1186

1187}

1188

1190

1191 IntTy = cast(DL.getIndexType(V->getType()));

1192 Zero = ConstantInt::get(IntTy, 0);

1193

1195

1196 if (!Result.bothKnown()) {

1197

1198

1199

1200 for (const Value *SeenVal : SeenVals) {

1202

1203 if (CacheIt != CacheMap.end() && CacheIt->second.anyKnown())

1204 CacheMap.erase(CacheIt);

1205 }

1206

1207

1208 for (Instruction *I : InsertedInstructions) {

1210 I->eraseFromParent();

1211 }

1212 }

1213

1214 SeenVals.clear();

1215 InsertedInstructions.clear();

1216 return Result;

1217}

1218

1220

1221

1222

1226

1228 if (Const.bothKnown())

1229 return SizeOffsetValue(ConstantInt::get(Context, Const.Size),

1230 ConstantInt::get(Context, Const.Offset));

1231

1232 V = V->stripPointerCasts();

1233

1234

1236 if (CacheIt != CacheMap.end())

1237 return CacheIt->second;

1238

1239

1240

1242 if (Instruction *I = dyn_cast(V))

1244

1245

1247

1248

1249

1250

1251 if (!SeenVals.insert(V).second) {

1253 } else if (GEPOperator *GEP = dyn_cast(V)) {

1255 } else if (Instruction *I = dyn_cast(V)) {

1257 } else if (isa(V) ||

1258 (isa(V) &&

1259 cast(V)->getOpcode() == Instruction::IntToPtr) ||

1260 isa(V) ||

1261 isa(V)) {

1262

1264 } else {

1266 dbgs() << "ObjectSizeOffsetEvaluator::compute() unhandled value: " << *V

1267 << '\n');

1269 }

1270

1271

1274}

1275

1277 if (I.getAllocatedType()->isSized())

1279

1280

1281 assert(I.isArrayAllocation() || I.getAllocatedType()->isScalableTy());

1282

1283

1284

1286 I.getArraySize(),

1289 "Expected zero constant to have pointer index type");

1290

1295}

1296

1299 if (!FnData)

1301

1302

1303 if (FnData->AllocTy == StrDupLike) {

1304

1306 }

1307

1310 if (FnData->SndParam < 0)

1312

1317}

1318

1322}

1323

1327}

1328

1333

1337}

1338

1340

1342}

1343

1346}

1347

1349

1350 PHINode *SizePHI = Builder.CreatePHI(IntTy, PHI.getNumIncomingValues());

1351 PHINode *OffsetPHI = Builder.CreatePHI(IntTy, PHI.getNumIncomingValues());

1352

1353

1355

1356

1357 for (unsigned i = 0, e = PHI.getNumIncomingValues(); i != e; ++i) {

1358 BasicBlock *IncomingBlock = PHI.getIncomingBlock(i);

1361

1365 InsertedInstructions.erase(OffsetPHI);

1368 InsertedInstructions.erase(SizePHI);

1370 }

1373 }

1374

1380 InsertedInstructions.erase(SizePHI);

1381 }

1386 InsertedInstructions.erase(OffsetPHI);

1387 }

1389}

1390

1394

1397 if (TrueSide == FalseSide)

1398 return TrueSide;

1399

1405}

1406

1408 LLVM_DEBUG(dbgs() << "ObjectSizeOffsetEvaluator unknown instruction:" << I

1409 << '\n');

1411}

This file implements a class to represent arbitrary precision integral constant values and operations...

MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL

This file contains the simple types necessary to represent the attributes associated with functions a...

BlockVerifier::State From

static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")

This file contains the declarations for the subclasses of Constant, which represent the different fla...

static std::optional< APInt > combinePossibleConstantValues(std::optional< APInt > LHS, std::optional< APInt > RHS, ObjectSizeOpts::Mode EvalMode)

static AllocFnKind getAllocFnKind(const Value *V)

static std::optional< AllocFnsTy > getAllocationDataForFunction(const Function *Callee, AllocType AllocTy, const TargetLibraryInfo *TLI)

Returns the allocation data for the given value if it's a call to a known allocation function.

static std::optional< AllocFnsTy > getAllocationData(const Value *V, AllocType AllocTy, const TargetLibraryInfo *TLI)

std::optional< FreeFnsTy > getFreeFunctionDataForFunction(const Function *Callee, const LibFunc TLIFn)

static bool checkFnAllocKind(const Value *V, AllocFnKind Wanted)

StringRef mangledNameForMallocFamily(const MallocFamily &Family)

static std::optional< AllocFnsTy > getAllocationSize(const CallBase *CB, const TargetLibraryInfo *TLI)

static bool CheckedZextOrTrunc(APInt &I, unsigned IntTyBits)

When we're compiling N-bit code, and the user uses parameters that are greater than N bits (e....

static const std::pair< LibFunc, FreeFnsTy > FreeFnData[]

static const Function * getCalledFunction(const Value *V)

static std::optional< APInt > aggregatePossibleConstantValues(const Value *V, ObjectSizeOpts::Mode EvalMode)

static cl::opt< unsigned > ObjectSizeOffsetVisitorMaxVisitInstructions("object-size-offset-visitor-max-visit-instructions", cl::desc("Maximum number of instructions for ObjectSizeOffsetVisitor to " "look at"), cl::init(100))

static std::optional< APInt > aggregatePossibleConstantValuesImpl(const Value *V, ObjectSizeOpts::Mode EvalMode, unsigned recursionDepth)

static const std::pair< LibFunc, AllocFnsTy > AllocationFnData[]

static APInt getSizeWithOverflow(const SizeOffsetAPInt &Data)

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

This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...

#define STATISTIC(VARNAME, DESC)

static std::optional< unsigned > getOpcode(ArrayRef< VPValue * > Values)

Returns the opcode of Values or ~0 if they do not all agree.

AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB)

The main low level interface to the alias analysis implementation.

Class for arbitrary precision integers.

APInt zext(unsigned width) const

Zero extend to a new width.

uint64_t getZExtValue() const

Get zero extended value.

unsigned getBitWidth() const

Return the number of bits in the APInt.

bool isNegative() const

Determine sign of this APInt.

APInt sadd_ov(const APInt &RHS, bool &Overflow) const

static APInt getZero(unsigned numBits)

Get the '0' value for the specified bit-width.

APInt ssub_ov(const APInt &RHS, bool &Overflow) const

The possible results of an alias query.

@ NoAlias

The two locations do not alias at all.

@ MustAlias

The two locations precisely alias each other.

an instruction to allocate memory on the stack

This class represents an incoming formal argument to a Function.

uint64_t getValueAsInt() const

Return the attribute's value as an integer.

std::pair< unsigned, std::optional< unsigned > > getAllocSizeArgs() const

Returns the argument numbers for the allocsize attribute.

StringRef getValueAsString() const

Return the attribute's value as a string.

bool isValid() const

Return true if the attribute is any kind of attribute.

LLVM Basic Block Representation.

iterator begin()

Instruction iterator methods.

const_iterator getFirstInsertionPt() const

Returns an iterator to the first instruction in this block that is suitable for inserting a non-PHI i...

InstListType::iterator iterator

Instruction iterators...

Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...

Function * getCalledFunction() const

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

Attribute getFnAttr(StringRef Kind) const

Get the attribute of a given kind for the function.

Value * getArgOperand(unsigned i) const

Value * getArgOperandWithAttribute(Attribute::AttrKind Kind) const

If one of the arguments has the specified attribute, returns its operand value.

unsigned arg_size() const

This is the shared class of boolean and integer constants.

const APInt & getValue() const

Return the constant as an APInt value reference.

A constant pointer value that points to null.

PointerType * getType() const

Specialize the getType() method to always return an PointerType, which reduces the amount of casting ...

This is an important base class in LLVM.

static Constant * getAllOnesValue(Type *Ty)

static Constant * getNullValue(Type *Ty)

Constructor to create a '0' constant of arbitrary type.

A parsed version of the target data layout string in and methods for querying it.

unsigned getIndexTypeSizeInBits(Type *Ty) const

Layout size of the index used in GEP calculation.

unsigned getAllocaAddrSpace() const

IntegerType * getIndexType(LLVMContext &C, unsigned AddressSpace) const

Returns the type of a GEP index in AddressSpace.

TypeSize getTypeAllocSize(Type *Ty) const

Returns the offset in bytes between successive objects of the specified type, including alignment pad...

iterator find(const_arg_type_t< KeyT > Val)

bool erase(const KeyT &Val)

DenseMapIterator< KeyT, ValueT, KeyInfoT, BucketT > iterator

Class to represent function types.

unsigned getNumParams() const

Return the number of fixed parameters this function type requires.

Type * getParamType(unsigned i) const

Parameter type accessors.

Type * getReturnType() const

LLVMContext & getContext() const

getContext - Return a reference to the LLVMContext associated with this function.

const Constant * getAliasee() const

MaybeAlign getAlign() const

Returns the alignment of the given variable or function.

bool hasExternalWeakLinkage() const

bool isInterposable() const

Return true if this global's definition can be substituted with an arbitrary definition at link time ...

Type * getValueType() const

bool hasInitializer() const

Definitions have initializers, declarations don't.

Value * CreateICmpULT(Value *LHS, Value *RHS, const Twine &Name="")

Value * CreateZExtOrTrunc(Value *V, Type *DestTy, const Twine &Name="")

Create a ZExt or Trunc from the integer value V to DestTy.

CallInst * CreateAssumption(Value *Cond, ArrayRef< OperandBundleDef > OpBundles={})

Create an assume intrinsic call that allows the optimizer to assume that the provided condition will ...

Value * CreateSelect(Value *C, Value *True, Value *False, const Twine &Name="", Instruction *MDFrom=nullptr)

Value * CreateTypeSize(Type *DstType, TypeSize Size)

Create an expression which evaluates to the number of units in Size at runtime.

Value * CreateICmpNE(Value *LHS, Value *RHS, const Twine &Name="")

PHINode * CreatePHI(Type *Ty, unsigned NumReservedValues, const Twine &Name="")

Value * CreateSub(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)

Value * CreateAdd(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)

void SetInsertPoint(BasicBlock *TheBB)

This specifies that created instructions should be appended to the end of the specified block.

Value * CreateMul(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)

Provides an 'InsertHelper' that calls a user-provided callback after performing the default insertion...

This provides a uniform API for creating instructions and inserting them into a basic block: either a...

void visit(Iterator Start, Iterator End)

InstListType::iterator eraseFromParent()

This method unlinks 'this' from the containing basic block and deletes it.

const Function * getFunction() const

Return the function this instruction belongs to.

const DataLayout & getDataLayout() const

Get the data layout of the module this instruction belongs to.

This class represents a cast from an integer to a pointer.

A wrapper class for inspecting calls to intrinsic functions.

Intrinsic::ID getIntrinsicID() const

Return the intrinsic ID of this intrinsic.

This is an important class for using LLVM in a threaded context.

An instruction for reading from memory.

Evaluate the size and offset of an object pointed to by a Value*.

SizeOffsetValue visitExtractValueInst(ExtractValueInst &I)

SizeOffsetValue visitExtractElementInst(ExtractElementInst &I)

SizeOffsetValue compute(Value *V)

SizeOffsetValue visitInstruction(Instruction &I)

ObjectSizeOffsetEvaluator(const DataLayout &DL, const TargetLibraryInfo *TLI, LLVMContext &Context, ObjectSizeOpts EvalOpts={})

SizeOffsetValue visitLoadInst(LoadInst &I)

SizeOffsetValue visitGEPOperator(GEPOperator &GEP)

SizeOffsetValue visitIntToPtrInst(IntToPtrInst &)

SizeOffsetValue visitPHINode(PHINode &PHI)

SizeOffsetValue visitCallBase(CallBase &CB)

SizeOffsetValue visitSelectInst(SelectInst &I)

SizeOffsetValue visitAllocaInst(AllocaInst &I)

static SizeOffsetValue unknown()

Evaluate the size and offset of an object pointed to by a Value* statically.

OffsetSpan visitSelectInst(SelectInst &I)

OffsetSpan visitExtractValueInst(ExtractValueInst &I)

OffsetSpan visitConstantPointerNull(ConstantPointerNull &)

OffsetSpan visitExtractElementInst(ExtractElementInst &I)

OffsetSpan visitGlobalVariable(GlobalVariable &GV)

OffsetSpan visitCallBase(CallBase &CB)

OffsetSpan visitIntToPtrInst(IntToPtrInst &)

OffsetSpan visitAllocaInst(AllocaInst &I)

ObjectSizeOffsetVisitor(const DataLayout &DL, const TargetLibraryInfo *TLI, LLVMContext &Context, ObjectSizeOpts Options={})

OffsetSpan visitLoadInst(LoadInst &I)

OffsetSpan visitPHINode(PHINode &)

OffsetSpan visitGlobalAlias(GlobalAlias &GA)

OffsetSpan visitInstruction(Instruction &I)

SizeOffsetAPInt compute(Value *V)

OffsetSpan visitUndefValue(UndefValue &)

OffsetSpan visitArgument(Argument &A)

void addIncoming(Value *V, BasicBlock *BB)

Add an incoming value to the end of the PHI list.

op_range incoming_values()

Value * hasConstantValue() const

If the specified PHI node always merges together the same value, return the value,...

unsigned getNumIncomingValues() const

Return the number of incoming edges.

unsigned getAddressSpace() const

Return the address space of the Pointer type.

static PoisonValue * get(Type *T)

Static factory methods - Return an 'poison' object of the specified type.

This class represents the LLVM 'select' instruction.

std::pair< iterator, bool > insert(PtrType Ptr)

Inserts Ptr if and only if there is no element in the container equal to Ptr.

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.

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

TargetFolder - Create constants with target dependent folding.

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.

bool isPointerTy() const

True if this is an instance of PointerType.

bool isSized(SmallPtrSetImpl< Type * > *Visited=nullptr) const

Return true if it makes sense to take the size of this type.

bool isVoidTy() const

Return true if this is 'void'.

'undef' values are things that do not have specified contents.

static UndefValue * get(Type *T)

Static factory methods - Return an 'undef' object of the specified type.

Value * getOperand(unsigned i) const

LLVM Value Representation.

Type * getType() const

All values are typed, get the type of this value.

void replaceAllUsesWith(Value *V)

Change all uses of this to point to a new Value.

constexpr bool isScalable() const

Returns whether the quantity is scaled by a runtime quantity (vscale).

constexpr ScalarTy getKnownMinValue() const

Returns the minimum value this quantity can represent.

An efficient, type-erasing, non-owning reference to a callable.

const ParentTy * getParent() const

#define llvm_unreachable(msg)

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

@ C

The default llvm calling convention, compatible with C.

initializer< Ty > init(const Ty &Val)

This is an optimization pass for GlobalISel generic memory operations.

Constant * getInitialValueOfAllocation(const Value *V, const TargetLibraryInfo *TLI, Type *Ty)

If this is a call to an allocation function that initializes memory to a fixed value,...

bool isUIntN(unsigned N, uint64_t x)

Checks if an unsigned integer fits into the given (dynamic) bit width.

bool isRemovableAlloc(const CallBase *V, const TargetLibraryInfo *TLI)

Return true if this is a call to an allocation function that does not have side effects that we are r...

std::optional< StringRef > getAllocationFamily(const Value *I, const TargetLibraryInfo *TLI)

If a function is part of an allocation family (e.g.

Value * lowerObjectSizeCall(IntrinsicInst *ObjectSize, const DataLayout &DL, const TargetLibraryInfo *TLI, bool MustSucceed)

Try to turn a call to @llvm.objectsize into an integer value of the given Type.

Value * getAllocAlignment(const CallBase *V, const TargetLibraryInfo *TLI)

Gets the alignment argument for an aligned_alloc-like function, using either built-in knowledge based...

bool isLibFreeFunction(const Function *F, const LibFunc TLIFn)

isLibFreeFunction - Returns true if the function is a builtin free()

Value * getReallocatedOperand(const CallBase *CB)

If this is a call to a realloc function, return the reallocated operand.

bool isAllocLikeFn(const Value *V, const TargetLibraryInfo *TLI)

Tests if a value is a call or invoke to a library function that allocates memory (either malloc,...

bool getObjectSize(const Value *Ptr, uint64_t &Size, const DataLayout &DL, const TargetLibraryInfo *TLI, ObjectSizeOpts Opts={})

Compute the size of the object pointed by Ptr.

Value * emitGEPOffset(IRBuilderBase *Builder, const DataLayout &DL, User *GEP, bool NoAssumptions=false)

Given a getelementptr instruction/constantexpr, emit the code necessary to compute the offset from th...

raw_ostream & dbgs()

dbgs() - This returns a reference to a raw_ostream for debugging messages.

uint64_t GetStringLength(const Value *V, unsigned CharSize=8)

If we can compute the length of the string pointed to by the specified pointer, return 'len+1'.

bool isMallocOrCallocLikeFn(const Value *V, const TargetLibraryInfo *TLI)

Tests if a value is a call or invoke to a library function that allocates memory similar to malloc or...

bool isReallocLikeFn(const Function *F)

Tests if a function is a call or invoke to a library function that reallocates memory (e....

uint64_t alignTo(uint64_t Size, Align A)

Returns a multiple of A needed to store Size bytes.

Value * getFreedOperand(const CallBase *CB, const TargetLibraryInfo *TLI)

If this if a call to a free function, return the freed operand.

auto find_if(R &&Range, UnaryPredicate P)

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

auto predecessors(const MachineBasicBlock *BB)

bool isAllocationFn(const Value *V, const TargetLibraryInfo *TLI)

Tests if a value is a call or invoke to a library function that allocates or reallocates memory (eith...

std::optional< APInt > getAllocSize(const CallBase *CB, const TargetLibraryInfo *TLI, function_ref< const Value *(const Value *)> Mapper=[](const Value *V) { return V;})

Return the size of the requested allocation.

std::optional< bool > isImpliedByDomCondition(const Value *Cond, const Instruction *ContextI, const DataLayout &DL)

Return the boolean condition value in the context of the given instruction if it is known based on do...

bool isNewLikeFn(const Value *V, const TargetLibraryInfo *TLI)

Tests if a value is a call or invoke to a library function that allocates memory via new.

This struct is a compact representation of a valid (power of two) or undefined (0) alignment.

Various options to control the behavior of getObjectSize.

bool NullIsUnknownSize

If this is true, null pointers in address space 0 will be treated as though they can't be evaluated.

Mode EvalMode

How we want to evaluate this object's size.

AAResults * AA

If set, used for more accurate evaluation.

bool RoundToAlign

Whether to round the result up to the alignment of allocas, byval arguments, and global variables.

Mode

Controls how we handle conditional statements with unknown conditions.

@ ExactUnderlyingSizeAndOffset

All branches must be known and have the same underlying size and offset to be merged.

@ Max

Same as Min, except we pick the maximum size of all of the branches.

@ Min

Evaluate all branches of an unknown condition.

@ ExactSizeFromOffset

All branches must be known and have the same size, starting from the offset, to be merged.

OffsetSpan - Used internally by ObjectSizeOffsetVisitor.

APInt After

Number of allocated bytes before this point.

SizeOffsetAPInt - Used by ObjectSizeOffsetVisitor, which works with APInts.

SizeOffsetType - A base template class for the object size visitors.

SizeOffsetWeakTrackingVH - Used by ObjectSizeOffsetEvaluator in a DenseMap.