標籤:c編譯器 ucc 跳轉指令 彙編代碼產生
6.3.3 為跳轉指令產生彙編代碼
在這一小節中,我們要為“有條件跳轉”、“無條件跳轉”和“間接跳轉”產生相應的彙編指令。中間指令的四元式如下所示:
<運算子opcode,目的運算元DST,源運算元SRC1,源運算元SRC2>
(1) 有條件跳轉,例如“if (a <= b) goto BB2;”,四元式為:
<JLE,BB2,a,b>
////////對應的彙編代碼//////////
movl a, %eax //把SRC1的值暫存在寄存器eax中
cmpl b, %eax //比較eax和b的大小
jle .BB2 //進行有條件跳轉
(2) 無條件跳轉,例如“goto BB3;”,四元式為:
<JMP,BB3,NULL,NULL>
////////////對應的彙編代碼///////////////
jmp .BB3
(3) 間接跳轉,例如“goto (BB4,BB5,BB6)[t0];”,在翻譯switch語句時會產生間接跳轉指令,其四元式為:
<IJMP,[BB4,BB5,BB6,NULL],t0,NULL>
////////////對應的彙編代碼///////////////
.data
swtchTable1: .long .BB4
.long .BB5
.long .BB6
.text
jmp*swtchTable1(,%eax,4)
由於跳轉指令位於基本塊的最末尾,我們在第6.2節的“圖6.2.3 EmitBBlock()”中,已對x87棧頂寄存器做過回寫操作。在本小節,我們還要中調用ClearRegs函數,對於x86 CPU中的寄存器進行回寫,6.3.7第7行、第26行和第54行所示。控制流程即將隨著跳轉指令的執行而進入另一個基本塊,而UCC編譯器僅在同一基本塊內對公用子運算式進行重用,因此,即使跳轉指令裡的運算元DST、SRC1和SRC2是臨時變數,我們沒有必要為其“長期”分配寄存器,換言之,我們不會調用在前面的章節中介紹過的AllocateReg函數,而是調用6.3.7第13行所示的PutInReg函數,把運算元SRC1的值暫存到某個寄存器中。
圖6.3.7第1至30行的EmitBranch函數用於為“有條件跳轉”產生彙編代碼,當運算元是浮點數時,我們在第8行調用EmitX87Branch函數來處理。當運算元是整數時,我們會在第11行做進一步判斷。由於常數會以“立即數”的形式存在於代碼區中,當程式運行時,CPU會從代碼區裡預讀機器指令,從而把立即數也載入入CPU,因此當運算元SRC2是常數時,我們可以不必把SRC1的值載入到寄存器中,這不會違反“同一條X86彙編指令的兩個運算元不可以都在記憶體中”的定址要求。這意味著我們可以產生形如“cmpl $3, a”的比較指令,但不可以產生形如“cmpl b, a”的比較指令。圖6.3.7第11至14行會在“SRC2存在且SRC2不是常數時”,通過第13行調用的PutInReg函數,把SRC1的值載入到某個寄存器中。第17行判斷SRC1的值是否在寄存器中,如果已載入寄存器,我們可在第18行把中間指令裡的源運算元SRC1改為SRC1->reg,之後在就可產生形如“cmpl b, %eax”的比較指令。第28行調用PutASMCode函數來產生比較和跳轉指令,形如“cmpl b, %eax;jle .BB2 ”。
圖6.3.7 EmitBranch()和EmitJump()
圖6.3.7第31至39行的EmitX87Branch用於處理浮點數的有條件跳轉,我們會在第34行先把運算元SRC1載入到x87棧頂寄存器中,然後在第37行產生浮點數比較和跳轉的指令,形如第35至36行的模板所示。我們已在“1.5 結合C語言來學彙編”介紹過這些指令,這裡不再重複。圖6.3.7第50至56行的函數EmitJump會為無條件跳轉產生彙編代碼。
接下來,我們來討論一下為“間接跳轉”產生彙編代碼的函數EmitIndirectJump,6.3.8所示。圖6.3.8第7行調用PutInReg函數把運算元SRC1載入到寄存器中,第10行用於產生“.data”,表示接下來的內容為資料區,第11至17行建立一個名稱形如“swtchTable1”的符號對象,第23至33行會在資料區中建立跳轉表,形如第19至21行所示。第36行輸出“.text”,表示接下來的內容為代碼區。由於已在第7行把SRC1載入到寄存器reg中,我們就可在彙編指令中使用該寄存器的名稱,為此我們要在第37行把中間指令的SRC1改為相應的寄存器。第38行調用ClearRegs對x86 CPU中的寄存器進行了必要的回寫,第41行調用PutASMCode產生了形如“jmp*swtchTable1(,%eax,4)”的彙編指令。
圖6.3.8 EmitIndirectJump()
C編譯器剖析_6.3.3 彙編代碼產生_為跳轉指令產生彙編代碼