//@ needs-llvm-components: avr //@ needs-rust-lld //! Regression test for #129301/llvm-project#106722 within `rustc`. //! //! Some LLVM-versions had wrong offsets in the local labels, causing the first //! loop instruction to be missed. This test therefore contains a simple loop //! with trivial instructions in it, to see, where the label is placed. //! //! This must be a `rmake`-test and cannot be a `tests/assembly`-test, since the //! wrong output is only produced with direct assembly generation, but not when //! "emit-asm" is used, as described in the issue description of #129301: //! https://github.com/rust-lang/rust/issues/129301#issue-2475070770 use run_make_support::{llvm_objdump, rustc}; fn main() { rustc() .input("avr-rjmp-offsets.rs") .opt_level("s") .panic("abort") .target("avr-unknown-gnu-atmega328") // normally one links with `avr-gcc`, but this is not available in CI, // hence this test diverges from the default behavior to enable linking // at all, which is necessary for the test (to resolve the labels). To // not depend on a special linker script, the main-function is marked as // the entry function, causing the linker to not remove it. .linker("rust-lld") .link_arg("--entry=main") .output("compiled") .run(); let disassembly = llvm_objdump().disassemble().input("compiled").run().stdout_utf8(); // search for the following instruction sequence: // ```disassembly // 00000080
: // 80: 81 e0 ldi r24, 0x1 // 82: 92 e0 ldi r25, 0x2 // 84: 85 b9 out 0x5, r24 // 86: 95 b9 out 0x5, r25 // 88: fd cf rjmp .-6 // ``` // This matches on all instructions, since the size of the instructions be- // fore the relative jump has an impact on the label offset. Old versions // of the Rust compiler did produce a label `rjmp .-4` (misses the first // instruction in the loop). assert!(disassembly.contains("
"), "no main function in output"); disassembly .trim() .lines() .skip_while(|&line| !line.contains("
")) .inspect(|line| println!("{line}")) .skip(1) .zip(["ldi\t", "ldi\t", "out\t", "out\t", "rjmp\t.-6"]) .for_each(|(line, expected_instruction)| { assert!( line.contains(expected_instruction), "expected instruction `{expected_instruction}`, got `{line}`" ); }); }