[LLVMdev] Loops Prevent Function Pointer Inlining?

Nicholas White n.j.white at gmail.com
Wed Sep 24 05:51:58 PDT 2014


Hi - I've been trying to track down why a function pointer isn't being
inlined in some cases, and have nailed it down to the following repro:

struct s
{
    int (*cmp) (const void *, const void *);
    int its[2];
};

static int __uint_compare(const void *e1, const void *e2)
{
    const int *i1 = e1;
    const int *i2 = e2;
    return *i2 - *i1;
}

int main()
{
    struct s hp;
    hp.cmp = __uint_compare;
    hp.its[0] = 1;
    hp.its[1] = 2;

    for (int i = 0; i < 1; i++)
    {
        int cmp = hp.cmp(&hp.its[i], &hp.its[i + 1]);
        if(cmp < 0)
        {
            return 1;
        }
    }

    return 0;
}

I've compiled it (as test2.c) with the following commands, and have
attached the unoptimised and optimised outputs.

clang  -O0 -S -emit-llvm -o test2.ll test2.c
opt -O3 -debug -S test2.ll > test2.opt.ll 2>log2

However, if I replace the main function with the code below (test.c),
the function call to __uint_compare is inlined and the whole function
is correctly replaced with a "ret i32 0".

int main()
{
    struct s hp;
    hp.cmp = __uint_compare;
    hp.its[0] = 1;
    hp.its[1] = 2;

    int cmp = hp.cmp(&hp.its[0], &hp.its[1]);
    if(cmp < 0)
    {
        return 1;
    }

    return 0;
}

As you can see, the first example always executes the for-loop exactly
once, so the semantics of both examples are identical. From looking at
the differences in the two (attached) log files, it seems like the
problem's in the GVN pass, as only the log for the second example has:

GVN iteration: 0
GVN removed:   %5 = load i32 (i8*, i8*)** %1, align 8
GVN iteration: 1

Is this analysis correct? Or is some other pass getting tricked by the
for loop (maybe because the load & store are no longer in the same
basic block)? I was thinking of trying to fix it myself, but am not
sure exactly where in the codebase I should get started.

Thanks -

Nick
-------------- next part --------------
A non-text attachment was scrubbed...
Name: test.c
Type: text/x-csrc
Size: 368 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20140924/b915e04d/attachment.c>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: test.ll
Type: application/octet-stream
Size: 2787 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20140924/b915e04d/attachment.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: test.opt.ll
Type: application/octet-stream
Size: 716 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20140924/b915e04d/attachment-0001.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: test2.c
Type: text/x-csrc
Size: 412 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20140924/b915e04d/attachment-0001.c>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: test2.ll
Type: application/octet-stream
Size: 3486 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20140924/b915e04d/attachment-0002.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: test2.opt.ll
Type: application/octet-stream
Size: 2404 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20140924/b915e04d/attachment-0003.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: log
Type: application/octet-stream
Size: 33397 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20140924/b915e04d/attachment-0004.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: log2
Type: application/octet-stream
Size: 49499 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20140924/b915e04d/attachment-0005.obj>


More information about the llvm-dev mailing list