-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LoongArch64实验性向量调用约定实现 (Experimental implementation of LoongArch64 vector calling convention) #114
Comments
复数类型需要特殊考虑吗? 在目前的非向量调用惯例中复数直接当成有两个浮点成员的结构体,会用两个 FPR,但是 CPUCFG word 2 bit 8 预留了“复数向量指令”,而且好像 (?) 即使没有专用的复数向量指令而只用一般向量指令,用向量寄存器传复数也是有好处的 (至少加减法就简化成一条指令)。 另外可以学 RISC-V 在二进制文件中打标记以防止不小心把 ABI 不兼容的东西链接起来:https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#dynamic-linking |
复数之前还没有考虑过,感觉可以试一试 不过之前准备在代码里如果出现了“有向量参数,vecarg开了,向量没开”的情况下给出警告,因为代码需要改动的地方比较多还没有做出来 |
对,就是在这种情况下让 ld 或者 ld.so 直接报错,不然运行到一半输出一堆乱码之类的很难调试。 |
可能需要考虑同一编译单元内的混搭:例如用户可能希望综合使用 GNU ifunc、 |
此外,考虑到这些研究成果在世界范围尚属新颖(如果没记错的话,RISC-V 的类似调用约定也未定稿),可能将这些内容翻译之后向 GCC、LLVM 等编译器社区发出 RFC 是不错的选择。这样也可以避免由于我们这些人菜,而未能提前预见,而造成又一次 rebuild world 之类的大量额外工作量。 |
RISC-V 的 STO_RISCV_VARIANT_CC 是符号粒度的,可以每个符号不一样。 |
另外还有 __int128 要不要走向量寄存器,因为我们向量指令集自带 128 位加减法,虽然我还没算清楚用向量指令做 128 位乘除会不会比一般做法快…… |
感觉可能要同时实现一下相关的128位操作,现在的运算依然还是用标量指令做的,如果走向量寄存器的话现在可能还涉及到取回标量寄存器去做运算的情况? 另外我发现之前的代码关于-mvecarg和vecarg attribute的实现有点问题(两者变成and的关系了,预想的是or的关系),稍微修复了一下。 |
可能不合适,这样的话会让 int128 的 ABI 取决于是否假定存在硬件向量扩展。另外,在做不受 LSX/LASX 直接支持的整数操作时,可能代价比倒腾两个整数寄存器更大。 |
最近尝试了以下似乎不太好实现
diff
|
For English version, please keep scrolling down.
这是目前基于GCC对LA64实现的一个实验性的向量调用约定,代码位于dev/vecarg分支,如果存在问题和不完善的情况欢迎大家进行讨论。如果中英文版本之间存在描述模棱两可的情况也请提出,谢谢大家!
代码位于#113
关键字
向量类型
向量的比特位宽可以是128bit或者256bit,并且总是包含多个元素。向量元素从最低比特起占据向量空间,并且拥有从0开始递增的index。
向量的元素类型遵循于LP64数据模型。
向量寄存器
LA64可以选择性的实现32个128位或者256位的向量寄存器硬件。如果实现向量寄存器,则必须实现双精度浮点硬件单元。
同编号的256位向量寄存器的低半部分与128位寄存器共用,同编号的128位向量寄存器低半部分和浮点寄存器共用。
以下为向量寄存器的使用约定:
TODO:对于在过程间保存完整内容的寄存器(static register/callee-saved register),目前尚无明确最终方案,需要有效的性能测试手段来辅助判断。
目前在配合sleef向量数学库(还未提交社区)对x264、libjpeg-turbo进行性能测试的过程中,不同s/t寄存器的分配对性能没有产生明显影响。
向量调用约定
向量调用约定扩展是叠加于LP64D之上、使用128/256位向量寄存器,对向量参数和返回值进行传递的调用约定扩展。
可以通过以下的方式启用该调用约定:
为了使向量调用约定在函数、编译模块之间的行为保持一致,需要遵循以下的要求:
p.s.: 对于GCC当前的PoC实现,vecarg选项对应
-mvecarg
, vecarg属性对应于__attribute__ ((vecarg))
。子程序调用流程
在以下的向量调用约定描述中,对于128/256位向量的传递描述中,我们都认为编译器开启了对应位宽的向量指令支持。
寄存器
VAR:0-7号向量寄存器按照编号依次用于向量参数的传递。同时,0-1号向量寄存器用于向量返回值的传递。向量参数传递时,总是会选择VRLEN等于向量参数位宽的VAR进行传递。
参数传递
在启用向量调用约定时,参数可能的传递形式如下:
单个向量参数的传递
128位向量
256位向量
带有向量成员的结构体的传递
无论何种场合,最多仅使用两个寄存器(所有使用的寄存器类型的数量之和)进行结构体的传递,否则从栈进行参数传递。
p.s.:如果结构体成员包含0长度位域、0长度数组、空结构体或空组合体等成员,其处理规则与基础ABI中Other structures中所描述的处理方式相同。
可变长参数列表的传递
对于向量参数,不使用VAR/FAR进行传递。
对于128位向量,如果至少有两个GAR可用,并且首个GAR的编号为偶数,则使用这对GAR传递参数。
对于256位向量,根据向量位宽遵循现有基础ABI定义。
返回值
0-1号VAR用于返回值的传递,传递方式与参数列表中首个参数的传递逻辑相同。
This is a experimental vector calling convention impl. for LoongArch64 based on GCC. The ad-hoc implementation can be found in this pull request: #113.
Any discussions about this prototype calling convention are welcome! And please report any inconsistency between Chinese and English version. Thanks!
Keywords
Vector Types
A vector can be either 128 bits or 256 bits width, and always contains
multiple elements. Each member of vector consecutively occupies the vector
from lowest bits, and has index that starting from zero.
Elements of a vector always have same base scalar type from LP64 data model.
Vector Register
LoongArch machines that implements LA64 can optionally have 32 vector registers
may be either 128 or 256-bit, depending on the hardware implementation. double-precision
FPU is required for vector registers. Floating-point registers and vector registers that have same
index postfix follow the overlapping rules below:
TODO: For "static register"/"callee-saved register", we didn't have a clear resolution for now, and we need effective performance measurements for definition.
In current performance test, when utilize different static/temp register allocation solutions with vector calling convention, x264/libjpeg-turbo's testing tool and sleef vector math library(loongarch support not released yet), we can't see significant difference in performance outputs.
Vector Calling Conventions
Vector calling convention extension is based on the LP64D, it utilizes 128-bit/256-bit vector register to pass vector argument and return value.It can be enabled via:
For consistent behavior between objects and functions, following rules should be considered while utilizing vector calling conventions:
p.s.: For current GCC PoC implementation, "vecarg option" refers to
-mvecarg
, "vecarg attribute" refers to__attribute__ ((vecarg))
。Subroutine Calling Sequence
In the following description of vector calling convention, we assume 128/256-bit vector insturction support is enabled in compiler while utilizing corresponding convention.
Registers
VAR: Number 0 - 7 vector register are preserved for vector argument passing, and number 0 - 1 vector are also used for vector return value.
Argument Passing
When vector calling convention is enabled, the possible passing method will be one of the following options:
$sp
.Passing Single Vector Argument
128-bit vector argument
256-bit vector argument
Passing Struct with Vector Member
For all conditions, we only use at most 2 registers(sum of all register types) to pass a struct with vector member, otherwise pass structure on stack.
p.s.: If struct contains zero-with bit field/zero-length array/empty struct/empty union, the passing rule is same as the description of "Other Structure" in base ABI document.
Variadic arguments
We don't use VAR/FAR to pass vector arguments.
For 128-bit vector argument, if at least 2 GARs are available, and first GAR's number is even, then use this pair of GARs to pass argument.
For 256-bit vector argument, it follows the current base ABI conventions with its data bit-width(256-bit).
Return Value
0 - 1 VARs are used for passing return value. The passing rule of return value is same as the first argument's method of argument list.
The text was updated successfully, but these errors were encountered: