Files
swift-mirror/test/stdlib/ParameterPassing.swift.gyb
Arnold Schwaighofer 39fa2f0228 Use the swift calling convention for swift functions
Use the generic type lowering algorithm described in
"docs/CallingConvention.rst#physical-lowering" to map from IRGen's explosion
type to the type expected by the ABI.

Change IRGen to use the swift calling convention (swiftcc) for native swift
functions.

Use the 'swiftself' attribute on self parameters and for closures contexts.

Use the 'swifterror' parameter for swift error parameters.

Change functions in the runtime that are called as native swift functions to use
the swift calling convention.

rdar://19978563
2017-02-14 12:17:57 -08:00

641 lines
16 KiB
Plaintext

//===--- ParameterPassing.swift -------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
// RUN: rm -rf %t
// RUN: mkdir -p %t
// RUN: %gyb %s -o %t/ParameterPassing.swift
// RUN: %line-directive %t/ParameterPassing.swift -- %target-build-swift %t/ParameterPassing.swift -o %t/a.out_Release -O
// RUN: %target-run %t/a.out_Release
// REQUIRES: executable_test
import StdlibUnittest
let tests = TestSuite("ParameterPassing")
struct MyError : Error {
let val = 127
}
%{
errorMethodTypes = [
('Throwing', 'throws', True, 'true'),
('Throws', 'throws', True, 'false'),
('', '', False, 'false'),
]
}%
// Float values.
% for TestType in 'Float', 'Double':
% for Num in range(0, 10):
@inline(__always)
func value${TestType}${Num}() -> ${TestType} {
return 1.${Num+1}
}
% end
% end
// Integer values.
% for TestType in 'UInt8', 'UInt16', 'UInt32', 'UInt64', 'Int8', 'Int16', 'Int32', 'Int64':
enum Enum${TestType} : Equatable {
case Empty
case Value(${TestType})
}
func == (lhs: Enum${TestType}, rhs: Enum${TestType}) -> Bool {
switch lhs {
case .Empty:
switch rhs {
case .Empty:
return true
case .Value(_):
return false
}
case .Value(let lhsVal):
switch lhs {
case .Empty:
return false
case .Value(let rhsVal):
return lhsVal == rhsVal
}
}
}
struct Struct${TestType} : Equatable {
let f0 : ${TestType}
let f1: Float
let f2: Double
init(f0: ${TestType}, f1: Float, f2: Double) {
self.f0 = f0
self.f1 = f1
self.f2 = f2
}
}
func ==(lhs: Struct${TestType}, rhs: Struct${TestType}) -> Bool {
return lhs.f0 == rhs.f0 && lhs.f1 == rhs.f1 && lhs.f2 == rhs.f2
}
% for Num in range(0, 10):
@inline(__always)
func value${TestType}${Num}() -> ${TestType} {
return ${Num+1}
}
@inline(__always)
func valueEnum${TestType}${Num}() -> Enum${TestType} {
return Enum${TestType}.Value(${Num+1})
}
func valueStruct${TestType}${Num}() -> Struct${TestType} {
return Struct${TestType}(f0: ${Num+1}, f1: 1.${Num}, f2: 2.${Num})
}
% end
% end
// Float80 values.
#if arch(i386) || arch(x86_64)
% for Num in range(0, 10):
@inline(__always)
func valueFloat80${Num}() -> Float80 {
return 1.${Num+1}
}
% end
#endif
% for (FuncName, Throw, MayThrow, DoesThrow) in errorMethodTypes:
@inline(never)
func clobber${FuncName}(
_ d0: Double, _ d1: Double, _ d2: Double, _ d3: Double, _ d4: Double, _ d5: Double,
_ d6: Double, _ d7: Double, _ d8: Double, _ d9: Double, _ i0: Int, _ i1: Int,
_ i2: Int, _ i3: Int, _ i4: Int, _ i5: Int, _ i6: Int, _ i7: Int, _ i8: Int,
_ i9: Int
) ${Throw} -> (Double, Int) {
let sumD = d0 + d1 + d2 + d3 + d4 + d5 + d6 + d7 + d8 + d9
let sumI = i0 + i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9
% if MayThrow:
var shouldThrow = ${DoesThrow}
withUnsafeMutablePointer(to: &shouldThrow, { _blackHole($0) })
if shouldThrow {
throw MyError()
}
% end
return (sumD, sumI)
}
%end
%{ testTypes = [
'Float', 'Float80', 'Double', 'UInt8', 'UInt16', 'UInt32', 'UInt64',
'Int8', 'Int16', 'Int32', 'Int64',
'EnumUInt8', 'EnumUInt16', 'EnumUInt32', 'EnumUInt64', 'EnumInt8',
'EnumInt16', 'EnumInt32', 'EnumInt64',
'StructUInt8', 'StructUInt16', 'StructUInt32', 'StructUInt64',
'StructInt8', 'StructInt16', 'StructInt32', 'StructInt64',
]
}%
% for TestType in testTypes:
% if TestType == 'Float80':
#if arch(i386) || arch(x86_64)
% end
% for (FuncName, Throw, MayThrow, DoesThrow) in errorMethodTypes:
@inline(never)
func verifyParameters${TestType}${FuncName}(
_ p0: ${TestType}, _ p1: ${TestType}, _ p2: ${TestType}, _ p3: ${TestType}, _ p4: ${TestType}, _ p5: ${TestType},
_ p6: ${TestType}, _ p7: ${TestType}, _ p8: ${TestType}, _ p9 : ${TestType}
) ${Throw} {
% for Num in range(0, 10):
precondition(p${Num} == value${TestType}${Num}())
% end
% if MayThrow:
let res = try clobber${FuncName}(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
% else:
let res = clobber${FuncName}(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
% end
2, 3, 5, 7, 11, 13, 17, 19, 23, 29)
precondition(res.0 == 5.5)
precondition(res.1 == 129)
% for Num in range(0, 10):
precondition(p${Num} == value${TestType}${Num}())
% end
}
@inline(never)
func verifyReturn${TestType}${FuncName}() ${Throw} -> (
% for Num in range(0, 9):
${TestType},
% end
${TestType}
)
{
% if MayThrow:
var shouldThrow = ${DoesThrow}
withUnsafeMutablePointer(to: &shouldThrow, { _blackHole($0) })
if shouldThrow {
throw MyError()
}
% end
return (
% for Num in range(0, 9):
value${TestType}${Num}(),
% end
value${TestType}9()
)
}
@inline(never)
func verifyReturnAndParameters${TestType}${FuncName}(
_ p0: ${TestType}, _ p1: ${TestType}, _ p2: ${TestType}, _ p3: ${TestType}, _ p4: ${TestType}, _ p5: ${TestType},
_ p6: ${TestType}, _ p7: ${TestType}, _ p8: ${TestType}, _ p9 : ${TestType}
) ${Throw} -> (
% for Num in range(0, 9):
${TestType},
% end
${TestType}
)
{
% for Num in range(0, 10):
precondition(p${Num} == value${TestType}${Num}())
% end
% if MayThrow:
let res = try clobber${FuncName}(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
% else:
let res = clobber${FuncName}(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
% end
2, 3, 5, 7, 11, 13, 17, 19, 23, 29)
precondition(res.0 == 5.5)
precondition(res.1 == 129)
% for Num in range(0, 10):
precondition(p${Num} == value${TestType}${Num}())
% end
return (
% for Num in range(0, 9):
value${TestType}${Num}(),
% end
value${TestType}9()
)
}
% end
protocol Proto${TestType} {
% for (FuncName, Throw, _, _) in errorMethodTypes:
func verifyParameters${FuncName}(
_ p0: ${TestType}, _ p1: ${TestType}, _ p2: ${TestType}, _ p3: ${TestType}, _ p4: ${TestType}, _ p5: ${TestType},
_ p6: ${TestType}, _ p7: ${TestType}, _ p8: ${TestType}, _ p9 : ${TestType}
) ${Throw}
func verifyReturn${FuncName}() ${Throw} -> (
% for Num in range(0, 9):
${TestType},
% end
${TestType}
)
@inline(never)
func verifyReturnAndParameters${FuncName}(
_ p0: ${TestType}, _ p1: ${TestType}, _ p2: ${TestType}, _ p3: ${TestType}, _ p4: ${TestType}, _ p5: ${TestType},
_ p6: ${TestType}, _ p7: ${TestType}, _ p8: ${TestType}, _ p9 : ${TestType}
) ${Throw} -> (
% for Num in range(0, 9):
${TestType},
% end
${TestType}
)
%end
}
public class A${TestType} : Proto${TestType} {
var dontStripSelfArg: Int = 7
init() {}
% for (FuncName, Throw, MayThrow, _) in errorMethodTypes:
@inline(never)
func verifyParameters${FuncName}(
_ p0: ${TestType}, _ p1: ${TestType}, _ p2: ${TestType}, _ p3: ${TestType}, _ p4: ${TestType}, _ p5: ${TestType},
_ p6: ${TestType}, _ p7: ${TestType}, _ p8: ${TestType}, _ p9 : ${TestType}
) ${Throw} {
% for Num in range(0, 10):
precondition(p${Num} == value${TestType}${Num}())
% end
% if MayThrow:
let res = try clobber${FuncName}(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
% else:
let res = clobber${FuncName}(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
% end
2, 3, 5, 7, 11, 13, 17, 19, 23, 29)
precondition(dontStripSelfArg == 7)
precondition(res.0 == 5.5)
precondition(res.1 == 129)
% for Num in range(0, 10):
precondition(p${Num} == value${TestType}${Num}())
% end
}
func verifyReturn${FuncName}() ${Throw} -> (
% for Num in range(0, 9):
${TestType},
% end
${TestType}
)
{
% if MayThrow:
var shouldThrow = ${DoesThrow}
withUnsafeMutablePointer(to: &shouldThrow, { _blackHole($0) })
if shouldThrow {
throw MyError()
}
% end
return (
% for Num in range(0, 9):
value${TestType}${Num}(),
% end
value${TestType}9()
)
}
@inline(never)
func verifyReturnAndParameters${FuncName}(
_ p0: ${TestType}, _ p1: ${TestType}, _ p2: ${TestType}, _ p3: ${TestType}, _ p4: ${TestType}, _ p5: ${TestType},
_ p6: ${TestType}, _ p7: ${TestType}, _ p8: ${TestType}, _ p9 : ${TestType}
) ${Throw} -> (
% for Num in range(0, 9):
${TestType},
% end
${TestType}
)
{
% for Num in range(0, 10):
precondition(p${Num} == value${TestType}${Num}())
% end
% if MayThrow:
let res = try clobber${FuncName}(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
% else:
let res = clobber${FuncName}(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
% end
2, 3, 5, 7, 11, 13, 17, 19, 23, 29)
precondition(res.0 == 5.5)
precondition(res.1 == 129)
% for Num in range(0, 10):
precondition(p${Num} == value${TestType}${Num}())
% end
return (
% for Num in range(0, 9):
value${TestType}${Num}(),
% end
value${TestType}9()
)
}
% end
}
% for (FuncName, throw, MayThrow, DoesThrow) in errorMethodTypes:
tests.test("${TestType}/Fun${FuncName}") {
// Test a regular function call.
% if MayThrow:
do {
try verifyParameters${TestType}${FuncName}(
%for Num in range(0, 9):
value${TestType}${Num}(),
%end
value${TestType}9()
)
} catch let e as MyError {
% if DoesThrow == 'true':
expectEqual(127, e.val)
% else:
preconditionFailure("Should not get there")
% end
} catch {
preconditionFailure("Should not get there")
}
% else:
verifyParameters${TestType}${FuncName}(
%for Num in range(0, 9):
value${TestType}${Num}(),
%end
value${TestType}9()
)
% end
}
tests.test("${TestType}/RetFun${FuncName}") {
// Test a regular function call.
% if MayThrow:
do {
let res = try verifyReturn${TestType}${FuncName}()
% for Num in range(0, 10):
expectEqual(value${TestType}${Num}(), res.${Num})
% end
} catch let e as MyError {
% if DoesThrow == 'true':
expectEqual(127, e.val)
% else:
preconditionFailure("Should not get there")
% end
} catch {
preconditionFailure("Should not get there")
}
% else:
let res = verifyReturn${TestType}${FuncName}()
%for Num in range(0, 10):
expectEqual(value${TestType}${Num}(), res.${Num})
% end
% end
}
tests.test("${TestType}/RetAndParamFun${FuncName}") {
// Test a regular function call.
% if MayThrow:
do {
let res = try verifyReturnAndParameters${TestType}${FuncName}(
%for Num in range(0, 9):
value${TestType}${Num}(),
%end
value${TestType}9()
)
% for Num in range(0, 10):
expectEqual(value${TestType}${Num}(), res.${Num})
% end
} catch let e as MyError {
% if DoesThrow == 'true':
expectEqual(127, e.val)
% else:
preconditionFailure("Should not get there")
% end
} catch {
preconditionFailure("Should not get there")
}
% else:
let res = verifyReturnAndParameters${TestType}${FuncName}(
%for Num in range(0, 9):
value${TestType}${Num}(),
%end
value${TestType}9()
)
% for Num in range(0, 10):
expectEqual(value${TestType}${Num}(), res.${Num})
% end
% end
}
tests.test("${TestType}/Method${FuncName}") {
var klazz = A${TestType}()
// Defeat type analysis such that the call below remains a method call.
withUnsafeMutablePointer(to: &klazz, { _blackHole($0) })
// Test a method call.
% if MayThrow:
do {
try klazz.verifyParameters${FuncName}(
%for Num in range(0, 9):
value${TestType}${Num}(),
%end
value${TestType}9()
)
} catch let e as MyError {
% if DoesThrow == 'true':
expectEqual(127, e.val)
% else:
preconditionFailure("Should not get there")
% end
} catch {
preconditionFailure("Should not get there")
}
% else:
klazz.verifyParameters${FuncName}(
%for Num in range(0, 9):
value${TestType}${Num}(),
%end
value${TestType}9()
)
% end
}
tests.test("${TestType}/RetMethod${FuncName}") {
var klazz = A${TestType}()
// Defeat type analysis such that the call below remains a method call.
withUnsafeMutablePointer(to: &klazz, { _blackHole($0) })
// Test a method call.
% if MayThrow:
do {
let res = try klazz.verifyReturn${FuncName}()
% for Num in range(0, 10):
expectEqual(value${TestType}${Num}(), res.${Num})
% end
} catch let e as MyError {
% if DoesThrow == 'true':
expectEqual(127, e.val)
% else:
preconditionFailure("Should not get there")
% end
} catch {
preconditionFailure("Should not get there")
}
% else:
let res = klazz.verifyReturn${FuncName}()
%for Num in range(0, 10):
expectEqual(value${TestType}${Num}(), res.${Num})
% end
% end
}
tests.test("${TestType}/RetAndParamMethod${FuncName}") {
var klazz = A${TestType}()
// Defeat type analysis such that the call below remains a method call.
withUnsafeMutablePointer(to: &klazz, { _blackHole($0) })
// Test a method call.
% if MayThrow:
do {
let res = try klazz.verifyReturnAndParameters${FuncName}(
%for Num in range(0, 9):
value${TestType}${Num}(),
%end
value${TestType}9()
)
%for Num in range(0, 10):
expectEqual(value${TestType}${Num}(), res.${Num})
% end
} catch let e as MyError {
% if DoesThrow == 'true':
expectEqual(127, e.val)
% else:
preconditionFailure("Should not get there")
% end
} catch {
preconditionFailure("Should not get there")
}
% else:
let res = klazz.verifyReturnAndParameters${FuncName}(
%for Num in range(0, 9):
value${TestType}${Num}(),
%end
value${TestType}9()
)
%for Num in range(0, 10):
expectEqual(value${TestType}${Num}(), res.${Num})
% end
% end
}
tests.test("${TestType}/WitnessMethod${FuncName}") {
var p : Proto${TestType} = A${TestType}()
withUnsafeMutablePointer(to: &p, { _blackHole($0) })
// Test a witness method call.
% if MayThrow:
do {
try p.verifyParameters${FuncName}(
%for Num in range(0, 9):
value${TestType}${Num}(),
%end
value${TestType}9()
)
} catch let e as MyError {
% if DoesThrow == 'true':
expectEqual(127, e.val)
% else:
preconditionFailure("Should not get there")
% end
} catch {
preconditionFailure("Should not get there")
}
% else:
p.verifyParameters${FuncName}(
%for Num in range(0, 9):
value${TestType}${Num}(),
%end
value${TestType}9()
)
% end
}
tests.test("${TestType}/RetWitnessMethod${FuncName}") {
var p : Proto${TestType} = A${TestType}()
withUnsafeMutablePointer(to: &p, { _blackHole($0) })
// Test a witness method call.
% if MayThrow:
do {
let res = try p.verifyReturn${FuncName}()
% for Num in range(0, 10):
expectEqual(value${TestType}${Num}(), res.${Num})
% end
} catch let e as MyError {
% if DoesThrow == 'true':
expectEqual(127, e.val)
% else:
preconditionFailure("Should not get there")
% end
} catch {
preconditionFailure("Should not get there")
}
% else:
let res = p.verifyReturn${FuncName}()
%for Num in range(0, 10):
expectEqual(value${TestType}${Num}(), res.${Num})
% end
% end
}
tests.test("${TestType}/RetAndParamWitnessMethod${FuncName}") {
var p : Proto${TestType} = A${TestType}()
withUnsafeMutablePointer(to: &p, { _blackHole($0) })
// Test a method call.
% if MayThrow:
do {
let res = try p.verifyReturnAndParameters${FuncName}(
%for Num in range(0, 9):
value${TestType}${Num}(),
%end
value${TestType}9()
)
%for Num in range(0, 10):
expectEqual(value${TestType}${Num}(), res.${Num})
% end
} catch let e as MyError {
% if DoesThrow == 'true':
expectEqual(127, e.val)
% else:
preconditionFailure("Should not get there")
% end
} catch {
preconditionFailure("Should not get there")
}
% else:
let res = p.verifyReturnAndParameters${FuncName}(
%for Num in range(0, 9):
value${TestType}${Num}(),
%end
value${TestType}9()
)
%for Num in range(0, 10):
expectEqual(value${TestType}${Num}(), res.${Num})
% end
% end
}
% end
% if TestType == 'Float80':
#endif
% end
% end
runAllTests()