LLVM: lib/Target/BPF/BPFCheckAndAdjustIR.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

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

36

37#define DEBUG_TYPE "bpf-check-and-opt-ir"

38

39using namespace llvm;

40

41namespace {

42

43class BPFCheckAndAdjustIR final : public ModulePass {

44 bool runOnModule(Module &F) override;

45

46public:

47 static char ID;

49 void getAnalysisUsage(AnalysisUsage &AU) const override;

50

51private:

52 void checkIR(Module &M);

53 bool adjustIR(Module &M);

54 bool removePassThroughBuiltin(Module &M);

55 bool removeCompareBuiltin(Module &M);

56 bool sinkMinMax(Module &M);

57 bool removeGEPBuiltins(Module &M);

58 bool insertASpaceCasts(Module &M);

59};

60}

61

62char BPFCheckAndAdjustIR::ID = 0;

64 false, false)

65

67 return new BPFCheckAndAdjustIR();

68}

69

70void BPFCheckAndAdjustIR::checkIR(Module &M) {

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86 for (Function &F : M)

87 for (auto &BB : F)

88 for (auto &I : BB) {

91 continue;

94 if (!GV)

95 continue;

99 }

100 }

101}

102

103bool BPFCheckAndAdjustIR::removePassThroughBuiltin(Module &M) {

104

105

106

108 CallInst *ToBeDeleted = nullptr;

109 for (Function &F : M)

110 for (auto &BB : F)

111 for (auto &I : BB) {

112 if (ToBeDeleted) {

114 ToBeDeleted = nullptr;

115 }

116

119 continue;

121 if (!GV)

122 continue;

123 if (!GV->getName().starts_with("llvm.bpf.passthrough"))

124 continue;

128 ToBeDeleted = Call;

129 }

131}

132

133bool BPFCheckAndAdjustIR::removeCompareBuiltin(Module &M) {

134

135

136

138 CallInst *ToBeDeleted = nullptr;

139 for (Function &F : M)

140 for (auto &BB : F)

141 for (auto &I : BB) {

142 if (ToBeDeleted) {

144 ToBeDeleted = nullptr;

145 }

146

149 continue;

151 if (!GV)

152 continue;

153 if (!GV->getName().starts_with("llvm.bpf.compare"))

154 continue;

155

160

163

164 auto *ICmp = new ICmpInst(Opcode, Arg1, Arg2);

166

168 ToBeDeleted = Call;

169 }

171}

172

185

188

189

190

191

192

195 V = ZExt->getOperand(0);

196 Info.ZExt = ZExt;

198 V = SExt->getOperand(0);

199 Info.SExt = SExt;

200 }

201

204 return false;

205

207 if (!Called)

208 return false;

209

210 switch (Called->getIntrinsicID()) {

211 case Intrinsic::smin:

212 case Intrinsic::umin:

213 case Intrinsic::smax:

214 case Intrinsic::umax:

215 break;

216 default:

217 return false;

218 }

219

221 return false;

222

224

225 return true;

226 };

227

230 if (Info.SExt) {

231 if (Info.SExt->getType() == V->getType())

232 return V;

233 return Builder.CreateSExt(V, Info.SExt->getType());

234 }

235 if (Info.ZExt) {

236 if (Info.ZExt->getType() == V->getType())

237 return V;

238 return Builder.CreateZExt(V, Info.ZExt->getType());

239 }

240 return V;

241 };

242

245

246

247

248

249

250

251

252

255 if (!ICmp)

256 continue;

258 continue;

262 bool FirstMinMax = IsMinMaxCall(ICmp->getOperand(0), First);

263 bool SecondMinMax = IsMinMaxCall(ICmp->getOperand(1), Second);

264 if (!(FirstMinMax ^ SecondMinMax))

265 continue;

267 }

268

269

270

271 for (auto &Info : SinkList) {

277 IID != Intrinsic::smax)

278 continue;

279

282 Value *A = ZeroOrSignExtend(Builder, MinMax->getArgOperand(0), Info);

283 Value *B = ZeroOrSignExtend(Builder, MinMax->getArgOperand(1), Info);

284 bool IsMin = IID == Intrinsic::smin || IID == Intrinsic::umin;

285 bool IsMax = IID == Intrinsic::smax || IID == Intrinsic::umax;

288 assert(IsMin ^ IsMax);

289 assert(IsLess ^ IsGreater);

290

291 Value *Replacement;

292 Value *LHS = Builder.CreateICmp(P, X, A);

293 Value *RHS = Builder.CreateICmp(P, X, B);

294 if ((IsLess && IsMin) || (IsGreater && IsMax))

295

296

297 Replacement = Builder.CreateLogicalAnd(LHS, RHS);

298 else

299

300

301 Replacement = Builder.CreateLogicalOr(LHS, RHS);

302

304

307 if (I && I->use_empty())

308 I->eraseFromParent();

309

311 }

312

314}

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343bool BPFCheckAndAdjustIR::sinkMinMax(Module &M) {

345

346 for (Function &F : M) {

347 if (F.isDeclaration())

348 continue;

349

350 LoopInfo &LI = getAnalysis(F).getLoopInfo();

351 for (Loop *L : LI)

352 for (BasicBlock *BB : L->blocks()) {

353

354 Loop *BBLoop = LI.getLoopFor(BB);

356 return LI.getLoopFor(I->getParent()) != BBLoop;

357 };

359 }

360 }

361

363}

364

365void BPFCheckAndAdjustIR::getAnalysisUsage(AnalysisUsage &AU) const {

367}

368

371 GEP->insertBefore(Call->getIterator());

372 Load->insertBefore(Call->getIterator());

373 Call->replaceAllUsesWith(Load);

374 Call->eraseFromParent();

375}

376

379 GEP->insertBefore(Call->getIterator());

380 Store->insertBefore(Call->getIterator());

381 Call->eraseFromParent();

382}

383

387 for (auto &BB : F)

388 for (auto &Insn : BB)

390 if (auto *Called = Call->getCalledFunction())

391 switch (Called->getIntrinsicID()) {

392 case Intrinsic::bpf_getelementptr_and_load:

394 break;

395 case Intrinsic::bpf_getelementptr_and_store:

397 break;

398 }

399

400 if (GEPLoads.empty() && GEPStores.empty())

401 return false;

402

405

406 return true;

407}

408

409

410

411

412

413bool BPFCheckAndAdjustIR::removeGEPBuiltins(Module &M) {

415 for (auto &F : M)

418}

419

420

421

422

423

424

425

426

427

428

431 auto It = Cache.find(ToWrap);

432 if (It != Cache.end())

433 return It->getSecond();

434

436 Value *Ptr = GEP->getPointerOperand();

439 auto *NewGEP = GEP->clone();

440 NewGEP->insertAfter(GEP->getIterator());

442 NewGEP->setOperand(GEP->getPointerOperandIndex(), WrappedPtr);

443 NewGEP->setName(GEP->getName());

444 Cache[ToWrap] = NewGEP;

445 return NewGEP;

446 }

447

450 IB.SetInsertPoint(*InsnPtr->getInsertionPointAfterDef());

451 else

452 IB.SetInsertPoint(F->getEntryBlock().getFirstInsertionPt());

453 auto *ASZeroPtrTy = IB.getPtrTy(0);

454 auto *ACast = IB.CreateAddrSpaceCast(ToWrap, ASZeroPtrTy, ToWrap->getName());

455 Cache[ToWrap] = ACast;

456 return ACast;

457}

458

459

460

462 unsigned OpNum) {

463 Value *OldOp = I->getOperand(OpNum);

465 return;

466

468 I->setOperand(OpNum, NewOp);

469

470

471 for (;;) {

473 if (!OldGEP)

474 break;

475 if (!OldGEP->use_empty())

476 break;

477 OldOp = OldGEP->getPointerOperand();

478 OldGEP->eraseFromParent();

479 }

480}

481

485 if (PTy->getAddressSpace() == 0)

486 return P;

487 }

489}

490

496

499 if (OldDst == NewDst)

500 return nullptr;

501

502

505

508 bool IsVolatile = MS->isVolatile();

509

510 if (ID == Intrinsic::memset)

511 return B.CreateMemSet(NewDst, Val, Len, Align, IsVolatile,

512 MI->getAAMetadata());

513 else

514 return B.CreateMemSetInline(NewDst, Align, Val, Len, IsVolatile,

515 MI->getAAMetadata());

516}

517

523

528 if (OldDst == NewDst && OldSrc == NewSrc)

529 return nullptr;

530

531

533

535 MaybeAlign DstAlign = MT->getDestAlign();

536 MaybeAlign SrcAlign = MT->getSourceAlign();

537 bool IsVolatile = MT->isVolatile();

538

539 return B.CreateMemTransferInst(ID, NewDst, DstAlign, NewSrc, SrcAlign, Len,

540 IsVolatile, MI->getAAMetadata());

541}

542

547

552 if (OldDst == NewDst && OldSrc == NewSrc)

553 return nullptr;

554

555

557

559 MaybeAlign DstAlign = MT->getDestAlign();

560 MaybeAlign SrcAlign = MT->getSourceAlign();

561 bool IsVolatile = MT->isVolatile();

562

563 return B.CreateMemMove(NewDst, DstAlign, NewSrc, SrcAlign, Len, IsVolatile,

564 MI->getAAMetadata());

565}

566

567

568

569

570

571

572

573

574

575

576

577

578bool BPFCheckAndAdjustIR::insertASpaceCasts(Module &M) {

580 for (Function &F : M) {

581 DenseMap<Value *, Value *> CastsCache;

582 for (BasicBlock &BB : F) {

584 unsigned PtrOpNum;

585

587 PtrOpNum = LD->getPointerOperandIndex();

589 continue;

590 }

592 PtrOpNum = ST->getPointerOperandIndex();

594 continue;

595 }

597 PtrOpNum = CmpXchg->getPointerOperandIndex();

599 continue;

600 }

602 PtrOpNum = RMW->getPointerOperandIndex();

604 continue;

605 }

606

608 if (!CI)

609 continue;

610

612 if (!Callee || Callee->isIntrinsic())

613 continue;

614

615

617 bool IsSet = ID == Intrinsic::memset || ID == Intrinsic::memset_inline;

618 bool IsCpy = ID == Intrinsic::memcpy || ID == Intrinsic::memcpy_inline;

619 bool IsMove = ID == Intrinsic::memmove;

620 if (!IsSet && !IsCpy && !IsMove)

621 continue;

622

624 if (IsSet)

626 else if (IsCpy)

628 else

630

631 if (!New)

632 continue;

633

634 I.replaceAllUsesWith(New);

635 New->takeName(&I);

636 I.eraseFromParent();

637 }

638 }

640 }

641

642

643 for (GlobalVariable &G : M.globals()) {

644 if (G.getAddressSpace() == 0 || G.hasSection())

645 continue;

646 SmallString<16> SecName;

647 raw_svector_ostream OS(SecName);

648 OS << ".addr_space." << G.getAddressSpace();

649 G.setSection(SecName);

650

651 G.setConstant(false);

652 }

654}

655

656bool BPFCheckAndAdjustIR::adjustIR(Module &M) {

657 bool Changed = removePassThroughBuiltin(M);

663}

664

665bool BPFCheckAndAdjustIR::runOnModule(Module &M) {

666 checkIR(M);

667 return adjustIR(M);

668}

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

ReachingDefInfo InstSet & ToRemove

static Instruction * aspaceMemSet(Intrinsic::ID ID, DenseMap< Value *, Value * > &Cache, CallInst *CI)

Definition BPFCheckAndAdjustIR.cpp:491

static Instruction * aspaceMemCpy(Intrinsic::ID ID, DenseMap< Value *, Value * > &Cache, CallInst *CI)

Definition BPFCheckAndAdjustIR.cpp:518

static Instruction * aspaceMemMove(DenseMap< Value *, Value * > &Cache, CallInst *CI)

Definition BPFCheckAndAdjustIR.cpp:543

static bool sinkMinMaxInBB(BasicBlock &BB, const std::function< bool(Instruction *)> &Filter)

Definition BPFCheckAndAdjustIR.cpp:186

static Value * wrapPtrIfASNotZero(DenseMap< Value *, Value * > &Cache, CallInst *CI, Value *P)

Definition BPFCheckAndAdjustIR.cpp:482

static void aspaceWrapOperand(DenseMap< Value *, Value * > &Cache, Instruction *I, unsigned OpNum)

Definition BPFCheckAndAdjustIR.cpp:461

static void unrollGEPStore(CallInst *Call)

Definition BPFCheckAndAdjustIR.cpp:377

static Value * aspaceWrapValue(DenseMap< Value *, Value * > &Cache, Function *F, Value *ToWrap)

Definition BPFCheckAndAdjustIR.cpp:429

static void unrollGEPLoad(CallInst *Call)

Definition BPFCheckAndAdjustIR.cpp:369

static bool removeGEPBuiltinsInFunc(Function &F)

Definition BPFCheckAndAdjustIR.cpp:384

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

static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")

Analysis containing CSE Info

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

Machine Check Debug Module

#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)

static TableGen::Emitter::OptClass< SkeletonEmitter > X("gen-skeleton-class", "Generate example skeleton class")

Represent the analysis usage information of a pass.

AnalysisUsage & addRequired()

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

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

LLVM Basic Block Representation.

Value * getCalledOperand() const

Value * getArgOperand(unsigned i) const

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

Predicate

This enumeration lists the possible predicates for CmpInst subclasses.

Predicate getSwappedPredicate() const

For example, EQ->EQ, SLE->SGE, ULT->UGT, OEQ->OEQ, ULE->UGE, OLT->OGT, etc.

Predicate getPredicate() const

Return the predicate for this instruction.

This instruction compares its operands according to the predicate given to the constructor.

static bool isGE(Predicate P)

Return true if the predicate is SGE or UGE.

static bool isLT(Predicate P)

Return true if the predicate is SLT or ULT.

static bool isGT(Predicate P)

Return true if the predicate is SGT or UGT.

bool isRelational() const

Return true if the predicate is relational (not EQ or NE).

static bool isLE(Predicate P)

Return true if the predicate is SLE or ULE.

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

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.

ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...

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

Value * getIncomingValue(unsigned i) const

Return incoming value number x.

unsigned getNumIncomingValues() const

Return the number of incoming edges.

static PointerType * getUnqual(Type *ElementType)

This constructs a pointer to an object of the specified type in the default address space (address sp...

This class represents a sign extension of integer types.

void push_back(const T &Elt)

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

LLVM_ABI unsigned getPointerAddressSpace() const

Get the address space of this pointer or pointer vector type.

Value * getOperand(unsigned i) const

LLVM Value Representation.

Type * getType() const

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

LLVM_ABI void replaceAllUsesWith(Value *V)

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

LLVM_ABI StringRef getName() const

Return a constant reference to the value's name.

This class represents zero extension of integer types.

self_iterator getIterator()

unsigned ID

LLVM IR allows to use arbitrary numbers as calling convention identifiers.

friend class Instruction

Iterator for Instructions in a `BasicBlock.

This is an optimization pass for GlobalISel generic memory operations.

FunctionAddr VTableAddr Value

UnaryFunction for_each(R &&Range, UnaryFunction F)

Provide wrappers to std::for_each 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.

ModulePass * createBPFCheckAndAdjustIR()

iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)

Make a range that does early increment to allow mutation of the underlying range without disrupting i...

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

@ First

Helpers to iterate all locations in the MemoryEffectsBase class.

decltype(auto) cast(const From &Val)

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

SExtInst * SExt

Definition BPFCheckAndAdjustIR.cpp:179

CallInst * MinMax

Definition BPFCheckAndAdjustIR.cpp:177

ICmpInst::Predicate Predicate

Definition BPFCheckAndAdjustIR.cpp:176

MinMaxSinkInfo(ICmpInst *ICmp, Value *Other, ICmpInst::Predicate Predicate)

Definition BPFCheckAndAdjustIR.cpp:181

Value * Other

Definition BPFCheckAndAdjustIR.cpp:175

ZExtInst * ZExt

Definition BPFCheckAndAdjustIR.cpp:178

ICmpInst * ICmp

Definition BPFCheckAndAdjustIR.cpp:174

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

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