CPU 速度遠超記憶體,有效利用寄存器可大幅減少記憶體存取。UCC 編譯器在中間代碼階段用臨時變數 t 保存公共子運算式(如 t: a+b),生成匯編時盡量將這些值放入寄存器重用。
eax, ebx, ecx, edx, esi, edi(6 個),esp/ebp 保留給堆疊幀。原始碼:
s3 = a + b; s4 = c + d; s5 = (a + b) + (c + d); // 重用 t0=a+b, t1=c+d s6 = (a + b) * (c + d); // 再次重用
中間代碼產生 3 個臨時變數(t0, t1, t2),對應 12 位元組堆疊空間。匯編代碼中:
eax 分配給 t0 (a+b),全程保持直到不再使用。edx 分配給 (a+b)+(c+d)。g 中因基本塊結束,eax 可重新分配給新運算式。GetRegInternalwidth 指定寬度(1/2/4 位元組),對應不同寄存器集合。FindEmptyReg),排除 esp/ebp 且未被當前指令佔用。SelectSpillReg 選擇犧牲寄存器:依據對應臨時變數剩餘引用次數總和,回寫引用最少者(類似 LRU)。SpillReg 執行回寫:僅當寄存器值已修改(needwb)且後續仍需使用(ref > 0)才產生存儲指令。僅使用棧頂寄存器保存單一浮點臨時變數,指標 X87Top 追蹤。控制流離開基本塊或函數調用前呼叫 SaveX87Top 回寫。
EmitBlockEmitIRInst 透過查表分派具體生成函數(如 EmitJump、EmitCall)。ClearRegs),函數調用依呼叫慣例僅回寫 eax, ecx, edx。d = (a > 0 ? b : c) + 1; // 中間碼: // if (a <= 0) goto BB4; // BB3: t0 = b; goto BB5; // BB4: t0 = c; // BB5: t1 = t0 + 1; d = t1;
t0 在 BB3/BB4 分別賦值,離開塊時必須回寫,確保 BB5 讀到正確值。