[PATCH] D50272: [tablegen] Improve performance of -gen-register-info by replacing barely-necessary std::map with a sorted vector

Roman Tereshin via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 3 15:51:30 PDT 2018


rtereshin requested changes to this revision.
rtereshin added a comment.
This revision now requires changes to proceed.

This is an impressive result, thanks for doing this!



================
Comment at: include/llvm/ADT/STLExtras.h:754
+  }
+};
+
----------------
Maybe it makes sense to do this `not_fn`-style (https://en.cppreference.com/w/cpp/utility/functional/not_fn) so it could work with function pointers and lambda-functions, not just struct-like function objects with trivial constructors.

Of course it makes sense to do that only when actually needed, not necessarily now.


================
Comment at: utils/TableGen/RegisterInfoEmitter.cpp:356
     maxLength = std::max((size_t)maxLength, RegNums.size());
-    if (DwarfRegNums.count(Reg))
-      PrintWarning(Reg->getLoc(), Twine("DWARF numbers for register ") +
-                   getQualifiedName(Reg) + "specified multiple times");
-    DwarfRegNums[Reg] = RegNums;
+    DwarfRegNums.emplace_back(Reg, RegNums);
   }
----------------
I feel like
```
DwarfRegNums.emplace_back(Reg, std::move(RegNums));  // I like to move it, move it
```
is going to make sense here: https://godbolt.org/g/rNN15d


================
Comment at: utils/TableGen/RegisterInfoEmitter.cpp:361
+  {
+    std::reverse(DwarfRegNums.begin(), DwarfRegNums.end());
+    std::stable_sort(DwarfRegNums.begin(), DwarfRegNums.end(),
----------------
I think instead of doing this `std::reverse` we could just do `std::unique` below on `rbegin`/`rend` instead of `begin`/`end` and achieve the same result with less memory churn.


================
Comment at: utils/TableGen/RegisterInfoEmitter.cpp:376
+    auto Last = std::unique(DwarfRegNums.begin(), DwarfRegNums.end(),
+                            on_first<equal>());
+    DwarfRegNums.erase(Last, DwarfRegNums.end());
----------------
Looks like the original `std::map` has uniqued the records by `!LessRecordRegister()(Reg, LastSeenReg) && !LessRecordRegister()(LastSeenReg, Reg)`, not by a pointer (see https://en.cppreference.com/w/cpp/container/map).

Maybe we could add another function object to `ADT/STLExtras.h`, something like
```
template<typename LessTy>
struct equivalent {
  LessTy less;

  template <typename A, typename B> bool operator()(A &&a, B &&b) const {
    return !less(std::forward<A>(a), std::forward<B>(b)) &&
           !less(std::forward<B>(b), std::forward<A>(a);
  }
};
```
(give or take) so we could call `std::unique(DwarfRegNums.begin(), DwarfRegNums.end(), on_first<equivalent<LessRecordRegister>>());`

More efficient way of achieving the same in this specific case I think is bringing in C++17's `not_fn` (https://en.cppreference.com/w/cpp/utility/functional/not_fn) and doing `std::unique(DwarfRegNums.begin(), DwarfRegNums.end(), not_fn(on_first<LessRecordRegister>()));`: if `a` is not less than `b` than `a` is equivalent `b` as the vector is sorted and `b` not less than `a` is already guaranteed.


================
Comment at: utils/TableGen/RegisterInfoEmitter.cpp:453
+           "Expected Alias to be present in map");
+    DwarfRegNums.emplace_back(Reg, Tmp->second);
   }
----------------
I think this immediately breaks the "sorted" invariant required for `lower_bound` to work correctly. I think we need to remember the size of the `DwarfRegNums` before the loop and do `std::lower_bound(DwarfRegNums.begin(), DwarfRegNums.begin() + DwarfRegNumsSize, ...)` instead of `std::lower_bound(DwarfRegNums.begin(), DwarfRegNums.end(), ...` to fix this. The `std::sort` after the loop will be of course still required.


Repository:
  rL LLVM

https://reviews.llvm.org/D50272





More information about the llvm-commits mailing list