Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 导致无前缀错误的内联程序集_C_Assembly_Clang_Inline Assembly_Gnu Assembler - Fatal编程技术网

C 导致无前缀错误的内联程序集

C 导致无前缀错误的内联程序集,c,assembly,clang,inline-assembly,gnu-assembler,C,Assembly,Clang,Inline Assembly,Gnu Assembler,你好, 所以,我正在优化我为正在开发的简单操作系统编写的一些函数。此函数,putpixel(),当前看起来像这样(如果我的程序集不清楚或错误): uint32\u t loc=(x*像素w)+(y*间距); vidmem[loc]=颜色&255; vidmem[loc+1]=(颜色>>8)和255; vidmem[loc+2]=(颜色>>16)和255; 这需要一点解释。首先,loc是我想在视频内存中写入的像素索引。X和Y坐标传递给函数。然后,我们将X乘以像素宽度(以字节为单位)(在本例中为3

你好,

所以,我正在优化我为正在开发的简单操作系统编写的一些函数。此函数,
putpixel()
,当前看起来像这样(如果我的程序集不清楚或错误):

uint32\u t loc=(x*像素w)+(y*间距);
vidmem[loc]=颜色&255;
vidmem[loc+1]=(颜色>>8)和255;
vidmem[loc+2]=(颜色>>16)和255;
这需要一点解释。首先,
loc
是我想在视频内存中写入的像素索引。X和Y坐标传递给函数。然后,我们将X乘以像素宽度(以字节为单位)(在本例中为3),将Y乘以每行中的字节数。可以找到更多信息

vidmem
是一个全局变量,是指向视频内存的
uint8\t
指针

也就是说,任何熟悉按位操作的人都应该能够相当容易地理解
putpixel()
的工作原理

现在,这是我的集会。请注意,它还没有经过测试,甚至可能更慢,或者根本无法工作。这个问题是关于如何使它编译

我将
loc
定义后的所有内容替换为:

\u asm(
“按%%rdi;”
“按%%rbx;”
mov%0,%%rdi
lea%1,%%rbx
添加%%rbx,%%rdi
“pop%%rbx;”
mov%2,%%rax
“stosb;”
“shr$8,%%rax;”
“stosb;”
“shr$8,%%rax;”
“stosb;”
“pop%%rdi;”::
“r”(loc)、“r”(vidmem)、“r”(颜色)
);
当我编译此命令时,对于每个
push
指令,clang都会给我这个错误:

所以当我看到这个错误时,我认为这与我省略了GAS后缀有关(无论如何,这应该是隐式决定的)。但是当我添加了“l”后缀(我所有的变量都是
uint32\u t
s)时,我得到了同样的错误!我不太确定是什么原因造成的,任何帮助都将不胜感激。提前谢谢

发现问题了

它在很多地方,但主要的是
vidmem
。我以为它会通过地址,但它导致了一个错误。在把它称为dword之后,它工作得非常好。我还必须将其他约束更改为“m”,我最终得到了这个结果(经过一些优化):

\u asm(
movl%0,%%edi
movl%k1,%%ebx
添加%%ebx、%%edi
movl%2,%%eax
“stosb;”
shrl$8,%%eax
“stosw;”::
“m”(loc)、“r”(vidmem)、“m”(彩色)
:“edi”、“ebx”、“eax”
);

感谢所有在评论中回答的人

在存储之前将
vidmem
加载到一个局部变量中,可能会使C版本的编译器输出效率更高。实际上,它不能假设存储没有别名
vidmem
,因此它会在每个字节存储之前重新加载指针。Hrm,这确实让GCC4.9.2避免了重新加载
vidmem
,但它仍然会生成一些讨厌的代码。Clang3.5做得稍微好一点

实现我在对您的回答的评论中所说的内容(即
stos
是3个uops,而
mov
是1个uops):

所有这些指令在英特尔CPU上解码为单个uop。(存储可以微融合,因为它们使用单寄存器寻址模式。)
movl%esi,%esi
将上限32归零,因为调用方可能已使用64位指令生成该函数arg,剩余垃圾位于
%rsi
的高位32。您的版本本来可以通过使用约束首先请求所需寄存器中的值来保存一些指令,但这仍然比
stos

还要注意我是如何让编译器负责将
loc
添加到
vidmem
的。你本可以在你的电脑中更有效地完成这项工作,使用
lea
将添加与移动相结合。然而,如果编译器想在循环中使用它时变得更聪明,它可以增加指针而不是地址。最后,这意味着相同的代码将适用于32位和64位<代码>%[ptr]在64位模式下为64位reg,但在32位模式下为32位reg。因为我不需要对它做任何数学运算,它就行了

我使用
=m
输出约束告诉编译器我们在内存中写入的位置。(我应该将指针投射到一个
结构{char a[3];}
或其他东西,告诉gcc它实际写入了多少内存,如中“Clobbers”部分末尾的提示所示)

我还使用
color
作为输入/输出约束,告诉编译器我们修改了它。如果这是内联的,并且以后的代码仍然希望在寄存器中找到
color
的值,那么我们就有问题了。在函数中使用此选项意味着
color
已经是调用方值的tmp副本,因此编译器将知道它需要丢弃旧颜色。使用两个只读输入在循环中调用此函数可能会稍微更有效:一个用于
color
,一个用于
color>>8

请注意,我可以将约束编写为

    : [col] "+r" (color), [memref] "=m" (vidmem[loc])
    :
    :
但是使用
%[memref]
1%[memref]
生成所需的地址将导致gcc发出

    movl    %esi, %esi
    movq    vidmem(%rip), %rax
# APP
    movb %edi, (%rax,%rsi)
    shrl $8, %edi;
    movw %edi, 1 (%rax,%rsi);
双寄存器寻址模式意味着存储指令不能微融合(至少在Sandybridge和更高版本上)

不过,您甚至不需要内联asm来获得像样的代码: 编译为(gcc 4.9.2和clang 3.5给出相同的输出):

这只比我们内联asm的效率低一点点,如果内联到循环中,优化器应该更容易进行优化

整体表现 在循环中调用这个可能是一个错误。将多个像素组合在一个寄存器(特别是向量寄存器)中,然后一次写入所有像素将更有效。或者,执行4字节写入,与上一次写入的最后一个字节重叠,直到到达末尾,并且必须在最后一块3之后保留该字节

    : [col] "+r" (color), [memref] "=m" (vidmem[loc])
    :
    :
    movl    %esi, %esi
    movq    vidmem(%rip), %rax
# APP
    movb %edi, (%rax,%rsi)
    shrl $8, %edi;
    movw %edi, 1 (%rax,%rsi);
void putpixel_cast(uint32_t color, uint32_t loc)
{
    // uint32_t loc  = (x*pixel_w)+(y*pitch);
    typeof(vidmem) vmem = vidmem;
    vmem[loc]   = color & 255;
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
    *(uint16_t *)(vmem+loc+1) = color >> 8;
#else
    vmem[loc+1] = (color >> 8) & 255; // gcc sucks at optimizing this for little endian :(
    vmem[loc+2] = (color >> 16) & 255;
#endif
}
    movq    vidmem(%rip), %rax
    movl    %esi, %esi
    movb    %dil, (%rax,%rsi)
    shrl    $8, %edi
    movw    %di, 1(%rax,%rsi)
    ret