mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-12-26 18:29:54 +00:00
Added support for init-value of global load/store memory variables.
This commit is contained in:
parent
030a379845
commit
2eb5aaa24f
@ -569,17 +569,16 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
initValue = Initializers.constantify(initValue, new Initializers.ValueTypeSpec(declVarType, declArraySpec), program, statementSource);
|
||||
VariableBuilder varBuilder = new VariableBuilder(varName, getCurrentScope(), false, declVarType, declArraySpec, declVarDirectives, currentDataSegment);
|
||||
Variable variable = varBuilder.build();
|
||||
if(variable.isKindConstant()) {
|
||||
// Set constant value
|
||||
ConstantValue constInitValue = getConstInitValue(initValue, initializer, statementSource);
|
||||
variable.setInitValue(constInitValue);
|
||||
// Add comments to constant
|
||||
variable.setComments(ensureUnusedComments(declVarComments));
|
||||
}
|
||||
if(!variable.isKindConstant() && !declVarStructMember) {
|
||||
Statement initStmt = new StatementAssignment(variable.getVariableRef(), initValue, true, statementSource, ensureUnusedComments(declVarComments));
|
||||
sequence.addStatement(initStmt);
|
||||
}
|
||||
if(variable.isKindConstant() || (variable.isKindLoadStore() && Variable.MemoryArea.MAIN_MEMORY.equals(variable.getMemoryArea()) && initValue instanceof ConstantValue && !declVarStructMember)) {
|
||||
// Set constant value
|
||||
ConstantValue constInitValue = getConstInitValue(initValue, initializer, statementSource);
|
||||
variable.setInitValue(constInitValue);
|
||||
// Add comments to constant
|
||||
variable.setComments(ensureUnusedComments(declVarComments));
|
||||
} else if(!variable.isKindConstant() && !declVarStructMember) {
|
||||
Statement initStmt = new StatementAssignment(variable.getVariableRef(), initValue, true, statementSource, ensureUnusedComments(declVarComments));
|
||||
sequence.addStatement(initStmt);
|
||||
}
|
||||
if(initializer != null)
|
||||
PrePostModifierHandler.addPostModifiers(this, initializer, statementSource);
|
||||
return null;
|
||||
|
@ -8,6 +8,7 @@ import dk.camelot64.kickc.model.iterator.ProgramValue;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
|
||||
import dk.camelot64.kickc.model.statements.*;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
import dk.camelot64.kickc.model.symbols.Variable;
|
||||
import dk.camelot64.kickc.model.values.LabelRef;
|
||||
import dk.camelot64.kickc.model.values.SymbolRef;
|
||||
import dk.camelot64.kickc.model.values.SymbolVariableRef;
|
||||
@ -34,7 +35,14 @@ public class Pass1AssertUsedVars extends Pass1Base {
|
||||
VariableReferenceInfos referenceInfos = getProgram().getVariableReferenceInfos();
|
||||
|
||||
ControlFlowBlock beginBlock = getProgram().getGraph().getBlock(new LabelRef(SymbolRef.BEGIN_BLOCK_NAME));
|
||||
assertUsedVars(beginBlock, null, referenceInfos, new LinkedHashSet<>(), new LinkedHashSet<>());
|
||||
final LinkedHashSet<SymbolVariableRef> defined = new LinkedHashSet<>();
|
||||
// Add all variables with an init-value
|
||||
for(Variable var : getScope().getAllVars(true)) {
|
||||
if(var.getInitValue()!=null) {
|
||||
defined.add(var.getRef());
|
||||
}
|
||||
}
|
||||
assertUsedVars(beginBlock, null, referenceInfos, defined, new LinkedHashSet<>());
|
||||
getProgram().clearVariableReferenceInfos();
|
||||
getProgram().clearStatementIndices();
|
||||
return false;
|
||||
|
@ -267,10 +267,9 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
||||
if(lValueUnwinding.isBulkCopyable() && rValueUnwinding.isBulkCopyable()) {
|
||||
// Use bulk unwinding for a struct member that is an array
|
||||
stmtIt.previous();
|
||||
//RValue lValueMemberVarPointer = lValueUnwinding.getBulkLValue(getScope());
|
||||
//LValue lValueMemberVarRef = new PointerDereferenceSimple(lValueMemberVarPointer);
|
||||
//if(rValueUnwinding.getArraySpec()==null || !lValueUnwinding.getArraySpec().equals(rValueUnwinding.getArraySpec()))
|
||||
// throw new RuntimeException("ArraySpec mismatch!");
|
||||
if(lValueUnwinding.getArraySpec()!=null)
|
||||
if(rValueUnwinding.getArraySpec()==null || !lValueUnwinding.getArraySpec().equals(rValueUnwinding.getArraySpec()))
|
||||
throw new RuntimeException("ArraySpec mismatch!");
|
||||
LValue lValueMemberVarRef = lValueUnwinding.getBulkLValue(getScope());
|
||||
RValue rValueBulkUnwinding = rValueUnwinding.getBulkRValue(getScope());
|
||||
if(lValueUnwoundList != null)
|
||||
|
@ -2,6 +2,7 @@ package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.symbols.StructDefinition;
|
||||
import dk.camelot64.kickc.model.symbols.Variable;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.values.*;
|
||||
@ -21,6 +22,8 @@ public class Pass3AssertArrayLengths extends Pass2SsaAssertion {
|
||||
public void check() throws AssertionFailed {
|
||||
Collection<Variable> allConstants = getScope().getAllConstants(true);
|
||||
for(Variable constantVar : allConstants) {
|
||||
if(constantVar.getScope() instanceof StructDefinition)
|
||||
continue;
|
||||
SymbolType constantType = constantVar.getType();
|
||||
if(constantVar.isArray() && constantVar.getArraySize() != null) {
|
||||
ConstantValue declaredSize = constantVar.getArraySize();
|
||||
|
@ -539,10 +539,23 @@ public class Pass4CodeGeneration {
|
||||
String alignment = AsmFormat.getAsmNumber(declaredAlignment);
|
||||
asm.addDataAlignment(alignment);
|
||||
}
|
||||
AsmDataChunk asmDataChunk = new AsmDataChunk();
|
||||
ConstantValue zeroValue = Initializers.createZeroValue(new Initializers.ValueTypeSpec(variable.getType(), variable.getArraySpec()), null);
|
||||
addChunkData(asmDataChunk, zeroValue, variable.getType(), variable.getArraySpec(), scopeRef);
|
||||
asmDataChunk.addToAsm(AsmFormat.asmFix(variable.getAsmName()), asm);
|
||||
if(variable.getInitValue()!=null) {
|
||||
// Variable has a constant init Value
|
||||
ConstantValue constantValue = variable.getInitValue();
|
||||
if(constantValue instanceof ConstantArray || constantValue instanceof ConstantString || constantValue instanceof ConstantStructValue || constantValue instanceof StructZero) {
|
||||
AsmDataChunk asmDataChunk = new AsmDataChunk();
|
||||
addChunkData(asmDataChunk, constantValue, variable.getType(), variable.getArraySpec(), scopeRef);
|
||||
asmDataChunk.addToAsm(AsmFormat.asmFix(variable.getAsmName()), asm);
|
||||
} else {
|
||||
throw new InternalError("Constant Variable not handled " + variable.toString(program));
|
||||
}
|
||||
} else {
|
||||
// Zero-fill variable
|
||||
AsmDataChunk asmDataChunk = new AsmDataChunk();
|
||||
ConstantValue zeroValue = Initializers.createZeroValue(new Initializers.ValueTypeSpec(variable.getType(), variable.getArraySpec()), null);
|
||||
addChunkData(asmDataChunk, zeroValue, variable.getType(), variable.getArraySpec(), scopeRef);
|
||||
asmDataChunk.addToAsm(AsmFormat.asmFix(variable.getAsmName()), asm);
|
||||
}
|
||||
added.add(variable.getAsmName());
|
||||
}
|
||||
} else {
|
||||
|
@ -1127,9 +1127,14 @@ public class TestPrograms {
|
||||
assertError("struct-err-0", "Unknown struct type");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStruct33() throws IOException, URISyntaxException {
|
||||
compileAndCompare("struct-33", log());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStruct32() throws IOException, URISyntaxException {
|
||||
compileAndCompare("struct-32", log());
|
||||
compileAndCompare("struct-32");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -1139,7 +1144,7 @@ public class TestPrograms {
|
||||
|
||||
@Test
|
||||
public void testStruct30() throws IOException, URISyntaxException {
|
||||
compileAndCompare("struct-30", log());
|
||||
compileAndCompare("struct-30");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -1229,17 +1234,17 @@ public class TestPrograms {
|
||||
|
||||
@Test
|
||||
public void testStruct12() throws IOException, URISyntaxException {
|
||||
compileAndCompare("struct-12", log());
|
||||
compileAndCompare("struct-12");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStruct11b() throws IOException, URISyntaxException {
|
||||
compileAndCompare("struct-11b", log());
|
||||
compileAndCompare("struct-11b");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStruct11() throws IOException, URISyntaxException {
|
||||
compileAndCompare("struct-11", log());
|
||||
compileAndCompare("struct-11");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
17
src/test/kc/struct-33.kc
Normal file
17
src/test/kc/struct-33.kc
Normal file
@ -0,0 +1,17 @@
|
||||
// Minimal struct with C-Standard behavior - declaration, instantiation and usage
|
||||
|
||||
struct Point {
|
||||
char x;
|
||||
char y;
|
||||
};
|
||||
|
||||
__mem __ma struct Point point;
|
||||
|
||||
const char* SCREEN = 0x0400;
|
||||
|
||||
void main() {
|
||||
point.x = 2;
|
||||
point.y = 3;
|
||||
SCREEN[0] = point.x;
|
||||
SCREEN[1] = point.y;
|
||||
}
|
@ -1,19 +1,9 @@
|
||||
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
|
||||
// Test a memory variable struct value
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(__bbegin)
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
.const SIZEOF_STRUCT_FOO = 2
|
||||
.const OFFSET_STRUCT_FOO_THING2 = 1
|
||||
__bbegin:
|
||||
ldy #SIZEOF_STRUCT_FOO
|
||||
!:
|
||||
lda __0-1,y
|
||||
sta bar-1,y
|
||||
dey
|
||||
bne !-
|
||||
jsr main
|
||||
rts
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
.label barp = bar
|
||||
@ -23,5 +13,4 @@ main: {
|
||||
sta SCREEN+1
|
||||
rts
|
||||
}
|
||||
__0: .byte 'a', 'b'
|
||||
bar: .fill SIZEOF_STRUCT_FOO, 0
|
||||
bar: .byte 'a', 'b'
|
||||
|
@ -1,5 +1,5 @@
|
||||
@begin: scope:[] from
|
||||
[0] *(&(struct foo) bar) ← memcpy(*(&(const struct foo) $0), struct foo, (const byte) SIZEOF_STRUCT_FOO)
|
||||
[0] phi()
|
||||
to:@1
|
||||
@1: scope:[] from @begin
|
||||
[1] phi()
|
||||
|
@ -1,12 +1,10 @@
|
||||
Setting inferred volatile on symbol affected by address-of (struct foo*) main::barp ← &(struct foo) bar
|
||||
Adding struct value member variable copy *(&(struct foo) bar) ← memcpy(*(&(const struct foo) $0), struct foo, (const byte) SIZEOF_STRUCT_FOO)
|
||||
Rewriting struct pointer member access *((struct foo*) main::barp).thing1
|
||||
Rewriting struct pointer member access *((struct foo*) main::barp).thing2
|
||||
Identified constant variable (struct foo*) main::barp
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
@begin: scope:[] from
|
||||
*(&(struct foo) bar) ← memcpy(*(&(const struct foo) $0), struct foo, (const byte) SIZEOF_STRUCT_FOO)
|
||||
to:@1
|
||||
|
||||
(void()) main()
|
||||
@ -30,15 +28,13 @@ main::@return: scope:[main] from main
|
||||
@end: scope:[] from @2
|
||||
|
||||
SYMBOL TABLE SSA
|
||||
(const struct foo) $0 = { thing1: (byte) 'a', thing2: (byte) 'b' }
|
||||
(label) @1
|
||||
(label) @2
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(const byte) OFFSET_STRUCT_FOO_THING1 = (byte) 0
|
||||
(const byte) OFFSET_STRUCT_FOO_THING2 = (byte) 1
|
||||
(const byte) SIZEOF_STRUCT_FOO = (byte) 2
|
||||
(struct foo) bar loadstore
|
||||
(struct foo) bar loadstore = { thing1: (byte) 'a', thing2: (byte) 'b' }
|
||||
(byte) foo::thing1
|
||||
(byte) foo::thing2
|
||||
(void()) main()
|
||||
@ -54,20 +50,20 @@ SYMBOL TABLE SSA
|
||||
|
||||
Simplifying constant pointer cast (byte*) 1024
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Constant right-side identified [2] (byte*~) main::$0 ← (byte*)(const struct foo*) main::barp + (const byte) OFFSET_STRUCT_FOO_THING1
|
||||
Constant right-side identified [5] (byte*~) main::$1 ← (byte*)(const struct foo*) main::barp + (const byte) OFFSET_STRUCT_FOO_THING2
|
||||
Constant right-side identified [1] (byte*~) main::$0 ← (byte*)(const struct foo*) main::barp + (const byte) OFFSET_STRUCT_FOO_THING1
|
||||
Constant right-side identified [4] (byte*~) main::$1 ← (byte*)(const struct foo*) main::barp + (const byte) OFFSET_STRUCT_FOO_THING2
|
||||
Successful SSA optimization Pass2ConstantRValueConsolidation
|
||||
Constant (const byte) main::i#0 = 0
|
||||
Constant (const byte*) main::$0 = (byte*)main::barp+OFFSET_STRUCT_FOO_THING1
|
||||
Constant (const byte*) main::$1 = (byte*)main::barp+OFFSET_STRUCT_FOO_THING2
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Simplifying expression containing zero (byte*)main::barp in
|
||||
Simplifying expression containing zero main::SCREEN in [3] *((const byte*) main::SCREEN + (const byte) main::i#0) ← *((const byte*) main::$0)
|
||||
Simplifying expression containing zero main::SCREEN in [2] *((const byte*) main::SCREEN + (const byte) main::i#0) ← *((const byte*) main::$0)
|
||||
Successful SSA optimization PassNSimplifyExpressionWithZero
|
||||
Eliminating unused variable (byte) main::i#2 and assignment [4] (byte) main::i#2 ← ++ (byte) main::i#1
|
||||
Eliminating unused variable (byte) main::i#2 and assignment [3] (byte) main::i#2 ← ++ (byte) main::i#1
|
||||
Eliminating unused constant (const byte) OFFSET_STRUCT_FOO_THING1
|
||||
Successful SSA optimization PassNEliminateUnusedVars
|
||||
Constant right-side identified [2] (byte) main::i#1 ← ++ (const byte) main::i#0
|
||||
Constant right-side identified [1] (byte) main::i#1 ← ++ (const byte) main::i#0
|
||||
Successful SSA optimization Pass2ConstantRValueConsolidation
|
||||
Constant (const byte) main::i#1 = ++main::i#0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
@ -82,6 +78,7 @@ Consolidated array index constant in *(main::SCREEN+++0)
|
||||
Successful SSA optimization Pass2ConstantAdditionElimination
|
||||
Simplifying constant integer increment ++0
|
||||
Successful SSA optimization Pass2ConstantSimplification
|
||||
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
|
||||
@ -91,12 +88,13 @@ 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] *(&(struct foo) bar) ← memcpy(*(&(const struct foo) $0), struct foo, (const byte) SIZEOF_STRUCT_FOO)
|
||||
[0] phi()
|
||||
to:@1
|
||||
@1: scope:[] from @begin
|
||||
[1] phi()
|
||||
@ -116,7 +114,7 @@ main::@return: scope:[main] from main
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
(struct foo) bar loadstore
|
||||
(struct foo) bar loadstore = { thing1: (byte) 'a', thing2: (byte) 'b' }
|
||||
(byte) foo::thing1
|
||||
(byte) foo::thing2
|
||||
(void()) main()
|
||||
@ -138,17 +136,9 @@ Target platform is c64basic / MOS6502X
|
||||
:BasicUpstart(__bbegin)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
.const SIZEOF_STRUCT_FOO = 2
|
||||
.const OFFSET_STRUCT_FOO_THING2 = 1
|
||||
// @begin
|
||||
__bbegin:
|
||||
// [0] *(&(struct foo) bar) ← memcpy(*(&(const struct foo) $0), struct foo, (const byte) SIZEOF_STRUCT_FOO) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
|
||||
ldy #SIZEOF_STRUCT_FOO
|
||||
!:
|
||||
lda __0-1,y
|
||||
sta bar-1,y
|
||||
dey
|
||||
bne !-
|
||||
// [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
__b1_from___bbegin:
|
||||
jmp __b1
|
||||
@ -178,11 +168,9 @@ main: {
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
__0: .byte 'a', 'b'
|
||||
bar: .fill SIZEOF_STRUCT_FOO, 0
|
||||
bar: .byte 'a', 'b'
|
||||
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [0] *(&(struct foo) bar) ← memcpy(*(&(const struct foo) $0), struct foo, (const byte) SIZEOF_STRUCT_FOO) [ ] ( [ ] ) always clobbers reg byte a reg byte y
|
||||
Statement [4] *((const byte*) main::SCREEN) ← *((byte*)(const struct foo*) main::barp) [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||
Statement [5] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(const struct foo*) main::barp+(const byte) OFFSET_STRUCT_FOO_THING2) [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||
Potential registers mem[2] [ bar ] : mem[2] ,
|
||||
@ -192,9 +180,9 @@ Uplift Scope [foo]
|
||||
Uplift Scope [main]
|
||||
Uplift Scope [] 0: mem[2] [ bar ]
|
||||
|
||||
Uplifting [foo] best 53 combination
|
||||
Uplifting [main] best 53 combination
|
||||
Uplifting [] best 53 combination mem[2] [ bar ]
|
||||
Uplifting [foo] best 37 combination
|
||||
Uplifting [main] best 37 combination
|
||||
Uplifting [] best 37 combination mem[2] [ bar ]
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
// File Comments
|
||||
@ -205,17 +193,9 @@ ASSEMBLER BEFORE OPTIMIZATION
|
||||
:BasicUpstart(__bbegin)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
.const SIZEOF_STRUCT_FOO = 2
|
||||
.const OFFSET_STRUCT_FOO_THING2 = 1
|
||||
// @begin
|
||||
__bbegin:
|
||||
// [0] *(&(struct foo) bar) ← memcpy(*(&(const struct foo) $0), struct foo, (const byte) SIZEOF_STRUCT_FOO) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
|
||||
ldy #SIZEOF_STRUCT_FOO
|
||||
!:
|
||||
lda __0-1,y
|
||||
sta bar-1,y
|
||||
dey
|
||||
bne !-
|
||||
// [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
__b1_from___bbegin:
|
||||
jmp __b1
|
||||
@ -245,32 +225,33 @@ main: {
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
__0: .byte 'a', 'b'
|
||||
bar: .fill SIZEOF_STRUCT_FOO, 0
|
||||
bar: .byte 'a', 'b'
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp __b1
|
||||
Removing instruction jmp __bend
|
||||
Removing instruction jmp __breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Replacing label __bbegin with __b1
|
||||
Removing instruction __bbegin:
|
||||
Removing instruction __b1_from___bbegin:
|
||||
Removing instruction __bend_from___b1:
|
||||
Succesful ASM optimization Pass5RedundantLabelElimination
|
||||
Removing instruction __b1:
|
||||
Removing instruction __bend:
|
||||
Removing instruction __breturn:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
Adding RTS to root block
|
||||
Succesful ASM optimization Pass5AddMainRts
|
||||
Updating BasicUpstart to call main directly
|
||||
Removing instruction jsr main
|
||||
Succesful ASM optimization Pass5SkipBegin
|
||||
Removing instruction __b1:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
(const struct foo) $0 = { thing1: (byte) 'a', thing2: (byte) 'b' }
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(const byte) OFFSET_STRUCT_FOO_THING2 = (byte) 1
|
||||
(const byte) SIZEOF_STRUCT_FOO = (byte) 2
|
||||
(struct foo) bar loadstore mem[2]
|
||||
(struct foo) bar loadstore mem[2] = { thing1: (byte) 'a', thing2: (byte) 'b' }
|
||||
(byte) foo::thing1
|
||||
(byte) foo::thing2
|
||||
(void()) main()
|
||||
@ -283,33 +264,21 @@ mem[2] [ bar ]
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 50
|
||||
Score: 22
|
||||
|
||||
// File Comments
|
||||
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
|
||||
// Test a memory variable struct value
|
||||
// Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(__bbegin)
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
.const SIZEOF_STRUCT_FOO = 2
|
||||
.const OFFSET_STRUCT_FOO_THING2 = 1
|
||||
// @begin
|
||||
__bbegin:
|
||||
// bar = { 'a', 'b' }
|
||||
// [0] *(&(struct foo) bar) ← memcpy(*(&(const struct foo) $0), struct foo, (const byte) SIZEOF_STRUCT_FOO) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
|
||||
ldy #SIZEOF_STRUCT_FOO
|
||||
!:
|
||||
lda __0-1,y
|
||||
sta bar-1,y
|
||||
dey
|
||||
bne !-
|
||||
// [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
|
||||
@ -330,6 +299,5 @@ main: {
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
__0: .byte 'a', 'b'
|
||||
bar: .fill SIZEOF_STRUCT_FOO, 0
|
||||
bar: .byte 'a', 'b'
|
||||
|
||||
|
@ -1,10 +1,8 @@
|
||||
(const struct foo) $0 = { thing1: (byte) 'a', thing2: (byte) 'b' }
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(const byte) OFFSET_STRUCT_FOO_THING2 = (byte) 1
|
||||
(const byte) SIZEOF_STRUCT_FOO = (byte) 2
|
||||
(struct foo) bar loadstore mem[2]
|
||||
(struct foo) bar loadstore mem[2] = { thing1: (byte) 'a', thing2: (byte) 'b' }
|
||||
(byte) foo::thing1
|
||||
(byte) foo::thing2
|
||||
(void()) main()
|
||||
|
@ -1,20 +1,10 @@
|
||||
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
|
||||
// Test a memory variable struct value - containing a fixed size array
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(__bbegin)
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
.const SIZEOF_STRUCT_FOO = $e
|
||||
.const OFFSET_STRUCT_FOO_THING2 = 1
|
||||
.const OFFSET_STRUCT_FOO_THING3 = 2
|
||||
__bbegin:
|
||||
ldy #SIZEOF_STRUCT_FOO
|
||||
!:
|
||||
lda __0-1,y
|
||||
sta bar-1,y
|
||||
dey
|
||||
bne !-
|
||||
jsr main
|
||||
rts
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
.label barp = bar
|
||||
@ -33,8 +23,7 @@ main: {
|
||||
bne __b1
|
||||
rts
|
||||
}
|
||||
__0: .byte 'a', 'b'
|
||||
bar: .byte 'a', 'b'
|
||||
.text "qwe"
|
||||
.byte 0
|
||||
.fill 8, 0
|
||||
bar: .fill SIZEOF_STRUCT_FOO, 0
|
||||
|
@ -1,5 +1,5 @@
|
||||
@begin: scope:[] from
|
||||
[0] *(&(struct foo) bar) ← memcpy(*(&(const struct foo) $0), struct foo, (const byte) SIZEOF_STRUCT_FOO)
|
||||
[0] phi()
|
||||
to:@1
|
||||
@1: scope:[] from @begin
|
||||
[1] phi()
|
||||
|
@ -3,7 +3,6 @@ Fixing struct type size struct foo to 14
|
||||
Fixing struct type SIZE_OF struct foo to 14
|
||||
Fixing struct type SIZE_OF struct foo to 14
|
||||
Setting inferred volatile on symbol affected by address-of (struct foo*) main::barp ← &(struct foo) bar
|
||||
Adding struct value member variable copy *(&(struct foo) bar) ← memcpy(*(&(const struct foo) $0), struct foo, (const byte) SIZEOF_STRUCT_FOO)
|
||||
Rewriting struct pointer member access *((struct foo*) main::barp).thing1
|
||||
Rewriting struct pointer member access *((struct foo*) main::barp).thing2
|
||||
Rewriting struct pointer member access *((struct foo*) main::barp).thing3
|
||||
@ -12,7 +11,6 @@ Culled Empty Block (label) main::@2
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
@begin: scope:[] from
|
||||
*(&(struct foo) bar) ← memcpy(*(&(const struct foo) $0), struct foo, (const byte) SIZEOF_STRUCT_FOO)
|
||||
to:@1
|
||||
|
||||
(void()) main()
|
||||
@ -47,7 +45,6 @@ main::@return: scope:[main] from main::@1
|
||||
@end: scope:[] from @2
|
||||
|
||||
SYMBOL TABLE SSA
|
||||
(const struct foo) $0 = { thing1: (byte) 'a', thing2: (byte) 'b', thing3: (string) "qwe" }
|
||||
(label) @1
|
||||
(label) @2
|
||||
(label) @begin
|
||||
@ -55,8 +52,7 @@ SYMBOL TABLE SSA
|
||||
(const byte) OFFSET_STRUCT_FOO_THING1 = (byte) 0
|
||||
(const byte) OFFSET_STRUCT_FOO_THING2 = (byte) 1
|
||||
(const byte) OFFSET_STRUCT_FOO_THING3 = (byte) 2
|
||||
(const byte) SIZEOF_STRUCT_FOO = (byte) $e
|
||||
(struct foo) bar loadstore
|
||||
(struct foo) bar loadstore = { thing1: (byte) 'a', thing2: (byte) 'b', thing3: (string) "qwe" }
|
||||
(byte) foo::thing1
|
||||
(byte) foo::thing2
|
||||
(const byte*) foo::thing3[(number) $c] = { fill( $c, 0) }
|
||||
@ -82,11 +78,11 @@ SYMBOL TABLE SSA
|
||||
|
||||
Simplifying constant pointer cast (byte*) 1024
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Simple Condition (bool~) main::$0 [15] if((byte) main::j#1!=rangelast(0,$b)) goto main::@1
|
||||
Simple Condition (bool~) main::$0 [14] if((byte) main::j#1!=rangelast(0,$b)) goto main::@1
|
||||
Successful SSA optimization Pass2ConditionalJumpSimplification
|
||||
Constant right-side identified [2] (byte*~) main::$1 ← (byte*)(const struct foo*) main::barp + (const byte) OFFSET_STRUCT_FOO_THING1
|
||||
Constant right-side identified [5] (byte*~) main::$2 ← (byte*)(const struct foo*) main::barp + (const byte) OFFSET_STRUCT_FOO_THING2
|
||||
Constant right-side identified [10] (byte*~) main::$3 ← (byte*)(const struct foo*) main::barp + (const byte) OFFSET_STRUCT_FOO_THING3
|
||||
Constant right-side identified [1] (byte*~) main::$1 ← (byte*)(const struct foo*) main::barp + (const byte) OFFSET_STRUCT_FOO_THING1
|
||||
Constant right-side identified [4] (byte*~) main::$2 ← (byte*)(const struct foo*) main::barp + (const byte) OFFSET_STRUCT_FOO_THING2
|
||||
Constant right-side identified [9] (byte*~) main::$3 ← (byte*)(const struct foo*) main::barp + (const byte) OFFSET_STRUCT_FOO_THING3
|
||||
Successful SSA optimization Pass2ConstantRValueConsolidation
|
||||
Constant (const byte) main::i#0 = 0
|
||||
Constant (const byte*) main::$1 = (byte*)main::barp+OFFSET_STRUCT_FOO_THING1
|
||||
@ -94,10 +90,10 @@ Constant (const byte*) main::$2 = (byte*)main::barp+OFFSET_STRUCT_FOO_THING2
|
||||
Constant (const byte) main::j#0 = 0
|
||||
Constant (const byte*) main::$3 = (byte*)main::barp+OFFSET_STRUCT_FOO_THING3
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Resolved ranged next value [13] main::j#1 ← ++ main::j#2 to ++
|
||||
Resolved ranged comparison value [15] if(main::j#1!=rangelast(0,$b)) goto main::@1 to (number) $c
|
||||
Resolved ranged next value [12] main::j#1 ← ++ main::j#2 to ++
|
||||
Resolved ranged comparison value [14] if(main::j#1!=rangelast(0,$b)) goto main::@1 to (number) $c
|
||||
Simplifying expression containing zero (byte*)main::barp in
|
||||
Simplifying expression containing zero main::SCREEN in [3] *((const byte*) main::SCREEN + (const byte) main::i#0) ← *((const byte*) main::$1)
|
||||
Simplifying expression containing zero main::SCREEN in [2] *((const byte*) main::SCREEN + (const byte) main::i#0) ← *((const byte*) main::$1)
|
||||
Successful SSA optimization PassNSimplifyExpressionWithZero
|
||||
Eliminating unused constant (const byte) OFFSET_STRUCT_FOO_THING1
|
||||
Successful SSA optimization PassNEliminateUnusedVars
|
||||
@ -107,11 +103,11 @@ Simplifying constant integer cast $c
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Finalized unsigned number type (byte) $c
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Constant right-side identified [2] (byte) main::i#1 ← ++ (const byte) main::i#0
|
||||
Constant right-side identified [1] (byte) main::i#1 ← ++ (const byte) main::i#0
|
||||
Successful SSA optimization Pass2ConstantRValueConsolidation
|
||||
Constant (const byte) main::i#1 = ++main::i#0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Constant right-side identified [3] (byte) main::i#2 ← ++ (const byte) main::i#1
|
||||
Constant right-side identified [2] (byte) main::i#2 ← ++ (const byte) main::i#1
|
||||
Successful SSA optimization Pass2ConstantRValueConsolidation
|
||||
Constant (const byte) main::i#2 = ++main::i#1
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
@ -135,6 +131,7 @@ Successful SSA optimization Pass2ConstantSimplification
|
||||
Simplifying constant integer increment ++1
|
||||
Successful SSA optimization Pass2ConstantSimplification
|
||||
Added new block during phi lifting main::@3(between main::@1 and main::@1)
|
||||
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
|
||||
@ -147,12 +144,13 @@ Coalesced [14] main::i#5 ← main::i#3
|
||||
Coalesced down to 2 phi equivalence classes
|
||||
Culled Empty Block (label) @2
|
||||
Culled Empty Block (label) main::@3
|
||||
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] *(&(struct foo) bar) ← memcpy(*(&(const struct foo) $0), struct foo, (const byte) SIZEOF_STRUCT_FOO)
|
||||
[0] phi()
|
||||
to:@1
|
||||
@1: scope:[] from @begin
|
||||
[1] phi()
|
||||
@ -180,7 +178,7 @@ main::@return: scope:[main] from main::@1
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
(struct foo) bar loadstore
|
||||
(struct foo) bar loadstore = { thing1: (byte) 'a', thing2: (byte) 'b', thing3: (string) "qwe" }
|
||||
(byte) foo::thing1
|
||||
(byte) foo::thing2
|
||||
(void()) main()
|
||||
@ -213,18 +211,10 @@ Target platform is c64basic / MOS6502X
|
||||
:BasicUpstart(__bbegin)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
.const SIZEOF_STRUCT_FOO = $e
|
||||
.const OFFSET_STRUCT_FOO_THING2 = 1
|
||||
.const OFFSET_STRUCT_FOO_THING3 = 2
|
||||
// @begin
|
||||
__bbegin:
|
||||
// [0] *(&(struct foo) bar) ← memcpy(*(&(const struct foo) $0), struct foo, (const byte) SIZEOF_STRUCT_FOO) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
|
||||
ldy #SIZEOF_STRUCT_FOO
|
||||
!:
|
||||
lda __0-1,y
|
||||
sta bar-1,y
|
||||
dey
|
||||
bne !-
|
||||
// [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
__b1_from___bbegin:
|
||||
jmp __b1
|
||||
@ -285,20 +275,17 @@ main: {
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
__0: .byte 'a', 'b'
|
||||
bar: .byte 'a', 'b'
|
||||
.text "qwe"
|
||||
.byte 0
|
||||
.fill 8, 0
|
||||
bar: .fill SIZEOF_STRUCT_FOO, 0
|
||||
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [0] *(&(struct foo) bar) ← memcpy(*(&(const struct foo) $0), struct foo, (const byte) SIZEOF_STRUCT_FOO) [ ] ( [ ] ) always clobbers reg byte a reg byte y
|
||||
Statement [4] *((const byte*) main::SCREEN) ← *((byte*)(const struct foo*) main::barp) [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||
Statement [5] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(const struct foo*) main::barp+(const byte) OFFSET_STRUCT_FOO_THING2) [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||
Statement [7] *((const byte*) main::SCREEN + (byte) main::i#4) ← *((byte*)(const struct foo*) main::barp+(const byte) OFFSET_STRUCT_FOO_THING3 + (byte) main::j#2) [ main::j#2 main::i#4 ] ( main:2 [ main::j#2 main::i#4 ] ) always clobbers reg byte a
|
||||
Removing always clobbered register reg byte a as potential for zp[1]:2 [ main::j#2 main::j#1 ]
|
||||
Removing always clobbered register reg byte a as potential for zp[1]:3 [ main::i#4 main::i#3 ]
|
||||
Statement [0] *(&(struct foo) bar) ← memcpy(*(&(const struct foo) $0), struct foo, (const byte) SIZEOF_STRUCT_FOO) [ ] ( [ ] ) always clobbers reg byte a reg byte y
|
||||
Statement [4] *((const byte*) main::SCREEN) ← *((byte*)(const struct foo*) main::barp) [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||
Statement [5] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(const struct foo*) main::barp+(const byte) OFFSET_STRUCT_FOO_THING2) [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||
Statement [7] *((const byte*) main::SCREEN + (byte) main::i#4) ← *((byte*)(const struct foo*) main::barp+(const byte) OFFSET_STRUCT_FOO_THING3 + (byte) main::j#2) [ main::j#2 main::i#4 ] ( main:2 [ main::j#2 main::i#4 ] ) always clobbers reg byte a
|
||||
@ -311,9 +298,9 @@ Uplift Scope [main] 27.5: zp[1]:2 [ main::j#2 main::j#1 ] 23.83: zp[1]:3 [ main:
|
||||
Uplift Scope [foo]
|
||||
Uplift Scope [] 0: mem[14] [ bar ]
|
||||
|
||||
Uplifting [main] best 360 combination reg byte y [ main::j#2 main::j#1 ] reg byte x [ main::i#4 main::i#3 ]
|
||||
Uplifting [foo] best 360 combination
|
||||
Uplifting [] best 360 combination mem[14] [ bar ]
|
||||
Uplifting [main] best 344 combination reg byte y [ main::j#2 main::j#1 ] reg byte x [ main::i#4 main::i#3 ]
|
||||
Uplifting [foo] best 344 combination
|
||||
Uplifting [] best 344 combination mem[14] [ bar ]
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
// File Comments
|
||||
@ -324,18 +311,10 @@ ASSEMBLER BEFORE OPTIMIZATION
|
||||
:BasicUpstart(__bbegin)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
.const SIZEOF_STRUCT_FOO = $e
|
||||
.const OFFSET_STRUCT_FOO_THING2 = 1
|
||||
.const OFFSET_STRUCT_FOO_THING3 = 2
|
||||
// @begin
|
||||
__bbegin:
|
||||
// [0] *(&(struct foo) bar) ← memcpy(*(&(const struct foo) $0), struct foo, (const byte) SIZEOF_STRUCT_FOO) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
|
||||
ldy #SIZEOF_STRUCT_FOO
|
||||
!:
|
||||
lda __0-1,y
|
||||
sta bar-1,y
|
||||
dey
|
||||
bne !-
|
||||
// [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
__b1_from___bbegin:
|
||||
jmp __b1
|
||||
@ -389,11 +368,10 @@ main: {
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
__0: .byte 'a', 'b'
|
||||
bar: .byte 'a', 'b'
|
||||
.text "qwe"
|
||||
.byte 0
|
||||
.fill 8, 0
|
||||
bar: .fill SIZEOF_STRUCT_FOO, 0
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp __b1
|
||||
@ -401,30 +379,32 @@ Removing instruction jmp __bend
|
||||
Removing instruction jmp __b1
|
||||
Removing instruction jmp __breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Replacing label __bbegin with __b1
|
||||
Replacing label __b1_from___b1 with __b1
|
||||
Removing instruction __bbegin:
|
||||
Removing instruction __b1_from___bbegin:
|
||||
Removing instruction __bend_from___b1:
|
||||
Removing instruction __b1_from___b1:
|
||||
Succesful ASM optimization Pass5RedundantLabelElimination
|
||||
Removing instruction __b1:
|
||||
Removing instruction __bend:
|
||||
Removing instruction __b1_from_main:
|
||||
Removing instruction __breturn:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
Adding RTS to root block
|
||||
Succesful ASM optimization Pass5AddMainRts
|
||||
Updating BasicUpstart to call main directly
|
||||
Removing instruction jsr main
|
||||
Succesful ASM optimization Pass5SkipBegin
|
||||
Removing instruction jmp __b1
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Removing instruction __b1:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
(const struct foo) $0 = { thing1: (byte) 'a', thing2: (byte) 'b', thing3: (string) "qwe" }
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(const byte) OFFSET_STRUCT_FOO_THING2 = (byte) 1
|
||||
(const byte) OFFSET_STRUCT_FOO_THING3 = (byte) 2
|
||||
(const byte) SIZEOF_STRUCT_FOO = (byte) $e
|
||||
(struct foo) bar loadstore mem[14]
|
||||
(struct foo) bar loadstore mem[14] = { thing1: (byte) 'a', thing2: (byte) 'b', thing3: (string) "qwe" }
|
||||
(byte) foo::thing1
|
||||
(byte) foo::thing2
|
||||
(const byte*) foo::thing3[(number) $c] = { fill( $c, 0) }
|
||||
@ -446,34 +426,22 @@ mem[14] [ bar ]
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 270
|
||||
Score: 242
|
||||
|
||||
// File Comments
|
||||
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
|
||||
// Test a memory variable struct value - containing a fixed size array
|
||||
// Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(__bbegin)
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
.const SIZEOF_STRUCT_FOO = $e
|
||||
.const OFFSET_STRUCT_FOO_THING2 = 1
|
||||
.const OFFSET_STRUCT_FOO_THING3 = 2
|
||||
// @begin
|
||||
__bbegin:
|
||||
// bar = { 'a', 'b', "qwe" }
|
||||
// [0] *(&(struct foo) bar) ← memcpy(*(&(const struct foo) $0), struct foo, (const byte) SIZEOF_STRUCT_FOO) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
|
||||
ldy #SIZEOF_STRUCT_FOO
|
||||
!:
|
||||
lda __0-1,y
|
||||
sta bar-1,y
|
||||
dey
|
||||
bne !-
|
||||
// [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
|
||||
@ -517,9 +485,8 @@ main: {
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
__0: .byte 'a', 'b'
|
||||
bar: .byte 'a', 'b'
|
||||
.text "qwe"
|
||||
.byte 0
|
||||
.fill 8, 0
|
||||
bar: .fill SIZEOF_STRUCT_FOO, 0
|
||||
|
||||
|
@ -1,11 +1,9 @@
|
||||
(const struct foo) $0 = { thing1: (byte) 'a', thing2: (byte) 'b', thing3: (string) "qwe" }
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(const byte) OFFSET_STRUCT_FOO_THING2 = (byte) 1
|
||||
(const byte) OFFSET_STRUCT_FOO_THING3 = (byte) 2
|
||||
(const byte) SIZEOF_STRUCT_FOO = (byte) $e
|
||||
(struct foo) bar loadstore mem[14]
|
||||
(struct foo) bar loadstore mem[14] = { thing1: (byte) 'a', thing2: (byte) 'b', thing3: (string) "qwe" }
|
||||
(byte) foo::thing1
|
||||
(byte) foo::thing2
|
||||
(const byte*) foo::thing3[(number) $c] = { fill( $c, 0) }
|
||||
|
@ -1,19 +1,9 @@
|
||||
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
|
||||
// Test a memory variable struct value
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(__bbegin)
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
.const SIZEOF_STRUCT_FOO = 2
|
||||
.const OFFSET_STRUCT_FOO_THING2 = 1
|
||||
__bbegin:
|
||||
ldy #SIZEOF_STRUCT_FOO
|
||||
!:
|
||||
lda __0-1,y
|
||||
sta bar-1,y
|
||||
dey
|
||||
bne !-
|
||||
jsr main
|
||||
rts
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
lda bar
|
||||
@ -22,5 +12,4 @@ main: {
|
||||
sta SCREEN+1
|
||||
rts
|
||||
}
|
||||
__0: .byte 'a', 'b'
|
||||
bar: .fill SIZEOF_STRUCT_FOO, 0
|
||||
bar: .byte 'a', 'b'
|
||||
|
@ -1,5 +1,5 @@
|
||||
@begin: scope:[] from
|
||||
[0] *(&(struct foo) bar) ← memcpy(*(&(const struct foo) $0), struct foo, (const byte) SIZEOF_STRUCT_FOO)
|
||||
[0] phi()
|
||||
to:@1
|
||||
@1: scope:[] from @begin
|
||||
[1] phi()
|
||||
|
@ -1,10 +1,8 @@
|
||||
Adding struct value member variable copy *(&(struct foo) bar) ← memcpy(*(&(const struct foo) $0), struct foo, (const byte) SIZEOF_STRUCT_FOO)
|
||||
Replacing struct member reference (struct foo) bar.thing1 with member unwinding reference *((byte*)&(struct foo) bar+(const byte) OFFSET_STRUCT_FOO_THING1)
|
||||
Replacing struct member reference (struct foo) bar.thing2 with member unwinding reference *((byte*)&(struct foo) bar+(const byte) OFFSET_STRUCT_FOO_THING2)
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
@begin: scope:[] from
|
||||
*(&(struct foo) bar) ← memcpy(*(&(const struct foo) $0), struct foo, (const byte) SIZEOF_STRUCT_FOO)
|
||||
to:@1
|
||||
|
||||
(void()) main()
|
||||
@ -26,15 +24,13 @@ main::@return: scope:[main] from main
|
||||
@end: scope:[] from @2
|
||||
|
||||
SYMBOL TABLE SSA
|
||||
(const struct foo) $0 = { thing1: (byte) 'a', thing2: (byte) 'b' }
|
||||
(label) @1
|
||||
(label) @2
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(const byte) OFFSET_STRUCT_FOO_THING1 = (byte) 0
|
||||
(const byte) OFFSET_STRUCT_FOO_THING2 = (byte) 1
|
||||
(const byte) SIZEOF_STRUCT_FOO = (byte) 2
|
||||
(struct foo) bar loadstore
|
||||
(struct foo) bar loadstore = { thing1: (byte) 'a', thing2: (byte) 'b' }
|
||||
(byte) foo::thing1
|
||||
(byte) foo::thing2
|
||||
(void()) main()
|
||||
@ -49,13 +45,13 @@ Simplifying constant pointer cast (byte*) 1024
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Constant (const byte) main::i#0 = 0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Simplifying expression containing zero (byte*)&bar in [2] *((const byte*) main::SCREEN + (const byte) main::i#0) ← *((byte*)&(struct foo) bar+(const byte) OFFSET_STRUCT_FOO_THING1)
|
||||
Simplifying expression containing zero main::SCREEN in [2] *((const byte*) main::SCREEN + (const byte) main::i#0) ← *((byte*)&(struct foo) bar)
|
||||
Simplifying expression containing zero (byte*)&bar in [1] *((const byte*) main::SCREEN + (const byte) main::i#0) ← *((byte*)&(struct foo) bar+(const byte) OFFSET_STRUCT_FOO_THING1)
|
||||
Simplifying expression containing zero main::SCREEN in [1] *((const byte*) main::SCREEN + (const byte) main::i#0) ← *((byte*)&(struct foo) bar)
|
||||
Successful SSA optimization PassNSimplifyExpressionWithZero
|
||||
Eliminating unused variable (byte) main::i#2 and assignment [4] (byte) main::i#2 ← ++ (byte) main::i#1
|
||||
Eliminating unused variable (byte) main::i#2 and assignment [3] (byte) main::i#2 ← ++ (byte) main::i#1
|
||||
Eliminating unused constant (const byte) OFFSET_STRUCT_FOO_THING1
|
||||
Successful SSA optimization PassNEliminateUnusedVars
|
||||
Constant right-side identified [2] (byte) main::i#1 ← ++ (const byte) main::i#0
|
||||
Constant right-side identified [1] (byte) main::i#1 ← ++ (const byte) main::i#0
|
||||
Successful SSA optimization Pass2ConstantRValueConsolidation
|
||||
Constant (const byte) main::i#1 = ++main::i#0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
@ -68,6 +64,7 @@ Consolidated array index constant in *(main::SCREEN+++0)
|
||||
Successful SSA optimization Pass2ConstantAdditionElimination
|
||||
Simplifying constant integer increment ++0
|
||||
Successful SSA optimization Pass2ConstantSimplification
|
||||
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
|
||||
@ -77,12 +74,13 @@ 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] *(&(struct foo) bar) ← memcpy(*(&(const struct foo) $0), struct foo, (const byte) SIZEOF_STRUCT_FOO)
|
||||
[0] phi()
|
||||
to:@1
|
||||
@1: scope:[] from @begin
|
||||
[1] phi()
|
||||
@ -102,7 +100,7 @@ main::@return: scope:[main] from main
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
(struct foo) bar loadstore
|
||||
(struct foo) bar loadstore = { thing1: (byte) 'a', thing2: (byte) 'b' }
|
||||
(byte) foo::thing1
|
||||
(byte) foo::thing2
|
||||
(void()) main()
|
||||
@ -124,17 +122,9 @@ Target platform is c64basic / MOS6502X
|
||||
:BasicUpstart(__bbegin)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
.const SIZEOF_STRUCT_FOO = 2
|
||||
.const OFFSET_STRUCT_FOO_THING2 = 1
|
||||
// @begin
|
||||
__bbegin:
|
||||
// [0] *(&(struct foo) bar) ← memcpy(*(&(const struct foo) $0), struct foo, (const byte) SIZEOF_STRUCT_FOO) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
|
||||
ldy #SIZEOF_STRUCT_FOO
|
||||
!:
|
||||
lda __0-1,y
|
||||
sta bar-1,y
|
||||
dey
|
||||
bne !-
|
||||
// [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
__b1_from___bbegin:
|
||||
jmp __b1
|
||||
@ -163,11 +153,9 @@ main: {
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
__0: .byte 'a', 'b'
|
||||
bar: .fill SIZEOF_STRUCT_FOO, 0
|
||||
bar: .byte 'a', 'b'
|
||||
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [0] *(&(struct foo) bar) ← memcpy(*(&(const struct foo) $0), struct foo, (const byte) SIZEOF_STRUCT_FOO) [ bar ] ( [ bar ] ) always clobbers reg byte a reg byte y
|
||||
Statement [4] *((const byte*) main::SCREEN) ← *((byte*)&(struct foo) bar) [ bar ] ( main:2 [ bar ] ) always clobbers reg byte a
|
||||
Statement [5] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)&(struct foo) bar+(const byte) OFFSET_STRUCT_FOO_THING2) [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||
Potential registers mem[2] [ bar ] : mem[2] ,
|
||||
@ -177,9 +165,9 @@ Uplift Scope [foo]
|
||||
Uplift Scope [main]
|
||||
Uplift Scope [] 0: mem[2] [ bar ]
|
||||
|
||||
Uplifting [foo] best 53 combination
|
||||
Uplifting [main] best 53 combination
|
||||
Uplifting [] best 53 combination mem[2] [ bar ]
|
||||
Uplifting [foo] best 37 combination
|
||||
Uplifting [main] best 37 combination
|
||||
Uplifting [] best 37 combination mem[2] [ bar ]
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
// File Comments
|
||||
@ -190,17 +178,9 @@ ASSEMBLER BEFORE OPTIMIZATION
|
||||
:BasicUpstart(__bbegin)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
.const SIZEOF_STRUCT_FOO = 2
|
||||
.const OFFSET_STRUCT_FOO_THING2 = 1
|
||||
// @begin
|
||||
__bbegin:
|
||||
// [0] *(&(struct foo) bar) ← memcpy(*(&(const struct foo) $0), struct foo, (const byte) SIZEOF_STRUCT_FOO) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
|
||||
ldy #SIZEOF_STRUCT_FOO
|
||||
!:
|
||||
lda __0-1,y
|
||||
sta bar-1,y
|
||||
dey
|
||||
bne !-
|
||||
// [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
__b1_from___bbegin:
|
||||
jmp __b1
|
||||
@ -229,32 +209,33 @@ main: {
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
__0: .byte 'a', 'b'
|
||||
bar: .fill SIZEOF_STRUCT_FOO, 0
|
||||
bar: .byte 'a', 'b'
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp __b1
|
||||
Removing instruction jmp __bend
|
||||
Removing instruction jmp __breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Replacing label __bbegin with __b1
|
||||
Removing instruction __bbegin:
|
||||
Removing instruction __b1_from___bbegin:
|
||||
Removing instruction __bend_from___b1:
|
||||
Succesful ASM optimization Pass5RedundantLabelElimination
|
||||
Removing instruction __b1:
|
||||
Removing instruction __bend:
|
||||
Removing instruction __breturn:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
Adding RTS to root block
|
||||
Succesful ASM optimization Pass5AddMainRts
|
||||
Updating BasicUpstart to call main directly
|
||||
Removing instruction jsr main
|
||||
Succesful ASM optimization Pass5SkipBegin
|
||||
Removing instruction __b1:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
(const struct foo) $0 = { thing1: (byte) 'a', thing2: (byte) 'b' }
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(const byte) OFFSET_STRUCT_FOO_THING2 = (byte) 1
|
||||
(const byte) SIZEOF_STRUCT_FOO = (byte) 2
|
||||
(struct foo) bar loadstore mem[2]
|
||||
(struct foo) bar loadstore mem[2] = { thing1: (byte) 'a', thing2: (byte) 'b' }
|
||||
(byte) foo::thing1
|
||||
(byte) foo::thing2
|
||||
(void()) main()
|
||||
@ -266,33 +247,21 @@ mem[2] [ bar ]
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 50
|
||||
Score: 22
|
||||
|
||||
// File Comments
|
||||
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
|
||||
// Test a memory variable struct value
|
||||
// Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(__bbegin)
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
.const SIZEOF_STRUCT_FOO = 2
|
||||
.const OFFSET_STRUCT_FOO_THING2 = 1
|
||||
// @begin
|
||||
__bbegin:
|
||||
// bar = { 'a', 'b' }
|
||||
// [0] *(&(struct foo) bar) ← memcpy(*(&(const struct foo) $0), struct foo, (const byte) SIZEOF_STRUCT_FOO) -- _deref_pssc1=_deref_pssc2_memcpy_vbuc3
|
||||
ldy #SIZEOF_STRUCT_FOO
|
||||
!:
|
||||
lda __0-1,y
|
||||
sta bar-1,y
|
||||
dey
|
||||
bne !-
|
||||
// [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
|
||||
@ -312,6 +281,5 @@ main: {
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
__0: .byte 'a', 'b'
|
||||
bar: .fill SIZEOF_STRUCT_FOO, 0
|
||||
bar: .byte 'a', 'b'
|
||||
|
||||
|
@ -1,10 +1,8 @@
|
||||
(const struct foo) $0 = { thing1: (byte) 'a', thing2: (byte) 'b' }
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(const byte) OFFSET_STRUCT_FOO_THING2 = (byte) 1
|
||||
(const byte) SIZEOF_STRUCT_FOO = (byte) 2
|
||||
(struct foo) bar loadstore mem[2]
|
||||
(struct foo) bar loadstore mem[2] = { thing1: (byte) 'a', thing2: (byte) 'b' }
|
||||
(byte) foo::thing1
|
||||
(byte) foo::thing2
|
||||
(void()) main()
|
||||
|
Loading…
Reference in New Issue
Block a user