llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Erich Keane (erichkeane) <details> <summary>Changes</summary> This DOES move checking functions out of CodeGen and into CodeGenUtils so both can use it. This is a diagnostic for builtins/etc that is built in to classic codegen. We have to implement it, because otherwise autoconfig thinks that we support AVX without a flag, and thus causes us to fail builds later on that now expect __AVX__/etc to be defined without enabling them. --- Patch is 44.03 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/223056.diff 22 Files Affected: - (modified) clang/include/clang/CodeGenUtils/CodeGenUtils.h (+23) - (modified) clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp (+22) - (modified) clang/lib/CIR/CodeGen/CIRGenCall.cpp (+17) - (modified) clang/lib/CIR/CodeGen/CIRGenFunction.h (+7) - (modified) clang/lib/CIR/FrontendAction/CIRGenAction.cpp (+4) - (modified) clang/lib/CodeGen/CodeGenFunction.cpp (+6-108) - (modified) clang/lib/CodeGenUtils/CodeGenUtils.cpp (+118) - (added) clang/test/CIR/CodeGen/avx512-error.c (+23) - (added) clang/test/CIR/CodeGen/target-builtin-error-2.c (+13) - (added) clang/test/CIR/CodeGen/target-builtin-error-3.c (+62) - (added) clang/test/CIR/CodeGen/target-builtin-error.c (+8) - (added) clang/test/CIR/CodeGen/target-builtin-noerror.c (+215) - (added) clang/test/CIR/CodeGen/target-features-error-2.c (+50) - (added) clang/test/CIR/CodeGen/target-features-error-3.c (+12) - (added) clang/test/CIR/CodeGen/target-features-error-4.c (+12) - (added) clang/test/CIR/CodeGen/target-features-error-5.c (+12) - (added) clang/test/CIR/CodeGen/target-features-error.c (+7) - (added) clang/test/CIR/CodeGen/target-features-no-error-2.c (+12) - (added) clang/test/CIR/CodeGen/target-features-no-error.c (+9) - (modified) clang/test/CIR/CodeGenBuiltins/X86/avx512vlvbmi2-builtins.c (+4-4) - (modified) clang/test/CIR/CodeGenBuiltins/X86/sqrt-builtins.c (+3-3) - (modified) clang/test/CIR/CodeGenBuiltins/builtin-undef-rvalue.cpp (-6) ``````````diff diff --git a/clang/include/clang/CodeGenUtils/CodeGenUtils.h b/clang/include/clang/CodeGenUtils/CodeGenUtils.h index 2ecae74d1f606..b24f457f9537c 100644 --- a/clang/include/clang/CodeGenUtils/CodeGenUtils.h +++ b/clang/include/clang/CodeGenUtils/CodeGenUtils.h @@ -10,6 +10,14 @@ #define LLVM_CLANG_CODEGENUTILS_CODEGENUTILS_H #include "clang/AST/ASTContext.h" +#include "clang/Basic/SourceLocation.h" + +namespace clang { +class CallExpr; +class DiagnosticsEngine; +class FunctionDecl; +class LangOptions; +} // namespace clang namespace clang::CodeGenUtils { /// Check whether we need to initialize any vtable pointers before calling this @@ -37,6 +45,21 @@ bool hasUnwindExceptions(const LangOptions &LangOpts); bool isAAPCS(const TargetInfo &TargetInfo); bool isInitializerOfDynamicClass(const CXXCtorInitializer *BaseInit); + +/// Check that a call to a target-specific builtin has the required target +/// features enabled in the caller, emitting an error diagnostic if not. +/// \p caller is the FunctionDecl of the enclosing function (may be null). +void checkTargetFeatures(ASTContext &Ctx, DiagnosticsEngine &Diags, + const LangOptions &LangOpts, const CallExpr *E, + const FunctionDecl *Caller, + const FunctionDecl *TargetDecl); + +/// Overload taking a raw source location instead of a CallExpr. +void checkTargetFeatures(ASTContext &Ctx, DiagnosticsEngine &Diags, + const LangOptions &LangOpts, SourceLocation Loc, + const FunctionDecl *Caller, + const FunctionDecl *TargetDecl); + } // namespace clang::CodeGenUtils #endif // LLVM_CLANG_CODEGENUTILS_CODEGENUTILS_H diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index c7ce147b68d61..e039f85851337 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -26,6 +26,7 @@ #include "clang/Basic/OperatorKinds.h" #include "clang/CIR/Dialect/IR/CIRTypes.h" #include "clang/CIR/MissingFeatures.h" +#include "clang/CodeGenUtils/CodeGenUtils.h" #include "llvm/ADT/STLExtras.h" #include "llvm/IR/Intrinsics.h" #include "llvm/Support/ErrorHandling.h" @@ -1236,6 +1237,20 @@ static cir::FuncType getIntrinsicType(CIRGenFunction &cgf, return cir::FuncType::get(context, argTypes, resultTy, isVarArg); } +void CIRGenFunction::checkTargetFeatures(const CallExpr *e, + const FunctionDecl *targetDecl) { + const FunctionDecl *fd = dyn_cast_or_null<FunctionDecl>(curCodeDecl); + CodeGenUtils::checkTargetFeatures(getContext(), cgm.getDiags(), getLangOpts(), + e, fd, targetDecl); +} + +void CIRGenFunction::checkTargetFeatures(SourceLocation loc, + const FunctionDecl *targetDecl) { + const FunctionDecl *fd = dyn_cast_or_null<FunctionDecl>(curCodeDecl); + CodeGenUtils::checkTargetFeatures(getContext(), cgm.getDiags(), getLangOpts(), + loc, fd, targetDecl); +} + RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, const CallExpr *e, ReturnValueSlot returnValue) { @@ -2998,6 +3013,13 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, return emitLibraryCall(*this, fd, e, emitScalarExpr(e->getCallee()).getDefiningOp()); + // Check that a call to a target specific builtin has the correct target + // features. + // This is down here to avoid non-target specific builtins, however, if + // generic builtins start to require generic target features then we + // can move this up to the beginning of the function. + checkTargetFeatures(e, fd); + // See if we have a target specific intrinsic. std::string name = getContext().BuiltinInfo.getName(builtinID); Intrinsic::ID intrinsicID = Intrinsic::not_intrinsic; diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index 2caf22d3beb88..b9c3472190553 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -1218,6 +1218,23 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo, SmallVector<mlir::Value, 16> cirCallArgs(args.size()); const Decl *targetDecl = callee.getAbstractInfo().getCalleeDecl().getDecl(); + + if (const FunctionDecl *fd = dyn_cast_or_null<FunctionDecl>(targetDecl)) { + // We can only guarantee that a function is called from the correct + // context/function based on the appropriate target attributes, + // so only check in the case where we have both always_inline and target + // since otherwise we could be making a conditional call after a check for + // the proper cpu features (and it won't cause code generation issues due to + // function based code generation). + if ((targetDecl->hasAttr<AlwaysInlineAttr>() && + (targetDecl->hasAttr<TargetAttr>() || + (curFuncDecl && curFuncDecl->hasAttr<TargetAttr>()))) || + (curFuncDecl && curFuncDecl->hasAttr<FlattenAttr>() && + (curFuncDecl->hasAttr<TargetAttr>() || + targetDecl->hasAttr<TargetAttr>()))) + checkTargetFeatures(clangLoc.getBegin(), fd); + } + const FunctionDecl *callerDecl = dyn_cast_or_null<FunctionDecl>(curCodeDecl); const FunctionDecl *calleeDecl = dyn_cast_or_null<FunctionDecl>(targetDecl); diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 86a8736980773..dc57fd826337b 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -2346,6 +2346,13 @@ class CIRGenFunction : public CIRGenTypeCache { emitTargetBuiltinExpr(unsigned builtinID, const clang::CallExpr *e, ReturnValueSlot &returnValue); + /// Emit a diagnostic if the target features required by \p targetDecl are + /// not available in the calling function. Mirrors CodeGenFunction behavior. + void checkTargetFeatures(const clang::CallExpr *e, + const clang::FunctionDecl *targetDecl); + void checkTargetFeatures(clang::SourceLocation loc, + const clang::FunctionDecl *targetDecl); + /// Given a value and its clang type, returns the value casted to its memory /// representation. /// Note: CIR defers most of the special casting to the final lowering passes diff --git a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp index 66c2f9b7a8937..57c40121fb39b 100644 --- a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp +++ b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp @@ -195,6 +195,10 @@ class CIRGenConsumer : public clang::ASTConsumer { MlirModule->print(out); } + // If errors occurred during codegen, stop before running the backend. + if (CI.getDiagnostics().hasErrorOccurred()) + return; + std::unique_ptr<llvm::Module> LLVMModule = lowerFromCIRToLLVMIR( MlirModule, LLVMCtx, C.getLangOpts().OpenMP, mlirSaveTempsOutFile, &CI.getVirtualFileSystem()); diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 7e7f9a072f765..fe39235fcd4f6 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -36,6 +36,7 @@ #include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" #include "clang/CodeGen/CGFunctionInfo.h" +#include "clang/CodeGenUtils/CodeGenUtils.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/Frontend/OpenMP/OMPIRBuilder.h" @@ -2884,121 +2885,18 @@ void CGBuilderInserter::InsertHelper( // called function. void CodeGenFunction::checkTargetFeatures(const CallExpr *E, const FunctionDecl *TargetDecl) { - // SemaChecking cannot handle below x86 builtins because they have different - // parameter ranges with different TargetAttribute of caller. - if (CGM.getContext().getTargetInfo().getTriple().isX86()) { - unsigned BuiltinID = TargetDecl->getBuiltinID(); - if (BuiltinID == X86::BI__builtin_ia32_cmpps || - BuiltinID == X86::BI__builtin_ia32_cmpss || - BuiltinID == X86::BI__builtin_ia32_cmppd || - BuiltinID == X86::BI__builtin_ia32_cmpsd) { - const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurCodeDecl); - llvm::StringMap<bool> TargetFetureMap; - CGM.getContext().getFunctionFeatureMap(TargetFetureMap, FD); - llvm::APSInt Result = - *(E->getArg(2)->getIntegerConstantExpr(CGM.getContext())); - if (Result.getSExtValue() > 7 && !TargetFetureMap.lookup("avx")) - CGM.getDiags().Report(E->getBeginLoc(), diag::err_builtin_needs_feature) - << TargetDecl->getDeclName() << "avx"; - } - } - return checkTargetFeatures(E->getBeginLoc(), TargetDecl); + const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurCodeDecl); + CodeGenUtils::checkTargetFeatures(CGM.getContext(), CGM.getDiags(), + getLangOpts(), E, FD, TargetDecl); } // Emits an error if we don't have a valid set of target features for the // called function. void CodeGenFunction::checkTargetFeatures(SourceLocation Loc, const FunctionDecl *TargetDecl) { - // Early exit if this is an indirect call. - if (!TargetDecl) - return; - - // Get the current enclosing function if it exists. If it doesn't - // we can't check the target features anyhow. const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurCodeDecl); - if (!FD) - return; - - bool IsAlwaysInline = TargetDecl->hasAttr<AlwaysInlineAttr>(); - bool IsFlatten = FD && FD->hasAttr<FlattenAttr>(); - - // Grab the required features for the call. For a builtin this is listed in - // the td file with the default cpu, for an always_inline function this is any - // listed cpu and any listed features. - unsigned BuiltinID = TargetDecl->getBuiltinID(); - std::string MissingFeature; - llvm::StringMap<bool> CallerFeatureMap; - CGM.getContext().getFunctionFeatureMap(CallerFeatureMap, FD); - // When compiling in HipStdPar mode we have to be conservative in rejecting - // target specific features in the FE, and defer the possible error to the - // AcceleratorCodeSelection pass, wherein iff an unsupported target builtin is - // referenced by an accelerator executable function, we emit an error. - bool IsHipStdPar = getLangOpts().HIPStdPar && getLangOpts().CUDAIsDevice; - if (BuiltinID) { - StringRef FeatureList(CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID)); - if (!Builtin::evaluateRequiredTargetFeatures( - FeatureList, CallerFeatureMap) && !IsHipStdPar) { - CGM.getDiags().Report(Loc, diag::err_builtin_needs_feature) - << TargetDecl->getDeclName() - << FeatureList; - } - } else if (!TargetDecl->isMultiVersion() && - TargetDecl->hasAttr<TargetAttr>()) { - // Get the required features for the callee. - - const TargetAttr *TD = TargetDecl->getAttr<TargetAttr>(); - ParsedTargetAttr ParsedAttr = - CGM.getContext().filterFunctionTargetAttrs(TD); - - SmallVector<StringRef, 1> ReqFeatures; - llvm::StringMap<bool> CalleeFeatureMap; - CGM.getContext().getFunctionFeatureMap(CalleeFeatureMap, TargetDecl); - - for (const auto &F : ParsedAttr.Features) { - if (F[0] == '+' && CalleeFeatureMap.lookup(F.substr(1))) - ReqFeatures.push_back(StringRef(F).substr(1)); - } - - for (const auto &F : CalleeFeatureMap) { - // Only positive features are "required". - if (F.getValue()) - ReqFeatures.push_back(F.getKey()); - } - if (!llvm::all_of(ReqFeatures, - [&](StringRef Feature) { - if (!CallerFeatureMap.lookup(Feature)) { - MissingFeature = Feature.str(); - return false; - } - return true; - }) && - !IsHipStdPar) { - if (IsAlwaysInline) - CGM.getDiags().Report(Loc, diag::err_function_needs_feature) - << FD->getDeclName() << TargetDecl->getDeclName() << MissingFeature; - else if (IsFlatten) - CGM.getDiags().Report(Loc, diag::err_flatten_function_needs_feature) - << FD->getDeclName() << TargetDecl->getDeclName() << MissingFeature; - } - - } else if (!FD->isMultiVersion() && FD->hasAttr<TargetAttr>()) { - llvm::StringMap<bool> CalleeFeatureMap; - CGM.getContext().getFunctionFeatureMap(CalleeFeatureMap, TargetDecl); - - for (const auto &F : CalleeFeatureMap) { - if (F.getValue() && - (!CallerFeatureMap.lookup(F.getKey()) || - !CallerFeatureMap.find(F.getKey())->getValue()) && - !IsHipStdPar) { - if (IsAlwaysInline) - CGM.getDiags().Report(Loc, diag::err_function_needs_feature) - << FD->getDeclName() << TargetDecl->getDeclName() << F.getKey(); - else if (IsFlatten) - CGM.getDiags().Report(Loc, diag::err_flatten_function_needs_feature) - << FD->getDeclName() << TargetDecl->getDeclName() << F.getKey(); - } - } - } + CodeGenUtils::checkTargetFeatures(CGM.getContext(), CGM.getDiags(), + getLangOpts(), Loc, FD, TargetDecl); } void CodeGenFunction::EmitSanitizerStatReport(llvm::SanitizerStatKind SSK) { diff --git a/clang/lib/CodeGenUtils/CodeGenUtils.cpp b/clang/lib/CodeGenUtils/CodeGenUtils.cpp index 42544c74af4aa..4fd78d6997e95 100644 --- a/clang/lib/CodeGenUtils/CodeGenUtils.cpp +++ b/clang/lib/CodeGenUtils/CodeGenUtils.cpp @@ -7,7 +7,13 @@ //===----------------------------------------------------------------------===// #include "clang/CodeGenUtils/CodeGenUtils.h" +#include "clang/AST/Attr.h" +#include "clang/AST/Expr.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/DiagnosticFrontend.h" +#include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/StringMap.h" namespace clang::CodeGenUtils { static bool @@ -112,4 +118,116 @@ bool isInitializerOfDynamicClass(const CXXCtorInitializer *BaseInit) { return BaseType->castAsCXXRecordDecl()->isDynamicClass(); } +// Emits an error if we don't have a valid set of target features for the +// called function. +void checkTargetFeatures(ASTContext &Ctx, DiagnosticsEngine &Diags, + const LangOptions &LangOpts, const CallExpr *E, + const FunctionDecl *Caller, + const FunctionDecl *TargetDecl) { + // SemaChecking cannot handle these x86 builtins because they have different + // parameter ranges depending on the caller's TargetAttribute. + if (Ctx.getTargetInfo().getTriple().isX86()) { + unsigned BuiltinID = TargetDecl->getBuiltinID(); + if (BuiltinID == X86::BI__builtin_ia32_cmpps || + BuiltinID == X86::BI__builtin_ia32_cmpss || + BuiltinID == X86::BI__builtin_ia32_cmppd || + BuiltinID == X86::BI__builtin_ia32_cmpsd) { + llvm::StringMap<bool> TargetFeatureMap; + Ctx.getFunctionFeatureMap(TargetFeatureMap, Caller); + llvm::APSInt Result = *(E->getArg(2)->getIntegerConstantExpr(Ctx)); + if (Result.getSExtValue() > 7 && !TargetFeatureMap.lookup("avx")) + Diags.Report(E->getBeginLoc(), diag::err_builtin_needs_feature) + << TargetDecl->getDeclName() << "avx"; + } + } + checkTargetFeatures(Ctx, Diags, LangOpts, E->getBeginLoc(), Caller, + TargetDecl); +} + +// Emits an error if we don't have a valid set of target features for the +// called function. +void checkTargetFeatures(ASTContext &Ctx, DiagnosticsEngine &Diags, + const LangOptions &LangOpts, SourceLocation Loc, + const FunctionDecl *Caller, + const FunctionDecl *TargetDecl) { + if (!TargetDecl || !Caller) + return; + + bool IsAlwaysInline = TargetDecl->hasAttr<AlwaysInlineAttr>(); + bool IsFlatten = Caller->hasAttr<FlattenAttr>(); + + unsigned BuiltinID = TargetDecl->getBuiltinID(); + std::string MissingFeature; + llvm::StringMap<bool> CallerFeatureMap; + Ctx.getFunctionFeatureMap(CallerFeatureMap, Caller); + // When compiling in HipStdPar mode we have to be conservative in rejecting + // target specific features in the FE, and defer the possible error to the + // AcceleratorCodeSelection pass, wherein iff an unsupported target builtin is + // referenced by an accelerator executable function, we emit an error. + bool IsHipStdPar = LangOpts.HIPStdPar && LangOpts.CUDAIsDevice; + if (BuiltinID) { + StringRef FeatureList(Ctx.BuiltinInfo.getRequiredFeatures(BuiltinID)); + if (!Builtin::evaluateRequiredTargetFeatures(FeatureList, + CallerFeatureMap) && + !IsHipStdPar) + Diags.Report(Loc, diag::err_builtin_needs_feature) + << TargetDecl->getDeclName() << FeatureList; + } else if (!TargetDecl->isMultiVersion() && + TargetDecl->hasAttr<TargetAttr>()) { + // Get the required features for the callee. + const TargetAttr *TD = TargetDecl->getAttr<TargetAttr>(); + ParsedTargetAttr ParsedAttr = Ctx.filterFunctionTargetAttrs(TD); + + SmallVector<StringRef, 1> ReqFeatures; + llvm::StringMap<bool> CalleeFeatureMap; + Ctx.getFunctionFeatureMap(CalleeFeatureMap, TargetDecl); + + for (const auto &F : ParsedAttr.Features) { + if (F[0] == '+' && CalleeFeatureMap.lookup(F.substr(1))) + ReqFeatures.push_back(StringRef(F).substr(1)); + } + for (const auto &F : CalleeFeatureMap) { + if (F.getValue()) + ReqFeatures.push_back(F.getKey()); + } + if (!llvm::all_of(ReqFeatures, + [&](StringRef Feature) { + if (!CallerFeatureMap.lookup(Feature)) { + MissingFeature = Feature.str(); + return false; + } + return true; + }) && + !IsHipStdPar) { + if (IsAlwaysInline) + Diags.Report(Loc, diag::err_function_needs_feature) + << Caller->getDeclName() << TargetDecl->getDeclName() + << MissingFeature; + else if (IsFlatten) + Diags.Report(Loc, diag::err_flatten_function_needs_feature) + << Caller->getDeclName() << TargetDecl->getDeclName() + << MissingFeature; + } + } else if (!Caller->isMultiVersion() && Caller->hasAttr<TargetAttr>()) { + llvm::StringMap<bool> CalleeFeatureMap; + Ctx.getFunctionFeatureMap(CalleeFeatureMap, TargetDecl); + + for (const auto &F : CalleeFeatureMap) { + if (F.getValue() && + (!CallerFeatureMap.lookup(F.getKey()) || + !CallerFeatureMap.find(F.getKey())->getValue()) && + !IsHipStdPar) { + if (IsAlwaysInline) + Diags.Report(Loc, diag::err_function_needs_feature) + << Caller->getDeclName() << TargetDecl->getDeclName() + << F.getKey(); + else if (IsFlatten) + Diags.Report(Loc, diag::err_flatten_function_needs_feature) + << Caller->getDeclName() << TargetDecl->getDeclName() + << F.getKey(); + } + } + } +} + } // namespace clang::CodeGenUtils diff --git a/clang/test/CIR/CodeGen/avx512-error.c b/clang/test/CIR/CodeGen/avx512-error.c new file mode 100644 index 0000000000000..1402c01ce5e55 --- /dev/null +++ b/clang/test/CIR/CodeGen/avx512-error.c @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 %s -ffreestanding -triple=x86_64-linux-gnu -fclangir -target-feature +avx512bw -emit-llvm -o /dev/null -verify +// RUN: %clang_cc1 %s -ffreestanding -triple=x86_64-linux-gnu -fclangir -target-feature +avx10.1 -emit-llvm -o /dev/null -verify + +#include <immintrin.h> + +__attribute__((target("avx512bw"))) +__mmask64 k64_verify_1(__mmask64 a) { + return _knot_mask64(a); // expected-no-diagnostics +} + +__mmask64 k64_verify_2(__mmask64 a) { + return _knot_mask64(a); // expected-no-diagnostic +} + +__attribute__((target("avx512bw"))) +__m512d zmm_verify_ok(__m512d a) { + return __builtin_ia32_... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/223056 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
