It's not very controlled, but the way I add loops is this:
First, I make all the rooms. I use
the so-called "BSP tree" method this article talks about (except I only use it to generate the rooms, not the tunnels), although this method should work with other methods of room generation too as long as when you make each room, you keep track of where it is and where its walls are.
Anyway, I go through all the rooms, select a random wall tile, and use a pathfinder that can't use diagonals to dig a tunnel to a random wall tile of another room. Then I run through the list of rooms again and make a second tunnel in the same way, so each room will have at least two exits.
Actually, to make it more interesting, the first time I do it, the pathfinder isn't allowed to go through any already-open space. It'll curve around other rooms (and tunnels too, I think. Don't remember if it ignores them or not).
The second time, it's allowed to go wherever it wants, including through other rooms, so some rooms might have multiple exits, and tunnels will intersect other tunnels.