diff --git a/compiler-rt/include/sanitizer/memprof_interface.h b/compiler-rt/include/sanitizer/memprof_interface.h
index 4660a7818c92b..6d9b2a2394f41 100644
--- a/compiler-rt/include/sanitizer/memprof_interface.h
+++ b/compiler-rt/include/sanitizer/memprof_interface.h
@@ -47,9 +47,9 @@ void SANITIZER_CDECL __memprof_print_accumulated_stats(void);
/// User-provided default option settings.
///
-/// You can provide your own implementation of this function to return a string
-/// containing MemProf runtime options (for example,
-/// verbosity=1:print_stats=1).
+/// You can set these options via the -memprof-runtime-default-options LLVM flag
+/// or you can provide your own implementation of this function. See
+/// memprof_flags.h for more info.
///
/// \returns Default options string.
const char *SANITIZER_CDECL __memprof_default_options(void);
diff --git a/compiler-rt/lib/memprof/memprof_flags.cpp b/compiler-rt/lib/memprof/memprof_flags.cpp
index b107ff8fa0a7c..95fde9d9672d6 100644
--- a/compiler-rt/lib/memprof/memprof_flags.cpp
+++ b/compiler-rt/lib/memprof/memprof_flags.cpp
@@ -89,5 +89,5 @@ void InitializeFlags() {
} // namespace __memprof
SANITIZER_INTERFACE_WEAK_DEF(const char *, __memprof_default_options, void) {
- return "";
+ return __memprof_default_options_str;
}
diff --git a/compiler-rt/lib/memprof/memprof_flags.h b/compiler-rt/lib/memprof/memprof_flags.h
index 2f2b628653dc1..4dd395a6be94a 100644
--- a/compiler-rt/lib/memprof/memprof_flags.h
+++ b/compiler-rt/lib/memprof/memprof_flags.h
@@ -17,13 +17,15 @@
#include "sanitizer_common/sanitizer_flag_parser.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
-// MemProf flag values can be defined in four ways:
-// 1) initialized with default values at startup.
-// 2) overriden during compilation of MemProf runtime by providing
-// compile definition MEMPROF_DEFAULT_OPTIONS.
-// 3) overriden from string returned by user-specified function
-// __memprof_default_options().
-// 4) overriden from env variable MEMPROF_OPTIONS.
+// Default MemProf flags are defined in memprof_flags.inc and sancov_flags.inc.
+// These values can be overridded in a number of ways, each option overrides the
+// prior one:
+// 1) by setting MEMPROF_DEFAULT_OPTIONS during the compilation of the MemProf
+// runtime
+// 2) by setting the LLVM flag -memprof-runtime-default-options during the
+// compilation of your binary
+// 3) by overriding the user-specified function __memprof_default_options()
+// 4) by setting the environment variable MEMPROF_OPTIONS during runtime
namespace __memprof {
diff --git a/compiler-rt/lib/memprof/memprof_interface_internal.h b/compiler-rt/lib/memprof/memprof_interface_internal.h
index 318bc41044056..7d3a937814a34 100644
--- a/compiler-rt/lib/memprof/memprof_interface_internal.h
+++ b/compiler-rt/lib/memprof/memprof_interface_internal.h
@@ -40,6 +40,9 @@ void __memprof_record_access_range(void const volatile *addr, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE void __memprof_print_accumulated_stats();
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE extern char
+ __memprof_default_options_str[1];
+
SANITIZER_INTERFACE_ATTRIBUTE
const char *__memprof_default_options();
diff --git a/compiler-rt/lib/memprof/memprof_rtl.cpp b/compiler-rt/lib/memprof/memprof_rtl.cpp
index 2cc6c2df5a6fe..ef8884a7e56f4 100644
--- a/compiler-rt/lib/memprof/memprof_rtl.cpp
+++ b/compiler-rt/lib/memprof/memprof_rtl.cpp
@@ -27,6 +27,8 @@
#include
+SANITIZER_WEAK_ATTRIBUTE char __memprof_default_options_str[1];
+
uptr __memprof_shadow_memory_dynamic_address; // Global interface symbol.
// Allow the user to specify a profile output file via the binary.
diff --git a/compiler-rt/lib/memprof/weak_symbols.txt b/compiler-rt/lib/memprof/weak_symbols.txt
index 271813612ab60..bfece89e2e157 100644
--- a/compiler-rt/lib/memprof/weak_symbols.txt
+++ b/compiler-rt/lib/memprof/weak_symbols.txt
@@ -1 +1 @@
-___memprof_default_options __memprof_profile_filename
+___memprof_default_options_str ___memprof_default_options __memprof_profile_filename
diff --git a/compiler-rt/test/memprof/TestCases/default_options.cpp b/compiler-rt/test/memprof/TestCases/default_options.cpp
index 1b6b61fc048b6..4042a7df588b0 100644
--- a/compiler-rt/test/memprof/TestCases/default_options.cpp
+++ b/compiler-rt/test/memprof/TestCases/default_options.cpp
@@ -1,5 +1,8 @@
// RUN: %clangxx_memprof -O2 %s -o %t && %run %t 2>&1 | FileCheck %s
+// Check that overriding __memprof_default_options() takes precedence over the LLVM flag
+// RUN: %clangxx_memprof -O2 %s -o %t-flag -mllvm -memprof-runtime-default-options="verbosity=0 help=0" && %run %t-flag 2>&1 | FileCheck %s
+
const char *kMemProfDefaultOptions = "verbosity=1 help=1";
extern "C" const char *__memprof_default_options() {
diff --git a/compiler-rt/test/memprof/TestCases/set_options.cpp b/compiler-rt/test/memprof/TestCases/set_options.cpp
new file mode 100644
index 0000000000000..dddcfcf98c5c0
--- /dev/null
+++ b/compiler-rt/test/memprof/TestCases/set_options.cpp
@@ -0,0 +1,16 @@
+// RUN: %clangxx_memprof %s -o %t-default
+// RUN: %run %t-default | FileCheck %s --check-prefix=DEFAULT
+
+// RUN: %clangxx_memprof %s -mllvm -memprof-runtime-default-options="print_text=true,log_path=stdout,atexit=false" -o %t
+// RUN: %run %t | FileCheck %s
+
+#include
+#include
+
+int main() {
+ printf("Options: \"%s\"\n", __memprof_default_options());
+ return 0;
+}
+
+// DEFAULT: Options: ""
+// CHECK: Options: "print_text=true,log_path=stdout,atexit=false"
diff --git a/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp b/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp
index 33a7a37fa28e6..ab7d3c7002991 100644
--- a/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp
+++ b/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp
@@ -166,6 +166,11 @@ static cl::opt
"context in this module's profiles"),
cl::Hidden, cl::init(false));
+static cl::opt
+ MemprofRuntimeDefaultOptions("memprof-runtime-default-options",
+ cl::desc("The default memprof options"),
+ cl::Hidden, cl::init(""));
+
extern cl::opt MemProfReportHintedSizes;
// Instrumentation statistics
@@ -547,6 +552,20 @@ void createMemprofHistogramFlagVar(Module &M) {
appendToCompilerUsed(M, MemprofHistogramFlag);
}
+void createMemprofDefaultOptionsVar(Module &M) {
+ Constant *OptionsConst = ConstantDataArray::getString(
+ M.getContext(), MemprofRuntimeDefaultOptions, /*AddNull=*/true);
+ GlobalVariable *OptionsVar =
+ new GlobalVariable(M, OptionsConst->getType(), /*isConstant=*/true,
+ GlobalValue::WeakAnyLinkage, OptionsConst,
+ "__memprof_default_options_str");
+ Triple TT(M.getTargetTriple());
+ if (TT.supportsCOMDAT()) {
+ OptionsVar->setLinkage(GlobalValue::ExternalLinkage);
+ OptionsVar->setComdat(M.getOrInsertComdat(OptionsVar->getName()));
+ }
+}
+
bool ModuleMemProfiler::instrumentModule(Module &M) {
// Create a module constructor.
@@ -566,6 +585,8 @@ bool ModuleMemProfiler::instrumentModule(Module &M) {
createMemprofHistogramFlagVar(M);
+ createMemprofDefaultOptionsVar(M);
+
return true;
}
diff --git a/llvm/test/Instrumentation/HeapProfiler/memprof-options.ll b/llvm/test/Instrumentation/HeapProfiler/memprof-options.ll
new file mode 100644
index 0000000000000..8e82d524952dd
--- /dev/null
+++ b/llvm/test/Instrumentation/HeapProfiler/memprof-options.ll
@@ -0,0 +1,11 @@
+; RUN: opt < %s -mtriple=x86_64-unknown-linux -passes='function(memprof),memprof-module' -S | FileCheck %s --check-prefixes=CHECK,EMPTY
+; RUN: opt < %s -mtriple=x86_64-unknown-linux -passes='function(memprof),memprof-module' -S -memprof-runtime-default-options="verbose=1" | FileCheck %s --check-prefixes=CHECK,VERBOSE
+
+define i32 @main() {
+entry:
+ ret i32 0
+}
+
+; CHECK: $__memprof_default_options_str = comdat any
+; EMPTY: @__memprof_default_options_str = constant [1 x i8] zeroinitializer, comdat
+; VERBOSE: @__memprof_default_options_str = constant [10 x i8] c"verbose=1\00", comdat