mirror of
https://github.com/odin-lang/Odin.git
synced 2026-10-08 13:51:37 -04:00
Merge pull request #7797 from corleypc/align-regression-tests
Adds alignment related regression tests
This commit is contained in:
2 files changed
+234
No files matched your search
@@ -1,5 +1,6 @@
|
||||
package test_internal
|
||||
|
||||
import "core:simd"
|
||||
import "core:testing"
|
||||
|
||||
U :: union { int, f64 }
|
||||
@@ -47,3 +48,201 @@ test_packed_field_by_reference :: proc(t: ^testing.T) {
|
||||
ptr^ = 7
|
||||
testing.expect_value(t, p.u, U(7))
|
||||
}
|
||||
|
||||
|
||||
// small loads and stores (<= 64 byte) through a #packed field;
|
||||
// access must not claim the field's type alignment (here 16),
|
||||
// because the field is at align 1
|
||||
// 1) through a ptr param (the field GEP carries is-packed metadata)
|
||||
// 2) directly on the global (the GEP folds to ConstantExpr, no metadata)
|
||||
|
||||
|
||||
Packed_Small :: struct #packed {
|
||||
_: u8,
|
||||
v: #simd[4]f32, // offset 1
|
||||
n: i64, // offset 17
|
||||
}
|
||||
|
||||
@(export)
|
||||
p1: Packed_Small
|
||||
|
||||
@(private="file")
|
||||
swap_v :: proc(p: ^Packed_Small, x: #simd[4]f32) -> #simd[4]f32 {
|
||||
y := p.v
|
||||
p.v = x
|
||||
return y
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_packed_field_pointer_access :: proc(t: ^testing.T) {
|
||||
p1.v = {1, 2, 3, 4} // store through a constant GEP
|
||||
|
||||
old := #force_no_inline swap_v(&p1, {5, 6, 7, 8})
|
||||
testing.expect(t, simd.to_array(old) == [4]f32{1, 2, 3, 4})
|
||||
testing.expect(t, simd.to_array(p1.v) == [4]f32{5, 6, 7, 8})
|
||||
}
|
||||
|
||||
|
||||
// element access to an array field of a #packed
|
||||
|
||||
Packed_Array :: struct #packed {
|
||||
_: u8,
|
||||
arr: [2]#simd[4]f32, // elems at offsets 1 and 17
|
||||
}
|
||||
|
||||
@(export)
|
||||
p2: Packed_Array
|
||||
|
||||
@(private="file")
|
||||
read_elem :: proc(p: ^Packed_Array, i: int) -> #simd[4]f32 {
|
||||
return p.arr[i]
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
write_elem :: proc(p: ^Packed_Array, i: int, x: #simd[4]f32) {
|
||||
p.arr[i] = x
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_packed_field_array_element_access :: proc(t: ^testing.T) {
|
||||
p2.arr[0] = {1, 2, 3, 4}
|
||||
p2.arr[1] = {5, 6, 7, 8}
|
||||
|
||||
y := #force_no_inline read_elem(&p2, 0)
|
||||
testing.expect(t, simd.to_array(y) == [4]f32{1, 2, 3, 4})
|
||||
|
||||
y = #force_no_inline read_elem(&p2, 1)
|
||||
testing.expect(t, simd.to_array(y) == [4]f32{5, 6, 7, 8})
|
||||
|
||||
#force_no_inline write_elem(&p2, 0, {9, 10, 11, 12})
|
||||
testing.expect(t, simd.to_array(p2.arr[0]) == [4]f32{9, 10, 11, 12})
|
||||
}
|
||||
|
||||
|
||||
// accesses derived from a #max_field_align struct's field
|
||||
// (array element, nested struct field) must not assume more
|
||||
// than the max_field_align cap
|
||||
|
||||
Capped_Inner :: struct { x: i64 }
|
||||
|
||||
Capped :: struct #max_field_align(4) {
|
||||
a: u16,
|
||||
b: u64, // offset 4
|
||||
arr: [2]u64, // elems at offs 12 and 20
|
||||
inner: Capped_Inner, // x at offs 28
|
||||
}
|
||||
|
||||
@(export)
|
||||
c1: Capped
|
||||
|
||||
@(private="file")
|
||||
swap_elem :: proc(c: ^Capped, i: int, v: u64) -> u64 {
|
||||
y := c.arr[i]
|
||||
c.arr[i] = v
|
||||
return y
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
swap_nested :: proc(c: ^Capped, v: i64) -> i64 {
|
||||
y := c.inner.x
|
||||
c.inner.x = v
|
||||
return y
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_max_field_align_derived_access :: proc(t: ^testing.T) {
|
||||
c1.b = 0xCAFECAFE_11223344
|
||||
c1.arr[0] = 1
|
||||
c1.arr[1] = 2
|
||||
c1.inner.x = -1
|
||||
|
||||
y := #force_no_inline swap_elem(&c1, 1, 5)
|
||||
testing.expect(t, y == 2)
|
||||
testing.expect(t, c1.arr[0] == 1)
|
||||
testing.expect(t, c1.arr[1] == 5)
|
||||
|
||||
z := #force_no_inline swap_nested(&c1, -2)
|
||||
testing.expect(t, z == -1)
|
||||
testing.expect(t, c1.inner.x == -2)
|
||||
testing.expect(t, c1.b == 0xCAFECAFE_11223344)
|
||||
}
|
||||
|
||||
|
||||
// a #min_field_align inner struct placed in a #packed outer struct;
|
||||
// the outer's #packed provides only align 1;
|
||||
// accesses must not assume the #min_field_align
|
||||
|
||||
Raised_Inner :: struct #min_field_align(16) {
|
||||
v: #simd[4]f32,
|
||||
}
|
||||
|
||||
Packed_Raised :: struct #packed {
|
||||
_: u8,
|
||||
inner: Raised_Inner, // offs 1
|
||||
}
|
||||
|
||||
@(export)
|
||||
p3: Packed_Raised
|
||||
|
||||
@(private="file")
|
||||
swap_raised :: proc(p: ^Packed_Raised, x: #simd[4]f32) -> #simd[4]f32 {
|
||||
y := p.inner.v
|
||||
p.inner.v = x
|
||||
return y
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_packed_field_min_align :: proc(t: ^testing.T) {
|
||||
p3.inner.v = {1, 2, 3, 4}
|
||||
|
||||
y := #force_no_inline swap_raised(&p3, {5, 6, 7, 8})
|
||||
testing.expect(t, simd.to_array(y) == [4]f32{1, 2, 3, 4})
|
||||
testing.expect(t, simd.to_array(p3.inner.v) == [4]f32{5, 6, 7, 8})
|
||||
}
|
||||
|
||||
|
||||
// by-reference type switch on a union field of a #packed struct;
|
||||
// the bound case variable inherits the field GEP's is-packed metadata;
|
||||
// accesses through it must not assume the variant type alignment
|
||||
|
||||
Packed_Union :: union {
|
||||
#simd[4]f32,
|
||||
u8,
|
||||
}
|
||||
|
||||
Packed_With_Union :: struct #packed {
|
||||
_: u8,
|
||||
u: Packed_Union, // offset 1
|
||||
}
|
||||
|
||||
Packed_Union_Helper :: struct {
|
||||
force: #simd[4]f32, // force align to 16
|
||||
_: u8,
|
||||
p: Packed_With_Union, // offset 17, union at 18
|
||||
}
|
||||
|
||||
@(export)
|
||||
p4: Packed_Union_Helper
|
||||
|
||||
@(private="file")
|
||||
swap_variant_ref :: proc(p: ^Packed_With_Union, x: #simd[4]f32) -> #simd[4]f32 {
|
||||
#partial switch &v in p.u {
|
||||
case #simd[4]f32:
|
||||
y := v
|
||||
v = x
|
||||
return y
|
||||
}
|
||||
return {}
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_packed_field_union_type_switch_ref :: proc(t: ^testing.T) {
|
||||
p4.p.u = #simd[4]f32{1, 2, 3, 4}
|
||||
|
||||
y := #force_no_inline swap_variant_ref(&p4.p, {5, 6, 7, 8})
|
||||
testing.expect(t, simd.to_array(y) == [4]f32{1, 2, 3, 4})
|
||||
|
||||
v, ok := p4.p.u.(#simd[4]f32)
|
||||
testing.expect(t, ok)
|
||||
testing.expect(t, simd.to_array(v) == [4]f32{5, 6, 7, 8})
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package test_internal
|
||||
|
||||
import "core:testing"
|
||||
|
||||
@(test)
|
||||
transmute_array_like_to_simd_and_u128 :: proc(t: ^testing.T) {
|
||||
Named_Lane :: enum { A, B, C, D }
|
||||
Item :: struct {
|
||||
tag: u32,
|
||||
arr: [4]f32, // offs 4
|
||||
e: [Named_Lane]u32, // offs 20
|
||||
w: [2]u64,
|
||||
}
|
||||
|
||||
items := make([]Item, 2)
|
||||
defer delete(items)
|
||||
items[0] = {1, {1, 2, 3, 4}, {.A = 5, .B = 6, .C = 7, .D = 8}, {9, 10}}
|
||||
it := &items[0]
|
||||
testing.expect_value(t, transmute([4]f32)transmute(#simd[4]f32)it.arr, [4]f32{1, 2, 3, 4})
|
||||
testing.expect_value(t, transmute([4]u32)transmute(#simd[4]u32)it.e, [4]u32{5, 6, 7, 8})
|
||||
testing.expect_value(t, transmute(u128)it.e, u128(8)<<96 | u128(7)<<64 | u128(6)<<32 | 5)
|
||||
testing.expect_value(t, transmute(u128)it.w, u128(10)<<64 | 9)
|
||||
|
||||
bytes: [32]u8
|
||||
for &b, i in bytes {
|
||||
b = u8(i)
|
||||
}
|
||||
odd := (^[16]u8)(&bytes[1])
|
||||
testing.expect_value(t, transmute(u128)odd^, u128(0x10_0f_0e_0d_0c_0b_0a_09_08_07_06_05_04_03_02_01))
|
||||
|
||||
local := [4]f32{1, 2, 3, 4}
|
||||
testing.expect_value(t, transmute([4]f32)transmute(#simd[4]f32)local, [4]f32{1, 2, 3, 4})
|
||||
local_e := [Named_Lane]u32{.A = 1, .B = 2, .C = 3, .D = 4}
|
||||
testing.expect_value(t, transmute(u128)local_e, u128(4)<<96 | u128(3)<<64 | u128(2)<<32 | 1)
|
||||
}
|
||||
Reference in new issue
Block a user