From ca8d817b5dd26df65d0fa6811eade33796c8b382 Mon Sep 17 00:00:00 2001 From: Jesper Gravgaard Date: Tue, 16 Oct 2018 11:07:46 +0200 Subject: [PATCH] Work in progress creating typed AsmParameters (to enable jmp/jsr etc. to be references and to support intelligent scope resolving during ASM generation). Currently not compiling. --- .../kickc/asm/AsmAddressingMode.java | 6 +- .../camelot64/kickc/asm/AsmInstruction.java | 8 +-- .../kickc/asm/AsmInstructionType.java | 4 +- .../dk/camelot64/kickc/asm/AsmParameter.java | 8 +++ .../kickc/asm/AsmParameterConstant.java | 25 +++++++ .../kickc/asm/AsmParameterLabel.java | 18 +++++ .../asm/AsmParameterLabelTransition.java | 20 ++++++ .../kickc/asm/AsmParameterProcedure.java | 18 +++++ .../dk/camelot64/kickc/asm/AsmProgram.java | 14 ++-- .../kickc/fragment/AsmFragmentInstance.java | 48 ++++++------- .../kickc/model/symbols/BlockScope.java | 20 ++++++ .../kickc/model/symbols/CallingScope.java | 29 ++++++++ .../camelot64/kickc/model/symbols/Scope.java | 72 ++++++------------- .../kickc/model/symbols/SymbolVariable.java | 2 +- .../kickc/passes/Pass4CodeGeneration.java | 23 +++--- .../passes/Pass5DoubleJumpElimination.java | 4 +- .../Pass5RedundantLabelElimination.java | 2 +- .../kickc/passes/Pass5RelabelLongLabels.java | 14 ++-- .../dk/camelot64/kickc/test/TestPrograms.java | 10 +-- 19 files changed, 226 insertions(+), 119 deletions(-) create mode 100644 src/main/java/dk/camelot64/kickc/asm/AsmParameter.java create mode 100644 src/main/java/dk/camelot64/kickc/asm/AsmParameterConstant.java create mode 100644 src/main/java/dk/camelot64/kickc/asm/AsmParameterLabel.java create mode 100644 src/main/java/dk/camelot64/kickc/asm/AsmParameterLabelTransition.java create mode 100644 src/main/java/dk/camelot64/kickc/asm/AsmParameterProcedure.java diff --git a/src/main/java/dk/camelot64/kickc/asm/AsmAddressingMode.java b/src/main/java/dk/camelot64/kickc/asm/AsmAddressingMode.java index 1498c630d..c136aa4c7 100644 --- a/src/main/java/dk/camelot64/kickc/asm/AsmAddressingMode.java +++ b/src/main/java/dk/camelot64/kickc/asm/AsmAddressingMode.java @@ -1,5 +1,7 @@ package dk.camelot64.kickc.asm; +import dk.camelot64.kickc.model.Program; + /** 6502 Assembler Instruction Addressing Modes. */ public enum AsmAddressingMode { NON("", "%i", 1), @@ -36,10 +38,10 @@ public enum AsmAddressingMode { return name; } - public String getAsm(String mnemnonic, String parameter) { + public String getAsm(String mnemnonic, AsmParameter parameter) { String replaced = template.replace("%i", mnemnonic); if(parameter != null) { - replaced = replaced.replace("%p", parameter); + replaced = replaced.replace("%p", parameter.getAsm()); } return replaced; } diff --git a/src/main/java/dk/camelot64/kickc/asm/AsmInstruction.java b/src/main/java/dk/camelot64/kickc/asm/AsmInstruction.java index 7c777b68c..e2d9fa507 100644 --- a/src/main/java/dk/camelot64/kickc/asm/AsmInstruction.java +++ b/src/main/java/dk/camelot64/kickc/asm/AsmInstruction.java @@ -5,22 +5,22 @@ public class AsmInstruction implements AsmLine { private AsmInstructionType type; - private String parameter; + private AsmParameter parameter; private int index; private boolean dontOptimize; - public AsmInstruction(AsmInstructionType type, String parameter) { + public AsmInstruction(AsmInstructionType type, AsmParameter parameter) { this.type = type; this.parameter = parameter; } - public String getParameter() { + public AsmParameter getParameter() { return parameter; } - public void setParameter(String parameter) { + public void setParameter(AsmParameter parameter) { this.parameter = parameter; } diff --git a/src/main/java/dk/camelot64/kickc/asm/AsmInstructionType.java b/src/main/java/dk/camelot64/kickc/asm/AsmInstructionType.java index 7319151c7..6a982309d 100644 --- a/src/main/java/dk/camelot64/kickc/asm/AsmInstructionType.java +++ b/src/main/java/dk/camelot64/kickc/asm/AsmInstructionType.java @@ -39,11 +39,11 @@ public class AsmInstructionType { return addressingMode.getBytes(); } - public int getOpcode() { + int getOpcode() { return opcode; } - public String getAsm(String parameter) { + public String getAsm(AsmParameter parameter) { return addressingMode.getAsm(mnemnonic, parameter); } diff --git a/src/main/java/dk/camelot64/kickc/asm/AsmParameter.java b/src/main/java/dk/camelot64/kickc/asm/AsmParameter.java new file mode 100644 index 000000000..6ccd3ae74 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/asm/AsmParameter.java @@ -0,0 +1,8 @@ +package dk.camelot64.kickc.asm; + +/** A parameter for an assembler instruction. */ +public interface AsmParameter { + + String getAsm(); + +} diff --git a/src/main/java/dk/camelot64/kickc/asm/AsmParameterConstant.java b/src/main/java/dk/camelot64/kickc/asm/AsmParameterConstant.java new file mode 100644 index 000000000..006e29c72 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/asm/AsmParameterConstant.java @@ -0,0 +1,25 @@ +package dk.camelot64.kickc.asm; + +import dk.camelot64.kickc.fragment.AsmFormat; +import dk.camelot64.kickc.model.Program; +import dk.camelot64.kickc.model.values.ConstantValue; +import dk.camelot64.kickc.model.values.ScopeRef; + +public class AsmParameterConstant implements AsmParameter { + + ConstantValue constantExpr; + ScopeRef codeScope; + Program program; + + + public AsmParameterConstant(ConstantValue constantExpr, ScopeRef codeScope, Program program) { + this.constantExpr = constantExpr; + this.codeScope = codeScope; + this.program = program; + } + + @Override + public String getAsm() { + return AsmFormat.getAsmConstant(program, constantExpr, 99, codeScope); + } +} diff --git a/src/main/java/dk/camelot64/kickc/asm/AsmParameterLabel.java b/src/main/java/dk/camelot64/kickc/asm/AsmParameterLabel.java new file mode 100644 index 000000000..b687bd25d --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/asm/AsmParameterLabel.java @@ -0,0 +1,18 @@ +package dk.camelot64.kickc.asm; + +import dk.camelot64.kickc.model.values.LabelRef; + +public class AsmParameterLabel implements AsmParameter { + + private LabelRef label; + + public AsmParameterLabel(LabelRef label) { + this.label = label; + } + + @Override + public String getAsm() { + return label.getLocalName().replace('@', 'b').replace(':', '_'); + } + +} diff --git a/src/main/java/dk/camelot64/kickc/asm/AsmParameterLabelTransition.java b/src/main/java/dk/camelot64/kickc/asm/AsmParameterLabelTransition.java new file mode 100644 index 000000000..6614af5cf --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/asm/AsmParameterLabelTransition.java @@ -0,0 +1,20 @@ +package dk.camelot64.kickc.asm; + +import dk.camelot64.kickc.model.values.LabelRef; + +public class AsmParameterLabelTransition implements AsmParameter { + + private LabelRef fromLabel; + private LabelRef toLabel; + + public AsmParameterLabelTransition(LabelRef fromLabel, LabelRef toLabel) { + this.fromLabel = fromLabel; + this.toLabel = toLabel; + } + + @Override + public String getAsm() { + return (toLabel.getLocalName() + "_from_" + fromLabel.getLocalName()).replace('@', 'b').replace(':', '_'); + } + +} diff --git a/src/main/java/dk/camelot64/kickc/asm/AsmParameterProcedure.java b/src/main/java/dk/camelot64/kickc/asm/AsmParameterProcedure.java new file mode 100644 index 000000000..86a128540 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/asm/AsmParameterProcedure.java @@ -0,0 +1,18 @@ +package dk.camelot64.kickc.asm; + +import dk.camelot64.kickc.model.values.ProcedureRef; + +public class AsmParameterProcedure implements AsmParameter { + + private ProcedureRef procedure; + + public AsmParameterProcedure(ProcedureRef procedure) { + this.procedure= procedure; + } + + @Override + public String getAsm() { + return procedure.getFullName(); + } + +} diff --git a/src/main/java/dk/camelot64/kickc/asm/AsmProgram.java b/src/main/java/dk/camelot64/kickc/asm/AsmProgram.java index b85a6733e..b6b66449a 100644 --- a/src/main/java/dk/camelot64/kickc/asm/AsmProgram.java +++ b/src/main/java/dk/camelot64/kickc/asm/AsmProgram.java @@ -70,7 +70,7 @@ public class AsmProgram { addLine(new AsmScopeEnd()); } - public AsmInstruction addInstruction(String mnemonic, AsmAddressingMode addressingMode, String parameter, boolean zp) { + public AsmInstruction addInstruction(String mnemonic, AsmAddressingMode addressingMode, AsmParameter parameter, boolean zp) { AsmInstructionType instructionType = AsmInstructionSet.getInstructionType(mnemonic, addressingMode, zp); AsmInstruction instruction = new AsmInstruction(instructionType, parameter); addLine(instruction); @@ -237,31 +237,31 @@ public class AsmProgram { boolean lineIdx; String indent; - public AsmPrintState(boolean comments, boolean lineIdx) { + AsmPrintState(boolean comments, boolean lineIdx) { this.comments = comments; this.lineIdx = lineIdx; this.indent = ""; } - public boolean isComments() { + boolean isComments() { return comments; } - public void incIndent() { + void incIndent() { this.indent = this.indent + " "; } - public void decIndent() { + void decIndent() { if(this.indent.length() >= 2) { this.indent = this.indent.substring(0, this.indent.length() - 2); } } - public String getIndent() { + String getIndent() { return indent; } - public boolean getLineIdx() { + boolean getLineIdx() { return lineIdx; } } diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstance.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstance.java index 9a34ffe2a..77cfe3396 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstance.java +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstance.java @@ -58,7 +58,7 @@ public class AsmFragmentInstance { * @param name The name of the bound value in the fragment * @return The bound value to use in the generated ASM code */ - public AsmParameter getBoundValue(String name) { + public AsmFragmentParameter getBoundValue(String name) { Value boundValue = null; if(name.length() == 2) { // Short name! @@ -80,7 +80,7 @@ public class AsmFragmentInstance { Variable boundVar = (Variable) boundValue; Registers.Register register = boundVar.getAllocation(); if(register != null && register instanceof Registers.RegisterZp) { - return new AsmParameter(AsmFormat.getAsmParamName(boundVar, codeScopeRef), true); + return new AsmFragmentParameter(AsmFormat.getAsmParamName(boundVar, codeScopeRef), true); } else { throw new RuntimeException("Register Type not implemented " + register); } @@ -88,15 +88,15 @@ public class AsmFragmentInstance { ConstantVar constantVar = (ConstantVar) boundValue; String constantValueAsm = AsmFormat.getAsmConstant(program, constantVar.getRef(), 99, codeScopeRef); boolean constantValueZp = SymbolType.BYTE.equals(constantVar.getType()); - return new AsmParameter(constantValueAsm, constantValueZp); + return new AsmFragmentParameter(constantValueAsm, constantValueZp); } else if(boundValue instanceof ConstantValue) { ConstantValue boundConst = (ConstantValue) boundValue; String constantValueAsm = AsmFormat.getAsmConstant(program, boundConst, 99, codeScopeRef); boolean constantValueZp = SymbolType.BYTE.equals(boundConst.getType(program.getScope())); - return new AsmParameter(constantValueAsm, constantValueZp); + return new AsmFragmentParameter(constantValueAsm, constantValueZp); } else if(boundValue instanceof Label) { String param = ((Label) boundValue).getLocalName().replace('@', 'b').replace(':', '_').replace("$", "_"); - return new AsmParameter(param, false); + return new AsmFragmentParameter(param, false); } else { throw new RuntimeException("Bound Value Type not implemented " + boundValue); } @@ -119,12 +119,12 @@ public class AsmFragmentInstance { /** * A parameter of an ASM instruction from a bound value. */ - public static class AsmParameter { + public static class AsmFragmentParameter { private String param; private boolean zp; - public AsmParameter(String param, boolean zp) { + public AsmFragmentParameter(String param, boolean zp) { this.param = param; this.zp = zp; } @@ -258,7 +258,7 @@ public class AsmFragmentInstance { AsmAddressingMode addressingMode) { KickCParser.AsmInstructionContext instructionCtx = (KickCParser.AsmInstructionContext) ctx.getParent(); String mnemonic = instructionCtx.MNEMONIC().getSymbol().getText(); - AsmParameter parameter = (AsmParameter) this.visit(exprCtx); + AsmFragmentParameter parameter = (AsmFragmentParameter) this.visit(exprCtx); AsmInstructionType type = AsmInstructionSet.getInstructionType( mnemonic, addressingMode, @@ -270,61 +270,61 @@ public class AsmFragmentInstance { } @Override - public AsmParameter visitAsmExprBinary(KickCParser.AsmExprBinaryContext ctx) { - AsmParameter left = (AsmParameter) this.visit(ctx.asmExpr(0)); - AsmParameter right = (AsmParameter) this.visit(ctx.asmExpr(1)); + public AsmFragmentParameter visitAsmExprBinary(KickCParser.AsmExprBinaryContext ctx) { + AsmFragmentParameter left = (AsmFragmentParameter) this.visit(ctx.asmExpr(0)); + AsmFragmentParameter right = (AsmFragmentParameter) this.visit(ctx.asmExpr(1)); String param = "" + left.getParam() + ctx.getChild(1).getText() + right.getParam(); boolean zp = left.isZp() && right.isZp(); - return new AsmParameter(param, zp); + return new AsmFragmentParameter(param, zp); } @Override - public AsmParameter visitAsmExprUnary(KickCParser.AsmExprUnaryContext ctx) { - AsmParameter sub = (AsmParameter) this.visit(ctx.asmExpr()); + public AsmFragmentParameter visitAsmExprUnary(KickCParser.AsmExprUnaryContext ctx) { + AsmFragmentParameter sub = (AsmFragmentParameter) this.visit(ctx.asmExpr()); String operator = ctx.getChild(0).getText(); String param = operator + sub.getParam(); boolean isZp = sub.isZp(); if(operator.equals("<") || operator.equals(">")) { isZp = true; } - return new AsmParameter(param, isZp); + return new AsmFragmentParameter(param, isZp); } @Override public Object visitAsmExprPar(KickCParser.AsmExprParContext ctx) { - AsmParameter sub = (AsmParameter) this.visit(ctx.asmExpr()); + AsmFragmentParameter sub = (AsmFragmentParameter) this.visit(ctx.asmExpr()); String param = "[" + sub.getParam() + "]"; - return new AsmParameter(param, sub.isZp()); + return new AsmFragmentParameter(param, sub.isZp()); } @Override - public AsmParameter visitAsmExprInt(KickCParser.AsmExprIntContext ctx) { + public AsmFragmentParameter visitAsmExprInt(KickCParser.AsmExprIntContext ctx) { Number number = NumberParser.parseLiteral(ctx.NUMBER().getText()); ConstantInteger intVal = new ConstantInteger(number.longValue()); boolean isZp = SymbolType.isByte(intVal.getType()) || SymbolType.isSByte(intVal.getType()); String param = AsmFormat.getAsmNumber(number); - return new AsmParameter(param, isZp); + return new AsmFragmentParameter(param, isZp); } @Override public Object visitAsmExprChar(KickCParser.AsmExprCharContext ctx) { - return new AsmParameter(ctx.getText(), true); + return new AsmFragmentParameter(ctx.getText(), true); } @Override - public AsmParameter visitAsmExprLabel(KickCParser.AsmExprLabelContext ctx) { + public AsmFragmentParameter visitAsmExprLabel(KickCParser.AsmExprLabelContext ctx) { String param = ctx.NAME().getSymbol().getText(); - return new AsmParameter(param, false); + return new AsmFragmentParameter(param, false); } @Override public Object visitAsmExprLabelRel(KickCParser.AsmExprLabelRelContext ctx) { String param = ctx.ASMREL().getSymbol().getText(); - return new AsmParameter(param, false); + return new AsmFragmentParameter(param, false); } @Override - public AsmParameter visitAsmExprReplace(KickCParser.AsmExprReplaceContext ctx) { + public AsmFragmentParameter visitAsmExprReplace(KickCParser.AsmExprReplaceContext ctx) { String replaceName = ctx.NAME().getSymbol().getText(); return bindings.getBoundValue(replaceName); } diff --git a/src/main/java/dk/camelot64/kickc/model/symbols/BlockScope.java b/src/main/java/dk/camelot64/kickc/model/symbols/BlockScope.java index 4461e6cd9..aea1a7c89 100644 --- a/src/main/java/dk/camelot64/kickc/model/symbols/BlockScope.java +++ b/src/main/java/dk/camelot64/kickc/model/symbols/BlockScope.java @@ -29,4 +29,24 @@ public class BlockScope extends Scope { public String toString(Program program) { return "scope "+getFullName(); } + + @Override + public VariableIntermediate addVariableIntermediate() { + return getScope().addVariableIntermediate(); + } + + @Override + public Label addLabelIntermediate() { + return getScope().addLabelIntermediate(); + } + + @Override + public String allocateIntermediateLabelName() { + return getScope().allocateIntermediateLabelName(); + } + + @Override + public String allocateIntermediateVariableName() { + return getScope().allocateIntermediateVariableName(); + } } diff --git a/src/main/java/dk/camelot64/kickc/model/symbols/CallingScope.java b/src/main/java/dk/camelot64/kickc/model/symbols/CallingScope.java index 81b822061..3a695af05 100644 --- a/src/main/java/dk/camelot64/kickc/model/symbols/CallingScope.java +++ b/src/main/java/dk/camelot64/kickc/model/symbols/CallingScope.java @@ -1,13 +1,42 @@ package dk.camelot64.kickc.model.symbols; +import dk.camelot64.kickc.model.types.SymbolType; + /** * A Scope that is a part of the call-graph. * This is the {@link ProgramScope} and {@link Procedure} */ public abstract class CallingScope extends Scope { + private int intermediateVarCount = 0; + private int intermediateLabelCount = 1; + CallingScope(String name, Scope parentScope) { super(name, parentScope); } + public String allocateIntermediateVariableName() { + return "$" + intermediateVarCount++; + } + + public String allocateIntermediateLabelName() { + return "@" + intermediateLabelCount++; + } + + public VariableIntermediate addVariableIntermediate() { + String name = allocateIntermediateVariableName(); + VariableIntermediate symbol = new VariableIntermediate(name, this, SymbolType.VAR); + add(symbol); + return symbol; + } + + + public Label addLabelIntermediate() { + String name = allocateIntermediateLabelName(); + Label symbol = new Label(name, this, true); + add(symbol); + return symbol; + } + + } diff --git a/src/main/java/dk/camelot64/kickc/model/symbols/Scope.java b/src/main/java/dk/camelot64/kickc/model/symbols/Scope.java index 8ea8742e4..cc07a929f 100644 --- a/src/main/java/dk/camelot64/kickc/model/symbols/Scope.java +++ b/src/main/java/dk/camelot64/kickc/model/symbols/Scope.java @@ -15,8 +15,6 @@ public abstract class Scope implements Symbol { private String name; private HashMap symbols; - private int intermediateVarCount = 0; - private int intermediateLabelCount = 1; private Scope parentScope; public Scope(String name, Scope parentScope) { @@ -97,13 +95,6 @@ public abstract class Scope implements Symbol { return symbol; } - public VariableIntermediate addVariableIntermediate() { - String name = allocateIntermediateVariableName(); - VariableIntermediate symbol = new VariableIntermediate(name, this, SymbolType.VAR); - add(symbol); - return symbol; - } - /** * Get all versions of an unversioned variable * @@ -124,10 +115,6 @@ public abstract class Scope implements Symbol { return versions; } - public String allocateIntermediateVariableName() { - return "$" + intermediateVarCount++; - } - public Symbol getSymbol(SymbolRef symbolRef) { return getSymbol(symbolRef.getFullName()); } @@ -155,6 +142,21 @@ public abstract class Scope implements Symbol { } } + public abstract VariableIntermediate addVariableIntermediate(); + + public abstract Label addLabelIntermediate(); + + public abstract String allocateIntermediateLabelName(); + + public abstract String allocateIntermediateVariableName(); + + public BlockScope addBlockScope() { + String name = allocateIntermediateLabelName(); + BlockScope scope = new BlockScope(name, this); + add(scope); + return scope; + } + public Variable getVariable(String name) { return (Variable) getSymbol(name); } @@ -239,19 +241,6 @@ public abstract class Scope implements Symbol { return symbol; } - public Label addLabelIntermediate() { - String name = "@" + intermediateLabelCount++; - Label symbol = new Label(name, this, true); - add(symbol); - return symbol; - } - - public BlockScope addBlockScope() { - String name = "@" + intermediateLabelCount++; - BlockScope scope = new BlockScope(name, this); - add(scope); - return scope; - } public Label getLabel(String name) { return (Label) getSymbol(name); @@ -356,36 +345,15 @@ public abstract class Scope implements Symbol { @Override public boolean equals(Object o) { - if(this == o) { - return true; - } - if(o == null || getClass() != o.getClass()) { - return false; - } - + if(this == o) return true; + if(o == null || getClass() != o.getClass()) return false; Scope scope = (Scope) o; - - if(intermediateVarCount != scope.intermediateVarCount) { - return false; - } - if(intermediateLabelCount != scope.intermediateLabelCount) { - return false; - } - if(!name.equals(scope.name)) { - return false; - } - if(!symbols.equals(scope.symbols)) { - return false; - } - return true; + return Objects.equals(name, scope.name) && + Objects.equals(parentScope, scope.parentScope); } @Override public int hashCode() { - int result = name.hashCode(); - result = 31 * result + intermediateVarCount; - result = 31 * result + intermediateLabelCount; - return result; + return Objects.hash(name, parentScope); } - } diff --git a/src/main/java/dk/camelot64/kickc/model/symbols/SymbolVariable.java b/src/main/java/dk/camelot64/kickc/model/symbols/SymbolVariable.java index 8c6e27e1a..083c534b1 100644 --- a/src/main/java/dk/camelot64/kickc/model/symbols/SymbolVariable.java +++ b/src/main/java/dk/camelot64/kickc/model/symbols/SymbolVariable.java @@ -34,7 +34,7 @@ public abstract class SymbolVariable implements Symbol { /** Specifies that the variable must always live in memory to be available for any multi-threaded accees (eg. in interrupts). */ private boolean declaredVolatile; - public SymbolVariable(String name, Scope scope, SymbolType type) { + SymbolVariable(String name, Scope scope, SymbolType type) { this.name = name; this.scope = scope; this.type = type; diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java index 9c99e92aa..81f2c69b1 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java @@ -66,10 +66,11 @@ public class Pass4CodeGeneration { } // Start scopes until the new scope is the current scope + LabelRef blockLabel = block.getLabel(); while(!currentScope.equals(newScope)) { currentScope = newScope.getParentScope(currentScope.getScopeDepth()+1); - asm.startSegment(currentScope, null, block.getLabel().getFullName()); - asm.addScopeBegin(block.getLabel().getFullName().replace('@', 'b').replace(':', '_')); + asm.startSegment(currentScope, null, blockLabel.getFullName()); + asm.addScopeBegin(currentScope.getLocalName().replace('@', 'b').replace(':', '_')); // Add all ZP labels for the scope addConstants(asm, currentScope); addZpLabels(asm, currentScope); @@ -86,27 +87,25 @@ public class Pass4CodeGeneration { } } else { // Generate label for block inside procedure - asm.startSegment(currentScope, null, block.getLabel().getFullName()); - asm.addLabel(block.getLabel().getLocalName().replace('@', 'b').replace(':', '_')); + asm.startSegment(currentScope, null, blockLabel.getFullName()); + asm.addLabel(blockLabel.getLocalName().replace('@', 'b').replace(':', '_')); } // Generate statements genStatements(asm, block); // Generate block exit ControlFlowBlock defaultSuccessor = getGraph().getDefaultSuccessor(block); if(defaultSuccessor != null) { + LabelRef defaultSuccessorLabel = defaultSuccessor.getLabel(); if(defaultSuccessor.hasPhiBlock()) { PhiTransitions.PhiTransition transition = getTransitions(defaultSuccessor).getTransition(block); if(!transition.isGenerated()) { genBlockPhiTransition(asm, block, defaultSuccessor, defaultSuccessor.getScope()); - String label = defaultSuccessor.getLabel().getLocalName().replace('@', 'b').replace(':', '_'); - asm.addInstruction("JMP", AsmAddressingMode.ABS, label, false); + asm.addInstruction("JMP", AsmAddressingMode.ABS, new AsmParameterLabel(defaultSuccessorLabel), false); } else { - String label = (defaultSuccessor.getLabel().getLocalName() + "_from_" + block.getLabel().getLocalName()).replace('@', 'b').replace(':', '_'); - asm.addInstruction("JMP", AsmAddressingMode.ABS, label, false); + asm.addInstruction("JMP", AsmAddressingMode.ABS, new AsmParameterLabelTransition(blockLabel, defaultSuccessorLabel), false); } } else { - String label = defaultSuccessor.getLabel().getLocalName().replace('@', 'b').replace(':', '_'); - asm.addInstruction("JMP", AsmAddressingMode.ABS, label, false); + asm.addInstruction("JMP", AsmAddressingMode.ABS, new AsmParameterLabel(defaultSuccessorLabel), false); } } } @@ -445,7 +444,7 @@ public class Pass4CodeGeneration { genBlockPhiTransition(asm, block, callSuccessor, block.getScope()); } } - asm.addInstruction("jsr", AsmAddressingMode.ABS, call.getProcedure().getFullName(), false); + asm.addInstruction("jsr", AsmAddressingMode.ABS, new AsmParameterProcedure(call.getProcedure()), false); } else if(statement instanceof StatementReturn) { Procedure.InterruptType interruptType = null; ScopeRef scope = block.getScope(); @@ -566,7 +565,7 @@ public class Pass4CodeGeneration { PhiTransitions.PhiTransition transition = transitions.getTransition(fromBlock); if(!transition.isGenerated() && toBlock.getLabel().equals(fromBlock.getConditionalSuccessor())) { genBlockPhiTransition(asm, fromBlock, toBlock, toBlock.getScope()); - asm.addInstruction("JMP", AsmAddressingMode.ABS, toBlock.getLabel().getLocalName().replace('@', 'b').replace(':', '_'), false); + asm.addInstruction("JMP", AsmAddressingMode.ABS, new AsmParameterLabel(toBlock.getLabel()), false); } } } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass5DoubleJumpElimination.java b/src/main/java/dk/camelot64/kickc/passes/Pass5DoubleJumpElimination.java index b58931b3c..ec691b4db 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass5DoubleJumpElimination.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass5DoubleJumpElimination.java @@ -21,7 +21,7 @@ public class Pass5DoubleJumpElimination extends Pass5AsmOptimization { // Find all labels immediately followed by a a jump String currentScope = ""; String currentLabel = null; - Map immediateJumps = new LinkedHashMap<>(); + Map immediateJumps = new LinkedHashMap<>(); for(AsmSegment segment : getAsmProgram().getSegments()) { for(AsmLine line : segment.getLines()) { if(line instanceof AsmScopeBegin) { @@ -61,7 +61,7 @@ public class Pass5DoubleJumpElimination extends Pass5AsmOptimization { } else if(line instanceof AsmInstruction) { AsmInstruction asmInstruction = (AsmInstruction) line; if(asmInstruction.getType().isJump()) { - String immediateJmpTarget = immediateJumps.get(currentScope + "::" + asmInstruction.getParameter()); + AsmParameter immediateJmpTarget = immediateJumps.get(currentScope + "::" + asmInstruction.getParameter()); if(immediateJmpTarget != null && !immediateJmpTarget.equals(asmInstruction.getParameter())) { getLog().append("Skipping double jump to " + immediateJmpTarget + " in " + asmInstruction.toString()); asmInstruction.setParameter(immediateJmpTarget); diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass5RedundantLabelElimination.java b/src/main/java/dk/camelot64/kickc/passes/Pass5RedundantLabelElimination.java index c5759dbe3..0245e36d3 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass5RedundantLabelElimination.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass5RedundantLabelElimination.java @@ -32,7 +32,7 @@ public class Pass5RedundantLabelElimination extends Pass5AsmOptimization { } else if(line instanceof AsmInstruction) { AsmInstruction instruction = (AsmInstruction) line; if(instruction.getType().isJump()) { - String labelStr = instruction.getParameter(); + String labelStr = instruction.getParameter().getAsm(); if(!labelStr.contains("!")) { // If redundant - Replace with the shortest for(RedundantLabels redundantLabels : redundantLabelSet) { diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass5RelabelLongLabels.java b/src/main/java/dk/camelot64/kickc/passes/Pass5RelabelLongLabels.java index 8ecbbae63..450f6b385 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass5RelabelLongLabels.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass5RelabelLongLabels.java @@ -46,7 +46,7 @@ public class Pass5RelabelLongLabels extends Pass5AsmOptimization { // Find relabels for all long labels // Scope->(Label->NewLabel) - Map> relabels = new LinkedHashMap<>(); + Map> relabels = new LinkedHashMap<>(); for(AsmSegment asmSegment : getAsmProgram().getSegments()) { for(AsmLine asmLine : asmSegment.getLines()) { if(asmLine instanceof AsmScopeBegin) { @@ -58,7 +58,7 @@ public class Pass5RelabelLongLabels extends Pass5AsmOptimization { if(asmLabel.getLabel().contains("_from_")) { // Found a long label Set scopeLabels = allLabels.get(currentScope); - Map scopeRelabels = relabels.get(currentScope); + Map scopeRelabels = relabels.get(currentScope); if(scopeRelabels == null) { scopeRelabels = new LinkedHashMap<>(); relabels.put(currentScope, scopeRelabels); @@ -86,9 +86,9 @@ public class Pass5RelabelLongLabels extends Pass5AsmOptimization { currentScope = ""; } else if(asmLine instanceof AsmLabel) { AsmLabel asmLabel = (AsmLabel) asmLine; - Map scopeRelabels = relabels.get(currentScope); + Map scopeRelabels = relabels.get(currentScope); if(scopeRelabels != null) { - String newLabel = scopeRelabels.get(asmLabel.getLabel()); + AsmParameter newLabel = scopeRelabels.get(asmLabel.getLabel()); if(newLabel != null) { asmLabel.setLabel(newLabel); } @@ -96,10 +96,10 @@ public class Pass5RelabelLongLabels extends Pass5AsmOptimization { } else if(asmLine instanceof AsmInstruction) { AsmInstruction asmInstruction = (AsmInstruction) asmLine; if(asmInstruction.getType().isJump()) { - String parameter = asmInstruction.getParameter(); - Map scopeRelabels = relabels.get(currentScope); + AsmParameter parameter = asmInstruction.getParameter(); + Map scopeRelabels = relabels.get(currentScope); if(scopeRelabels != null) { - String newLabel = scopeRelabels.get(parameter); + AsmParameter newLabel = scopeRelabels.get(parameter); if(newLabel != null) { asmInstruction.setParameter(newLabel); } diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index edb1bea8d..5a3dddf09 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -44,6 +44,11 @@ public class TestPrograms { AsmFragmentTemplateUsages.logUsages(log, false, false, false, false, false, false); } + @Test + public void testLocalScope() throws IOException, URISyntaxException { + compileAndCompare("local-scope"); + } + @Test public void testBitwiseNot() throws IOException, URISyntaxException { compileAndCompare("bitwise-not"); @@ -54,11 +59,6 @@ public class TestPrograms { // compileAndCompare("unroll-call"); //} - @Test - public void testLocalScope() throws IOException, URISyntaxException { - compileAndCompare("local-scope"); - } - @Test public void testUnrollInfinite() throws IOException, URISyntaxException { assertError("unroll-infinite", "Loop cannot be unrolled.");