[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