LLVM别名分析不正确

时间:2018-07-18 11:26:33

标签: llvm alias static-analysis llvm-ir

我要问一个类似于this post的问题,关于LLVM别名分析似乎给出了不正确的结果。 由于包含大量重写, 我决定将其发布为单独的问题。 我正在运行以下非常简单的代码:

char *foo()
{
    int i;
    int size;
    char *s=malloc(5);
    char *p=malloc(8);

    while ((i < size) && (s < p))
    {
        i--;
    }
    return NULL;
}

每次我的代码遇到一条icmp指令时,我都会问 其操作数可以是彼此的别名。第一次比较 它简单地回答“否”,但第二个比较 %tmp2%tmp3会回答是。 这是生成的LLVM位代码:

; Function Attrs: nounwind uwtable
define internal i8* @foo() #0 {
entry:
  %i = alloca i32, align 4
  %s = alloca i8*, align 8
  %p = alloca i8*, align 8
  %size = alloca i32, align 4
  %call = call noalias i8* @malloc(i64 8) #3
  store i8* %call, i8** %s, align 8
  %call1 = call noalias i8* @malloc(i64 13) #3
  store i8* %call1, i8** %p, align 8
  br label %while.cond

while.cond:    ; preds = %while.body, %entry
  %tmp = load i32, i32* %i, align 4
  %tmp1 = load i32, i32* %size, align 4
  %cmp = icmp sgt i32 %tmp, %tmp1
  br i1 %cmp, label %land.rhs, label %while.end

land.rhs:    ; preds = %while.cond
  %tmp2 = load i8*, i8** %p, align 8
  %tmp3 = load i8*, i8** %s, align 8
  %cmp2 = icmp ult i8* %tmp2, %tmp3
  br i1 %cmp2, label %while.body, label %while.end

while.body:    ; preds = %land.rhs
  %tmp5 = load i32, i32* %i, align 4
  %dec = add nsw i32 %tmp5, -1
  store i32 %dec, i32* %i, align 4
  br label %while.cond

while.end:    ; preds = %while.cond, %land.rhs
  ret i8* null
}

当我看规格时 the LLVM documentation-basicaa的密码,它明确表示(强调我):

  

不同的全局变量,堆栈分配和堆分配绝对不能混叠。

但是在这种情况下,有两个不同的堆分配。 发生了什么事?

编辑

这是打印别名集的输出

opt -basicaa -aa-eval -globals-aa -scev-aa -loop-simplify -instnamer -print-alias-sets -indvars -simplifycfg -view-cfg -o ./examples/input.ready.bc ./examples/input.bc
Alias Set Tracker: 4 alias sets for 4 pointer values.
  AliasSet[0x563ec3312a90, 1] must alias, Mod       Pointers: (i32* %argc.addr, 4)
  AliasSet[0x563ec3312b30, 1] must alias, Mod       Pointers: (i8*** %argv.addr, 8)
  AliasSet[0x563ec3312bd0, 1] must alias, Mod/Ref   Pointers: (i32* %i, 4)
  AliasSet[0x563ec3312c70, 2] may alias, Mod/Ref   Pointers: (i8* %arrayidx, 1)
  3 Unknown instructions: i8* %call, i32 %call1, i8* %call2

Alias Set Tracker: 3 alias sets for 3 pointer values.
  AliasSet[0x563ec3312a90, 1] must alias, Mod/Ref   Pointers: (i8** %lp.addr, 8)
  AliasSet[0x563ec3312b80, 1] must alias, Mod       Pointers: (i32* %size.addr, 4)
  AliasSet[0x563ec3312ae0, 1] must alias, Mod/Ref   Pointers: (i32* %i, 4)

Alias Set Tracker: 5 alias sets for 4 pointer values.
  AliasSet[0x563ec3312b80, 1] may alias, Mod/Ref   
  2 Unknown instructions: i8* %call, i8* %call1
  AliasSet[0x563ec3312bd0, 1] must alias, Mod/Ref   Pointers: (i8** %s, 8)
  AliasSet[0x563ec33129f0, 1] must alias, Mod/Ref   Pointers: (i8** %p, 8)
  AliasSet[0x563ec33229c0, 1] must alias, Mod/Ref   Pointers: (i32* %i, 4)
  AliasSet[0x563ec3322a60, 1] must alias, Ref       Pointers: (i32* %size, 4)

===== Alias Analysis Evaluator Report =====
  94 Total Alias Queries Performed
  73 no alias responses (77.6%)
  18 may alias responses (19.1%)
  2 partial alias responses (2.1%)
  1 must alias responses (1.0%)
  Alias Analysis Evaluator Pointer Alias Summary: 77%/19%/2%/1%
  54 Total ModRef Queries Performed
  17 no mod/ref responses (31.4%)
  0 mod responses (0.0%)
  3 ref responses (5.5%)
  34 mod & ref responses (62.9%)
  Alias Analysis Evaluator Mod/Ref Summary: 31%/0%/5%/62%

另一项编辑

这是我从(循环)传递中检查别名的方法:

virtual bool runOnLoop(Loop *loop, LPPassManager &LPM)
{       
    AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();

    for (auto it = loop->block_begin(); it != loop->block_end(); it++)
    {
        for (auto inst = (*it)->begin(); inst != (*it)->end(); inst++)
        {
            Instruction *i = (Instruction *) inst;
            if (strncmp(i->getOpcodeName(),"icmp",4) == 0)
            {
                CmpInst *ci = (CmpInst *) i;
                if (AA->isNoAlias(
                    ci->getOperand(0),
                    ci->getOperand(1)))
                {
                    errs() << ci->getOperand(0)->getName().str();
                    errs() << " and ";
                    errs() << ci->getOperand(1)->getName().str();
                    errs() << " are NOT aliases\n";
                }
                else
                {
                    errs() << ci->getOperand(0)->getName().str();
                    errs() << " and ";
                    errs() << ci->getOperand(1)->getName().str();
                    errs() << " are aliases of one another\n";
                }
            }
        }
    }

1 个答案:

答案 0 :(得分:1)

不同的堆分配被正确地认为是独立的(即非混叠),您可以通过在基本条目的末尾添加此指令来进行检查:

%cmp3 = icmp ult i8* %call, %call1

要使别名分析正确地“插入”,您需要在优化的代码上运行它。 在这种情况下,还应添加-mem2reg

此外,请确保您要分析的功能未标记有optnone属性(反汇编并检入可读的IR代码),这将禁用该功能的优化。