@@ -1982,6 +1982,9 @@ Signature SignatureExpansion::getSignature() {
1982
1982
result.Attributes = Attrs;
1983
1983
using ExtraData = Signature::ExtraData;
1984
1984
if (FnType->getLanguage () == SILFunctionLanguage::C) {
1985
+ // This is a potentially throwing function. The use of 'noexcept' /
1986
+ // 'nothrow' is applied at the call site in the \c FunctionPointer class.
1987
+ ForeignInfo.canThrow = IGM.isForeignExceptionHandlingEnabled ();
1985
1988
result.ExtraDataKind = ExtraData::kindForMember<ForeignFunctionInfo>();
1986
1989
result.ExtraDataStorage .emplace <ForeignFunctionInfo>(result.ExtraDataKind ,
1987
1990
ForeignInfo);
@@ -2227,9 +2230,10 @@ class SyncCallEmission final : public CallEmission {
2227
2230
index, IGF.IGM .getMaximalTypeExpansionContext ());
2228
2231
}
2229
2232
2230
- llvm::CallInst *createCall (const FunctionPointer &fn,
2233
+ llvm::CallBase *createCall (const FunctionPointer &fn,
2231
2234
ArrayRef<llvm::Value *> args) override {
2232
- return IGF.Builder .CreateCall (fn, Args);
2235
+ return IGF.Builder .CreateCallOrInvoke (fn, Args, invokeNormalDest,
2236
+ invokeUnwindDest);
2233
2237
}
2234
2238
2235
2239
void begin () override { super::begin (); }
@@ -2375,7 +2379,8 @@ class SyncCallEmission final : public CallEmission {
2375
2379
}
2376
2380
super::setArgs (adjusted, isOutlined, witnessMetadata);
2377
2381
}
2378
- void emitCallToUnmappedExplosion (llvm::CallInst *call, Explosion &out) override {
2382
+ void emitCallToUnmappedExplosion (llvm::CallBase *call,
2383
+ Explosion &out) override {
2379
2384
// Bail out immediately on a void result.
2380
2385
llvm::Value *result = call;
2381
2386
if (result->getType ()->isVoidTy ())
@@ -2678,7 +2683,8 @@ class AsyncCallEmission final : public CallEmission {
2678
2683
saveValue (resumeParentField, fnVal, isOutlined);
2679
2684
}
2680
2685
}
2681
- void emitCallToUnmappedExplosion (llvm::CallInst *call, Explosion &out) override {
2686
+ void emitCallToUnmappedExplosion (llvm::CallBase *call,
2687
+ Explosion &out) override {
2682
2688
// Bail out on a void result type.
2683
2689
auto &IGM = IGF.IGM ;
2684
2690
llvm::Value *result = call;
@@ -2770,7 +2776,7 @@ class AsyncCallEmission final : public CallEmission {
2770
2776
return IGF.getCalleeErrorResultSlot (errorType);
2771
2777
}
2772
2778
2773
- llvm::CallInst *createCall (const FunctionPointer &fn,
2779
+ llvm::CallBase *createCall (const FunctionPointer &fn,
2774
2780
ArrayRef<llvm::Value *> args) override {
2775
2781
auto &IGM = IGF.IGM ;
2776
2782
auto &Builder = IGF.Builder ;
@@ -2900,7 +2906,7 @@ void CallEmission::emitToUnmappedMemory(Address result) {
2900
2906
}
2901
2907
2902
2908
// / The private routine to ultimately emit a call or invoke instruction.
2903
- llvm::CallInst *CallEmission::emitCallSite () {
2909
+ llvm::CallBase *CallEmission::emitCallSite () {
2904
2910
assert (state == State::Emitting);
2905
2911
assert (LastArgWritten == 0 );
2906
2912
assert (!EmittedCall);
@@ -2921,8 +2927,16 @@ llvm::CallInst *CallEmission::emitCallSite() {
2921
2927
Args[i] = IGF.coerceValue (Args[i], paramTy, IGF.IGM .DataLayout );
2922
2928
}
2923
2929
2924
- // TODO: exceptions!
2930
+ if (fn.canThrowForeignException ()) {
2931
+ if (!fn.doesForeignCallCatchExceptionInThunk ()) {
2932
+ invokeNormalDest = IGF.createBasicBlock (" invoke.cont" );
2933
+ invokeUnwindDest = IGF.createExceptionUnwindBlock ();
2934
+ } else
2935
+ IGF.setCallsThunksWithForeignExceptionTraps ();
2936
+ }
2925
2937
auto call = createCall (fn, Args);
2938
+ if (invokeNormalDest)
2939
+ IGF.Builder .emitBlock (invokeNormalDest);
2926
2940
2927
2941
// Make coroutines calls opaque to LLVM analysis.
2928
2942
if (IsCoroutine) {
@@ -2984,8 +2998,9 @@ assertTypesInByValAndStructRetAttributes(llvm::FunctionType *fnType,
2984
2998
return attrList;
2985
2999
}
2986
3000
2987
- llvm::CallInst *IRBuilder::CreateCall (const FunctionPointer &fn,
2988
- ArrayRef<llvm::Value*> args) {
3001
+ llvm::CallBase *IRBuilder::CreateCallOrInvoke (
3002
+ const FunctionPointer &fn, ArrayRef<llvm::Value *> args,
3003
+ llvm::BasicBlock *invokeNormalDest, llvm::BasicBlock *invokeUnwindDest) {
2989
3004
assert (fn.getKind () == FunctionPointer::Kind::Function);
2990
3005
SmallVector<llvm::OperandBundleDef, 1 > bundles;
2991
3006
@@ -2999,8 +3014,13 @@ llvm::CallInst *IRBuilder::CreateCall(const FunctionPointer &fn,
2999
3014
3000
3015
assert (!isTrapIntrinsic (fn.getRawPointer ()) && " Use CreateNonMergeableTrap" );
3001
3016
auto fnTy = cast<llvm::FunctionType>(fn.getFunctionType ());
3002
- llvm::CallInst *call =
3003
- IRBuilderBase::CreateCall (fnTy, fn.getRawPointer (), args, bundles);
3017
+ llvm::CallBase *call;
3018
+ if (!fn.shouldUseInvoke ())
3019
+ call = IRBuilderBase::CreateCall (fnTy, fn.getRawPointer (), args, bundles);
3020
+ else
3021
+ call =
3022
+ IRBuilderBase::CreateInvoke (fnTy, fn.getRawPointer (), invokeNormalDest,
3023
+ invokeUnwindDest, args, bundles);
3004
3024
3005
3025
llvm::AttributeList attrs = fn.getAttributes ();
3006
3026
// If a parameter of a function is SRet, the corresponding argument should be
@@ -3024,6 +3044,13 @@ llvm::CallInst *IRBuilder::CreateCall(const FunctionPointer &fn,
3024
3044
return call;
3025
3045
}
3026
3046
3047
+ llvm::CallInst *IRBuilder::CreateCall (const FunctionPointer &fn,
3048
+ ArrayRef<llvm::Value *> args) {
3049
+ assert (!fn.shouldUseInvoke ());
3050
+ return cast<llvm::CallInst>(CreateCallOrInvoke (
3051
+ fn, args, /* invokeNormalDest=*/ nullptr , /* invokeUnwindDest=*/ nullptr ));
3052
+ }
3053
+
3027
3054
// / Emit the result of this call to memory.
3028
3055
void CallEmission::emitToMemory (Address addr,
3029
3056
const LoadableTypeInfo &indirectedResultTI,
@@ -4416,6 +4443,40 @@ void IRGenFunction::emitBBForReturn() {
4416
4443
CurFn->getBasicBlockList ().push_back (ReturnBB);
4417
4444
}
4418
4445
4446
+ llvm::BasicBlock *IRGenFunction::createExceptionUnwindBlock () {
4447
+ auto *result = createBasicBlock (" exception.unwind" );
4448
+ IRBuilder::SavedInsertionPointRAII insertRAII (Builder, result);
4449
+
4450
+ // Create a catch-all landing pad.
4451
+ // FIXME: Refactor Clang/lib/CodeGen to call into Clang here.
4452
+ // FIXME: MSVC support.
4453
+ llvm::LandingPadInst *lpad = Builder.CreateLandingPad (
4454
+ llvm::StructType::get (IGM.Int8PtrTy , IGM.Int32Ty ), 0 );
4455
+ lpad->addClause (llvm::ConstantPointerNull::get (IGM.Int8PtrTy ));
4456
+
4457
+ // The trap with a message informs the user that the exception hasn't
4458
+ // been caught. The trap creates a new debug inline frame for the message,
4459
+ // so ensure that the current debug location is preserved.
4460
+ auto oldDebugLoc = Builder.getCurrentDebugLocation ();
4461
+ emitTrap (IGM.Context .LangOpts .EnableObjCInterop
4462
+ ? " unhandled C++ / Objective-C exception"
4463
+ : " unhandled C++ exception" ,
4464
+ /* Unreachable=*/ true );
4465
+ Builder.SetCurrentDebugLocation (oldDebugLoc);
4466
+
4467
+ ExceptionUnwindBlocks.push_back (result);
4468
+ return result;
4469
+ }
4470
+
4471
+ void IRGenFunction::createExceptionTrapScope (
4472
+ llvm::function_ref<void (llvm::BasicBlock *, llvm::BasicBlock *)>
4473
+ invokeEmitter) {
4474
+ auto *invokeNormalDest = createBasicBlock (" invoke.cont" );
4475
+ auto *invokeUnwindDest = createExceptionUnwindBlock ();
4476
+ invokeEmitter (invokeNormalDest, invokeUnwindDest);
4477
+ Builder.emitBlock (invokeNormalDest);
4478
+ }
4479
+
4419
4480
// / Emit the prologue for the function.
4420
4481
void IRGenFunction::emitPrologue () {
4421
4482
// Set up the IRBuilder.
@@ -4466,12 +4527,42 @@ bool IRGenFunction::emitBranchToReturnBB() {
4466
4527
return true ;
4467
4528
}
4468
4529
4530
+ llvm::Function *IRGenModule::getForeignExceptionHandlingPersonalityFunc () {
4531
+ if (foreignExceptionHandlingPersonalityFunc)
4532
+ return foreignExceptionHandlingPersonalityFunc;
4533
+ foreignExceptionHandlingPersonalityFunc = llvm::Function::Create (
4534
+ llvm::FunctionType::get (Int32Ty, true ), llvm::Function::ExternalLinkage,
4535
+ " __gxx_personality_v0" , getModule ());
4536
+ return foreignExceptionHandlingPersonalityFunc;
4537
+ }
4538
+
4539
+ bool IRGenModule::isForeignExceptionHandlingEnabled () const {
4540
+ // FIXME: Support exceptions on windows MSVC.
4541
+ if (Triple.isWindowsMSVCEnvironment ())
4542
+ return false ;
4543
+ const auto &clangLangOpts =
4544
+ Context.getClangModuleLoader ()->getClangASTContext ().getLangOpts ();
4545
+ return Context.LangOpts .EnableCXXInterop && clangLangOpts.Exceptions &&
4546
+ !clangLangOpts.IgnoreExceptions ;
4547
+ }
4548
+
4469
4549
// / Emit the epilogue for the function.
4470
4550
void IRGenFunction::emitEpilogue () {
4471
4551
if (EarliestIP != AllocaIP)
4472
4552
EarliestIP->eraseFromParent ();
4473
4553
// Destroy the alloca insertion point.
4474
4554
AllocaIP->eraseFromParent ();
4555
+ // Add exception unwind blocks and additional exception handling info
4556
+ // if needed.
4557
+ if (!ExceptionUnwindBlocks.empty () ||
4558
+ callsAnyAlwaysInlineThunksWithForeignExceptionTraps) {
4559
+ // The function should have an unwind table when catching exceptions.
4560
+ CurFn->addFnAttr (llvm::Attribute::getWithUWTableKind (
4561
+ *IGM.LLVMContext , llvm::UWTableKind::Default));
4562
+ CurFn->setPersonalityFn (IGM.getForeignExceptionHandlingPersonalityFunc ());
4563
+ }
4564
+ for (auto *bb : ExceptionUnwindBlocks)
4565
+ CurFn->getBasicBlockList ().push_back (bb);
4475
4566
}
4476
4567
4477
4568
std::pair<Address, Size>
0 commit comments