Author: jeanPerier Date: 2024-06-27T19:21:19+02:00 New Revision: 5c45ad8a20989bd9ca9fdf8148ce690dc28c834c
URL: https://github.com/llvm/llvm-project/commit/5c45ad8a20989bd9ca9fdf8148ce690dc28c834c DIFF: https://github.com/llvm/llvm-project/commit/5c45ad8a20989bd9ca9fdf8148ce690dc28c834c.diff LOG: Revert "[flang] add extra component information in fir.type_info (#96746)" This reverts commit 1448ed2000ff0be17025dab0aad7412d054425eb. Added: Modified: flang/include/flang/Optimizer/Builder/FIRBuilder.h flang/include/flang/Optimizer/Dialect/FIROps.td flang/include/flang/Optimizer/Support/InternalNames.h flang/include/flang/Optimizer/Support/Utils.h flang/lib/Lower/Bridge.cpp flang/lib/Optimizer/Builder/FIRBuilder.cpp flang/lib/Optimizer/Dialect/FIROps.cpp flang/lib/Optimizer/Support/CMakeLists.txt flang/lib/Optimizer/Support/InternalNames.cpp flang/test/Fir/fir-ops.fir Removed: flang/lib/Optimizer/Support/Utils.cpp flang/test/Lower/HLFIR/type-info-components.f90 ################################################################################ diff --git a/flang/include/flang/Optimizer/Builder/FIRBuilder.h b/flang/include/flang/Optimizer/Builder/FIRBuilder.h index ea35b298c0209..f9ef8b7566299 100644 --- a/flang/include/flang/Optimizer/Builder/FIRBuilder.h +++ b/flang/include/flang/Optimizer/Builder/FIRBuilder.h @@ -286,10 +286,6 @@ class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener { fir::StringLitOp createStringLitOp(mlir::Location loc, llvm::StringRef string); - std::pair<fir::TypeInfoOp, mlir::OpBuilder::InsertPoint> - createTypeInfoOp(mlir::Location loc, fir::RecordType recordType, - fir::RecordType parentType); - //===--------------------------------------------------------------------===// // Linkage helpers (inline). The default linkage is external. //===--------------------------------------------------------------------===// diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td index 5b03806614f9b..baf095263479b 100644 --- a/flang/include/flang/Optimizer/Dialect/FIROps.td +++ b/flang/include/flang/Optimizer/Dialect/FIROps.td @@ -2956,10 +2956,7 @@ def fir_TypeInfoOp : fir_Op<"type_info", let hasVerifier = 1; - let regions = (region - MaxSizedRegion<1>:$dispatch_table, - MaxSizedRegion<1>:$component_info - ); + let regions = (region MaxSizedRegion<1>:$dispatch_table); let builders = [ OpBuilder<(ins "fir::RecordType":$type, "fir::RecordType":$parent_type, @@ -2970,7 +2967,6 @@ def fir_TypeInfoOp : fir_Op<"type_info", $sym_name (`noinit` $no_init^)? (`nodestroy` $no_destroy^)? (`nofinal` $no_final^)? (`extends` $parent_type^)? attr-dict `:` $type (`dispatch_table` $dispatch_table^)? - (`component_info` $component_info^)? }]; let extraClassDeclaration = [{ @@ -3014,24 +3010,6 @@ def fir_DTEntryOp : fir_Op<"dt_entry", [HasParent<"TypeInfoOp">]> { }]; } -def fir_DTComponentOp : fir_Op<"dt_component", [HasParent<"TypeInfoOp">]> { - let summary = "define extra information about a component inside fir.type_info"; - - let description = [{ - ``` - fir.dt_component i lbs [-1,2] init @init_val - ``` - }]; - - let arguments = (ins - StrAttr:$name, - OptionalAttr<DenseI64ArrayAttr>:$lower_bounds, - OptionalAttr<FlatSymbolRefAttr>:$init_val - ); - - let assemblyFormat = "$name (`lbs` $lower_bounds^)? (`init` $init_val^)? attr-dict"; -} - def fir_AbsentOp : fir_OneResultOp<"absent", [NoMemoryEffect]> { let summary = "create value to be passed for absent optional function argument"; let description = [{ diff --git a/flang/include/flang/Optimizer/Support/InternalNames.h b/flang/include/flang/Optimizer/Support/InternalNames.h index ff23510922372..23a03854c4abd 100644 --- a/flang/include/flang/Optimizer/Support/InternalNames.h +++ b/flang/include/flang/Optimizer/Support/InternalNames.h @@ -15,7 +15,6 @@ #include <optional> static constexpr llvm::StringRef typeDescriptorSeparator = ".dt."; -static constexpr llvm::StringRef componentInitSeparator = ".di."; static constexpr llvm::StringRef bindingTableSeparator = ".v."; static constexpr llvm::StringRef boxprocSuffix = "UnboxProc"; @@ -157,11 +156,6 @@ struct NameUniquer { static std::string getTypeDescriptorBindingTableName(llvm::StringRef mangledTypeName); - /// Given a mangled derived type name and a component name, get the name of - /// the global object containing the component default initialization. - static std::string getComponentInitName(llvm::StringRef mangledTypeName, - llvm::StringRef componentName); - /// Remove markers that have been added when doing partial type /// conversions. mlir::Type cannot be mutated in a pass, so new /// fir::RecordType must be created when lowering member types. diff --git a/flang/include/flang/Optimizer/Support/Utils.h b/flang/include/flang/Optimizer/Support/Utils.h index ae95a26be1d86..d8bcb5fae034d 100644 --- a/flang/include/flang/Optimizer/Support/Utils.h +++ b/flang/include/flang/Optimizer/Support/Utils.h @@ -137,29 +137,6 @@ inline void intrinsicTypeTODO(fir::FirOpBuilder &builder, mlir::Type type, " in " + intrinsicName); } -/// Find the fir.type_info that was created for this \p recordType in \p module, -/// if any. \p symbolTable can be provided to speed-up the lookup. This tool -/// will match record type even if they have been "altered" in type conversion -/// passes. -fir::TypeInfoOp -lookupTypeInfoOp(fir::RecordType recordType, mlir::ModuleOp module, - const mlir::SymbolTable *symbolTable = nullptr); - -/// Find the fir.type_info named \p name in \p module, if any. \p symbolTable -/// can be provided to speed-up the lookup. Prefer using the equivalent with a -/// RecordType argument unless it is certain \p name has not been altered by a -/// pass rewriting fir.type (see NameUniquer::dropTypeConversionMarkers). -fir::TypeInfoOp -lookupTypeInfoOp(llvm::StringRef name, mlir::ModuleOp module, - const mlir::SymbolTable *symbolTable = nullptr); - -/// Returns all lower bounds of \p component if it is an array component of \p -/// recordType with non default lower bounds. Returns nullopt if this is not an -/// array componnet of \p recordType or if its lower bounds are all ones. -std::optional<llvm::ArrayRef<int64_t>> getComponentLowerBoundsIfNonDefault( - fir::RecordType recordType, llvm::StringRef component, - mlir::ModuleOp module, const mlir::SymbolTable *symbolTable = nullptr); - } // namespace fir #endif // FORTRAN_OPTIMIZER_SUPPORT_UTILS_H diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index 34ab65a23b545..50f58843ec70b 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -148,71 +148,6 @@ struct ConstructContext { bool pushedScope = false; // was a scoped pushed for this construct? }; -/// Helper to gather the lower bounds of array components with non deferred -/// shape when they are not all ones. Return an empty array attribute otherwise. -static mlir::DenseI64ArrayAttr -gatherComponentNonDefaultLowerBounds(mlir::Location loc, - mlir::MLIRContext *mlirContext, - const Fortran::semantics::Symbol &sym) { - if (Fortran::semantics::IsAllocatableOrObjectPointer(&sym)) - return {}; - mlir::DenseI64ArrayAttr lbs_attr; - if (const auto *objDetails = - sym.detailsIf<Fortran::semantics::ObjectEntityDetails>()) { - llvm::SmallVector<std::int64_t> lbs; - bool hasNonDefaultLbs = false; - for (const Fortran::semantics::ShapeSpec &bounds : objDetails->shape()) - if (auto lb = bounds.lbound().GetExplicit()) { - if (auto constant = Fortran::evaluate::ToInt64(*lb)) { - hasNonDefaultLbs |= (*constant != 1); - lbs.push_back(*constant); - } else { - TODO(loc, "generate fir.dt_component for length parametrized derived " - "types"); - } - } - if (hasNonDefaultLbs) { - assert(static_cast<int>(lbs.size()) == sym.Rank() && - "expected component bounds to be constant or deferred"); - lbs_attr = mlir::DenseI64ArrayAttr::get(mlirContext, lbs); - } - } - return lbs_attr; -} - -// Helper class to generate name of fir.global containing component explicit -// default value for objects, and initial procedure target for procedure pointer -// components. -static mlir::FlatSymbolRefAttr gatherComponentInit( - mlir::Location loc, Fortran::lower::AbstractConverter &converter, - const Fortran::semantics::Symbol &sym, fir::RecordType derivedType) { - mlir::MLIRContext *mlirContext = &converter.getMLIRContext(); - // Return procedure target mangled name for procedure pointer components. - if (const auto *procPtr = - sym.detailsIf<Fortran::semantics::ProcEntityDetails>()) { - if (std::optional<const Fortran::semantics::Symbol *> maybeInitSym = - procPtr->init()) { - // So far, do not make distinction between p => NULL() and p without init, - // f18 always initialize pointers to NULL anyway. - if (!*maybeInitSym) - return {}; - return mlir::FlatSymbolRefAttr::get(mlirContext, - converter.mangleName(**maybeInitSym)); - } - } - - const auto *objDetails = - sym.detailsIf<Fortran::semantics::ObjectEntityDetails>(); - if (!objDetails || !objDetails->init().has_value()) - return {}; - // Object component initial value. Semantic package component object default - // value into compiler generated symbols that are lowered as read-only - // fir.global. Get the name of this global. - std::string name = fir::NameUniquer::getComponentInitName( - derivedType.getName(), toStringRef(sym.name())); - return mlir::FlatSymbolRefAttr::get(mlirContext, name); -} - /// Helper class to generate the runtime type info global data and the /// fir.type_info operations that contain the dipatch tables (if any). /// The type info global data is required to describe the derived type to the @@ -278,14 +213,15 @@ class TypeInfoConverter { parentType = mlir::cast<fir::RecordType>(converter.genType(*parent)); fir::FirOpBuilder &builder = converter.getFirOpBuilder(); - fir::TypeInfoOp dt; - mlir::OpBuilder::InsertPoint insertPointIfCreated; - std::tie(dt, insertPointIfCreated) = - builder.createTypeInfoOp(info.loc, info.type, parentType); - if (!insertPointIfCreated.isSet()) - return; // fir.type_info was already built in a previous call. - - // Set init, destroy, and nofinal attributes. + mlir::ModuleOp module = builder.getModule(); + fir::TypeInfoOp dt = + module.lookupSymbol<fir::TypeInfoOp>(info.type.getName()); + if (dt) + return; // Already created. + auto insertPt = builder.saveInsertionPoint(); + builder.setInsertionPoint(module.getBody(), module.getBody()->end()); + dt = builder.create<fir::TypeInfoOp>(info.loc, info.type, parentType); + if (!info.typeSpec.HasDefaultInitialization(/*ignoreAllocatable=*/false, /*ignorePointer=*/false)) dt->setAttr(dt.getNoInitAttrName(), builder.getUnitAttr()); @@ -294,12 +230,13 @@ class TypeInfoConverter { if (!Fortran::semantics::MayRequireFinalization(info.typeSpec)) dt->setAttr(dt.getNoFinalAttrName(), builder.getUnitAttr()); - const Fortran::semantics::Scope &derivedScope = - DEREF(info.typeSpec.GetScope()); + const Fortran::semantics::Scope *scope = info.typeSpec.scope(); + if (!scope) + scope = info.typeSpec.typeSymbol().scope(); + assert(scope && "failed to find type scope"); - // Fill binding table region if the derived type has bindings. Fortran::semantics::SymbolVector bindings = - Fortran::semantics::CollectBindings(derivedScope); + Fortran::semantics::CollectBindings(*scope); if (!bindings.empty()) { builder.createBlock(&dt.getDispatchTable()); for (const Fortran::semantics::SymbolRef &binding : bindings) { @@ -315,33 +252,7 @@ class TypeInfoConverter { } builder.create<fir::FirEndOp>(info.loc); } - // Gather info about components that is not reflected in fir.type and may be - // needed later: component initial values and array component non default - // lower bounds. - mlir::Block *componentInfo = nullptr; - for (const auto &componentName : - info.typeSpec.typeSymbol() - .get<Fortran::semantics::DerivedTypeDetails>() - .componentNames()) { - auto scopeIter = derivedScope.find(componentName); - assert(scopeIter != derivedScope.cend() && - "failed to find derived type component symbol"); - const Fortran::semantics::Symbol &component = scopeIter->second.get(); - mlir::FlatSymbolRefAttr init_val = - gatherComponentInit(info.loc, converter, component, info.type); - mlir::DenseI64ArrayAttr lbs = gatherComponentNonDefaultLowerBounds( - info.loc, builder.getContext(), component); - if (init_val || lbs) { - if (!componentInfo) - componentInfo = builder.createBlock(&dt.getComponentInfo()); - auto compName = mlir::StringAttr::get(builder.getContext(), - toStringRef(component.name())); - builder.create<fir::DTComponentOp>(info.loc, compName, lbs, init_val); - } - } - if (componentInfo) - builder.create<fir::FirEndOp>(info.loc); - builder.restoreInsertionPoint(insertPointIfCreated); + builder.restoreInsertionPoint(insertPt); } /// Store the front-end data that will be required to generate the type info diff --git a/flang/lib/Optimizer/Builder/FIRBuilder.cpp b/flang/lib/Optimizer/Builder/FIRBuilder.cpp index 2ea302d188018..4a1772ac91e6f 100644 --- a/flang/lib/Optimizer/Builder/FIRBuilder.cpp +++ b/flang/lib/Optimizer/Builder/FIRBuilder.cpp @@ -19,7 +19,6 @@ #include "flang/Optimizer/Dialect/FIRType.h" #include "flang/Optimizer/Support/FatalError.h" #include "flang/Optimizer/Support/InternalNames.h" -#include "flang/Optimizer/Support/Utils.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" #include "mlir/Dialect/OpenACC/OpenACC.h" #include "mlir/Dialect/OpenMP/OpenMPDialect.h" @@ -365,22 +364,6 @@ fir::GlobalOp fir::FirOpBuilder::createGlobal( return glob; } -std::pair<fir::TypeInfoOp, mlir::OpBuilder::InsertPoint> -fir::FirOpBuilder::createTypeInfoOp(mlir::Location loc, - fir::RecordType recordType, - fir::RecordType parentType) { - mlir::ModuleOp module = getModule(); - if (fir::TypeInfoOp typeInfo = - fir::lookupTypeInfoOp(recordType.getName(), module, symbolTable)) - return {typeInfo, InsertPoint{}}; - InsertPoint insertPoint = saveInsertionPoint(); - setInsertionPoint(module.getBody(), module.getBody()->end()); - auto typeInfo = create<fir::TypeInfoOp>(loc, recordType, parentType); - if (symbolTable) - symbolTable->insert(typeInfo); - return {typeInfo, insertPoint}; -} - mlir::Value fir::FirOpBuilder::convertWithSemantics( mlir::Location loc, mlir::Type toTy, mlir::Value val, bool allowCharacterConversion, bool allowRebox) { diff --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp index c3c10967673d6..84711c5406581 100644 --- a/flang/lib/Optimizer/Dialect/FIROps.cpp +++ b/flang/lib/Optimizer/Dialect/FIROps.cpp @@ -1579,7 +1579,6 @@ void fir::TypeInfoOp::build(mlir::OpBuilder &builder, fir::RecordType parentType, llvm::ArrayRef<mlir::NamedAttribute> attrs) { result.addRegion(); - result.addRegion(); result.addAttribute(mlir::SymbolTable::getSymbolAttrName(), builder.getStringAttr(type.getName())); result.addAttribute(getTypeAttrName(result.name), mlir::TypeAttr::get(type)); diff --git a/flang/lib/Optimizer/Support/CMakeLists.txt b/flang/lib/Optimizer/Support/CMakeLists.txt index eb93975c71b7e..55f5718a90b85 100644 --- a/flang/lib/Optimizer/Support/CMakeLists.txt +++ b/flang/lib/Optimizer/Support/CMakeLists.txt @@ -5,7 +5,6 @@ add_flang_library(FIRSupport DataLayout.cpp InitFIR.cpp InternalNames.cpp - Utils.cpp DEPENDS FIROpsIncGen diff --git a/flang/lib/Optimizer/Support/InternalNames.cpp b/flang/lib/Optimizer/Support/InternalNames.cpp index b2e2cd38f48e6..65046ea30252e 100644 --- a/flang/lib/Optimizer/Support/InternalNames.cpp +++ b/flang/lib/Optimizer/Support/InternalNames.cpp @@ -381,15 +381,6 @@ std::string fir::NameUniquer::getTypeDescriptorBindingTableName( return getDerivedTypeObjectName(mangledTypeName, bindingTableSeparator); } -std::string -fir::NameUniquer::getComponentInitName(llvm::StringRef mangledTypeName, - llvm::StringRef componentName) { - - std::string prefix = - getDerivedTypeObjectName(mangledTypeName, componentInitSeparator); - return prefix + "." + componentName.str(); -} - llvm::StringRef fir::NameUniquer::dropTypeConversionMarkers(llvm::StringRef mangledTypeName) { if (mangledTypeName.ends_with(boxprocSuffix)) diff --git a/flang/lib/Optimizer/Support/Utils.cpp b/flang/lib/Optimizer/Support/Utils.cpp deleted file mode 100644 index 5d663e28336c0..0000000000000 --- a/flang/lib/Optimizer/Support/Utils.cpp +++ /dev/null @@ -1,52 +0,0 @@ -//===-- Utils.cpp ---------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ -// -//===----------------------------------------------------------------------===// - -#include "flang/Optimizer/Support/Utils.h" -#include "flang/Optimizer/Dialect/FIROps.h" -#include "flang/Optimizer/Dialect/FIRType.h" -#include "flang/Optimizer/Support/InternalNames.h" - -fir::TypeInfoOp fir::lookupTypeInfoOp(fir::RecordType recordType, - mlir::ModuleOp module, - const mlir::SymbolTable *symbolTable) { - // fir.type_info was created with the mangled name of the derived type. - // It is the same as the name in the related fir.type, except when a pass - // lowered the fir.type (e.g., when lowering fir.boxproc type if the type has - // pointer procedure components), in which case suffix may have been added to - // the fir.type name. Get rid of them when looking up for the fir.type_info. - llvm::StringRef originalMangledTypeName = - fir::NameUniquer::dropTypeConversionMarkers(recordType.getName()); - return fir::lookupTypeInfoOp(originalMangledTypeName, module, symbolTable); -} - -fir::TypeInfoOp fir::lookupTypeInfoOp(llvm::StringRef name, - mlir::ModuleOp module, - const mlir::SymbolTable *symbolTable) { - if (symbolTable) - if (auto typeInfo = symbolTable->lookup<fir::TypeInfoOp>(name)) - return typeInfo; - return module.lookupSymbol<fir::TypeInfoOp>(name); -} - -std::optional<llvm::ArrayRef<int64_t>> fir::getComponentLowerBoundsIfNonDefault( - fir::RecordType recordType, llvm::StringRef component, - mlir::ModuleOp module, const mlir::SymbolTable *symbolTable) { - fir::TypeInfoOp typeInfo = - fir::lookupTypeInfoOp(recordType, module, symbolTable); - if (!typeInfo || typeInfo.getComponentInfo().empty()) - return std::nullopt; - for (auto componentInfo : - typeInfo.getComponentInfo().getOps<fir::DTComponentOp>()) - if (componentInfo.getName() == component) - return componentInfo.getLowerBounds(); - return std::nullopt; -} diff --git a/flang/test/Fir/fir-ops.fir b/flang/test/Fir/fir-ops.fir index b8ae566e87a1f..ecc5c4ecff35d 100644 --- a/flang/test/Fir/fir-ops.fir +++ b/flang/test/Fir/fir-ops.fir @@ -460,13 +460,6 @@ fir.type_info @dispatch_tbl : !fir.type<dispatch_tbl{i:i32}> dispatch_table { // CHECK-LABEL: fir.type_info @test_type_info noinit nodestroy nofinal extends !fir.type<parent{i:i32}> : !fir.type<test_type_info{i:i32,j:f32}> fir.type_info @test_type_info noinit nodestroy nofinal extends !fir.type<parent{i:i32}> : !fir.type<test_type_info{i:i32,j:f32}> -// CHECK-LABEL: fir.type_info @cpinfo : !fir.type<cpinfo{comp_i:!fir.array<10x20xi32>}> component_info { -// CHECK: fir.dt_component "component_info" lbs [2, 3] -// CHECK: } -fir.type_info @cpinfo : !fir.type<cpinfo{comp_i:!fir.array<10x20xi32>}> component_info { - fir.dt_component "component_info" lbs [2, 3] -} - // CHECK-LABEL: func @compare_complex( // CHECK-SAME: [[VAL_151:%.*]]: !fir.complex<16>, [[VAL_152:%.*]]: !fir.complex<16>) { func.func @compare_complex(%a : !fir.complex<16>, %b : !fir.complex<16>) { diff --git a/flang/test/Lower/HLFIR/type-info-components.f90 b/flang/test/Lower/HLFIR/type-info-components.f90 deleted file mode 100644 index ee36f9cf6588f..0000000000000 --- a/flang/test/Lower/HLFIR/type-info-components.f90 +++ /dev/null @@ -1,55 +0,0 @@ -! Test generation of fir.dt_component -! RUN: bbc -emit-hlfir %s -o - | FileCheck %s -subroutine test_1(x) - integer, save, target :: my_target - procedure() :: my_proc - type :: sometype - integer :: i(-1:8) = 42 - integer :: j(1:8) - integer, allocatable :: alloc(:) - integer, pointer :: p => my_target - integer, pointer :: p2 => NULL() - integer, pointer :: p3 - procedure(), pointer, nopass :: proc_p => my_proc - procedure(), pointer, nopass :: proc_p2 => NULL() - procedure(), pointer, nopass :: proc_p3 - end type - type(sometype) :: x -end subroutine -! CHECK-LABEL: fir.type_info @_QFtest_1Tsometype -! CHECK-SAME component_info { -! CHECK: fir.dt_component "i" lbs [-1] init @_QFtest_1E.di.sometype.i -! CHECK-NOT: fir.dt_component "j" -! CHECK: fir.dt_component "p" init @_QFtest_1E.di.sometype.p -! CHECK: fir.dt_component "p2" init @_QFtest_1E.di.sometype.p2 -! CHECK: fir.dt_component "proc_p" init @_QPmy_proc -! CHECK: } - -subroutine test_nesting(x) - type some_sub_type - integer :: i = 42 - end type - type sometype2 - type(some_sub_type) :: nested - end type - type(sometype2) :: x -end subroutine -! CHECK-LABEL: fir.type_info @_QFtest_nestingTsome_sub_type -! CHECK-SAME component_info { -! CHECK: fir.dt_component "i" init @_QFtest_nestingE.di.some_sub_type.i -! CHECK: } - -! CHECK: fir.type_info @_QFtest_nestingTsometype2 -! CHECK-NOT: fir.dt_component - - -subroutine data_like(x) - type sometype3 - integer :: i/42/ - end type - type(sometype3) :: x -end subroutine -! CHECK-LABEL: fir.type_info @_QFdata_likeTsometype3 -! CHECK-SAME component_info { -! CHECK: fir.dt_component "i" init @_QFdata_likeE.di.sometype3.i -! CHECK: } _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits