The compiler can move a release store of variable A past an aquire load of variable B because it violates neither constraints.
The opposite is not true: it can't move an aquire load of variable A past a release store of variable B because it violates both contraints.
For a lock, aquire/release semantics are sufficient because its only job is to protect some shared piece of data, it doesn't care about other locks.
> reordering would be bad even with different locks because it can introduce deadlocks, as somebody has pointed out.
Do you have an example of such a deadlock? Maybe it's best to work with some actual code.