İşte gerçek bir dünya örneği: Sabit nokta eski derleyicilerde çoğalır.
Bunlar sadece kayan nokta olmayan cihazlarda kullanışlı değildir, tahmin edilebilir bir hata ile size 32 bit hassasiyet verdiklerinden hassaslık konusunda parlarlar (şamandıra sadece 23 bit vardır ve hassas kaybı tahmin etmek daha zordur). mesela, muntazam yakın göreli hassasiyet ( ) yerine, tüm aralık boyunca muntazam mutlak hassasiyet ( ).float
Modern derleyiciler bu sabit nokta örneğini güzelce optimize eder, bu nedenle derleyiciye özgü koda ihtiyaç duyan daha modern örnekler için bkz.
C'nin tam çarpma işleci yoktur (N bit girişlerinden 2N bit sonucu). C olarak ifade etmenin olağan yolu, girdileri daha geniş bir türe dökmek ve derleyicinin girişlerin üst bitlerinin ilginç olmadığını fark etmesini ummaktır:
// on a 32-bit machine, int can hold 32-bit fixed-point integers.
int inline FixedPointMul (int a, int b)
{
long long a_long = a; // cast to 64 bit.
long long product = a_long * b; // perform multiplication
return (int) (product >> 16); // shift by the fixed point bias
}
Bu kodla ilgili sorun, doğrudan C dilinde ifade edilemeyen bir şey yapmamızdır. İki 32 bit sayıyı çarpmak ve orta bit 32 biti döndürdüğümüz 64 bit sonucu elde etmek istiyoruz. Bununla birlikte, C'de bu çarpma mevcut değildir. Yapabileceğiniz tek şey tamsayıları 64 bit'e yükseltmek ve 64 * 64 = 64 çarpımı yapmaktır.
x86 (ve ARM, MIPS ve diğerleri) çarpmayı tek bir komutla yapabilir. Bazı derleyiciler bu gerçeği yoksaymak ve çarpma yapmak için bir çalışma zamanı kitaplığı işlevini çağıran kod üretmek için kullanılır. 16'ya geçiş genellikle bir kütüphane rutini tarafından da yapılır (ayrıca x86 bu değişiklikleri yapabilir).
Bu yüzden sadece bir çarpma için bir veya iki kütüphane çağrısı kaldı. Bunun ciddi sonuçları var. Vardiya yavaşlamakla kalmaz, kayıtlar işlev çağrıları boyunca korunmalıdır ve satır içi ve kod çözme işlemlerine de yardımcı olmaz.
Aynı kodu (satır içi) birleştiricide yeniden yazarsanız, önemli bir hız artışı elde edebilirsiniz.
Buna ek olarak: ASM kullanmak sorunu çözmenin en iyi yolu değildir. Çoğu derleyici, C cinsinden ifade edemiyorsanız, bazı derleyici talimatlarını içsel formda kullanmanıza izin verir.
İçsel özellikleri kullanarak, işlevi C-derleyicisinin olup biteni anlama şansına sahip olacak şekilde yeniden yazabilirsiniz. Bu, kodun satır içine alınmasına, kayıt tahsisine izin verir, ortak alt ifade eliminasyonu ve sabit yayılım da yapılabilir. Elle yazılmış montajcı kodu üzerinde bu şekilde büyük bir performans artışı elde edersiniz .
Referans için: VS.NET derleyicisi için sabit noktalı mul için sonuç:
int inline FixedPointMul (int a, int b)
{
return (int) __ll_rshift(__emul(a,b),16);
}
Sabit nokta bölümlerinin performans farkı daha da büyüktür. Birkaç asm satırı yazarak bölüm ağır sabit nokta kodu için faktör 10'a kadar iyileştirmeler yaptım.
Visual C ++ 2013 kullanarak her iki yol için aynı derleme kodu verir.
2007'den gelen gcc4.1 de saf C versiyonunu güzel bir şekilde optimize ediyor. (Godbolt derleyici gezgininde gcc'nin daha önceki herhangi bir sürümü yüklü değildir, ancak muhtemelen eski GCC sürümleri bile bunu intrinsics olmadan yapabilir.)
Godbolt derleyici gezgininde x86 (32 bit) için kaynak + asm ve ARM'ye bakın . (Ne yazık ki basit saf C sürümünden kötü kod üretecek kadar eski derleyici yok.)
Modern CPU'lar C operatörleri yoktur şeyler yapabilirsiniz hiç gibi popcnt
veya bit tarama ilk veya son ayarlanan biraz bulmak için . (POSIX'in bir ffs()
işlevi vardır, ancak anlambilimi x86 bsf
/ ile eşleşmez bsr
. Bkz. Https://en.wikipedia.org/wiki/Find_first_set ).
Bazı derleyiciler bazen bir tamsayıdaki set bitlerinin sayısını sayan bir döngüyü tanıyabilir ve bunu bir popcnt
komut için derleyebilir (derleme zamanında etkinleştirildiyse), ancak __builtin_popcnt
GNU C'de veya yalnızca SSE4.2 ile hedefleme donanımı: _mm_popcnt_u32
from<immintrin.h>
.
Veya C ++ ile, a atayın std::bitset<32>
ve kullanın .count()
. (Bu dil portably her zaman doğru bir şey derlemek olacak şekilde, standart kütüphanesinde yoluyla popcount optimize edilmiş bir uygulama ortaya çıkarmak için bir yol bulmuş bir durumdur ve ne olursa olsun hedef desteklerin yararlanabilir.) Ayrıca bkz https : //en.wikipedia.org/wiki/Hamming_weight#Language_support .
Benzer şekilde, onu içeren bazı C uygulamalarında (endian dönüşümü için 32 bitlik bayt takas) ntohl
derleyebilir bswap
.
İçsel veya elle yazılmış asm için bir başka önemli alan, SIMD talimatları ile manuel vektörleştirmedir. Derleyiciler, gibi basit döngülerle kötü değildir dst[i] += src[i] * 10.0;
, ancak işler daha karmaşık hale geldiğinde genellikle kötü yapar veya hiç otomatik vektörleştirmez. Örneğin, SIMD kullanarak atoi nasıl uygulanır? derleyici tarafından skaler koddan otomatik olarak oluşturulur.