blob: f442396cfbb6e5fadb5064facda8be74d88bd48c [file] [log] [blame]
//===--- SIMDParameterPassing.swift ---------------------------*- swift -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
// RUN: %empty-directory(%t)
// RUN: %gyb %s -o %t/SIMDParameterPassing.swift
// RUN: %line-directive %t/SIMDParameterPassing.swift -- %target-build-swift %t/SIMDParameterPassing.swift -o %t/a.out_Release -O
// RUN: %target-run %t/a.out_Release
// REQUIRES: executable_test
// REQUIRES: long_test
// XFAIL: linux
import StdlibUnittest
import simd
% scalar_types = ['Float', 'Double', 'Int32', 'UInt32']
% float_types = ['Float', 'Double']
% ctype = { 'Float':'float', 'Double':'double', 'Int32':'int', 'UInt32':'uint'}
let tests = TestSuite("SIMDParameterPassing")
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':
% for Num in range(0, 10):
@inline(__always)
func value${TestType}${Num}() -> ${TestType} {
return ${Num+1}
}
% end
% end
// Vector values.
% for type in scalar_types:
% for cols in [2,3,4]:
% TestType = ctype[type] + str(cols)
// arm64 isel crashes when passing float3.
% if cols == 3:
#if !arch(arm64)
% end
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 : Int8
let f1 : Enum${TestType}
let f2: Float
let f3: Double
init(f0: Int8, f1: Enum${TestType}, f2: Float, f3: Double) {
self.f0 = f0
self.f1 = f1
self.f2 = f2
self.f3 = f3
}
}
func ==(lhs: Struct${TestType}, rhs: Struct${TestType}) -> Bool {
return lhs.f0 == rhs.f0 && lhs.f1 == rhs.f1 && lhs.f2 == rhs.f2 &&
lhs.f3 == rhs.f3
}
% for Num in range(0, 10):
@inline(__always)
func value${TestType}${Num}() -> ${TestType} {
return ${TestType}(${', '.join(map(lambda i: str(i), range(Num, Num+cols)))})
}
@inline(__always)
func valueEnum${TestType}${Num}() -> Enum${TestType} {
return Enum${TestType}.Value(value${TestType}${Num}())
}
func valueStruct${TestType}${Num}() -> Struct${TestType} {
return Struct${TestType}(f0: ${Num+1}, f1: valueEnum${TestType}${Num}(), f2: 1.${Num}, f3: 2.${Num})
}
% end
// arm64 isel crashes when passing float3.
% if cols == 3:
#endif
% end
% end
% end
% 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
% for type in scalar_types:
% for cols in [2,3,4]:
// arm64 isel crashes when passing float3.
% if cols == 3:
#if !arch(arm64)
% end
% for typePrefix in [ '', 'Enum', 'Struct']:
% TestType = typePrefix + ctype[type] + str(cols)
% 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()
)
% if DoesThrow == 'true':
} catch let e as MyError {
expectEqual(127, e.val)
% 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
% if DoesThrow == 'true':
} catch let e as MyError {
expectEqual(127, e.val)
% 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
% if DoesThrow == 'true':
} catch let e as MyError {
expectEqual(127, e.val)
% 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()
)
% if DoesThrow == 'true':
} catch let e as MyError {
expectEqual(127, e.val)
% 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
% if DoesThrow == 'true':
} catch let e as MyError {
expectEqual(127, e.val)
% 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
% if DoesThrow == 'true':
} catch let e as MyError {
expectEqual(127, e.val)
% 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()
)
% if DoesThrow == 'true':
} catch let e as MyError {
expectEqual(127, e.val)
% 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
% if DoesThrow == 'true':
} catch let e as MyError {
expectEqual(127, e.val)
% 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
% if DoesThrow == 'true':
} catch let e as MyError {
expectEqual(127, e.val)
% 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
% end
// arm64 isel crashes when passing float3.
% if cols == 3:
#endif
% end
% end
% end
runAllTests()