//===--- 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-codesign %t/a.out_Release // RUN: %target-run %t/a.out_Release // REQUIRES: executable_test // REQUIRES: long_test // XFAIL: OS=linux-gnu, OS=linux-android // UNSUPPORTED: OS=freebsd 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()