将递归函数调用转换为具有成本效益的表示形式

时间:2019-03-22 20:34:18

标签: algorithm recursion optimization

我正在尝试使用一些静态分析工具来检查程序,该程序广泛使用了递归调用。从概念上讲,它是这样的:

int counter = 0;
int access = 0;

extern int nd ();  // a nondeterministic value 
void compute1();
void compute2();

int get()
{
    static int fpa[2] = {2, 2};  // each function can be called for twice
    int k = nd() % 2;
    if (fpa[k] > 0) {
        fpa[k]--;
        return k+1;
    }
    else
       return 0;
}

void check_r(int* x) {
    if (x == &counter) {
        __VERIFIER_assert(!(access == 2));
        access = 1;
    }
}

void check_w(int* x) {
    if (x == &counter) {
         __VERIFIER_assert((access == 0));
         access = 2;
    }
}

void schedule() {        
    for (int i = 0; i < 5; i++) { 
       int fp = get();
       if (fp == 0)
         return;
       elif (fp == 1)
         compute1();
       elif (fp == 2)
         compute2();
    }
}

void compute1()
{
        // some computations
        ...
        schedule(); // recursive call
        check_w(&counter); // check write access
        ...
}

void compute2()
{
        // some computations
        ...
        schedule(); //recursive call
        check_r(&counter);
        ...
}

int main()
{
        schedule();
        return 0;
}

我的初步测试表明,由于进行了递归调用,因此静态分析变得太慢而无法终止

虽然从原则上讲,我可以将递归调用重写为switch statement左右,但是问题是在递归调用schedulecompute1compute2之前函数已经执行了大量的计算,因此很难保存程序上下文以备将来使用。

我已经被困了几天来优化这种情况,但只是无法提出一个特别的解决方案。有人可以提供一些评论和建议来摆脱此处的递归调用吗?非常感谢。

1 个答案:

答案 0 :(得分:0)

在我看来,所有schedule函数正在做的事情是确定是调用compute1还是compute2,而get所做的只是确保单个函数的调用不会被重复两次。我认为从计算到调度的递归调用是没有必要的,因为不会有两个以上的调用。递归似乎暗示着,每当我们能够成功调用一个计算函数时,我们就不会再有机会再次调用计算

void schedule() {
    int chances = 1; 
    for (int i = 0; i < 5 || chances > 0; i++) { 
       int fp = get();
       if (fp == 0){
           chances--;
           if(chances < 0)
              chances = 0;
           continue; 
       }
       elif (fp == 1){
         compute1(); chances++;
       }
       elif (fp == 2){
         compute2(); chances++;
       }
    }
}

void compute1()
{
        // some computations
        ...
        //schedule(); remove 
        check_w(&counter); // check write access
        ...
}

void compute2()
{
        // some computations
        ...
        //schedule(); remove 
        check_r(&counter);
        ...
}

此代码有点令人困惑,因此请澄清我是否做出了任何错误的假设