mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-12-24 20:32:39 +00:00
Added support for empty statements. Closes #395
This commit is contained in:
parent
b195a3c545
commit
75e71b5bbb
@ -17728,3 +17728,7 @@ tax
|
||||
//FRAGMENT vbuyy=_byte_pwuc1_derefidx_vbuyy
|
||||
lda {c1},y
|
||||
tay
|
||||
//FRAGMENT vbuc1_ge_vbuaa_then_la1
|
||||
cmp #{c1}
|
||||
bcc {la1}
|
||||
beq {la1}
|
||||
|
@ -163,7 +163,7 @@ public class StatementSource implements Serializable {
|
||||
return new StatementSource(nodeStart, nodeStop);
|
||||
}
|
||||
|
||||
public static StatementSource kickAsm(KickCParser.DeclKasmContext ctx) {
|
||||
public static StatementSource kickAsm(KickCParser.KasmContentContext ctx) {
|
||||
ParseTree nodeStart = ctx.getChild(0);
|
||||
ParseTree nodeStop = ctx.getChild(0);
|
||||
return new StatementSource(nodeStart, nodeStop);
|
||||
|
@ -53,7 +53,7 @@ typeDef
|
||||
|
||||
declVariableInit
|
||||
: NAME declArray* ('=' expr)? #declVariableInitExpr
|
||||
| NAME declArray* '=' declKasm #declVariableInitKasm
|
||||
| NAME declArray* '=' kasmContent #declVariableInitKasm
|
||||
;
|
||||
|
||||
declType
|
||||
@ -189,7 +189,8 @@ stmt
|
||||
| BREAK ';' #stmtBreak
|
||||
| CONTINUE ';' #stmtContinue
|
||||
| ASM asmDirectives? CURLY_BEGIN asmLines ASM_CURLY_END #stmtAsm
|
||||
| declKasm #stmtDeclKasm
|
||||
| kasmContent #stmtDeclKasm
|
||||
| ';' #stmtEmpty
|
||||
;
|
||||
|
||||
switchCases:
|
||||
@ -254,7 +255,7 @@ parameterList
|
||||
: expr (COMMA expr)*
|
||||
;
|
||||
|
||||
declKasm
|
||||
kasmContent
|
||||
: KICKASM asmDirectives? KICKASM_BODY
|
||||
;
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -997,6 +997,18 @@ public class KickCParserBaseListener implements KickCParserListener {
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitStmtDeclKasm(KickCParser.StmtDeclKasmContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void enterStmtEmpty(KickCParser.StmtEmptyContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitStmtEmpty(KickCParser.StmtEmptyContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
@ -1386,13 +1398,13 @@ public class KickCParserBaseListener implements KickCParserListener {
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void enterDeclKasm(KickCParser.DeclKasmContext ctx) { }
|
||||
@Override public void enterKasmContent(KickCParser.KasmContentContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitDeclKasm(KickCParser.DeclKasmContext ctx) { }
|
||||
@Override public void exitKasmContent(KickCParser.KasmContentContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
|
@ -587,6 +587,13 @@ public class KickCParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> imple
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitStmtDeclKasm(KickCParser.StmtDeclKasmContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitStmtEmpty(KickCParser.StmtEmptyContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
@ -817,7 +824,7 @@ public class KickCParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> imple
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitDeclKasm(KickCParser.DeclKasmContext ctx) { return visitChildren(ctx); }
|
||||
@Override public T visitKasmContent(KickCParser.KasmContentContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
|
@ -949,6 +949,18 @@ public interface KickCParserListener extends ParseTreeListener {
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitStmtDeclKasm(KickCParser.StmtDeclKasmContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by the {@code stmtEmpty}
|
||||
* labeled alternative in {@link KickCParser#stmt}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void enterStmtEmpty(KickCParser.StmtEmptyContext ctx);
|
||||
/**
|
||||
* Exit a parse tree produced by the {@code stmtEmpty}
|
||||
* labeled alternative in {@link KickCParser#stmt}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitStmtEmpty(KickCParser.StmtEmptyContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by {@link KickCParser#switchCases}.
|
||||
* @param ctx the parse tree
|
||||
@ -1328,15 +1340,15 @@ public interface KickCParserListener extends ParseTreeListener {
|
||||
*/
|
||||
void exitParameterList(KickCParser.ParameterListContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by {@link KickCParser#declKasm}.
|
||||
* Enter a parse tree produced by {@link KickCParser#kasmContent}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void enterDeclKasm(KickCParser.DeclKasmContext ctx);
|
||||
void enterKasmContent(KickCParser.KasmContentContext ctx);
|
||||
/**
|
||||
* Exit a parse tree produced by {@link KickCParser#declKasm}.
|
||||
* Exit a parse tree produced by {@link KickCParser#kasmContent}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitDeclKasm(KickCParser.DeclKasmContext ctx);
|
||||
void exitKasmContent(KickCParser.KasmContentContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by {@link KickCParser#asmDirectives}.
|
||||
* @param ctx the parse tree
|
||||
|
@ -564,6 +564,13 @@ public interface KickCParserVisitor<T> extends ParseTreeVisitor<T> {
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitStmtDeclKasm(KickCParser.StmtDeclKasmContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code stmtEmpty}
|
||||
* labeled alternative in {@link KickCParser#stmt}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitStmtEmpty(KickCParser.StmtEmptyContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link KickCParser#switchCases}.
|
||||
* @param ctx the parse tree
|
||||
@ -786,11 +793,11 @@ public interface KickCParserVisitor<T> extends ParseTreeVisitor<T> {
|
||||
*/
|
||||
T visitParameterList(KickCParser.ParameterListContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link KickCParser#declKasm}.
|
||||
* Visit a parse tree produced by {@link KickCParser#kasmContent}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitDeclKasm(KickCParser.DeclKasmContext ctx);
|
||||
T visitKasmContent(KickCParser.KasmContentContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link KickCParser#asmDirectives}.
|
||||
* @param ctx the parse tree
|
||||
|
@ -442,8 +442,8 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
|
||||
@Override
|
||||
public Object visitStmtDeclKasm(KickCParser.StmtDeclKasmContext ctx) {
|
||||
final KickAsm kickAsm = (KickAsm) this.visit(ctx.declKasm());
|
||||
StatementKickAsm statementKickAsm = new StatementKickAsm(kickAsm.kickAsmCode, kickAsm.bytes, kickAsm.cycles, kickAsm.uses, kickAsm.declaredClobber, StatementSource.kickAsm(ctx.declKasm()), ensureUnusedComments(getCommentsSymbol(ctx)));
|
||||
final KickAsm kickAsm = (KickAsm) this.visit(ctx.kasmContent());
|
||||
StatementKickAsm statementKickAsm = new StatementKickAsm(kickAsm.kickAsmCode, kickAsm.bytes, kickAsm.cycles, kickAsm.uses, kickAsm.declaredClobber, StatementSource.kickAsm(ctx.kasmContent()), ensureUnusedComments(getCommentsSymbol(ctx)));
|
||||
addStatement(statementKickAsm);
|
||||
return statementKickAsm;
|
||||
}
|
||||
@ -467,7 +467,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
}
|
||||
|
||||
@Override
|
||||
public KickAsm visitDeclKasm(KickCParser.DeclKasmContext ctx) {
|
||||
public Object visitKasmContent(KickCParser.KasmContentContext ctx) {
|
||||
String kasmBody = ctx.KICKASM_BODY().getText();
|
||||
Pattern p = Pattern.compile("\\{\\{[\\s]*(.*)[\\s]*\\}\\}", Pattern.DOTALL);
|
||||
Matcher m = p.matcher(kasmBody);
|
||||
@ -1036,7 +1036,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
throw new CompileError("KickAsm initializers only supported for arrays " + varDecl.getEffectiveType().getTypeName(), statementSource);
|
||||
}
|
||||
// Add KickAsm statement
|
||||
KickAsm kasm = (KickAsm) this.visit(ctx.declKasm());
|
||||
KickAsm kasm = (KickAsm) this.visit(ctx.kasmContent());
|
||||
if(kasm.cycles != null) {
|
||||
throw new CompileError("KickAsm initializers does not support 'cycles' directive.", statementSource);
|
||||
}
|
||||
|
@ -42,6 +42,11 @@ public class TestPrograms {
|
||||
public TestPrograms() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStmtEmpty() throws IOException, URISyntaxException {
|
||||
compileAndCompare("stmt-empty.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyFunction2() throws IOException, URISyntaxException {
|
||||
compileAndCompare("empty-function-2.c");
|
||||
|
10
src/test/kc/stmt-empty.c
Normal file
10
src/test/kc/stmt-empty.c
Normal file
@ -0,0 +1,10 @@
|
||||
// Test an empty statement ';'
|
||||
|
||||
void main() {
|
||||
// Start with an empty statement
|
||||
;
|
||||
// Fill screen with '*'. Body is an empty statement.
|
||||
for( char * screen = 0x0400; screen<0x400+1000; (*screen++)='*') ;
|
||||
// End with two empty statements
|
||||
; ;
|
||||
}
|
35
src/test/ref/stmt-empty.asm
Normal file
35
src/test/ref/stmt-empty.asm
Normal file
@ -0,0 +1,35 @@
|
||||
// Test an empty statement ';'
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
main: {
|
||||
.label screen = 2
|
||||
lda #<$400
|
||||
sta.z screen
|
||||
lda #>$400
|
||||
sta.z screen+1
|
||||
// Fill screen with '*'. Body is an empty statement.
|
||||
__b1:
|
||||
// for( char * screen = 0x0400; screen<0x400+1000; (*screen++)='*')
|
||||
lda.z screen+1
|
||||
cmp #>$400+$3e8
|
||||
bcc __b2
|
||||
bne !+
|
||||
lda.z screen
|
||||
cmp #<$400+$3e8
|
||||
bcc __b2
|
||||
!:
|
||||
// }
|
||||
rts
|
||||
__b2:
|
||||
// (*screen++)='*'
|
||||
lda #'*'
|
||||
ldy #0
|
||||
sta (screen),y
|
||||
// for( char * screen = 0x0400; screen<0x400+1000; (*screen++)='*')
|
||||
inc.z screen
|
||||
bne !+
|
||||
inc.z screen+1
|
||||
!:
|
||||
jmp __b1
|
||||
}
|
16
src/test/ref/stmt-empty.cfg
Normal file
16
src/test/ref/stmt-empty.cfg
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
(void()) main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@2
|
||||
[1] (byte*) main::screen#2 ← phi( main/(byte*) 1024 main::@2/(byte*) main::screen#1 )
|
||||
[2] if((byte*) main::screen#2<(word)(number) $400+(number) $3e8) goto main::@2
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[3] return
|
||||
to:@return
|
||||
main::@2: scope:[main] from main::@1
|
||||
[4] *((byte*) main::screen#2) ← (byte) '*'
|
||||
[5] (byte*) main::screen#1 ← ++ (byte*) main::screen#2
|
||||
to:main::@1
|
300
src/test/ref/stmt-empty.log
Normal file
300
src/test/ref/stmt-empty.log
Normal file
@ -0,0 +1,300 @@
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
|
||||
(void()) main()
|
||||
main: scope:[main] from __start
|
||||
(byte*) main::screen#0 ← (byte*)(number) $400
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@2
|
||||
(byte*) main::screen#2 ← phi( main/(byte*) main::screen#0 main::@2/(byte*) main::screen#1 )
|
||||
(bool~) main::$0 ← (byte*) main::screen#2 < (number) $400+(number) $3e8
|
||||
if((bool~) main::$0) goto main::@2
|
||||
to:main::@return
|
||||
main::@2: scope:[main] from main::@1
|
||||
(byte*) main::screen#3 ← phi( main::@1/(byte*) main::screen#2 )
|
||||
*((byte*) main::screen#3) ← (byte) '*'
|
||||
(byte*) main::screen#1 ← ++ (byte*) main::screen#3
|
||||
to:main::@1
|
||||
main::@return: scope:[main] from main::@1
|
||||
return
|
||||
to:@return
|
||||
|
||||
(void()) __start()
|
||||
__start: scope:[__start] from
|
||||
call main
|
||||
to:__start::@1
|
||||
__start::@1: scope:[__start] from __start
|
||||
to:__start::@return
|
||||
__start::@return: scope:[__start] from __start::@1
|
||||
return
|
||||
to:@return
|
||||
|
||||
SYMBOL TABLE SSA
|
||||
(void()) __start()
|
||||
(label) __start::@1
|
||||
(label) __start::@return
|
||||
(void()) main()
|
||||
(bool~) main::$0
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@return
|
||||
(byte*) main::screen
|
||||
(byte*) main::screen#0
|
||||
(byte*) main::screen#1
|
||||
(byte*) main::screen#2
|
||||
(byte*) main::screen#3
|
||||
|
||||
Adding number conversion cast (unumber) $400+$3e8 in (bool~) main::$0 ← (byte*) main::screen#2 < (number) $400+(number) $3e8
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Simplifying constant pointer cast (byte*) 1024
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Alias main::screen#2 = main::screen#3
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Simple Condition (bool~) main::$0 [3] if((byte*) main::screen#2<(word)(number) $400+(number) $3e8) goto main::@2
|
||||
Successful SSA optimization Pass2ConditionalJumpSimplification
|
||||
Constant (const byte*) main::screen#0 = (byte*) 1024
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Removing unused procedure __start
|
||||
Removing unused procedure block __start
|
||||
Removing unused procedure block __start::@1
|
||||
Removing unused procedure block __start::@return
|
||||
Successful SSA optimization PassNEliminateEmptyStart
|
||||
Inlining constant with var siblings (const byte*) main::screen#0
|
||||
Constant inlined main::screen#0 = (byte*) 1024
|
||||
Successful SSA optimization Pass2ConstantInlining
|
||||
Adding NOP phi() at start of main
|
||||
CALL GRAPH
|
||||
|
||||
Created 1 initial phi equivalence classes
|
||||
Coalesced [6] main::screen#4 ← main::screen#1
|
||||
Coalesced down to 1 phi equivalence classes
|
||||
Adding NOP phi() at start of main
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
|
||||
(void()) main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@2
|
||||
[1] (byte*) main::screen#2 ← phi( main/(byte*) 1024 main::@2/(byte*) main::screen#1 )
|
||||
[2] if((byte*) main::screen#2<(word)(number) $400+(number) $3e8) goto main::@2
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[3] return
|
||||
to:@return
|
||||
main::@2: scope:[main] from main::@1
|
||||
[4] *((byte*) main::screen#2) ← (byte) '*'
|
||||
[5] (byte*) main::screen#1 ← ++ (byte*) main::screen#2
|
||||
to:main::@1
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
(void()) main()
|
||||
(byte*) main::screen
|
||||
(byte*) main::screen#1 22.0
|
||||
(byte*) main::screen#2 14.666666666666666
|
||||
|
||||
Initial phi equivalence classes
|
||||
[ main::screen#2 main::screen#1 ]
|
||||
Complete equivalence classes
|
||||
[ main::screen#2 main::screen#1 ]
|
||||
Allocated zp[2]:2 [ main::screen#2 main::screen#1 ]
|
||||
|
||||
INITIAL ASM
|
||||
Target platform is c64basic / MOS6502X
|
||||
// File Comments
|
||||
// Test an empty statement ';'
|
||||
// Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
// main
|
||||
main: {
|
||||
.label screen = 2
|
||||
// [1] phi from main to main::@1 [phi:main->main::@1]
|
||||
__b1_from_main:
|
||||
// [1] phi (byte*) main::screen#2 = (byte*) 1024 [phi:main->main::@1#0] -- pbuz1=pbuc1
|
||||
lda #<$400
|
||||
sta.z screen
|
||||
lda #>$400
|
||||
sta.z screen+1
|
||||
jmp __b1
|
||||
// Fill screen with '*'. Body is an empty statement.
|
||||
// main::@1
|
||||
__b1:
|
||||
// [2] if((byte*) main::screen#2<(word)(number) $400+(number) $3e8) goto main::@2 -- pbuz1_lt_vwuc1_then_la1
|
||||
lda.z screen+1
|
||||
cmp #>$400+$3e8
|
||||
bcc __b2
|
||||
bne !+
|
||||
lda.z screen
|
||||
cmp #<$400+$3e8
|
||||
bcc __b2
|
||||
!:
|
||||
jmp __breturn
|
||||
// main::@return
|
||||
__breturn:
|
||||
// [3] return
|
||||
rts
|
||||
// main::@2
|
||||
__b2:
|
||||
// [4] *((byte*) main::screen#2) ← (byte) '*' -- _deref_pbuz1=vbuc1
|
||||
lda #'*'
|
||||
ldy #0
|
||||
sta (screen),y
|
||||
// [5] (byte*) main::screen#1 ← ++ (byte*) main::screen#2 -- pbuz1=_inc_pbuz1
|
||||
inc.z screen
|
||||
bne !+
|
||||
inc.z screen+1
|
||||
!:
|
||||
// [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
|
||||
__b1_from___b2:
|
||||
// [1] phi (byte*) main::screen#2 = (byte*) main::screen#1 [phi:main::@2->main::@1#0] -- register_copy
|
||||
jmp __b1
|
||||
}
|
||||
// File Data
|
||||
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [2] if((byte*) main::screen#2<(word)(number) $400+(number) $3e8) goto main::@2 [ main::screen#2 ] ( [ main::screen#2 ] { } ) always clobbers reg byte a
|
||||
Statement [4] *((byte*) main::screen#2) ← (byte) '*' [ main::screen#2 ] ( [ main::screen#2 ] { } ) always clobbers reg byte a reg byte y
|
||||
Potential registers zp[2]:2 [ main::screen#2 main::screen#1 ] : zp[2]:2 ,
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [main] 36.67: zp[2]:2 [ main::screen#2 main::screen#1 ]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [main] best 596 combination zp[2]:2 [ main::screen#2 main::screen#1 ]
|
||||
Uplifting [] best 596 combination
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
// File Comments
|
||||
// Test an empty statement ';'
|
||||
// Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
// main
|
||||
main: {
|
||||
.label screen = 2
|
||||
// [1] phi from main to main::@1 [phi:main->main::@1]
|
||||
__b1_from_main:
|
||||
// [1] phi (byte*) main::screen#2 = (byte*) 1024 [phi:main->main::@1#0] -- pbuz1=pbuc1
|
||||
lda #<$400
|
||||
sta.z screen
|
||||
lda #>$400
|
||||
sta.z screen+1
|
||||
jmp __b1
|
||||
// Fill screen with '*'. Body is an empty statement.
|
||||
// main::@1
|
||||
__b1:
|
||||
// [2] if((byte*) main::screen#2<(word)(number) $400+(number) $3e8) goto main::@2 -- pbuz1_lt_vwuc1_then_la1
|
||||
lda.z screen+1
|
||||
cmp #>$400+$3e8
|
||||
bcc __b2
|
||||
bne !+
|
||||
lda.z screen
|
||||
cmp #<$400+$3e8
|
||||
bcc __b2
|
||||
!:
|
||||
jmp __breturn
|
||||
// main::@return
|
||||
__breturn:
|
||||
// [3] return
|
||||
rts
|
||||
// main::@2
|
||||
__b2:
|
||||
// [4] *((byte*) main::screen#2) ← (byte) '*' -- _deref_pbuz1=vbuc1
|
||||
lda #'*'
|
||||
ldy #0
|
||||
sta (screen),y
|
||||
// [5] (byte*) main::screen#1 ← ++ (byte*) main::screen#2 -- pbuz1=_inc_pbuz1
|
||||
inc.z screen
|
||||
bne !+
|
||||
inc.z screen+1
|
||||
!:
|
||||
// [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
|
||||
__b1_from___b2:
|
||||
// [1] phi (byte*) main::screen#2 = (byte*) main::screen#1 [phi:main::@2->main::@1#0] -- register_copy
|
||||
jmp __b1
|
||||
}
|
||||
// File Data
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp __b1
|
||||
Removing instruction jmp __breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Removing instruction __b1_from_main:
|
||||
Removing instruction __breturn:
|
||||
Removing instruction __b1_from___b2:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
(void()) main()
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@return
|
||||
(byte*) main::screen
|
||||
(byte*) main::screen#1 screen zp[2]:2 22.0
|
||||
(byte*) main::screen#2 screen zp[2]:2 14.666666666666666
|
||||
|
||||
zp[2]:2 [ main::screen#2 main::screen#1 ]
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 536
|
||||
|
||||
// File Comments
|
||||
// Test an empty statement ';'
|
||||
// Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
// main
|
||||
main: {
|
||||
.label screen = 2
|
||||
// [1] phi from main to main::@1 [phi:main->main::@1]
|
||||
// [1] phi (byte*) main::screen#2 = (byte*) 1024 [phi:main->main::@1#0] -- pbuz1=pbuc1
|
||||
lda #<$400
|
||||
sta.z screen
|
||||
lda #>$400
|
||||
sta.z screen+1
|
||||
// Fill screen with '*'. Body is an empty statement.
|
||||
// main::@1
|
||||
__b1:
|
||||
// for( char * screen = 0x0400; screen<0x400+1000; (*screen++)='*')
|
||||
// [2] if((byte*) main::screen#2<(word)(number) $400+(number) $3e8) goto main::@2 -- pbuz1_lt_vwuc1_then_la1
|
||||
lda.z screen+1
|
||||
cmp #>$400+$3e8
|
||||
bcc __b2
|
||||
bne !+
|
||||
lda.z screen
|
||||
cmp #<$400+$3e8
|
||||
bcc __b2
|
||||
!:
|
||||
// main::@return
|
||||
// }
|
||||
// [3] return
|
||||
rts
|
||||
// main::@2
|
||||
__b2:
|
||||
// (*screen++)='*'
|
||||
// [4] *((byte*) main::screen#2) ← (byte) '*' -- _deref_pbuz1=vbuc1
|
||||
lda #'*'
|
||||
ldy #0
|
||||
sta (screen),y
|
||||
// for( char * screen = 0x0400; screen<0x400+1000; (*screen++)='*')
|
||||
// [5] (byte*) main::screen#1 ← ++ (byte*) main::screen#2 -- pbuz1=_inc_pbuz1
|
||||
inc.z screen
|
||||
bne !+
|
||||
inc.z screen+1
|
||||
!:
|
||||
// [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
|
||||
// [1] phi (byte*) main::screen#2 = (byte*) main::screen#1 [phi:main::@2->main::@1#0] -- register_copy
|
||||
jmp __b1
|
||||
}
|
||||
// File Data
|
||||
|
9
src/test/ref/stmt-empty.sym
Normal file
9
src/test/ref/stmt-empty.sym
Normal file
@ -0,0 +1,9 @@
|
||||
(void()) main()
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@return
|
||||
(byte*) main::screen
|
||||
(byte*) main::screen#1 screen zp[2]:2 22.0
|
||||
(byte*) main::screen#2 screen zp[2]:2 14.666666666666666
|
||||
|
||||
zp[2]:2 [ main::screen#2 main::screen#1 ]
|
Loading…
Reference in New Issue
Block a user