Conversation
a85899f to
a3d8dd1
Compare
| // There is no write, but without `MemoryEffect::Write`, the `PrintLn` is not lowered to masm. | ||
| // With `Read` only, `PrintLn` probably gets eliminated since it is not producing a result. | ||
| #[operand] | ||
| #[effects(MemoryEffect(MemoryEffect::Read, MemoryEffect::Write))] |
There was a problem hiding this comment.
Is there another way to prevent PrintLn getting eliminated? Using a fake Write is not ideal
There was a problem hiding this comment.
Create a new effect? I mean this operation produces a side effect that is handled in the debug executor (prints/logs/whatever).
There was a problem hiding this comment.
I would avoid adding a new effect for just this, and instead remove the effect annotation entirely - this will force analysis to be conservative with respect to this op (i.e. it cannot be presumed to be side-ffect free, and thus removable - and ops with effects cannot be reordered past it).
The effect mechanism is specifically there to opt-in operations to optimization, by declaring that the specific effects those ops have, and thus allowing the optimizer to make decisions about scheduling/reordering/etc. based on the details of those effects. In cases where we explicitly do not want the optimizer to be optimizing a specific op (and especially removing it due to perceived lack of use), it is best to avoid annotating effects at all.
a3d8dd1 to
7965460
Compare
greenhat
left a comment
There was a problem hiding this comment.
Looking good! Please see my notes.
| // There is no write, but without `MemoryEffect::Write`, the `PrintLn` is not lowered to masm. | ||
| // With `Read` only, `PrintLn` probably gets eliminated since it is not producing a result. | ||
| #[operand] | ||
| #[effects(MemoryEffect(MemoryEffect::Read, MemoryEffect::Write))] |
There was a problem hiding this comment.
Create a new effect? I mean this operation produces a side effect that is handled in the debug executor (prints/logs/whatever).
| dialect = HirDialect, | ||
| implements(MemoryEffectOpInterface, OpPrinter) | ||
| )] | ||
| pub struct PrintLn { |
There was a problem hiding this comment.
Would it be crazy to think that we should consider a new dialect for this operation?
There was a problem hiding this comment.
My thought was to place it in the debug dialect that @djolertrk created/was going to create - but since that isn't present in next, I think it is fine to put it in hir initially, and we can move it later.
|
|
||
| /// Emit a trace marker for `hir.println`, leaving the operands intact until after the trace. | ||
| pub fn println(&mut self, span: SourceSpan) { | ||
| // Leave them on the stack so debug executor can read them. |
There was a problem hiding this comment.
I think this comment is misleading - when we emit ops, the input operands are semantically consumed by the operation we emit as MASM - but in cases like this, where there is no actual op that consumes the operands (in fact, trace is not an op at all, but a decorator), it is the drop drop that acts as the "real" operation consuming the operands.
So it isn't that we are leaving them on the stack - we aren't - we are consuming the operands via drop drop below. The reason why we don't pop the operands here like we do elsewhere, is because we want to let the call to dropn(2) handle it.
There was a problem hiding this comment.
I would suggest we also define the println! macro, as follows:
#[macro_export]
macro_rules! println {
($message:literal) => {{
$crate::debug::println($message);
}};
($format:literal, $($arg:tt),+) => {{
let message = ::alloc::format!($format, $($arg),*);
$crate::debug::println(&message);
}}
}Then in downstream crates of the SDK, we can do stuff like:
use miden_sdk::println;
println!("hello world");
# or
println!("{greeting} {}", greeting = "hello", "world");| unimplemented!("debug intrinsics are only available when targeting the Miden VM") | ||
| } | ||
|
|
||
| /// Prints the string pointed to by `ptr` in the debug executor. |
There was a problem hiding this comment.
Functions with multiple cfg-dependent definitions should be defined next to each other when possible.
bitwalker
left a comment
There was a problem hiding this comment.
Looks good overall! I left a few notes on changes I'd like to make, but once this is ready, we'll merge it after miden-debug ships support for it.
Context: #1024
Adds trace-based println support across the compiler pipeline:
hirPrintLnop and aMASM TRACE_PRINT_LNeventPrintLnthat managesaddr, sizeof the string on the operand stack, such that evaluator and debug executor can pick it up.println(&str)helper to generate that op from Rust.lines.
Companion PR in
miden-debug: 54TODO
miden-debugGH dependency once changes inmiden-debugwere released