From 859339f60179aeaf2272c066a0b2dcefd1e9e2e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Tue, 18 Aug 2026 11:21:41 +0200 Subject: [PATCH 1/2] test(codegen): pin inline-asm leaf emission for #8121 --- crates/perry-codegen/src/dialect/mod.rs | 4 +-- crates/perry-codegen/src/inprocess.rs | 4 +-- crates/perry-codegen/src/native_emit.rs | 38 +++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/crates/perry-codegen/src/dialect/mod.rs b/crates/perry-codegen/src/dialect/mod.rs index 29d036fd97..202e9acef6 100644 --- a/crates/perry-codegen/src/dialect/mod.rs +++ b/crates/perry-codegen/src/dialect/mod.rs @@ -906,7 +906,7 @@ impl<'ctx, 'm> FnReader<'ctx, 'm> { .map_err(be)?; // Perry-emitted inline asm never calls back into the runtime, so it // can never reach a safepoint. Without this, RS4GC statepoint-wraps - // the call and produces IR the verifier rejects (#8082). + // the call and produces IR the verifier rejects (#8121). site.add_attribute( inkwell::attributes::AttributeLoc::Function, self.ctx.create_string_attribute("gc-leaf-function", ""), @@ -1613,7 +1613,7 @@ impl<'ctx, 'm> FnReader<'ctx, 'm> { .map_err(be)?; // The empty barrier can never reach a safepoint; the // exemption keeps RS4GC from statepoint-wrapping inline asm - // into invalid IR (#8082). + // into invalid IR (#8121). site.add_attribute( inkwell::attributes::AttributeLoc::Function, self.ctx.create_string_attribute("gc-leaf-function", ""), diff --git a/crates/perry-codegen/src/inprocess.rs b/crates/perry-codegen/src/inprocess.rs index f7503f1400..9325dd45ad 100644 --- a/crates/perry-codegen/src/inprocess.rs +++ b/crates/perry-codegen/src/inprocess.rs @@ -480,7 +480,7 @@ fn optimize_and_emit( ) })?; // Verify the rewritten module before it reaches the backend. RS4GC - // has produced verifier-invalid IR in the wild (#8082: it wrapped an + // has produced verifier-invalid IR in the wild (#8121: it wrapped an // inline-asm barrier into a gc.statepoint), and unlike the external // `opt` path — whose verifier aborts with the broken instruction — // the in-process pipeline would feed the broken module straight to @@ -580,7 +580,7 @@ mod tests { fn unattributed_asm_barrier_is_rejected_not_miscompiled() { // Sabotage arm: without the attribute RS4GC wraps the asm into a // gc.statepoint whose callee is inline asm — invalid IR. The - // pipeline must fail verification loudly (#8082's SIGBUS shape), + // pipeline must fail verification loudly (#8121's SIGBUS shape), // proving the leaf test above can actually fail. let result = statepoint_rewritten_ir( &asm_barrier_fixture(""), diff --git a/crates/perry-codegen/src/native_emit.rs b/crates/perry-codegen/src/native_emit.rs index dd518e507d..5c2ba4c6fd 100644 --- a/crates/perry-codegen/src/native_emit.rs +++ b/crates/perry-codegen/src/native_emit.rs @@ -695,6 +695,44 @@ mod tests { } } + /// #8121, emission half. The sibling pair in `inprocess::tests` proves the + /// LLVM mechanism (RS4GC breaks an unmarked inline-asm barrier, and + /// `gc-leaf-function` stops it) using hand-written IR, so it would still + /// pass if Perry stopped emitting the attribute. This asserts the emission + /// itself, on both paths. + #[test] + fn perry_emits_the_loop_barrier_as_a_gc_leaf() { + let mut module = LlModule::new(crate::codegen::default_target_triple()); + let function = module.define_function("barrier_emission_fixture", VOID, vec![]); + let entry = function.create_block("entry"); + entry.asm_sideeffect_barrier(); + entry.ret_void(); + + let text_ir = module.to_ir(); + assert!( + text_ir.contains("asm sideeffect"), + "fixture emitted no barrier, so this proves nothing:\n{text_ir}" + ); + assert!( + text_ir.contains(r#"call void asm sideeffect "", ""() "gc-leaf-function""#), + "text path barrier lost its gc-leaf callsite attribute (#8121):\n{text_ir}" + ); + + let context = Context::create(); + let native_ir = build_native_module(&context, &module) + .expect("barrier emission fixture constructs") + .print_to_string() + .to_string(); + assert!( + native_ir.contains("asm sideeffect"), + "native arm emitted no barrier, so this proves nothing:\n{native_ir}" + ); + assert!( + native_ir.contains("gc-leaf-function"), + "native path lost the gc-leaf attribute on the barrier (#8121):\n{native_ir}" + ); + } + fn compact_gc_map_section_name() -> &'static [u8] { if cfg!(target_os = "macos") { b"__perry_gcmap" From 104da760eaaae829d00165811813d3be29c6aac9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Tue, 18 Aug 2026 11:22:31 +0200 Subject: [PATCH 2/2] docs: add changelog for #8358 --- changelog.d/8358-inline-asm-leaf-emission-regression.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 changelog.d/8358-inline-asm-leaf-emission-regression.md diff --git a/changelog.d/8358-inline-asm-leaf-emission-regression.md b/changelog.d/8358-inline-asm-leaf-emission-regression.md new file mode 100644 index 0000000000..59fd322d0a --- /dev/null +++ b/changelog.d/8358-inline-asm-leaf-emission-regression.md @@ -0,0 +1,7 @@ +### Tests + +- Pin the `gc-leaf-function` marker on Perry's inline-assembly loop barrier in + both text and native LLVM emission. This closes the remaining regression gap + for #8121: the existing hand-written IR tests covered the LLVM behavior but + could not detect either Perry emitter dropping the marker and reintroducing + the `rewrite-statepoints-for-gc` SIGBUS.