1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-02-06 13:31:05 +00:00

Added MAKELONG4() constant identification and removed need for declaration in source. Closes #675

This commit is contained in:
jespergravgaard 2021-07-02 21:56:23 +02:00
parent 56e9346eb1
commit c740b9f487
19 changed files with 1736 additions and 50 deletions

View File

@ -1,4 +1,4 @@
//KICKC FRAGMENT CACHE a95ddb03f a95ddcfb1
//KICKC FRAGMENT CACHE aafa246f3 aafa2666a
//FRAGMENT vbuzz=vbuc1
ldz #{c1}
//FRAGMENT vbuzz_lt_vbuc1_then_la1

View File

@ -1,4 +1,4 @@
//KICKC FRAGMENT CACHE a95ddb03f a95ddcfb1
//KICKC FRAGMENT CACHE aafa246f3 aafa2666a
//FRAGMENT _deref_pbuc1=vbuc2
lda #{c2}
sta {c1}

View File

@ -1,4 +1,4 @@
//KICKC FRAGMENT CACHE a95ddb03f a95ddcfb1
//KICKC FRAGMENT CACHE aafa246f3 aafa2666a
//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 a95ddb03f a95ddcfb1
//KICKC FRAGMENT CACHE aafa246f3 aafa2666a
//FRAGMENT _deref_pbuc1=_inc__deref_pbuc1
inc {c1}
//FRAGMENT isr_hardware_all_entry

View File

@ -1,4 +1,4 @@
//KICKC FRAGMENT CACHE a95ddb03f a95ddcfb1
//KICKC FRAGMENT CACHE aafa246f3 aafa2666a
//FRAGMENT vbuz1=_deref_pbuc1
lda {c1}
sta {z1}

View File

@ -0,0 +1,5 @@
stx {m1}
sty {m1}+1
sta {m1}+2
lda #{c1}
sta {m1}+3

View File

@ -378,6 +378,7 @@ public class Compiler {
optimizations.add(new PassNArrayElementAddressOfRewriting(program));
optimizations.add(new Pass2ConditionalJumpSequenceImprovement(program));
optimizations.add(new Pass2ConstantRValueConsolidation(program));
optimizations.add(new Pass2ConstantIntrinsics(program));
optimizations.add(new Pass2ConstantIdentification(program));
optimizations.add(new Pass2ConstantValues(program));
optimizations.add(new Pass2ConstantCallPointerIdentification(program));

View File

@ -8,6 +8,11 @@ import dk.camelot64.kickc.model.statements.StatementCall;
import dk.camelot64.kickc.model.symbols.Procedure;
import dk.camelot64.kickc.model.symbols.Scope;
import dk.camelot64.kickc.model.symbols.Symbol;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypeProcedure;
import java.util.Arrays;
/**
* Updates procedure calls to point to the actual procedure called.
@ -25,6 +30,29 @@ public class Pass1Procedures extends Pass2SsaOptimization {
if(statement instanceof StatementCall) {
StatementCall call = (StatementCall) statement;
String procedureName = call.getProcedureName();
if(procedureName.equals(Pass1ByteXIntrinsicRewrite.INTRINSIC_MAKELONG4)) {
if(getScope().getGlobalSymbol(Pass1ByteXIntrinsicRewrite.INTRINSIC_MAKELONG4) == null) {
// Add the intrinsic MAKEWORD4()
final Procedure makeword4 = new Procedure(
Pass1ByteXIntrinsicRewrite.INTRINSIC_MAKELONG4,
new SymbolTypeProcedure(SymbolType.DWORD, Arrays.asList(new SymbolType[]{ SymbolType.BYTE, SymbolType.BYTE, SymbolType.BYTE, SymbolType.BYTE})),
getScope(),
Scope.SEGMENT_CODE_DEFAULT, Scope.SEGMENT_DATA_DEFAULT,
Procedure.CallingConvention.INTRINSIC_CALL);
makeword4.setDeclaredIntrinsic(true);
final Variable hihi = new Variable("hihi", Variable.Kind.PHI_MASTER, SymbolType.BYTE, makeword4, Variable.MemoryArea.ZEROPAGE_MEMORY, Scope.SEGMENT_DATA_DEFAULT, null);
makeword4.add(hihi);
final Variable hilo = new Variable("hilo", Variable.Kind.PHI_MASTER, SymbolType.BYTE, makeword4, Variable.MemoryArea.ZEROPAGE_MEMORY, Scope.SEGMENT_DATA_DEFAULT, null);
makeword4.add(hilo);
final Variable lohi = new Variable("lohi", Variable.Kind.PHI_MASTER, SymbolType.BYTE, makeword4, Variable.MemoryArea.ZEROPAGE_MEMORY, Scope.SEGMENT_DATA_DEFAULT, null);
makeword4.add(lohi);
final Variable lolo = new Variable("lolo", Variable.Kind.PHI_MASTER, SymbolType.BYTE, makeword4, Variable.MemoryArea.ZEROPAGE_MEMORY, Scope.SEGMENT_DATA_DEFAULT, null);
makeword4.add(lolo);
makeword4.setParameters(Arrays.asList(hihi, hilo, lohi, lolo));
getScope().add(makeword4);
}
}
Scope localScope = (Scope) getScope().getSymbol(block.getScope());
final Symbol procedureSymbol = localScope.findSymbol(procedureName);
if(procedureSymbol == null)

View File

@ -0,0 +1,75 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.operators.Operators;
import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.statements.StatementAssignment;
import dk.camelot64.kickc.model.statements.StatementCall;
import dk.camelot64.kickc.model.symbols.Procedure;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.values.ConstantBinary;
import dk.camelot64.kickc.model.values.ConstantInteger;
import dk.camelot64.kickc.model.values.ConstantValue;
import dk.camelot64.kickc.model.values.RValue;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
/**
* Compiler Pass propagating identifying (intrinsic) calls that return a constant value
*/
public class Pass2ConstantIntrinsics extends Pass2SsaOptimization {
public Pass2ConstantIntrinsics(Program program) {
super(program);
}
@Override
public boolean step() {
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
final ListIterator<Statement> stmtIt = block.getStatements().listIterator();
while(stmtIt.hasNext()) {
Statement statement = stmtIt.next();
if(statement instanceof StatementCall) {
final StatementCall call = (StatementCall) statement;
final Procedure procedure = getScope().getProcedure(call.getProcedure());
if(procedure.isDeclaredIntrinsic()) {
if(procedure.getFullName().equals(Pass1ByteXIntrinsicRewrite.INTRINSIC_MAKELONG4)) {
List<ConstantValue> constParams = new ArrayList<>();
for(RValue parameter : call.getParameters()) {
final ConstantValue constParam = Pass2ConstantIdentification.getConstant(parameter);
if(constParam == null) break;
constParams.add(constParam);
}
if(constParams.size() == 4) {
// All parameters are constant - dword is constant
final ConstantBinary constValue = new ConstantBinary(
new ConstantBinary(constParams.get(0), Operators.MULTIPLY, new ConstantInteger(0x1000000l, SymbolType.DWORD)),
Operators.PLUS,
new ConstantBinary(
new ConstantBinary(constParams.get(1), Operators.MULTIPLY, new ConstantInteger(0x10000l, SymbolType.DWORD)),
Operators.PLUS,
new ConstantBinary(
new ConstantBinary(constParams.get(2), Operators.MULTIPLY, new ConstantInteger(0x100l, SymbolType.DWORD)),
Operators.PLUS,
constParams.get(3)
)
)
);
// Remove the intrinsic call
stmtIt.remove();
// Add the constant assignment
stmtIt.add(new StatementAssignment(call.getlValue(), constValue, call.isInitialAssignment(), call.getSource(), call.getComments()));
getLog().append("Identified constant dword "+call.toString(getProgram(), false));
}
}
}
}
}
}
return false;
}
}

View File

@ -9,6 +9,11 @@ import java.io.IOException;
*/
public class TestProgramsFast extends TestPrograms {
@Test
public void testMakeLong41() throws IOException {
compileAndCompare("makelong4-1.c");
}
@Test
public void testMakeLong40() throws IOException {
compileAndCompare("makelong4-0.c");

View File

@ -1,8 +1,5 @@
// Test MAKELONG4()
__intrinsic __intrinsiccall unsigned long MAKELONG4(char hihi,char hilo,char lohi,char lolo);
void main() {
unsigned long* const SCREEN = (unsigned int*)0x0400;
for(char lolo=0;lolo<100;lolo++)

View File

@ -0,0 +1,6 @@
// Test MAKELONG4() with constants
void main() {
unsigned long* const SCREEN = (unsigned int*)0x0400;
*SCREEN = MAKELONG4(1, 2, 3, 4);
}

View File

@ -90,7 +90,6 @@ byte MAKELONG4::hihi
byte MAKELONG4::hilo
byte MAKELONG4::lohi
byte MAKELONG4::lolo
dword MAKELONG4::return
void __start()
void main()
bool~ main::$0
@ -273,7 +272,6 @@ byte MAKELONG4::hihi
byte MAKELONG4::hilo
byte MAKELONG4::lohi
byte MAKELONG4::lolo
dword MAKELONG4::return
void main()
dword~ main::$4 10001.0
byte main::hihi
@ -776,7 +774,6 @@ byte MAKELONG4::hihi
byte MAKELONG4::hilo
byte MAKELONG4::lohi
byte MAKELONG4::lolo
dword MAKELONG4::return
void main()
dword~ main::$4 zp[4]:4 10001.0
constant dword* const main::SCREEN = (word*) 1024

View File

@ -3,7 +3,6 @@ byte MAKELONG4::hihi
byte MAKELONG4::hilo
byte MAKELONG4::lohi
byte MAKELONG4::lolo
dword MAKELONG4::return
void main()
dword~ main::$4 zp[4]:4 10001.0
constant dword* const main::SCREEN = (word*) 1024

View File

@ -0,0 +1,24 @@
// Test MAKELONG4() with constants
// Commodore 64 PRG executable file
.file [name="makelong4-1.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)
.segment Code
main: {
.label SCREEN = $400
// *SCREEN = MAKELONG4(1, 2, 3, 4)
lda #<1*$1000000+2*$10000+3*$100+4
sta SCREEN
lda #>1*$1000000+2*$10000+3*$100+4
sta SCREEN+1
lda #<1*$1000000+2*$10000+3*$100+4>>$10
sta SCREEN+2
lda #>1*$1000000+2*$10000+3*$100+4>>$10
sta SCREEN+3
// }
rts
}

View File

@ -0,0 +1,8 @@
void main()
main: scope:[main] from
[0] *main::SCREEN = 1*$1000000+2*$10000+3*$100+4
to:main::@return
main::@return: scope:[main] from main
[1] return
to:@return

View File

@ -0,0 +1,184 @@
CONTROL FLOW GRAPH SSA
void main()
main: scope:[main] from __start
main::$0 = call MAKELONG4 1 2 3 4
*main::SCREEN = main::$0
to:main::@return
main::@return: scope:[main] from main
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
__intrinsic __intrinsiccall dword MAKELONG4(byte MAKELONG4::hihi , byte MAKELONG4::hilo , byte MAKELONG4::lohi , byte MAKELONG4::lolo)
byte MAKELONG4::hihi
byte MAKELONG4::hilo
byte MAKELONG4::lohi
byte MAKELONG4::lolo
void __start()
void main()
dword~ main::$0
constant dword* const main::SCREEN = (word*)$400
Adding number conversion cast (unumber) 1 in main::$0 = call MAKELONG4 1 2 3 4
Adding number conversion cast (unumber) 2 in main::$0 = call MAKELONG4 (unumber)1 2 3 4
Adding number conversion cast (unumber) 3 in main::$0 = call MAKELONG4 (unumber)1 (unumber)2 3 4
Adding number conversion cast (unumber) 4 in main::$0 = call MAKELONG4 (unumber)1 (unumber)2 (unumber)3 4
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant pointer cast (word*) 1024
Simplifying constant integer cast 1
Simplifying constant integer cast 2
Simplifying constant integer cast 3
Simplifying constant integer cast 4
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 2
Finalized unsigned number type (byte) 3
Finalized unsigned number type (byte) 4
Successful SSA optimization PassNFinalizeNumberTypeConversions
Identified constant dword [0] main::$0 = call MAKELONG4 1 2 3 4
Constant main::$0 = 1*$1000000+2*$10000+3*$100+4
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
Constant inlined main::$0 = 1*$1000000+2*$10000+3*$100+4
Successful SSA optimization Pass2ConstantInlining
CALL GRAPH
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
FINAL CONTROL FLOW GRAPH
void main()
main: scope:[main] from
[0] *main::SCREEN = 1*$1000000+2*$10000+3*$100+4
to:main::@return
main::@return: scope:[main] from main
[1] return
to:@return
VARIABLE REGISTER WEIGHTS
__intrinsic __intrinsiccall dword MAKELONG4(byte MAKELONG4::hihi , byte MAKELONG4::hilo , byte MAKELONG4::lohi , byte MAKELONG4::lolo)
byte MAKELONG4::hihi
byte MAKELONG4::hilo
byte MAKELONG4::lohi
byte MAKELONG4::lolo
void main()
Initial phi equivalence classes
Complete equivalence classes
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] *main::SCREEN = 1*$1000000+2*$10000+3*$100+4 [ ] ( [ ] { } ) always clobbers reg byte a
REGISTER UPLIFT SCOPES
Uplift Scope [main]
Uplift Scope [MAKELONG4]
Uplift Scope []
Uplifting [main] best 33 combination
Uplifting [MAKELONG4] best 33 combination
Uplifting [] best 33 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test MAKELONG4() with constants
// Upstart
// Commodore 64 PRG executable file
.file [name="makelong4-1.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
.segment Code
// main
main: {
.label SCREEN = $400
// [0] *main::SCREEN = 1*$1000000+2*$10000+3*$100+4 -- _deref_pduc1=vduc2
lda #<1*$1000000+2*$10000+3*$100+4
sta SCREEN
lda #>1*$1000000+2*$10000+3*$100+4
sta SCREEN+1
lda #<1*$1000000+2*$10000+3*$100+4>>$10
sta SCREEN+2
lda #>1*$1000000+2*$10000+3*$100+4>>$10
sta SCREEN+3
jmp __breturn
// main::@return
__breturn:
// [1] return
rts
}
// File Data
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
__intrinsic __intrinsiccall dword MAKELONG4(byte MAKELONG4::hihi , byte MAKELONG4::hilo , byte MAKELONG4::lohi , byte MAKELONG4::lolo)
byte MAKELONG4::hihi
byte MAKELONG4::hilo
byte MAKELONG4::lohi
byte MAKELONG4::lolo
void main()
constant dword* const main::SCREEN = (word*) 1024
FINAL ASSEMBLER
Score: 30
// File Comments
// Test MAKELONG4() with constants
// Upstart
// Commodore 64 PRG executable file
.file [name="makelong4-1.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
.segment Code
// main
main: {
.label SCREEN = $400
// *SCREEN = MAKELONG4(1, 2, 3, 4)
// [0] *main::SCREEN = 1*$1000000+2*$10000+3*$100+4 -- _deref_pduc1=vduc2
lda #<1*$1000000+2*$10000+3*$100+4
sta SCREEN
lda #>1*$1000000+2*$10000+3*$100+4
sta SCREEN+1
lda #<1*$1000000+2*$10000+3*$100+4>>$10
sta SCREEN+2
lda #>1*$1000000+2*$10000+3*$100+4>>$10
sta SCREEN+3
// main::@return
// }
// [1] return
rts
}
// File Data

View File

@ -0,0 +1,8 @@
__intrinsic __intrinsiccall dword MAKELONG4(byte MAKELONG4::hihi , byte MAKELONG4::hilo , byte MAKELONG4::lohi , byte MAKELONG4::lolo)
byte MAKELONG4::hihi
byte MAKELONG4::hilo
byte MAKELONG4::lohi
byte MAKELONG4::lolo
void main()
constant dword* const main::SCREEN = (word*) 1024