@@ -1982,6 +1982,17 @@ Signature SignatureExpansion::getSignature() {
1982
1982
result.Attributes = Attrs;
1983
1983
using ExtraData = Signature::ExtraData;
1984
1984
if (FnType->getLanguage () == SILFunctionLanguage::C) {
1985
+ const auto &clangLangOpts =
1986
+ IGM.Context .getClangModuleLoader ()->getClangASTContext ().getLangOpts ();
1987
+ bool exceptionHandlingEnabled = IGM.Context .LangOpts .EnableCXXInterop &&
1988
+ clangLangOpts.Exceptions &&
1989
+ !clangLangOpts.IgnoreExceptions ;
1990
+ // FIXME: Support exceptions on windows MSVC.
1991
+ if (IGM.Triple .isWindowsMSVCEnvironment ())
1992
+ exceptionHandlingEnabled = false ;
1993
+ // This is a potentially throwing function. The use of 'noexcept' /
1994
+ // 'nothrow' is applied at the call site in the \c FunctionPointer class.
1995
+ ForeignInfo.canThrow = exceptionHandlingEnabled;
1985
1996
result.ExtraDataKind = ExtraData::kindForMember<ForeignFunctionInfo>();
1986
1997
result.ExtraDataStorage .emplace <ForeignFunctionInfo>(result.ExtraDataKind ,
1987
1998
ForeignInfo);
@@ -2227,9 +2238,10 @@ class SyncCallEmission final : public CallEmission {
2227
2238
index, IGF.IGM .getMaximalTypeExpansionContext ());
2228
2239
}
2229
2240
2230
- llvm::CallInst *createCall (const FunctionPointer &fn,
2241
+ llvm::CallBase *createCall (const FunctionPointer &fn,
2231
2242
ArrayRef<llvm::Value *> args) override {
2232
- return IGF.Builder .CreateCall (fn, Args);
2243
+ return IGF.Builder .CreateCallOrInvoke (fn, Args, invokeNormalDest,
2244
+ invokeUnwindDest);
2233
2245
}
2234
2246
2235
2247
void begin () override { super::begin (); }
@@ -2375,7 +2387,8 @@ class SyncCallEmission final : public CallEmission {
2375
2387
}
2376
2388
super::setArgs (adjusted, isOutlined, witnessMetadata);
2377
2389
}
2378
- void emitCallToUnmappedExplosion (llvm::CallInst *call, Explosion &out) override {
2390
+ void emitCallToUnmappedExplosion (llvm::CallBase *call,
2391
+ Explosion &out) override {
2379
2392
// Bail out immediately on a void result.
2380
2393
llvm::Value *result = call;
2381
2394
if (result->getType ()->isVoidTy ())
@@ -2678,7 +2691,8 @@ class AsyncCallEmission final : public CallEmission {
2678
2691
saveValue (resumeParentField, fnVal, isOutlined);
2679
2692
}
2680
2693
}
2681
- void emitCallToUnmappedExplosion (llvm::CallInst *call, Explosion &out) override {
2694
+ void emitCallToUnmappedExplosion (llvm::CallBase *call,
2695
+ Explosion &out) override {
2682
2696
// Bail out on a void result type.
2683
2697
auto &IGM = IGF.IGM ;
2684
2698
llvm::Value *result = call;
@@ -2770,7 +2784,7 @@ class AsyncCallEmission final : public CallEmission {
2770
2784
return IGF.getCalleeErrorResultSlot (errorType);
2771
2785
}
2772
2786
2773
- llvm::CallInst *createCall (const FunctionPointer &fn,
2787
+ llvm::CallBase *createCall (const FunctionPointer &fn,
2774
2788
ArrayRef<llvm::Value *> args) override {
2775
2789
auto &IGM = IGF.IGM ;
2776
2790
auto &Builder = IGF.Builder ;
@@ -2900,7 +2914,7 @@ void CallEmission::emitToUnmappedMemory(Address result) {
2900
2914
}
2901
2915
2902
2916
// / The private routine to ultimately emit a call or invoke instruction.
2903
- llvm::CallInst *CallEmission::emitCallSite () {
2917
+ llvm::CallBase *CallEmission::emitCallSite () {
2904
2918
assert (state == State::Emitting);
2905
2919
assert (LastArgWritten == 0 );
2906
2920
assert (!EmittedCall);
@@ -2921,8 +2935,13 @@ llvm::CallInst *CallEmission::emitCallSite() {
2921
2935
Args[i] = IGF.coerceValue (Args[i], paramTy, IGF.IGM .DataLayout );
2922
2936
}
2923
2937
2924
- // TODO: exceptions!
2938
+ if (fn.canThrowForeignException ()) {
2939
+ invokeNormalDest = IGF.createBasicBlock (" invoke.cont" );
2940
+ invokeUnwindDest = IGF.createExceptionUnwindBlock ();
2941
+ }
2925
2942
auto call = createCall (fn, Args);
2943
+ if (invokeNormalDest)
2944
+ IGF.Builder .emitBlock (invokeNormalDest);
2926
2945
2927
2946
// Make coroutines calls opaque to LLVM analysis.
2928
2947
if (IsCoroutine) {
@@ -2984,8 +3003,9 @@ assertTypesInByValAndStructRetAttributes(llvm::FunctionType *fnType,
2984
3003
return attrList;
2985
3004
}
2986
3005
2987
- llvm::CallInst *IRBuilder::CreateCall (const FunctionPointer &fn,
2988
- ArrayRef<llvm::Value*> args) {
3006
+ llvm::CallBase *IRBuilder::CreateCallOrInvoke (
3007
+ const FunctionPointer &fn, ArrayRef<llvm::Value *> args,
3008
+ llvm::BasicBlock *invokeNormalDest, llvm::BasicBlock *invokeUnwindDest) {
2989
3009
assert (fn.getKind () == FunctionPointer::Kind::Function);
2990
3010
SmallVector<llvm::OperandBundleDef, 1 > bundles;
2991
3011
@@ -2999,8 +3019,13 @@ llvm::CallInst *IRBuilder::CreateCall(const FunctionPointer &fn,
2999
3019
3000
3020
assert (!isTrapIntrinsic (fn.getRawPointer ()) && " Use CreateNonMergeableTrap" );
3001
3021
auto fnTy = cast<llvm::FunctionType>(fn.getFunctionType ());
3002
- llvm::CallInst *call =
3003
- IRBuilderBase::CreateCall (fnTy, fn.getRawPointer (), args, bundles);
3022
+ llvm::CallBase *call;
3023
+ if (!fn.canThrowForeignException ())
3024
+ call = IRBuilderBase::CreateCall (fnTy, fn.getRawPointer (), args, bundles);
3025
+ else
3026
+ call =
3027
+ IRBuilderBase::CreateInvoke (fnTy, fn.getRawPointer (), invokeNormalDest,
3028
+ invokeUnwindDest, args, bundles);
3004
3029
3005
3030
llvm::AttributeList attrs = fn.getAttributes ();
3006
3031
// If a parameter of a function is SRet, the corresponding argument should be
@@ -3024,6 +3049,13 @@ llvm::CallInst *IRBuilder::CreateCall(const FunctionPointer &fn,
3024
3049
return call;
3025
3050
}
3026
3051
3052
+ llvm::CallInst *IRBuilder::CreateCall (const FunctionPointer &fn,
3053
+ ArrayRef<llvm::Value *> args) {
3054
+ assert (!fn.canThrowForeignException ());
3055
+ return cast<llvm::CallInst>(CreateCallOrInvoke (
3056
+ fn, args, /* invokeNormalDest=*/ nullptr , /* invokeUnwindDest=*/ nullptr ));
3057
+ }
3058
+
3027
3059
// / Emit the result of this call to memory.
3028
3060
void CallEmission::emitToMemory (Address addr,
3029
3061
const LoadableTypeInfo &indirectedResultTI,
@@ -4416,6 +4448,31 @@ void IRGenFunction::emitBBForReturn() {
4416
4448
CurFn->getBasicBlockList ().push_back (ReturnBB);
4417
4449
}
4418
4450
4451
+ llvm::BasicBlock *IRGenFunction::createExceptionUnwindBlock () {
4452
+ auto *result = createBasicBlock (" exception.unwind" );
4453
+ IRBuilder::SavedInsertionPointRAII insertRAII (Builder, result);
4454
+
4455
+ // Create a catch-all landing pad.
4456
+ // FIXME: Refactor Clang/lib/CodeGen to call into Clang here.
4457
+ // FIXME: MSVC support.
4458
+ llvm::LandingPadInst *lpad = Builder.CreateLandingPad (
4459
+ llvm::StructType::get (IGM.Int8PtrTy , IGM.Int32Ty ), 0 );
4460
+ lpad->addClause (llvm::ConstantPointerNull::get (IGM.Int8PtrTy ));
4461
+
4462
+ // The trap with a message informs the user that the exception hasn't
4463
+ // been caught. The trap creates a new debug inline frame for the message,
4464
+ // so ensure that the current debug location is preserved.
4465
+ auto oldDebugLoc = Builder.getCurrentDebugLocation ();
4466
+ emitTrap (IGM.Context .LangOpts .EnableObjCInterop
4467
+ ? " unhandled C++ / Objective-C exception"
4468
+ : " unhandled C++ exception" ,
4469
+ /* Unreachable=*/ true );
4470
+ Builder.SetCurrentDebugLocation (oldDebugLoc);
4471
+
4472
+ ExceptionUnwindBlocks.push_back (result);
4473
+ return result;
4474
+ }
4475
+
4419
4476
// / Emit the prologue for the function.
4420
4477
void IRGenFunction::emitPrologue () {
4421
4478
// Set up the IRBuilder.
@@ -4466,12 +4523,31 @@ bool IRGenFunction::emitBranchToReturnBB() {
4466
4523
return true ;
4467
4524
}
4468
4525
4526
+ llvm::Function *IRGenModule::getForeignExceptionHandlingPersonalityFunc () {
4527
+ if (foreignExceptionHandlingPersonalityFunc)
4528
+ return foreignExceptionHandlingPersonalityFunc;
4529
+ foreignExceptionHandlingPersonalityFunc = llvm::Function::Create (
4530
+ llvm::FunctionType::get (Int32Ty, true ), llvm::Function::ExternalLinkage,
4531
+ " __gxx_personality_v0" , getModule ());
4532
+ return foreignExceptionHandlingPersonalityFunc;
4533
+ }
4534
+
4469
4535
// / Emit the epilogue for the function.
4470
4536
void IRGenFunction::emitEpilogue () {
4471
4537
if (EarliestIP != AllocaIP)
4472
4538
EarliestIP->eraseFromParent ();
4473
4539
// Destroy the alloca insertion point.
4474
4540
AllocaIP->eraseFromParent ();
4541
+ // Add exception unwind blocks and additional exception handling info
4542
+ // if needed.
4543
+ if (!ExceptionUnwindBlocks.empty ()) {
4544
+ // The function should have an unwind table when catching exceptions.
4545
+ CurFn->addFnAttr (llvm::Attribute::getWithUWTableKind (
4546
+ *IGM.LLVMContext , llvm::UWTableKind::Default));
4547
+ CurFn->setPersonalityFn (IGM.getForeignExceptionHandlingPersonalityFunc ());
4548
+ for (auto *bb : ExceptionUnwindBlocks)
4549
+ CurFn->getBasicBlockList ().push_back (bb);
4550
+ }
4475
4551
}
4476
4552
4477
4553
std::pair<Address, Size>
0 commit comments