llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-hlsl Author: Helena Kotas (hekota) <details> <summary>Changes</summary> Introduces `__builtin_hlsl_buffer_update_counter` clang buildin that is used to implement the `IncrementCounter` and `DecrementCounter` methods on `RWStructuredBuffer` and `RasterizerOrderedStructuredBuffer` (see Note). The builtin is translated to LLVM intrisic `llvm.dx.bufferUpdateCounter` or `llvm.spv.bufferUpdateCounter`. Introduces `BuiltinTypeMethodBuilder` helper in `HLSLExternalSemaSource` that enables adding methods to builtin types using builder pattern like this: ``` BuiltinTypeMethodBuilder(Sema, RecordBuilder, "MethodName", ReturnType) .addParam("param_name", Type, InOutModifier) .callBuiltin("buildin_name", { BuiltinParams }) .finalizeMethod(); ``` Fixes #<!-- -->113513 [First version](llvm/llvm-project#<!-- -->114148) of this PR was reverted because of build break. --- Patch is 46.65 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/117608.diff 15 Files Affected: - (modified) clang/include/clang/Basic/Builtins.td (+6-1) - (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+6) - (modified) clang/lib/CodeGen/CGBuiltin.cpp (+9) - (modified) clang/lib/CodeGen/CGHLSLRuntime.h (+1) - (modified) clang/lib/Sema/HLSLExternalSemaSource.cpp (+321-93) - (modified) clang/lib/Sema/SemaExpr.cpp (+3) - (modified) clang/lib/Sema/SemaHLSL.cpp (+54) - (modified) clang/test/AST/HLSL/RWStructuredBuffer-AST.hlsl (+26) - (added) clang/test/CodeGenHLSL/builtins/StructuredBuffers-methods-lib.hlsl (+25) - (added) clang/test/CodeGenHLSL/builtins/StructuredBuffers-methods-ps.hlsl (+28) - (added) clang/test/SemaHLSL/BuiltIns/buffer_update_counter-errors.hlsl (+48) - (modified) llvm/include/llvm/IR/IntrinsicsDirectX.td (+1-1) - (modified) llvm/include/llvm/IR/IntrinsicsSPIRV.td (+5) - (modified) llvm/lib/Target/DirectX/DXILOpLowering.cpp (+1-1) - (renamed) llvm/test/CodeGen/DirectX/bufferUpdateCounter.ll (+3-3) ``````````diff diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 83c90b3d6e681b..eaff744924805e 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4882,7 +4882,6 @@ def HLSLSaturate : LangBuiltin<"HLSL_LANG"> { let Prototype = "void(...)"; } - def HLSLSelect : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_select"]; let Attributes = [NoThrow, Const]; @@ -4907,6 +4906,12 @@ def HLSLRadians : LangBuiltin<"HLSL_LANG"> { let Prototype = "void(...)"; } +def HLSLBufferUpdateCounter : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_buffer_update_counter"]; + let Attributes = [NoThrow]; + let Prototype = "uint32_t(...)"; +} + def HLSLSplitDouble: LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_elementwise_splitdouble"]; let Attributes = [NoThrow, Const]; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 6ff24c2bc8faad..834e588c18e376 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7287,6 +7287,8 @@ def err_typecheck_illegal_increment_decrement : Error< "cannot %select{decrement|increment}1 value of type %0">; def err_typecheck_expect_int : Error< "used type %0 where integer is required">; +def err_typecheck_expect_hlsl_resource : Error< + "used type %0 where __hlsl_resource_t is required">; def err_typecheck_arithmetic_incomplete_or_sizeless_type : Error< "arithmetic on a pointer to %select{an incomplete|sizeless}0 type %1">; def err_typecheck_pointer_arith_function_type : Error< @@ -12528,6 +12530,10 @@ def warn_attr_min_eq_max: Warning< def err_hlsl_attribute_number_arguments_insufficient_shader_model: Error< "attribute %0 with %1 arguments requires shader model %2 or greater">; +def err_hlsl_expect_arg_const_int_one_or_neg_one: Error< + "argument %0 must be constant integer 1 or -1">; +def err_invalid_hlsl_resource_type: Error< + "invalid __hlsl_resource_t type attributes">; // Layout randomization diagnostics. def err_non_designated_init_used : Error< diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 91b70b4fdf3d20..f32d5a2f43559a 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -19409,6 +19409,15 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { CGM.getHLSLRuntime().getRadiansIntrinsic(), ArrayRef<Value *>{Op0}, nullptr, "hlsl.radians"); } + case Builtin::BI__builtin_hlsl_buffer_update_counter: { + Value *ResHandle = EmitScalarExpr(E->getArg(0)); + Value *Offset = EmitScalarExpr(E->getArg(1)); + Value *OffsetI8 = Builder.CreateIntCast(Offset, Int8Ty, true); + return Builder.CreateIntrinsic( + /*ReturnType=*/Offset->getType(), + CGM.getHLSLRuntime().getBufferUpdateCounterIntrinsic(), + ArrayRef<Value *>{ResHandle, OffsetI8}, nullptr); + } case Builtin::BI__builtin_hlsl_elementwise_splitdouble: { assert((E->getArg(0)->getType()->hasFloatingRepresentation() && diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index a8e0ed42b79a35..854214d6bc0677 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -102,6 +102,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(UClamp, uclamp) GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromBinding, handle_fromBinding) + GENERATE_HLSL_INTRINSIC_FUNCTION(BufferUpdateCounter, bufferUpdateCounter) //===----------------------------------------------------------------------===// // End of reserved area for HLSL intrinsic getters. diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp index 0f37738b217c6d..886a4c098580ae 100644 --- a/clang/lib/Sema/HLSLExternalSemaSource.cpp +++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -12,7 +12,9 @@ #include "clang/Sema/HLSLExternalSemaSource.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" +#include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/Expr.h" #include "clang/AST/Type.h" #include "clang/Basic/SourceLocation.h" #include "clang/Sema/Lookup.h" @@ -20,36 +22,43 @@ #include "clang/Sema/SemaHLSL.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Frontend/HLSL/HLSLResource.h" +#include "llvm/Support/ErrorHandling.h" #include <functional> using namespace clang; using namespace llvm::hlsl; +static FunctionDecl *lookupBuiltinFunction(Sema &S, StringRef Name); + namespace { struct TemplateParameterListBuilder; struct BuiltinTypeDeclBuilder { + Sema &SemaRef; CXXRecordDecl *Record = nullptr; ClassTemplateDecl *Template = nullptr; ClassTemplateDecl *PrevTemplate = nullptr; NamespaceDecl *HLSLNamespace = nullptr; llvm::StringMap<FieldDecl *> Fields; - BuiltinTypeDeclBuilder(CXXRecordDecl *R) : Record(R) { + BuiltinTypeDeclBuilder(Sema &SemaRef, CXXRecordDecl *R) + : SemaRef(SemaRef), Record(R) { Record->startDefinition(); Template = Record->getDescribedClassTemplate(); } - BuiltinTypeDeclBuilder(Sema &S, NamespaceDecl *Namespace, StringRef Name) - : HLSLNamespace(Namespace) { - ASTContext &AST = S.getASTContext(); + BuiltinTypeDeclBuilder(Sema &SemaRef, NamespaceDecl *Namespace, + StringRef Name) + : SemaRef(SemaRef), HLSLNamespace(Namespace) { + ASTContext &AST = SemaRef.getASTContext(); IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier); - LookupResult Result(S, &II, SourceLocation(), Sema::LookupTagName); + LookupResult Result(SemaRef, &II, SourceLocation(), Sema::LookupTagName); CXXRecordDecl *PrevDecl = nullptr; - if (S.LookupQualifiedName(Result, HLSLNamespace)) { + if (SemaRef.LookupQualifiedName(Result, HLSLNamespace)) { + // Declaration already exists (from precompiled headers) NamedDecl *Found = Result.getFoundDecl(); if (auto *TD = dyn_cast<ClassTemplateDecl>(Found)) { PrevDecl = TD->getTemplatedDecl(); @@ -61,6 +70,7 @@ struct BuiltinTypeDeclBuilder { if (PrevDecl && PrevDecl->isCompleteDefinition()) { Record = PrevDecl; + Template = PrevTemplate; return; } @@ -84,8 +94,7 @@ struct BuiltinTypeDeclBuilder { BuiltinTypeDeclBuilder & addMemberVariable(StringRef Name, QualType Type, llvm::ArrayRef<Attr *> Attrs, AccessSpecifier Access = AccessSpecifier::AS_private) { - if (Record->isCompleteDefinition()) - return *this; + assert(!Record->isCompleteDefinition() && "record is already complete"); assert(Record->isBeingDefined() && "Definition must be started before adding members!"); ASTContext &AST = Record->getASTContext(); @@ -109,22 +118,16 @@ struct BuiltinTypeDeclBuilder { } BuiltinTypeDeclBuilder & - addHandleMember(Sema &S, ResourceClass RC, ResourceKind RK, bool IsROV, - bool RawBuffer, + addHandleMember(ResourceClass RC, ResourceKind RK, bool IsROV, bool RawBuffer, AccessSpecifier Access = AccessSpecifier::AS_private) { - if (Record->isCompleteDefinition()) - return *this; + assert(!Record->isCompleteDefinition() && "record is already complete"); - ASTContext &Ctx = S.getASTContext(); + ASTContext &Ctx = SemaRef.getASTContext(); TypeSourceInfo *ElementTypeInfo = nullptr; QualType ElemTy = Ctx.Char8Ty; - if (Template) { - if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>( - Template->getTemplateParameters()->getParam(0))) { - ElemTy = QualType(TTD->getTypeForDecl(), 0); - } - } + if (Template) + ElemTy = getFirstTemplateTypeParam(); ElementTypeInfo = Ctx.getTrivialTypeSourceInfo(ElemTy, SourceLocation()); // add handle member with resource type attributes @@ -137,32 +140,13 @@ struct BuiltinTypeDeclBuilder { ? HLSLContainedTypeAttr::CreateImplicit(Ctx, ElementTypeInfo) : nullptr}; Attr *ResourceAttr = HLSLResourceAttr::CreateImplicit(Ctx, RK); - if (CreateHLSLAttributedResourceType(S, Ctx.HLSLResourceTy, Attrs, + if (CreateHLSLAttributedResourceType(SemaRef, Ctx.HLSLResourceTy, Attrs, AttributedResTy)) addMemberVariable("__handle", AttributedResTy, {ResourceAttr}, Access); return *this; } - static DeclRefExpr *lookupBuiltinFunction(ASTContext &AST, Sema &S, - StringRef Name) { - IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier); - DeclarationNameInfo NameInfo = - DeclarationNameInfo(DeclarationName(&II), SourceLocation()); - LookupResult R(S, NameInfo, Sema::LookupOrdinaryName); - // AllowBuiltinCreation is false but LookupDirect will create - // the builtin when searching the global scope anyways... - S.LookupName(R, S.getCurScope()); - // FIXME: If the builtin function was user-declared in global scope, - // this assert *will* fail. Should this call LookupBuiltin instead? - assert(R.isSingleResult() && - "Since this is a builtin it should always resolve!"); - auto *VD = cast<ValueDecl>(R.getFoundDecl()); - QualType Ty = VD->getType(); - return DeclRefExpr::Create(AST, NestedNameSpecifierLoc(), SourceLocation(), - VD, false, NameInfo, Ty, VK_PRValue); - } - - BuiltinTypeDeclBuilder &addDefaultHandleConstructor(Sema &S) { + BuiltinTypeDeclBuilder &addDefaultHandleConstructor() { if (Record->isCompleteDefinition()) return *this; ASTContext &AST = Record->getASTContext(); @@ -187,25 +171,18 @@ struct BuiltinTypeDeclBuilder { } BuiltinTypeDeclBuilder &addArraySubscriptOperators() { - if (Record->isCompleteDefinition()) - return *this; addArraySubscriptOperator(true); addArraySubscriptOperator(false); return *this; } BuiltinTypeDeclBuilder &addArraySubscriptOperator(bool IsConst) { - if (Record->isCompleteDefinition()) - return *this; + assert(!Record->isCompleteDefinition() && "record is already complete"); ASTContext &AST = Record->getASTContext(); QualType ElemTy = AST.Char8Ty; - if (Template) { - if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>( - Template->getTemplateParameters()->getParam(0))) { - ElemTy = QualType(TTD->getTypeForDecl(), 0); - } - } + if (Template) + ElemTy = getFirstTemplateTypeParam(); QualType ReturnTy = ElemTy; FunctionProtoType::ExtProtoInfo ExtInfo; @@ -271,16 +248,31 @@ struct BuiltinTypeDeclBuilder { return *this; } + FieldDecl *getResourceHandleField() { + auto I = Fields.find("__handle"); + assert(I != Fields.end() && + I->second->getType()->isHLSLAttributedResourceType() && + "record does not have resource handle field"); + return I->second; + } + + QualType getFirstTemplateTypeParam() { + assert(Template && "record it not a template"); + if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>( + Template->getTemplateParameters()->getParam(0))) { + return QualType(TTD->getTypeForDecl(), 0); + } + return QualType(); + } + BuiltinTypeDeclBuilder &startDefinition() { - if (Record->isCompleteDefinition()) - return *this; + assert(!Record->isCompleteDefinition() && "record is already complete"); Record->startDefinition(); return *this; } BuiltinTypeDeclBuilder &completeDefinition() { - if (Record->isCompleteDefinition()) - return *this; + assert(!Record->isCompleteDefinition() && "record is already complete"); assert(Record->isBeingDefined() && "Definition must be started before completing it."); @@ -288,38 +280,47 @@ struct BuiltinTypeDeclBuilder { return *this; } - TemplateParameterListBuilder addTemplateArgumentList(Sema &S); - BuiltinTypeDeclBuilder & - addSimpleTemplateParams(Sema &S, ArrayRef<StringRef> Names, ConceptDecl *CD); - BuiltinTypeDeclBuilder &addConceptSpecializationExpr(Sema &S); + Expr *getConstantIntExpr(int value) { + ASTContext &AST = SemaRef.getASTContext(); + return IntegerLiteral::Create( + AST, llvm::APInt(AST.getTypeSize(AST.IntTy), value, true), AST.IntTy, + SourceLocation()); + } + + TemplateParameterListBuilder addTemplateArgumentList(); + BuiltinTypeDeclBuilder &addSimpleTemplateParams(ArrayRef<StringRef> Names, + ConceptDecl *CD); + + // Builtin types methods + BuiltinTypeDeclBuilder &addIncrementCounterMethod(); + BuiltinTypeDeclBuilder &addDecrementCounterMethod(); }; struct TemplateParameterListBuilder { BuiltinTypeDeclBuilder &Builder; - Sema &S; llvm::SmallVector<NamedDecl *> Params; - TemplateParameterListBuilder(Sema &S, BuiltinTypeDeclBuilder &RB) - : Builder(RB), S(S) {} + TemplateParameterListBuilder(BuiltinTypeDeclBuilder &RB) : Builder(RB) {} ~TemplateParameterListBuilder() { finalizeTemplateArgs(); } TemplateParameterListBuilder & addTypeParameter(StringRef Name, QualType DefaultValue = QualType()) { - if (Builder.Record->isCompleteDefinition()) - return *this; + assert(!Builder.Record->isCompleteDefinition() && + "record is already complete"); + ASTContext &AST = Builder.SemaRef.getASTContext(); unsigned Position = static_cast<unsigned>(Params.size()); auto *Decl = TemplateTypeParmDecl::Create( - S.Context, Builder.Record->getDeclContext(), SourceLocation(), + AST, Builder.Record->getDeclContext(), SourceLocation(), SourceLocation(), /* TemplateDepth */ 0, Position, - &S.Context.Idents.get(Name, tok::TokenKind::identifier), + &AST.Idents.get(Name, tok::TokenKind::identifier), /* Typename */ true, /* ParameterPack */ false, /* HasTypeConstraint*/ false); if (!DefaultValue.isNull()) - Decl->setDefaultArgument( - S.Context, S.getTrivialTemplateArgumentLoc(DefaultValue, QualType(), - SourceLocation())); + Decl->setDefaultArgument(AST, + Builder.SemaRef.getTrivialTemplateArgumentLoc( + DefaultValue, QualType(), SourceLocation())); Params.emplace_back(Decl); return *this; @@ -421,14 +422,14 @@ struct TemplateParameterListBuilder { BuiltinTypeDeclBuilder &finalizeTemplateArgs(ConceptDecl *CD = nullptr) { if (Params.empty()) return Builder; - ConceptSpecializationExpr *CSE = - CD ? constructConceptSpecializationExpr(S, CD) : nullptr; - auto *ParamList = TemplateParameterList::Create(S.Context, SourceLocation(), - SourceLocation(), Params, - SourceLocation(), CSE); + ASTContext &AST = Builder.SemaRef.Context; + ConceptSpecializationExpr *CSE = + CD ? constructConceptSpecializationExpr(Builder.SemaRef, CD) : nullptr; + auto *ParamList = TemplateParameterList::Create( + AST, SourceLocation(), SourceLocation(), Params, SourceLocation(), CSE); Builder.Template = ClassTemplateDecl::Create( - S.Context, Builder.Record->getDeclContext(), SourceLocation(), + AST, Builder.Record->getDeclContext(), SourceLocation(), DeclarationName(Builder.Record->getIdentifier()), ParamList, Builder.Record); @@ -443,26 +444,233 @@ struct TemplateParameterListBuilder { Params.clear(); QualType T = Builder.Template->getInjectedClassNameSpecialization(); - T = S.Context.getInjectedClassNameType(Builder.Record, T); + T = AST.getInjectedClassNameType(Builder.Record, T); return Builder; } }; + +// Builder for methods of builtin types. Allows adding methods to builtin types +// using the builder pattern like this: +// +// BuiltinTypeMethodBuilder(Sema, RecordBuilder, "MethodName", ReturnType) +// .addParam("param_name", Type, InOutModifier) +// .callBuiltin("buildin_name", { BuiltinParams }) +// .finalizeMethod(); +// +// The builder needs to have all of the method parameters before it can create +// a CXXMethodDecl. It collects them in addParam calls and when a first +// method that builds the body is called or when access to 'this` is needed it +// creates the CXXMethodDecl and ParmVarDecls instances. These can then be +// referenced from the body building methods. Destructor or an explicit call to +// finalizeMethod() will complete the method definition. +// +// The callBuiltin helper method passes in the resource handle as the first +// argument of the builtin call. If this is not desired it takes a bool flag to +// disable this. +// +// If the method that is being built has a non-void return type the +// finalizeMethod will create a return statent with the value of the last +// statement (unless the last statement is already a ReturnStmt). +struct BuiltinTypeMethodBuilder { + struct MethodParam { + const IdentifierInfo &NameII; + QualType Ty; + HLSLParamModifierAttr::Spelling Modifier; + MethodParam(const IdentifierInfo &NameII, QualType Ty, + HLSLParamModifierAttr::Spelling Modifier) + : NameII(NameII), Ty(Ty), Modifier(Modifier) {} + }; + + BuiltinTypeDeclBuilder &DeclBuilder; + DeclarationNameInfo NameInfo; + QualType ReturnTy; + CXXMethodDecl *Method; + llvm::SmallVector<MethodParam> Params; + llvm::SmallVector<Stmt *> StmtsList; + +public: + BuiltinTypeMethodBuilder(Sema &S, BuiltinTypeDeclBuilder &DB, StringRef Name, + QualType ReturnTy) + : DeclBuilder(DB), ReturnTy(ReturnTy), Method(nullptr) { + const IdentifierInfo &II = + S.getASTContext().Idents.get(Name, tok::TokenKind::identifier); + NameInfo = DeclarationNameInfo(DeclarationName(&II), SourceLocation()); + } + + BuiltinTypeMethodBuilder &addParam(StringRef Name, QualType Ty, + HLSLParamModifierAttr::Spelling Modifier = + HLSLParamModifierAttr::Keyword_in) { + assert(Method == nullptr && "Cannot add param, method already created"); + llvm_unreachable("not yet implemented"); + } + +private: + void createMethodDecl() { + assert(Method == nullptr && "Method already created"); + + // create method type + ASTContext &AST = DeclBuilder.SemaRef.getASTContext(); + SmallVector<QualType> ParamTypes; + for (MethodParam &MP : Params) + ParamTypes.emplace_back(MP.Ty); + QualType MethodTy = AST.getFunctionType(ReturnTy, ParamTypes, + FunctionProtoType::ExtProtoInfo()); + + // create method decl + auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation()); + Method = + CXXMethodDecl::Create(AST, DeclBuilder.Record, SourceLocation(), + NameInfo, MethodTy, TSInfo, SC_None, false, false, + ConstexprSpecKind::Unspecified, SourceLocation()); + + // create params & set them to the function prototype + SmallVector<ParmVarDecl *> ParmDecls; + auto FnProtoLoc = + Method->getTypeSourceInfo()->getTypeLoc().getAs<FunctionProtoTypeLoc>(); + for (int I = 0, E = Params.size(); I != E; I++) { + MethodParam &MP = Params[I]; + ParmVarDecl *Parm = ParmVarDecl::Create( + AST, Method->getDeclContext(), SourceLocation(), SourceLocation(), + &MP.NameII, MP.Ty, + AST.getTrivialTypeSourceInfo(MP.Ty, SourceLocation()), SC_None, + nullptr); + if (MP.Modifier != HLSLParamModifierAttr::Keyword_in) { + auto *Mod = + HLSLParamModifierAttr::Create(AST, SourceRange(), MP.Modifier); + Parm->addAttr(Mod); + } + ParmDecls.push_back(Parm); + FnProtoLoc.setParam(I, Parm); + } + Method->setParams({ParmDecls}); + } + +public: + ~BuiltinTypeMethodBuilder() { finalizeMethod(); } + + Expr *getResourceHandleExpr() { + // The first statement added to a method or access to 'this' creates the + // declaration. + if (!Method) + createMethodDecl(); + + ASTContext &AST = DeclBuilder.SemaRef.... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/117608 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits