1*349cc55cSDimitry Andric //===------------ BPFIRPeephole.cpp - IR Peephole Transformation ----------===// 2*349cc55cSDimitry Andric // 3*349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*349cc55cSDimitry Andric // 7*349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 8*349cc55cSDimitry Andric // 9*349cc55cSDimitry Andric // IR level peephole optimization, specifically removing @llvm.stacksave() and 10*349cc55cSDimitry Andric // @llvm.stackrestore(). 11*349cc55cSDimitry Andric // 12*349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 13*349cc55cSDimitry Andric 14*349cc55cSDimitry Andric #include "BPF.h" 15*349cc55cSDimitry Andric #include "llvm/IR/Instruction.h" 16*349cc55cSDimitry Andric #include "llvm/IR/Instructions.h" 17*349cc55cSDimitry Andric #include "llvm/IR/Module.h" 18*349cc55cSDimitry Andric #include "llvm/IR/PassManager.h" 19*349cc55cSDimitry Andric #include "llvm/IR/Type.h" 20*349cc55cSDimitry Andric #include "llvm/IR/User.h" 21*349cc55cSDimitry Andric #include "llvm/IR/Value.h" 22*349cc55cSDimitry Andric #include "llvm/Pass.h" 23*349cc55cSDimitry Andric 24*349cc55cSDimitry Andric #define DEBUG_TYPE "bpf-ir-peephole" 25*349cc55cSDimitry Andric 26*349cc55cSDimitry Andric using namespace llvm; 27*349cc55cSDimitry Andric 28*349cc55cSDimitry Andric namespace { 29*349cc55cSDimitry Andric 30*349cc55cSDimitry Andric static bool BPFIRPeepholeImpl(Function &F) { 31*349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "******** BPF IR Peephole ********\n"); 32*349cc55cSDimitry Andric 33*349cc55cSDimitry Andric bool Changed = false; 34*349cc55cSDimitry Andric Instruction *ToErase = nullptr; 35*349cc55cSDimitry Andric for (auto &BB : F) { 36*349cc55cSDimitry Andric for (auto &I : BB) { 37*349cc55cSDimitry Andric // The following code pattern is handled: 38*349cc55cSDimitry Andric // %3 = call i8* @llvm.stacksave() 39*349cc55cSDimitry Andric // store i8* %3, i8** %saved_stack, align 8 40*349cc55cSDimitry Andric // ... 41*349cc55cSDimitry Andric // %4 = load i8*, i8** %saved_stack, align 8 42*349cc55cSDimitry Andric // call void @llvm.stackrestore(i8* %4) 43*349cc55cSDimitry Andric // ... 44*349cc55cSDimitry Andric // The goal is to remove the above four instructions, 45*349cc55cSDimitry Andric // so we won't have instructions with r11 (stack pointer) 46*349cc55cSDimitry Andric // if eventually there is no variable length stack allocation. 47*349cc55cSDimitry Andric // InstrCombine also tries to remove the above instructions, 48*349cc55cSDimitry Andric // if it is proven safe (constant alloca etc.), but depending 49*349cc55cSDimitry Andric // on code pattern, it may still miss some. 50*349cc55cSDimitry Andric // 51*349cc55cSDimitry Andric // With unconditionally removing these instructions, if alloca is 52*349cc55cSDimitry Andric // constant, we are okay then. Otherwise, SelectionDag will complain 53*349cc55cSDimitry Andric // since BPF does not support dynamic allocation yet. 54*349cc55cSDimitry Andric if (ToErase) { 55*349cc55cSDimitry Andric ToErase->eraseFromParent(); 56*349cc55cSDimitry Andric ToErase = nullptr; 57*349cc55cSDimitry Andric } 58*349cc55cSDimitry Andric 59*349cc55cSDimitry Andric if (auto *Call = dyn_cast<CallInst>(&I)) { 60*349cc55cSDimitry Andric if (auto *GV = dyn_cast<GlobalValue>(Call->getCalledOperand())) { 61*349cc55cSDimitry Andric if (!GV->getName().equals("llvm.stacksave")) 62*349cc55cSDimitry Andric continue; 63*349cc55cSDimitry Andric if (!Call->hasOneUser()) 64*349cc55cSDimitry Andric continue; 65*349cc55cSDimitry Andric auto *Inst = cast<Instruction>(*Call->user_begin()); 66*349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "Remove:"; I.dump()); 67*349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "Remove:"; Inst->dump(); dbgs() << '\n'); 68*349cc55cSDimitry Andric Changed = true; 69*349cc55cSDimitry Andric Inst->eraseFromParent(); 70*349cc55cSDimitry Andric ToErase = &I; 71*349cc55cSDimitry Andric } 72*349cc55cSDimitry Andric continue; 73*349cc55cSDimitry Andric } 74*349cc55cSDimitry Andric 75*349cc55cSDimitry Andric if (auto *LD = dyn_cast<LoadInst>(&I)) { 76*349cc55cSDimitry Andric if (!LD->hasOneUser()) 77*349cc55cSDimitry Andric continue; 78*349cc55cSDimitry Andric auto *Call = dyn_cast<CallInst>(*LD->user_begin()); 79*349cc55cSDimitry Andric if (!Call) 80*349cc55cSDimitry Andric continue; 81*349cc55cSDimitry Andric auto *GV = dyn_cast<GlobalValue>(Call->getCalledOperand()); 82*349cc55cSDimitry Andric if (!GV) 83*349cc55cSDimitry Andric continue; 84*349cc55cSDimitry Andric if (!GV->getName().equals("llvm.stackrestore")) 85*349cc55cSDimitry Andric continue; 86*349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "Remove:"; I.dump()); 87*349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "Remove:"; Call->dump(); dbgs() << '\n'); 88*349cc55cSDimitry Andric Changed = true; 89*349cc55cSDimitry Andric Call->eraseFromParent(); 90*349cc55cSDimitry Andric ToErase = &I; 91*349cc55cSDimitry Andric } 92*349cc55cSDimitry Andric } 93*349cc55cSDimitry Andric } 94*349cc55cSDimitry Andric 95*349cc55cSDimitry Andric return Changed; 96*349cc55cSDimitry Andric } 97*349cc55cSDimitry Andric 98*349cc55cSDimitry Andric class BPFIRPeephole final : public FunctionPass { 99*349cc55cSDimitry Andric bool runOnFunction(Function &F) override; 100*349cc55cSDimitry Andric 101*349cc55cSDimitry Andric public: 102*349cc55cSDimitry Andric static char ID; 103*349cc55cSDimitry Andric BPFIRPeephole() : FunctionPass(ID) {} 104*349cc55cSDimitry Andric }; 105*349cc55cSDimitry Andric } // End anonymous namespace 106*349cc55cSDimitry Andric 107*349cc55cSDimitry Andric char BPFIRPeephole::ID = 0; 108*349cc55cSDimitry Andric INITIALIZE_PASS(BPFIRPeephole, DEBUG_TYPE, "BPF IR Peephole", false, false) 109*349cc55cSDimitry Andric 110*349cc55cSDimitry Andric FunctionPass *llvm::createBPFIRPeephole() { return new BPFIRPeephole(); } 111*349cc55cSDimitry Andric 112*349cc55cSDimitry Andric bool BPFIRPeephole::runOnFunction(Function &F) { return BPFIRPeepholeImpl(F); } 113*349cc55cSDimitry Andric 114*349cc55cSDimitry Andric PreservedAnalyses BPFIRPeepholePass::run(Function &F, 115*349cc55cSDimitry Andric FunctionAnalysisManager &AM) { 116*349cc55cSDimitry Andric return BPFIRPeepholeImpl(F) ? PreservedAnalyses::none() 117*349cc55cSDimitry Andric : PreservedAnalyses::all(); 118*349cc55cSDimitry Andric } 119