aboutsummaryrefslogtreecommitdiff
path: root/src/long_mode/display.rs
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2024-06-19 01:22:32 -0700
committeriximeow <me@iximeow.net>2024-06-19 01:32:27 -0700
commit85700ee8b91afcada27a9b4fffda498adf4573dc (patch)
tree5c6765a1701175fae03a0ac9ed6b1b3e96ab5dc3 /src/long_mode/display.rs
parentf6ad0a91226b12cb7ec928dbbb6983ea0425d9e2 (diff)
write_u64 helpers
Diffstat (limited to 'src/long_mode/display.rs')
-rw-r--r--src/long_mode/display.rs116
1 files changed, 78 insertions, 38 deletions
diff --git a/src/long_mode/display.rs b/src/long_mode/display.rs
index 2404847..d9f7f9e 100644
--- a/src/long_mode/display.rs
+++ b/src/long_mode/display.rs
@@ -428,6 +428,14 @@ pub trait DisplaySink: fmt::Write {
fn write_u32(&mut self, v: u32) -> Result<(), core::fmt::Error> {
write!(self, "{:x}", v)
}
+ /// write a u64 to the output as a base-16 integer.
+ ///
+ /// this is provided for optimization opportunities when the formatted integer can be written
+ /// directly to the sink (rather than formatted to an intermediate buffer and output as a
+ /// followup step)
+ fn write_u64(&mut self, v: u64) -> Result<(), core::fmt::Error> {
+ write!(self, "{:x}", v)
+ }
// fn write_char(&mut self, c: char) -> Result<(), core::fmt::Error>;
fn span_enter(&mut self, ty: TokenType);
fn span_end(&mut self, ty: TokenType);
@@ -830,6 +838,38 @@ impl DisplaySink for alloc::string::String {
Ok(())
}
+ /// write a u64 to the output as a base-16 integer.
+ ///
+ /// this is provided for optimization opportunities when the formatted integer can be written
+ /// directly to the sink (rather than formatted to an intermediate buffer and output as a
+ /// followup step)
+ #[inline(always)]
+ fn write_u64(&mut self, mut v: u64) -> Result<(), core::fmt::Error> {
+ // we can fairly easily predict the size of a formatted string here with lzcnt, which also
+ // means we can write directly into the correct offsets of the output string.
+ let printed_size = (((64 - v.leading_zeros()) >> 2) + 1) as usize;
+ self.reserve(printed_size);
+
+ unsafe {
+ let buf = unsafe { self.as_mut_vec() };
+ let p = buf.as_mut_ptr();
+ let mut curr = printed_size;
+ loop {
+ let digit = v % 16;
+ let c = c_to_hex(digit as u8);
+ curr -= 1;
+ p.offset(curr as isize).write(c);
+ v = v / 16;
+ if v == 0 {
+ break;
+ }
+ }
+
+ buf.set_len(buf.len() + printed_size);
+ }
+
+ Ok(())
+ }
fn span_enter(&mut self, ty: TokenType) {}
fn span_end(&mut self, ty: TokenType) {}
}
@@ -1161,6 +1201,37 @@ impl DisplaySink for BigEnoughString {
Ok(())
}
+ /// write a u64 to the output as a base-16 integer.
+ ///
+ /// this is provided for optimization opportunities when the formatted integer can be written
+ /// directly to the sink (rather than formatted to an intermediate buffer and output as a
+ /// followup step)
+ #[inline(always)]
+ fn write_u64(&mut self, mut v: u64) -> Result<(), core::fmt::Error> {
+ // we can fairly easily predict the size of a formatted string here with lzcnt, which also
+ // means we can write directly into the correct offsets of the output string.
+ let printed_size = (((64 - v.leading_zeros()) >> 2) + 1) as usize;
+
+ unsafe {
+ let buf = unsafe { self.content.as_mut_vec() };
+ let p = buf.as_mut_ptr();
+ let mut curr = printed_size;
+ loop {
+ let digit = v % 16;
+ let c = c_to_hex(digit as u8);
+ curr -= 1;
+ p.offset(curr as isize).write(c);
+ v = v / 16;
+ if v == 0 {
+ break;
+ }
+ }
+
+ buf.set_len(buf.len() + printed_size);
+ }
+
+ Ok(())
+ }
fn span_enter(&mut self, ty: TokenType) {}
fn span_end(&mut self, ty: TokenType) {}
}
@@ -1264,24 +1335,7 @@ impl <T: DisplaySink> crate::long_mode::OperandVisitor for ColorizingOperandVisi
fn visit_u64(&mut self, imm: u64) -> Result<Self::Ok, Self::Error> {
self.f.span_enter(TokenType::Immediate);
self.f.write_fixed_size("0x")?;
- let mut buf = [MaybeUninit::<u8>::uninit(); 16];
- let mut curr = buf.len();
- let mut v = imm;
- loop {
- let digit = v % 16;
- let c = c_to_hex(digit as u8);
- curr -= 1;
- buf[curr].write(c);
- v = v / 16;
- if v == 0 {
- break;
- }
- }
- let buf = &buf[curr..];
- let s: &str = unsafe {
- core::mem::transmute::<&[MaybeUninit<u8>], &str>(buf)
- };
- self.f.write_fixed_size(s)?;
+ self.f.write_u64(imm)?;
self.f.span_end(TokenType::Immediate);
Ok(())
}
@@ -1293,25 +1347,7 @@ impl <T: DisplaySink> crate::long_mode::OperandVisitor for ColorizingOperandVisi
v = -imm as u64;
}
self.f.write_fixed_size("0x")?;
- let mut buf = [core::mem::MaybeUninit::<u8>::uninit(); 64];
- let mut curr = buf.len();
- loop {
- let digit = v % 16;
- let c = c_to_hex(digit as u8);
- curr -= 1;
- buf[curr].write(c);
- v = v / 16;
- if v == 0 {
- break;
- }
- }
- let buf = &buf[curr..];
- let s = unsafe {
- core::mem::transmute::<&[core::mem::MaybeUninit<u8>], &str>(buf)
- };
-
- // not actually fixed size, but this should optimize right i hope..
- self.f.write_fixed_size(s)?;
+ self.f.write_u64(v)?;
self.f.span_end(TokenType::Immediate);
Ok(())
}
@@ -1393,7 +1429,11 @@ impl <T: DisplaySink> crate::long_mode::OperandVisitor for ColorizingOperandVisi
self.f.write_char(name[1] as char)?;
self.f.write_char(':')?;
}
- write!(self.f, "[{}]", u64_hex(imm))
+ self.f.write_fixed_size("[")?;
+ self.f.write_fixed_size("0x")?;
+ self.f.write_u64(imm)?;
+ self.f.write_fixed_size("]")?;
+ Ok(())
}
fn visit_disp(&mut self, reg: RegSpec, disp: i32) -> Result<Self::Ok, Self::Error> {
unsafe { self.f.write_lt_8(MEM_SIZE_STRINGS.get_kinda_unchecked(self.instr.mem_size as usize))? };