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

@@ -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
Ok(match func.signature.call_conv {
CallConv::Fast | CallConv::Cold | CallConv::SystemV => {
super::unwind::systemv::create_unwind_info(func, isa, Some(RU::rbp.into()))?
.map(|u| UnwindInfo::SystemV(u))
super::unwind::systemv::create_unwind_info(func, isa)?.map(|u| UnwindInfo::SystemV(u))
}
CallConv::WindowsFastcall => {
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(
func: &Function,
isa: &dyn TargetIsa,
frame_register: Option<RegUnit>,
) -> CodegenResult<Option<UnwindInfo<RegUnit>>> {
// Find last block based on max offset.
let last_block = func
@@ -36,10 +35,13 @@ pub(crate) fn create_unwind_info(
.map(|(i, b)| (*b, *i))
.collect::<HashMap<_, _>>();
let word_size = isa.pointer_bytes();
let mut stack_size = None;
let mut prologue_size = 0;
let mut prologue_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.
let mut blocks = func
@@ -93,7 +95,15 @@ pub(crate) fn create_unwind_info(
match opcode {
Opcode::X86Push => {
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 => {
let stack_size =
@@ -160,7 +170,7 @@ pub(crate) fn create_unwind_info(
// Note: the stack_offset here is relative to an adjusted SP
if dst == (RU::rsp as RegUnit) && FPR.contains(src) {
let stack_offset: i32 = stack_offset.into();
unwind_codes.push(UnwindCode::SaveXmmRegister {
unwind_codes.push(UnwindCode::SaveRegister {
offset,
reg: src,
stack_offset: stack_offset as u32,
@@ -168,12 +178,11 @@ pub(crate) fn create_unwind_info(
}
}
}
InstructionData::CopySpecial { src, dst, .. } => {
if let Some(fp) = frame_register {
// Check for change in CFA register (RSP is always the starting CFA)
if src == (RU::rsp as RegUnit) && dst == fp {
unwind_codes.push(UnwindCode::SetFramePointer { offset, reg: dst });
}
InstructionData::CopySpecial { src, dst, .. } if frame_register.is_none() => {
// Check for change in CFA register (RSP is always the starting CFA)
if src == (RU::rsp as RegUnit) {
unwind_codes.push(UnwindCode::SetFramePointer { offset, reg: dst });
frame_register = Some(dst);
}
}
InstructionData::NullAry { opcode } => match opcode {
@@ -195,9 +204,15 @@ pub(crate) fn create_unwind_info(
let reg = func.locations[*arg].unwrap_reg();
unwind_codes.push(UnwindCode::RestoreRegister { offset, reg });
unwind_codes.push(UnwindCode::StackDealloc {
offset,
size: word_size.into(),
});
}
epilogue_pop_offsets.clear();
// TODO ensure unwind codes sorted by offsets ?
if !is_last_block {
unwind_codes.push(UnwindCode::RestoreState { offset });
}
@@ -216,6 +231,7 @@ pub(crate) fn create_unwind_info(
prologue_unwind_codes,
epilogues_unwind_codes,
function_size,
word_size,
}))
}
@@ -246,7 +262,7 @@ mod tests {
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("expected unwind info");
@@ -255,9 +271,15 @@ mod tests {
UnwindInfo {
prologue_size: 9,
prologue_unwind_codes: vec![
UnwindCode::StackAlloc { offset: 2, size: 8 },
UnwindCode::SaveRegister {
offset: 2,
reg: RU::rbp.into(),
stack_offset: 0,
},
UnwindCode::SetFramePointer {
offset: 5,
reg: RU::rbp.into(),
},
UnwindCode::StackAlloc {
offset: 9,
@@ -272,9 +294,14 @@ mod tests {
UnwindCode::RestoreRegister {
offset: 15,
reg: RU::rbp.into()
},
UnwindCode::StackDealloc {
offset: 15,
size: 8
}
]],
function_size: 16,
word_size: 8,
}
);
}
@@ -293,7 +320,7 @@ mod tests {
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("expected unwind info");
@@ -302,9 +329,15 @@ mod tests {
UnwindInfo {
prologue_size: 27,
prologue_unwind_codes: vec![
UnwindCode::StackAlloc { offset: 2, size: 8 },
UnwindCode::SaveRegister {
offset: 2,
reg: RU::rbp.into(),
stack_offset: 0,
},
UnwindCode::SetFramePointer {
offset: 5,
reg: RU::rbp.into(),
},
UnwindCode::StackAlloc {
offset: 27,
@@ -319,9 +352,14 @@ mod tests {
UnwindCode::RestoreRegister {
offset: 36,
reg: RU::rbp.into()
},
UnwindCode::StackDealloc {
offset: 36,
size: 8
}
]],
function_size: 37,
word_size: 8,
}
);
}
@@ -340,7 +378,7 @@ mod tests {
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("expected unwind info");
@@ -349,9 +387,15 @@ mod tests {
UnwindInfo {
prologue_size: 27,
prologue_unwind_codes: vec![
UnwindCode::StackAlloc { offset: 2, size: 8 },
UnwindCode::SaveRegister {
offset: 2,
reg: RU::rbp.into(),
stack_offset: 0,
},
UnwindCode::SetFramePointer {
offset: 5,
reg: RU::rbp.into(),
},
UnwindCode::StackAlloc {
offset: 27,
@@ -366,9 +410,14 @@ mod tests {
UnwindCode::RestoreRegister {
offset: 36,
reg: RU::rbp.into()
},
UnwindCode::StackDealloc {
offset: 36,
size: 8
}
]],
function_size: 37,
word_size: 8,
}
);
}
@@ -400,7 +449,7 @@ mod tests {
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("expected unwind info");
@@ -409,9 +458,11 @@ mod tests {
UnwindInfo {
prologue_size: 5,
prologue_unwind_codes: vec![
UnwindCode::StackAlloc { offset: 2, size: 8 },
UnwindCode::SaveRegister {
offset: 2,
reg: RU::rbp.into()
reg: RU::rbp.into(),
stack_offset: 0,
},
UnwindCode::SetFramePointer {
offset: 5,
@@ -425,14 +476,25 @@ mod tests {
offset: 12,
reg: RU::rbp.into()
},
UnwindCode::StackDealloc {
offset: 12,
size: 8
},
UnwindCode::RestoreState { offset: 13 }
],
vec![UnwindCode::RestoreRegister {
offset: 15,
reg: RU::rbp.into()
}]
vec![
UnwindCode::RestoreRegister {
offset: 15,
reg: RU::rbp.into()
},
UnwindCode::StackDealloc {
offset: 15,
size: 8
}
]
],
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(
func: &Function,
isa: &dyn TargetIsa,
frame_register: Option<RegUnit>,
) -> CodegenResult<Option<UnwindInfo>> {
// Only System V-like calling conventions are supported
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 {
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,
None => {
return Ok(None);
@@ -126,12 +124,7 @@ pub(crate) fn create_unwind_info(
}
let map = RegisterMapper(isa);
Ok(Some(UnwindInfo::build(
unwind,
WORD_SIZE,
frame_register,
&map,
)?))
Ok(Some(UnwindInfo::build(unwind, &map)?))
}
#[cfg(test)]
@@ -172,7 +165,7 @@ mod tests {
_ => 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 {
@@ -212,7 +205,7 @@ mod tests {
_ => 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 {

View File

@@ -14,7 +14,7 @@ pub(crate) fn create_unwind_info(
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,
None => {
return Ok(None);
@@ -27,12 +27,12 @@ pub(crate) fn create_unwind_info(
struct 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) {
GPR.index_of(reg) as u8
MappedRegister::Int(GPR.index_of(reg) as u8)
} else if FPR.contains(reg) {
// XMM register
reg as u8
MappedRegister::Xmm(reg as u8)
} else {
panic!()
}