[flang-commits] [llvm] [clang] [flang] [Flang][WIP/RFC] Enable TSan for Flang (PR #74643)

via flang-commits flang-commits at lists.llvm.org
Wed Dec 6 11:02:20 PST 2023


https://github.com/jprotze created https://github.com/llvm/llvm-project/pull/74643

This patch enables ThreadSanitizer analysis for Fortran codes compiled with Flang. The patch is marked as WIP/RFC since it is at the moment a prove of concept.

Open questions from our side:
- Is it the right place to run the ThreadSanitizer pass?
- The ThreadSanitizer pass assumes the ThreadSanitizer attribute on each function to be instrumented. Clang adds this attribute during the CodeGen, if no (no)ThreadSanitizer is already attached to the function and if the function is not blacklisted. For this PoC we simply disabled the check for the attribute. We see different options for an actual solution:
  - run a separate pass before the TSan pass that adds the attribute to all functions while considering the blacklist
  - add a new flag to the TSan pass to skip the check and set the flag when the TSan pass is launched from Flang
- What is the best way to pass through all the different Sanitizer flags?

>From d04b05a69025c33aae027c07eda2c0c51b0b9426 Mon Sep 17 00:00:00 2001
From: Joachim Jenke <jenke at itc.rwth-aachen.de>
Date: Tue, 14 Nov 2023 13:54:41 +0100
Subject: [PATCH 1/3] Initial Flang+TSan tests

---
 flang/lib/Frontend/FrontendActions.cpp                  | 5 +++++
 flang/lib/Optimizer/CodeGen/CMakeLists.txt              | 4 ++++
 llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp | 2 +-
 3 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp
index 1be95cc27f42c..ffbd7eaac6ea9 100644
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -67,6 +67,9 @@
 #include "llvm/Target/TargetMachine.h"
 #include "llvm/TargetParser/TargetParser.h"
 #include "llvm/Transforms/Utils/ModuleUtils.h"
+#include "llvm/Transforms/Instrumentation.h"
+#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
+
 #include <memory>
 #include <system_error>
 
@@ -1073,6 +1076,8 @@ void CodeGenAction::runOptimizationPipeline(llvm::raw_pwrite_stream &os) {
   else
     mpm = pb.buildPerModuleDefaultPipeline(level);
 
+  mpm.addPass(llvm::ModuleThreadSanitizerPass());
+  mpm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::ThreadSanitizerPass()));
   if (action == BackendActionTy::Backend_EmitBC)
     mpm.addPass(llvm::BitcodeWriterPass(os));
 
diff --git a/flang/lib/Optimizer/CodeGen/CMakeLists.txt b/flang/lib/Optimizer/CodeGen/CMakeLists.txt
index 0daa97b00dfa0..2d48c873ff4a1 100644
--- a/flang/lib/Optimizer/CodeGen/CMakeLists.txt
+++ b/flang/lib/Optimizer/CodeGen/CMakeLists.txt
@@ -1,3 +1,7 @@
+set(LLVM_LINK_COMPONENTS
+  Instrumentation
+)
+
 add_flang_library(FIRCodeGen
   BoxedProcedure.cpp
   CGOps.cpp
diff --git a/llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp
index 8ee0bca7e354f..bd720634e467e 100644
--- a/llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp
@@ -511,7 +511,7 @@ bool ThreadSanitizer::sanitizeFunction(Function &F,
   SmallVector<Instruction*, 8> MemIntrinCalls;
   bool Res = false;
   bool HasCalls = false;
-  bool SanitizeFunction = F.hasFnAttribute(Attribute::SanitizeThread);
+  bool SanitizeFunction = F.hasFnAttribute(Attribute::SanitizeThread) || true;
   const DataLayout &DL = F.getParent()->getDataLayout();
 
   // Traverse all instructions, collect loads/stores/returns, check for calls.

>From 4dbbd7de3b0788665282e8ff3e7f79c46320da4c Mon Sep 17 00:00:00 2001
From: Joachim Jenke <jenke at itc.rwth-aachen.de>
Date: Wed, 15 Nov 2023 15:47:26 +0100
Subject: [PATCH 2/3] Propagate Tsan flag to fc1 and apply Tsan pass
 conditionally

---
 clang/include/clang/Driver/Options.td         | 8 ++++----
 clang/lib/Driver/ToolChains/Flang.cpp         | 1 +
 flang/include/flang/Common/Fortran-features.h | 3 ++-
 flang/lib/Frontend/CompilerInvocation.cpp     | 4 ++++
 flang/lib/Frontend/FrontendActions.cpp        | 7 +++++--
 5 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 0eec2b3526376..b99fe4e4a24f4 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2163,14 +2163,14 @@ def fmemory_profile_use_EQ : Joined<["-"], "fmemory-profile-use=">,
     HelpText<"Use memory profile for profile-guided memory optimization">,
     MarshallingInfoString<CodeGenOpts<"MemoryProfileUsePath">>;
 
+def fsanitize_EQ : CommaJoined<["-"], "fsanitize=">, Group<f_clang_Group>,
+                   MetaVarName<"<check>">, Visibility<[ClangOption, CC1Option, CLOption, FlangOption, FC1Option]>,
+                   HelpText<"Turn on runtime checks for various forms of undefined "
+                            "or suspicious behavior. See user manual for available checks">;
 // Begin sanitizer flags. These should all be core options exposed in all driver
 // modes.
 let Visibility = [ClangOption, CC1Option, CLOption] in {
 
-def fsanitize_EQ : CommaJoined<["-"], "fsanitize=">, Group<f_clang_Group>,
-                   MetaVarName<"<check>">,
-                   HelpText<"Turn on runtime checks for various forms of undefined "
-                            "or suspicious behavior. See user manual for available checks">;
 def fno_sanitize_EQ : CommaJoined<["-"], "fno-sanitize=">, Group<f_clang_Group>,
                       Visibility<[ClangOption, CLOption]>;
 
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index 9b21fe952af7a..7d433455f24cc 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -38,6 +38,7 @@ void Flang::addFortranDialectOptions(const ArgList &Args,
                             options::OPT_fopenmp,
                             options::OPT_fopenmp_version_EQ,
                             options::OPT_fopenacc,
+                            options::OPT_fsanitize_EQ,
                             options::OPT_finput_charset_EQ,
                             options::OPT_fimplicit_none,
                             options::OPT_fno_implicit_none,
diff --git a/flang/include/flang/Common/Fortran-features.h b/flang/include/flang/Common/Fortran-features.h
index a6b19e9833fc5..d3d4556b9cdbf 100644
--- a/flang/include/flang/Common/Fortran-features.h
+++ b/flang/include/flang/Common/Fortran-features.h
@@ -35,7 +35,7 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines,
     ProgramReturn, ImplicitNoneTypeNever, ImplicitNoneTypeAlways,
     ForwardRefImplicitNone, OpenAccessAppend, BOZAsDefaultInteger,
     DistinguishableSpecifics, DefaultSave, PointerInSeqType, NonCharacterFormat,
-    SaveMainProgram, SaveBigMainProgramVariables,
+    SaveMainProgram, SaveBigMainProgramVariables, TSan,
     DistinctArrayConstructorLengths, PPCVector, RelaxedIntentInChecking,
     ForwardRefImplicitNoneData, NullActualForAllocatable,
     ActualIntegerConvertedToSmallerKind, HollerithOrCharacterAsBOZ,
@@ -65,6 +65,7 @@ class LanguageFeatureControl {
     disable_.set(LanguageFeature::OldDebugLines);
     disable_.set(LanguageFeature::OpenACC);
     disable_.set(LanguageFeature::OpenMP);
+    disable_.set(LanguageFeature::TSan);
     disable_.set(LanguageFeature::CUDA); // !@cuf
     disable_.set(LanguageFeature::ImplicitNoneTypeNever);
     disable_.set(LanguageFeature::ImplicitNoneTypeAlways);
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index c623969a21e5e..6b3c0706c9273 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -862,6 +862,10 @@ static bool parseDialectArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
     res.getFrontendOpts().features.Enable(
         Fortran::common::LanguageFeature::OpenACC);
   }
+  if (args.hasArg(clang::driver::options::OPT_fsanitize_EQ) && llvm::StringRef(args.getLastArg(clang::driver::options::OPT_fsanitize_EQ)->getValue()) == "thread" ) {
+    res.getFrontendOpts().features.Enable(
+        Fortran::common::LanguageFeature::TSan);
+  }
   if (args.hasArg(clang::driver::options::OPT_fopenmp)) {
     // By default OpenMP is set to 1.1 version
     res.getLangOpts().OpenMPVersion = 11;
diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp
index ffbd7eaac6ea9..423e121cdf3dc 100644
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -1076,8 +1076,11 @@ void CodeGenAction::runOptimizationPipeline(llvm::raw_pwrite_stream &os) {
   else
     mpm = pb.buildPerModuleDefaultPipeline(level);
 
-  mpm.addPass(llvm::ModuleThreadSanitizerPass());
-  mpm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::ThreadSanitizerPass()));
+  if (this->getInstance().getInvocation().getFrontendOpts().features.IsEnabled(
+          Fortran::common::LanguageFeature::TSan)) {
+    mpm.addPass(llvm::ModuleThreadSanitizerPass());
+    mpm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::ThreadSanitizerPass()));
+  }
   if (action == BackendActionTy::Backend_EmitBC)
     mpm.addPass(llvm::BitcodeWriterPass(os));
 

>From 03c22524ecf8851951d37f6282b3cd43edb8607e Mon Sep 17 00:00:00 2001
From: "felix.tomski" <tomski at itc.rwth-aachen.de>
Date: Wed, 6 Dec 2023 18:23:18 +0100
Subject: [PATCH 3/3] Fix fsanitize option not known to clang

---
 clang/include/clang/Driver/Options.td | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index b99fe4e4a24f4..2fcc31495cdb5 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2164,7 +2164,7 @@ def fmemory_profile_use_EQ : Joined<["-"], "fmemory-profile-use=">,
     MarshallingInfoString<CodeGenOpts<"MemoryProfileUsePath">>;
 
 def fsanitize_EQ : CommaJoined<["-"], "fsanitize=">, Group<f_clang_Group>,
-                   MetaVarName<"<check>">, Visibility<[ClangOption, CC1Option, CLOption, FlangOption, FC1Option]>,
+                   MetaVarName<"<check>">, Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
                    HelpText<"Turn on runtime checks for various forms of undefined "
                             "or suspicious behavior. See user manual for available checks">;
 // Begin sanitizer flags. These should all be core options exposed in all driver



More information about the flang-commits mailing list