1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-04-08 14:37:40 +00:00

Changed declared const handling.

This commit is contained in:
jespergravgaard 2019-11-03 10:48:40 +01:00
parent d9582d6b0f
commit 5839a98c60
23 changed files with 433 additions and 59 deletions

View File

@ -113,11 +113,11 @@ public class DirectiveParserContext {
public void applyDirectives(Variable lValue, boolean isParameter, List<Directive> sourceDirectives, StatementSource source) {
DirectiveType directiveType = DirectiveType.getFor(lValue.getType());
if(hasDirective(Directive.Const.class, sourceDirectives))
lValue.setConstantDeclaration(Variable.ConstantDeclaration.CONST);
lValue.setDeclaredConst(true);
if(directiveType.equals(DirectiveType.ARRAY))
lValue.setConstantDeclaration(Variable.ConstantDeclaration.CONST);
lValue.setDeclaredConst(true);
if(hasDirective(Directive.NotConst.class, sourceDirectives))
lValue.setConstantDeclaration(Variable.ConstantDeclaration.NOT_CONST);
lValue.setDeclaredNotConst(true);
if(hasDirective(Directive.Volatile.class, sourceDirectives))
lValue.setDeclaredVolatile(true);
if(hasDirective(Directive.Export.class, sourceDirectives))

View File

@ -30,7 +30,7 @@ public class OperatorDivide extends OperatorBinary {
public SymbolType inferType(SymbolType left, SymbolType right) {
if(left instanceof SymbolTypePointer) {
if(SymbolType.isInteger(right)) {
return left;
return new SymbolTypePointer(((SymbolTypePointer) left).getElementType());
} else {
throw new NoMatchingType("Cannot divide pointer by "+right.toString());
}

View File

@ -24,7 +24,7 @@ public class OperatorMultiply extends OperatorBinary {
public SymbolType inferType(SymbolType left, SymbolType right) {
if(left instanceof SymbolTypePointer) {
if(SymbolType.BYTE.equals(right) || SymbolType.WORD.equals(right) || SymbolType.NUMBER.equals(right)) {
return left;
return new SymbolTypePointer(((SymbolTypePointer) left).getElementType());
} else {
throw new NoMatchingType("Cannot multiply pointer by "+right.toString());
}

View File

@ -20,7 +20,7 @@ public class OperatorSetHigh extends OperatorBinary {
@Override
public SymbolType inferType(SymbolType left, SymbolType right) {
if(left instanceof SymbolTypePointer) {
return left;
return new SymbolTypePointer(((SymbolTypePointer) left).getElementType());
} else if(SymbolType.BYTE.equals(left)) {
return SymbolType.WORD;
} else if(SymbolType.SBYTE.equals(left)) {

View File

@ -20,7 +20,7 @@ public class OperatorSetLow extends OperatorBinary {
@Override
public SymbolType inferType(SymbolType left, SymbolType right) {
if(left instanceof SymbolTypePointer) {
return left;
return new SymbolTypePointer(((SymbolTypePointer) left).getElementType());
}
if(SymbolType.WORD.equals(left)) {
return SymbolType.WORD;

View File

@ -35,6 +35,15 @@ public class Variable implements Symbol {
/** The storage strategy for the variable. */
private Kind kind;
/** True of the variable is a compile-time constant (previously ConstantVar) [ALL] */
private boolean isConstant;
/** Specifies that the variable is declared as const */
private boolean declaredConst;
/** Specifies that the variable is declared as __notconst */
private boolean declaredNotConst;
/** The local name of the variable. [ALL] */
private String name;
@ -53,12 +62,6 @@ public class Variable implements Symbol {
/** true if the symbol type is inferred (not declared) [kind:INTERMEDIATE] TODO: Collapse with kind==INTERMEDIATE? */
private boolean inferredType;
/** True of the variable is a compile-time constant (previously ConstantVar) [ALL] */
private boolean isConstant;
/** Specifies that the variable is declared a constant. It will be replaced by a ConstantVar when possible. [ALL] TODO: Collapse with isConstant?*/
private ConstantDeclaration constantDeclaration;
/** Specifies that the variable must be aligned in memory. Only allowed for arrays & strings. [Only Variables in memory and arrays] */
private Integer declaredAlignment;
@ -98,11 +101,6 @@ public class Variable implements Symbol {
/** If the variable is assigned to a specific "register", this contains the register. If null the variable has no allocation (yet). Constants are never assigned to registers. [Only variables - not constants and not PHI masters] */
private Registers.Register allocation;
/** Specifies whether the symbol is declared to be constant, never constant or maybe constant. */
public enum ConstantDeclaration {
CONST, NOT_CONST, MAYBE_CONST
}
/** Memory area used for storing the variable (if is is stored in memory). */
public enum MemoryArea {
ZEROPAGE_MEMORY, MAIN_MEMORY
@ -124,7 +122,6 @@ public class Variable implements Symbol {
this.dataSegment = dataSegment;
this.kind = Kind.CONSTANT;
this.memoryArea = MemoryArea.MAIN_MEMORY;
this.constantDeclaration = ConstantDeclaration.MAYBE_CONST;
this.constantValue = value;
this.inferredType = false;
this.comments = new ArrayList<>();
@ -148,7 +145,6 @@ public class Variable implements Symbol {
this.dataSegment = dataSegment;
this.kind = kind;
this.memoryArea = memoryArea;
this.constantDeclaration = ConstantDeclaration.MAYBE_CONST;
if(Kind.PHI_MASTER.equals(kind))
this.nextPhiVersionNumber = 0;
this.inferredType = false;
@ -168,7 +164,8 @@ public class Variable implements Symbol {
this.setDeclaredAlignment(phiMaster.getDeclaredAlignment());
this.setDeclaredAsRegister(phiMaster.isDeclaredAsRegister());
this.setDeclaredNotRegister(phiMaster.isDeclaredAsNotRegister());
this.setConstantDeclaration(phiMaster.getConstantDeclaration());
this.setDeclaredConst(phiMaster.isDeclaredConst());
this.setDeclaredNotConst(phiMaster.isDeclaredNotConst());
this.setDeclaredRegister(phiMaster.getDeclaredRegister());
this.setDeclaredVolatile(phiMaster.isDeclaredVolatile());
this.setDeclaredExport(phiMaster.isDeclaredExport());
@ -178,6 +175,7 @@ public class Variable implements Symbol {
}
public Kind getKind() {
return kind;
}
@ -357,20 +355,20 @@ public class Variable implements Symbol {
}
}
public void setConstantDeclaration(ConstantDeclaration constantDeclaration) {
this.constantDeclaration = constantDeclaration;
public boolean isDeclaredConst() {
return declaredConst;
}
public ConstantDeclaration getConstantDeclaration() {
return constantDeclaration;
public void setDeclaredConst(boolean declaredConst) {
this.declaredConst = declaredConst;
}
public boolean isDeclaredConstant() {
return ConstantDeclaration.CONST.equals(constantDeclaration);
public boolean isDeclaredNotConst() {
return declaredNotConst;
}
public boolean isDeclaredNotConstant() {
return ConstantDeclaration.NOT_CONST.equals(constantDeclaration);
public void setDeclaredNotConst(boolean declaredNotConst) {
this.declaredNotConst = declaredNotConst;
}
public Integer getDeclaredAlignment() {

View File

@ -622,7 +622,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
Variable lValue = getCurrentScope().addVariable(kind, varName, type, defaultMemoryArea, currentDataSegment);
// Add directives
directiveContext.applyDirectives(lValue, false, directives, new StatementSource(ctx));
if(lValue.isDeclaredConstant()) {
if(lValue.isDeclaredConst()) {
// Add comments to constant
lValue.setComments(ensureUnusedComments(comments));
}

View File

@ -18,7 +18,7 @@ public class Pass1AssertNoConstParams extends Pass1Base {
public boolean step() {
for(Procedure procedure : getScope().getAllProcedures(true)) {
for(Variable parameter : procedure.getParameters()) {
if(parameter.isDeclaredConstant()) {
if(parameter.isDeclaredConst()) {
throw new CompileError("Error! Const parameters not supported "+parameter.getName()+" in "+ procedure.getFullName()+"()");
}
}

View File

@ -28,8 +28,8 @@ public class Pass1EarlyConstantIdentification extends Pass1Base {
Collection<SymbolVariableRef> earlyConstants = new ArrayList<>();
for(Variable variable : getProgram().getScope().getAllVariables(true)) {
SymbolVariableRef variableRef = variable.getRef();
if(!variable.isDeclaredConstant() && !variable.isVolatile() && !variableRef.isIntermediate()) {
if(variable.isDeclaredNotConstant())
if(!variable.isDeclaredConst() && !variable.isVolatile() && !variableRef.isIntermediate()) {
if(variable.isDeclaredNotConst())
// Skip explicit non-constants
continue;
if(!isParameter(variableRef)) {

View File

@ -79,7 +79,7 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
Collection<SymbolVariableRef> earlyIdentifiedConstants = getProgram().getEarlyIdentifiedConstants();
Variable assignedVar = getScope().getVariable(lValueRef);
if(assignedVar.isKindPhiMaster()) {
if(assignedVar.isDeclaredConstant() || earlyIdentifiedConstants.contains(assignedVar.getRef()))
if(assignedVar.isDeclaredConst() || earlyIdentifiedConstants.contains(assignedVar.getRef()))
throw new InternalError("Error! Constants can not be versioned ", source);
Variable version = assignedVar.createVersion();
programLValue.set(version.getRef());
@ -171,7 +171,7 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
if(rValueVar.isKindPhiMaster()) {
// rValue needs versioning - look for version in statements
Variable rSymbol = rValueVar;
if(rSymbol.isDeclaredConstant() || earlyIdentifiedConstants.contains(rSymbol.getRef())) {
if(rSymbol.isDeclaredConst() || earlyIdentifiedConstants.contains(rSymbol.getRef())) {
// A constant - find the single created version
Scope scope = rSymbol.getScope();
Collection<Variable> versions = scope.getVersions(rSymbol);

View File

@ -303,7 +303,8 @@ public class Pass1ProcedureInline extends Pass1Base {
Variable inlineVar = callScope.addVariablePhiMaster(inlineVarName, procSymbol.getType(), procVar.getMemoryArea(), procVar.getDataSegment());
inlineVar.setInferredType(procVar.isInferredType());
inlineVar.setDeclaredAlignment(procVar.getDeclaredAlignment());
inlineVar.setConstantDeclaration(procVar.getConstantDeclaration());
inlineVar.setDeclaredConst(procVar.isDeclaredConst());
inlineVar.setDeclaredNotConst(procVar.isDeclaredNotConst());
inlineVar.setDeclaredAsRegister(procVar.isDeclaredAsRegister());
inlineVar.setDeclaredNotRegister(procVar.isDeclaredAsNotRegister());
inlineVar.setDeclaredRegister(procVar.getDeclaredRegister());

View File

@ -78,7 +78,8 @@ public class Pass1UnwindBlockScopes extends Pass1Base {
Variable var = (Variable) symbol;
Variable unwound = procedure.addVariablePhiMaster(name, symbol.getType(), var.getMemoryArea(), var.getDataSegment());
unwound.setDeclaredAlignment(var.getDeclaredAlignment());
unwound.setConstantDeclaration(var.getConstantDeclaration());
unwound.setDeclaredConst(var.isDeclaredConst());
unwound.setDeclaredNotConst((var.isDeclaredNotConst()));
unwound.setDeclaredVolatile(var.isDeclaredVolatile());
unwound.setInferredVolatile(var.isInferredVolatile());
unwound.setDeclaredRegister((var.getDeclaredRegister()));

View File

@ -223,7 +223,8 @@ public class Pass1UnwindStructValues extends Pass1Base {
}
memberVariable.setDeclaredVolatile(variable.isDeclaredVolatile());
memberVariable.setInferredVolatile(variable.isInferredVolatile());
memberVariable.setConstantDeclaration(variable.getConstantDeclaration());
memberVariable.setDeclaredConst(variable.isDeclaredConst());
memberVariable.setDeclaredNotConst(variable.isDeclaredNotConst());
memberVariable.setDeclaredExport(variable.isDeclaredExport());
memberVariable.setKind(variable.getKind());
if(memberVariable.getType() instanceof SymbolTypePointer) {

View File

@ -420,7 +420,7 @@ public class Pass2AliasElimination extends Pass2SsaOptimization {
String name;
int score;
Variable variable = scope.getVariable(var);
if(variable.isDeclaredConstant() || variable.isKindConstant()) {
if(variable.isDeclaredConst() || variable.isKindConstant()) {
name = var.getFullNameUnversioned();
score = 100;
} else if(var.isVersion()) {

View File

@ -152,7 +152,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
if(lValue instanceof VariableRef) {
VariableRef varRef = (VariableRef) lValue;
Variable var = getScope().getVariable(varRef);
if(var.isVolatile() || var.isDeclaredNotConstant() || var.isKindLoadStore())
if(var.isVolatile() || var.isDeclaredNotConst() || var.isKindLoadStore())
// Do not examine volatiles and non-versioned variables
continue;
ConstantValue constant = getConstant(assignment.getrValue2());
@ -168,7 +168,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
if(getConstant(phiRValue.getrValue()) != null) {
VariableRef varRef = phiVariable.getVariable();
Variable var = getScope().getVariable(varRef);
if(var.isVolatile() || var.isDeclaredNotConstant() || var.isKindLoadStore())
if(var.isVolatile() || var.isDeclaredNotConst() || var.isKindLoadStore())
// Do not examine volatiles and non-versioned variables
continue;
ConstantValue constant = getConstant(phiRValue.getrValue());
@ -182,7 +182,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
// Look for constants among non-versioned variables
for(Variable variable : getScope().getAllVariables(true)) {
if(variable.isVolatile() || variable.isDeclaredNotConstant() || !variable.isKindLoadStore())
if(variable.isVolatile() || variable.isDeclaredNotConst() || !variable.isKindLoadStore())
// Do not examine volatiles, non-constants or versioned variables
continue;
List<StatementLValue> assignments = getGraph().getAssignments(variable.getRef());

View File

@ -132,16 +132,6 @@ public class PassNTypeInference extends Pass2SsaOptimization {
if(SymbolType.VAR.equals(symbol.getType()) || SymbolType.NUMBER.equals(symbol.getType())|| SymbolType.UNUMBER.equals(symbol.getType()) || SymbolType.SNUMBER.equals(symbol.getType())) {
SymbolType type = SymbolTypeInference.inferType(programScope, new AssignmentRValue(assignment));
setInferedType(program, assignment, symbol, type);
// If the type is an array or a string the symbol is constant
if(symbol.getType() instanceof SymbolTypeArray) {
symbol.setConstantDeclaration(Variable.ConstantDeclaration.CONST);
symbol.setKind(Variable.Kind.CONSTANT);
symbol.setMemoryArea(Variable.MemoryArea.MAIN_MEMORY);
} else if(SymbolType.STRING.equals(symbol.getType())) {
symbol.setConstantDeclaration(Variable.ConstantDeclaration.CONST);
symbol.setKind(Variable.Kind.CONSTANT);
symbol.setMemoryArea(Variable.MemoryArea.MAIN_MEMORY);
}
}
}
}

View File

@ -37,6 +37,11 @@ public class TestPrograms {
public TestPrograms() {
}
@Test
public void testConstDeclaration() throws IOException, URISyntaxException {
compileAndCompare("const-declaration", log());
}
@Test
public void testStaticRegisterOptimizationProblem() throws IOException, URISyntaxException {
compileAndCompare("static-register-optimization-problem");

View File

@ -0,0 +1,17 @@
// Tests a number of constant declarations
const char* SCREEN = 0x0400;
const char LINE_LEN = 40;
const char MARGIN_TOP = 4;
const char MARGIN_LEFT = 4;
const unsigned int OFFSET = 40*5+5;
const char* BODY1 = SCREEN+MARGIN_TOP*LINE_LEN+MARGIN_LEFT;
const char* BODY2 = SCREEN+OFFSET;
void main() {
*BODY1 = '*';
*BODY2 = '*';
}

View File

@ -0,0 +1,16 @@
// Tests a number of constant declarations
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.label SCREEN = $400
.const LINE_LEN = $28
.const MARGIN_TOP = 4
.const MARGIN_LEFT = 4
.const OFFSET = $28*5+5
.label BODY2 = SCREEN+OFFSET
main: {
lda #'*'
sta SCREEN+MARGIN_TOP*LINE_LEN+MARGIN_LEFT
sta BODY2
rts
}

View File

@ -0,0 +1,18 @@
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
(void()) main()
main: scope:[main] from @1
[4] *((const byte*) SCREEN+(const byte) MARGIN_TOP*(const byte) LINE_LEN+(const byte) MARGIN_LEFT) ← (byte) '*'
[5] *((const byte*) BODY2) ← (byte) '*'
to:main::@return
main::@return: scope:[main] from main
[6] return
to:@return

View File

@ -0,0 +1,315 @@
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(byte*) SCREEN ← ((byte*)) (number) $400
(byte) LINE_LEN ← (number) $28
(byte) MARGIN_TOP ← (number) 4
(byte) MARGIN_LEFT ← (number) 4
(word) OFFSET ← (number) $28*(number) 5+(number) 5
(byte~) $0 ← (byte) MARGIN_TOP * (byte) LINE_LEN
(byte*~) $1 ← (byte*) SCREEN + (byte~) $0
(byte*~) $2 ← (byte*~) $1 + (byte) MARGIN_LEFT
(byte*) BODY1 ← (byte*~) $2
(byte*~) $3 ← (byte*) SCREEN + (word) OFFSET
(byte*) BODY2 ← (byte*~) $3
to:@1
(void()) main()
main: scope:[main] from @1
*((byte*) BODY1) ← (byte) '*'
*((byte*) BODY2) ← (byte) '*'
to:main::@return
main::@return: scope:[main] from main
return
to:@return
@1: scope:[] from @begin
call main
to:@2
@2: scope:[] from @1
to:@end
@end: scope:[] from @2
SYMBOL TABLE SSA
(byte~) $0
(byte*~) $1
(byte*~) $2
(byte*~) $3
(label) @1
(label) @2
(label) @begin
(label) @end
(byte*) BODY1
(byte*) BODY2
(byte) LINE_LEN
(byte) MARGIN_LEFT
(byte) MARGIN_TOP
(word) OFFSET
(byte*) SCREEN
(void()) main()
(label) main::@return
Adding number conversion cast (unumber) $28 in (byte) LINE_LEN ← (number) $28
Adding number conversion cast (unumber) 4 in (byte) MARGIN_TOP ← (number) 4
Adding number conversion cast (unumber) 4 in (byte) MARGIN_LEFT ← (number) 4
Adding number conversion cast (unumber) $28*5+5 in (word) OFFSET ← (number) $28*(number) 5+(number) 5
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast (byte*) SCREEN ← (byte*)(number) $400
Inlining cast (byte) LINE_LEN ← (unumber)(number) $28
Inlining cast (byte) MARGIN_TOP ← (unumber)(number) 4
Inlining cast (byte) MARGIN_LEFT ← (unumber)(number) 4
Inlining cast (word) OFFSET ← (unumber)(number) $28*(number) 5+(number) 5
Successful SSA optimization Pass2InlineCast
Simplifying constant pointer cast (byte*) 1024
Simplifying constant integer cast $28
Simplifying constant integer cast 4
Simplifying constant integer cast 4
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) $28
Finalized unsigned number type (byte) 4
Finalized unsigned number type (byte) 4
Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias (byte*) BODY1 = (byte*~) $2
Alias (byte*) BODY2 = (byte*~) $3
Successful SSA optimization Pass2AliasElimination
Constant right-side identified [4] (word) OFFSET ← (unumber)(number) $28*(number) 5+(number) 5
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte*) SCREEN = (byte*) 1024
Constant (const byte) LINE_LEN = $28
Constant (const byte) MARGIN_TOP = 4
Constant (const byte) MARGIN_LEFT = 4
Constant (const word) OFFSET = (unumber)$28*5+5
Successful SSA optimization Pass2ConstantIdentification
Converting *(pointer+n) to pointer[n] [11] *((byte*) BODY1) ← (byte) '*' -- *($1 + MARGIN_LEFT)
Successful SSA optimization Pass2InlineDerefIdx
Eliminating unused variable (byte*) BODY1 and assignment [2] (byte*) BODY1 ← (byte*~) $1 + (const byte) MARGIN_LEFT
Successful SSA optimization PassNEliminateUnusedVars
Constant right-side identified [0] (byte~) $0 ← (const byte) MARGIN_TOP * (const byte) LINE_LEN
Constant right-side identified [2] (byte*) BODY2 ← (const byte*) SCREEN + (const word) OFFSET
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte) $0 = MARGIN_TOP*LINE_LEN
Constant (const byte*) BODY2 = SCREEN+OFFSET
Successful SSA optimization Pass2ConstantIdentification
Constant right-side identified [0] (byte*~) $1 ← (const byte*) SCREEN + (const byte) $0
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte*) $1 = SCREEN+$0
Successful SSA optimization Pass2ConstantIdentification
Constant inlined $0 = (const byte) MARGIN_TOP*(const byte) LINE_LEN
Constant inlined $1 = (const byte*) SCREEN+(const byte) MARGIN_TOP*(const byte) LINE_LEN
Successful SSA optimization Pass2ConstantInlining
Consolidated array index constant in *(SCREEN+MARGIN_TOP*LINE_LEN+MARGIN_LEFT)
Successful SSA optimization Pass2ConstantAdditionElimination
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @2
Adding NOP phi() at start of @end
CALL GRAPH
Calls in [] to main:2
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
Culled Empty Block (label) @2
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
(void()) main()
main: scope:[main] from @1
[4] *((const byte*) SCREEN+(const byte) MARGIN_TOP*(const byte) LINE_LEN+(const byte) MARGIN_LEFT) ← (byte) '*'
[5] *((const byte*) BODY2) ← (byte) '*'
to:main::@return
main::@return: scope:[main] from main
[6] return
to:@return
VARIABLE REGISTER WEIGHTS
(void()) main()
Initial phi equivalence classes
Complete equivalence classes
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Tests a number of constant declarations
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
.const LINE_LEN = $28
.const MARGIN_TOP = 4
.const MARGIN_LEFT = 4
.const OFFSET = $28*5+5
.label BODY2 = SCREEN+OFFSET
// @begin
__bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [2] call main
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
__bend:
// main
main: {
// [4] *((const byte*) SCREEN+(const byte) MARGIN_TOP*(const byte) LINE_LEN+(const byte) MARGIN_LEFT) ← (byte) '*' -- _deref_pbuc1=vbuc2
lda #'*'
sta SCREEN+MARGIN_TOP*LINE_LEN+MARGIN_LEFT
// [5] *((const byte*) BODY2) ← (byte) '*' -- _deref_pbuc1=vbuc2
lda #'*'
sta BODY2
jmp __breturn
// main::@return
__breturn:
// [6] return
rts
}
// File Data
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [4] *((const byte*) SCREEN+(const byte) MARGIN_TOP*(const byte) LINE_LEN+(const byte) MARGIN_LEFT) ← (byte) '*' [ ] ( main:2 [ ] ) always clobbers reg byte a
Statement [5] *((const byte*) BODY2) ← (byte) '*' [ ] ( main:2 [ ] ) always clobbers reg byte a
REGISTER UPLIFT SCOPES
Uplift Scope [main]
Uplift Scope []
Uplifting [main] best 33 combination
Uplifting [] best 33 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Tests a number of constant declarations
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
.const LINE_LEN = $28
.const MARGIN_TOP = 4
.const MARGIN_LEFT = 4
.const OFFSET = $28*5+5
.label BODY2 = SCREEN+OFFSET
// @begin
__bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [2] call main
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
__bend:
// main
main: {
// [4] *((const byte*) SCREEN+(const byte) MARGIN_TOP*(const byte) LINE_LEN+(const byte) MARGIN_LEFT) ← (byte) '*' -- _deref_pbuc1=vbuc2
lda #'*'
sta SCREEN+MARGIN_TOP*LINE_LEN+MARGIN_LEFT
// [5] *((const byte*) BODY2) ← (byte) '*' -- _deref_pbuc1=vbuc2
lda #'*'
sta BODY2
jmp __breturn
// main::@return
__breturn:
// [6] return
rts
}
// File Data
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __bend
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction lda #'*'
Succesful ASM optimization Pass5UnnecesaryLoadElimination
Replacing label __bbegin with __b1
Removing instruction __bbegin:
Removing instruction __b1_from___bbegin:
Removing instruction __bend_from___b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction __bend:
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Updating BasicUpstart to call main directly
Removing instruction jsr main
Succesful ASM optimization Pass5SkipBegin
Removing instruction __b1:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(const byte*) BODY2 = (const byte*) SCREEN+(const word) OFFSET
(const byte) LINE_LEN = (byte) $28
(const byte) MARGIN_LEFT = (byte) 4
(const byte) MARGIN_TOP = (byte) 4
(const word) OFFSET = (byte)(number) $28*(number) 5+(number) 5
(const byte*) SCREEN = (byte*) 1024
(void()) main()
(label) main::@return
FINAL ASSEMBLER
Score: 16
// File Comments
// Tests a number of constant declarations
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
.const LINE_LEN = $28
.const MARGIN_TOP = 4
.const MARGIN_LEFT = 4
.const OFFSET = $28*5+5
.label BODY2 = SCREEN+OFFSET
// @begin
// [1] phi from @begin to @1 [phi:@begin->@1]
// @1
// [2] call main
// [3] phi from @1 to @end [phi:@1->@end]
// @end
// main
main: {
// *BODY1 = '*'
// [4] *((const byte*) SCREEN+(const byte) MARGIN_TOP*(const byte) LINE_LEN+(const byte) MARGIN_LEFT) ← (byte) '*' -- _deref_pbuc1=vbuc2
lda #'*'
sta SCREEN+MARGIN_TOP*LINE_LEN+MARGIN_LEFT
// *BODY2 = '*'
// [5] *((const byte*) BODY2) ← (byte) '*' -- _deref_pbuc1=vbuc2
sta BODY2
// main::@return
// }
// [6] return
rts
}
// File Data

View File

@ -0,0 +1,12 @@
(label) @1
(label) @begin
(label) @end
(const byte*) BODY2 = (const byte*) SCREEN+(const word) OFFSET
(const byte) LINE_LEN = (byte) $28
(const byte) MARGIN_LEFT = (byte) 4
(const byte) MARGIN_TOP = (byte) 4
(const word) OFFSET = (byte)(number) $28*(number) 5+(number) 5
(const byte*) SCREEN = (byte*) 1024
(void()) main()
(label) main::@return

View File

@ -30,8 +30,8 @@ main: scope:[main] from @9
*((byte*) SPRITES_YPOS + (number) 0) ← (number) $64
*((byte*) SPRITES_XPOS + (number) 0) ← (number) $64
(byte*~) main::$0 ← (byte*) SCREEN + (word) SPRITE_PTRS
(byte[$40]~) main::$1 ← (byte[$40]) SPRITE / (number) $40
(byte~) main::$2 ← ((byte)) (byte[$40]~) main::$1
(byte*~) main::$1 ← (byte[$40]) SPRITE / (number) $40
(byte~) main::$2 ← ((byte)) (byte*~) main::$1
*((byte*~) main::$0) ← (byte~) main::$2
call saveZeropage
to:main::@1
@ -126,7 +126,7 @@ SYMBOL TABLE SSA
(label) animSprite::@return
(void()) main()
(byte*~) main::$0
(byte[$40]~) main::$1
(byte*~) main::$1
(byte~) main::$2
(label) main::@1
(label) main::@2
@ -146,7 +146,7 @@ Adding number conversion cast (unumber) $64 in *((byte*) SPRITES_YPOS + (number)
Adding number conversion cast (unumber) 0 in *((byte*) SPRITES_YPOS + (number) 0) ← ((unumber)) (number) $64
Adding number conversion cast (unumber) $64 in *((byte*) SPRITES_XPOS + (number) 0) ← (number) $64
Adding number conversion cast (unumber) 0 in *((byte*) SPRITES_XPOS + (number) 0) ← ((unumber)) (number) $64
Adding number conversion cast (unumber) $40 in (byte[$40]~) main::$1 ← (byte[$40]) SPRITE / (number) $40
Adding number conversion cast (unumber) $40 in (byte*~) main::$1 ← (byte[$40]) SPRITE / (number) $40
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast (word) SPRITE_PTRS ← (unumber)(number) $3f8
Inlining cast (byte*) SPRITES_XPOS ← (byte*)(number) $d000
@ -156,7 +156,7 @@ Inlining cast (byte*) SCREEN ← (byte*)(number) $400
Inlining cast *((byte*) SPRITES_ENABLE) ← (unumber)(number) 1
Inlining cast *((byte*) SPRITES_YPOS + (unumber)(number) 0) ← (unumber)(number) $64
Inlining cast *((byte*) SPRITES_XPOS + (unumber)(number) 0) ← (unumber)(number) $64
Inlining cast (byte~) main::$2 ← (byte)(byte[$40]~) main::$1
Inlining cast (byte~) main::$2 ← (byte)(byte*~) main::$1
Successful SSA optimization Pass2InlineCast
Simplifying constant integer cast $3f8
Simplifying constant pointer cast (byte*) 53248
@ -195,10 +195,10 @@ Simplifying expression containing zero SPRITES_YPOS in [10] *((const byte*) SPRI
Simplifying expression containing zero SPRITES_XPOS in [11] *((const byte*) SPRITES_XPOS + (byte) 0) ← (byte) $64
Successful SSA optimization PassNSimplifyExpressionWithZero
Constant right-side identified [4] (byte*~) main::$0 ← (const byte*) SCREEN + (const word) SPRITE_PTRS
Constant right-side identified [5] (byte[$40]~) main::$1 ← (const byte[$40]) SPRITE / (byte) $40
Constant right-side identified [5] (byte*~) main::$1 ← (const byte[$40]) SPRITE / (byte) $40
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte*) main::$0 = SCREEN+SPRITE_PTRS
Constant (const byte[$40]) main::$1 = SPRITE/$40
Constant (const byte*) main::$1 = SPRITE/$40
Successful SSA optimization Pass2ConstantIdentification
Constant (const byte) main::$2 = (byte)main::$1
Successful SSA optimization Pass2ConstantIdentification