【ARMv8 SIMD和浮点指令编程】NEON 移动指令——精通 MOV?

news2024/11/15 23:48:40

移动指令主要涉及 MOV 和 MVN,它们分别是移动和求反移动。如果你认为仅仅两条指令,还是太小看设计者了!

1 MOV (element)

将向量元素移动到另一个向量元素。该指令将源 SIMD&FP 寄存器的向量元素复制到目标 SIMD&FP 寄存器的指定向量元素。该指令可以将数据插入 SIMD&FP 寄存器中的各个元素,而无需将剩余位清零。

在这里插入图片描述

MOV <Vd>.<Ts>[<index1>], <Vn>.<Ts>[<index2>]

等价指令

INS <Vd>.<Ts>[<index1>], <Vn>.<Ts>[<index2>]

<Vd> 是 SIMD&FP 目标寄存器的名称,在“Rd”字段中编码。

<Ts> 是元素大小说明符,编码为“imm5”:

imm5<Ts>
x0000RESERVED
xxxx1B
xxx10H
xx100S
x1000D

<index1> 是以“imm5”编码的目标元素索引:

imm5<index1>
x0000RESERVED
xxxx1imm5<4:1>
xxx10imm5<4:2>
xx100imm5<4:3>
x1000imm5<4>

<Vn> 是 SIMD&FP 源寄存器的名称,在“Rn”字段中编码。

<index2> 是以“imm5:imm4”编码的源元素索引:

imm5<index2>
x0000RESERVED
xxxx1imm4<3:0>
xxx10imm4<3:1>
xx100imm4<3:2>
x1000imm4<3>

“imm4”中未指定的位将被忽略,但应由汇编程序设置为零。

下面是使用 MOV (element) 指令的例子。

    int len = 4;
    auto *src = new unsigned int[len];
    auto *dst = new unsigned int[len]{0};

    for (int i = 0; i < len; i++) {
        src[i] = (i + 1) * 0x11111111;
    }

    LOGD("in src: src[%d]=0x%x src[%d]=0x%x src[%d]=0x%x src[%d]=0x%x", 0, src[0], 1, src[1],
         2, src[2], 3, src[3]);
    LOGD("in dst: dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x", 0, dst[0], 1, dst[1],
         2, dst[2], 3, dst[3]);

    asm volatile(
        "LD1 {v0.4S}, [%[src]]\n"
        "LD1 {v1.4S}, [%[dst]]\n"
        "MOV v1.S[0], v0.S[3]\n"
        "ST1 {v1.4S}, [%[dst]]\n"
    :[src] "+r"(src),
     [dst] "+r"(dst)
    :
    : "cc", "memory", "v0", "v1");

    LOGD("-----------------------------");
    LOGD("out dst: dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x", 0, dst[0], 1, dst[1],
         2, dst[2], 3, dst[3]);

    delete[] src;
    delete[] dst;

MOV v1.S[0], v0.S[3] 将 v0 S 第四通道的值移动到 v1 S 第一通道,v1 其他 S 通道的值保持不变。

在这里插入图片描述

运行结果:

2023-06-07 07:55:22.331 22545-22629/com.demo.myapplication D/NativeCore: in src: src[0]=0x11111111 src[1]=0x22222222 src[2]=0x33333333 src[3]=0x44444444
2023-06-07 07:55:22.331 22545-22629/com.demo.myapplication D/NativeCore: in dst: dst[0]=0x0 dst[1]=0x0 dst[2]=0x0 dst[3]=0x0
2023-06-07 07:55:22.331 22545-22629/com.demo.myapplication D/NativeCore: -----------------------------
2023-06-07 07:55:22.331 22545-22629/com.demo.myapplication D/NativeCore: out dst: dst[0]=0x44444444 dst[1]=0x0 dst[2]=0x0 dst[3]=0x0

2 MOV (from general)

将通用寄存器移动到向量元素。该指令将源通用寄存器的内容复制到目标 SIMD&FP 寄存器中指定的向量元素。该指令可以将数据插入 SIMD&FP 寄存器中的各个元素,而无需将剩余位清零。

在这里插入图片描述

MOV <Vd>.<Ts>[<index>], <R><n>

等价指令

INS <Vd>.<Ts>[<index>], <R><n>

<Vd> 是 SIMD&FP 目标寄存器的名称,在“Rd”字段中编码。

<Ts> 是元素大小说明符,编码为“imm5”:

imm5<Ts>
x0000RESERVED
xxxx1B
xxx10H
xx100S
x1000D

<index> 是以“imm5”编码的目标元素索引:

imm5<index>
x0000RESERVED
xxxx1imm5<4:1>
xxx10imm5<4:2>
xx100imm5<4:3>
x1000imm5<4>

<R> 是通用源寄存器的宽度说明符,编码为“imm5”:

imm5<R>
x0000RESERVED
xxxx1W
xxx10W
xx100W
x1000X

<n> 是通用源寄存器或 ZR (31) 的编号 [0-30],编码在“Rn”字段中。

下面是使用 MOV (from general) 指令的例子。

    int len = 4;
    auto *dst = new unsigned int[len]{0};
    unsigned int src = 0x12345678;

    LOGD("in src: 0x%x ", src);
    LOGD("in dst: dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x", 0, dst[0], 1, dst[1],
         2, dst[2], 3, dst[3]);

    asm volatile(
        "LD1 {v1.4S}, [%[dst]]\n"
        "MOV v1.S[0], %w[src]\n"
        "ST1 {v1.4S}, [%[dst]]\n"
    :[src] "+r"(src),
     [dst] "+r"(dst)
    :
    : "cc", "memory", "v1");

    LOGD("-----------------------------");
    LOGD("out dst: dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x", 0, dst[0], 1, dst[1],
         2, dst[2], 3, dst[3]);

    delete[] dst;

MOV v1.S[0], %w[src] 将通用 W 寄存器的值移动到 v1 S 第一通道,v1 其他 S 通道的值保持不变。

运行结果:

2023-06-07 08:20:59.353 20134-20205/com.demo.myapplication D/NativeCore: in src: 0x12345678 
2023-06-07 08:20:59.353 20134-20205/com.demo.myapplication D/NativeCore: in dst: dst[0]=0x0 dst[1]=0x0 dst[2]=0x0 dst[3]=0x0
2023-06-07 08:20:59.353 20134-20205/com.demo.myapplication D/NativeCore: -----------------------------
2023-06-07 08:20:59.353 20134-20205/com.demo.myapplication D/NativeCore: out dst: dst[0]=0x12345678 dst[1]=0x0 dst[2]=0x0 dst[3]=0x0

3 MOV (scalar)

将向量元素移动到标量。该指令将 SIMD&FP 源寄存器中的指定向量元素复制为标量,并将结果写入 SIMD&FP 目标寄存器。

在这里插入图片描述

MOV <V><d>, <Vn>.<T>[<index>]

等价指令

DUP <V><d>, <Vn>.<T>[<index>]

<V> 是目标宽度说明符,编码为“imm5”:

imm5<V>
x0000RESERVED
xxxx1B
xxx10H
xx100S
x1000D

<d> 是 SIMD&FP 目标寄存器的编号,编码在“Rd”字段中。

<Vn> 是 SIMD&FP 源寄存器的名称,在“Rn”字段中编码。

<T> 是元素宽度说明符,编码为“imm5”:

imm5<T>
x0000RESERVED
xxxx1B
xxx10H
xx100S
x1000D

<index> 是“imm5”中编码的元素索引:

imm5<index>
x0000RESERVED
xxxx1imm5<4:1>
xxx10imm5<4:2>
xx100imm5<4:3>
x1000imm5<4>

下面是使用 MOV (scalar) 指令的例子。

    int len = 4;
    auto *src = new unsigned int[len];
    auto *dst = new unsigned int[len]{0};

    for (int i = 0; i < len; i++) {
        src[i] = 0x11111111 * (i + 1);
    }
    LOGD("in src: src[%d]=0x%x src[%d]=0x%x src[%d]=0x%x src[%d]=0x%x", 0, src[0], 1, src[1],
         2, src[2], 3, src[3]);
    LOGD("in dst: dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x", 0, dst[0], 1, dst[1],
         2, dst[2], 3, dst[3]);

    asm volatile(
        "LD1 {v0.4S}, [%[src]]\n"
        "LD1 {v1.4S}, [%[dst]]\n"
        "MOV S1, v0.S[3]\n"
        "ST1 {v1.4S}, [%[dst]]\n"
    :[src] "+r"(src),
     [dst] "+r"(dst)
    :
    : "cc", "memory", "v1");

    LOGD("-----------------------------");
    LOGD("out dst: dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x", 0, dst[0], 1, dst[1],
         2, dst[2], 3, dst[3]);

    delete[] src;
    delete[] dst;

MOV S1, v0.S[3] 将 v0 S 第四通道值移动到标量 S1(映射为 v1 寄存器的最低 S 部分(第一 S 通道))。

运行结果:

2023-06-07 08:35:21.193 30974-31058/com.demo.myapplication D/NativeCore: in src: src[0]=0x11111111 src[1]=0x22222222 src[2]=0x33333333 src[3]=0x44444444
2023-06-07 08:35:21.193 30974-31058/com.demo.myapplication D/NativeCore: in dst: dst[0]=0x0 dst[1]=0x0 dst[2]=0x0 dst[3]=0x0
2023-06-07 08:35:21.193 30974-31058/com.demo.myapplication D/NativeCore: -----------------------------
2023-06-07 08:35:21.193 30974-31058/com.demo.myapplication D/NativeCore: out dst: dst[0]=0x44444444 dst[1]=0x0 dst[2]=0x0 dst[3]=0x0

4 MOV (to general)

将向量元素移动到通用寄存器。该指令从源 SIMD&FP 寄存器中读取无符号整数,对其进行零扩展以形成 32 位或 64 位值,并将结果写入目标通用寄存器。

在这里插入图片描述

32-bit (Q == 0 && imm5 == xx100)

MOV <Wd>, <Vn>.S[<index>]

等价指令

UMOV <Wd>, <Vn>.S[<index>]

64-bit (Q == 1 && imm5 == x1000)

MOV <Xd>, <Vn>.D[<index>]

等价指令

UMOV <Xd>, <Vn>.D[<index>]

<Wd> 是通用目标寄存器的 32 位名称,在“Rd”字段中编码。

<Xd> 是通用目标寄存器的 64 位名称,在“Rd”字段中编码。

<Vn> 是 SIMD&FP 源寄存器的名称,在“Rn”字段中编码。

<index> 对于 32 位变体:是在“imm5<4:3>”中编码的元素索引。对于 64 位变体:是在“imm5<4>”中编码的元素索引。

下面是使用 MOV (to general) 指令的例子。

    int len = 4;
    auto *src = new unsigned int[len];
    unsigned int dst = 0;

    for (int i = 0; i < len; i++) {
        src[i] = 0x11111111 * (i + 1);
    }
    LOGD("in src: src[%d]=0x%x src[%d]=0x%x src[%d]=0x%x src[%d]=0x%x", 0, src[0], 1, src[1],
         2, src[2], 3, src[3]);

    asm volatile(
        "LD1 {v0.4S}, [%[src]]\n"
        "MOV %w[dst], v0.S[3]\n"
    :[src] "+r"(src),
     [dst] "+r"(dst)
    :
    : "cc", "memory", "v1");

    LOGD("-----------------------------");
    LOGD("out dst: 0x%x", dst);

    delete[] src;

MOV %w[dst], v0.S[3] 将 v0 S 第四通道值移动到通用寄存器。

运行结果:

2023-06-08 07:46:51.911 3993-4135/com.demo.myapplication D/NativeCore: in src: src[0]=0x11111111 src[1]=0x22222222 src[2]=0x33333333 src[3]=0x44444444
2023-06-08 07:46:51.911 3993-4135/com.demo.myapplication D/NativeCore: -----------------------------
2023-06-08 07:46:51.911 3993-4135/com.demo.myapplication D/NativeCore: out dst: 0x44444444

5 MOV (vector)

移动向量。该指令将源 SIMD&FP 寄存器中的向量复制到目标 SIMD&FP 寄存器中。

在这里插入图片描述

MOV <Vd>.<T>, <Vn>.<T>

等价指令

ORR <Vd>.<T>, <Vn>.<T>, <Vn>.<T>

<Vd> 是 SIMD&FP 目标寄存器的名称,在“Rd”字段中编码。

<T> 是排列说明符,用“Q”编码:

Q<T>
08B
116B

<Vn> 是第一个 SIMD&FP 源寄存器的名称,在“Rn”字段中编码。

下面是使用 MOV (vector) 指令的例子。

    int len = 4;
    auto *src = new unsigned int[len];
    auto *dst = new unsigned int[len]{0};

    for (int i = 0; i < len; i++) {
        src[i] = 0x11111111 * (i + 1);
    }
    LOGD("in src: src[%d]=0x%x src[%d]=0x%x src[%d]=0x%x src[%d]=0x%x", 0, src[0], 1, src[1],
         2, src[2], 3, src[3]);
    LOGD("in dst: dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x", 0, dst[0], 1, dst[1],
         2, dst[2], 3, dst[3]);

    asm volatile(
    "LD1 {v0.4S}, [%[src]]\n"
    "LD1 {v1.4S}, [%[dst]]\n"
    "MOV v1.16B, v0.16B\n"
    "ST1 {v1.4S}, [%[dst]]\n"
    :[src] "+r"(src),
    [dst] "+r"(dst)
    :
    : "cc", "memory", "v1");

    LOGD("-----------------------------");
    LOGD("out dst: dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x", 0, dst[0], 1, dst[1],
         2, dst[2], 3, dst[3]);

    delete[] src;
    delete[] dst;

MOV v1.16B, v0.16B 将 v0 16 个 B 通道的值移动到对应的 v1 16 个 B 通道。

运行结果:

2023-06-08 07:54:34.443 8130-8174/com.demo.myapplication D/NativeCore: in src: src[0]=0x11111111 src[1]=0x22222222 src[2]=0x33333333 src[3]=0x44444444
2023-06-08 07:54:34.443 8130-8174/com.demo.myapplication D/NativeCore: in dst: dst[0]=0x0 dst[1]=0x0 dst[2]=0x0 dst[3]=0x0
2023-06-08 07:54:34.443 8130-8174/com.demo.myapplication D/NativeCore: -----------------------------
2023-06-08 07:54:34.443 8130-8174/com.demo.myapplication D/NativeCore: out dst: dst[0]=0x11111111 dst[1]=0x22222222 dst[2]=0x33333333 dst[3]=0x44444444

6 MOVI

移动立即数(向量)。该指令将一个立即数放入目标 SIMD&FP 寄存器的每个向量元素中。

在这里插入图片描述

8-bit (op == 0 && cmode == 1110)

MOVI <Vd>.<T>, #<imm8>{, LSL #0}

16-bit shifted immediate (op == 0 && cmode == 10x0)

MOVI <Vd>.<T>, #<imm8>{, LSL #<amount>}

32-bit shifted immediate (op == 0 && cmode == 0xx0)

MOVI <Vd>.<T>, #<imm8>{, LSL #<amount>}

32-bit shifting ones (op == 0 && cmode == 110x)

MOVI <Vd>.<T>, #<imm8>, MSL #<amount>

64-bit scalar (Q == 0 && op == 1 && cmode == 1110)

MOVI <Dd>, #<imm>

64-bit vector (Q == 1 && op == 1 && cmode == 1110)

MOVI <Vd>.2D, #<imm>

<Dd> 是 SIMD&FP 目标寄存器的 64 位名称,在“Rd”字段中编码。

<Vd> 是 SIMD&FP 目标寄存器的名称,在“Rd”字段中编码。

<imm> 是一个 64 位立即数 ‘aaaaaaaabbbbbbbbbccccccccdddddddddeeeeeeeeeffffffffggggggghhhhhhhh’,
编码为“a🅱️c:d:e:f:g:h”。

<T> 是排列说明符,以“Q”编码。

对于 8 位变体:

Q<T>
08B
116B

对于 16 位变体:

Q<T>
04H
18H

对于 32 位变体:

Q<T>
02S
14S

<imm8> 是以“a🅱️c:d:e:f:g:h”编码的 8 位立即数。

<amount>

对于 16 位移位立即数变体:是在“cmode<1>”中编码的移位量:

cmode<1><amount>
00
18

如果省略 LSL,则默认为 0。

对于 32 位移位立即数变体:是在“cmode<2:1>”中编码的移位量:

cmode<2:1><amount>
000
018
1016
1124

如果省略 LSL,则默认为 0。

对于 32 位移位变体:是编码在“cmode<0>”中的移位量:

cmode<0><amount>
08
116

下面是使用 MOVI 指令的例子。

    int len = 16;
    auto *dst = new char[len]{0};
    auto *dst1 = new unsigned int[4]{0};

    asm volatile(
        "MOVI v0.16B, #0x12\n"
        "MOVI v1.4S, #0x34\n"
        "ST1 {v0.16B}, [%[dst]]\n"
        "ST1 {v1.4S}, [%[dst1]]\n"
    :[dst] "+r"(dst),
     [dst1] "+r"(dst1)
    :
    : "cc", "memory", "v0", "v1");

    LOGD("-----------------------------");
    LOGD("out dst: dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x", 0, dst[0], 1, dst[1],
         2, dst[2], 3, dst[3]);
    LOGD("out dst: dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x", 4, dst[4], 5, dst[5],
         6, dst[6], 7, dst[7]);
    LOGD("out dst: dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x", 8, dst[8], 9, dst[9],
         10, dst[10], 11, dst[11]);
    LOGD("out dst: dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x", 12, dst[12], 13, dst[13],
         14, dst[14], 15, dst[15]);

    LOGD("out dst1: dst1[%d]=0x%x dst1[%d]=0x%x dst1[%d]=0x%x dst1[%d]=0x%x ", 0, dst1[0], 1,
         dst1[1], 2, dst1[2], 3, dst1[3]);

    delete[] dst;
    delete[] dst1;

MOVI v0.16B, #0x12 将立即数 0x12 移动到 v0 16 个 B 通道,MOVI v1.4S, #0x34 将立即数 0x34 移动到 v1 4 个 S 通道。

运行结果:

2023-06-08 08:42:46.982 27099-27138/com.demo.myapplication D/NativeCore: -----------------------------
2023-06-08 08:42:46.982 27099-27138/com.demo.myapplication D/NativeCore: out dst: dst[0]=0x12 dst[1]=0x12 dst[2]=0x12 dst[3]=0x12
2023-06-08 08:42:46.982 27099-27138/com.demo.myapplication D/NativeCore: out dst: dst[4]=0x12 dst[5]=0x12 dst[6]=0x12 dst[7]=0x12
2023-06-08 08:42:46.982 27099-27138/com.demo.myapplication D/NativeCore: out dst: dst[8]=0x12 dst[9]=0x12 dst[10]=0x12 dst[11]=0x12
2023-06-08 08:42:46.982 27099-27138/com.demo.myapplication D/NativeCore: out dst: dst[12]=0x12 dst[13]=0x12 dst[14]=0x12 dst[15]=0x12
2023-06-08 08:42:46.982 27099-27138/com.demo.myapplication D/NativeCore: out dst1: dst1[0]=0x34 dst1[1]=0x34 dst1[2]=0x34 dst1[3]=0x34 

7 MVN

按位 NOT(向量),该指令从源 SIMD&FP 寄存器中读取每个向量元素,将每个值的反码放入向量中,然后将向量写入目标 SIMD&FP 寄存器。

在这里插入图片描述

MVN <Vd>.<T>, <Vn>.<T>

等价指令

NOT <Vd>.<T>, <Vn>.<T>

<Vd> 是 SIMD&FP 目标寄存器的名称,在“Rd”字段中编码。

<T> 是排列说明符,用“Q”编码:

Q<T>
08B
116B

<Vn> 是 SIMD&FP 源寄存器的名称,在“Rn”字段中编码。

下面是使用 MVN 指令的例子。

    int len = 8;
    auto *dst = new char[len];
    for(int i = 0; i < len; i++){
        dst[i] = i;
    }

    LOGD("in dst: dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x", 0, dst[0], 1, dst[1],
         2, dst[2], 3, dst[3]);
    LOGD("in dst: dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x", 4, dst[4], 5, dst[5],
         6, dst[6], 7, dst[7]);

    asm volatile(
        "LD1 {v0.8B}, [%[dst]]\n"
        "MVN v1.8B, v0.8B\n"
        "ST1 {v1.8B}, [%[dst]]\n"
    :[dst] "+r"(dst)
    :
    : "cc", "memory", "v0", "v1");

    LOGD("-----------------------------");
    LOGD("out dst: dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x", 0, dst[0], 1, dst[1],
         2, dst[2], 3, dst[3]);
    LOGD("out dst: dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x", 4, dst[4], 5, dst[5],
         6, dst[6], 7, dst[7]);

    delete[] dst;

MVN v1.8B, v0.8B 将 v0 寄存器 8 个 B 通道的值取反码放入 v1 寄存器 8 个 B 通道。

运行结果:

2023-06-09 07:59:45.055 21805-21871/com.demo.myapplication D/NativeCore: in dst: dst[0]=0x0 dst[1]=0x1 dst[2]=0x2 dst[3]=0x3
2023-06-09 07:59:45.055 21805-21871/com.demo.myapplication D/NativeCore: in dst: dst[4]=0x4 dst[5]=0x5 dst[6]=0x6 dst[7]=0x7
2023-06-09 07:59:45.055 21805-21871/com.demo.myapplication D/NativeCore: -----------------------------
2023-06-09 07:59:45.055 21805-21871/com.demo.myapplication D/NativeCore: out dst: dst[0]=0xff dst[1]=0xfe dst[2]=0xfd dst[3]=0xfc
2023-06-09 07:59:45.055 21805-21871/com.demo.myapplication D/NativeCore: out dst: dst[4]=0xfb dst[5]=0xfa dst[6]=0xf9 dst[7]=0xf8

8 MVNI

移动取反立即数(向量),该指令将立即数的反码放入目标 SIMD&FP 寄存器的每个向量元素中。

在这里插入图片描述

16-bit shifted immediate (cmode == 10x0)

MVNI <Vd>.<T>, #<imm8>{, LSL #<amount>}

32-bit shifted immediate (cmode == 0xx0)

MVNI <Vd>.<T>, #<imm8>{, LSL #<amount>}

32-bit shifting ones (cmode == 110x)

MVNI <Vd>.<T>, #<imm8>, MSL #<amount>

<Vd> 是 SIMD&FP 目标寄存器的名称,在“Rd”字段中编码。

<T> 是排列说明符,以“Q”编码。

对于 16 位变体:

Q<T>
04H
18H

对于 32 位变体:

Q<T>
02S
14S

<imm8> 是以“a🅱️c:d:e:f:g:h”编码的 8 位立即数。

<amount>

对于 16 位移位立即数变体:是在“cmode<1>”中编码的移位量:

cmode<1><amount>
00
18

如果省略 LSL,则默认为 0。

对于 32 位移位立即数变体:是在“cmode<2:1>”中编码的移位量:

cmode<2:1><amount>
000
018
1016
1124

如果省略 LSL,则默认为 0。

对于 32 位移位变体:是编码在“cmode<0>”中的移位量:

cmode<0><amount>
08
116

下面是使用 MVNI 指令的例子。

    int len = 4;
    auto *dst = new unsigned int[len]{0};

    asm volatile(
        "MVNI v0.4S, #0x7, LSL#8\n"
        "ST1 {v0.4S}, [%[dst]]\n"
    :[dst] "+r"(dst)
    :
    : "cc", "memory", "v0");

    LOGD("-----------------------------");
    LOGD("out dst: dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x dst[%d]=0x%x", 0, dst[0], 1, dst[1],
         2, dst[2], 3, dst[3]);

    delete[] dst;

MVNI v0.4S, #0x7, LSL#8 将立即数 0x7 逻辑左移 8 位,即变为 0x700,接着按位取反即 0xfffff8ff,最终将 0xfffff8ff 移动到 v0 寄存器 4 个 S 通道。

运行结果:

2023-06-09 08:15:31.531 31584-31656/com.demo.myapplication D/NativeCore: -----------------------------
2023-06-09 08:15:31.531 31584-31656/com.demo.myapplication D/NativeCore: out dst: dst[0]=0xfffff8ff dst[1]=0xfffff8ff dst[2]=0xfffff8ff dst[3]=0xfffff8ff

9 SMOV

有符号移动向量元素到通用寄存器。该指令从源 SIMD&FP 寄存器中读取有符号整数,对其进行符号扩展以形成 32 位或 64 位值,并将结果写入目标通用寄存器。

在这里插入图片描述

32-bit (Q == 0)

SMOV <Wd>, <Vn>.<Ts>[<index>]

64-bit (Q == 1)

SMOV <Xd>, <Vn>.<Ts>[<index>]

<Wd> 是通用目标寄存器的 32 位名称,在“Rd”字段中编码。

<Xd> 是通用目标寄存器的 64 位名称,在“Rd”字段中编码。

<Vn> 是 SIMD&FP 源寄存器的名称,在“Rn”字段中编码。

<Ts> 是一个元素大小说明符,以“imm5”编码:

对于 32 位变体:

imm5<Ts>
xxx00RESERVED
xxxx1B
xxx10H

对于 64 位变体:

imm5<Ts>
xx000RESERVED
xxxx1B
xxx10H
xx100S

<index> 是在“imm5”中编码的元素索引:

对于 32 位变体:

imm5<index>
xxx00RESERVED
xxxx1imm5<4:1>
xxx10imm5<4:2>

对于 64 位变体:

imm5<index>
xx000RESERVED
xxxx1imm5<4:1>
xxx10imm5<4:2>
xx100imm5<4:3>

下面是使用 SMOV 指令的例子。

int len = 4;
    auto *src = new int[len];
    long long int dst = 0;

    for (int i = 0; i < len; i++) {
        src[i] = -100 * (i + 1);
    }
    LOGD("in src: src[%d]=%d src[%d]=%d src[%d]=%d src[%d]=%d", 0, src[0], 1, src[1],
         2, src[2], 3, src[3]);

    asm volatile(
        "LD1 {v0.4S}, [%[src]]\n"
        "SMOV %[dst], v0.S[3]\n"
    :[src] "+r"(src),
     [dst] "+r"(dst)
    :
    : "cc", "memory", "v0");

    LOGD("-----------------------------");
    LOGD("out dst: %lld", dst);

    delete[] src;

SMOV %[dst], v0.S[3] 将 v0 寄存器第四个 S 通道的值移动到通用 X 寄存器(对其进行符号扩展)。

运行结果:

2023-06-09 08:31:27.692 19705-19770/com.demo.myapplication D/NativeCore: in src: src[0]=-100 src[1]=-200 src[2]=-300 src[3]=-400
2023-06-09 08:31:27.692 19705-19770/com.demo.myapplication D/NativeCore: -----------------------------
2023-06-09 08:31:27.692 19705-19770/com.demo.myapplication D/NativeCore: out dst: -400

10 UMOV

无符号移动向量元素到通用寄存器,该指令从源 SIMD&FP 寄存器中读取无符号整数,对其进行零扩展以形成 32 位或 64 位值,并将结果写入目标通用寄存器。

在这里插入图片描述

32-bit (Q == 0)

UMOV <Wd>, <Vn>.<Ts>[<index>]

64-bit (Q == 1 && imm5 == x1000)

UMOV <Xd>, <Vn>.<Ts>[<index>]

<Xd> 是通用目标寄存器的 64 位名称,在“Rd”字段中编码。

<Vn> 是 SIMD&FP 源寄存器的名称,在“Rn”字段中编码。

<Ts> 是元素大小说明符,编码在“imm5”字段中。

对于 32 位变体:

imm5<Ts>
Bxxxx1
Hxxx10
Sxx100
RESERVEDxx000

对于 64 位变体:

imm5<Ts>
Dx1000
RESERVEDx0000
RESERVEDxxxx1
RESERVEDxxx10
RESERVEDxx100

<index>

对于 32 位变体:是在“imm5”字段中编码的元素索引。

imm5<index>
xx000RESERVED
xxxx1imm5<4:1>
xxx10imm5<4:2>
xx100imm5<4:3>

对于 64 位变体:是在“imm5<4>”中编码的元素索引。

下面是使用 UMOV 指令的例子。

    int len = 4;
    auto *src = new unsigned int[len];
    unsigned int dst = 0;

    for (int i = 0; i < len; i++) {
        src[i] = 100 * (i + 1);
    }
    LOGD("in src: src[%d]=%u src[%d]=%u src[%d]=%u src[%d]=%u", 0, src[0], 1, src[1],
         2, src[2], 3, src[3]);

    asm volatile(
        "LD1 {v0.4S}, [%[src]]\n"
        "UMOV %w[dst], v0.S[3]\n"
    :[src] "+r"(src),
     [dst] "+r"(dst)
    :
    : "cc", "memory", "v0");

    LOGD("-----------------------------");
    LOGD("out dst: %u", dst);

    delete[] src;

UMOV %[dst], v0.S[3] 将 v0 寄存器第四个 S 通道的值移动到通用 W 寄存器。

运行结果:

2023-06-10 08:06:12.981 20649-20649/com.example.myapplication D/native-armv8a: in src: src[0]=100 src[1]=200 src[2]=300 src[3]=400
2023-06-10 08:06:12.981 20649-20649/com.example.myapplication D/native-armv8a: -----------------------------
2023-06-10 08:06:12.981 20649-20649/com.example.myapplication D/native-armv8a: out dst: 400

参考资料

1.《ARMv8-A-Programmer-Guide》
2.《Arm® A64 Instruction Set Architecture Armv8, for Armv8-A architecture profile》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/658386.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

短视频seo系统源码私有化部署分享

短视频seo矩阵系统源码部署需要以下步骤&#xff1a; 确定系统环境要求&#xff1a;账号矩阵系统需要服务器环境支持PHP和MySQL数据库&#xff0c;因此需要确保服务器环境符合要求&#xff0c;并安装好相应的软件。例如&#xff0c;可以使用XAMPP或WAMP等软件包来快速安装PHP和…

中国唯一 一家Linux 基金会金牌会员 落户阿里云

导读2 月 20 日&#xff0c;全球知名非营利性组织 Linux 基金会宣布&#xff0c;阿里云正式成为 Linux 基金会金牌会员。阿里云表示将持续加大对开源项目的支持&#xff0c;并发挥自己的力量。 2 月 20 日&#xff0c;全球知名非营利性组织 Linux 基金会宣布&#xff0c;阿里云…

pyqt6安装

1、安装pyqt6和pyqt6-tools包 注意&#xff1a;pyqt6-tools目前仅支持python3.9版本&#xff0c;3.9版本后的安装部成功。&#xff08;截止2022.11.20&#xff09; 1.1 安装pyqt6和pyqt6-tools 安装pyqt和pyqt6-tools可以使用conda和pip进行安装 &#xff08;1&#xff09;…

【备战秋招】每日一题:2023.05-B卷-华为OD机试 - 报文回路

为了更好的阅读体检&#xff0c;可以查看我的算法学习博客报文回路 输入描述 第一行抓到的报文数量&#xff0c;后续C行依次输入设备节点D1和D2&#xff0c;表示从D1到D2发送了单向的报文&#xff0c;D1和D2用空格隔开 输出描述 组播通路是否“正常”&#xff0c;正常输出T…

SQL语言的四大组成部分——DCL(数据控制语言)

1️⃣前言 SQL语言中的DCL&#xff08;Data Control Language&#xff09;是一组用于控制数据库用户访问权限的语言&#xff0c;主要包括GRANT、REVOKE、DENY等关键字。 文章目录 1️⃣前言2️⃣DCL语言3️⃣GRANT关键字4️⃣REVOKE关键字5️⃣DENY关键字6️⃣总结附&#xff1…

从零搭建完整python自动化测试框架(UI自动化和接口自动化 )——持续更新

一、总体框架 总体框架如下图&#xff1a; 用例扫描、测试结果反馈&#xff0c;如要和其它项目管理系统或是用例管理系统对接&#xff08;比如testlink&#xff09;&#xff0c;就需要单独出来进行处理。 对于大型的产品&#xff0c;用例数特别多的话&#xff0c;需要建设一个…

AIGC提示(prompt)工程之开宗明义篇

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

VMware公司成为Linux基金会金牌会员

导读VMware是云基础架构和企业移动性的全球领导者&#xff0c;多年来一直积极参与开源开发。VMware通过Linux基金会项目(如ONAP&#xff0c;Cloud Native Computing Foundation(CNCF)&#xff0c;Cloud Foundry&#xff0c;Open vSwitch等)稳步提高其开源参与度。它刚刚成为了金…

HDFS初认识

HDFS初认识 文章目录 HDFS初认识HDFS是什么&#xff1f;HDFS的假想和设计目标HDFS的优缺点优点缺点 HDFS的架构组成客户端NameNodeDataNodeSecondary NameNode职责checkpoint机制 参考 HDFS是什么&#xff1f; Hadoop分布式文件系统&#xff08;HDFS&#xff09;是一个分布式文…

Websocket+protobuf怎么与服务器通信

Websocketprotobuf怎么与服务器通信 Websocket&#xff1a;WebSocket是⼀种⽹络传输协议&#xff0c;可在单个TCP连接上进⾏双全⼯通信&#xff0c;位于OSI模型的 应⽤层 实现⼀个简单的客⼾端和服务端 安装websockets pip3 install websockets客户端代码 import asyncio …

记一次异常外联事件应急响应

为方便您的阅读&#xff0c;可点击下方蓝色字体&#xff0c;进行跳转↓↓↓ 01 事件背景介绍02 事件分析过程03 事件分析结果04 安全加固建议 01 事件背景介绍 某内部应急演练中&#xff0c;安全部门收到来自业务部门的告警&#xff0c;称应用服务器存在异常外联情况&#xff0…

管理类联考——英语二——技巧篇——阅读理解——taiqi

第一章 翻译技巧概述 一、词汇方面 (一&#xff09;词义选择 大多数英语词汇是多义的&#xff0c;翻译时必须选择正确的词义。词义选择的方法有三&#xff1a;根据上下文和词的搭配选择根据词类选择、根据专业选择。 (二&#xff09;词义转换 在理解英文词汇的原始意义基础…

算法刷题-哈希表-三数之和

用哈希表解决了两数之和&#xff0c;那么三数之和呢&#xff1f; 第15题. 三数之和 力扣题目链接 给你一个包含 n 个整数的数组 nums&#xff0c;判断 nums 中是否存在三个元素 a&#xff0c;b&#xff0c;c &#xff0c;使得 a b c 0 &#xff1f;请你找出所有满足条件且…

后台服务守护进程神器pm2介绍及使用

前言 linux的后台服务程序需要在后台一直运行。如果通过ssh访问临时启动的&#xff0c;会话一结束就直接关闭了服务。想让服务在后台一直运行且永远不挂掉&#xff0c;推荐后台服务守护进程神器pm2&#xff0c;强大且适用于各种语言的后台服务程序。 pm2介绍 对于后台进程的管…

(十)异步-什么是异步方法(2)

一、什么是异步方法 异步方法在完成其工作之前即返回到调用方法&#xff0c;然后在调用方法继续执行的时候完成其工作。 特点&#xff1a; 方法头中包含 async 方法修饰符。包含一个或多个 await 表达式&#xff0c;表示可以异步完成的任务。必须具备3种返回类型之一&#x…

使用Gradio Interface构建交互式机器学习演示

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

chatgpt赋能python:Python列表排序方法介绍

Python 列表排序方法介绍 在 Python 中&#xff0c;列表是一种非常常见的数据类型。在处理列表时&#xff0c;有时需要对列表进行排序&#xff0c;以便更方便地对其进行查找、比较、统计等操作。Python 中提供了多种排序方法&#xff0c;本文将介绍这些方法并说明其使用方法。…

chatgpt赋能python:Python中的日期遍历方法详解

Python中的日期遍历方法详解 作为一门非常流行的编程语言&#xff0c;Python中的日期遍历方法备受程序员们喜爱。它可以遍历任意时间段内的日期并进行各种操作&#xff0c;比如日期加减、日期格式转换等等。在本文中&#xff0c;我们将详细介绍Python中的日期遍历方法&#xf…

lazarus:用FpSpreadsheet快速搭建基于电子表格文件的单机程序

目录 1 简介 2 制作简单的电子表格 3 需要几个控件&#xff0c;以及简单属性设置 3.1 TsWorksheetDataset 3.2 DataSource1控件 3.3 DBNavigate控件 3.4 DBGrid 3.5 编译运行&#xff0c;插入一行数据 1 简介 在FpSpreadsheet控件包中&#xff0c;有一个专门把电子表格…

Python3 注释与运算符 | 菜鸟教程(四)

目录 一、Python3 注释 &#xff08;一&#xff09;Python 中单行注释以 # 开头 &#xff08;二&#xff09;多行注释用三个单引号 或者三个双引号 """ 将注释括起来 1、单引号&#xff08;&#xff09; 2、双引号&#xff08;"""&#xff…