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

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

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.