-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clang][dataflow] Expose fields, globals, and functions referenced. #88534
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Exposes the collection functionality, but does not alter it beyond using a return value instead of output parameters. Also relocates underlying and related functions and a class from DataflowEnvironment's files to DataflowAnalysisContext's files, as no Environment is needed.
@llvm/pr-subscribers-clang-analysis @llvm/pr-subscribers-clang Author: Samira Bazuzi (bazuzi) ChangesExposes the collection functionality, but does not alter it beyond using a return value instead of output parameters. Also relocates underlying and related functions and a class from DataflowEnvironment's files to DataflowAnalysisContext's files, as no Environment is needed. Patch is 21.33 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/88534.diff 5 Files Affected:
diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
index 909a91059438ca..a34e5f603eb396 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
@@ -62,6 +62,52 @@ FieldSet getObjectFields(QualType Type);
bool containsSameFields(const FieldSet &Fields,
const RecordStorageLocation::FieldToLoc &FieldLocs);
+/// Returns the fields of a `RecordDecl` that are initialized by an
+/// `InitListExpr`, in the order in which they appear in
+/// `InitListExpr::inits()`.
+/// `Init->getType()` must be a record type.
+std::vector<const FieldDecl *>
+getFieldsForInitListExpr(const InitListExpr *InitList);
+
+/// Helper class for initialization of a record with an `InitListExpr`.
+/// `InitListExpr::inits()` contains the initializers for both the base classes
+/// and the fields of the record; this helper class separates these out into two
+/// different lists. In addition, it deals with special cases associated with
+/// unions.
+class RecordInitListHelper {
+public:
+ // `InitList` must have record type.
+ RecordInitListHelper(const InitListExpr *InitList);
+
+ // Base classes with their associated initializer expressions.
+ ArrayRef<std::pair<const CXXBaseSpecifier *, Expr *>> base_inits() const {
+ return BaseInits;
+ }
+
+ // Fields with their associated initializer expressions.
+ ArrayRef<std::pair<const FieldDecl *, Expr *>> field_inits() const {
+ return FieldInits;
+ }
+
+private:
+ SmallVector<std::pair<const CXXBaseSpecifier *, Expr *>> BaseInits;
+ SmallVector<std::pair<const FieldDecl *, Expr *>> FieldInits;
+
+ // We potentially synthesize an `ImplicitValueInitExpr` for unions. It's a
+ // member variable because we store a pointer to it in `FieldInits`.
+ std::optional<ImplicitValueInitExpr> ImplicitValueInitForUnion;
+};
+
+struct FieldsGlobalsAndFuncs {
+ FieldSet Fields;
+ // Globals includes all variables with global storage, notably including
+ // static data members and static variables declared within a function.
+ llvm::DenseSet<const VarDecl *> Globals;
+ llvm::DenseSet<const FunctionDecl *> Funcs;
+};
+
+FieldsGlobalsAndFuncs getFieldsGlobalsAndFuncs(const FunctionDecl &FD);
+
struct ContextSensitiveOptions {
/// The maximum depth to analyze. A value of zero is equivalent to disabling
/// context-sensitive analysis entirely.
diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index 706664d7db1c25..4277792219c0af 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -775,42 +775,6 @@ RecordStorageLocation *getImplicitObjectLocation(const CXXMemberCallExpr &MCE,
RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
const Environment &Env);
-/// Returns the fields of a `RecordDecl` that are initialized by an
-/// `InitListExpr`, in the order in which they appear in
-/// `InitListExpr::inits()`.
-/// `Init->getType()` must be a record type.
-std::vector<const FieldDecl *>
-getFieldsForInitListExpr(const InitListExpr *InitList);
-
-/// Helper class for initialization of a record with an `InitListExpr`.
-/// `InitListExpr::inits()` contains the initializers for both the base classes
-/// and the fields of the record; this helper class separates these out into two
-/// different lists. In addition, it deals with special cases associated with
-/// unions.
-class RecordInitListHelper {
-public:
- // `InitList` must have record type.
- RecordInitListHelper(const InitListExpr *InitList);
-
- // Base classes with their associated initializer expressions.
- ArrayRef<std::pair<const CXXBaseSpecifier *, Expr *>> base_inits() const {
- return BaseInits;
- }
-
- // Fields with their associated initializer expressions.
- ArrayRef<std::pair<const FieldDecl *, Expr *>> field_inits() const {
- return FieldInits;
- }
-
-private:
- SmallVector<std::pair<const CXXBaseSpecifier *, Expr *>> BaseInits;
- SmallVector<std::pair<const FieldDecl *, Expr *>> FieldInits;
-
- // We potentially synthesize an `ImplicitValueInitExpr` for unions. It's a
- // member variable because we store a pointer to it in `FieldInits`.
- std::optional<ImplicitValueInitExpr> ImplicitValueInitForUnion;
-};
-
/// Associates a new `RecordValue` with `Loc` and returns the new value.
RecordValue &refreshRecordValue(RecordStorageLocation &Loc, Environment &Env);
diff --git a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
index d520539dd25355..74b1299f014c66 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
@@ -55,6 +55,180 @@ FieldSet DataflowAnalysisContext::getModeledFields(QualType Type) {
return llvm::set_intersection(getObjectFields(Type), ModeledFields);
}
+std::vector<const FieldDecl *>
+getFieldsForInitListExpr(const InitListExpr *InitList) {
+ const RecordDecl *RD = InitList->getType()->getAsRecordDecl();
+ assert(RD != nullptr);
+
+ std::vector<const FieldDecl *> Fields;
+
+ if (InitList->getType()->isUnionType()) {
+ Fields.push_back(InitList->getInitializedFieldInUnion());
+ return Fields;
+ }
+
+ // Unnamed bitfields are only used for padding and do not appear in
+ // `InitListExpr`'s inits. However, those fields do appear in `RecordDecl`'s
+ // field list, and we thus need to remove them before mapping inits to
+ // fields to avoid mapping inits to the wrongs fields.
+ llvm::copy_if(
+ RD->fields(), std::back_inserter(Fields),
+ [](const FieldDecl *Field) { return !Field->isUnnamedBitfield(); });
+ return Fields;
+}
+
+RecordInitListHelper::RecordInitListHelper(const InitListExpr *InitList) {
+ auto *RD = InitList->getType()->getAsCXXRecordDecl();
+ assert(RD != nullptr);
+
+ std::vector<const FieldDecl *> Fields = getFieldsForInitListExpr(InitList);
+ ArrayRef<Expr *> Inits = InitList->inits();
+
+ // Unions initialized with an empty initializer list need special treatment.
+ // For structs/classes initialized with an empty initializer list, Clang
+ // puts `ImplicitValueInitExpr`s in `InitListExpr::inits()`, but for unions,
+ // it doesn't do this -- so we create an `ImplicitValueInitExpr` ourselves.
+ SmallVector<Expr *> InitsForUnion;
+ if (InitList->getType()->isUnionType() && Inits.empty()) {
+ assert(Fields.size() == 1);
+ ImplicitValueInitForUnion.emplace(Fields.front()->getType());
+ InitsForUnion.push_back(&*ImplicitValueInitForUnion);
+ Inits = InitsForUnion;
+ }
+
+ size_t InitIdx = 0;
+
+ assert(Fields.size() + RD->getNumBases() == Inits.size());
+ for (const CXXBaseSpecifier &Base : RD->bases()) {
+ assert(InitIdx < Inits.size());
+ Expr *Init = Inits[InitIdx++];
+ BaseInits.emplace_back(&Base, Init);
+ }
+
+ assert(Fields.size() == Inits.size() - InitIdx);
+ for (const FieldDecl *Field : Fields) {
+ assert(InitIdx < Inits.size());
+ Expr *Init = Inits[InitIdx++];
+ FieldInits.emplace_back(Field, Init);
+ }
+}
+
+static void insertIfGlobal(const Decl &D,
+ llvm::DenseSet<const VarDecl *> &Vars) {
+ if (auto *V = dyn_cast<VarDecl>(&D))
+ if (V->hasGlobalStorage())
+ Vars.insert(V);
+}
+
+static void insertIfFunction(const Decl &D,
+ llvm::DenseSet<const FunctionDecl *> &Funcs) {
+ if (auto *FD = dyn_cast<FunctionDecl>(&D))
+ Funcs.insert(FD);
+}
+
+static MemberExpr *getMemberForAccessor(const CXXMemberCallExpr &C) {
+ // Use getCalleeDecl instead of getMethodDecl in order to handle
+ // pointer-to-member calls.
+ const auto *MethodDecl = dyn_cast_or_null<CXXMethodDecl>(C.getCalleeDecl());
+ if (!MethodDecl)
+ return nullptr;
+ auto *Body = dyn_cast_or_null<CompoundStmt>(MethodDecl->getBody());
+ if (!Body || Body->size() != 1)
+ return nullptr;
+ if (auto *RS = dyn_cast<ReturnStmt>(*Body->body_begin()))
+ if (auto *Return = RS->getRetValue())
+ return dyn_cast<MemberExpr>(Return->IgnoreParenImpCasts());
+ return nullptr;
+}
+
+static void
+getFieldsGlobalsAndFuncs(const Decl &D, FieldSet &Fields,
+ llvm::DenseSet<const VarDecl *> &Vars,
+ llvm::DenseSet<const FunctionDecl *> &Funcs) {
+ insertIfGlobal(D, Vars);
+ insertIfFunction(D, Funcs);
+ if (const auto *Decomp = dyn_cast<DecompositionDecl>(&D))
+ for (const auto *B : Decomp->bindings())
+ if (auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding()))
+ // FIXME: should we be using `E->getFoundDecl()`?
+ if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
+ Fields.insert(FD);
+}
+
+/// Traverses `S` and inserts into `Fields`, `Vars` and `Funcs` any fields,
+/// global variables and functions that are declared in or referenced from
+/// sub-statements.
+static void
+getFieldsGlobalsAndFuncs(const Stmt &S, FieldSet &Fields,
+ llvm::DenseSet<const VarDecl *> &Vars,
+ llvm::DenseSet<const FunctionDecl *> &Funcs) {
+ for (auto *Child : S.children())
+ if (Child != nullptr)
+ getFieldsGlobalsAndFuncs(*Child, Fields, Vars, Funcs);
+ if (const auto *DefaultArg = dyn_cast<CXXDefaultArgExpr>(&S))
+ getFieldsGlobalsAndFuncs(*DefaultArg->getExpr(), Fields, Vars, Funcs);
+ if (const auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(&S))
+ getFieldsGlobalsAndFuncs(*DefaultInit->getExpr(), Fields, Vars, Funcs);
+
+ if (auto *DS = dyn_cast<DeclStmt>(&S)) {
+ if (DS->isSingleDecl())
+ getFieldsGlobalsAndFuncs(*DS->getSingleDecl(), Fields, Vars, Funcs);
+ else
+ for (auto *D : DS->getDeclGroup())
+ getFieldsGlobalsAndFuncs(*D, Fields, Vars, Funcs);
+ } else if (auto *E = dyn_cast<DeclRefExpr>(&S)) {
+ insertIfGlobal(*E->getDecl(), Vars);
+ insertIfFunction(*E->getDecl(), Funcs);
+ } else if (const auto *C = dyn_cast<CXXMemberCallExpr>(&S)) {
+ // If this is a method that returns a member variable but does nothing else,
+ // model the field of the return value.
+ if (MemberExpr *E = getMemberForAccessor(*C))
+ if (const auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl()))
+ Fields.insert(FD);
+ } else if (auto *E = dyn_cast<MemberExpr>(&S)) {
+ // FIXME: should we be using `E->getFoundDecl()`?
+ const ValueDecl *VD = E->getMemberDecl();
+ insertIfGlobal(*VD, Vars);
+ insertIfFunction(*VD, Funcs);
+ if (const auto *FD = dyn_cast<FieldDecl>(VD))
+ Fields.insert(FD);
+ } else if (auto *InitList = dyn_cast<InitListExpr>(&S)) {
+ if (InitList->getType()->isRecordType())
+ for (const auto *FD : getFieldsForInitListExpr(InitList))
+ Fields.insert(FD);
+ }
+}
+
+/// Collects and returns fields, global variables and functions that are
+/// declared in or referenced from `FD`.
+FieldsGlobalsAndFuncs getFieldsGlobalsAndFuncs(const FunctionDecl &FD) {
+ FieldsGlobalsAndFuncs Result;
+ // Look for global variable and field references in the
+ // constructor-initializers.
+ if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(&FD)) {
+ for (const auto *Init : CtorDecl->inits()) {
+ if (Init->isMemberInitializer()) {
+ Result.Fields.insert(Init->getMember());
+ } else if (Init->isIndirectMemberInitializer()) {
+ for (const auto *I : Init->getIndirectMember()->chain())
+ Result.Fields.insert(cast<FieldDecl>(I));
+ }
+ const Expr *E = Init->getInit();
+ assert(E != nullptr);
+ getFieldsGlobalsAndFuncs(*E, Result.Fields, Result.Globals, Result.Funcs);
+ }
+ // Add all fields mentioned in default member initializers.
+ for (const FieldDecl *F : CtorDecl->getParent()->fields())
+ if (const auto *I = F->getInClassInitializer())
+ getFieldsGlobalsAndFuncs(*I, Result.Fields, Result.Globals,
+ Result.Funcs);
+ }
+ getFieldsGlobalsAndFuncs(*FD.getBody(), Result.Fields, Result.Globals,
+ Result.Funcs);
+
+ return Result;
+}
+
void DataflowAnalysisContext::addModeledFields(const FieldSet &Fields) {
ModeledFields.set_union(Fields);
}
diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index bea15ce9bd24d1..6dae25441968de 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -304,93 +304,6 @@ widenKeyToValueMap(const llvm::MapVector<Key, Value *> &CurMap,
return WidenedMap;
}
-/// Initializes a global storage value.
-static void insertIfGlobal(const Decl &D,
- llvm::DenseSet<const VarDecl *> &Vars) {
- if (auto *V = dyn_cast<VarDecl>(&D))
- if (V->hasGlobalStorage())
- Vars.insert(V);
-}
-
-static void insertIfFunction(const Decl &D,
- llvm::DenseSet<const FunctionDecl *> &Funcs) {
- if (auto *FD = dyn_cast<FunctionDecl>(&D))
- Funcs.insert(FD);
-}
-
-static MemberExpr *getMemberForAccessor(const CXXMemberCallExpr &C) {
- // Use getCalleeDecl instead of getMethodDecl in order to handle
- // pointer-to-member calls.
- const auto *MethodDecl = dyn_cast_or_null<CXXMethodDecl>(C.getCalleeDecl());
- if (!MethodDecl)
- return nullptr;
- auto *Body = dyn_cast_or_null<CompoundStmt>(MethodDecl->getBody());
- if (!Body || Body->size() != 1)
- return nullptr;
- if (auto *RS = dyn_cast<ReturnStmt>(*Body->body_begin()))
- if (auto *Return = RS->getRetValue())
- return dyn_cast<MemberExpr>(Return->IgnoreParenImpCasts());
- return nullptr;
-}
-
-static void
-getFieldsGlobalsAndFuncs(const Decl &D, FieldSet &Fields,
- llvm::DenseSet<const VarDecl *> &Vars,
- llvm::DenseSet<const FunctionDecl *> &Funcs) {
- insertIfGlobal(D, Vars);
- insertIfFunction(D, Funcs);
- if (const auto *Decomp = dyn_cast<DecompositionDecl>(&D))
- for (const auto *B : Decomp->bindings())
- if (auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding()))
- // FIXME: should we be using `E->getFoundDecl()`?
- if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
- Fields.insert(FD);
-}
-
-/// Traverses `S` and inserts into `Fields`, `Vars` and `Funcs` any fields,
-/// global variables and functions that are declared in or referenced from
-/// sub-statements.
-static void
-getFieldsGlobalsAndFuncs(const Stmt &S, FieldSet &Fields,
- llvm::DenseSet<const VarDecl *> &Vars,
- llvm::DenseSet<const FunctionDecl *> &Funcs) {
- for (auto *Child : S.children())
- if (Child != nullptr)
- getFieldsGlobalsAndFuncs(*Child, Fields, Vars, Funcs);
- if (const auto *DefaultArg = dyn_cast<CXXDefaultArgExpr>(&S))
- getFieldsGlobalsAndFuncs(*DefaultArg->getExpr(), Fields, Vars, Funcs);
- if (const auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(&S))
- getFieldsGlobalsAndFuncs(*DefaultInit->getExpr(), Fields, Vars, Funcs);
-
- if (auto *DS = dyn_cast<DeclStmt>(&S)) {
- if (DS->isSingleDecl())
- getFieldsGlobalsAndFuncs(*DS->getSingleDecl(), Fields, Vars, Funcs);
- else
- for (auto *D : DS->getDeclGroup())
- getFieldsGlobalsAndFuncs(*D, Fields, Vars, Funcs);
- } else if (auto *E = dyn_cast<DeclRefExpr>(&S)) {
- insertIfGlobal(*E->getDecl(), Vars);
- insertIfFunction(*E->getDecl(), Funcs);
- } else if (const auto *C = dyn_cast<CXXMemberCallExpr>(&S)) {
- // If this is a method that returns a member variable but does nothing else,
- // model the field of the return value.
- if (MemberExpr *E = getMemberForAccessor(*C))
- if (const auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl()))
- Fields.insert(FD);
- } else if (auto *E = dyn_cast<MemberExpr>(&S)) {
- // FIXME: should we be using `E->getFoundDecl()`?
- const ValueDecl *VD = E->getMemberDecl();
- insertIfGlobal(*VD, Vars);
- insertIfFunction(*VD, Funcs);
- if (const auto *FD = dyn_cast<FieldDecl>(VD))
- Fields.insert(FD);
- } else if (auto *InitList = dyn_cast<InitListExpr>(&S)) {
- if (InitList->getType()->isRecordType())
- for (const auto *FD : getFieldsForInitListExpr(InitList))
- Fields.insert(FD);
- }
-}
-
namespace {
// Visitor that builds a map from record prvalues to result objects.
@@ -648,36 +561,13 @@ void Environment::initialize() {
void Environment::initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl) {
assert(FuncDecl->doesThisDeclarationHaveABody());
- FieldSet Fields;
- llvm::DenseSet<const VarDecl *> Vars;
- llvm::DenseSet<const FunctionDecl *> Funcs;
-
- // Look for global variable and field references in the
- // constructor-initializers.
- if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FuncDecl)) {
- for (const auto *Init : CtorDecl->inits()) {
- if (Init->isMemberInitializer()) {
- Fields.insert(Init->getMember());
- } else if (Init->isIndirectMemberInitializer()) {
- for (const auto *I : Init->getIndirectMember()->chain())
- Fields.insert(cast<FieldDecl>(I));
- }
- const Expr *E = Init->getInit();
- assert(E != nullptr);
- getFieldsGlobalsAndFuncs(*E, Fields, Vars, Funcs);
- }
- // Add all fields mentioned in default member initializers.
- for (const FieldDecl *F : CtorDecl->getParent()->fields())
- if (const auto *I = F->getInClassInitializer())
- getFieldsGlobalsAndFuncs(*I, Fields, Vars, Funcs);
- }
- getFieldsGlobalsAndFuncs(*FuncDecl->getBody(), Fields, Vars, Funcs);
+ FieldsGlobalsAndFuncs FGF = getFieldsGlobalsAndFuncs(*FuncDecl);
// These have to be added before the lines that follow to ensure that
// `create*` work correctly for structs.
- DACtx->addModeledFields(Fields);
+ DACtx->addModeledFields(FGF.Fields);
- for (const VarDecl *D : Vars) {
+ for (const VarDecl *D : FGF.Globals) {
if (getStorageLocation(*D) != nullptr)
continue;
@@ -689,7 +579,7 @@ void Environment::initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl) {
setStorageLocation(*D, createObject(*D, nullptr));
}
- for (const FunctionDecl *FD : Funcs) {
+ for (const FunctionDecl *FD : FGF.Funcs) {
if (getStorageLocation(*FD) != nullptr)
continue;
auto &Loc = createStorageLocation(*FD);
@@ -1349,64 +1239,6 @@ RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
return Env.get<RecordStorageLocation>(*Base);
}
-std::vector<const FieldDecl *>
-getFieldsForInitListExpr(const InitListExpr *InitList) {
- const RecordDecl *RD = InitList->getType()->getAsRecordDecl();
- assert(RD != nullptr);
-
- std::vector<const FieldDecl *> Fields;
-
- if (InitList->getType()->isUnionType()) {
- Fields.push_back(InitList->getInitializedFieldInUnion());
- return Fields;
- }
-
- // Unnamed bitfields are only used for padding and do not appear in
- // `InitListExpr`'s inits. However, those fields do appear in `RecordDecl`'s
- // field list, and we thus need to remove them before mapping inits to
- // fields to avoid mapping inits to the wrongs fields.
- llvm::copy_if(
- RD->fields(), std::back_inserter(Fields),
- [](const FieldDecl *Field) { return !Field->isUnnamedBitfield(); });
- return Fields;
-}
-
-RecordInitListHelper::RecordInitListHelper(const InitListExpr *InitList) {
- auto *RD = InitList->getType()->getAsCXXRecordDecl();
- assert(RD != nullptr);
-
- std::vector<const FieldDecl *> Fields = getFieldsForInitListExpr(InitList);
- ArrayRef<Expr *> Inits = InitList->inits();
-
- // Unions initialized with an empty initializer list need special treatment.
- // For structs/classes initialized with an empty initializer list, Clang
- // puts `ImplicitValueInitExpr`s in `InitListExpr::inits()`, but for unions,
- // it doesn't do this -- so we create an `ImplicitValueInitExpr` ourselves.
- SmallVector<Expr *> InitsForUnion;
- if (InitList->getType()->isUnionType() && Inits.empty()) {
- assert(Fields.size() == 1);
- ImplicitValueInitForUnion.emplace(Fields.front()->getType());
- Init...
[truncated]
|
@ymand Can you review and merge? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
// Globals includes all variables with global storage, notably including | ||
// static data members and static variables declared within a function. | ||
llvm::DenseSet<const VarDecl *> Globals; | ||
llvm::DenseSet<const FunctionDecl *> Funcs; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment Funcs
? I'm actually not sure offhand what that's for. :)
std::optional<ImplicitValueInitExpr> ImplicitValueInitForUnion; | ||
}; | ||
|
||
struct FieldsGlobalsAndFuncs { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe prefix "Mentioned" or "Referenced" or "Used"?
Also, please add a brief comment. In context, it's role is obvious, but for cross-referencing tools, its often helpful to have comment when you're looking at a mention in another file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My vote would be for Referenced
, and I would also suggest replacing FieldsGlobalsAndFuncs
(which is a name that IIRC has "accreted" over time). How about ReferencedDecls
(and getReferencedDecls()
), which reads better and will remain accurate if we add more types of declarations in the future?
DataflowAnalysisContext.h is starting to accumulate more and more functions that serve to extract various types of information from the AST; these aren't really related to the (I realize that this process started well before this patch, but as the purpose of this patch is to move declarations to more suitable places, maybe we should use the opportunity to create a more suitable place instead of moving them to DataflowAnalysisContext.h, which isn't really a good home for them either.) The common theme seems to be that these functions / classes all perform some operation on the AST, so maybe ASTOperations.h/.cpp? Not really a great name, but I think it's still a lot better than putting this all together with the |
/// `InitListExpr::inits()`. | ||
/// `Init->getType()` must be a record type. | ||
std::vector<const FieldDecl *> | ||
getFieldsForInitListExpr(const InitListExpr *InitList); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This appears to be used only in DataflowEnvironment.cpp -- would suggest simply making it a static function there (not exposed in any header).
(I believe it used to be that this was used more widely, but RecordInitListHelper
made that unnecessary, and I didn't notice that when I introduced this class?)
std::optional<ImplicitValueInitExpr> ImplicitValueInitForUnion; | ||
}; | ||
|
||
struct FieldsGlobalsAndFuncs { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My vote would be for Referenced
, and I would also suggest replacing FieldsGlobalsAndFuncs
(which is a name that IIRC has "accreted" over time). How about ReferencedDecls
(and getReferencedDecls()
), which reads better and will remain accurate if we add more types of declarations in the future?
llvm::DenseSet<const FunctionDecl *> Funcs; | ||
}; | ||
|
||
FieldsGlobalsAndFuncs getFieldsGlobalsAndFuncs(const FunctionDecl &FD); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a short comment for this function?
…rtion (llvm#88500) Tensor copy insertion currently uses memory_space = 0 when creating a tensor copy using alloc_tensor. This memory space should instead be the default memory space provided in bufferization options.
### Assembly Tests This adds assembly tests for ``` lcdfr, lndfr, lpdfr ``` ### Disassembly Tests This also adds a number of disassembly tests for the following menmonics: ``` cgit, cgrt, cit, clfit, clgit, clgrt, clgt, clrt, clt, crt, lcdfr, lndfr, lpdfr ``` For `cutfu` / `cu12`, it also adds a check for bad register choice.
…#88495) This commit skips the expansion of the `vector.reduce.add` intrinsic on vector-enabled SystemZ targets in order to introduce custom handling of `vector.reduce.add` for legal vector types using the VSUM instructions. This is limited to full vectors with scalar types up to `i32` due to performance concerns. It also adds testing for the generation of such custom handling, and adapts the related cost computation, as well as the testing for that. The expected result is a performance boost in certain benchmarks that make heavy use of `vector.reduce.add` with other benchmarks remaining constant. For instance, the assembly for `vector.reduce.add<4 x i32>` changes from ```hlasm vmrlg %v0, %v24, %v24 vaf %v0, %v24, %v0 vrepf %v1, %v0, 1 vaf %v0, %v0, %v1 vlgvf %r2, %v0, 0 ``` to ```hlasm vgbm %v0, 0 vsumqf %v0, %v24, %v0 vlgvf %r2, %v0, 3 ```
Making the clang resource headers into an interface library instead of a custom target means that we can attach the header search paths to the library. Targets that "link" against this library will automatically have the appropriate paths added to their header search paths to find them. Then downstream projects that embed a copy of clang can query the generated `ClangTargets.cmake` file for the header location instead of attempting to compute them.
Some functions allow a null SourceManager, no SourceManager, or a SourceManager in an inconsistent argument position. Since SourceManager is generally not null and it doesn't make sense to apply renaming without one, these inconsistencies are now gone.
…lvm#88215) In 4d5e834, casts were removed for pointers but one case was missed. Add missing check.
Commit d06b923 caused a regression that breaks after a block comment adjacent to a function paramter that follows. Fixes llvm#86573.
Needed for the future patch.
…#88305) This applies the same rules we have for the scalar operands of a BUILD_VECTOR where the scalar type must match the element type or for integer vectors we allow the scalar type to be larger than the element type. Hexagon uses i32 for an FP zero vector so we allow that as an exception.
## Abstract This pull request implements [P3029R1](https://wg21.link/P3029R1). The paper discusses the current behavior of `mdspan`'s most common pointer-indices CTAD, where the `Extents` template parameter is deduced as `dextents` (dynamic extents), even when passing compile-time constant values. The author believes this behavior is suboptimal, as it doesn't take advantage of the compile-time information. The proposed change suggests deducing static extents if `integral_constant`-like constants are passed, resulting in more intuitive syntax and less error-prone code. ## Reference - [P3029R1](https://wg21.link/P3029R1) - [Draft C++ Standard: [span.syn]](https://eel.is/c++draft/span.syn) - [Draft C++ Standard: [mdspan.syn]](https://eel.is/c++draft/mdspan.syn)
This is an NFC change split from llvm#68645.
This is an NFC change split from llvm#68645.
This is an NFC change split from llvm#68645.
This PR starts caching calls to `DependencyScanningWorkerFilesystem::getRealPath()` that we use whenever we canonicalize module map path. In the case of the real VFS, this functions performs an expensive syscall that we'd like to do as rarely as possible. This PR keeps the real path out of `CachedFileSystemEntry`, since that's **immutable**; populating the real path on creation of this data structure (every stat/open) would be expensive.
Android now supports both 4kB and 16kB page sizes. The vast majority of android apps are developed on x86_64 machines. In order to provide emulators that support larger page sizes, Android emulates the page-size in x86_64 to support testing apps for large page size support. For this reason, update Android x86_64 ELFs default max-page-size to 16384 to support both 4kB and 16kB page-size devices. Increase max-page-size raises concerns of increased disk space and extra VMA slab memory. In Android, RO partitions use sparse images, so that the holes on ELFs don't allocate blocks on disk; and PackageManager ensures to punch holes in ELF-paddings on the /data partition when apps are installed. Extra VMA slab memory is addressed by the bionic loader, which extends segment VMAs to cover the gaps between consecutive segment mappings, to avoid the extra VMAs needed for the gap PROT_NONE mappings (---p). This optimization is done in the crt_pad_segment note [1] is present in the ELF. [1] https://cs.android.com/android/platform/superproject/main/+/189e480390ef13199d59e1fb54078e8b78ea6f79:bionic/libc/arch-common/bionic/crt_pad_segment.S --------- Signed-off-by: Kalesh Singh <[email protected]> Co-authored-by: Kalesh Singh <[email protected]>
Caused by commit edd7fed
`__xray_customevent` and `__xray_typedevent` are built-in functions in Clang. With -fxray-instrument, they are lowered to `__xray_CustomEvent` (with 2 arguments) or `__xray_TypedEvent` (with 3 arguments). xray patching is supported for shared objects, but they may contain `__xray_customevent` and `__xray_typedevent` references that need to be satisfied by default visibility definitions exported by the executable. lld since df54f62, like GNU ld, catches the scenario at link time.
In the future, this utility could be made to also work with iterators, including bounded iterators. We could also query the ASAN runtime for this information when it's around.
Sorry, screwed up my git push here. Going to close this to avoid hitting recent authors any more. |
Exposes the collection functionality, but does not alter it beyond using a return value instead of output parameters. Also relocates underlying and related functions and a class from DataflowEnvironment's files to DataflowAnalysisContext's files, as no Environment is needed.