Có nhiều lý do khiến bạn không chỉ có một số lượng lớn các đăng ký:
- Chúng được liên kết chặt chẽ với hầu hết các giai đoạn đường ống. Đối với người mới bắt đầu, bạn cần theo dõi thời gian tồn tại của chúng và chuyển tiếp kết quả trở lại các giai đoạn trước đó. Sự phức tạp trở nên khó chữa rất nhanh và số lượng dây (theo nghĩa đen) liên quan tăng lên với tốc độ tương tự. Nó đắt về diện tích, điều đó cuối cùng có nghĩa là nó đắt về công suất, giá cả và hiệu suất sau một thời điểm nhất định.
- Nó chiếm không gian mã hóa hướng dẫn. 16 thanh ghi chiếm 4 bit cho nguồn và đích, và 4 thanh khác nếu bạn có lệnh 3 toán hạng (ví dụ: ARM). Đó là rất nhiều không gian mã hóa tập lệnh được sử dụng chỉ để chỉ định thanh ghi. Điều này cuối cùng ảnh hưởng đến giải mã, kích thước mã và một lần nữa độ phức tạp.
- Có nhiều cách tốt hơn để đạt được cùng một kết quả ...
Ngày nay, chúng ta thực sự có rất nhiều sổ đăng ký - chúng không được lập trình rõ ràng. Chúng tôi đã "đăng ký đổi tên". Trong khi bạn chỉ truy cập vào một tập hợp nhỏ (8-32 thanh ghi), chúng thực sự được hỗ trợ bởi một tập hợp lớn hơn nhiều (ví dụ: 64-256). Sau đó, CPU theo dõi khả năng hiển thị của từng thanh ghi và phân bổ chúng cho tập hợp đã đổi tên. Ví dụ: bạn có thể tải, sửa đổi, sau đó lưu trữ vào một thanh ghi nhiều lần liên tiếp và mỗi hoạt động này thực sự được thực hiện độc lập tùy thuộc vào các lần bỏ sót bộ nhớ cache, v.v. Trong ARM:
ldr r0, [r4]
add r0, r0, #1
str r0, [r4]
ldr r0, [r5]
add r0, r0, #1
str r0, [r5]
Các lõi Cortex A9 thực hiện đổi tên thanh ghi, vì vậy lần tải đầu tiên đến "r0" thực sự chuyển đến một thanh ghi ảo đã được đổi tên - hãy gọi nó là "v0". Việc tải, tăng và lưu trữ xảy ra trên "v0". Trong khi đó, chúng tôi cũng thực hiện tải / sửa đổi / lưu trữ thành r0 một lần nữa, nhưng điều đó sẽ được đổi tên thành "v1" vì đây là một chuỗi hoàn toàn độc lập sử dụng r0. Giả sử tải từ con trỏ trong "r4" bị đình trệ do lỗi bộ nhớ cache. Không sao cả - chúng ta không cần đợi "r0" sẵn sàng. Bởi vì nó được đổi tên, chúng tôi có thể chạy chuỗi tiếp theo với "v1" (cũng được ánh xạ đến r0) - và có lẽ đó là một lần truy cập bộ nhớ cache và chúng tôi vừa có một chiến thắng hiệu suất lớn.
ldr v0, [v2]
add v0, v0, #1
str v0, [v2]
ldr v1, [v3]
add v1, v1, #1
str v1, [v3]
Tôi nghĩ rằng x86 ngày nay có một số lượng khổng lồ các đăng ký được đổi tên (ballpark 256). Điều đó có nghĩa là có 8 bit nhân 2 cho mỗi lệnh chỉ để nói nguồn và đích là gì. Nó sẽ làm tăng số lượng dây cần thiết trên lõi và kích thước của nó. Vì vậy, có một điểm thú vị xung quanh 16-32 thanh ghi mà hầu hết các nhà thiết kế đã giải quyết và đối với các thiết kế CPU không theo thứ tự, đổi tên thanh ghi là cách để giảm thiểu nó.
Chỉnh sửa : Tầm quan trọng của việc thực hiện không theo thứ tự và đăng ký đổi tên về điều này. Khi bạn đã có OOO, số lượng thanh ghi không quan trọng lắm, vì chúng chỉ là "thẻ tạm thời" và được đổi tên thành tập thanh ghi ảo lớn hơn nhiều. Bạn không muốn số lượng quá nhỏ, vì sẽ khó viết các chuỗi mã nhỏ. Đây là một vấn đề đối với x86-32, bởi vì 8 thanh ghi hạn chế có nghĩa là rất nhiều thời gian tạm thời kết thúc qua ngăn xếp và lõi cần thêm logic để chuyển tiếp đọc / ghi vào bộ nhớ. Nếu bạn không có OOO, bạn thường nói về một lõi nhỏ, trong trường hợp đó, một bộ thanh ghi lớn là một lợi ích về chi phí / hiệu suất kém.
Vì vậy, có một điểm ngọt ngào tự nhiên cho kích thước ngân hàng thanh ghi, tối đa là khoảng 32 thanh ghi được tạo ra cho hầu hết các loại CPU. x86-32 có 8 thanh ghi và nó chắc chắn quá nhỏ. ARM đã đi với 16 đăng ký và đó là một sự thỏa hiệp tốt. 32 đăng ký là hơi quá nhiều nếu có - cuối cùng bạn không cần 10 cuối cùng hoặc lâu hơn.
Điều này không liên quan đến các thanh ghi bổ sung mà bạn nhận được cho SSE và các bộ đồng xử lý dấu chấm động vectơ khác. Chúng có ý nghĩa như một tập hợp bổ sung vì chúng chạy độc lập với lõi số nguyên và không làm tăng độ phức tạp của CPU theo cấp số nhân.