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