|
|
|
/*
|
|
|
|
* Copyright (c) 2018-present, Facebook, Inc.
|
|
|
|
*
|
|
|
|
* This source code is licensed under the MIT license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree.
|
|
|
|
*/
|
|
|
|
|
|
|
|
class HoistIndirect {
|
|
|
|
|
|
|
|
public static int svar = 0;
|
|
|
|
public int x = 0;
|
|
|
|
int[] array;
|
|
|
|
|
|
|
|
class Test {
|
|
|
|
|
|
|
|
int a = 0;
|
|
|
|
int[] test_array;
|
|
|
|
|
|
|
|
int foo(int x) {
|
|
|
|
return x + 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_test(Test test) {
|
|
|
|
test.a = 5;
|
|
|
|
}
|
|
|
|
|
|
|
|
int get_test(Test test) {
|
|
|
|
return test.a;
|
|
|
|
}
|
|
|
|
|
|
|
|
int get_sum_test(Test test, int x) {
|
|
|
|
return test.a + x;
|
|
|
|
}
|
|
|
|
|
|
|
|
Test return_only(Test t) {
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
int indirect_modification_dont_hoist(int size, Test t) {
|
|
|
|
int d = 0;
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
|
set_test(t);
|
|
|
|
d = get_test(t); // don't hoist since t changes
|
|
|
|
}
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
void variant_arg_dont_hoist(int size, Test t) {
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
|
set_test(t); // t is invalidated
|
|
|
|
get_sum_test(return_only(t), size); // return_only's argument is variant, hence don't hoist
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// t changes deep in the call stack
|
|
|
|
int deep_modification_dont_hoist(int size) {
|
|
|
|
int d = 0;
|
|
|
|
Test t = new Test();
|
|
|
|
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
|
indirect_modification_dont_hoist(size, t);
|
|
|
|
}
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
// foo(3) is ok to hoist
|
|
|
|
int indirect_modification_hoist(int size) {
|
|
|
|
int d = 0;
|
|
|
|
Test t = new Test();
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
|
set_test(t); // t is invalidated here
|
|
|
|
d = foo(3); // foo is still invariant so it is ok to hoist
|
|
|
|
}
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_only_first_param(Test test, Test no_mod) {
|
|
|
|
test.a = 5;
|
|
|
|
}
|
|
|
|
|
|
|
|
int indirect_modification_only_second_call_hoist(int size, Test t, Test no_mod_t) {
|
|
|
|
int d = 0;
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
|
set_only_first_param(t, no_mod_t);
|
|
|
|
d = get_test(t); // don't hoist since t changes
|
|
|
|
d = get_test(no_mod_t); // hoist since no_mod_t doesn't change
|
|
|
|
}
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void set() {
|
|
|
|
svar = 5;
|
|
|
|
}
|
|
|
|
|
|
|
|
int get() {
|
|
|
|
return svar;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
int indirect_this_modification_dont_hoist(int size) {
|
|
|
|
int d = 0;
|
|
|
|
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
|
d = get(); // don't hoist since HoistIndirect.svar changes in the loop
|
|
|
|
set();
|
|
|
|
}
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
int direct_this_modification_dont_hoist_FP(int size) {
|
|
|
|
int d = 0;
|
|
|
|
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
|
d += get(); // don't hoist since this.svar changes in the loop
|
|
|
|
svar = i;
|
|
|
|
}
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
int this_modification_outside_hoist(int size) {
|
|
|
|
int d = 0;
|
|
|
|
set();
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
|
d += get(); // ok to hoist since set is outside
|
|
|
|
}
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
int arg_modification_hoist(int size, Test t) {
|
|
|
|
int d = 0;
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
|
d += get(); // ok to hoist since set_test doesn't modify this
|
|
|
|
t.set_test(t);
|
|
|
|
}
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_ith(int i, int[] array) {
|
|
|
|
array[i] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int get_ith(int i, int[] array) {
|
|
|
|
return array[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
int modified_array_dont_hoist(int size, Test t) {
|
|
|
|
int d = 0;
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
|
set_ith(i, array);
|
|
|
|
d += get_ith(size, array); // don't hoist since array changes
|
|
|
|
}
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
int independent_hoist(int size, Test t) {
|
|
|
|
int d = 0;
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
|
set_ith(i, array);
|
|
|
|
t.foo(size); // hoist call to foo
|
|
|
|
d += get_ith(size, array); // don't hoist since array changes
|
|
|
|
}
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
int modified_inner_array_dont_hoist(int size, Test t) {
|
|
|
|
int d = 0;
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
|
set_ith(i, t.test_array);
|
|
|
|
d += t.foo(t.test_array[0]); // don't hoist since t.test_array changes
|
|
|
|
}
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int regionFirst(int[] region) {
|
|
|
|
return region[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
static void incrDest(int[] source, int[] dest) {
|
|
|
|
dest[0] = source[0] + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sumDest(int[] source, int[] dest, int x) {
|
|
|
|
dest[0] = source[0] + x;
|
|
|
|
}
|
|
|
|
|
|
|
|
void irvar_change_dont_hoist(int[][] nextRegionM, int p, int[] tempRegion) {
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
|
|
if (i < regionFirst(nextRegionM[p])) {
|
|
|
|
incrDest(tempRegion, nextRegionM[p]); // invalidate nextRegionM
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void tmp_irvar_change_dont_hoist(int[][] nextRegionM, int p, int[] tempRegion) {
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
|
|
if (i < regionFirst(nextRegionM[p])) {
|
|
|
|
int[] arr = nextRegionM[p];
|
|
|
|
incrDest(tempRegion, arr); // invalidate nextRegionM
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int double_me(int p) {
|
|
|
|
return 2 * p;
|
|
|
|
}
|
|
|
|
|
|
|
|
void irvar_independent_hoist(int[][] nextRegionM, int p, int[] tempRegion) {
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
|
|
if (i < regionFirst(nextRegionM[p]) + double_me(p)) { // double_me(p) can be hoisted
|
|
|
|
sumDest(tempRegion, nextRegionM[p], i); // invalidate nextRegionM
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void unmodified_arg_hoist(int[][] nextRegionM, int p, int[] tempRegion) {
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
|
|
if (i
|
|
|
|
< regionFirst(nextRegionM[p])
|
|
|
|
+ regionFirst(tempRegion)) { // regionFirst(tempRegion) can be hoisted
|
|
|
|
sumDest(tempRegion, nextRegionM[p], i); // invalidate nextRegionM
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// arr is modified via aliasing
|
|
|
|
void alias(int[] arr) {
|
|
|
|
|
|
|
|
int[] new_arr = arr;
|
|
|
|
new_arr[0] = 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
void alias_dont_hoist_FP(int[] arr) {
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
|
|
alias(arr); // alias modifies arr
|
|
|
|
get_ith(0, arr); // don't hoist
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int return_zero() {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_x() {
|
|
|
|
x = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Since we don't keep track of what values are read in purity
|
|
|
|
// analysis, when we call set_x, we add implicit arg. "this" to
|
|
|
|
// modified arguments which prevents any other call in the loop to
|
|
|
|
// be hoisted
|
|
|
|
int indirect_this_modification_hoist_FN(int size) {
|
|
|
|
int d = 0;
|
|
|
|
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
|
d = return_zero(); // OK to hoist
|
|
|
|
set_x();
|
|
|
|
}
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
}
|