47
47
// / These variables are used for both exceptions and setjmp/longjmps.
48
48
// / __THREW__ indicates whether an exception or a longjmp occurred or not. 0
49
49
// / 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
51
51
// / indicates the corresponding setjmp buffer the longjmp corresponds to.
52
52
// /
53
53
// / * Exception handling
54
54
// /
55
55
// / 2) We assume the existence of setThrew and setTempRet0/getTempRet0 functions
56
56
// / at link time. setThrew exists in Emscripten's compiler-rt:
57
57
// /
58
- // / void setThrew(int threw, int value) {
58
+ // / void setThrew(uintptr_t threw, int value) {
59
59
// / if (__THREW__ == 0) {
60
60
// / __THREW__ = threw;
61
61
// / __threwValue = value;
@@ -292,13 +292,12 @@ static bool canThrow(const Value *V) {
292
292
return true ;
293
293
}
294
294
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));
302
301
if (!GV)
303
302
report_fatal_error (Twine (" unable to create global: " ) + Name);
304
303
@@ -354,6 +353,28 @@ static Function *getEmscriptenFunction(FunctionType *Ty, const Twine &Name,
354
353
return F;
355
354
}
356
355
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
+
357
378
// Returns __cxa_find_matching_catch_N function, where N = NumClauses + 2.
358
379
// This is because a landingpad instruction contains two more arguments, a
359
380
// personality function and a cleanup bit, and __cxa_find_matching_catch_N
@@ -381,7 +402,8 @@ WebAssemblyLowerEmscriptenEHSjLj::getFindMatchingCatch(Module &M,
381
402
// Returns %__THREW__.val, which indicates whether an exception is thrown (or
382
403
// whether longjmp occurred), for future use.
383
404
Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke (CallBase *CI) {
384
- LLVMContext &C = CI->getModule ()->getContext ();
405
+ Module *M = CI->getModule ();
406
+ LLVMContext &C = M->getContext ();
385
407
386
408
// If we are calling a function that is noreturn, we must remove that
387
409
// attribute. The code we insert here does expect it to return, after we
@@ -397,7 +419,7 @@ Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(CallBase *CI) {
397
419
398
420
// Pre-invoke
399
421
// __THREW__ = 0;
400
- IRB.CreateStore (IRB. getInt32 ( 0 ), ThrewGV);
422
+ IRB.CreateStore (getAddrSizeInt (M, 0 ), ThrewGV);
401
423
402
424
// Invoke function wrapper in JavaScript
403
425
SmallVector<Value *, 16 > Args;
@@ -445,8 +467,8 @@ Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(CallBase *CI) {
445
467
// Post-invoke
446
468
// %__THREW__.val = __THREW__; __THREW__ = 0;
447
469
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);
450
472
return Threw;
451
473
}
452
474
@@ -541,7 +563,8 @@ void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
541
563
Value *SetjmpTableSize, Value *&Label, Value *&LongjmpResult,
542
564
BasicBlock *&EndBB) {
543
565
Function *F = BB->getParent ();
544
- LLVMContext &C = BB->getModule ()->getContext ();
566
+ Module *M = F->getParent ();
567
+ LLVMContext &C = M->getContext ();
545
568
IRBuilder<> IRB (C);
546
569
IRB.SetCurrentDebugLocation (DL);
547
570
@@ -550,7 +573,7 @@ void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
550
573
BasicBlock *ThenBB1 = BasicBlock::Create (C, " if.then1" , F);
551
574
BasicBlock *ElseBB1 = BasicBlock::Create (C, " if.else1" , F);
552
575
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 ));
554
577
Value *ThrewValue = IRB.CreateLoad (IRB.getInt32Ty (), ThrewValueGV,
555
578
ThrewValueGV->getName () + " .val" );
556
579
Value *ThrewValueCmp = IRB.CreateICmpNE (ThrewValue, IRB.getInt32 (0 ));
@@ -562,10 +585,10 @@ void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
562
585
IRB.SetInsertPoint (ThenBB1);
563
586
BasicBlock *ThenBB2 = BasicBlock::Create (C, " if.then2" , F);
564
587
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" );
569
592
Value *ThenLabel = IRB.CreateCall (
570
593
TestSetjmpF, {LoadedThrew, SetjmpTable, SetjmpTableSize}, " label" );
571
594
Value *Cmp2 = IRB.CreateICmpEQ (ThenLabel, IRB.getInt32 (0 ));
@@ -622,11 +645,12 @@ void WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA(Function &F) {
622
645
}
623
646
624
647
// 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.
628
651
static void replaceLongjmpWithEmscriptenLongjmp (Function *LongjmpF,
629
652
Function *EmLongjmpF) {
653
+ Module *M = LongjmpF->getParent ();
630
654
SmallVector<CallInst *, 8 > ToErase;
631
655
LLVMContext &C = LongjmpF->getParent ()->getContext ();
632
656
IRBuilder<> IRB (C);
@@ -638,7 +662,7 @@ static void replaceLongjmpWithEmscriptenLongjmp(Function *LongjmpF,
638
662
if (CI && CI->getCalledFunction () == LongjmpF) {
639
663
IRB.SetInsertPoint (CI);
640
664
Value *Jmpbuf =
641
- IRB.CreatePtrToInt (CI->getArgOperand (0 ), IRB. getInt32Ty ( ), " jmpbuf" );
665
+ IRB.CreatePtrToInt (CI->getArgOperand (0 ), getAddrIntType (M ), " jmpbuf" );
642
666
IRB.CreateCall (EmLongjmpF, {Jmpbuf, CI->getArgOperand (1 )});
643
667
ToErase.push_back (CI);
644
668
}
@@ -671,18 +695,15 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
671
695
assert (TPC && " Expected a TargetPassConfig" );
672
696
auto &TM = TPC->getTM <WebAssemblyTargetMachine>();
673
697
674
- if ((EnableEH || DoSjLj) &&
675
- Triple (M.getTargetTriple ()).getArch () == Triple::wasm64)
676
- report_fatal_error (" Emscripten EH/SjLj is not supported with wasm64 yet" );
677
698
if (EnableEH && TM.Options .ExceptionModel == ExceptionHandling::Wasm)
678
699
report_fatal_error (" -exception-model=wasm not allowed with "
679
700
" -enable-emscripten-cxx-exceptions" );
680
701
681
702
// Declare (or get) global variables __THREW__, __threwValue, and
682
703
// getTempRet0/setTempRet0 function which are used in common for both
683
704
// 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" );
686
707
GetTempRet0Func = getEmscriptenFunction (
687
708
FunctionType::get (IRB.getInt32Ty (), false ), " getTempRet0" , &M);
688
709
SetTempRet0Func = getEmscriptenFunction (
@@ -718,7 +739,7 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
718
739
719
740
// Register emscripten_longjmp function
720
741
FunctionType *FTy = FunctionType::get (
721
- IRB.getVoidTy (), {IRB. getInt32Ty ( ), IRB.getInt32Ty ()}, false );
742
+ IRB.getVoidTy (), {getAddrIntType (&M ), IRB.getInt32Ty ()}, false );
722
743
EmLongjmpF = getEmscriptenFunction (FTy, " emscripten_longjmp" , &M);
723
744
724
745
if (LongjmpF)
@@ -736,7 +757,8 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
736
757
// Register testSetjmp function
737
758
FTy = FunctionType::get (
738
759
IRB.getInt32Ty (),
739
- {IRB.getInt32Ty (), Type::getInt32PtrTy (C), IRB.getInt32Ty ()}, false );
760
+ {getAddrIntType (&M), Type::getInt32PtrTy (C), IRB.getInt32Ty ()},
761
+ false );
740
762
TestSetjmpF = getEmscriptenFunction (FTy, " testSetjmp" , &M);
741
763
742
764
// Only traverse functions that uses setjmp in order not to insert
@@ -794,7 +816,7 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(Function &F) {
794
816
ToErase.push_back (II);
795
817
796
818
// 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" );
798
820
IRB.CreateCondBr (Cmp, II->getUnwindDest (), II->getNormalDest ());
799
821
800
822
} else {
@@ -1060,12 +1082,15 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) {
1060
1082
// __THREW__ = 0;
1061
1083
for (auto I = std::next (BasicBlock::iterator (ThrewLI)), IE = BB->end ();
1062
1084
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 )) {
1066
1089
ThrewResetSI = SI;
1067
1090
break ;
1068
1091
}
1092
+ }
1093
+ }
1069
1094
}
1070
1095
assert (Threw && ThrewLI && " Cannot find __THREW__ load after invoke" );
1071
1096
assert (ThrewResetSI && " Cannot find __THREW__ store after invoke" );
0 commit comments