Refactor UnwindInfo codes and frame_register (#2307)

* Refactor UnwindInfo codes and frame_register

* use isa word_size

* fix filetests

* Add comment about UnwindCode::PushRegister
This commit is contained in:
Yury Delendik
2020-10-22 14:52:42 -05:00
committed by GitHub
parent 4f104d3a4e
commit b10e027fef
8 changed files with 219 additions and 128 deletions

View File

@@ -27,16 +27,12 @@ pub(crate) mod input {
SaveRegister { SaveRegister {
offset: CodeOffset, offset: CodeOffset,
reg: Reg, reg: Reg,
stack_offset: u32,
}, },
RestoreRegister { RestoreRegister {
offset: CodeOffset, offset: CodeOffset,
reg: Reg, reg: Reg,
}, },
SaveXmmRegister {
offset: CodeOffset,
reg: Reg,
stack_offset: u32,
},
StackAlloc { StackAlloc {
offset: CodeOffset, offset: CodeOffset,
size: u32, size: u32,
@@ -64,5 +60,6 @@ pub(crate) mod input {
pub(crate) prologue_unwind_codes: Vec<UnwindCode<Reg>>, pub(crate) prologue_unwind_codes: Vec<UnwindCode<Reg>>,
pub(crate) epilogues_unwind_codes: Vec<Vec<UnwindCode<Reg>>>, pub(crate) epilogues_unwind_codes: Vec<Vec<UnwindCode<Reg>>>,
pub(crate) function_size: CodeOffset, pub(crate) function_size: CodeOffset,
pub(crate) word_size: u8,
} }
} }

View File

@@ -115,12 +115,10 @@ pub struct UnwindInfo {
impl UnwindInfo { impl UnwindInfo {
pub(crate) fn build<'b>( pub(crate) fn build<'b>(
unwind: input::UnwindInfo<RegUnit>, unwind: input::UnwindInfo<RegUnit>,
word_size: u8,
frame_register: Option<RegUnit>,
map_reg: &'b dyn RegisterMapper, map_reg: &'b dyn RegisterMapper,
) -> CodegenResult<Self> { ) -> CodegenResult<Self> {
use input::UnwindCode; use input::UnwindCode;
let mut builder = InstructionBuilder::new(word_size, frame_register, map_reg); let mut builder = InstructionBuilder::new(unwind.word_size, map_reg);
for c in unwind.prologue_unwind_codes.iter().chain( for c in unwind.prologue_unwind_codes.iter().chain(
unwind unwind
@@ -130,9 +128,13 @@ impl UnwindInfo {
.flatten(), .flatten(),
) { ) {
match c { match c {
UnwindCode::SaveRegister { offset, reg } => { UnwindCode::SaveRegister {
offset,
reg,
stack_offset: 0,
} => {
builder builder
.push_reg(*offset, *reg) .save_reg(*offset, *reg)
.map_err(CodegenError::RegisterMappingError)?; .map_err(CodegenError::RegisterMappingError)?;
} }
UnwindCode::StackAlloc { offset, size } => { UnwindCode::StackAlloc { offset, size } => {
@@ -143,7 +145,7 @@ impl UnwindInfo {
} }
UnwindCode::RestoreRegister { offset, reg } => { UnwindCode::RestoreRegister { offset, reg } => {
builder builder
.pop_reg(*offset, *reg) .restore_reg(*offset, *reg)
.map_err(CodegenError::RegisterMappingError)?; .map_err(CodegenError::RegisterMappingError)?;
} }
UnwindCode::SetFramePointer { offset, reg } => { UnwindCode::SetFramePointer { offset, reg } => {
@@ -180,46 +182,29 @@ impl UnwindInfo {
} }
struct InstructionBuilder<'a> { struct InstructionBuilder<'a> {
word_size: u8, sp_offset: i32,
cfa_offset: i32,
saved_state: Option<i32>,
frame_register: Option<RegUnit>, frame_register: Option<RegUnit>,
saved_state: Option<(i32, Option<RegUnit>)>,
map_reg: &'a dyn RegisterMapper, map_reg: &'a dyn RegisterMapper,
instructions: Vec<(u32, CallFrameInstruction)>, instructions: Vec<(u32, CallFrameInstruction)>,
} }
impl<'a> InstructionBuilder<'a> { impl<'a> InstructionBuilder<'a> {
fn new( fn new(word_size: u8, map_reg: &'a (dyn RegisterMapper + 'a)) -> Self {
word_size: u8,
frame_register: Option<RegUnit>,
map_reg: &'a (dyn RegisterMapper + 'a),
) -> Self {
Self { Self {
word_size, sp_offset: word_size as i32, // CFA offset starts at word size offset to account for the return address on stack
cfa_offset: word_size as i32, // CFA offset starts at word size offset to account for the return address on stack
saved_state: None, saved_state: None,
frame_register, frame_register: None,
map_reg, map_reg,
instructions: Vec::new(), instructions: Vec::new(),
} }
} }
fn push_reg(&mut self, offset: u32, reg: RegUnit) -> Result<(), RegisterMappingError> { fn save_reg(&mut self, offset: u32, reg: RegUnit) -> Result<(), RegisterMappingError> {
self.cfa_offset += self.word_size as i32;
// Update the CFA if this is the save of the frame pointer register or if a frame pointer isn't being used
// When using a frame pointer, we only need to update the CFA to account for the push of the frame pointer itself
if match self.frame_register {
Some(fp) => reg == fp,
None => true,
} {
self.instructions
.push((offset, CallFrameInstruction::CfaOffset(self.cfa_offset)));
}
// Pushes in the prologue are register saves, so record an offset of the save // Pushes in the prologue are register saves, so record an offset of the save
self.instructions.push(( self.instructions.push((
offset, offset,
CallFrameInstruction::Offset(self.map_reg.map(reg)?, -self.cfa_offset), CallFrameInstruction::Offset(self.map_reg.map(reg)?, -self.sp_offset),
)); ));
Ok(()) Ok(())
@@ -228,27 +213,52 @@ impl<'a> InstructionBuilder<'a> {
fn adjust_sp_down_imm(&mut self, offset: u32, imm: i64) { fn adjust_sp_down_imm(&mut self, offset: u32, imm: i64) {
assert!(imm <= core::u32::MAX as i64); assert!(imm <= core::u32::MAX as i64);
self.sp_offset += imm as i32;
// Don't adjust the CFA if we're using a frame pointer // Don't adjust the CFA if we're using a frame pointer
if self.frame_register.is_some() { if self.frame_register.is_some() {
return; return;
} }
self.cfa_offset += imm as i32;
self.instructions self.instructions
.push((offset, CallFrameInstruction::CfaOffset(self.cfa_offset))); .push((offset, CallFrameInstruction::CfaOffset(self.sp_offset)));
} }
fn adjust_sp_up_imm(&mut self, offset: u32, imm: i64) { fn adjust_sp_up_imm(&mut self, offset: u32, imm: i64) {
assert!(imm <= core::u32::MAX as i64); assert!(imm <= core::u32::MAX as i64);
self.sp_offset -= imm as i32;
// Don't adjust the CFA if we're using a frame pointer // Don't adjust the CFA if we're using a frame pointer
if self.frame_register.is_some() { if self.frame_register.is_some() {
return; return;
} }
self.cfa_offset -= imm as i32; let cfa_inst_ofs = {
self.instructions // Scan to find and merge with CFA instruction with the same offset.
.push((offset, CallFrameInstruction::CfaOffset(self.cfa_offset))); let mut it = self.instructions.iter_mut();
loop {
match it.next_back() {
Some((i_offset, i)) if *i_offset == offset => {
if let CallFrameInstruction::Cfa(_, o) = i {
break Some(o);
}
}
_ => {
break None;
}
}
}
};
if let Some(o) = cfa_inst_ofs {
// Update previous CFA instruction.
*o = self.sp_offset;
} else {
// Add just CFA offset instruction.
self.instructions
.push((offset, CallFrameInstruction::CfaOffset(self.sp_offset)));
}
} }
fn set_cfa_reg(&mut self, offset: u32, reg: RegUnit) -> Result<(), RegisterMappingError> { fn set_cfa_reg(&mut self, offset: u32, reg: RegUnit) -> Result<(), RegisterMappingError> {
@@ -256,48 +266,39 @@ impl<'a> InstructionBuilder<'a> {
offset, offset,
CallFrameInstruction::CfaRegister(self.map_reg.map(reg)?), CallFrameInstruction::CfaRegister(self.map_reg.map(reg)?),
)); ));
self.frame_register = Some(reg);
Ok(()) Ok(())
} }
fn pop_reg(&mut self, offset: u32, reg: RegUnit) -> Result<(), RegisterMappingError> { fn restore_reg(&mut self, offset: u32, reg: RegUnit) -> Result<(), RegisterMappingError> {
self.cfa_offset -= self.word_size as i32; // Update the CFA if this is the restore of the frame pointer register.
if Some(reg) == self.frame_register {
// Update the CFA if this is the restore of the frame pointer register or if a frame pointer isn't being used self.frame_register = None;
match self.frame_register { self.instructions.push((
Some(fp) => { offset,
if reg == fp { CallFrameInstruction::Cfa(self.map_reg.rsp(), self.sp_offset),
self.instructions.push(( ));
offset, }
CallFrameInstruction::Cfa(self.map_reg.rsp(), self.cfa_offset), // Pops in the epilogue are register restores, so record a "same value" for the register
)); self.instructions.push((
} offset,
} CallFrameInstruction::SameValue(self.map_reg.map(reg)?),
None => { ));
self.instructions
.push((offset, CallFrameInstruction::CfaOffset(self.cfa_offset)));
// Pops in the epilogue are register restores, so record a "same value" for the register
// This isn't necessary when using a frame pointer as the CFA doesn't change for CSR restores
self.instructions.push((
offset,
CallFrameInstruction::SameValue(self.map_reg.map(reg)?),
));
}
};
Ok(()) Ok(())
} }
fn remember_state(&mut self, offset: u32) { fn remember_state(&mut self, offset: u32) {
self.saved_state = Some(self.cfa_offset); self.saved_state = Some((self.sp_offset, self.frame_register));
self.instructions self.instructions
.push((offset, CallFrameInstruction::RememberState)); .push((offset, CallFrameInstruction::RememberState));
} }
fn restore_state(&mut self, offset: u32) { fn restore_state(&mut self, offset: u32) {
let cfa_offset = self.saved_state.take().unwrap(); let (sp_offset, frame_register) = self.saved_state.take().unwrap();
self.cfa_offset = cfa_offset; self.sp_offset = sp_offset;
self.frame_register = frame_register;
self.instructions self.instructions
.push((offset, CallFrameInstruction::RestoreState)); .push((offset, CallFrameInstruction::RestoreState));

View File

@@ -137,10 +137,15 @@ impl UnwindCode {
} }
} }
pub(crate) enum MappedRegister {
Int(u8),
Xmm(u8),
}
/// Maps UnwindInfo register to Windows x64 unwind data. /// Maps UnwindInfo register to Windows x64 unwind data.
pub(crate) trait RegisterMapper { pub(crate) trait RegisterMapper {
/// Maps RegUnit. /// Maps RegUnit.
fn map(reg: RegUnit) -> u8; fn map(reg: RegUnit) -> MappedRegister;
} }
/// Represents Windows x64 unwind information. /// Represents Windows x64 unwind information.
@@ -219,14 +224,50 @@ impl UnwindInfo {
) -> CodegenResult<Self> { ) -> CodegenResult<Self> {
use crate::isa::unwind::input::UnwindCode as InputUnwindCode; use crate::isa::unwind::input::UnwindCode as InputUnwindCode;
let word_size: u32 = unwind.word_size.into();
let mut unwind_codes = Vec::new(); let mut unwind_codes = Vec::new();
for c in unwind.prologue_unwind_codes.iter() { for c in unwind.prologue_unwind_codes.iter() {
match c { match c {
InputUnwindCode::SaveRegister { offset, reg } => { InputUnwindCode::SaveRegister {
unwind_codes.push(UnwindCode::PushRegister { offset,
offset: ensure_unwind_offset(*offset)?, reg,
reg: MR::map(*reg), stack_offset,
}); } => {
let reg = MR::map(*reg);
let offset = ensure_unwind_offset(*offset)?;
match reg {
MappedRegister::Int(reg) => {
// Attempt to convert sequence of the `InputUnwindCode`:
// `StackAlloc { size = word_size }`, `SaveRegister { stack_offset: 0 }`
// to the shorter `UnwindCode::PushRegister`.
let push_reg_sequence = if let Some(UnwindCode::StackAlloc {
offset: alloc_offset,
size,
}) = unwind_codes.last()
{
*size == word_size && offset == *alloc_offset && *stack_offset == 0
} else {
false
};
if push_reg_sequence {
*unwind_codes.last_mut().unwrap() =
UnwindCode::PushRegister { offset, reg };
} else {
// TODO add `UnwindCode::SaveRegister` to handle multiple register
// pushes with single `UnwindCode::StackAlloc`.
return Err(CodegenError::Unsupported(
"Unsupported UnwindCode::PushRegister sequence".into(),
));
}
}
MappedRegister::Xmm(reg) => {
unwind_codes.push(UnwindCode::SaveXmm {
offset,
reg,
stack_offset: *stack_offset,
});
}
}
} }
InputUnwindCode::StackAlloc { offset, size } => { InputUnwindCode::StackAlloc { offset, size } => {
unwind_codes.push(UnwindCode::StackAlloc { unwind_codes.push(UnwindCode::StackAlloc {
@@ -234,17 +275,6 @@ impl UnwindInfo {
size: *size, size: *size,
}); });
} }
InputUnwindCode::SaveXmmRegister {
offset,
reg,
stack_offset,
} => {
unwind_codes.push(UnwindCode::SaveXmm {
offset: ensure_unwind_offset(*offset)?,
reg: MR::map(*reg),
stack_offset: *stack_offset,
});
}
_ => {} _ => {}
} }
} }

View File

@@ -1083,8 +1083,7 @@ pub fn create_unwind_info(
// In the future, we should be omitting frame pointer as an optimization, so this will change // In the future, we should be omitting frame pointer as an optimization, so this will change
Ok(match func.signature.call_conv { Ok(match func.signature.call_conv {
CallConv::Fast | CallConv::Cold | CallConv::SystemV => { CallConv::Fast | CallConv::Cold | CallConv::SystemV => {
super::unwind::systemv::create_unwind_info(func, isa, Some(RU::rbp.into()))? super::unwind::systemv::create_unwind_info(func, isa)?.map(|u| UnwindInfo::SystemV(u))
.map(|u| UnwindInfo::SystemV(u))
} }
CallConv::WindowsFastcall => { CallConv::WindowsFastcall => {
super::unwind::winx64::create_unwind_info(func, isa)?.map(|u| UnwindInfo::WindowsX64(u)) super::unwind::winx64::create_unwind_info(func, isa)?.map(|u| UnwindInfo::WindowsX64(u))

View File

@@ -15,7 +15,6 @@ use crate::isa::unwind::input::{UnwindCode, UnwindInfo};
pub(crate) fn create_unwind_info( pub(crate) fn create_unwind_info(
func: &Function, func: &Function,
isa: &dyn TargetIsa, isa: &dyn TargetIsa,
frame_register: Option<RegUnit>,
) -> CodegenResult<Option<UnwindInfo<RegUnit>>> { ) -> CodegenResult<Option<UnwindInfo<RegUnit>>> {
// Find last block based on max offset. // Find last block based on max offset.
let last_block = func let last_block = func
@@ -36,10 +35,13 @@ pub(crate) fn create_unwind_info(
.map(|(i, b)| (*b, *i)) .map(|(i, b)| (*b, *i))
.collect::<HashMap<_, _>>(); .collect::<HashMap<_, _>>();
let word_size = isa.pointer_bytes();
let mut stack_size = None; let mut stack_size = None;
let mut prologue_size = 0; let mut prologue_size = 0;
let mut prologue_unwind_codes = Vec::new(); let mut prologue_unwind_codes = Vec::new();
let mut epilogues_unwind_codes = Vec::new(); let mut epilogues_unwind_codes = Vec::new();
let mut frame_register: Option<RegUnit> = None;
// Process only entry block and blocks with epilogues. // Process only entry block and blocks with epilogues.
let mut blocks = func let mut blocks = func
@@ -93,7 +95,15 @@ pub(crate) fn create_unwind_info(
match opcode { match opcode {
Opcode::X86Push => { Opcode::X86Push => {
let reg = func.locations[arg].unwrap_reg(); let reg = func.locations[arg].unwrap_reg();
unwind_codes.push(UnwindCode::SaveRegister { offset, reg }); unwind_codes.push(UnwindCode::StackAlloc {
offset,
size: word_size.into(),
});
unwind_codes.push(UnwindCode::SaveRegister {
offset,
reg,
stack_offset: 0,
});
} }
Opcode::AdjustSpDown => { Opcode::AdjustSpDown => {
let stack_size = let stack_size =
@@ -160,7 +170,7 @@ pub(crate) fn create_unwind_info(
// Note: the stack_offset here is relative to an adjusted SP // Note: the stack_offset here is relative to an adjusted SP
if dst == (RU::rsp as RegUnit) && FPR.contains(src) { if dst == (RU::rsp as RegUnit) && FPR.contains(src) {
let stack_offset: i32 = stack_offset.into(); let stack_offset: i32 = stack_offset.into();
unwind_codes.push(UnwindCode::SaveXmmRegister { unwind_codes.push(UnwindCode::SaveRegister {
offset, offset,
reg: src, reg: src,
stack_offset: stack_offset as u32, stack_offset: stack_offset as u32,
@@ -168,12 +178,11 @@ pub(crate) fn create_unwind_info(
} }
} }
} }
InstructionData::CopySpecial { src, dst, .. } => { InstructionData::CopySpecial { src, dst, .. } if frame_register.is_none() => {
if let Some(fp) = frame_register { // Check for change in CFA register (RSP is always the starting CFA)
// Check for change in CFA register (RSP is always the starting CFA) if src == (RU::rsp as RegUnit) {
if src == (RU::rsp as RegUnit) && dst == fp { unwind_codes.push(UnwindCode::SetFramePointer { offset, reg: dst });
unwind_codes.push(UnwindCode::SetFramePointer { offset, reg: dst }); frame_register = Some(dst);
}
} }
} }
InstructionData::NullAry { opcode } => match opcode { InstructionData::NullAry { opcode } => match opcode {
@@ -195,9 +204,15 @@ pub(crate) fn create_unwind_info(
let reg = func.locations[*arg].unwrap_reg(); let reg = func.locations[*arg].unwrap_reg();
unwind_codes.push(UnwindCode::RestoreRegister { offset, reg }); unwind_codes.push(UnwindCode::RestoreRegister { offset, reg });
unwind_codes.push(UnwindCode::StackDealloc {
offset,
size: word_size.into(),
});
} }
epilogue_pop_offsets.clear(); epilogue_pop_offsets.clear();
// TODO ensure unwind codes sorted by offsets ?
if !is_last_block { if !is_last_block {
unwind_codes.push(UnwindCode::RestoreState { offset }); unwind_codes.push(UnwindCode::RestoreState { offset });
} }
@@ -216,6 +231,7 @@ pub(crate) fn create_unwind_info(
prologue_unwind_codes, prologue_unwind_codes,
epilogues_unwind_codes, epilogues_unwind_codes,
function_size, function_size,
word_size,
})) }))
} }
@@ -246,7 +262,7 @@ mod tests {
context.compile(&*isa).expect("expected compilation"); context.compile(&*isa).expect("expected compilation");
let unwind = create_unwind_info(&context.func, &*isa, None) let unwind = create_unwind_info(&context.func, &*isa)
.expect("can create unwind info") .expect("can create unwind info")
.expect("expected unwind info"); .expect("expected unwind info");
@@ -255,9 +271,15 @@ mod tests {
UnwindInfo { UnwindInfo {
prologue_size: 9, prologue_size: 9,
prologue_unwind_codes: vec![ prologue_unwind_codes: vec![
UnwindCode::StackAlloc { offset: 2, size: 8 },
UnwindCode::SaveRegister { UnwindCode::SaveRegister {
offset: 2, offset: 2,
reg: RU::rbp.into(), reg: RU::rbp.into(),
stack_offset: 0,
},
UnwindCode::SetFramePointer {
offset: 5,
reg: RU::rbp.into(),
}, },
UnwindCode::StackAlloc { UnwindCode::StackAlloc {
offset: 9, offset: 9,
@@ -272,9 +294,14 @@ mod tests {
UnwindCode::RestoreRegister { UnwindCode::RestoreRegister {
offset: 15, offset: 15,
reg: RU::rbp.into() reg: RU::rbp.into()
},
UnwindCode::StackDealloc {
offset: 15,
size: 8
} }
]], ]],
function_size: 16, function_size: 16,
word_size: 8,
} }
); );
} }
@@ -293,7 +320,7 @@ mod tests {
context.compile(&*isa).expect("expected compilation"); context.compile(&*isa).expect("expected compilation");
let unwind = create_unwind_info(&context.func, &*isa, None) let unwind = create_unwind_info(&context.func, &*isa)
.expect("can create unwind info") .expect("can create unwind info")
.expect("expected unwind info"); .expect("expected unwind info");
@@ -302,9 +329,15 @@ mod tests {
UnwindInfo { UnwindInfo {
prologue_size: 27, prologue_size: 27,
prologue_unwind_codes: vec![ prologue_unwind_codes: vec![
UnwindCode::StackAlloc { offset: 2, size: 8 },
UnwindCode::SaveRegister { UnwindCode::SaveRegister {
offset: 2, offset: 2,
reg: RU::rbp.into(), reg: RU::rbp.into(),
stack_offset: 0,
},
UnwindCode::SetFramePointer {
offset: 5,
reg: RU::rbp.into(),
}, },
UnwindCode::StackAlloc { UnwindCode::StackAlloc {
offset: 27, offset: 27,
@@ -319,9 +352,14 @@ mod tests {
UnwindCode::RestoreRegister { UnwindCode::RestoreRegister {
offset: 36, offset: 36,
reg: RU::rbp.into() reg: RU::rbp.into()
},
UnwindCode::StackDealloc {
offset: 36,
size: 8
} }
]], ]],
function_size: 37, function_size: 37,
word_size: 8,
} }
); );
} }
@@ -340,7 +378,7 @@ mod tests {
context.compile(&*isa).expect("expected compilation"); context.compile(&*isa).expect("expected compilation");
let unwind = create_unwind_info(&context.func, &*isa, None) let unwind = create_unwind_info(&context.func, &*isa)
.expect("can create unwind info") .expect("can create unwind info")
.expect("expected unwind info"); .expect("expected unwind info");
@@ -349,9 +387,15 @@ mod tests {
UnwindInfo { UnwindInfo {
prologue_size: 27, prologue_size: 27,
prologue_unwind_codes: vec![ prologue_unwind_codes: vec![
UnwindCode::StackAlloc { offset: 2, size: 8 },
UnwindCode::SaveRegister { UnwindCode::SaveRegister {
offset: 2, offset: 2,
reg: RU::rbp.into(), reg: RU::rbp.into(),
stack_offset: 0,
},
UnwindCode::SetFramePointer {
offset: 5,
reg: RU::rbp.into(),
}, },
UnwindCode::StackAlloc { UnwindCode::StackAlloc {
offset: 27, offset: 27,
@@ -366,9 +410,14 @@ mod tests {
UnwindCode::RestoreRegister { UnwindCode::RestoreRegister {
offset: 36, offset: 36,
reg: RU::rbp.into() reg: RU::rbp.into()
},
UnwindCode::StackDealloc {
offset: 36,
size: 8
} }
]], ]],
function_size: 37, function_size: 37,
word_size: 8,
} }
); );
} }
@@ -400,7 +449,7 @@ mod tests {
context.compile(&*isa).expect("expected compilation"); context.compile(&*isa).expect("expected compilation");
let unwind = create_unwind_info(&context.func, &*isa, Some(RU::rbp.into())) let unwind = create_unwind_info(&context.func, &*isa)
.expect("can create unwind info") .expect("can create unwind info")
.expect("expected unwind info"); .expect("expected unwind info");
@@ -409,9 +458,11 @@ mod tests {
UnwindInfo { UnwindInfo {
prologue_size: 5, prologue_size: 5,
prologue_unwind_codes: vec![ prologue_unwind_codes: vec![
UnwindCode::StackAlloc { offset: 2, size: 8 },
UnwindCode::SaveRegister { UnwindCode::SaveRegister {
offset: 2, offset: 2,
reg: RU::rbp.into() reg: RU::rbp.into(),
stack_offset: 0,
}, },
UnwindCode::SetFramePointer { UnwindCode::SetFramePointer {
offset: 5, offset: 5,
@@ -425,14 +476,25 @@ mod tests {
offset: 12, offset: 12,
reg: RU::rbp.into() reg: RU::rbp.into()
}, },
UnwindCode::StackDealloc {
offset: 12,
size: 8
},
UnwindCode::RestoreState { offset: 13 } UnwindCode::RestoreState { offset: 13 }
], ],
vec![UnwindCode::RestoreRegister { vec![
offset: 15, UnwindCode::RestoreRegister {
reg: RU::rbp.into() offset: 15,
}] reg: RU::rbp.into()
},
UnwindCode::StackDealloc {
offset: 15,
size: 8
}
]
], ],
function_size: 16, function_size: 16,
word_size: 8,
} }
); );
} }

View File

@@ -95,7 +95,6 @@ pub fn map_reg(isa: &dyn TargetIsa, reg: RegUnit) -> Result<Register, RegisterMa
pub(crate) fn create_unwind_info( pub(crate) fn create_unwind_info(
func: &Function, func: &Function,
isa: &dyn TargetIsa, isa: &dyn TargetIsa,
frame_register: Option<RegUnit>,
) -> CodegenResult<Option<UnwindInfo>> { ) -> CodegenResult<Option<UnwindInfo>> {
// Only System V-like calling conventions are supported // Only System V-like calling conventions are supported
match func.signature.call_conv { match func.signature.call_conv {
@@ -106,9 +105,8 @@ pub(crate) fn create_unwind_info(
if func.prologue_end.is_none() || isa.name() != "x86" || isa.pointer_bits() != 64 { if func.prologue_end.is_none() || isa.name() != "x86" || isa.pointer_bits() != 64 {
return Ok(None); return Ok(None);
} }
const WORD_SIZE: u8 = 8; // bytes
let unwind = match super::create_unwind_info(func, isa, frame_register)? { let unwind = match super::create_unwind_info(func, isa)? {
Some(u) => u, Some(u) => u,
None => { None => {
return Ok(None); return Ok(None);
@@ -126,12 +124,7 @@ pub(crate) fn create_unwind_info(
} }
let map = RegisterMapper(isa); let map = RegisterMapper(isa);
Ok(Some(UnwindInfo::build( Ok(Some(UnwindInfo::build(unwind, &map)?))
unwind,
WORD_SIZE,
frame_register,
&map,
)?))
} }
#[cfg(test)] #[cfg(test)]
@@ -172,7 +165,7 @@ mod tests {
_ => panic!("expected unwind information"), _ => panic!("expected unwind information"),
}; };
assert_eq!(format!("{:?}", fde), "FrameDescriptionEntry { address: Constant(1234), length: 16, lsda: None, instructions: [(2, CfaOffset(16)), (2, Offset(Register(6), -16)), (5, CfaRegister(Register(6))), (15, Cfa(Register(7), 8))] }"); assert_eq!(format!("{:?}", fde), "FrameDescriptionEntry { address: Constant(1234), length: 16, lsda: None, instructions: [(2, CfaOffset(16)), (2, Offset(Register(6), -16)), (5, CfaRegister(Register(6))), (15, Cfa(Register(7), 8)), (15, SameValue(Register(6)))] }");
} }
fn create_function(call_conv: CallConv, stack_slot: Option<StackSlotData>) -> Function { fn create_function(call_conv: CallConv, stack_slot: Option<StackSlotData>) -> Function {
@@ -212,7 +205,7 @@ mod tests {
_ => panic!("expected unwind information"), _ => panic!("expected unwind information"),
}; };
assert_eq!(format!("{:?}", fde), "FrameDescriptionEntry { address: Constant(4321), length: 16, lsda: None, instructions: [(2, CfaOffset(16)), (2, Offset(Register(6), -16)), (5, CfaRegister(Register(6))), (12, RememberState), (12, Cfa(Register(7), 8)), (13, RestoreState), (15, Cfa(Register(7), 8))] }"); assert_eq!(format!("{:?}", fde), "FrameDescriptionEntry { address: Constant(4321), length: 16, lsda: None, instructions: [(2, CfaOffset(16)), (2, Offset(Register(6), -16)), (5, CfaRegister(Register(6))), (12, RememberState), (12, Cfa(Register(7), 8)), (12, SameValue(Register(6))), (13, RestoreState), (15, Cfa(Register(7), 8)), (15, SameValue(Register(6)))] }");
} }
fn create_multi_return_function(call_conv: CallConv) -> Function { fn create_multi_return_function(call_conv: CallConv) -> Function {

View File

@@ -14,7 +14,7 @@ pub(crate) fn create_unwind_info(
return Ok(None); return Ok(None);
} }
let unwind = match super::create_unwind_info(func, isa, None)? { let unwind = match super::create_unwind_info(func, isa)? {
Some(u) => u, Some(u) => u,
None => { None => {
return Ok(None); return Ok(None);
@@ -27,12 +27,12 @@ pub(crate) fn create_unwind_info(
struct RegisterMapper; struct RegisterMapper;
impl crate::isa::unwind::winx64::RegisterMapper for RegisterMapper { impl crate::isa::unwind::winx64::RegisterMapper for RegisterMapper {
fn map(reg: RegUnit) -> u8 { fn map(reg: RegUnit) -> crate::isa::unwind::winx64::MappedRegister {
use crate::isa::unwind::winx64::MappedRegister;
if GPR.contains(reg) { if GPR.contains(reg) {
GPR.index_of(reg) as u8 MappedRegister::Int(GPR.index_of(reg) as u8)
} else if FPR.contains(reg) { } else if FPR.contains(reg) {
// XMM register MappedRegister::Xmm(reg as u8)
reg as u8
} else { } else {
panic!() panic!()
} }

View File

@@ -38,7 +38,7 @@ block0:
; nextln: DW_CFA_def_cfa_register (r6) ; nextln: DW_CFA_def_cfa_register (r6)
; nextln: DW_CFA_advance_loc (1) ; nextln: DW_CFA_advance_loc (1)
; nextln: DW_CFA_def_cfa (r7, 8) ; nextln: DW_CFA_def_cfa (r7, 8)
; nextln: DW_CFA_nop ; nextln: DW_CFA_same_value (r6)
; nextln: DW_CFA_nop ; nextln: DW_CFA_nop
; check a function with medium-sized stack alloc ; check a function with medium-sized stack alloc
@@ -77,7 +77,7 @@ block0:
; nextln: DW_CFA_def_cfa_register (r6) ; nextln: DW_CFA_def_cfa_register (r6)
; nextln: DW_CFA_advance_loc (21) ; nextln: DW_CFA_advance_loc (21)
; nextln: DW_CFA_def_cfa (r7, 8) ; nextln: DW_CFA_def_cfa (r7, 8)
; nextln: DW_CFA_nop ; nextln: DW_CFA_same_value (r6)
; nextln: DW_CFA_nop ; nextln: DW_CFA_nop
; check a function with large-sized stack alloc ; check a function with large-sized stack alloc
@@ -116,7 +116,7 @@ block0:
; nextln: DW_CFA_def_cfa_register (r6) ; nextln: DW_CFA_def_cfa_register (r6)
; nextln: DW_CFA_advance_loc (21) ; nextln: DW_CFA_advance_loc (21)
; nextln: DW_CFA_def_cfa (r7, 8) ; nextln: DW_CFA_def_cfa (r7, 8)
; nextln: DW_CFA_nop ; nextln: DW_CFA_same_value (r6)
; nextln: DW_CFA_nop ; nextln: DW_CFA_nop
; nextln: ; nextln:
@@ -169,7 +169,7 @@ block0(v0: i64, v1: i64):
; nextln: ; nextln:
; nextln: ; nextln:
; nextln: 0x00000018: FDE ; nextln: 0x00000018: FDE
; nextln: length: 0x00000034 ; nextln: length: 0x00000044
; nextln: CIE_pointer: 0x00000000 ; nextln: CIE_pointer: 0x00000000
; nextln: start_addr: 0x0000000000000000 ; nextln: start_addr: 0x0000000000000000
; nextln: range_size: 0x0000000000000074 (end_addr = 0x0000000000000074) ; nextln: range_size: 0x0000000000000074 (end_addr = 0x0000000000000074)
@@ -189,9 +189,18 @@ block0(v0: i64, v1: i64):
; nextln: DW_CFA_offset (r14, 6) ; nextln: DW_CFA_offset (r14, 6)
; nextln: DW_CFA_advance_loc (2) ; nextln: DW_CFA_advance_loc (2)
; nextln: DW_CFA_offset (r15, 7) ; nextln: DW_CFA_offset (r15, 7)
; nextln: DW_CFA_advance_loc (102) ; nextln: DW_CFA_advance_loc (94)
; nextln: DW_CFA_same_value (r15)
; nextln: DW_CFA_advance_loc (2)
; nextln: DW_CFA_same_value (r14)
; nextln: DW_CFA_advance_loc (2)
; nextln: DW_CFA_same_value (r13)
; nextln: DW_CFA_advance_loc (2)
; nextln: DW_CFA_same_value (r12)
; nextln: DW_CFA_advance_loc (1)
; nextln: DW_CFA_same_value (r3)
; nextln: DW_CFA_advance_loc (1)
; nextln: DW_CFA_def_cfa (r7, 8) ; nextln: DW_CFA_def_cfa (r7, 8)
; nextln: DW_CFA_nop ; nextln: DW_CFA_same_value (r6)
; nextln: DW_CFA_nop
; nextln: DW_CFA_nop ; nextln: DW_CFA_nop
; nextln: DW_CFA_nop ; nextln: DW_CFA_nop