RISC-V 目標使用者指南

簡介

RISC-V 目標為實作 RISC-V 規格受支援變體的處理器提供程式碼產生功能。它位於 llvm/lib/Target/RISCV 目錄中。

規格文件

RISC-V 規格已經過多次修訂。LLVM 旨在實作最新批准的標準 RISC-V 基礎 ISA 和 ISA 擴充功能版本,並具有務實的差異。最新的規格可以在以下網址找到:https://github.com/riscv/riscv-isa-manual/releases/

RISC-V International 官方規格頁面。也值得查看,但往往顯著落後於上面連結的規格。請務必查看 wiki 中尚未整合的擴充功能,並注意,此外,我們有時會支援尚未批准的擴充功能(這些將標記為實驗性 - 見下文)並支援各種供應商特定的擴充功能(見下文)。

目前已知的規格差異如下

  • 無條件允許來自 zifencei、zicsr、zicntr 和 zihpm 的指令,而無需閘控它們是否啟用擴充功能。規格的先前版本將這些指令包含在基礎 ISA 中,我們保留此行為以避免破壞現有程式碼。如果規格的未來版本將這些運算碼重新用於其他擴充功能,我們可能需要重新評估此選擇,因此建議使用者遷移建置系統,使其不依賴於此。

  • 允許在沒有閘控特定擴充功能的情況下命名 CSR。這適用於所有 CSR 名稱,而不僅僅是 zicsr、zicntr 和 zihpm 中的名稱。

  • 使用者指定的 ISA 命名字串(例如 -march)中不強制執行 z*s*x* 字首擴充功能名稱的順序。

目前我們積極決定不支援多個規格修訂版本。我們承認未來可能需要,但積極延遲圍繞處理此問題的決策制定,直到我們有一個實際硬體已出貨並且規格在之後進行不相容更改的具體範例。

基礎 ISA

規格定義了五個基礎指令集:RV32I、RV32E、RV64I、RV64E 和 RV128I。目前,LLVM 完全支援 RV32I 和 RV64I。RV32E 和 RV64E 僅由基於組譯器的工具支援。RV128I 不受支援。

指定目標三元組

表 118 RISC-V 架構

架構

描述

riscv32

XLEN=32 的 RISC-V (即 RV32I 或 RV32E)

riscv64

XLEN=64 的 RISC-V (即 RV64I 或 RV64E)

若要選擇 E 變體 ISA (例如 RV32E 而非 RV32I),請使用基礎架構字串 (例如 riscv32) 和擴充功能 e

設定檔

可以使用 -march 而非標準 ISA 命名字串傳遞支援的設定檔名稱。目前支援的設定檔

  • rvi20u32

  • rvi20u64

  • rva20u64

  • rva20s64

  • rva22u64

  • rva22s64

  • rva23u64

  • rva23s64

  • rvb23u64

  • rvb23s64

請注意,您也可以附加要啟用的其他擴充功能名稱,例如 rva20u64_zicond 將啟用 zicond 擴充功能以及 rva20u64 設定檔中的擴充功能。

除非指定 -menable-experimental-extensions(或其他工具的等效項),否則無法使用尚未批准的設定檔。這適用於以下設定檔

  • rvm23u32

擴充功能

下表提供了已批准且因此具有最終規格的擴充功能狀態摘要。如果相關,則會提供有關支援的詳細說明。

表 119 依狀態劃分的已批准擴充功能

擴充功能

狀態

A

已支援

B

已支援

C

已支援

D

已支援

F

已支援

E

已支援 (請參閱註解)

H

組譯器支援

M

已支援

Sha

已支援

Shcounterenw

組譯器支援 (請參閱註解)

Shgatpa

組譯器支援 (請參閱註解)

Shtvala

組譯器支援 (請參閱註解)

Shvsatpa

組譯器支援 (請參閱註解)

Shvstvala

組譯器支援 (請參閱註解)

Shvstvecd

組譯器支援 (請參閱註解)

Smaia

已支援

Smcdeleg

已支援

Smcsrind

已支援

Smdbltrp

已支援

Smepmp

已支援

Smmpm

已支援

Smnpm

已支援

Smrnmi

組譯器支援

Smstateen

組譯器支援

Ssaia

已支援

Ssccfg

已支援

Ssccptr

組譯器支援 (請參閱註解)

Sscofpmf

組譯器支援

Sscounterenw

組譯器支援 (請參閱註解)

Sscsrind

已支援

Ssdbltrp

已支援

Ssnpm

已支援

Sspm

已支援

Ssqosid

組譯器支援

Ssstateen

組譯器支援 (請參閱註解)

Ssstrict

組譯器支援 (請參閱註解)

Sstc

組譯器支援

Sstvala

組譯器支援 (請參閱註解)

Sstvecd

組譯器支援 (請參閱註解)

Ssu64xl

組譯器支援 (請參閱註解)

Supm

已支援

Svade

組譯器支援 (請參閱註解)

Svadu

組譯器支援

Svbare

組譯器支援 (請參閱註解)

Svinval

組譯器支援

Svnapot

組譯器支援

Svpbmt

已支援

Svvptc

已支援

V

已支援

Za128rs

已支援 (請參閱註解)

Za64rs

已支援 (請參閱註解)

Zaamo

組譯器支援

Zabha

已支援

Zacas

已支援 (請參閱註解)

Zalrsc

組譯器支援

Zama16b

已支援 (請參閱註解)

Zawrs

組譯器支援

Zba

已支援

Zbb

已支援

Zbc

已支援

Zbkb

已支援 (請參閱註解)

Zbkc

已支援

Zbkx

已支援 (請參閱註解)

Zbs

已支援

Zca

已支援

Zcb

已支援

Zcd

已支援

Zcf

已支援

Zcmop

已支援

Zcmp

已支援

Zcmt

組譯器支援

Zdinx

已支援

Zfa

已支援

Zfbfmin

已支援

Zfh

已支援

Zfhmin

已支援

Zfinx

已支援

Zhinx

已支援

Zhinxmin

已支援

Zic64b

已支援 (請參閱註解)

Zicbom

組譯器支援

Zicbop

已支援

Zicboz

組譯器支援

Ziccamoa

已支援 (請參閱註解)

Ziccif

已支援 (請參閱註解)

Zicclsm

已支援 (請參閱註解)

Ziccrse

已支援 (請參閱註解)

Zicntr

(請參閱註解)

Zicond

已支援

Zicsr

(請參閱註解)

Zifencei

(請參閱註解)

Zihintntl

已支援

Zihintpause

組譯器支援

Zihpm

(請參閱註解)

Zimop

已支援

Zkn

已支援

Zknd

已支援 (請參閱註解)

Zkne

已支援 (請參閱註解)

Zknh

已支援 (請參閱註解)

Zksed

已支援 (請參閱註解)

Zksh

已支援 (請參閱註解)

Zk

已支援

Zkr

已支援

Zks

已支援

Zkt

已支援

Zmmul

已支援

Ztso

已支援

Zvbb

已支援

Zvbc

已支援 (請參閱註解)

Zve32x

(部分) 支援

Zve32f

(部分) 支援

Zve64x

已支援

Zve64f

已支援

Zve64d

已支援

Zvfbfmin

已支援

Zvfbfwma

已支援

Zvfh

已支援

Zvfhmin

已支援

Zvkb

已支援

Zvkg

已支援 (請參閱註解)

Zvkn

已支援 (請參閱註解)

Zvknc

已支援 (請參閱註解)

Zvkned

已支援 (請參閱註解)

Zvkng

已支援 (請參閱註解)

Zvknha

已支援 (請參閱註解)

Zvknhb

已支援 (請參閱註解)

Zvks

已支援 (請參閱註解)

Zvksc

已支援 (請參閱註解)

Zvksed

已支援 (請參閱註解)

Zvksg

已支援 (請參閱註解)

Zvksh

已支援 (請參閱註解)

Zvkt

已支援

Zvl32b

(部分) 支援

Zvl64b

已支援

Zvl128b

已支援

Zvl256b

已支援

Zvl512b

已支援

Zvl1024b

已支援

Zvl2048b

已支援

Zvl4096b

已支援

Zvl8192b

已支援

Zvl16384b

已支援

Zvl32768b

已支援

Zvl65536b

已支援

組譯器支援

LLVM 支援組譯器中的相關指令。支援所有組譯器相關工具(例如組譯器、反組譯器、llvm-objdump 等)。編譯器和連結器將接受擴充功能名稱,並且連結的二進位檔案將包含適當的 ELF 旗標和屬性,以反映已命名的擴充功能的使用。

已支援

編譯器完全支援。這包括組譯器支援中的所有內容,以及 - 如果相關 - 指令的 C 語言內建函數以及編譯器的模式比對,以識別可以降低為相關指令的慣用模式。

E

實驗性支援 RV32E/RV64E 和 ilp32e/lp64e ABI。為了與 GCC 中 ilp32e 的實作相容,我們不使用對齊的暫存器來傳遞可變參數。此外,我們將長度為 2*XLEN 的類型的堆疊對齊設定為 4 個位元組。

ZbkbZbkx

對這些指令的模式比對支援不完整。

ZkndZkneZknhZksedZksh

不存在模式比對。因此,這些指令只能從組譯器或透過內建函數呼叫使用。

ZvbcZvkgZvknZvkncZvknedZvkngZvknhaZvknhbZvksZvksZvksZvkscZvksedZvksgZvksh

不存在模式比對。因此,這些指令只能從組譯器或透過內建函數呼叫使用。

Zve32xZve32fZvl32b

LLVM 目前在編譯期間假設最小 VLEN(向量暫存器寬度)為 64 位元,因此 Zve32xZve32f 僅在 VLEN>=64 時受到支援。組譯器支援沒有此限制。

ZicntrZicsrZifenceiZihpm

在基礎 I 規格的 2.0 版和 2.1 版之間,進行了向後不相容的更改,以從基礎 ISA 中移除選定的指令和 CSR。這些指令被分組為一組新的擴充功能,但不再是基礎 ISA 所必需的。規格文件中的「Document Version 20190608-Base-Ratified 序言」部分描述了此更改(未提及 zicntrzihpm 位元)。LLVM 目前實作基礎規格的 2.1 版。為了保持相容性,接受來自這些擴充功能的指令,而無需在 -march 字串中。LLVM 也允許在 -march 字串中明確指定擴充功能。

Za128rsZa64rsZama16bZic64bZiccamoaZiccifZicclsmZiccrseShcounterenvwShgatpaShtvalaShvsatpaShvstvalaShvstvecdSsccptrSscounterenwSsstateenSsstrictSstvalaSstvecdSsu64xlSvadeSvbare

這些擴充功能定義為 RISC-V 設定檔規格的一部分。它們本身不引入任何新功能,而是描述現有的硬體功能。

Zacas

由於 ABI 相容性,編譯器不會在 RV32 上產生 amocas.d 或在 RV64 上產生 amocas.q。這些只能在組譯器中使用。

原子操作 ABI

在撰寫本文時,有三個原子操作對應 (ABI) 為 RISC-V 定義。截至 LLVM 19,LLVM 預設為「A6S」,它與原始「A6」和未來的「A7」ABI 相容。請參閱 psABI 原子操作文件,以取得有關這些對應的更多資訊。

請注意,雖然使用了「A6S」對應,但由於在處理包含此屬性的檔案時,舊版本 binutils 中存在導致崩潰的錯誤,因此目前預設情況下不會發出記錄對應的 ELF 屬性。

實驗性擴充功能

LLVM 支援(在不同程度上)許多實驗性擴充功能。所有實驗性擴充功能都以 experimental- 作為字首。明確承諾工具鏈版本之間沒有相容性,並且強烈建議一般使用者在實驗性擴充功能達到批准狀態之前不要使用它們。

實驗性支援的主要目標是透過提供實作的存在證明,並簡化驗證針對大型程式碼庫提出的擴充功能價值的努力,來協助批准過程。實驗性擴充功能預計會轉換為批准狀態,或最終被移除。目前完全根據具體情況做出是否接受實驗性擴充功能的決定;如果您想提出一個,強烈建議參加每週兩次的 RISC-V 同步電話會議。

experimental-zalasr

LLVM 實作 0.0.5 草稿規格

experimental-zicfilpexperimental-zicfiss

LLVM 實作 1.0 發行規格

experimental-zvbc32eexperimental-zvkgs

LLVM 實作 0.7 發行規格

experimental-sdextexperimental-sdtrig

LLVM 實作 1.0-rc4 規格

experimental-smctrexperimental-ssctr

LLVM 實作 1.0-rc3 規格

experimental-svukte

LLVM 實作 0.3 草稿規格

若要從 clang 使用實驗性擴充功能,您必須將 -menable-experimental-extensions 新增至命令列,並指定您使用的實驗性擴充功能的確切版本。若要將實驗性擴充功能與 LLVM 的內部開發人員工具(例如 llcllvm-objdumpllvm-mc)搭配使用,您必須在擴充功能名稱前面加上 experimental-。請注意,您不需要使用內部工具指定版本,並且不應在使用 clang 時包含 experimental- 字首。

供應商擴充功能

供應商擴充功能是不由 RISC-V International 標準化的擴充功能,而是由硬體供應商定義。供應商擴充功能術語大致與 Volume I: RISC-V Unprivileged ISA 規格第 1.3 節中 非標準 擴充功能的定義平行。特別是,我們期望最終接受 自訂 擴充功能和 不符合標準 的擴充功能。

將根據具體情況考慮是否包含供應商擴充功能。所有提案都應提交給每週兩次的 RISC-V 同步電話會議進行討論。如需可能考慮的因素的一般概念,請參閱 Clang 文件

我們打算遵循 riscv-non-isa/riscv-toolchain-conventions 中描述的命名慣例。對此命名的例外情況需要有強烈的動機。

目前支援的供應商擴充功能包括

XTHeadBa

LLVM 實作 T-HEAD of Alibaba 在其中指定的 THeadBa(位址產生)供應商定義指令。指令以 th. 為字首,如規格中所述。

XTHeadBb

LLVM 實作 T-HEAD of Alibaba 在其中指定的 THeadBb(基本位元操作)供應商定義指令。指令以 th. 為字首,如規格中所述。

XTHeadBs

LLVM 實作 T-HEAD of Alibaba 在其中指定的 THeadBs(單位元操作)供應商定義指令。指令以 th. 為字首,如規格中所述。

XTHeadCondMov

LLVM 實作 T-HEAD of Alibaba 在其中指定的 THeadCondMov(條件移動)供應商定義指令。指令以 th. 為字首,如規格中所述。

XTHeadCmo

LLVM 實作 T-HEAD of Alibaba 在其中指定的 THeadCmo(快取管理操作)供應商定義指令。指令以 th. 為字首,如規格中所述。

XTHeadFMemIdx

LLVM 實作 T-HEAD of Alibaba 在其中指定的 THeadFMemIdx(浮點索引記憶體操作)供應商定義指令。指令以 th. 為字首,如規格中所述。

XTheadMac

LLVM 實作 T-HEAD of Alibaba 在其中指定的 XTheadMac(乘法累加指令)供應商定義指令。指令以 th. 為字首,如規格中所述。

XTHeadMemIdx

LLVM 實作 T-HEAD of Alibaba 在其中指定的 THeadMemIdx(索引記憶體操作)供應商定義指令。指令以 th. 為字首,如規格中所述。

XTHeadMemPair

LLVM 實作 T-HEAD of Alibaba 在其中指定的 THeadMemPair(雙 GPR 記憶體操作)供應商定義指令。指令以 th. 為字首,如規格中所述。

XTHeadSync

LLVM 實作 T-HEAD of Alibaba 在其中指定的 THeadSync(多核心同步指令)供應商定義指令。指令以 th. 為字首,如規格中所述。

XTHeadVdot

LLVM 實作 T-HEAD of Alibaba THeadV 系列自訂指令規格的 1.0.0 版。所有指令都以 th. 為字首,如規格和上面連結的 riscv-toolchain-convention 文件中所述。

XVentanaCondOps

LLVM 實作 Ventana Micro Systems VTx 系列自訂指令規格的 1.0.0 版。所有指令都以 vt. 為字首,如規格和上面連結的 riscv-toolchain-convention 文件中所述。這些指令目前僅適用於 riscv64。

XSfvcp

LLVM 實作 SiFive 向量協處理器介面 (VCIX) 軟體規格的 1.1.0 版。所有指令都以 sf.vc. 為字首,如規格和上面連結的 riscv-toolchain-convention 文件中所述。

XSfvqmaccdodXSfvqmaccqoq

LLVM 實作 SiFive Int8 矩陣乘法擴充功能規格的 1.1.0 版。所有指令都以 sf. 為字首,如上面連結的規格中所述。

Xsfvfnrclipxfqf

LLVM 實作 SiFive FP32 到 int8 範圍剪輯指令擴充功能規格的 1.0.0 版。所有指令都以 sf. 為字首,如上面連結的規格中所述。

Xsfvfwmaccqqq

LLVM 實作 SiFive 矩陣乘法累加指令擴充功能規格的 1.0.0 版。所有指令都以 sf. 為字首,如上面連結的規格中所述。

XCVbitmanip

LLVM 實作 OpenHW Group CORE-V 位元操作自訂指令規格的 1.0.0 版。所有指令都以 cv. 為字首,如規格中所述。

XCVelw

LLVM 實作 OpenHW Group CORE-V 事件載入自訂指令規格的 1.0.0 版。所有指令都以 cv. 為字首,如規格中所述。這些指令目前僅適用於 riscv32。

XCVmac

LLVM 實作 OpenHW Group CORE-V 乘法累加 (MAC) 自訂指令規格的 1.0.0 版。所有指令都以 cv.mac 為字首,如規格中所述。這些指令目前僅適用於 riscv32。

XCVmem

LLVM 實作 OpenHW Group CORE-V 後增量載入和儲存自訂指令規格的 1.0.0 版。所有指令都以 cv. 為字首,如規格中所述。這些指令目前僅適用於 riscv32。

XCValu

LLVM 實作 Core-V ALU 自訂指令規格的 1.0.0 版。所有指令都以 cv. 為字首,如規格中所述。這些指令目前僅適用於 riscv32。

XCVsimd

LLVM 實作 OpenHW Group CORE-V SIMD 自訂指令規格的 1.0.0 版。所有指令都以 cv. 為字首,如規格中所述。

XCVbi

LLVM 實作 OpenHW Group CORE-V 立即分支自訂指令規格的 1.0.0 版。所有指令都以 cv. 為字首,如規格中所述。這些指令目前僅適用於 riscv32。

XSiFivecdiscarddlone

LLVM 實作 SiFive sf.cdiscard.d.l1 指令,在其中指定

XSiFivecflushdlone

LLVM 實作 SiFive sf.cflush.d.l1 指令,在其中指定

XSfcease

LLVM 實作 SiFive sf.cease 指令,在其中指定

Xwchc

LLVM 實作 某些青稞核心中存在的自訂壓縮運算碼,由 WCH / 南京沁恆微電子提供。供應商將這些運算碼稱為「XW」。

experimental-Xqccmp

LLVM 實作 Qualcomm 16 位元推入/彈出指令和雙移動擴充功能規格的 0.1 版。所有指令都以 qc. 為字首,如規格中所述。

experimental-Xqcia

LLVM 實作 Qualcomm uC 算術擴充功能規格的 0.4 版。所有指令都以 qc. 為字首,如規格中所述。這些指令僅適用於 riscv32。

experimental-Xqciac

LLVM 實作 Qualcomm uC 載入-儲存位址計算擴充功能規格的 0.3 版。所有指令都以 qc. 為字首,如規格中所述。這些指令僅適用於 riscv32。

experimental-Xqcibm

LLVM 實作 Qualcomm uC 位元操作擴充功能規格的 0.4 版。所有指令都以 qc. 為字首,如規格中所述。這些指令僅適用於 riscv32。

experimental-Xqcicli

LLVM 實作 Qualcomm uC 條件載入立即值擴充功能規格的 0.2 版。所有指令都以 qc. 為字首,如規格中所述。這些指令僅適用於 riscv32。

experimental-Xqcicm

LLVM 實作 Qualcomm uC 條件移動擴充功能規格的 0.2 版。所有指令都以 qc. 為字首,如規格中所述。這些指令僅適用於 riscv32。

experimental-Xqcics

LLVM 實作 Qualcomm uC 條件選擇擴充功能規格的 0.2 版。所有指令都以 qc. 為字首,如規格中所述。這些指令僅適用於 riscv32。

experimental-Xqcicsr

LLVM 實作 Qualcomm uC CSR 擴充功能規格的 0.2 版。所有指令都以 qc. 為字首,如規格中所述。這些指令僅適用於 riscv32。

experimental-Xqciint

LLVM 實作 Qualcomm uC 中斷擴充功能規格的 0.2 版。所有指令都以 qc. 為字首,如規格中所述。這些指令僅適用於 riscv32。

experimental-Xqcilia

LLVM 實作 Qualcomm uC 大型立即值算術擴充功能規格的 0.2 版。所有指令都以 qc. 為字首,如規格中所述。這些指令僅適用於 riscv32。

experimental-Xqcilo

LLVM 實作了 Qualcomm 公司的 Qualcomm uC Large Offset Load Store 擴充規格 0.2 版。所有指令都以前綴詞 qc. 作為開頭,如規格所述。這些指令僅適用於 riscv32 架構。

experimental-Xqcilsm

LLVM 實作了 Qualcomm 公司的 Qualcomm uC Load Store Multiple 擴充規格 0.2 版。所有指令都以前綴詞 qc. 作為開頭,如規格所述。這些指令僅適用於 riscv32 架構。

experimental-Xqcisls

LLVM 實作了 Qualcomm 公司的 Qualcomm uC Scaled Load Store 擴充規格 0.2 版。所有指令都以前綴詞 qc. 作為開頭,如規格所述。這些指令僅適用於 riscv32 架構。

Xmipscmove

LLVM 實作了 MIPS 公司的 p8700 處理器 <https://mips.com/products/hardware/p8700/> 的條件移動指令。

Xmipslsp

LLVM 實作了 MIPS 公司的 p8700 處理器 <https://mips.com/products/hardware/p8700/> 的載入/儲存配對指令。

experimental-XRivosVisni

LLVM 實作了 Rivos Vector Integer Small New Instructions 擴充規格 0.1 版

experimental-XRivosVizip

LLVM 實作了 Rivos Vector Register Zips 擴充規格 0.1 版

實驗性 C 內建函數

在某些情況下,擴充功能可能不是實驗性的,但該擴充功能的 C 內建函數仍然是實驗性的。若要從 clang 使用此類擴充功能的 C 內建函數,您必須在命令列中加入 -menable-experimental-extensions。這目前適用於以下擴充功能:

沒有擴充功能具有實驗性內建函數。

長型(>32 位元)指令支援

RISC-V 是一種可變長度 ISA,但標準目前僅定義 16 位元和 32 位元指令。規格描述了更長的指令編碼,但這些尚未獲得批准。

LLVM 反組譯器 llvm-objdump 確實使用了規格中描述的更長指令編碼來猜測指令長度(最多 176 位元),並將相應地對編碼位元組的反組譯檢視進行分組。

LLVM 針對 RISC-V 的整合組譯器支援兩種不同的 .insn 指令,用於組譯 LLVM 尚不支援的指令

  • .insn type, args* 接受已知的指令類型和欄位列表。如果您的指令符合現有的指令類型,強烈建議您使用此變體的指令。

  • .insn [ length , ] encoding 接受(可選的)明確長度(以位元組為單位)和指令的原始編碼。當給定明確長度時,此變體可以編碼長達 64 位元的指令。指令的編碼部分必須給出指令的所有位元,沒有任何位元會為使用者填入。當在沒有可選長度的情況下使用時,此變體的指令將使用原始編碼的 LSB 來判斷指令是 16 位元還是 32 位元。LLVM 不會推斷指令可能超過 32 位元 - 在這種情況下,使用者必須明確給出長度。

強烈建議使用 .insn 指令來組譯不受支援的指令,而不是 .word.hword,因為它會產生正確的映射符號,將該字組標記為指令,而不是資料。

全域指標 (GP) 放鬆和小型資料限制

一些 RISC-V psABI 變體保留了 gpx3)作為「全域指標」使用,以提高產生資料位址的效率。

若要使用此功能,您需要執行以下所有操作:

  • 使用 medlow(又名 small)程式碼模型;

  • 不要將 gp 暫存器用於任何其他用途(某些平台將其用於陰影堆疊,另一些平台則將其用作臨時暫存器 – 如 Tag_RISCV_x3_reg_usage 建置屬性所指示);

  • 使用 Clang 的 -mrelax 選項編譯您的物件,以在可重定位物件上啟用放鬆註解(這是預設值,但 -mno-relax 會停用這些放鬆註解);

  • 為與位置相關的靜態可執行檔編譯(不是共享程式庫,且使用 -fno-PIC / -fno-pic / -fno-pie);以及

  • 使用 LLD 的 --relax-gp 選項。

LLD 將放鬆(重寫)任何程式碼序列,這些序列會將位址實體化在 __global_pointer$ 的 2048 位元組範圍內(如果使用了 __global_pointer$ 且它尚不存在,則將會定義 __global_pointer$),而是使用 gp 和正確的(帶符號)12 位元立即值來產生位址。與實體化完整的 32 位元位址值相比,這通常至少可以節省一條指令。

一個進程中只能有一個 gp 值(因為在呼叫共享程式庫中的函數時,gp 不會變更),因此該符號僅在可執行檔中定義,並且此放鬆僅針對可執行檔完成,而不針對共享程式庫。連結器期望可執行檔啟動程式碼在執行任何使用者程式碼之前,將 __global_pointer$ 的值(來自可執行檔)放入 gp 中。

可以說,這種定址模式最有效率的用途是用於較小的全域變數,因為較大的全域變數在被存取時可能需要更多的載入或儲存,因此實體化高位元的成本可以分攤。

因此,編譯器可以將較小的全域變數放入名稱以 .sdata.sbss 開頭的區段中(與名稱以 .data.bss 開頭的區段相符)。LLD 知道要將 global_pointer$ 符號定義在靠近這些區段的位置,並將這些區段佈局在與 .data 區段相鄰的位置。

Clang 的 -msmall-data-limit= 選項控制將全域變數視為小的閾值大小(以位元組為單位)。-msmall-data-limit=0 會停用以 .sdata.sbss 開頭的區段的使用。-msmall-data-limit= 選項不會移動具有明確資料區段的全域變數,並且如果您使用 -fdata-sections,則會將全域變數保留在單獨的區段中。

小型資料限制閾值也用於將小型常數分隔到名稱以 .srodata 開頭的區段中。LLD 不會將這些區段與 .sdata.sbss 區段放在一起,因為 .srodata 區段是唯讀的,而其他兩個是可寫入的。相反,.srodata 區段會放置在與 .rodata 相鄰的位置。

資料表明,這些選項可以在各種基準測試中產生顯著的改進。