1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-06-26 19:30:00 +00:00

Variable extern declarations are now supported. Closes #196

This commit is contained in:
jespergravgaard 2020-04-09 09:21:43 +02:00
parent 8bdc927694
commit 23ae5cf5f5
30 changed files with 1235 additions and 22 deletions

View File

@ -199,6 +199,7 @@ public class Compiler {
new Pass1GenerateControlFlowGraph(program).execute();
new Pass1ResolveForwardReferences(program).execute();
new Pass1AssertProcedureDefined(program).execute();
new Pass1AssertVariableDefined(program).execute();
new PassNAssertStructMembers(program).execute();
new Pass1UnwindBlockScopes(program).execute();
new Pass1Procedures(program).execute();

View File

@ -2,6 +2,7 @@ package dk.camelot64.kickc.model;
import dk.camelot64.kickc.model.symbols.*;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypeConversion;
import dk.camelot64.kickc.model.types.SymbolTypePointer;
import dk.camelot64.kickc.model.types.SymbolTypeStruct;
import dk.camelot64.kickc.model.values.ScopeRef;
@ -70,7 +71,34 @@ public class VariableBuilder {
}
variable.setMemoryArea(this.getMemoryArea());
variable.setMemoryAlignment(this.getAlignment());
scope.add(variable);
variable.setDeclarationOnly(this.isDeclarationOnly());
// Check if the symbol has already been declared
Symbol declaredSymbol = scope.getLocalSymbol(varName);
if(declaredSymbol!=null && !declaredSymbol.getFullName().equals(variable.getFullName()))
// We found another symbol!
declaredSymbol = null;
if(declaredSymbol!=null) {
if(!(declaredSymbol instanceof Variable))
throw new CompileError("Error! Conflicting declarations for: "+variable.getFullName());
Variable declaredVar = (Variable) declaredSymbol;
if(!declaredVar.isDeclarationOnly() && !variable.isDeclarationOnly())
throw new CompileError("Error! Redefinition of variable: "+variable.getFullName());
if(!SymbolTypeConversion.variableDeclarationMatch(declaredVar, variable))
throw new CompileError("Error! Conflicting declarations for: "+variable.getFullName());
// Update the variable with the definition
if(!variable.isDeclarationOnly()) {
scope.remove(declaredSymbol);
scope.add(variable);
}
} else {
// Not already declared - add it
scope.add(variable);
}
return variable;
}
@ -219,6 +247,14 @@ public class VariableBuilder {
return hasDirective(Directive.Export.class);
}
/**
* Declared but not defined. ( "extern" keyword)
* @return true if the variable is declared but not defined.
*/
public boolean isDeclarationOnly() {
return hasDirective(Directive.Extern.class);
}
/**
* Is the variable single-static-assignment ot multi-assignment.
* Depends on the type and scope of the variable plus directives directly affecting the memory layout ( __mma, __sa, __zp, __address, __align).

View File

@ -1,10 +1,7 @@
package dk.camelot64.kickc.model.symbols;
import dk.camelot64.kickc.model.CompileError;
import dk.camelot64.kickc.model.InternalError;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.Registers;
import dk.camelot64.kickc.model.VariableRegisterWeights;
import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.values.*;
@ -102,7 +99,7 @@ public abstract class Scope implements Symbol, Serializable {
public Variable addVariableIntermediate() {
String name = allocateIntermediateVariableName();
return add(Variable.createIntermediate( name, this, getSegmentData()));
return add(Variable.createIntermediate(name, this, getSegmentData()));
}
/**
@ -169,8 +166,8 @@ public abstract class Scope implements Symbol, Serializable {
public Variable getVariable(String name) {
Variable symbol = (Variable) getSymbol(name);
if(symbol!=null && !symbol.isVariable())
throw new InternalError("Symbol is not a variable! "+symbol.toString());
if(symbol != null && !symbol.isVariable())
throw new InternalError("Symbol is not a variable! " + symbol.toString());
return symbol;
}
@ -180,7 +177,8 @@ public abstract class Scope implements Symbol, Serializable {
public Variable getConstant(String name) {
Variable symbol = (Variable) getSymbol(name);
if(symbol!=null && !symbol.isKindConstant()) throw new InternalError("Symbol is not a constant! "+symbol.toString());
if(symbol != null && !symbol.isKindConstant())
throw new InternalError("Symbol is not a constant! " + symbol.toString());
return symbol;
}
@ -190,6 +188,7 @@ public abstract class Scope implements Symbol, Serializable {
/**
* Get all variables/constants
*
* @param includeSubScopes true to include sub-scopes
* @return all variables/constants
*/
@ -209,6 +208,7 @@ public abstract class Scope implements Symbol, Serializable {
/**
* Get all runtime variables (excluding constants)
*
* @param includeSubScopes true to include sub-scopes
* @return all runtime variables (excluding constants)
*/
@ -222,6 +222,7 @@ public abstract class Scope implements Symbol, Serializable {
/**
* Get all constants
*
* @param includeSubScopes true to include sub-scopes
* @return all constants
*/
@ -368,7 +369,7 @@ public abstract class Scope implements Symbol, Serializable {
res.append(symbol.toString(program));
if(symVar.isArray()) {
res.append("[");
if(symVar.getArraySize()!=null) {
if(symVar.getArraySize() != null) {
res.append(symVar.getArraySize().toString(program));
}
res.append("] ");
@ -395,7 +396,7 @@ public abstract class Scope implements Symbol, Serializable {
}
}
}
if(symVar.getInitValue()!=null) {
if(symVar.getInitValue() != null) {
res.append(" = " + symVar.getInitValue().toString(program));
}
res.append("\n");

View File

@ -112,6 +112,9 @@ 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;
/** If the variable is only declared and not defined (using the "extern" keyword). */
private boolean isDeclarationOnly;
/**
* Create a variable (or constant)
*
@ -594,6 +597,14 @@ public class Variable implements Symbol {
return getType() instanceof SymbolTypeStruct && isKindLoadStore();
}
public boolean isDeclarationOnly() {
return isDeclarationOnly;
}
public void setDeclarationOnly(boolean declarationOnly) {
isDeclarationOnly = declarationOnly;
}
public List<Comment> getComments() {
return comments;
}

View File

@ -5,6 +5,7 @@ import dk.camelot64.kickc.model.ConstantNotLiteral;
import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.symbols.Procedure;
import dk.camelot64.kickc.model.symbols.ProgramScope;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.values.ConstantInteger;
import dk.camelot64.kickc.model.values.ConstantLiteral;
import dk.camelot64.kickc.model.values.ConstantValue;
@ -226,8 +227,8 @@ public class SymbolTypeConversion {
return true;
}
if(lValueType instanceof SymbolTypePointer && rValueType instanceof SymbolTypePointer && assignmentTypeMatch(((SymbolTypePointer) lValueType).getElementType(), ((SymbolTypePointer) rValueType).getElementType())) {
// Pointer types assigned from each other
return true;
// Pointer types assigned from each other
return true;
}
return false;
}
@ -250,6 +251,7 @@ public class SymbolTypeConversion {
/**
* Checks that two procedure declarations are a proper match
*
* @param first The first procedure declaration
* @param second The first procedure declaration
* @return true if they match types. False otherwise
@ -265,4 +267,29 @@ public class SymbolTypeConversion {
}
/**
* Checks that two variable declarations are a proper match
*
* @param first The first variable declaration
* @param second The first variable declaration
* @return true if they match types. False otherwise
*/
public static boolean variableDeclarationMatch(Variable first, Variable second) {
if(!first.getFullName().equals(second.getFullName()))
return false;
if(!first.getType().equals(second.getType()))
return false;
if(first.isNoModify() != second.isNoModify())
return false;
if(first.isVolatile() != second.isVolatile())
return false;
if(first.isToNoModify() != second.isToNoModify())
return false;
if(first.isToVolatile() != second.isToVolatile())
return false;
if(first.isPermanent() != second.isPermanent())
return false;
return true;
}
}

View File

@ -1094,6 +1094,11 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
return new Directive.Static();
}
@Override
public Object visitDirectiveExtern(KickCParser.DirectiveExternContext ctx) {
return new Directive.Extern();
}
@Override
public Directive visitDirectiveExport(KickCParser.DirectiveExportContext ctx) {
return new Directive.Export();

View File

@ -22,7 +22,7 @@ public class Pass1AssertProcedureDefined extends Pass1Base {
final Label procedureLabel = procedure.getLabel();
final ControlFlowBlock procedureBlock = getGraph().getBlock(procedureLabel.getRef());
if(procedureBlock == null)
throw new CompileError("Error! Function is never declared: " + procedure.getFullName());
throw new CompileError("Error! Function body is never defined: " + procedure.getFullName());
}
return false;
}

View File

@ -0,0 +1,23 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.CompileError;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.symbols.Variable;
/** Pass that checks that all variables declared have a definition*/
public class Pass1AssertVariableDefined extends Pass1Base {
public Pass1AssertVariableDefined(Program program) {
super(program);
}
@Override
public boolean step() {
for(Variable var : getScope().getAllVars(true)) {
if(var.isDeclarationOnly())
throw new CompileError("Error! Variable is declared but never defined: " + var.getFullName());
}
return false;
}
}

View File

@ -38,23 +38,48 @@ public class TestPrograms {
}
@Test
public void testCStyleDeclMissing() throws IOException, URISyntaxException {
assertError("cstyle-decl-missing", "Error! Function is never declared: sum", false);
public void testCStyleDeclVarMultiple() throws IOException, URISyntaxException {
compileAndCompare("cstyle-decl-var-multiple");
}
@Test
public void testCStyleDeclRedefinition() throws IOException, URISyntaxException {
assertError("cstyle-decl-redefinition", "Error! Redefinition of function: sum");
public void testCStyleDeclVarMissing() throws IOException, URISyntaxException {
assertError("cstyle-decl-var-missing", "Variable is declared but never defined: SCREEN", false);
}
@Test
public void testCStyleDeclMismatch() throws IOException, URISyntaxException {
assertError("cstyle-decl-mismatch", "Error! Conflicting declarations for: sum");
public void testCStyleDeclVarMismatch() throws IOException, URISyntaxException {
assertError("cstyle-decl-var-mismatch", "Error! Conflicting declarations for: SCREEN");
}
@Test
public void testCStyleDecl0() throws IOException, URISyntaxException {
compileAndCompare("cstyle-decl-0");
public void testCStyleDeclVarRedefinition() throws IOException, URISyntaxException {
assertError("cstyle-decl-var-redefinition", "Error! Redefinition of variable: SCREEN");
}
@Test
public void testCStyleDeclVar() throws IOException, URISyntaxException {
compileAndCompare("cstyle-decl-var");
}
@Test
public void testCStyleDeclFunctionMissing() throws IOException, URISyntaxException {
assertError("cstyle-decl-function-missing", "Error! Function body is never defined: sum", false);
}
@Test
public void testCStyleDeclFunctionRedefinition() throws IOException, URISyntaxException {
assertError("cstyle-decl-function-redefinition", "Error! Redefinition of function: sum");
}
@Test
public void testCStyleDeclFunctionMismatch() throws IOException, URISyntaxException {
assertError("cstyle-decl-function-mismatch", "Error! Conflicting declarations for: sum");
}
@Test
public void testCStyleDeclFunction() throws IOException, URISyntaxException {
compileAndCompare("cstyle-decl-function");
}
@Test

View File

@ -0,0 +1,28 @@
// Test variable declarations
// Declaration type mismatch
// An extern with one type
extern unsigned int SCREEN;
// The actual declaration with another
char * const SCREEN = 0x0400;
char idx;
// And a little code using them
void main() {
SCREEN[idx++] = 'c';
SCREEN[idx++] = 'm';
SCREEN[idx++] = 'l';
}

View File

@ -0,0 +1,22 @@
// Test declarations of variables
// Missing definition
// The definition
extern char * const SCREEN = 0x0400;
//Second definition
char idx;
// And a little code using them
void main() {
SCREEN[idx++] = 'c';
SCREEN[idx++] = 'm';
SCREEN[idx++] = 'l';
}

View File

@ -0,0 +1,18 @@
// Test legal definition of multiple local variables with the same name
char * const SCREEN = 0x0400;
char idx;
// And a little code using them
void main() {
for( char c: 0..10)
for( char c: 0..10)
SCREEN[idx++] = '*';
}

View File

@ -0,0 +1,23 @@
// Test declarations of variables
// Redefinition
//First definition
char * const SCREEN = 0x0400;
//Second definition
char * const SCREEN = 0x0400;
char idx;
// And a little code using them
void main() {
SCREEN[idx++] = 'c';
SCREEN[idx++] = 'm';
SCREEN[idx++] = 'l';
}

View File

@ -0,0 +1,23 @@
// Test declarations of variables without definition
// A few externs
extern char * const SCREEN;
extern char idx;
// The actual declarations
char * const SCREEN = 0x0400;
char idx;
// And a little code using them
void main() {
SCREEN[idx++] = 'c';
SCREEN[idx++] = 'm';
SCREEN[idx++] = 'l';
}

View File

@ -0,0 +1,30 @@
// Test legal definition of multiple local variables with the same name
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.label SCREEN = $400
// And a little code using them
main: {
.label c = 2
lda #0
sta.z c
tay
__b1:
ldx #0
__b2:
// SCREEN[idx++] = '*'
lda #'*'
sta SCREEN,y
// SCREEN[idx++] = '*';
iny
// for( char c: 0..10)
inx
cpx #$b
bne __b2
inc.z c
lda #$b
cmp.z c
bne __b1
// }
rts
}

View File

@ -0,0 +1,33 @@
@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] phi()
to:main::@1
main::@1: scope:[main] from main main::@3
[5] (byte) main::c#4 ← phi( main/(byte) 0 main::@3/(byte) main::c#1 )
[5] (byte) idx#7 ← phi( main/(byte) 0 main::@3/(byte) idx#1 )
to:main::@2
main::@2: scope:[main] from main::@1 main::@2
[6] (byte) main::c1#2 ← phi( main::@1/(byte) 0 main::@2/(byte) main::c1#1 )
[6] (byte) idx#4 ← phi( main::@1/(byte) idx#7 main::@2/(byte) idx#1 )
[7] *((const nomodify byte*) SCREEN + (byte) idx#4) ← (byte) '*'
[8] (byte) idx#1 ← ++ (byte) idx#4
[9] (byte) main::c1#1 ← ++ (byte) main::c1#2
[10] if((byte) main::c1#1!=(byte) $b) goto main::@2
to:main::@3
main::@3: scope:[main] from main::@2
[11] (byte) main::c#1 ← ++ (byte) main::c#4
[12] if((byte) main::c#1!=(byte) $b) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@3
[13] return
to:@return

View File

@ -0,0 +1,531 @@
Culled Empty Block (label) main::@4
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(byte) idx#0 ← (byte) 0
to:@1
(void()) main()
main: scope:[main] from @1
(byte) idx#10 ← phi( @1/(byte) idx#9 )
(byte) main::c#0 ← (byte) 0
to:main::@1
main::@1: scope:[main] from main main::@3
(byte) main::c#4 ← phi( main/(byte) main::c#0 main::@3/(byte) main::c#1 )
(byte) idx#7 ← phi( main/(byte) idx#10 main::@3/(byte) idx#8 )
(byte) main::c1#0 ← (byte) 0
to:main::@2
main::@2: scope:[main] from main::@1 main::@2
(byte) main::c#3 ← phi( main::@1/(byte) main::c#4 main::@2/(byte) main::c#3 )
(byte) main::c1#2 ← phi( main::@1/(byte) main::c1#0 main::@2/(byte) main::c1#1 )
(byte) idx#4 ← phi( main::@1/(byte) idx#7 main::@2/(byte) idx#1 )
*((const nomodify byte*) SCREEN + (byte) idx#4) ← (byte) '*'
(byte) idx#1 ← ++ (byte) idx#4
(byte) main::c1#1 ← (byte) main::c1#2 + rangenext(0,$a)
(bool~) main::$0 ← (byte) main::c1#1 != rangelast(0,$a)
if((bool~) main::$0) goto main::@2
to:main::@3
main::@3: scope:[main] from main::@2
(byte) idx#8 ← phi( main::@2/(byte) idx#1 )
(byte) main::c#2 ← phi( main::@2/(byte) main::c#3 )
(byte) main::c#1 ← (byte) main::c#2 + rangenext(0,$a)
(bool~) main::$1 ← (byte) main::c#1 != rangelast(0,$a)
if((bool~) main::$1) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@3
(byte) idx#5 ← phi( main::@3/(byte) idx#8 )
(byte) idx#2 ← (byte) idx#5
return
to:@return
@1: scope:[] from @begin
(byte) idx#9 ← phi( @begin/(byte) idx#0 )
call main
to:@2
@2: scope:[] from @1
(byte) idx#6 ← phi( @1/(byte) idx#2 )
(byte) idx#3 ← (byte) idx#6
to:@end
@end: scope:[] from @2
SYMBOL TABLE SSA
(label) @1
(label) @2
(label) @begin
(label) @end
(const nomodify byte*) SCREEN = (byte*)(number) $400
(byte) idx
(byte) idx#0
(byte) idx#1
(byte) idx#10
(byte) idx#2
(byte) idx#3
(byte) idx#4
(byte) idx#5
(byte) idx#6
(byte) idx#7
(byte) idx#8
(byte) idx#9
(void()) main()
(bool~) main::$0
(bool~) main::$1
(label) main::@1
(label) main::@2
(label) main::@3
(label) main::@return
(byte) main::c
(byte) main::c#0
(byte) main::c#1
(byte) main::c#2
(byte) main::c#3
(byte) main::c#4
(byte) main::c1
(byte) main::c1#0
(byte) main::c1#1
(byte) main::c1#2
Simplifying constant pointer cast (byte*) 1024
Successful SSA optimization PassNCastSimplification
Alias main::c#2 = main::c#3
Alias idx#1 = idx#8 idx#5 idx#2
Alias idx#0 = idx#9
Alias idx#3 = idx#6
Successful SSA optimization Pass2AliasElimination
Identical Phi Values (byte) idx#10 (byte) idx#0
Identical Phi Values (byte) main::c#2 (byte) main::c#4
Identical Phi Values (byte) idx#3 (byte) idx#1
Successful SSA optimization Pass2IdenticalPhiElimination
Simple Condition (bool~) main::$0 [10] if((byte) main::c1#1!=rangelast(0,$a)) goto main::@2
Simple Condition (bool~) main::$1 [13] if((byte) main::c#1!=rangelast(0,$a)) goto main::@1
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant (const byte) idx#0 = 0
Constant (const byte) main::c#0 = 0
Constant (const byte) main::c1#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Resolved ranged next value [8] main::c1#1 ← ++ main::c1#2 to ++
Resolved ranged comparison value [10] if(main::c1#1!=rangelast(0,$a)) goto main::@2 to (number) $b
Resolved ranged next value [11] main::c#1 ← ++ main::c#4 to ++
Resolved ranged comparison value [13] if(main::c#1!=rangelast(0,$a)) goto main::@1 to (number) $b
Adding number conversion cast (unumber) $b in if((byte) main::c1#1!=(number) $b) goto main::@2
Adding number conversion cast (unumber) $b in if((byte) main::c#1!=(number) $b) goto main::@1
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant integer cast $b
Simplifying constant integer cast $b
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) $b
Finalized unsigned number type (byte) $b
Successful SSA optimization PassNFinalizeNumberTypeConversions
Inlining constant with var siblings (const byte) main::c#0
Inlining constant with var siblings (const byte) main::c1#0
Inlining constant with var siblings (const byte) idx#0
Constant inlined main::c1#0 = (byte) 0
Constant inlined main::c#0 = (byte) 0
Constant inlined idx#0 = (byte) 0
Successful SSA optimization Pass2ConstantInlining
Added new block during phi lifting main::@5(between main::@3 and main::@1)
Added new block during phi lifting main::@6(between main::@2 and main::@2)
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
Adding NOP phi() at start of main
CALL GRAPH
Calls in [] to main:2
Created 4 initial phi equivalence classes
Coalesced [7] idx#12 ← idx#7
Coalesced [16] idx#11 ← idx#1
Coalesced [17] main::c#5 ← main::c#1
Coalesced (already) [18] idx#13 ← idx#1
Coalesced [19] main::c1#3 ← main::c1#1
Coalesced down to 3 phi equivalence classes
Culled Empty Block (label) @2
Culled Empty Block (label) main::@5
Culled Empty Block (label) main::@6
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
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] phi()
to:main::@1
main::@1: scope:[main] from main main::@3
[5] (byte) main::c#4 ← phi( main/(byte) 0 main::@3/(byte) main::c#1 )
[5] (byte) idx#7 ← phi( main/(byte) 0 main::@3/(byte) idx#1 )
to:main::@2
main::@2: scope:[main] from main::@1 main::@2
[6] (byte) main::c1#2 ← phi( main::@1/(byte) 0 main::@2/(byte) main::c1#1 )
[6] (byte) idx#4 ← phi( main::@1/(byte) idx#7 main::@2/(byte) idx#1 )
[7] *((const nomodify byte*) SCREEN + (byte) idx#4) ← (byte) '*'
[8] (byte) idx#1 ← ++ (byte) idx#4
[9] (byte) main::c1#1 ← ++ (byte) main::c1#2
[10] if((byte) main::c1#1!=(byte) $b) goto main::@2
to:main::@3
main::@3: scope:[main] from main::@2
[11] (byte) main::c#1 ← ++ (byte) main::c#4
[12] if((byte) main::c#1!=(byte) $b) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@3
[13] return
to:@return
VARIABLE REGISTER WEIGHTS
(byte) idx
(byte) idx#1 420.59999999999997
(byte) idx#4 1552.0
(byte) idx#7 202.0
(void()) main()
(byte) main::c
(byte) main::c#1 151.5
(byte) main::c#4 33.666666666666664
(byte) main::c1
(byte) main::c1#1 1501.5
(byte) main::c1#2 667.3333333333334
Initial phi equivalence classes
[ main::c#4 main::c#1 ]
[ idx#4 idx#7 idx#1 ]
[ main::c1#2 main::c1#1 ]
Complete equivalence classes
[ main::c#4 main::c#1 ]
[ idx#4 idx#7 idx#1 ]
[ main::c1#2 main::c1#1 ]
Allocated zp[1]:2 [ main::c#4 main::c#1 ]
Allocated zp[1]:3 [ idx#4 idx#7 idx#1 ]
Allocated zp[1]:4 [ main::c1#2 main::c1#1 ]
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Test legal definition of multiple local variables with the same name
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
.label idx = 3
// @begin
__bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
main_from___b1:
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
__bend:
// main
// And a little code using them
main: {
.label c1 = 4
.label c = 2
// [5] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [5] phi (byte) main::c#4 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta.z c
// [5] phi (byte) idx#7 = (byte) 0 [phi:main->main::@1#1] -- vbuz1=vbuc1
lda #0
sta.z idx
jmp __b1
// [5] phi from main::@3 to main::@1 [phi:main::@3->main::@1]
__b1_from___b3:
// [5] phi (byte) main::c#4 = (byte) main::c#1 [phi:main::@3->main::@1#0] -- register_copy
// [5] phi (byte) idx#7 = (byte) idx#1 [phi:main::@3->main::@1#1] -- register_copy
jmp __b1
// main::@1
__b1:
// [6] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
__b2_from___b1:
// [6] phi (byte) main::c1#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuz1=vbuc1
lda #0
sta.z c1
// [6] phi (byte) idx#4 = (byte) idx#7 [phi:main::@1->main::@2#1] -- register_copy
jmp __b2
// [6] phi from main::@2 to main::@2 [phi:main::@2->main::@2]
__b2_from___b2:
// [6] phi (byte) main::c1#2 = (byte) main::c1#1 [phi:main::@2->main::@2#0] -- register_copy
// [6] phi (byte) idx#4 = (byte) idx#1 [phi:main::@2->main::@2#1] -- register_copy
jmp __b2
// main::@2
__b2:
// [7] *((const nomodify byte*) SCREEN + (byte) idx#4) ← (byte) '*' -- pbuc1_derefidx_vbuz1=vbuc2
lda #'*'
ldy.z idx
sta SCREEN,y
// [8] (byte) idx#1 ← ++ (byte) idx#4 -- vbuz1=_inc_vbuz1
inc.z idx
// [9] (byte) main::c1#1 ← ++ (byte) main::c1#2 -- vbuz1=_inc_vbuz1
inc.z c1
// [10] if((byte) main::c1#1!=(byte) $b) goto main::@2 -- vbuz1_neq_vbuc1_then_la1
lda #$b
cmp.z c1
bne __b2_from___b2
jmp __b3
// main::@3
__b3:
// [11] (byte) main::c#1 ← ++ (byte) main::c#4 -- vbuz1=_inc_vbuz1
inc.z c
// [12] if((byte) main::c#1!=(byte) $b) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
lda #$b
cmp.z c
bne __b1_from___b3
jmp __breturn
// main::@return
__breturn:
// [13] return
rts
}
// File Data
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [7] *((const nomodify byte*) SCREEN + (byte) idx#4) ← (byte) '*' [ main::c#4 idx#4 main::c1#2 ] ( main:2 [ main::c#4 idx#4 main::c1#2 ] { } ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp[1]:2 [ main::c#4 main::c#1 ]
Removing always clobbered register reg byte a as potential for zp[1]:3 [ idx#4 idx#7 idx#1 ]
Removing always clobbered register reg byte a as potential for zp[1]:4 [ main::c1#2 main::c1#1 ]
Statement [7] *((const nomodify byte*) SCREEN + (byte) idx#4) ← (byte) '*' [ main::c#4 idx#4 main::c1#2 ] ( main:2 [ main::c#4 idx#4 main::c1#2 ] { } ) always clobbers reg byte a
Potential registers zp[1]:2 [ main::c#4 main::c#1 ] : zp[1]:2 , reg byte x , reg byte y ,
Potential registers zp[1]:3 [ idx#4 idx#7 idx#1 ] : zp[1]:3 , reg byte x , reg byte y ,
Potential registers zp[1]:4 [ main::c1#2 main::c1#1 ] : zp[1]:4 , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 2,168.83: zp[1]:4 [ main::c1#2 main::c1#1 ] 185.17: zp[1]:2 [ main::c#4 main::c#1 ]
Uplift Scope [] 2,174.6: zp[1]:3 [ idx#4 idx#7 idx#1 ]
Uplifting [main] best 3583 combination reg byte x [ main::c1#2 main::c1#1 ] zp[1]:2 [ main::c#4 main::c#1 ]
Uplifting [] best 2953 combination reg byte y [ idx#4 idx#7 idx#1 ]
Attempting to uplift remaining variables inzp[1]:2 [ main::c#4 main::c#1 ]
Uplifting [main] best 2953 combination zp[1]:2 [ main::c#4 main::c#1 ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test legal definition of multiple local variables with the same name
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
// @begin
__bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
main_from___b1:
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
__bend:
// main
// And a little code using them
main: {
.label c = 2
// [5] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [5] phi (byte) main::c#4 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta.z c
// [5] phi (byte) idx#7 = (byte) 0 [phi:main->main::@1#1] -- vbuyy=vbuc1
ldy #0
jmp __b1
// [5] phi from main::@3 to main::@1 [phi:main::@3->main::@1]
__b1_from___b3:
// [5] phi (byte) main::c#4 = (byte) main::c#1 [phi:main::@3->main::@1#0] -- register_copy
// [5] phi (byte) idx#7 = (byte) idx#1 [phi:main::@3->main::@1#1] -- register_copy
jmp __b1
// main::@1
__b1:
// [6] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
__b2_from___b1:
// [6] phi (byte) main::c1#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuxx=vbuc1
ldx #0
// [6] phi (byte) idx#4 = (byte) idx#7 [phi:main::@1->main::@2#1] -- register_copy
jmp __b2
// [6] phi from main::@2 to main::@2 [phi:main::@2->main::@2]
__b2_from___b2:
// [6] phi (byte) main::c1#2 = (byte) main::c1#1 [phi:main::@2->main::@2#0] -- register_copy
// [6] phi (byte) idx#4 = (byte) idx#1 [phi:main::@2->main::@2#1] -- register_copy
jmp __b2
// main::@2
__b2:
// [7] *((const nomodify byte*) SCREEN + (byte) idx#4) ← (byte) '*' -- pbuc1_derefidx_vbuyy=vbuc2
lda #'*'
sta SCREEN,y
// [8] (byte) idx#1 ← ++ (byte) idx#4 -- vbuyy=_inc_vbuyy
iny
// [9] (byte) main::c1#1 ← ++ (byte) main::c1#2 -- vbuxx=_inc_vbuxx
inx
// [10] if((byte) main::c1#1!=(byte) $b) goto main::@2 -- vbuxx_neq_vbuc1_then_la1
cpx #$b
bne __b2_from___b2
jmp __b3
// main::@3
__b3:
// [11] (byte) main::c#1 ← ++ (byte) main::c#4 -- vbuz1=_inc_vbuz1
inc.z c
// [12] if((byte) main::c#1!=(byte) $b) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
lda #$b
cmp.z c
bne __b1_from___b3
jmp __breturn
// main::@return
__breturn:
// [13] return
rts
}
// File Data
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __bend
Removing instruction jmp __b1
Removing instruction jmp __b2
Removing instruction jmp __b3
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Replacing instruction ldy #0 with TAY
Replacing label __b2_from___b2 with __b2
Replacing label __b1_from___b3 with __b1
Removing instruction __b1_from___bbegin:
Removing instruction __b1:
Removing instruction main_from___b1:
Removing instruction __bend_from___b1:
Removing instruction __b1_from___b3:
Removing instruction __b2_from___b1:
Removing instruction __b2_from___b2:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction __bend:
Removing instruction __b1_from_main:
Removing instruction __b3:
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Updating BasicUpstart to call main directly
Removing instruction jsr main
Succesful ASM optimization Pass5SkipBegin
Removing instruction jmp __b1
Removing instruction jmp __b2
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __bbegin:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(const nomodify byte*) SCREEN = (byte*) 1024
(byte) idx
(byte) idx#1 reg byte y 420.59999999999997
(byte) idx#4 reg byte y 1552.0
(byte) idx#7 reg byte y 202.0
(void()) main()
(label) main::@1
(label) main::@2
(label) main::@3
(label) main::@return
(byte) main::c
(byte) main::c#1 c zp[1]:2 151.5
(byte) main::c#4 c zp[1]:2 33.666666666666664
(byte) main::c1
(byte) main::c1#1 reg byte x 1501.5
(byte) main::c1#2 reg byte x 667.3333333333334
zp[1]:2 [ main::c#4 main::c#1 ]
reg byte y [ idx#4 idx#7 idx#1 ]
reg byte x [ main::c1#2 main::c1#1 ]
FINAL ASSEMBLER
Score: 1951
// File Comments
// Test legal definition of multiple local variables with the same name
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
// @begin
// [1] phi from @begin to @1 [phi:@begin->@1]
// @1
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
// [3] phi from @1 to @end [phi:@1->@end]
// @end
// main
// And a little code using them
main: {
.label c = 2
// [5] phi from main to main::@1 [phi:main->main::@1]
// [5] phi (byte) main::c#4 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta.z c
// [5] phi (byte) idx#7 = (byte) 0 [phi:main->main::@1#1] -- vbuyy=vbuc1
tay
// [5] phi from main::@3 to main::@1 [phi:main::@3->main::@1]
// [5] phi (byte) main::c#4 = (byte) main::c#1 [phi:main::@3->main::@1#0] -- register_copy
// [5] phi (byte) idx#7 = (byte) idx#1 [phi:main::@3->main::@1#1] -- register_copy
// main::@1
__b1:
// [6] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
// [6] phi (byte) main::c1#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuxx=vbuc1
ldx #0
// [6] phi (byte) idx#4 = (byte) idx#7 [phi:main::@1->main::@2#1] -- register_copy
// [6] phi from main::@2 to main::@2 [phi:main::@2->main::@2]
// [6] phi (byte) main::c1#2 = (byte) main::c1#1 [phi:main::@2->main::@2#0] -- register_copy
// [6] phi (byte) idx#4 = (byte) idx#1 [phi:main::@2->main::@2#1] -- register_copy
// main::@2
__b2:
// SCREEN[idx++] = '*'
// [7] *((const nomodify byte*) SCREEN + (byte) idx#4) ← (byte) '*' -- pbuc1_derefidx_vbuyy=vbuc2
lda #'*'
sta SCREEN,y
// SCREEN[idx++] = '*';
// [8] (byte) idx#1 ← ++ (byte) idx#4 -- vbuyy=_inc_vbuyy
iny
// for( char c: 0..10)
// [9] (byte) main::c1#1 ← ++ (byte) main::c1#2 -- vbuxx=_inc_vbuxx
inx
// [10] if((byte) main::c1#1!=(byte) $b) goto main::@2 -- vbuxx_neq_vbuc1_then_la1
cpx #$b
bne __b2
// main::@3
// [11] (byte) main::c#1 ← ++ (byte) main::c#4 -- vbuz1=_inc_vbuz1
inc.z c
// [12] if((byte) main::c#1!=(byte) $b) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
lda #$b
cmp.z c
bne __b1
// main::@return
// }
// [13] return
rts
}
// File Data

View File

@ -0,0 +1,23 @@
(label) @1
(label) @begin
(label) @end
(const nomodify byte*) SCREEN = (byte*) 1024
(byte) idx
(byte) idx#1 reg byte y 420.59999999999997
(byte) idx#4 reg byte y 1552.0
(byte) idx#7 reg byte y 202.0
(void()) main()
(label) main::@1
(label) main::@2
(label) main::@3
(label) main::@return
(byte) main::c
(byte) main::c#1 c zp[1]:2 151.5
(byte) main::c#4 c zp[1]:2 33.666666666666664
(byte) main::c1
(byte) main::c1#1 reg byte x 1501.5
(byte) main::c1#2 reg byte x 667.3333333333334
zp[1]:2 [ main::c#4 main::c#1 ]
reg byte y [ idx#4 idx#7 idx#1 ]
reg byte x [ main::c1#2 main::c1#1 ]

View File

@ -0,0 +1,20 @@
// Test declarations of variables without definition
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// The actual declarations
.label SCREEN = $400
// And a little code using them
main: {
// SCREEN[idx++] = 'c'
lda #'c'
sta SCREEN
// SCREEN[idx++] = 'm'
lda #'m'
sta SCREEN+1
// SCREEN[idx++] = 'l'
lda #'l'
sta SCREEN+2
// }
rts
}

View File

@ -0,0 +1,19 @@
@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 nomodify byte*) SCREEN) ← (byte) 'c'
[5] *((const nomodify byte*) SCREEN+(byte) 1) ← (byte) 'm'
[6] *((const nomodify byte*) SCREEN+(byte) 2) ← (byte) 'l'
to:main::@return
main::@return: scope:[main] from main
[7] return
to:@return

View File

@ -0,0 +1,306 @@
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(byte) idx#0 ← (byte) 0
(byte) idx#1 ← (byte) 0
to:@1
(void()) main()
main: scope:[main] from @1
(byte) idx#7 ← phi( @1/(byte) idx#10 )
*((const nomodify byte*) SCREEN + (byte) idx#7) ← (byte) 'c'
(byte) idx#2 ← ++ (byte) idx#7
*((const nomodify byte*) SCREEN + (byte) idx#2) ← (byte) 'm'
(byte) idx#3 ← ++ (byte) idx#2
*((const nomodify byte*) SCREEN + (byte) idx#3) ← (byte) 'l'
(byte) idx#4 ← ++ (byte) idx#3
to:main::@return
main::@return: scope:[main] from main
(byte) idx#8 ← phi( main/(byte) idx#4 )
(byte) idx#5 ← (byte) idx#8
return
to:@return
@1: scope:[] from @begin
(byte) idx#10 ← phi( @begin/(byte) idx#1 )
call main
to:@2
@2: scope:[] from @1
(byte) idx#9 ← phi( @1/(byte) idx#5 )
(byte) idx#6 ← (byte) idx#9
to:@end
@end: scope:[] from @2
SYMBOL TABLE SSA
(label) @1
(label) @2
(label) @begin
(label) @end
(const nomodify byte*) SCREEN = (byte*)(number) $400
(byte) idx
(byte) idx#0
(byte) idx#1
(byte) idx#10
(byte) idx#2
(byte) idx#3
(byte) idx#4
(byte) idx#5
(byte) idx#6
(byte) idx#7
(byte) idx#8
(byte) idx#9
(void()) main()
(label) main::@return
Simplifying constant pointer cast (byte*) 1024
Successful SSA optimization PassNCastSimplification
Alias idx#4 = idx#8 idx#5
Alias idx#1 = idx#10
Alias idx#6 = idx#9
Successful SSA optimization Pass2AliasElimination
Identical Phi Values (byte) idx#7 (byte) idx#1
Identical Phi Values (byte) idx#6 (byte) idx#4
Successful SSA optimization Pass2IdenticalPhiElimination
Constant (const byte) idx#0 = 0
Constant (const byte) idx#1 = 0
Successful SSA optimization Pass2ConstantIdentification
Simplifying expression containing zero SCREEN in [3] *((const nomodify byte*) SCREEN + (const byte) idx#1) ← (byte) 'c'
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused variable (byte) idx#4 and assignment [5] (byte) idx#4 ← ++ (byte) idx#3
Eliminating unused constant (const byte) idx#0
Successful SSA optimization PassNEliminateUnusedVars
Constant right-side identified [1] (byte) idx#2 ← ++ (const byte) idx#1
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte) idx#2 = ++idx#1
Successful SSA optimization Pass2ConstantIdentification
Constant right-side identified [2] (byte) idx#3 ← ++ (const byte) idx#2
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte) idx#3 = ++idx#2
Successful SSA optimization Pass2ConstantIdentification
Inlining constant with different constant siblings (const byte) idx#1
Inlining constant with different constant siblings (const byte) idx#2
Inlining constant with different constant siblings (const byte) idx#3
Constant inlined idx#2 = ++(byte) 0
Constant inlined idx#3 = ++++(byte) 0
Constant inlined idx#1 = (byte) 0
Successful SSA optimization Pass2ConstantInlining
Consolidated array index constant in *(SCREEN+++0)
Consolidated array index constant in *(SCREEN+++++0)
Successful SSA optimization Pass2ConstantAdditionElimination
Simplifying constant integer increment ++0
Simplifying constant integer increment ++0
Successful SSA optimization Pass2ConstantSimplification
Simplifying constant integer increment ++1
Successful SSA optimization Pass2ConstantSimplification
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 nomodify byte*) SCREEN) ← (byte) 'c'
[5] *((const nomodify byte*) SCREEN+(byte) 1) ← (byte) 'm'
[6] *((const nomodify byte*) SCREEN+(byte) 2) ← (byte) 'l'
to:main::@return
main::@return: scope:[main] from main
[7] return
to:@return
VARIABLE REGISTER WEIGHTS
(byte) idx
(void()) main()
Initial phi equivalence classes
Complete equivalence classes
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Test declarations of variables without definition
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
// The actual declarations
.label SCREEN = $400
// @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
// And a little code using them
main: {
// [4] *((const nomodify byte*) SCREEN) ← (byte) 'c' -- _deref_pbuc1=vbuc2
lda #'c'
sta SCREEN
// [5] *((const nomodify byte*) SCREEN+(byte) 1) ← (byte) 'm' -- _deref_pbuc1=vbuc2
lda #'m'
sta SCREEN+1
// [6] *((const nomodify byte*) SCREEN+(byte) 2) ← (byte) 'l' -- _deref_pbuc1=vbuc2
lda #'l'
sta SCREEN+2
jmp __breturn
// main::@return
__breturn:
// [7] return
rts
}
// File Data
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [4] *((const nomodify byte*) SCREEN) ← (byte) 'c' [ ] ( main:2 [ ] { } ) always clobbers reg byte a
Statement [5] *((const nomodify byte*) SCREEN+(byte) 1) ← (byte) 'm' [ ] ( main:2 [ ] { } ) always clobbers reg byte a
Statement [6] *((const nomodify byte*) SCREEN+(byte) 2) ← (byte) 'l' [ ] ( main:2 [ ] { } ) always clobbers reg byte a
REGISTER UPLIFT SCOPES
Uplift Scope [main]
Uplift Scope []
Uplifting [main] best 39 combination
Uplifting [] best 39 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test declarations of variables without definition
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
// The actual declarations
.label SCREEN = $400
// @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
// And a little code using them
main: {
// [4] *((const nomodify byte*) SCREEN) ← (byte) 'c' -- _deref_pbuc1=vbuc2
lda #'c'
sta SCREEN
// [5] *((const nomodify byte*) SCREEN+(byte) 1) ← (byte) 'm' -- _deref_pbuc1=vbuc2
lda #'m'
sta SCREEN+1
// [6] *((const nomodify byte*) SCREEN+(byte) 2) ← (byte) 'l' -- _deref_pbuc1=vbuc2
lda #'l'
sta SCREEN+2
jmp __breturn
// main::@return
__breturn:
// [7] return
rts
}
// File Data
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __bend
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __b1_from___bbegin:
Removing instruction __b1:
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 __bbegin:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(const nomodify byte*) SCREEN = (byte*) 1024
(byte) idx
(void()) main()
(label) main::@return
FINAL ASSEMBLER
Score: 24
// File Comments
// Test declarations of variables without definition
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
// The actual declarations
.label SCREEN = $400
// @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
// And a little code using them
main: {
// SCREEN[idx++] = 'c'
// [4] *((const nomodify byte*) SCREEN) ← (byte) 'c' -- _deref_pbuc1=vbuc2
lda #'c'
sta SCREEN
// SCREEN[idx++] = 'm'
// [5] *((const nomodify byte*) SCREEN+(byte) 1) ← (byte) 'm' -- _deref_pbuc1=vbuc2
lda #'m'
sta SCREEN+1
// SCREEN[idx++] = 'l'
// [6] *((const nomodify byte*) SCREEN+(byte) 2) ← (byte) 'l' -- _deref_pbuc1=vbuc2
lda #'l'
sta SCREEN+2
// main::@return
// }
// [7] return
rts
}
// File Data

View File

@ -0,0 +1,8 @@
(label) @1
(label) @begin
(label) @end
(const nomodify byte*) SCREEN = (byte*) 1024
(byte) idx
(void()) main()
(label) main::@return