İşlemcide Komut Yürütmenin Yapısı
Aritmetik Mantık Birimi (ALU), ikili veriler üzerinde temel matematiksel işlemleri (toplama, çıkarma) ve mantıksal işlemleri (VE, VEYA, kaydırma) gerçekleştiren işlemcinin "hesaplama çekirdeğidir". Makine kodunu kaydedicilerdeki gerçek veri değişikliklerine dönüştüren ve program dallanmasını yönetmek için durum bayraklarını ayarlayan tam olarak ALU'dur. Çalışma prensibini anlamak, işlemci hattındaki darboğazlardan kaçınarak daha verimli kod yazmanıza yardımcı olur.
İçindekiler
CPU Mimarisinde ALU'nun Rolü
Merkezi İşlem Birimi (CPU), insan algısındaki gibi "düşünmez". Sadece talimatları sırayla işler. ALU, Execute (Yürütme) aşamasından sorumludur. Kontrol Birimi (Control Unit) komutu çözerken ve verileri seçerken, ALU hesaplama yapmak için sinyalleri bekler.
ALU'nun temel özelliği deterministik olmasıdır. Aynı girdi verileri ve kontrol sinyalleri için sonuç her zaman aynı olacak ve öngörülebilir bir sürede (gecikme/latency) elde edilecektir. ALU, hangi talimatın bir sonraki yürütüleceğine karar vermez; bu işi, önceki işlemden sonra ALU'nun kendisinin ayarladığı bayraklara dayalı olarak Kontrol Birimi yapar.
Dahili Yapı: Birim Nelerden Oluşur
ALU, monolitik bir kara kutu değildir. İçeride birkaç özel devreden oluşur:
- Kombinasyonel Mantık: Bit düzeyinde işlemleri (AND, OR, XOR, NOT) neredeyse anında (sinyalin yayılma süresi kadar) gerçekleştiren mantık kapıları seti.
- Toplayıcılar: Toplama ve çıkarma işlemlerini gerçekleştiren devreler. Genellikle geniş kaydedicilerle (64 bit ve üzeri) çalışmayı hızlandırmak için taşıma ileri bakışlı toplayıcılar (carry-lookahead adders) kullanılır.
- Varil Kaydırıcı (Barrel Shifter): Bitleri hızlıca sola veya sağa kaydırmak için kullanılan cihaz. $N$ pozisyonluk kaydırma, $N$ ardışık kaydırma döngüsü yerine tek bir saat döngüsünde gerçekleştirilir.
- Bayrak Kaydedicisi (EFLAGS/RFLAGS): Sonucun durumunu sabitleyen tetikleyici seti:
- ZF (Zero Flag - Sıfır Bayrağı): Sonuç sıfıra eşittir.
- CF (Carry Flag - Taşıma Bayrağı): En yüksek basamaktan taşıma gerçekleşti (işaretsiz aritmetik için önemlidir).
- SF (Sign Flag - İşaret Bayrağı): Sonucun en yüksek biti 1'dir (tümleyen kodunda negatif sayı).
- OF (Overflow Flag - Taşma Bayrağı): İşaretli taşma gerçekleşti.
Modern superscalar işlemcilerde birden fazla bağımsız ALU olabilir (örneğin, tamsayı işlemleri için 4–6 birim). Bu, birbirine bağlı olmadıkları sürece birden fazla talimatın aynı anda yürütülmesine (Instruction Level Parallelism) olanak tanır.
İşlem Türleri: Toplamadan Karşılaştırmaya
Tüm işlemci talimatları, ALU aracılığıyla veriler üzerindeki etki türüne göre sınıflandırılabilir.
Temel Aritmetik
- Toplama (ADD) ve Çıkarma (SUB): En hızlı işlemler. Birden fazla toplayıcının varlığı sayesinde genellikle 1 saat döngüsü gecikme (latency) ile ve çoğu zaman 1 saat döngüsünden daha az geçiş hızı (throughput) ile gerçekleştirilir.
- Artırma/Azaltma (INC/DEC): Bir ile toplama/çıkarma işleminin özel durumlarıdır. Modern mimarilerde (x86-64, ARM) genellikle ADD/SUB ile aynı maliyete sahiptirler, ancak taşıma bayrağı ile çalışma açısından farklılıklar gösterebilirler.
Mantıksal İşlemler ve Kaydırmalar
- Bit Düzeyinde Mantık (AND, OR, XOR, NOT): Bitleri maskelemek, kaydedicileri temizlemek (örneğin,
XOR RAX, RAXkaydediciyiMOV RAX, 0'dan daha hızlı ve kompakt bir şekilde sıfırlar) ve kriptografi için kullanılır. - Kaydırmalar (SHL, SHR, SAR, ROL, ROR): Aritmetik kaydırmalar sayının işaretini korur, mantıksal kaydırmalar ise sıfırlarla doldurur. Döngüsel kaydırmalar, dışarı atılan bitleri başa taşır.
Çarpma ve Bölme
Bu işlemler çok daha karmaşıktır.
- Çarpma (MUL/IMUL): Daha fazla transistör ve saat döngüsü gerektirir. 64-bit sayılar için gecikme 3–5 saat döngüsü olabilir.
- Bölme (DIV/IDIV): En yavaş tamsayı işlemidir. Gecikme, mimariye ve bit derinliğine bağlı olarak 20–90 saat döngüsüne kadar çıkabilir. Bölme, algoritmaların sıkça "darboğaz" yaratan kısmıdır.
Karşılaştırma (CMP/TEST)
Teknik olarak karşılaştırma, sonucu bir kaydediciye yazılmayan, yalnızca bayrakları güncelleyen bir çıkarma işlemidir.
CMP A, B, $A - B$ işlemini gerçekleştirir. Eğer $ZF=1$ ise, $A=B$ demektir. Eğer $SF \neq OF$ ise, $A < B$ demektir (işaretli sayılar için).TEST A, B, $A & B$ işlemini gerçekleştirir ve operandları değiştirmeden bayrakları günceller. Ayarlanmış bitlerin varlığını kontrol etmek için kullanılır.
Komut Yaşam Döngüsü: 5 Yürütme Aşaması
ALU'nun süreçte nerede olduğunu anlamak için klasik 5 aşamalı hattı (RISC mimarisi, örneğin MIPS veya ARM) inceleyelim:
- IF (Instruction Fetch - Talimat Getirme): Bellekten (L1 önbelleği) talimatın getirilmesi.
- ID (Instruction Decode - Talimat Çözme): Komutun çözülmesi. Kontrol birimi hangi işlemin gerektiğini belirler ve operandları kaydedici dosyasından okur.
- EX (Execute - Yürütme): ALU burada çalışır. Aritmetik veya mantıksal işlem gerçekleştirilir, yükleme/kaydetme için bellek adresi hesaplanır.
- MEM (Memory Access - Bellek Erişimi): Talimat belleğe erişim gerektiriyorsa (LOAD/STORE), okuma veya yazma işlemi gerçekleşir. Aritmetik talimatlar için bu aşama çoğu zaman boşta kalır.
- WB (Write Back - Geri Yazma): ALU'dan gelen sonuç hedef kaydediciye geri yazılır.
Veri Tehlikeleri (Data Hazards). Bir sonraki talimat, henüz WB aşamasında yazılmamış olan önceki talimatın sonucuna bağlıysa, işlemcinin beklemesi (stall) gerekir veya verileri EX aşamasından doğrudan bir sonraki ALU girişine aktarmak için kaydedici yeniden adlandırma ve sonuç iletme (forwarding/bypassing) mekanizmasını kullanması gerekir.
İşlemlerin Performans Üzerindeki Etkisi
Tüm işlemler aynı "ağırlıkta" değildir. Kritik kod bölümlerini (hot paths) optimize ederken şunları dikkate almak önemlidir:
| İşlem | Yaklaşık Gecikme (Saat Döngüsü) | Geçiş Hızı | Açıklama |
|---|---|---|---|
| Toplama/Çıkarma | 1 | 0.25–0.5 | Çok hızlı, birden fazla yürütme portu |
| Mantık (AND, OR) | 1 | 0.25–0.5 | Toplamaya benzer |
| Kaydırma | 1 | 0.5–1 | Hızlı, ancak ayrı bir port kaplayabilir |
| Çarpma (Tamsayı) | 3–5 | 1 | Bit derinliğine bağlıdır |
| Bölme (Tamsayı) | 20–90 | 10–20 | Döngülerde kaçınılmalıdır |
| Dallanma (Branch) | 1–20+ | 1 | Tahmin doğruluğuna bağlıdır |
Not: Rakamlar modern x86-64 (Intel Core / AMD Ryzen) ve ARM (Apple M-serisi / Cortex) için ortalamadır.
Dallanma Sorunu
ALU, koşullu dallanmalar (JE, JNE, B.EQ) için bayrakları ayarlar. Eğer Dallanma Tahmincisi (Branch Predictor) hata yaparsa, işlem hattı temizlenir ve onlarca saat döngüsü kaybedilir. Bu nedenle, lineer yürütme içeren kod (verilere bağımlı dallanmalar olmadan) her zaman daha hızlı çalışır.
Kod Optimizasyonu İçin İpuçları
- Bölmeyi çarpma ve kaydırma ile değiştirin. İkinin kuvvetine bölme ($x / 8$), sağa kaydırma ($x >> 3$) ile eşdeğerdir. Derleyiciler bunu sabitler için otomatik olarak yapar, ancak değişkenler için işlemin maliyetini hatırlamak gerekir.
- Koşullar yerine bit maskeleri kullanın. Şunun yerine:
if (x > 0) y = a; else y = b;
```
Boru hattı temizlemesini önleyen, bayrak aritmetiğine veya bit düzeyinde işlemlere dayalı dallanmasız mantık (branchless) kullanılabilir.
3. **Bağımsız işlemleri gruplayın.**
Birbirine bağlı olmayan iki karmaşık hesaplama yapmanız gerekiyorsa, bunları derleyicinin farklı ALU yürütme birimlerinde paralelleştirebilmesi için uygun şekilde yerleştirin.
4. **Yanlış bağımlılıklardan kaçının.**
x86'da sık yapılan bir hata, art arda farklı amaçlar için aynı kaydediciyi kullanmaktır. Kaydedicinin önceki değerinden bağımlılığı koparmak için sıfırlama amacıyla `XOR REG, REG` kullanın.
## Düşük Seviyeli Optimizasyonda Sık Yapılan Hatalar
* **Gerekmediği yerde mikro optimizasyon.** `i++` yerine `++i` kullanmak veya döngüleri manuel açmak, bu optimizasyonları insanlardan daha iyi yapan modern derleyicilerde (GCC, Clang, MSVC) genellikle performans artışı sağlamaz. Algoritmik karmaşıklığa ve bellek erişimine odaklanın.
* **Önbelleği göz ardı etmek.** Aritmetikte 1 saat döngüsü tasarruf etmek, kötü veri yerelliği nedeniyle işlemcinin ana bellekten veri almak için 200 saat döngüsü beklemesi durumunda anlamsızdır.
* **Bölme gecikmesini hesaba katmamak.** Büyük diziler üzerindeki yoğun bir döngü içinde `%` (bölmeden kalan) veya `/` operatörünün kullanılması, bit maskelerinin (`& (N-1)` ikinin kuvvetleri için) kullanımına kıyasla programı katbekat yavaşlatabilir.
## SSS
**ALU ile FPU arasındaki fark nedir?**
ALU tamsayılar (integer) ve adreslerle çalışır. FPU (Floating Point Unit) veya vektörel birimler (SIMD/AVX) kayan noktalı sayılarla çalışır. Modern işlemcilerde bu birimler fiziksel olarak ayrılmıştır ve farklı talimat setlerine ve kaydedicilere sahiptir.
**Neden `XOR RAX, RAX`, `MOV RAX, 0`'dan daha iyidir?**
x86 mimarisinde `XOR` talimatı daha kısadır (kodda daha az bayt) ve daha da önemlisi, `RAX` kaydedicisinin önceki değerinden bağımlılığı koparır. İşlemci, eski değere artık ihtiyaç olmadığını anlar ve fiziksel kaydediciyi daha erken serbest bırakarak paralellizi artırır.
**ALU kayan noktalı işlemler yapabilir mi?**
Hayır, klasik tamsayı ALU'su IEEE 754 formatıyla çalışamaz. Bunun için işlemcinin içinde bulunan ancak mimari olarak tamsayı yolundan ayrı olan ayrı yürütme birimleri (FP ALU) mevcuttur.
**SIMD nedir ve bunun ALU ile ilgisi nedir?**
SIMD (Single Instruction, Multiple Data - Tek Komut, Çoklu Veri), ALU yeteneklerinin bir genişletmesidir. Tek bir sayıyı işleyen skaler bir ALU yerine, tek bir işlemi (örneğin toplama) aynı anda bir veri paketine (örneğin dört adet 32-bit sayıya) uygulayan vektörel bir ALU kullanılır. Bu, grafik işleme, ses ve bilimsel hesaplamalar gibi görevler için geçiş hızını katlayarak artırır.