It turns out that during codegen I'll want to know which bindings were added for a particular constraint. Factoring that out and making sure to use it everywhere that constraints and bindings are created ensures that these will always stay in sync. It also simplifies the implementation of `normalize_equivalence_classes`, which needs to create bindings for constraints but doesn't care what they are. Also make `add_pattern_constraints` non-recursive and reuse allocations.
ISLE: Instruction Selection / Lowering Expressions
ISLE is a domain specific language (DSL) for instruction selection and lowering
clif instructions to vcode's MachInsts in Cranelift.
ISLE is a statically-typed term-rewriting language. You define rewriting rules
that map input terms (clif instructions) into output terms (MachInsts). These
rules get compiled down into Rust source test that uses a tree of match
expressions that is as good or better than what you would have written by hand.