blob: b7b99b01799540529d72eb1f44038eab519ef092 [file] [edit]
// RUN: fir-opt -flang-licm --split-input-file %s | FileCheck %s
// RUN: fir-opt -flang-licm -debug-only=flang-licm-cache --split-input-file %s \
// RUN: -o /dev/null 2>&1 | FileCheck %s --check-prefix=STATS
// REQUIRES: asserts
// Tests checking that Flang's LICM asks the alias analysis whether a loop may
// modify a location once per loop and location, and answers the other queries
// of the same run from its cache, without changing what is hoisted. The
// -debug-only=flang-licm-cache output has one line for each run of the pass
// that made queries: the number of queries answered from the cache (hits) and
// of those that asked the alias analysis (misses).
// Two loads of one location and a load of another one, none of them modified
// in the loop: the second load of the first location is a hit, and all the
// loads are hoisted.
// CHECK-LABEL: func.func @same_location_twice(
// CHECK: %[[X:.*]] = fir.alloca i32
// CHECK: %[[Y:.*]] = fir.alloca i32
// CHECK: %[[Z:.*]] = fir.alloca i32
// CHECK: %[[A:.*]] = fir.load %[[X]] : !fir.ref<i32>
// CHECK: %[[B:.*]] = fir.load %[[X]] : !fir.ref<i32>
// CHECK: %[[C:.*]] = fir.load %[[Y]] : !fir.ref<i32>
// CHECK: fir.do_loop
// CHECK-NOT: fir.load
// CHECK: fir.store {{.*}} to %[[Z]] : !fir.ref<i32>
// STATS: flang-licm-cache: @same_location_twice: 1 hits, 2 misses
func.func @same_location_twice(%n: index) {
%c1 = arith.constant 1 : index
%x = fir.alloca i32
%y = fir.alloca i32
%z = fir.alloca i32
fir.do_loop %i = %c1 to %n step %c1 {
%a = fir.load %x : !fir.ref<i32>
%b = fir.load %x : !fir.ref<i32>
%c = fir.load %y : !fir.ref<i32>
%s = arith.addi %a, %b : i32
%t = arith.addi %s, %c : i32
fir.store %t to %z : !fir.ref<i32>
}
return
}
// -----
// The location is modified in the loop: the answer is cached as well, so the
// second load is a hit, and neither load is hoisted.
// CHECK-LABEL: func.func @modified_location(
// CHECK: %[[X:.*]] = fir.alloca i32
// CHECK: fir.do_loop
// CHECK: %[[A:.*]] = fir.load %[[X]] : !fir.ref<i32>
// CHECK: %[[B:.*]] = fir.load %[[X]] : !fir.ref<i32>
// CHECK: fir.store {{.*}} to %[[X]] : !fir.ref<i32>
// STATS: flang-licm-cache: @modified_location: 1 hits, 1 misses
func.func @modified_location(%n: index) {
%c1 = arith.constant 1 : index
%x = fir.alloca i32
fir.do_loop %i = %c1 to %n step %c1 {
%a = fir.load %x : !fir.ref<i32>
%b = fir.load %x : !fir.ref<i32>
%s = arith.addi %a, %b : i32
fir.store %s to %x : !fir.ref<i32>
}
return
}
// -----
// The cache is not shared between loops: the same location asked about for
// two loops makes two queries to the alias analysis.
// CHECK-LABEL: func.func @two_loops(
// CHECK: %[[X:.*]] = fir.alloca i32
// CHECK: fir.load %[[X]] : !fir.ref<i32>
// CHECK: fir.do_loop
// CHECK: fir.load %[[X]] : !fir.ref<i32>
// CHECK: fir.do_loop
// STATS: flang-licm-cache: @two_loops: 0 hits, 2 misses
func.func @two_loops(%n: index) {
%c1 = arith.constant 1 : index
%x = fir.alloca i32
%z = fir.alloca i32
fir.do_loop %i = %c1 to %n step %c1 {
%a = fir.load %x : !fir.ref<i32>
fir.store %a to %z : !fir.ref<i32>
}
fir.do_loop %j = %c1 to %n step %c1 {
%b = fir.load %x : !fir.ref<i32>
fir.store %b to %z : !fir.ref<i32>
}
return
}
// -----
// A run that makes no queries prints nothing.
// CHECK-LABEL: func.func @no_queries(
// STATS-NOT: @no_queries
func.func @no_queries(%n: index) {
%c1 = arith.constant 1 : index
%z = fir.alloca i32
fir.do_loop %i = %c1 to %n step %c1 {
%c = arith.constant 7 : i32
fir.store %c to %z : !fir.ref<i32>
}
return
}