This PR significantly speeds up the whole compiler. Impala test suite runs in 23s instead of 89s on my notebook (Debug build). And this time includes firing up clang and running the actual compiled program. Apparently, we spend much time on master packing and unpacking debug infos.
Def::meta is gone
Was only used at two spots:
Memorize field names for extract expressions a#x in the frontend. We are now simply using a map instead.
For keeping track of implicits. This is now a flags of a Pi instead which is much cleaner and simpler anyway.
Sym
All strings are tossed into a global hash set - the SymPool. This one lives in a new class Driver where a few global variables live. Well, there are not really global - that's the point of the Driver class. Also, it decouples some stuff from World and fights its god class status.
Sym simply wraps const std::string* (so pass it around as value) and does ==/!= comparisons in O(1). The empty string is internally handled as nullptr. Thus, you can create a Sym representing an empty string without having access to the SymPool. The empty string, nullptr, and "\0" are all identified as Sym().
~Since creating a Sym has a slight runtime penalty (although much faster than the old solution), it's a good idea to create needed Symbols beforehand. You can see that in lower_for.h and a few other spots where I already did that but was too lazy to do it in all passes. It's only a slight penalty and hence probably hardly worth the effort. But if you feel like using this trick in your passes, the anonymous sruct and struct initialization - as I did in lower_for.h - are arguably the solution requiring the least amount of boilerplate.~
Def::dbg
This changed from const Def* to struct Dbg { Loc loc; Sym sym }.
Instead of passing const Def* dbg all over the place, all classes now have setters:
This PR significantly speeds up the whole compiler. Impala test suite runs in 23s instead of 89s on my notebook (Debug build). And this time includes firing up clang and running the actual compiled program. Apparently, we spend much time on
master
packing and unpacking debug infos.Def::meta
is goneWas only used at two spots:
a#x
in the frontend. We are now simply using a map instead.Pi
instead which is much cleaner and simpler anyway.Sym
All strings are tossed into a global hash set - the
SymPool
. This one lives in a new classDriver
where a few global variables live. Well, there are not really global - that's the point of theDriver
class. Also, it decouples some stuff fromWorld
and fights its god class status.Sym
simply wrapsconst std::string*
(so pass it around as value) and does==
/!=
comparisons in O(1). The empty string is internally handled asnullptr
. Thus, you can create aSym
representing an empty string without having access to theSymPool
. The empty string,nullptr
, and"\0"
are all identified asSym()
.~Since creating a
Sym
has a slight runtime penalty (although much faster than the old solution), it's a good idea to create neededSym
bols beforehand. You can see that inlower_for.h
and a few other spots where I already did that but was too lazy to do it in all passes. It's only a slight penalty and hence probably hardly worth the effort. But if you feel like using this trick in your passes, the anonymous sruct and struct initialization - as I did inlower_for.h
- are arguably the solution requiring the least amount of boilerplate.~Def::dbg
This changed from
const Def*
tostruct Dbg { Loc loc; Sym sym }
.Instead of passing
const Def* dbg
all over the place, all classes now have setters:Or directly set on creation:
Misc
const Def*
toRef
.