mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-02-20 00:29:10 +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.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);
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user