aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Kramer <benny.kra@googlemail.com>2012-12-11 18:00:22 +0000
committerBenjamin Kramer <benny.kra@googlemail.com>2012-12-11 18:00:22 +0000
commita07b59e5e9b55033239c80552094421a01b75c8a (patch)
tree2d6cbf05264b8c79894070781061e2d0ff2f6f54
parent10b5fa283359bd423f8624c4dda11899bcc8ca9c (diff)
Speed up looking up static diagnostic infos.
Instead of doing a binary search over the whole diagnostic table (which weighs a whopping 48k on x86_64), use the existing enums to compute the index in the table. This avoids loading any unneeded data from the table and avoids littering CPU caches with it. This code is in a hot path for code with many diagnostics. 1% speedup on -fsyntax-only gcc.c, which emits a lot of warnings. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@169890 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Basic/DiagnosticIDs.cpp49
1 files changed, 41 insertions, 8 deletions
diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp
index 1237fd5db1..4716a449a7 100644
--- a/lib/Basic/DiagnosticIDs.cpp
+++ b/lib/Basic/DiagnosticIDs.cpp
@@ -107,16 +107,49 @@ static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
}
#endif
- // Search the diagnostic table with a binary search.
- StaticDiagInfoRec Find = { static_cast<unsigned short>(DiagID),
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
- const StaticDiagInfoRec *Found =
- std::lower_bound(StaticDiagInfo, StaticDiagInfo + StaticDiagInfoSize, Find);
- if (Found == StaticDiagInfo + StaticDiagInfoSize ||
- Found->DiagID != DiagID)
+ // Out of bounds diag. Can't be in the table.
+ using namespace diag;
+ if (DiagID >= DIAG_UPPER_LIMIT)
return 0;
+ // Compute the index of the requested diagnostic in the static table.
+ // 1. Add the number of diagnostics in each category preceeding the
+ // diagnostic and of the category the diagnostic is in. This gives us
+ // the offset of the category in the table.
+ // 2. Subtract the number of IDs in each category from our ID. This gives us
+ // the offset of the diagnostic in the category.
+ // This is cheaper than a binary search on the table as it doesn't touch
+ // memory at all.
+ unsigned Offset = 0;
+ unsigned ID = DiagID;
+#define DIAG_START_COMMON 0 // Sentinel value.
+#define CATEGORY(NAME, PREV) \
+ if (DiagID > DIAG_START_##NAME) { \
+ Offset += NUM_BUILTIN_##PREV##_DIAGNOSTICS - DIAG_START_##PREV; \
+ ID -= DIAG_START_##NAME - DIAG_START_##PREV + 1; \
+ }
+CATEGORY(DRIVER, COMMON)
+CATEGORY(FRONTEND, DRIVER)
+CATEGORY(SERIALIZATION, FRONTEND)
+CATEGORY(LEX, SERIALIZATION)
+CATEGORY(PARSE, LEX)
+CATEGORY(AST, PARSE)
+CATEGORY(COMMENT, AST)
+CATEGORY(SEMA, COMMENT)
+CATEGORY(ANALYSIS, SEMA)
+#undef CATEGORY
+#undef DIAG_START_COMMON
+
+ // Avoid out of bounds reads.
+ if (ID + Offset >= StaticDiagInfoSize)
+ return 0;
+
+ const StaticDiagInfoRec *Found = &StaticDiagInfo[ID + Offset];
+ // If the diag id doesn't match we found a different diag, abort. This can
+ // happen when this function is called with an ID that points into a hole in
+ // the diagID space.
+ if (Found->DiagID != DiagID)
+ return 0;
return Found;
}