|
|
@@ -4,6 +4,8 @@
|
|
|
|
|
|
#include "toolchain/sem_ir/inst_fingerprinter.h"
|
|
|
|
|
|
+#include <variant>
|
|
|
+
|
|
|
#include "common/ostream.h"
|
|
|
#include "llvm/ADT/STLExtras.h"
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
|
@@ -19,7 +21,8 @@ struct Worklist {
|
|
|
// The file containing the instruction we're currently processing.
|
|
|
const File* sem_ir = nullptr;
|
|
|
// The instructions we need to compute fingerprints for.
|
|
|
- llvm::SmallVector<std::pair<const File*, InstId>> todo;
|
|
|
+ llvm::SmallVector<std::pair<const File*, std::variant<InstId, InstBlockId>>>
|
|
|
+ todo;
|
|
|
// The contents of the current instruction as accumulated so far. This is used
|
|
|
// to build a Merkle tree containing a fingerprint for the current
|
|
|
// instruction.
|
|
|
@@ -28,12 +31,6 @@ struct Worklist {
|
|
|
// the cache if not already present.
|
|
|
Map<std::pair<const File*, InstId>, uint64_t>* fingerprints;
|
|
|
|
|
|
- // Prepare to fingerprint a new instruction.
|
|
|
- auto Prepare(const File* file) -> void {
|
|
|
- sem_ir = file;
|
|
|
- contents.clear();
|
|
|
- }
|
|
|
-
|
|
|
// Finish fingerprinting and compute the fingerprint.
|
|
|
auto Finish() -> uint64_t { return llvm::stable_hash_combine(contents); }
|
|
|
|
|
|
@@ -301,7 +298,39 @@ struct Worklist {
|
|
|
auto Run() -> uint64_t {
|
|
|
CARBON_CHECK(!todo.empty());
|
|
|
while (true) {
|
|
|
- auto [next_sem_ir, next_inst_id] = todo.back();
|
|
|
+ const size_t init_size = todo.size();
|
|
|
+ auto [next_sem_ir, next_inst_id_or_block] = todo.back();
|
|
|
+
|
|
|
+ sem_ir = next_sem_ir;
|
|
|
+ contents.clear();
|
|
|
+
|
|
|
+ if (auto* inst_block_id =
|
|
|
+ std::get_if<InstBlockId>(&next_inst_id_or_block)) {
|
|
|
+ // Add all the instructions in the block so they all contribute to the
|
|
|
+ // `contents`.
|
|
|
+ Add(*inst_block_id);
|
|
|
+
|
|
|
+ // If we didn't add any more work, then we have a fingerprint for the
|
|
|
+ // instruction block, otherwise we wait until that work is completed. If
|
|
|
+ // the block is the last thing in `todo`, we return the fingerprint.
|
|
|
+ // Otherwise we would just discard it because we don't currently cache
|
|
|
+ // the fingerprint for blocks, but we really only expect `InstBlockId`
|
|
|
+ // to be at the bottom of the `todo` stack since they are not added to
|
|
|
+ // `todo` during Run().
|
|
|
+ if (todo.size() == init_size) {
|
|
|
+ auto fingerprint = Finish();
|
|
|
+ todo.pop_back();
|
|
|
+ CARBON_CHECK(todo.empty(),
|
|
|
+ "An InstBlockId was inserted into `todo` during Run()");
|
|
|
+ return fingerprint;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Move on to processing the instructions in the block; we will come
|
|
|
+ // back to this branch once they are done.
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ auto next_inst_id = std::get<InstId>(next_inst_id_or_block);
|
|
|
|
|
|
// If we already have a fingerprint for this instruction, we have nothing
|
|
|
// to do. Just pop it from `todo`.
|
|
|
@@ -317,13 +346,9 @@ struct Worklist {
|
|
|
// Keep this instruction in `todo` for now. If we add more work, we'll
|
|
|
// finish that work and process this instruction again, and if not, we'll
|
|
|
// pop the instruction at the end of the loop.
|
|
|
- size_t init_size = todo.size();
|
|
|
auto inst = next_sem_ir->insts().Get(next_inst_id);
|
|
|
auto [arg0_kind, arg1_kind] = inst.ArgKinds();
|
|
|
|
|
|
- // Prepare to fingerprint this instruction.
|
|
|
- Prepare(next_sem_ir);
|
|
|
-
|
|
|
// Add the instruction's fields to the contents.
|
|
|
Add(inst.kind());
|
|
|
|
|
|
@@ -362,17 +387,9 @@ auto InstFingerprinter::GetOrCompute(const File* file, InstId inst_id)
|
|
|
|
|
|
auto InstFingerprinter::GetOrCompute(const File* file,
|
|
|
InstBlockId inst_block_id) -> uint64_t {
|
|
|
- Worklist worklist = {.todo = {}, .fingerprints = &fingerprints_};
|
|
|
- worklist.Prepare(file);
|
|
|
- worklist.Add(inst_block_id);
|
|
|
- if (!worklist.todo.empty()) {
|
|
|
- worklist.Run();
|
|
|
- worklist.Prepare(file);
|
|
|
- worklist.Add(inst_block_id);
|
|
|
- }
|
|
|
- CARBON_CHECK(worklist.todo.empty(),
|
|
|
- "Should not require more than two passes.");
|
|
|
- return worklist.Finish();
|
|
|
+ Worklist worklist = {.todo = {{file, inst_block_id}},
|
|
|
+ .fingerprints = &fingerprints_};
|
|
|
+ return worklist.Run();
|
|
|
}
|
|
|
|
|
|
} // namespace Carbon::SemIR
|