[llvm] r346322 - Add support for llvm.is.constant intrinsic (PR4898)
James Y Knight via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 7 07:24:13 PST 2018
Author: jyknight
Date: Wed Nov 7 07:24:12 2018
New Revision: 346322
URL: http://llvm.org/viewvc/llvm-project?rev=346322&view=rev
Log:
Add support for llvm.is.constant intrinsic (PR4898)
This adds the llvm-side support for post-inlining evaluation of the
__builtin_constant_p GCC intrinsic.
Also fixed SCCPSolver::visitCallSite to not blow up when seeing a call
to a function where canConstantFoldTo returns true, and one of the
arguments is a struct.
Updated from patch initially by Janusz Sobczak.
Differential Revision: https://reviews.llvm.org/D4276
Added:
llvm/trunk/test/CodeGen/Generic/is-constant.ll
llvm/trunk/test/CodeGen/X86/is-constant.ll
Modified:
llvm/trunk/docs/LangRef.rst
llvm/trunk/include/llvm/Analysis/TargetTransformInfoImpl.h
llvm/trunk/include/llvm/IR/Intrinsics.td
llvm/trunk/lib/Analysis/ConstantFolding.cpp
llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp
llvm/trunk/lib/CodeGen/GlobalISel/IRTranslator.cpp
llvm/trunk/lib/CodeGen/SelectionDAG/FastISel.cpp
llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
llvm/trunk/lib/Transforms/Scalar/SCCP.cpp
llvm/trunk/test/Transforms/SCCP/ipsccp-basic.ll
Modified: llvm/trunk/docs/LangRef.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/LangRef.rst?rev=346322&r1=346321&r2=346322&view=diff
==============================================================================
--- llvm/trunk/docs/LangRef.rst (original)
+++ llvm/trunk/docs/LangRef.rst Wed Nov 7 07:24:12 2018
@@ -15417,6 +15417,51 @@ Semantics:
This intrinsic actually does nothing, but optimizers must assume that it
has externally observable side effects.
+'``llvm.is.constant.*``' Intrinsic
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+This is an overloaded intrinsic. You can use llvm.is.constant with any argument type.
+
+::
+
+ declare i1 @llvm.is.constant.i32(i32 %operand) nounwind readnone
+ declare i1 @llvm.is.constant.f32(float %operand) nounwind readnone
+ declare i1 @llvm.is.constant.TYPENAME(TYPE %operand) nounwind readnone
+
+Overview:
+"""""""""
+
+The '``llvm.is.constant``' intrinsic will return true if the argument
+is known to be a manifest compile-time constant. It is guaranteed to
+fold to either true or false before generating machine code.
+
+Semantics:
+""""""""""
+
+This intrinsic generates no code. If its argument is known to be a
+manifest compile-time constant value, then the intrinsic will be
+converted to a constant true value. Otherwise, it will be converted to
+a constant false value.
+
+In particular, note that if the argument is a constant expression
+which refers to a global (the address of which _is_ a constant, but
+not manifest during the compile), then the intrinsic evaluates to
+false.
+
+The result also intentionally depends on the result of optimization
+passes -- e.g., the result can change depending on whether a
+function gets inlined or not. A function's parameters are
+obviously not constant. However, a call like
+``llvm.is.constant.i32(i32 %param)`` *can* return true after the
+function is inlined, if the value passed to the function parameter was
+a constant.
+
+On the other hand, if constant folding is not run, it will never
+evaluate to true, even in simple cases.
+
Stack Map Intrinsics
--------------------
Modified: llvm/trunk/include/llvm/Analysis/TargetTransformInfoImpl.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/TargetTransformInfoImpl.h?rev=346322&r1=346321&r2=346322&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Analysis/TargetTransformInfoImpl.h (original)
+++ llvm/trunk/include/llvm/Analysis/TargetTransformInfoImpl.h Wed Nov 7 07:24:12 2018
@@ -160,6 +160,7 @@ public:
case Intrinsic::invariant_end:
case Intrinsic::launder_invariant_group:
case Intrinsic::strip_invariant_group:
+ case Intrinsic::is_constant:
case Intrinsic::lifetime_start:
case Intrinsic::lifetime_end:
case Intrinsic::objectsize:
Modified: llvm/trunk/include/llvm/IR/Intrinsics.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Intrinsics.td?rev=346322&r1=346321&r2=346322&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/Intrinsics.td (original)
+++ llvm/trunk/include/llvm/IR/Intrinsics.td Wed Nov 7 07:24:12 2018
@@ -900,6 +900,10 @@ def int_convert_from_fp16 : Intrinsic<[l
def int_clear_cache : Intrinsic<[], [llvm_ptr_ty, llvm_ptr_ty],
[], "llvm.clear_cache">;
+// Intrinsic to detect whether its argument is a constant.
+def int_is_constant : Intrinsic<[llvm_i1_ty], [llvm_any_ty], [IntrNoMem], "llvm.is.constant">;
+
+
//===-------------------------- Masked Intrinsics -------------------------===//
//
def int_masked_store : Intrinsic<[], [llvm_anyvector_ty,
Modified: llvm/trunk/lib/Analysis/ConstantFolding.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ConstantFolding.cpp?rev=346322&r1=346321&r2=346322&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/ConstantFolding.cpp (original)
+++ llvm/trunk/lib/Analysis/ConstantFolding.cpp Wed Nov 7 07:24:12 2018
@@ -1426,6 +1426,7 @@ bool llvm::canConstantFoldCallTo(Immutab
case Intrinsic::x86_avx512_vcvtsd2usi64:
case Intrinsic::x86_avx512_cvttsd2usi:
case Intrinsic::x86_avx512_cvttsd2usi64:
+ case Intrinsic::is_constant:
return true;
default:
return false;
@@ -1600,11 +1601,32 @@ double getValueAsDouble(ConstantFP *Op)
return APF.convertToDouble();
}
+static bool isManifestConstant(const Constant *c) {
+ if (isa<ConstantData>(c)) {
+ return true;
+ } else if (isa<ConstantAggregate>(c) || isa<ConstantExpr>(c)) {
+ for (const Value *subc : c->operand_values()) {
+ if (!isManifestConstant(cast<Constant>(subc)))
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
Constant *ConstantFoldScalarCall(StringRef Name, unsigned IntrinsicID, Type *Ty,
ArrayRef<Constant *> Operands,
const TargetLibraryInfo *TLI,
ImmutableCallSite CS) {
if (Operands.size() == 1) {
+ if (IntrinsicID == Intrinsic::is_constant) {
+ // We know we have a "Constant" argument. But we want to only
+ // return true for manifest constants, not those that depend on
+ // constants with unknowable values, e.g. GlobalValue or BlockAddress.
+ if (isManifestConstant(Operands[0]))
+ return ConstantInt::getTrue(Ty->getContext());
+ return nullptr;
+ }
if (isa<UndefValue>(Operands[0])) {
// cosine(arg) is between -1 and 1. cosine(invalid arg) is NaN
if (IntrinsicID == Intrinsic::cos)
Modified: llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp?rev=346322&r1=346321&r2=346322&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp (original)
+++ llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp Wed Nov 7 07:24:12 2018
@@ -321,6 +321,24 @@ class TypePromotionTransaction;
}
private:
+ template <typename F>
+ void resetIteratorIfInvalidatedWhileCalling(BasicBlock *BB, F f) {
+ // Substituting can cause recursive simplifications, which can invalidate
+ // our iterator. Use a WeakTrackingVH to hold onto it in case this
+ // happens.
+ Value *CurValue = &*CurInstIterator;
+ WeakTrackingVH IterHandle(CurValue);
+
+ f();
+
+ // If the iterator instruction was recursively deleted, start over at the
+ // start of the block.
+ if (IterHandle != CurValue) {
+ CurInstIterator = BB->begin();
+ SunkAddrs.clear();
+ }
+ }
+
bool eliminateFallThrough(Function &F);
bool eliminateMostlyEmptyBlocks(Function &F);
BasicBlock *findDestBlockOfMergeableEmptyBlock(BasicBlock *BB);
@@ -1690,21 +1708,18 @@ bool CodeGenPrepare::optimizeCallInst(Ca
// Lower all uses of llvm.objectsize.*
ConstantInt *RetVal =
lowerObjectSizeCall(II, *DL, TLInfo, /*MustSucceed=*/true);
- // Substituting this can cause recursive simplifications, which can
- // invalidate our iterator. Use a WeakTrackingVH to hold onto it in case
- // this
- // happens.
- Value *CurValue = &*CurInstIterator;
- WeakTrackingVH IterHandle(CurValue);
- replaceAndRecursivelySimplify(CI, RetVal, TLInfo, nullptr);
-
- // If the iterator instruction was recursively deleted, start over at the
- // start of the block.
- if (IterHandle != CurValue) {
- CurInstIterator = BB->begin();
- SunkAddrs.clear();
- }
+ resetIteratorIfInvalidatedWhileCalling(BB, [&]() {
+ replaceAndRecursivelySimplify(CI, RetVal, TLInfo, nullptr);
+ });
+ return true;
+ }
+ case Intrinsic::is_constant: {
+ // If is_constant hasn't folded away yet, lower it to false now.
+ Constant *RetVal = ConstantInt::get(II->getType(), 0);
+ resetIteratorIfInvalidatedWhileCalling(BB, [&]() {
+ replaceAndRecursivelySimplify(CI, RetVal, TLInfo, nullptr);
+ });
return true;
}
case Intrinsic::aarch64_stlxr:
Modified: llvm/trunk/lib/CodeGen/GlobalISel/IRTranslator.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/GlobalISel/IRTranslator.cpp?rev=346322&r1=346321&r2=346322&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/GlobalISel/IRTranslator.cpp (original)
+++ llvm/trunk/lib/CodeGen/GlobalISel/IRTranslator.cpp Wed Nov 7 07:24:12 2018
@@ -947,6 +947,11 @@ bool IRTranslator::translateKnownIntrins
MIRBuilder.buildConstant(getOrCreateVReg(CI), Min->isZero() ? -1ULL : 0);
return true;
}
+ case Intrinsic::is_constant:
+ // If this wasn't constant-folded away by now, then it's not a
+ // constant.
+ MIRBuilder.buildConstant(getOrCreateVReg(CI), 0);
+ return true;
case Intrinsic::stackguard:
getStackGuard(getOrCreateVReg(CI), MIRBuilder);
return true;
Modified: llvm/trunk/lib/CodeGen/SelectionDAG/FastISel.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/FastISel.cpp?rev=346322&r1=346321&r2=346322&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/SelectionDAG/FastISel.cpp (original)
+++ llvm/trunk/lib/CodeGen/SelectionDAG/FastISel.cpp Wed Nov 7 07:24:12 2018
@@ -1450,6 +1450,14 @@ bool FastISel::selectIntrinsicCall(const
updateValueMap(II, ResultReg);
return true;
}
+ case Intrinsic::is_constant: {
+ Constant *ResCI = ConstantInt::get(II->getType(), 0);
+ unsigned ResultReg = getRegForValue(ResCI);
+ if (!ResultReg)
+ return false;
+ updateValueMap(II, ResultReg);
+ return true;
+ }
case Intrinsic::launder_invariant_group:
case Intrinsic::strip_invariant_group:
case Intrinsic::expect: {
Modified: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp?rev=346322&r1=346321&r2=346322&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp (original)
+++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp Wed Nov 7 07:24:12 2018
@@ -5897,6 +5897,13 @@ SelectionDAGBuilder::visitIntrinsicCall(
setValue(&I, Res);
return nullptr;
}
+
+ case Intrinsic::is_constant:
+ // If this wasn't constant-folded away by now, then it's not a
+ // constant.
+ setValue(&I, DAG.getConstant(0, sdl, MVT::i1));
+ return nullptr;
+
case Intrinsic::annotation:
case Intrinsic::ptr_annotation:
case Intrinsic::launder_invariant_group:
Modified: llvm/trunk/lib/Transforms/Scalar/SCCP.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/SCCP.cpp?rev=346322&r1=346321&r2=346322&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Scalar/SCCP.cpp (original)
+++ llvm/trunk/lib/Transforms/Scalar/SCCP.cpp Wed Nov 7 07:24:12 2018
@@ -1230,6 +1230,8 @@ CallOverdefined:
SmallVector<Constant*, 8> Operands;
for (CallSite::arg_iterator AI = CS.arg_begin(), E = CS.arg_end();
AI != E; ++AI) {
+ if (AI->get()->getType()->isStructTy())
+ return markOverdefined(I); // Can't handle struct args.
LatticeVal State = getValueState(*AI);
if (State.isUnknown())
Added: llvm/trunk/test/CodeGen/Generic/is-constant.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Generic/is-constant.ll?rev=346322&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Generic/is-constant.ll (added)
+++ llvm/trunk/test/CodeGen/Generic/is-constant.ll Wed Nov 7 07:24:12 2018
@@ -0,0 +1,114 @@
+; RUN: opt -O2 -S < %s | FileCheck %s
+; RUN: llc -o /dev/null 2>&1 < %s
+; RUN: llc -O0 -o /dev/null 2>&1 < %s
+
+;; The llc runs above are just to ensure it doesn't blow up upon
+;; seeing an is_constant intrinsic.
+
+declare i1 @llvm.is.constant.i32(i32 %a)
+declare i1 @llvm.is.constant.i64(i64 %a)
+declare i1 @llvm.is.constant.i256(i256 %a)
+declare i1 @llvm.is.constant.v2i64(<2 x i64> %a)
+declare i1 @llvm.is.constant.f32(float %a)
+declare i1 @llvm.is.constant.sl_i32i32s({i32, i32} %a)
+declare i1 @llvm.is.constant.a2i32([2 x i32] %a)
+declare i1 @llvm.is.constant.p0i64(i64* %a)
+
+;; Basic test that optimization folds away the is.constant when given
+;; a constant.
+define i1 @test_constant() #0 {
+; CHECK-LABEL: @test_constant(
+; CHECK-NOT: llvm.is.constant
+; CHECK: ret i1 true
+%y = call i1 @llvm.is.constant.i32(i32 44)
+ ret i1 %y
+}
+
+;; And test that the intrinsic sticks around when given a
+;; non-constant.
+define i1 @test_nonconstant(i32 %x) #0 {
+; CHECK-LABEL: @test_nonconstant(
+; CHECK: @llvm.is.constant
+ %y = call i1 @llvm.is.constant.i32(i32 %x)
+ ret i1 %y
+}
+
+;; Ensure that nested is.constants fold.
+define i32 @test_nested() #0 {
+; CHECK-LABEL: @test_nested(
+; CHECK-NOT: llvm.is.constant
+; CHECK: ret i32 13
+ %val1 = call i1 @llvm.is.constant.i32(i32 27)
+ %val2 = zext i1 %val1 to i32
+ %val3 = add i32 %val2, 12
+ %1 = call i1 @llvm.is.constant.i32(i32 %val3)
+ %2 = zext i1 %1 to i32
+ %3 = add i32 %2, 12
+ ret i32 %3
+}
+
+ at G = global [2 x i64] zeroinitializer
+define i1 @test_global() #0 {
+; CHECK-LABEL: @test_global(
+; CHECK: llvm.is.constant
+ %ret = call i1 @llvm.is.constant.p0i64(i64* getelementptr ([2 x i64], [2 x i64]* @G, i32 0, i32 0))
+ ret i1 %ret
+}
+
+define i1 @test_diff() #0 {
+; CHECK-LABEL: @test_diff(
+ %ret = call i1 @llvm.is.constant.i64(i64 sub (
+ i64 ptrtoint (i64* getelementptr inbounds ([2 x i64], [2 x i64]* @G, i64 0, i64 1) to i64),
+ i64 ptrtoint ([2 x i64]* @G to i64)))
+ ret i1 %ret
+}
+
+define i1 @test_various_types(i256 %int, float %float, <2 x i64> %vec, {i32, i32} %struct, [2 x i32] %arr, i64* %ptr) #0 {
+; CHECK-LABEL: @test_various_types(
+; CHECK: llvm.is.constant
+; CHECK: llvm.is.constant
+; CHECK: llvm.is.constant
+; CHECK: llvm.is.constant
+; CHECK: llvm.is.constant
+; CHECK: llvm.is.constant
+; CHECK-NOT: llvm.is.constant
+ %v1 = call i1 @llvm.is.constant.i256(i256 %int)
+ %v2 = call i1 @llvm.is.constant.f32(float %float)
+ %v3 = call i1 @llvm.is.constant.v2i64(<2 x i64> %vec)
+ %v4 = call i1 @llvm.is.constant.sl_i32i32s({i32, i32} %struct)
+ %v5 = call i1 @llvm.is.constant.a2i32([2 x i32] %arr)
+ %v6 = call i1 @llvm.is.constant.p0i64(i64* %ptr)
+
+ %c1 = call i1 @llvm.is.constant.i256(i256 -1)
+ %c2 = call i1 @llvm.is.constant.f32(float 17.0)
+ %c3 = call i1 @llvm.is.constant.v2i64(<2 x i64> <i64 -1, i64 44>)
+ %c4 = call i1 @llvm.is.constant.sl_i32i32s({i32, i32} {i32 -1, i32 32})
+ %c5 = call i1 @llvm.is.constant.a2i32([2 x i32] [i32 -1, i32 32])
+ %c6 = call i1 @llvm.is.constant.p0i64(i64* inttoptr (i32 42 to i64*))
+
+ %x1 = add i1 %v1, %c1
+ %x2 = add i1 %v2, %c2
+ %x3 = add i1 %v3, %c3
+ %x4 = add i1 %v4, %c4
+ %x5 = add i1 %v5, %c5
+ %x6 = add i1 %v6, %c6
+
+ %res2 = add i1 %x1, %x2
+ %res3 = add i1 %res2, %x3
+ %res4 = add i1 %res3, %x4
+ %res5 = add i1 %res4, %x5
+ %res6 = add i1 %res5, %x6
+
+ ret i1 %res6
+}
+
+define i1 @test_various_types2() #0 {
+; CHECK-LABEL: @test_various_types2(
+; CHECK: ret i1 false
+ %r = call i1 @test_various_types(i256 -1, float 22.0, <2 x i64> <i64 -1, i64 44>,
+ {i32, i32} {i32 -1, i32 55}, [2 x i32] [i32 -1, i32 55],
+ i64* inttoptr (i64 42 to i64*))
+ ret i1 %r
+}
+
+attributes #0 = { nounwind uwtable }
Added: llvm/trunk/test/CodeGen/X86/is-constant.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/is-constant.ll?rev=346322&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/X86/is-constant.ll (added)
+++ llvm/trunk/test/CodeGen/X86/is-constant.ll Wed Nov 7 07:24:12 2018
@@ -0,0 +1,50 @@
+; RUN: llc -O2 < %s | FileCheck %s --check-prefix=CHECK-O2 --check-prefix=CHECK
+; RUN: llc -O0 -fast-isel < %s | FileCheck %s --check-prefix=CHECK-O0 --check-prefix=CHECK
+; RUN: llc -O0 -fast-isel=0 < %s | FileCheck %s --check-prefix=CHECK-O0 --check-prefix=CHECK
+; RUN: llc -O0 -global-isel < %s | FileCheck %s --check-prefix=CHECK-O0 --check-prefix=CHECK
+
+;; Ensure that an unfoldable is.constant gets lowered reasonably in
+;; optimized codegen, in particular, that the "true" branch is
+;; eliminated.
+;;
+;; This isn't asserting any specific output from non-optimized runs,
+;; (e.g., currently the not-taken branch does not get eliminated). But
+;; it does ensure that lowering succeeds in all 3 codegen paths.
+
+target triple = "x86_64-unknown-linux-gnu"
+
+declare i1 @llvm.is.constant.i32(i32 %a) nounwind readnone
+declare i1 @llvm.is.constant.i64(i64 %a) nounwind readnone
+declare i64 @llvm.objectsize.i64.p0i8(i8*, i1, i1) nounwind readnone
+
+declare i32 @subfun_1()
+declare i32 @subfun_2()
+
+define i32 @test_branch(i32 %in) nounwind {
+; CHECK-LABEL: test_branch:
+; CHECK-O2: %bb.0:
+; CHECK-O2-NEXT: jmp subfun_2
+ %v = call i1 @llvm.is.constant.i32(i32 %in)
+ br i1 %v, label %True, label %False
+
+True:
+ %call1 = tail call i32 @subfun_1()
+ ret i32 %call1
+
+False:
+ %call2 = tail call i32 @subfun_2()
+ ret i32 %call2
+}
+
+;; llvm.objectsize is another tricky case which gets folded to -1 very
+;; late in the game. We'd like to ensure that llvm.is.constant of
+;; llvm.objectsize is true.
+define i1 @test_objectsize(i8* %obj) nounwind {
+; CHECK-LABEL: test_objectsize:
+; CHECK-O2: %bb.0:
+; CHECK-O2: movb $1, %al
+; CHECK-O2-NEXT: retq
+ %os = call i64 @llvm.objectsize.i64.p0i8(i8* %obj, i1 false, i1 false)
+ %v = call i1 @llvm.is.constant.i64(i64 %os)
+ ret i1 %v
+}
Modified: llvm/trunk/test/Transforms/SCCP/ipsccp-basic.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/SCCP/ipsccp-basic.ll?rev=346322&r1=346321&r2=346322&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/SCCP/ipsccp-basic.ll (original)
+++ llvm/trunk/test/Transforms/SCCP/ipsccp-basic.ll Wed Nov 7 07:24:12 2018
@@ -258,3 +258,16 @@ define i64 @test11b() {
}
declare i64 @llvm.ctpop.i64(i64)
+
+;;======================== test12
+;; Ensure that a struct as an arg to a potentially constant-foldable
+;; function does not crash SCCP (for now it'll just ignores it)
+
+define i1 @test12() {
+ %c = call i1 @llvm.is.constant.sl_i32i32s({i32, i32} {i32 -1, i32 32})
+ ret i1 %c
+; CHECK-LABEL: define i1 @test12
+; CHECK: ret i1 %c
+}
+
+declare i1 @llvm.is.constant.sl_i32i32s({i32, i32} %a)
More information about the llvm-commits
mailing list