Incorrect LLVM alias analysis

孤街醉人 提交于 2019-12-11 21:31:41

问题


I'm asking a question similar to this post about an LLVM alias analysis that seems to give incorrect results. Since it contains considerable re-writing, I have decided to post it as a separate question. I'm running this very simple code:

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

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

Every time my code runs into an icmp instruction, I ask whether its operands can be aliases of one another. For the first comparison it trivially answers no, but for the second comparison between %tmp2 and %tmp3 it answers yes. Here is the resulting LLVM bitcode:

; 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
}

When I looked at the specifications of the pass -basicaa in the LLVM documentation, it explicitly says that (emphasis mine):

Distinct globals, stack allocations, and heap allocations can never alias.

But this is the case here, with two different heap allocations. What's going on?

EDIT:

Here is the output of print-alias-sets

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%

ANOTHER EDIT:

Here's how I check for aliasing from within the (Loop) pass:

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:


The different heap allocations are correctly regarded as separate (i.e. non-aliasing) and you can check that by adding this instruction at the end of the entry basic block:

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

For the alias analysis to properly "kick in", you need to run it over optimized code. In this case also adding -mem2reg should do it.

Moreover, make sure that the function you're analyzing is not marked with the optnone attribute (disassemble and check in the readable IR code), which will disable optimizations for it.



来源:https://stackoverflow.com/questions/51400856/incorrect-llvm-alias-analysis

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!