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:
parent
56e9346eb1
commit
c740b9f487
@ -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
|
||||
|
@ -1,4 +1,4 @@
|
||||
//KICKC FRAGMENT CACHE a95ddb03f a95ddcfb1
|
||||
//KICKC FRAGMENT CACHE aafa246f3 aafa2666a
|
||||
//FRAGMENT _deref_pbuc1=vbuc2
|
||||
lda #{c2}
|
||||
sta {c1}
|
||||
|
@ -1,4 +1,4 @@
|
||||
//KICKC FRAGMENT CACHE a95ddb03f a95ddcfb1
|
||||
//KICKC FRAGMENT CACHE aafa246f3 aafa2666a
|
||||
//FRAGMENT vbuz1=vbuc1
|
||||
lda #{c1}
|
||||
sta {z1}
|
||||
|
1425
src/main/fragment/cache/fragment-cache-mos6502x.asm
vendored
1425
src/main/fragment/cache/fragment-cache-mos6502x.asm
vendored
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -1,4 +1,4 @@
|
||||
//KICKC FRAGMENT CACHE a95ddb03f a95ddcfb1
|
||||
//KICKC FRAGMENT CACHE aafa246f3 aafa2666a
|
||||
//FRAGMENT vbuz1=_deref_pbuc1
|
||||
lda {c1}
|
||||
sta {z1}
|
||||
|
@ -0,0 +1,5 @@
|
||||
stx {m1}
|
||||
sty {m1}+1
|
||||
sta {m1}+2
|
||||
lda #{c1}
|
||||
sta {m1}+3
|
@ -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));
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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");
|
||||
|
@ -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++)
|
||||
|
6
src/test/kc/makelong4-1.c
Normal file
6
src/test/kc/makelong4-1.c
Normal file
@ -0,0 +1,6 @@
|
||||
// Test MAKELONG4() with constants
|
||||
|
||||
void main() {
|
||||
unsigned long* const SCREEN = (unsigned int*)0x0400;
|
||||
*SCREEN = MAKELONG4(1, 2, 3, 4);
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
24
src/test/ref/makelong4-1.asm
Normal file
24
src/test/ref/makelong4-1.asm
Normal 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
|
||||
}
|
8
src/test/ref/makelong4-1.cfg
Normal file
8
src/test/ref/makelong4-1.cfg
Normal 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
|
184
src/test/ref/makelong4-1.log
Normal file
184
src/test/ref/makelong4-1.log
Normal 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
|
||||
|
8
src/test/ref/makelong4-1.sym
Normal file
8
src/test/ref/makelong4-1.sym
Normal 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
|
||||
|
Loading…
x
Reference in New Issue
Block a user