mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 21:39:07 +00:00
implement panic on overflow for mul in the dev backend
This commit is contained in:
parent
865eff1956
commit
cfdfbe18a4
5 changed files with 71 additions and 9 deletions
|
@ -1424,9 +1424,38 @@ impl<
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_num_mul(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, layout: &InLayout<'a>) {
|
fn build_num_mul(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, layout: &InLayout<'a>) {
|
||||||
// for the time being, `num_mul` is implemented as wrapping multiplication. In roc, the normal
|
match self.layout_interner.get_repr(*layout) {
|
||||||
// `mul` should panic on overflow, but we just don't do that yet
|
LayoutRepr::Builtin(Builtin::Int(int_width)) => self.build_fn_call(
|
||||||
self.build_num_mul_wrap(dst, src1, src2, layout)
|
dst,
|
||||||
|
bitcode::NUM_MUL_OR_PANIC_INT[int_width].to_string(),
|
||||||
|
&[*src1, *src2],
|
||||||
|
&[*layout, *layout],
|
||||||
|
layout,
|
||||||
|
),
|
||||||
|
|
||||||
|
LayoutRepr::Builtin(Builtin::Float(FloatWidth::F64)) => {
|
||||||
|
let dst_reg = self.storage_manager.claim_float_reg(&mut self.buf, dst);
|
||||||
|
let src1_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src1);
|
||||||
|
let src2_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src2);
|
||||||
|
ASM::mul_freg64_freg64_freg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
|
||||||
|
}
|
||||||
|
LayoutRepr::Builtin(Builtin::Float(FloatWidth::F32)) => {
|
||||||
|
let dst_reg = self.storage_manager.claim_float_reg(&mut self.buf, dst);
|
||||||
|
let src1_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src1);
|
||||||
|
let src2_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src2);
|
||||||
|
ASM::mul_freg32_freg32_freg32(&mut self.buf, dst_reg, src1_reg, src2_reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
LayoutRepr::DEC => self.build_fn_call(
|
||||||
|
dst,
|
||||||
|
bitcode::DEC_MUL_OR_PANIC.to_string(),
|
||||||
|
&[*src1, *src2],
|
||||||
|
&[Layout::DEC, Layout::DEC],
|
||||||
|
&Layout::DEC,
|
||||||
|
),
|
||||||
|
|
||||||
|
other => unreachable!("NumMul for layout {other:?}"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_num_mul_wrap(
|
fn build_num_mul_wrap(
|
||||||
|
|
|
@ -523,12 +523,12 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Syste
|
||||||
use X86_64GeneralReg::*;
|
use X86_64GeneralReg::*;
|
||||||
type ASM = X86_64Assembler;
|
type ASM = X86_64Assembler;
|
||||||
|
|
||||||
// move the first argument to roc_panic (a *RocStr) into r8
|
// move the first argument to roc_panic (a *const RocStr) into r8
|
||||||
ASM::add_reg64_reg64_imm32(buf, R8, RSP, 8);
|
ASM::mov_reg64_reg64(buf, R8, RDI);
|
||||||
|
|
||||||
// move the crash tag into the second return register. We add 1 to it because the 0 value
|
// move the crash tag into the second return register. We add 1 to it because the 0 value
|
||||||
// is already used for "no crash occurred"
|
// is already used for "no crash occurred"
|
||||||
ASM::add_reg64_reg64_imm32(buf, RDX, RDI, 1);
|
ASM::add_reg64_reg64_imm32(buf, RDX, RSI, 1);
|
||||||
|
|
||||||
// the setlongjmp_buffer
|
// the setlongjmp_buffer
|
||||||
ASM::data_pointer(buf, relocs, String::from("setlongjmp_buffer"), RDI);
|
ASM::data_pointer(buf, relocs, String::from("setlongjmp_buffer"), RDI);
|
||||||
|
|
|
@ -668,14 +668,22 @@ trait Backend<'a> {
|
||||||
&Literal::Int((crash_tag as u128).to_ne_bytes()),
|
&Literal::Int((crash_tag as u128).to_ne_bytes()),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// this function gets a RocStr, but the roc_panic defined by a platform expects a `*RocStr`.
|
||||||
|
// we store the value in a global variable and then use a pointer to this global
|
||||||
|
let panic_msg_ptr = self.debug_symbol("panic_msg_ptr");
|
||||||
|
let ignored = self.debug_symbol("ignored");
|
||||||
|
self.build_data_pointer(&panic_msg_ptr, "panic_msg".to_string());
|
||||||
|
self.load_literal_symbols(&[msg]);
|
||||||
|
self.build_ptr_store(ignored, panic_msg_ptr, msg, Layout::STR);
|
||||||
|
|
||||||
// Now that the arguments are needed, load them if they are literals.
|
// Now that the arguments are needed, load them if they are literals.
|
||||||
let arguments = &[msg, error_message];
|
let arguments = &[panic_msg_ptr, error_message];
|
||||||
self.load_literal_symbols(arguments);
|
self.load_literal_symbols(arguments);
|
||||||
self.build_fn_call(
|
self.build_fn_call(
|
||||||
&Symbol::DEV_TMP2,
|
&Symbol::DEV_TMP2,
|
||||||
String::from("roc_panic"),
|
String::from("roc_panic"),
|
||||||
arguments,
|
arguments,
|
||||||
&[Layout::STR, Layout::U32],
|
&[Layout::U64, Layout::U32],
|
||||||
&Layout::UNIT,
|
&Layout::UNIT,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -159,6 +159,30 @@ fn define_setlongjmp_buffer(output: &mut Object) -> SymbolId {
|
||||||
symbol_id
|
symbol_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// needed to implement Crash when setjmp/longjmp is used
|
||||||
|
fn define_panic_msg(output: &mut Object) -> SymbolId {
|
||||||
|
let bss_section = output.section_id(StandardSection::Data);
|
||||||
|
|
||||||
|
// 3 words for a RocStr
|
||||||
|
const SIZE: usize = 3 * core::mem::size_of::<u64>();
|
||||||
|
|
||||||
|
let symbol = Symbol {
|
||||||
|
name: b"panic_msg".to_vec(),
|
||||||
|
value: 0,
|
||||||
|
size: SIZE as u64,
|
||||||
|
kind: SymbolKind::Data,
|
||||||
|
scope: SymbolScope::Linkage,
|
||||||
|
weak: false,
|
||||||
|
section: SymbolSection::Section(bss_section),
|
||||||
|
flags: SymbolFlags::None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let symbol_id = output.add_symbol(symbol);
|
||||||
|
output.add_symbol_data(symbol_id, bss_section, &[0x00; SIZE], 8);
|
||||||
|
|
||||||
|
symbol_id
|
||||||
|
}
|
||||||
|
|
||||||
fn generate_setjmp<'a, B: Backend<'a>>(backend: &mut B, output: &mut Object) {
|
fn generate_setjmp<'a, B: Backend<'a>>(backend: &mut B, output: &mut Object) {
|
||||||
let text_section = output.section_id(StandardSection::Text);
|
let text_section = output.section_id(StandardSection::Text);
|
||||||
let proc_symbol = Symbol {
|
let proc_symbol = Symbol {
|
||||||
|
@ -422,6 +446,7 @@ fn build_object<'a, B: Backend<'a>>(
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if backend.env().mode.generate_roc_panic() {
|
if backend.env().mode.generate_roc_panic() {
|
||||||
|
define_panic_msg(&mut output);
|
||||||
define_setlongjmp_buffer(&mut output);
|
define_setlongjmp_buffer(&mut output);
|
||||||
|
|
||||||
generate_roc_panic(&mut backend, &mut output);
|
generate_roc_panic(&mut backend, &mut output);
|
||||||
|
|
|
@ -1989,7 +1989,7 @@ fn float_sub_checked() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||||
#[should_panic(expected = r#"Roc failed with message: "Integer multiplication overflowed!"#)]
|
#[should_panic(expected = r#"Roc failed with message: "Integer multiplication overflowed!"#)]
|
||||||
fn int_positive_mul_overflow() {
|
fn int_positive_mul_overflow() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue