Skip to content
Draft
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
7fba0ad
[clang][Driver] Add option to emit summaries
isuckatcs May 22, 2025
3d7d23a
[clang][Summary] add the summarizer skeleton
isuckatcs Jun 7, 2025
2592f08
[clang][Summary] implement summary base prototype
isuckatcs Jun 7, 2025
43c1b90
[clang][Summary] implement summary inference prototype
isuckatcs Jun 8, 2025
f1ea491
[clang][Summary] summary printing prototype
isuckatcs Jun 8, 2025
6fb6404
[clang][Driver][Summary] add a flag to specify the directory to parse…
isuckatcs Jun 8, 2025
a45d2c0
[clang][Summary] implement parsing the summaries
isuckatcs Jun 9, 2025
e6b2107
[clang][Summary] implement reduction prototype
isuckatcs Jun 10, 2025
da80bdb
[clang][Summary] make `SummaryManager` own the attributes
isuckatcs Jun 11, 2025
4964c96
[clang][Summary] only keep one constructor for `FunctionSummary`
isuckatcs Jun 11, 2025
d8c26d3
[clang][Summary] the summary manager shouldn't be reading the JSON file
isuckatcs Jun 11, 2025
b5465c1
[clang][Summary] the summary manager shouldn't contain the JSON summa…
isuckatcs Jun 11, 2025
1754b30
[clang][Summary] rename description to attr
isuckatcs Jun 11, 2025
7e27c32
[clang][Summary] more flexible merge logic
isuckatcs Jun 12, 2025
4f8acb9
[clang][Summary] refactor summaries in the compiler instance and sema
isuckatcs Jun 13, 2025
d635e32
[clang][Summary] give the summary consumer a default value to keep th…
isuckatcs Jun 13, 2025
757c0d6
[clang][Summary] change frontend action and summary interaction
isuckatcs Jun 14, 2025
f511c22
[clang][Summary] explicitly flush summary
isuckatcs Jun 14, 2025
6964f2c
[clang][analyzer][Summary] pass summaries to the analyzer
isuckatcs Jun 14, 2025
81b039f
[analyzer] don't invalidate global regions if a function doesn't writ…
isuckatcs Jun 14, 2025
016dcdb
[clang][Summary] refactor summary attributes
isuckatcs Jun 14, 2025
1155844
[Summary] move the ast matcher callback out of the attribute declaration
isuckatcs Jun 14, 2025
49937a6
[clang] don't crash if there is no summary consumer
isuckatcs Jun 14, 2025
2499ff2
[Driver][Summary] implement emitting summary next to the object file
isuckatcs Jun 14, 2025
d44d9d0
[Summary] move summary related logic into a separate library
isuckatcs Jun 14, 2025
9e94174
link clangSummary against clangIndex
isuckatcs Jun 14, 2025
41c286b
format
isuckatcs Jun 14, 2025
103956b
make the summary context in the expression engine nullptr by default
isuckatcs Jun 14, 2025
8a5a967
initialize SummaryCtx to nullptr in AnalysisConsumer
isuckatcs Jun 14, 2025
f71dd84
handle when call event doesn't have a decl
isuckatcs Jun 14, 2025
daccc50
[Summary] flag functions that call virtual funtions and non-functions
isuckatcs Jun 18, 2025
0daa24f
fix crashes
isuckatcs Jun 19, 2025
e08fac7
a few experimental changes
isuckatcs Jun 25, 2025
8739704
add new attribute that checks if a function modifies a pointer argument
isuckatcs Jun 25, 2025
8dfc609
store string in function summary
isuckatcs Jun 29, 2025
da96155
yaml serialization... complete mess
isuckatcs Jun 29, 2025
03fc645
flexible serailization
isuckatcs Jun 30, 2025
b125329
add support for summary format selection
isuckatcs Jul 1, 2025
cfd792c
format
isuckatcs Jul 1, 2025
a2b8e2d
some cleanup
isuckatcs Jul 4, 2025
d3923ce
don't generate summary format argument if not needed
isuckatcs Jul 4, 2025
449adeb
emit summaries even if obj path has no base dir path
isuckatcs Jul 4, 2025
8449340
binary serialization prototype
isuckatcs Jul 6, 2025
767e3f9
unify summary layout accross the different formats
isuckatcs Jul 11, 2025
0e88fa8
remove nowriteptrparameter
isuckatcs Jul 12, 2025
5d72937
make file processing consistent
isuckatcs Jul 12, 2025
bbfa385
fix yamls parsing performance issues
isuckatcs Jul 12, 2025
cc3e507
format
isuckatcs Jul 12, 2025
6451e5b
path
isuckatcs Jul 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -5941,6 +5941,19 @@ def save_temps : Flag<["-", "--"], "save-temps">, Flags<[NoXarchOption]>,
Visibility<[ClangOption, FlangOption, FC1Option]>,
Alias<save_temps_EQ>, AliasArgs<["cwd"]>,
HelpText<"Alias for --save-temps=cwd">;
def summaries_dir_EQ : Joined<["-", "--"], "summaries-dir=">, Flags<[NoXarchOption]>,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Read summaries about different functions from this directory">,
MarshallingInfoString<FrontendOpts<"SummaryDirPath">>;
def emit_summaries_EQ : Joined<["-", "--"], "emit-summaries=">, Flags<[NoXarchOption]>,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Save summaries about the different functions. <arg> can be set to 'cwd' for "
"current working directory, or 'obj' which will save temporary files in the "
"same directory as the final output file">;
def emit_summaries : Flag<["-", "--"], "emit-summaries">, Flags<[NoXarchOption]>,
Visibility<[ClangOption]>,
Alias<emit_summaries_EQ>, AliasArgs<["cwd"]>,
HelpText<"Alias for --emit-summaries=cwd">;
def save_stats_EQ : Joined<["-", "--"], "save-stats=">, Flags<[NoXarchOption]>,
HelpText<"Save llvm statistics.">;
def save_stats : Flag<["-", "--"], "save-stats">, Flags<[NoXarchOption]>,
Expand Down Expand Up @@ -8148,6 +8161,10 @@ defm emit_llvm_uselists : BoolOption<"", "emit-llvm-uselists",
NegFlag<SetFalse, [], [ClangOption], "Don't preserve">,
BothFlags<[], [ClangOption], " order of LLVM use-lists when serializing">>;

def summary_file : Joined<["-"], "summary-file=">,
HelpText<"Filename to write summaries about function definitions to">,
MarshallingInfoString<FrontendOpts<"SummaryFile">>;

def print_stats : Flag<["-"], "print-stats">,
HelpText<"Print performance metrics and statistics">,
MarshallingInfoFlag<FrontendOpts<"ShowStats">>;
Expand Down
38 changes: 37 additions & 1 deletion clang/include/clang/Frontend/CompilerInstance.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "clang/Lex/DependencyDirectivesScanner.h"
#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/ModuleLoader.h"
#include "clang/Summary/SummaryContext.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
Expand Down Expand Up @@ -48,6 +49,8 @@ class ModuleFile;
}

class CodeCompleteConsumer;
class SummaryContext;
class SummaryConsumer;
class DiagnosticsEngine;
class DiagnosticConsumer;
class FileManager;
Expand Down Expand Up @@ -121,6 +124,15 @@ class CompilerInstance : public ModuleLoader {
/// The code completion consumer.
std::unique_ptr<CodeCompleteConsumer> CompletionConsumer;

/// The summary consumer.
std::unique_ptr<SummaryConsumer> TheSummaryConsumer;

/// The summary context.
std::unique_ptr<SummaryContext> SummaryCtx;

/// The summary output file.
std::unique_ptr<llvm::raw_fd_ostream> SummaryOS;

/// The semantic analysis object.
std::unique_ptr<Sema> TheSema;

Expand Down Expand Up @@ -611,6 +623,29 @@ class CompilerInstance : public ModuleLoader {
/// the compiler instance takes ownership of \p Value.
void setCodeCompletionConsumer(CodeCompleteConsumer *Value);

/// @}
/// @name Summary
/// @{

bool hasSummaryContext() { return (bool)SummaryCtx; }

SummaryContext &getSummaryContext() {
assert(SummaryCtx && "Compiler instance has no summary context!");
return *SummaryCtx;
}

void createSummaryContext() { SummaryCtx.reset(new SummaryContext()); }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we assert here that we don't have a summary context yet?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure tbh. I just mirrored what other create functions such as CompilerInstance::createSema() do. Those don't assert the existence, so maybe the consumers of the class expect this kind of behaviour.


bool hasSummaryConsumer() const { return (bool)TheSummaryConsumer; }

SummaryConsumer &getSummaryConsumer() const {
assert(TheSummaryConsumer &&
"Compiler instance has no code summary consumer!");
return *TheSummaryConsumer;
}

void createSummaryConsumer();

/// @}
/// @name Frontend timer
/// @{
Expand Down Expand Up @@ -738,7 +773,8 @@ class CompilerInstance : public ModuleLoader {

/// Create the Sema object to be used for parsing.
void createSema(TranslationUnitKind TUKind,
CodeCompleteConsumer *CompletionConsumer);
CodeCompleteConsumer *CompletionConsumer,
SummaryConsumer *SummaryConsumer = nullptr);

/// Create the frontend timer and replace any existing one with it.
void createFrontendTimer();
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Frontend/FrontendOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,12 @@ class FrontendOptions {
/// minimization hints.
std::string DumpMinimizationHintsPath;

/// Filename to write summaries about function definitions to.
std::string SummaryFile;

/// The directory used to load summary files.
std::string SummaryDirPath;

public:
FrontendOptions()
: DisableFree(false), RelocatablePCH(false), ShowHelp(false),
Expand Down
8 changes: 7 additions & 1 deletion clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ class CXXBasePath;
class CXXBasePaths;
class CXXFieldCollector;
class CodeCompleteConsumer;
class SummaryContext;
class SummaryConsumer;
enum class ComparisonCategoryType : unsigned char;
class ConstraintSatisfaction;
class DarwinSDKInfo;
Expand Down Expand Up @@ -883,7 +885,9 @@ class Sema final : public SemaBase {
public:
Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
TranslationUnitKind TUKind = TU_Complete,
CodeCompleteConsumer *CompletionConsumer = nullptr);
CodeCompleteConsumer *CompletionConsumer = nullptr,
SummaryContext *SummaryCtx = nullptr,
SummaryConsumer *SummaryConsumer = nullptr);
~Sema();

/// Perform initialization that occurs after the parser has been
Expand Down Expand Up @@ -1260,6 +1264,8 @@ class Sema final : public SemaBase {
DiagnosticsEngine &Diags;
SourceManager &SourceMgr;
api_notes::APINotesManager APINotes;
SummaryContext *SummaryCtx;
SummaryConsumer *SummaryCnsmr;

/// A RAII object to enter scope of a compound statement.
class CompoundScopeRAII {
Expand Down
14 changes: 10 additions & 4 deletions clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,20 @@
#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
#include "clang/Analysis/ProgramPoint.h"
#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h"
#include "clang/Summary/SummaryContext.h"
#include "llvm/ADT/ArrayRef.h"
#include <cassert>
#include <optional>
Expand Down Expand Up @@ -178,10 +179,13 @@ class ExprEngine {
/// The flag, which specifies the mode of inlining for the engine.
InliningModes HowToInline;

const SummaryContext *SummaryCtx;

public:
ExprEngine(cross_tu::CrossTranslationUnitContext &CTU, AnalysisManager &mgr,
SetOfConstDecls *VisitedCalleesIn,
FunctionSummariesTy *FS, InliningModes HowToInlineIn);
SetOfConstDecls *VisitedCalleesIn, FunctionSummariesTy *FS,
InliningModes HowToInlineIn,
const SummaryContext *SummaryCtx = nullptr);

virtual ~ExprEngine() = default;

Expand Down Expand Up @@ -214,6 +218,8 @@ class ExprEngine {
return &CTU;
}

const SummaryContext *getSummaryCtx() { return SummaryCtx; }

const NodeBuilderContext &getBuilderContext() {
assert(currBldrCtx);
return *currBldrCtx;
Expand Down
54 changes: 54 additions & 0 deletions clang/include/clang/Summary/SummaryAttribute.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#ifndef LLVM_CLANG_SUMMARY_SUMMARYATTRIBUTE_H
#define LLVM_CLANG_SUMMARY_SUMMARYATTRIBUTE_H

#include "clang/AST/Decl.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"

namespace clang {
enum SummaryAttrKind {
NO_WRITE_GLOBAL,
};

class FunctionSummary;
class SummaryContext;

class SummaryAttr {
const SummaryAttrKind Kind;
const char *Spelling;

protected:
SummaryAttr(SummaryAttrKind Kind, const char *Spelling)
: Kind(Kind), Spelling(Spelling) {};

public:
virtual ~SummaryAttr() = default;

SummaryAttrKind getKind() const { return Kind; }
const char *getSpelling() const { return Spelling; }

virtual bool infer(const FunctionDecl *FD) const = 0;
virtual bool merge(const FunctionSummary &Caller,
const FunctionSummary &Callee) const = 0;

virtual std::string serialize() const { return std::string(Spelling); };
virtual bool parse(std::string_view input) const {
return input == Spelling;
};
};

class NoWriteGlobalAttr : public SummaryAttr {
NoWriteGlobalAttr() : SummaryAttr(NO_WRITE_GLOBAL, "no_write_global") {}

public:
bool infer(const FunctionDecl *FD) const override final;
bool merge(const FunctionSummary &Caller,
const FunctionSummary &Callee) const override final;

static bool classof(const SummaryAttr *A) {
return A->getKind() == NO_WRITE_GLOBAL;
}
friend class SummaryContext;
};
} // namespace clang

#endif // LLVM_CLANG_SUMMARY_SUMMARYATTRIBUTEH
45 changes: 45 additions & 0 deletions clang/include/clang/Summary/SummaryConsumer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#ifndef LLVM_CLANG_SUMMARY_SUMMARYCONSUMER_H
#define LLVM_CLANG_SUMMARY_SUMMARYCONSUMER_H

#include "clang/Basic/LLVM.h"
#include "llvm/Support/JSON.h"
namespace clang {
class FunctionSummary;
class SummaryContext;

class SummaryConsumer {
protected:
const SummaryContext *SummaryCtx;

public:
SummaryConsumer(const SummaryContext &SummaryCtx) : SummaryCtx(&SummaryCtx) {}
virtual ~SummaryConsumer() = default;

virtual void ProcessStartOfSourceFile() {};
virtual void ProcessFunctionSummary(const FunctionSummary &) {};
virtual void ProcessEndOfSourceFile() {};
};

class PrintingSummaryConsumer : public SummaryConsumer {
public:
PrintingSummaryConsumer(const SummaryContext &SummaryCtx, raw_ostream &OS)
: SummaryConsumer(SummaryCtx) {}
};

class JSONPrintingSummaryConsumer : public PrintingSummaryConsumer {
llvm::json::OStream JOS;

public:
JSONPrintingSummaryConsumer(const SummaryContext &SummaryCtx, raw_ostream &OS)
: PrintingSummaryConsumer(SummaryCtx, OS), JOS(OS, 2) {}

void ProcessStartOfSourceFile() override { JOS.arrayBegin(); };
void ProcessFunctionSummary(const FunctionSummary &) override;
void ProcessEndOfSourceFile() override {
JOS.arrayEnd();
JOS.flush();
};
};
} // namespace clang

#endif // LLVM_CLANG_SUMMARY_SUMMARYCONSUMER_H
60 changes: 60 additions & 0 deletions clang/include/clang/Summary/SummaryContext.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#ifndef LLVM_CLANG_SUMMARY_SUMMARYCONTEXT_H
#define LLVM_CLANG_SUMMARY_SUMMARYCONTEXT_H

#include "clang/Summary/SummaryAttribute.h"
#include "clang/Summary/SummaryConsumer.h"
#include <set>

namespace clang {
class FunctionSummary {
SmallVector<char> ID;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why SmallVector instead of a string type?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just an artifact from index::generateUSRForDecl() expecting a SmallVectorImpl<char> & as it's buffer. In the very beginning, the constructor of this class took a FunctionDecl and generated the USR into this field.

This and every other data structure used needs to be revisited throught these source files once again before the patch is finalized.

std::set<const SummaryAttr *> Attrs;
std::set<SmallVector<char>> Calls;

public:
FunctionSummary(SmallVector<char> ID, std::set<const SummaryAttr *> Attrs,
std::set<SmallVector<char>> Calls);

SmallVector<char> getID() const { return ID; }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you want to return a StringRef/ArrayRef instead?

const std::set<const SummaryAttr *> &getAttributes() const { return Attrs; }
const std::set<SmallVector<char>> &getCalls() const { return Calls; }

template <typename T> bool hasAttribute() const {
for (auto &&attr : Attrs) {
if (llvm::isa<T>(attr))
return true;
}

return false;
}

void replaceAttributes(std::set<const SummaryAttr *> Attrs) {
this->Attrs = std::move(Attrs);
}
};

class SummaryContext {
std::map<SmallVector<char>, const FunctionSummary *> IDToSummary;
std::vector<std::unique_ptr<FunctionSummary>> FunctionSummaries;

std::map<SummaryAttrKind, const SummaryAttr *> KindToAttribute;
std::vector<std::unique_ptr<SummaryAttr>> Attributes;

void CreateSummary(SmallVector<char> ID, std::set<const SummaryAttr *> Attrs,
std::set<SmallVector<char>> Calls);
bool ReduceFunctionSummary(FunctionSummary &FunctionSummary);

template <typename T> void registerAttr();

public:
SummaryContext();

const FunctionSummary *GetSummary(const FunctionDecl *FD) const;
void SummarizeFunctionBody(const FunctionDecl *FD);

void ParseSummaryFromJSON(const llvm::json::Array &Summary);
void ReduceSummaries();
};
} // namespace clang

#endif // LLVM_CLANG_SUMMARY_SUMMARYCONTEXTH
1 change: 1 addition & 0 deletions clang/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ add_subdirectory(CrossTU)
add_subdirectory(Sema)
add_subdirectory(CodeGen)
add_subdirectory(Analysis)
add_subdirectory(Summary)
add_subdirectory(Edit)
add_subdirectory(ExtractAPI)
add_subdirectory(Rewrite)
Expand Down
Loading