Skip to content

Commit ae6c014

Browse files
committed
Fix SIMD projection mismatch for array-based SIMD types
Fixes the projection mismatch error that occurs when using the `simd_as` intrinsic with array-based SIMD types. The issue manifested when executing code with SIMD types that use array representations (e.g., `#[repr(simd)] struct V<T>([T; 2]))`, causing projection mismatches and "unsupported constructs" warnings. Resolves: #2264
1 parent 77e1d57 commit ae6c014

5 files changed

Lines changed: 236 additions & 0 deletions

File tree

kani-compiler/src/codegen_cprover_gotoc/codegen/place.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,37 @@ impl ProjectedPlace {
122122
{
123123
None
124124
}
125+
// SIMD types with array representation can have type mismatches during projection
126+
// because the GOTO representation is a vector type while the field access yields an array type.
127+
// This is expected for array-based SIMD types - see issue #2264.
128+
TyKind::RigidTy(RigidTy::Adt(def, _))
129+
if rustc_internal::internal(ctx.tcx, def).repr().simd() =>
130+
{
131+
// Check if the MIR type is an array (array-based SIMD representation)
132+
if matches!(t.kind(), TyKind::RigidTy(RigidTy::Array(..))) {
133+
// For array-based SIMD, expr_ty should be a vector and type_from_mir should be an array
134+
// Both represent the same data, just with different type representations
135+
if expr_ty.is_vector() || type_from_mir.is_vector() {
136+
None
137+
} else {
138+
Some((expr_ty, type_from_mir))
139+
}
140+
} else {
141+
Some((expr_ty, type_from_mir))
142+
}
143+
}
144+
TyKind::RigidTy(RigidTy::Array(..)) => {
145+
// Also handle when the type is an array that might be part of a SIMD structure
146+
// If both types are compatible in size and one is a vector, allow it
147+
if (expr_ty.is_vector() || type_from_mir.is_vector())
148+
&& expr_ty.sizeof(&ctx.symbol_table)
149+
== type_from_mir.sizeof(&ctx.symbol_table)
150+
{
151+
None
152+
} else {
153+
Some((expr_ty, type_from_mir))
154+
}
155+
}
125156
_ => Some((expr_ty, type_from_mir)),
126157
}
127158
} else {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Kani Rust Verifier
2+
CBMC version
3+
Reading GOTO program from file
4+
Generating GOTO Program
5+
Adding CPROVER library
6+
Removal of function pointers and virtual functions
7+
Generic Property Instrumentation
8+
Running with \d+ object bits
9+
Starting Bounded Model Checking
10+
Runtime Symex: \d+\.\d+s
11+
size of program expression: \d+ steps
12+
slicing removed \d+ assignments
13+
Generated \d+ VCC\(s\), \d+ remaining after simplification
14+
Runtime Postprocess Equation: \d+\.\d+(e-\d+)?s
15+
16+
RESULTS:
17+
VERIFICATION:- SUCCESSFUL
18+
19+
Verification Time: \d+\.\d+s
20+
21+
Manual Harness Summary:
22+
Complete - 1 successfully verified harnesses, 0 failures, 1 total.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright Kani Contributors
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
//
4+
// kani-flags: --no-assertion-reach-checks
5+
//
6+
//! Test for the `simd_as` intrinsic with array-based SIMD types.
7+
//! This test verifies that the intrinsic correctly handles type conversions
8+
//! between SIMD vectors with array-based representations, fixing issue #2264.
9+
10+
#![feature(repr_simd, core_intrinsics)]
11+
12+
use std::intrinsics::simd::simd_as;
13+
14+
#[derive(Copy)]
15+
#[repr(simd)]
16+
struct Vu32([u32; 2]);
17+
18+
impl Clone for Vu32 {
19+
fn clone(&self) -> Self {
20+
*self
21+
}
22+
}
23+
24+
#[derive(Copy)]
25+
#[repr(simd)]
26+
struct Vi32([i32; 2]);
27+
28+
impl Clone for Vi32 {
29+
fn clone(&self) -> Self {
30+
*self
31+
}
32+
}
33+
34+
#[kani::proof]
35+
fn test_simd_as_same_size() {
36+
unsafe {
37+
let u = Vu32([u32::MIN, u32::MAX]);
38+
let _i: Vi32 = simd_as(u);
39+
}
40+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright Kani Contributors
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
//! Fix for array-based SIMD projection mismatch issue #2264
4+
//!
5+
//! This test verifies that projection mismatches with array-based SIMD types
6+
//! no longer occur after the fix in the check_expr_typ_mismatch function.
7+
8+
#![feature(repr_simd)]
9+
10+
#[derive(Copy)]
11+
#[repr(simd)]
12+
struct ArraySimd<T>([T; 4]);
13+
14+
impl<T: Copy> Clone for ArraySimd<T> {
15+
fn clone(&self) -> Self {
16+
*self
17+
}
18+
}
19+
20+
#[kani::proof]
21+
fn test_array_simd_transmute() {
22+
let v = ArraySimd::<u32>([1, 2, 3, 4]);
23+
24+
// These operations previously caused projection mismatch errors
25+
// but should now work correctly
26+
unsafe {
27+
let _array: [u32; 4] = std::mem::transmute(v);
28+
let _same_size_different_type: ArraySimd<i32> = std::mem::transmute(v);
29+
let _same_size_different_scalar: ArraySimd<f32> = std::mem::transmute(v);
30+
}
31+
}
32+
33+
#[kani::proof]
34+
fn test_different_array_sizes() {
35+
let v2 = ArraySimd::<u16>([1, 2, 3, 4]);
36+
37+
// Test conversions to array types
38+
unsafe {
39+
let _arr2: [u16; 4] = std::mem::transmute(v2);
40+
41+
// Test same total bit size conversion (u16[4] = 64 bits = u32[2] = 64 bits)
42+
let v2_as_u32: [u32; 2] = std::mem::transmute(v2);
43+
assert_eq!(v2_as_u32.len(), 2);
44+
}
45+
}
46+
47+
#[kani::proof]
48+
fn test_field_access_equivalent() {
49+
let v = ArraySimd::<i32>([10, 20, 30, 40]);
50+
51+
// Test that we can access the underlying data
52+
unsafe {
53+
let arr: [i32; 4] = std::mem::transmute(v);
54+
assert_eq!(arr[0], 10);
55+
assert_eq!(arr[1], 20);
56+
assert_eq!(arr[2], 30);
57+
assert_eq!(arr[3], 40);
58+
}
59+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Copyright Kani Contributors
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
//! Test for projection mismatch fix with array-based SIMD types.
4+
//! This addresses the issue described in https://github.com/model-checking/kani/issues/2264
5+
//! where array-based SIMD types would cause projection mismatches during type conversions.
6+
7+
#![feature(repr_simd)]
8+
9+
#[derive(Copy)]
10+
#[repr(simd)]
11+
struct V<T>([T; 2]);
12+
13+
impl<T: Copy> Clone for V<T> {
14+
fn clone(&self) -> Self {
15+
*self
16+
}
17+
}
18+
19+
#[derive(Copy)]
20+
#[repr(simd)]
21+
struct VF32([f32; 2]);
22+
23+
impl Clone for VF32 {
24+
fn clone(&self) -> Self {
25+
*self
26+
}
27+
}
28+
29+
#[derive(Copy)]
30+
#[repr(simd)]
31+
struct VU32([u32; 2]);
32+
33+
impl Clone for VU32 {
34+
fn clone(&self) -> Self {
35+
*self
36+
}
37+
}
38+
39+
// Test transmute between SIMD types with same representation size
40+
// This should work with the projection fix for array-based SIMD types
41+
fn test_simd_transmute_same_size() {
42+
let v_f32 = VF32([1.0f32, 2.0f32]);
43+
let v_u32: VU32 = unsafe { std::mem::transmute(v_f32) };
44+
45+
// Verify the transmute worked by checking bit patterns
46+
let f32_bits = 1.0f32.to_bits();
47+
let u32_val = unsafe { std::mem::transmute::<VU32, [u32; 2]>(v_u32) };
48+
assert_eq!(u32_val[0], f32_bits);
49+
}
50+
51+
// Test field access on array-based SIMD (this was part of the original issue)
52+
fn test_simd_field_access() {
53+
let v = V::<u32>([u32::MIN, u32::MAX]);
54+
55+
// This should work without projection mismatch errors
56+
unsafe {
57+
let arr: [u32; 2] = std::mem::transmute(v);
58+
assert_eq!(arr[0], u32::MIN);
59+
assert_eq!(arr[1], u32::MAX);
60+
}
61+
}
62+
63+
#[kani::proof]
64+
fn verify_simd_transmute_same_size() {
65+
test_simd_transmute_same_size();
66+
}
67+
68+
#[kani::proof]
69+
fn verify_simd_field_access() {
70+
test_simd_field_access();
71+
}
72+
73+
#[kani::proof]
74+
fn verify_simd_clone() {
75+
let v = V::<i32>([42, -42]);
76+
let v2 = v.clone();
77+
78+
unsafe {
79+
let arr1: [i32; 2] = std::mem::transmute(v);
80+
let arr2: [i32; 2] = std::mem::transmute(v2);
81+
assert_eq!(arr1[0], arr2[0]);
82+
assert_eq!(arr1[1], arr2[1]);
83+
}
84+
}

0 commit comments

Comments
 (0)