llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-codegen
@llvm/pr-subscribers-clang
Author: Marco Elver (melver)
<details>
<summary>Changes</summary>
Introduce `__builtin_allow_sanitize_check("name")` which returns true if
the specified sanitizer is enabled for the function (after inlining).
Supported sanitizers are "address", "thread", "memory", "hwaddress", and
their "kernel-" variants, matching the names of the `no_sanitize("name"`
usage.
This builtin enables conditional execution of explicit checks only when
the sanitizer is enabled, respecting `no_sanitize` attributes, even when
used from `always_inline` functions that may be used in sanitized or
no_sanitize functions.
Since we must defer until after inlining and cannot determine the result
statically, Clang must lower to the `llvm.allow.sanitize.*` intrinsics,
which are then resolved by the `LowerAllowCheckPass`.
*Original Motivation:* The Linux kernel has a number of low-level
primitives that use inline assembly not visible to the sanitizers, but
use explicitly inserted checks to avoid coverage loss. Many of those
low-level helpers, however, are also used from so-called `noinstr`
functions, which use `no_sanitize(..)` to prohibit instrumentation;
these are used for very brittle code (such as when the kernel sets up a
task context *before* normal memory is accessible), and any
instrumentation, incl. from explicit instrumentation, is prohibited.
Many such helpers themselves are macros or `always_inline`, however, are
unable to be used from such brittle contexts because they contain
explicit instrumentation. This requires awkward workarounds to avoid the
instrumentation.
The ideal solution is this new builtin, that can be used to determine if
instrumentation is enabled in a given function or not, which the helper
can then use to insert instrumentation only where instrumentation is
allowed.
A recent such case came up in [1], where file-level instrumentation had
already been disabled for KASAN and KCSAN, which had not been necessary
if the new builtin were available.
[1]
https://lore.kernel.org/all/20251208-gcov-inline-noinstr-v1-0-623c48ca5714@<!--
-->google.com/
---
This change is part of the series:
* https://github.com/llvm/llvm-project/pull/172028
* https://github.com/llvm/llvm-project/pull/172029
* https://github.com/llvm/llvm-project/pull/172030
---
Full diff: https://github.com/llvm/llvm-project/pull/172030.diff
12 Files Affected:
- (modified) clang/docs/AddressSanitizer.rst (+34)
- (modified) clang/docs/MemorySanitizer.rst (+34)
- (modified) clang/docs/ReleaseNotes.rst (+7)
- (modified) clang/docs/ThreadSanitizer.rst (+34)
- (modified) clang/include/clang/Basic/Builtins.td (+6)
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+2)
- (modified) clang/lib/CodeGen/BackendUtil.cpp (+12-1)
- (modified) clang/lib/CodeGen/CGBuiltin.cpp (+32)
- (modified) clang/lib/Sema/SemaChecking.cpp (+24)
- (added) clang/test/CodeGen/builtin-allow-sanitize-check-lower.c (+23)
- (added) clang/test/CodeGen/builtin-allow-sanitize-check.c (+78)
- (added) clang/test/Sema/builtin-allow-sanitize-check.c (+24)
``````````diff
diff --git a/clang/docs/AddressSanitizer.rst b/clang/docs/AddressSanitizer.rst
index ed59afa1e0af5..dc0ba79f66cc2 100644
--- a/clang/docs/AddressSanitizer.rst
+++ b/clang/docs/AddressSanitizer.rst
@@ -254,6 +254,40 @@ AddressSanitizer also supports
works similarly to ``__attribute__((no_sanitize("address")))``, but it also
prevents instrumentation performed by other sanitizers.
+Conditional Sanitizer Checks with ``__builtin_allow_sanitize_check``
+--------------------------------------------------------------------
+
+The ``__builtin_allow_sanitize_check("address")`` builtin can be used to
+conditionally execute code only when AddressSanitizer is active for the current
+function (after inlining). This is particularly useful for inserting explicit,
+sanitizer-specific checks around operations like syscalls or inline assembly,
+which might otherwise be unchecked by the sanitizer.
+
+Example:
+
+.. code-block:: c
+
+ inline __attribute__((always_inline))
+ void copy_to_device(void *addr, size_t size) {
+ if (__builtin_allow_sanitize_check("address")) {
+ // Custom checks that address range is valid.
+ }
+ // ... actual device memory copy logic, potentially a syscall ...
+ }
+
+ void instrumented_function() {
+ ...
+ copy_to_device(buf, sizeof(buf)); // checks are active
+ ...
+ }
+
+ __attribute__((no_sanitize("address")))
+ void uninstrumented_function() {
+ ...
+ copy_to_device(buf, sizeof(buf)); // checks are skipped
+ ...
+ }
+
Disabling container overflow checks
-----------------------------------
diff --git a/clang/docs/MemorySanitizer.rst b/clang/docs/MemorySanitizer.rst
index 4f581427c36af..54f88d076d36e 100644
--- a/clang/docs/MemorySanitizer.rst
+++ b/clang/docs/MemorySanitizer.rst
@@ -101,6 +101,40 @@ positives and therefore should be used with care, and only
if absolutely
required; for example for certain code that cannot tolerate any instrumentation
and resulting side-effects. This attribute overrides ``no_sanitize("memory")``.
+Conditional Sanitizer Checks with ``__builtin_allow_sanitize_check``
+--------------------------------------------------------------------
+
+The ``__builtin_allow_sanitize_check("memory")`` builtin can be used to
+conditionally execute code only when MemorySanitizer is active for the current
+function (after inlining). This is particularly useful for inserting explicit,
+sanitizer-specific checks around operations like syscalls or inline assembly,
+which might otherwise be unchecked by the sanitizer.
+
+Example:
+
+.. code-block:: c
+
+ inline __attribute__((always_inline))
+ void copy_to_device(void *addr, size_t size) {
+ if (__builtin_allow_sanitize_check("memory")) {
+ // Custom checks if `data` is initialized.
+ }
+ // ... actual device memory copy logic, potentially a syscall ...
+ }
+
+ void instrumented_function() {
+ ...
+ copy_to_device(buf, sizeof(buf)); // checks are active
+ ...
+ }
+
+ __attribute__((no_sanitize("memory")))
+ void uninstrumented_function() {
+ ...
+ copy_to_device(buf, sizeof(buf)); // checks are skipped
+ ...
+ }
+
Ignorelist
----------
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 59abb0b27cfbe..1756a43d14267 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -798,6 +798,13 @@ Moved checkers
Sanitizers
----------
- Improved documentation for legacy ``no_sanitize`` attributes.
+- Added ``__builtin_allow_sanitize_check("name")`` that returns true if the
+ specified sanitizer is enabled for the current function (after inlining).
+ This allows for conditional code execution based on sanitizer enablement,
+ respecting ``no_sanitize`` attributes. It currently supports sanitizers:
+ "address", "kernel-address", "hwaddress", "kernel-hwaddress", "memory",
+ "kernel-memory", and "thread".
+
Python Binding Changes
----------------------
diff --git a/clang/docs/ThreadSanitizer.rst b/clang/docs/ThreadSanitizer.rst
index 5dc78fa5a7a56..c90d668600ec9 100644
--- a/clang/docs/ThreadSanitizer.rst
+++ b/clang/docs/ThreadSanitizer.rst
@@ -110,6 +110,40 @@ and only if absolutely required; for example for certain
code that cannot
tolerate any instrumentation and resulting side-effects. This attribute
overrides ``no_sanitize("thread")``.
+Conditional Sanitizer Checks with ``__builtin_allow_sanitize_check``
+--------------------------------------------------------------------
+
+The ``__builtin_allow_sanitize_check("thread")`` builtin can be used to
+conditionally execute code only when ThreadSanitizer is active for the current
+function (after inlining). This is particularly useful for inserting explicit,
+sanitizer-specific checks around operations like syscalls or inline assembly,
+which might otherwise be unchecked by the sanitizer.
+
+Example:
+
+.. code-block:: c
+
+ inline __attribute__((always_inline))
+ void copy_to_device(void *addr, size_t size) {
+ if (__builtin_allow_sanitize_check("thread")) {
+ // Custom checks that `data` is not concurrently modified.
+ }
+ // ... actual device memory copy logic, potentially a syscall ...
+ }
+
+ void instrumented_function() {
+ ...
+ copy_to_device(&shared_data, size); // checks are active
+ ...
+ }
+
+ __attribute__((no_sanitize("thread")))
+ void uninstrumented_function() {
+ ...
+ copy_to_device(&shared_data, size); // checks are skipped
+ ...
+ }
+
Ignorelist
----------
diff --git a/clang/include/clang/Basic/Builtins.td
b/clang/include/clang/Basic/Builtins.td
index 98fb2debad06d..ef312a4e02e7f 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -1226,6 +1226,12 @@ def AllowRuntimeCheck : Builtin {
let Prototype = "bool(char const*)";
}
+def BuiltinAllowSanitizeCheck : Builtin {
+ let Spellings = ["__builtin_allow_sanitize_check"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "bool(char const*)";
+}
+
def ShuffleVector : Builtin {
let Spellings = ["__builtin_shufflevector"];
let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 381d1fb063eba..03a38fa1a35e8 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -838,6 +838,8 @@ def warn_redecl_library_builtin : Warning<
InGroup<DiagGroup<"incompatible-library-redeclaration">>;
def err_builtin_definition : Error<"definition of builtin function %0">;
def err_builtin_redeclare : Error<"cannot redeclare builtin function %0">;
+def err_invalid_builtin_argument : Error<"invalid argument '%0' to %1">;
+
def err_arm_invalid_specialreg : Error<"invalid special register for builtin">;
def err_arm_invalid_coproc : Error<"coprocessor %0 must be configured as "
"%select{GCP|CDE}1">;
diff --git a/clang/lib/CodeGen/BackendUtil.cpp
b/clang/lib/CodeGen/BackendUtil.cpp
index 0f60af616aa7b..99c83cd710045 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -843,15 +843,25 @@ static void addSanitizers(const Triple &TargetTriple,
// LastEP does not need GlobalsAA.
PB.registerOptimizerLastEPCallback(SanitizersCallback);
}
+}
+void addLowerAllowCheckPass(const CodeGenOptions &CodeGenOpts,
+ const LangOptions &LangOpts, PassBuilder &PB) {
// SanitizeSkipHotCutoffs: doubles with range [0, 1]
// Opts.cutoffs: unsigned ints with range [0, 1000000]
auto ScaledCutoffs =
CodeGenOpts.SanitizeSkipHotCutoffs.getAllScaled(1000000);
uint64_t AllowRuntimeCheckSkipHotCutoff =
CodeGenOpts.AllowRuntimeCheckSkipHotCutoff.value_or(0.0) * 1000000;
+ bool LowerAllowSanitize = LangOpts.Sanitize.hasOneOf(
+ SanitizerKind::Address | SanitizerKind::KernelAddress |
+ SanitizerKind::Thread | SanitizerKind::Memory |
+ SanitizerKind::KernelMemory | SanitizerKind::HWAddress |
+ SanitizerKind::KernelHWAddress);
+
// TODO: remove IsRequested()
if (LowerAllowCheckPass::IsRequested() || ScaledCutoffs.has_value() ||
- CodeGenOpts.AllowRuntimeCheckSkipHotCutoff.has_value()) {
+ CodeGenOpts.AllowRuntimeCheckSkipHotCutoff.has_value() ||
+ LowerAllowSanitize) {
// We want to call it after inline, which is about
OptimizerEarlyEPCallback.
PB.registerOptimizerEarlyEPCallback(
[ScaledCutoffs, AllowRuntimeCheckSkipHotCutoff](
@@ -1124,6 +1134,7 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
// Most sanitizers only run during PreLink stage.
addSanitizers(TargetTriple, CodeGenOpts, LangOpts, PB);
addKCFIPass(TargetTriple, LangOpts, PB);
+ addLowerAllowCheckPass(CodeGenOpts, LangOpts, PB);
PB.registerPipelineStartEPCallback(
[&](ModulePassManager &MPM, OptimizationLevel Level) {
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 01be374422d93..98d80620b44a5 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3549,6 +3549,38 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl
GD, unsigned BuiltinID,
llvm::MetadataAsValue::get(Ctx, llvm::MDString::get(Ctx, Kind)));
return RValue::get(Allow);
}
+ case Builtin::BI__builtin_allow_sanitize_check: {
+ Intrinsic::ID IntrID = Intrinsic::not_intrinsic;
+ StringRef SanitizerName =
+ cast<StringLiteral>(E->getArg(0)->IgnoreParenCasts())->getString();
+
+ if (SanitizerName == "address" || SanitizerName == "kernel-address") {
+ if (CGM.getLangOpts().Sanitize.hasOneOf(SanitizerKind::Address |
+ SanitizerKind::KernelAddress))
+ IntrID = Intrinsic::allow_sanitize_address;
+ } else if (SanitizerName == "thread") {
+ if (CGM.getLangOpts().Sanitize.has(SanitizerKind::Thread))
+ IntrID = Intrinsic::allow_sanitize_thread;
+ } else if (SanitizerName == "memory" || SanitizerName == "kernel-memory") {
+ if (CGM.getLangOpts().Sanitize.hasOneOf(SanitizerKind::Memory |
+ SanitizerKind::KernelMemory))
+ IntrID = Intrinsic::allow_sanitize_memory;
+ } else if (SanitizerName == "hwaddress" ||
+ SanitizerName == "kernel-hwaddress") {
+ if (CGM.getLangOpts().Sanitize.hasOneOf(SanitizerKind::HWAddress |
+ SanitizerKind::KernelHWAddress))
+ IntrID = Intrinsic::allow_sanitize_hwaddress;
+ }
+
+ if (IntrID != Intrinsic::not_intrinsic) {
+ llvm::Value *Allow = Builder.CreateCall(CGM.getIntrinsic(IntrID));
+ return RValue::get(Allow);
+ }
+ // If the checked sanitizer is not enabled, we can safely lower to false
+ // right away. This is also more efficient, since the LowerAllowCheckPass
+ // must not always be enabled if none of the above sanitizers are enabled.
+ return RValue::get(Builder.getFalse());
+ }
case Builtin::BI__arithmetic_fence: {
// Create the builtin call if FastMath is selected, and the target
// supports the builtin, otherwise just return the argument.
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 67482f1d56da1..1f1cdd0a4c7ed 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -3583,6 +3583,30 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl,
unsigned BuiltinID,
}
break;
}
+
+ case Builtin::BI__builtin_allow_sanitize_check: {
+ Expr *Arg = TheCall->getArg(0);
+ // Check if the argument is a string literal.
+ const StringLiteral *SanitizerName =
+ dyn_cast<StringLiteral>(Arg->IgnoreParenImpCasts());
+ if (!SanitizerName) {
+ Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal)
+ << Arg->getSourceRange();
+ return ExprError();
+ }
+ // Validate the sanitizer name.
+ if (!llvm::StringSwitch<bool>(SanitizerName->getString())
+ .Cases({"address", "thread", "memory", "hwaddress",
+ "kernel-address", "kernel-memory", "kernel-hwaddress"},
+ true)
+ .Default(false)) {
+ Diag(TheCall->getBeginLoc(), diag::err_invalid_builtin_argument)
+ << SanitizerName->getString() << "__builtin_allow_sanitize_check"
+ << Arg->getSourceRange();
+ return ExprError();
+ }
+ break;
+ }
case Builtin::BI__builtin_counted_by_ref:
if (BuiltinCountedByRef(TheCall))
return ExprError();
diff --git a/clang/test/CodeGen/builtin-allow-sanitize-check-lower.c
b/clang/test/CodeGen/builtin-allow-sanitize-check-lower.c
new file mode 100644
index 0000000000000..05a0295799f55
--- /dev/null
+++ b/clang/test/CodeGen/builtin-allow-sanitize-check-lower.c
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=address -emit-llvm -O0
-o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=address -emit-llvm -O1
-o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=address -emit-llvm -O2
-o - %s | FileCheck %s
+
+// CHECK-NOT: call{{.*}} @llvm.allow.sanitize.address
+
+__attribute__((always_inline))
+_Bool check() {
+ return __builtin_allow_sanitize_check("address");
+}
+
+// CHECK-LABEL: @test
+// CHECK: ret i1 true
+_Bool test() {
+ return check();
+}
+
+// CHECK-LABEL: @test_no_sanitize
+// CHECK: ret i1 false
+__attribute__((no_sanitize("address")))
+_Bool test_no_sanitize() {
+ return check();
+}
diff --git a/clang/test/CodeGen/builtin-allow-sanitize-check.c
b/clang/test/CodeGen/builtin-allow-sanitize-check.c
new file mode 100644
index 0000000000000..d535885bd2ddb
--- /dev/null
+++ b/clang/test/CodeGen/builtin-allow-sanitize-check.c
@@ -0,0 +1,78 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o
- %s | FileCheck %s --check-prefixes=CHECK,NONE
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=address -emit-llvm
-disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,ASAN
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=kernel-address
-emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
--check-prefixes=CHECK,ASAN
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=thread -emit-llvm
-disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,TSAN
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=memory -emit-llvm
-disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,MSAN
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=kernel-memory
-emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
--check-prefixes=CHECK,MSAN
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=hwaddress -emit-llvm
-disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,HWASAN
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=kernel-hwaddress
-emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
--check-prefixes=CHECK,HWASAN
+
+// CHECK-LABEL: @test_address
+// NONE: ret i1 false
+// ASAN: call i1 @llvm.allow.sanitize.address()
+// TSAN: ret i1 false
+// MSAN: ret i1 false
+// HWASAN: ret i1 false
+_Bool test_address() {
+ return __builtin_allow_sanitize_check("address");
+}
+
+// CHECK-LABEL: @test_kernel_address
+// NONE: ret i1 false
+// ASAN: call i1 @llvm.allow.sanitize.address()
+// TSAN: ret i1 false
+// MSAN: ret i1 false
+// HWASAN: ret i1 false
+_Bool test_kernel_address() {
+ return __builtin_allow_sanitize_check("kernel-address");
+}
+
+// CHECK-LABEL: @test_thread
+// NONE: ret i1 false
+// ASAN: ret i1 false
+// TSAN: call i1 @llvm.allow.sanitize.thread()
+// MSAN: ret i1 false
+// HWASAN: ret i1 false
+_Bool test_thread() {
+ return __builtin_allow_sanitize_check("thread");
+}
+
+// CHECK-LABEL: @test_memory
+// NONE: ret i1 false
+// ASAN: ret i1 false
+// TSAN: ret i1 false
+// MSAN: call i1 @llvm.allow.sanitize.memory()
+// HWASAN: ret i1 false
+_Bool test_memory() {
+ return __builtin_allow_sanitize_check("memory");
+}
+
+// CHECK-LABEL: @test_kernel_memory
+// NONE: ret i1 false
+// ASAN: ret i1 false
+// TSAN: ret i1 false
+// MSAN: call i1 @llvm.allow.sanitize.memory()
+// HWASAN: ret i1 false
+_Bool test_kernel_memory() {
+ return __builtin_allow_sanitize_check("kernel-memory");
+}
+
+// CHECK-LABEL: @test_hwaddress
+// NONE: ret i1 false
+// ASAN: ret i1 false
+// TSAN: ret i1 false
+// MSAN: ret i1 false
+// HWASAN: call i1 @llvm.allow.sanitize.hwaddress()
+_Bool test_hwaddress() {
+ return __builtin_allow_sanitize_check("hwaddress");
+}
+
+// CHECK-LABEL: @test_kernel_hwaddress
+// NONE: ret i1 false
+// ASAN: ret i1 false
+// TSAN: ret i1 false
+// MSAN: ret i1 false
+// HWASAN: call i1 @llvm.allow.sanitize.hwaddress()
+_Bool test_kernel_hwaddress() {
+ return __builtin_allow_sanitize_check("kernel-hwaddress");
+}
diff --git a/clang/test/Sema/builtin-allow-sanitize-check.c
b/clang/test/Sema/builtin-allow-sanitize-check.c
new file mode 100644
index 0000000000000..94deb16dd89f9
--- /dev/null
+++ b/clang/test/Sema/builtin-allow-sanitize-check.c
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+void test_builtin_allow_sanitize_check() {
+ // Test with non-string literal argument
+ char str[] = "address";
+ (void)__builtin_allow_sanitize_check(str); // expected-error {{expression is
not a string literal}}
+ (void)__builtin_allow_sanitize_check(123); // expected-error {{expression is
not a string literal}}
+
+ // Test with unsupported sanitizer name
+ (void)__builtin_allow_sanitize_check("unsupported"); // expected-error
{{invalid argument 'unsupported' to __builtin_allow_sanitize_check}}
+
+ // Test with supported sanitizer names
+ (void)__builtin_allow_sanitize_check("address");
+ (void)__builtin_allow_sanitize_check("thread");
+ (void)__builtin_allow_sanitize_check("memory");
+ (void)__builtin_allow_sanitize_check("hwaddress");
+ (void)__builtin_allow_sanitize_check("kernel-address");
+ (void)__builtin_allow_sanitize_check("kernel-memory");
+ (void)__builtin_allow_sanitize_check("kernel-hwaddress");
+}
+
+#if !__has_builtin(__builtin_allow_sanitize_check)
+#error "missing __builtin_allow_sanitize_check"
+#endif
``````````
</details>
https://github.com/llvm/llvm-project/pull/172030
_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits