[llvm] 8e35a18 - [WebAssembly] Support Emscripten EH/SjLj in Wasm64
Heejin Ahn via llvm-commits
llvm-commits at lists.llvm.org
Fri May 14 03:45:16 PDT 2021
Author: Heejin Ahn
Date: 2021-05-14T03:45:09-07:00
New Revision: 8e35a18e4ad416c48c8e48492676fb189ee2c720
URL: https://github.com/llvm/llvm-project/commit/8e35a18e4ad416c48c8e48492676fb189ee2c720
DIFF: https://github.com/llvm/llvm-project/commit/8e35a18e4ad416c48c8e48492676fb189ee2c720.diff
LOG: [WebAssembly] Support Emscripten EH/SjLj in Wasm64
In wasm64, the signatures of some library functions and global variables
defined in Emscripten change:
- `emscripten_longjmp`: `(i32, i32) -> ()` -> `(i64, i32) -> ()`
This changes because the first argument is the address of a memory
buffer. This in turn causes more changes below.
- `setThrew`: `(i32, i32) -> ()` -> `(i64, i32) -> ()`
`emscripten_longjmp` calls `setThrew` with the i64 buffer argument as
the first parameter.
- `__THREW__` (global var): `i32` to `i64`
`setThrew`'s first argument is set to this `__THREW__` variable, so it
should change to i64 as well.
- `testSetjmp`: `(i32, i32*, i32) -> (i32)` -> `(i64, i32*, i32) -> (i32)`
In the code transformation done in this pass, the value of `__THREW__`
is passed as the first parameter of `testSetjmp`.
This patch creates some helper functions to easily get types that become
different depending on the wasm32/wasm64, and uses them to change
various function signatures and code transformations. Also updates the
tests with WASM32/WASM64 check lines.
(Untested) Emscripten side patch: https://github.com/emscripten-core/emscripten/pull/14108
Reviewed By: aardappel
Differential Revision: https://reviews.llvm.org/D101985
Added:
Modified:
llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll
llvm/test/CodeGen/WebAssembly/lower-em-exceptions.ll
llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
index 0ec4b38c70f9a..73c064523ab58 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
@@ -47,7 +47,7 @@
/// These variables are used for both exceptions and setjmp/longjmps.
/// __THREW__ indicates whether an exception or a longjmp occurred or not. 0
/// means nothing occurred, 1 means an exception occurred, and other numbers
-/// mean a longjmp occurred. In the case of longjmp, __threwValue variable
+/// mean a longjmp occurred. In the case of longjmp, __THREW__ variable
/// indicates the corresponding setjmp buffer the longjmp corresponds to.
///
/// * Exception handling
@@ -55,7 +55,7 @@
/// 2) We assume the existence of setThrew and setTempRet0/getTempRet0 functions
/// at link time. setThrew exists in Emscripten's compiler-rt:
///
-/// void setThrew(int threw, int value) {
+/// void setThrew(uintptr_t threw, int value) {
/// if (__THREW__ == 0) {
/// __THREW__ = threw;
/// __threwValue = value;
@@ -292,13 +292,12 @@ static bool canThrow(const Value *V) {
return true;
}
-// Get a global variable with the given name. If it doesn't exist declare it,
-// which will generate an import and asssumes that it will exist at link time.
-static GlobalVariable *getGlobalVariableI32(Module &M, IRBuilder<> &IRB,
- WebAssemblyTargetMachine &TM,
- const char *Name) {
- auto Int32Ty = IRB.getInt32Ty();
- auto *GV = dyn_cast<GlobalVariable>(M.getOrInsertGlobal(Name, Int32Ty));
+// Get a global variable with the given name. If it doesn't exist declare it,
+// which will generate an import and assume that it will exist at link time.
+static GlobalVariable *getGlobalVariable(Module &M, Type *Ty,
+ WebAssemblyTargetMachine &TM,
+ const char *Name) {
+ auto *GV = dyn_cast<GlobalVariable>(M.getOrInsertGlobal(Name, Ty));
if (!GV)
report_fatal_error(Twine("unable to create global: ") + Name);
@@ -354,6 +353,28 @@ static Function *getEmscriptenFunction(FunctionType *Ty, const Twine &Name,
return F;
}
+// Returns an integer type for the target architecture's address space.
+// i32 for wasm32 and i64 for wasm64.
+static Type *getAddrIntType(Module *M) {
+ IRBuilder<> IRB(M->getContext());
+ return IRB.getIntNTy(M->getDataLayout().getPointerSizeInBits());
+}
+
+// Returns an integer pointer type for the target architecture's address space.
+// i32* for wasm32 and i64* for wasm64.
+static Type *getAddrPtrType(Module *M) {
+ return Type::getIntNPtrTy(M->getContext(),
+ M->getDataLayout().getPointerSizeInBits());
+}
+
+// Returns an integer whose type is the integer type for the target's address
+// space. Returns (i32 C) for wasm32 and (i64 C) for wasm64, when C is the
+// integer.
+static Value *getAddrSizeInt(Module *M, uint64_t C) {
+ IRBuilder<> IRB(M->getContext());
+ return IRB.getIntN(M->getDataLayout().getPointerSizeInBits(), C);
+}
+
// Returns __cxa_find_matching_catch_N function, where N = NumClauses + 2.
// This is because a landingpad instruction contains two more arguments, a
// personality function and a cleanup bit, and __cxa_find_matching_catch_N
@@ -381,7 +402,8 @@ WebAssemblyLowerEmscriptenEHSjLj::getFindMatchingCatch(Module &M,
// Returns %__THREW__.val, which indicates whether an exception is thrown (or
// whether longjmp occurred), for future use.
Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(CallBase *CI) {
- LLVMContext &C = CI->getModule()->getContext();
+ Module *M = CI->getModule();
+ LLVMContext &C = M->getContext();
// If we are calling a function that is noreturn, we must remove that
// attribute. The code we insert here does expect it to return, after we
@@ -397,7 +419,7 @@ Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(CallBase *CI) {
// Pre-invoke
// __THREW__ = 0;
- IRB.CreateStore(IRB.getInt32(0), ThrewGV);
+ IRB.CreateStore(getAddrSizeInt(M, 0), ThrewGV);
// Invoke function wrapper in JavaScript
SmallVector<Value *, 16> Args;
@@ -445,8 +467,8 @@ Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(CallBase *CI) {
// Post-invoke
// %__THREW__.val = __THREW__; __THREW__ = 0;
Value *Threw =
- IRB.CreateLoad(IRB.getInt32Ty(), ThrewGV, ThrewGV->getName() + ".val");
- IRB.CreateStore(IRB.getInt32(0), ThrewGV);
+ IRB.CreateLoad(getAddrIntType(M), ThrewGV, ThrewGV->getName() + ".val");
+ IRB.CreateStore(getAddrSizeInt(M, 0), ThrewGV);
return Threw;
}
@@ -541,7 +563,8 @@ void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
Value *SetjmpTableSize, Value *&Label, Value *&LongjmpResult,
BasicBlock *&EndBB) {
Function *F = BB->getParent();
- LLVMContext &C = BB->getModule()->getContext();
+ Module *M = F->getParent();
+ LLVMContext &C = M->getContext();
IRBuilder<> IRB(C);
IRB.SetCurrentDebugLocation(DL);
@@ -550,7 +573,7 @@ void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
BasicBlock *ThenBB1 = BasicBlock::Create(C, "if.then1", F);
BasicBlock *ElseBB1 = BasicBlock::Create(C, "if.else1", F);
BasicBlock *EndBB1 = BasicBlock::Create(C, "if.end", F);
- Value *ThrewCmp = IRB.CreateICmpNE(Threw, IRB.getInt32(0));
+ Value *ThrewCmp = IRB.CreateICmpNE(Threw, getAddrSizeInt(M, 0));
Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
ThrewValueGV->getName() + ".val");
Value *ThrewValueCmp = IRB.CreateICmpNE(ThrewValue, IRB.getInt32(0));
@@ -562,10 +585,10 @@ void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
IRB.SetInsertPoint(ThenBB1);
BasicBlock *ThenBB2 = BasicBlock::Create(C, "if.then2", F);
BasicBlock *EndBB2 = BasicBlock::Create(C, "if.end2", F);
- Value *ThrewInt = IRB.CreateIntToPtr(Threw, Type::getInt32PtrTy(C),
- Threw->getName() + ".i32p");
- Value *LoadedThrew = IRB.CreateLoad(IRB.getInt32Ty(), ThrewInt,
- ThrewInt->getName() + ".loaded");
+ Value *ThrewPtr =
+ IRB.CreateIntToPtr(Threw, getAddrPtrType(M), Threw->getName() + ".p");
+ Value *LoadedThrew = IRB.CreateLoad(getAddrIntType(M), ThrewPtr,
+ ThrewPtr->getName() + ".loaded");
Value *ThenLabel = IRB.CreateCall(
TestSetjmpF, {LoadedThrew, SetjmpTable, SetjmpTableSize}, "label");
Value *Cmp2 = IRB.CreateICmpEQ(ThenLabel, IRB.getInt32(0));
@@ -622,11 +645,12 @@ void WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA(Function &F) {
}
// Replace uses of longjmp with emscripten_longjmp. emscripten_longjmp takes
-// arguments of type {i32, i32} and longjmp takes {jmp_buf*, i32}, so we need a
-// ptrtoint instruction here to make the type match. jmp_buf* will eventually be
-// lowered to i32 in the wasm backend.
+// arguments of type {i32, i32} (wasm32) / {i64, i32} (wasm64) and longjmp takes
+// {jmp_buf*, i32}, so we need a ptrtoint instruction here to make the type
+// match. jmp_buf* will eventually be lowered to i32 in the wasm backend.
static void replaceLongjmpWithEmscriptenLongjmp(Function *LongjmpF,
Function *EmLongjmpF) {
+ Module *M = LongjmpF->getParent();
SmallVector<CallInst *, 8> ToErase;
LLVMContext &C = LongjmpF->getParent()->getContext();
IRBuilder<> IRB(C);
@@ -638,7 +662,7 @@ static void replaceLongjmpWithEmscriptenLongjmp(Function *LongjmpF,
if (CI && CI->getCalledFunction() == LongjmpF) {
IRB.SetInsertPoint(CI);
Value *Jmpbuf =
- IRB.CreatePtrToInt(CI->getArgOperand(0), IRB.getInt32Ty(), "jmpbuf");
+ IRB.CreatePtrToInt(CI->getArgOperand(0), getAddrIntType(M), "jmpbuf");
IRB.CreateCall(EmLongjmpF, {Jmpbuf, CI->getArgOperand(1)});
ToErase.push_back(CI);
}
@@ -671,9 +695,6 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
assert(TPC && "Expected a TargetPassConfig");
auto &TM = TPC->getTM<WebAssemblyTargetMachine>();
- if ((EnableEH || DoSjLj) &&
- Triple(M.getTargetTriple()).getArch() == Triple::wasm64)
- report_fatal_error("Emscripten EH/SjLj is not supported with wasm64 yet");
if (EnableEH && TM.Options.ExceptionModel == ExceptionHandling::Wasm)
report_fatal_error("-exception-model=wasm not allowed with "
"-enable-emscripten-cxx-exceptions");
@@ -681,8 +702,8 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
// Declare (or get) global variables __THREW__, __threwValue, and
// getTempRet0/setTempRet0 function which are used in common for both
// exception handling and setjmp/longjmp handling
- ThrewGV = getGlobalVariableI32(M, IRB, TM, "__THREW__");
- ThrewValueGV = getGlobalVariableI32(M, IRB, TM, "__threwValue");
+ ThrewGV = getGlobalVariable(M, getAddrIntType(&M), TM, "__THREW__");
+ ThrewValueGV = getGlobalVariable(M, IRB.getInt32Ty(), TM, "__threwValue");
GetTempRet0Func = getEmscriptenFunction(
FunctionType::get(IRB.getInt32Ty(), false), "getTempRet0", &M);
SetTempRet0Func = getEmscriptenFunction(
@@ -718,7 +739,7 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
// Register emscripten_longjmp function
FunctionType *FTy = FunctionType::get(
- IRB.getVoidTy(), {IRB.getInt32Ty(), IRB.getInt32Ty()}, false);
+ IRB.getVoidTy(), {getAddrIntType(&M), IRB.getInt32Ty()}, false);
EmLongjmpF = getEmscriptenFunction(FTy, "emscripten_longjmp", &M);
if (LongjmpF)
@@ -736,7 +757,8 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
// Register testSetjmp function
FTy = FunctionType::get(
IRB.getInt32Ty(),
- {IRB.getInt32Ty(), Type::getInt32PtrTy(C), IRB.getInt32Ty()}, false);
+ {getAddrIntType(&M), Type::getInt32PtrTy(C), IRB.getInt32Ty()},
+ false);
TestSetjmpF = getEmscriptenFunction(FTy, "testSetjmp", &M);
// Only traverse functions that uses setjmp in order not to insert
@@ -794,7 +816,7 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(Function &F) {
ToErase.push_back(II);
// Insert a branch based on __THREW__ variable
- Value *Cmp = IRB.CreateICmpEQ(Threw, IRB.getInt32(1), "cmp");
+ Value *Cmp = IRB.CreateICmpEQ(Threw, getAddrSizeInt(&M, 1), "cmp");
IRB.CreateCondBr(Cmp, II->getUnwindDest(), II->getNormalDest());
} else {
@@ -1060,12 +1082,15 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) {
// __THREW__ = 0;
for (auto I = std::next(BasicBlock::iterator(ThrewLI)), IE = BB->end();
I != IE; ++I) {
- if (auto *SI = dyn_cast<StoreInst>(I))
- if (auto *GV = dyn_cast<GlobalVariable>(SI->getPointerOperand()))
- if (GV == ThrewGV && SI->getValueOperand() == IRB.getInt32(0)) {
+ if (auto *SI = dyn_cast<StoreInst>(I)) {
+ if (auto *GV = dyn_cast<GlobalVariable>(SI->getPointerOperand())) {
+ if (GV == ThrewGV &&
+ SI->getValueOperand() == getAddrSizeInt(&M, 0)) {
ThrewResetSI = SI;
break;
}
+ }
+ }
}
assert(Threw && ThrewLI && "Cannot find __THREW__ load after invoke");
assert(ThrewResetSI && "Cannot find __THREW__ store after invoke");
diff --git a/llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll b/llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll
index 6ab5e3a4f77e7..a7b4b864c2b84 100644
--- a/llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll
+++ b/llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll
@@ -1,8 +1,6 @@
; RUN: llc < %s -enable-emscripten-cxx-exceptions | FileCheck %s --check-prefix=EH
; RUN: llc < %s -enable-emscripten-sjlj | FileCheck %s --check-prefix=SJLJ
; RUN: llc < %s | FileCheck %s --check-prefix=NONE
-; RUN: not --crash llc < %s -enable-emscripten-cxx-exceptions -mtriple=wasm64-unknown-unknown 2>&1 | FileCheck %s --check-prefix=WASM64-EH
-; RUN: not --crash llc < %s -enable-emscripten-sjlj -mtriple=wasm64-unknown-unknown 2>&1 | FileCheck %s --check-prefix=WASM64-SJLJ
; RUN: not --crash llc < %s -enable-emscripten-cxx-exceptions -exception-model=wasm 2>&1 | FileCheck %s --check-prefix=WASM-EH-EM-EH
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
@@ -103,6 +101,4 @@ attributes #2 = { nounwind }
; SJLJ-NOT: .import_module emscripten_longjmp_jmpbuf
; SJLJ-NOT: .import_name emscripten_longjmp_jmpbuf
-; WASM64-EH: LLVM ERROR: Emscripten EH/SjLj is not supported with wasm64 yet
-; WASM64-SJLJ: LLVM ERROR: Emscripten EH/SjLj is not supported with wasm64 yet
; WASM-EH-EM-EH: LLVM ERROR: -exception-model=wasm not allowed with -enable-emscripten-cxx-exceptions
diff --git a/llvm/test/CodeGen/WebAssembly/lower-em-exceptions.ll b/llvm/test/CodeGen/WebAssembly/lower-em-exceptions.ll
index 88073f3a926f7..8df0b5dcba7b9 100644
--- a/llvm/test/CodeGen/WebAssembly/lower-em-exceptions.ll
+++ b/llvm/test/CodeGen/WebAssembly/lower-em-exceptions.ll
@@ -1,14 +1,15 @@
-; RUN: opt < %s -wasm-lower-em-ehsjlj -S | FileCheck %s --check-prefixes=CHECK,NO-TLS
-; RUN: opt < %s -wasm-lower-em-ehsjlj -S --mattr=+atomics,+bulk-memory | FileCheck %s --check-prefixes=CHECK,TLS
+; RUN: opt < %s -wasm-lower-em-ehsjlj -S | FileCheck %s --check-prefixes=CHECK,NO-TLS -DPTR=i32
+; RUN: opt < %s -wasm-lower-em-ehsjlj -S --mattr=+atomics,+bulk-memory | FileCheck %s --check-prefixes=CHECK,TLS -DPTR=i32
+; RUN: opt < %s -wasm-lower-em-ehsjlj --mtriple=wasm64-unknown-unknown -data-layout="e-m:e-p:64:64-i64:64-n32:64-S128" -S | FileCheck %s --check-prefixes=CHECK -DPTR=i64
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-unknown"
@_ZTIi = external constant i8*
@_ZTIc = external constant i8*
-; NO-TLS-DAG: __THREW__ = external global i32
+; NO-TLS-DAG: __THREW__ = external global [[PTR]]
; NO-TLS-DAG: __threwValue = external global i32
-; TLS-DAG: __THREW__ = external thread_local(localexec) global i32
+; TLS-DAG: __THREW__ = external thread_local(localexec) global [[PTR]]
; TLS-DAG: __threwValue = external thread_local(localexec) global i32
; Test invoke instruction with clauses (try-catch block)
@@ -18,11 +19,11 @@ entry:
invoke void @foo(i32 3)
to label %invoke.cont unwind label %lpad
; CHECK: entry:
-; CHECK-NEXT: store i32 0, i32* @__THREW__
+; CHECK-NEXT: store [[PTR]] 0, [[PTR]]* @__THREW__
; CHECK-NEXT: call cc{{.*}} void @__invoke_void_i32(void (i32)* @foo, i32 3)
-; CHECK-NEXT: %[[__THREW__VAL:.*]] = load i32, i32* @__THREW__
-; CHECK-NEXT: store i32 0, i32* @__THREW__
-; CHECK-NEXT: %cmp = icmp eq i32 %[[__THREW__VAL]], 1
+; CHECK-NEXT: %[[__THREW__VAL:.*]] = load [[PTR]], [[PTR]]* @__THREW__
+; CHECK-NEXT: store [[PTR]] 0, [[PTR]]* @__THREW__
+; CHECK-NEXT: %cmp = icmp eq [[PTR]] %[[__THREW__VAL]], 1
; CHECK-NEXT: br i1 %cmp, label %lpad, label %invoke.cont
invoke.cont: ; preds = %entry
@@ -74,11 +75,11 @@ entry:
invoke void @foo(i32 3)
to label %invoke.cont unwind label %lpad
; CHECK: entry:
-; CHECK-NEXT: store i32 0, i32* @__THREW__
+; CHECK-NEXT: store [[PTR]] 0, [[PTR]]* @__THREW__
; CHECK-NEXT: call cc{{.*}} void @__invoke_void_i32(void (i32)* @foo, i32 3)
-; CHECK-NEXT: %[[__THREW__VAL:.*]] = load i32, i32* @__THREW__
-; CHECK-NEXT: store i32 0, i32* @__THREW__
-; CHECK-NEXT: %cmp = icmp eq i32 %[[__THREW__VAL]], 1
+; CHECK-NEXT: %[[__THREW__VAL:.*]] = load [[PTR]], [[PTR]]* @__THREW__
+; CHECK-NEXT: store [[PTR]] 0, [[PTR]]* @__THREW__
+; CHECK-NEXT: %cmp = icmp eq [[PTR]] %[[__THREW__VAL]], 1
; CHECK-NEXT: br i1 %cmp, label %lpad, label %invoke.cont
invoke.cont: ; preds = %entry
@@ -125,7 +126,7 @@ entry:
%0 = invoke noalias i8* @bar(i8 signext 1, i8 zeroext 2)
to label %invoke.cont unwind label %lpad
; CHECK: entry:
-; CHECK-NEXT: store i32 0, i32* @__THREW__
+; CHECK-NEXT: store [[PTR]] 0, [[PTR]]* @__THREW__
; CHECK-NEXT: %0 = call cc{{.*}} noalias i8* @"__invoke_i8*_i8_i8"(i8* (i8, i8)* @bar, i8 signext 1, i8 zeroext 2)
invoke.cont: ; preds = %entry
diff --git a/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll
index 9d87934f081fc..e918ac6b8031d 100644
--- a/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll
+++ b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll
@@ -1,5 +1,6 @@
-; RUN: opt < %s -wasm-lower-em-ehsjlj -S | FileCheck %s --check-prefixes=CHECK,NO-TLS
-; RUN: opt < %s -wasm-lower-em-ehsjlj -S --mattr=+atomics,+bulk-memory | FileCheck %s --check-prefixes=CHECK,TLS
+; RUN: opt < %s -wasm-lower-em-ehsjlj -S | FileCheck %s --check-prefixes=CHECK,NO-TLS -DPTR=i32
+; RUN: opt < %s -wasm-lower-em-ehsjlj -S --mattr=+atomics,+bulk-memory | FileCheck %s --check-prefixes=CHECK,TLS -DPTR=i32
+; RUN: opt < %s -wasm-lower-em-ehsjlj --mtriple=wasm64-unknown-unknown -data-layout="e-m:e-p:64:64-i64:64-n32:64-S128" -S | FileCheck %s --check-prefixes=CHECK -DPTR=i64
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-unknown"
@@ -7,12 +8,12 @@ target triple = "wasm32-unknown-unknown"
%struct.__jmp_buf_tag = type { [6 x i32], i32, [32 x i32] }
@global_var = global i32 0, align 4
-; NO-TLS-DAG: __THREW__ = external global i32
-; NO-TLS-DAG: __threwValue = external global i32
+; NO-TLS-DAG: __THREW__ = external global [[PTR]]
+; NO-TLS-DAG: __threwValue = external global [[PTR]]
; TLS-DAG: __THREW__ = external thread_local(localexec) global i32
; TLS-DAG: __threwValue = external thread_local(localexec) global i32
@global_longjmp_ptr = global void (%struct.__jmp_buf_tag*, i32)* @longjmp, align 4
-; CHECK-DAG: @global_longjmp_ptr = global void (%struct.__jmp_buf_tag*, i32)* bitcast (void (i32, i32)* @emscripten_longjmp to void (%struct.__jmp_buf_tag*, i32)*)
+; CHECK-DAG: @global_longjmp_ptr = global void (%struct.__jmp_buf_tag*, i32)* bitcast (void ([[PTR]], i32)* @emscripten_longjmp to void (%struct.__jmp_buf_tag*, i32)*)
; Test a simple setjmp - longjmp sequence
define void @setjmp_longjmp() {
@@ -38,12 +39,12 @@ entry:
; CHECK: entry.split:
; CHECK-NEXT: phi i32 [ 0, %entry ], [ %[[LONGJMP_RESULT:.*]], %if.end ]
; CHECK-NEXT: %[[ARRAYDECAY1:.*]] = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %[[BUF]], i32 0, i32 0
-; CHECK-NEXT: %[[JMPBUF:.*]] = ptrtoint %struct.__jmp_buf_tag* %[[ARRAYDECAY1]] to i32
-; CHECK-NEXT: store i32 0, i32* @__THREW__
-; CHECK-NEXT: call cc{{.*}} void @__invoke_void_i32_i32(void (i32, i32)* @emscripten_longjmp, i32 %[[JMPBUF]], i32 1)
-; CHECK-NEXT: %[[__THREW__VAL:.*]] = load i32, i32* @__THREW__
-; CHECK-NEXT: store i32 0, i32* @__THREW__
-; CHECK-NEXT: %[[CMP0:.*]] = icmp ne i32 %__THREW__.val, 0
+; CHECK-NEXT: %[[JMPBUF:.*]] = ptrtoint %struct.__jmp_buf_tag* %[[ARRAYDECAY1]] to [[PTR]]
+; CHECK-NEXT: store [[PTR]] 0, [[PTR]]* @__THREW__
+; CHECK-NEXT: call cc{{.*}} void @__invoke_void_[[PTR]]_i32(void ([[PTR]], i32)* @emscripten_longjmp, [[PTR]] %[[JMPBUF]], i32 1)
+; CHECK-NEXT: %[[__THREW__VAL:.*]] = load [[PTR]], [[PTR]]* @__THREW__
+; CHECK-NEXT: store [[PTR]] 0, [[PTR]]* @__THREW__
+; CHECK-NEXT: %[[CMP0:.*]] = icmp ne [[PTR]] %__THREW__.val, 0
; CHECK-NEXT: %[[THREWVALUE_VAL:.*]] = load i32, i32* @__threwValue
; CHECK-NEXT: %[[CMP1:.*]] = icmp ne i32 %[[THREWVALUE_VAL]], 0
; CHECK-NEXT: %[[CMP:.*]] = and i1 %[[CMP0]], %[[CMP1]]
@@ -53,9 +54,9 @@ entry:
; CHECK-NEXT: unreachable
; CHECK: if.then1:
-; CHECK-NEXT: %[[__THREW__VAL_I32P:.*]] = inttoptr i32 %[[__THREW__VAL]] to i32*
-; CHECK-NEXT: %[[__THREW__VAL_I32P_LOADED:.*]] = load i32, i32* %[[__THREW__VAL_I32P]]
-; CHECK-NEXT: %[[LABEL:.*]] = call i32 @testSetjmp(i32 %[[__THREW__VAL_I32P_LOADED]], i32* %[[SETJMP_TABLE1]], i32 %[[SETJMP_TABLE_SIZE1]])
+; CHECK-NEXT: %[[__THREW__VAL_P:.*]] = inttoptr [[PTR]] %[[__THREW__VAL]] to [[PTR]]*
+; CHECK-NEXT: %[[__THREW__VAL_P_LOADED:.*]] = load [[PTR]], [[PTR]]* %[[__THREW__VAL_P]]
+; CHECK-NEXT: %[[LABEL:.*]] = call i32 @testSetjmp([[PTR]] %[[__THREW__VAL_P_LOADED]], i32* %[[SETJMP_TABLE1]], i32 %[[SETJMP_TABLE_SIZE1]])
; CHECK-NEXT: %[[CMP:.*]] = icmp eq i32 %[[LABEL]], 0
; CHECK-NEXT: br i1 %[[CMP]], label %if.then2, label %if.end2
@@ -70,7 +71,7 @@ entry:
; CHECK-NEXT: ]
; CHECK: if.then2:
-; CHECK-NEXT: call void @emscripten_longjmp(i32 %[[__THREW__VAL]], i32 %[[THREWVALUE_VAL]])
+; CHECK-NEXT: call void @emscripten_longjmp([[PTR]] %[[__THREW__VAL]], i32 %[[THREWVALUE_VAL]])
; CHECK-NEXT: unreachable
; CHECK: if.end2:
@@ -110,18 +111,18 @@ entry:
to label %try.cont unwind label %lpad
; CHECK: entry.split:
-; CHECK: store i32 0, i32* @__THREW__
+; CHECK: store [[PTR]] 0, [[PTR]]* @__THREW__
; CHECK-NEXT: call cc{{.*}} void @__invoke_void(void ()* @foo)
-; CHECK-NEXT: %[[__THREW__VAL:.*]] = load i32, i32* @__THREW__
-; CHECK-NEXT: store i32 0, i32* @__THREW__
-; CHECK-NEXT: %[[CMP0:.*]] = icmp ne i32 %[[__THREW__VAL]], 0
+; CHECK-NEXT: %[[__THREW__VAL:.*]] = load [[PTR]], [[PTR]]* @__THREW__
+; CHECK-NEXT: store [[PTR]] 0, [[PTR]]* @__THREW__
+; CHECK-NEXT: %[[CMP0:.*]] = icmp ne [[PTR]] %[[__THREW__VAL]], 0
; CHECK-NEXT: %[[THREWVALUE_VAL:.*]] = load i32, i32* @__threwValue
; CHECK-NEXT: %[[CMP1:.*]] = icmp ne i32 %[[THREWVALUE_VAL]], 0
; CHECK-NEXT: %[[CMP:.*]] = and i1 %[[CMP0]], %[[CMP1]]
; CHECK-NEXT: br i1 %[[CMP]], label %if.then1, label %if.else1
; CHECK: entry.split.split:
-; CHECK-NEXT: %[[CMP:.*]] = icmp eq i32 %[[__THREW__VAL]], 1
+; CHECK-NEXT: %[[CMP:.*]] = icmp eq [[PTR]] %[[__THREW__VAL]], 1
; CHECK-NEXT: br i1 %[[CMP]], label %lpad, label %try.cont
lpad: ; preds = %entry
@@ -191,7 +192,7 @@ entry:
call void @longjmp(%struct.__jmp_buf_tag* %arraydecay, i32 5) #1
unreachable
; CHECK: %[[JMPBUF:.*]] = ptrtoint
-; CHECK-NEXT: call void @emscripten_longjmp(i32 %[[JMPBUF]], i32 5)
+; CHECK-NEXT: call void @emscripten_longjmp([[PTR]] %[[JMPBUF]], i32 5)
}
; Test inline asm handling
@@ -265,7 +266,7 @@ entry:
; Store longjmp in a local variable, load it, and call it
store void (%struct.__jmp_buf_tag*, i32)* @longjmp, void (%struct.__jmp_buf_tag*, i32)** %local_longjmp_ptr, align 4
- ; CHECK: store void (%struct.__jmp_buf_tag*, i32)* bitcast (void (i32, i32)* @emscripten_longjmp to void (%struct.__jmp_buf_tag*, i32)*), void (%struct.__jmp_buf_tag*, i32)** %local_longjmp_ptr, align 4
+ ; CHECK: store void (%struct.__jmp_buf_tag*, i32)* bitcast (void ([[PTR]], i32)* @emscripten_longjmp to void (%struct.__jmp_buf_tag*, i32)*), void (%struct.__jmp_buf_tag*, i32)** %local_longjmp_ptr, align 4
%longjmp_from_local_ptr = load void (%struct.__jmp_buf_tag*, i32)*, void (%struct.__jmp_buf_tag*, i32)** %local_longjmp_ptr, align 4
%arraydecay = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %buf0, i32 0, i32 0
call void %longjmp_from_local_ptr(%struct.__jmp_buf_tag* %arraydecay, i32 0)
@@ -278,7 +279,7 @@ entry:
; Pass longjmp as a function argument. This is a call but longjmp is not a
; callee but an argument.
call void @take_longjmp(void (%struct.__jmp_buf_tag*, i32)* @longjmp)
- ; CHECK: call void @take_longjmp(void (%struct.__jmp_buf_tag*, i32)* bitcast (void (i32, i32)* @emscripten_longjmp to void (%struct.__jmp_buf_tag*, i32)*))
+ ; CHECK: call void @take_longjmp(void (%struct.__jmp_buf_tag*, i32)* bitcast (void ([[PTR]], i32)* @emscripten_longjmp to void (%struct.__jmp_buf_tag*, i32)*))
ret void
}
@@ -297,8 +298,8 @@ declare void @free(i8*)
; CHECK-DAG: declare i32 @getTempRet0()
; CHECK-DAG: declare void @setTempRet0(i32)
; CHECK-DAG: declare i32* @saveSetjmp(%struct.__jmp_buf_tag*, i32, i32*, i32)
-; CHECK-DAG: declare i32 @testSetjmp(i32, i32*, i32)
-; CHECK-DAG: declare void @emscripten_longjmp(i32, i32)
+; CHECK-DAG: declare i32 @testSetjmp([[PTR]], i32*, i32)
+; CHECK-DAG: declare void @emscripten_longjmp([[PTR]], i32)
; CHECK-DAG: declare void @__invoke_void(void ()*)
attributes #0 = { returns_twice }
More information about the llvm-commits
mailing list