1
0
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:
jespergravgaard 2020-01-11 13:39:10 +01:00
parent 030a379845
commit 2eb5aaa24f
19 changed files with 162 additions and 254 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -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();

View File

@ -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 {

View File

@ -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
View 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;
}

View File

@ -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'

View File

@ -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()

View File

@ -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'

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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) }

View File

@ -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'

View File

@ -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()

View File

@ -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'

View File

@ -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()