669 lines · cpp
1//===------------ BPFCheckAndAdjustIR.cpp - Check and Adjust IR -----------===//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-exception6//7//===----------------------------------------------------------------------===//8//9// Check IR and adjust IR for verifier friendly codes.10// The following are done for IR checking:11// - no relocation globals in PHI node.12// The following are done for IR adjustment:13// - remove __builtin_bpf_passthrough builtins. Target independent IR14// optimizations are done and those builtins can be removed.15// - remove llvm.bpf.getelementptr.and.load builtins.16// - remove llvm.bpf.getelementptr.and.store builtins.17// - for loads and stores with base addresses from non-zero address space18// cast base address to zero address space (support for BPF address spaces).19//20//===----------------------------------------------------------------------===//21 22#include "BPF.h"23#include "BPFCORE.h"24#include "llvm/Analysis/LoopInfo.h"25#include "llvm/IR/GlobalVariable.h"26#include "llvm/IR/IRBuilder.h"27#include "llvm/IR/Instruction.h"28#include "llvm/IR/Instructions.h"29#include "llvm/IR/IntrinsicInst.h"30#include "llvm/IR/IntrinsicsBPF.h"31#include "llvm/IR/Module.h"32#include "llvm/IR/Type.h"33#include "llvm/IR/Value.h"34#include "llvm/Pass.h"35#include "llvm/Transforms/Utils/BasicBlockUtils.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;48 BPFCheckAndAdjustIR() : ModulePass(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} // End anonymous namespace61 62char BPFCheckAndAdjustIR::ID = 0;63INITIALIZE_PASS(BPFCheckAndAdjustIR, DEBUG_TYPE, "BPF Check And Adjust IR",64 false, false)65 66ModulePass *llvm::createBPFCheckAndAdjustIR() {67 return new BPFCheckAndAdjustIR();68}69 70void BPFCheckAndAdjustIR::checkIR(Module &M) {71 // Ensure relocation global won't appear in PHI node72 // This may happen if the compiler generated the following code:73 // B1:74 // g1 = @llvm.skb_buff:0:1...75 // ...76 // goto B_COMMON77 // B2:78 // g2 = @llvm.skb_buff:0:2...79 // ...80 // goto B_COMMON81 // B_COMMON:82 // g = PHI(g1, g2)83 // x = load g84 // ...85 // If anything likes the above "g = PHI(g1, g2)", issue a fatal error.86 for (Function &F : M)87 for (auto &BB : F)88 for (auto &I : BB) {89 PHINode *PN = dyn_cast<PHINode>(&I);90 if (!PN || PN->use_empty())91 continue;92 for (int i = 0, e = PN->getNumIncomingValues(); i < e; ++i) {93 auto *GV = dyn_cast<GlobalVariable>(PN->getIncomingValue(i));94 if (!GV)95 continue;96 if (GV->hasAttribute(BPFCoreSharedInfo::AmaAttr) ||97 GV->hasAttribute(BPFCoreSharedInfo::TypeIdAttr))98 report_fatal_error("relocation global in PHI node");99 }100 }101}102 103bool BPFCheckAndAdjustIR::removePassThroughBuiltin(Module &M) {104 // Remove __builtin_bpf_passthrough()'s which are used to prevent105 // certain IR optimizations. Now major IR optimizations are done,106 // remove them.107 bool Changed = false;108 CallInst *ToBeDeleted = nullptr;109 for (Function &F : M)110 for (auto &BB : F)111 for (auto &I : BB) {112 if (ToBeDeleted) {113 ToBeDeleted->eraseFromParent();114 ToBeDeleted = nullptr;115 }116 117 auto *Call = dyn_cast<CallInst>(&I);118 if (!Call)119 continue;120 auto *GV = dyn_cast<GlobalValue>(Call->getCalledOperand());121 if (!GV)122 continue;123 if (!GV->getName().starts_with("llvm.bpf.passthrough"))124 continue;125 Changed = true;126 Value *Arg = Call->getArgOperand(1);127 Call->replaceAllUsesWith(Arg);128 ToBeDeleted = Call;129 }130 return Changed;131}132 133bool BPFCheckAndAdjustIR::removeCompareBuiltin(Module &M) {134 // Remove __builtin_bpf_compare()'s which are used to prevent135 // certain IR optimizations. Now major IR optimizations are done,136 // remove them.137 bool Changed = false;138 CallInst *ToBeDeleted = nullptr;139 for (Function &F : M)140 for (auto &BB : F)141 for (auto &I : BB) {142 if (ToBeDeleted) {143 ToBeDeleted->eraseFromParent();144 ToBeDeleted = nullptr;145 }146 147 auto *Call = dyn_cast<CallInst>(&I);148 if (!Call)149 continue;150 auto *GV = dyn_cast<GlobalValue>(Call->getCalledOperand());151 if (!GV)152 continue;153 if (!GV->getName().starts_with("llvm.bpf.compare"))154 continue;155 156 Changed = true;157 Value *Arg0 = Call->getArgOperand(0);158 Value *Arg1 = Call->getArgOperand(1);159 Value *Arg2 = Call->getArgOperand(2);160 161 auto OpVal = cast<ConstantInt>(Arg0)->getValue().getZExtValue();162 CmpInst::Predicate Opcode = (CmpInst::Predicate)OpVal;163 164 auto *ICmp = new ICmpInst(Opcode, Arg1, Arg2);165 ICmp->insertBefore(Call->getIterator());166 167 Call->replaceAllUsesWith(ICmp);168 ToBeDeleted = Call;169 }170 return Changed;171}172 173struct MinMaxSinkInfo {174 ICmpInst *ICmp;175 Value *Other;176 ICmpInst::Predicate Predicate;177 CallInst *MinMax;178 ZExtInst *ZExt;179 SExtInst *SExt;180 181 MinMaxSinkInfo(ICmpInst *ICmp, Value *Other, ICmpInst::Predicate Predicate)182 : ICmp(ICmp), Other(Other), Predicate(Predicate), MinMax(nullptr),183 ZExt(nullptr), SExt(nullptr) {}184};185 186static bool sinkMinMaxInBB(BasicBlock &BB,187 const std::function<bool(Instruction *)> &Filter) {188 // Check if V is:189 // (fn %a %b) or (ext (fn %a %b))190 // Where:191 // ext := sext | zext192 // fn := smin | umin | smax | umax193 auto IsMinMaxCall = [=](Value *V, MinMaxSinkInfo &Info) {194 if (auto *ZExt = dyn_cast<ZExtInst>(V)) {195 V = ZExt->getOperand(0);196 Info.ZExt = ZExt;197 } else if (auto *SExt = dyn_cast<SExtInst>(V)) {198 V = SExt->getOperand(0);199 Info.SExt = SExt;200 }201 202 auto *Call = dyn_cast<CallInst>(V);203 if (!Call)204 return false;205 206 auto *Called = dyn_cast<Function>(Call->getCalledOperand());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 220 if (!Filter(Call))221 return false;222 223 Info.MinMax = Call;224 225 return true;226 };227 228 auto ZeroOrSignExtend = [](IRBuilder<> &Builder, Value *V,229 MinMaxSinkInfo &Info) {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 243 bool Changed = false;244 SmallVector<MinMaxSinkInfo, 2> SinkList;245 246 // Check BB for instructions like:247 // insn := (icmp %a (fn ...)) | (icmp (fn ...) %a)248 //249 // Where:250 // fn := min | max | (sext (min ...)) | (sext (max ...))251 //252 // Put such instructions to SinkList.253 for (Instruction &I : BB) {254 ICmpInst *ICmp = dyn_cast<ICmpInst>(&I);255 if (!ICmp)256 continue;257 if (!ICmp->isRelational())258 continue;259 MinMaxSinkInfo First(ICmp, ICmp->getOperand(1),260 ICmpInst::getSwappedPredicate(ICmp->getPredicate()));261 MinMaxSinkInfo Second(ICmp, ICmp->getOperand(0), ICmp->getPredicate());262 bool FirstMinMax = IsMinMaxCall(ICmp->getOperand(0), First);263 bool SecondMinMax = IsMinMaxCall(ICmp->getOperand(1), Second);264 if (!(FirstMinMax ^ SecondMinMax))265 continue;266 SinkList.push_back(FirstMinMax ? First : Second);267 }268 269 // Iterate SinkList and replace each (icmp ...) with corresponding270 // `x < a && x < b` or similar expression.271 for (auto &Info : SinkList) {272 ICmpInst *ICmp = Info.ICmp;273 CallInst *MinMax = Info.MinMax;274 Intrinsic::ID IID = MinMax->getCalledFunction()->getIntrinsicID();275 ICmpInst::Predicate P = Info.Predicate;276 if (ICmpInst::isSigned(P) && IID != Intrinsic::smin &&277 IID != Intrinsic::smax)278 continue;279 280 IRBuilder<> Builder(ICmp);281 Value *X = Info.Other;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;286 bool IsLess = ICmpInst::isLE(P) || ICmpInst::isLT(P);287 bool IsGreater = ICmpInst::isGE(P) || ICmpInst::isGT(P);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 // x < min(a, b) -> x < a && x < b296 // x > max(a, b) -> x > a && x > b297 Replacement = Builder.CreateLogicalAnd(LHS, RHS);298 else299 // x > min(a, b) -> x > a || x > b300 // x < max(a, b) -> x < a || x < b301 Replacement = Builder.CreateLogicalOr(LHS, RHS);302 303 ICmp->replaceAllUsesWith(Replacement);304 305 Instruction *ToRemove[] = {ICmp, Info.ZExt, Info.SExt, MinMax};306 for (Instruction *I : ToRemove)307 if (I && I->use_empty())308 I->eraseFromParent();309 310 Changed = true;311 }312 313 return Changed;314}315 316// Do the following transformation:317//318// x < min(a, b) -> x < a && x < b319// x > min(a, b) -> x > a || x > b320// x < max(a, b) -> x < a || x < b321// x > max(a, b) -> x > a && x > b322//323// Such patterns are introduced by LICM.cpp:hoistMinMax()324// transformation and might lead to BPF verification failures for325// older kernels.326//327// To minimize "collateral" changes only do it for icmp + min/max328// calls when icmp is inside a loop and min/max is outside of that329// loop.330//331// Verification failure happens when:332// - RHS operand of some `icmp LHS, RHS` is replaced by some RHS1;333// - verifier can recognize RHS as a constant scalar in some context;334// - verifier can't recognize RHS1 as a constant scalar in the same335// context;336//337// The "constant scalar" is not a compile time constant, but a register338// that holds a scalar value known to verifier at some point in time339// during abstract interpretation.340//341// See also:342// https://lore.kernel.org/bpf/20230406164505.1046801-1-yhs@fb.com/343bool BPFCheckAndAdjustIR::sinkMinMax(Module &M) {344 bool Changed = false;345 346 for (Function &F : M) {347 if (F.isDeclaration())348 continue;349 350 LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>(F).getLoopInfo();351 for (Loop *L : LI)352 for (BasicBlock *BB : L->blocks()) {353 // Filter out instructions coming from the same loop354 Loop *BBLoop = LI.getLoopFor(BB);355 auto OtherLoopFilter = [&](Instruction *I) {356 return LI.getLoopFor(I->getParent()) != BBLoop;357 };358 Changed |= sinkMinMaxInBB(*BB, OtherLoopFilter);359 }360 }361 362 return Changed;363}364 365void BPFCheckAndAdjustIR::getAnalysisUsage(AnalysisUsage &AU) const {366 AU.addRequired<LoopInfoWrapperPass>();367}368 369static void unrollGEPLoad(CallInst *Call) {370 auto [GEP, Load] = BPFPreserveStaticOffsetPass::reconstructLoad(Call);371 GEP->insertBefore(Call->getIterator());372 Load->insertBefore(Call->getIterator());373 Call->replaceAllUsesWith(Load);374 Call->eraseFromParent();375}376 377static void unrollGEPStore(CallInst *Call) {378 auto [GEP, Store] = BPFPreserveStaticOffsetPass::reconstructStore(Call);379 GEP->insertBefore(Call->getIterator());380 Store->insertBefore(Call->getIterator());381 Call->eraseFromParent();382}383 384static bool removeGEPBuiltinsInFunc(Function &F) {385 SmallVector<CallInst *> GEPLoads;386 SmallVector<CallInst *> GEPStores;387 for (auto &BB : F)388 for (auto &Insn : BB)389 if (auto *Call = dyn_cast<CallInst>(&Insn))390 if (auto *Called = Call->getCalledFunction())391 switch (Called->getIntrinsicID()) {392 case Intrinsic::bpf_getelementptr_and_load:393 GEPLoads.push_back(Call);394 break;395 case Intrinsic::bpf_getelementptr_and_store:396 GEPStores.push_back(Call);397 break;398 }399 400 if (GEPLoads.empty() && GEPStores.empty())401 return false;402 403 for_each(GEPLoads, unrollGEPLoad);404 for_each(GEPStores, unrollGEPStore);405 406 return true;407}408 409// Rewrites the following builtins:410// - llvm.bpf.getelementptr.and.load411// - llvm.bpf.getelementptr.and.store412// As (load (getelementptr ...)) or (store (getelementptr ...)).413bool BPFCheckAndAdjustIR::removeGEPBuiltins(Module &M) {414 bool Changed = false;415 for (auto &F : M)416 Changed = removeGEPBuiltinsInFunc(F) || Changed;417 return Changed;418}419 420// Wrap ToWrap with cast to address space zero:421// - if ToWrap is a getelementptr,422// wrap it's base pointer instead and return a copy;423// - if ToWrap is Instruction, insert address space cast424// immediately after ToWrap;425// - if ToWrap is not an Instruction (function parameter426// or a global value), insert address space cast at the427// beginning of the Function F;428// - use Cache to avoid inserting too many casts;429static Value *aspaceWrapValue(DenseMap<Value *, Value *> &Cache, Function *F,430 Value *ToWrap) {431 auto It = Cache.find(ToWrap);432 if (It != Cache.end())433 return It->getSecond();434 435 if (auto *GEP = dyn_cast<GetElementPtrInst>(ToWrap)) {436 Value *Ptr = GEP->getPointerOperand();437 Value *WrappedPtr = aspaceWrapValue(Cache, F, Ptr);438 auto *GEPTy = cast<PointerType>(GEP->getType());439 auto *NewGEP = GEP->clone();440 NewGEP->insertAfter(GEP->getIterator());441 NewGEP->mutateType(PointerType::getUnqual(GEPTy->getContext()));442 NewGEP->setOperand(GEP->getPointerOperandIndex(), WrappedPtr);443 NewGEP->setName(GEP->getName());444 Cache[ToWrap] = NewGEP;445 return NewGEP;446 }447 448 IRBuilder IB(F->getContext());449 if (Instruction *InsnPtr = dyn_cast<Instruction>(ToWrap))450 IB.SetInsertPoint(*InsnPtr->getInsertionPointAfterDef());451 else452 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// Wrap a pointer operand OpNum of instruction I460// with cast to address space zero461static void aspaceWrapOperand(DenseMap<Value *, Value *> &Cache, Instruction *I,462 unsigned OpNum) {463 Value *OldOp = I->getOperand(OpNum);464 if (OldOp->getType()->getPointerAddressSpace() == 0)465 return;466 467 Value *NewOp = aspaceWrapValue(Cache, I->getFunction(), OldOp);468 I->setOperand(OpNum, NewOp);469 // Check if there are any remaining users of old GEP,470 // delete those w/o users471 for (;;) {472 auto *OldGEP = dyn_cast<GetElementPtrInst>(OldOp);473 if (!OldGEP)474 break;475 if (!OldGEP->use_empty())476 break;477 OldOp = OldGEP->getPointerOperand();478 OldGEP->eraseFromParent();479 }480}481 482static Value *wrapPtrIfASNotZero(DenseMap<Value *, Value *> &Cache,483 CallInst *CI, Value *P) {484 if (auto *PTy = dyn_cast<PointerType>(P->getType())) {485 if (PTy->getAddressSpace() == 0)486 return P;487 }488 return aspaceWrapValue(Cache, CI->getFunction(), P);489}490 491static Instruction *aspaceMemSet(Intrinsic::ID ID,492 DenseMap<Value *, Value *> &Cache,493 CallInst *CI) {494 auto *MI = cast<MemIntrinsic>(CI);495 IRBuilder<> B(CI);496 497 Value *OldDst = CI->getArgOperand(0);498 Value *NewDst = wrapPtrIfASNotZero(Cache, CI, OldDst);499 if (OldDst == NewDst)500 return nullptr;501 502 // memset(new_dst, val, len, align, isvolatile, md)503 Value *Val = CI->getArgOperand(1);504 Value *Len = CI->getArgOperand(2);505 506 auto *MS = cast<MemSetInst>(CI);507 MaybeAlign Align = MS->getDestAlign();508 bool IsVolatile = MS->isVolatile();509 510 if (ID == Intrinsic::memset)511 return B.CreateMemSet(NewDst, Val, Len, Align, IsVolatile,512 MI->getAAMetadata());513 else514 return B.CreateMemSetInline(NewDst, Align, Val, Len, IsVolatile,515 MI->getAAMetadata());516}517 518static Instruction *aspaceMemCpy(Intrinsic::ID ID,519 DenseMap<Value *, Value *> &Cache,520 CallInst *CI) {521 auto *MI = cast<MemIntrinsic>(CI);522 IRBuilder<> B(CI);523 524 Value *OldDst = CI->getArgOperand(0);525 Value *OldSrc = CI->getArgOperand(1);526 Value *NewDst = wrapPtrIfASNotZero(Cache, CI, OldDst);527 Value *NewSrc = wrapPtrIfASNotZero(Cache, CI, OldSrc);528 if (OldDst == NewDst && OldSrc == NewSrc)529 return nullptr;530 531 // memcpy(new_dst, dst_align, new_src, src_align, len, isvolatile, md)532 Value *Len = CI->getArgOperand(2);533 534 auto *MT = cast<MemTransferInst>(CI);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 543static Instruction *aspaceMemMove(DenseMap<Value *, Value *> &Cache,544 CallInst *CI) {545 auto *MI = cast<MemIntrinsic>(CI);546 IRBuilder<> B(CI);547 548 Value *OldDst = CI->getArgOperand(0);549 Value *OldSrc = CI->getArgOperand(1);550 Value *NewDst = wrapPtrIfASNotZero(Cache, CI, OldDst);551 Value *NewSrc = wrapPtrIfASNotZero(Cache, CI, OldSrc);552 if (OldDst == NewDst && OldSrc == NewSrc)553 return nullptr;554 555 // memmove(new_dst, dst_align, new_src, src_align, len, isvolatile, md)556 Value *Len = CI->getArgOperand(2);557 558 auto *MT = cast<MemTransferInst>(CI);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// Support for BPF address spaces:568// - for each function in the module M, update pointer operand of569// each memory access instruction (load/store/cmpxchg/atomicrmw)570// or intrinsic call insns (memset/memcpy/memmove)571// by casting it from non-zero address space to zero address space, e.g:572//573// (load (ptr addrspace (N) %p) ...)574// -> (load (addrspacecast ptr addrspace (N) %p to ptr))575//576// - assign section with name .addr_space.N for globals defined in577// non-zero address space N578bool BPFCheckAndAdjustIR::insertASpaceCasts(Module &M) {579 bool Changed = false;580 for (Function &F : M) {581 DenseMap<Value *, Value *> CastsCache;582 for (BasicBlock &BB : F) {583 for (Instruction &I : llvm::make_early_inc_range(BB)) {584 unsigned PtrOpNum;585 586 if (auto *LD = dyn_cast<LoadInst>(&I)) {587 PtrOpNum = LD->getPointerOperandIndex();588 aspaceWrapOperand(CastsCache, &I, PtrOpNum);589 continue;590 }591 if (auto *ST = dyn_cast<StoreInst>(&I)) {592 PtrOpNum = ST->getPointerOperandIndex();593 aspaceWrapOperand(CastsCache, &I, PtrOpNum);594 continue;595 }596 if (auto *CmpXchg = dyn_cast<AtomicCmpXchgInst>(&I)) {597 PtrOpNum = CmpXchg->getPointerOperandIndex();598 aspaceWrapOperand(CastsCache, &I, PtrOpNum);599 continue;600 }601 if (auto *RMW = dyn_cast<AtomicRMWInst>(&I)) {602 PtrOpNum = RMW->getPointerOperandIndex();603 aspaceWrapOperand(CastsCache, &I, PtrOpNum);604 continue;605 }606 607 auto *CI = dyn_cast<CallInst>(&I);608 if (!CI)609 continue;610 611 Function *Callee = CI->getCalledFunction();612 if (!Callee || !Callee->isIntrinsic())613 continue;614 615 // Check memset/memcpy/memmove616 Intrinsic::ID ID = Callee->getIntrinsicID();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 623 Instruction *New;624 if (IsSet)625 New = aspaceMemSet(ID, CastsCache, CI);626 else if (IsCpy)627 New = aspaceMemCpy(ID, CastsCache, CI);628 else629 New = aspaceMemMove(CastsCache, CI);630 631 if (!New)632 continue;633 634 I.replaceAllUsesWith(New);635 New->takeName(&I);636 I.eraseFromParent();637 }638 }639 Changed |= !CastsCache.empty();640 }641 // Merge all globals within same address space into single642 // .addr_space.<addr space no> section643 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 // Prevent having separate section for constants651 G.setConstant(false);652 }653 return Changed;654}655 656bool BPFCheckAndAdjustIR::adjustIR(Module &M) {657 bool Changed = removePassThroughBuiltin(M);658 Changed = removeCompareBuiltin(M) || Changed;659 Changed = sinkMinMax(M) || Changed;660 Changed = removeGEPBuiltins(M) || Changed;661 Changed = insertASpaceCasts(M) || Changed;662 return Changed;663}664 665bool BPFCheckAndAdjustIR::runOnModule(Module &M) {666 checkIR(M);667 return adjustIR(M);668}669