mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
A single-field struct with an @_alignment attribute does not have the same layout as its field. This caused the runtime to compute incorrect layouts for generic structs containing SIMD types. Fixes <rdar://problem/33794343>.
350 lines
10 KiB
Plaintext
350 lines
10 KiB
Plaintext
// RUN: %target-run-simple-swiftgyb
|
|
// REQUIRES: executable_test
|
|
|
|
// FIXME: No simd module on linux rdar://problem/20795411
|
|
// XFAIL: linux
|
|
|
|
import simd
|
|
import StdlibUnittest
|
|
|
|
|
|
% scalar_types = ['Float', 'Double', 'Int32', 'UInt32']
|
|
% float_types = ['Float', 'Double']
|
|
% ctype = { 'Float':'float', 'Double':'double', 'Int32':'int', 'UInt32':'uint'}
|
|
% component = ['.x','.y','.z','.w']
|
|
|
|
% for type in scalar_types:
|
|
% for cols in [2,3,4]:
|
|
// Workaround <rdar://problem/18900352>
|
|
% vectype = ctype[type] + str(cols)
|
|
func same(_ x: ${vectype}, _ y: ${vectype}) -> Bool {
|
|
for i in 0..<${cols} {
|
|
// Workaround <rdar://problem/18900352>
|
|
% if type in float_types:
|
|
if x[i] != y[i] && !(x[i].isNaN && y[i].isNaN) { return false }
|
|
% else:
|
|
if x[i] != y[i] { return false }
|
|
% end
|
|
}
|
|
return true
|
|
}
|
|
% if type in float_types:
|
|
// Workaround <rdar://problem/18900352>
|
|
% for rows in [2,3,4]:
|
|
// Workaround <rdar://problem/18900352>
|
|
% mattype = ctype[type] + str(cols) + 'x' + str(rows)
|
|
func same(_ x: ${mattype}, _ y: ${mattype}) -> Bool {
|
|
for i in 0..<${cols} {
|
|
if !same(x[i], y[i]) { return false }
|
|
}
|
|
return true
|
|
}
|
|
% end # for rows in [2,3,4]
|
|
% end # if type in float_types
|
|
% end # for cols in [2,3,4]
|
|
% end # for type in scalar_types
|
|
|
|
|
|
|
|
/*
|
|
func same<M: SIMDMatrixType>(_ x:M, _ y:M) -> Bool {
|
|
for i in 0 ..< x.columns {
|
|
if (!same(x[i], y[i])) { return false }
|
|
}
|
|
return true
|
|
}
|
|
*/
|
|
|
|
var simdTestSuite = TestSuite("simd")
|
|
|
|
simdTestSuite.test("sizes") {
|
|
// C interop requires that vector be the right size.
|
|
expectEqual(8, MemoryLayout<float2>.size)
|
|
expectEqual(16, MemoryLayout<float3>.size)
|
|
expectEqual(16, MemoryLayout<float4>.size)
|
|
expectEqual(8, MemoryLayout<int2>.size)
|
|
expectEqual(16, MemoryLayout<int3>.size)
|
|
expectEqual(16, MemoryLayout<int4>.size)
|
|
expectEqual(16, MemoryLayout<double2>.size)
|
|
expectEqual(32, MemoryLayout<double3>.size)
|
|
expectEqual(32, MemoryLayout<double4>.size)
|
|
|
|
expectEqual(16, MemoryLayout<float2x2>.size)
|
|
expectEqual(32, MemoryLayout<float2x3>.size)
|
|
expectEqual(32, MemoryLayout<float2x4>.size)
|
|
expectEqual(24, MemoryLayout<float3x2>.size)
|
|
expectEqual(48, MemoryLayout<float3x3>.size)
|
|
expectEqual(48, MemoryLayout<float3x4>.size)
|
|
expectEqual(32, MemoryLayout<float4x2>.size)
|
|
expectEqual(64, MemoryLayout<float4x3>.size)
|
|
expectEqual(64, MemoryLayout<float4x4>.size)
|
|
|
|
expectEqual(32, MemoryLayout<double2x2>.size)
|
|
expectEqual(64, MemoryLayout<double2x3>.size)
|
|
expectEqual(64, MemoryLayout<double2x4>.size)
|
|
expectEqual(48, MemoryLayout<double3x2>.size)
|
|
expectEqual(96, MemoryLayout<double3x3>.size)
|
|
expectEqual(96, MemoryLayout<double3x4>.size)
|
|
expectEqual(64, MemoryLayout<double4x2>.size)
|
|
expectEqual(128, MemoryLayout<double4x3>.size)
|
|
expectEqual(128, MemoryLayout<double4x4>.size)
|
|
}
|
|
|
|
simdTestSuite.test("alignment") {
|
|
struct GenericLayout<T> {
|
|
let t: T = 0 as! T
|
|
let v: int4 = [1,2,3,4]
|
|
}
|
|
|
|
let g = GenericLayout<Int>()
|
|
expectEqual(0, g.t)
|
|
expectEqual([1,2,3,4], g.v)
|
|
}
|
|
|
|
|
|
simdTestSuite.test("vector init") {
|
|
% for type in scalar_types:
|
|
% for size in [2,3,4]:
|
|
// Workaround <rdar://problem/18900352>
|
|
% vectype = ctype[type] + str(size)
|
|
% vec = 'v_' + vectype
|
|
|
|
// Check empty initializer.
|
|
var ${vec} = ${vectype}()
|
|
expectEqualTest(${[0]*size}, ${vec}, sameValue: same)
|
|
|
|
// Check literal initializer.
|
|
${vec} = ${vectype}(2)
|
|
expectEqualTest(${[2]*size}, ${vec}, sameValue: same)
|
|
|
|
// Check scalar initializer.
|
|
expectEqualTest(${vectype}(${type}(2)), ${vec}, sameValue: same)
|
|
|
|
// Check elementwise initializer.
|
|
${vec} = ${vectype}(${', '.join(map(lambda i: str(i), range(size)))})
|
|
expectEqualTest(${range(size)}, ${vec}, sameValue: same)
|
|
|
|
// Check labeled elementwise initializer.
|
|
${vec} = ${vectype}(${', '.join(map(lambda i:
|
|
component[i][1:] + ':' + str(i),
|
|
range(size)))})
|
|
expectEqualTest(${range(size)}, ${vec}, sameValue: same)
|
|
|
|
// Previous checks implicitly use the array initializer, so we're good
|
|
// with that one already.
|
|
|
|
% end # for size in [2,3,4]
|
|
% end # for type in scalar_types
|
|
}
|
|
|
|
simdTestSuite.test("vector elements") {
|
|
% for type in scalar_types:
|
|
% for size in [2,3,4]:
|
|
// Workaround <rdar://problem/18900352>
|
|
% vectype = ctype[type] + str(size)
|
|
% vec = 'v_' + vectype
|
|
var ${vec} = ${vectype}()
|
|
|
|
// Check getting and setting .xyzw
|
|
% for i in range(size):
|
|
${vec + component[i]} = ${2*i}
|
|
expectEqual(${vec + component[i]}, ${2*i})
|
|
% end
|
|
|
|
// Check getting and setting [i]
|
|
for i in 0..<${size} { ${vec}[i] = ${vec}[i]/2 }
|
|
expectEqualTest(${vec}, ${range(size)}, sameValue: same)
|
|
|
|
% end # for size in [2,3,4]
|
|
% end # for type in scalar_types
|
|
}
|
|
|
|
% for type in scalar_types:
|
|
// ----
|
|
% if type not in float_types:
|
|
// ----
|
|
% for size in [2,3,4]:
|
|
// ----
|
|
% vectype = ctype[type] + str(size)
|
|
|
|
extension ${vectype}: Equatable {}
|
|
public func ==(a: ${vectype}, b: ${vectype}) -> Bool {
|
|
% for i in xrange(0, size):
|
|
if (a${component[i]} != b${component[i]}) { return false }
|
|
% end
|
|
return true
|
|
}
|
|
|
|
simdTestSuite.test("${vectype} wrapping arithmetic") {
|
|
|
|
expectEqual(${vectype}(.max) &+ ${vectype}(1),
|
|
${vectype}(.min))
|
|
|
|
expectEqual(${vectype}(.min) &- ${vectype}(1),
|
|
${vectype}(.max))
|
|
|
|
expectEqual(${vectype}(.max) &* ${vectype}(.max),
|
|
${vectype}(1))
|
|
expectEqual(${vectype}(.max) &* .max,
|
|
${vectype}(1))
|
|
expectEqual(.max &* ${vectype}(.max),
|
|
${vectype}(1))
|
|
}
|
|
|
|
% end
|
|
% end
|
|
% end
|
|
|
|
|
|
simdTestSuite.test("vector debugDescription") {
|
|
var f2 = float2(1, 2)
|
|
expectEqual("float2(1.0, 2.0)", f2.debugDescription)
|
|
var f3 = float3(1, 2, 3)
|
|
expectEqual("float3(1.0, 2.0, 3.0)", f3.debugDescription)
|
|
var f4 = float4(1, 2, 3, 4)
|
|
expectEqual("float4(1.0, 2.0, 3.0, 4.0)", f4.debugDescription)
|
|
|
|
var d2 = double2(1, 2)
|
|
expectEqual("double2(1.0, 2.0)", d2.debugDescription)
|
|
var d3 = double3(1, 2, 3)
|
|
expectEqual("double3(1.0, 2.0, 3.0)", d3.debugDescription)
|
|
var d4 = double4(1, 2, 3, 4)
|
|
expectEqual("double4(1.0, 2.0, 3.0, 4.0)", d4.debugDescription)
|
|
|
|
var i2 = int2(1, 2)
|
|
expectEqual("int2(1, 2)", i2.debugDescription)
|
|
var i3 = int3(1, 2, 3)
|
|
expectEqual("int3(1, 2, 3)", i3.debugDescription)
|
|
var i4 = int4(1, 2, 3, 4)
|
|
expectEqual("int4(1, 2, 3, 4)", i4.debugDescription)
|
|
}
|
|
|
|
simdTestSuite.test("vector distance") {
|
|
% for type in float_types:
|
|
let ${ctype[type]}2_x = ${ctype[type]}2(0,5)
|
|
let ${ctype[type]}2_y = ${ctype[type]}2(3,1)
|
|
expectEqual(5, distance(${ctype[type]}2_x, ${ctype[type]}2_y))
|
|
expectEqual(0, distance(${ctype[type]}2_x, ${ctype[type]}2_x))
|
|
expectEqual(25, distance_squared(${ctype[type]}2_x, ${ctype[type]}2_y))
|
|
expectEqual(0, distance_squared(${ctype[type]}2_x, ${ctype[type]}2_x))
|
|
|
|
let ${ctype[type]}3_x = ${ctype[type]}3(-1,-2,-4)
|
|
let ${ctype[type]}3_y = ${ctype[type]}3( 1, 1, 2)
|
|
expectEqual(7, distance(${ctype[type]}3_x, ${ctype[type]}3_y))
|
|
expectEqual(0, distance(${ctype[type]}3_x, ${ctype[type]}3_x))
|
|
expectEqual(49, distance_squared(${ctype[type]}3_x, ${ctype[type]}3_y))
|
|
expectEqual(0, distance_squared(${ctype[type]}3_x, ${ctype[type]}3_x))
|
|
|
|
let ${ctype[type]}4_x = ${ctype[type]}4(-1, 0, 1, 1)
|
|
let ${ctype[type]}4_y = ${ctype[type]}4( 0, 1, 0, 2)
|
|
expectEqual(2, distance(${ctype[type]}4_x, ${ctype[type]}4_y))
|
|
expectEqual(0, distance(${ctype[type]}4_x, ${ctype[type]}4_x))
|
|
expectEqual(4, distance_squared(${ctype[type]}4_x, ${ctype[type]}4_y))
|
|
expectEqual(0, distance_squared(${ctype[type]}4_x, ${ctype[type]}4_x))
|
|
% end # for type in float_types
|
|
}
|
|
|
|
simdTestSuite.test("matrix init") {
|
|
% for type in float_types:
|
|
% for cols in [2,3,4]:
|
|
// Workaround <rdar://problem/18900352>
|
|
% for rows in [2,3,4]:
|
|
// Workaround <rdar://problem/18900352>
|
|
% mattype = ctype[type] + str(cols) + 'x' + str(rows)
|
|
% coltype = ctype[type] + str(rows)
|
|
% mat = 'm_' + mattype
|
|
% diagsize = rows if rows < cols else cols
|
|
|
|
// Check empty initializer.
|
|
var ${mat} = ${mattype}()
|
|
expectEqualTest(${mat}, ${mattype}(${[[0]*rows]*cols}), sameValue: same)
|
|
|
|
// Check scalar initializer.
|
|
${mat} = ${mattype}(2)
|
|
for i in 0..<${rows} {
|
|
for j in 0..<${cols} {
|
|
if i == j { expectEqual(${mat}[i, i], 2) }
|
|
else { expectEqual(${mat}[j, i], 0) }
|
|
}
|
|
}
|
|
|
|
// Check diagonal initializer.
|
|
${mat} = ${mattype}(diagonal: ${range(diagsize)})
|
|
for i in 0..<${rows} {
|
|
for j in 0..<${cols} {
|
|
if i == j { expectEqual(${mat}[i, i], ${type}(i)) }
|
|
else { expectEqual(${mat}[j, i], 0) }
|
|
}
|
|
}
|
|
|
|
// All the previous checks implicitly used the column initializer.
|
|
|
|
// Check row initializer.
|
|
${mat} = ${mattype}(rows:[
|
|
% for i in range(rows):
|
|
${range(i*cols, (i+1)*cols)},
|
|
% end # for i
|
|
])
|
|
for i in 0..<${rows} {
|
|
for j in 0..<${cols} {
|
|
expectEqual(${mat}[j, i], ${type}(${cols}*i + j))
|
|
}
|
|
}
|
|
|
|
% end # for rows
|
|
% end # for cols
|
|
% end # for type
|
|
}
|
|
|
|
simdTestSuite.test("matrix elements") {
|
|
% for type in float_types:
|
|
% for cols in [2,3,4]:
|
|
// Workaround <rdar://problem/18900352>
|
|
% for rows in [2,3,4]:
|
|
// Workaround <rdar://problem/18900352>
|
|
% mattype = ctype[type] + str(cols) + 'x' + str(rows)
|
|
% coltype = ctype[type] + str(rows)
|
|
% mat = 'm_' + mattype
|
|
% basis = type.lower() + 'basis' + str(cols) + 'x' + str(rows)
|
|
% diagsize = rows if rows < cols else cols
|
|
|
|
// Check getting and setting columns.
|
|
let ${basis} : [${coltype}] = [
|
|
% for i in range(cols):
|
|
[${', '.join(map(lambda j:
|
|
'1' if i == j else '0',
|
|
range(rows)))}],
|
|
% end
|
|
]
|
|
var ${mat} = ${mattype}()
|
|
for i in 0..<${cols} {
|
|
${mat}[i] = ${type}(i+1)*${basis}[i]
|
|
}
|
|
expectEqualTest(
|
|
${mat}, ${mattype}(diagonal:${range(1, diagsize + 1)}), sameValue: same)
|
|
for i in 0..<${cols} {
|
|
expectEqualTest(${mat}[i], ${type}(i + 1)*${basis}[i], sameValue: same)
|
|
}
|
|
|
|
// Check getting and setting elements (and transpose).
|
|
${mat} = ${mattype}()
|
|
for i in 0..<${rows} {
|
|
for j in 0..<${cols} {
|
|
${mat}[j, i] = ${type}(${cols}*i + j)
|
|
}
|
|
}
|
|
var ${'trans'+mat} = ${mat}.transpose
|
|
for j in 0..<${cols} {
|
|
for i in 0..<${rows} {
|
|
expectEqual(${'trans'+mat}[i, j], ${type}(${cols}*i + j))
|
|
}
|
|
}
|
|
|
|
% end # for rows
|
|
% end # for cols
|
|
% end # for type
|
|
}
|
|
|
|
runAllTests()
|
|
|