電子產(chǎn)業(yè)一站式賦能平臺(tái)

PCB聯(lián)盟網(wǎng)

搜索
查看: 48|回復(fù): 0
收起左側(cè)

Keil AC6編譯器實(shí)現(xiàn)的原理

[復(fù)制鏈接]

319

主題

319

帖子

2727

積分

三級(jí)會(huì)員

Rank: 3Rank: 3

積分
2727
跳轉(zhuǎn)到指定樓層
樓主
發(fā)表于 2024-10-23 10:45:00 | 只看該作者 |只看大圖 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
關(guān)注+星標(biāo)公眾號(hào),不錯(cuò)過(guò)精彩內(nèi)容

作者 | strongerHuang微信公眾號(hào) | 嵌入式專欄
Keil MDK自V5.36版本之后,就“拋棄”了AC5(Arm Compiler 5)編譯器,你會(huì)發(fā)現(xiàn),下載最新版V5.38a,沒(méi)有AC5編譯器。
而AC6相較于AC5在編譯速度上有很大的提升,那么,你知道為什么嗎?
原因在于AC6是基于現(xiàn)代LLVM和Clang技術(shù)構(gòu)建而成,今天就來(lái)講講AC6和LLVM的編譯原理。
關(guān)于編譯器AC6
早在2015年,Arm就推出了AC6編譯器,并集成在Keil MDK中。但由于AC5和AC6對(duì)代碼的的兼容性不友好,導(dǎo)致很多使用Keil MDK的用戶還是AC5編譯器。
所以兼容性不友好,但AC6的編譯速度相比AC5快很多,因此還是吸引了一部分人使用AC6編譯器。
為什么AC6編譯速度快了很多呢?原因在于AC6使用了一套全新的架構(gòu)技術(shù)。
AC6組件如下圖:

1.armclang
  • 基于現(xiàn)代LLVM和Clang技術(shù)構(gòu)建
  • 支持GNU語(yǔ)法匯編
  • 與最初為GCC編寫的源代碼高度兼容
  • 實(shí)現(xiàn)規(guī)范,包括ANSI / ISO C和C ++,用于Arm架構(gòu)的ABI,用于64位Arm架構(gòu)的ABI以及Arm C語(yǔ)言擴(kuò)展(ACLE)
    2.armlink功能豐富的專用嵌入式鏈接器,該鏈接器將對(duì)象和庫(kù)組合在一起以生成可執(zhí)行文件
    3.Arm C庫(kù):由Arm針對(duì)性能和代碼密度進(jìn)行了優(yōu)化,并包括 用于深度嵌入式應(yīng)用程序的微型MicroLib。
    4.Arm C++庫(kù):基于LLVM libc ++項(xiàng)目的庫(kù)
    這部分內(nèi)容可參看:
    https://developer.arm.com/tools-and-software/embedded/arm-compiler
    Keil MDK 編譯器 AC5 和 AC6 優(yōu)化選項(xiàng)重要內(nèi)容有著很大區(qū)別:ARM Compiler 5(和更早版本)使用armcc編譯器,而ARM Compiler 6將armcc替換為armclang,armclang基于LLVM,它具有不同的命令行參數(shù)、指令等,因此算是一個(gè)新的編譯器。
    這里推薦閱讀:
    手把手教你Keil MDK編譯器從V5升級(jí)到V6手把手教你升級(jí)Keil MDK的ARM編譯器手把手教你在Keil MDK中使用GCC編譯器工具鏈Keil MDK使用編譯器AC5與AC6生成瀏覽信息的差異
    LLVM基礎(chǔ)內(nèi)容
    上面我們講到了AC6是基于LLVM,下面就來(lái)講講關(guān)于LLVM的內(nèi)容。
    1.什么LLVM?
    LLVM是構(gòu)架編譯器(compiler)的框架系統(tǒng),以C++編寫而成,用于優(yōu)化以任意程序語(yǔ)言編寫的程序的編譯時(shí)間(compile-time)、鏈接時(shí)間(link-time)、運(yùn)行時(shí)間(run-time)以及空閑時(shí)間(idle-time),對(duì)開(kāi)發(fā)者保持開(kāi)放,并兼容已有腳本。
    在理解LLVM時(shí),我們可以認(rèn)為它包括了一個(gè)狹義的LLVM和一個(gè)廣義的LLVM。廣義的LLVM其實(shí)就是指整個(gè)LLVM編譯器架構(gòu),包括了前端、后端、優(yōu)化器、眾多的庫(kù)函數(shù)以及很多的模塊;而狹義的LLVM其實(shí)就是聚焦于編譯器后端功能(代碼生成、代碼優(yōu)化、JIT等)的一系列模塊和庫(kù)。
    2.LLVM優(yōu)勢(shì)傳統(tǒng)編譯器分三個(gè)階段: 前端(Frontend)-- 優(yōu)化器(Optimizer)-- 后端(Backend)
    前端負(fù)責(zé)分析源代碼,可以檢查語(yǔ)法級(jí)錯(cuò)誤,并構(gòu)建針對(duì)語(yǔ)言的抽象語(yǔ)法樹(shù)(AST);抽象語(yǔ)法樹(shù)可以進(jìn)一步轉(zhuǎn)換為優(yōu)化,最終轉(zhuǎn)為新的表示方式,然后再交給讓優(yōu)化器和后端處理;
    最終由后端生成可執(zhí)行的機(jī)器碼。

    llvm也分三個(gè)階段,但是設(shè)計(jì)上略微的有些區(qū)別, LLVM不同的就是對(duì)于不同的語(yǔ)言它都提供了同一種中間表示:

    前端可以使用不同的編譯工具對(duì)代碼文件做詞法分析以形成抽象語(yǔ)法樹(shù)AST,然后將分析好的代碼轉(zhuǎn)換成LLVM的中間表示IR(intermediate representation);中間部分的優(yōu)化器只對(duì)中間表示IR操作,通過(guò)一系列的pass對(duì)IR做優(yōu)化;后端負(fù)責(zé)將優(yōu)化好的IR解釋成對(duì)應(yīng)平臺(tái)的機(jī)器碼。LLVM的優(yōu)點(diǎn)在于,中間表示IR代碼編寫良好,而且不同的前端語(yǔ)言最終都轉(zhuǎn)換成同一種的IR。
    為什么使用三段式設(shè)計(jì)??jī)?yōu)勢(shì)在哪里?首先解決一個(gè)很大的問(wèn)題:假如有N種語(yǔ)言(C、OC、C++、Swift...)的前端,同時(shí)也有M個(gè)架構(gòu)(模擬器、arm64、x86...)的target,是否就需要N*M個(gè)編譯器?三段式架構(gòu)的價(jià)值就提現(xiàn)出來(lái)了,通過(guò)共享優(yōu)化器的中轉(zhuǎn),很好的解決了這個(gè)問(wèn)題。
    Clang和LLVM關(guān)系
    Clang是一個(gè)C++編寫、基于LLVM、發(fā)布于LLVM BSD許可證下的C/C++/Objective-C/Objective-C++編譯器。那么為什么已經(jīng)有了GCC還要開(kāi)發(fā)Clang呢?Clang相比于GCC有什么優(yōu)勢(shì)呢?
    其實(shí),這也是Clang當(dāng)初在設(shè)計(jì)開(kāi)發(fā)的時(shí)候所主要考慮的原因。Clang是一個(gè)高度模塊化開(kāi)發(fā)的輕量級(jí)編譯器,它的編譯速度快、占用內(nèi)存小、非常方便進(jìn)行二次開(kāi)發(fā)。
    LVM和Clang的關(guān)系是怎樣的呢。我們將它們對(duì)應(yīng)于傳統(tǒng)的編譯器當(dāng)中的幾個(gè)獨(dú)立的部分,這樣能夠更加方便明確生動(dòng)的表述。

    其實(shí),對(duì)應(yīng)到這個(gè)圖中,我們就可以非常明確的找出它們的對(duì)應(yīng)關(guān)系。LLVM與Clang是C/C++編譯器套件。對(duì)于整個(gè)LLVM的框架來(lái)說(shuō),包含了Clang,因?yàn)镃lang是LLVM的框架的一部分,是它的一個(gè)C/C++的前端。Clang使用了LLVM中的一些功能,目前知道的就是針對(duì)中間格式代碼的優(yōu)化,或許還有一部分生成代碼的功能。
    從源代碼角度來(lái)講,clang是基于LLVM的一個(gè)工具。而功能的角度來(lái)說(shuō),LLVM可以認(rèn)為是一個(gè)編譯器的后端,而clang是一個(gè)編譯器的前端,他們的關(guān)系更加的明了,一個(gè)編譯器前端想要程序最終變成可執(zhí)行文件,是缺少不了對(duì)編譯器后端的介紹的。
    LLVM編譯工具鏈編譯流程
    使用LLVM的對(duì)一門語(yǔ)言編譯的簡(jiǎn)圖如下所示:

    LLVM編譯一個(gè)源文件的過(guò)程:預(yù)處理 -> 詞法分析 -> Token -> 語(yǔ)法分析 -> AST -> 代碼生成 -> LLVM IR -> 優(yōu)化 -> 生成匯編代碼 -> Link -> 目標(biāo)文件.
    完全需要我們手工,或者依靠其他工具如lex, yacc來(lái)做的事情,是從源代碼到token的詞法分析和從token到AST的語(yǔ)法分析;詞法分析的輸出是將源代碼解析成一個(gè)個(gè)的token。這些token就是有類型和值的一些小單元,比如是關(guān)鍵字,還是數(shù)字,還是標(biāo)識(shí)符,從AST轉(zhuǎn)LLVM開(kāi)始,LLVM就開(kāi)始提供一系列的工具幫助我們快速開(kāi)發(fā)。從IR(中間指令代碼)到DAG(有向無(wú)環(huán)圖)再到機(jī)器指令,針對(duì)常用的平臺(tái),LLVM有完善的后端。也就是說(shuō),我們只要完成了到IR這一步,后面的工作我們就享有和Clang一樣的先進(jìn)生產(chǎn)力了。
    CodeGen負(fù)責(zé)將語(yǔ)法樹(shù)從頂至下遍歷,翻譯成LLVM IR,LLVM IR是Frontend的輸出,也是LLVM Backerend的輸入,橋接前后端。
    LLVM命令:可以使用 llc 將 LLVM 字節(jié)代碼轉(zhuǎn)換成特定于平臺(tái)的匯編代碼lli 可以通過(guò)解釋器或使用高級(jí)選項(xiàng)中的即時(shí) (JIT) 編譯器執(zhí)行此工作llvm-gcc 是 GNU Compiler Collection (gcc) 的修改版本,可以在使用 -S -emit-llvm 選項(xiàng)運(yùn)行時(shí)會(huì)生成 LLVM 字節(jié)代碼。
    編譯指令:clang -c -emit-llvm test1.c -o test1.bc  編譯產(chǎn)生字節(jié)碼
    clang -S -emit-llvm test.c -o test.ll   編譯產(chǎn)生可視化字節(jié)碼
    llvm-dis test1.bc test1.ll    bc字節(jié)碼轉(zhuǎn)為可視化字節(jié)碼ll
    llvm-as test1.ll test1.bc    可視化字節(jié)碼轉(zhuǎn)為字節(jié)碼bc  
    ------------ END ------------



    ●專欄《嵌入式工具
    ●專欄《嵌入式開(kāi)發(fā)》
    ●專欄《Keil教程》
    ●嵌入式專欄精選教程

    關(guān)注公眾號(hào)回復(fù)“加群”按規(guī)則加入技術(shù)交流群,回復(fù)“1024”查看更多內(nèi)容。



    點(diǎn)擊“閱讀原文”查看更多分享。
  • 發(fā)表回復(fù)

    本版積分規(guī)則

    關(guān)閉

    站長(zhǎng)推薦上一條 /1 下一條


    聯(lián)系客服 關(guān)注微信 下載APP 返回頂部 返回列表