llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-flang-openmp Author: David Pagan (ddpagan) <details> <summary>Changes</summary> Parse and perform semantic checks for declare_target 'local' clause. When compiling for device offloading, generate a warning that 'local' is not yet fully supported. On the host, 'local' is/will be a no-op, so no warning is generated. NOTE: The minimal CodeGen changes allow 'local' to flow through as equivalent to the 'enter' clause after warning is generated. Testing: - Updated messages and ast tests for declare target/declare_target - ninja check-all. --- Patch is 43.24 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/186281.diff 12 Files Affected: - (modified) clang/include/clang/Basic/Attr.td (+9-11) - (modified) clang/include/clang/Basic/DiagnosticParseKinds.td (+9-6) - (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+12-4) - (modified) clang/lib/CodeGen/CGExpr.cpp (+7-4) - (modified) clang/lib/CodeGen/CGOpenMPRuntime.cpp (+9-4) - (modified) clang/lib/CodeGen/CodeGenModule.cpp (+4-2) - (modified) clang/lib/Parse/ParseOpenMP.cpp (+39-21) - (modified) clang/lib/Sema/SemaOpenMP.cpp (+25-4) - (modified) clang/test/AST/dump.cpp (+26-1) - (modified) clang/test/OpenMP/declare_target_ast_print.cpp (+49-1) - (modified) clang/test/OpenMP/declare_target_messages.cpp (+119-20) - (modified) llvm/include/llvm/Frontend/OpenMP/OMP.td (+1) ``````````diff diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 8ab4aaa6f5781..61194e3c2c940 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4715,17 +4715,15 @@ def OMPDeclareTargetDecl : InheritableAttr { let SemaHandler = 0; let Subjects = SubjectList<[Function, SharedVar]>; let Documentation = [OMPDeclareTargetDocs]; - let Args = [ - EnumArgument<"MapType", "MapTypeTy", /*is_string=*/false, - [ "to", "enter", "link" ], - [ "MT_To", "MT_Enter", "MT_Link" ]>, - EnumArgument<"DevType", "DevTypeTy", /*is_string=*/false, - [ "host", "nohost", "any" ], - [ "DT_Host", "DT_NoHost", "DT_Any" ]>, - ExprArgument<"IndirectExpr">, - BoolArgument<"Indirect">, - UnsignedArgument<"Level"> - ]; + let Args = [EnumArgument< + "MapType", "MapTypeTy", + /*is_string=*/false, ["to", "enter", "link", "local"], + ["MT_To", "MT_Enter", "MT_Link", "MT_Local"]>, + EnumArgument<"DevType", "DevTypeTy", + /*is_string=*/false, ["host", "nohost", "any"], + ["DT_Host", "DT_NoHost", "DT_Any"]>, + ExprArgument<"IndirectExpr">, BoolArgument<"Indirect">, + UnsignedArgument<"Level">]; let AdditionalMembers = [{ void printPrettyPragma(raw_ostream &OS, const PrintingPolicy &Policy) const; static std::optional<MapTypeTy> diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index de10dbe5d0628..19edc7f7a3b23 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1558,18 +1558,21 @@ def note_omp_assumption_clause_continue_here : Note<"the ignored tokens spans until here">; def err_omp_declare_target_unexpected_clause: Error< "unexpected '%0' clause, only %select{'device_type'|'to' or 'link'|'to', 'link' or 'device_type'|'device_type', 'indirect'|'to', 'link', 'device_type' or 'indirect'}1 clauses expected">; -def err_omp_declare_target_unexpected_clause_52: Error< - "unexpected '%0' clause, only %select{'device_type'|'enter' or 'link'|'enter', 'link' or 'device_type'|'device_type', 'indirect'|'enter', 'link', 'device_type' or 'indirect'}1 clauses expected">; +def err_omp_declare_target_unexpected_clause_52 + : Error<"unexpected '%0' clause, only %select{'device_type'|'enter' or " + "'link'|'enter', 'link' or 'device_type'|'device_type', " + "'indirect'|'enter', 'link', 'device_type' or 'indirect'|'enter', " + "'link', 'device_type', 'indirect' or 'local'}1 clauses expected">; def err_omp_begin_declare_target_unexpected_implicit_to_clause: Error< "unexpected '(', only 'to', 'link' or 'device_type' clauses expected for 'begin declare target' directive">; def err_omp_declare_target_wrong_clause_after_implicit_to: Error< "unexpected clause after an implicit 'to' clause">; def err_omp_declare_target_wrong_clause_after_implicit_enter: Error< "unexpected clause after an implicit 'enter' clause">; -def err_omp_declare_target_missing_to_or_link_clause: Error< - "expected at least one %select{'to' or 'link'|'to', 'link' or 'indirect'}0 clause">; -def err_omp_declare_target_missing_enter_or_link_clause: Error< - "expected at least one %select{'enter' or 'link'|'enter', 'link' or 'indirect'}0 clause">; +def err_omp_declare_target_missing_required_clause + : Error<"expected at least one %select{'to' or 'link'|'to', 'link' or " + "'indirect'|'enter', 'link' or 'indirect'|'enter', 'link', " + "'indirect' or 'local'}0 clause">; def err_omp_declare_target_unexpected_to_clause: Error< "unexpected 'to' clause, use 'enter' instead">; def err_omp_declare_target_unexpected_enter_clause: Error< diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 0c25eb2443d5e..38efae80429b8 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12127,13 +12127,16 @@ def warn_omp_alignment_not_power_of_two : Warning< InGroup<OpenMPClauses>; def err_omp_invalid_target_decl : Error< "%0 used in declare target directive is not a variable or a function name">; -def err_omp_declare_target_to_and_link : Error< - "%0 must not appear in both clauses 'to' and 'link'">; +def err_omp_declare_target_var_in_both_clauses + : Error<"%0 must not appear in both clauses '%1' and '%2'">; +def err_omp_declare_target_local_host_only + : Error<"'local' clause is incompatible with 'device_type(host)'; " + "local variables exist only on the device">; def warn_omp_not_in_target_context : Warning< "declaration is not declared in any declare target region">, InGroup<OpenMPTarget>; -def err_omp_function_in_link_clause : Error< - "function name is not allowed in 'link' clause">; +def err_omp_function_in_target_clause_list + : Error<"function name is not allowed in '%0' clause">; def err_omp_aligned_expected_array_or_ptr : Error< "argument of aligned clause should be array" "%select{ or pointer|, pointer, reference to array or reference to pointer}1" @@ -12549,6 +12552,11 @@ def err_omp_declare_target_has_local_vars : Error< def warn_omp_declare_target_after_first_use : Warning< "declaration marked as declare target after first use, it may lead to incorrect results">, InGroup<OpenMPTarget>; +def warn_omp_declare_target_local_not_implemented + : Warning<"'local' clause on 'declare_target' directive is not yet fully " + "implemented; " + "variable will be treated as 'enter'">, + InGroup<OpenMPTarget>; def err_omp_declare_variant_incompat_attributes : Error< "'#pragma omp declare variant' is not compatible with any target-specific attributes">; def warn_omp_declare_variant_score_not_constant diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 069846b854a87..88b2b6b3c33fb 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -3327,15 +3327,18 @@ static Address emitDeclTargetVarDeclLValue(CodeGenFunction &CGF, std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res = OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD); // Return an invalid address if variable is MT_To (or MT_Enter starting with - // OpenMP 5.2) and unified memory is not enabled. For all other cases: MT_Link - // and MT_To (or MT_Enter) with unified memory, return a valid address. + // OpenMP 5.2, or MT_Local in OpenMP 6.0) and unified memory is not enabled. + // For all other cases: MT_Link and MT_To (or MT_Enter/MT_Local) with unified + // memory, return a valid address. if (!Res || ((*Res == OMPDeclareTargetDeclAttr::MT_To || - *Res == OMPDeclareTargetDeclAttr::MT_Enter) && + *Res == OMPDeclareTargetDeclAttr::MT_Enter || + *Res == OMPDeclareTargetDeclAttr::MT_Local) && !CGF.CGM.getOpenMPRuntime().hasRequiresUnifiedSharedMemory())) return Address::invalid(); assert(((*Res == OMPDeclareTargetDeclAttr::MT_Link) || ((*Res == OMPDeclareTargetDeclAttr::MT_To || - *Res == OMPDeclareTargetDeclAttr::MT_Enter) && + *Res == OMPDeclareTargetDeclAttr::MT_Enter || + *Res == OMPDeclareTargetDeclAttr::MT_Local) && CGF.CGM.getOpenMPRuntime().hasRequiresUnifiedSharedMemory())) && "Expected link clause OR to clause with unified memory enabled."); QualType PtrTy = CGF.getContext().getPointerType(VD->getType()); diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index 3ec09b4e8c630..fb87a42b1cad2 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -1529,6 +1529,7 @@ convertCaptureClause(const VarDecl *VD) { return llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryTo; break; case OMPDeclareTargetDeclAttr::MapTypeTy::MT_Enter: + case OMPDeclareTargetDeclAttr::MapTypeTy::MT_Local: return llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryEnter; break; case OMPDeclareTargetDeclAttr::MapTypeTy::MT_Link: @@ -7980,7 +7981,8 @@ class MappableExprsHandler { OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD)) { if ((*Res == OMPDeclareTargetDeclAttr::MT_Link) || ((*Res == OMPDeclareTargetDeclAttr::MT_To || - *Res == OMPDeclareTargetDeclAttr::MT_Enter) && + *Res == OMPDeclareTargetDeclAttr::MT_Enter || + *Res == OMPDeclareTargetDeclAttr::MT_Local) && CGF.CGM.getOpenMPRuntime().hasRequiresUnifiedSharedMemory())) { RequiresReference = true; BP = CGF.CGM.getOpenMPRuntime().getAddrOfDeclareTargetVar(VD); @@ -11299,7 +11301,8 @@ bool CGOpenMPRuntime::emitTargetGlobalVariable(GlobalDecl GD) { cast<VarDecl>(GD.getDecl())); if (!Res || *Res == OMPDeclareTargetDeclAttr::MT_Link || ((*Res == OMPDeclareTargetDeclAttr::MT_To || - *Res == OMPDeclareTargetDeclAttr::MT_Enter) && + *Res == OMPDeclareTargetDeclAttr::MT_Enter || + *Res == OMPDeclareTargetDeclAttr::MT_Local) && HasRequiresUnifiedSharedMemory)) { DeferredGlobalVariables.insert(cast<VarDecl>(GD.getDecl())); return true; @@ -11369,13 +11372,15 @@ void CGOpenMPRuntime::emitDeferredTargetDecls() const { if (!Res) continue; if ((*Res == OMPDeclareTargetDeclAttr::MT_To || - *Res == OMPDeclareTargetDeclAttr::MT_Enter) && + *Res == OMPDeclareTargetDeclAttr::MT_Enter || + *Res == OMPDeclareTargetDeclAttr::MT_Local) && !HasRequiresUnifiedSharedMemory) { CGM.EmitGlobal(VD); } else { assert((*Res == OMPDeclareTargetDeclAttr::MT_Link || ((*Res == OMPDeclareTargetDeclAttr::MT_To || - *Res == OMPDeclareTargetDeclAttr::MT_Enter) && + *Res == OMPDeclareTargetDeclAttr::MT_Enter || + *Res == OMPDeclareTargetDeclAttr::MT_Local) && HasRequiresUnifiedSharedMemory)) && "Expected link clause or to clause with unified memory."); (void)CGM.getOpenMPRuntime().getAddrOfDeclareTargetVar(VD); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 3b64be7a477d6..153bfad5fae18 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -4407,13 +4407,15 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { bool UnifiedMemoryEnabled = getOpenMPRuntime().hasRequiresUnifiedSharedMemory(); if ((*Res == OMPDeclareTargetDeclAttr::MT_To || - *Res == OMPDeclareTargetDeclAttr::MT_Enter) && + *Res == OMPDeclareTargetDeclAttr::MT_Enter || + *Res == OMPDeclareTargetDeclAttr::MT_Local) && !UnifiedMemoryEnabled) { (void)GetAddrOfGlobalVar(VD); } else { assert(((*Res == OMPDeclareTargetDeclAttr::MT_Link) || ((*Res == OMPDeclareTargetDeclAttr::MT_To || - *Res == OMPDeclareTargetDeclAttr::MT_Enter) && + *Res == OMPDeclareTargetDeclAttr::MT_Enter || + *Res == OMPDeclareTargetDeclAttr::MT_Local) && UnifiedMemoryEnabled)) && "Link clause or to clause with unified memory expected."); (void)getOpenMPRuntime().getAddrOfDeclareTargetVar(VD); diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 0bb503484299d..29397d67b5bcc 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -1758,14 +1758,14 @@ parseOpenMPSimpleClause(Parser &P, OpenMPClauseKind Kind) { void Parser::ParseOMPDeclareTargetClauses( SemaOpenMP::DeclareTargetContextInfo &DTCI) { SourceLocation DeviceTypeLoc; - bool RequiresToOrLinkOrIndirectClause = false; - bool HasToOrLinkOrIndirectClause = false; + bool RequiresToLinkLocalOrIndirectClause = false; + bool HasToLinkLocalOrIndirectClause = false; while (Tok.isNot(tok::annot_pragma_openmp_end)) { OMPDeclareTargetDeclAttr::MapTypeTy MT = OMPDeclareTargetDeclAttr::MT_To; bool HasIdentifier = Tok.is(tok::identifier); if (HasIdentifier) { - // If we see any clause we need a to or link clause. - RequiresToOrLinkOrIndirectClause = true; + // If we see any clause we need a to, link, or local clause. + RequiresToLinkLocalOrIndirectClause = true; IdentifierInfo *II = Tok.getIdentifierInfo(); StringRef ClauseName = II->getName(); bool IsDeviceTypeClause = @@ -1774,6 +1774,7 @@ void Parser::ParseOMPDeclareTargetClauses( bool IsIndirectClause = getLangOpts().OpenMP >= 51 && getOpenMPClauseKind(ClauseName) == OMPC_indirect; + if (DTCI.Indirect && IsIndirectClause) { unsigned OMPVersion = Actions.getLangOpts().OpenMP; Diag(Tok, diag::err_omp_more_one_clause) @@ -1781,9 +1782,9 @@ void Parser::ParseOMPDeclareTargetClauses( << getOpenMPClauseName(OMPC_indirect) << 0; break; } - bool IsToEnterOrLinkClause = + bool IsToEnterLinkOrLocalClause = OMPDeclareTargetDeclAttr::ConvertStrToMapTypeTy(ClauseName, MT); - assert((!IsDeviceTypeClause || !IsToEnterOrLinkClause) && + assert((!IsDeviceTypeClause || !IsToEnterLinkOrLocalClause) && "Cannot be both!"); // Starting with OpenMP 5.2 the `to` clause has been replaced by the @@ -1797,25 +1798,42 @@ void Parser::ParseOMPDeclareTargetClauses( break; } + // The 'local' clause is only available in OpenMP 6.0. + if (getLangOpts().OpenMP < 60 && ClauseName == "local") { + Diag(Tok, getLangOpts().OpenMP >= 52 + ? diag::err_omp_declare_target_unexpected_clause_52 + : diag::err_omp_declare_target_unexpected_clause) + << ClauseName + << (getLangOpts().OpenMP >= 51 ? 4 + : getLangOpts().OpenMP >= 50 ? 2 + : 1); + break; + } + if (!IsDeviceTypeClause && !IsIndirectClause && DTCI.Kind == OMPD_begin_declare_target) { - Diag(Tok, diag::err_omp_declare_target_unexpected_clause) + Diag(Tok, getLangOpts().OpenMP >= 52 + ? diag::err_omp_declare_target_unexpected_clause_52 + : diag::err_omp_declare_target_unexpected_clause) << ClauseName << (getLangOpts().OpenMP >= 51 ? 3 : 0); break; } - if (!IsDeviceTypeClause && !IsToEnterOrLinkClause && !IsIndirectClause) { + + if (!IsDeviceTypeClause && !IsToEnterLinkOrLocalClause && + !IsIndirectClause) { Diag(Tok, getLangOpts().OpenMP >= 52 ? diag::err_omp_declare_target_unexpected_clause_52 : diag::err_omp_declare_target_unexpected_clause) << ClauseName - << (getLangOpts().OpenMP >= 51 - ? 4 - : getLangOpts().OpenMP >= 50 ? 2 : 1); + << (getLangOpts().OpenMP > 52 ? 5 + : getLangOpts().OpenMP >= 51 ? 4 + : getLangOpts().OpenMP >= 50 ? 2 + : 1); break; } - if (IsToEnterOrLinkClause || IsIndirectClause) - HasToOrLinkOrIndirectClause = true; + if (IsToEnterLinkOrLocalClause || IsIndirectClause) + HasToLinkLocalOrIndirectClause = true; if (IsIndirectClause) { if (!ParseOpenMPIndirectClause(DTCI, /*ParseOnly*/ false)) @@ -1892,14 +1910,14 @@ void Parser::ParseOMPDeclareTargetClauses( if (DTCI.Indirect && DTCI.DT != OMPDeclareTargetDeclAttr::DT_Any) Diag(DeviceTypeLoc, diag::err_omp_declare_target_indirect_device_type); - // For declare target require at least 'to' or 'link' to be present. - if (DTCI.Kind == OMPD_declare_target && RequiresToOrLinkOrIndirectClause && - !HasToOrLinkOrIndirectClause) - Diag(DTCI.Loc, - getLangOpts().OpenMP >= 52 - ? diag::err_omp_declare_target_missing_enter_or_link_clause - : diag::err_omp_declare_target_missing_to_or_link_clause) - << (getLangOpts().OpenMP >= 51 ? 1 : 0); + // declare target requires at least one clause. + if (DTCI.Kind == OMPD_declare_target && RequiresToLinkLocalOrIndirectClause && + !HasToLinkLocalOrIndirectClause) + Diag(DTCI.Loc, diag::err_omp_declare_target_missing_required_clause) + << (getLangOpts().OpenMP >= 60 ? 3 + : getLangOpts().OpenMP == 52 ? 2 + : getLangOpts().OpenMP == 51 ? 1 + : 0); SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); } diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index bbb4f939028ec..fe7199be4ead3 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -24453,6 +24453,14 @@ void SemaOpenMP::ActOnOpenMPDeclareTargetName( if (getLangOpts().HIP) Diag(Loc, diag::warn_hip_omp_target_directives); + // 'local' is incompatible with 'device_type(host)' because 'local' + // variables exist only on the device. + if (MT == OMPDeclareTargetDeclAttr::MT_Local && + DTCI.DT == OMPDeclareTargetDeclAttr::DT_Host) { + Diag(Loc, diag::err_omp_declare_target_local_host_only); + return; + } + // Explicit declare target lists have precedence. const unsigned Level = -1; @@ -24469,7 +24477,11 @@ void SemaOpenMP::ActOnOpenMPDeclareTargetName( } if (ActiveAttr && (*ActiveAttr)->getMapType() != MT && (*ActiveAttr)->getLevel() == Level) { - Diag(Loc, diag::err_omp_declare_target_to_and_link) << ND; + Diag(Loc, diag::err_omp_declare_target_var_in_both_clauses) + << ND + << OMPDeclareTargetDeclAttr::ConvertMapTypeTyToStr( + (*ActiveAttr)->getMapType()) + << OMPDeclareTargetDeclAttr::ConvertMapTypeTyToStr(MT); return; } @@ -24483,6 +24495,11 @@ void SemaOpenMP::ActOnOpenMPDeclareTargetName( if (!IndirectE) IsIndirect = true; } + // FIXME: 'local' clause is not yet implemented in CodeGen. For now, it is + // treated as 'enter'. For host compilation, 'local' is a no-op. + if (MT == OMPDeclareTargetDeclAttr::MT_Local && + getLangOpts().OpenMPIsTargetDevice) + Diag(Loc, diag::warn_omp_declare_target_local_not_implemented); auto *A = OMPDeclareTargetDeclAttr::CreateImplicit( getASTContext(), MT, DTCI.DT, IndirectE, IsIndirect, Level, SourceRange(Loc, Loc)); @@ -24508,7 +24525,8 @@ static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR, SemaRef.getCurBlock() || SemaRef.getCurCapturedRegion()) && VD->hasGlobalStorage()) { if (!MapTy || (*MapTy != OMPDeclareTargetDeclAttr::MT_To && - *MapTy != OMPDeclareTargetDeclAttr::MT_Enter)) { + *MapTy != OMPDeclareTargetDeclAttr::MT_Enter && + *MapTy != OMPDeclareTargetDeclAttr::MT_Local)) { // OpenMP 5.0, 2.12.7 declare target Directive, Restrictions // If a lambda declaration and definition appears between a // declare target directive and the matching end declare target @@ -24559,8 +24577,11 @@ void SemaOpenMP::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, if (auto *FD = dyn_cast<FunctionDecl>(D)) { std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res = OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(FD); - if (IdLoc.isValid() && Res && *Res == OMPDeclareTargetDeclAttr::MT_Link) { - Diag(IdLoc, diag::err_omp_function_in_link_clause); + if (IdLoc.isValid() && Res && + (*Res == OMPDeclareTargetDeclAttr::MT_Link || + *Res == OMPDeclareTargetDeclAttr::MT_Local)) { + Diag(IdLoc, diag::err_omp_function_in_target_clause_list) + << OMPDeclareTargetDeclAttr::ConvertMapTypeTyToStr(*Res); Diag(FD->getLocation(), diag::note_defined_here) << FD; return; } diff --git a/clang/test/AST/dump.cpp b/clang/test/AST/dump.cpp ind... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/186281 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
