c, Liên kết thông qua stack
5.1.4. Nhóm lệnh dịch chuyển của dữ liệu
Thực chất vấn đề biên dịch câu lệnh của nhóm lệnh dịch chuyển dữ liệu chính là việc chuyển việc sử dụng các biến số và hằng số có trong ngôn ngữ bậc cao sang vị trí một ô nhớ trong hợp ngữ. Vấn đề này đã được giải quyết trong phần 5.1.3. bằng cách sử dụng stack và thanh ghi %fp để lưu trữ các biến số. Trong phần này, chúng ta sẽ bàn kỹ hơn một chút về vấn đề sử dụng các biến mà kiểu biến được định nghĩa bởi người sử dụng
Biến dạng cấu trúc
Trong ngôn ngữ C, ta có kiểu biến mà người sử dụng định nghĩa, đó là kiểu struct hay là kiểu record trong Pascal
Xem xét kiểu struct trong C, ta lấy ví dụ về kiểu struct này với dữ liệu
được định nghĩa là kiểu point với cấu trúc như sau Struct point {
Int x; Int y; Int z; }
Biến (có tên là điểm A) sử dụng cấu trúc trên được khai báo trong C như sau Struct point diemA ;
Với cách định nghĩa trên, người dùng có thể truy cập vào từng phần tử của biến diemA bằng toán tử dấu chấm quen thuộc diemA.x.
Đối với việc biên dịch sang ngôn ngữ hợp ngữ, trình biên dịch sẽ phải tạo ra các ô nhớ tương ứng với cấu trúc point. Với việc khai báo biến diemA có cấu trúc trên, trình biên dịch sẽ tạo ra một “biến”-một ô nhớ có tên là diemA. Biến diemA.x sẽ tương ứng với ô nhớ [diemA], biến diemA.y tương ứng [diemA + 4], biến diemA.z tương ứng [diemA + 8] . Do đó, câu lệnh
để nạp biến y vào thanh ghi %r1 sẽ là ld [diemA + 4], %r1
Biến dạng mảng
Hầu hết các ngôn ngữ lập trình đều cung cấp kiểu dữ liệu mảng array. Trong ngôn ngữ C, để định nghĩa mảng A gồm 10 phần tử kiểu int ta sử dụng câu lệnh
Int A[10];
Khi đó, C sẽ tạo ra một chuỗi phần tử kiểu int có cùng tên là A và được gán các chỉ số từ 0 đến 9 để phân biệt
Hợp ngữ truy cập các phần tử trong mảng hoàn toàn tương tự như đối với cấu trúc struct. Có nghĩa là phần tửA[3] sẽ được lưu tại vị trí [A + 12] (Lưu ý rằng phần tử đầu tiên của mảng A có chỉ số là 0)
Trong ngôn ngữ Pascal, mảng được khai báo
A : array [-10..10] of integer ;
Cách khai báo như trên được chấp nhận. Khi đó, Pascal tạo ra mảng A gồm 21 phần tử kiểu int có chỉ số từ -10 đến 10
Việc biên dịch ngôn ngữ Pascal do đó phức tạp hơn so với C bởi hợp ngữ cũng có chỉ số bắt đầu từ 0. Để tính được phần tử A[i] bất kỳ, ta sử dụng công thức chuyển đổi
Địa chỉ phần tử i = Địa chỉ cơ sở + (Chỉ số - Chỉ số bắt đầu) * Size Với khai báo như trên, để nạp phần tử A[5] vào thanh ghi %r1 ta phải biên dịch thành chuỗi lệnh sau Ld %r0, 5, %r3 Ld %r0, -10, %r4 Sub %r3, %r4, %r6 Sll %r6, 2, %r6 Ld [A + %r6], %r1 5.1.5. Các lệnh toán học
Các lệnh toán học được biên dịch rất đơn giản vì các phép toán được thể hiện trong ngôn ngữ bậc cao đều có câu lệnh hợp ngữ tương ứng. Quá trình biên dịch chỉ có một chút phức tạp đối với máy tính dạng load-store như máy tính ARC
hoặc các máy tính dựa trên kiến trúc RISC. Với máy tính này, phép toán trước khi được thực hiện, các toán hạng phải được đưa vào các thanh ghi. Mặc dù số
lượng các thanh ghi trong máy tính luôn luôn tăng lên trong lịch sử phát triển, tuy nhiên vẫn luôn có trường hợp số lượng thanh ghi cần sử dụng lớn hơn số
lượng thanh ghi mà máy tính có. Trong trường hợp này, trình biên dịch sẽ tạm thời lưu trữ các biến trong bộ nhớ stack, kỹ thuật này còn có tên là register spill. Khi đó, trình biên dịch sẽ sử dụng một kỹ thuật phức tạp có tên là register coloring để quyết định sẽ tiếp tục lưu trữ thanh ghi nào, và nội dung thanh ghi nào sẽ phải được lưu trữ trên bộ nhớ stack để nhường thanh ghi đó cho một biến khác, thậm chí, kỹ thuật register coloring còn có khả năng xác định xem có cần thiết phải lưu lại một nội dung của một thanh ghi nữa hay không