mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-02-05 21:30:52 +00:00
Implemented interrupt procedures and pointers to procedures initial support.
This commit is contained in:
parent
c0c7a1da44
commit
f463606742
@ -2,11 +2,10 @@ package dk.camelot64.kickc.fragment;
|
||||
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.operators.Operator;
|
||||
import dk.camelot64.kickc.model.operators.OperatorBinary;
|
||||
import dk.camelot64.kickc.model.operators.OperatorUnary;
|
||||
import dk.camelot64.kickc.model.operators.Operators;
|
||||
import dk.camelot64.kickc.model.operators.*;
|
||||
import dk.camelot64.kickc.model.symbols.ConstantVar;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
import dk.camelot64.kickc.model.symbols.Symbol;
|
||||
import dk.camelot64.kickc.model.symbols.Variable;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeInference;
|
||||
@ -54,10 +53,16 @@ public class AsmFormat {
|
||||
(parenthesis ? ")" : "");
|
||||
} else if(value instanceof ConstantPointer) {
|
||||
return getAsmNumber(((ConstantPointer) value).getValue());
|
||||
} else if(value instanceof ConstantVarPointer) {
|
||||
VariableRef toVar = ((ConstantVarPointer) value).getToVar();
|
||||
Variable variable = program.getScope().getVariable(toVar);
|
||||
return getAsmParamName(variable, codeScope);
|
||||
} else if(value instanceof ConstantSymbolPointer) {
|
||||
SymbolRef toSym = ((ConstantSymbolPointer) value).getToSymbol();
|
||||
Symbol symbol = program.getScope().getSymbol(toSym);
|
||||
if(symbol instanceof Variable) {
|
||||
return getAsmParamName((Variable) symbol, codeScope);
|
||||
} else if(symbol instanceof Procedure) {
|
||||
return getAsmParamName((Procedure) symbol, codeScope);
|
||||
} else {
|
||||
throw new RuntimeException("Unhandled symbol type "+symbol);
|
||||
}
|
||||
} else if(value instanceof ConstantCastValue) {
|
||||
ConstantCastValue castValue = (ConstantCastValue) value;
|
||||
OperatorUnary castOperator = Operators.getCastUnary(castValue.getToType());
|
||||
@ -110,7 +115,7 @@ public class AsmFormat {
|
||||
} else {
|
||||
return getAsmConstant(program, new ConstantBinary(new ConstantInteger((long)0xff), Operators.BOOL_AND, operand), outerPrecedence, codeScope);
|
||||
}
|
||||
} else if(Operators.CAST_WORD.equals(operator) || Operators.CAST_SWORD.equals(operator) || Operators.CAST_PTRBY.equals(operator)|| Operators.CAST_PTRSBY.equals(operator)|| Operators.CAST_PTRWO.equals(operator)|| Operators.CAST_PTRSWO.equals(operator)|| Operators.CAST_PTRDWO.equals(operator)|| Operators.CAST_PTRSDWO.equals(operator)|| Operators.CAST_PTRBO.equals(operator)) {
|
||||
} else if(operator instanceof OperatorCastPtr || Operators.CAST_WORD.equals(operator) || Operators.CAST_SWORD.equals(operator) || Operators.CAST_PTRBY.equals(operator)|| Operators.CAST_PTRSBY.equals(operator)|| Operators.CAST_PTRWO.equals(operator)|| Operators.CAST_PTRSWO.equals(operator)|| Operators.CAST_PTRDWO.equals(operator)|| Operators.CAST_PTRSDWO.equals(operator)|| Operators.CAST_PTRBO.equals(operator)) {
|
||||
SymbolType operandType = SymbolTypeInference.inferType(program.getScope(), operand);
|
||||
if(SymbolType.isWord(operandType) || SymbolType.isSWord(operandType) || SymbolType.isByte(operandType) || SymbolType.isSByte(operandType) || operandType instanceof SymbolTypePointer) {
|
||||
// No cast needed
|
||||
@ -230,4 +235,17 @@ public class AsmFormat {
|
||||
String asmName = boundVar.getAsmName() == null ? boundVar.getLocalName() : boundVar.getAsmName();
|
||||
return getAsmParamName(varScopeRef, asmName, codeScopeRef);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ASM parameter for a specific bound constant
|
||||
*
|
||||
* @param boundProc The constant
|
||||
* @return The ASM parameter to use in the ASM code
|
||||
*/
|
||||
private static String getAsmParamName(Procedure boundProc, ScopeRef codeScopeRef) {
|
||||
ScopeRef procScopeRef = boundProc.getScope().getRef();
|
||||
String asmName = boundProc.getLocalName();
|
||||
return getAsmParamName(procScopeRef, asmName, codeScopeRef);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import dk.camelot64.kickc.model.symbols.Variable;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeInference;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypePointer;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeProcedure;
|
||||
import dk.camelot64.kickc.model.values.*;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
@ -322,6 +323,10 @@ public class AsmFragmentInstanceSpec {
|
||||
return "pws";
|
||||
} else if(SymbolType.BOOLEAN.equals(elementType)) {
|
||||
return "pbo";
|
||||
} else if(elementType instanceof SymbolTypeProcedure) {
|
||||
return "ppr";
|
||||
} else if(elementType instanceof SymbolTypePointer) {
|
||||
return "ppt";
|
||||
} else {
|
||||
throw new RuntimeException("Not implemented " + type);
|
||||
}
|
||||
|
@ -0,0 +1,4 @@
|
||||
lda #<{c2}
|
||||
sta {c1}
|
||||
lda #>{c2}
|
||||
sta {c1}+1
|
@ -361,22 +361,22 @@ public abstract class ProgramValue {
|
||||
/**
|
||||
* Pointer inside a variable pointer.
|
||||
*/
|
||||
public static class VarPointer extends ProgramValue {
|
||||
private final ConstantVarPointer varPointer;
|
||||
public static class ConstantSymbolPointerTo extends ProgramValue {
|
||||
private final ConstantSymbolPointer varPointer;
|
||||
|
||||
|
||||
VarPointer(ConstantVarPointer varPointer) {
|
||||
ConstantSymbolPointerTo(ConstantSymbolPointer varPointer) {
|
||||
this.varPointer = varPointer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue get() {
|
||||
return varPointer.getToVar();
|
||||
return (RValue) varPointer.getToSymbol();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(RValue val) {
|
||||
varPointer.setToVar((VariableRef) val);
|
||||
varPointer.setToSymbol((VariableRef) val);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -178,8 +178,8 @@ public class ProgramValueIterator {
|
||||
subValues.add(new ProgramValue.CastValue((CastValue) value));
|
||||
} else if(value instanceof ConstantCastValue) {
|
||||
subValues.add(new ProgramValue.ConstantCastValue((ConstantCastValue) value));
|
||||
} else if(value instanceof ConstantVarPointer) {
|
||||
subValues.add(new ProgramValue.VarPointer((ConstantVarPointer) value));
|
||||
} else if(value instanceof ConstantSymbolPointer) {
|
||||
subValues.add(new ProgramValue.ConstantSymbolPointerTo((ConstantSymbolPointer) value));
|
||||
} else if(value instanceof RangeValue) {
|
||||
subValues.add(new ProgramValue.RangeFirst((RangeValue) value));
|
||||
subValues.add(new ProgramValue.RangeLast((RangeValue) value));
|
||||
@ -194,6 +194,7 @@ public class ProgramValueIterator {
|
||||
subValues.add(new ProgramValue.ConstantArrayFilledSize((ConstantArrayFilled) value));
|
||||
} else if(value == null ||
|
||||
value instanceof VariableRef ||
|
||||
value instanceof ProcedureRef ||
|
||||
value instanceof ConstantLiteral ||
|
||||
value instanceof ConstantRef ||
|
||||
value instanceof LvalueIntermediate
|
||||
|
@ -0,0 +1,34 @@
|
||||
package dk.camelot64.kickc.model.operators;
|
||||
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypePointer;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeSimple;
|
||||
import dk.camelot64.kickc.model.values.ConstantInteger;
|
||||
import dk.camelot64.kickc.model.values.ConstantLiteral;
|
||||
import dk.camelot64.kickc.model.values.ConstantPointer;
|
||||
|
||||
/** Unary Cast to a pointer ( type* ) */
|
||||
public class OperatorCastPtr extends OperatorUnary {
|
||||
|
||||
private final SymbolType elementType;
|
||||
|
||||
public OperatorCastPtr(int precedence, SymbolType elementType) {
|
||||
super("((" + elementType.toString() + "*))", "_ptr_", precedence);
|
||||
this.elementType = elementType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConstantLiteral calculateLiteral(ConstantLiteral value) {
|
||||
if(value instanceof ConstantInteger) {
|
||||
return new ConstantPointer(((ConstantInteger) value).getInteger(), elementType);
|
||||
}
|
||||
throw new CompileError("Calculation not implemented " + getOperator() + " " + value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SymbolType inferType(SymbolTypeSimple operandType) {
|
||||
return new SymbolTypePointer(elementType);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package dk.camelot64.kickc.model.operators;
|
||||
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypePointer;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeProcedure;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeSimple;
|
||||
import dk.camelot64.kickc.model.values.ConstantInteger;
|
||||
import dk.camelot64.kickc.model.values.ConstantLiteral;
|
||||
import dk.camelot64.kickc.model.values.ConstantPointer;
|
||||
|
||||
/** Unary Cast to procedure pointer operator ( (void()*) x ) */
|
||||
public class OperatorCastPtrProc extends OperatorUnary {
|
||||
|
||||
public OperatorCastPtrProc(int precedence) {
|
||||
super("((void()*))", "_ptrproc_", precedence);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConstantLiteral calculateLiteral(ConstantLiteral value) {
|
||||
if(value instanceof ConstantInteger) {
|
||||
return new ConstantPointer(((ConstantInteger) value).getInteger(), new SymbolTypeProcedure(SymbolType.VOID));
|
||||
}
|
||||
throw new CompileError("Calculation not implemented " + getOperator() + " " + value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SymbolType inferType(SymbolTypeSimple operandType) {
|
||||
return new SymbolTypePointer(new SymbolTypeProcedure(SymbolType.VOID));
|
||||
}
|
||||
|
||||
}
|
@ -32,6 +32,7 @@ public class Operators {
|
||||
public static final OperatorUnary CAST_PTRDWO = new OperatorCastPtrDWord(2);
|
||||
public static final OperatorUnary CAST_PTRSDWO = new OperatorCastPtrSignedDWord(2);
|
||||
public static final OperatorUnary CAST_PTRBO = new OperatorCastPtrBool(2);
|
||||
public static final OperatorUnary CAST_PTRPROC = new OperatorCastPtrProc(2);
|
||||
public static final OperatorUnary CAST_BOOL= new OperatorCastBool(2);
|
||||
public static final OperatorBinary MULTIPLY = new OperatorMultiply(3);
|
||||
public static final OperatorBinary DIVIDE = new OperatorDivide(3);
|
||||
@ -169,6 +170,8 @@ public class Operators {
|
||||
return CAST_PTRSDWO;
|
||||
} else if(castType instanceof SymbolTypePointer && SymbolType.BOOLEAN.equals(((SymbolTypePointer) castType).getElementType())) {
|
||||
return CAST_PTRBO;
|
||||
} else if(castType instanceof SymbolTypePointer) {
|
||||
return new OperatorCastPtr(CAST_BYTE.getPrecedence(), ((SymbolTypePointer) castType).getElementType());
|
||||
} else {
|
||||
throw new RuntimeException("Unknown cast type " + castType);
|
||||
|
||||
|
@ -176,8 +176,8 @@ public class SymbolTypeInference {
|
||||
return new SymbolTypeArray(((ArrayFilled) rValue).getElementType(), ((ArrayFilled) rValue).getSize());
|
||||
} else if(rValue instanceof ConstantArrayFilled) {
|
||||
return new SymbolTypeArray(((ConstantArrayFilled) rValue).getElementType(), ((ConstantArrayFilled) rValue).getSize());
|
||||
} else if(rValue instanceof ConstantVarPointer) {
|
||||
return ((ConstantVarPointer) rValue).getType(symbols);
|
||||
} else if(rValue instanceof ConstantSymbolPointer) {
|
||||
return ((ConstantSymbolPointer) rValue).getType(symbols);
|
||||
} else if(rValue instanceof CastValue) {
|
||||
return ((CastValue) rValue).getToType();
|
||||
} else if(rValue instanceof ConstantCastValue) {
|
||||
@ -188,6 +188,9 @@ public class SymbolTypeInference {
|
||||
return ((RangeComparison) rValue).getType();
|
||||
} else if(rValue instanceof RangeNext) {
|
||||
return SymbolType.BYTE;
|
||||
} else if(rValue instanceof ProcedureRef) {
|
||||
Procedure procedure = symbols.getProcedure((ProcedureRef) rValue);
|
||||
return procedure.getType();
|
||||
}
|
||||
if(type == null) {
|
||||
throw new RuntimeException("Cannot infer type for " + rValue.toString());
|
||||
@ -382,6 +385,7 @@ public class SymbolTypeInference {
|
||||
/**
|
||||
* Find the symbol type that is the intersection between the two passed types.
|
||||
* Handles SymbolTypeMulti by intersecting the sub type lists.
|
||||
*
|
||||
* @param type1 The first type
|
||||
* @param type2 The second type
|
||||
* @return The intersection between the two types (handling multi-types)
|
||||
@ -417,12 +421,12 @@ public class SymbolTypeInference {
|
||||
}
|
||||
}
|
||||
}
|
||||
if(newSubTypes.size()==0) {
|
||||
return null;
|
||||
} else if(newSubTypes.size()==1) {
|
||||
if(newSubTypes.size() == 0) {
|
||||
return null;
|
||||
} else if(newSubTypes.size() == 1) {
|
||||
// A single type matching - use it
|
||||
return newSubTypes.get(0);
|
||||
} else {
|
||||
} else {
|
||||
// Multiple matches was found - use them
|
||||
return new SymbolTypeMulti(newSubTypes);
|
||||
}
|
||||
|
@ -31,9 +31,7 @@ public class SymbolTypePointer implements SymbolTypeSimple {
|
||||
if(o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SymbolTypePointer that = (SymbolTypePointer) o;
|
||||
|
||||
return elementType != null ? elementType.equals(that.elementType) : that.elementType == null;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
package dk.camelot64.kickc.model.types;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/** A function returning another type */
|
||||
public class SymbolTypeProcedure implements SymbolTypeSimple {
|
||||
|
||||
@ -23,4 +25,17 @@ public class SymbolTypeProcedure implements SymbolTypeSimple {
|
||||
return getTypeName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if(this == o) return true;
|
||||
if(o == null || getClass() != o.getClass()) return false;
|
||||
SymbolTypeProcedure that = (SymbolTypeProcedure) o;
|
||||
return Objects.equals(returnType, that.returnType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
return Objects.hash(returnType);
|
||||
}
|
||||
}
|
||||
|
@ -2,31 +2,31 @@ package dk.camelot64.kickc.model.values;
|
||||
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.symbols.ProgramScope;
|
||||
import dk.camelot64.kickc.model.symbols.Variable;
|
||||
import dk.camelot64.kickc.model.symbols.Symbol;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypePointer;
|
||||
|
||||
/** A pointer to a variable */
|
||||
public class ConstantVarPointer implements ConstantValue {
|
||||
/** A pointer to a symbol (variable or procedure) */
|
||||
public class ConstantSymbolPointer implements ConstantValue {
|
||||
|
||||
/** The variable pointed to. */
|
||||
private VariableRef toVar;
|
||||
private SymbolRef toSymbol;
|
||||
|
||||
public ConstantVarPointer(VariableRef toVar) {
|
||||
this.toVar = toVar;
|
||||
public ConstantSymbolPointer(SymbolRef toSymbol) {
|
||||
this.toSymbol = toSymbol;
|
||||
}
|
||||
|
||||
public VariableRef getToVar() {
|
||||
return toVar;
|
||||
public SymbolRef getToSymbol() {
|
||||
return toSymbol;
|
||||
}
|
||||
|
||||
public void setToVar(VariableRef toVar) {
|
||||
this.toVar = toVar;
|
||||
public void setToSymbol(SymbolRef toSymbol) {
|
||||
this.toSymbol = toSymbol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SymbolType getType(ProgramScope scope) {
|
||||
Variable to = scope.getVariable(toVar);
|
||||
Symbol to = scope.getSymbol(toSymbol);
|
||||
return new SymbolTypePointer(to.getType());
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@ public class ConstantVarPointer implements ConstantValue {
|
||||
|
||||
@Override
|
||||
public String toString(Program program) {
|
||||
return "&" + toVar.toString(program);
|
||||
return "&" + toSymbol.toString(program);
|
||||
}
|
||||
|
||||
@Override
|
@ -22,6 +22,6 @@ public class ForwardVariableRef implements RValue {
|
||||
|
||||
@Override
|
||||
public String toString(Program program) {
|
||||
return null;
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package dk.camelot64.kickc.model.values;
|
||||
|
||||
/** A reference to a procedure */
|
||||
public class ProcedureRef extends ScopeRef {
|
||||
public class ProcedureRef extends ScopeRef implements RValue {
|
||||
|
||||
public ProcedureRef(String fullName) {
|
||||
super(fullName);
|
||||
|
@ -94,10 +94,12 @@ forIteration
|
||||
;
|
||||
|
||||
typeDecl
|
||||
: SIMPLETYPE #typeSimple
|
||||
: '(' typeDecl ')' #typePar
|
||||
| SIMPLETYPE #typeSimple
|
||||
| 'signed' SIMPLETYPE #typeSignedSimple
|
||||
| typeDecl '*' #typePtr
|
||||
| typeDecl '[' (expr)? ']' #typeArray
|
||||
| typeDecl '(' ')' #typeProcedure
|
||||
;
|
||||
|
||||
expr
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Generated from /Users/jespergravgaard/c64/kickc/src/main/java/dk/camelot64/kickc/parser/KickC.g4 by ANTLR 4.7
|
||||
// Generated from C:/c64/kickc/src/main/java/dk/camelot64/kickc/parser\KickC.g4 by ANTLR 4.7
|
||||
package dk.camelot64.kickc.parser;
|
||||
|
||||
import org.antlr.v4.runtime.ParserRuleContext;
|
||||
@ -467,6 +467,30 @@ public class KickCBaseListener implements KickCListener {
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitForRange(KickCParser.ForRangeContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void enterTypePar(KickCParser.TypeParContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitTypePar(KickCParser.TypeParContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void enterTypeProcedure(KickCParser.TypeProcedureContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitTypeProcedure(KickCParser.TypeProcedureContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Generated from /Users/jespergravgaard/c64/kickc/src/main/java/dk/camelot64/kickc/parser/KickC.g4 by ANTLR 4.7
|
||||
// Generated from C:/c64/kickc/src/main/java/dk/camelot64/kickc/parser\KickC.g4 by ANTLR 4.7
|
||||
package dk.camelot64.kickc.parser;
|
||||
import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;
|
||||
|
||||
@ -277,6 +277,20 @@ public class KickCBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitForRange(KickCParser.ForRangeContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitTypePar(KickCParser.TypeParContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitTypeProcedure(KickCParser.TypeProcedureContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Generated from /Users/jespergravgaard/c64/kickc/src/main/java/dk/camelot64/kickc/parser/KickC.g4 by ANTLR 4.7
|
||||
// Generated from C:/c64/kickc/src/main/java/dk/camelot64/kickc/parser\KickC.g4 by ANTLR 4.7
|
||||
package dk.camelot64.kickc.parser;
|
||||
import org.antlr.v4.runtime.Lexer;
|
||||
import org.antlr.v4.runtime.CharStream;
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Generated from /Users/jespergravgaard/c64/kickc/src/main/java/dk/camelot64/kickc/parser/KickC.g4 by ANTLR 4.7
|
||||
// Generated from C:/c64/kickc/src/main/java/dk/camelot64/kickc/parser\KickC.g4 by ANTLR 4.7
|
||||
package dk.camelot64.kickc.parser;
|
||||
import org.antlr.v4.runtime.tree.ParseTreeListener;
|
||||
|
||||
@ -437,6 +437,30 @@ public interface KickCListener extends ParseTreeListener {
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitForRange(KickCParser.ForRangeContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by the {@code typePar}
|
||||
* labeled alternative in {@link KickCParser#typeDecl}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void enterTypePar(KickCParser.TypeParContext ctx);
|
||||
/**
|
||||
* Exit a parse tree produced by the {@code typePar}
|
||||
* labeled alternative in {@link KickCParser#typeDecl}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitTypePar(KickCParser.TypeParContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by the {@code typeProcedure}
|
||||
* labeled alternative in {@link KickCParser#typeDecl}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void enterTypeProcedure(KickCParser.TypeProcedureContext ctx);
|
||||
/**
|
||||
* Exit a parse tree produced by the {@code typeProcedure}
|
||||
* labeled alternative in {@link KickCParser#typeDecl}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitTypeProcedure(KickCParser.TypeProcedureContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by the {@code typePtr}
|
||||
* labeled alternative in {@link KickCParser#typeDecl}.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
// Generated from /Users/jespergravgaard/c64/kickc/src/main/java/dk/camelot64/kickc/parser/KickC.g4 by ANTLR 4.7
|
||||
// Generated from C:/c64/kickc/src/main/java/dk/camelot64/kickc/parser\KickC.g4 by ANTLR 4.7
|
||||
package dk.camelot64.kickc.parser;
|
||||
import org.antlr.v4.runtime.tree.ParseTreeVisitor;
|
||||
|
||||
@ -263,6 +263,20 @@ public interface KickCVisitor<T> extends ParseTreeVisitor<T> {
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitForRange(KickCParser.ForRangeContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code typePar}
|
||||
* labeled alternative in {@link KickCParser#typeDecl}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitTypePar(KickCParser.TypeParContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code typeProcedure}
|
||||
* labeled alternative in {@link KickCParser#typeDecl}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitTypeProcedure(KickCParser.TypeProcedureContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code typePtr}
|
||||
* labeled alternative in {@link KickCParser#typeDecl}.
|
||||
|
@ -13,6 +13,7 @@ import dk.camelot64.kickc.model.symbols.*;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeArray;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypePointer;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeProcedure;
|
||||
import dk.camelot64.kickc.model.values.*;
|
||||
import dk.camelot64.kickc.parser.KickCBaseVisitor;
|
||||
import dk.camelot64.kickc.parser.KickCParser;
|
||||
@ -639,6 +640,11 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
return SymbolType.get("signed " + ctx.SIMPLETYPE().getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SymbolType visitTypePar(KickCParser.TypeParContext ctx) {
|
||||
return (SymbolType) visit(ctx.typeDecl());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SymbolType visitTypePtr(KickCParser.TypePtrContext ctx) {
|
||||
SymbolType elementType = (SymbolType) visit(ctx.typeDecl());
|
||||
@ -656,6 +662,12 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitTypeProcedure(KickCParser.TypeProcedureContext ctx) {
|
||||
SymbolType returnType = (SymbolType) visit(ctx.typeDecl());
|
||||
return new SymbolTypeProcedure(returnType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitExprAssignment(KickCParser.ExprAssignmentContext ctx) {
|
||||
Object val = visit(ctx.expr(0));
|
||||
@ -813,13 +825,20 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
|
||||
@Override
|
||||
public RValue visitExprId(KickCParser.ExprIdContext ctx) {
|
||||
Variable variable = getCurrentSymbols().getVariable(ctx.NAME().getText());
|
||||
if(variable != null) {
|
||||
Symbol symbol = getCurrentSymbols().getSymbol(ctx.NAME().getText());
|
||||
if(symbol instanceof Variable) {
|
||||
Variable variable = (Variable) symbol;
|
||||
return variable.getRef();
|
||||
} else {
|
||||
} else if(symbol instanceof Procedure) {
|
||||
Procedure procedure = (Procedure) symbol;
|
||||
if(procedure.isDeclaredInterrupt()) {
|
||||
return procedure.getRef();
|
||||
}
|
||||
} else if(symbol==null){
|
||||
// Either forward reference or a non-existing variable. Create a forward reference for later resolving.
|
||||
return new ForwardVariableRef(ctx.NAME().getText());
|
||||
}
|
||||
throw new CompileError("Error! Unhandled symbol "+symbol.toString(program));
|
||||
}
|
||||
|
||||
public StatementSequence getSequence() {
|
||||
|
@ -6,6 +6,7 @@ import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementCall;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.values.ProcedureRef;
|
||||
|
||||
/** Asserts that interrupts are never called and are not declared inline */
|
||||
@ -28,8 +29,16 @@ public class Pass1AssertInterrupts extends Pass1Base {
|
||||
}
|
||||
}
|
||||
for(Procedure procedure : getScope().getAllProcedures(true)) {
|
||||
if(procedure.isDeclaredInline() && procedure.isDeclaredInterrupt()) {
|
||||
throw new CompileError("Error! Interrupts cannot be inlined. " + procedure.toString());
|
||||
if(procedure.isDeclaredInterrupt()) {
|
||||
if(procedure.isDeclaredInline()) {
|
||||
throw new CompileError("Error! Interrupts cannot be inlined. " + procedure.toString());
|
||||
}
|
||||
if(procedure.getParameters().size()>0) {
|
||||
throw new CompileError("Error! Interrupts cannot have parameters. " + procedure.toString());
|
||||
}
|
||||
if(!SymbolType.VOID.equals(procedure.getReturnType())) {
|
||||
throw new CompileError("Error! Interrupts cannot return anything. " + procedure.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementCall;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
@ -34,7 +35,7 @@ public class Pass1EliminateUncalledProcedures extends Pass1Base {
|
||||
Set<ProcedureRef> unusedProcedures = new LinkedHashSet<>();
|
||||
Collection<Procedure> allProcedures = getProgram().getScope().getAllProcedures(true);
|
||||
for(Procedure procedure : allProcedures) {
|
||||
if(!calledProcedures.contains(procedure.getRef())) {
|
||||
if(!calledProcedures.contains(procedure.getRef()) && !Pass2ConstantIdentification.isAddressOfUsed(procedure.getRef(), getProgram())) {
|
||||
// The procedure is not used - mark for removal!
|
||||
unusedProcedures.add(procedure.getRef());
|
||||
}
|
||||
|
@ -3,7 +3,9 @@ package dk.camelot64.kickc.passes;
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
|
||||
import dk.camelot64.kickc.model.operators.OperatorBinary;
|
||||
import dk.camelot64.kickc.model.operators.OperatorCastPtr;
|
||||
import dk.camelot64.kickc.model.operators.OperatorUnary;
|
||||
import dk.camelot64.kickc.model.operators.Operators;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
@ -100,7 +102,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
||||
if(statement instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) statement;
|
||||
findConstantsAssignment(constants, assignment);
|
||||
} else if( statement instanceof StatementPhiBlock) {
|
||||
} else if(statement instanceof StatementPhiBlock) {
|
||||
StatementPhiBlock phi = (StatementPhiBlock) statement;
|
||||
findConstantsPhi(constants, phi);
|
||||
}
|
||||
@ -131,7 +133,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
||||
if(assignment.getOperator() == null) {
|
||||
// Constant assignment
|
||||
ConstantValue constant = getConstant(assignment.getrValue2());
|
||||
if(constant!=null) {
|
||||
if(constant != null) {
|
||||
constants.put(variable, constant);
|
||||
}
|
||||
} else {
|
||||
@ -174,7 +176,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
||||
} else {
|
||||
if(!SymbolTypeInference.typeMatch(listType, elmType)) {
|
||||
SymbolType intersectType = SymbolTypeInference.intersectTypes(listType, elmType);
|
||||
if(intersectType==null) {
|
||||
if(intersectType == null) {
|
||||
// No overlap between list type and element type
|
||||
throw new RuntimeException("Array type " + listType + " does not match element type" + elmType + ". Array: " + valueList.toString(getProgram()));
|
||||
} else {
|
||||
@ -195,11 +197,11 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
||||
constants.put(variable, constant);
|
||||
}
|
||||
}
|
||||
} else if(Operators.ADDRESS_OF.equals(assignment.getOperator()) && assignment.getrValue1()==null) {
|
||||
} else if(Operators.ADDRESS_OF.equals(assignment.getOperator()) && assignment.getrValue1() == null) {
|
||||
// Constant address-of variable
|
||||
if(assignment.getrValue2() instanceof VariableRef) {
|
||||
ConstantVarPointer constantVarPointer = new ConstantVarPointer((VariableRef) assignment.getrValue2());
|
||||
constants.put(variable, constantVarPointer);
|
||||
if(assignment.getrValue2() instanceof SymbolRef) {
|
||||
ConstantSymbolPointer constantSymbolPointer = new ConstantSymbolPointer((SymbolRef) assignment.getrValue2());
|
||||
constants.put(variable, constantSymbolPointer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -220,7 +222,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
||||
} else if(rValue instanceof CastValue) {
|
||||
CastValue castValue = (CastValue) rValue;
|
||||
ConstantValue castConstant = getConstant(castValue.getValue());
|
||||
if(castConstant !=null) {
|
||||
if(castConstant != null) {
|
||||
return new ConstantCastValue(castValue.getToType(), castConstant);
|
||||
}
|
||||
} else if(rValue instanceof ArrayFilled) {
|
||||
@ -233,6 +235,9 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
||||
}
|
||||
|
||||
static ConstantValue createUnary(OperatorUnary operator, ConstantValue c) {
|
||||
if(operator instanceof OperatorCastPtr) {
|
||||
return new ConstantUnary(operator, c);
|
||||
}
|
||||
switch(operator.getOperator()) {
|
||||
case "-":
|
||||
case "+":
|
||||
@ -309,37 +314,32 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
||||
|
||||
/**
|
||||
* Determines if the variable is ever operated on by the address-of operator
|
||||
* @param var tHe variable to examine
|
||||
*
|
||||
* @param symbolRef tHe variable to examine
|
||||
* @return true if the address-of operator is used on the variable
|
||||
*/
|
||||
public static boolean isAddressOfUsed(VariableRef var, Program program) {
|
||||
public static boolean isAddressOfUsed(SymbolRef symbolRef, Program program) {
|
||||
final boolean[] found = {false};
|
||||
ProgramValueIterator.execute(program, (programValue, currentStmt, stmtIt, currentBlock) -> {
|
||||
RValue value = programValue.get();
|
||||
if(value instanceof ConstantSymbolPointer) {
|
||||
ConstantSymbolPointer constantSymbolPointer = (ConstantSymbolPointer) value;
|
||||
if(constantSymbolPointer.getToSymbol().equals(symbolRef)) {
|
||||
found[0] = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
if(found[0]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for(ControlFlowBlock block : program.getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) statement;
|
||||
if(Operators.ADDRESS_OF.equals(assignment.getOperator()) && var.equals(assignment.getrValue2())) {
|
||||
if(Operators.ADDRESS_OF.equals(assignment.getOperator()) && symbolRef.equals(assignment.getrValue2())) {
|
||||
return true;
|
||||
}
|
||||
} else if(statement instanceof StatementPhiBlock) {
|
||||
for(StatementPhiBlock.PhiVariable phiVariable : ((StatementPhiBlock) statement).getPhiVariables()) {
|
||||
for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) {
|
||||
if(phiRValue.getrValue() instanceof ConstantVarPointer) {
|
||||
if(((ConstantVarPointer)phiRValue.getrValue()).getToVar().equals(var)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for(ConstantVar constVar : program.getScope().getAllConstants(true)) {
|
||||
ConstantValue constantValue = constVar.getValue();
|
||||
if(constantValue instanceof ConstantVarPointer) {
|
||||
ConstantVarPointer constantVarPointer = (ConstantVarPointer) constantValue;
|
||||
if(constantVarPointer.getToVar().equals(var)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -347,5 +347,4 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementAssignment;
|
||||
import dk.camelot64.kickc.model.statements.StatementPhiBlock;
|
||||
import dk.camelot64.kickc.model.symbols.Label;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
import dk.camelot64.kickc.model.symbols.Variable;
|
||||
import dk.camelot64.kickc.model.values.LValue;
|
||||
import dk.camelot64.kickc.model.values.LabelRef;
|
||||
@ -26,11 +27,10 @@ public class Pass2EliminateUnusedBlocks extends Pass2SsaOptimization {
|
||||
|
||||
@Override
|
||||
public boolean step() {
|
||||
Set<LabelRef> referencedBlocks = new LinkedHashSet<>();
|
||||
findReferencedBlocks(getGraph().getFirstBlock(), referencedBlocks);
|
||||
Set<LabelRef> referencedBlocks = getReferencedBlocks();
|
||||
Set<LabelRef> unusedBlocks = new LinkedHashSet<>();
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
if(!referencedBlocks.contains(block.getLabel())) {
|
||||
if(!referencedBlocks.contains(block.getLabel()) ) {
|
||||
unusedBlocks.add(block.getLabel());
|
||||
for(Statement stmt : block.getStatements()) {
|
||||
if(stmt instanceof StatementAssignment) {
|
||||
@ -55,6 +55,24 @@ public class Pass2EliminateUnusedBlocks extends Pass2SsaOptimization {
|
||||
return unusedBlocks.size()>0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all referenced blocks en the entire program
|
||||
* @return All blocks referenced
|
||||
*/
|
||||
private Set<LabelRef> getReferencedBlocks() {
|
||||
Set<LabelRef> referencedBlocks = new LinkedHashSet<>();
|
||||
findReferencedBlocks(getGraph().getFirstBlock(), referencedBlocks);
|
||||
for(Procedure procedure : getScope().getAllProcedures(true)) {
|
||||
if(Pass2ConstantIdentification.isAddressOfUsed(procedure.getRef(), getProgram())) {
|
||||
// Address-of is used on the procedure
|
||||
Label procedureLabel = procedure.getLabel();
|
||||
ControlFlowBlock procedureBlock = getGraph().getBlock(procedureLabel.getRef());
|
||||
findReferencedBlocks(procedureBlock, referencedBlocks);
|
||||
}
|
||||
}
|
||||
return referencedBlocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all PHI RValues in any phi-statements referencing the passed block
|
||||
* @param removeBlock The block to remove from PHI RValues
|
||||
|
@ -1,6 +1,8 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.symbols.Label;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
import dk.camelot64.kickc.model.values.LabelRef;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.symbols.Scope;
|
||||
@ -18,11 +20,23 @@ public class Pass3BlockSequencePlanner extends Pass2Base {
|
||||
}
|
||||
|
||||
public void plan() {
|
||||
|
||||
for(Procedure procedure : getProgram().getScope().getAllProcedures(true)) {
|
||||
if(Pass2ConstantIdentification.isAddressOfUsed(procedure.getRef(), getProgram())) {
|
||||
// Address-of is used on the procedure
|
||||
Label procedureLabel = procedure.getLabel();
|
||||
ControlFlowBlock procedureBlock = getGraph().getBlock(procedureLabel.getRef());
|
||||
pushTodo(procedureBlock);
|
||||
}
|
||||
}
|
||||
|
||||
ControlFlowBlock mainBlock = getGraph().getMainBlock();
|
||||
if(mainBlock != null) {
|
||||
pushTodo(mainBlock);
|
||||
}
|
||||
pushTodo(getGraph().getFirstBlock());
|
||||
|
||||
|
||||
List<LabelRef> sequence = new ArrayList<>();
|
||||
while(hasTodo()) {
|
||||
ControlFlowBlock block = popTodo();
|
||||
|
@ -1,6 +1,8 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.symbols.Label;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
import dk.camelot64.kickc.model.values.LabelRef;
|
||||
|
||||
import java.util.*;
|
||||
@ -27,7 +29,17 @@ public class Pass3LoopDepthAnalysis extends Pass2Base {
|
||||
public void findLoopDepths() {
|
||||
Deque<LabelRef> todo = new ArrayDeque<>();
|
||||
Set<LabelRef> done = new LinkedHashSet<>();
|
||||
// Add the main block block
|
||||
todo.push(callGraph.getFirstCallBlock());
|
||||
// Also add all address-of referenced blocks
|
||||
for(Procedure procedure : getProgram().getScope().getAllProcedures(true)) {
|
||||
if(Pass2ConstantIdentification.isAddressOfUsed(procedure.getRef(), getProgram())) {
|
||||
// Address-of is used on the procedure
|
||||
Label procedureLabel = procedure.getLabel();
|
||||
todo.push(procedureLabel.getRef());
|
||||
}
|
||||
}
|
||||
|
||||
while(!todo.isEmpty()) {
|
||||
LabelRef currentScope = todo.pop();
|
||||
done.add(currentScope);
|
||||
|
@ -5,10 +5,7 @@ import dk.camelot64.kickc.fragment.*;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.operators.Operators;
|
||||
import dk.camelot64.kickc.model.statements.*;
|
||||
import dk.camelot64.kickc.model.symbols.ConstantVar;
|
||||
import dk.camelot64.kickc.model.symbols.ProgramScope;
|
||||
import dk.camelot64.kickc.model.symbols.Scope;
|
||||
import dk.camelot64.kickc.model.symbols.Variable;
|
||||
import dk.camelot64.kickc.model.symbols.*;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeArray;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypePointer;
|
||||
@ -432,7 +429,20 @@ public class Pass4CodeGeneration {
|
||||
}
|
||||
asm.addInstruction("jsr", AsmAddressingMode.ABS, call.getProcedure().getFullName(), false);
|
||||
} else if(statement instanceof StatementReturn) {
|
||||
asm.addInstruction("rts", AsmAddressingMode.NON, null, false);
|
||||
boolean isInterrupt = false;
|
||||
ScopeRef scope = block.getScope();
|
||||
if(!scope.equals(ScopeRef.ROOT)) {
|
||||
Procedure procedure = getScope().getProcedure(scope.getFullName());
|
||||
if(procedure!=null) {
|
||||
isInterrupt = procedure.isDeclaredInterrupt();
|
||||
}
|
||||
}
|
||||
if(isInterrupt) {
|
||||
asm.addInstruction("rti", AsmAddressingMode.NON, null, false);
|
||||
} else {
|
||||
asm.addInstruction("rts", AsmAddressingMode.NON, null, false);
|
||||
}
|
||||
|
||||
} else if(statement instanceof StatementAsm) {
|
||||
StatementAsm statementAsm = (StatementAsm) statement;
|
||||
HashMap<String, Value> bindings = new HashMap<>();
|
||||
|
@ -1,7 +1,8 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.values.ConstantVarPointer;
|
||||
import dk.camelot64.kickc.model.values.ConstantSymbolPointer;
|
||||
import dk.camelot64.kickc.model.values.SymbolRef;
|
||||
import dk.camelot64.kickc.model.values.VariableRef;
|
||||
import dk.camelot64.kickc.model.symbols.ConstantVar;
|
||||
import dk.camelot64.kickc.model.symbols.Variable;
|
||||
@ -70,9 +71,9 @@ public class Pass4RegisterUpliftPotentialInitialize extends Pass2Base {
|
||||
private boolean varRefExtracted(LiveRangeEquivalenceClass equivalenceClass) {
|
||||
Collection<ConstantVar> allConstants = getProgram().getScope().getAllConstants(true);
|
||||
for(ConstantVar allConstant : allConstants) {
|
||||
if(allConstant.getValue() instanceof ConstantVarPointer) {
|
||||
VariableRef toVar = ((ConstantVarPointer) allConstant.getValue()).getToVar();
|
||||
if(equivalenceClass.getVariables().contains(toVar)) {
|
||||
if(allConstant.getValue() instanceof ConstantSymbolPointer) {
|
||||
SymbolRef toSym = ((ConstantSymbolPointer) allConstant.getValue()).getToSymbol();
|
||||
if(equivalenceClass.getVariables().contains(toSym)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -46,6 +46,11 @@ public class TestPrograms {
|
||||
AsmFragmentTemplateUsages.logUsages(log, false, false, false, false, false, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInterrupt() throws IOException, URISyntaxException {
|
||||
compileAndCompare("test-interrupt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiplexer() throws IOException, URISyntaxException {
|
||||
compileAndCompare("simple-multiplexer");
|
||||
@ -891,6 +896,16 @@ public class TestPrograms {
|
||||
assertError("no-calledinterrupt", "Interrupts cannot be called.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoParamInterrupt() throws IOException, URISyntaxException {
|
||||
assertError("no-paraminterrupt", "Interrupts cannot have parameters.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoReturnInterrupt() throws IOException, URISyntaxException {
|
||||
assertError("no-returninterrupt", "Interrupts cannot return anything.");
|
||||
}
|
||||
|
||||
private void assertError(String kcFile, String expectError) throws IOException, URISyntaxException {
|
||||
try {
|
||||
compileAndCompare(kcFile);
|
||||
|
@ -0,0 +1,11 @@
|
||||
// Test that inline interrupts not allowed
|
||||
|
||||
byte* SCREEN = $400;
|
||||
|
||||
void main() {
|
||||
SCREEN[0]++;
|
||||
}
|
||||
|
||||
interrupt void irq(byte b) {
|
||||
SCREEN[1]++;
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
// Test that inline interrupts not allowed
|
||||
|
||||
byte* SCREEN = $400;
|
||||
|
||||
void main() {
|
||||
SCREEN[0]++;
|
||||
}
|
||||
|
||||
interrupt byte irq() {
|
||||
SCREEN[1]++;
|
||||
return 2;
|
||||
}
|
22
src/test/java/dk/camelot64/kickc/test/kc/test-interrupt.kc
Normal file
22
src/test/java/dk/camelot64/kickc/test/kc/test-interrupt.kc
Normal file
@ -0,0 +1,22 @@
|
||||
void()** VECTOR_IRQ = $0314;
|
||||
|
||||
interrupt void irq() {
|
||||
byte* BGCOL = $d020;
|
||||
(*BGCOL)++;
|
||||
asm {
|
||||
lda $dc0d
|
||||
pla
|
||||
tay
|
||||
pla
|
||||
tax
|
||||
pla
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
*VECTOR_IRQ = &irq;
|
||||
byte* FGCOL = $d021;
|
||||
while(true) {
|
||||
(*FGCOL)++;
|
||||
}
|
||||
}
|
26
src/test/java/dk/camelot64/kickc/test/ref/test-interrupt.asm
Normal file
26
src/test/java/dk/camelot64/kickc/test/ref/test-interrupt.asm
Normal file
@ -0,0 +1,26 @@
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
.label VECTOR_IRQ = $314
|
||||
jsr main
|
||||
main: {
|
||||
.label FGCOL = $d021
|
||||
lda #<irq
|
||||
sta VECTOR_IRQ
|
||||
lda #>irq
|
||||
sta VECTOR_IRQ+1
|
||||
b2:
|
||||
inc FGCOL
|
||||
jmp b2
|
||||
}
|
||||
irq: {
|
||||
.label BGCOL = $d020
|
||||
inc BGCOL
|
||||
lda $dc0d
|
||||
pla
|
||||
tay
|
||||
pla
|
||||
tax
|
||||
pla
|
||||
rti
|
||||
}
|
22
src/test/java/dk/camelot64/kickc/test/ref/test-interrupt.cfg
Normal file
22
src/test/java/dk/camelot64/kickc/test/ref/test-interrupt.cfg
Normal file
@ -0,0 +1,22 @@
|
||||
@begin: scope:[] from
|
||||
[0] phi() [ ] ( )
|
||||
to:@2
|
||||
@2: scope:[] from @begin
|
||||
[1] phi() [ ] ( )
|
||||
[2] call main [ ] ( )
|
||||
to:@end
|
||||
@end: scope:[] from @2
|
||||
[3] phi() [ ] ( )
|
||||
main: scope:[main] from @2
|
||||
[4] *((const void()**) VECTOR_IRQ#0) ← &interrupt (void()) irq() [ ] ( main:2 [ ] )
|
||||
to:main::@2
|
||||
main::@2: scope:[main] from main main::@2
|
||||
[5] *((const byte*) main::FGCOL#0) ← ++ *((const byte*) main::FGCOL#0) [ ] ( main:2 [ ] )
|
||||
to:main::@2
|
||||
irq: scope:[irq] from
|
||||
[6] *((const byte*) irq::BGCOL#0) ← ++ *((const byte*) irq::BGCOL#0) [ ] ( )
|
||||
asm { lda$dc0d pla tay pla tax pla }
|
||||
to:irq::@return
|
||||
irq::@return: scope:[irq] from irq
|
||||
[8] return [ ] ( )
|
||||
to:@return
|
467
src/test/java/dk/camelot64/kickc/test/ref/test-interrupt.log
Normal file
467
src/test/java/dk/camelot64/kickc/test/ref/test-interrupt.log
Normal file
@ -0,0 +1,467 @@
|
||||
PARSING src/test/java/dk/camelot64/kickc/test/kc/test-interrupt.kc
|
||||
void()** VECTOR_IRQ = $0314;
|
||||
|
||||
interrupt void irq() {
|
||||
byte* BGCOL = $d020;
|
||||
(*BGCOL)++;
|
||||
asm {
|
||||
lda $dc0d
|
||||
pla
|
||||
tay
|
||||
pla
|
||||
tax
|
||||
pla
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
*VECTOR_IRQ = &irq;
|
||||
byte* FGCOL = $d021;
|
||||
while(true) {
|
||||
(*FGCOL)++;
|
||||
}
|
||||
}
|
||||
|
||||
Adding pre/post-modifier *((byte*) irq::BGCOL) ← ++ *((byte*) irq::BGCOL)
|
||||
Adding pre/post-modifier *((byte*) main::FGCOL) ← ++ *((byte*) main::FGCOL)
|
||||
SYMBOLS
|
||||
(label) @1
|
||||
(label) @2
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(void()**) VECTOR_IRQ
|
||||
interrupt (void()) irq()
|
||||
(label) irq::@return
|
||||
(byte*) irq::BGCOL
|
||||
(void()) main()
|
||||
(void()*~) main::$0
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@3
|
||||
(label) main::@4
|
||||
(label) main::@5
|
||||
(label) main::@6
|
||||
(label) main::@return
|
||||
(byte*) main::FGCOL
|
||||
|
||||
Promoting word/signed word/dword/signed dword to void()** in VECTOR_IRQ ← ((void()**)) 788
|
||||
Promoting word/dword/signed dword to byte* in irq::BGCOL ← ((byte*)) 53280
|
||||
Promoting word/dword/signed dword to byte* in main::FGCOL ← ((byte*)) 53281
|
||||
INITIAL CONTROL FLOW GRAPH
|
||||
@begin: scope:[] from
|
||||
(void()**) VECTOR_IRQ ← ((void()**)) (word/signed word/dword/signed dword) 788
|
||||
to:@1
|
||||
irq: scope:[irq] from
|
||||
(byte*) irq::BGCOL ← ((byte*)) (word/dword/signed dword) 53280
|
||||
*((byte*) irq::BGCOL) ← ++ *((byte*) irq::BGCOL)
|
||||
asm { lda$dc0d pla tay pla tax pla }
|
||||
to:irq::@return
|
||||
irq::@return: scope:[irq] from irq
|
||||
return
|
||||
to:@return
|
||||
@1: scope:[] from @begin
|
||||
to:@2
|
||||
main: scope:[main] from
|
||||
(void()*~) main::$0 ← & interrupt (void()) irq()
|
||||
*((void()**) VECTOR_IRQ) ← (void()*~) main::$0
|
||||
(byte*) main::FGCOL ← ((byte*)) (word/dword/signed dword) 53281
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@2
|
||||
if(true) goto main::@2
|
||||
to:main::@4
|
||||
main::@2: scope:[main] from main::@1 main::@5
|
||||
*((byte*) main::FGCOL) ← ++ *((byte*) main::FGCOL)
|
||||
to:main::@1
|
||||
main::@4: scope:[main] from main::@1
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@4 main::@6
|
||||
to:main::@return
|
||||
main::@5: scope:[main] from
|
||||
to:main::@2
|
||||
main::@6: scope:[main] from
|
||||
to:main::@3
|
||||
main::@return: scope:[main] from main::@3
|
||||
return
|
||||
to:@return
|
||||
@2: scope:[] from @1
|
||||
call main
|
||||
to:@end
|
||||
@end: scope:[] from @2
|
||||
|
||||
Removing empty block @1
|
||||
Removing empty block main::@4
|
||||
Removing empty block main::@3
|
||||
Removing empty block main::@5
|
||||
Removing empty block main::@6
|
||||
PROCEDURE MODIFY VARIABLE ANALYSIS
|
||||
|
||||
Completing Phi functions...
|
||||
Completing Phi functions...
|
||||
|
||||
CONTROL FLOW GRAPH SSA WITH ASSIGNMENT CALL & RETURN
|
||||
@begin: scope:[] from
|
||||
(void()**) VECTOR_IRQ#0 ← ((void()**)) (word/signed word/dword/signed dword) 788
|
||||
to:@2
|
||||
irq: scope:[irq] from
|
||||
(byte*) irq::BGCOL#0 ← ((byte*)) (word/dword/signed dword) 53280
|
||||
*((byte*) irq::BGCOL#0) ← ++ *((byte*) irq::BGCOL#0)
|
||||
asm { lda$dc0d pla tay pla tax pla }
|
||||
to:irq::@return
|
||||
irq::@return: scope:[irq] from irq
|
||||
return
|
||||
to:@return
|
||||
main: scope:[main] from @2
|
||||
(void()**) VECTOR_IRQ#1 ← phi( @2/(void()**) VECTOR_IRQ#2 )
|
||||
(void()*~) main::$0 ← & interrupt (void()) irq()
|
||||
*((void()**) VECTOR_IRQ#1) ← (void()*~) main::$0
|
||||
(byte*) main::FGCOL#0 ← ((byte*)) (word/dword/signed dword) 53281
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@2
|
||||
(byte*) main::FGCOL#2 ← phi( main/(byte*) main::FGCOL#0 main::@2/(byte*) main::FGCOL#1 )
|
||||
if(true) goto main::@2
|
||||
to:main::@return
|
||||
main::@2: scope:[main] from main::@1
|
||||
(byte*) main::FGCOL#1 ← phi( main::@1/(byte*) main::FGCOL#2 )
|
||||
*((byte*) main::FGCOL#1) ← ++ *((byte*) main::FGCOL#1)
|
||||
to:main::@1
|
||||
main::@return: scope:[main] from main::@1
|
||||
return
|
||||
to:@return
|
||||
@2: scope:[] from @begin
|
||||
(void()**) VECTOR_IRQ#2 ← phi( @begin/(void()**) VECTOR_IRQ#0 )
|
||||
call main
|
||||
to:@3
|
||||
@3: scope:[] from @2
|
||||
to:@end
|
||||
@end: scope:[] from @3
|
||||
|
||||
SYMBOL TABLE SSA
|
||||
(label) @2
|
||||
(label) @3
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(void()**) VECTOR_IRQ
|
||||
(void()**) VECTOR_IRQ#0
|
||||
(void()**) VECTOR_IRQ#1
|
||||
(void()**) VECTOR_IRQ#2
|
||||
interrupt (void()) irq()
|
||||
(label) irq::@return
|
||||
(byte*) irq::BGCOL
|
||||
(byte*) irq::BGCOL#0
|
||||
(void()) main()
|
||||
(void()*~) main::$0
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@return
|
||||
(byte*) main::FGCOL
|
||||
(byte*) main::FGCOL#0
|
||||
(byte*) main::FGCOL#1
|
||||
(byte*) main::FGCOL#2
|
||||
|
||||
OPTIMIZING CONTROL FLOW GRAPH
|
||||
Culled Empty Block (label) @3
|
||||
Succesful SSA optimization Pass2CullEmptyBlocks
|
||||
Not aliassing across scopes: VECTOR_IRQ#1 VECTOR_IRQ#2
|
||||
Alias (byte*) main::FGCOL#1 = (byte*) main::FGCOL#2
|
||||
Alias (void()**) VECTOR_IRQ#0 = (void()**) VECTOR_IRQ#2
|
||||
Succesful SSA optimization Pass2AliasElimination
|
||||
Not aliassing across scopes: VECTOR_IRQ#1 VECTOR_IRQ#0
|
||||
Self Phi Eliminated (byte*) main::FGCOL#1
|
||||
Succesful SSA optimization Pass2SelfPhiElimination
|
||||
Redundant Phi (void()**) VECTOR_IRQ#1 (void()**) VECTOR_IRQ#0
|
||||
Redundant Phi (byte*) main::FGCOL#1 (byte*) main::FGCOL#0
|
||||
Succesful SSA optimization Pass2RedundantPhiElimination
|
||||
Constant (const void()**) VECTOR_IRQ#0 = ((void()**))788
|
||||
Constant (const byte*) irq::BGCOL#0 = ((byte*))53280
|
||||
Constant (const void()*) main::$0 = &irq
|
||||
Constant (const byte*) main::FGCOL#0 = ((byte*))53281
|
||||
Succesful SSA optimization Pass2ConstantIdentification
|
||||
if() condition always true - replacing block destination if(true) goto main::@2
|
||||
Succesful SSA optimization Pass2ConstantIfs
|
||||
Removing unused block main::@return
|
||||
Succesful SSA optimization Pass2EliminateUnusedBlocks
|
||||
Culled Empty Block (label) main::@1
|
||||
Succesful SSA optimization Pass2CullEmptyBlocks
|
||||
OPTIMIZING CONTROL FLOW GRAPH
|
||||
Constant inlined main::$0 = &interrupt (void()) irq()
|
||||
Succesful SSA optimization Pass2ConstantInlining
|
||||
Block Sequence Planned @begin @2 @end main main::@2 irq irq::@return
|
||||
Block Sequence Planned @begin @2 @end main main::@2 irq irq::@return
|
||||
Adding NOP phi() at start of @begin
|
||||
Adding NOP phi() at start of @2
|
||||
Adding NOP phi() at start of @end
|
||||
CALL GRAPH
|
||||
Calls in [] to main:2
|
||||
|
||||
Propagating live ranges...
|
||||
Created 0 initial phi equivalence classes
|
||||
Coalesced down to 0 phi equivalence classes
|
||||
Block Sequence Planned @begin @2 @end main main::@2 irq irq::@return
|
||||
Adding NOP phi() at start of @begin
|
||||
Adding NOP phi() at start of @2
|
||||
Adding NOP phi() at start of @end
|
||||
Propagating live ranges...
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
@begin: scope:[] from
|
||||
[0] phi() [ ] ( )
|
||||
to:@2
|
||||
@2: scope:[] from @begin
|
||||
[1] phi() [ ] ( )
|
||||
[2] call main [ ] ( )
|
||||
to:@end
|
||||
@end: scope:[] from @2
|
||||
[3] phi() [ ] ( )
|
||||
main: scope:[main] from @2
|
||||
[4] *((const void()**) VECTOR_IRQ#0) ← &interrupt (void()) irq() [ ] ( main:2 [ ] )
|
||||
to:main::@2
|
||||
main::@2: scope:[main] from main main::@2
|
||||
[5] *((const byte*) main::FGCOL#0) ← ++ *((const byte*) main::FGCOL#0) [ ] ( main:2 [ ] )
|
||||
to:main::@2
|
||||
irq: scope:[irq] from
|
||||
[6] *((const byte*) irq::BGCOL#0) ← ++ *((const byte*) irq::BGCOL#0) [ ] ( )
|
||||
asm { lda$dc0d pla tay pla tax pla }
|
||||
to:irq::@return
|
||||
irq::@return: scope:[irq] from irq
|
||||
[8] return [ ] ( )
|
||||
to:@return
|
||||
|
||||
DOMINATORS
|
||||
@begin dominated by @begin
|
||||
@2 dominated by @2 @begin
|
||||
@end dominated by @2 @begin @end
|
||||
main dominated by @2 @begin main
|
||||
main::@2 dominated by @2 @begin main::@2 main
|
||||
irq dominated by @2 @begin @end main::@2 irq irq::@return main
|
||||
irq::@return dominated by @2 @begin @end main::@2 irq irq::@return main
|
||||
|
||||
NATURAL LOOPS
|
||||
Found back edge: Loop head: main::@2 tails: main::@2 blocks: null
|
||||
Found back edge: Loop head: irq::@return tails: irq blocks: null
|
||||
Populated: Loop head: main::@2 tails: main::@2 blocks: main::@2
|
||||
Populated: Loop head: irq::@return tails: irq blocks: irq
|
||||
Loop head: main::@2 tails: main::@2 blocks: main::@2
|
||||
Loop head: irq::@return tails: irq blocks: irq
|
||||
|
||||
NATURAL LOOPS WITH DEPTH
|
||||
Found 1 loops in scope [irq]
|
||||
Loop head: irq::@return tails: irq blocks: irq
|
||||
Found 0 loops in scope []
|
||||
Found 1 loops in scope [main]
|
||||
Loop head: main::@2 tails: main::@2 blocks: main::@2
|
||||
Loop head: main::@2 tails: main::@2 blocks: main::@2 depth: 1
|
||||
Loop head: irq::@return tails: irq blocks: irq depth: 1
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
(void()**) VECTOR_IRQ
|
||||
interrupt (void()) irq()
|
||||
(byte*) irq::BGCOL
|
||||
(void()) main()
|
||||
(byte*) main::FGCOL
|
||||
|
||||
Initial phi equivalence classes
|
||||
Complete equivalence classes
|
||||
|
||||
INITIAL ASM
|
||||
//SEG0 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
//SEG1 Global Constants & labels
|
||||
.label VECTOR_IRQ = $314
|
||||
//SEG2 @begin
|
||||
bbegin:
|
||||
//SEG3 [1] phi from @begin to @2 [phi:@begin->@2]
|
||||
b2_from_bbegin:
|
||||
jmp b2
|
||||
//SEG4 @2
|
||||
b2:
|
||||
//SEG5 [2] call main [ ] ( )
|
||||
jsr main
|
||||
//SEG6 [3] phi from @2 to @end [phi:@2->@end]
|
||||
bend_from_b2:
|
||||
jmp bend
|
||||
//SEG7 @end
|
||||
bend:
|
||||
//SEG8 main
|
||||
main: {
|
||||
.label FGCOL = $d021
|
||||
//SEG9 [4] *((const void()**) VECTOR_IRQ#0) ← &interrupt (void()) irq() [ ] ( main:2 [ ] ) -- _deref_pptc1=pprc2
|
||||
lda #<irq
|
||||
sta VECTOR_IRQ
|
||||
lda #>irq
|
||||
sta VECTOR_IRQ+1
|
||||
jmp b2
|
||||
//SEG10 main::@2
|
||||
b2:
|
||||
//SEG11 [5] *((const byte*) main::FGCOL#0) ← ++ *((const byte*) main::FGCOL#0) [ ] ( main:2 [ ] ) -- _deref_pbuc1=_inc__deref_pbuc1
|
||||
inc FGCOL
|
||||
jmp b2
|
||||
}
|
||||
//SEG12 irq
|
||||
irq: {
|
||||
.label BGCOL = $d020
|
||||
//SEG13 [6] *((const byte*) irq::BGCOL#0) ← ++ *((const byte*) irq::BGCOL#0) [ ] ( ) -- _deref_pbuc1=_inc__deref_pbuc1
|
||||
inc BGCOL
|
||||
//SEG14 asm { lda$dc0d pla tay pla tax pla }
|
||||
lda $dc0d
|
||||
pla
|
||||
tay
|
||||
pla
|
||||
tax
|
||||
pla
|
||||
jmp breturn
|
||||
//SEG15 irq::@return
|
||||
breturn:
|
||||
//SEG16 [8] return [ ] ( )
|
||||
rti
|
||||
}
|
||||
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [4] *((const void()**) VECTOR_IRQ#0) ← &interrupt (void()) irq() [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||
Statement asm { lda$dc0d pla tay pla tax pla } always clobbers reg byte a reg byte x reg byte y
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [irq]
|
||||
Uplift Scope [main]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [irq] best 413 combination
|
||||
Uplifting [main] best 413 combination
|
||||
Uplifting [] best 413 combination
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
//SEG0 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
//SEG1 Global Constants & labels
|
||||
.label VECTOR_IRQ = $314
|
||||
//SEG2 @begin
|
||||
bbegin:
|
||||
//SEG3 [1] phi from @begin to @2 [phi:@begin->@2]
|
||||
b2_from_bbegin:
|
||||
jmp b2
|
||||
//SEG4 @2
|
||||
b2:
|
||||
//SEG5 [2] call main [ ] ( )
|
||||
jsr main
|
||||
//SEG6 [3] phi from @2 to @end [phi:@2->@end]
|
||||
bend_from_b2:
|
||||
jmp bend
|
||||
//SEG7 @end
|
||||
bend:
|
||||
//SEG8 main
|
||||
main: {
|
||||
.label FGCOL = $d021
|
||||
//SEG9 [4] *((const void()**) VECTOR_IRQ#0) ← &interrupt (void()) irq() [ ] ( main:2 [ ] ) -- _deref_pptc1=pprc2
|
||||
lda #<irq
|
||||
sta VECTOR_IRQ
|
||||
lda #>irq
|
||||
sta VECTOR_IRQ+1
|
||||
jmp b2
|
||||
//SEG10 main::@2
|
||||
b2:
|
||||
//SEG11 [5] *((const byte*) main::FGCOL#0) ← ++ *((const byte*) main::FGCOL#0) [ ] ( main:2 [ ] ) -- _deref_pbuc1=_inc__deref_pbuc1
|
||||
inc FGCOL
|
||||
jmp b2
|
||||
}
|
||||
//SEG12 irq
|
||||
irq: {
|
||||
.label BGCOL = $d020
|
||||
//SEG13 [6] *((const byte*) irq::BGCOL#0) ← ++ *((const byte*) irq::BGCOL#0) [ ] ( ) -- _deref_pbuc1=_inc__deref_pbuc1
|
||||
inc BGCOL
|
||||
//SEG14 asm { lda$dc0d pla tay pla tax pla }
|
||||
lda $dc0d
|
||||
pla
|
||||
tay
|
||||
pla
|
||||
tax
|
||||
pla
|
||||
jmp breturn
|
||||
//SEG15 irq::@return
|
||||
breturn:
|
||||
//SEG16 [8] return [ ] ( )
|
||||
rti
|
||||
}
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp b2
|
||||
Removing instruction jmp bend
|
||||
Removing instruction jmp b2
|
||||
Removing instruction jmp breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Removing instruction bbegin:
|
||||
Removing instruction b2_from_bbegin:
|
||||
Removing instruction bend_from_b2:
|
||||
Succesful ASM optimization Pass5RedundantLabelElimination
|
||||
Removing instruction b2:
|
||||
Removing instruction bend:
|
||||
Removing instruction breturn:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
(label) @2
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(void()**) VECTOR_IRQ
|
||||
(const void()**) VECTOR_IRQ#0 VECTOR_IRQ = ((void()**))(word/signed word/dword/signed dword) 788
|
||||
interrupt (void()) irq()
|
||||
(label) irq::@return
|
||||
(byte*) irq::BGCOL
|
||||
(const byte*) irq::BGCOL#0 BGCOL = ((byte*))(word/dword/signed dword) 53280
|
||||
(void()) main()
|
||||
(label) main::@2
|
||||
(byte*) main::FGCOL
|
||||
(const byte*) main::FGCOL#0 FGCOL = ((byte*))(word/dword/signed dword) 53281
|
||||
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 374
|
||||
|
||||
//SEG0 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
//SEG1 Global Constants & labels
|
||||
.label VECTOR_IRQ = $314
|
||||
//SEG2 @begin
|
||||
//SEG3 [1] phi from @begin to @2 [phi:@begin->@2]
|
||||
//SEG4 @2
|
||||
//SEG5 [2] call main [ ] ( )
|
||||
jsr main
|
||||
//SEG6 [3] phi from @2 to @end [phi:@2->@end]
|
||||
//SEG7 @end
|
||||
//SEG8 main
|
||||
main: {
|
||||
.label FGCOL = $d021
|
||||
//SEG9 [4] *((const void()**) VECTOR_IRQ#0) ← &interrupt (void()) irq() [ ] ( main:2 [ ] ) -- _deref_pptc1=pprc2
|
||||
lda #<irq
|
||||
sta VECTOR_IRQ
|
||||
lda #>irq
|
||||
sta VECTOR_IRQ+1
|
||||
//SEG10 main::@2
|
||||
b2:
|
||||
//SEG11 [5] *((const byte*) main::FGCOL#0) ← ++ *((const byte*) main::FGCOL#0) [ ] ( main:2 [ ] ) -- _deref_pbuc1=_inc__deref_pbuc1
|
||||
inc FGCOL
|
||||
jmp b2
|
||||
}
|
||||
//SEG12 irq
|
||||
irq: {
|
||||
.label BGCOL = $d020
|
||||
//SEG13 [6] *((const byte*) irq::BGCOL#0) ← ++ *((const byte*) irq::BGCOL#0) [ ] ( ) -- _deref_pbuc1=_inc__deref_pbuc1
|
||||
inc BGCOL
|
||||
//SEG14 asm { lda$dc0d pla tay pla tax pla }
|
||||
lda $dc0d
|
||||
pla
|
||||
tay
|
||||
pla
|
||||
tax
|
||||
pla
|
||||
//SEG15 irq::@return
|
||||
//SEG16 [8] return [ ] ( )
|
||||
rti
|
||||
}
|
||||
|
14
src/test/java/dk/camelot64/kickc/test/ref/test-interrupt.sym
Normal file
14
src/test/java/dk/camelot64/kickc/test/ref/test-interrupt.sym
Normal file
@ -0,0 +1,14 @@
|
||||
(label) @2
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(void()**) VECTOR_IRQ
|
||||
(const void()**) VECTOR_IRQ#0 VECTOR_IRQ = ((void()**))(word/signed word/dword/signed dword) 788
|
||||
interrupt (void()) irq()
|
||||
(label) irq::@return
|
||||
(byte*) irq::BGCOL
|
||||
(const byte*) irq::BGCOL#0 BGCOL = ((byte*))(word/dword/signed dword) 53280
|
||||
(void()) main()
|
||||
(label) main::@2
|
||||
(byte*) main::FGCOL
|
||||
(const byte*) main::FGCOL#0 FGCOL = ((byte*))(word/dword/signed dword) 53281
|
||||
|
Loading…
x
Reference in New Issue
Block a user