gp_ir/lower_consts: visit nodes in postorder

We can't modify a node until we've visited its children, or else stale
pointers could remain and bad things could happen; this also makes
lower_consts do the same things as the original lowering pass.
gp_ir: flesh out constant folding

Implement a lot more operations, and simplify some existing ones.
gp_ir: do constant folding after doing register elimination

Register elimination opens up some opportunities for constant folding,
so this order makes more sense.
gp_ir/symbols: fix memory leak
lima/gp_ir: fix the way we order root nodes

There were a couple things wrong with root_node_order():

- It checked against the first and last element of the list, meaning
  that if one of the nodes were already first or last, then it would
  miss the check and the pointer would go around the circle.
- It did the check mentioned above after checking if two pointers have
  crossed, so if the two pointers that crossed were at the ends of the
  list then we would have returned something incorrect.

Also, make it public so it can be used by other things.