mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-11-26 12:49:21 +00:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
c6d0f41c14
2
.gitignore
vendored
2
.gitignore
vendored
@ -3,9 +3,11 @@
|
|||||||
*/*.brk
|
*/*.brk
|
||||||
*/*.prg
|
*/*.prg
|
||||||
*/*.sym
|
*/*.sym
|
||||||
|
*/.tmpdirs
|
||||||
*/bin/
|
*/bin/
|
||||||
*/workspace.xml
|
*/workspace.xml
|
||||||
./target/
|
./target/
|
||||||
target/
|
target/
|
||||||
**/.DS_Store
|
**/.DS_Store
|
||||||
.project
|
.project
|
||||||
|
.tmpdirs
|
||||||
|
@ -220,6 +220,9 @@ public class KickC implements Callable<Integer> {
|
|||||||
|
|
||||||
Program program = compiler.getProgram();
|
Program program = compiler.getProgram();
|
||||||
|
|
||||||
|
// Initialize tmp dir manager
|
||||||
|
TmpDirManager.init(program.getAsmFragmentBaseFolder());
|
||||||
|
|
||||||
// Initialize the master ASM fragment synthesizer
|
// Initialize the master ASM fragment synthesizer
|
||||||
program.initAsmFragmentMasterSynthesizer(!optimizeNoFragmentCache);
|
program.initAsmFragmentMasterSynthesizer(!optimizeNoFragmentCache);
|
||||||
|
|
||||||
@ -486,6 +489,9 @@ public class KickC implements Callable<Integer> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(TmpDirManager.MANAGER!=null)
|
||||||
|
TmpDirManager.MANAGER.cleanup();
|
||||||
|
|
||||||
return CommandLine.ExitCode.OK;
|
return CommandLine.ExitCode.OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
136
src/main/java/dk/camelot64/kickc/TmpDirManager.java
Normal file
136
src/main/java/dk/camelot64/kickc/TmpDirManager.java
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
package dk.camelot64.kickc;
|
||||||
|
|
||||||
|
import dk.camelot64.kickc.model.CompileError;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages temporary folders with files.
|
||||||
|
* KickAssembler holds open handles to compiled ASM files. Therefore they cannot be deleted immediately after compilation.
|
||||||
|
* This manager
|
||||||
|
* - supports creation of new temporary folders
|
||||||
|
* - attempts deletion on exit
|
||||||
|
* - if deletion is not successful the folder paths are saved to a file. The folders in this file is attempted deleted on the next invocation.
|
||||||
|
*/
|
||||||
|
public class TmpDirManager {
|
||||||
|
|
||||||
|
/** Singleton manager. */
|
||||||
|
public static TmpDirManager MANAGER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the singleton manager
|
||||||
|
*
|
||||||
|
* @param baseFolder The base folder where the TXT file containing dirs to delete will be loaded/saved from.
|
||||||
|
*/
|
||||||
|
public static void init(Path baseFolder) {
|
||||||
|
MANAGER = new TmpDirManager(baseFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The base folder where the TXT file containing dirs to delete will be loaded/saved from. */
|
||||||
|
private Path baseFolder;
|
||||||
|
|
||||||
|
/** Tmp folders that have been created and not deleted. */
|
||||||
|
private List<Path> tmpDirs;
|
||||||
|
|
||||||
|
private TmpDirManager(Path baseFolder) {
|
||||||
|
this.baseFolder = baseFolder;
|
||||||
|
this.tmpDirs = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new temporary directory
|
||||||
|
*
|
||||||
|
* @return The new temporary folder
|
||||||
|
*/
|
||||||
|
public Path newTmpDir() {
|
||||||
|
try {
|
||||||
|
Path tmpDir = Files.createTempDirectory("kickc");
|
||||||
|
this.tmpDirs.add(tmpDir);
|
||||||
|
return tmpDir;
|
||||||
|
} catch(IOException e) {
|
||||||
|
throw new CompileError("Error creating temporary directory. ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes all temporary folders - including any files in the folders.
|
||||||
|
* If deletion is not successful the absolute paths are saved to a txt-file to tried again later.
|
||||||
|
* This also loads the txt-file with previous failed deletions and retries them
|
||||||
|
*/
|
||||||
|
public void cleanup() {
|
||||||
|
try {
|
||||||
|
// Attempt deletion of all temporary folders - including all files in the folders
|
||||||
|
List<Path> failedDirs = new ArrayList<>();
|
||||||
|
for(Path tmpDir : tmpDirs) {
|
||||||
|
boolean success = deleteTmpDir(tmpDir);
|
||||||
|
if(!success) {
|
||||||
|
failedDirs.add(tmpDir);
|
||||||
|
//System.out.println("Cannot delete temporary folder, postponing " + tmpDir);
|
||||||
|
} else {
|
||||||
|
//System.out.println("Successfully deleted temporary folder " + tmpDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Read postponed file and delete any paths
|
||||||
|
File todoFile = baseFolder.resolve(".tmpdirs").toFile();
|
||||||
|
if(todoFile.exists()) {
|
||||||
|
FileReader todoFileReader = new FileReader(todoFile);
|
||||||
|
BufferedReader todoBufferedReader = new BufferedReader(todoFileReader);
|
||||||
|
String todoPathAbs = todoBufferedReader.readLine();
|
||||||
|
while(todoPathAbs != null) {
|
||||||
|
Path todoPath = new File(todoPathAbs).toPath();
|
||||||
|
boolean success = deleteTmpDir(todoPath);
|
||||||
|
if(!success) {
|
||||||
|
System.err.println("Cannot delete postponed temporary folder - skipping " + todoPathAbs);
|
||||||
|
} else {
|
||||||
|
//System.out.println("Successfully deleted postponed temporary folder " + todoPathAbs);
|
||||||
|
}
|
||||||
|
todoPathAbs = todoBufferedReader.readLine();
|
||||||
|
}
|
||||||
|
todoBufferedReader.close();
|
||||||
|
todoFileReader.close();
|
||||||
|
}
|
||||||
|
// Delete the old postponed file
|
||||||
|
if(todoFile.exists()) {
|
||||||
|
if(!todoFile.delete())
|
||||||
|
System.err.println("Warning! Cannot delete .tmpdir file " + todoFile.getAbsolutePath());
|
||||||
|
//System.out.println("Deleted old .tmpdir file " + todoFile.getAbsolutePath());
|
||||||
|
}
|
||||||
|
// Save any failed paths to new postponed file
|
||||||
|
if(failedDirs.size() > 0) {
|
||||||
|
PrintStream todoPrintStream = new PrintStream(todoFile);
|
||||||
|
for(Path failedDir : failedDirs) {
|
||||||
|
todoPrintStream.println(failedDir.toAbsolutePath());
|
||||||
|
}
|
||||||
|
todoPrintStream.close();
|
||||||
|
//System.out.println("Saved .tmpdir file with " + failedDirs.size() + " postponed temporary folders " + todoFile.getAbsolutePath());
|
||||||
|
}
|
||||||
|
} catch(IOException e) {
|
||||||
|
throw new CompileError("Error cleaning up temporary files", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean deleteTmpDir(Path tmpDir) {
|
||||||
|
// Delete the temporary directory with folders
|
||||||
|
boolean success = true;
|
||||||
|
String[] entries = tmpDir.toFile().list();
|
||||||
|
if(entries != null)
|
||||||
|
for(String s : entries) {
|
||||||
|
File currentFile = new File(tmpDir.toFile(), s);
|
||||||
|
if(!currentFile.delete()) {
|
||||||
|
//System.err.println("Warning! Cannot delete temporary file " + currentFile.getAbsolutePath());
|
||||||
|
success = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!tmpDir.toFile().delete()) {
|
||||||
|
//System.err.println("Warning! Cannot delete temporary folder " + tmpDir.toAbsolutePath());
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -2,6 +2,7 @@ package dk.camelot64.kickc.passes;
|
|||||||
|
|
||||||
import dk.camelot64.cpufamily6502.CpuAddressingMode;
|
import dk.camelot64.cpufamily6502.CpuAddressingMode;
|
||||||
import dk.camelot64.cpufamily6502.CpuOpcode;
|
import dk.camelot64.cpufamily6502.CpuOpcode;
|
||||||
|
import dk.camelot64.kickc.TmpDirManager;
|
||||||
import dk.camelot64.kickc.asm.*;
|
import dk.camelot64.kickc.asm.*;
|
||||||
import dk.camelot64.kickc.model.CompileError;
|
import dk.camelot64.kickc.model.CompileError;
|
||||||
import dk.camelot64.kickc.model.Program;
|
import dk.camelot64.kickc.model.Program;
|
||||||
@ -21,8 +22,6 @@ import java.util.regex.Pattern;
|
|||||||
*/
|
*/
|
||||||
public class Pass5FixLongBranches extends Pass5AsmOptimization {
|
public class Pass5FixLongBranches extends Pass5AsmOptimization {
|
||||||
|
|
||||||
private Path tmpDir;
|
|
||||||
|
|
||||||
public Pass5FixLongBranches(Program program) {
|
public Pass5FixLongBranches(Program program) {
|
||||||
super(program);
|
super(program);
|
||||||
}
|
}
|
||||||
@ -54,35 +53,25 @@ public class Pass5FixLongBranches extends Pass5AsmOptimization {
|
|||||||
private boolean step() {
|
private boolean step() {
|
||||||
// Reindex ASM lines
|
// Reindex ASM lines
|
||||||
new Pass5ReindexAsmLines(getProgram()).optimize();
|
new Pass5ReindexAsmLines(getProgram()).optimize();
|
||||||
|
Path tmpDir = TmpDirManager.MANAGER.newTmpDir();
|
||||||
// Create a temporary directory for the ASM file
|
|
||||||
try {
|
|
||||||
tmpDir = Files.createTempDirectory("kickc");
|
|
||||||
} catch(IOException e) {
|
|
||||||
throw new CompileError("Error creating temp file.", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate the ASM file
|
// Generate the ASM file
|
||||||
String outputFileName = getProgram().getPrimaryFileName();
|
String outputFileName = getProgram().getPrimaryFileName();
|
||||||
try {
|
try {
|
||||||
//getLog().append("ASM");
|
//getLog().append("ASM");
|
||||||
//getLog().append(getProgram().getAsm().toString(false, true));
|
//getLog().append(getProgram().getAsm().toString(false, true));
|
||||||
|
writeOutputFile(tmpDir, outputFileName, ".asm", getProgram().getAsm().toString(new AsmProgram.AsmPrintState(false), null));
|
||||||
writeOutputFile(outputFileName, ".asm", getProgram().getAsm().toString(new AsmProgram.AsmPrintState(false), null));
|
|
||||||
|
|
||||||
// Copy Resource Files
|
// Copy Resource Files
|
||||||
for(Path asmResourceFile : getProgram().getAsmResourceFiles()) {
|
for(Path asmResourceFile : getProgram().getAsmResourceFiles()) {
|
||||||
File binFile = getTmpFile(asmResourceFile.getFileName().toString());
|
File binFile = getTmpFile(tmpDir, asmResourceFile.getFileName().toString());
|
||||||
Files.copy(asmResourceFile, binFile.toPath());
|
Files.copy(asmResourceFile, binFile.toPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
throw new CompileError("Error writing ASM temp file.", e);
|
throw new CompileError("Error writing ASM temp file.", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compile using KickAssembler - catch the output in a String
|
// Compile using KickAssembler - catch the output in a String
|
||||||
File asmFile = getTmpFile(outputFileName, ".asm");
|
File asmFile = getTmpFile(tmpDir, outputFileName, ".asm");
|
||||||
File binaryFile = getTmpFile(outputFileName, "."+getProgram().getTargetPlatform().getOutFileExtension());
|
File binaryFile = getTmpFile(tmpDir, outputFileName, "."+getProgram().getTargetPlatform().getOutFileExtension());
|
||||||
ByteArrayOutputStream kickAssOut = new ByteArrayOutputStream();
|
ByteArrayOutputStream kickAssOut = new ByteArrayOutputStream();
|
||||||
System.setOut(new PrintStream(kickAssOut));
|
System.setOut(new PrintStream(kickAssOut));
|
||||||
int asmRes = -1;
|
int asmRes = -1;
|
||||||
@ -117,7 +106,6 @@ public class Pass5FixLongBranches extends Pass5AsmOptimization {
|
|||||||
// Found line number
|
// Found line number
|
||||||
//getLog().append("Found long branch line number "+contextLineIdx);
|
//getLog().append("Found long branch line number "+contextLineIdx);
|
||||||
if(fixLongBranch(contextLineIdx - 1)) {
|
if(fixLongBranch(contextLineIdx - 1)) {
|
||||||
removeTmpDir();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -125,25 +113,9 @@ public class Pass5FixLongBranches extends Pass5AsmOptimization {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeTmpDir();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeTmpDir() {
|
|
||||||
// Delete the temporary directory with folders
|
|
||||||
String[]entries = tmpDir.toFile().list();
|
|
||||||
for(String s: entries){
|
|
||||||
File currentFile = new File(tmpDir.toFile(),s);
|
|
||||||
if(!currentFile.delete()) {
|
|
||||||
System.err.println("Warning! Cannot delete temporary file "+currentFile.getAbsolutePath());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!tmpDir.toFile().delete()) {
|
|
||||||
System.err.println("Warning! Cannot delete temporary folder "+tmpDir.toAbsolutePath());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fix a long branch detected at a specific ASM index
|
* Fix a long branch detected at a specific ASM index
|
||||||
*
|
*
|
||||||
@ -202,9 +174,9 @@ public class Pass5FixLongBranches extends Pass5AsmOptimization {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public File writeOutputFile(String fileName, String extension, String outputString) throws IOException {
|
private File writeOutputFile(Path tmpDir, String fileName, String extension, String outputString) throws IOException {
|
||||||
// Write output file
|
// Write output file
|
||||||
File file = getTmpFile(fileName, extension);
|
File file = getTmpFile(tmpDir, fileName, extension);
|
||||||
FileOutputStream outputStream = new FileOutputStream(file);
|
FileOutputStream outputStream = new FileOutputStream(file);
|
||||||
OutputStreamWriter writer = new OutputStreamWriter(outputStream);
|
OutputStreamWriter writer = new OutputStreamWriter(outputStream);
|
||||||
writer.write(outputString);
|
writer.write(outputString);
|
||||||
@ -214,12 +186,12 @@ public class Pass5FixLongBranches extends Pass5AsmOptimization {
|
|||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
public File getTmpFile(String fileName, String extension) {
|
private static File getTmpFile(Path tmpDir, String fileName, String extension) {
|
||||||
Path kcPath = FileSystems.getDefault().getPath(fileName);
|
Path kcPath = FileSystems.getDefault().getPath(fileName);
|
||||||
return new File(tmpDir.toFile(), kcPath.getFileName().toString() + extension);
|
return new File(tmpDir.toFile(), kcPath.getFileName().toString() + extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
public File getTmpFile(String fileName) {
|
private static File getTmpFile(Path tmpDir, String fileName) {
|
||||||
return new File(tmpDir.toFile(), fileName );
|
return new File(tmpDir.toFile(), fileName );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package dk.camelot64.kickc.test;
|
package dk.camelot64.kickc.test;
|
||||||
|
|
||||||
|
import dk.camelot64.kickc.TmpDirManager;
|
||||||
import kickass.KickAssembler65CE02;
|
import kickass.KickAssembler65CE02;
|
||||||
import kickass.nonasm.c64.CharToPetsciiConverter;
|
import kickass.nonasm.c64.CharToPetsciiConverter;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -19,16 +20,22 @@ public class TestKickAssRun {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testKickAssRun() throws IOException, URISyntaxException {
|
public void testKickAssRun() throws IOException, URISyntaxException {
|
||||||
|
TmpDirManager.init(new File("").toPath());
|
||||||
|
|
||||||
ReferenceHelper asmHelper = new ReferenceHelperFolder("src/test/java/dk/camelot64/kickc/test/");
|
ReferenceHelper asmHelper = new ReferenceHelperFolder("src/test/java/dk/camelot64/kickc/test/");
|
||||||
URI asmUri = asmHelper.loadReferenceFile("kickasstest", ".asm");
|
URI asmUri = asmHelper.loadReferenceFile("kickasstest", ".asm");
|
||||||
Path asmPath = Paths.get(asmUri);
|
Path asmPath = Paths.get(asmUri);
|
||||||
File asmPrgFile = getTmpFile("kickasstest", ".prg");
|
|
||||||
|
Path tmpDir = TmpDirManager.MANAGER.newTmpDir();
|
||||||
|
File asmFile = getTmpFile(tmpDir, "kickasstest", ".asm");
|
||||||
|
File asmPrgFile = getTmpFile(tmpDir, "kickasstest", ".prg");
|
||||||
|
Files.copy(asmPath, asmFile.toPath());
|
||||||
ByteArrayOutputStream kickAssOut = new ByteArrayOutputStream();
|
ByteArrayOutputStream kickAssOut = new ByteArrayOutputStream();
|
||||||
System.setOut(new PrintStream(kickAssOut));
|
System.setOut(new PrintStream(kickAssOut));
|
||||||
try {
|
try {
|
||||||
CharToPetsciiConverter.setCurrentEncoding("screencode_mixed");
|
CharToPetsciiConverter.setCurrentEncoding("screencode_mixed");
|
||||||
KickAssembler65CE02.main2(new String[]{asmPath.toAbsolutePath().toString(), "-o", asmPrgFile.getAbsolutePath()});
|
KickAssembler65CE02.main2(new String[]{asmFile.getAbsolutePath(), "-o", asmPrgFile.getAbsolutePath()});
|
||||||
} catch (AssertionError e) {
|
} catch(AssertionError e) {
|
||||||
System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out)));
|
System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out)));
|
||||||
String output = kickAssOut.toString();
|
String output = kickAssOut.toString();
|
||||||
System.out.println(output);
|
System.out.println(output);
|
||||||
@ -38,11 +45,11 @@ public class TestKickAssRun {
|
|||||||
}
|
}
|
||||||
String output = kickAssOut.toString();
|
String output = kickAssOut.toString();
|
||||||
System.out.println(output);
|
System.out.println(output);
|
||||||
|
|
||||||
|
TmpDirManager.MANAGER.cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static File getTmpFile(Path tmpDir, String fileName, String extension) throws IOException {
|
||||||
public File getTmpFile(String fileName, String extension) throws IOException {
|
|
||||||
Path tmpDir = Files.createTempDirectory("kickc");
|
|
||||||
Path kcPath = FileSystems.getDefault().getPath(fileName);
|
Path kcPath = FileSystems.getDefault().getPath(fileName);
|
||||||
return new File(tmpDir.toFile(), kcPath.getFileName().toString() + extension);
|
return new File(tmpDir.toFile(), kcPath.getFileName().toString() + extension);
|
||||||
}
|
}
|
||||||
@ -90,7 +97,7 @@ public class TestKickAssRun {
|
|||||||
private void printPetscii(String encoding, char ch, String sCh) {
|
private void printPetscii(String encoding, char ch, String sCh) {
|
||||||
CharToPetsciiConverter.setCurrentEncoding(encoding);
|
CharToPetsciiConverter.setCurrentEncoding(encoding);
|
||||||
Byte petscii = CharToPetsciiConverter.convert(ch);
|
Byte petscii = CharToPetsciiConverter.convert(ch);
|
||||||
System.out.println(encoding+": "+sCh+" > "+(petscii==null?"null":(int)petscii));
|
System.out.println(encoding + ": " + sCh + " > " + (petscii == null ? "null" : (int) petscii));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ package dk.camelot64.kickc.test;
|
|||||||
import dk.camelot64.kickc.CompileLog;
|
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.TmpDirManager;
|
||||||
import dk.camelot64.kickc.asm.AsmProgram;
|
import dk.camelot64.kickc.asm.AsmProgram;
|
||||||
import dk.camelot64.kickc.model.CompileError;
|
import dk.camelot64.kickc.model.CompileError;
|
||||||
import dk.camelot64.kickc.model.Program;
|
import dk.camelot64.kickc.model.Program;
|
||||||
@ -74,6 +75,7 @@ public class TestPrograms {
|
|||||||
public void testAtariXlMd5b() throws IOException, URISyntaxException {
|
public void testAtariXlMd5b() throws IOException, URISyntaxException {
|
||||||
compileAndCompare("atarixl-md5b.c");
|
compileAndCompare("atarixl-md5b.c");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAtariXlMd5() throws IOException, URISyntaxException {
|
public void testAtariXlMd5() throws IOException, URISyntaxException {
|
||||||
compileAndCompare("atarixl-md5.c");
|
compileAndCompare("atarixl-md5.c");
|
||||||
@ -4828,10 +4830,13 @@ public class TestPrograms {
|
|||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
public static void setUp() {
|
public static void setUp() {
|
||||||
|
TmpDirManager.init(new File("").toPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterAll
|
@AfterAll
|
||||||
public static void tearDown() {
|
public static void tearDown() {
|
||||||
|
if(TmpDirManager.MANAGER != null)
|
||||||
|
TmpDirManager.MANAGER.cleanup();
|
||||||
//AsmFragmentTemplateUsages.logUsages(log, false, false, false, false, false, false);
|
//AsmFragmentTemplateUsages.logUsages(log, false, false, false, false, false, false);
|
||||||
//printGCStats();
|
//printGCStats();
|
||||||
}
|
}
|
||||||
|
26
src/test/ref/inline-asm-uses-problem-2.asm
Normal file
26
src/test/ref/inline-asm-uses-problem-2.asm
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Demonstrates problem with inline ASM usages - and early-detect constants
|
||||||
|
// zp2 should be forced to live at address $fc - but is identified to be constant by Pass1EarlyConstantIdentification
|
||||||
|
.pc = $801 "Basic"
|
||||||
|
:BasicUpstart(main)
|
||||||
|
.pc = $80d "Program"
|
||||||
|
main: {
|
||||||
|
.label zp2 = $fc
|
||||||
|
// zp2 = 0x0400
|
||||||
|
lda #<$400
|
||||||
|
sta.z zp2
|
||||||
|
lda #>$400
|
||||||
|
sta.z zp2+1
|
||||||
|
// zp2[1] = '*'
|
||||||
|
lda #'*'
|
||||||
|
ldy #1
|
||||||
|
sta (zp2),y
|
||||||
|
// asm
|
||||||
|
lda #$28
|
||||||
|
sta zp2
|
||||||
|
// zp2[2] = '*'
|
||||||
|
lda #'*'
|
||||||
|
ldy #2
|
||||||
|
sta (zp2),y
|
||||||
|
// }
|
||||||
|
rts
|
||||||
|
}
|
11
src/test/ref/inline-asm-uses-problem-2.cfg
Normal file
11
src/test/ref/inline-asm-uses-problem-2.cfg
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
void main()
|
||||||
|
main: scope:[main] from
|
||||||
|
[0] main::zp2 = (byte*) 1024
|
||||||
|
[1] main::zp2[1] = '*'
|
||||||
|
asm { lda#$28 stazp2 }
|
||||||
|
[3] main::zp2[2] = '*'
|
||||||
|
to:main::@return
|
||||||
|
main::@return: scope:[main] from main
|
||||||
|
[4] return
|
||||||
|
to:@return
|
176
src/test/ref/inline-asm-uses-problem-2.log
Normal file
176
src/test/ref/inline-asm-uses-problem-2.log
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
Setting inferred volatile on symbol affected by address-of: main::zp2 in asm { lda#$28 stazp2 }
|
||||||
|
|
||||||
|
CONTROL FLOW GRAPH SSA
|
||||||
|
|
||||||
|
void main()
|
||||||
|
main: scope:[main] from __start
|
||||||
|
main::zp2 = (byte*)$400
|
||||||
|
main::zp2[1] = '*'
|
||||||
|
asm { lda#$28 stazp2 }
|
||||||
|
main::zp2[2] = '*'
|
||||||
|
to:main::@return
|
||||||
|
main::@return: scope:[main] from main
|
||||||
|
return
|
||||||
|
to:@return
|
||||||
|
|
||||||
|
void __start()
|
||||||
|
__start: scope:[__start] from
|
||||||
|
call main
|
||||||
|
to:__start::@1
|
||||||
|
__start::@1: scope:[__start] from __start
|
||||||
|
to:__start::@return
|
||||||
|
__start::@return: scope:[__start] from __start::@1
|
||||||
|
return
|
||||||
|
to:@return
|
||||||
|
|
||||||
|
SYMBOL TABLE SSA
|
||||||
|
void __start()
|
||||||
|
void main()
|
||||||
|
volatile byte* main::zp2 loadstore !zp[-1]:252
|
||||||
|
|
||||||
|
Adding number conversion cast (unumber) 1 in main::zp2[1] = '*'
|
||||||
|
Adding number conversion cast (unumber) 2 in main::zp2[2] = '*'
|
||||||
|
Successful SSA optimization PassNAddNumberTypeConversions
|
||||||
|
Simplifying constant pointer cast (byte*) 1024
|
||||||
|
Simplifying constant integer cast 1
|
||||||
|
Simplifying constant integer cast 2
|
||||||
|
Successful SSA optimization PassNCastSimplification
|
||||||
|
Finalized unsigned number type 1
|
||||||
|
Finalized unsigned number type 2
|
||||||
|
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||||
|
Removing unused procedure __start
|
||||||
|
Removing unused procedure block __start
|
||||||
|
Removing unused procedure block __start::@1
|
||||||
|
Removing unused procedure block __start::@return
|
||||||
|
Successful SSA optimization PassNEliminateEmptyStart
|
||||||
|
CALL GRAPH
|
||||||
|
|
||||||
|
Created 0 initial phi equivalence classes
|
||||||
|
Coalesced down to 0 phi equivalence classes
|
||||||
|
|
||||||
|
FINAL CONTROL FLOW GRAPH
|
||||||
|
|
||||||
|
void main()
|
||||||
|
main: scope:[main] from
|
||||||
|
[0] main::zp2 = (byte*) 1024
|
||||||
|
[1] main::zp2[1] = '*'
|
||||||
|
asm { lda#$28 stazp2 }
|
||||||
|
[3] main::zp2[2] = '*'
|
||||||
|
to:main::@return
|
||||||
|
main::@return: scope:[main] from main
|
||||||
|
[4] return
|
||||||
|
to:@return
|
||||||
|
|
||||||
|
|
||||||
|
VARIABLE REGISTER WEIGHTS
|
||||||
|
void main()
|
||||||
|
volatile byte* main::zp2 loadstore !zp[-1]:252 2.0
|
||||||
|
|
||||||
|
Initial phi equivalence classes
|
||||||
|
Added variable main::zp2 to live range equivalence class [ main::zp2 ]
|
||||||
|
Complete equivalence classes
|
||||||
|
[ main::zp2 ]
|
||||||
|
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||||
|
Statement [0] main::zp2 = (byte*) 1024 [ main::zp2 ] ( [ main::zp2 ] { } ) always clobbers reg byte a
|
||||||
|
Statement [1] main::zp2[1] = '*' [ main::zp2 ] ( [ main::zp2 ] { } ) always clobbers reg byte a reg byte y
|
||||||
|
Statement asm { lda#$28 stazp2 } always clobbers reg byte a
|
||||||
|
Statement [3] main::zp2[2] = '*' [ ] ( [ ] { } ) always clobbers reg byte a reg byte y
|
||||||
|
Potential registers zp[2]:252 [ main::zp2 ] : zp[2]:252 ,
|
||||||
|
|
||||||
|
REGISTER UPLIFT SCOPES
|
||||||
|
Uplift Scope [main] 2: zp[2]:252 [ main::zp2 ]
|
||||||
|
Uplift Scope []
|
||||||
|
|
||||||
|
Uplifting [main] best 45 combination zp[2]:252 [ main::zp2 ]
|
||||||
|
Uplifting [] best 45 combination
|
||||||
|
|
||||||
|
ASSEMBLER BEFORE OPTIMIZATION
|
||||||
|
// File Comments
|
||||||
|
// Demonstrates problem with inline ASM usages - and early-detect constants
|
||||||
|
// zp2 should be forced to live at address $fc - but is identified to be constant by Pass1EarlyConstantIdentification
|
||||||
|
// Upstart
|
||||||
|
.pc = $801 "Basic"
|
||||||
|
:BasicUpstart(main)
|
||||||
|
.pc = $80d "Program"
|
||||||
|
// Global Constants & labels
|
||||||
|
// main
|
||||||
|
main: {
|
||||||
|
.label zp2 = $fc
|
||||||
|
// [0] main::zp2 = (byte*) 1024 -- pbuz1=pbuc1
|
||||||
|
lda #<$400
|
||||||
|
sta.z zp2
|
||||||
|
lda #>$400
|
||||||
|
sta.z zp2+1
|
||||||
|
// [1] main::zp2[1] = '*' -- pbuz1_derefidx_vbuc1=vbuc2
|
||||||
|
lda #'*'
|
||||||
|
ldy #1
|
||||||
|
sta (zp2),y
|
||||||
|
// asm { lda#$28 stazp2 }
|
||||||
|
lda #$28
|
||||||
|
sta zp2
|
||||||
|
// [3] main::zp2[2] = '*' -- pbuz1_derefidx_vbuc1=vbuc2
|
||||||
|
lda #'*'
|
||||||
|
ldy #2
|
||||||
|
sta (zp2),y
|
||||||
|
jmp __breturn
|
||||||
|
// main::@return
|
||||||
|
__breturn:
|
||||||
|
// [4] return
|
||||||
|
rts
|
||||||
|
}
|
||||||
|
// File Data
|
||||||
|
|
||||||
|
ASSEMBLER OPTIMIZATIONS
|
||||||
|
Removing instruction jmp __breturn
|
||||||
|
Succesful ASM optimization Pass5NextJumpElimination
|
||||||
|
Removing instruction __breturn:
|
||||||
|
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||||
|
|
||||||
|
FINAL SYMBOL TABLE
|
||||||
|
void main()
|
||||||
|
volatile byte* main::zp2 loadstore !zp[-1]:252 zp[2]:252 2.0
|
||||||
|
|
||||||
|
zp[2]:252 [ main::zp2 ]
|
||||||
|
|
||||||
|
|
||||||
|
FINAL ASSEMBLER
|
||||||
|
Score: 42
|
||||||
|
|
||||||
|
// File Comments
|
||||||
|
// Demonstrates problem with inline ASM usages - and early-detect constants
|
||||||
|
// zp2 should be forced to live at address $fc - but is identified to be constant by Pass1EarlyConstantIdentification
|
||||||
|
// Upstart
|
||||||
|
.pc = $801 "Basic"
|
||||||
|
:BasicUpstart(main)
|
||||||
|
.pc = $80d "Program"
|
||||||
|
// Global Constants & labels
|
||||||
|
// main
|
||||||
|
main: {
|
||||||
|
.label zp2 = $fc
|
||||||
|
// zp2 = 0x0400
|
||||||
|
// [0] main::zp2 = (byte*) 1024 -- pbuz1=pbuc1
|
||||||
|
lda #<$400
|
||||||
|
sta.z zp2
|
||||||
|
lda #>$400
|
||||||
|
sta.z zp2+1
|
||||||
|
// zp2[1] = '*'
|
||||||
|
// [1] main::zp2[1] = '*' -- pbuz1_derefidx_vbuc1=vbuc2
|
||||||
|
lda #'*'
|
||||||
|
ldy #1
|
||||||
|
sta (zp2),y
|
||||||
|
// asm
|
||||||
|
// asm { lda#$28 stazp2 }
|
||||||
|
lda #$28
|
||||||
|
sta zp2
|
||||||
|
// zp2[2] = '*'
|
||||||
|
// [3] main::zp2[2] = '*' -- pbuz1_derefidx_vbuc1=vbuc2
|
||||||
|
lda #'*'
|
||||||
|
ldy #2
|
||||||
|
sta (zp2),y
|
||||||
|
// main::@return
|
||||||
|
// }
|
||||||
|
// [4] return
|
||||||
|
rts
|
||||||
|
}
|
||||||
|
// File Data
|
||||||
|
|
4
src/test/ref/inline-asm-uses-problem-2.sym
Normal file
4
src/test/ref/inline-asm-uses-problem-2.sym
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
void main()
|
||||||
|
volatile byte* main::zp2 loadstore !zp[-1]:252 zp[2]:252 2.0
|
||||||
|
|
||||||
|
zp[2]:252 [ main::zp2 ]
|
Loading…
Reference in New Issue
Block a user