diff --git a/0001-BPF-Revert-the-behavior-when-handling-traps.patch b/0001-BPF-Revert-the-behavior-when-handling-traps.patch deleted file mode 100644 index 5fe5779..0000000 --- a/0001-BPF-Revert-the-behavior-when-handling-traps.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 10c38a8830c2c93b490b342596a2d286f4f21ae6 Mon Sep 17 00:00:00 2001 -From: Tulio Magno Quites Machado Filho -Date: Wed, 29 Oct 2025 10:59:29 -0300 -Subject: [PATCH] [BPF] Revert the behavior when handling traps - -Commit ab391beb11f733b526b86f9df23734a34657d876 in LLVM 21 changed the -behavior of the BPF backend when handling traps in order to require -kfunc __bpf_trap. This kfunc is only available on Linux >= 6.16 via -commit f95695f2c46592b4260032736a9bfc6e2a01c77c. - -RHEL 8 uses Linux 4.18, which means we can't adopt the new behavior -unless __bpf_trap is backported. ---- - llvm/lib/Target/BPF/BPFTargetMachine.cpp | 3 ++- - llvm/test/CodeGen/BPF/BTF/unreachable.ll | 4 ++-- - 2 files changed, 4 insertions(+), 3 deletions(-) - -diff --git a/llvm/lib/Target/BPF/BPFTargetMachine.cpp b/llvm/lib/Target/BPF/BPFTargetMachine.cpp -index ad3df2c879fe..426facc74904 100644 ---- a/llvm/lib/Target/BPF/BPFTargetMachine.cpp -+++ b/llvm/lib/Target/BPF/BPFTargetMachine.cpp -@@ -40,7 +40,8 @@ opt DisableMIPeephole("disable-bpf-peephole", cl::Hidden, - cl::desc("Disable machine peepholes for BPF")); - - static cl::opt -- DisableCheckUnreachable("bpf-disable-trap-unreachable", cl::Hidden, -+ DisableCheckUnreachable("bpf-disable-trap-unreachable", cl::init(true), -+ cl::Hidden, - cl::desc("Disable Trap Unreachable for BPF")); - - extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeBPFTarget() { -diff --git a/llvm/test/CodeGen/BPF/BTF/unreachable.ll b/llvm/test/CodeGen/BPF/BTF/unreachable.ll -index 5f53a7445433..91bd94e8dc45 100644 ---- a/llvm/test/CodeGen/BPF/BTF/unreachable.ll -+++ b/llvm/test/CodeGen/BPF/BTF/unreachable.ll -@@ -1,7 +1,7 @@ --; RUN: llc -mtriple=bpfel -mcpu=v3 -filetype=obj -o %t1 %s -+; RUN: llc -mtriple=bpfel -mcpu=v3 -filetype=obj -o %t1 -bpf-disable-trap-unreachable=0 %s - ; RUN: llvm-objcopy --dump-section='.BTF'=%t2 %t1 - ; RUN: %python %p/print_btf.py %t2 | FileCheck -check-prefixes=CHECK-BTF %s --; RUN: llc -mtriple=bpfel -mcpu=v3 < %s | FileCheck -check-prefixes=CHECK %s -+; RUN: llc -mtriple=bpfel -mcpu=v3 -bpf-disable-trap-unreachable=0 < %s | FileCheck -check-prefixes=CHECK %s - - define void @foo() { - entry: --- -2.50.1 - diff --git a/0001-BPF-Support-Jump-Table-149715.patch b/0001-BPF-Support-Jump-Table-149715.patch new file mode 100644 index 0000000..c1cbc12 --- /dev/null +++ b/0001-BPF-Support-Jump-Table-149715.patch @@ -0,0 +1,1354 @@ +From 528baf4740aed86443e3041eb3b6044963f96e1a Mon Sep 17 00:00:00 2001 +From: yonghong-song +Date: Tue, 16 Sep 2025 09:27:08 -0700 +Subject: [PATCH] [BPF] Support Jump Table (#149715) + +Add jump table (switch statement and computed goto) support for BPF +backend. +A `gotox ` insn is implemented and the `` holds the target +insn where the gotox will go. + +For a switch statement like +``` +... + 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; + } +... +``` +and the final binary +``` + The final binary: + 4: 67 01 00 00 03 00 00 00 r1 <<= 0x3 + 5: 18 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r2 = 0x0 ll + 0000000000000028: R_BPF_64_64 BPF.JT.0.0 + 7: 0f 12 00 00 00 00 00 00 r2 += r1 + ... + Symbol table: + 4: 0000000000000000 240 OBJECT GLOBAL DEFAULT 4 BPF.JT.0.0 + 5: 0000000000000000 4 OBJECT GLOBAL DEFAULT 6 ret_user + 6: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND bar + 7: 00000000000000f0 256 OBJECT GLOBAL DEFAULT 4 BPF.JT.0.1 + and + [ 4] .jumptables PROGBITS 0000000000000000 0001c8 0001f0 00 0 0 1 +``` +Note that for the above example, `-mllvm -bpf-min-jump-table-entries=5` +should be in compilation flags as the current default +bpf-min-jump-table-entries is 13. For example. +``` +clang --target=bpf -mcpu=v4 -O2 -mllvm -bpf-min-jump-table-entries=5 -S -g test.c +``` + +For computed goto like +``` + int foo(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; + } +``` +The final binary: +``` + 12: bf 23 20 00 00 00 00 00 r3 = (s32)r2 + 13: 67 03 00 00 03 00 00 00 r3 <<= 0x3 + 14: 18 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r2 = 0x0 ll + 0000000000000070: R_BPF_64_64 BPF.JT.0.0 + 16: 0f 32 00 00 00 00 00 00 r2 += r3 + 17: bf 11 20 00 00 00 00 00 r1 = (s32)r1 + 18: 67 01 00 00 03 00 00 00 r1 <<= 0x3 + 19: 18 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r3 = 0x0 ll + 0000000000000098: R_BPF_64_64 BPF.JT.0.1 + 21: 0f 13 00 00 00 00 00 00 r3 += r1 + + [ 4] .jumptables PROGBITS 0000000000000000 000160 000020 00 0 0 1 + + 4: 0000000000000000 16 OBJECT GLOBAL DEFAULT 4 BPF.JT.0.0 + 5: 0000000000000010 16 OBJECT GLOBAL DEFAULT 4 BPF.JT.0.1 +``` + +A more complicated test with both switch-statement triggered jump table +and compute gotos: + +``` +$ cat test3.c +struct simple_ctx { + int x; + int y; + int z; +}; + +int ret_user, ret_user2; +void bar(void); +int foo(struct simple_ctx *ctx, struct simple_ctx *ctx2, 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; + + bar(); + + 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; + } + + return ret; +} +``` +Compile with +``` + clang --target=bpf -mcpu=v4 -O2 -S test3.c + clang --target=bpf -mcpu=v4 -O2 -c test3.c +``` + The binary: +``` + /* For computed goto */ + 13: bf 42 20 00 00 00 00 00 r2 = (s32)r4 + 14: 67 02 00 00 03 00 00 00 r2 <<= 0x3 + 15: 18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0x0 ll + 0000000000000078: R_BPF_64_64 BPF.JT.0.1 + 17: 0f 21 00 00 00 00 00 00 r1 += r2 + 18: bf 32 20 00 00 00 00 00 r2 = (s32)r3 + 19: 67 02 00 00 03 00 00 00 r2 <<= 0x3 + 20: 18 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r3 = 0x0 ll + 00000000000000a0: R_BPF_64_64 BPF.JT.0.2 + 22: 0f 23 00 00 00 00 00 00 r3 += r2 + + /* For switch statement */ + 39: 67 01 00 00 03 00 00 00 r1 <<= 0x3 + 40: 18 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r2 = 0x0 ll + 0000000000000140: R_BPF_64_64 BPF.JT.0.0 + 42: 0f 12 00 00 00 00 00 00 r2 += r1 +``` +You can see jump table symbols are all different. + +(cherry picked from commit c3fb2e1cee954338acb83955b157e0a2e82a4849) +--- + .../lib/Target/BPF/AsmParser/BPFAsmParser.cpp | 1 + + llvm/lib/Target/BPF/BPFAsmPrinter.cpp | 114 +++++++++++--- + llvm/lib/Target/BPF/BPFAsmPrinter.h | 48 ++++++ + llvm/lib/Target/BPF/BPFISelLowering.cpp | 143 +++++++++++++++++- + llvm/lib/Target/BPF/BPFISelLowering.h | 8 +- + llvm/lib/Target/BPF/BPFInstrInfo.cpp | 45 ++++++ + llvm/lib/Target/BPF/BPFInstrInfo.h | 3 + + llvm/lib/Target/BPF/BPFInstrInfo.td | 26 +++- + llvm/lib/Target/BPF/BPFMCInstLower.cpp | 6 + + llvm/lib/Target/BPF/BPFMCInstLower.h | 6 +- + llvm/lib/Target/BPF/BPFSubtarget.cpp | 4 + + llvm/lib/Target/BPF/BPFSubtarget.h | 3 +- + .../BPF/BPFTargetLoweringObjectFile.cpp | 19 +++ + .../Target/BPF/BPFTargetLoweringObjectFile.h | 25 +++ + llvm/lib/Target/BPF/BPFTargetMachine.cpp | 3 +- + llvm/lib/Target/BPF/CMakeLists.txt | 1 + + llvm/test/CodeGen/BPF/jump_table_blockaddr.ll | 91 +++++++++++ + .../test/CodeGen/BPF/jump_table_global_var.ll | 83 ++++++++++ + .../CodeGen/BPF/jump_table_switch_stmt.ll | 126 +++++++++++++++ + 19 files changed, 716 insertions(+), 39 deletions(-) + create mode 100644 llvm/lib/Target/BPF/BPFAsmPrinter.h + create mode 100644 llvm/lib/Target/BPF/BPFTargetLoweringObjectFile.cpp + create mode 100644 llvm/lib/Target/BPF/BPFTargetLoweringObjectFile.h + create mode 100644 llvm/test/CodeGen/BPF/jump_table_blockaddr.ll + create mode 100644 llvm/test/CodeGen/BPF/jump_table_global_var.ll + create mode 100644 llvm/test/CodeGen/BPF/jump_table_switch_stmt.ll + +diff --git a/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp b/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp +index a347794a9a30..d96f403d2f81 100644 +--- a/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp ++++ b/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp +@@ -234,6 +234,7 @@ public: + .Case("callx", true) + .Case("goto", true) + .Case("gotol", true) ++ .Case("gotox", true) + .Case("may_goto", true) + .Case("*", true) + .Case("exit", true) +diff --git a/llvm/lib/Target/BPF/BPFAsmPrinter.cpp b/llvm/lib/Target/BPF/BPFAsmPrinter.cpp +index e3843e0e112e..77dc4a75a7d6 100644 +--- a/llvm/lib/Target/BPF/BPFAsmPrinter.cpp ++++ b/llvm/lib/Target/BPF/BPFAsmPrinter.cpp +@@ -11,52 +11,35 @@ + // + //===----------------------------------------------------------------------===// + ++#include "BPFAsmPrinter.h" + #include "BPF.h" + #include "BPFInstrInfo.h" + #include "BPFMCInstLower.h" + #include "BTFDebug.h" + #include "MCTargetDesc/BPFInstPrinter.h" + #include "TargetInfo/BPFTargetInfo.h" ++#include "llvm/BinaryFormat/ELF.h" + #include "llvm/CodeGen/AsmPrinter.h" + #include "llvm/CodeGen/MachineConstantPool.h" + #include "llvm/CodeGen/MachineInstr.h" ++#include "llvm/CodeGen/MachineJumpTableInfo.h" + #include "llvm/CodeGen/MachineModuleInfo.h" ++#include "llvm/CodeGen/TargetLowering.h" + #include "llvm/IR/Module.h" + #include "llvm/MC/MCAsmInfo.h" ++#include "llvm/MC/MCExpr.h" + #include "llvm/MC/MCInst.h" + #include "llvm/MC/MCStreamer.h" + #include "llvm/MC/MCSymbol.h" ++#include "llvm/MC/MCSymbolELF.h" + #include "llvm/MC/TargetRegistry.h" + #include "llvm/Support/Compiler.h" + #include "llvm/Support/raw_ostream.h" ++#include "llvm/Target/TargetLoweringObjectFile.h" + using namespace llvm; + + #define DEBUG_TYPE "asm-printer" + +-namespace { +-class BPFAsmPrinter : public AsmPrinter { +-public: +- explicit BPFAsmPrinter(TargetMachine &TM, +- std::unique_ptr Streamer) +- : AsmPrinter(TM, std::move(Streamer), ID), BTF(nullptr) {} +- +- StringRef getPassName() const override { return "BPF Assembly Printer"; } +- bool doInitialization(Module &M) override; +- void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O); +- bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, +- const char *ExtraCode, raw_ostream &O) override; +- bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, +- const char *ExtraCode, raw_ostream &O) override; +- +- void emitInstruction(const MachineInstr *MI) override; +- +- static char ID; +- +-private: +- BTFDebug *BTF; +-}; +-} // namespace +- + bool BPFAsmPrinter::doInitialization(Module &M) { + AsmPrinter::doInitialization(M); + +@@ -69,6 +52,45 @@ bool BPFAsmPrinter::doInitialization(Module &M) { + return false; + } + ++const BPFTargetMachine &BPFAsmPrinter::getBTM() const { ++ return static_cast(TM); ++} ++ ++bool BPFAsmPrinter::doFinalization(Module &M) { ++ // Remove unused globals which are previously used for jump table. ++ const BPFSubtarget *Subtarget = getBTM().getSubtargetImpl(); ++ if (Subtarget->hasGotox()) { ++ std::vector Targets; ++ for (GlobalVariable &Global : M.globals()) { ++ if (Global.getLinkage() != GlobalValue::PrivateLinkage) ++ continue; ++ if (!Global.isConstant() || !Global.hasInitializer()) ++ continue; ++ ++ Constant *CV = dyn_cast(Global.getInitializer()); ++ if (!CV) ++ continue; ++ ConstantArray *CA = dyn_cast(CV); ++ if (!CA) ++ continue; ++ ++ for (unsigned i = 1, e = CA->getNumOperands(); i != e; ++i) { ++ if (!dyn_cast(CA->getOperand(i))) ++ continue; ++ } ++ Targets.push_back(&Global); ++ } ++ ++ for (GlobalVariable *GV : Targets) { ++ GV->replaceAllUsesWith(PoisonValue::get(GV->getType())); ++ GV->dropAllReferences(); ++ GV->eraseFromParent(); ++ } ++ } ++ ++ return AsmPrinter::doFinalization(M); ++} ++ + void BPFAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + const MachineOperand &MO = MI->getOperand(OpNum); +@@ -150,6 +172,50 @@ void BPFAsmPrinter::emitInstruction(const MachineInstr *MI) { + EmitToStreamer(*OutStreamer, TmpInst); + } + ++MCSymbol *BPFAsmPrinter::getJTPublicSymbol(unsigned JTI) { ++ SmallString<60> Name; ++ raw_svector_ostream(Name) ++ << "BPF.JT." << MF->getFunctionNumber() << '.' << JTI; ++ MCSymbol *S = OutContext.getOrCreateSymbol(Name); ++ if (auto *ES = static_cast(S)) { ++ ES->setBinding(ELF::STB_GLOBAL); ++ ES->setType(ELF::STT_OBJECT); ++ } ++ return S; ++} ++ ++void BPFAsmPrinter::emitJumpTableInfo() { ++ const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); ++ if (!MJTI) ++ return; ++ ++ const std::vector &JT = MJTI->getJumpTables(); ++ if (JT.empty()) ++ return; ++ ++ const TargetLoweringObjectFile &TLOF = getObjFileLowering(); ++ const Function &F = MF->getFunction(); ++ MCSection *JTS = TLOF.getSectionForJumpTable(F, TM); ++ assert(MJTI->getEntryKind() == MachineJumpTableInfo::EK_BlockAddress); ++ unsigned EntrySize = MJTI->getEntrySize(getDataLayout()); ++ OutStreamer->switchSection(JTS); ++ for (unsigned JTI = 0; JTI < JT.size(); JTI++) { ++ ArrayRef JTBBs = JT[JTI].MBBs; ++ if (JTBBs.empty()) ++ continue; ++ ++ MCSymbol *JTStart = getJTPublicSymbol(JTI); ++ OutStreamer->emitLabel(JTStart); ++ for (const MachineBasicBlock *MBB : JTBBs) { ++ const MCExpr *LHS = MCSymbolRefExpr::create(MBB->getSymbol(), OutContext); ++ OutStreamer->emitValue(LHS, EntrySize); ++ } ++ const MCExpr *JTSize = ++ MCConstantExpr::create(JTBBs.size() * EntrySize, OutContext); ++ OutStreamer->emitELFSize(JTStart, JTSize); ++ } ++} ++ + char BPFAsmPrinter::ID = 0; + + INITIALIZE_PASS(BPFAsmPrinter, "bpf-asm-printer", "BPF Assembly Printer", false, +diff --git a/llvm/lib/Target/BPF/BPFAsmPrinter.h b/llvm/lib/Target/BPF/BPFAsmPrinter.h +new file mode 100644 +index 000000000000..0cfb2839c8ff +--- /dev/null ++++ b/llvm/lib/Target/BPF/BPFAsmPrinter.h +@@ -0,0 +1,48 @@ ++//===-- BPFFrameLowering.h - Define frame lowering for BPF -----*- C++ -*--===// ++// ++// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. ++// See https://llvm.org/LICENSE.txt for license information. ++// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception ++// ++//===----------------------------------------------------------------------===// ++ ++#ifndef LLVM_LIB_TARGET_BPF_BPFASMPRINTER_H ++#define LLVM_LIB_TARGET_BPF_BPFASMPRINTER_H ++ ++#include "BPFTargetMachine.h" ++#include "BTFDebug.h" ++#include "llvm/CodeGen/AsmPrinter.h" ++ ++namespace llvm { ++ ++class BPFAsmPrinter : public AsmPrinter { ++public: ++ explicit BPFAsmPrinter(TargetMachine &TM, ++ std::unique_ptr Streamer) ++ : AsmPrinter(TM, std::move(Streamer), ID), BTF(nullptr), TM(TM) {} ++ ++ StringRef getPassName() const override { return "BPF Assembly Printer"; } ++ bool doInitialization(Module &M) override; ++ bool doFinalization(Module &M) override; ++ void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O); ++ bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, ++ const char *ExtraCode, raw_ostream &O) override; ++ bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, ++ const char *ExtraCode, raw_ostream &O) override; ++ ++ void emitInstruction(const MachineInstr *MI) override; ++ MCSymbol *getJTPublicSymbol(unsigned JTI); ++ virtual void emitJumpTableInfo() override; ++ ++ static char ID; ++ ++private: ++ BTFDebug *BTF; ++ TargetMachine &TM; ++ ++ const BPFTargetMachine &getBTM() const; ++}; ++ ++} // namespace llvm ++ ++#endif /* LLVM_LIB_TARGET_BPF_BPFASMPRINTER_H */ +diff --git a/llvm/lib/Target/BPF/BPFISelLowering.cpp b/llvm/lib/Target/BPF/BPFISelLowering.cpp +index f4f414d192df..6e5520c3dbb1 100644 +--- a/llvm/lib/Target/BPF/BPFISelLowering.cpp ++++ b/llvm/lib/Target/BPF/BPFISelLowering.cpp +@@ -18,6 +18,7 @@ + #include "llvm/CodeGen/MachineFrameInfo.h" + #include "llvm/CodeGen/MachineFunction.h" + #include "llvm/CodeGen/MachineInstrBuilder.h" ++#include "llvm/CodeGen/MachineJumpTableInfo.h" + #include "llvm/CodeGen/MachineRegisterInfo.h" + #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" + #include "llvm/CodeGen/ValueTypes.h" +@@ -38,6 +39,10 @@ static cl::opt BPFExpandMemcpyInOrder("bpf-expand-memcpy-in-order", + cl::Hidden, cl::init(false), + cl::desc("Expand memcpy into load/store pairs in order")); + ++static cl::opt BPFMinimumJumpTableEntries( ++ "bpf-min-jump-table-entries", cl::init(13), cl::Hidden, ++ cl::desc("Set minimum number of entries to use a jump table on BPF")); ++ + static void fail(const SDLoc &DL, SelectionDAG &DAG, const Twine &Msg, + SDValue Val = {}) { + std::string Str; +@@ -67,12 +72,16 @@ BPFTargetLowering::BPFTargetLowering(const TargetMachine &TM, + + setOperationAction(ISD::BR_CC, MVT::i64, Custom); + setOperationAction(ISD::BR_JT, MVT::Other, Expand); +- setOperationAction(ISD::BRIND, MVT::Other, Expand); + setOperationAction(ISD::BRCOND, MVT::Other, Expand); + ++ if (!STI.hasGotox()) ++ setOperationAction(ISD::BRIND, MVT::Other, Expand); ++ + setOperationAction(ISD::TRAP, MVT::Other, Custom); + + setOperationAction({ISD::GlobalAddress, ISD::ConstantPool}, MVT::i64, Custom); ++ if (STI.hasGotox()) ++ setOperationAction({ISD::JumpTable, ISD::BlockAddress}, MVT::i64, Custom); + + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Custom); + setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); +@@ -159,6 +168,7 @@ BPFTargetLowering::BPFTargetLowering(const TargetMachine &TM, + + setBooleanContents(ZeroOrOneBooleanContent); + setMaxAtomicSizeInBitsSupported(64); ++ setMinimumJumpTableEntries(BPFMinimumJumpTableEntries); + + // Function alignments + setMinFunctionAlignment(Align(8)); +@@ -246,6 +256,10 @@ bool BPFTargetLowering::isZExtFree(SDValue Val, EVT VT2) const { + return TargetLoweringBase::isZExtFree(Val, VT2); + } + ++unsigned BPFTargetLowering::getJumpTableEncoding() const { ++ return MachineJumpTableInfo::EK_BlockAddress; ++} ++ + BPFTargetLowering::ConstraintType + BPFTargetLowering::getConstraintType(StringRef Constraint) const { + if (Constraint.size() == 1) { +@@ -316,10 +330,14 @@ SDValue BPFTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { + report_fatal_error("unimplemented opcode: " + Twine(Op.getOpcode())); + case ISD::BR_CC: + return LowerBR_CC(Op, DAG); ++ case ISD::JumpTable: ++ return LowerJumpTable(Op, DAG); + case ISD::GlobalAddress: + return LowerGlobalAddress(Op, DAG); + case ISD::ConstantPool: + return LowerConstantPool(Op, DAG); ++ case ISD::BlockAddress: ++ return LowerBlockAddress(Op, DAG); + case ISD::SELECT_CC: + return LowerSELECT_CC(Op, DAG); + case ISD::SDIV: +@@ -780,6 +798,11 @@ SDValue BPFTargetLowering::LowerTRAP(SDValue Op, SelectionDAG &DAG) const { + return LowerCall(CLI, InVals); + } + ++SDValue BPFTargetLowering::LowerJumpTable(SDValue Op, SelectionDAG &DAG) const { ++ JumpTableSDNode *N = cast(Op); ++ return getAddr(N, DAG); ++} ++ + const char *BPFTargetLowering::getTargetNodeName(unsigned Opcode) const { + switch ((BPFISD::NodeType)Opcode) { + case BPFISD::FIRST_NUMBER: +@@ -800,17 +823,17 @@ const char *BPFTargetLowering::getTargetNodeName(unsigned Opcode) const { + return nullptr; + } + +-static SDValue getTargetNode(GlobalAddressSDNode *N, const SDLoc &DL, EVT Ty, +- SelectionDAG &DAG, unsigned Flags) { +- return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags); +-} +- + static SDValue getTargetNode(ConstantPoolSDNode *N, const SDLoc &DL, EVT Ty, + SelectionDAG &DAG, unsigned Flags) { + return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlign(), + N->getOffset(), Flags); + } + ++static SDValue getTargetNode(JumpTableSDNode *N, const SDLoc &DL, EVT Ty, ++ SelectionDAG &DAG, unsigned Flags) { ++ return DAG.getTargetJumpTable(N->getIndex(), Ty, Flags); ++} ++ + template + SDValue BPFTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG, + unsigned Flags) const { +@@ -827,7 +850,15 @@ SDValue BPFTargetLowering::LowerGlobalAddress(SDValue Op, + if (N->getOffset() != 0) + report_fatal_error("invalid offset for global address: " + + Twine(N->getOffset())); +- return getAddr(N, DAG); ++ ++ const GlobalValue *GVal = N->getGlobal(); ++ SDLoc DL(Op); ++ ++ // Wrap it in a TargetGlobalAddress ++ SDValue Addr = DAG.getTargetGlobalAddress(GVal, DL, MVT::i64); ++ ++ // Emit pseudo instruction ++ return SDValue(DAG.getMachineNode(BPF::LDIMM64, DL, MVT::i64, Addr), 0); + } + + SDValue BPFTargetLowering::LowerConstantPool(SDValue Op, +@@ -837,6 +868,18 @@ SDValue BPFTargetLowering::LowerConstantPool(SDValue Op, + return getAddr(N, DAG); + } + ++SDValue BPFTargetLowering::LowerBlockAddress(SDValue Op, ++ SelectionDAG &DAG) const { ++ const BlockAddress *BA = cast(Op)->getBlockAddress(); ++ SDLoc DL(Op); ++ ++ // Wrap it in a TargetBlockAddress ++ SDValue Addr = DAG.getTargetBlockAddress(BA, MVT::i64); ++ ++ // Emit pseudo instruction ++ return SDValue(DAG.getMachineNode(BPF::LDIMM64, DL, MVT::i64, Addr), 0); ++} ++ + unsigned + BPFTargetLowering::EmitSubregExt(MachineInstr &MI, MachineBasicBlock *BB, + unsigned Reg, bool isSigned) const { +@@ -900,6 +943,86 @@ BPFTargetLowering::EmitInstrWithCustomInserterMemcpy(MachineInstr &MI, + return BB; + } + ++MachineBasicBlock *BPFTargetLowering::EmitInstrWithCustomInserterLDimm64( ++ MachineInstr &MI, MachineBasicBlock *BB) const { ++ MachineFunction *MF = BB->getParent(); ++ const BPFInstrInfo *TII = MF->getSubtarget().getInstrInfo(); ++ const TargetRegisterClass *RC = getRegClassFor(MVT::i64); ++ MachineRegisterInfo &RegInfo = MF->getRegInfo(); ++ DebugLoc DL = MI.getDebugLoc(); ++ ++ // Build address taken map for Global Varaibles and BlockAddresses ++ DenseMap AddressTakenBBs; ++ for (MachineBasicBlock &MBB : *MF) { ++ if (const BasicBlock *BB = MBB.getBasicBlock()) ++ if (BB->hasAddressTaken()) ++ AddressTakenBBs[BB] = &MBB; ++ } ++ ++ MachineOperand &MO = MI.getOperand(1); ++ assert(MO.isBlockAddress() || MO.isGlobal()); ++ ++ MCRegister ResultReg = MI.getOperand(0).getReg(); ++ Register TmpReg = RegInfo.createVirtualRegister(RC); ++ ++ std::vector Targets; ++ unsigned JTI; ++ ++ if (MO.isBlockAddress()) { ++ auto *BA = MO.getBlockAddress(); ++ MachineBasicBlock *TgtMBB = AddressTakenBBs[BA->getBasicBlock()]; ++ assert(TgtMBB); ++ ++ Targets.push_back(TgtMBB); ++ JTI = MF->getOrCreateJumpTableInfo(getJumpTableEncoding()) ++ ->createJumpTableIndex(Targets); ++ ++ BuildMI(*BB, MI, DL, TII->get(BPF::LD_imm64), TmpReg) ++ .addJumpTableIndex(JTI); ++ BuildMI(*BB, MI, DL, TII->get(BPF::LDD), ResultReg) ++ .addReg(TmpReg) ++ .addImm(0); ++ MI.eraseFromParent(); ++ return BB; ++ } ++ ++ // Helper: emit LD_imm64 with operand GlobalAddress or JumpTable ++ auto emitLDImm64 = [&](const GlobalValue *GV = nullptr, unsigned JTI = -1) { ++ auto MIB = BuildMI(*BB, MI, DL, TII->get(BPF::LD_imm64), ResultReg); ++ if (GV) ++ MIB.addGlobalAddress(GV); ++ else ++ MIB.addJumpTableIndex(JTI); ++ MI.eraseFromParent(); ++ return BB; ++ }; ++ ++ // Must be a global at this point ++ const GlobalValue *GVal = MO.getGlobal(); ++ const auto *GV = dyn_cast(GVal); ++ ++ if (!GV || GV->getLinkage() != GlobalValue::PrivateLinkage || ++ !GV->isConstant() || !GV->hasInitializer()) ++ return emitLDImm64(GVal); ++ ++ const auto *CA = dyn_cast(GV->getInitializer()); ++ if (!CA) ++ return emitLDImm64(GVal); ++ ++ for (const Use &Op : CA->operands()) { ++ if (!isa(Op)) ++ return emitLDImm64(GVal); ++ auto *BA = cast(Op); ++ MachineBasicBlock *TgtMBB = AddressTakenBBs[BA->getBasicBlock()]; ++ assert(TgtMBB); ++ Targets.push_back(TgtMBB); ++ } ++ ++ JTI = MF->getOrCreateJumpTableInfo(getJumpTableEncoding()) ++ ->createJumpTableIndex(Targets); ++ return emitLDImm64(nullptr, JTI); ++} ++ + MachineBasicBlock * + BPFTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, + MachineBasicBlock *BB) const { +@@ -912,6 +1035,7 @@ BPFTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, + Opc == BPF::Select_32_64); + + bool isMemcpyOp = Opc == BPF::MEMCPY; ++ bool isLDimm64Op = Opc == BPF::LDIMM64; + + #ifndef NDEBUG + bool isSelectRIOp = (Opc == BPF::Select_Ri || +@@ -919,13 +1043,16 @@ BPFTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, + Opc == BPF::Select_Ri_32 || + Opc == BPF::Select_Ri_32_64); + +- if (!(isSelectRROp || isSelectRIOp || isMemcpyOp)) ++ if (!(isSelectRROp || isSelectRIOp || isMemcpyOp || isLDimm64Op)) + report_fatal_error("unhandled instruction type: " + Twine(Opc)); + #endif + + if (isMemcpyOp) + return EmitInstrWithCustomInserterMemcpy(MI, BB); + ++ if (isLDimm64Op) ++ return EmitInstrWithCustomInserterLDimm64(MI, BB); ++ + bool is32BitCmp = (Opc == BPF::Select_32 || + Opc == BPF::Select_32_64 || + Opc == BPF::Select_Ri_32 || +diff --git a/llvm/lib/Target/BPF/BPFISelLowering.h b/llvm/lib/Target/BPF/BPFISelLowering.h +index 8f60261c10e9..5243d4944667 100644 +--- a/llvm/lib/Target/BPF/BPFISelLowering.h ++++ b/llvm/lib/Target/BPF/BPFISelLowering.h +@@ -66,6 +66,8 @@ public: + + MVT getScalarShiftAmountTy(const DataLayout &, EVT) const override; + ++ unsigned getJumpTableEncoding() const override; ++ + private: + // Control Instruction Selection Features + bool HasAlu32; +@@ -81,6 +83,8 @@ private: + SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerTRAP(SDValue Op, SelectionDAG &DAG) const; ++ SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const; ++ SDValue LowerJumpTable(SDValue Op, SelectionDAG &DAG) const; + + template + SDValue getAddr(NodeTy *N, SelectionDAG &DAG, unsigned Flags = 0) const; +@@ -163,7 +167,9 @@ private: + MachineBasicBlock * EmitInstrWithCustomInserterMemcpy(MachineInstr &MI, + MachineBasicBlock *BB) + const; +- ++ MachineBasicBlock * ++ EmitInstrWithCustomInserterLDimm64(MachineInstr &MI, ++ MachineBasicBlock *BB) const; + }; + } + +diff --git a/llvm/lib/Target/BPF/BPFInstrInfo.cpp b/llvm/lib/Target/BPF/BPFInstrInfo.cpp +index 70bc163615f6..bf2b4213201d 100644 +--- a/llvm/lib/Target/BPF/BPFInstrInfo.cpp ++++ b/llvm/lib/Target/BPF/BPFInstrInfo.cpp +@@ -181,6 +181,11 @@ bool BPFInstrInfo::analyzeBranch(MachineBasicBlock &MBB, + if (!isUnpredicatedTerminator(*I)) + break; + ++ // From base method doc: ... returning true if it cannot be understood ... ++ // Indirect branch has multiple destinations and no true/false concepts. ++ if (I->isIndirectBranch()) ++ return true; ++ + // A terminator that isn't a branch can't easily be handled + // by this analysis. + if (!I->isBranch()) +@@ -259,3 +264,43 @@ unsigned BPFInstrInfo::removeBranch(MachineBasicBlock &MBB, + + return Count; + } ++ ++int BPFInstrInfo::getJumpTableIndex(const MachineInstr &MI) const { ++ if (MI.getOpcode() != BPF::JX) ++ return -1; ++ ++ // The pattern looks like: ++ // %0 = LD_imm64 %jump-table.0 ; load jump-table address ++ // %1 = ADD_rr %0, $another_reg ; address + offset ++ // %2 = LDD %1, 0 ; load the actual label ++ // JX %2 ++ const MachineFunction &MF = *MI.getParent()->getParent(); ++ const MachineRegisterInfo &MRI = MF.getRegInfo(); ++ ++ Register Reg = MI.getOperand(0).getReg(); ++ if (!Reg.isVirtual()) ++ return -1; ++ MachineInstr *Ldd = MRI.getUniqueVRegDef(Reg); ++ if (Ldd == nullptr || Ldd->getOpcode() != BPF::LDD) ++ return -1; ++ ++ Reg = Ldd->getOperand(1).getReg(); ++ if (!Reg.isVirtual()) ++ return -1; ++ MachineInstr *Add = MRI.getUniqueVRegDef(Reg); ++ if (Add == nullptr || Add->getOpcode() != BPF::ADD_rr) ++ return -1; ++ ++ Reg = Add->getOperand(1).getReg(); ++ if (!Reg.isVirtual()) ++ return -1; ++ MachineInstr *LDimm64 = MRI.getUniqueVRegDef(Reg); ++ if (LDimm64 == nullptr || LDimm64->getOpcode() != BPF::LD_imm64) ++ return -1; ++ ++ const MachineOperand &MO = LDimm64->getOperand(1); ++ if (!MO.isJTI()) ++ return -1; ++ ++ return MO.getIndex(); ++} +diff --git a/llvm/lib/Target/BPF/BPFInstrInfo.h b/llvm/lib/Target/BPF/BPFInstrInfo.h +index d8bbad44e314..d88e37975980 100644 +--- a/llvm/lib/Target/BPF/BPFInstrInfo.h ++++ b/llvm/lib/Target/BPF/BPFInstrInfo.h +@@ -58,6 +58,9 @@ public: + MachineBasicBlock *FBB, ArrayRef Cond, + const DebugLoc &DL, + int *BytesAdded = nullptr) const override; ++ ++ int getJumpTableIndex(const MachineInstr &MI) const override; ++ + private: + void expandMEMCPY(MachineBasicBlock::iterator) const; + +diff --git a/llvm/lib/Target/BPF/BPFInstrInfo.td b/llvm/lib/Target/BPF/BPFInstrInfo.td +index b21f1a0eee3b..9d3ac7ffa6ff 100644 +--- a/llvm/lib/Target/BPF/BPFInstrInfo.td ++++ b/llvm/lib/Target/BPF/BPFInstrInfo.td +@@ -61,6 +61,7 @@ def BPFNoMovsx : Predicate<"!Subtarget->hasMovsx()">; + def BPFNoBswap : Predicate<"!Subtarget->hasBswap()">; + def BPFHasStoreImm : Predicate<"Subtarget->hasStoreImm()">; + def BPFHasLoadAcqStoreRel : Predicate<"Subtarget->hasLoadAcqStoreRel()">; ++def BPFHasGotox : Predicate<"Subtarget->hasGotox()">; + + class ImmediateAsmOperand : AsmOperandClass { + let Name = name; +@@ -216,6 +217,18 @@ class JMP_RI + let BPFClass = BPF_JMP; + } + ++class JMP_IND Pattern> ++ : TYPE_ALU_JMP { ++ bits<4> dst; ++ ++ let Inst{51-48} = dst; ++ let BPFClass = BPF_JMP; ++} ++ + class JMP_JCOND Pattern> + : TYPE_ALU_JMP; + defm JSLE : J; + def JCOND : JMP_JCOND; ++ ++let Predicates = [BPFHasGotox] in { ++ let isIndirectBranch = 1, isBarrier = 1 in { ++ def JX : JMP_IND; ++ } ++} + } + + // ALU instructions +@@ -849,8 +868,8 @@ let usesCustomInserter = 1, isCodeGenOnly = 1 in { + } + + // load 64-bit global addr into register +-def : Pat<(BPFWrapper tglobaladdr:$in), (LD_imm64 tglobaladdr:$in)>; + def : Pat<(BPFWrapper tconstpool:$in), (LD_imm64 tconstpool:$in)>; ++def : Pat<(BPFWrapper tjumptable:$in), (LD_imm64 tjumptable:$in)>; + + // 0xffffFFFF doesn't fit into simm32, optimize common case + def : Pat<(i64 (and (i64 GPR:$src), 0xffffFFFF)), +@@ -1372,3 +1391,8 @@ let usesCustomInserter = 1, isCodeGenOnly = 1 in { + "#memcpy dst: $dst, src: $src, len: $len, align: $align", + [(BPFmemcpy GPR:$dst, GPR:$src, imm:$len, imm:$align)]>; + } ++ ++// For GlobalValue and BlockAddress. ++let usesCustomInserter = 1, isCodeGenOnly = 1 in { ++ def LDIMM64 : Pseudo<(outs GPR:$dst), (ins i64imm:$addr), "", []>; ++} +diff --git a/llvm/lib/Target/BPF/BPFMCInstLower.cpp b/llvm/lib/Target/BPF/BPFMCInstLower.cpp +index 040a1fb75070..7d671d2c464e 100644 +--- a/llvm/lib/Target/BPF/BPFMCInstLower.cpp ++++ b/llvm/lib/Target/BPF/BPFMCInstLower.cpp +@@ -12,6 +12,8 @@ + //===----------------------------------------------------------------------===// + + #include "BPFMCInstLower.h" ++#include "BPFAsmPrinter.h" ++#include "BPFISelLowering.h" + #include "llvm/CodeGen/AsmPrinter.h" + #include "llvm/CodeGen/MachineBasicBlock.h" + #include "llvm/CodeGen/MachineInstr.h" +@@ -19,6 +21,7 @@ + #include "llvm/MC/MCContext.h" + #include "llvm/MC/MCExpr.h" + #include "llvm/MC/MCInst.h" ++#include "llvm/MC/MCStreamer.h" + #include "llvm/Support/ErrorHandling.h" + #include "llvm/Support/raw_ostream.h" + using namespace llvm; +@@ -77,6 +80,9 @@ void BPFMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { + case MachineOperand::MO_ConstantPoolIndex: + MCOp = LowerSymbolOperand(MO, Printer.GetCPISymbol(MO.getIndex())); + break; ++ case MachineOperand::MO_JumpTableIndex: ++ MCOp = LowerSymbolOperand(MO, Printer.getJTPublicSymbol(MO.getIndex())); ++ break; + } + + OutMI.addOperand(MCOp); +diff --git a/llvm/lib/Target/BPF/BPFMCInstLower.h b/llvm/lib/Target/BPF/BPFMCInstLower.h +index 4bd0f1f0bf1c..483edd9a0283 100644 +--- a/llvm/lib/Target/BPF/BPFMCInstLower.h ++++ b/llvm/lib/Target/BPF/BPFMCInstLower.h +@@ -12,7 +12,7 @@ + #include "llvm/Support/Compiler.h" + + namespace llvm { +-class AsmPrinter; ++class BPFAsmPrinter; + class MCContext; + class MCInst; + class MCOperand; +@@ -24,10 +24,10 @@ class MachineOperand; + class LLVM_LIBRARY_VISIBILITY BPFMCInstLower { + MCContext &Ctx; + +- AsmPrinter &Printer; ++ BPFAsmPrinter &Printer; + + public: +- BPFMCInstLower(MCContext &ctx, AsmPrinter &printer) ++ BPFMCInstLower(MCContext &ctx, BPFAsmPrinter &printer) + : Ctx(ctx), Printer(printer) {} + void Lower(const MachineInstr *MI, MCInst &OutMI) const; + +diff --git a/llvm/lib/Target/BPF/BPFSubtarget.cpp b/llvm/lib/Target/BPF/BPFSubtarget.cpp +index 4167547680b1..a11aa6933147 100644 +--- a/llvm/lib/Target/BPF/BPFSubtarget.cpp ++++ b/llvm/lib/Target/BPF/BPFSubtarget.cpp +@@ -43,6 +43,8 @@ static cl::opt + static cl::opt Disable_load_acq_store_rel( + "disable-load-acq-store-rel", cl::Hidden, cl::init(false), + cl::desc("Disable load-acquire and store-release insns")); ++static cl::opt Disable_gotox("disable-gotox", cl::Hidden, cl::init(false), ++ cl::desc("Disable gotox insn")); + + void BPFSubtarget::anchor() {} + +@@ -66,6 +68,7 @@ void BPFSubtarget::initializeEnvironment() { + HasGotol = false; + HasStoreImm = false; + HasLoadAcqStoreRel = false; ++ HasGotox = false; + } + + void BPFSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) { +@@ -96,6 +99,7 @@ void BPFSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) { + HasGotol = !Disable_gotol; + HasStoreImm = !Disable_StoreImm; + HasLoadAcqStoreRel = !Disable_load_acq_store_rel; ++ HasGotox = !Disable_gotox; + return; + } + } +diff --git a/llvm/lib/Target/BPF/BPFSubtarget.h b/llvm/lib/Target/BPF/BPFSubtarget.h +index aed2211265e2..e870dfdc85ec 100644 +--- a/llvm/lib/Target/BPF/BPFSubtarget.h ++++ b/llvm/lib/Target/BPF/BPFSubtarget.h +@@ -65,7 +65,7 @@ protected: + + // whether cpu v4 insns are enabled. + bool HasLdsx, HasMovsx, HasBswap, HasSdivSmod, HasGotol, HasStoreImm, +- HasLoadAcqStoreRel; ++ HasLoadAcqStoreRel, HasGotox; + + std::unique_ptr CallLoweringInfo; + std::unique_ptr InstSelector; +@@ -94,6 +94,7 @@ public: + bool hasGotol() const { return HasGotol; } + bool hasStoreImm() const { return HasStoreImm; } + bool hasLoadAcqStoreRel() const { return HasLoadAcqStoreRel; } ++ bool hasGotox() const { return HasGotox; } + + bool isLittleEndian() const { return IsLittleEndian; } + +diff --git a/llvm/lib/Target/BPF/BPFTargetLoweringObjectFile.cpp b/llvm/lib/Target/BPF/BPFTargetLoweringObjectFile.cpp +new file mode 100644 +index 000000000000..997f09870bad +--- /dev/null ++++ b/llvm/lib/Target/BPF/BPFTargetLoweringObjectFile.cpp +@@ -0,0 +1,19 @@ ++//===------------------ BPFTargetLoweringObjectFile.cpp -------------------===// ++// ++// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. ++// See https://llvm.org/LICENSE.txt for license information. ++// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception ++// ++//===----------------------------------------------------------------------===// ++ ++#include "BPFTargetLoweringObjectFile.h" ++#include "llvm/MC/MCContext.h" ++#include "llvm/MC/MCSectionELF.h" ++ ++using namespace llvm; ++ ++MCSection *BPFTargetLoweringObjectFileELF::getSectionForJumpTable( ++ const Function &F, const TargetMachine &TM, ++ const MachineJumpTableEntry *JTE) const { ++ return getContext().getELFSection(".jumptables", ELF::SHT_PROGBITS, 0); ++} +diff --git a/llvm/lib/Target/BPF/BPFTargetLoweringObjectFile.h b/llvm/lib/Target/BPF/BPFTargetLoweringObjectFile.h +new file mode 100644 +index 000000000000..f3064c0c8cb8 +--- /dev/null ++++ b/llvm/lib/Target/BPF/BPFTargetLoweringObjectFile.h +@@ -0,0 +1,25 @@ ++//===============- BPFTargetLoweringObjectFile.h -*- C++ -*-================// ++// ++// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. ++// See https://llvm.org/LICENSE.txt for license information. ++// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception ++// ++//===----------------------------------------------------------------------===// ++ ++#ifndef LLVM_LIB_TARGET_BPF_BPFTARGETLOWERINGOBJECTFILE ++#define LLVM_LIB_TARGET_BPF_BPFTARGETLOWERINGOBJECTFILE ++ ++#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" ++#include "llvm/Target/TargetLoweringObjectFile.h" ++ ++namespace llvm { ++class BPFTargetLoweringObjectFileELF : public TargetLoweringObjectFileELF { ++ ++public: ++ virtual MCSection * ++ getSectionForJumpTable(const Function &F, const TargetMachine &TM, ++ const MachineJumpTableEntry *JTE) const override; ++}; ++} // namespace llvm ++ ++#endif // LLVM_LIB_TARGET_BPF_BPFTARGETLOWERINGOBJECTFILE +diff --git a/llvm/lib/Target/BPF/BPFTargetMachine.cpp b/llvm/lib/Target/BPF/BPFTargetMachine.cpp +index 527a48035457..d538b6fe1167 100644 +--- a/llvm/lib/Target/BPF/BPFTargetMachine.cpp ++++ b/llvm/lib/Target/BPF/BPFTargetMachine.cpp +@@ -12,6 +12,7 @@ + + #include "BPFTargetMachine.h" + #include "BPF.h" ++#include "BPFTargetLoweringObjectFile.h" + #include "BPFTargetTransformInfo.h" + #include "MCTargetDesc/BPFMCAsmInfo.h" + #include "TargetInfo/BPFTargetInfo.h" +@@ -80,7 +81,7 @@ BPFTargetMachine::BPFTargetMachine(const Target &T, const Triple &TT, + : CodeGenTargetMachineImpl(T, computeDataLayout(TT), TT, CPU, FS, Options, + getEffectiveRelocModel(RM), + getEffectiveCodeModel(CM, CodeModel::Small), OL), +- TLOF(std::make_unique()), ++ TLOF(std::make_unique()), + Subtarget(TT, std::string(CPU), std::string(FS), *this) { + if (!DisableCheckUnreachable) { + this->Options.TrapUnreachable = true; +diff --git a/llvm/lib/Target/BPF/CMakeLists.txt b/llvm/lib/Target/BPF/CMakeLists.txt +index eade4cacb710..3678f1335ca3 100644 +--- a/llvm/lib/Target/BPF/CMakeLists.txt ++++ b/llvm/lib/Target/BPF/CMakeLists.txt +@@ -37,6 +37,7 @@ add_llvm_target(BPFCodeGen + BPFRegisterInfo.cpp + BPFSelectionDAGInfo.cpp + BPFSubtarget.cpp ++ BPFTargetLoweringObjectFile.cpp + BPFTargetMachine.cpp + BPFMIPeephole.cpp + BPFMIChecking.cpp +diff --git a/llvm/test/CodeGen/BPF/jump_table_blockaddr.ll b/llvm/test/CodeGen/BPF/jump_table_blockaddr.ll +new file mode 100644 +index 000000000000..d5a1d63b644a +--- /dev/null ++++ b/llvm/test/CodeGen/BPF/jump_table_blockaddr.ll +@@ -0,0 +1,91 @@ ++; Checks generated using command: ++; llvm/utils/update_test_body.py llvm/test/CodeGen/BPF/jump_table_blockaddr.ll ++ ++; RUN: rm -rf %t && split-file %s %t && cd %t ++; RUN: llc -march=bpf -mcpu=v4 < test.ll | FileCheck %s ++; ++; Source code: ++; int bar(int a) { ++; __label__ l1, l2; ++; void * volatile tgt; ++; int ret = 0; ++; if (a) ++; tgt = &&l1; // synthetic jump table generated here ++; else ++; tgt = &&l2; // another synthetic jump table ++; goto *tgt; ++; l1: ret += 1; ++; l2: ret += 2; ++; return ret; ++; } ++; ++; Compilation Flags: ++; clang --target=bpf -mcpu=v4 -O2 -emit-llvm -S test.c ++ ++.ifdef GEN ++;--- test.ll ++define dso_local range(i32 2, 4) i32 @bar(i32 noundef %a) local_unnamed_addr{ ++entry: ++ %tgt = alloca ptr, align 8 ++ %tobool.not = icmp eq i32 %a, 0 ++ %. = select i1 %tobool.not, ptr blockaddress(@bar, %l2), ptr blockaddress(@bar, %l1) ++ store volatile ptr %., ptr %tgt, align 8 ++ %tgt.0.tgt.0.tgt.0.tgt.0. = load volatile ptr, ptr %tgt, align 8 ++ indirectbr ptr %tgt.0.tgt.0.tgt.0.tgt.0., [label %l1, label %l2] ++ ++l1: ; preds = %entry ++ br label %l2 ++ ++l2: ; preds = %l1, %entry ++ %ret.0 = phi i32 [ 3, %l1 ], [ 2, %entry ] ++ ret i32 %ret.0 ++} ++ ++;--- gen ++echo "" ++echo "; Generated checks follow" ++echo ";" ++llc -march=bpf -mcpu=v4 < test.ll \ ++ | awk '/# -- End function/ {p=0} /@function/ {p=1} p {print "; CHECK" ": " $0}' ++ ++.endif ++ ++; Generated checks follow ++; ++; CHECK: .type bar,@function ++; CHECK: bar: # @bar ++; CHECK: .Lbar$local: ++; CHECK: .type .Lbar$local,@function ++; CHECK: .cfi_startproc ++; CHECK: # %bb.0: # %entry ++; CHECK: r2 = BPF.JT.0.0 ll ++; CHECK: r2 = *(u64 *)(r2 + 0) ++; CHECK: r3 = BPF.JT.0.1 ll ++; CHECK: r3 = *(u64 *)(r3 + 0) ++; CHECK: if w1 == 0 goto LBB0_2 ++; CHECK: # %bb.1: # %entry ++; CHECK: r3 = r2 ++; CHECK: LBB0_2: # %entry ++; CHECK: *(u64 *)(r10 - 8) = r3 ++; CHECK: r1 = *(u64 *)(r10 - 8) ++; CHECK: gotox r1 ++; CHECK: .Ltmp0: # Block address taken ++; CHECK: LBB0_3: # %l1 ++; CHECK: w0 = 3 ++; CHECK: goto LBB0_5 ++; CHECK: .Ltmp1: # Block address taken ++; CHECK: LBB0_4: # %l2 ++; CHECK: w0 = 2 ++; CHECK: LBB0_5: # %.split ++; CHECK: exit ++; CHECK: .Lfunc_end0: ++; CHECK: .size bar, .Lfunc_end0-bar ++; CHECK: .size .Lbar$local, .Lfunc_end0-bar ++; CHECK: .cfi_endproc ++; CHECK: .section .jumptables,"",@progbits ++; CHECK: BPF.JT.0.0: ++; CHECK: .quad LBB0_3 ++; CHECK: .size BPF.JT.0.0, 8 ++; CHECK: BPF.JT.0.1: ++; CHECK: .quad LBB0_4 ++; CHECK: .size BPF.JT.0.1, 8 +diff --git a/llvm/test/CodeGen/BPF/jump_table_global_var.ll b/llvm/test/CodeGen/BPF/jump_table_global_var.ll +new file mode 100644 +index 000000000000..bbca46850843 +--- /dev/null ++++ b/llvm/test/CodeGen/BPF/jump_table_global_var.ll +@@ -0,0 +1,83 @@ ++; Checks generated using command: ++; llvm/utils/update_test_body.py llvm/test/CodeGen/BPF/jump_table_global_var.ll ++ ++; RUN: rm -rf %t && split-file %s %t && cd %t ++; RUN: llc -march=bpf -mcpu=v4 < test.ll | FileCheck %s ++; ++; Source code: ++; int foo(unsigned a) { ++; __label__ l1, l2; ++; void *jt1[] = {[0]=&&l1, [1]=&&l2}; ++; int ret = 0; ++; ++; goto *jt1[a % 2]; ++; l1: ret += 1; ++; l2: ret += 3; ++; return ret; ++; } ++; ++; Compilation Flags: ++; clang --target=bpf -mcpu=v4 -O2 -emit-llvm -S test.c ++ ++.ifdef GEN ++;--- test.ll ++@__const.foo.jt1 = private unnamed_addr constant [2 x ptr] [ptr blockaddress(@foo, %l1), ptr blockaddress(@foo, %l2)], align 8 ++ ++define dso_local range(i32 3, 5) i32 @foo(i32 noundef %a) local_unnamed_addr { ++entry: ++ %rem = and i32 %a, 1 ++ %idxprom = zext nneg i32 %rem to i64 ++ %arrayidx = getelementptr inbounds nuw [2 x ptr], ptr @__const.foo.jt1, i64 0, i64 %idxprom ++ %0 = load ptr, ptr %arrayidx, align 8 ++ indirectbr ptr %0, [label %l1, label %l2] ++ ++l1: ; preds = %entry ++ br label %l2 ++ ++l2: ; preds = %l1, %entry ++ %ret.0 = phi i32 [ 4, %l1 ], [ 3, %entry ] ++ ret i32 %ret.0 ++} ++ ++;--- gen ++echo "" ++echo "; Generated checks follow" ++echo ";" ++llc -march=bpf -mcpu=v4 < test.ll \ ++ | awk '/# -- End function/ {p=0} /@function/ {p=1} p {print "; CHECK" ": " $0}' ++ ++.endif ++ ++; Generated checks follow ++; ++; CHECK: .type foo,@function ++; CHECK: foo: # @foo ++; CHECK: .Lfoo$local: ++; CHECK: .type .Lfoo$local,@function ++; CHECK: .cfi_startproc ++; CHECK: # %bb.0: # %entry ++; CHECK: # kill: def $w1 killed $w1 def $r1 ++; CHECK: w1 &= 1 ++; CHECK: r1 <<= 3 ++; CHECK: r2 = BPF.JT.0.0 ll ++; CHECK: r2 += r1 ++; CHECK: r1 = *(u64 *)(r2 + 0) ++; CHECK: gotox r1 ++; CHECK: .Ltmp0: # Block address taken ++; CHECK: LBB0_1: # %l1 ++; CHECK: w0 = 4 ++; CHECK: goto LBB0_3 ++; CHECK: .Ltmp1: # Block address taken ++; CHECK: LBB0_2: # %l2 ++; CHECK: w0 = 3 ++; CHECK: LBB0_3: # %.split ++; CHECK: exit ++; CHECK: .Lfunc_end0: ++; CHECK: .size foo, .Lfunc_end0-foo ++; CHECK: .size .Lfoo$local, .Lfunc_end0-foo ++; CHECK: .cfi_endproc ++; CHECK: .section .jumptables,"",@progbits ++; CHECK: BPF.JT.0.0: ++; CHECK: .quad LBB0_1 ++; CHECK: .quad LBB0_2 ++; CHECK: .size BPF.JT.0.0, 16 +diff --git a/llvm/test/CodeGen/BPF/jump_table_switch_stmt.ll b/llvm/test/CodeGen/BPF/jump_table_switch_stmt.ll +new file mode 100644 +index 000000000000..682b025d665d +--- /dev/null ++++ b/llvm/test/CodeGen/BPF/jump_table_switch_stmt.ll +@@ -0,0 +1,126 @@ ++; Checks generated using command: ++; llvm/utils/update_test_body.py llvm/test/CodeGen/BPF/jump_table_switch_stmt.ll ++ ++; RUN: rm -rf %t && split-file %s %t && cd %t ++; RUN: llc -march=bpf -mcpu=v4 -bpf-min-jump-table-entries=3 < test.ll | FileCheck %s ++; ++; Source code: ++; int ret_user; ++; int foo(int a) ++; { ++; switch (a) { ++; case 1: ret_user = 18; break; ++; case 20: ret_user = 6; break; ++; case 30: ret_user = 2; break; ++; default: break; ++; } ++; return 0; ++; } ++; ++; Compilation Flags: ++; clang --target=bpf -mcpu=v4 -O2 -emit-llvm -S test.c ++ ++.ifdef GEN ++;--- test.ll ++@ret_user = dso_local local_unnamed_addr global i32 0, align 4 ++ ++define dso_local noundef i32 @foo(i32 noundef %a) local_unnamed_addr { ++entry: ++ switch i32 %a, label %sw.epilog [ ++ i32 1, label %sw.epilog.sink.split ++ i32 20, label %sw.bb1 ++ i32 30, label %sw.bb2 ++ ] ++ ++sw.bb1: ; preds = %entry ++ br label %sw.epilog.sink.split ++ ++sw.bb2: ; preds = %entry ++ br label %sw.epilog.sink.split ++ ++sw.epilog.sink.split: ; preds = %entry, %sw.bb1, %sw.bb2 ++ %.sink = phi i32 [ 2, %sw.bb2 ], [ 6, %sw.bb1 ], [ 18, %entry ] ++ store i32 %.sink, ptr @ret_user, align 4 ++ br label %sw.epilog ++ ++sw.epilog: ; preds = %sw.epilog.sink.split, %entry ++ ret i32 0 ++} ++ ++;--- gen ++echo "" ++echo "; Generated checks follow" ++echo ";" ++llc -march=bpf -mcpu=v4 -bpf-min-jump-table-entries=3 < test.ll \ ++ | awk '/# -- End function/ {p=0} /@function/ {p=1} p {print "; CHECK" ": " $0}' ++ ++.endif ++ ++; Generated checks follow ++; ++; CHECK: .type foo,@function ++; CHECK: foo: # @foo ++; CHECK: .Lfoo$local: ++; CHECK: .type .Lfoo$local,@function ++; CHECK: .cfi_startproc ++; CHECK: # %bb.0: # %entry ++; CHECK: # kill: def $w1 killed $w1 def $r1 ++; CHECK: w1 += -1 ++; CHECK: if w1 > 29 goto LBB0_5 ++; CHECK: # %bb.1: # %entry ++; CHECK: w2 = 18 ++; CHECK: r1 <<= 3 ++; CHECK: r3 = BPF.JT.0.0 ll ++; CHECK: r4 = BPF.JT.0.0 ll ++; CHECK: r4 += r1 ++; CHECK: r1 = *(u64 *)(r4 + 0) ++; CHECK: r3 += r1 ++; CHECK: gotox r3 ++; CHECK: LBB0_2: # %sw.bb1 ++; CHECK: w2 = 6 ++; CHECK: goto LBB0_4 ++; CHECK: LBB0_3: # %sw.bb2 ++; CHECK: w2 = 2 ++; CHECK: LBB0_4: # %sw.epilog.sink.split ++; CHECK: r1 = ret_user ll ++; CHECK: *(u32 *)(r1 + 0) = w2 ++; CHECK: LBB0_5: # %sw.epilog ++; CHECK: w0 = 0 ++; CHECK: exit ++; CHECK: .Lfunc_end0: ++; CHECK: .size foo, .Lfunc_end0-foo ++; CHECK: .size .Lfoo$local, .Lfunc_end0-foo ++; CHECK: .cfi_endproc ++; CHECK: .section .jumptables,"",@progbits ++; CHECK: BPF.JT.0.0: ++; CHECK: .quad LBB0_4 ++; CHECK: .quad LBB0_5 ++; CHECK: .quad LBB0_5 ++; CHECK: .quad LBB0_5 ++; CHECK: .quad LBB0_5 ++; CHECK: .quad LBB0_5 ++; CHECK: .quad LBB0_5 ++; CHECK: .quad LBB0_5 ++; CHECK: .quad LBB0_5 ++; CHECK: .quad LBB0_5 ++; CHECK: .quad LBB0_5 ++; CHECK: .quad LBB0_5 ++; CHECK: .quad LBB0_5 ++; CHECK: .quad LBB0_5 ++; CHECK: .quad LBB0_5 ++; CHECK: .quad LBB0_5 ++; CHECK: .quad LBB0_5 ++; CHECK: .quad LBB0_5 ++; CHECK: .quad LBB0_5 ++; CHECK: .quad LBB0_2 ++; CHECK: .quad LBB0_5 ++; CHECK: .quad LBB0_5 ++; CHECK: .quad LBB0_5 ++; CHECK: .quad LBB0_5 ++; CHECK: .quad LBB0_5 ++; CHECK: .quad LBB0_5 ++; CHECK: .quad LBB0_5 ++; CHECK: .quad LBB0_5 ++; CHECK: .quad LBB0_5 ++; CHECK: .quad LBB0_3 ++; CHECK: .size BPF.JT.0.0, 240 +-- +2.50.1 + diff --git a/0002-BPF-Remove-unused-weak-symbol-__bpf_trap-166003.patch b/0002-BPF-Remove-unused-weak-symbol-__bpf_trap-166003.patch new file mode 100644 index 0000000..0c7e018 --- /dev/null +++ b/0002-BPF-Remove-unused-weak-symbol-__bpf_trap-166003.patch @@ -0,0 +1,130 @@ +From be4fa19ecf95d94d3ef46be183d3d4b4ebb6bb47 Mon Sep 17 00:00:00 2001 +From: yonghong-song +Date: Mon, 3 Nov 2025 11:11:47 -0800 +Subject: [PATCH] [BPF] Remove unused weak symbol __bpf_trap (#166003) + +Nikita Popov reported an issue ([1]) where a dangling weak symbol +__bpf_trap is in the final binary and this caused libbpf failing like +below: + + $ veristat -v ./t.o + Processing 't.o'... + libbpf: elf: skipping unrecognized data section(4) .eh_frame + libbpf: elf: skipping relo section(5) .rel.eh_frame for section(4) .eh_frame + libbpf: failed to find BTF for extern '__bpf_trap': -3 + Failed to open './t.o': -3 + +In llvm, the dag selection phase generates __bpf_trap in code. Later the +UnreachableBlockElim pass removed __bpf_trap from the code, but +__bpf_trap symbol survives in the symbol table. + +Having a dangling __bpf_trap weak symbol is not good for old kernels as +seen in the above veristat failure. Although users could use compiler +flag `-mllvm -bpf-disable-trap-unreachable` to workaround the issue, +this patch fixed the issue by removing the dangling __bpf_trap. + + [1] https://github.com/llvm/llvm-project/issues/165696 + +(cherry picked from commit 8fd1bf2f8c9e6e7c4bc5f6915a9d52bb3672601b) +--- + llvm/lib/Target/BPF/BPFAsmPrinter.cpp | 24 ++++++++++++++++++++ + llvm/lib/Target/BPF/BPFAsmPrinter.h | 1 + + llvm/test/CodeGen/BPF/bpf_trap.ll | 32 +++++++++++++++++++++++++++ + 3 files changed, 57 insertions(+) + create mode 100644 llvm/test/CodeGen/BPF/bpf_trap.ll + +diff --git a/llvm/lib/Target/BPF/BPFAsmPrinter.cpp b/llvm/lib/Target/BPF/BPFAsmPrinter.cpp +index 77dc4a75a7d6..b2a82040ee82 100644 +--- a/llvm/lib/Target/BPF/BPFAsmPrinter.cpp ++++ b/llvm/lib/Target/BPF/BPFAsmPrinter.cpp +@@ -88,6 +88,16 @@ bool BPFAsmPrinter::doFinalization(Module &M) { + } + } + ++ for (GlobalObject &GO : M.global_objects()) { ++ if (!GO.hasExternalWeakLinkage()) ++ continue; ++ ++ if (!SawTrapCall && GO.getName() == BPF_TRAP) { ++ GO.eraseFromParent(); ++ break; ++ } ++ } ++ + return AsmPrinter::doFinalization(M); + } + +@@ -160,6 +170,20 @@ bool BPFAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, + } + + void BPFAsmPrinter::emitInstruction(const MachineInstr *MI) { ++ if (MI->isCall()) { ++ for (const MachineOperand &Op : MI->operands()) { ++ if (Op.isGlobal()) { ++ if (const GlobalValue *GV = Op.getGlobal()) ++ if (GV->getName() == BPF_TRAP) ++ SawTrapCall = true; ++ } else if (Op.isSymbol()) { ++ if (const MCSymbol *Sym = Op.getMCSymbol()) ++ if (Sym->getName() == BPF_TRAP) ++ SawTrapCall = true; ++ } ++ } ++ } ++ + BPF_MC::verifyInstructionPredicates(MI->getOpcode(), + getSubtargetInfo().getFeatureBits()); + +diff --git a/llvm/lib/Target/BPF/BPFAsmPrinter.h b/llvm/lib/Target/BPF/BPFAsmPrinter.h +index 0cfb2839c8ff..60a285ea2b7d 100644 +--- a/llvm/lib/Target/BPF/BPFAsmPrinter.h ++++ b/llvm/lib/Target/BPF/BPFAsmPrinter.h +@@ -39,6 +39,7 @@ public: + private: + BTFDebug *BTF; + TargetMachine &TM; ++ bool SawTrapCall = false; + + const BPFTargetMachine &getBTM() const; + }; +diff --git a/llvm/test/CodeGen/BPF/bpf_trap.ll b/llvm/test/CodeGen/BPF/bpf_trap.ll +new file mode 100644 +index 000000000000..ab8df5ff7cb0 +--- /dev/null ++++ b/llvm/test/CodeGen/BPF/bpf_trap.ll +@@ -0,0 +1,32 @@ ++; RUN: llc < %s | FileCheck %s ++; ++target triple = "bpf" ++ ++define i32 @test(i8 %x) { ++entry: ++ %0 = and i8 %x, 3 ++ switch i8 %0, label %default.unreachable4 [ ++ i8 0, label %return ++ i8 1, label %sw.bb1 ++ i8 2, label %sw.bb2 ++ i8 3, label %sw.bb3 ++ ] ++ ++sw.bb1: ; preds = %entry ++ br label %return ++ ++sw.bb2: ; preds = %entry ++ br label %return ++ ++sw.bb3: ; preds = %entry ++ br label %return ++ ++default.unreachable4: ; preds = %entry ++ unreachable ++ ++return: ; preds = %entry, %sw.bb3, %sw.bb2, %sw.bb1 ++ %retval.0 = phi i32 [ 12, %sw.bb1 ], [ 43, %sw.bb2 ], [ 54, %sw.bb3 ], [ 32, %entry ] ++ ret i32 %retval.0 ++} ++ ++; CHECK-NOT: __bpf_trap +-- +2.50.1 + diff --git a/0003-BPF-Remove-dead-code-related-to-__bpf_trap-global-va.patch b/0003-BPF-Remove-dead-code-related-to-__bpf_trap-global-va.patch new file mode 100644 index 0000000..08de31e --- /dev/null +++ b/0003-BPF-Remove-dead-code-related-to-__bpf_trap-global-va.patch @@ -0,0 +1,34 @@ +From ac5b6151976c70c8b676d3bc6ff82895fe0e1d01 Mon Sep 17 00:00:00 2001 +From: yonghong-song +Date: Tue, 4 Nov 2025 15:15:33 -0800 +Subject: [PATCH] [BPF] Remove dead code related to __bpf_trap global var + (#166440) + +In [1], the symbol __bpf_trap (macro BPF_TRAP) is removed if it is not +used in the code. In the discussion in [1], it is found that the branch +"if (Op.isSymbol())" is actually always false. Remove it to avoid +confusion. + + [1] https://github.com/llvm/llvm-project/pull/166003 +--- + llvm/lib/Target/BPF/BPFAsmPrinter.cpp | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/llvm/lib/Target/BPF/BPFAsmPrinter.cpp b/llvm/lib/Target/BPF/BPFAsmPrinter.cpp +index 378a72ab27dd..abe081c0c76f 100644 +--- a/llvm/lib/Target/BPF/BPFAsmPrinter.cpp ++++ b/llvm/lib/Target/BPF/BPFAsmPrinter.cpp +@@ -176,10 +176,6 @@ void BPFAsmPrinter::emitInstruction(const MachineInstr *MI) { + if (const GlobalValue *GV = Op.getGlobal()) + if (GV->getName() == BPF_TRAP) + SawTrapCall = true; +- } else if (Op.isSymbol()) { +- if (const MCSymbol *Sym = Op.getMCSymbol()) +- if (Sym->getName() == BPF_TRAP) +- SawTrapCall = true; + } + } + } +-- +2.50.1 + diff --git a/llvm.spec b/llvm.spec index f48fb5c..1385227 100644 --- a/llvm.spec +++ b/llvm.spec @@ -2,7 +2,7 @@ #region version %global maj_ver 21 %global min_ver 1 -%global patch_ver 4 +%global patch_ver 7 #global rc_ver rc3 %bcond_with snapshot_build @@ -19,6 +19,24 @@ %bcond_with gold %endif +# Enable this in order to disable a lot of features and get to clang as fast +# as possible. This is useful in order to bisect issues affecting LLVM, clang +# or LLD. +%bcond_with fastclang +%if %{with fastclang} +%define bcond_override_default_lldb 0 +%define bcond_override_default_offload 0 +%define bcond_override_default_mlir 0 +%define bcond_override_default_flang 0 +%define bcond_override_default_build_bolt 0 +%define bcond_override_default_polly 0 +%define bcond_override_default_pgo 0 +%define bcond_override_default_libcxx 0 +%define bcond_override_default_lto_build 0 +%define bcond_override_default_check 0 +%define _find_debuginfo_dwz_opts %{nil} +%endif + # Build compat packages llvmN instead of main package for the current LLVM # version. Used on Fedora. %bcond_with compat_build @@ -236,8 +254,10 @@ end %global __cxx /usr/bin/clang++-%{host_clang_maj_ver} %endif -%if %{defined rhel} && 0%{?rhel} < 10 -%global gts_version 14 +# The upper bound must remain and never exceed the latest RHEL version with GTS, +# so that this does not apply to ELN or a brand new RHEL version. +%if %{defined rhel} && 0%{?rhel} <= 10 +%global gts_version 15 %endif %if %{defined rhel} && 0%{?rhel} <= 8 @@ -493,9 +513,13 @@ Patch2202: 0001-22-polly-shared-libs.patch #region RHEL patches # RHEL 8 only Patch501: 0001-Fix-page-size-constant-on-aarch64-and-ppc64le.patch -# Ensure that the BPF backend does not require kfunc __bpf_trap which is not -# available on RHEL 8. -Patch502: 0001-BPF-Revert-the-behavior-when-handling-traps.patch +# Backport a fix for https://github.com/llvm/llvm-project/issues/165696 from +# LLVM 22. The first patch is a requirement of the second patch. +# Apply the fix to RHEL8 only because the other distros do not need this fix +# because they already support kfunc __bpf_trap. +Patch502: 0001-BPF-Support-Jump-Table-149715.patch +Patch503: 0002-BPF-Remove-unused-weak-symbol-__bpf_trap-166003.patch +Patch504: 0003-BPF-Remove-dead-code-related-to-__bpf_trap-global-va.patch #endregion RHEL patches # Fix a pgo miscompilation triggered by building Rust 1.87 with pgo on ppc64le. @@ -523,6 +547,13 @@ Patch2201: 0001-clang-Add-a-hack-to-fix-the-offload-build-with-the-m.patch %global __python3 /usr/bin/python3.12 %endif +%if %{with fastclang} +# fastclang depends on overriding default conditionals via +# bcond_override_default which is only available on RPM 4.20 and newer. +# More info: +# https://rpm-software-management.github.io/rpm/manual/conditionalbuilds.html#overriding-defaults +BuildRequires: rpm >= 4.20 +%endif %if %{defined gts_version} # Required for 64-bit atomics on i686. BuildRequires: gcc-toolset-%{gts_version}-libatomic-devel @@ -568,6 +599,10 @@ BuildRequires: python3-scipy %endif %endif +%else +%if %{with use_lld} +BuildRequires: lld +%endif %endif # This intentionally does not use python3_pkgversion. RHEL 8 does not have @@ -834,7 +869,11 @@ Requires: gcc-toolset-%{gts_version}-gcc-c++ Recommends: %{pkg_name_compiler_rt}%{?_isa} = %{version}-%{release} Requires: %{pkg_name_llvm}-libs = %{version}-%{release} # atomic support is not part of compiler-rt +%if %{defined gts_version} +Recommends: gcc-toolset-%{gts_version}-libatomic-devel +%else Recommends: libatomic%{?_isa} +%endif # libomp-devel is required, so clang can find the omp.h header when compiling # with -fopenmp. Recommends: %{pkg_name_libomp}-devel%{_isa} = %{version}-%{release} @@ -1305,7 +1344,12 @@ Flang runtime libraries. %if %{defined rhel} && 0%{?rhel} == 8 %patch -p1 -P501 +%if %{maj_ver} < 22 +# The following patches have been backported from LLVM 22. %patch -p1 -P502 +%patch -p1 -P503 +%patch -p1 -P504 +%endif %endif #region LLVM preparation @@ -1375,7 +1419,7 @@ cd llvm/utils/lit %ifarch %ix86 %global reduce_debuginfo 1 %endif -%if 0%{?rhel} == 8 +%if 0%{?rhel} == 8 || %{with fastclang} %global reduce_debuginfo 1 %endif @@ -1416,7 +1460,10 @@ cd llvm/utils/lit %global runtimes %{runtimes};offload %endif -%global cfg_file_content --gcc-triple=%{_target_cpu}-redhat-linux +%global gcc_triple --gcc-triple=%{_target_cpu}-redhat-linux + +%global cfg_file_content %{gcc_triple} +%global cfg_file_content_flang %{gcc_triple} # We want to use DWARF-5 on all snapshot builds. %if %{without snapshot_build} && %{defined rhel} && 0%{?rhel} < 10 @@ -2335,6 +2382,7 @@ rm -v %{buildroot}%{install_libdir}/libFIRAnalysis.a \ %{buildroot}%{install_libdir}/libFortranDecimal.a %if %{maj_ver} >= 22 rm -v %{buildroot}%{install_libdir}/libFortranUtils.a \ + %{buildroot}%{install_libdir}/libFIROpenACCAnalysis.a \ %{buildroot}%{install_libdir}/libFIROpenACCTransforms.a \ %{buildroot}%{install_libdir}/libMIFDialect.a %endif @@ -2343,6 +2391,14 @@ find %{buildroot}%{install_includedir}/flang -type f -a ! -iname '*.mod' -delete # this is a test binary rm -v %{buildroot}%{install_bindir}/f18-parse-demo + +# Probably this directory already existed before +mkdir -pv %{buildroot}%{_sysconfdir}/%{pkg_name_clang}/ +echo " %{cfg_file_content_flang}" >> %{buildroot}%{_sysconfdir}/%{pkg_name_clang}/%{_target_platform}-flang.cfg +%ifarch x86_64 +# On x86_64, install an additional config file. +echo " %{cfg_file_content_flang}" >> %{buildroot}%{_sysconfdir}/%{pkg_name_clang}/i386-redhat-linux-gnu-flang.cfg +%endif %endif #endregion flang installation @@ -2454,6 +2510,17 @@ install -m 0755 ../llvm-compat-libs/lib/liblldb.so.%{compat_maj_ver}* %{buildroo # TODO(kkleine): Instead of deleting test files we should mark them as expected # to fail. See https://llvm.org/docs/CommandGuide/lit.html#cmdoption-lit-xfail +# Tell if the GTS version used by the newly built clang is equal to the +# expected version. +function is_gts_equal { + local gts_used=$(`pwd`/%{_vpath_builddir}/bin/clang -v 2>&1 | grep "Selected GCC installation" | sed 's|.*/\([0-9]\+\)$|\1|') + if [[ -z "%{gts_version}" ]]; then + return 0 + fi + test "x$gts_used" = "x%{gts_version}" + return $? +} + # Increase open file limit while running tests. if [[ $(ulimit -n) -lt 10000 ]]; then ulimit -n 10000 @@ -2755,7 +2822,16 @@ export LD_LIBRARY_PATH=%{buildroot}%{_prefix}/lib/clang/%{maj_ver}/lib/%{llvm_tr %if 0%{?rhel} # libomp tests are often very slow on s390x brew builders %ifnarch s390x riscv64 -%cmake_build --target check-openmp +# Rarely, the system clang uses a GCC installation directory that is +# different from what we'd like to build with. +# Our newly built clang ends up using that old GCC because of the config +# files under /etc/clang pointing to the old GCC. We won't be able to run all +# tests because the installed libatomic cannot be found due to our newly built +# clang using the wrong GCC directory, e.g. we installed the libatomic from +# the latest GTS, but the installed GCC is 1 version earlier. +if is_gts_equal; then + %cmake_build --target check-openmp +fi %endif %else %cmake_build --target check-openmp @@ -3252,6 +3328,11 @@ fi llvm-opt-fuzzer llvm-test-mustache-spec }} +%if %{maj_ver} >= 22 +%{expand_bins %{expand: + llvm-cas +}} +%endif %{expand_mans %{expand: llvm-test-mustache-spec }} @@ -3458,6 +3539,11 @@ fi %ifnarch %{ix86} s390x riscv64 %{_prefix}/lib/clang/%{maj_ver}/lib/%{compiler_rt_triple}/liborc_rt.a %endif +%ifarch s390x +%if %{maj_ver} >= 22 +%{_prefix}/lib/clang/%{maj_ver}/lib/%{compiler_rt_triple}/liborc_rt.a +%endif +%endif # Additional symlink if two triples are in use. %if "%{llvm_triple}" != "%{compiler_rt_triple}" @@ -3611,6 +3697,12 @@ fi libMLIR*.so.%{maj_ver}* }} +%if %{maj_ver} >= 22 +%{expand_libs %{expand: + libmlir_apfloat_wrappers.so.%{maj_ver}* +}} +%endif + %files -n %{pkg_name_mlir}-static %expand_libs libMLIR*.a @@ -3642,6 +3734,12 @@ fi libMLIR*.so }} +%if %{maj_ver} >= 22 +%{expand_libs %{expand: + libmlir_apfloat_wrappers.so +}} +%endif + %files -n python%{python3_pkgversion}-%{pkg_name_mlir} %{python3_sitearch}/mlir/ %endif @@ -3682,7 +3780,12 @@ fi flang/iso_fortran_env_impl.mod flang/omp_lib.mod flang/omp_lib_kinds.mod + flang/flang_debug.mod }} +%{_sysconfdir}/%{pkg_name_clang}/%{_target_platform}-flang.cfg +%ifarch x86_64 +%{_sysconfdir}/%{pkg_name_clang}/i386-redhat-linux-gnu-flang.cfg +%endif %{_prefix}/lib/clang/%{maj_ver}/include/ISO_Fortran_binding.h diff --git a/sources b/sources index b92ad3a..4f012ca 100644 --- a/sources +++ b/sources @@ -1,4 +1,4 @@ -SHA512 (llvm-project-21.1.4.src.tar.xz) = a8c0883abe7c5a3e55ca7ed0fd974fae4351184a0b0df18295a982ca8ddb0f8d167353564204ed00f0cd9a1d8baef7074c0b39a99e0b5c52ced6bbee73dde3da -SHA512 (llvm-project-21.1.4.src.tar.xz.sig) = 4812c2e3861aa3b726d842c3ca259b19ef1aa531fed9f6f47099483de91de2b2a165f40d243f6f40f2eea749741d5f8b7090f394399c56db02053f308921077a SHA512 (llvm-project-20.1.8.src.tar.xz) = f330e72e6a1da468569049437cc0ba7a41abb816ccece7367189344f7ebfef730f4788ac7af2bef0aa8a49341c15ab1d31e941ffa782f264d11fe0dc05470773 SHA512 (llvm-project-20.1.8.src.tar.xz.sig) = d74369bdb4d1b82775161ea53c9c5f3a23ce810f4df5ff617123023f9d8ce720e7d6ecc9e17f8ebd39fd9e7a9de79560abdf2ffe73bcb907a43148d43665d619 +SHA512 (llvm-project-21.1.7.src.tar.xz) = ae30a53ed929df979849f7433bf705bc3d540aa9e12a02a175eb2483d1a56f9ca1203c9b67795f6e84cf2407c28d46d5d5351b290d8735adb5206103fee6f379 +SHA512 (llvm-project-21.1.7.src.tar.xz.sig) = d02b09c77abd537eb24d6d43470f962c80a9ec6ccc03ac0efc950d90dbdec5b94dd6abad18143890ff85cee2bdeb7bcf1dac2a576ffcab8ef053d8526417bdcc