llvm/llvm/test/MC/WebAssembly/eh-assembly.s

# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+exception-handling < %s | FileCheck %s
# Check that it converts to .o without errors, but don't check any output:
# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -mattr=+exception-handling -o %t.o < %s

  .tagtype  __cpp_exception i32
  .tagtype  __c_longjmp i32
  .functype  foo () -> ()

eh_test:
  .functype  eh_test (exnref) -> ()

  # try_table with all four kinds of catch clauses
  block exnref
    block
      block () -> (i32, exnref)
        block i32
          try_table (catch __cpp_exception 0) (catch_ref __c_longjmp 1) (catch_all 2) (catch_all_ref 3)
            i32.const 0
            throw     __cpp_exception
          end_try_table
          return
        end_block
        drop
        return
      end_block
      throw_ref
    end_block
    return
  end_block
  drop

  # You can use the same kind of catch clause more than once
  block
    block exnref
      block
        try_table (catch_all 0) (catch_all_ref 1) (catch_all 2)
          call  foo
        end_try_table
      end_block
      return
    end_block
    drop
  end_block

  # Two catch clauses targeting the same block
  block
    try_table (catch_all 0) (catch_all 0)
    end_try_table
  end_block

  # try_table with a return type
  block
    try_table f32 (catch_all 0)
      f32.const 0.0
    end_try_table
    drop
  end_block

  # try_table with a multivalue type return
  block
    try_table () -> (i32, f32) (catch_all 0)
      i32.const 0
      f32.const 0.0
    end_try_table
    drop
    drop
  end_block

  # catch-less try_tables
  try_table
    call  foo
  end_try_table

  try_table i32
    i32.const 0
  end_try_table
  drop

  try_table () -> (i32, f32)
    i32.const 0
    f32.const 0.0
  end_try_table
  drop
  drop

  # try_table targeting loops
  i32.const 0
  loop (i32) -> ()
    local.get 0
    loop (exnref) -> ()
      try_table (catch __cpp_exception 1) (catch_all_ref 0)
      end_try_table
      drop
    end_loop
    drop
  end_loop
  end_function

eh_legacy_test:
  .functype  eh_legacy_test () -> ()

  # try-catch with catch, catch_all, throw, and rethrow
  try
    i32.const 3
    throw     __cpp_exception
  catch       __cpp_exception
    drop
    rethrow 0
  catch       __c_longjmp
    drop
  catch_all
    rethrow 0
  end_try

  # Nested try-catch with a rethrow
  try
    call  foo
  catch_all
    try
    catch_all
      rethrow 1
    end_try
  end_try

  # try-catch with a single return value
  try i32
    i32.const 0
  catch       __cpp_exception
  end_try
  drop

  # try-catch with a mulvivalue return
  try () -> (i32, f32)
    i32.const 0
    f32.const 0.0
  catch       __cpp_exception
    f32.const 1.0
  end_try
  drop
  drop

  # Catch-less try
  try
    call  foo
  end_try
  end_function


# CHECK-LABEL: eh_test:
# CHECK:         block           exnref
# CHECK-NEXT:    block
# CHECK-NEXT:    block           () -> (i32, exnref)
# CHECK-NEXT:    block           i32
# CHECK-NEXT:    try_table        (catch __cpp_exception 0) (catch_ref __c_longjmp 1) (catch_all 2) (catch_all_ref 3)
# CHECK:         i32.const       0
# CHECK-NEXT:    throw           __cpp_exception
# CHECK-NEXT:    end_try_table
# CHECK-NEXT:    return
# CHECK-NEXT:    end_block
# CHECK-NEXT:    drop
# CHECK-NEXT:    return
# CHECK-NEXT:    end_block
# CHECK-NEXT:    throw_ref
# CHECK-NEXT:    end_block
# CHECK-NEXT:    return
# CHECK-NEXT:    end_block
# CHECK-NEXT:    drop

# CHECK:         block
# CHECK-NEXT:    block           exnref
# CHECK-NEXT:    block
# CHECK-NEXT:    try_table        (catch_all 0) (catch_all_ref 1) (catch_all 2)
# CHECK:         call    foo
# CHECK-NEXT:    end_try_table
# CHECK-NEXT:    end_block
# CHECK-NEXT:    return
# CHECK-NEXT:    end_block
# CHECK-NEXT:    drop
# CHECK-NEXT:    end_block

# CHECK:         block
# CHECK-NEXT:    try_table        (catch_all 0) (catch_all 0)
# CHECK:         end_try_table
# CHECK-NEXT:    end_block

# CHECK:         block
# CHECK-NEXT:    try_table       f32 (catch_all 0)
# CHECK:         f32.const       0x0p0
# CHECK-NEXT:    end_try_table
# CHECK-NEXT:    drop
# CHECK-NEXT:    end_block

# CHECK:         block
# CHECK-NEXT:    try_table       () -> (i32, f32) (catch_all 0)
# CHECK:         i32.const       0
# CHECK-NEXT:    f32.const       0x0p0
# CHECK-NEXT:    end_try_table
# CHECK-NEXT:    drop
# CHECK-NEXT:    drop
# CHECK-NEXT:    end_block

# CHECK:         try_table
# CHECK-NEXT:    call    foo
# CHECK-NEXT:    end_try_table

# CHECK:         try_table       i32
# CHECK-NEXT:    i32.const       0
# CHECK-NEXT:    end_try_table
# CHECK-NEXT:    drop

# CHECK:         try_table       () -> (i32, f32)
# CHECK-NEXT:    i32.const       0
# CHECK-NEXT:    f32.const       0x0p0
# CHECK-NEXT:    end_try_table
# CHECK-NEXT:    drop
# CHECK-NEXT:    drop

# CHECK:         i32.const       0
# CHECK-NEXT:    loop            (i32) -> ()
# CHECK-NEXT:    local.get       0
# CHECK-NEXT:    loop            (exnref) -> ()
# CHECK-NEXT:    try_table        (catch __cpp_exception 1) (catch_all_ref 0)
# CHECK:         end_try_table
# CHECK-NEXT:    drop
# CHECK-NEXT:    end_loop
# CHECK-NEXT:    drop
# CHECK-NEXT:    end_loop

# CHECK:       eh_legacy_test:
# CHECK:         try
# CHECK-NEXT:    i32.const       3
# CHECK-NEXT:    throw           __cpp_exception
# CHECK-NEXT:    catch           __cpp_exception
# CHECK-NEXT:    drop
# CHECK-NEXT:    rethrow         0
# CHECK-NEXT:    catch           __c_longjmp
# CHECK-NEXT:    drop
# CHECK-NEXT:    catch_all
# CHECK-NEXT:    rethrow         0
# CHECK-NEXT:    end_try

# CHECK:         try
# CHECK-NEXT:    call    foo
# CHECK-NEXT:    catch_all
# CHECK-NEXT:    try
# CHECK-NEXT:    catch_all
# CHECK-NEXT:    rethrow         1
# CHECK-NEXT:    end_try
# CHECK-NEXT:    end_try

# CHECK:         try             i32
# CHECK-NEXT:    i32.const       0
# CHECK-NEXT:    catch           __cpp_exception
# CHECK-NEXT:    end_try
# CHECK-NEXT:    drop

# CHECK:         try             () -> (i32, f32)
# CHECK-NEXT:    i32.const       0
# CHECK-NEXT:    f32.const       0x0p0
# CHECK-NEXT:    catch           __cpp_exception
# CHECK-NEXT:    f32.const       0x1p0
# CHECK-NEXT:    end_try
# CHECK-NEXT:    drop
# CHECK-NEXT:    drop

# CHECK:         try
# CHECK-NEXT:    call    foo
# CHECK-NEXT:    end_try