You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
use std::arch::asm;use proptest::prelude::*;fnmain(){}/// Вычислить d как результат (a * b / c), где при переполнении числа или при/// делении на 0 результатом будет None.fncalc_d(a:i16,b:i16,c:u8) -> Option<i16>{// Референсная реализация для использовании в тестировании свойств// (prop(-erty)test)
a.checked_mul(b).and_then(|it| it.checked_div(c asi16))}/// Вычислить d как результат (a * b / c), где при переполнении числа или/// при делении на 0 результатом будет None.fncalc_d_asm(muta:i16,b:i16,c:u8) -> Option<i16>{/// Флаги, указывающие на результат выполнения ассемблерной вставки////// Поскольку ABI Rust'а нестабильно, мы не можем напрямую из ассемблера/// мутировать переменную типа `Option<i16>`. Этот тип будет создаваться на/// основании этого флага.// тип перечисления будет занимать 1 беззнаковый байт (u8)#[repr(u8)]#[derive(Debug,Eq,PartialEq,Copy,Clone)]// мы не конструируем флаги напрямую, поэтому отключаем предупреждение#[allow(dead_code)]enumFlag{Ok = 0,Overflow = 1,DivByZero = 2,}// По умолчанию считаем, что вставка выполнится успешно.// Ассемблерная вставка будет менять этот флаг в случае ошибки.letmut flag = Flag::Okasu8;unsafe{#[rustfmt::skip]asm!(// умножаем `a` (в регистре `ax`) на `b`, // записываем результат в `ax` (где и хранится `a`)"imul ax, {b:x}",
// если произошло переполнение, то прыгаем на метку 2// здесь и далее `f` - это `forward`, т. е. метка дальше в коде// без такой пометки значение интерпретируется как число, // что некорректно для операции `jo`"jo 2f",
// проверяем делитель на 0"cmp {c}, 0",
// если делитель равен 0, то прыгаем на метку 3"je 3f",
// Производим само деление:// Поскольку нам нужен `i16` как результат, одной операцией// `idiv` воспользоваться не получиться. // Следует расширить `ax` до 32 бит (регистр `dx:ax`),// а `c` - до 16 бит, преобразовав // беззнаковый байт `c` в положительное знаковое слово.// расширяем знаком `ax` до 32 бит `dx:ax`"cwd",
// расширяем `c` до 16 бит, преобразовав его в `i16`,// выполняем деление `dx:ax` на `c`"idiv {c:x}",
// прыгаем на конец вставки"jmp 4f",
"2:",
// Произошло переполнение: устанавливаем наш флаг,// чтобы вернуть None из функции, прыгаем на конец вставки"mov {flag}, 1",
"jmp 4f",
"3:",
// Произошла попытка деления на 0: устанавливаем наш флаг,// чтобы вернуть None из функции"mov {flag}, 2",
// Конец вставки"4:",
// регистр `ax` с доступом на чтение и запись,// в который записывается значение переменной `a`
inout("ax") a,
// параметр под именем `b` с доступом на чтение
b = in(reg) b,
// параметр под именем `c` с доступом на чтение.// Поскольку компилятор Rust требует для значений класса `reg`// размерность не менее 16 бит, то мы преобразуем `c` в `u16` (noop).
c = in(reg) c asu16,
// использованный для временного хранения значения `a`, расширенного до 32 бит,// регистр `dx`.
out("dx") _,
// параметр под именем `flag` с доступом на чтение и запись,// в регистр которого записывается значение переменной `flag`,// а размерность регистра равна 1 байту
flag = inout(reg_byte) flag,
// опции и свойства ассемблерной вставки:// pure - вставка не имеет побочных эффектов // (её результат зависит только от входных параметров)// nomem - вставка не обращается к памяти// nostack - вставка не использует стек
//
// данные опции и свойства являются указанием для компилятора,// позволяющим ему оптимизировать код
options(pure, nomem, nostack),
);}// Реинтерпретируем значение флага (u8) как перечисление `Flag` (тоже u8)// Поскольку мы не записываем в `flag` ничего, кроме значений 0, 1 или 2,// то эта операция безопасна.let flag:Flag = unsafe{ std::mem::transmute(flag)};// В зависимости от значения флага, возвращаем тот или иной результатmatch flag {// Если флаг равен `Flag::Ok`, то возвращаем результат вычисления, обёрнутый в `Some`Flag::Ok => Some(a),// Если флаг равен `Flag::Overflow` или `Flag::DivByZero`, то возвращаем `None`Flag::Overflow | Flag::DivByZero => None,}}/// Вычислить e как результат выражения (a - b) * (b - c), где при переполнении/// числа результатом будет None.fncalc_e(a:i16,b:i16,c:u8) -> Option<i16>{// Референсная реализация для использовании в тестировании свойств// (prop(-erty)test)let lhs = a.checked_sub(b)?;let rhs = b.checked_sub(c asi16)?;
lhs.checked_mul(rhs)}fncalc_e_asm(_a:i16,_b:i16,_c:u8) -> Option<i16>{enumFlag{Ok = 0,OverflowLhs = 1,OverflowRhs = 2,OverflowMul = 3,}todo!()}// Тестирование свойств (property testing)proptest!{
#[test]// Для любых a, b, c из множеств i16, i16, u8 соответственно,// выполнить функцию `calc_d` (референсная реализация) и `calc_d_asm` (наша реализация) и// проверить, что их результаты равны.
//
// Если тест проходит, то `calc_d` и `calc_d_asm` эквивалентны, а так как `calc_d` работает// корректно, то и `calc_d_asm` работает корректно.fn test_d(a in any::<i16>(), b in any::<i16>(), c in any::<u8>()){let d = calc_d(a, b, c);
let d_asm = calc_d_asm(a, b, c);
assert_eq!(d, d_asm);
}// Для любых a, b, c из множеств i16, i16, u8 соответственно,// выполнить функцию `calc_e` (референсная реализация) и `calc_e_asm` (наша реализация) и// проверить, что их результаты равны.
//
// Если тест проходит, то `calc_e` и `calc_e_asm` эквивалентны, а так как `calc_e` работает// корректно, то и `calc_e_asm` работает корректно.// #[test]// fn test_e(a in any::<i16>(), b in any::<i16>(), c in any::<u8>()) {// let e = calc_e(a, b, c);// let e_asm = calc_e_asm(a, b, c);// assert_eq!(e, e_asm);// }}
Output:
thread 'main' panicked at /rust/deps/annotate-snippets-0.9.2/src/display_list/from_snippet.rs:275:9:
SourceAnnotation range `(85, 87)` is bigger than source length `57`
stack backtrace:
0: 0x7faf4d294ffa - <std::sys::backtrace::BacktraceLock::print::DisplayBacktrace as core::fmt::Display>::fmt::h214716e6e0c5cd2c
1: 0x7faf4da0468a - core::fmt::write::hbd48ce2ad7284a0a
2: 0x7faf4ee08651 - std::io::Write::write_fmt::hb2eafdc8e5760cec
3: 0x7faf4d294e52 - std::sys::backtrace::BacktraceLock::print::hbc5009a8dd7de74f
4: 0x7faf4d297356 - std::panicking::default_hook::{{closure}}::he4a5a0eb6c634694
5: 0x7faf4d2971a0 - std::panicking::default_hook::h6ba3c19e5efafdd4
6: 0x7faf4c31eeb1 - std[d5e65f54d52c6b80]::panicking::update_hook::<alloc[543edef93a4acc51]::boxed::Box<rustc_driver_impl[5dcda6566a109f30]::install_ice_hook::{closure#0}>>::{closure#0}
7: 0x7faf4d297a68 - std::panicking::rust_panic_with_hook::h773803f4ebfbed1e
8: 0x7faf4d29783a - std::panicking::begin_panic_handler::{{closure}}::h09c6376b3729e5b0
9: 0x7faf4d2954a9 - std::sys::backtrace::__rust_end_short_backtrace::h1dd30efd00c5bb69
10: 0x7faf4d2974fc - rust_begin_unwind
11: 0x7faf49ce49c0 - core::panicking::panic_fmt::hcd050e92ce3ec7a3
12: 0x55f7e0dfb65d - <annotate_snippets[9b90caa08906aceb]::display_list::structs::DisplayList as core[47afb5b034596fb9]::convert::From<annotate_snippets[9b90caa08906aceb]::snippet::Snippet>>::from
13: 0x55f7e0c1edf4 - <rustfmt_nightly[b45938c28a441e9d]::format_report_formatter::FormatReportFormatter as core[47afb5b034596fb9]::fmt::Display>::fmt
14: 0x7faf4da0468a - core::fmt::write::hbd48ce2ad7284a0a
15: 0x7faf4d289b3e - <&std::io::stdio::Stderr as std::io::Write>::write_fmt::h141d1231c6b074d3
16: 0x7faf4d28a3f8 - std::io::stdio::_eprint::h337e8ced72dc4635
17: 0x55f7e0b08811 - rustfmt[deac11de4eeee1a2]::format_and_emit_report::<std[d5e65f54d52c6b80]::io::stdio::Stdout>
18: 0x55f7e0b0622f - rustfmt[deac11de4eeee1a2]::execute
19: 0x55f7e0b0211c - rustfmt[deac11de4eeee1a2]::main
20: 0x55f7e0af2a43 - std[d5e65f54d52c6b80]::sys::backtrace::__rust_begin_short_backtrace::<fn(), ()>
21: 0x55f7e0af4ad9 - std[d5e65f54d52c6b80]::rt::lang_start::<()>::{closure#0}
22: 0x7faf4e9511c1 - std::rt::lang_start_internal::h5758e332aa2f8cc6
23: 0x55f7e0b09868 - main
24: 0x7faf48917e08 - <unknown>
25: 0x7faf48917ecc - __libc_start_main
26: 0x55f7e0ade1b9 - <unknown>
27: 0x0 - <unknown>
error: the compiler unexpectedly panicked. this is a bug.
note: we would appreciate a bug report: https://github.com/rust-lang/rustfmt/issues/new?labels=bug
note: please make sure that you have updated to the latest nightly
note: please attach the file at `/home/bezkonca/uni/sem-3/comptech/lab3/lab3-rs/rustc-ice-2024-11-18T10_38_07-2250081.txt` to your bug report
query stack during panic:
end of query stack
@sicikh thanks for the report. Any chance you can get the reproducible example down to a smaller size? rustfmt can work on code that doesn't compile so it should be easy to remove lines of code that don't contribute to the problem.
Command:
Code:
Output:
File
/home/bezkonca/uni/sem-3/comptech/lab3/lab3-rs/rustc-ice-2024-11-18T10_32_31-2249440.txt
:Comments:
It looks like #6392.
The text was updated successfully, but these errors were encountered: