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:
parent
67dedcc299
commit
a63adec0f0
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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");
|
||||||
|
@ -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
|
||||||
|
7
src/test/kc/minus-precedence-problem.c
Normal file
7
src/test/kc/minus-precedence-problem.c
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
const unsigned char matrixSize = 8;
|
||||||
|
const unsigned char matrixSizeMask = 255 - (matrixSize - 1);
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
*((unsigned char *)0x400) = matrixSizeMask;
|
||||||
|
}
|
25
src/test/kc/problem-ma-var-overwrite.c
Normal file
25
src/test/kc/problem-ma-var-overwrite.c
Normal 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);
|
||||||
|
}
|
@ -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"
|
||||||
|
@ -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"
|
||||||
|
@ -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
|
||||||
|
12
src/test/ref/minus-precedence-problem.asm
Normal file
12
src/test/ref/minus-precedence-problem.asm
Normal 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
|
||||||
|
}
|
17
src/test/ref/minus-precedence-problem.cfg
Normal file
17
src/test/ref/minus-precedence-problem.cfg
Normal 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
|
222
src/test/ref/minus-precedence-problem.log
Normal file
222
src/test/ref/minus-precedence-problem.log
Normal 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
|
||||||
|
|
8
src/test/ref/minus-precedence-problem.sym
Normal file
8
src/test/ref/minus-precedence-problem.sym
Normal 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
|
||||||
|
|
61
src/test/ref/problem-ma-var-overwrite.asm
Normal file
61
src/test/ref/problem-ma-var-overwrite.asm
Normal 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
|
||||||
|
}
|
31
src/test/ref/problem-ma-var-overwrite.cfg
Normal file
31
src/test/ref/problem-ma-var-overwrite.cfg
Normal 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
|
536
src/test/ref/problem-ma-var-overwrite.log
Normal file
536
src/test/ref/problem-ma-var-overwrite.log
Normal 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
|
||||||
|
|
21
src/test/ref/problem-ma-var-overwrite.sym
Normal file
21
src/test/ref/problem-ma-var-overwrite.sym
Normal 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 ]
|
Loading…
x
Reference in New Issue
Block a user