国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

簡單介紹一個(gè)編譯器的結(jié)構(gòu)(下)

這篇具有很好參考價(jià)值的文章主要介紹了簡單介紹一個(gè)編譯器的結(jié)構(gòu)(下)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。


《編譯器結(jié)構(gòu)介紹(下)》主要是圍繞編譯器后端知識(shí)和技術(shù)展開的一個(gè)簡單介紹,編譯器前端技術(shù)的介紹在文章《 編譯器結(jié)構(gòu)介紹(上)》中,如果對(duì)編譯器整個(gè)技術(shù)棧不了解的話,先閱讀上,再閱讀下這篇文章,會(huì)更容易理解。

七、機(jī)器無關(guān)代碼優(yōu)化

經(jīng)過中間代碼生成過程產(chǎn)生的中間代碼是正確的,但未必就是更“好”的,所以我們要對(duì)中間代碼做一些優(yōu)化,使其可以更“好”。這個(gè)“好”是個(gè)泛指,比如我們希望它生成的匯編代碼量可以更小(GCC加-Os)、或者生成的匯編代碼執(zhí)行時(shí)的內(nèi)存使用量更小、或者生成的匯編代碼執(zhí)行速度可以更快(GCC加-O[1/2/3])。一般而言,最期望的“好”還是執(zhí)行速度可以更快,我們接下來的介紹也是以這部分內(nèi)容展開。

7.1 常見優(yōu)化的案例

1)常數(shù)折疊

常量折疊(constant folding)指的是把常量表達(dá)式在編譯時(shí)進(jìn)行運(yùn)算。譬如下面的 C 語言代碼。

int max_size = 2 * 1024 * 1024; /* 2MB */

這里的 2* 1024 * 1024 是只含常量的表達(dá)式,因此可以在編譯時(shí)進(jìn)行計(jì)算。如果在編譯時(shí)進(jìn)行了運(yùn)算,那么程序運(yùn)行時(shí)就可以省略這次運(yùn)算,因此可以獲得更快的執(zhí)行速度。這就是常量折疊。

2)代數(shù)簡化

代數(shù)簡化(algebraic simplification)指的是利用表達(dá)式的數(shù)學(xué)性質(zhì),對(duì)表達(dá)式進(jìn)行簡化。比如 x*1 這個(gè)表達(dá)式和 x 是一樣的,可以直接替換成 x。同樣地,x+0x–0 等也可以替換成 x。而 x*0 恒等于 0,因此也可以直接用 0 來代替。

3)降低運(yùn)算強(qiáng)度

降低運(yùn)算強(qiáng)度(strength reduction)指的是用更高速的指令進(jìn)行運(yùn)算。
比如說 x*2 這個(gè)表達(dá)式,可以轉(zhuǎn)換成加法運(yùn)算 x+x。一般來說 CPU 計(jì)算加法比計(jì)算乘法效率更高,因此雖然兩個(gè)式子效果相同,但 x+x 的運(yùn)算速度更快。

把乘法轉(zhuǎn)換成位移運(yùn)算也是降低運(yùn)算強(qiáng)度的一個(gè)例子。一般而言,求整數(shù)與 2 的階乘的乘積可以用位移運(yùn)算來優(yōu)化。因?yàn)?x 乘以 4 和 x 左移 2 比特的效果是一樣的,而后者速度更快。

4)削除共同子表達(dá)式

削除共同子表達(dá)式(common-subexpression elimination)指的是有重復(fù)運(yùn)算的情況下,把多次運(yùn)算壓縮為一次運(yùn)算的方法。譬如下面的 C 語言代碼。

int x = a * b + c + 1;
int y = 2 + a * b + c;

對(duì) x 和 y 的計(jì)算中,a*b+c 這個(gè)部分的運(yùn)算是一致的。這種情況下,因?yàn)?a*b+c 的值一樣,所以不必要計(jì)算 2 次。只要把上述代碼進(jìn)行如下轉(zhuǎn)換,這部分就可以只計(jì)算 1 次。

int tmp = a * b + c;
int x = tmp + 1;
int y = 2 + tmp;

5)消除無效語句

消除無效語句(dead code elimination)指的是刪除從程序邏輯上執(zhí)行不到的指令。譬如下面的 C 語言代碼毫無意義,完全可以刪除掉。

if (0) {
 fprintf(stderr, "program started\n");
}

6)函數(shù)內(nèi)聯(lián)

函數(shù)內(nèi)聯(lián)(function inlining)指的是把(小的)函數(shù)體直接嵌入到函數(shù)調(diào)用處,使得函數(shù)調(diào)用的作用域歸零的方法。

int region_size(int n_block) {
 return n_block * 1024;
}

假設(shè)在別的地方通過 region_size(2) 這個(gè)語句進(jìn)行了函數(shù)調(diào)用,那么將其替換成2*1024 結(jié)果也是一樣的。這就是函數(shù)內(nèi)聯(lián)。不過,因?yàn)?region_size 是全局作用域的函數(shù),編譯時(shí)的優(yōu)化僅限于同一個(gè)文件中定義的函數(shù)調(diào)用。如果想對(duì)程序中所有的 region_size 函數(shù)調(diào)用都進(jìn)行函數(shù)內(nèi)聯(lián),那么鏈接時(shí)也需要進(jìn)行代碼優(yōu)化。

另外,2*1024 又是只含常量的表達(dá)式,因此可以進(jìn)一步用常量折疊的方法替換成 2048。這樣組合運(yùn)用多種優(yōu)化方法可以獲得更大的優(yōu)化效果。以什么樣的順序組合各種優(yōu)化方法,從而獲取更好的優(yōu)化效果,也是非常關(guān)鍵的一點(diǎn)。

7.2 優(yōu)化的作用階段

一般的編譯器可以在以下幾個(gè)時(shí)間節(jié)點(diǎn)上進(jìn)行優(yōu)化。

  1. 語義分析后(針對(duì)抽象語法樹的優(yōu)化)
  2. 生成中間代碼后(針對(duì)中間代碼的優(yōu)化)
  3. 生成匯編代碼后(針對(duì)匯編代碼的優(yōu)化)
  4. 鏈接后(針對(duì)程序整體的優(yōu)化)

通常來說,越早進(jìn)行,越能針對(duì)編程語言的結(jié)構(gòu)、語義等進(jìn)行優(yōu)化。譬如在抽象語法樹階段,我們能簡單地識(shí)別循環(huán),因此在這個(gè)階段能針對(duì)循環(huán)體進(jìn)行優(yōu)化。

在中間代碼階段可以進(jìn)行語言無關(guān)的優(yōu)化。該階段可以使用從局部優(yōu)化到全局優(yōu)化的多種優(yōu)化方法。此外,有時(shí)候還會(huì)根據(jù)情況把一段中間代碼拆散,令其更容易進(jìn)行優(yōu)化。

一旦編譯成了匯編代碼,就很難對(duì)代碼進(jìn)行大范圍的優(yōu)化了。這個(gè)階段的優(yōu)化基本上集中在窺視孔優(yōu)化這種方式上。

最后,鏈接后也可進(jìn)行優(yōu)化。鏈接后構(gòu)成程序主體的各個(gè)處理流程(函數(shù))已經(jīng)固定,可以對(duì)程序整體進(jìn)行大范圍的解析優(yōu)化。

總結(jié)】與優(yōu)化相關(guān)的內(nèi)容很多,如果對(duì)這一塊內(nèi)容感興趣,可以看我總結(jié)的文章,《編譯器設(shè)計(jì)(九~十四)》全是優(yōu)化相關(guān)的理論和技術(shù)。

八、匯編代碼生成

當(dāng)機(jī)器無關(guān)代碼優(yōu)化后,就會(huì)生成更“好”的、我們最終想要的中間代碼。匯編代碼生成就是將中間代碼,編譯成語義等價(jià)的匯編代碼。這部分內(nèi)容相比于優(yōu)化,也不抽象,在實(shí)現(xiàn)起來要簡單很多。

現(xiàn)在有以下C代碼,文件名是main.c,定義了2個(gè)全局變量global_init_varglobal_uninit_var,兩個(gè)函數(shù)func1main,靜態(tài)變量static_varstatic_var2,以及調(diào)用printf函數(shù)時(shí)使用到的字符串"%d\n"

int global_init_var = 84;
int global_uninit_var;
 
void func1(int i){
	printf("%d\n", i);
}
 
int main(void){
	static int static_var = 85;
	static int static_var2;
 
	int a = 1;
	int b;
 
	func1(static_var + static_var2 + a + b);
 
	return a;
}

現(xiàn)在用LLVM IR來表示上面C代碼,文章來源地址http://www.zghlxwxcb.cn/news/detail-485555.html

source_filename = "main.c"

@global_init_var = dso_local global i32 84, align 4
@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
@main.static_var = internal global i32 85, align 4
@main.static_var2 = internal global i32 0, align 4
@global_uninit_var = dso_local global i32 0, align 4

define dso_local void @func1(i32 noundef %0) {
  %2 = alloca i32, align 4
  store i32 %0, i32* %2, align 4
	...
  ret void
}

declare i32 @printf(i8* noundef, ...)

define dso_local i32 @main() {
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
 	...
  ret i32 %11 
}
.file   "main.c"
        .data
.globl global_init_var
        .align  4
        .type   global_init_var,@object
        .size   global_init_var,4
global_init_var:
.long   84  
        .align  4
        .type   static_var.0,@object
        .size   static_var.0,4
static_var.0:
.long   85  
        .section        .rodata
.LC0:
        .string "%d\n"
        .text
.globl func1
        .type   func1,@function
func1:
        pushl   %ebp
        movl    %esp, %ebp
        movl    8(%ebp), %eax
        pushl   %eax
        movl    $.LC0, %eax
        pushl   %eax
        call    printf
        addl    $8, %esp
.L0:
        movl    %ebp, %esp
        popl    %ebp
        ret
        .size   func1,.-func1
.globl main
        .type   main,@function
main:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        movl    $1, %eax
        movl    %eax, -4(%ebp)
        movl    static_var.0, %eax
        movl    static_var2.0, %ecx
        addl    %ecx, %eax
        movl    -4(%ebp), %ecx
        addl    %ecx, %eax
        movl    -8(%ebp), %ecx
        addl    %ecx, %eax
        pushl   %eax
        call    func1
        addl    $4, %esp
        movl    -4(%ebp), %eax
        jmp     .L1
.L1:
        movl    %ebp, %esp
        popl    %ebp
        ret
        .size   main,.-main
        .comm   global_uninit_var,4,4
.local static_var2.0
        .comm   static_var2.0,4,4 

九、目標(biāo)代碼生成

十、可執(zhí)行文件生成

十一、加載可執(zhí)行文件

到了這里,關(guān)于簡單介紹一個(gè)編譯器的結(jié)構(gòu)(下)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 一個(gè)關(guān)于編譯器優(yōu)化選項(xiàng)問題的解決

    一個(gè)關(guān)于編譯器優(yōu)化選項(xiàng)問題的解決

    因?yàn)楫?dāng)前項(xiàng)目單片機(jī)容量不夠使用,打算開啟編譯器優(yōu)化,結(jié)果在使用KEIL編譯器優(yōu)化后,程序在發(fā)送Modbus數(shù)據(jù)時(shí),程序直接跑飛了 最后發(fā)現(xiàn)是 局部變量指針 作為了DMA的內(nèi)存地址參數(shù),導(dǎo)致當(dāng)DMA連續(xù)搬運(yùn)數(shù)據(jù)時(shí),實(shí)際那個(gè)局部變量已經(jīng)被釋放,導(dǎo)致DMA搬運(yùn)數(shù)據(jù)的過程中出現(xiàn)錯(cuò)

    2024年04月09日
    瀏覽(38)
  • 從編譯器的角度 理解程序的邏輯結(jié)構(gòu)

    從編譯器的角度 理解程序的邏輯結(jié)構(gòu) 先說一下結(jié)論如果從人的思維的角度上看,程序的邏輯結(jié)構(gòu)有三種, 分別是順序結(jié)構(gòu),分支結(jié)構(gòu)和循環(huán)結(jié)構(gòu)。但是如果學(xué)習(xí)了匯編語言, 從機(jī)器的角度上看,已經(jīng)分不出分支和循環(huán)了,它們都是用跳轉(zhuǎn)指令。 從編譯器的角度上看,分支

    2024年02月08日
    瀏覽(17)
  • 【Rust日?qǐng)?bào)】用Rust從頭實(shí)現(xiàn)一個(gè)C編譯器

    一個(gè)聲明式解析庫 Untwine 發(fā)布0.4 Untwine是一個(gè)聲明性解析庫,它允許一種類似于使用自定義宏語法進(jìn)行直接模式匹配的解析風(fēng)格。這允許創(chuàng)建具有良好性能特征和高質(zhì)量錯(cuò)誤消息的極其緊湊的解析器。這些解析器實(shí)現(xiàn)起來很簡單,有幾個(gè)精心挑選的例子: 一個(gè)幾乎完整的JSO

    2024年04月22日
    瀏覽(22)
  • 鴻蒙篇——初次使用鴻蒙原生編譯器DevEcoStudio創(chuàng)建一個(gè)鴻蒙原生應(yīng)用遇到的坑--匯總(持續(xù)更新)

    背景:2023年12月13日,使用DevEcoStudio?4.0.0.600版本,項(xiàng)目的compileSdkVersion是8。 一.提示類似于ohpm ERROR: NOTFOUND package \\\"@ohos/hypium\\\" not found from all the registries或者npm ERR! 404 \\\'@ohos/hvigor@3.0.9\\\' is not in this registry.的錯(cuò)誤。 1.這里存在的第一個(gè)問題,無論怎么按照官方文檔設(shè)置ohpm 和 npm的倉

    2024年01月21日
    瀏覽(24)
  • C語言系列(所需基礎(chǔ):大學(xué)C語言及格)-1-編譯器/簡單的求和代碼/數(shù)據(jù)類型/變量的分類/變量的作用域和生命周期

    C語言系列(所需基礎(chǔ):大學(xué)C語言及格)-1-編譯器/簡單的求和代碼/數(shù)據(jù)類型/變量的分類/變量的作用域和生命周期

    為了方便,我使用的是在線的C語言編譯器進(jìn)行程序的運(yùn)行。 鏈接:https://www.bejson.com/runcode/c740/ 效果如下: 分為局部變量和全局變量 說白了,放在main函數(shù)外面的變量為全局變量,其他為局部變量。

    2024年02月19日
    瀏覽(25)
  • C++輸出編譯器名稱和版本以及編譯器位數(shù)、C/C++常見編譯器

    C++輸出編譯器名稱和版本以及編譯器位數(shù)、C/C++常見編譯器

    常見的C/C++編譯器主要包括以下幾種: GCC (GNU Compiler Collection):GCC是一個(gè)廣泛使用的編譯器套件,支持多種編程語言,包括C、C++、Objective-C等。它具有強(qiáng)大的優(yōu)化能力和跨平臺(tái)支持,并且被廣泛應(yīng)用于各種操作系統(tǒng)和開發(fā)環(huán)境。 Clang :Clang是基于LLVM的編譯器前端,支持C、

    2024年02月13日
    瀏覽(20)
  • python在線編譯器搭建,python在線編譯器源碼

    python在線編譯器搭建,python在線編譯器源碼

    本篇文章給大家談?wù)刾ython在線編譯器搭建,以及python在線編譯器源碼,希望對(duì)各位有所幫助,不要忘了收藏本站喔。 1. PyCharm集成開發(fā)環(huán)境 2. PyCharm的下載與安裝 3. Pycharm的使用 3.1 創(chuàng)建Python項(xiàng)目 3.2 創(chuàng)建子目錄 3.3 創(chuàng)建Python文件 3.4 切換解釋器 3.5 常用快捷鍵 4. Pycharm常用配置

    2024年03月25日
    瀏覽(24)
  • 編譯器(Compiler)及C/C++編譯器安裝(c+安裝)

    編譯器(Compiler)及C/C++編譯器安裝(c+安裝)

    目錄 一、常用編程語言的編譯器(compiler) 概述 二、GCC、MinGW、MinGW-w64 、TDM-GCC、Cygwin、MSYS、MSYS2的區(qū)別 三、MinGW-w64編譯器套件下載及安裝 四、MinGW-w64安裝后,windows環(huán)境變量配置(設(shè)置) 五、編譯器的運(yùn)行及其與開發(fā)環(huán)境的關(guān)系、編譯器的來源 ? ? ? ?機(jī)器語言是一種計(jì)算機(jī)指

    2024年02月07日
    瀏覽(28)
  • 探索Kotlin K2編譯器和Java編譯器的功能和能力

    文章首發(fā)地址 Kotlin K2編譯器是Kotlin語言的編譯器,負(fù)責(zé)將Kotlin源代碼轉(zhuǎn)換為Java字節(jié)碼或者其他目標(biāo)平臺(tái)的代碼。K2編譯器是Kotlin語言的核心組件之一,它的主要功能是將Kotlin代碼編譯為可在JVM上運(yùn)行的字節(jié)碼。 編譯過程: Kotlin K2編譯器將Kotlin源代碼作為輸入,并經(jīng)過詞法分

    2024年02月11日
    瀏覽(23)
  • 前端框架編譯器之模板編譯

    前端框架編譯器之模板編譯

    編譯原理:是計(jì)算機(jī)科學(xué)的一個(gè)分支,研究如何將 高級(jí)程序語言 轉(zhuǎn)換為 計(jì)算機(jī)可執(zhí)行的目標(biāo)代碼 的技術(shù)和理論。 高級(jí)程序語言:Python、Java、JavaScript、TypeScript、C、C++、Go 等。 計(jì)算機(jī)可執(zhí)行的目標(biāo)代碼:機(jī)器碼、匯編語言、字節(jié)碼、目標(biāo)代碼等。 編譯器 (Compiler):是一種將

    2024年04月28日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包