1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-01-27 06:34:19 +00:00

Added hash and lastModified check to the fragment synthesis cache. Location of cache changed to always be inside fragments-folder. Cache is enabled by default and can be disabled by command-line switch. #469

This commit is contained in:
jespergravgaard 2020-06-02 23:28:32 +02:00
parent 558e19f47f
commit b73601f483
11 changed files with 323 additions and 241 deletions

View File

@ -1,113 +1,4 @@
//FRAGMENT vbuz1=vbuc1 //KICKC FRAGMENT CACHE 1a8109f402
lda #{c1}
sta {z1}
//FRAGMENT vbuz1_lt_vbuc1_then_la1
lda {z1}
cmp #{c1}
bcc {la1}
//FRAGMENT pbuc1_derefidx_vbuz1=vbuc2
lda #{c2}
ldy {z1}
sta {c1},y
//FRAGMENT vbuz1=vbuz2_band_vbuc1
lda #{c1}
and {z2}
sta {z1}
//FRAGMENT vbuz1_neq_0_then_la1
lda {z1}
cmp #0
bne {la1}
//FRAGMENT vbuz1=vbuz1_plus_vbuc1
lda #{c1}
clc
adc {z1}
sta {z1}
//FRAGMENT vbuz1=_inc_vbuz1
inc {z1}
//FRAGMENT vbuaa_lt_vbuc1_then_la1
cmp #{c1}
bcc {la1}
//FRAGMENT pbuc1_derefidx_vbuaa=vbuc2
tay
lda #{c2}
sta {c1},y
//FRAGMENT pbuc1_derefidx_vbuxx=vbuc2
lda #{c2}
sta {c1},x
//FRAGMENT pbuc1_derefidx_vbuyy=vbuc2
lda #{c2}
sta {c1},y
//FRAGMENT vbuaa=vbuz1_band_vbuc1
lda #{c1}
and {z1}
//FRAGMENT vbuxx=vbuz1_band_vbuc1
lda #{c1}
and {z1}
tax
//FRAGMENT vbuyy=vbuz1_band_vbuc1
lda #{c1}
and {z1}
tay
//FRAGMENT vbuz1=vbuxx_band_vbuc1
txa
and #{c1}
sta {z1}
//FRAGMENT vbuaa=vbuxx_band_vbuc1
txa
and #{c1}
//FRAGMENT vbuxx=vbuxx_band_vbuc1
txa
and #{c1}
tax
//FRAGMENT vbuyy=vbuxx_band_vbuc1
txa
and #{c1}
tay
//FRAGMENT vbuz1=vbuyy_band_vbuc1
tya
and #{c1}
sta {z1}
//FRAGMENT vbuaa=vbuyy_band_vbuc1
tya
and #{c1}
//FRAGMENT vbuxx=vbuyy_band_vbuc1
tya
and #{c1}
tax
//FRAGMENT vbuyy=vbuyy_band_vbuc1
tya
and #{c1}
tay
//FRAGMENT vbuaa_neq_0_then_la1
cmp #0
bne {la1}
//FRAGMENT vbuxx=vbuxx_plus_vbuc1
txa
clc
adc #{c1}
tax
//FRAGMENT vbuyy=vbuyy_plus_vbuc1
tya
clc
adc #{c1}
tay
//FRAGMENT vbuxx_lt_vbuc1_then_la1
cpx #{c1}
bcc {la1}
//FRAGMENT vbuxx=vbuc1
ldx #{c1}
//FRAGMENT vbuxx=_inc_vbuxx
inx
//FRAGMENT vbuyy=vbuc1
ldy #{c1}
//FRAGMENT vbuyy_lt_vbuc1_then_la1
cpy #{c1}
bcc {la1}
//FRAGMENT vbuyy=_inc_vbuyy
iny
//FRAGMENT vbuxx_neq_0_then_la1
cpx #0
bne {la1}
//FRAGMENT _deref_pbuc1=vbuc2 //FRAGMENT _deref_pbuc1=vbuc2
lda #{c2} lda #{c2}
sta {c1} sta {c1}
@ -119,6 +10,15 @@ sta {z1}
lda #{c1} lda #{c1}
cmp {z1} cmp {z1}
beq {la1} beq {la1}
//FRAGMENT vbuz1=vbuc1
lda #{c1}
sta {z1}
//FRAGMENT pbuc1_derefidx_vbuz1=vbuc2
lda #{c2}
ldy {z1}
sta {c1},y
//FRAGMENT vbuz1=_inc_vbuz1
inc {z1}
//FRAGMENT vbuc1_neq_vbuz1_then_la1 //FRAGMENT vbuc1_neq_vbuz1_then_la1
lda #{c1} lda #{c1}
cmp {z1} cmp {z1}
@ -138,6 +38,10 @@ lda #<{c1}
sta {z1} sta {z1}
lda #>{c1} lda #>{c1}
sta {z1}+1 sta {z1}+1
//FRAGMENT vbuz1_lt_vbuc1_then_la1
lda {z1}
cmp #{c1}
bcc {la1}
//FRAGMENT pbuz1=pbuc1 //FRAGMENT pbuz1=pbuc1
lda #<{c1} lda #<{c1}
sta {z1} sta {z1}
@ -229,6 +133,10 @@ bcc {la1}
//FRAGMENT vbuz1=vbuz2 //FRAGMENT vbuz1=vbuz2
lda {z2} lda {z2}
sta {z1} sta {z1}
//FRAGMENT vbuz1=vbuz2_band_vbuc1
lda #{c1}
and {z2}
sta {z1}
//FRAGMENT _deref_pbuc1=_inc__deref_pbuc1 //FRAGMENT _deref_pbuc1=_inc__deref_pbuc1
inc {c1} inc {c1}
//FRAGMENT _deref_pbuc1=_dec__deref_pbuc1 //FRAGMENT _deref_pbuc1=_dec__deref_pbuc1
@ -255,9 +163,22 @@ tay
//FRAGMENT vbuc1_eq_vbuaa_then_la1 //FRAGMENT vbuc1_eq_vbuaa_then_la1
cmp #{c1} cmp #{c1}
beq {la1} beq {la1}
//FRAGMENT pbuc1_derefidx_vbuaa=vbuc2
tay
lda #{c2}
sta {c1},y
//FRAGMENT pbuc1_derefidx_vbuxx=vbuc2
lda #{c2}
sta {c1},x
//FRAGMENT pbuc1_derefidx_vbuyy=vbuc2
lda #{c2}
sta {c1},y
//FRAGMENT vbuc1_neq_vbuxx_then_la1 //FRAGMENT vbuc1_neq_vbuxx_then_la1
cpx #{c1} cpx #{c1}
bne {la1} bne {la1}
//FRAGMENT vbuaa_lt_vbuc1_then_la1
cmp #{c1}
bcc {la1}
//FRAGMENT pbuz1=pbuc1_plus_vbuaa //FRAGMENT pbuz1=pbuc1_plus_vbuaa
clc clc
adc #<{c1} adc #<{c1}
@ -335,14 +256,55 @@ ldx {z1}
//FRAGMENT vbuz1=vbuaa_band_vbuc1 //FRAGMENT vbuz1=vbuaa_band_vbuc1
and #{c1} and #{c1}
sta {z1} sta {z1}
//FRAGMENT vbuz1=vbuxx_band_vbuc1
txa
and #{c1}
sta {z1}
//FRAGMENT vbuz1=vbuyy_band_vbuc1
tya
and #{c1}
sta {z1}
//FRAGMENT vbuaa=vbuz1_band_vbuc1
lda #{c1}
and {z1}
//FRAGMENT vbuaa=vbuaa_band_vbuc1 //FRAGMENT vbuaa=vbuaa_band_vbuc1
and #{c1} and #{c1}
//FRAGMENT vbuaa=vbuxx_band_vbuc1
txa
and #{c1}
//FRAGMENT vbuaa=vbuyy_band_vbuc1
tya
and #{c1}
//FRAGMENT vbuxx=vbuz1_band_vbuc1
lda #{c1}
and {z1}
tax
//FRAGMENT vbuxx=vbuaa_band_vbuc1 //FRAGMENT vbuxx=vbuaa_band_vbuc1
and #{c1} and #{c1}
tax tax
//FRAGMENT vbuxx=vbuxx_band_vbuc1
txa
and #{c1}
tax
//FRAGMENT vbuxx=vbuyy_band_vbuc1
tya
and #{c1}
tax
//FRAGMENT vbuyy=vbuz1_band_vbuc1
lda #{c1}
and {z1}
tay
//FRAGMENT vbuyy=vbuaa_band_vbuc1 //FRAGMENT vbuyy=vbuaa_band_vbuc1
and #{c1} and #{c1}
tay tay
//FRAGMENT vbuyy=vbuxx_band_vbuc1
txa
and #{c1}
tay
//FRAGMENT vbuyy=vbuyy_band_vbuc1
tya
and #{c1}
tay
//FRAGMENT vbuz1=vbuaa_rol_1 //FRAGMENT vbuz1=vbuaa_rol_1
asl asl
sta {z1} sta {z1}
@ -420,8 +382,19 @@ ora {z2}
sta {z1} sta {z1}
//FRAGMENT vbuz1=vbuxx_bor_vbuxx //FRAGMENT vbuz1=vbuxx_bor_vbuxx
stx {z1} stx {z1}
//FRAGMENT vbuxx_lt_vbuc1_then_la1
cpx #{c1}
bcc {la1}
//FRAGMENT _deref_pbuc1=vbuyy //FRAGMENT _deref_pbuc1=vbuyy
sty {c1} sty {c1}
//FRAGMENT vbuxx=vbuc1
ldx #{c1}
//FRAGMENT vbuyy=vbuc1
ldy #{c1}
//FRAGMENT vbuxx=_inc_vbuxx
inx
//FRAGMENT vbuyy=_inc_vbuyy
iny
//FRAGMENT vbuc1_neq_vbuyy_then_la1 //FRAGMENT vbuc1_neq_vbuyy_then_la1
cpy #{c1} cpy #{c1}
bne {la1} bne {la1}
@ -431,6 +404,9 @@ beq {la1}
//FRAGMENT vbuc1_eq_vbuyy_then_la1 //FRAGMENT vbuc1_eq_vbuyy_then_la1
cpy #{c1} cpy #{c1}
beq {la1} beq {la1}
//FRAGMENT vbuyy_lt_vbuc1_then_la1
cpy #{c1}
bcc {la1}
//FRAGMENT vbuz1=vbuz2_bor_vbuyy //FRAGMENT vbuz1=vbuz2_bor_vbuyy
tya tya
ora {z2} ora {z2}
@ -530,9 +506,6 @@ ora $ff
tax tax
//FRAGMENT vbuyy=vbuaa //FRAGMENT vbuyy=vbuaa
tay tay
//FRAGMENT vbuyy_neq_0_then_la1
cpy #0
bne {la1}
//FRAGMENT pbuz1=pbuz1_plus_vbuc1 //FRAGMENT pbuz1=pbuz1_plus_vbuc1
lda #{c1} lda #{c1}
clc clc
@ -541,3 +514,31 @@ sta {z1}
bcc !+ bcc !+
inc {z1}+1 inc {z1}+1
!: !:
//FRAGMENT vbuz1_neq_0_then_la1
lda {z1}
cmp #0
bne {la1}
//FRAGMENT vbuz1=vbuz1_plus_vbuc1
lda #{c1}
clc
adc {z1}
sta {z1}
//FRAGMENT vbuaa_neq_0_then_la1
cmp #0
bne {la1}
//FRAGMENT vbuxx=vbuxx_plus_vbuc1
txa
clc
adc #{c1}
tax
//FRAGMENT vbuyy=vbuyy_plus_vbuc1
tya
clc
adc #{c1}
tay
//FRAGMENT vbuxx_neq_0_then_la1
cpx #0
bne {la1}
//FRAGMENT vbuyy_neq_0_then_la1
cpy #0
bne {la1}

View File

@ -1,3 +1,4 @@
//KICKC FRAGMENT CACHE 1a8109f402
//FRAGMENT vbuz1=vbuc1 //FRAGMENT vbuz1=vbuc1
lda #{c1} lda #{c1}
sta {z1} sta {z1}
@ -7510,6 +7511,8 @@ sta {z1}
lda {z1}+1 lda {z1}+1
sbc {z2}+1 sbc {z2}+1
sta {z1}+1 sta {z1}+1
//FRAGMENT vbuyy=pbuc1_derefidx_vbuxx
ldy {c1},x
//FRAGMENT _stackpullbyte_1 //FRAGMENT _stackpullbyte_1
pla pla
//FRAGMENT vbsz1=_sbyte_vwuz2 //FRAGMENT vbsz1=_sbyte_vwuz2
@ -7902,8 +7905,6 @@ beq {la1}
cpy #{c1} cpy #{c1}
bcc {la1} bcc {la1}
beq {la1} beq {la1}
//FRAGMENT vbuyy=pbuc1_derefidx_vbuxx
ldy {c1},x
//FRAGMENT vbsaa=_inc_vbsaa //FRAGMENT vbsaa=_inc_vbsaa
clc clc
adc #1 adc #1
@ -13824,6 +13825,62 @@ lda {z1}
cmp #<{c1} cmp #<{c1}
bcc {la1} bcc {la1}
!: !:
//FRAGMENT vbuz1=_deref_pbuc1_bxor_vbuc2
lda #{c2}
eor {c1}
sta {z1}
//FRAGMENT vbuz1=vbuc1_bxor_vbuaa
eor #{c1}
sta {z1}
//FRAGMENT vbuz1=vbuc1_bxor_vbuxx
txa
eor #{c1}
sta {z1}
//FRAGMENT vbuz1=vbuc1_bxor_vbuyy
tya
eor #{c1}
sta {z1}
//FRAGMENT vbuaa=vbuc1_bxor_vbuaa
eor #{c1}
//FRAGMENT vbuaa=vbuc1_bxor_vbuxx
txa
eor #{c1}
//FRAGMENT vbuaa=vbuc1_bxor_vbuyy
tya
eor #{c1}
//FRAGMENT vbuxx=vbuc1_bxor_vbuaa
eor #{c1}
tax
//FRAGMENT vbuxx=vbuc1_bxor_vbuxx
txa
eor #{c1}
tax
//FRAGMENT vbuxx=vbuc1_bxor_vbuyy
tya
eor #{c1}
tax
//FRAGMENT vbuyy=vbuc1_bxor_vbuaa
eor #{c1}
tay
//FRAGMENT vbuyy=vbuc1_bxor_vbuxx
txa
eor #{c1}
tay
//FRAGMENT vbuyy=vbuc1_bxor_vbuyy
tya
eor #{c1}
tay
//FRAGMENT vbuaa=_deref_pbuc1_bxor_vbuc2
lda #{c2}
eor {c1}
//FRAGMENT vbuxx=_deref_pbuc1_bxor_vbuc2
lda #{c2}
eor {c1}
tax
//FRAGMENT vbuyy=_deref_pbuc1_bxor_vbuc2
lda #{c2}
eor {c1}
tay
//FRAGMENT vbuz1=vbuz1_plus_vbuaa //FRAGMENT vbuz1=vbuz1_plus_vbuaa
clc clc
adc {z1} adc {z1}
@ -14849,18 +14906,6 @@ sta ({z1}),y
//FRAGMENT vbuaa_eq_vbuz1_then_la1 //FRAGMENT vbuaa_eq_vbuz1_then_la1
cmp {z1} cmp {z1}
beq {la1} beq {la1}
//FRAGMENT vwsz1_lt_vbsc1_then_la1
NO_SYNTHESIS
//FRAGMENT vwsz1_lt_vwuc1_then_la1
lda {z1}+1
bmi {la1}
cmp #>{c1}
bcc {la1}
bne !+
lda {z1}
cmp #<{c1}
bcc {la1}
!:
//FRAGMENT vbuz1=vbuxx_band_pbuz2_derefidx_vbuc1 //FRAGMENT vbuz1=vbuxx_band_pbuz2_derefidx_vbuc1
ldy #{c1} ldy #{c1}
txa txa
@ -17242,6 +17287,18 @@ lda {z1}+3
cmp {z2}+3 cmp {z2}+3
beq {la1} beq {la1}
!: !:
//FRAGMENT vwsz1_lt_vbsc1_then_la1
NO_SYNTHESIS
//FRAGMENT vwsz1_lt_vwuc1_then_la1
lda {z1}+1
bmi {la1}
cmp #>{c1}
bcc {la1}
bne !+
lda {z1}
cmp #<{c1}
bcc {la1}
!:
//FRAGMENT vwsz1=pwsc1_derefidx_vbuz2_minus_pwsc2_derefidx_vbuz2 //FRAGMENT vwsz1=pwsc1_derefidx_vbuz2_minus_pwsc2_derefidx_vbuz2
ldy {z2} ldy {z2}
sec sec
@ -17627,62 +17684,6 @@ sta {c1},y
lda #{c2} lda #{c2}
ora {c1},x ora {c1},x
sta {c1},x sta {c1},x
//FRAGMENT vbuz1=_deref_pbuc1_bxor_vbuc2
lda #{c2}
eor {c1}
sta {z1}
//FRAGMENT vbuz1=vbuc1_bxor_vbuaa
eor #{c1}
sta {z1}
//FRAGMENT vbuz1=vbuc1_bxor_vbuxx
txa
eor #{c1}
sta {z1}
//FRAGMENT vbuz1=vbuc1_bxor_vbuyy
tya
eor #{c1}
sta {z1}
//FRAGMENT vbuaa=vbuc1_bxor_vbuaa
eor #{c1}
//FRAGMENT vbuaa=vbuc1_bxor_vbuxx
txa
eor #{c1}
//FRAGMENT vbuaa=vbuc1_bxor_vbuyy
tya
eor #{c1}
//FRAGMENT vbuxx=vbuc1_bxor_vbuaa
eor #{c1}
tax
//FRAGMENT vbuxx=vbuc1_bxor_vbuxx
txa
eor #{c1}
tax
//FRAGMENT vbuxx=vbuc1_bxor_vbuyy
tya
eor #{c1}
tax
//FRAGMENT vbuyy=vbuc1_bxor_vbuaa
eor #{c1}
tay
//FRAGMENT vbuyy=vbuc1_bxor_vbuxx
txa
eor #{c1}
tay
//FRAGMENT vbuyy=vbuc1_bxor_vbuyy
tya
eor #{c1}
tay
//FRAGMENT vbuaa=_deref_pbuc1_bxor_vbuc2
lda #{c2}
eor {c1}
//FRAGMENT vbuxx=_deref_pbuc1_bxor_vbuc2
lda #{c2}
eor {c1}
tax
//FRAGMENT vbuyy=_deref_pbuc1_bxor_vbuc2
lda #{c2}
eor {c1}
tay
//FRAGMENT pbuc1_derefidx_vbuyy=pbuc1_derefidx_vbuyy_bor_vbuc2 //FRAGMENT pbuc1_derefidx_vbuyy=pbuc1_derefidx_vbuyy_bor_vbuc2
lda #{c2} lda #{c2}
ora {c1},y ora {c1},y

View File

@ -98,10 +98,6 @@ public class Compiler {
program.setAsmFragmentBaseFolder(asmFragmentBaseFolder); program.setAsmFragmentBaseFolder(asmFragmentBaseFolder);
} }
public void setAsmFragmentCacheFolder(Path asmFragmentCacheDir) {
program.setAsmFragmentCacheFolder(asmFragmentCacheDir);
}
public AsmFragmentTemplateMasterSynthesizer getAsmFragmentMasterSynthesizer() { public AsmFragmentTemplateMasterSynthesizer getAsmFragmentMasterSynthesizer() {
return program.getAsmFragmentMasterSynthesizer(); return program.getAsmFragmentMasterSynthesizer();
} }

View File

@ -95,8 +95,8 @@ public class KickC implements Callable<Integer> {
@CommandLine.Option(names = {"-Onoloophead"}, description = "Optimization Option. Disabled experimental loop-head constant pass which identifies loops where the condition is constant on the first iteration.") @CommandLine.Option(names = {"-Onoloophead"}, description = "Optimization Option. Disabled experimental loop-head constant pass which identifies loops where the condition is constant on the first iteration.")
private boolean optimizeNoLoopHeadConstant = false; private boolean optimizeNoLoopHeadConstant = false;
@CommandLine.Option(names = {"-Ocache"}, description = "Optimization Option. Enables a fragment cache file.") @CommandLine.Option(names = {"-Onocache"}, description = "Optimization Option. Disables the fragment synthesis cache. The cache is enabled by default.")
private boolean optimizeFragmentCache = false; private boolean optimizeNoFragmentCache = false;
@CommandLine.Option(names = {"-Oliverangecallpath"}, description = "Optimization Option. Enables live ranges per call path optimization, which limits memory usage and code, but takes a lot of compile time.") @CommandLine.Option(names = {"-Oliverangecallpath"}, description = "Optimization Option. Enables live ranges per call path optimization, which limits memory usage and code, but takes a lot of compile time.")
private boolean optimizeLiveRangeCallPath = false; private boolean optimizeLiveRangeCallPath = false;
@ -214,25 +214,14 @@ public class KickC implements Callable<Integer> {
if(fragmentDir == null) { if(fragmentDir == null) {
fragmentDir = new File("fragment/").toPath(); fragmentDir = new File("fragment/").toPath();
} }
compiler.setAsmFragmentBaseFolder(fragmentDir);
Path fragmentCacheDir = null;
if(optimizeFragmentCache) {
if(outputDir != null) {
fragmentCacheDir = outputDir;
} else {
fragmentCacheDir = new File(".").toPath();
}
}
configVerbosity(compiler); configVerbosity(compiler);
compiler.setAsmFragmentBaseFolder(fragmentDir);
compiler.setAsmFragmentCacheFolder(fragmentCacheDir);
Program program = compiler.getProgram(); Program program = compiler.getProgram();
// Initialize the master ASM fragment synthesizer // Initialize the master ASM fragment synthesizer
program.initAsmFragmentMasterSynthesizer(); program.initAsmFragmentMasterSynthesizer(!optimizeNoFragmentCache);
Path currentPath = new File(".").toPath(); Path currentPath = new File(".").toPath();

View File

@ -0,0 +1,66 @@
package dk.camelot64.kickc.fragment;
import dk.camelot64.kickc.model.TargetCpu;
import java.io.File;
import java.nio.file.Path;
/**
* Capable of creating a hash code that describes the total state of the ASM fragment system.
* <p>
* This hash is used to determine whether to use or discard the cache.
*/
public class AsmFragmentSystemHash {
/** Hash of the fragment source files. */
private long hash;
/** Last modified date for the fragment source files. */
private long lastModified;
AsmFragmentSystemHash(long hash, long lastModified) {
this.lastModified = lastModified;
this.hash = hash;
}
/**
* Run through the fragment folder and calculate the hash/modify time
* @param baseFragmentFolder The fragment folder
* @return The fragment system hash
*/
public static AsmFragmentSystemHash calculate(Path baseFragmentFolder) {
long hash = 0;
long lastModified = 0;
final TargetCpu.Feature[] cpuFeatures = TargetCpu.Feature.values();
for(TargetCpu.Feature cpuFeature : cpuFeatures) {
hash += cpuFeature.getName().hashCode();
final Path cpuFeatureFolder = baseFragmentFolder.resolve(cpuFeature.getName());
final File cpuFeatureFolderFile = cpuFeatureFolder.toFile();
if(cpuFeatureFolderFile.exists() && cpuFeatureFolderFile.isDirectory()) {
final File[] files = cpuFeatureFolderFile.listFiles((dir, name) -> name.endsWith(".asm"));
if(files != null)
for(File file : files) {
hash += file.length();
hash += file.getName().hashCode();
if(file.lastModified() > lastModified)
lastModified = file.lastModified();
}
}
}
return new AsmFragmentSystemHash(hash, lastModified);
}
public long getHash() {
return hash;
}
public String getHashString() {
return Long.toHexString(hash);
}
public long getLastModified() {
return lastModified;
}
}

View File

@ -14,6 +14,12 @@ import java.util.Map;
/** Cache for ASM fragments. The cache remembers all synthesized fragments allowing for faster access after the first synthesis. */ /** Cache for ASM fragments. The cache remembers all synthesized fragments allowing for faster access after the first synthesis. */
public class AsmFragmentTemplateCache { public class AsmFragmentTemplateCache {
/** Hash and lastModify information for the fragment system. */
private AsmFragmentSystemHash fragmentSystemHash;
/** Name of the sub-folder holding the fragment cache. */
public static final String CACHE_FOLDER_NAME = "cache";
/** The folder containing cached fragment files. */ /** The folder containing cached fragment files. */
private Path cacheFolder; private Path cacheFolder;
@ -26,9 +32,10 @@ public class AsmFragmentTemplateCache {
/** Detects any modification of the cache. */ /** Detects any modification of the cache. */
private boolean modified; private boolean modified;
public AsmFragmentTemplateCache(Path cacheFolder, TargetCpu cpu, Map<String, AsmFragmentTemplate> cache) { AsmFragmentTemplateCache(Path cacheFolder, TargetCpu cpu, AsmFragmentSystemHash fragmentSystemHash, Map<String, AsmFragmentTemplate> cache) {
this.cacheFolder = cacheFolder; this.cacheFolder = cacheFolder;
this.cpu = cpu; this.cpu = cpu;
this.fragmentSystemHash = fragmentSystemHash;
this.cache = cache; this.cache = cache;
this.modified = false; this.modified = false;
} }
@ -36,7 +43,10 @@ public class AsmFragmentTemplateCache {
/** Special singleton representing that the fragment can not be synthesized or loaded. */ /** Special singleton representing that the fragment can not be synthesized or loaded. */
public static AsmFragmentTemplate NO_SYNTHESIS = new AsmFragmentTemplate("NO_SYNTHESIS", "NO_SYNTHESIS", false); public static AsmFragmentTemplate NO_SYNTHESIS = new AsmFragmentTemplate("NO_SYNTHESIS", "NO_SYNTHESIS", false);
/** The prefix for header.lines in the fragment cache file. */ /** Prefix for the fragment hash file header. */
public static final String HASH_HEADER = "//KICKC FRAGMENT CACHE ";
/** The prefix for fragment header lines in the fragment cache file. */
public static final String FRAGMENT_HEADER = "//FRAGMENT "; public static final String FRAGMENT_HEADER = "//FRAGMENT ";
/** /**
@ -68,25 +78,57 @@ public class AsmFragmentTemplateCache {
return "fragment-cache-" + cpu.getName() + ".asm"; return "fragment-cache-" + cpu.getName() + ".asm";
} }
/**
* Creates an empty memory-only fragment cache
*
* @param cpu The CPU to make a cache for
* @return The new empty cache
*/
public static AsmFragmentTemplateCache memory(TargetCpu cpu) {
return new AsmFragmentTemplateCache(null, cpu, new AsmFragmentSystemHash(0, 0), new LinkedHashMap<>());
}
/** /**
* Attempt to load a fragment cache containing all best synthesized fragments * Attempt to load a fragment cache containing all best synthesized fragments
* *
* @param cacheFolder Folder containing the cache * @param baseFragmentFolder Folder containing fragments. (The cache is localed in the sub-folder named "cache)
* @param log The compile log * @param log The compile log
* @return The map with all best fragments from the cache file. null if the cache file is not found. * @return The map with all best fragments from the cache file. null if the cache file is not found.
*/ */
public static AsmFragmentTemplateCache load(Path cacheFolder, TargetCpu cpu, CompileLog log) { public static AsmFragmentTemplateCache load(TargetCpu cpu, Path baseFragmentFolder, CompileLog log) {
final AsmFragmentSystemHash fragmentSystemHash = AsmFragmentSystemHash.calculate(baseFragmentFolder);
Path cacheFolder = baseFragmentFolder.resolve(CACHE_FOLDER_NAME);
final Date before = new Date(); final Date before = new Date();
if(cacheFolder == null) { if(!cacheFolder.toFile().exists()) {
return new AsmFragmentTemplateCache(null, cpu, new LinkedHashMap<>()); if(log.isVerboseFragmentLog())
log.append("Creating fragment cache folder " + cacheFolder.toAbsolutePath().toString());
cacheFolder.toFile().mkdir();
return new AsmFragmentTemplateCache(cacheFolder, cpu, fragmentSystemHash, new LinkedHashMap<>());
} }
try { try {
File cacheFile = cacheFolder.resolve(getCacheFileName(cpu)).toFile(); File cacheFile = cacheFolder.resolve(getCacheFileName(cpu)).toFile();
if(!cacheFile.exists()) { if(!cacheFile.exists()) {
return new AsmFragmentTemplateCache(cacheFolder, cpu, new LinkedHashMap<>()); return new AsmFragmentTemplateCache(cacheFolder, cpu, fragmentSystemHash, new LinkedHashMap<>());
}
if(cacheFile.lastModified() < fragmentSystemHash.getLastModified()) {
if(log.isVerboseFragmentLog())
log.append("Deleting outdated fragment cache file " + cacheFile.getAbsolutePath());
cacheFile.delete();
return new AsmFragmentTemplateCache(cacheFolder, cpu, fragmentSystemHash, new LinkedHashMap<>());
} }
LinkedHashMap<String, AsmFragmentTemplate> cache = new LinkedHashMap<>(); LinkedHashMap<String, AsmFragmentTemplate> cache = new LinkedHashMap<>();
BufferedReader fragmentCacheReader = new BufferedReader(new FileReader(cacheFile)); BufferedReader fragmentCacheReader = new BufferedReader(new FileReader(cacheFile));
String hashLine = fragmentCacheReader.readLine();
final String hash = hashLine.substring(HASH_HEADER.length());
// Compare cache file hash with fragment system hash
if(!hash.equals(fragmentSystemHash.getHashString())) {
// Cache file hash does not match fragment system hash
if(log.isVerboseFragmentLog())
log.append("Deleting hash mismatch fragment cache file " + cacheFile.getAbsolutePath());
cacheFile.delete();
return new AsmFragmentTemplateCache(cacheFolder, cpu, fragmentSystemHash, new LinkedHashMap<>());
}
// Read the first "real" line
String cacheLine = fragmentCacheReader.readLine(); String cacheLine = fragmentCacheReader.readLine();
StringBuilder body = null; StringBuilder body = null;
String signature = null; String signature = null;
@ -112,7 +154,7 @@ public class AsmFragmentTemplateCache {
final long millis = after.getTime() - before.getTime(); final long millis = after.getTime() - before.getTime();
if(log.isVerboseFragmentLog()) if(log.isVerboseFragmentLog())
log.append("Loaded cached fragments " + cache.size() + " from " + cacheFile.getPath() + " in " + millis + "ms"); log.append("Loaded cached fragments " + cache.size() + " from " + cacheFile.getPath() + " in " + millis + "ms");
return new AsmFragmentTemplateCache(cacheFolder, cpu, cache); return new AsmFragmentTemplateCache(cacheFolder, cpu, fragmentSystemHash, cache);
} catch(IOException e) { } catch(IOException e) {
throw new RuntimeException("Error loading fragment cache file " + cacheFolder, e); throw new RuntimeException("Error loading fragment cache file " + cacheFolder, e);
} catch(StringIndexOutOfBoundsException e) { } catch(StringIndexOutOfBoundsException e) {
@ -145,10 +187,11 @@ public class AsmFragmentTemplateCache {
File cacheFile = this.cacheFolder.resolve(getCacheFileName(cpu)).toFile(); File cacheFile = this.cacheFolder.resolve(getCacheFileName(cpu)).toFile();
try { try {
PrintStream fragmentFilePrint = new PrintStream(cacheFile); PrintStream fragmentFilePrint = new PrintStream(cacheFile);
fragmentFilePrint.println(HASH_HEADER + fragmentSystemHash.getHashString());
for(String signature : this.cache.keySet()) { for(String signature : this.cache.keySet()) {
AsmFragmentTemplate fragmentTemplate = this.cache.get(signature); AsmFragmentTemplate fragmentTemplate = this.cache.get(signature);
fragmentFilePrint.println(FRAGMENT_HEADER + signature); fragmentFilePrint.println(FRAGMENT_HEADER + signature);
if(fragmentTemplate==NO_SYNTHESIS) { if(fragmentTemplate == NO_SYNTHESIS) {
fragmentFilePrint.println(NO_SYNTHESIS.getBody()); fragmentFilePrint.println(NO_SYNTHESIS.getBody());
} else { } else {
if(fragmentTemplate.getBody() != null) if(fragmentTemplate.getBody() != null)

View File

@ -14,8 +14,8 @@ public class AsmFragmentTemplateMasterSynthesizer {
/** Fragment base folder. */ /** Fragment base folder. */
private final Path baseFragmentFolder; private final Path baseFragmentFolder;
/** Fragment cache folder. */ /** Use the fragment synthesis cache */
private final Path cacheFolder; private boolean useFragmentCache;
/** Compile Log. */ /** Compile Log. */
private CompileLog log; private CompileLog log;
@ -23,9 +23,9 @@ public class AsmFragmentTemplateMasterSynthesizer {
private Map<TargetCpu, AsmFragmentTemplateSynthesizer> synthesizers; private Map<TargetCpu, AsmFragmentTemplateSynthesizer> synthesizers;
/** Create master synthesizer. */ /** Create master synthesizer. */
public AsmFragmentTemplateMasterSynthesizer(Path baseFragmentFolder, Path cacheFolder, CompileLog log) { public AsmFragmentTemplateMasterSynthesizer(Path baseFragmentFolder, boolean useFragmentCache, CompileLog log) {
this.baseFragmentFolder = baseFragmentFolder; this.baseFragmentFolder = baseFragmentFolder;
this.cacheFolder = cacheFolder; this.useFragmentCache = useFragmentCache;
this.log = log; this.log = log;
this.synthesizers = new LinkedHashMap<>(); this.synthesizers = new LinkedHashMap<>();
} }
@ -33,7 +33,7 @@ public class AsmFragmentTemplateMasterSynthesizer {
public AsmFragmentTemplateSynthesizer getSynthesizer(TargetCpu targetCpu) { public AsmFragmentTemplateSynthesizer getSynthesizer(TargetCpu targetCpu) {
AsmFragmentTemplateSynthesizer synthesizer = synthesizers.get(targetCpu); AsmFragmentTemplateSynthesizer synthesizer = synthesizers.get(targetCpu);
if(synthesizer==null) { if(synthesizer==null) {
synthesizer = new AsmFragmentTemplateSynthesizer(baseFragmentFolder, targetCpu, cacheFolder, log); synthesizer = new AsmFragmentTemplateSynthesizer(targetCpu, baseFragmentFolder, useFragmentCache, log);
synthesizers.put(targetCpu, synthesizer); synthesizers.put(targetCpu, synthesizer);
} }
return synthesizer; return synthesizer;

View File

@ -26,12 +26,15 @@ import java.util.*;
public class AsmFragmentTemplateSynthesizer { public class AsmFragmentTemplateSynthesizer {
/** Create synthesizer. */ /** Create synthesizer. */
public AsmFragmentTemplateSynthesizer(Path baseFragmentFolder, TargetCpu cpu, Path cacheFolder, CompileLog log) { public AsmFragmentTemplateSynthesizer(TargetCpu cpu, Path baseFragmentFolder, boolean useFragmentCache, CompileLog log) {
this.baseFragmentFolder = baseFragmentFolder; this.baseFragmentFolder = baseFragmentFolder;
this.cpu = cpu; this.cpu = cpu;
this.synthesisGraph = new LinkedHashMap<>(); this.synthesisGraph = new LinkedHashMap<>();
this.bestTemplateUpdate = new ArrayDeque<>(); this.bestTemplateUpdate = new ArrayDeque<>();
this.fragmentCache = AsmFragmentTemplateCache.load(cacheFolder, cpu, log); if(useFragmentCache)
this.fragmentCache = AsmFragmentTemplateCache.load(cpu, baseFragmentFolder, log);
else
this.fragmentCache = AsmFragmentTemplateCache.memory(cpu);
} }
/** The folder containing fragment files. */ /** The folder containing fragment files. */

View File

@ -35,8 +35,6 @@ public class Program {
/** Base folder for finding ASM fragment files. (STATIC) */ /** Base folder for finding ASM fragment files. (STATIC) */
private Path asmFragmentBaseFolder; private Path asmFragmentBaseFolder;
/** Cache folder for finding ASM fragment files. (STATIC) */
private Path asmFragmentCacheFolder;
/** The ASM fragment synthesizer responsible for loading/synthesizing ASM fragments. Depends on the target CPU. (STATIC) */ /** The ASM fragment synthesizer responsible for loading/synthesizing ASM fragments. Depends on the target CPU. (STATIC) */
private AsmFragmentTemplateMasterSynthesizer asmFragmentMasterSynthesizer; private AsmFragmentTemplateMasterSynthesizer asmFragmentMasterSynthesizer;
@ -192,14 +190,6 @@ public class Program {
this.warnArrayType = errorArrayKickC; this.warnArrayType = errorArrayKickC;
} }
public Path getAsmFragmentCacheFolder() {
return asmFragmentCacheFolder;
}
public void setAsmFragmentCacheFolder(Path asmFragmentCacheFolder) {
this.asmFragmentCacheFolder = asmFragmentCacheFolder;
}
public Path getAsmFragmentBaseFolder() { public Path getAsmFragmentBaseFolder() {
return asmFragmentBaseFolder; return asmFragmentBaseFolder;
} }
@ -212,8 +202,8 @@ public class Program {
return asmFragmentMasterSynthesizer; return asmFragmentMasterSynthesizer;
} }
public void initAsmFragmentMasterSynthesizer() { public void initAsmFragmentMasterSynthesizer(boolean useFragmentCache) {
this.asmFragmentMasterSynthesizer = new AsmFragmentTemplateMasterSynthesizer(asmFragmentBaseFolder, asmFragmentCacheFolder, getLog()); this.asmFragmentMasterSynthesizer = new AsmFragmentTemplateMasterSynthesizer(asmFragmentBaseFolder, useFragmentCache, getLog());
} }
public TargetPlatform getTargetPlatform() { public TargetPlatform getTargetPlatform() {

View File

@ -24,7 +24,7 @@ public class TestFragments {
@BeforeClass @BeforeClass
public static void setUp() { public static void setUp() {
asmFragmentTemplateSynthesizer = new AsmFragmentTemplateSynthesizer(new File("src/main/fragment/").toPath(), TargetCpu.MOS6502X, null, new CompileLog()); asmFragmentTemplateSynthesizer = new AsmFragmentTemplateSynthesizer(TargetCpu.MOS6502X, new File("src/main/fragment/").toPath(), false, new CompileLog());
} }
@AfterClass @AfterClass
@ -193,7 +193,7 @@ public class TestFragments {
*/ */
private void testFragmentExists(String signature) { private void testFragmentExists(String signature) {
CompileLog log = new CompileLog(); CompileLog log = new CompileLog();
asmFragmentTemplateSynthesizer = new AsmFragmentTemplateSynthesizer(new File("src/main/fragment/").toPath(), TargetCpu.MOS6502X, null, new CompileLog()); asmFragmentTemplateSynthesizer = new AsmFragmentTemplateSynthesizer(TargetCpu.MOS6502X, new File("src/main/fragment/").toPath(), false, new CompileLog());
log.setSysOut(true); log.setSysOut(true);
//log.setVerboseFragmentLog(true); //log.setVerboseFragmentLog(true);
List<AsmFragmentTemplate> templates = List<AsmFragmentTemplate> templates =
@ -211,7 +211,7 @@ public class TestFragments {
private void testFragments(String fileName, Collection<String> signatures) throws IOException { private void testFragments(String fileName, Collection<String> signatures) throws IOException {
CompileLog log = new CompileLog(); CompileLog log = new CompileLog();
asmFragmentTemplateSynthesizer = new AsmFragmentTemplateSynthesizer(new File("src/main/fragment/").toPath(), TargetCpu.MOS6502X, null, new CompileLog()); asmFragmentTemplateSynthesizer = new AsmFragmentTemplateSynthesizer(TargetCpu.MOS6502X, new File("src/main/fragment/").toPath(), false, new CompileLog());
List<String> sigs = new ArrayList<>(signatures); List<String> sigs = new ArrayList<>(signatures);
// Always test max 1000 signatures // Always test max 1000 signatures

View File

@ -4,7 +4,6 @@ import dk.camelot64.kickc.CompileLog;
import dk.camelot64.kickc.Compiler; import dk.camelot64.kickc.Compiler;
import dk.camelot64.kickc.SourceLoader; import dk.camelot64.kickc.SourceLoader;
import dk.camelot64.kickc.asm.AsmProgram; import dk.camelot64.kickc.asm.AsmProgram;
import dk.camelot64.kickc.fragment.AsmFragmentTemplateSynthesizer;
import dk.camelot64.kickc.model.CompileError; import dk.camelot64.kickc.model.CompileError;
import dk.camelot64.kickc.model.Program; import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.TargetPlatform; import dk.camelot64.kickc.model.TargetPlatform;
@ -4302,13 +4301,8 @@ public class TestPrograms {
compileAndCompare("condition-type-mismatch.c"); compileAndCompare("condition-type-mismatch.c");
} }
static AsmFragmentTemplateSynthesizer asmFragmentSynthesizer;
@BeforeClass @BeforeClass
public static void setUp() { public static void setUp() {
//Path asmFragmentBaseFolder = new File("src/main/fragment/").toPath();
//Path asmFragmentCacheFolder = new File("src/main/fragment/cache").toPath();
//asmFragmentSynthesizer = new AsmFragmentTemplateSynthesizer(asmFragmentBaseFolder, TargetCpu.MOS6502X, asmFragmentCacheFolder, new CompileLog());
} }
@AfterClass @AfterClass
@ -4402,7 +4396,6 @@ public class TestPrograms {
Compiler compiler = new Compiler(); Compiler compiler = new Compiler();
compiler.setWarnFragmentMissing(true); compiler.setWarnFragmentMissing(true);
compiler.setAsmFragmentBaseFolder(new File("src/main/fragment/").toPath()); compiler.setAsmFragmentBaseFolder(new File("src/main/fragment/").toPath());
compiler.setAsmFragmentCacheFolder(new File("src/main/fragment/cache/").toPath());
if(compileLog != null) { if(compileLog != null) {
compiler.setLog(compileLog); compiler.setLog(compileLog);
} }
@ -4418,7 +4411,7 @@ public class TestPrograms {
files.add(filePath); files.add(filePath);
Program program = compiler.getProgram(); Program program = compiler.getProgram();
// Initialize the master ASM fragment synthesizer // Initialize the master ASM fragment synthesizer
program.initAsmFragmentMasterSynthesizer(); program.initAsmFragmentMasterSynthesizer(true);
final File platformFile = SourceLoader.loadFile(TargetPlatform.DEFAULT_NAME + "." + CTargetPlatformParser.FILE_EXTENSION, filePath, program.getTargetPlatformPaths()); final File platformFile = SourceLoader.loadFile(TargetPlatform.DEFAULT_NAME + "." + CTargetPlatformParser.FILE_EXTENSION, filePath, program.getTargetPlatformPaths());
final TargetPlatform targetPlatform = CTargetPlatformParser.parseTargetPlatformFile(TargetPlatform.DEFAULT_NAME, platformFile, filePath, program.getTargetPlatformPaths()); final TargetPlatform targetPlatform = CTargetPlatformParser.parseTargetPlatformFile(TargetPlatform.DEFAULT_NAME, platformFile, filePath, program.getTargetPlatformPaths());
program.setTargetPlatform(targetPlatform); program.setTargetPlatform(targetPlatform);