Stream: compiler development

Topic: roc_dbg with roc build


view this post on Zulip Luke Boswell (Oct 17 2024 at 05:58):

I'm trying to use roc_dbg with roc build --no-link ... and I'm thinking roc must be throwing away the calls or something because it doesn't seem to be getting called. Just wondering if anyone knows what might be happening here?

view this post on Zulip Luke Boswell (Oct 17 2024 at 05:59):

Oh wait... I think I know

view this post on Zulip Luke Boswell (Oct 17 2024 at 05:59):

Relevant previous discussion https://roc.zulipchat.com/#narrow/channel/304641-ideas/topic/Roc.20cli.20workflow/near/451019991

view this post on Zulip Luke Boswell (Oct 17 2024 at 06:06):

At what stage do we remove the Dbg statements?

view this post on Zulip Luke Boswell (Oct 17 2024 at 06:08):

(deleted)

view this post on Zulip Luke Boswell (Oct 17 2024 at 06:16):

Found something that looks relevant in crates/compiler/mono/src/ir.rs Stmt::Dbg which is used to code gen the lowlevel call...

view this post on Zulip Luke Boswell (Oct 17 2024 at 06:36):

Ok, I got something working using this

diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs
index 83c7270350..15a737595a 100644
--- a/crates/cli/src/lib.rs
+++ b/crates/cli/src/lib.rs
@@ -845,7 +845,7 @@ pub fn build(
     } else {
         let backend_mode = match opt_level {
             OptLevel::Development => LlvmBackendMode::BinaryDev,
-            OptLevel::Normal | OptLevel::Size | OptLevel::Optimize => LlvmBackendMode::Binary,
+            OptLevel::Normal | OptLevel::Size | OptLevel::Optimize => LlvmBackendMode::BinaryDev,
         };

         CodeGenBackend::Llvm(backend_mode)

I'm thinking if we want to modify this behaviour in the cli so we always generate dbg statements, we'll need to see how that get's threaded through and what it affects.

Anyway... generating dbg statements when using roc build enables me to have the graphics platform "pause" when it hits a dbg statement and await for user input. I thought about more exciting things like a msgbox popup, but it seems raylib doesn't support multiple windows by default and this is ok to to test the idea.

Screenshot 2024-10-17 at 17.33.33.png

view this post on Zulip Brendan Hansknecht (Oct 17 2024 at 06:57):

The issues is that dbg and expect are linked in compiler lowering currently

view this post on Zulip Brendan Hansknecht (Oct 17 2024 at 06:58):

But expect is not wired up to the platform interface currently

view this post on Zulip Brendan Hansknecht (Oct 17 2024 at 06:58):

So it requires running through the roc executable to function

view this post on Zulip Brendan Hansknecht (Oct 17 2024 at 06:59):

This does not work with roc build, so it is set to be stripped out.

view this post on Zulip Brendan Hansknecht (Oct 17 2024 at 06:59):

The change you made above would probably break if someone added an inline expect.

view this post on Zulip Brendan Hansknecht (Oct 17 2024 at 07:00):

We could just unlink them to fix this, though the more full fix is to update expect to work the the platform api and then keep both by default

view this post on Zulip Luke Boswell (Oct 17 2024 at 07:01):

I'm ok with a quick fix. I think it will be pretty helpful for graphics users to have even something basic working.

view this post on Zulip Luke Boswell (Oct 17 2024 at 07:01):

Is this something I could implement?

view this post on Zulip Brendan Hansknecht (Oct 17 2024 at 07:08):

Is the plan to make dbg always included?

view this post on Zulip Brendan Hansknecht (Oct 17 2024 at 07:09):

If so, I think you just have to delete the conditional on line 3563 of llvm/build.rs

view this post on Zulip Brendan Hansknecht (Oct 17 2024 at 07:10):

Though I know there are other pieces to actually including/generating expect and dbg. So not 100% sure that will be engouh

view this post on Zulip Luke Boswell (Oct 17 2024 at 07:42):

That works. Thank you @Brendan Hansknecht

The next issue is that for some reason it seems like roc_dbg is getting called many times...

LLVM IR looks ok, like just one call in init... (as in there are no other calls to dbg anywhere)

define internal fastcc { { { i32, i32 }, {} }, {} } @"#UserApp_init_7ceb2e607d153edd175217b82e8ded113c6e4df27e27777d9f9694c716aa427"() !dbg !269 {
entry:
  %const_str_store1 = alloca %str.RocStr, align 8
  %const_str_store = alloca %str.RocStr, align 8
  %result_value = alloca %str.RocStr, align 8
  call fastcc void @Inspect_toStr_21b5c7d5305aa5ff4df495f05c9e59c37d76367eacec9dd321a0e78143dfc4a3(i64 1234, ptr nonnull %result_value), !dbg !270
  store ptr getelementptr inbounds ([36 x i8], ptr @_str_literal_5112864010422196678, i64 0, i64 8), ptr %const_str_store, align 8, !dbg !270
  %const_str_store.repack6 = getelementptr inbounds %str.RocStr, ptr %const_str_store, i64 0, i32 1, !dbg !270
  store i64 28, ptr %const_str_store.repack6, align 8, !dbg !270
  %const_str_store.repack7 = getelementptr inbounds %str.RocStr, ptr %const_str_store, i64 0, i32 2, !dbg !270
  store i64 28, ptr %const_str_store.repack7, align 8, !dbg !270
  store ptr inttoptr (i64 875770417 to ptr), ptr %const_str_store1, align 8, !dbg !270
  %const_str_store1.repack8 = getelementptr inbounds %str.RocStr, ptr %const_str_store1, i64 0, i32 1, !dbg !270
  store i64 0, ptr %const_str_store1.repack8, align 8, !dbg !270
  %const_str_store1.repack9 = getelementptr inbounds %str.RocStr, ptr %const_str_store1, i64 0, i32 2, !dbg !270
  store i64 -8935141660703064064, ptr %const_str_store1.repack9, align 8, !dbg !270
  call void @roc_dbg(ptr %const_str_store, ptr %result_value, ptr %const_str_store1), !dbg !270
  call fastcc void @"#Attr_#dec_8"(ptr nonnull %result_value), !dbg !270
  %call = call fastcc float @"#UserApp_height_8256d790c99390129cd6628d4d43bc44f55cfb83af722d8248666b192be24d65"(), !dbg !270
  %call2 = call fastcc float @"#UserApp_width_6fdff3e812be393e397a32aeb76ae96155b45793f22c8c7f8b12de3628ba863"(), !dbg !270
  %insert_record_field = insertvalue { float, float } zeroinitializer, float %call, 0, !dbg !270
  %insert_record_field3 = insertvalue { float, float } %insert_record_field, float %call2, 1, !dbg !270
  %call4 = call fastcc { { i32, i32 }, {} } @RocRay_setWindowSize_5c8e2eddb65717d2b7a69c4d944bbaab3db37fe30ea4d8f6e4bc9d32cef({ float, float } %insert_record_field3), !dbg !270
  %call5 = call fastcc { { { i32, i32 }, {} }, {} } @Task_await_f411d2d207cb75ff49124b128ee5a4cdec2daf8d1cf0a733c3c7d426729b6b({ { i32, i32 }, {} } %call4, {} zeroinitializer), !dbg !270
  ret { { { i32, i32 }, {} }, {} } %call5, !dbg !270
}

Here is the impl

#[no_mangle]
pub unsafe extern "C" fn roc_dbg(loc: &RocStr, msg: &RocStr) {
    let msg = CString::new(format!("[{}] {}\n", loc, msg)).unwrap();
    bindings::TraceLog(bindings::TraceLogLevel_LOG_DEBUG as i32, msg.as_ptr());
}

and this is what I see when I run the program...

DEBUG: [examples/basic-shapes.roc:15] 1234
DEBUG: [examples/basic-shapes.roc:15] 1234
DEBUG: [examples/basic-shapes.roc:15] 1234
DEBUG: [examples/basic-shapes.roc:15] 1234
DEBUG: [examples/basic-shapes.roc:15] 1234
DEBUG: [examples/basic-shapes.roc:15] 1234
DEBUG: [examples/basic-shapes.roc:15] 1234
.... etc

view this post on Zulip Luke Boswell (Oct 17 2024 at 07:50):

Same behaviour with

#[no_mangle]
pub unsafe extern "C" fn roc_dbg(loc: &RocStr, msg: &RocStr) {
    eprintln!("[{}] {}", loc, msg);
}

view this post on Zulip Luke Boswell (Oct 17 2024 at 08:00):

I realised the roc_dbg takes three pointers from reading the LLVM... so fixed that... but still get the same repeated calls

#[no_mangle]
pub unsafe extern "C" fn roc_dbg(loc: &RocStr, msg: &RocStr, src: &RocStr) {
    let msg = CString::new(format!("[{}] {} = {}", loc, src, msg)).unwrap();
    bindings::TraceLog(bindings::TraceLogLevel_LOG_DEBUG as i32, msg.as_ptr());
}

view this post on Zulip Luke Boswell (Nov 09 2024 at 23:24):

I need to get back to investigating this. It's such a helpful tool to have print debugging available and we're currently missing it in roc-ray.


Last updated: Jul 06 2025 at 12:14 UTC