1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-02-18 01:30:56 +00:00

Fixed problem with incorrect parenthesising of non-associative binary operators in constant expressions. Closes #450

This commit is contained in:
jespergravgaard 2020-05-27 09:05:20 +02:00
parent 67dedcc299
commit a63adec0f0
41 changed files with 1011 additions and 42 deletions

View File

@ -89,6 +89,7 @@ public class AsmFormat {
* @return * @return
*/ */
private static String getAsmConstantBinary(Program program, ConstantValue left, OperatorBinary operator, ConstantValue right, ScopeRef codeScope) { private static String getAsmConstantBinary(Program program, ConstantValue left, OperatorBinary operator, ConstantValue right, ScopeRef codeScope) {
if(Operators.MODULO.equals(operator)) { if(Operators.MODULO.equals(operator)) {
// Remainder operator % not supported by KickAss - use modulo function instead // Remainder operator % not supported by KickAss - use modulo function instead
return "mod(" + return "mod(" +
@ -96,11 +97,20 @@ public class AsmFormat {
"," + "," +
getAsmConstant(program, right, operator.getPrecedence(), codeScope) + getAsmConstant(program, right, operator.getPrecedence(), codeScope) +
")"; ")";
} else {
return getAsmConstant(program, left, operator.getPrecedence(), codeScope) +
operator.getOperator() +
getAsmConstant(program, right, operator.getPrecedence(), codeScope);
} }
// Handle non-associative operators - only handle right side since parser is left-associativeA-B-C = (A-B)-C
boolean rightParenthesis = false;
if(!operator.isAssociative()) {
if(right instanceof ConstantBinary && ((ConstantBinary) right).getOperator().equals(operator)) {
// Right sub-expression is also binary with the same non-associative operator
rightParenthesis = true;
}
}
return getAsmConstant(program, left, operator.getPrecedence(), codeScope) +
operator.getOperator() +
(rightParenthesis ? "(" : "") + getAsmConstant(program, right, operator.getPrecedence(), codeScope) + (rightParenthesis ? ")" : "");
} }
/** /**
@ -220,9 +230,9 @@ public class AsmFormat {
} else if(Operators.POS.equals(operator)) { } else if(Operators.POS.equals(operator)) {
return getAsmConstant(program, operand, outerPrecedence, codeScope); return getAsmConstant(program, operand, outerPrecedence, codeScope);
} else if(Operators.NEG.equals(operator) && operand instanceof ConstantUnary) { } else if(Operators.NEG.equals(operator) && operand instanceof ConstantUnary) {
return operator.getOperator() + "(" +getAsmConstant(program, operand, operator.getPrecedence(), codeScope)+ ")"; return operator.getOperator() + "(" + getAsmConstant(program, operand, operator.getPrecedence(), codeScope) + ")";
} else if(Operators.NEG.equals(operator) && operand instanceof ConstantInteger && ((ConstantInteger) operand).getInteger()<0) { } else if(Operators.NEG.equals(operator) && operand instanceof ConstantInteger && ((ConstantInteger) operand).getInteger() < 0) {
return operator.getOperator() + "(" +getAsmConstant(program, operand, operator.getPrecedence(), codeScope)+ ")"; return operator.getOperator() + "(" + getAsmConstant(program, operand, operator.getPrecedence(), codeScope) + ")";
} else { } else {
return operator.getOperator() + return operator.getOperator() +
getAsmConstant(program, operand, operator.getPrecedence(), codeScope); getAsmConstant(program, operand, operator.getPrecedence(), codeScope);

View File

@ -8,7 +8,7 @@ import dk.camelot64.kickc.model.values.ConstantLiteral;
public class OperatorAssignment extends OperatorBinary { public class OperatorAssignment extends OperatorBinary {
public OperatorAssignment(int precedence) { public OperatorAssignment(int precedence) {
super("=", "_assign_", precedence); super("=", "_assign_", precedence, false);
} }
@Override @Override

View File

@ -6,8 +6,12 @@ import dk.camelot64.kickc.model.values.ConstantLiteral;
/** A binary expression operator */ /** A binary expression operator */
public abstract class OperatorBinary extends Operator { public abstract class OperatorBinary extends Operator {
public OperatorBinary(String operator, String asmOperator, int precedence) { /** Is the operator associative, meaning that (A+B)+C = A+(B+C). */
private boolean associative;
public OperatorBinary(String operator, String asmOperator, int precedence, boolean associative) {
super(operator, asmOperator, Type.BINARY, precedence); super(operator, asmOperator, Type.BINARY, precedence);
this.associative = associative;
} }
/** /**
@ -26,4 +30,7 @@ public abstract class OperatorBinary extends Operator {
*/ */
public abstract SymbolType inferType(SymbolType left, SymbolType right); public abstract SymbolType inferType(SymbolType left, SymbolType right);
public boolean isAssociative() {
return associative;
}
} }

View File

@ -11,7 +11,7 @@ import dk.camelot64.kickc.model.values.ConstantPointer;
public class OperatorBitwiseAnd extends OperatorBinary { public class OperatorBitwiseAnd extends OperatorBinary {
public OperatorBitwiseAnd(int precedence) { public OperatorBitwiseAnd(int precedence) {
super("&", "_band_", precedence); super("&", "_band_", precedence, true);
} }
@Override @Override

View File

@ -14,7 +14,7 @@ import dk.camelot64.kickc.model.values.ConstantPointer;
public class OperatorBitwiseOr extends OperatorBinary { public class OperatorBitwiseOr extends OperatorBinary {
public OperatorBitwiseOr(int precedence) { public OperatorBitwiseOr(int precedence) {
super("|", "_bor_", precedence); super("|", "_bor_", precedence, true);
} }
@Override @Override

View File

@ -11,7 +11,7 @@ import dk.camelot64.kickc.model.values.ConstantPointer;
public class OperatorBitwiseXor extends OperatorBinary { public class OperatorBitwiseXor extends OperatorBinary {
public OperatorBitwiseXor(int precedence) { public OperatorBitwiseXor(int precedence) {
super("^", "_bxor_", precedence); super("^", "_bxor_", precedence, true);
} }
@Override @Override

View File

@ -11,7 +11,7 @@ import dk.camelot64.kickc.model.values.ConstantLiteral;
public class OperatorDWord extends OperatorBinary { public class OperatorDWord extends OperatorBinary {
public OperatorDWord(int precedence) { public OperatorDWord(int precedence) {
super("dw=", "_dword_", precedence); super("dw=", "_dword_", precedence, false);
} }
@Override @Override

View File

@ -9,7 +9,7 @@ import dk.camelot64.kickc.model.values.ConstantLiteral;
public class OperatorDerefIdx extends OperatorBinary { public class OperatorDerefIdx extends OperatorBinary {
public OperatorDerefIdx(int precedence) { public OperatorDerefIdx(int precedence) {
super("*idx=", "_derefidx_", precedence); super("*idx=", "_derefidx_", precedence, false);
} }
@Override @Override

View File

@ -10,7 +10,7 @@ import dk.camelot64.kickc.model.values.ConstantPointer;
public class OperatorDivide extends OperatorBinary { public class OperatorDivide extends OperatorBinary {
public OperatorDivide(int precedence) { public OperatorDivide(int precedence) {
super("/", "_div_", precedence); super("/", "_div_", precedence, false);
} }
@Override @Override

View File

@ -12,7 +12,7 @@ import java.util.Objects;
public class OperatorEqual extends OperatorBinary { public class OperatorEqual extends OperatorBinary {
public OperatorEqual(int precedence) { public OperatorEqual(int precedence) {
super("==", "_eq_", precedence); super("==", "_eq_", precedence, false);
} }
@Override @Override

View File

@ -8,7 +8,7 @@ import dk.camelot64.kickc.model.values.*;
public class OperatorGreaterThan extends OperatorBinary { public class OperatorGreaterThan extends OperatorBinary {
public OperatorGreaterThan(int precedence) { public OperatorGreaterThan(int precedence) {
super(">", "_gt_", precedence); super(">", "_gt_", precedence, false);
} }
@Override @Override

View File

@ -8,7 +8,7 @@ import dk.camelot64.kickc.model.values.*;
public class OperatorGreaterThanEqual extends OperatorBinary { public class OperatorGreaterThanEqual extends OperatorBinary {
public OperatorGreaterThanEqual(int precedence) { public OperatorGreaterThanEqual(int precedence) {
super(">=", "_ge_", precedence); super(">=", "_ge_", precedence, false);
} }
@Override @Override

View File

@ -10,7 +10,7 @@ import dk.camelot64.kickc.model.values.ConstantLiteral;
public class OperatorLessThan extends OperatorBinary { public class OperatorLessThan extends OperatorBinary {
public OperatorLessThan(int precedence) { public OperatorLessThan(int precedence) {
super("<", "_lt_", precedence); super("<", "_lt_", precedence, false);
} }
@Override @Override

View File

@ -8,7 +8,7 @@ import dk.camelot64.kickc.model.values.*;
public class OperatorLessThanEqual extends OperatorBinary { public class OperatorLessThanEqual extends OperatorBinary {
public OperatorLessThanEqual(int precedence) { public OperatorLessThanEqual(int precedence) {
super("<=", "_le_", precedence); super("<=", "_le_", precedence, false);
} }
@Override @Override

View File

@ -9,7 +9,7 @@ import dk.camelot64.kickc.model.values.ConstantLiteral;
public class OperatorLogicAnd extends OperatorBinary { public class OperatorLogicAnd extends OperatorBinary {
public OperatorLogicAnd(int precedence) { public OperatorLogicAnd(int precedence) {
super("&&", "_and_", precedence); super("&&", "_and_", precedence, true);
} }
@Override @Override

View File

@ -9,7 +9,7 @@ import dk.camelot64.kickc.model.values.ConstantLiteral;
public class OperatorLogicOr extends OperatorBinary { public class OperatorLogicOr extends OperatorBinary {
public OperatorLogicOr(int precedence) { public OperatorLogicOr(int precedence) {
super("||", "_or_", precedence); super("||", "_or_", precedence, true);
} }
@Override @Override

View File

@ -11,7 +11,7 @@ import dk.camelot64.kickc.model.values.*;
public class OperatorMinus extends OperatorBinary { public class OperatorMinus extends OperatorBinary {
public OperatorMinus(int precedence) { public OperatorMinus(int precedence) {
super("-", "_minus_", precedence); super("-", "_minus_", precedence, false);
} }
@Override @Override

View File

@ -10,7 +10,7 @@ import dk.camelot64.kickc.model.values.ConstantPointer;
public class OperatorModulo extends OperatorBinary { public class OperatorModulo extends OperatorBinary {
public OperatorModulo(int precedence) { public OperatorModulo(int precedence) {
super("%", "_mod_", precedence); super("%", "_mod_", precedence, false);
} }
@Override @Override

View File

@ -9,7 +9,7 @@ import dk.camelot64.kickc.model.values.ConstantLiteral;
public class OperatorMultiply extends OperatorBinary { public class OperatorMultiply extends OperatorBinary {
public OperatorMultiply(int precedence) { public OperatorMultiply(int precedence) {
super("*", "_mul_", precedence); super("*", "_mul_", precedence, true);
} }
@Override @Override

View File

@ -10,7 +10,7 @@ import java.util.Objects;
public class OperatorNotEqual extends OperatorBinary { public class OperatorNotEqual extends OperatorBinary {
public OperatorNotEqual(int precedence) { public OperatorNotEqual(int precedence) {
super("!=", "_neq_", precedence); super("!=", "_neq_", precedence, false);
} }
@Override @Override

View File

@ -12,7 +12,7 @@ import dk.camelot64.kickc.model.values.*;
public class OperatorPlus extends OperatorBinary { public class OperatorPlus extends OperatorBinary {
public OperatorPlus(int precedence) { public OperatorPlus(int precedence) {
super("+", "_plus_", precedence); super("+", "_plus_", precedence, true);
} }
@Override @Override

View File

@ -9,7 +9,7 @@ import dk.camelot64.kickc.model.values.ConstantLiteral;
public class OperatorSetHigh extends OperatorBinary { public class OperatorSetHigh extends OperatorBinary {
public OperatorSetHigh(int precedence) { public OperatorSetHigh(int precedence) {
super("hi=", "_sethi_", precedence); super("hi=", "_sethi_", precedence, false);
} }
@Override @Override

View File

@ -9,7 +9,7 @@ import dk.camelot64.kickc.model.values.ConstantLiteral;
public class OperatorSetLow extends OperatorBinary { public class OperatorSetLow extends OperatorBinary {
public OperatorSetLow(int precedence) { public OperatorSetLow(int precedence) {
super("lo=", "_setlo_", precedence); super("lo=", "_setlo_", precedence, false);
} }
@Override @Override

View File

@ -9,7 +9,7 @@ import dk.camelot64.kickc.model.values.ConstantLiteral;
public class OperatorShiftLeft extends OperatorBinary { public class OperatorShiftLeft extends OperatorBinary {
public OperatorShiftLeft(int precedence) { public OperatorShiftLeft(int precedence) {
super("<<", "_rol_", precedence); super("<<", "_rol_", precedence, false);
} }
@Override @Override

View File

@ -9,7 +9,7 @@ import dk.camelot64.kickc.model.values.ConstantLiteral;
public class OperatorShiftRight extends OperatorBinary { public class OperatorShiftRight extends OperatorBinary {
public OperatorShiftRight(int precedence) { public OperatorShiftRight(int precedence) {
super(">>", "_ror_", precedence); super(">>", "_ror_", precedence, false);
} }
@Override @Override

View File

@ -10,7 +10,7 @@ import dk.camelot64.kickc.model.values.ConstantLiteral;
public class OperatorWord extends OperatorBinary { public class OperatorWord extends OperatorBinary {
public OperatorWord(int precedence) { public OperatorWord(int precedence) {
super("w=", "_word_", precedence); super("w=", "_word_", precedence, false);
} }
@Override @Override

View File

@ -44,6 +44,18 @@ public class TestPrograms {
public TestPrograms() { public TestPrograms() {
} }
@Test
public void testProblemMaVarOverwrite() throws IOException, URISyntaxException {
compileAndCompare("problem-ma-var-overwrite.c");
}
@Test
public void testMinusPrecedenceProblem() throws IOException, URISyntaxException {
compileAndCompare("minus-precedence-problem.c");
}
@Test @Test
public void testNesDemo() throws IOException, URISyntaxException { public void testNesDemo() throws IOException, URISyntaxException {
compileAndCompare("examples/nes/nes-demo.c"); compileAndCompare("examples/nes/nes-demo.c");

View File

@ -95,9 +95,9 @@ struct SpriteData SPRITES[] = {
// Color Palette // Color Palette
char PALETTE[0x20] = { char PALETTE[0x20] = {
// Background palettes // Background palettes
0x0f, 0x2d, 0x08, 0x18, 0x11, 0x2d, 0x08, 0x18,
0x0f, 0x06, 0x15, 0x36, 0x11, 0x06, 0x15, 0x36,
0x0f, 0x39, 0x4a, 0x5b, 0x11, 0x39, 0x4a, 0x5b,
0x0f, 0x3d, 0x4e, 0x5f, 0x0f, 0x3d, 0x4e, 0x5f,
// Sprite palettes (selected by the attribute bits 0-1 of the sprites) // Sprite palettes (selected by the attribute bits 0-1 of the sprites)
0x11, 0x0f, 0x30, 0x08, // Goomba upper colors 0x11, 0x0f, 0x30, 0x08, // Goomba upper colors

View File

@ -0,0 +1,7 @@
const unsigned char matrixSize = 8;
const unsigned char matrixSizeMask = 255 - (matrixSize - 1);
void main(void)
{
*((unsigned char *)0x400) = matrixSizeMask;
}

View File

@ -0,0 +1,25 @@
// Demonstrates that a local __ma variable overwrites a parameter§
unsigned char *volatile h1; // This must be volatile because is used in an interrupt routine...
void test(unsigned char *videoMem, unsigned char *colorMem, unsigned char *other)
{
unsigned char *diff;
__ma unsigned char *dst; // This must be declared as __ma because is used in an assembly routine...
diff = colorMem - videoMem;
dst = other + ((unsigned int)diff);
dst[0] = 1;
asm {
ldy #0
lda #1
sta (dst),y
}
}
void main(void)
{
test(h1, 0xD800, 0xC000);
}

View File

@ -543,7 +543,7 @@ readJoy1: {
// Sprite Data // Sprite Data
SPRITES: .byte $96, $36, 2, $c, $96, $37, 2, $14, $9e, $38, 2, $c, $9e, $39, 2, $14, $96, $70, 0, $48, $96, $71, 0, $50, $9e, $72, 1, $48, $9e, $73, 1, $50 SPRITES: .byte $96, $36, 2, $c, $96, $37, 2, $14, $9e, $38, 2, $c, $9e, $39, 2, $14, $96, $70, 0, $48, $96, $71, 0, $50, $9e, $72, 1, $48, $9e, $73, 1, $50
// Color Palette // Color Palette
PALETTE: .byte $f, $2d, 8, $18, $f, 6, $15, $36, $f, $39, $4a, $5b, $f, $3d, $4e, $5f, $11, $f, $30, 8, $11, $f, $18, 8, $11, $30, $37, $1a, $f, $f, $f, $f PALETTE: .byte $11, $2d, 8, $18, $11, 6, $15, $36, $11, $39, $4a, $5b, $f, $3d, $4e, $5f, $11, $f, $30, 8, $11, $f, $18, 8, $11, $30, $37, $1a, $f, $f, $f, $f
.segment Tiles .segment Tiles
TILES: TILES:
.import binary "smb1_chr.bin" .import binary "smb1_chr.bin"

View File

@ -627,7 +627,7 @@ SYMBOL TABLE SSA
(const byte) OFFSET_STRUCT_RICOH_2C02_PPUSTATUS = (byte) 2 (const byte) OFFSET_STRUCT_RICOH_2C02_PPUSTATUS = (byte) 2
(const byte) OFFSET_STRUCT_SPRITEDATA_X = (byte) 3 (const byte) OFFSET_STRUCT_SPRITEDATA_X = (byte) 3
(const byte) OFFSET_STRUCT_SPRITEDATA_Y = (byte) 0 (const byte) OFFSET_STRUCT_SPRITEDATA_Y = (byte) 0
(const byte*) PALETTE[(number) $20] = { (byte) $f, (byte) $2d, (byte) 8, (byte) $18, (byte) $f, (byte) 6, (byte) $15, (byte) $36, (byte) $f, (byte) $39, (byte) $4a, (byte) $5b, (byte) $f, (byte) $3d, (byte) $4e, (byte) $5f, (byte) $11, (byte) $f, (byte) $30, (byte) 8, (byte) $11, (byte) $f, (byte) $18, (byte) 8, (byte) $11, (byte) $30, (byte) $37, (byte) $1a, (byte) $f, (byte) $f, (byte) $f, (byte) $f } (const byte*) PALETTE[(number) $20] = { (byte) $11, (byte) $2d, (byte) 8, (byte) $18, (byte) $11, (byte) 6, (byte) $15, (byte) $36, (byte) $11, (byte) $39, (byte) $4a, (byte) $5b, (byte) $f, (byte) $3d, (byte) $4e, (byte) $5f, (byte) $11, (byte) $f, (byte) $30, (byte) 8, (byte) $11, (byte) $f, (byte) $18, (byte) 8, (byte) $11, (byte) $30, (byte) $37, (byte) $1a, (byte) $f, (byte) $f, (byte) $f, (byte) $f }
(const struct RICOH_2C02*) PPU = (struct RICOH_2C02*)(number) $2000 (const struct RICOH_2C02*) PPU = (struct RICOH_2C02*)(number) $2000
(const nomodify byte*) PPU_ATTRIBUTE_TABLE_0 = (byte*)(number) $23c0 (const nomodify byte*) PPU_ATTRIBUTE_TABLE_0 = (byte*)(number) $23c0
(const nomodify byte*) PPU_NAME_TABLE_0 = (byte*)(number) $2000 (const nomodify byte*) PPU_NAME_TABLE_0 = (byte*)(number) $2000
@ -3335,7 +3335,7 @@ readJoy1: {
// Sprite Data // Sprite Data
SPRITES: .byte $96, $36, 2, $c, $96, $37, 2, $14, $9e, $38, 2, $c, $9e, $39, 2, $14, $96, $70, 0, $48, $96, $71, 0, $50, $9e, $72, 1, $48, $9e, $73, 1, $50 SPRITES: .byte $96, $36, 2, $c, $96, $37, 2, $14, $9e, $38, 2, $c, $9e, $39, 2, $14, $96, $70, 0, $48, $96, $71, 0, $50, $9e, $72, 1, $48, $9e, $73, 1, $50
// Color Palette // Color Palette
PALETTE: .byte $f, $2d, 8, $18, $f, 6, $15, $36, $f, $39, $4a, $5b, $f, $3d, $4e, $5f, $11, $f, $30, 8, $11, $f, $18, 8, $11, $30, $37, $1a, $f, $f, $f, $f PALETTE: .byte $11, $2d, 8, $18, $11, 6, $15, $36, $11, $39, $4a, $5b, $f, $3d, $4e, $5f, $11, $f, $30, 8, $11, $f, $18, 8, $11, $30, $37, $1a, $f, $f, $f, $f
.segment Tiles .segment Tiles
TILES: TILES:
.import binary "smb1_chr.bin" .import binary "smb1_chr.bin"
@ -4380,7 +4380,7 @@ readJoy1: {
// Sprite Data // Sprite Data
SPRITES: .byte $96, $36, 2, $c, $96, $37, 2, $14, $9e, $38, 2, $c, $9e, $39, 2, $14, $96, $70, 0, $48, $96, $71, 0, $50, $9e, $72, 1, $48, $9e, $73, 1, $50 SPRITES: .byte $96, $36, 2, $c, $96, $37, 2, $14, $9e, $38, 2, $c, $9e, $39, 2, $14, $96, $70, 0, $48, $96, $71, 0, $50, $9e, $72, 1, $48, $9e, $73, 1, $50
// Color Palette // Color Palette
PALETTE: .byte $f, $2d, 8, $18, $f, 6, $15, $36, $f, $39, $4a, $5b, $f, $3d, $4e, $5f, $11, $f, $30, 8, $11, $f, $18, 8, $11, $30, $37, $1a, $f, $f, $f, $f PALETTE: .byte $11, $2d, 8, $18, $11, 6, $15, $36, $11, $39, $4a, $5b, $f, $3d, $4e, $5f, $11, $f, $30, 8, $11, $f, $18, 8, $11, $30, $37, $1a, $f, $f, $f, $f
.segment Tiles .segment Tiles
TILES: TILES:
.import binary "smb1_chr.bin" .import binary "smb1_chr.bin"
@ -4576,7 +4576,7 @@ FINAL SYMBOL TABLE
(const byte) OFFSET_STRUCT_RICOH_2C02_PPUSCROLL = (byte) 5 (const byte) OFFSET_STRUCT_RICOH_2C02_PPUSCROLL = (byte) 5
(const byte) OFFSET_STRUCT_RICOH_2C02_PPUSTATUS = (byte) 2 (const byte) OFFSET_STRUCT_RICOH_2C02_PPUSTATUS = (byte) 2
(const byte) OFFSET_STRUCT_SPRITEDATA_X = (byte) 3 (const byte) OFFSET_STRUCT_SPRITEDATA_X = (byte) 3
(const byte*) PALETTE[(number) $20] = { (byte) $f, (byte) $2d, (byte) 8, (byte) $18, (byte) $f, (byte) 6, (byte) $15, (byte) $36, (byte) $f, (byte) $39, (byte) $4a, (byte) $5b, (byte) $f, (byte) $3d, (byte) $4e, (byte) $5f, (byte) $11, (byte) $f, (byte) $30, (byte) 8, (byte) $11, (byte) $f, (byte) $18, (byte) 8, (byte) $11, (byte) $30, (byte) $37, (byte) $1a, (byte) $f, (byte) $f, (byte) $f, (byte) $f } (const byte*) PALETTE[(number) $20] = { (byte) $11, (byte) $2d, (byte) 8, (byte) $18, (byte) $11, (byte) 6, (byte) $15, (byte) $36, (byte) $11, (byte) $39, (byte) $4a, (byte) $5b, (byte) $f, (byte) $3d, (byte) $4e, (byte) $5f, (byte) $11, (byte) $f, (byte) $30, (byte) 8, (byte) $11, (byte) $f, (byte) $18, (byte) 8, (byte) $11, (byte) $30, (byte) $37, (byte) $1a, (byte) $f, (byte) $f, (byte) $f, (byte) $f }
(const struct RICOH_2C02*) PPU = (struct RICOH_2C02*) 8192 (const struct RICOH_2C02*) PPU = (struct RICOH_2C02*) 8192
(const nomodify byte*) PPU_ATTRIBUTE_TABLE_0 = (byte*) 9152 (const nomodify byte*) PPU_ATTRIBUTE_TABLE_0 = (byte*) 9152
(const nomodify byte*) PPU_NAME_TABLE_0 = (byte*) 8192 (const nomodify byte*) PPU_NAME_TABLE_0 = (byte*) 8192
@ -5606,7 +5606,7 @@ readJoy1: {
// Sprite Data // Sprite Data
SPRITES: .byte $96, $36, 2, $c, $96, $37, 2, $14, $9e, $38, 2, $c, $9e, $39, 2, $14, $96, $70, 0, $48, $96, $71, 0, $50, $9e, $72, 1, $48, $9e, $73, 1, $50 SPRITES: .byte $96, $36, 2, $c, $96, $37, 2, $14, $9e, $38, 2, $c, $9e, $39, 2, $14, $96, $70, 0, $48, $96, $71, 0, $50, $9e, $72, 1, $48, $9e, $73, 1, $50
// Color Palette // Color Palette
PALETTE: .byte $f, $2d, 8, $18, $f, 6, $15, $36, $f, $39, $4a, $5b, $f, $3d, $4e, $5f, $11, $f, $30, 8, $11, $f, $18, 8, $11, $30, $37, $1a, $f, $f, $f, $f PALETTE: .byte $11, $2d, 8, $18, $11, 6, $15, $36, $11, $39, $4a, $5b, $f, $3d, $4e, $5f, $11, $f, $30, 8, $11, $f, $18, 8, $11, $30, $37, $1a, $f, $f, $f, $f
.segment Tiles .segment Tiles
TILES: TILES:
.import binary "smb1_chr.bin" .import binary "smb1_chr.bin"

View File

@ -20,7 +20,7 @@
(const byte) OFFSET_STRUCT_RICOH_2C02_PPUSCROLL = (byte) 5 (const byte) OFFSET_STRUCT_RICOH_2C02_PPUSCROLL = (byte) 5
(const byte) OFFSET_STRUCT_RICOH_2C02_PPUSTATUS = (byte) 2 (const byte) OFFSET_STRUCT_RICOH_2C02_PPUSTATUS = (byte) 2
(const byte) OFFSET_STRUCT_SPRITEDATA_X = (byte) 3 (const byte) OFFSET_STRUCT_SPRITEDATA_X = (byte) 3
(const byte*) PALETTE[(number) $20] = { (byte) $f, (byte) $2d, (byte) 8, (byte) $18, (byte) $f, (byte) 6, (byte) $15, (byte) $36, (byte) $f, (byte) $39, (byte) $4a, (byte) $5b, (byte) $f, (byte) $3d, (byte) $4e, (byte) $5f, (byte) $11, (byte) $f, (byte) $30, (byte) 8, (byte) $11, (byte) $f, (byte) $18, (byte) 8, (byte) $11, (byte) $30, (byte) $37, (byte) $1a, (byte) $f, (byte) $f, (byte) $f, (byte) $f } (const byte*) PALETTE[(number) $20] = { (byte) $11, (byte) $2d, (byte) 8, (byte) $18, (byte) $11, (byte) 6, (byte) $15, (byte) $36, (byte) $11, (byte) $39, (byte) $4a, (byte) $5b, (byte) $f, (byte) $3d, (byte) $4e, (byte) $5f, (byte) $11, (byte) $f, (byte) $30, (byte) 8, (byte) $11, (byte) $f, (byte) $18, (byte) 8, (byte) $11, (byte) $30, (byte) $37, (byte) $1a, (byte) $f, (byte) $f, (byte) $f, (byte) $f }
(const struct RICOH_2C02*) PPU = (struct RICOH_2C02*) 8192 (const struct RICOH_2C02*) PPU = (struct RICOH_2C02*) 8192
(const nomodify byte*) PPU_ATTRIBUTE_TABLE_0 = (byte*) 9152 (const nomodify byte*) PPU_ATTRIBUTE_TABLE_0 = (byte*) 9152
(const nomodify byte*) PPU_NAME_TABLE_0 = (byte*) 8192 (const nomodify byte*) PPU_NAME_TABLE_0 = (byte*) 8192

View File

@ -0,0 +1,12 @@
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.const matrixSize = 8
.const matrixSizeMask = $ff-(matrixSize-1)
main: {
// *((unsigned char *)0x400) = matrixSizeMask
lda #matrixSizeMask
sta $400
// }
rts
}

View File

@ -0,0 +1,17 @@
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
(void()) main()
main: scope:[main] from @1
[4] *((byte*) 1024) ← (const nomodify byte) matrixSizeMask
to:main::@return
main::@return: scope:[main] from main
[5] return
to:@return

View File

@ -0,0 +1,222 @@
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
to:@1
(void()) main()
main: scope:[main] from @1
*((byte*)(number) $400) ← (const nomodify byte) matrixSizeMask
to:main::@return
main::@return: scope:[main] from main
return
to:@return
@1: scope:[] from @begin
call main
to:@2
@2: scope:[] from @1
to:@end
@end: scope:[] from @2
SYMBOL TABLE SSA
(label) @1
(label) @2
(label) @begin
(label) @end
(void()) main()
(label) main::@return
(const nomodify byte) matrixSize = (byte) 8
(const nomodify byte) matrixSizeMask = (byte)(number) $ff-(const nomodify byte) matrixSize-(number) 1
Adding number conversion cast (unumber) 1 in
Successful SSA optimization PassNAddNumberTypeConversions
Adding number conversion cast (unumber) $ff in
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant integer cast $ff
Simplifying constant integer cast 1
Simplifying constant pointer cast (byte*) 1024
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) $ff
Finalized unsigned number type (byte) 1
Successful SSA optimization PassNFinalizeNumberTypeConversions
Simplifying constant integer cast (byte) $ff-(const nomodify byte) matrixSize-(byte) 1
Successful SSA optimization PassNCastSimplification
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @2
Adding NOP phi() at start of @end
CALL GRAPH
Calls in [] to main:2
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
Culled Empty Block (label) @2
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
(void()) main()
main: scope:[main] from @1
[4] *((byte*) 1024) ← (const nomodify byte) matrixSizeMask
to:main::@return
main::@return: scope:[main] from main
[5] return
to:@return
VARIABLE REGISTER WEIGHTS
(void()) main()
Initial phi equivalence classes
Complete equivalence classes
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.const matrixSize = 8
.const matrixSizeMask = $ff-(matrixSize-1)
// @begin
__bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [2] call main
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
__bend:
// main
main: {
// [4] *((byte*) 1024) ← (const nomodify byte) matrixSizeMask -- _deref_pbuc1=vbuc2
lda #matrixSizeMask
sta $400
jmp __breturn
// main::@return
__breturn:
// [5] return
rts
}
// File Data
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [4] *((byte*) 1024) ← (const nomodify byte) matrixSizeMask [ ] ( main:2 [ ] { } ) always clobbers reg byte a
REGISTER UPLIFT SCOPES
Uplift Scope [main]
Uplift Scope []
Uplifting [main] best 27 combination
Uplifting [] best 27 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.const matrixSize = 8
.const matrixSizeMask = $ff-(matrixSize-1)
// @begin
__bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [2] call main
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
__bend:
// main
main: {
// [4] *((byte*) 1024) ← (const nomodify byte) matrixSizeMask -- _deref_pbuc1=vbuc2
lda #matrixSizeMask
sta $400
jmp __breturn
// main::@return
__breturn:
// [5] return
rts
}
// File Data
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __bend
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __b1_from___bbegin:
Removing instruction __b1:
Removing instruction __bend_from___b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction __bbegin:
Removing instruction __bend:
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Removing instruction jsr main
Succesful ASM optimization Pass5SkipBegin
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(void()) main()
(label) main::@return
(const nomodify byte) matrixSize = (byte) 8
(const nomodify byte) matrixSizeMask = (byte) $ff-(const nomodify byte) matrixSize-(byte) 1
FINAL ASSEMBLER
Score: 12
// File Comments
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.const matrixSize = 8
.const matrixSizeMask = $ff-(matrixSize-1)
// @begin
// [1] phi from @begin to @1 [phi:@begin->@1]
// @1
// [2] call main
// [3] phi from @1 to @end [phi:@1->@end]
// @end
// main
main: {
// *((unsigned char *)0x400) = matrixSizeMask
// [4] *((byte*) 1024) ← (const nomodify byte) matrixSizeMask -- _deref_pbuc1=vbuc2
lda #matrixSizeMask
sta $400
// main::@return
// }
// [5] return
rts
}
// File Data

View File

@ -0,0 +1,8 @@
(label) @1
(label) @begin
(label) @end
(void()) main()
(label) main::@return
(const nomodify byte) matrixSize = (byte) 8
(const nomodify byte) matrixSizeMask = (byte) $ff-(const nomodify byte) matrixSize-(byte) 1

View File

@ -0,0 +1,61 @@
// Demonstrates that a local __ma variable overwrites a parameter§
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
.label h1 = 2
__bbegin:
// h1
lda #<0
sta.z h1
sta.z h1+1
jsr main
rts
main: {
// test(h1, 0xD800, 0xC000)
lda.z h1
sta.z test.videoMem
lda.z h1+1
sta.z test.videoMem+1
jsr test
// }
rts
}
// This must be volatile because is used in an interrupt routine...
// test(byte* zp(4) videoMem)
test: {
.label colorMem = $d800
.label other = $c000
.label dst = 4
.label __1 = 4
.label diff = 4
.label videoMem = 4
// dst
lda #<0
sta.z dst
sta.z dst+1
// colorMem - videoMem
sec
lda #<colorMem
sbc.z diff
sta.z diff
lda #>colorMem
sbc.z diff+1
sta.z diff+1
// other + ((unsigned int)diff)
clc
lda.z __1
adc #<other
sta.z __1
lda.z __1+1
adc #>other
sta.z __1+1
// dst = other + ((unsigned int)diff)
// dst[0] = 1
lda #1
ldy #0
sta (dst),y
// asm
sta (dst),y
// }
rts
}

View File

@ -0,0 +1,31 @@
@begin: scope:[] from
[0] (volatile byte*) h1 ← (byte*) 0
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
(void()) main()
main: scope:[main] from @1
[4] (byte*) test::videoMem#0 ← (volatile byte*) h1
[5] call test
to:main::@return
main::@return: scope:[main] from main
[6] return
to:@return
(void()) test((byte*) test::videoMem , (byte*) test::colorMem , (byte*) test::other)
test: scope:[test] from main
[7] (byte*) test::dst ← (byte*) 0
[8] (word) test::diff#1 ← (const byte*) test::colorMem#0 - (byte*) test::videoMem#0
[9] (byte*~) test::$1 ← (const byte*) test::other#0 + (word)(byte*)(word) test::diff#1
[10] (byte*) test::dst ← (byte*~) test::$1
[11] *((byte*) test::dst) ← (byte) 1
asm { ldy#0 lda#1 sta(dst),y }
to:test::@return
test::@return: scope:[test] from test
[13] return
to:@return

View File

@ -0,0 +1,536 @@
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(volatile byte*) h1 ← (byte*) 0
to:@1
(void()) test((byte*) test::videoMem , (byte*) test::colorMem , (byte*) test::other)
test: scope:[test] from main
(byte*) test::other#1 ← phi( main/(byte*) test::other#0 )
(byte*) test::videoMem#1 ← phi( main/(byte*) test::videoMem#0 )
(byte*) test::colorMem#1 ← phi( main/(byte*) test::colorMem#0 )
(byte*) test::diff#0 ← (byte*) 0
(byte*) test::dst ← (byte*) 0
(word~) test::$0 ← (byte*) test::colorMem#1 - (byte*) test::videoMem#1
(byte*) test::diff#1 ← ((byte*)) (word~) test::$0
(word~) test::$2 ← (word)(byte*) test::diff#1
(byte*~) test::$1 ← (byte*) test::other#1 + (word~) test::$2
(byte*) test::dst ← (byte*~) test::$1
*((byte*) test::dst + (number) 0) ← (number) 1
asm { ldy#0 lda#1 sta(dst),y }
to:test::@return
test::@return: scope:[test] from test
return
to:@return
(void()) main()
main: scope:[main] from @1
(byte*) test::videoMem#0 ← (volatile byte*) h1
(byte*) test::colorMem#0 ← (byte*)(number) $d800
(byte*) test::other#0 ← (byte*)(number) $c000
call test
to:main::@1
main::@1: scope:[main] from main
to:main::@return
main::@return: scope:[main] from main::@1
return
to:@return
@1: scope:[] from @begin
call main
to:@2
@2: scope:[] from @1
to:@end
@end: scope:[] from @2
SYMBOL TABLE SSA
(label) @1
(label) @2
(label) @begin
(label) @end
(volatile byte*) h1 loadstore
(void()) main()
(label) main::@1
(label) main::@return
(void()) test((byte*) test::videoMem , (byte*) test::colorMem , (byte*) test::other)
(word~) test::$0
(byte*~) test::$1
(word~) test::$2
(label) test::@return
(byte*) test::colorMem
(byte*) test::colorMem#0
(byte*) test::colorMem#1
(byte*) test::diff
(byte*) test::diff#0
(byte*) test::diff#1
(byte*) test::dst loadstore
(byte*) test::other
(byte*) test::other#0
(byte*) test::other#1
(byte*) test::videoMem
(byte*) test::videoMem#0
(byte*) test::videoMem#1
Adding number conversion cast (unumber) 1 in *((byte*) test::dst + (number) 0) ← (number) 1
Adding number conversion cast (unumber) 0 in *((byte*) test::dst + (number) 0) ← ((unumber)) (number) 1
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast (byte*) test::diff#1 ← (byte*)(word~) test::$0
Inlining cast *((byte*) test::dst + (unumber)(number) 0) ← (unumber)(number) 1
Successful SSA optimization Pass2InlineCast
Simplifying constant integer cast 1
Simplifying constant integer cast 0
Simplifying constant pointer cast (byte*) 55296
Simplifying constant pointer cast (byte*) 49152
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 0
Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias candidate removed (volatile)test::dst = test::$1
Identical Phi Values (byte*) test::colorMem#1 (byte*) test::colorMem#0
Identical Phi Values (byte*) test::videoMem#1 (byte*) test::videoMem#0
Identical Phi Values (byte*) test::other#1 (byte*) test::other#0
Successful SSA optimization Pass2IdenticalPhiElimination
Constant (const byte*) test::diff#0 = (byte*) 0
Constant (const byte*) test::colorMem#0 = (byte*) 55296
Constant (const byte*) test::other#0 = (byte*) 49152
Successful SSA optimization Pass2ConstantIdentification
Simplifying expression containing zero test::dst in [9] *((byte*) test::dst + (byte) 0) ← (byte) 1
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused constant (const byte*) test::diff#0
Successful SSA optimization PassNEliminateUnusedVars
Alias candidate removed (volatile)test::dst = test::$1
Inlining Noop Cast [3] (byte*) test::diff#1 ← (byte*)(word~) test::$0 keeping test::diff#1
Successful SSA optimization Pass2NopCastInlining
Inlining Noop Cast [4] (word~) test::$2 ← (word)(byte*)(word) test::diff#1 keeping (byte*)test::diff#1
Successful SSA optimization Pass2NopCastInlining
Alias candidate removed (volatile)test::dst = test::$1
Alias candidate removed (volatile)test::dst = test::$1
Adding NOP phi() at start of @1
Adding NOP phi() at start of @2
Adding NOP phi() at start of @end
Adding NOP phi() at start of main::@1
CALL GRAPH
Calls in [] to main:2
Calls in [main] to test:6
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
Culled Empty Block (label) @2
Culled Empty Block (label) main::@1
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] (volatile byte*) h1 ← (byte*) 0
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
(void()) main()
main: scope:[main] from @1
[4] (byte*) test::videoMem#0 ← (volatile byte*) h1
[5] call test
to:main::@return
main::@return: scope:[main] from main
[6] return
to:@return
(void()) test((byte*) test::videoMem , (byte*) test::colorMem , (byte*) test::other)
test: scope:[test] from main
[7] (byte*) test::dst ← (byte*) 0
[8] (word) test::diff#1 ← (const byte*) test::colorMem#0 - (byte*) test::videoMem#0
[9] (byte*~) test::$1 ← (const byte*) test::other#0 + (word)(byte*)(word) test::diff#1
[10] (byte*) test::dst ← (byte*~) test::$1
[11] *((byte*) test::dst) ← (byte) 1
asm { ldy#0 lda#1 sta(dst),y }
to:test::@return
test::@return: scope:[test] from test
[13] return
to:@return
VARIABLE REGISTER WEIGHTS
(volatile byte*) h1 loadstore 6.5
(void()) main()
(void()) test((byte*) test::videoMem , (byte*) test::colorMem , (byte*) test::other)
(byte*~) test::$1 202.0
(byte*) test::colorMem
(byte*) test::diff
(word) test::diff#1 101.0
(byte*) test::dst loadstore 151.5
(byte*) test::other
(byte*) test::videoMem
(byte*) test::videoMem#0 56.0
Initial phi equivalence classes
Added variable h1 to live range equivalence class [ h1 ]
Added variable test::videoMem#0 to live range equivalence class [ test::videoMem#0 ]
Added variable test::dst to live range equivalence class [ test::dst ]
Added variable test::diff#1 to live range equivalence class [ test::diff#1 ]
Added variable test::$1 to live range equivalence class [ test::$1 ]
Complete equivalence classes
[ h1 ]
[ test::videoMem#0 ]
[ test::dst ]
[ test::diff#1 ]
[ test::$1 ]
Allocated zp[2]:2 [ h1 ]
Allocated zp[2]:4 [ test::videoMem#0 ]
Allocated zp[2]:6 [ test::dst ]
Allocated zp[2]:8 [ test::diff#1 ]
Allocated zp[2]:10 [ test::$1 ]
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Demonstrates that a local __ma variable overwrites a parameter§
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label h1 = 2
// @begin
__bbegin:
// [0] (volatile byte*) h1 ← (byte*) 0 -- pbuz1=pbuc1
lda #<0
sta.z h1
lda #>0
sta.z h1+1
// [1] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [2] call main
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
__bend:
// main
main: {
// [4] (byte*) test::videoMem#0 ← (volatile byte*) h1 -- pbuz1=pbuz2
lda.z h1
sta.z test.videoMem
lda.z h1+1
sta.z test.videoMem+1
// [5] call test
jsr test
jmp __breturn
// main::@return
__breturn:
// [6] return
rts
}
// test
// This must be volatile because is used in an interrupt routine...
// test(byte* zp(4) videoMem)
test: {
.label colorMem = $d800
.label other = $c000
.label dst = 6
.label __1 = $a
.label diff = 8
.label videoMem = 4
// [7] (byte*) test::dst ← (byte*) 0 -- pbuz1=pbuc1
lda #<0
sta.z dst
lda #>0
sta.z dst+1
// [8] (word) test::diff#1 ← (const byte*) test::colorMem#0 - (byte*) test::videoMem#0 -- vwuz1=pbuc1_minus_pbuz2
sec
lda #<colorMem
sbc.z videoMem
sta.z diff
lda #>colorMem
sbc.z videoMem+1
sta.z diff+1
// [9] (byte*~) test::$1 ← (const byte*) test::other#0 + (word)(byte*)(word) test::diff#1 -- pbuz1=pbuc1_plus_vwuz2
lda.z diff
clc
adc #<other
sta.z __1
lda.z diff+1
adc #>other
sta.z __1+1
// [10] (byte*) test::dst ← (byte*~) test::$1 -- pbuz1=pbuz2
lda.z __1
sta.z dst
lda.z __1+1
sta.z dst+1
// [11] *((byte*) test::dst) ← (byte) 1 -- _deref_pbuz1=vbuc1
lda #1
ldy #0
sta (dst),y
// asm { ldy#0 lda#1 sta(dst),y }
ldy #0
lda #1
sta (dst),y
jmp __breturn
// test::@return
__breturn:
// [13] return
rts
}
// File Data
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] (volatile byte*) h1 ← (byte*) 0 [ h1 ] ( [ h1 ] { } ) always clobbers reg byte a
Statement [4] (byte*) test::videoMem#0 ← (volatile byte*) h1 [ test::videoMem#0 ] ( main:2 [ test::videoMem#0 ] { { test::videoMem#0 = h1 } } ) always clobbers reg byte a
Statement [7] (byte*) test::dst ← (byte*) 0 [ test::videoMem#0 ] ( main:2::test:5 [ test::videoMem#0 ] { { test::videoMem#0 = h1 } } ) always clobbers reg byte a
Statement [8] (word) test::diff#1 ← (const byte*) test::colorMem#0 - (byte*) test::videoMem#0 [ test::diff#1 ] ( main:2::test:5 [ test::diff#1 ] { { test::videoMem#0 = h1 } } ) always clobbers reg byte a
Statement [9] (byte*~) test::$1 ← (const byte*) test::other#0 + (word)(byte*)(word) test::diff#1 [ test::$1 ] ( main:2::test:5 [ test::$1 ] { { test::videoMem#0 = h1 } } ) always clobbers reg byte a
Statement [10] (byte*) test::dst ← (byte*~) test::$1 [ test::dst ] ( main:2::test:5 [ test::dst ] { { test::videoMem#0 = h1 } } ) always clobbers reg byte a
Statement [11] *((byte*) test::dst) ← (byte) 1 [ test::dst ] ( main:2::test:5 [ test::dst ] { { test::videoMem#0 = h1 } } ) always clobbers reg byte a reg byte y
Statement asm { ldy#0 lda#1 sta(dst),y } always clobbers reg byte a reg byte y
Potential registers zp[2]:2 [ h1 ] : zp[2]:2 ,
Potential registers zp[2]:4 [ test::videoMem#0 ] : zp[2]:4 ,
Potential registers zp[2]:6 [ test::dst ] : zp[2]:6 ,
Potential registers zp[2]:8 [ test::diff#1 ] : zp[2]:8 ,
Potential registers zp[2]:10 [ test::$1 ] : zp[2]:10 ,
REGISTER UPLIFT SCOPES
Uplift Scope [test] 202: zp[2]:10 [ test::$1 ] 151.5: zp[2]:6 [ test::dst ] 101: zp[2]:8 [ test::diff#1 ] 56: zp[2]:4 [ test::videoMem#0 ]
Uplift Scope [] 6.5: zp[2]:2 [ h1 ]
Uplift Scope [main]
Uplifting [test] best 136 combination zp[2]:10 [ test::$1 ] zp[2]:6 [ test::dst ] zp[2]:8 [ test::diff#1 ] zp[2]:4 [ test::videoMem#0 ]
Uplifting [] best 136 combination zp[2]:2 [ h1 ]
Uplifting [main] best 136 combination
Coalescing zero page register [ zp[2]:4 [ test::videoMem#0 ] ] with [ zp[2]:8 [ test::diff#1 ] ] - score: 1
Coalescing zero page register [ zp[2]:6 [ test::dst ] ] with [ zp[2]:10 [ test::$1 ] ] - score: 1
Coalescing zero page register [ zp[2]:4 [ test::videoMem#0 test::diff#1 ] ] with [ zp[2]:6 [ test::dst test::$1 ] ] - score: 1
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Demonstrates that a local __ma variable overwrites a parameter§
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label h1 = 2
// @begin
__bbegin:
// [0] (volatile byte*) h1 ← (byte*) 0 -- pbuz1=pbuc1
lda #<0
sta.z h1
lda #>0
sta.z h1+1
// [1] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [2] call main
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
__bend:
// main
main: {
// [4] (byte*) test::videoMem#0 ← (volatile byte*) h1 -- pbuz1=pbuz2
lda.z h1
sta.z test.videoMem
lda.z h1+1
sta.z test.videoMem+1
// [5] call test
jsr test
jmp __breturn
// main::@return
__breturn:
// [6] return
rts
}
// test
// This must be volatile because is used in an interrupt routine...
// test(byte* zp(4) videoMem)
test: {
.label colorMem = $d800
.label other = $c000
.label dst = 4
.label __1 = 4
.label diff = 4
.label videoMem = 4
// [7] (byte*) test::dst ← (byte*) 0 -- pbuz1=pbuc1
lda #<0
sta.z dst
lda #>0
sta.z dst+1
// [8] (word) test::diff#1 ← (const byte*) test::colorMem#0 - (byte*) test::videoMem#0 -- vwuz1=pbuc1_minus_pbuz1
sec
lda #<colorMem
sbc.z diff
sta.z diff
lda #>colorMem
sbc.z diff+1
sta.z diff+1
// [9] (byte*~) test::$1 ← (const byte*) test::other#0 + (word)(byte*)(word) test::diff#1 -- pbuz1=pbuc1_plus_vwuz1
clc
lda.z __1
adc #<other
sta.z __1
lda.z __1+1
adc #>other
sta.z __1+1
// [10] (byte*) test::dst ← (byte*~) test::$1
// [11] *((byte*) test::dst) ← (byte) 1 -- _deref_pbuz1=vbuc1
lda #1
ldy #0
sta (dst),y
// asm { ldy#0 lda#1 sta(dst),y }
ldy #0
lda #1
sta (dst),y
jmp __breturn
// test::@return
__breturn:
// [13] return
rts
}
// File Data
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __bend
Removing instruction jmp __breturn
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction lda #>0
Removing instruction lda #>0
Removing instruction ldy #0
Removing instruction lda #1
Succesful ASM optimization Pass5UnnecesaryLoadElimination
Removing instruction __b1_from___bbegin:
Removing instruction __bend_from___b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction __b1:
Removing instruction __bend:
Removing instruction __breturn:
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Adding RTS to root block
Succesful ASM optimization Pass5AddMainRts
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(volatile byte*) h1 loadstore zp[2]:2 6.5
(void()) main()
(label) main::@return
(void()) test((byte*) test::videoMem , (byte*) test::colorMem , (byte*) test::other)
(byte*~) test::$1 zp[2]:4 202.0
(label) test::@return
(byte*) test::colorMem
(const byte*) test::colorMem#0 colorMem = (byte*) 55296
(byte*) test::diff
(word) test::diff#1 diff zp[2]:4 101.0
(byte*) test::dst loadstore zp[2]:4 151.5
(byte*) test::other
(const byte*) test::other#0 other = (byte*) 49152
(byte*) test::videoMem
(byte*) test::videoMem#0 videoMem zp[2]:4 56.0
zp[2]:2 [ h1 ]
zp[2]:4 [ test::videoMem#0 test::diff#1 test::dst test::$1 ]
FINAL ASSEMBLER
Score: 110
// File Comments
// Demonstrates that a local __ma variable overwrites a parameter§
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label h1 = 2
// @begin
__bbegin:
// h1
// [0] (volatile byte*) h1 ← (byte*) 0 -- pbuz1=pbuc1
lda #<0
sta.z h1
sta.z h1+1
// [1] phi from @begin to @1 [phi:@begin->@1]
// @1
// [2] call main
jsr main
rts
// [3] phi from @1 to @end [phi:@1->@end]
// @end
// main
main: {
// test(h1, 0xD800, 0xC000)
// [4] (byte*) test::videoMem#0 ← (volatile byte*) h1 -- pbuz1=pbuz2
lda.z h1
sta.z test.videoMem
lda.z h1+1
sta.z test.videoMem+1
// [5] call test
jsr test
// main::@return
// }
// [6] return
rts
}
// test
// This must be volatile because is used in an interrupt routine...
// test(byte* zp(4) videoMem)
test: {
.label colorMem = $d800
.label other = $c000
.label dst = 4
.label __1 = 4
.label diff = 4
.label videoMem = 4
// dst
// [7] (byte*) test::dst ← (byte*) 0 -- pbuz1=pbuc1
lda #<0
sta.z dst
sta.z dst+1
// colorMem - videoMem
// [8] (word) test::diff#1 ← (const byte*) test::colorMem#0 - (byte*) test::videoMem#0 -- vwuz1=pbuc1_minus_pbuz1
sec
lda #<colorMem
sbc.z diff
sta.z diff
lda #>colorMem
sbc.z diff+1
sta.z diff+1
// other + ((unsigned int)diff)
// [9] (byte*~) test::$1 ← (const byte*) test::other#0 + (word)(byte*)(word) test::diff#1 -- pbuz1=pbuc1_plus_vwuz1
clc
lda.z __1
adc #<other
sta.z __1
lda.z __1+1
adc #>other
sta.z __1+1
// dst = other + ((unsigned int)diff)
// [10] (byte*) test::dst ← (byte*~) test::$1
// dst[0] = 1
// [11] *((byte*) test::dst) ← (byte) 1 -- _deref_pbuz1=vbuc1
lda #1
ldy #0
sta (dst),y
// asm
// asm { ldy#0 lda#1 sta(dst),y }
sta (dst),y
// test::@return
// }
// [13] return
rts
}
// File Data

View File

@ -0,0 +1,21 @@
(label) @1
(label) @begin
(label) @end
(volatile byte*) h1 loadstore zp[2]:2 6.5
(void()) main()
(label) main::@return
(void()) test((byte*) test::videoMem , (byte*) test::colorMem , (byte*) test::other)
(byte*~) test::$1 zp[2]:4 202.0
(label) test::@return
(byte*) test::colorMem
(const byte*) test::colorMem#0 colorMem = (byte*) 55296
(byte*) test::diff
(word) test::diff#1 diff zp[2]:4 101.0
(byte*) test::dst loadstore zp[2]:4 151.5
(byte*) test::other
(const byte*) test::other#0 other = (byte*) 49152
(byte*) test::videoMem
(byte*) test::videoMem#0 videoMem zp[2]:4 56.0
zp[2]:2 [ h1 ]
zp[2]:4 [ test::videoMem#0 test::diff#1 test::dst test::$1 ]