Skip to content

Commit

Permalink
Merge pull request #398 from 0xPolygonMiden/greenhat/i363-felt-intrin…
Browse files Browse the repository at this point in the history
…sics

[1/x] feature(frontend): implement felt intrinsics
  • Loading branch information
bitwalker authored Feb 14, 2025
2 parents 83b34b3 + 84d0205 commit c582ced
Show file tree
Hide file tree
Showing 11 changed files with 350 additions and 281 deletions.
41 changes: 23 additions & 18 deletions frontend-wasm2/src/code_translator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use wasmparser::{MemArg, Operator};

use crate::{
error::WasmResult,
intrinsics::{convert_intrinsics_call, is_miden_intrinsics_module},
miden_abi::{is_miden_abi_module, transform::transform_miden_abi_call},
module::{
func_translation_state::{ControlStackFrame, ElseData, FuncTranslationState},
Expand Down Expand Up @@ -675,15 +676,16 @@ fn translate_call(
span: SourceSpan,
diagnostics: &DiagnosticsHandler,
) -> WasmResult<()> {
let func_ref = module_state.get_direct_func(function_index, diagnostics)?;
let sig = func_ref.borrow().signature().clone();
let num_args = sig.params().len();
let args = func_state.peekn(num_args);
// if is_miden_intrinsics_module(func_id.module.as_symbol()) {
// let results = convert_intrinsics_call(func_id, args, builder, span);
// func_state.popn(num_wasm_args);
// func_state.pushn(&results);
// } else if is_miden_abi_module(func_id.module.as_symbol()) {
let defined_func = module_state.get_direct_func(function_index, diagnostics)?;
let wasm_sig = defined_func.signature.clone();
let num_wasm_args = wasm_sig.params().len();
let args = func_state.peekn(num_wasm_args);
if is_miden_intrinsics_module(defined_func.wasm_id.module.as_symbol()) {
let results = convert_intrinsics_call(&defined_func, args, builder, span)?;
func_state.popn(num_wasm_args);
func_state.pushn(&results);
}
// else if is_miden_abi_module(func_id.module.as_symbol()) {
// // Miden SDK function call, transform the call to the Miden ABI if needed
// let results = transform_miden_abi_call(func_id, args, builder, span, diagnostics);
// assert_eq!(
Expand All @@ -702,15 +704,18 @@ fn translate_call(
// );
// func_state.popn(num_wasm_args);
// func_state.pushn(&results);
// } else { code below }

let exec = builder.ins().exec(func_ref, sig, args.to_vec(), span)?;
let borrow = exec.borrow();
let results = borrow.as_ref().results();
func_state.popn(num_args);
let result_vals: Vec<ValueRef> =
results.iter().map(|op_res| op_res.borrow().as_value_ref()).collect();
func_state.pushn(&result_vals);
else {
let func_ref = defined_func
.function_ref
.expect("expected DefinedFunction::function_ref to be set");
let exec = builder.ins().exec(func_ref, wasm_sig, args.to_vec(), span)?;
let borrow = exec.borrow();
let results = borrow.as_ref().results();
func_state.popn(num_wasm_args);
let result_vals: Vec<ValueRef> =
results.iter().map(|op_res| op_res.borrow().as_value_ref()).collect();
func_state.pushn(&result_vals);
}
Ok(())
}

Expand Down
239 changes: 119 additions & 120 deletions frontend-wasm2/src/intrinsics/felt.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::vec;

use midenc_hir::{FunctionIdent, InstBuilder, SourceSpan, Type::*, Value};
use midenc_hir2::ValueRef;
use midenc_dialect_hir::InstBuilder;
use midenc_hir2::{FunctionIdent, SourceSpan, Type, ValueRef};

use crate::module::function_builder_ext::FunctionBuilderExt;
use crate::{error::WasmResult, module::function_builder_ext::FunctionBuilderExt};

pub(crate) const MODULE_ID: &str = "intrinsics::felt";

Expand All @@ -13,121 +13,120 @@ pub(crate) fn convert_felt_intrinsics(
args: &[ValueRef],
builder: &mut FunctionBuilderExt<'_>,
span: SourceSpan,
) -> Vec<ValueRef> {
todo!()
// match func_id.function.as_symbol().as_str() {
// // Conversion operations
// "from_u64_unchecked" => {
// assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id);
// let inst = builder.ins().cast(args[0], Felt, span);
// vec![inst]
// }
// "from_u32" => {
// assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id);
// let inst = builder.ins().bitcast(args[0], Felt, span);
// vec![inst]
// }
// "as_u64" => {
// assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id);
// // we're casting to i64 instead of u64 because Wasm doesn't have u64
// // and this value will be used in Wasm ops or local vars that expect i64
// let inst = builder.ins().cast(args[0], I64, span);
// vec![inst]
// }
// // Arithmetic operations
// "add" => {
// assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id);
// let inst = builder.ins().add_unchecked(args[0], args[1], span);
// vec![inst]
// }
// "sub" => {
// assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id);
// let inst = builder.ins().sub_unchecked(args[0], args[1], span);
// vec![inst]
// }
// "mul" => {
// assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id);
// let inst = builder.ins().mul_unchecked(args[0], args[1], span);
// vec![inst]
// }
// "div" => {
// assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id);
// let inst = builder.ins().div_unchecked(args[0], args[1], span);
// vec![inst]
// }
// "neg" => {
// assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id);
// let inst = builder.ins().neg(args[0], span);
// vec![inst]
// }
// "inv" => {
// assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id);
// let inst = builder.ins().inv(args[0], span);
// vec![inst]
// }
// "pow2" => {
// assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id);
// let inst = builder.ins().pow2(args[0], span);
// vec![inst]
// }
// "exp" => {
// assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id);
// let inst = builder.ins().exp(args[0], args[1], span);
// vec![inst]
// }
// // Comparison operations
// "eq" => {
// assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id);
// let inst = builder.ins().eq(args[0], args[1], span);
// let cast = builder.ins().cast(inst, I32, span);
// vec![cast]
// }
// "gt" => {
// assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id);
// let inst = builder.ins().gt(args[0], args[1], span);
// let cast = builder.ins().cast(inst, I32, span);
// vec![cast]
// }
// "ge" => {
// assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id);
// let inst = builder.ins().gte(args[0], args[1], span);
// let cast = builder.ins().cast(inst, I32, span);
// vec![cast]
// }
// "lt" => {
// assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id);
// let inst = builder.ins().lt(args[0], args[1], span);
// let cast = builder.ins().cast(inst, I32, span);
// vec![cast]
// }
// "le" => {
// assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id);
// let inst = builder.ins().lte(args[0], args[1], span);
// let cast = builder.ins().cast(inst, I32, span);
// vec![cast]
// }
// "is_odd" => {
// assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id);
// let inst = builder.ins().is_odd(args[0], span);
// let cast = builder.ins().cast(inst, I32, span);
// vec![cast]
// }
// // Assert operations
// "assert" => {
// assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id);
// builder.ins().assert(args[0], span);
// vec![]
// }
// "assertz" => {
// assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id);
// builder.ins().assertz(args[0], span);
// vec![]
// }
// "assert_eq" => {
// assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id);
// builder.ins().assert_eq(args[0], args[1], span);
// vec![]
// }
// _ => panic!("No felt op intrinsics found for {}", func_id),
// }
) -> WasmResult<Vec<ValueRef>> {
match func_id.function.as_symbol().as_str() {
// Conversion operations
"from_u64_unchecked" => {
assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id);
let inst = builder.ins().cast(args[0], Type::Felt, span)?;
Ok(vec![inst])
}
"from_u32" => {
assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id);
let inst = builder.ins().bitcast(args[0], Type::Felt, span)?;
Ok(vec![inst])
}
"as_u64" => {
assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id);
// we're casting to i64 instead of u64 because Wasm doesn't have u64
// and this value will be used in Wasm ops or local vars that expect i64
let inst = builder.ins().cast(args[0], Type::I64, span)?;
Ok(vec![inst])
}
// Arithmetic operations
"add" => {
assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id);
let inst = builder.ins().add_unchecked(args[0], args[1], span)?;
Ok(vec![inst])
}
"sub" => {
assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id);
let inst = builder.ins().sub_unchecked(args[0], args[1], span)?;
Ok(vec![inst])
}
"mul" => {
assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id);
let inst = builder.ins().mul_unchecked(args[0], args[1], span)?;
Ok(vec![inst])
}
"div" => {
assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id);
let inst = builder.ins().div(args[0], args[1], span)?;
Ok(vec![inst])
}
"neg" => {
assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id);
let inst = builder.ins().neg(args[0], span)?;
Ok(vec![inst])
}
"inv" => {
assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id);
let inst = builder.ins().inv(args[0], span)?;
Ok(vec![inst])
}
"pow2" => {
assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id);
let inst = builder.ins().pow2(args[0], span)?;
Ok(vec![inst])
}
"exp" => {
assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id);
let inst = builder.ins().exp(args[0], args[1], span)?;
Ok(vec![inst])
}
// Comparison operations
"eq" => {
assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id);
let inst = builder.ins().eq(args[0], args[1], span)?;
let cast = builder.ins().cast(inst, Type::I32, span)?;
Ok(vec![cast])
}
"gt" => {
assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id);
let inst = builder.ins().gt(args[0], args[1], span)?;
let cast = builder.ins().cast(inst, Type::I32, span)?;
Ok(vec![cast])
}
"ge" => {
assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id);
let inst = builder.ins().gte(args[0], args[1], span)?;
let cast = builder.ins().cast(inst, Type::I32, span)?;
Ok(vec![cast])
}
"lt" => {
assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id);
let inst = builder.ins().lt(args[0], args[1], span)?;
let cast = builder.ins().cast(inst, Type::I32, span)?;
Ok(vec![cast])
}
"le" => {
assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id);
let inst = builder.ins().lte(args[0], args[1], span)?;
let cast = builder.ins().cast(inst, Type::I32, span)?;
Ok(vec![cast])
}
"is_odd" => {
assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id);
let inst = builder.ins().is_odd(args[0], span)?;
let cast = builder.ins().cast(inst, Type::I32, span)?;
Ok(vec![cast])
}
// Assert operations
"assert" => {
assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id);
builder.ins().assert(args[0], span);
Ok(vec![])
}
"assertz" => {
assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id);
builder.ins().assertz(args[0], span);
Ok(vec![])
}
"assert_eq" => {
assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id);
builder.ins().assert_eq(args[0], args[1], span);
Ok(vec![])
}
_ => panic!("No felt op intrinsics found for {}", func_id),
}
}
56 changes: 27 additions & 29 deletions frontend-wasm2/src/intrinsics/mem.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use midenc_hir::{
AbiParam, FunctionIdent, FunctionType, InstBuilder, Signature, SourceSpan, Type, Value,
};
use midenc_hir2::ValueRef;
use midenc_dialect_hir::InstBuilder;
use midenc_hir2::{AbiParam, FunctionIdent, FunctionType, Signature, SourceSpan, Type, ValueRef};

use crate::module::function_builder_ext::FunctionBuilderExt;
use crate::{
error::WasmResult,
module::{
function_builder_ext::FunctionBuilderExt, module_translation_state::CallableFunction,
},
};

pub const MODULE_ID: &str = "intrinsics::mem";

Expand All @@ -29,31 +32,26 @@ fn signature(func_id: &FunctionIdent) -> Signature {

/// Convert a call to a memory intrinsic function
pub(crate) fn convert_mem_intrinsics(
func_id: FunctionIdent,
def_func: &CallableFunction,
args: &[ValueRef],
builder: &mut FunctionBuilderExt,
span: SourceSpan,
) -> Vec<ValueRef> {
todo!()
// match func_id.function.as_symbol().as_str() {
// HEAP_BASE => {
// assert_eq!(args.len(), 0, "{} takes no arguments", func_id);
// if builder
// .data_flow_graph()
// .get_import_by_name(func_id.module, func_id.function)
// .is_none()
// {
// let signature = signature(&func_id);
// let _ = builder.data_flow_graph_mut().import_function(
// func_id.module,
// func_id.function,
// signature,
// );
// }
// let call = builder.ins().exec(func_id, &[], span);
// let value = builder.data_flow_graph().first_result(call);
// vec![value]
// }
// _ => panic!("No allowed memory intrinsics found for {}", func_id),
// }
) -> WasmResult<Vec<ValueRef>> {
match def_func.wasm_id.function.as_symbol().as_str() {
HEAP_BASE => {
assert_eq!(args.len(), 0, "{} takes no arguments", def_func.wasm_id);

let func_ref = def_func.function_ref.unwrap_or_else(|| {
panic!("expected DefinedFunction::function_ref to be set for {}", def_func.wasm_id)
});
let exec =
builder.ins().exec(func_ref, def_func.signature.clone(), args.to_vec(), span)?;
let borrow = exec.borrow();
let results = borrow.as_ref().results();
let result_vals: Vec<ValueRef> =
results.iter().map(|op_res| op_res.borrow().as_value_ref()).collect();
Ok(result_vals)
}
_ => panic!("No allowed memory intrinsics found for {}", def_func.wasm_id),
}
}
Loading

0 comments on commit c582ced

Please sign in to comment.