| // RUN: %empty-directory(%t) |
| // RUN: %build-irgen-test-overlays |
| // RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t -I %S/../IDE/Inputs/custom-modules) %s -emit-ir | %FileCheck %s -DINT=i%target-ptrsize |
| // RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t -I %S/../IDE/Inputs/custom-modules) %s -emit-ir -O | %FileCheck %s -check-prefix=OPT -DINT=i%target-ptrsize |
| import CoreFoundation |
| import Foundation |
| import Newtype |
| |
| // REQUIRES: objc_interop |
| |
| // Conformance descriptor for synthesized ClosedEnums : _ObjectiveCBridgeable. |
| // CHECK: @"$sSo13SNTClosedEnumas21_ObjectiveCBridgeableSCMc" = |
| |
| // CHECK-LABEL: define swiftcc %TSo8NSStringC* @"$s7newtype14getErrorDomainSo08SNTErrorD0ayF"() |
| public func getErrorDomain() -> ErrorDomain { |
| // CHECK: load %TSo8NSStringC*, %TSo8NSStringC** getelementptr inbounds (%TSo14SNTErrorDomaina, %TSo14SNTErrorDomaina* {{.*}}@SNTErrOne |
| return .one |
| } |
| |
| // CHECK-LABEL: $s7newtype6getFooSo18NSNotificationNameayF |
| public func getFoo() -> NSNotification.Name { |
| return NSNotification.Name.Foo |
| // CHECK: load {{.*}} @FooNotification |
| // CHECK: ret |
| } |
| |
| // CHECK-LABEL: $s7newtype21getGlobalNotificationySSSiF |
| public func getGlobalNotification(_ x: Int) -> String { |
| switch x { |
| case 1: return kNotification |
| // CHECK: load {{.*}} @kNotification |
| case 2: return Notification |
| // CHECK: load {{.*}} @Notification |
| case 3: return swiftNamedNotification |
| // CHECK: load {{.*}} @kSNNotification |
| default: return NSNotification.Name.bar.rawValue |
| // CHECK: load {{.*}} @kBarNotification |
| } |
| // CHECK: ret |
| } |
| |
| // CHECK-LABEL: $s7newtype17getCFNewTypeValue6useVarSo0cD0aSb_tF |
| public func getCFNewTypeValue(useVar: Bool) -> CFNewType { |
| if (useVar) { |
| return CFNewType.MyCFNewTypeValue |
| // CHECK: load {{.*}} @MyCFNewTypeValue |
| } else { |
| return FooAudited() |
| // CHECK: call {{.*}} @FooAudited() |
| } |
| // CHECK: ret |
| } |
| |
| // CHECK-LABEL: $s7newtype21getUnmanagedCFNewType6useVars0C0VySo11CFStringRefaGSb_tF |
| public func getUnmanagedCFNewType(useVar: Bool) -> Unmanaged<CFString> { |
| if (useVar) { |
| return CFNewType.MyCFNewTypeValueUnaudited |
| // CHECK: load {{.*}} @MyCFNewTypeValueUnaudited |
| } else { |
| return FooUnaudited() |
| // CHECK: call {{.*}} @FooUnaudited() |
| } |
| // CHECK: ret |
| } |
| |
| public func hasArrayOfClosedEnums(closed: [ClosedEnum]) { |
| // Triggers instantiation of ClosedEnum : _ObjectiveCBridgeable |
| // witness table. |
| print(closed[0]) |
| } |
| |
| // CHECK-LABEL: $s7newtype11compareABIsyyF |
| public func compareABIs() { |
| let new = getMyABINewType() |
| let old = getMyABIOldType() |
| takeMyABINewType(new) |
| takeMyABIOldType(old) |
| |
| takeMyABINewTypeNonNull(new!) |
| takeMyABIOldTypeNonNull(old!) |
| |
| let newNS = getMyABINewTypeNS() |
| let oldNS = getMyABIOldTypeNS() |
| takeMyABINewTypeNonNullNS(newNS!) |
| takeMyABIOldTypeNonNullNS(oldNS!) |
| |
| // Make sure that the calling conventions align correctly, that is we don't |
| // have double-indirection or anything else like that |
| // CHECK: declare %struct.__CFString* @getMyABINewType() |
| // CHECK: declare %struct.__CFString* @getMyABIOldType() |
| // |
| // CHECK: declare void @takeMyABINewType(%struct.__CFString*) |
| // CHECK: declare void @takeMyABIOldType(%struct.__CFString*) |
| // |
| // CHECK: declare void @takeMyABINewTypeNonNull(%struct.__CFString*) |
| // CHECK: declare void @takeMyABIOldTypeNonNull(%struct.__CFString*) |
| // |
| // CHECK: declare %0* @getMyABINewTypeNS() |
| // CHECK: declare %0* @getMyABIOldTypeNS() |
| // |
| // CHECK: declare void @takeMyABINewTypeNonNullNS(%0*) |
| // CHECK: declare void @takeMyABIOldTypeNonNullNS(%0*) |
| } |
| |
| // OPT-LABEL: define swiftcc i1 @"$s7newtype12compareInitsSbyF" |
| public func compareInits() -> Bool { |
| let mf = MyInt(rawValue: 1) |
| let mfNoLabel = MyInt(1) |
| let res = mf.rawValue == MyInt.one.rawValue |
| && mfNoLabel.rawValue == MyInt.one.rawValue |
| // OPT: [[ONE:%.*]] = load i32, i32*{{.*}}@kMyIntOne{{.*}}, align 4 |
| // OPT-NEXT: [[COMP:%.*]] = icmp eq i32 [[ONE]], 1 |
| |
| takesMyInt(mf) |
| takesMyInt(mfNoLabel) |
| takesMyInt(MyInt(rawValue: kRawInt)) |
| takesMyInt(MyInt(kRawInt)) |
| // OPT: tail call void @takesMyInt(i32 1) |
| // OPT-NEXT: tail call void @takesMyInt(i32 1) |
| // OPT-NEXT: [[RAWINT:%.*]] = load i32, i32*{{.*}} @kRawInt{{.*}}, align 4 |
| // OPT-NEXT: tail call void @takesMyInt(i32 [[RAWINT]]) |
| // OPT-NEXT: tail call void @takesMyInt(i32 [[RAWINT]]) |
| |
| return res |
| // OPT-NEXT: ret i1 [[COMP]] |
| } |
| |
| // CHECK-LABEL: anchor |
| // OPT-LABEL: anchor |
| public func anchor() -> Bool { |
| return false |
| } |
| |
| class ObjCTest { |
| // CHECK-LABEL: define hidden %0* @"$s7newtype8ObjCTestC19optionalPassThroughySo14SNTErrorDomainaSgAGFTo" |
| // CHECK: [[CASTED:%.+]] = ptrtoint %0* %2 to [[INT]] |
| // CHECK: [[RESULT:%.+]] = call swiftcc [[INT]] @"$s7newtype8ObjCTestC19optionalPassThroughySo14SNTErrorDomainaSgAGF"([[INT]] [[CASTED]], %T7newtype8ObjCTestC* swiftself {{%.+}}) |
| // CHECK: [[CAST_RESULT:%.+]] = inttoptr [[INT]] [[RESULT]] to i8* |
| // CHECK: [[AUTORELEASE_RESULT:%.+]] = {{(tail )?}}call i8* @llvm.objc.autoreleaseReturnValue(i8* [[CAST_RESULT]]) |
| // CHECK: [[CAST_AUTORELEASE_RESULT:%.+]] = ptrtoint i8* [[AUTORELEASE_RESULT]] to [[INT]] |
| // CHECK: [[OPAQUE_RESULT:%.+]] = inttoptr [[INT]] [[CAST_AUTORELEASE_RESULT]] to %0* |
| // CHECK: ret %0* [[OPAQUE_RESULT]] |
| // CHECK: {{^}$}} |
| |
| // OPT-LABEL: define hidden %0* @"$s7newtype8ObjCTestC19optionalPassThroughySo14SNTErrorDomainaSgAGFTo" |
| // OPT: [[ARG_CASTED:%.*]] = bitcast %0* %2 to %objc_object* |
| // OPT: [[ARG_RECASTED:%.*]] = bitcast %objc_object* [[ARG_CASTED]] to i8* |
| // OPT: [[ARG_CASTED2:%.*]] = bitcast %0* %2 to i8* |
| // OPT: tail call i8* @llvm.objc.retainAutoreleaseReturnValue(i8* [[ARG_RECASTED]]) |
| // OPT: [[CAST_FOR_RETURN:%.*]] = bitcast i8* [[ARG_CASTED2]] to %0* |
| // OPT: ret %0* [[CAST_FOR_RETURN]] |
| // OPT: {{^}$}} |
| @objc func optionalPassThrough(_ ed: ErrorDomain?) -> ErrorDomain? { |
| return ed |
| } |
| |
| // CHECK-LABEL: define hidden i32 @"$s7newtype8ObjCTestC18integerPassThroughySo5MyIntaAFFTo" |
| // CHECK: [[RESULT:%.+]] = call swiftcc i32 @"$s7newtype8ObjCTestC18integerPassThroughySo5MyIntaAFF"(i32 %2, %T7newtype8ObjCTestC* swiftself {{%.+}}) |
| // CHECK: ret i32 [[RESULT]] |
| // CHECK: {{^}$}} |
| |
| // OPT-LABEL: define hidden i32 @"$s7newtype8ObjCTestC18integerPassThroughySo5MyIntaAFFTo" |
| // OPT: ret i32 %2 |
| // OPT: {{^}$}} |
| @objc func integerPassThrough(_ num: MyInt) -> MyInt { |
| return num |
| } |
| } |
| |
| // OPT-LABEL: $s7newtype6mutateyyF |
| public func mutate() { |
| // Check for a mismatch in indirectness of the swift_newtype and the Clang |
| // type. These pointers should be passed directly for non-mutating functions, |
| // rather than passing a pointer indirectly. I.e. only 1 overall level of |
| // indirection for non-mutating, 2 for mutating. |
| // |
| // OPT: [[TRefAlloca:%.+]] = alloca %struct.T*, |
| // OPT: [[TRef:%.+]] = tail call %struct.T* @create_T() |
| // OPT: store %struct.T* [[TRef]], %struct.T** [[TRefAlloca]], |
| var myT = create_T() |
| |
| // OPT: [[TRefConst:%.+]] = tail call %struct.T* @create_ConstT() |
| let myConstT = create_ConstT() |
| |
| // OPT: tail call void @mutate_TRef_Pointee(%struct.T* [[TRef]]) |
| myT.mutatePointee() |
| |
| // OPT: call void @mutate_TRef(%struct.T** nonnull [[TRefAlloca]]) |
| myT.mutate() |
| |
| // Since myT itself got mutated, now we have to reload from the alloca |
| // |
| // OPT: [[TRefReloaded:%.+]] = load %struct.T*, %struct.T** [[TRefAlloca]], |
| // OPT: call void @mutate_TRef_Pointee(%struct.T* [[TRefReloaded]]) |
| myT.mutatePointee() |
| |
| // OPT: call void @use_ConstT(%struct.T* [[TRefConst]]) |
| myConstT.use() |
| |
| // OPT: ret void |
| } |
| |
| // OPT-LABEL: $s7newtype9mutateRefyyF |
| public func mutateRef() { |
| // Check for a mismatch in indirectness of the swift_newtype and the Clang |
| // type. These pointer pointers should be passed directly, rather than passing |
| // a pointer pointer indirectly. I.e. only 2 overall levels of indirection for |
| // non-mutating, 3 for mutating. |
| // |
| // OPT: [[TRefRefAlloca:%.+]] = alloca %struct.T**, |
| // OPT: [[TRefRef:%.+]] = tail call %struct.T** @create_TRef() |
| // OPT: store %struct.T** [[TRefRef]], %struct.T*** [[TRefRefAlloca]] |
| var myTRef = create_TRef() |
| |
| // OPT: [[ConstTRefRef:%.+]] = tail call %struct.T** @create_ConstTRef() |
| let myConstTRef = create_ConstTRef() |
| |
| // OPT: tail call void @mutate_TRefRef_Pointee(%struct.T** [[TRefRef]]) |
| myTRef.mutatePointee() |
| |
| // OPT: call void @mutate_TRefRef(%struct.T*** nonnull [[TRefRefAlloca]]) |
| myTRef.mutate() |
| |
| // Since myTRef itself got mutated, now we have to reload from the alloca |
| // |
| // OPT: [[TRefReloaded:%.+]] = load %struct.T**, %struct.T*** [[TRefRefAlloca]] |
| // OPT: call void @mutate_TRefRef_Pointee(%struct.T** [[TRefReloaded]]) |
| myTRef.mutatePointee() |
| |
| // OPT: call void @use_ConstTRef(%struct.T** [[ConstTRefRef]]) |
| myConstTRef.use() |
| |
| // OPT: ret void |
| } |
| |
| |