mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-11-16 21:07:56 +00:00
Intermediate variables are now affected by the var_model. Closes #666
This commit is contained in:
parent
78e378a8e1
commit
194e851f0d
@ -215,6 +215,7 @@ public class Compiler {
|
||||
new Pass1UnwindBlockScopes(program).execute();
|
||||
new Pass1Procedures(program).execute();
|
||||
new PassNTypeInference(program).execute();
|
||||
new PassNFixIntermediateMemoryArea(program).execute();
|
||||
new PassNTypeIdSimplification(program).execute();
|
||||
new Pass1StructTypeSizeFix(program).execute();
|
||||
new Pass1PrintfIntrinsicRewrite(program).execute();
|
||||
@ -549,7 +550,6 @@ public class Compiler {
|
||||
if(getLog().isVerboseSizeInfo()) {
|
||||
getLog().append(program.getSizeInfo());
|
||||
}
|
||||
|
||||
new Pass3AssertNoTypeId(program).check();
|
||||
new Pass3AssertRValues(program).check();
|
||||
new Pass3AssertNoNumbers(program).check();
|
||||
|
@ -54,6 +54,8 @@ public class VariableBuilder {
|
||||
|
||||
/**
|
||||
* Create a variable builder for an intermediate variable
|
||||
*
|
||||
*
|
||||
* @param scope The scope to create the intermediate variable in
|
||||
* @param type The variable type
|
||||
* @param program The global program
|
||||
@ -139,6 +141,15 @@ public class VariableBuilder {
|
||||
return type instanceof SymbolTypePointer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the type is a var (currently unknown).
|
||||
*
|
||||
* @return True if the type is currently unknown
|
||||
*/
|
||||
public boolean isTypeVar() {
|
||||
return SymbolType.VAR.equals(type) || SymbolType.VOID.equals(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the variable a global variable
|
||||
*
|
||||
@ -303,7 +314,7 @@ public class VariableBuilder {
|
||||
return false;
|
||||
else {
|
||||
VariableBuilderConfig.Scope scope = VariableBuilderConfig.getScope(isScopeGlobal(), isScopeLocal(), isScopeIntermediate(), isScopeParameter(), isScopeMember());
|
||||
VariableBuilderConfig.Type type = VariableBuilderConfig.getType(isTypeInteger(), isArray(), isTypePointer(), isTypeStruct());
|
||||
VariableBuilderConfig.Type type = VariableBuilderConfig.getType(isTypeInteger(), isArray(), isTypePointer(), isTypeStruct(), isTypeVar());
|
||||
VariableBuilderConfig.Setting setting = config.getSetting(scope, type);
|
||||
if(setting != null && VariableBuilderConfig.Optimization.MA.equals(setting.optimization))
|
||||
return false;
|
||||
@ -351,10 +362,7 @@ public class VariableBuilder {
|
||||
return Variable.MemoryArea.ZEROPAGE_MEMORY;
|
||||
else {
|
||||
VariableBuilderConfig.Scope scope = VariableBuilderConfig.getScope(isScopeGlobal(), isScopeLocal(), isScopeIntermediate(), isScopeParameter(), isScopeMember());
|
||||
if(scope.equals(VariableBuilderConfig.Scope.INTERMEDIATE)) {
|
||||
return Variable.MemoryArea.ZEROPAGE_MEMORY;
|
||||
} else {
|
||||
VariableBuilderConfig.Type type = VariableBuilderConfig.getType(isTypeInteger(), isArray(), isTypePointer(), isTypeStruct());
|
||||
VariableBuilderConfig.Type type = VariableBuilderConfig.getType(isTypeInteger(), isArray(), isTypePointer(), isTypeStruct(), isTypeVar());
|
||||
VariableBuilderConfig.Setting setting = config.getSetting(scope, type);
|
||||
if(setting != null && VariableBuilderConfig.MemoryArea.MEM.equals(setting.memoryArea))
|
||||
return Variable.MemoryArea.MAIN_MEMORY;
|
||||
@ -362,7 +370,6 @@ public class VariableBuilder {
|
||||
return Variable.MemoryArea.ZEROPAGE_MEMORY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get any memory-alignment of the variables data
|
||||
|
@ -93,6 +93,8 @@ public class VariableBuilderConfig {
|
||||
config.addSetting("parameter_ssa", StatementSource.NONE);
|
||||
// Pointers are always on zeropage
|
||||
config.addSetting("pointer_zp", StatementSource.NONE);
|
||||
// Pointers are always on zeropage
|
||||
config.addSetting("intermediate_var_zp", StatementSource.NONE);
|
||||
}
|
||||
|
||||
/** The different scopes. */
|
||||
@ -102,7 +104,7 @@ public class VariableBuilderConfig {
|
||||
|
||||
/** The different types. */
|
||||
public enum Type {
|
||||
INTEGER, POINTER, STRUCT, ARRAY
|
||||
INTEGER, POINTER, STRUCT, ARRAY, VAR
|
||||
}
|
||||
|
||||
/** The optimizations. */
|
||||
@ -207,6 +209,9 @@ public class VariableBuilderConfig {
|
||||
} else if(paramElement.equals("parameter")) {
|
||||
paramElements.remove(0);
|
||||
return Arrays.asList(Scope.PARAMETER);
|
||||
} else if(paramElement.equals("intermediate")) {
|
||||
paramElements.remove(0);
|
||||
return Arrays.asList(Scope.INTERMEDIATE);
|
||||
} else
|
||||
return Arrays.asList(Scope.values());
|
||||
}
|
||||
@ -232,6 +237,9 @@ public class VariableBuilderConfig {
|
||||
} else if(paramElement.equals("struct")) {
|
||||
paramElements.remove(0);
|
||||
return Arrays.asList(Type.STRUCT);
|
||||
} else if(paramElement.equals("var")) {
|
||||
paramElements.remove(0);
|
||||
return Arrays.asList(Type.VAR);
|
||||
} else
|
||||
return Arrays.asList(Type.values());
|
||||
}
|
||||
@ -303,7 +311,7 @@ public class VariableBuilderConfig {
|
||||
throw new InternalError("Unknown scope!");
|
||||
}
|
||||
|
||||
public static Type getType(boolean isTypeInteger, boolean isTypeArray, boolean isTypePointer, boolean isTypeStruct) {
|
||||
public static Type getType(boolean isTypeInteger, boolean isTypeArray, boolean isTypePointer, boolean isTypeStruct, boolean isTypeVar) {
|
||||
if(isTypeInteger)
|
||||
return Type.INTEGER;
|
||||
if(isTypeArray)
|
||||
@ -312,6 +320,8 @@ public class VariableBuilderConfig {
|
||||
return Type.POINTER;
|
||||
if(isTypeStruct)
|
||||
return Type.STRUCT;
|
||||
if(isTypeVar)
|
||||
return Type.VAR;
|
||||
throw new InternalError("Unknown type!");
|
||||
}
|
||||
|
||||
|
@ -588,8 +588,9 @@ public class Pass4CodeGeneration {
|
||||
// Add any comments
|
||||
generateComments(asm, variable.getComments());
|
||||
final String mainAsmName = AsmFormat.getAsmConstant(program, new ConstantSymbolPointer(mainVar.getRef()), 99, scopeRef);
|
||||
if(!mainAsmName.equals(variable.getAsmName())) {
|
||||
asm.addLabelDecl(variable.getAsmName(), mainAsmName);
|
||||
final String asmSymbolName = AsmFormat.getAsmSymbolName(program, mainVar, scopeRef);
|
||||
if(!mainAsmName.equals(asmSymbolName)) {
|
||||
asm.addLabelDecl(asmSymbolName, mainAsmName);
|
||||
} else {
|
||||
// Add any alignment
|
||||
Integer declaredAlignment = variable.getMemoryAlignment();
|
||||
|
@ -0,0 +1,36 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.VariableBuilder;
|
||||
import dk.camelot64.kickc.model.VariableBuilderConfig;
|
||||
import dk.camelot64.kickc.model.symbols.Variable;
|
||||
|
||||
/**
|
||||
* Fix the memory area for intermediate variables
|
||||
*/
|
||||
public class PassNFixIntermediateMemoryArea extends Pass2SsaOptimization {
|
||||
|
||||
public PassNFixIntermediateMemoryArea(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean step() {
|
||||
boolean modified = false;
|
||||
final VariableBuilderConfig variableBuilderConfig = getProgram().getTargetPlatform().getVariableBuilderConfig();
|
||||
for(Variable var : getScope().getAllVars(true)) {
|
||||
if(var.isKindIntermediate()) {
|
||||
final VariableBuilder builder = new VariableBuilder(var.getLocalName(), var.getScope(), false, true, var.getType(), null, var.getDataSegment(), variableBuilderConfig);
|
||||
final Variable.MemoryArea memoryArea = builder.getMemoryArea();
|
||||
if(!memoryArea.equals(var.getMemoryArea())) {
|
||||
// Update the variable memory area
|
||||
getLog().append("Updating intermediate variable memory area to "+memoryArea.name() + " " + var.toString());
|
||||
var.setMemoryArea(memoryArea);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
}
|
@ -970,6 +970,11 @@ public class TestProgramsFast extends TestPrograms {
|
||||
compileAndCompare("varmodel-ma_mem.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVarModelMem1() throws IOException {
|
||||
compileAndCompare("varmodel-mem-1.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVarModelUnknown() throws IOException {
|
||||
assertError("varmodel-unknown.c", "Malformed var_model parameter");
|
||||
|
17
src/test/kc/varmodel-mem-1.c
Normal file
17
src/test/kc/varmodel-mem-1.c
Normal file
@ -0,0 +1,17 @@
|
||||
// Test that memory model "mem" affects intermediates
|
||||
|
||||
#pragma var_model(mem)
|
||||
|
||||
void main() {
|
||||
// A local pointer
|
||||
char* const SCREEN = (char*)0x0400;
|
||||
// A local counter
|
||||
for( char i: 0..5 ) {
|
||||
// Generates an intermediate
|
||||
*(SCREEN+i) = sum(i,i)+sum(i,i);
|
||||
}
|
||||
}
|
||||
|
||||
char sum(char a, char b) {
|
||||
return a+b;
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
Resolved forward reference SINTABLE to SINTABLE
|
||||
Updating intermediate variable memory area to MAIN_MEMORY main::$0
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
Updating intermediate variable memory area to MAIN_MEMORY main::$0
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
Updating intermediate variable memory area to ZEROPAGE_MEMORY model_ma_mem::$0
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
Updating intermediate variable memory area to MAIN_MEMORY main::$0
|
||||
Inlined call call __init
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
|
@ -1,3 +1,4 @@
|
||||
Updating intermediate variable memory area to MAIN_MEMORY main::$0
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
|
||||
@ -82,15 +83,15 @@ Complete equivalence classes
|
||||
[ main::i ]
|
||||
[ main::$1 ]
|
||||
Allocated mem[1] [ main::i ]
|
||||
Allocated zp[1]:2 [ main::$1 ]
|
||||
Allocated mem[1] [ main::$1 ]
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [0] main::i = 0 [ main::i ] ( [ main::i ] { } ) always clobbers reg byte a
|
||||
Statement [1] SCREEN[main::i] = '*' [ main::i ] ( [ main::i ] { } ) always clobbers reg byte a reg byte y
|
||||
Potential registers mem[1] [ main::i ] : mem[1] ,
|
||||
Potential registers zp[1]:2 [ main::$1 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers mem[1] [ main::$1 ] : mem[1] , reg byte a , reg byte x , reg byte y ,
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [main] 11: zp[1]:2 [ main::$1 ] 9.2: mem[1] [ main::i ]
|
||||
Uplift Scope [main] 11: mem[1] [ main::$1 ] 9.2: mem[1] [ main::i ]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [main] best 300 combination reg byte a [ main::$1 ] mem[1] [ main::i ]
|
||||
|
49
src/test/ref/varmodel-mem-1.asm
Normal file
49
src/test/ref/varmodel-mem-1.asm
Normal file
@ -0,0 +1,49 @@
|
||||
// Test that memory model "mem" affects intermediates
|
||||
// Commodore 64 PRG executable file
|
||||
.file [name="varmodel-mem-1.prg", type="prg", segments="Program"]
|
||||
.segmentdef Program [segments="Basic, Code, Data"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segment Basic
|
||||
:BasicUpstart(main)
|
||||
.segment Code
|
||||
main: {
|
||||
// A local pointer
|
||||
.label SCREEN = $400
|
||||
ldx #0
|
||||
// A local counter
|
||||
__b1:
|
||||
// sum(i,i)
|
||||
txa
|
||||
jsr sum
|
||||
// sum(i,i)
|
||||
sta __1
|
||||
txa
|
||||
jsr sum
|
||||
// sum(i,i)
|
||||
// sum(i,i)+sum(i,i)
|
||||
clc
|
||||
adc __1
|
||||
// *(SCREEN+i) = sum(i,i)+sum(i,i)
|
||||
// Generates an intermediate
|
||||
sta SCREEN,x
|
||||
// for( char i: 0..5 )
|
||||
inx
|
||||
cpx #6
|
||||
bne __b1
|
||||
// }
|
||||
rts
|
||||
.segment Data
|
||||
__1: .byte 0
|
||||
}
|
||||
.segment Code
|
||||
// sum(byte register(A) a, byte register(X) b)
|
||||
sum: {
|
||||
// a+b
|
||||
stx.z $ff
|
||||
clc
|
||||
adc.z $ff
|
||||
// }
|
||||
rts
|
||||
}
|
39
src/test/ref/varmodel-mem-1.cfg
Normal file
39
src/test/ref/varmodel-mem-1.cfg
Normal file
@ -0,0 +1,39 @@
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@3
|
||||
[1] main::i#2 = phi( main/0, main::@3/main::i#1 )
|
||||
[2] sum::a#0 = main::i#2
|
||||
[3] sum::b#0 = main::i#2
|
||||
[4] call sum
|
||||
[5] sum::return#0 = sum::return#2
|
||||
to:main::@2
|
||||
main::@2: scope:[main] from main::@1
|
||||
[6] main::$1 = sum::return#0
|
||||
[7] sum::a#1 = main::i#2
|
||||
[8] sum::b#1 = main::i#2
|
||||
[9] call sum
|
||||
[10] sum::return#1 = sum::return#2
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@2
|
||||
[11] main::$2 = sum::return#1
|
||||
[12] main::$3 = main::$1 + main::$2
|
||||
[13] main::SCREEN[main::i#2] = main::$3
|
||||
[14] main::i#1 = ++ main::i#2
|
||||
[15] if(main::i#1!=6) goto main::@1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@3
|
||||
[16] return
|
||||
to:@return
|
||||
|
||||
byte sum(byte sum::a , byte sum::b)
|
||||
sum: scope:[sum] from main::@1 main::@2
|
||||
[17] sum::b#2 = phi( main::@1/sum::b#0, main::@2/sum::b#1 )
|
||||
[17] sum::a#2 = phi( main::@1/sum::a#0, main::@2/sum::a#1 )
|
||||
[18] sum::return#2 = sum::a#2 + sum::b#2
|
||||
to:sum::@return
|
||||
sum::@return: scope:[sum] from sum
|
||||
[19] return
|
||||
to:@return
|
511
src/test/ref/varmodel-mem-1.log
Normal file
511
src/test/ref/varmodel-mem-1.log
Normal file
@ -0,0 +1,511 @@
|
||||
Updating intermediate variable memory area to MAIN_MEMORY main::$1
|
||||
Updating intermediate variable memory area to MAIN_MEMORY main::$2
|
||||
Updating intermediate variable memory area to MAIN_MEMORY main::$3
|
||||
Updating intermediate variable memory area to MAIN_MEMORY main::$4
|
||||
Updating intermediate variable memory area to MAIN_MEMORY sum::$0
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
|
||||
void main()
|
||||
main: scope:[main] from __start
|
||||
main::i#0 = 0
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@3
|
||||
main::i#2 = phi( main/main::i#0, main::@3/main::i#1 )
|
||||
main::$0 = main::SCREEN + main::i#2
|
||||
sum::a#0 = main::i#2
|
||||
sum::b#0 = main::i#2
|
||||
call sum
|
||||
sum::return#0 = sum::return#3
|
||||
to:main::@2
|
||||
main::@2: scope:[main] from main::@1
|
||||
main::i#3 = phi( main::@1/main::i#2 )
|
||||
sum::return#4 = phi( main::@1/sum::return#0 )
|
||||
main::$1 = sum::return#4
|
||||
sum::a#1 = main::i#3
|
||||
sum::b#1 = main::i#3
|
||||
call sum
|
||||
sum::return#1 = sum::return#3
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@2
|
||||
main::i#4 = phi( main::@2/main::i#3 )
|
||||
sum::return#5 = phi( main::@2/sum::return#1 )
|
||||
main::$2 = sum::return#5
|
||||
main::$3 = main::$1 + main::$2
|
||||
*main::$0 = main::$3
|
||||
main::i#1 = main::i#4 + rangenext(0,5)
|
||||
main::$4 = main::i#1 != rangelast(0,5)
|
||||
if(main::$4) goto main::@1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@3
|
||||
return
|
||||
to:@return
|
||||
|
||||
byte sum(byte sum::a , byte sum::b)
|
||||
sum: scope:[sum] from main::@1 main::@2
|
||||
sum::b#2 = phi( main::@1/sum::b#0, main::@2/sum::b#1 )
|
||||
sum::a#2 = phi( main::@1/sum::a#0, main::@2/sum::a#1 )
|
||||
sum::$0 = sum::a#2 + sum::b#2
|
||||
sum::return#2 = sum::$0
|
||||
to:sum::@return
|
||||
sum::@return: scope:[sum] from sum
|
||||
sum::return#6 = phi( sum/sum::return#2 )
|
||||
sum::return#3 = sum::return#6
|
||||
return
|
||||
to:@return
|
||||
|
||||
void __start()
|
||||
__start: scope:[__start] from
|
||||
call main
|
||||
to:__start::@1
|
||||
__start::@1: scope:[__start] from __start
|
||||
to:__start::@return
|
||||
__start::@return: scope:[__start] from __start::@1
|
||||
return
|
||||
to:@return
|
||||
|
||||
SYMBOL TABLE SSA
|
||||
void __start()
|
||||
void main()
|
||||
byte*~ main::$0
|
||||
byte~ main::$1
|
||||
byte~ main::$2
|
||||
byte~ main::$3
|
||||
bool~ main::$4
|
||||
constant byte* const main::SCREEN = (byte*)$400
|
||||
byte main::i
|
||||
byte main::i#0
|
||||
byte main::i#1
|
||||
byte main::i#2
|
||||
byte main::i#3
|
||||
byte main::i#4
|
||||
byte sum(byte sum::a , byte sum::b)
|
||||
byte~ sum::$0
|
||||
byte sum::a
|
||||
byte sum::a#0
|
||||
byte sum::a#1
|
||||
byte sum::a#2
|
||||
byte sum::b
|
||||
byte sum::b#0
|
||||
byte sum::b#1
|
||||
byte sum::b#2
|
||||
byte sum::return
|
||||
byte sum::return#0
|
||||
byte sum::return#1
|
||||
byte sum::return#2
|
||||
byte sum::return#3
|
||||
byte sum::return#4
|
||||
byte sum::return#5
|
||||
byte sum::return#6
|
||||
|
||||
Simplifying constant pointer cast (byte*) 1024
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Alias sum::return#0 = sum::return#4
|
||||
Alias main::i#2 = main::i#3 main::i#4
|
||||
Alias sum::return#1 = sum::return#5
|
||||
Alias sum::return#2 = sum::$0 sum::return#6 sum::return#3
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Simple Condition main::$4 [17] if(main::i#1!=rangelast(0,5)) goto main::@1
|
||||
Successful SSA optimization Pass2ConditionalJumpSimplification
|
||||
Constant main::i#0 = 0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Resolved ranged next value [15] main::i#1 = ++ main::i#2 to ++
|
||||
Resolved ranged comparison value [17] if(main::i#1!=rangelast(0,5)) goto main::@1 to 6
|
||||
Converting *(pointer+n) to pointer[n] [14] *main::$0 = main::$3 -- main::SCREEN[main::i#2]
|
||||
Successful SSA optimization Pass2InlineDerefIdx
|
||||
Eliminating unused variable main::$0 and assignment [1] main::$0 = main::SCREEN + main::i#2
|
||||
Successful SSA optimization PassNEliminateUnusedVars
|
||||
Removing unused procedure __start
|
||||
Removing unused procedure block __start
|
||||
Removing unused procedure block __start::@1
|
||||
Removing unused procedure block __start::@return
|
||||
Successful SSA optimization PassNEliminateEmptyStart
|
||||
Adding number conversion cast (unumber) 6 in [14] if(main::i#1!=6) goto main::@1
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Simplifying constant integer cast 6
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Finalized unsigned number type (byte) 6
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Inlining constant with var siblings main::i#0
|
||||
Constant inlined main::i#0 = 0
|
||||
Successful SSA optimization Pass2ConstantInlining
|
||||
Added new block during phi lifting main::@4(between main::@3 and main::@1)
|
||||
Adding NOP phi() at start of main
|
||||
CALL GRAPH
|
||||
Calls in [main] to sum:6 sum:13
|
||||
|
||||
Created 3 initial phi equivalence classes
|
||||
Coalesced [4] sum::a#3 = sum::a#0
|
||||
Coalesced [5] sum::b#3 = sum::b#0
|
||||
Coalesced [11] sum::a#4 = sum::a#1
|
||||
Coalesced [12] sum::b#4 = sum::b#1
|
||||
Coalesced [21] main::i#5 = main::i#1
|
||||
Coalesced down to 3 phi equivalence classes
|
||||
Culled Empty Block label main::@4
|
||||
Adding NOP phi() at start of main
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
|
||||
void main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@3
|
||||
[1] main::i#2 = phi( main/0, main::@3/main::i#1 )
|
||||
[2] sum::a#0 = main::i#2
|
||||
[3] sum::b#0 = main::i#2
|
||||
[4] call sum
|
||||
[5] sum::return#0 = sum::return#2
|
||||
to:main::@2
|
||||
main::@2: scope:[main] from main::@1
|
||||
[6] main::$1 = sum::return#0
|
||||
[7] sum::a#1 = main::i#2
|
||||
[8] sum::b#1 = main::i#2
|
||||
[9] call sum
|
||||
[10] sum::return#1 = sum::return#2
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@2
|
||||
[11] main::$2 = sum::return#1
|
||||
[12] main::$3 = main::$1 + main::$2
|
||||
[13] main::SCREEN[main::i#2] = main::$3
|
||||
[14] main::i#1 = ++ main::i#2
|
||||
[15] if(main::i#1!=6) goto main::@1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@3
|
||||
[16] return
|
||||
to:@return
|
||||
|
||||
byte sum(byte sum::a , byte sum::b)
|
||||
sum: scope:[sum] from main::@1 main::@2
|
||||
[17] sum::b#2 = phi( main::@1/sum::b#0, main::@2/sum::b#1 )
|
||||
[17] sum::a#2 = phi( main::@1/sum::a#0, main::@2/sum::a#1 )
|
||||
[18] sum::return#2 = sum::a#2 + sum::b#2
|
||||
to:sum::@return
|
||||
sum::@return: scope:[sum] from sum
|
||||
[19] return
|
||||
to:@return
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
void main()
|
||||
byte~ main::$1 3.6666666666666665
|
||||
byte~ main::$2 22.0
|
||||
byte~ main::$3 22.0
|
||||
byte main::i
|
||||
byte main::i#1 16.5
|
||||
byte main::i#2 5.9230769230769225
|
||||
byte sum(byte sum::a , byte sum::b)
|
||||
byte sum::a
|
||||
byte sum::a#0 11.0
|
||||
byte sum::a#1 11.0
|
||||
byte sum::a#2 123.0
|
||||
byte sum::b
|
||||
byte sum::b#0 22.0
|
||||
byte sum::b#1 22.0
|
||||
byte sum::b#2 123.0
|
||||
byte sum::return
|
||||
byte sum::return#0 22.0
|
||||
byte sum::return#1 22.0
|
||||
byte sum::return#2 30.75
|
||||
|
||||
Initial phi equivalence classes
|
||||
[ main::i#2 main::i#1 ]
|
||||
[ sum::a#2 sum::a#0 sum::a#1 ]
|
||||
[ sum::b#2 sum::b#0 sum::b#1 ]
|
||||
Added variable sum::return#0 to live range equivalence class [ sum::return#0 ]
|
||||
Added variable main::$1 to live range equivalence class [ main::$1 ]
|
||||
Added variable sum::return#1 to live range equivalence class [ sum::return#1 ]
|
||||
Added variable main::$2 to live range equivalence class [ main::$2 ]
|
||||
Added variable main::$3 to live range equivalence class [ main::$3 ]
|
||||
Added variable sum::return#2 to live range equivalence class [ sum::return#2 ]
|
||||
Complete equivalence classes
|
||||
[ main::i#2 main::i#1 ]
|
||||
[ sum::a#2 sum::a#0 sum::a#1 ]
|
||||
[ sum::b#2 sum::b#0 sum::b#1 ]
|
||||
[ sum::return#0 ]
|
||||
[ main::$1 ]
|
||||
[ sum::return#1 ]
|
||||
[ main::$2 ]
|
||||
[ main::$3 ]
|
||||
[ sum::return#2 ]
|
||||
Allocated mem[1] [ main::i#2 main::i#1 ]
|
||||
Allocated mem[1] [ sum::a#2 sum::a#0 sum::a#1 ]
|
||||
Allocated mem[1] [ sum::b#2 sum::b#0 sum::b#1 ]
|
||||
Allocated mem[1] [ sum::return#0 ]
|
||||
Allocated mem[1] [ main::$1 ]
|
||||
Allocated mem[1] [ sum::return#1 ]
|
||||
Allocated mem[1] [ main::$2 ]
|
||||
Allocated mem[1] [ main::$3 ]
|
||||
Allocated mem[1] [ sum::return#2 ]
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [12] main::$3 = main::$1 + main::$2 [ main::i#2 main::$3 ] ( [ main::i#2 main::$3 ] { } ) always clobbers reg byte a
|
||||
Removing always clobbered register reg byte a as potential for mem[1] [ main::i#2 main::i#1 ]
|
||||
Statement [18] sum::return#2 = sum::a#2 + sum::b#2 [ sum::return#2 ] ( sum:4 [ main::i#2 sum::return#2 ] { { sum::b#0 = sum::b#2 sum::a#2 sum::a#0 main::i#2 } { sum::return#0 = sum::return#2 } } sum:9 [ main::i#2 main::$1 sum::return#2 ] { { sum::b#1 = sum::b#2 sum::a#2 sum::a#1 main::i#2 } { sum::return#1 = sum::return#2 } } ) always clobbers reg byte a
|
||||
Removing always clobbered register reg byte a as potential for mem[1] [ main::$1 ]
|
||||
Statement [12] main::$3 = main::$1 + main::$2 [ main::i#2 main::$3 ] ( [ main::i#2 main::$3 ] { } ) always clobbers reg byte a
|
||||
Statement [18] sum::return#2 = sum::a#2 + sum::b#2 [ sum::return#2 ] ( sum:4 [ main::i#2 sum::return#2 ] { { sum::b#0 = sum::b#2 sum::a#2 sum::a#0 main::i#2 } { sum::return#0 = sum::return#2 } } sum:9 [ main::i#2 main::$1 sum::return#2 ] { { sum::b#1 = sum::b#2 sum::a#2 sum::a#1 main::i#2 } { sum::return#1 = sum::return#2 } } ) always clobbers reg byte a
|
||||
Potential registers mem[1] [ main::i#2 main::i#1 ] : mem[1] , reg byte x , reg byte y ,
|
||||
Potential registers mem[1] [ sum::a#2 sum::a#0 sum::a#1 ] : mem[1] , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers mem[1] [ sum::b#2 sum::b#0 sum::b#1 ] : mem[1] , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers mem[1] [ sum::return#0 ] : mem[1] , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers mem[1] [ main::$1 ] : mem[1] , reg byte x , reg byte y ,
|
||||
Potential registers mem[1] [ sum::return#1 ] : mem[1] , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers mem[1] [ main::$2 ] : mem[1] , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers mem[1] [ main::$3 ] : mem[1] , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers mem[1] [ sum::return#2 ] : mem[1] , reg byte a , reg byte x , reg byte y ,
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [sum] 167: mem[1] [ sum::b#2 sum::b#0 sum::b#1 ] 145: mem[1] [ sum::a#2 sum::a#0 sum::a#1 ] 30.75: mem[1] [ sum::return#2 ] 22: mem[1] [ sum::return#0 ] 22: mem[1] [ sum::return#1 ]
|
||||
Uplift Scope [main] 22.42: mem[1] [ main::i#2 main::i#1 ] 22: mem[1] [ main::$2 ] 22: mem[1] [ main::$3 ] 3.67: mem[1] [ main::$1 ]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [sum] best 980 combination reg byte x [ sum::b#2 sum::b#0 sum::b#1 ] reg byte a [ sum::a#2 sum::a#0 sum::a#1 ] reg byte a [ sum::return#2 ] reg byte a [ sum::return#0 ] mem[1] [ sum::return#1 ]
|
||||
Limited combination testing to 100 combinations of 1024 possible.
|
||||
Uplifting [main] best 540 combination reg byte x [ main::i#2 main::i#1 ] reg byte a [ main::$2 ] reg byte a [ main::$3 ] mem[1] [ main::$1 ]
|
||||
Limited combination testing to 100 combinations of 144 possible.
|
||||
Uplifting [] best 540 combination
|
||||
Attempting to uplift remaining variables inmem[1] [ sum::return#1 ]
|
||||
Uplifting [sum] best 460 combination reg byte a [ sum::return#1 ]
|
||||
Attempting to uplift remaining variables inmem[1] [ main::$1 ]
|
||||
Uplifting [main] best 460 combination mem[1] [ main::$1 ]
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
// File Comments
|
||||
// Test that memory model "mem" affects intermediates
|
||||
// Upstart
|
||||
// Commodore 64 PRG executable file
|
||||
.file [name="varmodel-mem-1.prg", type="prg", segments="Program"]
|
||||
.segmentdef Program [segments="Basic, Code, Data"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segment Basic
|
||||
:BasicUpstart(main)
|
||||
// Global Constants & labels
|
||||
.segment Code
|
||||
// main
|
||||
main: {
|
||||
// A local pointer
|
||||
.label SCREEN = $400
|
||||
// [1] phi from main to main::@1 [phi:main->main::@1]
|
||||
__b1_from_main:
|
||||
// [1] phi main::i#2 = 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
|
||||
ldx #0
|
||||
jmp __b1
|
||||
// A local counter
|
||||
// [1] phi from main::@3 to main::@1 [phi:main::@3->main::@1]
|
||||
__b1_from___b3:
|
||||
// [1] phi main::i#2 = main::i#1 [phi:main::@3->main::@1#0] -- register_copy
|
||||
jmp __b1
|
||||
// main::@1
|
||||
__b1:
|
||||
// [2] sum::a#0 = main::i#2 -- vbuaa=vbuxx
|
||||
txa
|
||||
// [3] sum::b#0 = main::i#2
|
||||
// [4] call sum
|
||||
// [17] phi from main::@1 to sum [phi:main::@1->sum]
|
||||
sum_from___b1:
|
||||
// [17] phi sum::b#2 = sum::b#0 [phi:main::@1->sum#0] -- register_copy
|
||||
// [17] phi sum::a#2 = sum::a#0 [phi:main::@1->sum#1] -- register_copy
|
||||
jsr sum
|
||||
// [5] sum::return#0 = sum::return#2
|
||||
jmp __b2
|
||||
// main::@2
|
||||
__b2:
|
||||
// [6] main::$1 = sum::return#0 -- vbum1=vbuaa
|
||||
sta __1
|
||||
// [7] sum::a#1 = main::i#2 -- vbuaa=vbuxx
|
||||
txa
|
||||
// [8] sum::b#1 = main::i#2
|
||||
// [9] call sum
|
||||
// [17] phi from main::@2 to sum [phi:main::@2->sum]
|
||||
sum_from___b2:
|
||||
// [17] phi sum::b#2 = sum::b#1 [phi:main::@2->sum#0] -- register_copy
|
||||
// [17] phi sum::a#2 = sum::a#1 [phi:main::@2->sum#1] -- register_copy
|
||||
jsr sum
|
||||
// [10] sum::return#1 = sum::return#2
|
||||
jmp __b3
|
||||
// main::@3
|
||||
__b3:
|
||||
// [11] main::$2 = sum::return#1
|
||||
// [12] main::$3 = main::$1 + main::$2 -- vbuaa=vbum1_plus_vbuaa
|
||||
clc
|
||||
adc __1
|
||||
// [13] main::SCREEN[main::i#2] = main::$3 -- pbuc1_derefidx_vbuxx=vbuaa
|
||||
// Generates an intermediate
|
||||
sta SCREEN,x
|
||||
// [14] main::i#1 = ++ main::i#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
// [15] if(main::i#1!=6) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
|
||||
cpx #6
|
||||
bne __b1_from___b3
|
||||
jmp __breturn
|
||||
// main::@return
|
||||
__breturn:
|
||||
// [16] return
|
||||
rts
|
||||
.segment Data
|
||||
__1: .byte 0
|
||||
}
|
||||
.segment Code
|
||||
// sum
|
||||
// sum(byte register(A) a, byte register(X) b)
|
||||
sum: {
|
||||
// [18] sum::return#2 = sum::a#2 + sum::b#2 -- vbuaa=vbuaa_plus_vbuxx
|
||||
stx.z $ff
|
||||
clc
|
||||
adc.z $ff
|
||||
jmp __breturn
|
||||
// sum::@return
|
||||
__breturn:
|
||||
// [19] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp __b1
|
||||
Removing instruction jmp __b2
|
||||
Removing instruction jmp __b3
|
||||
Removing instruction jmp __breturn
|
||||
Removing instruction jmp __breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Replacing label __b1_from___b3 with __b1
|
||||
Removing instruction __b1_from___b3:
|
||||
Succesful ASM optimization Pass5RedundantLabelElimination
|
||||
Removing instruction __b1_from_main:
|
||||
Removing instruction sum_from___b1:
|
||||
Removing instruction __b2:
|
||||
Removing instruction sum_from___b2:
|
||||
Removing instruction __b3:
|
||||
Removing instruction __breturn:
|
||||
Removing instruction __breturn:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
Removing instruction jmp __b1
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
void main()
|
||||
byte~ main::$1 mem[1] 3.6666666666666665
|
||||
byte~ main::$2 reg byte a 22.0
|
||||
byte~ main::$3 reg byte a 22.0
|
||||
constant byte* const main::SCREEN = (byte*) 1024
|
||||
byte main::i
|
||||
byte main::i#1 reg byte x 16.5
|
||||
byte main::i#2 reg byte x 5.9230769230769225
|
||||
byte sum(byte sum::a , byte sum::b)
|
||||
byte sum::a
|
||||
byte sum::a#0 reg byte a 11.0
|
||||
byte sum::a#1 reg byte a 11.0
|
||||
byte sum::a#2 reg byte a 123.0
|
||||
byte sum::b
|
||||
byte sum::b#0 reg byte x 22.0
|
||||
byte sum::b#1 reg byte x 22.0
|
||||
byte sum::b#2 reg byte x 123.0
|
||||
byte sum::return
|
||||
byte sum::return#0 reg byte a 22.0
|
||||
byte sum::return#1 reg byte a 22.0
|
||||
byte sum::return#2 reg byte a 30.75
|
||||
|
||||
reg byte x [ main::i#2 main::i#1 ]
|
||||
reg byte a [ sum::a#2 sum::a#0 sum::a#1 ]
|
||||
reg byte x [ sum::b#2 sum::b#0 sum::b#1 ]
|
||||
reg byte a [ sum::return#0 ]
|
||||
mem[1] [ main::$1 ]
|
||||
reg byte a [ sum::return#1 ]
|
||||
reg byte a [ main::$2 ]
|
||||
reg byte a [ main::$3 ]
|
||||
reg byte a [ sum::return#2 ]
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 307
|
||||
|
||||
// File Comments
|
||||
// Test that memory model "mem" affects intermediates
|
||||
// Upstart
|
||||
// Commodore 64 PRG executable file
|
||||
.file [name="varmodel-mem-1.prg", type="prg", segments="Program"]
|
||||
.segmentdef Program [segments="Basic, Code, Data"]
|
||||
.segmentdef Basic [start=$0801]
|
||||
.segmentdef Code [start=$80d]
|
||||
.segmentdef Data [startAfter="Code"]
|
||||
.segment Basic
|
||||
:BasicUpstart(main)
|
||||
// Global Constants & labels
|
||||
.segment Code
|
||||
// main
|
||||
main: {
|
||||
// A local pointer
|
||||
.label SCREEN = $400
|
||||
// [1] phi from main to main::@1 [phi:main->main::@1]
|
||||
// [1] phi main::i#2 = 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
|
||||
ldx #0
|
||||
// A local counter
|
||||
// [1] phi from main::@3 to main::@1 [phi:main::@3->main::@1]
|
||||
// [1] phi main::i#2 = main::i#1 [phi:main::@3->main::@1#0] -- register_copy
|
||||
// main::@1
|
||||
__b1:
|
||||
// sum(i,i)
|
||||
// [2] sum::a#0 = main::i#2 -- vbuaa=vbuxx
|
||||
txa
|
||||
// [3] sum::b#0 = main::i#2
|
||||
// [4] call sum
|
||||
// [17] phi from main::@1 to sum [phi:main::@1->sum]
|
||||
// [17] phi sum::b#2 = sum::b#0 [phi:main::@1->sum#0] -- register_copy
|
||||
// [17] phi sum::a#2 = sum::a#0 [phi:main::@1->sum#1] -- register_copy
|
||||
jsr sum
|
||||
// sum(i,i)
|
||||
// [5] sum::return#0 = sum::return#2
|
||||
// main::@2
|
||||
// [6] main::$1 = sum::return#0 -- vbum1=vbuaa
|
||||
sta __1
|
||||
// [7] sum::a#1 = main::i#2 -- vbuaa=vbuxx
|
||||
txa
|
||||
// [8] sum::b#1 = main::i#2
|
||||
// [9] call sum
|
||||
// [17] phi from main::@2 to sum [phi:main::@2->sum]
|
||||
// [17] phi sum::b#2 = sum::b#1 [phi:main::@2->sum#0] -- register_copy
|
||||
// [17] phi sum::a#2 = sum::a#1 [phi:main::@2->sum#1] -- register_copy
|
||||
jsr sum
|
||||
// sum(i,i)
|
||||
// [10] sum::return#1 = sum::return#2
|
||||
// main::@3
|
||||
// [11] main::$2 = sum::return#1
|
||||
// sum(i,i)+sum(i,i)
|
||||
// [12] main::$3 = main::$1 + main::$2 -- vbuaa=vbum1_plus_vbuaa
|
||||
clc
|
||||
adc __1
|
||||
// *(SCREEN+i) = sum(i,i)+sum(i,i)
|
||||
// [13] main::SCREEN[main::i#2] = main::$3 -- pbuc1_derefidx_vbuxx=vbuaa
|
||||
// Generates an intermediate
|
||||
sta SCREEN,x
|
||||
// for( char i: 0..5 )
|
||||
// [14] main::i#1 = ++ main::i#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
// [15] if(main::i#1!=6) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
|
||||
cpx #6
|
||||
bne __b1
|
||||
// main::@return
|
||||
// }
|
||||
// [16] return
|
||||
rts
|
||||
.segment Data
|
||||
__1: .byte 0
|
||||
}
|
||||
.segment Code
|
||||
// sum
|
||||
// sum(byte register(A) a, byte register(X) b)
|
||||
sum: {
|
||||
// a+b
|
||||
// [18] sum::return#2 = sum::a#2 + sum::b#2 -- vbuaa=vbuaa_plus_vbuxx
|
||||
stx.z $ff
|
||||
clc
|
||||
adc.z $ff
|
||||
// sum::@return
|
||||
// }
|
||||
// [19] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
31
src/test/ref/varmodel-mem-1.sym
Normal file
31
src/test/ref/varmodel-mem-1.sym
Normal file
@ -0,0 +1,31 @@
|
||||
void main()
|
||||
byte~ main::$1 mem[1] 3.6666666666666665
|
||||
byte~ main::$2 reg byte a 22.0
|
||||
byte~ main::$3 reg byte a 22.0
|
||||
constant byte* const main::SCREEN = (byte*) 1024
|
||||
byte main::i
|
||||
byte main::i#1 reg byte x 16.5
|
||||
byte main::i#2 reg byte x 5.9230769230769225
|
||||
byte sum(byte sum::a , byte sum::b)
|
||||
byte sum::a
|
||||
byte sum::a#0 reg byte a 11.0
|
||||
byte sum::a#1 reg byte a 11.0
|
||||
byte sum::a#2 reg byte a 123.0
|
||||
byte sum::b
|
||||
byte sum::b#0 reg byte x 22.0
|
||||
byte sum::b#1 reg byte x 22.0
|
||||
byte sum::b#2 reg byte x 123.0
|
||||
byte sum::return
|
||||
byte sum::return#0 reg byte a 22.0
|
||||
byte sum::return#1 reg byte a 22.0
|
||||
byte sum::return#2 reg byte a 30.75
|
||||
|
||||
reg byte x [ main::i#2 main::i#1 ]
|
||||
reg byte a [ sum::a#2 sum::a#0 sum::a#1 ]
|
||||
reg byte x [ sum::b#2 sum::b#0 sum::b#1 ]
|
||||
reg byte a [ sum::return#0 ]
|
||||
mem[1] [ main::$1 ]
|
||||
reg byte a [ sum::return#1 ]
|
||||
reg byte a [ main::$2 ]
|
||||
reg byte a [ main::$3 ]
|
||||
reg byte a [ sum::return#2 ]
|
Loading…
Reference in New Issue
Block a user