[llvm-dev] is there something obviously wrong with my llvm ir code? why is it generating a trap?

Andrew Kelley via llvm-dev llvm-dev at lists.llvm.org
Sun Jul 21 21:05:32 PDT 2019


I figured it out. Wrong calling convention at the callsite.

   %2 = call fastcc i64 @simpleAsyncFn(%"@Frame(simpleAsyncFn)"* %p)

vs

   %5 = call i64 @simpleAsyncFn(%"@Frame(simpleAsyncFn)"* %p)

Missing `fastcc` on the second one.

On 7/21/19 11:49 PM, Andrew Kelley via llvm-dev wrote:
> Here's the frontend code:
> 
> var x: i32 = 1;
> 
> export fn entry() void {
>     const p = async simpleAsyncFn(2);
>     assert(x == 3);
>     resume p;
>     assert(x == 5); // this is getting replace with a trap()
> }
> fn simpleAsyncFn(delta: i32) void {
>     x += delta;
>     suspend;
>     x += delta;
> }
> 
> 
> Here's the generated LLVM IR:
> 
> ; ModuleID = 'test'
> source_filename = "test"
> target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
> target triple = "x86_64-unknown-linux-gnu"
> 
> %"[]u8" = type { i8*, i64 }
> %builtin.StackTrace = type { i64, %"[]usize" }
> %"[]usize" = type { i64*, i64 }
> %"@Frame(simpleAsyncFn)" = type { i64, i32 }
> 
> @x = internal unnamed_addr global i32 1, align 4
> @assert = internal unnamed_addr constant void (i1)* @std.debug.assert,
> align 8
> 
> ; Function Attrs: nobuiltin nounwind
> define internal fastcc void @std.debug.assert(i1) unnamed_addr #0 {
> Entry:
>   %ok = alloca i1, align 1
>   store i1 %0, i1* %ok, align 1
>   %1 = load i1, i1* %ok, align 1
>   %2 = icmp eq i1 %1, false
>   br i1 %2, label %Then, label %Else
> 
> Then:                                             ; preds = %Entry
>   unreachable
> 
> Else:                                             ; preds = %Entry
>   br label %EndIf
> 
> EndIf:                                            ; preds = %Else
>   ret void
> }
> 
> ; Function Attrs: nobuiltin nounwind
> define void @entry() #0 {
> Entry:
>   %p = alloca %"@Frame(simpleAsyncFn)", align 8
>   %0 = getelementptr inbounds %"@Frame(simpleAsyncFn)",
> %"@Frame(simpleAsyncFn)"* %p, i32 0, i32 0
>   store i64 0, i64* %0
>   %1 = getelementptr inbounds %"@Frame(simpleAsyncFn)",
> %"@Frame(simpleAsyncFn)"* %p, i32 0, i32 1
>   store i32 2, i32* %1
>   %2 = call fastcc i64 @simpleAsyncFn(%"@Frame(simpleAsyncFn)"* %p)
>   %3 = load i32, i32* @x, align 4
>   %4 = icmp eq i32 %3, 3
>   call fastcc void @std.debug.assert(i1 %4)
>   %5 = call i64 @simpleAsyncFn(%"@Frame(simpleAsyncFn)"* %p)
>   %6 = load i32, i32* @x, align 4
>   %7 = icmp eq i32 %6, 5
>   call fastcc void @std.debug.assert(i1 %7)
>   ret void
> }
> 
> ; Function Attrs: nobuiltin nounwind
> define internal fastcc i64 @simpleAsyncFn(%"@Frame(simpleAsyncFn)"*
> nonnull align 8) unnamed_addr #0 {
> AsyncSwitch:
>   %1 = getelementptr inbounds %"@Frame(simpleAsyncFn)",
> %"@Frame(simpleAsyncFn)"* %0, i32 0, i32 1
>   %2 = getelementptr inbounds %"@Frame(simpleAsyncFn)",
> %"@Frame(simpleAsyncFn)"* %0, i32 0, i32 0
>   %3 = load i64, i64* %2
>   switch i64 %3, label %BadResume [
>     i64 0, label %Entry
>     i64 1, label %GetSize
>     i64 2, label %Resume
>   ]
> 
> Entry:                                            ; preds = %AsyncSwitch
>   %4 = load i32, i32* @x, align 4
>   %5 = load i32, i32* %1, align 4
>   %6 = add nsw i32 %4, %5
>   store i32 %6, i32* @x, align 4
>   %7 = getelementptr inbounds %"@Frame(simpleAsyncFn)",
> %"@Frame(simpleAsyncFn)"* %0, i32 0, i32 0
>   store i64 2, i64* %7
>   ret i64 undef
> 
> Resume:                                           ; preds = %AsyncSwitch
>   %8 = load i32, i32* @x, align 4
>   %9 = load i32, i32* %1, align 4
>   %10 = add nsw i32 %8, %9
>   store i32 %10, i32* @x, align 4
>   ret i64 undef
> 
> BadResume:                                        ; preds = %AsyncSwitch
>   unreachable
> 
> GetSize:                                          ; preds = %AsyncSwitch
>   ret i64 16
> }
> 
> attributes #0 = { nobuiltin nounwind }
> attributes #1 = { nobuiltin noreturn nounwind }
> 
> !llvm.module.flags = !{!0}
> !llvm.dbg.cu = !{!1}
> 
> !0 = !{i32 2, !"Debug Info Version", i32 3}
> !1 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, producer:
> "zig 0.4.0", isOptimized: true, runtimeVersion: 0, emissionKind:
> NoDebug, enums: !3)
> !2 = !DIFile(filename: "test", directory: ".")
> !3 = !{}
> 
> 
> When I turn on optimizations, I get this (note the trap() at the end):
> 
> 
> define void @entry() local_unnamed_addr #0 {
> Entry:
>   %p = alloca %"@Frame(simpleAsyncFn)", align 8
>   %0 = getelementptr inbounds %"@Frame(simpleAsyncFn)",
> %"@Frame(simpleAsyncFn)"* %p, i64 0, i32 0
>   store i64 0, i64* %0, align 8
>   %1 = getelementptr inbounds %"@Frame(simpleAsyncFn)",
> %"@Frame(simpleAsyncFn)"* %p, i64 0, i32 1
>   store i32 2, i32* %1, align 8
>   call fastcc void @simpleAsyncFn(%"@Frame(simpleAsyncFn)"* %p)
>   tail call void @llvm.trap()
>   unreachable
> }
> 
> 
> This seems to indicate that the optimizer was able to prove that my
> (second) assertion was incorrect. But I don't see how this is possible.
> Does anyone else see it?
> 
> Thanks,
> Andrew
> 
> 
> _______________________________________________
> LLVM Developers mailing list
> llvm-dev at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
> 


-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: OpenPGP digital signature
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20190722/53caa53b/attachment.sig>


More information about the llvm-dev mailing list