This is an archive of the discontinued LLVM Phabricator instance.

[ConstantFolding] Small fix to prevent constant folding having to repeatedly scan operands.
ClosedPublic

Authored by dmgreen on Mar 7 2017, 3:09 AM.

Details

Summary

We are seeing a case where after the unroll threshold was increased in
295538, a loop is fully unrolled into very large constant expression
chains. These are recursively scanned, leading to timeouts and hence
failures. This prevents having to rescan already scanned operands.

Diff Detail

Event Timeline

dmgreen created this revision.Mar 7 2017, 3:09 AM

I've put together a little reproducer. The original case was from the preprocessed CSiBE lwip-0.5.3.preproc/src/core/memp.i source file, this shows the same thing going on:

struct ST {
    struct ST* next;
};
static char global[LOOP*sizeof(struct ST)+1];
#define ALIGN(m, y) (m + ((m%y==0) ? 0 : m%y))
void func(void)
{
    struct ST* s = (struct ST*)&global;
    for(int j = 0; j < LOOP; j++) {
        s->next = (struct ST*)ALIGN((unsigned)((char*)s+sizeof(struct ST)), 2);
        s = s->next;
    }
    s->next = 0;
}

Compiling with something like "clang -c simple.c -O3 -DLOOP=X" I get these compile times for various values of LOOP:

10 0.2
12 0.3
14 0.6
16 1.2
18 8.6
20 33.9
22 215.0

The original code looks significantly dodgy to me. From a read of the code and the intent, I think your change is right (the original code always added {FoldedC, FoldedC} which is totally bogus).

However, I think a testcase should be possible?

James

dmgreen updated this revision to Diff 91759.Mar 14 2017, 12:14 PM

Hello,

Thanks for taking a look. The only test I could come up with would be one that times out given a high enough LOOP define in the above reproducer. This patch should otherwise be an NFC.

I don't see any other examples of tests we have that are expected to not timeout, but I've come up with something that should, with the patch, compile fine. I'm not sure if it's a great test (without the fix it will just hang) but at least it's something.

Dave

jmolloy accepted this revision.Mar 15 2017, 1:53 AM

Hi David,

I agree that a hanging test is not ideal. However, if it's a choice between that or silently regressing, I'd prefer a hanging test. At least people will *notice* if it starts taking an ice age to complete.

LGTM, but can you double check that the test is actually run? I thought LIT only inspected the top rows for RUN: lines and stopped when it found a non-RUN: line.

James

This revision is now accepted and ready to land.Mar 15 2017, 1:53 AM
sanjoy added a subscriber: sanjoy.Mar 18 2017, 12:13 PM

Would a C++ test case (like the ones in unittests/) be better for this?

Sorry for the delay, I was obtaining commit access and then busy with a few other things.

Adding a unittest is an interesting idea. I'm not sure if it would be a lot better though, as it would be testing a fairly minor implementation detail of the Constant Folding interface. The results of the constant folding should be the same, it will just be recursively called a lot less. This test case also has the advantage of making sure nothing else causes the same kind of execution time blow-up.

Unless you have any objections, I'll commit this later today. Let me know.
Dave

This revision was automatically updated to reflect the committed changes.