mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-03-07 11:30:29 +00:00
Implemented inline dword constructor dword dw = { wl, wh };
This commit is contained in:
parent
0c7883532e
commit
76d3e25b84
@ -179,7 +179,7 @@ public class Compiler {
|
||||
optimizations.add(new Pass2ConditionalJumpSimplification(program));
|
||||
optimizations.add(new Pass2ConstantIdentification(program));
|
||||
optimizations.add(new Pass2ConstantAdditionElimination(program));
|
||||
optimizations.add(new Pass2FixWordConstructors(program));
|
||||
optimizations.add(new Pass2FixInlineConstructors(program));
|
||||
optimizations.add(new PassNEliminateUnusedVars(program));
|
||||
optimizations.add(new Pass2NopCastElimination(program));
|
||||
pass2OptimizeSSA(optimizations);
|
||||
|
@ -0,0 +1,4 @@
|
||||
lda {z1}
|
||||
sta {c1}
|
||||
lda {z1}+1
|
||||
sta {c1}+1
|
@ -0,0 +1,6 @@
|
||||
ldy #0
|
||||
lda {z2}
|
||||
sta ({z1}),y
|
||||
iny
|
||||
lda {z2}+1
|
||||
sta ({z1}),y
|
@ -0,0 +1,4 @@
|
||||
lda #<{c1}
|
||||
sta {z1}
|
||||
lda #>{c1}
|
||||
sta {z1}+1
|
@ -0,0 +1,8 @@
|
||||
lda {z2}
|
||||
sta {z1}
|
||||
lda {z2}+1
|
||||
sta {z1}+1
|
||||
lda {z3}
|
||||
sta {z1}+2
|
||||
lda {z3}+1
|
||||
sta {z1}+3
|
@ -0,0 +1,7 @@
|
||||
lda {z1}
|
||||
sec
|
||||
sbc #<{c1}
|
||||
sta {z1}
|
||||
lda {z1}+1
|
||||
sbc #>{c1}
|
||||
sta {z1}+1
|
@ -14,6 +14,7 @@ public class Operator {
|
||||
public static final Operator DEREF = new Operator("*", "_deref_", Type.UNARY, 2);
|
||||
public static final Operator ADDRESS_OF = new Operator("&", "_addr_", Type.UNARY, 2);
|
||||
public static final Operator WORD = new Operator("w=", "_word_", Type.BINARY, 2);
|
||||
public static final Operator DWORD = new Operator("dw=", "_dword_", Type.BINARY, 2);
|
||||
public static final Operator DEREF_IDX = new Operator("*idx", "_derefidx_", Type.BINARY, 2);
|
||||
public static final Operator SET_LOWBYTE = new Operator("lo=", "_setlo_", Type.BINARY, 2);
|
||||
public static final Operator SET_HIBYTE = new Operator("hi=", "_sethi_", Type.BINARY, 2);
|
||||
|
@ -117,6 +117,8 @@ public class SymbolTypeInference {
|
||||
return type1;
|
||||
} else if(Operator.WORD.equals(operator)) {
|
||||
return SymbolType.WORD;
|
||||
} else if(Operator.DWORD.equals(operator)) {
|
||||
return SymbolType.DWORD;
|
||||
}
|
||||
|
||||
String op = operator.getOperator();
|
||||
@ -369,6 +371,12 @@ public class SymbolTypeInference {
|
||||
types.add(new SymbolTypeArray(elmType));
|
||||
types.add(SymbolType.WORD);
|
||||
return new SymbolTypeInline(types);
|
||||
} else if((list.getList().size() == 2 && SymbolType.isWord(elmType) )) {
|
||||
// Potentially a dword constructor - return a composite type
|
||||
ArrayList<SymbolType> types = new ArrayList<>();
|
||||
types.add(new SymbolTypeArray(elmType));
|
||||
types.add(SymbolType.DWORD);
|
||||
return new SymbolTypeInline(types);
|
||||
} else {
|
||||
return new SymbolTypeArray(elmType);
|
||||
}
|
||||
|
@ -0,0 +1,115 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.*;
|
||||
|
||||
import java.util.ListIterator;
|
||||
|
||||
/**
|
||||
* Identifies word constructors <code>{ b1, b2 }</code> and replaces
|
||||
* them with a binary operator <code>word w = b1 w= b2 ;</code>
|
||||
*/
|
||||
public class Pass2FixInlineConstructors extends Pass2SsaOptimization {
|
||||
|
||||
public Pass2FixInlineConstructors(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean step() {
|
||||
WordConstructor wordConstructor = new WordConstructor();
|
||||
ValueReplacer.executeAll(getGraph(), wordConstructor);
|
||||
DWordConstructor dwordConstructor = new DWordConstructor();
|
||||
ValueReplacer.executeAll(getGraph(), dwordConstructor);
|
||||
return wordConstructor.isOptimized() || dwordConstructor.isOptimized();
|
||||
}
|
||||
|
||||
/** Replaces { b1, b2 } with a w= operator */
|
||||
private class WordConstructor extends InlineConstructor {
|
||||
|
||||
public WordConstructor() {
|
||||
super(SymbolType.WORD, Operator.WORD);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isSubType(SymbolType elmType) {
|
||||
return SymbolType.isByte(elmType);
|
||||
}
|
||||
}
|
||||
|
||||
/** Replaces { w1, w2 } with a dw= operator */
|
||||
private class DWordConstructor extends InlineConstructor {
|
||||
|
||||
public DWordConstructor() {
|
||||
super(SymbolType.DWORD, Operator.DWORD);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isSubType(SymbolType elmType) {
|
||||
return SymbolType.isWord(elmType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private abstract class InlineConstructor implements ValueReplacer.Replacer {
|
||||
private SymbolTypeInteger constructType;
|
||||
private Operator constructOperator;
|
||||
private boolean optimized;
|
||||
|
||||
public InlineConstructor(SymbolTypeInteger constructType, Operator constructOperator) {
|
||||
this.constructType = constructType;
|
||||
this.constructOperator = constructOperator;
|
||||
}
|
||||
|
||||
protected abstract boolean isSubType(SymbolType elmType);
|
||||
|
||||
public boolean isOptimized() {
|
||||
return optimized;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ValueReplacer.ReplaceableValue replaceable, Statement currentStmt, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock) {
|
||||
RValue rValue = replaceable.get();
|
||||
if(rValue instanceof ValueList) {
|
||||
ValueList list = (ValueList) rValue;
|
||||
if(list.getList().size() == 2) {
|
||||
// We have a simple assignment of a length 2 value list to a variable
|
||||
SymbolType elmType1 = SymbolTypeInference.inferType(Pass2FixInlineConstructors.this.getScope(), list.getList().get(0));
|
||||
SymbolType elmType2 = SymbolTypeInference.inferType(Pass2FixInlineConstructors.this.getScope(), list.getList().get(1));
|
||||
if(isSubType(elmType1) && isSubType(elmType2)) {
|
||||
// We have a 2-element list { byte, byte }
|
||||
|
||||
// Check if we are assigning into a declared byte array
|
||||
if(currentStmt instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) currentStmt;
|
||||
if(assignment.getrValue1() == null && assignment.getOperator() == null && assignment.getrValue2().equals(rValue)) {
|
||||
SymbolType lType = SymbolTypeInference.inferType(Pass2FixInlineConstructors.this.getScope(), assignment.getlValue());
|
||||
if(lType instanceof SymbolTypeArray && isSubType(((SymbolTypeArray) lType).getElementType())) {
|
||||
// We are assigning into a declared byte array - do not convert!
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert list to a word constructor in a new tmp variable
|
||||
Scope currentScope = Pass2FixInlineConstructors.this.getScope().getScope(currentBlock.getScope());
|
||||
VariableIntermediate tmpVar = currentScope.addVariableIntermediate();
|
||||
tmpVar.setTypeInferred(constructType);
|
||||
// Move backward - to insert before the current statement
|
||||
stmtIt.previous();
|
||||
// Add assignment of the new tmpVar
|
||||
StatementAssignment assignment = new StatementAssignment(tmpVar.getRef(), list.getList().get(0), constructOperator, list.getList().get(1));
|
||||
stmtIt.add(assignment);
|
||||
// Move back before the current statement
|
||||
stmtIt.next();
|
||||
// Replace current value with the reference
|
||||
replaceable.set(tmpVar.getRef());
|
||||
Pass2FixInlineConstructors.this.getLog().append("Fixing inline constructor with " + assignment.toString());
|
||||
optimized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.*;
|
||||
|
||||
import java.util.ListIterator;
|
||||
|
||||
/**
|
||||
* Identifies word constructors <code>{ b1, b2 }</code> and replaces
|
||||
* them with a binary operator <code>word w = b1 w= b2 ;</code>
|
||||
*/
|
||||
public class Pass2FixWordConstructors extends Pass2SsaOptimization {
|
||||
|
||||
public Pass2FixWordConstructors(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean step() {
|
||||
final boolean[] optimized = {false};
|
||||
|
||||
ValueReplacer.executeAll(getGraph(), new ValueReplacer.Replacer() {
|
||||
@Override
|
||||
public void execute(ValueReplacer.ReplaceableValue replaceable, Statement currentStmt, ListIterator<Statement> stmtIt, ControlFlowBlock currentBlock) {
|
||||
RValue rValue = replaceable.get();
|
||||
if(rValue instanceof ValueList) {
|
||||
ValueList list = (ValueList) rValue;
|
||||
if(list.getList().size() == 2) {
|
||||
// We have a simple assignment of a length 2 value list to a variable
|
||||
SymbolType elmType1 = SymbolTypeInference.inferType(Pass2FixWordConstructors.this.getScope(), list.getList().get(0));
|
||||
SymbolType elmType2 = SymbolTypeInference.inferType(Pass2FixWordConstructors.this.getScope(), list.getList().get(1));
|
||||
if(SymbolType.isByte(elmType1) && SymbolType.isByte(elmType2)) {
|
||||
// We have a 2-element list { byte, byte }
|
||||
|
||||
// Check if we are assigning into a declared byte array
|
||||
if(currentStmt instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) currentStmt;
|
||||
if(assignment.getrValue1() == null && assignment.getOperator() == null && assignment.getrValue2().equals(rValue)) {
|
||||
SymbolType lType = SymbolTypeInference.inferType(Pass2FixWordConstructors.this.getScope(), assignment.getlValue());
|
||||
if(lType instanceof SymbolTypeArray && SymbolType.isByte(((SymbolTypeArray) lType).getElementType())) {
|
||||
// We are assigning into a declared byte array - do not convert!
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert list to a word constructor in a new tmp variable
|
||||
Scope currentScope = getScope().getScope(currentBlock.getScope());
|
||||
VariableIntermediate tmpVar = currentScope.addVariableIntermediate();
|
||||
tmpVar.setTypeInferred(SymbolType.WORD);
|
||||
// Move backward - to insert before the current statement
|
||||
stmtIt.previous();
|
||||
// Add assignment of the new tmpVar
|
||||
StatementAssignment assignment = new StatementAssignment(tmpVar.getRef(), list.getList().get(0), Operator.WORD, list.getList().get(1));
|
||||
stmtIt.add(assignment);
|
||||
// Move back before the current statement
|
||||
stmtIt.next();
|
||||
// Replace current value with the reference
|
||||
replaceable.set(tmpVar.getRef());
|
||||
Pass2FixWordConstructors.this.getLog().append("Fixing word constructor with " + assignment.toString());
|
||||
optimized[0] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return optimized[0];
|
||||
}
|
||||
|
||||
}
|
@ -167,6 +167,9 @@ public class Pass4CodeGeneration {
|
||||
if(SymbolType.isByte(constantArrayFilled.getElementType())) {
|
||||
asm.addDataFilled(asmName.replace("#", "_").replace("$", "_"), AsmDataNumeric.Type.BYTE, constantArrayFilled.getSize(), "0");
|
||||
added.add(asmName);
|
||||
} else if(SymbolType.isWord(constantArrayFilled.getElementType())) {
|
||||
asm.addDataFilled(asmName.replace("#", "_").replace("$", "_"), AsmDataNumeric.Type.WORD, constantArrayFilled.getSize(), "0");
|
||||
added.add(asmName);
|
||||
} else {
|
||||
throw new RuntimeException("Unhandled constant array element type " + constantArrayFilled.toString(program));
|
||||
}
|
||||
|
@ -45,12 +45,16 @@ public class TestPrograms {
|
||||
AsmFragmentTemplateUsages.logUsages(log, false, false, false, false, false, false);
|
||||
}
|
||||
|
||||
//@Test
|
||||
//public void testLineGen() throws IOException, URISyntaxException {
|
||||
// compileAndCompare("linegen");
|
||||
//}
|
||||
|
||||
@Test
|
||||
public void testLowHigh() throws IOException, URISyntaxException {
|
||||
compileAndCompare("test-lowhigh");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLongJump2() throws IOException, URISyntaxException {
|
||||
compileAndCompare("longjump2");
|
||||
|
30
src/test/java/dk/camelot64/kickc/test/kc/linegen.kc
Normal file
30
src/test/java/dk/camelot64/kickc/test/kc/linegen.kc
Normal file
@ -0,0 +1,30 @@
|
||||
// Linear table generator
|
||||
// Work in progress towards a sinus generator
|
||||
import "division.kc"
|
||||
import "print.kc"
|
||||
|
||||
void main() {
|
||||
word[20] lintab;
|
||||
lin16u_gen(557, 29793, lintab, 20);
|
||||
print_cls();
|
||||
for(byte i=0; i<20*2; i=i+2) {
|
||||
print_byte(i);
|
||||
print_str(" @");
|
||||
print_word(lintab[i]);
|
||||
print_ln();
|
||||
}
|
||||
}
|
||||
|
||||
// Generate word linear table
|
||||
// lintab - the table to generate into
|
||||
// length - the number of points in a total sinus wavelength (the size of the table)
|
||||
void lin16u_gen(word min, word max, word* lintab, word length) {
|
||||
word ampl = max-min;
|
||||
dword step = { rem16u, div16u(ampl, length-1) };
|
||||
dword val = { 0, min };
|
||||
for(word i=0; i<length; i++) {
|
||||
*lintab = >val;
|
||||
val = val + step;
|
||||
lintab = lintab+2;
|
||||
}
|
||||
}
|
49
src/test/java/dk/camelot64/kickc/test/kc/sinusgen.kc
Normal file
49
src/test/java/dk/camelot64/kickc/test/kc/sinusgen.kc
Normal file
@ -0,0 +1,49 @@
|
||||
// Sinus Generator functions using only multiplication, addition and bit shifting
|
||||
// USes a single division for converting the wavelength to a reciprocal.
|
||||
// Generates sinus using the series sin(x) = x - x^/3! + x^-5! - x^7/7! ...
|
||||
// Uses the approximation sin(x) = x - x^/6 + x^/128
|
||||
// Uses reciprocal
|
||||
// Generates the sinus value over the interval 0-PI/2 and uses mirroring to get the remaining values
|
||||
|
||||
import "division.kc"
|
||||
import "multiply.kc"
|
||||
import "print.kc"
|
||||
|
||||
void main() {
|
||||
|
||||
word[20] lintab;
|
||||
|
||||
lin16u_gen(1000, 30000, lintab, 20);
|
||||
|
||||
print_cls();
|
||||
for(byte i=0; i<20*2; i=i+2) {
|
||||
print_byte(i);
|
||||
print_str(" @");
|
||||
print_word(lintab[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Generate signed word sinus table
|
||||
// sintab - the table to generate into
|
||||
// wavelength - the number of sinus points in a total sinus wavelength (the size of the table)
|
||||
void sin16s_gen(word* sintab, word wavelength) {
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Generate word linear table
|
||||
// lintab - the table to generate into
|
||||
// length - the number of points in a total sinus wavelength (the size of the table)
|
||||
void lin16u_gen(word min, word max, word* lintab, word length) {
|
||||
word ampl = max-min;
|
||||
word dstep = div16u(ampl, length);
|
||||
|
||||
dword val = min<<16;
|
||||
for(word i=0; i<length; i++) {
|
||||
*lintab = >val;
|
||||
val = val + step;
|
||||
}
|
||||
|
||||
}
|
@ -2892,9 +2892,9 @@ Multiple usages for variable. Not optimizing sub-constant (byte) init_plot_table
|
||||
Multiple usages for variable. Not optimizing sub-constant (byte) init_plot_tables::y#2
|
||||
Multiple usages for variable. Not optimizing sub-constant (byte) init_plot_tables::y#2
|
||||
Multiple usages for variable. Not optimizing sub-constant (byte*) init_plot_tables::yoffs#2
|
||||
Fixing word constructor with plot::$2 ← *(plot_xhi#0 + plot::x#4) w= *(plot_xlo#0 + plot::x#4)
|
||||
Fixing word constructor with plot::$3 ← *(plot_yhi#0 + plot::y#4) w= *(plot_ylo#0 + plot::y#4)
|
||||
Succesful SSA optimization Pass2FixWordConstructors
|
||||
Fixing inline constructor with plot::$2 ← *(plot_xhi#0 + plot::x#4) w= *(plot_xlo#0 + plot::x#4)
|
||||
Fixing inline constructor with plot::$3 ← *(plot_yhi#0 + plot::y#4) w= *(plot_ylo#0 + plot::y#4)
|
||||
Succesful SSA optimization Pass2FixInlineConstructors
|
||||
Eliminating Noop Cast (byte*) plot::plotter#0 ← ((byte*)) (word~) plot::$0
|
||||
Succesful SSA optimization Pass2NopCastElimination
|
||||
Culled Empty Block (label) main::@4
|
||||
|
@ -214,8 +214,8 @@ Constant (const byte) main::$4 = >main::$3
|
||||
Succesful SSA optimization Pass2ConstantIdentification
|
||||
Constant (const byte[]) main::his#0 = { main::$0, main::$2, main::$4 }
|
||||
Succesful SSA optimization Pass2ConstantIdentification
|
||||
Fixing word constructor with main::$8 ← *(main::his#0 + main::h#4) w= main::l#2
|
||||
Succesful SSA optimization Pass2FixWordConstructors
|
||||
Fixing inline constructor with main::$8 ← *(main::his#0 + main::h#4) w= main::l#2
|
||||
Succesful SSA optimization Pass2FixInlineConstructors
|
||||
Eliminating Noop Cast (byte*) main::sc#0 ← ((byte*)) (word) main::w#0
|
||||
Succesful SSA optimization Pass2NopCastElimination
|
||||
Alias (word) main::w#0 = (word~) main::$8
|
||||
|
@ -2114,8 +2114,8 @@ Succesful SSA optimization Pass2ConstantIdentification
|
||||
Constant (const byte[]) prepareMEM::mem#2 = addMEMtoFAC::mem#0
|
||||
Constant (const byte[]) prepareMEM::mem#3 = divMEMbyFAC::mem#0
|
||||
Succesful SSA optimization Pass2ConstantIdentification
|
||||
Fixing word constructor with getFAC::$0 ← *(memHi#0) w= *(memLo#0)
|
||||
Succesful SSA optimization Pass2FixWordConstructors
|
||||
Fixing inline constructor with getFAC::$0 ← *(memHi#0) w= *(memLo#0)
|
||||
Succesful SSA optimization Pass2FixInlineConstructors
|
||||
Eliminating Noop Cast (byte*) prepareMEM::mem#0 ← ((byte*)) (word) setFAC::w#3
|
||||
Succesful SSA optimization Pass2NopCastElimination
|
||||
Culled Empty Block (label) print_ln::@2
|
||||
|
@ -4764,8 +4764,8 @@ Multiple usages for variable. Not optimizing sub-constant (byte) init::i#2
|
||||
Multiple usages for variable. Not optimizing sub-constant (byte) place_sprites::spr_x#2
|
||||
Multiple usages for variable. Not optimizing sub-constant (byte*) gen_sprites::spr#2
|
||||
Multiple usages for variable. Not optimizing sub-constant (byte*) gen_chargen_sprite::sprite#4
|
||||
Fixing word constructor with getFAC::$0 ← *(memHi#0) w= *(memLo#0)
|
||||
Succesful SSA optimization Pass2FixWordConstructors
|
||||
Fixing inline constructor with getFAC::$0 ← *(memHi#0) w= *(memLo#0)
|
||||
Succesful SSA optimization Pass2FixInlineConstructors
|
||||
Eliminating unused constant (const byte) progress_idx#35
|
||||
Succesful SSA optimization PassNEliminateUnusedVars
|
||||
Eliminating Noop Cast (byte*) prepareMEM::mem#0 ← ((byte*)) (word) setFAC::w#5
|
||||
|
@ -5931,8 +5931,8 @@ Constant (const byte[512]) mulf_tables_cmp::asm_sqr#0 = mula_sqr1_lo#0
|
||||
Constant (const byte[512]) mulf_tables_cmp::kc_sqr#0 = mulf_sqr1_lo#0
|
||||
Constant (const byte*) mulf_tables_cmp::$9 = mulf_sqr1_lo#0+mulf_tables_cmp::$8
|
||||
Succesful SSA optimization Pass2ConstantIdentification
|
||||
Fixing word constructor with mulf8u::$0 ← *(mulf8u::memB#0) w= *(mulf8u::memA#0)
|
||||
Succesful SSA optimization Pass2FixWordConstructors
|
||||
Fixing inline constructor with mulf8u::$0 ← *(mulf8u::memB#0) w= *(mulf8u::memA#0)
|
||||
Succesful SSA optimization Pass2FixInlineConstructors
|
||||
Eliminating Noop Cast (word) print_word::w#0 ← ((word)) (signed word) print_sword::w#5
|
||||
Eliminating Noop Cast (byte) print_byte::b#0 ← ((byte)) (signed byte) print_sbyte::b#4
|
||||
Eliminating Noop Cast (byte) mul8u::a#1 ← ((byte)) (signed byte) mul8s::a#0
|
||||
|
@ -190,10 +190,10 @@ Constant (const byte*) main::bgcol#0 = ((byte*))53281
|
||||
Succesful SSA optimization Pass2ConstantIdentification
|
||||
Consolidated array index constant in *(main::bs#0+1)
|
||||
Succesful SSA optimization Pass2ConstantAdditionElimination
|
||||
Fixing word constructor with main::$4 ← main::b#0 w= 0
|
||||
Fixing word constructor with main::$5 ← 1 w= 1
|
||||
Fixing word constructor with main::$6 ← 0 w= 0
|
||||
Succesful SSA optimization Pass2FixWordConstructors
|
||||
Fixing inline constructor with main::$4 ← main::b#0 w= 0
|
||||
Fixing inline constructor with main::$5 ← 1 w= 1
|
||||
Fixing inline constructor with main::$6 ← 0 w= 0
|
||||
Succesful SSA optimization Pass2FixInlineConstructors
|
||||
Eliminating Noop Cast (byte*) main::sc#0 ← ((byte*)) (word) main::w2#0
|
||||
Succesful SSA optimization Pass2NopCastElimination
|
||||
Alias (word) main::w#0 = (word~) main::$4
|
||||
|
Loading…
x
Reference in New Issue
Block a user