Skip to content

Commit 48f06f1

Browse files
authored
Merge pull request #627 from 0xMiden/greenhat/i626-advice-map-sdk
Advice map loading in Miden SDK
2 parents 7c128d1 + d236627 commit 48f06f1

59 files changed

Lines changed: 2745 additions & 196 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#! ADV_PUSH_MAPVALN: Pushes a list of field elements onto the advice stack.
2+
#! The list is looked up in the advice map using `key` as the key.
3+
#!
4+
#! Stack Input: [key3, key2, key1, key0, ...]
5+
#! Stack Output: [num_elements, ...] (returns the number of elements pushed)
6+
#!
7+
#! The key is a Word (4 field elements) used to lookup values in the advice map
8+
export.adv_push_mapvaln
9+
# Stack: [key3, key2, key1, key0, ...]
10+
11+
# Call the VM instruction to push values from advice map
12+
adv.push_mapvaln
13+
# Stack: [key3, key2, key1, key0, ...]
14+
# Side effect: [n, ele1, ele2, ...] pushed to advice stack where n is the count
15+
16+
# Drop the key word from the stack
17+
dropw
18+
# Stack: [...]
19+
20+
# The adv.push_mapvaln instruction pushes the count on top of the advice stack
21+
# We need to pop it from the advice stack to return it
22+
# Note: The advice stack now has [ele1, ele2, ...] with count removed
23+
adv_push.1
24+
# Stack: [num_elements, ...]
25+
end

codegen/masm/src/intrinsics.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ pub const I32_INTRINSICS_MODULE_NAME: &str = "intrinsics::i32";
88
pub const I64_INTRINSICS_MODULE_NAME: &str = "intrinsics::i64";
99
pub const MEM_INTRINSICS_MODULE_NAME: &str = "intrinsics::mem";
1010
pub const CRYPTO_INTRINSICS_MODULE_NAME: &str = "intrinsics::crypto";
11+
pub const ADVICE_INTRINSICS_MODULE_NAME: &str = "intrinsics::advice";
1112

12-
pub const INTRINSICS_MODULE_NAMES: [&str; 4] = [
13+
pub const INTRINSICS_MODULE_NAMES: [&str; 5] = [
1314
I32_INTRINSICS_MODULE_NAME,
1415
I64_INTRINSICS_MODULE_NAME,
1516
MEM_INTRINSICS_MODULE_NAME,
1617
CRYPTO_INTRINSICS_MODULE_NAME,
18+
ADVICE_INTRINSICS_MODULE_NAME,
1719
];
1820

1921
const I32_INTRINSICS: &str =
@@ -24,9 +26,11 @@ const MEM_INTRINSICS: &str =
2426
include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/intrinsics/mem.masm"));
2527
const CRYPTO_INTRINSICS: &str =
2628
include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/intrinsics/crypto.masm"));
29+
const ADVICE_INTRINSICS: &str =
30+
include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/intrinsics/advice.masm"));
2731

2832
/// This is a mapping of intrinsics module name to the raw MASM source for that module
29-
const INTRINSICS: [(&str, &str, &str); 4] = [
33+
const INTRINSICS: [(&str, &str, &str); 5] = [
3034
(
3135
I32_INTRINSICS_MODULE_NAME,
3236
I32_INTRINSICS,
@@ -47,6 +51,11 @@ const INTRINSICS: [(&str, &str, &str); 4] = [
4751
CRYPTO_INTRINSICS,
4852
concat!(env!("CARGO_MANIFEST_DIR"), "/intrinsics/crypto.masm"),
4953
),
54+
(
55+
ADVICE_INTRINSICS_MODULE_NAME,
56+
ADVICE_INTRINSICS,
57+
concat!(env!("CARGO_MANIFEST_DIR"), "/intrinsics/advice.masm"),
58+
),
5059
];
5160

5261
/// This helper loads the named module from the set of intrinsics modules defined in this crate.
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
use midenc_dialect_hir::HirOpBuilder;
2+
use midenc_hir::{
3+
dialects::builtin::FunctionRef,
4+
interner::{symbols, Symbol},
5+
Builder, FunctionType, SmallVec, SourceSpan, SymbolNameComponent, Type, ValueRef,
6+
};
7+
8+
use crate::{error::WasmResult, module::function_builder_ext::FunctionBuilderExt};
9+
10+
pub(crate) const MODULE_ID: &str = "intrinsics::advice";
11+
/// The module path prefix for advice intrinsics, not including the function name
12+
pub const MODULE_PREFIX: &[SymbolNameComponent] = &[
13+
SymbolNameComponent::Root,
14+
SymbolNameComponent::Component(symbols::Intrinsics),
15+
SymbolNameComponent::Component(symbols::Advice),
16+
];
17+
18+
/// Get the [FunctionType] of an advice intrinsic, if it is implemented as a function.
19+
///
20+
/// Returns `None` for intrinsics which are unknown, or correspond to native instructions.
21+
pub fn function_type(function: Symbol) -> Option<FunctionType> {
22+
match function.as_str() {
23+
"adv_push_mapvaln" => {
24+
// The WASM import signature: takes 4 f32 values (Word) and returns 1 f32
25+
let sig = FunctionType::new(
26+
midenc_hir::CallConv::Wasm,
27+
vec![
28+
Type::I32, // key0
29+
Type::I32, // key1
30+
Type::I32, // key2
31+
Type::I32, // key3
32+
],
33+
vec![Type::I32], // Returns number of elements pushed
34+
);
35+
Some(sig)
36+
}
37+
_ => None,
38+
}
39+
}
40+
41+
/// Convert a call to an advice intrinsic function into instruction(s)
42+
pub fn convert_advice_intrinsics<B: ?Sized + Builder>(
43+
function: Symbol,
44+
function_ref: Option<FunctionRef>,
45+
args: &[ValueRef],
46+
builder: &mut FunctionBuilderExt<'_, B>,
47+
span: SourceSpan,
48+
) -> WasmResult<SmallVec<[ValueRef; 1]>> {
49+
let function_ref =
50+
function_ref.unwrap_or_else(|| panic!("expected '{function}' to have been declared"));
51+
52+
match function.as_str() {
53+
"adv_push_mapvaln" => {
54+
// The WASM import has 4 parameters (key0-3) and returns 1 f32
55+
assert_eq!(args.len(), 4, "{function} takes exactly four arguments (key0-3)");
56+
57+
let func = function_ref.borrow();
58+
let signature = func.signature().clone();
59+
drop(func);
60+
61+
// Call the function with all arguments
62+
// The intrinsics::io::adv_push_mapvaln function will be mapped to the MASM adv_push_mapvaln
63+
let exec = builder.exec(function_ref, signature, args.iter().copied(), span)?;
64+
65+
// Extract the return value from the exec operation
66+
let borrow = exec.borrow();
67+
let results = borrow.as_ref().results();
68+
let result_vals: SmallVec<[ValueRef; 1]> =
69+
results.iter().map(|op_res| op_res.borrow().as_value_ref()).collect();
70+
71+
// The function returns the number of elements pushed as i32
72+
Ok(result_vals)
73+
}
74+
_ => {
75+
panic!("unsupported io intrinsic: '{function}'")
76+
}
77+
}
78+
}

frontend/wasm/src/intrinsics/felt.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub(crate) const MODULE_ID: &str = "intrinsics::felt";
1212
pub(crate) const MODULE_PREFIX: &[SymbolNameComponent] = &[
1313
SymbolNameComponent::Root,
1414
SymbolNameComponent::Component(symbols::Intrinsics),
15-
SymbolNameComponent::Component(symbols::Felt),
15+
SymbolNameComponent::Component(symbols::FeltModule),
1616
];
1717

1818
/// Convert a call to a felt op intrinsic function into instruction(s)

frontend/wasm/src/intrinsics/intrinsic.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use midenc_hir::{
44
FunctionType, SymbolNameComponent, SymbolPath, Type,
55
};
66

7-
use super::{crypto, debug, felt, mem};
7+
use super::{advice, crypto, debug, felt, mem};
88

99
/// Error raised when an attempt is made to use or load an unrecognized intrinsic
1010
#[derive(Debug, thiserror::Error, Diagnostic)]
@@ -26,6 +26,8 @@ pub enum Intrinsic {
2626
Felt(Symbol),
2727
/// A cryptographic intrinsic
2828
Crypto(Symbol),
29+
/// An advice intrinsic
30+
Advice(Symbol),
2931
}
3032

3133
/// Attempt to recognize an intrinsic function from the given [SymbolPath].
@@ -62,8 +64,9 @@ impl TryFrom<&SymbolPath> for Intrinsic {
6264
match kind {
6365
symbols::Debug => Ok(Self::Debug(function)),
6466
symbols::Mem => Ok(Self::Mem(function)),
65-
symbols::Felt => Ok(Self::Felt(function)),
67+
symbols::FeltModule => Ok(Self::Felt(function)),
6668
symbols::Crypto => Ok(Self::Crypto(function)),
69+
symbols::Advice => Ok(Self::Advice(function)),
6770
_ => Err(UnknownIntrinsicError(path.clone())),
6871
}
6972
}
@@ -83,8 +86,9 @@ impl Intrinsic {
8386
match self {
8487
Self::Debug(_) => symbols::Debug,
8588
Self::Mem(_) => symbols::Mem,
86-
Self::Felt(_) => symbols::Felt,
89+
Self::Felt(_) => symbols::FeltModule,
8790
Self::Crypto(_) => symbols::Crypto,
91+
Self::Advice(_) => symbols::Advice,
8892
}
8993
}
9094

@@ -95,6 +99,7 @@ impl Intrinsic {
9599
Self::Mem(_) => SymbolPath::from_iter(mem::MODULE_PREFIX.iter().copied()),
96100
Self::Felt(_) => SymbolPath::from_iter(felt::MODULE_PREFIX.iter().copied()),
97101
Self::Crypto(_) => SymbolPath::from_iter(crypto::MODULE_PREFIX.iter().copied()),
102+
Self::Advice(_) => SymbolPath::from_iter(advice::MODULE_PREFIX.iter().copied()),
98103
}
99104
}
100105

@@ -104,7 +109,8 @@ impl Intrinsic {
104109
Self::Debug(function)
105110
| Self::Mem(function)
106111
| Self::Felt(function)
107-
| Self::Crypto(function) => *function,
112+
| Self::Crypto(function)
113+
| Self::Advice(function) => *function,
108114
}
109115
}
110116

@@ -138,6 +144,7 @@ impl Intrinsic {
138144
_ => None,
139145
}
140146
}
147+
Self::Advice(function) => advice::function_type(*function),
141148
}
142149
}
143150

@@ -150,6 +157,10 @@ impl Intrinsic {
150157
mem::function_type(*function).map(IntrinsicsConversionResult::FunctionType)
151158
}
152159
Self::Debug(_) | Self::Felt(_) => Some(IntrinsicsConversionResult::MidenVmOp),
160+
Self::Advice(_function) => self
161+
.function_type()
162+
.map(IntrinsicsConversionResult::FunctionType)
163+
.or(Some(IntrinsicsConversionResult::MidenVmOp)),
153164
// Crypto intrinsics are converted to function calls
154165
Self::Crypto(_function) => self
155166
.function_type()

frontend/wasm/src/intrinsics/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ mod intrinsic;
22

33
pub use self::intrinsic::*;
44

5+
pub mod advice;
56
pub mod crypto;
67
pub mod debug;
78
pub mod felt;
@@ -25,6 +26,7 @@ fn modules() -> &'static FxHashSet<SymbolPath> {
2526
s.insert(SymbolPath::from_iter(felt::MODULE_PREFIX.iter().copied()));
2627
s.insert(SymbolPath::from_iter(debug::MODULE_PREFIX.iter().copied()));
2728
s.insert(SymbolPath::from_iter(crypto::MODULE_PREFIX.iter().copied()));
29+
s.insert(SymbolPath::from_iter(advice::MODULE_PREFIX.iter().copied()));
2830
s
2931
});
3032
&MODULES
@@ -51,6 +53,9 @@ pub fn convert_intrinsics_call<B: ?Sized + Builder>(
5153
Intrinsic::Crypto(function) => {
5254
crypto::convert_crypto_intrinsics(function, function_ref, args, builder, span)
5355
}
56+
Intrinsic::Advice(function) => {
57+
advice::convert_advice_intrinsics(function, function_ref, args, builder, span)
58+
}
5459
}
5560
}
5661

frontend/wasm/src/miden_abi/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ pub fn recover_imported_masm_module(wasm_module_id: &str) -> Result<SymbolPath,
119119
Ok(SymbolPath::from_masm_module_id(intrinsics::debug::MODULE_ID))
120120
} else if wasm_module_id.starts_with("miden:core-intrinsics/intrinsics-crypto") {
121121
Ok(SymbolPath::from_masm_module_id(intrinsics::crypto::MODULE_ID))
122+
} else if wasm_module_id.starts_with("miden:core-intrinsics/intrinsics-advice") {
123+
Ok(SymbolPath::from_masm_module_id(intrinsics::advice::MODULE_ID))
122124
} else if wasm_module_id.starts_with("miden:core-base/account") {
123125
Ok(SymbolPath::from_masm_module_id(tx_kernel::account::MODULE_ID))
124126
} else if wasm_module_id.starts_with("miden:core-base/note") {

frontend/wasm/src/miden_abi/stdlib/mem.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub(crate) const MODULE_PREFIX: &[SymbolNameComponent] = &[
1515

1616
pub(crate) const PIPE_WORDS_TO_MEMORY: &str = "pipe_words_to_memory";
1717
pub(crate) const PIPE_DOUBLE_WORDS_TO_MEMORY: &str = "pipe_double_words_to_memory";
18+
pub(crate) const PIPE_PREIMAGE_TO_MEMORY: &str = "pipe_preimage_to_memory";
1819

1920
pub(crate) fn signatures() -> ModuleFunctionTypeMap {
2021
let mut m: ModuleFunctionTypeMap = Default::default();
@@ -52,6 +53,20 @@ pub(crate) fn signatures() -> ModuleFunctionTypeMap {
5253
],
5354
),
5455
);
56+
funcs.insert(
57+
Symbol::from(PIPE_PREIMAGE_TO_MEMORY),
58+
FunctionType::new(
59+
CallConv::Wasm,
60+
[
61+
Felt, // num_words
62+
I32, // write_ptr
63+
Felt, Felt, Felt, Felt, // COM (commitment)
64+
],
65+
[
66+
I32, // write_ptr'
67+
],
68+
),
69+
);
5570
m.insert(SymbolPath::from_iter(MODULE_PREFIX.iter().copied()), funcs);
5671
m
5772
}

frontend/wasm/src/miden_abi/transform.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ fn get_transform_strategy(path: &SymbolPath) -> Option<TransformStrategy> {
3030
stdlib::mem::PIPE_WORDS_TO_MEMORY | stdlib::mem::PIPE_DOUBLE_WORDS_TO_MEMORY => {
3131
Some(TransformStrategy::ReturnViaPointer)
3232
}
33+
stdlib::mem::PIPE_PREIMAGE_TO_MEMORY => Some(TransformStrategy::NoTransform),
3334
_ => None,
3435
},
3536
symbols::Crypto => match components.next()?.as_symbol_name() {

hir-symbol/src/symbols.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,10 @@ blake3 = {}
106106
crypto = {}
107107
debug = {}
108108
dsa = {}
109+
felt_module = { value = "felt" }
109110
hashes = {}
110111
intrinsics = {}
112+
advice = {}
111113
miden = {}
112114
mem = {}
113115
note = {}

0 commit comments

Comments
 (0)