xref: /freebsd/contrib/llvm-project/llvm/lib/Target/BPF/BPFIRPeephole.cpp (revision af23369a6deaaeb612ab266eb88b8bb8d560c322)
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 
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;
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 
110 FunctionPass *llvm::createBPFIRPeephole() { return new BPFIRPeephole(); }
111 
112 bool BPFIRPeephole::runOnFunction(Function &F) { return BPFIRPeepholeImpl(F); }
113 
114 PreservedAnalyses BPFIRPeepholePass::run(Function &F,
115                                          FunctionAnalysisManager &AM) {
116   return BPFIRPeepholeImpl(F) ? PreservedAnalyses::none()
117                               : PreservedAnalyses::all();
118 }
119