llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-debuginfo Author: William G Hatch (willghatch) <details> <summary>Changes</summary> This patch adds support for encoding PTX registers for DWARF, using the encoding supported by nvcc and cuda-gcc. There are some other features still needed for proper register debugging that this patch does not address, such as DW_AT_address_class. --- Patch is 364.44 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/109495.diff 8 Files Affected: - (modified) llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp (+6) - (modified) llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp (+21) - (modified) llvm/lib/Target/NVPTX/NVPTXAsmPrinter.h (+1) - (modified) llvm/lib/Target/NVPTX/NVPTXRegisterInfo.cpp (+45) - (modified) llvm/lib/Target/NVPTX/NVPTXRegisterInfo.h (+16) - (modified) llvm/test/DebugInfo/NVPTX/cu-range-hole.ll (+25-11) - (modified) llvm/test/DebugInfo/NVPTX/debug-addr-class.ll (+40-13) - (modified) llvm/test/DebugInfo/NVPTX/debug-info.ll (+1127-1119) ``````````diff diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp index 08c762485b6527..f5d2863ae70b70 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -105,6 +105,12 @@ bool DwarfExpression::addMachineReg(const TargetRegisterInfo &TRI, DwarfRegs.push_back(Register::createRegister(-1, nullptr)); return true; } + // Try getting dwarf register for virtual register anyway, eg. for NVPTX. + int64_t Reg = TRI.getDwarfRegNum(MachineReg, false); + if (Reg > 0) { + DwarfRegs.push_back(Register::createRegister(Reg, nullptr)); + return true; + } return false; } diff --git a/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp b/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp index 38c51666139a89..6baaab3c635fba 100644 --- a/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp +++ b/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp @@ -490,6 +490,7 @@ void NVPTXAsmPrinter::emitFunctionEntryLabel() { // Emit open brace for function body. OutStreamer->emitRawText(StringRef("{\n")); setAndEmitFunctionVirtualRegisters(*MF); + encodeDebugInfoRegisterNumbers(*MF); // Emit initial .loc debug directive for correct relocation symbol data. if (const DISubprogram *SP = MF->getFunction().getSubprogram()) { assert(SP->getUnit()); @@ -1773,6 +1774,26 @@ void NVPTXAsmPrinter::setAndEmitFunctionVirtualRegisters( OutStreamer->emitRawText(O.str()); } +/// Translate virtual register numbers in DebugInfo locations to their printed +/// encodings, as used by CUDA-GDB. +void NVPTXAsmPrinter::encodeDebugInfoRegisterNumbers( + const MachineFunction &MF) { + const NVPTXSubtarget &STI = MF.getSubtarget<NVPTXSubtarget>(); + const NVPTXRegisterInfo *registerInfo = STI.getRegisterInfo(); + + // Clear the old mapping, and add the new one. This mapping is used after the + // printing of the current function is complete, but before the next function + // is printed. + registerInfo->clearDebugRegisterMap(); + + for (auto classMap : VRegMapping) { + for (auto registerMapping : classMap.getSecond()) { + auto reg = registerMapping.getFirst(); + registerInfo->addToDebugRegisterMap(reg, getVirtualRegisterName(reg)); + } + } +} + void NVPTXAsmPrinter::printFPConstant(const ConstantFP *Fp, raw_ostream &O) { APFloat APF = APFloat(Fp->getValueAPF()); // make a copy bool ignored; diff --git a/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.h b/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.h index d950047dc92c7e..f58b4bdc404748 100644 --- a/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.h +++ b/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.h @@ -181,6 +181,7 @@ class LLVM_LIBRARY_VISIBILITY NVPTXAsmPrinter : public AsmPrinter { void emitVirtualRegister(unsigned int vr, raw_ostream &); void emitFunctionParamList(const Function *, raw_ostream &O); void setAndEmitFunctionVirtualRegisters(const MachineFunction &MF); + void encodeDebugInfoRegisterNumbers(const MachineFunction &MF); void printReturnValStr(const Function *, raw_ostream &O); void printReturnValStr(const MachineFunction &MF, raw_ostream &O); bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, diff --git a/llvm/lib/Target/NVPTX/NVPTXRegisterInfo.cpp b/llvm/lib/Target/NVPTX/NVPTXRegisterInfo.cpp index a8a23f04c1249f..0521e52d71de3f 100644 --- a/llvm/lib/Target/NVPTX/NVPTXRegisterInfo.cpp +++ b/llvm/lib/Target/NVPTX/NVPTXRegisterInfo.cpp @@ -20,6 +20,7 @@ #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/MC/MachineLocation.h" +#include "MCTargetDesc/NVPTXInstPrinter.h" using namespace llvm; @@ -141,3 +142,47 @@ NVPTXRegisterInfo::getFrameLocalRegister(const MachineFunction &MF) const { static_cast<const NVPTXTargetMachine &>(MF.getTarget()); return TM.is64Bit() ? NVPTX::VRFrameLocal64 : NVPTX::VRFrameLocal32; } + +void NVPTXRegisterInfo::clearDebugRegisterMap() const { + debugRegisterMap.clear(); +} + +static uint64_t encodeRegisterForDwarf(std::string registerName) { + if (registerName.length() > 8) { + // The name is more than 8 characters long, and so won't fit into 64 bits. + return 0; + } + + // Encode the name string into a DWARF register number using cuda-gdb's + // encoding. See cuda_check_dwarf2_reg_ptx_virtual_register in cuda-tdep.c, + // https://github.com/NVIDIA/cuda-gdb/blob/e5cf3bddae520ffb326f95b4d98ce5c7474b828b/gdb/cuda/cuda-tdep.c#L353 + // IE the bytes of the string are concatenated in reverse into a single + // number, which is stored in ULEB128, but in practice must be no more than 8 + // bytes (excluding null terminator, which is not included). + uint64_t result = 0; + for (int i = 0; i < registerName.length(); ++i) { + result = result << 8; + char c = registerName[i]; + result += c; + } + return result; +} + +void NVPTXRegisterInfo::addToDebugRegisterMap( + uint64_t preEncodedVirtualRegister, std::string registerName) const { + uint64_t mapped = encodeRegisterForDwarf(registerName); + if (mapped == 0) + return; + debugRegisterMap.insert({preEncodedVirtualRegister, mapped}); +} + +int64_t NVPTXRegisterInfo::getDwarfRegNum(MCRegister RegNum, bool isEH) const { + if (Register::isPhysicalRegister(RegNum)) { + std::string name = NVPTXInstPrinter::getRegisterName(RegNum.id()); + return encodeRegisterForDwarf(name); + } + auto lookup = debugRegisterMap.lookup(RegNum.id()); + if (lookup) + return lookup; + return -1; +} diff --git a/llvm/lib/Target/NVPTX/NVPTXRegisterInfo.h b/llvm/lib/Target/NVPTX/NVPTXRegisterInfo.h index 7bce3bd18ae8fc..d2f6d257d6b07e 100644 --- a/llvm/lib/Target/NVPTX/NVPTXRegisterInfo.h +++ b/llvm/lib/Target/NVPTX/NVPTXRegisterInfo.h @@ -26,6 +26,10 @@ class NVPTXRegisterInfo : public NVPTXGenRegisterInfo { // Hold Strings that can be free'd all together with NVPTXRegisterInfo BumpPtrAllocator StrAlloc; UniqueStringSaver StrPool; + // State for debug register mapping that can be mutated even through a const + // pointer so that we can get the proper dwarf register encoding during ASM + // emission. + mutable DenseMap<uint64_t, uint64_t> debugRegisterMap; public: NVPTXRegisterInfo(); @@ -56,6 +60,18 @@ class NVPTXRegisterInfo : public NVPTXGenRegisterInfo { return getStrPool().save(O.str()).data(); } + // Manage the debugRegisterMap. PTX virtual registers for DebugInfo are + // encoded using the names used in the emitted text of the PTX assembly. This + // mapping must be managed during assembly emission. + // + // These are marked const because the interfaces used to access this + // RegisterInfo object are all const, but we need to communicate some state + // here, because the proper encoding for debug registers is available only + // temporarily during ASM emission. + void addToDebugRegisterMap(uint64_t preEncodedVirtualRegister, + std::string registerName) const; + void clearDebugRegisterMap() const; + int64_t getDwarfRegNum(MCRegister RegNum, bool isEH) const override; }; std::string getNVPTXRegClassName(const TargetRegisterClass *RC); diff --git a/llvm/test/DebugInfo/NVPTX/cu-range-hole.ll b/llvm/test/DebugInfo/NVPTX/cu-range-hole.ll index 4ae0b78f160c83..6acc1ba2512711 100644 --- a/llvm/test/DebugInfo/NVPTX/cu-range-hole.ll +++ b/llvm/test/DebugInfo/NVPTX/cu-range-hole.ll @@ -120,6 +120,8 @@ entry: ; CHECK-NEXT: .b8 3 // Abbreviation Code ; CHECK-NEXT: .b8 5 // DW_TAG_formal_parameter ; CHECK-NEXT: .b8 0 // DW_CHILDREN_no +; CHECK-NEXT: .b8 2 // DW_AT_location +; CHECK-NEXT: .b8 10 // DW_FORM_block1 ; CHECK-NEXT: .b8 3 // DW_AT_name ; CHECK-NEXT: .b8 8 // DW_FORM_string ; CHECK-NEXT: .b8 58 // DW_AT_decl_file @@ -145,12 +147,12 @@ entry: ; CHECK-NEXT: } ; CHECK-NEXT: .section .debug_info ; CHECK-NEXT: { -; CHECK-NEXT: .b32 183 // Length of Unit +; CHECK-NEXT: .b32 195 // Length of Unit ; CHECK-NEXT: .b8 2 // DWARF version number ; CHECK-NEXT: .b8 0 ; CHECK-NEXT: .b32 .debug_abbrev // Offset Into Abbrev. Section ; CHECK-NEXT: .b8 8 // Address Size (in bytes) -; CHECK-NEXT: .b8 1 // Abbrev [1] 0xb:0xb0 DW_TAG_compile_unit +; CHECK-NEXT: .b8 1 // Abbrev [1] 0xb:0xbc DW_TAG_compile_unit ; CHECK-NEXT: .b8 99 // DW_AT_producer ; CHECK-NEXT: .b8 108 ; CHECK-NEXT: .b8 97 @@ -223,7 +225,7 @@ entry: ; CHECK-NEXT: .b8 0 ; CHECK-NEXT: .b64 $L__func_begin0 // DW_AT_low_pc ; CHECK-NEXT: .b64 $L__func_end2 // DW_AT_high_pc -; CHECK-NEXT: .b8 2 // Abbrev [2] 0x65:0x27 DW_TAG_subprogram +; CHECK-NEXT: .b8 2 // Abbrev [2] 0x65:0x2d DW_TAG_subprogram ; CHECK-NEXT: .b64 $L__func_begin0 // DW_AT_low_pc ; CHECK-NEXT: .b64 $L__func_end0 // DW_AT_high_pc ; CHECK-NEXT: .b8 1 // DW_AT_frame_base @@ -233,16 +235,22 @@ entry: ; CHECK-NEXT: .b8 1 // DW_AT_decl_file ; CHECK-NEXT: .b8 1 // DW_AT_decl_line ; CHECK-NEXT: .b8 1 // DW_AT_prototyped -; CHECK-NEXT: .b32 179 // DW_AT_type +; CHECK-NEXT: .b32 191 // DW_AT_type ; CHECK-NEXT: .b8 1 // DW_AT_external -; CHECK-NEXT: .b8 3 // Abbrev [3] 0x82:0x9 DW_TAG_formal_parameter +; CHECK-NEXT: .b8 3 // Abbrev [3] 0x82:0xf DW_TAG_formal_parameter +; CHECK-NEXT: .b8 5 // DW_AT_location +; CHECK-NEXT: .b8 144 +; CHECK-NEXT: .b8 177 +; CHECK-NEXT: .b8 228 +; CHECK-NEXT: .b8 149 +; CHECK-NEXT: .b8 1 ; CHECK-NEXT: .b8 99 // DW_AT_name ; CHECK-NEXT: .b8 0 ; CHECK-NEXT: .b8 1 // DW_AT_decl_file ; CHECK-NEXT: .b8 1 // DW_AT_decl_line -; CHECK-NEXT: .b32 179 // DW_AT_type +; CHECK-NEXT: .b32 191 // DW_AT_type ; CHECK-NEXT: .b8 0 // End Of Children Mark -; CHECK-NEXT: .b8 2 // Abbrev [2] 0x8c:0x27 DW_TAG_subprogram +; CHECK-NEXT: .b8 2 // Abbrev [2] 0x92:0x2d DW_TAG_subprogram ; CHECK-NEXT: .b64 $L__func_begin2 // DW_AT_low_pc ; CHECK-NEXT: .b64 $L__func_end2 // DW_AT_high_pc ; CHECK-NEXT: .b8 1 // DW_AT_frame_base @@ -252,16 +260,22 @@ entry: ; CHECK-NEXT: .b8 1 // DW_AT_decl_file ; CHECK-NEXT: .b8 3 // DW_AT_decl_line ; CHECK-NEXT: .b8 1 // DW_AT_prototyped -; CHECK-NEXT: .b32 179 // DW_AT_type +; CHECK-NEXT: .b32 191 // DW_AT_type ; CHECK-NEXT: .b8 1 // DW_AT_external -; CHECK-NEXT: .b8 3 // Abbrev [3] 0xa9:0x9 DW_TAG_formal_parameter +; CHECK-NEXT: .b8 3 // Abbrev [3] 0xaf:0xf DW_TAG_formal_parameter +; CHECK-NEXT: .b8 5 // DW_AT_location +; CHECK-NEXT: .b8 144 +; CHECK-NEXT: .b8 177 +; CHECK-NEXT: .b8 228 +; CHECK-NEXT: .b8 149 +; CHECK-NEXT: .b8 1 ; CHECK-NEXT: .b8 101 // DW_AT_name ; CHECK-NEXT: .b8 0 ; CHECK-NEXT: .b8 1 // DW_AT_decl_file ; CHECK-NEXT: .b8 3 // DW_AT_decl_line -; CHECK-NEXT: .b32 179 // DW_AT_type +; CHECK-NEXT: .b32 191 // DW_AT_type ; CHECK-NEXT: .b8 0 // End Of Children Mark -; CHECK-NEXT: .b8 4 // Abbrev [4] 0xb3:0x7 DW_TAG_base_type +; CHECK-NEXT: .b8 4 // Abbrev [4] 0xbf:0x7 DW_TAG_base_type ; CHECK-NEXT: .b8 105 // DW_AT_name ; CHECK-NEXT: .b8 110 ; CHECK-NEXT: .b8 116 diff --git a/llvm/test/DebugInfo/NVPTX/debug-addr-class.ll b/llvm/test/DebugInfo/NVPTX/debug-addr-class.ll index c25742ef0d2764..03a120cd52fabc 100644 --- a/llvm/test/DebugInfo/NVPTX/debug-addr-class.ll +++ b/llvm/test/DebugInfo/NVPTX/debug-addr-class.ll @@ -160,6 +160,8 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata) ; CHECK-NEXT:.b8 5 // Abbreviation Code ; CHECK-NEXT:.b8 5 // DW_TAG_formal_parameter ; CHECK-NEXT:.b8 0 // DW_CHILDREN_no +; CHECK-NEXT:.b8 2 // DW_AT_location +; CHECK-NEXT:.b8 10 // DW_FORM_block1 ; CHECK-NEXT:.b8 3 // DW_AT_name ; CHECK-NEXT:.b8 8 // DW_FORM_string ; CHECK-NEXT:.b8 58 // DW_AT_decl_file @@ -171,6 +173,19 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata) ; CHECK-NEXT:.b8 0 // EOM(1) ; CHECK-NEXT:.b8 0 // EOM(2) ; CHECK-NEXT:.b8 6 // Abbreviation Code +; CHECK-NEXT:.b8 5 // DW_TAG_formal_parameter +; CHECK-NEXT:.b8 0 // DW_CHILDREN_no +; CHECK-NEXT:.b8 3 // DW_AT_name +; CHECK-NEXT:.b8 8 // DW_FORM_string +; CHECK-NEXT:.b8 58 // DW_AT_decl_file +; CHECK-NEXT:.b8 11 // DW_FORM_data1 +; CHECK-NEXT:.b8 59 // DW_AT_decl_line +; CHECK-NEXT:.b8 11 // DW_FORM_data1 +; CHECK-NEXT:.b8 73 // DW_AT_type +; CHECK-NEXT:.b8 19 // DW_FORM_ref4 +; CHECK-NEXT:.b8 0 // EOM(1) +; CHECK-NEXT:.b8 0 // EOM(2) +; CHECK-NEXT:.b8 7 // Abbreviation Code ; CHECK-NEXT:.b8 15 // DW_TAG_pointer_type ; CHECK-NEXT:.b8 0 // DW_CHILDREN_no ; CHECK-NEXT:.b8 73 // DW_AT_type @@ -181,12 +196,12 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata) ; CHECK-NEXT: } ; CHECK-NEXT: .section .debug_info ; CHECK-NEXT: { -; CHECK-NEXT:.b32 240 // Length of Unit +; CHECK-NEXT:.b32 252 // Length of Unit ; CHECK-NEXT:.b8 2 // DWARF version number ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b32 .debug_abbrev // Offset Into Abbrev. Section ; CHECK-NEXT:.b8 8 // Address Size (in bytes) -; CHECK-NEXT:.b8 1 // Abbrev [1] 0xb:0xe9 DW_TAG_compile_unit +; CHECK-NEXT:.b8 1 // Abbrev [1] 0xb:0xf5 DW_TAG_compile_unit ; CHECK-NEXT:.b8 99 // DW_AT_producer ; CHECK-NEXT:.b8 108 ; CHECK-NEXT:.b8 97 @@ -298,7 +313,7 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata) ; CHECK-NEXT:.b8 9 // DW_AT_location ; CHECK-NEXT:.b8 3 ; CHECK-NEXT:.b64 SHARED -; CHECK-NEXT:.b8 4 // Abbrev [4] 0xa0:0x45 DW_TAG_subprogram +; CHECK-NEXT:.b8 4 // Abbrev [4] 0xa0:0x51 DW_TAG_subprogram ; CHECK-NEXT:.b64 $L__func_begin0 // DW_AT_low_pc ; CHECK-NEXT:.b64 $L__func_end0 // DW_AT_high_pc ; CHECK-NEXT:.b8 1 // DW_AT_frame_base @@ -316,32 +331,44 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata) ; CHECK-NEXT:.b8 1 // DW_AT_decl_file ; CHECK-NEXT:.b8 6 // DW_AT_decl_line ; CHECK-NEXT:.b8 1 // DW_AT_external -; CHECK-NEXT:.b8 5 // Abbrev [5] 0xc0:0x9 DW_TAG_formal_parameter +; CHECK-NEXT:.b8 5 // Abbrev [5] 0xc0:0xf DW_TAG_formal_parameter +; CHECK-NEXT:.b8 5 // DW_AT_location +; CHECK-NEXT:.b8 144 +; CHECK-NEXT:.b8 177 +; CHECK-NEXT:.b8 204 +; CHECK-NEXT:.b8 149 +; CHECK-NEXT:.b8 1 ; CHECK-NEXT:.b8 97 // DW_AT_name ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 1 // DW_AT_decl_file ; CHECK-NEXT:.b8 6 // DW_AT_decl_line -; CHECK-NEXT:.b32 229 // DW_AT_type -; CHECK-NEXT:.b8 5 // Abbrev [5] 0xc9:0x9 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 241 // DW_AT_type +; CHECK-NEXT:.b8 6 // Abbrev [6] 0xcf:0x9 DW_TAG_formal_parameter ; CHECK-NEXT:.b8 120 // DW_AT_name ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 1 // DW_AT_decl_file ; CHECK-NEXT:.b8 6 // DW_AT_decl_line -; CHECK-NEXT:.b32 238 // DW_AT_type -; CHECK-NEXT:.b8 5 // Abbrev [5] 0xd2:0x9 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 250 // DW_AT_type +; CHECK-NEXT:.b8 6 // Abbrev [6] 0xd8:0x9 DW_TAG_formal_parameter ; CHECK-NEXT:.b8 121 // DW_AT_name ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 1 // DW_AT_decl_file ; CHECK-NEXT:.b8 6 // DW_AT_decl_line -; CHECK-NEXT:.b32 238 // DW_AT_type -; CHECK-NEXT:.b8 5 // Abbrev [5] 0xdb:0x9 DW_TAG_formal_parameter +; CHECK-NEXT:.b32 250 // DW_AT_type +; CHECK-NEXT:.b8 5 // Abbrev [5] 0xe1:0xf DW_TAG_formal_parameter +; CHECK-NEXT:.b8 5 // DW_AT_location +; CHECK-NEXT:.b8 144 +; CHECK-NEXT:.b8 177 +; CHECK-NEXT:.b8 228 +; CHECK-NEXT:.b8 149 +; CHECK-NEXT:.b8 1 ; CHECK-NEXT:.b8 105 // DW_AT_name ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 1 // DW_AT_decl_file ; CHECK-NEXT:.b8 6 // DW_AT_decl_line ; CHECK-NEXT:.b32 127 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark -; CHECK-NEXT:.b8 3 // Abbrev [3] 0xe5:0x9 DW_TAG_base_type +; CHECK-NEXT:.b8 3 // Abbrev [3] 0xf1:0x9 DW_TAG_base_type ; CHECK-NEXT:.b8 102 // DW_AT_name ; CHECK-NEXT:.b8 108 ; CHECK-NEXT:.b8 111 @@ -350,8 +377,8 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata) ; CHECK-NEXT:.b8 0 ; CHECK-NEXT:.b8 4 // DW_AT_encoding ; CHECK-NEXT:.b8 4 // DW_AT_byte_size -; CHECK-NEXT:.b8 6 // Abbrev [6] 0xee:0x5 DW_TAG_pointer_type -; CHECK-NEXT:.b32 229 // DW_AT_type +; CHECK-NEXT:.b8 7 // Abbrev [7] 0xfa:0x5 DW_TAG_pointer_type +; CHECK-NEXT:.b32 241 // DW_AT_type ; CHECK-NEXT:.b8 0 // End Of Children Mark ; CHECK-NEXT: } ; CHECK-NEXT: .section .debug_loc { } ... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/109495 _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits