mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-11-23 08:32:39 +00:00
Added support for full var_models and var_models with default setting applied pre/post.
This commit is contained in:
parent
7dacbb2c75
commit
827f63c315
@ -1,6 +1,5 @@
|
||||
package dk.camelot64.kickc.model;
|
||||
|
||||
import dk.camelot64.kickc.CompileLog;
|
||||
import dk.camelot64.kickc.model.symbols.*;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypePointer;
|
||||
@ -51,24 +50,6 @@ public class VariableBuilder {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public static VariableBuilderConfig getDefaultConfig(CompileLog log) {
|
||||
VariableBuilderConfig config = new VariableBuilderConfig();
|
||||
|
||||
//config.addSetting("ssa_mem", log, null);
|
||||
//config.addSetting("pointer_ssa_zp", log, null);
|
||||
//config.addSetting("array_ma_mem", log, null);
|
||||
//config.addSetting("global_struct_ma_mem", log, null);
|
||||
|
||||
//config.addSetting("ma_mem", log, null);
|
||||
//config.addSetting("pointer_ma_zp", log, null);
|
||||
//config.addSetting("parameter_ssa_mem", log, null);
|
||||
|
||||
config.addSetting("ssa_zp", log, null);
|
||||
config.addSetting("array_ma_mem", log, null);
|
||||
config.addSetting("global_struct_ma_mem", log, null);
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the variable with the properties derived from type, scope, directives and configuration.
|
||||
*
|
||||
|
@ -10,20 +10,70 @@ import java.util.*;
|
||||
* Holds settings specified using <code>#pragma var_model(...)</code>
|
||||
* The parameters to the pragma has the form <i>scope</i>_<i>type</i>_<i>optimization</i>_<i>memoryarea</i>.
|
||||
* <ul>
|
||||
* <li><i>scope</i> is one of <i>global</i>, <i>local</i></li>
|
||||
* <li><i>scope</i> is one of <i>global</i>, <i>local</i> or <i>parameter</i></li>
|
||||
* <li><i>type</i> is one of <i>struct</i>, <i>array</i>, <i>integer</i>, <i>pointer</i></li>
|
||||
* <li><i>optimization</i> is one of <i>ma</i> (meaning multiple-assignment or load/store), <i>ssa</i> (meaning single-static-assignment)</li>
|
||||
* <li><i>memoryarea</i> is one of <i>zp</i> (meaning zeropage), <i>mem</i> (meaning main memory)</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* For instance the parameter <i>local_pointer_ssa_zp</i> specifies that local pointer variables must be SSA-optimized and placed on zeropage.
|
||||
* Multiple parameters can be added to the pragma to apply settings for many types/scopes. All applied parameters are processed in order potentially overwriting each other.
|
||||
* </p><p>
|
||||
* The scope or type sub-element of the pragma parameter can be left out to apply to all scopes/types.
|
||||
* For instance the parameter <i>pointer_ssa_zp</i> specifies that all pointer variables regardless of scope must be SSA-optimized and placed on zeropage.
|
||||
* <p>
|
||||
* Multiple parameters can be added to the pragma to apply settings for many types/scopes.
|
||||
* For instance the parameter <i>integer_ssa_mem</i> specifies that all integer variables regardless of scope must be SSA-optimized and placed in main memory.
|
||||
* </p><p>
|
||||
* Optimization or memoryarea can also be left out to only change that one setting for the scope/type combinations.
|
||||
* For instance the parameter <i>parameter_ssa</i> specifies that all parameters must be single-static-assignment but does not specify what memory area they should be placed in.
|
||||
* </p><p>
|
||||
* If the very first parameter is <i>full</i> no default settings are applied. This means the parameters must configure all scopes/types.
|
||||
* If the first parameter is not <i>full</i> then default settings are automatically added before and after the settings passed as parameters.
|
||||
* The default settings are
|
||||
* <ul>
|
||||
* <li><i>ssa_zp</i> Applied before the passed parameters (defaulting everything to single static assignment on zeropage)</li>
|
||||
* <li>... The passed parameters are then applied modifying the default</li>
|
||||
* <li><i>array_ma_mem</i> Applied after the passed parameters (forcing arrays to load/store in main-memory)</li>
|
||||
* <li><i>global_struct_ma_mem</i> Applied after the passed parameters (forcing global structs to load/store in main-memory)</li>
|
||||
* <li><i>parameter_ssa</i> Applied after the passed parameters (forcing parameters to single static assignment)</li>
|
||||
* <li><i>pointer_zp</i> Applied after the passed parameters (forcing pointers to zeropage)</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*/
|
||||
public class VariableBuilderConfig {
|
||||
|
||||
/** Setting specifying that the Variable Builder config is "full" and the default pre/post should not be applied. */
|
||||
public static final String SETTING_FULL = "full";
|
||||
|
||||
/**
|
||||
* Apply any default pre configuration of the variable builder configuration.
|
||||
* Done as the first step when initializing a variable builder configuration
|
||||
* @param config The variable builder configuration
|
||||
* @param log The compile log
|
||||
*/
|
||||
public static void defaultPreConfig(VariableBuilderConfig config, CompileLog log) {
|
||||
config.addSetting("ssa_zp", log, StatementSource.NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply any default post configuration of the variable builder configuration.
|
||||
* Done as the last step when initializing a variable builder configuration
|
||||
* @param config The variable builder configuration
|
||||
* @param log The compile log
|
||||
*/
|
||||
public static void defaultPostConfig(VariableBuilderConfig config, CompileLog log) {
|
||||
// Arrays are always load/store variables in main memory
|
||||
// TODO: Theoretically some program may want an array on ZP. How to support that?
|
||||
config.addSetting("array_ma_mem", log, StatementSource.NONE);
|
||||
// Global struct values are always load/store variables in main memory
|
||||
// TODO: Global structs can be SSA (and then unwound) which can optimize some programs. How to support that?
|
||||
config.addSetting("global_struct_ma_mem", log, StatementSource.NONE);
|
||||
// Parameters are always passed using single-static-assignment
|
||||
// TODO: Compilation Unit support will require parameters that are not SSA. How to specify that?
|
||||
config.addSetting("parameter_ssa", log, StatementSource.NONE);
|
||||
// Pointers are always on zeropage
|
||||
// TODO: Pointers can technically exist in main-memory and be moved to ZP on every use. How to specify that?
|
||||
config.addSetting("pointer_zp", log, StatementSource.NONE);
|
||||
}
|
||||
|
||||
/** The different scopes. */
|
||||
public enum Scope {
|
||||
LOCAL, GLOBAL, PARAMETER, MEMBER
|
||||
@ -89,7 +139,7 @@ public class VariableBuilderConfig {
|
||||
*/
|
||||
private Map<ScopeType, Setting> settings;
|
||||
|
||||
VariableBuilderConfig() {
|
||||
public VariableBuilderConfig() {
|
||||
this.settings = new HashMap<>();
|
||||
}
|
||||
|
||||
@ -99,10 +149,14 @@ public class VariableBuilderConfig {
|
||||
List<Type> types = getTypes(paramElements);
|
||||
Optimization optimization = getOptimization(paramElements);
|
||||
MemoryArea memoryArea = getMemoryArea(paramElements);
|
||||
if(memoryArea == null || optimization == null || paramElements.size() > 0)
|
||||
if((memoryArea == null && optimization == null) || paramElements.size() > 0)
|
||||
throw new CompileError("Warning: Malformed var_model parameter " + pragmaParam, statementSource);
|
||||
for(Scope scope : scopes) {
|
||||
for(Type type : types) {
|
||||
if(memoryArea == null)
|
||||
memoryArea = getSetting(scope, type).memoryArea;
|
||||
if(optimization == null)
|
||||
optimization = getSetting(scope, type).optimization;
|
||||
settings.put(new ScopeType(scope, type), new Setting(scope, type, memoryArea, optimization));
|
||||
}
|
||||
}
|
||||
@ -166,6 +220,8 @@ public class VariableBuilderConfig {
|
||||
* @return The matched memory area.
|
||||
*/
|
||||
private MemoryArea getMemoryArea(List<String> paramElements) {
|
||||
if(paramElements.size() == 0)
|
||||
return null;
|
||||
final String paramElement = paramElements.get(0);
|
||||
if(paramElement.equals("mem")) {
|
||||
paramElements.remove(0);
|
||||
@ -185,6 +241,8 @@ public class VariableBuilderConfig {
|
||||
* @return The matched optimization.
|
||||
*/
|
||||
private Optimization getOptimization(List<String> paramElements) {
|
||||
if(paramElements.size() == 0)
|
||||
return null;
|
||||
final String paramElement = paramElements.get(0);
|
||||
if(paramElement.equals("ssa")) {
|
||||
paramElements.remove(0);
|
||||
|
@ -33,6 +33,9 @@ public class StatementSource implements Serializable {
|
||||
this.stopIndex = stopIndex;
|
||||
}
|
||||
|
||||
/** An empty statement source. */
|
||||
public static StatementSource NONE = new StatementSource(null, null, null, 0, 0);
|
||||
|
||||
public StatementSource(Token tokenStart, Token tokenStop) {
|
||||
if(tokenStart != null) {
|
||||
this.startIndex = tokenStart.getStartIndex();
|
||||
|
@ -58,7 +58,10 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
this.sequence = program.getStatementSequence();
|
||||
this.scopeStack = new Stack<>();
|
||||
this.defaultMemoryArea = Variable.MemoryArea.ZEROPAGE_MEMORY;
|
||||
this.variableBuilderConfig = VariableBuilder.getDefaultConfig(program.getLog());
|
||||
VariableBuilderConfig config = new VariableBuilderConfig();
|
||||
VariableBuilderConfig.defaultPreConfig(config, program.getLog());
|
||||
VariableBuilderConfig.defaultPostConfig(config, program.getLog());
|
||||
this.variableBuilderConfig = config;
|
||||
scopeStack.push(program.getScope());
|
||||
}
|
||||
|
||||
@ -104,10 +107,22 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
|
||||
@Override
|
||||
public Object visitGlobalDirectiveVarModel(KickCParser.GlobalDirectiveVarModelContext ctx) {
|
||||
this.variableBuilderConfig = VariableBuilder.getDefaultConfig(program.getLog());
|
||||
for(TerminalNode varModel : ctx.NAME()) {
|
||||
variableBuilderConfig.addSetting(varModel.getText(), program.getLog(), new StatementSource(ctx));
|
||||
List<TerminalNode> settings = new ArrayList<>(ctx.NAME());
|
||||
// Detect if the first setting is "full"
|
||||
boolean full = false;
|
||||
if(settings.size() > 0 && settings.get(0).getText().equals(VariableBuilderConfig.SETTING_FULL)) {
|
||||
full = true;
|
||||
settings = settings.subList(1, settings.size());
|
||||
}
|
||||
VariableBuilderConfig config = new VariableBuilderConfig();
|
||||
if(!full)
|
||||
VariableBuilderConfig.defaultPreConfig(config, program.getLog());
|
||||
for(TerminalNode varModel : settings) {
|
||||
config.addSetting(varModel.getText(), program.getLog(), new StatementSource(ctx));
|
||||
}
|
||||
if(!full)
|
||||
VariableBuilderConfig.defaultPostConfig(config, program.getLog());
|
||||
this.variableBuilderConfig = config;
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -583,7 +598,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
VariableBuilder varBuilder = new VariableBuilder(varName, getCurrentScope(), false, declVarType, declArraySpec, declVarDirectives, currentDataSegment, variableBuilderConfig);
|
||||
Variable variable = varBuilder.build();
|
||||
boolean isPermanent = ScopeRef.ROOT.equals(variable.getScope().getRef()) || variable.isPermanent();
|
||||
if(variable.isKindConstant() || (isPermanent && variable.isKindLoadStore() && Variable.MemoryArea.MAIN_MEMORY.equals(variable.getMemoryArea()) && initValue instanceof ConstantValue && !declVarStructMember && variable.getRegister()==null)) {
|
||||
if(variable.isKindConstant() || (isPermanent && variable.isKindLoadStore() && Variable.MemoryArea.MAIN_MEMORY.equals(variable.getMemoryArea()) && initValue instanceof ConstantValue && !declVarStructMember && variable.getRegister() == null)) {
|
||||
// Set initial value
|
||||
ConstantValue constInitValue = getConstInitValue(initValue, initializer, statementSource);
|
||||
variable.setInitValue(constInitValue);
|
||||
|
@ -45,7 +45,7 @@ public class TestPrograms {
|
||||
|
||||
@Test
|
||||
public void testVarModelMaMem4() throws IOException, URISyntaxException {
|
||||
compileAndCompare("varmodel-ma_mem-4", log());
|
||||
compileAndCompare("varmodel-ma_mem-4");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Demonstrates problem with __ma coalescing
|
||||
// c1a is erroneously zp-coalesced with c1A
|
||||
|
||||
#pragma var_model(ma_mem, pointer_ma_zp, parameter_ssa_mem)
|
||||
#pragma var_model(ma_mem)
|
||||
|
||||
const char* SCREEN = 0x0400;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Test memory model multiple-assignment/main memory for all non-pointer variables
|
||||
|
||||
#pragma var_model(ma_mem, pointer_ma_zp)
|
||||
#pragma var_model(ma_mem)
|
||||
|
||||
void main() {
|
||||
// A local pointer
|
||||
|
@ -5,7 +5,7 @@ void main() {
|
||||
model_ssa_zp();
|
||||
}
|
||||
|
||||
#pragma var_model(ma_mem)
|
||||
#pragma var_model(full, ma_mem)
|
||||
|
||||
void model_ma_mem() {
|
||||
// A local pointer
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Test memory model multiple-assignment/main memory for all variables (here local variables)
|
||||
|
||||
#pragma var_model(ma_mem)
|
||||
#pragma var_model(full, ma_mem)
|
||||
|
||||
void main() {
|
||||
// A local pointer
|
||||
|
Loading…
Reference in New Issue
Block a user