From 2b36c5c18b174e1ff7c830d8e8ffad78ebd09581 Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Mon, 23 Sep 2019 08:30:18 +0200 Subject: [PATCH] Fixed parameter push type sizes. #316 --- .../fragment/AsmFragmentInstanceSpec.java | 10 +- .../model/operators/OperatorCastByte.java | 3 + .../kickc/model/values/ConstantChar.java | 19 ++ .../kickc/passes/Pass4CodeGeneration.java | 10 +- .../dk/camelot64/kickc/test/TestPrograms.java | 2 +- .../kc/procedure-callingconvention-stack-3.kc | 2 +- .../procedure-callingconvention-stack-3.asm | 10 +- .../procedure-callingconvention-stack-3.log | 163 ++++-------------- 8 files changed, 79 insertions(+), 140 deletions(-) diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpec.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpec.java index 9a003f18b..9f0d017a2 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpec.java +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpec.java @@ -5,6 +5,7 @@ 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,8 +95,14 @@ public class AsmFragmentInstanceSpec { Value value = bindings.get(name); if(value instanceof ConstantValue) { ConstantLiteral constantLiteral = ((ConstantValue) value).calculateLiteral(program.getScope()); + Long constIntValue = null; if(constantLiteral instanceof ConstantInteger) { - List types = getVariationTypes(((ConstantInteger) constantLiteral).getValue()); + constIntValue = ((ConstantInteger) constantLiteral).getValue(); + } else if(constantLiteral instanceof ConstantChar) { + constIntValue = ((ConstantChar) constantLiteral).getIntValue(); + } + if(constIntValue != null) { + List types = getVariationTypes(constIntValue); if(types.size() > 1) { // Found constant value with multiple types variationConstant = (ConstantValue) value; @@ -120,6 +127,7 @@ public class AsmFragmentInstanceSpec { /** * Find any fixed integer types that can contain the passed integer value + * * @param value the value to examine * @return All fixed size integer types capable of representing the passed value */ diff --git a/src/main/java/dk/camelot64/kickc/model/operators/OperatorCastByte.java b/src/main/java/dk/camelot64/kickc/model/operators/OperatorCastByte.java index 7b843b4c0..701ecddbd 100644 --- a/src/main/java/dk/camelot64/kickc/model/operators/OperatorCastByte.java +++ b/src/main/java/dk/camelot64/kickc/model/operators/OperatorCastByte.java @@ -3,6 +3,7 @@ package dk.camelot64.kickc.model.operators; import dk.camelot64.kickc.model.CompileError; import dk.camelot64.kickc.model.symbols.ProgramScope; import dk.camelot64.kickc.model.types.SymbolType; +import dk.camelot64.kickc.model.values.ConstantChar; import dk.camelot64.kickc.model.values.ConstantInteger; import dk.camelot64.kickc.model.values.ConstantLiteral; import dk.camelot64.kickc.model.values.ConstantPointer; @@ -20,6 +21,8 @@ public class OperatorCastByte extends OperatorCast { return new ConstantInteger(0xff & ((ConstantInteger) value).getValue(), SymbolType.BYTE); } else if(value instanceof ConstantPointer) { return new ConstantInteger(0xff & ((ConstantPointer) value).getLocation(), SymbolType.BYTE); + } else if(value instanceof ConstantChar) { + return new ConstantInteger(((ConstantChar) value).getIntValue(), SymbolType.BYTE); } throw new CompileError("Calculation not implemented " + getOperator() + " " + value ); } diff --git a/src/main/java/dk/camelot64/kickc/model/values/ConstantChar.java b/src/main/java/dk/camelot64/kickc/model/values/ConstantChar.java index 7f2e5e444..b729c4c93 100644 --- a/src/main/java/dk/camelot64/kickc/model/values/ConstantChar.java +++ b/src/main/java/dk/camelot64/kickc/model/values/ConstantChar.java @@ -5,6 +5,7 @@ import dk.camelot64.kickc.model.InternalError; import dk.camelot64.kickc.model.Program; import dk.camelot64.kickc.model.symbols.ProgramScope; import dk.camelot64.kickc.model.types.SymbolType; +import kickass.nonasm.c64.CharToPetsciiConverter; /** * SSA form constant char value (a byte) @@ -36,6 +37,24 @@ public class ConstantChar implements ConstantLiteral { return value; } + /** + * Get the integer value of the character + * @return The integer value (taking encoding into account) + */ + public Long getIntValue() { + Byte constCharIntValue = null; + if(ConstantString.Encoding.SCREENCODE_MIXED.equals(encoding)) { + constCharIntValue = CharToPetsciiConverter.charToScreenCode_mixed.get(value); + } else if(ConstantString.Encoding.SCREENCODE_UPPER.equals(encoding)) { + constCharIntValue = CharToPetsciiConverter.charToScreenCode_upper.get(value); + } else if(ConstantString.Encoding.PETSCII_MIXED.equals(encoding)) { + constCharIntValue = CharToPetsciiConverter.charToPetscii_mixed.get(value); + } else if(ConstantString.Encoding.PETSCII_UPPER.equals(encoding)) { + constCharIntValue = CharToPetsciiConverter.charToPetscii_upper.get(value); + } + return constCharIntValue.longValue(); + } + public ConstantString.Encoding getEncoding() { return encoding; } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java index 42dd94857..0039343c9 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java @@ -754,9 +754,13 @@ public class Pass4CodeGeneration { Procedure procedure = getScope().getProcedure(call.getProcedure()); if(Procedure.CallingConvension.STACK_CALL.equals(procedure.getCallingConvension())) { // Push parameters to the stack - for(RValue parameter : call.getParameters()) { - SymbolType parameterType = SymbolTypeInference.inferType(program.getScope(), parameter); - AsmFragmentInstanceSpecFactory asmFragmentInstanceSpecFactory = new AsmFragmentInstanceSpecFactory(new StackPushValue(parameterType), parameter, program, block.getScope()); + List callParameters = call.getParameters(); + List procParameters = procedure.getParameters(); + for(int i = 0; i < procParameters.size(); i++) { + Variable procParameter = procParameters.get(i); + RValue callParameter = callParameters.get(i); + SymbolType parameterType = procParameter.getType(); + AsmFragmentInstanceSpecFactory asmFragmentInstanceSpecFactory = new AsmFragmentInstanceSpecFactory(new StackPushValue(parameterType), callParameter, program, block.getScope()); asm.startChunk(block.getScope(), statement.getIndex(), statement.toString(program, verboseAliveInfo)); ensureEncoding(asm, asmFragmentInstanceSpecFactory); generateAsm(asm, asmFragmentInstanceSpecFactory.getAsmFragmentInstanceSpec()); diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index 57f221398..9ae8ceaf7 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -42,7 +42,7 @@ public class TestPrograms { @Test public void testProcedureCallingConventionStack3() throws IOException, URISyntaxException { - compileAndCompare("procedure-callingconvention-stack-3", log().verboseLiveRanges()); //, log().verboseCreateSsa().verboseParse().verboseStatementSequence()); + compileAndCompare("procedure-callingconvention-stack-3"); //, log().verboseCreateSsa().verboseParse().verboseStatementSequence()); } @Test diff --git a/src/test/kc/procedure-callingconvention-stack-3.kc b/src/test/kc/procedure-callingconvention-stack-3.kc index 2040c7628..b4de8df32 100644 --- a/src/test/kc/procedure-callingconvention-stack-3.kc +++ b/src/test/kc/procedure-callingconvention-stack-3.kc @@ -1,6 +1,6 @@ // Test a procedure with calling convention stack // Test casting of parameter types -// Currently fails because the pushed are done based on the actual value instead of the decalred parameter type +// Currently fails because the pushed are done based on the actual value instead of the declared parameter type // https://gitlab.com/camelot/kickc/issues/319 const word* SCREEN = 0x0400; diff --git a/src/test/ref/procedure-callingconvention-stack-3.asm b/src/test/ref/procedure-callingconvention-stack-3.asm index acca2e938..8c897ff0d 100644 --- a/src/test/ref/procedure-callingconvention-stack-3.asm +++ b/src/test/ref/procedure-callingconvention-stack-3.asm @@ -1,6 +1,6 @@ // Test a procedure with calling convention stack // Test casting of parameter types -// Currently fails because the pushed are done based on the actual value instead of the decalred parameter type +// Currently fails because the pushed are done based on the actual value instead of the declared parameter type // https://gitlab.com/camelot/kickc/issues/319 .pc = $801 "Basic" :BasicUpstart(main) @@ -9,9 +9,13 @@ .const STACK_BASE = $103 main: { .label _0 = 2 - lda #'0' + lda #>'0' pha - lda #7 + lda #<'0' + pha + lda #>7 + pha + lda #<7 pha jsr plus pla diff --git a/src/test/ref/procedure-callingconvention-stack-3.log b/src/test/ref/procedure-callingconvention-stack-3.log index acd2a4510..871d96339 100644 --- a/src/test/ref/procedure-callingconvention-stack-3.log +++ b/src/test/ref/procedure-callingconvention-stack-3.log @@ -142,117 +142,6 @@ plus::@return: scope:[plus] from plus VARIABLE REGISTER WEIGHTS -Adding empty live range for unused variable main::$0 -Adding used var main::$0 to [7] main::$0 ← callfinalize plus -Adding empty live range for unused variable plus::a#0 -Adding empty live range for unused variable plus::b#0 -Adding empty live range for unused variable plus::return#0 -Adding used var plus::a#0 to [11] plus::b#0 ← stackidx(word,plus::OFFSET_STACK_B) -Adding used var plus::b#0 to [11] plus::b#0 ← stackidx(word,plus::OFFSET_STACK_B) -Adding used var plus::return#0 to [12] plus::return#0 ← plus::a#0 + plus::b#0 -Propagating live ranges... -CONTROL FLOW GRAPH - LIVE RANGES IN PROGRESS -@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] phi() [ ] ( main:2 [ ] ) - [5] callprepare plus (byte) '0' (byte) 7 [ ] ( main:2 [ ] ) - [6] callexecute plus [ ] ( main:2 [ ] ) - [7] (word~) main::$0 ← callfinalize plus [ main::$0 ] ( main:2 [ main::$0 ] ) - [8] *((const word*) SCREEN#0) ← (word~) main::$0 [ ] ( main:2 [ ] ) - to:main::@return -main::@return: scope:[main] from main - [9] return [ ] ( main:2 [ ] ) - to:@return - -__stackcall (word()) plus((word) plus::a , (word) plus::b) -plus: scope:[plus] from - [10] (word) plus::a#0 ← stackidx(word,(const byte) plus::OFFSET_STACK_A) [ ] ( main:2::plus:6 [ ] ) - [11] (word) plus::b#0 ← stackidx(word,(const byte) plus::OFFSET_STACK_B) [ plus::a#0 plus::b#0 ] ( main:2::plus:6 [ plus::a#0 plus::b#0 ] ) - [12] (word) plus::return#0 ← (word) plus::a#0 + (word) plus::b#0 [ plus::return#0 ] ( main:2::plus:6 [ plus::return#0 ] ) - to:plus::@return -plus::@return: scope:[plus] from plus - [13] return (word) plus::return#0 [ ] ( main:2::plus:6 [ ] ) - to:@return - -Propagated alive var plus::a#0 to [10] plus::a#0 ← stackidx(word,plus::OFFSET_STACK_A) -Propagating live ranges... -CONTROL FLOW GRAPH - LIVE RANGES IN PROGRESS -@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] phi() [ ] ( main:2 [ ] ) - [5] callprepare plus (byte) '0' (byte) 7 [ ] ( main:2 [ ] ) - [6] callexecute plus [ ] ( main:2 [ ] ) - [7] (word~) main::$0 ← callfinalize plus [ main::$0 ] ( main:2 [ main::$0 ] ) - [8] *((const word*) SCREEN#0) ← (word~) main::$0 [ ] ( main:2 [ ] ) - to:main::@return -main::@return: scope:[main] from main - [9] return [ ] ( main:2 [ ] ) - to:@return - -__stackcall (word()) plus((word) plus::a , (word) plus::b) -plus: scope:[plus] from - [10] (word) plus::a#0 ← stackidx(word,(const byte) plus::OFFSET_STACK_A) [ plus::a#0 ] ( main:2::plus:6 [ ] ) - [11] (word) plus::b#0 ← stackidx(word,(const byte) plus::OFFSET_STACK_B) [ plus::a#0 plus::b#0 ] ( main:2::plus:6 [ plus::a#0 plus::b#0 ] ) - [12] (word) plus::return#0 ← (word) plus::a#0 + (word) plus::b#0 [ plus::return#0 ] ( main:2::plus:6 [ plus::return#0 ] ) - to:plus::@return -plus::@return: scope:[plus] from plus - [13] return (word) plus::return#0 [ ] ( main:2::plus:6 [ ] ) - to:@return - -Propagating live ranges... -CONTROL FLOW GRAPH - LIVE RANGES IN PROGRESS -@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] phi() [ ] ( main:2 [ ] ) - [5] callprepare plus (byte) '0' (byte) 7 [ ] ( main:2 [ ] ) - [6] callexecute plus [ ] ( main:2 [ ] ) - [7] (word~) main::$0 ← callfinalize plus [ main::$0 ] ( main:2 [ main::$0 ] ) - [8] *((const word*) SCREEN#0) ← (word~) main::$0 [ ] ( main:2 [ ] ) - to:main::@return -main::@return: scope:[main] from main - [9] return [ ] ( main:2 [ ] ) - to:@return - -__stackcall (word()) plus((word) plus::a , (word) plus::b) -plus: scope:[plus] from - [10] (word) plus::a#0 ← stackidx(word,(const byte) plus::OFFSET_STACK_A) [ plus::a#0 ] ( main:2::plus:6 [ ] ) - [11] (word) plus::b#0 ← stackidx(word,(const byte) plus::OFFSET_STACK_B) [ plus::a#0 plus::b#0 ] ( main:2::plus:6 [ plus::a#0 plus::b#0 ] ) - [12] (word) plus::return#0 ← (word) plus::a#0 + (word) plus::b#0 [ plus::return#0 ] ( main:2::plus:6 [ plus::return#0 ] ) - to:plus::@return -plus::@return: scope:[plus] from plus - [13] return (word) plus::return#0 [ ] ( main:2::plus:6 [ ] ) - to:@return - (word*) SCREEN (void()) main() (word~) main::$0 2.0 @@ -284,7 +173,7 @@ Target platform is c64basic / MOS6502X // File Comments // Test a procedure with calling convention stack // Test casting of parameter types -// Currently fails because the pushed are done based on the actual value instead of the decalred parameter type +// Currently fails because the pushed are done based on the actual value instead of the declared parameter type // https://gitlab.com/camelot/kickc/issues/319 // Upstart .pc = $801 "Basic" @@ -313,11 +202,15 @@ bend: main: { .label _0 = 2 // [5] callprepare plus (byte) '0' (byte) 7 - // [5] callprepare plus (byte) '0' (byte) 7 -- _stackpushbyte_=vbuc1 - lda #'0' + // [5] callprepare plus (byte) '0' (byte) 7 -- _stackpushword_=vwuc1 + lda #>'0' pha - // [5] callprepare plus (byte) '0' (byte) 7 -- _stackpushbyte_=vbuc1 - lda #7 + lda #<'0' + pha + // [5] callprepare plus (byte) '0' (byte) 7 -- _stackpushword_=vwuc1 + lda #>7 + pha + lda #<7 pha // [5] callprepare plus (byte) '0' (byte) 7 // [6] callexecute plus -- jsr @@ -388,7 +281,7 @@ REGISTER UPLIFT POTENTIAL REGISTERS Statement [5] callprepare plus (byte) '0' (byte) 7 [ ] ( main:2 [ ] ) always clobbers reg byte a Statement [7] (word~) main::$0 ← callfinalize plus [ main::$0 ] ( main:2 [ main::$0 ] ) always clobbers reg byte a Statement [8] *((const word*) SCREEN#0) ← (word~) main::$0 [ ] ( main:2 [ ] ) always clobbers reg byte a -Statement [10] (word) plus::a#0 ← stackidx(word,(const byte) plus::OFFSET_STACK_A) [ plus::a#0 ] ( main:2::plus:6 [ ] ) always clobbers reg byte a reg byte x +Statement [10] (word) plus::a#0 ← stackidx(word,(const byte) plus::OFFSET_STACK_A) [ plus::a#0 ] ( main:2::plus:6 [ plus::a#0 ] ) always clobbers reg byte a reg byte x Statement [11] (word) plus::b#0 ← stackidx(word,(const byte) plus::OFFSET_STACK_B) [ plus::a#0 plus::b#0 ] ( main:2::plus:6 [ plus::a#0 plus::b#0 ] ) always clobbers reg byte a reg byte x Statement [12] (word) plus::return#0 ← (word) plus::a#0 + (word) plus::b#0 [ plus::return#0 ] ( main:2::plus:6 [ plus::return#0 ] ) always clobbers reg byte a Statement [13] return (word) plus::return#0 [ ] ( main:2::plus:6 [ ] ) always clobbers reg byte a reg byte x @@ -402,9 +295,9 @@ Uplift Scope [plus] 4: zp ZP_WORD:6 [ plus::b#0 ] 2: zp ZP_WORD:4 [ plus::a#0 ] Uplift Scope [main] 2: zp ZP_WORD:2 [ main::$0 ] Uplift Scope [] -Uplifting [plus] best 154 combination zp ZP_WORD:6 [ plus::b#0 ] zp ZP_WORD:4 [ plus::a#0 ] zp ZP_WORD:8 [ plus::return#0 ] -Uplifting [main] best 154 combination zp ZP_WORD:2 [ main::$0 ] -Uplifting [] best 154 combination +Uplifting [plus] best 164 combination zp ZP_WORD:6 [ plus::b#0 ] zp ZP_WORD:4 [ plus::a#0 ] zp ZP_WORD:8 [ plus::return#0 ] +Uplifting [main] best 164 combination zp ZP_WORD:2 [ main::$0 ] +Uplifting [] best 164 combination Coalescing zero page register [ zp ZP_WORD:4 [ plus::a#0 ] ] with [ zp ZP_WORD:8 [ plus::return#0 ] ] - score: 1 Coalescing zero page register [ zp ZP_WORD:4 [ plus::a#0 plus::return#0 ] ] with [ zp ZP_WORD:2 [ main::$0 ] ] Allocated (was zp ZP_WORD:4) zp ZP_WORD:2 [ plus::a#0 plus::return#0 main::$0 ] @@ -414,7 +307,7 @@ ASSEMBLER BEFORE OPTIMIZATION // File Comments // Test a procedure with calling convention stack // Test casting of parameter types -// Currently fails because the pushed are done based on the actual value instead of the decalred parameter type +// Currently fails because the pushed are done based on the actual value instead of the declared parameter type // https://gitlab.com/camelot/kickc/issues/319 // Upstart .pc = $801 "Basic" @@ -443,11 +336,15 @@ bend: main: { .label _0 = 2 // [5] callprepare plus (byte) '0' (byte) 7 - // [5] callprepare plus (byte) '0' (byte) 7 -- _stackpushbyte_=vbuc1 - lda #'0' + // [5] callprepare plus (byte) '0' (byte) 7 -- _stackpushword_=vwuc1 + lda #>'0' pha - // [5] callprepare plus (byte) '0' (byte) 7 -- _stackpushbyte_=vbuc1 - lda #7 + lda #<'0' + pha + // [5] callprepare plus (byte) '0' (byte) 7 -- _stackpushword_=vwuc1 + lda #>7 + pha + lda #<7 pha // [5] callprepare plus (byte) '0' (byte) 7 // [6] callexecute plus -- jsr @@ -561,12 +458,12 @@ zp ZP_WORD:4 [ plus::b#0 ] FINAL ASSEMBLER -Score: 136 +Score: 146 // File Comments // Test a procedure with calling convention stack // Test casting of parameter types -// Currently fails because the pushed are done based on the actual value instead of the decalred parameter type +// Currently fails because the pushed are done based on the actual value instead of the declared parameter type // https://gitlab.com/camelot/kickc/issues/319 // Upstart .pc = $801 "Basic" @@ -587,11 +484,15 @@ main: { .label _0 = 2 // plus('0', 7) // [5] callprepare plus (byte) '0' (byte) 7 - // [5] callprepare plus (byte) '0' (byte) 7 -- _stackpushbyte_=vbuc1 - lda #'0' + // [5] callprepare plus (byte) '0' (byte) 7 -- _stackpushword_=vwuc1 + lda #>'0' pha - // [5] callprepare plus (byte) '0' (byte) 7 -- _stackpushbyte_=vbuc1 - lda #7 + lda #<'0' + pha + // [5] callprepare plus (byte) '0' (byte) 7 -- _stackpushword_=vwuc1 + lda #>7 + pha + lda #<7 pha // [5] callprepare plus (byte) '0' (byte) 7 // [6] callexecute plus -- jsr