在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

            ARM下高效C編程

            作者: 時間:2016-11-20 來源:網(wǎng)絡(luò) 收藏
            通過一定的風(fēng)格來編寫C程序,可以幫助C編譯器生成執(zhí)行速度更快的ARM代碼。下面就是一些與性能相關(guān)的關(guān)鍵點:
            1、對局部變量、函數(shù)參數(shù)和返回值要使用signed和unsigned int類型。這樣可以避免類型轉(zhuǎn)換,而且可高效地使用ARM的32位數(shù)據(jù)操作指令。
            2、最高效的循環(huán)體形式是減計數(shù)到零(counts down to zero)的do-while循環(huán)。
            3、展開重要的循環(huán)來減少循環(huán)的開銷。
            4、不要依賴編譯器來優(yōu)化掉重復(fù)的存儲器訪問。指針別名會阻止編譯器的這種優(yōu)化。
            5、盡可能把函數(shù)參數(shù)的個數(shù)限制在4個以內(nèi)。如果函數(shù)參數(shù)都存放在寄存器內(nèi),那么函數(shù)調(diào)用就會快得多。
            6、按元素尺寸從小到大排列的方法來安排結(jié)構(gòu)體,特別是在thumb模式下編譯。
            7、不要使用位域,可以用掩碼和邏輯操作來替代。
            8、避免除法,可以用倒數(shù)的乘法來替代。
            9、避免邊界不對齊的數(shù)據(jù)。如果數(shù)據(jù)有可能邊界不對齊,那么就要使用char *指針類型來訪問。
            10、在C編譯器中使用內(nèi)嵌匯編可以利用到C編譯器本來不支持的指令或優(yōu)化。
            一、數(shù)據(jù)類型使用上的優(yōu)化
            1、局部變量
            一個char類型的數(shù)據(jù)比int類型的數(shù)據(jù)占用更小的寄存器空間或者更小的ARM堆??臻g。這兩種設(shè)想對于ARM來說,都是錯誤的。所有的ARM寄存器都是32位的,所有的堆棧入口至少是32位的。當(dāng)我們執(zhí)行i++,要利用當(dāng)i=255后,i++=0這個條件時,可以把它定義為char類型。
            2、函數(shù)參數(shù)
            盡管寬和窄的函數(shù)調(diào)用規(guī)則各有其優(yōu)點,但char或short類型的函數(shù)參數(shù)和返回值都會產(chǎn)生額外的開銷,導(dǎo)致性能的下降,并增加了代碼尺寸。所以,即使是傳輸一個8位的數(shù)據(jù),函數(shù)參數(shù)和返回值使用int類型也會更有效。
            3、總結(jié)
            1)對于存放在寄存器中的局部變量,除了8位或16位的算術(shù)模運算外,盡量不要使用char和short類型,而要使用有符號或無符號int類型。除法運算時使用無符號數(shù)執(zhí)行速度更快。
            2)對于存放在主存儲器中的數(shù)組和全局變量,在滿足數(shù)據(jù)大小的前提下,應(yīng)盡可能使用小尺寸的數(shù)據(jù)類型,這樣可以節(jié)省存儲空間。ARMv4體系結(jié)構(gòu)可以有效地裝載和存儲所有寬度的數(shù)據(jù),并可以使用遞增數(shù)組指針來有效地訪問數(shù)組。對于short類型數(shù)組,要避免使用數(shù)組基地址的偏移量,因為LDRH指令不支持偏移尋址。
            3)通過讀取數(shù)組或全局變量并賦給不同類型的局部變量時,或者把局部變量寫入不同類型的數(shù)組或者全局變量時,要進行顯式數(shù)據(jù)類型轉(zhuǎn)換。這種轉(zhuǎn)換使編譯器可以明確、快速地處理,把存儲器中數(shù)據(jù)寬度比較窄的數(shù)據(jù)類型擴展,并賦給寄存器中較寬的類型。
            4)由于隱式或者顯式的數(shù)據(jù)類型轉(zhuǎn)換通常會有額外的指令周期開銷,所以在表達(dá)式中應(yīng)盡量避免使用。Load和store指令一般不會產(chǎn)生額外的轉(zhuǎn)換開銷,因為load和store指令是自動完成數(shù)據(jù)類型轉(zhuǎn)換的。
            5)對于函數(shù)參數(shù)和返回值應(yīng)盡量避免使用char和short類型。即使參數(shù)范圍比較小,也應(yīng)該使用int類型,以防止編譯器做不必要的類型轉(zhuǎn)換。
            二、C循環(huán)結(jié)構(gòu)
            在ARM上,一個循環(huán)其實只要2條指令就足夠了:
            一條減法指令,進行循環(huán)減法計數(shù),同時設(shè)置結(jié)果的條件標(biāo)志;
            一條條件分支指令。
            這里的關(guān)鍵是,循環(huán)的終止條件應(yīng)為減計數(shù)到零,而不是計數(shù)增加到某個特定的限制值。由于減計數(shù)結(jié)構(gòu)已存儲在條件標(biāo)志里,與零比較的指令就可以省略了。由于不用i作為數(shù)組的下標(biāo)索引,采用減計數(shù)就沒有任何問題了。
            總而言之,無論對于有符號的循環(huán)計數(shù)值,都應(yīng)使用i!=0作為循環(huán)的結(jié)束條件。對有符號數(shù)i,這比使用條件i>0少了一條指令。
            總結(jié):
            1)使用減計數(shù)到零的循環(huán)結(jié)構(gòu),這樣編譯器就不需要分配一個寄存器來保存循環(huán)終止值,而且與0比較的指令也可以省略。
            2)使用無符號的循環(huán)計數(shù)值,循環(huán)繼續(xù)的條件為i!=0而不是i>0,這樣可以保證循環(huán)開銷只有兩條指令。
            3)如果事先知道循環(huán)體至少會執(zhí)行一次,那么使用do-while循環(huán)要比for循環(huán)要好,這樣可以使編譯器省去檢查循環(huán)計數(shù)值是否為零的步驟。
            4)展開重要的循環(huán)體可降低循環(huán)開銷,但不要過度展開,如果循環(huán)的開銷對整個程序來說占的比例很小,那么循環(huán)展開反而會增加代碼量并降低cache的性能。
            5)盡量使數(shù)組的大小是4或8的倍數(shù),這樣可以容易的以2,4,8次等多種選擇展開循環(huán),而不需要擔(dān)心剩余數(shù)組元素的問題。
            三、寄存器分配
            高效的寄存器分配
            應(yīng)該盡量限制函數(shù)內(nèi)部循環(huán)所用局部變量的數(shù)目,最多不超過12個,這樣,編譯器就可以把這些變量都分配給ARM寄存器。
            四、函數(shù)調(diào)用
            4寄存器規(guī)則
            帶有4個或者更少參數(shù)的函數(shù),要比多于4個參數(shù)的函數(shù)執(zhí)行效率高得多。對帶有少于4個參數(shù)的函數(shù)來說,編譯器可以用寄存器傳遞所有的參數(shù);而對于多于4個參數(shù)的函數(shù),函數(shù)調(diào)用者和被調(diào)用者必須通過訪問堆棧來傳遞一些參數(shù)。
            如果函數(shù)體積很小,只用到很少的寄存器,那么還有一些其他的方法來減少函數(shù)調(diào)用的開銷??梢园颜{(diào)用函數(shù)和被調(diào)用函數(shù)放在同一個C文件中,這樣編譯器就知道了被調(diào)用函數(shù)生成的代碼,并以此對調(diào)用函數(shù)進行一些優(yōu)化。
            總結(jié):
            1)盡量限制函數(shù)的參數(shù),不要超過4個,這樣函數(shù)調(diào)用的效率會更高。也可以將幾個相關(guān)的參數(shù)組織在一個結(jié)構(gòu)體中,用傳遞結(jié)構(gòu)體指針來代替多個參數(shù)。
            2)把比較小的被調(diào)用函數(shù)和調(diào)用函數(shù)放在同一個源文件中,并且要先定義,后調(diào)用,編譯器就可以優(yōu)化函數(shù)調(diào)用或者內(nèi)聯(lián)較小的函數(shù)。
            3)對性能影響較大的重要函數(shù)可使用關(guān)鍵字_inline進行內(nèi)聯(lián)。
            五、指針別名
            定義:當(dāng)2個指針指向同一個地址對象時,這2個指針被稱作該對象的別名(alias)。如果對其中一個指針進行寫入,就會影響從另一個指針的讀出。在一個函數(shù)中,編譯器通常不知道哪一個指針是別名,哪一個不是;或哪一個指針有別名,哪一個沒有。
            避免指針別名:
            1)不要依賴編譯器來消除包含存儲器訪問的公共子表達(dá)式,而應(yīng)建立一個新的局部變量來保存這個表達(dá)式的值,這樣可以保證只對這個表達(dá)式求一次值;
            2)避免使用局部變量的地址,否則對這個變量的訪問效率會比較低。
            六、結(jié)構(gòu)體安排
            在ARM上使用結(jié)構(gòu)體有2個問題需要考慮:結(jié)構(gòu)體地址邊界對齊和結(jié)構(gòu)體總的大小。
            獲得高效結(jié)構(gòu)體的原則:
            1)把所有8位大小的元素安排在結(jié)構(gòu)體的前面;
            2)以此安排16位、32位和64位的元素;
            3)把所有數(shù)組和比較大的元素安排在結(jié)構(gòu)體最后。
            4)對于一條指令,如果結(jié)構(gòu)體太大而不能訪問所有的元素,那么把元素組織到一個子結(jié)構(gòu)體中。編譯器可以維持單獨的子結(jié)構(gòu)體的指針。
            小結(jié):
            結(jié)構(gòu)體元素要按照元素的大小來排列,以最小的元素放在開始,最大的元素安排在最后;避免使用很大的結(jié)構(gòu)體,可以用層次化的小結(jié)構(gòu)體來代替;為了提高可移植性,人工對API的結(jié)構(gòu)體增加填充位,這樣,結(jié)構(gòu)體的安排將不會依賴與編譯器;在API的結(jié)構(gòu)體中要謹(jǐn)慎使用枚舉類型。一個枚舉類型的大小是編譯器相關(guān)的。
            七、位域
            注意事項:
            1)應(yīng)避免使用位域,而使用#define或者enum來定義屏蔽位;
            2)使用整型邏輯運算AND、OR、“異或”操作和屏蔽對位域進行測試、取反和設(shè)置操作。這些操作編譯效率高,還可以同時對多個位域進行測試、取反和設(shè)置。
            八、邊界不對齊數(shù)據(jù)和字節(jié)排列方式(大/小端)
            邊界不對齊數(shù)據(jù)和字節(jié)排列方式這2個問題,可使內(nèi)存訪問和移植問題復(fù)雜化。須考慮數(shù)組指針是否邊界對齊,ARM配置是大端(big-endian),還是小端(little-endian)的存儲器系統(tǒng)。
            總結(jié):
            1)盡量避免使用邊界不對齊的數(shù)據(jù);
            2)使用類型char *可指向任意字節(jié)邊界的數(shù)據(jù)。通過讀字節(jié)來訪問數(shù)據(jù),使用邏輯操作來組合數(shù)據(jù),這樣代碼就不會依賴于邊界是否對齊或者ARM的字節(jié)排列方式的配置;
            3)為了快速訪問邊界不對齊的結(jié)構(gòu)體,可以根據(jù)指針邊界和處理器的字節(jié)排序方式寫出不同的程序變體。
            九、除法
            ARM硬件上不支持除法指令,當(dāng)代碼中出現(xiàn)除法運算時,ARM編譯器會調(diào)用C庫函數(shù)(有符號的除法調(diào)用_rt_sdiv,無符號的調(diào)用_rt_udiv),來實現(xiàn)除法操作。有許多不同類型的除法程序來適應(yīng)不同的除數(shù)和被除數(shù)。
            總結(jié):
            1)盡可能避免使用除法。對環(huán)形緩沖區(qū)的處理可以不用除法。
            2)如果不能避免除法運算,那么盡可能考慮使用除法程序同時產(chǎn)生商n/d和余數(shù)n%d的好處。
            3)對于重復(fù)對同一除數(shù)d的除法,預(yù)先計算好s=(2k-1)/d??捎贸艘詓的2k位乘法來代替除以d的k位無符號整數(shù)除法。
            4)使用2的整數(shù)次冪作除數(shù)。當(dāng)2的整數(shù)次冪做除數(shù)時,編譯器會自動將除法運算轉(zhuǎn)換成移位運算。所以在編寫程序算法時,盡量使用2的整數(shù)次冪做除數(shù)。
            5)求余運算??梢詫⒁恍┑湫偷那笥噙\算進行轉(zhuǎn)換,以避免在程序中使用除法運算。如:
            uint counter1(uint count)
            {
            return (++count`);
            }
            轉(zhuǎn)換成:
            uint counter2(uint count)
            {
            if (++count >=60)
            count=0;
            return (count);
            }
            十、浮點運算
            大多數(shù)ARM處理器硬件上并不支持浮點運算。這樣在一個對價格敏感的嵌入式應(yīng)用系統(tǒng)中,可節(jié)省空間和降低功耗。除了硬件向量浮點累加器VFP和ARM7500FE上的浮點累加器FPA外,C編譯器必須在軟件上提供浮點支持。
            十一、內(nèi)聯(lián)函數(shù)和內(nèi)嵌匯編
            高效地調(diào)用函數(shù),使用內(nèi)聯(lián)函數(shù)可以完全去除函數(shù)調(diào)用的開銷,另外許多編譯器允許在C源程序中使用內(nèi)嵌匯編。使用包含匯編的內(nèi)嵌函數(shù),可以使編譯器支持通常不能有效使用的ARM指令和優(yōu)化方法。
            內(nèi)聯(lián)函數(shù)和內(nèi)嵌匯編最大的好處是,可以實現(xiàn)一些在C語言部分中通常難以完成的操作。使用內(nèi)聯(lián)函數(shù)要比使用#define宏定義更好,因為后者不檢查函數(shù)參數(shù)和返回值的類型。


            關(guān)鍵詞: ARMC編

            評論


            技術(shù)專區(qū)

            關(guān)閉