brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.3 KiB · e1cb859 Raw
142 lines · plain
1; RUN: opt < %s -wasm-lower-em-ehsjlj -wasm-enable-sjlj -S | FileCheck %s -DPTR=i322; RUN: opt < %s -wasm-lower-em-ehsjlj -wasm-enable-sjlj -S --mattr=+atomics,+bulk-memory | FileCheck %s -DPTR=i323; RUN: opt < %s -wasm-lower-em-ehsjlj -wasm-enable-sjlj --mtriple=wasm64-unknown-unknown -data-layout="e-m:e-p:64:64-i64:64-n32:64-S128" -S | FileCheck %s -DPTR=i644 5target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"6target triple = "wasm32-unknown-unknown"7 8%struct.__jmp_buf_tag = type { [6 x i32], i32, [32 x i32] }9 10; These variables are only used in Emscripten EH/SjLj, so they shouldn't be11; generated.12; CHECK-NOT: @__THREW__ =13; CHECK-NOT: @__threwValue =14 15@global_longjmp_ptr = global ptr @longjmp, align 416; CHECK-DAG: @global_longjmp_ptr = global ptr @__wasm_longjmp17 18; Test a simple setjmp - longjmp sequence19define void @setjmp_longjmp() {20; CHECK-LABEL: @setjmp_longjmp()21entry:22  %buf = alloca [1 x %struct.__jmp_buf_tag], align 1623  %call = call i32 @setjmp(ptr %buf) #024  call void @longjmp(ptr %buf, i32 1) #125  unreachable26 27; CHECK:    entry:28; CHECK-NEXT: %buf = alloca [1 x %struct.__jmp_buf_tag], align 1629; CHECK-NEXT: %functionInvocationId = alloca i32, align 430; CHECK-NEXT: br label %setjmp.dispatch31 32; CHECK:    setjmp.dispatch:33; CHECK-NEXT: %[[VAL2:.*]] = phi i32 [ %val, %if.end ], [ undef, %entry ]34; CHECK-NEXT: %label.phi = phi i32 [ %label, %if.end ], [ -1, %entry ]35; CHECK-NEXT: switch i32 %label.phi, label %entry.split [36; CHECK-NEXT:   i32 1, label %entry.split.split37; CHECK-NEXT: ]38 39; CHECK:    entry.split:40; CHECK-NEXT: call void @__wasm_setjmp(ptr %buf, i32 1, ptr %functionInvocationId)41; CHECK-NEXT: br label %entry.split.split42 43; CHECK:    entry.split.split:44; CHECK-NEXT: %setjmp.ret = phi i32 [ 0, %entry.split ], [ %[[VAL2]], %setjmp.dispatch ]45; CHECK-NEXT: invoke void @__wasm_longjmp(ptr %buf, i32 1)46; CHECK-NEXT:         to label %.noexc unwind label %catch.dispatch.longjmp47 48; CHECK:    .noexc:49; CHECK-NEXT: unreachable50 51; CHECK:    catch.dispatch.longjmp:52; CHECK-NEXT: %0 = catchswitch within none [label %catch.longjmp] unwind to caller53 54; CHECK:    catch.longjmp:55; CHECK-NEXT: %1 = catchpad within %0 []56; CHECK-NEXT: %thrown = call ptr @llvm.wasm.catch(i32 1)57; CHECK-NEXT: %env_gep = getelementptr { ptr, i32 }, ptr %thrown, i32 0, i32 058; CHECK-NEXT: %val_gep = getelementptr { ptr, i32 }, ptr %thrown, i32 0, i32 159; CHECK-NEXT: %env = load ptr, ptr %env_gep, align {{.*}}60; CHECK-NEXT: %val = load i32, ptr %val_gep, align 461; CHECK-NEXT: %label = call i32 @__wasm_setjmp_test(ptr %env, ptr %functionInvocationId) [ "funclet"(token %1) ]62; CHECK-NEXT: %2 = icmp eq i32 %label, 063; CHECK-NEXT: br i1 %2, label %if.then, label %if.end64 65; CHECK:    if.then:66; CHECK-NEXT: call void @__wasm_longjmp(ptr %env, i32 %val) [ "funclet"(token %1) ]67; CHECK-NEXT: unreachable68 69; CHECK:    if.end:70; CHECK-NEXT: catchret from %1 to label %setjmp.dispatch71}72 73; When there are multiple longjmpable calls after setjmp. This will turn each of74; longjmpable call into an invoke whose unwind destination is75; 'catch.dispatch.longjmp' BB.76define void @setjmp_multiple_longjmpable_calls() {77; CHECK-LABEL: @setjmp_multiple_longjmpable_calls78entry:79  %buf = alloca [1 x %struct.__jmp_buf_tag], align 1680  %call = call i32 @setjmp(ptr %buf) #081  call void @foo()82  call void @foo()83  ret void84 85; CHECK: entry.split.split:86; CHECK:   invoke void @foo()87; CHECK:           to label %{{.*}} unwind label %catch.dispatch.longjmp88 89; CHECK: .noexc:90; CHECK:   invoke void @foo()91; CHECK:           to label %{{.*}} unwind label %catch.dispatch.longjmp92}93 94; Tests cases where longjmp function pointer is used in other ways than direct95; calls. longjmps should be replaced with (void(*)(jmp_buf*, int))__wasm_longjmp.96declare void @take_longjmp(ptr %arg_ptr)97define void @indirect_longjmp() {98; CHECK-LABEL: @indirect_longjmp99entry:100  %local_longjmp_ptr = alloca ptr, align 4101  %buf0 = alloca [1 x %struct.__jmp_buf_tag], align 16102  %buf1 = alloca [1 x %struct.__jmp_buf_tag], align 16103 104  ; Store longjmp in a local variable, load it, and call it105  store ptr @longjmp, ptr %local_longjmp_ptr, align 4106  ; CHECK: store ptr @__wasm_longjmp, ptr %local_longjmp_ptr, align 4107  %longjmp_from_local_ptr = load ptr, ptr %local_longjmp_ptr, align 4108  call void %longjmp_from_local_ptr(ptr %buf0, i32 0)109 110  ; Load longjmp from a global variable and call it111  %longjmp_from_global_ptr = load ptr, ptr @global_longjmp_ptr, align 4112  call void %longjmp_from_global_ptr(ptr %buf1, i32 0)113 114  ; Pass longjmp as a function argument. This is a call but longjmp is not a115  ; callee but an argument.116  call void @take_longjmp(ptr @longjmp)117  ; CHECK: call void @take_longjmp(ptr @__wasm_longjmp)118  ret void119}120 121; Function Attrs: nounwind122declare void @foo() #2123; The pass removes the 'nounwind' attribute, so there should be no attributes124; CHECK-NOT: declare void @foo #{{.*}}125; Function Attrs: returns_twice126declare i32 @setjmp(ptr) #0127; Function Attrs: noreturn128declare void @longjmp(ptr, i32) #1129declare i32 @__gxx_personality_v0(...)130declare ptr @__cxa_begin_catch(ptr)131declare void @__cxa_end_catch()132declare void @free(ptr)133 134; Runtime glue function declarations135; CHECK-DAG: declare void @__wasm_setjmp(ptr, i32, ptr)136; CHECK-DAG: declare i32 @__wasm_setjmp_test(ptr, ptr)137; CHECK-DAG: declare void @__wasm_longjmp(ptr, i32)138 139attributes #0 = { returns_twice }140attributes #1 = { noreturn }141attributes #2 = { nounwind }142