COMPILAÇÃO DE ALGORITMOS EM JAVAÔ PARA SISTEMAS …w3.ualg.pt/~jmcardo/MyThesis/PhD.pdf · João...

312
UNIVERSIDADE TÉCNICA DE LISBOA INSTITUTO SUPERIOR TÉCNICO COMPILAÇÃO DE ALGORITMOS EM JAVA PARA SISTEMAS COMPUTACIONAIS RECONFIGURÁVEIS COM EXPLORAÇÃO DO PARALELISMO AO NÍVEL DAS OPERAÇÕES João Manuel Paiva Cardoso (Mestre) Dissertação para a obtenção do grau de Doutor em Engenharia Electrotécnica e de Computadores Orientador: Doutor Horácio Cláudio de Campos Neto Presidente: Reitor da Universidade Técnica de Lisboa Vogais: Doutor António Manuel de Brito Ferrari Almeida Doutor Guilherme Diniz Moreno da Silva Arroz Doutor Carlos Francisco Beltran Tavares de Almeida Doutor Henrique Manuel Dinis dos Santos Doutor Horácio Cláudio de Campos Neto Doutor Leonel Augusto Pires Seabra de Sousa Outubro de 2000

Transcript of COMPILAÇÃO DE ALGORITMOS EM JAVAÔ PARA SISTEMAS …w3.ualg.pt/~jmcardo/MyThesis/PhD.pdf · João...

UNIVERSIDADE TÉCNICA DE LISBOA

INSTITUTO SUPERIOR TÉCNICO

COMPILAÇÃO DE ALGORITMOS EM JAVA PARA SISTEMAS

COMPUTACIONAIS RECONFIGURÁVEIS COM EXPLORAÇÃO DO PARALELISMO

AO NÍVEL DAS OPERAÇÕES

João Manuel Paiva Cardoso

(Mestre)

Dissertação para a obtenção do grau de Doutor em

Engenharia Electrotécnica e de Computadores

Orientador: Doutor Horácio Cláudio de Campos Neto

Presidente: Reitor da Universidade Técnica de Lisboa

Vogais: Doutor António Manuel de Brito Ferrari Almeida

Doutor Guilherme Diniz Moreno da Silva Arroz

Doutor Carlos Francisco Beltran Tavares de Almeida

Doutor Henrique Manuel Dinis dos Santos

Doutor Horácio Cláudio de Campos Neto

Doutor Leonel Augusto Pires Seabra de Sousa

Outubro de 2000

Copyright, João Manuel Paiva Cardoso, 2000

Título: “COMPILAÇÃO DE ALGORITMOS EM JAVA PARA SISTEMAS

COMPUTACIONAIS RECONFIGURÁVEIS COM EXPLORAÇÃO DO

PARALELISMO AO NÍVEL DAS OPERAÇÕES”

Autor: João Manuel Paiva Cardoso

Mestre em Eng.ª Electrotécnica e de Computadores, IST/UTL, 1997

Licenciado em Eng.ª Electrónica e Telecomunicações, Universidade de Aveiro, 1993

Email: [email protected]

Tese realizada sob a supervisão do

Doutor Eng.º Horácio Cláudio de Campos Neto

Professor Associado do Departamento de Engenharia

Electrotécnica e de Computadores

Instituto Superior Técnico

v

Dedico esta tese a meus pais,

vi

vii

“Não se pode pensar,

fora das possibilidades da língua em que se pensa.”

Vergílio Ferreira, Pensar, Maio 1991

viii

ix

Agradecimentos

Esta tese e o trabalho nela descrito não teriam sido possíveis de realizar sem a ajuda e

compreensão de muitas pessoas. Por isso, sinto a necessidade de agradecer a todos

aqueles cujos contributos foram em meu entender mais notórios. Fico-lhes

imensamente agradecido e peço que eventuais omissões sejam perdoadas.

Agradeço ao meu orientador, Prof. Horácio Neto, pelo incentivo, discussão de ideias,

orientação, conselhos e total disponibilidade demonstrada ao longo da realização da

tese. Os meus agradecimentos por me ter facultado trabalhar no grupo ESDA do

INESC, pela forma como lidou comigo durante todos estes anos, pelos momentos de

descontracção proporcionados, principalmente nos almoços, fundamentais para que o

trabalho ao longo do dia não se tornasse monótono e fatigante, por ter acreditado nas

minhas capacidades, por algumas das vezes me ter feito acordar para caminhos

factíveis, e pela forma como me deixou percorrer o meu próprio caminho. Agradeço-

lhe também as inúmeras revisões realizadas em versões preliminares desta tese e em

artigos publicados.

Aos meus colegas de sala no INESC, Ana e Marcelino, pelos momentos que passámos

juntos, pela amizade, e por nos termos compreendido sempre tão bem. Pelas tentativas

de todos por alegrar o ambiente e por tornar a realização dos nossos doutoramentos

menos morosa.

Ao Mário Véstias, pelas discussões quase diárias que tivemos sobre todos os aspectos

de investigação. Muitas delas, embora tivessem parecido a ambos pouco profícuas,

reconheço agora que foram muito importantes.

Ao Anton Chichkov pelas discussões que tivemos nas fases iniciais deste trabalho, por

me ter despertado para a computação reconfigurável e por me ter feito aperceber de

algumas das lacunas existentes nesta área. O trabalho desenvolvido para a sua tese de

doutoramento viria a servir de suporte e de inspiração para algumas ideias de

importância inolvidável no cômputo geral.

Ao José Sousa por todo o ânimo acrescentado que veio incutir ao grupo, pela força

inicial de alguém que acaba de chegar, pelo apoio que me deu e pelas trocas de ideias

x

que tivemos sobre computação reconfigurável.

À Claudia Calidonna por me ter despertado para as propriedades do HTG de Girkar &

Polychronopoulos depois de algumas discussões que tivemos durante o curso:

“Architecture and Programming of Parallel High Performance Systems”, no Centro

para Computação de Alto-Desempenho em Groningen.

A todos os elementos do grupo ESDA do INESC, Ana Teresa, Mário Véstias, José

Sousa, e Paulo Flores por todo o apoio e pela verdadeira equipa que formámos sempre

que foi preciso resolver um problema. Agradeço também ao José Pedro Abreu pelo

apoio dado sempre que por mim solicitado quando ainda era membro do grupo.

Agradeço ao Prof. Arlindo Oliveira por me ter um dia proposto uma visita ao

laboratório PARADES em Roma para apresentar o meu trabalho inicial,

proporcionando-me o contacto com um laboratório de investigação autónomo. Esta

visita acabou por também marcar a evolução desta tese.

Agradeço todo o apoio demonstrado pelos meus pais – Maria Cristina de Paiva e Luís

Cardoso Adrega –, irmãos – Isabel e Zé – e cunhados – Cristina e Albertino. Durante

o tempo de realização do trabalho que culminou com a escrita desta tese vi-me muitas

vezes privado da companhia de toda a minha família e, por isso, agradeço-lhes toda a

compreensão e encorajamento demonstrados. Aos meus sobrinhos – Tininha, João,

Pedro e Tiago – pelos momentos de companhia proporcionados, poucos mas sempre

revitalizantes.

Agradeço à Prof. Otília e ao Prof. Armando, por terem despertado em mim o gosto

pela aprendizagem, pela leitura, e por desde sempre me manterem em permanente

motivação.

Agradeço à Teresa, pela compreensão que demonstrou ao longo de todo este tempo.

Por nunca ter transformado os maus momentos dela em maus momentos meus e por

ter sempre compreendido as minhas fases menos boas.

Aos meus amigos por me terem sempre compreendido e dado imensa força para que

os meus objectivos fossem realizados e pelos sempre surpreendentes convívios em

que pude desfrutar da companhia deles em Faro, Lisboa ou Aveiro.

xi

Esta tese não teria sido possível de realizar sem a autorização de dispensa de serviço

docente dada pela Universidade do Algarve. Neste particular, estou também

agradecido à Área Departamental de Eng.ª Electrónica e Computação da Unidade de

Ciências Exactas e Humanas por não se ter oposto ao facto de eu ter vindo fazer

doutoramento ao IST.

Agradeço o suporte do programa de doutoramento da acção 5.2 do Prodep, que

possibilitou a minha ausência da Universidade do Algarve nos 3 anos completamente

devotados à realização desta tese.

Agradeço o apoio financeiro proporcionado pelos Projectos do programa Praxis XXI,

da Fundação para a Ciência e Tecnologia, PRAXIS/2/2.1/TIT/1643/95 e

PRAXIS/P/EEI/12154/1998. Estes apoios revelaram-se fundamentais para a

apresentação de publicações relacionadas com esta tese em conferências

internacionais.

Por último, agradeço o apoio dado sob a forma de bolsas de viagens, de alojamento e

de despesas da NATO, da JNICT e da União Europeia que me permitiram frequentar

os cursos “A NATO Advanced Study Institute on System Level Synthesis” e

“International School on Advanced Algorithmic Techniques for Parallel Computation

with Applications”, e a escola de Verão “Architecture and Programming of Parallel

High Performance Systems”.

Lisboa, Outubro de 2000

xii

xiii

Resumo

Neste trabalho é proposta uma estratégia inovadora para compilar algoritmos descritos

em linguagem Java em hardware reconfigurável. A estratégia é suportada por várias

etapas de análise e optimização que permitem gerar eficientemente hardware

especializado. Estas etapas foram implementadas, originando dois compiladores, e

foram estudadas e validadas com exemplos reais.

Os dois compiladores desenvolvidos actuam em série e possibilitam a compilação de

um algoritmo representado por bytecodes de Java em hardware reconfigurável

constituído por um FPGA (Field-Programmable Gate Array) acoplado a uma ou mais

memórias. É apresentado um fluxo completo de compilação, desde a representação

dos bytecodes fonte num formato intermédio propício para explorar os graus elevados

de paralelismo possíveis com os FPGAs da nova geração e a existência de fluxos de

controlo múltiplos, até à geração da estrutura das unidades de dados e da descrição

das unidades de controlo. De permeio são dissecadas as técnicas necessárias para a

geração de uma arquitectura específica e especializada, que implemente

eficientemente o algoritmo fonte em hardware reconfigurável, e permitindo, caso

necessário, a partilha temporal do FPGA.

Os resultados obtidos com a geração do hardware para um número significativo de

exemplos mostram que as técnicas implementadas concretizam a compilação em

tempos de computação razoáveis com resultados eficientes. Estes resultados

confirmam a validade da metodologia proposta e mostram a eficiência, exequibilidade

e efectividade do fluxo de compilação desenvolvido.

xiv

xv

Abstract

This thesis proposes a novel strategy for the compilation of algorithms described in

the Java language to reconfigurable hardware. The strategy is supported by a number

of analysis and optimizations steps that permit to generate efficiently specialized

hardware. These steps were implemented, originating two compilers, and they were

studied and validated with real examples.

The two compilers work in serial and make possible the compilation of an algorithm

represented in Java bytecodes to reconfigurable hardware consisting of one FPGA

(Field-Programmable Gate Array) coupled to one or more memories. A complete

compilation flow is presented, from the representation of the bytecodes on a format

suitable to expose explicitly the larger degrees of parallelism that can be satisfied with

the FPGAs of the new generation and the existence of multiple control flows, to the

generation of the structure of the datapath unit and the description of the control unit.

Meanwhile, the techniques necessary to the generation of a specific and specialized

architecture that implements efficiently the source algorithm in reconfigurable

hardware, and enabling, when necessary, the time-sharing of the FPGA, are also

described.

The results obtained with the hardware generation for a significant set of examples

show that the implemented techniques achieve the compilation in reasonable amounts

of CPU time with efficient results. These results support and validate the proposed

methodology and show the effectiveness of the developed compilation flow.

xvi

xvii

Palavras Chave Java

Compilação

Optimização de Código

Paralelismo ao Nível de Instruções

Computação Reconfigurável/Adaptativa

Síntese de Arquitecturas

Keywords Java

Compilation

Code Optimization

Instruction-Level Parallelism (ILP)

Reconfigurable/Adaptative Computing

Architectural Synthesis

xviii

xix

Índice

CAPÍTULO 1. INTRODUÇÃO 1

1.1 FUNDAMENTOS DE COMPUTAÇÃO RECONFIGURÁVEL 3

1.1.1 ORGANIZAÇÃO DOS SISTEMAS PARA SUPORTE DE COMPUTAÇÃO

RECONFIGURÁVEL 5

1.2 INCENTIVO PARA A INVESTIGAÇÃO EM COMPILADORES PARA SISTEMAS

COMPUTACIONAIS RECONFIGURÁVEIS 7

1.2.1 POR QUÊ COMPILAR DE JAVA, E EM PARTICULAR DOS BYTECODES? 12

1.2.2 POR QUÊ EXPLORAR O PARALELISMO PARA ALÉM DOS BLOCOS BÁSICOS? 13

1.3 CONTRIBUIÇÕES DA TESE 14

1.4 ESTRUTURA DA TESE 17

CAPÍTULO 2. COMPILADORES PARA RECONFIGWARE (HARDWARE

RECONFIGURÀVEL) 21

2.1 COMPILADORES PARA FCCMS 22

2.2 COMPILADOR APRESENTADO POR CHICHKOV 27

2.3 COMPILADOR PRISM-I E II 28

2.4 TRANSMOGRIFIER-C 29

2.5 COMPILADOR NAPA C 30

2.6 SÍNTESE DE PIPELINES EM FPGAS 31

2.7 UTILIZAÇÃO DE AMBIENTES DE SÍNTESE ARQUITECTURAL ADAPTADOS

PARA FPGAS 33

2.8 COMPILADORES PARA ARQUITECTURAS NÃO COMERCIAIS 35

2.9 CONCLUSÕES 40

CAPÍTULO 3. MODELOS DE REPRESENTAÇÃO INTERMÉDIA E SUA

CONSTRUÇÃO 45

3.1 MODELOS DE REPRESENTAÇÃO 46

3.2 ETAPAS ÍNICIAS DO COMPILADOR 49

3.2.1 CONSTRUÇÃO DO GRAFO DE FLUXO DE CONTROLO 50

3.2.2 IDENTIFICAÇÃO DOS CICLOS 52

xx

3.3 CONSTRUÇÃO DO GRAFO DE DEPENDÊNCIAS DE CONTROLO 53

3.4 EXPOSIÇÃO AUTOMÀTICA DE DEPENDÊNCIAS DE DADOS 54

3.4.1 DEPENDÊNCIAS DE DADOS RELATIVAS A VARIÁVEIS LOCAIS 55

3.4.2 DEPENDÊNCIAS DE DADOS ORIGINADAS PELO USO DA PILHA DE

OPERANDOS 59

3.4.3 DEPENDÊNCIAS DE DADOS RELATIVAS AO USO DE ARRAYS 61

3.4.4 DEPENDÊNCIAS DE DADOS RELATIVAS AO USO DE ATRIBUTOS (CAMPOS) 63

3.5 O GRAFO DE DEPENDÊNCIAS DE DADOS 63

3.6 COMPUTAÇÃO DOS PONTOS DE SELECÇÃO E DA LÓGICA DECISÓRIA DO

PROGRAMA 66

3.6.1 PONTOS DE SELECÇÃO 67

3.6.2 TIPOS DE LÓGICA DECISÓRIA DO PROGRAMA UTILIZADOS 69

3.7 COMPUTAÇÃO DO GRAFO HIERÁRQUICO DE DEPENDÊNCIAS DO

PROGRAMA 72

3.8 CRIAÇÃO DO DFG GLOBAL 73

3.9 CONCLUSÕES 76

CAPÍTULO 4. SUPORTE À GERAÇÃO DE RECONFIGWARE 79

4.1 PRÉ-ETAPAS DO NENYA 79

4.2 ESTRUTURA DO RECONFIGWARE GERADO PELO NENYA 81

4.3 BIBLIOTECA TECNOLÓGICA 82

4.4 MAPEAMENTO DE OPERAÇÕES EM UNIDADES FUNCIONAIS E

ESCALONAMENTOS INICIAIS 86

4.5 ACESSOS A MEMÓRIAS EXTERNAS 92

4.5.1 ESPECIALIZAÇÃO PARA O CÁLCULO DE ENDEREÇOS 92

4.5.2 PARTILHA DE ACESSOS A MEMÓRIAS 94

4.6 ATRIBUIÇÃO DE REGISTOS 95

4.7 PARTILHA DE UNIDADES FUNCIONAIS 97

4.8 GERAÇÃO DO RECONFIGWARE PARA A UNIDADE DE DADOS 100

4.9 SUPORTE DE RETAGUARDA DA GERAÇÃO DE RECONFIGWARE 103

4.10 CONCLUSÕES 104

CAPÍTULO 5. OPTIMIZAÇÕES DO GRAFO DE FLUXO DE DADOS 107

5.1 OPTIMIZAÇÕES DE FLUXO DE DADOS 107

5.1.1 REASSOCIAÇÃO DE OPERAÇÕES 109

xxi

5.1.2 REDUÇÃO DO CUSTO DE OPERAÇÕES 111

5.2 TRABALHOS PRÉVIOS EM AFERIÇÃO DO NÚMERO DE BITS DE

REPRESENTAÇÃO 114

5.3 AFERIÇÃO DE SUBTIPOS PRIMITIVOS NOS BYTECODES 117

5.4 AFERIÇÃO DO NÚMERO DE BITS DE REPRESENTAÇÃO NO NENYA 119

5.5 PROPAGAÇÃO DE PADRÕES DE CONSTANTES AO NÍVEL DO BIT 121

5.6 AFERIÇÃO DO NÚMERO DE BITS EM REGIÕES CÍCLICAS 124

5.7 RESULTADOS 129

5.8 CONCLUSÕES 135

CAPÍTULO 6. PARTIÇÃO TEMPORAL 137

6.1 INCENTIVO PARA A PARTIÇÃO TEMPORAL 138

6.2 PANORÂMICA RELATIVAMENTE À PARTIÇÃO TEMPORAL 140

6.3 FORMULAÇÃO DO PROBLEMA 142

6.4 ESQUEMAS DE SUPORTE À EXECUÇÃO DE FRACÇÕES TEMPORAIS 144

6.5 MÉTODOS BASEADOS NOS ESQUEMAS ASAP/ALAP 146

6.6 O ALGORITMO DE PARTIÇÃO TEMPORAL BASEADO NUM ESCALONADOR

ESTÁTICO EM LISTA 150

6.7 ABORDAGEM BASEADA NO SIMULATED ANNEALING 152

6.8 RESULTADOS EXPERIMENTAIS 156

6.9 CONCLUSÕES 161

CAPÍTULO 7. ESCALONAMENTO BASEADO EM REGIÕES 163

7.1 ESCALONAMENTO E GRAFOS GERADOS 164

7.2 ESCALONAMENTO DE REGIÕES ACÍCLICAS 168

7.3 ESCALONAMENTO DE REGIÕES CÍCLICAS/ACÍCLICAS 170

7.4 ESCALONAMENTO DE REGIÕES CÍCLICAS CONCORRENTES 177

7.5 MELHORIAS DE DESEMPENHO DO HPDG SOBRE O CDFG 180

7.6 CONCLUSÕES 183

CAPÍTULO 8. PROTÓTIPOS E RESULTADOS EXPERIMENTAIS 185

8.1 COMPILADORES GALADRIEL & NENYA 186

8.2 ESTUDOS EXPERIMENTAIS 187

8.3 PROTOTIPAGEM NA FAMÍLIA DE FPGAS XC6200 192

xxii

8.3.1 DESCODIFICADOR DE HAMMING 192

8.3.2 PROBLEMAS COM A INTEGRAÇÃO DAS FASES DE RETAGUARDA 196

8.4 PROTOTIPAGEM NA FAMÍLIA DE FPGAS VIRTEX 197

8.5 CONCLUSÕES 200

CAPÍTULO 9. CONCLUSÕES 203

9.1 TRABALHO REALIZADO 203

9.2 PERSPECTIVAS DE TRABALHO FUTURO 205

APÊNDICE A TECNOLOGIA JAVA 211

APÊNDICE B FLUXO DE COMPILAÇÃO ALVEJANDO ASICS 215

APÊNDICE C IMPLEMENTAÇÃO SIMPLIFICADA DE ALGUMAS

CONSTRUÇÕES ORIENTADAS POR OBJECTOS EM HARDWARE

ESPECÍFICO 219

APÊNDICE D EXEMPLOS UTILIZADOS 223

D.1 GRUPO DE NÚCLEOS DE ALGORITMOS 223

D.2 ALGORITMOS MAIS COMPLEXOS 228

APÊNDICE E INTERFACE SOFTWARE/RECONFIGWARE 233

APÊNDICE F GLOSSÁRIO 239

APÊNDICE G LISTA DE SÍMBOLOS 247

REFERÊNCIAS 251

xxiii

Lista de Figuras

Figura 1.1. Célula representativa da maioria dos FPGAs de granulosidade fina. 4

Figura 1.2. Exemplo de uma matriz de células e de interligações comum na

maioria dos FPGAs comerciais. 4

Figura 1.3. Organização de um sistema de computação com integração de

hardware reconfigurável. 5

Figura 1.4. Número de transístores integrados num único dispositivo. 8

Figura 1.5. Fluxo de compilação. 15

Figura 1.6. Arquitectura alvejada pelo compilador de reconfigware desenvolvido. 15

Figura 1.7. Etapas realizadas pelos compiladores. 20

Figura 2.1. Exemplo de compilação de uma descrição alto-nível para VHDL

comportamental ao nível de transferências entre registos. 26

Figura 2.2. Organização do compilador NAPA C. 30

Figura 2.3. Exemplo de um ciclo do tipo FOR: a) código em Modula-2; b) grafo

de fluxo de dados do corpo do ciclo. 33

Figura 2.4. Grafo de fluxo de dados com os valores calculados e os registos de

pipeline. 33

Figura 2.5. Arquitectura do rDPA. 36

Figura 2.6. Arquitectura do RaPiD. 38

Figura 2.7. Exemplo de agrupamento de operações pelo compilador de C para o

Chimaera. 38

Figura 3.1. Fluxo para obtenção do HPDG e do DFG global no GALADRIEL a

partir dos bytecodes Java. 49

Figura 3.2. a) Instruções da JVM para o método “mult” extraídas dos bytecodes;

b) CFG de blocos básicos obtido. 51

Figura 3.3. Árvore de dominâncias para o exemplo “mult”. 53

Figura 3.4. Exemplo “mult”: a) Árvore de pós-dominâncias; b) CDG. 54

Figura 3.5. Identificação de definições e de usos no exemplo “mult”. 56

Figura 3.6. Conjuntos obtidos pela análise das definições incidentes. 57

xxiv

Figura 3.7. Cadeias de uso-definição (UD). 57

Figura 3.8. Cadeias de definição-uso (DU) e os blocos básicos onde ocorrem as

respectivas definições e usos. 57

Figura 3.9. Algoritmo para computar as cadeias uso-definição. 58

Figura 3.10. Algoritmo para computar as cadeias definição-uso a partir das cadeias

uso-definição. 58

Figura 3.11. Computação das dependências de dados oriundas do uso da pilha de

operandos. 60

Figura 3.12. Algoritmo que analisa as dependências entre blocos básicos ao nível

da pilha de operandos. 60

Figura 3.13. Exemplo que ilustra a sobreposição de elementos em memória: a)

fragmento de código em Java; b) endereços de cada array em

memória para os dois caminhos mutuamente exclusivos. 62

Figura 3.14. Transformação do programa para resolução estática da sobreposição

condicional de dois arrays. 63

Figura 3.15. DDG do exemplo “mult”: os círculos nos laços indicam dependências

entre iterações do ciclo. 64

Figura 3.16. Identificação de conjuntos de blocos básicos mutuamente exclusivos

no CDG: a) exclusividade ao mesmo nível; b) exclusividade em níveis

diferentes. 65

Figura 3.17. Exemplo que identifica as dependências de dados na mesma iteração

de um ciclo. a) CFG do exemplo com dois blocos básicos mutuamente

exclusivos; b) CDG do exemplo. 66

Figura 3.18. a) Exemplo em Java com os blocos básicos identificados; b)

respectivo CFG. 68

Figura 3.19. CDG, DDG e MDG obtidos para o exemplo. 68

Figura 3.20. DDG em que estão representados os pontos de selecção. 69

Figura 3.21. Exemplo que ilustra os caminhos de selecção que permitem

seleccionar, de um conjunto de definições que alcançam um

determinado uso, a definição correcta para o valor específico das

condições. a) CFG do exemplo; b) correspondente CDG. 71

Figura 3.22. Transformações realizadas na vanguarda das fases de compilação: a)

xxv

fragmento de código Java; b) instruções JVM correspondentes; c)

CFG com um DFG por cada bloco básico; d) DDG; e) CDG; f)

HPDG. 73

Figura 3.23. Exemplo da construção do DFG para um bloco básico: a) instruções

JVM do bloco básico; b) correspondente DFG. 74

Figura 3.24. DFG global para o exemplo da Figura 3.22. 78

Figura 4.1. Etapas realizadas pelo NENYA. 80

Figura 4.2. Identificação de um segmento de código com restrição temporal. 81

Figura 4.3. Estrutura do hardware no FPGA. 82

Figura 4.4. Colocação relativa de células no FPGA: a) atributos no VHDL; b)

colocação no FPGA que é sempre relativa ao posicionamento do nível

imediatamente a seguir na hierarquia de componentes. 83

Figura 4.5. Melhoria relativa em termos de área e de atraso para circuitos de

adição do tipo “ripple-carry” gerados pela macrocélula versus

somadores sintetizados pela ferramenta de síntese lógica. 84

Figura 4.6. Descrição de uma macrocélula na biblioteca tecnológica. 85

Figura 4.7. Área dos circuitos de multiplicação sintetizados tendo em conta

diferentes tamanhos (em número de bits) dos operandos e do

resultado. 86

Figura 4.8. Algoritmo do escalonador ASAP sem restrições de recursos baseado

em pilha. 87

Figura 4.9. Algoritmo iterativo do escalonador ASAP sem restrições de recursos. 88

Figura 4.10. Algoritmo do escalonador ASAP sem restrições de recursos quando os

nós do DFG são acedidos por ordem topológica. 88

Figura 4.11. Melhorias dos algoritmos ASAP, com os nós topologicamente

ordenados e com o método iterativo, relativamente ao algoritmo

baseado em pilha. 89

Figura 4.12. Impacto na execução: a) com registos; b) sem registos entre

operações. 90

Figura 4.13. Algoritmo para mapear as operações nas unidades funcionais. 91

Figura 4.14. Algoritmo que, para cada memória, atribui os endereços BASE dos

arrays mapeados na memória considerada. 94

xxvi

Figura 4.15. Acessos à macrocélula de interface com uma memória externa

acoplada ao FPGA. 95

Figura 4.16. Grafo da unidade de dados representativo do DFG global da Figura

3.24 quando os dois arrays são mapeados numa memória de porto

único. 97

Figura 4.17. a) segmento de código Java; b) DFG correspondente; c) DFG com

partilha de um multiplicador entre caminhos mutuamente exclusivos;

d) DFG com partilha do multiplicador e do somador. 99

Figura 4.18. Transformações realizadas no DFG global para aceder à memória

externa quando os arrays não são colocados em posições de memória

que possibilitem a simplificação do circuito de endereçamento. 101

Figura 4.19. Transformação entre a) DFG global e b) correspondente grafo de

hardware; c) parte da estrutura descrita em VHDL. 102

Figura 4.20. Etapas de retaguarda a partir da descrição em VHDL para a família

XC6000 de FPGAs da Xilinx. 104

Figura 5.1. Impacto da utilização de THR na computação do número de bits: a)

cadeia de somadores com três níveis; b) redução do número de níveis

para dois com consequente redução do número de bits. 110

Figura 5.2. Resultados da aplicação de THR e da aferição do número de bits

suficiente no escalonamento de exemplos que somam elementos de

um array. 111

Figura 5.3. Árvore de decomposições da expressão 350 × a. 113

Figura 5.4. Número de operações (adições e multiplicações) obtidas pela

decomposição binária para redução do custo de multiplicações de uma

variável por constantes de 0 a 65.535 com a utilização de adições,

subtracções e deslocamentos. 114

Figura 5.5. Exemplo de aferição de tipos primitivos do DFG. 118

Figura 5.6. Algoritmo de propagação em sentido inverso. 120

Figura 5.7. Algoritmo de propagação em sentido directo. 121

Figura 5.8. Exemplo que reverte os dois primeiros bits de uma palavra: a)

propagação para trás; b) propagação para a frente; c) propagação de

padrões de constantes ao nível do bit. 124

xxvii

Figura 5.9. Número de bits da variável A suficiente para cada iteração. 126

Figura 5.10. Melhorias, em termos de área, do NENYA com optimizações e da

síntese lógica (SL) em relação ao NENYA sem optimizações. 133

Figura 5.11. Melhorias, em termos de atraso, do NENYA com optimizações e da

síntese lógica (SL) em relação ao NENYA sem optimizações. 134

Figura 5.12. Percentagem para o exemplo I da área do circuito dedicada aos

multiplexadores para compilações com e sem as optimizações. 134

Figura 6.1. DFG para o corpo do ciclo do exemplo HAL e o custo de cada

operador. 145

Figura 6.2. Execução do corpo do ciclo do exemplo HAL com partilha temporal

do FPGA. 146

Figura 6.3. Aplicação de dois esquemas de partição temporal: a) pelos níveis de

ASAP; b) pelos níveis de ALAP. 147

Figura 6.4. Algoritmo para partição temporal orientado pela mobilidade de cada

nó e com procura no mesmo nível de ASAP ou ALAP. 149

Figura 6.5. Algoritmo de partição temporal baseado no algoritmo estático de

escalonamento em lista. 151

Figura 6.6. Versão do algoritmo Simulated Annealing para partição temporal. 154

Figura 6.7. Exemplo de um movimento entre fracções temporais considerado

válido pela abordagem SA (Simulated Annealing) apresentada. 155

Figura 6.8. Gráfico comparativo das diversas abordagens. 160

Figura 7.1. a) Exemplo; b) atraso para cada operação do exemplo; c) Os dois

blocos básicos e os DFGs correspondentes; d) Escalonamento ao nível

do bloco básico; e) Agrupamento dos dois blocos básicos e DFG

global; f) Escalonamento com agrupamento de blocos básicos. 166

Figura 7.2. Melhorias relativas do escalonamento interblocos básicos baseado na

granulosidade do operador versus a granulosidade do bloco básico. 167

Figura 7.3. Escalonamento com diferentes ordenações das operações: a) DFG

inicial; b) possível escalonamento com prioridade unicamente baseada

no valor da mobilidade de cada operação; c) escalonamento com

prioridades atribuídas às operações com base na mobilidade e nos

sucessores comuns. 169

xxviii

Figura 7.4. Algoritmo de escalonamento por regiões. 171

Figura 7.5. Algoritmo de escalonamento de regiões cíclicas. 172

Figura 7.6. Algoritmo de criação do STG (State Transition Graph). 173

Figura 7.7. Algoritmo de criação do STG (2ª parte). 174

Figura 7.8. Algoritmo de criação do STG (3ª parte). 174

Figura 7.9. Grafo da unidade de dados gerada pelo NENYA para o exemplo da

soma de dois vectores. 175

Figura 7.10. Escalonamento de operações. 176

Figura 7.11. a) Nível de topo do HPDG para o exemplo Kalman; Diagramas de

blocos que representam as FSMs responsáveis pela execução da

unidade de dados do exemplo: b) quando não há partilha de recursos

entre os ciclos “loop.1” e “loop.4”; c) quando há partilha de recursos

entre os ciclos “loop.1” e “loop.4”. 179

Figura 7.12. Densidade de operações por ciclo de relógio para dois modelos de

representação. 180

Figura 7.13. Número máximo de operações por estado do STG para dois modelos

de representação. 181

Figura 7.14. Desempenhos dos escalonamentos feitos sobre o HPDG e sobre o

CDFG – valores normalizados ao CDFG. 181

Figura 7.15. Densidade de operações por estado do STG para dois modelos de

representação, utilizando uma memória de porto único. 182

Figura 7.16. Número máximo de operações por estado do STG para dois modelos

de representação, utilizando uma memória de porto único. 182

Figura 7.17. Desempenhos dos escalonamentos feitos sobre o HPDG e sobre o

CDFG, utilizando uma memória de porto único. 183

Figura 8.1. Resultados de escalonamentos para várias versões do exemplo

KALMAN considerando várias memórias externas. 188

Figura 8.2. Número de operações em execução num estado do STG para o

exemplo KALMAN considerando vários números de memórias

acopladas ao FPGA. 189

Figura 8.3. Rácios dos melhores e dos piores escalonamentos para as várias

versões sobre o escalonamento considerando uma memória de portos

xxix

múltiplos. 190

Figura 8.4. Efeitos da utilização de THR com uma de um porto ou de portos

múltiplos ou várias memórias para o exemplo KALMAN. 190

Figura 8.5. Degradação do desempenho com uma memória de porto único versus

uma memória multiporto. 191

Figura 8.6. DFG do exemplo HAMMING gerado pelo NENYA. 193

Figura 8.7. Exemplo HAMMING: a) Grafo de fluxo de controlo (CFG); b)

implantação física no FPGA XC6216. 194

Figura 8.8. Efectividade das optimizações do fluxo de dados no desempenho do

reconfigware. 199

Figura 8.9. Efectividade das optimizações do fluxo de dados na área de

reconfigware. 199

Figura 8.10. Acelerações do reconfigware versus software. 200

Figura A.1. Fluxo de compilação/execução da tecnologia Java. 211

Figura B.1. O ambiente de compilação de fragmentos de código Java em hardware

específico com a utilização de uma ferramenta de síntese arquitectural. 215

Figura B.2. Tradução de Java com a utilização de operações de leitura e escrita. 217

Figura C.1. Desdobramento de objectos. 221

Figura C.2. Aplanação da estrutura hierárquica de classes. 221

Figura C.3. Implementação de despacho dinâmico. 222

Figura D.1. Exemplo REVERSE. 224

Figura D.2. Exemplo COUNT8. 224

Figura D.3. Exemplo HAMMDIST. 224

Figura D.4. Exemplo EVENONES. 225

Figura D.5. Exemplo SQRT. 225

Figura D.6. Exemplo USQRT. 226

Figura D.7. Exemplo CRC-32. 226

Figura D.8. Exemplo HAMMING. 227

Figura D.9. Exemplo MULT. 227

xxx

Figura D.10. Exemplo KALMAN. 230

Figura E.1. Biblioteca para comunicação software/hardware: a) Declaração da

classe Java que contém os métodos nativos; b) Cabeçalhos da

declaração dos métodos em linguagem C; c) chamada da classe em

Java. 234

Figura E.2. Exemplo de comunicação entre o software e o reconfigware que

implementa o exemplo apresentado na Figura 3.23. 235

Figura E.3. a) Segmento de software inicial; b) Solução reconfigware/software. 236

Figura E.4. Implantação física (Layout) do exemplo EUCDIST no FPGA

XC6216. 237

xxxi

Lista de Tabelas

Tabela 1.1. Alguns sistemas computacionais reconfiguráveis. 6

Tabela 1.2. O subconjunto da linguagem Java cujas instruções correspondentes da

JVM (Java Virtual Machine) são suportadas correntemente pelo

NENYA é mostrado dentro de rectângulos. 17

Tabela 2.1. Exemplos de arquitecturas. 36

Tabela 2.2. Intervalos de acelerações apresentadas na literatura para dispositivos

que incorporam um microprocessador e lógica reconfigurável. 40

Tabela 2.3. Resumo das características dos compiladores considerados. 41

Tabela 2.4. Resumo das características dos compiladores considerados no que

respeita à possibilidade de partição reconfigware/software. 44

Tabela 5.1. Regras de propagação em sentidos directo e inverso para alguns

operadores. 119

Tabela 5.2. Algumas operações e respectivas simplificações quando em presença

de um operando constante. 122

Tabela 5.3. Codificação e o respectivo valor lógico para cada bit. 123

Tabela 5.4. Regras para a propagação de padrões de constantes ao nível do bit em

alguns operadores. 123

Tabela 5.5. Resultados que ilustram a utilização das optimizações descritas com o

exemplo A. 130

Tabela 5.6. Resultados obtidos com os exemplos B, C e D para optimizações

diferentes. 131

Tabela 5.7. Resultados que ilustram a utilização das optimizações descritas com

os exemplos E, F, G, H e I. 132

Tabela 5.8. Tempos de computação da síntese lógica e do GALADRIEL +

NENYA. 135

Tabela 6.1. Resultados para o corpo do exemplo HAL. 150

Tabela 6.2. Resultados para o exemplo HAL. 158

Tabela 6.3. Resultados para o filtro SEWHA, considerando dois dispositivos com

áreas máximas de 4.096 células e de 16.384 células. 158

xxxii

Tabela 6.4. Resultados para 100 grafos gerados pseudo-aleatoriamente. 159

Tabela 8.1. Macrocélulas utilizadas pelo NENYA para implementar o

descodificador de Hamming. 194

Tabela 8.2. Resultados do reconfigware para o descodificador de Hamming. 194

Tabela 8.3. Resultados da compilação do exemplo HAMMING utilizando várias

optimizações. 196

Tabela 8.4. Resultados da compilação para reconfigware. 198

Tabela D.1. Características do primeiro grupo de exemplos. 228

Tabela D.2. Características dos exemplos considerados: codificação de imagem e

vídeo. 232

Tabela D.3. Características dos exemplos considerados: Filtros de processamento

de imagens. 232

Tabela D.4. Características do exemplo Kalman. 232

Tabela D.5. Características dos outros exemplos considerados. 232

xxxiii

Lista de Exemplos

Exemplo 3.1. Sobreposição de elementos em memória. 62

Exemplo 3.2. Dependências de dados na mesma iteração de um ciclo. 65

Exemplo 3.3. Grafos de representação para um exemplo. 67

Exemplo 3.4. Obtenção da lógica decisória do programa. 70

Exemplo 3.5. DFG para um bloco básico. 74

Exemplo 3.6. DFG global. 75

Exemplo 4.1. Partilha de recursos em caminhos mutuamente exclusivos. 98

Exemplo 4.2. Geração da unidade de dados para o exemplo da Figura 3.22. 102

Exemplo 5.1. Redução do custo de multiplicação por constantes. 112

Exemplo 5.2. Aferição de subtipos primitivos nos bytecodes. 118

Exemplo 5.3. Identificação do número de bits na presença de ciclos. 125

Exemplo 6.1. Corpo do ciclo do exemplo HAL. 145

Exemplo 6.2. Partição temporal orientada pelos níveis de ASAP ou de ALAP. 147

Exemplo 6.3. Corpo do ciclo do exemplo HAL. 148

Exemplo 6.4. Movimentos válidos entre fracções temporais. 155

Exemplo 7.1. Agrupamento de blocos básicos. 165

Exemplo 7.2 Escalonamento de um ciclo. 174

Exemplo 7.3. Execução concorrente de regiões cíclicas. 178

Exemplo B.1. Exemplo da tradução de bytecodes Java para VHDL comportamental. 216

Exemplo C.1. Desdobramento de objectos. 220

Exemplo C.2. Aplanação da estrutura hierárquica de classes. 221

Exemplo C.3. Implementação de despacho dinâmico. 222

xxxiv

1

1. Introdução

"It is a very good thing if you keep your eye on the donut and not on the

hole. In other words follow the story and not to get lost in technology."

David Lynch

Os sistemas computacionais reconfiguráveis têm como característica principal a presença de

hardware que pode ser modificado durante o ciclo de vida do dispositivo. Estes sistemas

combinam a especialização de hardware dedicado e graus de flexibilidade ainda mais

poderosos do que os disponíveis pelos componentes de software. Enquanto que os

componentes software estão limitados à arquitectura do microprocessador utilizado, a

utilização de hardware reconfigurável (reconfigware) permite ter arquitecturas adaptadas às

aplicações.

Embora o conceito de adaptabilidade de uma arquitectura à aplicação tivesse sido introduzido

por Estrin no início da década de 60 [Estrin60], só com o desenvolvimento dos primeiros

dispositivos de lógica programável [Brown96] comercializados em meados dos anos 80 pela

Xilinx [XilinxURL] e pela Altera [AlteraURL], é que alguns investigadores começaram

a visionar a efectividade deste novo paradigma de computação [Gray89] designado por

computação reconfigurável1.

1 Alguns autores designam a computação reconfigurável por computação adaptativa e as máquinas de computação baseadas neste conceito por “máquinas de computação personalizadas no campo” (FCCMs, do inglês: Field-Custom Computing Machines) ou simplesmente por “máquinas de computação personalizadas” (CCMs).

2 CAP. 1 INTRODUÇÃO

A área de computação reconfigurável, enquanto área emergente, tem atraído diversas

comunidades de investigadores. Algumas revistas científicas de âmbito genérico têm dado

ênfase a esta área promissora [Villasenor97][Economist99] que se prevê vir a desempenhar

um papel fundamental na forma como é realizada a computação. Diversas áreas podem

beneficiar deste modelo: os sistemas de comunicação, os sistemas de vídeo, os sistemas

embebidos de 3ª geração [Master99], etc. A par com as conferências internacionais

específicas [FCCMURL][FPLURL][FPGA93-00][RAWURL][MAPURL][EvolvURL] têm

aparecido workshops e sessões especiais em muitas das mais prestigiadas conferências

[DACURL][PACT][SPIE][PDTA][HPCA][HICSS98] (só para citar algumas) que de alguma

forma traduzem o interesse generalizado por esta área.

Contudo, ao nível comercial, o mercado de computação reconfigurável só nos finais dos anos

90 parece ter atraído os fabricantes de dispositivos lógicos programáveis após fabricação

(FPGAs). Uma das experiências mais interessantes foi a fabricação pela Xilinx da série de

FPGAs XC6200 [Xilinx97], que acabou por ser descontinuada. Esta série de FPGAs

representa um dos poucos dispositivos comerciais realmente idealizado para suporte à

computação reconfigurável. Os novos FPGAs integram algumas facilidades vocacionadas

para este paradigma, como sejam os bancos de memória distribuídos pelo agregado,

capacidade de reconfiguração parcial, e tempos de reconfiguração mais reduzidos (família

Virtex [VirtexURL] de FPGAs da Xilinx, por exemplo). Contudo, continua a não haver, por

parte dos principais fabricantes de FPGAs, uma aposta clara e específica para computação

reconfigurável. Entretanto, a comunidade espera que a investigação bem sucedida de

arquitecturas, de ferramentas e de compiladores, e o desenvolvimento de aplicações chave

possam vir a tornar a computação reconfigurável como um modelo dominante em muitas

áreas aplicacionais e possam também sensibilizar os fabricantes de FPGAs.

Com a explosão do consumo de potência em processadores de sinais digitais (DSPs) e

microprocessadores maioritariamente devida às unidades de controlo, busca e descodificação

de instruções e distribuição do relógio pelo integrado (60-90% do consumo de potência total,

dependendo do microprocessador [Brooks99]), ao utilizarem arquitecturas específicas sem

serem baseadas no modelo de software, os FPGAs podem ter um papel fundamental nos

sistemas computacionais do futuro.

Na maioria dos sistemas computacionais reconfiguráveis os dispositivos de reconfigware são

adicionados aos sistemas de software tradicionais com o objectivo de retirar as melhores

CAP. 1 INTRODUÇÃO 3

potencialidades dos dois tipos de computação. Por isso, faz sentido aproveitar algumas ideias

de projecto de sistemas com componentes hardware e software que foram identificadas pela

comunidade de co-projecto hardware/software2 [Micheli97]. Embora se possam utilizar e

adaptar algumas dessas ideias a nova dimensão de reconfiguração adicionada ao projecto dos

componentes hardware abre novas perspectivas e requer abordagens adequadas.

Nos últimos anos foram desenvolvidas inúmeras aplicações computacionais em sistemas

reconfiguráveis muitas das quais foram apresentadas em sessões de aplicações das

conferências específicas a este tema enumeradas previamente. Existem áreas de aplicação em

que a utilização destes sistemas fornece implementações com desempenhos inalcançáveis

com sistemas computacionais tradicionais e até com sistemas de topo de gama. Contudo, a

programação destes sistemas assenta tipicamente na experiência dos projectistas de hardware

e, por este motivo, um dos maiores desafios da comunidade que investiga na área de

computação reconfigurável aponta para a investigação e desenvolvimento de ferramentas de

suporte3. Para atrair a comunidade de software (a qual se acredita ter o predomínio no

desenvolvimento de sistemas electrónicos digitais) é necessário que sejam investigadas

formas eficientes de compilar automaticamente para reconfigware aplicações descritas a um

nível de abstracção elevado. Foi com este incentivo que o trabalho desta tese foi efectuado.

1.1 Fundamentos de Computação Reconfigurável

Os FPGAs são os dispositivos com maior utilização pela comunidade de computação

reconfigurável [Hauck98]. Sem perda de generalidade, pode assumir-se que os FPGAs se

baseiam na célula básica representada na Figura 1.1. As saídas da célula podem ser

programadas para serem oriundas de um registo ou do bloco de lógica reconfigurável. Este

bloco pode ser constituído por uma LUT4 ou por um esquema de multiplexadores e é

programado por bits armazenados em memória (SRAM em FPGAs do tipo SRAM). Um

FPGA é constituído por uma matriz (agregado) de células (ver Figura 1.2) com canais de fios

2 Projecto em que se estabelecem compromissos entre componentes hardware e componentes software, com vista à integração conjunta, respeitando os objectivos de desempenho e a tecnologia de implementação. 3 Aconselha-se a consulta de [Compton00], onde é apresentada uma panorâmica do estado-da-arte em sistemas e software para computação reconfigurável. 4 Do inglês: Look-Up Table.

4 CAP. 1 INTRODUÇÃO

cujas ligações podem ser programadas e normalmente de posicionamento simétrico que

permite a posição relativa de blocos e o movimento destes sem nova colocação e

encaminhamento. Em algumas famílias de FPGAs existem também blocos de memória do

tipo RAM distribuídos pelo agregado. Em [Brown96] pode ser encontrada uma panorâmica

sobre dispositivos de lógica programável.

Lógica Reconfigurável

FF

Figura 1 .1 . Célula representat iva da maior ia dos FPGAs de

granulosidade f ina.

célula célula célula

célula célula célula

Figura 1 .2 . Exemplo de um a matr iz de células e de inter l igações comum

na maior ia dos FPGAs comerc ia is .

Alguns FPGAs permitem a reconfiguração parcial do agregado, permitindo a execução de

regiões de reconfigware concorrentemente com a reconfiguração de outras regiões do

dispositivo. A família de FPGAs XC6200 permite a reconfiguração parcial, e permite que um

sistema de hospedagem tenha acesso a todos os registos internos sem necessidade de

encaminhamentos especiais para os pinos do dispositivo [Churcher95]. Em placas que

CAP. 1 INTRODUÇÃO 5

utilizam esta família de FPGAs o acesso aos registos internos é feito por endereçamento e o

software vê os recursos do FPGA mapeados na memória do sistema [Nisbet97].

1.1.1 Organização dos Sistemas para Suporte de Computação

Reconfigurável

A colocação de reconfigware nos sistemas de computação tradicionais pode ser considerada

nas proximidades de quase todos os componentes dos sistemas computacionais, ou mesmo

nos próprios componentes. Este facto deve-se às vantagens de colocação de elementos de

processamento o mais próximo possível do local de armazenamento dos dados durante a

execução. A Figura 1.3 ilustra uma organização computacional tradicional e a existência

possível de reconfigware. Uma das abordagens deste visionamento é a colocação de

pequenas unidades de lógica reconfigurável em memórias [Oskin98], que permite que

pequenas partes da execução de um programa possam ser computadas neste dispositivo sem

intervenção do microprocessador (não necessita de transferências dos dados entre memória e

microprocessador e vice-versa).

L1 Cache

L2

Cache

RW

RW

Barramento de memória

Barramento de E/S

Memória RW RW RW

RW

CPU RW

RW DISCO

Figura 1 .3 . Organização de um s is tema de computação com integração

de hardware reconf igurável (RW).

6 CAP. 1 INTRODUÇÃO

Os sistemas de suporte à computação reconfigurável actualmente existentes podem ser

agrupados em quatro tipos distintos5, baseados na localização do reconfigware:

• Unidades funcionais reconfiguráveis: são sistemas em que um agregado (matriz) de

células lógicas reconfiguráveis integra o microprocessador com acoplamento via

barramento interno com acesso ao ficheiro de registos. Normalmente, a unidade

funcional implementa sequências de instruções e não tem acesso directo ao exterior

do microprocessador nem a memórias internas;

• Co-processadores: do mesmo tipo do sistema anterior mas no qual o agregado pode

ter execução autónoma e tem acesso a memórias internas ou externas;

• Placas conectadas ao sistema de hospedagem: estes sistemas integram as vulgares

placas comerciais de FPGAs que são conectadas normalmente a barramentos de

periféricos do sistema de hospedagem (ligação ao barramento PCI6, por exemplo).

Uma lista bastante exaustiva de placas pode ser consultada em [FCMURL];

• Processadores principais: este tipo de sistemas são uma solução isolada em que o

reconfigware desempenha a computação principal (são sistemas maioritariamente

utilizados para resolver problemas específicos).

Na Tabela 1.1 são apresentados alguns exemplos para cada um dos tipos supraenumerados.

Tabela 1 .1 . Alguns sistemas computacionais reconf iguráveis.

Acoplamento Exemplo de sistemas

Unidade Funcional Reconfigurável

Chimaera [Hauck97][Ye00b] PRISC7 [Razdan94a][Razdan94c][Razdan94a] OneChip [Witting96] ConCISe [Kastrup99][Kastrup00] Active Pages [Oskin98]

Co-Processador NAPA [Gokhale98]

5 Em [Radunovic98] pode ser encontrado um agrupamento diferente para as arquitecturas de sistemas

computacionais reconfiguráveis.

6 Do ingles: Peripheral Controller Interface. 7 Do inglês: Programmable Reduced Instruction Set Computers.

CAP. 1 INTRODUÇÃO 7

DISC8 [Wirthlin95] REMARC9 [Miyamori98] Garp [Hauser97] Piperench [Goldstein99][Goldstein00] RaPiD [Ebeling95] Spyder [Iseli93] MorphoSys [Singh98][Lee00] Lista de Guccione [FCMURL]

Placas para conexão ao sistema de hospedagem

HOT-I,II [Nisbet97] Xputer [Hartenst90][Hartenst95] PRISM I,II [Athanas93][Wazlows93] SPLASH 1,2 [Gokhale90][Arnold92] ArMem [Raimbault93] Teramac [Amerson95] DECPerLe-1 [Moll95] Transmogrifier 1,2 [Lewis98]

Processador Principal RAW [Waingold97] HAL [StarBridURL] DeCypher [TimeLoURL]

1.2 Incentivo para a Investigação em Compiladores para

Sistemas Computacionais Reconfiguráveis

A utilização de reconfigware torna possível acoplar o computador de hospedagem com

recursos hardware mais flexíveis, melhor adaptados à aplicação em execução corrente, e com

a possibilidade de adaptação a novas versões de uma aplicação. Mais ainda, a capacidade de

reconfigurações dinâmicas torna possível a partilha temporal do dispositivo de reconfigware

por tarefas diferentes, que pode reduzir significativamente a área de silício necessária para

implementar o sistema. A diminuição dos tempos de reconfiguração começa de facto a tornar

viável o conceito de “hardware virtual” (baseado na assumpção de que existem recursos

hardware teoricamente ilimitados).

Os dispositivos de reconfigware, como sejam os FPGAs, têm tido aumentos da capacidade

(número de transístores) no mesmo circuito integrado mais acentuados do que o dos

congéneres microprocessadores (ver Figura 1.4). Este crescimento (apenas comparável ao das

memórias RAM) deve-se à regularidade da estrutura dos FPGAs e ao facto destes

dispositivos não terem custos de teste tão elevados como os microprocessadores. Os novos

FPGAs anunciam a existência de 4 milhões de portas de sistema (system gates) [VirtexURL],

8 Do inglês: Dynamic Instruction Set Computer. 9 Do inglês: REconfigurable Multimedia Array Coprocessor.

8 CAP. 1 INTRODUÇÃO

ou seja, cerca de 1 milhão de portas lógicas equivalentes. A taxa de crescimento da

capacidade dos FPGAs acentua cada vez mais a discrepância entre as capacidades actuais no

projecto de hardware e de área disponível [Hartenst96b].

1,0E+06

5,0E+08

1,0E+09

1,5E+09

2,0E+09

2,5E+09

3,0E+09

3,5E+09

4,0E+09

4,5E+09

1996 1997 1998 1999 2000 2001 2002 2003 2004 2005

Ano

Tra

nsí

sto

res

FPGAs micoprocessadores Memórias

Figura 1 .4 . Número de transístores integrados num único disposit ivo.

Fonte para os microprocessadores: [uPURL]. Fonte para os FPGAs:

[Xi l inxURL]. Fonte para as memórias: baseado no tamanho das

memór ias comerc ia l izadas para os PCs.

De um modo geral, os sistemas computacionais reconfiguráveis têm um objectivo comum aos

sistemas de processamento paralelo: diminuir os tempos de computação de aplicações10.

Enquanto que nos sistemas paralelos tradicionais o caminho para a aceleração é a exploração

do paralelismo da aplicação por diferentes microprocessadores, nos sistemas computacionais

reconfiguráveis o caminho é a implementação em reconfigware das zonas do programa

computacionalmente mais intensivas. Nos sistemas computacionais reconfiguráveis a

exploração do paralelismo existente numa aplicação tem a oportunidade de utilizar um

modelo intrinsecamente concorrente (hardware) em vez dos modelos baseados no modelo

sequencial de von Neumann utilizados pela maioria dos sistemas de suporte ao

processamento paralelo. As máquinas personalizadas ao nível da porta lógica não possuem a

10 Outro dos objectivos pode ser a implementação de sistemas de baixo consumo de potência que necessitem da flexibilidade dos FPGAs ou para os quais estes dispositivos sejam soluções de menor custo do que a utilização de ASICs.

CAP. 1 INTRODUÇÃO 9

limitação de largura de banda no carregamento de instruções, facto que limita o desempenho

das arquitecturas paralelas baseadas em vários microprocessadores.

Contudo, apesar de novas arquitecturas terem sido propostas e novos conceitos apresentados

[Radunovic98], a utilização dos sistemas computacionais reconfiguráveis requer etapas

morosas e complexas que requerem conhecimentos específicos de projecto de hardware.

Como foi mencionado em [Smith97], a computação reconfigurável utilizada com o objectivo

de melhorar o desempenho de aplicações necessita de uma metodologia suportada por

compiladores que possam explorar automaticamente as sinergias existentes nestes sistemas.

Enquanto não existir um suporte efectivo a estes sistemas, os programadores de software não

se sentirão atraídos pelo desenvolvimento de aplicações neste modelo, pois a implementação

dos mesmos requer muito tempo de projecto e necessita de especialistas de hardware.

O desenvolvimento de aplicações em sistemas computacionais reconfiguráveis aponta para as

seguintes metodologias:

• Utilização de objectos hardware (cores) fornecidos por vendedores específicos e

desenvolvidos por projectistas de hardware, com interface específico à linguagem de

software utilizada. Este método pode ser apropriado para desenvolvimento de

aplicações que necessitem de funcionalidades standard como sejam: FFTs,

codificadores/descodificadores JPEG, MPEG, etc.

• Utilização de ferramentas que forneçam, a partir de uma descrição da aplicação numa

linguagem com níveis de abstracção elevados, o código objecto para ser executado no

microprocessador e os ficheiros de configuração para programar a parte de

reconfigware.

Esta tese pretende resolver alguns dos problemas existentes ao nível da compilação de

reconfigware incluída no segundo tópico anterior. A possibilidade, contudo, de inclusão de

bibliotecas de componentes reconfigware durante o desenvolvimento de um sistema deve ser

considerada em trabalhos futuros. Esta integração pode não ser uma tarefa simples por

envolver a compilação de interfaces que dependem dos modelos de comunicação utilizados

pelos componentes.

Para se produzirem compiladores eficientes devem ser combinadas técnicas das áreas de

compiladores e de automação do projecto de circuitos integrados de aplicação específica

10 CAP. 1 INTRODUÇÃO

(ASICs). Da última, destacam-se algumas das ideias utilizadas pela comunidade de síntese

arquitectural [Gajski92]. As técnicas de síntese arquitectural permitem a geração do hardware

a partir de descrições a um nível de abstracção próximo dos níveis utilizados em linguagens

de programação de software (linguagem C, por exemplo) com base em componentes pré-

definidos que implementam os operadores da linguagem.

Contudo, muitas das etapas das ferramentas de síntese arquitectural produzem resultados

ineficientes quando o circuito gerado é mapeado num FPGA pelas razões seguintes:

• a arquitectura baseada num ficheiro de registos é centralizada e necessita da análise de

vida das variáveis de forma a utilizar o menor número possível de registos, enquanto

que num FPGA os registos são distribuídos e em número elevado;

• a partilha de unidades funcionais, por exemplo somadores, produz resultados práticos

ineficientes, pois na maioria dos FPGAs, a área de um somador do tipo ripple-carry é

similar à área de cada um dos componentes necessários para a implementação da

partilha de qualquer unidade funcional11: circuitos de selecção de entradas

(multiplexador, por exemplo) e registos;

• a partilha de recursos pode complicar a colocação e encaminhamento e produzir

resultados inesperados.

A maioria dos sistemas de síntese arquitectural utiliza um conjunto discreto de componentes

sem parametrização durante o escalonamento (o que conduz em muitos casos a um

desnecessário sobredimensionamento face ao número de bits requerido pelas operações) de

forma a facilitar o mapeamento e o escalonamento, que mesmo assim continuam a ser

problemas computacionalmente árduos (difíceis) [Micheli94][Gajski92]. A maioria das

ferramentas afere um componente mesmo quando a funcionalidade não requer lógica

(deslocadores por constantes, por exemplo).

O tempo de computação necessário por estas ferramentas (síntese arquitectural, síntese

lógica, colocação e encaminhamento) é inaceitável para a comunidade de sistemas

computacionais reconfiguráveis, que prognostica ferramentas com tempos de computação

11 Partilhas baseadas em colocação dos operandos em série não necessitam de circuitos de selecção mas de registos com deslocamento.

CAP. 1 INTRODUÇÃO 11

competitivos com os tempos gastos pelos compiladores de software. Em [Postula98] a síntese

arquitectural de um algoritmo computacionalmente intensivo descrito em VHDL

comportamental que foi traduzido directamente (preservando as construções iniciais) de uma

versão em Fortran requereu 22 horas para produzir um circuito com 429 CLBs12 (duas vezes

mais lento e 30% maior do que uma versão especificada manualmente em VHDL-RTL e

posteriormente sintetizada).

Muitas das ferramentas só consideram o paralelismo existente dentro de blocos básicos, facto

que limita o desempenho. Utilizam a técnica de armazenar as variáveis, com cadeias

definição-uso entre blocos básicos, em registos que facilita a selecção das definições de entre

caminhos mutuamente exclusivos, por ser garantida pela máquina de estados que controla o

fluxo de execução, mas pode prejudicar o escalonamento. Este fluxo controlado pela máquina

de estados respeita, na maioria das vezes, o fluxo de controlo originalmente descrito pelo

programador que não é necessariamente o melhor e que foi idealizado tendo em mente o

modelo sequencial de computação.

Pelos motivos supracitados, as técnicas tradicionais utilizadas em síntese arquitectural para

alvejarem ASICs têm de ser redefinidas. Trabalhos iniciais realizados pelo autor desta tese

(ver apêndice B) serviram para identificar estas limitações. A maioria destas limitações deve-

se ao facto do alvo reconfigware permitir reconfiguração e ter uma estrutura pré-definida

(fixa) e por isso sem a liberdade de implantação física (layout) dos ASICs. Devem ser

adicionadas etapas que permitam lidar com a possibilidade de partilha temporal do FPGA,

que pode permitir o uso de áreas de silício menores. A exploração da partilha de operadores,

com viabilidade, pode reduzir o número de configurações necessárias e, por isso, deve

também ser considerada. As capacidades de reconfiguração dinâmica e parcial são outros

factores que podem ser explorados pelas etapas de compilação de modo a que a

implementação final sirva os propósitos do programador de modo mais eficaz.

Em conclusão, para que a computação reconfigurável possa ser adoptada como um

paradigma de computação têm de ser desenvolvidas ferramentas eficientes, rápidas, de fácil

manuseamento e que explorem o conceito de “hardware virtual”. É notório que estas

ferramentas devem resolver as inadequações da síntese arquitectural supraidentificadas.

12 Configurable Logic Blocks de um FPGA XC4010 da Xilinx.

12 CAP. 1 INTRODUÇÃO

1.2.1 Porquê compilar de Java, e em particular dos bytecodes?

A linguagem de programação utilizada não deve estar dependente da informação temporal e

deve permitir ao programador uma abstracção elevada em relação aos recursos de hardware

(arquitectura, componentes, implantação física, etc.). Uma das linguagens de programação

que tem vindo a captar enorme entusiasmo e adeptos em diversas áreas é a linguagem Java

[Gosling97] acompanhada da sua tecnologia de suporte [Gosling96]. Esta linguagem tem sido

considerada para especificação de sistemas hardware/software [Passerone98][Helaihel97]

[Cardoso98a] e hardware [Weaver98] [Bellows98].

A adopção da linguagem Java como linguagem de programação de sistemas computacionais

reconfiguráveis assenta nos seguintes factos:

• Simplicidade da linguagem, sem perda de potencialidades julgadas críticas na

especificação de sistemas complexos;

• Utilização de referências e ausência de ponteiros. Não permite aritmética sobre

referências e a memória de armazenamento é tratada com a atomicidade de objectos

ou de arrays e não por endereços físicos;

• Nível de abstracção elevado e orientação por objectos de raiz;

• Suporte à programação concorrente, pela utilização de threads. Permite que ao nível

de granulosidades mais grossas (por exemplo tarefas, processos) a concorrência seja

especificada explicitamente pelo programador (a este nível é facilmente identificada),

utilizando as capacidades inatas da linguagem de expressar concorrência;

• Tecnologia neutral: independente do sistema operativo e da arquitectura utilizados,

permitindo o desenvolvimento de aplicações portáveis;

• Sintaxe parecida com o C/C++, que facilita a migração dos inúmeros utilizadores

destas linguagens e a tradução do código existente;

• Contém um modelo de tratamento de excepções;

• Existência de ferramentas de compilação e de depuração grátis.

CAP. 1 INTRODUÇÃO 13

Em particular, a utilização do modelo de bytecodes do Java [Gosling95] que utiliza a

máquina abstracta da tecnologia Java (JVM13) [Lindholm96] tem as seguintes vantagens:

• Independente da plataforma de execução;

• Executável;

• Orientado por objectos;

• Mantém quase toda a informação do programa fonte;

• Utilização de referências com atomicidade do objecto ou do array;

• Um modelo de execução na Internet;

• Suporta várias linguagens de programação de software.

A par das vantagens supracitadas, o facto da representação em bytecodes de uma aplicação

ser fruto de algumas etapas iniciais e neutrais de compilação foi outro dos pontos chave que

originou a adopção deste modelo como formato de entrada para o compilador de anteguarda

implementado no âmbito desta tese.

1.2.2 Porquê explorar o paralelismo para além dos blocos básicos?

O grau de paralelismo em cada bloco básico em programas de fluxo de controlo intensivo é

muito baixo, ao contrário dos programas de fluxo de dados intensivo, nos quais os blocos

básicos aparentam muito mais operações e por isso graus de paralelismo muito maiores.

Estudos mostram que o grau de paralelismo ao nível de instruções (ILP14) em cada bloco

básico é tipicamente de 2 a 3,5 [Fisher95]. Por este motivo, nos casos em que o engenho

computacional suporta graus de paralelismo mais elevados é necessário que o compilador

procure paralelismo entre blocos básicos e gere implementações com fluxos de controlo

múltiplos.

13 Do ingles: Java Virtual Machine. 14 Do inglês: Instruction-Level Parallelism.

14 CAP. 1 INTRODUÇÃO

Na compilação para processadores VLIW15 e superescalares alguns autores revelam que a

utilização das optimizações de código e dos escalonadores convencionais não permitiam ter

maior aceleração do que 2 sobre os processadores escalares em aplicações

predominantemente de fluxo de controlo intensivo [Hwu93].

Como em FPGAs existe a liberdade de implementação de arquitecturas adaptadas à aplicação

e suporte efectivo de graus elevados de ILP, a exposição do paralelismo a vários níveis de

granulosidade e escalonadores que lidem eficientemente com o paralelismo exibido devem

ser tarefas de investigação prementes.

1.3 Contribuições da Tese

Esta tese propõe o fluxo de compilação para sistemas computacionais reconfiguráveis

ilustrado na Figura 1.5. O fluxo referido é uma proposta original e os compiladores

implementados de suporte ao mesmo são contribuições originais e bem sucedidas como o

leitor pode constatar pela análise ao estado-da-arte em compiladores para sistemas

computacionais reconfiguráveis baseados em FPGAs. Os dois compiladores novos que

actuam em sequência são:

• Um compilador de anteguarda, designado por GALADRIEL, que recebe um

algoritmo em bytecodes do Java e efectua várias etapas que conduzem a

representações intermédias vocacionadas para as características do hardware.

• Um compilador para reconfigware, designado por NENYA, que tem como alvo a

arquitectura ilustrada na Figura 1.6, constituída por um FPGA acoplado a várias

memórias.

No que se refere ao compilador de anteguarda, são propostas e implementadas várias análises

que permitem extrair dos bytecodes o paralelismo existente num dado método. Este trabalho

fornece representações intermédias que possibilitam implementações com fluxos de controlo

múltiplos e graus de paralelismo teoricamente sem limites. Segundo julgamos saber foi o

15 Do inglês: Very Long Instruction Width.

CAP. 1 INTRODUÇÃO 15

primeiro trabalho a partir dos bytecodes do Java de uma dada aplicação e a computar os

grafos de representação para um modelo intrinsecamente concorrente.

Reconfigware

CPU

I/O

Memória Principal

Memória

Retaguarda

Descrição RTL-VHDL

Bitstreams

Biblioteca de

Macrocélulas

DFG (DataFlow Graph)

COMPILADOR DE

ANTEGUARDA

Java Classfiles

COMPILAÇÂO PARA

RECONFIGWARE

Java Classfiles com

comunicação com RPUs

GALADRIEL

NENYA Descrição da Arquitectura

Alvo Compilação do

Software

HPDG (Hierarchical Program

Dependence Graph)

Figura 1 .5 . F luxo de compi lação.

RAM

FPGA

RAM

RAM RAM

...

...

SISTEMA DE HOSPEDAGEM

Figura 1 .6 . Arquitectura alvejada pelo compilador de reconfigware

desenvolv ido.

16 CAP. 1 INTRODUÇÃO

No que se refere ao compilador NENYA foram integrados os seguintes algoritmos, que por si

só são contribuições originais:

• Um novo algoritmo de partição temporal baseado no escalonador de lista. Nas fases

de investigação e desenvolvimento do algoritmo o mesmo foi confrontado com outros

algoritmos previamente propostos na literatura e com uma versão do simulated

annealing realizada também no âmbito desta dissertação. Os resultados comprovam a

eficiência, efectividade e robustez do algoritmo desenvolvido. Pelo que é do nosso

conhecimento, foi também a primeira vez que o simulated annealing foi utilizado para

resolver o problema da partição temporal;

• Algoritmos que permitem determinar estaticamente, para cada operando, o número de

bits suficiente para satisfazer a funcionalidade inicial e que desempenham um papel

crucial na compilação para hardware específico como é demonstrado pelos resultados

apresentados;

• Um algoritmo que realiza a propagação de constantes ao nível do bit com resultados

de grande impacto em aplicações que manipulem bits. A eficiência deste algoritmo é

testemunhada pelos resultados obtidos de núcleos de aplicações;

• Um escalonador baseado em regiões que permite efectuar o escalonamento de

estruturas de representação hierárquicas, a implementação de ciclos em hardware

específico e o controlo das sequências de acesso à mesma memória RAM.

Outros dos algoritmos desenvolvidos são implementações adaptadas de análises sólidas

existentes e que servem de etapas para a optimização global e automatização da geração do

hardware. Neste contexto, é possível reivindicar abordagens diferentes de resolução dos

problemas que surgiram, alguns dos quais pelo facto do ponto de partida da compilação

serem programas em linguagem Java.

A versão actual do compilador NENYA aceita os bytecodes correspondentes a enunciados em

linguagem Java de controlo, ciclos, variáveis do tipo array, dados do tipo inteiro (byte,

int), booleano, etc (ver Tabela 1.2). O subconjunto da linguagem aceite presentemente

garante, sem alterações, a compilação de muitos algoritmos realistas, ao contrário da maioria

dos compiladores previamente desenvolvidos (ver capítulo 2).

CAP. 1 INTRODUÇÃO 17

Tabela 1 .2 . O subconjunto da l inguagem Java cujas instruções

correspondentes da JVM são suportadas correntemente pe lo NENYA é

mostrado dentro de rectângulos (♣♣ apenas arrays unidimensionais) .

Tipos de dados Operações Controlo e outros mecanismos

Boolean Byte Short Int char Long Float, double, Referências a arrays♣ Referências a objectos

/, %, *, ++, --, +, -, <<, >>, >>>, ||, &&, &, |, ^, ~, <, >, <=, >=, ==, !=

Tratamento de excepções Invocação de métodos Criação de objectos Criação de arrays♣ While, for, do while Break, continue If, ? :, switch Conversões (cast)

O objectivo de compilar para reconfigware, algoritmos descritos em linguagens de

programação de software com exploração do paralelismo implícito, foi amplamente atingido.

A dissertação e os compiladores nela propostos provam a exequibilidade do fluxo de

compilação apresentado. A efectividade dos compiladores é demonstrada por exemplos

realistas e complexos, que provam o conceito e as análises de optimização propostas.

As ferramentas realizadas permitem o suporte a investigações futuras de novas soluções para

alguns problemas específicos (partição espacial, mapeamento e escalonamento com partilha

de operadores, partição hardware/software, etc.). Sem ferramentas de arquitectura aberta,

onde possam ser integradas, estas tarefas são difíceis de validar e torna-se intrincado avaliar o

seu potencial.

1.4 Estrutura da Tese

A tese é constituída por nove capítulos (incluindo o actual). Na Figura 1.7 estão apresentadas

as etapas que constituem os compiladores GALADRIEL e NENYA e, para cada etapa, é

indicado o capítulo onde o leitor pode encontrar informações. Em alguns capítulos são

apresentados resultados que demonstram a escolha de um método particular. De seguida é

resumido cada um dos capítulos subsequentes.

CAP. 2: COMPILADORES PARA RECONFIGWARE: são descritos os compiladores

para reconfigware encontrados na literatura que de alguma forma estão relacionados com o

trabalho apresentado. Na parte final do capítulo é situado o trabalho realizado no âmbito

desta tese em relação ao estado da arte.

18 CAP. 1 INTRODUÇÃO

CAP. 3: MODELOS DE REPRESENTAÇÃO INTERMÉDIA E SUA CONSTRUÇÃO:

são apresentadas as representações intermédias utilizadas pelos compiladores desenvolvidos e

explicadas as etapas realizadas pelo compilador de anteguarda (GALADRIEL).

CAP. 4: SUPORTE À GERAÇÃO DE RECONFIGWARE: são descritas as etapas de

suporte adoptadas no compilador NENYA com vista à geração de reconfigware especializado

a partir dos modelos de representação intermédios propostos no capítulo 3.

CAP. 5: OPTIMIZAÇÕES DO GRAFO DE FLUXO DE DADOS: são apresentadas as

técnicas de optimização do grafo de fluxo de dados, as técnicas para a determinação do

número de bits suficiente para preservar a funcionalidade original para cada operação, e as

técnicas que exploram a possibilidade de propagação dos bits constantes e permitem eliminar

lógica desnecessária.

CAP. 6: PARTIÇÃO TEMPORAL: é apresentada a abordagem utilizada na partição

temporal para que a implementação final possa ser executada por multiplexagem do FPGA.

Para tal, é apresentado um novo algoritmo baseado em heurísticas e uma forma de partição

temporal baseada no algoritmo de optimização simulated annealing.

CAP. 7: ESCALONAMENTO BASEADO EM REGIÕES: é apresentado o método de

escalonamento que origina a descrição da máquina de estados responsável pela orquestração

da execução.

CAP. 8: PROTÓTIPOS E RESULTADOS EXPERIMENTAIS: são apresentados

resultados obtidos com os compiladores apresentados considerando exemplos complexos e

são avaliados os impactos das optimizações sobre esses exemplos.

CAP. 9: CONCLUSÕES: são apresentadas as conclusões acerca do trabalho efectuado e

enumeradas algumas ideias e direcções passíveis de investigação e desenvolvimento futuros.

CAP. 1 INTRODUÇÃO 19

Netlists (EDIF)

NENYA

Descrição da Arquitectura

Alvo

Atribuição e Mapeamento de UFs

Partição Temporal & Escalonamento

STG (State Transition Graphs)

RTG (Reconfiguration Transition Graph)

Síntese de FSMs

Atribuição de Registos

Optimizações do DFG

Inferência de Bits

Propagação de Bits Constantes

Reassociação de Operações

Redução do custo de Operações

Caracterização das Macrocélulas

STG para VHDL-RTL

comportamental

DFG para VHDL-RTL estrutural

Tradução de VHDL-RTL Estrutural

para EDIF

GALADRIEL

CAPÍTULO 3

CAPÍTULO 5

CAPÍTULOS 6 e 7

CAPÍTULO 4

CAPÍTULO 4

DFG HPDG

DDG CDG

Bytecodes Java

CFG

MDG

Figura 1 .7 . Etapas real izadas pelos compi ladores.

São partes constituintes desta tese sete apêndices que adicionam algumas explicações e

funcionam como complemento:

APÊNDICE A: é apresentada uma descrição breve sobre a tecnologia Java.

APÊNDICE B: é apresentado um fluxo de compilação que alveja ASICs através da

utilização de uma ferramenta de síntese arquitectural. Este fluxo foi considerado no início dos

trabalhos que conduziram a esta tese.

20 CAP. 1 INTRODUÇÃO

APÊNDICE C: são apresentados alguns conceitos que permitem a implementação

simplificada de algumas construções orientadas por objectos em hardware específico.

APÊNDICE D: é apresentado o modo como é efectuada a interface e a comunicação

reconfigware/software para alguns dos exemplos que foram prototipados.

APÊNDICE E: são apresentados os exemplos considerados durante a tese.

APÊNDICE F: é apresentado o glossário dos termos e acrónimos mais utilizados.

APÊNDICE G: é apresentada uma lista dos símbolos utilizados.

21

2. Compiladores para Reconfigware1

"Did not Gandalf tell you that the rings give power according to the measure of each possessor? Before you could use that power you would need to become far stronger, and to train your will to the domination of others."

J. R. R. Tolkien, The Fellowship of the Ring

Neste capítulo são descritos trabalhos em compilação de programas em linguagens com nível

de abstracção elevado para máquinas de computação reconfigurável. Pretendeu-se descrever

com algum pormenor as abordagens consideradas mais importantes, desde os primeiros

protótipos até aos trabalhos actualmente em investigação e desenvolvimento.

Foi dado maior destaque a compiladores que têm como alvo FPGAs comerciais por estarem

mais relacionados com o trabalho desta tese. Contudo, incluem-se alguns compiladores para

arquitecturas em investigação, desde arquitecturas de granulosidade mais grossa do que a dos

vulgares FPGAs comerciais, a dispositivos que incluem microprocessador e lógica

reconfigurável.

São assim apresentados os compiladores PRISM-I [Athanas93], II [Wazlows93],

Transmogrifier C [Galloway95] e NAPA C [Gokhale98], e ainda os compiladores para o

Garp [Callahan00], para o RaPiD [Cronquist98], para o PipeRench [Budiu99], e para o

Chimaera [Ye00a]. Para finalizar o capítulo são apresentados alguns dos trabalhos em síntese

1 Abreviatura para hardware reconfigurável.

22 CAP. 2 COMPILADORES PARA RECONFIGWARE

de pipelines. Não são considerados trabalhos em síntese lógica dedicados a FPGAs

[Vincent93] por, na maioria dos casos, partirem de um nível de abstracção mais baixo e

utilizarem níveis de representação intermédia ao nível da porta/função lógica.

2.1 Compiladores para FCCMs

O processo de transformação de uma descrição numa linguagem alto-nível numa descrição

capaz de ser directamente interpretada pela máquina alvo considerada, seja esta real ou

virtual, designa-se por compilação. Nos casos em que a máquina alvo tem uma arquitectura

pré-definida (microprocessadores, por exemplo) a descrição obtida programa de algum modo

a execução dos recursos pré-existentes e daí o nome de compilação. Quando a máquina alvo

não tem inerentemente nenhuma arquitectura pré-associada (como é o caso de um ASIC) o

processo designa-se por síntese de hardware, embora no início fosse chamado de

“compilação de silício”. Os FCCMs situam-se entre estes dois tipos de engenhos

computacionais. Embora tenham inerentemente uma arquitectura pré-definida (matriz de

CLBs2 nos FPGAs, por exemplo), têm a flexibilidade de poderem teoricamente implementar

qualquer circuito digital tal como nos ASICs. Este facto origina muitas vezes a utilização dos

dois termos, compilação e síntese, para referenciar o processo anteriormente identificado.

Esta dicotomia entre os dois termos deve-se também ao facto de a comunidade de síntese

arquitectural tratar, ao nível de ferramentas, os FPGAs como ASICs. Contudo, a

especificidade dos primeiros aliada à flexibilidade até então apenas disponível em

componentes software, tem originado interesses na área emergente designada por

computação reconfigurável, e consequente investigação e desenvolvimento de ferramentas de

compilação apropriadas.

Os chamados “compiladores de silício” tiveram origem em finais da década de 80

[Johnson83], [Ullman84], [Girczyc85] e [Trickey85]. A compilação de linguagens alto-nível

em hardware específico foi inicialmente considerada pelos sistemas HARP (Fortran)

[Tanaka89], Flamel (Pascal) [Trickey87], Cyber (C e BDL) [Wakabay91] e [Girczyc85]

(Ada). Depois destas abordagens iniciais a investigação foi centrada para a compilação de

silício a partir de modelos descritivos adequados à representação de hardware específico,

2 Do inglês: Configurable Logic Block.

CAP. 2 COMPILADORES PARA RECONFIGWARE 23

como são os casos das linguagens de descrição de hardware (Verilog e VHDL).

Recentemente, contudo, a compilação a partir de linguagens de programação (C, por

exemplo) tem angariado cada vez mais adeptos e mais esforços de investigação

nomeadamente na área emergente de computação reconfigurável. Esta tendência deve-se a

vários factores:

• Necessidade de níveis de abstracção mais elevados, que possam facilitar a

especificação de sistemas cada vez mais complexos;

• Necessidade de proliferar o conceito por comunidades reticentes aos modelos de

hardware, devido à disparidade entre as semânticas dos modelos de computação;

• Reutilização de inúmeros algoritmos já implementados em linguagens com grande

utilização;

• Constante aumento do número de elementos lógicos em FPGAs, que requer cada vez

mais esforços na inovação com menor ênfase na redução da área.

Compiladores para hardware de descrições efectuadas em alto-nível, sobretudo de C, são

comercializados por algumas empresas. Destes, destacam-se os compiladores de: C-RTL para

Verilog [CLevelURL], ANSI-C para Verilog-RTL [CompiURL], Java para Verilog-RTL

[LavaURL], C para Verilog ou VHDL [FrontierURL], C/C++ para Verilog-RTL

[CynAppsURL], etc. Uma das abordagens engloba na linguagem Verilog semânticas e

sintaxes parecidas com o C [SuperURL]. A iniciativa SystemC [SystemCURL] parece

pretender definir um standard para descrição de sistemas baseado na linguagem C++. Estes

esforços acrescentam às linguagens de software a possibilidade de descrever ao nível RTL3.

Contudo, todos os compiladores descritos foram desenvolvidos para alvejarem hardware não

reconfigurável, e por isso não incluem técnicas específicas para alvejar reconfigware.

Existem duas abordagens para o desenvolvimento de sistemas baseados em FCCMs

utilizando uma linguagem de alto-nível (normalmente de software):

• Implementação do algoritmo com base em componentes a implementar no FPGA que

constituem uma arquitectura de processamento pré-definida (neste caso é vulgar a

3 Do inglês: Register Transfer Level.

24 CAP. 2 COMPILADORES PARA RECONFIGWARE

utilização de mecanismos que possam especificar ao nível RTL). Nesta abordagem é

especificado um sistema digital que implemente o algoritmo;

• especificação do algoritmo como se se tratasse de software puro, com a utilização das

construções permitidas pela linguagem utilizada, e sem qualquer referência implícita

aos componentes alvo utilizados e, por isso, também sem referência à arquitectura que

implementará o algoritmo.

A primeira abordagem tem sido bastante utilizada por permitir a utilização de linguagens

amplamente disseminadas e, através de algumas extensões ou utilização de bibliotecas

apropriadas, capacidades não suportadas por linguagens de descrição de hardware. Alguns

exemplos desta abordagem utilizam C++ [Iseli95], [Mencer98] ou Java [Weaver98],

[Bellows98]. Este tipo de compiladores serão nesta tese identificados por “geradores de

circuitos”, por não incluírem as etapas de um verdadeiro compilador, e por partirem de

descrições muito próximas do hardware a implementar (sendo por isso análogas a linguagens

assembly). Para desenvolver reconfigware com estas abordagens é necessário que o

programador domine o desenvolvimento de circuitos digitais, pois a descrição é ao nível de

portas lógicas ou de transferência entre registos (RTL). Um dos casos de maior sucesso é o

ambiente de desenvolvimento de circuitos digitais em FPGAs designado por JHDL (Java

Hardware Description Language) [Bellows98][JHDLURL], que, com base em APIs4

específicos e na tecnologia Java, inclui simulador, síntese de máquinas de estado,

mapeamento no FPGA alvo, colocação relativa, etc. Existem também interfaces amigáveis

com FPGAs como são os casoss dos APIs JERC [Lechner97] e JBits [Guccione00] para

Java, que permitem que em linguagem Java se programe respectivamente os bitstreams de

FPGAs das famílias Xilinx XC6200, e XC4000 e Virtex.

A segunda abordagem considerada, por estar a um nível de programação distante do nível de

portas lógicas e da arquitectura do hardware (do sistema digital que implementará um

determinado algoritmo), não necessita que o programador seja um perito em projecto de

sistemas digitais. Existem pelo menos duas vertentes nesta abordagem: a transformação do

algoritmo inicial numa descrição VHDL-RTL sintetizável por ferramentas de síntese lógica

para FCCMs (Synplify [Synplicity99] para FPGAs, por exemplo), ou a utilização de

4 Do inglês: Application Program Interface.

CAP. 2 COMPILADORES PARA RECONFIGWARE 25

técnicas de síntese arquitectural para geração das unidades de dados e de controlo, embora

sendo possível utilizar também síntese lógica para optimização, o resultado pode ser

directamente submetido às ferramentas de colocação e encaminhamento (P&R 5) comerciais

com utilização de geradores de circuitos ou de implementações prévias para cada operador

utilizado. É nesta última vertente que se enquadra o trabalho apresentado nesta tese.

Alguns compiladores compilam apenas blocos básicos [Gokhale98][Gokhale95], outros

aceitam também construções condicionais do tipo if-then-else [Ye00a][Chichkov98] e outros

permitem segmentos de código que contêm ciclos [Callahan00][Wazlows93] nos quais se

incluem os compiladores desenvolvidos no âmbito desta tese. Algumas destas limitações são

explicadas por os compiladores terem sempre como alvo uma arquitectura que contém um

microprocessador encarregue de executar as partes da aplicação não suportadas pelo

compilador para reconfigware.

Existem poucos compiladores que integram partição temporal, como o compilador NENYA

desenvolvido neste trabalho, e o ambiente SPARCS (Synthesis and Partitioning for Adaptive

and Reconfigurable Computer Systems) [Ouaiss98a]. Alguns autores investigam o

escalonamento e a partição temporal partindo de grafos de representação inseridos

manualmente [Vasilko96]. Embora estes possam ser obtidos automaticamente por um

compilador de anteguarda, a sua não integração num fluxo de compilação torna morosa a

exploração de exemplos de grandes dimensões.

Existem trabalhos que compilam programas em occam [Page91], Handel-C [Page96], Oberon

[Wirth98], MATLAB (projecto MATCH) [Banerjee00], SA-C (projecto CAMERON)

[Hammes99][Rinker00], Khoros (projecto Champion) [Natarajan99], C (projecto

DEFACTO) [Diniz00][Bondala99a], entre outros, em reconfigware do tipo FPGA. Alguns

deles transformam a descrição fonte em VHDL comportamental ao nível RTL para que

depois uma ferramenta de síntese lógica produza o circuito final. Um dos exemplos anteriores

é o projecto MATCH. Na Figura 2.1 pode ser vista a tradução de um segmento de código

MATLAB para VHDL-RTL comportamental.

Algumas das abordagens não exploram o potencial implícito de paralelização existente em

muitos algoritmos. Alguns destes compiladores, mais simplificados por muitas das etapas

5 Do inglês: Place and Route. Em português: colocação e encaminhamento.

26 CAP. 2 COMPILADORES PARA RECONFIGWARE

intermédias não serem efectuadas, são orientados pela sintaxe da descrição inicial [Page96]

[Wirth98].

Em [Page96] são apresentadas técnicas para compilar para hardware programas em Handel-C

(subconjunto de Occam2 [Page91]). Esta linguagem permite enunciados de paralelização de

operações que permitem ao programador especificar concorrência a níveis de abstracção

baixos. Sendo um compilador orientado pela sintaxe, apenas o paralelismo explicitamente

especificado é considerado em hardware. A abordagem considera que entre atribuições a

variáveis todas as operações são executadas num ciclo. Este facto permite que o hardware

gerado pelo compilador seja independente do FPGA considerado (sem ser considerado uma

biblioteca tecnológica) mas tem a enorme desvantagem de não considerar o facto de haver

grandes desfasamentos entre atrasos para operações diferentes. Esta desvantagem é ainda

mais notória quando são considerados diferentes tamanhos de palavra.

Figura 2 .1 . Exemplo de compi lação de uma descr ição a l to -nível para

VHDL comportamental ao nível de transferências entre registos (RTL) .

Figura extraída de [Baner jee00].

Em [Wirth98] é apresentado um compilador protótipo para compilar programas em Oberon

para reconfigware. Este compilador utiliza um esquema parecido ao anterior.

CAP. 2 COMPILADORES PARA RECONFIGWARE 27

Em [Wo94] é apresentado um compilador de C em agregados de células, que compila

programas num subconjunto da linguagem C em estruturas de portas lógicas. O compilador

fornece a estrutura num formato aceite pela ferramenta de P&R utilizada. O compilador

utiliza a abordagem de compilação para uma máquina de estados algorítmica, na qual o fluxo

de controlo é misturado com as operações. Embora o compilador explore o paralelismo ao

nível do bloco básico é incapaz de o explorar a outros níveis. O compilador não utiliza uma

biblioteca de descrição das características dos operadores. Estes são assumidos como tendo

atraso de um ciclo de relógio e a sua execução é embebida num dos estados da máquina de

estados.

2.2 Compilador Apresentado por Chichkov

Chichkov [Chichkov98][Chichkov97] apresentou outro compilador de um subconjunto de C

que utiliza o formato RTL*6 do GCC [gccURL] para gerar VHDL-RTL comportamental da

parte do código original que é implementado em hardware específico. O compilador não

aceita enunciados com ciclos, arrays, estruturas, ponteiros, chamadas a funções,

recursividade, etc.

O compilador integra um tradutor dirigido pela sintaxe que gera a partir da descrição RTL*

de cada bloco básico uma descrição VHDL-RTL comportamental equivalente. Em

[Chichkov98] são apresentadas implementações combinatórias e sequenciais de cada bloco

básico.

Na abordagem sequencial são utilizados sinais de concluído_entrada e concluído_saída para

sincronizar o funcionamento de um bloco básico. O compilador insere registos nos arcos de

dependências de dados entre blocos básicos e os laços de dependências de controlo são

implementados por sinais que determinam o estado dos registos de saída e de entrada de cada

bloco básico. O compilador assume que a implementação hardware de cada bloco básico

executa num ciclo de relógio, facto que degrada a execução global, pois o ciclo de relógio do

reconfigware para uma região tem de ter período igual ao maior dos atrasos dos blocos

básicos pertencentes a essa região.

6 Representação intermédia utilizada pelo GCC (não confundir com o RTL de especificações para descrever o nível de abstracção em linguagens de descrição de hardware) que é baseada em código de três endereços.

28 CAP. 2 COMPILADORES PARA RECONFIGWARE

Para implementar o reconfigware no FPGA são utilizadas ferramentas comerciais de síntese

lógica e de colocação e encaminhamento.

Embora com grandes limitações no suporte a construções da linguagem C, o compilador

produz, sendo grande parte do processo controlado manualmente, estimativas do software e

do reconfigware (para a família de FPGAs XC4000 da Xilinx) e realiza a partição entre estes

dois componentes baseada na extracção de paralelismo entre blocos básicos.

2.3 Compilador PRISM-I e II

Em [Athanas93] é apresentado um compilador de linguagem C para um sistema constituído

por um processador de propósito geral e FPGAs. Os segmentos de código, sob a forma de

funções, computacionalmente intensivos são compilados em reconfigware de forma a que ao

código software sejam adicionadas operações especiais implementadas em FPGAs.

O compilador foi designado por PRISM [Athanas92] (Processor Reconfiguration Instruction

Set Metamorphosis) e o protótipo inicial por PRISM-I [Athanas93]. Mais tarde foram

apresentados melhoramentos no PRISM-II [Wazlows93], relacionados principalmente com o

suporte de construções da linguagem C. O programador escolhe as funções que deseja que

sejam implementadas como operações especiais e que, por isso, necessitam de ser compiladas

para hardware.

Este compilador foi um dos primeiros trabalhos a integrar totalmente no processo de

compilação a síntese de algumas operações (transparente ao programador). O compilador

aceita um programa como entrada e produz uma imagem mista (reconfigware/software)

como saída. A imagem reconfigware consiste na especificação física utilizada para programar

o agregado reconfigurável, a imagem software consiste em código de máquina vulgar com a

adição de código que realiza a comunicação com os novos elementos computacionais.

O compilador explora o paralelismo existente dentro dos blocos básicos, mas não altera o

fluxo de controlo imposto pelo modelo sequencial utilizado pela linguagem C. O grau de

paralelismo obtido é por isso bastante limitado.

O subconjunto da linguagem C suportado inclui dados do tipo inteiro, instruções condicionais

e ciclos. Não inclui operações de vírgula flutuante, variáveis do tipo array, estruturas de

CAP. 2 COMPILADORES PARA RECONFIGWARE 29

dados mais complexas (registos), ponteiros, etc. O compilador de C da GNU (GCC) é

utilizado como anteguarda (é utilizada a representação intermédia, RTL*, fornecida pelo

GCC).

O compilador pode converter a representação RTL* em VHDL, criar os grafos de fluxo de

controlo e de fluxo de dados e usá-los para gerar a representação do circuito. São utilizadas

ferramentas comerciais para gerar a imagem hardware da representação do circuito.

Os tempos de compilação sem terem em conta a colocação e o encaminhamento são na

ordem dos minutos mesmo para exemplos pequenos [Athanas93]. O compilador é orientado

pelo CFG obtido da descrição fonte e por isso não considera a ordem das instrução de acordo

com as dependências expostas.

Em [Agarwal94] são apresentados melhoramentos relativos à geração da unidade de controlo.

São apresentadas técnicas que permitem o agrupamento de estados relativos a blocos básicos

distintos.

2.4 Transmogrifier-C

Outros dos compiladores que parte de um algoritmo descrito num subconjunto da linguagem

C, com algumas extensões, é o compilador Transmogrifier C [Galloway95]. Este

compilador tem como alvo a família de FGPAs XC4000 da Xilinx. O compilador não permite

a existência no código de entrada de variáveis do tipo array, estruturas de dados do tipo

registo, ponteiros, etc. O programador deve especificar no programa, através de directivas, o

número de bits de cada tipo de representação de inteiros suportada.

O subconjunto da linguagem C é bastante reduzido no compilador apresentado em

[Galloway95]. Não são suportadas multiplicações, divisões, ponteiros, arrays, estruturas,

recursividade, ciclos for e do-while, etc.

O compilador produz uma solução do tipo máquina de estados com operações que apenas

mudam de estado no início de um ciclo ou de uma chamada a uma função. A única forma de

partilha de recursos é realizada pelo programador ao definir funções nas quais integra as

zonas de código cujas implementações deseja serem partilhadas no reconfigware.

30 CAP. 2 COMPILADORES PARA RECONFIGWARE

O compilador realiza algumas optimizações lógicas, embora com bons resultados apenas para

funções lógicas de (até) 4 variáveis.

2.5 Compilador NAPA C

O compilador NAPA C [Gokhale98] (cujo fluxo se encontra ilustrado na Figura 2.2) tem

como objectivo a geração de reconfigware optimizado para implementação de partes de um

programa na linguagem NAPA C. Esta linguagem é um subconjunto da linguagem C

adicionado de algumas características (construções de especificação de paralelismo, tipos de

dados com especificação do número de bits, etc.). Nesta abordagem, o programador declara o

fragmento do código a ser compilado para reconfigware. A linguagem aceita como modelos

de comunicação: chamada de procedimentos (passagem dos parâmetros - executa e retorna o

resultado num número de ciclos de relógio), memória partilhada (o processador de

hospedagem passa os endereços de dados e o reconfigware opera autonomamente) e cadeias-

de-dados7 (interface FIFO8 fornece dados sincronamente com o reconfigware).

MARGE Module Generator

HDL

Software Blocos FPGA

Plataforma Alvo ou

Co-Simulador Hardware/Software FPGA

bitstreams

C ou C paralelo SUIF: pré-processamento e co-síntese Suporte de

Execução Software

Gerador de Módulos

P&R

HDL

Suporte de Execução Hardware

Executável Síntese

Figura 2 .2 . Organização do compi lador NAPA C.

A ferramenta responsável pela geração do reconfigware é o MARGE (Malleable

Architecture Generator) [Gokhale98]. O compilador utiliza uma biblioteca de funções

7 No inglês: streams. 8 Do inglês: First In First Out.

CAP. 2 COMPILADORES PARA RECONFIGWARE 31

(ALUs, contadores, codificadores, filtros, SRAMs, bancos de registos, etc.) parametrizáveis

de acordo com o número de bits dos operandos. Alguns destes elementos são pré-colocados e

pré-encaminhados reduzindo o tempo de compilação total de horas para minutos

[Gokhale97]. As macros podem ser especificadas pelo programador utilizando a ferramenta

Modgen [Gokhale98]. Esta ferramenta utiliza uma linguagem parecida com C, e integra um

ambiente de simulação que permite testar rapidamente cada módulo. São aceites

especificações do número de bits, forma geométrica, etc. O resultado da compilação para

reconfigware é uma descrição RTL com componentes do Modgen.

A ferramenta só compila para reconfigware o conteúdo de blocos básicos. O controlo é

efectuado pelo componente software. O compilador tenta reutilizar componentes sempre que

a unidade funcional seja do tamanho e funcionalidade apropriadas e não esteja a ser utilizada

por uma operação no ciclo escalonado. O escalonamento das operações é feito pela rotulagem

de cada instância do Modgen na descrição RTL do número da instrução e do número do

ciclo. O compilador utiliza um registo por cada variável declarada no programa e o conjunto

de registos necessário para armazenar dados temporariamente (os registos são implementados

pelo banco de registos do Modgen).

Em [Gokhale97] o compilador tem como alvo o FPGA, National Semiconductor CLAy

FPGA9, de granulosidade fina, e em [Gokhale98] o dispositivo NAPA (RISC+FPGA)

[Rupp98].

Em [Gokhale99] é apresentado um algoritmo integrado no compilador NAPA C para mapear

variáveis do tipo array em memórias conectadas ao FPGA. Para reduzir o espaço de

exploração, de cariz exponencial, é utilizada uma técnica de busca, conhecida por

enumeração implícita.

2.6 Síntese de Pipelines em FPGAs

Alguns autores têm-se preocupado com a síntese de circuitos baseados em pipelines na

implementação de ciclos (de último nível10, quando existem encadeamentos) para que a

9 Neste FPGA cada célula tem 3 entradas e duas saídas. O FPGA é reconfigurável parcialmente por cada célula. O CLAy31 pode ser totalmente reconfigurado em cerca de 0,6 ms (8 milhões de portas lógicas por segundo).

32 CAP. 2 COMPILADORES PARA RECONFIGWARE

próxima iteração de um ciclo possa ser executada antes do término da iteração actual. Esta

técnica é conhecida no meio dos compiladores por software pipelining [Muchnick97] e na

área de síntese arquitectural por loop folding [Gajski92].

As técnicas apresentadas para síntese de circuitos com funcionamento em pipelines são

utilizadas em ciclos bem comportados (limites constantes) e com indexação de elementos de

arrays utilizando funções de acesso do tipo affine11. O objectivo destes compiladores, dos

quais se destacam [Weinhardt00] e [Diniz00], é a inserção de registos de forma a que o

circuito possa funcionar à frequência de trabalho da largura de banda das entradas/saídas.

Weinhardt [Weinhardt97][Weinhardt99][Weinhardt00] tem investigado e desenvolvido

técnicas para síntese dos pipelines de modo a obter um circuito eficiente para ser

implementado em FPGAs. As técnicas apresentadas permitem executar todos as operações

dos ciclos de último nível em paralelo. O compilador permite executar o corpo do ciclo

interno em apenas um ciclo desde que não seja necessário seriar os acessos à mesma memória

quando o corpo do ciclo inclui acessos. Em [Weinhardt99][Weinhardt00] são apresentadas

algumas transformações (desenrolamento de ciclos, por exemplo) que potenciam o aumento

do paralelismo. As técnicas descritas são úteis para programas vectorizáveis, como são

muitos dos algoritmos de processamento de sinais e imagens. As técnicas são viáveis apenas

quando existem padrões de acesso a arrays do tipo X[i+c] ou X[-i+c] (i identifica uma

variável de indução, c identifica uma constante) e o ciclo tem um contador que começa por

zero e é sempre incrementado de uma unidade (do tipo: FOR I:=0 TO N DO...). Em muitos

dos casos é possível, com transformações do programa fonte, obter ciclos deste tipo

[Muchnick97].

A unidade de controlo do pipeline sintetizado utiliza contadores que implementam a estrutura

de controlo do ciclo.

A Figura 2.3b ilustra o grafo de fluxo de dados gerado pelo compilador a partir do código do

exemplo ilustrado na Figura 2.3a. A Figura 2.4 apresenta o grafo de fluxo de dados da Figura

2.3b com os registos inseridos para que seja permitida a execução em pipelines.

10 Em inglês: inner loops. 11 Do tipo: C1×X+C2, com C1 e C2 constantes do tipo inteiro;

CAP. 2 COMPILADORES PARA RECONFIGWARE 33

Em [Moisset99][Diniz00] é apresentado outro compilador para sintetizar pipelines. Uma

unidade centralizada controla a execução em pipeline e implementa a interface com a

memória externa. A compilação proposta é baseada na tradução directa da árvore abstracta de

sintaxe (AST12) para VHDL-RTL comportamental. Análise de dependências de dados

determinam o número e o local de buffers e como controlar a execução utilizando pipelines.

O compilador considera a adição de registos de forma a reduzir o número de acessos a

memórias externas.

a) b)

Figura 2 .3 . Exemplo de um cic lo do t ipo FOR: a) código em Modula -2; b)

grafo de f luxo de dados do corpo do ciclo. ( f igura extraída de

[Weinhardt97])

Figura 2 .4 . Grafo de f luxo de dados com os valores calculados e os

registos de pipel ine. ( f igura extraída de [Weinhardt97])

12 Do inglês: Abstract Syntax Tree.

34 CAP. 2 COMPILADORES PARA RECONFIGWARE

2.7 Utilização de Ambientes de Síntese Arquitectural Adaptados

para FPGAs

Algumas ferramentas iniciais tiveram como alvo FPGAs unicamente para efeitos de teste de

circuitos mais tarde implementados em ASICs. Alguns autores pegaram em ferramentas e

conceitos de síntese arquitectural e criaram ambientes para computação reconfigurável. Essas

abordagens são cada vez mais inapropriadas para alvejarem os FPGAs da nova geração

devido ao facto destes não serem meros agregados de células lógicas. O sistema COBRA-

ABS [Duncan98] é um exemplo de uma destas abordagens. Outro exemplo, embora os

autores tenham integrado ferramentas dedicadas a sistemas computacionais reconfiguráveis é

o projecto SPARCS [Ouaiss98a].

A ferramenta COBRA-ABS [Duncan98] sintetiza arquitecturas personalizadas para

algoritmos com grande intensidade de fluxo de dados descritos num subconjunto de C (os

autores não especificam quais as restrições). A ferramenta integra os problemas de partição

espacial, escalonamento, mapeamento e alocação num problema de optimização global

resolvido por um algoritmo baseado no simulated annealing. O sistema alvo do COBRA-

ABS é uma plataforma constituída por vários FPGAs, ASICs de aritmética, e memórias

RAM. O sistema utiliza uma arquitectura alvo tipo VLIW13, com ficheiros de registos (de

dados, de constantes e de endereços) e uma unidade de controlo centrais. Os FPGAs são a

única parte do sistema alvo possível de reconfigurar. As especificações ao nível de

transferência de registos podem depois ser implementadas em FPGAs por ferramentas

comerciais de síntese, de colocação e encaminhamento. A ferramenta utiliza a abordagem da

síntese arquitectural tendo como alvo ASICs e, por isso, incorre nos principais defeitos

daquela abordagem. Embora a utilização do simulated annealing para resolver os problemas

da síntese arquitectural globalmente possa permitir melhorias significativas, os tempos de

computação apresentados tornam proibitiva esta abordagem (11 a 12 horas numa estação de

trabalho Sun Ultra 1/140 para sintetizar um exemplo com 13 operações e 12 acessos à

memória para cada arquitectura de placa considerada) [Duncan98] no contexto de compilação

13 Do inglês: Very Long Instruction Width.

CAP. 2 COMPILADORES PARA RECONFIGWARE 35

para FCCMs. O sistema considera várias memórias acopladas aos FPGAs mas o mapeamento

de arrays em cada uma delas é realizado manualmente.

O sistema SPARCS [Ouaiss98a] aceita descrições comportamentais de grafos de tarefas em

que cada tarefa é especificada em VHDL. O sistema tem como alvo um número de FPGAs e

memórias. As ligações entre FPGAs e as memórias podem ser estáticas ou configuráveis. É

utilizada partição temporal e espacial antes das fases de síntese arquitectural. Em cada uma

destas fases são utilizadas estimativas que entram em linha de conta com as fases seguintes.

São utilizadas ferramentas de síntese lógica e de P&R comerciais como ferramentas de

retaguarda.

2.8 Compiladores para Arquitecturas não Comerciais

Têm sido investigadas e desenvolvidas inúmeras arquitecturas para suporte da computação

reconfigurável. Todas elas têm por base uma matriz de células em que as interligações e a

funcionalidade de cada célula podem ser reconfiguráveis. Ao nível da complexidade

funcional destas células podem-se considerar três subconjuntos de arquitecturas, com

exemplos ilustrados na Tabela 2.1:

• Granulosidade fina: as células podem implementar funções lógicas simples, e para

se implementar, por exemplo, um somador tem de se utilizar várias destas células.

Este subconjunto engloba os FPGAs comerciais;

• Granulosidade média: as células podem implementar operações mais complexas do

que no subconjunto anterior. Algumas das arquitecturas utilizam células que podem

implementar operações lógico-aritméticas;

• Granulosidade grossa: as células são constituídas por verdadeiros núcleos de

processamento que muitas das vezes incorporam um microprocessador e memória

acoplados a uma matriz de lógica reconfigurável com arquitectura que pode ser de um

dos tipos anteriores.

Também é possível utilizar uma camada intermédia que define um modelo de arquitectura

cujas unidades funcionais são reconfiguradas conforme a aplicação. Esta máquina é depois

36 CAP. 2 COMPILADORES PARA RECONFIGWARE

implementada num dispositivo de granulosidade mais fina (um dos exemplos é o

microprocessador DISC [Wirthlin95]). Este tipo de abordagem pode permitir a utilização de

compiladores existentes para, por exemplo, processadores superescalares embora mantenha,

na generalidade, as deficiências dos microprocessadores.

Os elementos de processamento reconfiguráveis que integram agregados de ALUs são

habitualmente designados por Field-Programmable ALU Arrays (FPAAs).

Tabela 2 .1 . Exemplos de arqui tecturas.

Granulosidade de cada célula

Exemplo de dispositivos Tipo de célula Número de bits

FPGAs, CPLDs LUT, multiplexador, registo 2-5 Fina (fio) DPGA [DeHon96] LUT 4 Xputer (rDPA) [Hartenst95][Hartenst90]

ALU + registo 32

MATRIX [Mirsky96] ALU com multiplicador + memória 8 RaPiD [Ebeling95] ALU, multiplicadores, registos, RAM 16

Média (operando)

PipeRench [Goldstein99][Goldstein00]

ALU + Ficheiro de registos de passagem

2-3214

Grossa (dados) RAW [Waingold97] RISC+FPGA+memória 32

No paradigma Xputer [Hartenst90] um rDPA (re-configurable Data-Path Architecture)

[Hartenst95][Hartenst96a] - matriz de ALUs com 32 bits (Figura 2.5) – é utilizado para

realizar o processamento mais intensivo. Estas ALUs de 32 bits podem ser reconfiguradas

para executarem alguns dos operadores da linguagem C. Em [Becker98] é apresentado o

CoDe-X, uma ferramenta para compilar para o Xputer. O objectivo desta ferramenta é o

mapeamento automático das porções mais apropriadas de um programa em C em rPDAs.

Alguns resultados obtidos com esta abordagem foram apresentados em [Hartenst96a], sendo

reportadas acelerações (comparados com a execução dos programas sem suporte de rDPAs)

de 13 para o algoritmo de compressão, e de 70 para um filtro FIR15 bidimensional.

No PipeRench [Goldstein99] é utilizada uma matriz de elementos de processamento. Cada

elemento é constituído por uma ALU e um ficheiro de registos de passagem. A arquitectura

foi realizada para permitir facilidades de computação em pipeline em aplicações baseadas em

14 Têm sido considerados estudos de desempenho considerando granulosidades de 2 a 32 bits. 15 Do inglês: Finite Impulse Response.

CAP. 2 COMPILADORES PARA RECONFIGWARE 37

cadeias-de-dados. A ideia centra-se na virtualização da máquina e encadeamento em

pipelines da execução-reconfiguração. O sistema é programado em DIL16 [Budiu99], que é

uma linguagem de atribuição-única e com operadores do tipo dos de C. A linguagem permite

a especificação discreta do número de bits para cada variável declarada. O programador pode

utilizar essa propriedade ou delegar para os analisadores apresentados em [Budiu00] a

extracção do número de bits. O compilador de DIL para o PipeRench foi apresentado em

[Budiu99]. O compilador expande todas as chamadas a funções, desenrola todos os ciclos

(para implementação no PipeRench são apenas permitidos ciclos com número de iterações

conhecido estaticamente), para produzir um programa planar em código de atribuição-única

sobre o qual são realizadas as análises de extracção de bits, a decomposição de operadores, e

a colocação e encaminhamento. Para esta última etapa são utilizados algoritmos “gulosos”

desenvolvidos pelos autores [Budiu99] que tornam esta fase 2 a 3 ordens de magnitude mais

rápida do que quando realizada por ferramentas comerciais.

Figura 2 .5 . Arquitectura do rDPA (f igura extraída de [Hartenst90]).

No RaPiD [Ebeling95] é utilizada uma matriz linear de unidades funcionais, cujo tipo de

função é determinado pela aplicação, interligadas, como desejado, por barramentos

segmentados (ver Figura 2.6) programáveis após fabricação. O modelo de computação

utilizado é baseado em cadeias-de-dados, os dados entram no pipeline via cadeias-de-dados

de entrada e saem via cadeias-de-dados de saída. O compilador aceita RaPiD C, que é uma

nova linguagem de programação paralela baseada no C, com algumas extensões. A

16 Do inglês: Dataflow Intermediate Language, que é uma linguagem intermédia para compilação de linguagens alto-nível.

38 CAP. 2 COMPILADORES PARA RECONFIGWARE

linguagem permite a especificação de paralelismo, movimento de dados e partição

[Cronquist98].

O compilador extrai os ciclos internos de último nível, desenrola-os e gera a unidade de

dados responsável pela implementação destes.

Outros compiladores têm como arquitectura alvo um microprocessador com conexão a uma

matriz de lógica reconfigurável. Um dos compiladores para uma arquitectura deste tipo é o

compilador de C para o Chimaera [Ye00a]. Neste último, sequências de instruções em C são

agrupadas em uma única operação implementada no reconfigware (Dst = f(src1, scr2, …,

src9);). A Figura 2.7 ilustra um exemplo de agrupamento de instruções.

Memória

A L U

A L U

Memória

Cadeias de

dados de

saída

C adeias de

dados de

entrada

A L U

Multiplicador

A L U

Função Personalizada Multiplicador

Figura 2 .6 . Arquitectura do RaPiD.

r4 = RFUOP #1;

... r2 = r3<<2; r4 = r2+r5; r6 = lw 0(r4); ...

Figura 2 .7 . Exemplo de agrupamento de operações pelo compi lador de

C para o Chimaera [Ye00a].

CAP. 2 COMPILADORES PARA RECONFIGWARE 39

Os objectivos do compilador para o Garp [Hauser97] (constituído por um processador RISC

e uma matriz de lógica reconfigurável integrados no mesmo dispositivo) são permitir a co-

compilação, e reduzir o tempo de mapeamento e colocação tornando-o comparável à

compilação de software.

Este compilador designado por garpcc [Callahan98a] compila programas em linguagem C na

arquitectura Garp. O compilador procura no código por núcleos intensivos (ciclos ou partes

de ciclos) para serem implementados na matriz de lógica reconfigurável, que funciona como

co-processador. O resto do programa é executado no microprocessador. O compilador utiliza

o hiperbloco [Mahlke92], representação utilizada por alguns compiladores para processadores

do tipo VLIW, para identificar a parte de cada ciclo que vai ser implementada em hardware

específico. A formação do hiperbloco é, por enquanto, feita de modo a que instruções que não

podem ser implementadas em hardware (chamadas ao sistema, por exemplo) fiquem fora do

hiperbloco, e pontos de saída deste são utilizados para manter o fluxo de controlo original. As

implementações funcionam com interactividade entre o núcleo de processamento do Garp e

a lógica reconfigurável.

Os blocos básicos contidos num hiperbloco dão origem a um grafo de fluxo de dados (DFG)

transformando o fluxo de controlo em execução predicativa. Em seguida, a ferramenta Gama

[Callahan98b] pega no DFG e gera a configuração para a matriz. O Gama realiza o

mapeamento dos módulos, a colocação e o encaminhamento. Um controlador é sintetizado

pelo Gama para coordenar a execução dos módulos.

O processador e o co-processador reconfigurável têm acesso ao mesmo sistema de memória

(incluindo todas as memórias cache). Por isso, a transferência de dados incorre num custo

adicional pequeno em virtude do reconfigware aceder directamente às memórias do sistema.

Na Tabela 2.2 são apresentados algumas acelerações reportadas na literatura para

arquitecturas de suporte à computação reconfigurável que adicionam a um microprocessador

do tipo RISC um agregado de lógica reconfigurável.

40 CAP. 2 COMPILADORES PARA RECONFIGWARE

Tabela 2 .2 . Intervalos de acelerações apresentadas na l i teratura para

disposi t ivos que incorporam um microprocessador e lógica

reconfigurável .

Arquitectura Garp [Callahan00]

Chimaera [Ye00a]

PipeRench [Goldstein00]

PRISC [Razdan94c]

Aceleração [1,4 a 12,7] [1,14 a 7,19] [12 a 189,7] [1,06 a 1,91] Tipo de comparação: SW = solução software RW = solução reconfigware SW-RW = solução mista

SW versus SW-RW

SW versus SW-RW

SW versus RW

SW versus SW-RW

2.9 Conclusões

Neste capítulo foram apresentados alguns dos compiladores que ilustram o estado-da-arte na

compilação para FCCMs. Foi dado relevo especial aos compiladores que têm como alvo

FPGAs comerciais, por estarem mais próximos do trabalho desenvolvido no âmbito desta

tese. Na parte final do capítulo foram apresentados resumos de alguns compiladores e das

respectivas arquitecturas alvo que têm sido foco de investigações recentes. Muitas das ideias

destes compiladores podem ser utilizadas para compilar para FPGAs comerciais.

A Tabela 2.3 apresenta um resumo, no que diz respeito à compilação para reconfigware, de

alguns dos compiladores descritos mais próximos do apresentado nesta tese. Quando se trata

de compilação para reconfigware, os compiladores apresentados aceitam programas em

subconjuntos das linguagens enunciadas (linha 3 da tabela). A última coluna da tabela refere-

se aos compiladores desenvolvidos no âmbito desta tese.

Muitos dos compiladores iniciais incorporam análises simplificadas e poucas etapas de

compilação. Algumas carências têm a ver com o facto do objectivo de muitos destes

protótipos ter sido a validação do conceito de compilação para reconfigware. Só ultimamente

têm sido consideradas algumas abordagens que utilizam análises adaptadas da área de

compiladores para alto-desempenho.

A maioria dos compiladores propostos exploram o paralelismo existente dentro dos blocos

básicos, mas não alteram o fluxo de controlo único imposto pelo modelo utilizado por

linguagens de programação sequenciais (linguagem C, por exemplo) nem o paralelismo entre

blocos básicos. O grau de paralelismo exposto é por isso bastante limitado e inadequado ao

modelo puramente concorrente do hardware.

CAP. 2 COMPILADORES PARA RECONFIGWARE 41

Alguns compiladores integram etapas de retaguarda que abordam as fases de colocação e

encaminhamento de modo diferente das ferramentas comerciais. Nestas abordagens são

utilizadas heurísticas, para a colocação e encaminhamento do circuito constituído por

componentes, que tornam rápida a compilação da linguagem até às cadeias de bits para

reconfiguração do FPGA. Estas heurísticas, ao contrário da utilização do simulated annealing

por parte da maioria, senão todas, das ferramentas comerciais de colocação e

encaminhamento, não são vocacionadas para a procura de soluções óptimas. É por isso

possível realizar as tarefas de colocação e encaminhamento com tempos de computação na

ordem dos segundos, em vez de minutos ou horas necessários com ferramentas comerciais.

Tabela 2 .3 . Resumo das caracter íst icas dos compi ladores considerados

(as característ icas referem -se à compi lação para reconfigware ). ♠♠

suportada pela ferramenta de síntese lógica. ♣♣real izadas por uma

ferramenta de síntese lógica comercial .

Compilador PRISM-I, II

Transmogrifier-C

Chichkov NAPA C (MARGE

)

Compilador para o Garp

GALADRIEL +

NENYA

Ano da 1ª publicação

1993 [Athanas92][Athana

s93]

1995 [Gallowa

y95]

1997 [Chichkov98][Chichk

ov97]

1997 [Gokhale98][Gokh

ale97]

1998 [Callaha

n98a] [Callaha

n98b]

1998:1999 [Cardoso98a]

Linguagem C C com extensões

C C com extensões (paralelo,...)

C Qualquer linguagem compilável para a JVM

Representações intermédias utilizadas

DFG + CFG

AST CDG + DDG + AST

AST Hiperbloco + DFG

HPDG + DFG

Construções condicionais If-then-else

3 3 3 - 3 3

Ciclos 3 Do tipo while

corpo corpo 3 3

Arrays 3 - - 3 3 3 Mapeamento de arrays em memórias

- - - Automático ou manual

- Manual ou exaustivo

Considera várias unidades funcionais para a mesma operação?

- - - - - 3

Escalonamento - Muda de estado no

- Partilha de

- Estático e baseado em

42 CAP. 2 COMPILADORES PARA RECONFIGWARE

início de ciclos e de chamadas a funções

operações (não é indicado algoritmo)

lista por regiões

Partição temporal - - - - - 3 Dispositivo alvo, resultados apresentados

FPGA, XC4000

FPGA, XC4000

XC4000, FPGA♠

FPGA ♠, NAPA

Garp (uP+FPGA)

FPGA♠ + memória acoplada

Optimização booleana

3 Limitada (bons resultados para funções de até 4 variáveis)

Realizada por uma ferramenta de síntese lógica

Utiliza-ção de macro-células parame-trizáveis

? Utilização de macrocélulas parametrizá-veis

Extracção da largura de bits

Optimiza-ções booleanas

Optimiza-ções booleanas

♣ Especifi-cação pelo progra-mador

- 3 ou ♣

Grau de Paralelismo

Operações ao nível do bloco básico

Operações ao nível do bloco básico

Operações ao nível do bloco básico

Opera-ções ao nível do bloco básico

Opera-ções ao nível do hiper-bloco

Operações ao nível da função

Modelo utilizado para representar o reconfigware (se algum)

Directa-mente bitstreams

Directa-mente bitstreams (XNF)

VHDL comporta-mental

Formato proprie-tário de bit-streams

VHDL estrutural da unidade de dados, VHDL-RTL do STG

Unidade de controlo

FSM FSM com codifica-ção OHE

Mecanis-mo de semáforospor cada bloco básico ou implemen-tação puramente combina-tória

Sequen-ciadores embebi-dos

Sequen-ciadores embebi-dos

FSM

Retaguarda P&R comercial

P&R comercial

P&R comercial

P&R comercial

Gama (ferra-menta dos autores)

P&R comercial

Em conclusão, o trabalho apresentado nesta tese difere das abordagens que têm sido mais

disseminadas pelo facto de compilar algoritmos especificados em software a um nível de

abstracção elevado, e ter como alvo um FPGA com uma ou mais memórias externas

CAP. 2 COMPILADORES PARA RECONFIGWARE 43

acopladas. O algoritmo pode ser textualmente descrito em qualquer linguagem de

programação que possa ser compilada para a JVM. Neste momento, os compiladores

suportam um subconjunto de bytecodes do Java suficientemente lato para permitir a

compilação de exemplos reais. O compilador utiliza janelas temporais de granulosidade

inferior ao período do ciclo de relógio para escalonar operações, considera diferentes

alternativas para a mesma operação, e entra em linha de conta com o número de bits dos

operandos para estimar o atraso e a área de cada operação. Vários graus de paralelismo são

expostos pelo compilador de anteguarda para que se obtenham implementações em

reconfigware eficientes. Análises de inferência do número de bits suficientes para cada

operando de forma a preservar a funcionalidade original são parte integrante dos

compiladores desenvolvidos. Dos compiladores apresentados na Tabela 2.3 é o único que

integra partição temporal. No que se refere à capacidade de explorar paralelismo em

espectros vastos apenas o compilador para o Garp se assemelha ao compilador aqui

apresentado.

Embora não tenha sido dada ênfase à partição reconfigware/software, necessária na maioria

dos compiladores para computação reconfigurável pois a maioria dos sistemas de suporte à

computação reconfigurável incluem componentes software (microprocessadores, por

exemplo) são apresentadas na Tabela 2.4 as propriedades dos compiladores da Tabela 2.3

referentes a este tipo de partição. A maioria das abordagens, quando em presença de

arquitecturas com um microprocessador, opta pela realização manual da partição

reconfigware/software (o utilizador tem de distinguir o segmento de código ou a função que

acha com capacidade para que a implementação em reconfigware possa acelerar o

desempenho global). Uma forma para lidar com instruções com implementações em

reconfigware ineficientes ou impossíveis que possam aparecer no segmento de código a

implementar em reconfigware é a abordagem do compilador para o Garp. Alguns autores,

dos quais destacamos o trabalho de Chichkov, têm desenvolvido métodos quasi-automáticos

para a partição reconfigware/software. Nos últimos anos têm sido investigados pela

comunidade de co-projecto hardware/software métodos para resolver o problema

[Micheli97]. Contudo, no âmbito de sistemas computacionais reconfiguráveis o problema da

partição hardware/software reveste-se de diferenças significativas, que têm a ver com a

capacidade destes sistemas terem teoricamente recursos de reconfigware ilimitados.

44 CAP. 2 COMPILADORES PARA RECONFIGWARE

Tabela 2 .4 . Resumo das caracter íst icas dos compi ladores considerados

no que respei ta à possibi l idade de part ição reconfigware /software. ♣♣

Não podem incluir instruções não suportadas pelo reconfigware .

Compilador Capacidade de partição reconfigware /software

PRISM-I, II O programador escolhe uma função ♣ Transmogrifier-C O programador escolhe uma função ♣ Chichkov Semiautomática. Orientada pelo paralelismo (inclui estimativas do

reconfigware e do software). NAPA-C ♣ Compilador para o Garp Semiautomática. Utilização do hiperbloco para migrar apenas

instruções realizáveis em reconfigware. GALADRIEL + NENYA O programador escolhe uma função ou um segmento de código ♣

45

3. Modelos de Representação Intermédia e sua Construção

“But Galadriel sat upon a white palfrey and was robed all in glimmering white, like clouds about the moon; for she herself seemed to shine with a soft light.”

J. R. R. Tolkien, The Return of the King

Neste capítulo são apresentadas as representações intermédias propostas e utilizadas pelos

compiladores desenvolvidos. Estas representações, ao exibirem explicitamente o paralelismo

ao nível da operação, entre blocos básicos e entre ciclos considerando sempre a granulosidade

da operação, permitem a exploração eficiente de implementações em hardware específico.

Para tal, são utilizados dois modelos de representação que permitem lidar com a hierarquia

definida pelos ciclos no programa fonte e com o paralelismo ao nível da operação nos

agrupamentos de blocos básicos.

Ao longo do capítulo são explicadas as etapas realizadas pelo compilador de anteguarda

implementado no âmbito da tese que permitem a exposição do paralelismo e a construção das

representações intermédias a partir dos bytecodes do Java. Remetemos o leitor não

familiarizado com a tecnologia Java para um resumo situado no apêndice A, no qual pode

encontrar algumas fontes.

46 CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA...

3.1 Modelos de Representação

O grau de paralelismo em cada bloco básico em programas com fluxo de controlo intensivo

(CFI1) é muito baixo (2 a 3,5 [Fisher95]), ao contrário dos programas com fluxo de dados

intensivo (DFI2), nos quais os blocos básicos contêm muito mais operações e por isso

potenciais graus de paralelismo, ao nível da operação/instrução, mais elevados. Em relação à

compilação para reconfigware é necessário que o compilador procure também o paralelismo

entre blocos básicos e permita a execução especulativa de operações e de fluxos de controlo

múltiplos.

A comunidade de síntese arquitectural centrou inicialmente os esforços na automatização do

conceito de gerar a partir de uma descrição alto-nível uma arquitectura específica que

implementa essa descrição. Para isso, serviu-se das análises robustas, e utilizadas

previamente pelos compiladores de software tendo predominantemente como alvo modelos

de computação do tipo von Neumman. Este facto, originou o uso de representações que não

possibilitam elevados graus de paralelismo em aplicações CFI, como por exemplo o uso do

CDFG3 que é a utilização do grafo de fluxo de controlo (CFG4) [Aho86] com cada bloco

básico representado por um grafo de fluxo de dados (DFG5) [Gajski92]. Este modelo tem,

quando se considera um número elevado de unidades funcionais que podem executar em

paralelo, as seguintes desvantagens:

• Um único fluxo de controlo, baseado em descrições feitas propositadamente para o

modelo de computação de von Neumman. Embora na maioria das HDLs6 possam co-

1 Do inglês: Control-Flow Intensive. 2 Do inglês: Data-Flow Intensive. 3 Do inglês Control/Data Flow Graph. Têm existido definições não consensuais do CDFG. Nesta tese referimo-nos à definição em [Gajski92]. Muitos autores chamam ao DFG com nós de branch (SELECT), de merge (END_SELECT), de entry e de exit de CDFG [Ouaiss98b] (embora na maioria dos casos esta representação assuma também apenas um fluxo de controlo). Uma forma especializada desta representação, denominada de CDFG disjunto, permite representar o comportamento do sistema, apresentando dois modelos de grafos separados. Um, responsável pela modelação do fluxo de dados, o outro, responsável pela modelação do fluxo de controlo. Esta representação é referida pois é propícia para a modelação de sistemas baseados em duas unidades, Controlo + Dados. As construções de controlo são mapeadas em nós de fluxo de controlo e atribuições dentro dos blocos básicos são mapeadas em fluxos de dados. Esta representação captura sequência, saltos condicionais, ciclos e actividades operacionais descritas pelas instruções de atribuição em VHDL. 4 Do inglês: Control Flow Graph. 5 Do ingles: Data Flow Graph. 6 Do inglês: Hardware Description Languages. Em português: Linguagens de Descrição de Hardware.

CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA... 47

existir processos concorrentes, este tipo de concorrência só parece fazer sentido a

níveis altos e nunca ao nível de operadores, por se tornar fastidioso e erróneo

descrever paralelismo ao nível de operações;

• Impossibilidade de explorar o paralelismo existente entre blocos básicos;

• Disposição dos blocos básicos apenas pela ordem de um único fluxo de controlo e não

das dependências de dados e de controlo.

Uma representação ao nível da operação é o DFG estendido com nós que permitem a

representação de estruturas de controlo e de ciclos [Eijndhov92][Gajski92]. Embora esta

representação permita o acesso ao nível da operação, o tratamento a este nível é complicado

sem a presença de hierarquias que representem eficientemente os ciclos do programa fonte, e

por isso muitos dos compiladores utilizem como representação de topo o CFG. Pelo que

julgamos saber, as ferramentas de síntese arquitectural embora usem o DFG estendido

mantêm um único fluxo de controlo para representação do código sequencial da descrição

fonte7.

Duas formas conhecidas na literatura de exibir explicitamente os dois tipos de dependências

(de dados e de controlo) são o grafo de dependências de dados (DDG8) e o grafo de

dependências de controlo (CDG9) [Cytron91]. Com estas duas formas pode ser construído

um CFG com um único fluxo de controlo que exibe alguma concorrência entre blocos

básicos. Esta construção, utilizada em [Chichkov98] na partição reconfigware/software,

embora exponha o paralelismo existente entre blocos básicos continua a ser, na perspectiva

do hardware, uma representação de um único fluxo de controlo10.

Os modelos de representação utilizados nesta tese tentam suprimir as lacunas dos modelos

anteriormente revistos no contexto de compilação para engenhos computacionais

personalizados com suporte amplo de paralelismo. É utilizado um grafo que representa a

hierarquia da descrição fonte e no qual cada nó contempla uma região de nós e laços no DFG

7 Normalmente um por cada processo existente na descrição fonte (por exemplo, VHDL). 8 Do inglês: Data-Dependence Graph. 9 Do inglês: Control-Dependence Graph. 10 Chichkov considera fluxos de controlo com execução concorrente entre o componente software e o componente hardware.

48 CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA...

global (representa toda a região de código a ser compilado). A representação hierárquica foi

denominada de grafo hierárquico de dependências do programa (HPDG11), cuja construção

será explicada neste capítulo. Este grafo exibe explicitamente as dependências de dados,

fluxos de controlo múltiplos e os ciclos existentes no programa fonte (nesta representação são

encapsulados em hierarquias). As primeiras etapas do compilador constroem o CFG de

blocos básicos. Como o CFG representa a estrutura sequencial (um único fluxo de controlo)

da função original é necessário expor as dependências de controlo e de dados para que a

função original possa ser representada mais eficientemente e sejam expostos, sempre que

possível, vários fluxos de controlo. Por estes motivos são construídos o CDG, o grafo de

dependências de fusão (MDG12) e o DDG que servirão de suporte à criação do HPDG e do

DFG global.

O DFG global incorpora explicitamente os predicados (condições segundo as quais

determinada instrução é executada) para operações cuja execução dependa de construções

condicionais acíclicas. Um predicado de uma operação define se essa operação será

executada com base na avaliação de uma função lógica cujas variáveis são resultados de

comparações. O uso de predicados foi abordado para conversão de programas com saltos em

código puramente sequencial na formação do hiperbloco13 [Mahlke92]. Esta conversão é

utilizada na compilação de programas para arquitecturas que suportam a execução predicativa

(EPIC [Schlansk00], por exemplo) e transforma dependências sobre uma sequência de saltos

condicionais em dependências sobre uma sequência de comparações que formam funções

lógicas de conjunções e/ou de disjunções designadas por funções lógicas decisórias do

programa14. A transformação completa é designada por predicados completamente resolvidos

e para cada instrução existente num caminho condicional do CFG é lhe associado um

predicado (activado ou desactivado pela lógica decisória do programa).

O processo de compilação foi dividido em diversas etapas. O compilador designado por

GALADRIEL é o responsável pelas etapas que terminam na criação do HPDG e do DFG

11 Do inglês: Hierarchical Program Dependence Graph. 12 Do inglês: Merge-Dependence Graph. 13 Conjunto de blocos básicos que formam um bloco com apenas uma entrada e com várias possibilidades de saída. 14 A criação da lógica decisória do programa é um problema bem compreendido [August99] na compilação para arquitecturas que suportam a execução predicativa, representa a condição para a qual determinada instrução do programa é executada e tem de ser tal que permita o correcto funcionamento da execução em modo predicativo.

CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA... 49

global e que são consideradas etapas de anteguarda (ver fluxo de compilação representado na

Figura 3.1). O GALADRIEL recebe como descrição fonte a classfile [Lindholm96] que

contém o método seleccionado pelo utilizador. No caso da classe que contém o método a

compilar estar representada numa linguagem textual, o passo prévio à execução do

GALADRIEL deverá ser a geração dos bytecodes que a representam por compilação para a

JVM [Lindholm96] (no caso do código ser em Java pode ser, por exemplo, utilizado o javac

[J2SDKURL]).

DFG HPDG

DDG CDG

Bytecodes Java

CFG

MDG

Figura 3 .1 . F luxo para obtenção do HPDG e do DFG global no

GALADRIEL a par t i r dos bytecodes Java .

Nas secções seguintes é descrito em pormenor como são obtidas pelo compilador, dos

bytecodes Java de uma aplicação, as representações intermédias.

3.2 Etapas Inicias do Compilador

O compilador de anteguarda GALADRIEL começa por extrair, da classfile fonte, a

informação necessária (métodos, tabela de excepções, etc.) e armazena-a num modelo

interno.

As análises consideradas pelo GALADRIEL são intraprocedimentais, ou seja apenas são

realizadas ao longo da estrutura interna dos métodos e não incluem análises

interprocedimentais (entre métodos/funções).

50 CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA...

3.2.1 Construção do Grafo de Fluxo de Controlo

O GALADRIEL extrai as instruções da JVM dos bytecodes da classfile para o método

seleccionado (ver o exemplo da Figura 3.2a) e constrói o grafo que representa o fluxo de

controlo, CFG15, em que cada nó (vértice) representa uma instrução JVM, e que como o

próprio nome indica representa o fluxo de controlo do método especificado.

Para analisar as dependências de controlo e de dados o CFG inicial é transformado de tal

modo que cada novo vértice é um bloco básico [Aho86] (ver o exemplo da Figura 3.2b). A

definição de bloco básico é a mesma que a utilizada em [Bik97] e cada bloco básico

representa uma sequência de instruções JVM consecutivas nos bytecodes no qual o fluxo de

controlo entra no início e o único ponto de saída é a última instrução sem a possibilidade de

saltos ou de geração de uma excepção excepto no fim e sem a possibilidade de ser iniciado

excepto na primeira instrução. O interior de um bloco básico pode ser representado por um

grafo acíclico direccionado (DAG16).

Definição 3 -1 17

O CFG, G = (V, E, START, END), consiste num grafo direccionado/orientado

com um conjunto de vértices V que representam instruções e um conjunto de

laços E que representam a dependência de execução entre instruções. O grafo

inclui o vértice START, início do CFG, e o vértice END, término do CFG. O

vértice START não tem predecessores e o vértice END não tem sucessores. Cada

vértice está contido no caminho entre o vértice START e o vértice END. Existe

um laço entre dois nós (ν1, ν2), ambos pertencentes a V, sse a instrução do

vértice ν2 pode ser executada imediatamente a seguir à execução da instrução em

ν1.

15 O CFG referido suporta vértices do tipo switch, como são os casos dos vértices formados pelas instruções da JVM: tableswitch e lookupswitch. 16 Do inglês: Directed Acyclic Graph. 17 A definição é válida para o CFG de blocos básicos em que neste caso onde se lê instrução deve ler-se bloco básico.

CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA... 51

Method mult(II)I 0: iconst_0 1: istore_2 2: iconst_0 3: istore_3 4: goto 14 5: iload_2 6: iload_0 7: iadd 8: istore_2 9: iinc 3 1 10: iload_3 11: iload_1 12: if_icmplt 5 13: iload_2 14: ireturn

0: iconst_0 1: istore_2 2: iconst_0 3: istore_3 4: goto 14

5: iload_2 6: iload_0 7: iadd 8: istore_2 9: iinc 3 1

10: iload_3 11: iload_1 12: if_icmplt 5

13: iload_2 14: ireturn

start

end

BB0

BB2 BB1

BB3

a ) b)

Figura 3 .2 . a) Instruções da JVM para o método “mul t” extra ídas dos

bytecodes; b) CFG de blocos básicos obt ido, no qual os rectângulos

representam os blocos básicos ident i f icados por BB#.

As instruções de invocação de métodos e de criação de objectos formam só por si um bloco

básico. Para a formação de blocos básicos são inicialmente identificados os líderes, tal como

em [Bik97]. Contudo, o GALADRIEL, por omissão, não considera as instruções que podem

gerar excepções como delimitadores de blocos básicos. As regras na formação dos líderes são

as seguintes:

• A primeira instrução no CFG é um líder;

• Todas as invocações de métodos são líderes;

• Qualquer instrução que seja o alvo de saltos condicionais ou incondicionais (if_<>,

goto, tableswitch, lookupswitch, etc.) é um líder;

• Qualquer instrução a seguir a uma invocação de um método ou a um salto é um líder.

52 CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA...

Cada bloco básico consiste em um líder e em todas as instruções que, em sentido directo (do

fluxo), se lhe seguem no CFG até ao líder imediatamente a seguir (exclusive) ou até ao

vértice END.

Neste CFG existe um laço (ν1, ν2) sse o bloco básico ν2 representa instruções JVM a seguir

ao bloco básico ν1 nos bytecodes e ν1 não termina num salto incondicional, ou se a última

instrução de ν1 é um salto (condicional ou incondicional) para a primeira instrução de ν2.

Existe também um laço entre o bloco básico de cada tableswitch ou lookupswitch e

o bloco básico de cada instrução que é definida como alvo destes selectores. Para cada

chamada a sub-rotinas existe um laço da instrução que chama a sub-rotina (jsr ou jsr_w)

até ao primeiro bloco básico da sub-rotina e do bloco básico que contém a instrução ret

(retorno de uma sub-rotina) até ao bloco básico que contém a instrução imediatamente a

seguir ao jsr ou ao jsr_w. Existe também um laço de cada bloco básico que contém uma

instrução que pode originar uma excepção até ao bloco básico de tratamento de excepções e

até ao correspondente bloco básico de término anormal.

3.2.2 Identificação dos Ciclos

De seguida, a partir do CFG formado por blocos básicos de um dado método é determinado o

respectivo conjunto de dominadores [Aho86]. Considerando os vértices ν1, ν2 ∈ V (conjunto

dos nós do CFG), diz-se que ν1 domina ν2 se todos os caminhos do nó START a ν2 contêm o

vértice ν1. Por definição um nó domina-se a si próprio. A árvore de dominâncias, na qual

Dom(νi) ⊂ V, para todos os vértices ν i ∈ V, é criada com o algoritmo iterativo indicado em

[Aho86]. Na Figura 3.3 é apresentado um exemplo de uma árvore de dominâncias.

Um laço (ν2, ν1) ∈ E (conjunto dos laços do CFG) em que ν2 ∈ Dom(ν1) chama-se um laço

refluente [Aho86] e define um ciclo natural L: L ⊂ V, consistindo de todos os vértices que

podem chegar a ν2 sem passarem por ν1. Na presença de ciclos encadeados o conjunto L2

para um ciclo interno está contido no conjunto L1 do ciclo externo. Nesta abordagem

considera-se que o grafo de cada método é redutível, isto é, a única forma de entrar num ciclo

é pelo cabeçalho. Este tipo de grafos permite a partição em dois grafos disjuntos, um obtido

pelos lados afluentes (grafo acíclico), e outro pelos lados refluentes. Como a linguagem Java

CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA... 53

não possui a instrução goto18, os grafos obtidos são sempre redutíveis, e a identificação de

ciclos naturais pelo modo apresentado não tem limitações [Aho86].

start

BB0

BB1

BB2

BB3

Figura 3 .3 . Árvore de dominâncias para o exemplo “mult”: os blocos

básicos BB1 e BB2 per tencem ao c ic lo .

3.3 Construção do Grafo de Dependências de Controlo

Para geração do CDG é primeiramente construída a árvore de pós-dominâncias (ver o

exemplo da Figura 3.4a). Esta é construída de modo similar à árvore de dominâncias, só que

neste caso o CFG é percorrido do fim (nó END) para o princípio (nó START) usando o

sentido inverso do indicado em cada laço. Considerando os vértices ν1 e ν2 ∈ V, diz-se que ν2

pós-domina ν1 se todos os caminhos inversos do nó END a ν1 incluem o vértice ν2. Por

definição um nó pós-domina-se a si próprio.

Com a árvore de pós-dominâncias e o CFG é criado o CDG com base no facto de um nó ν1

ser dependente em termos de controlo do nó ν2 sse:

1. Existir um caminho não nulo de ν2 a ν1, de modo a que ν1 pós-domina todos os

nós após ν2 no caminho, e

2. ν1 não pós-domina estritamente o nó ν2.

18 A instrução existe e é utilizada na JVM. Por isso não é garantido que os bytecodes Java tenham sempre grafos redutíveis (por exemplo quando são obtidos por compilação de um programa numa linguagem que aceite instruções do tipo goto).

54 CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA...

end

BB3

BB1

BB2

BB0

start

BB2 BB3

BB1

BB0 end

T: 2 →→ 1

a ) b)

Figura 3 .4 . Exemplo “mult”: a) Árvore de pós-dominâncias; b) CDG, em

que o laço em torno de um vért ice indica que o b loco básico é o

cabeçalho do c ic lo.

O CDG contém nos laços entre blocos básicos rótulos que indicam em que condição

(verdadeira ou falsa) é executado o bloco básico destino. O CDG obtido para o exemplo

considerado, com o algoritmo implementado, está ilustrado na Figura 3.4b. O rótulo T: 2 → 1

indica que em caso da condição no bloco básico BB2 ser avaliada como verdadeira (T=true)

deve ser realizado o salto de BB2 para BB1.

3.4 Exposição Automática das Dependências de Dados

As dependências de dados podem ser classificadas em quatro subtipos:

§ Dependências verdadeiras (ou de fluxo): ocorrem quando uma instrução I1 escreve

num local que a instrução I2 mais tarde lê. Ex. a = …; …; … = a. Um bloco básico BBi é

fluxo-dependente do bloco básico BBj se usar uma variável definida pela última vez em

BBj e se existir um caminho no CFG entre BBj e BBi;

§ Antidependências: ocorrem quando uma instrução I1 lê um local no qual a instrução I2

mais tarde escreverá. Ex. … = a; …; a = …;

§ Dependências de saída: ocorrem quando uma instrução I1 escreve num local mais tarde

também escrito pela instrução I2. Ex. a = …; …; a = …;

CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA... 55

§ Dependências de entrada: ocorrem quando uma instrução I1 lê um local que a instrução

I2 mais tarde também lerá. Ex. … = a; …; … = a;.

As dependências de entrada não restringem a ordem das instruções, não sendo por isso

consideradas pelo compilador.

Ao nível do código constituído por instruções da JVM foram identificadas várias origens de

dependências de dados: pelo uso das variáveis locais, pelo uso da pilha de operandos, pelo

uso de variáveis do tipo array e pelo uso dos campos (atributos) de um objecto.

Outras dependências identificadas são dependências semânticas tais como a criação de um

objecto e a invocação do seu construtor19.

3.4.1 Dependências de Dados Relativas a Variáveis Locais

São definidas variáveis locais quando aparece no código qualquer instrução que atribui um

valor a uma variável local. No contexto da JVM acontece com as instruções: istore_<l>,

istore, iinc, fstore_<l>, fstore, astore_<a>, astore, dstore_<d>,

dstore, lstore_<l>, ou lstore. Exemplos de definições podem ser visualizados na

Figura 3.5 (d1, d2, etc).

Se N palavras são passadas como parâmetros de um método do tipo static, então a

invocação do método forma a definição inicial das primeiras N variáveis locais do método

invocado (ver definições d1 e d2 na Figura 3.5). No caso do método invocado não ser do tipo

static, a primeira definição contém o apontador this e são inicialmente definidas N+1

variáveis locais.

Quando existe nos bytecodes uma instrução que usa o valor de uma variável local:

iload_<l>, iload, iinc, fload_<l>, fload, aload_<a>, aload, dload_<d>,

dload, lload_<l>, ou lload, diz-se que a variável local é usada. O estudo da utilização

de variáveis é feito pela análise de cada bloco básico. Para cada bloco básico são

identificadas as variáveis locais cujos valores sejam utilizados internamente ao bloco. No

19 Embora o compilador tenha capacidade para as identificar, para efeitos de geração do hardware estas não serão abordadas nesta tese, por não ser permitida a criação de objectos nos segmentos de código a compilar.

56 CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA...

mesmo bloco é considerada sempre a última referência à mesma variável. Exemplo de usos

podem ser visualizados na Figura 3.5.

Method mult(II)I //d1, d2 0: iconst_0 1: istore_2 //d3 2: iconst_0 BB0 3: istore_3 //d4 4: goto 14 5: iload_2 //u1 6: iload_0 //u2 7: iadd BB1 8: istore_2 //d5 9: iinc 3 1 //d6,u3 10: iload_3 //u4 11: iload_1 //u5 BB2 12: if_icmplt 7 13: iload_2 //u6 BB3 14: ireturn

Figura 3 .5 . Ident i f icação de def inições e de usos no exemplo “mult” .

Para se obterem as dependências de dados de fluxo entre blocos do CFG, são determinadas as

cadeias uso-definição e definição-uso [Aho86]. Cada uso ui de uma variável local tem um

conjunto associado UD(ui), constituído por todas as definições que atingem ou alcançam esse

uso20. Por outro lado, cada definição de uma variável local dj tem um conjunto associado

DU(dj), constituído por todos os usos que são atingidos por esta definição.

O compilador GALADRIEL executa um algoritmo que define para cada bloco básico o

conjunto das definições que o alcançam (incidentes). O algoritmo utilizado é o algoritmo

iterativo “worklist” indicado em [Aho86] que se baseia nas equações (3.1) e (3.2).

U)(

)()(iBBpredx

i xOutBBIn∈

= (3 .1 )

))()(()()( xKillxInxGenxOut −∪= (3 .2 )

O algoritmo computa quatro conjuntos para cada bloco básico: as definições geradas (Gen);

as definições mortas (Kill); as definições de entrada (In); e as definições de saída (Out). O

20 Uma definição de uma variável x diz-se que alcança um uso de x se existe um caminho de fluxo de controlo da definição até ao uso que não passe por outra definição de x.

CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA... 57

resultado do algoritmo para o exemplo “mult” é apresentado na Figura 3.6 considerando as

definições e usos identificados na Figura 3.5.

Bloco básico (vi) Gen[vi] Kill[vi] In[vi] Out[vi] BB0 d3, d4 d5, d6 d1, d2 d1, d2, d3, d4 BB1 d5, d6 d3, d4 d1-6 d1, d2, d5, d6 BB2 ∅ ∅ d1-6 d1-6 BB3 d1-6 ∅ ∅ d1-6

Figura 3 .6 . Conjuntos obt idos pela anál ise das def inições incidentes

(d1-6 = d1, d2, d3, d4, d5, d6) .

A Figura 3.7 mostra as cadeias UD para cada uso de uma variável local para o método “mult”

que tem vindo a ser considerado.

u1 u2 u3 u4 u5 u6 UD(u) d5, d3 d1 d4, d6 d4, d6 d2 d3, d5

Figura 3 .7 . Cadeias de uso-definição (UD).

Depois de determinadas as cadeias UD para cada uso de uma variável local, são determinadas

as cadeias DU, pela relação u ∈∈ DU(d) ⇔⇔ d ∈∈ UD(u) [Bik97], e para o exemplo que temos

vindo a considerar obtêm-se as cadeias representadas na Figura 3.8.

d1 d2 d3 d4 d5 d6 BBdef 0 0 0 0 1 1 DU(di) u2 u5 u1, u6 u3, u4 u1, u6 u3, u4 BBuso 1 2 1, 3 1, 2 1, 3 1, 2

Figura 3 .8 . Cadeias de def inição-uso (DU) e os b locos básicos onde

ocorrem as respect ivas def in ições e usos.

Estas cadeias contêm informações para a análise das dependências de dados. Se DU(di) = φ

então a definição não alcança nenhum uso e a correspondente instrução pode ser eliminada

(código morto). Se UD(ui) = φ, então a variável usada não foi iniciada (erro de programa)21.

21 Nunca ocorre na linguagem Java, pois todas as variáveis têm de ser iniciadas.

58 CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA...

Compute Use-Definition (UD) Chains Inputs: Defs Vector, Usages Vector Output: Array of UD Chains CompUD Foreach Usagesi LocalUse = Usagesi.getLocal(); BBNum = Usagesi.getBBNum(); InstNum = Usagesi.getInstNum(); Rd_in = DefsBBNum.getIn(); Rd_gen = DefsBBNum.getGen(); Foreach rd_genj Find y : (Defsy.getDefNum() == rd_genj.value) && (Defsy.getBBNum == BBNum) && (Defsy.getInstNum() < InstNum); If y found If(Defsy.getLocal() == LocalUse) NumDef = Defsy.getDefNum(); UDi.add(rd_inj); Foreach rd_inj Find k : Defsk.getDefNum() == rd_inj.value; If k find If((Defsk.getLocal() == LocalUse) && !((y find) && (NumDef == Defsy.getDefNum()) && (y != Defsk.getdefNum()))) UDi.add(rd_inj);

Figura 3 .9 . Algor i tmo para computar as cadeias uso-definição.

Compute Definition-Use (DU) Chains Inputs: Defs Vector, Usages Vector, Array of UD Chains Output: Array of DU Chains CompUD Foreach Usagesi Defs1 = UDi; Foreach Defs1j Index = Def1j.value; DUindex-1 = DUindex-1.add(i+1)

Figura 3 .10 . Algor i tmo para computar as cadeias def inição-uso a part ir

das cadeias uso-definição.

CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA... 59

Se uma determinada definição da variável local l1 gerada num bloco básico BBj alcança o

uso de l1 no bloco básico BBi, então o bloco i depende, em termos de fluxo de dados

relacionados com as variáveis locais, do bloco j (BBj → BBi).

Como veremos mais à frente não há necessidade de determinar as dependências de dados do

tipo anti e de saída no âmbito das variáveis locais.

3.4.2 Dependências de Dados Originadas pelo Uso da Pilha de Operandos

O compilador GALADRIEL percorre cada instrução no CFG e guarda o estado da pilha de

operandos após a execução de cada instrução. O uso da pilha de operandos pela JVM obedece

a determinadas regras [Lindholm96]. A pilha de operandos contém sempre o mesmo número

de elementos (palavras) antes da execução de uma determinada instrução do CFG, mesmo

que a execução do programa passe por esta instrução repetidamente ou possa entrar vinda de

mais do que um caminho do CFG. É esta propriedade que torna realizável a determinação

estática dos estados da pilha.

Na Figura 3.11 encontram-se entre colchetes os números das instruções, pela ordem dos

bytecodes na correspondente classfile, que mantêm, ou formam, um uso de uma palavra da

pilha para um exemplo. Por exemplo, após a execução da primeira instrução (iconst_0) o

topo da pilha contém o valor 0 (informação representada no primeiro estado da pilha).

Depois do estado da pilha ser determinado para cada instrução é executado o algoritmo

apresentado na Figura 3.12 (para simplificar é apresentada uma versão que não considera as

dependências formadas pelas instruções dup, swap, etc.), que retorna a árvore de

dependências entre blocos ao nível da utilização da pilha. No algoritmo, st_in[ν] representa o

estado da pilha imediatamente anterior ao bloco básico ν e st_out[ν] representa o estado da

pilha imediatamente a seguir ao bloco básico ν. O algoritmo tem por base o seguinte facto:

quando todos os estados que entram num bloco básico saírem do bloco e não forem usados

por mais nenhuma instrução, o correcto funcionamento do bloco não depende de elementos

da pilha de operandos de mais nenhum bloco básico. Na prática a maioria das instruções que

usa operandos da pilha retira-os e coloca um novo operando (os estados da pilha na saída do

bloco são diferentes dos estados da pilha na entrada do bloco). As instruções que utilizam

elementos da pilha sem os retirarem, como é o caso da instrução dup, necessitam que o

60 CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA...

algoritmo teste a existência deste tipo de instruções em cada bloco básico e determine os

blocos básicos fornecedores dos operandos utilizados.

0: iconst _0 [0 CONST 0] 1: istore _2 [ ] 2: iconst _0 [2 CONST 0] 3: istore _3 [ ] 4: goto 14 [ ]

5: iload _2 [5 VAR 2] 6: iload _0 [5 VAR 2 6 VAR 0] 7: iadd [7 EXP] 8: istore _2 [ ] 9: iinc 3 1 [ ]

10: iload _3 [10 VAR 3] 11: iload _1 [10 VAR 3 11 VAR 1] 12: if_ icmplt 5 [ ]

13: iload _2 [13 VAR 2] 14: ireturn [14 VAR]

BB0

BB1

BB2

BB3

Instruções JVM Estados da Pilha

Figura 3 .11 . Computação das dependências de dados or iundas da

ut i l ização da pi lha de operandos.

Input: CFGBB= (V, E), where each vertex of the CFG has information about the stack contents. Output: Dependence graph between BBs of the method. st_in[v1] = stack_state(Last_Inst(v0)); for each vi ∈ V – v0 st_out[vi] = stack_state(Last_Inst(vi)); for each elementj ∈ st_in[vi] if(elementj ≠ st_out[vi]j) vi dependes of CFGBBk : CFGBBk ⊃ Inst[elementj]); for each Instj ∈ vI if(Instj ∈ dup, …) vi dependes of CFGBBk : CFGBBk ⊃ Last_element(stack_state(Instj)); st_In[vI+1] = st_out[vi];

Figura 3 .12 . Algor i tmo que anal isa as dependências entre blocos

básicos ao nível da pi lha de operandos.

CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA... 61

Uma análise ao conteúdo da pilha de modo a que a utilização de constantes guardadas na

pilha de operandos não possa introduzir dependências de dados desnecessárias deve ser

realizada em versões subsequentes do compilador.

3.4.3 Dependências de Dados Relativas ao Uso de Arrays

As dependências de dados oriundas do uso de variáveis do tipo array são computadas da

mesma forma que as das variáveis locais, com a diferença que as definições e os usos são

determinados por inspecção no código do método pelas instruções da JVM de acesso a

elementos do array. Nesta versão do GALADRIEL estas dependências entram em linha de

conta com acessos a arrays diferentes mas não distinguem acessos a elementos diferentes do

mesmo array. Embora as análises à indexação de elementos de arrays possam potenciar a

exposição de graus de paralelismo maiores, foram deixadas para melhoramentos futuros, por

serem de maior complexidade.

As análises de dependências de dados ao nível de arrays necessitam, ao contrário das análises

no contexto das variáveis locais, de considerar também as antidependências e as

dependências de saída. As antidependências são computadas considerando o problema das

definições incidentes em modo inverso (retrocessivo). Com base no atravessamento do CFG

em sentido inverso são computadas as cadeias de definição-uso, considerando os usos como

definições e as definições como usos. As dependências de saída são computadas por simples

atravessamento do CFG sem iterações.

A sobreposição de elementos em memória22, exemplificada na Figura 3.13, é um problema

com análise similar ao problema das “expressões disponíveis” [Muchnick97]. Designamos

este problema por “atribuição de objectos/arrays disponíveis”. Uma atribuição objecto/array

A está disponível num ponto p do programa, se para todos os caminhos no CFG do nó

START até p existe uma atribuição A e nenhuma definição da variável23 atribuída em A entre

a atribuição e p. Para cada atribuição de objectos/arrays disponíveis as duas variáveis usadas

na expressão de atribuição têm de ser tratadas como uma variável única. Por enquanto, este

22 Deve responder à questão: “Podem duas referências aceder sempre/nunca/talvez à mesma posição de memória?” 23 O problema é definido com variáveis locais, pois nos bytecodes as referências a todos os objectos/arrays são guardadas em variáveis locais.

62 CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA...

problema não se encontra resolvido em casos em que condicionalmente possa ser realizada

atribuição da mesma referência, e terá que ser o programador a alterar o código fonte de

modo a que as atribuições a elementos sobrepostos em memória estejam estaticamente

resolvidas (ver Exemplo 3-1).

Exemplo 3 -1 . Sobreposição de e lementos em memór ia .

O exemplo da Figura 3.13a ilustra o caso em que sempre que seja executada

a atribuição (B=A) na linha 6 a atribuição ao elemento 2 do array B na

linha 12 (B[2]=...) seja de facto ao array A, pois ambas as variáveis B e A

identificam, nesse caso, o mesmo array. Uma análise conservadora de

extracção do paralelismo considera que nos pontos de acesso a A ou a B

alcançados no programa pela atribuição (B=A) ambas as variáveis A e B

identificam o mesmo array. Uma possibilidade mais eficiente seria a

resolução estática da sobreposição com base na transformação do tipo da

identificada na Figura 3.14. Nesta transformação quando um ponto P do

programa com um acesso a um array é alcançado por mais do que um

identificador de arrays é transformado no código condicional que permite

seleccionar o identificador correcto (ver linhas 7 a 10 da Figura 3.14).

1. … 2. int[] A = new int[10]; 3. int[] B = null; 4. ... 5. If(t) 6. B = A; 7. else 8. B = new int[10]; 9. ... 10. A[3] = …; 11. ... 12. B[2] = …; 13. ...

A

B A

B A

A[3]= …; B[2] = …;

A[3]= …; B[2] = …;

a ) b)

Figura 3 .13 . Exemplo que i lustra a sobreposição de e lementos em

memória: a ) f ragmento de código em Java; b) endereços de cada array

em memór ia para os dois caminhos mutuamente exc lus ivos.

CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA... 63

1. … 2. int[] A = new int[10]; 3. int[] B = new int[10]; 4. ... 5. A[3] = …; 6. ... 7. If(t) 8. A[2] = …; 9. else 10. B[2] = …; 11. ...

Figura 3 .14 . Transformação do programa para resolução estát ica da

sobreposição condicional de dois arrays.

3.4.4 Dependências de Dados Relativas ao Uso de Atributos (Campos)

Parte das análises das dependências de dados no âmbito de definições/usos de campos de

objectos podem ser realizadas com a determinação das definições incidentes. Contudo, a este

nível as análises devem ter em conta a criação de objectos o que implica análises

interprocedimentais. Uma análise conservativa que não distinga campos do mesmo objecto

(uso da atomicidade do objecto) pode simplificar a análise, embora restrinja a possibilidade

de paralelização. A extracção do paralelismo relativa a campos de objectos reserva-se para

desenvolvimentos futuros.

3.5 O Grafo de Dependências de Dados

A reunião das dependências de dados (dependências ao nível das variáveis locais,

dependências ao nível da utilização da pilha de operandos, etc.) forma o grafo de

dependências de dados (DDG) do método especificado que permite representar

explicitamente o paralelismo ao nível dos dados passível de ser exposto pelas análises

utilizadas. A Figura 3.15 ilustra o DDG para o exemplo “mult” na qual se pode ver uma

dependência entre iterações do ciclo identificada por um laço com um círculo.

Definição 3 -2

O DDG é um grafo direccionado que engloba o conjunto de vértices do CFG de

onde foi obtido, mas em que os laços entre blocos básicos representam

dependências de dados que restringem a ordem pela qual estes blocos devem ser

64 CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA...

executados de forma a preservar a funcionalidade do programa ao nível de

dependências de dados. Cada laço é anotado com a seguinte informação:

• Origem da dependência: variável local, pilha de operandos, ou arrays;

• Identificador da origem: número da variável local, nível da pilha, ou

identificador do array;

• Tipo da dependência: de fluxo, anti, de saída;

• Tipo de ciclo-dependência: na mesma iteração ou entre iterações.

start

BB0

BB2 BB1 BB3

Figura 3 .15 . DDG do exemplo “mult”: os c í rculos nos laços indicam

dependências entre i terações do cic lo.

As dependências de dados na presença de ciclos são agrupadas no DDG em dois conjuntos

distintos:

• O conjunto das dependências originadas por fluxos na mesma iteração (identificadas

na Figura 3.15 por laços sem círculos);

• O conjunto das dependências originadas por fluxos entre iterações diferentes

(originados pelos laços refluentes das regiões cíclicas e identificadas na Figura 3.15

por laços com círculos).

O conjunto de dependências de laços originados pela mesma iteração de um ciclo é um

subconjunto das cadeias de definição-uso tal que24:

24 Considerando o CFG ordenado topologicamente no que respeita aos laços não refluentes.

CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA... 65

1. O identificador do bloco básico do uso é menor que o identificador do bloco básico da

definição, e

2. Não exista um caminho entre o bloco básico do uso e o bloco básico da definição no

CDG, e

3. A dependência não seja entre dois blocos básicos pertencentes a conjuntos

mutuamente exclusivos.

Ao nível do CDG, dois blocos básicos são mutuamente exclusivos se ambos tiverem o

mesmo nó (diferente do nó START e do nó cabeçalho de um ciclo) de raiz na subárvore do

CDG a que ambos pertencem e os laços desse nó a cada um deles tiverem rótulos diferentes.

Na Figura 3.16 são apresentados alguns exemplos.

start

BB1

BB0

F

BB2

T

start

BB0

F

BB2

BB1

BB3

BB4

F

T

T

a ) b)

Figura 3 .16 . Ident i f icação de conjuntos de blocos básicos mutuamente

exclusivos no CDG: a) exclusiv idade ao mesmo nível , BB1

BB2; b)

exclusividade em níveis di ferentes, BB1, BB2, BB3

BB4 e BB2

BB3 .

Def inição 3 -3

Dois conjuntos de blocos básicos são mutuamente exclusivos se por cada

passagem (iteração) da execução do programa apenas um deles puder ser

executado.

Exemplo 3 -2 . Dependências de dados na mesma i teração de um c ic lo .

Na Figura 3.17 são apresentadas duas dependências possíveis de dados

(cujos laços são ilustrados a tracejado por d1 e d2 no CDG) obtidas pela

66 CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA...

análise de definições de alcance. Embora o identificador do bloco básico do

uso seja menor que o identificador do bloco básico da definição, não são

dependências na mesma iteração do ciclo. A dependência d1 é uma

dependência criada pelo nó refluente que forma o ciclo e a dependência d2

é uma dependência entre regiões mutuamente exclusivas e por isso refere-se

também a dependências entre iterações diferentes do ciclo.

start

BB4

BB1

BB0

BB2

BB3

d 1

d 2

start

BB4 T

BB0

BB1 BB2

BB3

end

F

T F

T T

T F

a ) b)

Figura 3 .17 . Exemplo que ident i f ica as dependências de dados na

mesma i teração de um c ic lo . a ) CFG do exemplo com dois b locos

básicos mutuamente exclusivos (BB1

BB2) ; b) CDG do exemplo (os

laços a t racejado representam possíveis cadeias de def in ição-uso).

3.6 Computação dos Pontos de Selecção e da Lógica Decisória

do Programa

No âmbito da compilação, para hardware específico, abordada nesta tese é necessário

determinar os pontos de selecção (pontos do programa ou da representação intermédia onde é

necessário colocar unidades de selecção de entre vários dados oriundos de caminhos

mutuamente exclusivos), os nós condicionais que controlam esses pontos de selecção (que

definem a condição para que um dado oriundo de um determinado caminho alcance o ponto

de selecção) e os nós condicionais que controlam as operações com efeitos colaterais em

caminhos mutuamente exclusivos.

CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA... 67

3.6.1 Pontos de Selecção

Para a representação do programa no DFG global são primeiramente determinados os pontos

de selecção onde são colocadas estruturas de selecção como por exemplo multiplexadores.

Estes pontos de selecção são devidos a definições da mesma variável em pontos do programa

(caminhos mutuamente exclusivos) que permitem que essas definições alcancem um

determinado ponto do DFG.

Por inspecção do DDG o compilador, para cada nó com mais do que um laço incidente e que

represente uma dependência de dados de fluxo rotulada com a mesma variável local, insere

um ponto de selecção que é dependente dos nós exibidos no grafo de dependências de fusão

(MDG). Os pontos de selecção são controlados por lógica decisória do programa que é

constituída por uma função lógica que representa a condição para a qual determinada

definição possa atingir um ponto de selecção. A lógica que controla a selecção é determinada

por inspecção do CDG.

Definição 3 -4

Um ponto de selecção é um ponto no qual deve ser colocado um mecanismo de

selecção que permita escolher entre duas ou mais definições da mesma variável

que alcançam esse ponto.

Definição 3 -5

O MDG é um grafo direccionado em que os laços entre nós (blocos básicos do

CFG) representam dependências de controlo de selecção ou de execução. Os

nós fonte indicam nós controladores e os nós destino indicam os nós que

necessitam de ser controlados.

Exemplo 3 -3 . Grafos de representação para um exemplo.

Considere-se o código Java e o CFG correspondente apresentados

respectivamente nas alíneas a) e b) da Figura 3.18. As variáveis locais da

JVM l0, l1 e l2 correspondem respectivamente às variáveis no código Java

f, h e e. A Figura 3.19 ilustra os grafos DDG, CDG e MDG obtidos para

o exemplo. O laço a tracejado entre BB0 e BB1 indica uma dependência de

saída, que como foi previamente explicado não é considerada. No DDG

representado pode ver-se que cada uma das variáveis l1 e l2 tem mais do

68 CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA...

que uma definição a atingir o BB3. A definição de l1 em BB2 ou o valor de

l1 passado como argumento da função atinge BB3 caso o teste da condição

na linha 3 da Figura 3.18a seja respectivamente falso ou verdadeiro. Por

este motivo é colocado um ponto de selecção para seleccionar de entre as

duas ligações de l1 que atingem BB3 com base no valor da comparação

referida. Pode ver-se também que para l2 também existem duas ligações a

atingirem o BB3 e por isso é necessário mais um ponto de selecção. O

MDG do exemplo representado por um laço entre BB0 e BB3 indica que os

pontos de selecção em BB3 dependem da comparação em BB0. A inserção

de pontos de selecção, sob a forma de multiplexadores, pode ser vista na

Figura 3.20. A transformação permite que os blocos básicos BB1 e BB2

sejam executados especulativamente (executados em paralelo ou antes da

execução de BB0).

1. static int ex(int f, int h) 2. int e = 0; BB0 3. if(f<4) BB0 4. e = f + h; BB1 5. else 6. h = 3 * h; BB2 7. e = 3 * h + e; BB3 8. return e; BB3 9.

2

3

start

0

1

end

T F

a ) b)

Figura 3 .18 . a ) Exemplo em Java com os blocos básicos identi f icados;

b) respect ivo CFG.

2

3

start

0

1

end

2

start

0

1

l0, l1

l0, l1

l2

DDG CDG

l2 l1

l1

0

0

start

0

3

MDG

T F

Figura 3 .19 . CDG, DDG e MDG obt idos para o exemplo .

CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA... 69

2

3

start

0 1

end

l0, l1

l1_1

l1

l2_1 l2

l2_2 l1_2

Mux(l1, l1_1) Mux(l2, l2_1)

Figura 3 .20 . DDG em que estão representados os pontos de se lecção.

3.6.2 Tipos de Lógica Decisória do Programa Utilizados

Um modelo com computação especulativa de todas as operações excepto a escrita em

memória, apenas requer lógica decisória nos pontos de selecção e nos pontos de escrita em

memória25 que pertençam no CFG a caminhos mutuamente exclusivos. No âmbito desta tese

são, por isso, considerados dois tipos de lógica decisória do programa:

• Lógica decisória de selecção26: responsável pela selecção da definição correcta de

uma variável;

• Lógica decisória de execução: responsável pela execução de uma operação (atribuição

a um elemento de um array, por exemplo).

Como os registos são só usados para preservar a funcionalidade dos ciclos, e são colocados à

frente dos pontos de selecção que possam existir no corpo de um ciclo, a decisão de escrita é

feita inteiramente pela unidade de controlo cuja geração é descrita no capítulo 7.

Surgem duas questões na construção da lógica decisória do programa:

• Como obter expressões com o mínimo de condições na lógica decisória do programa?

• Como obter o mínimo de lógica decisória do programa?

25 Nestes casos, e devido aos acessos a memórias terem execução síncrona, a lógica decisória é utilizada pela unidade de controlo para decidir a execução ou não da operação em causa. 26 A condição sob a qual uma definição atinge um nó confluente no CFG foi também considerada como extensão do formato Single Static Assignment (SSA) [Cytron91] e foi denominada de Gated Single-Assignment (GSA) [Balance90].

70 CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA...

O primeiro problema é resolvido pela determinação da função lógica decisória do programa

tomando como base o caminho de selecção no CDG de cada definição ao uso. Esta é obtida

pela inspecção do DDG e do CDG, no qual dois nós condicionantes em série implicam

conjunções e dois nós condicionantes que sejam fontes para um determinado bloco básico

implicam disjunções. O GALADRIEL representa a função lógica decisória do programa

explicitamente no DFG.

No segundo problema, estudado em [August99] no âmbito de compilação para máquinas de

execução predicativa, a lógica decisória de programa é representada em diagramas de decisão

binários ordenados (OBDDs27) [Micheli94] para posterior aplicação de optimizações

booleanas. No caso de compilação para hardware específico as conjunções e disjunções da

lógica decisória de programa são implementadas por simples portas lógicas AND e OR, de

muito menores custos do que no caso das máquinas de execução predicativa em que são

utilizadas instruções lógicas para computar a lógica decisória. É, por isso, necessário avaliar o

impacto do uso das optimizações booleanas nas funções lógicas decisórias de forma a que se

consiga responder à pergunta: vale a pena optimizar as funções de lógica decisória no

contexto de compilação para hardware específico?

Definição 3 -6

Caminho de selecção de duas ou mais definições da mesma variável que

alcançam um determinado uso é o caminho mais longo no CDG constituído pelos

nós condicionais entre as definições e os usos.

Definição 3 -7

Função lógica decisória do programa é uma função lógica cujos literais são nós

condicionais do CDG que activam um caminho de selecção ou a execução de

uma determinada operação.

Exemplo 3 -4 . Obtenção da lógica decisór ia do programa.

A Figura 3.21 ilustra a obtenção da lógica decisória num ponto de selecção.

No fragmento existem duas definições da variável A que podem alcançar o

uso de A em BB3. Por este motivo é inserido um ponto de selecção em

27 Do inglês: Ordered Binary Decision Diagrams.

CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA... 71

BB3. Os caminhos de execução possíveis do fragmento do programa

apresentado são:

a) BB0 → BB1 → BB3: este caminho é percorrido caso a avaliação da

expressão lógica p0 && !p1 tenha valor verdadeiro.

b) BB0 → BB1 → BB2 → BB3: este caminho é percorrido caso a avaliação

da expressão lógica p0 && p1 tenha valor verdadeiro.

c) BB0 → BB2 → BB3: este caminho é percorrido caso a avaliação da

expressão lógica !p0 tenha valor verdadeiro.

Se analisarmos o CFG, verificamos que para que a definição Def1 (BB0)

atinja o uso1 (BB3) tem que ser percorrido o caminho a) e que isso

acontece quando p0 && !p1 tiver valor lógico verdadeiro. A outra definição

que também alcança o uso em BB3 é a definição Def2 (BB2) e tal é

possível para os caminhos b) ou c). Por isso a lógica decisória destes dois

caminhos é a conjunção das lógicas decisórias para cada caminho !p0 || (p0

&& p1).

start

BB3

BB2

T

p0

end

F

T

BB0

p1

BB1

F

A = … Def1

… = A … uso1

A = … Def2

start

BB0

BB1

BB2

BB3

OR

AND

a) b)

!p0 || (p0 && p1)

p0 && !p1

F T

T

Figura 3 .21 . Exemplo que i lustra os caminhos de selecção que

permitem seleccionar , de um conjunto de def in ições que a lcançam um

determinado uso, a def inição correcta para o valor específ ico das

condições. a ) CFG do exemplo; b) correspondente CDG.

72 CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA...

3.7 Computação do Grafo Hierárquico de Dependências do

Programa

Uma representação intermédia eficiente para lidar com o paralelismo funcional é o grafo

hierárquico de tarefas (HTG28) [Girkar92]. O HTG, como o próprio nome indica, é uma

representação hierárquica e permite que:

• todos os nós na hierarquia sejam representados por grafos direccionados acíclicos

(DAGs);

• os ciclos e as estruturas de controlo estejam explicitamente representados por

hierarquias (sub-HTGs);

• como é uma representação intermédia construída com base nas dependências de dados

e de controlo possibilita a exposição explícita de vários fluxos de controlo.

O HTG é constituído por nós de três tipos: compostos (que representam blocos if-then-else),

ciclos, e simples (que representam instruções ou blocos básicos). Os nós do tipo ciclo e os

nós compostos servem como ponte para sub-HTGs que representam o corpo destas estruturas.

O grafo hierárquico de dependências do programa (HPDG) proposto nesta tese é baseado no

HTG com as seguintes ressalvas:

• Só incorpora níveis de hierarquia na presença de ciclos. A representação usa a

conversão de saltos condicionais em pontos de selecção, a execução especulativa de

todas as operações excepto da escrita em memória, que usam as funções de lógica

decisória, e, por estes motivos, não necessita de utilizar directamente o CDG;

• O HPDG representa em cada nível hierárquico um subconjunto do DDG (não inclui as

dependências de dados entre iterações diferentes de um ciclo, e por isso fornece um

grafo acíclico) reunido com o MDG;

• Cada nó sem hierarquia no HPDG tem uma região associada no DFG global que

representa as operações e as interligações entre elas do programa original.

28 Do inglês: Hierarchical Task Graphs.

CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA... 73

A Figura 3.22 ilustra as representações utilizadas durante as fases de anteguarda do

compilador. Na Figura 3.22f pode ver-se o HPDG para o exemplo apresentado.

1 iconst_0 2 istore_2 3 iconst_0 4 istore_3 5 goto 22 6 aload_0 7 iload_3 8 saload 9 aload_1 10 iload_3 11 saload 12 isub 13 i2s 14 istore 4 15 iload_2 16 iload 4 17 iload 4 18 imul 19 iadd 20 istore_2 21 iinc 3 1 22 iload_3 23 iconst_4 24 if_icmplt 6 25 iload_2 25 ireturn

… int L2NORM = 0; for(int i=0; i<4;i++) short Aux = X[i] - Y[i]; L2NORM += Aux*Aux; …

a)

b)

0 0

l3 l2

4 l3

l2

l3 l0

l3 l1

l4

l2

l2

l3

l3

BB0

BB4

BB5

BB1

BB2

BB3

load

load

c)

BB0

BB1

BB2

BB3

BB4

BB5

start

end

d)

e)

Região cíclica

1 2 3

4

start

end

start

3

0

1

2

5

4

0

5

ciclo.1

1 2

3

4

start

end

start

end

f)

Figura 3 .22 . Transformações real izadas na vanguarda das fases de

compi lação: a) f ragmento de código Java; b) instruções JVM

correspondentes; c ) CFG com um DFG por cada b loco básico; d) DDG;

e ) CDG; f ) HPDG.

3.8 Criação do DFG Global

Para gerar o DFG global é inicialmente criado um DFG para cada bloco básico. Cada DFG é

constituído por um conjunto de nós que representam operações (aritméticas, lógicas e

comparações), variáveis, constantes, escrita e leitura em memória, e por um conjunto de laços

que representam o fluxo de dados entre os nós ou simplesmente precedências. Os nós de

variáveis servem também para interligar um nó fonte a diferentes receptores. Os nós do tipo

74 CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA...

variável no DFG podem ser mapeados em fios, registos, ou locais de memória durante as

fases de escalonamento.

Exemplo 3 -5 . DFG para um bloco básico.

Considere-se as instruções JVM de um bloco básico de um exemplo

hipotético apresentadas na Figura 3.23a. A sequência de instruções descreve

a expressão: TOPO pilha = (l10 + l13) × l2 + l11 + l14.

Na Figura 3.23b está ilustrado o DFG correspondente no qual os círculos

representam operações e os rectângulos representam usos/atribuições de/a

variáveis. Como se pode ver pela figura, esta representação exibe

explicitamente o paralelismo ao nível de operações.

Iload 10 Iload 13 Iadd Iload_2 Imul Iload 11 Iload 14 Iadd Iadd

l10 l13

l2 l11 l14

TOPO pilha

start

end a ) b)

Figura 3 .23 . Exemplo da construção do DFG para um bloco básico: a )

instruções JVM do bloco básico; b) correspondente DFG.

A criação de cada DFG é realizada usando a simulação do funcionamento da pilha de

operandos. O algoritmo é incremental, começa com a primeira instrução JVM do bloco

básico e vai construindo o DFG à medida que vai percorrendo as instruções que se seguem

até ao fim do bloco básico em consideração. Os operandos de uma dada operação são

procurados pela ordem LIFO29 no DFG construído até então. Se um operando não existir é

criado um nó do tipo variável que identifica o nível da pilha e a partir daqui o operando em

causa.

29 Do inglês: Last In First Out.

CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA... 75

Os acessos a elementos de arrays dentro de um bloco básico são seriados com laços próprios

por simples atravessamento em sentido directo do DFG que representa o bloco básico em

consideração. Esta análise distingue acessos a diferentes arrays, mas não a elementos do

mesmo array. A análise de dependência de dados ao nível de arrays fornece as dependências

de fluxo, anti e de saída.

Exemplo 3 -6 . DFG global .

Na Figura 3.24 é apresentado o DFG global que representa o exemplo da

Figura 3.22. Pela figura pode ver-se que o DFG global é planar. Podem

distinguir-se facilmente no DFG os nós que representam operações. Os nós

trapezoidais da figura representam acessos a elementos de arrays (neste

caso leituras). Os rectângulos na figura representam nós de variáveis às

quais foram atribuídos registos. O processo de identificação dos mesmos só

será explicado no capítulo seguinte.

REG i

0

REG i

4

lt_N

Endereço X

Endereço Y

LOAD X LOAD Y

REG RESULT

0

L2NORM

REG RESULT

Figura 3 .24 . DFG global para o exemplo da Figura 3 .22 . Dois nós em

formato de rectângulo com rótulos iguais representam atr ibuições ao

mesmo regis to .

O DFG global é criado com base no HPDG, nos DFGs construídos para cada bloco básico e

na lógica decisória de programa. O DFG global é um DAG que contém, de forma a

possibilitar a correcta representação do programa original, mecanismos que implementam os

76 CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA...

fluxos de controlo sempre que haja necessidade da preservação dos mesmos. Nos pontos de

selecção são colocadas estruturas de selecção sob a forma de multiplexadores e a lógica

decisória e de selecção é também representada no DFG global. Sempre que seja necessário,

existe um laço no DFG global entre a lógica decisória e a escrita de um elemento de um

array.

Cada nó do DFG global é rotulado com um majorante do número de vezes que a execução do

programa passa pelo nó, por 1 se o nó não pertencer a um ciclo e por +∞ quando o número de

iterações não for conhecido estaticamente.

3.9 Conclusões

Neste capítulo foi inicialmente explicado como é criado o CFG de um método em Java

bytecodes. Foi também explicado como extrair o paralelismo existente no CFG do programa

original para ser representado num DDG. Com base nos resultados conhecidos da área de

compilação de software em microprocessadores foram implementadas as análises que

possibilitam a extracção dos ciclos e a criação do CDG.

Foram descritos os tipos de dependências e identificados aqueles que realmente é necessário

preservar na compilação para um modelo personalizado com elevados graus de paralelismo e

de fluxos de controlo teoricamente ilimitados.

É proposta uma representação que permite manusear ciclos eficientemente, mantendo a

hierarquia existente no programa original. Esta representação, denominada de HPDG, é

obtida da reunião de um subconjunto do DDG com o MDG e é por isso uma representação

poderosa para lidar com o paralelismo ao nível de dados existente entre blocos básicos ou

ciclos. Esta representação tem associado um DFG global que representa as operações do

programa original e a forma como estão interligadas e com algumas transformações permite

fornecer a imagem da unidade de dados específica.

Embora as análises desenvolvidas sejam intraprocedimentais, extensões das mesmas podem

ser facilmente integradas no compilador. A extracção do paralelismo existente em acessos à

memória (arrays, por exemplo) fica reservada para futuras melhorias do compilador

GALADRIEL.

CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA... 77

Existem alguns problemas na extracção de paralelismo de descrições baseadas no modelo de

computação de von Neumann (linguagens puramente sequenciais). Um deles é a

possibilidade de quebra de especificações baseadas propositadamente no modelo sequencial.

Este facto pode ocorrer, por exemplo, em ciclos de espera ou de gasto de tempo. Quando não

há dependências na descrição fonte, estes ciclos podem ser escalonados em posições que

alteram a funcionalidade prevista. Só a utilização de directivas explícitas pelo programador

poderão resolver este problema.

Segundo julgamos saber, o trabalho apresentado neste capítulo foi um dos primeiros a:

• considerar a compilação dos bytecodes do Java tendo como alvo FCCMs30 baseadas

em FPGAs;

• considerar a extracção e exploração do paralelismo ao nível de operações a partir dos

bytecodes;

• fornecer representações intermédias com fluxos de controlo múltiplos vocacionadas

para a compilação para FCCMs.

As representações apresentadas, algumas delas obtidas por extensões de trabalhos publicados

pelas comunidades de síntese arquitectural e de compiladores de software em

microprocessadores, são também contribuições originais no âmbito da área científica na qual

esta tese se insere. Realça-se que, segundo o que nos é julgado saber, o uso de uma estrutura

hierárquica com base no grafo de dependências de dados e no grafo de dependências de fusão

nunca tinha sido considerado anteriormente.

Como suporte à depuração e compreensão, todos os grafos podem ser visualizados

graficamente com o uso do programa DOTTY [DottyURL]. Para tal o compilador de

anteguarda, GALADRIEL, fornece os ficheiros de texto necessários.

30 Do inglês: Field-Custom Computing Machines.

78 CAP. 3 MODELOS DE REPRESENTAÇÃO INTERMÉDIA...

79

4. Suporte à Geração de Reconfigware

“[…] On her finger was Nenya, the ring wrought of mithril, that bore a single white stone flickering like frosty air.”

J. R. R. Tolkien, The Return of the King

Este capítulo descreve as etapas de suporte adoptadas no compilador NENYA com vista à

geração de hardware reconfigurável especializado a partir dos modelos de representação

apresentados no capítulo anterior. Estas etapas, em conjunto com outras descritas nos

capítulos subsequentes, permitem ao NENYA suportar a compilação para uma arquitectura

constituída por um FPGA acoplado a uma ou mais memórias RAM via barramentos

independentes. São apresentados os conceitos que permitem o suporte a este tipo de

compilação e as estruturas que são geradas para a automatização de todo o processo. As

etapas incluem o mapeamento de operações, do DFG global descrito no capítulo 3, em

unidades funcionais e a atribuição de registos de modo a que a funcionalidade de programas

com ciclos seja preservada.

4.1 Pré-Etapas do NENYA

O compilador apresentado pode ser usado para compilar um programa completo para

reconfigware, desde que o programa respeite o subconjunto de Java presentemente aceite

pelo NENYA, ou segmentos de código de um programa cuja implementação final usa uma

arquitectura constituída por componentes software (microprocessador e memória RAM) e

80 CAP. 4 SUPORTE À GERAÇÃO DE RECONFIGWARE

reconfigware. A comunicação software/reconfigware é realizada com bibliotecas de interface

pré-definidas entre os dois componentes (ver Apêndice E).

Antes da execução, o compilador necessita das especificações do ciclo de relógio do

reconfigware, das memórias externas, da área máxima do FPGA, e da caracterização dos

componentes responsáveis pelos operadores existentes no programa fonte em linguagem

Java.

O compilador NENYA recebe os grafos gerados pelo GALADRIEL para um dado método

em Java e a identificação do segmento de código desse método que o programador deseja

compilar para reconfigware. As etapas realizadas pelo NENYA encontram-se ilustradas na

Figura 4.1.

Netlists (EDIF)

DFG

NENYA Descrição da Arquitectura

Alvo

Atribuição e Mapeamento de UFs

Partição Temporal & Escalonamento

STG (State Transition Graphs)

RTG (Reconfiguration Transition Graph)

Síntese de FSMs

Atribuição de Registos

Optimizações do DFG

HPDG

Inferência de Bits

Propagação de Bits Constantes

Reassociação de Operações

Redução do Custo de Operações

Caracterização das Macrocélulas

STG para VHDL-RTL

Comportamental

DFG para VHDL-RTL Estrutural

Tradução de VHDL-RTL Estrutural

para EDIF

Figura 4 .1 . Etapas real izadas pelo NENYA.

CAP. 4 SUPORTE À GERAÇÃO DE RECONFIGWARE 81

Por omissão, o GALADRIEL considera o corpo do método especificado pelo programador

para ser compilado para reconfigware. O utilizador pode servir-se de rótulos especiais para

identificar a região do código Java que deseja compilar para reconfigware. A rotulagem é

feita com a utilização de chamadas a métodos definidos em classes específicas (ver Figura

4.2) que são identificadas posteriormente pelo GALADRIEL. Com este modo de rotulagem

não é necessário estender a linguagem Java, o que permite o uso, sem restrições, da

tecnologia Java existente. A invocação dos métodos start() (linha 5) e end() (linha 7) de uma

instância da classe MAXTIME (linha 3) identifica um segmento de código e permite que o

utilizador obtenha uma estimativa do tempo de computação do segmento, quando

implementado em software, por execução do programa.

1. import Timing.MAXTIME; 2. ... 3. MAXTIME Code1 = new MAXTIME(10e-6); // 10uS 4. ... 5. Code1.start(); 6. ... // segmento de código com restrição temporal 7. Code1.end(); 8. ...

Figura 4 .2 . Ident i f icação de um segmento de código com restr ição temporal .

4.2 Estrutura do Reconfigware gerado pelo NENYA

A estrutura utilizada pelo NENYA para implementar o reconfigware relativo a uma dada

descrição em Java no FPGA é ilustrada na Figura 4.3. A arquitectura assenta no modelo

constituído por duas unidades diferenciadas que interagem entre si: a unidade de controlo e a

unidade de dados.

A unidade de dados pode incorporar, em aplicações que os necessitem, componentes que

acedem a dispositivos externos ao FPGA (quadrados a preto na Figura 4.3). Um destes tipos

de componentes é a macrocélula de acesso a uma memória externa. O endereçamento de

dados armazenados numa memória é realizado por circuitos especializados (constituídos por

macrocélulas) presentes na unidade de dados.

O compilador baseia-se numa biblioteca de macrocélulas parametrizáveis, definidas sob a

forma de geradores de circuitos, para produzir a unidade de dados. Cada uma das

macrocélulas gera a estrutura de um circuito especializado que representa uma determinada

82 CAP. 4 SUPORTE À GERAÇÃO DE RECONFIGWARE

operação. Para que o NENYA possa gerar o reconfigware, a cada nó do DFG global que

representa um operador é associado o componente, da biblioteca de macrocélulas, de

funcionalidade correspondente com menor atraso. O compilador permite o refinamento

automático do supracitado mapeamento inicial. Baseando-se no tempo livre de cada

operador, procura por macrocélulas que tenham funcionalidade equivalente mas um menor

custo em termos de área de circuito e que não alterem o atraso do caminho crítico.

A unidade de controlo é responsável pelo controlo dos acessos a memórias externas, pelo

controlo de escritas em registos e pela execução correcta dos ciclos.

Unidade de Controlo

Unidade de

Dados

sinais de controlo

sinais de estado

done

clock

reset

start

Figura 4 .3 . Estrutura do hardw are no FPGA.

Não foram consideradas outras formas de execução, como o uso de controlo distribuído,

constituído por sequenciadores com comunicação entre si, embebido na unidade de dados. A

utilização de controlo distribuído, no contexto de FPGAs, pode apresentar algumas

vantagens, tais como, permitir sintonizar mais facilmente os atrasos devidos ao

encaminhamento. No entanto, são necessários estudos comparativos detalhados para se

obterem conclusões definitivas.

4.3 Biblioteca Tecnológica

Como foi anteriormente referido, o compilador NENYA baseia-se numa biblioteca de

macrocélulas sob a forma de geradores de circuitos para produzir a unidade de dados. A

biblioteca [Cardoso99d] considerada tem como alvo a família XC6000 de FPGAs da Xilinx

[Xilinx97]. Alguns componentes foram adaptados das implementações em

[Velab98][Hartenst98].

CAP. 4 SUPORTE À GERAÇÃO DE RECONFIGWARE 83

A biblioteca inclui operadores inteiros (aritméticos, lógicos, comparadores, deslocadores,

etc.), uma macrocélula de acesso a memórias externas acopladas ao FPGA, multiplexadores,

etc.

Cada operador tem uma descrição estrutural em VHDL com as seguintes propriedades:

• Parametrização: de acordo com o número de bits dos operandos de entrada/saída é

gerado um circuito especializado.

• Colocação relativa: os elementos são pré-colocados aquando da formação do operador

(esta pré-colocação é definida utilizando as capacidades dos atributos do VHDL

[IEEE99] como é exemplificado na Figura 4.4).

Os componentes parametrizáveis eliminam a necessidade de acomodamento de bibliotecas de

componentes pré-definidos, permitem largura de bits contínua (especialização), e facilitam a

geração de circuitos optimizados para cada operador em área/atraso, pelo uso de algoritmos

mais eficientes e mais específicos para a família de FPGAs considerada.

… ATTRIBUTE rloc OF cell1 : LABEL IS "X1,Y0"; ATTRIBUTE rloc OF cell2 : LABEL IS "X2,Y1"; BEGIN cell1 : and2 PORT MAP(…); cell2 : or2 PORT MAP(…); …

X 0 1 2 3

0

1

2

Y

a ) b)

Figura 4 .4 . Colocação relat iva de células no FPGA: a) atr ibutos no

VHDL; b) colocação no FPGA que é sempre re la t iva ao posic ionamento

do nível imediatamente a seguir na hierarquia de componentes.

A colocação relativa permite encaminhamentos com menores variações, e por isso maior

previsibilidade nos atrasos das ligações, e reduz os tempos de colocação e encaminhamento

globais.

84 CAP. 4 SUPORTE À GERAÇÃO DE RECONFIGWARE

No caso da família de FPGAs XC6000, a descrição estrutural em VHDL assenta na utilização

das portas lógicas elementares que podem ser implementadas por cada célula da FPGA.

A Figura 4.5 apresenta os resultados obtidos em termos de melhoria relativa da

implementação de somadores com o uso de uma macrocélula em comparação com o uso de

síntese lógica [Synopsys95]. Verifica-se que o uso da macrocélula permite a utilização de

somadores com menores atrasos e áreas menores. Outros ganhos, relativamente à utilização

de geradores de circuitos em vez de síntese lógica, poderiam ser reportados:

• no tempo total de computação para a criação da estrutura lógica, que é muito menor

no caso das macrocélulas, pois é apenas necessário criar a estrutura, sem ser

necessário realizar qualquer tipo de optimizações da lógica;

• no tempo de computação para a colocação e encaminhamento, que é menor no caso

das macrocélulas devido a estas serem pré-colocadas.

0,0%

10,0%

20,0%

30,0%

40,0%

50,0%

60,0%

4 8 16 24 32

melhoria_área

melhoria_atraso

Figura 4 .5 . Melhor ia re lat iva em termos de área e de atraso para

circuitos de adição do t ipo “ripple -carry ” (área mínima) gerados pela

macrocélula versus somadores s intet izados pela ferramenta de s íntese

lógica (com direct iva de área mínima).

Em vez de VHDL podem ser utilizadas outras linguagens para a geração dos circuitos para as

macrocélulas. Alguns autores desenvolveram ambientes que permitem gerar circuitos com

base na descrição em C++ [Mencer98] ou em Java [Weaver98][Bellows98] da estrutura ao

nível de porta lógica. Outra forma poderia ser a utilização de geradores de circuitos

CAP. 4 SUPORTE À GERAÇÃO DE RECONFIGWARE 85

disponibilizados pelos fabricantes de FPGAs, como é o caso do X-BLOX [X-Blox92] da

Xilinx existente para algumas das famílias de FPGAs deste fabricante. Qualquer destas

abordagens permitiria a prototipagem para mais do que uma família de FPGAs. Contudo, a

escolha recaiu no VHDL por ser aceite pela maioria das ferramentas de retaguarda e por isso

possibilitar o suporte de FPGAs de famílias e marcas diferentes. O facto das abordagens mais

interessantes a geradores de circuitos (as supracitadas baseadas em C++ ou Java) serem

proprietárias e encontrarem-se em fases de investigação e desenvolvimento foi outro dos

motivos pelo qual a escolha recaiu em VHDL.

Nas fases de alocação e escalonamento o compilador utiliza uma descrição de cada operador

para a família de FPGAs utilizada. Um ficheiro que contém a caracterização da biblioteca de

componentes é interpretado pelo compilador. Um exemplo da caracterização de um

multiplicador de inteiros é ilustrado na Figura 4.6. O compilador suporta o parsing do

ficheiro e o carregamento dos componentes num formato intermédio apropriado para o

processamento durante a fase de mapeamento de operadores a componentes. Este esquema

permite que o NENYA possa compilar para várias famílias de FPGAs, bastando para isso que

o utilizador forneça a descrição de cada macrocélula com base na caracterização da área e

atraso em função do número de bits dos operandos. Esta descrição de cada componente

permite que o NENYA utilize estimativas de atraso e de área para cada componente, de

forma a poder realizar o escalonamento e estimar a área total necessária para implementar o

circuito.

1. … 2. Component mult_op 3. Area=(a+b)**2; //a e b representam o número 4. //de bits de cada operando. 5. Delay=14*a-20ns; //atraso da macrocélula 6. //em função de a. 7. Operation=imul; //tipo de função 8. … //imul=multiplicador de inteiros 9. 10. …

Figura 4 .6 . Descr ição de uma macrocélula na bibl ioteca tecnológica.

De futuro pode ser considerada a utilização de Java para caracterizar cada macrocélula em

vez da descrição utilizada (ver Figura 4.6). O uso de Java possibilitaria caracterizações mais

exactas, pelo uso de construções condicionais e expressões mais complexas aceites pela

linguagem, para modelar a área e o atraso de cada operador. A Figura 4.7 representa o gráfico

86 CAP. 4 SUPORTE À GERAÇÃO DE RECONFIGWARE

que caracteriza os multiplicadores obtidos, por síntese lógica mantendo as mesmas directivas

(área mínima), quando se consideram vários tamanhos de operandos e do resultado, e ilustra a

complexidade que poderia ter uma caracterização menos pessimista.

4 6 8 1216

2432

4864

3224

168

4

0

1000

2000

3000

4000

5000

6000

7000

8000

células

bits do resultadobits dos

operandos

7000-8000

6000-7000

5000-6000

4000-5000

3000-4000

2000-3000

1000-2000

0-1000

Figura 4 .7 . Área dos circuitos de mult ipl icação sintet izados tendo em

conta d i ferentes tamanhos (em número de bi ts) dos operandos e do

resultado.

4.4 Mapeamento de Operações em Unidades Funcionais e

Escalonamentos Iniciais

Cada nó do DFG global, que representa um operador, é mapeado num componente da

biblioteca de macrocélulas para que o reconfigware possa ser gerado. À partida, o compilador

atribui, a cada operador, o componente de funcionalidade correspondente com menor atraso

existente na biblioteca especificada pelo utilizador. Com base nesta atribuição são realizados

os escalonamentos ASAP1 e ALAP2 sem restrições de recursos. Estes escalonamentos são

1 Do inglês: As Soon As Possible (ASAP). Esquema de escalonamento em que as operações são colocadas o mais próximo possível do início do escalonamento. 2 Do inglês: As Late As Possible (ALAP). Esquema de escalonamento em que as operações são colocadas o mais próximo possível do fim do escalonamento.

CAP. 4 SUPORTE À GERAÇÃO DE RECONFIGWARE 87

obtidos pelo atravessamento do DFG global do início para o fim e vice-versa,

respectivamente. Foram consideradas várias possibilidades para implementar os esquemas

ASAP e ALAP. Uma implementação, baseada em pilha, do esquema ASAP é apresentada na

Figura 4.8. No algoritmo, succ()e pred() representam respectivamente no DFG os nós

sucessores e os nós predecessores do nó considerado e push() representa a colocação de

um nó no topo da pilha se o topo ainda não contiver o nó considerado. A função MAX calcula

o máximo de dois números inteiros. Esta versão tem o pior tempo de execução proporcional a

|V|+|E| (O(|V|+|E|)), sendo |V| o número de nós e |E| o número de laços do grafo. Na prática,

contudo, o carregamento de nós na pilha necessita de tamanho suplementar de memória, no

pior dos casos proporcional a |E|, facto que agrava o tempo de execução do algoritmo no caso

de grafos com elevado número de laços. Uma forma de melhorar o tempo de computação do

algoritmo consiste em implementar uma versão iterativa deste (ver Figura 4.9) que não

necessita do uso da pilha. O grafo é sucessivamente atravessado, e para cada nó são

determinados os tempos do escalonamento, até que não haja modificações no escalonamento.

Esta versão tem o pior tempo de execução proporcional a |V|2+|V||E| (O(|V|2+|V||E|)), mas na

prática comporta-se melhor do que o algoritmo baseado em pilha, devido ao facto da maioria

dos nós do DFG poderem ser acedidos por ordem topológica (em alguns casos obteve-se

metade do tempo de execução do algoritmo baseado em pilha) e de não requerer memória

adicional.

1. ASAP(DAG DFG) 2. Stack Nodes = new Stack(); 3. Forall Succ(DFG.START) 4. Nodes.push(succ(DFG.START)); 5. 6. 7. while(!Nodes.empty()) 8. DAGNode A = Nodes.pop(); 9. 10. Foreach DAGNode Bi ∈ A.pred() 11. ASAPstart(A) = MAX(ASAPend(Bi), ASAPstart(A)); 12. 13. 14. ASAPend(A) = ASAPstart(A) + delay(A); 15. 16. Forall DAGNodes ∈ A.succ() 17. Nodes.push(A.succ()); 18. 19. 20.

Figura 4 .8 . Algor i tmo do escalonador ASAP sem restr ições de recursos

baseado em pi lha .

88 CAP. 4 SUPORTE À GERAÇÃO DE RECONFIGWARE

1. ASAP(DAG DFG) 2. Boolean modified; 3. do 4. modified = false; 5. 6. foreach(DAGNode Aj ∈ DFG) 7. int oldASAPstart = ASAPstart(Aj) 8. int newASAPstart = oldASAPstart; 9. Foreach DAGNode Bi ∈ Aj.pred() 10. newASAPstart = MAX(ASAPend(Bi), newASAPstart); 11. 12. if(newASAPstart ≠ oldASAPstart) 13. ASAPend(Aj) = newASAPstart + delay(A); 14. modified = true; 15. 16. while(modified) 17.

Figura 4 .9 . Algori tmo i terat ivo do escalonador ASAP sem restr ições de

recursos.

Para facilitar todas as análises baseadas no atravessamento do DFG global, a criação deste é

realizada de forma a que a ordem de armazenamento dos nós no DFG seja a ordem

topológica no mesmo. Deste modo, os algoritmos de ASAP/ALAP utilizados requerem

apenas uma simples passagem pelo DFG. Na Figura 4.10 é apresentado o algoritmo de ASAP

usado, que é semelhante ao algoritmo da Figura 4.9 com excepção dos enunciados

encarregues da parte iterativa. Com o algoritmo da Figura 4.10 o pior tempo de execução é

proporcional a |V|+|E| (O(|V|+|E|)).

1. ASAP(DAG DFG) 2. foreach(DAGNode Aj ∈ DFG in topological order) 3. int oldASAPstart = ASAPstart(Aj) 4. int newASAPstart = oldASAPstart; 5. Foreach DAGNode Bi ∈ Aj.pred() 6. newASAPstart = MAX(ASAPend(Bi), newASAPstart); 7. 8. if(newASAPstart ≠ oldASAPstart) 9. ASAPend(Aj) = newASAPstart + delay(A); 10. 11. 12.

Figura 4 .10 . Algor i tmo do escalonador ASAP sem restr ições de

recursos quando os nós do DFG são acedidos por ordem topológica .

O algoritmo para efectuar o escalonamento ALAP é similar aos anteriores com as

modificações baseadas no facto de que este necessita de atravessamento do DFG por ordem

CAP. 4 SUPORTE À GERAÇÃO DE RECONFIGWARE 89

inversa do fluxo (começa com o atraso máximo obtido pelo ASAP) e é baseado na equação

ALAPend(A) = MIN(ALAPstart(Succ(A)), ALAPend(A)), em que MIN

representa o cálculo do valor mínimo de dois números inteiros. Tal como foi descrito para o

algoritmo de ASAP, quando o DFG é representado por ordem topológica, o algoritmo de

ALAP só necessita de uma passagem pelo DFG global.

Todos os algoritmos apresentados são genéricos e simplificados para melhor compreensão

(não incluem o tratamento de operações especiais, por exemplo). A Figura 4.11 apresenta

alguns resultados comparativos dos três algoritmos propostos para o ASAP com exemplos

apresentados no apêndice D. A utilização do algoritmo de uma passagem origina, como seria

de esperar, melhorias significativas que, por isso, justificam a sua escolha. O algoritmo

iterativo também produziu melhores resultados, exceptuando um caso (Mult53), do que o

algoritmo baseado em pilha.

-40,0%

-20,0%

0,0%

20,0%

40,0%

60,0%

80,0%

100,0%

Mult53 Mult89 Mult161 Mult305 Mult573 sqrt217 usqrt603

Melhoria(Top. Ord.) Melhoria(Iterativo)

Figura 4 .11 . Melhor ias dos a lgor i tmos ASAP, com os nós

topologicamente ordenados e com o método i terat ivo, re lat ivamente ao

a lgor i tmo baseado em pi lha (os números a segui r ao nome do exemplo

ident i f icam o número de nós de cada DFG global ) .

Os escalonamentos realizados são ditos de granulosidade fina, por serem feitos em fracções

do período do ciclo de relógio3 previamente escolhido pelo utilizador, ao invés dos

3 É usado um décimo do período como passo de escalonamento. Pode também ser utilizado o máximo divisor comum de todos os atrasos das macrocélulas utilizadas como passo.

90 CAP. 4 SUPORTE À GERAÇÃO DE RECONFIGWARE

escalonamentos feitos com o período do ciclo de relógio como escala mínima [Micheli94]

(ditos de granulosidade grossa). A utilização destes últimos é por vezes devida ao facto de os

operandos/resultados das unidades funcionais estarem/serem armazenados em registos, em

alguns casos apenas nas fronteiras de blocos básicos, que são carregados em transições

positivas ou negativas do ciclo de relógio (embora também seja possível realizar

encadeamentos de operações num mesmo ciclo de relógio [Micheli94]).

No NENYA os operandos e os resultados das unidades funcionais são, sempre que possível,

promovidos a fios. Este facto permite que as unidades que necessitam de operandos

fornecidos por outras unidades comecem, para efeitos de escalonamento, virtualmente a

execução no final do tempo de atraso do caminho crítico das fornecedoras. Pode-se ver pela

Figura 4.12a que quando existem registos entre unidades funcionais4, o começo da execução

de cada unidade tem de ser escalonado para o início de um novo ciclo de relógio. No caso em

que não existem registos entre operações as unidades podem começar a execução de seguida

(ver Figura 4.12b). É óbvio que para operações que não sejam mutuamente exclusivas e que

partilhem fisicamente a mesma unidade funcional, a necessidade de armazenar os dados

correspondentes a cada operação introduz registos e induz o escalonamento das operações

para o início do ciclo de relógio.

REG

REG

OP2

REG

OP1

OP1

OP2

a ) b )

Figura 4 .12 . Impacto na execução: a) com registos; b) sem re gistos

entre operações.

4 Para unidades funcionais puramente combinatórias.

CAP. 4 SUPORTE À GERAÇÃO DE RECONFIGWARE 91

Quando aparece um nó do DFG que refere uma unidade funcional cuja actividade só pode ser

iniciada no início de um ciclo de relógio (acessos à memória, escrita em registos e unidades

partilhadas) é lhe atribuído um valor de ASAP correspondente ao início do ciclo de relógio

mais próximo, que não viole os tempos de finalização das unidades que fornecem dados à

unidade em consideração.

O mapeamento inicial realizado atribui a cada operador do DFG o componente da biblioteca

de macrocélulas mais rápido (linhas 3 a 5 da Figura 4.13). De seguida o algoritmo de

mapeamento utilizado, ilustrado na Figura 4.13, tenta refinar o mapeamento inicial com base

no tempo livre de cada operação. Após a obtenção das medidas ASAPstart, ASAPend, ALAPstart

e ALAPend para cada nó do DFG (linhas 5 e 6 da Figura 4.13), determinando os

escalonamentos ASAP e ALAP sem restrições de recursos e sem tratamento especial dos nós

pertencentes a regiões cíclicas e/ou ramos condicionais (linhas 6 e 7 da Figura 4.13).

1. Mapping 2. Library LD = LoadLibrary(); 3. Map each Operation Nodei of DFG to a 4. Functional equivalent Macrocell ∈ LD with 5. Minimum delay; 6. DelayMAX = Compute fine-grain ASAP(ASAPstart, ASAPend); 7. Compute fine-grain ALAP(ASAPstart,ASAPend, DelayMAX); 8. Compute TI(ASAP, ALAP); 9. Refine Mapping(TI, DFG); 10. 11. 12. Refine Mapping(TI, DFG) 13. Foreach Operation Nodei of DFG with TI > Delayi 14. S1 = Search in LD for the set of functional 15. Equivalent Macrocells of the operation 16. in Nodei; 17. If((S1 ≠ ∅) && (Search Macroj ∈ S1 with 18. lower area and delayj ≤ TI(Nodei))) 19. Nodei.SetMacro(Macroj); 20. Compute the new fine-grain ASAP for the 21. path which contains Nodei; 22. Compute the new fine-grain ALAP for the 23. path which contains Nodei; 24. Compute the new TIs for the path which 25. Contains Nodei; 26. 27. 28.

Figura 4 .13 . Algor i tmo para mapear as operações nas unidades

funcionais (macrocélulas) . O algori tmo engloba o ref inamento do

mapeamento, ao permit i r a t roca entre macrocélu las de menor área

desde que a mesma não v io le o caminho cr í t ico .

92 CAP. 4 SUPORTE À GERAÇÃO DE RECONFIGWARE

Após o cálculo dos escalonamentos ASAP e ALAP, é determinado o tempo que uma

operação pode usar sem afectar o atraso do caminho crítico (linha 7 da Figura 4.13). Este

intervalo de tempo é calculado pela equação (4.1), e representa a soma da mobilidade (tempo

livre que uma operação individualmente ainda pode usar sem que isso altere o atraso do

caminho crítico e que é calculado pela subtracção dos tempos de ALAP e de ASAP relativos

a essa operação) com o atraso da operação.

startiendii ASAPALAPTI −= (4 .1 )

Baseado no TI de cada operação do DFG, o algoritmo selecciona de entre as macrocélulas

com funcionalidade equivalente a de menor área que não perturbe o atraso do caminho crítico

(linhas 13 a 16 da Figura 4.13). Para cada troca de macrocélula o algoritmo repete o processo

até não serem possíveis mais refinamentos.

4.5 Acessos a Memórias Externas

Nesta versão do compilador, o mapeamento de variáveis do tipo array utilizadas na descrição

fonte é feito em dispositivos de memória externos ao FPGA, por ser a forma de garantir

espaço para armazenamento, principalmente em FPGAs sem memórias internas como é o

caso da família XC6200. Em trabalhos futuros espera poder-se promover o armazenamento

de arrays, sempre que tal for possível, em memórias internas do FPGA5. De forma a reduzir

o impacto dos acessos a elementos de arrays armazenados externamente, é considerado o uso

de várias memórias acopladas ao FPGA e formas de mapeamento destas de forma a que o

cálculo de endereços, por impor custos elevados de área e de atraso, seja feito por um circuito

de dimensão e atraso reduzidos.

4.5.1 Especialização para o Cálculo de Endereços

A localização em memória (endereço físico) do elemento indexado por I de um array uni-

dimensional A, A[I], é calculada pela equação (4.2) em modelos sem offset (linguagens

5 Os novos FPGAs, como é o caso da família Virtex de FPGAs da Xilinx [VirtexURL], integram bancos de memória distribuídos e possibilitam que cada CLB (Configurable Logic Block) possa também ser usado como memória de tamanho reduzido.

CAP. 4 SUPORTE À GERAÇÃO DE RECONFIGWARE 93

Java e C, por exemplo). O termo BASE representa o endereço físico a partir do qual se

situam todos os elementos do array (normalmente por ordem crescente) e o factor de

multiplicação W representa a transformação necessária que normalmente é função da unidade

de endereçamento (múltipo do byte) e do tipo de dados do array (arrays do tipo int em

memórias endereçáveis byte-a-byte requerem W=4, por exemplo).

I x W + BASE (4 .2 )

Como os dados são representados em múltiplos do byte, o factor multiplicativo na equação

pode ser implementado por um simples deslocador por uma constante que, no caso de

hardware especializado, é implementado simplificadamente por interligações sem

necessidade de lógica.

A complexidade do conversor de índices de arrays em endereços físicos da memória onde

estão armazenados os elementos do array depende da posição destes na memória. Quando os

arrays são mapeados em posições de memória múltiplas de 2n o factor de soma do índice

alinhado ao endereço base do respectivo array pode ser substituído por uma simples

concatenação de bits identificadores do endereço base com o índice. Por exemplo, se o array

A tiver dimensão de 8 bytes e endereço base (endereço do primeiro elemento) 64, a instrução

A[i] pode ser especificada em VHDL por A(“0..01000” & i(2 downto 0)) e,

como se pode constatar, a implementação reduz a geração do endereçamento a simples

interligações. Este tipo de alocação usa os recursos da memória de uma forma pouco

económica6, mas permite optimização no acesso (não havendo necessidade do somador, facto

que poderia degradar o desempenho e aumentaria a área do circuito). Embora a compilação

de implementações reconfigware assumindo a colocação de arrays na memória

contiguamente não traga qualquer problema adicional, nesta versão, o compilador usa sempre

a alocação dos arrays anteriormente explicada para que os acessos às memórias não afecte

tanto o desempenho.

Na Figura 4.14 é apresentado o algoritmo de atribuição de endereços base a cada array na

memória definida pelo mapeamento. O algoritmo pressupõe que previamente foi feito o

mapeamento dos arrays nas memórias disponíveis e assegurado que a atribuição de

6 Na maioria de aplicações parece ser tolerável devido aos recursos de memória existentes na maioria das placas para computação reconfigurável e na maioria dos próprios FPGAs serem grandes.

94 CAP. 4 SUPORTE À GERAÇÃO DE RECONFIGWARE

endereços base não implica a violação do tamanho máximo de cada memória. O algoritmo

assume que o tamanho dos arrays foi determinado previamente e, por isso, quando o

compilador não consegue obter esta informação requer a inserção da mesma pelo utilizador.

1. MapBase(ℑℑ(℘)) 2. Foreach Memoryi ∈∈ ℑℑ 3. Boolean lastshift = false; 4. int ArrayRef = 0, ArrayBef = 0, thisNumArrays = 0; 5. ℘ = arrays mapped to Memoryi sorted by increasing size; 6. foreach Arrayj ∈∈ ℘ // por ordem crescente 7. int bytes = getScale(Arrayj.type); 8. if(thisNumArrays == 0) 9. ArrayRefs[Arrayj] = 0; 10. else 11. ArrayRef = 2^log2(Arrayj.size*bytes); 12. if(ArrayRef == ArrayBef) 13. ArrayRef[Arrayj] = ArrayRef[Arrayj-1] + 14. 2^log2((Arrayj.size-1)*bytes); 15. lastshift = !lastshift; 16. else 17. ArrayRefs[Arrayj] = ArrayRef; 18. lastshift = false, 19. 20. 21. thisNumArrays++; 22. ArrayBef = ArrayRef; 23. 24. return ArrayRefs; 25.

Figura 4 .14 . Algor i tmo que, para cada memória, atr ibui os endereços

BASE dos arrays mapeados na memór ia considerada .

Para cada memória externa (ℑ representa o conjunto de memórias), o algoritmo determina o

endereço do primeiro elemento de cada um dos arrays mapeados nessa memória. De seguida

o algoritmo visita cada um dos arrays pela ordem crescente do tamanho em bytes (linhas 5 e

6 da Figura 4.14). Ao primeiro array da lista ordenada é atribuído o endereço zero (linha 9 da

Figura 4.14). Aos restantes são atribuídos endereços com apenas um bit com valor lógico um

que garantam espaço suficiente entre endereços para armazenar cada um dos arrays (linhas

10 a 20).

4.5.2 Partilha de Acessos a Memórias

Por cada memória externa de porto único acoplada ao FPGA por um barramento próprio é

instanciada uma macrocélula que corresponde a um circuito de acesso especializado. O

CAP. 4 SUPORTE À GERAÇÃO DE RECONFIGWARE 95

diagrama de blocos da macrocélula é exemplificado na Figura 4.15. Todos os acessos a esta

macrocélula são multiplexados no tempo e por isso são colocados blocos de selecção nas

linhas de endereçamento e de dados com mais do que uma linha incidente. A unidade de

controlo é responsável por assegurar a ordem de acessos correcta.

LEITURA/ ESCRITA

Índice1 αα1

Índice2

Índicek

αα1

ααk

Memória

Dados de entrada

Endereços Dados de saída

FPGA

Selecciona

selecciona

WE

Figura 4 .15 . Acessos à macrocélu la de in ter face com uma memória

externa acoplada ao FPGA. Os índices de 1 a k ident i f icam elementos de

u m array e os parâmetros αα representam a t ransformação do índice no

endereço real na memória . Caixas axadrezadas representam registos.

Os dados de entrada da macrocélula que acede à RAM usam registos a seguir aos blocos de

selecção para armazenar os valores dos dados e dos endereços, pois deste modo o

escalonamento obtido é mais eficiente quando há acessos consecutivos à macro. Os registos

isolam o valor do bloco de selecção permitindo que enquanto a macrocélula está em execução

os valores para o próximo acesso possam já estar a ser seleccionados.

Para memórias com mais do que um porto é instanciada uma macrocélula de interface para

cada porto.

4.6 Atribuição de Registos

O compilador usa sempre que possível a promoção de variáveis em fios, mesmo nos casos em

que a variável tem um registo da JVM associado. A promoção em fios em descrições

acíclicas implica a não necessidade de registos para garantir o correcto funcionamento. Com

este tipo de promoção não é necessário respeitar dependências de dados de saída e anti, e de

96 CAP. 4 SUPORTE À GERAÇÃO DE RECONFIGWARE

restauro de execução especulativa em descrições com apenas variáveis locais. A eliminação

das dependências de saída e anti pode potenciar maiores graus de paralelismo sempre que tais

existam.

A compilação relativa à maioria dos dispositivos de lógica reconfig uráveis não necessita de

utilizar técnicas de partilha de registos baseadas no tempo de vida das variáveis, pois estes

possuem inerentemente registos em número elevado sem gastos adicionais. Na maioria dos

FPGAs o tamanho de um registo é equivalente ao tamanho de um multiplexador, tornando

inglória a partilha baseada na poupança de área. Além do mais, as unidades de dados

baseadas em arquitecturas com ficheiros de registos, sendo vocacionadas para a reutilização

destes (registos), tornam o encaminhamento mais complicado, são muito mais apropriadas

para a liberdade de implantação física de um ASIC do que para as arquitecturas pré-definidas

de FPGAs, e restringem a implementação de graus elevados de paralelismo. Por estes

motivos não se considera a reutilização de registos, nem arquitecturas alvo baseadas na

partilha de uma ou mais unidades de ficheiros de registos.

Contudo, os registos são necessários para implementar ciclos e para permitir a partilha de

unidades funcionais por operadores. Como a versão corrente do compilador não permite a

partilha de unidades funcionais da forma usual, apenas as unidades de acesso às memórias

externas necessitam de registos para armazenar os valores lidos. Apenas operações do mesmo

tipo em caminhos mutuamente exclusivos podem utilizar a mesma unidade funcional sem a

necessidade de armazenamento de dados, pois a unidade é apenas utilizada uma única vez por

cada passagem do programa, como se explicará na secção seguinte.

No caso dos ciclos os registos são necessários para armazenar dados cujo valor é necessário

entre iterações. O compilador determina o número de registos mínimo e os nós de variáveis

no DFG global onde estes devem ser colocados para preservar a computação de ciclos. O

algoritmo procura no DFG por cadeias uso-definição dentro de um ciclo. Para uma dada

variável que refere um registo, a última definição anterior à execução do ciclo e a última

definição dentro do ciclo são, respectivamente, a primeira e a última atribuições ao registo.

No caso de existirem pontos de selecção alcançados por atribuições a uma variável que

necessita de um registo, este é colocado a seguir ao ponto de selecção.

O DFG ilustrado na Figura 3.24 apresenta a atribuição de registos a variáveis realizada pelo

NENYA. Cada registo atribuído apresenta o desdobramento no DFG dado pela inicialização

CAP. 4 SUPORTE À GERAÇÃO DE RECONFIGWARE 97

da variável e pela última definição desta no corpo do ciclo. É por isso que aparecem na

Figura 3.24 dois nós para o registo “REG i” e dois para o registo “REG Result”. As duas

atribuições a qualquer destes registos são implementadas na unidade de dados por

multiplexamento dos laços incidentes aos nós identificadores da mesma variável à qual foi

atribuído um registo (ver Figura 4.16).

REG i

0

4

lt_N

Address X

REG Xi REG Yi

REG RESULT

0

L2NORM

LOAD

Sel1

Sel2

Address YSel3

g)

Figura 4 .16 . Grafo da unidade de dados representat ivo do DFG global da

Figura 3.24 quando os dois arrays são mapeados numa memór ia de

porto único. As atr ibuições ao mesmo registo foram mult ip lexadas.

4.7 Partilha de Unidades Funcionais

A partilha viável de unidades funcionais por operações aritméticas de grandes dimensões

(multiplicadores, por exemplo) deve ser considerada em trabalhos futuros. Esta não foi

considerada nesta dissertação por a mesma requerer também abordagens diferentes dos

métodos usualmente propostos pela comunidade de síntese arquitectural vocacionada para

ASICs [Gajski92][Micheli94] e necessitar de investigações morosas que são naturalmente

complementares a esta tese. Algoritmos que entrem em linha de conta com a possibilidade da

partilha de unidades funcionais e de partição temporal necessitam de ser investigados. Alguns

trabalhos têm proposto formas de lidar com estes dois problemas baseadas em programação

linear inteira (ILP7) em conjunção com heurísticas [Ouaiss98a], o que limita fortemente a sua

aplicação por implicar elevados tempos de computação. Contudo, o problema é ainda mais

complexo pois a partilha de unidades funcionais por operadores distantes no DFG pode

7 Do inglês: Integer Linear Programming.

98 CAP. 4 SUPORTE À GERAÇÃO DE RECONFIGWARE

complicar a colocação e encaminhamento, podendo não reduzir a área do circuito final como

era esperado durante o escalonamento.

No compilador é usada uma forma de partilha de unidades funcionais sem necessidade da

intervenção da unidade de controlo. Este tipo de partilha de recursos é exemplificada no

Exemplo 4-1 e pode ser utilizado em caminhos mutuamente exclusivos que façam uso de

operadores com a mesma funcionalidade e só permite a partilha de uma unidade por apenas

um operador de cada caminho mutuamente exclusivo. O mecanismo baseia-se na utilização

da selecção do caminho, pela lógica decisória do programa, para também seleccionar os

operandos da unidade partilhada entre operações de caminhos mutuamente exclusivos. É por

isso um mecanismo de partilha espacial e não permite a partilha temporal de uma unidade

funcional por duas operações executadas incondicionalmente.

A partilha pode reduzir a área do circuito mas pode também introduzir atrasos no caminho

crítico pois a selecção de operandos do operador partilhado precisa de conhecer o resultado

da lógica decisória. Por este motivo o mecanismo pode ser avaliado previamente pelo

utilizador. Por omissão, o compilador não considera a partilha anterior.

Exemplo 4 -1 . Part i lha de recursos em caminhos mutuamente exc lus ivos.

Considere-se o segmento de código Java apresentado na Figura 4.17a. O

código é constituído por dois caminhos mutuamente exclusivos. Um dos

caminhos é constituído pelo bloco básico BB1 que contém duas

multiplicações e uma adição (linha 3). O outro caminho é constituído pelo

bloco básico BB2 que contém uma multiplicação e uma adição (linha 5). A

Figura 4.17b apresenta o DFG correspondente ao segmento de código

apresentado. Neste exemplo todas as operações de multiplicação podem

partilhar entre elas a mesma unidade de multiplicação. Contudo para

preservar a funcionalidade a partilha da mesma unidade por operações

pertencentes ao mesmo caminho necessita do uso de registos e da

interacção com a unidade de controlo.

Para que a partilha seja apenas assegurada por fluxo de dados a partilha de

um multiplicador tem de ser feita entre Op1 e Op3 ou Op2 e Op3. Com a

partilha de um multiplicador entre Op1 e Op3 obtém-se o DFG

CAP. 4 SUPORTE À GERAÇÃO DE RECONFIGWARE 99

representado na Figura 4.17c. Da mesma forma as operações de adição Op4

e Op5 podem também partilhar a mesma unidade de adição. O DFG

representado na Figura 4.17d ilustra a partilha de um multiplicador e de um

somador.

Este tipo de partilha não requer interacção com a unidade de controlo como

se pode constatar. Contudo, deve-se ter em conta que neste exemplo a

selecção de operandos do operador partilhado Figura 4.17b precisa de

conhecer o resultado da comparação, e por isso o atraso do caminho crítico

é maior.

1. … 2. if(f<10) 3. a = b * c + d * e; BB1 4. else 5. a = d * c + e; BB2 6. … a_1

c

a_3 Mux(a_1, a_2)

a_2

d

e

e d c b 10 f

BB1 BB2

1 2 3

4 5

6

a ) b)

a_1

a_3

Mux(a_1, a_2)

a_2

e

e

d

c

b 10 f

d

Mux(b, d)

a_3

e

e

d

c

b 10 f

d

Mux(b, d)

c ) d)

Figura 4 .17 . a) segmento de código Java; b) DFG correspondente; c)

DFG com part i lha de um mult ip l icador entre caminhos mutuamente

exclusivos; d) DFG com part i lha do mult ip l icador e do somador.

100 CAP. 4 SUPORTE À GERAÇÃO DE RECONFIGWARE

4.8 Geração do Reconfigware para a Unidade de Dados

A unidade de dados é obtida do DFG global após algumas transformações:

• A partilha de uma macrocélula nos acessos à mesma memória externa, requer a

colocação de circuitos que seleccionem de entre as linhas de dados e de

endereçamento incidentes a essa macrocélula, e de registos para cada leitura existente

no DFG;

• Os acessos necessitam da resolução estática do endereço base de cada array e do

circuito gerador do endereçamento. É necessário colocar um somador no circuito de

endereçamento sempre que os arrays não sejam colocados em posições de memória

que permitam formas simplificadas de endereçamento. A Figura 4.18 mostra o DFG

obtido dos bytecodes, no qual o endereço do array acedido se encontra armazenado

numa variável local, e um DFG representativo das transformações realizadas;

• Os nós do DFG representando a mesma variável, à qual foi atribuído um registo, são

transformados num único registo. A saída do registo é ligada a todos os laços de saída

dos nós dessa variável e são colocados multiplexadores ligados ao registo para

seleccionar de entre os laços incidentes aos nós da variável;

• Por cada ponto de selecção necessita de ser colocada no DFG global uma unidade de

selecção.

As unidades de selecção podem ser implementadas por um ou mais multiplexadores ou por

um conjunto de drivers tri-state. Por exemplo, a família XC6200 não suporta drivers tri-state

e por isso as unidades de selecção são sempre implementadas à custa dos multiplexadores de

duas entradas e de uma saída suportados por cada célula do FPGA. Em FPGAs com suporte a

tri-state, as unidades de selecção podem ser implementadas por uma linha acedida por estes

drivers. Este mecanismo de selecção tem vantagens óbvias, pois permite reduzir a área total

do circuito e o atraso do bloco de selecção face ao mecanismo implementado por

multiplexadores quando o número de linhas a seleccionar é acima de um certo valor8.

8 Depende da granulosidade e da arquitectura do FPGA.

CAP. 4 SUPORTE À GERAÇÃO DE RECONFIGWARE 101

… aload_1 bipush 7 iaload …

REG

0

GALADRIEL

SRAM MACRO

… … = A[7]; …

7

2 Nó de leitura da memória

Nó de variável

0x00000f00 7

Endereço real do array A na

memória.

NENYA

start

end

end

start

Figura 4 .18 . Transformações real izadas no DFG global para aceder à

memór ia externa quando os arrays não são co locados em posições de

memória que possibi l i tem a simpl i f icação do circui to de

endereçamento.

Durante o escalonamento o compilador estima a área e o atraso do multiplexador baseando-

se, sempre que necessário, na criação de uma árvore balanceada de multiplexadores. O

número de multiplexadores básicos (2 entradas:1 saída) é obtido subtraindo uma unidade ao

número de entradas (N), e o número de níveis da árvore é dado pela expressão log2(N). Os

multiplexadores considerados pressupõem que a selecção das linhas é realizada por linhas

descodificadas. Cada multiplexador recebe um conjunto de operandos v1, v2, … vn, e um

conjunto de sinais de selecção s1, s2, ..sm, e retorna um operando. Cada sinal de selecção tem

origem directa de um comparador ou da unidade de controlo. Além do conjunto de

multiplexadores (2:1) é necessária lógica para controlar a passagem de dados pela árvore de

modo a respeitar a funcionalidade pretendida. O número de portas lógicas equivalentes é

estimado como sendo igual ao número necessário de multiplexadores básicos, quando este

número é maior do que um (um multiplexador de duas entradas não precisa de lógica para

resolver a selecção na árvore balanceada de multiplexadores).

O NENYA gera o VHDL-RTL estrutural respectivo a partir do DFG global tendo em conta

as transformações necessárias e por isso não necessita da criação explícita do grafo

representativo da unidade de dados. A Figura 4.19a apresenta uma parte de um DFG global

102 CAP. 4 SUPORTE À GERAÇÃO DE RECONFIGWARE

típico ao qual foi atribuído um registo. A representação em grafo do hardware da unidade de

dados que implementa este DFG é apresentado na Figura 4.19b. Do DFG global da Figura

4.19a, o VHDL-RTL estrutural representativo do grafo da Figura 4.19b pode ser gerado

automaticamente sem ser necessária a criação deste último (ver Figura 4.19c).

A geração do VHDL-RTL estrutural para unidades de dados em que haja partilha da

macrocélula de acesso a uma memória é realizada de modo semelhante (sem criação explícita

de um grafo com a partilha).

REG 1

0

REG 1

1

0

2

3

4

REG 1

0

a ) b)

1. ... 2. lv_0 <= (others => “0”); 3. Mux_1: mux generic map(32) port map(sel_1_2, lv_0, lv_2, lv_aux_1); 4. REG1: reg generic map(32) port map(clock, load_1, lv_aux_1, lv_1); 5. lv_3 <= lv_1; 6. ... c )

Figura 4 .19 . Transformação entre a) DFG global (do lado direi to

encontram -se os ident i f icadores dos nós) e b) correspondente grafo da

unidade de dados; c) parte da estrutura descr i ta em VHDL.

Exemplo 4 -2 . Geração da unidade de dados para o exemplo da Figura

3.22.

A Figura 4.16 apresenta o grafo representativo da unidade de dados após a

aplicação das transformações ao DFG global da Figura 3.25 gerado pelo

NENYA a partir do exemplo da Figura 3.22. Este grafo é facilmente

CAP. 4 SUPORTE À GERAÇÃO DE RECONFIGWARE 103

representado em VHDL estrutural, pois apenas é necessário instanciar as

operações envolvidas (utilizando elementos da biblioteca tecnológica) e os

sinais que interligam esses componentes.

Como se pode ver na Figura 4.16 foram atribuídos dois registos

relacionados com o ciclo. O registo “REG i” é usado pela unidade de

controlo para supervisionar a execução das iterações do ciclo e o registo

“REG RESULT” armazena o valor do resultado rotulado de "L2NORM".

Os registos “REG Xi” e “REG Yi” são usados para armazenar os dados

lidos na memória externa pela macrocélula de acesso (os registos de

armazenamento do endereço, de cada dado de entrada na macrocélula de

acesso à memória não estão representados).

4.9 Suporte de Retaguarda da Geração de Reconfigware

De forma a implementar o hardware num FPGA é necessário gerar a descrição da unidade de

dados e da unidade de controlo num formato que possa ser suportado pelas ferramentas de

colocação e encaminhamento para o FPGA específico. Optou-se pelo formato EDIF

[Stanford90] por ser aceite pela maioria das ferramentas e suportar os atributos de colocação

relativa.

A geração do EDIF que representa a unidade de dados é uma simples tradução entre uma

estrutura definida em VHDL para EDIF, e por isso, caso também exista descrição estrutural

das macrocélulas, não necessita de passagem por ferramentas de síntese lógica. No caso da

compilação para a família de FPGAs XC6000 da Xilinx [Xilinx97] é usado o programa

VELAB [VelabURL] para fornecer as descrições em EDIF.

A descrição da unidade de controlo é gerada pelo compilador em VHDL-RTL

comportamental e por isso é necessário utilizar uma ferramenta de síntese lógica para se obter

o circuito final.

As etapas de retaguarda referentes ao uso de FPGAs da família XC6000 encontram-se

ilustradas na Figura 4.20. Para esta família de FPGAs foi usada a ferramenta de síntese lógica

104 CAP. 4 SUPORTE À GERAÇÃO DE RECONFIGWARE

“Design Compiler” da Synopsys [Synopsys95]. Contudo as etapas de síntese lógica

requeridas pelo NENYA podem ser realizadas por qualquer ferramenta de síntese lógica9

(Synplify [Synplicity99] da Synplicity, por exemplo), desde que o FPGA utilizado seja

suportado pela ferramenta.

No caso de não existirem descrições estruturais das macrocélulas para uma dada família de

FPGAs pode ser usada uma ferramenta de síntese lógica para obtenção do circuito da unidade

de dados. Neste caso, é utilizada a descrição comportamental das macrocélulas da biblioteca

tecnológica, podendo a síntese ser realizada por qualquer ferramenta de síntese lógica que

aceite descrições em VHDL e suporte o FPGA considerado.

Síntese Lógica

FPGA: Colocação e

Encaminhamento

Descrições RTL-VHDL

estrutura (EDIF)

bitstreams

Biblioteca de Macrocélulas para o FPGA

1. Synopsys Design Compiler 2. velab

XACTstep 6000 series

VHDL para EDIF

1 2

Unidade de Dados

Unidade de Controlo

Figura 4 .20 . Etapas de retaguarda a part i r da descr ição em VHDL para a

famí l ia XC6000 de FPGAs da Xi l inx .

4.10 Conclusões

Neste capítulo foram descritas as etapas realizadas pelo compilador NENYA para gerar a

unidade de dados.

9 Terá, logicamente, de suportar descrições fonte em VHDL-RTL.

CAP. 4 SUPORTE À GERAÇÃO DE RECONFIGWARE 105

Foram explicados os processos de atribuição de registos de modo a garantir o funcionamento

correcto dos ciclos, e de mapeamento de operações do DFG global em unidades funcionais

implementadas por macrocélulas. Foi apresentado o algoritmo que realiza o refinamento do

mapeamento quando existem várias unidades funcionais para implementar o mesmo

operador.

Foram descritas as vantagens do uso de macrocélulas para auxiliar as etapas de compilação e

as etapas de retaguarda necessárias para compilar para FPGAs. Foram também explicados os

acessos a memórias externas ao FPGA e a geração do VHDL estrutural que representa a

unidade de dados com base na instanciação de macrocélulas.

A partilha de componentes apresentada tem a limitação de só poder ser realizada entre

caminhos mutuamente exclusivos mas não necessita de interacção com a unidade de controlo.

O uso de controlo distribuído implementado por sequenciadores (simples contadores) com

comunicação entre si em vez da unidade de controlo central necessita de ser estudado. Esta

forma de controlo permitiria ter uma arquitectura alvo localmente síncrona e globalmente

assíncrona e não necessitaria de escalonamento global, pois a comunicação entre

sequenciadores garantiria a ordem correcta de execução das operações.

106 CAP. 4 SUPORTE À GERAÇÃO DE RECONFIGWARE

107

5. Optimizações do Grafo de Fluxo de Dados

“She lifted up her hand and from the ring that she wore there issued a great light that illuminated her alone and left all else dark.”

J. R. R. Tolkien, The Fellowship of the Ring

Neste capítulo são apresentadas as técnicas para optimização do grafo de fluxo de dados

(DFG) implementadas no compilador NENYA: reassociação de operações de uma expressão

e a redução da força (ou do custo) de operações. Ambas as técnicas ao potenciarem a redução

do caminho crítico e da área do circuito produzem soluções mais eficientes.

São ainda apresentadas técnicas para a determinação do número de bits “seguro” – suficiente

para preservar a funcionalidade - para cada operação do DFG global, tendo em vista a

redução do atraso e da área total do circuito final. São também apresentadas técnicas que,

baseadas no conhecimento de constantes ao nível do bit, exploram a possibilidade de

propagação dos bits constantes e permitem eliminar lógica desnecessária. Estas técnicas são

utilizadas ao nível da estrutura que interliga as operações (DFG), não necessitam da

representação de cada operador ao nível da porta lógica e foram implementadas e integradas

no compilador NENYA. São efectivas e eficientes em algoritmos com ciclos e permitem

melhoramentos significativos na geração de hardware específico.

Para finalizar o capítulo, são apresentados resultados obtidos pela execução do NENYA, com

e sem as etapas de optimização, que permitem aquilatar a potencialidade das técnicas

apresentadas (em alguns casos produzem resultados próximos de soluções quasi-óptimas).

108 CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS

5.1 Optimizações de Fluxo de Dados

Algumas das técnicas utilizadas na optimização de representações obtidas de linguagens

imperativas [Aho86], por produzirem bons resultados independentemente da máquina alvo

(tipo de processador ou hardware específico), encaixam bem nas fases iniciais de qualquer

compilador e por isso podem ser realizadas antes da compilação para o modelo intermédio

sobre o qual se efectuará a compilação para a arquitectura alvo utilizada. Em casos em que

não se tem acesso ao código original da aplicação, mas apenas a um modelo intermédio

(representação bytecodes, por exemplo), estas optimizações devem ser consideradas nesse

nível para colmatar eventuais deficiências.

As optimizações sobre o fluxo de dados englobam [Muchnick97]: propagação de constantes,

substituição de operações entre constantes pelo resultado estaticamente conhecido,

eliminação de operações redundantes (subexpressões comuns), eliminação de código morto

(inatingível), detecção de operações invariantes a iterações de ciclos e movimento destas para

fora do corpo do ciclo. As simplificações algébricas (por exemplo: I2, por I×I; -1×A, por -A; -

(-J), por J; 0+I, por I) são também independentes da arquitectura escolhida (a sua utilização

não necessita de conhecimento da arquitectura e produz sempre resultados iguais ou

melhores).

No fluxo de compilação proposto nesta tese, todas as técnicas anteriores pertenceriam a fases

de pré-compilação (optimização de bytecodes), não sendo neste momento concretizadas pelo

compilador GALADRIEL. Nesta fase é admitido que algumas destas técnicas foram

realizadas anteriormente (compilação para os bytecodes, por exemplo).

Outras optimizações transformam algumas estruturas de controlo em fluxos de dados como

são os casos do desenrolamento de ciclos e da expansão de funções. Estas técnicas podem

proporcionar, combinadas ou não com as optimizações de fluxo de dados, graus de

paralelismo mais elevados, mas não foram incluídas nesta versão do compilador por não

serem o objectivo principal do trabalho.

Algumas optimizações sobre o fluxo de dados são específicas a uma determinada

implementação. Neste conjunto encontram-se: redução da força de operações1 (ex. 2×I, por

1 Em inglês: operator strength reduction.

CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS 109

I<<1; 3×I, por I+(I<<1)), reunião de operações sucessivas em uma única operação existente

na biblioteca com funcionalidade equivalente, e reassociação de operações2 (THR)

[Gajski92][Micheli94]. O uso de THR foi primeiramente estudado por [Baer68][Muraoka71]

e estendido posteriormente em [Brent74].

A redução da força de operações é uma técnica maioritariamente aplicada às operações de

multiplicação e divisão sobre dados do tipo inteiro, quando um dos operandos é uma

constante [Magenhei88]. A técnica resume-se à substituição destes operadores por operações

de menor custo (adição, subtracção e deslocamento). A operação de subtracção pode ser

utilizada quando não é feito tratamento de overflows da operação original no modelo

utilizado (ex. 7×I, por (I<<3)-I) 3.

A reassociação de operações de forma a permitir a diminuição da altura de um DFG é

bastante poderosa quando a máquina computacional alvo tem capacidade para executar várias

instruções em paralelo. Esta transformação possibilita, através de algumas propriedades

matemáticas (comutatividade, associatividade e distributividade), em muitos casos, a redução

do número de operações em cascata e, como será explicado posteriormente, a diminuição do

próprio tamanho dos operadores.

Em seguida são apresentadas as técnicas – reassociação e redução da força de operações - que

foram implementadas no NENYA.

5.1.1 Reassociação de Operações

Como foi referido anteriormente a reassociação de operações é uma transformação realizada

sobre o fluxo de dados que permite reordenar um DFG de modo a que a distância do início ao

fim seja reduzida (expondo maior grau de paralelismo). A transformação baseia-se nos casos

mais simples (quando todos os nós do conjunto considerado desempenham a mesma

operação) no balanceamento de uma árvore, ou na utilização das propriedades associativa,

comutativa e distributiva em casos mais complexos. A redução conduz a melhores resultados

na maioria dos casos, principalmente quando em presença de recursos suficientes para fazer

face ao paralelismo acrescentado. A reassociação na presença de operações com atrasos

2 Conhecida na literatura por Tree-Height Reduction (THR). 3 Transformações deste tipo podem ser utilizadas em linguagens que ignorem o overflow.

110 CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS

diferentes tem como objectivo a diminuição do atraso do DFG que pode não ter a mesma

solução do que a diminuição da altura do grafo.

A redução permite também que a computação do número de bits obtenha, em alguns casos,

melhores resultados. Na Figura 5.1 é apresentado um exemplo que ilustra o uso de THR para

reduzir o atraso do circuito. A optimização permitiu a redução do número de bits de dois dos

somadores com consequências na diminuição da área e do próprio atraso.

start

end

+

a2

a)

+

+

b

c

d

2

3

4

5

2

2

start

end

+

a2

+

+

b d2

3 3

4

2c2

b)

Figura 5 .1 . Impacto do uso de THR na computação do número de b i ts :

a ) cadeia de somadores com três n íveis; b) redução do número de

n íve is para dois com consequente redução do número de b i ts . Os

rótulos nos laços indicam o número de bi ts suf ic iente.

Por questões de prioridade, a versão actual do compilador NENYA realiza apenas THR de

cadeias de adições, multiplicações, ANDs e ORs, por se julgarem os casos mais comuns. Este

suporte a THR permitiu a avaliação do impacto nos exemplos considerados nesta tese. Após a

extracção destas cadeias no DFG, o compilador gera, para cada uma, uma árvore balanceada

e refaz o DFG com base nas árvores geradas. A colocação das entradas em cada árvore

balanceada deve ser de modo a permitir que os resultados disponíveis mais cedo possam ligar

ao último nível da árvore (primeiro nível de lógica). Existem casos em que o uso de THR

pode desfavorecer o escalonamento [Cardoso99e] e por isso a sua aplicação pode ser inibida

por uma opção do compilador. Esta deterioração pode ocorrer quando a unidade a partilhar

tem atraso maior do que a cadeia de operadores potencial para o THR.

CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS 111

A Figura 5.2 apresenta os resultados do escalonamento (número máximo de ciclos de relógio

para executar o reconfigware) da soma de todos os elementos de um array, considerando

arrays com 10, 20, 30 e 40 elementos, e do tipo byte, short e int, com e sem utilização

de THR. O escalonamento é o resultado da aplicação do escalonador estático baseado em

lista (descrito no capítulo 7) considerando que os elementos do array se encontram todos na

mesma memória acoplada ao FPGA. Considera-se também que a memória é de porto único.

Os resultados mostram ganhos que atingem valores próximos de 60% (soma de 40

elementos) quando se utiliza THR, mesmo em exemplos em que o paralelismo não é

completamente explorado devido à restrição de apenas se efectuar um acesso à memória ao

mesmo tempo.

0

10

20

30

40

50

60

10 20 30 40

Número de elementos somados

Mel

ho

ria

rela

tiva

no

es

calo

nam

ento

(%

)

byte[] short[] int[]

Figura 5 .2 . Resul tados da apl icação de THR e da afer ição do número de

b i ts suf ic iente no escalonamento de exemplos que somam elementos

d e u m array. Os resul tados apresentam a melhor ia re lat iva sobre o

esca lonamento sem THR.

5.1.2 Redução do Custo de Operações

Esta técnica de optimização, como foi anteriormente referido, permite a substituição de

operações com custos elevados (área, atraso, etc.) por operações de custos menores que

implementem a funcionalidade inicial. Os casos mais simples de redução do custo de uma

operação ocorrem quando em presença de divisões ou multiplicações por constantes do tipo 2

elevado a N, em que N representa um número inteiro positivo. Nestes casos, cada operação é

substituída por um deslocamento por uma constante (implementado por interligações), de

112 CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS

valor N, para a esquerda ou para a direita caso se trate, respectivamente, de uma

multiplicação ou de uma divisão.

Quando a constante não é do tipo 2N a redução do custo da operação (multiplicação ou

divisão) tem de ser feita com base em adições, subtracções e deslocamentos. Nestes casos o

compilador NENYA apenas realiza a redução do custo de operações em multiplicações por

constantes com os métodos explicados de seguida. Trabalhos futuros devem considerar a

redução do custo de divisões por constantes deste tipo.

Uma forma natural de realizar a redução do custo de multiplicações por constantes é a

geração de sequências de deslocamentos e adições. Esta transformação pode ser obtida por

inspecção na representação binária da constante pelos bits de valor lógico igual a um, sendo

por isso de implementação fácil. Este método utiliza, considerando que a constante tem N bits

de valor lógico um, N-1 adições. O aumento linear de operações com o número de bits da

constante indicia que esta técnica pode não fornecer soluções eficientes.

De forma a proporcionar soluções mais eficientes, o algoritmo realizado para redução do

custo de multiplicações por constantes cria uma árvore exaustiva da decomposição da

operação em sequências de multiplicações por constantes do tipo 2N (implementadas por

simples deslocadores por constantes) considerando sequências de adições e subtracções.

Supondo que o menor ramo da árvore criada é constituído por K níveis, então a expressão

final necessita de K-1 operações de soma ou subtracção. A criação da árvore pode ser

melhorada por memorização de expressões (linha a tracejado da Figura 5.3) e supressões

(pruning) no espaço de procura de modo a evitar construções e procuras redundantes.

Exemplo 5 -1 . Redução do custo de mult ip l icação por constantes.

Considere-se a multiplicação de uma variável do tipo inteiro, a, pela

constante 350 (350×a). A árvore da decomposição da expressão em somas e

subtracções de multiplicações por constantes do tipo 2N está ilustrada na

Figura 5.3. As setas a tracejado na figura representam memorização de

expressões cuja decomposição já havia sido representada na árvore. Por

inspecção da árvore o algoritmo escolhe a primeira expressão encontrada

com o menor número de operações: 512×a-(128×a+32×a+2×a). A

expressão 256×a+128×a-(32×a+2×a) é outra das soluções com número

mínimo de operações. A solução com apenas deslocamentos e adições pode

CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS 113

ser obtida directamente da representação binária da constante (350 =

b’101011110): 256×a+64×a+16×a+8×a+4×a+2×a. Esta última solução

precisa de 5 somas ao invés de 2 somas e de 1 subtracção requeridos pela

primeira solução. Este exemplo ilustra a redução permitida pelo uso de

somas e subtracções em vez de apenas somas.

512×a

350×a

256×a 94×a

256×a 94×a 128×a

162×a

34×a

128×a 34×a 64×a 30×a

64×a 30×a 32×a 2×a

32×a 2×a 16×a 14×a

16×a 2×a 8×a 6×a

128×a 34×a 64×a 30×a

64×a 30×a 32×a 2×a

32×a 2×a 16×a 14×a

8×a 2×a 4×a 2×a

Figura 5 .3 . Árvore de decomposições da expressão 350 × a .

A Figura 5.4 ilustra a distribuição da expressão a×C, variando a constante C de 0 a 65.535,

pelo número de operações obtido utilizando o método apresentado de redução do custo da

multiplicação em somas, subtracções e deslocamentos. O número máximo de operações

(adições e/ou subtracções) obtido é de 9. Com a redução do custo obtida directamente da

representação binária o número máximo de somas é de 16. Como se pode ver, o uso de somas

e subtracções em vez do uso de apenas somas pode reduzir significativamente o número de

operações necessárias com redução da área e do atraso do circuito para implementar a

funcionalidade original (multiplicação por uma constante).

A utilização de redução do custo de operações é deixada ao critério do utilizador (através da

invocação de uma opção quando da execução do NENYA), de forma a que este possa avaliar

o impacto desta no reconfigware final.

114 CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS

0

2000

4000

6000

8000

10000

12000

14000

16000

18000

1 2 3 4 5 6 7 8 9 10

#Operações (adições/subtracções)

#Co

nst

ante

s

Figura 5 .4 . Número de operações (adições e mult ip l icações) obtidas

pela decomposição binár ia para redução do custo de mult ip l icações de

uma var iável por constantes de 0 a 65.535 (16 bi ts) com o uso de

adições, subtracções e deslocamentos (não considerados no número

de operações) . O eixo vert ical representa o número de constantes.

Como trabalho futuro podem ser considerados algoritmos que, para obtenção de soluções

mais eficientes, para além de decompor possam também factorizar. Este último método é

baseado na factorização da constante e posterior substituição de cada uma das constantes por

somas/subtracções e deslocamentos [Bernstein86][Briggs94].

Ao novo DFG obtido por aplicação destas técnicas deve ser aplicado THR para produzir

implementações melhores em hardware reconfigurável. Neste momento a aplicação desta

técnica é apenas considerada para cadeias com a mesma operação desde que esta goze da

propriedade associativa.

5.2 Trabalhos Prévios em Aferição do Número de Bits de

Representação

Em muitos programas os tipos de dados utilizados apresentam um sobredimensionamento no

que respeita ao número de bits necessário para preservar a funcionalidade pretendida. Este

facto pode não afectar o desempenho e área quando são utilizados elementos de

processamento com unidades de dados fixas (microprocessadores, por exemplo), mas pode

ser incomportável em elementos de processamento com capacidades específicas e

CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS 115

especializadas. As linguagens mais disseminadas para programar software apenas permitem

declarações de tipos de dados inteiros em alguns múltiplos do byte, para ajudar o

programador e principalmente devido às implementações em microprocessadores RISC4 não

favorecerem na maioria dos casos a especificidade. Alguns autores adoptaram, para projecto

de sistemas embebidos baseados em núcleos de processamento com unidade de dados

parametrizável no que respeita ao tamanho de palavra, linguagens baseadas no C como é o

caso da linguagem Valen-C em que o programador tem de especificar o número de bits para

cada tipo de dados aquando da declaração [Inoue98]. Contudo o uso de declarações com

especificação do número de bits tornam a programação mais complexa e dão muitas vezes

azo a especificações erróneas, pelo facto do programador não se ter apercebido, por exemplo,

da possível saturação de uma determinada variável.

Por estes motivos é necessário integrar em compiladores para hardware reconfigurável

técnicas que permitam reduzir o número de bits de cada operação e operando do algoritmo

fonte, preservando a funcionalidade original. A redução do número de bits tem implicações

directas na área e no atraso dos circuitos gerados, como é o caso da compilação com suporte

de macrocélulas com propriedades de especialização.

A aferição estática do número de bits das operações foi previamente utilizada por

[Razdan94a][Razdan94b][Razdan94c] no âmbito da utilização de unidades de lógica

reconfigurável acopladas à unidade de dados de um microprocessador. Estes autores

apresentam análises que exploraram a integração de sequências de operações talhadas para

serem implementadas por instruções especiais, com preponderância de sequências de

instruções que manuseiam bits.

Com base em algumas das técnicas previamente apresentadas, realizaram-se estudos que

permitiram o desenvolvimento de análises estáticas de aferição do número de bits.

Praticamente em paralelo [Budiu00] propôs também técnicas com objectivos similares. A

utilização da linguagem DIL5 - que só permite que o programador especifique os subtipos no

interface da função com o exterior – pelos autores torna proibitivo o uso de análises de

aferição do número de bits.

4 Do inglês: Reduced Instruction Set Computers. 5 Do inglês: Dataflow Intermediate Language, que é uma linguagem intermédia para compilação de linguagens alto-nível.

116 CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS

Em [Stephen00] são propostas análises baseadas na determinação dos intervalos de valores

para cada variável. A análise é completamente estática e para casos com sequências não

lineares os algoritmos iteram até encontrarem o ponto fixo. Embora estas análises possam

determinar intervalos mais próximos dos efectivamente necessários, pois incluem também

informações paralelas (o tamanho de arrays e o facto dos índices a estes arrays não

indexarem elementos fora destes tamanhos, por exemplo), não têm a capacidade de lidar ao

nível de bits sem ser nas extremidades de cada palavra.

Alguns autores que utilizam análises dinâmicas com métodos baseados na extracção de

informação através da execução do programa reclamam, justamente, que a análise estática é

frequentemente demasiado pessimista. Contudo, as análises dinâmicas incorrem do elevado

tempo de execução, em presença de estruturas cíclicas encadeadas, e podem retornar

informação dependente do conjunto de prova utilizado, podendo por isso incorrer em

imprecisões quando entradas não abrangidas no conjunto de prova desencadeiam padrões de

execução não considerados na fase de análise. Contudo, em [Ogawa99] foi proposta uma

nova forma de análise dinâmica que não necessita de conjuntos de prova, embora mantenha a

desvantagem de requerer longos tempos de compilação.

Implementações capazes de tirar dinamicamente partido da presença de dados com número

de bits de representação não standard têm também sido abordadas no contexto de

arquitecturas de processadores genéricos [Brooks99].

Há autores [Bondala99b] que, em computação reconfigurável, apresentaram formas de

especialização do hardware para cada iteração de um ciclo, com base na extracção do número

de bits suficiente, através de análise dinâmica baseada em conjuntos de prova.

Das técnicas estáticas utilizadas, a abordagem apresentada neste capítulo é mais eficiente do

que as análises com base no desenrolamento do ciclo, ou com simulação das iterações deste.

Algumas das técnicas aqui descritas, principalmente as análises para aferição do número de

bits suficiente e a propagação de constantes ao nível de bit, apresentam conceitos, tanto

quanto sabemos, nunca até aqui considerados num compilador.

As técnicas de [Budiu00] e de [Stephen00], tal como as técnicas propostas nesta tese,

melhoram os pressupostos de [Razdan94a][Razdan94b][Razdan94c] ao considerarem

também ciclos. Contudo, a forma de lidar com ciclos é diferente da técnica proposta nesta

tese, na qual são consideradas expressões que captam o comportamento de operações com as

CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS 117

iterações do ciclo em vez de iterar um ciclo até ao ponto estável ser encontrado. Outras

diferenças residem no uso do DFG em vez do uso de cadeias definição-uso.

5.3 Aferição de Subtipos Primitivos nos Bytecodes

A JVM utiliza operadores com comprimento de palavra de 32 ou 64 bits. Quando, por

exemplo, é necessário proceder a uma operação de 32 bits cujo resultado é representado em 8

bits (tipo primitivo byte) é utilizada, a seguir à operação, uma instrução que converte o

resultado de 32 em 8 bits (int2byte).

A análise começa com a atribuição a cada nó do número conservador de bits (32 ou 64 bits).

Nos pontos de conversão é atribuído o número de bits do tipo para o qual um determinado

valor é convertido, e nos nós que representam constantes é fixado o número necessário para

representar o valor, número este que não volta a ser mudado durante as propagações

efectuadas pelas análises.

Para se extraírem os tipos de dados primitivos de uma representação de tamanho menor que

32 bits, utilizados pela JVM (byte, char e short), é necessário propagar no sentido oposto ao

fluxo de dados e no sentido do fluxo de dados (a partir daqui utilizar-se-ão os termos

propagação inversa e propagação directa) a informação dada pelas conversões de tipos. As

variáveis que constituem argumentos ou que são retornadas duma função têm representações

nos bytecodes explicitamente tipificadas e, por esse motivo, revelam-se importantes na

inferência de tipos primitivos.

Este esquema com propagações inversas e directas deve ser repetido até que haja

convergência, ou seja, até que deixe de haver alterações durante as propagações. As

propagações referidas são feitas no DFG global (percorrendo em sentido directo ou em

sentido inverso as cadeias de operações que o constituem). Esta análise é parecida com a

análise identificada em [Aho86] para inferir tipos na análise de linguagens com referências-

fracas6 (apontadores que podem referenciar qualquer tipo de dados - apontadores para tipo

void na linguagem C, por exemplo) e foi, tanto quanto sabemos, pela primeira vez utilizada

no âmbito de inferência de tipos primitivos na JVM pelo autor desta tese em [Cardoso99a].

6 Do inglês: weak-references, que é o oposto de strong-references (referências fortes: quando o tipo de dados para o qual um ponteiro aponta é conhecido estaticamente).

118 CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS

O facto de nos bytecodes o tipo boolean ser representado como byte pode implicar

implementações sobredimensionadas quando não é feita a aferição do número de bits de cada

operando/operação existente no DFG.

Exemplo 5 -2 . Aferiç ão de subt ipos pr imit ivos nos bytecodes.

Na Figura 5.5 é apresentado o código de um exemplo que ilustra uma

conversão de tipos e o respectivo DFG. O exemplo consiste de uma

multiplicação de dois inteiros (32 bits) em que só são utilizados os 8 bits

menos significativos do resultado. Como a operação de multiplicação

precisa de fornecer apenas esses 8 bits, é intuitivo que são apenas

necessários os 8 bits menos significativos de cada um dos operandos e

consequentemente a operação pode ser realizada por um multiplicador com

operandos e resultado representados cada um por 8 bits (8 × 8 = 8)7.

start

end

l1

iload_1iload_3imuli2bistore_2

l2

l3

int a, b;…byte c = (byte) (a * b);

8i2b: converte uma representação deinteirocom sinal de tamanho 32para 8 bits.

Figura 5 .5 . Exemplo de afer ição de t ipos pr imit ivos do DFG.

A técnica anterior permite a inferência dos subtipos de dados primitivos da linguagem Java

nos bytecodes da aplicação. Contudo, os tipos de dados utilizados pelo programador não são

necessariamente as escolhas acertadas e o facto de ter de considerar tipos de dados de um

subconjunto dos múltiplos do byte origina, muitas vezes, o sobredimensionamento na escolha

do tamanho das variáveis para armazenar os valores. De forma a que o hardware gerado seja

o menos dependente possível das declarações de dados impostas pelo programador, são

necessárias análises mais poderosas/sofisticadas que permitem determinar o número

7 Operandos e resultado de 8 bits.

CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS 119

suficiente de bits para cada operador e para cada operando preservando a funcionalidade

original. Neste sentido, são apresentadas na próxima secção técnicas de aferição do número

de bits que se servem da inferência dos tipos de dados primitivos para fornecer os majorantes

do número de bits para cada operando e operador.

5.4 Aferição do Número de Bits de Representação no NENYA

A análise baseia-se no atravessamento em sentidos inverso e directo do DFG e no uso de

regras para cada operação que permitem a propagação do número de bits. A Tabela 5.1

apresenta as regras utilizadas com alguns operadores. Por exemplo, a cada operação lógica do

tipo AND, em que um dos operandos é uma constante positiva, é atribuído ao resultado o

número de bits até ao último bit de valor lógico um presente na representação binária da

constante. As atribuições apresentadas só são feitas se o número de bits que daí resulta for

inferior ao número de bits actual.

Tabela 5 .1 . Regras de propagação em sent idos directo e inverso para

a lguns operadores. Bi ts(A) representa o número de bi ts para o

operando A.

Operação A = B op C

Sentido directo Sentido inverso

× Bits(A) = Bits(B) + Bits(C) Bits(B) = Bits(Asucc) Bits(C) = Bits(Asucc)

+, - Bits(A) = MAX(Bits(B), Bits(C))+1 MAX: valor máximo

Bits(B) = Bits(Asucc) Bits(C) = Bits(Asucc)

>>, >>>, C == const Bits(A) = Bits(B) - Bits(const) Bits(B) = Bits(A)+Bits(const) <<, C == const Bits(A) = Bits(B) + Bits(const) Bits(B) = Bits(A)-Bits(const) &, |, ^, ~ Bits(A) = MAX(Bits(B), Bits(C))

MAX: valor máximo Bits(B) = Bits(Asucc) Bits(C) = Bits(Asucc)

&, C== const Bits(A) = NumBits2LastOne(const) NumBits2LastOne: Número de bits do bit menos significativo até ao bit mais significativo de valor lógico um.

Bits(B) = Bits(Asucc)

A= MUX(A1, A2, …An) MUX: multiplexador

Bits(A) = Máximo de bits de todos os predecessores

Bits(Ai) = Bits(Asucc)

Com o uso do DFG o compilador extrai para cada operador o número de bits suficiente de

modo a preservar a funcionalidade original. Para cada laço do DFG é atribuído o número de

bits. Este número de bits é sempre menor ou igual ao número de bits inferido pela análise

efectuada de aferição de subtipos.

120 CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS

Algumas operações permitem identificar operandos sempre positivos, permitindo assim

eventuais simplificações. O facto de nos bytecodes e na própria linguagem Java não existirem

tipos para declarações de variáveis que armazenem apenas números inteiros positivos (ao

contrário do tipo unsigned int da linguagem C, por exemplo) pode tornar a aferição do

número de bits menos agressiva, ao não poder, ou não ser possível identificar, em algumas

situações, operandos sempre positivos.

Na propagação inversa, quando na presença de um nó em que a saída fornece valores a mais

do que um operador, o número de bits a atribuir é o número de bits máximo de todos os laços

de saída que o nó tem, sempre que este número seja menor que o número de bits considerado

inicialmente (antes das propagações).

No caso de operadores de deslocamento em que ambos os operandos não são constantes, é

preservada a informação ou utilizado o valor máximo (desde que este valor seja inferior ao

valor inicial) quando o operador é respectivamente um deslocador para a direita ou para a

esquerda.

A Figura 5.6 e a Figura 5.7 ilustram simplificadamente os algoritmos de propagação inversa e

directa. As funções CompWidthRev e CompWidthFor são baseadas nas regras representadas

na Tabela 5.1. Os algoritmos apresentados são iterativos devido ao facto de necessitarem de

menos memória, do que algoritmos recursivos ou algoritmos baseados na utilização de uma

lista ou pilha com os sucessores ou predecessores do nó em análise.

1. Boolean change =false; 2. Do 3. Change = false; 4. Foreach Node A ∈ DFG 5. Foreach Bi ∈ (A.getPred() ≠ STARTnode) 6. Bi.setWidth(CompWidthRev(A, Bi)); 7. Forall Cj ∈ (Bi.getSucc() ≠ ENDnode) 8. MaxOut = max(Cj.getWidth()); 9. 10. Bi.setWidth(MaxOut, MaxWidth(Bi)); 11. If(width of Bi was modified) change = true; 12. 13. 14. while(change);

Figura 5 .6 . Algor i tmo de propagação em sent ido inverso.

CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS 121

1. Boolean change = false; 2. Do 3. Change = false; 4. Foreach Node A ∈ DFG 5. Foreach Bi ∈ (A.getPred() ≠ STARTnode) 6. If(A ≠ ConstNode) 7. A.setWidth(CompWidthFor(A, Bi)); 8. 9. 10. If(width of A was modified) change = true; 11. 12. while(change);

Figura 5 .7 . Algor i tmo de propagação em sent ido directo.

Este método serve para determinar o número de bits suficiente para cada operando/operador

que, quando permite a redução, tem implicações directas na área e no desempenho da unidade

de dados.

5.5 Propagação de Padrões de Constantes ao Nível do Bit

Além da redução do número de bits suficiente para cada operador, para se obterem melhores

resultados no circuito final, deve ser considerada a propagação de constantes ao nível do bit,

pois esta permite em algumas operações reduzir a área e o atraso do circuito gerado, devido à

simplificação obtida quando se sabe à partida que um determinado bit tem valor lógico um ou

zero. Estas simplificações podem produzir melhores resultados quando em presença de

operações lógicas e são de uso limitado em operações aritméticas, como se pode ver pela

Tabela 5.2. Ao nível dos operadores lógicos é fácil aos geradores de circuitos instanciarem as

portas necessárias com base no conhecimento de bits constantes.

Outra simplificação pode ocorrer quando os padrões de entrada de uma dada operação têm

valores lógicos iguais numa determinada posição. Quando em presença de multiplexadores e

comparadores, esses bits constantes e com o mesmo valor podem ser excluídos da

computação realizada por estas operações (por exemplo: a comparação, 00uuu0 == u0uuuu,

pode ser realizada com um comparador de 5 bits em vez de 6, pois o bit 5 de ambos os

operandos tem o mesmo valor), reduzindo deste modo a área total necessária.

122 CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS

Tabela 5 .2 . A lgumas operações e respect ivas s impl i f icações quando em

presença de um operando constante .

Operação bit tem o valor lógico zero bit tem o valor lógico um AND Bit de saída igual a zero Bit de saída ligado ao bit de entrada OR Bit de saída ligado ao bit de entrada Bit de saída igual a um XOR Bit de saída ligado ao bit de entrada Bit de saída igual ao bit de entrada invertido EQ8 Bit de saída ligado ao bit de entrada

invertido Bit de saída igual ao bit de entrada

+9 Bit de saída ligado ao bit do carry-out do último FA

-

A representação utilizada dos padrões de constantes ao nível do bit é baseada em três estados

para cada bit 0, 1, u, representando respectivamente os valores lógico zero, um e

indefinido10 (representa um sinal cujo valor não é possível conhecer estaticamente). Esta

representação, de modo a facilitar a propagação, foi codificada em duas representações de

padrões: a representação do valor lógico zero (PZ) e do valor lógico um (PU). Cada padrão é

representado num inteiro em que a posição de cada bit representa o estado do respectivo bit

do operador considerado. O padrão que representa o valor lógico zero utiliza o zero para

representar o zero e o valor lógico um para representar outro valor qualquer. O padrão que

representa o valor lógico um utiliza o um para representar o um e o zero para representar

outro valor qualquer. Na Tabela 5.3 é ilustrada a representação utilizada para cada bit e o

respectivo valor lógico.

Esta representação permite, durante a propagação, que para cada operador lógico no DFG

seja simplesmente realizada uma operação lógica sobre os padrões de entrada. A Tabela 5.4

apresenta as regras utilizadas pelo algoritmo de propagação directa, idêntico ao apresentado

na Figura 5.7. Esta análise pode ser estendida para multiplicações e adições/subtracções

embora regras para lidarem com este tipo de operações sejam dependentes da estrutura das

unidades utilizadas. Por exemplo, a área do multiplicador pode ser reduzida quando os

operandos de entrada têm os primeiros bits iguais ao valor lógico zero (estes podem ser

8 Esta simplificação é exemplificada, mas apenas se deve ao facto do primeiro nível do operador EQ (retorna o valor um quando os dois operandos de entrada são ambos iguais) ser constituído por XORs. Esta simplificação é de utilização limitada, por ser dependente da estrutura da unidade funcional. 9 Esta simplificação apenas se deve ao facto de se assumir a utilização de um somador do tipo ripple-carry constituído por FAs (do inglês: Full-Adders - somadores completos). 10 Não confundir com o 'u' normalmente utilizado na lógica de 9 estados, na qual indefinido indica que ainda não foi inicializado.

CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS 123

directamente ligados à saída, ou para simplificar o encaminhamento não seriam ligados ao

multiplicador e este encarregar-se-ia de fornecer o valor lógico zero para a saída).

Tabela 5 .3 . Codif icação e o respect ivo valor lógico para cada bit .

Codificação Bit1,bit0 00 01 10 11

Valor lógico 0 Não utilizado u 1

Tabela 5 .4 . Regras para a propagação de padrões de constantes ao

nível do bi t em alguns operadores.

Operação Padrão dos zeros (PZR) Padrão dos uns (PUR) >>, >>>, const PZA >>, >>> const PUA >>, >>> const <<, const PZA << const PUA << const & PZA & PZB PUA & PUB &, const PZA & const PUA & const ^ ^, const

One = PZA ^ PUA | PZB ^ PUB; Two = PZA & PUA ~( PUB & PZB) | PZB ^ PZB & PUB~( PUA & PZA); PZR = Two; PUR = One | Two;

| PZA | PZB PUA | PUB |, const PZA | const PUA | const ~ ~PUA ~PZA * FirstBitsResult = NumBits2FirstOne(A) + NumBits2FirstOne(B);

Igual a 00 (0) outros iguais a 01 (u) MUX PZR = & (PZs dos predecessores); PUR = | (PUs dos predecessores); outras 1…11 0…00

Aquando do mapeamento das unidades funcionais a área do circuito para cada operador é

estimada com base no número de bits determinado e nos padrões de entrada. Por exemplo, se

os dois padrões de entrada de um operador lógico AND forem 0uu e 01u (saída 0uu, que

induziria 2 portas AND), é apenas necessário utilizar uma porta AND dado que o valor lógico

um no segundo operando permite a utilização de um simples fio que liga o segundo bit menos

significativo do primeiro operando ao segundo bit menos significativo do resultado.

Procedimentos similares são utilizados com outros operadores lógicos.

A Figura 5.8 apresenta a técnica da propagação de padrões de constantes ao nível do bit para

um exemplo em que se pretende trocar as posições de dois bits. Pode verificar-se pelo

exemplo que estas técnicas conseguem determinar que a função pode ser efectuada apenas

por interligações.

124 CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS

start

end

>> &

<<&

|

1

1

1

131

22

1

32 32

32

start

end

>> &

<<&

|

1

1

1

11

22

1

1 2

2

start

end

>> &

<<&

|

1

1

1

10u0

u1u0u1u0

0u1

0u1 u00

u0u1

a) b) c)

Figura 5 .8 . Exemplo que reverte os dois pr imeiros bi ts de uma palavra:

a) propagação para trás; b) propagação para a f rente; c) propagação de

padrões de constantes ao nível do bi t . Os rótulos nos laços em a) e b)

indicam o número de bi ts suf ic iente e os rótulos em c) indicam a

representação dos padrões (os índices nos u’s indicam o número do

bit).

Estas técnicas também permitem ao compilador NENYA identificar que instruções de alto

nível, tais como (detecção do valor de um bit):

if((ans & 0x8000) == 0x8000)

podem ser implementadas sem utilização de portas lógicas.

Em [Budiu00] é utilizada a propagação de don’t cares. Esta análise pode ter impacto na

propagação inversa de máscaras AND de bits internos (1010, por exemplo). Este tipo de

propagação, apenas suportado neste momento nos bits mais significativos (0111, por

exemplo), poderia ser integrado sem dificuldade nas análises propostas nesta tese.

5.6 Aferição do Número de Bits em Regiões Cíclicas

As regiões cíclicas de um programa desempenham um papel fundamental pois normalmente

representam as partes mais intensivas de computação, e por isso são as melhores candidatas a

optimizações. É nestas regiões que pequenas reduções no tamanho de bits de uma operação

podem implicar ganhos elevados ao nível do atraso total do ciclo, devido ao facto do

operador ser por norma executado várias vezes.

CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS 125

A cada nó do DFG pertencente a uma região cíclica é atribuído o número de vezes que será

executado em cada chamada da função que o contém. Nos casos em que não é possível

determinar estaticamente este número11 é atribuído +∞ ao nó.

Exemplo 5 -3 . Ident i f icação do número de bi ts na presença de cic los.

Do exemplo a seguir pode ver-se que a variável Sum entra no ciclo com

valor zero atribuído (1 bit necessário):

Short[] A;

Int Sum = 0;

For(int I=0; I< 10; I++)

Sum += A[I];

O ciclo executará 10 iterações. Assim, a variável Sum necessitará de 16 +

log2(11) = 20 bits (< 32 bits da representação do int). A variável de

controlo de iterações do ciclo, I, toma valores entre [0, 10], e requer 1 +

log2(11) = 5 bits.

Para uma determinada soma com uso-definição de operandos do tipo A = A+B, em que não

existem definições da variável B dentro da região cíclica e, supondo que a instrução é

executada N vezes, pode ser obtido um limite superior do número máximo de bits suficiente

para armazenar o valor da variável A por:

++≤ )1(log))(),(max()( 2 NBBitsABitsABits inicial (5 .1 )

em que Bits(Ainicial) indica o número de bits da variável A imediatamente antes da execução

do ciclo. Quando existem definições da variável B dentro da região cíclica obtemos:

NBBitsABitsABits inicialinicial +≤ ))(),(max()( (5 .2 )

11 Por dois motivos: porque a análise implementada não é suficientemente poderosa para extrair a informação, ou por que de facto o número de vezes que o nó é repetido depende dos valores dos dados com que o programa é estimulado.

126 CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS

A Figura 5.9 apresenta o número de bits suficiente para armazenar o valor da variável A,

considerando a expressão A = A + 3 (com o valor 0 atribuído inicialmente a A), em cada

iteração para um total de 20, obtido pela simulação da execução repetitiva da expressão e pela

aplicação directa da equação (5.1).

01234567

1 3 5 7 9 11 13 15 17 19

Iteração (N)

mer

o d

e b

its

Óptimo Limite Superior

Figura 5 .9 . Número de bi ts da var iável A suf ic iente para cada i teração

(exemplo A = A + 3 , com 0 como valor in ic ia l de A) .

No caso de se estar perante uma operação de multiplicação em que há iterativamente uso-

definição de um dos operandos, como seja a instrução A = A ×× B, supondo como

anteriormente que esta instrução é executada N vezes, e que não existe qualquer definição de

B dentro da região cíclica:

)()()( BBitsNABitsABits inicial ×+≤ (5 .3 )

Quando existem definições da variável B dentro da região cíclica obtemos:

[ ])()(2)( 1inicialinicial

N BBitsABitsABits +×≤ − (5 .4 )

Quando na presença de expressões do tipo A = A << k, em que k é um valor constante,

teremos:

kNABitsABits inicial +≤ )()( (5 .5 )

CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS 127

Quando na presença de expressões do tipo A = A >> k, em que k é um valor constante,

teremos:

kABitsABits inicial −≤ )()( (5 .6 )

A inequação (5.6) é utilizada para salvaguardar o valor das expressões intermédias. Contudo,

no final da execução do ciclo com N iterações, a variável A poderia ser representada pelo

número de bits inicial menos N vezes k se a expressão for de facto executada N vezes.

Devido ao facto da análise ser insensível ao fluxo de programa, para salvaguardar a correcta

funcionalidade é utilizada simplesmente a equação (5.6).

As equações anteriores têm como valor máximo o número de bits do tipo de dados em que

cada variável foi declarada. Dos exemplos apresentados torna-se intuitiva a forma como é

calculado o número de bits para os restantes operadores.

O algoritmo implementado executa sobre o DFG global12 e integra os algoritmos

apresentados na Figura 5.6 e Figura 5.7 com ligeiras modificações. As etapas do algoritmo

são as seguintes:

1. Propagação em sentido inverso sem distinção de operações em regiões cíclicas;

2. Propagação em sentido directo sem distinção de operações em regiões cíclicas;

3. Propagação em sentido directo a partir dos nós de variáveis aos quais foi atribuído um

registo que representam no DFG a primeira atribuição. A propagação inclui

informação relativa ao ciclo e as equações apresentadas anteriormente;

4. Propagação em sentido directo das modificações em cada ciclo para o exterior e para

os ciclos dependentes. Para cada ciclo dependente é exigido o regresso ao ponto 3.

A sequência de etapas 1 e 2 é realizada sucessivamente até que haja convergência. Como se

pode ver nas etapas 3 e 4 não é realizada propagação em sentido inverso para fora nem para

dentro de ciclos. Realçamos mais uma vez que, para todos os algoritmos, os valores

12 O DFG global utilizado é sempre acíclico (regiões cíclicas são representadas pela hierarquia no HPDG), como foi explicado no capítulo 3.

128 CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS

determinados para cada variável (nó identificador de uma variável no DFG) só são

considerados se forem menores que o número de bits inferido pela análise de aferição de

subtipos.

Todas as análises apresentadas são conservadoras, no sentido em que para preservarem a

funcionalidade optam, por defeito ou sempre que haja lacunas de informação, pelos limites

máximos (declarados pelo programador). A própria análise não é sensível ao comportamento

do corpo do ciclo, obtendo-se por isso sobredimensionamentos quando em presença de

instruções de um ciclo que não são executadas em todas as iterações como é o caso da

instrução 5 do seguinte pedaço de código:

1. Int a = 0; 2. For(int I = 0; I < 10; i++) 3. a++; 4. If(I == 2) 5. a = a << 2; 6.

A análise proposta anteriormente obtém, para a variável A, 25 bits - próximo do valor exacto

21, considerando que a instrução 5 é executada em todas as iterações do ciclo. Contudo, o

número de bits necessário para armazenar o valor da variável A é 12 (devido ao facto da

instrução 5 ser executada apenas na terceira iteração do ciclo).

A análise descrita produz também resultados válidos para exemplos do tipo seguinte:

1. Int a = 0; 2. For(int I = 0; I < 10; i++) 5. If(I == 2) 6. a = a << 2; 7. else 8. a++; 9.

Neste caso o número de bits final para armazenar a variável é obtido pelo deslocamento de

dois bits.

O desenrolamento de um ciclo pode provocar o uso de um número de bits maior do que seria

suficiente devido ao cariz pessimista da determinação do número de bits em algumas

operações. Se considerarmos, por exemplo, uma expressão A = A+1 dentro de um ciclo que

itera 10 vezes e supondo que A chega ao ciclo com comprimento de 16 bits obtém-se, pela

aplicação da equação (5.1), 20 bits para armazenar o valor da variável. Se, por outro lado, o

ciclo for desenrolado e mantida a cadeia de somas com a aplicação da regra para os

CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS 129

somadores apresentada anteriormente obtêm-se 26 bits para armazenar a variável. O número

exacto de bits necessário para a variável A é 17. Como se pode ver, utilizando as análises

propostas, o desenrolamento do ciclo, sem optimizações, traduziu-se num número de bits

para A mais pessimista do que o determinado sem desenrolamento.

Análises baseadas nos intervalos de valores que cada variável pode ter, nas quais se considera

a abordagem recente em [Stephen00], forneceriam os 17 bits. Como trabalho futuro, as

análises propostas nesta tese deverão ser combinadas com análises baseadas nos intervalos de

valores para que o hardware específico obtido seja ainda mais eficiente.

5.7 Resultados

Foram utilizados vários exemplos para avaliar o impacto das técnicas descritas neste capítulo.

A descrição de cada um dos exemplos encontra-se no apêndice D. Para cada exemplo, são

apresentados os resultados obtidos pela utilização de síntese lógica (SL) a partir da descrição

em VHDL com o uso da ferramenta “Design Compiler” [Synopsys95] da Synopsys, em

modo “medium effort” e com directiva para obtenção de área mínima. Na maioria dos casos

foi feito o desagrupamento da estrutura após a primeira optimização e realizada uma nova

optimização sobre a estrutura planar. Os resultados são baseados em estimativas obtidas pelo

NENYA ou pela ferramenta de síntese lógica e reportam-se unicamente à estrutura dos

circuitos em portas lógicas (sem custos de encaminhamentos). O uso de síntese lógica,

possível neste subconjunto de exemplos, serve para ilustrar a distância das análises propostas

a resultados próximos do óptimo.

O primeiro subconjunto de exemplos representa algoritmos simples com manuseamento de

bits intenso mas sem estruturas de controlo do tipo if-then-else. O exemplo A (REVERSE) é

utilizado para ilustrar as capacidades da propagação de constantes ao nível do bit. Ao

desenrolar-se o ciclo obtém-se um DFG com um número significativo de operações, algumas

das quais podem ser directamente implementadas por interligações (deslocamentos por

valores constantes). Com a propagação referida, o circuito final obtido tem área zero e atraso

originado unicamente pelas interligações. Este resultado é obtido sem que haja optimizações

“booleanas” complexas com a criação da representação do circuito ao nível lógico. Na Tabela

5.5 são apresentados os resultados obtidos utilizando o compilador NENYA aquando da

aplicação das optimizações descritas ao exemplo A. Os resultados apresentados na 4ª coluna

da tabela mostram a capacidade dos optimizadores integrados no compilador (aferição do

130 CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS

número de bits e da propagação dos padrões de constantes ao nível do bit) na geração de um

circuito unicamente constituído por interligações. Este resultado foi também alcançado pela

ferramenta de síntese lógica supracitada. A ferramenta de síntese arquitectural CADDY

[CaddyII] originou uma complicada estrutura de multiplexadores e unidades lógicas.

Todos os tempos de compilação apresentados na Tabela 5.5 referem-se aos tempos de

execução das ferramentas desde o código fonte até à geração dos ficheiros que descrevem em

VHDL a estrutura do circuito.

Os resultados ao nível de área ocupada e atraso global são ainda mais desfasados quando

também se consideram os atrasos das interligações, após se ter feito a colocação e o

encaminhamento no FPGA utilizado [Xilinx97].

Tabela 5 .5 . Resultados que i lustram o uso das opt imizações descr i tas

com o exemplo A .

NENYA Optimização s/ Optimizações ANB13 ANB+PBC14

SL CADDY

Área (células) 2.016 527 0 0 - Atraso (ns) 165 160 0 0 - Tempo de compilação 4,9s 5,2s 5,4s 39s >10m

Como se pode ver pelo exemplo apresentado, as técnicas anteriormente descritas revelam-se

fundamentais para a compilação de descrições software que utilizam intensivamente

manipulações de bits, como são os casos das aplicações de codificação/descodificação e

criptografia.

A Tabela 5.6 mostra os resultados obtidos com o uso das optimizações para os restantes

exemplos. A utilização de THR permitiu reduzir o número de somadores em cadeia nos

exemplos B (COUNT) e C (HAMMDIST), diminuindo por isso o atraso do circuito. No

entanto, o uso desta técnica não potenciou optimizações na aferição do número de bits e

consequente redução da área necessária, devido ao facto dos operandos não terem

declarações no programa com menor número de bits do que o resultado. Os resultados

apresentados na Tabela 5.6 para os exemplos B e C ilustram melhorias significativas do

NENYA em comparação com a síntese lógica. Parte destas melhorias são devidas ao uso de

13 ANB - Aferição do número de bits suficiente. 14 PBC - propagação de padrões de constantes ao nível do bit.

CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS 131

THR e aumentam com o aumento do número de adições em cadeia (ver Tabela 5.6, de B8

para B32 e de C8 para C32).

Os resultados apresentados na Tabela 5.6 para o exemplo D (EVENONES) ilustram uma

melhoria aparente do NENYA em relação ao uso de síntese lógica apenas devida aos modelos

temporais da síntese lógica serem mais correctos pois consideram os fan-outs das portas

lógicas. De facto, a estrutura obtida por ambas as abordagens tem os mesmos níveis de lógica

no caminho crítico.

Tabela 5 .6 . Resul tados obt idos com os exemplos B, C e D para

opt imizações di ferentes .

Tipo de compilação SL NENYA

Melhoria relativa (%) Optimizações

1 2 3 4 THR - - 4 - 4

Exemplo

ANB+PBC - - - 4 4

2-1 4-3 4-2 4-SL

B B8 Área (células) 27 928 928 84 33 0 61 96 -22 Atraso (ns) 23.2 753 326 97 21 57 78 94 16

B16 Área (células) 105 1.952 1.952 360 78 0 78 96 26 Atraso (ns) 70.3 1.600 432 409 35 73 91 92 52

B32 Área (células) 282 4.000 4.000 1.488 171 0 89 96 39 Atraso (ns) 135 3.320 540 1.671 53 84 97 90 61

C C8 Área (células) 40 960 960 85 41 0 52 96 -3 Atraso (ns) 35 759 331 102 26 56 75 92 26

C16 Área (células) 109 1.232 1.232 376 94 0 75 92 14 Atraso (ns) 69 819 226 414 40 72 90 82 42

C32 Área (células) 268 4.032 4.032 1.582 172 0 89 96 36 Atraso (ns) 133 3.326 545 1.676 58 84 97 89 56

D D8 Área (células) 7 480 15 7 7 97 0 53 0 Atraso (ns) 10.7 29 29 25 11 0 56 62 35

D16 Área (células) 15 1.024 32 15 15 97 0 53 0 Atraso (ns) 16.7 36 36 33 15 0 55 58 35

D32 Área (células) 31 2.144 67 31 31 97 0 54 0 Atraso (ns) 20.8 124 124 113 19 0 83 85 32

Quando se utilizam todas as optimizações descritas neste capítulo, o NENYA produz em

alguns casos resultados melhores do que a ferramenta de síntese lógica devido à incapacidade

desta prever, ao nível da estrutura do circuito em portas, que o uso de THR pode diminuir o

tamanho dos somadores. Contudo, nos exemplos anteriores as melhorias mais significativas

são exclusivas do uso das técnicas de aferição do número de bits e de propagação de

constantes ao nível do bit.

132 CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS

As optimizações foram também testadas em alguns exemplos com uma componente de

controlo importante. Na Tabela 5.7 são apresentados os resultados obtidos utilizando as

técnicas abordadas e a comparação com os resultados obtidos com a ferramenta de síntese

lógica. Para estes exemplos o NENYA ficou mais distante de resultados quasi-óptimos. Este

facto deve-se sobretudo à capacidade das optimizações sobre estruturas ao nível da porta

lógica poderem realizar transformações “booleanas” que optimizam as construções de

controlo. Na presença de estruturas de controlo do tipo if-then-else o NENYA insere pontos

de selecção sob a forma de multiplexadores que acabam por necessitar de bastante área. Os

resultados menos eficientes do NENYA devem-se também ao facto deste não permitir

optimizações em profundidade. Para estes exemplos não existe potencial para a aplicação de

THR.

Tabela 5 .7 . Resultados que i lustram o uso das opt imizações descr i tas

com os exemplos E, F , G, H e I .

Tipo de compilação NENYA

Melhoria relativa (%) Optimizações SL

1 2 3 ANB - - 4 4

Exemplo

PBC - - 4

2-1 3-1 3-2 3-SL

E: USQRT Área (células) 1.358 6.944 3.922 3.712 44 47 5 -173 Atraso (ns) 977 3.313 2.493 2.493 25 25 0 -155

F: CRC-32 Área (células) 41 1.760 761 415 57 76 45 -912 Atraso (ns) 13,13 574 77 56 87 90 27 -327

G: HAMMING Área (células) 41 860 106 63 88 93 41 -54 Atraso (ns) 19,6 109 51 30 53 72 41 -53

H: SQRT Área (células) 154 1.760 409 253 77 86 38 -64 Atraso (ns) 186,6 1.239 361 307 71 75 15 -65

I: MULT Área (células) 3.259 23.471 20.495 20.401 13 13 0 -526 Atraso (ns) 540 3.843 3.781 3.776 2 2 0 -599

I1: MULT Área (células) 3.259 - - 4.002 - - - -23 (Uso de SSA) Atraso (ns) 540 - - 3.432 - - - -536

A Figura 5.10 e a Figura 5.11 ilustram respectivamente as melhorias de área e de atraso

obtidas pelo NENYA com todas as optimizações (NENYAOpt) e pela síntese lógica (SL)

relativamente aos resultados obtidos pelo NENYA sem aferição do número de bits suficiente

e propagação de constantes ao nível do bit. Nos exemplos com manipulação de bits

dominante as optimizações obtiveram melhorias na ordem dos 90%. Para o exemplo I as

técnicas enunciadas neste capítulo permitiram melhorias de apenas 13,1% e 1,7%

relativamente à área e ao atraso. Contudo, para este exemplo o potencial de melhoramento é

CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS 133

da ordem de 90% como se pode constatar pelos resultados obtidos pela utilização de síntese

lógica.

Nos exemplos F e I a maior parte da área do circuito obtido pelo NENYA é devida aos

multiplexadores utilizados nos pontos de selecção. A Figura 5.12 mostra a percentagem de

área ocupada pelos multiplexadores no exemplo I. Este facto mostra a deficiência da

determinação dos pontos de selecção a partir das cadeias de definição-uso quando existem

muitas definições a alcançarem um determinado uso oriundas de sequências de enunciados de

controlo. Ao último uso de uma variável chegam todas as definições possíveis dessa variável,

o que para o exemplo I se traduz na colocação de pontos de selecção com vários operandos

de entrada que requerem grandes unidades de selecção. A colocação de multiplexadores nos

pontos de selecção φ da representação SSA15 [Cytron91] permitiu reduzir o número de

multiplexadores e obter um circuito com área muito mais próxima da área do circuito obtido

por síntese lógica (ver I1 na Tabela 5.7).

0%

20%

40%

60%

80%

100%

A B8 B16 B32 C8 C16 C32 D8 D16 D32 E F G H I

Exemplo

NENYAOPt SL

Figura 5 .10 . Melhor ias , em termos de área, do NENYA com opt imizações

(NENYAOpt) e da s íntese lógica (SL) em re lação ao NENYA sem

opt imizações.

15 Do inglês: Single Static Assignment.

134 CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS

0%

20%

40%

60%

80%

100%

A B8 B16 B32 C8 C16 C32 D8 D16 D32 E F G H I

Exemplo

NENYAOpt SL

Figura 5 .11 . Melhor ias , em termos de at raso, do NENYA com

opt imizações (NENYAOpt) e da s íntese lógica (SL) em relação ao

NENYA sem opt imizações .

68%70%72%74%76%78%80%82%84%86%88%

s/Optimizações ANB ANB+PBC

Opções do NENYA

Per

cen

tag

em d

e Á

rea

de

MU

XE

S

Figura 5 .12 . Percentagem para o exemplo I da área do c i rcui to dedicada

aos mul t ip lexadores para compi lações com e sem as opt imizações.

Análises de fluxos de dados utilizando a representação SSA serão incorporadas

proximamente para se poder avaliar quantitativamente a determinação de pontos de selecção

por cada uma das análises.

Na Tabela 5.8 estão representados os tempos de compilação da descrição de alto-nível até à

obtenção da descrição em VHDL da estrutura de cada circuito. Como se pode constatar, os

tempos de computação do NENYA em relação aos do Design Compiler são bastante

inferiores. Os rácios dos tempos de computação entre as duas abordagens vão de 1,9 a 3.024.

Os tempos de computação obtidos pela execução do NENYA são dominados pelo

CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS 135

processamento do JIT16 e daí aparecerem na tabela muitos casos com tempos na ordem dos

9s.

Tabela 5 .8 . Tempos de computação da s íntese lógica e do GALADRIEL +

N E N Y A .

Tempo de Computação Exemplo LS GALADRIEL

+ NENYA

Aceleração

A: REVERSE 39s < 9s 4,3 B8: COUNT8 68s < 9s 7,6 B16: COUNT16 4m < 9s 26,7 B32: COUNT32 13m < 10s 78 C8: HAMMDIST8 3,2m < 9s 21,3 C16: HAMMDIST16 36m < 9s 240 C32: HAMMDIST32 2,37h < 9s 1.348 D8: EVENONES8 17s < 9s 1,9 D16: EVENONES16 31s < 9s 3,4 D32: EVENONES32 57s < 9s 6,3 E: SQRT 1,7m < 9s 11,3 F: USQRT 8,4h <10s 3.024 G: CRC-32 28,3s < 9s 3,1 H: HAMMING 39,7s < 9s 4,4 I: MULTUNROLLED 31,2m < 13s 144,1

5.8 Conclusões

Neste capítulo foram apresentadas as optimizações do grafo de fluxo de dados integradas no

compilador NENYA. Estas optimizações incluem: reassociação de operações, redução do

custo de multiplicações/divisões por constantes, inferências dos subtipos de dados primitivos,

aferição do número de bits e propagação de constantes ao nível do bit. Estas optimizações,

feitas nas primeiras fases da compilação para reconfigware, são potencializadas pela

utilização de macrocélulas parametrizáveis para cada operador existente na descrição alto-

nível

Os resultados da aplicação das optimizações revelaram grande potencial e melhorias

significativas sobre a compilação para hardware específico sem a utilização das mesmas. Os

resultados obtidos pelo NENYA, em exemplos possíveis de aplicabilidade de síntese lógica e

em que não existem (ou não são dominantes) fluxos de controlo na descrição, revelaram-se

16 Do inglês: Just In Time.

136 CAP. 5 OPTIMIZAÇÕES DO GRAFO DE FLUXOS DE DADOS

próximos e em alguns casos melhores (quando existe potencial para realizar THR) do que os

obtidos com uma ferramenta comercial de síntese lógica17 à correspondente descrição em

VHDL. Embora o intuito desta comparação nunca ter tido o objectivo de mostrar

melhoramentos, mas sim atestar das distâncias entre os resultados obtidos pelos métodos

apresentados e os resultados próximos do óptimo fornecidos pela síntese lógica, os resultados

revelaram que a utilização das optimizações sugeridas sobre um DFG podem em alguns casos

se sobrepor aos utilizados por algumas ferramentas comerciais de síntese lógica.

As optimizações de reassociação de operações (THR) e de redução do custo de operações

foram consideradas simplistamente para possibilitar a integração no NENYA e com o

objectivo principal de obtenção do efeito destas em alguns exemplos. Contudo, trabalhos

futuros devem debruçar-se na procura de formas mais poderosas de resolução dos dois

problemas sem hipotecarem a razoabilidade dos tempos de compilação. Ao nível das

optimizações algébricas, alguns autores têm investigado formas de optimização, sendo uma

delas baseada em algoritmos genéticos [Landwehr97] e por isso demasiado complexa. É por

isso necessário investigar heurísticas que permitam tempos de computação reduzidos.

As análises propostas e implementadas de aferição do número de bits suficiente para

representação dos operandos são puramente estáticas e utilizam equações que permitem

determinar os bits suficientes em operações internas a ciclos. As análises iteram de modo a

haver convergência e não utilizam o processo de iteração até ao ponto fixo na presença de

ciclos. As análises propostas podem ser combinadas com algumas das propostas

recentemente em [Stephen00] para se obterem melhores resultados. A aferição dos padrões

de constantes ao nível do bit permite em muitos exemplos com manuseamento de bits

optimizações favoráveis e, pelo que nos foi possível averiguar, nunca tinha sido proposta.

Todas as técnicas apresentadas podem ser incluídas em qualquer compilador para hardware

específico e não somente para hardware reconfigurável.

17 O tipo de compilação sugerido tem vantagens intrínsecas em relação à utilização de síntese lógica, como sejam a capacidade de compilar descrições com comportamentos cíclicos sem resolução estática, compilar para arquitecturas com dispositivos RAM acoplados ao FPGA, permitir a compilação de exemplos de grandes dimensões sem os enormes esforços computacionais (tempo de execução e memória de sistema) da síntese lógica, entre outras.

137

6. Partição Temporal

“The biggest difference between time and space is that you can’t reuse

time.”

Merrick Furst

Neste capítulo é descrita a abordagem utilizada na partição temporal de descrições de alto-

nível para que a implementação final possa ser executada por multiplexagem do FPGA. É

apresentado um novo algoritmo baseado em heurísticas, que assenta na reformulação do

algoritmo estático de escalonamento baseado em lista [Gajski92], especialmente adaptado

para lidar com a partição temporal. O algoritmo selecciona os nós da representação

intermédia de grafos para serem mapeados numa fracção temporal com base em modelos de

custo calculados estaticamente. De forma a aliviar o tempo de computação não é considerada

a reavaliação dos custos durante a execução do algoritmo. O custo para cada modelo integra

os efeitos de comunicação, o caminho crítico e a possibilidade do caminho crítico esconder

os atrasos dos nós paralelos.

Os resultados experimentais atestam as virtudes do algoritmo face a diversas abordagens e

mostram que o algoritmo é capaz de encontrar bons resultados, quando comparado com

outros métodos, em tempos de computação razoáveis. Os resultados também mostram que o

algoritmo é robusto, efectivo e eficiente.

Para se ter noção da distância dos resultados obtidos por métodos construtivos a resultados

próximos de valores óptimos foi implementada uma versão da partição temporal com base no

algoritmo simulated annealing. Pelo que julgamos saber esta implementação foi uma das

primeiras a usar o simulated annealing para partição temporal.

138 CAP. 6 PARTIÇÃO TEMPORAL

No capítulo começam por ser explicadas as razões para a partição temporal e descritas

algumas das abordagens mais interessantes. É apresentada a formulação do problema que se

pretende solucionar, e são apresentadas algumas das formas de execução de fracções

temporais pela partilha de uma unidade de processamento reconfigurável. São descritos os

esquemas de partição temporal baseados nos escalonadores ASAP e ALAP. De seguida, são

dissecados o algoritmo desenvolvido e uma versão do simulated annealing para lidar com a

partição temporal. Finalmente são apresentados resultados e conclusões.

6.1 Incentivo para a Partição Temporal

A disponibilidade de arquitecturas de unidades de processamento reconfiguráveis, como é o

caso dos novos FPGAs, com menores tempos de reconfiguração, tornou possível a

concretização do conceito de “hardware virtual” [Long93]: os recursos de hardware são

considerados ilimitados e a partição temporal é usada para resolver a implementação de

circuitos cujo tamanho excede a área disponível. As fracções obtidas são executadas pela

partilha temporal do dispositivo de um modo que cada fracção cabe na área disponível e a

funcionalidade global é preservada. Contudo, a investigação e o desenvolvimento de

algoritmos de partição temporal, capazes de explorar este conceito encontram-se ainda numa

fase embrionária. O problema da partição temporal requer compromissos entre paralelismo,

custos de comunicação, atraso e tempo de reconfiguração. Os nós do grafo que representa o

circuito ou um programa têm de ser escalonados em fracções temporais que são executadas

no dispositivo uma de cada vez. A partição temporal tem de preservar as dependências entre

nós (que são inerentemente dependências temporais) de forma a que um nó A dependente de

um nó B não possa ser mapeado numa fracção executada antes da fracção que contém o nó B.

Como foi descrito em [GajjalaPu98b], o problema tem similaridades com o problema de

escalonamento da síntese de alto-nível [Micheli94]. As similitudes dos dois problemas

permitem o uso dos esquemas de escalonamento para partição temporal. Um factor

importante, contudo, que deve ser considerado é o custo de intercomunicação (comunicação

entre fracções originada pelo corte de ligações no grafo original que requer o transporte de

dados) que pode ser muito dispendioso e é dependente do fraccionamento considerado.

O conceito de partilha temporal de um dispositivo lógico programável pode vir a ser uma

solução eficiente ao permitir a substituição de placas inteiras de circuitos integrados ou a

poupança de área de silício. Uma das aplicações do conceito é a mutação entre

CAP. 6 PARTIÇÃO TEMPORAL 139

funcionalidades que têm exclusividade mútua no domínio do tempo, tal como a comutação

entre esquemas de codificação/descodificação nos sistemas de comunicação, vídeo ou áudio.

Este tipo de aplicação tem o nome de mutação de contexto em que cada contexto pode

representar uma funcionalidade atómica e independente. Para cada funcionalidade podem,

contudo, existir várias configurações obtidas por partição temporal.

Foi já demonstrado que FPGAs de granulosidade fina, como é o caso da família de FPGAs

Xilinx [Xilinx97], podem ser aceleradores eficientes de desempenho quando comparado com

implementações puramente software. Em particular, o FPGA XC6200 tem características

específicas, como são os casos de tempos de reconfiguração menores do que os FPGAs

tradicionais, que o tornaram predilecto para reconfiguração dinâmica e parcial [Hudson98].

Contudo, este FPGA não incorpora mecanismos para implementação eficiente do

fraccionamento temporal e o tempo de reconfiguração de todo o dispositivo é na ordem das

centenas de microsegundos (XC6216). Esforços de investigação pela indústria têm sido

considerados para melhorar as capacidades dos FPGAs em lidarem com o conceito de

“hardware virtual”. Alguns apresentam unidades de processamento reconfiguráveis que

armazenam várias configurações no dispositivo permitindo a mutação de contextos em

poucos nanosegundos [Scalera98][Trimberger97][Fujii99]. O armazenamento das várias

configurações pode ser realizado durante o arranque do sistema, ou em paralelo com a

execução da configuração activa1. Um dos novos dispositivos é o DRLE2 [Fujii99] da NEC,

que apenas necessita de 5 nanosegundos para comutar de configurações e suporta até 8

configurações no dispositivo. Os autores afirmam ter planos para realizarem dispositivos

deste tipo com capacidade de armazenamento de 100 configurações. A tendência para se

terem configurações passivas no dispositivo em detrimento de mais células de lógica é

explicada pelo facto de que a área da SRAM para armazenar os bits de configuração para

cada célula é mais pequena do que a própria célula.

Mecanismos de comunicação eficientes entre fracções temporais têm sido activamente

pesquisados. A maioria dos esforços considera registos especiais do FPGA que mantêm o

estado entre contextos sempre que necessário (um exemplo são os micro-registos

[Trimberger97]).

1 A configuração que define o circuito actualmente em execução ou disponível para execução. 2 Do inglês: Dynamically Reconfigurable Logic Engine.

140 CAP. 6 PARTIÇÃO TEMPORAL

A partição temporal considerada no âmbito desta tese refere-se à partição no domínio do

tempo, de um algoritmo fonte, durante as fases da geração de uma arquitectura específica que

implemente o referido algoritmo. Os algoritmos têm, contudo, versatilidade suficiente para

também serem aplicados à prototipagem rápida. O trabalho desenvolvido permitiu a

realização de algoritmos que automatizam o processo de partição temporal, mantendo tempos

de computação competitivos. Foi dado particular ênfase à consideração dos custos de

comunicação entre fracções temporais.

6.2 Panorâmica Relativamente à Partição Temporal

A investigação de algoritmos para automatizar o processo de partição temporal de um grafo,

representativo de uma descrição comportamental, cuja implementação será executada pela

partilha temporal de uma unidade de processamento reconfigurável foi, quanto sabemos,

primeiramente formulada em [Vasilko96][Long93].

Em [Chang97] os autores usam um escalonador em lista para minimizarem o número de fios

entre fracções temporais (e consequentemente o número de buffers necessários). O algoritmo

computa ao nível da estrutura (4-LUTs3) de circuitos combinatórios, usa o caminho crítico

como função de prioridade, e o fanout de cada nó para desempate. A abordagem é apropriada

para unidades de processamento reconfiguráveis com registos que mantêm o estado entre

fracções temporais. Estes tipos de arquitecturas têm custos de comunicação pequenos, e a

optimização global pode ser resolvida usando apenas o caminho crítico como primeira chave

de prioridades. Os autores desenvolveram uma extensão do algoritmo de escalonamento

directo baseado em forças que também considera circuitos sequenciais [Chang98].

Em [Trimberger98] é usada uma variante do escalonador estático baseado em lista seguida de

um optimizador para partição temporal de circuitos. O algoritmo usa três regras para

seleccionar de entre os nós prontos para mapeamento e é vocacionado para o FPGA “Time-

Multiplexed” [Trimberger97].

Em [Liu98][Liu99] é apresentado um método baseado no fluxo na rede para multi-partição.

Em [Liu98] o algoritmo tem como alvo o FPGA “Time-Multiplexed” e os resultados superam

3 LUTs de 4 entradas.

CAP. 6 PARTIÇÃO TEMPORAL 141

o algoritmo baseado em lista usado em [Trimberger98], em termos de custos de comunicação

(número de fios entre fracções temporais). O algoritmo usa o cômputo do máximo-fluxo

mínimo-corte iterativamente para encontrar k fracções. Os resultados em [Liu99] mostram

melhorias sobre a extensão do algoritmo FDS4 [Chang98] no que respeita aos custos de

comunicação. Resultados comparativos do atraso global não são apresentados nem

examinados e, por isso, é por enquanto desconhecida a eficiência desta abordagem em

optimizar globalmente.

As abordagens apresentadas anteriormente são todas baseadas na estrutura do circuito final

mapeado no FPGA alvo. São, por isso, apropriadas para a prototipagem com o intuito de

depuração/emulação, mas não podem explorar o fraccionamento ao nível comportamental.

Este facto é fundamental quando se considera a integração da partição temporal na

compilação de descrições alto-nível. Mais ainda, estas abordagens sofrem do número pesado

de laços e nós (fios e de portas lógicas) que têm de ser manipulados. Em níveis de

representação mais elevados, os nós representam operações que encapsulam estruturas

complicadas e apenas os grupos de fios que transportam operandos são visíveis a esse nível.

Contudo, o uso de um nível de representação mais elevado usa a atomicidade do nó e, por

isso, não permite granulosidades mais finas.

Alguns autores, tais como [Vasilko96][Ouaiss98a], consideraram a partição temporal a níveis

altos de abstracção tendo em mente a integração da síntese. Em [Vasilko96] é apresentada

uma heurística baseada no escalonador estático baseado em lista, estendido para considerar

restrições dinâmicas de área. A abordagem não considera os custos de comunicação.

Em [Ouaiss98a][Kaul98] a partição temporal é formalizada por um modelo de programação

não linear 0-1. Contudo, mesmo para grafos pequenos, a formulação não é sempre resolvida

em tempos de execução razoáveis. Estes problemas são NP completos e métodos baseados

em heurísticas têm de ser desenvolvidos para permitir a partição temporal automática de

exemplos complexos.

Em [GajjalaPu98b] [GajjalaPu99] é apresentado um algoritmo baseado nos níveis atribuídos

pelo escalonamento ASAP sem restrições de recursos. É também apresentado um algoritmo

4 Do inglês: Force Direct Scheduling. Ver, por exemplo, [Micheli94].

142 CAP. 6 PARTIÇÃO TEMPORAL

com capacidade de agrupamento de nós. Estes algoritmos são de baixa complexidade e

tornam factível a partição temporal automática.

Para que a partição temporal seja realizada de modo a minimizar uma determinada função de

custo, que pode incluir o caminho crítico global e os custos de comunicação de dados entre

fracções temporais, foi por nós estudado e reformulado o algoritmo de escalonamento

estático baseado em lista que é apresentado neste capítulo.

6.3 Formulação do Problema

Considere-se um programa fonte descrito por um grafo, G = (V, E), ordenado, direccionado e

acíclico com |V| nós, ν1, ν2,…, ν|V| e |E| laços, e em que cada nó νi representa um

comportamento. Cada laço ei,j ∈ E representa uma dependência temporal5 entre os nós νi e νj.

Uma dependência pode ser apenas de precedência ou de transporte (de dados entre dois nós).

O nível hierárquico de topo do HPDG, descrito no capítulo 3, é um grafo deste tipo. O HPDG

é uma representação hierárquica em que os níveis da hierarquia traduzem a presença de ciclos

no programa fonte. O nível mais baixo da representação é ilustrado sob a forma de um DFG,

no qual os nós representam operações. Para simplificar o problema só se consideram nós do

HPDG com atrasos conhecidos estaticamente. Cada nó do HPDG sem hierarquia representa

uma região do DFG.

Assume-se que os valores do atraso e da área (CLBs, células, etc.) para cada nó foram

determinados previamente. O tempo de comunicação associado a cada laço ei,j representativo

de uma dependência de transporte é calculado por:

×

=

)Part()Part( if 0

)Part()Part( if bw

d

)(e

ij

ijji,

ji,

νν

ννξω (6 .1 )

Em que bw representa a largura de banda máxima para cada leitura/escrita atómica, e di,j é o

número de bytes da comunicação do laço ei,j. A multiplicação por ξ modela a comunicação

5 De tal forma que νi → νj.

CAP. 6 PARTIÇÃO TEMPORAL 143

necessária para guardar um operando e torná-lo disponível na fracção seguinte. Por exemplo,

para operandos guardados numa memória ξ deve ser igual a dois pois, para cada inter-

comunicação, o operando tem de ser guardado pela fracção onde foi definido e lido pela

fracção que o usa (assumindo tempos de escrita e de leitura iguais). Uma dependência de

precedência (sem transporte) tem custo zero (valor de di,j igual a zero).

O objectivo da partição temporal é a criação de um conjunto de fracções temporais de modo a

que um determinado custo6 seja minimizado e cada fracção caiba na área de reconfigware

disponível. Cada fracção, Πi, é um subconjunto não vazio de V. Poderemos dizer que um

grafo G partido temporalmente em k subconjuntos é correcto se e só se:

• O conjunto de fracções temporais ℘ = Π1 ∪ Π2 ∪ … ∪ Πk ≡ V;

• ∀ Πi ∈ ℘, Area(Πi) ≤ MaxArea; Cada fracção temporal cabe nos recursos

disponibilizados do FPGA.

• ∀ ei,j ∈ Ε, (℘(νi) → ℘(νj)) ∨ (℘(νi) ≡℘(νj)); → indica a ordem de execução. Todas

as dependências de dados são obedecidas (condição necessária para obter a mesma

funcionalidade).

Um conjunto correcto de fracções temporais garante que a descrição mantém a

funcionalidade original. Na partição temporal podem-se ter em conta diversos objectivos,

como sejam a minimização do atraso global ou do número de laços entre fracções. O custo

que reflecte o atraso global da execução de um grafo numa unidade de processamento

reconfigurável por multiplexagem no tempo pode ser calculado pela equação:

( ) ( ) ( )[ ] ( )[ ]∑=

Π+Π+Π×=ΩNumPart

iiAtrasoiiciclosA MaxOutInRWModelG

1

, τ (6 .2 )

Em que τciclos representa o número de ciclos de relógio para ler/escrever um operando de

tamanho menor ou igual à largura de banda da interface de comunicação. A função

6 Neste trabalho o custo a minimizar é o tempo de computação total do reconfigware sem contar com os custos de reconfiguração.

144 CAP. 6 PARTIÇÃO TEMPORAL

MaxAtraso(Πi) calcula o atraso do caminho crítico7 da fracção Πi e as funções In(Πi), Out(Πi)

correspondem à soma dos pesos dos laços de entrada/saída (ω(ei,j)) de um nó sem considerar

as entradas e as saídas primárias.

6.4 Esquemas de Suporte à Execução de Fracções Temporais

É importante, sob o ponto de vista de compilação para computação reconfigurável, considerar

organizações diferentes dos dispositivos que constituem o sistema. Cada organização pode

impor custos diferentes de comunicação entre fracções temporais devido a esquemas

diferentes de comunicação.

Pelo menos três mecanismos de comunicação entre fracções temporais podem ser

considerados:

• O uso de registos e de uma tarefa em execução no microprocessador para controlar a

escrita/leitura de dados entre fracções. Este esquema é apropriado para placas de

unidades de processamento reconfiguráveis com um microprocessador ou

microcontrolador que pode gerir as reconfigurações e comunicações, ou para placas

sem qualquer esquema de armazenamento (buffer) que lhes permitam manter dados

entre fracções. Com o advento de dispositivos que integram um microprocessador e

uma unidade de processamento reconfigurável no mesmo circuito integrado este pode

ser um esquema eficiente devido aos custos reduzidos de comunicação entre os dois

engenhos;

• O uso de um conjunto de registos na unidade de processamento reconfigurável quando

o dispositivo pode ser reconfigurado parcialmente. A área de registos pode ser

configurada inicialmente e partilhada temporalmente pelas fracções. Este esquema é

apropriado para FPGAs com recursos especiais (por exemplo, micro-registos) para

partilha temporal;

• O uso de memórias acopladas ao FPGA para guardar os dados interfracções. O

hardware usa circuitos de interface a estas memórias. Este esquema é apropriado para

7 Para simplificar assumem-se tempos de execução deterministas.

CAP. 6 PARTIÇÃO TEMPORAL 145

unidades de processamento reconfiguráveis sem microprocessadores de hospedagem

ou quando as comunicações entre as dois engenhos são demasiado elevadas. É também

útil quando é necessário transferir grandes quantidades de dados (por exemplo, arrays).

Exemplo 6 -1 . Corpo do c ic lo do exemplo HAL.

A Figura 6.1 apresenta o DFG do corpo do ciclo do exemplo HAL

[Paulin86]. No canto direito são apresentados os custos de implementação

dos operadores considerados pelo exemplo. A Figura 6.2 mostra o grafo

repartido por duas fracções temporais. Este fraccionamento temporal

necessita que apenas um operando seja transferido entre fracções. No início

o FPGA é reconfigurado com o reconfigware da primeira fracção e os

operandos de entrada (x, dx, u e y) são disponibilizados. No fim da

execução desta fracção, são guardados o operando intermédio (aux) e os

primeiros resultados (y_1 e x_1). De seguida o FPGA é reconfigurado com

o reconfigware da segunda fracção e disponibilizados os operandos (aux,

dx, y e u). No fim da execução desta fracção, é guardado o outro resultado

(u_1). O buffer para armazenar o operando intermédio pode ser uma

posição em memória, um registo local, ou registos do próprio

microprocessador.g

Operador (16 bits)

Área (células)

Atraso (ciclos de relógio)

× 1024 20

+, - 48 6

<< 1 << 1

+

×

u

×

dx

-

u

-

×

dx

+

u_1

x y

+

dx x

x_1

×

dx u

y_1

+

y

Gexec = 58 ciclos Área(G) = 4.384 células

Figura 6 .1 . DFG para o corpo do c ic lo do exemplo HAL e o custo de

cada operador .

146 CAP. 6 PARTIÇÃO TEMPORAL

<< 1

<< 1

+

×

u

×

dx

-

u

-

×

dx +

u_1

x

y

dx x

x_1

×

dx u

y_1

+

y

x

dx

y

u

x_1

y_1 aux

aux

dx

u

x_1

y_1

aux

dx

u_1

tempo

+

x

dx

y

u

aux

aux

x_1

y_1

u_1

reconfiguração

execução

reconfiguração

execução

Figura 6 .2 . Execução do corpo do c ic lo do exemplo HAL com part i lha

tempora l do FPGA.

6.5 Métodos Baseados nos Esquemas ASAP/ALAP

Os métodos de partição temporal mais simples baseiam-se nos níveis de ASAP8

[GajjalaPu99]. Nestes métodos é atribuído a cada nó do DFG o número máximo de nós que é

necessário percorrer do início do grafo até ao nó inclusive. O algoritmo começa pelos nós do

primeiro nível obtido pelo ASAP e vai mapeando um-a-um na fracção temporal enquanto a

área não for excedida. Quando aparece um nó cuja área excede a área disponível é criada uma

nova fracção temporal. Depois de todos os nós de um dado nível ASAP serem mapeados, o

algoritmo considera os nós do nível imediatamente a seguir. O algoritmo continua até que

todos os nós do DFG tenham sido mapeados. A selecção dos nós de um dado nível de ASAP

é arbitrária.

8 O nível de ASAP de um determinado nó do grafo indica o número de nós anteriores ao nó considerado que se encontram no caminho do início do grafo até esse nó.

CAP. 6 PARTIÇÃO TEMPORAL 147

Um algoritmo semelhante orientado pelos níveis de ALAP pode também ser considerado. No

Exemplo 6-2 o algoritmo de partição temporal baseado nos níveis ALAP produz melhores

resultados do que o baseado nos níveis ASAP. Este facto deve-se à proximidade local de

dependências nos níveis ALAP.

Exemplo 6 -2 . Part ição temporal or ientada pelos níveis de ASAP ou de

A L A P .

Suponha-se que todos os laços têm os mesmos custos de comunicação, cada

nó tem uma unidade de área e a área máxima do FPGA é de 4 unidades. O

fraccionamento temporal resultante da aplicação de uma versão do

algoritmo apresentado em [GajjalaPu99] com orientação ASAP ou ALAP é

apresentado nas Figura 6.3.a e Figura 6.3.b respectivamente. Para este

exemplo a orientação pelos níveis ALAP produz menos laços de

comunicação entre as duas fracções temporais.g

2

3

4

5 6 7 1

L1 L2 L3 L4

2 3

4

5 6 7 1

L1 L2 L3 L4

a ) b)

Figura 6 .3 . Apl icação de dois esquemas de part ição temporal : a) pelos

níveis de ASAP; b) pelos níveis de ALAP.

Foram implementados dois esquemas. O algoritmo 1 estende o algoritmo apresentado em

[GajjalaPu99]. O algoritmo permite seleccionar um nó da lista de nós com o mesmo nível de

ASAP ou ALAP por uma função local de prioridades. Esta função é aplicada a todos os nós

do mesmo nível e permite orientar a selecção pela ordem crescente de mobilidades. Assim, o

caminho crítico do DFG tem maior prioridade no mapeamento dos nós na fracção temporal

em preenchimento (corrente).

148 CAP. 6 PARTIÇÃO TEMPORAL

Este algoritmo considera uma nova fracção quando aparece um nó que não cabe na área

disponível sem, contudo, considerar os outros nós do nível em consideração.

O algoritmo 2 (ver Figura 6.4) tenta resolver este problema, ao considerar a procura recursiva

na lista de nós prontos para mapeamento na fracção temporal corrente, de nós que possam ser

alojados. O algoritmo considera que cada nó do grafo foi previamente rotulado com o nível

ASAP ou ALAP. No início o algoritmo, por cada nível, forma uma pilha com todos os nós

desse nível ordenados pelo valor da mobilidade9 (linhas 4 a 10 da Figura 6.4). De seguida vai

atribuindo os nós da pilha à fracção temporal em consideração até que esta atinja a área

máxima (linhas 11 a 19). Sempre que o mapeamento de um determinado nó ultrapasse a área

máxima disponível o algoritmo tenta mapear outro nó. Quando, para o nível em consideração,

não houver mais nós possíveis de serem mapeados na fracção temporal corrente é criada uma

nova fracção temporal (linha 21) e o algoritmo prossegue com o mapeamento. Quando

durante o mapeamento de nós a uma dada fracção, a pilha for esvaziada é criada uma nova

pilha considerando os nós do nível seguinte (linhas 23 e 24). O algoritmo termina quando

todos os nós tiverem sido mapeados em fracções temporais.

Este algoritmo pode também ser baseado nos níveis de ASAP ou ALAP e pode incluir a

função de custo do algoritmo 1.

Exemplo 6 -3 . Corpo do c ic lo do exemplo HAL.

Considere-se novamente o corpo do ciclo do exemplo HAL com operandos

de 16 bits. O circuito correspondente ao DFG inicial sem partilha de

operadores cabe apenas no FPGA XC6264. Quando se usa o FPGA

XC6216 o DFG tem que ser partido em dois. A Tabela 6.1 apresenta as

características do hardware implementado considerando cada um dos

FPGAs mencionados. A implementação de partilha temporal do FPGA usa

software para escalonar as reconfigurações e a escrita/leitura dos operandos.

A área máxima disponibilizada foi especificada como sendo de 60% (2.458

células no FPGA XC6216) da área total do FPGA (para garantir que a

colocação e encaminhamento seja realizável). Os resultados obtidos com o

9 Segmento temporal no qual um determinado nó pode ser escalonado sem alterar o atraso do caminho crítico. É obtido, para cada nó do DFG, pela diferença entre o valor de ALAP e o valor de ASAP do nó.

CAP. 6 PARTIÇÃO TEMPORAL 149

uso do algoritmo da Figura 6.4 orientado pelos níveis de ASAP são

apresentados nas linhas terceira e quarta da Tabela 6.1. O uso do algoritmo

mencionado permitiu que o fraccionamento resultante mantivesse (sem

considerar os custos da comunicação) o caminho crítico da implementação

sem partição (3ª coluna da tabela). Melhores desempenhos globais podem

ser obtidos com o uso de uma memória local para armazenar os operandos,

pois os custos de comunicação seriam inferiores. Os tempos de

reconfiguração apresentados (REC) não consideram as capacidades de

reconfiguração parcial do FPGA, facto que poderia diminuir o número de

pares de endereço/dados e consequentemente o tempo de reconfiguração. O

fraccionamento realizado adiciona 4 escritas e 2 leituras às leituras/escritas

da implementação sem fracções (última coluna da tabela).

1.TempPart(Schedul, SL, ScheduleNum, CurrentLevel, 2. IsALAP, NodesLevel, SameLevel) 3. If(CurrentLevel <= getMaxLevels()) 4. SameLevel = SortMobility(SL, CurrentLevel, 5. IsALAP); 6. If(NodesLevel == null) 7. NodesLevel = new Stack(); 8. Colocação dos nós do nível corrente 9. (SameLevel) em NodesLevel; 10. 11. Foreach Unscheduled Node of CurrentLevel 12. Sorted by mobility 13. NodesLevel.peek(Nodei); 14. If(Area(Nodei) + Schedul(ScheduleNum).getArea() < AMAX) 15. Schedul(ScheduleNum).Put(Nodei); 16. Sched(ScheduleNum).upDateArea(Area(Nodei)); 17. NodesLevel.Pop(Nodei) 18. 19. 20. If(NodesLevel.notEmpty()) 21. ScheduleNum++; 22. else 23. NodesLevel = null; 24. CurrentLevel++; 25. 26. TempPart(Schedul,SL,ScheduleNum,CurrentLevel, 27. IsALAP,NodesLevel,SameLevel); 28. 29.

Figura 6 .4 . Algori tmo para part ição temporal or ientado pela mobi l idade

de cada nó e com procura no mesmo n íve l de ASAP ou ALAP.

150 CAP. 6 PARTIÇÃO TEMPORAL

Tabela 6 .1 . Resultados para o corpo do exemplo HAL (♠♠ valores

est imados sem os tempos de comunicação) .

FPGA Área (células)

atraso (ns) ♠

Pares de endereço-

dados

X × Y células

REC (µs)

# escritas/ leituras

XC6264 4.420 564 7.263 108×72 220,1 4/3 2.328 255 3.873 64×64 117,4 4/4 XC6216 Fracção #1

Fracção #2 2.156 309 3.346 52×64 101,4 4/1

6.6 O Algoritmo de Partição Temporal Baseado num Escalonador

Estático em Lista

Nesta secção apresenta-se um algoritmo que ao tentar minimizar uma função global, que

integra os custos de comunicação e o atraso do caminho crítico, permite a obtenção de

fraccionamentos mais eficazes. O algoritmo de partição temporal é baseado num escalonador

estático em lista (ELS) [Cardoso99c] e está representado sumariamente na Figura 6.5. O

algoritmo começa por considerar os valores de ASAP e de ALAP de cada nó (linhas 2 e 3).

Um custo calculado pela equação (6.3) é adicionado a cada nó do grafo na fase inicial (linhas

7 a 9). Cada termo da equação tem um factor multiplicativo para dar mais peso aos custos de

comunicação (α), caminho crítico (β), ou ao compromisso entre os dois (η). O termo (6.4) dá

ênfase aos custos de comunicação. O termo (6.5) tenta preconizar o paralelismo existente,

dando mais peso aos nós com menor ASAP (criando a oportunidade de colocação de nós

disponíveis em paralelo com os nós do caminho crítico já mapeados). Este factor aumenta

quando se diminui o peso dos custos de comunicação. O terceiro termo (6.6) representa o

valor do ASAP de granularidade fina do nó.

Ao factor de escala (scale) foi atribuído o valor da divisão do número máximo de níveis do

ASAP pelo atraso do caminho crítico. Experimentalmente foi determinado que o peso η

expresso por β/(α+1) conduzia a bons resultados. Contudo, outro peso independente pode ser

usado para não limitar a exploração de soluções.

De seguida, o algoritmo insere na lista de nós disponíveis para mapeamento (List) na

primeira fracção temporal todos os nós do grafo cujo nó fonte seja unicamente o nó START

(linha 11). Esta lista é ordenada pela ordem descendente dos custos de cada nó (linha 12).

CAP. 6 PARTIÇÃO TEMPORAL 151

1. ELS(MaxArea, G(V, E),α, β, η) 2. Compute ASAP(G); 3. Compute ALAP(G); 4. 5. Int CurrentArea=0, SchedNum=0, NumNode=0, NumSchedNodes=0; 6. 7. For each vi ∈ V 8. Costsvi=ComputeCost(vi, α, β, η); 9. 10. 11. List = Create List of ready nodes to be scheduled; 12. Sort(list, Costs); 13. 14. BitSet SchedNodes = new BitSet(|V|); 15. 16. While(NumSchedNodes < |V|) 17. Node A = List.ElementAt(NumNode); 18. Boolean Fit = ((CurrentArea + Area(A)) <= MaxArea); 19. If(Fit) 20. List.removeElement(A(Area, Delay)); 21. ScheduleElement(A, CurrentArea, SchedNum, SchedNodes); 22. NumSchedNodes++; 23. If(List.Update(G, A, SchedNodes)) 24. Sort(List, Costs); 25. NumNode = 0; 26. else if(NumNode ≥ List.size()) && (List.size() != 0) 27. SchedNum++; NumNode = 0; CurrentArea = 0; 28. 29. else if(NumNode ≤≤ List.size()-2) 30. NumNode++; 31. else 32. SchedNum++; NumNode = 0; CurrentArea = 0; 33. 34. 35.

Figura 6 .5 . Algori tmo de part ição temporal baseado no algor i tmo

estát ico de escalonamento em l ista .

[ ] ( ) ( ) ( )idelayidelaycommicommi vvvvW ψβψηψα ×+×+×= / (6 .3 )

( ) ( ) ( )[ ]iiicomm vLevelALAPMaxLevelsvOutvIn +−−=ψ (6 .4 )

( )istartdelaycomm vASAPscale ×−=/ψ (6 .5 )

152 CAP. 6 PARTIÇÃO TEMPORAL

( )istartdelay vALAPscale×−=ψ (6 .6 )

Na linha 14 é criado um vector de bits com tamanho igual ao número de nós do grafo, que

indicará os nós que já tiverem sido mapeados, e que na criação terá todos os bits a zero

indicando que nenhum foi ainda mapeado.

As linhas 16 a 34 representam o núcleo do algoritmo que é executado até que todos os nós

tenham sido mapeados numa fracção temporal (linha 16). Da lista é indexado um nó (linha

17), de seguida é determinado se esse mesmo nó cabe na fracção temporal corrente (linha

18), e se couber é executado o ramo condicional correspondente (linhas 20 à 28).

Sempre que um nó é mapeado numa fracção (linhas 20 a 22) o algoritmo determina se o

mapeamento desse nó disponibiliza, do conjunto dos seus sucessores, outros nós (linha 23).

Se tal acontecer, os nós da lista de nós disponíveis para serem mapeados são ordenados pela

ordem descendente dos custos (linha 24) e o próximo nó da lista a ser considerado para a

fracção corrente é o primeiro da lista (linha 25)10. No caso de nenhum nó ter sido

acrescentado à lista após mapeamento do nó em último lugar da lista e esta ainda contiver nós

é criada uma nova fracção temporal (linha 27). Por cada nó da lista considerado que não

caiba na fracção corrente (linha 29) é indexado o nó seguinte da lista (linha 30). Quando o

indexamento realizado pela variável NumNode tiver considerado o último nó na procura de

um nó que caiba no fraccionamento corrente é criada uma nova fracção temporal (linha 32).

Os algoritmos de ASAP e de ALAP têm complexidades computacionais de Ο(|V|+|E|) e o

algoritmo ELS apresentado de Ο(|V|2+|E|).

6.7 Abordagem Baseada no Simulated Annealing

Sem o conhecimento de resultados óptimos ou quasi-óptimos é impossível sabermos se

merece a pena investir no refinamento e na investigação de algoritmos que possam produzir

resultados melhores. Contudo, a exploração exaustiva do espaço de exploração não é

10 Uma melhoria seria considerar o primeiro dos nós na lista ordenada dos que foram inseridos ou do nó que se encontrava em consideração imediatamente antes da actualização da lista.

CAP. 6 PARTIÇÃO TEMPORAL 153

praticável devido ao número elevado de alternativas. A modelação ILP11 do problema da

partição temporal também parece não ser praticável em exemplos de dimensões elevadas,

como o comprovam os elevados tempos de computação apresentados em [Kaul98].

Pelos motivos acima expostos, considerou-se nesta tese um algoritmo iterativo com

características que permitissem escapar a mínimos locais e que permitisse avaliar a distância

dos métodos construtivos baseados em heurísticas a soluções próximas do óptimo. A escolha

recaiu no simulated annealing12 (SA) [Kirkpatrick83] pela facilidade de implementação e por

ter custos computacionais toleráveis. Os algoritmos baseados no simulated annealing

caracterizam-se por a temperaturas altas a probabilidade de aceitação de movimentos que têm

custos piores ser maior, e à medida que a temperatura decresce a probabilidade de aceitação

de movimentos com custos piores vai também decrescendo. Esta característica de que

movimentos que produzem custos piores terem sempre possibilidades de serem aceites

permite que o algoritmo fuja a mínimos locais.

A versão implementada é sintonizada para a resolução da partição temporal (ver Figura 6.6).

O algoritmo parte de um fraccionamento temporal inicial (obtido pelos métodos construtivos

previamente considerados, por exemplo) e tenta refiná-lo movendo nós (escolhidos

aleatoriamente de entre os nós que podem ser movidos validamente) entre fracções adjacentes

(linhas 11 e 12). A opção de partir de um fraccionamento inicial realizável permite que o

algoritmo retorne sempre um fraccionamento temporal factível, pois como é sabido o SA não

garante que em tempo limitado seja encontrada uma solução realizável.

Defin ição 6 -1 . Movimento vál ido de um nó entre f racções temporais .

É um movimento de um nó entre fracções adjacentes que não viola nenhuma

precedência temporal, mas que pode originar a excedência da área máxima

disponível na fracção temporal receptora.

O algoritmo vai iterativamente construindo novos fraccionamentos temporais tentando

conseguir fraccionamentos que melhorem o valor da função de custo (6.2). No algoritmo, k1

11 Do inglês: Integer Linear Programming. 12 A intenção desta investigação não foi avançar o estado da arte nos procedimentos do simulated annealing em geral. Por isso, as opções realizadas não serão, nesta tese, discutidas nem justificadas em pormenor.

154 CAP. 6 PARTIÇÃO TEMPORAL

representa o peso do atraso do caminho crítico e k2 o peso dos custos de comunicação entre

fracções.

Por cada decréscimo da temperatura são realizadas várias iterações (linhas 10 a 28). Por cada

iteração é realizado um movimento válido de um nó. A probabilidade de aceitação de um

novo movimento é dada pelo valor da exponencial e-∆/temp e o critério de aceitação é baseado

na escolha de um número aleatório pertencente ao intervalo [0, 1] (linha 16). Na equação

temp representa a temperatura corrente e ∆ a diferença entre o custo da última solução e o

custo da solução actual (linha 13).

1. doSimAnnealTempPart(graph G, TempPart TP, int k1, int k2) 2. TempPart newTP = TP.clone(); 3. int iter = Anneal.computeIter(G); 4. float temp = Anneal.FindTemp(TP, iter, k1, k2);

5. float ε = 0.9f; 6. float γ = 1.02f 7. long costOld = TP.getCost(k1, k2); 8. long costMin = CostOld; 9. do 10. for(int I=0; I<iter;I++) 11. <NumNodeA, NumPartA, NumPartB> = TP.getValidMove(); 12. boolean unfeas = TP.move(NumNodeA, NumPartA, NumPartB); 13. long costNew = unfeas ? (costMin+1) : TP.getCost(k1, k2); 14. long delta = costNew – costOld; 15. if(delta > 0)

16. if(random.nextFloat() < temp

delta

e−

) 17. TP.undoMove(NumNodeA, NumPartA, NumPartB); 18. else 19. costOld = costNew; 20. else 21. if(!unfeas) 22. if(costNew < costMin) 23. costMin = costNew; 24. newTP = TP.clone(); 25. 26. costOld = costNew; 27. 28.

29. temp = ε * temp; 30. iter = γ * iter; 31. while (temp > Anneal.finalTemp); 32. return newTP; 33.

F igura 6 .6 . Versão do a lgori tmo Simulated Annealing para part ição

temporal .

CAP. 6 PARTIÇÃO TEMPORAL 155

Exemplo 6 -4 . Movimentos vál idos entre f racções temporais .

A Figura 6.7 mostra um exemplo de um movimento válido realizado pelo

SA apresentado. Supondo um fraccionamento temporal inicial como o

apresentado na Figura 6.7, o algoritmo escolhe aleatoriamente duas fracções

adjacentes e um nó que possa ser movido entre as duas. Na Figura 6.7 um

nó seleccionado do conjunto 1, 8, 6, 7 produz um movimento válido da

fracção #1 para a #2. Um nó seleccionado do conjunto 9, 11 produz um

movimento válido da fracção #2 para a #1. Se, por exemplo, considerarmos

o movimento do nó 7 da fracção #1 para a #2 o próximo movimento válido

deverá ser escolhido dos subconjuntos 1, 8, 6, 4 ou 9, 11, 7 para cada

uma das direcções referidas.

Quando um movimento de um nó causa a criação de uma fracção temporal irrealizável (a

área da fracção excede a área total disponibilizada) é atribuído ao custo desse fraccionamento

um valor maior do que o valor mínimo encontrado até então (linha 13). A solução final

resultante corresponde ao fraccionamento com menor custo encontrado até então (linhas 22 a

25).

<< 1 << 1

+

××

u

××

dx

-

u

-

××

dx

+

u_1

x y

++

dx x

x_1

××

dx u

y_1

y

+

1 2 3 4

5 6 7

8

9

10 11

12

Fracção #1

Fracção #2

Figura 6 .7 . Exemplo de um movimento entre f racções temporais

considerado vál ido pela abordagem SA apresentada.

156 CAP. 6 PARTIÇÃO TEMPORAL

Outras possibilidades poderiam ser consideradas, como sejam o movimento de nós entre

fracções não adjacentes e o movimento de agrupamentos de nós. Este tipo de movimentos

poderá ajudar o algoritmo a encontrar soluções óptimas mais rapidamente mas não foram

realizados estudos que o confirmem.

A temperatura inicial é calculada com base na média do número de movimentos numa pré-

avaliação do SA (linha 4). O número de iterações é função do número mínimo de fracções e

do número de nós no grafo (linha 4). O SA implementado usa uma relação de arrefecimento ε

fixa para calcular a próxima temperatura Tk = ε × Tk-1 (linha 29). Os resultados experimentais

indicaram que um valor de ε de 0,95 produz resultados satisfatórios. O número de iterações

para cada valor de temperatura é calculado por Iterk = γ × Iterk-1 (linha 30) em que γ foi fixado

em 1,02. O algoritmo finaliza (linha 31) quando a temperatura atinge o valor fixado como

mínimo (para a maioria dos casos foi aceitável 0,1).

O uso do algoritmo baseado no simulated annealing permite explorar a utilização de um

número maior de fracções temporais do que o usado pela solução inicial. Para tal, o utilizador

necessita de especificar o número de fracções temporais vazias que deve ser adicionado à

solução inicial que será fornecida ao algoritmo.

6.8 Resultados Experimentais

Todos os algoritmos supracitados foram implementados em linguagem Java. Nesta secção

são apresentados resultados experimentais de forma a se poderem avaliar os algoritmos.

Os símbolos Ω, Γexec e ∆com referem o resultado total e resultados parcelares da equação (6.2).

Na expressão (6.7) é indicada cada parcela correspondente ao símbolo indicado. Ω representa

o atraso do caminho crítico do grafo (sem a escrita/leitura das entradas/saídas primárias) em

ciclos de relógio. Os resultados não consideram a escrita/leitura das entradas/saídas primárias

nem a possibilidade de intercalar a execução com comunicações entre fracções temporais. O

factor δ serve para, sempre que necessário, inibir a soma dos tempos de execução do caminho

crítico de cada fracção (δ =0).

CAP. 6 PARTIÇÃO TEMPORAL 157

( ) ( )[ ][ ] ( )[ ]444 3444 2144444 344444 21

exec

Max

com

OutInNumPart

iiAtraso

NumPart

iiiciclos

Γ

Π+

Π+Π×=Ω ∑∑== 11

δτ (6.7)

S1 refere o algoritmo em [GajjalaPu98b] que foi explicado previamente. S2 refere o mesmo

algoritmo orientado pelos níveis de ALAP. S3 e S4 referem o algoritmo da Figura 6.4 que

pode ser orientado pelos níveis ASAP (S3) ou ALAP (S4). S5 é uma versão de S2 com os nós

ordenados pela ordem ascendente dos níveis de ALAP e os nós com o mesmo nível de ALAP

ordenados pelos níveis de ASAP (por ordem ascendente). S6 é uma versão de S1 no qual os

nós de cada nível ASAP são ordenados pela ordem ascendente dos níveis de ALAP. S7 é uma

versão do algoritmo estático baseado em lista em que os nós da lista de nós prontos para

mapeamento são ordenados pela ordem ascendente do valor ALAPstart. Finalmente, os

algoritmos ELS e SA referem respectivamente a extensão ao escalonador estático baseado em

lista (ver Figura 6.5) e à abordagem simulated annealing (ver Figura 6.6).

Nas tabelas, E é a melhoria do custo da solução SA relativamente à solução ELS e é

calculada pela expressão ( ) ELSSAELSE ΩΩ−Ω= .

Os tempos de computação apresentados referem os tempos de execução dos Java bytecodes,

obtidos pela compilação pelo javac do JDK1.2, com o JIT da Symantec num PC (@133MHz,

64 MB RAM, Windows95). Os métodos construtivos obtiveram cada solução em menos de 1

ms.

Os resultados do SA nas Tabela 6.2 e Tabela 6.3 são resultados muito próximos do óptimo. O

algoritmo foi executado diversas vezes, muitas das vezes partindo de soluções iniciais

resultado da aplicação prévia do SA, e os resultados foram sempre os mesmos.

O primeiro exemplo a considerar é o corpo do ciclo do exemplo HAL [Paulin86] cujo DFG

foi previamente apresentado na Figura 6.1. O exemplo tem área total de 4.384 células e atraso

do caminho crítico de 58 ciclos de relógio.

Os resultados apresentados na Tabela 6.2 mostram melhorias pequenas do SA em relação ao

ELS. O SA tem a capacidade de criar agrupamentos de nós com ligações fortes entre eles

reduzindo os custos de comunicação. Estes resultados também mostram que o ELS produz

resultados pelo menos tão bons como os obtidos pelas outras heurísticas.

158 CAP. 6 PARTIÇÃO TEMPORAL

Tabela 6 .2 . Resul tados para o exemplo HAL ( ττciclos=2).

CASO #Part. Max Área

Medidas S1 S2 S3 S4 S5 S6 S7 ELS α=2

SA

E (%)

A 5 2.457

Ω ∆com

Γexec

tempo

70 6 58 -

86 4 78 -

86 4 78 -

80 4 72 -

80 4 72 -

70 6 58 -

80 4 72 -

66, β=20 4 58 < 1 ms

62 2 58 7,8 s

6,1

B 2 4.096

Ω ∆com

Γexec

tempo

66 4 58 -

86 4 78 -

66 4 58 -

84 6 72 -

84 6 72 -

66 4 58 -

84 6 72 -

66, β=1 4 58 < 1 ms

60 2 58 5,7 s

9,1

O segundo exemplo é o filtro SEWHA [Jain88]. O exemplo é constituído por 16

multiplicadores e 12 somadores (28 nós no DFG) contribuindo para uma área total de 16.960

células e um caminho crítico de 90 ciclos de relógio (consideraram-se operandos de 16 bits).

Os resultados revelaram que os piores resultados obtidos pelo ELS normalmente aparecem

quando poucas fracções temporais necessitam de ser consideradas. O ELS sofre da

incapacidade de balancear as fracções (por ser um algoritmo “guloso”, tenta preencher as

fracções temporais sequencialmente). Como foi referido esta deficiência tem mais impacto

quando o número de fracções temporais é pequeno, como se pode constatar pelos resultados

apresentados na Tabela 6.2 e na Tabela 6.3.

Tabela 6 .3 . Resultados para o f i l t ro SEWHA, considerando dois

d isposi t ivos com áreas máximas de 4 .096 célu las (casos A) e de 16.384

células (casos B) respect ivamente.

CASO/#Part τciclos Medidas S1 S2 ELS (α,β) SA tempo E (%) A1/5 2 Ω 222 202 202 (2,20) 194 26,4 s 3,9 B1/2 2 Ω 134 142 134 (2, 1) 98 90 s 26,8 A2/5 1 Ω 186 166 166 (1, 1) 162 25,4 s 2,4 B2/2 1 Ω 122 126 122 (1, 1) 94 85 s 22,95 A3/5 0 Γexec 150 130 118 (0, 1) 118 26 s 0 B3/2 0 Γexec 110 110 110 (0, 1) 90 68 s 18,18 A4/5 1 ∆com 36 36 26 (13 laços) (1, 0) 22 19,2 s 15,38 B4/2 1 ∆com 12 16 6 (3 laços) (1, 0) 2 66,7 s 66,7

Na maioria das vezes os resultados não melhoram se se permitir que o SA explore mais

fracções do que o número obtido pelo S1 (o SA converge para o número mínimo de fracções

temporais).

CAP. 6 PARTIÇÃO TEMPORAL 159

Para permitir um estudo estatístico do comportamento dos vários algoritmos foi

implementado um sintetizador de grafos pseudo-aleatórios. O sintetizador permite seleccionar

o número de nós e para cada nó, o número máximo de laços de saída, os valores mínimo e

máximo da área e atraso, e o grau de paralelismo que permite sintetizar grafos preconizando

seriação ou paralelismo.

Na Tabela 6.4 estão apresentados resultados, que podem ser visualizados graficamente na

Figura 6.8, obtidos com grafos sintetizados. Cada grafo tem 50 nós e os laços de saída de

cada nó variam entre 0 e 4, ou entre 0 e 10. Para cada algoritmo é apresentada a melhoria

relativamente ao método S1. São também apresentados resultados para custos de

comunicação diferentes.

As linhas 2 e 3 da Tabela 6.4 apresentam os resultados considerando que cada leitura/escrita

para comunicação entre fracções temporais custa 2 ciclos de relógio. As linhas 4 e 5,

apresentam resultados combinando custos de comunicação e de atraso do caminho crítico. Os

resultados das linhas 6 e 7 foram obtidos, quando apenas foi considerada o atraso do caminho

crítico e as linhas 8 e 9 apresentam resultados, quando apenas são considerados os custos de

comunicação. A última coluna apresenta a média das melhorias relativas do SA sobre o ELS

e a última linha as médias das melhorias relativas para os diversos custos de

intercomunicação considerados.

Tabela 6 .4 . Resul tados para 100 grafos gerados pseudo-aleator iamente.

Laços de saída

τciclos / δ

S2 S3 S4 S5 S6 S7 ELS (α,β) SA E

(%)

1: [0 10] 2/1 -0,9 9,1 1,1 -2,2 -1,4 9,2 12,2 (2,1) 29,7 19,9 2: [0 4] 2/1 -1,0 12,4 1,7 -3,1 -0,8 14,5 18,5 (2,1) 38,1 24 3: [0 10] 1/1 -0,3 5,8 0,2 -0,7 0,7 8,7 6,8 (1,1) 22,9 17,3 4: [0 4] 1/1 -0,3 7,4 0,7 -1,1 3,3 13,7 10,6 (1,1) 28 19,5 5: [0 10] 0/1 2,8 -8,6 -3,5 5,4 8,6 6,0 9,5 (0,1) 13 3,9 6: [0 4] 0/1 2,2 -11,1 -2,9 5,8 16,2 10,8 10,9 (0,1) 16 5,7 7: [0 10] 1/0 -2,2 15,3 2,7 -5,1 -5,3 10,3 29,8 (1,0) 45 21,7

E/N (%)

8: [0 4] 1/0 -2,5 22,9 -3,7 -7,1 -9,8 16,0 48 (1,0) 57,8 18,8

Total 9: - - 0,28 6,65 -0,46 -1,0 1,4 11,2 18,3 20,6 16,4

Os resultados apresentados para o SA foram obtidos pela execução deste tendo como solução

inicial o fraccionamento temporal fornecido pelo ELS. Em muitos casos voltou-se a executar

repetidamente o SA com a solução obtida anteriormente pelo próprio até não se verificarem

melhorias significativas.

160 CAP. 6 PARTIÇÃO TEMPORAL

A Tabela 6.4 mostra que o S3 foi o melhor algoritmo das abordagens baseadas nos níveis

ASAP/ALAP no que respeita a custos de comunicação13. Os resultados mostram melhores

soluções dos escalonadores baseados em lista sobre as abordagens ASAP/ALAP no que

respeita ao atraso do caminho crítico como seria de esperar devido à oportunidade de

executar nós disponíveis em paralelo com nós do caminho crítico.

-20

-10

0

10

20

30

40

50

60

1 2 3 4 5 6 7 8 Ganhototal

S2S3S4S5S6S7ELSSAE

Figura 6 .8 . Gráfico comparat ivo das diversas abordagens. O e ixo

hor izontal representa os números indicados na segunda coluna da

Tabela 6 .4 . O eixo vert ical representa a melhoria relat iva (%) a S1.

S6 revelou-se o melhor algoritmo dos métodos construtivos exceptuando o ELS quando o

objectivo é a minimização do atraso do caminho crítico sem entrar em linha de conta com os

custos de comunicação entre fracções temporais. Este facto deve-se ao algoritmo considerar

primeiramente o mapeamento de todos os nós de um determinado nível antes de considerar os

nós do nível imediatamente a seguir. Quando se utiliza um algoritmo de escalonamento

baseado em lista, para cada nó escalonado, o algoritmo procura por nós que possam ser

adicionados à lista de nós prontos, devido ao facto de terem todos os nós fonte mapeados.

Quando os custos de comunicação entre fracções não são negligenciáveis, mas sem pesos

13 Na função do custo total (6.7) a atribuição dos valores: a) (τciclos =0, δ≠0): implica apenas consideração dos custos de execução (atraso do caminho crítico); b) (τciclos ≠0, δ=0): implica apenas consideração dos custos de comunicação.

CAP. 6 PARTIÇÃO TEMPORAL 161

demasiado elevados, o S7 foi o melhor dos métodos construtivos considerados, e os

resultados até ultrapassam os obtidos com o ELS, sem exploração dos custos de cada termo

na função de custo. Devido ao facto do ELS se poder reduzir ao S7 (fazendo α=0, β=1, η=0

na equação (6.3)) estes resultados são por isso também encontrados pelo ELS para os valores

indicados dos parâmetros.

Os resultados mostram uma melhoria global do ELS em relação às outras heurísticas

consideradas. O ELS encontrou uma solução comparável em média em cerca de 16% do

resultado obtido pelo SA (de 4 a 24%). É previsível que, utilizando o ELS, melhores

resultados possam ser conseguidos explorando os parâmetros α, β na equação (6.3) como

foram os casos apresentados na Tabela 6.2 (caso A) e na Tabela 6.3 (caso A1) nos quais foi

utilizado 20 para o valor de β. A exploração do parâmetro η na mesma equação pode também

permitir a obtenção de resultados melhores.

Os resultados obtidos de experiências com grafos gerados pseudo-aleatoriamente confirmam

o pressuposto de que o número de fracções obtido pelas heurísticas (ASAP, ELS, etc.) é

próximo do óptimo, e poucos casos necessitaram de mais fracções (uma) para minimizar a

função de custo. Esta observação pode ser explicada pelo facto de que mais fracções têm

tendência a aumentar o atraso do caminho crítico, e apenas em poucos casos podem reduzir o

custo total das comunicações entre fracções.

6.9 Conclusões

Foram apresentadas neste capítulo técnicas de partição temporal que exploram o conceito de

“hardware virtual”.

Os resultados mostram que algoritmos simples podem ser usados para resolver a partição

temporal ao nível comportamental. O algoritmo apresentado (ELS), baseado num escalonador

estático em lista, reduz a complexidade da implementação e o tempo de computação. Sendo

um algoritmo inicialmente usado para escalonamento de operações pode ser facilmente

capacitado para a partilha de recursos (embora a metodologia mais fácil seja a execução do

algoritmo para diferentes restrições do número de recursos, o espaço de exploração

exponencial torna esta solução proibitiva e por isso, formas de redução do espaço, sem

realização de escalonamento, devem ser consideradas). A baixa complexidade do ELS torna-

162 CAP. 6 PARTIÇÃO TEMPORAL

o apropriado para lidar com grafos de grande dimensão. Os resultados mostraram a eficiência

do algoritmo e as melhorias obtidas relativamente a algoritmos de partição temporal mais

simples. Os resultados mostram melhorias sobre a abordagem ASAP apresentada em

[GajjalaPu98a] e [GajjalaPu98b] sem acrescentar demasiada complexidade computacional.

Neste capítulo foi também apresentada uma versão do simulated annealing para resolução da

partição temporal. Contudo, esquemas mais eficientes de “arrefecimento” necessitam de ser

estudados para englobar o algoritmo no compilador. Com base nos tempos de computação e

nos resultados obtidos, a solução SA não parece, pelo menos só por si, uma escolha razoável

para compiladores quando um dos objectivos principais é a celeridade da compilação. No

entanto, a abordagem SA pode ser usada depois do ELS como um procedimento de

refinamento, sempre que a rapidez de compilação não for prioritária.

Os resultados obtidos mostraram que na maioria das vezes o número óptimo de fracções

temporais é o mínimo. Esta conclusão, baseada em resultados obtidos pelo SA, vem ao

encontro de [DeHon96].

Esquemas de partição temporal capazes de lidar com a partição temporal de ciclos deverão

ser investigados. A técnica de distribuição de ciclos usada pela comunidade de compiladores

de software é um bom ponto de partida.

A possibilidade de partilha de recursos hardware de dimensões elevadas (como é o caso dos

multiplicadores) deverá também ser considerada. Pode aliviar os efeitos de comunicação e

permite a reutilização de operadores cuja configuração está activa.

O algoritmo ELS apresentado neste capítulo foi englobado no compilador NENYA

apresentado nesta tese e a sua integração será dissecada no capítulo 7.

163

7. Escalonamento Baseado em Regiões

“Lost time is never found again.”

John H. Aughey

Nos capítulos anteriores foram apresentados os modelos intermédios, optimizações do fluxo

de dados, o suporte à geração do reconfigware e a partição temporal. Neste capítulo é

detalhado o modo como é obtido o controlo responsável por orquestrar a execução do

algoritmo em reconfigware. Para tal, é descrito o escalonador que aqui se refere à ordenação

estática de operações, existentes em modelos intermédios que representam fluxos intensivos

de controlo e/ou de dados, pelos ciclos de relógio. O método de escalonamento é baseado em

regiões constituídas pelo conjunto de operações resultante da união de vários blocos básicos.

Embora nos tenhamos baseado num dos algoritmos de escalonamento mais simples - o

algoritmo de escalonamento estático baseado em lista [Gajski92] - os conceitos podem ser

aplicados a outros algoritmos de escalonamento mais complexos. O principal objectivo foi o

de garantir tempos de compilação competitivos com a compilação de software, sem descurar

critérios que asseguram resultados minimamente eficientes. Concretamente, uma das

finalidades deste escalonador é a de resolver os conflitos nos acessos às memórias acopladas

164 CAP. 7 ESCALONAMENTO BASEADO EM REGIÕES

ao FPGA, ao sequenciar esses mesmos acessos durante a execução do hardware1. Outra das

finalidades é a de controlar a execução de regiões cíclicas2.

O capítulo começa por descrever os tipos de escalonamento possíveis com base na

representação em grafos utilizada. É definido o grafo, que representa as transições de estados,

gerado pelo escalonador e é apresentado o algoritmo de escalonamento baseado em regiões.

Embora não tenham sido ainda implementadas no compilador são apresentadas formas de

lidar com regiões cíclicas concorrentes. Por último, são apresentados alguns resultados

comparativos entre um escalonamento baseado no bloco básico com o escalonamento

baseado em regiões.

7.1 Escalonamento e Grafos Gerados

Os tipos de escalonamento podem ser agrupados pelo tipo de grafos representantes da

descrição inicial e pela forma como lidam com esses mesmos grafos:

• CDFG3: Os escalonamentos baseados neste tipo de representação escalonam, bloco

básico a bloco básico (ou instrução a instrução), as operações, pela ordem de

aparecimento no CFG construído a partir da descrição alto-nível. Este tipo de

representação restringe o escalonamento ao não tirar completamente partido do

paralelismo interbloco existente e da possibilidade de existência de fluxos de controlo

múltiplos. Contudo, a representação permite lidar facilmente com estruturas de

controlo. Alguns autores estudaram esquemas que permitem movimentações de

operações (cujos movimentos não violem dependências) entre blocos básicos de

forma a melhorar os resultados finais quando existem restrições de recursos.

• DFG4 estendido5: Esta representação torna mais difícil a manipulação de ramos

condicionais, mas permite a representação do paralelismo existente ao nível da

1 O escalonador pode ser facilmente expandido para suportar partilha de unidades funcionais (por exemplo multiplicadores). 2 Consideramos região cíclica como sendo a região de um programa que compreende um ciclo podendo ou não conter sub-regiões cíclicas (ciclos). No caso geral, a existência de recursividade no programa também forma regiões cíclicas, mas este tipo de regiões cíclicas não serão abordadas nesta tese. 3 Do inglês: Control/Data Flow Graph. 4 Do inglês: Data Flow Graph.

CAP. 7 ESCALONAMENTO BASEADO EM REGIÕES 165

operação. No PRISM-II [Agarwal94] é utilizado o CFG de blocos básicos para

escalonar as operações apresentadas no DFG global. São utilizadas técnicas de

agrupamento de estados. Contudo, o escalonamento interblocos tem a granulosidade

do bloco básico.

• HPDG6: Esta representação assume tantos fluxos de controlo quantos os que forem

necessários. O escalonamento tomando como base este tipo de modelo pode ser

baseado em regiões, o que permite a obtenção de melhores resultados. Neste

escalonamento, os blocos básicos no HPDG são agrupados para formarem uma região

do DFG global, que é posteriormente escalonada em conjunto. Este tipo de

escalonamento permite que as operações apareçam no escalonamento pelas

dependências determinadas, possibilitando que operações em diferentes blocos

básicos possam ser consideradas no mesmo passo de escalonamento devido à

ausência de dependências de dados e/ou ao facto de poderem ter execução

especulativa.

Em [Cardoso99a] foi considerado um escalonamento baseado nos CDG e DDG sem

agrupamentos por regiões. Este tipo de escalonamento, embora útil para lidar com a

reestruturação baseada nas dependências de dados lidava com um DFG por cada bloco

básico. Não permitia formar agregações de blocos básicos nem manter, por cada agregação,

ligação aos nós correspondentes no DFG global. Essa forma de escalonamento, embora capaz

de considerar dependências interblocos, pode produzir escalonamentos ineficientes devido à

granulosidade utilizada. A Figura 7.2 apresenta as melhorias obtidas para um conjunto de

exemplos cujas características se encontram descritas no apêndice D. Dos exemplos

considerados obteve-se uma melhoria relativa de quase 35% para o exemplo USQRT. Para os

exemplos CRC-32 e HAMMING não foram obtidas melhorias.

Exemplo 7 -1 . Agrupamento de b locos básicos.

Considere-se o exemplo com dois blocos básicos apresentado na Figura

7.1a e os atrasos para cada operação definidos na Figura 7.1b. Ao se

considerarem os blocos básicos individualmente (ver Figura 7.1c) é obtido

5 Adicionado de nós de if, case, loop e select. 6 Do inglês: Hierarchical Program Dependence Graph.

166 CAP. 7 ESCALONAMENTO BASEADO EM REGIÕES

o escalonamento apresentado na Figura 7.1d. No caso dos blocos básicos

serem agrupados (ver Figura 7.1e) o escalonamento obtido (ver Figura 7.1f)

elimina um ciclo de relógio (6 ciclos) ao escalonamento de blocos básicos

sem agrupamento (7 ciclos) da Figura 7.1d.

... A = B*C; BB0 D = A*(E+C); BB0 If(A > 10) BB0 C = A+F; BB1 …

B C E

F

A

C

BB0

BB1

10

a) c)

B C E

F

A

C

BB0 – BB1

10

e)

10

d)

f) b)

Figura 7 .1 . a) Exemplo; b) atraso para cada operação do exemplo (cada

quadrado representa um cic lo de re lógio) ; c) Os dois blocos básicos e

os DFGs correspondentes; d) Escalonamento ao nível do bloco básico;

e) Agrupamento dos dois blocos básicos e DFG global ; f )

Esca lonamento com agrupamento de b locos básicos.

O processo de escalonamento utiliza como entrada os grafos previamente apresentados no

capítulo 3. Assim, é assumida a existência do grafo que representa a hierarquia (HPDG) e do

DFG global. Cada nó do grafo hierárquico identifica os nós do DFG que lhe pertencem.

Nesta fase, os nós correspondentes a operações do DFG global devem ter associada uma

macrocélula existente na biblioteca tecnológica [Cardoso99d], como foi descrito no capítulo

4 (e por isso devem estar caracterizados em termos de atraso e de área). Nesta fase os

escalonamentos ASAP e ALAP foram também determinados (capítulo 4).

CAP. 7 ESCALONAMENTO BASEADO EM REGIÕES 167

Para assegurar a correcta execução (preservando as dependências determinadas) das

operações, o escalonador forma um STG7 por cada fracção temporal.

0%

5%

10%

15%

20%

25%

30%

35%

MULT573 SQRT USQRT CRC-32 HAMMING QRS

Figura 7 .2 . Melhorias relat ivas do escalonamento interblocos básicos

baseado na granulosidade do opera dor versus a granulosidade do

bloco básico.

Def inição 7 -1

O grafo de transição de estados (STG), G(S, T), é um grafo direccionado

constituído por um nó START, um nó END, um conjunto finito de estados (nós), S

= s1, s2, ..., s|S|, e um conjunto de relações assimétricas formadas por transições

(laços) direccionadas, T ⊂ S × S. Um laço tij ∈ T, entre o nó si e o nó sj, ambos

pertencentes a S, indica uma transição de estados entre o nó si e o nó sj.

O grafo começa no nó START e termina no nó END. Não existem laços

incidentes a START nem laços difusores de END.

Cada estado (nó) do STG corresponde a um ciclo de relógio, indica a unidade

funcional (UF) em execução nesse mesmo estado e contém informação acerca de

UFs com execução condicionada pelo valor de uma expressão booleana. Cada

7 Do Inglês: State Transition Graph.

168 CAP. 7 ESCALONAMENTO BASEADO EM REGIÕES

estado atribui o valor dos respectivos sinais possivelmente condicionados por

sinais externos.

O STG representa também quais as condições para haver a transição para um

estado específico sempre que exista mais do que uma opção.

Cada STG gerado pode depois ser implementado por hardware específico, sob a forma de

uma máquina de estados finita (FSM8). O compilador gera uma descrição VHDL

comportamental ao nível de transferência de registos para cada STG que pode posteriormente

ser sintetizada em hardware específico por uma ferramenta de síntese lógica.

Existem diversas possibilidades para garantir o funcionamento de descrições alto-nível cuja

execução pode percorrer caminhos diferentes (ramos de construções if-else, por exemplo):

• Explicitamente pelo STG, ao incluir os caminhos do CFG. Esta representação permite

lidar facilmente com operações load/store mutuamente exclusivas, pois o próprio

caminho percorrido no STG garante a resolução de conflitos.

• Por ligações directas entre as operações que seleccionam o caminho a ser percorrido,

a selecção de definições que alcançam um determinado ponto e a atribuição de

predicados em operações com efeitos colaterais (escritas em memória).

Como um dos objectivos deste trabalho é permitir a execução especulativa de operações em

casos em que tal execução não necessita de ser restaurada optou-se pela segunda opção.

7.2 Escalonamento de Regiões Acíclicas

O escalonamento de regiões acíclicas resume-se ao simples escalonador estático em lista que

vai resolvendo a competição por unidades funcionais operador a operador, com base na

atribuição de prioridades. Na literatura podem-se encontrar diversos esquemas de atribuição

de prioridades a operadores [Gajski92][Micheli94]. No algoritmo utilizado as prioridades são

baseadas no valor de ALAP de cada operação, mas como veremos de seguida é

implicitamente utilizada uma segunda chave.

8 Do Inglês: Finite-State Machine.

CAP. 7 ESCALONAMENTO BASEADO EM REGIÕES 169

Na Figura 7.3 são apresentados resultados obtidos por um escalonador estático baseado em

lista com diferentes ordenações das operações a escalonar. O exemplo (ver Figura 7.3a)

ilustra o facto de que ordenações baseadas em mobilidades, tempo que falta para o fim, etc,

podem produzir escalonamentos ineficientes. No exemplo, as operações de leitura de

elementos dos arrays A e B, assim como as duas primeiras operações de adição têm os

mesmos escalonamentos ASAP e ALAP. Se considerarmos que só é possível um acesso à

memória em cada ciclo de relógio e que existe apenas um somador, o escalonamento

resultante, baseado nas mobilidades dos operadores, pode ser o representado na Figura 7.3b.

Este tipo de ordenação dos operadores não toma em consideração o facto de duas ou mais

operações poderem produzir dados para a mesma operação. Uma forma de lidar com este

problema é utilizar uma segunda chave, ou seja operações com o mesmo valor de primeira

chave (mobilidades, por exemplo) são ordenadas pelo valor da segunda (em ordem crescente

ou decrescente). O ordenamento com base numa segunda chave que agrupa as operações com

sucessores comuns e que tenham a mesma mobilidade produz o escalonamento apresentado

na Figura 7.3c. Embora este exemplo também utilize partilha de somadores, mesmo quando

apenas os acessos a memória são seriados esta segunda chave pode produzir resultados

melhores.

B[2] A[1] B[4] A[3]

C[1]

B[2]

A[1]

B[4]

A[3]

C[1]

B[2]

A[1]

B[4]

A[3]

C[1]

a) b) c)

Figura 7 .3 . Escalonamento com di ferentes ordenações das operações

(os rectângulos representam acessos a e lementos de arrays): a ) DFG

inic ia l ; b) possível escalonamento com pr ior idade unicamente baseada

no valor da mobi l idade de cada operação; c ) escalonamento com

prioridades atr ibuídas às operações com base na mobi l idade e nos

sucessores comuns.

170 CAP. 7 ESCALONAMENTO BASEADO EM REGIÕES

O algoritmo considerado não tem necessidade de produzir a segunda chave devido ao facto

das operações nos bytecodes aparecerem pela ordem de consumo.

Na secção seguinte é apresentado o algoritmo de escalonamento geral que aceita regiões

cíclicas e acíclicas.

7.3 Escalonamento de Regiões Cíclicas/Acíclicas

Na Figura 7.4 é apresentado o algoritmo de escalonamento por regiões com a partição

temporal incorporada. Recordamos que o algoritmo de partição temporal foi introduzido

previamente no capítulo 6. A partição temporal é realizada no nível de topo do HPDG e por

isso apenas o algoritmo de escalonamento do nível hierárquico de topo considera a partição

temporal. Para níveis da hierarquia abaixo deste é utilizado o algoritmo apresentado na Figura

7.5 que é fundamentalmente uma versão do algoritmo da Figura 7.4 sem a inclusão dos

aspectos relacionados com a partição temporal.

O algoritmo da Figura 7.4 vai agrupando os blocos básicos até que apareça um nó

identificador de um ciclo ou até que não existam nós para agrupar. Sempre que aparece um

nó identificador de um ciclo (linha 12) o algoritmo realiza o escalonamento do agrupamento

criado até então (desde o último grupo escalonado), linha 13, e um novo segmento de estados

é adicionado ao STG. Em seguida, é chamado o algoritmo de escalonamento de regiões

cíclicas (linha 14).

O algoritmo de escalonamento de regiões cíclicas apresentado na Figura 7.5 começa por

encontrar o nó no DFG global da região considerada que controla o ciclo (linha 2). De

seguida o algoritmo comporta-se similarmente ao algoritmo anterior, isto é, vai agrupando

blocos básicos até aparecerem novas regiões cíclicas, e nessa situação é chamado

recursivamente (linha 13), ou até todos os blocos básicos terem sido agrupados (linha 7). No

final, o algoritmo coloca o laço cíclico no STG (linha 23) e retorna informação que permite

que os novos segmentos de estados a adicionar ao STG partam do estado que representa o

início de um ciclo.

CAP. 7 ESCALONAMENTO BASEADO EM REGIÕES 171

1. DoSchedRec(MaxArea, DFG(V, E), Costs) 2. int CurrentArea=0, SchedNum=0, NumNode=0, NumSchedNodes=0; 3. SortedList = Create a sorted List of ready nodes; 4. BitSet SchedNodes = new BitSet(|V|); 5. STG = doInitSTG(); 6. while(NumSchedNodes < |V|) 7. Node A = SortedList.ElementAt(NumNode); 8. Boolean Fit = ((CurrentArea + Area(A)) <= MaxArea); 9. if(Fit) 10. SortedList.removeElement(A); 11. NumSchedNodes++; 12. if(A instanceof Loop) 13. doSTG(A, STG); Figura 7.6 14. doSchedRecLoop(A, STG); Figura 7.5 15. else 16. ScheduleElement(A, CurrentArea, SchedNum, SchedNodes); 17. 18. if(SortedList.Update(DFG, A, SchedNodes)) 19. NumNode = 0; 20. else if(NumNode ≥ List.size()) && (List.size() != 0) 21. SchedNum++; NumNode = 0; CurrentArea = 0; 22. STG = InitSTG(); 23. 24. else 25. if(NumNode ≤≤ SortedList.size()-2) 26. NumNode++; 27. else 28. SchedNum++; NumNode = 0; CurrentArea = 0; 29. doFinalEdge(STG); 30. STG = InitSTG(); 31. 32. 33. doSTG(A, STG); Figura 7.6 34. doFinalEdge(STG); 35.

Figura 7 .4 . Algor i tmo de escalonamento por regiões.

O algoritmo que escalona as operações de uma região do DFG global é apresentado nas

Figura 7.6, Figura 7.7 e Figura 7.8. Este algoritmo, como foi previamente referido, é baseado

no algoritmo de escalonamento estático baseado em lista. Os nós disponíveis para

escalonamento são ordenados pelo valor das respectivas mobilidades em ordem crescente

(linha 7 e linha 27 da Figura 7.6). O algoritmo apresentado utiliza três vectores: o vector

List que armazena as operações disponíveis para serem escalonadas, o vector Link que

armazena as operações que já foram escalonadas mas que ainda não completaram a execução,

o vector ListComp que armazena as operações que terminaram a execução (são movidos de

Link para ListComp aquando do término da execução). Quando é acrescentada uma

operação ao vector ListComp o algoritmo procura na região se há operações que possam

ficar disponíveis para serem escalonadas e adiciona-as ao vector List.

172 CAP. 7 ESCALONAMENTO BASEADO EM REGIÕES

1. DoSchedRecLoop(LoopNode B, StateTransGraph STG) 2. IfNode If1 = getIF(B); 3. GraphNew Ginner = B.getContent(); 4. Vector List = Ginner.getFirstNodes(); 5. Vector ListReady = new Vector(); 6. int NumNodesSched = 0, NumNode = 0; 7. while(NumNodesSched < Ginner.size()) 8. Node A = List.element(NumNode); 9. List.remove(NumNode); 10. NumNodesSched++; 11. if(A instanceof LoopNode) 12. doSTG(STG, getRegion(ListReady)); Figura 7.6 13. doSchedRecLoop(A); 14. else 15. ListReady.add(A); 16. ListSched.set(A.getID()); 17. 18. if(UpDate(A, ListSched, List) 19. NumNode = 0; 20. 21. 22. doSTG(STG); Figura 7.6 23. doBackEdge(STG); 24.

Figura 7 .5 . Algor i tmo de escalonamento de regiões cíc l icas.

Por cada novo estado (linha 12 da Figura 7.6) o algoritmo avança passo a passo (linha 17) até

ao fim do estado (linha 13). No final, um novo ciclo de relógio é considerado (linha 33).

O algoritmo vai produzindo o escalonamento utilizando o passo de granulosidade fina, que é

uma fracção do período do ciclo de relógio escolhido previamente (capítulo 4). Por cada

incrementação do passo é subtraído a todas as operações existentes no vector Link o valor

do incremento (linha 18).

Para a partilha de recursos o algoritmo utiliza uma janela temporal para cada operador a

partilhar (neste momento unicamente acessos à memória) e só atribui à janela temporal o

atraso de um operador do mesmo tipo quando a janela temporal está vazia (tem o valor menor

ou igual a zero, linha 4 da Figura 7.7). A atribuição do atraso de um operador a uma janela

temporal corresponde ao escalonamento do operador. Por cada incrementação do passo é

também subtraído a cada janela temporal o valor do incremento (linha 18 da Figura 7.6).

CAP. 7 ESCALONAMENTO BASEADO EM REGIÕES 173

1. DoSTG(Node A, StateTransGraph STG, DAG Region(DFG), ControlNode) 2. StateSTG LastState = STG.getLasState(); 3. StateSTG State = LastState; 4. int StateID = LastStateID; 5. StateSTG ControlStateInit, ControlStateEnd; 6. Vector List = getFirstNodes(Region); 7. List.doSort(); 8. Vector Link = new Vector(), Comp = new Vector(); 9. int[] MemSlot = new int[Board.NumOffMemories]; 10. int step = 0; clockCycle = 0; 11. while(!(List.isEmpty() && Link.isEmpty())) 12. State = new StateSTG(StateID++); 13. while(getNumCLKs(step) <= clockCycle) 14. for each Node Ai ∈List 15. Schedul(Ai, List, ListComp, Link, ControlNode); 16. 17. step += stepInc; 18. boolean hasCtrEnded = Decrement(MemSlot, ListComp); 19. if(hasCtrEnded) ControlStateEnd = State; 20. Boolean update = false; 21. for each Node Bj ListComp 22. if(update(Bj)) 23. ListComp.remove(Bj); 24. update = true; 25. 26. 27. if(update) List.doSort(); 27. 28. if(LastState has only registers) 29. STG.add(State); 30. STG.addEdge(LastState, State); 31. LastState = State; 32. else StateID--; 33. clockCyle++; 34. 35. ControlStateEnd.addFlag(ControlNode); 36. Return Loop Information(ControlStateEnd, ControlStateInit); 37.

Figura 7 .6 . Algor i tmo de cr iação do STG.

A parte do algoritmo representada na Figura 7.8 retira o nó da lista de nós disponíveis para

serem escalonados (linha 2) e se o nó tiver atraso não nulo (linha 3) adiciona-o à lista de nós

que foram escalonados mas ainda não completaram a execução (Link, linha 4). No caso do

atraso ser nulo (linha 5) é feita a busca de nós que possam ficar disponíveis para serem

escalonados e se essa busca der resultados os nós encontrados são adicionados

ordenadamente à lista de nós disponíveis para escalonamento (linhas 6 a 8).

Como foi referido, o algoritmo utiliza uma janela temporal para cada memória e assume que

os arrays foram previamente mapeados em cada uma das memórias existentes. Os nós no

174 CAP. 7 ESCALONAMENTO BASEADO EM REGIÕES

DFG de acesso à memória são rotulados com o identificador da respectiva memória. No caso

de partilha de outros recursos o mapeamento pode ser feito durante a execução do algoritmo

de escalonamento. O algoritmo necessita, nesse caso, de procurar uma janela temporal livre

com o mesmo tipo do operador a escalonar.

1. Schedul(DAGNode A, Vector List, Vector ListComp, Vector Link, DAGNode ControlNode) 2. if(Ai instanceof LdNode or StNode) 3. int MemID = Ai.getMemID(); 4. if((MemSlot[MemID] <= 0) && isInitCycle(step)) 5. MemSlot[MemID] = Ai.delay(); 6. LastState.add(Sel, St1, Ai); 7. Schedule(Ai,Link, List); Figura 7.8 8. 9. else if((Ai is Register) && isInitCycle(step)) 10. Schedule(Ai,Link, List); Figura 7.8 11. if(Ai.isFirstAssign()) 12. LastState.add(Sel, St1, Ai); 13. else 14. EndLoopState.add(Sel, St1, Ai); 15. 16. else if(Ai is ControlNode) 17. ControlStateInit = State; 18. ControlStateEnd = State; 19. Schedule(Ai,Link, List); Figura 7.8 20. else 21. Schedule(Ai,Link, List); Figura 7.8 22. 23.

Figura 7 .7 . Algor i tmo de cr iação do STG (2ª parte).

1. Schedule(DAGNode A, Vector Link, Vector List) 2. List.remove(A); 3. if(Ai.delay() > 0) 4. Link.add(A); 5. else 6. if(update(A, List)) 7. List.doSort(); 8. 9. 10.

Figura 7 .8 . Algor i tmo de cr iação do STG (3ª parte).

Exemplo 7 -2 Escalonamento de um c ic lo .

Considere-se o exemplo seguinte, e que os arrays A, B e C foram

mapeados numa memória de um porto:

CAP. 7 ESCALONAMENTO BASEADO EM REGIÕES 175

for(int i=0;i<10;i++)

c[I]=a[I]+b[I];

O compilador produz um STG com 9 estados com execução em 73 ciclos (7

× 10 + 1 + 2). A Figura 7.9 apresenta o grafo correspondente à unidade de

dados gerada pelo NENYA e a Figura 7.10 ilustra o escalonamento das

operações em cada estado do STG. No último estado de cada iteração de

um ciclo (estado 9 para o exemplo da Figura 7.10) são gerados os sinais

necessários para o estado seguinte (primeiro estado de cada iteração do

ciclo). Não é, por isso, necessário utilizar um estado unicamente

responsável pela actualização de uma nova iteração da região cíclica. Deve-

se ter em atenção que, no exemplo considerado, o primeiro acesso à

memória (leitura) é feito de forma especulativa, e por isso o endereço

determinado pelo índice vem directamente do multiplexador em vez do

registo que armazena o valor referente à variável i. No fim de cada iteração

do ciclo a variável i é actualizada no início do estado imediatamente a

seguir à iteração.

REG i

0

10

lt_N

Endereço A

REG Ai REG Bi

LOAD/STORE Sel1 Endereço B

Sel2

Endereço C

Ci

Figura 7 .9 . Grafo da unidade de dados gerada pe lo NENYA para o

exemplo da soma de dois vectores .

176 CAP. 7 ESCALONAMENTO BASEADO EM REGIÕES

++ < 10

+

2

3

4

5

6

7

8

9

B[I]

A[I]

C[I]

start

end

+ = 3,54 ciclos load/store = 1 ciclo ++ = 0,4 ciclos < 10 = 0,37 ciclos

Estado

1

Figura 7 .10 . Escalonamento de operações (exemplo: soma de vectores,

C = A + B, com 10 e lementos cada) .

O algoritmo descrito até aqui escalona em série regiões cíclicas que apareçam lado a lado no

HPDG. A possibilidade de execução concorrente destas regiões pode ser uma fonte de

melhoria de desempenho, pois permite a sobreposição de regiões por natureza

computacionalmente intensivas. Na secção seguinte é apresentada uma forma de lidar com a

execução de regiões cíclicas concorrentes.

CAP. 7 ESCALONAMENTO BASEADO EM REGIÕES 177

7.4 Escalonamento de Regiões Cíclicas Concorrentes

A principal característica do modelo de representação utilizado é o de explicitamente

representar regiões com possibilidade de serem executadas concorrentemente. O

escalonamento deste tipo de concorrência pode ser realizado região-a-região e o controlador

gerado pode ser constituído por FSMs também concorrentes, sincronizadas nos pontos de

junção (término das regiões concorrentes). As regiões cíclicas concorrentes apresentam,

contudo, dificuldades suplementares sempre que seja necessário partilhar recursos entre elas.

Em [Lakshmin99] é apresentado um escalonador que permite a execução de regiões cíclicas

em paralelo por meio de uma única FSM. Quando existem várias regiões cíclicas prontas a

escalonar, o escalonador resolve estaticamente a partilha de unidades ao considerar todos os

casos possíveis de execução dessas regiões. Por isso, sofre do problema da explosão devido à

necessidade de cobertura de todos os casos possíveis (término de cada ciclo e execução dos

restantes).

Nesta tese é apresentada uma abordagem diferente. Cada região cíclica pode ser representada

por uma sub-STG, havendo execução concorrente entre sub-STGs que representem regiões

cíclicas com funcionamento concorrente. No caso de existirem regiões cíclicas concorrentes é

construído um STG que incorpora dois tipos de nós especiais, o nó fork e o nó join. O nó fork

inicia sub-STGs e o nó join sincroniza sub-STGs. Cada sub-STG pode ser implementado por

uma FSM activada por um sinal de start e que após finalizar a execução produz um sinal de

done. Os nós de join que aparecem no STG podem ser implementados por estados da FSM

que ficam à espera que sejam activados todos os sinais done de cada FSM correspondente a

cada sub-STG.

Quando não existem competições interciclos o escalonamento é facilitado e resolve-se pela

simples geração de escalonadores concorrentes com pontos de sincronização no fim.

Os possíveis conflitos nas utilizações dos mesmos operadores por parte de, por exemplo duas

regiões concorrentes, são salvaguardados por um mecanismo de arbitragem que resolve

acessos ao mesmo recurso. Para simplificar o processo de arbitragem são dadas prioridades

178 CAP. 7 ESCALONAMENTO BASEADO EM REGIÕES

estáticas a cada região cíclica concorrente9. O árbitro baseado neste esquema é bastante

simples (formado, para cada sinal de aceitação, pela conjunção do próprio com os sinais de

requerimento com maior prioridade invertidos). As prioridades podem ser baseadas na ordem

decrescente dos pesos calculados com o número de iterações multiplicado pelo atraso do

caminho crítico do ciclo (operações em ciclos com maior tempo de execução devem ter maior

prioridade). Neste mecanismo, existe um árbitro por cada porto de cada memória acedido por

mais do que uma região cíclica concorrente.

Exemplo 7 -3 . Execução concorrente de regiões cícl icas.

Considere-se o filtro Kalman, cujas características se encontram ilustradas

no apêndice D. O GALADRIEL fornece para o nível de topo do HPDG o

grafo representado na Figura 7.11a. Pelo HPDG pode ver-se que os nós

“loop.1” e “loop.4” representativos respectivamente dos dois primeiros

ciclos do exemplo podem ter execução concorrente. Quando os arrays X e

Y são mapeados em memórias distintas (MEM0 e MEM1 da Figura 7.11b)

o funcionamento concorrente pode ser realizado pela execução concorrente

de duas FSMs como indicado no diagrama de blocos da Figura 7.11b. Para

tal é apenas necessário que a ambas seja comunicado o início de execução

pela FSM anterior e que a execução da FSM posterior entre em execução

quando as duas FSMs concorrentes terminarem. Quando os arrays X e Y

são mapeados na mesma memória (MEM0 da Figura 7.11c) o

funcionamento concorrente pode ser realizado pela execução concorrente

de duas FSMs em que os acessos de cada sub-STG são arbitrados como

indicado no diagrama de blocos da Figura 7.11c. Neste caso cada sub-STG

tem um estado de espera até que lhe seja dada permissão para aceder ao

recurso partilhado.

9 Em [Ouaiss00] é apresentado um esquema de arbitragem baseado no round-robin que parece ser mais propício para acessos a recursos partilhados no contexto de aplicações multitarefas.

CAP. 7 ESCALONAMENTO BASEADO EM REGIÕES 179

0

start

end

loop.1

3 6

loop.4

loop.7

loop.13

18

12

STG0

STG1 STG2

STG3

a) b )

MEM1 MEM0

STG0

STG1 STG2

STG3

c)

ÁRBITRO

MEM0

Figura 7 .11 . a ) Níve l de topo do HPDG para o exemplo Kalman (os nós

“ loop.#” encapsulam o resto da hierarquia e as regiões def inidas por

c ic los estão representadas por t raços) ; Diagramas de blocos que

representam as FSMs responsáveis pe la execução da unidade de dados

do exemplo: b) quando não há part i lha de recursos entre os c ic los

“ loop.1” e “ loop.4”; c) quando há part i lha de recursos entre os ciclos

“loop.1” e “ loop.4”.

180 CAP. 7 ESCALONAMENTO BASEADO EM REGIÕES

7.5 Melhorias de Desempenho do HPDG sobre o CDFG

No início do capítulo foram descritas as vantagens do HPDG que justificaram a opção pela

utilização deste modelo hierárquico em vez de um modelo hierárquico obtido directamente do

CFG original. Nesta secção comparam-se escalonamentos partindo de cada um destes dois

modelos. Para tal são apresentados resultados para vários exemplos.

Para medir o grau de paralelismo foram utilizadas as medidas do número máximo de

operações em execução num ciclo de relógio (estado do STG) e a soma do número de

operações em execução por cada ciclo de relógio a dividir pelo número total de ciclos de

relógio.

As Figura 7.12 e Figura 7.13 apresentam os resultados destas duas medidas para os dois tipos

de grafos (CDFG e HPDG) para exemplos com grande densidade de construções

condicionais (if-then-else). Na Figura 7.13 pode ver-se que em alguns casos o número

máximo de operações em execução num estado é muito maior no HPDG do que no CDFG.

Intuitivamente, se o número de operações em paralelo aumenta, diminui o número de estados

e consequentemente aumenta a densidade de operações em execução por ciclo de relógio

como se pode verificar pela Figura 7.12. No que respeita ao número máximo de operações

em execução num estado, no exemplo USQRT são conseguidos, com a utilização do HPDG

versus a do CDFG, aumentos de 12 para 54 e no INTERSECT de 5 para 65. Para os outros

exemplos os aumentos foram menos significativos mas não deixam de ser importantes.

0

5

10

15

20

25

SQRT

USQRT

CRC-32

QRS

HAMM

ING

MASKBIT

SCCW

INTERSECT

CDFG

HPDG

Figura 7 .12 . Densidade de operações por c ic lo de re lógio para dois

modelos de representação (exemplos com grande densidade de

construções condicionais: if-then-else).

CAP. 7 ESCALONAMENTO BASEADO EM REGIÕES 181

0

10

20

30

40

50

60

70

SQRT

USQRT

CRC-32

QRS

HAMM

ING

MASKBIT

SCCW

INTERSECT

CDFG

HPDG

Figura 7 .13 . Número máximo de operações por estado do STG para dois

modelos de representação (exemplos com grande densidade de

construções condic ionais: if-then-else).

A Figura 7.14 apresenta a efectividade do escalonamento no desempenho a partir do HPDG

face ao CDFG. Pode ver-se que para 3 dos exemplos (CRC-32, QRS e INTERSECT) o

número de ciclos de relógio obtido com a utilização do HPDG é cerca de 10% do obtido com

a utilização do CDFG. Para todos os exemplos o número de ciclos de relógio obtido com a

utilização do HPDG é inferior a 70% do obtido com a utilização do CDFG.

0%10%20%30%40%50%60%70%80%90%

100%

SQRT

USQRT

CRC-32

QRS

HAMM

ING

MASKBIT

SCCW

INTERSECT

CDFG

HPDG

Figura 7 .14 . Desempenhos dos escalonamentos fe i tos sobre o HPDG e

sobre o CDFG – va lores normal izados ao CDFG (exemplos com grande

densidade de construções condicionais: if-then-else).

As Figura 7.15 e Figura 7.16 mostram os resultados das duas medidas para os dois tipos de

grafos (CDFG e HPDG) para exemplos com utilização elevada de arrays, considerando uma

182 CAP. 7 ESCALONAMENTO BASEADO EM REGIÕES

memória de porto único acoplada ao FPGA. Estes exemplos têm pouca densidade de

construções condicionais e, daí, a diminuição nas melhorias dos escalonamentos realizados

sobre os dois tipos de grafos. No que respeita ao número máximo de operações em execução

num estado os aumentos mais significativos verificam-se nos exemplos BPIC2, aumento de

37 para 53, no BPIC3, de 120 para 134, e no SOBEL, de 10 para 16.

0

2

4

6

8

10

12

14

BPIC1 BPIC2 BPIC3 FPBI IDEA SOBEL KALMAN1

CDFG

HPDG

Figura 7 .15 . Densidade de operações por estado do STG para dois

modelos de representação, ut i l izando uma memór ia de por to único.

0102030405060708090

100110120130140

BPIC1 BPIC2 BPIC3 FPBI IDEA SOBEL KALMAN1

CDFG

HPDG

Figura 7 .16 . Número máximo de operações por estado do STG para dois

modelos de representação, ut i l izando uma memória de porto único.

A Figura 7.17 apresenta a efectividade do escalonamento no desempenho a partir do HPDG

face ao CDFG. Pode ver-se que para o exemplo BPIC1 não existe melhoria, para o

KALMAN1 o número de ciclos de relógio obtido com o HPDG é 90% face ao do CDFG e

para todos os outros exemplos o número de ciclos de relógio obtido com a utilização do

HPDG é inferior a 70% do obtido com o CDFG.

CAP. 7 ESCALONAMENTO BASEADO EM REGIÕES 183

0%

20%

40%

60%

80%

100%

BPIC1 BPIC2 BPIC3 FPBI IDEA SOBEL KALMAN1

CDFG

HPDG

Figura 7 .17 . Desempenhos dos escalonamentos fe i tos sobre o HPDG e

sobre o CDFG, ut i l izando uma memória de porto único (valores

normal izados ao CDFG).

Os resultados apresentados nesta secção mostram em geral melhorias significativas do

escalonamento com o HPDG face ao escalonamento com o CDFG. As melhorias aumentam

quando o algoritmo fonte tem um número elevado de construções condicionais e blocos

básicos sem dependências de dados (possibilita a execução paralela destes).

7.6 Conclusões

Neste capítulo foi demonstrada a exequibilidade da utilização do HPDG em conjunto com o

DFG global propostos no capítulo 3 como representações intermédias para compilação de

linguagens de alto-nível em hardware específico.

A forma como é feito o escalonamento por regiões foi ilustrada e comparada com

escalonamentos baseados no bloco básico. Foram apresentadas as vantagens de executar o

escalonamento sobre o HPDG face ao CDFG. O CDFG aqui considerado mantém a ordem de

blocos básicos do CFG e o escalonamento é realizado bloco básico a bloco básico com a

utilização do DFG global. Os resultados mostram as melhorias que se obtiveram com o

escalonamento sobre o HPDG em vez do CDFG. Estas melhorias são mais significativas

quando os exemplos são do tipo de fluxo de controlo intensivo. O escalonamento por regiões

permite fornecer arquitecturas sintonizadas com o paralelismo previamente exposto, permite

a execução especulativa de operações, a execução concorrente de regiões cíclicas e a

utilização real de fluxos de controlo múltiplos.

184 CAP. 7 ESCALONAMENTO BASEADO EM REGIÕES

O escalonamento é de resolução fina, possibilitando por isso, e sempre que possível, o

encadeamento de operações no mesmo ciclo.

O trabalho futuro deve ter em conta a técnica de folding de ciclos10 [Gajski92] e de

exploração do factor de desenrolamento de modo a permitir melhores desempenhos das

implementações finais.

O esquema de arbitragem de acessos a recursos partilhados por regiões cíclicas concorrentes

que sejam expostas pelas análises de dependências deverá ser avaliado em implementações

futuras. Deverá ser estudado se a adição de arbitragem permite obter melhores desempenhos

do que a simples execução destas regiões sequencialmente.

O escalonador implementado não distingue ramos mutuamente exclusivos. Os

melhoramentos devem ter em conta caminhos de saída de ramos mutuamente exclusivos

considerando a execução especulativa de operações sem efeitos colaterais.

Sob o ponto de vista de melhoramento de desempenho, uma optimização possível é a criação

de caminhos de saída de unidades funcionais com base na pré-detecção de zeros nos

operandos de entrada. Por exemplo, a detecção de zeros nos 16 bits mais significativos dos

dois operandos de entrada de um multiplicador de 32 bits permitiria que o resultado estivesse,

sob o ponto de vista do escalonamento, disponível mais cedo quando os operandos de entrada

obedecessem a esse critério (utilizaria o atraso máximo para realizar uma multiplicação de 16

bits em vez do referente a uma multiplicação de 32 bits).

10 Nome atribuído pela comunidade de síntese arquitectural. Normalmente designada pela comunidade de compiladores de software por software pipelining ou mais correctamente por loop pipelining [Muchnick97].

185

8. Protótipos e Resultados Experimentais

“Few things are harder to put up with than a good example.”

Mark Twain

Conforme referido, foram implementados dois compiladores protótipo (GALADRIEL e

NENYA) que permitiram validar a metodologia e as análises propostas. Neste capítulo,

começa-se por descrever os aspectos de suporte no desenvolvimento dos dois compiladores e

ainda as limitações dos mesmos. De seguida, e de modo a consubstanciar a validação da

metodologia, são apresentados resultados da compilação de exemplos mais complexos. Os

exemplos permitiram a compilação directa do código original sem ser necessário alterar os

algoritmos de maneira a que estes fossem suportados pelos compiladores. Pretendeu-se, para

além de mostrar as características dos elementos compilados para uma arquitectura específica

face à execução dos mesmos em software, apresentar resultados da aplicação de diversas

optimizações e da utilização de várias memórias acopladas ao FPGA usufruindo de

barramentos distintos. Nos exemplos apresentados todas as variáveis do tipo array são

consideradas indivisíveis, havendo mapeamento em várias memórias de forma a melhorar o

desempenho sempre que existam recursos. Alguns resultados consideram o caso teórico

extremo de utilização de memórias com número de portos suficientemente elevado de forma

a que não haja competição pelos recursos de acesso à memória para cada aplicação (permite

avaliar a degradação do desempenho resultante da seriação dos acessos à mesma memória).

Estes resultados permitiram avaliar as optimizações sem inibição do paralelismo exposto.

186 CAP. 8 PROTÓTOTIPOS E RESULTADOS EXPERIMENTAIS

As características dos exemplos considerados neste capítulo encontram-se detalhadas no

apêndice D. Os exemplos foram escolhidos de modo a serem abrangidas várias áreas

computacionais. São considerados, entre outros, exemplos de processamento de imagem

(Sobel e FPBI), de criptografia (IDEA) e codificação (DCT). As dimensões dos exemplos

vão desde 10 até 400 linhas de código Java. O conjunto inclui exemplos com 7 ciclos e 6

variáveis do tipo array. O maior dos DFG globais gerados pelo GALADRIEL para os

exemplos considerados tem 1.558 nós.

Os tempos de execução do software apresentados foram medidos numa Sun SPARC 10,

com 196MB de RAM, sob o sistema operativo Solaris 2.5.

8.1 Compiladores GALADRIEL & NENYA

As duas ferramentas foram desenvolvidas inteiramente com a linguagem Java, utilizando

alguns dos APIs1 fornecidos pela tecnologia Java [Gosling96] e alguns pacotes em Java

disponíveis publicamente. Foram utilizados durante o desenvolvimento os seguintes pacotes:

o gerador de analisadores léxicos e sintácticos JavaCC [JavaCCURL], o gerador de bytecodes

Jas [JasURL] e o carregador de ficheiros de classes Java [Mcma96URL].

Foram desenvolvidas aproximadamente 30.000 linhas de código em Java (incluindo os

comentários) distribuídas por 131 classes. A utilização da tecnologia Java no

desenvolvimento dos compiladores revelou-se bastante eficaz corroborando o aumento de

produtividade na programação utilizando esta tecnologia defendido por muitos utilizadores.

A ferramenta DOTTY [DottyURL] desempenhou um papel fundamental na visualização dos

grafos apresentados e na depuração da geração dos mesmos. Por opção, o compilador pode

gerar ficheiros com a representação dos grafos no formato aceite pelo DOTTY.

O pacote em Java de visualização gráfica GOOGU [GooguURL] ajudou na depuração dos

escalonamentos gerados pelo NENYA por inspecção dos gráficos de Gantt. Do mesmo modo

o compilador pode gerar os ficheiros que representam o escalonamento para serem lidos pelo

GOOGU.

1 Do inglês: Application Programmer´s Interface.

CAP. 8 PROTÓTOTIPOS E RESULTADOS EXPERIMENTAIS 187

Para prototipagem de exemplos foram utilizadas as classes em Java para comunicação com a

placa de desenvolvimento HOT da VCC fornecidas pelo fabricante [VCCURL].

Embora o compilador de anteguarda, GALADRIEL, não inclua a exposição de paralelismo a

todos os níveis (utiliza análises conservativas) não apresenta restrições à linguagem Java. O

compilador NENYA aceita presentemente os tipos de dados, as operações sobre esses dados e

as construções de controlo apresentados na Tabela 1.2. Algumas das restrições serão

certamente consideradas em trabalhos futuros e outras, por incluírem construções demasiado

complexas para serem implementadas em FPGA, necessitam de investigações prévias. Para

as operações de divisão (“/”) e do resto da divisão (“%”) não existe ainda suporte de

macrocélulas na biblioteca desenvolvida.

Quando o utilizador não tem macrocélulas para um dado FPGA pode ser utilizada uma

ferramenta de síntese lógica (que suporte o dispositivo e aceite descrições em VHDL) no

processo de geração do circuito da unidade de dados. Neste caso, são utilizadas as descrições

em VHDL comportamental de cada uma das macrocélulas. Contudo, para exemplos que

necessitem de unidade de controlo o utilizador tem de caracterizar, em termos de área e de

atraso, as macrocélulas com base nos resultados obtidos pela ferramenta de síntese lógica.

8.2 Estudos Experimentais

A utilização da reassociação de operações (THR) levanta algumas questões: Qual o impacto

desta optimização em exemplos reais? Será que a utilização de THR quando o paralelismo

exposto não é correspondido/satisfeito produz sempre melhores resultados? Outras dúvidas

estão relacionadas com a utilização do desenrolamento de ciclos e de várias memórias.

Pretende-se, por isso, nesta secção, avaliar quantitativamente o impacto das optimizações e a

degradação do desempenho resultante dos acessos a uma memória terem de ser seriados em

exemplos reais.

Os resultados apresentados nesta secção reportam valores obtidos pelo escalonamento sem

serem considerados os efeitos da colocação e do encaminhamento (P&R) no FPGA alvo

(família XC6200).

A Figura 8.1 apresenta os resultados obtidos para o exemplo KALMAN original

(KALMAN1) explorando o número de memórias acopladas ao FPGA. O exemplo utiliza 6

188 CAP. 8 PROTÓTOTIPOS E RESULTADOS EXPERIMENTAIS

variáveis do tipo array. Na figura é apresentado o melhor escalonamento para cada número

de memórias externas considerado. Os resultados foram obtidos pela exploração exaustiva do

mapeamento das variáveis do tipo array nas memórias acopladas ao FPGA realizando para

cada mapeamento o escalonamento. Devido ao espaço de exploração ser exponencial (MN,

em que M é o número de memórias e N o número de arrays, quando todas as memórias são

consideradas diferentes) esta solução é de aplicação restrita pelos elevados recursos

computacionais necessários. Como curiosidade, refira-se que a exploração exaustiva do

espaço de mapeamentos possíveis durou 31 minutos para o exemplo KALMAN1 e 12 horas

para o exemplo KALMAN2. Tempos de computação maiores são necessários para as outras

versões do exemplo KALMAN. O NENYA permite também o mapeamento manual que,

embora ajude em alguns casos, não é viável em exemplos complexos, por ser difícil ao

programador encontrar o melhor mapeamento. As formas de mapeamento sem necessidade

de escalonamento serão estudadas futuramente. Estas formas devem permitir encontrar

mapeamentos quasi-óptimos (no sentido de fornecerem os melhores desempenhos) sem a

necessidade de realizar o escalonamento e da procura exaustiva do espaço constituído pelos

mapeamentos possíveis.

0

20

40

60

80

100

120

140

1 2 3 4 5 6

#Memórias

Atr

aso

(u

s) KALMAN1

KALMAN2

KALMAN3

KALMAN4

Figura 8 .1 . Resul tados de escalonamentos para vár ias versões do

exemplo KALMAN (ut i l iza 6 var iáveis do t ipo array) considerando vár ias

memórias externas. Para cada conjunto de memórias externas

acopladas é representado o mapeamento que produz o melhor

desempenho.

CAP. 8 PROTÓTOTIPOS E RESULTADOS EXPERIMENTAIS 189

Pela Figura 8.1 pode verificar-se que para o algoritmo original o melhor escalonamento é

obtido com apenas 2 memórias, com 4 memórias para a versão KALMAN2, com 3 memórias

para a versão KALMAN3 e 5 memórias para KALMAN4. A figura indica que com

desenrolamento parcial e a utilização de várias memórias foi possível obter uma aceleração

de quase 7 sobre o escalonamento da versão original considerando apenas uma memória.

O desenrolamento de alguns ciclos realizado nas versões KALMAN2, KALMAN3 e

KALMAN4 aumentou o grau de paralelismo existente como se pode verificar pela Figura

8.2. A versão KALMAN3 permitiu reduzir o número de acessos a arrays o que se traduziu no

facto desta versão necessitar de menos uma memória do que o KALMAN2 para produzir o

mesmo escalonamento.

A Figura 8.3 mostra os rácios obtidos para os melhores e para os piores escalonamentos da

Figura 8.1 sobre o escalonamento considerando uma memória multiporto. A figura ilustra que

com o mapeamento óptimo dos arrays em várias memórias o paralelismo existente no

algoritmo sem utilização de THR é praticamente satisfeito como se pode ver pelas melhorias

pequenas obtidas sobre os melhores escalonamentos (segundo grupo de colunas na Figura

8.3). Com a utilização de THR pode ver-se que os melhores escalonamentos obtidos pela

utilização de várias memórias são mais modestos (último grupo de colunas na Figura 8.3),

pois os graus de paralelismo não são satisfeitos. Formas de conseguir satisfazer esse

paralelismo passam pela utilização de memórias com mais do que um porto e/ou pela partição

de cada array por mais do que uma memória.

05

101520253035404550

1 2 3 4

#Memórias

#Op

eraç

ões

KALMAN1

KALMAN2

KALMAN3

KALMAN4

Figura 8 .2 . Número de operações em execução num estado do STG para

o exemplo KALMAN considerando vár ios números de memór ias

acopladas ao FPGA.

190 CAP. 8 PROTÓTOTIPOS E RESULTADOS EXPERIMENTAIS

0,51,01,52,02,53,03,54,04,55,0

pior

/m

ultip

orto

s/T

HR

mel

hor/

mul

tipor

tos/

TH

R

pior

/m

ultip

orto

c/T

HR

mel

hor/

mul

tipor

toc/

TH

R

Ace

lera

ção

KALMAN1KALMAN2KALMAN3KALMAN4

Figura 8 .3 . Rácios dos melhores e dos p iores escalonamentos para as

vár ias versões sobre o escalonamento considerando uma memór ia de

portos múlt iplos.

Na Figura 8.4 pode ver-se que a utilização de THR nas versões com potencial (KALMAN2,

3 e 4) pode fornecer escalonamentos melhores ou piores. Com a utilização de apenas uma

memória o resultado do escalonamento para as versões KALMAN2 e 3 utilizando THR foi

melhorado. Para várias memórias os resultados da aplicação de THR foram todos piores.

Contudo, no caso hipotético de utilização de uma memória de portos múltiplos (sem inibição

do paralelismo potenciado pela utilização de THR) a aplicação de THR produz melhorias

significativas.

0

20

40

60

80

100

120

140

KALMAN1 KALMAN2 KALMAN3 KALMAN4

atra

so (

us)

s/ THR (1 Mem)

THR (1 Mem)

s/ THR (6 Mem)

THR (6 Mem)

s/ THR (multiporto)

c/ THR (multiporto)

Figura 8 .4 . Efe i tos da ut i l ização de THR com uma de um porto ou de

por tos múl t ip los ou vár ias memórias para o exemplo KALMAN.

CAP. 8 PROTÓTOTIPOS E RESULTADOS EXPERIMENTAIS 191

A Figura 8.5 ilustra a degradação do desempenho resultante da seriação dos acessos a uma

memória de apenas um único porto face à utilização de uma memória multiporto hipotética.

A utilização de uma memória hipotética de portos múltiplos serve para indicar o desempenho

máximo que se poderia obter com a utilização de várias memórias acopladas ao FPGA ou

com a utilização de uma memória com mais do que um porto. A figura ilustra um aumento da

degradação do desempenho quando se utiliza a técnica de desenrolamento de ciclos

(exemplos BPIC, FPBI e DCT).

80%

100%

120%

140%

160%

180%

200%

BPIC1 BPIC2 BPIC3 FPBI FPBI1 FPBI2 FPBI3 IDEA SOBEL DCT DCT1

Figura 8 .5 . Degradação do desempenho (va lores maiores do que 100%)

com uma memór ia de por to único versus uma memór ia mul t ipor to

(va lores normal izados aos desempenhos obt idos com memória

multiporto). Foi ut i l izado THR nos exemplos em que este permite

melhorar os resul tados do escalonamento.

As análises experimentais apresentadas servem para se ter uma ideia dos graus de paralelismo

expostos pela utilização do desenrolamento de ciclos. Embora na maioria dos casos o

paralelismo aumente, a seriação de acessos a memórias pode limitar as melhorias de

desempenho obtidas. Em alguns casos estas seriações restringem as próprias optimizações

sobre o fluxo de dados como é o caso de THR (em alguns casos a sua utilização piora o

desempenho final). São necessárias várias memórias acopladas ao FPGA com barramentos

distintos de forma a não defraudar as expectativas em exemplos com elevado número de

acessos à memória. Este facto torna -se ainda mais evidente quando a aplicação do

desenrolamento não permite reduzir o número total de acessos à memória.

192 CAP. 8 PROTÓTOTIPOS E RESULTADOS EXPERIMENTAIS

A utilização teórica de uma memória multiporto serve para mostrar o paralelismo realmente

exposto e indicia perdas que justificam esforços na investigação de técnicas de partição de

arrays por várias memórias. Como era intuitivo, em exemplos com grande número de acessos

ao mesmo array, e sem ser considerada a partição destes, a existência de uma memória com

mais do que um porto é em alguns casos mais benéfica do que a utilização de várias

memórias.

8.3 Prototipagem na Família de FPGAs XC6200

Foram efectuados protótipos de alguns exemplos, para validar os compiladores apresentados,

na placa de desenvolvimento [Nisbet97] ligada ao barramento PCI2 de um computador

pessoal (PC) com sistema operativo Windows98. O FPGA utilizado foi o XC6216

[Xilinx97]. Foram implementados vários exemplos para validação dos compiladores. A título

de exemplo são apresentados os resultados obtidos da compilação do exemplo HAMMING

descrito no apêndice D.

8.3.1 Descodificador de Hamming

O exemplo HAMMING depois de compilado para os bytecodes Java tem 121 instruções JVM

agrupadas pelo GALADRIEL em 6 blocos básicos. A Figura 8.6 ilustra o DFG global do

exemplo gerado pelo GALADRIEL. Na figura, os laços estão rotulados com o número de bits

suficiente obtido pela análise de aferição do número de bits apresentada neste trabalho. A

Tabela 8.1 ilustra as macrocélulas utilizadas pelo NENYA na estrutura final do circuito. A

utilização da macrocélula CONST_op é apenas devida ao facto do programa Velab

[VelabURL] não suportar descrições em VHDL com atribuições de constantes a variáveis. O

circuito gerado pelo NENYA com estas constantes requer 321 células (ver linha NENYA da

Tabela 8.2). A Figura 8.7a apresenta o CFG do exemplo HAMMING e a Figura 8.7b

apresenta a implantação física (layout) do circuito num FPGA XC6216 com identificação da

área do circuito ocupada por cada bloco básico do CFG.

2 Do inglês: Peripheral Controller Interface.

CAP. 8 PROTÓTOTIPOS E RESULTADOS EXPERIMENTAIS 193

A Tabela 8.2 compara os resultados obtidos por compilação do exemplo com o NENYA com

as soluções obtidas com a ferramenta de síntese arquitectural, CADDY-II [CaddyURL], e

com a ferramenta de síntese lógica (SL), Design Compiler [Synopsys95].

end

start

&

0

>>

&

>>

&

>>

&

>>

&

>>

&

>>

1

^

2

^

3

^

^

4

^

8 16

3 4

32

5

64

6

2

1

4

2 &

1

^ ^

^ ^

<<

1

|

<<

1

|

5

EQ

1

EQ

2

EQ EQ

4 3

MUX

&

15

^

1

^

2

^

4

^

8 [4] [u000]

[1] [u]

[1] [u]

[1] [u]

[1] [u]

[1] [u]

[1] [u]

[1] [u]

[1] [u]

[1] [u]

[1] [u]

[8] [uuuuuuuu]

[1] [u]

[1] [u]

[2] [u0]

[3] [uu0]

[3] [uuu]

[4] [uuuu]

[4] [uuuu]

[4] [uuuu]

[4] [uuuu]

[4] [uuuu]

[4] [uuuu]

[4] [uuuu]

Figura 8 .6 . DFG do exemplo HAMMING gerado pe lo NENYA. Os rótu los

nos laços indicam o número de bi ts suf ic iente e os padrões de

constantes (ambos determinados pelo NENYA).

194 CAP. 8 PROTÓTOTIPOS E RESULTADOS EXPERIMENTAIS

Tabela 8 .1 . Macrocélulas ut i l izadas pelo NENYA para implementar o

descodi f icador de Hamming.

Macrocélula Descrição Quantidade AND_op AND lógico 8 CONST_op Constante 16 OR_op OR lógico 2 XOR_op XOR lógico 13 SHR_c_op Deslocamento lógico para a direita 6 SHL_c_op Deslocamento lógico para a esquerda 2 MUX_5_1 Multiplexador de 5 entradas 1 EQ_op Comparador de igualdade 4

Tabela 8 .2 . Resultados do reconfigware para o descodif icador de

HAMMING. (♠♠ sem os at rasos provocados pelo encaminhamento; ♣♣

est imat iva fe i ta pela ferramenta XACTstep; REC: tempo de

conf iguração, com base no PCI de 32bi ts @33MHz) .

atraso (ns) Ferramenta Área (células) ♠ ♣

Pares endereço/dados

X × Y células REC (µs)

NENYA 75 32 76 181 11×7 5,48 SL 41 19,6 52 127 7×8 3,85

CADDY 1.080 - - - - -

2

5

start

0

3

end

CFG

41

BB0

BB5

BB4

BB3

BB2 BB1 REG IN

REG OUT

a) b)

Figura 8 .7 . Exemplo HAMMING: a) Grafo de f luxo de controlo (CFG); b)

implantação f ís ica no FPGA XC6216 .

O circuito obtido pela ferramenta de síntese arquitectural não foi prototipado no FPGA

devido à impossibilidade de o fazer em tempo útil. O circuito tem uma estrutura irregular e as

CAP. 8 PROTÓTOTIPOS E RESULTADOS EXPERIMENTAIS 195

fases de colocação têm de ser feitas manualmente. O circuito requer 1.080 células de lógica

(ver linha CADDY na Tabela 8.2), facto que ilustra as deficiências da síntese arquitectural.

Este circuito utiliza vários multiplexadores e registos. O resultado não considera a aplanação

da estrutura RTL e subsequente síntese lógica. A área obtida pelo NENYA é inferior à obtida

pela ferramenta de síntese arquitectural devido à habilidade do NENYA de tirar partido da

especialização das macrocélulas parametrizáveis em vez da utilização de componentes

genéricos e das análises de extracção do número de bits e de propagação de constantes ao

nível do bit. A ferramenta de síntese arquitectural produz sempre uma unidade de controlo

mesmo que esta não seja necessária (nos casos em que o software garante o controlo, por

exemplo).

O circuito gerado por aplicação de síntese lógica tem 41 células de área e 52 ns de atraso (ver

linha SL na Tabela 8.2). Embora a síntese lógica possa ser aplicada a este exemplo, não o

pode ser em exemplos de grande complexidade por ser demasiadamente ineficiente gerar a

estrutura do circuito ao nível booleano (portas lógicas ou diagramas de decisão binários).

Ainda mais, quando o algoritmo fonte inclui acessos a memória e ciclos, a síntese lógica pura

não é apropriada e nem mesmo factível. Os resultados obtidos pela utilização de síntese

lógica são apresentados apenas como referências quasi-óptimas.

Na Tabela 8.2 estão ilustrados os atrasos fornecidos por cada uma das ferramentas e os

atrasos fornecidos pela ferramenta de colocação e encaminhamento [Xact97] após colocação

e encaminhamento do circuito no FPGA. As diferenças nos atrasos devem-se ao peso do

encaminhamento no atraso do caminho crítico que, nestes exemplos, chega a atingir

aproximadamente 70% do atraso global.

Todos os tempos de computação foram medidos da descrição fonte até à geração da estrutura

do circuito no formato EDIF [Stanford90]. O tempo de compilação do exemplo pelo

GALADRIEL+NENYA foi menor do que 4s (dos bytecodes do exemplo até à geração dos

ficheiros VHDL que descrevem a estrutura do circuito) e o tempo total de compilação

(GALADRIEL+NENYA seguido do VELAB) de cerca de 10s (execuções feitas numa Sun

SPARC 10 com o GALADRIEL+NENYA executado por um compilador do tipo JIT). Este

exemplo mostra uma redução substancial no tempo de compilação do

GALADRIEL+NENYA (10s) em relação à síntese arquitectural (> 8m) e à síntese lógica

(54s).

196 CAP. 8 PROTÓTOTIPOS E RESULTADOS EXPERIMENTAIS

Sem optimizações o NENYA gerou um circuito com 321 células (ver 1 na Tabela 8.3). Com

utilização da expansão de constantes e de deslocamentos obteve-se, por compilação com o

NENYA, 201 células (ver 2 na Tabela 8.3). Na compilação concretizada pelo NENYA as

operações de deslocamento por uma constante são promovidas a fios. Quando operações

AND, OR, XOR e EQ lidam com um operando de entrada constante podem também ser

implementadas por fios. Com esta transformação a área do circuito gerado pelo NENYA

passa de 201 para 178 células (ver 2 e 3 na Tabela 8.3). A aplicação da propagação de

constantes ao nível do bit forneceu área de 75 células (ver 4 e 5 na Tabela 8.3), muito mais

próxima da área resultante da aplicação de síntese lógica (41 células).

Tabela 8 .3 . Resul tados da compi lação do exemplo HAMMING ut i l i zando

vár ias opt imizações.

Abordagem SL GALADRIEL+NENYA 1 2 3 4 5

Tempo de compilação 54s 10s 10s 10s 10s 10s Área (células) 41 321 201 178 75 75 Rectângulo no FPGA (X×Y) 7×8 24×32 19×19 - 11×8 - Pares de endereçamento/dados 127 946 514 - 181 - Atraso estimado antes do P&R (ns) 19,6 50 50 46 32 26 Atraso estimado após o P&R (ns) 52 160 150 - 76 -

Propagação de constants ao nível do bit - 4 4 THR (reassociação de operações) - 4 4 Macrocélulas - 4 4 4 4 4 Macrocélulas especializadas - 4 4 4 4 Aferição do número de bits suficiente - 4 4 4 4

8.3.2 Problemas com a Integração das Fases de Retaguarda

A inexistência de estimativas dos atrasos do encaminhamento, durante as fases de

escalonamento, requer que no circuito prototipado a frequência de relógio seja diminuída até

que seja garantido o funcionamento do mesmo. Em alguns casos é necessário refinar a

unidade de controlo para se obterem soluções melhores.

A unidade de controlo centralizada requer muitas vezes a utilização de interligações longas

com maiores atrasos, facto que limita a frequência de relógio máxima. Problemas devidos aos

escassos recursos de encaminhamento da família de FPGAs XC6000 e ao estado embrionário

do software de colocação e encaminhamento, XACTstep [Xact97], tornam as etapas de

colocação e encaminhamento morosas e semimanuais.

CAP. 8 PROTÓTOTIPOS E RESULTADOS EXPERIMENTAIS 197

Nos circuitos de controlo e em ligações irregulares entre as macrocélulas da unidade de

dados, as etapas de colocação e encaminhamento são dificílimas e requerem intervenção do

utilizador.

A frequência de relógio dos exemplos é também limitada pela impossibilidade da ferramenta

XACTstep realizar colocação e encaminhamento com directivas de atraso.

8.4 Prototipagem na Família de FPGAs Virtex

Devido às limitações da família de FPGAs XC6000 e da respectiva ferramenta de colocação e

encaminhamento os exemplos mais complexos foram prototipados na família de FPGAs

Virtex [VirtexURL]. Por não se terem ainda macrocélulas para esta família de FPGAs é

utilizada síntese lógica (ferramenta Synplify [Synplicity99]) para implementar a unidade de

dados gerada pelo NENYA, em que para cada operador em vez da utilização dos geradores

de circuitos é utilizada a descrição VHDL-comportamental respectiva [Cardoso99d].

Antes da compilação é necessário descrever as macrocélulas para o FPGA alvo. A descrição

utilizada para a família Virtex de FPGAs baseou-se na síntese de cada componente variando

o número de bits dos operandos de entrada e após a colocação e o encaminhamento. São por

isso estimativas bastante próximas do circuito prototipado. Na descrição da biblioteca foram

apenas consideradas implementações das macrocélulas com área mínima.

A síntese lógica, elaborada pelo Synplify, e a colocação e encaminhamento, executada pela

ferramenta Alliance da Xilinx [Alliance98], foram realizadas sem restrições de desempenho e

com directiva de área mínima.

As experiências foram conduzidas sem intervenção do utilizador desde a compilação do

GALADRIEL+NENYA até à geração dos bitstreams. Foi seleccionada uma frequência de

relógio de 33MHz durante a compilação com o NENYA. Em todos os exemplos, os circuitos

finais foram testados com a frequência anterior. Os resultados foram validados por simulação

do VHDL representativo do reconfigware com a informação fornecida após colocação e

encaminhamento.

A Tabela 8.4 mostra os resultados da compilação: número de linhas de VHDL geradas pelo

NENYA, número máximo de operações em execução num estado, percentagem de recursos

198 CAP. 8 PROTÓTOTIPOS E RESULTADOS EXPERIMENTAIS

utilizados no FPGA, número de slices3 do FPGA, número de flip-flops (FFs) do circuito final,

tempo de CPU gasto pelo GALADRIEL + NENYA, e o tempo de execução da solução

reconfigware. Os circuitos obtidos têm tamanhos de 3.148 a 86.006 portas equivalentes

(eqG). O número máximo de operações em execução num estado vai desde 8 a 54. Os

resultados para o exemplo FPBI1 consideram imagens de 16×16 pixéis.

Por omissão, os resultados apresentados consideram apenas uma memória de porto único

acoplada ao FPGA.

Para os exemplos, o tempo de CPU gasto na SL foi entre 1 a 23 minutos4, e na colocação e

encaminhamento entre 5 a 100 minutos. A fase de SL pode ser parcialmente eliminada e a

geração da unidade de dados pode ser realizada em segundos com a utilização de geradores

de circuitos. Esperamos também que o tempo de CPU gasto na colocação e encaminhamento

possa ser substancialmente reduzido com a utilização de macrocélulas com pré-colocação

relativa.

Tabela 8 .4 . Resul tados da compi lação para reconfigware. Todos os

exemplos foram protót ipados num FPGA Vir tex XCV300-4, excepto o

exemplo DCT2 que fo i protót ipado num XCV400-4 .

Exemplo

# Linhas VHDL (caminho de dados)

# Linhas de VHDL (unidade de controlo)

Número Máximo Ops./ Estado

% FPGA #Slices #eqG

# FFs

GALADRIEL+ NENYA tempo de CPU (s)

Tempo de execução do Reconfigware

DCT 1.877 742 8 22 681 13.586 267 14,1 264,7µs DCT1 2.452 1.029 27 86 2.650 58.532 644 16,6 165,8µs DCT2 4.710 417 44 79 3.798 86.006 340 16,3 16,1µs IDEA 1.963 410 19 43 1.323 30.277 372 10,1 6,3µs FPBI1 492 203 10 12 374 7.608 216 9,7 113,4µs USQRT 1.430 91 54 5 166 3.148 24 9,6 696,9ns

As Figura 8.8 e Figura 8.9 mostram, respectivamente, o efeito de cada optimização do fluxo

de dados realizada pelo NENYA no escalonamento e na área do circuito, considerando

3 Cada Slice na família Virtex é constituído por dois LUTs e cada CLB por dois Slices. 4 O tempo de computação da colocação e encaminhamento refere o tempo de CPU até à geração dos bitstreams.

CAP. 8 PROTÓTOTIPOS E RESULTADOS EXPERIMENTAIS 199

apenas uma memória de porto único acoplada ao FPGA. As optimizações consideradas são:

reassociação de operações (THR), redução do custo de operações (OSR), inferência do

número de bits e propagação de bits constantes (ANB+PBC). Os valores apresentados são

normalizados aos resultados obtidos sem utilização das optimizações. Os resultados mostram

que as optimizações OSR e ANB+PBC têm um maior impacto na redução da área do que no

desempenho. A utilização de THR no FPBI1 e no DCT2 prejudica o desempenho devido à

seriação dos acessos à memória que restringe o grau de ILP exposto.

0%

10%

20%

30%

40%

50%

60%

70%

80%

90%

100%

110%

USQRT FPBI1 IDEA DCT DCT1 DCT2

s/ opt

c/ THR

c/ OSR

c/ ANB+PBC

melhor

Figura 8 .8 . Efect iv idade das opt imizações do f luxo de dados no

desempenho do reconfigware.

0%

10%

20%

30%

40%

50%

60%

70%

80%

90%

100%

USQRT FPBI1 IDEA DCT DCT1 DCT2

s/ opt

c/ THR

c/ OSR

c/ ANB+PBC

melhor

Figura 8 .9 . Efect iv idade das opt imizações do f luxo de dados na área de

reconfigware.

200 CAP. 8 PROTÓTOTIPOS E RESULTADOS EXPERIMENTAIS

A Figura 8.10 mostra as acelerações obtidas pela execução do reconfigware versus a

execução do software, utilizando o compilador JIT integrado no pacote Java2 SDK

[J2SDKURL]. Na figura, (1) representa o caso em que são utilizadas várias memórias de

porto único, e (2) o caso de uma memória de acessos múltiplos ao mesmo tempo (máximo de

14 leituras para o DCT1 e 7 leituras para o DCT2). Os resultados para o DCT1(2) e DCT2(2)

mostram a efectividade da utilização de THR quando os acessos a memórias não necessitam

de partilhar o interface. A utilização apenas teórica de uma memória de portos múltiplos é

considerado apenas para mostrar o quanto a partilha do interface com a memória pode limitar

o grau de ILP previamente exposto. Neste caso o DCT2(2) com a utilização de THR tem um

máximo de 256 operações em execução no mesmo estado, em vez das 42 da implementação

apresentada na Tabela 8.4.

1435

10

3651

1930

310

25 3994 132

598 676

1

10

100

1000

10000

USQRT

FPBI1

IDEA

DCTDCT1

DCT2

DCT(1)

DCT1(1)

DCT1(2)

DCT1(2)

THR

DCT2(2)

DCT2(2)

THRA

cele

raçã

o (

JIT

/Rec

on

fig

war

e)

Figura 8 .10 . Acelerações do reconfigware versus software.

Estes resultados podem ainda ser melhorados de várias formas: direccionando a SL e a

colocação e encaminhamento, sintonizando a frequência de relógio de acordo com o

escalonamento realizado pelo NENYA, procurando experimentalmente a frequência de

relógio máxima de funcionamento do circuito, ou utilizando macrocélulas com atrasos

menores.

8.5 Conclusões

Embora os tempos de execução do GALADRIEL+NENYA sejam reduzidos, importa realçar

que o desenvolvimento do software dos compiladores foi sempre orientado para a robustez,

CAP. 8 PROTÓTOTIPOS E RESULTADOS EXPERIMENTAIS 201

facilidade de adicionar funcionalidades, facilidade de leitura, teste, e nunca

predominantemente de desempenho. São por isso previsíveis melhorias de desempenho por

simples reescrita de partes do código. Um dos exemplos que corrobora esta afirmação é a

utilização de várias passagens de análises independentes que poderiam ser englobadas em

uma única passagem.

Foram apresentados resultados para um conjunto de exemplos que ilustram as capacidades

dos compiladores desenvolvidos. Vários estudos foram apresentados, variando o número de

memórias, com desenrolamento de ciclos, que permitiram ilustrar os níveis de paralelismo

extraídos.

O desenrolamento de ciclos, por enquanto realizado manualmente, permitiu estudar melhor o

efeito de algumas das optimizações, pois na maioria das vezes aumenta o potencial de

paralelismo e do efeito das optimizações de código. Contudo, a utilização de desenrolamento

nos casos em que este potencia o aumento do paralelismo não produz só por si melhorias

significativas. Este facto é mais notório quando se utiliza apenas uma memória com um único

porto que inibe o paralelismo existente ao necessitar que os acessos sejam seriados

independentemente de serem acessos a arrays distintos. A análise conservadora de

dependências relacionadas com os acessos a arrays também inibe muitas das vezes o

potencial real que pode existir ao desenrolar-se um ciclo quando em presença de memórias

com mais do que um porto. É por isso necessário integrar análises que resolvam a extracção

do paralelismo ao nível dos acessos a elementos de cada array. Estas análises são de

importância fundamental quando se consideram memórias com mais do que um porto ou

quando cada array pode ser partido em fracções e estas mapeadas em memórias distintas.

De futuro será integrado o desenrolamento automático de ciclos, parcial e global. O folding

de ciclos será também integrado e espera-se poder avaliar as optimizações em conjunto com

esta técnica.

A aplicação de transformações (desenrolamento de ciclos, redução de acessos à memória)

potencia aumentos da aceleração com favorecimento da versão reconfigware sobre o

software devido à natureza mais especializada e concorrente do reconfigware.

A utilização de THR deve ser sempre considerada quando o potencial de paralelismo é

satisfeito completamente. Caso contrário, a utilização desta optimização deve ser avaliada

pelo utilizador pois o DFG obtido pode originar escalonamentos com pior desempenho.

202 CAP. 8 PROTÓTOTIPOS E RESULTADOS EXPERIMENTAIS

Para os exemplos considerados, a utilização de redução do custo de operações produziu

sempre resultados satisfatórios, mesmo considerando o facto de que as adições e subtracções

utilizam circuitos com área mínima.

Como se pode constatar pelos resultados apresentados a utilização das análises de aferição do

número de bits e de propagação de constantes ao nível do bit produz quase sempre melhorias

significativas.

O reconfigware para a família Virtex de FPGAs foi obtido automaticamente. Este facto

indica claramente que foi plenamente atingido um dos principais objectivos deste trabalho: o

de propiciar a utilização de reconfigware por utilizadores sem conhecimentos de projecto de

hardware.

203

9. Conclusões

«”It is good to be back in the world of light and warmth,”

said Galadriel, and Isildur thought that never before had her

many years shown so clearly on her face.»

Cirdan, The Gray Havens - Songs & Tales

Neste capítulo são sumariados os objectivos cumpridos pelo trabalho realizado, apresentadas

algumas conclusões, e sugeridos trabalhos futuros que podem contribuir para melhorar os

compiladores descritos e para desenvolver o estado da arte em compilação para hardware

reconfigurável.

9.1 Trabalho Realizado

Esta tese apresenta um caminho dos bytecodes do Java até hardware reconfigurável suportado

eficientemente por ferramentas computacionais (compiladores). Os compiladores permitem a

criação de arquitecturas específicas e eficientes para serem implementadas em FPGAs. As

arquitecturas geradas permitem explorar o paralelismo massivo possível de exposição a partir

de uma descrição sequencial de um algoritmo.

É uma abordagem genérica que permite que qualquer algoritmo (desde que obedeça ao

subconjunto da linguagem actualmente aceite) possa ser compilado e executado num FPGA

sem que o utilizador tenha conhecimentos de projecto de hardware.

204 CAP. 9 CONCLUSÕES

Devido à complexidade computacional1 da maioria dos problemas existentes na compilação

de descrições alto-nível em hardware específico (vulgo síntese arquitectural), torna-se

necessário dividir as fases de compilação em etapas permitindo que cada uma delas seja

resolvida com algoritmos baseados em heurísticas. O fluxo de compilação foi, por isso,

dividido em fases procurando sempre atingir resultados globais eficientes.

Globalmente, as contribuições desta tese são:

• Fornecer um caminho automático de algoritmos descritos em Java até à sua

implementação num FPGA;

• Permitir a compilação rápida e específica para FPGAs com uma ou mais memórias do

tipo SRAM acopladas;

• Exposição automática de graus de paralelismo elevados e representação explícita

desse mesmo paralelismo;

• Exposição automática dos vários fluxos de controlo que possam existir e

representação explícita dos mesmos;

• Escalonamento das operações e dos ciclos sempre ao nível das operações quer seja

quando se trata de um bloco básico ou de múltiplos blocos básicos com ou sem

dependências entre eles;

• Possibilidade de execução especulativa de todas as operações exceptuando operações

de escrita em memória;

• Partição temporal baseada numa nova reformulação do algoritmo de escalonamento

baseado em lista;

• Apresentação de alguns estudos que permitem aquilatar de possíveis melhoramentos e

da efectividade das análises propostas;

Por todos os pontos supraenunciados consideramos que os objectivos propostos foram

amplamente atingidos. A dissertação e os compiladores nela apresentados provam a

1 Acredita-se que o conjunto das tarefas (algumas delas já provadas serem NP-completas, como são os casos do escalonamento e da alocação) forme um problema global NP-difícil.

CAP. 9 CONCLUSÕES 205

exequibilidade, efectividade e eficiência do fluxo de compilação proposto. A compilação é

realizada em tempos de computação aceitáveis (dezenas de segundos em exemplos bastante

complexos). Os resultados obtidos da compilação de exemplos reais complexos

consubstanciam a metodologia e as análises de optimização apresentadas. Os resultados

confrontados com resultados quasi-óptimos comprovam a eficiência das técnicas de

compilação propostas.

As técnicas desenvolvidas representam um passo importante para que qualquer programador

(e não apenas os projectistas de hardware) possa utilizar eficientemente os recursos de

hardware reconfigurável que eventualmente estejam disponíveis no sistema computacional

utilizado.

No entanto, muito trabalho poderá ser adicionado de forma a potenciar ainda mais os

compiladores desenvolvidos. Por isso, de seguida são apresentadas ideias e descritos alguns

pontos de investigação que poderão ser considerados num futuro próximo.

9.2 Perspectivas de Trabalho Futuro

Existem possibilidades variadas de trabalho futuro nesta área. São descritas aqui as que se

julgam mais relevantes e com maiores possibilidades de serem consideradas proximamente.

Estruturas de Representação Intermédia

A utilização do formato de atribuição única (SSA2) está em consideração. As análises de

construção deste formato permitirão diminuir o tamanho dos pontos de selecção em alguns

exemplos.

Inferências do Número de Bits nos Operandos

A comparação das análises propostas nesta tese para aferição do número de bits de cada

operando com as propostas recentemente em [Stephen00] e a possibilidade de combinação de

ambas deve ser considerada.

Optimizações de Ciclos

2 Do ingles: Static Single Assignment.

206 CAP. 9 CONCLUSÕES

Duas das técnicas com possibilidade de fornecerem resultados melhores ao nível do tempo de

execução da implementação em hardware reconfigurável lidam com a existência de ciclos

nos algoritmos fonte. Estas técnicas referem-se à utilização de software pipelining (folding de

ciclos) e de desenrolamento de ciclos.

A primeira permitirá a obtenção de implementações mais rápidas sem adicionar muito mais

área ao circuito final.

A integração de desenrolamento parcial ou total de ciclos permitirá, na maioria dos casos, o

aumento do grau de paralelismo, embora com aumento da área do circuito final que necessita

de, por isso, ser considerado. Esta técnica deve ser integrada com a partição temporal de

forma a que a exploração do factor de desenrolamento possa ser automaticamente utilizada

para fornecer implementações de ciclos que possam caber na área confinada a cada fracção

temporal.

A integração de técnicas que lidem com as optimizações anteriores foram propostas no

projecto AXEL [AxelURL] financiado pelo programa PRAXIS XXI e encontram-se em fase

de investigação.

A utilização de desenrolamento de ciclos parcial de modo a potenciar a aplicação de SWAR3

em acessos a memórias deve ser também considerada, pois permitirá, em alguns casos,

diminuir o número de acessos a memórias.

Partição Temporal

Algoritmos de partição temporal que permitam considerar os tempos de reconfiguração, a

partilha de algumas unidades e o intercalamento entre execução e reconfiguração devem

constituir um foco de novas investigações e desenvolvimentos. O intercalamento entre a

execução de uma fracção temporal e a reconfiguração da próxima fracção temporal a

executar pode permitir a obtenção de fraccionamentos temporais mais eficientes. Contudo

esta característica torna a tarefa de partição temporal mais complicada, pois para além desta

ser capaz de fornecer um fraccionamento eficiente também tem de considerar que cada

fracção deve ocupar um determinado espaço variável de forma a minimizar o tempo de

execução global. Um algoritmo baseado em heurísticas foi recentemente apresentado em

3 Do inglês: SIMD (Single Instruction, Multiple Data) Within A Register.

CAP. 9 CONCLUSÕES 207

[Ganesan00] que realiza a partição temporal considerando a divisão do FPGA em duas partes

de igual área (uma para reconfiguração, a outra para execução). Embora a divisão utilizada

possa produzir intercalamentos de reconfiguração e execução ineficientes o trabalho

supracitado é um bom ponto de partida.

Partilha de Unidades Funcionais

Deveriam ser consideradas técnicas que permitam explorar rapidamente a partilha de algumas

unidades funcionais (multiplicadores, por exemplo). É conveniente que uma nova abordagem

não assente na maioria das abordagens da síntese arquitectural para ASICs. Nestas últimas, o

utilizador escolhe o número de unidades funcionais para cada operador, ou a ferramenta

explora o espaço de projecto exaustivamente, ou com técnicas de supressão (prunning) de

buscas. Estas abordagens são demasiado complexas, só se justificando para implementações

em ASICs e não para compilação normal, em que o programador espera resultados o mais

rapidamente possível.

Escalonamento

A possibilidade do escalonamento utilizar unidades funcionais com mais do que um atraso

para término de computação deve ser considerada. Algumas unidades funcionais podem

terminar a computação antes do atraso máximo, com base na identificação de bits mais

significativos de nível lógico zero nos operandos de entrada. Este tipo de término foi

utilizado no âmbito de microprocessadores [Brooks99].

O escalonamento deve também ser estendido de modo a permitir a execução concorrente de

ciclos presentes lado-a-lado (mesmo nível) no HPDG. O principal problema reside no facto

dos ciclos concorrentes poderem aceder à mesma memória no mesmo instante. Uma das

formas de resolver o problema é a utilização do mecanismo de arbitragem baseado em

prioridades estáticas que foi apresentado no capítulo 7.

É também importante que sejam considerados acessos a memórias do tipo DRAM. O trabalho

apresentado em [Panda97] é um bom ponto de partida.

Integração de Colocação

208 CAP. 9 CONCLUSÕES

Espera-se que se possa num futuro próximo incluir na compilação fases de colocação com

base na geometria de cada macrocélula. Algum do trabalho apresentado em

[Callahan98b][Budiu99] pode servir como ponto de partida, embora nestes casos os autores

usem uma granulosidade abaixo do nível da operação.

Algoritmos baseados em heurísticas necessitam de ser estudados e os resultados avaliados na

prototipagem para FPGAs comerciais. Espera-se que com a colocação a este nível se possa

reduzir substancialmente o tempo de CPU gasto nas fases de colocação e encaminhamento.

Partição de Arrays

As arquitecturas com memórias distribuídas necessitam, para que o compilador possa

fornecer reconfigware eficiente, que a partição de um array por mais de uma memória seja

realizada automaticamente. Uma panorâmica da partição de arrays por bancos de memória

utilizada pela comunidade de computação de alto-desempenho pode ser consultada em

[Gokhale92].

Mapeamento de Arrays em Memórias

A hierarquia de memórias disponível nos sistemas reconfiguráveis que utilizam os novos

FPGAs (Virtex, por exemplo) necessita que, ao nível da compilação, os arrays possam ser

mapeados automaticamente nos níveis de memória existentes.

No âmbito da síntese arquitectural, algumas formas de distribuição de variáveis do tipo array

pelas memórias disponíveis foram consideradas em [Schmit97][Ramachan94]. Em especial,

são apresentadas em [Schmit98] técnicas de agrupamento e de colocação de arrays em

memória de forma a minimizar as unidades de endereçamento. Estas técnicas permitem

economizar mais memória do que a colocação dos arrays em bancos de tamanho 2N.

Recentemente, algumas formas de resolver o problema começaram a ser exploradas no

âmbito de compiladores para computação reconfigurável. Em [Gokhale99] é utilizada uma

técnica baseada na estimativa do custo de um determinado mapeamento para selecção de

entre as várias possibilidades. Esta técnica não necessita que para cada mapeamento seja feito

o escalonamento. Contudo, é necessário quantificar as distâncias dos resultados a

mapeamentos óptimos ou pelo menos quasi-óptimos. Uma técnica conhecida por enumeração

implícita é utilizada para reduzir o espaço de exploração, reconhecidamente exponencial.

CAP. 9 CONCLUSÕES 209

Os trabalhos supracitados parecem ser bons pontos de partida para a investigação destes

problemas.

Melhorias na Exposição de Paralelismo

Devem ser consideradas análises que possam expor o paralelismo ao nível de acessos a

elementos do mesmo array. Este paralelismo pode ter bastante impacto quando as memórias

têm mais do que um porto.

Compilação para Reconfigware de Descrições Orientadas por Objectos

Algumas construções orientadas por objectos podem ser implementadas eficientemente por

aplicação de transformações como o desdobramento de objectos, aplanação da estrutura

hierárquica, alocação estática e implementação de despacho dinâmico de métodos. O trabalho

desenvolvido nas fases iniciais desta tese é um bom começo para a síntese arquitectural de

descrições de alto-nível orientadas por objectos (ver apêndice C).

Necessitam de ser realizados estudos que quantifiquem a viabilidade da resolução estática de

invocações de métodos e das referências em exemplos reais. É também necessário avaliar a

utilização de implementações em hardware específico que durante a execução resolvam as

propriedades dinâmicas. Estas últimas implementações podem ter praticabilidade devido à

dimensão dos novos FPGAs. A conjugação destas duas formas (resoluções estática e

dinâmica) é definitivamente a mais apropriada para implementações específicas de uma

aplicação e, por isso, devem ser estudadas técnicas de resolução estática de algumas

construções com propriedades dinâmicas sempre que tal for possível, e implementações de

unidades em hardware específico que resolvam dinamicamente essas construções.

A utilização de algumas técnicas de gestão de memória para lidar com alocação de dados em

especificações que utilizam estruturas de dados (listas ligadas, por exemplo), deveria ser

considerada [Jong95].

A síntese de hardware a partir de especificações orientadas por objectos tem tido atenções

recentes. Em [Radetzki00] pode ser encontrada uma descrição da panorâmica sobre algumas

das abordagens existentes e é apresentada uma metodologia que sintetiza cada objecto numa

unidade de dados e de controlo que implementa todos os serviços disponibilizados pelo

objecto em causa. A metodologia tem algumas restrições mas parece ser um bom ponto de

partida.

210 CAP. 9 CONCLUSÕES

Considerações sobre Bytecodes Actualmente não Suportados

Será evidentemente importante permitir o suporte de programas em Java que usem métodos.

A possibilidade da partilha da implementação em reconfigware de cada método em relação à

expansão do seu corpo deve também constar no processo de compilação para que o utilizador

possa avaliar várias implementações.

Geradores de Operadores Lógico-Aritméticos Universais

O estudo e desenvolvimento de geradores de circuitos para cada operador suportado na

compilação para reconfigware que permitam prototipar várias FPGAs deve ser realizado.

Estes geradores podem ser baseados em descrições estruturais de cada operador (em Java ou

VHDL) com base num conjunto primitivo de portas lógicas de, por exemplo, duas entradas.

Na anteguarda, uma tarefa de mapeamento no FPGA alvejado permitirá a geração da

estrutura com um formato, por exemplo EDIF, possível de ser lido pelas ferramentas de

colocação e encaminhamento proprietárias.

Geração dos Circuitos de Controlo

O desenvolvimento de métodos que possam sintetizar a unidade de controlo a partir do grafo

de transições de estados (STG) deve ser considerado para que os compiladores não

necessitem da intervenção de uma ferramenta de síntese lógica. Neste contexto deve ser

comparada a utilização de contadores/sequenciadores com a utilização de máquinas de estado

finitas com codificação do tipo One-Hot.

Desenvolvimento de Código

O autor espera que a avaliação e depuração dos compiladores continue para que estes possam

vir a ser utilizados pela comunidade científica interessada.

Por último, a realização de uma interface Web para que o compilador possa estar disponível

numa página Web para avaliação [CardosoURL] por parte de possíveis interessados é sob o

ponto de vista de desenvolvimento bastante aliciante.

Por último, espera-se que a infra-estrutura desenvolvida no âmbito desta tese possa ser

utilizada para investigação e ensino.

251

Referências

[Agarwal94] Lalit Agarwal, Mike Wazlowski, and Sumit Ghosh, “An Asynchronous

Approach to Efficient Execution of Programs on Adaptive Architectures Utilizing

FPGAs”, In Proc. of the 2nd IEEE Workshop on FPGAs for Custom Computing

Machines (FCCM’94), Napa Valley, CA, USA, April 10-13, 1994, Published by the

IEEE Computer Society Press, Duncan A. Buell and Kenneth L. Pocek, editors, Los

Alamitos, CA, USA, 1994, pp. 101-110.

[Ahmed74] N. Ahmed, T. Natarajan, and K.R. Rao, “Discrete cosine transform,” IEEE

Trans. On Computers, vol. C-23, pp. 90-93, Jan 1974.

[Aho86] A. V. Aho, R. Sethi, J. D. Ullman, Compilers: Principles, Techniques and

Tools, Addison-Wesley, Reading, Massachusetts, 1986.

[Alliance98] Xilinx, Inc., “Alliance M1.5.19,” 1998, San Jose, CA, USA.

[AlteraURL] Altera Inc., URL: http://www.altera.com.

[Amerson95] R. Amerson, R. J. Carter, W. B. Culbertson, P. Kuekes, G. Snider, “Teramac

- Configurable Custom Computing,” In Proc. of the IEEE Symposium on FPGAs for

Custom Computing Machines (FCCM’95), Napa Valley, CA, USA, April 19-21, 1995,

Published by the IEEE Computer Society Press, Peter Athanas and Kenneth L. Pocek,

editors, Los Alamitos, CA, USA, 1995, pp. 32-38.

[Arnold92] J. M. Arnold, et al., “The Splash 2,” In Proc. of the 4th Annual ACM

Symposium on Parallel Algorithms and Architectures, June 1992, pp. 316-324.

[Athanas92] Peter Mark Athanas, An Adaptive Machine Architecture and Compiler for

Dynamic Processor Reconfiguration, PhD Thesis, Brown University, 1992.

252 REFERÊNCIAS

[Athanas93] P. Athanas, and H. Silverman, “Processor Reconfiguration through

Instruction-Set Metamorphosis: Architecture and Compiler,” IEEE Computer, vol. 26,

n. 3, March 1993, pp. 11-18.

[August99] David I. August, et al., “The Program Decision Logic Approach to Predicated

Execution,” In Proc. of the (ISCA99), 1999.

[AxelURL] Projecto AXEL, “AXEL: Acceleration of Computationally Intensive

Algorithms Using Systems Based on Dynamic Reconfiguration,” INESC: ESDA Group,

URL: http://esda.inesc.pt/esda/Projects/axel/main.html. Projecto

PRAXIS/P/EEI/12154/1998.

[Baer68] J. L. Baer, and D. P. Bovet, “Compilation of Arithmetic Expressions for

Parallel Computations,” In Proc. of the IFIP Congress, 1968, pp. 34-46.

[Balance90] R. Balance, A. Maccabe, and K. Ottenstein, “The program dependence web: a

representation supporting control-, data-, and demand-driven interpretation of

imperative languages,” In Proc. of the SIGPLAN’90 Conference on Programming

Language Design and Implementation, June 1990, pp. 257-271.

[Banerjee00] P. Banerjee, et al., “A MATLAB Compiler For Distributed, Heterogeneous,

Reconfigurable Computing Systems,” In Proc. of the IEEE Symposium on Field-

Programmable Custom Computing Machines (FCCM’00), Napa Valley, CA, USA,

April 16-19, 2000, Published by the IEEE Computer Society Press, Kenneth L. Pocek

and Jeffrey Arnolds, editors, Los Alamitos, CA, USA, 2000.

[Becker98] J. Becker, R. Hartenstein, M. Herz, U. Nageldinger, “Parallelization in Co-

Compilation for Configurable Accelerators,” In Proc. of the Asia South Pacific Design

Automation Conference (ASP-DAC'98), Yokohama, Japan, February 10-13, 1998.

[Bellows98] P. Bellows, and B. Hutchings, “JHDL-An HDL for Reconfigurable Systems,”

In Proc. of the IEEE 6th Symposium on Field-Programmable Custom Computing

Machines (FCCM'98), Napa Valley, CA, USA, April 15-17, 1998, Published by the

IEEE Computer Society Press, Kenneth L. Pocek and Jeffrey Arnolds, editors, Los

Alamitos, CA, USA, 1998, pp. 175-184.

REFERÊNCIAS 253

[Ben92URL] ______, Benchmarks repository, Workshop on High-Level Synthesis, 1992,

1995, ftp://ftp.ics.uci.edu/pub/hlsynth/HLSynth92.

[Ben95URL] ______, Benchmarks repository, Workshop on High-Level Synthesis, 1995,

ftp://ftp.ics.uci.edu/pub/hlsynth/HLSynth95.

[Bernstein86] Robert Bernstein, “Multiplication by Integer Constants,” In Software Practice

and Experience, Vol. 16, No. 7, July, 1986, pp. 641-652.

[Bik97] Aart J.C. Bik, and Dennis B. Gannon, “javab - a prototype bytecode

parallelization tool”, Computer Science Department Technical Report, Indiana

University, USA, URL: http://www.extreme.indiana.edu/hpjava/, 1997, pp. 46.

[Bondala99a] Kiran Bondalapati, et al., “DEFACTO: A Design Environment for Adaptive

Computing Technology”, In Proc. of the 6th Reconfigurable Architectures Workshop

(RAW'99), San Juan, Puerto Rico, April 12, 1999, Published in Springer-Verlag,

Berlin,Germany, 1999.

[Bondala99b] Kiran Bondalapati, and Viktor K. Prasanna, “Dynamic Precision Management

for Loop Computations on Reconfigurable Architectures,” In Proc. of the IEEE 7th

Symposium on Field-Programmable Custom Computing Machines (FCCM'99), Napa

Valley, CA, USA, April 21-23, 1999, Published by the IEEE Computer Society Press,

Kenneth L. Pocek and Jeffrey Arnolds, editors, Los Alamitos, CA, USA, 1999, pp. 249-

258.

[Brent74] R. P. Brent, “The Parallel Evaluation of Generic Arithmetic Expressions,” In

Journal of the ACM, 21(2), 1974.

[Briggs94] Preston Briggs, Tim Harvey, “Multiplication by Integer Constants,” July 13,

1994. URL: http://softlib.rice.edu/MSCP

[Brooks99] David Brooks, and Margaret Martonosi. “Dynamically Exploiting Narrow

Width Operands to Improve Processor Power and Performance,” In Proc. of the Fifth

Intl. Symposium on High-Performance Computer Architecture, Orlando, Jan. 1999.

254 REFERÊNCIAS

[Brown96] Stephen Brown, and Jonathan Rose, “FPGA and CPLD Architectures: A

Tutorial,” IEEE Design & Test of Computers, Summer 1996, Vol. 13, No. 2, pp. 42-

57.

[Budimlic97] Zoran Budimlic and Ken Kennedy. “Optimizing Java - theory and practice”.

In Concurrency, Practice and Experience, 9(6):445-463, 1997.

[Budiu00] Mihai Budiu, Seth Copen Goldstein, Majd Sakr and Kip Walker, “BitValue

Inference: Detecting and Exploiting Narrow Bitwidth Computations,” In Proc. of the

European Conference on Parallel Computing (EuroPar’00), Munich, Germany, Aug.

2000.

[Budiu99] Mihai Budiu, and Seth Copen Goldstein, “Fast Compilation for Pipelined

Reconfigurable Fabrics,” In Proc. of the ACM/SIGDA 6th International Symposium on

Field Programmable Gate Arrays, Monterey, CA, USA, January, 1999.

[CaddyURL] CADDY-II, FZI, Karlsruhe, version 5.10. URL:

http://www.fzi.de/sim/people/ bringmann/caddy/caddy.html.

[Callahan00] Timothy J. Callahan, John Hauser, and John Wawrzynek, “The Garp

Architecture and C Compiler,” IEEE Computer, Vol.33, No. 4, April 2000, pp. 62-69.

[Callahan98a] Timothy J. Callahan and John Wawrzynek, “Instruction Level Parallelism for

Reconfigurable Computing,” In Proc. Of the 8th International Workshop on Field-

Programmable Logic and Applications (FPL'98), Tallinn, Estonia, August 31-

September 3, 1998. Published in Springer-Verlag LNCS 1482, Hartenstein and

Keevallik eds, Berlin, Germany, 1998, pp. 248-257.

[Callahan98b] Timothy J. Callahan, Philip Chong, Andri DeHon, and John Wawrzynek,

“Fast Module Mapping and Placement for Datapaths in FPGAs,” In Proc. of the 1998

ACM/SIGDA Sixth International Symposium on Field Programmable Gate Arrays

(FPGA'98), February 22-24, 1998, ACM Press, New York, USA, pp. 123-132.

[Cardoso98a] João M. P. Cardoso, and Horácio C. Neto, “An Approach to Hardware

Synthesis from a System Java(tm) Specification “, In Proc. of the 1st International

Workshop on Design, Test and Applications (WDTA’98), Sponsored by IEEE region 8

REFERÊNCIAS 255

and IEEE TTTC, ISBN 953-184-009-1, Dubrovnik, Croatia, June 8-10, 1998, pp. 149-

152.

[Cardoso98b] João M. P. Cardoso, and Horácio C. Neto, “Towards an Automatic Path from

Java(tm) Bytecodes to Hardware Through High-Level Synthesis”, In Proc. of the 5th

IEEE International Conference on Electronics, Circuits and Systems (ICECS-98),

Lisbon, Portugal, September 7-10, 1998, Vol. 1, pp. 85-88.

[Cardoso99a] João M. P. Cardoso, and Horácio C. Neto, “Macro-Based Hardware

Compilation of Java Bytecodes into a Dynamic Reconfigurable Computing System,”

In Proc. of the IEEE 7th Symposium on Field-Programmable Custom Computing

Machines (FCCM'99), Napa Valley, CA, USA, April 21-23, 1999, Published by the

IEEE Computer Society Press, Kenneth L. Pocek and Jeffrey Arnolds, editors, Los

Alamitos, CA, USA, 1999, pp. 2-11.

[Cardoso99b] João M. P. Cardoso, and Horácio C. Neto, “Fast Hardware Compilation of

Behaviors into an FPGA-Based Dynamic Reconfigurable Computing System,” In Proc.

of the XII Symposium on Integrated Circuits and Systems Design (SBCCI’99), (Co-

)Sponsored by the Brazilian Computer Society and the IFIP WG 10.5, Natal-RN, Brazil,

Sept. 29-Oct. 2, 1999, In Vladimir C. Alves, Marcelo Lubaszewski, and Ivan S. Silva

(Editors), IEEE Computer Society Press, Los Alamitos, CA, USA, pp. 150-153.

[Cardoso99c] João M. P. Cardoso, and Horácio C. Neto, “An Enhanced Static-List

Scheduling Algorithm for Temporal Partitioning onto RPUs,” In Proc. of the IFIP TC10

WG10.5 X International Conference on Very Large Scale Integration (VLSI'99),

Lisbon, December 1-3, 1999. VLSI: Systems on a Chip, Luis M. Silveira, Srinivas

Devadas and Ricardo Reis (Editors), Kluwer Academic Publishers, pp. 485-496.

[Cardoso99d] J. M. P. Cardoso, H. C. Neto, “The Library of macro-cells used by NENYA:

Circuit generators for the Xilinx XC6000 FPGA series,” INESC Technical Report,

December 1998, revised April 1999.

[Cardoso99e] João M. P. Cardoso, and Mário P. Véstias, “Architectures and Compilation

Techniques to Support the Reconfigurable Computing Concept”, In Crossroads, the

Association for Computing Machinery (ACM) Student Magazine, topic: Computer

256 REFERÊNCIAS

Architectures, Spring 1999, Issue 5.3, pp. 15-22. Version online at:

http://turing.acm.org/crossroads/xrds5-3/rcconcept.html.

[CardosoURL] João M. P. Cardoso, “The Galadriel & Nenya Home Page: A Compilation

Path from Java Programs to Reconfigurable Computing,” INESC, ESDA group, Lisbon,

Portugal. URL: http://esda.inesc.pt/~jmpc/GALNEN/GALNEN.html.

[Chang97] Douglas Chang, Malgorzata Marek-Sadowska, “Buffer Minimization and

Time-multiplexed I/O on Dynamically Reconfigurable FPGAs,” In Proc. 5th

ACM/SIGDA International Symposium on Field Programmable Gate Arrays

(FPGA'97), Monterey, CA, USA, 1997, pp. 142-148.

[Chang98] Douglas Chang, Malgorzata Marek-Sadowska, “Partitioning Sequential

Circuits on Dynamically Reconfigurable FPGAs,” In Proc. 6th ACM/SIGDA

International Symposium on Field Programmable Gate Arrays (FPGA'98), Monterey,

CA, USA, February 22-24, 1998.

[Chichkov97] A. V. Chichkov, C. B. Almeida, “An Hardware/Software Partitioning

Algorithm for Custom Computing Machines”, Published in Springer-Verlag Lecture

Notes in Computer Science 1304, W. Luk, P. Y. K. Cheung, and M. Glesner, Eds.

Berlin, Germany, 1997, pp.274-283.

[Chichkov98] A. V. Chichkov, Metodologia de Co-Projecto Hardware/Software Para

Arquitecturas Computacionais Reconfiguráveis Utilizando uma Partição Baseada no

Paralelismo Implícito, Dissertação para a obtenção do grau de doutor em Engenharia

Electrotécnica e de Computadores, Instituto Superior Técnico (IST) da Universidade

Técnica de Lisboa (UTL), Lisboa, Janeiro de 1998.

[Churcher95] Steven Churcher, Tom Kean, and Bill Wilkie, “XC6200 FastMap Processor

Interface,” In Proc. of the Int. Conference on Field-Programmable Logic and

Applications (FPL’95), Oxford, United Kingdom, Aug.-Sept., 1995. Published in

Springer-Verlag LNCS 975, Will Moore and Wayne Luk, eds., Berlin, Germany, 1995,

pp. 36-43.

[Cierniak97] Michal Cierniak and Wei Li. “Optimizing Java bytecodes,” In Concurrency,

Practice and Experience, 9(6):427-444, 1997.

REFERÊNCIAS 257

[CLevelURL] C Level Design, Inc., URL: http://www.cleveldesign.com.

[CompiURL] Compilogic Corporation, D. Soderman, Y. Panchul, “Implementating C

Designs in Hardware: ANSI C to RTL Verilog Design & Test-Bench Compiler,” March

1998. URL: http://www.compilogic.com/pubs.htm.

[Compton00] K. Compton, S. Hauck, “Configurable Computing: A Survey of Systems and

Software,” submitted to ACM Computing Surveys, 2000.

[Connor97] J. Michael O'Connor and Marc Tremblay, “picoJava-I: The Java Virtual

Machine in Hardware”, IEEE Micro, Vol. 17, No. 2, March-April 1997, pp.

[Cramer97] Timothy Cramer, et al., “Compiling Java Just in Time”, IEEE Micro,

May/June 1997, pp. 36-43.

[Cronquist98] D. C. Cronquist, P. Franklin, S. Berg, M. Ebeling, “Specifying and Compiling

Applications for RaPiD,” In Proc. of the IEEE Symposium on FPGAs for Custom

Computing Machines (FCCM’98), Napa Valley, CA, USA, April 15-17, 1998,

Published by the IEEE Computer Society Press, Kenneth L. Pocek and Jeffrey Arnolds,

editors, Los Alamitos, CA, USA, 1998, pp. 116-125.

[CynAppsURL] CynApps, Inc., URL: http://www.cynapps.com.

[Cytron91] Ron Cytron, et al., “Efficiently Computing static single assignment form and

the control dependence graph,” In ACM Transactions on Programming Languages and

Systems, 13(4), October 1991, pp. 451-490.

[DACURL] _____, Proc. of the IEEE/ACM Design Automation Conference. URL:

http://www.dac.com.

[DeHon96] A. DeHon, Reconfigurable Architectures for General Purpose Computing,

PhD Thesis, AI Technical Report 1586, Massachusetts Institute of Technology, 545

Technology Sq., Cambridge, MA02139, Sept. 1996, URL:

http://www.ai.mit.edu/people/andre/phd.html.

[Diniz00] Pedro Diniz, and Joonseok Park, “Automatic Synthesis of Data Storage and

Control Structures for FPGA-based Computing Engines,” In Proc. Of the IEEE

258 REFERÊNCIAS

Symposium on Field-Programmable Custom Computing Machines (FCCM’00), Napa

Valley, CA, USA, April 16-19, 2000, Published by the IEEE Computer Society Press,

Kenneth L. Pocek and Jeffrey Arnolds, editors, Los Alamitos, CA, USA, 2000.

[DottyURL] AT&T Inc., dotty: Graphviz, version 1.3, 1998. URL: http://

www.research.att.com/sw/tools/graphviz.

[Duncan98] A. A. Duncan, D. C. Hendry, and P. Gray, “An overview of the COBRA-

ABS high level synthesis system for multi-FPGA Systems,” In Proc. of the IEEE

Symposium on FPGAs for Custom Computing Machines (FCCM’98), Napa Valley, CA,

USA, April 15-17, 1998, Published by the IEEE Computer Society Press, Kenneth L.

Pocek and Jeffrey Arnolds, editors, Los Alamitos, CA, USA, 1998, pp. 106-115.

[Ebeling95] M. Ebeling, D. C. Cronquist, and P. Franklin, “RaPiD - Reconfigurable

Pipelined Datapath,” In Proc. of the International Workshop on Field Programmable

Logic and Applications (FPL'95), Oxford, United Kingdom, Aug.-Sept., 1995.

Published in Springer-Verlag LNCS 975, Will Moore and Wayne Luk, eds., Berlin,

Germany, 1995, pp. 126-135.

[Economist99] The Economist Scince and Technology: “Hardware goes soft,”

http://www.economist.com/editorial/freeforall/22-5-99/st9188.html, 22 May 1999.

[Eijndhov92] Jos T. J. van Eijndhoven and Leon Stok, “A Data Flow Graph Exchange

Standard,” In Proc. of the European Conference on Design Automation (EDAC’92),

Brussels, Belgium, March 1992, pp. 193-199.

[Ernst93] Rolf Ernst, J. Henkel, T. Benner, “HW-SW Cosynthesis for

Microcontrollers,” In IEEE Design & Test of Computers, Vol. 10, No. 4, December

1993, pp. 64-75.

[Estrin60] Gerald Estrin, “Organization of computer systems - the fixed plus variable

structure computer,” In Proceedings of the Western Joint Computer Conference, May

1960, pp. 33-40.

[EvolvURL] _____, Proc. of the SA/DoD Workshop on Evolvable Hardware, 13-15 July,

Silicon Valley, CA, USA . URL: http://ic-www.arc.nasa.gov/ic/eh2000/.

REFERÊNCIAS 259

[FCCMURL] _____, Proc. of the IEEE Symposium on Field-Programmable Custom

Computing Machines. 1993-2000. URL: http://www.fccm.org. Printed by IEEE

Computer Society Press, Los Alamitos, Calif., USA.

[FCMURL] Steve Guccione, “List of FPGA-based Computing Machines,” URL:

http://www.io.com/~guccione/HW_list.html.

[Fisher95] J. A. Fisher, and B. R. Rau, “Instruction-Level Parallel Processing,” In H. C.

Torng and S.Vassiliadis, editors, Instruction-Level Parallel Processors, IEEE Computer

Society Press, 1995, pp. 41-49.

[FPGA93-00] _____, Proc. of the ACM/SIGDA International Symposium on Field-

Programmable Gate Arrays (FPGA), 1993-2000.

[FPLURL] _____, Proc. of the International Workshop on Field-Programmable Logic

and Applications. 1991-2000. URL: http://xputers.informatik.uni-kl.de/FPL/index_fpl

.html. Printed by Springer-Verlag.

[FrontierURL] Frontier Design, Inc., URL: http://www.frontierd.com.

[Fujii99] T. Fujii, K.-i. Furuta, M. Motomura, M. Nomura, M. Mizuno, K.-i. Anjo, K.

Wakabayashi, Y. Hirota, Y.-e. Nakazawa, H. Ito, M. Yamashina, “A Dynamically

Reconfigurable Logic Engine with a Multi-Context/Multi-Mode Unified-Cell

Architecture,” In Proc. IEEE International Solid State Circuits Conference (ISSCC'99),

San Francisco, CA, Feb. 15-17, 1999. See NEC Corp., Kanagawa, Japan, URL:

http://www.nec.co.jp/english/today/newsrel/9902/1502.html.

[GajjalaPu98a] Karthikeya M. GajjalaPurna, and Dinesh Bhatia, “Emulating Large Designs on

Small Reconfigurable Hardware”, In Proc. 9th IEEE International Workshop on Rapid

System Prototyping (RSP '98), Leuven, Belgium, June 3 –5, 1998.

[GajjalaPu98b] Karthikeya M. GajjalaPurna, and Dinesh Bhatia, “Partitioning in Time: A

Paradigm for Reconfigurable Computing”, In Proc. IEEE Int. Conference on Computer

Design (ICCD'98), Austin, Texas, October 5-7, 1998, pp. 340-345.

260 REFERÊNCIAS

[GajjalaPu99] Karthikeya M. GajjalaPurna, and Dinesh Bhatia, “Temporal Partitioning and

Scheduling Data Flow Graphs for Reconfigurable Computers”, In IEEE Transactions on

Computers, vol. 48, no. 6, June 1999, pp. 579-591.

[Gajski92] D. Gajski, et al., High-Level Synthesis, Introduction to Chip and System

Design, Kluwer Academic Publishers, 1992.

[Galloway95] D. Galloway, “The Transmogrifier C Hardware Description Language and

Compiler for FPGAs”, In Proc. of the 3rd IEEE Workshop on FPGAs for Custom

Computing Machines (FCCM’95), Napa Valley, CA, USA, April 19-21, 1995,

Published by the IEEE Computer Society Press, Peter Athanas and Kenneth L. Pocek,

editors, Los Alamitos, CA, USA, 1995, pp. 136-144.

[Ganesan00] Satish Ganesan, and Ranga Vemuri, “An Integrated Temporal Partitioning

and Partial Reconfiguration Technique for Design Latency Improvement,” In Proc.

Design, Automation & Test in Europe (DATE'00), Paris, France, March 27-30, 2000,

pp. 320-325.

[gccURL] ______, GNU C Compiler, URL: http://www.gnu.org.

[Girczyc85] E. F. Girczyc, et al.: “Applicability of a Subset of Ada as an Algorithmic

Hardware Description Language for Graph-Based Hardware Compilation”, IEEE

Transactions on CAD, April 1985, pp. 134-142.

[Girkar92] M. Girkar, and C. D. Polychronopoulos, “Automatic Extraction of Functional

Parallelism from ordinary Programs,” In IEEE Transactions on Parallel and Distributed

Systems, Vol. 3,No. 2, March 1992, pp. 166-178.

[Gokhale90] Maya Gokhale, et al., “SPLASH: A Reconfigurable Linear Logic Array,” In

Proc. of the International Conference on Parallel Processing, Aug. 1990, pp. 526-532.

[Gokhale92] Maya Gokhale, and W. Carlson, “An Introduction to compilation issues for

parallel machines,” In The Journal of Supercomputing, December 1992, pp. 283-314.

[Gokhale95] Maya Gokhale and A. Marks, “Automatic Synthesis of Parallel Programs

Targeted to Dynamically Reconfigurable Logic Arrays,” In Proc. of the International

REFERÊNCIAS 261

Workshop on Field Programmable Logic and Applications (FPL'95), Oxford, United

Kingdom, Aug.-Sept., 1995. Published in Springer-Verlag LNCS 975, Will Moore and

Wayne Luk, eds., Berlin, Germany, 1995, pp. 399-408.

[Gokhale97] Maya Gokhale, and Edson Gomersall, “High-Level Compilation for Fine

Grained FPGAs,” In Proc. of the IEEE 5th Symposium on Field-Programmable Custom

Computing Machines (FCCM'97), Napa Valley, CA, USA, April 16-18, 1997,

Published by the IEEE Computer Society Press, Kenneth L. Pocek and Jeffrey Arnolds,

editors, Los Alamitos, CA, USA, 1997, pp. 165-173.

[Gokhale98] Maya Gokhale, and Janice M. Stone, “Napa C: Compiling for a Hybrid/FPGA

Architecture,” In Proc. of the IEEE 6th Symposium on Field-Programmable Custom

Computing Machines (FCCM'98), Napa Valley, CA, USA, April 15-17, 1998,

Published by the IEEE Computer Society Press, Kenneth L. Pocek and Jeffrey Arnolds,

editors, Los Alamitos, CA, USA, 1998, pp. 126-135.

[Gokhale99] Maya Gokhale and Janice M. Stone, “Automatic Allocation of Arrays to

Memories in FPGA Processors with Multiple Memory Banks,” In Proc. of the IEEE 7th

Symposium on Field-Programmable Custom Computing Machines (FCCM'99), Napa

Valley, CA, USA, April 21-23, 1999, Published by the IEEE Computer Society Press,

Kenneth L. Pocek and Jeffrey Arnolds, editors, Los Alamitos, CA, USA, 1999, pp. 63-

69.

[Goldstein00] Seth Copen Goldstein, Herman Schmit, Mihai Budiu, Srihari Cadambi, Matt

Moe, and Reed Taylor, “PipeRench: A Reconfigurable Architecture and Compiler,” In

IEEE Computer, Vol.33, No. 4, April 2000, pp. 70-77.

[Goldstein99] Seth Copen Goldstein, Herman Schmit, Matthew Moe, Mihai Budiu, Srihari

Cadambi, R. Reed Taylor, Ronald Laufer, “PipeRench: a Coprocessor for Streaming

Multimedia Acceleration,” In Proc. of the 26th Annual International Symposium on

Computer Architecture (ISCA'99), June 1999.

[GooguURL] Genetic Adaptive System Lab, GOOGU (Generic Object-Oriented Graphing

Utility), version 1.3.4, University of Nevada, Reno, USA, 1998. URL:

http://gaslab.cs.unr.edu/googu-demo/.

262 REFERÊNCIAS

[Gordon98] Rob Gordon, Essential JNI: Java Native Interface, Prentice Hall, Upper

Saddle River, NJ 07458, 1998.

[Gosling95] James Gosling, “Java Intermediate Bytecodes,” In Proc of the ACM

SIGPLAN Workshop on Intermediate Representations (IR'95), ACM SIGPLAN Notices

(March 1995).

[Gosling96] James Gosling, Bill Joy, and Guy Steele, The Java Language Specification,

Addison-Wesley, Reading, Massachusetts, 1996.

[Gosling97] Ken Arnold, James Gosling. Java Programming Language. Addison-Wesley,

Reading, Massachusetts, 1997.

[Gray89] J. Gray, and T. Kean, “Configurable hardware: A new paradigm for

computation,” Advanced Research in VLSI, In Proc. of the Decennial Caltech

Conference on VLSI, Pasadena, CA, 1989.

[Guccione00] Steve Guccione, Delon Levi and Prasanna Sundararajan, “Jbits: Java based

interface for reconfigurable computing,” In Proc. of the Military and Aerospace

Applications of Programmable Devices and Technologies Conference (MAPLD'00),

The Johns Hopkins Univerisity- Applied Physics Laboratory, Laurel, Maryland, USA,

September 26-28, 2000.

[Hammes99] J. Hammes, R. Rinker, W. Böhm, W. Najjar, B. Draper, R. Beveridge,

“Cameron: High Level Language Compilation for Reconfigurable Systems,” In Proc. of

the Int. Conference on Parallel Architectures and Compilation Techniques (PACT'99),

Newport Beach, CA, USA, Oct. 12-16, 1999.

[Hartenst90] R. W. Hartenstein, A. G. Hirschbiel, and M. Weber, “The Machine Paradigm

Of Xputers and its Application to Digital Signal Processing Acceleration,” In Proc. of

the International Conference on Parallel Processing, 1990.

[Hartenst95] R. W. Hartenstein and R. Kress, “A Datapath Synthesis System for the Re-

configurable Datapath Architecture,” In Proc. of the Asia and South Pacific Design

Automation Conference (ASP-DAC’95), 1995, pp. 479-484

REFERÊNCIAS 263

[Hartenst96a] R. W. Hartenstein, et al., “High-Performance Computing Using a

Reconfigurable Accelerator,” In CPE Journal, Special Issue of Concurrency: Practice

and Experience, John Wiley & Sons Ltd., 1996.

[Hartenst96b] Reiner W. Hartenstein, Jurgen Becker, Michael Herz, et al., “Co-Design and

High Performance Computing: Scenes and Crisis”, In Proc. of the Reconfigurable

Technology for Rapid Product Development & Computing, Part of SPIE's International

Symposium '96, Boston, USA, Nov. 1996.

[Hartenst98] R. W. Hartenstein, M. Herz, and F. Gilbert, “Designing for Xilinx XC6200

FPGAs,” In Proc. of 8th International Workshop on Field Programmable Logic and

Applications (FPL'98), Tallinn, Estonia, August 31-September 3, 1998. Published in

Springer-Verlag LNCS 1482, Hartenstein and Keevallik eds, Berlin, Germany, 1998, pp.

29-38.

[Hauck97] S. Hauck, T. W. Fry, M. M. Hosler, J. P. Kao, “The Chimaera Reconfigurable

Functional Unit”, In Proc. of the 5th IEEE Symposium on Field Programmable Custom

Computing Machines (FCCM'97), Napa Valley, CA, USA, April 16-18, 1997,

Published by the IEEE Computer Society Press, Kenneth L. Pocek and Jeffrey Arnolds,

editors, Los Alamitos, CA, USA, 1997, pp. 87-96.

[Hauck98] S. Hauck, “The Roles of FPGAs in Reprogrammable Systems,” In

Proceedings of the IEEE, Vol. 86, No. 4, pp. 615-638, April, 1998.

[Hauser97] J. R. Hauser, J. Wawrzynek, “Garp: A MIPS Processor with a Reconfigurable

Coprocessor”, In Proc. of the IEEE Symposium on FPGAs for Custom Computing

Machines (FCCM’97), Napa Valley, CA, USA, April 16-18, 1997, Published by the

IEEE Computer Society Press, Kenneth L. Pocek and Jeffrey Arnolds, editors, Los

Alamitos, CA, USA, 1997, pp. 12-21.

[Helaihel97] R. Helaihel, and K. Olukotun, “Java as a specification Language for

Hardware-Software Systems,” In Proc. of the ICCAD’97, San Jose, CA, USA,

November 9-13, 1997, pp. 690-697.

264 REFERÊNCIAS

[HICSS98] _____, Configware Minitrack in the Software Technology Track of the

Thirty-First Hawaii International Conference on System Sciences (HICSS-31), Hawaii,

Jan 1998.

[HPCA] _____, International Symposium on High-Performance Computer

Architecture, (HPCA'98) Las Vegas, Nevada USA, 31January - 4 February, 1998, IEEE

Computer Society.

[Hsieh97] C.-H. A. Hsieh et al., “Optimizing NET Compilers for Improved Java

Performance,” In IEEE computer, June 1997, pp. 67-76.

[Hudson98] R. D. Hudson, D. I. Lehn, and P. M. Athanas, “A Run-Time Reconfigurable

Engine for Image Interpolation”, In Proc. of the 6th IEEE Symposium on Field

Programmable Custom Computing Machines (FCCM'98), Napa Valley, CA, USA,

April 15-17, 1998, Published by the IEEE Computer Society Press, Kenneth L. Pocek

and Jeffrey Arnolds, editors, Los Alamitos, CA, USA, 1998, pp. 88-95.

[Hwu93] Wen-mei W. Hwu, et al.. “The SuperBlock: An Effective Technique for

VLIW and Superscalar Compilation,” In Journal of Supercomputing, Kluwer Academic

Publishers, 1993, pp. 229-248.

[IEEE99] The Institute of Electrical and Electronics Engineers, Inc., IEEE Standard

1076.1-1999 VHDL Language Reference Manual, IEEE, 1999.

[IMS93] IMS, 1.2 µm CMOS Gate Forest Static Cells, 15-Dec-93.

[Inoue98] Akihiko Inoue, et al., “Language and Compiler for Optimizing Datapath

Widths of Embedded Systems,” In IEICE Transactions Fundamentals, vol. E81-A, no.

12, December, 1998, pp. 2595-2604.

[Iseli93] Christian Iseli, and Eduardo Sanchez, “Spyder: A Reconfigurable VLIW

Processor using FPGAs,” In Proc. of the IEEE Workshop on FPGAs for Custom

Computing Machines (FCCM’93), Napa Valley, CA, USA, April 5-7, 1993, Published

by the IEEE Computer Society Press, Duncan A. Buell and Kenneth L. Pocek, editors,

Los Alamitos, CA, USA, 1993, pp. 17-24.

REFERÊNCIAS 265

[Iseli95] Christian Iseli, and Eduardo Sanchez, “A C++ compiler for FPGA custom

execution units synthesis,” In Proc. of the IEEE Symposium on FPGAs for Custom

Computing Machines (FCCM’95), Napa Valley, CA, USA, April 19-21, 1995,

Published by the IEEE Computer Society Press, Peter Athanas and Kenneth L. Pocek,

editors, Los Alamitos, CA, USA, 1995, pp. 173-179.

[J2SDKURL] Sun Microsystems, Inc., The Java Developer’s Kit, URL:

http://java.sun.com/j2se.

[Jain88] R. Jain, A. Parker, N. Park, “Module Selection for Pipelined Synthesis, “ In

Proc. 25th Design Automation Conference, 1988, pp. 542-547.

[JasURL] K. B. Sriram, Jas: Java bytecode assembler, version 0.4, 1997. URL:

http://www.sbktech.org/jas.html.

[JavaCCURL] Sun, Inc., JavaCC: Java Compiler Compiler, version 0.7.1, 1998, URL:

http://www.suntest.com/JavaCC/.

[JHDLURL] URL: http://www.jhdl.org

[Johnson83] S. C. Johnson, “Code Generation for Silicon,” In Proc. of the 10th Annual

ACM Symposium on Principles of Programming Languages, 1983, pp. 14-19.

[Jong95] G. de Jong, et al., “Background memory management for dynamic data

structure intensive processing systems”, In Proc. of the IEEE ICCAD’95, San Jose, CA,

USA, Nov. 1995, pp. 515-520.

[JVMLanURL] Robert Tolksdorf, Programming Languages for the Java Virtual Machine.

Since November 2, 1996. URL: http://grunge.cs.tu-berlin.de/~tolk/vmlanguages.html

[Kastrup00] Bernardo Kastrup, Jeroen Trum, Orlando Moreira, Jan Hoogerbrugge, and

Jef van Meerbergen, “Compiling Applications for ConCISe: An Example of Automatic

HW/SW Partitioning and Synthesis,” In Proc. of the 10th Int. Conference on Field-

Programmable Logic and Applications (FPL’00), Villach, Austria, August 27-30, 2000.

Published in Springer-Verlag Lecture Notes in Computer Science 1896, Reiner W.

Hartenstein and Herbert Grünbacher (Editors), Berlin, pp. 695-706.

266 REFERÊNCIAS

[Kastrup99] Bernardo Kastrup, Arjan Bink, and Jan Hoogerbrugge, “ConCISe: A

Compiler-Driven CPLD-Based Instruction Set Accelerator,” In Proc. of the IEEE 7th

Symposium on Field-Programmable Custom Computing Machines (FCCM'99), Napa

Valley, CA, USA, April 21-23, 1999, Published by the IEEE Computer Society Press,

Kenneth L. Pocek and Jeffrey Arnolds, editors, Los Alamitos, CA, USA, 1999, pp. 92-

101.

[Kaul98] M. Kaul, R. Vemuri, “Optimal Temporal Partitioning and Synthesis for

Reconfigurable Architectures,” In Proc. Design, Automation & Test in Europe

(DATE'98), Paris, France, Feb. 23-26, 1998, pp. 389-396.

[Kirkpatrick83] S. Kirkpatrick, C. Gelatt, Jr., and M. Vecchi, “Optimization by Simulated

Annealing,” In Science, Vol. 220, No. 4598, May 1983, pp. 671-680.

[Lakshmin99] G. Lakshminarayana, K. S. Khouri, and N. K. Jha, “Wavesched: A Novel

Scheduling Technique for Control-Flow Intensive Designs,” In IEEE Transactions on

Computer-Aided Design of Integrated Circuits and Systems, vol. 18, no. 5, May 1999,

pp. 505-523.

[Landwehr97] Birger Landwehr, and Peter Marwedel, “A New Optimization Technique for

Improving Resource Exploitation and Critical Path Minization,” In Proc. of the 10th

International Symposium on System Synthesis, 1997, pp. 65 – 72.

[LavaURL] LavaLogic, TSI TelSys, Inc., URL: http://www.lavalogic.com.

[Lechner97] Eric Lechner, and Steve Guccione, “The Java Environment for

Reconfigurable Computing,” In Proc. of the 7th International Workshop on Field-

Programmable Logic and Applications (FPL'97), London, United Kingdom, September

1997. Published in Springer-Verlag LNCS 1304, Wayne Luk and Peter Y. K. Cheung,

eds., Berlin, Germany, 1997, pp. 284-293.

[Lee00] Ming-Hau Lee, “Design and Implementation of the MorphoSys

Reconfigurable Computing Processor,” In Journal of VLSI and Signal Processing-

Systems for Signal, Image and Video Technology, March 2000.

REFERÊNCIAS 267

[Lewis98] D. Lewis, D. Galloway, M. van Ierssel, J. Rose, P. Chow, “The

Transmogrifier-2: A 1 Million Gate Rapid Prototyping System,” in IEEE Transactions

on VLSI, Vol. 6, No. 2, June 1998, pp 188-198.

[Lindholm96] Tim Lindholm and Frank Yellin. The Java Virtual Machine Specification.

Addison-Wesley, Reading, Massachusetts, 1996.

[Liu98] Huiqun Liu, and D. F. Wong, “Network flow based circuit partitioning for

time-multiplexed FPGAs,” In Proc. ACM/IEEE International Conference on Computer

Aided Design (ICCAD'98), San Jose, CA, November, 1998.

[Liu99] Huiqun Liu, and D. F. Wong, “Circuit partitioning for dynamically

reconfigurable FPGAs,” In Proc. International Symposium on Field Programmable

Gate Arrays (FPGA'99), Monterey, CA, Feb 21-23, 1999.

[Lobo91] Donald A. Lobo, and Barry M. Pangrle, “Redundant operator creation: a

scheduling optimization technique,” In Proc. of the 28th Conference on ACM/IEEE

Design Automation Conference (DAC'91), 1991, pp. 775 - 778.

[Long93] X.-P. Long, H. Amano, “WASMII: a Data Driven Computer on a Virtual

Hardware,” In Proc. 1st IEEE Workshop on FPGAs for Custom Computing Machines

(FCCM’93), Napa Valley, CA, USA, April 5-7, 1993, Published by the IEEE Computer

Society Press, Duncan A. Buell and Kenneth L. Pocek, editors, Los Alamitos, CA,

USA, 1993, pp. 33-42.

[Magenhei88] Daniel J. Magenheimer, Liz Peters, Karl W. Pettis, and Dan Zuras, “Integer

Multiplication and Division on the HP Precision Architecture,” In IEEE Transactions on

Computers, vol. 37, no. 8, August 1988, pp. 980-990.

[Mahlke92] Scott A. Mahlke, David C. Lin, William Y. Chen, Richard E. Hank, Roger A.

Bringmann, “Effective Compiler Support for Predicated Execution Using the

Hyperblock,” In Proc. of the 25th International Symposium on Microarchitecture, Dec.

1992, pp. 45-54.

268 REFERÊNCIAS

[MAPURL] _____, Proc. of the Military and Aerospace Applications of Programmable

Devices and Technologies Conference (MAPLD), 1998-2000. URL:

http://rk.gsfc.nasa.gov

[Master99] Paul Master, and Peter M. Athanas, “Reconfigurable Computing Offers

Options for 3G,” In Wireless Systems Design, January 1999, pp. 20-23.

[Mcma96URL] Chuck McManis, Class Loader Package, version 1.6, August 1995. See “The

basics of Java class loaders”, In JavaWorld, October 1996, URL:

http://www.javaworld.com/javaworld/jw-10-1996/jw-10-indepth.html.

[Mencer98] O. Mencer, M. Morf, and M. J. Flynn, “PAM-Blox: High Performance FPGA

Design for Adaptive Computing,” In Proc. of the IEEE 6th Symposium on Field-

Programmable Custom Computing Machines (FCCM'98), Napa Valley, CA, USA,

April 15-17, 1998, Published by the IEEE Computer Society Press, Kenneth L. Pocek

and Jeffrey Arnolds, editors, Los Alamitos, CA, USA, 1998, pp. 167-174.

[Micheli94] G. De Micheli, Synthesis and Optimization of Digital Circuits, McGraw Hill,

1994.

[Micheli97] G. De Micheli, R. K. Gupta, “Hardware/Software Co-Design,” In

Proceedings of the IEEE, vol. 85, no. 3, March 1997, pp. 349-365.

[Mirsky96] E. Mirsky, and A. DeHon, “MATRIX: A Reconfigurable Computing Device

with Configurable Instruction Deployable Resources,” In Proc. of the IEEE Symposium

on FPGAs for Custom Computing Machines (FCCM’96), Napa Valley, CA, USA, April

17-19, 1996, Published by the IEEE Computer Society Press, Kenneth L. Pocek and

Jeffrey Arnolds, editors, Los Alamitos, CA, USA, 1996, pp. 157-166.

[Miyamori98] T. Miyamori, and K. Olukotun, “A Quantitative Analysis of Reconfigurable

Coprocessors for Multimedia Applications,” In Proc. of the 6th IEEE Symposium on

Field Programmable Custom Computing Machines (FCCM'98), Napa Valley, CA,

USA, April 15-17, 1998, Published by the IEEE Computer Society Press, Kenneth L.

Pocek and Jeffrey Arnolds, editors, Los Alamitos, CA, USA, 1998, pp. 2-11.

REFERÊNCIAS 269

[Moisset99] Pablo Moisset, Joonseok Park and Pedro Diniz, “Very High-Level Synthesis

of Control and Datapath Structure for Reconfigurable Logic Devices,” In Proc. of the

Second Workshop on Compiler and Architecture Support for Embedded Systems

(CASES'99), Washington, DC, USA, Oct. 1999.

[Moll95] L. Moll, J. Vuillemin, P. Boucard, “High-Energy Physics on DECPeRLe-1

Programmable Active Memory,” In Proc. of the ACM/SIGDA International Symposium

on Field-Programmable Gate Arrays (FPGA’95), 1995, pp. 47-52.

[Morse94] Morse Rodriguez, “Evaluating Video Codecs,” In IEEE Multimedia, Fall

1994, pp. 25-33.

[Muchnick97] S. S. Muchnick. Advanced Compiler Design and Implementation. Morgan

Kaufmann Publishers, Inc., San Francisco, CA, USA, 1997.

[Muraoka71] Y. Muraoka, Parallelism Exposure and Exploitation in Programs, PhD

Thesis, University of Illinois, Urbana-Champagne, 1971.

[Natarajan99] S. Natarajan, B. Levine, C.Tan, D. Newport, D. Bouldin, “Automatic

Mapping of Khoros-based applications to adaptive computing systems,” In Proc. of the

Military and Aerospace Applications of Programmable Devices and Technologies

Conference (MAPLD'99), Laurel, MD, USA, Sept. 28-30, 1999, pp. 101-107.

[Nicolau91] Alexandru Nicolau, and Roni Potasmann, “Incremental tree height reduction

for high level synthesis,” In Proc. of the 28th Conference on ACM/IEEE Design

Automation Conference (DAC'91), 1991, pp. 770 - 774.

[Nisbet97] S. Nisbet, and S. A. Guccione, “The XC6200DS Development System,” In

Proc. of the 7th Int. Workshop on Field-Programmable Logic and Applications

(FPL'97), London, United Kingdom, September 1997. Published in Springer-Verlag

LNCS 1304, Wayne Luk and Peter Y. K. Cheung, eds., Berlin, Germany, 1997, pp. 61-

68.

[Ogawa99] Osamu Ogawa, et al., “Hardware Synthesis from C Programs with Estimation

of Bit Length of Variables,” In IEICE Transactions Fundamentals, vol. E82-A, no. 11,

November, 1999, pp. 2338-2346.

270 REFERÊNCIAS

[Oskin98] Mark Oskin, Frederic T. Chong, and Timothy Sherwood, “Active Pages: A

Model of Computation for Intelligent Memory,” In Proc. of the 25th Annual

International Symposium on Computer Architecture (ISCA98), Barcelona, Spain, pp.

192-203.

[Ouaiss00] Iyad Ouaiss, and Ranga Vemuri, “Efficient Resource Arbitration in

Reconfigurable Computing Environments,” In Proc. Design, Automation & Test in

Europe (DATE'00), Paris, France, March 27-30, 2000, pp. 560-566.

[Ouaiss98a] I. Ouaiss, et al., “An Integrated Partioning and Synthesis System for

Dynamically Reconfigurable Multi-FPGA Architectures,” In Proc. 5th Reconfigurable

Architectures Workshop (RAW'98), Orlando, Florida, USA, March 30, 1998, Published

in Springer-Verlag LNCS 1388, José Rolim, editor, Berlin,Germany, 1998, pp. 31-36.

[Ouaiss98b] Iyad Ouaiss, et al., “A Unified Specification Model of Concurrency and

Coordination for Synthesis from VHDL,” In Proc. of the International Conference on

Information Systems Analysis and Synthesis (ISAS’98), Orlando, Florida, July 12-16,

1998.

[PACT] _____, Proc. of the PACT'99 Workshop on Reconfigurable Computing

(WoRC'99), held in conjunction with PACT'99.

[Page91] Ian Page and Wayne Luk “Compiling occam into FPGAs,” In FPGAs, Will

Moore and Wayne Luk, editors, Abingdon EE&CS Books, Abingdon, England, UK,

1991, pp. 271-283.

[Page96] Ian Page, “Constructing Hardware-Software Systems from a Single

Description,” In Journal of VLSI Signal Processing, Dec. 1996, pp. 87-107.

[Panda97] Preeti Ranjan Panda, Nikil D. Dutt, Alexandru Nicolau, “Exploiting Off-Chip

Memory Access Modes in High-Level Synthesis,” In Proc. of the IEEE/ACM

International Conference on Computer Aided Design (ICCAD’97), Austin, October

1997.

REFERÊNCIAS 271

[Passerone98] C. Passerone, et al., “Modeling Reactive Systems in Java,” In Proc. of the 6th

IEEE/ACM Int. Workshop on HW/SW Co-Design, Seattle, Washington, USA, March

15-18, 1998.

[Paulin86] P. G. Paulin, J. P. Knight, and E. F. Girczyc, “HAL: A Multi-Paradigm

Approach to Automatic Data Path Synthesis, “ in Proc. 23rd Design Automation

Conference, June 29-July 2, 1986, 263-270.

[PCI95URL] PCI Special Interest Group, PCI Local Bus Specification – Revision 2.1, June

1995. URL: http://www.pcisig.com.

[PDTA] _____, The International Workshop: “Engineering of Reconfigurable

Hardware/Software Objects (ENREGLE),” http://www.cs.rdg.ac.uk/~tpp/enr.html,

International Conference on Parallel and Distributed Processing Techniques and

Applications (PDPTA), http://www.cps.udayton.edu/~pan/pdpta/.

[Postula98] Adam Postula, et al., “A Comparision of High Level Synthesis and Register

Transfer Level Design Techniques for Custom Computing Machines,” In Proc. of the 31

Hawaii Int. Conference on System Sciences (HICSS-31), January 1998, vol. VII, pp.

207-214.

[Radetzki00] von Martin Radetski, Synthesis of Digital Circuits from Object-Oriented

Specifications, IX, 252 S., Oldenburg, University, Ph.D. Thesis, 2000.

http://www.bis.uni-oldenburg.de/dissertation/2000/radsyn00/radsyn00.html

[Radunovic98] B. Radunovic, V. Milutinovic, “A Survey of Reconfigurable Computing

Architectures,” Tutorial in 8th Int. Workshop on Field Programmable Logic and

Applications (FPL'98), Tallinn, Estonia, August 31-September 3, 1998. Published in

Springer-Verlag LNCS 1482, Hartenstein and Keevallik eds, Berlin, Germany, 1998, pp.

376-385.

[Raimbault93] F. Raimbault, D. Lavenier, S. Rubini, and B. Pottier. “Fine grain parallelism

on an MIMD machine using FPGAs,” In D. Buell and K. Pocek, editors, Proceeding of

IEEE Workshop FPGAs for custom computing machines, volume 3890-02, Napa,

California, April 1993. IEEE Computer Society Press.

272 REFERÊNCIAS

[Ramachan94] L. Ramachandran, D. D. Gajski, and V. Chaiyakul, “An Algorithm for array

variable clustering,” in Proc. of the European Design Test Conference (EDAC’94),

1994.

[RAWURL] _____, Proceedings of the Reconfigurable Architectures Workshop (RAW).

Part of the International Parallel and Distributed Processing Symposium (IPDPS), 1994-

1999 (RAA 94-96). URL: http://xputers.informatik.uni-kl.de/RAW/index_raw.html.

[Razdan94a] Rahul Razdan, PRISC: Programmable Reduced Instruction Set Computers.

Ph.D. Thesis, Harvard University, Division of Applied Sciences, May 1994. (Harvard

University Technical Report 14-94, Center for Research in Computing Technology,

1994).

[Razdan94b] Rahul Razdan, K. Brace, and M. D. Smith, “PRISC Software Acceleration

Techniques”, In Proc. of the IEEE International Conference on Computer Design, Oct.

1994, pp. 145-149.

[Razdan94c] Rahul Razdan, and Michael D. Smith, “A High-Performance

Microarchitecture with Hardware-Programmable Functional Units,” In Proc. of the 27th

Annual IEEE/ACM Intl. Symposium on Microarchitecture (MICRO-27), IEEE

Computer Society Press, Los Alamitos, CA, USA, November 1994, pp. 172-180.

[Rinker00] R. Rinker, et al., “Compiling Image Processing Applications to

Reconfigurable Hardware,” In Proc. of the IEEE International Conference on

Application-Specific Systems, Architectures and Processors (ASAP’00), Boston,

Massachusetts, USA, July 10-12, 2000.

[Rupp98] C. Rupp, et al., “The NAPA Adaptive Processing Architecture,” In Proc. of

the IEEE 6th Symposium on Field-Programmable Custom Computing Machines

(FCCM'98), Napa Valley, CA, USA, April 15-17, 1998, Published by the IEEE

Computer Society Press, Kenneth L. Pocek and Jeffrey Arnolds, editors, Los Alamitos,

CA, USA, 1998, pp. 28-37.

[Scalera98] S. M. Scalera, J. R. Vázquez, “The Design and Implementation of a Context

Switching FPGA,” In Proceeding 6th IEEE Symposium on Field-Programmable Custom

Computing Machines (FCCM’98), Napa Valley, CA, USA, April 15-17, 1998,

REFERÊNCIAS 273

Published by the IEEE Computer Society Press, Kenneth L. Pocek and Jeffrey Arnolds,

editors, Los Alamitos, CA, USA, 1998, pp. 78-85.

[Schlansk00] M. S. Schlansker and B. Ramakrishna Rau, “EPIC: Explicity Parallel

Instruction Computing,” In IEEE Computer, Vol. 33, No. 2, February 2000, pp. 37-45.

[Schmit97] Herman Schmit, and Donald E. Thomas, “Synthesis of Applications-Specific

Memory Designs,” In IEEE Transactions on VLSI Systems, Vol. 5, No. 1, pp. 101-111

March, 1997.

[Schmit98] Herman Schmit, and Donald E. Thomas, “Address Generation for Memories

Containing Multiple Arrays,” In IEEE Transactions on CAD, vol.17, no.5, pp. 377-385,

May, 1998.

[Schneier96] Bruce Schneier, Applied Cryptography, John Wiley, New York, USA, 1996.

[Sedgewick92] Robert Sedgewick, Algorithms in C++, Addison-Wesley, Publishing

Company, Inc., 1992.

[Singh98] Hartej Singh, et al., “MorphoSys: An Integrated Re-configurable

Architecture,” In Proc. of the NATO RTO Symposium of System Concepts and

Integration, Monterey, CA, USA, April 1998.

[Smith97] W. H. Mangione-Smith, et al., “Seeking Solutions in Configurable

Computing,” In IEEE Computer, 30, 12 December 1997, pp. 38-43.

[SPIE] _____, International Society for Optical Engineering (SPIE) Photonics East

Conference, In John Schewel, editor, 1995-2000.

[Stanford90] P. Stanford, and P. Mancuso, eds., EDIF Electronic Design Interchange

Format Version 2 0 0. Electronic Industries Association, 2nd ed., 1990.

[StarBridURL] Star Bridge Systems, Inc., URL: http//www.starbridgesystems.com, Draper,

Utah, USA.

[Stephen00] Mark Stephenson, Jonathan Babb, and Saman Amarasinghe, “Bitwidth

Analysis with Application to Silicon Compilation,” In Proc. of the SIGPLAN Conference

274 REFERÊNCIAS

on Programming Language Design and Implementation (PLDI2000), Vancouver,

British Columbia, Canada, June 2000. See BitWise Project: URL:

http://www.cag.lcs.mit.edu/bitwise.

[SuperURL] Co-Design, Inc., URL: http://www.co-design.com/superlog.

[Synopsys95] Synopsys Inc., Design Compiler v3.3a, April 8, 1995.

[Synplicity99] Synplicity Inc., Synplify v5.2.2a, 1999.

[SystemCURL] The Open SystemC Initiative, URL: http://www.systemc.org.

[Tanaka89] Toshiaki Tanaka, Tsutomu Kobayashi, and Osamu Karatsu, “HARP: Fortran

to Silicon,” In IEEE Tansactions on Computer-Aided Design, vol. 8, no. 6, June 1989,

pp. 649-660.

[TimeLoURL] TimeLogic, Corp., URL: http//www.timelogic.com, Incline Village, Nevada,

USA.

[Trickey85] Howard Trickey, Compiling Pascal Programs into Silicon, Ph.D. Thesis,

Stanford University, USA, 1985.

[Trickey87] Howard Trickey, “Flamel: A High-Level Hardware Compiler,” In IEEE

Transactions on Computer-Aided Design, Vol 6, No 2, March 1987.

[Trimberger97] S. Trimberger, D. Carberry, A. Johnson, J. Wong, “A Time-Multiplexed

FPGA,” In Proceeding of the 5th IEEE Symposium on Field-Programmable Custom

Computing Machines (FCCM’97), Napa Valley, CA, USA, April 16-18, 1997,

Published by the IEEE Computer Society Press, Kenneth L. Pocek and Jeffrey Arnolds,

editors, Los Alamitos, CA, USA, 1997, pp. 22-28.

[Trimberger98] Steve Trimberger, “Scheduling Designs into a Time-Multiplexed FPGA,” In

Proc. 6th ACM/SIGDA International Symposium on Field Programmable Gate Arrays

(FPGA'98), Monterey, CA, USA, February 22-24, 1998.

[Ullman84] J. D. Ullman, Computational Aspects of VLSI, Computer Science Press,

Rockville, Md, 1984.

REFERÊNCIAS 275

[uPURL] ____, “General Processor Information”, URL:

http://bwrc.eecs.berkeley.edu/CIC/summary.

[Vasilko96] M. Vasilko, D. Ait-Boudaoud, “Architectural Synthesis Techniques for

Dynamically Reconfigurable Logic,” In Proc. 6th Int. Workshop on Field-

Programmable Logic and Applications (FPL'96), Darmstadt, Germany, Sept. 23-25,

1996, Published in Springer-Verlag LNCS 1142, Reiner R. Hartenstein and Menfred

Glesner, edts., 1996, pp. 290-296.

[VCCURL] VCC, Corp., The HOT-I and HOTF-I boards of RPUs. With the Xilinx(tm)

XC6162 and XC6264 respectively. URL: http://www.vcc.com/Hotworks.html.

[Velab98] ____, Paramaterised Library for XC6200, Velab – VHDL Elaborator,

January 1998.

[VelabURL] Douglas M. Grant, Velab: VHDL Elaborator for XC6200, v0.52, October

1997. See: Velab Release Notes, Xilinx Inc., URL:

http://www.xilinx.com/apps/velabrel.html, 1998.

[Villasenor97] John Villasenor, William H. Mangione-Smith, “Configurable Computing”, In

Scientific American, June 1997, pp. 66-71. URL:

http://www.sciam.com/0697issue/0697villasenor.html.

[Vincent93] Alberto Sangiovanni-Vincentelli, Abbas El Gamal, and Jonathan Rose,

“Synthesis methods for field programmable gate arrays,” In Proceedings of the IEEE,

81(7), July 1993, pp. 1057-1083.

[VirtexURL] Xilinx, Inc., “The Virtex Series of FPGAs,” URL:

http://www.xilinx.com/products/virtex.

[VIUFURL] _____, 3rd Annual VIUF Design Contest, 1997. URL:

http://rassp.scra.org/Fall97_VIUF/Design_Contest/.

[Waingold97] Elliot Waingold, et al., “Baring It All to Software: Raw Machines,” In IEEE

Computer, September 1997, pp. 86-93.

276 REFERÊNCIAS

[Wakabay91] K. Wakabayashi, “Cyber: High-Level Synthesis System from Software into

ASIC,” In High-Level VLSI Synthesis, Kluwer Academic Publishers, 1991, pp. 79-104.

[Wazlows93] M. Wazlowski, et al, “PRISM-II Compiler and Architecture”, In Proc. of the

IEEE Workshop on FPGAs for Custom Computing Machines, Napa, CA, April 5-7,

1993, pp. 9-16.

[Weaver98] M. Chu, N. Weaver, K. Sulimma, A. DeHon, and J. Wawrzynek, “Object

Oriented Circuit-Generators in Java,” In Proc. of the IEEE 6th Symposium on Field-

Programmable Custom Computing Machines (FCCM'98), Napa Valley, CA, USA,

April 15-17, 1998, Published by the IEEE Computer Society Press, Kenneth L. Pocek

and Jeffrey Arnolds, editors, Los Alamitos, CA, USA, 1998, pp. 158-166.

[Weinhardt00] M. Weinhardt and W. Luk, “Pipeline Vectorization,” submitted to: IEEE

Transactions on Computer-Aided Design of Integrated Circuits and Systems, 2000.

[Weinhardt97] M. Weinhardt, “Pipeline Synthesis and Optimization for Reconfigurable

Custom Computing Machines,” Interner Bericht 1/97, Fakultdt fur Informatik,

Universitdt Karlsruhe; also presented at poster session of 5th ACM/SIGDA Int.

Symposium on FPGAs (FPGA’97), Monterey, CA, Feb. 1997.

[Weinhardt99] M. Weinhardt and W. Luk, “Pipeline Vectorization for Reconfigurable

Systems,” In Proc. of the IEEE Symposium on Field-Programmable Custom Computing

Machines (FCCM'99), Napa Valley, CA, USA, April 21-23, 1999, Published by the

IEEE Computer Society Press, Kenneth L. Pocek and Jeffrey Arnolds, editors, Los

Alamitos, CA, USA, 1999, pp. 52-62.

[Wirth98] Niklaus Wirth, “Hardware Compilation: Translating Programs into Circuits,”

In IEEE Computer, June 1998, pp. 25-31.

[Wirthlin95] M. J. Wirthlin, and B. L. Hutchings, “A Dynamic Instruction Set Computer”,

In Proc. of the 4th IEEE Symposium on FPGAs for Custom Computing Machines

(FCCM'95), Napa Valley, CA, USA, April 19-21, 1995, Published by the IEEE

Computer Society Press, Peter Athanas and Kenneth L. Pocek, editors, Los Alamitos,

CA, USA, 1995, pp. 99-107.

REFERÊNCIAS 277

[Witting96] R. D. Witting, and P. Chow, “OneChip: An FPGA Processor with

Reconfigurable Logic”, In Proc. of the IEEE Symposium on FPGAs for Custom

Computing Machines, Napa Valley, CA, USA, April 17-19, 1996, pp. 126-135.

[Wo94] David Wo, and Kevin Forward, “Compiling to the Gate Level for

Reconfigurable Co-Processor”, In Proc. of the IEEE Symposium on FPGAs for Custom

Computing Machines (FCCM’94), Napa Valley, CA, USA, April 10-13, 1994,

Published by the IEEE Computer Society Press, Duncan A. Buell and Kenneth L.

Pocek, editors, Los Alamitos, CA, USA, 1994, pp. 147-154.

[Xact97] Xilinx, Inc., XACTstep 6000 Series tool, Xilinx, San Jose, CA, USA, 1997.

[X-Blox92] Xilinx Inc., San Jose, CA, USA, X-BLOX Design Tool User Guide, 1992.

[Xilinx97] Xilinx Inc., San Jose, CA, USA, XC6000 Field Programmable Gate Arrays,

version 1.10, April 24, 1997.

[XilinxURL] Xilinx Inc., URL: http://www.xilinx.com.

[Ye00a] Z. Ye, N. Shenoy, and P. Banerjee, “A C Compiler for a Processor with a

Reconfigurable Functional Unit,” In Proc. of the ACM/SIGDA Symposium on Field

Programmable Gate Arrays (FPGA’2000), Monterey, CA, Feb. 2000.

[Ye00b] Z. Ye, P. Banerjee, S. Hauck, and A. Moshovos “CHIMAERA: A High-

Performance Architecture with a Tightly-Coupled Reconfigurable Unit,” In Proc. of the

International Symposium on Computer Architecture (ISCA’2000), Toronto, CANADA,

June 2000.

278 REFERÊNCIAS

211

Apêndice A Tecnologia Java O fluxo de compilação/execução da tecnologia Java pode ser visto na Figura A.1. Cada classe

descrita em linguagem Java é compilada (javac [J2SDKURL], por exemplo) para um ficheiro

designado por classfile, que contém toda a informação necessária do programa origem num

formato conhecido como bytecodes [Gosling95], de modo a poder ser executado por uma

máquina abstracta. Os bytecodes de cada classe são constituídos por uma constant pool (com

as referências simbólicas, cadeias de caracteres constantes, entre outras informações). Estes

bytecodes contêm ainda instruções para cada método, definidas por uma máquina virtual

designada por JVM [Lindholm96].

CAFEBABE0003002D00 2008...

Processador Java

Programa em Java

Compilador de Java

Compilador JIT Interpretador

Bytecodes para Código nativo

Bibliotecas Nativas (.so, .dll)

Classfiles Java

(.class)

Compilador de Java para Código Nativo

Class Mult static int mult(int a, int b) int r=0; for(int i=0; i<b; i++) r+=a; return r;

Figura A .1 . F luxo de compi lação/execução da tecnologia Java.

212 APÊNDICE A TECNOLOGIA JAVA

Este modelo de representação executável preserva quase toda a informação original como por

exemplo a divisão em classes, os campos e métodos de cada classe, os arrays existentes no

programa original1, etc.

A JVM tem uma arquitectura baseada numa pilha de operandos - escolhida por ser eficiente

na interpretação e portabilidade para diferentes arquitecturas alvo (RISC e CISC), e por

garantir ficheiros objecto de dimensão reduzida - e registos.

Os tipos de dados da JVM são: byte, short, int, long, float, double, char, returnAddress.

Todas as mnemónicas (200 atribuídas, 24 variações rápidas, e 2 reservadas) têm 8 bits

seguidas de 0 a 4 operandos.

As instruções aritméticas e lógicas retiram os operandos das posições cimeiras da pilha e

colocam o resultado no topo (exemplo: iadd corresponde ao RISC a: add tos, tos-1,

tos, sendo tos o conteúdo do topo da pilha).

A pilha de operandos é também utilizada para a passagem dos argumentos e retorno de

valores dos métodos. Existem instruções para movimentar valores das variáveis locais para o

topo da pilha e vice-versa, instruções para a criação e manipulação de objectos, de arrays,

instruções de fluxo de controlo (if, goto, switch, etc.), saltos para sub-rotinas para

tratamento de excepções, invocação de métodos, etc.

Os bytecodes podem ser executados por 4 modos diferentes:

• por um interpretador (por exemplo: java [J2SDKURL]);

• por um compilador JIT2 [Cramer97] (normalmente chamada de compilação

dinâmica);

• por tradução dos bytecodes em código nativo [Hsieh97];

• por implementações da JVM ou de parte da JVM em hardware, como é o caso do

processador picoJava-I [Connor97].

1 Não havendo, quando não existe sobreposição em memória, a ambiguidade nos acessos a arrays como acontece em códigos de três endereços em que os arrays do programa são embebidos numa memória global. 2 Do inglês: Just-In-Time.

APÊNDICE A TECNOLOGIA JAVA 213

Têm sido desenvolvidos tradutores directos de Java para C, que depois utilizam um

compilador de C. Esta solução, contudo, abdica, entre outras coisas, da principal

característica desta tecnologia, que é a proliferação de aplicações em classfiles e não de

ficheiros de texto com o programa original.

Têm também sido desenvolvidos compiladores de diversas linguagens3 (Ada, Eiffel, Cobol,

Scheme, etc.) tendo como alvo a JVM. Estes compiladores geram bytecodes a partir do

programa fonte (descrito numa linguagem de programação diferente da linguagem Java). As

propriedades do modelo bytecodes tornam a utilização de várias linguagens para uma

aplicação uma realidade, e reforçam a ideia do modelo JVM como um possível modelo de

distribuição de aplicações independente da plataforma.

Têm sido feitos inúmeros esforços com a finalidade de acelerar a execução dos bytecodes.

Alguns destes esforços foram direccionados para a optimização dos bytecodes estaticamente,

com técnicas avançadas de compilação [Cierniak97][Budimlic97] (conhecidos por

optimizadores bytecodes-to-bytecodes). Outros baseiam-se na utilização de técnicas ao nível

dos compiladores do tipo JIT [Cramer97]. E ainda outros optam pela paralelização dos

bytecodes. Em [Bik97] é descrita uma ferramenta para detecção automática de paralelismo

implícito em código cíclico ao nível da JVM. Esta paralelização tem como objectivo tirar

partido de arquitecturas que tenham suporte efectivo de multi-threads.

3 Uma lista de alguns compiladores pode ser consultada em [JVMLang].

214 APÊNDICE A TECNOLOGIA JAVA

215

Apêndice B Fluxo de Compilação Alvejando ASICs Este apêndice descreve um fluxo de compilação, a partir de um algoritmo em linguagem

Java, que integra uma ferramenta de síntese arquitectural tradicional. É explicado um

caminho de um subconjunto de bytecodes do Java de uma dada aplicação à geração de VHDL

comportamental que pode depois ser utilizado por uma ferramenta de síntese arquitectural

para a criação do circuito final. Este fluxo de compilação foi considerado no início dos

trabalhos que conduziram a esta tese e publicado em [Cardoso98b].

A Figura B.1 ilustra o referido fluxo de compilação. O fluxo utiliza como retaguarda uma

ferramenta de síntese arquitectural (é utilizado o CADDY-II [CaddyURL]).

Programa em

Java

Compilador para

bytecodes

Bytecodes Java GALADRIEL

VHDL comportamental

Síntese Arquitectural

VHDL RTL

Síntese Lógica

EDIF Colocação &

Encaminhamento Netlist do circuito

Figura B .1 . O ambiente de compi lação de f ragmentos de código Java

em hardware especí f ico com a ut i l ização de uma ferramenta de s íntese

arquitectural.

216 APÊNDICE B FLUXO DE COMPILAÇÃO ALVEJANDO ASICS

A compilação de bytecodes para VHDL comportamental é directamente realizada sobre os

bytecodes. Cada tradução fornece uma entidade VHDL constituída por um único processo. A

tradução é facilitada pela prévia identificação dos ciclos, e da informação relativa às

dependências de controlo, e pelo facto do VHDL gerado incluir a pilha de operandos.

Cada tipo primitivo da linguagem Java (byte, short, int, boolean, long, e char) é traduzido

para o tipo correspondente em VHDL4.

De momento, o VHDL comportamental gerado utiliza 32 bits como comprimento de palavra.

As instruções da JVM para conversão de tipos são traduzidas para funções VHDL

equivalentes. Por exemplo, a instrução i2s (int para short) é traduzida para p# :=

int2short(p#), em que int2short é a função VHDL que converte um inteiro de 32

bits para 16 bits (esta função reside na biblioteca de conversões) ambos representados em

complemento para dois.

As operações com operandos de 64 bits (tipo long) utilizam dois níveis da pilha de

operandos ou duas variáveis locais para armazenar cada operando. Por exemplo, a instrução

da JVM, ladd é convertida em (p#+1, p#) := (p# & p#+1) + (p#+2 &

p#+3), em que & é o operador de concatenação.

As instruções de leitura/escrita de elementos de arrays são traduzidas para funções em

VHDL de funcionalidade semelhante.

Exemplo B -1 . Exemplo da t radução de bytecodes Java para VHDL

comportamental .

Considere-se o fragmento Java apresentado na Figura B.2 que especifica a

expressão: (b + c) × d + e + f; em que todos os operandos são do tipo int

(32 bits). O compilador identifica as variáveis e os operandos da pilha que

têm de ser transferidos entre o software e o hardware e vice-versa. Neste

caso identifica 5 variáveis locais de entrada e o operando do topo da pilha

como resultado. O corpo da arquitectura da entidade em VHDL lê 5

operandos de 32 bit e retorna o resultado em 32 bits (ver Figura B.2, na

qual Din e Dout são portos da entidade).

4 Funções de suporte a operações de vírgula flutuante seriam, contudo, necessárias.

APÊNDICE B FLUXO DE COMPILAÇÃO ALVEJANDO ASICS 217

(…) index = (b + c) * d + e + f; (…)

VHDL

bytecodes

(…) iload 10 iload 13 iadd iload_2 imul iload 11 iload 14 iadd iadd (…)

(…) l10 := Din; -- read() l13 := Din; -- read() l2 := Din; -- read() l11 := Din; -- read() l14 := Din; -- read() p1 := l10; p2 := l13; p1 := p2 + p1; p2 := l2; p1 := p2 * p1; p2 := l11; p3 := l14; p2 := p3 + p2; p1 := p2 + p1; Dout <= p1; -- write() (…)

código Java

Com a construção de um DFG para cada bloco básico

p1 := (l10 + l13) * l2 + l11 + l14;

Figura B .2 . Tradução de Java com a ut i l ização de o perações de le i tura e

escrita.

A tradução dos bytecodes para VHDL com utilização do funcionamento da pilha de

operandos assume que a ferramenta de síntese arquitectural é suficientemente poderosa para

optimizar a descrição.

Cada ramo da construção switch do Java, quando não termina num break é copiado para

cada uma das opções em VHDL (todas as opções da instrução when, do VHDL, terminam a

instrução no fim do ramo). Quando várias opções da instrução Java switch seleccionam o

mesmo corpo de instruções é utilizada a construção when do VHDL com o OR das opções.

Todos os ciclos do código Java são implementados por construções do tipo while do

VHDL. Contudo, os ciclos do programa fonte não podem ter internamente instruções break.

Embora este fluxo de compilação possa parecer propício para realizar hardware específico a

partir de descrições de algoritmos em linguagem Java, tal facto não é inteiramente aplicável

tratando-se de reconfigware. As propriedades inerentes ao reconfigware fazem com que

técnicas especializadas tenham de ser utilizadas para se obterem soluções eficientes. O alvo

218 APÊNDICE B FLUXO DE COMPILAÇÃO ALVEJANDO ASICS

reconfigware permite reconfiguração e tem uma estrutura pré-definida (fixa) e por isso sem a

liberdade de implantação física (layout) dos ASICs.

219

Apêndice C Implementação Simplificada de Algumas Construções Orientadas por Objectos em Hardware Específico É fundamental que as ferramentas de compilação para hardware específico possam

estabelecer um caminho automático de especificações orientadas por objectos até uma

arquitectura sintonizada com a própria aplicação. Em muitos casos, estas especificações

podem ser implementadas simplificadamente em hardware específico. Para tal, são

necessárias algumas transformações (previamente apresentadas em [Cardoso98a]):

• Desdobramento de objectos: nesta transformação o objecto é expandido nos campos

e nos métodos que o constituem (ver Exemplo C-1);

• Aplanação da estrutura hierárquica: nesta transformação são englobadas em

instâncias de classes que sejam derivadas todas as características das classes na

hierarquia (ver Exemplo C-2);

• Implementação de despacho dinâmico: quando não é conhecida estaticamente a

classe de um determinado objecto referenciado, a invocação de um método nessa

referência é resolvida pela determinação do objecto de entre o conjunto

dinamicamente possível (ver Exemplo C-3);

• Alocação estática de objectos: uma das formas de lidar com a criação de objectos é

fazer a pré-alocação destes em memória durante a compilação. Devido à natureza

parcialmente dinâmica da linguagem Java, o compilador tem de determinar que

220 APÊNDICE C IMPLEMENTAÇÃO SIMPLIFICADA DE ALGUMAS...

classes na hierarquia de classes poderão ser instanciadas pela aplicação. Muitas das

características dinâmicas podem ser resolvidas estaticamente. Uma das

transformações é realizada pela análise pessimista da alocação de objectos em

memória. Na pré-alocação é determinado o conjunto de classes que possam definir

uma determinada referência a um objecto e alocada memória capaz de armazenar o

objecto de maior dimensão. A criação de objectos e arrays dentro de ciclos pode ser

estaticamente resolvida quando é possível de determinar estaticamente o número das

iterações do ciclo ou um seu majorante. A incapacidade de resolução estática de

objectos ou de arrays dentro de ciclos mal-comportados (quando o número de

iterações não pode ser conhecido estaticamente) é um exemplo da necessidade de

construções dinâmicas em hardware específico. Sem alocação dinâmica, quando uma

variável pode armazenar a referência para instâncias de classes diferentes, tem de ser

reservada memória que possa albergar o maior dos objectos. Este problema pode ter

custos incomportáveis quando existem arrays de objectos ou criações de objectos

inseridas em estruturas cíclicas.

Todas as transformações anteriores requerem a existência da hierarquia de classes em tempo

de compilação e são orientadas para implementações simplificadas em hardware específico.

Parece ser opinião unânime de que a implementação em hardware específico de mecanismos

que assegurem o funcionamento das propriedades dinâmicas requer custos e complexidades

demasiadamente elevados. Contudo, formas de implementação necessitam de ser

investigadas.

Foram apresentadas formas simples e eficientes de implementação de descrições orientadas

por objectos em hardware específico que se baseiam na resolução estática dessas construções.

Para consolidar as técnicas propostas necessitam de ser elaborados estudos de avaliação e

aplicabilidade das mesmas em exemplos complexos.

Exemplo C -1 . Desdobramento de objectos.

Na Figura C.1 é apresentada a classe “Rect”, constituída por dois atributos

do tipo inteiro, um construtor e um método que calcula a área de um

rectângulo. O programa cria um novo objecto do tipo “Rect” (com

parâmetros l1 e l2) e invoca o método area(). O construtor pode ser

realizado por simples atribuição às duas variáveis correspondentes aos

APÊNDICE C IMPLEMENTAÇÃO SIMPLIFICADA DE ALGUMAS... 221

atributos dos valores iniciais (l1 e l2) e a invocação do método por um

procedimento que recebe como parâmetros as variáveis correspondentes aos

atributos e a variável que armazena a área calculada.

Rect

Int l1; Int l2; Rect(int a, int b) This.l1 = a; This.l2 = b; public int area() return (this.l1 * this.l2);

Java … rect S = new Rect(l1, l2); … int area = S.area(); …

VHDL … Rect_l1 := l1; Rect_l2 := l2; … Rect_area(Rect_l1, Rect_l2, area); …

Figura C .1 . Desdobramento de objectos.

Exemplo C -2 . Aplanação da estrutura hierárquica de c lasses.

Na Figura C.2 são apresentadas duas classes: a classe “Circle” e a classe

derivada “Rect”. O encapsulamento dos atributos da classe mãe

(“Circle”) na classe derivada (“Rect”) produz uma nova classe “Rect”.

A partir desta pode ser utilizado o supracitado desdobramento de objectos

para implementar o objecto em hardware.

Circle

Int l1; Circle(radius a) This.l1 = a; public int area() return 3*l1*l1;

Rect extends Circle

Int l2; Rect(int a, int b) Super(a); This.l2 = b; public int area() return l1*l2;

Int l1; Int l2; Rect(int a, int b) This.l1 = a; This.l2 = b; public int area() return l1*l2;

Rect

Figura C .2 . Aplanação da estrutura hierárquica de c lasses.

222 APÊNDICE C IMPLEMENTAÇÃO SIMPLIFICADA DE ALGUMAS...

Exemplo C -3 . Implementação de despacho d inâmico.

Na Figura C.3 é apresentado um exemplo em que num determinado ponto

do programa não é possível conhecer estaticamente a classe do objecto que

a variável S referencia. Por este motivo, o método invocado na linha 9

(caixa Java) pode ser o método area() da classe “Rect” ou o da classe

“Circle”. Com a codificação de cada classe é possível implementar a

especificação em VHDL no qual é determinada a classe que foi instanciada

e por isso chamado o respectivo método (linhas 13 a 17 da caixa VHDL).

Neste ponto S pode ser uma referência a um objecto do tipo Rect ou Circle

Java 1. … 2. Shape S; 3. … 4. if(option == 2) 5. S = new Rect(l1, l2); 6. Else 7. S = new Circle(l1); 8. … 9. int Area = S.area(); 10. …

VHDL 1. … 2. Type CLASSES is (Circle, Rect); 3. Variable Class_1: CLASSES; 4. … 5. if(option = 2) then 6. newRect(l1, l2, Rect_l1_1, Rect_l2_1); 7. Class_1 := Rect; 8. else 9. newCircle(l1, Circle_radius_1); 10. Class_1 := Circle; 11. end if; 12. … 13. if(Class_1 = CLASSES’(Rect)) then 14. Rect_area(Rect_l1_1, Rect_l2_1, area); 15. Else 16. Circle_area(Circle_radius_1, area); 17. End if; 18. …

Figura C .3 . Implementação de despacho d inâmico.

223

Apêndice D Exemplos Utilizados

“Example is not the main thing in influencing others. It is the only thing.”

Albert Schweitzer

Neste apêndice são apresentados os exemplos considerados na dissertação. É apresentado o

código Java para cada um dos exemplos mais simples. São também apresentadas, para cada

exemplo, as características principais (linhas de código Java, número de blocos básicos,

número de instruções da JVM, número de nós do DFG global gerado pelo GALADRIEL,

número de ciclos, número de variáveis do tipo array e número de acessos à memória).

O primeiro grupo de exemplos refere-se a núcleos de processamento simples, que na maioria

das vezes integram exemplos reais. Todos os exemplos deste grupo podem ser

implementados por aplicação de síntese lógica ao código, numa linguagem de descrição de

hardware, traduzido directamente das versões em Java. O segundo grupo de exemplos integra

algoritmos completos e mais complexos.

Alguns exemplos considerados referem-se aos exemplos apresentados com os ciclos

desenrolados totalmente ou de um factor K. Um ciclo desenrolado de um factor K significa

que o novo ciclo tem como corpo K iterações do ciclo original.

D.1 Grupo de Núcleos de Algoritmos

A: REVERSE

Função que reverte os bits de uma palavra de 32 bits (ver Figura D.1). Esta função é utilizada

por algumas implementações da transformada de Fourier (FFT).

224 APÊNDICE D EXEMPLOS UTILIZADOS

int Reverse(int Word) int WordRev = 0; For(int I=0; I<32; I++) WordRev |= (Word & 1); WordRev << 1; Word >> 1; Return WordRev;

Figura D .1 . Exemplo REVERSE.

B: COUNT

Função que conta o número de bits de valor lógico um de uma palavra (ver Figura D.2). B8

identifica o exemplo desenrolado e que utiliza como entrada um palavra de 8 bits, B16, o

exemplo desenrolado com palavra de 16 bits e B32, o exemplo desenrolado com palavra de

32 bits.

Int count(int word) int NumOnes = 0; For(int I=0; I<8; I++) NumOnes += (Word >> I) & 1; Return NumOnes;

Figura D .2 . Exemplo COUNT8.

C: HAMMDIST

Função que retorna a distância de Hamming entre duas palavras (ver Figura D.3). C8

identifica o exemplo desenrolado com palavras de 8 bits, C16, o exemplo desenrolado com

palavras de 16 bits e C32, o exemplo desenrolado com palavras de 32 bits.

Int hammingDist(int I1, int I2) Int result = 0; Int xor1 = I1 ^ I2; For(int I=0; I<32; I++) Result = (xor1 & 1) + result; Xor1 = xor1 >> 1; return result;

Figura D .3 . Exemplo HAMMDIST.

APÊNDICE D EXEMPLOS UTILIZADOS 225

D: EVENONES

Função que retorna um se o número de bits de uma palavra iguais a um for ímpar (ver Figura

D.4). D8 identifica o exemplo desenrolado com palavra de 8 bits, D16, o exemplo

desenrolado com palavra de 16 bits e D32, o exemplo desenrolado com palavra de 32 bits.

Int evenOnes(int temp, int Num) Int cnt = 0; For(int I=0; I<Num; I++) Cnt ^= (temp & 1); temp >>= 1; return cnt;

Figura D .4 . Exemplo E V E N O N E S .

E: SQRT

Função que calcula a raiz quadrada, de um número inteiro de 12 bits, implementada em Java

(ver Figura D.5). O resultado é representado em 6 bits. E1 identifica o exemplo desenrolado.

public static short sqrt(short vsqn) short vsq = vsqn, asq = 0, a = 0, tvsq = 0; for (int i = 0; i < 6; i++) short nasq = (short) (((asq+a) << 2) | 1); short sa = (short) (a << 1); tvsq = (short) ((tvsq << 2) | ((vsq >> 10) & 3)); vsq = (short) (vsq << 2); if (nasq <= tvsq) a = (short) (sa | 1); asq = nasq; else a = sa; asq = (short) (asq << 2); return a;

Figura D .5 . Exemplo SQRT.

F: USQRT

Função que calcula a raiz quadrada de um número inteiro representado em 32 bits (ver Figura

D.6). O resultado é representado por apenas 16 bits. F1 identifica o exemplo desenrolado.

226 APÊNDICE D EXEMPLOS UTILIZADOS

public static int usqrt(int x) int a = 0; // accumulator int r = 0; // remainder int e = 0; // trial product for (int i = 0; i < 16; i++) r = (r << 2) + (((x & (3 << 14)) >> 14)); x <<= 2; a <<= 1; e = (a << 1) + 1; if (r >= e) r -= e; a++; return (e>>9);

Figura D .6 . Exemplo USQRT.

G: CRC-32

Função que calcula o CRC (Cyclic Redundancy Check) de 32 bits, um byte de cada vez

utilizando a convenção Big-Endian (ver Figura D.7). O polinomial gerado é o utilizado no

protocolo Ethernet: 1245101112162632 ++++++++++ xxxxxxxxxx .

int crc_32(int data) data = data & 0xff; int ans = data << 24; for(int i=0;i<8;i++) if((ans & 0x80000000) == 0x80000000) ans = (ans << 1) ^ 0x04c11db7; else ans <<= 1; return ans;

Figura D .7 . Exemplo CRC-32 .

H: HAMMING

Função que implementa um descodificador de Hamming de uma palavra de 7 bits (ver Figura

D.8). O resultado é representado em 4 bits.

APÊNDICE D EXEMPLOS UTILIZADOS 227

static byte Hamming(byte word) byte syndrome, bit1, bit2, bit3; byte bit4, bit5, bit6, bit7; bit1 = (byte) (word & 0x1); bit2 = (byte) ((word & 0x2) >> 1); bit3 = (byte) ((word & 0x4) >> 2); bit4 = (byte) ((word & 0x8) >> 3); bit5 = (byte) ((word & 0x10) >> 4); bit6 = (byte) ((word & 0x20) >> 5); bit7 = (byte) ((word & 0x40) >> 6); syndrome=(byte)(bit1^bit3^bit5^bit7); syndrome <<= 1; syndrome|=(byte)(bit2^bit3^bit6^bit7); syndrome <<= 1; syndrome|=(byte)(bit4^bit5^bit6^bit7); switch(syndrome) case 1: word ^= 0x1; break; case 2: word ^= 0x2; break; case 3: word ^= 0x4; break; case 4: word ^= 0x8; break; return (byte) (word & 0xf);

Figura D .8 . Exemplo HAMMING.

I: MULT

Função que implementa um multiplicador de dois inteiros positivos de 32 bits com resultado

representado em 32 bits (ver Figura D.9). I1 identifica o exemplo completamente

desenrolado, I2 desenrolado de um factor de 2, I4 de um factor de 4, I8 de um factor de 8 e

I16 de um factor de 16.

public int mult(int x, int y) int t1 = x; int t2 = y; int t3 = 0; // mult result for(int i=0; i < 32; i++) // 32 bits if((t2 & 0x1) == 0x1) t0 += t1; t1 <<= 1; t2 >>= 1; return t0;

Figura D .9 . Exemplo MULT.

228 APÊNDICE D EXEMPLOS UTILIZADOS

Na Tabela D.1 são apresentas algumas das características dos exemplos previamente

apresentados.

Tabela D .1 . Caracter íst icas do pr imeiro grupo de exemplos.

Exemplo # linhas de Java

# Inst. JVM

# BBs # nós do DFG

A: REVERSE 10 25 4 26 A1: REVERSE+ 129 440 1 251 B: COUNT 7 19 4 21 B8: COUNT8+ 11 62 1 39 B16: COUNT16+ 21 126 1 79 B32: COUNT32+ 39 254 1 159 C: HAMMDIST 9 28 4 27 C8: HAMMDIST8+ 19 80 1 48 C16: HAMMDIST16+ 36 194 1 98 C32: HAMMDIST32+ 71 320 1 192 D: EVENONES 8 21 4 23 D8: EVENONES8+ 18 76 1 45 D16: EVENONES16+ 37 164 1 99 D32: EVENONES32+ 71 336 1 201 E: SQRT 21 65 7 57 E1: SQRT+ 75 256 19 217 F: USQRT 17 49 6 51 F1: USQRT+ 130 477 31 485 G: CRC-32 10 34 7 34 G1: CRC-32+ 46 153 25 157 H: HAMMING 25 121 6 75 I: MULT 11 32 6 36 I2: MULT2 19 49 8 55 I4: MULT4 23 83 12 96 I8: MULT8 39 151 20 190 I16: MULT16 71 287 36 426 I1: MULT+ 228 542 65 573

D.2 Algoritmos mais Complexos

DCT (Discrete Cosine Transform)

O DCT [Ahmed74] é uma transformada utilizada pelos standards de codificação de imagem

(JPEG – Joint Photographic Expert Group) e de vídeo (MPEG5 - Motion Picture Expert

Group) e transforma uma representação (sinal) no domínio do espaço para o domínio da

frequência.

5 Os standards de codificação/descodificação MPEG utilizam respectivamente o DCT e o IDCT.

APÊNDICE D EXEMPLOS UTILIZADOS 229

O DCT considerado é o DCT bidimensional que recebe blocos de pixeis de dimensão 8 × 8

(dimensão utilizada pela maioria dos standards de compressão de dados). A implementação

em Java não é uma implementação optimizada mas a simples divisão do DCT 2-D em dois

DCT 1-D (cada um dos quais é realizado por simples multiplicação de matrizes) e uma

transposição de matrizes. A equação (D.1) ilustra as operações realizadas, na qual a matriz W

representa a matriz de coeficientes, X a matriz de entrada e Y a matriz de saída (todas as

matrizes são de dimensão 8 × 8). A implementação considerada utiliza os coeficientes

representados por 12 bits (vírgula fixa).

( )TWXWY ××= (D .1 )

Um DCT é realizado sobre uma imagem bidimensional (M × N) decompondo esta em blocos

de 8 × 8, sendo cada um deles computados pela equação anterior.

O exemplo DCT identifica o exemplo completo e DCT1 o exemplo completo com os ciclos

internos dos algoritmos de multiplicação de matrizes completamente desenrolados. O

exemplo DCT2 utiliza apenas dois ciclos.

Filtro Kalman

O filtro Kalman foi traduzido da versão em VHDL utilizada como exemplo-teste

(benchmark) para síntese arquitectural [Ben92URL]. O exemplo KALMAN1 é a descrição

traduzida directamente do original (ver Figura D.10), KALMAN2 uma versão com os dois

ciclos internos desenrolados, KALMAN3 uma versão com os dois primeiros ciclos e os dois

ciclos internos desenrolados e KALMAN4 com os dois primeiros ciclos, o ciclo interno da

segunda região cíclica e os últimos dois desenrolados.

1. static final short[] kalman1(short[] A, short[] X, 2. short[] K, short[] Y, short[] G) 2. 3. 4. short[] V = new short[4]; 5. 6. //Initializing state Vector X 7. for(int i=0; i<16; i++) 8. X[i] = 0; 9. 10. 11. for(int i=13; i<16; i++) 12. Y[i] = 0; 13. 14. 15. // Computing state Vector X

230 APÊNDICE D EXEMPLOS UTILIZADOS

16. for(int i=0; i<16; i++) 17. short temp = 0; 18. for(int j=0; j<16; j++) 19. int index = i * 16 + j; 20. temp += (short) (A[index] * X[j] + K[index] * Y[j]); 21. 22. X[i] = temp; 23. 24. 25. // Computing output Vector V 26. for(int i=0; i<4; i++) 27. short temp = 0; 28. for(int j=0; j<16; j++) 29. int index = i * 16 + j; 30. temp += (short) (G[index] * X[j]); 31. 32. V[i] = (short) (temp * Y[i+1]); 33. 34. 35. // Output Vector V 36. return V; 37.

Figura D .10 . Exemplo KALMAN.

Filtro Passa-Baixo para Imagens (FPBI)

Implementação em Java de um algoritmo que implementa um filtro passa-baixo para imagens

2-D. O algoritmo percorre a imagem inicial com uma janela de dimensão 3 por 3 pixeis. Cada

pixel da imagem filtrada é determinado pela soma pesada do pixel e dos seus vizinhos na

imagem original. A primeira implementação do algoritmo (FPBI) tem 4 ciclos encadeados e

utiliza um array onde são colocados os 9 coeficientes do filtro. Os dois ciclos mais externos

iteram sobre as linhas e colunas da imagem. A segunda implementação (FPBI1) foi obtida

desenrolando os dois ciclos internos. A terceira implementação (FPBI2) é uma versão da

anterior com os coeficientes fixos. A quarta implementação (FPBI3) é baseada na versão

anterior com o segundo ciclo desenrolado de um factor de 2. A quinta implementação

(FPBI4) é baseada na versão anterior com o segundo ciclo desenrolado de um factor de 2.

Detecção de Contornos (SOBEL)

Versão em Java do algoritmo de detecção de contornos, Sobel, proposto em [VIUFURL]. O

algoritmo utiliza dois níveis de convolução (horizontal seguida de vertical).

APÊNDICE D EXEMPLOS UTILIZADOS 231

IDEA

Parte do algoritmo de encriptação IDEA (International Data Encryption Algorithm)

[Schneier96]. O exemplo IDEA refere-se à encriptação de 8 elementos do tipo byte baseada

numa subchave de 52 elementos e retorna 8 bytes.

QRS

Algoritmo de monitorização do batimento cardíaco em ECG [Ben95URL]. A implementação

em Java corresponde ao código interno do ciclo infinito.

BPIC (Binary Pattern Image Coding)

Algoritmo que decompõe uma imagem em blocos de 4×4 pixeis e codifica cada bloco numa

única palavra de 32 bits [Morse94]. Como exemplo é considerada a parte do algoritmo que

calcula a codificação baseado na luminância e na média das luminâncias dos pixeis de um

determinado bloco.

EUCDIST

Algoritmo que calcula a distância euclideana entre dois vectores. A implementação utiliza

arrays com elementos do tipo short (16 bits) para armazenar os vectores. Este algoritmo é

amplamente utilizado em técnicas de agrupamento (clustering), processamento de imagem,

reconhecimento de voz, etc.

CCW e INTERSEC

São duas funções de geometria [Sedgewick92]. CCW implementa uma função que determina

se, dados três pontos num plano bidimensional, o trajecto que começa no primeiro, passa pelo

segundo e termina no terceiro é um trajecto no sentido directo dos ponteiros de um relógio ou

em sentido inverso. Intersec é uma função que indica se dois segmentos de recta num plano

bidimensional, cada um representada por dois pontos, se intersectam. O algoritmo utiliza o

algoritmo CCW.

Nas Tabela D.2, Tabela D.3, Tabela D.4 e Tabela D.5 estão representadas algumas das

características dos exemplos deste grupo.

232 APÊNDICE D EXEMPLOS UTILIZADOS

Tabela D .2 . Caracter íst icas dos exemplos considerados: codif icação de

imagem e v ídeo.

Exemplo # linhas de Java

# Inst. JVM

# BBs # Nós do DFG

# ciclos

# arrays

# acessos à memória

DCT1 33 406 25 407 8 5 4.352 DCT2 46 586 19 495 6 5 2.304 DCT3 188 930 7 1.257 2 3 256 BPIC1 56 203 30 199 7 5 24.832 BPIC2 116 537 42 468 3 5 24.832 BPIC3 178 1.082 39 831 2 5 24.832

Tabela D .3 . Caracter íst icas dos exemplos considerados: Fi l t ros de

processamento de imagens.

Exemplo

# linhas de Java

# Inst. JVM

# BBs

# Nós do DFG

# ciclos

# arrays

# acessos à memória Imagem: (m×n) pixeis

FPBI 28 110 13 116 4 3 9+19× ((m-3) × (n-3)) FPBI1 28 230 7 156 2 3 9+19× ((m-3) × (n-3)) FPBI2 42 276 7 185 2 3 9+15× (n-3) × (m-3) FPBI3 23 160 7 108 2 2 10× (n-3) × (m-3) FPBI4 40 183 7 121 2 2 7× (n-3) × (m-3) SOBEL 71 267 29 310 7 4 11×m×n-9×m+2×n-4

Tabela D .4 . Caracter íst icas do exemplo Kalman.

Exemplo # linhas de Java

# Inst. JVM

# BBs

# Nós do DFG

# ciclos

# arrays

# acessos à memória

KALMAN1 30 118 19 108 6 6 1.191 KALMAN2 96 694 13 438 4 6 1.191 KALMAN3 135 770 7 443 2 6 853 KALMAN4 239 1.417 4 656 1 6 853

Tabela D .5 . Caracter íst icas dos outros exemplos considerados.

Exemplo # linhas de Java

# Inst. JVM

# BBs

# Nós do DFG

# ciclos

# arrays

# acessos à memória

QRS 95 327 49 351 - - - IDEA 128 544 64 544 1 3 68 EUCDIST 8 26 4 23 1 2 2×n CCW 14 65 10 61 - - - INTERSEC 74 312 40 260 - - -

233

Apêndice E Interface Software/Reconfigware Para comunicação entre o software (sob a forma de bytecodes) e o hardware são utilizadas

chamadas a métodos nativos [Gordon98] (C ou C++) inseridas nos bytecodes da aplicação

sempre que seja necessária comunicação entre os dois domínios. A Figura E.1 mostra uma

interface simples (utilizando o conceito de memória partilhada, em que portos de

entrada/saída do FPGA se encontram mapeados em posições de memória). A classe Java que

contém os métodos nativos é ilustrada na Figura E.1a. Estes métodos nativos são descritos em

C (cujos cabeçalhos se encontram na Figura E.1b). A Figura E.1c ilustra a utilização da classe

de interface num programa em Java. A Figura E.2 ilustra os bytecodes (assumindo a

configuração do FPGA com o circuito em fases anteriores) que implementam a comunicação

com o reconfigware responsável pela implementação do exemplo da Figura 3.23. No código

da figura aparecem as colocações dos 5 operandos em registos do FPGA e no final da

execução do reconfigware, a transferência do resultado para o topo da pilha da JVM.

Os exemplos realizados utilizam a placa de desenvolvimento descrita em [Nisbet97]

conectada ao barramento PCI [PCI95URL] de um PC. Para a comunicação

software/reconfigware foi utilizada a classe em Java fornecida pelo fabricante [VCCURL],

que permite aceder do código Java aos recursos da placa (FPGA, RAMs, etc.). As variáveis

do tipo array que têm de ser transferidas para o reconfigware são copiadas para as memórias

SRAM da placa. Os elementos de variáveis do tipo array são transferidos de ou para as

memórias da placa e o reconfigware gerado pelo NENYA assume a pré-colocação destes

elementos. A comunicação de escalares (variáveis de tipo primitivo) entre os dois

234 APÊNDICE E INTERFACE SOFTWARE/RECONFIGWARE

componentes é feita pela utilização da interface FastMap6 [Churcher95]. Para cada variável

que necessita de comunicação é colocado numa coluna do FPGA um registo acessível pelo

sistema de computacional de hospedagem (PC).

a)

1. package HwInterface; 2. public class InOut 3. final static public void setup() 4. System.loadLibrary("InOutNat"); 5. 6. final static public native void write(int Address, int Data); 7. final static public native int read(int Address); 8. … 9. b)

10. #include <jni.h> 11. #include "HwInterface_InOut.h" 12. JNIEXPORT void JNICALL Java_HwInterface_InOut_write 13. (JNIEnv *Env, jobject c, jint a, jint b) … 14. JNIEXPORT jint JNICALL Java_HwInterface_InOut_read 15. (JNIEnv *Env, jobject c, jint a) … c )

16. … 17. HwInterface.InOut.setup(); … 18. HwInterface.InOut.write(Address1, Data1); 19. … 20. Data2 = HwInterface.InOut.read(Address2); 21. …

Figura E .1 . Bibl ioteca para comunicação software/hardware: a)

Declaração da c lasse Java que contém os métodos nat ivos; b)

Cabeçalhos da declaração dos métodos em l in guagem C; c ) chamada

da c lasse em Java .

O mecanismo utilizado para sincronizar a execução do reconfigware com o software é o

seguinte: durante a execução do reconfigware, o software pode esperar até que seja atribuído

o valor lógico um à flag de concluído, ou por um número pré-definido de milisegundos.

Durante a espera podem ser executadas instruções que não dependam de resultados do

reconfigware.

6 Os dispositivos da família XC6200 de FPGAs são acedidos via um interface SRAM: todos os FFs (Flip-Flops) do FPGA são mapeados na memória do sistema de hospedagem possibilitando que o conteúdo dos mesmos possa ser escrito ou lido pelo software por simples acesso à memória.

APÊNDICE E INTERFACE SOFTWARE/RECONFIGWARE 235

1. … 2. new #2 class InOut 3. dup 4. invokenonvirtual #5 <Method InOut.init()V> 5. astore 1 6. // transfere para o reconfigware os 5 operandos 7. // l10, l13, l2, l11, l14 8. aload 1 9. iconst 0 // posição 0 10. iload 10 // operando 10 11. invokevirtual #4 <Method InOut.write(II)V> 12. aload 1 13. iconst 1 // posição 1 14. iload 13 // operando 13 15. invokevirtual #4 <Method InOut.write(II)V> 16. aload 1 17. iconst 2 // posição 2 18. iload 2 // operando 2 19. invokevirtual #4 <Method InOut.write(II)V> 20. aload 1 21. iconst 3 // posição 3 22. iload_11 // operando 11 23. invokevirtual #4 <Method InOut.write(II)V> 24. aload 1 25. iconst 4 // posição 4 26. iload 13 // operando 13 27. invokevirtual #4 <Method InOut.write(II)V> 28. 29. // Espera que o reconfigware calcule 30. 31. aload 1 32. iconst 5 33. invokevirtual #4 <Method InOut.read(I)I> 34. // resultado no topo da pilha da JVM 35. ...

Figura E .2 . Exemplo de comunicação entre o sof tware e o reconfigware

que implementa o exemplo apresentado na Figura 3.23.

De seguida apresenta-se um exemplo que foi realizado e que é constituído por um

componente software e um componente reconfigware [Cardoso99b].

O algoritmo de determinação da distância euclideana é um algoritmo simples (ver EUCDIST

no apêndice D). A Figura E.3b mostra a versão reconfigware/software do exemplo puramente

software da Figura E.3a. A versão reconfigware/software utiliza, por parte do software, o

mecanismo de espera pela activação do sinal concluído fornecido pelo reconfigware (Figura

E.3b).

Para a dimensão dos vectores X e Y de 4 a implementação tem uma área de 1.481 células e

atraso de 1,9 µs. O atraso foi medido com a frequência máxima de 20MHz determinada

236 APÊNDICE E INTERFACE SOFTWARE/RECONFIGWARE

experimentalmente. O tempo de execução não tem em conta os custos de transferência para

armazenar os dois vectores nas memórias da placa e para ir buscar o resultado com a

utilização da interface FastMap. A implantação física (layout) do exemplo no FPGA

XC6216 está ilustrado na Figura E.4.

… // Number of array elements N int N=4; // create a reconfigware object Reconfigware RW1 = new Reconfigware(“vect_dist.cal”); // set the FPGA clock frequency to 20MHz RW1.setClock(20); // Give control of the memory of the board to the Host RW1.setBankControl(0); //send the arrays to the memory of the board RW1.writeRAM(X, AddrX, N); RW1.writeRAM(Y, AddrY, N); //give control of the memory of the board to the FPGA RW1.setBankControl(3); RW1.setMapLow32(0xfffffffe); // reset the FSM RW1.setColumn(RESET, 0); // start the FSM RW1.setColumn(START, 1); // pool the DONE bit till the completion of the // hardware execution do while(board.getColumn(DONE) != 1); // get the result from the register on the FPGA RW1.setMapLow32(0); Int L2NORM = RW1.getColumn(RESULT); // return the control of the memory of the board //to the host RW1.setBankControl(0); …

… // Number of array elements N int N=4; MAXTIME c1 = new MAXTIME(); c1.start(); int L2NORM = 0; for(int i=0; i<N;i++) short Aux = X[i] - Y[i]; L2NORM += Aux*Aux; c1.end(); …

a) b)

Figura E .3 . a) Segmento de software inicial ; b) Solução

reconfigware/software.

O exemplo apresentado permite ilustrar a interface reconfigware/software utilizada. Esta

interface baseia-se na utilização de uma placa ligada ao PCI de um computador pessoal e

forma por isso um sistema computacional reconfigurável com custos elevados de

comunicação entre os componentes reconfigware e software. Outros sistemas, como por

exemplo aqueles em que o componente reconfigware é ligado ao barramento de sistema ou os

novos dispositivos com o componente reconfigware integrado no mesmo dispositivo do que o

microprocessador têm custos de comunicação muito mais baixos e, por isso, permitem

soluções mistas mais eficazes.

APÊNDICE E INTERFACE SOFTWARE/RECONFIGWARE 237

Figura E .4 . Implantação f ís ica (Layout) do exemplo EUCDIST n o F P G A

XC6216 .

238 APÊNDICE E INTERFACE SOFTWARE/RECONFIGWARE

239

Apêndice F Glossário

ALAP – Acrónimo para: As Late As Possible. Esquema de escalonamento em que as

operações são executadas o mais próximo possível do fim.

ALU – Acrónimo para: Arithmetic-Logic Unit. Unidade lógico-aritmética. Esta unidade é

responsável pela realização de operações aritméticas (adição, multiplicação, etc.) e lógicas

(AND, OR, XOR, etc.).

ANB – Acrónimo para: aferição do número de bits suficiente.

Anteguarda – Termo utilizado para designar as fases iniciais do fluxo de compilação

proposto.

API – Acrónimo para: Application Programmer´s Interface. Interface software que permite a

aplicações comunicarem entre si.

ASAP – Acrónimo para: As Soon As Possible. Esquema de escalonamento em que as

operações são executadas o mais próximo possível do início.

ASIC – Acrónimo para: Application Specific Integrated Circuit. Circuito integrado de

aplicação específica.

Bytecodes – Representação binária de uma classe previamente compilada para a JVM.

Cadeias-de-dados – Utilizado na tese para designar séries não interrompidas de dados. Em

inglês é utilizado o termo streams.

Caminho Crítico – caminho de um grafo, constituído pela sequência de nós, com maior

atraso.

240 APÊNDICE F GLOSSÁRIO

CCM – Acrónimo para: Custom Computing Machine. Máquina computacional

personalizada.

CDFG – Acrónimo para: Control/Data Flow Graph. Grafo de Fluxo de Dados e de Controlo.

CDG – Acrónimo para: Control Dependence Graph. Grafo de Dependências de Controlo.

CFG – Acrónimo para: Control Flow Graph. Grafo de Fluxo de Controlo.

CFI – Acrónimo para: Control-Flow Intensive. Denominação dada a programas com fluxo

de controlo intensivo.

Classfile – Nome dado ao ficheiro que armazena os bytecodes de uma classe.

CLB – Acrónimo para: Configurable Logic Block. Bloco de lógica reconfigurável de um

FPGA.

Computação Adaptativa – o mesmo que Computação Reconfigurável.

Computação Reconfigurável – Tipo de computação baseado em máquinas computacionais

personalizadas, que combinam as sinergias de FPGAs com capacidades elevadas com

sistemas computacionais baseados em microprocessadores. Definição por Danish Bathia: ''An

ability for software to reach through the hardware layers and change the data-path for

optimising the performance''.

Configuração – programação da lógica e do encaminhamento de um agregado de lógica

configurável ou reconfigurável.

Co-Projecto Hardware/Software – Projecto concorrente do hardware e do software.

CPLD – Acrónimo para: Complex Programmable Logic Devices. Dispositivos de Lógica

Programável Complexos.

CPU – Acrónimo para: Central Processing Unit. Unidade de processamento central.

DAG – Acrónimo para: Directed Acyclic Graph. Grafo acíclico direccionado/orientado.

DDG – Acrónimo para: Data Dependence Graph. Grafo de Dependências de Dados.

DFG – Acrónimo para: Data Flow Graph. Grafo de Fluxo de Dados.

APÊNDICE F GLOSSÁRIO 241

DFI – Acrónimo para: Data-Flow Intensive. Nome dado a programas com fluxo de dados

intensivo.

DISC – Acrónimo para: Dynamic Instruction Set Computer. Computador com conjunto de

instruções dinâmico.

Dispositivos Reconfiguráveis – dispositivos de lógica que podem ser configurados uma ou

mais vezes.

DRLE – Acrónimo para: Dynamically Reconfigurable Logic Engine. Engenho de lógica

reconfigurável dinamicamente.

DSP – Acrónimo para: Digital Signal Processor. Processador de sinais digitais.

Equivalent Gates – (portas lógicas equivalentes) Número de transístores do circuito

considerado dividido pelo número de transístores de uma porta lógica NAND de duas

entradas (normalmente 4 transístores em tecnologia CMOS).

Escalonamento – Distribuição das operações de um grafo por passos temporais de modo a

que a relação temporal entre as operações no grafo seja mantida e existam nesse passo

temporal os recursos necessários para executar as operações consideradas.

Escalonamento Baseado em Lista – Escalonamento em que as operações são

incrementalmente alocadas a recursos vagos e em que é mantida uma lista de operações

disponíveis para serem escalonadas que vai sendo actualizada por cada operação escalonada.

Uma operação da lista é escolhida para escalonamento (desde que haja recursos livres) com

base em mecanismos de prioridades. As prioridades podem ser: estáticas (prioridades

determinadas em fases prévias ao escalonamento) ou dinâmicas (as prioridades são

reanalisadas durante o escalonamento com base nas operações previamente escalonadas).

FCCM – Acrónimo para: Field-Custom Computing Machine. Máquina computacional

personalizada no “campo”.

FIFO – Acrónimo para: First In First Out. Tipo de armazenamento em que o primeiro dado

a ser guardado é o primeiro a poder saír (ao contrário de uma pilha de dados).

Fluxo de Controlo Único – Tipo de execução em que os blocos básicos são executados

sequencialmente e não havendo, por isso, execução concorrente de blocos básicos.

242 APÊNDICE F GLOSSÁRIO

Fluxos de Controlo Múltiplos – Tipo de execução em que os blocos básicos podem ser

executados concorrentemente independentemente de serem blocos básicos com vários

destinos de fluxo de controlo.

FPAA – Acrónimo para: Field-Programmable ALU Arrays. Agregados de ALUs

programáveis pós-fabricação.

FPGA – Acrónimo para: Field Programmable Gate Arrays. Agregados de lógica

programáveis no “campo”.

FSM – Acrónimo para: Finite-State Machine. Máquina de estados finitos.

GALADRIEL – Nome atribuído ao compilador de anteguarda desenvolvido. O nome foi

retirado de textos de J. R. R. Tolkien: Rainha Elven de Lothlórien. Personagem do mundo

fantástico inventado por J. R. R. Tolkien. Galadriel em Sindarin (linguagem inventada por

J. R. R. Tolkien) significa: “A senhora da luz”.

Gráfico de Gantt – Nome dado a gráficos de barras horizontais que representam relações

temporais.

Grafo Direccionado ou Orientado – Tipo de grafo em que os laços têm atribuído um

sentido.

GSA – Acrónimo para: Gated Single-Assignment.

HAL – Nome dado ao exemplo da equação diferencial [Paulin86].

HDL – Acrónimo para: Hardware Description Language. Linguagem de descrição de

hardware.

HPDG – Acrónimo para: Hierarchical Program Dependence Graph. Grafo hierárquico de

dependências de programa.

HTG – Acrónimo para: Hierarchical Task Graphs. Grafo hierárquico de tarefas.

IEEE – Acrónimo para: Institute of Electrical and Electronic Engineers. Organização

internacional que agrega engenheiros de electrotecnia, electrónica, computadores e áreas

afins de todo o mundo.

APÊNDICE F GLOSSÁRIO 243

ILP – Acrónimo para: Instruction Level Parallelism. Paralelismo ao nível da

instrução/operação. No contexto de investigação operacional é o acrónimo para: Integer

Linear Programming. Programação Linear Inteira.

Inlining – (por exemplo de funções). Utilizado o termo português: expansão.

JIT – Acrónimo para: Just In Time. Compiladores do tipo JIT são caracterizados por

compilarem no imediato (compilam no momento de executar).

JVM – Acrónimo para: Java Virtual Machine. Máquina virtual da tecnologia Java.

Loop – Utilizado o termo português: ciclo. Embora no contexto de grafos o termo ciclo possa

representar não apenas loops mas também recursividade.

LUT – Acrónimo para: Look-Up Table. Tipo de implementação da unidade de funções

lógicas utilizado pela maioria dos FPGAs que é uma memória do tipo RAM, pequena e

rápida. (por exemplo: 4-LUTs indica que se trata de um FPGA com LUTs de 4 entradas)

Mapeamento – Estabelecer uma relação entre duas coisas.

NENYA – Nome atribuído ao compilador desenvolvido responsável pelas fases de síntese

arquitectural. Textos de J. R. R. Tolkien: um dos três aneis Elven feitos por Celebrimbor.

Chamado de Ring of Water, Ring of Adamant ou White Ring. O anel foi dado a Galadriel.

Operator Stength Reduction – Redução do custo de operações (redução da capacidade).

Utilizado em multiplicações e divisões por constantes (estas operações são transformadas em

sequências de deslocamentos e de somas/subtracções que implementam a operação original).

Ordenação Topológica de um DAG – É uma ordenação linear de todos os nós (vértices) do

DAG de modo a que se existir um laço entre o nó u e o nó v (u, v), então u aparece antes de v

na ordem.

OSR – Acrónimo para: Operator Strength Reduction. Redução do custo de operações.

P&R – Acrónimo para: Place and Route. Colocação e encaminhamento.

Partição Espacial – Habilidade de partir (dividir) uma função/circuito por um conjunto de

dispositivos de lógica reconfigurável.

244 APÊNDICE F GLOSSÁRIO

Partição Temporal – Habilidade de partir (dividir) uma função/circuito de modo a que cada

parte (fracção) possa ser executada por partilha temporal de um ou mais dispositivos de

lógica reconfigurável.

PCB – Acrónimo para: propagação de padrões de constantes ao nível do bit.

PCI – Acrónimo para: Peripheral Controller Interface.

RAM – Acrónimo para: Random-Access Memory. Memória de acesso aleatório.

rDPA – Acrónimo para: re-configurable Data-Path Architecture. Arquitectura de unidades

de dados reconfiguráveis.

Reconfiguração Dinâmica – Personalização de um agregado de lógica reconfigurável

durante a execução.

Reconfigware – Utilizado como abreviatura para hardware reconfigurável (reconfigurable

hardware).

Retaguarda – Termo utilizado para designar as fases finais do fluxo de compilação proposto.

RISC – Acrónimo para: Reduced Instruction-Set Computer. Microprocessador com conjunto

de instruções reduzido.

RPU – Acrónimo para: Reconfigurable Processing Unit. Unidade reconfigurável de

processamento.

RTL – Acrónimo para: Register Transfer Level. Nível de transferência entre registos.

SA – Acrónimo utilizado na tese para indicar o algoritmo realizado de partição temporal

baseado no algoritmo de optimização Simulated Annealing.

Shifter – deslocador de uma palavra.

Síntese arquitectural (em inglês: Architectural Synthesis) – geração a partir de uma descrição

em alto-nível da estrutura baseada em componentes e suas interligações ao nível de

transferência entre registos. É designada muitas vezes por “síntese de alto nível” (em inglês:

high-level synthesis) ou por “síntese comportamental” (em inglês: behavioral synthesis).

APÊNDICE F GLOSSÁRIO 245

Definição em [Gajski92]: ''A transformation of a behavioural description into a set of

connected storage and functional units''.

SRAM – Acrónimo para: Static Random-Access Memory. Memória estática de acesso

aleatório.

SRAM FPGA – Tipo de FPGA baseado em tecnologia de memórias estáticas que é

reprogramável no campo e requer dispositivos de arranque externos.

SSA – Acrónimo para: Single Static Assignment. Formato estático de atribuição única.

STG – Acrónimo para: State Transition Graph. Grafo de transição de estados.

THR – Acrónimo para: Tree-Height Reduction. Redução/diminuição da altura de uma árvore

por distribuição paralela dos seus nós (também designado por reassociação de operações).

Unrolling – (por exemplo de ciclos). Utilizado o termo português: desenrolamento.

VHDL – Acrónimo para: VHSIC (Very High Speed Integrated Circuit) Hardware

Description Language. Linguagem de descrição de hardware com ampla aceitação e

normalizada pelo IEEE.

VLIW – Acrónimo para: Very-Long Instruction Width. Tipo de arquitectura em que uma

instrução é utilizada para fornecer dados a várias unidades funcionais com execução

concorrente.

246 APÊNDICE F GLOSSÁRIO

247

Apêndice G Lista de Símbolos ! NOT lógico;

& operação AND;

&& AND lógico;

µ

ν indica que os nós µ e ν são mutuamente exclusivos;

µ → ν indica que o nó µ é executado depois de ν;

≡ coincidente;

∅ conjunto ou lista vazia;

≠ diferente;

⊂ está contido no conjunto ou na lista;

∨ ou lógico;

∈ pertence ao conjunto;

∪ reunião de conjuntos;

℘(ν) identificador da fracção temporal que contém o nó ν;

(µ, v) indica a existência de um laço entre os nós µ e ν;

x retorna o número inteiro mais próximo menor ou igual a x: ceiling(x);

248 APÊNDICE G LISTA DE SÍMBOLOS

| operação OR;

|| OR lógico;

|V| indica o número de elementos do conjunto V;

~ operação de negação;

Area(...) estimativa da área do circuito correspondente a um nó ou a um conjunto de

nós;

ASAPstart(ν) tempo imediatamente antes da execução do nó ν quando o escalonamento é

feito pela ordem ASAP;

Bits(A) número de bits para representar a variável A;

Dom(ν) conjunto de nós do CFG dominados pelo nó ν;

E conjunto de laços de um grafo;

forall para todos os elementos de um conjunto ou lista;

foreach para cada elemento de um conjunto ou lista;

G grafo;

Gen(ν) conjunto de definição geradas no bloco básico ν;

In(ν) conjunto de definição que entram no bloco básico ν;

In(Πi) número de entradas de dados na fracção temporal Πi;

Kill(ν) conjunto de definição mortas no bloco básico ν;

LevelALAP(ν) valor do nível do nó ν quando os níveis são atribuídos pela ordem ALAP;

MAX(A, B) valor máximo entre A e B;

MIN(A, B) valor mínimo entre A e B;

MUX() multiplexagem das entradas especificadas como parâmetros;

APÊNDICE G LISTA DE SÍMBOLOS 249

Op operação aritmética ou lógica;

Out(ν) conjunto de definição que saem do bloco básico ν;

Out(Πi) número de saídas de dados na fracção temporal Πi;

PosDom(ν) conjunto de nós do CFG pós-dominados pelo nó ν;

Pred(ν) conjunto de nós de um grafo predecessores ao nó ν;

sse se e só se;

Succ(ν) conjunto de nós de um grafo sucessores ao nó ν;

thread sequência de instruções que formam blocos computacionais que podem ser

executados concorrentemente ou em paralelo (vulgarmente designadas por

“processos leves”, em virtude de permitirem exprimir concorrência com

granulosidades mais finas do que as utilizadas nos processos);

V conjunto de nós (vértices) de um grafo;

250 APÊNDICE G LISTA DE SÍMBOLOS