@@ -1984,6 +1984,9 @@ Signature SignatureExpansion::getSignature() {
1984
1984
result.Attributes = Attrs;
1985
1985
using ExtraData = Signature::ExtraData;
1986
1986
if (FnType->getLanguage () == SILFunctionLanguage::C) {
1987
+ // This is a potentially throwing function. The use of 'noexcept' /
1988
+ // 'nothrow' is applied at the call site in the \c FunctionPointer class.
1989
+ ForeignInfo.canThrow = IGM.isForeignExceptionHandlingEnabled ();
1987
1990
result.ExtraDataKind = ExtraData::kindForMember<ForeignFunctionInfo>();
1988
1991
result.ExtraDataStorage .emplace <ForeignFunctionInfo>(result.ExtraDataKind ,
1989
1992
ForeignInfo);
@@ -2230,9 +2233,10 @@ class SyncCallEmission final : public CallEmission {
2230
2233
index, IGF.IGM .getMaximalTypeExpansionContext ());
2231
2234
}
2232
2235
2233
- llvm::CallInst *createCall (const FunctionPointer &fn,
2236
+ llvm::CallBase *createCall (const FunctionPointer &fn,
2234
2237
ArrayRef<llvm::Value *> args) override {
2235
- return IGF.Builder .CreateCall (fn, Args);
2238
+ return IGF.Builder .CreateCallOrInvoke (fn, Args, invokeNormalDest,
2239
+ invokeUnwindDest);
2236
2240
}
2237
2241
2238
2242
void begin () override { super::begin (); }
@@ -2379,7 +2383,8 @@ class SyncCallEmission final : public CallEmission {
2379
2383
}
2380
2384
super::setArgs (adjusted, isOutlined, witnessMetadata);
2381
2385
}
2382
- void emitCallToUnmappedExplosion (llvm::CallInst *call, Explosion &out) override {
2386
+ void emitCallToUnmappedExplosion (llvm::CallBase *call,
2387
+ Explosion &out) override {
2383
2388
// Bail out immediately on a void result.
2384
2389
llvm::Value *result = call;
2385
2390
if (result->getType ()->isVoidTy ())
@@ -2682,7 +2687,8 @@ class AsyncCallEmission final : public CallEmission {
2682
2687
saveValue (resumeParentField, fnVal, isOutlined);
2683
2688
}
2684
2689
}
2685
- void emitCallToUnmappedExplosion (llvm::CallInst *call, Explosion &out) override {
2690
+ void emitCallToUnmappedExplosion (llvm::CallBase *call,
2691
+ Explosion &out) override {
2686
2692
// Bail out on a void result type.
2687
2693
auto &IGM = IGF.IGM ;
2688
2694
llvm::Value *result = call;
@@ -2774,7 +2780,7 @@ class AsyncCallEmission final : public CallEmission {
2774
2780
return IGF.getCalleeErrorResultSlot (errorType);
2775
2781
}
2776
2782
2777
- llvm::CallInst *createCall (const FunctionPointer &fn,
2783
+ llvm::CallBase *createCall (const FunctionPointer &fn,
2778
2784
ArrayRef<llvm::Value *> args) override {
2779
2785
auto &IGM = IGF.IGM ;
2780
2786
auto &Builder = IGF.Builder ;
@@ -2904,7 +2910,7 @@ void CallEmission::emitToUnmappedMemory(Address result) {
2904
2910
}
2905
2911
2906
2912
// / The private routine to ultimately emit a call or invoke instruction.
2907
- llvm::CallInst *CallEmission::emitCallSite () {
2913
+ llvm::CallBase *CallEmission::emitCallSite () {
2908
2914
assert (state == State::Emitting);
2909
2915
assert (LastArgWritten == 0 );
2910
2916
assert (!EmittedCall);
@@ -2925,8 +2931,16 @@ llvm::CallInst *CallEmission::emitCallSite() {
2925
2931
Args[i] = IGF.coerceValue (Args[i], paramTy, IGF.IGM .DataLayout );
2926
2932
}
2927
2933
2928
- // TODO: exceptions!
2934
+ if (fn.canThrowForeignException ()) {
2935
+ if (!fn.doesForeignCallCatchExceptionInThunk ()) {
2936
+ invokeNormalDest = IGF.createBasicBlock (" invoke.cont" );
2937
+ invokeUnwindDest = IGF.createExceptionUnwindBlock ();
2938
+ } else
2939
+ IGF.setCallsThunksWithForeignExceptionTraps ();
2940
+ }
2929
2941
auto call = createCall (fn, Args);
2942
+ if (invokeNormalDest)
2943
+ IGF.Builder .emitBlock (invokeNormalDest);
2930
2944
2931
2945
// Make coroutines calls opaque to LLVM analysis.
2932
2946
if (IsCoroutine) {
@@ -2988,8 +3002,9 @@ assertTypesInByValAndStructRetAttributes(llvm::FunctionType *fnType,
2988
3002
return attrList;
2989
3003
}
2990
3004
2991
- llvm::CallInst *IRBuilder::CreateCall (const FunctionPointer &fn,
2992
- ArrayRef<llvm::Value*> args) {
3005
+ llvm::CallBase *IRBuilder::CreateCallOrInvoke (
3006
+ const FunctionPointer &fn, ArrayRef<llvm::Value *> args,
3007
+ llvm::BasicBlock *invokeNormalDest, llvm::BasicBlock *invokeUnwindDest) {
2993
3008
assert (fn.getKind () == FunctionPointer::Kind::Function);
2994
3009
SmallVector<llvm::OperandBundleDef, 1 > bundles;
2995
3010
@@ -3003,8 +3018,13 @@ llvm::CallInst *IRBuilder::CreateCall(const FunctionPointer &fn,
3003
3018
3004
3019
assert (!isTrapIntrinsic (fn.getRawPointer ()) && " Use CreateNonMergeableTrap" );
3005
3020
auto fnTy = cast<llvm::FunctionType>(fn.getFunctionType ());
3006
- llvm::CallInst *call =
3007
- IRBuilderBase::CreateCall (fnTy, fn.getRawPointer (), args, bundles);
3021
+ llvm::CallBase *call;
3022
+ if (!fn.shouldUseInvoke ())
3023
+ call = IRBuilderBase::CreateCall (fnTy, fn.getRawPointer (), args, bundles);
3024
+ else
3025
+ call =
3026
+ IRBuilderBase::CreateInvoke (fnTy, fn.getRawPointer (), invokeNormalDest,
3027
+ invokeUnwindDest, args, bundles);
3008
3028
3009
3029
llvm::AttributeList attrs = fn.getAttributes ();
3010
3030
// If a parameter of a function is SRet, the corresponding argument should be
@@ -3028,6 +3048,13 @@ llvm::CallInst *IRBuilder::CreateCall(const FunctionPointer &fn,
3028
3048
return call;
3029
3049
}
3030
3050
3051
+ llvm::CallInst *IRBuilder::CreateCall (const FunctionPointer &fn,
3052
+ ArrayRef<llvm::Value *> args) {
3053
+ assert (!fn.shouldUseInvoke ());
3054
+ return cast<llvm::CallInst>(CreateCallOrInvoke (
3055
+ fn, args, /* invokeNormalDest=*/ nullptr , /* invokeUnwindDest=*/ nullptr ));
3056
+ }
3057
+
3031
3058
// / Emit the result of this call to memory.
3032
3059
void CallEmission::emitToMemory (Address addr,
3033
3060
const LoadableTypeInfo &indirectedResultTI,
@@ -4425,6 +4452,40 @@ void IRGenFunction::emitBBForReturn() {
4425
4452
CurFn->getBasicBlockList ().push_back (ReturnBB);
4426
4453
}
4427
4454
4455
+ llvm::BasicBlock *IRGenFunction::createExceptionUnwindBlock () {
4456
+ auto *result = createBasicBlock (" exception.unwind" );
4457
+ IRBuilder::SavedInsertionPointRAII insertRAII (Builder, result);
4458
+
4459
+ // Create a catch-all landing pad.
4460
+ // FIXME: Refactor Clang/lib/CodeGen to call into Clang here.
4461
+ // FIXME: MSVC support.
4462
+ llvm::LandingPadInst *lpad = Builder.CreateLandingPad (
4463
+ llvm::StructType::get (IGM.Int8PtrTy , IGM.Int32Ty ), 0 );
4464
+ lpad->addClause (llvm::ConstantPointerNull::get (IGM.Int8PtrTy ));
4465
+
4466
+ // The trap with a message informs the user that the exception hasn't
4467
+ // been caught. The trap creates a new debug inline frame for the message,
4468
+ // so ensure that the current debug location is preserved.
4469
+ auto oldDebugLoc = Builder.getCurrentDebugLocation ();
4470
+ emitTrap (IGM.Context .LangOpts .EnableObjCInterop
4471
+ ? " unhandled C++ / Objective-C exception"
4472
+ : " unhandled C++ exception" ,
4473
+ /* Unreachable=*/ true );
4474
+ Builder.SetCurrentDebugLocation (oldDebugLoc);
4475
+
4476
+ ExceptionUnwindBlocks.push_back (result);
4477
+ return result;
4478
+ }
4479
+
4480
+ void IRGenFunction::createExceptionTrapScope (
4481
+ llvm::function_ref<void (llvm::BasicBlock *, llvm::BasicBlock *)>
4482
+ invokeEmitter) {
4483
+ auto *invokeNormalDest = createBasicBlock (" invoke.cont" );
4484
+ auto *invokeUnwindDest = createExceptionUnwindBlock ();
4485
+ invokeEmitter (invokeNormalDest, invokeUnwindDest);
4486
+ Builder.emitBlock (invokeNormalDest);
4487
+ }
4488
+
4428
4489
// / Emit the prologue for the function.
4429
4490
void IRGenFunction::emitPrologue () {
4430
4491
// Set up the IRBuilder.
@@ -4475,12 +4536,42 @@ bool IRGenFunction::emitBranchToReturnBB() {
4475
4536
return true ;
4476
4537
}
4477
4538
4539
+ llvm::Function *IRGenModule::getForeignExceptionHandlingPersonalityFunc () {
4540
+ if (foreignExceptionHandlingPersonalityFunc)
4541
+ return foreignExceptionHandlingPersonalityFunc;
4542
+ foreignExceptionHandlingPersonalityFunc = llvm::Function::Create (
4543
+ llvm::FunctionType::get (Int32Ty, true ), llvm::Function::ExternalLinkage,
4544
+ " __gxx_personality_v0" , getModule ());
4545
+ return foreignExceptionHandlingPersonalityFunc;
4546
+ }
4547
+
4548
+ bool IRGenModule::isForeignExceptionHandlingEnabled () const {
4549
+ // FIXME: Support exceptions on windows MSVC.
4550
+ if (Triple.isWindowsMSVCEnvironment ())
4551
+ return false ;
4552
+ const auto &clangLangOpts =
4553
+ Context.getClangModuleLoader ()->getClangASTContext ().getLangOpts ();
4554
+ return Context.LangOpts .EnableCXXInterop && clangLangOpts.Exceptions &&
4555
+ !clangLangOpts.IgnoreExceptions ;
4556
+ }
4557
+
4478
4558
// / Emit the epilogue for the function.
4479
4559
void IRGenFunction::emitEpilogue () {
4480
4560
if (EarliestIP != AllocaIP)
4481
4561
EarliestIP->eraseFromParent ();
4482
4562
// Destroy the alloca insertion point.
4483
4563
AllocaIP->eraseFromParent ();
4564
+ // Add exception unwind blocks and additional exception handling info
4565
+ // if needed.
4566
+ if (!ExceptionUnwindBlocks.empty () ||
4567
+ callsAnyAlwaysInlineThunksWithForeignExceptionTraps) {
4568
+ // The function should have an unwind table when catching exceptions.
4569
+ CurFn->addFnAttr (llvm::Attribute::getWithUWTableKind (
4570
+ *IGM.LLVMContext , llvm::UWTableKind::Default));
4571
+ CurFn->setPersonalityFn (IGM.getForeignExceptionHandlingPersonalityFunc ());
4572
+ }
4573
+ for (auto *bb : ExceptionUnwindBlocks)
4574
+ CurFn->getBasicBlockList ().push_back (bb);
4484
4575
}
4485
4576
4486
4577
std::pair<Address, Size>
0 commit comments