aboutsummaryrefslogtreecommitdiff
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Analysis/ThreadSafety.cpp36
-rw-r--r--clang/lib/Driver/ToolChains/Flang.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Core/CallEvent.cpp31
3 files changed, 41 insertions, 29 deletions
diff --git a/clang/lib/Analysis/ThreadSafety.cpp b/clang/lib/Analysis/ThreadSafety.cpp
index d19f86a..a56fdb1 100644
--- a/clang/lib/Analysis/ThreadSafety.cpp
+++ b/clang/lib/Analysis/ThreadSafety.cpp
@@ -419,22 +419,28 @@ public:
// The expression for this variable, OR
const Expr *Exp = nullptr;
- // Reference to another VarDefinition
- unsigned Ref = 0;
+ // Direct reference to another VarDefinition
+ unsigned DirectRef = 0;
+
+ // Reference to underlying canonical non-reference VarDefinition.
+ unsigned CanonicalRef = 0;
// The map with which Exp should be interpreted.
Context Ctx;
bool isReference() const { return !Exp; }
+ void invalidateRef() { DirectRef = CanonicalRef = 0; }
+
private:
// Create ordinary variable definition
VarDefinition(const NamedDecl *D, const Expr *E, Context C)
: Dec(D), Exp(E), Ctx(C) {}
// Create reference to previous definition
- VarDefinition(const NamedDecl *D, unsigned R, Context C)
- : Dec(D), Ref(R), Ctx(C) {}
+ VarDefinition(const NamedDecl *D, unsigned DirectRef, unsigned CanonicalRef,
+ Context C)
+ : Dec(D), DirectRef(DirectRef), CanonicalRef(CanonicalRef), Ctx(C) {}
};
private:
@@ -445,7 +451,7 @@ private:
public:
LocalVariableMap() {
// index 0 is a placeholder for undefined variables (aka phi-nodes).
- VarDefinitions.push_back(VarDefinition(nullptr, 0u, getEmptyContext()));
+ VarDefinitions.push_back(VarDefinition(nullptr, 0, 0, getEmptyContext()));
}
/// Look up a definition, within the given context.
@@ -471,7 +477,7 @@ public:
Ctx = VarDefinitions[i].Ctx;
return VarDefinitions[i].Exp;
}
- i = VarDefinitions[i].Ref;
+ i = VarDefinitions[i].DirectRef;
}
return nullptr;
}
@@ -508,7 +514,7 @@ public:
void dump() {
for (unsigned i = 1, e = VarDefinitions.size(); i < e; ++i) {
const Expr *Exp = VarDefinitions[i].Exp;
- unsigned Ref = VarDefinitions[i].Ref;
+ unsigned Ref = VarDefinitions[i].DirectRef;
dumpVarDefinitionName(i);
llvm::errs() << " = ";
@@ -539,9 +545,9 @@ protected:
friend class VarMapBuilder;
// Resolve any definition ID down to its non-reference base ID.
- unsigned getCanonicalDefinitionID(unsigned ID) {
+ unsigned getCanonicalDefinitionID(unsigned ID) const {
while (ID > 0 && VarDefinitions[ID].isReference())
- ID = VarDefinitions[ID].Ref;
+ ID = VarDefinitions[ID].CanonicalRef;
return ID;
}
@@ -564,10 +570,11 @@ protected:
}
// Add a new reference to an existing definition.
- Context addReference(const NamedDecl *D, unsigned i, Context Ctx) {
+ Context addReference(const NamedDecl *D, unsigned Ref, Context Ctx) {
unsigned newID = VarDefinitions.size();
Context NewCtx = ContextFactory.add(Ctx, D, newID);
- VarDefinitions.push_back(VarDefinition(D, i, Ctx));
+ VarDefinitions.push_back(
+ VarDefinition(D, Ref, getCanonicalDefinitionID(Ref), Ctx));
return NewCtx;
}
@@ -769,15 +776,14 @@ void LocalVariableMap::intersectBackEdge(Context C1, Context C2) {
const unsigned *I2 = C2.lookup(P.first);
if (!I2) {
// Variable does not exist at the end of the loop, invalidate.
- VDef->Ref = 0;
+ VDef->invalidateRef();
continue;
}
// Compare the canonical IDs. This correctly handles chains of references
// and determines if the variable is truly loop-invariant.
- if (getCanonicalDefinitionID(VDef->Ref) != getCanonicalDefinitionID(*I2)) {
- VDef->Ref = 0; // Mark this variable as undefined
- }
+ if (VDef->CanonicalRef != getCanonicalDefinitionID(*I2))
+ VDef->invalidateRef(); // Mark this variable as undefined
}
}
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index 426bc52..a56fa41 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -822,6 +822,9 @@ static void addFloatingPointOptions(const Driver &D, const ArgList &Args,
complexRangeKindToStr(Range)));
}
+ if (Args.hasArg(options::OPT_fno_fast_real_mod))
+ CmdArgs.push_back("-fno-fast-real-mod");
+
if (!HonorINFs && !HonorNaNs && AssociativeMath && ReciprocalMath &&
ApproxFunc && !SignedZeros &&
(FPContract == "fast" || FPContract.empty())) {
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index 180056c..06ba015 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -1254,6 +1254,15 @@ template <> struct DenseMapInfo<PrivateMethodKey> {
};
} // end namespace llvm
+// NOTE: This cache is a "global" variable, and it is cleared by
+// CallEventManager's constructor so we do not keep old entries when
+// loading/unloading ASTs. If we are worried about concurrency, we may need to
+// revisit this someday. In terms of memory, this table stays around until clang
+// quits, which also may be bad if we need to release memory.
+using PrivateMethodCacheTy =
+ llvm::DenseMap<PrivateMethodKey, std::optional<const ObjCMethodDecl *>>;
+static PrivateMethodCacheTy PrivateMethodCache;
+
static const ObjCMethodDecl *
lookupRuntimeDefinition(const ObjCInterfaceDecl *Interface,
Selector LookupSelector, bool InstanceMethod) {
@@ -1262,21 +1271,8 @@ lookupRuntimeDefinition(const ObjCInterfaceDecl *Interface,
// that repeated queries on the same ObjCIntefaceDecl and Selector
// don't incur the same cost. On some test cases, we can see the
// same query being issued thousands of times.
- //
- // NOTE: This cache is essentially a "global" variable, but it
- // only gets lazily created when we get here. The value of the
- // cache probably comes from it being global across ExprEngines,
- // where the same queries may get issued. If we are worried about
- // concurrency, or possibly loading/unloading ASTs, etc., we may
- // need to revisit this someday. In terms of memory, this table
- // stays around until clang quits, which also may be bad if we
- // need to release memory.
- using PrivateMethodCache =
- llvm::DenseMap<PrivateMethodKey, std::optional<const ObjCMethodDecl *>>;
-
- static PrivateMethodCache PMC;
std::optional<const ObjCMethodDecl *> &Val =
- PMC[{Interface, LookupSelector, InstanceMethod}];
+ PrivateMethodCache[{Interface, LookupSelector, InstanceMethod}];
// Query lookupPrivateMethod() if the cache does not hit.
if (!Val) {
@@ -1422,6 +1418,13 @@ void ObjCMethodCall::getInitialStackFrameContents(
}
}
+CallEventManager::CallEventManager(llvm::BumpPtrAllocator &alloc)
+ : Alloc(alloc) {
+ // Clear the method cache to avoid hits when multiple AST are loaded/unloaded
+ // within a single process. This can happen with unit tests, for instance.
+ PrivateMethodCache.clear();
+}
+
CallEventRef<>
CallEventManager::getSimpleCall(const CallExpr *CE, ProgramStateRef State,
const LocationContext *LCtx,