1
0
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:
Jesper Gravgaard 2020-02-25 21:38:29 +01:00
parent 7dacbb2c75
commit 827f63c315
9 changed files with 101 additions and 44 deletions

View File

@ -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.
*

View File

@ -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);

View File

@ -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();

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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