如何有效实施:
fn shorten(arg: [u8; 32]) -> [u8; 30] { ??? }
丢弃最后两个字节显然,我可以使用for循环,并在堆栈上创建一个新的更短的数组。编译器似乎有机会将[u8; 32]留在堆栈上,只使用它的[u8; 30]。通常我会使用切片,但这里我需要返回一个更短的数组。
[u8; 32]
[u8; 30]
n1bvdmb61#
这是其中一个问题,直接的答案并不真正有价值。但让我们从直接的答案开始:您可以将该函数实现为
fn shorten(arg: [u8; 32]) -> [u8; 30] { std::array::from_fn(|i| arg[i]) } // or fn shorten(arg: [u8; 32]) -> [u8; 30] { arg[..30].try_into().unwrap() } // or fn shorten(arg: [u8; 32]) -> [u8; 30] { let mut ret = [0; 30]; ret.copy_from_slice(&arg[..30]); ret } // or fn shorten(arg: [u8; 32]) -> [u8; 30] { let mut ret = [0; 30]; for i in 0..30 { ret[i] = arg[i]; } ret }
忽略函数调用的脚手架,这些都优化到四个x86指令。
movups xmm0, xmmword ptr [rsi] movups xmm1, xmmword ptr [rsi + 14] movups xmmword ptr [rdi + 14], xmm1 movups xmmword ptr [rdi], xmm0
(See这里的技巧,与重叠的加载/存储?聪明. -.-)godbolt现在,对于答案的不直接部分:问题是,孤立地看待fn shorten是没有意义的:
fn shorten
shorten
最后,shorten是四个x86指令。你真的在这一点上吃了很大一部分你的执行时间?
1条答案
按热度按时间n1bvdmb61#
这是其中一个问题,直接的答案并不真正有价值。但让我们从直接的答案开始:您可以将该函数实现为
忽略函数调用的脚手架,这些都优化到四个x86指令。
(See这里的技巧,与重叠的加载/存储?聪明. -.-)godbolt
现在,对于答案的不直接部分:问题是,孤立地看待
fn shorten
是没有意义的:shorten
是它自己的函数,并且返回一个拥有的[u8; 30]
,它就必须复制一个副本,因为返回值是一个独立于参数的值。它不能返回指向参数的指针,因为签名承诺它返回一个值。shorten
很短,LLVM肯定会内联它。接下来的问题是LLVM是否可以弄清楚,无论使用shorten
的结果是什么,它也会对[u8; 32]
感到满意。它是否能做到这一点并不能用你提供的信息来回答。最后,
shorten
是四个x86指令。你真的在这一点上吃了很大一部分你的执行时间?