Skip to content

Commit

Permalink
[clang][dataflow] Expose DataflowAnalysisContext from DataflowEnviron…
Browse files Browse the repository at this point in the history
…ment.

This will eliminate the need for more pass-through APIs. Also replace pass-through usages with this exposure.

Reviewed By: ymandel, gribozavr2, xazax.hun

Differential Revision: https://reviews.llvm.org/D149464
  • Loading branch information
bazuzi authored and ymand committed May 2, 2023
1 parent 084ca63 commit 2cdb6b8
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 25 deletions.
28 changes: 19 additions & 9 deletions clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "clang/Analysis/FlowSensitive/Value.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include <memory>
#include <type_traits>
Expand Down Expand Up @@ -178,12 +179,16 @@ class Environment {
/// with a symbolic representation of the `this` pointee.
Environment(DataflowAnalysisContext &DACtx, const DeclContext &DeclCtx);

LLVM_DEPRECATED("Use getDataflowAnalysisContext().getOptions() instead.", "")
const DataflowAnalysisContext::Options &getAnalysisOptions() const {
return DACtx->getOptions();
}

LLVM_DEPRECATED("Use getDataflowAnalysisContext().arena() instead.", "")
Arena &arena() const { return DACtx->arena(); }

LLVM_DEPRECATED("Use getDataflowAnalysisContext().getOptions().Log instead.",
"")
Logger &logger() const { return *DACtx->getOptions().Log; }

/// Creates and returns an environment to use for an inline analysis of the
Expand Down Expand Up @@ -331,61 +336,61 @@ class Environment {
template <typename T, typename... Args>
std::enable_if_t<std::is_base_of<Value, T>::value, T &>
create(Args &&...args) {
return arena().create<T>(std::forward<Args>(args)...);
return DACtx->arena().create<T>(std::forward<Args>(args)...);
}

/// Returns a symbolic boolean value that models a boolean literal equal to
/// `Value`
AtomicBoolValue &getBoolLiteralValue(bool Value) const {
return arena().makeLiteral(Value);
return DACtx->arena().makeLiteral(Value);
}

/// Returns an atomic boolean value.
BoolValue &makeAtomicBoolValue() const {
return arena().create<AtomicBoolValue>();
return DACtx->arena().create<AtomicBoolValue>();
}

/// Returns a unique instance of boolean Top.
BoolValue &makeTopBoolValue() const {
return arena().create<TopBoolValue>();
return DACtx->arena().create<TopBoolValue>();
}

/// Returns a boolean value that represents the conjunction of `LHS` and
/// `RHS`. Subsequent calls with the same arguments, regardless of their
/// order, will return the same result. If the given boolean values represent
/// the same value, the result will be the value itself.
BoolValue &makeAnd(BoolValue &LHS, BoolValue &RHS) const {
return arena().makeAnd(LHS, RHS);
return DACtx->arena().makeAnd(LHS, RHS);
}

/// Returns a boolean value that represents the disjunction of `LHS` and
/// `RHS`. Subsequent calls with the same arguments, regardless of their
/// order, will return the same result. If the given boolean values represent
/// the same value, the result will be the value itself.
BoolValue &makeOr(BoolValue &LHS, BoolValue &RHS) const {
return arena().makeOr(LHS, RHS);
return DACtx->arena().makeOr(LHS, RHS);
}

/// Returns a boolean value that represents the negation of `Val`. Subsequent
/// calls with the same argument will return the same result.
BoolValue &makeNot(BoolValue &Val) const {
return arena().makeNot(Val);
return DACtx->arena().makeNot(Val);
}

/// Returns a boolean value represents `LHS` => `RHS`. Subsequent calls with
/// the same arguments, will return the same result. If the given boolean
/// values represent the same value, the result will be a value that
/// represents the true boolean literal.
BoolValue &makeImplication(BoolValue &LHS, BoolValue &RHS) const {
return arena().makeImplies(LHS, RHS);
return DACtx->arena().makeImplies(LHS, RHS);
}

/// Returns a boolean value represents `LHS` <=> `RHS`. Subsequent calls with
/// the same arguments, regardless of their order, will return the same
/// result. If the given boolean values represent the same value, the result
/// will be a value that represents the true boolean literal.
BoolValue &makeIff(BoolValue &LHS, BoolValue &RHS) const {
return arena().makeEquals(LHS, RHS);
return DACtx->arena().makeEquals(LHS, RHS);
}

/// Returns the token that identifies the flow condition of the environment.
Expand All @@ -409,10 +414,15 @@ class Environment {

/// Returns the `ControlFlowContext` registered for `F`, if any. Otherwise,
/// returns null.
LLVM_DEPRECATED(
"Use getDataflowAnalysisContext().getControlFlowContext(F) instead.", "")
const ControlFlowContext *getControlFlowContext(const FunctionDecl *F) {
return DACtx->getControlFlowContext(F);
}

/// Returns the `DataflowAnalysisContext` used by the environment.
DataflowAnalysisContext &getDataflowAnalysisContext() const { return *DACtx; }

LLVM_DUMP_METHOD void dump() const;
LLVM_DUMP_METHOD void dump(raw_ostream &OS) const;

Expand Down
10 changes: 5 additions & 5 deletions clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ void Environment::pushCallInternal(const FunctionDecl *FuncDecl,

QualType ParamType = Param->getType();
if (ParamType->isReferenceType()) {
auto &Val = arena().create<ReferenceValue>(*ArgLoc);
auto &Val = DACtx->arena().create<ReferenceValue>(*ArgLoc);
setValue(Loc, Val);
} else if (auto *ArgVal = getValue(*ArgLoc)) {
setValue(Loc, *ArgVal);
Expand Down Expand Up @@ -707,7 +707,7 @@ Value *Environment::createValueUnlessSelfReferential(
// with integers, and so distinguishing them serves no purpose, but could
// prevent convergence.
CreatedValuesCount++;
return &arena().create<IntegerValue>();
return &DACtx->arena().create<IntegerValue>();
}

if (Type->isReferenceType() || Type->isPointerType()) {
Expand All @@ -725,9 +725,9 @@ Value *Environment::createValueUnlessSelfReferential(
}

if (Type->isReferenceType())
return &arena().create<ReferenceValue>(PointeeLoc);
return &DACtx->arena().create<ReferenceValue>(PointeeLoc);
else
return &arena().create<PointerValue>(PointeeLoc);
return &DACtx->arena().create<PointerValue>(PointeeLoc);
}

if (Type->isRecordType()) {
Expand All @@ -747,7 +747,7 @@ Value *Environment::createValueUnlessSelfReferential(
Visited.erase(FieldType.getCanonicalType());
}

return &arena().create<StructValue>(std::move(FieldValues));
return &DACtx->arena().create<StructValue>(std::move(FieldValues));
}

return nullptr;
Expand Down
7 changes: 4 additions & 3 deletions clang/lib/Analysis/FlowSensitive/Transfer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
}

void VisitReturnStmt(const ReturnStmt *S) {
if (!Env.getAnalysisOptions().ContextSensitiveOpts)
if (!Env.getDataflowAnalysisContext().getOptions().ContextSensitiveOpts)
return;

auto *Ret = S->getRetValue();
Expand Down Expand Up @@ -863,12 +863,13 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
// `F` of `S`. The type `E` must be either `CallExpr` or `CXXConstructExpr`.
template <typename E>
void transferInlineCall(const E *S, const FunctionDecl *F) {
const auto &Options = Env.getAnalysisOptions();
const auto &Options = Env.getDataflowAnalysisContext().getOptions();
if (!(Options.ContextSensitiveOpts &&
Env.canDescend(Options.ContextSensitiveOpts->Depth, F)))
return;

const ControlFlowContext *CFCtx = Env.getControlFlowContext(F);
const ControlFlowContext *CFCtx =
Env.getDataflowAnalysisContext().getControlFlowContext(F);
if (!CFCtx)
return;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,8 @@ struct AnalysisContext {
llvm::ArrayRef<std::optional<TypeErasedDataflowAnalysisState>>
BlockStates)
: CFCtx(CFCtx), Analysis(Analysis), InitEnv(InitEnv),
Log(InitEnv.logger()), BlockStates(BlockStates) {
Log(*InitEnv.getDataflowAnalysisContext().getOptions().Log),
BlockStates(BlockStates) {
Log.beginAnalysis(CFCtx, Analysis);
}
~AnalysisContext() { Log.endAnalysis(); }
Expand Down
10 changes: 6 additions & 4 deletions clang/unittests/Analysis/FlowSensitive/LoggerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,16 @@ class TestAnalysis : public DataflowAnalysis<TestAnalysis, TestLattice> {

static TestLattice initialElement() { return TestLattice{}; }
void transfer(const CFGElement &, TestLattice &L, Environment &E) {
E.logger().log([](llvm::raw_ostream &OS) { OS << "transfer()"; });
E.getDataflowAnalysisContext().getOptions().Log->log(
[](llvm::raw_ostream &OS) { OS << "transfer()"; });
++L.Elements;
}
void transferBranch(bool Branch, const Stmt *S, TestLattice &L,
Environment &E) {
E.logger().log([&](llvm::raw_ostream &OS) {
OS << "transferBranch(" << Branch << ")";
});
E.getDataflowAnalysisContext().getOptions().Log->log(
[&](llvm::raw_ostream &OS) {
OS << "transferBranch(" << Branch << ")";
});
++L.Branches;
}
};
Expand Down
7 changes: 4 additions & 3 deletions clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,10 @@ void runDataflow(llvm::StringRef Code, Matcher Match,
[UseBuiltinModel = Options.BuiltinOpts.has_value()](ASTContext &C,
Environment &Env) {
return NoopAnalysis(
C, DataflowAnalysisOptions{UseBuiltinModel
? Env.getAnalysisOptions()
: std::optional<BuiltinOptions>()});
C,
DataflowAnalysisOptions{
UseBuiltinModel ? Env.getDataflowAnalysisContext().getOptions()
: std::optional<BuiltinOptions>()});
});
AI.ASTBuildArgs = ASTBuildArgs;
if (Options.BuiltinOpts)
Expand Down

0 comments on commit 2cdb6b8

Please sign in to comment.