1// RUN: mlir-opt %s -pass-pipeline='func.func(scf-for-loop-range-folding)' -split-input-file | FileCheck %s 2 3func.func @fold_one_loop(%arg0: memref<?xi32>, %arg1: index, %arg2: index) { 4 %c0 = arith.constant 0 : index 5 %c1 = arith.constant 1 : index 6 %c4 = arith.constant 4 : index 7 scf.for %i = %c0 to %arg1 step %c1 { 8 %0 = arith.addi %arg2, %i : index 9 %1 = arith.muli %0, %c4 : index 10 %2 = memref.load %arg0[%1] : memref<?xi32> 11 %3 = arith.muli %2, %2 : i32 12 memref.store %3, %arg0[%1] : memref<?xi32> 13 } 14 return 15} 16 17// CHECK-LABEL: func @fold_one_loop 18// CHECK-SAME: (%[[ARG0:.*]]: {{.*}}, %[[ARG1:.*]]: {{.*}}, %[[ARG2:.*]]: {{.*}} 19// CHECK: %[[C0:.*]] = arith.constant 0 : index 20// CHECK: %[[C1:.*]] = arith.constant 1 : index 21// CHECK: %[[C4:.*]] = arith.constant 4 : index 22// CHECK: %[[I0:.*]] = arith.addi %[[ARG2]], %[[C0]] : index 23// CHECK: %[[I1:.*]] = arith.addi %[[ARG2]], %[[ARG1]] : index 24// CHECK: %[[I2:.*]] = arith.muli %[[I1]], %[[C4]] : index 25// CHECK: %[[I3:.*]] = arith.muli %[[C1]], %[[C4]] : index 26// CHECK: scf.for %[[I:.*]] = %[[I0]] to %[[I2]] step %[[I3]] { 27// CHECK: %[[I4:.*]] = memref.load %[[ARG0]]{{\[}}%[[I]] 28// CHECK: %[[I5:.*]] = arith.muli %[[I4]], %[[I4]] : i32 29// CHECK: memref.store %[[I5]], %[[ARG0]]{{\[}}%[[I]] 30 31func.func @fold_one_loop2(%arg0: memref<?xi32>, %arg1: index, %arg2: index) { 32 %c0 = arith.constant 0 : index 33 %c1 = arith.constant 1 : index 34 %c4 = arith.constant 4 : index 35 %c10 = arith.constant 10 : index 36 scf.for %j = %c0 to %c10 step %c1 { 37 scf.for %i = %c0 to %arg1 step %c1 { 38 %0 = arith.addi %arg2, %i : index 39 %1 = arith.muli %0, %c4 : index 40 %2 = memref.load %arg0[%1] : memref<?xi32> 41 %3 = arith.muli %2, %2 : i32 42 memref.store %3, %arg0[%1] : memref<?xi32> 43 } 44 } 45 return 46} 47 48// CHECK-LABEL: func @fold_one_loop2 49// CHECK-SAME: (%[[ARG0:.*]]: {{.*}}, %[[ARG1:.*]]: {{.*}}, %[[ARG2:.*]]: {{.*}} 50// CHECK: %[[C0:.*]] = arith.constant 0 : index 51// CHECK: %[[C1:.*]] = arith.constant 1 : index 52// CHECK: %[[C4:.*]] = arith.constant 4 : index 53// CHECK: %[[C10:.*]] = arith.constant 10 : index 54// CHECK: scf.for %[[J:.*]] = %[[C0]] to %[[C10]] step %[[C1]] { 55// CHECK: %[[I0:.*]] = arith.addi %[[ARG2]], %[[C0]] : index 56// CHECK: %[[I1:.*]] = arith.addi %[[ARG2]], %[[ARG1]] : index 57// CHECK: %[[I2:.*]] = arith.muli %[[I1]], %[[C4]] : index 58// CHECK: %[[I3:.*]] = arith.muli %[[C1]], %[[C4]] : index 59// CHECK: scf.for %[[I:.*]] = %[[I0]] to %[[I2]] step %[[I3]] { 60// CHECK: %[[I4:.*]] = memref.load %[[ARG0]]{{\[}}%[[I]] 61// CHECK: %[[I5:.*]] = arith.muli %[[I4]], %[[I4]] : i32 62// CHECK: memref.store %[[I5]], %[[ARG0]]{{\[}}%[[I]] 63 64func.func @fold_two_loops(%arg0: memref<?xi32>, %arg1: index, %arg2: index) { 65 %c0 = arith.constant 0 : index 66 %c1 = arith.constant 1 : index 67 %c4 = arith.constant 4 : index 68 %c10 = arith.constant 10 : index 69 scf.for %j = %c0 to %c10 step %c1 { 70 scf.for %i = %j to %arg1 step %c1 { 71 %0 = arith.addi %arg2, %i : index 72 %1 = arith.muli %0, %c4 : index 73 %2 = memref.load %arg0[%1] : memref<?xi32> 74 %3 = arith.muli %2, %2 : i32 75 memref.store %3, %arg0[%1] : memref<?xi32> 76 } 77 } 78 return 79} 80 81// CHECK-LABEL: func @fold_two_loops 82// CHECK-SAME: (%[[ARG0:.*]]: {{.*}}, %[[ARG1:.*]]: {{.*}}, %[[ARG2:.*]]: {{.*}} 83// CHECK: %[[C0:.*]] = arith.constant 0 : index 84// CHECK: %[[C1:.*]] = arith.constant 1 : index 85// CHECK: %[[C4:.*]] = arith.constant 4 : index 86// CHECK: %[[C10:.*]] = arith.constant 10 : index 87// CHECK: %[[I0:.*]] = arith.addi %[[ARG2]], %[[C0]] : index 88// CHECK: %[[I1:.*]] = arith.addi %[[ARG2]], %[[C10]] : index 89// CHECK: scf.for %[[J:.*]] = %[[I0]] to %[[I1]] step %[[C1]] { 90// CHECK: %[[I1:.*]] = arith.addi %[[ARG2]], %[[ARG1]] : index 91// CHECK: %[[I2:.*]] = arith.muli %[[I1]], %[[C4]] : index 92// CHECK: %[[I3:.*]] = arith.muli %[[C1]], %[[C4]] : index 93// CHECK: scf.for %[[I:.*]] = %[[J]] to %[[I2]] step %[[I3]] { 94// CHECK: %[[I4:.*]] = memref.load %[[ARG0]]{{\[}}%[[I]] 95// CHECK: %[[I5:.*]] = arith.muli %[[I4]], %[[I4]] : i32 96// CHECK: memref.store %[[I5]], %[[ARG0]]{{\[}}%[[I]] 97 98// If an instruction's operands are not defined outside the loop, we cannot 99// perform the optimization, as is the case with the arith.muli below. (If 100// paired with loop invariant code motion we can continue.) 101func.func @fold_only_first_add(%arg0: memref<?xi32>, %arg1: index, %arg2: index) { 102 %c0 = arith.constant 0 : index 103 %c1 = arith.constant 1 : index 104 %c4 = arith.constant 4 : index 105 scf.for %i = %c0 to %arg1 step %c1 { 106 %0 = arith.addi %arg2, %i : index 107 %1 = arith.addi %arg2, %c4 : index 108 %2 = arith.muli %0, %1 : index 109 %3 = memref.load %arg0[%2] : memref<?xi32> 110 %4 = arith.muli %3, %3 : i32 111 memref.store %4, %arg0[%2] : memref<?xi32> 112 } 113 return 114} 115 116// CHECK-LABEL: func @fold_only_first_add 117// CHECK-SAME: (%[[ARG0:.*]]: {{.*}}, %[[ARG1:.*]]: {{.*}}, %[[ARG2:.*]]: {{.*}} 118// CHECK: %[[C0:.*]] = arith.constant 0 : index 119// CHECK: %[[C1:.*]] = arith.constant 1 : index 120// CHECK: %[[C4:.*]] = arith.constant 4 : index 121// CHECK: %[[I0:.*]] = arith.addi %[[ARG2]], %[[C0]] : index 122// CHECK: %[[I1:.*]] = arith.addi %[[ARG2]], %[[ARG1]] : index 123// CHECK: scf.for %[[I:.*]] = %[[I0]] to %[[I1]] step %[[C1]] { 124// CHECK: %[[I2:.*]] = arith.addi %[[ARG2]], %[[C4]] : index 125// CHECK: %[[I3:.*]] = arith.muli %[[I]], %[[I2]] : index 126// CHECK: %[[I4:.*]] = memref.load %[[ARG0]]{{\[}}%[[I3]] 127// CHECK: %[[I5:.*]] = arith.muli %[[I4]], %[[I4]] : i32 128// CHECK: memref.store %[[I5]], %[[ARG0]]{{\[}}%[[I3]] 129