1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-12-20 07:30:00 +00:00

Preventing double imports. Closes #102

This commit is contained in:
jespergravgaard 2017-12-02 16:56:58 +01:00
parent 41fd3bc436
commit 9c39311d67
8 changed files with 612 additions and 54 deletions

View File

@ -19,8 +19,7 @@ public class Compiler {
private Program program; private Program program;
public Compiler() { public Compiler() {
this.program = new Program(new ProgramScope(), new CompileLog()); this.program = new Program();
this.program.setImportPaths(new ArrayList<>());
} }
public CompileLog getLog() { public CompileLog getLog() {
@ -57,7 +56,14 @@ public class Compiler {
} }
public static void loadAndParseFile(String fileName, Program program, StatementSequenceGenerator statementSequenceGenerator) { public static void loadAndParseFile(String fileName, Program program, StatementSequenceGenerator statementSequenceGenerator) {
CharStream fileStream = loadFile(fileName, program); try {
File file = loadFile(fileName, program);
List<String> imported = program.getImported();
if (imported.contains(file.getAbsolutePath())) {
return;
}
final CharStream fileStream = CharStreams.fromPath(file.toPath());
imported.add(file.getAbsolutePath());
program.getLog().append(fileStream.toString()); program.getLog().append(fileStream.toString());
KickCLexer lexer = new KickCLexer(fileStream); KickCLexer lexer = new KickCLexer(fileStream);
KickCParser parser = new KickCParser(new CommonTokenStream(lexer)); KickCParser parser = new KickCParser(new CommonTokenStream(lexer));
@ -75,13 +81,15 @@ public class Compiler {
} }
}); });
statementSequenceGenerator.generate(parser.file()); statementSequenceGenerator.generate(parser.file());
} catch (IOException e) {
throw new CompileError("Error loading file " + fileName, e);
}
} }
private static CharStream loadFile(String fileName, Program program) { private static File loadFile(String fileName, Program program) {
if (!fileName.endsWith(".kc")) { if (!fileName.endsWith(".kc")) {
fileName += ".kc"; fileName += ".kc";
} }
try {
List<String> importPaths = program.getImportPaths(); List<String> importPaths = program.getImportPaths();
for (String importPath : importPaths) { for (String importPath : importPaths) {
if (!importPath.endsWith("/")) { if (!importPath.endsWith("/")) {
@ -90,12 +98,9 @@ public class Compiler {
String filePath = importPath + fileName; String filePath = importPath + fileName;
File file = new File(filePath); File file = new File(filePath);
if (file.exists()) { if (file.exists()) {
return CharStreams.fromPath(file.toPath()); return file;
} }
} }
} catch (IOException e) {
throw new CompileError("Error loading file " + fileName, e);
}
throw new CompileError("File not found " + fileName); throw new CompileError("File not found " + fileName);
} }

View File

@ -1,10 +1,9 @@
package dk.camelot64.kickc.model; package dk.camelot64.kickc.model;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import dk.camelot64.kickc.CompileLog; import dk.camelot64.kickc.CompileLog;
import dk.camelot64.kickc.asm.AsmProgram; import dk.camelot64.kickc.asm.AsmProgram;
import java.util.ArrayList;
import java.util.List; import java.util.List;
/** A KickC Intermediate Compiler Language (ICL) Program */ /** A KickC Intermediate Compiler Language (ICL) Program */
@ -12,6 +11,8 @@ public class Program {
/** Paths used for importing files. */ /** Paths used for importing files. */
private List<String> importPaths; private List<String> importPaths;
/** Imported files. */
private List<String> imported;
/** The initial statement sequence generated byt the parser. */ /** The initial statement sequence generated byt the parser. */
private StatementSequence statementSequence; private StatementSequence statementSequence;
/** The main scope. */ /** The main scope. */
@ -52,27 +53,19 @@ public class Program {
/** Separation of live range equivalence classes into scopes - used for register uplift */ /** Separation of live range equivalence classes into scopes - used for register uplift */
private RegisterUpliftProgram registerUpliftProgram; private RegisterUpliftProgram registerUpliftProgram;
@JsonCreator public Program() {
public Program( this.scope = new ProgramScope();
@JsonProperty("scope") ProgramScope scope, this.log = new CompileLog();
@JsonProperty("graph") ControlFlowGraph graph, this.importPaths = new ArrayList<>();
@JsonProperty("asm") AsmProgram asm) { this.imported = new ArrayList<>();
this.scope = scope;
this.graph = graph;
this.asm = asm;
}
public Program(ProgramScope programScope, CompileLog log) {
this.scope = programScope;
this.log = log;
} }
public List<String> getImportPaths() { public List<String> getImportPaths() {
return importPaths; return importPaths;
} }
public void setImportPaths(List<String> importPaths) { public List<String> getImported() {
this.importPaths = importPaths; return imported;
} }
public StatementSequence getStatementSequence() { public StatementSequence getStatementSequence() {

View File

@ -24,6 +24,10 @@ public class TestPrograms extends TestCase {
helper = new ReferenceHelper("dk/camelot64/kickc/test/ref/"); helper = new ReferenceHelper("dk/camelot64/kickc/test/ref/");
} }
public void testDoubleImport() throws IOException, URISyntaxException {
compileAndCompare("double-import");
}
public void testImporting() throws IOException, URISyntaxException { public void testImporting() throws IOException, URISyntaxException {
compileAndCompare("importing"); compileAndCompare("importing");
} }

View File

@ -0,0 +1,6 @@
import "imported"
import "imported"
void main() {
*BGCOL = RED;
}

View File

@ -0,0 +1,11 @@
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.const BGCOL = $d021
.const RED = 2
jsr main
main: {
lda #RED
sta BGCOL
rts
}

View File

@ -0,0 +1,15 @@
@begin: scope:[] from
[0] phi() [ ] ( )
to:@1
@1: scope:[] from @begin
[1] phi() [ ] ( )
[2] call main param-assignment [ ] ( )
to:@end
@end: scope:[] from @1
[3] phi() [ ] ( )
main: scope:[main] from @1
[4] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ] ( main:2 [ ] )
to:main::@return
main::@return: scope:[main] from main
[5] return [ ] ( main:2 [ ] )
to:@return

View File

@ -0,0 +1,514 @@
import "imported"
import "imported"
void main() {
*BGCOL = RED;
}
Importing imported
const byte *BGCOL = $d021;
const byte RED = 2;
Importing imported
PROGRAM
(byte*) BGCOL ← (word) 53281
(byte) RED ← (byte/signed byte/word/signed word) 2
proc (void()) main()
*((byte*) BGCOL) ← (byte) RED
main::@return:
return
endproc // main()
call main
SYMBOLS
(byte*) BGCOL
(byte) RED
(void()) main()
(label) main::@return
Promoting word to byte* in BGCOL ← ((byte*)) 53281
INITIAL CONTROL FLOW GRAPH
@begin: scope:[] from
(byte*) BGCOL ← ((byte*)) (word) 53281
(byte) RED ← (byte/signed byte/word/signed word) 2
to:@1
main: scope:[main] from
*((byte*) BGCOL) ← (byte) RED
to:main::@return
main::@return: scope:[main] from main
return
to:@return
@1: scope:[] from @begin
call main
to:@end
@end: scope:[] from @1
CONTROL FLOW GRAPH
@begin: scope:[] from
(byte*) BGCOL ← ((byte*)) (word) 53281
(byte) RED ← (byte/signed byte/word/signed word) 2
to:@1
main: scope:[main] from
*((byte*) BGCOL) ← (byte) RED
to:main::@return
main::@return: scope:[main] from main
return
to:@return
@1: scope:[] from @begin
call main
to:@end
@end: scope:[] from @1
PROCEDURE MODIFY VARIABLE ANALYSIS
CONTROL FLOW GRAPH WITH ASSIGNMENT CALL
@begin: scope:[] from
(byte*) BGCOL ← ((byte*)) (word) 53281
(byte) RED ← (byte/signed byte/word/signed word) 2
to:@1
main: scope:[main] from @1
*((byte*) BGCOL) ← (byte) RED
to:main::@return
main::@return: scope:[main] from main
return
to:@return
@1: scope:[] from @begin
call main param-assignment
to:@2
@2: scope:[] from @1
to:@end
@end: scope:[] from @2
Completing Phi functions...
Completing Phi functions...
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(byte*) BGCOL#0 ← ((byte*)) (word) 53281
(byte) RED#0 ← (byte/signed byte/word/signed word) 2
to:@1
main: scope:[main] from @1
(byte*) BGCOL#1 ← phi( @1/(byte*) BGCOL#2 )
(byte) RED#1 ← phi( @1/(byte) RED#2 )
*((byte*) BGCOL#1) ← (byte) RED#1
to:main::@return
main::@return: scope:[main] from main
return
to:@return
@1: scope:[] from @begin
(byte*) BGCOL#2 ← phi( @begin/(byte*) BGCOL#0 )
(byte) RED#2 ← phi( @begin/(byte) RED#0 )
call main param-assignment
to:@2
@2: scope:[] from @1
to:@end
@end: scope:[] from @2
CONTROL FLOW GRAPH WITH ASSIGNMENT CALL & RETURN
@begin: scope:[] from
(byte*) BGCOL#0 ← ((byte*)) (word) 53281
(byte) RED#0 ← (byte/signed byte/word/signed word) 2
to:@1
main: scope:[main] from @1
(byte*) BGCOL#1 ← phi( @1/(byte*) BGCOL#2 )
(byte) RED#1 ← phi( @1/(byte) RED#2 )
*((byte*) BGCOL#1) ← (byte) RED#1
to:main::@return
main::@return: scope:[main] from main
return
to:@return
@1: scope:[] from @begin
(byte*) BGCOL#2 ← phi( @begin/(byte*) BGCOL#0 )
(byte) RED#2 ← phi( @begin/(byte) RED#0 )
call main param-assignment
to:@2
@2: scope:[] from @1
to:@end
@end: scope:[] from @2
INITIAL SSA SYMBOL TABLE
(label) @1
(label) @2
(label) @begin
(label) @end
(byte*) BGCOL
(byte*) BGCOL#0
(byte*) BGCOL#1
(byte*) BGCOL#2
(byte) RED
(byte) RED#0
(byte) RED#1
(byte) RED#2
(void()) main()
(label) main::@return
Culled Empty Block (label) @2
Succesful SSA optimization Pass2CullEmptyBlocks
CONTROL FLOW GRAPH
@begin: scope:[] from
(byte*) BGCOL#0 ← ((byte*)) (word) 53281
(byte) RED#0 ← (byte/signed byte/word/signed word) 2
to:@1
main: scope:[main] from @1
(byte*) BGCOL#1 ← phi( @1/(byte*) BGCOL#2 )
(byte) RED#1 ← phi( @1/(byte) RED#2 )
*((byte*) BGCOL#1) ← (byte) RED#1
to:main::@return
main::@return: scope:[main] from main
return
to:@return
@1: scope:[] from @begin
(byte*) BGCOL#2 ← phi( @begin/(byte*) BGCOL#0 )
(byte) RED#2 ← phi( @begin/(byte) RED#0 )
call main param-assignment
to:@end
@end: scope:[] from @1
Not aliassing across scopes: RED#1 RED#2
Not aliassing across scopes: BGCOL#1 BGCOL#2
Alias (byte) RED#0 = (byte) RED#2
Alias (byte*) BGCOL#0 = (byte*) BGCOL#2
Succesful SSA optimization Pass2AliasElimination
CONTROL FLOW GRAPH
@begin: scope:[] from
(byte*) BGCOL#0 ← ((byte*)) (word) 53281
(byte) RED#0 ← (byte/signed byte/word/signed word) 2
to:@1
main: scope:[main] from @1
(byte*) BGCOL#1 ← phi( @1/(byte*) BGCOL#0 )
(byte) RED#1 ← phi( @1/(byte) RED#0 )
*((byte*) BGCOL#1) ← (byte) RED#1
to:main::@return
main::@return: scope:[main] from main
return
to:@return
@1: scope:[] from @begin
call main param-assignment
to:@end
@end: scope:[] from @1
Not aliassing across scopes: RED#1 RED#0
Not aliassing across scopes: BGCOL#1 BGCOL#0
Redundant Phi (byte) RED#1 (byte) RED#0
Redundant Phi (byte*) BGCOL#1 (byte*) BGCOL#0
Succesful SSA optimization Pass2RedundantPhiElimination
CONTROL FLOW GRAPH
@begin: scope:[] from
(byte*) BGCOL#0 ← ((byte*)) (word) 53281
(byte) RED#0 ← (byte/signed byte/word/signed word) 2
to:@1
main: scope:[main] from @1
*((byte*) BGCOL#0) ← (byte) RED#0
to:main::@return
main::@return: scope:[main] from main
return
to:@return
@1: scope:[] from @begin
call main param-assignment
to:@end
@end: scope:[] from @1
Constant (const byte*) BGCOL#0 = ((byte*))53281
Constant (const byte) RED#0 = 2
Succesful SSA optimization Pass2ConstantIdentification
CONTROL FLOW GRAPH
@begin: scope:[] from
to:@1
main: scope:[main] from @1
*((const byte*) BGCOL#0) ← (const byte) RED#0
to:main::@return
main::@return: scope:[main] from main
return
to:@return
@1: scope:[] from @begin
call main param-assignment
to:@end
@end: scope:[] from @1
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(byte*) BGCOL
(const byte*) BGCOL#0 = ((byte*))(word) 53281
(byte) RED
(const byte) RED#0 = (byte/signed byte/word/signed word) 2
(void()) main()
(label) main::@return
Block Sequence Planned @begin @1 @end main main::@return
Block Sequence Planned @begin @1 @end main main::@return
CONTROL FLOW GRAPH - PHI LIFTED
@begin: scope:[] from
to:@1
@1: scope:[] from @begin
call main param-assignment
to:@end
@end: scope:[] from @1
main: scope:[main] from @1
*((const byte*) BGCOL#0) ← (const byte) RED#0
to:main::@return
main::@return: scope:[main] from main
return
to:@return
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
CALL GRAPH
Calls in [] to main:2
Propagating live ranges...
CONTROL FLOW GRAPH - LIVE RANGES FOUND
@begin: scope:[] from
[0] phi() [ ]
to:@1
@1: scope:[] from @begin
[1] phi() [ ]
[2] call main param-assignment [ ]
to:@end
@end: scope:[] from @1
[3] phi() [ ]
main: scope:[main] from @1
[4] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ]
to:main::@return
main::@return: scope:[main] from main
[5] return [ ]
to:@return
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
Block Sequence Planned @begin @1 @end main main::@return
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
Propagating live ranges...
CONTROL FLOW GRAPH - BEFORE EFFECTIVE LIVE RANGES
@begin: scope:[] from
[0] phi() [ ]
to:@1
@1: scope:[] from @begin
[1] phi() [ ]
[2] call main param-assignment [ ]
to:@end
@end: scope:[] from @1
[3] phi() [ ]
main: scope:[main] from @1
[4] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ]
to:main::@return
main::@return: scope:[main] from main
[5] return [ ]
to:@return
CONTROL FLOW GRAPH - PHI MEM COALESCED
@begin: scope:[] from
[0] phi() [ ] ( )
to:@1
@1: scope:[] from @begin
[1] phi() [ ] ( )
[2] call main param-assignment [ ] ( )
to:@end
@end: scope:[] from @1
[3] phi() [ ] ( )
main: scope:[main] from @1
[4] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ] ( main:2 [ ] )
to:main::@return
main::@return: scope:[main] from main
[5] return [ ] ( main:2 [ ] )
to:@return
DOMINATORS
@begin dominated by @begin
@1 dominated by @1 @begin
@end dominated by @1 @begin @end
main dominated by @1 @begin main
main::@return dominated by main::@return @1 @begin main
NATURAL LOOPS
Found 0 loops in scope []
Found 0 loops in scope [main]
NATURAL LOOPS WITH DEPTH
VARIABLE REGISTER WEIGHTS
(byte*) BGCOL
(byte) RED
(void()) main()
Initial phi equivalence classes
Complete equivalence classes
INITIAL ASM
//SEG0 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
//SEG1 Global Constants & labels
.const BGCOL = $d021
.const RED = 2
//SEG2 @begin
bbegin:
//SEG3 [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
//SEG4 @1
b1:
//SEG5 [2] call main param-assignment [ ] ( )
jsr main
//SEG6 [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
//SEG7 @end
bend:
//SEG8 main
main: {
//SEG9 [4] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ] ( main:2 [ ] ) -- _deref_cowo1=coby2
lda #RED
sta BGCOL
jmp breturn
//SEG10 main::@return
breturn:
//SEG11 [5] return [ ] ( main:2 [ ] )
rts
}
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [4] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ] ( main:2 [ ] ) always clobbers reg byte a
REGISTER UPLIFT SCOPES
Uplift Scope [main]
Uplift Scope []
Uplifting [main] best 27 combination
Uplifting [] best 27 combination
Removing instruction jmp b1
Removing instruction jmp bend
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
ASSEMBLER
//SEG0 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
//SEG1 Global Constants & labels
.const BGCOL = $d021
.const RED = 2
//SEG2 @begin
bbegin:
//SEG3 [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
//SEG4 @1
b1:
//SEG5 [2] call main param-assignment [ ] ( )
jsr main
//SEG6 [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
//SEG7 @end
bend:
//SEG8 main
main: {
//SEG9 [4] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ] ( main:2 [ ] ) -- _deref_cowo1=coby2
lda #RED
sta BGCOL
//SEG10 main::@return
breturn:
//SEG11 [5] return [ ] ( main:2 [ ] )
rts
}
Removing instruction bbegin:
Removing instruction b1_from_bbegin:
Removing instruction bend_from_b1:
Succesful ASM optimization Pass5RedundantLabelElimination
ASSEMBLER
//SEG0 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
//SEG1 Global Constants & labels
.const BGCOL = $d021
.const RED = 2
//SEG2 @begin
//SEG3 [1] phi from @begin to @1 [phi:@begin->@1]
//SEG4 @1
b1:
//SEG5 [2] call main param-assignment [ ] ( )
jsr main
//SEG6 [3] phi from @1 to @end [phi:@1->@end]
//SEG7 @end
bend:
//SEG8 main
main: {
//SEG9 [4] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ] ( main:2 [ ] ) -- _deref_cowo1=coby2
lda #RED
sta BGCOL
//SEG10 main::@return
breturn:
//SEG11 [5] return [ ] ( main:2 [ ] )
rts
}
Removing instruction b1:
Removing instruction bend:
Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
ASSEMBLER
//SEG0 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
//SEG1 Global Constants & labels
.const BGCOL = $d021
.const RED = 2
//SEG2 @begin
//SEG3 [1] phi from @begin to @1 [phi:@begin->@1]
//SEG4 @1
//SEG5 [2] call main param-assignment [ ] ( )
jsr main
//SEG6 [3] phi from @1 to @end [phi:@1->@end]
//SEG7 @end
//SEG8 main
main: {
//SEG9 [4] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ] ( main:2 [ ] ) -- _deref_cowo1=coby2
lda #RED
sta BGCOL
//SEG10 main::@return
//SEG11 [5] return [ ] ( main:2 [ ] )
rts
}
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(byte*) BGCOL
(const byte*) BGCOL#0 BGCOL = ((byte*))(word) 53281
(byte) RED
(const byte) RED#0 RED = (byte/signed byte/word/signed word) 2
(void()) main()
(label) main::@return
FINAL CODE
//SEG0 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
//SEG1 Global Constants & labels
.const BGCOL = $d021
.const RED = 2
//SEG2 @begin
//SEG3 [1] phi from @begin to @1 [phi:@begin->@1]
//SEG4 @1
//SEG5 [2] call main param-assignment [ ] ( )
jsr main
//SEG6 [3] phi from @1 to @end [phi:@1->@end]
//SEG7 @end
//SEG8 main
main: {
//SEG9 [4] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ] ( main:2 [ ] ) -- _deref_cowo1=coby2
lda #RED
sta BGCOL
//SEG10 main::@return
//SEG11 [5] return [ ] ( main:2 [ ] )
rts
}

View File

@ -0,0 +1,10 @@
(label) @1
(label) @begin
(label) @end
(byte*) BGCOL
(const byte*) BGCOL#0 BGCOL = ((byte*))(word) 53281
(byte) RED
(const byte) RED#0 RED = (byte/signed byte/word/signed word) 2
(void()) main()
(label) main::@return