From bc0fcc50fd5c312691b7a852c023c52379590770 Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Mon, 2 Aug 2021 22:30:04 +0200 Subject: [PATCH] Added NULL pointer to standard library. Closes #647 --- .../cache/fragment-cache-mos6502x.asm | 185 +++++++++ .../passes/Pass2ConstantIdentification.java | 6 +- .../kickc/passes/PassNAssertTypeMatch.java | 11 + src/main/kc/include/stddef.h | 9 + src/main/kc/include/stdio.h | 1 + src/main/kc/include/stdlib.h | 1 + src/main/kc/include/string.h | 3 +- .../kickc/test/TestProgramsFast.java | 5 + src/test/kc/null-constant.c | 16 + src/test/ref/null-constant.asm | 64 +++ src/test/ref/null-constant.cfg | 18 + src/test/ref/null-constant.log | 372 ++++++++++++++++++ src/test/ref/null-constant.sym | 11 + src/test/ref/plus4-keyboard-test.asm | 1 + src/test/ref/plus4-keyboard-test.log | 2 + src/test/ref/sieve-min.asm | 1 + src/test/ref/sieve-min.log | 2 + 17 files changed, 705 insertions(+), 3 deletions(-) create mode 100644 src/main/kc/include/stddef.h create mode 100644 src/test/kc/null-constant.c create mode 100644 src/test/ref/null-constant.asm create mode 100644 src/test/ref/null-constant.cfg create mode 100644 src/test/ref/null-constant.log create mode 100644 src/test/ref/null-constant.sym diff --git a/src/main/fragment/cache/fragment-cache-mos6502x.asm b/src/main/fragment/cache/fragment-cache-mos6502x.asm index e9d327d49..47fbcc615 100644 --- a/src/main/fragment/cache/fragment-cache-mos6502x.asm +++ b/src/main/fragment/cache/fragment-cache-mos6502x.asm @@ -15573,3 +15573,188 @@ sta {z1} bcc !+ inc {z1}+1 !: +//FRAGMENT vbum1=vbum2_rol_5 +lda {m2} +asl +asl +asl +asl +asl +sta {m1} +//FRAGMENT vbum1=vbum2_rol_1 +lda {m2} +asl +sta {m1} +//FRAGMENT _deref_pssc1=pssc2_derefidx_vbum1_memcpy_vbuc3 +ldx {m1} +ldy #0 +!: +lda {c2},x +sta {c1},y +inx +iny +cpy #{c3} +bne !- +//FRAGMENT pbuc1_derefidx_vbum1=_deref_pbuc2 +lda {c2} +ldy {m1} +sta {c1},y +//FRAGMENT vbum1=vbuaa_rol_5 +asl +asl +asl +asl +asl +sta {m1} +//FRAGMENT vbum1=vbuxx_rol_5 +txa +asl +asl +asl +asl +asl +sta {m1} +//FRAGMENT vbum1=vbuyy_rol_5 +tya +asl +asl +asl +asl +asl +sta {m1} +//FRAGMENT vbuaa=vbum1_rol_5 +lda {m1} +asl +asl +asl +asl +asl +//FRAGMENT vbuaa=vbuaa_rol_5 +asl +asl +asl +asl +asl +//FRAGMENT vbuaa=vbuxx_rol_5 +txa +asl +asl +asl +asl +asl +//FRAGMENT vbuaa=vbuyy_rol_5 +tya +asl +asl +asl +asl +asl +//FRAGMENT vbuxx=vbum1_rol_5 +lda {m1} +asl +asl +asl +asl +asl +tax +//FRAGMENT vbuxx=vbuaa_rol_5 +asl +asl +asl +asl +asl +tax +//FRAGMENT vbuxx=vbuxx_rol_5 +txa +asl +asl +asl +asl +asl +tax +//FRAGMENT vbuxx=vbuyy_rol_5 +tya +asl +asl +asl +asl +asl +tax +//FRAGMENT vbuyy=vbum1_rol_5 +lda {m1} +asl +asl +asl +asl +asl +tay +//FRAGMENT vbuyy=vbuaa_rol_5 +asl +asl +asl +asl +asl +tay +//FRAGMENT vbuyy=vbuxx_rol_5 +txa +asl +asl +asl +asl +asl +tay +//FRAGMENT vbuyy=vbuyy_rol_5 +tya +asl +asl +asl +asl +asl +tay +//FRAGMENT vbum1=vbuaa_rol_1 +asl +sta {m1} +//FRAGMENT vbum1=vbuxx_rol_1 +txa +asl +sta {m1} +//FRAGMENT vbum1=vbuyy_rol_1 +tya +asl +sta {m1} +//FRAGMENT vbuaa=vbum1_rol_1 +lda {m1} +asl +//FRAGMENT vbuxx=vbum1_rol_1 +lda {m1} +asl +tax +//FRAGMENT vbuyy=vbum1_rol_1 +lda {m1} +asl +tay +//FRAGMENT pbuz1=qbuz2_derefidx_vbuc1 +ldy #{c1} +lda ({z2}),y +sta {z1} +iny +lda ({z2}),y +sta {z1}+1 +//FRAGMENT vwuz1=pwuz2_derefidx_vbuc1 +ldy #{c1} +lda ({z2}),y +sta {z1} +iny +lda ({z2}),y +sta {z1}+1 +//FRAGMENT _deref_(_deref_qbuz1)=vbuc1 +lda #{c1} +pha +ldy #1 +lda ({z1}),y +sta $ff +dey +lda ({z1}),y +sta $fe +pla +sta ($fe),y diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java b/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java index bf98717b2..38d1798bf 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java @@ -18,6 +18,7 @@ import dk.camelot64.kickc.model.symbols.Variable; import dk.camelot64.kickc.model.types.SymbolType; import dk.camelot64.kickc.model.types.SymbolTypeConversion; import dk.camelot64.kickc.model.types.SymbolTypeInference; +import dk.camelot64.kickc.model.types.SymbolTypePointer; import dk.camelot64.kickc.model.values.*; import dk.camelot64.kickc.passes.utils.VarAssignments; @@ -57,7 +58,10 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization { continue; } - if(!SymbolTypeConversion.assignmentTypeMatch(variableType, valueType)) { + if(variableType instanceof SymbolTypePointer && constVal instanceof ConstantInteger && ((ConstantInteger) constVal).getInteger().equals(0L)) + // NULL pointer assigment is OK + ; + else if(!SymbolTypeConversion.assignmentTypeMatch(variableType, valueType)) { ConstantLiteral constantLiteral = null; try { constantLiteral = constVal.calculateLiteral(getScope()); diff --git a/src/main/java/dk/camelot64/kickc/passes/PassNAssertTypeMatch.java b/src/main/java/dk/camelot64/kickc/passes/PassNAssertTypeMatch.java index 807dc6cbb..03008d8d2 100644 --- a/src/main/java/dk/camelot64/kickc/passes/PassNAssertTypeMatch.java +++ b/src/main/java/dk/camelot64/kickc/passes/PassNAssertTypeMatch.java @@ -9,8 +9,11 @@ import dk.camelot64.kickc.model.symbols.Variable; import dk.camelot64.kickc.model.types.SymbolType; import dk.camelot64.kickc.model.types.SymbolTypeConversion; import dk.camelot64.kickc.model.types.SymbolTypeInference; +import dk.camelot64.kickc.model.types.SymbolTypePointer; import dk.camelot64.kickc.model.values.AssignmentRValue; +import dk.camelot64.kickc.model.values.ConstantInteger; import dk.camelot64.kickc.model.values.LValue; +import dk.camelot64.kickc.model.values.RValue; /** * Asserts that types match in all assignments and calculations @@ -52,6 +55,14 @@ public class PassNAssertTypeMatch extends Pass2SsaAssertion { private void checkAssignment(StatementAssignment statement) { LValue lValue = statement.getlValue(); SymbolType lValueType = SymbolTypeInference.inferType(getScope(), lValue); + // Test NULL pointer assignment + if(lValueType instanceof SymbolTypePointer) { + final RValue rValue = statement.getrValue2(); + if(rValue instanceof ConstantInteger && ((ConstantInteger) rValue).getInteger().equals(0L)) + // A null-pointer assignment is OK! + return; + } + SymbolType rValueType = SymbolTypeInference.inferType(getScope(), new AssignmentRValue(statement)); if(SymbolTypeConversion.assignmentTypeMatch(lValueType, rValueType)) return; // Types do not match diff --git a/src/main/kc/include/stddef.h b/src/main/kc/include/stddef.h new file mode 100644 index 000000000..f870e1008 --- /dev/null +++ b/src/main/kc/include/stddef.h @@ -0,0 +1,9 @@ + +#ifndef _HAVE_NULL +/// NULL pointer +#define NULL 0 +#define _HAVE_NULL +#endif + +/// The unsigned integral type that is the result of the sizeof keyword. +typedef unsigned int size_t ; \ No newline at end of file diff --git a/src/main/kc/include/stdio.h b/src/main/kc/include/stdio.h index 0088e4471..6d52f33c1 100644 --- a/src/main/kc/include/stdio.h +++ b/src/main/kc/include/stdio.h @@ -1,4 +1,5 @@ /// @file /// Functions for performing input and output. +#include #include \ No newline at end of file diff --git a/src/main/kc/include/stdlib.h b/src/main/kc/include/stdlib.h index b0e1a1639..2df4223a8 100644 --- a/src/main/kc/include/stdlib.h +++ b/src/main/kc/include/stdlib.h @@ -2,6 +2,7 @@ /// C standard library stdlib.h /// /// Implementation of functions found int C stdlib.h / stdlib.c +#include #include /// Allocates a block of size chars of memory, returning a pointer to the beginning of the block. diff --git a/src/main/kc/include/string.h b/src/main/kc/include/string.h index ec2f98e37..7ad36d381 100644 --- a/src/main/kc/include/string.h +++ b/src/main/kc/include/string.h @@ -2,8 +2,7 @@ /// C standard library string.h /// /// Functions to manipulate C strings and arrays. - -typedef unsigned int size_t ; +#include /// Copy block of memory (forwards) /// Copies the values of num chars from the location pointed to by source directly to the memory block pointed to by destination. diff --git a/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java b/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java index 3ed59dc8e..50774bc6b 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java +++ b/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java @@ -14,6 +14,11 @@ public class TestProgramsFast extends TestPrograms { // compileAndCompare("shadow-variable-error-1.c"); //} + @Test + public void testNullConstant() throws IOException { + compileAndCompare("null-constant.c"); + } + @Test public void testBlockError2() throws IOException { compileAndCompare("block-error-2.c"); diff --git a/src/test/kc/null-constant.c b/src/test/kc/null-constant.c new file mode 100644 index 000000000..e7d18457d --- /dev/null +++ b/src/test/kc/null-constant.c @@ -0,0 +1,16 @@ +// Test the NULL pointer + +#include + +char * screen = NULL; + +char * ptrs[] = { (char*)0x400, (char*)0x450, (char*)0x4a0, NULL }; + +void main() { + for(char ** ptr = ptrs; *ptr; ptr++) { + **ptr = 'a'; + screen = *ptr; + screen[1] = 'b'; + } + +} \ No newline at end of file diff --git a/src/test/ref/null-constant.asm b/src/test/ref/null-constant.asm new file mode 100644 index 000000000..71da12919 --- /dev/null +++ b/src/test/ref/null-constant.asm @@ -0,0 +1,64 @@ +// Test the NULL pointer + // Commodore 64 PRG executable file +.file [name="null-constant.prg", type="prg", segments="Program"] +.segmentdef Program [segments="Basic, Code, Data"] +.segmentdef Basic [start=$0801] +.segmentdef Code [start=$80d] +.segmentdef Data [startAfter="Code"] +.segment Basic +:BasicUpstart(main) + .const SIZEOF_POINTER = 2 + .label screen = 4 +.segment Code +main: { + .label ptr = 2 + lda #ptrs + sta.z ptr+1 + __b1: + // for(char ** ptr = ptrs; *ptr; ptr++) + ldy #0 + tya + cmp (ptr),y + bne __b2 + iny + cmp (ptr),y + bne __b2 + // } + rts + __b2: + // **ptr = 'a' + lda #'a' + pha + ldy #1 + lda (ptr),y + sta.z $ff + dey + lda (ptr),y + sta.z $fe + pla + sta ($fe),y + // screen = *ptr + ldy #0 + lda (ptr),y + sta.z screen + iny + lda (ptr),y + sta.z screen+1 + // screen[1] = 'b' + lda #'b' + ldy #1 + sta (screen),y + // for(char ** ptr = ptrs; *ptr; ptr++) + lda #SIZEOF_POINTER + clc + adc.z ptr + sta.z ptr + bcc !+ + inc.z ptr+1 + !: + jmp __b1 +} +.segment Data + ptrs: .word $400, $450, $4a0, 0 diff --git a/src/test/ref/null-constant.cfg b/src/test/ref/null-constant.cfg new file mode 100644 index 000000000..dff0d0686 --- /dev/null +++ b/src/test/ref/null-constant.cfg @@ -0,0 +1,18 @@ + +void main() +main: scope:[main] from + [0] phi() + to:main::@1 +main::@1: scope:[main] from main main::@2 + [1] main::ptr#2 = phi( main/ptrs, main::@2/main::ptr#1 ) + [2] if((byte*)0!=*main::ptr#2) 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] *(*main::ptr#2) = 'a' + [5] screen#0 = *main::ptr#2 + [6] screen#0[1] = 'b' + [7] main::ptr#1 = main::ptr#2 + SIZEOF_POINTER + to:main::@1 diff --git a/src/test/ref/null-constant.log b/src/test/ref/null-constant.log new file mode 100644 index 000000000..76b966ecd --- /dev/null +++ b/src/test/ref/null-constant.log @@ -0,0 +1,372 @@ +Inlined call call __init + +CONTROL FLOW GRAPH SSA + +void main() +main: scope:[main] from __start::@1 + screen#10 = phi( __start::@1/screen#9 ) + main::ptr#0 = ptrs + to:main::@1 +main::@1: scope:[main] from main main::@2 + screen#8 = phi( main/screen#10, main::@2/screen#0 ) + main::ptr#2 = phi( main/main::ptr#0, main::@2/main::ptr#1 ) + main::$0 = (byte*)0 != *main::ptr#2 + if(main::$0) goto main::@2 + to:main::@return +main::@2: scope:[main] from main::@1 + main::ptr#3 = phi( main::@1/main::ptr#2 ) + *(*main::ptr#3) = 'a' + screen#0 = *main::ptr#3 + screen#0[1] = 'b' + main::ptr#1 = main::ptr#3 + SIZEOF_POINTER + to:main::@1 +main::@return: scope:[main] from main::@1 + screen#5 = phi( main::@1/screen#8 ) + screen#1 = screen#5 + return + to:@return + +void __start() +__start: scope:[__start] from + to:__start::__init1 +__start::__init1: scope:[__start] from __start + screen#2 = 0 + to:__start::@1 +__start::@1: scope:[__start] from __start::__init1 + screen#9 = phi( __start::__init1/screen#2 ) + call main + to:__start::@2 +__start::@2: scope:[__start] from __start::@1 + screen#6 = phi( __start::@1/screen#1 ) + screen#3 = screen#6 + to:__start::@return +__start::@return: scope:[__start] from __start::@2 + screen#7 = phi( __start::@2/screen#3 ) + screen#4 = screen#7 + return + to:@return + +SYMBOL TABLE SSA +constant byte SIZEOF_POINTER = 2 +void __start() +void main() +bool~ main::$0 +byte** main::ptr +byte** main::ptr#0 +byte** main::ptr#1 +byte** main::ptr#2 +byte** main::ptr#3 +constant byte** ptrs[] = { (byte*)$400, (byte*)$450, (byte*)$4a0, 0 } +byte* screen +byte* screen#0 +byte* screen#1 +byte* screen#10 +byte* screen#2 +byte* screen#3 +byte* screen#4 +byte* screen#5 +byte* screen#6 +byte* screen#7 +byte* screen#8 +byte* screen#9 + +Adding number conversion cast (unumber) 1 in screen#0[1] = 'b' +Adding number conversion cast (unumber) 0 in screen#2 = 0 +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast screen#2 = (unumber)0 +Successful SSA optimization Pass2InlineCast +Simplifying constant pointer cast (byte*) 1024 +Simplifying constant pointer cast (byte*) 1104 +Simplifying constant pointer cast (byte*) 1184 +Simplifying constant integer cast 1 +Simplifying constant integer cast 0 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 1 +Finalized unsigned number type (byte) 0 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Alias main::ptr#2 = main::ptr#3 +Alias screen#1 = screen#5 screen#8 +Alias screen#2 = screen#9 +Alias screen#3 = screen#6 screen#7 screen#4 +Successful SSA optimization Pass2AliasElimination +Identical Phi Values screen#10 screen#2 +Identical Phi Values screen#3 screen#1 +Successful SSA optimization Pass2IdenticalPhiElimination +Simple Condition main::$0 [4] if((byte*)0!=*main::ptr#2) goto main::@2 +Successful SSA optimization Pass2ConditionalJumpSimplification +Constant main::ptr#0 = ptrs +Constant screen#2 = 0 +Successful SSA optimization Pass2ConstantIdentification +Eliminating unused variable - keeping the phi block screen#1 +Successful SSA optimization PassNEliminateUnusedVars +Eliminating unused constant screen#2 +Successful SSA optimization PassNEliminateUnusedVars +Removing unused procedure __start +Removing unused procedure block __start +Removing unused procedure block __start::__init1 +Removing unused procedure block __start::@1 +Removing unused procedure block __start::@2 +Removing unused procedure block __start::@return +Successful SSA optimization PassNEliminateEmptyStart +Inlining constant with var siblings main::ptr#0 +Constant inlined main::ptr#0 = ptrs +Successful SSA optimization Pass2ConstantInlining +Finalized unsigned number type (byte) 0 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Adding NOP phi() at start of main +CALL GRAPH + +Created 1 initial phi equivalence classes +Coalesced [8] main::ptr#4 = main::ptr#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] main::ptr#2 = phi( main/ptrs, main::@2/main::ptr#1 ) + [2] if((byte*)0!=*main::ptr#2) 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] *(*main::ptr#2) = 'a' + [5] screen#0 = *main::ptr#2 + [6] screen#0[1] = 'b' + [7] main::ptr#1 = main::ptr#2 + SIZEOF_POINTER + to:main::@1 + + +VARIABLE REGISTER WEIGHTS +void main() +byte** main::ptr +byte** main::ptr#1 22.0 +byte** main::ptr#2 11.0 +byte* screen +byte* screen#0 22.0 + +Initial phi equivalence classes +[ main::ptr#2 main::ptr#1 ] +Added variable screen#0 to live range equivalence class [ screen#0 ] +Complete equivalence classes +[ main::ptr#2 main::ptr#1 ] +[ screen#0 ] +Allocated zp[2]:2 [ main::ptr#2 main::ptr#1 ] +Allocated zp[2]:4 [ screen#0 ] +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [2] if((byte*)0!=*main::ptr#2) goto main::@2 [ main::ptr#2 ] ( [ main::ptr#2 ] { } ) always clobbers reg byte a reg byte y +Statement [4] *(*main::ptr#2) = 'a' [ main::ptr#2 ] ( [ main::ptr#2 ] { } ) always clobbers reg byte a reg byte y +Statement [5] screen#0 = *main::ptr#2 [ main::ptr#2 screen#0 ] ( [ main::ptr#2 screen#0 ] { } ) always clobbers reg byte a reg byte y +Statement [6] screen#0[1] = 'b' [ main::ptr#2 ] ( [ main::ptr#2 ] { } ) always clobbers reg byte a reg byte y +Statement [7] main::ptr#1 = main::ptr#2 + SIZEOF_POINTER [ main::ptr#1 ] ( [ main::ptr#1 ] { } ) always clobbers reg byte a +Potential registers zp[2]:2 [ main::ptr#2 main::ptr#1 ] : zp[2]:2 , +Potential registers zp[2]:4 [ screen#0 ] : zp[2]:4 , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 33: zp[2]:2 [ main::ptr#2 main::ptr#1 ] +Uplift Scope [] 22: zp[2]:4 [ screen#0 ] + +Uplifting [main] best 1281 combination zp[2]:2 [ main::ptr#2 main::ptr#1 ] +Uplifting [] best 1281 combination zp[2]:4 [ screen#0 ] + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Test the NULL pointer + // Upstart + // Commodore 64 PRG executable file +.file [name="null-constant.prg", type="prg", segments="Program"] +.segmentdef Program [segments="Basic, Code, Data"] +.segmentdef Basic [start=$0801] +.segmentdef Code [start=$80d] +.segmentdef Data [startAfter="Code"] +.segment Basic +:BasicUpstart(main) + // Global Constants & labels + .const SIZEOF_POINTER = 2 + .label screen = 4 +.segment Code + // main +main: { + .label ptr = 2 + // [1] phi from main to main::@1 [phi:main->main::@1] + __b1_from_main: + // [1] phi main::ptr#2 = ptrs [phi:main->main::@1#0] -- qbuz1=qbuc1 + lda #ptrs + sta.z ptr+1 + jmp __b1 + // main::@1 + __b1: + // [2] if((byte*)0!=*main::ptr#2) goto main::@2 -- pbuc1_neq__deref_qbuz1_then_la1 + ldy #0 + lda #<0 + cmp (ptr),y + bne __b2 + iny + lda #>0 + cmp (ptr),y + bne __b2 + jmp __breturn + // main::@return + __breturn: + // [3] return + rts + // main::@2 + __b2: + // [4] *(*main::ptr#2) = 'a' -- _deref_(_deref_qbuz1)=vbuc1 + lda #'a' + pha + ldy #1 + lda (ptr),y + sta.z $ff + dey + lda (ptr),y + sta.z $fe + pla + sta ($fe),y + // [5] screen#0 = *main::ptr#2 -- pbuz1=_deref_qbuz2 + ldy #0 + lda (ptr),y + sta.z screen + iny + lda (ptr),y + sta.z screen+1 + // [6] screen#0[1] = 'b' -- pbuz1_derefidx_vbuc1=vbuc2 + lda #'b' + ldy #1 + sta (screen),y + // [7] main::ptr#1 = main::ptr#2 + SIZEOF_POINTER -- qbuz1=qbuz1_plus_vbuc1 + lda #SIZEOF_POINTER + clc + adc.z ptr + sta.z ptr + bcc !+ + inc.z ptr+1 + !: + // [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1] + __b1_from___b2: + // [1] phi main::ptr#2 = main::ptr#1 [phi:main::@2->main::@1#0] -- register_copy + jmp __b1 +} + // File Data +.segment Data + ptrs: .word $400, $450, $4a0, 0 + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp __b1 +Removing instruction jmp __breturn +Succesful ASM optimization Pass5NextJumpElimination +Replacing instruction lda #<0 with TYA +Removing instruction lda #>0 +Succesful ASM optimization Pass5UnnecesaryLoadElimination +Removing instruction __b1_from_main: +Removing instruction __breturn: +Removing instruction __b1_from___b2: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +constant byte SIZEOF_POINTER = 2 +void main() +byte** main::ptr +byte** main::ptr#1 ptr zp[2]:2 22.0 +byte** main::ptr#2 ptr zp[2]:2 11.0 +constant byte** ptrs[] = { (byte*) 1024, (byte*) 1104, (byte*) 1184, 0 } +byte* screen +byte* screen#0 screen zp[2]:4 22.0 + +zp[2]:2 [ main::ptr#2 main::ptr#1 ] +zp[2]:4 [ screen#0 ] + + +FINAL ASSEMBLER +Score: 1201 + + // File Comments +// Test the NULL pointer + // Upstart + // Commodore 64 PRG executable file +.file [name="null-constant.prg", type="prg", segments="Program"] +.segmentdef Program [segments="Basic, Code, Data"] +.segmentdef Basic [start=$0801] +.segmentdef Code [start=$80d] +.segmentdef Data [startAfter="Code"] +.segment Basic +:BasicUpstart(main) + // Global Constants & labels + .const SIZEOF_POINTER = 2 + .label screen = 4 +.segment Code + // main +main: { + .label ptr = 2 + // [1] phi from main to main::@1 [phi:main->main::@1] + // [1] phi main::ptr#2 = ptrs [phi:main->main::@1#0] -- qbuz1=qbuc1 + lda #ptrs + sta.z ptr+1 + // main::@1 + __b1: + // for(char ** ptr = ptrs; *ptr; ptr++) + // [2] if((byte*)0!=*main::ptr#2) goto main::@2 -- pbuc1_neq__deref_qbuz1_then_la1 + ldy #0 + tya + cmp (ptr),y + bne __b2 + iny + cmp (ptr),y + bne __b2 + // main::@return + // } + // [3] return + rts + // main::@2 + __b2: + // **ptr = 'a' + // [4] *(*main::ptr#2) = 'a' -- _deref_(_deref_qbuz1)=vbuc1 + lda #'a' + pha + ldy #1 + lda (ptr),y + sta.z $ff + dey + lda (ptr),y + sta.z $fe + pla + sta ($fe),y + // screen = *ptr + // [5] screen#0 = *main::ptr#2 -- pbuz1=_deref_qbuz2 + ldy #0 + lda (ptr),y + sta.z screen + iny + lda (ptr),y + sta.z screen+1 + // screen[1] = 'b' + // [6] screen#0[1] = 'b' -- pbuz1_derefidx_vbuc1=vbuc2 + lda #'b' + ldy #1 + sta (screen),y + // for(char ** ptr = ptrs; *ptr; ptr++) + // [7] main::ptr#1 = main::ptr#2 + SIZEOF_POINTER -- qbuz1=qbuz1_plus_vbuc1 + lda #SIZEOF_POINTER + clc + adc.z ptr + sta.z ptr + bcc !+ + inc.z ptr+1 + !: + // [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1] + // [1] phi main::ptr#2 = main::ptr#1 [phi:main::@2->main::@1#0] -- register_copy + jmp __b1 +} + // File Data +.segment Data + ptrs: .word $400, $450, $4a0, 0 + diff --git a/src/test/ref/null-constant.sym b/src/test/ref/null-constant.sym new file mode 100644 index 000000000..f4540203a --- /dev/null +++ b/src/test/ref/null-constant.sym @@ -0,0 +1,11 @@ +constant byte SIZEOF_POINTER = 2 +void main() +byte** main::ptr +byte** main::ptr#1 ptr zp[2]:2 22.0 +byte** main::ptr#2 ptr zp[2]:2 11.0 +constant byte** ptrs[] = { (byte*) 1024, (byte*) 1104, (byte*) 1184, 0 } +byte* screen +byte* screen#0 screen zp[2]:4 22.0 + +zp[2]:2 [ main::ptr#2 main::ptr#1 ] +zp[2]:4 [ screen#0 ] diff --git a/src/test/ref/plus4-keyboard-test.asm b/src/test/ref/plus4-keyboard-test.asm index 8d5336c8e..65b2e96f4 100644 --- a/src/test/ref/plus4-keyboard-test.asm +++ b/src/test/ref/plus4-keyboard-test.asm @@ -3,6 +3,7 @@ /// C standard library string.h /// /// Functions to manipulate C strings and arrays. +/// NULL pointer // Commodore 16 / Plus/4 executable PRG file .file [name="plus4-keyboard-test.prg", type="prg", segments="Program"] .segmentdef Program [segments="Basic, Code, Data"] diff --git a/src/test/ref/plus4-keyboard-test.log b/src/test/ref/plus4-keyboard-test.log index f307fb288..a81c2dd14 100644 --- a/src/test/ref/plus4-keyboard-test.log +++ b/src/test/ref/plus4-keyboard-test.log @@ -547,6 +547,7 @@ ASSEMBLER BEFORE OPTIMIZATION /// C standard library string.h /// /// Functions to manipulate C strings and arrays. +/// NULL pointer // Upstart // Commodore 16 / Plus/4 executable PRG file .file [name="plus4-keyboard-test.prg", type="prg", segments="Program"] @@ -800,6 +801,7 @@ Score: 7354 /// C standard library string.h /// /// Functions to manipulate C strings and arrays. +/// NULL pointer // Upstart // Commodore 16 / Plus/4 executable PRG file .file [name="plus4-keyboard-test.prg", type="prg", segments="Program"] diff --git a/src/test/ref/sieve-min.asm b/src/test/ref/sieve-min.asm index 82781515b..47cd2e737 100644 --- a/src/test/ref/sieve-min.asm +++ b/src/test/ref/sieve-min.asm @@ -2,6 +2,7 @@ /// C standard library string.h /// /// Functions to manipulate C strings and arrays. +/// NULL pointer // Commodore 64 PRG executable file .file [name="sieve-min.prg", type="prg", segments="Program"] .segmentdef Program [segments="Basic, Code, Data"] diff --git a/src/test/ref/sieve-min.log b/src/test/ref/sieve-min.log index f1469db2e..adad839f4 100644 --- a/src/test/ref/sieve-min.log +++ b/src/test/ref/sieve-min.log @@ -979,6 +979,7 @@ ASSEMBLER BEFORE OPTIMIZATION /// C standard library string.h /// /// Functions to manipulate C strings and arrays. +/// NULL pointer // Upstart // Commodore 64 PRG executable file .file [name="sieve-min.prg", type="prg", segments="Program"] @@ -1469,6 +1470,7 @@ Score: 9717 /// C standard library string.h /// /// Functions to manipulate C strings and arrays. +/// NULL pointer // Upstart // Commodore 64 PRG executable file .file [name="sieve-min.prg", type="prg", segments="Program"]