C#中是否有限制等价物

Is there restrict equivalent in C#

我有以下函数(我稍微清理了一下以便更容易理解)它获取目标数组获取索引 n 处的元素添加到它 src1[i] 然后将它与 src2[i] 相乘(没什么特别的):

static void F(long[] dst, long[] src1, long[] src2, ulong n) 
{
    dst[n] += src1[n];
    dst[n] *= src2[n];
}

否这会生成以下 ASM:

<Program>$.<<Main>$>g__F|0_0(Int64[], Int64[], Int64[], UInt64)
    L0000: sub rsp, 0x28
    L0004: test r9, r9
    L0007: jl short L0051
    L0009: mov rax, r9
    L000c: mov r9d, [rcx+8]
    L0010: movsxd r9, r9d
    L0013: cmp rax, r9
    L0016: jae short L0057
    L0018: lea rcx, [rcx+rax*8+0x10]
    L001d: mov r9, rcx
    L0020: mov r10, [r9]
    L0023: mov r11d, [rdx+8]
    L0027: movsxd r11, r11d
    L002a: cmp rax, r11
    L002d: jae short L0057
    L002f: add r10, [rdx+rax*8+0x10]
    L0034: mov [r9], r10
    L0037: mov edx, [r8+8]
    L003b: movsxd rdx, edx
    L003e: cmp rax, rdx
    L0041: jae short L0057
    L0043: imul r10, [r8+rax*8+0x10]
    L0049: mov [rcx], r10
    L004c: add rsp, 0x28
    L0050: ret
    L0051: call 0x00007ffc9dadb710
    L0056: int3
    L0057: call 0x00007ffc9dadbc70
    L005c: int3

尽你所能,它添加了一堆东西,因为我可以保证 n 将在合法范围之间:我可以使用指针。

static unsafe void G(long* dst, long* src1, long* src2, ulong n) 
{
    dst[n] += src1[n];
    dst[n] *= src2[n];
}

现在这生成更简单 ASM:

<Program>$.<<Main>$>g__G|0_1(Int64*, Int64*, Int64*, UInt64)
    L0000: lea rax, [rcx+r9*8]
    L0004: mov rcx, rax
    L0007: mov rdx, [rdx+r9*8]
    L000b: add [rcx], rdx
    L000e: mov rdx, [rax]               ; loads the value again?
    L0011: imul rdx, [r8+r9*8]
    L0016: mov [rax], rdx
    L0019: ret

您可能已经注意到,那里有一个额外的 MOV(我想,至少我无法解释为什么会在那里)。

问题

备注

void
f(int64_t  *dst, 
  int64_t  *src1, 
  int64_t  *src2, 
  uint64_t  n) {
        dst[n] += src1[n];
        dst[n] *= src2[n];
}

void
g(int64_t *restrict dst, 
  int64_t *restrict src1,  
  int64_t *restrict src2, 
  uint64_t          n) {
        dst[n] += src1[n];
        dst[n] *= src2[n];
}

这会生成:

f:
        mov     r10, rdx
        lea     rdx, [rcx+r9*8]
        mov     rax, QWORD PTR [rdx]
        add     rax, QWORD PTR [r10+r9*8]
        mov     QWORD PTR [rdx], rax       ; this is strange. It loads the value back to [RDX]?
                                           ; shouldn't that be other way around? I don't know.
        imul    rax, QWORD PTR [r8+r9*8]
        mov     QWORD PTR [rdx], rax
        ret

g:
        mov     r10, rdx
        lea     rdx, [rcx+r9*8]
        mov     rax, QWORD PTR [rdx]
        add     rax, QWORD PTR [r10+r9*8]
        imul    rax, QWORD PTR [r8+r9*8]
        mov     QWORD PTR [rdx], rax
        ret

这里是 Godbolt link.

这个:

dst[n] = (dst[n] + src1[n]) * src2[n];

删除多余的 mov

C# 中没有 C 语言的 restrict 限定词的等价物。

C# ECMA-334:2017 语言规范中,在23. Unsafe Code 章中,没有语法来指定只能通过特定指针访问内存的一部分。并且没有语法来指定指针指向的内存区域不重叠。因此没有这样的等价物。这可能是因为 C# 是一种托管语言,允许使用 pointers/unmanaged 内存的 unsafe 语法是 C# 中的一种边缘情况。指针上的 restrict 将是边缘情况的边缘情况。