A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

Geração de Código Intermediário Vantagens do uso de uma notação intermediária: –facilidade de retargetting: geração de código para vários processadores.

Apresentações semelhantes


Apresentação em tema: "Geração de Código Intermediário Vantagens do uso de uma notação intermediária: –facilidade de retargetting: geração de código para vários processadores."— Transcrição da apresentação:

1 Geração de Código Intermediário Vantagens do uso de uma notação intermediária: –facilidade de retargetting: geração de código para vários processadores diferentes, reusando o máximo possível do código em todos os compiladores, mudando apenas o gerador de código final. –uso de otimizador único para vários geradores de código diferentes.

2 Tradução dirigida por sintaxe parser verificador de código código intermediário gerador de código intermediário gerador de código

3 Código de Três Endereços Frequentemente usado como código intermediário, para linguagens imperativas/OO. Abstrai um assembler, onde cada instrução básica referencia 3 (ou menos) endereços (i.e. variáveis). Formato: x := y op z Exemplo: x + y * z é reescrito para t 1 := y * z t 2 := x + t 1

4 Código de três endereços - exemplo t 1 := -c t 2 := b * t 1 t 3 := -c t 4 := b * t 3 t 5 := t 2 + t 4 a := t 5 * assign + uminus a * c b b c

5 Tipos de código de três endereços Atribuição do tipo: x := y op z Atribuição do tipo: x := op y Cópia: x := y desvios incondicionais: goto L desvios condicionais: if x relop y goto L chamada de procedimentos: param x e call p,n e return y

6 Tipos de código de três endereços (cont.) atribuição indexada: x := y[i] e x[i] := y atribuição de endereços e ponteiros: x := &y, x := *y e *x := y

7 Tradução dirigida por sintaxe para código de três endereços S  id := E S.code := E.code || gen(id.place ‘:=‘ E.place) E  E 1 + E 2 E.place := newtemp; E.code := E 1.code || E 2.code || gen(E.place ‘:=‘ E 1.place ‘*’ E 2.place) E  - E 1 E.place := newtemp; E.code := E 1.code || gen(E.place ‘:=‘ ‘uminus’ E 1.place) E  ( E 1 ) E.place := E 1.place; E.code := E 1.code E  id E.place := id.place; E.code := ‘’

8 Tradução do while S  while E do S 1 regra semântica: S.begin := newlabel; S.end := newlabel; S.code := gen(S.begin ‘:’) || E.code || gen(‘if’ E.place ‘=‘ ‘0’ ‘goto’ S.end) || S 1.code || gen(‘goto’ S.begin) || gen(S.end ‘: ‘)

9 Declarações Declarações dentro de um procedimento frequentemente são tratadas como um único grupo, e são acessadas como um offset do ponto onde começam a ser armazenadas (na pilha). offset inicialmente é zero, e a cada novo símbolo declarado o valor do offset é guardado na tabela de símbolos, e o offset é incrementado. exemplo: procedimento enter(name,type,offset)

10 Declarações P  {offset := 0} D D  D ; D D  id : T { enter(id.name, T.type, offset); offset := offset + T.width } T  integer { T.type := integer; T.width := 4; } T  real { T.type := real; T.width := 8; } T  array [ num ] of T 1 { T.type := array(num.val, T 1.type); T.width := num.val * T 1.width }

11 Declarações –tratando escopo uma possibilidade é manter tabelas de símbolos separadas para cada procedimento, com referências ao contexto mais externo (outra tabela de símbolos).

12 Declarações –tratando escopo procedimentos utilizados: –mktable(previous) – cria uma nova tabela de símbolos, con referência à anterior –enter(table, name, type, offset) – insere um novo símbolo na tabela –addwidth(table, width) – incrementa contador do tamanho da tabela –enterproc(table,name,newtable) – insere um novo símbolo (procedimento) na tabela e pilhas offset e tblptr

13 Declarações –tratando escopo P  M D { addwidth(top(tblptr),top(offset)); pop(tblptr); pop(offset); } M   {t := mktable(nil); push(t,tblptr); push(0,offset);} D  D 1 ; D 2 D  proc id ; N D 1 ; S { t := top(tblptr); addwidth(t, top(offset)); pop(tblptr); pop(offset); enterproc(top(tblptr),id.name,t)} D  id : T { enter(top(tblptr),id.name,T.type,top(offset)); top(offset) := top(offset) + T.width } N   { t := mktable(top(tblptr)); push(t,tblptr); push (0,offset) }

14 Declarações –tratando registros nomes de campos de registros também podem ser guardados usando tabelas de símbolos específicas para cada (tipo) registro. T  record L D end { T.type := record(top(tblptr)); T.width := top(offset); pop(tblptr); pop(offset); } L   { t := mktable(nil); push(t,tblptr); push (0,offset) }

15 Revendo Atribuições S  id := E { p := lookup(id.name); if p != nil then emit (p ‘:=‘ E.place) else error } E  E 1 + E 2 { E.place := newtemp; emit (E.place ‘:=‘ E 1.place ‘*’ E 2.place) } E  - E 1 { E.place := newtemp; emit(E.place ‘:=‘ ‘uminus’ E 1.place) } E  ( E 1 ) { E.place := E 1.place } E  id { p := lookup(id.name); if p != nil then E.place := p else error }

16 Reuso de nomes controlando o tempo de vida dos nomes usados dentro de cada statement ou expressão, é possível fazer o reuso de nomes de variáveis temporárias. Exemplo: usar contador incrementado para cada novo temporário, e decrementado para cada uso. evaluate E 1 to t 1 evaluate E 2 to t 2 t := t 1 + t 2

17 Reuso de nomes - exemplo x := ((a * b) + (c * d)) – (e * f) $0 := a * b $1 := c * d $0 := $0 + $1 $1 := e * f $0 := $0 - $1 x := $0

18 Acesso a Arrays controlado de acordo com o tamanho e o tipo do array: base + (i – low) * w ou melhor ainda: i * w + (base – low * w) existem fórmulas genéricas para arrays multidimensionais: –2D: A[i 1, i 2 ] base + ((i 1 – low 1 ) * n 2 + i 2 – low 2 ) * w row-major vs. column-major

19 Expressões Booleanas Podem ser avaliadas de duas formas: –codificar true e false como números, e avaliar as expressões da mesma forma que expressões matemáticas. –usar o fluxo de controle, i.e. representar um valor por uma posição atingida no programa. Usada em if- then-else, while-do etc. Permite “curto-circuito” de expressões: se E 1 é avaliado como true, na expressão E 1 or E 2, não é necessário avaliar E 2.

20 Representação numérica - exemplo a or b and not c t 1 := not c t 2 := b and t 1 t 3 := a or t 2

21 Representação numérica - exemplo a < b é traduzido para if a < b then 1 else 0 100: if a < b goto : t := 0 102: goto : t := 1 104:

22 Esquema de Tradução E  E 1 or E 2 { E.place := newtemp; emit (E.place ‘:=‘ E 1.place ‘or’ E 2.place) } E  id 1 relop id 2 { E.place := newtemp; emit(‘if’ id 1.place relop.op id 2.place ‘goto’ nextstat + 3); emit(E.place ‘:=‘ ‘0’); emit(‘goto’ nextstat + 2); emit(E.place ‘:=‘ ‘1’)} E  ( E 1 ) { E.place := E 1.place } E  true { E.place := newtemp; emit(E.place ‘:=‘ ‘0’) }

23 Representação numérica - exemplo a < b or c < d and e < f 100: if a < b goto : t1 := 0 102: goto : t1 := 1 104: if c < d goto : t2 := 0 106: goto : t2 := 1 108: if e < f goto : t3 := 0 110: goto : t3 := 1 112: t4 := t2 and t3 113: t5 := t1 or t4

24 Fluxo de controle Associamos a cada expressão booleana desvios para labels caso a expressão seja avaliada para true ou false. E.true e E.false

25 Tradução do if-then S  if E then S 1 regra semântica: E.true := newlabel; E.false := S.next; S 1.next := S.next; S.code := E.code || gen(E.true ‘:’) || S 1.code

26 Tradução do if-then-else S  if E then S 1 else S 2 regra semântica: E.true := newlabel; E.false := newlabel; S 1.next := S.next; S 2.next := S.next; S.code := E.code || gen(E.true ‘:’) || S 1.code gen(‘goto’ S.next); gen(E.false ‘:’) || S 2.code

27 Tradução do while S  while E do S 1 regra semântica: S.begin := newlabel; E.true := newlabel; E.false := S.next; S 1.next := S.begin; S.code := gen(S.begin ‘:’) || E.code || gen(E.true ‘:’) || S 1.code || gen(‘goto’ S.begin)

28 Fluxo de controle a < b traduzido para: if a < b goto E.true goto E.false

29 Esquema de Tradução E  E 1 or E 2 { E 1.true := E.true; E 1.false := newlabel; E 2.true := E.true; E 2.false := E.false; E.code := E 1.code || gen(E 1.false ‘:’) || E 2.code) } E  E 1 and E 2 {E 1.true := newlabel; E 1.false := E.false; E 2.true := E.true; E 2.false := E.false; E.code := E 1.code || gen(E 1.true ‘:’) || E 2.code) }

30 Esquema de Tradução E  not E 1 { E 1.true := E.false; E 1.false := E.true; E 2.true := E.true; E 2.false := E.false; E.code := E 1.code} E  id 1 relop id 2 {E.code := gen(‘if’ id 1.place relop.op id 2.place ‘goto’ E.true || gen(‘goto’ E.false) } E  true {E.code := gen(‘goto’ E.true } E  false {E.code := gen(‘goto’ E.false }

31 Exemplo 1 a < b or c < d and e < f if a < b goto Ltrue goto L1 L1: if c < d goto L2 goto Lfalse L2: if e < f goto Ltrue goto LFalse é possível otimizar o código acima.

32 Exemplo 2 while a < b do if c < d then x := y + z else x := y – z L1: if a < b goto L2 goto Lnext L2: if c < d goto L3 goto L4 L3: t1 := y + z x := t1 goto L1 L4: t2 := y – z x := t2 goto L1

33 switch/case switch expression begin case value: statement case value: statement … case value: statement default: statement end

34 implementação de switch/case sequência de goto’s condicionais, um para cada caso. loop percorrendo uma tabela de valores e labels para o código do statement correspodente. hash table com valores e labels criar um array de labels, com o label para o statement j na posição da tabela índice j.

35 tradução de switch/case switch E begin case V 1 : S 1 case V 2 : S 2 … case V n-1 : S n-1 default: S n end

36 tradução de switch/case código para avaliar E em t goto test L 1 : código para S 1 goto next L 2 : código para S 2 goto next … L n-1 : código para S n-1 goto next L n : código para S n goto next test: if t = V 1 goto L 1 if t = V 2 goto L 2 … if t = V n-1 goto L n-1 goto L n next:

37 outra tradução de switch/case código para avaliar E em t if t  V 1 goto L 1 código para S 1 goto next L 1 : if t  V 2 goto L 2 código para S 2 goto next L 2 : … L n-2 : if t  V n-1 goto L n-1 código para S n-1 goto next L n-1 : código para S n next:

38 Backpatching uso de um passo extra para resolver as referências a labels definidos posteriormente.

39 Esquema de Tradução E  E 1 or M E 2 { backpatch(E 1.falselist,M.quad); E.truelist := merge(E1.truelist,E 2.truelist); E.falselist := E 2.falselist } M   {M.quad := nextquad } E  E 1 and M E 2 { backpatch(E 1.truelist,M.quad); E.truelist := E 2.truelist; E.falselist := merge(E1.falselist,E 2.falselist); }

40 Esquema de Tradução E  true { E.truelist := makelist(nextquad); emit(‘goto _’) } E  false { E.falselist := makelist(nextquad); emit(‘goto _’) }


Carregar ppt "Geração de Código Intermediário Vantagens do uso de uma notação intermediária: –facilidade de retargetting: geração de código para vários processadores."

Apresentações semelhantes


Anúncios Google