Skip to content

Commit 161abc2

Browse files
committed
test: parametrize the rountrip generation for memory intrinsics store/load tests
Add tests for i8, u8, i16, u16 types.
1 parent 5c5fae4 commit 161abc2

File tree

1 file changed

+91
-150
lines changed

1 file changed

+91
-150
lines changed

codegen/masm/src/tests.rs

Lines changed: 91 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#![allow(unused_imports)]
2-
use std::sync::Arc;
2+
use std::{fmt::Display, sync::Arc};
33

44
use midenc_hir::{
55
self as hir,
@@ -500,83 +500,18 @@ fn i32_checked_neg() {
500500
harness.invoke(neg, &[min]).expect("execution failed");
501501
}
502502

503-
#[test]
504-
fn codegen_mem_store_sw_load_sw() {
505-
let context = TestContext::default();
506-
let mut builder = ProgramBuilder::new(&context.session.diagnostics);
507-
let mut mb = builder.module("test");
508-
let id = {
509-
let mut fb = mb
510-
.function(
511-
"store_load_sw",
512-
Signature::new(
513-
[AbiParam::new(Type::U32), AbiParam::new(Type::U32)],
514-
[AbiParam::new(Type::U32)],
515-
),
516-
)
517-
.expect("unexpected symbol conflict");
518-
let entry = fb.current_block();
519-
let (ptr_u32, value) = {
520-
let args = fb.block_params(entry);
521-
(args[0], args[1])
522-
};
523-
let ptr = fb.ins().inttoptr(ptr_u32, Type::Ptr(Type::U32.into()), SourceSpan::UNKNOWN);
524-
fb.ins().store(ptr, value, SourceSpan::UNKNOWN);
525-
let loaded_value = fb.ins().load(ptr, SourceSpan::UNKNOWN);
526-
fb.ins().ret(Some(loaded_value), SourceSpan::UNKNOWN);
527-
fb.build().expect("unexpected error building function")
528-
};
529-
530-
mb.build().expect("unexpected error constructing test module");
531-
532-
let program = builder.with_entrypoint(id).link().expect("failed to link program");
533-
534-
let mut compiler = MasmCompiler::new(&context.session);
535-
let program = compiler
536-
.compile(program)
537-
.expect("compilation failed")
538-
.unwrap_executable()
539-
.freeze();
540-
541-
// eprintln!("{}", program);
542-
543-
fn roundtrip(program: Arc<Program>, ptr: u32, value: u32) -> u32 {
544-
eprintln!("---------------------------------");
545-
eprintln!("testing store_sw/load_sw ptr: {ptr}, value: {value}");
546-
eprintln!("---------------------------------");
547-
let mut harness = TestByEmulationHarness::with_emulator_config(
548-
MEMORY_SIZE_VM_WORDS as usize,
549-
Emulator::DEFAULT_HEAP_START as usize,
550-
Emulator::DEFAULT_LOCALS_START as usize,
551-
true,
552-
);
553-
let mut stack = harness
554-
.execute_program(program.clone(), &[Felt::new(ptr as u64), Felt::new(value as u64)])
555-
.expect("execution failed");
556-
stack.pop().unwrap().as_int() as u32
557-
}
558-
559-
TestRunner::new(Config::with_cases(1024))
560-
.run(&(0u32..MEMORY_SIZE_BYTES - 4, any::<u32>()), move |(ptr, value)| {
561-
let out = roundtrip(program.clone(), ptr, value);
562-
prop_assert_eq!(out, value);
563-
Ok(())
564-
})
565-
.unwrap();
566-
}
567-
568-
#[test]
569-
fn codegen_mem_store_dw_load_dw() {
503+
fn roundtrip_store_t_load_t<T: ToCanonicalRepr + Display>(ty: Type) -> impl Fn(u32, T) -> T {
570504
let context = TestContext::default();
571505
let mut builder = ProgramBuilder::new(&context.session.diagnostics);
572506
let mut mb = builder.module("test");
507+
let type_name = ty.to_string();
573508
let id = {
574509
let mut fb = mb
575510
.function(
576-
"store_load_dw",
511+
format!("store_load_{type_name}").as_str(),
577512
Signature::new(
578-
[AbiParam::new(Type::U32), AbiParam::new(Type::U64)],
579-
[AbiParam::new(Type::U64)],
513+
[AbiParam::new(Type::U32), AbiParam::new(ty.clone())],
514+
[AbiParam::new(ty.clone())],
580515
),
581516
)
582517
.expect("unexpected symbol conflict");
@@ -585,7 +520,7 @@ fn codegen_mem_store_dw_load_dw() {
585520
let args = fb.block_params(entry);
586521
(args[0], args[1])
587522
};
588-
let ptr = fb.ins().inttoptr(ptr_u32, Type::Ptr(Type::U64.into()), SourceSpan::UNKNOWN);
523+
let ptr = fb.ins().inttoptr(ptr_u32, Type::Ptr(ty.into()), SourceSpan::UNKNOWN);
589524
fb.ins().store(ptr, value, SourceSpan::UNKNOWN);
590525
let loaded_value = fb.ins().load(ptr, SourceSpan::UNKNOWN);
591526
fb.ins().ret(Some(loaded_value), SourceSpan::UNKNOWN);
@@ -616,112 +551,104 @@ fn codegen_mem_store_dw_load_dw() {
616551

617552
eprintln!("{}", program);
618553

619-
fn roundtrip(program: Arc<Program>, ptr: u32, value: u64) -> u64 {
554+
move |ptr: u32, value: T| -> T {
620555
eprintln!("---------------------------------");
621-
eprintln!("testing store_dw/load_dw ptr: {ptr}, value: {value}");
556+
eprintln!("testing store {type_name}/load {type_name} ptr: {ptr}, value: {value}");
622557
eprintln!("---------------------------------");
623558
let mut harness = TestByEmulationHarness::with_emulator_config(
624559
MEMORY_SIZE_VM_WORDS as usize,
625560
Emulator::DEFAULT_HEAP_START as usize,
626561
Emulator::DEFAULT_LOCALS_START as usize,
627562
true,
628563
);
564+
629565
let mut args: SmallVec<[Felt; 4]> = smallvec!(Felt::new(ptr as u64));
630566
args.extend(value.canonicalize());
631567
let mut stack = harness.execute_program(program.clone(), &args).expect("execution failed");
632-
u64::from_stack(&mut stack)
568+
ToCanonicalRepr::from_stack(&mut stack)
633569
}
634-
635-
TestRunner::new(Config::with_cases(1024))
636-
.run(&(0u32..MEMORY_SIZE_BYTES - 4, any::<u64>()), move |(ptr, value)| {
637-
let out = roundtrip(program.clone(), ptr, value);
638-
prop_assert_eq!(out, value);
639-
Ok(())
640-
})
641-
.unwrap();
642570
}
643571

644572
#[test]
645-
fn codegen_mem_store_felt_load_felt() {
646-
let context = TestContext::default();
647-
let mut builder = ProgramBuilder::new(&context.session.diagnostics);
648-
let mut mb = builder.module("test");
649-
let id = {
650-
let mut fb = mb
651-
.function(
652-
"store_load_felt",
653-
Signature::new(
654-
[AbiParam::new(Type::U32), AbiParam::new(Type::Felt)],
655-
[AbiParam::new(Type::Felt)],
656-
),
657-
)
658-
.expect("unexpected symbol conflict");
659-
let entry = fb.current_block();
660-
let (ptr_u32, value) = {
661-
let args = fb.block_params(entry);
662-
(args[0], args[1])
663-
};
664-
let ptr = fb.ins().inttoptr(ptr_u32, Type::Ptr(Type::Felt.into()), SourceSpan::UNKNOWN);
665-
fb.ins().store(ptr, value, SourceSpan::UNKNOWN);
666-
let loaded_value = fb.ins().load(ptr, SourceSpan::UNKNOWN);
667-
fb.ins().ret(Some(loaded_value), SourceSpan::UNKNOWN);
668-
fb.build().expect("unexpected error building function")
669-
};
670-
671-
mb.build().expect("unexpected error constructing test module");
672-
673-
let program = builder.with_entrypoint(id).link().expect("failed to link program");
674-
675-
let ir_module = program
676-
.modules()
677-
.iter()
678-
.take(1)
679-
.collect::<Vec<&midenc_hir::Module>>()
680-
.first()
681-
.expect("no module in IR program")
682-
.to_string();
683-
684-
eprintln!("{}", ir_module.as_str());
685-
686-
let mut compiler = MasmCompiler::new(&context.session);
687-
let program = compiler
688-
.compile(program)
689-
.expect("compilation failed")
690-
.unwrap_executable()
691-
.freeze();
692-
693-
eprintln!("{}", program);
694-
695-
fn roundtrip(program: Arc<Program>, ptr: u32, value: Felt) -> Felt {
696-
eprintln!("---------------------------------");
697-
eprintln!("testing store_felt/load_felt ptr: {ptr}, value: {value}");
698-
eprintln!("---------------------------------");
699-
let mut harness = TestByEmulationHarness::with_emulator_config(
700-
MEMORY_SIZE_VM_WORDS as usize,
701-
Emulator::DEFAULT_HEAP_START as usize,
702-
Emulator::DEFAULT_LOCALS_START as usize,
703-
true,
704-
);
705-
let mut stack = harness
706-
.execute_program(program.clone(), &[Felt::new(ptr as u64), value])
707-
.expect("execution failed");
708-
stack.pop().unwrap()
709-
}
710-
573+
fn codegen_mem_store_load_felt() {
574+
let roundtrip = roundtrip_store_t_load_t::<Felt>(Type::Felt);
711575
TestRunner::new(Config::with_cases(1024))
712576
.run(
713577
&(0u32..(MEMORY_SIZE_BYTES / MIN_ALIGN - 1), (0u64..u64::MAX).prop_map(Felt::new)),
714578
move |(word_ptr, value)| {
715579
// a felt memory pointer must be naturally aligned, i.e. a multiple of MIN_ALIGN
716580
let ptr = word_ptr * MIN_ALIGN;
717-
let out = roundtrip(program.clone(), ptr, value);
581+
let out = roundtrip(ptr, value);
718582
prop_assert_eq!(out, value);
719583
Ok(())
720584
},
721585
)
722586
.unwrap();
723587
}
724588

589+
#[test]
590+
fn codegen_mem_store_load_u32() {
591+
let roundtrip = roundtrip_store_t_load_t::<u32>(Type::U32);
592+
TestRunner::new(Config::with_cases(1024))
593+
.run(&(0u32..MEMORY_SIZE_BYTES - 4, any::<u32>()), move |(ptr, value)| {
594+
let out = roundtrip(ptr, value);
595+
prop_assert_eq!(out, value);
596+
Ok(())
597+
})
598+
.unwrap();
599+
}
600+
601+
#[test]
602+
fn codegen_mem_store_load_i32() {
603+
let roundtrip = roundtrip_store_t_load_t::<i32>(Type::I32);
604+
TestRunner::new(Config::with_cases(1024))
605+
.run(&(0u32..MEMORY_SIZE_BYTES - 4, any::<i32>()), move |(ptr, value)| {
606+
let out = roundtrip(ptr, value);
607+
prop_assert_eq!(out, value);
608+
Ok(())
609+
})
610+
.unwrap();
611+
}
612+
613+
#[test]
614+
fn codegen_mem_store_load_u64() {
615+
let roundtrip = roundtrip_store_t_load_t::<u64>(Type::U64);
616+
TestRunner::new(Config::with_cases(1024))
617+
.run(&(0u32..MEMORY_SIZE_BYTES - 4, any::<u64>()), move |(ptr, value)| {
618+
let out = roundtrip(ptr, value);
619+
prop_assert_eq!(out, value);
620+
Ok(())
621+
})
622+
.unwrap();
623+
}
624+
625+
#[test]
626+
fn codegen_mem_store_load_i64() {
627+
let roundtrip = roundtrip_store_t_load_t::<i64>(Type::I64);
628+
TestRunner::new(Config::with_cases(1024))
629+
.run(&(0u32..MEMORY_SIZE_BYTES - 4, any::<i64>()), move |(ptr, value)| {
630+
let out = roundtrip(ptr, value);
631+
prop_assert_eq!(out, value);
632+
Ok(())
633+
})
634+
.unwrap();
635+
}
636+
637+
#[test]
638+
fn codegen_mem_store_load_u8() {
639+
let roundtrip = roundtrip_store_t_load_t(Type::U8);
640+
assert_eq!(roundtrip(0, 1), 1);
641+
// TestRunner::new(Config::with_cases(32))
642+
// .run(&(0u32..MEMORY_SIZE_BYTES - 4, any::<u8>()), move |(ptr, value)| {
643+
// let out = roundtrip(ptr, value);
644+
// prop_assert_eq!(out, value);
645+
// Ok(())
646+
// })
647+
// .unwrap();
648+
}
649+
650+
// TODO: cover i8, u16, i16 cases
651+
725652
#[allow(unused)]
726653
macro_rules! proptest_unary_numeric_op {
727654
($ty_name:ident :: $op:ident, $ty:ty => $ret:ty, $rust_op:ident) => {
@@ -965,6 +892,20 @@ impl ToCanonicalRepr for i128 {
965892
}
966893
}
967894

895+
impl ToCanonicalRepr for Felt {
896+
fn ir_type() -> Type {
897+
Type::Felt
898+
}
899+
900+
fn canonicalize(self) -> SmallVec<[Felt; 4]> {
901+
smallvec![self]
902+
}
903+
904+
fn from_stack(stack: &mut OperandStack<Felt>) -> Self {
905+
stack.pop().unwrap()
906+
}
907+
}
908+
968909
proptest! {
969910
#![proptest_config(ProptestConfig { cases: 1000, failure_persistence: None, ..Default::default() })]
970911

0 commit comments

Comments
 (0)