|
| 1 | +//@ needs-llvm-components: avr |
| 2 | +//@ needs-rust-lld |
| 3 | +//! Regression test for #129301/llvm-project#106722 within `rustc`. |
| 4 | +//! |
| 5 | +//! Some LLVM-versions had wrong offsets in the local labels, causing the first |
| 6 | +//! loop instruction to be missed. This test therefore contains a simple loop |
| 7 | +//! with trivial instructions in it, to see, where the label is placed. |
| 8 | +//! |
| 9 | +//! This must be a `rmake`-test and cannot be a `tests/assembly`-test, since the |
| 10 | +//! wrong output is only produced with direct assembly generation, but not when |
| 11 | +//! "emit-asm" is used, as described in the issue description of #129301: |
| 12 | +//! https://github.com/rust-lang/rust/issues/129301#issue-2475070770 |
| 13 | +use run_make_support::{llvm_objdump, rustc}; |
| 14 | + |
| 15 | +fn main() { |
| 16 | + rustc() |
| 17 | + .input("avr-rjmp-offsets.rs") |
| 18 | + .opt_level("s") |
| 19 | + .panic("abort") |
| 20 | + .target("avr-unknown-gnu-atmega328") |
| 21 | + // normally one links with `avr-gcc`, but this is not available in CI, |
| 22 | + // hence this test diverges from the default behavior to enable linking |
| 23 | + // at all, which is necessary for the test (to resolve the labels). To |
| 24 | + // not depend on a special linker script, the main-function is marked as |
| 25 | + // the entry function, causing the linker to not remove it. |
| 26 | + .linker("rust-lld") |
| 27 | + .link_arg("--entry=main") |
| 28 | + .output("compiled") |
| 29 | + .run(); |
| 30 | + |
| 31 | + let disassembly = llvm_objdump().disassemble().input("compiled").run().stdout_utf8(); |
| 32 | + |
| 33 | + // search for the following instruction sequence: |
| 34 | + // ```disassembly |
| 35 | + // 00000080 <main>: |
| 36 | + // 80: 81 e0 ldi r24, 0x1 |
| 37 | + // 82: 92 e0 ldi r25, 0x2 |
| 38 | + // 84: 85 b9 out 0x5, r24 |
| 39 | + // 86: 95 b9 out 0x5, r25 |
| 40 | + // 88: fd cf rjmp .-6 |
| 41 | + // ``` |
| 42 | + // This matches on all instructions, since the size of the instructions be- |
| 43 | + // fore the relative jump has an impact on the label offset. Old versions |
| 44 | + // of the Rust compiler did produce a label `rjmp .-4` (misses the first |
| 45 | + // instruction in the loop). |
| 46 | + assert!(disassembly.contains("<main>"), "no main function in output"); |
| 47 | + disassembly |
| 48 | + .trim() |
| 49 | + .lines() |
| 50 | + .skip_while(|&line| !line.contains("<main>")) |
| 51 | + .inspect(|line| println!("{line}")) |
| 52 | + .skip(1) |
| 53 | + .zip(["ldi\t", "ldi\t", "out\t", "out\t", "rjmp\t.-6"]) |
| 54 | + .for_each(|(line, expected_instruction)| { |
| 55 | + assert!( |
| 56 | + line.contains(expected_instruction), |
| 57 | + "expected instruction `{expected_instruction}`, got `{line}`" |
| 58 | + ); |
| 59 | + }); |
| 60 | +} |
0 commit comments