[llvm] [BPF] Support Jump Table (PR #149715)

via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 20 11:36:39 PDT 2025


yonghong-song wrote:

I also tried to remove those global variables (with blockaddresses) when gotox is available at pretty late optimizations:

```
diff --git a/llvm/lib/Target/BPF/BPFMIPeephole.cpp b/llvm/lib/Target/BPF/BPFMIPeephole.cpp
index 6275d5b7721c..91768eb1ae3f 100644
--- a/llvm/lib/Target/BPF/BPFMIPeephole.cpp
+++ b/llvm/lib/Target/BPF/BPFMIPeephole.cpp
@@ -30,6 +30,7 @@
 #include "llvm/CodeGen/MachineFunctionPass.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/IR/Module.h"
 #include "llvm/Support/Debug.h"
 #include <set>
 
@@ -308,6 +309,8 @@ struct BPFMIPreEmitPeephole : public MachineFunctionPass {
   const TargetRegisterInfo *TRI;
   const BPFInstrInfo *TII;
   bool SupportGotol;
+  bool SupportGotox;
+  bool doneRemoveUnneededGV = false;
 
   BPFMIPreEmitPeephole() : MachineFunctionPass(ID) {}
 
@@ -321,6 +324,7 @@ private:
   bool insertMissingCallerSavedSpills();
   bool removeMayGotoZero();
   bool addExitAfterUnreachable();
+  bool removeUnneededGV();
 
 public:
 
@@ -338,6 +342,8 @@ public:
     Changed |= insertMissingCallerSavedSpills();
     Changed |= removeMayGotoZero();
     Changed |= addExitAfterUnreachable();
+    if (SupportGotox && !doneRemoveUnneededGV)
+      Changed |= removeUnneededGV();
     return Changed;
   }
 };
@@ -348,6 +354,7 @@ void BPFMIPreEmitPeephole::initialize(MachineFunction &MFParm) {
   TII = MF->getSubtarget<BPFSubtarget>().getInstrInfo();
   TRI = MF->getSubtarget<BPFSubtarget>().getRegisterInfo();
   SupportGotol = MF->getSubtarget<BPFSubtarget>().hasGotol();
+  SupportGotox = MF->getSubtarget<BPFSubtarget>().hasGotox();
   LLVM_DEBUG(dbgs() << "*** BPF PreEmit peephole pass ***\n\n");
 }
 
@@ -750,6 +757,40 @@ bool BPFMIPreEmitPeephole::addExitAfterUnreachable() {
   return true;
 }

+// Remove global variables which has blockaddress since those global variables
+// have been converted to proper jump tables.
+bool BPFMIPreEmitPeephole::removeUnneededGV() {
+  bool Changed = false;
+  Module *M = MF->getFunction().getParent();
+  std::vector<GlobalVariable *> Targets;
+  for (GlobalVariable &Global : M->globals()) {
+    if (Global.getLinkage() != GlobalValue::PrivateLinkage)
+      continue;
+    if (!Global.isConstant() || !Global.hasInitializer())
+      continue;
+
+    Constant *CV = dyn_cast<Constant>(Global.getInitializer());
+    if (!CV)
+      continue;
+    ConstantArray *CA = dyn_cast<ConstantArray>(CV);
+    if (!CA)
+      continue;
+
+    for (unsigned i = 1, e = CA->getNumOperands(); i != e; ++i) {
+      if (!dyn_cast<BlockAddress>(CA->getOperand(i)))
+        continue;
+    }
+    Targets.push_back(&Global);
+    Changed = true;
+  }
+
+  for (GlobalVariable *GV : Targets)
+    GV->eraseFromParent();
+
+  doneRemoveUnneededGV = true;
+  return Changed;
+}
+
 } // end default namespace
 
 INITIALIZE_PASS(BPFMIPreEmitPeephole, "bpf-mi-pemit-peephole",
```

Unfortunately, tried a few examples, e.g.,
```
struct simple_ctx {          
        int x;                                                         
        int y;                                                         
        int z;  
};
                                   
int ret_user, ret_user2;
void bar(void);  
int foo1(struct simple_ctx *ctx, struct simple_ctx *ctx2)
{                
        switch (ctx->x) {
        case 1: ret_user = 18; break;
        case 20: ret_user = 6; break;
        case 16: ret_user = 9; break;     
        case 6: ret_user = 16; break;
        case 8: ret_user = 14; break;
        case 30: ret_user = 2; break;
        default: ret_user = 1; break;
        }

        bar();

        switch (ctx2->x) {
        case 0: ret_user2 = 8; break;
        case 31: ret_user2 = 5; break;
        case 13: ret_user2 = 8; break;
        case 1: ret_user2 = 3; break;
        case 11: ret_user2 = 4; break;
        default: ret_user2 = 29; break;
        }

        return 0;
}

int foo2(int a, int b) {
    __label__ l1, l2, l3, l4;
    void *jt1[] = {[0]=&&l1, [1]=&&l2};
    void *jt2[] = {[0]=&&l3, [1]=&&l4};
    int ret = 0;

    goto *jt1[a % 2];
    l1: ret += 1;
    l2: ret += 3;
    goto *jt2[b % 2];
    l3: ret += 5;
    l4: ret += 7;
    return ret;
}
```
It does not work.
As we discussed earlier I think it is okay to leave these unused globals, it does not impact anything except tiny bit space increase.

https://github.com/llvm/llvm-project/pull/149715


More information about the llvm-commits mailing list