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 <je...@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 <je...@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" <tom...@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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits