• Nenhum resultado encontrado

4.2 Seleção de instruções

4.2.3 Legalização do DAG

Na fase de legalização do DAG remove-se as instruções e tipos de dados que não são suportados pela máquina alvo. Para isso é necessário fornecer à framework algumas informações específicas do nosso target tais como:

 Os tipos de dados suportados por cada instrução e para cada tipo de dados qual a classe de registos que deve ser utilizada.

 Expandir ou promover instruções para que possam ser utilizadas pela máquina alvo.

 Como lidar com as instruções que não podem ser transformadas automaticamente.

 Como lidar com as convenções de chamada de uma função.

A classe M2upTargetLowering foi implementada como uma subclasse da classe TargetLowering e fornece estas informações à framework do LLVM.

4.2.3.1 Convenções de chamada

A forma como os argumentos são passados e retornados numa função podem variar de máquina para máquina pois enquanto algumas máquinas determinam um conjunto de

restrições outras funcionam de forma agnóstica. O M2up não define nenhuma convenção de chamada, mas tendo em conta o reduzido número de registos decidiu-se adotar as seguintes:

 Um argumento do tipo i16 pode ser passado no registo R3.

 Caso os registos não sejam suficientes para passar todos os argumentos, estes serão passados através da stack.

 Os valores de retorno são retornados no registo R5.

Um ficheiro de descrição TableGen foi utilizado para definir as convenções de chamada. Na Figura 4.7 estão definidas as convecções de chamada para o M2up apresentadas acima.

Figura 4.7-Descrição das convenções de chamada definidas para o M2up

O RetCC_M2up define o tipo de valores e qual o registo a utilizar para guardar os valores de retorno de uma função. No CC_M2up define-se que os argumentos do tipo i8 devem ser promovidos para o tipo i16 para poderem ser passados no registo R3 ou através da stack.

Sempre que um valor de retorno ou argumento de uma função passa por este processo de legalização a convenção de chamada apropriada é chamada determinando assim o local de destino para a variável. Para além da localização dos argumentos e valores de retorno é necessário definir o processo de legalização para a chamada e retorno de uma função. Este processo não está implementado num ficheiro de descrição mas sim no M2upTargetLowering. As seguintes funções são chamadas neste processo:

LowerCall( ): Quando uma função é chamada, a função LowerCall() é utilizada. Primeiro é calculado o tamanho da stack necessário para os argumentos da função. Este tamanho é definido como um argumento da pseudo-instrução CALLSEQ_START que indica o início da sequência de chamada. Em seguida uma sequência de STORES são inseridos para guardar os argumentos na stack. A seguir aos STORES a instrução CALL é então inserida. Finalmente é inserida a pseudo-instrução CALLSEQ_END para indicar o fim da sequência.

LowerFormalArguments( ): Quando entramos no scope de uma função é necessário que esta possa aceder aos argumentos. Para isso é necessário passar os argumentos para registos virtuais. Os argumentos que já estejam em registos são copiados para registos virtuais. Os argumentos que estão na stack são passados para os registos virtuais através da inserção de uma sequência de LOADs no DAG.

LowerReturn( ): O método LowerReturn() é utilizado na saída do scope de uma função. O valor de retorno caso exista é copiado para o registo físico definido nas convenções de chamada e um nodo RET_FLAG é emitido que mais tarde na seleção de instruções será substituído por um salto para o valor guardado no registo R7.

4.2.3.2 Instruções ilegais

Existem algumas operações e operandos que têm de ser transformados manualmente devido a algumas características específicas. Neste passo estes nodos serão substituídos por nodos intermédios que podem ser utilizados no processo de seleção de instruções

Saltos condicionais: No código intermédio LLVM uma instrução de

salto condicional é sempre precedida por uma instrução de comparação. A linguagem LLVM IR utiliza uma instrução icmp para comparar dois números inteiros. Esta instrução recebe 3 operandos: uma condição para indicar o tipo de comparação a efetuar e os 2 valores a comparar. A mesma retorna um valor booleano indicando se a condição comparada é verdadeira ou falsa. Este valor verdadeiro ou falso é depois utilizado para decidir se o salto condicional deve

ser efetuado ou não. Como foi visto nas secções anteriores estas duas instruções são inicialmente substituídas no Dag pela sequência de nodos setcc

brcond. O M2up não possuiu uma instrução de comparação e o salto

condicional recebe apenas a condição de salto e o endereço de destino. Na fase de otimização os nodos setcc e brcond são substituídos pelo nodo br_cc. Este salto condicional já é mais próximo do salto condicional do M2up pois recebe como operando a condição de salto, no entanto ao contrário do salto do M2up o

br_cc efetua a comparação entre os valores. O M2up não possui uma instrução

de comparação mas possui um registo PSW que contêm as flags Carry, Zero, Equal, Greater e Less. Estas flags podem ser afetadas por todas as instruções aritméticas e lógicas. As instruções SUB e SUBi foram utilizadas para comparar valores ativando assim as flags corretas antes de um salto condicional. O nodo br_cc é assim substituído por um nodo um nodo intermédio M2upISD::CMPPSW que na fase de instruções poderá ser substituído pelas instruções SUB ou SUBi seguida de um nodo intermédio M2upISD::BR_CC que recebe uma flag correspondente á condição de comparação e que na fase de seleção de instruções será substituído pelo salto condicional correspondente. O M2up possuí 5 saltos condicionais, um para cada flag sendo que o salto é efetuado caso a flag correspondente esteja ativa. O LLVM possuí condições de comparação para a qual o M2up não saltos condicionais como por exemplo a condição GE(greater equal). Estas condições levavam a que fosse necessário incluir 2 saltos condicionais, para o caso do GE um com a flag Greater e outro com a flag equal pois os saltos M2up aceitam apenas uma das flags de cada vez. Nestes casos é utilizada a instrução MPSW do M2up fazendo o toogle á flag oposta, no caso do GE a flag Less alterando- se assim o salto para um Branch Less em vez de um Branch Greater Equal que não existe no M2up.

Deslocamentos: O LLVM possui três instruções de deslocamento de

bits, o SHL (Shift Left), o ASHR (Arithmetic shift right) e o LSHR (Logical

Shift Right). O M2up possuí apenas Rotates: RL (Rotate Left), RR (Rotate Right) , RLC (Rotate Left with Carry) e RRC(Rotate Right with Carry). É

o SHL: o SHL de um pode ser transformado num RLC de um desde que a flag Carry esteja a zero. O SHL é assim substituído por uma instrução MPSW para colocar a flag Carry a 0 e por um RLC. Quando pretendemos deslocamentos superiores a um é necessário introduzir um ciclo para introduzir o conjunto MPSW e RLC n vezes sendo n o número de vezes que se pretende deslocar um número à esquerda.

o LSHR: o LSHR de um pode ser transformado num RRC de um desde que a flag Carry esteja a zero. O LSHR é assim substituído por uma instrução MPSW para colocar a

flag Carry a 0 e por um RLC. Quando pretendemos

deslocamentos superiores a um é necessário introduzir um ciclo para introduzir o conjunto MPSW e RLC n vezes sendo n o número de vezes que se pretende deslocar um número à direita.

o ASHR: o ASHR de um pode ser transformado num RRC de um desde que a flag Carry seja uma cópia do bit de sinal. O ASHR é assim substituído por uma instrução MPSW para colocar a flag Carry com o sinal do número que pretendemos deslocar e por um RRC. Quando pretendemos deslocar mais que uma vez é necessário introduzir um ciclo para introduzir o conjunto MPSW e RRC n vezes sendo n o número de vezes que se pretende deslocar um número à direita.

O DAG otimizado mas com instruções ilegais da Figura 4.6 é transformado no DAG apresentado na Figura 4.8 na fase de Legalização do DAG.

Figura 4.8-DAG para o bloco entry da função recurssiva depois do processo de legalização do Dag.

O nodo ilegal br_cc foi substituído pelos nodos intermédios M2upISD::CMPPSW e M2upISD:BR_CC que na fase de seleção de instruções no DAG já podem ser substituídos por instruções nativas do M2up.

Documentos relacionados