Skip to content

Commit ee1d0c6

Browse files
authored
Get Kani to run on Apple M1 (#1323)
1 parent e2e786c commit ee1d0c6

File tree

7 files changed

+259
-93
lines changed

7 files changed

+259
-93
lines changed

kani-compiler/src/codegen_cprover_gotoc/compiler_interface.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,11 +229,14 @@ fn check_target(session: &Session) {
229229
let is_linux_target = session.target.llvm_target == "x86_64-unknown-linux-gnu";
230230
// Comparison with `x86_64-apple-darwin` does not work well because the LLVM
231231
// target may become `x86_64-apple-macosx10.7.0` (or similar) and fail
232-
let is_darwin_target = session.target.llvm_target.starts_with("x86_64-apple-");
232+
let is_x86_64_darwin_target = session.target.llvm_target.starts_with("x86_64-apple-");
233+
// looking for `arm64-apple-*`
234+
let is_arm64_darwin_target = session.target.llvm_target.starts_with("arm64-apple-");
233235

234-
if !is_linux_target && !is_darwin_target {
236+
if !is_linux_target && !is_x86_64_darwin_target && !is_arm64_darwin_target {
235237
let err_msg = format!(
236-
"Kani requires the target platform to be `x86_64-unknown-linux-gnu` or `x86_64-apple-darwin`, but it is {}",
238+
"Kani requires the target platform to be `x86_64-unknown-linux-gnu` or \
239+
`x86_64-apple-*` or `arm64-apple-*`, but it is {}",
237240
&session.target.llvm_target
238241
);
239242
session.err(&err_msg);

kani-compiler/src/codegen_cprover_gotoc/context/goto_ctx.rs

Lines changed: 89 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -350,10 +350,10 @@ impl MetadataLoader for GotocMetadataLoader {
350350

351351
/// Builds a machine model which is required by CBMC
352352
fn machine_model_from_session(sess: &Session) -> MachineModel {
353-
// The model assumes a `x86_64-unknown-linux-gnu` or `x86_64-apple-darwin`
354-
// platform. We check the target platform in function `check_target` from
355-
// src/kani-compiler/src/codegen_cprover_gotoc/compiler_interface.rs and
356-
// error if it is not any of the ones we expect.
353+
// The model assumes a `x86_64-unknown-linux-gnu`, `x86_64-apple-darwin`
354+
// or `aarch64-apple-darwin` platform. We check the target platform in function
355+
// `check_target` from src/kani-compiler/src/codegen_cprover_gotoc/compiler_interface.rs
356+
// and error if it is not any of the ones we expect.
357357
let architecture = &sess.target.arch;
358358
let pointer_width = sess.target.pointer_width.into();
359359

@@ -372,45 +372,90 @@ fn machine_model_from_session(sess: &Session) -> MachineModel {
372372

373373
// The values below cannot be obtained from the session so they are
374374
// hardcoded using standard ones for the supported platforms
375-
let bool_width = 8;
376-
let char_is_unsigned = false;
377-
let char_width = 8;
378-
let double_width = 64;
379-
let float_width = 32;
380-
let int_width = 32;
381-
let long_double_width = 128;
382-
let long_int_width = 64;
383-
let long_long_int_width = 64;
384-
let memory_operand_size = 4;
385-
let null_is_zero = true;
386-
let short_int_width = 16;
387-
let single_width = 32;
388-
let wchar_t_is_unsigned = false;
389-
let wchar_t_width = 32;
390-
let word_size = 32;
391-
let rounding_mode = RoundingMode::ToNearest;
392-
393-
MachineModel {
394-
architecture: architecture.to_string(),
395-
alignment,
396-
bool_width,
397-
char_is_unsigned,
398-
char_width,
399-
double_width,
400-
float_width,
401-
int_width,
402-
is_big_endian,
403-
long_double_width,
404-
long_int_width,
405-
long_long_int_width,
406-
memory_operand_size,
407-
null_is_zero,
408-
pointer_width,
409-
rounding_mode,
410-
short_int_width,
411-
single_width,
412-
wchar_t_is_unsigned,
413-
wchar_t_width,
414-
word_size,
375+
// see /tools/sizeofs/main.cpp.
376+
// For reference, the definition in CBMC:
377+
//https://github.com/diffblue/cbmc/blob/develop/src/util/config.cpp
378+
match architecture.as_ref() {
379+
"x86_64" => {
380+
let bool_width = 8;
381+
let char_is_unsigned = false;
382+
let char_width = 8;
383+
let double_width = 64;
384+
let float_width = 32;
385+
let int_width = 32;
386+
let long_double_width = 128;
387+
let long_int_width = 64;
388+
let long_long_int_width = 64;
389+
let short_int_width = 16;
390+
let single_width = 32;
391+
let wchar_t_is_unsigned = false;
392+
let wchar_t_width = 32;
393+
394+
MachineModel {
395+
architecture: architecture.to_string(),
396+
alignment,
397+
bool_width,
398+
char_is_unsigned,
399+
char_width,
400+
double_width,
401+
float_width,
402+
int_width,
403+
is_big_endian,
404+
long_double_width,
405+
long_int_width,
406+
long_long_int_width,
407+
memory_operand_size: int_width / 8,
408+
null_is_zero: true,
409+
pointer_width,
410+
rounding_mode: RoundingMode::ToNearest,
411+
short_int_width,
412+
single_width,
413+
wchar_t_is_unsigned,
414+
wchar_t_width,
415+
word_size: int_width,
416+
}
417+
}
418+
"aarch64" => {
419+
let bool_width = 8;
420+
let char_is_unsigned = true;
421+
let char_width = 8;
422+
let double_width = 64;
423+
let float_width = 32;
424+
let int_width = 32;
425+
let long_double_width = 64;
426+
let long_int_width = 64;
427+
let long_long_int_width = 64;
428+
let short_int_width = 16;
429+
let single_width = 32;
430+
let wchar_t_is_unsigned = false;
431+
let wchar_t_width = 32;
432+
433+
MachineModel {
434+
architecture: architecture.to_string(),
435+
alignment,
436+
bool_width,
437+
char_is_unsigned,
438+
char_width,
439+
double_width,
440+
float_width,
441+
int_width,
442+
is_big_endian,
443+
long_double_width,
444+
long_int_width,
445+
long_long_int_width,
446+
memory_operand_size: int_width / 8,
447+
null_is_zero: true,
448+
pointer_width,
449+
rounding_mode: RoundingMode::ToNearest,
450+
short_int_width,
451+
single_width,
452+
wchar_t_is_unsigned,
453+
wchar_t_width,
454+
word_size: int_width,
455+
}
456+
}
457+
_ => {
458+
panic!("Unsupported architecture: {}", architecture);
459+
}
415460
}
416461
}

tests/kani/Intrinsics/AlignOfVal/align_of_basic.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ enum MyEnum {
2323

2424
#[kani::proof]
2525
fn main() {
26+
#[cfg(target_arch = "x86_64")]
2627
unsafe {
2728
// Scalar types
2829
assert!(min_align_of_val(&0i8) == 1);
@@ -49,4 +50,31 @@ fn main() {
4950
assert!(min_align_of_val(&MyEnum::Variant) == 1);
5051
assert!(min_align_of_val(&CStruct { a: 0u8, b: 0i32 }) == 4);
5152
}
53+
#[cfg(target_arch = "aarch64")]
54+
unsafe {
55+
// Scalar types
56+
assert!(min_align_of_val(&0i8) == 1);
57+
assert!(min_align_of_val(&0i16) == 2);
58+
assert!(min_align_of_val(&0i32) == 4);
59+
assert!(min_align_of_val(&0i64) == 8);
60+
assert!(min_align_of_val(&0i128) == 16);
61+
assert!(min_align_of_val(&0isize) == 8);
62+
assert!(min_align_of_val(&0u8) == 1);
63+
assert!(min_align_of_val(&0u16) == 2);
64+
assert!(min_align_of_val(&0u32) == 4);
65+
assert!(min_align_of_val(&0u64) == 8);
66+
assert!(min_align_of_val(&0u128) == 16);
67+
assert!(min_align_of_val(&0usize) == 8);
68+
assert!(min_align_of_val(&0f32) == 4);
69+
assert!(min_align_of_val(&0f64) == 8);
70+
assert!(min_align_of_val(&false) == 1);
71+
assert!(min_align_of_val(&(0 as char)) == 4);
72+
// Compound types (tuple and array)
73+
assert!(min_align_of_val(&(0i32, 0i32)) == 4);
74+
assert!(min_align_of_val(&[0i32; 5]) == 4);
75+
// Custom data types (struct and enum)
76+
assert!(min_align_of_val(&MyStruct { val: 0u32 }) == 4);
77+
assert!(min_align_of_val(&MyEnum::Variant) == 1);
78+
assert!(min_align_of_val(&CStruct { a: 0u8, b: 0i32 }) == 4);
79+
}
5280
}

tests/kani/Intrinsics/AlignOfVal/align_of_fat_ptr.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ impl T for A {}
1818
fn check_align_simple() {
1919
let a = A { id: 0 };
2020
let t: &dyn T = &a;
21+
#[cfg(target_arch = "x86_64")]
2122
assert_eq!(align_of_val(t), 8);
23+
#[cfg(target_arch = "aarch64")]
24+
assert_eq!(align_of_val(t), 16);
2225
assert_eq!(align_of_val(&t), 8);
2326
}
2427

tests/kani/Intrinsics/ConstEval/min_align_of.rs

Lines changed: 53 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,27 +12,57 @@ enum MyEnum {}
1212

1313
#[kani::proof]
1414
fn main() {
15-
// Scalar types
16-
assert!(min_align_of::<i8>() == 1);
17-
assert!(min_align_of::<i16>() == 2);
18-
assert!(min_align_of::<i32>() == 4);
19-
assert!(min_align_of::<i64>() == 8);
20-
assert!(min_align_of::<i128>() == 8);
21-
assert!(min_align_of::<isize>() == 8);
22-
assert!(min_align_of::<u8>() == 1);
23-
assert!(min_align_of::<u16>() == 2);
24-
assert!(min_align_of::<u32>() == 4);
25-
assert!(min_align_of::<u64>() == 8);
26-
assert!(min_align_of::<u128>() == 8);
27-
assert!(min_align_of::<usize>() == 8);
28-
assert!(min_align_of::<f32>() == 4);
29-
assert!(min_align_of::<f64>() == 8);
30-
assert!(min_align_of::<bool>() == 1);
31-
assert!(min_align_of::<char>() == 4);
32-
// Compound types (tuple and array)
33-
assert!(min_align_of::<(i32, i32)>() == 4);
34-
assert!(min_align_of::<[i32; 5]>() == 4);
35-
// Custom data types (struct and enum)
36-
assert!(min_align_of::<MyStruct>() == 1);
37-
assert!(min_align_of::<MyEnum>() == 1);
15+
#[cfg(target_arch = "x86_64")]
16+
{
17+
// Scalar types
18+
assert!(min_align_of::<i8>() == 1);
19+
assert!(min_align_of::<i16>() == 2);
20+
assert!(min_align_of::<i32>() == 4);
21+
assert!(min_align_of::<i64>() == 8);
22+
assert!(min_align_of::<i128>() == 8);
23+
assert!(min_align_of::<isize>() == 8);
24+
assert!(min_align_of::<u8>() == 1);
25+
assert!(min_align_of::<u16>() == 2);
26+
assert!(min_align_of::<u32>() == 4);
27+
assert!(min_align_of::<u64>() == 8);
28+
assert!(min_align_of::<u128>() == 8);
29+
assert!(min_align_of::<usize>() == 8);
30+
assert!(min_align_of::<f32>() == 4);
31+
assert!(min_align_of::<f64>() == 8);
32+
assert!(min_align_of::<bool>() == 1);
33+
assert!(min_align_of::<char>() == 4);
34+
// Compound types (tuple and array)
35+
assert!(min_align_of::<(i32, i32)>() == 4);
36+
assert!(min_align_of::<[i32; 5]>() == 4);
37+
// Custom data types (struct and enum)
38+
assert!(min_align_of::<MyStruct>() == 1);
39+
assert!(min_align_of::<MyEnum>() == 1);
40+
}
41+
42+
#[cfg(target_arch = "aarch64")]
43+
{
44+
// Scalar types
45+
assert!(min_align_of::<i8>() == 1);
46+
assert!(min_align_of::<i16>() == 2);
47+
assert!(min_align_of::<i32>() == 4);
48+
assert!(min_align_of::<i64>() == 8);
49+
assert!(min_align_of::<i128>() == 16);
50+
assert!(min_align_of::<isize>() == 8);
51+
assert!(min_align_of::<u8>() == 1);
52+
assert!(min_align_of::<u16>() == 2);
53+
assert!(min_align_of::<u32>() == 4);
54+
assert!(min_align_of::<u64>() == 8);
55+
assert!(min_align_of::<u128>() == 16);
56+
assert!(min_align_of::<usize>() == 8);
57+
assert!(min_align_of::<f32>() == 4);
58+
assert!(min_align_of::<f64>() == 8);
59+
assert!(min_align_of::<bool>() == 1);
60+
assert!(min_align_of::<char>() == 4);
61+
// Compound types (tuple and array)
62+
assert!(min_align_of::<(i32, i32)>() == 4);
63+
assert!(min_align_of::<[i32; 5]>() == 4);
64+
// Custom data types (struct and enum)
65+
assert!(min_align_of::<MyStruct>() == 1);
66+
assert!(min_align_of::<MyEnum>() == 1);
67+
}
3868
}

tests/kani/Intrinsics/ConstEval/pref_align_of.rs

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,27 +12,56 @@ enum MyEnum {}
1212

1313
#[kani::proof]
1414
fn main() {
15-
// Scalar types
16-
assert!(unsafe { pref_align_of::<i8>() } == 1);
17-
assert!(unsafe { pref_align_of::<i16>() } == 2);
18-
assert!(unsafe { pref_align_of::<i32>() } == 4);
19-
assert!(unsafe { pref_align_of::<i64>() } == 8);
20-
assert!(unsafe { pref_align_of::<i128>() } == 8);
21-
assert!(unsafe { pref_align_of::<isize>() } == 8);
22-
assert!(unsafe { pref_align_of::<u8>() } == 1);
23-
assert!(unsafe { pref_align_of::<u16>() } == 2);
24-
assert!(unsafe { pref_align_of::<u32>() } == 4);
25-
assert!(unsafe { pref_align_of::<u64>() } == 8);
26-
assert!(unsafe { pref_align_of::<u128>() } == 8);
27-
assert!(unsafe { pref_align_of::<usize>() } == 8);
28-
assert!(unsafe { pref_align_of::<f32>() } == 4);
29-
assert!(unsafe { pref_align_of::<f64>() } == 8);
30-
assert!(unsafe { pref_align_of::<bool>() } == 1);
31-
assert!(unsafe { pref_align_of::<char>() } == 4);
32-
// Compound types (tuple and array)
33-
assert!(unsafe { pref_align_of::<(i32, i32)>() } == 8);
34-
assert!(unsafe { pref_align_of::<[i32; 5]>() } == 4);
35-
// Custom data types (struct and enum)
36-
assert!(unsafe { pref_align_of::<MyStruct>() } == 8);
37-
assert!(unsafe { pref_align_of::<MyEnum>() } == 1);
15+
#[cfg(target_arch = "x86_64")]
16+
{
17+
// Scalar types
18+
assert!(unsafe { pref_align_of::<i8>() } == 1);
19+
assert!(unsafe { pref_align_of::<i16>() } == 2);
20+
assert!(unsafe { pref_align_of::<i32>() } == 4);
21+
assert!(unsafe { pref_align_of::<i64>() } == 8);
22+
assert!(unsafe { pref_align_of::<i128>() } == 8);
23+
assert!(unsafe { pref_align_of::<isize>() } == 8);
24+
assert!(unsafe { pref_align_of::<u8>() } == 1);
25+
assert!(unsafe { pref_align_of::<u16>() } == 2);
26+
assert!(unsafe { pref_align_of::<u32>() } == 4);
27+
assert!(unsafe { pref_align_of::<u64>() } == 8);
28+
assert!(unsafe { pref_align_of::<u128>() } == 8);
29+
assert!(unsafe { pref_align_of::<usize>() } == 8);
30+
assert!(unsafe { pref_align_of::<f32>() } == 4);
31+
assert!(unsafe { pref_align_of::<f64>() } == 8);
32+
assert!(unsafe { pref_align_of::<bool>() } == 1);
33+
assert!(unsafe { pref_align_of::<char>() } == 4);
34+
// Compound types (tuple and array)
35+
assert!(unsafe { pref_align_of::<(i32, i32)>() } == 8);
36+
assert!(unsafe { pref_align_of::<[i32; 5]>() } == 4);
37+
// Custom data types (struct and enum)
38+
assert!(unsafe { pref_align_of::<MyStruct>() } == 8);
39+
assert!(unsafe { pref_align_of::<MyEnum>() } == 1);
40+
}
41+
#[cfg(target_arch = "aarch64")]
42+
{
43+
// Scalar types
44+
assert!(unsafe { pref_align_of::<i8>() } == 1);
45+
assert!(unsafe { pref_align_of::<i16>() } == 2);
46+
assert!(unsafe { pref_align_of::<i32>() } == 4);
47+
assert!(unsafe { pref_align_of::<i64>() } == 8);
48+
assert!(unsafe { pref_align_of::<i128>() } == 16);
49+
assert!(unsafe { pref_align_of::<isize>() } == 8);
50+
assert!(unsafe { pref_align_of::<u8>() } == 1);
51+
assert!(unsafe { pref_align_of::<u16>() } == 2);
52+
assert!(unsafe { pref_align_of::<u32>() } == 4);
53+
assert!(unsafe { pref_align_of::<u64>() } == 8);
54+
assert!(unsafe { pref_align_of::<u128>() } == 16);
55+
assert!(unsafe { pref_align_of::<usize>() } == 8);
56+
assert!(unsafe { pref_align_of::<f32>() } == 4);
57+
assert!(unsafe { pref_align_of::<f64>() } == 8);
58+
assert!(unsafe { pref_align_of::<bool>() } == 1);
59+
assert!(unsafe { pref_align_of::<char>() } == 4);
60+
// Compound types (tuple and array)
61+
assert!(unsafe { pref_align_of::<(i32, i32)>() } == 8);
62+
assert!(unsafe { pref_align_of::<[i32; 5]>() } == 4);
63+
// Custom data types (struct and enum)
64+
assert!(unsafe { pref_align_of::<MyStruct>() } == 8);
65+
assert!(unsafe { pref_align_of::<MyEnum>() } == 1);
66+
}
3867
}

0 commit comments

Comments
 (0)