[llvm-dev] struct bitfield regression between 3.6 and 3.9 (using -O0)

Phil Tomson via llvm-dev llvm-dev at lists.llvm.org
Thu Dec 22 17:45:45 PST 2016


Given that this is compiled with -O0, would there a way to skip the
Optimization of the Type-legalized selection DAG? It's fine until it
optimizes the Type-legalized selection DAG into the Optimized
Type-legalized selection DAG.

Phil

On Thu, Dec 22, 2016 at 10:29 AM, Friedman, Eli <efriedma at codeaurora.org>
wrote:

> On 12/21/2016 4:45 PM, Phil Tomson via llvm-dev wrote:
>
> Here's our testcase:
>
> #include <stdio.h>
>
> struct flags {
>     unsigned frog: 1;
>     unsigned foo : 1;
>     unsigned bar : 1;
>     unsigned bat : 1;
>     unsigned baz : 1;
>     unsigned bam : 1;
> };
>
> int main() {
>     struct flags flags;
>     flags.bar = 1;
>     flags.foo = 1;
>     if (flags.foo == 1) {
>         printf("Pass\n");
>         return 0;
>     } else {
>         printf("FAIL\n");
>         return 1;
>     }
> }
>
> when we compile this using LLVM 3.9 we get the "FAIL" message. However,
> when we compile in LLVM 3.6 it passes. (this is only an issue with -O0,
> higher levels of optimization work fine)
>
> After some investigation we discovered the problem, here's the relevant
> part of our assembly generated by LVM 3.9:
>
>     load          r0, r510, 24, 8
>     slr           r0, r0, 1, 8
>     cmpimm        r0, r0, 1, 0, 8, SNE
>     bitop1        r0, r0, 1<<0, AND, 64
>     jct          .LBB0_2, r0, 0, N
>     jrel         .LBB0_1
>
> Notice the slr (shift logical right) instruction there is shifting to the
> right 1 position in order to get  flags.foo into bit 0 of r0.  But the
> problem is that the compare(cmpimm) is comparing not just the single bit
> but the whole value in r0 (an 8-bit value) against 1. If we insert a
> logical AND with '1' to mask r0 just prior to the compare it works fine.
>
> And as it turns out, we see that *and* in the LLVM IR generated using -O0
> and -emit-llvm has the AND included:
>  ...
>   %bf.lshr = lshr i8 %bf.load4, 1
> *  %bf.clear5 = and i8 %bf.lshr, 1*
>   %bf.cast = zext i8 %bf.clear5 to i32
>   %cmp = icmp eq i32 %bf.cast, 1
>   br i1 %cmp, label %if.then, label %if.else
>
> (compiled with:  clang -O0 -emit-llvm -S failing.c -o failing.ll )
>
> I reran passing -debug to llc to see what's happening at various stages of
> DAG optimization:
>
> clang -O0 -mllvm -debug -S failing.c -o failing.s
>
> The initial selection DAG has the AND op node:
>
>             t22: i8 = srl t19, Constant:i64<1>
> *            t23: i8 = and t22, Constant:i8<1>*
>           t24: i32 = zero_extend t23
>         t27: i1 = setcc t24, Constant:i32<1>, seteq:ch
>       t29: i1 = xor t27, Constant:i1<-1>
>     t31: ch = brcond t18, t29, BasicBlock:ch<if.else 0xa5f8d48>
>   t33: ch = br t31, BasicBlock:ch<if.then 0xa5f8c98>
>
> The Optimized lowered selection DAG does not contain the* AND* node, but
> it does have a truncate which would seem to stand in for it given the
> result is only 1bit wide and the xor following it is operating on 1-bit
> wide values:
>
>          t22: i8 = srl t19, Constant:i64<1>
>         t35: i1 = truncate t22
>       t29: i1 = xor t35, Constant:i1<-1>
>     t31: ch = brcond t18, t29, BasicBlock:ch<if.else 0xa5f8d48>
>   t33: ch = br t31, BasicBlock:ch<if.then 0xa5f8c98>
>
> Next we get to the Type-legalized selection DAG:
>
>         t22: i8 = srl t19, Constant:i64<1>
>       t40: i8 = xor t22, Constant:i8<1>
>     t31: ch = brcond t18, t40, BasicBlock:ch<if.else 0xa5f8d48>
>   t33: ch = br t31, BasicBlock:ch<if.then 0xa5f8c98>
>
>  The truncate is now gone.
>
> Next we have the Optimzied type-legalized DAG:
>
>         t22: i8 = srl t19, Constant:i64<1>
>       t43: i8 = setcc t22, Constant:i8<1>, setne:ch
>     t31: ch = brcond t18, t43, BasicBlock:ch<if.else 0xa5f8d48>
>   t33: ch = br t31, BasicBlock:ch<if.then 0xa5f8c98>
>
> The *xor* has been replaced with a *setcc*. The legalized selection DAG
> is essentially the same. As is the optimized legalized selection DAG.
>
> So if t19 contains 0b00000110 then
> t22 contains 0b00000011
> setcc then compares t22 with a constant 1 and since they're not equal (
> setne) it sets bit 0 of t43.
> brcond will then test bit 0 of t43 and since it's set it branches to the
> else branch (prints FAIL in this case)
>
> If instead t22 contained 0b00000001 (as would be the case if the mask was
> still there) the setcc would find both values to compare equal and since setne
> is specified the branch in brcond will not be taken (the correct behavior)
>
> Things seem to have gone wrong when the Type-legalized selection DAG was
> optimized and the *xor *node was changed to a *setcc *(and actually, the
> *xor* seems like it was more optimal than the *setcc *anyway)*. *
>
>  Any ideas about why this is happening?
>
>
> I would suggest starting with DAGTypeLegalizer::PromoteIntOp_BRCOND, I
> think...
>
> -Eli
>
> --
> Employee of Qualcomm Innovation Center, Inc.
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20161222/1612f960/attachment.html>


More information about the llvm-dev mailing list