Add trap codes to the Cretonne IL.

The trap and trapz/trapnz instructions now take a trap code immediate
operand which indicates the reason for trapping.
This commit is contained in:
Jakob Stoklund Olesen
2017-09-20 13:58:57 -07:00
parent 0f21fd342a
commit e8723be33f
28 changed files with 199 additions and 62 deletions

View File

@@ -7,7 +7,7 @@ function %nonsense(i32) {
; check: digraph %nonsense { ; check: digraph %nonsense {
ebb0(v1: i32): ebb0(v1: i32):
trap ; error: terminator instruction was encountered before the end trap user0 ; error: terminator instruction was encountered before the end
brnz v1, ebb2 ; unordered: ebb0:inst1 -> ebb2 brnz v1, ebb2 ; unordered: ebb0:inst1 -> ebb2
jump ebb1 ; unordered: ebb0:inst2 -> ebb1 jump ebb1 ; unordered: ebb0:inst2 -> ebb1

View File

@@ -9,7 +9,7 @@ function %not_reached(i32) -> i32 {
ebb0(v0: i32): ebb0(v0: i32):
brnz v0, ebb2 ; unordered: ebb0:inst0 -> ebb2 brnz v0, ebb2 ; unordered: ebb0:inst0 -> ebb2
trap trap user0
ebb1: ebb1:
v1 = iconst.i32 1 v1 = iconst.i32 1

View File

@@ -369,5 +369,5 @@ ebb1:
; asm: ebb2: ; asm: ebb2:
ebb2: ebb2:
trap ; bin: 0f 0b trap user0 ; bin: 0f 0b
} }

View File

@@ -861,5 +861,5 @@ ebb0:
; asm: movl %r10d, %ecx ; asm: movl %r10d, %ecx
[-,%rcx] v32 = uextend.i64 v13 ; bin: 44 89 d1 [-,%rcx] v32 = uextend.i64 v13 ; bin: 44 89 d1
trap ; bin: 0f 0b trap user0 ; bin: 0f 0b
} }

View File

@@ -9,22 +9,22 @@ isa intel
function %cond_trap(i32) { function %cond_trap(i32) {
ebb0(v1: i32): ebb0(v1: i32):
trapz v1 trapz v1, user67
return return
; check: $ebb0($v1: i32): ; check: $ebb0($v1: i32):
; nextln: brnz $v1, $(new=$EBB) ; nextln: brnz $v1, $(new=$EBB)
; nextln: trap ; nextln: trap user67
; check: $new: ; check: $new:
; nextln: return ; nextln: return
} }
function %cond_trap2(i32) { function %cond_trap2(i32) {
ebb0(v1: i32): ebb0(v1: i32):
trapnz v1 trapnz v1, int_ovf
return return
; check: $ebb0($v1: i32): ; check: $ebb0($v1: i32):
; nextln: brz $v1, $(new=$EBB) ; nextln: brz $v1, $(new=$EBB)
; nextln: trap ; nextln: trap int_ovf
; check: $new: ; check: $new:
; nextln: return ; nextln: return
} }
@@ -32,11 +32,11 @@ ebb0(v1: i32):
function %cond_trap_b1(i32) { function %cond_trap_b1(i32) {
ebb0(v1: i32): ebb0(v1: i32):
v2 = icmp_imm eq v1, 6 v2 = icmp_imm eq v1, 6
trapz v2 trapz v2, user7
return return
; check: $ebb0($v1: i32): ; check: $ebb0($v1: i32):
; check: brnz $v2, $(new=$EBB) ; check: brnz $v2, $(new=$EBB)
; nextln: trap ; nextln: trap user7
; check: $new: ; check: $new:
; nextln: return ; nextln: return
} }
@@ -44,11 +44,11 @@ ebb0(v1: i32):
function %cond_trap2_b1(i32) { function %cond_trap2_b1(i32) {
ebb0(v1: i32): ebb0(v1: i32):
v2 = icmp_imm eq v1, 6 v2 = icmp_imm eq v1, 6
trapnz v2 trapnz v2, user9
return return
; check: $ebb0($v1: i32): ; check: $ebb0($v1: i32):
; check: brz $v2, $(new=$EBB) ; check: brz $v2, $(new=$EBB)
; nextln: trap ; nextln: trap user9
; check: $new: ; check: $new:
; nextln: return ; nextln: return
} }

View File

@@ -64,7 +64,7 @@ ebb0(v0: i32, v999: i64):
; Boundscheck code ; Boundscheck code
; check: $(oob=$V) = icmp ; check: $(oob=$V) = icmp
; nextln: brz $oob, $(ok=$EBB) ; nextln: brz $oob, $(ok=$EBB)
; nextln: trap ; nextln: trap heap_oob
; check: $ok: ; check: $ok:
; Checks here are assuming that no pipehole opts fold the load offsets. ; Checks here are assuming that no pipehole opts fold the load offsets.
; nextln: $(xoff=$V) = uextend.i64 $v0 ; nextln: $(xoff=$V) = uextend.i64 $v0

View File

@@ -86,13 +86,13 @@ function %jumptable(i32) {
ebb10(v3: i32): ebb10(v3: i32):
br_table v3, jt2 br_table v3, jt2
trap trap user1
ebb20: ebb20:
trap trap user2
ebb30: ebb30:
trap trap user3
ebb40: ebb40:
trap trap user4
} }
; sameln: function %jumptable(i32) native { ; sameln: function %jumptable(i32) native {
; nextln: jt0 = jump_table 0 ; nextln: jt0 = jump_table 0
@@ -100,14 +100,14 @@ ebb40:
; nextln: ; nextln:
; nextln: ebb0($v3: i32): ; nextln: ebb0($v3: i32):
; nextln: br_table $v3, jt1 ; nextln: br_table $v3, jt1
; nextln: trap ; nextln: trap user1
; nextln: ; nextln:
; nextln: ebb1: ; nextln: ebb1:
; nextln: trap ; nextln: trap user2
; nextln: ; nextln:
; nextln: ebb2: ; nextln: ebb2:
; nextln: trap ; nextln: trap user3
; nextln: ; nextln:
; nextln: ebb3: ; nextln: ebb3:
; nextln: trap ; nextln: trap user4
; nextln: } ; nextln: }

View File

@@ -7,7 +7,7 @@ isa riscv
function %foo(i32, i32) { function %foo(i32, i32) {
ebb1(v0: i32 [%x8], v1: i32): ebb1(v0: i32 [%x8], v1: i32):
[-,-] v2 = iadd v0, v1 [-,-] v2 = iadd v0, v1
[-] trap [-] trap heap_oob
[R#1234, %x5, %x11] v6, v7 = iadd_cout v2, v0 [R#1234, %x5, %x11] v6, v7 = iadd_cout v2, v0
[Rshamt#beef, %x25] v8 = ishl_imm v6, 2 [Rshamt#beef, %x25] v8 = ishl_imm v6, 2
v9 = iadd v8, v7 v9 = iadd v8, v7
@@ -16,7 +16,7 @@ ebb1(v0: i32 [%x8], v1: i32):
; sameln: function %foo(i32, i32) native { ; sameln: function %foo(i32, i32) native {
; nextln: $ebb1($v0: i32 [%x8], $v1: i32): ; nextln: $ebb1($v0: i32 [%x8], $v1: i32):
; nextln: [-,-]$WS $v2 = iadd $v0, $v1 ; nextln: [-,-]$WS $v2 = iadd $v0, $v1
; nextln: [-]$WS trap ; nextln: [-]$WS trap heap_oob
; nextln: [R#1234,%x5,%x11]$WS $v6, $v7 = iadd_cout $v2, $v0 ; nextln: [R#1234,%x5,%x11]$WS $v6, $v7 = iadd_cout $v2, $v0
; nextln: [Rshamt#beef,%x25]$WS $v8 = ishl_imm $v6, 2 ; nextln: [Rshamt#beef,%x25]$WS $v8 = ishl_imm $v6, 2
; nextln: [-,-]$WS $v9 = iadd $v8, $v7 ; nextln: [-,-]$WS $v9 = iadd $v8, $v7

View File

@@ -13,13 +13,13 @@ function %defs() {
ebb100(v20: i32): ebb100(v20: i32):
v1000 = iconst.i32x8 5 v1000 = iconst.i32x8 5
v9200 = f64const 0x4.0p0 v9200 = f64const 0x4.0p0
trap trap user4
} }
; sameln: function %defs() native { ; sameln: function %defs() native {
; nextln: $ebb100($v20: i32): ; nextln: $ebb100($v20: i32):
; nextln: $v1000 = iconst.i32x8 5 ; nextln: $v1000 = iconst.i32x8 5
; nextln: $v9200 = f64const 0x1.0000000000000p2 ; nextln: $v9200 = f64const 0x1.0000000000000p2
; nextln: trap ; nextln: trap user4
; nextln: } ; nextln: }
; Using values. ; Using values.

View File

@@ -3,11 +3,11 @@ test cat
; The smallest possible function. ; The smallest possible function.
function %minimal() { function %minimal() {
ebb0: ebb0:
trap trap user0
} }
; sameln: function %minimal() native { ; sameln: function %minimal() native {
; nextln: ebb0: ; nextln: ebb0:
; nextln: trap ; nextln: trap user0
; nextln: } ; nextln: }
; Create and use values. ; Create and use values.

View File

@@ -4,10 +4,10 @@ set return_at_end
function %ok(i32) { function %ok(i32) {
ebb0(v0: i32): ebb0(v0: i32):
brnz v0, ebb1 brnz v0, ebb1
trap trap int_divz
ebb1: ebb1:
trapz v0 trapz v0, user5
return return
} }
@@ -17,6 +17,6 @@ ebb0(v0: i32):
return ; error: Internal return not allowed return ; error: Internal return not allowed
ebb1: ebb1:
trapz v0 trapz v0, user6
return return
} }

View File

@@ -46,5 +46,5 @@ ebb1(v2: i32):
function %undefined() { function %undefined() {
ebb0: ebb0:
trap trap user0
} }

View File

@@ -44,11 +44,11 @@ fn simple_traversal() {
brz v4, ebb4 brz v4, ebb4
jump ebb5 jump ebb5
ebb3: ebb3:
trap trap user0
ebb4: ebb4:
trap trap user0
ebb5: ebb5:
trap trap user0
} }
", ",
vec![0, 1, 3, 2, 4, 5], vec![0, 1, 3, 2, 4, 5],
@@ -123,7 +123,7 @@ fn loops_three() {
jump ebb6 jump ebb6
ebb5: ebb5:
brz v0, ebb4 brz v0, ebb4
trap trap user0
ebb6: ebb6:
jump ebb7 jump ebb7
ebb7: ebb7:
@@ -152,7 +152,7 @@ fn back_edge_one() {
brnz v0, ebb0 brnz v0, ebb0
return return
ebb4: ebb4:
trap trap user0
} }
", ",
vec![0, 1, 3, 2, 4], vec![0, 1, 3, 2, 4],

View File

@@ -9,7 +9,7 @@ from __future__ import absolute_import
from cdsl.formats import InstructionFormat from cdsl.formats import InstructionFormat
from cdsl.operands import VALUE, VARIABLE_ARGS from cdsl.operands import VALUE, VARIABLE_ARGS
from .immediates import imm64, uimm8, uimm32, ieee32, ieee64, offset32 from .immediates import imm64, uimm8, uimm32, ieee32, ieee64, offset32
from .immediates import boolean, intcc, floatcc, memflags, regunit from .immediates import boolean, intcc, floatcc, memflags, regunit, trapcode
from . import entities from . import entities
from .entities import ebb, sig_ref, func_ref, stack_slot, heap from .entities import ebb, sig_ref, func_ref, stack_slot, heap
@@ -61,5 +61,8 @@ HeapAddr = InstructionFormat(heap, VALUE, uimm32)
RegMove = InstructionFormat(VALUE, ('src', regunit), ('dst', regunit)) RegMove = InstructionFormat(VALUE, ('src', regunit), ('dst', regunit))
Trap = InstructionFormat(trapcode)
CondTrap = InstructionFormat(VALUE, trapcode)
# Finally extract the names of global variables in this module. # Finally extract the names of global variables in this module.
InstructionFormat.extract_names(globals()) InstructionFormat.extract_names(globals())

View File

@@ -105,3 +105,19 @@ regunit = ImmediateKind(
'regunit', 'regunit',
'A register unit in the target ISA', 'A register unit in the target ISA',
rust_type='isa::RegUnit') rust_type='isa::RegUnit')
#: A trap code indicating the reason for trapping.
#:
#: The Rust enum type also has a `User(u16)` variant for user-provided trap
#: codes.
trapcode = ImmediateKind(
'trapcode',
'A trap reason code.',
default_member='code',
rust_type='ir::TrapCode',
values={
"stk_ovf": 'StackOverflow',
"heap_oob": 'HeapOutOfBounds',
"int_ovf": 'IntegerOverflow',
"int_divz": 'IntegerDivisionByZero',
})

View File

@@ -11,6 +11,7 @@ from cdsl.instructions import Instruction, InstructionGroup
from base.types import f32, f64, b1 from base.types import f32, f64, b1
from base.immediates import imm64, uimm8, uimm32, ieee32, ieee64, offset32 from base.immediates import imm64, uimm8, uimm32, ieee32, ieee64, offset32
from base.immediates import boolean, intcc, floatcc, memflags, regunit from base.immediates import boolean, intcc, floatcc, memflags, regunit
from base.immediates import trapcode
from base import entities from base import entities
from cdsl.ti import WiderOrEq from cdsl.ti import WiderOrEq
import base.formats # noqa import base.formats # noqa
@@ -126,11 +127,12 @@ br_table = Instruction(
""", """,
ins=(x, JT), is_branch=True) ins=(x, JT), is_branch=True)
code = Operand('code', trapcode)
trap = Instruction( trap = Instruction(
'trap', r""" 'trap', r"""
Terminate execution unconditionally. Terminate execution unconditionally.
""", """,
is_terminator=True, can_trap=True) ins=code, is_terminator=True, can_trap=True)
trapz = Instruction( trapz = Instruction(
'trapz', r""" 'trapz', r"""
@@ -138,7 +140,7 @@ trapz = Instruction(
if ``c`` is non-zero, execution continues at the following instruction. if ``c`` is non-zero, execution continues at the following instruction.
""", """,
ins=c, can_trap=True) ins=(c, code), can_trap=True)
trapnz = Instruction( trapnz = Instruction(
'trapnz', r""" 'trapnz', r"""
@@ -146,7 +148,7 @@ trapnz = Instruction(
if ``c`` is zero, execution continues at the following instruction. if ``c`` is zero, execution continues at the following instruction.
""", """,
ins=c, can_trap=True) ins=(c, code), can_trap=True)
rvals = Operand('rvals', VARIABLE_ARGS, doc='return values') rvals = Operand('rvals', VARIABLE_ARGS, doc='return values')

View File

@@ -287,8 +287,8 @@ I64.enc(base.brnz.b1, *r.t8jccb_abcd(0x75))
# #
# Trap as ud2 # Trap as ud2
# #
I32.enc(base.trap, *r.noop(0x0f, 0x0b)) I32.enc(base.trap, *r.trap(0x0f, 0x0b))
I64.enc(base.trap, *r.noop(0x0f, 0x0b)) I64.enc(base.trap, *r.trap(0x0f, 0x0b))
# #
# Comparisons # Comparisons

View File

@@ -5,7 +5,7 @@ from __future__ import absolute_import
from cdsl.isa import EncRecipe from cdsl.isa import EncRecipe
from cdsl.predicates import IsSignedInt, IsEqual from cdsl.predicates import IsSignedInt, IsEqual
from base.formats import Unary, UnaryImm, Binary, BinaryImm, MultiAry from base.formats import Unary, UnaryImm, Binary, BinaryImm, MultiAry
from base.formats import Nullary, Call, IndirectCall, Store, Load from base.formats import Trap, Call, IndirectCall, Store, Load
from base.formats import IntCompare from base.formats import IntCompare
from base.formats import RegMove, Ternary, Jump, Branch, FuncAddr from base.formats import RegMove, Ternary, Jump, Branch, FuncAddr
from .registers import GPR, ABCD, FPR from .registers import GPR, ABCD, FPR
@@ -195,8 +195,8 @@ class TailRecipe:
null = EncRecipe('null', Unary, size=0, ins=GPR, outs=0, emit='') null = EncRecipe('null', Unary, size=0, ins=GPR, outs=0, emit='')
# XX opcode, no ModR/M. # XX opcode, no ModR/M.
noop = TailRecipe( trap = TailRecipe(
'noop', Nullary, size=0, ins=(), outs=(), 'trap', Trap, size=0, ins=(), outs=(),
emit='PUT_OP(bits, BASE_REX, sink);') emit='PUT_OP(bits, BASE_REX, sink);')
# XX /r # XX /r

View File

@@ -428,7 +428,7 @@ mod test {
use cursor::{Cursor, FuncCursor}; use cursor::{Cursor, FuncCursor};
use flowgraph::ControlFlowGraph; use flowgraph::ControlFlowGraph;
use ir::types::*; use ir::types::*;
use ir::{Function, InstBuilder, types}; use ir::{Function, InstBuilder, types, TrapCode};
use settings; use settings;
use super::*; use super::*;
use verifier::verify_context; use verifier::verify_context;
@@ -506,7 +506,7 @@ mod test {
let jmp02 = cur.ins().jump(ebb2, &[]); let jmp02 = cur.ins().jump(ebb2, &[]);
cur.insert_ebb(ebb1); cur.insert_ebb(ebb1);
let trap = cur.ins().trap(); let trap = cur.ins().trap(TrapCode::User(5));
cur.insert_ebb(ebb2); cur.insert_ebb(ebb2);
let jmp21 = cur.ins().jump(ebb1, &[]); let jmp21 = cur.ins().jump(ebb1, &[]);

View File

@@ -214,6 +214,12 @@ pub enum InstructionData {
src: RegUnit, src: RegUnit,
dst: RegUnit, dst: RegUnit,
}, },
Trap { opcode: Opcode, code: ir::TrapCode },
CondTrap {
opcode: Opcode,
arg: Value,
code: ir::TrapCode,
},
} }
/// A variable list of `Value` operands used for function call arguments and passing arguments to /// A variable list of `Value` operands used for function call arguments and passing arguments to

View File

@@ -17,6 +17,7 @@ mod globalvar;
mod heap; mod heap;
mod memflags; mod memflags;
mod progpoint; mod progpoint;
mod trapcode;
mod valueloc; mod valueloc;
pub use ir::builder::{InstBuilder, InstBuilderBase, InstInserterBase, InsertBuilder}; pub use ir::builder::{InstBuilder, InstBuilderBase, InstInserterBase, InsertBuilder};
@@ -34,6 +35,7 @@ pub use ir::layout::{Layout, CursorBase, Cursor};
pub use ir::memflags::MemFlags; pub use ir::memflags::MemFlags;
pub use ir::progpoint::{ProgramPoint, ProgramOrder, ExpandedProgramPoint}; pub use ir::progpoint::{ProgramPoint, ProgramOrder, ExpandedProgramPoint};
pub use ir::stackslot::{StackSlots, StackSlotKind, StackSlotData}; pub use ir::stackslot::{StackSlots, StackSlotKind, StackSlotData};
pub use ir::trapcode::TrapCode;
pub use ir::types::Type; pub use ir::types::Type;
pub use ir::valueloc::{ValueLoc, ArgumentLoc}; pub use ir::valueloc::{ValueLoc, ArgumentLoc};

View File

@@ -0,0 +1,89 @@
//! Trap codes describing the reason for a trap.
use std::fmt::{self, Display, Formatter};
use std::str::FromStr;
/// A trap code describing the reason for a trap.
///
/// All trap instructions have an explicit trap code.
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum TrapCode {
/// The current stack space was exhausted.
///
/// On some platforms, a stack overflow may also be indicated by a segmentation fault from the
/// stack guard page.
StackOverflow,
/// A `heap_addr` instruction detected an out-of-bounds error.
///
/// Some out-of-bounds heap accesses are detected by a segmentation fault on the heap guard
/// pages.
HeapOutOfBounds,
/// An integer arithmetic operation caused an overflow.
IntegerOverflow,
/// An integer division by zero.
IntegerDivisionByZero,
/// A user-defined trap code.
User(u16),
}
impl Display for TrapCode {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use self::TrapCode::*;
let identifier = match *self {
StackOverflow => "stk_ovf",
HeapOutOfBounds => "heap_oob",
IntegerOverflow => "int_ovf",
IntegerDivisionByZero => "int_divz",
User(x) => return write!(f, "user{}", x),
};
f.write_str(identifier)
}
}
impl FromStr for TrapCode {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
use self::TrapCode::*;
match s {
"stk_ovf" => Ok(StackOverflow),
"heap_oob" => Ok(HeapOutOfBounds),
"int_ovf" => Ok(IntegerOverflow),
"int_divz" => Ok(IntegerDivisionByZero),
_ if s.starts_with("user") => s[4..].parse().map(User).map_err(|_| ()),
_ => Err(()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
// Everything but user-defined codes.
const CODES: [TrapCode; 4] = [
TrapCode::StackOverflow,
TrapCode::HeapOutOfBounds,
TrapCode::IntegerOverflow,
TrapCode::IntegerDivisionByZero,
];
#[test]
fn display() {
for r in &CODES {
let tc = *r;
assert_eq!(tc.to_string().parse(), Ok(tc));
}
assert_eq!("bogus".parse::<TrapCode>(), Err(()));
assert_eq!(TrapCode::User(17).to_string(), "user17");
assert_eq!("user22".parse(), Ok(TrapCode::User(22)));
assert_eq!("user".parse::<TrapCode>(), Err(()));
assert_eq!("user-1".parse::<TrapCode>(), Err(()));
assert_eq!("users".parse::<TrapCode>(), Err(()));
}
}

View File

@@ -74,14 +74,14 @@ fn dynamic_addr(
// We need an overflow check for the adjusted offset. // We need an overflow check for the adjusted offset.
let size_val = pos.ins().iconst(offset_ty, size); let size_val = pos.ins().iconst(offset_ty, size);
let (adj_offset, overflow) = pos.ins().iadd_cout(offset, size_val); let (adj_offset, overflow) = pos.ins().iadd_cout(offset, size_val);
pos.ins().trapnz(overflow); pos.ins().trapnz(overflow, ir::TrapCode::HeapOutOfBounds);
oob = pos.ins().icmp( oob = pos.ins().icmp(
IntCC::UnsignedGreaterThan, IntCC::UnsignedGreaterThan,
adj_offset, adj_offset,
bound, bound,
); );
} }
pos.ins().trapnz(oob); pos.ins().trapnz(oob, ir::TrapCode::HeapOutOfBounds);
offset_addr(inst, heap, addr_ty, offset, offset_ty, pos.func); offset_addr(inst, heap, addr_ty, offset, offset_ty, pos.func);
} }
@@ -103,7 +103,7 @@ fn static_addr(
// Start with the bounds check. Trap if `offset + size > bound`. // Start with the bounds check. Trap if `offset + size > bound`.
if size > bound { if size > bound {
// This will simply always trap since `offset >= 0`. // This will simply always trap since `offset >= 0`.
pos.ins().trap(); pos.ins().trap(ir::TrapCode::HeapOutOfBounds);
pos.func.dfg.replace(inst).iconst(addr_ty, 0); pos.func.dfg.replace(inst).iconst(addr_ty, 0);
return; return;
} }
@@ -129,7 +129,7 @@ fn static_addr(
limit, limit,
) )
}; };
pos.ins().trapnz(oob); pos.ins().trapnz(oob, ir::TrapCode::HeapOutOfBounds);
} }
offset_addr(inst, heap, addr_ty, offset, offset_ty, pos.func); offset_addr(inst, heap, addr_ty, offset, offset_ty, pos.func);

View File

@@ -106,15 +106,15 @@ include!(concat!(env!("OUT_DIR"), "/legalizer.rs"));
fn expand_cond_trap(inst: ir::Inst, func: &mut ir::Function, cfg: &mut ControlFlowGraph) { fn expand_cond_trap(inst: ir::Inst, func: &mut ir::Function, cfg: &mut ControlFlowGraph) {
// Parse the instruction. // Parse the instruction.
let trapz; let trapz;
let arg = match func.dfg[inst] { let (arg, code) = match func.dfg[inst] {
ir::InstructionData::Unary { opcode, arg } => { ir::InstructionData::CondTrap { opcode, arg, code } => {
// We want to branch *over* an unconditional trap. // We want to branch *over* an unconditional trap.
trapz = match opcode { trapz = match opcode {
ir::Opcode::Trapz => true, ir::Opcode::Trapz => true,
ir::Opcode::Trapnz => false, ir::Opcode::Trapnz => false,
_ => panic!("Expected cond trap: {}", func.dfg.display_inst(inst, None)), _ => panic!("Expected cond trap: {}", func.dfg.display_inst(inst, None)),
}; };
arg (arg, code)
} }
_ => panic!("Expected cond trap: {}", func.dfg.display_inst(inst, None)), _ => panic!("Expected cond trap: {}", func.dfg.display_inst(inst, None)),
}; };
@@ -138,7 +138,7 @@ fn expand_cond_trap(inst: ir::Inst, func: &mut ir::Function, cfg: &mut ControlFl
} }
let mut pos = FuncCursor::new(func).after_inst(inst); let mut pos = FuncCursor::new(func).after_inst(inst);
pos.ins().trap(); pos.ins().trap(code);
pos.insert_ebb(new_ebb); pos.insert_ebb(new_ebb);
// Finally update the CFG. // Finally update the CFG.

View File

@@ -337,7 +337,9 @@ impl<'a> Verifier<'a> {
FloatCompare { .. } | FloatCompare { .. } |
Load { .. } | Load { .. } |
Store { .. } | Store { .. } |
RegMove { .. } => {} RegMove { .. } |
Trap { .. } |
CondTrap { .. } => {}
} }
Ok(()) Ok(())

View File

@@ -376,6 +376,8 @@ pub fn write_operands(
write!(w, " {}, %{} -> %{}", arg, src, dst) write!(w, " {}, %{} -> %{}", arg, src, dst)
} }
} }
Trap { code, .. } => write!(w, " {}", code),
CondTrap { arg, code, .. } => write!(w, " {}, {}", arg, code),
} }
} }

View File

@@ -2192,6 +2192,19 @@ impl<'a> Parser<'a> {
dst, dst,
} }
} }
InstructionFormat::Trap => {
let code = self.match_enum("expected trap code")?;
InstructionData::Trap { opcode, code }
}
InstructionFormat::CondTrap => {
let arg = self.match_value("expected SSA value operand")?;
self.match_token(
Token::Comma,
"expected ',' between operands",
)?;
let code = self.match_enum("expected trap code")?;
InstructionData::CondTrap { opcode, arg, code }
}
}; };
Ok(idata) Ok(idata)
} }
@@ -2365,7 +2378,7 @@ mod tests {
jt10 = jump_table ebb0 jt10 = jump_table ebb0
; Jumptable ; Jumptable
ebb0: ; Basic block ebb0: ; Basic block
trap ; Instruction trap user42; Instruction
} ; Trailing. } ; Trailing.
; More trailing.", ; More trailing.",
).parse_function(None) ).parse_function(None)
@@ -2459,7 +2472,7 @@ mod tests {
let func = Parser::new( let func = Parser::new(
"function #1234567890AbCdEf() native { "function #1234567890AbCdEf() native {
ebb0: ebb0:
trap trap int_divz
}", }",
).parse_function(None) ).parse_function(None)
.unwrap() .unwrap()
@@ -2470,7 +2483,7 @@ mod tests {
let mut parser = Parser::new( let mut parser = Parser::new(
"function #12ww() native { "function #12ww() native {
ebb0: ebb0:
trap trap stk_ovf
}", }",
); );
assert!(parser.parse_function(None).is_err()); assert!(parser.parse_function(None).is_err());
@@ -2479,7 +2492,7 @@ mod tests {
let mut parser = Parser::new( let mut parser = Parser::new(
"function #1() native { "function #1() native {
ebb0: ebb0:
trap trap user0
}", }",
); );
assert!(parser.parse_function(None).is_err()); assert!(parser.parse_function(None).is_err());
@@ -2488,7 +2501,7 @@ mod tests {
let func = Parser::new( let func = Parser::new(
"function #() native { "function #() native {
ebb0: ebb0:
trap trap int_ovf
}", }",
).parse_function(None) ).parse_function(None)
.unwrap() .unwrap()

View File

@@ -101,7 +101,9 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
// We do nothing // We do nothing
} }
Operator::Unreachable => { Operator::Unreachable => {
builder.ins().trap(); // We use `trap user0` to indicate a user-generated trap.
// We could make the trap code configurable if need be.
builder.ins().trap(ir::TrapCode::User(0));
state.real_unreachable_stack_depth = 1; state.real_unreachable_stack_depth = 1;
} }
/***************************** Control flow blocks ********************************** /***************************** Control flow blocks **********************************