iT邦幫忙

2024 iThome 鐵人賽

DAY 19
0
Software Development

離塵指引.卷之一.試結丹:程式語言自舉系列 第 19

零.一版精五真言生成(二)堆疊機

  • 分享至 

  • xImage
  •  

在語法樹中,算式是一棵二元樹,要從樹形轉換為循序、線性的真言並不是一目瞭然的事情。若先將算術二元樹轉換為後序表達式,計算的順序會比較明瞭一些。道友們在煉氣(學習編程基礎、資料結構)時,想必對後序表達式不陌生,後序拜訪二元樹就能得到。

後序拜訪(樹) {
    後序拜訪(樹.左子樹)
    後序拜訪(樹.右子樹)
    打印(樹.值)
}

舉個例子:

       +
      / \
     *   5
    / \
   3   -
      / \
     4   2

後序拜訪後,會打印出:

3 4 2 - * 5 +

這時計算的順序就很清楚了,由左而右是 - * + ,得到順序後,把每個數字放進一個暫存器,可以生成真言

li t0, 3
li t1, 4
li t2, 2
sub t1, t1, t2
mul t0, t1, t1
li t1, 5
add t0, t1, t1

然而算術樹可能會很高很畸形,導致暫存器的數量不夠用,這時就得把數字放進記憶體暫時儲存了。

道友們煉氣時應該都有印象,藉助資料結構「棧(堆疊)」可以很輕鬆的計算後序表達式,若需要複習,可以看看下方的逐步操作回憶一下:

[3]               # 遇數字 3,壓入棧
[3, 4]            # 遇數字 4,壓入棧
[3, 4, 2]         # 遇數字 2,壓入棧
[3, 2]            # 遇運算 -,計算 4 - 2 = 2,將結果壓入棧
[6]               # 遇運算 *,計算 3 * 2 = 6,將結果壓入棧
[6, 5]            # 遇數字 5,壓入棧
[11]              # 遇運算 +,計算 6 + 5 = 11,將結果壓入棧

把所有運算都存到棧裡是很慢的,畢竟一次記憶體存取可能比是存取暫存器要慢上幾十乃至上百倍,即使快取命中也要好幾個 cycle 才拿得回來,但堆疊機實現起來容易。就先暫且把暫存器分配問題丟到一邊,來看看在精五真言中如何模擬堆疊機。

精五真言棧操作

精五(RISC-V)架構的棧一般來說是從高位址往低位址成長的。棧頂位址由暫存器 sp 記錄,addi sp, sp, -8 可擴大棧,相反地,addi sp, sp, 8會縮小棧。

以下精五真言將數字 3 壓入棧

addi sp, sp, -8   # 擴大棧 64 位元(8 位元組 = 64 位元)
li t0, 3          # t0 = 3
sd t0, 0(sp)      # sd 將 64 位元 t0 存到棧頂

最後來看上述算術樹轉成堆疊機操作的完整精五真言:

# 3 入棧
	addi sp, sp, -8
	li t0, 3
	sd t0, 0(sp)
# 4 入棧
	addi sp, sp, -8
	li t0, 4
	sd t0, 0(sp)
# 2 入棧
	addi sp, sp, -8
	li t0, 2
	sd t0, 0(sp)
# 減
	ld t1, 0(sp)     # t1 = 棧頂
	addi sp, sp, 8   # 棧頂縮小 64 位元
	ld t0, 0(sp)     # t0 = 棧頂
	sub t0, t0, t1   # t0 = t0 - t1
	sd t0, 0(sp)     # sd 將 64 位元 t0 存到棧頂
# 乘
	ld t1, 0(sp)
	addi sp, sp, 8
	ld t0, 0(sp)
	mul t0, t0, t1
	sd t0, 0(sp)
# 5 入棧
	addi sp, sp, -8
	li t0, 5
	sd t0, 0(sp)
# 加
	ld t1, 0(sp)
	addi sp, sp, 8
	ld t0, 0(sp)
	add t0, t0, t1
	sd t0, 0(sp)

上一篇
零.一版精五真言生成(一)變數儲存
下一篇
零.一版精五真言生成(三)實作
系列文
離塵指引.卷之一.試結丹:程式語言自舉31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言