Oi pessoal! Tudo bem? Espero que sim. Hoje retomo o assunto ARRAY, isto porque mostrei a vocês como compilar expressões matemáticas para MIPS quando o ARRAY, com índice específico, é um operando e quando ele armazena o resultado de uma operação. Porém faltou mostrar a compilação de quando o ARRAY tem um índice variável e não uma “posição” específica. Vamos lá então!
Compilando
Vou usar como exemplo a seguinte expressão matemática:
g = h + a[i];
Também farei a seguinte atribuição de registradores:
g = $s0 h = $s1 a = $s2 i = $s3
Note que agora o Array a possui um índice variável, que neste caso é o i, e não mais um índice específico, como, por exemplo, a[3] ou a[10]. Como então definir o i? Não sabemos quem é i, isso é verdade, não sabemos o seu valor, a sua posição, porém sabemos que i tem um endereço.
Também sabemos que o primeiro passo para a compilação desta expressão é ler a[i] carregando-o para um registrador temporário e, para isso, precisamos do seu endereço. Conforme explicado no artigo sobre a instrução SLT, o MIPS trabalha com endereçamento em bytes e, por isso, é necessário realizar um cálculo para o endereço, o qual sempre é múltiplo de 4. Assim sendo, no caso dos índices variáveis em Arrays, devemos multiplicar esses índices por 4. Mas, como fazer isto? Existem duas formas;
1 – Somar i até chegar em 4i
Nesta forma usamos a operação de soma, ADD, para chegar em 4*i, não fazemos a multiplicação direta. O registrador $s3 é a variável i, portanto, vamos começar somando esse registrador, armazenando o resultado em um registrador temporário:
ADD $t1, $s3, $s3 # $t1 = $s3 + $s3 $t1 = i + i = 2*i
O registrador $t1 armazenou o valor 2*i, pois i + i é 2*i, correto?! Portanto, $t1 agora “vale” 2*i. Se fizermos $t1 + $t1 vamos obter 4*i, pois 2*i + 2*i = 4*i, confere? Usando o mesmo registrador temporário $t1 para armazenar o resultado, de forma a aproveitarmos melhor o uso dos registradores, veja como fica:
ADD $t1, $t1, $t1 # $t1 = $t1 + $t1 $t1 = 2i + 2i = 4i
Essas duas linhas são referentes à soma de i até chegar em 4*i, isso garante que o endereço de i esteja correto, não importando o valor que ele contenha. Estamos falando aqui de um array, chamado a, o qual está atribuído ao registrador $s2, portanto, precisamos fazer o cálculo do endereço completo.
ADD $t1, $t1, $s2 # $t1 = ( $t1 + $s2 ) = ( 4*i + $s2) que é o mesmo que a[i]
Agora sim o cálculo do endereço de a[i] está completo e correto! Toda vez que encontrar um Array com índice variável, lembre-se de que, nesta forma de compilação, ele sempre vai resultar em três linhas de código no Assembly MIPS, as quais são três somas.
Da forma como mostrei aqui, o registrador $t1 acaba por ter o comportamento de um registrador acumulador (muitas vezes conhecido como ACC na Arquitetura Intel), que é aquele registrador que realiza operações e armazena resultados, consigo próprio. Agora que o endereço de a[i] já foi calculado, o restante da expressão pode ser compilada da forma que você já conhece, veja:
LW $t2,0($t1) # $t2 = a[i]
ADD $s0, $s2, $t2 # g = h + a[i]
O código completo fica da seguinte forma:
ADD $t1, $s3, $s3 # 2*i
ADD $t1, $t1, $t1 # 4*i
ADD $t1, $t1, $s2 # a[i] = (4*i + $s2)
LW $t2, 0($t1) # $t1 = a[i]
ADD $s0, $s1, $t2 # g = h + a[i]
Para essa instrução, g = h + a[i], e com esta forma de compilação, o código resultante em MIPS é de cinco linhas. Tente agora fazer a compilação para linguagem de máquina, representação e código de máquina.
2 – Usar a operação de deslocamento lógico à esquerda
Nesta forma de compilação não usamos a soma de forma a simular uma multiplicação. Ao invés disso, usamos a operação SLL, a qual gera o mesmo resultado que uma multiplicação por 2i. O deslocamento à esquerda de 2 bits multiplica por 22, ou seja, 4. A compilação ficará da seguinte forma:
SLL $t1, $s3, 2 # $t1 = 4*i
Na forma anterior precisamos de duas linhas para chegar no 4*i, já com a SLL uma única linha já nos fornece o resultado almejado. Ainda é preciso calcular o resto do endereço, somando $t1 com a base do Array a:
ADD $t1, $t1, $s2 # $t1 = ( $t1 + $s2 ) = ( 4*i + $s2) que é o mesmo que a[i]
O restante da compilação permanece o mesmo, veja:
LW $t2, 0($t1) # $t1 = a[i]
ADD $s0, $s1, $t2 # g = h + a[i]
Usando SLL conseguimos diminuir em UM (1) a quantidade de linhas do código compilado em ASSEMBLY, o que não quer dizer que esse trecho de código será executado mais rapidamente. Nem sempre quantidade de linhas é sinônimo de execução rápida, as vezes com mais linhas a execução é mais rápida, as vezes não, e, as vezes em menos linhas a execução é mais rápida, as vezes não. Isso depende de uma série de outros fatores. Voltarei a falar sobre isso em artigos próximos, por hora, fica a reflexão! O código completo fica assim:
SLL $t1, $s3, 2 # 4*i
ADD $t1, $t1, $s2 # a[i] = (4*i + $s2)
LW $t2, 0($t1) # $t1 = a[i]
ADD $s0, $s1, $t2 # g = h + a[i]
Tente fazer o restante da compilação: linguagem de máquina, representação e código de máquina.
Conclusão
Neste artigo você aprendeu a compilar uma instrução de alto nível com Array de índice variável, para um trecho de código em linguagem Assembly MIPS. Você pode também escolher o método para fazer isso. Não entendeu alguma coisa? Por favor, deixe aqui nos comentários que eu tentarei responder o mais breve possível. Obrigada leitor! Até o próximo artigo.
Saiba mais
SiFive lança o primeiro SoC RISC-V compatível com Linux
FE310G: Um microcontrolador open source – Interrupções no RISC-V
FE310G: Um microcontrolador open source – Estrutura básica do RISC-V










