1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-09-30 09:57:11 +00:00

Added support for indirect calls to advanced expressions through a new fragment type. Closes #708

This commit is contained in:
jespergravgaard 2021-08-08 17:45:56 +02:00
parent 77db0e8701
commit 66a1222fdb
23 changed files with 1460 additions and 2415 deletions

View File

@ -1,4 +1,4 @@
//KICKC FRAGMENT CACHE 8d6655dbd 8d6657e44
//KICKC FRAGMENT CACHE 84ae04234 84ae062c1
//FRAGMENT vbuzz=vbuc1
ldz #{c1}
//FRAGMENT vbuzz_lt_vbuc1_then_la1

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
//KICKC FRAGMENT CACHE 8d6655dbd 8d6657e44
//KICKC FRAGMENT CACHE 84ae04234 84ae062c1
//FRAGMENT vbuz1=vbuc1
lda #{c1}
sta {z1}

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
//KICKC FRAGMENT CACHE 8d6655dbd 8d6657e44
//KICKC FRAGMENT CACHE 84ae04234 84ae062c1
//FRAGMENT _deref_pbuc1=_inc__deref_pbuc1
inc {c1}
//FRAGMENT isr_hardware_all_entry

View File

@ -1,4 +1,4 @@
//KICKC FRAGMENT CACHE 8d6655dbd 8d6657e44
//KICKC FRAGMENT CACHE 84ae04234 84ae062c1
//FRAGMENT vbuz1=_deref_pbuc1
lda {c1}
sta {z1}
@ -244,81 +244,3 @@ inc
//FRAGMENT vbuyy_neq_vbuc1_then_la1
cpy #{c1}
bne {la1}
//FRAGMENT 0_neq_pbuc1_derefidx_vbuz1_then_la1
ldy {z1}
lda {c1},y
cmp #0
bne {la1}
//FRAGMENT pbuz1=pbuz2
lda {z2}
sta {z1}
lda {z2}+1
sta {z1}+1
//FRAGMENT vbuz1=pbuc1_derefidx_vbuz2
ldy {z2}
lda {c1},y
sta {z1}
//FRAGMENT pbuz1=_inc_pbuz2
clc
lda {z2}
adc #1
sta {z1}
lda {z2}+1
adc #0
sta {z1}+1
//FRAGMENT _deref_pbuc1=_deref_pbuz1
ldy #0
lda ({z1}),y
sta {c1}
//FRAGMENT vbuz1=_byte0_pbuz2
lda {z2}
sta {z1}
//FRAGMENT vbuz1=_byte1_pbuz2
lda {z2}+1
sta {z1}
//FRAGMENT 0_neq_pbuc1_derefidx_vbuaa_then_la1
tay
lda {c1},y
cmp #0
bne {la1}
//FRAGMENT 0_neq_pbuc1_derefidx_vbuxx_then_la1
lda {c1},x
cmp #0
bne {la1}
//FRAGMENT 0_neq_pbuc1_derefidx_vbuyy_then_la1
lda {c1},y
cmp #0
bne {la1}
//FRAGMENT vbuz1=pbuc1_derefidx_vbuxx
lda {c1},x
sta {z1}
//FRAGMENT vbuz1=pbuc1_derefidx_vbuyy
lda {c1},y
sta {z1}
//FRAGMENT vbuaa=pbuc1_derefidx_vbuz1
ldy {z1}
lda {c1},y
//FRAGMENT vbuaa=pbuc1_derefidx_vbuxx
lda {c1},x
//FRAGMENT vbuaa=pbuc1_derefidx_vbuyy
lda {c1},y
//FRAGMENT vbuxx=pbuc1_derefidx_vbuz1
ldy {z1}
ldx {c1},y
//FRAGMENT vbuaa=_byte0_pbuz1
lda {z1}
//FRAGMENT vbuxx=_byte0_pbuz1
ldx {z1}
//FRAGMENT vbuaa=_byte1_pbuz1
lda {z1}+1
//FRAGMENT vbuxx=_byte1_pbuz1
ldx {z1}+1
//FRAGMENT vbuyy=_byte0_pbuz1
ldy {z1}
//FRAGMENT vbuyy=_byte1_pbuz1
ldy {z1}+1
//FRAGMENT vbuyy=pbuc1_derefidx_vbuz1
ldx {z1}
ldy {c1},x
//FRAGMENT vbuxx=pbuc1_derefidx_vbuyy
ldx {c1},y

View File

@ -0,0 +1 @@
jsr {c1}

View File

@ -0,0 +1,7 @@
lda ({z1}),y
sta !+ +1
iny
lda ({z1}),y
sta !+ +2
!:
jsr $0000

View File

@ -58,6 +58,24 @@ public class AsmFragmentInstanceSpecBuilder {
return new AsmFragmentInstanceSpecBuilder(program, bindings, fragmentInstanceSpec);
}
/**
* Create a fragment instance spec factory for an indirect call
* @return the fragment instance spec factory
*/
public static AsmFragmentInstanceSpecBuilder call(StatementCallExecute call, Program program) {
return new AsmFragmentInstanceSpecBuilder(call, program);
}
private AsmFragmentInstanceSpecBuilder(StatementCallExecute call, Program program) {
this.program = program;
this.bindings = new LinkedHashMap<>();
ScopeRef codeScope = program.getStatementInfos().getBlock(call).getScope();
StringBuilder signature = new StringBuilder();
signature.append("call_");
signature.append(bind(call.getProcedureRVal()));
this.asmFragmentInstanceSpec = new AsmFragmentInstanceSpec(program, signature.toString(), bindings, codeScope);
}
/**
* Create a fragment instance spec factory for an interrupt routine entry
*

View File

@ -17,7 +17,6 @@ import dk.camelot64.kickc.model.values.*;
import dk.camelot64.kickc.passes.calcs.PassNCalcVariableReferenceInfos;
import dk.camelot64.kickc.passes.utils.SizeOfConstants;
import java.io.File;
import java.util.*;
/**
@ -658,17 +657,17 @@ public class Pass4CodeGeneration {
ConstantValue memberValue = structValue.getValue(memberRef);
Variable memberVariable = getScope().getVar(memberRef);
addChunkData(dataChunk, memberValue, memberVariable.getType(), memberVariable.getArraySpec(), scopeRef);
size += SymbolTypeStruct.getMemberSizeBytes(memberVariable.getType(), memberVariable.getArraySize(), getScope());
size += SymbolTypeStruct.getMemberSizeBytes(memberVariable.getType(), memberVariable.getArraySize(), getScope());
}
// Add padding if this is a union and the first member does not use all bytes
final int declaredSize = structValue.getStructType().getSizeBytes();
if(size<declaredSize) {
if(size < declaredSize) {
long paddingSize = declaredSize - size;
// TODO: Use SIZEOF constant
ConstantValue paddingSizeVal = new ConstantInteger(paddingSize);
String paddingBytesAsm = AsmFormat.getAsmConstant(program, paddingSizeVal, 99, scopeRef);
String paddingBytesAsm = AsmFormat.getAsmConstant(program, paddingSizeVal, 99, scopeRef);
ConstantValue zeroValue = new ConstantInteger(0l, SymbolType.BYTE);
dataChunk.addDataZeroFilled(AsmDataNumeric.Type.BYTE, paddingBytesAsm, (int)paddingSize, getEncoding(zeroValue));
dataChunk.addDataZeroFilled(AsmDataNumeric.Type.BYTE, paddingBytesAsm, (int) paddingSize, getEncoding(zeroValue));
}
} else if(value instanceof StructZero) {
final SymbolTypeStruct typeStruct = ((StructZero) value).getTypeStruct();
@ -814,7 +813,7 @@ public class Pass4CodeGeneration {
StatementSource statementSource = statement.getSource();
if(warnFragmentMissing) {
String stmtFormat = "";
if(statementSource!=null)
if(statementSource != null)
stmtFormat = statementSource.format();
program.getLog().append("Warning! Unknown fragment for statement " + statement.toString(program, false) + "\nMissing ASM fragment " + e.getFragmentSignature() + "\n" + stmtFormat);
asm.addLine(new AsmInlineKickAsm(".assert \"Missing ASM fragment " + e.getFragmentSignature() + "\", 0, 1", 0L, 0L));
@ -892,8 +891,8 @@ public class Pass4CodeGeneration {
AsmFragmentInstanceSpecBuilder asmFragmentInstanceSpecBuilder = AsmFragmentInstanceSpecBuilder.makelong4(call, program);
ensureEncoding(asm, asmFragmentInstanceSpecBuilder);
generateAsm(asm, asmFragmentInstanceSpecBuilder.getAsmFragmentInstanceSpec());
} else {
throw new CompileError("Intrinsic procedure not supported "+procedure.toString(program));
} else {
throw new CompileError("Intrinsic procedure not supported " + procedure.toString(program));
}
} else if(Procedure.CallingConvention.PHI_CALL.equals(procedure.getCallingConvention())) {
// Generate PHI transition
@ -921,19 +920,18 @@ public class Pass4CodeGeneration {
supported = true;
} else if(procedureRVal instanceof PointerDereferenceSimple) {
RValue pointer = ((PointerDereferenceSimple) procedureRVal).getPointer();
if(pointer instanceof ConstantValue) {
ensureEncoding(asm, pointer);
asm.addInstruction("jsr", CpuAddressingMode.ABS, AsmFormat.getAsmConstant(program, (ConstantValue) pointer, 99, block.getScope()), false);
asm.getCurrentChunk().setClobberOverwrite(CpuClobber.CLOBBER_ALL);
supported = true;
} else if(pointer instanceof VariableRef) {
while(pointer instanceof CastValue)
pointer = ((CastValue) pointer).getValue();
if(pointer instanceof VariableRef) {
Variable variable = getScope().getVariable((VariableRef) pointer);
generateIndirectCall(asm, variable, block.getScope());
asm.getCurrentChunk().setClobberOverwrite(CpuClobber.CLOBBER_ALL);
supported = true;
} else if(pointer instanceof CastValue && ((CastValue) pointer).getValue() instanceof VariableRef) {
Variable variable = getScope().getVariable((VariableRef) ((CastValue) pointer).getValue());
generateIndirectCall(asm, variable, block.getScope());
} else {
// Generate ASM for an indirect call
AsmFragmentInstanceSpecBuilder asmFragmentInstanceSpecBuilder = AsmFragmentInstanceSpecBuilder.call(call, program);
ensureEncoding(asm, asmFragmentInstanceSpecBuilder);
generateAsm(asm, asmFragmentInstanceSpecBuilder.getAsmFragmentInstanceSpec());
asm.getCurrentChunk().setClobberOverwrite(CpuClobber.CLOBBER_ALL);
supported = true;
}
@ -1059,7 +1057,7 @@ public class Pass4CodeGeneration {
entryName = entryFragment.getAsmFragmentInstanceSpec().getSignature();
}
try {
asm.startChunk(procedure.getRef(), null, "interrupt(" + entryName+ ")");
asm.startChunk(procedure.getRef(), null, "interrupt(" + entryName + ")");
generateAsm(asm, entryFragment.getAsmFragmentInstanceSpec());
} catch(AsmFragmentTemplateSynthesizer.UnknownFragmentException e) {
throw new CompileError("Interrupt type not supported " + procedure.getInterruptType() + " int " + procedure.toString() + "\n" + e.getMessage());

View File

@ -3393,6 +3393,11 @@ public class TestProgramsFast extends TestPrograms {
compileAndCompare("function-pointer-noarg-call.c");
}
@Test
public void testFunctionPointerReturn3() throws IOException {
compileAndCompare("function-pointer-return-3.c");
}
@Test
public void testFunctionPointerReturn2() throws IOException {
compileAndCompare("function-pointer-return-2.c");

View File

@ -1,5 +1,5 @@
// Calling a function pointer with parameters
// Reference the function without &
// Calling a function pointer with return value
// Reference the function without &, Call it without *
char * const RASTER = (char*)0xd012;
char * const BORDER = (char*)0xd020;

View File

@ -0,0 +1,40 @@
// Calling a function pointer with return value
// Calling a function pointer inside a struct without *
struct Task {
char param;
void (*handler)(char);
};
char * const RASTER = (char*)0xd012;
char * const BORDER = (char*)0xd020;
char * const BACKGROUND = (char*)0xd021;
void set_border(char col) {
*BORDER = col;
}
void set_bg(char col) {
*BACKGROUND = col;
}
void run(struct Task* task) {
task->handler(task->param);
}
struct Task tasks[] = {
{ 0, &set_border },
{ 0, &set_bg },
{ 1, &set_border },
{ 2, &set_bg }
};
void main() {
for(;;) {
for(char i=0; i < sizeof(tasks)/sizeof(struct Task); i++) {
run(tasks+i);
}
}
}

View File

@ -1,5 +1,5 @@
Inlined call vicSelectGfxBank::$0 = call toDd00(vicSelectGfxBank::gfx)
Inlined call call __init
Inlined call call __init
Calling convention STACK_CALL adding prepare/execute/finalize for call *musicInit
Calling convention STACK_CALL adding prepare/execute/finalize for call *musicPlay
@ -31,7 +31,7 @@ __start: scope:[__start] from
__start::__init1: scope:[__start] from __start
to:__start::@1
__start::@1: scope:[__start] from __start::__init1
call main
call main
to:__start::@2
__start::@2: scope:[__start] from __start::@1
to:__start::@return
@ -158,7 +158,7 @@ ASSEMBLER BEFORE OPTIMIZATION
// main
// Play the music
main: {
// [1] callexecute *musicInit
// [1] callexecute *musicInit -- call__deref_pprc1
// Initialize the music
jsr musicInit
jmp __b1
@ -174,7 +174,7 @@ main: {
__b2:
// [3] *((byte*)VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR) = ++ *((byte*)VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR) -- _deref_pbuc1=_inc__deref_pbuc1
inc VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR
// [4] callexecute *musicPlay
// [4] callexecute *musicPlay -- call__deref_pprc1
// Play the music
jsr musicPlay
jmp __b3
@ -249,7 +249,7 @@ Score: 1066
// Play the music
main: {
// (*musicInit)()
// [1] callexecute *musicInit
// [1] callexecute *musicInit -- call__deref_pprc1
// Initialize the music
jsr musicInit
// Wait for the RASTER
@ -265,7 +265,7 @@ main: {
// [3] *((byte*)VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR) = ++ *((byte*)VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR) -- _deref_pbuc1=_inc__deref_pbuc1
inc VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR
// (*musicPlay)()
// [4] callexecute *musicPlay
// [4] callexecute *musicPlay -- call__deref_pprc1
// Play the music
jsr musicPlay
// main::@3

View File

@ -1,6 +1,6 @@
Resolved forward reference irq_play to __interrupt(rom_sys_c64) void irq_play()
Inlined call vicSelectGfxBank::$0 = call toDd00(vicSelectGfxBank::gfx)
Inlined call call __init
Inlined call call __init
Calling convention STACK_CALL adding prepare/execute/finalize for call *musicInit
Calling convention STACK_CALL adding prepare/execute/finalize for call *musicPlay
@ -42,7 +42,7 @@ __start: scope:[__start] from
__start::__init1: scope:[__start] from __start
to:__start::@1
__start::@1: scope:[__start] from __start::__init1
call main
call main
to:__start::@2
__start::@2: scope:[__start] from __start::@1
to:__start::@return
@ -220,7 +220,7 @@ irq_play: {
// interrupt(isr_rom_sys_c64_entry) -- isr_rom_sys_c64_entry
// [0] *((byte*)VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR) = ++ *((byte*)VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR) -- _deref_pbuc1=_inc__deref_pbuc1
inc VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR
// [1] callexecute *musicPlay
// [1] callexecute *musicPlay -- call__deref_pprc1
// Play SID
jsr musicPlay
jmp __b1
@ -244,7 +244,7 @@ irq_play: {
main: {
// asm { sei }
sei
// [6] callexecute *musicInit
// [6] callexecute *musicInit -- call__deref_pprc1
jsr musicInit
jmp __b1
// main::@1
@ -378,7 +378,7 @@ irq_play: {
// [0] *((byte*)VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR) = ++ *((byte*)VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR) -- _deref_pbuc1=_inc__deref_pbuc1
inc VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR
// (*musicPlay)()
// [1] callexecute *musicPlay
// [1] callexecute *musicPlay -- call__deref_pprc1
// Play SID
jsr musicPlay
// irq_play::@1
@ -403,7 +403,7 @@ main: {
// asm { sei }
sei
// (*musicInit)()
// [6] callexecute *musicInit
// [6] callexecute *musicInit -- call__deref_pprc1
jsr musicInit
// main::@1
// CIA1->INTERRUPT = CIA_INTERRUPT_CLEAR

View File

@ -52,7 +52,7 @@ Setting inferred volatile on symbol affected by address-of: memoryRemap256M::xVa
Setting inferred volatile on symbol affected by address-of: memoryRemap256M::yVal in asm { ldalMb ldx#$0f ldyuMb ldz#$0f map ldaaVal ldxxVal ldyyVal ldzzVal map eom }
Setting inferred volatile on symbol affected by address-of: memoryRemap256M::zVal in asm { ldalMb ldx#$0f ldyuMb ldz#$0f map ldaaVal ldxxVal ldyyVal ldzzVal map eom }
Inlined call vicSelectGfxBank::$0 = call toDd00(vicSelectGfxBank::gfx)
Inlined call call __init
Inlined call call __init
Eliminating unused variable with no statement memoryRemap::$0
Eliminating unused variable with no statement memoryRemap::$4
Eliminating unused variable with no statement memoryRemap::$5
@ -98,7 +98,7 @@ memoryRemapBlock: scope:[memoryRemapBlock] from irq main::@6
memoryRemap::remapBlocks#0 = memoryRemapBlock::blockBits#0
memoryRemap::lowerPageOffset#0 = memoryRemapBlock::pageOffset#0
memoryRemap::upperPageOffset#0 = memoryRemapBlock::pageOffset#0
call memoryRemap
call memoryRemap
to:memoryRemapBlock::@1
memoryRemapBlock::@1: scope:[memoryRemapBlock] from memoryRemapBlock
to:memoryRemapBlock::@return
@ -136,7 +136,7 @@ main: scope:[main] from __start::@1
memoryRemap::remapBlocks#1 = 0
memoryRemap::lowerPageOffset#1 = 0
memoryRemap::upperPageOffset#1 = 0
call memoryRemap
call memoryRemap
to:main::@5
main::@5: scope:[main] from main
*((byte*)VICIII+OFFSET_STRUCT_MOS4569_VICIII_KEY) = $47
@ -152,12 +152,12 @@ main::@5: scope:[main] from main
memcpy_dma4::src_bank#0 = 0
memcpy_dma4::src#0 = (void*)upperCodeData
memcpy_dma4::num#0 = main::$1
call memcpy_dma4
call memcpy_dma4
to:main::@6
main::@6: scope:[main] from main::@5
memoryRemapBlock::blockPage#0 = $40
memoryRemapBlock::memoryPage#0 = $100
call memoryRemapBlock
call memoryRemapBlock
to:main::@7
main::@7: scope:[main] from main::@6
asm { lda#0 }
@ -167,7 +167,7 @@ main::@1: scope:[main] from main::@7
memoryRemap::remapBlocks#2 = 0
memoryRemap::lowerPageOffset#2 = 0
memoryRemap::upperPageOffset#2 = 0
call memoryRemap
call memoryRemap
to:main::@8
main::@8: scope:[main] from main::@1
*((byte*)CIA1+OFFSET_STRUCT_MOS6526_CIA_INTERRUPT) = CIA_INTERRUPT_CLEAR
@ -206,7 +206,7 @@ irq: scope:[irq] from
*((byte*)VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR) = ++ *((byte*)VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR)
memoryRemapBlock::blockPage#1 = $40
memoryRemapBlock::memoryPage#1 = $100
call memoryRemapBlock
call memoryRemapBlock
to:irq::@4
irq::@4: scope:[irq] from irq
callexecute *musicPlay
@ -215,7 +215,7 @@ irq::@1: scope:[irq] from irq::@4
memoryRemap::remapBlocks#3 = 0
memoryRemap::lowerPageOffset#3 = 0
memoryRemap::upperPageOffset#3 = 0
call memoryRemap
call memoryRemap
to:irq::@5
irq::@5: scope:[irq] from irq::@1
irq::raster#0 = *((byte*)VICII+OFFSET_STRUCT_MOS6569_VICII_RASTER)
@ -238,7 +238,7 @@ __start: scope:[__start] from
__start::__init1: scope:[__start] from __start
to:__start::@1
__start::@1: scope:[__start] from __start::__init1
call main
call main
to:__start::@2
__start::@2: scope:[__start] from __start::@1
to:__start::@return
@ -666,7 +666,7 @@ __interrupt(hardware_clobber) void irq()
irq: scope:[irq] from
[0] *((byte*)VICII+OFFSET_STRUCT_MOS6569_VICII_IRQ_STATUS) = IRQ_RASTER
[1] *((byte*)VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR) = ++ *((byte*)VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR)
[2] call memoryRemapBlock
[2] call memoryRemapBlock
to:irq::@4
irq::@4: scope:[irq] from irq
[3] phi()
@ -674,7 +674,7 @@ irq::@4: scope:[irq] from irq
to:irq::@1
irq::@1: scope:[irq] from irq::@4
[5] phi()
[6] call memoryRemap
[6] call memoryRemap
to:irq::@5
irq::@5: scope:[irq] from irq::@1
[7] irq::raster#0 = *((byte*)VICII+OFFSET_STRUCT_MOS6569_VICII_RASTER)
@ -692,7 +692,7 @@ irq::@return: scope:[irq] from irq::@3
void main()
main: scope:[main] from
asm { sei }
[12] call memoryRemap
[12] call memoryRemap
to:main::@5
main::@5: scope:[main] from main
[13] *((byte*)VICIII+OFFSET_STRUCT_MOS4569_VICIII_KEY) = $47
@ -702,11 +702,11 @@ main::@5: scope:[main] from main
[17] *PROCPORT_DDR = PROCPORT_DDR_MEMORY_MASK
[18] *PROCPORT = PROCPORT_RAM_IO
[19] *((byte*)VICIV+OFFSET_STRUCT_MEGA65_VICIV_SIDBDRWD_LO) = 1
[20] call memcpy_dma4
[20] call memcpy_dma4
to:main::@6
main::@6: scope:[main] from main::@5
[21] phi()
[22] call memoryRemapBlock
[22] call memoryRemapBlock
to:main::@7
main::@7: scope:[main] from main::@6
asm { lda#0 }
@ -714,7 +714,7 @@ main::@7: scope:[main] from main::@6
to:main::@1
main::@1: scope:[main] from main::@7
[25] phi()
[26] call memoryRemap
[26] call memoryRemap
to:main::@8
main::@8: scope:[main] from main::@1
[27] *((byte*)CIA1+OFFSET_STRUCT_MOS6526_CIA_INTERRUPT) = CIA_INTERRUPT_CLEAR
@ -741,7 +741,7 @@ main::@4: scope:[main] from main::@3
void memoryRemapBlock(byte memoryRemapBlock::blockPage , word memoryRemapBlock::memoryPage)
memoryRemapBlock: scope:[memoryRemapBlock] from irq main::@6
[40] phi()
[41] call memoryRemap
[41] call memoryRemap
to:memoryRemapBlock::@return
memoryRemapBlock::@return: scope:[memoryRemapBlock] from memoryRemapBlock
[42] return
@ -1137,7 +1137,7 @@ irq: {
sta VICII+OFFSET_STRUCT_MOS6569_VICII_IRQ_STATUS
// [1] *((byte*)VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR) = ++ *((byte*)VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR) -- _deref_pbuc1=_inc__deref_pbuc1
inc VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR
// [2] call memoryRemapBlock
// [2] call memoryRemapBlock
// Remap memory to put music at $4000
// [40] phi from irq to memoryRemapBlock [phi:irq->memoryRemapBlock]
memoryRemapBlock_from_irq:
@ -1147,7 +1147,7 @@ irq: {
jmp __b4
// irq::@4
__b4:
// [4] callexecute *musicPlay
// [4] callexecute *musicPlay -- call__deref_pprc1
// Play remapped SID
jsr musicPlay
// [5] phi from irq::@4 to irq::@1 [phi:irq::@4->irq::@1]
@ -1155,7 +1155,7 @@ irq: {
jmp __b1
// irq::@1
__b1:
// [6] call memoryRemap
// [6] call memoryRemap
// Reset memory mapping
// [43] phi from irq::@1 to memoryRemap [phi:irq::@1->memoryRemap]
memoryRemap_from___b1:
@ -1205,7 +1205,7 @@ main: {
// asm { sei }
// Stop IRQ's
sei
// [12] call memoryRemap
// [12] call memoryRemap
// Map memory to BANK 0 : 0x00XXXX - giving access to I/O
// [43] phi from main to memoryRemap [phi:main->memoryRemap]
memoryRemap_from_main:
@ -1252,7 +1252,7 @@ main: {
// open sideborder
lda #1
sta VICIV+OFFSET_STRUCT_MEGA65_VICIV_SIDBDRWD_LO
// [20] call memcpy_dma4
// [20] call memcpy_dma4
// Transfer banked code/data to upper memory ($10000)
jsr memcpy_dma4
// [21] phi from main::@5 to main::@6 [phi:main::@5->main::@6]
@ -1260,7 +1260,7 @@ main: {
jmp __b6
// main::@6
__b6:
// [22] call memoryRemapBlock
// [22] call memoryRemapBlock
// Remap [$4000-$5fff] to point to [$10000-$11fff]
// [40] phi from main::@6 to memoryRemapBlock [phi:main::@6->memoryRemapBlock]
memoryRemapBlock_from___b6:
@ -1271,14 +1271,14 @@ main: {
// asm { lda#0 }
// Initialize SID
lda #0
// [24] callexecute *musicInit
// [24] callexecute *musicInit -- call__deref_pprc1
jsr musicInit
// [25] phi from main::@7 to main::@1 [phi:main::@7->main::@1]
__b1_from___b7:
jmp __b1
// main::@1
__b1:
// [26] call memoryRemap
// [26] call memoryRemap
// Reset memory mapping
// [43] phi from main::@1 to memoryRemap [phi:main::@1->memoryRemap]
memoryRemap_from___b1:
@ -1374,7 +1374,7 @@ memoryRemapBlock: {
// Which block is being remapped? (0-7)
.const block = $40>>5
.const blockBits = 1<<block
// [41] call memoryRemap
// [41] call memoryRemap
// [43] phi from memoryRemapBlock to memoryRemap [phi:memoryRemapBlock->memoryRemap]
memoryRemap_from_memoryRemapBlock:
// [43] phi memoryRemap::upperPageOffset#4 = memoryRemapBlock::pageOffset#0 [phi:memoryRemapBlock->memoryRemap#0] -- vwuz1=vwuc1
@ -1839,20 +1839,20 @@ irq: {
// [1] *((byte*)VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR) = ++ *((byte*)VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR) -- _deref_pbuc1=_inc__deref_pbuc1
inc VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR
// memoryRemapBlock(0x40, 0x100)
// [2] call memoryRemapBlock
// [2] call memoryRemapBlock
// Remap memory to put music at $4000
// [40] phi from irq to memoryRemapBlock [phi:irq->memoryRemapBlock]
jsr memoryRemapBlock
// [3] phi from irq to irq::@4 [phi:irq->irq::@4]
// irq::@4
// (*musicPlay)()
// [4] callexecute *musicPlay
// [4] callexecute *musicPlay -- call__deref_pprc1
// Play remapped SID
jsr musicPlay
// [5] phi from irq::@4 to irq::@1 [phi:irq::@4->irq::@1]
// irq::@1
// memoryRemap(0,0,0)
// [6] call memoryRemap
// [6] call memoryRemap
// Reset memory mapping
// [43] phi from irq::@1 to memoryRemap [phi:irq::@1->memoryRemap]
// [43] phi memoryRemap::upperPageOffset#4 = 0 [phi:irq::@1->memoryRemap#0] -- vwuz1=vbuc1
@ -1897,7 +1897,7 @@ main: {
// Stop IRQ's
sei
// memoryRemap(0,0,0)
// [12] call memoryRemap
// [12] call memoryRemap
// Map memory to BANK 0 : 0x00XXXX - giving access to I/O
// [43] phi from main to memoryRemap [phi:main->memoryRemap]
// [43] phi memoryRemap::upperPageOffset#4 = 0 [phi:main->memoryRemap#0] -- vwuz1=vbuc1
@ -1946,13 +1946,13 @@ main: {
lda #1
sta VICIV+OFFSET_STRUCT_MEGA65_VICIV_SIDBDRWD_LO
// memcpy_dma4(1, (void*)0x0000, 0, upperCodeData, MUSIC_END-MUSIC)
// [20] call memcpy_dma4
// [20] call memcpy_dma4
// Transfer banked code/data to upper memory ($10000)
jsr memcpy_dma4
// [21] phi from main::@5 to main::@6 [phi:main::@5->main::@6]
// main::@6
// memoryRemapBlock(0x40, 0x100)
// [22] call memoryRemapBlock
// [22] call memoryRemapBlock
// Remap [$4000-$5fff] to point to [$10000-$11fff]
// [40] phi from main::@6 to memoryRemapBlock [phi:main::@6->memoryRemapBlock]
jsr memoryRemapBlock
@ -1962,12 +1962,12 @@ main: {
// Initialize SID
lda #0
// (*musicInit)()
// [24] callexecute *musicInit
// [24] callexecute *musicInit -- call__deref_pprc1
jsr musicInit
// [25] phi from main::@7 to main::@1 [phi:main::@7->main::@1]
// main::@1
// memoryRemap(0,0,0)
// [26] call memoryRemap
// [26] call memoryRemap
// Reset memory mapping
// [43] phi from main::@1 to memoryRemap [phi:main::@1->memoryRemap]
// [43] phi memoryRemap::upperPageOffset#4 = 0 [phi:main::@1->memoryRemap#0] -- vwuz1=vbuc1
@ -2062,7 +2062,7 @@ memoryRemapBlock: {
.const block = $40>>5
.const blockBits = 1<<block
// memoryRemap(blockBits, pageOffset, pageOffset)
// [41] call memoryRemap
// [41] call memoryRemap
// [43] phi from memoryRemapBlock to memoryRemap [phi:memoryRemapBlock->memoryRemap]
// [43] phi memoryRemap::upperPageOffset#4 = memoryRemapBlock::pageOffset#0 [phi:memoryRemapBlock->memoryRemap#0] -- vwuz1=vwuc1
lda #<pageOffset

View File

@ -23,7 +23,7 @@ Setting inferred volatile on symbol affected by address-of: memoryRemap256M::xVa
Setting inferred volatile on symbol affected by address-of: memoryRemap256M::yVal in asm { ldalMb ldx#$0f ldyuMb ldz#$0f map ldaaVal ldxxVal ldyyVal ldzzVal map eom }
Setting inferred volatile on symbol affected by address-of: memoryRemap256M::zVal in asm { ldalMb ldx#$0f ldyuMb ldz#$0f map ldaaVal ldxxVal ldyyVal ldzzVal map eom }
Inlined call vicSelectGfxBank::$0 = call toDd00(vicSelectGfxBank::gfx)
Inlined call call __init
Inlined call call __init
Eliminating unused variable with no statement memset::$2
Eliminating unused variable with no statement irq::$1
Eliminating unused variable with no statement irq::$17
@ -89,7 +89,7 @@ main::@1: scope:[main] from main
memset::str#0 = (void*)SCREEN
memset::c#0 = ' '
memset::num#0 = $28*$19
call memset
call memset
memset::return#2 = memset::return#1
to:main::@11
main::@11: scope:[main] from main::@1
@ -450,7 +450,7 @@ __start::__init1: scope:[__start] from __start
greet_idx = 0
to:__start::@1
__start::@1: scope:[__start] from __start::__init1
call main
call main
to:__start::@2
__start::@2: scope:[__start] from __start::@1
to:__start::@return
@ -1326,7 +1326,7 @@ __start::__init1: scope:[__start] from __start
to:__start::@1
__start::@1: scope:[__start] from __start::__init1
[6] phi()
[7] call main
[7] call main
to:__start::@return
__start::@return: scope:[__start] from __start::@1
[8] return
@ -1539,7 +1539,7 @@ main: scope:[main] from __start::@1
to:main::@1
main::@1: scope:[main] from main
[117] phi()
[118] call memset
[118] call memset
to:main::@2
main::@2: scope:[main] from main::@1 main::@3
[119] main::i1#2 = phi( main::@1/0, main::@3/main::i1#1 )
@ -2203,7 +2203,7 @@ __start: {
jmp __b1
// __start::@1
__b1:
// [7] call main
// [7] call main
jsr main
jmp __breturn
// __start::@return
@ -2255,7 +2255,7 @@ irq: {
jmp __b4
// irq::@4
__b4:
// [17] callexecute *songPlay
// [17] callexecute *songPlay -- call__deref_pprc1
// play music
jsr songPlay
jmp __b1
@ -2734,14 +2734,14 @@ main: {
// asm { lda#0 }
// Initialize music
lda #0
// [116] callexecute *songInit
// [116] callexecute *songInit -- call__deref_pprc1
jsr songInit
// [117] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
jmp __b1
// main::@1
__b1:
// [118] call memset
// [118] call memset
// Clear screen
// [144] phi from main::@1 to memset [phi:main::@1->memset]
memset_from___b1:
@ -3396,7 +3396,7 @@ __start: {
sta.z greet_idx
// [6] phi from __start::__init1 to __start::@1 [phi:__start::__init1->__start::@1]
// __start::@1
// [7] call main
// [7] call main
jsr main
// __start::@return
// [8] return
@ -3449,7 +3449,7 @@ irq: {
// [16] phi from irq::@2 to irq::@4 [phi:irq::@2->irq::@4]
// irq::@4
// (*songPlay)()
// [17] callexecute *songPlay
// [17] callexecute *songPlay -- call__deref_pprc1
// play music
jsr songPlay
// irq::@1
@ -3946,12 +3946,12 @@ main: {
// Initialize music
lda #0
// (*songInit)()
// [116] callexecute *songInit
// [116] callexecute *songInit -- call__deref_pprc1
jsr songInit
// [117] phi from main to main::@1 [phi:main->main::@1]
// main::@1
// memset(SCREEN, ' ', 40*25)
// [118] call memset
// [118] call memset
// Clear screen
// [144] phi from main::@1 to memset [phi:main::@1->memset]
jsr memset

View File

@ -1,5 +1,5 @@
// Calling a function pointer with parameters
// Reference the function without &
// Calling a function pointer with return value
// Reference the function without &, Call it without *
// Commodore 64 PRG executable file
.file [name="function-pointer-return-2.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]

View File

@ -238,8 +238,8 @@ Uplifting [] best 194 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Calling a function pointer with parameters
// Reference the function without &
// Calling a function pointer with return value
// Reference the function without &, Call it without *
// Upstart
// Commodore 64 PRG executable file
.file [name="function-pointer-return-2.prg", type="prg", segments="Program"]
@ -391,8 +391,8 @@ FINAL ASSEMBLER
Score: 95
// File Comments
// Calling a function pointer with parameters
// Reference the function without &
// Calling a function pointer with return value
// Reference the function without &, Call it without *
// Upstart
// Commodore 64 PRG executable file
.file [name="function-pointer-return-2.prg", type="prg", segments="Program"]

View File

@ -0,0 +1,94 @@
// Calling a function pointer with return value
// Calling a function pointer inside a struct without *
// Commodore 64 PRG executable file
.file [name="function-pointer-return-3.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_STRUCT_TASK = 3
.const OFFSET_STRUCT_TASK_HANDLER = 1
.const STACK_BASE = $103
.label BORDER = $d020
.label BACKGROUND = $d021
.segment Code
main: {
.label i = 2
__b3:
lda #0
sta.z i
__b1:
// for(char i=0; i < sizeof(tasks)/sizeof(struct Task); i++)
lda.z i
cmp #4*SIZEOF_STRUCT_TASK/SIZEOF_STRUCT_TASK
bcc __b2
jmp __b3
__b2:
// tasks+i
lda.z i
asl
clc
adc.z i
tax
// run(tasks+i)
txa
clc
adc #<tasks
sta.z run.task
lda #>tasks
adc #0
sta.z run.task+1
jsr run
// for(char i=0; i < sizeof(tasks)/sizeof(struct Task); i++)
inc.z i
jmp __b1
}
// set_bg(byte register(A) col)
set_bg: {
.const OFFSET_STACK_COL = 0
tsx
lda STACK_BASE+OFFSET_STACK_COL,x
// *BACKGROUND = col
sta BACKGROUND
// }
rts
}
// set_border(byte register(A) col)
set_border: {
.const OFFSET_STACK_COL = 0
tsx
lda STACK_BASE+OFFSET_STACK_COL,x
// *BORDER = col
sta BORDER
// }
rts
}
// run(struct Task* zp(3) task)
run: {
.label task = 3
// task->handler(task->param)
lda tasks,x
pha
ldy #OFFSET_STRUCT_TASK_HANDLER
lda (task),y
sta !+ +1
iny
lda (task),y
sta !+ +2
!:
jsr 0
pla
// }
rts
}
.segment Data
tasks: .byte 0
.word set_border
.byte 0
.word set_bg
.byte 1
.word set_border
.byte 2
.word set_bg

View File

@ -0,0 +1,46 @@
void main()
main: scope:[main] from
[0] phi()
to:main::@1
main::@1: scope:[main] from main main::@1 main::@3
[1] main::i#2 = phi( main/0, main::@3/main::i#1, main::@1/0 )
[2] if(main::i#2<4*SIZEOF_STRUCT_TASK/SIZEOF_STRUCT_TASK) goto main::@2
to:main::@1
main::@2: scope:[main] from main::@1
[3] main::$6 = main::i#2 << 1
[4] main::$5 = main::$6 + main::i#2
[5] run::task#0 = tasks + main::$5
[6] call run
to:main::@3
main::@3: scope:[main] from main::@2
[7] main::i#1 = ++ main::i#2
to:main::@1
__stackcall void set_bg(byte set_bg::col)
set_bg: scope:[set_bg] from
[8] set_bg::col#0 = stackidx(byte,set_bg::OFFSET_STACK_COL)
[9] *BACKGROUND = set_bg::col#0
to:set_bg::@return
set_bg::@return: scope:[set_bg] from set_bg
[10] return
to:@return
__stackcall void set_border(byte set_border::col)
set_border: scope:[set_border] from
[11] set_border::col#0 = stackidx(byte,set_border::OFFSET_STACK_COL)
[12] *BORDER = set_border::col#0
to:set_border::@return
set_border::@return: scope:[set_border] from set_border
[13] return
to:@return
void run(struct Task* run::task)
run: scope:[run] from main::@2
[14] stackpush(byte) = ((byte*)tasks)[main::$5]
[15] callexecute *(((void(byte)**)run::task#0)[OFFSET_STRUCT_TASK_HANDLER])
sideeffect stackpullbytes(1)
to:run::@return
run::@return: scope:[run] from run
[17] return
to:@return

View File

@ -0,0 +1,646 @@
Setting inferred __stackcall on procedure affected by address-of __stackcall void set_border(byte set_border::col) caused by statement void set_border(byte set_border::col)
Setting inferred __stackcall on procedure affected by address-of __stackcall void set_bg(byte set_bg::col) caused by statement void set_bg(byte set_bg::col)
Setting inferred __stackcall on procedure affected by address-of __stackcall void set_border(byte set_border::col) caused by statement __stackcall void set_border(byte set_border::col)
Setting inferred __stackcall on procedure affected by address-of __stackcall void set_bg(byte set_bg::col) caused by statement __stackcall void set_bg(byte set_bg::col)
Adding parameter assignment in __stackcall procedure set_border::col = param(set_border::col)
Adding parameter assignment in __stackcall procedure set_bg::col = param(set_bg::col)
Calling convention STACK_CALL adding prepare/execute/finalize for call *(*run::$1) *run::$2
Calling convention STACK_CALL replacing param(set_border::col) with stackidx(byte,set_border::OFFSET_STACK_COL)
Calling convention STACK_CALL replacing param(set_bg::col) with stackidx(byte,set_bg::OFFSET_STACK_COL)
Calling convention STACK_CALL adding stack push stackpush(byte) = *run::$2
CONTROL FLOW GRAPH SSA
__stackcall void set_border(byte set_border::col)
set_border: scope:[set_border] from
set_border::col#0 = stackidx(byte,set_border::OFFSET_STACK_COL)
*BORDER = set_border::col#0
to:set_border::@return
set_border::@return: scope:[set_border] from set_border
return
to:@return
__stackcall void set_bg(byte set_bg::col)
set_bg: scope:[set_bg] from
set_bg::col#0 = stackidx(byte,set_bg::OFFSET_STACK_COL)
*BACKGROUND = set_bg::col#0
to:set_bg::@return
set_bg::@return: scope:[set_bg] from set_bg
return
to:@return
void run(struct Task* run::task)
run: scope:[run] from main::@3
run::task#1 = phi( main::@3/run::task#0 )
run::$3 = (void(byte)**)run::task#1
run::$1 = run::$3 + OFFSET_STRUCT_TASK_HANDLER
run::$4 = (byte*)run::task#1
run::$2 = run::$4 + OFFSET_STRUCT_TASK_PARAM
stackpush(byte) = *run::$2
callexecute *(*run::$1)
sideeffect stackpullbytes(1)
to:run::@return
run::@return: scope:[run] from run
return
to:@return
void main()
main: scope:[main] from __start
to:main::@1
main::@1: scope:[main] from main main::@2
main::i#0 = 0
to:main::@2
main::@2: scope:[main] from main::@1 main::@4
main::i#2 = phi( main::@1/main::i#0, main::@4/main::i#1 )
main::$0 = sizeof tasks
main::$1 = main::$0 / SIZEOF_STRUCT_TASK
main::$2 = main::i#2 < main::$1
if(main::$2) goto main::@3
to:main::@1
main::@3: scope:[main] from main::@2
main::i#3 = phi( main::@2/main::i#2 )
main::$5 = main::i#3 * SIZEOF_STRUCT_TASK
main::$3 = tasks + main::$5
run::task#0 = main::$3
call run
to:main::@4
main::@4: scope:[main] from main::@3
main::i#4 = phi( main::@3/main::i#3 )
main::i#1 = ++ main::i#4
to:main::@2
main::@return: scope:[main] from
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
constant byte* const BACKGROUND = (byte*)$d021
constant byte* const BORDER = (byte*)$d020
constant byte OFFSET_STRUCT_TASK_HANDLER = 1
constant byte OFFSET_STRUCT_TASK_PARAM = 0
constant byte SIZEOF_STRUCT_TASK = 3
constant word STACK_BASE = $103
void __start()
void main()
word~ main::$0
word~ main::$1
bool~ main::$2
struct Task*~ main::$3
byte~ main::$5
byte main::i
byte main::i#0
byte main::i#1
byte main::i#2
byte main::i#3
byte main::i#4
void run(struct Task* run::task)
void(byte)**~ run::$1
byte*~ run::$2
void(byte)**~ run::$3
byte*~ run::$4
struct Task* run::task
struct Task* run::task#0
struct Task* run::task#1
__stackcall void set_bg(byte set_bg::col)
constant byte set_bg::OFFSET_STACK_COL = 0
byte set_bg::col
byte set_bg::col#0
__stackcall void set_border(byte set_border::col)
constant byte set_border::OFFSET_STACK_COL = 0
byte set_border::col
byte set_border::col#0
constant struct Task* tasks[] = { { param: 0, handler: &set_border }, { param: 0, handler: &set_bg }, { param: 1, handler: &set_border }, { param: 2, handler: &set_bg } }
Simplifying constant pointer cast (byte*) 53280
Simplifying constant pointer cast (byte*) 53281
Successful SSA optimization PassNCastSimplification
Alias main::i#2 = main::i#3 main::i#4
Alias run::task#0 = main::$3
Successful SSA optimization Pass2AliasElimination
Identical Phi Values run::task#1 run::task#0
Successful SSA optimization Pass2IdenticalPhiElimination
Simple Condition main::$2 [20] if(main::i#2<main::$1) goto main::@3
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant right-side identified [17] main::$0 = sizeof tasks
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant main::i#0 = 0
Constant main::$0 = sizeof tasks
Successful SSA optimization Pass2ConstantIdentification
Converting *(pointer+n) to pointer[n] [11] stackpush(byte) = *run::$2 -- run::$4[OFFSET_STRUCT_TASK_PARAM]
Converting *(pointer+n) to pointer[n] [12] callexecute *(*run::$1) -- run::$3[OFFSET_STRUCT_TASK_HANDLER]
Successful SSA optimization Pass2InlineDerefIdx
Simplifying expression containing zero run::$4 in [10] run::$2 = run::$4 + OFFSET_STRUCT_TASK_PARAM
Simplifying expression containing zero run::$4 in [11] stackpush(byte) = run::$4[OFFSET_STRUCT_TASK_PARAM]
Successful SSA optimization PassNSimplifyExpressionWithZero
Removing unused block main::@return
Successful SSA optimization Pass2EliminateUnusedBlocks
Eliminating unused variable run::$1 and assignment [7] run::$1 = run::$3 + OFFSET_STRUCT_TASK_HANDLER
Eliminating unused variable run::$2 and assignment [9] run::$2 = run::$4
Eliminating unused constant OFFSET_STRUCT_TASK_PARAM
Successful SSA optimization PassNEliminateUnusedVars
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
Resolving array sizeof() sizeof tasks
Successful SSA optimization PassNSizeOfSimplification
Constant right-side identified [13] main::$1 = main::$0 / SIZEOF_STRUCT_TASK
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant main::$1 = main::$0/SIZEOF_STRUCT_TASK
Successful SSA optimization Pass2ConstantIdentification
Converting *(pointer+n) to pointer[n] [8] stackpush(byte) = *run::$4 -- ((byte*)tasks)[main::$5]
Successful SSA optimization Pass2InlineDerefIdx
Eliminating unused variable run::$4 and assignment [7] run::$4 = (byte*)run::task#0
Successful SSA optimization PassNEliminateUnusedVars
Adding number conversion cast (unumber) 4 in
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant integer cast 4
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 4
Successful SSA optimization PassNFinalizeNumberTypeConversions
Constant value identified (byte*)tasks in [7] stackpush(byte) = ((byte*)tasks)[main::$5]
Successful SSA optimization Pass2ConstantValues
Inlining Noop Cast [6] run::$3 = (void(byte)**)run::task#0 keeping run::task#0
Successful SSA optimization Pass2NopCastInlining
Rewriting multiplication to use shift and addition[13] main::$5 = main::i#2 * SIZEOF_STRUCT_TASK
Inlining constant with var siblings main::i#0
Constant inlined main::$1 = 4*SIZEOF_STRUCT_TASK/SIZEOF_STRUCT_TASK
Constant inlined main::i#0 = 0
Constant inlined main::$0 = 4*SIZEOF_STRUCT_TASK
Successful SSA optimization Pass2ConstantInlining
Alias main::$5 = main::$7
Successful SSA optimization Pass2AliasElimination
Finalized unsigned number type (byte) 1
Successful SSA optimization PassNFinalizeNumberTypeConversions
Adding NOP phi() at start of main
Adding NOP phi() at start of main::@1
CALL GRAPH
Calls in [main] to run:7
Calls in [run] to null:17
Created 1 initial phi equivalence classes
Coalesced [9] main::i#5 = main::i#1
Coalesced down to 1 phi equivalence classes
Culled Empty Block label main::@1
Renumbering block main::@2 to main::@1
Renumbering block main::@3 to main::@2
Renumbering block main::@4 to main::@3
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::@1 main::@3
[1] main::i#2 = phi( main/0, main::@3/main::i#1, main::@1/0 )
[2] if(main::i#2<4*SIZEOF_STRUCT_TASK/SIZEOF_STRUCT_TASK) goto main::@2
to:main::@1
main::@2: scope:[main] from main::@1
[3] main::$6 = main::i#2 << 1
[4] main::$5 = main::$6 + main::i#2
[5] run::task#0 = tasks + main::$5
[6] call run
to:main::@3
main::@3: scope:[main] from main::@2
[7] main::i#1 = ++ main::i#2
to:main::@1
__stackcall void set_bg(byte set_bg::col)
set_bg: scope:[set_bg] from
[8] set_bg::col#0 = stackidx(byte,set_bg::OFFSET_STACK_COL)
[9] *BACKGROUND = set_bg::col#0
to:set_bg::@return
set_bg::@return: scope:[set_bg] from set_bg
[10] return
to:@return
__stackcall void set_border(byte set_border::col)
set_border: scope:[set_border] from
[11] set_border::col#0 = stackidx(byte,set_border::OFFSET_STACK_COL)
[12] *BORDER = set_border::col#0
to:set_border::@return
set_border::@return: scope:[set_border] from set_border
[13] return
to:@return
void run(struct Task* run::task)
run: scope:[run] from main::@2
[14] stackpush(byte) = ((byte*)tasks)[main::$5]
[15] callexecute *(((void(byte)**)run::task#0)[OFFSET_STRUCT_TASK_HANDLER])
sideeffect stackpullbytes(1)
to:run::@return
run::@return: scope:[run] from run
[17] return
to:@return
VARIABLE REGISTER WEIGHTS
void main()
byte~ main::$5 61.5
byte~ main::$6 22.0
byte main::i
byte main::i#1 22.0
byte main::i#2 24.16666666666666
void run(struct Task* run::task)
struct Task* run::task
struct Task* run::task#0 110.0
__stackcall void set_bg(byte set_bg::col)
byte set_bg::col
byte set_bg::col#0 4.0
__stackcall void set_border(byte set_border::col)
byte set_border::col
byte set_border::col#0 4.0
Initial phi equivalence classes
[ main::i#2 main::i#1 ]
Added variable main::$6 to live range equivalence class [ main::$6 ]
Added variable main::$5 to live range equivalence class [ main::$5 ]
Added variable run::task#0 to live range equivalence class [ run::task#0 ]
Added variable set_bg::col#0 to live range equivalence class [ set_bg::col#0 ]
Added variable set_border::col#0 to live range equivalence class [ set_border::col#0 ]
Complete equivalence classes
[ main::i#2 main::i#1 ]
[ main::$6 ]
[ main::$5 ]
[ run::task#0 ]
[ set_bg::col#0 ]
[ set_border::col#0 ]
Allocated zp[1]:2 [ main::i#2 main::i#1 ]
Allocated zp[1]:3 [ main::$6 ]
Allocated zp[1]:4 [ main::$5 ]
Allocated zp[2]:5 [ run::task#0 ]
Allocated zp[1]:7 [ set_bg::col#0 ]
Allocated zp[1]:8 [ set_border::col#0 ]
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [3] main::$6 = main::i#2 << 1 [ main::i#2 main::$6 ] ( [ main::i#2 main::$6 ] { } ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp[1]:2 [ main::i#2 main::i#1 ]
Statement [4] main::$5 = main::$6 + main::i#2 [ main::i#2 main::$5 ] ( [ main::i#2 main::$5 ] { } ) always clobbers reg byte a
Statement [5] run::task#0 = tasks + main::$5 [ main::i#2 main::$5 ] ( [ main::i#2 main::$5 ] { } ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp[1]:4 [ main::$5 ]
Statement [8] set_bg::col#0 = stackidx(byte,set_bg::OFFSET_STACK_COL) [ set_bg::col#0 ] ( [ set_bg::col#0 ] { } ) always clobbers reg byte a reg byte x
Statement [11] set_border::col#0 = stackidx(byte,set_border::OFFSET_STACK_COL) [ set_border::col#0 ] ( [ set_border::col#0 ] { } ) always clobbers reg byte a reg byte x
Statement [14] stackpush(byte) = ((byte*)tasks)[main::$5] [ ] ( run:6 [ main::i#2 ] { } ) always clobbers reg byte a
Statement [15] callexecute *(((void(byte)**)run::task#0)[OFFSET_STRUCT_TASK_HANDLER]) [ ] ( run:6 [ main::i#2 ] { } ) always clobbers reg byte a reg byte x reg byte y
Removing always clobbered register reg byte x as potential for zp[1]:2 [ main::i#2 main::i#1 ]
Removing always clobbered register reg byte y as potential for zp[1]:2 [ main::i#2 main::i#1 ]
Statement sideeffect stackpullbytes(1) always clobbers reg byte a
Statement [2] if(main::i#2<4*SIZEOF_STRUCT_TASK/SIZEOF_STRUCT_TASK) goto main::@2 [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a
Statement [3] main::$6 = main::i#2 << 1 [ main::i#2 main::$6 ] ( [ main::i#2 main::$6 ] { } ) always clobbers reg byte a
Statement [4] main::$5 = main::$6 + main::i#2 [ main::i#2 main::$5 ] ( [ main::i#2 main::$5 ] { } ) always clobbers reg byte a
Statement [5] run::task#0 = tasks + main::$5 [ main::i#2 main::$5 ] ( [ main::i#2 main::$5 ] { } ) always clobbers reg byte a
Statement [8] set_bg::col#0 = stackidx(byte,set_bg::OFFSET_STACK_COL) [ set_bg::col#0 ] ( [ set_bg::col#0 ] { } ) always clobbers reg byte a reg byte x
Statement [11] set_border::col#0 = stackidx(byte,set_border::OFFSET_STACK_COL) [ set_border::col#0 ] ( [ set_border::col#0 ] { } ) always clobbers reg byte a reg byte x
Statement [14] stackpush(byte) = ((byte*)tasks)[main::$5] [ ] ( run:6 [ main::i#2 ] { } ) always clobbers reg byte a
Statement [15] callexecute *(((void(byte)**)run::task#0)[OFFSET_STRUCT_TASK_HANDLER]) [ ] ( run:6 [ main::i#2 ] { } ) always clobbers reg byte a reg byte x reg byte y
Statement sideeffect stackpullbytes(1) always clobbers reg byte a
Potential registers zp[1]:2 [ main::i#2 main::i#1 ] : zp[1]:2 ,
Potential registers zp[1]:3 [ main::$6 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:4 [ main::$5 ] : zp[1]:4 , reg byte x , reg byte y ,
Potential registers zp[2]:5 [ run::task#0 ] : zp[2]:5 ,
Potential registers zp[1]:7 [ set_bg::col#0 ] : zp[1]:7 , reg byte a , reg byte x , reg byte y ,
Potential registers zp[1]:8 [ set_border::col#0 ] : zp[1]:8 , reg byte a , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 61.5: zp[1]:4 [ main::$5 ] 46.17: zp[1]:2 [ main::i#2 main::i#1 ] 22: zp[1]:3 [ main::$6 ]
Uplift Scope [run] 110: zp[2]:5 [ run::task#0 ]
Uplift Scope [set_border] 4: zp[1]:8 [ set_border::col#0 ]
Uplift Scope [set_bg] 4: zp[1]:7 [ set_bg::col#0 ]
Uplift Scope [Task]
Uplift Scope []
Uplifting [main] best 2669 combination reg byte x [ main::$5 ] zp[1]:2 [ main::i#2 main::i#1 ] reg byte a [ main::$6 ]
Uplifting [run] best 2669 combination zp[2]:5 [ run::task#0 ]
Uplifting [set_border] best 2663 combination reg byte a [ set_border::col#0 ]
Uplifting [set_bg] best 2657 combination reg byte a [ set_bg::col#0 ]
Uplifting [Task] best 2657 combination
Uplifting [] best 2657 combination
Attempting to uplift remaining variables inzp[1]:2 [ main::i#2 main::i#1 ]
Uplifting [main] best 2657 combination zp[1]:2 [ main::i#2 main::i#1 ]
Allocated (was zp[2]:5) zp[2]:3 [ run::task#0 ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Calling a function pointer with return value
// Calling a function pointer inside a struct without *
// Upstart
// Commodore 64 PRG executable file
.file [name="function-pointer-return-3.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_STRUCT_TASK = 3
.const OFFSET_STRUCT_TASK_HANDLER = 1
.const STACK_BASE = $103
.label BORDER = $d020
.label BACKGROUND = $d021
.segment Code
// main
main: {
.label i = 2
// [1] phi from main main::@1 to main::@1 [phi:main/main::@1->main::@1]
__b1_from_main:
__b1_from___b1:
// [1] phi main::i#2 = 0 [phi:main/main::@1->main::@1#0] -- vbuz1=vbuc1
lda #0
sta.z i
jmp __b1
// main::@1
__b1:
// [2] if(main::i#2<4*SIZEOF_STRUCT_TASK/SIZEOF_STRUCT_TASK) goto main::@2 -- vbuz1_lt_vbuc1_then_la1
lda.z i
cmp #4*SIZEOF_STRUCT_TASK/SIZEOF_STRUCT_TASK
bcc __b2
jmp __b1_from___b1
// main::@2
__b2:
// [3] main::$6 = main::i#2 << 1 -- vbuaa=vbuz1_rol_1
lda.z i
asl
// [4] main::$5 = main::$6 + main::i#2 -- vbuxx=vbuaa_plus_vbuz1
clc
adc.z i
tax
// [5] run::task#0 = tasks + main::$5 -- pssz1=pssc1_plus_vbuxx
txa
clc
adc #<tasks
sta.z run.task
lda #>tasks
adc #0
sta.z run.task+1
// [6] call run
jsr run
jmp __b3
// main::@3
__b3:
// [7] main::i#1 = ++ main::i#2 -- vbuz1=_inc_vbuz1
inc.z i
// [1] phi from main::@3 to main::@1 [phi:main::@3->main::@1]
__b1_from___b3:
// [1] phi main::i#2 = main::i#1 [phi:main::@3->main::@1#0] -- register_copy
jmp __b1
}
// set_bg
// set_bg(byte register(A) col)
set_bg: {
.const OFFSET_STACK_COL = 0
// [8] set_bg::col#0 = stackidx(byte,set_bg::OFFSET_STACK_COL) -- vbuaa=_stackidxbyte_vbuc1
tsx
lda STACK_BASE+OFFSET_STACK_COL,x
// [9] *BACKGROUND = set_bg::col#0 -- _deref_pbuc1=vbuaa
sta BACKGROUND
jmp __breturn
// set_bg::@return
__breturn:
// [10] return
rts
}
// set_border
// set_border(byte register(A) col)
set_border: {
.const OFFSET_STACK_COL = 0
// [11] set_border::col#0 = stackidx(byte,set_border::OFFSET_STACK_COL) -- vbuaa=_stackidxbyte_vbuc1
tsx
lda STACK_BASE+OFFSET_STACK_COL,x
// [12] *BORDER = set_border::col#0 -- _deref_pbuc1=vbuaa
sta BORDER
jmp __breturn
// set_border::@return
__breturn:
// [13] return
rts
}
// run
// run(struct Task* zp(3) task)
run: {
.label task = 3
// [14] stackpush(byte) = ((byte*)tasks)[main::$5] -- _stackpushbyte_=pbuc1_derefidx_vbuxx
lda tasks,x
pha
// [15] callexecute *(((void(byte)**)run::task#0)[OFFSET_STRUCT_TASK_HANDLER]) -- call__deref_(qprz1_derefidx_vbuc1)
ldy #OFFSET_STRUCT_TASK_HANDLER
lda (task),y
sta !+ +1
iny
lda (task),y
sta !+ +2
!:
jsr 0
// sideeffect stackpullbytes(1) -- _stackpullbyte_1
pla
jmp __breturn
// run::@return
__breturn:
// [17] return
rts
}
// File Data
.segment Data
tasks: .byte 0
.word set_border
.byte 0
.word set_bg
.byte 1
.word set_border
.byte 2
.word set_bg
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __b3
Removing instruction jmp __breturn
Removing instruction jmp __breturn
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __b1_from_main:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction __b3:
Removing instruction __b1_from___b3:
Removing instruction __breturn:
Removing instruction __breturn:
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Relabelling long label __b1_from___b1 to __b3
Succesful ASM optimization Pass5RelabelLongLabels
FINAL SYMBOL TABLE
constant byte* const BACKGROUND = (byte*) 53281
constant byte* const BORDER = (byte*) 53280
constant byte OFFSET_STRUCT_TASK_HANDLER = 1
constant byte SIZEOF_STRUCT_TASK = 3
constant word STACK_BASE = $103
void main()
byte~ main::$5 reg byte x 61.5
byte~ main::$6 reg byte a 22.0
byte main::i
byte main::i#1 i zp[1]:2 22.0
byte main::i#2 i zp[1]:2 24.16666666666666
void run(struct Task* run::task)
struct Task* run::task
struct Task* run::task#0 task zp[2]:3 110.0
__stackcall void set_bg(byte set_bg::col)
constant byte set_bg::OFFSET_STACK_COL = 0
byte set_bg::col
byte set_bg::col#0 reg byte a 4.0
__stackcall void set_border(byte set_border::col)
constant byte set_border::OFFSET_STACK_COL = 0
byte set_border::col
byte set_border::col#0 reg byte a 4.0
constant struct Task* tasks[] = { { param: 0, handler: &set_border }, { param: 0, handler: &set_bg }, { param: 1, handler: &set_border }, { param: 2, handler: &set_bg } }
zp[1]:2 [ main::i#2 main::i#1 ]
reg byte a [ main::$6 ]
reg byte x [ main::$5 ]
zp[2]:3 [ run::task#0 ]
reg byte a [ set_bg::col#0 ]
reg byte a [ set_border::col#0 ]
FINAL ASSEMBLER
Score: 2318
// File Comments
// Calling a function pointer with return value
// Calling a function pointer inside a struct without *
// Upstart
// Commodore 64 PRG executable file
.file [name="function-pointer-return-3.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_STRUCT_TASK = 3
.const OFFSET_STRUCT_TASK_HANDLER = 1
.const STACK_BASE = $103
.label BORDER = $d020
.label BACKGROUND = $d021
.segment Code
// main
main: {
.label i = 2
// [1] phi from main main::@1 to main::@1 [phi:main/main::@1->main::@1]
__b3:
// [1] phi main::i#2 = 0 [phi:main/main::@1->main::@1#0] -- vbuz1=vbuc1
lda #0
sta.z i
// main::@1
__b1:
// for(char i=0; i < sizeof(tasks)/sizeof(struct Task); i++)
// [2] if(main::i#2<4*SIZEOF_STRUCT_TASK/SIZEOF_STRUCT_TASK) goto main::@2 -- vbuz1_lt_vbuc1_then_la1
lda.z i
cmp #4*SIZEOF_STRUCT_TASK/SIZEOF_STRUCT_TASK
bcc __b2
jmp __b3
// main::@2
__b2:
// tasks+i
// [3] main::$6 = main::i#2 << 1 -- vbuaa=vbuz1_rol_1
lda.z i
asl
// [4] main::$5 = main::$6 + main::i#2 -- vbuxx=vbuaa_plus_vbuz1
clc
adc.z i
tax
// run(tasks+i)
// [5] run::task#0 = tasks + main::$5 -- pssz1=pssc1_plus_vbuxx
txa
clc
adc #<tasks
sta.z run.task
lda #>tasks
adc #0
sta.z run.task+1
// [6] call run
jsr run
// main::@3
// for(char i=0; i < sizeof(tasks)/sizeof(struct Task); i++)
// [7] main::i#1 = ++ main::i#2 -- vbuz1=_inc_vbuz1
inc.z i
// [1] phi from main::@3 to main::@1 [phi:main::@3->main::@1]
// [1] phi main::i#2 = main::i#1 [phi:main::@3->main::@1#0] -- register_copy
jmp __b1
}
// set_bg
// set_bg(byte register(A) col)
set_bg: {
.const OFFSET_STACK_COL = 0
// [8] set_bg::col#0 = stackidx(byte,set_bg::OFFSET_STACK_COL) -- vbuaa=_stackidxbyte_vbuc1
tsx
lda STACK_BASE+OFFSET_STACK_COL,x
// *BACKGROUND = col
// [9] *BACKGROUND = set_bg::col#0 -- _deref_pbuc1=vbuaa
sta BACKGROUND
// set_bg::@return
// }
// [10] return
rts
}
// set_border
// set_border(byte register(A) col)
set_border: {
.const OFFSET_STACK_COL = 0
// [11] set_border::col#0 = stackidx(byte,set_border::OFFSET_STACK_COL) -- vbuaa=_stackidxbyte_vbuc1
tsx
lda STACK_BASE+OFFSET_STACK_COL,x
// *BORDER = col
// [12] *BORDER = set_border::col#0 -- _deref_pbuc1=vbuaa
sta BORDER
// set_border::@return
// }
// [13] return
rts
}
// run
// run(struct Task* zp(3) task)
run: {
.label task = 3
// task->handler(task->param)
// [14] stackpush(byte) = ((byte*)tasks)[main::$5] -- _stackpushbyte_=pbuc1_derefidx_vbuxx
lda tasks,x
pha
// [15] callexecute *(((void(byte)**)run::task#0)[OFFSET_STRUCT_TASK_HANDLER]) -- call__deref_(qprz1_derefidx_vbuc1)
ldy #OFFSET_STRUCT_TASK_HANDLER
lda (task),y
sta !+ +1
iny
lda (task),y
sta !+ +2
!:
jsr 0
// sideeffect stackpullbytes(1) -- _stackpullbyte_1
pla
// run::@return
// }
// [17] return
rts
}
// File Data
.segment Data
tasks: .byte 0
.word set_border
.byte 0
.word set_bg
.byte 1
.word set_border
.byte 2
.word set_bg

View File

@ -0,0 +1,30 @@
constant byte* const BACKGROUND = (byte*) 53281
constant byte* const BORDER = (byte*) 53280
constant byte OFFSET_STRUCT_TASK_HANDLER = 1
constant byte SIZEOF_STRUCT_TASK = 3
constant word STACK_BASE = $103
void main()
byte~ main::$5 reg byte x 61.5
byte~ main::$6 reg byte a 22.0
byte main::i
byte main::i#1 i zp[1]:2 22.0
byte main::i#2 i zp[1]:2 24.16666666666666
void run(struct Task* run::task)
struct Task* run::task
struct Task* run::task#0 task zp[2]:3 110.0
__stackcall void set_bg(byte set_bg::col)
constant byte set_bg::OFFSET_STACK_COL = 0
byte set_bg::col
byte set_bg::col#0 reg byte a 4.0
__stackcall void set_border(byte set_border::col)
constant byte set_border::OFFSET_STACK_COL = 0
byte set_border::col
byte set_border::col#0 reg byte a 4.0
constant struct Task* tasks[] = { { param: 0, handler: &set_border }, { param: 0, handler: &set_bg }, { param: 1, handler: &set_border }, { param: 2, handler: &set_bg } }
zp[1]:2 [ main::i#2 main::i#1 ]
reg byte a [ main::$6 ]
reg byte x [ main::$5 ]
zp[2]:3 [ run::task#0 ]
reg byte a [ set_bg::col#0 ]
reg byte a [ set_border::col#0 ]