Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions include/swift/SIL/SILFunctionConventions.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,11 @@ class SILFunctionConventions {
return getSILType(funcTy->getErrorResult(), context);
}

bool isTypedError() const {
return !funcTy->getErrorResult()
.getInterfaceType()->isExistentialWithError();
}

/// Returns an array of result info.
/// Provides convenient access to the underlying SILFunctionType.
ArrayRef<SILResultInfo> getResults() const {
Expand Down
1 change: 1 addition & 0 deletions lib/IRGen/EntryPointArgumentEmission.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class NativeCCEntryPointArgumentEmission
public:
virtual void mapAsyncParameters() = 0;
virtual llvm::Value *getCallerErrorResultArgument() = 0;
virtual llvm::Value *getCallerTypedErrorResultArgument() = 0;
virtual llvm::Value *getContext() = 0;
virtual Explosion getArgumentExplosion(unsigned index, unsigned size) = 0;
virtual llvm::Value *getSelfWitnessTable() = 0;
Expand Down
2 changes: 1 addition & 1 deletion lib/IRGen/GenBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
auto error = args.claimNext();
auto errorTy = IGF.IGM.Context.getErrorExistentialType();
auto errorBuffer = IGF.getCalleeErrorResultSlot(
SILType::getPrimitiveObjectType(errorTy));
SILType::getPrimitiveObjectType(errorTy), false);
IGF.Builder.CreateStore(error, errorBuffer);

auto context = llvm::UndefValue::get(IGF.IGM.Int8PtrTy);
Expand Down
143 changes: 110 additions & 33 deletions lib/IRGen/GenCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,9 @@ namespace {

void expandCoroutineResult(bool forContinuation);
void expandCoroutineContinuationParameters();

void addIndirectThrowingResult();
llvm::Type *getErrorRegisterType();
};
} // end anonymous namespace
} // end namespace irgen
Expand Down Expand Up @@ -1850,12 +1853,16 @@ void SignatureExpansion::expandParameters(
if (FnType->hasErrorResult()) {
if (claimError())
IGM.addSwiftErrorAttributes(Attrs, ParamIRTypes.size());
llvm::Type *errorType =
IGM.getStorageType(getSILFuncConventions().getSILType(
FnType->getErrorResult(), IGM.getMaximalTypeExpansionContext()));
llvm::Type *errorType = getErrorRegisterType();
ParamIRTypes.push_back(errorType->getPointerTo());
if (recordedABIDetails)
recordedABIDetails->hasErrorResult = true;
if (getSILFuncConventions().isTypedError()) {
ParamIRTypes.push_back(
IGM.getStorageType(getSILFuncConventions().getSILType(
FnType->getErrorResult(), IGM.getMaximalTypeExpansionContext())
)->getPointerTo());
}
}

// Witness methods have some extra parameter types.
Expand Down Expand Up @@ -1903,6 +1910,14 @@ void SignatureExpansion::expandCoroutineContinuationType() {
expandCoroutineContinuationParameters();
}

llvm::Type *SignatureExpansion::getErrorRegisterType() {
if (getSILFuncConventions().isTypedError())
return IGM.Int8PtrTy;

return IGM.getStorageType(getSILFuncConventions().getSILType(
FnType->getErrorResult(), IGM.getMaximalTypeExpansionContext()));
}

void SignatureExpansion::expandAsyncReturnType() {
// Build up the signature of the return continuation function.
// void (AsyncTask *, ExecutorRef, AsyncContext *, DirectResult0, ...,
Expand All @@ -1914,9 +1929,7 @@ void SignatureExpansion::expandAsyncReturnType() {
auto addErrorResult = [&]() {
// Add the error pointer at the end.
if (FnType->hasErrorResult()) {
llvm::Type *errorType =
IGM.getStorageType(getSILFuncConventions().getSILType(
FnType->getErrorResult(), IGM.getMaximalTypeExpansionContext()));
llvm::Type *errorType = getErrorRegisterType();
claimSelf();
auto selfIdx = ParamIRTypes.size();
IGM.addSwiftSelfAttributes(Attrs, selfIdx);
Expand All @@ -1943,6 +1956,17 @@ void SignatureExpansion::expandAsyncReturnType() {
addErrorResult();
}

void SignatureExpansion::addIndirectThrowingResult() {
if (getSILFuncConventions().funcTy->hasErrorResult() &&
getSILFuncConventions().isTypedError()) {
auto resultType = getSILFuncConventions().getSILErrorType(
IGM.getMaximalTypeExpansionContext());
const TypeInfo &resultTI = cast<LoadableTypeInfo>(IGM.getTypeInfo(resultType));
auto storageTy = resultTI.getStorageType();
ParamIRTypes.push_back(storageTy->getPointerTo());
}

}
void SignatureExpansion::expandAsyncEntryType() {
ResultIRType = IGM.VoidTy;

Expand Down Expand Up @@ -2029,6 +2053,8 @@ void SignatureExpansion::expandAsyncEntryType() {
}
}

addIndirectThrowingResult();

// For now we continue to store the error result in the context to be able to
// reuse non throwing functions.

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

auto addErrorResult = [&]() {
if (FnType->hasErrorResult()) {
llvm::Type *errorType =
llvm::Type *errorType = getErrorRegisterType();
IGM.getStorageType(getSILFuncConventions().getSILType(
FnType->getErrorResult(), IGM.getMaximalTypeExpansionContext()));
Comment on lines 2079 to 2080
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dead code?

auto selfIdx = components.size();
Expand Down Expand Up @@ -2376,9 +2402,16 @@ class SyncCallEmission final : public CallEmission {
// don't need to do anything extra here.
SILFunctionConventions fnConv(fnType, IGF.getSILModule());
Address errorResultSlot = IGF.getCalleeErrorResultSlot(
fnConv.getSILErrorType(IGF.IGM.getMaximalTypeExpansionContext()));
fnConv.getSILErrorType(IGF.IGM.getMaximalTypeExpansionContext()),
fnConv.isTypedError());

assert(LastArgWritten > 0);
if (fnConv.isTypedError()) {
// Return the error indirectly.
auto buf = IGF.getCalleeTypedErrorResultSlot(
fnConv.getSILErrorType(IGF.IGM.getMaximalTypeExpansionContext()));
Args[--LastArgWritten] = buf.getAddress();
}
Args[--LastArgWritten] = errorResultSlot.getAddress();
addParamAttribute(LastArgWritten, llvm::Attribute::NoCapture);
IGF.IGM.addSwiftErrorAttributes(CurCallee.getMutableAttributes(),
Expand Down Expand Up @@ -2575,7 +2608,10 @@ class SyncCallEmission final : public CallEmission {
out = nativeSchema.mapFromNative(IGF.IGM, IGF, nativeExplosion, resultType);
}
Address getCalleeErrorSlot(SILType errorType, bool isCalleeAsync) override {
return IGF.getCalleeErrorResultSlot(errorType);
SILFunctionConventions fnConv(getCallee().getOrigFunctionType(),
IGF.getSILModule());

return IGF.getCalleeErrorResultSlot(errorType, fnConv.isTypedError());
};

llvm::Value *getResumeFunctionPointer() override {
Expand Down Expand Up @@ -2674,6 +2710,18 @@ class AsyncCallEmission final : public CallEmission {
}
}

// Add the indirect typed error result if we have one.
SILFunctionConventions fnConv(fnType, IGF.getSILModule());
if (fnType->hasErrorResult() && fnConv.isTypedError()) {
// The invariant is that this is always zero-initialized, so we
// don't need to do anything extra here.
assert(LastArgWritten > 0);
// Return the error indirectly.
auto buf = IGF.getCalleeTypedErrorResultSlot(
fnConv.getSILErrorType(IGF.IGM.getMaximalTypeExpansionContext()));
Args[--LastArgWritten] = buf.getAddress();
}

llvm::Value *contextPtr = CurCallee.getSwiftContext();
// Add the data pointer if we have one.
if (contextPtr) {
Expand Down Expand Up @@ -2855,15 +2903,16 @@ class AsyncCallEmission final : public CallEmission {
if (resultTys.size() == 1) {
result = Builder.CreateExtractValue(result, numAsyncContextParams);
if (hasError) {
Address errorAddr = IGF.getCalleeErrorResultSlot(errorType);
Address errorAddr = IGF.getCalleeErrorResultSlot(errorType,
substConv.isTypedError());
Builder.CreateStore(result, errorAddr);
return;
}
} else if (resultTys.size() == 2 && hasError) {
auto tmp = result;
result = Builder.CreateExtractValue(result, numAsyncContextParams);
auto errorResult = Builder.CreateExtractValue(tmp, numAsyncContextParams + 1);
Address errorAddr = IGF.getCalleeErrorResultSlot(errorType);
Address errorAddr = IGF.getCalleeErrorResultSlot(errorType, substConv.isTypedError());
Builder.CreateStore(errorResult, errorAddr);
} else {
auto directResultTys = hasError ? resultTys.drop_back() : resultTys;
Expand All @@ -2877,7 +2926,7 @@ class AsyncCallEmission final : public CallEmission {
if (hasError) {
auto errorResult = Builder.CreateExtractValue(
result, numAsyncContextParams + directResultTys.size());
Address errorAddr = IGF.getCalleeErrorResultSlot(errorType);
Address errorAddr = IGF.getCalleeErrorResultSlot(errorType, substConv.isTypedError());
Builder.CreateStore(errorResult, errorAddr);
}
result = resultAgg;
Expand Down Expand Up @@ -2915,7 +2964,9 @@ class AsyncCallEmission final : public CallEmission {
out = nativeSchema.mapFromNative(IGF.IGM, IGF, nativeExplosion, resultType);
}
Address getCalleeErrorSlot(SILType errorType, bool isCalleeAsync) override {
return IGF.getCalleeErrorResultSlot(errorType);
SILFunctionConventions fnConv(getCallee().getOrigFunctionType(),
IGF.getSILModule());
return IGF.getCalleeErrorResultSlot(errorType, fnConv.isTypedError());
}

llvm::CallBase *createCall(const FunctionPointer &fn,
Expand Down Expand Up @@ -3050,7 +3101,8 @@ void CallEmission::emitToUnmappedMemory(Address result) {
errorType =
substConv.getSILErrorType(IGM.getMaximalTypeExpansionContext());
auto result = Builder.CreateExtractValue(call, numAsyncContextParams);
Address errorAddr = IGF.getCalleeErrorResultSlot(errorType);
Address errorAddr = IGF.getCalleeErrorResultSlot(errorType,
substConv.isTypedError());
Builder.CreateStore(result, errorAddr);
}
}
Expand Down Expand Up @@ -4604,17 +4656,21 @@ Explosion IRGenFunction::collectParameters() {
params.add(&*i);
return params;
}

Address IRGenFunction::createErrorResultSlot(SILType errorType, bool isAsync) {
Address IRGenFunction::createErrorResultSlot(SILType errorType, bool isAsync,
bool setSwiftErrorFlag,
bool isTypedError) {
auto &errorTI = cast<FixedTypeInfo>(getTypeInfo(errorType));

IRBuilder builder(IGM.getLLVMContext(), IGM.DebugInfo != nullptr);
builder.SetInsertPoint(AllocaIP->getParent(), AllocaIP->getIterator());

auto errorStorageType = isTypedError ? IGM.Int8PtrTy :
errorTI.getStorageType();
auto errorAlignment = isTypedError ? IGM.getPointerAlignment() :
errorTI.getFixedAlignment();
// Create the alloca. We don't use allocateStack because we're
// not allocating this in stack order.
auto addr = createAlloca(errorTI.getStorageType(),
errorTI.getFixedAlignment(), "swifterror");
auto addr = createAlloca(errorStorageType,
errorAlignment, "swifterror");

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

// Initialize at the alloca point.
auto nullError = llvm::ConstantPointerNull::get(
cast<llvm::PointerType>(errorTI.getStorageType()));
builder.CreateStore(nullError, addr);
if (setSwiftErrorFlag) {
auto nullError = llvm::ConstantPointerNull::get(
cast<llvm::PointerType>(errorStorageType));
builder.CreateStore(nullError, addr);
}

return addr;
}

/// Fetch the error result slot.
Address IRGenFunction::getCalleeErrorResultSlot(SILType errorType) {
Address IRGenFunction::getCalleeErrorResultSlot(SILType errorType,
bool isTypedError) {
if (!CalleeErrorResultSlot.isValid()) {
CalleeErrorResultSlot = createErrorResultSlot(errorType, /*isAsync=*/false);
CalleeErrorResultSlot = createErrorResultSlot(errorType, /*isAsync=*/false,
/*setSwiftError*/true,
isTypedError);
}
return CalleeErrorResultSlot;
}

/// Fetch the error result slot.
Address IRGenFunction::getAsyncCalleeErrorResultSlot(SILType errorType) {
assert(isAsync() &&
"throwing async functions must be called from async functions");
if (!AsyncCalleeErrorResultSlot.isValid()) {
AsyncCalleeErrorResultSlot =
createErrorResultSlot(errorType, /*isAsync=*/true);
Address IRGenFunction::getCalleeTypedErrorResultSlot(SILType errorType) {

auto &errorTI = cast<FixedTypeInfo>(getTypeInfo(errorType));
if (!CalleeTypedErrorResultSlot.isValid() ||
CalleeTypedErrorResultSlot.getElementType() != errorTI.getStorageType()) {
CalleeTypedErrorResultSlot =
createErrorResultSlot(errorType, /*isAsync=*/false,
/*setSwiftErrorFlag*/false);
}
return AsyncCalleeErrorResultSlot;
return CalleeTypedErrorResultSlot;
}


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

// Set the error result slot for a typed throw for the current function.
// This should only be done in the prologue.
void IRGenFunction::setCallerTypedErrorResultSlot(Address address) {
assert(!CallerTypedErrorResultSlot.isValid() &&
"already have a caller error result slot!");
assert(isa<llvm::PointerType>(address.getAddress()->getType()));
CallerTypedErrorResultSlot = address;
}

Address IRGenFunction::getCallerTypedErrorResultSlot() {
assert(CallerTypedErrorResultSlot.isValid() && "no error result slot!");
assert(isa<llvm::Argument>(CallerTypedErrorResultSlot.getAddress()));
return CallerTypedErrorResultSlot;
}
/// Emit the basic block that 'return' should branch to and insert it into
/// the current function. This creates a second
/// insertion point that most blocks should be inserted before.
Expand Down
12 changes: 10 additions & 2 deletions lib/IRGen/GenFunc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1118,6 +1118,10 @@ class SyncPartialApplicationForwarderEmission
void forwardErrorResult() override {
llvm::Value *errorResultPtr = origParams.claimNext();
args.add(errorResultPtr);
if (origConv.isTypedError()) {
auto *typedErrorResultPtr = origParams.claimNext();
args.add(typedErrorResultPtr);
}
}
llvm::CallInst *createCall(FunctionPointer &fnPtr) override {
return subIGF.Builder.CreateCall(fnPtr, args.claimAll());
Expand Down Expand Up @@ -1289,8 +1293,12 @@ class AsyncPartialApplicationForwarderEmission
}

void forwardErrorResult() override {
// Nothing to do here. The error result pointer is already in the
// appropriate position.
// The error result pointer is already in the appropriate position but the
// type error address is not.
if (origConv.isTypedError()) {
auto *typedErrorResultPtr = origParams.claimNext();
args.add(typedErrorResultPtr);
}
}
llvm::CallInst *createCall(FunctionPointer &fnPtr) override {
PointerAuthInfo newAuthInfo =
Expand Down
13 changes: 10 additions & 3 deletions lib/IRGen/IRGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ class IRGenFunction {

friend class Scope;

Address createErrorResultSlot(SILType errorType, bool isAsync);
Address createErrorResultSlot(SILType errorType, bool isAsync, bool setSwiftErrorFlag = true, bool isTypedError = false);

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

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

/// Set the error result slot for the current function.
void setCallerErrorResultSlot(Address address);
/// Set the error result slot for a typed throw for the current function.
void setCallerTypedErrorResultSlot(Address address);

Address getCallerTypedErrorResultSlot();
Address getCalleeTypedErrorResultSlot(SILType errorType);

/// Are we currently emitting a coroutine?
bool isCoroutine() {
Expand Down Expand Up @@ -198,6 +203,8 @@ class IRGenFunction {
Address CalleeErrorResultSlot;
Address AsyncCalleeErrorResultSlot;
Address CallerErrorResultSlot;
Address CallerTypedErrorResultSlot;
Address CalleeTypedErrorResultSlot;
llvm::Value *CoroutineHandle = nullptr;
llvm::Value *AsyncCoroutineCurrentResume = nullptr;
llvm::Value *AsyncCoroutineCurrentContinuationContext = nullptr;
Expand Down
Loading