4747// / These variables are used for both exceptions and setjmp/longjmps.
4848// / __THREW__ indicates whether an exception or a longjmp occurred or not. 0
4949// / means nothing occurred, 1 means an exception occurred, and other numbers
50- // / mean a longjmp occurred. In the case of longjmp, __threwValue variable
50+ // / mean a longjmp occurred. In the case of longjmp, __THREW__ variable
5151// / indicates the corresponding setjmp buffer the longjmp corresponds to.
5252// /
5353// / * Exception handling
5454// /
5555// / 2) We assume the existence of setThrew and setTempRet0/getTempRet0 functions
5656// / at link time. setThrew exists in Emscripten's compiler-rt:
5757// /
58- // / void setThrew(int threw, int value) {
58+ // / void setThrew(uintptr_t threw, int value) {
5959// / if (__THREW__ == 0) {
6060// / __THREW__ = threw;
6161// / __threwValue = value;
@@ -292,13 +292,12 @@ static bool canThrow(const Value *V) {
292292 return true ;
293293}
294294
295- // Get a global variable with the given name. If it doesn't exist declare it,
296- // which will generate an import and asssumes that it will exist at link time.
297- static GlobalVariable *getGlobalVariableI32 (Module &M, IRBuilder<> &IRB,
298- WebAssemblyTargetMachine &TM,
299- const char *Name) {
300- auto Int32Ty = IRB.getInt32Ty ();
301- auto *GV = dyn_cast<GlobalVariable>(M.getOrInsertGlobal (Name, Int32Ty));
295+ // Get a global variable with the given name. If it doesn't exist declare it,
296+ // which will generate an import and assume that it will exist at link time.
297+ static GlobalVariable *getGlobalVariable (Module &M, Type *Ty,
298+ WebAssemblyTargetMachine &TM,
299+ const char *Name) {
300+ auto *GV = dyn_cast<GlobalVariable>(M.getOrInsertGlobal (Name, Ty));
302301 if (!GV)
303302 report_fatal_error (Twine (" unable to create global: " ) + Name);
304303
@@ -354,6 +353,28 @@ static Function *getEmscriptenFunction(FunctionType *Ty, const Twine &Name,
354353 return F;
355354}
356355
356+ // Returns an integer type for the target architecture's address space.
357+ // i32 for wasm32 and i64 for wasm64.
358+ static Type *getAddrIntType (Module *M) {
359+ IRBuilder<> IRB (M->getContext ());
360+ return IRB.getIntNTy (M->getDataLayout ().getPointerSizeInBits ());
361+ }
362+
363+ // Returns an integer pointer type for the target architecture's address space.
364+ // i32* for wasm32 and i64* for wasm64.
365+ static Type *getAddrPtrType (Module *M) {
366+ return Type::getIntNPtrTy (M->getContext (),
367+ M->getDataLayout ().getPointerSizeInBits ());
368+ }
369+
370+ // Returns an integer whose type is the integer type for the target's address
371+ // space. Returns (i32 C) for wasm32 and (i64 C) for wasm64, when C is the
372+ // integer.
373+ static Value *getAddrSizeInt (Module *M, uint64_t C) {
374+ IRBuilder<> IRB (M->getContext ());
375+ return IRB.getIntN (M->getDataLayout ().getPointerSizeInBits (), C);
376+ }
377+
357378// Returns __cxa_find_matching_catch_N function, where N = NumClauses + 2.
358379// This is because a landingpad instruction contains two more arguments, a
359380// personality function and a cleanup bit, and __cxa_find_matching_catch_N
@@ -381,7 +402,8 @@ WebAssemblyLowerEmscriptenEHSjLj::getFindMatchingCatch(Module &M,
381402// Returns %__THREW__.val, which indicates whether an exception is thrown (or
382403// whether longjmp occurred), for future use.
383404Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke (CallBase *CI) {
384- LLVMContext &C = CI->getModule ()->getContext ();
405+ Module *M = CI->getModule ();
406+ LLVMContext &C = M->getContext ();
385407
386408 // If we are calling a function that is noreturn, we must remove that
387409 // attribute. The code we insert here does expect it to return, after we
@@ -397,7 +419,7 @@ Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(CallBase *CI) {
397419
398420 // Pre-invoke
399421 // __THREW__ = 0;
400- IRB.CreateStore (IRB. getInt32 ( 0 ), ThrewGV);
422+ IRB.CreateStore (getAddrSizeInt (M, 0 ), ThrewGV);
401423
402424 // Invoke function wrapper in JavaScript
403425 SmallVector<Value *, 16 > Args;
@@ -445,8 +467,8 @@ Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(CallBase *CI) {
445467 // Post-invoke
446468 // %__THREW__.val = __THREW__; __THREW__ = 0;
447469 Value *Threw =
448- IRB.CreateLoad (IRB. getInt32Ty ( ), ThrewGV, ThrewGV->getName () + " .val" );
449- IRB.CreateStore (IRB. getInt32 ( 0 ), ThrewGV);
470+ IRB.CreateLoad (getAddrIntType (M ), ThrewGV, ThrewGV->getName () + " .val" );
471+ IRB.CreateStore (getAddrSizeInt (M, 0 ), ThrewGV);
450472 return Threw;
451473}
452474
@@ -541,7 +563,8 @@ void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
541563 Value *SetjmpTableSize, Value *&Label, Value *&LongjmpResult,
542564 BasicBlock *&EndBB) {
543565 Function *F = BB->getParent ();
544- LLVMContext &C = BB->getModule ()->getContext ();
566+ Module *M = F->getParent ();
567+ LLVMContext &C = M->getContext ();
545568 IRBuilder<> IRB (C);
546569 IRB.SetCurrentDebugLocation (DL);
547570
@@ -550,7 +573,7 @@ void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
550573 BasicBlock *ThenBB1 = BasicBlock::Create (C, " if.then1" , F);
551574 BasicBlock *ElseBB1 = BasicBlock::Create (C, " if.else1" , F);
552575 BasicBlock *EndBB1 = BasicBlock::Create (C, " if.end" , F);
553- Value *ThrewCmp = IRB.CreateICmpNE (Threw, IRB. getInt32 ( 0 ));
576+ Value *ThrewCmp = IRB.CreateICmpNE (Threw, getAddrSizeInt (M, 0 ));
554577 Value *ThrewValue = IRB.CreateLoad (IRB.getInt32Ty (), ThrewValueGV,
555578 ThrewValueGV->getName () + " .val" );
556579 Value *ThrewValueCmp = IRB.CreateICmpNE (ThrewValue, IRB.getInt32 (0 ));
@@ -562,10 +585,10 @@ void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
562585 IRB.SetInsertPoint (ThenBB1);
563586 BasicBlock *ThenBB2 = BasicBlock::Create (C, " if.then2" , F);
564587 BasicBlock *EndBB2 = BasicBlock::Create (C, " if.end2" , F);
565- Value *ThrewInt = IRB. CreateIntToPtr (Threw, Type::getInt32PtrTy (C),
566- Threw->getName () + " .i32p " );
567- Value *LoadedThrew = IRB.CreateLoad (IRB. getInt32Ty ( ), ThrewInt ,
568- ThrewInt ->getName () + " .loaded" );
588+ Value *ThrewPtr =
589+ IRB. CreateIntToPtr (Threw, getAddrPtrType (M), Threw->getName () + " .p " );
590+ Value *LoadedThrew = IRB.CreateLoad (getAddrIntType (M ), ThrewPtr ,
591+ ThrewPtr ->getName () + " .loaded" );
569592 Value *ThenLabel = IRB.CreateCall (
570593 TestSetjmpF, {LoadedThrew, SetjmpTable, SetjmpTableSize}, " label" );
571594 Value *Cmp2 = IRB.CreateICmpEQ (ThenLabel, IRB.getInt32 (0 ));
@@ -622,11 +645,12 @@ void WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA(Function &F) {
622645}
623646
624647// Replace uses of longjmp with emscripten_longjmp. emscripten_longjmp takes
625- // arguments of type {i32, i32} and longjmp takes {jmp_buf* , i32}, so we need a
626- // ptrtoint instruction here to make the type match. jmp_buf* will eventually be
627- // lowered to i32 in the wasm backend.
648+ // arguments of type {i32, i32} (wasm32) / {i64 , i32} (wasm64) and longjmp takes
649+ // {jmp_buf*, i32}, so we need a ptrtoint instruction here to make the type
650+ // match. jmp_buf* will eventually be lowered to i32 in the wasm backend.
628651static void replaceLongjmpWithEmscriptenLongjmp (Function *LongjmpF,
629652 Function *EmLongjmpF) {
653+ Module *M = LongjmpF->getParent ();
630654 SmallVector<CallInst *, 8 > ToErase;
631655 LLVMContext &C = LongjmpF->getParent ()->getContext ();
632656 IRBuilder<> IRB (C);
@@ -638,7 +662,7 @@ static void replaceLongjmpWithEmscriptenLongjmp(Function *LongjmpF,
638662 if (CI && CI->getCalledFunction () == LongjmpF) {
639663 IRB.SetInsertPoint (CI);
640664 Value *Jmpbuf =
641- IRB.CreatePtrToInt (CI->getArgOperand (0 ), IRB. getInt32Ty ( ), " jmpbuf" );
665+ IRB.CreatePtrToInt (CI->getArgOperand (0 ), getAddrIntType (M ), " jmpbuf" );
642666 IRB.CreateCall (EmLongjmpF, {Jmpbuf, CI->getArgOperand (1 )});
643667 ToErase.push_back (CI);
644668 }
@@ -671,18 +695,15 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
671695 assert (TPC && " Expected a TargetPassConfig" );
672696 auto &TM = TPC->getTM <WebAssemblyTargetMachine>();
673697
674- if ((EnableEH || DoSjLj) &&
675- Triple (M.getTargetTriple ()).getArch () == Triple::wasm64)
676- report_fatal_error (" Emscripten EH/SjLj is not supported with wasm64 yet" );
677698 if (EnableEH && TM.Options .ExceptionModel == ExceptionHandling::Wasm)
678699 report_fatal_error (" -exception-model=wasm not allowed with "
679700 " -enable-emscripten-cxx-exceptions" );
680701
681702 // Declare (or get) global variables __THREW__, __threwValue, and
682703 // getTempRet0/setTempRet0 function which are used in common for both
683704 // exception handling and setjmp/longjmp handling
684- ThrewGV = getGlobalVariableI32 (M, IRB , TM, " __THREW__" );
685- ThrewValueGV = getGlobalVariableI32 (M, IRB, TM, " __threwValue" );
705+ ThrewGV = getGlobalVariable (M, getAddrIntType (&M) , TM, " __THREW__" );
706+ ThrewValueGV = getGlobalVariable (M, IRB. getInt32Ty () , TM, " __threwValue" );
686707 GetTempRet0Func = getEmscriptenFunction (
687708 FunctionType::get (IRB.getInt32Ty (), false ), " getTempRet0" , &M);
688709 SetTempRet0Func = getEmscriptenFunction (
@@ -718,7 +739,7 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
718739
719740 // Register emscripten_longjmp function
720741 FunctionType *FTy = FunctionType::get (
721- IRB.getVoidTy (), {IRB. getInt32Ty ( ), IRB.getInt32Ty ()}, false );
742+ IRB.getVoidTy (), {getAddrIntType (&M ), IRB.getInt32Ty ()}, false );
722743 EmLongjmpF = getEmscriptenFunction (FTy, " emscripten_longjmp" , &M);
723744
724745 if (LongjmpF)
@@ -736,7 +757,8 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
736757 // Register testSetjmp function
737758 FTy = FunctionType::get (
738759 IRB.getInt32Ty (),
739- {IRB.getInt32Ty (), Type::getInt32PtrTy (C), IRB.getInt32Ty ()}, false );
760+ {getAddrIntType (&M), Type::getInt32PtrTy (C), IRB.getInt32Ty ()},
761+ false );
740762 TestSetjmpF = getEmscriptenFunction (FTy, " testSetjmp" , &M);
741763
742764 // Only traverse functions that uses setjmp in order not to insert
@@ -794,7 +816,7 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(Function &F) {
794816 ToErase.push_back (II);
795817
796818 // Insert a branch based on __THREW__ variable
797- Value *Cmp = IRB.CreateICmpEQ (Threw, IRB. getInt32 ( 1 ), " cmp" );
819+ Value *Cmp = IRB.CreateICmpEQ (Threw, getAddrSizeInt (&M, 1 ), " cmp" );
798820 IRB.CreateCondBr (Cmp, II->getUnwindDest (), II->getNormalDest ());
799821
800822 } else {
@@ -1060,12 +1082,15 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) {
10601082 // __THREW__ = 0;
10611083 for (auto I = std::next (BasicBlock::iterator (ThrewLI)), IE = BB->end ();
10621084 I != IE; ++I) {
1063- if (auto *SI = dyn_cast<StoreInst>(I))
1064- if (auto *GV = dyn_cast<GlobalVariable>(SI->getPointerOperand ()))
1065- if (GV == ThrewGV && SI->getValueOperand () == IRB.getInt32 (0 )) {
1085+ if (auto *SI = dyn_cast<StoreInst>(I)) {
1086+ if (auto *GV = dyn_cast<GlobalVariable>(SI->getPointerOperand ())) {
1087+ if (GV == ThrewGV &&
1088+ SI->getValueOperand () == getAddrSizeInt (&M, 0 )) {
10661089 ThrewResetSI = SI;
10671090 break ;
10681091 }
1092+ }
1093+ }
10691094 }
10701095 assert (Threw && ThrewLI && " Cannot find __THREW__ load after invoke" );
10711096 assert (ThrewResetSI && " Cannot find __THREW__ store after invoke" );
0 commit comments