Những phụ thuộc điều khiển

Một phần của tài liệu Kiến trúc máy tính tiên tiến (Trang 55 - 58)

KHỐI XỬ LÝ SONG SONG Ở MỨC LỆNH MÁY

2.1. Kỹ thuật đường ống và xử lý song song ở mức lệnh máy

2.1.2. Các khó khăn khi sử dụng đường ống và cách khắc phục

2.1.2.3. Những phụ thuộc điều khiển

Loại cuối cùng của sự phụ thuộc là sự phụ thuộc điều khiển. Một phụ thuộc điều khiển quyết định trật tự của một lệnh, i, đối với một nhánh lệnh thì lệnh i được thực hiện theo trật tự chương trình đúng và chỉ khi nó cần. Mọi lệnh, ngoại trừ những lệnh trong khối cơ bản đầu tiên của chương trình, là phụ thuộc điều khiển vào một số tập nhánh và, nói chung, những phụ thuộc điều khiển này phải được bảo toàn để đảm bảo trật tự chương trình. Một trong những ví dụ đơn giản nhất về một sự phụ thuộc điều khiển là sự phụ thuộc của những câu lệnh trong phần “then” của câu lệnh if trong nhánh. Ví dụ, trong đoạn mã sau đây:

If p1 { S1;

};

If p2 { S2;

}

S1 là điều khiển phụ thuộc vào p1 và S2 là điều khiển phụ thuộc vào p2 nhưng không phải p1. Nói chung, có hai điều kiện ràng buộc được áp đặt bởi những phụ thuộc điều khiển:

1. Một lệnh là điều khiển phụ thuộc vào một nhánh không thể di chuyển trước nhánh để việc thi hành nó không còn được điều khiển bởi nhánh. Ví dụ, chúng ta không thể lấy một lệnh từ phần then của một câu lệnh if và di chuyển nó trước câu lệnh if.

2. Một lệnh không phải là điều khiển phụ thuộc vào một nhánh không thể di chuyển sau nhánh để việc thi hành của nó được điều khiển bởi nhánh. Ví dụ, chúng tôi không thể lấy một câu lệnh trước câu lệnh if và di chuyển nó vào phần then.

Khi những bộ xử lý đảm bảo trật tự chương trình nghiêm ngặt, chúng đảm bảo những phụ thuộc điều khiển cũng được bảo toàn. Chúng ta có thể thực hiện các lệnh không nên được thực hiện, tuy nhiên, cách đó vi phạm các phụ thuộc điều khiển, nếu chúng ta có thể làm như vậy mà không ảnh hưởng đến tính đúng đắn của chương trình. Phụ thuộc điều khiển không phải là đặc tính quan trọng mà phải được bảo đảm. Thay vào đó, hai đặc tính quan trọng đối với sự đúng đắn của chương trình - và thường được đảm bảo bằng việc duy trì sự phụ thuộc dữ liệu và điều khiển - là những trạng thái ngoại lệ và là dòng dữ liệu.

Việc bảo đảm các trạng thái ngoại lệ có nghĩa là bất kỳ thay đổi trong trật tự của việc thi hành lệnh cũng không làm thay đổi những ngoại lệ được nêu lên trong chương trình. Một cách dễ hiểu điều này nghĩa là việc sắp xếp lại thứ tự thi hành lệnh không gây ra bất kỳ trường hợp ngoại lệ mới trong chương trình. Một ví dụ đơn giản cho thấy cách duy trì những phụ thuộc điều khiển và dữ liệu có thể ngăn ngừa những tình huống như vậy. Hãy xem xét đoạn mã này:

DADDU R2, R3, R4 BEQZ R2, L1 LW R1, 0 (R2) L1:

Trong trường hợp này, dễ thấy rằng nếu chúng ta không duy trì sự phụ thuộc dữ liệu liên quan đến R2, chúng ta có thể thay đổi kết quả của chương trình. Chỉ lệnh nạp vào này có thể gây ra một ngoại lệ bảo vệ bộ nhớ. Chú ý rằng không có sự phụ thuộc dữ liệu nào ngăn cản chúng ta khỏi việc hoán đổi giữa BEQZ và LW, chỉ có sự phụ thuộc điều khiển. Để cho phép chúng ta sắp xếp lại các lệnh này (và vẫn bảo toàn được sự phụ thuộc dữ liệu), chúng ta chỉ cần bỏ qua những trường hợp ngoại lệ khi nhánh được thực hiện. Trong mục 2.6, chúng ta sẽ xem xét một kỹ thuật phần cứng, sự tích lũy, cho phép chúng ta khắc phục vấn đề ngoại lệ này.

Thuộc tính thứ hai được bảo toàn bằng cách duy trì phụ thuộc dữ liệu và phụ thuộc điều khiển là dòng dữ liệu. Dòng dữ liệu là lưu lượng thực tế của những giá trị dữ liệu trong số các lệnh dùng để đưa ra các kết quả và sử dụng chúng. Những nhánh tạo ra dòng dữ liệu động, vì chúng cho phép nguồn dữ liệu cho một chỉ lệnh được đưa ra đến từ nhiều điểm. Nói cách khác, nó không đủ để duy trì sự phụ thuộc dữ liệu vì một lệnh có thể là dữ liệu phụ thuộc vào nhiều hơn một sự việc xảy ra trước. Trật tự chương trình thì quyết định biến cố trước đó sẽ thực sự mang lại một giá trị dữ liệu nào đó cho một lệnh. Trật tự chương trình được đảm bảo bằng việc duy trì những phụ thuộc điều khiển.

Ví dụ, hãy xem xét các đoạn mã sau:

DADDU R1, R2, R3 BEQZ R4, L DSUBU R1, R5, R6 L: ...

OR R7, R1, R8

Trong ví dụ này, giá trị của R1 được sử dụng bởi lệnh OR phụ thuộc vào việc liệu nhánh này có được thực hiện hay không. Một mình phụ thuộc dữ liệu là không đủ để bảo toàn được tính đúng đắn. Lệnh OR ở đây là dữ liệu phụ thuộc

vào cả lệnh DADDU và DSUBU, nhưng bảo đảm một mình trật tự là không đủ cho việc thực hiện đúng.

Thay vào đó, khi những chỉ lệnh thực hiện, dòng dữ liệu phải được bảo toàn:

Nếu nhánh là không thực hiện, thì giá trị của R1 được tính toán bởi DSUBU sẽ được sử dụng bởi OR và nếu nhánh được thực hiện, thì giá trị của R1 được tính toán bởi DADDU sẽ được sử dụng bởi OR. Bằng cách đảm bảo sự phụ thuộc điều khiển của OR trên nhánh, chúng ta sẽ ngăn chặn sự thay đổi bất hợp pháp đến dòng chảy dữ liệu. Vì những lý do tương tự, lệnh DSUBU không thể di chuyển lên trên nhánh.

Sự tích lũy cũng sẽ cho phép chúng ta giảm bớt ảnh hưởng của sự phụ thuộc điều khiển, trong khi vẫn duy trì dòng dữ liệu, như chúng ta sẽ thấy trong mục 2.6.

Đôi khi chúng ta có thể xác định rằng sự vi phạm phụ thuộc điều khiển thì không thể ảnh hưởng đến trạng thái ngoại lệ hoặc dòng dữ liệu. Xét đoạn mã sau:

DADDU R1, R2, R3 BEQZ R12, skip DSUBU R4, R5, R6 DADDU R5, R4, R9 skip: OR R7, R8, R9

Giả sử chúng ta biết rằng đích đến thanh ghi của lệnh DSUBU (R4) không được sử dụng sau lệnh được gán skip (thuộc tính của việc liệu một giá trị sẽ được sử dụng bởi một chỉ lệnh sắp tới hay không được gọi là liveness). Nếu R4 không sử dụng, thì việc thay đổi giá trị của R4 ngay trước nhánh sẽ không ảnh hưởng đến dòng dữ liệu vì R4 sẽ biến mất (chứ không tồn tại) trong vùng mã sau skip. Vì vậy, nếu R4 biến mất và lệnh DSUBU tồn tại không thể tạo ra một ngoại lệ (khác với những gì mà bộ xử lý tiếp tục cùng một tiến trình từ nó), chúng ta có thể di chuyển lệnh DSUBU trước nhánh, vì dòng dữ liệu không thể bị ảnh hưởng bởi thay đổi này.

Nếu nhánh này được thực hiện, lệnh DSUBU sẽ thực hiện và sẽ vô dụng, nhưng nó sẽ không ảnh hưởng đến kết quả chương trình. Loại mã lập lịch cũng là một hình thức tích lũy, thường được gọi là phần mềm tích lũy, vì trình biên dịch sẽ đánh giá hiệu quả nhánh; trong trường hợp này, việc đánh giá này nghĩa là nhánh này thường không được thực hiện. Thông thường, nó sẽ rõ ràng khi chúng ta nói rằng cơ chế của sự tích lũy là cơ chế phần cứng hay phần mềm; khi nó không rõ ràng, tốt nhất là nói "tích lũy phần cứng" hoặc "tích lũy phần mềm".

Sự phụ thuộc điều khiển được đảm bảo bằng cách thực hiện việc kiểm tra rủi ro điều khiển mà gây ra những trì hoãn điều khiển. Những trì hoãn điều khiển có thể được loại bỏ hoặc giảm bớt bằng những kỹ thuật phần cứng và phần mềm khác nhau, chúng ta sẽ kiểm tra tại mục 2.3.

Một phần của tài liệu Kiến trúc máy tính tiên tiến (Trang 55 - 58)

Tải bản đầy đủ (PDF)

(260 trang)