From 89e08ac1a3768cce967fb8aebb961cf84064dbf0 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Mon, 22 May 2023 09:35:00 +0100 Subject: [PATCH 01/69] Add basic structure of RegisterAllocation class --- .../pt/up/fe/comp2023/ollir/Optimization.java | 15 +++++++ .../optimization/RegisterAllocation.java | 41 +++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index e5652b9..94d773c 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -1,5 +1,9 @@ package pt.up.fe.comp2023.ollir; +import org.specs.comp.ollir.ClassUnit; +import org.specs.comp.ollir.Instruction; +import org.specs.comp.ollir.Method; +import org.specs.comp.ollir.OllirErrorException; import pt.up.fe.comp.jmm.analysis.JmmSemanticsResult; import pt.up.fe.comp.jmm.analysis.table.Symbol; import pt.up.fe.comp.jmm.analysis.table.SymbolTable; @@ -11,10 +15,13 @@ import pt.up.fe.comp2023.ollir.OllirUtils; import pt.up.fe.comp2023.optimization.ConstantFolding; import pt.up.fe.comp2023.optimization.ConstantPropagation; +import pt.up.fe.comp2023.optimization.RegisterAllocation; import pt.up.fe.comp2023.semantic.MySymbolTable; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class Optimization extends AJmmVisitor implements JmmOptimization { String code = ""; @@ -45,6 +52,14 @@ public JmmSemanticsResult optimize(JmmSemanticsResult semanticsResult) { return semanticsResult; } + public OllirResult optimize(OllirResult ollirResult) { + ClassUnit classUnit = ollirResult.getOllirClass(); + + for(Method method : classUnit.getMethods()) + new RegisterAllocation(method); + return ollirResult; + } + @Override protected void buildVisitor() { setDefaultVisit(this::visitAllChildren); diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java new file mode 100644 index 0000000..2269c4d --- /dev/null +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -0,0 +1,41 @@ +package pt.up.fe.comp2023.optimization; + +import org.specs.comp.ollir.Element; +import org.specs.comp.ollir.Instruction; +import org.specs.comp.ollir.Method; + +import java.util.*; + +public class RegisterAllocation { + private Method method; + private Map> defs = new HashMap<>(); + private Map> uses = new HashMap<>(); + private Map> in = new HashMap<>(); + private Map> out = new HashMap<>(); + public RegisterAllocation(Method method) { + this.method = method; + method.buildCFG(); + + for (Instruction instruction : method.getInstructions()){ + this.defs.put(instruction, getDef(instruction)); + this.uses.put(instruction, getUse(instruction)); + } + + computeInOuts(); + } + + public Set getDef(Instruction instruction){ + //TODO + return new HashSet(); + + } + + public Set getUse(Instruction instruction){ + //TODO + return new HashSet(); + } + + public void computeInOuts() { + //TODO + } +} From 5e6300977143a179020a4525c3e1b0cbddc8c62d Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Mon, 22 May 2023 17:50:20 +0100 Subject: [PATCH 02/69] Add methods to compute def and use of each instruction --- .../optimization/RegisterAllocation.java | 72 +++++++++++++++---- 1 file changed, 60 insertions(+), 12 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java index 2269c4d..70f7e94 100644 --- a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -1,13 +1,17 @@ package pt.up.fe.comp2023.optimization; -import org.specs.comp.ollir.Element; -import org.specs.comp.ollir.Instruction; -import org.specs.comp.ollir.Method; +import org.specs.comp.ollir.*; -import java.util.*; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.Map; + +import static org.specs.comp.ollir.InstructionType.ASSIGN; public class RegisterAllocation { - private Method method; + private final Method method; private Map> defs = new HashMap<>(); private Map> uses = new HashMap<>(); private Map> in = new HashMap<>(); @@ -16,23 +20,67 @@ public RegisterAllocation(Method method) { this.method = method; method.buildCFG(); + //TODO: remove + System.out.println(method.getMethodName()); + System.out.println("------------------"); + for (Instruction instruction : method.getInstructions()){ this.defs.put(instruction, getDef(instruction)); - this.uses.put(instruction, getUse(instruction)); - } + this.uses.put(instruction, getUse(instruction, new HashSet<>())); + //TODO: remove + instruction.show(); + System.out.println("Defs:" + defs.get(instruction)); + System.out.println("Uses:" + uses.get(instruction)); + } computeInOuts(); } public Set getDef(Instruction instruction){ - //TODO - return new HashSet(); + Set def = new HashSet<>(); + if(instruction.getInstType() == ASSIGN) { + AssignInstruction assignInst = (AssignInstruction)instruction; + def.add(assignInst.getDest()); + } + return def; } - public Set getUse(Instruction instruction){ - //TODO - return new HashSet(); + public Set getUse(Instruction instruction, Set result){ + switch (instruction.getInstType()) { + case ASSIGN -> { + AssignInstruction assignInst = (AssignInstruction) instruction; + return getUse(assignInst.getRhs(), result); + } + case CALL -> { + CallInstruction callInst = (CallInstruction) instruction; + List arguments = callInst.getListOfOperands(); + for (Element argument : arguments) { + if (!argument.isLiteral()) + result.add(argument); + } + } + case RETURN -> { + ReturnInstruction returnInst = (ReturnInstruction) instruction; + Element returnElement = returnInst.getOperand(); + if (returnElement != null && !returnElement.isLiteral()) + result.add(returnElement); + } + case BINARYOPER -> { + BinaryOpInstruction binInst = (BinaryOpInstruction) instruction; + if (!binInst.getLeftOperand().isLiteral()) + result.add(binInst.getLeftOperand()); + if (!binInst.getRightOperand().isLiteral()) + result.add(binInst.getRightOperand()); + } + case NOPER -> { + SingleOpInstruction singleOpInstruction = (SingleOpInstruction) instruction; + Element operand = singleOpInstruction.getSingleOperand(); + if (!operand.isLiteral()) + result.add(operand); + } + } + return result; } public void computeInOuts() { From 91f2386ad28d440b49bb390c68b4077ae6b6cc97 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Mon, 22 May 2023 17:54:09 +0100 Subject: [PATCH 03/69] change to grammar --- src/main/antlr/comp2023/grammar/Javamm.g4 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/antlr/comp2023/grammar/Javamm.g4 b/src/main/antlr/comp2023/grammar/Javamm.g4 index ebfd873..830cde8 100644 --- a/src/main/antlr/comp2023/grammar/Javamm.g4 +++ b/src/main/antlr/comp2023/grammar/Javamm.g4 @@ -58,6 +58,8 @@ statement expression : '(' expression ')' #ParenthesesExpr + | 'new' 'int' '[' expression ']' #ArrayCreation + | 'new' classname=ID '(' ')' #ObjectCreation | expression '[' expression ']' #ArraySubscript | expression '.' field='length' #LengthFieldAccess | expression '.' methodcall=ID '(' methodCallParameters ')' #MethodCall @@ -67,8 +69,6 @@ expression | expression op=('<' | '>') expression #ComparisonExpr | expression op='&&' expression #LogicalExpr | expression op='||' expression #LogicalExpr - | 'new' 'int' '[' expression ']' #ArrayCreation - | 'new' classname=ID '(' ')' #ObjectCreation | value=INT #Integer | value=('true' | 'false') #Boolean | 'this' #This From a1069cf110ea36af79da2c4010b4377a9389e478 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Mon, 22 May 2023 17:55:14 +0100 Subject: [PATCH 04/69] aa --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index 4e89ec7..81bdad0 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -188,6 +188,8 @@ private Void dealWithObjectCreation(JmmNode jmmNode, Void unused) { } private Void dealWithArrayCreation(JmmNode jmmNode, Void unused) { + JmmNode size = jmmNode.getChildren().get(0); + String for (var child : jmmNode.getChildren()) visit(child); From db390b04a8c492eacaceef514908dfdea7d1b3f7 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Mon, 22 May 2023 17:56:28 +0100 Subject: [PATCH 05/69] hotfix grammar --- src/main/antlr/comp2023/grammar/Javamm.g4 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/antlr/comp2023/grammar/Javamm.g4 b/src/main/antlr/comp2023/grammar/Javamm.g4 index f2425c7..68b3c62 100644 --- a/src/main/antlr/comp2023/grammar/Javamm.g4 +++ b/src/main/antlr/comp2023/grammar/Javamm.g4 @@ -58,6 +58,8 @@ statement expression : '(' expression ')' #ParenthesesExpr + | 'new' 'int' '[' expression ']' #ArrayCreation + | 'new' classname=ID '(' ')' #ObjectCreation | expression '[' expression ']' #ArraySubscript | expression '.' field='length' #LengthFieldAccess | expression '.' methodcall=ID '(' methodCallParameters ')' #MethodCall @@ -67,8 +69,6 @@ expression | expression op=('<' | '>') expression #ComparisonExpr | expression op='&&' expression #LogicalExpr | expression op='||' expression #LogicalExpr - | 'new' 'int' '[' expression ']' #ArrayCreation - | 'new' classname=ID '(' ')' #ObjectCreation | value=INT #Integer | value=('true' | 'false') #Boolean | 'this' #This From 5742fac288b0460d2e4adb114eb8ee69400095a7 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Mon, 22 May 2023 22:50:40 +0100 Subject: [PATCH 06/69] Add utils methods compute union and difference of sets --- .../optimization/OptimizationUtils.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java index 648c113..b34e64a 100644 --- a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java +++ b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java @@ -1,6 +1,10 @@ package pt.up.fe.comp2023.optimization; +import org.specs.comp.ollir.Element; + +import java.util.HashSet; import java.util.Map; +import java.util.Set; public class OptimizationUtils { public static void intersectMaps (Map map1, Map map2, Map result){ @@ -14,4 +18,18 @@ public static void intersectMaps (Map map1, Map result.put(key, value); } } + + public static Set differenceSets (Set set1, Set set2){ + Set result = new HashSet<>(set1); + result.removeAll(set2); + + return result; + } + + public static Set unionSets (Set set1, Set set2){ + Set result = new HashSet<>(set1); + result.addAll(set2); + + return result; + } } From bdc427b92da87b8cc229ab06a8516004aa08bcd4 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Mon, 22 May 2023 22:51:27 +0100 Subject: [PATCH 07/69] Implement method to compute liveIn and liveOut --- .../optimization/RegisterAllocation.java | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java index 70f7e94..4bcaeab 100644 --- a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -9,6 +9,8 @@ import java.util.Map; import static org.specs.comp.ollir.InstructionType.ASSIGN; +import static pt.up.fe.comp2023.optimization.OptimizationUtils.differenceSets; +import static pt.up.fe.comp2023.optimization.OptimizationUtils.unionSets; public class RegisterAllocation { private final Method method; @@ -33,7 +35,7 @@ public RegisterAllocation(Method method) { System.out.println("Defs:" + defs.get(instruction)); System.out.println("Uses:" + uses.get(instruction)); } - computeInOuts(); + computeLiveInOuts(); } public Set getDef(Instruction instruction){ @@ -83,7 +85,36 @@ public Set getUse(Instruction instruction, Set result){ return result; } - public void computeInOuts() { - //TODO + public void computeLiveInOuts() { + for (Instruction instruction : method.getInstructions()){ + this.in.put(instruction, new HashSet<>()); + this.out.put(instruction, new HashSet<>()); + } + + boolean liveChanged; + do { + liveChanged = false; + for(Instruction instruction : method.getInstructions()){ + //Save current liveIn and liveOut + Set liveInAux = new HashSet<>(this.in.get(instruction)); + Set liveOutAux = new HashSet<>(this.out.get(instruction)); + + //Update liveIn + Set difference = differenceSets(this.out.get(instruction), this.defs.get(instruction)); + Set newLiveIn = unionSets(this.uses.get(instruction), difference); + + //Update liveOut + Set newLiveOut = new HashSet<>(); + for(Node node : instruction.getSuccessors()){ + Instruction successor = (Instruction) node; + newLiveOut.addAll(this.in.get(successor)); + } + this.out.put(instruction, newLiveOut); + + //Check if liveIn or liveOut changed + if(!liveOutAux.equals(newLiveOut) || !liveInAux.equals(newLiveIn)) + liveChanged = true; + } + } while(liveChanged); } } From 59331a894ab8c3dd8ad96f23fba3b128377defb8 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Tue, 23 May 2023 11:03:56 +0100 Subject: [PATCH 08/69] fix if --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index 81bdad0..75d0da0 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -80,11 +80,11 @@ private Void dealWithCycle(JmmNode jmmNode, Void unused) { } private Void dealWithCondition(JmmNode jmmNode, Void unused) { - code += "\t\t"; visit(jmmNode.getJmmChild(0)); + code += "\t\t"; visit(jmmNode.getJmmChild(0)); var ifId = tempVarId++; // Condition statement - code += "\t\tif (" + temp + ") goto if" + ifId + ";\n"; + code += "\t\tif (" + jmmNode.getJmmChild(0).get("valueOl") + ") goto if" + ifId + ";\n"; // What occurs if the condition isn't met code += "\t\t\t"; visit(jmmNode.getJmmChild(2)); @@ -189,7 +189,7 @@ private Void dealWithObjectCreation(JmmNode jmmNode, Void unused) { private Void dealWithArrayCreation(JmmNode jmmNode, Void unused) { JmmNode size = jmmNode.getChildren().get(0); - String + for (var child : jmmNode.getChildren()) visit(child); From 5411ddf3cc83efdb8b3fad005ae4c116064dac35 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Tue, 23 May 2023 11:18:01 +0100 Subject: [PATCH 09/69] while hotfix --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index 75d0da0..29c22f2 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -65,7 +65,7 @@ private Void dealWithCycle(JmmNode jmmNode, Void unused) { var ifId = tempVarId++; // Condition statement - negation - code += "\t\tif (!.bool " + temp + ") goto end_loop" + ifId + ";\n"; + code += "\t\tif (!.bool " + jmmNode.getJmmChild(0).get("valueOl") + ") goto end_loop" + ifId + ";\n"; // What occurs if the condition is met code += "\t\tloop" + ifId + ":\n\t"; visit(jmmNode.getJmmChild(1)); From 32a84631b065a51e08c09d3fc7cc132655f4ce2f Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Tue, 23 May 2023 12:05:34 +0100 Subject: [PATCH 10/69] Add method to check if an element is a local variable --- .../fe/comp2023/optimization/OptimizationUtils.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java index b34e64a..3c1e77a 100644 --- a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java +++ b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java @@ -1,7 +1,11 @@ package pt.up.fe.comp2023.optimization; +import org.specs.comp.ollir.Descriptor; import org.specs.comp.ollir.Element; +import org.specs.comp.ollir.Method; +import org.specs.comp.ollir.Operand; +import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -32,4 +36,13 @@ public static Set unionSets (Set set1, Set set2){ return result; } + + public static boolean isLocalVar(Element element, Method method) { + HashMap varTable = method.getVarTable(); + String varName = ((Operand)element).getName(); + int firstLocalVarRegister = method.isStaticMethod() ? 0 : 1 + method.getParams().size(); + + return varTable.get(element.toString()).getVirtualReg() < firstLocalVarRegister) + } + } From 295a91423bc0282700c870c0fa4c441d056bdf57 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Tue, 23 May 2023 12:07:03 +0100 Subject: [PATCH 11/69] Instruction selection: iinc --- .../comp2023/jasmin/JVMInstructionUtils.java | 24 ++++++++++++++++++- .../inst_selection/InstSelection_iinc.ollir | 11 +++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_iinc.ollir diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index cf4c280..3f9c66c 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -183,6 +183,23 @@ public static String createUnaryOpStatement(UnaryOpInstruction instruction, Hash return statementList; } + public static String checkInc(BinaryOpInstruction instruction, HashMap varTable) { + Element leftOperand = instruction.getLeftOperand(); + Element rightOperand = instruction.getRightOperand(); + + if (!(leftOperand instanceof LiteralElement) && + rightOperand instanceof LiteralElement && + parseInt(((LiteralElement)rightOperand).getLiteral()) == 1) + return "\tiinc " + varTable.get(((Operand)leftOperand).getName()).getVirtualReg() + " 1\n"; + + if (leftOperand instanceof LiteralElement && + !(rightOperand instanceof LiteralElement) && + parseInt(((LiteralElement)leftOperand).getLiteral()) == 1) + return "\tiinc " + varTable.get(((Operand)rightOperand).getName()).getVirtualReg() + " 1\n"; + + return ""; + } + public static String createBinaryOpInstruction(BinaryOpInstruction instruction, HashMap varTable, boolean isBranchCond) { String statementList = ""; statementList += getLoadInstruction(instruction.getLeftOperand(), varTable); @@ -254,9 +271,14 @@ public static String createNoperInstruction(SingleOpInstruction instruction, Has } public static String createAssignStatement(AssignInstruction instruction, HashMap varTable) { - Element assignElement = instruction.getDest(); String statementList = ""; + if (instruction.getRhs() instanceof BinaryOpInstruction) { + statementList = checkInc((BinaryOpInstruction) instruction.getRhs(), varTable); + if (!statementList.equals("")) + return statementList; + } + Element assignElement = instruction.getDest(); if (assignElement instanceof ArrayOperand) statementList += getArrayLoadInstruction((ArrayOperand)assignElement, varTable); statementList += JasminUtils.handleInstruction(instruction.getRhs(), varTable, true); diff --git a/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_iinc.ollir b/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_iinc.ollir new file mode 100644 index 0000000..750e2d5 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_iinc.ollir @@ -0,0 +1,11 @@ +InstSelection_iinc { + .construct InstSelection_iinc().V { + invokespecial(this, "").V; + } + + .method public static main(args.array.String).V{ + i.i32 :=.i32 2.i32; + i.i32:=.i32 i.i32 +.i32 1.i32; + ret.V; + } +} \ No newline at end of file From d57caafe9e890b54bf21bbcc66d4f57f7906c3d4 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Tue, 23 May 2023 12:08:18 +0100 Subject: [PATCH 12/69] Small correction to isLocalVar() --- src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java index 3c1e77a..70c3023 100644 --- a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java +++ b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java @@ -42,7 +42,7 @@ public static boolean isLocalVar(Element element, Method method) { String varName = ((Operand)element).getName(); int firstLocalVarRegister = method.isStaticMethod() ? 0 : 1 + method.getParams().size(); - return varTable.get(element.toString()).getVirtualReg() < firstLocalVarRegister) + return varTable.get(varName).getVirtualReg() < firstLocalVarRegister; } } From a0391f260489e8f2fee1e8b9320d57271b621bc6 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Tue, 23 May 2023 12:16:33 +0100 Subject: [PATCH 13/69] Improved getUse() in order to check if element is a local variable --- .../optimization/RegisterAllocation.java | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java index 4bcaeab..560d539 100644 --- a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -1,16 +1,14 @@ package pt.up.fe.comp2023.optimization; import org.specs.comp.ollir.*; - import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.Map; -import static org.specs.comp.ollir.InstructionType.ASSIGN; -import static pt.up.fe.comp2023.optimization.OptimizationUtils.differenceSets; -import static pt.up.fe.comp2023.optimization.OptimizationUtils.unionSets; +import static org.specs.comp.ollir.InstructionType.*; +import static pt.up.fe.comp2023.optimization.OptimizationUtils.*; public class RegisterAllocation { private final Method method; @@ -35,7 +33,7 @@ public RegisterAllocation(Method method) { System.out.println("Defs:" + defs.get(instruction)); System.out.println("Uses:" + uses.get(instruction)); } - computeLiveInOuts(); + //computeLiveInOuts(); } public Set getDef(Instruction instruction){ @@ -43,7 +41,8 @@ public Set getDef(Instruction instruction){ if(instruction.getInstType() == ASSIGN) { AssignInstruction assignInst = (AssignInstruction)instruction; - def.add(assignInst.getDest()); + if(isLocalVar(assignInst.getDest(), this.method)) + def.add(assignInst.getDest()); } return def; } @@ -58,27 +57,29 @@ public Set getUse(Instruction instruction, Set result){ CallInstruction callInst = (CallInstruction) instruction; List arguments = callInst.getListOfOperands(); for (Element argument : arguments) { - if (!argument.isLiteral()) + if (!argument.isLiteral() && isLocalVar(argument, this.method)) result.add(argument); } } case RETURN -> { ReturnInstruction returnInst = (ReturnInstruction) instruction; Element returnElement = returnInst.getOperand(); - if (returnElement != null && !returnElement.isLiteral()) + if (returnElement != null && !returnElement.isLiteral() && isLocalVar(returnElement, this.method)) result.add(returnElement); } case BINARYOPER -> { BinaryOpInstruction binInst = (BinaryOpInstruction) instruction; - if (!binInst.getLeftOperand().isLiteral()) - result.add(binInst.getLeftOperand()); - if (!binInst.getRightOperand().isLiteral()) - result.add(binInst.getRightOperand()); + Element leftOperand = binInst.getLeftOperand(); + Element rightOperand = binInst.getRightOperand(); + if (!leftOperand.isLiteral() && isLocalVar(leftOperand, this.method)) + result.add(leftOperand); + if (!rightOperand.isLiteral() && isLocalVar(rightOperand, this.method)) + result.add(rightOperand); } case NOPER -> { SingleOpInstruction singleOpInstruction = (SingleOpInstruction) instruction; Element operand = singleOpInstruction.getSingleOperand(); - if (!operand.isLiteral()) + if (!operand.isLiteral() && isLocalVar(operand, this.method)) result.add(operand); } } From 46d9fc3fbc8e1c6a7233aa8a162323df0098f3b5 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Tue, 23 May 2023 13:35:16 +0100 Subject: [PATCH 14/69] Improve getUse() to handle PUTFIELD instruction type --- .../fe/comp2023/optimization/OptimizationUtils.java | 2 +- .../comp2023/optimization/RegisterAllocation.java | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java index 70c3023..713fef0 100644 --- a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java +++ b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java @@ -42,7 +42,7 @@ public static boolean isLocalVar(Element element, Method method) { String varName = ((Operand)element).getName(); int firstLocalVarRegister = method.isStaticMethod() ? 0 : 1 + method.getParams().size(); - return varTable.get(varName).getVirtualReg() < firstLocalVarRegister; + return varTable.get(varName).getVirtualReg() >= firstLocalVarRegister; } } diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java index 560d539..b70d712 100644 --- a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -78,10 +78,17 @@ public Set getUse(Instruction instruction, Set result){ } case NOPER -> { SingleOpInstruction singleOpInstruction = (SingleOpInstruction) instruction; - Element operand = singleOpInstruction.getSingleOperand(); - if (!operand.isLiteral() && isLocalVar(operand, this.method)) - result.add(operand); + Element rightOperand = singleOpInstruction.getSingleOperand(); + if (!rightOperand.isLiteral() && isLocalVar(rightOperand, this.method)) + result.add(rightOperand); + } + case PUTFIELD -> { + PutFieldInstruction putFieldInstruction = (PutFieldInstruction) instruction; + Element rightOperand = putFieldInstruction.getThirdOperand(); + if (!rightOperand.isLiteral() && isLocalVar(rightOperand, this.method)) + result.add(rightOperand); } + //TODO: } return result; } From ae073f09cb5a59b3c046648c58bff35c7f219350 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Tue, 23 May 2023 13:47:04 +0100 Subject: [PATCH 15/69] Improve getUse() to handle UNARYOPER instruction type --- .../pt/up/fe/comp2023/optimization/RegisterAllocation.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java index b70d712..1d3febd 100644 --- a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -67,6 +67,12 @@ public Set getUse(Instruction instruction, Set result){ if (returnElement != null && !returnElement.isLiteral() && isLocalVar(returnElement, this.method)) result.add(returnElement); } + case UNARYOPER -> { + UnaryOpInstruction unaryOpInstruction = (UnaryOpInstruction) instruction; + Element operand = unaryOpInstruction.getOperand(); + if (!operand.isLiteral() && isLocalVar(operand, this.method)) + result.add(operand); + } case BINARYOPER -> { BinaryOpInstruction binInst = (BinaryOpInstruction) instruction; Element leftOperand = binInst.getLeftOperand(); @@ -88,7 +94,6 @@ public Set getUse(Instruction instruction, Set result){ if (!rightOperand.isLiteral() && isLocalVar(rightOperand, this.method)) result.add(rightOperand); } - //TODO: } return result; } From 15763205b3d47fdaaa0bcdf23294506581892ade Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Tue, 23 May 2023 15:27:21 +0100 Subject: [PATCH 16/69] array creation --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index 29c22f2..afb0505 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -188,10 +188,10 @@ private Void dealWithObjectCreation(JmmNode jmmNode, Void unused) { } private Void dealWithArrayCreation(JmmNode jmmNode, Void unused) { - JmmNode size = jmmNode.getChildren().get(0); + visit(jmmNode.getJmmChild(0)); + code += "\t\tt" + tempVarId + ".array.i32 :=.array.i32 new(array, " + jmmNode.getJmmChild(0).get("valueOl") +").array.i32;\n"; - for (var child : jmmNode.getChildren()) - visit(child); + jmmNode.put("valueOl", "t" + tempVarId++ + ".array.i32" ); return null; } From 26cca1182539086b062b764dd6b6451ec62e6a31 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Tue, 23 May 2023 12:21:59 +0100 Subject: [PATCH 17/69] Verified if binary operation is addition before doing iinc --- src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 3f9c66c..ff58645 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -187,12 +187,14 @@ public static String checkInc(BinaryOpInstruction instruction, HashMap Date: Tue, 23 May 2023 16:49:29 +0100 Subject: [PATCH 18/69] this changed to always display class name --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index afb0505..de41e82 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -160,7 +160,7 @@ else if (isField) { } private Void dealWithThis(JmmNode jmmNode, Void unused) { - jmmNode.put("valueOl", "this"); + jmmNode.put("valueOl", "this." + table.getClassName()); return null; } From 24ef437c5e4ca6620705f1c4c9f89cd3da67872b Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Tue, 23 May 2023 16:50:55 +0100 Subject: [PATCH 19/69] Verified if the left and right side variables are the same before using iinc --- .../pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index ff58645..ce8f784 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -183,19 +183,22 @@ public static String createUnaryOpStatement(UnaryOpInstruction instruction, Hash return statementList; } - public static String checkInc(BinaryOpInstruction instruction, HashMap varTable) { + public static String checkInc(BinaryOpInstruction instruction, Element dest, HashMap varTable) { Element leftOperand = instruction.getLeftOperand(); Element rightOperand = instruction.getRightOperand(); + String destName = ((Operand)dest).getName(); if (instruction.getOperation().getOpType() == OperationType.ADD && !(leftOperand instanceof LiteralElement) && rightOperand instanceof LiteralElement && + destName.equals(((Operand)leftOperand).getName()) && parseInt(((LiteralElement)rightOperand).getLiteral()) == 1) return "\tiinc " + varTable.get(((Operand)leftOperand).getName()).getVirtualReg() + " 1\n"; if (instruction.getOperation().getOpType() == OperationType.ADD && leftOperand instanceof LiteralElement && !(rightOperand instanceof LiteralElement) && + destName.equals(((Operand)rightOperand).getName()) && parseInt(((LiteralElement)leftOperand).getLiteral()) == 1) return "\tiinc " + varTable.get(((Operand)rightOperand).getName()).getVirtualReg() + " 1\n"; @@ -273,14 +276,14 @@ public static String createNoperInstruction(SingleOpInstruction instruction, Has } public static String createAssignStatement(AssignInstruction instruction, HashMap varTable) { + Element assignElement = instruction.getDest(); String statementList = ""; if (instruction.getRhs() instanceof BinaryOpInstruction) { - statementList = checkInc((BinaryOpInstruction) instruction.getRhs(), varTable); + statementList = checkInc((BinaryOpInstruction) instruction.getRhs(), assignElement, varTable); if (!statementList.equals("")) return statementList; } - Element assignElement = instruction.getDest(); if (assignElement instanceof ArrayOperand) statementList += getArrayLoadInstruction((ArrayOperand)assignElement, varTable); statementList += JasminUtils.handleInstruction(instruction.getRhs(), varTable, true); From 0269fe01988d920723d0f06414ee12d9b8eccb98 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Tue, 23 May 2023 17:04:13 +0100 Subject: [PATCH 20/69] negation implemented --- .../pt/up/fe/comp2023/ollir/Optimization.java | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index de41e82..e3e492d 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -291,7 +291,7 @@ private Void dealWithLogicalExpr(JmmNode jmmNode, Void unused) { String right = rightSon.get("valueOl"); temp = "t" + tempVarId++ + ".bool"; - code += temp + ":=.bool " + left + " " + jmmNode.get("op") + ".bool " + right + ";\n"; + code += temp + " :=.bool " + left + " " + jmmNode.get("op") + ".bool " + right + ";\n"; jmmNode.put("valueOl", temp); return null; @@ -300,9 +300,6 @@ private Void dealWithLogicalExpr(JmmNode jmmNode, Void unused) { private Void dealWithComparison(JmmNode jmmNode, Void unused) { JmmNode leftSon = jmmNode.getJmmChild(0); JmmNode rightSon = jmmNode.getJmmChild(1); - var condition = jmmNode.getAncestor("Condition"); - var cycle = jmmNode.getAncestor("Cycle"); - visit(leftSon); visit(rightSon); @@ -311,9 +308,8 @@ private Void dealWithComparison(JmmNode jmmNode, Void unused) { String right = rightSon.get("valueOl"); temp = "t" + tempVarId++ + ".bool"; - code += temp + ":=.bool " + left + " " + jmmNode.get("op") + ".bool " + right; - //if (condition.isEmpty() || cycle.isEmpty()) - code += ";\n"; + code += temp + " :=.bool " + left + " " + jmmNode.get("op") + ".bool " + right; + code += ";\n"; jmmNode.put("valueOl", temp); return null; @@ -330,16 +326,19 @@ private Void dealWithArithmetic(JmmNode jmmNode, Void unused) { String right = rightSon.get("valueOl"); temp = "t" + tempVarId++ + ".i32"; - code += temp + ":=.i32 " + left + " " + jmmNode.get("op") + ".i32 " + right + ";\n"; + code += temp + " :=.i32 " + left + " " + jmmNode.get("op") + ".i32 " + right + ";\n"; jmmNode.put("valueOl", temp); return null; } private Void dealWithNegationExpr(JmmNode jmmNode, Void unused) { - for (var child : jmmNode.getChildren()) - visit(child); - + JmmNode son = jmmNode.getJmmChild(0); + visit(son); + String sonS = son.get("valueOl"); + temp = "t" + tempVarId++ + ".bool"; + code += temp + " :=.bool !.bool " + sonS + ";\n"; + jmmNode.put("valueOl", temp); return null; } From e8996bebe3e731359c1dd87dd8c82ca4f7a180af Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Tue, 23 May 2023 17:28:16 +0100 Subject: [PATCH 21/69] fix semicolon on cycles --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index e3e492d..a5a819f 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -467,13 +467,11 @@ else if (isField) } private Void dealWithExpr(JmmNode jmmNode, Void unused) { - var cycle = jmmNode.getAncestor("Cycle"); code += "\t\t"; for (var child : jmmNode.getChildren()) visit(child); - if (cycle.isEmpty()) - code += ";\n"; + code += ";\n"; System.out.println(jmmNode.getKind()); return null; } From f5a147ee838a8380dd1c84cb5b654ea69659d3b7 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Tue, 23 May 2023 17:51:26 +0100 Subject: [PATCH 22/69] Refactored binary operation instruction generation --- .../comp2023/jasmin/JVMInstructionUtils.java | 91 ++++++++++--------- 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index ce8f784..2b553e7 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -205,59 +205,66 @@ public static String checkInc(BinaryOpInstruction instruction, Element dest, Has return ""; } - public static String createBinaryOpInstruction(BinaryOpInstruction instruction, HashMap varTable, boolean isBranchCond) { - String statementList = ""; - statementList += getLoadInstruction(instruction.getLeftOperand(), varTable); - statementList += getLoadInstruction(instruction.getRightOperand(), varTable); + public static String createArithmeticInstruction(OperationType operationType) { + decreaseStackSize(1); - switch (instruction.getOperation().getOpType()) { + switch (operationType) { case ADD: - statementList += "\tiadd\n"; - decreaseStackSize(1); - break; + return "\tiadd\n"; case SUB: - statementList += "\tisub\n"; - decreaseStackSize(1); - break; + return "\tisub\n"; case MUL: - statementList += "\timul\n"; - decreaseStackSize(1); - break; + return "\timul\n"; case DIV: - statementList += "\tidiv\n"; - decreaseStackSize(1); - break; + return "\tidiv\n"; + } + return ""; + } + + public static String createLogicalInstruction(OperationType operationType) { + decreaseStackSize(1); + + switch (operationType) { case AND: case ANDB: - statementList += "\tiand\n"; - decreaseStackSize(1); - break; + return "\tiand\n"; case OR: case ORB: - statementList += "\tior\n"; - decreaseStackSize(1); - break; + return "\tior\n"; + } + return ""; + } + + public static String createComparisonInstruction(OperationType operationType, boolean isBranchCond) { + decreaseStackSize(2); + String statementList = ""; + + switch (operationType) { case LTH: - statementList += "\tif_icmplt "; - if (!isBranchCond) - statementList += createAuxBranchStatement(); - decreaseStackSize(2); - break; + return isBranchCond ? "\tif_icmplt " : "\tif_icmplt " + createAuxBranchStatement(); case LTE: - statementList += "\tif_icmple "; - if (!isBranchCond) - statementList += createAuxBranchStatement(); - decreaseStackSize(2); - break; + return isBranchCond ? "\tif_icmple " : "\tif_icmple " + createAuxBranchStatement(); case GTH: - statementList += "\tif_icmpgt "; - if (!isBranchCond) - statementList += createAuxBranchStatement(); - decreaseStackSize(2); - break; + return isBranchCond ? "\tif_icmpgt " : "\tif_icmpgt " + createAuxBranchStatement(); case GTE: - statementList += "\tif_icmpge "; - if (!isBranchCond) - statementList += createAuxBranchStatement(); - decreaseStackSize(2); + return isBranchCond ? "\tif_icmpge " : "\tif_icmpge " + createAuxBranchStatement(); + } + return ""; + } + + public static String createBinaryOpInstruction(BinaryOpInstruction instruction, HashMap varTable, boolean isBranchCond) { + OperationType operationType = instruction.getOperation().getOpType(); + String statementList = ""; + statementList += getLoadInstruction(instruction.getLeftOperand(), varTable); + statementList += getLoadInstruction(instruction.getRightOperand(), varTable); + + switch (operationType) { + case ADD: case SUB: case MUL: case DIV: + statementList += createArithmeticInstruction(operationType); + break; + case AND: case ANDB: case OR: case ORB: + statementList += createLogicalInstruction(operationType); + break; + case LTH: case LTE: case GTH: case GTE: + statementList += createComparisonInstruction(operationType, isBranchCond); break; } return statementList; From f168a5cb3f16129c6bbb1110deea76c478de5ec9 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 24 May 2023 09:21:42 +0100 Subject: [PATCH 23/69] Add utils method to get local vars from the varTable --- .../optimization/OptimizationUtils.java | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java index 713fef0..df7c5a9 100644 --- a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java +++ b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java @@ -32,7 +32,8 @@ public static Set differenceSets (Set set1, Set set2) public static Set unionSets (Set set1, Set set2){ Set result = new HashSet<>(set1); - result.addAll(set2); + if(set2 != null) + result.addAll(set2); return result; } @@ -45,4 +46,23 @@ public static boolean isLocalVar(Element element, Method method) { return varTable.get(varName).getVirtualReg() >= firstLocalVarRegister; } + public static boolean isLocalVar(String identifier, Method method) { + HashMap varTable = method.getVarTable(); + int firstLocalVarRegister = method.isStaticMethod() ? 0 : 1 + method.getParams().size(); + + return varTable.get(identifier).getVirtualReg() >= firstLocalVarRegister; + } + + public static Set getLocalVars(Method method) { + HashMap varTable = method.getVarTable(); + Set localsVars = new HashSet<>(); + + for(Map.Entry entry : varTable.entrySet()){ + String identifier = entry.getKey(); + if(isLocalVar(identifier, method)) + localsVars.add(identifier); + } + return localsVars; + } + } From ec2b377765c07cc134e0088de5525e8a019af1e4 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 24 May 2023 14:38:50 +0100 Subject: [PATCH 24/69] Fixed computeLiveInOuts() --- .../optimization/RegisterAllocation.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java index 1d3febd..0dc2edf 100644 --- a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -12,10 +12,10 @@ public class RegisterAllocation { private final Method method; - private Map> defs = new HashMap<>(); - private Map> uses = new HashMap<>(); - private Map> in = new HashMap<>(); - private Map> out = new HashMap<>(); + private final Map> defs = new HashMap<>(); + private final Map> uses = new HashMap<>(); + private final Map> in = new HashMap<>(); + private final Map> out = new HashMap<>(); public RegisterAllocation(Method method) { this.method = method; method.buildCFG(); @@ -33,7 +33,7 @@ public RegisterAllocation(Method method) { System.out.println("Defs:" + defs.get(instruction)); System.out.println("Uses:" + uses.get(instruction)); } - //computeLiveInOuts(); + computeLiveInOuts(); } public Set getDef(Instruction instruction){ @@ -115,17 +115,19 @@ public void computeLiveInOuts() { //Update liveIn Set difference = differenceSets(this.out.get(instruction), this.defs.get(instruction)); Set newLiveIn = unionSets(this.uses.get(instruction), difference); + this.in.put(instruction, newLiveIn); //Update liveOut Set newLiveOut = new HashSet<>(); - for(Node node : instruction.getSuccessors()){ - Instruction successor = (Instruction) node; - newLiveOut.addAll(this.in.get(successor)); + + for(Node successor : instruction.getSuccessors()){ + Set liveInSuccessor = this.in.get(successor); + newLiveOut = unionSets(newLiveOut, liveInSuccessor); } this.out.put(instruction, newLiveOut); //Check if liveIn or liveOut changed - if(!liveOutAux.equals(newLiveOut) || !liveInAux.equals(newLiveIn)) + if(!liveInAux.equals(newLiveIn) || !liveOutAux.equals(newLiveOut)) liveChanged = true; } } while(liveChanged); From abe58f1f9c7dc3e413e0deb63c567ac9d68246fd Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 24 May 2023 14:50:23 +0100 Subject: [PATCH 25/69] Create MyNode class and add basic methods --- .../interferenceGraph/MyNode.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyNode.java diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyNode.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyNode.java new file mode 100644 index 0000000..e3ea03b --- /dev/null +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyNode.java @@ -0,0 +1,34 @@ +package pt.up.fe.comp2023.optimization.interferenceGraph; + +import org.specs.comp.ollir.Element; +import java.util.HashSet; +import java.util.Set; + +public class MyNode { + private final String varName; + private final Set adj = new HashSet<>(); + + public MyNode(String varName){ + this.varName = varName; + } + + public String getVariable() { + return this.varName; + } + + public Set getAdj() { + return adj; + } + + public void addAdj(String varName) { + this.adj.add(varName); + } + + public int getNodeDegree() { + return this.adj.size(); + } + + public void removeAdj(String varName){ + this.adj.remove(varName); + } +} From 23e2c93eb981a470c53c8e260bf3ff0c6e1cfb15 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 24 May 2023 14:50:47 +0100 Subject: [PATCH 26/69] Create MyInterferenceGraph class and add basic methods --- .../MyInterferenceGraph.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java new file mode 100644 index 0000000..591c230 --- /dev/null +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java @@ -0,0 +1,35 @@ +package pt.up.fe.comp2023.optimization.interferenceGraph; + +import java.util.ArrayList; +import java.util.List; + +public class MyInterferenceGraph { + private final List nodes = new ArrayList<>(); + + public void addNode(String variable){ + MyNode newNode = new MyNode(variable); + this.nodes.add(newNode); + } + + public MyNode getNode(String varName){ + for(MyNode node : this.nodes){ + if(node.getVariable().equals(varName)) + return node; + } + return null; + } + public void addEdge(String src, String dest){ + getNode(src).getAdj().add(dest); + getNode(dest).getAdj().add(src); + } + + public void removeNode(String varName){ + MyNode node = getNode(varName); + + for(String adj : node.getAdj()){ + MyNode adjNode = getNode(adj); + adjNode.removeAdj(varName); + } + this.nodes.remove(node); + } +} From ec6f30eb87b99935fd3b84657210727f55ef7a48 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 24 May 2023 15:36:28 +0100 Subject: [PATCH 27/69] Add method to get variable name of an Element --- .../fe/comp2023/optimization/OptimizationUtils.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java index df7c5a9..5caf3cf 100644 --- a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java +++ b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java @@ -5,10 +5,7 @@ import org.specs.comp.ollir.Method; import org.specs.comp.ollir.Operand; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; public class OptimizationUtils { public static void intersectMaps (Map map1, Map map2, Map result){ @@ -53,9 +50,9 @@ public static boolean isLocalVar(String identifier, Method method) { return varTable.get(identifier).getVirtualReg() >= firstLocalVarRegister; } - public static Set getLocalVars(Method method) { + public static List getLocalVars(Method method) { HashMap varTable = method.getVarTable(); - Set localsVars = new HashSet<>(); + List localsVars = new ArrayList<>(); for(Map.Entry entry : varTable.entrySet()){ String identifier = entry.getKey(); @@ -65,4 +62,8 @@ public static Set getLocalVars(Method method) { return localsVars; } + public static String toVarName(Element element){ + return ((Operand)element).getName(); + } + } From f8a487d393df2febb0a9a8d95e00d8fa8476e65f Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 24 May 2023 15:46:15 +0100 Subject: [PATCH 28/69] Refactor: define differenceSets and unionSets as generic methods --- .../fe/comp2023/optimization/OptimizationUtils.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java index 5caf3cf..e80cdb2 100644 --- a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java +++ b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java @@ -20,15 +20,16 @@ public static void intersectMaps (Map map1, Map } } - public static Set differenceSets (Set set1, Set set2){ - Set result = new HashSet<>(set1); - result.removeAll(set2); + public static Set differenceSets(Set set1, Set set2) { + Set result = new HashSet<>(set1); + if(set2 != null) + result.removeAll(set2); return result; } - public static Set unionSets (Set set1, Set set2){ - Set result = new HashSet<>(set1); + public static Set unionSets(Set set1, Set set2) { + Set result = new HashSet<>(set1); if(set2 != null) result.addAll(set2); @@ -65,5 +66,4 @@ public static List getLocalVars(Method method) { public static String toVarName(Element element){ return ((Operand)element).getName(); } - } From f93fab32f949093f31cf415e75c9c102cf46b646 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 24 May 2023 15:49:27 +0100 Subject: [PATCH 29/69] Change key type in maps of RegisterAllocation from Element to String --- .../optimization/RegisterAllocation.java | 52 ++++++++++--------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java index 0dc2edf..331bb1e 100644 --- a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -1,6 +1,8 @@ package pt.up.fe.comp2023.optimization; import org.specs.comp.ollir.*; +import pt.up.fe.comp2023.optimization.interferenceGraph.MyInterferenceGraph; + import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -12,10 +14,10 @@ public class RegisterAllocation { private final Method method; - private final Map> defs = new HashMap<>(); - private final Map> uses = new HashMap<>(); - private final Map> in = new HashMap<>(); - private final Map> out = new HashMap<>(); + private final Map> defs = new HashMap<>(); + private final Map> uses = new HashMap<>(); + private final Map> in = new HashMap<>(); + private final Map> out = new HashMap<>(); public RegisterAllocation(Method method) { this.method = method; method.buildCFG(); @@ -33,21 +35,23 @@ public RegisterAllocation(Method method) { System.out.println("Defs:" + defs.get(instruction)); System.out.println("Uses:" + uses.get(instruction)); } - computeLiveInOuts(); + computeLiveInOut(); } - public Set getDef(Instruction instruction){ - Set def = new HashSet<>(); + public Set getDef(Instruction instruction){ + Set def = new HashSet<>(); if(instruction.getInstType() == ASSIGN) { AssignInstruction assignInst = (AssignInstruction)instruction; - if(isLocalVar(assignInst.getDest(), this.method)) - def.add(assignInst.getDest()); + if(isLocalVar(assignInst.getDest(), this.method)){ + Element dest = assignInst.getDest(); + def.add(toVarName(dest)); + } } return def; } - public Set getUse(Instruction instruction, Set result){ + public Set getUse(Instruction instruction, Set result){ switch (instruction.getInstType()) { case ASSIGN -> { AssignInstruction assignInst = (AssignInstruction) instruction; @@ -58,47 +62,47 @@ public Set getUse(Instruction instruction, Set result){ List arguments = callInst.getListOfOperands(); for (Element argument : arguments) { if (!argument.isLiteral() && isLocalVar(argument, this.method)) - result.add(argument); + result.add(toVarName(argument)); } } case RETURN -> { ReturnInstruction returnInst = (ReturnInstruction) instruction; Element returnElement = returnInst.getOperand(); if (returnElement != null && !returnElement.isLiteral() && isLocalVar(returnElement, this.method)) - result.add(returnElement); + result.add(toVarName(returnElement)); } case UNARYOPER -> { UnaryOpInstruction unaryOpInstruction = (UnaryOpInstruction) instruction; Element operand = unaryOpInstruction.getOperand(); if (!operand.isLiteral() && isLocalVar(operand, this.method)) - result.add(operand); + result.add(toVarName(operand)); } case BINARYOPER -> { BinaryOpInstruction binInst = (BinaryOpInstruction) instruction; Element leftOperand = binInst.getLeftOperand(); Element rightOperand = binInst.getRightOperand(); if (!leftOperand.isLiteral() && isLocalVar(leftOperand, this.method)) - result.add(leftOperand); + result.add(toVarName(leftOperand)); if (!rightOperand.isLiteral() && isLocalVar(rightOperand, this.method)) - result.add(rightOperand); + result.add(toVarName(rightOperand)); } case NOPER -> { SingleOpInstruction singleOpInstruction = (SingleOpInstruction) instruction; Element rightOperand = singleOpInstruction.getSingleOperand(); if (!rightOperand.isLiteral() && isLocalVar(rightOperand, this.method)) - result.add(rightOperand); + result.add(toVarName(rightOperand)); } case PUTFIELD -> { PutFieldInstruction putFieldInstruction = (PutFieldInstruction) instruction; Element rightOperand = putFieldInstruction.getThirdOperand(); if (!rightOperand.isLiteral() && isLocalVar(rightOperand, this.method)) - result.add(rightOperand); + result.add(toVarName(rightOperand)); } } return result; } - public void computeLiveInOuts() { + public void computeLiveInOut() { for (Instruction instruction : method.getInstructions()){ this.in.put(instruction, new HashSet<>()); this.out.put(instruction, new HashSet<>()); @@ -109,19 +113,19 @@ public void computeLiveInOuts() { liveChanged = false; for(Instruction instruction : method.getInstructions()){ //Save current liveIn and liveOut - Set liveInAux = new HashSet<>(this.in.get(instruction)); - Set liveOutAux = new HashSet<>(this.out.get(instruction)); + Set liveInAux = new HashSet<>(this.in.get(instruction)); + Set liveOutAux = new HashSet<>(this.out.get(instruction)); //Update liveIn - Set difference = differenceSets(this.out.get(instruction), this.defs.get(instruction)); - Set newLiveIn = unionSets(this.uses.get(instruction), difference); + Set difference = differenceSets(this.out.get(instruction), this.defs.get(instruction)); + Set newLiveIn = unionSets(this.uses.get(instruction), difference); this.in.put(instruction, newLiveIn); //Update liveOut - Set newLiveOut = new HashSet<>(); + Set newLiveOut = new HashSet<>(); for(Node successor : instruction.getSuccessors()){ - Set liveInSuccessor = this.in.get(successor); + Set liveInSuccessor = this.in.get(successor); newLiveOut = unionSets(newLiveOut, liveInSuccessor); } this.out.put(instruction, newLiveOut); From ec2ec137fb7d6772b0d05016f511162fc8e40ae3 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 24 May 2023 16:30:34 +0100 Subject: [PATCH 30/69] Add new method to connect interfering variables --- .../interferenceGraph/MyInterferenceGraph.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java index 591c230..18ccc1e 100644 --- a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java @@ -18,11 +18,22 @@ public MyNode getNode(String varName){ } return null; } - public void addEdge(String src, String dest){ + public void addInterferenceEdge(String src, String dest){ getNode(src).getAdj().add(dest); getNode(dest).getAdj().add(src); } + public void connectInterferingVariables(List variables){ + for(int i = 0; i < variables.size(); i++){ + for(int j = i + 1; j < variables.size(); j++){ + String src = variables.get(i); + String dest = variables.get(j); + + addInterferenceEdge(src, dest); + } + } + } + public void removeNode(String varName){ MyNode node = getNode(varName); From 79bf55d1a6b932c0031a2987c1e26b1b7e3d2544 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 24 May 2023 16:31:04 +0100 Subject: [PATCH 31/69] Add method to create interference graph --- .../optimization/RegisterAllocation.java | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java index 331bb1e..6111ee1 100644 --- a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -3,11 +3,7 @@ import org.specs.comp.ollir.*; import pt.up.fe.comp2023.optimization.interferenceGraph.MyInterferenceGraph; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.Map; +import java.util.*; import static org.specs.comp.ollir.InstructionType.*; import static pt.up.fe.comp2023.optimization.OptimizationUtils.*; @@ -18,6 +14,7 @@ public class RegisterAllocation { private final Map> uses = new HashMap<>(); private final Map> in = new HashMap<>(); private final Map> out = new HashMap<>(); + private final MyInterferenceGraph interferenceGraph = new MyInterferenceGraph(); public RegisterAllocation(Method method) { this.method = method; method.buildCFG(); @@ -36,6 +33,7 @@ public RegisterAllocation(Method method) { System.out.println("Uses:" + uses.get(instruction)); } computeLiveInOut(); + createInterferenceGraph(); } public Set getDef(Instruction instruction){ @@ -136,4 +134,21 @@ public void computeLiveInOut() { } } while(liveChanged); } + + private void createInterferenceGraph() { + List localVars = getLocalVars(this.method); + + //Add a node for each variable + for(String var : localVars) + this.interferenceGraph.addNode(var); + + //Compute edges + for(Instruction instruction : this.method.getInstructions()){ + List liveIn = new ArrayList<>(this.in.get(instruction)); + List defAndLiveOut = new ArrayList<>(unionSets(this.defs.get(instruction), this.out.get(instruction))); + + this.interferenceGraph.connectInterferingVariables(liveIn); + this.interferenceGraph.connectInterferingVariables(defAndLiveOut); + } + } } From 38b2ddeb91890e658a4d6e8d204c778f78640f24 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Wed, 24 May 2023 17:04:31 +0100 Subject: [PATCH 32/69] little fix to assignment --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index a5a819f..ef435c1 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -264,7 +264,7 @@ private Void dealWithLenFieldAccess(JmmNode jmmNode, Void unused) { visit(caller); jmmNode.put("valueOl", "t" + tempVarId + ".i32"); String caller_name = caller.get("valueOl"); - code += "t" + tempVarId++ + ".i32 :=.i32 arraylength(" + caller_name + ").i32;"; + code += "t" + tempVarId++ + ".i32 :=.i32 arraylength(" + caller_name + ").i32;\n"; return null; } @@ -457,7 +457,7 @@ private Void dealWithAssignment(JmmNode jmmNode, Void unused) { if (isLocal) code += "\t\t" + left + OllirUtils.ollirTypes(var.getType()) + " :=" + OllirUtils.ollirTypes(var.getType()) + " "; else if (isParam) - code += "\t\t$" + idParam + left + OllirUtils.ollirTypes(var.getType()) + " :=" + OllirUtils.ollirTypes(var.getType()) + " "; + code += "\t\t$" + idParam + "." + left + OllirUtils.ollirTypes(var.getType()) + " :=" + OllirUtils.ollirTypes(var.getType()) + " "; else if (isField) code += "\t\tputfield(this, " + left + OllirUtils.ollirTypes(var.getType()) + ", "; From e33b6140d52325110c33cdba048d5f1e2a571749 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 24 May 2023 17:40:58 +0100 Subject: [PATCH 33/69] Improve parseArgs() to handle "-r" option --- src/main/pt/up/fe/comp2023/Launcher.java | 34 +++++++++++++++++-- .../pt/up/fe/comp2023/ollir/Optimization.java | 8 +++-- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Launcher.java b/src/main/pt/up/fe/comp2023/Launcher.java index 713fb9a..6573699 100644 --- a/src/main/pt/up/fe/comp2023/Launcher.java +++ b/src/main/pt/up/fe/comp2023/Launcher.java @@ -84,6 +84,8 @@ public static void main(String[] args) { } OllirResult ollirResult = optimization.toOllir(semanticsResult); + if (Integer.parseInt(config.get("registerAllocation")) >= 0) + optimization.optimize(ollirResult); JasminGenerator jasminGenerator = new JasminGenerator(); JasminResult jasminResult = jasminGenerator.toJasmin(ollirResult); @@ -97,20 +99,46 @@ private static Map parseArgs(String[] args) { // Check if there is at least one argument if (args.length < 1) { - throw new RuntimeException("Usage: ./jmm [-o]"); + throw new RuntimeException("./abc [-o] [-p ]"); } // Create config Map config = new HashMap<>(); config.put("inputFile", args[0]); - config.put("registerAllocation", "-1"); config.put("debug", "false"); + config.put("optimize", "false"); + config.put("registerAllocation", "-1"); + + for (int i = 2; i < args.length; i++) { + if(args[i].equals("-o")) + config.put("optimize", "true"); + + else if(args[i].equals("-p")) { + if(i + 1 >= args.length) + throw new RuntimeException("Missing argument for -r option."); + else { + try { + int n = Integer.parseInt(args[i + 1]); + config.put("registerAllocation", Integer.toString(n)); + i++; + } catch (NumberFormatException e) { + System.out.println("Invalid argument for -r option: " + args[i + 1]); + } + } + } + } - if (Arrays.asList(args).contains("-o")) + if (Arrays.asList(args).contains("-o")) config.put("optimize", "true"); else config.put("optimize", "false"); + if (Arrays.asList(args).contains("-p")){ + Arrays.asList(args).fin + } + else + config.put("registerAllocation", "-1"); + return config; } } diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index c2ca311..f8738be 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -45,10 +45,12 @@ public JmmSemanticsResult optimize(JmmSemanticsResult semanticsResult) { } public OllirResult optimize(OllirResult ollirResult) { - ClassUnit classUnit = ollirResult.getOllirClass(); + if (Integer.parseInt(ollirResult.getConfig().get("registerAllocation")) >= 0){ + ClassUnit classUnit = ollirResult.getOllirClass(); - for(Method method : classUnit.getMethods()) - new RegisterAllocation(method); + for (Method method : classUnit.getMethods()) + new RegisterAllocation(method); + } return ollirResult; } From d264320cb84cceedab4f200feb464ecd9835d276 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Wed, 24 May 2023 19:51:55 +0100 Subject: [PATCH 34/69] Added special method to generate instruction for zero comparison --- .../comp2023/jasmin/JVMInstructionUtils.java | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 2b553e7..06d5886 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -235,7 +235,6 @@ public static String createLogicalInstruction(OperationType operationType) { public static String createComparisonInstruction(OperationType operationType, boolean isBranchCond) { decreaseStackSize(2); - String statementList = ""; switch (operationType) { case LTH: @@ -250,21 +249,51 @@ public static String createComparisonInstruction(OperationType operationType, bo return ""; } + public static String createZeroComparisonInstruction(OperationType operationType, boolean isBranchCond) { + decreaseStackSize(1); + + switch (operationType) { + case LTH: + return isBranchCond ? "\tiflt " : "\tiflt " + createAuxBranchStatement(); + case LTE: + return isBranchCond ? "\tifle " : "\tifle " + createAuxBranchStatement(); + case GTH: + return isBranchCond ? "\tifgt " : "\tifgt " + createAuxBranchStatement(); + case GTE: + return isBranchCond ? "\tifge " : "\tifge " + createAuxBranchStatement(); + } + return ""; + } + public static String createBinaryOpInstruction(BinaryOpInstruction instruction, HashMap varTable, boolean isBranchCond) { OperationType operationType = instruction.getOperation().getOpType(); + Element leftOperand = instruction.getLeftOperand(); + Element rightOperand = instruction.getRightOperand(); String statementList = ""; - statementList += getLoadInstruction(instruction.getLeftOperand(), varTable); - statementList += getLoadInstruction(instruction.getRightOperand(), varTable); switch (operationType) { case ADD: case SUB: case MUL: case DIV: + statementList += getLoadInstruction(leftOperand, varTable); + statementList += getLoadInstruction(rightOperand, varTable); statementList += createArithmeticInstruction(operationType); break; case AND: case ANDB: case OR: case ORB: + statementList += getLoadInstruction(leftOperand, varTable); + statementList += getLoadInstruction(rightOperand, varTable); statementList += createLogicalInstruction(operationType); break; case LTH: case LTE: case GTH: case GTE: - statementList += createComparisonInstruction(operationType, isBranchCond); + if (leftOperand instanceof LiteralElement && parseInt(((LiteralElement)leftOperand).getLiteral()) == 0) { + statementList += getLoadInstruction(rightOperand, varTable); + statementList += createZeroComparisonInstruction(operationType, isBranchCond); + } else if (rightOperand instanceof LiteralElement && parseInt(((LiteralElement)rightOperand).getLiteral()) == 0) { + statementList += getLoadInstruction(leftOperand, varTable); + statementList += createZeroComparisonInstruction(operationType, isBranchCond); + } else { + statementList += getLoadInstruction(leftOperand, varTable); + statementList += getLoadInstruction(rightOperand, varTable); + statementList += createComparisonInstruction(operationType, isBranchCond); + } break; } return statementList; From d0da02e7b0607d59c9c8c6608382048b1f6005ad Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Wed, 24 May 2023 22:36:04 +0100 Subject: [PATCH 35/69] Added data structure to keep track of which temps are equivalent to which vars --- .../comp2023/jasmin/JVMInstructionUtils.java | 1 + .../pt/up/fe/comp2023/jasmin/JasminUtils.java | 43 ++++++++++++++----- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 06d5886..4c535c5 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -13,6 +13,7 @@ public class JVMInstructionUtils { public static int numLocals = 0; public static int stackSize = 0; public static int currStackSize = 0; + public static Map varEquivalence = new HashMap<>(); public static void increaseStackSize(int n) { currStackSize += n; diff --git a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java index d8e7bdc..4ba3e5a 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java @@ -4,6 +4,8 @@ import java.util.ArrayList; import java.util.HashMap; +import java.util.List; +import java.util.Objects; public class JasminUtils { @@ -69,6 +71,19 @@ public static String createFieldDirective(Field field) { return fieldDirective + '\n'; } + public static String createConstructMethod(String superClassName) { + String methodDirective = ".method public ()V\n"; + methodDirective += "\taload_0\n"; + methodDirective += "\tinvokespecial "; + if (superClassName != null) + methodDirective += superClassName; + else + methodDirective += "java/lang/Object"; + methodDirective += "/()V\n"; + methodDirective += "\treturn\n"; + return methodDirective + ".end method\n\n"; + } + public static String createMethodSignature(String methodName, ArrayList listOfParameters, Type returnType, boolean isDeclaration) { String methodSignature = ""; methodSignature += methodName + "("; @@ -96,6 +111,7 @@ public static String createMethodDeclaration(Method method) { } public static String handleInstruction(Instruction instruction, HashMap varTable, boolean isRhs) { + instruction.show(); String statementList = ""; switch (instruction.getInstType()) { case ASSIGN: @@ -184,23 +200,28 @@ public static String handleMethodStatements(Method method) { return statementList; } - public static String createConstructMethod(String superClassName) { - String methodDirective = ".method public ()V\n"; - methodDirective += "\taload_0\n"; - methodDirective += "\tinvokespecial "; - if (superClassName != null) - methodDirective += superClassName; - else - methodDirective += "java/lang/Object"; - methodDirective += "/()V\n"; - methodDirective += "\treturn\n"; - return methodDirective + ".end method\n\n"; + public static void createVarEquivalence(Method method) { + JVMInstructionUtils.varEquivalence.clear(); + for (Instruction instruction: method.getInstructions()) { + if (instruction instanceof AssignInstruction) { + Operand lhs = ((Operand)((AssignInstruction)instruction).getDest()); + Instruction rhsInstruction = ((AssignInstruction)instruction).getRhs(); + if (rhsInstruction instanceof SingleOpInstruction && + ((SingleOpInstruction)rhsInstruction).getSingleOperand() instanceof Operand) { + Operand rhs = ((Operand)((SingleOpInstruction)rhsInstruction).getSingleOperand()); + + JVMInstructionUtils.varEquivalence.put(rhs.getName(), lhs.getName()); + } + } + } } public static String createMethodDirective(Method method) { JVMInstructionUtils.numLocals = 0; JVMInstructionUtils.stackSize = 0; JVMInstructionUtils.currStackSize = 0; + createVarEquivalence(method); + String instructions = handleMethodStatements(method); if (method.isStaticMethod() && method.getParams().size() > 0) JVMInstructionUtils.numLocals++; From 037c91bf5692df70f49819b2dba655c3d103a82e Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Thu, 25 May 2023 14:34:56 +0100 Subject: [PATCH 36/69] fix parenthesis --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index ef435c1..a0d6013 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -221,8 +221,8 @@ private Void dealWithMethodCall(JmmNode jmmNode, Void unused) { if (left.getKind().equals("This")) { code += "invokevirtual("; } else { - if (table.getImports().contains(left.get("value"))) { - code += "invokestatic(" + left.get("value") + " , \"" + methodName + "\""; // The first arg is the object that calls the method and the second is the name of the method called + if (table.getImports().contains(left.get("valueOl"))) { + code += "invokestatic(" + left.get("valueOl") + " , \"" + methodName + "\""; // The first arg is the object that calls the method and the second is the name of the method called isStatic = true; } else code += "invokevirtual("; From 4ba7c2383dd2a97d8638b7c043678f1d533043e2 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Thu, 25 May 2023 14:39:58 +0100 Subject: [PATCH 37/69] fix? --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index a0d6013..dbed159 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -386,6 +386,7 @@ private Void dealWithArrayAssignment(JmmNode jmmNode, Void unused) { JmmNode right = jmmNode.getChildren().get(0); JmmNode last = jmmNode.getChildren().get(1); visit(right); + visit(last); if (isLocal) code += "\t\t" + left; @@ -395,11 +396,7 @@ else if (isField) code += "\t\tt" + tempVarId + ".array.i32 :=.array.i32 getfield(this, " + left + ".array.i32).array.i32;" + "\n\t\tt" + tempVarId++; - code += "[" + right.get("valueOl") + "].i32 :=.i32 "; - - visit(last); - - code += last.get("valueOl") +";\n"; + code += "[" + right.get("valueOl") + "].i32 :=.i32 " + last.get("valueOl") +";\n"; return null; } From a2af6b3235488fbc7f3bf48f4c1e1dfb99143e69 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Thu, 25 May 2023 17:21:45 +0100 Subject: [PATCH 38/69] fix error --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index dbed159..0bcddfc 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -70,7 +70,7 @@ private Void dealWithCycle(JmmNode jmmNode, Void unused) { // What occurs if the condition is met code += "\t\tloop" + ifId + ":\n\t"; visit(jmmNode.getJmmChild(1)); code += "\t\t"; visit(jmmNode.getJmmChild(0)); code += "\n"; - code += "\t\t if( " + temp + ") goto loop" + ifId + ";\n"; + code += "\t\t if( " + jmmNode.getJmmChild(0).get("valueOl") + ") goto loop" + ifId + ";\n"; // End of If code +="\t\tend_loop" + ifId + ":\n\t"; From 37d980963a1b99ca60f8b18c105d8ed4a9946252 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Thu, 25 May 2023 17:24:13 +0100 Subject: [PATCH 39/69] Remove var name from known constants if the assignment is inside a cycle --- .../pt/up/fe/comp2023/optimization/ConstantPropagation.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java index 1e46c23..c31abf8 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java @@ -78,6 +78,9 @@ private Void dealWithCycle(JmmNode jmmNode, Map constants) { private Void dealWithAssignment(JmmNode jmmNode, Map constants) { String varName = jmmNode.get("varname"); + if(jmmNode.getAncestor("Cycle").isPresent()) + constants.remove(varName); + JmmNode exprNode = jmmNode.getJmmChild(0); visit(exprNode, constants); From 1f9f86c8d0d8981a18ba03e0692e1a5acc410e89 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Thu, 25 May 2023 17:37:26 +0100 Subject: [PATCH 40/69] Improve parseArgs() method to handle "-r" option --- src/main/pt/up/fe/comp2023/Launcher.java | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Launcher.java b/src/main/pt/up/fe/comp2023/Launcher.java index 6573699..fcf54e6 100644 --- a/src/main/pt/up/fe/comp2023/Launcher.java +++ b/src/main/pt/up/fe/comp2023/Launcher.java @@ -73,7 +73,7 @@ public static void main(String[] args) { Optimization optimization = new Optimization(); - //Apply Constant Propagation and Constant Folding optimizations + // Apply Constant Propagation and Constant Folding optimizations if (Boolean.parseBoolean(config.get("optimize"))) { System.out.println("Applying optimizations..."); @@ -84,6 +84,8 @@ public static void main(String[] args) { } OllirResult ollirResult = optimization.toOllir(semanticsResult); + + // Optimize register allocation if (Integer.parseInt(config.get("registerAllocation")) >= 0) optimization.optimize(ollirResult); @@ -98,9 +100,8 @@ private static Map parseArgs(String[] args) { SpecsLogs.info("Executing with args: " + Arrays.toString(args)); // Check if there is at least one argument - if (args.length < 1) { - throw new RuntimeException("./abc [-o] [-p ]"); - } + if (args.length < 1) + throw new RuntimeException("Usage: ./jmm [-o] [-p ]"); // Create config Map config = new HashMap<>(); @@ -127,18 +128,6 @@ else if(args[i].equals("-p")) { } } } - - if (Arrays.asList(args).contains("-o")) - config.put("optimize", "true"); - else - config.put("optimize", "false"); - - if (Arrays.asList(args).contains("-p")){ - Arrays.asList(args).fin - } - else - config.put("registerAllocation", "-1"); - return config; } } From cbc9aa44c1da7def584c4c618c6737384615e3ae Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Thu, 25 May 2023 18:53:59 +0100 Subject: [PATCH 41/69] Small fix to parseArgs() method --- src/main/pt/up/fe/comp2023/Launcher.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Launcher.java b/src/main/pt/up/fe/comp2023/Launcher.java index fcf54e6..50073c9 100644 --- a/src/main/pt/up/fe/comp2023/Launcher.java +++ b/src/main/pt/up/fe/comp2023/Launcher.java @@ -110,11 +110,11 @@ private static Map parseArgs(String[] args) { config.put("optimize", "false"); config.put("registerAllocation", "-1"); - for (int i = 2; i < args.length; i++) { + for (int i = 1; i < args.length; i++) { if(args[i].equals("-o")) config.put("optimize", "true"); - else if(args[i].equals("-p")) { + else if(args[i].equals("-r")) { if(i + 1 >= args.length) throw new RuntimeException("Missing argument for -r option."); else { From a8dfb3b38f973c3be39e253a69d39a571064626a Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 26 May 2023 11:06:41 +0100 Subject: [PATCH 42/69] Improve RegisterAllocation to receive allocation option --- .../pt/up/fe/comp2023/ollir/Optimization.java | 7 +++--- .../optimization/RegisterAllocation.java | 22 +++++++++++-------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index f8738be..d902d3d 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -45,11 +45,12 @@ public JmmSemanticsResult optimize(JmmSemanticsResult semanticsResult) { } public OllirResult optimize(OllirResult ollirResult) { - if (Integer.parseInt(ollirResult.getConfig().get("registerAllocation")) >= 0){ - ClassUnit classUnit = ollirResult.getOllirClass(); + int registerAllocationOption = Integer.parseInt(ollirResult.getConfig().get("registerAllocation")); + if (registerAllocationOption >= 0){ + ClassUnit classUnit = ollirResult.getOllirClass(); for (Method method : classUnit.getMethods()) - new RegisterAllocation(method); + new RegisterAllocation(method, registerAllocationOption); } return ollirResult; } diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java index 6111ee1..a1c84e6 100644 --- a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -10,30 +10,34 @@ public class RegisterAllocation { private final Method method; + private final int registerAllocationOption; private final Map> defs = new HashMap<>(); private final Map> uses = new HashMap<>(); private final Map> in = new HashMap<>(); private final Map> out = new HashMap<>(); private final MyInterferenceGraph interferenceGraph = new MyInterferenceGraph(); - public RegisterAllocation(Method method) { + public RegisterAllocation(Method method, int registerAllocationOption) { + this.registerAllocationOption = registerAllocationOption; this.method = method; - method.buildCFG(); - - //TODO: remove - System.out.println(method.getMethodName()); - System.out.println("------------------"); + method.buildCFG(); for (Instruction instruction : method.getInstructions()){ this.defs.put(instruction, getDef(instruction)); this.uses.put(instruction, getUse(instruction, new HashSet<>())); + } + computeLiveInOut(); + createInterferenceGraph(); - //TODO: remove + //TODO: remove + System.out.println(method.getMethodName()); + System.out.println("------------------"); + for(Instruction instruction : method.getInstructions()){ instruction.show(); System.out.println("Defs:" + defs.get(instruction)); System.out.println("Uses:" + uses.get(instruction)); + System.out.println("In:" + in.get(instruction)); + System.out.println(("Out: "+ out.get(instruction))); } - computeLiveInOut(); - createInterferenceGraph(); } public Set getDef(Instruction instruction){ From 019f13330cd94df8044e2ac027d803bf5b1a38e1 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 26 May 2023 11:12:09 +0100 Subject: [PATCH 43/69] Refactor RegisterAllocation class --- .../optimization/RegisterAllocation.java | 55 +++++++++++-------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java index a1c84e6..6205ecc 100644 --- a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -20,13 +20,18 @@ public RegisterAllocation(Method method, int registerAllocationOption) { this.registerAllocationOption = registerAllocationOption; this.method = method; - method.buildCFG(); - for (Instruction instruction : method.getInstructions()){ + livenessAnalysis(); + createInterferenceGraph(); + graphColoring(); + } + + private void livenessAnalysis(){ + this.method.buildCFG(); + for (Instruction instruction : this.method.getInstructions()){ this.defs.put(instruction, getDef(instruction)); this.uses.put(instruction, getUse(instruction, new HashSet<>())); } computeLiveInOut(); - createInterferenceGraph(); //TODO: remove System.out.println(method.getMethodName()); @@ -40,7 +45,28 @@ public RegisterAllocation(Method method, int registerAllocationOption) { } } - public Set getDef(Instruction instruction){ + private void createInterferenceGraph() { + List localVars = getLocalVars(this.method); + + //Add a node for each variable + for(String var : localVars) + this.interferenceGraph.addNode(var); + + //Compute edges + for(Instruction instruction : this.method.getInstructions()){ + List liveIn = new ArrayList<>(this.in.get(instruction)); + List defAndLiveOut = new ArrayList<>(unionSets(this.defs.get(instruction), this.out.get(instruction))); + + this.interferenceGraph.connectInterferingVariables(liveIn); + this.interferenceGraph.connectInterferingVariables(defAndLiveOut); + } + } + + private void graphColoring() { + //TODO + } + + private Set getDef(Instruction instruction){ Set def = new HashSet<>(); if(instruction.getInstType() == ASSIGN) { @@ -53,7 +79,7 @@ public Set getDef(Instruction instruction){ return def; } - public Set getUse(Instruction instruction, Set result){ + private Set getUse(Instruction instruction, Set result){ switch (instruction.getInstType()) { case ASSIGN -> { AssignInstruction assignInst = (AssignInstruction) instruction; @@ -104,7 +130,7 @@ public Set getUse(Instruction instruction, Set result){ return result; } - public void computeLiveInOut() { + private void computeLiveInOut() { for (Instruction instruction : method.getInstructions()){ this.in.put(instruction, new HashSet<>()); this.out.put(instruction, new HashSet<>()); @@ -138,21 +164,4 @@ public void computeLiveInOut() { } } while(liveChanged); } - - private void createInterferenceGraph() { - List localVars = getLocalVars(this.method); - - //Add a node for each variable - for(String var : localVars) - this.interferenceGraph.addNode(var); - - //Compute edges - for(Instruction instruction : this.method.getInstructions()){ - List liveIn = new ArrayList<>(this.in.get(instruction)); - List defAndLiveOut = new ArrayList<>(unionSets(this.defs.get(instruction), this.out.get(instruction))); - - this.interferenceGraph.connectInterferingVariables(liveIn); - this.interferenceGraph.connectInterferingVariables(defAndLiveOut); - } - } } From 1b83e62d8f7b04f88bd2acf47105e513f446c970 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Fri, 26 May 2023 11:48:14 +0100 Subject: [PATCH 44/69] Used var equivalence to know when to use iinc --- src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 4c535c5..9b8f830 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -192,14 +192,14 @@ public static String checkInc(BinaryOpInstruction instruction, Element dest, Has if (instruction.getOperation().getOpType() == OperationType.ADD && !(leftOperand instanceof LiteralElement) && rightOperand instanceof LiteralElement && - destName.equals(((Operand)leftOperand).getName()) && + (destName.equals(((Operand)leftOperand).getName()) || (JVMInstructionUtils.varEquivalence.get(destName).equals(((Operand)leftOperand).getName()))) && parseInt(((LiteralElement)rightOperand).getLiteral()) == 1) return "\tiinc " + varTable.get(((Operand)leftOperand).getName()).getVirtualReg() + " 1\n"; if (instruction.getOperation().getOpType() == OperationType.ADD && leftOperand instanceof LiteralElement && !(rightOperand instanceof LiteralElement) && - destName.equals(((Operand)rightOperand).getName()) && + (destName.equals(((Operand)rightOperand).getName()) || (JVMInstructionUtils.varEquivalence.get(destName).equals(((Operand)rightOperand).getName()))) && parseInt(((LiteralElement)leftOperand).getLiteral()) == 1) return "\tiinc " + varTable.get(((Operand)rightOperand).getName()).getVirtualReg() + " 1\n"; From 3e1a4444a6c6c99c8a22e713cabdf65246ff539d Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 26 May 2023 12:23:43 +0100 Subject: [PATCH 45/69] Implement method to find optimal coloring --- .../MyInterferenceGraph.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java index 18ccc1e..9855bfb 100644 --- a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java @@ -1,10 +1,13 @@ package pt.up.fe.comp2023.optimization.interferenceGraph; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class MyInterferenceGraph { private final List nodes = new ArrayList<>(); + private Map nodeColor = new HashMap<>(); public void addNode(String variable){ MyNode newNode = new MyNode(variable); @@ -43,4 +46,30 @@ public void removeNode(String varName){ } this.nodes.remove(node); } + + public Map isMColoringFeasible(int maxColors){ + //TODO + + return this.nodeColor; + } + + public Map findOptimalColoring(){ + int maxColors = this.nodes.size(); + + for(MyNode node : this.nodes){ + for(int color = 0; color < maxColors; color++){ + if(isValidColor(node, color)) + nodeColor.put(node.getVariable(), color); + } + } + return this.nodeColor; + } + + private boolean isValidColor(MyNode node, int color){ + for(String adj : node.getAdj()){ + if(nodeColor.get(adj) == color) + return false; + } + return true; + } } From 5cd37811bd9fdccaef574b0814a93fad7b9a2757 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Fri, 26 May 2023 12:54:21 +0100 Subject: [PATCH 46/69] Refactor: method to check if a temp value is being assigned to a variable --- .../fe/comp2023/jasmin/JVMInstructionUtils.java | 16 +++++++++++++--- .../pt/up/fe/comp2023/jasmin/JasminUtils.java | 11 +++-------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 9b8f830..f130dde 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -192,14 +192,14 @@ public static String checkInc(BinaryOpInstruction instruction, Element dest, Has if (instruction.getOperation().getOpType() == OperationType.ADD && !(leftOperand instanceof LiteralElement) && rightOperand instanceof LiteralElement && - (destName.equals(((Operand)leftOperand).getName()) || (JVMInstructionUtils.varEquivalence.get(destName).equals(((Operand)leftOperand).getName()))) && + (destName.equals(((Operand)leftOperand).getName()) || (varEquivalence.get(destName).equals(((Operand)leftOperand).getName()))) && parseInt(((LiteralElement)rightOperand).getLiteral()) == 1) return "\tiinc " + varTable.get(((Operand)leftOperand).getName()).getVirtualReg() + " 1\n"; if (instruction.getOperation().getOpType() == OperationType.ADD && leftOperand instanceof LiteralElement && !(rightOperand instanceof LiteralElement) && - (destName.equals(((Operand)rightOperand).getName()) || (JVMInstructionUtils.varEquivalence.get(destName).equals(((Operand)rightOperand).getName()))) && + (destName.equals(((Operand)rightOperand).getName()) || (varEquivalence.get(destName).equals(((Operand)rightOperand).getName()))) && parseInt(((LiteralElement)leftOperand).getLiteral()) == 1) return "\tiinc " + varTable.get(((Operand)rightOperand).getName()).getVirtualReg() + " 1\n"; @@ -312,11 +312,21 @@ public static String createNoperInstruction(SingleOpInstruction instruction, Has return getLoadInstruction(operand, varTable); } + public static boolean checkTempAssign(AssignInstruction instruction) { + Operand lhs = ((Operand)((AssignInstruction)instruction).getDest()); + Instruction rhsInstruction = ((AssignInstruction)instruction).getRhs(); + if (!(rhsInstruction instanceof SingleOpInstruction)) + return false; + if (!(((SingleOpInstruction)rhsInstruction).getSingleOperand() instanceof Operand)) + return false; + return true; + } + public static String createAssignStatement(AssignInstruction instruction, HashMap varTable) { Element assignElement = instruction.getDest(); String statementList = ""; if (instruction.getRhs() instanceof BinaryOpInstruction) { - statementList = checkInc((BinaryOpInstruction) instruction.getRhs(), assignElement, varTable); + statementList = checkInc((BinaryOpInstruction)instruction.getRhs(), assignElement, varTable); if (!statementList.equals("")) return statementList; } diff --git a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java index 4ba3e5a..b8fc0e8 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java @@ -203,15 +203,10 @@ public static String handleMethodStatements(Method method) { public static void createVarEquivalence(Method method) { JVMInstructionUtils.varEquivalence.clear(); for (Instruction instruction: method.getInstructions()) { - if (instruction instanceof AssignInstruction) { + if (instruction instanceof AssignInstruction && JVMInstructionUtils.checkTempAssign((AssignInstruction)instruction)) { Operand lhs = ((Operand)((AssignInstruction)instruction).getDest()); - Instruction rhsInstruction = ((AssignInstruction)instruction).getRhs(); - if (rhsInstruction instanceof SingleOpInstruction && - ((SingleOpInstruction)rhsInstruction).getSingleOperand() instanceof Operand) { - Operand rhs = ((Operand)((SingleOpInstruction)rhsInstruction).getSingleOperand()); - - JVMInstructionUtils.varEquivalence.put(rhs.getName(), lhs.getName()); - } + Operand rhs = ((Operand)((SingleOpInstruction)(((AssignInstruction)instruction).getRhs())).getSingleOperand()); + JVMInstructionUtils.varEquivalence.put(rhs.getName(), lhs.getName()); } } } From 0b2294faef5f2374631246b683686b0d0964c04d Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 26 May 2023 13:11:42 +0100 Subject: [PATCH 47/69] Add method to check if a graph is m coloring feasible --- .../MyInterferenceGraph.java | 47 +++++++++++++++---- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java index 9855bfb..d41e16a 100644 --- a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java @@ -1,14 +1,19 @@ package pt.up.fe.comp2023.optimization.interferenceGraph; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; public class MyInterferenceGraph { private final List nodes = new ArrayList<>(); private Map nodeColor = new HashMap<>(); + public MyInterferenceGraph deepCopy(){ + MyInterferenceGraph copy = new MyInterferenceGraph(); + + for(MyNode node : this.nodes) + copy.addNode(node.getVariable()); + return copy; + } + public void addNode(String variable){ MyNode newNode = new MyNode(variable); this.nodes.add(newNode); @@ -37,19 +42,43 @@ public void connectInterferingVariables(List variables){ } } - public void removeNode(String varName){ - MyNode node = getNode(varName); - + public void removeNode(MyNode node){ for(String adj : node.getAdj()){ MyNode adjNode = getNode(adj); - adjNode.removeAdj(varName); + adjNode.removeAdj(node.getVariable()); } this.nodes.remove(node); } public Map isMColoringFeasible(int maxColors){ - //TODO + MyInterferenceGraph copyGraph = deepCopy(); + Stack stack = new Stack<>(); + boolean foundNode; + + while(copyGraph.nodes.size() > 0){ + foundNode = false; + Iterator iterator = copyGraph.nodes.iterator(); + + while (iterator.hasNext()) { + MyNode node = iterator.next(); + if (node.getAdj().size() < maxColors) { + foundNode = true; + stack.push(node.getVariable()); + copyGraph.removeNode(node); + } + } + if (!foundNode) + throw new RuntimeException("The provided number of registers is not enough to store the variables."); + } + + while (!stack.isEmpty()){ + String nodeName = stack.pop(); + for(int color = 0; color < maxColors; color++){ + if(isValidColor(getNode(nodeName), color)) + this.nodeColor.put(nodeName, color); + } + } return this.nodeColor; } From cb4ad97cdf6875563b17ee1f5a9640388552b5db Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 26 May 2023 13:16:08 +0100 Subject: [PATCH 48/69] Refactor: add method to compute M coloring stack --- .../interferenceGraph/MyInterferenceGraph.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java index d41e16a..c901564 100644 --- a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java @@ -50,14 +50,13 @@ public void removeNode(MyNode node){ this.nodes.remove(node); } - public Map isMColoringFeasible(int maxColors){ - MyInterferenceGraph copyGraph = deepCopy(); + public Stack computeMColoringStack(int maxColors){ Stack stack = new Stack<>(); boolean foundNode; - while(copyGraph.nodes.size() > 0){ + while (this.nodes.size() > 0) { foundNode = false; - Iterator iterator = copyGraph.nodes.iterator(); + Iterator iterator = this.nodes.iterator(); while (iterator.hasNext()) { MyNode node = iterator.next(); @@ -65,12 +64,18 @@ public Map isMColoringFeasible(int maxColors){ if (node.getAdj().size() < maxColors) { foundNode = true; stack.push(node.getVariable()); - copyGraph.removeNode(node); + this.removeNode(node); } } if (!foundNode) throw new RuntimeException("The provided number of registers is not enough to store the variables."); } + return stack; + } + + public Map isMColoringFeasible(int maxColors){ + MyInterferenceGraph copyGraph = deepCopy(); + Stack stack = copyGraph.computeMColoringStack(maxColors); while (!stack.isEmpty()){ String nodeName = stack.pop(); From 573191318b1a978a4f15bfdd25b18ec5559b3f13 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 26 May 2023 13:18:23 +0100 Subject: [PATCH 49/69] Add fuction to check if a method has access to 'this' --- .../pt/up/fe/comp2023/optimization/OptimizationUtils.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java index e80cdb2..4c6a92d 100644 --- a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java +++ b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java @@ -66,4 +66,12 @@ public static List getLocalVars(Method method) { public static String toVarName(Element element){ return ((Operand)element).getName(); } + + public static int methodAccessThis(Method method) { + return method.isStaticMethod() ? 0 : 1; + } + + public static int numParams(Method method){ + return method.getParams().size(); + } } From 3bf5809aa6b5f2f206e9437bbee14796e1b010c4 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 26 May 2023 13:19:28 +0100 Subject: [PATCH 50/69] Implement graphColoring in RegisterAllocation --- .../comp2023/optimization/RegisterAllocation.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java index 6205ecc..9056cf5 100644 --- a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -11,18 +11,21 @@ public class RegisterAllocation { private final Method method; private final int registerAllocationOption; + private Map optimalRegisters = new HashMap<>(); private final Map> defs = new HashMap<>(); private final Map> uses = new HashMap<>(); private final Map> in = new HashMap<>(); private final Map> out = new HashMap<>(); private final MyInterferenceGraph interferenceGraph = new MyInterferenceGraph(); + public RegisterAllocation(Method method, int registerAllocationOption) { this.registerAllocationOption = registerAllocationOption; this.method = method; livenessAnalysis(); createInterferenceGraph(); - graphColoring(); + graphColoring(); //Updates optimalRegisters + //updateVarsRegisters(); } private void livenessAnalysis(){ @@ -63,9 +66,14 @@ private void createInterferenceGraph() { } private void graphColoring() { - //TODO + if(registerAllocationOption > 0) { // Try to use at most local variables + int k = registerAllocationOption - methodAccessThis(method) - numParams(method); + this.optimalRegisters = this.interferenceGraph.isMColoringFeasible(k); + } + else // Try to use as few local variables as it can + this.optimalRegisters = this.interferenceGraph.findOptimalColoring(); } - + private Set getDef(Instruction instruction){ Set def = new HashSet<>(); From fc36d1d8235f73253fb319d24c509f9deaf119ef Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 26 May 2023 13:30:22 +0100 Subject: [PATCH 51/69] Add method to update virtual registers --- .../comp2023/optimization/RegisterAllocation.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java index 9056cf5..b924185 100644 --- a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -25,7 +25,7 @@ public RegisterAllocation(Method method, int registerAllocationOption) { livenessAnalysis(); createInterferenceGraph(); graphColoring(); //Updates optimalRegisters - //updateVarsRegisters(); + updateVirtualRegisters(); } private void livenessAnalysis(){ @@ -74,6 +74,18 @@ private void graphColoring() { this.optimalRegisters = this.interferenceGraph.findOptimalColoring(); } + private void updateVirtualRegisters(){ + int firstLocalVarRegister = methodAccessThis(method) + numParams(method); + + for (Map.Entry entry : optimalRegisters.entrySet()) { + String var = entry.getKey(); + Integer register = entry.getValue(); + int virtualRegister = firstLocalVarRegister + register; + + method.getVarTable().get(var).setVirtualReg(virtualRegister); + } + } + private Set getDef(Instruction instruction){ Set def = new HashSet<>(); From a9d1b0acf032e471106dca5ab3d3bb8220a00930 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 26 May 2023 13:41:35 +0100 Subject: [PATCH 52/69] Refactor the method that checks if an Element is a local var --- .../optimization/OptimizationUtils.java | 3 +-- .../interferenceGraph/MyInterferenceGraph.java | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java index 4c6a92d..8bf8e89 100644 --- a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java +++ b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java @@ -39,9 +39,8 @@ public static Set unionSets(Set set1, Set set2) { public static boolean isLocalVar(Element element, Method method) { HashMap varTable = method.getVarTable(); String varName = ((Operand)element).getName(); - int firstLocalVarRegister = method.isStaticMethod() ? 0 : 1 + method.getParams().size(); - return varTable.get(varName).getVirtualReg() >= firstLocalVarRegister; + return isLocalVar(varName, method); } public static boolean isLocalVar(String identifier, Method method) { diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java index c901564..2f717ac 100644 --- a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java @@ -4,7 +4,7 @@ public class MyInterferenceGraph { private final List nodes = new ArrayList<>(); - private Map nodeColor = new HashMap<>(); + private final Map nodeColor = new HashMap<>(); public MyInterferenceGraph deepCopy(){ MyInterferenceGraph copy = new MyInterferenceGraph(); @@ -26,6 +26,7 @@ public MyNode getNode(String varName){ } return null; } + public void addInterferenceEdge(String src, String dest){ getNode(src).getAdj().add(dest); getNode(dest).getAdj().add(src); @@ -50,6 +51,14 @@ public void removeNode(MyNode node){ this.nodes.remove(node); } + private boolean isValidColor(MyNode node, int color){ + for(String adj : node.getAdj()){ + if(nodeColor.get(adj) == color) + return false; + } + return true; + } + public Stack computeMColoringStack(int maxColors){ Stack stack = new Stack<>(); boolean foundNode; @@ -99,11 +108,4 @@ public Map findOptimalColoring(){ return this.nodeColor; } - private boolean isValidColor(MyNode node, int color){ - for(String adj : node.getAdj()){ - if(nodeColor.get(adj) == color) - return false; - } - return true; - } } From ecc3450b50866e785c40c058bd80f479375bd9cc Mon Sep 17 00:00:00 2001 From: Comp2023 TP Teachers Date: Fri, 26 May 2023 16:56:38 +0100 Subject: [PATCH 53/69] Updates OLLIR JAR to support interface TreeNode (e.g. Instruction now has .getChildren()) --- libs/comp2023-ollir-sources.jar | Bin 56192 -> 58443 bytes libs/comp2023-ollir.jar | Bin 91980 -> 95878 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/libs/comp2023-ollir-sources.jar b/libs/comp2023-ollir-sources.jar index 7841631f482cad36b4be784084ae396e31a27b9a..d6cfa168433f1cbafc3d1cf571ff1fb2df931483 100644 GIT binary patch delta 16641 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 P!1eZ}d?QMa{L}hBREFYx diff --git a/libs/comp2023-ollir.jar b/libs/comp2023-ollir.jar index 5dfb25f5b00665edf8b15216f6719a25b04cca83..e31b06abea4891000c6003ba921c843933d96a30 100644 GIT binary patch delta 28741 zcmY(pV~l3ux-{ILwr$(CZQHi3r)}Guwr$(CjcIpJ8{h1G&YLeMS;@7MJ6Tyj?yA&P zRnxQJVb|briZY;J&_FDrO zAn^ZQ)YZW!W<$V%fEWzRRZk}<(h0UsJD5~$x0j4(!Qn0rOUQS4BXcd;Rx*3@b^ z1MJHdc08man(J4iGo#W5&tIRv-YuHXnw2lO_`W*I04fT%)AUXv>{QS9pc@-JFa9rG z@f|#$-)EO~K(mKi_^t&iBI$8*5sa{#@>F^?5yEVG^;4v=I>{v-L!sV+7C6Q|!{R%;GOu)SdGM#FYh@TqB(bco7N)uZj=%9Vb-UM^(fAvUPW^^{QGRBL|Aaw*|xEmyzj`$d99z}f+ zh5x400sF-1?&=-Lik+XDnG(Z!dqlMcV1owsgKDQnhYJ3ZA5X4bMB_fmuZ?iV> zTyO?OB7Q`&{=wR(t$2@ip26g5c1_F`djcyXyEf@En0ewtE_KM&)jxx?&2-$waOI2v zJ9%*6xV>*mD%`oye=6w14BLf57X~b+ReY~_YfCC&b`KR7Zv1Hnc>W#VbP#L|nt9u} z>>3rW*1A+PKXB`?qyT%k7e5Ur#`!n?i&fSq^Lw5So2(EANAlnkAZRDTb?$D5kXM*~ zD(ybN7#&w%?hSXMkxQ{<)l(meg6&GoCnK=rnxiVJBd4E7^H9hJ5HWe$P_)~ApsZ#x zi#WZ`QbAM+ySk_W47jjSU(EM+TW-6Z-aMf#)=tAC=K|*#l=xuq7ry#DGhlW zGDNz{D-px+&zo`TK!qvBc|{KZ^u={v=Vej|+`$!uON)Rox1rkst1 znykKZdOP~5wOV=15L62~=j>t{=w1t@XEe>1g7AFJyLNGD3I?yW&dq})X~7km`@!1E^XkQR6K5WLeB ztxC;#T6>y;XRGuTd^|(9zBTg=(@B#^jZ-z^s*nEy@KtgD<-9qBJE4p7@l2*IN%zmM z6x-BGioZS46w&7WR2o!R>Z3D(7C5 z^t`YK7#PFU76b7NN`xO)_>56eU|a~?bIfx$&>fNKUmCnA0TSf6k>d>Kmo>y-UWQ3l zO}H0qknrt&Y8mS$c*okSqd!X95iYEA$bbQc?I|>p_EX}j`oxU;&?_rZcjA(q3(kb> zw`8O=&D=a z{R;>P3^^Hr3Maiw9T=gh9cuL#(ti&3TX-dVL4kn!Ac25rlM|t^(&06L(E+h)(f0oc zo$rWqcX)$*U%8AG&aEGKi&ytOgc}M|q`yLnQa)C(L>kAZKHb*6W`{}n`*;3=I$TA< zCc?RdT8>t>VUioNOkQqo$JsW|*)Gq=-jBmK_#I!K9B~*Es1wSOB&6>1r#sX6q`9K4 zH_uMd8E2~j?XSQc_bU5>Pk_G4Mjnk}{si-+p%a@w5%fxOf>WrQ4@3cDJEQnc0RAJ9J9zYBq(49Poj5JNk zKa>+VCpUc*B=}4UPuC+@q+6#!P|MOl!42n9A~v0&*)L|CZo8&V1M;?g(f<|}W+6v= z*x2t$sMa!)a#r~k7KodSIZ@B{0NSs;S~G5rOdZ7F~`hRCiw%03g>He zNZyOgi2}W@(yBuH0qAX!$qGSRw$<~C?l1^@+FAFe%D&7!CKAq01vAI&KmBFKFF>7i z_sMG$YC%|U-sRlW)Q6vBsy1e>OR~(j=z7e7x$spV%v?sOfHqD0!3vuQ$&*RFe=PE;(#q8}-^xz6#quy39rS9I)GQlrbD+mx;l|Hn^odK=w6K$^F3{O-L zPu{Jv*J7MHMuZKH?&0r$>b!OENeq5))(~Wx`AL<$`+WqOy##-% z4z7ss@41Assef=@BOTsD6dEESX8XYZ4-GVdq9K9*SH5+WQ`X}^0RiD+CJX*kZ+zGo zfC~W17?%HNQepxI>>(pOCOfLF)&npn7;@L|eZfOf!D!%c!Q|?a7CKs)sAghZE}W!< zW};(D7^%%gVeiG1`SnvvmnX?B)*gWufs496ewMB@Gb=NZrKe!=CYIa#?y>IM>9L>Q zcl-dj*D+hwfumpz5jJzEYH5pKTP|2EfHa%<5((z(3sdGqyIc08i9FTW$x{<`;#}l% zsS^oz^Xclus53Cp_>{vnMjYV4j>zRg*Xe|iu6R?~K(vJ@VKSjIge<`wp`(O_JXYo4 z>mGIXMC|P(1=1sP_5keZ6~$;Tkfu)LijWqmeiZ9n96>}FU(IqOBy^bbTJF*Sz_X5( zPILdDqD!-?Q5maoWSIB1=w_fOyM^6slKVd?S|jB$EUT3(^zM`y20>efL^4{xkt@IO z-W$R;tToH5jIM_YllmunfNrVEZGb_q#HJmK=7O3enMuVdP#t6Bq&u$ZB1ld1TBJCP z9BVSn3W*t>r}bH?j?D&Arfy~yklEl$E#C%CG*8^KNL^3wI#eoIc#XYkNcTvUIj+U? zi+ss0Q7*p?dE$9yquPm78bo_9P{&uZ?m*oZQFC8dq>T|z)w+iav?FQE zxPViuGd#w&?#*#mb|fQ)qy5HMNT|elRUXb@IK7SkP}Uhs5IAI`5`fiQs$P~*E=Attkw$`f$=IF`mxYD-?9(uGyZ$d@sJ6Lo8>P4c0O4GY>M@agNBYlK zseR+`Os$=H6J;crTKnIwV?{=$zr_$9T|3codYTf0Pek;GhD2^c(iwKW){i? zi@PMG$9c>oIEj^T(JX5fU8KEC2`>6|xp+$toOlN^aPB=LvE&EY_82bm7Vpq_>11qq zd%2|QRxv1QlN&Bk0m+|O8^w7wDLC@rrUzGYu%)o2RI&QE>bsq#429X6m8X-E7;R<_ z9^CR?EeoQP$KrjNJ9bYL9mp|_0u(RU8zGJt~) z*ncrM26BcK)5zSt)I-aAjl+>MmTa&Z4z9&Vf%QcQx1e{l0d-(TgK8kySl$%asdkdh zzekqks9uug!X$?M&bSX*!oA(mQj5Z*CGjLyn8h2YfNSDP9+`DOcvEI81ua5l+m^Qc z=8V!7>QU2@(L!|3%uK`dI27b{j@J(tZBFXt4eyst$pTSc+J5#jEMo3q+0FRL_J0Or z%f4Tz1!^#!0RVI(8c74LWLGIt8u1szKT@lvOEB_W3$siwW6&QQhv2)~)6YA&?)6WV zDt!&I?`}=A3fLrHP9`hEO=c_Dc^b+7hT!LNXH85lI>PuNp=2W+a+gOlmNMLSP7C9< z95scmyc#?(N5HzHXau#BRc~z12NTRR26jWGDt6Z#fN6FS{T|N`KD}*NJYk*l9a<78 zmNx1vd4w~TT>A7(=ot6%sqvRC*Bxi1#r@q7vj^@^8Fv0c7{9}wQW$|w#Zq`jQTF~->-j?=XPP%`mCyQ@;tcbW`=Gzu6F3T zPGns70As+r|Is2SAz%8>~0%O`YeDR>T2KyR3KcOjT{uqZr#&4C# z3>X?mHn?orKn#bZKj8X@!clAN$wV&!!QoT1LDbx2(yjGiVkPYcH_vu!_cp2|C5 zcf0sz$-!|U+i3ib9!Qrbx-OM+bBMz@OjL zX7)5@y=$QxvsoPN&*Z%)L52zy3Ayybm3P;|L3l^$uIthY>CN9H)7|hK2)S{JTP@!; z;0M%4xkgt}{^9gF!y7io@GM7jTKuME|}3TP8cO z_X?s>6VCo(j&V@|&5-gTAySJy5_=pZwO?k3Ylk@~nNum0@eVq#$c;ywxV0~FfCm!h z$xjC?F}-#-)IvwUzm(4*ReyRG#flMcQ4^|7FM-1&k0DR@DHm`>@bE{Nc}IK37NRIn zE9F|#Kq}eQ;6t)5_1Th7im>+>L^W=5_w#az1r%35=NnFOJ4!6F z$g8b#tz%g271p=3&BO36%ee5%09h7{1apgta|%SEeH{x{0Uk@<13WfiPI1>fpNrdTPht7?B^OE#0EqWf31{ z>NOe}QFV>3y`}Zxb{F7RvH$ZxH%J`3M+Q&rw{6>G^t-{~RVR%>1I~F>_Se0dyyM-`%wNldIz#-w_!2)4kD^U8HW~r_nmqo9eDkrpcIKm`8u28CaMILyJ^S3BI zh%wZ>6-FOu`CQ`Ca>kI!C!k9uBh+h3Dj!4+EzkfuZdH+%8#DqmwPiBC=jCoe9!~m# z?AwiltYJqbp%>3ooS_#HKj;)K$(SQ z-L&Ly$Vv);F?>nRoY~4WYcna!%uWicHE2Abkm92YHu~{RkEdlvdnv+>G+Ubm%TCso zLjp;hG^9Mrxg7cwVxE$+A*QD@=y0=B-e`apEmhdhRkJNzmP+4tPDv@WW4l#+(OX=* zuwZf_Ygsv1&WXq5H$=(g8#VeqC%DnjDod7~IVvrnyk@GQerd;nUV;rhtX^`&n6|LH zf)rX>}j}`-Yz_^`FEDSlXh8=eomN24Ccgl>oa`AM){#>gBB5oPs_BqorE$5g&eg! z8U+%-WmrCb{Wpe_PRSuFQk$f3NVNpc>d4In^(>+gJl2pEi-``gwM7Ldj!n70A_j)` z7S{QSHh9yQ5XLqg_3Vh(@#^~r_>1apXD{VyAzjE{YW4!Xfx-TBTV#^DAoXD@J!OY% zR^5Tf78QnW`^&UD$KojYoH6Eur{m2ozt5vNh9?Tn-rk*+eO^mWlwNPc>yC!YS?X41=6mgITbirq6#wVXKM zez;cf#+Nx7c&VNwBqYk8$Y#VfBZK!3M{}F~#U}0m5QGS(vXP;MzjusQEC2LwLuqeJ zqYOEWMVsv2Kbwv&XsD!Ogi>v#?%vN3+g_;Ti$vW@V&Wk__5sw|Ip|fU(qOadOhG%< ze7mW3q`IO?@53ATXeNiW+=joKfAb;(w$dxwb(fQp+}4f=B~ON~v~h9njYTRUHLs@~C*H0+WWOo{)X{SO z%ESyide~=%IVajKEFiy&!!+)(VhP7@$}ho=#0jRF!Jlx%r?k0V9&cu)(abZ*2QQb0 zNz-gsC0)D3a^xyZu%#whVqvB|VPq$>TO63ACn<693BM7nKNmL_mO)N}YjEd~xgrXd zZ7`(M=P1d7mWcKEWsEmx<^E;|7=?qFsP=8-YE0);Cg+jPT#`Yf<*IB#MQ_Vo+0ou? z;lDh<8#q6LwuTXT4wD_7_B@sin5Y%|YI?{*<0#UPZ_If;4e$+_l84$<=}b6ttw_9F zd#Tsu$sKk(r>Y|2bb|S<6hg*aQMuj-m64j(cb0;E^sPp>p_ACh&cB1wef`L z_}!U6T1!61x!{MIv%mMxTCqL>uOKA@462enDi7Qft4dG-QPd|(`Fa;};uVJs#$=S; zSq{5_9XLu8xJ6(azfzKKzLsLbn z*JEadYbRk^Z9xxX4|5sD!+RQ@NT1l|_TwHp!@Db+O3QQEZCLH&Op(32h^jMAjIOAJ zal0e(Drj; zKHok}u)Q7+V7Gf!(1T_2aT=!Yo}F$Ddk`hC1BBiQLOV;+mkxMBpTI8|6HG5hq5 zpUbga4Bi`*dKFEc6Yx$4*oT*de7 zGDy^&X-9pdHcCwapEw3MfB!NCDlxeTR!Z?~kj4KDq=(*WN~eea99GdSX4Q$~e};RY zJ2CTye~Jk^i=MW$O)THamTb$HH<|Q^`sS{Jhu%R8c*e_5vR@*aVCBoL-EVmF6n#SP zCnFvb2$Z*bP*{kyN0SH$bpPGKRdBhe+&19fI$ymZy^&ef7dUj1IJx0Ewn{`s=Txl)V?rT9jS>h- z_9Qpm&_#O$cyt_%ch`nd++l-z7~)gNpz+3L-HbX_xBsMKgcKQ9Nb;@+s?#2NT-;k8 z!T9!+IU>#B_XjKgb=GK!kmrhuBg7T{8(ls+)~+NxgK+;d)GU@6N!J40>Z*7vzPTu+ zGn=1D2aTUu0S*U@?y91LK({UmL!VOt{>$8(pbShCfLPW#(`*PscmDNrd$iC`s&}EV zXcs8;jtSp6ebymWndJ4i$SLQIHS3F+env`VMMeefh?7)JAnwav(^*dI8lxCI<1pn5 zWjp)s(p+GO3}l5egf-?Urv@&*xFx$PZj{1N2uV9_JCZAWp{d3x$U~CkP{Ay?J7E(D z4++*7fZn%W)c_-tAPOo_5c=&c(RwCM0zYM)9a{1VW+8T*5v_n+9d!aOTF@O5hL{y< zp>RmGHtw?1o(j|Cd8QM+|0{hVr#{u^eX<0d=*r5Mn$Q;SyIxP7(Ki2d*COb^yoA8M zmhe^wx_`z(FPJ}k?w4ukp{ZE@UTqs52~95|AOkJRV44kl=Y#mAH^f3Wd9{OFEEF;G z-&)|XueXz7qPomN9mQ}&vlwAd^I&RNIX`x#bV!(2ntlAczqSg$~{$xidFAZo6?aR^CMk zxV5J>7tkNI&sotpx~NM0(o2*w2r3!@N$U;1g%DhH2XNj%h5SC#EK$j%11RlajDPag zu~n0|5LXo(6Vd`c@d@XGxsWG$q2?46zC;2q`v|K2m+QWPyzt>ve}ea!cmJd_%0q=i zr`(^|WBoAJvt0c(7!oa@(NO3tnnnQt=nr=JDJ-7l_vM%^a!w|py16VSVmgT}tmF`F z8>beaib6HH=h_48Hz+z!wl?VEcNOX;{*+Z&@gFBiRL5wkCVB z%VKti>xjH~pC$A1%-xxp18@2n8`lUK6bs+yo?5aO0R+u?}0RegcGY=X6Wd)e& zh+4onfLL`q4ID94e{wMPkdoyTW#E!6XuDnMP3s1BNirlbxB{?X%^G`l5-m-47k7&0 zSDDXCu5X~fl(+}DUpEeSb?5i9HxKB_`;M6A=C^*Q9dkV%VSPVaKPdfO>sR7nc+f@E z+zTTK?%RKJ*7n2FS#oN`XB%jjX3+4u)E(Wn0OfOAd5+m(jCk3FON&+8#*!)QPj-A3 z7th|cw7N_Bb2Jf5+m<`@ta4SOJDjM)YEOb@=UJ?FDzZ$jq$;VLwFL?TYG`#t0|hN) zE>Xg=oWQIi0A{x|iJ+n@4JSNMQ45*9W7Md^Xf>5(t5c{Qbo`;*W34%M!=#r#)DTRf zfbPHI!CP!$KIso|Boq;lyNdVZ;+Wp69h%mTi!I`~$l*`fgU!xlODJ#nmhC0`tx;`^ zla41(7GdQU{&RjOr)b+onB4qs9ab3> zrBTQHwZ!2cu+&cJYDN%Nm}CzaWK-$4fWnm9YxI@0N}O%Pv+}fp7&7hL(a(Su%#R*lTN|YP)@QG?oJOd1o?yL(9E3GoS zZ-M8ARVPF~8(B?Z>tvjaWm5S*fHR2w?rx+j&ukumVJ} zfj5Gcs^vG)@n0^He?RfJuLJ=4kx7m;y|{kj0DnM&y)y3w|HwZ-HXb&sVv3izdNF-# z*oW&i_O*lb&~ZTm3#Lv42+DDLr(k@e4%7T82=)&+`=z-0Jg+zT`(?f>-lm`4zPi+d zsXO5dl;gtw6{%;S`jG+_*U*+u^ZJOsKK#i5i@CQg`d1Ye)-wMt6d`k$Cn-tHJFdgO zq#iTYBhmnRNHQ4{3zacW!Ll{%7rzIcA)0f1p|F9>uotEntzjZDKnI!)+MT~7ckVNH zyl|*axAE+SeC!Bx#?;v-AWE2JwFj` zGd^S;uQ%R1pv*?OiBGo8-0c#q6?+uT&|iKR4bU3JaQuVStWVPA@Tv470lIB5d53qo z-oO9z|F{Vp66inelqQaHkpCu{k~dtYtp5^CmVc2a@qbtfAZBZ3XJ+q8Z(?iY;u5R6 zrHmqk$d?>qi_B3Jp?hqsS|o*dh)3obD?X1_Jvd11t33!wlbySK0~RfCPvWaMC4+|G zA3$KX(WI4@0CU1Wee>j+f5Ts9@$yW&7=#6EN#|8QfumZnv~SU3=q|w1!z!B&1{k z_cM$fzxB7b>4Miq9D)iE?RSdsNmL)LaNm0U`~7ly-i)Se{mRZLbz z`dXt54a!+;q&TJp%an7Glp|DCm3yt|)*&D9nRRFe5FMkOW%_-hpIg_BpoRHIe-Y=Q z==dmOp0VPHml?L0j}Hr3nRST?_O$bf2`DT&sz3%dy$fxl<}WS1O?weZ_$QK>Iy?Uz z^$Na0J+2Htp_TI+8{87?MlBh#+-JbCS;NFvfLoa6#@-W7+E6-93*1dF6NhahEM}4Q zrcJ30pu*2EX2LF7G>2DTBrIjjj8n5=+uJ`DwNWIvjgCLbD0+(A1w~ZD0cw1S=Pu`p ziNCjaGAV_4nQaNCwPapx!Lh2_xZ>uipTEkIyfq(^i0>lnuZFIDv|OD)oCFo`C<>fe z$&pG}g@_ofg~rvLV8`i|#&jj>4gOG>dI#tjfc(7Z!gg~zn>l3NYFQ?iWS(aJwteX< zcY&Wo;*>goGP|`$+BpTee4dmvnKn?&n1s-fe<&iBZ0x{(gPkwl2U~y9^h*N)TR%~L ztZQ+bJ=ZDl#w?9qJaAWW4dt>BfKdb0_;Ns9!_rK%m|f8{=utoSgfu`~SlZfy|Tf~eW*D?WjP>$W$OU}`|CC}*YAk)22>@=Pp$Bd z(>%z(*sqXdA3m+fgrOZJ9WJ&2AO*^T;g(jB7!qJ=RX}=OT-9o&8OIZ7&rLgc-uKne zzB$zYMYkltxV<|BJ2L%TAVyV!d?sA2DjkqY{W++LvnwTP)f0v}LLrqVGOZes3C(mC zc}RY`QqUn;*wfUJHcJdFjtcXA!~eI$S^O?xHvjF93+)>hrhb1vv-l72{{!6r;H`v@ z9Q40 z_PgPAxn*$~68ORUgxiPkk0^vAf-=Ioj$q8$RQFhkDaL%Ml_FDLbmH)qkqlz&7BaDbBAO zVRutu8%ECOr!YxS0C-%;$IVt(g?;Oy&Il`uiJXn6*0j=tvzzEmHSbhcTpR;t|y8vhOEx)OpeT|524Ydq4uCa{>|s-CJ78`R-hmYEO( zHd4g4=^Im-VudR4in`s}$wH~-wNNf4&MAwR9=1k*1W=`D=_}nCX}J_q&9kxTBm8_w z_}8i0Q0=-XZH22aBcpqIPGQY^wNZDhWo5GH)LsimUIC1U36oNWvBQs2WThq+m*Y< zaf5QT^w8c4U%y)YVkdHzl?NGSj?wK%U_QfBB_1GcQVHz!rE)*`Dkd zgqp6XtWnes;h-WwJxqR`ZM1`(}Uly^XX^QI$<(i!_M`F_YBcDZY8>>lGA2ZI1LH~G@vcY|V7 z2?+8G2)d;q85Q(-SAhM}cR@o+o`4{}W+R?*6-V$Lqgc$u-wscL=g6(emIf<#Z9PI} z>e}uvZyGH}p+S|N-ABUz#i;CWW8_Mfut2B|+7DW@|0i&t?VSo8ajjvseV254n90dc z7~}v45TpPa5z{jISDi3%?yduY-Iur+3~)mX^%c{bF8MG3431oPcf)YLPuj&fk#INt zhmKLi)PhM=%nj@j&Q!w2R3dZ|D{s*Q(@w;<=c&Lg2MC9J%bjl~BX!WWK9$G2s#~KO8NkXq z@GeG0rI~%B5vD-D>JXz-0K#y>)HB6!kJbqg0sbs}&!8^fM)6Y}kfa^o@3u$M92wGF zD(MT{k_TWim()gOi>}iqKkC`pZ?a@W>B9(}`GLJQ$kvHwVr`w~T1yYHj}puLBO4^d zFo!#kJ(GRF|Dk7i^_AX84eft2sN!F-i{^i683UkdqktlW%D40@)V&ZAvYLEE&;qsj8(V2g5h6-CsTkJN$9 zrP$PwqvPo;tkp?#H)mKD@yZBPMiueM_=9&L|nMEG^r$oTfv`72E zHh}ak$8ldtv$`S;QH~O~*X;w3VsT%lV+Dcr&nK_Tvr8inm^Sfw*oY^Xo{1r$pf zN|!Uv%;%RAwFtfGx{Ks8hOkF@Ewbh<$n~o5^Bu3|xm(W5YLsRy#rVxEj^S5So$u zX=CY_tud)%rO7}Mm?Y-BupT2$(eE!2-EEp+KvbhNjv07zi5lL5k&vSLwM*N*D7sF1EIA%UvmPJTJJcmIG zp`OsMRt`>$MJ@VuoK1+I;$S;SOEh6zuLN&=kZO{8x0W@2FRN~B+Uka3lW8n^9k*-& z3*Ki;8eoudciE_4EF++BLdYyIUU`25#6Z72NJ#9psCVJ;zXE0pYUMZT|1z7 z8S|5L%6_u7YVdzB*il8g3jO-=LPXQ2O?F(m)R zw!JPy@|G4VKs+&u5VD984U-xTO^Jyd6oSwQ0dUNm(d%cOM8>6YQC>*)!#MbsW6VRGg{!S zDO1}v-!W@Ya?}vCN!Quhc-ao={h5aQoL9&z)3dw(9*4Nrb{Ik6t8%M95_7YlAY9T& ztVOZqN}Tg0_PH8%+M74ZaU4ji8UL&98+LO9Fv&hpyNEuShcmqj?;6t{FbPcj!R0`+ z@N#M-H>p%%8=8+!1EGlP(Zng1aS5ldoDX~5yu-=F!bH7Af-Oki4T#?(it|VB6@D93 znB&l$UgjryBpwkOtYwEsG2h~pE^l^LDPB?$>kOjJl35I`yNASq7HVq`u@9Moc5(xU!D zuU`GWrY?t}gGNTFS<>(@V)=c${bD|03UL8)JnQq4=W@e! zmiJfwb(Mz#pQ0%A@>Ewj#Vld!w=H1OC<_tVLrucFCQi~#qP(n)8x`_(XvL=5(xW_? zierDv9-P?5w?`IyM&s4}qw=HZTab<1nvd|9ohqGImZbIN4K#NKYJad%i)!D?RJm7( zM3%ZBQT9zlJ+ra1nsOU(GH^ZullL07=^D?Opr<7Fb~knauoa@@T-<*g2J95$>B;RTxDsOZ1HCWce-l z`y9Dmm)$1Va>-^9HEYuJ*|KIs+Yoz&H%7K*o{G(id&baNXTZ|aAUlFjRVO2;b<#3T z=!9HN@dVM%3am}QI@E7LF#}*Vjkry2fe&V`(js)0%^H3xynH|?E8fPiXnY-Ot;7y9 z>YGeo04`fwkcY3Arv4U9xSeoBV~48rU`e!+p-Ka`%{dF#E0}LKZ%po>O=1HrUUb0k z$5@1cIkrd?@@L3skN?Axp(qk$(Qwh(8mz0wZ{J=C+k}ha5lLJls~I4TIRji=RpSSt zH_gfnynzn)5v=E>Dmg=5Q;2?b@h3zCwTxwc#u(g2&Ksd7Sj+wD+&U=m)erb56r#bLqFbs{RhZE6(5%sTqTXn%&e!=06g&0jw5AYO5 zLpNTpU_XzJ53b{+xfh^3mLBP7J7qARPPE3ZL`SwWrF9UvRY&jJP^Nq-=#it04^yie zEoVw@lbkaQ?J7kobIV>iT(irkjbZy{3x7U2O^T;HdIF`j$nU`Lqjz_D*-T00CEFGJ z8Z0T#0rHjj4%@+-w5JmvIuPdXyl8NcNZb^Er0!*j9z>{I6e8fNn3b;NJr14*SqtUz z>Gn>?=*p7TL074-7fXVbtX0Akxe~ z#L9Z33n)5sSCD|^;%HD<-DJuc=@jK(?NP#zw6#dbmv6n#vOQ5I=Joe++SUkE)}m*R zAS=$(o-E1|^CD)wH)4{@1^s)oP(IUzeW!(`>^erIHXp!{ZaICvPe8Q?9aeN8?Bq`c zop91M$3@c}#g}xWedHs8U6oT~UWU!u?-?t&yLTy9_J~BOlyi`X+M52CQ1go3t_HT)ErFoHk z)TKtcB3MA?;Z9KZ(JRFTQ*f{C;?a{RIf0yzaEg9wZEuN@nmC5s&PYKWV`^DEX`$g+ zV?D$A0w3v5P7#INJ2szL8GY`M%42>pRB$i6*V3YWY6BB4eCSa_4-OjOc?y z_7fh`R!d_`&q~3qxpM!cA}ec1kHxtZ!j9CB$s*u|Ecfi4WTq1g67wlo7Gh@;Ccv;P zJg*o-_Puc2T#(&~sA9+8b}{-1Wf?ugMlPyfg$2*d8TK3NYr7y_);rUGz;$vjp$5Xdn9phj9njYAwG3q4B%}lGCDn%XXA&$X5@g zwJ1QUkK+PxfzVpt`X)O`nuJoKUm_r#@{Y2U1e@0}fMNd!61e?>HiR^&N4yT_2_yMi z+QBrc*j<+)cSu!lvvrK%I$=@qsz5b34cf8-f)4K#(po0@m-~}P^6u|8LSxEpDl1V9 zM>&Wul4K#a0&_{?G?}ssyX4(MAynG${Tl$Hv8r!8tdgGOI{ozYXcmB1 z9@WUWVn$f=CWPG7sCxp%lXw$2QjptYY(7CYEafdS#DP&e3G1RsiuCXnnmimSZ&*LM zZ2a^P*Dpz;>hUM#k?b3Hol9J^jHG5WH*~` z{)Q9cHY~Ai3|q_k%xgEtL!`K;v}ftiLtcdh{HCiw6qi4QBX>YWK!RG6*4z3$XPi8d zeM0NJwpv$Zu(ZD04qx)i!1_VG(BzdQcCo*>@pwvZca(p6;C1tzn>!(5R@sD@8%8;N zBA4lRixEuD@;!WVS3Axafe=6{IBq8N9jWk>)WGOLUTTf&5BAntoek3ZRA_d=1d-7W znvhFc^oAaJIQaav2Q@M9wWA9G3Q_7ke)5ZSL+VoDln{pj)bU1cVflbY3Az)`P|^k* z|2QjsYyBWX&9m6T^CnqdIKn&`{_flwp~L-$;%55D)PgA|+C zhWp{ARr8rX40Te*hS{=5jSqnip5LdyAcjx5P@nF^fcX2WjRFM3QX~-25+~v(srSdWKh+=;b#7L6Z3iMq*z{3NKiQJ=k%9FRZ|3niihXB6m%07a z2oVkT<9%LrKG}l%ax0`#lc|dmi)>M6Lh<)0LJK8haSzwFKLr@Aw3aHiaW)Tju3a;h*TG77IR0s z)S#`lXumTj1kTbCX%UMqK?6fv%C^mm4B0VHUY47;`hRLJ-C>{A6zp-VfeBdS&R`bR zklifmywjGM^n#X@NivGVSTLU#Wa@Bzvz||wrc8CiqP4L4H0Y|ZMQOWQv4Bk4uZ7v1R8K+ zPItJ1z#(vf#o;aNrxo${^Wh0f&WecIli*$FJAzv;4d#^~7U>gFg)|N75qhYi4b(wx z-8$a@8vx3--z<|q8EkgaU;HNmk~;4RW|1;R6=T@fANo9*_ID#!wVsd|4Ge4<^zs}( zb)CnTfN0IjhU4N=ope{K+zL@wY|rMZg3gY(0jjZ23(i(~Y$cEz! zkh4qLw4My>B@d4?Or0GjZ`q}i6z*Shv(LYHY5+ZyI#~g6yeJX^zbLi~7TA34tKGw4 zVScEvk{+XY#Kjh!$iGb>+54RCnm}#zeeBjBcVlnXUoYT#!p*YWYF}E`?QJ#4sj+S) zRVMm{`=y=xz;GTU)Jc081x3&j-C3-P<_WAY-)DdyzyiYLqTX{pWp&TT6VENNG~_lM{Vl_-Byc2{ms$fxYFS@M#XRG}%OxVI8hz%Q*io+n0imz>|y z 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 J2GptH{ttmOV7&kU From b7d7382e835bef3553d4c2a2e8cb4a7affb7f9f8 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Fri, 26 May 2023 18:29:47 +0100 Subject: [PATCH 54/69] Made assign instruction load dependent on whether there was an iinc instruction --- .../comp2023/jasmin/JVMInstructionUtils.java | 35 ++++++++++++++----- .../pt/up/fe/comp2023/jasmin/JasminUtils.java | 6 ++-- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index f130dde..ee13743 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -14,6 +14,7 @@ public class JVMInstructionUtils { public static int stackSize = 0; public static int currStackSize = 0; public static Map varEquivalence = new HashMap<>(); + public static Map iincVars = new HashMap<>(); public static void increaseStackSize(int n) { currStackSize += n; @@ -188,20 +189,30 @@ public static String checkInc(BinaryOpInstruction instruction, Element dest, Has Element leftOperand = instruction.getLeftOperand(); Element rightOperand = instruction.getRightOperand(); String destName = ((Operand)dest).getName(); + String iincVarEquivalent = varEquivalence.get(destName); + + if (iincVarEquivalent == null) + return ""; if (instruction.getOperation().getOpType() == OperationType.ADD && !(leftOperand instanceof LiteralElement) && rightOperand instanceof LiteralElement && - (destName.equals(((Operand)leftOperand).getName()) || (varEquivalence.get(destName).equals(((Operand)leftOperand).getName()))) && - parseInt(((LiteralElement)rightOperand).getLiteral()) == 1) - return "\tiinc " + varTable.get(((Operand)leftOperand).getName()).getVirtualReg() + " 1\n"; + parseInt(((LiteralElement)rightOperand).getLiteral()) == 1) { + if (iincVarEquivalent.equals(((Operand) leftOperand).getName())) + iincVars.put(iincVarEquivalent, destName); + if (destName.equals(((Operand) leftOperand).getName()) || iincVarEquivalent.equals(((Operand) leftOperand).getName())) + return "\tiinc " + varTable.get(((Operand) leftOperand).getName()).getVirtualReg() + " 1\n"; + } if (instruction.getOperation().getOpType() == OperationType.ADD && leftOperand instanceof LiteralElement && !(rightOperand instanceof LiteralElement) && - (destName.equals(((Operand)rightOperand).getName()) || (varEquivalence.get(destName).equals(((Operand)rightOperand).getName()))) && - parseInt(((LiteralElement)leftOperand).getLiteral()) == 1) - return "\tiinc " + varTable.get(((Operand)rightOperand).getName()).getVirtualReg() + " 1\n"; + parseInt(((LiteralElement)leftOperand).getLiteral()) == 1) { + if (iincVarEquivalent.equals(((Operand)rightOperand).getName())) + iincVars.put(iincVarEquivalent, destName); + if (destName.equals(((Operand)rightOperand).getName()) || iincVarEquivalent.equals(((Operand)rightOperand).getName())) + return "\tiinc " + varTable.get(((Operand) rightOperand).getName()).getVirtualReg() + " 1\n"; + } return ""; } @@ -317,14 +328,20 @@ public static boolean checkTempAssign(AssignInstruction instruction) { Instruction rhsInstruction = ((AssignInstruction)instruction).getRhs(); if (!(rhsInstruction instanceof SingleOpInstruction)) return false; - if (!(((SingleOpInstruction)rhsInstruction).getSingleOperand() instanceof Operand)) - return false; - return true; + return ((SingleOpInstruction) rhsInstruction).getSingleOperand() instanceof Operand; } public static String createAssignStatement(AssignInstruction instruction, HashMap varTable) { Element assignElement = instruction.getDest(); String statementList = ""; + + if (checkTempAssign(instruction)) { + Element rhsElement = ((SingleOpInstruction)instruction.getRhs()).getSingleOperand(); + String iincVarEquivalent = iincVars.get(((Operand)assignElement).getName()); + if (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand)rhsElement).getName())) + return ""; + } + if (instruction.getRhs() instanceof BinaryOpInstruction) { statementList = checkInc((BinaryOpInstruction)instruction.getRhs(), assignElement, varTable); if (!statementList.equals("")) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java index b8fc0e8..f9811c1 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java @@ -4,8 +4,6 @@ import java.util.ArrayList; import java.util.HashMap; -import java.util.List; -import java.util.Objects; public class JasminUtils { @@ -111,7 +109,6 @@ public static String createMethodDeclaration(Method method) { } public static String handleInstruction(Instruction instruction, HashMap varTable, boolean isRhs) { - instruction.show(); String statementList = ""; switch (instruction.getInstType()) { case ASSIGN: @@ -201,7 +198,10 @@ public static String handleMethodStatements(Method method) { } public static void createVarEquivalence(Method method) { + JVMInstructionUtils.iincVars.clear(); JVMInstructionUtils.varEquivalence.clear(); + JVMInstructionUtils.iincVars.clear(); + for (Instruction instruction: method.getInstructions()) { if (instruction instanceof AssignInstruction && JVMInstructionUtils.checkTempAssign((AssignInstruction)instruction)) { Operand lhs = ((Operand)((AssignInstruction)instruction).getDest()); From 1d8c9b9875e7de59511ae7159d7eebc604cfda00 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 27 May 2023 19:22:00 +0100 Subject: [PATCH 55/69] Set default value of registerAllocation key --- .../pt/up/fe/comp2023/ollir/Optimization.java | 2 +- .../MyInterferenceGraph.java | 21 +++++++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index 18c076a..deda0a0 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -45,7 +45,7 @@ public JmmSemanticsResult optimize(JmmSemanticsResult semanticsResult) { } public OllirResult optimize(OllirResult ollirResult) { - int registerAllocationOption = Integer.parseInt(ollirResult.getConfig().get("registerAllocation")); + int registerAllocationOption = Integer.parseInt(ollirResult.getConfig().getOrDefault("registerAllocation", "-1")); if (registerAllocationOption >= 0){ ClassUnit classUnit = ollirResult.getOllirClass(); diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java index 2f717ac..8296e3f 100644 --- a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java @@ -61,22 +61,21 @@ private boolean isValidColor(MyNode node, int color){ public Stack computeMColoringStack(int maxColors){ Stack stack = new Stack<>(); - boolean foundNode; while (this.nodes.size() > 0) { - foundNode = false; - Iterator iterator = this.nodes.iterator(); + MyNode nodeToRemove = null; - while (iterator.hasNext()) { - MyNode node = iterator.next(); - - if (node.getAdj().size() < maxColors) { - foundNode = true; - stack.push(node.getVariable()); - this.removeNode(node); + for(MyNode node : this.nodes){ + if(node.getAdj().size() < maxColors){ + nodeToRemove = node; + break; } } - if (!foundNode) + if(nodeToRemove != null){ + stack.push(nodeToRemove.getVariable()); + this.removeNode(nodeToRemove); + } + else throw new RuntimeException("The provided number of registers is not enough to store the variables."); } return stack; From d2710838b3f4a76f39572b7a2098425caa6e07fd Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 27 May 2023 19:24:48 +0100 Subject: [PATCH 56/69] Refactor isLocalVar() using methodAccessThis() --- src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java index 8bf8e89..6b059c3 100644 --- a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java +++ b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java @@ -45,7 +45,7 @@ public static boolean isLocalVar(Element element, Method method) { public static boolean isLocalVar(String identifier, Method method) { HashMap varTable = method.getVarTable(); - int firstLocalVarRegister = method.isStaticMethod() ? 0 : 1 + method.getParams().size(); + int firstLocalVarRegister = methodAccessThis(method) + method.getParams().size(); return varTable.get(identifier).getVirtualReg() >= firstLocalVarRegister; } From 37e6c227a837e6ced79019498cfdf10d718809cd Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 27 May 2023 19:52:57 +0100 Subject: [PATCH 57/69] Improved findOptimalColoring() --- .../MyInterferenceGraph.java | 43 +++++++++++++++++-- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java index 8296e3f..37ec6f2 100644 --- a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java @@ -81,6 +81,30 @@ public Stack computeMColoringStack(int maxColors){ return stack; } + public Stack computeOptimalColoringStack(int maxColors){ + Stack stack = new Stack<>(); + + while (this.nodes.size() > 0) { + MyNode nodeToRemove = null; + + for(MyNode node : this.nodes){ + if(node.getAdj().size() < maxColors){ + nodeToRemove = node; + break; + } + } + if(nodeToRemove != null){ + stack.push(nodeToRemove.getVariable()); + this.removeNode(nodeToRemove); + } + else{ + stack.clear(); + return stack; + } + } + return stack; + } + public Map isMColoringFeasible(int maxColors){ MyInterferenceGraph copyGraph = deepCopy(); Stack stack = copyGraph.computeMColoringStack(maxColors); @@ -98,11 +122,22 @@ public Map isMColoringFeasible(int maxColors){ public Map findOptimalColoring(){ int maxColors = this.nodes.size(); - for(MyNode node : this.nodes){ - for(int color = 0; color < maxColors; color++){ - if(isValidColor(node, color)) - nodeColor.put(node.getVariable(), color); + for(int currentMaxColors = 1; currentMaxColors <= maxColors; currentMaxColors++){ + this.nodeColor.clear(); + MyInterferenceGraph copyGraph = deepCopy(); + Stack stack = copyGraph.computeOptimalColoringStack(currentMaxColors); + + if(stack.isEmpty()) + continue; + + while (!stack.isEmpty()){ + String nodeName = stack.pop(); + for(int color = 0; color < maxColors; color++){ + if(isValidColor(getNode(nodeName), color)) + this.nodeColor.put(nodeName, color); + } } + break; } return this.nodeColor; } From 631228d25c5d311af1d27acf5c22037a007811f5 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Sat, 27 May 2023 20:52:16 +0000 Subject: [PATCH 58/69] Used iinc for other additions besides 1 --- .../up/fe/comp2023/jasmin/JVMInstructionUtils.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index ee13743..4d94357 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -196,22 +196,22 @@ public static String checkInc(BinaryOpInstruction instruction, Element dest, Has if (instruction.getOperation().getOpType() == OperationType.ADD && !(leftOperand instanceof LiteralElement) && - rightOperand instanceof LiteralElement && - parseInt(((LiteralElement)rightOperand).getLiteral()) == 1) { + rightOperand instanceof LiteralElement) { if (iincVarEquivalent.equals(((Operand) leftOperand).getName())) iincVars.put(iincVarEquivalent, destName); if (destName.equals(((Operand) leftOperand).getName()) || iincVarEquivalent.equals(((Operand) leftOperand).getName())) - return "\tiinc " + varTable.get(((Operand) leftOperand).getName()).getVirtualReg() + " 1\n"; + return "\tiinc " + varTable.get(((Operand) leftOperand).getName()).getVirtualReg() + + " " + ((LiteralElement)rightOperand).getLiteral() + "\n"; } if (instruction.getOperation().getOpType() == OperationType.ADD && leftOperand instanceof LiteralElement && - !(rightOperand instanceof LiteralElement) && - parseInt(((LiteralElement)leftOperand).getLiteral()) == 1) { + !(rightOperand instanceof LiteralElement)) { if (iincVarEquivalent.equals(((Operand)rightOperand).getName())) iincVars.put(iincVarEquivalent, destName); if (destName.equals(((Operand)rightOperand).getName()) || iincVarEquivalent.equals(((Operand)rightOperand).getName())) - return "\tiinc " + varTable.get(((Operand) rightOperand).getName()).getVirtualReg() + " 1\n"; + return "\tiinc " + varTable.get(((Operand) rightOperand).getName()).getVirtualReg() + + " " + ((LiteralElement)leftOperand).getLiteral() + "\n"; } return ""; From 71f11ccea544c31d719852280c3a27ba3e008b16 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Sat, 27 May 2023 21:13:25 +0000 Subject: [PATCH 59/69] Fixed var equivalence data structure usage in iinc to also accept ollir without temps --- .../up/fe/comp2023/jasmin/JVMInstructionUtils.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 4d94357..090095f 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -191,15 +191,13 @@ public static String checkInc(BinaryOpInstruction instruction, Element dest, Has String destName = ((Operand)dest).getName(); String iincVarEquivalent = varEquivalence.get(destName); - if (iincVarEquivalent == null) - return ""; - if (instruction.getOperation().getOpType() == OperationType.ADD && !(leftOperand instanceof LiteralElement) && rightOperand instanceof LiteralElement) { - if (iincVarEquivalent.equals(((Operand) leftOperand).getName())) + if (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand) leftOperand).getName())) iincVars.put(iincVarEquivalent, destName); - if (destName.equals(((Operand) leftOperand).getName()) || iincVarEquivalent.equals(((Operand) leftOperand).getName())) + if (destName.equals(((Operand) leftOperand).getName()) || + (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand) leftOperand).getName()))) return "\tiinc " + varTable.get(((Operand) leftOperand).getName()).getVirtualReg() + " " + ((LiteralElement)rightOperand).getLiteral() + "\n"; } @@ -207,9 +205,10 @@ public static String checkInc(BinaryOpInstruction instruction, Element dest, Has if (instruction.getOperation().getOpType() == OperationType.ADD && leftOperand instanceof LiteralElement && !(rightOperand instanceof LiteralElement)) { - if (iincVarEquivalent.equals(((Operand)rightOperand).getName())) + if (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand)rightOperand).getName())) iincVars.put(iincVarEquivalent, destName); - if (destName.equals(((Operand)rightOperand).getName()) || iincVarEquivalent.equals(((Operand)rightOperand).getName())) + if (destName.equals(((Operand)rightOperand).getName()) || + (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand)rightOperand).getName()))) return "\tiinc " + varTable.get(((Operand) rightOperand).getName()).getVirtualReg() + " " + ((LiteralElement)leftOperand).getLiteral() + "\n"; } From ae10e7937f5309dc5c89f74d20d4e2190cc3cf65 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Sat, 27 May 2023 21:22:17 +0000 Subject: [PATCH 60/69] Implemented iinc for negative constants --- .../fe/comp2023/jasmin/JVMInstructionUtils.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 090095f..64ca0c3 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -186,31 +186,36 @@ public static String createUnaryOpStatement(UnaryOpInstruction instruction, Hash } public static String checkInc(BinaryOpInstruction instruction, Element dest, HashMap varTable) { + OperationType operationType = instruction.getOperation().getOpType(); Element leftOperand = instruction.getLeftOperand(); Element rightOperand = instruction.getRightOperand(); String destName = ((Operand)dest).getName(); String iincVarEquivalent = varEquivalence.get(destName); - if (instruction.getOperation().getOpType() == OperationType.ADD && + if ((operationType == OperationType.ADD || operationType == OperationType.SUB) && !(leftOperand instanceof LiteralElement) && rightOperand instanceof LiteralElement) { + if (instruction.getOperation().getOpType() == OperationType.ADD) + if (instruction.getOperation().getOpType() == OperationType.SUB) if (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand) leftOperand).getName())) iincVars.put(iincVarEquivalent, destName); if (destName.equals(((Operand) leftOperand).getName()) || (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand) leftOperand).getName()))) - return "\tiinc " + varTable.get(((Operand) leftOperand).getName()).getVirtualReg() - + " " + ((LiteralElement)rightOperand).getLiteral() + "\n"; + return "\tiinc " + varTable.get(((Operand) leftOperand).getName()).getVirtualReg() + " " + + (operationType == OperationType.SUB ? "-" : "") + + ((LiteralElement)rightOperand).getLiteral() + "\n"; } - if (instruction.getOperation().getOpType() == OperationType.ADD && + if ((operationType == OperationType.ADD || operationType == OperationType.SUB) && leftOperand instanceof LiteralElement && !(rightOperand instanceof LiteralElement)) { if (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand)rightOperand).getName())) iincVars.put(iincVarEquivalent, destName); if (destName.equals(((Operand)rightOperand).getName()) || (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand)rightOperand).getName()))) - return "\tiinc " + varTable.get(((Operand) rightOperand).getName()).getVirtualReg() - + " " + ((LiteralElement)leftOperand).getLiteral() + "\n"; + return "\tiinc " + varTable.get(((Operand) rightOperand).getName()).getVirtualReg() + " " + + (operationType == OperationType.SUB ? "-" : "") + + ((LiteralElement)leftOperand).getLiteral() + "\n"; } return ""; From 5f24e892650503418cd9132894080c8677f50c45 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Sat, 27 May 2023 21:27:49 +0000 Subject: [PATCH 61/69] Removed unused if --- src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 64ca0c3..15d10a2 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -195,8 +195,6 @@ public static String checkInc(BinaryOpInstruction instruction, Element dest, Has if ((operationType == OperationType.ADD || operationType == OperationType.SUB) && !(leftOperand instanceof LiteralElement) && rightOperand instanceof LiteralElement) { - if (instruction.getOperation().getOpType() == OperationType.ADD) - if (instruction.getOperation().getOpType() == OperationType.SUB) if (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand) leftOperand).getName())) iincVars.put(iincVarEquivalent, destName); if (destName.equals(((Operand) leftOperand).getName()) || From a48208d536ca4f4c076b801765edf6fb265a105f Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sun, 28 May 2023 14:47:11 +0100 Subject: [PATCH 62/69] Refactor MyInterferenceGraph --- .../optimization/RegisterAllocation.java | 11 ----------- .../MyInterferenceGraph.java | 18 +++++++++--------- .../interferenceGraph/MyNode.java | 19 +++++++++---------- .../comp2023/semantic/ExpressionAnalysis.java | 2 +- 4 files changed, 19 insertions(+), 31 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java index b924185..d72ea82 100644 --- a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -35,17 +35,6 @@ private void livenessAnalysis(){ this.uses.put(instruction, getUse(instruction, new HashSet<>())); } computeLiveInOut(); - - //TODO: remove - System.out.println(method.getMethodName()); - System.out.println("------------------"); - for(Instruction instruction : method.getInstructions()){ - instruction.show(); - System.out.println("Defs:" + defs.get(instruction)); - System.out.println("Uses:" + uses.get(instruction)); - System.out.println("In:" + in.get(instruction)); - System.out.println(("Out: "+ out.get(instruction))); - } } private void createInterferenceGraph() { diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java index 37ec6f2..c189fb8 100644 --- a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java @@ -28,8 +28,8 @@ public MyNode getNode(String varName){ } public void addInterferenceEdge(String src, String dest){ - getNode(src).getAdj().add(dest); - getNode(dest).getAdj().add(src); + getNode(src).addNeighbour(dest); + getNode(dest).addNeighbour(src); } public void connectInterferingVariables(List variables){ @@ -44,16 +44,16 @@ public void connectInterferingVariables(List variables){ } public void removeNode(MyNode node){ - for(String adj : node.getAdj()){ - MyNode adjNode = getNode(adj); - adjNode.removeAdj(node.getVariable()); + for(String neighbour : node.getNeighbours()){ + MyNode neighbourNode = getNode(neighbour); + neighbourNode.removeNeighbour(node.getVariable()); } this.nodes.remove(node); } private boolean isValidColor(MyNode node, int color){ - for(String adj : node.getAdj()){ - if(nodeColor.get(adj) == color) + for(String neighbour : node.getNeighbours()){ + if(nodeColor.get(neighbour) == color) return false; } return true; @@ -66,7 +66,7 @@ public Stack computeMColoringStack(int maxColors){ MyNode nodeToRemove = null; for(MyNode node : this.nodes){ - if(node.getAdj().size() < maxColors){ + if(node.getDegree() < maxColors){ nodeToRemove = node; break; } @@ -88,7 +88,7 @@ public Stack computeOptimalColoringStack(int maxColors){ MyNode nodeToRemove = null; for(MyNode node : this.nodes){ - if(node.getAdj().size() < maxColors){ + if(node.getDegree() < maxColors){ nodeToRemove = node; break; } diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyNode.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyNode.java index e3ea03b..ffd784b 100644 --- a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyNode.java +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyNode.java @@ -1,12 +1,11 @@ package pt.up.fe.comp2023.optimization.interferenceGraph; -import org.specs.comp.ollir.Element; import java.util.HashSet; import java.util.Set; public class MyNode { private final String varName; - private final Set adj = new HashSet<>(); + private final Set neighbours = new HashSet<>(); public MyNode(String varName){ this.varName = varName; @@ -16,19 +15,19 @@ public String getVariable() { return this.varName; } - public Set getAdj() { - return adj; + public Set getNeighbours() { + return neighbours; } - public void addAdj(String varName) { - this.adj.add(varName); + public void addNeighbour(String varName) { + this.neighbours.add(varName); } - public int getNodeDegree() { - return this.adj.size(); + public int getDegree() { + return this.neighbours.size(); } - public void removeAdj(String varName){ - this.adj.remove(varName); + public void removeNeighbour(String varName){ + this.neighbours.remove(varName); } } diff --git a/src/main/pt/up/fe/comp2023/semantic/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/semantic/ExpressionAnalysis.java index 0e5cc40..2b5eac9 100644 --- a/src/main/pt/up/fe/comp2023/semantic/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/semantic/ExpressionAnalysis.java @@ -225,7 +225,7 @@ else if(findImport(this.imports, objectClassName)){ } String message = "Cannot find '" + objectClassName + "'."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(jmmNode), getNodeColumn(jmmNode), message)); //TODO: use column of 'classname' + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(jmmNode), getNodeColumn(jmmNode), message)); jmmNode.put(TYPENAME, UNKNOWN); return UNKNOWN_TYPE; } From 59151fe8df30bd7da2bf6879a5c2ecb98a896ef2 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sun, 28 May 2023 14:52:22 +0100 Subject: [PATCH 63/69] Refactor method that computes the coloring stack --- .../MyInterferenceGraph.java | 32 ++++--------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java index c189fb8..7ef0e67 100644 --- a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java @@ -59,7 +59,7 @@ private boolean isValidColor(MyNode node, int color){ return true; } - public Stack computeMColoringStack(int maxColors){ + public Stack computeColoringStack(int maxColors, boolean isOptimal){ Stack stack = new Stack<>(); while (this.nodes.size() > 0) { @@ -75,39 +75,19 @@ public Stack computeMColoringStack(int maxColors){ stack.push(nodeToRemove.getVariable()); this.removeNode(nodeToRemove); } - else - throw new RuntimeException("The provided number of registers is not enough to store the variables."); - } - return stack; - } - - public Stack computeOptimalColoringStack(int maxColors){ - Stack stack = new Stack<>(); - - while (this.nodes.size() > 0) { - MyNode nodeToRemove = null; - - for(MyNode node : this.nodes){ - if(node.getDegree() < maxColors){ - nodeToRemove = node; - break; - } - } - if(nodeToRemove != null){ - stack.push(nodeToRemove.getVariable()); - this.removeNode(nodeToRemove); - } - else{ + else if (isOptimal){ stack.clear(); return stack; } + else + throw new RuntimeException("The provided number of registers is not enough to store the local variables."); } return stack; } public Map isMColoringFeasible(int maxColors){ MyInterferenceGraph copyGraph = deepCopy(); - Stack stack = copyGraph.computeMColoringStack(maxColors); + Stack stack = copyGraph.computeColoringStack(maxColors, false); while (!stack.isEmpty()){ String nodeName = stack.pop(); @@ -125,7 +105,7 @@ public Map findOptimalColoring(){ for(int currentMaxColors = 1; currentMaxColors <= maxColors; currentMaxColors++){ this.nodeColor.clear(); MyInterferenceGraph copyGraph = deepCopy(); - Stack stack = copyGraph.computeOptimalColoringStack(currentMaxColors); + Stack stack = copyGraph.computeColoringStack(currentMaxColors, true); if(stack.isEmpty()) continue; From 80e9cf9f051da4fb51e43368256dd35cd43f24ce Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Sun, 28 May 2023 15:03:57 +0000 Subject: [PATCH 64/69] Fixed limits through which iinc can be used --- .../comp2023/jasmin/JVMInstructionUtils.java | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 15d10a2..1abc42b 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -195,25 +195,35 @@ public static String checkInc(BinaryOpInstruction instruction, Element dest, Has if ((operationType == OperationType.ADD || operationType == OperationType.SUB) && !(leftOperand instanceof LiteralElement) && rightOperand instanceof LiteralElement) { - if (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand) leftOperand).getName())) + String increment = ""; + if (operationType == OperationType.ADD && parseInt(((LiteralElement)rightOperand).getLiteral()) <= 127) + increment = ((LiteralElement)rightOperand).getLiteral(); + else if (operationType == OperationType.SUB && parseInt(((LiteralElement)rightOperand).getLiteral()) <= 128) + increment = "-" + ((LiteralElement)rightOperand).getLiteral(); + if (!Objects.equals(increment, "") && iincVarEquivalent != null && + iincVarEquivalent.equals(((Operand) leftOperand).getName())) iincVars.put(iincVarEquivalent, destName); - if (destName.equals(((Operand) leftOperand).getName()) || - (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand) leftOperand).getName()))) - return "\tiinc " + varTable.get(((Operand) leftOperand).getName()).getVirtualReg() + " " - + (operationType == OperationType.SUB ? "-" : "") - + ((LiteralElement)rightOperand).getLiteral() + "\n"; + if (!Objects.equals(increment, "") && (destName.equals(((Operand) leftOperand).getName()) || + (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand) leftOperand).getName())))) + return "\tiinc " + varTable.get(((Operand) leftOperand).getName()).getVirtualReg() + + " " + increment + "\n"; } if ((operationType == OperationType.ADD || operationType == OperationType.SUB) && leftOperand instanceof LiteralElement && !(rightOperand instanceof LiteralElement)) { - if (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand)rightOperand).getName())) + String increment = ""; + if (operationType == OperationType.ADD && parseInt(((LiteralElement)leftOperand).getLiteral()) <= 127) + increment = ((LiteralElement)leftOperand).getLiteral(); + else if (operationType == OperationType.SUB && parseInt(((LiteralElement)leftOperand).getLiteral()) <= 128) + increment = "-" + ((LiteralElement)leftOperand).getLiteral(); + if (!Objects.equals(increment, "") && iincVarEquivalent != null && + iincVarEquivalent.equals(((Operand)rightOperand).getName())) iincVars.put(iincVarEquivalent, destName); - if (destName.equals(((Operand)rightOperand).getName()) || - (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand)rightOperand).getName()))) - return "\tiinc " + varTable.get(((Operand) rightOperand).getName()).getVirtualReg() + " " - + (operationType == OperationType.SUB ? "-" : "") - + ((LiteralElement)leftOperand).getLiteral() + "\n"; + if (!Objects.equals(increment, "") && (destName.equals(((Operand)rightOperand).getName()) || + (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand)rightOperand).getName())))) + return "\tiinc " + varTable.get(((Operand) rightOperand).getName()).getVirtualReg() + + " " + increment + "\n"; } return ""; From ec3d9ca332889b2cd3f37e17f82d786ade3c4cf7 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Sun, 28 May 2023 15:06:41 +0000 Subject: [PATCH 65/69] Small adjustment --- src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 1abc42b..9d28f2b 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -191,11 +191,11 @@ public static String checkInc(BinaryOpInstruction instruction, Element dest, Has Element rightOperand = instruction.getRightOperand(); String destName = ((Operand)dest).getName(); String iincVarEquivalent = varEquivalence.get(destName); + String increment = ""; if ((operationType == OperationType.ADD || operationType == OperationType.SUB) && !(leftOperand instanceof LiteralElement) && rightOperand instanceof LiteralElement) { - String increment = ""; if (operationType == OperationType.ADD && parseInt(((LiteralElement)rightOperand).getLiteral()) <= 127) increment = ((LiteralElement)rightOperand).getLiteral(); else if (operationType == OperationType.SUB && parseInt(((LiteralElement)rightOperand).getLiteral()) <= 128) @@ -212,7 +212,6 @@ else if (operationType == OperationType.SUB && parseInt(((LiteralElement)rightOp if ((operationType == OperationType.ADD || operationType == OperationType.SUB) && leftOperand instanceof LiteralElement && !(rightOperand instanceof LiteralElement)) { - String increment = ""; if (operationType == OperationType.ADD && parseInt(((LiteralElement)leftOperand).getLiteral()) <= 127) increment = ((LiteralElement)leftOperand).getLiteral(); else if (operationType == OperationType.SUB && parseInt(((LiteralElement)leftOperand).getLiteral()) <= 128) From 919a0cbb493bcf639fec59bf43d5d859bd3d7728 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sun, 28 May 2023 18:34:40 +0100 Subject: [PATCH 66/69] Small fix to isValidColor() method --- .../optimization/interferenceGraph/MyInterferenceGraph.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java index 7ef0e67..1ce8fed 100644 --- a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java @@ -53,7 +53,7 @@ public void removeNode(MyNode node){ private boolean isValidColor(MyNode node, int color){ for(String neighbour : node.getNeighbours()){ - if(nodeColor.get(neighbour) == color) + if(nodeColor.getOrDefault(neighbour, -1) == color) return false; } return true; From 5f31a9a22b8a6c188e2b8ca9c390456832e2bee9 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sun, 28 May 2023 19:11:52 +0100 Subject: [PATCH 67/69] Improve findOptimalColoring --- .../MyInterferenceGraph.java | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java index 1ce8fed..fc6d84a 100644 --- a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java @@ -59,7 +59,7 @@ private boolean isValidColor(MyNode node, int color){ return true; } - public Stack computeColoringStack(int maxColors, boolean isOptimal){ + public Stack computeColoringStack(int maxColors) throws RuntimeException{ Stack stack = new Stack<>(); while (this.nodes.size() > 0) { @@ -75,19 +75,15 @@ public Stack computeColoringStack(int maxColors, boolean isOptimal){ stack.push(nodeToRemove.getVariable()); this.removeNode(nodeToRemove); } - else if (isOptimal){ - stack.clear(); - return stack; - } else throw new RuntimeException("The provided number of registers is not enough to store the local variables."); } return stack; } - public Map isMColoringFeasible(int maxColors){ + public Map isMColoringFeasible(int maxColors) throws RuntimeException{ MyInterferenceGraph copyGraph = deepCopy(); - Stack stack = copyGraph.computeColoringStack(maxColors, false); + Stack stack = copyGraph.computeColoringStack(maxColors); while (!stack.isEmpty()){ String nodeName = stack.pop(); @@ -103,19 +99,11 @@ public Map findOptimalColoring(){ int maxColors = this.nodes.size(); for(int currentMaxColors = 1; currentMaxColors <= maxColors; currentMaxColors++){ - this.nodeColor.clear(); - MyInterferenceGraph copyGraph = deepCopy(); - Stack stack = copyGraph.computeColoringStack(currentMaxColors, true); + try{ + this.isMColoringFeasible(currentMaxColors); - if(stack.isEmpty()) + }catch (RuntimeException e){ //currentMaxColor is not enough continue; - - while (!stack.isEmpty()){ - String nodeName = stack.pop(); - for(int color = 0; color < maxColors; color++){ - if(isValidColor(getNode(nodeName), color)) - this.nodeColor.put(nodeName, color); - } } break; } From becef83efc0db5e3bbd79042f0ce03d4fb63e083 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sun, 28 May 2023 21:19:23 +0100 Subject: [PATCH 68/69] Update README.md --- README.md | 69 ++++++++++++++++++------------------------------------- 1 file changed, 22 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 3cfd557..0d8416d 100644 --- a/README.md +++ b/README.md @@ -1,47 +1,22 @@ -# Compilers Project - -For this project, you need to install [Java](https://jdk.java.net/), [Gradle](https://gradle.org/install/), and [Git](https://git-scm.com/downloads/) (and optionally, a [Git GUI client](https://git-scm.com/downloads/guis), such as TortoiseGit or GitHub Desktop). Please check the [compatibility matrix](https://docs.gradle.org/current/userguide/compatibility.html) for Java and Gradle versions. - -## Project setup - -There are some import folders in the repository. Your development source code is inside the subfolder named ``src/main``. Specifically, your initially application is in the folder ``src/main/pt/up/fe/comp2023``, and the grammar is in the subfolder ``src/main/antlr/comp2023/grammar``. Finally, the subfolder named ``test`` contains your unit tests. - -## Compile and Running - -To compile and install the program, run ``gradle installDist``. This will compile your classes and create a launcher script in the folder ``./build/install/jmm/bin``. For convenience, there are two script files in the root folder, one for Windows (``jmm.bat``) and another for Linux (``jmm``), that call this launcher script. - -After compilation, a series of tests will be automatically executed. The build will stop if any test fails. Whenever you want to ignore the tests and build the program anyway, you can call Gradle with the flag ``-x test``. - - -## Tests - -The base repository comes with two classes that contains unitary tests in the package ``pt.up.fe.comp``, ``TutorialTest`` and `` GrammarTest``. The tests in ``TutorialTest`` should all pass just using the provided code. ``GrammarTest`` contains tests for the complete Java-- grammar, and most should fail. By the end of Checkpoint 1, all tests should pass. - -The class ``GrammarTest`` contains several static String variables at the beginning of the class where you should put the name of your rules for each type of rule that appears there. You have to set these variables to pass all tests. - -To test the program, run ``gradle test``. This will execute the build, and run the JUnit tests in the ``test`` folder. If you want to see output printed during the tests, use the flag ``-i`` (i.e., ``gradle test -i``). - -You can also see a test report by opening the file ``./build/reports/tests/test/index.html``. - - -### Reports -We also included in this project the class ``pt.up.fe.comp.jmm.report.Report``. This class is used to generate important reports, including error and warning messages, but also can be used to include debugging and logging information. E.g. When you want to generate an error, create a new Report with the ``Error`` type and provide the stage in which the error occurred. - -### Parser Interface - -We have included the interface ``pt.up.fe.comp.jmm.parser.JmmParser``, for which we already provide an example implementation in the file ``src/main/pt/up/fe/comp2023/SimpleParser.java``. - -To configure the name of the class of the JmmParser implementation that should be automatically used for tests, use the file ``config.properties`` (more details below). - -### Compilation Stages - -The project is divided in four compilation stages, that you will be developing during the semester. The stages are Parser, Analysis, Optimization and Backend, and for each of these stages there is a corresponding Java interface that you will have to implement (e.g. for the Parser stage, you have to implement the interface JmmParser). - - -### config.properties - -The testing framework, which uses the class ``pt.up.fe.comp.TestUtils``, has methods to test each of the four compilation stages (e.g., ``TestUtils.parse()`` for testing the Parser stage). - -In order for the test class to find your implementations for the stages, it uses the file ``config.properties`` that is in root of your repository. It has four fields, one for each stage (i.e. ``ParserClass``, ``AnalysisClass``, ``OptimizationClass``, ``BackendClass``), and initially it only has one value, ``pt.up.fe.comp2023.SimpleParser``, associated with the first stage. - -During the development of your compiler you will update this file in order to setup the classes that implement each of the compilation stages. +# Compilers Project (Group 7B) + +## Group members +- Isabel Amaral (up202006677) +- Mariana Rocha (up202004656) +- Milena Gouveia (up202008862) + +## Distribution of work +- Isabel Amaral (33%) +- Mariana Rocha (33%) +- Milena Gouveia (33%) + +## Implemented optimizations +- Option `-o`: + - constant propagation + - constant folding +- Option `–r=` (register allocation): + - `n ≥ 1`: the compiler tries to use at most `` local variables when generating Jasmin instructions. It aborts and reports an error if `` is not enough to store the local variables. + - `n = −1`: This is the default value where the compiler uses as many variables as originally present in the OLLIR representation. + +## Self-assessment +The developed project seems to be working as expected except for the optimization where the compiler tries to use the fewest registers as possible (option `-r 0`). However, considering that all the project requirements and all the remaining optimizations were implemented, we believe that our project deserves a grade of 19-19.5 out of 20. From ea5d907ed13b27e714fd4f40393f119f143bce47 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Sat, 10 Jun 2023 18:19:01 +0100 Subject: [PATCH 69/69] Update README.md --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 0d8416d..ca40c0e 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ # Compilers Project (Group 7B) -## Group members -- Isabel Amaral (up202006677) -- Mariana Rocha (up202004656) -- Milena Gouveia (up202008862) +## 👥 Group members +- Isabel Amaral (up202006677) +- Mariana Rocha (up202004656) +- Milena Gouveia (up202008862) -## Distribution of work -- Isabel Amaral (33%) -- Mariana Rocha (33%) -- Milena Gouveia (33%) +## 👩‍💻 Distribution of work +- Isabel Amaral (33%) - Jasmin +- Mariana Rocha (33%) - Ollir +- Milena Gouveia (33%) - Semantic Analysis and Optimizations -## Implemented optimizations +## 🪛 Implemented optimizations - Option `-o`: - constant propagation - constant folding @@ -18,5 +18,5 @@ - `n ≥ 1`: the compiler tries to use at most `` local variables when generating Jasmin instructions. It aborts and reports an error if `` is not enough to store the local variables. - `n = −1`: This is the default value where the compiler uses as many variables as originally present in the OLLIR representation. -## Self-assessment +## 🔎 Self-assessment The developed project seems to be working as expected except for the optimization where the compiler tries to use the fewest registers as possible (option `-r 0`). However, considering that all the project requirements and all the remaining optimizations were implemented, we believe that our project deserves a grade of 19-19.5 out of 20.