Arvorezinha – MIPS Assembly Optimizada
Ola de novo. Com ajuda do sir dongs, optimizei a arvorezinha em mips, e decidi vir blogar sobre isso.
As alterações foram as seguintes:
De:
slt t0,s2,s1 # se s1 < s2 entao t0 = 1 li t1,1 # t1 = 1 para a comparacao do branch seguinte beq t0,t1,_estrela # se o r0 = 1 (t1) -> _estrela |
Para:
>slt t0,s2,s1 # se s1 < s2 entao t0 = 1 bne t0, zero,_estrela # se o r0 ! 0 -> _estrela |
Em vez de se verificar quando t1 é 1, compara-se t1 com o registo zero (que tem sempre o valor 0) quando não é igual a 0 é 1 entao, faz se o branch. | |
De:
>li t1,1 # para a soma seguinte add t0,s1,t1 # t0 = s1 (counter1) + t1 (1) move s1,t0 # s1 = t0, actualiza counter1 |
Para:
addi s1, s1, 1 |
O dongs aqui novamente, deu me a conhecer a magia da instrução addi. Depois disto, pensei que podia fazer uma função com o syscall do write, para não repetir duas vezes o código. Então fui descobrir como era um call, mas pelos vistos tal coisa não existe, o que há é a instrução jal "jump and link", que faz o jump para o sitio devido, e mete o endereço para onde se deve voltar no registo $31 (ra), e para voltar basta um jr ra "jump register". Então adicionei o seguinte código: .ent _print _print: li a0, 1 # stdout li a2,1 # terceiro argumento - numero de bytes a escrever li v0,0x000003EC syscall jr ra .end _print E substitui: |
|
De:
li a0,1 # primeiro argumento pro write() - 1 = stdout la a1,newline # segundo argumento pro write() - endereco da str li a2,1 # terceiro argumento - numero de bytes a escrever li v0,0x000003EC syscall |
Para:
la a1,newline # segundo argumento pro write() - endereco da str jal _print |
Até aqui tudo bem, corria, mas à saída dava segmentation fault. O problema é que ao inicio o registo ra tem o return address do que o que lhe executou. E ao executar a instrução jal, o ra é alterado, e depois à saida do programa quando se faz jr ra, o gajo já nao vai para onde era suposto e chora. Então adicionei logo no inicio do programa um move s8,ra que guarda o valor de ra no registo s8, e depois no final antes de sair faço o contrario move ra,s8 e assim o programa já sai sem drama.
O código completo:
#include <regdef.h> .data estrela: .asciiz "*" newline: .byte 0xa .text .globl main .ent main main: la s0,5 # numero total estrelas la s1,0 # s1 = 0 - counter1 move s8,ra # guarda o valor do return adress em s8 .end main .ent _ciclo1 _ciclo1: beq s1,s0,_fim # se s1 = s0 -> _fim la s2,0 # s2 = 0 - counter2 .end _ciclo1 .ent _ciclo2 _ciclo2: beq s1,s2,_estrela # se s1 = s2 -> estrela slt t0,s2,s1 # se s1 < s2 entao t0 = 1 bne t0, zero,_estrela # se o r0 ! 0 -> _estrela la a1,newline # segundo argumento pro write() - endereco da str jal _print addi s1, s1, 1 b _ciclo1 # volta ao _ciclo1 .end _ciclo2 .ent _estrela _estrela: la a1,estrela # segundo argumento pro write() - endereco da str jal _print addi s2, s2, 1 b _ciclo2 # volta ao ciclo2 .end _estrela .ent _print _print: li a0, 1 # stdout li a2,1 # terceiro argumento - numero de bytes a escrever li v0,0x000003EC syscall jr ra .end _print .ent _fim _fim: move ra,s8 # volta a meter o ra em ra jr ra .end _fim
Adoro optimizações assembly, continua!
BRAVO!