void do_step(int rmin, int rmax, int cmin, int cmax, double **grid,
             double **next_grid) {
  int k, l, j, i;
  double sum;
#pragma omp parallel for private(i, j, k) reduction(+ : sum)
  for (i = rmin; i <= rmax; i++) {
#pragma offload_transfer target(mic) in(grid                                   \
                                        : length(nrows + 2 * ncols + 2) ALLOC) \
    nocopy(next_grid                                                           \
           : length(nrows + 2 * ncols + 2))
#pragma offload target(mic) in(grid : REUSE)in(next_grid : REUSE)
    {
      for (j = cmin; j <= cmax; j++) {
        double neighbors = 0.0;
        neighbors = grid[i + 1][j + 1] + grid[i + 1][j] + grid[i + 1][j - 1] +
                    grid[i][j + 1] + grid[i][j - 1] + grid[i - 1][j + 1] +
                    grid[i - 1][j] + grid[i - 1][j - 1];
        if ((neighbors > 3.0) || (neighbors < 2.0))
          next_grid[i][j] = 0.0;
        else if (neighbors == 3.0)
          next_grid[i][j] = 1.0;
        else
          next_grid[i][j] = grid[i][j];
      }
    }
  }
#pragma offload_transfer target(mic)                                           \
    nocopy(grid, next_grid                                                     \
           : length(nrows + 2 * ncols + 2) FREE)
}


x86 assembly (clang, -O0):
<do_step>:
push   %rbp
mov    %rsp,%rbp
mov    %edi,-0x4(%rbp)
mov    %esi,-0x8(%rbp)
mov    %edx,-0xc(%rbp)
mov    %ecx,-0x10(%rbp)
mov    %r8,-0x18(%rbp)
mov    %r9,-0x20(%rbp)
mov    -0x4(%rbp),%eax
mov    %eax,-0x30(%rbp)
mov    -0x30(%rbp),%eax
cmp    -0x8(%rbp),%eax
jg     1308 <do_step+0x208>
mov    -0xc(%rbp),%eax
mov    %eax,-0x2c(%rbp)
mov    -0x2c(%rbp),%eax
cmp    -0x10(%rbp),%eax
jg     12f5 <do_step+0x1f5>
xorps  %xmm0,%xmm0
movsd  %xmm0,-0x40(%rbp)
mov    -0x18(%rbp),%rax
mov    -0x30(%rbp),%ecx
add    $0x1,%ecx
movslq %ecx,%rcx
mov    (%rax,%rcx,8),%rax
mov    -0x2c(%rbp),%ecx
add    $0x1,%ecx
movslq %ecx,%rcx
movsd  (%rax,%rcx,8),%xmm0
mov    -0x18(%rbp),%rax
mov    -0x30(%rbp),%ecx
add    $0x1,%ecx
movslq %ecx,%rcx
mov    (%rax,%rcx,8),%rax
movslq -0x2c(%rbp),%rcx
addsd  (%rax,%rcx,8),%xmm0
mov    -0x18(%rbp),%rax
mov    -0x30(%rbp),%ecx
add    $0x1,%ecx
movslq %ecx,%rcx
mov    (%rax,%rcx,8),%rax
mov    -0x2c(%rbp),%ecx
sub    $0x1,%ecx
movslq %ecx,%rcx
addsd  (%rax,%rcx,8),%xmm0
mov    -0x18(%rbp),%rax
movslq -0x30(%rbp),%rcx
mov    (%rax,%rcx,8),%rax
mov    -0x2c(%rbp),%ecx
add    $0x1,%ecx
movslq %ecx,%rcx
addsd  (%rax,%rcx,8),%xmm0
mov    -0x18(%rbp),%rax
movslq -0x30(%rbp),%rcx
mov    (%rax,%rcx,8),%rax
mov    -0x2c(%rbp),%ecx
sub    $0x1,%ecx
movslq %ecx,%rcx
addsd  (%rax,%rcx,8),%xmm0
mov    -0x18(%rbp),%rax
mov    -0x30(%rbp),%ecx
sub    $0x1,%ecx
movslq %ecx,%rcx
mov    (%rax,%rcx,8),%rax
mov    -0x2c(%rbp),%ecx
add    $0x1,%ecx
movslq %ecx,%rcx
addsd  (%rax,%rcx,8),%xmm0
mov    -0x18(%rbp),%rax
mov    -0x30(%rbp),%ecx
sub    $0x1,%ecx
movslq %ecx,%rcx
mov    (%rax,%rcx,8),%rax
movslq -0x2c(%rbp),%rcx
addsd  (%rax,%rcx,8),%xmm0
mov    -0x18(%rbp),%rax
mov    -0x30(%rbp),%ecx
sub    $0x1,%ecx
movslq %ecx,%rcx
mov    (%rax,%rcx,8),%rax
mov    -0x2c(%rbp),%ecx
sub    $0x1,%ecx
movslq %ecx,%rcx
addsd  (%rax,%rcx,8),%xmm0
movsd  %xmm0,-0x40(%rbp)
movsd  -0x40(%rbp),%xmm0
movsd  0xdc6(%rip),%xmm1
ucomisd %xmm1,%xmm0
ja     1257 <do_step+0x157>
movsd  0xdbc(%rip),%xmm0
ucomisd -0x40(%rbp),%xmm0
jbe    1274 <do_step+0x174>
mov    -0x20(%rbp),%rax
movslq -0x30(%rbp),%rcx
mov    (%rax,%rcx,8),%rax
movslq -0x2c(%rbp),%rcx
xorps  %xmm0,%xmm0
movsd  %xmm0,(%rax,%rcx,8)
jmp    12e2 <do_step+0x1e2>
movsd  -0x40(%rbp),%xmm0
movsd  0xd7f(%rip),%xmm1
ucomisd %xmm1,%xmm0
jne    12b3 <do_step+0x1b3>
jp     12b3 <do_step+0x1b3>
mov    -0x20(%rbp),%rax
movslq -0x30(%rbp),%rcx
mov    (%rax,%rcx,8),%rax
movslq -0x2c(%rbp),%rcx
movsd  0xd67(%rip),%xmm0
movsd  %xmm0,(%rax,%rcx,8)
jmp    12dd <do_step+0x1dd>
mov    -0x18(%rbp),%rax
movslq -0x30(%rbp),%rcx
mov    (%rax,%rcx,8),%rax
movslq -0x2c(%rbp),%rcx
movsd  (%rax,%rcx,8),%xmm0
mov    -0x20(%rbp),%rax
movslq -0x30(%rbp),%rcx
mov    (%rax,%rcx,8),%rax
movslq -0x2c(%rbp),%rcx
movsd  %xmm0,(%rax,%rcx,8)
jmp    12e2 <do_step+0x1e2>
jmp    12e7 <do_step+0x1e7>
mov    -0x2c(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x2c(%rbp)
jmp    1130 <do_step+0x30>
jmp    12fa <do_step+0x1fa>
mov    -0x30(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x30(%rbp)
jmp    111e <do_step+0x1e>
pop    %rbp
ret

x86 assembly (clang, -O2):
<do_step>:
push   %r15
push   %r14
push   %r12
push   %rbx
cmp    %esi,%edi
jle    1113 <do_step+0x13>
pop    %rbx
pop    %r12
pop    %r14
pop    %r15
ret
movslq %edx,%r10
movslq %edi,%rax
add    $0x1,%esi
mov    %ecx,%r14d
sub    %r10d,%r14d
add    $0x1,%r14d
shl    $0x3,%r10
movsd  0xece(%rip),%xmm0
movsd  0xece(%rip),%xmm1
movsd  0xece(%rip),%xmm2
jmp    1158 <do_step+0x58>
cs nopw 0x0(%rax,%rax,1)
xchg   %ax,%ax
mov    %r11,%rax
cmp    %r11d,%esi
je     110b <do_step+0xb>
lea    0x1(%rax),%r11
cmp    %ecx,%edx
jg     1150 <do_step+0x50>
mov    (%r9,%rax,8),%r15
add    %r10,%r15
mov    (%r8,%r11,8),%rbx
add    %r10,%rbx
mov    -0x8(%r8,%rax,8),%rdi
add    %r10,%rdi
mov    (%r8,%rax,8),%r12
add    %r10,%r12
xor    %eax,%eax
jmp    119f <do_step+0x9f>
cs nopw 0x0(%rax,%rax,1)
nopl   0x0(%rax,%rax,1)
movsd  %xmm4,(%r15,%rax,8)
add    $0x1,%rax
cmp    %eax,%r14d
je     1150 <do_step+0x50>
movsd  0x8(%rbx,%rax,8),%xmm3
addsd  (%rbx,%rax,8),%xmm3
addsd  -0x8(%rbx,%rax,8),%xmm3
addsd  0x8(%r12,%rax,8),%xmm3
addsd  -0x8(%r12,%rax,8),%xmm3
addsd  0x8(%rdi,%rax,8),%xmm3
addsd  (%rdi,%rax,8),%xmm3
addsd  -0x8(%rdi,%rax,8),%xmm3
ucomisd %xmm0,%xmm3
xorps  %xmm4,%xmm4
ja     1190 <do_step+0x90>
ucomisd %xmm3,%xmm1
ja     1190 <do_step+0x90>
ucomisd %xmm0,%xmm3
movaps %xmm2,%xmm4
jne    11e9 <do_step+0xe9>
jnp    1190 <do_step+0x90>
movsd  (%r12,%rax,8),%xmm4
jmp    1190 <do_step+0x90>

LLVM IR (-O0):
define void @do_step(i32 %0, i32 %1, i32 %2, i32 %3, double** %4, double** %5) {
%7 = alloca i32
%8 = alloca i32
%9 = alloca i32
%10 = alloca i32
%11 = alloca double**
%12 = alloca double**
%13 = alloca i32
%14 = alloca i32
%15 = alloca i32
%16 = alloca i32
%17 = alloca double
%18 = alloca double
store i32 %0, i32* %7
store i32 %1, i32* %8
store i32 %2, i32* %9
store i32 %3, i32* %10
store double** %4, double*** %11
store double** %5, double*** %12
%19 = load i32, i32* %7
store i32 %19, i32* %16
br label %20
20: ; preds = %172, %6
%21 = load i32, i32* %16
%22 = load i32, i32* %8
%23 = icmp sle i32 %21, %22
br i1 %23, label %24, label %175
24: ; preds = %20
%25 = load i32, i32* %9
store i32 %25, i32* %15
br label %26
26: ; preds = %168, %24
%27 = load i32, i32* %15
%28 = load i32, i32* %10
%29 = icmp sle i32 %27, %28
br i1 %29, label %30, label %171
30: ; preds = %26
store double 0.000000e+00, double* %18
%31 = load double**, double*** %11
%32 = load i32, i32* %16
%33 = add nsw i32 %32, 1
%34 = sext i32 %33 to i64
%35 = getelementptr inbounds double*, double** %31, i64 %34
%36 = load double*, double** %35
%37 = load i32, i32* %15
%38 = add nsw i32 %37, 1
%39 = sext i32 %38 to i64
%40 = getelementptr inbounds double, double* %36, i64 %39
%41 = load double, double* %40
%42 = load double**, double*** %11
%43 = load i32, i32* %16
%44 = add nsw i32 %43, 1
%45 = sext i32 %44 to i64
%46 = getelementptr inbounds double*, double** %42, i64 %45
%47 = load double*, double** %46
%48 = load i32, i32* %15
%49 = sext i32 %48 to i64
%50 = getelementptr inbounds double, double* %47, i64 %49
%51 = load double, double* %50
%52 = fadd double %41, %51
%53 = load double**, double*** %11
%54 = load i32, i32* %16
%55 = add nsw i32 %54, 1
%56 = sext i32 %55 to i64
%57 = getelementptr inbounds double*, double** %53, i64 %56
%58 = load double*, double** %57
%59 = load i32, i32* %15
%60 = sub nsw i32 %59, 1
%61 = sext i32 %60 to i64
%62 = getelementptr inbounds double, double* %58, i64 %61
%63 = load double, double* %62
%64 = fadd double %52, %63
%65 = load double**, double*** %11
%66 = load i32, i32* %16
%67 = sext i32 %66 to i64
%68 = getelementptr inbounds double*, double** %65, i64 %67
%69 = load double*, double** %68
%70 = load i32, i32* %15
%71 = add nsw i32 %70, 1
%72 = sext i32 %71 to i64
%73 = getelementptr inbounds double, double* %69, i64 %72
%74 = load double, double* %73
%75 = fadd double %64, %74
%76 = load double**, double*** %11
%77 = load i32, i32* %16
%78 = sext i32 %77 to i64
%79 = getelementptr inbounds double*, double** %76, i64 %78
%80 = load double*, double** %79
%81 = load i32, i32* %15
%82 = sub nsw i32 %81, 1
%83 = sext i32 %82 to i64
%84 = getelementptr inbounds double, double* %80, i64 %83
%85 = load double, double* %84
%86 = fadd double %75, %85
%87 = load double**, double*** %11
%88 = load i32, i32* %16
%89 = sub nsw i32 %88, 1
%90 = sext i32 %89 to i64
%91 = getelementptr inbounds double*, double** %87, i64 %90
%92 = load double*, double** %91
%93 = load i32, i32* %15
%94 = add nsw i32 %93, 1
%95 = sext i32 %94 to i64
%96 = getelementptr inbounds double, double* %92, i64 %95
%97 = load double, double* %96
%98 = fadd double %86, %97
%99 = load double**, double*** %11
%100 = load i32, i32* %16
%101 = sub nsw i32 %100, 1
%102 = sext i32 %101 to i64
%103 = getelementptr inbounds double*, double** %99, i64 %102
%104 = load double*, double** %103
%105 = load i32, i32* %15
%106 = sext i32 %105 to i64
%107 = getelementptr inbounds double, double* %104, i64 %106
%108 = load double, double* %107
%109 = fadd double %98, %108
%110 = load double**, double*** %11
%111 = load i32, i32* %16
%112 = sub nsw i32 %111, 1
%113 = sext i32 %112 to i64
%114 = getelementptr inbounds double*, double** %110, i64 %113
%115 = load double*, double** %114
%116 = load i32, i32* %15
%117 = sub nsw i32 %116, 1
%118 = sext i32 %117 to i64
%119 = getelementptr inbounds double, double* %115, i64 %118
%120 = load double, double* %119
%121 = fadd double %109, %120
store double %121, double* %18
%122 = load double, double* %18
%123 = fcmp ogt double %122, 3.000000e+00
br i1 %123, label %127, label %124
124: ; preds = %30
%125 = load double, double* %18
%126 = fcmp olt double %125, 2.000000e+00
br i1 %126, label %127, label %136
127: ; preds = %124, %30
%128 = load double**, double*** %12
%129 = load i32, i32* %16
%130 = sext i32 %129 to i64
%131 = getelementptr inbounds double*, double** %128, i64 %130
%132 = load double*, double** %131
%133 = load i32, i32* %15
%134 = sext i32 %133 to i64
%135 = getelementptr inbounds double, double* %132, i64 %134
store double 0.000000e+00, double* %135
br label %167
136: ; preds = %124
%137 = load double, double* %18
%138 = fcmp oeq double %137, 3.000000e+00
br i1 %138, label %139, label %148
139: ; preds = %136
%140 = load double**, double*** %12
%141 = load i32, i32* %16
%142 = sext i32 %141 to i64
%143 = getelementptr inbounds double*, double** %140, i64 %142
%144 = load double*, double** %143
%145 = load i32, i32* %15
%146 = sext i32 %145 to i64
%147 = getelementptr inbounds double, double* %144, i64 %146
store double 1.000000e+00, double* %147
br label %166
148: ; preds = %136
%149 = load double**, double*** %11
%150 = load i32, i32* %16
%151 = sext i32 %150 to i64
%152 = getelementptr inbounds double*, double** %149, i64 %151
%153 = load double*, double** %152
%154 = load i32, i32* %15
%155 = sext i32 %154 to i64
%156 = getelementptr inbounds double, double* %153, i64 %155
%157 = load double, double* %156
%158 = load double**, double*** %12
%159 = load i32, i32* %16
%160 = sext i32 %159 to i64
%161 = getelementptr inbounds double*, double** %158, i64 %160
%162 = load double*, double** %161
%163 = load i32, i32* %15
%164 = sext i32 %163 to i64
%165 = getelementptr inbounds double, double* %162, i64 %164
store double %157, double* %165
br label %166
166: ; preds = %148, %139
br label %167
167: ; preds = %166, %127
br label %168
168: ; preds = %167
%169 = load i32, i32* %15
%170 = add nsw i32 %169, 1
store i32 %170, i32* %15
br label %26
171: ; preds = %26
br label %172
172: ; preds = %171
%173 = load i32, i32* %16
%174 = add nsw i32 %173, 1
store i32 %174, i32* %16
br label %20
175: ; preds = %20
ret void
}

LLVM IR (-O2):
define void @do_step(i32 %0, i32 %1, i32 %2, i32 %3, double** nocapture %4, double** nocapture %5) {
%7 = icmp sgt i32 %0, %1
br i1 %7, label %70, label %8
8: ; preds = %6
%9 = icmp sgt i32 %2, %3
%10 = sext i32 %2 to i64
%11 = add i32 %3, 1
%12 = sext i32 %0 to i64
%13 = add i32 %1, 1
br label %14
14: ; preds = %8, %67
%15 = phi i64 [ %12, %8 ], [ %16, %67 ]
%16 = add nsw i64 %15, 1
br i1 %9, label %67, label %17
17: ; preds = %14
%18 = getelementptr inbounds double*, double** %4, i64 %16
%19 = load double*, double** %18
%20 = getelementptr inbounds double*, double** %4, i64 %15
%21 = load double*, double** %20
%22 = add nsw i64 %15, -1
%23 = getelementptr inbounds double*, double** %4, i64 %22
%24 = load double*, double** %23
%25 = getelementptr inbounds double*, double** %5, i64 %15
%26 = load double*, double** %25
br label %27
27: ; preds = %17, %62
%28 = phi i64 [ %10, %17 ], [ %29, %62 ]
%29 = add nsw i64 %28, 1
%30 = getelementptr inbounds double, double* %19, i64 %29
%31 = load double, double* %30
%32 = getelementptr inbounds double, double* %19, i64 %28
%33 = load double, double* %32
%34 = fadd double %31, %33
%35 = add nsw i64 %28, -1
%36 = getelementptr inbounds double, double* %19, i64 %35
%37 = load double, double* %36
%38 = fadd double %34, %37
%39 = getelementptr inbounds double, double* %21, i64 %29
%40 = load double, double* %39
%41 = fadd double %38, %40
%42 = getelementptr inbounds double, double* %21, i64 %35
%43 = load double, double* %42
%44 = fadd double %41, %43
%45 = getelementptr inbounds double, double* %24, i64 %29
%46 = load double, double* %45
%47 = fadd double %44, %46
%48 = getelementptr inbounds double, double* %24, i64 %28
%49 = load double, double* %48
%50 = fadd double %47, %49
%51 = getelementptr inbounds double, double* %24, i64 %35
%52 = load double, double* %51
%53 = fadd double %50, %52
%54 = fcmp ogt double %53, 3.000000e+00
%55 = fcmp olt double %53, 2.000000e+00
%56 = or i1 %54, %55
br i1 %56, label %62, label %57
57: ; preds = %27
%58 = fcmp oeq double %53, 3.000000e+00
br i1 %58, label %62, label %59
59: ; preds = %57
%60 = getelementptr inbounds double, double* %21, i64 %28
%61 = load double, double* %60
br label %62
62: ; preds = %57, %27, %59
%63 = phi double [ %61, %59 ], [ 0.000000e+00, %27 ], [ 1.000000e+00, %57 ]
%64 = getelementptr inbounds double, double* %26, i64 %28
store double %63, double* %64
%65 = trunc i64 %29 to i32
%66 = icmp eq i32 %11, %65
br i1 %66, label %67, label %27
67: ; preds = %62, %14
%68 = trunc i64 %16 to i32
%69 = icmp eq i32 %13, %68
br i1 %69, label %70, label %14
70: ; preds = %67, %6
ret void
}