martong created this revision.
martong added reviewers: NoQ, Szelethus, balazske, vsavchenko.
Herald added subscribers: cfe-commits, ASDenysPetrov, steakhal, Charusso, 
gamesh411, dkrupp, donat.nagy, mikhail.ramalho, a.sidorin, rnkovacs, szepet, 
baloghadamsoftware, xazax.hun, whisperity, mgorny.
Herald added a project: clang.
martong requested review of this revision.

Access the IR from the components of the Clang Static Analyzer. There are many
important and useful analyses in the LLVM layer that we can use during the path
sensitive analysis. Most notably, the "readnone" and "readonly" function
attributes  which can be used to identify "pure" functions (those without side
effects). Here, I am using the pureness info from the IR to avoid invalidation
of any variables during conservative evaluation (when we evaluate a pure
function).


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D85319

Files:
  clang/include/clang/CodeGen/CodeGenMangling.h
  clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def
  clang/include/clang/StaticAnalyzer/Core/IRContext.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
  clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h
  clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h
  clang/lib/CodeGen/CMakeLists.txt
  clang/lib/CodeGen/CodeGenMangling.cpp
  clang/lib/StaticAnalyzer/Core/CMakeLists.txt
  clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
  clang/lib/StaticAnalyzer/Core/IRContext.cpp
  clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
  clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt
  clang/lib/StaticAnalyzer/Frontend/FrontendActions.cpp
  clang/test/Analysis/analyzer-config.c
  clang/test/Analysis/ctu-different-triples.cpp
  clang/test/Analysis/ircontext.c
  clang/test/Analysis/ircontext.cpp
  clang/unittests/StaticAnalyzer/Reusables.h

Index: clang/unittests/StaticAnalyzer/Reusables.h
===================================================================
--- clang/unittests/StaticAnalyzer/Reusables.h
+++ clang/unittests/StaticAnalyzer/Reusables.h
@@ -10,8 +10,9 @@
 #define LLVM_CLANG_UNITTESTS_STATICANALYZER_REUSABLES_H
 
 #include "clang/ASTMatchers/ASTMatchFinder.h"
-#include "clang/Frontend/CompilerInstance.h"
 #include "clang/CrossTU/CrossTranslationUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/StaticAnalyzer/Core/IRContext.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
 
 namespace clang {
@@ -41,11 +42,13 @@
 class ExprEngineConsumer : public ASTConsumer {
 protected:
   CompilerInstance &C;
+  CodeGenerator *CG = nullptr;
 
 private:
   // We need to construct all of these in order to construct ExprEngine.
   CheckerManager ChkMgr;
   cross_tu::CrossTranslationUnitContext CTU;
+  IRContext IRCtx;
   PathDiagnosticConsumers Consumers;
   AnalysisManager AMgr;
   SetOfConstDecls VisitedCallees;
@@ -58,12 +61,12 @@
   ExprEngineConsumer(CompilerInstance &C)
       : C(C),
         ChkMgr(C.getASTContext(), *C.getAnalyzerOpts(), C.getPreprocessor()),
-        CTU(C), Consumers(),
+        CTU(C), IRCtx(CG), Consumers(),
         AMgr(C.getASTContext(), C.getPreprocessor(), Consumers,
              CreateRegionStoreManager, CreateRangeConstraintManager, &ChkMgr,
              *C.getAnalyzerOpts()),
-        VisitedCallees(), FS(),
-        Eng(CTU, AMgr, &VisitedCallees, &FS, ExprEngine::Inline_Regular) {}
+        VisitedCallees(), FS(), Eng(CTU, IRCtx, AMgr, &VisitedCallees, &FS,
+                                    ExprEngine::Inline_Regular) {}
 };
 
 } // namespace ento
Index: clang/test/Analysis/ircontext.cpp
===================================================================
--- /dev/null
+++ clang/test/Analysis/ircontext.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_analyze_cc1 %s \
+// RUN:   -analyzer-checker=core,debug.ExprInspection \
+// RUN:   -analyzer-config eagerly-assume=false \
+// RUN:   -analyzer-config ipa=none \
+// RUN:   -analyzer-config generate-llvm-ir=true \
+// RUN:   -triple i686-unknown-linux \
+// RUN:   -verify
+
+void clang_analyzer_eval(int);
+
+int g = 0;
+int foo(int *x) { return *x; }
+
+void test() {
+  g = 3;
+  int l = 0;
+  foo(&l);
+  clang_analyzer_eval(g == 3); // expected-warning{{TRUE}}
+}
Index: clang/test/Analysis/ircontext.c
===================================================================
--- /dev/null
+++ clang/test/Analysis/ircontext.c
@@ -0,0 +1,18 @@
+// RUN: %clang_analyze_cc1 %s \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-config ipa=none \
+// RUN:   -triple i686-unknown-linux \
+// RUN:   -verify
+
+// expected-no-diagnostics
+
+void clang_analyzer_eval(int);
+
+int g = 0;
+int foo(int *x) { return *x; }
+
+void test() {
+  g = 3;
+  int l = 0;
+  foo(&l);
+}
Index: clang/test/Analysis/ctu-different-triples.cpp
===================================================================
--- clang/test/Analysis/ctu-different-triples.cpp
+++ clang/test/Analysis/ctu-different-triples.cpp
@@ -12,6 +12,8 @@
 
 // We expect an error in this file, but without a location.
 // expected-error-re@./ctu-different-triples.cpp:*{{imported AST from {{.*}} had been generated for a different target, current: powerpc64-montavista-linux-gnu, imported: x86_64-pc-linux-gnu}}
+// FIXME Why do we get the error twice?
+// expected-error-re@./ctu-different-triples.cpp:*{{imported AST from {{.*}} had been generated for a different target, current: powerpc64-montavista-linux-gnu, imported: x86_64-pc-linux-gnu}}
 
 int f(int);
 
Index: clang/test/Analysis/analyzer-config.c
===================================================================
--- clang/test/Analysis/analyzer-config.c
+++ clang/test/Analysis/analyzer-config.c
@@ -80,6 +80,7 @@
 // CHECK-NEXT: experimental-enable-naive-ctu-analysis = false
 // CHECK-NEXT: exploration_strategy = unexplored_first_queue
 // CHECK-NEXT: faux-bodies = true
+// CHECK-NEXT: generate-llvm-ir = false
 // CHECK-NEXT: graph-trim-interval = 1000
 // CHECK-NEXT: inline-lambdas = true
 // CHECK-NEXT: ipa = dynamic-bifurcate
Index: clang/lib/StaticAnalyzer/Frontend/FrontendActions.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Frontend/FrontendActions.cpp
+++ clang/lib/StaticAnalyzer/Frontend/FrontendActions.cpp
@@ -7,14 +7,61 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
+#include "clang/Frontend/MultiplexConsumer.h"
 #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
 #include "clang/StaticAnalyzer/Frontend/ModelConsumer.h"
+
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/Frontend/CompilerInstance.h"
+
+#include "llvm/IR/LLVMContext.h"
+
 using namespace clang;
 using namespace ento;
 
+namespace {
+std::unique_ptr<CodeGenerator> BuildCodeGen(CompilerInstance &CI,
+                                            llvm::LLVMContext &LLVMCtx,
+                                            DiagnosticsEngine &CodeGenDiags) {
+  StringRef ModuleName("csa_module");
+  CodeGenOptions &CGO = CI.getCodeGenOpts();
+  // Set the optimization level, so CodeGenFunciton would emit lifetime
+  // markers which are used by some LLVM analysis (e.g. AliasAnalysis).
+  CGO.OptimizationLevel = 2; // -O2
+
+  return std::unique_ptr<CodeGenerator>(
+      CreateLLVMCodeGen(CodeGenDiags, ModuleName, CI.getHeaderSearchOpts(),
+                        CI.getPreprocessorOpts(), CGO, LLVMCtx));
+}
+} // namespace
+
+AnalysisAction::~AnalysisAction() {}
+
 std::unique_ptr<ASTConsumer>
 AnalysisAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
-  return CreateAnalysisConsumer(CI);
+  std::vector<std::unique_ptr<ASTConsumer>> ASTConsumers;
+  auto AConsumer = CreateAnalysisConsumer(CI);
+
+  AnalyzerOptionsRef Opts = CI.getAnalyzerOpts();
+  if (Opts->GenerateLLVMIR) {
+    DiagnosticsEngine &SADiagEng = CI.getDiagnostics();
+    // Supress diagnostics during CodeGen.
+    CodeGenDiags = std::make_unique<DiagnosticsEngine>(
+        SADiagEng.getDiagnosticIDs(), &SADiagEng.getDiagnosticOptions(),
+        SADiagEng.getClient(), /*ShouldOwnClient=*/false);
+    CodeGenDiags->setSuppressAllDiagnostics(true);
+    LLVMCtx = std::make_shared<llvm::LLVMContext>();
+    auto CGConsumer = BuildCodeGen(CI, *LLVMCtx, *CodeGenDiags);
+    AConsumer->setCodeGen(CGConsumer.get());
+    ASTConsumers.push_back(std::move(CGConsumer));
+  }
+
+  ASTConsumers.push_back(std::move(AConsumer));
+  return std::make_unique<MultiplexConsumer>(std::move(ASTConsumers));
+}
+
+std::unique_ptr<AnalysisAction> CreateAnalysisAction() {
+  return std::make_unique<AnalysisAction>();
 }
 
 ParseModelFileAction::ParseModelFileAction(llvm::StringMap<Stmt *> &Bodies)
Index: clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt
===================================================================
--- clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt
+++ clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt
@@ -14,10 +14,12 @@
   ModelInjector.cpp
 
   LINK_LIBS
+  LLVMCore
   clangAST
   clangASTMatchers
   clangAnalysis
   clangBasic
+  clangCodeGen
   clangCrossTU
   clangFrontend
   clangLex
Index: clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -30,6 +30,7 @@
 #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/IRContext.h"
 #include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
@@ -90,6 +91,7 @@
   ArrayRef<std::string> Plugins;
   CodeInjector *Injector;
   cross_tu::CrossTranslationUnitContext CTU;
+  IRContext IRCtx;
 
   /// Stores the declarations from the local translation unit.
   /// Note, we pre-compute the local declarations at parse time as an
@@ -122,7 +124,7 @@
                    CodeInjector *injector)
       : RecVisitorMode(0), RecVisitorBR(nullptr), Ctx(nullptr),
         PP(CI.getPreprocessor()), OutDir(outdir), Opts(std::move(opts)),
-        Plugins(plugins), Injector(injector), CTU(CI) {
+        Plugins(plugins), Injector(injector), CTU(CI), IRCtx(CG) {
     DigestAnalyzerOptions();
     if (Opts->PrintStats || Opts->ShouldSerializeStats) {
       AnalyzerTimers = std::make_unique<llvm::TimerGroup>(
@@ -541,6 +543,7 @@
     reportAnalyzerProgress("All checks are disabled using a supplied option\n");
   } else {
     // Otherwise, just run the analysis.
+    IRCtx.runOptimizerPipeline();
     runAnalysisOnTranslationUnit(C);
   }
 
@@ -693,7 +696,7 @@
   if (!Mgr->getAnalysisDeclContext(D)->getAnalysis<RelaxedLiveVariables>())
     return;
 
-  ExprEngine Eng(CTU, *Mgr, VisitedCallees, &FunctionSummaries, IMode);
+  ExprEngine Eng(CTU, IRCtx, *Mgr, VisitedCallees, &FunctionSummaries, IMode);
 
   // Execute the worklist algorithm.
   if (ExprEngineTimer)
Index: clang/lib/StaticAnalyzer/Core/IRContext.cpp
===================================================================
--- /dev/null
+++ clang/lib/StaticAnalyzer/Core/IRContext.cpp
@@ -0,0 +1,100 @@
+//===-------------- IRContext.cpp -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/IRContext.h"
+#include "clang/CodeGen/CodeGenMangling.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+
+#include "llvm/IR/Module.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/Passes/PassBuilder.h"
+#include "llvm/Transforms/Utils/EntryExitInstrumenter.h"
+
+using namespace llvm;
+using namespace clang;
+using namespace ento;
+
+void IRContext::runOptimizerPipeline() {
+  if (CodeGen == nullptr)
+    return;
+
+  // TargetMachine is not set, so we will not do optimizations based on
+  // target-aware cost modeling of IR contructs. Still, a default
+  // TargetIRAnalysis is registerd in registerFunctionAnalyses. That will use
+  // the module's datalayout to construct a baseline conservative result.
+  PassBuilder PB;
+
+  // FIXME make this an option.
+  constexpr const bool Debug = false;
+
+  LoopAnalysisManager LAM(Debug);
+  FunctionAnalysisManager FAM(Debug);
+  CGSCCAnalysisManager CGAM(Debug);
+  ModuleAnalysisManager MAM(Debug);
+
+  // Register the AA manager first so that our version is the one used.
+  FAM.registerPass([&] { return PB.buildDefaultAAPipeline(); });
+
+  auto *M = CodeGen->GetModule();
+
+  // Register the target library analysis directly and give it a customized
+  // preset TLI.
+  Triple TargetTriple(M->getTargetTriple());
+  std::unique_ptr<TargetLibraryInfoImpl> TLII(
+      new TargetLibraryInfoImpl(TargetTriple));
+  FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); });
+
+  // Register all the basic analyses with the managers.
+  PB.registerModuleAnalyses(MAM);
+  PB.registerCGSCCAnalyses(CGAM);
+  PB.registerFunctionAnalyses(FAM);
+  PB.registerLoopAnalyses(LAM);
+  PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
+
+  ModulePassManager MPM(Debug);
+
+  PB.registerPipelineStartEPCallback([](ModulePassManager &MPM) {
+    MPM.addPass(createModuleToFunctionPassAdaptor(
+        EntryExitInstrumenterPass(/*PostInlining=*/false)));
+  });
+
+  MPM = PB.buildPerModuleDefaultPipeline(PassBuilder::OptimizationLevel::O2,
+                                         Debug);
+  MPM.run(*M, MAM);
+}
+
+llvm::Function *IRContext::getFunction(GlobalDecl GD) {
+  if (CodeGen == nullptr)
+    return nullptr;
+
+  CodeGen::CodeGenModule &CGM = CodeGen->CGM();
+  StringRef Name = getMangledName(CGM, GD);
+
+  auto *M = CodeGen->GetModule();
+  // There are functions which are not generated. E.g. not used operator=, etc.
+  return M->getFunction(Name);
+}
+
+llvm::Function *IRContext::getFunction(const FunctionDecl *FD) {
+  if (CodeGen == nullptr)
+    return nullptr;
+
+  // We use the complete versions of the constructors and desctructors.
+  // Use the other overload of getFunction to get the base object ctor/dtor.
+  GlobalDecl GD;
+  if (const auto *CD = dyn_cast<CXXConstructorDecl>(FD))
+    GD = GlobalDecl(CD, Ctor_Complete);
+  else if (const auto *DD = dyn_cast<CXXDestructorDecl>(FD))
+    GD = GlobalDecl(DD, Dtor_Complete);
+  else if (FD->hasAttr<CUDAGlobalAttr>())
+    GD = GlobalDecl(FD, KernelReferenceKind::Kernel);
+  else
+    GD = GlobalDecl(FD);
+
+  return getFunction(GD);
+}
Index: clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -17,10 +17,12 @@
 #include "clang/Analysis/Analyses/LiveVariables.h"
 #include "clang/Analysis/ConstructionContext.h"
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/IRContext.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/Statistic.h"
+#include "llvm/IR/Function.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/SaveAndRestore.h"
@@ -707,6 +709,16 @@
 // a conjured return value.
 void ExprEngine::conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr,
                                       ExplodedNode *Pred, ProgramStateRef State) {
+  // Query the LLVM IR whether this function is pure.
+  if (const Decl *D = Call.getRuntimeDefinition().getDecl())
+    if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+      if (FD->getDefinition())
+        if (auto *F = getIRContext()->getFunction(FD))
+          // Pure function.
+          if (F->getAttributes().hasFnAttribute(llvm::Attribute::ReadNone) ||
+              F->getAttributes().hasFnAttribute(llvm::Attribute::ReadOnly))
+            return;
+
   State = Call.invalidateRegions(currBldrCtx->blockCount(), State);
   State = bindReturnValue(Call, Pred->getLocationContext(), State);
 
Index: clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -200,24 +200,18 @@
 static const char* TagProviderName = "ExprEngine";
 
 ExprEngine::ExprEngine(cross_tu::CrossTranslationUnitContext &CTU,
-                       AnalysisManager &mgr,
+                       IRContext &IRCtx, AnalysisManager &mgr,
                        SetOfConstDecls *VisitedCalleesIn,
-                       FunctionSummariesTy *FS,
-                       InliningModes HowToInlineIn)
-    : CTU(CTU), AMgr(mgr),
+                       FunctionSummariesTy *FS, InliningModes HowToInlineIn)
+    : CTU(CTU), IRCtx(IRCtx), AMgr(mgr),
       AnalysisDeclContexts(mgr.getAnalysisDeclContextManager()),
       Engine(*this, FS, mgr.getAnalyzerOptions()), G(Engine.getGraph()),
       StateMgr(getContext(), mgr.getStoreManagerCreator(),
-               mgr.getConstraintManagerCreator(), G.getAllocator(),
-               this),
-      SymMgr(StateMgr.getSymbolManager()),
-      MRMgr(StateMgr.getRegionManager()),
-      svalBuilder(StateMgr.getSValBuilder()),
-      ObjCNoRet(mgr.getASTContext()),
-      BR(mgr, *this),
-      VisitedCallees(VisitedCalleesIn),
-      HowToInline(HowToInlineIn)
-  {
+               mgr.getConstraintManagerCreator(), G.getAllocator(), this),
+      SymMgr(StateMgr.getSymbolManager()), MRMgr(StateMgr.getRegionManager()),
+      svalBuilder(StateMgr.getSValBuilder()), ObjCNoRet(mgr.getASTContext()),
+      BR(mgr, *this), VisitedCallees(VisitedCalleesIn),
+      HowToInline(HowToInlineIn) {
   unsigned TrimInterval = mgr.options.GraphTrimInterval;
   if (TrimInterval != 0) {
     // Enable eager node reclamation when constructing the ExplodedGraph.
Index: clang/lib/StaticAnalyzer/Core/CMakeLists.txt
===================================================================
--- clang/lib/StaticAnalyzer/Core/CMakeLists.txt
+++ clang/lib/StaticAnalyzer/Core/CMakeLists.txt
@@ -31,6 +31,7 @@
   ExprEngineObjC.cpp
   FunctionSummary.cpp
   HTMLDiagnostics.cpp
+  IRContext.cpp
   IssueHash.cpp
   LoopUnrolling.cpp
   LoopWidening.cpp
@@ -52,10 +53,15 @@
   WorkList.cpp
 
   LINK_LIBS
+  LLVMAnalysis
+  LLVMCore
+  LLVMPasses
+  LLVMTransformUtils
   clangAST
   clangASTMatchers
   clangAnalysis
   clangBasic
+  clangCodeGen
   clangCrossTU
   clangFrontend
   clangLex
Index: clang/lib/CodeGen/CodeGenMangling.cpp
===================================================================
--- /dev/null
+++ clang/lib/CodeGen/CodeGenMangling.cpp
@@ -0,0 +1,25 @@
+//==--- CodeGenMangling.cpp - Get mangled names from the CodeGenModule -----==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// CodeGenMangling provides name mangling that depends on the target set for
+// the given CodeGen.
+//===----------------------------------------------------------------------===//
+
+#include "clang/CodeGen/CodeGenMangling.h"
+#include "CodeGenModule.h"
+
+using namespace llvm;
+
+namespace clang {
+namespace CodeGen {
+
+StringRef getMangledName(CodeGenModule &CGM, GlobalDecl GD) {
+  return CGM.getMangledName(GD);
+}
+
+} // namespace CodeGen
+} // namespace clang
Index: clang/lib/CodeGen/CMakeLists.txt
===================================================================
--- clang/lib/CodeGen/CMakeLists.txt
+++ clang/lib/CodeGen/CMakeLists.txt
@@ -68,6 +68,7 @@
   CodeGenABITypes.cpp
   CodeGenAction.cpp
   CodeGenFunction.cpp
+  CodeGenMangling.cpp
   CodeGenModule.cpp
   CodeGenPGO.cpp
   CodeGenTBAA.cpp
Index: clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h
+++ clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h
@@ -13,6 +13,12 @@
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
 
+#include <memory>
+
+namespace llvm {
+class LLVMContext;
+} // namespace llvm
+
 namespace clang {
 
 class Stmt;
@@ -27,11 +33,21 @@
 //===----------------------------------------------------------------------===//
 
 class AnalysisAction : public ASTFrontendAction {
+  // Cannot be a unique_ptr because then ClangFrontendTool would
+  // depend on this lib.
+  std::shared_ptr<llvm::LLVMContext> LLVMCtx;
+  std::unique_ptr<DiagnosticsEngine> CodeGenDiags;
+
 protected:
   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
                                                  StringRef InFile) override;
+
+public:
+  ~AnalysisAction();
 };
 
+std::unique_ptr<AnalysisAction> CreateAnalysisAction();
+
 /// Frontend action to parse model files.
 ///
 /// This frontend action is responsible for parsing model files. Model files can
Index: clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h
+++ clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h
@@ -24,6 +24,7 @@
 class Preprocessor;
 class DiagnosticsEngine;
 class CodeInjector;
+class CodeGenerator;
 class CompilerInstance;
 
 namespace ento {
@@ -32,6 +33,9 @@
 class CheckerRegistry;
 
 class AnalysisASTConsumer : public ASTConsumer {
+protected:
+  CodeGenerator *CG = nullptr;
+
 public:
   virtual void AddDiagnosticConsumer(PathDiagnosticConsumer *Consumer) = 0;
 
@@ -47,6 +51,8 @@
   ///   });
   virtual void
   AddCheckerRegistrationFn(std::function<void(CheckerRegistry &)> Fn) = 0;
+
+  void setCodeGen(CodeGenerator *Cg) { CG = Cg; }
 };
 
 /// CreateAnalysisConsumer - Creates an ASTConsumer to run various code
@@ -57,6 +63,6 @@
 
 } // namespace ento
 
-} // end clang namespace
+} // namespace clang
 
 #endif
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -87,6 +87,7 @@
 class ExplodedNodeSet;
 class ExplodedNode;
 class IndirectGotoNodeBuilder;
+class IRContext;
 class MemRegion;
 struct NodeBuilderContext;
 class NodeBuilderWithSinks;
@@ -140,6 +141,8 @@
 private:
   cross_tu::CrossTranslationUnitContext &CTU;
 
+  IRContext &IRCtx;
+
   AnalysisManager &AMgr;
 
   AnalysisDeclContextManager &AnalysisDeclContexts;
@@ -181,8 +184,8 @@
   InliningModes HowToInline;
 
 public:
-  ExprEngine(cross_tu::CrossTranslationUnitContext &CTU, AnalysisManager &mgr,
-             SetOfConstDecls *VisitedCalleesIn,
+  ExprEngine(cross_tu::CrossTranslationUnitContext &CTU, IRContext &IRCtx,
+             AnalysisManager &mgr, SetOfConstDecls *VisitedCalleesIn,
              FunctionSummariesTy *FS, InliningModes HowToInlineIn);
 
   virtual ~ExprEngine() = default;
@@ -224,6 +227,8 @@
     return &CTU;
   }
 
+  IRContext *getIRContext() { return &IRCtx; }
+
   const NodeBuilderContext &getBuilderContext() {
     assert(currBldrCtx);
     return *currBldrCtx;
Index: clang/include/clang/StaticAnalyzer/Core/IRContext.h
===================================================================
--- /dev/null
+++ clang/include/clang/StaticAnalyzer/Core/IRContext.h
@@ -0,0 +1,48 @@
+//== IRContext.h - Get info from the IR in CSA -*- C++ -*--------------------=//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines auxilary structures for getting data from the IR inside
+// the Clang Static Analyzer.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_IRCONTEXT_H
+#define LLVM_CLANG_STATICANALYZER_CORE_IRCONTEXT_H
+
+#include "clang/AST/GlobalDecl.h"
+
+namespace llvm {
+class Function;
+} // namespace llvm
+
+namespace clang {
+class CodeGenerator;
+class FunctionDecl;
+
+namespace ento {
+
+// Static Analyzer components can get access to the LLVM IR of a translation
+// unit throught this class.
+class IRContext {
+  // Set by AnalysisAction if the AnalyzerOptions requires that.
+  clang::CodeGenerator *&CodeGen;
+
+public:
+  IRContext(clang::CodeGenerator *&CodeGen) : CodeGen(CodeGen) {}
+  void runOptimizerPipeline();
+  llvm::Function *getFunction(GlobalDecl GD);
+  // Get the LLVM code for a function. We use the complete versions of the
+  // constructors and desctructors in this overload. Use the other overload to
+  // get the base object ctor/dtor.
+  llvm::Function *getFunction(const FunctionDecl *FD);
+};
+
+} // namespace ento
+} // namespace clang
+
+#endif
Index: clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def
+++ clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def
@@ -314,6 +314,11 @@
                 "Display the checker name for textual outputs",
                 true)
 
+ANALYZER_OPTION(bool, GenerateLLVMIR, "generate-llvm-ir",
+                "Whether to generate LLVM IR for the translation unit. "
+                "The analyzer can be more precise by using info from the IR.",
+                false)
+
 //===----------------------------------------------------------------------===//
 // Unsigned analyzer options.
 //===----------------------------------------------------------------------===//
Index: clang/include/clang/CodeGen/CodeGenMangling.h
===================================================================
--- /dev/null
+++ clang/include/clang/CodeGen/CodeGenMangling.h
@@ -0,0 +1,27 @@
+//==----- CodeGenMangling.h - Get mangled names from the CodeGenModule -----==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// CodeGenMangling provides name mangling that depends on the target set for
+// the given CodeGen.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CODEGEN_CODEGENMANGLING_H
+#define LLVM_CLANG_CODEGEN_CODEGENMANGLING_H
+
+#include "clang/AST/GlobalDecl.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+namespace CodeGen {
+class CodeGenModule;
+
+llvm::StringRef getMangledName(CodeGenModule &CGM, GlobalDecl GD);
+
+} // namespace CodeGen
+} // namespace clang
+
+#endif
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to