mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-02-16 18:30:37 +00:00
- Code improvements for CallingDistance and CallingProximity
This commit is contained in:
parent
3735b248c3
commit
4aeed59d0e
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user