1
0
Fork 0
mirror of https://github.com/alacritty/alacritty.git synced 2024-11-18 13:55:23 -05:00

Specialize Storage::swap for Row<T>

Removes 4 movaps instructions from generated assembly.
This commit is contained in:
Joe Wilm 2018-05-20 16:04:14 -07:00
parent 182524b884
commit 6eead1f95c
4 changed files with 59 additions and 15 deletions

View file

@ -27,7 +27,7 @@ pub use self::row::Row;
mod tests; mod tests;
mod storage; mod storage;
use self::storage::Storage; use self::storage::{Storage, Swap};
/// Bidirection iterator /// Bidirection iterator
pub trait BidirectionalIterator: Iterator { pub trait BidirectionalIterator: Iterator {

View file

@ -58,7 +58,6 @@ impl<T: Copy + Clone> Row<T> {
} }
/// Resets contents to the contents of `other` /// Resets contents to the contents of `other`
#[inline(never)]
pub fn reset(&mut self, other: &T) { pub fn reset(&mut self, other: &T) {
let occ = self.occ; let occ = self.occ;
for item in &mut self.inner[..occ] { for item in &mut self.inner[..occ] {

View file

@ -15,10 +15,67 @@ use std::ops::{Index, IndexMut};
use std::slice; use std::slice;
use index::Line; use index::Line;
use grid::Row;
/// Maximum number of invisible lines before buffer is resized /// Maximum number of invisible lines before buffer is resized
const TRUNCATE_STEP: usize = 100; const TRUNCATE_STEP: usize = 100;
pub trait Swap {
fn swap(&mut self, _: usize, _: usize);
}
impl<T> Swap for Storage<T> {
/// Swap two lines in raw buffer
///
/// # Panics
///
/// `swap` will panic if either `a` or `b` are out-of-bounds of the
/// underlying storage.
default fn swap(&mut self, a: usize, b: usize) {
let a = self.compute_index(a);
let b = self.compute_index(b);
self.inner.swap(a, b);
}
}
impl<T> Swap for Storage<Row<T>> {
/// Custom swap implementation for Row<T>.
///
/// Exploits the known size of Row<T> to produce a slightly more efficient
/// swap than going through slice::swap.
///
/// The default implementation from swap generates 8 movups and 4 movaps
/// instructions. This implementation only uses 8 movups instructions.
fn swap(&mut self, a: usize, b: usize) {
use std::mem::{size_of, uninitialized};
use ::libc::memcpy;
debug_assert!(size_of::<Row<T>>() == 32);
let a = self.compute_index(a);
let b = self.compute_index(b);
unsafe {
// Cast to a u64 array of size 4 to pretend that the data is copy
let a_ptr = self.inner.as_mut_ptr().offset(a as isize) as *mut u64;
let b_ptr = self.inner.as_mut_ptr().offset(b as isize) as *mut u64;
// Swap space
let mut tmp: u64;
// Copy 1 qword at a time
//
// The optimizer unrolls this loop and vectorizes it.
for i in 0..4 {
tmp = *a_ptr.offset(i);
*a_ptr.offset(i) = *b_ptr.offset(i);
*b_ptr.offset(i) = tmp;
}
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Storage<T> { pub struct Storage<T> {
inner: Vec<T>, inner: Vec<T>,
@ -205,19 +262,6 @@ impl<T> Storage<T> {
self.inner.swap(a, b); self.inner.swap(a, b);
} }
/// Swap two lines in raw buffer
///
/// # Panics
///
/// `swap` will panic if either `a` or `b` are out-of-bounds of the
/// underlying storage.
pub fn swap(&mut self, a: usize, b: usize) {
let a = self.compute_index(a);
let b = self.compute_index(b);
self.inner.swap(a, b);
}
/// Iterator over *logical* entries in the storage /// Iterator over *logical* entries in the storage
/// ///
/// This *does not* iterate over hidden entries. /// This *does not* iterate over hidden entries.

View file

@ -13,6 +13,7 @@
// limitations under the License. // limitations under the License.
// //
//! Alacritty - The GPU Enhanced Terminal //! Alacritty - The GPU Enhanced Terminal
#![feature(specialization)]
#![cfg_attr(feature = "clippy", feature(plugin))] #![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))] #![cfg_attr(feature = "clippy", plugin(clippy))]
#![cfg_attr(feature = "clippy", deny(clippy))] #![cfg_attr(feature = "clippy", deny(clippy))]