[llvm-commits] [llvm] r86941 - in /llvm/trunk: lib/ExecutionEngine/JIT/JITEmitter.cpp unittests/ExecutionEngine/JIT/JITTest.cpp
Eric Christopher
echristo at apple.com
Thu Nov 12 09:11:58 PST 2009
Yeah I sent mail to test results last night. I can't duplicate it on
my machine in either 32 or 64bit. I asked Jeffrey for a bit of help
tracking it down. If you've got a machine in the office that can
duplicate it that'd be awesome :)
-eric
On Nov 12, 2009, at 7:42 AM, Daniel Dunbar <daniel at zuster.org> wrote:
> Hi Eric,
>
> This test:
> LLVM-Unit::ExecutionEngine/JIT/Debug/JITTests/
> JITTest.FarCallToKnownFunction
> appears to be failing with this change, on linux and x86_64. Can you
> take a look?
>
> - Daniel
>
> On Wed, Nov 11, 2009 at 7:12 PM, Eric Christopher
> <echristo at apple.com> wrote:
>> Author: echristo
>> Date: Wed Nov 11 21:12:18 2009
>> New Revision: 86941
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=86941&view=rev
>> Log:
>> Use stubs when we have them, otherwise use code we already have,
>> otherwise create a stub.
>>
>> Add a test to make sure we don't create extraneous stubs.
>>
>> Modified:
>> llvm/trunk/lib/ExecutionEngine/JIT/JITEmitter.cpp
>> llvm/trunk/unittests/ExecutionEngine/JIT/JITTest.cpp
>>
>> Modified: llvm/trunk/lib/ExecutionEngine/JIT/JITEmitter.cpp
>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/JIT/JITEmitter.cpp?rev=86941&r1=86940&r2=86941&view=diff
>>
>> ===
>> ===
>> ===
>> =====================================================================
>> --- llvm/trunk/lib/ExecutionEngine/JIT/JITEmitter.cpp (original)
>> +++ llvm/trunk/lib/ExecutionEngine/JIT/JITEmitter.cpp Wed Nov 11
>> 21:12:18 2009
>> @@ -225,7 +225,7 @@
>> assert(TheJITResolver == 0 && "Multiple JIT resolvers?");
>> TheJITResolver = this;
>> }
>> -
>> +
>> ~JITResolver() {
>> TheJITResolver = 0;
>> }
>> @@ -256,10 +256,10 @@
>> state.AddCallSite(locked, Location, F);
>> return (void*)(intptr_t)LazyResolverFn;
>> }
>> -
>> +
>> void getRelocatableGVs(SmallVectorImpl<GlobalValue*> &GVs,
>> SmallVectorImpl<void*> &Ptrs);
>> -
>> +
>> GlobalValue *invalidateStub(void *Stub);
>>
>> /// getGOTIndexForAddress - Return a new or existing index in
>> the GOT for
>> @@ -291,7 +291,7 @@
>> /// Relocations - These are the relocations that the function
>> needs, as
>> /// emitted.
>> std::vector<MachineRelocation> Relocations;
>> -
>> +
>> /// MBBLocations - This vector is a mapping from MBB ID's to
>> their address.
>> /// It is filled in by the StartMachineBasicBlock callback and
>> queried by
>> /// the getMachineBasicBlockAddress callback.
>> @@ -312,7 +312,7 @@
>> /// JumpTable - The jump tables for the current function.
>> ///
>> MachineJumpTableInfo *JumpTable;
>> -
>> +
>> /// JumpTableBase - A pointer to the first entry in the jump
>> table.
>> ///
>> void *JumpTableBase;
>> @@ -326,7 +326,7 @@
>> /// DR - The debug registerer for the jit.
>> OwningPtr<JITDebugRegisterer> DR;
>>
>> - /// LabelLocations - This vector is a mapping from Label ID's
>> to their
>> + /// LabelLocations - This vector is a mapping from Label ID's
>> to their
>> /// address.
>> std::vector<uintptr_t> LabelLocations;
>>
>> @@ -336,7 +336,7 @@
>> // GVSet - a set to keep track of which globals have been seen
>> SmallPtrSet<const GlobalVariable*, 8> GVSet;
>>
>> - // CurFn - The llvm function being emitted. Only valid during
>> + // CurFn - The llvm function being emitted. Only valid during
>> // finishFunction().
>> const Function *CurFn;
>>
>> @@ -368,7 +368,7 @@
>> // reference the stub. When the count of a stub's references
>> drops to zero,
>> // the stub is unused.
>> DenseMap<void *, SmallPtrSet<const Function*, 1> > StubFnRefs;
>> -
>> +
>> DebugLocTuple PrevDLT;
>>
>> public:
>> @@ -388,7 +388,7 @@
>> DR.reset(new JITDebugRegisterer(TM));
>> }
>> }
>> - ~JITEmitter() {
>> + ~JITEmitter() {
>> delete MemMgr;
>> }
>>
>> @@ -397,16 +397,16 @@
>> ///
>> static inline bool classof(const JITEmitter*) { return true; }
>> static inline bool classof(const MachineCodeEmitter*) { return
>> true; }
>> -
>> +
>> JITResolver &getJITResolver() { return Resolver; }
>>
>> virtual void startFunction(MachineFunction &F);
>> virtual bool finishFunction(MachineFunction &F);
>> -
>> +
>> void emitConstantPool(MachineConstantPool *MCP);
>> void initJumpTableInfo(MachineJumpTableInfo *MJTI);
>> void emitJumpTableInfo(MachineJumpTableInfo *MJTI);
>> -
>> +
>> virtual void startGVStub(const GlobalValue* GV, unsigned
>> StubSize,
>> unsigned Alignment = 1);
>> virtual void startGVStub(const GlobalValue* GV, void *Buffer,
>> @@ -425,7 +425,7 @@
>> virtual void addRelocation(const MachineRelocation &MR) {
>> Relocations.push_back(MR);
>> }
>> -
>> +
>> virtual void StartMachineBasicBlock(MachineBasicBlock *MBB) {
>> if (MBBLocations.size() <= (unsigned)MBB->getNumber())
>> MBBLocations.resize((MBB->getNumber()+1)*2);
>> @@ -438,7 +438,7 @@
>> virtual uintptr_t getJumpTableEntryAddress(unsigned Entry) const;
>>
>> virtual uintptr_t getMachineBasicBlockAddress(MachineBasicBlock
>> *MBB) const {
>> - assert(MBBLocations.size() > (unsigned)MBB->getNumber() &&
>> + assert(MBBLocations.size() > (unsigned)MBB->getNumber() &&
>> MBBLocations[MBB->getNumber()] && "MBB not emitted!");
>> return MBBLocations[MBB->getNumber()];
>> }
>> @@ -456,7 +456,7 @@
>> /// using the stub at the specified address. Allows
>> /// deallocateMemForFunction to also remove stubs no longer
>> referenced.
>> void AddStubToCurrentFunction(void *Stub);
>> -
>> +
>> virtual void processDebugLoc(DebugLoc DL, bool
>> BeforePrintingInsn);
>>
>> virtual void emitLabel(uint64_t LabelID) {
>> @@ -466,11 +466,11 @@
>> }
>>
>> virtual uintptr_t getLabelAddress(uint64_t LabelID) const {
>> - assert(LabelLocations.size() > (unsigned)LabelID &&
>> + assert(LabelLocations.size() > (unsigned)LabelID &&
>> LabelLocations[LabelID] && "Label not emitted!");
>> return LabelLocations[LabelID];
>> }
>> -
>> +
>> virtual void setModuleInfo(MachineModuleInfo* Info) {
>> MMI = Info;
>> if (DE.get()) DE->setModuleInfo(Info);
>> @@ -479,7 +479,7 @@
>> void setMemoryExecutable() {
>> MemMgr->setMemoryExecutable();
>> }
>> -
>> +
>> JITMemoryManager *getMemMgr() const { return MemMgr; }
>>
>> private:
>> @@ -573,7 +573,7 @@
>> IndirectSym = TheJIT->getJITInfo().emitGlobalValueIndirectSym(GV,
>> GVAddress,
>> JE);
>>
>> - DEBUG(errs() << "JIT: Indirect symbol emitted at [" << IndirectSym
>> + DEBUG(errs() << "JIT: Indirect symbol emitted at [" << IndirectSym
>> << "] for GV '" << GV->getName() << "'\n");
>>
>> return IndirectSym;
>> @@ -607,10 +607,10 @@
>> void JITResolver::getRelocatableGVs(SmallVectorImpl<GlobalValue*>
>> &GVs,
>> SmallVectorImpl<void*> &Ptrs) {
>> MutexGuard locked(TheJIT->lock);
>> -
>> +
>> const FunctionToStubMapTy &FM = state.getFunctionToStubMap(locked);
>> GlobalToIndirectSymMapTy &GM = state.getGlobalToIndirectSymMap
>> (locked);
>> -
>> +
>> for (FunctionToStubMapTy::const_iterator i = FM.begin(), e =
>> FM.end();
>> i != e; ++i){
>> Function *F = i->first;
>> @@ -646,7 +646,7 @@
>> GM.erase(i);
>> return GV;
>> }
>> -
>> +
>> // Lastly, check to see if it's in the ExternalFnToStubMap.
>> for (std::map<void *, void *>::iterator i =
>> ExternalFnToStubMap.begin(),
>> e = ExternalFnToStubMap.end(); i != e; ++i) {
>> @@ -655,7 +655,7 @@
>> ExternalFnToStubMap.erase(i);
>> break;
>> }
>> -
>> +
>> return 0;
>> }
>>
>> @@ -664,7 +664,7 @@
>> /// it if necessary, then returns the resultant function pointer.
>> void *JITResolver::JITCompilerFn(void *Stub) {
>> JITResolver &JR = *TheJITResolver;
>> -
>> +
>> Function* F = 0;
>> void* ActualPtr = 0;
>>
>> @@ -684,16 +684,16 @@
>>
>> // If we have already code generated the function, just return
>> the address.
>> void *Result = TheJIT->getPointerToGlobalIfAvailable(F);
>> -
>> +
>> if (!Result) {
>> // Otherwise we don't have it, do lazy compilation now.
>> -
>> +
>> // If lazy compilation is disabled, emit a useful error message
>> and abort.
>> if (!TheJIT->isCompilingLazily()) {
>> llvm_report_error("LLVM JIT requested to do lazy compilation
>> of function '"
>> + F->getName() + "' when lazy compiles are
>> disabled!");
>> }
>> -
>> +
>> DEBUG(errs() << "JIT: Lazily resolving function '" << F->getName
>> ()
>> << "' In stub ptr = " << Stub << " actual ptr = "
>> << ActualPtr << "\n");
>> @@ -736,15 +736,18 @@
>>
>> // If we have already compiled the function, return a pointer to
>> its body.
>> Function *F = cast<Function>(V);
>> - void *ResultPtr;
>> - if (MayNeedFarStub) {
>> - // Return the function stub if it's already created.
>> - ResultPtr = Resolver.getFunctionStubIfAvailable(F);
>> - if (ResultPtr)
>> - AddStubToCurrentFunction(ResultPtr);
>> - } else {
>> - ResultPtr = TheJIT->getPointerToGlobalIfAvailable(F);
>> +
>> + void *FnStub = Resolver.getFunctionStubIfAvailable(F);
>> + if (FnStub) {
>> + // Return the function stub if it's already created. We do
>> this first
>> + // so that we're returning the same address for the function
>> as any
>> + // previous call.
>> + AddStubToCurrentFunction(FnStub);
>> + return FnStub;
>> }
>> +
>> + // Otherwise if we have code, go ahead and return that.
>> + void *ResultPtr = TheJIT->getPointerToGlobalIfAvailable(F);
>> if (ResultPtr) return ResultPtr;
>>
>> // If this is an external function pointer, we can force the JIT to
>> @@ -778,11 +781,11 @@
>> // resolved address.
>> void *GVAddress = getPointerToGlobal(V, Reference, false);
>> void *StubAddr = Resolver.getGlobalValueIndirectSym(V, GVAddress);
>> -
>> +
>> // Add the stub to the current function's list of referenced
>> stubs, so we can
>> // deallocate them if the current function is ever freed.
>> AddStubToCurrentFunction(StubAddr);
>> -
>> +
>> return StubAddr;
>> }
>>
>> @@ -807,7 +810,7 @@
>> NextLine.Loc = DL;
>> EmissionDetails.LineStarts.push_back(NextLine);
>> }
>> -
>> +
>> PrevDLT = CurDLT;
>> }
>> }
>> @@ -832,7 +835,7 @@
>> static unsigned GetJumpTableSizeInBytes(MachineJumpTableInfo
>> *MJTI) {
>> const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables
>> ();
>> if (JT.empty()) return 0;
>> -
>> +
>> unsigned NumEntries = 0;
>> for (unsigned i = 0, e = JT.size(); i != e; ++i)
>> NumEntries += JT[i].MBBs.size();
>> @@ -844,7 +847,7 @@
>>
>> static uintptr_t RoundUpToAlign(uintptr_t Size, unsigned
>> Alignment) {
>> if (Alignment == 0) Alignment = 1;
>> - // Since we do not know where the buffer will be allocated, be
>> pessimistic.
>> + // Since we do not know where the buffer will be allocated, be
>> pessimistic.
>> return Size + Alignment;
>> }
>>
>> @@ -854,7 +857,7 @@
>> unsigned JITEmitter::addSizeOfGlobal(const GlobalVariable *GV,
>> unsigned Size) {
>> const Type *ElTy = GV->getType()->getElementType();
>> size_t GVSize = (size_t)TheJIT->getTargetData()->getTypeAllocSize
>> (ElTy);
>> - size_t GVAlign =
>> + size_t GVAlign =
>> (size_t)TheJIT->getTargetData()->getPreferredAlignment(GV);
>> DEBUG(errs() << "JIT: Adding in size " << GVSize << " alignment "
>> << GVAlign);
>> DEBUG(GV->dump());
>> @@ -871,7 +874,7 @@
>> /// but are referenced from the constant; put them in GVSet and
>> add their
>> /// size into the running total Size.
>>
>> -unsigned JITEmitter::addSizeOfGlobalsInConstantVal(const Constant
>> *C,
>> +unsigned JITEmitter::addSizeOfGlobalsInConstantVal(const Constant
>> *C,
>> unsigned Size) {
>> // If its undefined, return the garbage.
>> if (isa<UndefValue>(C))
>> @@ -934,7 +937,7 @@
>> /// addSizeOfGLobalsInInitializer - handle any globals that we
>> haven't seen yet
>> /// but are referenced from the given initializer.
>>
>> -unsigned JITEmitter::addSizeOfGlobalsInInitializer(const Constant
>> *Init,
>> +unsigned JITEmitter::addSizeOfGlobalsInInitializer(const Constant
>> *Init,
>> unsigned Size) {
>> if (!isa<UndefValue>(Init) &&
>> !isa<ConstantVector>(Init) &&
>> @@ -955,7 +958,7 @@
>> unsigned Size = 0;
>> GVSet.clear();
>>
>> - for (MachineFunction::iterator MBB = MF.begin(), E = MF.end();
>> + for (MachineFunction::iterator MBB = MF.begin(), E = MF.end();
>> MBB != E; ++MBB) {
>> for (MachineBasicBlock::const_iterator I = MBB->begin(), E =
>> MBB->end();
>> I != E; ++I) {
>> @@ -987,7 +990,7 @@
>> DEBUG(errs() << "JIT: About to look through initializers\n");
>> // Look for more globals that are referenced only from
>> initializers.
>> // GVSet.end is computed each time because the set can grow as we
>> go.
>> - for (SmallPtrSet<const GlobalVariable *, 8>::iterator I =
>> GVSet.begin();
>> + for (SmallPtrSet<const GlobalVariable *, 8>::iterator I =
>> GVSet.begin();
>> I != GVSet.end(); I++) {
>> const GlobalVariable* GV = *I;
>> if (GV->hasInitializer())
>> @@ -1009,10 +1012,10 @@
>> const TargetInstrInfo* TII = F.getTarget().getInstrInfo();
>> MachineJumpTableInfo *MJTI = F.getJumpTableInfo();
>> MachineConstantPool *MCP = F.getConstantPool();
>> -
>> +
>> // Ensure the constant pool/jump table info is at least 4-byte
>> aligned.
>> ActualSize = RoundUpToAlign(ActualSize, 16);
>> -
>> +
>> // Add the alignment of the constant pool
>> ActualSize = RoundUpToAlign(ActualSize, MCP-
>> >getConstantPoolAlignment());
>>
>> @@ -1024,7 +1027,7 @@
>>
>> // Add the jump table size
>> ActualSize += GetJumpTableSizeInBytes(MJTI);
>> -
>> +
>> // Add the alignment for the function
>> ActualSize = RoundUpToAlign(ActualSize,
>> std::max(F.getFunction()-
>> >getAlignment(), 8U));
>> @@ -1097,7 +1100,7 @@
>> ResultPtr = TheJIT->getPointerToNamedFunction
>> (MR.getExternalSymbol(),
>> false);
>> DEBUG(errs() << "JIT: Map \'" << MR.getExternalSymbol()
>> << "\' to ["
>> - << ResultPtr << "]\n");
>> + << ResultPtr << "]\n");
>>
>> // If the target REALLY wants a stub for this function,
>> emit it now.
>> if (MR.mayNeedFarStub()) {
>> @@ -1255,7 +1258,7 @@
>>
>> if (MMI)
>> MMI->EndFunction();
>> -
>> +
>> return false;
>> }
>>
>> @@ -1293,20 +1296,20 @@
>> // If the function did not reference any stubs, return.
>> if (CurFnStubUses.find(F) == CurFnStubUses.end())
>> return;
>> -
>> +
>> // For each referenced stub, erase the reference to this
>> function, and then
>> // erase the list of referenced stubs.
>> SmallVectorImpl<void *> &StubList = CurFnStubUses[F];
>> for (unsigned i = 0, e = StubList.size(); i != e; ++i) {
>> void *Stub = StubList[i];
>> -
>> +
>> // If we already invalidated this stub for this function,
>> continue.
>> if (StubFnRefs.count(Stub) == 0)
>> continue;
>> -
>> +
>> SmallPtrSet<const Function *, 1> &FnRefs = StubFnRefs[Stub];
>> FnRefs.erase(F);
>> -
>> +
>> // If this function was the last reference to the stub,
>> invalidate the stub
>> // in the JITResolver. Were there a memory manager
>> deallocateStub routine,
>> // we could call that at this point too.
>> @@ -1389,7 +1392,7 @@
>>
>> const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables
>> ();
>> if (JT.empty()) return;
>> -
>> +
>> unsigned NumEntries = 0;
>> for (unsigned i = 0, e = JT.size(); i != e; ++i)
>> NumEntries += JT[i].MBBs.size();
>> @@ -1409,7 +1412,7 @@
>>
>> const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables
>> ();
>> if (JT.empty() || JumpTableBase == 0) return;
>> -
>> +
>> if (TargetMachine::getRelocationModel() == Reloc::PIC_) {
>> assert(MJTI->getEntrySize() == 4 && "Cross JIT'ing?");
>> // For each jump table, place the offset from the beginning of
>> the table
>> @@ -1428,8 +1431,8 @@
>> }
>> } else {
>> assert(MJTI->getEntrySize() == sizeof(void*) && "Cross
>> JIT'ing?");
>> -
>> - // For each jump table, map each target in the jump table to
>> the address of
>> +
>> + // For each jump table, map each target in the jump table to
>> the address of
>> // an emitted MachineBasicBlock.
>> intptr_t *SlotPtr = (intptr_t*)JumpTableBase;
>>
>> @@ -1448,7 +1451,7 @@
>> SavedBufferBegin = BufferBegin;
>> SavedBufferEnd = BufferEnd;
>> SavedCurBufferPtr = CurBufferPtr;
>> -
>> +
>> BufferBegin = CurBufferPtr = MemMgr->allocateStub(GV, StubSize,
>> Alignment);
>> BufferEnd = BufferBegin+StubSize+1;
>> }
>> @@ -1458,7 +1461,7 @@
>> SavedBufferBegin = BufferBegin;
>> SavedBufferEnd = BufferEnd;
>> SavedCurBufferPtr = CurBufferPtr;
>> -
>> +
>> BufferBegin = CurBufferPtr = (uint8_t *)Buffer;
>> BufferEnd = BufferBegin+StubSize+1;
>> }
>> @@ -1487,15 +1490,15 @@
>> uintptr_t JITEmitter::getJumpTableEntryAddress(unsigned Index)
>> const {
>> const std::vector<MachineJumpTableEntry> &JT = JumpTable-
>> >getJumpTables();
>> assert(Index < JT.size() && "Invalid jump table index!");
>> -
>> +
>> unsigned Offset = 0;
>> unsigned EntrySize = JumpTable->getEntrySize();
>> -
>> +
>> for (unsigned i = 0; i < Index; ++i)
>> Offset += JT[i].MBBs.size();
>> -
>> +
>> Offset *= EntrySize;
>> -
>> +
>> return (uintptr_t)((char *)JumpTableBase + Offset);
>> }
>>
>> @@ -1540,7 +1543,7 @@
>> // If we have already code generated the function, just return
>> the address.
>> if (void *Addr = getPointerToGlobalIfAvailable(F))
>> return Addr;
>> -
>> +
>> // Get a stub if the target supports it.
>> assert(isa<JITEmitter>(JCE) && "Unexpected MCE?");
>> JITEmitter *JE = cast<JITEmitter>(getCodeEmitter());
>>
>> Modified: llvm/trunk/unittests/ExecutionEngine/JIT/JITTest.cpp
>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ExecutionEngine/JIT/JITTest.cpp?rev=86941&r1=86940&r2=86941&view=diff
>>
>> ===
>> ===
>> ===
>> =====================================================================
>> --- llvm/trunk/unittests/ExecutionEngine/JIT/JITTest.cpp (original)
>> +++ llvm/trunk/unittests/ExecutionEngine/JIT/JITTest.cpp Wed Nov 11
>> 21:12:18 2009
>> @@ -61,6 +61,7 @@
>> public:
>> RecordingJITMemoryManager()
>> : Base(JITMemoryManager::CreateDefaultMemManager()) {
>> + stubsAllocated = 0;
>> }
>>
>> virtual void setMemoryWritable() { Base->setMemoryWritable(); }
>> @@ -88,8 +89,10 @@
>> StartFunctionBodyCall(Result, F, InitialActualSize,
>> ActualSize));
>> return Result;
>> }
>> + int stubsAllocated;
>> virtual uint8_t *allocateStub(const GlobalValue* F, unsigned
>> StubSize,
>> unsigned Alignment) {
>> + stubsAllocated++;
>> return Base->allocateStub(F, StubSize, Alignment);
>> }
>> struct EndFunctionBodyCall {
>> @@ -455,6 +458,44 @@
>> NumTablesDeallocated);
>> }
>>
>> +typedef int (*FooPtr) ();
>> +
>> +TEST_F(JITTest, NoStubs) {
>> + LoadAssembly("define void @bar() {"
>> + "entry: "
>> + "ret void"
>> + "}"
>> + " "
>> + "define i32 @foo() {"
>> + "entry:"
>> + "call void @bar()"
>> + "ret i32 undef"
>> + "}"
>> + " "
>> + "define i32 @main() {"
>> + "entry:"
>> + "%0 = call i32 @foo()"
>> + "call void @bar()"
>> + "ret i32 undef"
>> + "}");
>> + Function *foo = M->getFunction("foo");
>> + uintptr_t tmp = (uintptr_t)(TheJIT->getPointerToFunction(foo));
>> + FooPtr ptr = (FooPtr)(tmp);
>> +
>> + (ptr)();
>> +
>> + // We should now allocate no more stubs, we have the code to foo
>> + // and the existing stub for bar.
>> + int stubsBefore = RJMM->stubsAllocated;
>> + Function *func = M->getFunction("main");
>> + TheJIT->getPointerToFunction(func);
>> +
>> + Function *bar = M->getFunction("bar");
>> + TheJIT->getPointerToFunction(bar);
>> +
>> + ASSERT_EQ(stubsBefore, RJMM->stubsAllocated);
>> +}
>> +
>> // This code is copied from JITEventListenerTest, but it only runs
>> once for all
>> // the tests in this directory. Everything seems fine, but that's
>> strange
>> // behavior.
>>
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>>
More information about the llvm-commits
mailing list