1 / 70

Blocos básicos e Traces

Departamento de Estatística e Informática Universidade Federal de Sergipe Compiladores. Blocos básicos e Traces. Giovanny Lucero giovanny@ufs.br. Adequação de Tree. Alguns aspectos de Tree não tem correspondência com linguagens de máquina CJUMP tem dois rótulos

peri
Download Presentation

Blocos básicos e Traces

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Departamento de Estatística e Informática Universidade Federal de Sergipe Compiladores Blocos básicos e Traces Giovanny Lucero giovanny@ufs.br

  2. Adequação de Tree • Alguns aspectos de Tree não tem correspondência com linguagens de máquina • CJUMP tem dois rótulos • Ordem de avaliação de expressões interfere com otimização • Sem ESEQ e CALL, ordem de avaliação não importa

  3. Transformação em três passos • Trees canônicos sem SEQ ou ESEQ • Subindo SEQ e ESEQ ao topo da árvore • Todo pai de SEQ é um SEQ • Portanto, substituímos os SEQs por uma lista de Tree.Stm • Agrupação em blocos sem JUMPS internos ou rótulos (Blocos Básicos) • Traces: c/CJUMP seguido imediatamente pelo seu rótulo false

  4. Árvores Canônicas • Não tem SEQ nem ESEQ • O pai de cada CALL é • EXP(...) ou MOVE(Temp t, ...)

  5. Regras de transformação ESEQ ESEQ e ESEQ s1 SEQ s2 e s2 s1 ESEQ(s1,ESEQ(s2,e)) = ESEQ(SEQ(s1,s2),e)

  6. ESEQ BINOP BINOP s1 op ESEQ e2 e1 op e2 e1 s1 BINOP(op, ESEQ(s1,e1),e2) = ESEQ(s1, BINOP(op, e1,e2)) MEM(ESEQ(s,e1)) = ESEQ(s,MEM(e1)) JUMP(ESEQ(s,e1) = SEQ(s,JUMP(e1) CJUMP(op,ESEQ(s,e1),e2,L1,L2) = SEQ(s,CJUMP(op,e1,e2,L1,L2))

  7. BINOP ESEQ BINOP(op,e1,ESEQ(s1,e2)) = ESEQ(s1, BINOP(op,e1,e2)) op e1 ESEQ s1 BINOP e2 s1 op e2 e1 Está correto?

  8. BINOP ESEQ BINOP(op,e1,ESEQ(s1,e2)) = ESEQ(s1, BINOP(op,e1,e2)) op e1 ESEQ s1 BINOP e2 s1 op e2 e1 • Está correto? Não em todos os casos. • s1 pode realizar alguma ação que modifique o valor de e1.

  9. BINOP ESEQ op e1 ESEQ MOVE ESEQ e2 s1 s1 BINOP TEMP e1 op TEMP e2 • Solução • Criar um temporário t. t t BINOP(op,e1,ESEQ(s1,e2)) = ESEQ(MOVE(TEMP t, e1), ESEQ(s1, BINOP(op, TEMP t, e2)

  10. CJUMP(op,e1,ESEQ(s,e2),L1,L2) = SEQ(MOVE(TEMP t,e1), SEQ(s, CJUMP(op,TEMP t,e2,L1,L2)))

  11. Se s e e1 comutam: BINOP(op,e1,ESEQ(s,e2)) = ESEQ(s,BINOP(op,e1,e2)) CJUMP(op,e1,ESEQ(s,e2),L1,L2) = SEQ(s, CJUMP(op,e1,e2,L1,L2) ) • Observe que s e e1 comutam se s não produz efeitos colaterais que alterem e1 • Dados de e1não são referenciados por s • Não podemos saber sempre se duas expressões comutam. MOVE(MEM(x),y) e MEM(z) • Tomamos uma abordagem conservadora • NAME(L) e CONST(n) comutam com todo mundo.

  12. CALL • Regras similares são aplicadas a CALL quando seu pai não é MOVE ou EXP. • Exemplo: • BINOP(PLUS, CALL(...), CALL(...)); • CALLs devolvem resultados em um mesmo registrador. (Sobrescrita).

  13. CALL • Para resolver este problema, substituir cada ocorrência de CALL por: • ESEQ(MOVE(TEMP tnew, CALL(...), TEMP tnew).

  14. Linearização dos Statements • Após execução destes passos, todos os SEQ estarão próximos a raiz da árvore. • No entanto podemos encontrar construções desta forma: • SEQ(SEQ(a,b), c)). • Para eliminarmos estas construções, aplicamos novas transformações tal que: • SEQ(SEQ(a,b),c) = SEQ(a, SEQ(b, c)). • Agora sim, podemos eliminar os construtores SEQ.

  15. Transformação em três passos • Trees canônicos sem SEQ ou ESEQ • Subindo SEQ e ESEQ ao topo da árvore • Todo pai de SEQ é um SEQ • Portanto, substituímos os SEQs por uma lista de Tree.Stm • Agrupação em blocos sem JUMPS internos ou rótulos (Blocos Básicos) • Traces: c/CJUMP seguido imediatamente pelo seu rótulo false

  16. Blocos Básicos • Em um bloco básico: • O primeiro comando é um rótulo • O último comando é um JUMP ou CJUMP • Não há mais rótulos JUMPS ou CJUMPS Algoritmo: • scanear o programa Tree assim: • Se um rótulo é achado, começa um novo bloco • Se um (C)JUMP é achado, termina o bloco • Se ficou algum bloco não finalizado por (C)JUMP, adicione um JUMP para o próximo bloco • Se ficou algum bloco sem começar com rótulo, invente um novo rótulo

  17. Transformação em três passos • Trees canônicos sem SEQ ou ESEQ • Subindo SEQ e ESEQ ao topo da árvore • Todo pai de SEQ é um SEQ • Portanto, substituímos os SEQs por uma lista de Tree.Stm • Agrupação em blocos sem JUMPS internos ou rótulos (Blocos Básicos) • Traces: c/CJUMP seguido imediatamente pelo seu rótulo false

  18. Traces • Observe que os blocos básicos podem ser re-arranjados em qualquer ordem sem alterar a semântica do programa • Escolhemos um ordenamento de blocos tal que c/CJUMP é seguido por seu rótulo falso, e • Se possível, JUMPs seguido imediatamente do seu rótulo alvo

  19. Traces • Algoritmo: • Enquanto existir blocos não marcados. • Comece com qualquer bloco (marque o bloco) • Siga o possível caminho de execução (JUMP), marcando os blocos percorridos. • Se CJUMP() escolha um dos dois caminhos. • Ligue os blocos percorridos (trace gerado).

  20. Traces • Finalizando: • Qualquer CJUMP imediatamente seguido pelo seu rótulo “false”. • Deixe como está. • Qualquer CJUMP imediatamente seguido pelo seu rótulo “true”. • Trocamos o rótulo true por false e negamos a condição.

  21. Traces • Qualquer CJUMP(cond, a, b, lt, lf) seguido nem por true ou false. • Rescrevemos o CJUMP para a seguinte forma: • CJUMP(cond, a, b, lt, l’f) • LABEL l’f • JUMP(NAME lf);

  22. Departamento de Estatística e Informática Universidade Federal de Sergipe Compiladores Seleção de instrução Giovanny Lucero giovanny@ufs.br

  23. Padrões Tree • Identificamos uma instrução de máquina como um fragmento de Tree (um padrão) • Tiling: recortamos a árvore em um mosaico/“quebra cabeças” de padrões • Objetivo: obter um conjunto “otimizado” de padrões.

  24. Padrões para Jouette + × - / + + CONST CONST CONST - CONST Em jouette o registrador 0 sempre contém 0

  25. MEM MEM MEM MEM + + CONST CONST CONST MOVE MOVE MOVE MOVE MEM MEM MEM MEM + + CONST CONST CONST MOVE MEM MEM

  26. Tiling árvores MOVE MEM MEM + + CONST x fp MEM * TEMP i CONST 4 + CONST a fp a[i]:=x

  27. Tiling árvores 9 MOVE 8 MEM MEM 6 + + 7 2 CONST x fp MEM * 5 TEMP i CONST 4 + 2. LOAD r_1 ← M[fp+a] 4. ADDI r_2 ← r_0 + 4 5. MUL r_2 ← r_i × r_2 6. ADD r_1 ← r_1 + r_2 8. LOAD r_2 ← M[fp+x] 9. STORE M[r_1+0] ← r_2 3 4 fp CONST a fp 1 a[i]:=x

  28. Tiling árvores 9 MOVE MOVE 8 MEM MEM MEM MEM 6 + 2. LOAD r_1 ← M[fp+a] 4. ADDI r_2 ← r_0 + 4 5. MUL r_2 ← r_i × r_2 6. ADD r_1 ← r_1 + r_2 8. LOAD r_2 ← M[fp+x] 9. STORE M[r_1+0] ← r_2 9. MOVEM M[r1] ← M[r2] + + + 7 2 MEM * fp CONST x CONST x fp 5 MEM * TEMP i CONST 4 + TEMP i CONST 4 + 3 4 X X X X X X X X fp CONST a CONST a fp 1 a[i]:=x

  29. Tilings ótimos e “otimais” • C/instrução de máquina tem um custo (tempo de execução) • Ótimo  soma dos custos dos tiles é mínima • Otimal  não existe nenhum par de tiles adjacentes que possam ser combinados em um único tile mais eficiente • Ótimo  Ótimal, mas não viceversa • Para RISC otimal e ótimo não são muito diferentes • Para CISC nota-se às vezes a diferença

  30. MaximalMunch • Algoritmo top-down que calcula tilingotimal • Começando pela raiz, sempre escolha o tile maior que puder • Continue top-down com as sub-árvores ainda sem cobrir • Por c/tile colocado, gere as instruções correspondentes • Gera instruções em ordem inversa • Se todas as instruções têm o mesmo peso, o tile maior é o que tem mais nós.

  31. Tiling Ótimo • O algoritmo usa programação dinâmica: encontra a solução ótima baseada nas soluções ótimas de cada subproblema • Tiling ótimo de uma árvore é baseado no tiling ótimos das sub-árvores • Associa com cada nó um custo • a soma dos custos do conjunto de instruções ótimo para sua sub-árvore • Trabalha bottom-up

  32. MEM + CONST1 CONS2 Exemplo • CONST1 só é casado por ADDI e tem custo 1 • Similarmente CONST2 • Para + temos: + + CONST + CONST

  33. MEM + CONST1 CONS2 • Para MEM temos MEM MEM + CONST MEM + CONST

  34. Emissão de código • Uma vez calculado o custo da raiz (e assim da árvore inteira), emitimos o código assim emission(n): para cada folha l do tile t selecionado para n faça emission(l); emita o código para t

  35. MEM + CONST1 CONS2 Emissão de código O código emitido para o exemplo é ADDI r_1 ← r_0+1 observe que não é gerado código para o nó +

  36. MEM + CONST1 CONS2 Emissão de código O código emitido para o exemplo é ADDI r_1 ← r_0+1 LOAD r_1 ←M[r_1+2] observe que não é gerado código para o nó +

  37. Complexidade dos Algoritmos • Tanto maximal munch como programação dinâmica tem complexidade linear. Porém a constante do maximal munch é bem menor. • Detalhes no livro do tigre • Na prática esta fase é muito eficiente se comparada com outras do compilador.

  38. Geradores de geradores • Existem ferramentas que geram automaticamente um gerador de código • Recebem como entrada a especificação dos Tiles usando gramáticas • Para cada regra da gramática é associado um custo e uma ação específica. • Custos são usados para encontrar o Tiling ótimo. • Ações das regras casadas são usadas na fase de emissão.

  39. Departamento de Estatística e Informática Universidade Federal de Sergipe Compiladores Análise de Liveness Giovanny Lucero giovanny@ufs.br

  40. Longevidade (Liveness) • Tradução para código intermediário assume um número ilimitado de temporários • Máquinas têm um número limitado de registradores • Dois temporários cabem num registrador se eles não são usados ao mesmo tempo • Excessos de temporários devem ser armazenados em memória • Análise de Liveness é uma tarefa prévia a alocação de registradores • Baseado no grafo de fluxo de controle • a está vivo (live) sse contém um valor necessário no futuro

  41. Grafo de fluxo de controle 1 a:=0 a ← 0 L1: b ← a + 1 c ← c + b a ← b * 2 if a < N goto L1 return c 2 b := a+1 3 c := c+b 4 a := b*2 b está viva em 3→4 e 2→3 a em 1→2 e 4→5→2, mas não em 3→4 c em todo o programa 5 a < N 6 return c Análise de liveness é feita de trás para frente

  42. Definições • definição = ocorrência no lado esquerdo de uma atribuição • uso = no lado direito • def(a)={n| n define a} (a é variável e n nó) • def(n)={a|n define a} • Similarmente definimos use(a) e use(n) • Liveness: • Uma variável está viva numa aresta se há um caminho dirigido desde esta aresta até um nó que a usa e que não passa por nós que a definem • Uma variável está viva num nó se ela está viva em alguma aresta que entra neste nó • Uma variável vivefora de um nó se está viva em alguma aresta de saída

  43. Liveness estático vs. dinâmico • Note que o nó 4 nunca é alcançado. Logo a nãoestá vivo fora de 2 (liveness dinâmico). • Obs. dinâmico  estático • Infelizmente, liveness dinâmico é indecidível. • Liveness estático é suficiente para realizar boas otimizações 1 a:=b*b 2 c := a+b 3 c<=b 4 5 return a return c

  44. Interferência entre variáveis • Análise de liveness é útil para otimizações mas principalmente para alocação de registradores • Duas variáveis se interferem se não podem ser alocadas num mesmo registrador • a e b estão vivas na mesma instrução • b está viva numa instrução que define a há um caso particular para instruções MOVE t  s (copia) ... x  ... s ... (uso de s) ... y  ... t ... (uso de t) t e s não se interferem

  45. Grafos de interferência • Grafo de interferências • os nós são as variáveis • aresta de a para b se a e b se interferem

  46. Grafos de interferência

  47. Departamento de Estatística e Informática Universidade Federal de Sergipe Compiladores Alocação de Registradores Giovanny Lucero giovanny@ufs.br

  48. Alocador de registradores • Atribui aos temporários um número pequeno de registradores • Atribui uma locação de memória quando não é possível atribuir um registrador • Se possível atribui o mesmo registrador a mais de um temporário.

  49. Alocador de registradores • Se reduz ao problema do coloreamento de grafos • Colorir o grafo de interferências (onde os nós são os temporários) • 1 cor por registrador (K registradores  K cores) • nós adjacentes devem ter cores diferentes • o coloreamento se corresponde com uma atribuição de registradores que satisfaz as interferências • Se não houver coloreamento, alguns temporários são alocados em memória (spilling) • O problema é NP-Completo • Boa aproximação em tempo linear

  50. Coloreando por simplificação • Cinco fases: Build, Simplify, Spill, Select e Start Over • Build • Construa o grafo de interferências (análise de dataflow) • Simplify (heurística simples) • Se grau(n) < k  coloreie G’ e então pinte n com uma cor diferente dos seus vizinhos (implementado com uma pilha de nós). • Spill • Se todos os nós tem grau ≥ k  escolha um nó candidato a eliminação (alocação em memória). Seja otimista e empilhe.

More Related