F#如何内联带度量单位校验的数组包装类索引器以生成等价汇编代码
F# 带度量单位索引校验的数组零开销封装问题
我尝试封装数组并使用Units of Measure对索引进行校验,目标是在获得额外安全保证的同时,生成与原生数组完全等价的汇编代码,以下是我的初始实现:
type Arr<[<Measure>] 'Measure, 'Value> (values: array<'Value>) = member _.Item with get (idx: int<'Measure>) = values.[int idx] member _.Length = FSharp.Core.LanguagePrimitives.Int32WithMeasure<'Measure> values.Length [<Measure>] type ItemIdx let test1 (x: array<float>) = let mutable acc = 0.0 let mutable idx = 0 let len = x.Length while idx < len do acc <- acc + x.[idx] acc let test2 (x: Arr<ItemIdx, float>) = let mutable acc = 0.0 let mutable idx = 0<ItemIdx> let len = x.Length while idx < len do acc <- acc + x.[idx] acc
test1为原生数组测试函数,生成的汇编代码如下:
; Core CLR 6.0.21.52210 on amd64 _.test1(System.Double[]) L0000: vzeroupper L0003: vxorps xmm0, xmm0, xmm0 L0007: mov eax, [rcx+8] L000a: test eax, eax L000c: jle short L0015 L000e: vaddsd xmm0, xmm0, [rcx+0x10] L0013: jmp short L000a L0015: ret
test2为封装数组测试函数,生成的汇编代码如下:
; Core CLR 6.0.21.52210 on amd64 _.test2(Arr`1<System.Double>) L0000: sub rsp, 0x28 L0004: vzeroupper L0007: vxorps xmm0, xmm0, xmm0 L000c: mov rax, [rcx+8] L0010: mov edx, [rax+8] L0013: nop [rax+rax] L0018: nop [rax+rax] L0020: test edx, edx L0022: jle short L0034 L0024: mov rcx, rax L0027: cmp dword ptr [rcx+8], 0 L002b: jbe short L0039 L002d: vaddsd xmm0, xmm0, [rcx+0x10] L0032: jmp short L0020 L0034: add rsp, 0x28 L0038: ret L0039: call 0x00007ffd109ee750 L003e: int3
可见test2生成的汇编代码更为冗长。我尝试给member _.Item添加[<MethodImpl(MethodImplOptions.AggressiveInlining)>]属性,编译器报错“该属性不适用于此语言元素”:
[<MethodImpl(MethodImplOptions.AggressiveInlining)>] // <-- 编译器报错 member _.Item with get (idx: int<'Measure>) = values.[int idx]
之后我尝试使用inline关键字,同样报错:
member inline _.Item // <-- 编译器报错 with get (idx: int<'Measure>) = values.[int idx]
编译器错误信息为The value 'Item' was marked inline, but its implementation makes use of an internal or private function which is not sufficiently accesible。
更新
我发现标记为inline的方法不能使用私有成员,因此修改了Arr<'Measure, 'Value>的实现如下:
type Arr<[<Measure>] 'Measure, 'Value> (values: array<'Value>) = member _.Values = values member inline this.Item with get (idx: int<'Measure>) = this.Values.[int idx] member _.Length = FSharp.Core.LanguagePrimitives.Int32WithMeasure<'Measure> values.Length
但最终生成的汇编代码仍然没有变化,请问有什么方法可以内联该方法调用,得到与原生数组等价的汇编代码?
内容的提问来源于stack exchange,提问作者Matthew Crews
相关产品推荐
相关产品推荐

