[WIP] Add a Trap sink to code generation (#279)
* First draft of TrapSink implementation. * Add trap sink calls to 'trapif' and 'trapff' recipes. * Add SourceLoc to trap sink calls, and add trap sink calls to all loads and stores. * Add IntegerDivisionByZero trap to div recipe. * Only emit load/store traps if 'notrap' flag is not set on the instruction. * Update filetest machinery to add new trap sink functionality. * Update filetests to include traps in output. * Add a few more trap outputs to filetests. * Add trap output to CLI tool.
This commit is contained in:
committed by
Dan Gohman
parent
d566faa8fb
commit
951ff11f85
@@ -278,7 +278,10 @@ null = EncRecipe('null', Unary, size=0, ins=GPR, outs=0, emit='')
|
||||
# XX opcode, no ModR/M.
|
||||
trap = TailRecipe(
|
||||
'trap', Trap, size=0, ins=(), outs=(),
|
||||
emit='PUT_OP(bits, BASE_REX, sink);')
|
||||
emit='''
|
||||
sink.trap(code, func.srclocs[inst]);
|
||||
PUT_OP(bits, BASE_REX, sink);
|
||||
''')
|
||||
|
||||
# Macro: conditional jump over a ud2.
|
||||
trapif = EncRecipe(
|
||||
@@ -289,6 +292,7 @@ trapif = EncRecipe(
|
||||
sink.put1(0x70 | (icc2opc(cond.inverse()) as u8));
|
||||
sink.put1(2);
|
||||
// ud2.
|
||||
sink.trap(code, func.srclocs[inst]);
|
||||
sink.put1(0x0f);
|
||||
sink.put1(0x0b);
|
||||
''')
|
||||
@@ -302,6 +306,7 @@ trapff = EncRecipe(
|
||||
sink.put1(0x70 | (fcc2opc(cond.inverse()) as u8));
|
||||
sink.put1(2);
|
||||
// ud2.
|
||||
sink.trap(code, func.srclocs[inst]);
|
||||
sink.put1(0x0f);
|
||||
sink.put1(0x0b);
|
||||
''')
|
||||
@@ -450,6 +455,7 @@ div = TailRecipe(
|
||||
'div', Ternary, size=1,
|
||||
ins=(GPR.rax, GPR.rdx, GPR), outs=(GPR.rax, GPR.rdx),
|
||||
emit='''
|
||||
sink.trap(TrapCode::IntegerDivisionByZero, func.srclocs[inst]);
|
||||
PUT_OP(bits, rex1(in_reg2), sink);
|
||||
modrm_r_bits(in_reg2, bits, sink);
|
||||
''')
|
||||
@@ -678,6 +684,9 @@ st = TailRecipe(
|
||||
instp=IsEqual(Store.offset, 0),
|
||||
clobbers_flags=False,
|
||||
emit='''
|
||||
if !flags.notrap() {
|
||||
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||
}
|
||||
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
||||
modrm_rm(in_reg1, in_reg0, sink);
|
||||
''')
|
||||
@@ -690,6 +699,9 @@ st_abcd = TailRecipe(
|
||||
when_prefixed=st,
|
||||
clobbers_flags=False,
|
||||
emit='''
|
||||
if !flags.notrap() {
|
||||
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||
}
|
||||
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
||||
modrm_rm(in_reg1, in_reg0, sink);
|
||||
''')
|
||||
@@ -700,6 +712,9 @@ fst = TailRecipe(
|
||||
instp=IsEqual(Store.offset, 0),
|
||||
clobbers_flags=False,
|
||||
emit='''
|
||||
if !flags.notrap() {
|
||||
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||
}
|
||||
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
||||
modrm_rm(in_reg1, in_reg0, sink);
|
||||
''')
|
||||
@@ -710,6 +725,9 @@ stDisp8 = TailRecipe(
|
||||
instp=IsSignedInt(Store.offset, 8),
|
||||
clobbers_flags=False,
|
||||
emit='''
|
||||
if !flags.notrap() {
|
||||
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||
}
|
||||
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
||||
modrm_disp8(in_reg1, in_reg0, sink);
|
||||
let offset: i32 = offset.into();
|
||||
@@ -721,6 +739,9 @@ stDisp8_abcd = TailRecipe(
|
||||
when_prefixed=stDisp8,
|
||||
clobbers_flags=False,
|
||||
emit='''
|
||||
if !flags.notrap() {
|
||||
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||
}
|
||||
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
||||
modrm_disp8(in_reg1, in_reg0, sink);
|
||||
let offset: i32 = offset.into();
|
||||
@@ -731,6 +752,9 @@ fstDisp8 = TailRecipe(
|
||||
instp=IsSignedInt(Store.offset, 8),
|
||||
clobbers_flags=False,
|
||||
emit='''
|
||||
if !flags.notrap() {
|
||||
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||
}
|
||||
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
||||
modrm_disp8(in_reg1, in_reg0, sink);
|
||||
let offset: i32 = offset.into();
|
||||
@@ -742,6 +766,9 @@ stDisp32 = TailRecipe(
|
||||
'stDisp32', Store, size=5, ins=(GPR, GPR_DEREF_SAFE), outs=(),
|
||||
clobbers_flags=False,
|
||||
emit='''
|
||||
if !flags.notrap() {
|
||||
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||
}
|
||||
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
||||
modrm_disp32(in_reg1, in_reg0, sink);
|
||||
let offset: i32 = offset.into();
|
||||
@@ -752,6 +779,9 @@ stDisp32_abcd = TailRecipe(
|
||||
when_prefixed=stDisp32,
|
||||
clobbers_flags=False,
|
||||
emit='''
|
||||
if !flags.notrap() {
|
||||
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||
}
|
||||
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
||||
modrm_disp32(in_reg1, in_reg0, sink);
|
||||
let offset: i32 = offset.into();
|
||||
@@ -761,6 +791,9 @@ fstDisp32 = TailRecipe(
|
||||
'fstDisp32', Store, size=5, ins=(FPR, GPR_DEREF_SAFE), outs=(),
|
||||
clobbers_flags=False,
|
||||
emit='''
|
||||
if !flags.notrap() {
|
||||
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||
}
|
||||
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
||||
modrm_disp32(in_reg1, in_reg0, sink);
|
||||
let offset: i32 = offset.into();
|
||||
@@ -827,6 +860,9 @@ ld = TailRecipe(
|
||||
instp=IsEqual(Load.offset, 0),
|
||||
clobbers_flags=False,
|
||||
emit='''
|
||||
if !flags.notrap() {
|
||||
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||
}
|
||||
PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
|
||||
modrm_rm(in_reg0, out_reg0, sink);
|
||||
''')
|
||||
@@ -837,6 +873,9 @@ fld = TailRecipe(
|
||||
instp=IsEqual(Load.offset, 0),
|
||||
clobbers_flags=False,
|
||||
emit='''
|
||||
if !flags.notrap() {
|
||||
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||
}
|
||||
PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
|
||||
modrm_rm(in_reg0, out_reg0, sink);
|
||||
''')
|
||||
@@ -847,6 +886,9 @@ ldDisp8 = TailRecipe(
|
||||
instp=IsSignedInt(Load.offset, 8),
|
||||
clobbers_flags=False,
|
||||
emit='''
|
||||
if !flags.notrap() {
|
||||
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||
}
|
||||
PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
|
||||
modrm_disp8(in_reg0, out_reg0, sink);
|
||||
let offset: i32 = offset.into();
|
||||
@@ -859,6 +901,9 @@ fldDisp8 = TailRecipe(
|
||||
instp=IsSignedInt(Load.offset, 8),
|
||||
clobbers_flags=False,
|
||||
emit='''
|
||||
if !flags.notrap() {
|
||||
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||
}
|
||||
PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
|
||||
modrm_disp8(in_reg0, out_reg0, sink);
|
||||
let offset: i32 = offset.into();
|
||||
@@ -871,6 +916,9 @@ ldDisp32 = TailRecipe(
|
||||
instp=IsSignedInt(Load.offset, 32),
|
||||
clobbers_flags=False,
|
||||
emit='''
|
||||
if !flags.notrap() {
|
||||
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||
}
|
||||
PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
|
||||
modrm_disp32(in_reg0, out_reg0, sink);
|
||||
let offset: i32 = offset.into();
|
||||
@@ -883,6 +931,9 @@ fldDisp32 = TailRecipe(
|
||||
instp=IsSignedInt(Load.offset, 32),
|
||||
clobbers_flags=False,
|
||||
emit='''
|
||||
if !flags.notrap() {
|
||||
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||
}
|
||||
PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
|
||||
modrm_disp32(in_reg0, out_reg0, sink);
|
||||
let offset: i32 = offset.into();
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
//! relocations to a `RelocSink` trait object. Relocations are less frequent than the
|
||||
//! `CodeSink::put*` methods, so the performance impact of the virtual callbacks is less severe.
|
||||
|
||||
use ir::{ExternalName, JumpTable};
|
||||
use ir::{ExternalName, JumpTable, TrapCode, SourceLoc};
|
||||
use super::{CodeSink, CodeOffset, Reloc, Addend};
|
||||
use std::ptr::write_unaligned;
|
||||
|
||||
@@ -33,15 +33,21 @@ pub struct MemoryCodeSink<'a> {
|
||||
data: *mut u8,
|
||||
offset: isize,
|
||||
relocs: &'a mut RelocSink,
|
||||
traps: &'a mut TrapSink,
|
||||
}
|
||||
|
||||
impl<'a> MemoryCodeSink<'a> {
|
||||
/// Create a new memory code sink that writes a function to the memory pointed to by `data`.
|
||||
pub fn new(data: *mut u8, relocs: &mut RelocSink) -> MemoryCodeSink {
|
||||
pub fn new<'sink>(
|
||||
data: *mut u8,
|
||||
relocs: &'sink mut RelocSink,
|
||||
traps: &'sink mut TrapSink,
|
||||
) -> MemoryCodeSink<'sink> {
|
||||
MemoryCodeSink {
|
||||
data,
|
||||
offset: 0,
|
||||
relocs,
|
||||
traps,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,6 +64,12 @@ pub trait RelocSink {
|
||||
fn reloc_jt(&mut self, CodeOffset, Reloc, JumpTable);
|
||||
}
|
||||
|
||||
/// A trait for receiving trap codes and offsets.
|
||||
pub trait TrapSink {
|
||||
/// Add trap information for a specific offset.
|
||||
fn trap(&mut self, CodeOffset, SourceLoc, TrapCode);
|
||||
}
|
||||
|
||||
impl<'a> CodeSink for MemoryCodeSink<'a> {
|
||||
fn offset(&self) -> CodeOffset {
|
||||
self.offset as CodeOffset
|
||||
@@ -105,4 +117,9 @@ impl<'a> CodeSink for MemoryCodeSink<'a> {
|
||||
let ofs = self.offset();
|
||||
self.relocs.reloc_jt(ofs, rel, jt);
|
||||
}
|
||||
|
||||
fn trap(&mut self, code: TrapCode, srcloc: SourceLoc) {
|
||||
let ofs = self.offset();
|
||||
self.traps.trap(ofs, srcloc, code);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,9 @@ mod memorysink;
|
||||
|
||||
pub use regalloc::RegDiversions;
|
||||
pub use self::relaxation::relax_branches;
|
||||
pub use self::memorysink::{MemoryCodeSink, RelocSink};
|
||||
pub use self::memorysink::{MemoryCodeSink, RelocSink, TrapSink};
|
||||
|
||||
use ir::{ExternalName, JumpTable, Function, Inst};
|
||||
use ir::{ExternalName, JumpTable, Function, Inst, TrapCode, SourceLoc};
|
||||
use std::fmt;
|
||||
|
||||
/// Offset in bytes from the beginning of the function.
|
||||
@@ -86,6 +86,9 @@ pub trait CodeSink {
|
||||
|
||||
/// Add a relocation referencing a jump table.
|
||||
fn reloc_jt(&mut self, Reloc, JumpTable);
|
||||
|
||||
/// Add trap information for the current offset.
|
||||
fn trap(&mut self, TrapCode, SourceLoc);
|
||||
}
|
||||
|
||||
/// Report a bad encoding error.
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
//! contexts concurrently. Typically, you would have one context per compilation thread and only a
|
||||
//! single ISA instance.
|
||||
|
||||
use binemit::{CodeOffset, relax_branches, MemoryCodeSink, RelocSink};
|
||||
use binemit::{CodeOffset, relax_branches, MemoryCodeSink, RelocSink, TrapSink};
|
||||
use dominator_tree::DominatorTree;
|
||||
use flowgraph::ControlFlowGraph;
|
||||
use ir::Function;
|
||||
@@ -111,9 +111,15 @@ impl Context {
|
||||
/// code is returned by `compile` above.
|
||||
///
|
||||
/// The machine code is not relocated. Instead, any relocations are emitted into `relocs`.
|
||||
pub fn emit_to_memory(&self, mem: *mut u8, relocs: &mut RelocSink, isa: &TargetIsa) {
|
||||
pub fn emit_to_memory(
|
||||
&self,
|
||||
mem: *mut u8,
|
||||
relocs: &mut RelocSink,
|
||||
traps: &mut TrapSink,
|
||||
isa: &TargetIsa,
|
||||
) {
|
||||
let _tt = timing::binemit();
|
||||
isa.emit_function(&self.func, &mut MemoryCodeSink::new(mem, relocs));
|
||||
isa.emit_function(&self.func, &mut MemoryCodeSink::new(mem, relocs, traps));
|
||||
}
|
||||
|
||||
/// Run the verifier on the function.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Emitting binary Intel machine code.
|
||||
|
||||
use binemit::{CodeSink, Reloc, bad_encoding};
|
||||
use ir::{Function, Inst, Ebb, InstructionData, Opcode};
|
||||
use ir::{Function, Inst, Ebb, InstructionData, Opcode, TrapCode};
|
||||
use ir::condcodes::{CondCode, IntCC, FloatCC};
|
||||
use isa::{RegUnit, StackRef, StackBase, StackBaseMask};
|
||||
use regalloc::RegDiversions;
|
||||
|
||||
@@ -102,6 +102,10 @@ impl binemit::CodeSink for TextSink {
|
||||
fn reloc_jt(&mut self, reloc: binemit::Reloc, jt: ir::JumpTable) {
|
||||
write!(self.text, "{}({}) ", reloc, jt).unwrap();
|
||||
}
|
||||
|
||||
fn trap(&mut self, code: ir::TrapCode, _srcloc: ir::SourceLoc) {
|
||||
write!(self.text, "{} ", code).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl SubTest for TestBinEmit {
|
||||
|
||||
@@ -111,4 +111,5 @@ impl binemit::CodeSink for SizeSink {
|
||||
) {
|
||||
}
|
||||
fn reloc_jt(&mut self, _reloc: binemit::Reloc, _jt: ir::JumpTable) {}
|
||||
fn trap(&mut self, _code: ir::TrapCode, _srcloc: ir::SourceLoc) {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user