[llvm-dev] LLVM behavior different depending on function symbol name

Andrew Kelley via llvm-dev llvm-dev at lists.llvm.org
Mon Jun 19 09:03:29 PDT 2017


On Mon, Jun 19, 2017 at 11:58 AM, Tom Stellard <tstellar at redhat.com> wrote:

> On 06/19/2017 11:45 AM, Andrew Kelley via llvm-dev wrote:
> > Greetings,
> >
> > I have a Zig implementation of ceil which is emitted into LLVM IR like
> this:
> >
> > ; Function Attrs: nobuiltin nounwind
> > define internal fastcc float @ceil(float) unnamed_addr #3 !dbg !644 {
> > Entry:
> >   %x = alloca float, align 4
> >   store float %0, float* %x
> >   call void @llvm.dbg.declare(metadata float* %x, metadata !649,
> metadata !494), !dbg !651
> >   %1 = load float, float* %x, !dbg !652
> >   %2 = call fastcc float @ceil32(float %1) #8, !dbg !656
> >   ret float %2, !dbg !657
> > }
> >
>
> What does the declaration of @ceil32() look like ?
>

LLVM IR follows; source follows after that.

; Function Attrs: nobuiltin nounwind
define internal fastcc float @ceil32(float) unnamed_addr #3 !dbg !658 {
Entry:
  %x = alloca float, align 4
  %u = alloca i32, align 4
  %e = alloca i32, align 4
  %m = alloca i32, align 4
  store float %0, float* %x
  call void @llvm.dbg.declare(metadata float* %x, metadata !660, metadata
!494), !dbg !670
  %1 = load float, float* %x, !dbg !671
  %2 = bitcast float %1 to i32, !dbg !672
  store i32 %2, i32* %u, !dbg !673
  call void @llvm.dbg.declare(metadata i32* %u, metadata !661, metadata
!494), !dbg !673
  %3 = load i32, i32* %u, !dbg !674
  %4 = lshr i32 %3, 23, !dbg !675
  %5 = and i32 %4, 255, !dbg !676
  %6 = sub nsw i32 %5, 127, !dbg !677
  store i32 %6, i32* %e, !dbg !678
  call void @llvm.dbg.declare(metadata i32* %e, metadata !665, metadata
!494), !dbg !678
  call void @llvm.dbg.declare(metadata i32* %m, metadata !668, metadata
!494), !dbg !679
  %7 = load i32, i32* %e, !dbg !680
  %8 = icmp sge i32 %7, 23, !dbg !682
  br i1 %8, label %Then, label %Else, !dbg !682

Then:                                             ; preds = %Entry
  %9 = load float, float* %x, !dbg !683
  ret float %9, !dbg !685

Else:                                             ; preds = %Entry
  %10 = load i32, i32* %e, !dbg !686
  %11 = icmp sge i32 %10, 0, !dbg !687
  br i1 %11, label %Then1, label %Else2, !dbg !687

Then1:                                            ; preds = %Else
  %12 = load i32, i32* %e, !dbg !688
  %13 = lshr i32 8388607, %12, !dbg !690
  store i32 %13, i32* %m, !dbg !691
  %14 = load i32, i32* %u, !dbg !692
  %15 = load i32, i32* %m, !dbg !693
  %16 = and i32 %14, %15, !dbg !694
  %17 = icmp eq i32 %16, 0, !dbg !695
  br i1 %17, label %Then3, label %Else4, !dbg !695

Else2:                                            ; preds = %Else
  %18 = load float, float* %x, !dbg !696
  %19 = fadd fast float %18, 0x4770000000000000, !dbg !698
  call fastcc void @forceEval(float %19), !dbg !699
  %20 = load i32, i32* %u, !dbg !700
  %21 = lshr i32 %20, 31, !dbg !701
  %22 = icmp ne i32 %21, 0, !dbg !702
  br i1 %22, label %Then5, label %Else6, !dbg !702

Then3:                                            ; preds = %Then1
  %23 = load float, float* %x, !dbg !703
  ret float %23, !dbg !705

Else4:                                            ; preds = %Then1
  br label %EndIf, !dbg !706

Then5:                                            ; preds = %Else2
  ret float -0.000000e+00, !dbg !707

Else6:                                            ; preds = %Else2
  br label %EndIf7, !dbg !709

EndIf:                                            ; preds = %Else4
  %24 = load float, float* %x, !dbg !710
  %25 = fadd fast float %24, 0x4770000000000000, !dbg !711
  call fastcc void @forceEval(float %25), !dbg !712
  %26 = load i32, i32* %u, !dbg !713
  %27 = lshr i32 %26, 31, !dbg !714
  %28 = icmp eq i32 %27, 0, !dbg !715
  br i1 %28, label %Then8, label %Else9, !dbg !715

EndIf7:                                           ; preds = %Else6
  br label %EndIf11, !dbg !716

Then8:                                            ; preds = %EndIf
  %29 = load i32, i32* %u, !dbg !717
  %30 = load i32, i32* %m, !dbg !719
  %31 = add nuw i32 %29, %30, !dbg !720
  store i32 %31, i32* %u, !dbg !720
  br label %EndIf10, !dbg !721

Else9:                                            ; preds = %EndIf
  br label %EndIf10, !dbg !721

EndIf10:                                          ; preds = %Else9, %Then8
  %32 = load i32, i32* %u, !dbg !722
  %33 = load i32, i32* %m, !dbg !723
  %34 = xor i32 %33, -1, !dbg !724
  %35 = and i32 %32, %34, !dbg !725
  store i32 %35, i32* %u, !dbg !725
  %36 = load i32, i32* %u, !dbg !726
  %37 = bitcast i32 %36 to float, !dbg !727
  br label %EndIf11, !dbg !716

EndIf11:                                          ; preds = %EndIf10,
%EndIf7
  %38 = phi float [ %37, %EndIf10 ], [ 1.000000e+00, %EndIf7 ], !dbg !716
  ret float %38, !dbg !728
}
; Function Attrs: nobuiltin nounwind
define internal fastcc void @forceEval(float) unnamed_addr #3 !dbg !840 {
Entry:
  %value = alloca float, align 4
  %x = alloca float, align 4
  %p = alloca float*, align 8
  store float %0, float* %value
  call void @llvm.dbg.declare(metadata float* %value, metadata !844,
metadata !494), !dbg !854
  call void @llvm.dbg.declare(metadata float* %x, metadata !846, metadata
!494), !dbg !855
  store float* %x, float** %p, !dbg !856
  call void @llvm.dbg.declare(metadata float** %p, metadata !851, metadata
!494), !dbg !856
  %1 = load float*, float** %p, !dbg !857
  %2 = load float, float* %x, !dbg !859
  store volatile float %2, float* %1, !dbg !860
  ret void, !dbg !861
}


Source:
fn ceil32(x: f32) -> f32 {
    var u = @bitCast(u32, x);
    var e = i32((u >> 23) & 0xFF) - 0x7F;
    var m: u32 = undefined;

    if (e >= 23) {
        return x;
    }
    else if (e >= 0) {
        m = 0x007FFFFF >> u32(e);
        if (u & m == 0) {
            return x;
        }
        math.forceEval(x + 0x1.0p120);
        if (u >> 31 == 0) {
            u += m;
        }
        u &= ~m;
        @bitCast(f32, u)
    } else {
        math.forceEval(x + 0x1.0p120);
        if (u >> 31 != 0) {
            return -0.0;
        } else {
            1.0
        }
    }
}
pub fn forceEval(value: var) {
    const T = @typeOf(value);
    switch (T) {
        f32 => {
            var x: f32 = undefined;
            const p = @ptrCast(&volatile f32, &x);
            *p = x;
        },
        f64 => {
            var x: f64 = undefined;
            const p = @ptrCast(&volatile f64, &x);
            *p = x;
        },
        else => {
            @compileError("forceEval not implemented for " ++ @typeName(T));
        },
    }
}



>
>
> > Test case:
> >
> > test "math.ceil" {
> >     assert(ceil(f32(0.0)) == ceil32(0.0));
> >     assert(ceil(f64(0.0)) == ceil64(0.0));
> > }
> >
> >
> > When I compile with optimizations on, this test case fails. The
> optimized code for the test case ends up being a call to panic (assertion
> failure), which means that LLVM determined the test failed at compile-time.
> >
> > What's strange about this is that if I change the function name from
> @ceil to @ceil_asdf (and change the callers) then the test passes.
> >
> > So I think LLVM is doing some kind of string comparison on the symbol
> name and detecting that it is "ceil" and then having different, undesired
> behavior.
> >
> > I tried putting `nobuiltin` in the function attributes and at the
> callsite, but that did not change anything.
> >
> > Any ideas what's going on?
> >
> > Downstream issue: https://github.com/zig-lang/zig/issues/393
> >
> > Regards,
> > Andrew
> >
> >
> > _______________________________________________
> > LLVM Developers mailing list
> > llvm-dev at lists.llvm.org
> > http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
> >
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20170619/1df77cc3/attachment-0001.html>


More information about the llvm-dev mailing list