diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp index 28f65990120cb..c3990d12f2c28 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp @@ -782,6 +782,24 @@ void WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA(Function &F) { for (Instruction &I : BB) { if (I.getType()->isVoidTy()) continue; + + if (isa(&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(U); + return UserI->isLifetimeStartOrEnd() && !DT.dominates(&I, UserI); + }); + if (HasNonDominatedLifetimeMarker) { + for (User *U : make_early_inc_range(I.users())) { + auto *UserI = cast(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. @@ -1269,10 +1287,20 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) { // Setjmp preparation + SmallVector StaticAllocas; + for (Instruction &I : F.getEntryBlock()) + if (auto *AI = dyn_cast(&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 diff --git a/llvm/test/CodeGen/WebAssembly/lower-em-sjlj-alloca.ll b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj-alloca.ll new file mode 100644 index 0000000000000..0f968de8a7344 --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj-alloca.ll @@ -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 +} diff --git a/llvm/test/CodeGen/WebAssembly/lower-em-sjlj-debuginfo.ll b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj-debuginfo.ll index fec9836a1607c..bab8403aa7b9e 100644 --- a/llvm/test/CodeGen/WebAssembly/lower-em-sjlj-debuginfo.ll +++ b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj-debuginfo.ll @@ -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:.*]] diff --git a/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll index b584342adc91f..51dcf2fc7ec62 100644 --- a/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll +++ b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll @@ -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__ diff --git a/llvm/test/CodeGen/WebAssembly/lower-wasm-ehsjlj.ll b/llvm/test/CodeGen/WebAssembly/lower-wasm-ehsjlj.ll index b4c93c49a97c2..9de6652d48cbf 100644 --- a/llvm/test/CodeGen/WebAssembly/lower-wasm-ehsjlj.ll +++ b/llvm/test/CodeGen/WebAssembly/lower-wasm-ehsjlj.ll @@ -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 diff --git a/llvm/test/CodeGen/WebAssembly/lower-wasm-sjlj.ll b/llvm/test/CodeGen/WebAssembly/lower-wasm-sjlj.ll index 82c04e24b72f1..e1cb859b5562f 100644 --- a/llvm/test/CodeGen/WebAssembly/lower-wasm-sjlj.ll +++ b/llvm/test/CodeGen/WebAssembly/lower-wasm-sjlj.ll @@ -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: