mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-12-28 16:31:36 +00:00
Fixed problem problem where constant references are not literal. Closes #540
This commit is contained in:
parent
2068fd3b7b
commit
6a9ca1537c
@ -0,0 +1,8 @@
|
||||
lda #>{c1}
|
||||
cmp #>{c2}
|
||||
bne !+
|
||||
lda #<{c1}
|
||||
cmp #<{c2}
|
||||
beq {la1}
|
||||
!:
|
||||
bcc {la1}
|
3
src/main/fragment/mos6502-common/vwum1=vbuaa_rol_8.asm
Normal file
3
src/main/fragment/mos6502-common/vwum1=vbuaa_rol_8.asm
Normal file
@ -0,0 +1,3 @@
|
||||
sta {m1}+1
|
||||
lda #0
|
||||
sta {m1}
|
@ -1,11 +1,11 @@
|
||||
package dk.camelot64.kickc.fragment;
|
||||
|
||||
import dk.camelot64.kickc.model.ConstantNotLiteral;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeIntegerFixed;
|
||||
import dk.camelot64.kickc.model.values.*;
|
||||
import kickass.nonasm.c64.CharToPetsciiConverter;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@ -94,7 +94,12 @@ public class AsmFragmentInstanceSpec {
|
||||
// Found a constant value that may be multi-typed
|
||||
Value value = bindings.get(name);
|
||||
if(value instanceof ConstantValue) {
|
||||
ConstantLiteral constantLiteral = ((ConstantValue) value).calculateLiteral(program.getScope());
|
||||
ConstantLiteral constantLiteral = null;
|
||||
try {
|
||||
constantLiteral = ((ConstantValue) value).calculateLiteral(program.getScope());
|
||||
} catch (ConstantNotLiteral e) {
|
||||
// ignore
|
||||
}
|
||||
Long constIntValue = null;
|
||||
if(constantLiteral instanceof ConstantInteger) {
|
||||
constIntValue = ((ConstantInteger) constantLiteral).getValue();
|
||||
|
@ -44,6 +44,11 @@ public class TestPrograms {
|
||||
public TestPrograms() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstRefNotLiteralProblem() throws IOException, URISyntaxException {
|
||||
compileAndCompare("constref-not-literal-problem.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStrengthReduction1() throws IOException, URISyntaxException {
|
||||
compileAndCompare("strength-reduction-1.c");
|
||||
|
17
src/test/kc/constref-not-literal-problem.c
Normal file
17
src/test/kc/constref-not-literal-problem.c
Normal file
@ -0,0 +1,17 @@
|
||||
// Demonstrates a problem where constant references are not literal
|
||||
|
||||
char A[] = "qwe";
|
||||
char * B = 0x8000;
|
||||
|
||||
void main() {
|
||||
copy(B, A);
|
||||
}
|
||||
|
||||
// Copy a byte if the destination is after the source
|
||||
void copy(void* destination, void* source) {
|
||||
if((unsigned int)destination>(unsigned int)source) {
|
||||
char* src = source;
|
||||
char* dst = destination;
|
||||
*dst = *src;
|
||||
}
|
||||
}
|
35
src/test/ref/constref-not-literal-problem.asm
Normal file
35
src/test/ref/constref-not-literal-problem.asm
Normal file
@ -0,0 +1,35 @@
|
||||
// Demonstrates a problem where constant references are not literal
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
.label B = $8000
|
||||
main: {
|
||||
// copy(B, A)
|
||||
jsr copy
|
||||
// }
|
||||
rts
|
||||
}
|
||||
// Copy a byte if the destination is after the source
|
||||
copy: {
|
||||
.label destination = B
|
||||
.label source = A
|
||||
.label src = source
|
||||
.label dst = destination
|
||||
// if((unsigned int)destination>(unsigned int)source)
|
||||
lda #>destination
|
||||
cmp #>source
|
||||
bne !+
|
||||
lda #<destination
|
||||
cmp #<source
|
||||
beq __breturn
|
||||
!:
|
||||
bcc __breturn
|
||||
// *dst = *src
|
||||
lda src
|
||||
sta dst
|
||||
__breturn:
|
||||
// }
|
||||
rts
|
||||
}
|
||||
A: .text "qwe"
|
||||
.byte 0
|
20
src/test/ref/constref-not-literal-problem.cfg
Normal file
20
src/test/ref/constref-not-literal-problem.cfg
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
[1] call copy
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
[2] return
|
||||
to:@return
|
||||
|
||||
void copy(void* copy::destination , void* copy::source)
|
||||
copy: scope:[copy] from main
|
||||
[3] if((word)copy::destination#0<=(word)copy::source#0) goto copy::@return
|
||||
to:copy::@1
|
||||
copy::@1: scope:[copy] from copy
|
||||
[4] *copy::dst#0 = *copy::src#0
|
||||
to:copy::@return
|
||||
copy::@return: scope:[copy] from copy copy::@1
|
||||
[5] return
|
||||
to:@return
|
294
src/test/ref/constref-not-literal-problem.log
Normal file
294
src/test/ref/constref-not-literal-problem.log
Normal file
@ -0,0 +1,294 @@
|
||||
Inlined call call __init
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
|
||||
void main()
|
||||
main: scope:[main] from __start::@1
|
||||
copy::destination#0 = (void*)B
|
||||
copy::source#0 = (void*)A
|
||||
call copy
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
return
|
||||
to:@return
|
||||
|
||||
void copy(void* copy::destination , void* copy::source)
|
||||
copy: scope:[copy] from main
|
||||
copy::source#1 = phi( main/copy::source#0 )
|
||||
copy::destination#1 = phi( main/copy::destination#0 )
|
||||
copy::$2 = (word)copy::destination#1
|
||||
copy::$3 = (word)copy::source#1
|
||||
copy::$0 = copy::$2 > copy::$3
|
||||
copy::$1 = ! copy::$0
|
||||
if(copy::$1) goto copy::@return
|
||||
to:copy::@1
|
||||
copy::@1: scope:[copy] from copy
|
||||
copy::destination#2 = phi( copy/copy::destination#1 )
|
||||
copy::source#2 = phi( copy/copy::source#1 )
|
||||
copy::src#0 = ((byte*)) copy::source#2
|
||||
copy::dst#0 = ((byte*)) copy::destination#2
|
||||
*copy::dst#0 = *copy::src#0
|
||||
to:copy::@return
|
||||
copy::@return: scope:[copy] from copy copy::@1
|
||||
return
|
||||
to:@return
|
||||
|
||||
void __start()
|
||||
__start: scope:[__start] from
|
||||
to:__start::__init1
|
||||
__start::__init1: scope:[__start] from __start
|
||||
to:__start::@1
|
||||
__start::@1: scope:[__start] from __start::__init1
|
||||
call main
|
||||
to:__start::@2
|
||||
__start::@2: scope:[__start] from __start::@1
|
||||
to:__start::@return
|
||||
__start::@return: scope:[__start] from __start::@2
|
||||
return
|
||||
to:@return
|
||||
|
||||
SYMBOL TABLE SSA
|
||||
const byte* A[] = "qwe"
|
||||
const byte* B = (byte*)$8000
|
||||
void __start()
|
||||
void copy(void* copy::destination , void* copy::source)
|
||||
bool~ copy::$0
|
||||
bool~ copy::$1
|
||||
word~ copy::$2
|
||||
word~ copy::$3
|
||||
void* copy::destination
|
||||
void* copy::destination#0
|
||||
void* copy::destination#1
|
||||
void* copy::destination#2
|
||||
byte* copy::dst
|
||||
byte* copy::dst#0
|
||||
void* copy::source
|
||||
void* copy::source#0
|
||||
void* copy::source#1
|
||||
void* copy::source#2
|
||||
byte* copy::src
|
||||
byte* copy::src#0
|
||||
void main()
|
||||
|
||||
Inlining cast copy::src#0 = (byte*)copy::source#2
|
||||
Inlining cast copy::dst#0 = (byte*)copy::destination#2
|
||||
Successful SSA optimization Pass2InlineCast
|
||||
Simplifying constant pointer cast (byte*) 32768
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Inversing boolean not [8] copy::$1 = copy::$2 <= copy::$3 from [7] copy::$0 = copy::$2 > copy::$3
|
||||
Successful SSA optimization Pass2UnaryNotSimplification
|
||||
Alias copy::source#1 = copy::source#2
|
||||
Alias copy::destination#1 = copy::destination#2
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Identical Phi Values copy::destination#1 copy::destination#0
|
||||
Identical Phi Values copy::source#1 copy::source#0
|
||||
Successful SSA optimization Pass2IdenticalPhiElimination
|
||||
Simple Condition copy::$1 [8] if(copy::$2<=copy::$3) goto copy::@return
|
||||
Successful SSA optimization Pass2ConditionalJumpSimplification
|
||||
Constant right-side identified [0] copy::destination#0 = (void*)B
|
||||
Successful SSA optimization Pass2ConstantRValueConsolidation
|
||||
Constant copy::destination#0 = (void*)B
|
||||
Constant copy::source#0 = (void*)A
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Constant copy::$2 = (word)copy::destination#0
|
||||
Constant copy::$3 = (word)copy::source#0
|
||||
Constant copy::src#0 = (byte*)copy::source#0
|
||||
Constant copy::dst#0 = (byte*)copy::destination#0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Removing unused procedure __start
|
||||
Removing unused procedure block __start
|
||||
Removing unused procedure block __start::__init1
|
||||
Removing unused procedure block __start::@1
|
||||
Removing unused procedure block __start::@2
|
||||
Removing unused procedure block __start::@return
|
||||
Successful SSA optimization PassNEliminateEmptyStart
|
||||
Constant inlined copy::$2 = (word)copy::destination#0
|
||||
Constant inlined copy::$3 = (word)copy::source#0
|
||||
Successful SSA optimization Pass2ConstantInlining
|
||||
Adding NOP phi() at start of main
|
||||
Adding NOP phi() at start of main::@1
|
||||
CALL GRAPH
|
||||
Calls in [main] to copy:1
|
||||
|
||||
Created 0 initial phi equivalence classes
|
||||
Coalesced down to 0 phi equivalence classes
|
||||
Culled Empty Block label main::@1
|
||||
Adding NOP phi() at start of main
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
[1] call copy
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
[2] return
|
||||
to:@return
|
||||
|
||||
void copy(void* copy::destination , void* copy::source)
|
||||
copy: scope:[copy] from main
|
||||
[3] if((word)copy::destination#0<=(word)copy::source#0) goto copy::@return
|
||||
to:copy::@1
|
||||
copy::@1: scope:[copy] from copy
|
||||
[4] *copy::dst#0 = *copy::src#0
|
||||
to:copy::@return
|
||||
copy::@return: scope:[copy] from copy copy::@1
|
||||
[5] return
|
||||
to:@return
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
void copy(void* copy::destination , void* copy::source)
|
||||
void* copy::destination
|
||||
byte* copy::dst
|
||||
void* copy::source
|
||||
byte* copy::src
|
||||
void main()
|
||||
|
||||
Initial phi equivalence classes
|
||||
Complete equivalence classes
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [3] if((word)copy::destination#0<=(word)copy::source#0) goto copy::@return [ ] ( copy:1 [ ] { } ) always clobbers reg byte a
|
||||
Statement [4] *copy::dst#0 = *copy::src#0 [ ] ( copy:1 [ ] { } ) always clobbers reg byte a
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [main]
|
||||
Uplift Scope [copy]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [main] best 50 combination
|
||||
Uplifting [copy] best 50 combination
|
||||
Uplifting [] best 50 combination
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
// File Comments
|
||||
// Demonstrates a problem where constant references are not literal
|
||||
// Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
.label B = $8000
|
||||
// main
|
||||
main: {
|
||||
// [1] call copy
|
||||
jsr copy
|
||||
jmp __breturn
|
||||
// main::@return
|
||||
__breturn:
|
||||
// [2] return
|
||||
rts
|
||||
}
|
||||
// copy
|
||||
// Copy a byte if the destination is after the source
|
||||
copy: {
|
||||
.label destination = B
|
||||
.label source = A
|
||||
.label src = source
|
||||
.label dst = destination
|
||||
// [3] if((word)copy::destination#0<=(word)copy::source#0) goto copy::@return -- vwuc1_le_vwuc2_then_la1
|
||||
lda #>destination
|
||||
cmp #>source
|
||||
bne !+
|
||||
lda #<destination
|
||||
cmp #<source
|
||||
beq __breturn
|
||||
!:
|
||||
bcc __breturn
|
||||
jmp __b1
|
||||
// copy::@1
|
||||
__b1:
|
||||
// [4] *copy::dst#0 = *copy::src#0 -- _deref_pbuc1=_deref_pbuc2
|
||||
lda src
|
||||
sta dst
|
||||
jmp __breturn
|
||||
// copy::@return
|
||||
__breturn:
|
||||
// [5] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
A: .text "qwe"
|
||||
.byte 0
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp __breturn
|
||||
Removing instruction jmp __b1
|
||||
Removing instruction jmp __breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Removing instruction __breturn:
|
||||
Removing instruction __b1:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
const byte* A[] = "qwe"
|
||||
const byte* B = (byte*) 32768
|
||||
void copy(void* copy::destination , void* copy::source)
|
||||
void* copy::destination
|
||||
const void* copy::destination#0 destination = (void*)B
|
||||
byte* copy::dst
|
||||
const byte* copy::dst#0 dst = (byte*)copy::destination#0
|
||||
void* copy::source
|
||||
const void* copy::source#0 source = (void*)A
|
||||
byte* copy::src
|
||||
const byte* copy::src#0 src = (byte*)copy::source#0
|
||||
void main()
|
||||
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 41
|
||||
|
||||
// File Comments
|
||||
// Demonstrates a problem where constant references are not literal
|
||||
// Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
.label B = $8000
|
||||
// main
|
||||
main: {
|
||||
// copy(B, A)
|
||||
// [1] call copy
|
||||
jsr copy
|
||||
// main::@return
|
||||
// }
|
||||
// [2] return
|
||||
rts
|
||||
}
|
||||
// copy
|
||||
// Copy a byte if the destination is after the source
|
||||
copy: {
|
||||
.label destination = B
|
||||
.label source = A
|
||||
.label src = source
|
||||
.label dst = destination
|
||||
// if((unsigned int)destination>(unsigned int)source)
|
||||
// [3] if((word)copy::destination#0<=(word)copy::source#0) goto copy::@return -- vwuc1_le_vwuc2_then_la1
|
||||
lda #>destination
|
||||
cmp #>source
|
||||
bne !+
|
||||
lda #<destination
|
||||
cmp #<source
|
||||
beq __breturn
|
||||
!:
|
||||
bcc __breturn
|
||||
// copy::@1
|
||||
// *dst = *src
|
||||
// [4] *copy::dst#0 = *copy::src#0 -- _deref_pbuc1=_deref_pbuc2
|
||||
lda src
|
||||
sta dst
|
||||
// copy::@return
|
||||
__breturn:
|
||||
// }
|
||||
// [5] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
A: .text "qwe"
|
||||
.byte 0
|
||||
|
13
src/test/ref/constref-not-literal-problem.sym
Normal file
13
src/test/ref/constref-not-literal-problem.sym
Normal file
@ -0,0 +1,13 @@
|
||||
const byte* A[] = "qwe"
|
||||
const byte* B = (byte*) 32768
|
||||
void copy(void* copy::destination , void* copy::source)
|
||||
void* copy::destination
|
||||
const void* copy::destination#0 destination = (void*)B
|
||||
byte* copy::dst
|
||||
const byte* copy::dst#0 dst = (byte*)copy::destination#0
|
||||
void* copy::source
|
||||
const void* copy::source#0 source = (void*)A
|
||||
byte* copy::src
|
||||
const byte* copy::src#0 src = (byte*)copy::source#0
|
||||
void main()
|
||||
|
Loading…
Reference in New Issue
Block a user