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