1349cc55cSDimitry Andric //===------------ BPFIRPeephole.cpp - IR Peephole Transformation ----------===// 2349cc55cSDimitry Andric // 3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6349cc55cSDimitry Andric // 7349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 8349cc55cSDimitry Andric // 9349cc55cSDimitry Andric // IR level peephole optimization, specifically removing @llvm.stacksave() and 10349cc55cSDimitry Andric // @llvm.stackrestore(). 11349cc55cSDimitry Andric // 12349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 13349cc55cSDimitry Andric 14349cc55cSDimitry Andric #include "BPF.h" 15349cc55cSDimitry Andric #include "llvm/IR/Instruction.h" 16349cc55cSDimitry Andric #include "llvm/IR/Instructions.h" 17*bdd1243dSDimitry Andric #include "llvm/IR/IntrinsicInst.h" 18349cc55cSDimitry Andric #include "llvm/IR/Module.h" 19349cc55cSDimitry Andric #include "llvm/IR/PassManager.h" 20349cc55cSDimitry Andric #include "llvm/IR/Type.h" 21349cc55cSDimitry Andric #include "llvm/IR/User.h" 22349cc55cSDimitry Andric #include "llvm/IR/Value.h" 23349cc55cSDimitry Andric #include "llvm/Pass.h" 24349cc55cSDimitry Andric 25349cc55cSDimitry Andric #define DEBUG_TYPE "bpf-ir-peephole" 26349cc55cSDimitry Andric 27349cc55cSDimitry Andric using namespace llvm; 28349cc55cSDimitry Andric 29349cc55cSDimitry Andric namespace { 30349cc55cSDimitry Andric 31349cc55cSDimitry Andric static bool BPFIRPeepholeImpl(Function &F) { 32349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "******** BPF IR Peephole ********\n"); 33349cc55cSDimitry Andric 34349cc55cSDimitry Andric bool Changed = false; 35349cc55cSDimitry Andric Instruction *ToErase = nullptr; 36349cc55cSDimitry Andric for (auto &BB : F) { 37349cc55cSDimitry Andric for (auto &I : BB) { 38349cc55cSDimitry Andric // The following code pattern is handled: 39349cc55cSDimitry Andric // %3 = call i8* @llvm.stacksave() 40349cc55cSDimitry Andric // store i8* %3, i8** %saved_stack, align 8 41349cc55cSDimitry Andric // ... 42349cc55cSDimitry Andric // %4 = load i8*, i8** %saved_stack, align 8 43349cc55cSDimitry Andric // call void @llvm.stackrestore(i8* %4) 44349cc55cSDimitry Andric // ... 45349cc55cSDimitry Andric // The goal is to remove the above four instructions, 46349cc55cSDimitry Andric // so we won't have instructions with r11 (stack pointer) 47349cc55cSDimitry Andric // if eventually there is no variable length stack allocation. 48349cc55cSDimitry Andric // InstrCombine also tries to remove the above instructions, 49349cc55cSDimitry Andric // if it is proven safe (constant alloca etc.), but depending 50349cc55cSDimitry Andric // on code pattern, it may still miss some. 51349cc55cSDimitry Andric // 52349cc55cSDimitry Andric // With unconditionally removing these instructions, if alloca is 53349cc55cSDimitry Andric // constant, we are okay then. Otherwise, SelectionDag will complain 54349cc55cSDimitry Andric // since BPF does not support dynamic allocation yet. 55349cc55cSDimitry Andric if (ToErase) { 56349cc55cSDimitry Andric ToErase->eraseFromParent(); 57349cc55cSDimitry Andric ToErase = nullptr; 58349cc55cSDimitry Andric } 59349cc55cSDimitry Andric 60*bdd1243dSDimitry Andric if (auto *II = dyn_cast<IntrinsicInst>(&I)) { 61*bdd1243dSDimitry Andric if (II->getIntrinsicID() != Intrinsic::stacksave) 62349cc55cSDimitry Andric continue; 63*bdd1243dSDimitry Andric if (!II->hasOneUser()) 64349cc55cSDimitry Andric continue; 65*bdd1243dSDimitry Andric auto *Inst = cast<Instruction>(*II->user_begin()); 66349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "Remove:"; I.dump()); 67349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "Remove:"; Inst->dump(); dbgs() << '\n'); 68349cc55cSDimitry Andric Changed = true; 69349cc55cSDimitry Andric Inst->eraseFromParent(); 70349cc55cSDimitry Andric ToErase = &I; 71349cc55cSDimitry Andric continue; 72349cc55cSDimitry Andric } 73349cc55cSDimitry Andric 74349cc55cSDimitry Andric if (auto *LD = dyn_cast<LoadInst>(&I)) { 75349cc55cSDimitry Andric if (!LD->hasOneUser()) 76349cc55cSDimitry Andric continue; 77*bdd1243dSDimitry Andric auto *II = dyn_cast<IntrinsicInst>(*LD->user_begin()); 78*bdd1243dSDimitry Andric if (!II) 79349cc55cSDimitry Andric continue; 80*bdd1243dSDimitry Andric if (II->getIntrinsicID() != Intrinsic::stackrestore) 81349cc55cSDimitry Andric continue; 82349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "Remove:"; I.dump()); 83*bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Remove:"; II->dump(); dbgs() << '\n'); 84349cc55cSDimitry Andric Changed = true; 85*bdd1243dSDimitry Andric II->eraseFromParent(); 86349cc55cSDimitry Andric ToErase = &I; 87349cc55cSDimitry Andric } 88349cc55cSDimitry Andric } 89349cc55cSDimitry Andric } 90349cc55cSDimitry Andric 91349cc55cSDimitry Andric return Changed; 92349cc55cSDimitry Andric } 93349cc55cSDimitry Andric 94349cc55cSDimitry Andric class BPFIRPeephole final : public FunctionPass { 95349cc55cSDimitry Andric bool runOnFunction(Function &F) override; 96349cc55cSDimitry Andric 97349cc55cSDimitry Andric public: 98349cc55cSDimitry Andric static char ID; 99349cc55cSDimitry Andric BPFIRPeephole() : FunctionPass(ID) {} 100349cc55cSDimitry Andric }; 101349cc55cSDimitry Andric } // End anonymous namespace 102349cc55cSDimitry Andric 103349cc55cSDimitry Andric char BPFIRPeephole::ID = 0; 104349cc55cSDimitry Andric INITIALIZE_PASS(BPFIRPeephole, DEBUG_TYPE, "BPF IR Peephole", false, false) 105349cc55cSDimitry Andric 106349cc55cSDimitry Andric FunctionPass *llvm::createBPFIRPeephole() { return new BPFIRPeephole(); } 107349cc55cSDimitry Andric 108349cc55cSDimitry Andric bool BPFIRPeephole::runOnFunction(Function &F) { return BPFIRPeepholeImpl(F); } 109349cc55cSDimitry Andric 110349cc55cSDimitry Andric PreservedAnalyses BPFIRPeepholePass::run(Function &F, 111349cc55cSDimitry Andric FunctionAnalysisManager &AM) { 112349cc55cSDimitry Andric return BPFIRPeepholeImpl(F) ? PreservedAnalyses::none() 113349cc55cSDimitry Andric : PreservedAnalyses::all(); 114349cc55cSDimitry Andric } 115