簡體   English   中英

ARMv8浮點輸出內聯匯編

[英]ARMv8 floating point output inline assembly

為了添加兩個整數,我寫:

int sum;
asm volatile("add %0, x3, x4" : "=r"(sum) : :);

如何用兩個浮子做到這一點? 我試過了:

float sum;
asm volatile("fadd %0, s3, s4" : "=r"(sum) : :);

但這給了我一個錯誤:

錯誤:操作數1應該是SIMD向量寄存器-`fadd x0,s3,s4'

有任何想法嗎?

因為寄存器在AArch64中可以有多個名稱(v0,b0,h0,s0,d0都引用同一個寄存器),所以有必要在打印字符串中添加輸出修飾符:

在哥德寶

float foo()
{
    float sum;
    asm volatile("fadd %s0, s3, s4" : "=w"(sum) : :);
    return sum;
}

double dsum()
{
    double sum;
    asm volatile("fadd %d0, d3, d4" : "=w"(sum) : :);
    return sum;
}

將產生:

foo:
        fadd s0, s3, s4 // sum
        ret     
dsum:
        fadd d0, d3, d4 // sum
        ret  

"=r"是GP整數寄存器的約束。

GCC手冊聲稱"=w"是AArch64上FP / SIMD寄存器的約束。 但是,如果嘗試這樣做,則不會得到v0而不是s0 我在這里不知道解決方法,您可能應該報告gcc bugzilla,該手冊中記錄的約束不適用於標量FP。

在Godbolt上,我嘗試了以下來源:

float foo()
{
    float sum;
#ifdef __aarch64__
    asm volatile("fadd %0, s3, s4" : "=w"(sum) : :);   // AArch64
#else
    asm volatile("fadds %0, s3, s4" : "=t"(sum) : :);  // ARM32
#endif
    return sum;
}

double dsum()
{
    double sum;
#ifdef __aarch64__
    asm volatile("fadd %0, d3, d4" : "=w"(sum) : :);   // AArch64
#else
    asm volatile("faddd %0, d3, d4" : "=w"(sum) : :);  // ARM32
#endif
    return sum;
}

clang7.0(及其內置的匯編程序)要求asm實際上是有效的。 但是對於gcc,我們僅編譯為asm,而Godbolt對於非x86沒有“二進制模式”。

# AArch64 gcc 8.2  -xc -O3 -fverbose-asm -Wall
# INVALID ASM, errors if you try to actually assemble it.
foo:
    fadd v0, s3, s4 // sum
    ret     
dsum:
    fadd v0, d3, d4 // sum
    ret

clang產生相同的asm,並且其內置匯編器錯誤包括:

<source>:5:18: error: invalid operand for instruction
    asm volatile("fadd %0, s3, s4" : "=w"(sum) : :);
                 ^
<inline asm>:1:11: note: instantiated into assembly here
        fadd v0, s3, s4
             ^

在32位ARM上=t"表示單項工作,但是"=w"表示(本手冊說您應該使用雙精度),gcc也會給您s0 。但是它適用於clang。您必須使用-mfloat-abi=hard-mcpu=帶有FPU的東西,例如-mcpu=cortex-a15

# clang7.0 -xc -O3 -Wall--target=arm -mcpu=cortex-a15 -mfloat-abi=hard
# valid asm for ARM 32
foo:
        vadd.f32        s0, s3, s4
        bx      lr
dsum:
        vadd.f64        d0, d3, d4
        bx      lr

但是gcc失敗了:

# ARM gcc 8.2  -xc -O3 -fverbose-asm -Wall -mfloat-abi=hard -mcpu=cortex-a15
foo:
        fadds s0, s3, s4        @ sum
        bx      lr  @
dsum:
        faddd s0, d3, d4        @ sum    @@@ INVALID
        bx      lr  @

因此,對於gcc,可以將=t用於單值,但對於double可以使用%something0修飾符,以將寄存器名稱顯示為d0而不是s0 ,並輸出"=w"


顯然,如果您還添加了約束以指定輸入操作數,而不是讀取s3和s4中的內容,則這些asm語句僅對語法學習以外的任何事情有用。

另請參閱https://stackoverflow.com/tags/inline-assembly/info

ARMv7 double: %P修飾符

GCC開發人員在https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89482#c4告知我正確的ARMv7修飾符加倍了,也許有一天我應該不再懶惰並grep GCC:

main.c中

#include <assert.h>

int main(void) {
    double my_double = 1.5;
    __asm__ (
        "vmov.f64 d0, 1.0;"
        "vadd.f64 %P[my_double], %P[my_double], d0;"
        : [my_double] "+w" (my_double)
        :
        : "d0"
    );
    assert(my_double == 2.5);
}

編譯並運行:

sudo apt-get install qemu-user gcc-arm-linux-gnueabihf
arm-linux-gnueabihf-gcc -O3 -std=c99 -ggdb3 -march=armv7-a -marm \
  -pedantic -Wall -Wextra -o main.out main.c
qemu-arm -L /usr/arm-linux-gnueabihf main.out

拆卸包含:

   0x00010320 <+4>:     08 7b b7 ee     vmov.f64        d7, #120        ; 0x3fc00000  1.5
   0x00010324 <+8>:     00 0b b7 ee     vmov.f64        d0, #112        ; 0x3f800000  1.0
   0x00010328 <+12>:    00 7b 37 ee     vadd.f64        d7, d7, d0

在Ubuntu 16.04,GCC 5.4.0,QEMU 2.5.0中進行了測試。

源代碼定義點

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM