You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 06:18:00