Функция RISCV с использованием регистров - PullRequest
0 голосов
/ 10 июля 2020

Какое значение возвращает этот код с использованием RISCV рассмотрим c форма int fun(int n)

fun: 
addi s0, zero, 0 
addi s1, zero, 1 
add t0, zero, a0
loop: 
beq s0, t0, exit 
add s1, s1, s1 
addi s0, s0, 1 
jal zero, loop 
exit: 
add a0, zero, s1 
jalr zero, 0(ra)

1 Ответ

0 голосов
/ 10 июля 2020

Иногда при анализе сборки может быть полезно напрямую указать, что происходит, как C, а затем упростить:

int fun(int n) {
    int s0 = 0;
    int s1 = 1;
    int t0 = n; // n is in a0

loop:
    if (s0 == t0) {
        goto loop_exit;
    }

    s1 = s1 + s1;
    s0 = s0 + 1;

    goto loop;

loop_exit:
    return s1; // Returns in a0
}

Мы видим, что копирование в t0 не требуется, мы можем используйте n напрямую. Кроме того, эта конструкция goto очень похожа на while l oop, с проверкой условий для цикла в начале.

int fun(int n) {
    int s0 = 0;
    int s1 = 1;

    while (s0 != n) {
        s1 += s1;
        s0 += 1;
    }

    return s1;
}

Теперь мы видим, что s1 начинается с 1, а затем удвоить n раз. Мы можем переписать, дав описательные имена и заменив while на for:

int fun(int n) {
    int value = 1;

    for (int counter = 0; counter != n; counter += 1) {
        value += value;
    }

    return value;
}

Благодаря красоте компиляторов эти три набора кода фактически генерируют то же самое. сборка (на этом конкретном компиляторе c, на момент написания этой статьи).

Когда n меньше точности int, эта функция ведет себя как сдвиг влево 1 на n бит.

В этом неграничном случае fun является эквивалентно:

int fun(int n) {
    return 1 << n;
}

Если n имеет точность не менее int, тогда вы столкнетесь с переполнением целого числа со знаком, что приводит к поведению, определяемому реализацией.

...