條件分支
程式不只是一串由上而下執行的步驟,它會做決定:如果密碼正確就登入,否則拒絕。在機器層級,這個岔路口就是條件分支(conditional branch):一道指令,先測試某件事,再依結果決定是跳到程式碼的另一處,還是直接落到下一行。這是硬體提出是非題、並走向兩條路之一的方式。
分支作用在程式計數器(program counter)上,也就是存放下一道指令位址的暫存器。平常程式計數器只是前進到下一道指令。條件分支會比較兩個值(或檢查某個旗標),若條件成立,就改用某個標籤目標的位址取代程式計數器。在 RISC-V 中,beq a0, a1, label 的意思是「若 a0 等於 a1 則分支」:若相等,執行就跳到 label;若不相等,就繼續往下走。還有不等於(bne)、小於(blt)、大於等於(bge)等變體。這就是組成 IF/ELSE 與迴圈的單一基本零件。
條件分支對效能的影響極大,而不只關乎正確性。一顆全速向前奔跑的處理器,在分支被計算出來之前並不知道它會往哪走,於是它會猜(分支預測,branch prediction),並悄悄為猜測的那條路先做好工作。猜錯就白費了那些工。這就是為什麼層層巢狀、難以預測的分支會慢,也是為什麼編譯器與程式設計者有時會重整程式碼,讓分支更好預測、甚至乾脆避開分支。
手動翻譯 if (a == b) x = 1; else x = 2;: beq a0, a1, equal # 若 a0 == a1 跳到 equal li t0, 2 # else 分支:x = 2 j done equal: li t0, 1 # then 分支:x = 1 done: beq 決定走哪條路;j(jump)跳過 else 部分。
IF/ELSE 變成一道條件分支、一道無條件跳躍,再加上幾個標籤。
手動翻譯時常見的錯誤:忘了在 else 區塊之前放一道無條件跳躍,導致 then 路徑落穿過去、把 else 的程式碼也跑了一遍。