Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,24 @@ void WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA(Function &F) {
for (Instruction &I : BB) {
if (I.getType()->isVoidTy())
continue;

if (isa<AllocaInst>(&I)) {
// If the alloca has any lifetime marker that is no longer dominated
// by the alloca, remove all lifetime markers. Lifetime markers must
// always work directly on the alloca, and this is no longer possible.
bool HasNonDominatedLifetimeMarker = any_of(I.users(), [&](User *U) {
auto *UserI = cast<Instruction>(U);
return UserI->isLifetimeStartOrEnd() && !DT.dominates(&I, UserI);
});
if (HasNonDominatedLifetimeMarker) {
for (User *U : make_early_inc_range(I.users())) {
auto *UserI = cast<Instruction>(U);
if (UserI->isLifetimeStartOrEnd())
UserI->eraseFromParent();
}
}
}

unsigned VarID = SSA.AddVariable(I.getName(), I.getType());
// If a value is defined by an invoke instruction, it is only available in
// its normal destination and not in its unwind destination.
Expand Down Expand Up @@ -1269,10 +1287,20 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) {

// Setjmp preparation

SmallVector<AllocaInst *> StaticAllocas;
for (Instruction &I : F.getEntryBlock())
if (auto *AI = dyn_cast<AllocaInst>(&I))
if (AI->isStaticAlloca())
StaticAllocas.push_back(AI);

BasicBlock *Entry = &F.getEntryBlock();
DebugLoc FirstDL = getOrCreateDebugLoc(&*Entry->begin(), F.getSubprogram());
SplitBlock(Entry, &*Entry->getFirstInsertionPt());

// Move static allocas back into the entry block, so they stay static.
for (AllocaInst *AI : StaticAllocas)
AI->moveBefore(Entry->getTerminator()->getIterator());

IRB.SetInsertPoint(Entry->getTerminator()->getIterator());
// This alloca'ed pointer is used by the runtime to identify function
// invocations. It's just for pointer comparisons. It will never be
Expand Down
129 changes: 129 additions & 0 deletions llvm/test/CodeGen/WebAssembly/lower-em-sjlj-alloca.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -S -wasm-lower-em-ehsjlj -wasm-enable-sjlj -mtriple=wasm32-unknown-emscripten < %s | FileCheck %s

@buf = external global i8
declare i32 @setjmp(ptr) returns_twice
declare void @dummy()

define void @test_static() {
; CHECK-LABEL: define void @test_static() personality ptr @__gxx_wasm_personality_v0 {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[X:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[FUNCTIONINVOCATIONID:%.*]] = alloca i32, align 4
; CHECK-NEXT: br label %[[SETJMP_DISPATCH:.*]]
; CHECK: [[SETJMP_DISPATCH]]:
; CHECK-NEXT: [[VAL1:%.*]] = phi i32 [ [[VAL:%.*]], %[[IF_END:.*]] ], [ undef, %[[ENTRY]] ]
; CHECK-NEXT: [[LABEL_PHI:%.*]] = phi i32 [ [[LABEL:%.*]], %[[IF_END]] ], [ -1, %[[ENTRY]] ]
; CHECK-NEXT: switch i32 [[LABEL_PHI]], label %[[ENTRY_SPLIT:.*]] [
; CHECK-NEXT: i32 1, label %[[ENTRY_SPLIT_SPLIT:.*]]
; CHECK-NEXT: ]
; CHECK: [[ENTRY_SPLIT]]:
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[X]])
; CHECK-NEXT: call void @__wasm_setjmp(ptr @buf, i32 1, ptr [[FUNCTIONINVOCATIONID]])
; CHECK-NEXT: br label %[[ENTRY_SPLIT_SPLIT]]
; CHECK: [[ENTRY_SPLIT_SPLIT]]:
; CHECK-NEXT: [[SETJMP_RET:%.*]] = phi i32 [ 0, %[[ENTRY_SPLIT]] ], [ [[VAL1]], %[[SETJMP_DISPATCH]] ]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[SETJMP_RET]], 0
; CHECK-NEXT: br i1 [[CMP]], label %[[IF:.*]], label %[[ELSE:.*]]
; CHECK: [[IF]]:
; CHECK-NEXT: invoke void @dummy()
; CHECK-NEXT: to [[DOTNOEXC:label %.*]] unwind label %[[CATCH_DISPATCH_LONGJMP:.*]]
; CHECK: [[_NOEXC:.*:]]
; CHECK-NEXT: ret void
; CHECK: [[ELSE]]:
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr [[X]])
; CHECK-NEXT: ret void
; CHECK: [[CATCH_DISPATCH_LONGJMP]]:
; CHECK-NEXT: [[TMP0:%.*]] = catchswitch within none [label %catch.longjmp] unwind to caller
; CHECK: [[CATCH_LONGJMP:.*:]]
; CHECK-NEXT: [[TMP1:%.*]] = catchpad within [[TMP0]] []
; CHECK-NEXT: [[THROWN:%.*]] = call ptr @llvm.wasm.catch(i32 1)
; CHECK-NEXT: [[ENV_GEP:%.*]] = getelementptr { ptr, i32 }, ptr [[THROWN]], i32 0, i32 0
; CHECK-NEXT: [[VAL_GEP:%.*]] = getelementptr { ptr, i32 }, ptr [[THROWN]], i32 0, i32 1
; CHECK-NEXT: [[ENV:%.*]] = load ptr, ptr [[ENV_GEP]], align 4
; CHECK-NEXT: [[VAL]] = load i32, ptr [[VAL_GEP]], align 4
; CHECK-NEXT: [[LABEL]] = call i32 @__wasm_setjmp_test(ptr [[ENV]], ptr [[FUNCTIONINVOCATIONID]]) [ "funclet"(token [[TMP1]]) ]
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[LABEL]], 0
; CHECK-NEXT: br i1 [[TMP2]], label %[[IF_THEN:.*]], label %[[IF_END]]
; CHECK: [[IF_THEN]]:
; CHECK-NEXT: call void @__wasm_longjmp(ptr [[ENV]], i32 [[VAL]]) [ "funclet"(token [[TMP1]]) ]
; CHECK-NEXT: unreachable
; CHECK: [[IF_END]]:
; CHECK-NEXT: catchret from [[TMP1]] to label %[[SETJMP_DISPATCH]]
;
entry:
%x = alloca i32, align 4
call void @llvm.lifetime.start.p0(i64 4, ptr %x)
%call = call i32 @setjmp(ptr @buf) returns_twice
%cmp = icmp eq i32 %call, 0
br i1 %cmp, label %if, label %else

if:
call void @dummy()
ret void

else:
call void @llvm.lifetime.end.p0(i64 4, ptr %x)
ret void
}

define void @test_dynamic(i32 %size) {
; CHECK-LABEL: define void @test_dynamic(
; CHECK-SAME: i32 [[SIZE:%.*]]) personality ptr @__gxx_wasm_personality_v0 {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[FUNCTIONINVOCATIONID:%.*]] = alloca i32, align 4
; CHECK-NEXT: br label %[[SETJMP_DISPATCH:.*]]
; CHECK: [[SETJMP_DISPATCH]]:
; CHECK-NEXT: [[VAL1:%.*]] = phi i32 [ [[VAL:%.*]], %[[IF_END:.*]] ], [ undef, %[[ENTRY]] ]
; CHECK-NEXT: [[LABEL_PHI:%.*]] = phi i32 [ [[LABEL:%.*]], %[[IF_END]] ], [ -1, %[[ENTRY]] ]
; CHECK-NEXT: switch i32 [[LABEL_PHI]], label %[[ENTRY_SPLIT:.*]] [
; CHECK-NEXT: i32 1, label %[[ENTRY_SPLIT_SPLIT:.*]]
; CHECK-NEXT: ]
; CHECK: [[ENTRY_SPLIT]]:
; CHECK-NEXT: [[X:%.*]] = alloca i32, i32 [[SIZE]], align 4
; CHECK-NEXT: call void @__wasm_setjmp(ptr @buf, i32 1, ptr [[FUNCTIONINVOCATIONID]])
; CHECK-NEXT: br label %[[ENTRY_SPLIT_SPLIT]]
; CHECK: [[ENTRY_SPLIT_SPLIT]]:
; CHECK-NEXT: [[SETJMP_RET:%.*]] = phi i32 [ 0, %[[ENTRY_SPLIT]] ], [ [[VAL1]], %[[SETJMP_DISPATCH]] ]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[SETJMP_RET]], 0
; CHECK-NEXT: br i1 [[CMP]], label %[[IF:.*]], label %[[ELSE:.*]]
; CHECK: [[IF]]:
; CHECK-NEXT: invoke void @dummy()
; CHECK-NEXT: to [[DOTNOEXC:label %.*]] unwind label %[[CATCH_DISPATCH_LONGJMP:.*]]
; CHECK: [[_NOEXC:.*:]]
; CHECK-NEXT: ret void
; CHECK: [[ELSE]]:
; CHECK-NEXT: ret void
; CHECK: [[CATCH_DISPATCH_LONGJMP]]:
; CHECK-NEXT: [[TMP0:%.*]] = catchswitch within none [label %catch.longjmp] unwind to caller
; CHECK: [[CATCH_LONGJMP:.*:]]
; CHECK-NEXT: [[TMP1:%.*]] = catchpad within [[TMP0]] []
; CHECK-NEXT: [[THROWN:%.*]] = call ptr @llvm.wasm.catch(i32 1)
; CHECK-NEXT: [[ENV_GEP:%.*]] = getelementptr { ptr, i32 }, ptr [[THROWN]], i32 0, i32 0
; CHECK-NEXT: [[VAL_GEP:%.*]] = getelementptr { ptr, i32 }, ptr [[THROWN]], i32 0, i32 1
; CHECK-NEXT: [[ENV:%.*]] = load ptr, ptr [[ENV_GEP]], align 4
; CHECK-NEXT: [[VAL]] = load i32, ptr [[VAL_GEP]], align 4
; CHECK-NEXT: [[LABEL]] = call i32 @__wasm_setjmp_test(ptr [[ENV]], ptr [[FUNCTIONINVOCATIONID]]) [ "funclet"(token [[TMP1]]) ]
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[LABEL]], 0
; CHECK-NEXT: br i1 [[TMP2]], label %[[IF_THEN:.*]], label %[[IF_END]]
; CHECK: [[IF_THEN]]:
; CHECK-NEXT: call void @__wasm_longjmp(ptr [[ENV]], i32 [[VAL]]) [ "funclet"(token [[TMP1]]) ]
; CHECK-NEXT: unreachable
; CHECK: [[IF_END]]:
; CHECK-NEXT: catchret from [[TMP1]] to label %[[SETJMP_DISPATCH]]
;
entry:
%x = alloca i32, i32 %size, align 4
call void @llvm.lifetime.start.p0(i64 -1, ptr %x)
%call = call i32 @setjmp(ptr @buf) returns_twice
%cmp = icmp eq i32 %call, 0
br i1 %cmp, label %if, label %else

if:
call void @dummy()
ret void

else:
call void @llvm.lifetime.end.p0(i64 -1, ptr %x)
ret void
}
4 changes: 2 additions & 2 deletions llvm/test/CodeGen/WebAssembly/lower-em-sjlj-debuginfo.ll
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ entry:
call void @foo(), !dbg !7
ret void, !dbg !8
; CHECK: entry:
; CHECK-NEXT: %functionInvocationId = alloca i32, align 4, !dbg ![[DL0:.*]]
; CHECK-NEXT: %buf = alloca [1 x %struct.__jmp_buf_tag], align 16, !dbg ![[DL0:.*]]
; CHECK-NEXT: %functionInvocationId = alloca i32, align 4, !dbg ![[DL0]]

; CHECK: entry.split:
; CHECK: alloca {{.*}}, !dbg ![[DL0]]
; CHECK: call void @__wasm_setjmp{{.*}}, !dbg ![[DL1:.*]]
; CHECK-NEXT: br {{.*}}, !dbg ![[DL2:.*]]

Expand Down
6 changes: 3 additions & 3 deletions llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,17 @@ entry:
call void @longjmp(ptr %buf, i32 1) #1
unreachable
; CHECK: entry:
; CHECK-NEXT: %buf = alloca [1 x %struct.__jmp_buf_tag], align 16
; CHECK-NEXT: %functionInvocationId = alloca i32, align 4
; CHECK-NEXT: br label %entry.split

; CHECK: entry.split
; CHECK-NEXT: %[[BUF:.*]] = alloca [1 x %struct.__jmp_buf_tag]
; CHECK-NEXT: call void @__wasm_setjmp(ptr %[[BUF]], i32 1, ptr %functionInvocationId)
; CHECK-NEXT: call void @__wasm_setjmp(ptr %buf, i32 1, ptr %functionInvocationId)
; CHECK-NEXT: br label %entry.split.split

; CHECK: entry.split.split:
; CHECK-NEXT: phi i32 [ 0, %entry.split ], [ %[[LONGJMP_RESULT:.*]], %if.end ]
; CHECK-NEXT: %[[JMPBUF:.*]] = ptrtoint ptr %[[BUF]] to [[PTR]]
; CHECK-NEXT: %[[JMPBUF:.*]] = ptrtoint ptr %buf to [[PTR]]
; CHECK-NEXT: store [[PTR]] 0, ptr @__THREW__
; CHECK-NEXT: call cc{{.*}} void @__invoke_void_[[PTR]]_i32(ptr @emscripten_longjmp, [[PTR]] %[[JMPBUF]], i32 1)
; CHECK-NEXT: %[[__THREW__VAL:.*]] = load [[PTR]], ptr @__THREW__
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/CodeGen/WebAssembly/lower-wasm-ehsjlj.ll
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ catch: ; preds = %catch.start
call void @__cxa_end_catch() [ "funclet"(token %2) ]
catchret from %2 to label %catchret.dest
; CHECK: catch: ; preds = %catch.start
; CHECK-NEXT: %exn = load ptr, ptr %exn.slot6, align 4
; CHECK-NEXT: %exn = load ptr, ptr %exn.slot, align 4
; CHECK-NEXT: %5 = call ptr @__cxa_begin_catch(ptr %exn) #3 [ "funclet"(token %2) ]
; CHECK-NEXT: invoke void @__cxa_end_catch() [ "funclet"(token %2) ]
; CHECK-NEXT: to label %.noexc unwind label %catch.dispatch.longjmp
Expand Down
6 changes: 2 additions & 4 deletions llvm/test/CodeGen/WebAssembly/lower-wasm-sjlj.ll
Original file line number Diff line number Diff line change
Expand Up @@ -25,26 +25,24 @@ entry:
unreachable

; CHECK: entry:
; CHECK-NEXT: %buf = alloca [1 x %struct.__jmp_buf_tag], align 16
; CHECK-NEXT: %functionInvocationId = alloca i32, align 4
; CHECK-NEXT: br label %setjmp.dispatch

; CHECK: setjmp.dispatch:
; CHECK-NEXT: %[[VAL2:.*]] = phi i32 [ %val, %if.end ], [ undef, %entry ]
; CHECK-NEXT: %[[BUF:.*]] = phi ptr [ %[[BUF2:.*]], %if.end ], [ undef, %entry ]
; CHECK-NEXT: %label.phi = phi i32 [ %label, %if.end ], [ -1, %entry ]
; CHECK-NEXT: switch i32 %label.phi, label %entry.split [
; CHECK-NEXT: i32 1, label %entry.split.split
; CHECK-NEXT: ]

; CHECK: entry.split:
; CHECK-NEXT: %buf = alloca [1 x %struct.__jmp_buf_tag], align 16
; CHECK-NEXT: call void @__wasm_setjmp(ptr %buf, i32 1, ptr %functionInvocationId)
; CHECK-NEXT: br label %entry.split.split

; CHECK: entry.split.split:
; CHECK-NEXT: %[[BUF2]] = phi ptr [ %[[BUF]], %setjmp.dispatch ], [ %buf, %entry.split ]
; CHECK-NEXT: %setjmp.ret = phi i32 [ 0, %entry.split ], [ %[[VAL2]], %setjmp.dispatch ]
; CHECK-NEXT: invoke void @__wasm_longjmp(ptr %[[BUF2]], i32 1)
; CHECK-NEXT: invoke void @__wasm_longjmp(ptr %buf, i32 1)
; CHECK-NEXT: to label %.noexc unwind label %catch.dispatch.longjmp

; CHECK: .noexc:
Expand Down
Loading