1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-11-24 14:31:15 +00:00

Fixed problems casting strings to void*. Closes #281

This commit is contained in:
jespergravgaard 2019-08-25 15:54:09 +02:00
parent bfe90bdf04
commit c75e788fd1
8 changed files with 1667 additions and 7 deletions

View File

@ -1,12 +1,14 @@
package dk.camelot64.kickc.model.operators; package dk.camelot64.kickc.model.operators;
import dk.camelot64.kickc.model.CompileError; import dk.camelot64.kickc.model.ConstantNotLiteral;
import dk.camelot64.kickc.model.InternalError;
import dk.camelot64.kickc.model.symbols.ProgramScope; import dk.camelot64.kickc.model.symbols.ProgramScope;
import dk.camelot64.kickc.model.types.SymbolType; import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypePointer; import dk.camelot64.kickc.model.types.SymbolTypePointer;
import dk.camelot64.kickc.model.values.ConstantInteger; import dk.camelot64.kickc.model.values.ConstantInteger;
import dk.camelot64.kickc.model.values.ConstantLiteral; import dk.camelot64.kickc.model.values.ConstantLiteral;
import dk.camelot64.kickc.model.values.ConstantPointer; import dk.camelot64.kickc.model.values.ConstantPointer;
import dk.camelot64.kickc.model.values.ConstantString;
/** Unary Cast to a pointer ( type* ) */ /** Unary Cast to a pointer ( type* ) */
public class OperatorCastPtr extends OperatorCast { public class OperatorCastPtr extends OperatorCast {
@ -24,8 +26,10 @@ public class OperatorCastPtr extends OperatorCast {
return new ConstantPointer(((ConstantInteger) value).getInteger(), pointerType.getElementType()); return new ConstantPointer(((ConstantInteger) value).getInteger(), pointerType.getElementType());
} else if(value instanceof ConstantPointer) { } else if(value instanceof ConstantPointer) {
return new ConstantPointer(((ConstantPointer) value).getLocation(), pointerType.getElementType()); return new ConstantPointer(((ConstantPointer) value).getLocation(), pointerType.getElementType());
} else if(value instanceof ConstantString){
throw new ConstantNotLiteral("Constant string not literal");
} }
throw new CompileError("Calculation not implemented " + getOperator() + " " + value); throw new InternalError("Calculation not implemented " + getOperator() + " " + value);
} }
@Override @Override

View File

@ -58,6 +58,16 @@ public class PassNAddTypeConversionAssignment extends Pass2SsaOptimization {
getLog().append("Adding pointer type conversion cast to void pointer (" + leftType + ") " + binary.getRight().toString() + " in " + currentStmt.toString(getProgram(), false)); getLog().append("Adding pointer type conversion cast to void pointer (" + leftType + ") " + binary.getRight().toString() + " in " + currentStmt.toString(getProgram(), false));
binary.addRightCast(leftType, stmtIt, currentBlock.getScope(), getScope()); binary.addRightCast(leftType, stmtIt, currentBlock.getScope(), getScope());
modified.set(true); modified.set(true);
} else if((leftType instanceof SymbolTypePointer) && SymbolType.STRING.equals(rightType) && SymbolType.VOID.equals(((SymbolTypePointer) leftType).getElementType())) {
if(pass2 || getLog().isVerbosePass1CreateSsa())
getLog().append("Adding void pointer type conversion cast (" + leftType + ") " + binary.getRight().toString() + " in " + currentStmt.toString(getProgram(), false));
binary.addRightCast(leftType, stmtIt, currentBlock.getScope(), getScope());
modified.set(true);
} else if(leftType.equals(SymbolType.STRING) && rightType instanceof SymbolTypePointer && SymbolType.VOID.equals(((SymbolTypePointer) rightType).getElementType())) {
if(pass2 || getLog().isVerbosePass1CreateSsa())
getLog().append("Adding pointer type conversion cast to void pointer (" + leftType + ") " + binary.getRight().toString() + " in " + currentStmt.toString(getProgram(), false));
binary.addRightCast(leftType, stmtIt, currentBlock.getScope(), getScope());
modified.set(true);
} else if(SymbolType.WORD.equals(leftType) && isLiteralWordCandidate(right)) { } else if(SymbolType.WORD.equals(leftType) && isLiteralWordCandidate(right)) {
// Detect word literal constructor // Detect word literal constructor
SymbolType conversionType = SymbolType.WORD; SymbolType conversionType = SymbolType.WORD;

View File

@ -377,13 +377,10 @@ public class TestPrograms {
compileAndCompare("font-hex-show"); compileAndCompare("font-hex-show");
} }
// TODO: Fix string not converted to void* properly https://gitlab.com/camelot/kickc/issues/281
/*
@Test @Test
public void testMemcpy1() throws IOException, URISyntaxException { public void testMemcpy1() throws IOException, URISyntaxException {
compileAndCompare("memcpy-1", log()); compileAndCompare("memcpy-1");
} }
*/
@Test @Test
public void testMemcpy0() throws IOException, URISyntaxException { public void testMemcpy0() throws IOException, URISyntaxException {

View File

@ -18,7 +18,6 @@ void main() {
*sc2++ = *reigns++; *sc2++ = *reigns++;
} }
// Not working
memcpy(SCREEN+10, CAMELOT, 7); memcpy(SCREEN+10, CAMELOT, 7);
memcpy(SCREEN+50, "rules", 5); memcpy(SCREEN+50, "rules", 5);

131
src/test/ref/memcpy-1.asm Normal file
View File

@ -0,0 +1,131 @@
// Test memcpy on strings (
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.label SCREEN = $400
main: {
.label sc = 6
.label camelot = 4
.label sc2 = 2
.label reigns = 8
ldx #0
lda #<SCREEN
sta.z sc
lda #>SCREEN
sta.z sc+1
lda #<CAMELOT
sta.z camelot
lda #>CAMELOT
sta.z camelot+1
b1:
ldy #0
lda (camelot),y
sta (sc),y
inc.z sc
bne !+
inc.z sc+1
!:
inc.z camelot
bne !+
inc.z camelot+1
!:
inx
cpx #7
bne b1
ldx #0
lda #<SCREEN+$28
sta.z sc2
lda #>SCREEN+$28
sta.z sc2+1
lda #<reigns_0
sta.z reigns
lda #>reigns_0
sta.z reigns+1
b2:
ldy #0
lda (reigns),y
sta (sc2),y
inc.z sc2
bne !+
inc.z sc2+1
!:
inc.z reigns
bne !+
inc.z reigns+1
!:
inx
cpx #6
bne b2
lda #<7
sta.z memcpy.num
lda #>7
sta.z memcpy.num+1
lda #<SCREEN+$a
sta.z memcpy.destination
lda #>SCREEN+$a
sta.z memcpy.destination+1
lda #<CAMELOT
sta.z memcpy.source
lda #>CAMELOT
sta.z memcpy.source+1
jsr memcpy
lda #<5
sta.z memcpy.num
lda #>5
sta.z memcpy.num+1
lda #<SCREEN+$32
sta.z memcpy.destination
lda #>SCREEN+$32
sta.z memcpy.destination+1
lda #<_8
sta.z memcpy.source
lda #>_8
sta.z memcpy.source+1
jsr memcpy
rts
_8: .text "rules"
.byte 0
reigns_0: .text "reigns"
.byte 0
}
// Copy block of memory (forwards)
// Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination.
// memcpy(void* zeropage(6) destination, void* zeropage(4) source, word zeropage(8) num)
memcpy: {
.label src_end = 8
.label dst = 6
.label src = 4
.label source = 4
.label destination = 6
.label num = 8
lda.z src_end
clc
adc.z source
sta.z src_end
lda.z src_end+1
adc.z source+1
sta.z src_end+1
b1:
lda.z src+1
cmp.z src_end+1
bne b2
lda.z src
cmp.z src_end
bne b2
rts
b2:
ldy #0
lda (src),y
sta (dst),y
inc.z dst
bne !+
inc.z dst+1
!:
inc.z src
bne !+
inc.z src+1
!:
jmp b1
}
CAMELOT: .text "camelot"
.byte 0

64
src/test/ref/memcpy-1.cfg Normal file
View File

@ -0,0 +1,64 @@
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
main: scope:[main] from @1
[4] phi()
to:main::@1
main::@1: scope:[main] from main main::@1
[5] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 )
[5] (byte*) main::sc#2 ← phi( main/(const byte*) SCREEN#0 main::@1/(byte*) main::sc#1 )
[5] (byte*) main::camelot#2 ← phi( main/(const byte[]) CAMELOT#0 main::@1/(byte*) main::camelot#1 )
[6] *((byte*) main::sc#2) ← *((byte*) main::camelot#2)
[7] (byte*) main::sc#1 ← ++ (byte*) main::sc#2
[8] (byte*) main::camelot#1 ← ++ (byte*) main::camelot#2
[9] (byte) main::i#1 ← ++ (byte) main::i#2
[10] if((byte) main::i#1!=(byte) 7) goto main::@1
to:main::@2
main::@2: scope:[main] from main::@1 main::@2
[11] (byte) main::i1#2 ← phi( main::@1/(byte) 0 main::@2/(byte) main::i1#1 )
[11] (byte*) main::sc2#2 ← phi( main::@1/(const byte*) SCREEN#0+(byte) $28 main::@2/(byte*) main::sc2#1 )
[11] (byte*) main::reigns#2 ← phi( main::@1/(const byte*) main::reigns#0 main::@2/(byte*) main::reigns#1 )
[12] *((byte*) main::sc2#2) ← *((byte*) main::reigns#2)
[13] (byte*) main::sc2#1 ← ++ (byte*) main::sc2#2
[14] (byte*) main::reigns#1 ← ++ (byte*) main::reigns#2
[15] (byte) main::i1#1 ← ++ (byte) main::i1#2
[16] if((byte) main::i1#1!=(byte) 6) goto main::@2
to:main::@3
main::@3: scope:[main] from main::@2
[17] phi()
[18] call memcpy
to:main::@4
main::@4: scope:[main] from main::@3
[19] phi()
[20] call memcpy
to:main::@return
main::@return: scope:[main] from main::@4
[21] return
to:@return
memcpy: scope:[memcpy] from main::@3 main::@4
[22] (word) memcpy::num#2 ← phi( main::@3/(byte) 7 main::@4/(byte) 5 )
[22] (void*) memcpy::destination#2 ← phi( main::@3/(void*)(const byte*) SCREEN#0+(byte) $a main::@4/(void*)(const byte*) SCREEN#0+(byte) $32 )
[22] (void*) memcpy::source#2 ← phi( main::@3/(void*)(const byte[]) CAMELOT#0 main::@4/(void*)(const string) main::$8 )
[23] (byte*) memcpy::src_end#0 ← (byte*)(void*) memcpy::source#2 + (word) memcpy::num#2
[24] (byte*~) memcpy::src#4 ← (byte*)(void*) memcpy::source#2
[25] (byte*~) memcpy::dst#4 ← (byte*)(void*) memcpy::destination#2
to:memcpy::@1
memcpy::@1: scope:[memcpy] from memcpy memcpy::@2
[26] (byte*) memcpy::dst#2 ← phi( memcpy/(byte*~) memcpy::dst#4 memcpy::@2/(byte*) memcpy::dst#1 )
[26] (byte*) memcpy::src#2 ← phi( memcpy/(byte*~) memcpy::src#4 memcpy::@2/(byte*) memcpy::src#1 )
[27] if((byte*) memcpy::src#2!=(byte*) memcpy::src_end#0) goto memcpy::@2
to:memcpy::@return
memcpy::@return: scope:[memcpy] from memcpy::@1
[28] return
to:@return
memcpy::@2: scope:[memcpy] from memcpy::@1
[29] *((byte*) memcpy::dst#2) ← *((byte*) memcpy::src#2)
[30] (byte*) memcpy::dst#1 ← ++ (byte*) memcpy::dst#2
[31] (byte*) memcpy::src#1 ← ++ (byte*) memcpy::src#2
to:memcpy::@1

1394
src/test/ref/memcpy-1.log Normal file

File diff suppressed because it is too large Load Diff

61
src/test/ref/memcpy-1.sym Normal file
View File

@ -0,0 +1,61 @@
(label) @1
(label) @begin
(label) @end
(byte[]) CAMELOT
(const byte[]) CAMELOT#0 CAMELOT = (string) "camelot"
(byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = (byte*) 1024
(void()) main()
(const string) main::$8 $8 = (string) "rules"
(label) main::@1
(label) main::@2
(label) main::@3
(label) main::@4
(label) main::@return
(byte*) main::camelot
(byte*) main::camelot#1 camelot zp ZP_WORD:4 7.333333333333333
(byte*) main::camelot#2 camelot zp ZP_WORD:4 11.0
(byte) main::i
(byte) main::i#1 reg byte x 16.5
(byte) main::i#2 reg byte x 5.5
(byte) main::i1
(byte) main::i1#1 reg byte x 16.5
(byte) main::i1#2 reg byte x 5.5
(byte*) main::reigns
(const byte*) main::reigns#0 reigns#0 = (string) "reigns"
(byte*) main::reigns#1 reigns zp ZP_WORD:8 7.333333333333333
(byte*) main::reigns#2 reigns zp ZP_WORD:8 11.0
(byte*) main::sc
(byte*) main::sc#1 sc zp ZP_WORD:6 5.5
(byte*) main::sc#2 sc zp ZP_WORD:6 16.5
(byte*) main::sc2
(byte*) main::sc2#1 sc2 zp ZP_WORD:2 5.5
(byte*) main::sc2#2 sc2 zp ZP_WORD:2 16.5
(void*()) memcpy((void*) memcpy::destination , (void*) memcpy::source , (word) memcpy::num)
(label) memcpy::@1
(label) memcpy::@2
(label) memcpy::@return
(void*) memcpy::destination
(void*) memcpy::destination#2 destination zp ZP_WORD:6
(byte*) memcpy::dst
(byte*) memcpy::dst#1 dst zp ZP_WORD:6 11.0
(byte*) memcpy::dst#2 dst zp ZP_WORD:6 11.666666666666666
(byte*~) memcpy::dst#4 dst zp ZP_WORD:6 4.0
(word) memcpy::num
(word) memcpy::num#2 num zp ZP_WORD:8 2.0
(void*) memcpy::return
(void*) memcpy::source
(void*) memcpy::source#2 source zp ZP_WORD:4
(byte*) memcpy::src
(byte*) memcpy::src#1 src zp ZP_WORD:4 22.0
(byte*) memcpy::src#2 src zp ZP_WORD:4 11.5
(byte*~) memcpy::src#4 src zp ZP_WORD:4 2.0
(byte*) memcpy::src_end
(byte*) memcpy::src_end#0 src_end zp ZP_WORD:8 1.625
reg byte x [ main::i#2 main::i#1 ]
zp ZP_WORD:2 [ main::sc2#2 main::sc2#1 ]
reg byte x [ main::i1#2 main::i1#1 ]
zp ZP_WORD:4 [ memcpy::source#2 memcpy::src#2 memcpy::src#4 memcpy::src#1 main::camelot#2 main::camelot#1 ]
zp ZP_WORD:6 [ memcpy::destination#2 memcpy::dst#2 memcpy::dst#4 memcpy::dst#1 main::sc#2 main::sc#1 ]
zp ZP_WORD:8 [ memcpy::num#2 memcpy::src_end#0 main::reigns#2 main::reigns#1 ]