1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-11-26 12:49:21 +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
*/
private static String getAsmConstantBinary(Program program, ConstantValue left, OperatorBinary operator, ConstantValue right, ScopeRef codeScope) {
if(Operators.MODULO.equals(operator)) {
// Remainder operator % not supported by KickAss - use modulo function instead
return "mod(" +
@ -96,11 +97,20 @@ public class AsmFormat {
"," +
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)) {
return getAsmConstant(program, operand, outerPrecedence, codeScope);
} else if(Operators.NEG.equals(operator) && operand instanceof ConstantUnary) {
return operator.getOperator() + "(" +getAsmConstant(program, operand, operator.getPrecedence(), codeScope)+ ")";
} 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 if(Operators.NEG.equals(operator) && operand instanceof ConstantInteger && ((ConstantInteger) operand).getInteger() < 0) {
return operator.getOperator() + "(" + getAsmConstant(program, operand, operator.getPrecedence(), codeScope) + ")";
} else {
return operator.getOperator() +
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 OperatorAssignment(int precedence) {
super("=", "_assign_", precedence);
super("=", "_assign_", precedence, false);
}
@Override

View File

@ -6,8 +6,12 @@ import dk.camelot64.kickc.model.values.ConstantLiteral;
/** A binary expression 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);
this.associative = associative;
}
/**
@ -26,4 +30,7 @@ public abstract class OperatorBinary extends Operator {
*/
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 OperatorBitwiseAnd(int precedence) {
super("&", "_band_", precedence);
super("&", "_band_", precedence, true);
}
@Override

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -44,6 +44,18 @@ public class 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
public void testNesDemo() throws IOException, URISyntaxException {
compileAndCompare("examples/nes/nes-demo.c");

View File

@ -95,9 +95,9 @@ struct SpriteData SPRITES[] = {
// Color Palette
char PALETTE[0x20] = {
// Background palettes
0x0f, 0x2d, 0x08, 0x18,
0x0f, 0x06, 0x15, 0x36,
0x0f, 0x39, 0x4a, 0x5b,
0x11, 0x2d, 0x08, 0x18,
0x11, 0x06, 0x15, 0x36,
0x11, 0x39, 0x4a, 0x5b,
0x0f, 0x3d, 0x4e, 0x5f,
// Sprite palettes (selected by the attribute bits 0-1 of the sprites)
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
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
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
TILES:
.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_SPRITEDATA_X = (byte) 3
(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 nomodify byte*) PPU_ATTRIBUTE_TABLE_0 = (byte*)(number) $23c0
(const nomodify byte*) PPU_NAME_TABLE_0 = (byte*)(number) $2000
@ -3335,7 +3335,7 @@ readJoy1: {
// 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
// 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
TILES:
.import binary "smb1_chr.bin"
@ -4380,7 +4380,7 @@ readJoy1: {
// 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
// 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
TILES:
.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_PPUSTATUS = (byte) 2
(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 nomodify byte*) PPU_ATTRIBUTE_TABLE_0 = (byte*) 9152
(const nomodify byte*) PPU_NAME_TABLE_0 = (byte*) 8192
@ -5606,7 +5606,7 @@ readJoy1: {
// 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
// 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
TILES:
.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_PPUSTATUS = (byte) 2
(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 nomodify byte*) PPU_ATTRIBUTE_TABLE_0 = (byte*) 9152
(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 ]