2013-04-04 134 views
4

我知道什麼時候使用一個皮匠列表(例如列出一個在程序集中修改過的寄存器,以便它不會被選作輸入寄存器等),但是我無法將頭圍繞在早期約束&。如果列出你的輸出,那麼這不意味着輸入不能使用選定的寄存器(除了匹配的數字約束)?何時在擴展GCC內聯彙編中使用earlyclobber約束?

例如:

asm(
    "movl $1, %0;" 
    "addl $3, %0;" 
    "addl $4, %1;" 
    "addl %1, %0;" 
    : "=g"(num_out) 
    : "g"(num_in) 
    : 
); 

&甚至需要爲輸出變量?編譯器應該知道爲輸出選擇的寄存器,因此不知道用於輸入。

回答

10

默認情況下,編譯器假定在寫入任何輸出寄存器之前,所有輸入都將被消耗,因此它允許兩者使用相同的寄存器。如果可能的話,這會導致更好的代碼,但是如果這種假設是錯誤的,事情將會發生災難性的失敗。 「早期的clobber」標記是告訴編譯器這種輸出將在所有輸入被消耗之前被寫入的一種方式,因此它不能與任何輸入共享一個寄存器。

+0

因此,這意味着編譯器可以假設我輸入所用的'eax'寄存器在需要輸出時不再需要,因此它會重用'eax'寄存器?這是否意味着原始問題中代碼中的輸出事實上需要'&'修飾符? – 2013-04-04 19:29:14

+2

由於多種原因,您的代碼有誤。例如,你正在修改一個輸入寄存器。 – 2013-04-04 20:31:47

+0

x86的典型「earlyclobber」是使用擴展乘法,其中'EDX:EAX' /'RDX:RAX' _implicitly_是輸出。當這些指令用於多輸入'asm()'語句中時,在早期輸出「消耗」內容之後,'d'和'a'寄存器不能用作輸入。如果該特定輸入操作數被多次使用,編譯器會將其放入_different_寄存器。 – 2013-04-19 08:43:17