So it turns out the Metal shader compiler has a for loop unrolling problem. Interesting how it differs from HLSL's compiler that way...