LICM: add an optimization to move multiple loads and stores from/to the same memory location out of a loop.
This is a combination of load hoisting and store sinking, e.g.
  preheader:
    br header_block
  header_block:
    %x = load %not_aliased_addr
    // use %x and define %y
    store %y to %not_aliased_addr
    ...
  exit_block:
is transformed to:
  preheader:
    %x = load %not_aliased_addr
    br header_block
  header_block:
    // use %x and define %y
    ...
  exit_block:
    store %y to %not_aliased_addr