mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-08-09 04:25:12 +00:00
Implemented target platform defines by putting the handling of #pragma target() into the preprocessor/parser.
This commit is contained in:
@@ -6,6 +6,7 @@ import dk.camelot64.kickc.fragment.AsmFragmentTemplateUsages;
|
|||||||
import dk.camelot64.kickc.model.*;
|
import dk.camelot64.kickc.model.*;
|
||||||
import dk.camelot64.kickc.model.statements.StatementSource;
|
import dk.camelot64.kickc.model.statements.StatementSource;
|
||||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||||
|
import dk.camelot64.kickc.parser.CTargetPlatformParser;
|
||||||
import kickass.KickAssembler;
|
import kickass.KickAssembler;
|
||||||
import kickass.nonasm.c64.CharToPetsciiConverter;
|
import kickass.nonasm.c64.CharToPetsciiConverter;
|
||||||
import picocli.CommandLine;
|
import picocli.CommandLine;
|
||||||
@@ -156,7 +157,7 @@ public class KickC implements Callable<Integer> {
|
|||||||
private boolean interleaveIclFile = false;
|
private boolean interleaveIclFile = false;
|
||||||
|
|
||||||
@CommandLine.Option(names = {"-p", "-t", "-target", "-platform"}, description = "The target platform. Default is C64 with BASIC upstart. See #pragma target")
|
@CommandLine.Option(names = {"-p", "-t", "-target", "-platform"}, description = "The target platform. Default is C64 with BASIC upstart. See #pragma target")
|
||||||
private String targetPlatform = null;
|
private String targetPlatform = TargetPlatform.DEFAULT_NAME;
|
||||||
|
|
||||||
@CommandLine.Option(names = {"-cpu"}, description = "The target CPU. Default is 6502 with illegal opcodes. See #pragma cpu")
|
@CommandLine.Option(names = {"-cpu"}, description = "The target CPU. Default is 6502 with illegal opcodes. See #pragma cpu")
|
||||||
private String cpu = null;
|
private String cpu = null;
|
||||||
@@ -228,18 +229,15 @@ public class KickC implements Callable<Integer> {
|
|||||||
|
|
||||||
// Set up Target Platform
|
// Set up Target Platform
|
||||||
try {
|
try {
|
||||||
if(targetPlatform != null) {
|
final File platformFile = SourceLoader.loadFile(targetPlatform + "." + CTargetPlatformParser.FILE_EXTENSION, currentPath, program.getTargetPlatformPaths());
|
||||||
TargetPlatform.setTargetPlatform(targetPlatform, currentPath, program, null);
|
final TargetPlatform targetPlatform = CTargetPlatformParser.parseTargetPlatformFile(this.targetPlatform, platformFile, currentPath, program.getTargetPlatformPaths());
|
||||||
} else {
|
program.setTargetPlatform(targetPlatform);
|
||||||
TargetPlatform.setTargetPlatform(TargetPlatform.DEFAULT_NAME, currentPath, program, null);
|
|
||||||
}
|
|
||||||
} catch(CompileError e) {
|
} catch(CompileError e) {
|
||||||
// Print the error and exit with compile error
|
// Print the error and exit with compile error
|
||||||
System.err.println(e.getMessage());
|
System.err.println(e.getMessage());
|
||||||
return COMPILE_ERROR;
|
return COMPILE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Update link script
|
// Update link script
|
||||||
if(linkScript != null) {
|
if(linkScript != null) {
|
||||||
program.getTargetPlatform().setLinkScriptFile(SourceLoader.loadFile(linkScript, currentPath, program.getTargetPlatformPaths()));
|
program.getTargetPlatform().setLinkScriptFile(SourceLoader.loadFile(linkScript, currentPath, program.getTargetPlatformPaths()));
|
||||||
@@ -350,9 +348,9 @@ public class KickC implements Callable<Integer> {
|
|||||||
cFiles.stream().forEach(path -> CFileNames.append(path.toString()).append(" "));
|
cFiles.stream().forEach(path -> CFileNames.append(path.toString()).append(" "));
|
||||||
|
|
||||||
Map<String, String> effectiveDefines = new LinkedHashMap<>();
|
Map<String, String> effectiveDefines = new LinkedHashMap<>();
|
||||||
if(defines!=null)
|
if(defines != null)
|
||||||
effectiveDefines.putAll(defines);
|
effectiveDefines.putAll(defines);
|
||||||
if(program.getTargetPlatform().getDefines()!=null)
|
if(program.getTargetPlatform().getDefines() != null)
|
||||||
effectiveDefines.putAll(program.getTargetPlatform().getDefines());
|
effectiveDefines.putAll(program.getTargetPlatform().getDefines());
|
||||||
|
|
||||||
if(preprocess) {
|
if(preprocess) {
|
||||||
|
@@ -1,22 +1,7 @@
|
|||||||
package dk.camelot64.kickc.model;
|
package dk.camelot64.kickc.model;
|
||||||
|
|
||||||
import dk.camelot64.kickc.SourceLoader;
|
|
||||||
import dk.camelot64.kickc.model.statements.StatementSource;
|
|
||||||
|
|
||||||
import javax.json.Json;
|
|
||||||
import javax.json.JsonObject;
|
|
||||||
import javax.json.JsonReader;
|
|
||||||
import javax.json.JsonValue;
|
|
||||||
import javax.json.stream.JsonParsingException;
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The target platform the compiler is creating a program for.
|
* The target platform the compiler is creating a program for.
|
||||||
@@ -29,9 +14,6 @@ public class TargetPlatform {
|
|||||||
/** The name of the default target platform. */
|
/** The name of the default target platform. */
|
||||||
public static String DEFAULT_NAME = "c64basic";
|
public static String DEFAULT_NAME = "c64basic";
|
||||||
|
|
||||||
/** The file extension used for target platform files. */
|
|
||||||
public static final String FILE_EXTENSION = "tgt";
|
|
||||||
|
|
||||||
/** The platform name. */
|
/** The platform name. */
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@@ -91,56 +73,5 @@ public class TargetPlatform {
|
|||||||
this.defines = defines;
|
this.defines = defines;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the target platform from a platform name
|
|
||||||
*
|
|
||||||
* @param platformName The platform name
|
|
||||||
* @param currentFolder The current folder (added to the search path)
|
|
||||||
* @param program The program.
|
|
||||||
* @param statementSource The source file & line used for errors
|
|
||||||
*/
|
|
||||||
public static void setTargetPlatform(String platformName, Path currentFolder, Program program, StatementSource statementSource) {
|
|
||||||
final File platformFile = SourceLoader.loadFile(platformName + "." + FILE_EXTENSION, currentFolder, program.getTargetPlatformPaths());
|
|
||||||
if(platformFile != null) {
|
|
||||||
// Set the target platform
|
|
||||||
try {
|
|
||||||
final JsonReader jsonReader = Json.createReader(new BufferedInputStream(new FileInputStream(platformFile)));
|
|
||||||
final JsonObject platformJson = jsonReader.readObject();
|
|
||||||
TargetPlatform targetPlatform = new TargetPlatform(platformName);
|
|
||||||
final String cpuName = platformJson.getString("cpu", null);
|
|
||||||
if(cpuName != null)
|
|
||||||
targetPlatform.setCpu(TargetCpu.getTargetCpu(cpuName, false));
|
|
||||||
final String linkScriptName = platformJson.getString("link", null);
|
|
||||||
if(linkScriptName != null)
|
|
||||||
targetPlatform.setLinkScriptFile(SourceLoader.loadFile(linkScriptName, currentFolder, program.getTargetPlatformPaths()));
|
|
||||||
final String emulatorCommand = platformJson.getString("emulator", null);
|
|
||||||
if(emulatorCommand != null)
|
|
||||||
targetPlatform.setEmulatorCommand(emulatorCommand);
|
|
||||||
final JsonObject defines = platformJson.getJsonObject("defines");
|
|
||||||
if(defines!=null) {
|
|
||||||
final Set<String> macroNames = defines.keySet();
|
|
||||||
final LinkedHashMap<String, String> macros = new LinkedHashMap<>();
|
|
||||||
for(String macroName : macroNames) {
|
|
||||||
final JsonValue jsonValue = defines.get(macroName);
|
|
||||||
final String macroBody = jsonValue.toString();
|
|
||||||
macros.put(macroName, macroBody);
|
|
||||||
}
|
|
||||||
targetPlatform.setDefines(macros);
|
|
||||||
}
|
|
||||||
program.setTargetPlatform(targetPlatform);
|
|
||||||
} catch(CompileError | IOException | JsonParsingException e) {
|
|
||||||
throw new CompileError("Error parsing target platform file " + platformFile.getAbsolutePath() + "\n"+e.getMessage(), statementSource);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
StringBuilder supported = new StringBuilder();
|
|
||||||
final List<File> platformFiles = SourceLoader.listFiles(currentFolder, program.getTargetPlatformPaths(), FILE_EXTENSION);
|
|
||||||
for(File file : platformFiles) {
|
|
||||||
String name = file.getName();
|
|
||||||
name = name.substring(0, name.length()- FILE_EXTENSION.length()-1);
|
|
||||||
supported.append(name).append(" ");
|
|
||||||
}
|
|
||||||
throw new CompileError("Unknown target platform '"+platformName+"'. Supported: " + supported.toString(), statementSource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,7 @@ import dk.camelot64.kickc.Compiler;
|
|||||||
import dk.camelot64.kickc.SourceLoader;
|
import dk.camelot64.kickc.SourceLoader;
|
||||||
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.preprocessor.CPreprocessor;
|
import dk.camelot64.kickc.preprocessor.CPreprocessor;
|
||||||
import org.antlr.v4.runtime.*;
|
import org.antlr.v4.runtime.*;
|
||||||
|
|
||||||
@@ -65,7 +66,7 @@ public class CParser {
|
|||||||
this.program = program;
|
this.program = program;
|
||||||
this.cFiles = new LinkedHashMap<>();
|
this.cFiles = new LinkedHashMap<>();
|
||||||
this.cTokenSource = new CTokenSource();
|
this.cTokenSource = new CTokenSource();
|
||||||
this.preprocessor = new CPreprocessor(cTokenSource, new HashMap<>());
|
this.preprocessor = new CPreprocessor(this, cTokenSource, new HashMap<>());
|
||||||
this.preprocessedTokenStream = new CommonTokenStream(preprocessor);
|
this.preprocessedTokenStream = new CommonTokenStream(preprocessor);
|
||||||
this.parser = new KickCParser(preprocessedTokenStream, this);
|
this.parser = new KickCParser(preprocessedTokenStream, this);
|
||||||
this.typedefs = new ArrayList<>();
|
this.typedefs = new ArrayList<>();
|
||||||
@@ -103,6 +104,7 @@ public class CParser {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Define a new macro
|
* Define a new macro
|
||||||
|
*
|
||||||
* @param macroName The macro name
|
* @param macroName The macro name
|
||||||
* @param macroBody The macro body
|
* @param macroBody The macro body
|
||||||
*/
|
*/
|
||||||
@@ -115,6 +117,7 @@ public class CParser {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Undef a macro
|
* Undef a macro
|
||||||
|
*
|
||||||
* @param macroName The macro name
|
* @param macroName The macro name
|
||||||
*/
|
*/
|
||||||
public void undef(String macroName) {
|
public void undef(String macroName) {
|
||||||
@@ -158,7 +161,7 @@ public class CParser {
|
|||||||
*
|
*
|
||||||
* @return The path of the folder containing the source file currently being tokenized
|
* @return The path of the folder containing the source file currently being tokenized
|
||||||
*/
|
*/
|
||||||
private Path getCurrentSourceFolderPath() {
|
public Path getCurrentSourceFolderPath() {
|
||||||
TokenSource currentSource = cTokenSource.getCurrentSource();
|
TokenSource currentSource = cTokenSource.getCurrentSource();
|
||||||
String sourceName = currentSource.getSourceName();
|
String sourceName = currentSource.getSourceName();
|
||||||
CFile cFile = cFiles.get(sourceName);
|
CFile cFile = cFiles.get(sourceName);
|
||||||
@@ -224,6 +227,34 @@ public class CParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void loadTargetPlatform(String platformName, Path currentPath) {
|
||||||
|
final File platformFile = SourceLoader.loadFile(platformName + "." + CTargetPlatformParser.FILE_EXTENSION, currentPath, program.getTargetPlatformPaths());
|
||||||
|
if(platformFile != null) {
|
||||||
|
final TargetPlatform targetPlatform = CTargetPlatformParser.parseTargetPlatformFile(platformName, platformFile, currentPath, program.getTargetPlatformPaths());
|
||||||
|
// Remove macros from existing platform!
|
||||||
|
if(program.getTargetPlatform() != null && program.getTargetPlatform().getDefines() != null)
|
||||||
|
for(String macroName : program.getTargetPlatform().getDefines().keySet())
|
||||||
|
preprocessor.undef(macroName);
|
||||||
|
// Set the new program platform
|
||||||
|
program.setTargetPlatform(targetPlatform);
|
||||||
|
// Define macros from new platform!
|
||||||
|
if(program.getTargetPlatform().getDefines() != null)
|
||||||
|
for(String macroName : program.getTargetPlatform().getDefines().keySet())
|
||||||
|
define(macroName, program.getTargetPlatform().getDefines().get(macroName));
|
||||||
|
// Re-initialize ASM fragment synthesizer
|
||||||
|
program.initAsmFragmentSynthesizer();
|
||||||
|
} else {
|
||||||
|
StringBuilder supported = new StringBuilder();
|
||||||
|
final List<File> platformFiles = SourceLoader.listFiles(currentPath, program.getTargetPlatformPaths(), CTargetPlatformParser.FILE_EXTENSION);
|
||||||
|
for(File file : platformFiles) {
|
||||||
|
String name = file.getName();
|
||||||
|
name = name.substring(0, name.length() - CTargetPlatformParser.FILE_EXTENSION.length() - 1);
|
||||||
|
supported.append(name).append(" ");
|
||||||
|
}
|
||||||
|
throw new CompileError("Unknown target platform '" + platformName + "'. Supported: " + supported.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a lexer for a char stream
|
* Make a lexer for a char stream
|
||||||
*
|
*
|
||||||
|
@@ -0,0 +1,64 @@
|
|||||||
|
package dk.camelot64.kickc.parser;
|
||||||
|
|
||||||
|
import dk.camelot64.kickc.SourceLoader;
|
||||||
|
import dk.camelot64.kickc.model.CompileError;
|
||||||
|
import dk.camelot64.kickc.model.TargetCpu;
|
||||||
|
import dk.camelot64.kickc.model.TargetPlatform;
|
||||||
|
|
||||||
|
import javax.json.Json;
|
||||||
|
import javax.json.JsonObject;
|
||||||
|
import javax.json.JsonReader;
|
||||||
|
import javax.json.JsonValue;
|
||||||
|
import javax.json.stream.JsonParsingException;
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parser for target platform files xxx.tgt.
|
||||||
|
* The file format is JSON.
|
||||||
|
*/
|
||||||
|
public class CTargetPlatformParser {
|
||||||
|
|
||||||
|
/** The file extension used for target platform files. */
|
||||||
|
public static final String FILE_EXTENSION = "tgt";
|
||||||
|
|
||||||
|
|
||||||
|
public static TargetPlatform parseTargetPlatformFile(String platformName, File platformFile, Path currentFolder, List<String> platformSearchPaths) {
|
||||||
|
try {
|
||||||
|
final JsonReader jsonReader = Json.createReader(new BufferedInputStream(new FileInputStream(platformFile)));
|
||||||
|
final JsonObject platformJson = jsonReader.readObject();
|
||||||
|
TargetPlatform targetPlatform = new TargetPlatform(platformName);
|
||||||
|
final String cpuName = platformJson.getString("cpu", null);
|
||||||
|
if(cpuName != null)
|
||||||
|
targetPlatform.setCpu(TargetCpu.getTargetCpu(cpuName, false));
|
||||||
|
final String linkScriptName = platformJson.getString("link", null);
|
||||||
|
if(linkScriptName != null)
|
||||||
|
targetPlatform.setLinkScriptFile(SourceLoader.loadFile(linkScriptName, currentFolder, platformSearchPaths));
|
||||||
|
final String emulatorCommand = platformJson.getString("emulator", null);
|
||||||
|
if(emulatorCommand != null)
|
||||||
|
targetPlatform.setEmulatorCommand(emulatorCommand);
|
||||||
|
final JsonObject defines = platformJson.getJsonObject("defines");
|
||||||
|
if(defines != null) {
|
||||||
|
final Set<String> macroNames = defines.keySet();
|
||||||
|
final LinkedHashMap<String, String> macros = new LinkedHashMap<>();
|
||||||
|
for(String macroName : macroNames) {
|
||||||
|
final JsonValue jsonValue = defines.get(macroName);
|
||||||
|
final String macroBody = jsonValue.toString();
|
||||||
|
macros.put(macroName, macroBody);
|
||||||
|
}
|
||||||
|
targetPlatform.setDefines(macros);
|
||||||
|
}
|
||||||
|
return targetPlatform;
|
||||||
|
} catch(CompileError | IOException | JsonParsingException e) {
|
||||||
|
throw new CompileError("Error parsing target platform file " + platformFile.getAbsolutePath() + "\n" + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@@ -179,21 +179,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitGlobalDirectivePlatform(KickCParser.GlobalDirectivePlatformContext ctx) {
|
public Object visitGlobalDirectivePlatform(KickCParser.GlobalDirectivePlatformContext ctx) {
|
||||||
final String platformName = ctx.NAME().getText();
|
throw new InternalError("Error! #pragma target() should be handled in preprocessor!");
|
||||||
final Path currentFolder = cParser.getSourceFolderPath(ctx);
|
|
||||||
final StatementSource statementSource = new StatementSource(ctx);
|
|
||||||
// Remove macros from existing platform!
|
|
||||||
if(program.getTargetPlatform().getDefines() !=null)
|
|
||||||
for(String macroName : program.getTargetPlatform().getDefines().keySet())
|
|
||||||
cParser.undef(macroName);
|
|
||||||
TargetPlatform.setTargetPlatform(platformName, currentFolder, program, statementSource);
|
|
||||||
// Define macros from new platform!
|
|
||||||
if(program.getTargetPlatform().getDefines() !=null)
|
|
||||||
for(String macroName : program.getTargetPlatform().getDefines().keySet())
|
|
||||||
cParser.define(macroName, program.getTargetPlatform().getDefines().get(macroName));
|
|
||||||
// Update the ASM fragment synthesizer to match the new CPU
|
|
||||||
program.initAsmFragmentSynthesizer();
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -22,6 +22,9 @@ import java.util.*;
|
|||||||
*/
|
*/
|
||||||
public class CPreprocessor implements TokenSource {
|
public class CPreprocessor implements TokenSource {
|
||||||
|
|
||||||
|
/** The CParser used for loading files. */
|
||||||
|
private CParser cParser;
|
||||||
|
|
||||||
/** The token source containing the input */
|
/** The token source containing the input */
|
||||||
private CTokenSource input;
|
private CTokenSource input;
|
||||||
|
|
||||||
@@ -47,7 +50,8 @@ public class CPreprocessor implements TokenSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public CPreprocessor(TokenSource input, Map<String, Macro> defines) {
|
public CPreprocessor(CParser cParser, TokenSource input, Map<String, Macro> defines) {
|
||||||
|
this.cParser = cParser;
|
||||||
if(input instanceof CTokenSource) {
|
if(input instanceof CTokenSource) {
|
||||||
// If possible use the input directly instead of wrapping it
|
// If possible use the input directly instead of wrapping it
|
||||||
this.input = (CTokenSource) input;
|
this.input = (CTokenSource) input;
|
||||||
@@ -135,12 +139,15 @@ public class CPreprocessor implements TokenSource {
|
|||||||
return true;
|
return true;
|
||||||
} else if(inputToken.getType() == KickCLexer.NAME) {
|
} else if(inputToken.getType() == KickCLexer.NAME) {
|
||||||
return expand(inputToken, cTokenSource);
|
return expand(inputToken, cTokenSource);
|
||||||
//} else if(inputToken.getType() == KickCLexer.PRAGMA) {
|
} else if(inputToken.getType() == KickCLexer.PRAGMA) {
|
||||||
// return pragma(inputToken, cTokenSource);
|
return pragma(inputToken, cTokenSource);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** #pragmas to be handled by the parser (skipped in the preprocessor). */
|
||||||
|
private List<Token> parserPragmas = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle any #pragma that must be handled by the preprocessor
|
* Handle any #pragma that must be handled by the preprocessor
|
||||||
*
|
*
|
||||||
@@ -149,13 +156,11 @@ public class CPreprocessor implements TokenSource {
|
|||||||
* @return true if the input token was preprocessed (and should not be added to the output). False if the token was not a preprocessor token
|
* @return true if the input token was preprocessed (and should not be added to the output). False if the token was not a preprocessor token
|
||||||
*/
|
*/
|
||||||
private boolean pragma(Token inputToken, CTokenSource cTokenSource) {
|
private boolean pragma(Token inputToken, CTokenSource cTokenSource) {
|
||||||
if(inputToken instanceof PragmaToken)
|
if(parserPragmas.contains(inputToken))
|
||||||
// Already examined by the preprocessor - and determined to be for the parser
|
// Already examined by the preprocessor - and determined to be for the parser
|
||||||
return false;
|
return false;
|
||||||
final List<Token> ws = skipWhitespace(cTokenSource);
|
final List<Token> ws = skipWhitespace(cTokenSource);
|
||||||
final Token pragmaType = cTokenSource.nextToken();
|
final Token pragmaType = cTokenSource.nextToken();
|
||||||
|
|
||||||
/*
|
|
||||||
if(KickCLexer.TARGET == pragmaType.getType()) {
|
if(KickCLexer.TARGET == pragmaType.getType()) {
|
||||||
skipWhitespace(cTokenSource);
|
skipWhitespace(cTokenSource);
|
||||||
nextToken(cTokenSource, KickCLexer.PAR_BEGIN);
|
nextToken(cTokenSource, KickCLexer.PAR_BEGIN);
|
||||||
@@ -163,15 +168,14 @@ public class CPreprocessor implements TokenSource {
|
|||||||
final String targetName = nextToken(cTokenSource, KickCLexer.NAME).getText();
|
final String targetName = nextToken(cTokenSource, KickCLexer.NAME).getText();
|
||||||
skipWhitespace(cTokenSource);
|
skipWhitespace(cTokenSource);
|
||||||
nextToken(cTokenSource, KickCLexer.PAR_END);
|
nextToken(cTokenSource, KickCLexer.PAR_END);
|
||||||
//TargetPlatform.setTargetPlatform(targetName, null, );
|
cParser.loadTargetPlatform(targetName, cParser.getCurrentSourceFolderPath());
|
||||||
throw new InternalError("TODO: Implement #pragma target");
|
return true;
|
||||||
// return true;
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
// Pass on the #pragma to the parser
|
// Pass on the #pragma to the parser
|
||||||
|
parserPragmas.add(inputToken);
|
||||||
final ArrayList<Token> pragmaTokens = new ArrayList<>();
|
final ArrayList<Token> pragmaTokens = new ArrayList<>();
|
||||||
pragmaTokens.add(new PragmaToken(inputToken));
|
pragmaTokens.add(inputToken);
|
||||||
pragmaTokens.addAll(ws);
|
pragmaTokens.addAll(ws);
|
||||||
pragmaTokens.add(pragmaType);
|
pragmaTokens.add(pragmaType);
|
||||||
cTokenSource.addSourceFirst(new ListTokenSource(pragmaTokens));
|
cTokenSource.addSourceFirst(new ListTokenSource(pragmaTokens));
|
||||||
@@ -280,7 +284,7 @@ public class CPreprocessor implements TokenSource {
|
|||||||
List<List<Token>> expandedParamValues = new ArrayList<>();
|
List<List<Token>> expandedParamValues = new ArrayList<>();
|
||||||
for(List<Token> paramTokens : paramValues) {
|
for(List<Token> paramTokens : paramValues) {
|
||||||
List<Token> expandedParamValue = new ArrayList<>();
|
List<Token> expandedParamValue = new ArrayList<>();
|
||||||
CPreprocessor subPreprocessor = new CPreprocessor(new ListTokenSource(paramTokens), new HashMap<>(defines));
|
CPreprocessor subPreprocessor = new CPreprocessor(cParser, new ListTokenSource(paramTokens), new HashMap<>(defines));
|
||||||
while(true) {
|
while(true) {
|
||||||
final Token expandedToken = subPreprocessor.nextToken();
|
final Token expandedToken = subPreprocessor.nextToken();
|
||||||
if(expandedToken.getType() == Token.EOF)
|
if(expandedToken.getType() == Token.EOF)
|
||||||
@@ -409,7 +413,7 @@ public class CPreprocessor implements TokenSource {
|
|||||||
// Evaluate any uses of the defined operator (to prevent expansion of the named macro)
|
// Evaluate any uses of the defined operator (to prevent expansion of the named macro)
|
||||||
evaluateDefinedOperator(conditionTokens);
|
evaluateDefinedOperator(conditionTokens);
|
||||||
// Expand the condition body before evaluating it
|
// Expand the condition body before evaluating it
|
||||||
CPreprocessor subPreprocessor = new CPreprocessor(new ListTokenSource(conditionTokens), new HashMap<>(defines));
|
CPreprocessor subPreprocessor = new CPreprocessor(cParser, new ListTokenSource(conditionTokens), new HashMap<>(defines));
|
||||||
// Parse the expression
|
// Parse the expression
|
||||||
KickCParser.ExprContext conditionExpr = ExprParser.parseExpression(subPreprocessor);
|
KickCParser.ExprContext conditionExpr = ExprParser.parseExpression(subPreprocessor);
|
||||||
// Evaluate the expression
|
// Evaluate the expression
|
||||||
@@ -730,69 +734,4 @@ public class CPreprocessor implements TokenSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A pragma token that should be handled in the parser (not in the lexer)
|
|
||||||
* Used to allow the lexer to ensure the preprocessor skips it the second time around.
|
|
||||||
**/
|
|
||||||
public static class PragmaToken implements Token {
|
|
||||||
|
|
||||||
/** The underlying pragma token. */
|
|
||||||
private Token subToken;
|
|
||||||
|
|
||||||
PragmaToken(Token subToken) {
|
|
||||||
this.subToken = subToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getText() {
|
|
||||||
return subToken.getText();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getType() {
|
|
||||||
return subToken.getType();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getLine() {
|
|
||||||
return subToken.getLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getCharPositionInLine() {
|
|
||||||
return subToken.getCharPositionInLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getChannel() {
|
|
||||||
return subToken.getChannel();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getTokenIndex() {
|
|
||||||
return subToken.getTokenIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getStartIndex() {
|
|
||||||
return subToken.getStartIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getStopIndex() {
|
|
||||||
return subToken.getStopIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TokenSource getTokenSource() {
|
|
||||||
return subToken.getTokenSource();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CharStream getInputStream() {
|
|
||||||
return subToken.getInputStream();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -31,6 +31,9 @@ char * const COLORRAM = 0xd800;
|
|||||||
// Color Ram
|
// Color Ram
|
||||||
char * const COLS = 0xd800;
|
char * const COLS = 0xd800;
|
||||||
|
|
||||||
|
// Default address of screen character matrix
|
||||||
|
char * const DEFAULT_SCREEN = 0x0c00;
|
||||||
|
|
||||||
// The CIA#1: keyboard matrix, joystick #1/#2
|
// The CIA#1: keyboard matrix, joystick #1/#2
|
||||||
struct MOS6526_CIA * const CIA1 = 0xdc00;
|
struct MOS6526_CIA * const CIA1 = 0xdc00;
|
||||||
// The CIA#2: Serial bus, RS-232, VIC memory bank
|
// The CIA#2: Serial bus, RS-232, VIC memory bank
|
||||||
|
@@ -2,12 +2,14 @@ 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.asm.AsmProgram;
|
import dk.camelot64.kickc.asm.AsmProgram;
|
||||||
import dk.camelot64.kickc.fragment.AsmFragmentTemplateSynthesizer;
|
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.TargetCpu;
|
import dk.camelot64.kickc.model.TargetCpu;
|
||||||
import dk.camelot64.kickc.model.TargetPlatform;
|
import dk.camelot64.kickc.model.TargetPlatform;
|
||||||
|
import dk.camelot64.kickc.parser.CTargetPlatformParser;
|
||||||
import kickass.KickAssembler;
|
import kickass.KickAssembler;
|
||||||
import kickass.nonasm.c64.CharToPetsciiConverter;
|
import kickass.nonasm.c64.CharToPetsciiConverter;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
@@ -42,10 +44,15 @@ public class TestPrograms {
|
|||||||
public TestPrograms() {
|
public TestPrograms() {
|
||||||
}
|
}
|
||||||
|
|
||||||
//@Test
|
@Test
|
||||||
//public void testPlus4Define() throws IOException, URISyntaxException {
|
public void testPlatformPlus4Define() throws IOException, URISyntaxException {
|
||||||
// compileAndCompare("plus4-define.c", log());
|
compileAndCompare("platform-plus4-define.c");
|
||||||
//}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPlatformDefaultDefine() throws IOException, URISyntaxException {
|
||||||
|
compileAndCompare("platform-default-define.c");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIncludeDefine() throws IOException, URISyntaxException {
|
public void testIncludeDefine() throws IOException, URISyntaxException {
|
||||||
@@ -4313,7 +4320,6 @@ public class TestPrograms {
|
|||||||
compiler.addIncludePath(stdIncludePath);
|
compiler.addIncludePath(stdIncludePath);
|
||||||
compiler.addLibraryPath(stdLibPath);
|
compiler.addLibraryPath(stdLibPath);
|
||||||
compiler.addTargetPlatformPath(stdPlatformPath);
|
compiler.addTargetPlatformPath(stdPlatformPath);
|
||||||
compiler.initAsmFragmentSynthesizer(asmFragmentSynthesizer);
|
|
||||||
if(upliftCombinations != null) {
|
if(upliftCombinations != null) {
|
||||||
compiler.setUpliftCombinations(upliftCombinations);
|
compiler.setUpliftCombinations(upliftCombinations);
|
||||||
}
|
}
|
||||||
@@ -4321,7 +4327,11 @@ public class TestPrograms {
|
|||||||
final Path filePath = Paths.get(fileName);
|
final Path filePath = Paths.get(fileName);
|
||||||
files.add(filePath);
|
files.add(filePath);
|
||||||
Program program = compiler.getProgram();
|
Program program = compiler.getProgram();
|
||||||
TargetPlatform.setTargetPlatform(TargetPlatform.DEFAULT_NAME, filePath, program, null);
|
|
||||||
|
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());
|
||||||
|
program.setTargetPlatform(targetPlatform);
|
||||||
|
compiler.initAsmFragmentSynthesizer(asmFragmentSynthesizer);
|
||||||
compiler.compile(files, program.getTargetPlatform().getDefines());
|
compiler.compile(files, program.getTargetPlatform().getDefines());
|
||||||
compileAsm(fileName, program);
|
compileAsm(fileName, program);
|
||||||
boolean success = true;
|
boolean success = true;
|
||||||
|
11
src/test/kc/platform-default-define.c
Normal file
11
src/test/kc/platform-default-define.c
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
// Test the #define for the default platform
|
||||||
|
|
||||||
|
char* const SCREEN = 0x0400;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
#ifdef __C64__
|
||||||
|
SCREEN[0] = 'a';
|
||||||
|
#else
|
||||||
|
SCREEN[0] = 'b';
|
||||||
|
#endif
|
||||||
|
}
|
12
src/test/kc/platform-plus4-define.c
Normal file
12
src/test/kc/platform-plus4-define.c
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
// Test the #define for the plus4 target platform
|
||||||
|
#pragma target(plus4basic)
|
||||||
|
|
||||||
|
char * const SCREEN = 0x0c00;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
#ifdef __PLUS4__
|
||||||
|
SCREEN[0] = 'a';
|
||||||
|
#else
|
||||||
|
SCREEN[0] = 'b';
|
||||||
|
#endif
|
||||||
|
}
|
@@ -1,12 +0,0 @@
|
|||||||
// Test writing to the Plus/4 TED HSCAN_POS
|
|
||||||
#pragma target(plus4basic)
|
|
||||||
|
|
||||||
#include <plus4.h>
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
#ifdef __PLUS4__
|
|
||||||
DEFAULT_SCREEN[0] = 'a';
|
|
||||||
#else
|
|
||||||
DEFAULT_SCREEN[0] = 'b';
|
|
||||||
#endif
|
|
||||||
}
|
|
12
src/test/ref/platform-default-define.asm
Normal file
12
src/test/ref/platform-default-define.asm
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
// Test the #define for the default platform
|
||||||
|
.pc = $801 "Basic"
|
||||||
|
:BasicUpstart(main)
|
||||||
|
.pc = $80d "Program"
|
||||||
|
.label SCREEN = $400
|
||||||
|
main: {
|
||||||
|
// SCREEN[0] = 'a'
|
||||||
|
lda #'a'
|
||||||
|
sta SCREEN
|
||||||
|
// }
|
||||||
|
rts
|
||||||
|
}
|
17
src/test/ref/platform-default-define.cfg
Normal file
17
src/test/ref/platform-default-define.cfg
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
@begin: scope:[] from
|
||||||
|
[0] phi()
|
||||||
|
to:@1
|
||||||
|
@1: scope:[] from @begin
|
||||||
|
[1] phi()
|
||||||
|
[2] call main
|
||||||
|
to:@end
|
||||||
|
@end: scope:[] from @1
|
||||||
|
[3] phi()
|
||||||
|
|
||||||
|
(void()) main()
|
||||||
|
main: scope:[main] from @1
|
||||||
|
[4] *((const nomodify byte*) SCREEN) ← (byte) 'a'
|
||||||
|
to:main::@return
|
||||||
|
main::@return: scope:[main] from main
|
||||||
|
[5] return
|
||||||
|
to:@return
|
216
src/test/ref/platform-default-define.log
Normal file
216
src/test/ref/platform-default-define.log
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
|
||||||
|
CONTROL FLOW GRAPH SSA
|
||||||
|
@begin: scope:[] from
|
||||||
|
to:@1
|
||||||
|
|
||||||
|
(void()) main()
|
||||||
|
main: scope:[main] from @1
|
||||||
|
*((const nomodify byte*) SCREEN + (number) 0) ← (byte) 'a'
|
||||||
|
to:main::@return
|
||||||
|
main::@return: scope:[main] from main
|
||||||
|
return
|
||||||
|
to:@return
|
||||||
|
@1: scope:[] from @begin
|
||||||
|
call main
|
||||||
|
to:@2
|
||||||
|
@2: scope:[] from @1
|
||||||
|
to:@end
|
||||||
|
@end: scope:[] from @2
|
||||||
|
|
||||||
|
SYMBOL TABLE SSA
|
||||||
|
(label) @1
|
||||||
|
(label) @2
|
||||||
|
(label) @begin
|
||||||
|
(label) @end
|
||||||
|
(const nomodify byte*) SCREEN = (byte*)(number) $400
|
||||||
|
(void()) main()
|
||||||
|
(label) main::@return
|
||||||
|
|
||||||
|
Adding number conversion cast (unumber) 0 in *((const nomodify byte*) SCREEN + (number) 0) ← (byte) 'a'
|
||||||
|
Successful SSA optimization PassNAddNumberTypeConversions
|
||||||
|
Simplifying constant pointer cast (byte*) 1024
|
||||||
|
Simplifying constant integer cast 0
|
||||||
|
Successful SSA optimization PassNCastSimplification
|
||||||
|
Finalized unsigned number type (byte) 0
|
||||||
|
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||||
|
Simplifying expression containing zero SCREEN in [0] *((const nomodify byte*) SCREEN + (byte) 0) ← (byte) 'a'
|
||||||
|
Successful SSA optimization PassNSimplifyExpressionWithZero
|
||||||
|
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
|
||||||
|
CALL GRAPH
|
||||||
|
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] phi()
|
||||||
|
to:@1
|
||||||
|
@1: scope:[] from @begin
|
||||||
|
[1] phi()
|
||||||
|
[2] call main
|
||||||
|
to:@end
|
||||||
|
@end: scope:[] from @1
|
||||||
|
[3] phi()
|
||||||
|
|
||||||
|
(void()) main()
|
||||||
|
main: scope:[main] from @1
|
||||||
|
[4] *((const nomodify byte*) SCREEN) ← (byte) 'a'
|
||||||
|
to:main::@return
|
||||||
|
main::@return: scope:[main] from main
|
||||||
|
[5] return
|
||||||
|
to:@return
|
||||||
|
|
||||||
|
|
||||||
|
VARIABLE REGISTER WEIGHTS
|
||||||
|
(void()) main()
|
||||||
|
|
||||||
|
Initial phi equivalence classes
|
||||||
|
Complete equivalence classes
|
||||||
|
|
||||||
|
INITIAL ASM
|
||||||
|
Target platform is c64basic / MOS6502X
|
||||||
|
// File Comments
|
||||||
|
// Test the #define for the default platform
|
||||||
|
// Upstart
|
||||||
|
.pc = $801 "Basic"
|
||||||
|
:BasicUpstart(main)
|
||||||
|
.pc = $80d "Program"
|
||||||
|
// Global Constants & labels
|
||||||
|
.label SCREEN = $400
|
||||||
|
// @begin
|
||||||
|
__bbegin:
|
||||||
|
// [1] phi from @begin to @1 [phi:@begin->@1]
|
||||||
|
__b1_from___bbegin:
|
||||||
|
jmp __b1
|
||||||
|
// @1
|
||||||
|
__b1:
|
||||||
|
// [2] call main
|
||||||
|
jsr main
|
||||||
|
// [3] phi from @1 to @end [phi:@1->@end]
|
||||||
|
__bend_from___b1:
|
||||||
|
jmp __bend
|
||||||
|
// @end
|
||||||
|
__bend:
|
||||||
|
// main
|
||||||
|
main: {
|
||||||
|
// [4] *((const nomodify byte*) SCREEN) ← (byte) 'a' -- _deref_pbuc1=vbuc2
|
||||||
|
lda #'a'
|
||||||
|
sta SCREEN
|
||||||
|
jmp __breturn
|
||||||
|
// main::@return
|
||||||
|
__breturn:
|
||||||
|
// [5] return
|
||||||
|
rts
|
||||||
|
}
|
||||||
|
// File Data
|
||||||
|
|
||||||
|
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||||
|
Statement [4] *((const nomodify byte*) SCREEN) ← (byte) 'a' [ ] ( main:2 [ ] { } ) always clobbers reg byte a
|
||||||
|
|
||||||
|
REGISTER UPLIFT SCOPES
|
||||||
|
Uplift Scope [main]
|
||||||
|
Uplift Scope []
|
||||||
|
|
||||||
|
Uplifting [main] best 27 combination
|
||||||
|
Uplifting [] best 27 combination
|
||||||
|
|
||||||
|
ASSEMBLER BEFORE OPTIMIZATION
|
||||||
|
// File Comments
|
||||||
|
// Test the #define for the default platform
|
||||||
|
// Upstart
|
||||||
|
.pc = $801 "Basic"
|
||||||
|
:BasicUpstart(main)
|
||||||
|
.pc = $80d "Program"
|
||||||
|
// Global Constants & labels
|
||||||
|
.label SCREEN = $400
|
||||||
|
// @begin
|
||||||
|
__bbegin:
|
||||||
|
// [1] phi from @begin to @1 [phi:@begin->@1]
|
||||||
|
__b1_from___bbegin:
|
||||||
|
jmp __b1
|
||||||
|
// @1
|
||||||
|
__b1:
|
||||||
|
// [2] call main
|
||||||
|
jsr main
|
||||||
|
// [3] phi from @1 to @end [phi:@1->@end]
|
||||||
|
__bend_from___b1:
|
||||||
|
jmp __bend
|
||||||
|
// @end
|
||||||
|
__bend:
|
||||||
|
// main
|
||||||
|
main: {
|
||||||
|
// [4] *((const nomodify byte*) SCREEN) ← (byte) 'a' -- _deref_pbuc1=vbuc2
|
||||||
|
lda #'a'
|
||||||
|
sta SCREEN
|
||||||
|
jmp __breturn
|
||||||
|
// main::@return
|
||||||
|
__breturn:
|
||||||
|
// [5] return
|
||||||
|
rts
|
||||||
|
}
|
||||||
|
// File Data
|
||||||
|
|
||||||
|
ASSEMBLER OPTIMIZATIONS
|
||||||
|
Removing instruction jmp __b1
|
||||||
|
Removing instruction jmp __bend
|
||||||
|
Removing instruction jmp __breturn
|
||||||
|
Succesful ASM optimization Pass5NextJumpElimination
|
||||||
|
Removing instruction __b1_from___bbegin:
|
||||||
|
Removing instruction __b1:
|
||||||
|
Removing instruction __bend_from___b1:
|
||||||
|
Succesful ASM optimization Pass5RedundantLabelElimination
|
||||||
|
Removing instruction __bbegin:
|
||||||
|
Removing instruction __bend:
|
||||||
|
Removing instruction __breturn:
|
||||||
|
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||||
|
Removing instruction jsr main
|
||||||
|
Succesful ASM optimization Pass5SkipBegin
|
||||||
|
|
||||||
|
FINAL SYMBOL TABLE
|
||||||
|
(label) @1
|
||||||
|
(label) @begin
|
||||||
|
(label) @end
|
||||||
|
(const nomodify byte*) SCREEN = (byte*) 1024
|
||||||
|
(void()) main()
|
||||||
|
(label) main::@return
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
FINAL ASSEMBLER
|
||||||
|
Score: 12
|
||||||
|
|
||||||
|
// File Comments
|
||||||
|
// Test the #define for the default platform
|
||||||
|
// Upstart
|
||||||
|
.pc = $801 "Basic"
|
||||||
|
:BasicUpstart(main)
|
||||||
|
.pc = $80d "Program"
|
||||||
|
// Global Constants & labels
|
||||||
|
.label SCREEN = $400
|
||||||
|
// @begin
|
||||||
|
// [1] phi from @begin to @1 [phi:@begin->@1]
|
||||||
|
// @1
|
||||||
|
// [2] call main
|
||||||
|
// [3] phi from @1 to @end [phi:@1->@end]
|
||||||
|
// @end
|
||||||
|
// main
|
||||||
|
main: {
|
||||||
|
// SCREEN[0] = 'a'
|
||||||
|
// [4] *((const nomodify byte*) SCREEN) ← (byte) 'a' -- _deref_pbuc1=vbuc2
|
||||||
|
lda #'a'
|
||||||
|
sta SCREEN
|
||||||
|
// main::@return
|
||||||
|
// }
|
||||||
|
// [5] return
|
||||||
|
rts
|
||||||
|
}
|
||||||
|
// File Data
|
||||||
|
|
7
src/test/ref/platform-default-define.sym
Normal file
7
src/test/ref/platform-default-define.sym
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
(label) @1
|
||||||
|
(label) @begin
|
||||||
|
(label) @end
|
||||||
|
(const nomodify byte*) SCREEN = (byte*) 1024
|
||||||
|
(void()) main()
|
||||||
|
(label) main::@return
|
||||||
|
|
13
src/test/ref/platform-plus4-define.asm
Normal file
13
src/test/ref/platform-plus4-define.asm
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
// Test the #define for the plus4 target platform
|
||||||
|
.pc = $1001 "Basic"
|
||||||
|
:BasicUpstart(main)
|
||||||
|
.pc = $100d "Program"
|
||||||
|
|
||||||
|
.label SCREEN = $c00
|
||||||
|
main: {
|
||||||
|
// SCREEN[0] = 'a'
|
||||||
|
lda #'a'
|
||||||
|
sta SCREEN
|
||||||
|
// }
|
||||||
|
rts
|
||||||
|
}
|
17
src/test/ref/platform-plus4-define.cfg
Normal file
17
src/test/ref/platform-plus4-define.cfg
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
@begin: scope:[] from
|
||||||
|
[0] phi()
|
||||||
|
to:@1
|
||||||
|
@1: scope:[] from @begin
|
||||||
|
[1] phi()
|
||||||
|
[2] call main
|
||||||
|
to:@end
|
||||||
|
@end: scope:[] from @1
|
||||||
|
[3] phi()
|
||||||
|
|
||||||
|
(void()) main()
|
||||||
|
main: scope:[main] from @1
|
||||||
|
[4] *((const nomodify byte*) SCREEN) ← (byte) 'a'
|
||||||
|
to:main::@return
|
||||||
|
main::@return: scope:[main] from main
|
||||||
|
[5] return
|
||||||
|
to:@return
|
219
src/test/ref/platform-plus4-define.log
Normal file
219
src/test/ref/platform-plus4-define.log
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
|
||||||
|
CONTROL FLOW GRAPH SSA
|
||||||
|
@begin: scope:[] from
|
||||||
|
to:@1
|
||||||
|
|
||||||
|
(void()) main()
|
||||||
|
main: scope:[main] from @1
|
||||||
|
*((const nomodify byte*) SCREEN + (number) 0) ← (byte) 'a'
|
||||||
|
to:main::@return
|
||||||
|
main::@return: scope:[main] from main
|
||||||
|
return
|
||||||
|
to:@return
|
||||||
|
@1: scope:[] from @begin
|
||||||
|
call main
|
||||||
|
to:@2
|
||||||
|
@2: scope:[] from @1
|
||||||
|
to:@end
|
||||||
|
@end: scope:[] from @2
|
||||||
|
|
||||||
|
SYMBOL TABLE SSA
|
||||||
|
(label) @1
|
||||||
|
(label) @2
|
||||||
|
(label) @begin
|
||||||
|
(label) @end
|
||||||
|
(const nomodify byte*) SCREEN = (byte*)(number) $c00
|
||||||
|
(void()) main()
|
||||||
|
(label) main::@return
|
||||||
|
|
||||||
|
Adding number conversion cast (unumber) 0 in *((const nomodify byte*) SCREEN + (number) 0) ← (byte) 'a'
|
||||||
|
Successful SSA optimization PassNAddNumberTypeConversions
|
||||||
|
Simplifying constant pointer cast (byte*) 3072
|
||||||
|
Simplifying constant integer cast 0
|
||||||
|
Successful SSA optimization PassNCastSimplification
|
||||||
|
Finalized unsigned number type (byte) 0
|
||||||
|
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||||
|
Simplifying expression containing zero SCREEN in [0] *((const nomodify byte*) SCREEN + (byte) 0) ← (byte) 'a'
|
||||||
|
Successful SSA optimization PassNSimplifyExpressionWithZero
|
||||||
|
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
|
||||||
|
CALL GRAPH
|
||||||
|
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] phi()
|
||||||
|
to:@1
|
||||||
|
@1: scope:[] from @begin
|
||||||
|
[1] phi()
|
||||||
|
[2] call main
|
||||||
|
to:@end
|
||||||
|
@end: scope:[] from @1
|
||||||
|
[3] phi()
|
||||||
|
|
||||||
|
(void()) main()
|
||||||
|
main: scope:[main] from @1
|
||||||
|
[4] *((const nomodify byte*) SCREEN) ← (byte) 'a'
|
||||||
|
to:main::@return
|
||||||
|
main::@return: scope:[main] from main
|
||||||
|
[5] return
|
||||||
|
to:@return
|
||||||
|
|
||||||
|
|
||||||
|
VARIABLE REGISTER WEIGHTS
|
||||||
|
(void()) main()
|
||||||
|
|
||||||
|
Initial phi equivalence classes
|
||||||
|
Complete equivalence classes
|
||||||
|
|
||||||
|
INITIAL ASM
|
||||||
|
Target platform is plus4basic / MOS6502X
|
||||||
|
// File Comments
|
||||||
|
// Test the #define for the plus4 target platform
|
||||||
|
// Upstart
|
||||||
|
.pc = $1001 "Basic"
|
||||||
|
:BasicUpstart(main)
|
||||||
|
.pc = $100d "Program"
|
||||||
|
|
||||||
|
// Global Constants & labels
|
||||||
|
.label SCREEN = $c00
|
||||||
|
// @begin
|
||||||
|
__bbegin:
|
||||||
|
// [1] phi from @begin to @1 [phi:@begin->@1]
|
||||||
|
__b1_from___bbegin:
|
||||||
|
jmp __b1
|
||||||
|
// @1
|
||||||
|
__b1:
|
||||||
|
// [2] call main
|
||||||
|
jsr main
|
||||||
|
// [3] phi from @1 to @end [phi:@1->@end]
|
||||||
|
__bend_from___b1:
|
||||||
|
jmp __bend
|
||||||
|
// @end
|
||||||
|
__bend:
|
||||||
|
// main
|
||||||
|
main: {
|
||||||
|
// [4] *((const nomodify byte*) SCREEN) ← (byte) 'a' -- _deref_pbuc1=vbuc2
|
||||||
|
lda #'a'
|
||||||
|
sta SCREEN
|
||||||
|
jmp __breturn
|
||||||
|
// main::@return
|
||||||
|
__breturn:
|
||||||
|
// [5] return
|
||||||
|
rts
|
||||||
|
}
|
||||||
|
// File Data
|
||||||
|
|
||||||
|
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||||
|
Statement [4] *((const nomodify byte*) SCREEN) ← (byte) 'a' [ ] ( main:2 [ ] { } ) always clobbers reg byte a
|
||||||
|
|
||||||
|
REGISTER UPLIFT SCOPES
|
||||||
|
Uplift Scope [main]
|
||||||
|
Uplift Scope []
|
||||||
|
|
||||||
|
Uplifting [main] best 27 combination
|
||||||
|
Uplifting [] best 27 combination
|
||||||
|
|
||||||
|
ASSEMBLER BEFORE OPTIMIZATION
|
||||||
|
// File Comments
|
||||||
|
// Test the #define for the plus4 target platform
|
||||||
|
// Upstart
|
||||||
|
.pc = $1001 "Basic"
|
||||||
|
:BasicUpstart(main)
|
||||||
|
.pc = $100d "Program"
|
||||||
|
|
||||||
|
// Global Constants & labels
|
||||||
|
.label SCREEN = $c00
|
||||||
|
// @begin
|
||||||
|
__bbegin:
|
||||||
|
// [1] phi from @begin to @1 [phi:@begin->@1]
|
||||||
|
__b1_from___bbegin:
|
||||||
|
jmp __b1
|
||||||
|
// @1
|
||||||
|
__b1:
|
||||||
|
// [2] call main
|
||||||
|
jsr main
|
||||||
|
// [3] phi from @1 to @end [phi:@1->@end]
|
||||||
|
__bend_from___b1:
|
||||||
|
jmp __bend
|
||||||
|
// @end
|
||||||
|
__bend:
|
||||||
|
// main
|
||||||
|
main: {
|
||||||
|
// [4] *((const nomodify byte*) SCREEN) ← (byte) 'a' -- _deref_pbuc1=vbuc2
|
||||||
|
lda #'a'
|
||||||
|
sta SCREEN
|
||||||
|
jmp __breturn
|
||||||
|
// main::@return
|
||||||
|
__breturn:
|
||||||
|
// [5] return
|
||||||
|
rts
|
||||||
|
}
|
||||||
|
// File Data
|
||||||
|
|
||||||
|
ASSEMBLER OPTIMIZATIONS
|
||||||
|
Removing instruction jmp __b1
|
||||||
|
Removing instruction jmp __bend
|
||||||
|
Removing instruction jmp __breturn
|
||||||
|
Succesful ASM optimization Pass5NextJumpElimination
|
||||||
|
Removing instruction __b1_from___bbegin:
|
||||||
|
Removing instruction __b1:
|
||||||
|
Removing instruction __bend_from___b1:
|
||||||
|
Succesful ASM optimization Pass5RedundantLabelElimination
|
||||||
|
Removing instruction __bbegin:
|
||||||
|
Removing instruction __bend:
|
||||||
|
Removing instruction __breturn:
|
||||||
|
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||||
|
Removing instruction jsr main
|
||||||
|
Succesful ASM optimization Pass5SkipBegin
|
||||||
|
|
||||||
|
FINAL SYMBOL TABLE
|
||||||
|
(label) @1
|
||||||
|
(label) @begin
|
||||||
|
(label) @end
|
||||||
|
(const nomodify byte*) SCREEN = (byte*) 3072
|
||||||
|
(void()) main()
|
||||||
|
(label) main::@return
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
FINAL ASSEMBLER
|
||||||
|
Score: 12
|
||||||
|
|
||||||
|
// File Comments
|
||||||
|
// Test the #define for the plus4 target platform
|
||||||
|
// Upstart
|
||||||
|
.pc = $1001 "Basic"
|
||||||
|
:BasicUpstart(main)
|
||||||
|
.pc = $100d "Program"
|
||||||
|
|
||||||
|
// Global Constants & labels
|
||||||
|
.label SCREEN = $c00
|
||||||
|
// @begin
|
||||||
|
// [1] phi from @begin to @1 [phi:@begin->@1]
|
||||||
|
// @1
|
||||||
|
// [2] call main
|
||||||
|
// [3] phi from @1 to @end [phi:@1->@end]
|
||||||
|
// @end
|
||||||
|
// main
|
||||||
|
main: {
|
||||||
|
// SCREEN[0] = 'a'
|
||||||
|
// [4] *((const nomodify byte*) SCREEN) ← (byte) 'a' -- _deref_pbuc1=vbuc2
|
||||||
|
lda #'a'
|
||||||
|
sta SCREEN
|
||||||
|
// main::@return
|
||||||
|
// }
|
||||||
|
// [5] return
|
||||||
|
rts
|
||||||
|
}
|
||||||
|
// File Data
|
||||||
|
|
7
src/test/ref/platform-plus4-define.sym
Normal file
7
src/test/ref/platform-plus4-define.sym
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
(label) @1
|
||||||
|
(label) @begin
|
||||||
|
(label) @end
|
||||||
|
(const nomodify byte*) SCREEN = (byte*) 3072
|
||||||
|
(void()) main()
|
||||||
|
(label) main::@return
|
||||||
|
|
Reference in New Issue
Block a user