跳轉到

1980-RISC與編譯器#

案件摘要#

1970 年代末,微處理器走上 CISC 軍備競賽:VAX 有 300 多道指令、x86 指令越加越複雜,微碼層層轉譯、效率低落。1980-1982 年,Berkeley 的 David Patterson 與 Stanford 的 John Hennessy 各自帶隊,用量化追蹤發現了一個驚人的事實:編譯器產生的程式中,簡單指令佔絕大多數——那何必把硬體做得那麼複雜?他們反其道而行:簡化指令集,把優化責任交給編譯器。RISC 革命證明「硬體與編譯器要一起設計」,最終為兩人贏得 2017 年圖靈獎,並讓今日 ARM、RISC-V 晶片統治世界。

前因 -- 為什麼會有這個案子#

  • CISC 的微碼暴政:VAX-11/780(1977)的指令集複雜到硬體直接實作不划算,於是靠微碼(microcode)轉譯——每道複雜指令在內部拆成一串微指令,層層開銷;編譯器卻很難有效利用這些指令。
  • 記憶體與 CPU 的速度差:半導體記憶體追不上 CPU,複雜指令想「一道指令做多件事」來減少記憶體存取,但管線化(pipelining)技術使單週期簡單指令反而整體更快。
  • 量化研究的空缺:當時指令集設計靠直覺與「越豐富越好」的信仰,幾乎沒有人系統地統計「編譯器實際產生什麼指令」——Patterson 與 Hennessy 決定用數據破案。
  • 大學的實驗平台:Patterson 的 Berkeley RISC 計畫(1980)與 Hennessy 的 Stanford MIPS 計畫(1981)各自以 VLSI 技術打造原型晶片,大學首次有能力自製微處理器。

線索與推理 -- 數學式、程式、理論#

80/20 法則:數據透露的真相#

Patterson 與 Hennessy 對編譯器產生的程式做指令使用頻率統計,發現驚人的分布(以 C 語言程式為例):

指令類型 佔比(約) 說明
Load/Store(資料搬移) ~45% 記憶體存取是大宗
分支/跳躍 ~20% 控制流頻繁
簡單 ALU(add, and, cmp…) ~30% 複雜運算很少用
複雜指令(字串處理、呼叫套件) ~5% 幾乎用不到

合計約 80% 的動態指令只需最簡單的硬體,而 VAX 卻為 5% 的複雜指令付出全部的設計複雜度。這是編譯器視角對硬體的「翻案」:複雜指令不是資產,而是負債。

Amdahl 定理與管線加速比#

管線化的加速比受最慢階段限制。若管線有 \(n\) 級、各級延遲為 \(t_i\) (含暫存器開銷 \(t_r\) ),時脈週期為:

\[ T_{clk} = \max_i (t_i) + t_r, \qquad \text{加速比} \le \frac{T_{nonpipe}}{T_{clk}} \approx \frac{\sum_i t_i}{\max_i t_i} \approx n \]

理想上 \(n\) 級管線可加速 \(n\) 倍,但指令執行時間不均與資料/控制相依會破壞管線。Amdahl 定理給出上限:若程式中比例 \(f\) 的部分可加速 \(s\) 倍,總加速比為

\[ S = \frac{1}{(1-f) + f/s} \]

CISC 的複雜指令讓各級延遲不均、管線經常停頓( \(s\) 變小);RISC 的單週期指令讓管線滿載( \(f \to 1, s \to n\) )——這就是 RISC 快的數學根源。

CISC vs RISC 對照#

CISC(VAX, x86) RISC(Berkeley RISC, MIPS)
指令數 200-300+ < 100
指令長度 變動長度 固定長度(利於解碼與管線)
記憶體存取 許多指令可直接碰記憶體 僅 load/store 碰記憶體
暫存器 少(x86: 8 個) 多(RISC-I: 78 個 + 暫存器視窗)
複雜操作 微碼轉譯 交給編譯器用簡單指令組合
優化責任 硬體 編譯器(_DELAY_BRANCH、指令排程)

簡單 RISC 組合語言:load/store 架構範例#

; 計算 c = a + b,RISC 風格(僅 load/store 碰記憶體)
    lw   r1, 0(r8)      ; r1 <- mem[a]     載入 a
    lw   r2, 4(r8)      ; r2 <- mem[b]     載入 b
    add  r3, r1, r2     ; r3 <- r1 + r2    單週期 ALU 運算
    sw   r3, 8(r8)      ; mem[c] <- r3     存回 c

; 同樣的運算,CISC(x86 風格)允許記憶體運算元:
;     add eax, [b]        一道指令混合載入與運算——微碼在內部拆成
;                         多個微指令,管線難以滿載

RISC 的鐵律:所有運算只在暫存器間進行,記憶體僅由 load/store 接觸。這讓每道指令的硬體路徑完全一致,管線可以滿載奔馳;複雜語意(如字串複製)由編譯器展開成簡單指令迴圈——優化責任從硬體移轉到軟體。

延遲分支與暫存器視窗:編譯器接手硬體#

RISC 的兩大創新都需要編譯器配合:

  1. 延遲分支(delayed branch):分支後的一個槽位(delay slot)永遠執行。編譯器負責把無關指令填入槽位,避免管線氣泡:
\[ \text{理想填滿率 } = \frac{\text{有效指令數}}{\text{槽位總數}} \to 1 \quad \text{(靠編譯器指令排程)} \]
  1. 暫存器視窗(register window):RISC-I 有 78 個實體暫存器,函式呼叫時只需切換視窗指標(重疊視窗傳遞參數),省去大量 push/pop:
# 視窗切換:呼叫 f 時,f 的 r0-r9 映射到呼叫者的 r16-r25(重疊區)
def call_prologue(CWP, W=16):
    caller_out = CWP * W + 16   # 呼叫者傳出參數區
    callee_in  = caller_out     # 被呼叫者輸入區 = 同一批實體暫存器
    return callee_in            # 只改一個指標,零記憶體存取

Patterson 的數據顯示:程序呼叫佔動態指令約 12-15%,視窗機制把這部分開銷大幅壓低——又是「用數據設計硬體」的推理。

結案 -- 後果與影響#

  • 商業化與普及:Stanford MIPS 孕育了 MIPS Technologies(1984),Berkeley RISC 技術授權給 Sun,成為 SPARC;Acorn 的 ARM(1985)採 RISC 路線,今日統治手機與嵌入式世界;RISC-V(2010,Berkeley)延續開源 RISC 理念。
  • 《Computer Architecture: A Quantitative Approach》:Hennessy 與 Patterson 合著的量化架構聖經(1990 初版),確立「用測量與成本效益分析設計架構」的方法學,成為全球體系教材。
  • 2017 年圖靈獎:Hennessy 與 Patterson 獲獎,表揚「對精簡指令集(RISC)概念與量化架構設計方法的開創性貢獻」——編譯器驅動的硬體設計得到最高肯定。
  • x86 的融合:Intel 在 x86 內部也偷偷 RISC 化——Pentium Pro(1995)起,外部 CISC 指令在內部解碼成類 RISC 微指令,實證了 Patterson 當年的判斷。
  • 硬體-軟體共同設計的典範:RISC 證明指令集、編譯器、管線是一個系統,必須一起設計——這成為電腦架構與編譯器課程的核心思想。

關鍵人物與文獻#

  • David Patterson(Berkeley):RISC-I(1981-82)計畫主持人,後為 Google 資深副總。
  • John Hennessy(Stanford):MIPS 計畫主持人,後為 Stanford 校長、Google 母公司 Alphabet 董事長。
  • 文獻:
  • D. Patterson, D. Sequin, "RISC-I: A Reduced Instruction Set VLSI Computer," ISCA, 1982.
  • J. Hennessy et al., "Hardware/Software Tradeoffs for Increased Performance," SIGARCH, 1982.
  • J. Hennessy, D. Patterson, Computer Architecture: A Quantitative Approach, Morgan Kaufmann, 1990.
  • G. Amdahl, "Validity of the Single Processor Approach to Achieving Large Scale Computing Capabilities," AFIPS, 1967.