1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-08-02 09:29:35 +00:00

Implemented inline dword constructor dword dw = { wl, wh };

This commit is contained in:
jespergravgaard 2018-02-18 15:35:17 +01:00
parent 0c7883532e
commit 76d3e25b84
20 changed files with 256 additions and 86 deletions

View File

@ -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);

View File

@ -0,0 +1,4 @@
lda {z1}
sta {c1}
lda {z1}+1
sta {c1}+1

View File

@ -0,0 +1,6 @@
ldy #0
lda {z2}
sta ({z1}),y
iny
lda {z2}+1
sta ({z1}),y

View File

@ -0,0 +1,4 @@
lda #<{c1}
sta {z1}
lda #>{c1}
sta {z1}+1

View File

@ -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

View File

@ -0,0 +1,7 @@
lda {z1}
sec
sbc #<{c1}
sta {z1}
lda {z1}+1
sbc #>{c1}
sta {z1}+1

View File

@ -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);

View File

@ -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);
}

View File

@ -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;
}
}
}
}
}
}

View File

@ -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];
}
}

View File

@ -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));
}

View File

@ -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");

View 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;
}
}

View 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;
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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