1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-06-03 07:29:37 +00:00

- Code improvements for CallingDistance and CallingProximity

This commit is contained in:
Flight_Control 2023-04-18 10:14:47 +02:00
parent 3735b248c3
commit 4aeed59d0e
4 changed files with 94 additions and 66 deletions

View File

@ -14,6 +14,7 @@ import dk.camelot64.kickc.model.operators.OperatorUnary;
import dk.camelot64.kickc.model.operators.Operators; import dk.camelot64.kickc.model.operators.Operators;
import dk.camelot64.kickc.model.statements.*; import dk.camelot64.kickc.model.statements.*;
import dk.camelot64.kickc.model.symbols.Label; import dk.camelot64.kickc.model.symbols.Label;
import dk.camelot64.kickc.model.symbols.Procedure;
import dk.camelot64.kickc.model.symbols.Symbol; import dk.camelot64.kickc.model.symbols.Symbol;
import dk.camelot64.kickc.model.types.SymbolType; import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypeInference; import dk.camelot64.kickc.model.types.SymbolTypeInference;
@ -44,19 +45,17 @@ final public class AsmFragmentInstanceSpecBuilder {
/** /**
* Create a fragment instance spec factory for a subroutine call * Create a fragment instance spec factory for a subroutine call
* *
* @param distance The string expressing the distance of the call: "near", "close", "far". * @param callingDistance The class expressing the distance of the call: "near", "close", "far" plus bankArea and bank information calculated from the from and to procedure.
* @param callingConvention The string expressing the calling convention supported by the fragment. * @param callingConvention The string expressing the calling convention supported by the fragment.
* @param bankArea The bank area where the procedure is to be called.
* @param bank The bank where the procedure is to be called.
* @param procedureName The full name of the procedure. * @param procedureName The full name of the procedure.
* @param program The program * @param program The program
* @return the fragment instance spec factory * @return the fragment instance spec factory
*/ */
public static AsmFragmentInstanceSpec callBanked(String distance, String callingConvention, String bankArea, Long bank, String procedureName, Program program) { public static AsmFragmentInstanceSpec callBanked(Procedure.CallingDistance callingDistance, String callingConvention, String procedureName, Program program) {
AsmFragmentBindings bindings = new AsmFragmentBindings(program); AsmFragmentBindings bindings = new AsmFragmentBindings(program);
AsmFragmentSignature signature = new AsmFragmentSignature.CallBanked(distance, callingConvention, bankArea, bank); AsmFragmentSignature signature = new AsmFragmentSignature.CallBanked(callingDistance, callingConvention);
ScopeRef codeScope = program.getScope().getRef(); ScopeRef codeScope = program.getScope().getRef();
bindings.bind("c1", new ConstantInteger(bank)); bindings.bind("c1", new ConstantInteger(callingDistance.getBank()));
bindings.bind("la1", new LabelRef(procedureName)); bindings.bind("la1", new LabelRef(procedureName));
return new AsmFragmentInstanceSpec(program, signature, bindings, codeScope); return new AsmFragmentInstanceSpec(program, signature, bindings, codeScope);
} }

View File

@ -2,6 +2,7 @@ package dk.camelot64.kickc.fragment.signature;
import dk.camelot64.kickc.asm.fragment.signature.AsmFragmentSignatureLexer; import dk.camelot64.kickc.asm.fragment.signature.AsmFragmentSignatureLexer;
import dk.camelot64.kickc.asm.fragment.signature.AsmFragmentSignatureParser; import dk.camelot64.kickc.asm.fragment.signature.AsmFragmentSignatureParser;
import dk.camelot64.kickc.model.symbols.Procedure;
import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.CommonTokenStream;
@ -75,21 +76,17 @@ public interface AsmFragmentSignature {
*/ */
class CallBanked implements AsmFragmentSignature { class CallBanked implements AsmFragmentSignature {
final private String distance; final private Procedure.CallingDistance callingDistance;
final private String callingConvention; final private String callingConvention;
final private String bankArea;
final private Long bank;
public CallBanked(String distance, String callingConvention, String bankArea, Long bank) { public CallBanked(Procedure.CallingDistance callingDistance, String callingConvention) {
this.distance = distance; this.callingDistance = callingDistance;
this.callingConvention = callingConvention; this.callingConvention = callingConvention;
this.bankArea = bankArea;
this.bank = bank;
} }
@Override @Override
public String getName() { public String getName() {
return "call_" + callingConvention.toLowerCase() + "_" + distance.toLowerCase() + ((bankArea.isEmpty()) ? "" : ("_" + bankArea.toLowerCase())); return "call_" + callingConvention.toLowerCase() + "_" + callingDistance.getFragmentName().toLowerCase();
} }
} }

View File

@ -64,6 +64,89 @@ public class Procedure extends Scope {
this.bankLocation = bankLocation; this.bankLocation = bankLocation;
} }
public enum CallingProximity {
NEAR("near"),
CLOSE("close"),
FAR("far");
public String getProximity() {
return proximity;
}
private final String proximity;
CallingProximity(String proximity) {
this.proximity = proximity;
}
}
/** The method for expressing the call distance to implement banking
*
* The following variations exist related to banked calls:
* - #1 - unbanked to unbanked and no banking areas
* - #2 - unbanked to banked to any bank area
* - #3 - banked to unbanked from any bank area
* - #4 - banked to same bank in same bank area
* - #5 - banked to different bank in same bank area
* - #6 - banked to any bank between different bank areas
*
* This brings us to the call types:
* - CallingDistance.NEAR - case #1, #3, #4
* - CallingDistance.CLOSE - case #2, #6
* - CallingDistance.FAR - case #5
*/
public static class CallingDistance {
private CallingProximity proximity;
private String bankArea;
private Long bank;
public CallingProximity getProximity() {
return proximity;
}
public String getBankArea() {
return bankArea;
}
public Long getBank() {
return bank;
}
public CallingDistance(Procedure from, Procedure to) {
if (((!from.isDeclaredBanked() && !to.isDeclaredBanked())) ||
((from.isDeclaredBanked() && !to.isDeclaredBanked())) ||
((from.isDeclaredBanked() && to.isDeclaredBanked()) &&
(from.getBank() == to.getBank()) &&
(from.getBankArea().contentEquals(to.getBankArea()))
)
) {
// near call - case #1, #3, #4
this.proximity = CallingProximity.NEAR;
this.bankArea = "";
this.bank = 0L;
} else {
if ((!from.isDeclaredBanked() && to.isDeclaredBanked()) ||
((from.isDeclaredBanked() && to.isDeclaredBanked()) && (!from.getBankArea().contentEquals(to.getBankArea())))
) {
// close call - case #2, #6
this.proximity = CallingProximity.CLOSE;
this.bankArea = to.getBankArea();
this.bank = to.getBank();
} else {
// far call - case #5
this.proximity = CallingProximity.FAR;
this.bankArea = to.getBankArea();
this.bank = to.getBank();
}
}
}
public String getFragmentName() {
return this.proximity.getProximity() + (this.bankArea.isEmpty() ? "" : "_" + this.bankArea);
}
}
/** The method for passing parameters and return value to the procedure. */ /** The method for passing parameters and return value to the procedure. */
public enum CallingConvention { public enum CallingConvention {

View File

@ -906,56 +906,13 @@ public class Pass4CodeGeneration {
genBlockPhiTransition(asm, block, callSuccessor, block.getScope()); genBlockPhiTransition(asm, block, callSuccessor, block.getScope());
} }
} }
/* AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.callBanked(new Procedure.CallingDistance(fromProcedure, toProcedure),"phi", call.getProcedure().getFullName(), program), program);
The following variations exist related to banked calls:
#1 - unbanked to unbanked and no banking areas
#2 - unbanked to banked to any bank area
#3 - banked to unbanked from any bank area
#4 - banked to same bank in same bank area
#5 - banked to different bank in same bank area
#6 - banked to any bank between different bank areas
This brings us to the call types:
near - case #1, #3, #4
close - case #2, #6
far - case #5
*/
String fromBankArea = fromProcedure.getBankArea();
String toBankArea = toProcedure.getBankArea();
Boolean fromIsBanked = fromProcedure.isDeclaredBanked();
Boolean toIsBanked = toProcedure.isDeclaredBanked();
Long fromBank = fromProcedure.getBank();
Long toBank = toProcedure.getBank();
if( ((!fromIsBanked && !toIsBanked)) ||
((fromIsBanked && !toIsBanked)) ||
((fromIsBanked && toIsBanked) && (fromBank == toBank) && (fromBankArea.contentEquals(toBankArea)))
) {
// near call - case #1, #3, #4
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.callBanked( "near","phi", "", 0L, call.getProcedure().getFullName(), program), program);
// // Otherwise, Generate AM for a normal near call.
// asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false);
} else {
if( (!fromIsBanked && toIsBanked) ||
((fromIsBanked && toIsBanked) && (!fromBankArea.contentEquals(toBankArea)))
) {
// close call - case #2, #6
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.callBanked( "close","phi", toBankArea, toBank, call.getProcedure().getFullName(), program), program);
} else {
// far call - case #5
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.callBanked( "far","phi", toBankArea, toBank, call.getProcedure().getFullName(), program), program);
}
}
} else if (Procedure.CallingConvention.STACK_CALL.equals(toProcedure.getCallingConvention())) { } else if (Procedure.CallingConvention.STACK_CALL.equals(toProcedure.getCallingConvention())) {
// Same as PHI
String fromBankArea = fromProcedure.getBankArea();
String toBankArea = toProcedure.getBankArea();
Boolean fromIsBanked = fromProcedure.isDeclaredBanked();
Boolean toIsBanked = toProcedure.isDeclaredBanked(); Boolean toIsBanked = toProcedure.isDeclaredBanked();
Long fromBank = fromProcedure.getBank(); Long fromBank = fromProcedure.getBank();
Long toBank = toProcedure.getBank(); Long toBank = toProcedure.getBank();
if(toIsBanked && fromBank != toBank) { if(toIsBanked && fromBank != toBank) {
throw new CompileError("Stack Call procedure not supported in banked mode " + toProcedure.toString(program)); throw new CompileError("Stack Call procedure not supported in banked mode " + toProcedure.toString(program));
// AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.callBanked("far", "stack", toProcedure.getBankArea(), toProcedure.getBank(), call.getProcedure().getFullName(), program), program);
} else { } else {
asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false); asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false);
} }
@ -967,20 +924,12 @@ public class Pass4CodeGeneration {
ProgramScope scope = getScope(); ProgramScope scope = getScope();
Procedure toProcedure = scope.getProcedure(procedureRef); Procedure toProcedure = scope.getProcedure(procedureRef);
Procedure fromProcedure = block.getProcedure(this.program); // We obtain from where the procedure is called, to validate the bank equality. Procedure fromProcedure = block.getProcedure(this.program); // We obtain from where the procedure is called, to validate the bank equality.
String fromBankArea = fromProcedure.getBankArea();
String toBankArea = toProcedure.getBankArea();
Boolean fromIsBanked = fromProcedure.isDeclaredBanked();
Boolean toIsBanked = toProcedure.isDeclaredBanked();
Long fromBank = fromProcedure.getBank();
Long toBank = toProcedure.getBank();
RValue procedureRVal = call.getProcedureRVal(); RValue procedureRVal = call.getProcedureRVal();
// Same as PHI // Same as PHI
if (toProcedure.isDeclaredBanked() && fromProcedure.getBank() != toProcedure.getBank()) { if (toProcedure.isDeclaredBanked() && fromProcedure.getBank() != toProcedure.getBank()) {
throw new CompileError("Stack Call procedure not supported in banked mode " + toProcedure.toString(program)); throw new CompileError("Stack Call procedure not supported in banked mode " + toProcedure.toString(program));
// AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.callBanked( "far", "stack", toProcedure.getBankArea(), toProcedure.getBank(), call.getProcedure().getFullName(), program), program);
} else { } else {
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.call(call, indirectCallCount++, program), program); AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.call(call, indirectCallCount++, program), program);
// AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.callBanked( "near", "stack", toProcedure.getBankArea(), toProcedure.getBank(), call.getProcedure().getFullName(), program), program);
} }
if (!(procedureRVal instanceof ProcedureRef)) { if (!(procedureRVal instanceof ProcedureRef)) {
asm.getCurrentChunk().setClobberOverwrite(CpuClobber.CLOBBER_ALL); asm.getCurrentChunk().setClobberOverwrite(CpuClobber.CLOBBER_ALL);