Смещение адреса в инструкции загрузки RIS C -V жестко запрограммировано или нет? - PullRequest
0 голосов
/ 28 мая 2020

В образовательных целях я использовал https://godbolt.org/z/7F-Lhm для перевода

// C++ code
char i = 3;
char A[] = {0,1,2,3,4,5};  
int myfunction() {
    return A[i];
}

в

# RISC-V instructions 
myfunction():                        # @myfunction()
        lui     a0, %hi(i)
        lbu     a0, %lo(i)(a0)
        lui     a1, %hi(A)
        addi    a1, a1, %lo(A)
        add     a0, a0, a1
        lbu     a0, 0(a0)
        ret
i:
        .byte   3                       # 0x3

A:
        .ascii  "\000\001\002\003\004\005"

Но почему A[i] загружается с add a0, a0, a1, lbu a0, 0(a0), а не только с lbu a0, a0(a1)?

Было бы разумно, если бы для lbu dest, offset(baseAdress) только dest и baseAdresse могли быть зарегистрированными адресами, тогда как offset - это жестко запрограммированное число в само слово инструкции. Но в том же коде, приведенном выше, я вижу lbu a0, %lo(i)(a0), так что offset, по-видимому, также может быть «несколько изменчивым»?

Может быть, я не понимаю этого, потому что я действительно не понимаю, почему это $hi $lo вещь нужна в первую очередь. Почему мы делаем lui a0, %hi(i), lbu a0, %lo(i)(a0) вместо lbu a0, 0(i)?

Ответы [ 2 ]

1 голос
/ 28 мая 2020

Как сказал Эрик Эйдт, i - глобальная переменная, т.е. находится где-то в 32/64-битной адресуемой памяти и может измениться в любое время.

32/64-битный адрес i загружается двумя частями, так как 32/64-битный адрес не может быть закодирован сразу. %hi(i) и %lo(i) - это верхняя и нижняя части адреса из i. i загружается из памяти, так как он мог измениться между вызовами myfunction ().

1 голос
/ 28 мая 2020

и не только с lbu a0, a0 (a1)?

RIS C V (и MIPS) не имеют режима адресации базовый регистр + базовый регистр - они оба имеют только один, и это базовый регистр + немедленный.

Таким образом, операция регистр + регистр, необходимая для A + i, должна выполняться отдельной инструкцией добавления.

вместо простого lbu a0, 0 (i)?

В 32-битной инструкции недостаточно места для хранения адреса глобального, поэтому используются несколько инструкций.


Вы объявили переменные как глобальные, поэтому часть этого кода касается доступа к глобальным переменным.

myfunction():                        # @myfunction()
        lui     a0, %hi(i)      <--- 1st part of 2 instructions for the char i global
        lbu     a0, %lo(i)(a0)  <--- 2nd instruction for fetching the char i global
        lui     a1, %hi(A)      <--- 1st part of 2 instructions for A global array
        addi    a1, a1, %lo(A)  <--- 2nd instruction for fetching addr of A global

        add     a0, a0, a1      <--- the array indexing A + i
        lbu     a0, 0(a0)       <--- the dereference *(A+i)
        ret
i:
        .byte   3                       # 0x3

A:
        .ascii  "\000\001\002\003\004\005"

Если вы попробуете другой подход, вы увидите, что некоторые из них исчезнут, поэтому вы можете увидеть ссылку на массив более прямо:

int myfunction(char A [], int i) {
    return A[i];
}

myfunction(char*, int):                      # @myfunction(char*, int)
    add     a0, a0, a1
    lbu     a0, 0(a0)
    ret
...