mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-06-03 07:29:37 +00:00
Libraries
This commit is contained in:
parent
1025aa5b00
commit
1f0bddc768
|
@ -80,6 +80,7 @@ FORM_SSA: '__ssa' ;
|
|||
FORM_MA: '__ma' ;
|
||||
INTRINSIC: '__intrinsic' ;
|
||||
CALLINGCONVENTION: '__stackcall' | '__phicall' | '__varcall' | '__intrinsiccall';
|
||||
LIBRARY: '__library';
|
||||
IF: 'if' ;
|
||||
ELSE: 'else' ;
|
||||
WHILE: 'while' ;
|
||||
|
|
|
@ -166,6 +166,7 @@ directive
|
|||
| INTERRUPT ( PAR_BEGIN NAME PAR_END )? #directiveInterrupt
|
||||
| LOCAL_RESERVE PAR_BEGIN pragmaParam ( COMMA pragmaParam )* PAR_END #directiveReserveZp
|
||||
| CALLINGCONVENTION #directiveCallingConvention
|
||||
| LIBRARY PAR_BEGIN pragmaParam PAR_END #directiveLibrary
|
||||
;
|
||||
|
||||
stmtSeq
|
||||
|
|
|
@ -242,7 +242,7 @@ public class Compiler {
|
|||
|
||||
if(getLog().isVerbosePass1CreateSsa()) {
|
||||
getLog().append("SYMBOLS");
|
||||
getLog().append(program.getScope().toStringVars(program, false));
|
||||
getLog().append(program.getScope().toStringVars(program, false, false));
|
||||
}
|
||||
|
||||
new Pass1FixLValuesLoHi(program).execute();
|
||||
|
@ -337,7 +337,7 @@ public class Compiler {
|
|||
getLog().append(program.prettyControlFlowGraph());
|
||||
|
||||
getLog().append("SYMBOL TABLE SSA");
|
||||
getLog().append(program.getScope().toStringVars(program, false));
|
||||
getLog().append(program.getScope().toStringVars(program, false, false));
|
||||
|
||||
program.endPass1();
|
||||
|
||||
|
@ -673,7 +673,7 @@ public class Compiler {
|
|||
|
||||
getLog().append("\nVARIABLE REGISTER WEIGHTS");
|
||||
program.getVariableRegisterWeights();
|
||||
getLog().append(program.getScope().toStringVars(program, true));
|
||||
getLog().append(program.getScope().toStringVars(program, true, false));
|
||||
|
||||
new Pass4LiveRangeEquivalenceClassesFinalize(program).allocate();
|
||||
new Pass4RegistersFinalize(program).allocate(true, false);
|
||||
|
@ -784,12 +784,15 @@ public class Compiler {
|
|||
}
|
||||
|
||||
getLog().append("\nFINAL SYMBOL TABLE");
|
||||
getLog().append(program.getScope().toStringVars(program, false));
|
||||
getLog().append(program.getScope().toStringVars(program, false, false));
|
||||
|
||||
getLog().append("\nFINAL ASSEMBLER");
|
||||
getLog().append("Score: " + Pass4RegisterUpliftCombinations.getAsmScore(program) + "\n");
|
||||
getLog().append(program.getAsm().toString(new AsmProgram.AsmPrintState(false, true, true, false), program));
|
||||
|
||||
getLog().append("\nZERO PAGE TABLE");
|
||||
getLog().append(program.getScope().toStringVars(program, true, true));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -292,7 +292,7 @@ public class AsmFormat {
|
|||
if(!symbolScopeRef.equals(codeScopeRef)) {
|
||||
if(symbolScopeRef.getFullName().length() > 0)
|
||||
// Reference to symbol in another scope
|
||||
return asmFix(symbolScopeRef.getFullName() + "." + asmName);
|
||||
return asmFix2(symbolScopeRef.getFullName() + "." + asmName, symbolScopeRef.getFullName());
|
||||
else {
|
||||
// Check if the local code scope has a symbol with the same name
|
||||
final Scope codeScope = program.getScope().getScope(codeScopeRef);
|
||||
|
@ -305,7 +305,7 @@ public class AsmFormat {
|
|||
}
|
||||
} else {
|
||||
// Reference to local symbol
|
||||
return asmFix(asmName);
|
||||
return asmFix2(asmName, codeScopeRef.getLocalName());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -337,5 +337,32 @@ public class AsmFormat {
|
|||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix characters in an ASM parameter/label name. Handles '@:$#'
|
||||
*
|
||||
* @param source The source string
|
||||
* @return The fixed string
|
||||
*/
|
||||
public static String asmFix2(String source, String prefix) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
char[] sourceChars = source.toCharArray();
|
||||
for(char sourceChar : sourceChars) {
|
||||
switch(sourceChar) {
|
||||
case '@':
|
||||
result.append("__b");
|
||||
break;
|
||||
case ':':
|
||||
case '#':
|
||||
result.append('_');
|
||||
break;
|
||||
case '$':
|
||||
result.append( prefix + "__");
|
||||
break;
|
||||
default:
|
||||
result.append(sourceChar);
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ final public class AsmFragmentInstanceSpecBuilder {
|
|||
(callingDistance.equals(Bank.CallingDistance.NEAR)?null:toBank.bankArea()));
|
||||
ScopeRef codeScope = program.getScope().getRef();
|
||||
bindings.bind("c1", new ConstantInteger(toBank.bankNumber()));
|
||||
bindings.bind("la1", new LabelRef(toProcedure.getFullName()));
|
||||
bindings.bind("la1", new LabelRef(((toProcedure.getLibrary() != null)?toProcedure.getLibrary().toLowerCase() + ".":"") + toProcedure.getFullName()));
|
||||
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.Bank;
|
||||
import org.antlr.v4.runtime.CharStream;
|
||||
import org.antlr.v4.runtime.CharStreams;
|
||||
import org.antlr.v4.runtime.CommonTokenStream;
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
package dk.camelot64.kickc.model;
|
||||
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
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.SymbolTypeProcedure;
|
||||
import dk.camelot64.kickc.model.values.ConstantInteger;
|
||||
|
|
|
@ -176,5 +176,23 @@ public class Directive {
|
|||
}
|
||||
}
|
||||
|
||||
/** Indicates the location is in a library. */
|
||||
public static class Library extends Directive {
|
||||
public String getLibrary() {
|
||||
return library;
|
||||
}
|
||||
|
||||
public void setLibrary(String library) {
|
||||
this.library = library;
|
||||
}
|
||||
|
||||
private String library;
|
||||
|
||||
public Library(String library) {
|
||||
super("__library");
|
||||
this.library = library;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -23,6 +23,10 @@ public class Procedure extends Scope {
|
|||
private List<String> parameterNames;
|
||||
/** True if the parameter list ends with a variable length parameter list "..." */
|
||||
private boolean variableLengthParameterList;
|
||||
/** True if the procedure is declared extern, which will declare the procedure and it's parameters,
|
||||
* but a coding block is not defined within the compilation and must be handled at an other place.
|
||||
*/
|
||||
private boolean declaredExtern;
|
||||
/** true if the procedure is declared inline. */
|
||||
private boolean declaredInline;
|
||||
/** True if the procedure is declared intrinsic. */
|
||||
|
@ -41,6 +45,18 @@ public class Procedure extends Scope {
|
|||
private boolean isConstructor;
|
||||
/** The source of the procedure definition. */
|
||||
private StatementSource definitionSource;
|
||||
|
||||
/** The library where the function resides */
|
||||
private String library;
|
||||
|
||||
public String getLibrary() {
|
||||
return library;
|
||||
}
|
||||
|
||||
public void setLibrary(String library) {
|
||||
this.library = library;
|
||||
}
|
||||
|
||||
/**
|
||||
* The bank that the procedure code is placed in.
|
||||
* Used to decide whether to produce near, close or far call code when generating calls.
|
||||
|
@ -109,6 +125,7 @@ public class Procedure extends Scope {
|
|||
super(name, parentScope, segmentData);
|
||||
this.procedureType = procedureType;
|
||||
this.declaredInline = false;
|
||||
this.declaredExtern = false;
|
||||
this.bank = Objects.requireNonNull(bank);
|
||||
this.interruptType = null;
|
||||
this.comments = new ArrayList<>();
|
||||
|
@ -116,6 +133,7 @@ public class Procedure extends Scope {
|
|||
this.callingConvention = callingConvention;
|
||||
this.constructorRefs = new ArrayList<>();
|
||||
this.isConstructor = false;
|
||||
this.library = null;
|
||||
}
|
||||
|
||||
public StatementSource getDefinitionSource() {
|
||||
|
@ -153,6 +171,13 @@ public class Procedure extends Scope {
|
|||
public boolean isVariableLengthParameterList() {
|
||||
return variableLengthParameterList;
|
||||
}
|
||||
public boolean isDeclaredExtern() {
|
||||
return declaredExtern;
|
||||
}
|
||||
|
||||
public void setDeclaredExtern(boolean declaredExtern) {
|
||||
this.declaredExtern = declaredExtern;
|
||||
}
|
||||
|
||||
public boolean isDeclaredIntrinsic() {
|
||||
return declaredIntrinsic;
|
||||
|
@ -206,7 +231,7 @@ public class Procedure extends Scope {
|
|||
StringBuilder res = new StringBuilder();
|
||||
res.append(toString(program));
|
||||
res.append("\n");
|
||||
res.append(super.toStringVars(program, onlyVars));
|
||||
res.append(super.toStringVars(program, onlyVars, false));
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package dk.camelot64.kickc.model.symbols;
|
|||
import dk.camelot64.kickc.model.LiveRangeEquivalenceClass;
|
||||
import dk.camelot64.kickc.model.LiveRangeEquivalenceClassSet;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.Registers;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeProgram;
|
||||
import dk.camelot64.kickc.model.values.*;
|
||||
|
@ -112,16 +113,25 @@ public class ProgramScope extends Scope {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String toStringVars(Program program, boolean onlyVars) {
|
||||
public String toStringVars(Program program, boolean onlyVars, boolean onlyZP) {
|
||||
LiveRangeEquivalenceClassSet liveRangeEquivalenceClassSet = program.getLiveRangeEquivalenceClassSet();
|
||||
StringBuilder out = new StringBuilder();
|
||||
out.append(super.toStringVars(program, onlyVars));
|
||||
out.append(super.toStringVars(program, onlyVars, onlyZP));
|
||||
if(liveRangeEquivalenceClassSet != null) {
|
||||
out.append("\n");
|
||||
Integer maxZP = 0;
|
||||
for(LiveRangeEquivalenceClass liveRangeEquivalenceClass : liveRangeEquivalenceClassSet.getEquivalenceClasses()) {
|
||||
out.append(liveRangeEquivalenceClass.toString());
|
||||
out.append("\n");
|
||||
Registers.Register register = liveRangeEquivalenceClass.getRegister();
|
||||
if(onlyZP && register != null && Registers.RegisterType.ZP_MEM == register.getType()) {
|
||||
out.append(liveRangeEquivalenceClass.toString());
|
||||
out.append("\n");
|
||||
Integer ZP = ((Registers.RegisterZpMem) register).getZp();
|
||||
if (ZP > maxZP && !program.getReservedZps().contains(ZP)) {
|
||||
maxZP = ZP;
|
||||
}
|
||||
}
|
||||
}
|
||||
out.append("\nMaximum zeropage register consumed: " + maxZP + String.format(" (0x%x)", maxZP));
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
|
|
@ -356,7 +356,7 @@ public abstract class Scope implements Symbol {
|
|||
return (Scope) symbol;
|
||||
}
|
||||
|
||||
public String toStringVars(Program program, boolean onlyVars) {
|
||||
public String toStringVars(Program program, boolean onlyVars, boolean onlyZP) {
|
||||
VariableRegisterWeights registerWeights = program.getOrNullVariableRegisterWeights();
|
||||
StringBuilder res = new StringBuilder();
|
||||
Set<String> names = symbols.keySet();
|
||||
|
@ -369,10 +369,11 @@ public abstract class Scope implements Symbol {
|
|||
if(symbol instanceof StructDefinition)
|
||||
continue;
|
||||
if(!onlyVars || symbol instanceof Procedure || symbol instanceof BlockScope || symbol instanceof ProgramScope)
|
||||
res.append(((Scope) symbol).toStringVars(program, onlyVars));
|
||||
res.append(((Scope) symbol).toStringVars(program, onlyVars, false));
|
||||
} else if(symbol instanceof Variable) {
|
||||
Variable symVar = (Variable) symbol;
|
||||
if(!onlyVars || symVar.isVariable()) {
|
||||
if(!(onlyZP && symVar.getRegister() instanceof Registers.RegisterZpMem && symVar.getRegister().getType() == Registers.RegisterType.ZP_MEM)) continue; // Show only ZP vars
|
||||
// Output if not instructed to only output variables - or if it is a variable
|
||||
if(symVar.isKindLoadStore()) res.append("__loadstore ");
|
||||
if(symVar.isKindConstant()) res.append("__constant ");
|
||||
|
|
|
@ -320,17 +320,14 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||
program.addReservedZps(reservedZps);
|
||||
}
|
||||
case CParser.PRAGMA_CONSTRUCTOR_FOR -> {
|
||||
this.pragmaConstructorFors.add(ctx);
|
||||
return null;
|
||||
this.pragmaConstructorFors.add(ctx);
|
||||
return null;
|
||||
}
|
||||
// Defines that the result is an asm routine or capability library instead of a program.
|
||||
case CParser.PRAGMA_LIBRARY -> {
|
||||
this.asmLibrary = pragmaParamName(pragmaParamSingle(ctx));
|
||||
program.setAsmLibrary(this.asmLibrary);
|
||||
}
|
||||
default -> {
|
||||
program.getLog().append("Warning! Unknown #pragma " + pragmaName);
|
||||
case CParser.PRAGMA_LIBRARY -> { // Defines that the result is an asm routine or capability library instead of a program.
|
||||
this.asmLibrary = pragmaParamName(pragmaParamSingle(ctx));
|
||||
program.setAsmLibrary(this.asmLibrary);
|
||||
}
|
||||
default -> program.getLog().append("Warning! Unknown #pragma " + pragmaName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -473,6 +470,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||
// enter the procedure
|
||||
scopeStack.push(procedure);
|
||||
|
||||
/** Copied to solve Issue #820 - the preparation of the return block */
|
||||
Variable returnVar = procedure.getLocalVar("return");
|
||||
|
||||
// Add the body
|
||||
|
@ -537,7 +535,97 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||
program.createProcedureCompilation(procedure.getRef());
|
||||
}
|
||||
|
||||
if(defineProcedure) {
|
||||
if(procedure.isDeclaredExtern() && !defineProcedure) {
|
||||
|
||||
/** This is an almost exact copy of a procedure definition.
|
||||
* When a procedure is defined external, the required control blocks are to be allocated
|
||||
* for the procedure parameters and return value for the sequent steps in the compiler to work.
|
||||
* However, during assembler generation, an externally defined procedure is completely ignored from being generated.
|
||||
* In this way, without too much impact on the compiler design, external functions could be implemented.
|
||||
*
|
||||
* The code is copied and reworked from (Search for #820):
|
||||
* - Issue #820 TAG A - the preparation of the parameters and the entry block.
|
||||
* - Issue #820 TAG B - the preparation of the return block.
|
||||
*
|
||||
*/
|
||||
|
||||
// Make sure comments, directives and source are from the definition
|
||||
addDirectives(procedure, varDecl.getDeclDirectives());
|
||||
procedure.setComments(ensureUnusedComments(getCommentsSymbol(ctx)));
|
||||
procedure.setDefinitionSource(statementSource);
|
||||
// enter the procedure
|
||||
scopeStack.push(procedure);
|
||||
// Add parameter variables...
|
||||
boolean variableLengthParameterList = false;
|
||||
List<Variable> parameterList = new ArrayList<>();
|
||||
for (ParameterDecl parameter : varDecl.parameters) {
|
||||
// Handle variable length parameter lists
|
||||
if (SymbolType.PARAM_LIST.equals(parameter.type)) {
|
||||
procedure.setVariableLengthParameterList(true);
|
||||
variableLengthParameterList = true;
|
||||
continue;
|
||||
} else if (variableLengthParameterList)
|
||||
throw new CompileError("Variable length parameter list is only legal as the last parameter.", statementSource);
|
||||
|
||||
// Handle stray void parameters (Any single void parameter was removed by the type parser)
|
||||
if (SymbolType.VOID.equals(parameter.type))
|
||||
throw new CompileError("Illegal void parameter.", statementSource);
|
||||
|
||||
// Handle parameters without a name in the declaration
|
||||
if (parameter.name == null)
|
||||
throw new CompileError("Illegal unnamed parameter.", statementSource);
|
||||
|
||||
VariableBuilder varBuilder = new VariableBuilder(parameter.name, getCurrentScope(), true, false, parameter.type, null, currentSegmentData, program.getTargetPlatform().getVariableBuilderConfig());
|
||||
final Variable paramVar = varBuilder.build();
|
||||
parameterList.add(paramVar);
|
||||
}
|
||||
procedure.setParameters(parameterList);
|
||||
procedure.setSegmentData(currentSegmentData); // When a procedure is defined, the currentDataSegment is to be set.
|
||||
procedure.setSegmentCode(currentSegmentCode); // When a procedure is defined, the currentSegmentCode is to be set.
|
||||
if(procedure.getBank() == null && currentBank != null) {
|
||||
procedure.setBank(currentBank); // When a procedure is defined, the currentBank is to be set, or far calls won't work.
|
||||
}
|
||||
// Add return variable
|
||||
if(!SymbolType.VOID.equals(procedure.getReturnType())) {
|
||||
final VariableBuilder builder = new VariableBuilder("return", procedure, false, false, procedure.getReturnType(), varDecl.getDeclDirectives(), currentSegmentData, program.getTargetPlatform().getVariableBuilderConfig());
|
||||
builder.build();
|
||||
}
|
||||
|
||||
Variable returnVar = procedure.getLocalVar("return");
|
||||
|
||||
// Add the body
|
||||
addStatement(new StatementProcedureBegin(procedure.getRef(), statementSource, Comment.NO_COMMENTS));
|
||||
|
||||
Label procExit = procedure.addLabel(SymbolRef.PROCEXIT_BLOCK_NAME);
|
||||
|
||||
// Variable tmpVar = addIntermediateVar();
|
||||
// RValue rValue = tmpVar.getRef();
|
||||
// returnVar = procedure.getLocalVariable("return");
|
||||
//
|
||||
// addStatement(new StatementAssignment((LValue) returnVar.getRef(), rValue, false, statementSource, null));
|
||||
// Label returnLabel = procedure.getLocalLabel(SymbolRef.PROCEXIT_BLOCK_NAME);
|
||||
// addStatement(new StatementJump(returnLabel.getRef(), new StatementSource(ctx), ensureUnusedComments(getCommentsSymbol(ctx))));
|
||||
|
||||
addStatement(new StatementLabel(procExit.getRef(), statementSource, Comment.NO_COMMENTS));
|
||||
if(Procedure.CallingConvention.PHI_CALL.equals(procedure.getCallingConvention()) && returnVar != null && returnVar.isKindPhiMaster()) {
|
||||
addStatement(new StatementAssignment(returnVar.getVariableRef(), returnVar.getRef(), false, statementSource, Comment.NO_COMMENTS));
|
||||
}
|
||||
SymbolVariableRef returnVarRef = null;
|
||||
if(returnVar != null) {
|
||||
returnVarRef = returnVar.getRef();
|
||||
returnVar.setDeclarationOnly(false); // The procedure is defined as extern and this property is interited by the variable.
|
||||
|
||||
// program.getScope().add(tmpVar);
|
||||
//tmpVar.setDeclarationOnly(false); // Same for the temporary return value.
|
||||
}
|
||||
addStatement(new StatementReturn(returnVarRef, statementSource, Comment.NO_COMMENTS));
|
||||
addStatement(new StatementProcedureEnd(procedure.getRef(), statementSource, Comment.NO_COMMENTS));
|
||||
|
||||
scopeStack.pop();
|
||||
}
|
||||
|
||||
/** Copied to solve Issue #820 TAG A */
|
||||
if(defineProcedure && !procedure.isDeclaredExtern()) {
|
||||
// Make sure comments, directives and source are from the definition
|
||||
addDirectives(procedure, varDecl.getDeclDirectives());
|
||||
procedure.setComments(ensureUnusedComments(getCommentsSymbol(ctx)));
|
||||
|
@ -1198,6 +1286,8 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||
} else if(directive instanceof Directive.Bank directiveBank) {
|
||||
Bank bank = new Bank(directiveBank.getBankArea(), directiveBank.getBankNumber());
|
||||
procedure.setBank(bank);
|
||||
} else if(directive instanceof Directive.Library) {
|
||||
procedure.setLibrary(((Directive.Library) directive).getLibrary());
|
||||
} else if(directive instanceof Directive.CallingConvention) {
|
||||
procedure.setCallingConvention(((Directive.CallingConvention) directive).callingConvention);
|
||||
} else if(directive instanceof Directive.Interrupt) {
|
||||
|
@ -1206,6 +1296,8 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||
procedure.setReservedZps(((Directive.ReserveZp) directive).reservedZp);
|
||||
} else if(directive instanceof Directive.Intrinsic) {
|
||||
procedure.setDeclaredIntrinsic(true);
|
||||
} else if(directive instanceof Directive.Extern) {
|
||||
procedure.setDeclaredExtern(true);
|
||||
//} else {
|
||||
// throw new CompileError("Unsupported function directive " + directive.getName(), source);
|
||||
}
|
||||
|
@ -1264,6 +1356,11 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||
return new Directive.Interrupt(interruptType);
|
||||
}
|
||||
|
||||
public Object visitDirectiveLibrary(KickCParser.DirectiveLibraryContext ctx) {
|
||||
String library = ctx.pragmaParam().getText().toLowerCase(Locale.ENGLISH);
|
||||
return new Directive.Library(library);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Directive visitDirectiveCallingConvention(KickCParser.DirectiveCallingConventionContext ctx) {
|
||||
Procedure.CallingConvention callingConvention = Procedure.CallingConvention.getCallingConvension(ctx.getText());
|
||||
|
|
|
@ -62,10 +62,14 @@ public class Pass1AssertReturn extends Pass1Base {
|
|||
}
|
||||
}
|
||||
Graph.Block successor = graph.getBlock(block.getDefaultSuccessor());
|
||||
if(successor == null || successor.getLabel().getLocalName().equals(SymbolRef.PROCEXIT_BLOCK_NAME)) {
|
||||
throw new CompileError("Error! Method must end with a return statement. " + block.getScope().toString(getProgram()));
|
||||
} else {
|
||||
assertReturn(graph, successor, visited);
|
||||
Procedure procedure = getProgram().getProcedure(successor);
|
||||
// External procedures have a dummy return statement, it is for a placeholder only and it is not defined properly.
|
||||
if(!procedure.isDeclaredExtern()) {
|
||||
if (successor == null || successor.getLabel().getLocalName().equals(SymbolRef.PROCEXIT_BLOCK_NAME)) {
|
||||
throw new CompileError("Error! Method must end with a return statement. " + block.getScope().toString(getProgram()));
|
||||
} else {
|
||||
assertReturn(graph, successor, visited);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -70,6 +70,8 @@ public class Pass1AssertUsedVars extends Pass1Base {
|
|||
for(Statement statement : block.getStatements()) {
|
||||
// PHI block has already been examined
|
||||
if(statement instanceof StatementPhiBlock) continue;
|
||||
// External procedures have no defined variables, not even the return statement. The blocks are dummy blocks.
|
||||
if(this.getProgram().getProcedure(block).isDeclaredExtern()) continue;
|
||||
Collection<VariableRef> used = referenceInfos.getUsedVars(statement);
|
||||
for(VariableRef usedRef : used) {
|
||||
if(!defined.contains(usedRef)) {
|
||||
|
|
|
@ -133,20 +133,21 @@ public class Pass1CallStack extends Pass2SsaOptimization {
|
|||
final StatementSource source = call.getSource();
|
||||
List<Comment> comments = call.getComments();
|
||||
List<SymbolType> paramTypes = call.getProcedureType().getParamTypes();
|
||||
for(int i=0;i<paramTypes.size();i++) {
|
||||
SymbolType paramType = paramTypes.get(i);
|
||||
final RValue parameterVal = call.getParameters().get(i);
|
||||
generateStackPushValues(parameterVal, paramType, source, comments, stmtIt);
|
||||
// Clear comments - enduring they are only output once
|
||||
comments = Comment.NO_COMMENTS;
|
||||
}
|
||||
// Push additional bytes for padding if needed
|
||||
long stackFrameByteSize = CallingConventionStack.getStackFrameByteSize(call.getProcedureType());
|
||||
long parametersByteSize = CallingConventionStack.getParametersByteSize(call.getProcedureType());
|
||||
final long stackPadBytes = stackFrameByteSize - parametersByteSize;
|
||||
if(stackFrameByteSize > parametersByteSize) {
|
||||
// Add padding to the stack to make room for the return value
|
||||
stmtIt.add(new StatementExprSideEffect( new StackPushPadding(new ConstantInteger(stackPadBytes)), source, comments));
|
||||
stmtIt.add(new StatementExprSideEffect( new StackPushPadding(new ConstantInteger(stackPadBytes)), source, comments));
|
||||
}
|
||||
// Now calculate the variables.
|
||||
for(int i=0;i<paramTypes.size();i++) {
|
||||
SymbolType paramType = paramTypes.get(i);
|
||||
final RValue parameterVal = call.getParameters().get(i);
|
||||
generateStackPushValues(parameterVal, paramType, source, comments, stmtIt);
|
||||
// Clear comments - enduring they are only output once
|
||||
comments = Comment.NO_COMMENTS;
|
||||
}
|
||||
stmtIt.next();
|
||||
stmtIt.remove();
|
||||
|
|
|
@ -28,9 +28,11 @@ public class Pass1GenerateControlFlowGraph extends Pass1Base {
|
|||
continue;
|
||||
final ProcedureCompilation procedureCompilation = getProgram().getProcedureCompilation(procedure.getRef());
|
||||
final StatementSequence sequence = procedureCompilation.getStatementSequence();
|
||||
if(sequence.getStatements().size()==0)
|
||||
// Empty procedures should not produce any blocks
|
||||
continue;
|
||||
if(!procedure.isDeclaredExtern()) {
|
||||
if (sequence.getStatements().size() == 0)
|
||||
// Empty procedures should not produce any blocks
|
||||
continue;
|
||||
}
|
||||
|
||||
List<Graph.Block> blocks = new ArrayList<>();
|
||||
|
||||
|
|
|
@ -19,24 +19,24 @@ public class Pass2AssertPhiPredecessors extends Pass2SsaAssertion {
|
|||
|
||||
@Override
|
||||
public void check() throws AssertionFailed {
|
||||
// We cannot do this assertion if the output is an assembler library,
|
||||
// since an asm library does not contain a main function ...
|
||||
if(this.getProgram().getAsmLibrary() == null) {
|
||||
for(var block : getGraph().getAllBlocks()) {
|
||||
if(block.hasPhiBlock()) {
|
||||
StatementPhiBlock phiBlock = block.getPhiBlock();
|
||||
List<Graph.Block> phiPredecessors = Pass1GenerateSingleStaticAssignmentForm.getPhiPredecessors(block, getProgram());
|
||||
List<LabelRef> predecessors =
|
||||
phiPredecessors.stream().map(Graph.Block::getLabel).toList();
|
||||
for (StatementPhiBlock.PhiVariable phiVariable : phiBlock.getPhiVariables()) {
|
||||
for (StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) {
|
||||
if (!predecessors.contains(phiRValue.getPredecessor())) {
|
||||
throw new CompileError("INTERNAL ERROR! Block " + block.getLabel() + " phi references non-predecessor block " + phiRValue.getPredecessor() +
|
||||
"\n " + phiBlock.toString(getProgram(), false));
|
||||
}
|
||||
// We cannot do this assertion if the output is an assembler library,
|
||||
// since an asm library does not contain a main function ...
|
||||
if(this.getProgram().getAsmLibrary() == null) {
|
||||
for (var block : getGraph().getAllBlocks()) {
|
||||
if (block.hasPhiBlock()) {
|
||||
StatementPhiBlock phiBlock = block.getPhiBlock();
|
||||
List<Graph.Block> phiPredecessors = Pass1GenerateSingleStaticAssignmentForm.getPhiPredecessors(block, getProgram());
|
||||
List<LabelRef> predecessors =
|
||||
phiPredecessors.stream().map(Graph.Block::getLabel).toList();
|
||||
for (StatementPhiBlock.PhiVariable phiVariable : phiBlock.getPhiVariables()) {
|
||||
for (StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) {
|
||||
if (!predecessors.contains(phiRValue.getPredecessor())) {
|
||||
throw new CompileError("INTERNAL ERROR! Block " + block.getLabel() + " phi references non-predecessor block " + phiRValue.getPredecessor() +
|
||||
"\n " + phiBlock.toString(getProgram(), false));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,10 +8,7 @@ import dk.camelot64.kickc.model.types.SymbolType;
|
|||
import dk.camelot64.kickc.model.types.SymbolTypePointer;
|
||||
import dk.camelot64.kickc.model.values.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Compiler Pass finding and consolidating identical constant strings
|
||||
|
|
|
@ -123,67 +123,70 @@ public class Pass4CodeGeneration {
|
|||
/** Issue #820 - Reworked the code generation, avoiding code to be generated
|
||||
* for procedures which are external. These must be included through linkage.
|
||||
*/
|
||||
Procedure procedure = block.getProcedure(program);
|
||||
Procedure procedure = program.getProcedure(block);
|
||||
if (!block.getScope().equals(currentScope)) {
|
||||
// The current block is in a different scope. End the old scope.
|
||||
if(oldProcedure != null && !oldProcedure.isDeclaredExtern()) {
|
||||
|
||||
if (oldProcedure != null && !oldProcedure.isDeclaredExtern()) {
|
||||
// The current block is in a different scope. End the old scope.
|
||||
generateScopeEnding(asm, currentScope);
|
||||
}
|
||||
currentScope = block.getScope();
|
||||
oldProcedure = procedure;
|
||||
if (program.isProcedureEntry(block)) {
|
||||
Procedure procedure = program.getProcedure(block);
|
||||
currentCodeSegmentName = procedure.getSegmentCode();
|
||||
}
|
||||
setCurrentSegment(currentCodeSegmentName, asm);
|
||||
asm.startChunk(currentScope, null, block.getLabel().getFullName());
|
||||
if (!procedure.isDeclaredExtern()) {
|
||||
setCurrentSegment(currentCodeSegmentName, asm);
|
||||
asm.startChunk(currentScope, null, block.getLabel().getFullName());
|
||||
}
|
||||
// Add any procedure comments
|
||||
if (program.isProcedureEntry(block)) {
|
||||
Procedure procedure = program.getProcedure(block);
|
||||
generateComments(asm, procedure.getComments());
|
||||
// Generate parameter information
|
||||
generateSignatureComments(asm, procedure);
|
||||
}
|
||||
// Start the new scope
|
||||
asm.addScopeBegin(AsmFormat.asmFix(block.getLabel().getFullName()));
|
||||
// Add all ZP labels for the scope
|
||||
addConstantsAndLabels(asm, currentScope);
|
||||
}
|
||||
|
||||
generateComments(asm, block.getComments());
|
||||
// Generate entry points (if needed)
|
||||
genBlockEntryPoints(asm, block);
|
||||
|
||||
if (program.isProcedureEntry(block)) {
|
||||
// Generate interrupt entry if needed
|
||||
Procedure procedure = program.getProcedure(block);
|
||||
if (procedure != null && procedure.getInterruptType() != null) {
|
||||
generateInterruptEntry(asm, procedure);
|
||||
if (!procedure.isDeclaredExtern()) {
|
||||
// Start the new scope
|
||||
asm.addScopeBegin(AsmFormat.asmFix(block.getLabel().getFullName()));
|
||||
// Add all ZP labels for the scope
|
||||
addConstantsAndLabels(asm, currentScope);
|
||||
}
|
||||
} else {
|
||||
// Generate label for block inside procedure
|
||||
asm.startChunk(currentScope, null, block.getLabel().getFullName());
|
||||
asm.addLabel(AsmFormat.asmFix(block.getLabel().getLocalName()));
|
||||
}
|
||||
// Generate statements
|
||||
genStatements(asm, block);
|
||||
// Generate exit
|
||||
Graph.Block defaultSuccessor = getGraph().getDefaultSuccessor(block);
|
||||
if (defaultSuccessor != null) {
|
||||
if (defaultSuccessor.hasPhiBlock()) {
|
||||
PhiTransitions.PhiTransition transition = getTransitions(defaultSuccessor).getTransition(block);
|
||||
if (!transitionIsGenerated(transition)) {
|
||||
genBlockPhiTransition(asm, block, defaultSuccessor, defaultSuccessor.getScope());
|
||||
String label = AsmFormat.asmFix(defaultSuccessor.getLabel().getLocalName());
|
||||
asm.addInstruction("JMP", CpuAddressingMode.ABS, label, false);
|
||||
} else {
|
||||
String label = AsmFormat.asmFix(defaultSuccessor.getLabel().getLocalName() + "_from_" + block.getLabel().getLocalName());
|
||||
asm.addInstruction("JMP", CpuAddressingMode.ABS, label, false);
|
||||
|
||||
if (!program.getProcedure(block).isDeclaredExtern()) {
|
||||
generateComments(asm, block.getComments());
|
||||
// Generate entry points (if needed)
|
||||
genBlockEntryPoints(asm, block);
|
||||
|
||||
if (program.isProcedureEntry(block)) {
|
||||
// Generate interrupt entry if needed
|
||||
if (procedure != null && procedure.getInterruptType() != null) {
|
||||
generateInterruptEntry(asm, procedure);
|
||||
}
|
||||
} else {
|
||||
String label = AsmFormat.asmFix(defaultSuccessor.getLabel().getLocalName());
|
||||
asm.addInstruction("JMP", CpuAddressingMode.ABS, label, false);
|
||||
// Generate label for block inside procedure
|
||||
asm.startChunk(currentScope, null, block.getLabel().getFullName());
|
||||
asm.addLabel(AsmFormat.asmFix(block.getLabel().getLocalName()));
|
||||
}
|
||||
// Generate statements
|
||||
genStatements(asm, block);
|
||||
// Generate exit
|
||||
Graph.Block defaultSuccessor = getGraph().getDefaultSuccessor(block);
|
||||
if (defaultSuccessor != null) {
|
||||
if (defaultSuccessor.hasPhiBlock()) {
|
||||
PhiTransitions.PhiTransition transition = getTransitions(defaultSuccessor).getTransition(block);
|
||||
if (!transitionIsGenerated(transition)) {
|
||||
genBlockPhiTransition(asm, block, defaultSuccessor, defaultSuccessor.getScope());
|
||||
String label = AsmFormat.asmFix(defaultSuccessor.getLabel().getLocalName());
|
||||
asm.addInstruction("JMP", CpuAddressingMode.ABS, label, false);
|
||||
} else {
|
||||
String label = AsmFormat.asmFix(defaultSuccessor.getLabel().getLocalName() + "_from_" + block.getLabel().getLocalName());
|
||||
asm.addInstruction("JMP", CpuAddressingMode.ABS, label, false);
|
||||
}
|
||||
} else {
|
||||
String label = AsmFormat.asmFix(defaultSuccessor.getLabel().getLocalName());
|
||||
asm.addInstruction("JMP", CpuAddressingMode.ABS, label, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -200,11 +203,11 @@ public class Pass4CodeGeneration {
|
|||
}
|
||||
|
||||
// Name of the current data segment
|
||||
private String currentCodeSegmentName = Scope.SEGMENT_CODE_DEFAULT;
|
||||
String currentCodeSegmentName = Scope.SEGMENT_CODE_DEFAULT;
|
||||
// Name of the current code segment
|
||||
private final String currentDataSegmentName = Scope.SEGMENT_DATA_DEFAULT;
|
||||
final String currentDataSegmentName = Scope.SEGMENT_DATA_DEFAULT;
|
||||
// Name of the current active segment
|
||||
private String currentSegmentName = "";
|
||||
String currentSegmentName = "";
|
||||
|
||||
/**
|
||||
* Set the current ASM segment - if needed
|
||||
|
@ -498,7 +501,7 @@ public class Pass4CodeGeneration {
|
|||
// Ensure encoding is good
|
||||
AsmEncodingHelper.ensureEncoding(asm, variable.getInitValue());
|
||||
// Find the constant value calculation
|
||||
asm.addLabelDecl(AsmFormat.asmFix(asmName), asmConstant);
|
||||
asm.addLabelDecl(AsmFormat.asmFix2(asmName, variable.getScope().getLocalName()), asmConstant);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -583,7 +586,7 @@ public class Pass4CodeGeneration {
|
|||
if (constantValue instanceof ConstantArray || constantValue instanceof ConstantString || constantValue instanceof ConstantStructValue) {
|
||||
AsmDataChunk asmDataChunk = new AsmDataChunk();
|
||||
addChunkData(asmDataChunk, constantValue, constantVar.getType(), constantVar.getArraySpec(), scopeRef);
|
||||
asmDataChunk.addToAsm(AsmFormat.asmFix(asmName), asm);
|
||||
asmDataChunk.addToAsm(AsmFormat.asmFix2(asmName, constantVar.getScope().getLocalName()), asm);
|
||||
} else {
|
||||
throw new InternalError("Constant Variable not handled " + constantVar.toString(program));
|
||||
}
|
||||
|
@ -624,14 +627,15 @@ public class Pass4CodeGeneration {
|
|||
ConstantValue constantValue = variable.getInitValue();
|
||||
AsmDataChunk asmDataChunk = new AsmDataChunk();
|
||||
addChunkData(asmDataChunk, constantValue, variable.getType(), variable.getArraySpec(), scopeRef);
|
||||
asmDataChunk.addToAsm(AsmFormat.asmFix(variable.getAsmName()), asm);
|
||||
asmDataChunk.addToAsm(AsmFormat.asmFix2(variable.getAsmName(), variable.getScope().getLocalName()), asm);
|
||||
} else {
|
||||
// Zero-fill variable
|
||||
AsmDataChunk asmDataChunk = new AsmDataChunk();
|
||||
ConstantValue zeroValue = Initializers.createZeroValue(new Initializers.ValueTypeSpec(variable.getType()), null);
|
||||
addChunkData(asmDataChunk, zeroValue, variable.getType(), variable.getArraySpec(), scopeRef);
|
||||
asmDataChunk.addToAsm(AsmFormat.asmFix(variable.getAsmName()), asm);
|
||||
asmDataChunk.addToAsm(AsmFormat.asmFix2(variable.getAsmName(), variable.getScope().getLocalName()), asm);
|
||||
}
|
||||
|
||||
}
|
||||
added.add(variable.getAsmName());
|
||||
}
|
||||
|
@ -907,7 +911,14 @@ public class Pass4CodeGeneration {
|
|||
} else if (Procedure.CallingConvention.STACK_CALL.equals(toProcedure.getCallingConvention())) {
|
||||
final Bank.CallingDistance callingDistance = Bank.CallingDistance.forCall(fromProcedure.getBank(), toProcedure.getBank());
|
||||
if(Bank.CallingDistance.NEAR.equals(callingDistance)) {
|
||||
asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false);
|
||||
if(toProcedure.getLibrary() == null) {
|
||||
asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false);
|
||||
} else {
|
||||
// Call the library routine and clobber all registers.
|
||||
// Possibly an option to be given that specific routines only clobber specific registers.
|
||||
asm.addInstruction("jsr", CpuAddressingMode.ABS, toProcedure.getLibrary() + "." + call.getProcedure().getFullName(), false);
|
||||
asm.getCurrentChunk().setClobberOverwrite(CpuClobber.CLOBBER_ALL);
|
||||
}
|
||||
} else {
|
||||
throw new CompileError("Stack Call procedure not supported in banked mode " + toProcedure.toString(program));
|
||||
}
|
||||
|
@ -918,14 +929,26 @@ public class Pass4CodeGeneration {
|
|||
if(procedureRef != null) {
|
||||
ProgramScope scope = getScope();
|
||||
Procedure toProcedure = scope.getProcedure(procedureRef);
|
||||
Procedure fromProcedure = program.getProcedure(block);
|
||||
final Bank.CallingDistance callingDistance = Bank.CallingDistance.forCall(fromProcedure.getBank(), toProcedure.getBank());
|
||||
if(Bank.CallingDistance.NEAR.equals(callingDistance)) {
|
||||
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.call(call, indirectCallCount++, program), program);
|
||||
} else {
|
||||
throw new CompileError("Stack Call procedure not supported in banked mode " + toProcedure.toString(program));
|
||||
}
|
||||
Procedure fromProcedure = program.getProcedure(block); // We obtain from where the procedure is called, to validate the bank equality.
|
||||
RValue procedureRVal = call.getProcedureRVal();
|
||||
// Same as PHI
|
||||
final Bank.CallingDistance callingDistance = Bank.CallingDistance.forCall(fromProcedure.getBank(), toProcedure.getBank());
|
||||
if (Bank.CallingDistance.FAR.equals(callingDistance)) {
|
||||
// if (toProcedure.isDeclaredBanked() && fromProcedure.getBank() != toProcedure.getBank()) {
|
||||
throw new CompileError("Stack Call procedure not supported in banked mode " + toProcedure.toString(program));
|
||||
} else {
|
||||
if (toProcedure.getLibrary() == null) {
|
||||
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.call(call, indirectCallCount++, program), program);
|
||||
} else {
|
||||
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.callBanked(toProcedure, callingDistance, program), program);
|
||||
|
||||
// Call the library routine and clobber all registers.
|
||||
// Possibly an option to be given that specific routines only clobber specific registers.
|
||||
//asm.addInstruction("jsr", CpuAddressingMode.ABS, toProcedure.getLibrary() + "." + call.getProcedure().getFullName(), false);
|
||||
asm.getCurrentChunk().setClobberOverwrite(CpuClobber.CLOBBER_ALL);
|
||||
}
|
||||
}
|
||||
// RValue procedureRVal = call.getProcedureRVal();
|
||||
if (!(procedureRVal instanceof ProcedureRef)) {
|
||||
asm.getCurrentChunk().setClobberOverwrite(CpuClobber.CLOBBER_ALL);
|
||||
}
|
||||
|
@ -969,11 +992,47 @@ public class Pass4CodeGeneration {
|
|||
}
|
||||
}
|
||||
}
|
||||
/* author: sven.van.de.velde@telenet.be - 2023-03-21
|
||||
The following logic ensures that inlined asm{} blocks placed in inline functions()
|
||||
are replacing the used C constants or variables with the inlined version
|
||||
of these C constants or variables.
|
||||
During pass1, in the functions inlineStatement() and execute() in the Pass1ProcedureInline.c,
|
||||
the asm fragment gets scanned for referenced constants or variables and the
|
||||
referenced constant names get updated with the modified inlined referenced constant names.
|
||||
These modified reference names are then used here in the asm generation, to scan the asm fragment,
|
||||
of which the source is the bare, parsed antlr source, and really directly in the cut/pasted source
|
||||
search for any constant or variable in operand1 and replace with the inlined reference
|
||||
constant or variable name using the Operand1 structure.
|
||||
This is the only pragmatic way I saw possible.
|
||||
However, this section gets called during coalescing many, many times and
|
||||
slows the compiler. However, such solution requires a complete redesign and cannot
|
||||
just be put in scope to add this fix. So I hope that this change is acceptable.
|
||||
*/
|
||||
for (AsmLine asmLine : currentChunk.getLines()) {
|
||||
if (asmLine instanceof AsmInstruction) {
|
||||
AsmInstruction asmInstruction = (AsmInstruction) asmLine;
|
||||
Map<String, SymbolRef> referenced = statementAsm.getReferenced();
|
||||
for(String reference : referenced.keySet()) {
|
||||
String operand = asmInstruction.getOperand1();
|
||||
if(operand != null) {
|
||||
String replace = referenced.get(reference).getLocalName();
|
||||
if(operand.startsWith(replace)) {
|
||||
} else {
|
||||
if(operand.contains(reference)) {
|
||||
operand = operand.replaceAll(reference, replace);
|
||||
asmInstruction.setOperand1(operand);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (statement instanceof StatementKickAsm) {
|
||||
StatementKickAsm statementKasm = (StatementKickAsm) statement;
|
||||
addKickAsm(asm, statementKasm);
|
||||
AsmChunk currentChunk = asm.getCurrentChunk();
|
||||
if (statementKasm.getDeclaredClobber() != null) {
|
||||
asm.getCurrentChunk().setClobberOverwrite(statementKasm.getDeclaredClobber());
|
||||
currentChunk.setClobberOverwrite(statementKasm.getDeclaredClobber());
|
||||
}
|
||||
} else if (statement instanceof StatementCallPointer) {
|
||||
throw new InternalError("Statement not supported " + statement);
|
||||
|
|
|
@ -122,10 +122,13 @@ public abstract class Pass4MemoryCoalesce extends Pass2Base {
|
|||
for(VariableRef varRef : equivalenceClass.getVariables()) {
|
||||
Variable variable = program.getScope().getVariable(varRef);
|
||||
ScopeRef scopeRef = variable.getScope().getRef();
|
||||
if(scopeRef.equals(ScopeRef.ROOT)) {
|
||||
ProcedureRef mainThreadHead = program.getScope().getLocalProcedure(SymbolRef.MAIN_PROC_NAME).getRef();
|
||||
if(!threads.contains(mainThreadHead)) {
|
||||
threads.add(mainThreadHead);
|
||||
if(scopeRef.equals(ScopeRef.ROOT) ) {
|
||||
Procedure localProcedure = program.getScope().getLocalProcedure(SymbolRef.MAIN_PROC_NAME);
|
||||
if(localProcedure != null && program.getAsmLibrary() != "") {
|
||||
ProcedureRef mainThreadHead = localProcedure.getRef();
|
||||
if(!threads.contains(mainThreadHead)) {
|
||||
threads.add(mainThreadHead);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Collection<ScopeRef> recursiveCallers = callGraph.getRecursiveCallerProcs(scopeRef);
|
||||
|
|
|
@ -70,7 +70,7 @@ public class Pass4RegisterUpliftPotentialRegisterAnalysis extends Pass2Base {
|
|||
RegisterPotentials registerPotentials = getProgram().getRegisterPotentials();
|
||||
|
||||
VariableReferenceInfos referenceInfo = getProgram().getVariableReferenceInfos();
|
||||
for(var block : getProgram().getGraph().getAllBlocks()) {
|
||||
for(var block : getProgram().getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
|
||||
// Find all variables referenced/assigned in the statement
|
||||
|
|
|
@ -29,7 +29,7 @@ public class PassNEliminateEmptyProcedure extends Pass2SsaOptimization {
|
|||
boolean optimized = false;
|
||||
for(Procedure procedure : allProcedures) {
|
||||
if(procedure.isDeclaredIntrinsic()) continue;
|
||||
if(hasEmptyBody(procedure.getRef())) {
|
||||
if(hasEmptyBody(procedure.getRef()) && !procedure.isDeclaredExtern()) {
|
||||
if(!hasExternalUsages(procedure.getRef(), getProgram()) && !SymbolRef.MAIN_PROC_NAME.equals(procedure.getLabel().getLocalName())) {
|
||||
// TODO: Entry point procedures include isAddressOfUsed!
|
||||
// Remove all calls
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
package dk.camelot64.kickc.passes.unwinding;
|
||||
|
||||
import dk.camelot64.kickc.model.Graph;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.InternalError;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.VariableBuilder;
|
||||
import dk.camelot64.kickc.model.operators.Operators;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementAssignment;
|
||||
|
@ -120,7 +118,7 @@ public class ValueSourcePointerDereferenceIndexed extends ValueSourceBase {
|
|||
}
|
||||
} else {
|
||||
if(memberArraySpec != null)
|
||||
throw new InternalError("Not implemented!");
|
||||
throw new CompileError("Not implemented!", currentStmt);
|
||||
Scope scope = programScope.getScope(currentBlock.getScope());
|
||||
SymbolTypePointer type = new SymbolTypePointer(memberType);
|
||||
Variable memberAddress = VariableBuilder.createIntermediate(scope, type, program);
|
||||
|
|
|
@ -193,7 +193,7 @@ public class TestPrograms {
|
|||
ReferenceHelper helper = new ReferenceHelperFolder(refPath);
|
||||
String baseFileName = FileNameUtils.removeExtension(fileName);
|
||||
success &= helper.testOutput(baseFileName, ".asm", program.getAsm().toString(new AsmProgram.AsmPrintState(false, true, false, false), program));
|
||||
success &= helper.testOutput(baseFileName, ".sym", program.getScope().toStringVars(program, false));
|
||||
success &= helper.testOutput(baseFileName, ".sym", program.getScope().toStringVars(program, false, false));
|
||||
success &= helper.testOutput(baseFileName, ".cfg", program.prettyControlFlowGraph());
|
||||
success &= helper.testOutput(baseFileName, ".log", program.getLog().toString());
|
||||
if(!success) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user