有可能吗?我的小黑客工作了吗?
[<StructLayout(LayoutKind.Explicit,Size=8)>]
type Slice =
struct
[<FieldOffset(0)>]val mutable Address: int64
end
let incSlice (slice: Slice) = slice.Address + 1L
let incInt64 (address: int64) = address + 1L
incSlice
和incInt64
是否编译为相同的汇编代码?
时间几乎相同,但我不是100%肯定
答案 0 :(得分:4)
这里的问题是尝试在不影响运行时性能的情况下为函数添加编译时安全性。虽然只有一个字段的结构可能有用,但很难预测。
相反,更好的解决方案是Units of measure
您可以使用
定义度量类型[<Measure>] type Address
然后功能变为
let slice (t:int64<Address>)= t+1L<Address>
编译器将完全优化测量类型,同时提供类型安全性。
答案 1 :(得分:3)
琐碎基准的问题在于优化器总是会造成混乱。但是,我尝试通过在Release模式下构建exe并查看调试器中的反汇编来进行简单的测试。
看起来Slice
仍有比int64
版本更多的地址计算工作:
let v1 = incSlice sl1
00000066 lea edi,[ebp-1Ch]
00000069 lea esi,[ebp-14h]
0000006c movq xmm0,mmword ptr [esi]
00000070 movq mmword ptr [edi],xmm0
00000074 mov eax,dword ptr [ebp-1Ch]
00000077 mov edx,dword ptr [ebp-18h]
0000007a mov ecx,1
0000007f xor ebx,ebx
00000081 add eax,ecx
00000083 adc edx,ebx
00000085 mov dword ptr [ebp-24h],eax
00000088 mov dword ptr [ebp-20h],edx
let v2 = incInt64 n
0000008b mov eax,dword ptr [ebp+8]
0000008e mov edx,dword ptr [ebp+0Ch]
00000091 mov ecx,1
00000096 xor ebx,ebx
00000098 add eax,ecx
0000009a adc edx,ebx
0000009c mov dword ptr [ebp-2Ch],eax
0000009f mov dword ptr [ebp-28h],edx
在另一个测试中,我直接使用文字值,发现int64
版本已针对结果进行了优化,而Slice
版本没有 - 即它的存在似乎打败了优化者更多案例。
编辑:请注意,这是32位。根据越南的答案,64位通常看起来更好。
事实证明,只有在调试器下运行程序才会开始。如果在方法运行后附加调试器,则代码看起来非常相似,并且对于int64
和Slice
个案,具有文字值的变量将保持不变。
答案 2 :(得分:1)
现在看起来非常相同
let test1(s: Slice) =
printfn "%d" 10
let x = s.address + 1
printfn "%d" x
产生
000000c1 mov rax,qword ptr [rsp+000000A0h]
000000c9 inc rax
000000cc mov qword ptr [rsp+28h],rax
似乎已经过优化
并在内联的帮助下
let inline incSlice(s: Slice) = s.address + 1
let test2 (s: Slice) =
printfn "%d" 10
let x = incSlice s
产生
000000be mov rax,qword ptr [rsp+000000A0h]
000000c6 mov qword ptr [rsp+30h],rax
000000cb mov rax,qword ptr [rsp+30h]
000000d0 inc rax
000000d3 mov qword ptr [rsp+28h],rax
与test1
有趣的汇编代码:D,rax
四处移动 - 我不认为调试器中的反汇编被优化的原因