Skip to content

Commit bf1bfbe

Browse files
Merge pull request #68833 from aschwaighofer/irgen_typed_throws
Preliminary IRGen support for typed throws
2 parents a8296e1 + 6b74f51 commit bf1bfbe

File tree

9 files changed

+503
-70
lines changed

9 files changed

+503
-70
lines changed

include/swift/SIL/SILFunctionConventions.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,11 @@ class SILFunctionConventions {
214214
return getSILType(funcTy->getErrorResult(), context);
215215
}
216216

217+
bool isTypedError() const {
218+
return !funcTy->getErrorResult()
219+
.getInterfaceType()->isExistentialWithError();
220+
}
221+
217222
/// Returns an array of result info.
218223
/// Provides convenient access to the underlying SILFunctionType.
219224
ArrayRef<SILResultInfo> getResults() const {

lib/IRGen/EntryPointArgumentEmission.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class NativeCCEntryPointArgumentEmission
4545
public:
4646
virtual void mapAsyncParameters() = 0;
4747
virtual llvm::Value *getCallerErrorResultArgument() = 0;
48+
virtual llvm::Value *getCallerTypedErrorResultArgument() = 0;
4849
virtual llvm::Value *getContext() = 0;
4950
virtual Explosion getArgumentExplosion(unsigned index, unsigned size) = 0;
5051
virtual llvm::Value *getSelfWitnessTable() = 0;

lib/IRGen/GenBuiltin.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,7 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
581581
auto error = args.claimNext();
582582
auto errorTy = IGF.IGM.Context.getErrorExistentialType();
583583
auto errorBuffer = IGF.getCalleeErrorResultSlot(
584-
SILType::getPrimitiveObjectType(errorTy));
584+
SILType::getPrimitiveObjectType(errorTy), false);
585585
IGF.Builder.CreateStore(error, errorBuffer);
586586

587587
auto context = llvm::UndefValue::get(IGF.IGM.Int8PtrTy);

lib/IRGen/GenCall.cpp

Lines changed: 110 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,9 @@ namespace {
517517

518518
void expandCoroutineResult(bool forContinuation);
519519
void expandCoroutineContinuationParameters();
520+
521+
void addIndirectThrowingResult();
522+
llvm::Type *getErrorRegisterType();
520523
};
521524
} // end anonymous namespace
522525
} // end namespace irgen
@@ -1850,12 +1853,16 @@ void SignatureExpansion::expandParameters(
18501853
if (FnType->hasErrorResult()) {
18511854
if (claimError())
18521855
IGM.addSwiftErrorAttributes(Attrs, ParamIRTypes.size());
1853-
llvm::Type *errorType =
1854-
IGM.getStorageType(getSILFuncConventions().getSILType(
1855-
FnType->getErrorResult(), IGM.getMaximalTypeExpansionContext()));
1856+
llvm::Type *errorType = getErrorRegisterType();
18561857
ParamIRTypes.push_back(errorType->getPointerTo());
18571858
if (recordedABIDetails)
18581859
recordedABIDetails->hasErrorResult = true;
1860+
if (getSILFuncConventions().isTypedError()) {
1861+
ParamIRTypes.push_back(
1862+
IGM.getStorageType(getSILFuncConventions().getSILType(
1863+
FnType->getErrorResult(), IGM.getMaximalTypeExpansionContext())
1864+
)->getPointerTo());
1865+
}
18591866
}
18601867

18611868
// Witness methods have some extra parameter types.
@@ -1903,6 +1910,14 @@ void SignatureExpansion::expandCoroutineContinuationType() {
19031910
expandCoroutineContinuationParameters();
19041911
}
19051912

1913+
llvm::Type *SignatureExpansion::getErrorRegisterType() {
1914+
if (getSILFuncConventions().isTypedError())
1915+
return IGM.Int8PtrTy;
1916+
1917+
return IGM.getStorageType(getSILFuncConventions().getSILType(
1918+
FnType->getErrorResult(), IGM.getMaximalTypeExpansionContext()));
1919+
}
1920+
19061921
void SignatureExpansion::expandAsyncReturnType() {
19071922
// Build up the signature of the return continuation function.
19081923
// void (AsyncTask *, ExecutorRef, AsyncContext *, DirectResult0, ...,
@@ -1914,9 +1929,7 @@ void SignatureExpansion::expandAsyncReturnType() {
19141929
auto addErrorResult = [&]() {
19151930
// Add the error pointer at the end.
19161931
if (FnType->hasErrorResult()) {
1917-
llvm::Type *errorType =
1918-
IGM.getStorageType(getSILFuncConventions().getSILType(
1919-
FnType->getErrorResult(), IGM.getMaximalTypeExpansionContext()));
1932+
llvm::Type *errorType = getErrorRegisterType();
19201933
claimSelf();
19211934
auto selfIdx = ParamIRTypes.size();
19221935
IGM.addSwiftSelfAttributes(Attrs, selfIdx);
@@ -1943,6 +1956,17 @@ void SignatureExpansion::expandAsyncReturnType() {
19431956
addErrorResult();
19441957
}
19451958

1959+
void SignatureExpansion::addIndirectThrowingResult() {
1960+
if (getSILFuncConventions().funcTy->hasErrorResult() &&
1961+
getSILFuncConventions().isTypedError()) {
1962+
auto resultType = getSILFuncConventions().getSILErrorType(
1963+
IGM.getMaximalTypeExpansionContext());
1964+
const TypeInfo &resultTI = cast<LoadableTypeInfo>(IGM.getTypeInfo(resultType));
1965+
auto storageTy = resultTI.getStorageType();
1966+
ParamIRTypes.push_back(storageTy->getPointerTo());
1967+
}
1968+
1969+
}
19461970
void SignatureExpansion::expandAsyncEntryType() {
19471971
ResultIRType = IGM.VoidTy;
19481972

@@ -2029,6 +2053,8 @@ void SignatureExpansion::expandAsyncEntryType() {
20292053
}
20302054
}
20312055

2056+
addIndirectThrowingResult();
2057+
20322058
// For now we continue to store the error result in the context to be able to
20332059
// reuse non throwing functions.
20342060

@@ -2049,7 +2075,7 @@ void SignatureExpansion::expandAsyncAwaitType() {
20492075

20502076
auto addErrorResult = [&]() {
20512077
if (FnType->hasErrorResult()) {
2052-
llvm::Type *errorType =
2078+
llvm::Type *errorType = getErrorRegisterType();
20532079
IGM.getStorageType(getSILFuncConventions().getSILType(
20542080
FnType->getErrorResult(), IGM.getMaximalTypeExpansionContext()));
20552081
auto selfIdx = components.size();
@@ -2376,9 +2402,16 @@ class SyncCallEmission final : public CallEmission {
23762402
// don't need to do anything extra here.
23772403
SILFunctionConventions fnConv(fnType, IGF.getSILModule());
23782404
Address errorResultSlot = IGF.getCalleeErrorResultSlot(
2379-
fnConv.getSILErrorType(IGF.IGM.getMaximalTypeExpansionContext()));
2405+
fnConv.getSILErrorType(IGF.IGM.getMaximalTypeExpansionContext()),
2406+
fnConv.isTypedError());
23802407

23812408
assert(LastArgWritten > 0);
2409+
if (fnConv.isTypedError()) {
2410+
// Return the error indirectly.
2411+
auto buf = IGF.getCalleeTypedErrorResultSlot(
2412+
fnConv.getSILErrorType(IGF.IGM.getMaximalTypeExpansionContext()));
2413+
Args[--LastArgWritten] = buf.getAddress();
2414+
}
23822415
Args[--LastArgWritten] = errorResultSlot.getAddress();
23832416
addParamAttribute(LastArgWritten, llvm::Attribute::NoCapture);
23842417
IGF.IGM.addSwiftErrorAttributes(CurCallee.getMutableAttributes(),
@@ -2575,7 +2608,10 @@ class SyncCallEmission final : public CallEmission {
25752608
out = nativeSchema.mapFromNative(IGF.IGM, IGF, nativeExplosion, resultType);
25762609
}
25772610
Address getCalleeErrorSlot(SILType errorType, bool isCalleeAsync) override {
2578-
return IGF.getCalleeErrorResultSlot(errorType);
2611+
SILFunctionConventions fnConv(getCallee().getOrigFunctionType(),
2612+
IGF.getSILModule());
2613+
2614+
return IGF.getCalleeErrorResultSlot(errorType, fnConv.isTypedError());
25792615
};
25802616

25812617
llvm::Value *getResumeFunctionPointer() override {
@@ -2674,6 +2710,18 @@ class AsyncCallEmission final : public CallEmission {
26742710
}
26752711
}
26762712

2713+
// Add the indirect typed error result if we have one.
2714+
SILFunctionConventions fnConv(fnType, IGF.getSILModule());
2715+
if (fnType->hasErrorResult() && fnConv.isTypedError()) {
2716+
// The invariant is that this is always zero-initialized, so we
2717+
// don't need to do anything extra here.
2718+
assert(LastArgWritten > 0);
2719+
// Return the error indirectly.
2720+
auto buf = IGF.getCalleeTypedErrorResultSlot(
2721+
fnConv.getSILErrorType(IGF.IGM.getMaximalTypeExpansionContext()));
2722+
Args[--LastArgWritten] = buf.getAddress();
2723+
}
2724+
26772725
llvm::Value *contextPtr = CurCallee.getSwiftContext();
26782726
// Add the data pointer if we have one.
26792727
if (contextPtr) {
@@ -2855,15 +2903,16 @@ class AsyncCallEmission final : public CallEmission {
28552903
if (resultTys.size() == 1) {
28562904
result = Builder.CreateExtractValue(result, numAsyncContextParams);
28572905
if (hasError) {
2858-
Address errorAddr = IGF.getCalleeErrorResultSlot(errorType);
2906+
Address errorAddr = IGF.getCalleeErrorResultSlot(errorType,
2907+
substConv.isTypedError());
28592908
Builder.CreateStore(result, errorAddr);
28602909
return;
28612910
}
28622911
} else if (resultTys.size() == 2 && hasError) {
28632912
auto tmp = result;
28642913
result = Builder.CreateExtractValue(result, numAsyncContextParams);
28652914
auto errorResult = Builder.CreateExtractValue(tmp, numAsyncContextParams + 1);
2866-
Address errorAddr = IGF.getCalleeErrorResultSlot(errorType);
2915+
Address errorAddr = IGF.getCalleeErrorResultSlot(errorType, substConv.isTypedError());
28672916
Builder.CreateStore(errorResult, errorAddr);
28682917
} else {
28692918
auto directResultTys = hasError ? resultTys.drop_back() : resultTys;
@@ -2877,7 +2926,7 @@ class AsyncCallEmission final : public CallEmission {
28772926
if (hasError) {
28782927
auto errorResult = Builder.CreateExtractValue(
28792928
result, numAsyncContextParams + directResultTys.size());
2880-
Address errorAddr = IGF.getCalleeErrorResultSlot(errorType);
2929+
Address errorAddr = IGF.getCalleeErrorResultSlot(errorType, substConv.isTypedError());
28812930
Builder.CreateStore(errorResult, errorAddr);
28822931
}
28832932
result = resultAgg;
@@ -2915,7 +2964,9 @@ class AsyncCallEmission final : public CallEmission {
29152964
out = nativeSchema.mapFromNative(IGF.IGM, IGF, nativeExplosion, resultType);
29162965
}
29172966
Address getCalleeErrorSlot(SILType errorType, bool isCalleeAsync) override {
2918-
return IGF.getCalleeErrorResultSlot(errorType);
2967+
SILFunctionConventions fnConv(getCallee().getOrigFunctionType(),
2968+
IGF.getSILModule());
2969+
return IGF.getCalleeErrorResultSlot(errorType, fnConv.isTypedError());
29192970
}
29202971

29212972
llvm::CallBase *createCall(const FunctionPointer &fn,
@@ -3050,7 +3101,8 @@ void CallEmission::emitToUnmappedMemory(Address result) {
30503101
errorType =
30513102
substConv.getSILErrorType(IGM.getMaximalTypeExpansionContext());
30523103
auto result = Builder.CreateExtractValue(call, numAsyncContextParams);
3053-
Address errorAddr = IGF.getCalleeErrorResultSlot(errorType);
3104+
Address errorAddr = IGF.getCalleeErrorResultSlot(errorType,
3105+
substConv.isTypedError());
30543106
Builder.CreateStore(result, errorAddr);
30553107
}
30563108
}
@@ -4604,17 +4656,21 @@ Explosion IRGenFunction::collectParameters() {
46044656
params.add(&*i);
46054657
return params;
46064658
}
4607-
4608-
Address IRGenFunction::createErrorResultSlot(SILType errorType, bool isAsync) {
4659+
Address IRGenFunction::createErrorResultSlot(SILType errorType, bool isAsync,
4660+
bool setSwiftErrorFlag,
4661+
bool isTypedError) {
46094662
auto &errorTI = cast<FixedTypeInfo>(getTypeInfo(errorType));
46104663

46114664
IRBuilder builder(IGM.getLLVMContext(), IGM.DebugInfo != nullptr);
46124665
builder.SetInsertPoint(AllocaIP->getParent(), AllocaIP->getIterator());
4613-
4666+
auto errorStorageType = isTypedError ? IGM.Int8PtrTy :
4667+
errorTI.getStorageType();
4668+
auto errorAlignment = isTypedError ? IGM.getPointerAlignment() :
4669+
errorTI.getFixedAlignment();
46144670
// Create the alloca. We don't use allocateStack because we're
46154671
// not allocating this in stack order.
4616-
auto addr = createAlloca(errorTI.getStorageType(),
4617-
errorTI.getFixedAlignment(), "swifterror");
4672+
auto addr = createAlloca(errorStorageType,
4673+
errorAlignment, "swifterror");
46184674

46194675
if (!isAsync) {
46204676
builder.SetInsertPoint(getEarliestInsertionPoint()->getParent(),
@@ -4628,36 +4684,43 @@ Address IRGenFunction::createErrorResultSlot(SILType errorType, bool isAsync) {
46284684
// The slot for async callees cannot be annotated swifterror because those
46294685
// errors are never passed in registers but rather are always passed
46304686
// indirectly in the async context.
4631-
if (IGM.ShouldUseSwiftError && !isAsync)
4687+
if (IGM.ShouldUseSwiftError && !isAsync && setSwiftErrorFlag)
46324688
cast<llvm::AllocaInst>(addr.getAddress())->setSwiftError(true);
46334689

46344690
// Initialize at the alloca point.
4635-
auto nullError = llvm::ConstantPointerNull::get(
4636-
cast<llvm::PointerType>(errorTI.getStorageType()));
4637-
builder.CreateStore(nullError, addr);
4691+
if (setSwiftErrorFlag) {
4692+
auto nullError = llvm::ConstantPointerNull::get(
4693+
cast<llvm::PointerType>(errorStorageType));
4694+
builder.CreateStore(nullError, addr);
4695+
}
46384696

46394697
return addr;
46404698
}
46414699

46424700
/// Fetch the error result slot.
4643-
Address IRGenFunction::getCalleeErrorResultSlot(SILType errorType) {
4701+
Address IRGenFunction::getCalleeErrorResultSlot(SILType errorType,
4702+
bool isTypedError) {
46444703
if (!CalleeErrorResultSlot.isValid()) {
4645-
CalleeErrorResultSlot = createErrorResultSlot(errorType, /*isAsync=*/false);
4704+
CalleeErrorResultSlot = createErrorResultSlot(errorType, /*isAsync=*/false,
4705+
/*setSwiftError*/true,
4706+
isTypedError);
46464707
}
46474708
return CalleeErrorResultSlot;
46484709
}
46494710

4650-
/// Fetch the error result slot.
4651-
Address IRGenFunction::getAsyncCalleeErrorResultSlot(SILType errorType) {
4652-
assert(isAsync() &&
4653-
"throwing async functions must be called from async functions");
4654-
if (!AsyncCalleeErrorResultSlot.isValid()) {
4655-
AsyncCalleeErrorResultSlot =
4656-
createErrorResultSlot(errorType, /*isAsync=*/true);
4711+
Address IRGenFunction::getCalleeTypedErrorResultSlot(SILType errorType) {
4712+
4713+
auto &errorTI = cast<FixedTypeInfo>(getTypeInfo(errorType));
4714+
if (!CalleeTypedErrorResultSlot.isValid() ||
4715+
CalleeTypedErrorResultSlot.getElementType() != errorTI.getStorageType()) {
4716+
CalleeTypedErrorResultSlot =
4717+
createErrorResultSlot(errorType, /*isAsync=*/false,
4718+
/*setSwiftErrorFlag*/false);
46574719
}
4658-
return AsyncCalleeErrorResultSlot;
4720+
return CalleeTypedErrorResultSlot;
46594721
}
46604722

4723+
46614724
/// Fetch the error result slot received from the caller.
46624725
Address IRGenFunction::getCallerErrorResultSlot() {
46634726
assert(CallerErrorResultSlot.isValid() && "no error result slot!");
@@ -4679,6 +4742,20 @@ void IRGenFunction::setCallerErrorResultSlot(Address address) {
46794742
}
46804743
}
46814744

4745+
// Set the error result slot for a typed throw for the current function.
4746+
// This should only be done in the prologue.
4747+
void IRGenFunction::setCallerTypedErrorResultSlot(Address address) {
4748+
assert(!CallerTypedErrorResultSlot.isValid() &&
4749+
"already have a caller error result slot!");
4750+
assert(isa<llvm::PointerType>(address.getAddress()->getType()));
4751+
CallerTypedErrorResultSlot = address;
4752+
}
4753+
4754+
Address IRGenFunction::getCallerTypedErrorResultSlot() {
4755+
assert(CallerTypedErrorResultSlot.isValid() && "no error result slot!");
4756+
assert(isa<llvm::Argument>(CallerTypedErrorResultSlot.getAddress()));
4757+
return CallerTypedErrorResultSlot;
4758+
}
46824759
/// Emit the basic block that 'return' should branch to and insert it into
46834760
/// the current function. This creates a second
46844761
/// insertion point that most blocks should be inserted before.

lib/IRGen/GenFunc.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,10 @@ class SyncPartialApplicationForwarderEmission
11181118
void forwardErrorResult() override {
11191119
llvm::Value *errorResultPtr = origParams.claimNext();
11201120
args.add(errorResultPtr);
1121+
if (origConv.isTypedError()) {
1122+
auto *typedErrorResultPtr = origParams.claimNext();
1123+
args.add(typedErrorResultPtr);
1124+
}
11211125
}
11221126
llvm::CallInst *createCall(FunctionPointer &fnPtr) override {
11231127
return subIGF.Builder.CreateCall(fnPtr, args.claimAll());
@@ -1289,8 +1293,12 @@ class AsyncPartialApplicationForwarderEmission
12891293
}
12901294

12911295
void forwardErrorResult() override {
1292-
// Nothing to do here. The error result pointer is already in the
1293-
// appropriate position.
1296+
// The error result pointer is already in the appropriate position but the
1297+
// type error address is not.
1298+
if (origConv.isTypedError()) {
1299+
auto *typedErrorResultPtr = origParams.claimNext();
1300+
args.add(typedErrorResultPtr);
1301+
}
12941302
}
12951303
llvm::CallInst *createCall(FunctionPointer &fnPtr) override {
12961304
PointerAuthInfo newAuthInfo =

lib/IRGen/IRGenFunction.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ class IRGenFunction {
9090

9191
friend class Scope;
9292

93-
Address createErrorResultSlot(SILType errorType, bool isAsync);
93+
Address createErrorResultSlot(SILType errorType, bool isAsync, bool setSwiftErrorFlag = true, bool isTypedError = false);
9494

9595
//--- Function prologue and epilogue
9696
//-------------------------------------------
@@ -122,14 +122,19 @@ class IRGenFunction {
122122
///
123123
/// For async functions, this is different from the caller result slot because
124124
/// that is a gep into the %swift.context.
125-
Address getCalleeErrorResultSlot(SILType errorType);
126-
Address getAsyncCalleeErrorResultSlot(SILType errorType);
125+
Address getCalleeErrorResultSlot(SILType errorType,
126+
bool isTypedError);
127127

128128
/// Return the error result slot provided by the caller.
129129
Address getCallerErrorResultSlot();
130130

131131
/// Set the error result slot for the current function.
132132
void setCallerErrorResultSlot(Address address);
133+
/// Set the error result slot for a typed throw for the current function.
134+
void setCallerTypedErrorResultSlot(Address address);
135+
136+
Address getCallerTypedErrorResultSlot();
137+
Address getCalleeTypedErrorResultSlot(SILType errorType);
133138

134139
/// Are we currently emitting a coroutine?
135140
bool isCoroutine() {
@@ -198,6 +203,8 @@ class IRGenFunction {
198203
Address CalleeErrorResultSlot;
199204
Address AsyncCalleeErrorResultSlot;
200205
Address CallerErrorResultSlot;
206+
Address CallerTypedErrorResultSlot;
207+
Address CalleeTypedErrorResultSlot;
201208
llvm::Value *CoroutineHandle = nullptr;
202209
llvm::Value *AsyncCoroutineCurrentResume = nullptr;
203210
llvm::Value *AsyncCoroutineCurrentContinuationContext = nullptr;

0 commit comments

Comments
 (0)