Tôi đã luôn tự hỏi tại sao bộ xử lý dừng lại ở 32 thanh ghi. Đây là phần nhanh nhất của máy, tại sao không tạo ra bộ xử lý lớn hơn với nhiều thanh ghi hơn? Điều đó có nghĩa là sẽ ít đi RAM hơn?
Tôi đã luôn tự hỏi tại sao bộ xử lý dừng lại ở 32 thanh ghi. Đây là phần nhanh nhất của máy, tại sao không tạo ra bộ xử lý lớn hơn với nhiều thanh ghi hơn? Điều đó có nghĩa là sẽ ít đi RAM hơn?
Câu trả lời:
Đầu tiên, không phải tất cả các kiến trúc bộ xử lý dừng lại ở 32 thanh ghi. Hầu như tất cả các kiến trúc RISC có 32 thanh ghi được hiển thị trong tập lệnh thực sự có 32 thanh ghi nguyên và thêm 32 thanh ghi dấu phẩy động (vì vậy 64). (Dấu phẩy động "thêm" sử dụng các thanh ghi khác với số nguyên "thêm".) Kiến trúc SPARC có các cửa sổ đăng ký. Trên SPARC, bạn chỉ có thể truy cập 32 thanh ghi số nguyên cùng một lúc, nhưng các thanh ghi hoạt động như một ngăn xếp và bạn có thể đẩy và bật các thanh ghi mới 16 tại một thời điểm. Kiến trúc Itanium của HP / Intel có 128 số nguyên và 128 thanh ghi dấu phẩy động được hiển thị trong tập lệnh. Các GPU hiện đại của NVidia, AMD, Intel, ARM và Imagination Technologies, tất cả đều phơi bày số lượng lớn các thanh ghi trong các tệp đăng ký của chúng. (Tôi biết điều này đúng với kiến trúc của NVidia và Intel, tôi không rành lắm về các tập lệnh AMD, ARM và Tưởng tượng, nhưng tôi nghĩ rằng các tệp đăng ký cũng lớn ở đó.)
Thứ hai, hầu hết các bộ vi xử lý hiện đại đều thực hiện đổi tên thanh ghi để loại bỏ việc xê-ri hóa không cần thiết do cần sử dụng lại tài nguyên, vì vậy các tệp thanh ghi vật lý cơ bản có thể lớn hơn (các thanh ghi 96, 128 hoặc 192 trên một số máy.) Điều này (và lập lịch trình động) loại bỏ một số cần cho trình biên dịch để tạo ra rất nhiều tên đăng ký duy nhất, trong khi vẫn cung cấp một tệp đăng ký lớn hơn cho bộ lập lịch.
Có hai lý do tại sao có thể khó tăng thêm số lượng thanh ghi được hiển thị trong tập lệnh. Trước tiên, bạn cần có khả năng chỉ định các định danh đăng ký trong mỗi hướng dẫn. 32 thanh ghi yêu cầu một bộ xác định thanh ghi 5 bit, vì vậy các lệnh 3 địa chỉ (phổ biến trên các kiến trúc RISC) dành 15 trong số 32 bit lệnh chỉ để chỉ định các thanh ghi. Nếu bạn tăng nó lên 6 hoặc 7 bit, thì bạn sẽ có ít không gian hơn để chỉ định opcodes và hằng. GPU và Itanium có hướng dẫn lớn hơn nhiều . Các hướng dẫn lớn hơn có chi phí: bạn cần sử dụng nhiều bộ nhớ lệnh hơn, do đó hành vi bộ đệm hướng dẫn của bạn ít lý tưởng hơn.
Lý do thứ hai là thời gian truy cập. Bạn càng tạo ra bộ nhớ càng lớn thì việc truy cập dữ liệu từ nó càng chậm. (Chỉ xét về mặt vật lý cơ bản: dữ liệu được lưu trữ trong không gian 2 chiều, vì vậy nếu bạn đang lưu trữ bit, khoảng cách trung bình đến một bit cụ thể là .) Tệp đăng ký chỉ là một bộ nhớ đa cổng nhỏ và một trong những hạn chế của việc làm cho nó lớn hơn là cuối cùng bạn sẽ cần bắt đầu đồng hồ máy của mình chậm hơn để chứa tệp đăng ký lớn hơn. Thông thường về tổng hiệu suất thì đây là một mất mát. O ( √
Chỉ hai lý do nữa để giới hạn số lượng đăng ký:
Rất nhiều mã có nhiều truy cập bộ nhớ (30% là một con số điển hình). Trong số đó, thông thường khoảng 2/3 là truy cập đọc và 1/3 là truy cập ghi. Điều này không phải là do hết đăng ký nhiều như truy cập mảng, truy cập các biến thành viên đối tượng, v.v.
Điều này phải được thực hiện trong bộ nhớ (hoặc bộ đệm dữ liệu) do cách tạo C / C ++ (mọi thứ bạn có thể nhận được một con trỏ cần phải có một địa chỉ phải được lưu trong bộ nhớ). Nếu trình biên dịch có thể đoán rằng bạn sẽ không ghi vào các biến willy-nilly bằng các thủ thuật con trỏ gián tiếp điên rồ, nó sẽ đưa chúng vào các thanh ghi, và điều này hoạt động rất tốt cho các biến chức năng nhưng không phải cho các biến có thể truy cập toàn cầu (nói chung, mọi thứ xuất phát từ malloc ()) bởi vì về cơ bản không thể đoán được trạng thái toàn cầu sẽ thay đổi như thế nào.
Bởi vì điều này, không phổ biến rằng trình biên dịch sẽ có thể làm bất cứ điều gì với hơn 16 thanh ghi sử dụng chung dù sao đi nữa. Đó là lý do tại sao tất cả các kiến trúc phổ biến có nhiều về điều đó (ARM có 16).
MIPS và các RISC khác có xu hướng có 32 vì không khó để có nhiều đăng ký - chi phí đủ thấp nên có một chút "tại sao không?". Hơn 32 phần lớn là vô dụng và có nhược điểm là làm cho tệp đăng ký dài hơn để truy cập (mỗi lần nhân đôi số lượng thanh ghi có khả năng thêm một lớp ghép kênh bổ sung thêm một chút chậm trễ ...). Nó cũng làm cho các lệnh trung bình dài hơn một chút - có nghĩa là khi chạy loại chương trình phụ thuộc vào băng thông bộ nhớ lệnh, các thanh ghi bổ sung của bạn thực sự làm bạn chậm lại!
Nếu cpu của bạn theo thứ tự và không đăng ký đổi tên và bạn đang cố gắng thực hiện nhiều thao tác trên mỗi chu kỳ (hơn 3), thì theo lý thuyết, bạn cần nhiều đăng ký hơn khi số lượng op của mỗi chu kỳ tăng lên. Đây là lý do tại sao Itanium có rất nhiều đăng ký! Nhưng trong thực tế, ngoài mã định hướng số nổi hoặc SIMD (mà Itanium thực sự giỏi), hầu hết các mã sẽ có rất nhiều bộ nhớ đọc / ghi và nhảy khiến cho giấc mơ này có nhiều hơn 3 op mỗi chu kỳ (đặc biệt là trong các phần mềm hướng máy chủ như cơ sở dữ liệu, trình biên dịch, thực thi ngôn ngữ cấp cao như javascript, mô phỏng, v.v.). Đây là những gì đã đánh chìm Itanium.
Tất cả là do sự khác biệt giữa tính toán và thực thi!
Ai nói với bạn rằng bộ xử lý luôn có 32 thanh ghi? x86 có 8, ARM 32-bit và x86_64 có 16, IA-64 có 128 và nhiều số khác. Bạn có thể có một cái nhìn ở đây . Ngay cả MIPS, PPC hoặc bất kỳ kiến trúc nào có 32 thanh ghi mục đích chung trong tập lệnh, số này lớn hơn 32 vì vẫn luôn có các thanh ghi cờ (nếu có), các thanh ghi điều khiển ... không bao gồm các thanh ghi được đổi tên và các thanh ghi phần cứng
Mọi thứ đều có giá của nó. Số lượng thanh ghi càng lớn, bạn càng có nhiều công việc khi thực hiện chuyển đổi tác vụ, bạn càng cần nhiều không gian hơn trong mã hóa lệnh. Nếu bạn có ít đăng ký hơn, bạn không phải lưu trữ và khôi phục nhiều khi gọi và trả lại từ các chức năng hoặc chuyển đổi các tác vụ với việc không có các thanh ghi trong một số mã mở rộng tính toán
Hơn nữa, tập tin đăng ký càng lớn, nó sẽ càng tốn kém và phức tạp. SRAM là RAM nhanh nhất và đắt nhất vì vậy nó chỉ được sử dụng trong bộ đệm CPU. Nhưng nó vẫn rẻ hơn nhiều và chiếm ít diện tích hơn một tệp đăng ký có cùng dung lượng.
Ví dụ, bộ xử lý Intel điển hình có "chính thức" 16 số nguyên và 16 thanh ghi vector. Nhưng trong thực tế, có nhiều hơn nữa: Bộ xử lý sử dụng "đăng ký đổi tên". Nếu bạn có một lệnh reg3 = reg1 + reg2, bạn sẽ gặp vấn đề nếu một lệnh khác sử dụng reg3 chưa kết thúc - bạn không thể thực hiện lệnh mới trong trường hợp nó ghi đè lên reg3 trước khi nó được đọc bởi lệnh trước đó.
Do đó, có khoảng 160 hoặc hơn đăng ký thực sự . Vì vậy, hướng dẫn đơn giản ở trên được thay đổi thành "regX = reg1 + reg2 và hãy nhớ rằng regX chứa reg3". Nếu không đổi tên các thanh ghi, việc thực hiện ngoài trật tự sẽ hoàn toàn chết trong nước.
Tôi không phải là kỹ sư điện, nhưng tôi nghĩ một khả năng khác vì lý do giới hạn số lượng thanh ghi, là định tuyến. Có một số lượng hạn chế các đơn vị số học, và chúng phải có thể lấy đầu vào từ mỗi thanh ghi, và đầu ra cho mỗi thanh ghi. Điều này đặc biệt đúng khi bạn có các chương trình đường ống có thể thực hiện nhiều lệnh trong mỗi chu kỳ.
Một phiên bản đơn giản này sẽ có độ phức tạp , làm tăng số lượng thanh ghi không thể quét được, hoặc nếu không yêu cầu thiết kế lại định tuyến đến một thứ gì đó phức tạp hơn nhiều để định tuyến mọi thứ với độ phức tạp tốt hơn.
Tôi có ý tưởng cho câu trả lời này khi xem một số cuộc nói chuyện của Ivan Godard trên CPU Mill. Một phần của sự đổi mới của CPU Mill là bạn không thể xuất ra các thanh ghi tùy ý - tất cả các đầu ra được đẩy vào ngăn xếp thanh ghi hoặc "vành đai", do đó làm giảm các vấn đề định tuyến, bởi vì bạn luôn biết đầu ra sẽ đi đâu. Lưu ý rằng họ vẫn có vấn đề định tuyến để nhận các thanh ghi đầu vào cho các đơn vị số học.
Xem Kiến trúc CPU Mill - Vành đai (2 trên 9) để biết báo cáo sự cố và giải pháp của Mill.
Đối với MIPS ISA, Hennessy và Patterson, Tổ chức máy tính và Thiết kế phiên bản thứ 4 p. 176, trả lời trực tiếp câu hỏi cụ thể này:
Nhỏ hơn là nhanh hơn. Mong muốn về tốc độ là lý do mà MIPS có 32 thanh ghi chứ không phải nhiều hơn nữa.