[llvm-commits] [llvm-gcc-4.2] r100531 - in /llvm-gcc-4.2/trunk/gcc: llvm-backend.cpp llvm-convert.cpp llvm-debug.cpp llvm-debug.h llvm-internal.h
Devang Patel
dpatel at apple.com
Tue Apr 6 11:49:40 PDT 2010
Stuart,
On Apr 6, 2010, at 10:19 AM, Stuart Hastings wrote:
> Author: stuart
> Date: Tue Apr 6 12:19:47 2010
> New Revision: 100531
>
> URL: http://llvm.org/viewvc/llvm-project?rev=100531&view=rev
> Log:
> Revise debug info machinery to digest nested functions and classes.
>
> A certain GDB testsuite case (local.cc) has a function nested inside a
> class nested inside another function. GCC presents the innermost
> function to llvm-convert first. Heretofore, the debug info mistakenly
> placed the inner function at module scope. This patch walks the GCC
> context links and instantiates the outer class and function so the
> debug info is properly nested. Radar 7426545.
>
> Modified:
> llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp
> llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp
> llvm-gcc-4.2/trunk/gcc/llvm-debug.cpp
> llvm-gcc-4.2/trunk/gcc/llvm-debug.h
> llvm-gcc-4.2/trunk/gcc/llvm-internal.h
>
> Modified: llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp?rev=100531&r1=100530&r2=100531&view=diff
> ==============================================================================
> --- llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp (original)
> +++ llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp Tue Apr 6 12:19:47 2010
> @@ -512,6 +512,8 @@
> if (!flag_pch_file &&
> debug_info_level > DINFO_LEVEL_NONE)
> TheDebugInfo = new DebugInfo(TheModule);
> + else
> + TheDebugInfo = 0;
> }
>
> /// performLateBackendInitialization - Set backend options that may only be
> @@ -533,8 +535,6 @@
> }
>
> void llvm_lang_dependent_init(const char *Name) {
> - if (TheDebugInfo)
> - TheDebugInfo->Initialize();
What is the motivation behind this ?
> if (Name)
> TheModule->setModuleIdentifier(Name);
> }
> @@ -1010,7 +1010,7 @@
> // Convert the AST to raw/ugly LLVM code.
> Function *Fn;
> {
> - TreeToLLVM Emitter(fndecl);
> + TreeToLLVM *Emitter = getTreeToLLVM(fndecl);
> enum symbol_visibility vis = DECL_VISIBILITY (fndecl);
>
> if (vis != VISIBILITY_DEFAULT)
> @@ -1018,7 +1018,7 @@
> // visibility that's not supported by the target.
> targetm.asm_out.visibility(fndecl, vis);
>
> - Fn = Emitter.EmitFunction();
> + Fn = Emitter->EmitFunction();
> }
>
> #if 0
> @@ -1317,6 +1317,10 @@
>
> timevar_push(TV_LLVM_GLOBALS);
>
> + // Insure debug info machinery initialized, even if current module
> + // lacks functions.
> + getTreeToLLVM(decl);
> +
> // Get or create the global variable now.
> GlobalVariable *GV = cast<GlobalVariable>(DECL_LLVM(decl));
>
>
> Modified: llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp?rev=100531&r1=100530&r2=100531&view=diff
> ==============================================================================
> --- llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp (original)
> +++ llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp Tue Apr 6 12:19:47 2010
> @@ -148,7 +148,6 @@
> //===----------------------------------------------------------------------===//
>
> /// TheTreeToLLVM - Keep track of the current function being compiled.
> -static TreeToLLVM *TheTreeToLLVM = 0;
>
> const TargetData &getTargetData() {
> return *TheTarget->getTargetData();
> @@ -157,20 +156,22 @@
> /// EmitDebugInfo - Return true if debug info is to be emitted for current
> /// function.
> bool TreeToLLVM::EmitDebugInfo() {
> - if (TheDebugInfo && !DECL_IGNORED_P(getFUNCTION_DECL()))
> + if (TheDebugInfo &&
> + (!getFUNCTION_DECL() || !DECL_IGNORED_P(getFUNCTION_DECL())))
> return true;
> return false;
> }
>
> -TreeToLLVM::TreeToLLVM(tree fndecl) :
> - TD(getTargetData()), Builder(Context, *TheFolder) {
> - FnDecl = fndecl;
> +TreeToLLVM::TreeToLLVM(tree decl) :
> + TD(getTargetData()), Builder(Context, *TheFolder) {
> + // If this isn't a FUNCITON_DECL, use only the source loc info from it.
> + FnDecl = (decl && TREE_CODE(decl) == FUNCTION_DECL) ? decl : NULL_TREE;
> Fn = 0;
> ReturnBB = UnwindBB = 0;
> ReturnOffset = 0;
>
> if (EmitDebugInfo()) {
> - expanded_location Location = expand_location(DECL_SOURCE_LOCATION (fndecl));
> + expanded_location Location = expand_location(DECL_SOURCE_LOCATION (decl));
>
> if (Location.file) {
> TheDebugInfo->setLocationFile(Location.file);
> @@ -179,6 +180,7 @@
> TheDebugInfo->setLocationFile("<unknown file>");
> TheDebugInfo->setLocationLine(0);
> }
> + TheDebugInfo->Initialize();
> }
I do not think this is correct. DebugInfo::Initialize() should be called only once. Are you sure, you are not losing debug info with this change ?
>
> AllocaInsertionPoint = 0;
> @@ -188,13 +190,25 @@
> FuncEHException = 0;
> FuncEHSelector = 0;
> FuncEHGetTypeID = 0;
> -
> - assert(TheTreeToLLVM == 0 && "Reentering function creation?");
> - TheTreeToLLVM = this;
> }
>
> -TreeToLLVM::~TreeToLLVM() {
> - TheTreeToLLVM = 0;
> +
> +TreeToLLVM::~TreeToLLVM() {}
> +
> +TreeToLLVM *getTreeToLLVM(tree decl) {
> + // FIXME: should this static move into the TreeToLLVM class decl?
> + static std::map<tree_node *, TreeToLLVM * > FunctionMap;
Why not?
-
Devang
> + TreeToLLVM *newTreeToLLVM = FunctionMap[decl];
> + if (!newTreeToLLVM) {
> + tree fndecl = (decl && TREE_CODE(decl) == FUNCTION_DECL) ? decl : NULL_TREE;
> + newTreeToLLVM = FunctionMap[fndecl] = new TreeToLLVM(decl);
> + }
> + return newTreeToLLVM;
> +}
> +
> +TreeToLLVM *getCurrentTreeToLLVM(void) {
> + assert(current_function_decl && "no current_function_decl?");
> + return getTreeToLLVM(current_function_decl);
> }
>
> /// getLabelDeclBlock - Lazily get and create a basic block for the specified
> @@ -308,7 +322,8 @@
> assert(TREE_CODE(TREE_TYPE(ResultDecl)) == REFERENCE_TYPE &&
> "Not type match and not passing by reference?");
> // Create an alloca for the ResultDecl.
> - Value *Tmp = TheTreeToLLVM->CreateTemporary(AI->getType());
> + TreeToLLVM *Emitter = getCurrentTreeToLLVM();
> + Value *Tmp = Emitter->CreateTemporary(AI->getType());
> Builder.CreateStore(AI, Tmp);
>
> SET_DECL_LLVM(ResultDecl, Tmp);
> @@ -451,7 +466,7 @@
> }
> }
>
> -void TreeToLLVM::StartFunctionBody() {
> +Function *TreeToLLVM::StartFunctionBody() {
> const char *Name = "";
> // Get the name of the function.
> if (tree ID = DECL_ASSEMBLER_NAME(FnDecl))
> @@ -610,10 +625,10 @@
> // Set the BLOCK_NUMBER()s to the depth of each lexical block.
> setLexicalBlockDepths(FnDecl, block_declared_vars, 1);
>
> - SeenBlocks.clear();
> -
> - if (EmitDebugInfo())
> - TheDebugInfo->EmitFunctionStart(FnDecl, Fn, Builder.GetInsertBlock());
> + if (TheDebugInfo) {
> + TheDebugInfo->EmitFunctionStart(FnDecl);
> + Builder.GetInsertBlock();
> + }
>
> // Loop over all of the arguments to the function, setting Argument names and
> // creating argument alloca's for the PARM_DECLs in case their address is
> @@ -628,7 +643,7 @@
> ABIConverter.HandleReturnType(TREE_TYPE(TREE_TYPE(FnDecl)), FnDecl,
> DECL_BUILT_IN(FnDecl));
> // Remember this for use by FinishFunctionBody.
> - TheTreeToLLVM->ReturnOffset = Client.Offset;
> + ReturnOffset = Client.Offset;
>
> // Prepend the static chain (if any) to the list of arguments.
> tree Args = static_chain ? static_chain : DECL_ARGUMENTS(FnDecl);
> @@ -709,12 +724,7 @@
> block_declared_vars.count(TREE_VALUE(t)) == 0)
> EmitAutomaticVariableDecl(TREE_VALUE(t));
> }
> -
> - // Push the outermost lexical block onto the RegionStack.
> - switchLexicalBlock(DECL_INITIAL(FnDecl));
> -
> - // Create a new block for the return node, but don't insert it yet.
> - ReturnBB = BasicBlock::Create(Context, "return");
> + return Fn;
> }
>
> Function *TreeToLLVM::FinishFunctionBody() {
> @@ -802,9 +812,19 @@
> }
>
> Function *TreeToLLVM::EmitFunction() {
> - // Set up parameters and prepare for return, for the function.
> + // Set up parameters for the function.
> StartFunctionBody();
>
> + // We'll remember the lexical BLOCKs we've seen here.
> + SeenBlocks.clear();
> +
> + // FIXME: Should these two statements move to StartFunctionBody() ?
> + // Push the outermost lexical block onto the RegionStack.
> + switchLexicalBlock(DECL_INITIAL(FnDecl));
> +
> + // Create a new block for the return node, but don't insert it yet.
> + ReturnBB = BasicBlock::Create(Context, "return");
> +
> // Emit the body of the function iterating over all BBs
> basic_block bb;
> edge e;
> @@ -2616,7 +2636,7 @@
> if (!Loc) {
> // A value. Store to a temporary, and return the temporary's address.
> // Any future access to this argument will reuse the same address.
> - Loc = TheTreeToLLVM->CreateTemporary(TheValue->getType());
> + Loc = getCurrentTreeToLLVM()->CreateTemporary(TheValue->getType());
> Builder.CreateStore(TheValue, Loc);
> }
> return Loc;
> @@ -2656,7 +2676,7 @@
> assert(ConvertType(type) ==
> cast<PointerType>(RetBuf.Ptr->getType())->getElementType() &&
> "Inconsistent result types!");
> - TheTreeToLLVM->EmitAggregateCopy(*DestLoc, RetBuf, type);
> + getCurrentTreeToLLVM()->EmitAggregateCopy(*DestLoc, RetBuf, type);
> return 0;
> } else {
> // Read out the scalar return value now.
> @@ -2699,7 +2719,7 @@
>
> if (DestLoc == 0) {
> // The result is unused, but still needs to be stored somewhere.
> - Value *Buf = TheTreeToLLVM->CreateTemporary(PtrArgTy->getElementType());
> + Value *Buf = getCurrentTreeToLLVM()->CreateTemporary(PtrArgTy->getElementType());
> CallOperands.push_back(Buf);
> } else if (useReturnSlot) {
> // Letting the call write directly to the final destination is safe and
> @@ -2709,7 +2729,7 @@
> // Letting the call write directly to the final destination may not be
> // safe (eg: if DestLoc aliases a parameter) and is not required - pass
> // a buffer and copy it to DestLoc after the call.
> - RetBuf = TheTreeToLLVM->CreateTempLoc(PtrArgTy->getElementType());
> + RetBuf = getCurrentTreeToLLVM()->CreateTempLoc(PtrArgTy->getElementType());
> CallOperands.push_back(RetBuf.Ptr);
> }
>
> @@ -2730,7 +2750,7 @@
> "Call returns a scalar but caller expects aggregate!");
> // Create a buffer to hold the result. The result will be loaded out of
> // it after the call.
> - RetBuf = TheTreeToLLVM->CreateTempLoc(PtrArgTy->getElementType());
> + RetBuf = getCurrentTreeToLLVM()->CreateTempLoc(PtrArgTy->getElementType());
> CallOperands.push_back(RetBuf.Ptr);
>
> // Note the use of a shadow argument.
> @@ -2754,7 +2774,7 @@
> if (Loc->getType() != CalledTy) {
> assert(type && "Inconsistent parameter types?");
> bool isSigned = !TYPE_UNSIGNED(type);
> - Loc = TheTreeToLLVM->CastToAnyType(Loc, isSigned, CalledTy, false);
> + Loc = getCurrentTreeToLLVM()->CastToAnyType(Loc, isSigned, CalledTy, false);
> }
> }
>
> @@ -8457,18 +8477,18 @@
>
> /// EmitLV_LABEL_DECL - Someone took the address of a label.
> Constant *TreeConstantToLLVM::EmitLV_LABEL_DECL(tree exp) {
> - assert(TheTreeToLLVM &&
> + assert(getCurrentTreeToLLVM() &&
> "taking the address of a label while not compiling the function!");
>
> // Figure out which function this is for, verify it's the one we're compiling.
> if (DECL_CONTEXT(exp)) {
> assert(TREE_CODE(DECL_CONTEXT(exp)) == FUNCTION_DECL &&
> "Address of label in nested function?");
> - assert(TheTreeToLLVM->getFUNCTION_DECL() == DECL_CONTEXT(exp) &&
> + assert(getCurrentTreeToLLVM()->getFUNCTION_DECL() == DECL_CONTEXT(exp) &&
> "Taking the address of a label that isn't in the current fn!?");
> }
>
> - return TheTreeToLLVM->EmitLV_LABEL_DECL(exp);
> + return getCurrentTreeToLLVM()->EmitLV_LABEL_DECL(exp);
> }
>
> Constant *TreeConstantToLLVM::EmitLV_COMPLEX_CST(tree exp) {
>
> Modified: llvm-gcc-4.2/trunk/gcc/llvm-debug.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-debug.cpp?rev=100531&r1=100530&r2=100531&view=diff
> ==============================================================================
> --- llvm-gcc-4.2/trunk/gcc/llvm-debug.cpp (original)
> +++ llvm-gcc-4.2/trunk/gcc/llvm-debug.cpp Tue Apr 6 12:19:47 2010
> @@ -289,12 +289,10 @@
> setCurrentLexicalBlock(desired);
> }
>
> -/// EmitFunctionStart - Constructs the debug code for entering a function -
> -/// "llvm.dbg.func.start."
> -void DebugInfo::EmitFunctionStart(tree FnDecl, Function *Fn,
> - BasicBlock *CurBB) {
> - setCurrentLexicalBlock(FnDecl);
> +/// CreateSubprogramFromFnDecl - Constructs the debug code for
> +/// entering a function - "llvm.dbg.func.start."
>
> +DISubprogram DebugInfo::CreateSubprogramFromFnDecl(tree FnDecl) {
> DIType FNType = getOrCreateType(TREE_TYPE(FnDecl));
>
> std::map<tree_node *, WeakVH >::iterator I = SPCache.find(FnDecl);
> @@ -302,12 +300,9 @@
> DISubprogram SPDecl(cast<MDNode>(I->second));
> DISubprogram SP =
> DebugFactory.CreateSubprogramDefinition(SPDecl);
> - SPDecl.getNode()->replaceAllUsesWith(SP.getNode());
> -
> - // Push function on region stack.
> - RegionStack.push_back(WeakVH(SP.getNode()));
> - RegionMap[FnDecl] = WeakVH(SP.getNode());
> - return;
> + if (SP.getNode() != SPDecl.getNode())
> + SPDecl.getNode()->replaceAllUsesWith(SP.getNode());
> + return SP;
> }
>
> bool ArtificialFnWithAbstractOrigin = false;
> @@ -329,12 +324,13 @@
> DISubprogram SPDecl(cast<MDNode>(I->second));
> DISubprogram SP =
> DebugFactory.CreateSubprogramDefinition(SPDecl);
> - SPDecl.getNode()->replaceAllUsesWith(SP.getNode());
> + if (SP.getNode() != SPDecl.getNode())
> + SPDecl.getNode()->replaceAllUsesWith(SP.getNode());
>
> // Push function on region stack.
> RegionStack.push_back(WeakVH(SP.getNode()));
> RegionMap[FnDecl] = WeakVH(SP.getNode());
> - return;
> + return SP;
> }
>
> // Gather location information.
> @@ -356,23 +352,36 @@
> }
>
> StringRef FnName = getFunctionName(FnDecl);
> -
> + // If the Function * hasn't been created yet, use a bogus value for
> + // the debug internal linkage bit.
> + bool hasInternalLinkage = true;
> + if (GET_DECL_LLVM_INDEX(FnDecl)) {
> + Function *Fn = cast<Function>DECL_LLVM(FnDecl);
> + hasInternalLinkage = Fn->hasInternalLinkage();
> + }
> DISubprogram SP =
> DebugFactory.CreateSubprogram(SPContext,
> FnName, FnName,
> LinkageName,
> getOrCreateFile(Loc.file), lineno,
> FNType,
> - Fn->hasInternalLinkage(),
> + hasInternalLinkage,
> true /*definition*/,
> Virtuality, VIndex, ContainingType);
>
>
> SPCache[FnDecl] = WeakVH(SP.getNode());
> + RegionMap[FnDecl] = WeakVH(SP.getNode());
> + return SP;
> +}
>
> +/// EmitFunctionStart - Constructs the debug code for entering a function -
> +/// "llvm.dbg.func.start", and pushes it onto the RegionStack.
> +void DebugInfo::EmitFunctionStart(tree FnDecl) {
> + setCurrentLexicalBlock(FnDecl);
> + DISubprogram SP = CreateSubprogramFromFnDecl(FnDecl);
> // Push function on region stack.
> RegionStack.push_back(WeakVH(SP.getNode()));
> - RegionMap[FnDecl] = WeakVH(SP.getNode());
> }
>
> /// getOrCreateNameSpace - Get name space descriptor for the tree node.
> @@ -405,12 +414,20 @@
> DIType Ty = getOrCreateType(Node);
> return DIDescriptor(Ty.getNode());
> } else if (DECL_P (Node)) {
> - if (TREE_CODE (Node) == NAMESPACE_DECL) {
> + switch (TREE_CODE(Node)) {
> + default:
> + /// What kind of DECL is this?
> + return findRegion (DECL_CONTEXT (Node));
> + case NAMESPACE_DECL: {
> DIDescriptor NSContext = findRegion(DECL_CONTEXT(Node));
> DINameSpace NS = getOrCreateNameSpace(Node, NSContext);
> return DIDescriptor(NS.getNode());
> }
> - return findRegion (DECL_CONTEXT (Node));
> + case FUNCTION_DECL: {
> + DISubprogram SP = CreateSubprogramFromFnDecl(Node);
> + return SP;
> + }
> + }
> } else if (TREE_CODE(Node) == BLOCK) {
> // TREE_BLOCK is GCC's lexical block.
> // Recursively create all necessary contexts:
> @@ -623,7 +640,7 @@
> sprintf(FwdTypeName, "fwd.type.%d", FwdTypeCount++);
> llvm::DIType FwdType =
> DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_subroutine_type,
> - getOrCreateFile(main_input_filename),
> + findRegion(TYPE_CONTEXT(type)),
> FwdTypeName,
> getOrCreateFile(main_input_filename),
> 0, 0, 0, 0, 0,
> @@ -709,9 +726,10 @@
> return Ty;
> }
>
> + tree type_with_context = TYPE_CONTEXT(type) ? type : TREE_TYPE(type);
> StringRef PName = FromTy.getName();
> DIType PTy =
> - DebugFactory.CreateDerivedType(Tag, findRegion(TYPE_CONTEXT(type)),
> + DebugFactory.CreateDerivedType(Tag, findRegion(type_with_context),
> Tag == DW_TAG_pointer_type ?
> StringRef() : PName,
> getOrCreateFile(main_input_filename),
>
> Modified: llvm-gcc-4.2/trunk/gcc/llvm-debug.h
> URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-debug.h?rev=100531&r1=100530&r2=100531&view=diff
> ==============================================================================
> --- llvm-gcc-4.2/trunk/gcc/llvm-debug.h (original)
> +++ llvm-gcc-4.2/trunk/gcc/llvm-debug.h Tue Apr 6 12:19:47 2010
> @@ -118,9 +118,13 @@
> // by GCC's cfglayout.c:change_scope().
> void change_regions(tree_node *desired, tree_node *grand);
>
> - /// EmitFunctionStart - Constructs the debug code for entering a function -
> + /// CreateSubprogramFromFnDecl - Constructs the debug code for entering a function -
> /// "llvm.dbg.func.start."
> - void EmitFunctionStart(tree_node *FnDecl, Function *Fn, BasicBlock *CurBB);
> + DISubprogram CreateSubprogramFromFnDecl(tree_node *FnDecl);
> +
> + /// EmitFunctionStart - Constructs the debug code for entering a function -
> + /// "llvm.dbg.func.start", and pushes it onto the RegionStack.
> + void EmitFunctionStart(tree_node *FnDecl);
>
> /// EmitFunctionEnd - Constructs the debug code for exiting a declarative
> /// region - "llvm.dbg.region.end."
>
> Modified: llvm-gcc-4.2/trunk/gcc/llvm-internal.h
> URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-internal.h?rev=100531&r1=100530&r2=100531&view=diff
> ==============================================================================
> --- llvm-gcc-4.2/trunk/gcc/llvm-internal.h (original)
> +++ llvm-gcc-4.2/trunk/gcc/llvm-internal.h Tue Apr 6 12:19:47 2010
> @@ -75,7 +75,7 @@
> extern llvm::Module *TheModule;
>
> /// TheDebugInfo - This object is responsible for gather all debug information.
> -/// If it's value is NULL then no debug information should be gathered.
> +/// If its value is NULL then no debug information should be gathered.
> extern llvm::DebugInfo *TheDebugInfo;
>
> /// TheTarget - The current target being compiled for.
> @@ -281,6 +281,7 @@
> BasicBlock *ReturnBB;
> BasicBlock *UnwindBB;
> unsigned ReturnOffset;
> +
> // Lexical BLOCKS that we have previously seen and processed.
> treeset SeenBlocks;
>
> @@ -397,6 +398,10 @@
> // allocation would change with -g, and users dislike that.
> void switchLexicalBlock(tree_node *exp);
>
> + /// StartFunctionBody - Start the emission of 'FnDecl', outputing all
> + /// declarations for parameters and setting things up.
> + Function *StartFunctionBody();
> +
> private: // Helper functions.
>
> // Walk over the lexical BLOCK() tree of the given FUNCTION_DECL;
> @@ -405,10 +410,6 @@
> // the given set.
> void setLexicalBlockDepths(tree_node *t, treeset &s, unsigned level);
>
> - /// StartFunctionBody - Start the emission of 'fndecl', outputing all
> - /// declarations for parameters and setting things up.
> - void StartFunctionBody();
> -
> /// FinishFunctionBody - Once the body of the function has been emitted, this
> /// cleans up and returns the result function.
> Function *FinishFunctionBody();
> @@ -608,6 +609,9 @@
> Constant *EmitLV_LABEL_DECL(tree_node *exp);
> };
>
> +/// Locate a previously exiting TreeToLLVM. Construct one if necessary.
> +TreeToLLVM *getTreeToLLVM(tree_node *fndecl);
> +
> /// TreeConstantToLLVM - An instance of this class is created and used to
> /// convert tree constant values to LLVM. This is primarily for things like
> /// global variable initializers.
>
>
> _______________________________________________
> 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