mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-11-27 04:49:27 +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;
|
package dk.camelot64.kickc.model;
|
||||||
|
|
||||||
import dk.camelot64.kickc.CompileLog;
|
|
||||||
import dk.camelot64.kickc.model.symbols.*;
|
import dk.camelot64.kickc.model.symbols.*;
|
||||||
import dk.camelot64.kickc.model.types.SymbolType;
|
import dk.camelot64.kickc.model.types.SymbolType;
|
||||||
import dk.camelot64.kickc.model.types.SymbolTypePointer;
|
import dk.camelot64.kickc.model.types.SymbolTypePointer;
|
||||||
@ -51,24 +50,6 @@ public class VariableBuilder {
|
|||||||
this.config = config;
|
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.
|
* 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>
|
* 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>.
|
* The parameters to the pragma has the form <i>scope</i>_<i>type</i>_<i>optimization</i>_<i>memoryarea</i>.
|
||||||
* <ul>
|
* <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>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>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>
|
* <li><i>memoryarea</i> is one of <i>zp</i> (meaning zeropage), <i>mem</i> (meaning main memory)</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* <p>
|
* <p>
|
||||||
* For instance the parameter <i>local_pointer_ssa_zp</i> specifies that local pointer variables must be SSA-optimized and placed on zeropage.
|
* 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.
|
* 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.
|
* 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><p>
|
||||||
* Multiple parameters can be added to the pragma to apply settings for many types/scopes.
|
* 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 {
|
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. */
|
/** The different scopes. */
|
||||||
public enum Scope {
|
public enum Scope {
|
||||||
LOCAL, GLOBAL, PARAMETER, MEMBER
|
LOCAL, GLOBAL, PARAMETER, MEMBER
|
||||||
@ -89,7 +139,7 @@ public class VariableBuilderConfig {
|
|||||||
*/
|
*/
|
||||||
private Map<ScopeType, Setting> settings;
|
private Map<ScopeType, Setting> settings;
|
||||||
|
|
||||||
VariableBuilderConfig() {
|
public VariableBuilderConfig() {
|
||||||
this.settings = new HashMap<>();
|
this.settings = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,10 +149,14 @@ public class VariableBuilderConfig {
|
|||||||
List<Type> types = getTypes(paramElements);
|
List<Type> types = getTypes(paramElements);
|
||||||
Optimization optimization = getOptimization(paramElements);
|
Optimization optimization = getOptimization(paramElements);
|
||||||
MemoryArea memoryArea = getMemoryArea(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);
|
throw new CompileError("Warning: Malformed var_model parameter " + pragmaParam, statementSource);
|
||||||
for(Scope scope : scopes) {
|
for(Scope scope : scopes) {
|
||||||
for(Type type : types) {
|
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));
|
settings.put(new ScopeType(scope, type), new Setting(scope, type, memoryArea, optimization));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -166,6 +220,8 @@ public class VariableBuilderConfig {
|
|||||||
* @return The matched memory area.
|
* @return The matched memory area.
|
||||||
*/
|
*/
|
||||||
private MemoryArea getMemoryArea(List<String> paramElements) {
|
private MemoryArea getMemoryArea(List<String> paramElements) {
|
||||||
|
if(paramElements.size() == 0)
|
||||||
|
return null;
|
||||||
final String paramElement = paramElements.get(0);
|
final String paramElement = paramElements.get(0);
|
||||||
if(paramElement.equals("mem")) {
|
if(paramElement.equals("mem")) {
|
||||||
paramElements.remove(0);
|
paramElements.remove(0);
|
||||||
@ -185,6 +241,8 @@ public class VariableBuilderConfig {
|
|||||||
* @return The matched optimization.
|
* @return The matched optimization.
|
||||||
*/
|
*/
|
||||||
private Optimization getOptimization(List<String> paramElements) {
|
private Optimization getOptimization(List<String> paramElements) {
|
||||||
|
if(paramElements.size() == 0)
|
||||||
|
return null;
|
||||||
final String paramElement = paramElements.get(0);
|
final String paramElement = paramElements.get(0);
|
||||||
if(paramElement.equals("ssa")) {
|
if(paramElement.equals("ssa")) {
|
||||||
paramElements.remove(0);
|
paramElements.remove(0);
|
||||||
|
@ -33,6 +33,9 @@ public class StatementSource implements Serializable {
|
|||||||
this.stopIndex = stopIndex;
|
this.stopIndex = stopIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** An empty statement source. */
|
||||||
|
public static StatementSource NONE = new StatementSource(null, null, null, 0, 0);
|
||||||
|
|
||||||
public StatementSource(Token tokenStart, Token tokenStop) {
|
public StatementSource(Token tokenStart, Token tokenStop) {
|
||||||
if(tokenStart != null) {
|
if(tokenStart != null) {
|
||||||
this.startIndex = tokenStart.getStartIndex();
|
this.startIndex = tokenStart.getStartIndex();
|
||||||
|
@ -58,7 +58,10 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
this.sequence = program.getStatementSequence();
|
this.sequence = program.getStatementSequence();
|
||||||
this.scopeStack = new Stack<>();
|
this.scopeStack = new Stack<>();
|
||||||
this.defaultMemoryArea = Variable.MemoryArea.ZEROPAGE_MEMORY;
|
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());
|
scopeStack.push(program.getScope());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,10 +107,22 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitGlobalDirectiveVarModel(KickCParser.GlobalDirectiveVarModelContext ctx) {
|
public Object visitGlobalDirectiveVarModel(KickCParser.GlobalDirectiveVarModelContext ctx) {
|
||||||
this.variableBuilderConfig = VariableBuilder.getDefaultConfig(program.getLog());
|
List<TerminalNode> settings = new ArrayList<>(ctx.NAME());
|
||||||
for(TerminalNode varModel : ctx.NAME()) {
|
// Detect if the first setting is "full"
|
||||||
variableBuilderConfig.addSetting(varModel.getText(), program.getLog(), new StatementSource(ctx));
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -583,7 +598,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
VariableBuilder varBuilder = new VariableBuilder(varName, getCurrentScope(), false, declVarType, declArraySpec, declVarDirectives, currentDataSegment, variableBuilderConfig);
|
VariableBuilder varBuilder = new VariableBuilder(varName, getCurrentScope(), false, declVarType, declArraySpec, declVarDirectives, currentDataSegment, variableBuilderConfig);
|
||||||
Variable variable = varBuilder.build();
|
Variable variable = varBuilder.build();
|
||||||
boolean isPermanent = ScopeRef.ROOT.equals(variable.getScope().getRef()) || variable.isPermanent();
|
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
|
// Set initial value
|
||||||
ConstantValue constInitValue = getConstInitValue(initValue, initializer, statementSource);
|
ConstantValue constInitValue = getConstInitValue(initValue, initializer, statementSource);
|
||||||
variable.setInitValue(constInitValue);
|
variable.setInitValue(constInitValue);
|
||||||
|
@ -45,7 +45,7 @@ public class TestPrograms {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testVarModelMaMem4() throws IOException, URISyntaxException {
|
public void testVarModelMaMem4() throws IOException, URISyntaxException {
|
||||||
compileAndCompare("varmodel-ma_mem-4", log());
|
compileAndCompare("varmodel-ma_mem-4");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Demonstrates problem with __ma coalescing
|
// Demonstrates problem with __ma coalescing
|
||||||
// c1a is erroneously zp-coalesced with c1A
|
// 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;
|
const char* SCREEN = 0x0400;
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// Test memory model multiple-assignment/main memory for all non-pointer variables
|
// 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() {
|
void main() {
|
||||||
// A local pointer
|
// A local pointer
|
||||||
|
@ -5,7 +5,7 @@ void main() {
|
|||||||
model_ssa_zp();
|
model_ssa_zp();
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma var_model(ma_mem)
|
#pragma var_model(full, ma_mem)
|
||||||
|
|
||||||
void model_ma_mem() {
|
void model_ma_mem() {
|
||||||
// A local pointer
|
// A local pointer
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// Test memory model multiple-assignment/main memory for all variables (here local variables)
|
// 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() {
|
void main() {
|
||||||
// A local pointer
|
// A local pointer
|
||||||
|
Loading…
Reference in New Issue
Block a user