2012-06-04 14 views
5

tôi biên soạn mã C sau:về mã gcc-biên soạn x86_64 và tối ưu hóa mã C

typedef struct { 
    long x, y, z; 
} Foo; 

long Bar(Foo *f, long i) 
{ 
    return f[i].x + f[i].y + f[i].z; 
} 

với lệnh gcc -S -O3 test.c. Đây là chức năng Bar trong đầu ra:

.section __TEXT,__text,regular,pure_instructions 
    .globl _Bar 
    .align 4, 0x90 
_Bar: 
Leh_func_begin1: 
    pushq %rbp 
Ltmp0: 
    movq %rsp, %rbp 
Ltmp1: 
    leaq (%rsi,%rsi,2), %rcx 
    movq 8(%rdi,%rcx,8), %rax 
    addq (%rdi,%rcx,8), %rax 
    addq 16(%rdi,%rcx,8), %rax 
    popq %rbp 
    ret 
Leh_func_end1: 

Tôi có một số câu hỏi về mã lắp ráp này:

  1. mục đích "pushq %rbp", "movq %rsp, %rbp", và "popq %rbp" là gì, nếu không phải rbp cũng không phải rsp được sử dụng trong phần thân của hàm?
  2. Tại sao rsirdi tự động chứa đối số cho hàm C (if tương ứng) mà không đọc chúng từ ngăn xếp?
  3. Tôi đã thử tăng kích thước của Foo lên 88 byte (11 long s) và hướng dẫn leaq trở thành imulq. Nó sẽ làm cho tinh thần để thiết kế cấu trúc của tôi để có kích thước "tròn" để tránh các hướng dẫn nhân (để tối ưu hóa truy cập mảng)? Các hướng dẫn leaq được thay thế bằng:

    imulq $88, %rsi, %rcx 
    

Trả lời

7
  1. Chức năng chỉ đơn giản là tạo khung ngăn xếp của riêng mình bằng các hướng dẫn này. Không có gì thực sự khác thường về chúng. Tuy nhiên, bạn nên lưu ý rằng do kích thước nhỏ của hàm này, nó có thể sẽ được gạch chân khi được sử dụng trong mã. Trình biên dịch luôn được yêu cầu để tạo ra một phiên bản "bình thường" của hàm này. Ngoài ra, những gì @ouah nói trong câu trả lời của mình.

  2. Điều này là do đó là cách AMD64 ABI chỉ định các đối số nên được chuyển đến các hàm.

    Nếu lớp là INTEGER, thanh ghi có sẵn tiếp theo của chuỗi % rdi,% rsi,% rdx,% rcx,% r8 và% r9 được sử dụng.

    Trang 20, AMD64 ABI dự thảo 0.99.5 - ngày 03 tháng 9 2010

  3. Đây không phải là trực tiếp liên quan đến kích thước cấu trúc, chứ không phải - địa chỉ tuyệt đối rằng chức năng có truy cập. Nếu kích thước của cấu trúc là 24 byte, f là địa chỉ của mảng chứa cấu trúc và i là chỉ mục mà mảng đó phải được truy cập, sau đó bù đắp byte cho mỗi cấu trúc là i*24.Nhân với 24 trong trường hợp này được thực hiện bằng cách kết hợp lea và địa chỉ SIB. Lệnh lea đầu tiên chỉ cần tính toán i*3, sau đó mọi lệnh tiếp theo sử dụng i*3 và nhân nó thêm 8, do đó truy cập mảng tại độ lệch byte tuyệt đối cần thiết và sau đó sử dụng chuyển vị ngay lập tức để truy cập các thành viên cấu trúc riêng lẻ ((%rdi,%rcx,8). 8(%rdi,%rcx,8)) 16(%rdi,%rcx,8)). Nếu bạn thực hiện kích thước của cấu trúc 88 byte, đơn giản là không có cách nào để thực hiện một điều nhanh như vậy với sự kết hợp của lea và bất kỳ loại địa chỉ nào. Trình biên dịch chỉ đơn giản giả định rằng một đơn giản imull sẽ hiệu quả hơn khi tính toán i*88 so với một loạt các thay đổi, bổ sung, lea s hoặc bất kỳ thứ gì khác.

+0

Tôi đã đăng mã tôi nhận được. – Matt

+0

Có, tôi biết tất cả điều đó. Câu hỏi của tôi là nó có giá trị đệm cấu trúc với không gian thêm chỉ để làm cho nó một số "tròn" (như 12 longs thay vì 11 longs) mà sẽ tránh sử dụng một nhân trong tính toán chỉ số mảng? – Matt

+1

@Matt: không ai có thể trả lời rằng nói chung - padding không đến miễn phí hoặc (kích thước bộ nhớ cache); đừng đoán, đo! – Christoph

2
  1. mục đích pushq% RBP, movq% RSP,% RBP, và popq% RBP là gì, nếu không phải RBP cũng không RSP được sử dụng trong cơ thể của hàm?

Để theo dõi các khung khi bạn sử dụng trình gỡ lỗi. Thêm để tối ưu hóa (lưu ý rằng nó phải được kích hoạt tại -O3 nhưng trong nhiều phiên bản gcc tôi đã sử dụng nó không phải là).

0
3. I tried increasing the size of Foo to 88 bytes (11 longs) and the leaq instruction became an imulq. Would it make sense to design my structs to have "rounder" sizes to avoid the multiply instructions (in order to optimize array access)? 

Cuộc gọi leaq là (cơ bản và trong CAE này) tính toán k * a + b ở đâu "k" là 1, 2, 4, hoặc 8 và "a" và "b" là thanh ghi . Nếu "a" và "b" giống nhau, nó có thể được sử dụng cho các cấu trúc 1, 2, 3, 4, 5, 8 và 9.

Cấu trúc lớn hơn như 16 longs có thể được tối ưu hóa bằng cách tính toán độ lệch với "k" và tăng gấp đôi, nhưng tôi không biết đó có phải là trình biên dịch thực sự làm hay không; bạn sẽ phải kiểm tra.

+0

Tôi đã thử nó với mười hai và nó tối ưu hóa nó. ("' leaq (% rsi,% rsi, 2),% rcx' "và sau đó" 'shlq $ 5,% rcx'") Nhưng câu hỏi của tôi là nó có giá trị tăng kích thước cho phép nói từ 88 đến 96 chỉ để tránh nhân trong khi truy cập mảng (giả sử tôi sẽ thực hiện rất nhiều truy cập mảng). – Matt

+1

Ah, xin lỗi. Nếu bộ nhớ kém quan trọng hơn hiệu suất và bạn có thể tự tin rằng imul sẽ được tránh, sau đó có, tôi sẽ. (Chèn ở đây tuyên bố từ chối trách nhiệm chuẩn về việc tối ưu hóa trước và thử nghiệm để xác minh.) – DocMax