[llvm] [TableGen][NFC] convert TreePatternNode pointers to references (PR #81134)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Feb 8 05:30:02 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-globalisel
Author: Tomas Matheson (tmatheson-arm)
<details>
<summary>Changes</summary>
Almost all uses of `*TreePatternNode` expect it to be non-null. There was the occasional check that it wasn't, which I have removed. Making them references makes it clear that they exist.
This was attempted in 2018 (1b465767d6ca69f4b7201503f5f21e6125fe049a) for `TreePatternNode::getChild()` but that was reverted.
---
Patch is 151.20 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/81134.diff
9 Files Affected:
- (modified) llvm/utils/TableGen/CodeGenDAGPatterns.cpp (+199-201)
- (modified) llvm/utils/TableGen/CodeGenDAGPatterns.h (+15-16)
- (modified) llvm/utils/TableGen/DAGISelEmitter.cpp (+22-21)
- (modified) llvm/utils/TableGen/DAGISelMatcher.cpp (+2-2)
- (modified) llvm/utils/TableGen/DAGISelMatcherEmitter.cpp (+14-12)
- (modified) llvm/utils/TableGen/DAGISelMatcherGen.cpp (+150-157)
- (modified) llvm/utils/TableGen/DAGISelMatcherOpt.cpp (+2-2)
- (modified) llvm/utils/TableGen/FastISelEmitter.cpp (+54-57)
- (modified) llvm/utils/TableGen/GlobalISelEmitter.cpp (+206-216)
``````````diff
diff --git a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp
index f88e25ea1d167..c4d6571be1ad5 100644
--- a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp
+++ b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp
@@ -1412,10 +1412,10 @@ std::string TreePredicateFn::getCodeToRunOnSDNode() const {
// PatternToMatch implementation
//
-static bool isImmAllOnesAllZerosMatch(const TreePatternNode *P) {
- if (!P->isLeaf())
+static bool isImmAllOnesAllZerosMatch(const TreePatternNode &P) {
+ if (!P.isLeaf())
return false;
- DefInit *DI = dyn_cast<DefInit>(P->getLeafValue());
+ DefInit *DI = dyn_cast<DefInit>(P.getLeafValue());
if (!DI)
return false;
@@ -1426,15 +1426,15 @@ static bool isImmAllOnesAllZerosMatch(const TreePatternNode *P) {
/// getPatternSize - Return the 'size' of this pattern. We want to match large
/// patterns before small ones. This is used to determine the size of a
/// pattern.
-static unsigned getPatternSize(const TreePatternNode *P,
+static unsigned getPatternSize(const TreePatternNode &P,
const CodeGenDAGPatterns &CGP) {
unsigned Size = 3; // The node itself.
// If the root node is a ConstantSDNode, increases its size.
// e.g. (set R32:$dst, 0).
- if (P->isLeaf() && isa<IntInit>(P->getLeafValue()))
+ if (P.isLeaf() && isa<IntInit>(P.getLeafValue()))
Size += 2;
- if (const ComplexPattern *AM = P->getComplexPatternInfo(CGP)) {
+ if (const ComplexPattern *AM = P.getComplexPatternInfo(CGP)) {
Size += AM->getComplexity();
// We don't want to count any children twice, so return early.
return Size;
@@ -1442,14 +1442,14 @@ static unsigned getPatternSize(const TreePatternNode *P,
// If this node has some predicate function that must match, it adds to the
// complexity of this node.
- if (!P->getPredicateCalls().empty())
+ if (!P.getPredicateCalls().empty())
++Size;
// Count children in the count if they are also nodes.
- for (unsigned i = 0, e = P->getNumChildren(); i != e; ++i) {
- const TreePatternNode *Child = P->getChild(i);
- if (!Child->isLeaf() && Child->getNumTypes()) {
- const TypeSetByHwMode &T0 = Child->getExtType(0);
+ for (unsigned i = 0, e = P.getNumChildren(); i != e; ++i) {
+ const TreePatternNode &Child = P.getChild(i);
+ if (!Child.isLeaf() && Child.getNumTypes()) {
+ const TypeSetByHwMode &T0 = Child.getExtType(0);
// At this point, all variable type sets should be simple, i.e. only
// have a default mode.
if (T0.getMachineValueType() != MVT::Other) {
@@ -1457,14 +1457,14 @@ static unsigned getPatternSize(const TreePatternNode *P,
continue;
}
}
- if (Child->isLeaf()) {
- if (isa<IntInit>(Child->getLeafValue()))
+ if (Child.isLeaf()) {
+ if (isa<IntInit>(Child.getLeafValue()))
Size += 5; // Matches a ConstantSDNode (+3) and a specific value (+2).
- else if (Child->getComplexPatternInfo(CGP))
+ else if (Child.getComplexPatternInfo(CGP))
Size += getPatternSize(Child, CGP);
else if (isImmAllOnesAllZerosMatch(Child))
Size += 4; // Matches a build_vector(+3) and a predicate (+1).
- else if (!Child->getPredicateCalls().empty())
+ else if (!Child.getPredicateCalls().empty())
++Size;
}
}
@@ -1590,7 +1590,7 @@ SDTypeConstraint::SDTypeConstraint(Record *R, const CodeGenHwModes &CGH) {
/// getOperandNum - Return the node corresponding to operand #OpNo in tree
/// N, and the result number in ResNo.
-static TreePatternNode *getOperandNum(unsigned OpNo, TreePatternNode *N,
+static TreePatternNode &getOperandNum(unsigned OpNo, TreePatternNode &N,
const SDNodeInfo &NodeInfo,
unsigned &ResNo) {
unsigned NumResults = NodeInfo.getNumResults();
@@ -1601,126 +1601,120 @@ static TreePatternNode *getOperandNum(unsigned OpNo, TreePatternNode *N,
OpNo -= NumResults;
- if (OpNo >= N->getNumChildren()) {
+ if (OpNo >= N.getNumChildren()) {
std::string S;
raw_string_ostream OS(S);
OS << "Invalid operand number in type constraint "
<< (OpNo+NumResults) << " ";
- N->print(OS);
+ N.print(OS);
PrintFatalError(S);
}
- return N->getChild(OpNo);
+ return N.getChild(OpNo);
}
/// ApplyTypeConstraint - Given a node in a pattern, apply this type
/// constraint to the nodes operands. This returns true if it makes a
/// change, false otherwise. If a type contradiction is found, flag an error.
-bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N,
+bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode &N,
const SDNodeInfo &NodeInfo,
TreePattern &TP) const {
if (TP.hasError())
return false;
unsigned ResNo = 0; // The result number being referenced.
- TreePatternNode *NodeToApply = getOperandNum(OperandNo, N, NodeInfo, ResNo);
+ TreePatternNode &NodeToApply = getOperandNum(OperandNo, N, NodeInfo, ResNo);
TypeInfer &TI = TP.getInfer();
switch (ConstraintType) {
case SDTCisVT:
// Operand must be a particular type.
- return NodeToApply->UpdateNodeType(ResNo, VVT, TP);
+ return NodeToApply.UpdateNodeType(ResNo, VVT, TP);
case SDTCisPtrTy:
// Operand must be same as target pointer type.
- return NodeToApply->UpdateNodeType(ResNo, MVT::iPTR, TP);
+ return NodeToApply.UpdateNodeType(ResNo, MVT::iPTR, TP);
case SDTCisInt:
// Require it to be one of the legal integer VTs.
- return TI.EnforceInteger(NodeToApply->getExtType(ResNo));
+ return TI.EnforceInteger(NodeToApply.getExtType(ResNo));
case SDTCisFP:
// Require it to be one of the legal fp VTs.
- return TI.EnforceFloatingPoint(NodeToApply->getExtType(ResNo));
+ return TI.EnforceFloatingPoint(NodeToApply.getExtType(ResNo));
case SDTCisVec:
// Require it to be one of the legal vector VTs.
- return TI.EnforceVector(NodeToApply->getExtType(ResNo));
+ return TI.EnforceVector(NodeToApply.getExtType(ResNo));
case SDTCisSameAs: {
unsigned OResNo = 0;
- TreePatternNode *OtherNode =
- getOperandNum(x.SDTCisSameAs_Info.OtherOperandNum, N, NodeInfo, OResNo);
- return (int)NodeToApply->UpdateNodeType(ResNo,
- OtherNode->getExtType(OResNo), TP) |
- (int)OtherNode->UpdateNodeType(OResNo,
- NodeToApply->getExtType(ResNo), TP);
+ TreePatternNode &OtherNode =
+ getOperandNum(x.SDTCisSameAs_Info.OtherOperandNum, N, NodeInfo, OResNo);
+ return (int)NodeToApply.UpdateNodeType(ResNo, OtherNode.getExtType(OResNo),
+ TP) |
+ (int)OtherNode.UpdateNodeType(OResNo, NodeToApply.getExtType(ResNo),
+ TP);
}
case SDTCisVTSmallerThanOp: {
// The NodeToApply must be a leaf node that is a VT. OtherOperandNum must
// have an integer type that is smaller than the VT.
- if (!NodeToApply->isLeaf() ||
- !isa<DefInit>(NodeToApply->getLeafValue()) ||
- !cast<DefInit>(NodeToApply->getLeafValue())->getDef()
- ->isSubClassOf("ValueType")) {
- TP.error(N->getOperator()->getName() + " expects a VT operand!");
+ if (!NodeToApply.isLeaf() || !isa<DefInit>(NodeToApply.getLeafValue()) ||
+ !cast<DefInit>(NodeToApply.getLeafValue())
+ ->getDef()
+ ->isSubClassOf("ValueType")) {
+ TP.error(N.getOperator()->getName() + " expects a VT operand!");
return false;
}
- DefInit *DI = cast<DefInit>(NodeToApply->getLeafValue());
+ DefInit *DI = cast<DefInit>(NodeToApply.getLeafValue());
const CodeGenTarget &T = TP.getDAGPatterns().getTargetInfo();
auto VVT = getValueTypeByHwMode(DI->getDef(), T.getHwModes());
TypeSetByHwMode TypeListTmp(VVT);
unsigned OResNo = 0;
- TreePatternNode *OtherNode =
- getOperandNum(x.SDTCisVTSmallerThanOp_Info.OtherOperandNum, N, NodeInfo,
- OResNo);
+ TreePatternNode &OtherNode = getOperandNum(
+ x.SDTCisVTSmallerThanOp_Info.OtherOperandNum, N, NodeInfo, OResNo);
- return TI.EnforceSmallerThan(TypeListTmp, OtherNode->getExtType(OResNo),
+ return TI.EnforceSmallerThan(TypeListTmp, OtherNode.getExtType(OResNo),
/*SmallIsVT*/ true);
}
case SDTCisOpSmallerThanOp: {
unsigned BResNo = 0;
- TreePatternNode *BigOperand =
- getOperandNum(x.SDTCisOpSmallerThanOp_Info.BigOperandNum, N, NodeInfo,
- BResNo);
- return TI.EnforceSmallerThan(NodeToApply->getExtType(ResNo),
- BigOperand->getExtType(BResNo));
+ TreePatternNode &BigOperand = getOperandNum(
+ x.SDTCisOpSmallerThanOp_Info.BigOperandNum, N, NodeInfo, BResNo);
+ return TI.EnforceSmallerThan(NodeToApply.getExtType(ResNo),
+ BigOperand.getExtType(BResNo));
}
case SDTCisEltOfVec: {
unsigned VResNo = 0;
- TreePatternNode *VecOperand =
- getOperandNum(x.SDTCisEltOfVec_Info.OtherOperandNum, N, NodeInfo,
- VResNo);
+ TreePatternNode &VecOperand = getOperandNum(
+ x.SDTCisEltOfVec_Info.OtherOperandNum, N, NodeInfo, VResNo);
// Filter vector types out of VecOperand that don't have the right element
// type.
- return TI.EnforceVectorEltTypeIs(VecOperand->getExtType(VResNo),
- NodeToApply->getExtType(ResNo));
+ return TI.EnforceVectorEltTypeIs(VecOperand.getExtType(VResNo),
+ NodeToApply.getExtType(ResNo));
}
case SDTCisSubVecOfVec: {
unsigned VResNo = 0;
- TreePatternNode *BigVecOperand =
- getOperandNum(x.SDTCisSubVecOfVec_Info.OtherOperandNum, N, NodeInfo,
- VResNo);
+ TreePatternNode &BigVecOperand = getOperandNum(
+ x.SDTCisSubVecOfVec_Info.OtherOperandNum, N, NodeInfo, VResNo);
// Filter vector types out of BigVecOperand that don't have the
// right subvector type.
- return TI.EnforceVectorSubVectorTypeIs(BigVecOperand->getExtType(VResNo),
- NodeToApply->getExtType(ResNo));
+ return TI.EnforceVectorSubVectorTypeIs(BigVecOperand.getExtType(VResNo),
+ NodeToApply.getExtType(ResNo));
}
case SDTCVecEltisVT: {
- return TI.EnforceVectorEltTypeIs(NodeToApply->getExtType(ResNo), VVT);
+ return TI.EnforceVectorEltTypeIs(NodeToApply.getExtType(ResNo), VVT);
}
case SDTCisSameNumEltsAs: {
unsigned OResNo = 0;
- TreePatternNode *OtherNode =
- getOperandNum(x.SDTCisSameNumEltsAs_Info.OtherOperandNum,
- N, NodeInfo, OResNo);
- return TI.EnforceSameNumElts(OtherNode->getExtType(OResNo),
- NodeToApply->getExtType(ResNo));
+ TreePatternNode &OtherNode = getOperandNum(
+ x.SDTCisSameNumEltsAs_Info.OtherOperandNum, N, NodeInfo, OResNo);
+ return TI.EnforceSameNumElts(OtherNode.getExtType(OResNo),
+ NodeToApply.getExtType(ResNo));
}
case SDTCisSameSizeAs: {
unsigned OResNo = 0;
- TreePatternNode *OtherNode =
- getOperandNum(x.SDTCisSameSizeAs_Info.OtherOperandNum,
- N, NodeInfo, OResNo);
- return TI.EnforceSameSize(OtherNode->getExtType(OResNo),
- NodeToApply->getExtType(ResNo));
+ TreePatternNode &OtherNode = getOperandNum(
+ x.SDTCisSameSizeAs_Info.OtherOperandNum, N, NodeInfo, OResNo);
+ return TI.EnforceSameSize(OtherNode.getExtType(OResNo),
+ NodeToApply.getExtType(ResNo));
}
}
llvm_unreachable("Invalid ConstraintType!");
@@ -1766,7 +1760,7 @@ bool TreePatternNode::ContainsUnresolvedType(TreePattern &TP) const {
if (!TP.getInfer().isConcrete(Types[i], true))
return true;
for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
- if (getChild(i)->ContainsUnresolvedType(TP))
+ if (getChild(i).ContainsUnresolvedType(TP))
return true;
return false;
}
@@ -1943,7 +1937,7 @@ void TreePatternNode::print(raw_ostream &OS) const {
ListSeparator LS;
for (unsigned i = 0, e = getNumChildren(); i != e; ++i) {
OS << LS;
- getChild(i)->print(OS);
+ getChild(i).print(OS);
}
}
OS << ")";
@@ -1974,36 +1968,37 @@ void TreePatternNode::dump() const {
/// the assigned name is present in the dependent variable set, then
/// the assigned name is considered significant and the node is
/// isomorphic if the names match.
-bool TreePatternNode::isIsomorphicTo(const TreePatternNode *N,
+bool TreePatternNode::isIsomorphicTo(const TreePatternNode &N,
const MultipleUseVarSet &DepVars) const {
- if (N == this) return true;
- if (N->isLeaf() != isLeaf())
+ if (&N == this)
+ return true;
+ if (N.isLeaf() != isLeaf())
return false;
// Check operator of non-leaves early since it can be cheaper than checking
// types.
if (!isLeaf())
- if (N->getOperator() != getOperator() ||
- N->getNumChildren() != getNumChildren())
+ if (N.getOperator() != getOperator() ||
+ N.getNumChildren() != getNumChildren())
return false;
- if (getExtTypes() != N->getExtTypes() ||
- getPredicateCalls() != N->getPredicateCalls() ||
- getTransformFn() != N->getTransformFn())
+ if (getExtTypes() != N.getExtTypes() ||
+ getPredicateCalls() != N.getPredicateCalls() ||
+ getTransformFn() != N.getTransformFn())
return false;
if (isLeaf()) {
if (DefInit *DI = dyn_cast<DefInit>(getLeafValue())) {
- if (DefInit *NDI = dyn_cast<DefInit>(N->getLeafValue())) {
+ if (DefInit *NDI = dyn_cast<DefInit>(N.getLeafValue())) {
return ((DI->getDef() == NDI->getDef()) &&
- (!DepVars.contains(getName()) || getName() == N->getName()));
+ (!DepVars.contains(getName()) || getName() == N.getName()));
}
}
- return getLeafValue() == N->getLeafValue();
+ return getLeafValue() == N.getLeafValue();
}
for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
- if (!getChild(i)->isIsomorphicTo(N->getChild(i), DepVars))
+ if (!getChild(i).isIsomorphicTo(N.getChild(i), DepVars))
return false;
return true;
}
@@ -2018,7 +2013,7 @@ TreePatternNodePtr TreePatternNode::clone() const {
std::vector<TreePatternNodePtr> CChildren;
CChildren.reserve(Children.size());
for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
- CChildren.push_back(getChild(i)->clone());
+ CChildren.push_back(getChild(i).clone());
New = makeIntrusiveRefCnt<TreePatternNode>(
getOperator(), std::move(CChildren), getNumTypes());
}
@@ -2037,7 +2032,7 @@ void TreePatternNode::RemoveAllTypes() {
std::fill(Types.begin(), Types.end(), TypeSetByHwMode());
if (isLeaf()) return;
for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
- getChild(i)->RemoveAllTypes();
+ getChild(i).RemoveAllTypes();
}
@@ -2048,23 +2043,23 @@ void TreePatternNode::SubstituteFormalArguments(
if (isLeaf()) return;
for (unsigned i = 0, e = getNumChildren(); i != e; ++i) {
- TreePatternNode *Child = getChild(i);
- if (Child->isLeaf()) {
- Init *Val = Child->getLeafValue();
+ TreePatternNode &Child = getChild(i);
+ if (Child.isLeaf()) {
+ Init *Val = Child.getLeafValue();
// Note that, when substituting into an output pattern, Val might be an
// UnsetInit.
if (isa<UnsetInit>(Val) || (isa<DefInit>(Val) &&
cast<DefInit>(Val)->getDef()->getName() == "node")) {
// We found a use of a formal argument, replace it with its value.
- TreePatternNodePtr NewChild = ArgMap[Child->getName()];
+ TreePatternNodePtr NewChild = ArgMap[Child.getName()];
assert(NewChild && "Couldn't find formal argument!");
- assert((Child->getPredicateCalls().empty() ||
- NewChild->getPredicateCalls() == Child->getPredicateCalls()) &&
+ assert((Child.getPredicateCalls().empty() ||
+ NewChild->getPredicateCalls() == Child.getPredicateCalls()) &&
"Non-empty child predicate clobbered!");
setChild(i, std::move(NewChild));
}
} else {
- getChild(i)->SubstituteFormalArguments(ArgMap);
+ getChild(i).SubstituteFormalArguments(ArgMap);
}
}
}
@@ -2341,7 +2336,7 @@ getIntrinsicInfo(const CodeGenDAGPatterns &CDP) const {
getOperator() != CDP.get_intrinsic_wo_chain_sdnode())
return nullptr;
- unsigned IID = cast<IntInit>(getChild(0)->getLeafValue())->getValue();
+ unsigned IID = cast<IntInit>(getChild(0).getLeafValue())->getValue();
return &CDP.getIntrinsicInfo(IID);
}
@@ -2416,7 +2411,7 @@ bool TreePatternNode::TreeHasProperty(SDNP Property,
if (NodeHasProperty(Property, CGP))
return true;
for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
- if (getChild(i)->TreeHasProperty(Property, CGP))
+ if (getChild(i).TreeHasProperty(Property, CGP))
return true;
return false;
}
@@ -2430,11 +2425,11 @@ TreePatternNode::isCommutativeIntrinsic(const CodeGenDAGPatterns &CDP) const {
return false;
}
-static bool isOperandClass(const TreePatternNode *N, StringRef Class) {
- if (!N->isLeaf())
- return N->getOperator()->isSubClassOf(Class);
+static bool isOperandClass(const TreePatternNode &N, StringRef Class) {
+ if (!N.isLeaf())
+ return N.getOperator()->isSubClassOf(Class);
- DefInit *DI = dyn_cast<DefInit>(N->getLeafValue());
+ DefInit *DI = dyn_cast<DefInit>(N.getLeafValue());
if (DI && DI->getDef()->isSubClassOf(Class))
return true;
@@ -2528,15 +2523,15 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
}
// Apply type info to the intrinsic ID.
- MadeChange |= getChild(0)->UpdateNodeType(0, MVT::iPTR, TP);
+ MadeChange |= getChild(0).UpdateNodeType(0, MVT::iPTR, TP);
for (unsigned i = 0, e = getNumChildren()-1; i != e; ++i) {
- MadeChange |= getChild(i+1)->ApplyTypeConstraints(TP, NotRegisters);
+ MadeChange |= getChild(i + 1).ApplyTypeConstraints(TP, NotRegisters);
MVT::SimpleValueType OpVT =
getValueType(Int->IS.ParamTys[i]->getValueAsDef("VT"));
- assert(getChild(i + 1)->getNumTypes() == 1 && "Unhandled case");
- MadeChange |= getChild(i + 1)->UpdateNodeType(0, OpVT, TP);
+ assert(getChild(i + 1).getNumTypes() == 1 && "Unhandled case");
+ MadeChange |= getChild(i + 1).UpdateNodeType(0, OpVT, TP);
}
return MadeChange;
}
@@ -2554,8 +2549,8 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
bool MadeChange = false;
for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
- MadeChange |= getChild(i)->ApplyTypeConstraints(TP, NotRegisters);
- MadeChange |= NI.ApplyTypeConstraints(this, TP);
+ MadeChange |= getChild(i).ApplyTypeConstraints(TP, NotRegisters);
+ MadeChange |= NI.ApplyTypeConstraints(*this, TP);
return MadeChange;
}
@@ -2590,9 +2585,9 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
// If this is an INSERT_SUBREG, constrain the source and destination VTs to
// be the same.
if (getOperator()->getName() == "INSERT_SUBREG") {
- assert(getChild(0)->getNumTypes() == 1 && "FIXME: Unhandled");
- MadeChange |= UpdateNodeType(0, getChild(0)->getExtType(0), TP);
- MadeChange |= getChild(0)->UpdateNodeType(0, getExtType(0), TP);
+ assert(getChild(0).getNumTypes() == 1 && "FIXME: Unhandled");
+ MadeChange |= UpdateNodeType(0, getChild(0).getExtType(0), TP);
+ MadeChange |= getChild(0).UpdateNodeType(0, getExtType(0), TP);
} else if (getOperator()->getName() == "REG_SEQUENCE") {
// We need to do extra, custom typechecking for REG_SEQUENCE since it is
// variadic.
@@ -2614,7 +2609,7 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
}
for (unsigned I = 1; I < NChild; I += 2) {
- TreePatternNode *SubIdxChild = getChild(I + 1);
+ ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/81134
More information about the llvm-commits
mailing list