LLVM: lib/Target/BPF/BPFPreserveStaticOffset.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

116#include "llvm/IR/IntrinsicsBPF.h"

120

121#define DEBUG_TYPE "bpf-preserve-static-offset"

122

123using namespace llvm;

124

127

130 if (Function *Func = Call->getCalledFunction())

131 return Func->getIntrinsicID() == Id;

132 return false;

133}

134

138

140 if (isIntrinsicCall(I, Intrinsic::bpf_getelementptr_and_load))

142 return nullptr;

143}

144

146 if (isIntrinsicCall(I, Intrinsic::bpf_getelementptr_and_store))

148 return nullptr;

149}

150

151template

153 DebugLoc Merged = (*Insns.begin())->getDebugLoc();

154 for (T *I : Insns)

156 return Merged;

157}

158

160 Intrinsic::BPFIntrinsics Intrinsic,

163

166}

167

172

177

182

187

188namespace {

189struct GEPChainInfo {

190 bool InBounds;

191 Type *SourceElementType;

194

195 GEPChainInfo() { reset(); }

196

197 void reset() {

198 InBounds = true;

199 SourceElementType = nullptr;

200 Indices.clear();

201 Members.clear();

202 }

203};

204}

205

206template <class T = std::disjunction<LoadInst, StoreInst>>

208 GEPChainInfo &GEP, T *Insn) {

211

212 unsigned AlignShiftValue = Log2_64(Insn->getAlign().value());

213 Args.push_back(GEP.Members[0]->getPointerOperand());

214 Args.push_back(ConstantInt::get(Int1Ty, Insn->isVolatile()));

215 Args.push_back(ConstantInt::get(Int8Ty, (unsigned)Insn->getOrdering()));

216 Args.push_back(ConstantInt::get(Int8Ty, (unsigned)Insn->getSyncScopeID()));

217 Args.push_back(ConstantInt::get(Int8Ty, AlignShiftValue));

218 Args.push_back(ConstantInt::get(Int1Ty, GEP.InBounds));

219 Args.append(GEP.Indices.begin(), GEP.Indices.end());

220}

221

227 {Load->getType()}, Args);

230 Call->setName((*GEP.Members.rbegin())->getName());

231 if (Load->isUnordered()) {

232 Call->setOnlyReadsMemory();

233 Call->setOnlyAccessesArgMemory();

235 }

237 Call->addParamAttr(I, Attribute::ImmArg);

238 Call->setAAMetadata(Load->getAAMetadata());

240}

241

245 Args.push_back(Store->getValueOperand());

249 {Store->getValueOperand()->getType()}, Args);

251 if (Store->getValueOperand()->getType()->isPointerTy())

254 if (Store->isUnordered()) {

255 Call->setOnlyWritesMemory();

256 Call->setOnlyAccessesArgMemory();

258 }

260 Call->addParamAttr(I, Attribute::ImmArg);

261 Call->setAAMetadata(Store->getAAMetadata());

263}

264

267 return Int->getValue().getZExtValue();

268 std::string Report;

270 ReportS << "Expecting ConstantInt as argument #" << ArgNo << " of " << *Call

271 << "\n";

273}

274

277 Indices.append(Call->data_operands_begin() + 6 + Delta,

278 Call->data_operands_end());

279 Type *GEPPointeeType = Call->getParamElementType(Delta);

280 auto *GEP =

284 return GEP;

285}

286

287template <class T = std::disjunction<LoadInst, StoreInst>>

289 int Delta) {

294 Insn->setAlignment(Align(1ULL << AlignShiftValue));

295 GEP->setDebugLoc(Call->getDebugLoc());

296 Insn->setDebugLoc(Call->getDebugLoc());

297 Insn->setAAMetadata(Call->getAAMetadata());

298}

299

300std::pair<GetElementPtrInst *, LoadInst *>

303 Type *ReturnType = Call->getFunctionType()->getReturnType();

304 auto *Load = new LoadInst(ReturnType, GEP, "",

305

306 false, Align(1));

308 return std::pair{GEP, Load};

309}

310

311std::pair<GetElementPtrInst *, StoreInst *>

315

316 false, Align(1));

318 return std::pair{GEP, Store};

319}

320

323 return CI && CI->isZero();

324}

325

326

327

328

330 GEPChainInfo &Info) {

331 if (GEPs.empty())

332 return false;

333

335 return GEP->hasAllConstantIndices();

336 }))

337 return false;

338

340 Info.InBounds = First->isInBounds();

341 Info.SourceElementType = First->getSourceElementType();

342 Type *ResultElementType = First->getResultElementType();

343 Info.Indices.append(First->idx_begin(), First->idx_end());

345

347 if (isZero(*GEP->idx_begin())) {

348 Info.reset();

349 return false;

350 }

351 if (GEP->getSourceElementType() ||

352 GEP->getSourceElementType() != ResultElementType) {

353 Info.reset();

354 return false;

355 }

356 Info.InBounds &= GEP->isInBounds();

357 Info.Indices.append(GEP->idx_begin() + 1, GEP->idx_end());

358 Info.Members.push_back(GEP);

359 ResultElementType = GEP->getResultElementType();

360 }

361

362 return true;

363}

364

365

366

367

369 GEPChainInfo &Info) {

370 if (GEPs.empty())

371 return false;

372

376 Type *PtrTy = First->getType()->getScalarType();

377 APInt Offset(DL.getIndexTypeSizeInBits(PtrTy), 0);

379 if (GEP->accumulateConstantOffset(DL, Offset)) {

380 Info.reset();

381 return false;

382 }

383 Info.InBounds &= GEP->isInBounds();

384 Info.Members.push_back(GEP);

385 }

387 Info.Indices.push_back(ConstantInt::get(C, Offset));

388

389 return true;

390}

391

395 Twine("Non-constant offset in access to a field of a type marked "

396 "with preserve_static_offset might be rejected by BPF verifier")

398 ? ""

399 : " (pass -g option to get exact location)"),

401}

402

405 return GEP->hasAllZeroIndices();

406 });

407}

408

412 GEPChainInfo GEPChain;

415 return false;

416 }

422 }

426 }

427 return true;

428}

429

430

433 return L->getPointerOperand() == I;

435 return S->getPointerOperand() == I;

437 return GEP->getPointerOperand() == I;

439 return Call->getArgOperand(0) == I;

441 return Call->getArgOperand(1) == I;

442 return false;

443}

444

447 return Call->hasFnAttr(Attribute::InlineHint);

448 return false;

449}

450

454 bool AllowPatial, bool &StillUsed);

455

459 bool &StillUsed) {

465 else

467 llvm::dbgs() << "unsupported usage in BPFPreserveStaticOffsetPass:\n";

468 llvm::dbgs() << " Insn: " << *Insn << "\n";

469 llvm::dbgs() << " User: " << *U << "\n";

470 });

471 }

472}

473

474

475

476

477

478

479

480

481

482

483

484

485

486

487

488

489

490

491

492

493

494

495

496

500 bool AllowPatial, bool &StillUsed) {

501 auto MarkAndTraverseUses = [&]() {

503 rewriteUses(Insn, GEPs, Visited, AllowPatial, StillUsed);

504 };

505 auto TryToReplace = [&](Instruction *LoadOrStore) {

506

507

508

510 return;

513 return;

514 }

515 if (!AllowPatial)

517 StillUsed = true;

518 };

520 TryToReplace(Insn);

522 auto [GEP, Load] =

525 TryToReplace(Load);

527 delete Load;

528 delete GEP;

530

531

532

533 auto [GEP, Store] =

536 TryToReplace(Store);

538 delete Store;

539 delete GEP;

542 MarkAndTraverseUses();

545 MarkAndTraverseUses();

547

548

549

550

551

552

553 if (AllowPatial)

554 StillUsed = true;

555 } else {

558 BufStream << *Insn;

560 Twine("Unexpected rewriteAccessChain Insn = ").concat(Buf));

561 }

562}

563

568

573 bool StillUsed = false;

574 rewriteUses(Marker, GEPs, Visited, AllowPatial, StillUsed);

575

576

577 for (auto V = Visited.rbegin(); V != Visited.rend(); ++V) {

580 RemovedMarkers.insert(*V);

581 } else if ((*V)->use_empty()) {

582 (*V)->eraseFromParent();

583 }

584 }

585 return StillUsed;

586}

587

588static std::vector<Instruction *>

590 std::vector<Instruction *> Calls;

593 Calls.push_back(&Insn);

594 return Calls;

595}

596

598 return isIntrinsicCall(V, Intrinsic::preserve_array_access_index);

599}

600

602 return isIntrinsicCall(V, Intrinsic::preserve_struct_access_index);

603}

604

606 return isIntrinsicCall(V, Intrinsic::preserve_union_access_index);

607}

608

610 auto IsPointerOperand = [](Value *Op, User *U) {

612 return GEP->getPointerOperand() == Op;

616 return false;

617 };

618

621 do {

624 if (IsPointerOperand(V, U))

628 continue;

635 } while (!WorkList.empty());

636}

637

638

639

640

641

642

643

645 LLVM_DEBUG(dbgs() << "********** BPFPreserveStaticOffsetPass (AllowPartial="

646 << AllowPartial << ") ************\n");

647

650

651 LLVM_DEBUG(dbgs() << "There are " << MarkerCalls.size()

652 << " preserve.static.offset calls\n");

653

654 if (MarkerCalls.empty())

655 return false;

656

657 for (auto *Call : MarkerCalls)

659

660 for (auto *Call : MarkerCalls) {

662 continue;

664 if (!StillUsed || !AllowPartial)

666 }

667

668 return true;

669}

670

MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL

Expand Atomic instructions

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

static CallInst * isGEPAndLoad(Value *I)

Definition BPFPreserveStaticOffset.cpp:139

bool isPreserveUnionIndex(Value *V)

Definition BPFPreserveStaticOffset.cpp:605

bool isPreserveArrayIndex(Value *V)

Definition BPFPreserveStaticOffset.cpp:597

static bool isPreserveStaticOffsetCall(Value *I)

Definition BPFPreserveStaticOffset.cpp:135

static void setParamElementType(CallInst *Call, unsigned ArgNo, Type *Type)

Definition BPFPreserveStaticOffset.cpp:168

static bool foldGEPChainAsU8Access(SmallVector< GetElementPtrInst * > &GEPs, GEPChainInfo &Info)

Definition BPFPreserveStaticOffset.cpp:368

static void fillCommonArgs(LLVMContext &C, SmallVector< Value * > &Args, GEPChainInfo &GEP, T *Insn)

Definition BPFPreserveStaticOffset.cpp:207

static void removePAICalls(Instruction *Marker)

Definition BPFPreserveStaticOffset.cpp:609

static void reportNonStaticGEPChain(Instruction *Insn)

Definition BPFPreserveStaticOffset.cpp:392

static bool foldGEPChainAsStructAccess(SmallVector< GetElementPtrInst * > &GEPs, GEPChainInfo &Info)

Definition BPFPreserveStaticOffset.cpp:329

static const unsigned GepAndStoreFirstIdxArg

Definition BPFPreserveStaticOffset.cpp:126

static void removeMarkerCall(Instruction *Marker)

Definition BPFPreserveStaticOffset.cpp:564

static Instruction * makeGEPAndStore(Module *M, GEPChainInfo &GEP, StoreInst *Store)

Definition BPFPreserveStaticOffset.cpp:242

static void rewriteUses(Instruction *Insn, SmallVector< GetElementPtrInst * > &GEPs, SmallVector< Instruction * > &Visited, bool AllowPatial, bool &StillUsed)

Definition BPFPreserveStaticOffset.cpp:456

static void setParamReadNone(CallInst *Call, unsigned ArgNo)

Definition BPFPreserveStaticOffset.cpp:173

static Instruction * makeGEPAndLoad(Module *M, GEPChainInfo &GEP, LoadInst *Load)

Definition BPFPreserveStaticOffset.cpp:222

static unsigned getOperandAsUnsigned(CallInst *Call, unsigned ArgNo)

Definition BPFPreserveStaticOffset.cpp:265

bool isPreserveStructIndex(Value *V)

Definition BPFPreserveStaticOffset.cpp:601

static void setParamReadOnly(CallInst *Call, unsigned ArgNo)

Definition BPFPreserveStaticOffset.cpp:178

static void rewriteAccessChain(Instruction *Insn, SmallVector< GetElementPtrInst * > &GEPs, SmallVector< Instruction * > &Visited, bool AllowPatial, bool &StillUsed)

Definition BPFPreserveStaticOffset.cpp:497

static bool isInlineableCall(User *U)

Definition BPFPreserveStaticOffset.cpp:445

static const unsigned GepAndLoadFirstIdxArg

Definition BPFPreserveStaticOffset.cpp:125

static DebugLoc mergeDebugLocs(SmallVector< T * > &Insns)

Definition BPFPreserveStaticOffset.cpp:152

static GetElementPtrInst * reconstructGEP(CallInst *Call, int Delta)

Definition BPFPreserveStaticOffset.cpp:275

static CallInst * makeIntrinsicCall(Module *M, Intrinsic::BPFIntrinsics Intrinsic, ArrayRef< Type * > Types, ArrayRef< Value * > Args)

Definition BPFPreserveStaticOffset.cpp:159

static bool allZeroIndices(SmallVector< GetElementPtrInst * > &GEPs)

Definition BPFPreserveStaticOffset.cpp:403

static std::vector< Instruction * > collectPreserveStaticOffsetCalls(Function &F)

Definition BPFPreserveStaticOffset.cpp:589

static bool rewriteFunction(Function &F, bool AllowPartial)

Definition BPFPreserveStaticOffset.cpp:644

static bool tryToReplaceWithGEPBuiltin(Instruction *LoadOrStoreTemplate, SmallVector< GetElementPtrInst * > &GEPs, Instruction *InsnToReplace)

Definition BPFPreserveStaticOffset.cpp:409

static void reconstructCommon(CallInst *Call, GetElementPtrInst *GEP, T *Insn, int Delta)

Definition BPFPreserveStaticOffset.cpp:288

static CallInst * isGEPAndStore(Value *I)

Definition BPFPreserveStaticOffset.cpp:145

static void setParamWriteOnly(CallInst *Call, unsigned ArgNo)

Definition BPFPreserveStaticOffset.cpp:183

static bool isIntrinsicCall(Value *I, Intrinsic::ID Id)

Definition BPFPreserveStaticOffset.cpp:128

static bool isPointerOperand(Value *I, User *U)

Definition BPFPreserveStaticOffset.cpp:431

static bool isIntrinsicCall(const CallBase *Call, Intrinsic::ID IID)

Analysis containing CSE Info

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

Module.h This file contains the declarations for the Module class.

static bool isZero(Value *V, const DataLayout &DL, DominatorTree *DT, AssumptionCache *AC)

This file defines the SmallPtrSet class.

This file defines the SmallVector class.

Class for arbitrary precision integers.

ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...

static LLVM_ABI Attribute get(LLVMContext &Context, AttrKind Kind, uint64_t Val=0)

Return a uniquified Attribute object.

static std::pair< GetElementPtrInst *, StoreInst * > reconstructStore(CallInst *Call)

Definition BPFPreserveStaticOffset.cpp:312

static std::pair< GetElementPtrInst *, LoadInst * > reconstructLoad(CallInst *Call)

Definition BPFPreserveStaticOffset.cpp:301

PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)

Definition BPFPreserveStaticOffset.cpp:672

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

static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)

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

static LLVM_ABI DebugLoc getMergedLocation(DebugLoc LocA, DebugLoc LocB)

When two instructions are combined into a single instruction we also need to combine the original loc...

Diagnostic information for unsupported feature in backend.

an instruction for type-safe pointer arithmetic to access elements of arrays and structs

static GetElementPtrInst * Create(Type *PointeeType, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)

const DebugLoc & getDebugLoc() const

Return the debug location for this node as a DebugLoc.

LLVM_ABI const Module * getModule() const

Return the module owning the function this instruction belongs to or nullptr it the function does not...

LLVM_ABI void insertBefore(InstListType::iterator InsertPos)

Insert an unlinked instruction into a basic block immediately before the specified position.

LLVM_ABI InstListType::iterator eraseFromParent()

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

LLVM_ABI const Function * getFunction() const

Return the function this instruction belongs to.

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

LLVM_ABI void diagnose(const DiagnosticInfo &DI)

Report a message to the currently installed diagnostic handler.

An instruction for reading from memory.

A Module instance is used to store all the information related to an LLVM module.

A set of analyses that are preserved following a run of a transformation pass.

static PreservedAnalyses none()

Convenience factory function for the empty preserved set.

static PreservedAnalyses all()

Construct a special preserved set that preserves all passes.

A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...

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

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

bool contains(ConstPtrType Ptr) const

SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.

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

void append(ItTy in_start, ItTy in_end)

Add the specified range to the end of the SmallVector.

void push_back(const T &Elt)

reverse_iterator rbegin()

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.

Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...

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

static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)

static LLVM_ABI IntegerType * getInt1Ty(LLVMContext &C)

Value * getOperand(unsigned i) const

LLVM Value Representation.

LLVM_ABI void replaceAllUsesWith(Value *V)

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

iterator_range< user_iterator > users()

LLVM_ABI LLVMContext & getContext() const

All values hold a context through their type.

self_iterator getIterator()

A raw_ostream that writes to an std::string.

A raw_ostream that writes to an SmallVector or SmallString.

@ C

The default llvm calling convention, compatible with C.

This namespace contains an enum with a value for every intrinsic/builtin function known by LLVM.

LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})

Look up the Function declaration of the intrinsic id in the Module M.

This is an optimization pass for GlobalISel generic memory operations.

auto drop_begin(T &&RangeOrContainer, size_t N=1)

Return a range covering RangeOrContainer with the first N elements excluded.

bool all_of(R &&range, UnaryPredicate P)

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

decltype(auto) dyn_cast(const From &Val)

dyn_cast - Return the argument parameter cast to the specified type.

unsigned Log2_64(uint64_t Value)

Return the floor log base 2 of the specified value, -1 if the value is zero.

detail::concat_range< ValueT, RangeTs... > concat(RangeTs &&...Ranges)

Returns a concatenated range across two or more ranges.

LLVM_ABI raw_ostream & dbgs()

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

LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)

class LLVM_GSL_OWNER SmallVector

Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...

bool isa(const From &Val)

isa - Return true if the parameter to the template is an instance of one of the template type argu...

AtomicOrdering

Atomic ordering for LLVM's memory model.

@ First

Helpers to iterate all locations in the MemoryEffectsBase class.

DWARFExpression::Operation Op

decltype(auto) cast(const From &Val)

cast - Return the argument parameter cast to the specified type.

AnalysisManager< Function > FunctionAnalysisManager

Convenience typedef for the Function analysis manager.

This struct is a compact representation of a valid (non-zero power of two) alignment.