Merge pull request #18920 from mikeash/willthrow-error-register

[Runtime][ABI] Have swift_willThrow take the error value in the return register.
This commit is contained in:
Mike Ash
2018-09-06 18:00:43 -04:00
committed by GitHub
15 changed files with 86 additions and 33 deletions

View File

@@ -387,9 +387,6 @@ BUILTIN_SIL_OPERATION(IdentityKeyPath, "identityKeyPath", Special)
BUILTIN(Id, Name, Attrs)
#endif
/// willThrow: Error -> ()
BUILTIN_RUNTIME_CALL(WillThrow, "willThrow", "n")
/// unexpectedError: Error -> ()
BUILTIN_RUNTIME_CALL(UnexpectedError, "unexpectedError", "")
@@ -539,6 +536,9 @@ BUILTIN_MISC_OPERATION(GetObjCTypeEncoding, "getObjCTypeEncoding", "n", Special)
// Swift3ImplicitObjCEntrypoint has type () -> ()
BUILTIN_MISC_OPERATION(Swift3ImplicitObjCEntrypoint, "swift3ImplicitObjCEntrypoint", "", Special)
/// willThrow: Error -> ()
BUILTIN_MISC_OPERATION(WillThrow, "willThrow", "", Special)
#undef BUILTIN_MISC_OPERATION
/// Builtins for instrumentation added by sanitizers during SILGen.

View File

@@ -130,9 +130,9 @@ FUNCTION(SlowDealloc, swift_slowDealloc, C_CC,
ATTRS(NoUnwind))
// void swift_willThrow(error *ptr);
FUNCTION(WillThrow, swift_willThrow, C_CC,
FUNCTION(WillThrow, swift_willThrow, SwiftCC,
RETURNS(VoidTy),
ARGS(ErrorPtrTy),
ARGS(Int8PtrTy, ErrorPtrTy->getPointerTo()),
ATTRS(NoUnwind))
// void swift_errorInMain(error *ptr);

View File

@@ -353,6 +353,40 @@ if (Builtin.ID == BuiltinValueKind::id) { \
#define BUILTIN(ID, Name, Attrs) // Ignore the rest.
#include "swift/AST/Builtins.def"
if (Builtin.ID == BuiltinValueKind::WillThrow) {
// willThrow is emitted like a Swift function call with the error in
// the error return register. We also have to pass a fake context
// argument due to how swiftcc works in clang.
auto *fn = cast<llvm::Function>(IGF.IGM.getWillThrowFn());
auto error = args.claimNext();
auto errorBuffer = IGF.getErrorResultSlot(
SILType::getPrimitiveObjectType(IGF.IGM.Context.getErrorDecl()
->getDeclaredType()
->getCanonicalType()));
IGF.Builder.CreateStore(error, errorBuffer);
auto context = llvm::UndefValue::get(IGF.IGM.Int8PtrTy);
llvm::CallInst *call = IGF.Builder.CreateCall(fn,
{context, errorBuffer.getAddress()});
call->setCallingConv(IGF.IGM.SwiftCC);
call->addAttribute(llvm::AttributeList::FunctionIndex,
llvm::Attribute::NoUnwind);
call->addAttribute(llvm::AttributeList::FirstArgIndex + 1,
llvm::Attribute::ReadOnly);
auto attrs = call->getAttributes();
IGF.IGM.addSwiftSelfAttributes(attrs, 0);
IGF.IGM.addSwiftErrorAttributes(attrs, 1);
call->setAttributes(attrs);
IGF.Builder.CreateStore(llvm::ConstantPointerNull::get(IGF.IGM.ErrorPtrTy),
errorBuffer);
return out.add(call);
}
if (Builtin.ID == BuiltinValueKind::FNeg) {
llvm::Value *rhs = args.claimNext();
llvm::Value *lhs = llvm::ConstantFP::get(rhs->getType(), "-0.0");

View File

@@ -182,17 +182,22 @@ void IRGenModule::addSwiftSelfAttributes(llvm::AttributeList &attrs,
void IRGenModule::addSwiftErrorAttributes(llvm::AttributeList &attrs,
unsigned argIndex) {
// Don't add the swifterror attribute on ABI that don't pass it in a register.
llvm::AttrBuilder b;
// Don't add the swifterror attribute on ABIs that don't pass it in a register.
// We create a shadow stack location of the swifterror parameter for the
// debugger on such platforms and so we can't mark the parameter with a
// swifterror attribute.
if (!this->IsSwiftErrorInRegister)
return;
llvm::AttrBuilder b;
if (IsSwiftErrorInRegister)
b.addAttribute(llvm::Attribute::SwiftError);
attrs = attrs.addAttributes(this->LLVMContext,
argIndex + llvm::AttributeList::FirstArgIndex, b);
// The error result should not be aliased, captured, or pointed at invalid
// addresses regardless.
b.addAttribute(llvm::Attribute::NoAlias);
b.addAttribute(llvm::Attribute::NoCapture);
b.addDereferenceableAttr(getPointerSize().getValue());
auto attrIndex = argIndex + llvm::AttributeList::FirstArgIndex;
attrs = attrs.addAttributes(this->LLVMContext, attrIndex, b);
}
void irgen::addByvalArgumentAttributes(IRGenModule &IGM,

View File

@@ -527,6 +527,10 @@ static void visitBuiltinAddress(BuiltinInst *builtin,
builtin->dump();
llvm_unreachable("unexpected bulitin memory access.");
// WillThrow exists for the debugger, does nothing.
case BuiltinValueKind::WillThrow:
return;
// Buitins that affect memory but can't be formal accesses.
case BuiltinValueKind::UnexpectedError:
case BuiltinValueKind::ErrorInMain:

View File

@@ -206,8 +206,9 @@ SWIFT_RUNTIME_STDLIB_API
void swift_errorRelease(SwiftError *object);
/// Breakpoint hook for debuggers.
SWIFT_RUNTIME_STDLIB_API
void swift_willThrow(SwiftError *object);
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
void swift_willThrow(SWIFT_CONTEXT void *unused,
SWIFT_ERROR_RESULT SwiftError **object);
/// Halt in response to an error.
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API LLVM_ATTRIBUTE_NORETURN

View File

@@ -555,8 +555,9 @@ swift::swift_errorRelease(SwiftError *error) {
}
/// Breakpoint hook for debuggers.
void
swift::swift_willThrow(SwiftError *error) {
SWIFT_CC(swift) void
swift::swift_willThrow(SWIFT_CONTEXT void *unused,
SWIFT_ERROR_RESULT SwiftError **error) {
// empty
}

View File

@@ -106,6 +106,11 @@ swift::swift_getErrorValue(const SwiftError *errorObject,
out->errorConformance = errorObject->errorConformance;
}
void swift::swift_willThrow(SwiftError *object) { }
/// Breakpoint hook for debuggers.
SWIFT_CC(swift) void
swift::swift_willThrow(SWIFT_CONTEXT void *unused,
SWIFT_ERROR_RESULT SwiftError **error) {
// do nothing
}
#endif

View File

@@ -11,7 +11,7 @@ enum MyError : Error {
// thrown error we create a shadow stack location holding the address of the
// location that holds the pointer to the error instead.
func simple(_ placeholder: Int64) throws -> () {
// CHECK: define {{.*}}void @"$S8ErrorVar6simpleyys5Int64VKF"(i64, %swift.refcounted* swiftself, %swift.error**)
// CHECK: define {{.*}}void @"$S8ErrorVar6simpleyys5Int64VKF"(i64, %swift.refcounted* swiftself, %swift.error** noalias nocapture dereferenceable(4))
// CHECK: call void @llvm.dbg.declare
// CHECK: call void @llvm.dbg.declare({{.*}}, metadata ![[ERROR:[0-9]+]], metadata !DIExpression(DW_OP_deref))
// CHECK: ![[ERRTY:.*]] = !DICompositeType({{.*}}identifier: "$Ss5Error_pD"

View File

@@ -446,17 +446,17 @@ class Foo {
return g.invert(b)
}
// x86_64-macosx: define hidden swiftcc void @"$S8abitypes3FooC10throwsTestyySbKF"(i1, %T8abitypes3FooC* swiftself, %swift.error** swifterror) {{.*}} {
// x86_64-macosx: define hidden swiftcc void @"$S8abitypes3FooC10throwsTestyySbKF"(i1, %T8abitypes3FooC* swiftself, %swift.error** noalias nocapture swifterror dereferenceable(8)) {{.*}} {
// x86_64-macosx: [[SEL:%[0-9]+]] = load i8*, i8** @"\01L_selector(negateThrowing:error:)", align 8
// x86_64-macosx: call signext i8 bitcast (void ()* @objc_msgSend to i8 (%1*, i8*, i8, %2**)*)(%1* {{%[0-9]+}}, i8* [[SEL]], i8 signext {{%[0-9]+}}, %2** {{%[0-9]+}})
// x86_64-macosx: }
// x86_64-ios: define hidden swiftcc void @"$S8abitypes3FooC10throwsTestyySbKF"(i1, %T8abitypes3FooC* swiftself, %swift.error** swifterror) {{.*}} {
// x86_64-ios: define hidden swiftcc void @"$S8abitypes3FooC10throwsTestyySbKF"(i1, %T8abitypes3FooC* swiftself, %swift.error** noalias nocapture swifterror dereferenceable(8)) {{.*}} {
// x86_64-ios: [[SEL:%[0-9]+]] = load i8*, i8** @"\01L_selector(negateThrowing:error:)", align 8
// x86_64-ios: call zeroext i1 bitcast (void ()* @objc_msgSend to i1 (%1*, i8*, i1, %2**)*)(%1* {{%[0-9]+}}, i8* [[SEL]], i1 zeroext {{%[0-9]+}}, %2** {{%[0-9]+}})
// x86_64-ios: }
// i386-ios: define hidden swiftcc void @"$S8abitypes3FooC10throwsTestyySbKF"(i1, %T8abitypes3FooC* swiftself, %swift.error**) {{.*}} {
// i386-ios: define hidden swiftcc void @"$S8abitypes3FooC10throwsTestyySbKF"(i1, %T8abitypes3FooC* swiftself, %swift.error** noalias nocapture dereferenceable(4)) {{.*}} {
// i386-ios: [[SEL:%[0-9]+]] = load i8*, i8** @"\01L_selector(negateThrowing:error:)", align 4
// i386-ios: call signext i8 bitcast (void ()* @objc_msgSend to i8 (%1*, i8*, i8, %2**)*)(%1* {{%[0-9]+}}, i8* [[SEL]], i8 signext {{%[0-9]+}}, %2** {{%[0-9]+}})
// i386-ios: }

View File

@@ -65,7 +65,7 @@ bb0(%0 : $_ArrayBuffer<Element>):
return %9 : $BigTempStruct<Element>
}
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @testTryApply(%T22big_types_corner_cases9BigStructV* noalias nocapture sret, i8*, %swift.refcounted*, %swift.refcounted* swiftself, %swift.error** swifterror)
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @testTryApply(%T22big_types_corner_cases9BigStructV* noalias nocapture sret, i8*, %swift.refcounted*, %swift.refcounted* swiftself, %swift.error** noalias nocapture swifterror dereferenceable(8))
// CHECK: [[ALLOC:%.*]] = alloca %T22big_types_corner_cases9BigStructV
// CHECK: call swiftcc void {{.*}}(%T22big_types_corner_cases9BigStructV* noalias nocapture sret [[ALLOC]]
// CHECK: ret void

View File

@@ -335,11 +335,11 @@ public extension sr8076_QueryHandler {
}
// CHECK-LABEL-64: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i64 } @"$S22big_types_corner_cases19sr8076_QueryHandlerPAAE13forceHandle_45query8ReturnedQyd___SbAA9BigStructVcSgtqd___tKAA0e1_F0Rd__lF"(%swift.opaque* noalias nocapture, %swift.opaque* noalias nocapture, %swift.type*{{.*}}, %swift.type*{{.*}}, i8** {{.*}}.sr8076_QueryHandler, i8** {{.*}}.sr8076_Query, %swift.opaque* noalias nocapture swiftself, %swift.error** swifterror)
// CHECK-64: {{.*}} = call swiftcc { i64, i64 } {{.*}}(%swift.opaque* noalias nocapture {{.*}}, %swift.opaque* noalias nocapture {{.*}}, %swift.refcounted* swiftself {{.*}}, %swift.error** nocapture swifterror {{.*}})
// CHECK-64: {{.*}} = call swiftcc { i64, i64 } {{.*}}(%swift.opaque* noalias nocapture {{.*}}, %swift.opaque* noalias nocapture {{.*}}, %swift.refcounted* swiftself {{.*}}, %swift.error** noalias nocapture swifterror {{.*}})
// CHECK-64: ret { i64, i64 }
// CHECK-LABEL-32: define{{( dllexport)?}}{{( protected)?}} swiftcc { i32, i32} @"$S22big_types_corner_cases19sr8076_QueryHandlerPAAE13forceHandle_45query8ReturnedQyd___SbAA9BigStructVcSgtqd___tKAA0e1_F0Rd__lF"(%swift.opaque* noalias nocapture, %swift.opaque* noalias nocapture, %swift.type*{{.*}}, %swift.type*{{.*}}, i8** {{.*}}.sr8076_QueryHandler, i8** {{.*}}.sr8076_Query, %swift.opaque* noalias nocapture swiftself, %swift.error** swifterror)
// CHECK-32: {{.*}} = call swiftcc { i32, i32 } {{.*}}(%swift.opaque* noalias nocapture {{.*}}, %swift.opaque* noalias nocapture {{.*}}, %swift.refcounted* swiftself {{.*}}, %swift.error** nocapture {{.*}})
// CHECK-32: {{.*}} = call swiftcc { i32, i32 } {{.*}}(%swift.opaque* noalias nocapture {{.*}}, %swift.opaque* noalias nocapture {{.*}}, %swift.refcounted* swiftself {{.*}}, %swift.error** noalias nocapture {{.*}})
// CHECK-32: ret { i32, i32 }
func forceHandle_4<Q: sr8076_Query>(query: Q) throws -> (Q.Returned, sr8076_Filter?) {
guard let body = handle_4 as? (Q) throws -> (Q.Returned, sr8076_Filter?) else {

View File

@@ -26,7 +26,9 @@ sil @does_throw : $@convention(thin) () -> @error Error {
%0 = function_ref @create_error : $@convention(thin) () -> @owned Error
%1 = apply %0() : $@convention(thin) () -> @owned Error
// CHECK-NEXT: call void @swift_willThrow
// CHECK-NEXT: store %swift.error* [[T0]], %swift.error** %1,
// CHECK-NEXT: call swiftcc void @swift_willThrow
// CHECK-NEXT: store %swift.error* null, %swift.error** %1,
// CHECK-NEXT: store %swift.error* [[T0]], %swift.error** %1,
// CHECK-NEXT: ret void
builtin "willThrow"(%1 : $Error) : $()
@@ -64,8 +66,8 @@ entry(%0 : $AnyObject):
// CHECK-aarch64: [[ERRORSLOT:%.*]] = alloca [[SWIFTERROR:.*]] %swift.error*, align
// CHECK-NEXT: store %swift.error* null, %swift.error** [[ERRORSLOT]], align
// CHECK-objc-NEXT: [[RESULT:%.*]] = call swiftcc %objc_object* @try_apply_helper(%objc_object* %0, %swift.refcounted* swiftself undef, %swift.error** nocapture [[SWIFTERROR]]{{( )?}}[[ERRORSLOT]])
// CHECK-native-NEXT: [[RESULT:%.*]] = call swiftcc %swift.refcounted* @try_apply_helper(%swift.refcounted* %0, %swift.refcounted* swiftself undef, %swift.error** nocapture [[SWIFTERROR]]{{( )?}}[[ERRORSLOT]])
// CHECK-objc-NEXT: [[RESULT:%.*]] = call swiftcc %objc_object* @try_apply_helper(%objc_object* %0, %swift.refcounted* swiftself undef, %swift.error** noalias nocapture [[SWIFTERROR]]{{( )?}}dereferenceable({{.}}) [[ERRORSLOT]])
// CHECK-native-NEXT: [[RESULT:%.*]] = call swiftcc %swift.refcounted* @try_apply_helper(%swift.refcounted* %0, %swift.refcounted* swiftself undef, %swift.error** noalias nocapture [[SWIFTERROR]]{{( )?}}dereferenceable({{.}}) [[ERRORSLOT]])
// CHECK-NEXT: [[ERR:%.*]] = load %swift.error*, %swift.error** [[ERRORSLOT]], align
// CHECK-NEXT: [[T0:%.*]] = icmp ne %swift.error* [[ERR]], null
// CHECK-NEXT: br i1 [[T0]],
@@ -100,7 +102,7 @@ enum ColorError : Error {
}
// CHECK-LABEL: TestCallToWillThrowCallBack
// CHECK: call void @swift_willThrow(%swift.error* %0)
// CHECK: call swiftcc void @swift_willThrow(i8* swiftself undef, %swift.error** noalias nocapture readonly [[SWIFTERROR]]{{( )?}}dereferenceable({{.}}) %2)
// CHECK: store %swift.error* %0
// CHECK: ret i64 undef
sil hidden @TestCallToWillThrowCallBack : $@convention(thin) (@owned Error) -> (Int64, @error Error) {
@@ -113,9 +115,9 @@ bb0(%0 : $Error):
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc { i8*, %swift.refcounted* } @partial_apply_single(%T6errors1AC*)
// CHECK: insertvalue { i8*, %swift.refcounted* } { i8* bitcast (void (%swift.refcounted*, %swift.error**)* @"$S27partial_apply_single_helperTA" to i8*), %swift.refcounted* undef },
// CHECK: define internal swiftcc void @"$S27partial_apply_single_helperTA"(%swift.refcounted* swiftself, %swift.error**{{( )?}}[[SWIFTERROR]])
// CHECK: define internal swiftcc void @"$S27partial_apply_single_helperTA"(%swift.refcounted* swiftself, %swift.error** noalias nocapture{{( )?}}[[SWIFTERROR]]{{( )?}}dereferenceable({{.}}))
// CHECK: [[T0:%.*]] = bitcast %swift.refcounted* {{%.*}} to %T6errors1AC*
// CHECK-NEXT: tail call swiftcc void @partial_apply_single_helper(%T6errors1AC* [[T0]], %swift.refcounted* swiftself undef, %swift.error**{{( )?}}[[SWIFTERROR]]{{( )?}}{{%.*}})
// CHECK-NEXT: tail call swiftcc void @partial_apply_single_helper(%T6errors1AC* [[T0]], %swift.refcounted* swiftself undef, %swift.error** noalias nocapture{{( )?}}[[SWIFTERROR]]{{( )?}}dereferenceable({{.}}){{( )?}}{{%.*}})
// CHECK-NEXT: ret void
sil @partial_apply_single : $@convention(thin) (@owned A) -> @callee_owned () -> @error Error {
entry(%0 : $A):

View File

@@ -59,11 +59,11 @@ public protocol MyResilientProtocol {
// CHECK-NEXT: call swiftcc void [[FN]](%Any* noalias nocapture sret %0, %swift.opaque* noalias nocapture swiftself %1, %swift.type* %2, i8** %3)
// CHECK-NEXT: ret void
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @"$S26protocol_resilience_thunks19MyResilientProtocolP12throwingFuncyyKFTj"(%swift.opaque* noalias nocapture swiftself, %swift.error**{{( swifterror)?}}, %swift.type*, i8**)
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @"$S26protocol_resilience_thunks19MyResilientProtocolP12throwingFuncyyKFTj"(%swift.opaque* noalias nocapture swiftself, %swift.error**{{( noalias nocapture( swifterror)? dereferenceable\(.\))?}}, %swift.type*, i8**)
// CHECK: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** %3, i32 4
// CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]]
// CHECK-NEXT: [[FN:%.*]] = bitcast i8* [[WITNESS]] to void (%swift.opaque*, %swift.error**, %swift.type*, i8**)*
// CHECK-NEXT: call swiftcc void [[FN]](%swift.opaque* noalias nocapture swiftself %0, %swift.error**{{( swifterror)?}} %1, %swift.type* %2, i8** %3)
// CHECK-NEXT: call swiftcc void [[FN]](%swift.opaque* noalias nocapture swiftself %0, %swift.error**{{( noalias nocapture( swifterror)? dereferenceable\(.\))?}} %1, %swift.type* %2, i8** %3)
// CHECK-NEXT: ret void
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @"$S26protocol_resilience_thunks19MyResilientProtocolP11genericFuncyqd__qd__lFTj"(%swift.opaque* noalias nocapture sret, %swift.opaque* noalias nocapture, %swift.type*, %swift.opaque* noalias nocapture swiftself, %swift.type*, i8**)

View File

@@ -202,6 +202,7 @@ sil @try_apply_func : $@convention(thin) () -> (Builtin.Int32, @error Error)
// CHECK-NEXT: dealloc_stack [[NEW_ALLOC_STACK]]
// CHECK-NEXT: return
// CHECK: bb6(
// CHECK-NEXT: builtin "willThrow"
// CHECK-NEXT: dealloc_stack [[NEW_ALLOC_STACK]]
// CHECK-NEXT: throw
// CHECK: } // end sil function 'sil_combine_dead_partial_apply_try_apply'