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[],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*,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(我想,至少我想不通它为什么在那里)。

问题

  • 如何删除该行?在 C 中,如果我没记错的话,我可以使用关键字 restrict。 C#中有这样的关键字吗?很遗憾,我在互联网上找不到任何内容。

注意

  • 这是 SharpLab 链接。
  • 以下是 C 示例:
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,QWORD PTR [r10+r9*8]
        imul    rax,rax
        ret

这里是 Godbolt 链接。

解决方法

这个:

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

删除额外的 mov

C# 中,没有与 restrict 语言中的 C 限定符等效。

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

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...