package de.fuberlin.optimierung;
import java.util.*;
import de.fuberlin.optimierung.commands.*;
public class LLVM_Function {
String func_define = "";
String afterFunc = "";
//private LLVM_Block startBlock;
//private LLVM_Block endBlock;
private ArrayList<LLVM_Block> blocks;
private int numberBlocks;
private HashMap<String,Integer> labelToBlock = new HashMap<String,Integer>();
private LLVM_RegisterMap registerMap = new LLVM_RegisterMap();
public LLVM_Function(String code) throws LLVM_OptimizationException{
func_define = "define " + code.substring(0, code.indexOf("\n"));
// Fix, weil llc uwtable nicht mag
if (func_define.contains("uwtable")) func_define = func_define.replace("uwtable", "");
code = code.substring(code.indexOf("\n")+1);
afterFunc = code.substring(code.lastIndexOf("}")+1);
code = code.substring(0, code.lastIndexOf("}"));
// Whitespaces und leere Zeilen entfernen
String tmp_code = "";
for (String line : code.split("\n")){
line = line.trim();
if (line.length() == 0) continue;
tmp_code += line + "\n";
}
code = tmp_code;
// add newline after Branch
int searchindex = 0;
boolean search = true;
while(search){
search = code.indexOf("br ", searchindex) >= 0;
if (search){
searchindex = code.indexOf("br ", searchindex) + 3;
int index = code.indexOf('\n', searchindex);
if (index != code.length()-1){
code = code.substring(0, index) + "\n" + code.substring(index);
searchindex = index;
}
}
}
// add newline after Return
searchindex = 0;
search = true;
while(search){
search = code.indexOf("ret ", searchindex) >= 0;
if (search){
searchindex = code.indexOf("ret ", searchindex) + 4;
int index = code.indexOf('\n', searchindex);
if (index != code.length()-1){
code = code.substring(0, index) + "\n" + code.substring(index);
searchindex = index;
}
}
}
String codeBlocks[] = code.split("\n\n");
this.numberBlocks = codeBlocks.length;
this.blocks = new ArrayList<LLVM_Block>(this.numberBlocks);
for(int i = 0; i < this.numberBlocks; i++) {
this.blocks.add(new LLVM_Block(codeBlocks[i],this));
}
//this.startBlock = this.blocks.get(0);
//this.endBlock = this.blocks.get(this.numberBlocks-1);
}
/*
* *********************************************************
* *********** Flussgraph - Erstellung *********************
* *********************************************************
*/
/**
* Erstellt den Flussgraphen zwischen den Bloecken, d.h. die Attribute
* nextBlocks und previousBlocks der Bloecke werden gesetzt.
* Labels werden gegebenenfalls erstellt.
*/
public void createFlowGraph() throws LLVM_OptimizationException{
// Teste, ob Labels gesetzt sind
// Wenn nein, dann erstelle die Labels
/*if(this.numberBlocks>1) {
if(this.blocks.get(1).getLabel().equals("")) {
this.createNewLabels();
}
}*/
this.createNewLabels();
// Erstelle Label zu Block Mapping
this.mapLabelsToBlocks();
// Setze Zeiger
for(LLVM_Block block : this.blocks) { // Durchlaufe Bloecke
LLVM_GenericCommand branchCommand = block.getLastCommand();
if (branchCommand == null) continue;
LinkedList<LLVM_Parameter> operands = branchCommand.getOperands();
if(branchCommand.getOperation()==LLVM_Operation.RET) {
// void-return
// Aktueller Block ist this.endBlock
}
else if(branchCommand.getOperation()==LLVM_Operation.RET_CODE) {
// Return mit Rueckgabewert
// Aktueller Block ist this.endBlock
}
else if(branchCommand.getOperation()==LLVM_Operation.BR) {
// Unbedingter Sprung
String label = operands.getFirst().getName();
Integer blockPosition = this.labelToBlock.get(label);
if(blockPosition!=null) {
block.appendToNextBlocks(this.blocks.get(blockPosition));
this.blocks.get(blockPosition).appendToPreviousBlocks(block);
}
}
else if(branchCommand.getOperation()==LLVM_Operation.BR_CON) {
// Bedingter Sprung
String label1 = operands.get(1).getName();
String label2 = operands.get(2).getName();
Integer blockPosition1 = this.labelToBlock.get(label1);
Integer blockPosition2 = this.labelToBlock.get(label2);
if(blockPosition1!=null) {
block.appendToNextBlocks(this.blocks.get(blockPosition1));
this.blocks.get(blockPosition1).appendToPreviousBlocks(block);
}
if(blockPosition2!=null) {
block.appendToNextBlocks(this.blocks.get(blockPosition2));
this.blocks.get(blockPosition2).appendToPreviousBlocks(block);
}
}
else{
throw new LLVM_OptimizationException("corrupt block-end");
}
}
}
/**
* Setze Labels fuer Bloecke in denen sie noch nicht gesetzt sind
* Neue Labels haben die Form wie z.B. %4
*/
private void createNewLabels() {
String nextUnnamed = "%1";
int nextNumber = 1;
// Erster Block muss nicht betrachtet werden
for(int i=0; i<this.numberBlocks; i++) {
LLVM_Block block = this.blocks.get(i);
// Setze ab zweitem Block das Label
// Nur falls kein Label gesetzt ist
if(i>0 && block.getLabel().equals("")) {
block.setLabel(nextUnnamed);
nextNumber++;
nextUnnamed = "%" + nextNumber;
}
if(!block.isEmpty()) {
LLVM_GenericCommand c = block.getFirstCommand();
while(c!=null) {
LLVM_Parameter p = c.getTarget();
if(p!=null) {
String name = p.getName();
if(name!=null && name.equals(nextUnnamed)) {
nextNumber++;
nextUnnamed = "%" + nextNumber;
}
}
c = c.getSuccessor();
}
} // if block not empty
} // for
}
/**
* Initialisiert die Hashmap labelToBlock, die Labelnamen dem jeweiligen Block zuordnet
* (als Index in this.blocks)
* Wird bei Erstellung des Flussgraphen zwischen den Bloecken benoetigt
*/
private void mapLabelsToBlocks() {
this.labelToBlock.clear();
// Durchlaufe alle Bloecke
for(int i=0; i<this.numberBlocks; i++) {
String label = this.blocks.get(i).getLabel();
this.labelToBlock.put(label, i);
}
}
/*
* *********************************************************
* *********** Registermaps initialisieren *****************
* *********************************************************
*/
/**
* Definition und Verwendungen der Register werden in registerMap abgelegt
* Alte Informationen werden entfernt, aktuelle gesetzt
*/
public void createRegisterMaps() throws LLVM_OptimizationException{
// Loesche alte Werte
this.registerMap.clean();
// Setze neue Werte
for(LLVM_Block block : this.blocks) { // Gehe Bloecke durch
// Ist Block leer?
if(!block.isEmpty()) {
// Gehe Befehle des Blockes durch
LLVM_GenericCommand c = block.getFirstCommand();
while(c!=null) {
// Fuege c in Register Maps ein
this.registerMap.addCommand(c);
c = c.getSuccessor();
}
}
}
}
/*
* *********************************************************
* *********** Globale Lebendigkeit ************************
* *********************************************************
*/
/**
* Erstelle IN und OUT Mengen fuer globale Lebendigkeitsanalyse
* Arbeitet nicht auf Registern, sondern auf Speicheradressen
* Dannach ist zwischen den Bloecken bekannt, ob eine Speicheradresse lebendig ist
* Dient dazu, spaeter ueberfluessige stores und loads entfernen zu koennen
* Vorraussetzung: def und use Mengen der Bloecke sind gesetzt
*/
private void createInOutLiveVariables() {
// Algorithmus siehe Seite 610 Drachenbuch
boolean changes = true;
while(changes) {
changes = false;
for(LLVM_Block b : this.blocks) {
if(b.updateInOutLiveVariables()) {
changes = true;
}
}
}
}
/**
* Erstelle IN OUT Mengen pro Block fuer Lebendigkeitsanalyse
* Entferne anschliessend ueberfluessige Stores
*/
public void globalLiveVariableAnalysis() throws LLVM_OptimizationException{
for(LLVM_Block b : this.blocks) {
b.createDefUseSets();
}
this.createInOutLiveVariables();
for(LLVM_Block b : this.blocks) {
b.deleteDeadStores();
}
}
/*
* *********************************************************
* *********** Reaching Analysis ***************************
* *********************************************************
*/
/**
* Erstelle IN und OUT Mengen fuer Reaching Analyse
* Arbeitet nicht auf Registern, sondern auf Speicheradressen
* Dient dazu, spaeter store/load-paare zusammenfuegen zu koennen
* Vorraussetzung: gen und kill Mengen der Bloecke sind gesetzt
*/
private void createInOutReaching() {
// Algorithmus siehe Seite 607 Drachenbuch
boolean changes = true;
while(changes) {
changes = false;
for(LLVM_Block b : this.blocks) {
if(b.updateInOutReaching()) {
changes = true;
}
}
}
}
/**
* Erstelle IN OUT Mengen pro Block fuer Lebendigkeitsanalyse
* Entferne anschliessend ueberfluessige Stores
*/
public void reachingAnalysis() throws LLVM_OptimizationException{
for(LLVM_Block b : this.blocks) {
b.clearReaching();
}
for(LLVM_Block b : this.blocks) {
b.createGenKillSets();
}
this.createInOutReaching();
for(LLVM_Block b : this.blocks) {
b.foldStoreLoad();
}
}
/*
* *********************************************************
* *********** CommonExpressions ***************************
* *********************************************************
*/
/**
* Löscht alle doppelten Befehle in einem Block
*/
public void removeCommonExpressions () throws LLVM_OptimizationException{
for (LLVM_Block block : blocks){
block.removeCommonExpressions();
}
}
/*
* *********************************************************
* *********** Folding / Propagation ***********************
* *********************************************************
*/
private boolean fold(LLVM_GenericCommand cmd) {
if(cmd.getClass().equals(LLVM_BinaryCommand.class)){
LinkedList<LLVM_Parameter> operands = cmd.getOperands();
LLVM_Parameter op1 = operands.get(0);
LLVM_Parameter op2 = operands.get(1);
try{
if(op1.getType() == LLVM_ParameterType.INTEGER && op2.getType() == LLVM_ParameterType.INTEGER){
int iOP1 = Integer.parseInt(op1.getName());
int iOP2 = Integer.parseInt(op2.getName());
int result = 0;
boolean hasResult = true;
switch(cmd.getOperation()){
case ADD :
result = iOP1 + iOP2;
break;
case SUB :
result = iOP1 - iOP2;
break;
case MUL :
result = iOP1 * iOP2;
break;
case DIV :
result = iOP1 / iOP2;
break;
case SDIV :
result = iOP1 / iOP2;
break;
case UDIV :
result = iOP1 / iOP2;
break;
case UREM :
result = iOP1 % iOP2;
break;
case SREM :
result = iOP1 % iOP2;
break;
case AND :
result = iOP1 & iOP2;
break;
case OR :
result = iOP1 | iOP2;
break;
case XOR :
result = iOP1 ^ iOP2;
break;
case SHL :
result = iOP1 << iOP2;
break;
case LSHR :
result = iOP1 >>> iOP2;
break;
case ASHR :
result = iOP1 >> iOP2;
break;
default:
hasResult = false;
break;
}
if (hasResult){
op1.setName(""+result);
op2.setName("0");
}
return true;
}else if(op1.getType() == LLVM_ParameterType.REGISTER && op2.getType() == LLVM_ParameterType.INTEGER){
int iOP2 = Integer.parseInt(op2.getName());
if(iOP2 == 0){
return true;
}
}else if(op1.getType() == LLVM_ParameterType.DOUBLE && op2.getType() == LLVM_ParameterType.DOUBLE){
double iOP1 = Double.parseDouble(op1.getName());
double iOP2 = Double.parseDouble(op2.getName());
double result = 0;
boolean hasResult = true;
switch(cmd.getOperation()){
case FADD :
result = iOP1 + iOP2;
break;
case FSUB :
result = iOP1 - iOP2;
break;
case FMUL :
result = iOP1 * iOP2;
break;
case FDIV :
result = iOP1 / iOP2;
break;
case FREM :
result = iOP1 % iOP2;
break;
default:
hasResult = false;
break;
}
if (hasResult){
op1.setName(""+result);
op2.setName("0");
}
return true;
}else if(op1.getType() == LLVM_ParameterType.REGISTER && op2.getType() == LLVM_ParameterType.DOUBLE){
double iOP2 = Double.parseDouble(op2.getName());
if(iOP2 == 0){
return true;
}
}
}catch(NumberFormatException e){
// no numbers
}
}else if(cmd.getClass().equals(LLVM_XcmpCommand.class)){
LinkedList<LLVM_Parameter> operands = cmd.getOperands();
LLVM_Parameter op1 = operands.get(0);
LLVM_Parameter op2 = operands.get(1);
try{
if(op1.getType() == LLVM_ParameterType.INTEGER && op2.getType() == LLVM_ParameterType.INTEGER){
int iOP1 = Integer.parseInt(op1.getName());
int iOP2 = Integer.parseInt(op2.getName());
boolean result = false;
boolean hasResult = true;
switch(cmd.getOperation()){
case ICMP_EQ :
result = iOP1 == iOP2;
break;
case ICMP_NE :
result = iOP1 != iOP2;
break;
case ICMP_UGT :
result = iOP1 > iOP2;
break;
case ICMP_UGE :
result = iOP1 >= iOP2;
break;
case ICMP_ULT :
result = iOP1 < iOP2;
break;
case ICMP_ULE :
result = iOP1 <= iOP2;
break;
case ICMP_SGT :
result = iOP1 > iOP2;
break;
case ICMP_SGE :
result = iOP1 >= iOP2;
break;
case ICMP_SLT :
result = iOP1 < iOP2;
break;
case ICMP_SLE :
result = iOP1 <= iOP2;
break;
default:
hasResult = false;
break;
}
if (hasResult){
op1.setName(result?"1":"0");
op2.setName("0");
op1.setTypeString("i1");
}
return true;
}else if(op1.getType() == LLVM_ParameterType.DOUBLE && op2.getType() == LLVM_ParameterType.DOUBLE){
double iOP1 = Double.parseDouble(op1.getName());
double iOP2 = Double.parseDouble(op2.getName());
boolean result = false;
boolean hasResult = true;
switch(cmd.getOperation()){
case FCMP_OEQ :
result = iOP1 == iOP2;
break;
case FCMP_ONE :
result = iOP1 != iOP2;
break;
case FCMP_OGT :
result = iOP1 > iOP2;
break;
case FCMP_OGE :
result = iOP1 >= iOP2;
break;
case FCMP_OLT :
result = iOP1 < iOP2;
break;
case FCMP_OLE :
result = iOP1 <= iOP2;
break;
case FCMP_ORD :
hasResult = false;
break;
case FCMP_UGT :
result = iOP1 > iOP2;
break;
case FCMP_UGE :
result = iOP1 >= iOP2;
break;
case FCMP_ULT :
result = iOP1 < iOP2;
break;
case FCMP_ULE :
result = iOP1 <= iOP2;
break;
case FCMP_UNE :
result = iOP1 != iOP2;
break;
case FCMP_UNO :
hasResult = false;
break;
case FCMP_TRUE :
result = true;
break;
case FCMP_FALSE :
result = false;
break;
default:
hasResult = false;
break;
}
if (hasResult){
op1.setName(result?"1":"0");
op2.setName("0");
op1.setTypeString("i1");
op1.setType(LLVM_ParameterType.INTEGER);
}
return true;
}
}catch(NumberFormatException e){
// no numbers
}
}else if(cmd.getClass().equals(LLVM_BranchCommand.class)){
LinkedList<LLVM_Parameter> operands = cmd.getOperands();
LLVM_Parameter op1 = operands.get(0);
if(cmd.getOperation() == LLVM_Operation.BR_CON){
if(op1.getType() == LLVM_ParameterType.INTEGER){
int iOP = Integer.parseInt(op1.getName());
registerMap.deleteCommand(cmd);
operands.remove(0);
LLVM_Parameter p;
if(iOP == 0){
p = operands.remove(0);
}else{
p = operands.remove(1);
}
cmd.setOperation(LLVM_Operation.BR);
registerMap.addCommand(cmd);
LLVM_Block block = cmd.getBlock();
for(LLVM_Block b : block.getNextBlocks()){
if(p.getName().compareTo(b.getLabel()) == 0){
b.removeFromPreviousBlocks(block);
block.removeFromNextBlocks(b);
break;
}
}
}
}
}
return false;
}
public void constantFolding() throws LLVM_OptimizationException{
LinkedList<LLVM_GenericCommand> changed_cmds = new LinkedList<LLVM_GenericCommand>();
for(LLVM_Block block : blocks){
LLVM_GenericCommand cmd = block.getFirstCommand();
if (cmd == null) continue;
while(!cmd.isLastCommand()){
if(fold(cmd)){
changed_cmds.add(cmd);
}
// next cmd
cmd = cmd.getSuccessor();
}
}
if(changed_cmds.size() > 0){
constantPropagation(changed_cmds);
}
}
public void constantFolding(LinkedList<LLVM_GenericCommand> cmds) {
LinkedList<LLVM_GenericCommand> changed_cmds = new LinkedList<LLVM_GenericCommand>();
for(LLVM_GenericCommand cmd : cmds){
if(fold(cmd)){
changed_cmds.add(cmd);
}
}
if(changed_cmds.size() > 0){
constantPropagation(changed_cmds);
}
}
public void constantPropagation(LinkedList<LLVM_GenericCommand> cmds) {
LinkedList<LLVM_GenericCommand> changed_cmds = new LinkedList<LLVM_GenericCommand>();
for(LLVM_GenericCommand cmd : cmds) {
LinkedList<LLVM_GenericCommand> uses = registerMap.getUses(cmd.getTarget().getName());
if(uses != null){
LinkedList<LLVM_GenericCommand> _cmds = (LinkedList<LLVM_GenericCommand>) uses.clone();
for(int j = 0; j < _cmds.size(); j++){
LinkedList<LLVM_Parameter> operands = _cmds.get(j).getOperands();
for(int k = 0; k < operands.size(); k++){
if(cmd.getTarget().getName().equals(operands.get(k).getName())){
if(!changed_cmds.contains(_cmds.get(j)))
changed_cmds.add(_cmds.get(j));
LLVM_Parameter op = cmd.getOperands().get(0);
registerMap.deleteCommand(_cmds.get(j));
//registerMap.deleteCommand(_cmds.get(j), cmd.getTarget());
//operands.get(k).setName(op.getName());
operands.set(k, new LLVM_Parameter(op.getName(),
op.getType(), operands.get(k).getTypeString()));
//operands.set(k, new LLVM_Parameter(op.getName(), op.getType(), op.getTypeString()));
registerMap.addCommand(_cmds.get(j));
}
}
}
}
cmd.deleteCommand("constantPropagation");
registerMap.deleteCommand(cmd);
}
if(changed_cmds.size() > 0){
constantFolding(changed_cmds);
}
}
/*
* *********************************************************
* *********** Tote Register entfernen *********************
* *********************************************************
*/
/**
* Teste, ob gegebenes Register nicht verwendet wird
* Wenn es tot ist, so wird die Definition geloescht
* @param registerName Name des Registers
* @return geloeschte Definition (um spaeter Operanden zu testen) oder null, falls nichts geloescht wurde
*/
private LLVM_GenericCommand eliminateDeadRegister(String registerName) {
// Teste, ob Verwendungen existieren
if(!this.registerMap.existsUses(registerName) &&
this.registerMap.existsDefintion(registerName)) {
// keine Verwendungen, aber eine Definition
LLVM_GenericCommand c = this.registerMap.getDefinition(registerName);
// Nur entfernen, wenn c kein call-Befehl ist
if(c.getOperation()!=LLVM_Operation.CALL) {
this.registerMap.deleteCommand(c);
c.deleteCommand("eliminateDeadRegister - normal");
return c;
}
return null;
}
// Wenn einzige Verwendung ein Store, dann löschen
if (this.registerMap.existsUses(registerName) &&
this.registerMap.existsDefintion(registerName)) {
LinkedList<LLVM_GenericCommand> uses = this.registerMap.getUses(registerName);
LLVM_GenericCommand def = this.registerMap.getDefinition(registerName);
if(uses.size() == 1 && uses.get(0).getOperation() == LLVM_Operation.STORE
&& def.getOperation() == LLVM_Operation.ALLOCA){
LLVM_GenericCommand store = uses.get(0);
this.registerMap.deleteCommand(store);
store.deleteCommand("eliminateDeadRegister - store");
return store;
}
}
return null;
}
/**
* Register in Operanden der uebergebenen Befehle werden auf spaetere Verwendung getestet
* Diese Befehle wurden bereits geloescht
* Werden sie nich verwendet, so wird die Definition des Registers geloescht
* @param list zu testende Befehle
* @return geloeschte Definitionen (um Operanden nochmals testen zu koennen)
*/
public LinkedList<LLVM_GenericCommand> eliminateDeadRegistersFromList(LinkedList<LLVM_GenericCommand> list) {
LinkedList<LLVM_GenericCommand> deletedCommands = new LinkedList<LLVM_GenericCommand>();
// Teste, ob Operanden aus list geloescht werden koennen
for(LLVM_GenericCommand c : list) {
LinkedList<LLVM_Parameter> operands = c.getOperands();
if(operands!=null) {
for(LLVM_Parameter op : operands) {
if(op.getType()==LLVM_ParameterType.REGISTER) {
LLVM_GenericCommand del = this.eliminateDeadRegister(op.getName());
if(del!=null)
deletedCommands.addFirst(del);
}
}
}
}
return deletedCommands;
}
/**
* Tote Register werden aus Programm entfernt, d.h. ihre Definitionen werden geloescht
* Funktion wird einmal komplett durchgegangen, Abhaengigkeiten werden nicht aufgeloest
* Geloeschte Befehle werden zurueckgegeben, um spaeter die Operanden testen zu koennen
* Die Register-Maps (Definition und Verwendung) muessen aktuell sein
* @return Geloeschte Befehle
*/
private LinkedList<LLVM_GenericCommand> eliminateDeadRegistersGlobal() {
LinkedList<LLVM_GenericCommand> deletedCommands = new LinkedList<LLVM_GenericCommand>();
String registerNames[] = this.registerMap.getDefinedRegisterNames().
toArray(new String[0]);
// Iteriere ueber alle definierten Register
for(String registerName : registerNames) {
// Teste fuer jedes Register r, ob Verwendungen existieren
// c ist geloeschter Befehl (Definition) oder null, falls
// es nich geloescht werden kann
LLVM_GenericCommand c = this.eliminateDeadRegister(registerName);
if(c!=null)
deletedCommands.addFirst(c);
}
return deletedCommands;
}
/**
* Tote Register werden aus Programm entfernt, d.h. ihre Definitionen werden geloescht
* Abhaengigkeiten von toten Registern werden abgearbeitet
* eliminateDeadRegistersGlobal und eliminateDeadRegistersFromList werden als
* Unterfunktionen verwendet
*/
public void eliminateDeadRegisters() throws LLVM_OptimizationException{
LinkedList<LLVM_GenericCommand> deletedCommands;
deletedCommands = this.eliminateDeadRegistersGlobal();
// Bisher geloeschte Befehle koennen Operanden enthalten, die nun keine Verwendung mehr haben
// Dann koennen diese ebenfalls geloescht werden
// Teste also geloeschte Befehle durch, bis nichts mehr geloescht werden kann
while(!deletedCommands.isEmpty()) {
deletedCommands = this.eliminateDeadRegistersFromList(deletedCommands);
}
}
/*
* *********************************************************
* *********** Tote Bloecke entfernen **********************
* *********************************************************
*/
/**
* Tote Bloecke, d.h. Bloecke, die im Flussgraph nicht erreichbar sind,
* werden entfernt.
* Definitionen von Registern, deren einzige Verwendung innerhalb eines geloeschten
* Blocks waren, werden geloescht. Dead register elimination ist anschliessend
* nicht extra noetig.
* @return Bloecke, die geloescht wurden, um anschliessend die Kinder zu testen
*/
private LinkedList<LLVM_Block> eliminateDeadBlocksGlobal() {
LinkedList<LLVM_GenericCommand> deletedCommands = new LinkedList<LLVM_GenericCommand>();
LinkedList<LLVM_Block> deletedBlocks = new LinkedList<LLVM_Block>();
for(int i=1; i<this.numberBlocks; i++) {
LLVM_Block block = this.blocks.get(i);
if(!block.hasPreviousBlocks()) {
// Block hat keine Vorgaenger, kann entfernt werden
block.deleteBlock(); // aus Flussgraphen entfernen
deletedBlocks.add(block);
// Befehle des Blocks zu deletedCommands hinzufuegen
if(!block.isEmpty()) {
// Gehe Befehle des Blockes durch
LLVM_GenericCommand c = block.getFirstCommand();
while(c!=null) {
// Fuege c in deletedCommands ein
deletedCommands.add(c);
c = c.getSuccessor();
}
}
}
}
// Entferne geloeschte Bloecke aus this.blocks
for(LLVM_Block block : deletedBlocks) {
this.blocks.remove(block);
this.numberBlocks--;
}
// Entferne geloeschte Befehle aus Register-Hashmaps
// und entferne Definitionen von Registern mit einziger Verwendung in
// einem geloeschten Block
for(LLVM_GenericCommand c : deletedCommands) {
this.registerMap.deleteCommand(c);
}
while(!deletedCommands.isEmpty()) {
deletedCommands = this.eliminateDeadRegistersFromList(deletedCommands);
}
return deletedBlocks;
}
/**
* Tote Bloecke, d.h. Bloecke, die im Flussgraph nicht erreichbar sind,
* werden entfernt.
* Es werden nicht alle Bloecke getestet, sondern nur Kindbloecke der uebergebenen Liste.
* Definitionen von Registern, deren einzige Verwendung innerhalb eines geloeschten
* Blocks waren, werden geloescht. Dead register elimination ist anschliessend
* nicht extra noetig.
* @return Bloecke, die geloescht wurden, um anschliessend die Kinder zu testen
*/
private LinkedList<LLVM_Block> eliminateDeadBlocksFromList(
LinkedList<LLVM_Block> blocks) {
LinkedList<LLVM_GenericCommand> deletedCommands = new LinkedList<LLVM_GenericCommand>();
LinkedList<LLVM_Block> deletedBlocks = new LinkedList<LLVM_Block>();
for(LLVM_Block father : blocks) {
for(LLVM_Block block : father.getNextBlocks()) {
// block wird getestet
if(!block.hasPreviousBlocks() && this.blocks.contains(block)) {
// Block hat keine Vorgaenger, kann entfernt werden
block.deleteBlock(); // aus Flussgraphen entfernen
deletedBlocks.add(block);
// Befehle des Blocks zu deletedCommands hinzufuegen
if(!block.isEmpty()) {
// Gehe Befehle des Blockes durch
LLVM_GenericCommand c = block.getFirstCommand();
while(c!=null) {
// Fuege c in deletedCommands ein
deletedCommands.add(c);
c = c.getSuccessor();
}
}
}
}
}
// Entferne geloeschte Bloecke aus this.blocks
for(LLVM_Block block : deletedBlocks) {
this.blocks.remove(block);
this.numberBlocks--;
}
// Entferne geloeschte Befehle aus Register-Hashmaps
// und entferne Definitionen von Registern mit einziger Verwendung in
// einem geloeschten Block
for(LLVM_GenericCommand c : deletedCommands) {
this.registerMap.deleteCommand(c);
}
while(!deletedCommands.isEmpty()) {
deletedCommands = this.eliminateDeadRegistersFromList(deletedCommands);
}
return deletedBlocks;
}
/**
* Tote Bloecke werden aus dem Programm entfernt
* Operanden der geloeschten Befehle werden auf weitere Verwendungen getestet
* und gegebenenfalls ebenfalls geloescht
* Abhaengigkeiten zwischen Bloecken werden aufgeloest
*/
public void eliminateDeadBlocks() throws LLVM_OptimizationException{
LinkedList<LLVM_Block> deletedBlocks;
deletedBlocks = this.eliminateDeadBlocksGlobal();
// Loesche gegebenenfalls Nachfolgebloecke eines schon geloeschten Blocks
while(!deletedBlocks.isEmpty()) {
deletedBlocks = this.eliminateDeadBlocksFromList(deletedBlocks);
}
}
/**
* Entferne Bloecke, die nur unbedingten Sprungbefehl enthalten
*/
public void deleteEmptyBlocks() throws LLVM_OptimizationException{
LLVM_Block nextFirst = null;
LLVM_Block lastFirst = null;
// Gehe Bloecke durch
LinkedList<LLVM_Block> toDelete = new LinkedList<LLVM_Block>();
for(LLVM_Block actualBlock : this.blocks) {
//if(actualBlock!=this.blocks.get(0)) {
// Enthaelt Block nur einen unbedingten Sprungbefehl?
if(!actualBlock.isEmpty() && actualBlock.getFirstCommand().
getOperation()==LLVM_Operation.BR) {
// Block kann geloescht werden
LLVM_Block targetBlock = actualBlock.getNextBlocks().getFirst();
String targetBlockLabel = targetBlock.getLabel();
String actualBlockLabel = actualBlock.getLabel();
if(actualBlock==this.blocks.get(0)) {
toDelete.add(actualBlock);
targetBlock.removeFromPreviousBlocks(actualBlock);
actualBlock.removeFromNextBlocks(targetBlock);
nextFirst = targetBlock;
lastFirst = actualBlock;
break;
}
// Gehe Vorgaengerbloecke durch
for(LLVM_Block previousBlock : actualBlock.getPreviousBlocks()) {
// Hole Sprungbefehl des Vorgaengerblocks
// Dieser muss angepasst werden
LLVM_GenericCommand branchCommand = previousBlock.getLastCommand();
// Befehl aus Registermap austragen
this.registerMap.deleteCommand(branchCommand);
for(LLVM_Parameter p : branchCommand.getOperands()){
if(actualBlockLabel.equals(p.getName())){
p.setName(targetBlockLabel);
}
}
// Setze Registermapeintrag neu
this.registerMap.addCommand(branchCommand);
// Passe Flussgraph an:
// previousBlock hat actualBlock nicht mehr als Nachfolger,
// sondern targetBlock
// targetBlock hat previousBlock als Vorgaenger
targetBlock.appendToPreviousBlocks(previousBlock);
targetBlock.removeFromPreviousBlocks(actualBlock);
previousBlock.appendToNextBlocks(targetBlock);
previousBlock.removeFromNextBlocks(actualBlock);
}
toDelete.add(actualBlock);
}else if (!actualBlock.isEmpty() && actualBlock.getPreviousBlocks().size() > 0 && (actualBlock.getFirstCommand().
getOperation()==LLVM_Operation.RET || actualBlock.getFirstCommand().
getOperation()==LLVM_Operation.RET_CODE)){
if(actualBlock==this.blocks.get(0)) {
continue;
}
for(LLVM_Block previousBlock : actualBlock.getPreviousBlocks()) {
LLVM_GenericCommand branchCommand = previousBlock.getLastCommand();
if(branchCommand.getOperation()==LLVM_Operation.BR_CON)
return;
}
// Gehe Vorgaengerbloecke durch
for(LLVM_Block previousBlock : actualBlock.getPreviousBlocks()) {
// Hole Sprungbefehl des Vorgaengerblocks
// Dieser muss ersetzt werden
LLVM_GenericCommand branchCommand = previousBlock.getLastCommand();
// Befehl aus Registermap austragen
this.registerMap.deleteCommand(branchCommand);
// Clone für Registermap erstellen
LLVM_GenericCommand tmp = new LLVM_ReturnCommand(actualBlock.getFirstCommand().toString(), branchCommand.getPredecessor(), previousBlock);
branchCommand.replaceCommand(tmp);
// Setze Registermapeintrag neu
this.registerMap.addCommand(tmp);
// Passe Flussgraph an:
// previousBlock hat actualBlock nicht mehr als Nachfolger,
previousBlock.removeFromNextBlocks(actualBlock);
}
toDelete.add(actualBlock);
}
//}
}
if(nextFirst!=null) {
int index = this.blocks.indexOf(nextFirst);
this.blocks.set(0, nextFirst);
this.blocks.set(index, lastFirst);
}
// Alle gelöschten Blöcke entfernen
for (LLVM_Block del : toDelete){
// Entferne zu loeschenden Block aus Flussgraph
//del.deleteBlock();
// Entferne Befehle aus entferntem Block aus Registermap
this.registerMap.deleteCommand(del.getFirstCommand());
// Entferne zu loeschenden Block aus this.blocks
this.blocks.remove(del);
this.numberBlocks--;
}
if(nextFirst!=null) {
this.deleteEmptyBlocks();
}
}
/*
* *********************************************************
* *********** Strength Reduction **************************
* *********************************************************
*/
/**
* Ersetze Multiplikationen/Divisionen mit Zweierpotenz durch
* schneller zu berechnende Bitshifts in gegebenem Befehl c.
* Hilfsfunktion fuer strengthReduction.
* @param c gegebener Befehl
*/
private void commandStrengthReduction(LLVM_GenericCommand c) {
if(c.getOperation()==LLVM_Operation.MUL) {
// Multiplikation gefunden
LinkedList<LLVM_Parameter> operands = c.getOperands();
LLVM_Parameter o = operands.getFirst();
if(o.getType()==LLVM_ParameterType.INTEGER) {
// Im ersten Operanden koennte eine Zweierpotenz stehen
int powerOfTwo = 1;
for(int i=1; i<32; i++) {
powerOfTwo = powerOfTwo * 2;
if ( (new Integer(powerOfTwo)).toString().equals(o.getName()) ) {
// Passende Zweierpotenz wurde gefunden
LLVM_Parameter sndOperand = operands.get(1);
LLVM_Parameter tmp = new LLVM_Parameter(sndOperand.getName(),
sndOperand.getType(), sndOperand.getTypeString());
sndOperand.setName((new Integer(i)).toString());
sndOperand.setType(LLVM_ParameterType.INTEGER);
sndOperand.setTypeString(o.getTypeString());
operands.set(0, tmp);
c.setOperation(LLVM_Operation.SHL);
}
}
}
else {
o = operands.get(1);
if(o.getType()==LLVM_ParameterType.INTEGER) {
// Im zweiten Operanden koennte eine Zweierpotenz stehen
int powerOfTwo = 1;
for(int i=1; i<32; i++) {
powerOfTwo = powerOfTwo * 2;
if ( (new Integer(powerOfTwo)).toString().equals(o.getName()) ) {
// Passende Zweierpotenz wurde gefunden
c.setOperation(LLVM_Operation.SHL);
o.setName((new Integer(i)).toString());
}
}
}
}
}
else if(c.getOperation()==LLVM_Operation.SDIV) {
// Division gefunden
LinkedList<LLVM_Parameter> operands = c.getOperands();
LLVM_Parameter o = operands.get(1);
if(o.getType()==LLVM_ParameterType.INTEGER) {
// Im zweiten Operanden koennte eine Zweierpotenz stehen
int powerOfTwo = 1;
for(int i=1; i<32; i++) {
powerOfTwo = powerOfTwo * 2;
if ( (new Integer(powerOfTwo)).toString().equals(o.getName()) ) {
// Passende Zweierpotenz wurde gefunden
c.setOperation(LLVM_Operation.ASHR);
o.setName((new Integer(i)).toString());
}
}
}
}
else if(c.getOperation()==LLVM_Operation.UDIV) {
// Division gefunden
LinkedList<LLVM_Parameter> operands = c.getOperands();
LLVM_Parameter o = operands.get(1);
if(o.getType()==LLVM_ParameterType.INTEGER) {
// Im zweiten Operanden koennte eine Zweierpotenz stehen
int powerOfTwo = 1;
for(int i=1; i<32; i++) {
powerOfTwo = powerOfTwo * 2;
if ( (new Integer(powerOfTwo)).toString().equals(o.getName()) ) {
// Passende Zweierpotenz wurde gefunden
c.setOperation(LLVM_Operation.LSHR);
o.setName((new Integer(i)).toString());
}
}
}
}
}
/**
* Ersetze Multiplikationen/Divisionen mit Zweierpotenz durch
* schneller zu berechnende Bitshifts
*/
public void strengthReduction() throws LLVM_OptimizationException{
for(LLVM_Block b : this.blocks) {
if(!b.isEmpty()) {
for(LLVM_GenericCommand c = b.getFirstCommand(); c!=null; c=c.getSuccessor()) {
this.commandStrengthReduction(c);
}
}
}
}
/*
* *********************************************************
* *********** Labels zur Ausgabe anpassen *****************
* *********************************************************
*/
/**
* Aendere den Namen aller Operanden mit Namen oldName in c zu newName.
* @param c Befehl, dessen Operanden durchsucht werden
* @param oldName zu aendernder Name
* @param newName neu zu setzender Name
*/
private void changeOperandName(LLVM_GenericCommand c, String oldName, String newName) {
LinkedList<LLVM_Parameter> operands = c.getOperands();
for(LLVM_Parameter o : operands) {
if(o.getName().equals(oldName)) {
o.setName(newName);
}
}
}
/**
* Durch das Loeschen von Befehlen kann nach %2=... ein %4=... folgen.
* Dies ist nicht erlaubt, diese Funktion passt die Namen an.
* Achtung: nur direkt vor der Ausgabe des Codes nutzen, Hashmaps
* werden nicht aktualisiert.
*/
public void updateUnnamedLabelNames() throws LLVM_OptimizationException{
String nextUnnamed = "%1";
int nextNumber = 1;
// Erster Block muss nicht betrachtet werden
for(int i=0; i<this.numberBlocks; i++) {
LLVM_Block block = this.blocks.get(i);
if(i==0) {
block.setLabel("");
}
// Teste ab zweitem Block das Label
if(i>0) {
String label = block.getLabel();
// Ist es ein unbenanntes Label?
if(label!=null && label.matches("%[1-9][0-9]*")) {
// Ist es nicht der folgende Bezeichner?
if(!label.equals(nextUnnamed)) {
// Setze Label auf nextUnnamed
block.setLabel(nextUnnamed);
// Setze alle Verwendungen auf nextUnnamed
LinkedList<LLVM_GenericCommand> uses = this.registerMap.getUses(label);
if(uses != null){
for(LLVM_GenericCommand u : uses) {
this.changeOperandName(u, label, nextUnnamed);
}
}
}
nextNumber++;
nextUnnamed = "%" + nextNumber;
}
}
// Gehe Befehle des Blocks durch
if(!block.isEmpty()) {
LLVM_GenericCommand c = block.getFirstCommand();
while(c!=null) {
LLVM_Parameter p = c.getTarget();
if(p!=null) {
String name = p.getName();
// Ist name unbenannenter Bezeichner?
if(name!=null && name.matches("%[1-9][0-9]*")) {
// Ist es nicht der folgende Bezeichner?
if(!name.equals(nextUnnamed)) {
// Ersetze in Definition durch nextUnnamed
p.setName(nextUnnamed);
// Ersetze in allen Verwendungen durch nextUnnamed
LinkedList<LLVM_GenericCommand> uses = this.registerMap.getUses(name);
if(uses != null) {
for(LLVM_GenericCommand u : uses) {
this.changeOperandName(u, name, nextUnnamed);
}
}
}
nextNumber++;
nextUnnamed = "%" + nextNumber;
}
}
c = c.getSuccessor();
}
} // if block not empty
} // for
}
/*
* *********************************************************
* *********** Setter / Getter / toString ******************
* *********************************************************
*/
public LLVM_RegisterMap getRegisterMap() {
return registerMap;
}
public ArrayList<LLVM_Block> getBlocks() {
return blocks;
}
public String toString() {
String output = func_define + "\n";
int i = 0;
for (i = 0; i < this.numberBlocks-1; i++) {
output += blocks.get(i).toString()+"\n";
}
output += blocks.get(i).toString();
output += "}\n";
output += this.afterFunc;
return output;
}
public String toGraph() {
// Workaround
blocks.get(0).setLabel("%0");
String graph = "digraph g { graph [fontsize=30 labelloc=\"t\" label=\"\" splines=true overlap=false rankdir = \"TD\"]; ratio = auto;";
for (int i = 0; i < this.numberBlocks; i++) {
graph += blocks.get(i).toGraph();
}
LinkedList<LLVM_Block> nxt_Blocks;
for (int i = 0; i < this.numberBlocks; i++) {
nxt_Blocks = blocks.get(i).getNextBlocks();
for(LLVM_Block b : nxt_Blocks){
graph += "\""+blocks.get(i).getLabel()+"\" -> \""+b.getLabel()+"\" [ penwidth = 1 fontsize = 14 fontcolor = \"grey28\" label = \"\" ];";
}
}
return graph + "}";
}
}