This is a large patch, but only because I had to add some (optional) parameters to computeKnownBits and friends. These functions now (optionally) take a "context" instruction pointer and also a DomTree pointer, and most of the changes are just to pass this new information when it is easily available from InstSimplify, InstCombine, etc.
The significant changes are all in ValueTracking. Two main changes: First, as with the rest of the code, new parameters need to be passed around. To make this easier, I grouped them into a structure, and I made internal static versions of the relevant functions that take this structure as a parameter. The new code does as you might expect, it looks for invariant expressions that make use of the value we're trying to learn something about, attempts to pattern match that expression, and uses the result if successful.
Part of the structure being passed around inside ValueTracking is a set of already-considered invariants. This is to prevent a query using, for example, the invariant(a == b), to recurse on itself. The context and DT params are used to find applicable invariants. An invariant needs to dominate the context instruction, or come after it deterministically. In this latter case we only handle the specific case where both the invariant and the context instruction are in the same block, and we need to exclude invariants from being used to simplify their own ephemeral values (those which contribute only to the invariant) because otherwise the invariant would prove its feeding comparison trivial and would be removed.