除了其他方面,x86-64 SysV ABI指定了如何在寄存器中传递函数参数(第一个参数in rdi,then rsi等等),以及如何传回整数返回值(in rax和then rdx表示非常大的值).
然而,我找不到的是当传递小于64位的类型时,参数或返回值寄存器的高位应该是什么.
例如,对于以下功能:
void foo(unsigned x, unsigned y);
Run Code Online (Sandbox Code Playgroud)
... x将被传入rdi和y在rsi,但他们只是32位.不要的高32位rdi和rsi必须为零?直观地说,我会假设是,但是所有gcc,clang和icc 生成的代码mov在开始时都有特定的指令将高位清零,所以看起来编译器假定不然.
类似地,编译器似乎假设rax如果返回值小于64 位,则返回值的高位可能具有垃圾位.例如,以下代码中的循环:
unsigned gives32();
unsigned short gives16();
long sum32_64() {
long total = 0;
for (int i=1000; i--; ) {
total += gives32();
}
return total;
}
long sum16_64() {
long total = 0;
for (int i=1000; i--; ) {
total += …Run Code Online (Sandbox Code Playgroud) 在-XX:+PrintCompilation最近使用(JDK 8r111)来检查方法编译时,我注意到一个新列,它没有出现在我可以在该主题上找到的文档中:
this column
|
|
v
600 1 s 3 java.util.Hashtable::get (69 bytes)
601 4 3 java.lang.Character::toLowerCase (6 bytes)
601 8 3 java.io.UnixFileSystem::normalize (75 bytes)
602 12 3 java.lang.ThreadLocal::get (38 bytes)
602 14 3 java.lang.ThreadLocal$ThreadLocalMap::getEntry (42 bytes)
602 18 2 java.lang.String::startsWith (72 bytes)
602 10 4 java.lang.String::equals (81 bytes)
602 2 % 4 java.lang.String::hashCode @ 24 (55 bytes)
602 16 s! 3 sun.misc.URLClassPath::getLoader (197 bytes)
603 23 n 0 java.lang.System::arraycopy (native) (static)
604 …Run Code Online (Sandbox Code Playgroud) struct在某些情况下,我注意到clang和gcc优化了堆栈中声明的volatile的构造或赋值.例如,以下代码:
struct nonvol2 {
uint32_t a, b;
};
void volatile_struct2()
{
volatile nonvol2 temp = {1, 2};
}
Run Code Online (Sandbox Code Playgroud)
编译 clang:
volatile_struct2(): # @volatile_struct2()
ret
Run Code Online (Sandbox Code Playgroud)
另一方面,gcc不会删除商店,尽管它确实将两个隐含商店优化为一个商店:
volatile_struct2():
movabs rax, 8589934593
mov QWORD PTR [rsp-8], rax
ret
Run Code Online (Sandbox Code Playgroud)
奇怪的是,clang不会将易失性存储优化为单个int变量:
void volatile_int() {
volatile int x = 42;
}
Run Code Online (Sandbox Code Playgroud)
编译为:
volatile_int(): # @volatile_int()
mov dword ptr [rsp - 4], 1
ret
Run Code Online (Sandbox Code Playgroud)
此外,没有优化具有1个成员而不是2个成员的结构.
虽然gcc在这种特殊情况下不会删除构造,但在struct成员本身被声明的情况下,它可能甚至更积极的优化volatile,而不是在struct构造点本身:
typedef struct {
volatile uint32_t a, b;
} vol2;
void volatile_def2()
{ …Run Code Online (Sandbox Code Playgroud) 在支持的英特尔x86-64的系统syscall和sysret什么是从64位用户代码"最快"的系统调用在香草内核?
特别是,它必须是一个系统调用来执行syscall/ sysretuser < - >内核转换1,但除此之外的工作量最少.它甚至不需要进行系统调用本身:某种类型的早期错误从未调度到内核端的特定调用,这是好的,只要它不会因为这样而走慢路径.
这样的调用可用于估计原始syscall和sysret开销,而与呼叫完成的任何工作无关.
1特别是,这排除了似乎是系统调用但在VDSO中实现的内容(例如,clock_gettime)或由运行时缓存(例如getpid).
考虑以下x86-64程序集:
inner:
...
ret
outer:
.top:
call inner
dec rdi
jnz .top
ret
Run Code Online (Sandbox Code Playgroud)
该函数outer只是重复call地对函数inner(其主体未显示) - 它可能是空的.
内部的一系列call指令outer和相应的ret指令是否inner在实践中形成一个依赖链(为了估计性能)?
这条链可以形成多种方式.例如,是否ret依赖于前一条call指令的延迟,然后后续call指令是否依赖于ret,形成call -> ret -> call链?或者也许ret是独立但call不是,形成一个call -> call链?如果有链,是通过内存,寄存器,堆栈引擎,返回地址预测器1还是什么?
动机:这个问题起源于对另一个问题的一系列评论,主要是这个评论和早期评论.
1这里的术语可能有些不清楚:堆栈引擎通常被理解为将转换rsp修改指令处理为具有适当偏移的单个访问,因此push rax; push rbx可能会转换为某些临时寄存器,mov [t0], rax; mov [t0 - 8], …
特别是,允许不同函数中两个自动变量的地址比较如下:
sink.c
#include <stdio.h>
#include <stdlib.h>
void sink(void *l, void *r) {
puts(l == r ? "equal" : "not equal");
exit(0);
}
Run Code Online (Sandbox Code Playgroud)
main.c中
typedef struct { char x[32]; } Foo;
void sink(void *l, void *r);
Foo make(void *p) {
Foo f2;
sink(&f2, p);
return f2;
}
int main() {
Foo f1 = make(&f1);
}
Run Code Online (Sandbox Code Playgroud)
我希望它可以打印not equal的f1和f2是不同的对象.使用gcc我得到了not equal,但是使用我的本地版本的clang 3.8 1,它在打印equal时编译为clang -O1 sink.c main.c2.
拆卸make和main …
我想创建一个宏或函数1 mask(n),给定一个数字n返回一个无符号整数,其n最低有效位设置.虽然这似乎应该是一个基本的原语,经过大量讨论的实现有效编译 - 似乎并非如此.
当然,各种实现对于原始整数类型可能具有不同的大小unsigned int,因此,为了具体起见,我们假设我们正在讨论uint64_t具体返回,尽管当然可接受的解决方案对于任何无符号整数类型都有效(具有不同的定义).特别是,当返回的类型等于或小于平台的原始宽度时,解决方案应该是高效的.
重要的是,这必须适用于所有人n[0,64].尤其是mask(0) == 0和mask(64) == (uint64_t)-1.许多"明显的"解决方案不适用于这两种情况之一.
最重要的标准是正确性:只有不依赖于未定义行为的正确解决方案才是有趣的.
第二个最重要的标准是性能:理想情况下,成语应该编译成大致最有效的平台特定方式,以便在通用平台上执行此操作.
在性能名称中牺牲简单性的解决方案,例如,在不同平台上使用不同的实现,是很好的.
1最常见的情况是一个函数,但理想情况下它也可以作为宏工作,而不必多次重新评估它的任何参数.
假设我正在实现一个集合,例如std::vector。我需要实现iterator和const_iterator,但是一旦完成,iterator就const_iterator不能仅实现为iterator<const T>(T集合中的类型在哪里)?
一定有原因为什么它不起作用,因为有上百万个问题有关如何在实现时重用代码iterator,const_iterator但是没有一个说“仅const T作为类型使用”。