- 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.statements.*;
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.types.SymbolType;
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
*
* @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 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 program The program
* @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);
AsmFragmentSignature signature = new AsmFragmentSignature.CallBanked(distance, callingConvention, bankArea, bank);
AsmFragmentSignature signature = new AsmFragmentSignature.CallBanked(callingDistance, callingConvention);
ScopeRef codeScope = program.getScope().getRef();
bindings.bind("c1", new ConstantInteger(bank));
bindings.bind("c1", new ConstantInteger(callingDistance.getBank()));
bindings.bind("la1", new LabelRef(procedureName));
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.AsmFragmentSignatureParser;
import dk.camelot64.kickc.model.symbols.Procedure;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
@ -75,21 +76,17 @@ public interface AsmFragmentSignature {
*/
class CallBanked implements AsmFragmentSignature {
final private String distance;
final private Procedure.CallingDistance callingDistance;
final private String callingConvention;
final private String bankArea;
final private Long bank;
public CallBanked(String distance, String callingConvention, String bankArea, Long bank) {
this.distance = distance;
public CallBanked(Procedure.CallingDistance callingDistance, String callingConvention) {
this.callingDistance = callingDistance;
this.callingConvention = callingConvention;
this.bankArea = bankArea;
this.bank = bank;
}
@Override
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;
}
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. */
public enum CallingConvention {

View File

@ -906,56 +906,13 @@ public class Pass4CodeGeneration {
genBlockPhiTransition(asm, block, callSuccessor, block.getScope());
}
}
/*
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);
}
}
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.callBanked(new Procedure.CallingDistance(fromProcedure, toProcedure),"phi", call.getProcedure().getFullName(), program), program);
} 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();
Long fromBank = fromProcedure.getBank();
Long toBank = toProcedure.getBank();
if(toIsBanked && fromBank != toBank) {
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 {
asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false);
}
@ -967,20 +924,12 @@ public class Pass4CodeGeneration {
ProgramScope scope = getScope();
Procedure toProcedure = scope.getProcedure(procedureRef);
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();
// Same as PHI
if (toProcedure.isDeclaredBanked() && fromProcedure.getBank() != toProcedure.getBank()) {
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 {
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)) {
asm.getCurrentChunk().setClobberOverwrite(CpuClobber.CLOBBER_ALL);