diff --git a/.gitignore b/.gitignore index 0ee3384..65eb8c7 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ /BUILDROOT /out /version.spec.inc +/.gdbinit 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/0001-SystemZ-Fix-ICE-with-i128-i64-uaddo-carry-chain.patch b/0001-SystemZ-Fix-ICE-with-i128-i64-uaddo-carry-chain.patch deleted file mode 100644 index 4ec2d1d..0000000 --- a/0001-SystemZ-Fix-ICE-with-i128-i64-uaddo-carry-chain.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 6d5697f7cb4e933d2f176c46b7ac05a9cbaeb8b6 Mon Sep 17 00:00:00 2001 -From: Ulrich Weigand -Date: Thu, 23 Jan 2025 19:11:18 +0100 -Subject: [PATCH] [SystemZ] Fix ICE with i128->i64 uaddo carry chain - -We can only optimize a uaddo_carry via specialized instruction -if the carry was produced by another uaddo(_carry) instruction; -there is already a check for that. - -However, i128 uaddo(_carry) use a completely different mechanism; -they indicate carry in a vector register instead of the CC flag. -Thus, we must also check that we don't mix those two - that check -has been missing. - -Fixes: https://github.com/llvm/llvm-project/issues/124001 ---- - .../Target/SystemZ/SystemZISelLowering.cpp | 12 ++++++---- - llvm/test/CodeGen/SystemZ/pr124001.ll | 23 +++++++++++++++++++ - 2 files changed, 31 insertions(+), 4 deletions(-) - create mode 100644 llvm/test/CodeGen/SystemZ/pr124001.ll - -diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp -index 4040ab6d4510..1fb31c26e20d 100644 ---- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp -+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp -@@ -4708,15 +4708,19 @@ SDValue SystemZTargetLowering::lowerXALUO(SDValue Op, - } - - static bool isAddCarryChain(SDValue Carry) { -- while (Carry.getOpcode() == ISD::UADDO_CARRY) -+ while (Carry.getOpcode() == ISD::UADDO_CARRY && -+ Carry->getValueType(0) != MVT::i128) - Carry = Carry.getOperand(2); -- return Carry.getOpcode() == ISD::UADDO; -+ return Carry.getOpcode() == ISD::UADDO && -+ Carry->getValueType(0) != MVT::i128; - } - - static bool isSubBorrowChain(SDValue Carry) { -- while (Carry.getOpcode() == ISD::USUBO_CARRY) -+ while (Carry.getOpcode() == ISD::USUBO_CARRY && -+ Carry->getValueType(0) != MVT::i128) - Carry = Carry.getOperand(2); -- return Carry.getOpcode() == ISD::USUBO; -+ return Carry.getOpcode() == ISD::USUBO && -+ Carry->getValueType(0) != MVT::i128; - } - - // Lower UADDO_CARRY/USUBO_CARRY nodes. -diff --git a/llvm/test/CodeGen/SystemZ/pr124001.ll b/llvm/test/CodeGen/SystemZ/pr124001.ll -new file mode 100644 -index 000000000000..9cf630a55dd6 ---- /dev/null -+++ b/llvm/test/CodeGen/SystemZ/pr124001.ll -@@ -0,0 +1,23 @@ -+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 -+; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z13 | FileCheck %s -+ -+define i64 @test(i128 %in) { -+; CHECK-LABEL: test: -+; CHECK: # %bb.0: -+; CHECK-NEXT: larl %r1, .LCPI0_0 -+; CHECK-NEXT: vl %v0, 0(%r2), 3 -+; CHECK-NEXT: vl %v1, 0(%r1), 3 -+; CHECK-NEXT: vaccq %v0, %v0, %v1 -+; CHECK-NEXT: vlgvg %r1, %v0, 1 -+; CHECK-NEXT: la %r2, 1(%r1) -+; CHECK-NEXT: br %r14 -+ %1 = tail call { i128, i1 } @llvm.uadd.with.overflow.i128(i128 %in, i128 1) -+ %2 = extractvalue { i128, i1 } %1, 1 -+ %3 = zext i1 %2 to i64 -+ %4 = add i64 %3, 1 -+ ret i64 %4 -+} -+ -+declare { i128, i1 } @llvm.uadd.with.overflow.i128(i128, i128) #0 -+ -+attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } --- -2.48.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/llvm.spec b/llvm.spec index 5849ed1..c28ca09 100644 --- a/llvm.spec +++ b/llvm.spec @@ -2,7 +2,7 @@ #region version %global maj_ver 21 %global min_ver 1 -%global patch_ver 3 +%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 @@ -49,16 +67,18 @@ %else %bcond_without offload %endif -%elifarch %{ix86} +%else +%ifarch %{ix86} # libomptarget is not supported on 32-bit systems. %bcond_with offload %else %bcond_without offload %endif +%endif # MLIR version 22 started to require nanobind >= 2.9, which is only available # on Fedora >= 44. -%if %{without compat_build} && ((%{maj_ver} >= 22 && 0%{?fedora} >= 44) || (%{maj_ver} < 22 && 0%{?fedora} >= 41)) +%if %{without compat_build} && %{defined fedora} && (%{maj_ver} < 22 || 0%{?fedora} >= 44) %ifarch %{ix86} %bcond_with mlir %else @@ -68,10 +88,69 @@ %bcond_with mlir %endif +#region flang +%if %{without compat_build} && %{defined fedora} && (%{maj_ver} >= 22 && 0%{?fedora} >= 44) +# Link error on i686. +# s390x is not supported upstream yet. +%ifarch i686 s390x +%bcond_with flang +%else +%bcond_without flang +%endif +%endif + +%if %{with flang} + +# Sanity check for flang +# flang depends on mlir, clang, flang, openmp. +# Make sure those are being built. +%if %{without mlir} +%{error:flang must be built --with=mlir} +%endif + +# Set Fortran build flags to nil because they contain flags that don't apply to flang. +%global build_fflags %{nil} + +%{lua: + +-- Return the maximum number of parallel jobs a build can run based on the +-- amount of maximum memory used per process (per_proc_mem). +function print_max_procs(per_proc_mem) + local f = io.open("/proc/meminfo", "r") + local mem = 0 + local nproc_str = nil + for line in f:lines() do + _, _, mem = string.find(line, "MemTotal:%s+(%d+)%s+kB") + if mem then + break + end + end + f:close() + + local proc_handle = io.popen("nproc") + _, _, nproc_str = string.find(proc_handle:read("*a"), "(%d+)") + proc_handle:close() + local nproc = tonumber(nproc_str) + if nproc < 1 then + nproc = 1 + end + local mem_mb = mem / 1024 + local cpu = math.floor(mem_mb / per_proc_mem) + if cpu < 1 then + cpu = 1 + end + + if cpu > nproc then + cpu = nproc + end + print(cpu) +end +} +%endif +#endregion flang + # The libcxx build condition also enables libcxxabi and libunwind. -# Fedora 41 is the first version that enabled FatLTO for clang-built files. -# Without FatLTO, we can't enable ThinLTO and link using GNU LD. -%if %{without compat_build} && 0%{?fedora} >= 41 +%if %{without compat_build} && %{defined fedora} %bcond_without libcxx %else %bcond_with libcxx @@ -79,7 +158,7 @@ # I've called the build condition "build_bolt" to indicate that this does not # necessarily "use" BOLT in order to build LLVM. -%if %{without compat_build} && 0%{?fedora} >= 41 +%if %{without compat_build} && %{defined fedora} # BOLT only supports aarch64 and x86_64 %ifarch aarch64 x86_64 %bcond_without build_bolt @@ -90,7 +169,7 @@ %bcond_with build_bolt %endif -%if %{without compat_build} && 0%{?fedora} >= 41 +%if %{without compat_build} && %{defined fedora} %bcond_without polly %else %bcond_with polly @@ -131,8 +210,24 @@ %ifarch %ix86 riscv64 %bcond_with lto_build %else +%if %{defined rhel} && 0%{?rhel} <= 8 +# LTO builds got enabled on Fedora and RHEL >= 9 only. +%bcond_with lto_build +%else %bcond_without lto_build %endif +%endif + +# Historically, LLD was used used at the same combinations that enabled PGO. +# If this changes, we need to update the following lines. +# However, we should be able to link using LLD even if PGO is disabled. +# Reminder: RHEL8 still builds with gcc + ld.bfd. +%if %{with pgo} +%bcond_without use_lld +%else +# RHEL8 still builds with gcc + ld.bfd. +%bcond_with use_lld +%endif # For PGO Disable LTO for now because of LLVMgold.so not found error # Use LLVM_ENABLE_LTO:BOOL=ON flags to enable LTO instead @@ -142,6 +237,7 @@ # We are building with clang for faster/lower memory LTO builds. # See https://docs.fedoraproject.org/en-US/packaging-guidelines/#_compiler_macros +# Reminder: This only works on Fedora and RHEL >= 9. %global toolchain clang # Make sure that we are not building with a newer compiler than the targeted @@ -158,8 +254,10 @@ %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 @@ -314,6 +412,10 @@ %endif #endregion PGO globals +#region flang globals +%global pkg_name_flang flang%{pkg_suffix} +#endregion flang globals + #endregion globals #region packages @@ -411,6 +513,12 @@ Patch2202: 0001-22-polly-shared-libs.patch #region RHEL patches # RHEL 8 only Patch501: 0001-Fix-page-size-constant-on-aarch64-and-ppc64le.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 #endregion RHEL patches # Fix a pgo miscompilation triggered by building Rust 1.87 with pgo on ppc64le. @@ -438,6 +546,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 @@ -483,6 +598,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 @@ -571,7 +690,7 @@ BuildRequires: procps-ng # For reproducible pyc file generation # See https://docs.fedoraproject.org/en-US/packaging-guidelines/Python_Appendix/#_byte_compilation_reproducibility # Since Fedora 41 this happens automatically, and RHEL 8 does not support this. -%if %{without compat_build} && ((%{defined fedora} && 0%{?fedora} < 41) || 0%{?rhel} == 9 || 0%{?rhel} == 10) +%if %{without compat_build} && (0%{?rhel} == 9 || 0%{?rhel} == 10) BuildRequires: /usr/bin/marshalparser %global py_reproducible_pyc_path %{buildroot}%{python3_sitelib} %endif @@ -749,7 +868,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} @@ -1146,6 +1269,42 @@ Polly header files. %endif #endregion polly packages +#region flang packages +%if %{with flang} +%package -n %{pkg_name_flang} +Summary: a Fortran language front-end designed for integration with LLVM +Requires: %{pkg_name_flang}-runtime%{?_isa} = %{version}-%{release} +# flang installs headers in the clang resource directory +Requires: %{pkg_name_clang}-resource-filesystem%{?_isa} = %{version}-%{release} +# flang implicitly calls ld.bfd when linking and depends on the gcc runtime objects. +Requires: binutils +Requires: gcc +# Up to version 17.0.6-1, flang used to provide a flang-devel package. +# This changed in 17.0.6-2 and all development-related files are now +# distributed in the main flang package. +Obsoletes: %{pkg_name_flang}-devel < 17.0.6-2 + +# We no longer ship flang-doc. +Obsoletes: %{pkg_name_flang}-doc < 22 + +License: Apache-2.0 WITH LLVM-exception +URL: https://flang.llvm.org + +%description -n %{pkg_name_flang} + +Flang is a ground-up implementation of a Fortran front end written in modern +C++. + +%package -n %{pkg_name_flang}-runtime +Summary: Flang runtime libraries +Conflicts: %{pkg_name_flang} < 17.0.6-2 + +%description -n %{pkg_name_flang}-runtime +Flang runtime libraries. + +%endif +#endregion flang packages + #endregion packages #region prep @@ -1184,6 +1343,11 @@ Polly header files. %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 +%endif %endif #region LLVM preparation @@ -1253,7 +1417,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 @@ -1281,6 +1445,11 @@ cd llvm/utils/lit %global projects %{projects};polly %endif +%if %{with flang} +%global projects %{projects};flang +%global runtimes %{runtimes};flang-rt +%endif + %if %{with libcxx} %global runtimes %{runtimes};libcxx;libcxxabi;libunwind %endif @@ -1289,7 +1458,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 @@ -1373,6 +1545,11 @@ popd -DLLVM_ENABLE_EH=ON %endif +%if %reduce_debuginfo == 1 + %global cmake_common_args %{cmake_common_args} -DCMAKE_C_FLAGS_RELWITHDEBINFO="%{optflags} -DNDEBUG" + %global cmake_common_args %{cmake_common_args} -DCMAKE_CXX_FLAGS_RELWITHDEBINFO="%{optflags} -DNDEBUG" +%endif + %global cmake_config_args %{cmake_common_args} #region clang options @@ -1401,7 +1578,8 @@ popd #region compiler-rt options %global cmake_config_args %{cmake_config_args} \\\ -DCOMPILER_RT_INCLUDE_TESTS:BOOL=OFF \\\ - -DCOMPILER_RT_INSTALL_PATH=%{_prefix}/lib/clang/%{maj_ver} + -DCOMPILER_RT_INSTALL_PATH=%{_prefix}/lib/clang/%{maj_ver} \\\ + -DLLVM_BUILD_EXTERNAL_COMPILER_RT:BOOL=ON #endregion compiler-rt options #region docs options @@ -1469,7 +1647,6 @@ popd %global cmake_config_args %{cmake_config_args} \\\ -DLLVM_APPEND_VC_REV:BOOL=OFF \\\ -DLLVM_BUILD_EXAMPLES:BOOL=OFF \\\ - -DLLVM_BUILD_EXTERNAL_COMPILER_RT:BOOL=ON \\\ -DLLVM_BUILD_RUNTIME:BOOL=ON \\\ -DLLVM_BUILD_TOOLS:BOOL=ON \\\ -DLLVM_BUILD_UTILS:BOOL=ON \\\ @@ -1502,6 +1679,7 @@ popd -DMLIR_INSTALL_AGGREGATE_OBJECTS=OFF \\\ -DMLIR_BUILD_MLIR_C_DYLIB=ON \\\ -DMLIR_ENABLE_BINDINGS_PYTHON:BOOL=ON + %endif #endregion mlir options @@ -1538,6 +1716,23 @@ popd %endif #endregion polly options +#region flang options +%if %{with flang} +%global cmake_config_args %{cmake_config_args} \\\ + -DFLANG_INCLUDE_DOCS:BOOL=ON +# Build both, shared and static flang runtime objects. +# See also https://llvm.org/devmtg/2025-04/slides/quick_talk/kruse_flang-rt.pdf +%global cmake_config_args %{cmake_config_args} \\\ + -DFLANG_RT_ENABLE_SHARED:BOOL=ON \\\ + -DFLANG_RT_ENABLE_STATIC:BOOL=ON +# The amount of RAM used per process has been set by trial and error. +# This number may increase/decrease from time to time and may require changes. +# We prefer to be on the safe side in order to avoid spurious errors. +%global cmake_config_args %{cmake_config_args} \\\ + -DFLANG_PARALLEL_COMPILE_JOBS=%{lua: print_max_procs(3072)} +%endif +#endregion flang options + #region test options %global cmake_config_args %{cmake_config_args} \\\ @@ -1547,11 +1742,7 @@ popd -DLLVM_LIT_ARGS="-vv" %if %{with lto_build} -%if 0%{?fedora} >= 41 %global cmake_config_args %{cmake_config_args} -DLLVM_UNITTEST_LINK_FLAGS="-fno-lto" -%else - %global cmake_config_args %{cmake_config_args} -DLLVM_UNITTEST_LINK_FLAGS="-Wl,-plugin-opt=O0" -%endif %endif #endregion test options @@ -1579,11 +1770,6 @@ popd %global cmake_config_args %{cmake_config_args} -DPPC_LINUX_DEFAULT_IEEELONGDOUBLE=ON %endif -%if %reduce_debuginfo == 1 - %global cmake_config_args %{cmake_config_args} -DCMAKE_C_FLAGS_RELWITHDEBINFO="%{optflags} -DNDEBUG" - %global cmake_config_args %{cmake_config_args} -DCMAKE_CXX_FLAGS_RELWITHDEBINFO="%{optflags} -DNDEBUG" -%endif - %if 0%{?__isa_bits} == 64 %global cmake_config_args %{cmake_config_args} -DLLVM_LIBDIR_SUFFIX=64 %endif @@ -1609,7 +1795,11 @@ popd # This option uses the NUMBER_OF_LOGICAL_CORES query in CMake which doesn't # work on s390x. # https://gitlab.kitware.com/cmake/cmake/-/issues/26619 - %global cmake_config_args %{cmake_config_args} -DLLVM_RAM_PER_COMPILE_JOB=2048 + # The value 4096 was used after we've seen cases of memory exhaustion on a + # system with 64GiB RAM and 16 jobs. It worked a few times after applied, + # but we can't guarantee it's enough. It's important to remember that RHEL8 + # uses GCC. This value should not be applied to a build using clang. + %global cmake_config_args %{cmake_config_args} -DLLVM_RAM_PER_COMPILE_JOB=4096 %endif %endif #endregion misc options @@ -1731,11 +1921,15 @@ cd $OLD_CWD # LLVM_VP_COUNTERS_PER_SITE instead of adding it, hence the # -DLLVM_VP_COUNTERS_PER_SITE=8. %global extra_cmake_opts %{extra_cmake_opts} -DLLVM_VP_COUNTERS_PER_SITE=8 +%endif + %if 0%{with lto_build} %global extra_cmake_opts %{extra_cmake_opts} -DLLVM_ENABLE_LTO:BOOL=Thin %global extra_cmake_opts %{extra_cmake_opts} -DLLVM_ENABLE_FATLTO=ON %endif - %global extra_cmake_opts %{extra_cmake_opts} -DLLVM_USE_LINKER=lld + +%if 0%{with use_lld} +%global extra_cmake_opts %{extra_cmake_opts} -DLLVM_USE_LINKER=lld %endif %cmake -G Ninja %{cmake_config_args} %{extra_cmake_opts} $extra_cmake_args @@ -1887,6 +2081,14 @@ popd %cmake_install +%if %{with flang} +# Create ld.so.conf.d entry +mkdir -p %{buildroot}%{_sysconfdir}/ld.so.conf.d +cat >> %{buildroot}%{_sysconfdir}/ld.so.conf.d/%{pkg_name_flang}-%{_arch}.conf << EOF +%{_prefix}/lib/clang/%{maj_ver}/lib/%{llvm_triple}/ +EOF +%endif + popd mkdir -p %{buildroot}/%{_bindir} @@ -2066,7 +2268,8 @@ echo " %{cfg_file_content}" >> %{buildroot}%{_sysconfdir}/%{pkg_name_clang}/i386 %ifarch ppc64le # Fix install path on ppc64le so that the directory name matches the triple used # by clang. -mv %{buildroot}%{_prefix}/lib/clang/%{maj_ver}/lib/powerpc64le-redhat-linux-gnu %{buildroot}%{_prefix}/lib/clang/%{maj_ver}/lib/%{llvm_triple} +mkdir -pv %{buildroot}%{_prefix}/lib/clang/%{maj_ver}/lib/%{llvm_triple} +mv %{buildroot}%{_prefix}/lib/clang/%{maj_ver}/lib/powerpc64le-redhat-linux-gnu/* %{buildroot}%{_prefix}/lib/clang/%{maj_ver}/lib/%{llvm_triple} %endif %ifarch %{ix86} @@ -2141,6 +2344,62 @@ rm -rf %{buildroot}%{install_prefix}/src/python %endif #endregion mlir installation +#region flang installation +%if %{with flang} +# Remove unnecessary files. +rm -rfv %{buildroot}%{install_libdir}/cmake/flang + +# Remove runtime development headers (see https://github.com/llvm/llvm-project/pull/165610) +rm -rfv %{buildroot}%{install_includedir}/flang-rt + +rm -v %{buildroot}%{install_libdir}/libFIRAnalysis.a \ + %{buildroot}%{install_libdir}/libFIRBuilder.a \ + %{buildroot}%{install_libdir}/libFIRCodeGen.a \ + %{buildroot}%{install_libdir}/libFIRCodeGenDialect.a \ + %{buildroot}%{install_libdir}/libFIRDialect.a \ + %{buildroot}%{install_libdir}/libFIRDialectSupport.a \ + %{buildroot}%{install_libdir}/libFIROpenACCSupport.a \ + %{buildroot}%{install_libdir}/libFIROpenMPSupport.a \ + %{buildroot}%{install_libdir}/libFIRSupport.a \ + %{buildroot}%{install_libdir}/libFIRTestAnalysis.a \ + %{buildroot}%{install_libdir}/libFIRTestOpenACCInterfaces.a \ + %{buildroot}%{install_libdir}/libFIRTransforms.a \ + %{buildroot}%{install_libdir}/libflangFrontend.a \ + %{buildroot}%{install_libdir}/libflangFrontendTool.a \ + %{buildroot}%{install_libdir}/libflangPasses.a \ + %{buildroot}%{install_libdir}/libFlangOpenMPTransforms.a \ + %{buildroot}%{install_libdir}/libFortranEvaluate.a \ + %{buildroot}%{install_libdir}/libFortranLower.a \ + %{buildroot}%{install_libdir}/libFortranParser.a \ + %{buildroot}%{install_libdir}/libFortranSemantics.a \ + %{buildroot}%{install_libdir}/libFortranSupport.a \ + %{buildroot}%{install_libdir}/libHLFIRDialect.a \ + %{buildroot}%{install_libdir}/libHLFIRTransforms.a \ + %{buildroot}%{install_libdir}/libCUFAttrs.a \ + %{buildroot}%{install_libdir}/libCUFDialect.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 + +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 + #region libcxx installation %if %{with libcxx} # We can't install the unversionned path on default location because that would conflict with @@ -2195,14 +2454,14 @@ move_and_replace_with_symlinks %{buildroot}%{install_datadir} %{buildroot}%{_dat mkdir -p %{buildroot}%{_bindir} for f in %{buildroot}%{install_bindir}/*; do filename=`basename $f` - if [[ "$filename" =~ ^(lit|ld|clang-%{maj_ver})$ ]]; then + if [[ "$filename" =~ ^(lit|ld|clang-%{maj_ver}|flang-%{maj_ver})$ ]]; then continue fi %if %{with compat_build} ln -s ../../%{install_bindir}/$filename %{buildroot}/%{_bindir}/$filename-%{maj_ver} %else - # clang-NN is already created by the build system. - if [[ "$filename" == "clang" ]]; then + # clang-NN and flang-NN are already created by the build system. + if [[ "$filename" =~ ^(clang|flang)$ ]]; then continue fi ln -s $filename %{buildroot}/%{_bindir}/$filename-%{maj_ver} @@ -2249,6 +2508,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 @@ -2357,6 +2627,7 @@ export LIT_XFAIL="tools/UpdateTestChecks" #region Test CLANG reset_test_opts export LIT_XFAIL="$LIT_XFAIL;clang/test/CodeGen/profile-filter.c" + %cmake_build --target check-clang #endregion Test Clang @@ -2539,10 +2810,26 @@ adjust_lit_filter_out test_list_filter_out # to pass. And then we can adapt this number. export LIT_OPTS="$LIT_OPTS --max-retries-per-test=4" +%if %{with flang} +# Without this we run into a libflang_rt.runtime.so not found error. +# See https://github.com/llvm/llvm-project/pull/150722 for why this only +# happens when flang is found. +export LD_LIBRARY_PATH=%{buildroot}%{_prefix}/lib/clang/%{maj_ver}/lib/%{llvm_triple} +%endif + %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 @@ -2603,6 +2890,12 @@ test_list_filter_out+=("MLIR :: python/execution_engine.py") test_list_filter_out+=("MLIR :: python/multithreaded_tests.py") %endif +%if %{with flang} +# TODO(kkleine): This test needs to be re-enabled. I currently only fails when building with flang. +# Here's the test failure: https://gist.github.com/kwk/5d551e27a28dfc1b34a09dca781f91df +test_list_filter_out+=("MLIR :: mlir-pdll-lsp-server/view-output.test") +%endif + adjust_lit_filter_out test_list_filter_out export PYTHONPATH=%{buildroot}/%{python3_sitearch} @@ -2638,6 +2931,8 @@ if ! grep -q atomics /proc/cpuinfo; then fi %endif +adjust_lit_filter_out test_list_filter_out + %cmake_build --target check-bolt %endif #endregion BOLT tests @@ -2649,6 +2944,25 @@ reset_test_opts %endif #endregion polly tests +#region flang tests +%if %{with flang} +reset_test_opts + +# https://github.com/llvm/llvm-project/issues/126051 +test_list_filter_out+=("Flang :: Driver/linker-flags.f90") + +# We filter our the location.f90 test for now because with LTO+PGO enabled, +# We miss the location.f90 entry in the loc_kind_array[ base, inclusion] entry. +# https://github.com/llvm/llvm-project/issues/156629 +test_list_filter_out+=("Flang :: Lower/location.f90") + +adjust_lit_filter_out test_list_filter_out + +%cmake_build --target check-flang +%cmake_build --target check-flang-rt + +%endif +#endregion flang tests %endif @@ -3012,6 +3326,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 }} @@ -3371,6 +3690,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 @@ -3402,12 +3727,69 @@ 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 #endregion MLIR files #region libcxx files + +#region flang files +%if %{with flang} +%files -n %{pkg_name_flang} +%license flang/LICENSE.TXT +%{expand_mans flang} +%{expand_bins %{expand: + tco + bbc + fir-opt + fir-lsp-server + flang + flang-new +}} +%{install_bindir}/flang-%{maj_ver} +%{expand_includes %{expand: + flang/__cuda_builtins.mod + flang/__cuda_device.mod + flang/__fortran_builtins.mod + flang/__fortran_ieee_exceptions.mod + flang/__fortran_type_info.mod + flang/__ppc_intrinsics.mod + flang/__ppc_types.mod + flang/cooperative_groups.mod + flang/ieee_arithmetic.mod + flang/ieee_exceptions.mod + flang/ieee_features.mod + flang/iso_c_binding.mod + flang/iso_fortran_env.mod + flang/mma.mod + flang/cudadevice.mod + 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 + +%files -n %{pkg_name_flang}-runtime +%{_prefix}/lib/clang/%{maj_ver}/lib/%{llvm_triple}/libflang_rt.runtime.a +%{_prefix}/lib/clang/%{maj_ver}/lib/%{llvm_triple}/libflang_rt.runtime.so +%config(noreplace) %{_sysconfdir}/ld.so.conf.d/%{pkg_name_flang}-%{_arch}.conf + +%endif +#region flang files + %if %{with libcxx} %files -n %{pkg_name_libcxx} diff --git a/sources b/sources index 1641647..cf40641 100644 --- a/sources +++ b/sources @@ -1,4 +1,4 @@ -SHA512 (llvm-project-21.1.3.src.tar.xz) = d3058e7c18ada2a6a6192c7e75970406520e0d2ba390dba3b89e99f05959198fd2976d38c200f8e6af37fb569d866b6367bf6e0e249fe4b340dfab74499e5723 -SHA512 (llvm-project-21.1.3.src.tar.xz.sig) = d218a4071451e32a77890dd2e7de7a3b8a310ca85c7e6d90b88d85bad128979cf6866c9d772b880b50da2ec117832e77ba162049478c1deb7b0299cae008151a +SHA512 (llvm-project-21.1.7.src.tar.xz) = ae30a53ed929df979849f7433bf705bc3d540aa9e12a02a175eb2483d1a56f9ca1203c9b67795f6e84cf2407c28d46d5d5351b290d8735adb5206103fee6f379 +SHA512 (llvm-project-21.1.7.src.tar.xz.sig) = d02b09c77abd537eb24d6d43470f962c80a9ec6ccc03ac0efc950d90dbdec5b94dd6abad18143890ff85cee2bdeb7bcf1dac2a576ffcab8ef053d8526417bdcc SHA512 (llvm-project-20.1.8.src.tar.xz) = f330e72e6a1da468569049437cc0ba7a41abb816ccece7367189344f7ebfef730f4788ac7af2bef0aa8a49341c15ab1d31e941ffa782f264d11fe0dc05470773 SHA512 (llvm-project-20.1.8.src.tar.xz.sig) = d74369bdb4d1b82775161ea53c9c5f3a23ce810f4df5ff617123023f9d8ce720e7d6ecc9e17f8ebd39fd9e7a9de79560abdf2ffe73bcb907a43148d43665d619