1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-11-26 12:49:21 +00:00

Implemented target platform defines by putting the handling of #pragma target() into the preprocessor/parser.

This commit is contained in:
jespergravgaard 2020-05-15 08:19:26 +02:00
parent e046e27e52
commit 1d534dcc3d
19 changed files with 672 additions and 191 deletions

View File

@ -6,6 +6,7 @@ import dk.camelot64.kickc.fragment.AsmFragmentTemplateUsages;
import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.statements.StatementSource;
import dk.camelot64.kickc.model.symbols.Procedure;
import dk.camelot64.kickc.parser.CTargetPlatformParser;
import kickass.KickAssembler;
import kickass.nonasm.c64.CharToPetsciiConverter;
import picocli.CommandLine;
@ -156,7 +157,7 @@ public class KickC implements Callable<Integer> {
private boolean interleaveIclFile = false;
@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")
private String cpu = null;
@ -228,18 +229,15 @@ public class KickC implements Callable<Integer> {
// Set up Target Platform
try {
if(targetPlatform != null) {
TargetPlatform.setTargetPlatform(targetPlatform, currentPath, program, null);
} else {
TargetPlatform.setTargetPlatform(TargetPlatform.DEFAULT_NAME, currentPath, program, null);
}
final File platformFile = SourceLoader.loadFile(targetPlatform + "." + CTargetPlatformParser.FILE_EXTENSION, currentPath, program.getTargetPlatformPaths());
final TargetPlatform targetPlatform = CTargetPlatformParser.parseTargetPlatformFile(this.targetPlatform, platformFile, currentPath, program.getTargetPlatformPaths());
program.setTargetPlatform(targetPlatform);
} catch(CompileError e) {
// Print the error and exit with compile error
System.err.println(e.getMessage());
return COMPILE_ERROR;
}
// Update link script
if(linkScript != null) {
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(" "));
Map<String, String> effectiveDefines = new LinkedHashMap<>();
if(defines!=null)
if(defines != null)
effectiveDefines.putAll(defines);
if(program.getTargetPlatform().getDefines()!=null)
if(program.getTargetPlatform().getDefines() != null)
effectiveDefines.putAll(program.getTargetPlatform().getDefines());
if(preprocess) {

View File

@ -1,22 +1,7 @@
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.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.Set;
/**
* The target platform the compiler is creating a program for.
@ -29,9 +14,6 @@ public class TargetPlatform {
/** The name of the default target platform. */
public static String DEFAULT_NAME = "c64basic";
/** The file extension used for target platform files. */
public static final String FILE_EXTENSION = "tgt";
/** The platform name. */
private String name;
@ -91,56 +73,5 @@ public class TargetPlatform {
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);
}
}
}

View File

@ -4,6 +4,7 @@ import dk.camelot64.kickc.Compiler;
import dk.camelot64.kickc.SourceLoader;
import dk.camelot64.kickc.model.CompileError;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.TargetPlatform;
import dk.camelot64.kickc.preprocessor.CPreprocessor;
import org.antlr.v4.runtime.*;
@ -65,7 +66,7 @@ public class CParser {
this.program = program;
this.cFiles = new LinkedHashMap<>();
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.parser = new KickCParser(preprocessedTokenStream, this);
this.typedefs = new ArrayList<>();
@ -103,6 +104,7 @@ public class CParser {
/**
* Define a new macro
*
* @param macroName The macro name
* @param macroBody The macro body
*/
@ -115,6 +117,7 @@ public class CParser {
/**
* Undef a macro
*
* @param macroName The macro name
*/
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
*/
private Path getCurrentSourceFolderPath() {
public Path getCurrentSourceFolderPath() {
TokenSource currentSource = cTokenSource.getCurrentSource();
String sourceName = currentSource.getSourceName();
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
*

View File

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

View File

@ -179,21 +179,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
@Override
public Object visitGlobalDirectivePlatform(KickCParser.GlobalDirectivePlatformContext ctx) {
final String platformName = ctx.NAME().getText();
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;
throw new InternalError("Error! #pragma target() should be handled in preprocessor!");
}
@Override

View File

@ -22,6 +22,9 @@ import java.util.*;
*/
public class CPreprocessor implements TokenSource {
/** The CParser used for loading files. */
private CParser cParser;
/** The token source containing the 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 possible use the input directly instead of wrapping it
this.input = (CTokenSource) input;
@ -135,12 +139,15 @@ public class CPreprocessor implements TokenSource {
return true;
} else if(inputToken.getType() == KickCLexer.NAME) {
return expand(inputToken, cTokenSource);
//} else if(inputToken.getType() == KickCLexer.PRAGMA) {
// return pragma(inputToken, cTokenSource);
} else if(inputToken.getType() == KickCLexer.PRAGMA) {
return pragma(inputToken, cTokenSource);
}
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
*
@ -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
*/
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
return false;
final List<Token> ws = skipWhitespace(cTokenSource);
final Token pragmaType = cTokenSource.nextToken();
/*
if(KickCLexer.TARGET == pragmaType.getType()) {
skipWhitespace(cTokenSource);
nextToken(cTokenSource, KickCLexer.PAR_BEGIN);
@ -163,15 +168,14 @@ public class CPreprocessor implements TokenSource {
final String targetName = nextToken(cTokenSource, KickCLexer.NAME).getText();
skipWhitespace(cTokenSource);
nextToken(cTokenSource, KickCLexer.PAR_END);
//TargetPlatform.setTargetPlatform(targetName, null, );
throw new InternalError("TODO: Implement #pragma target");
// return true;
cParser.loadTargetPlatform(targetName, cParser.getCurrentSourceFolderPath());
return true;
}
*/
// Pass on the #pragma to the parser
parserPragmas.add(inputToken);
final ArrayList<Token> pragmaTokens = new ArrayList<>();
pragmaTokens.add(new PragmaToken(inputToken));
pragmaTokens.add(inputToken);
pragmaTokens.addAll(ws);
pragmaTokens.add(pragmaType);
cTokenSource.addSourceFirst(new ListTokenSource(pragmaTokens));
@ -280,7 +284,7 @@ public class CPreprocessor implements TokenSource {
List<List<Token>> expandedParamValues = new ArrayList<>();
for(List<Token> paramTokens : paramValues) {
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) {
final Token expandedToken = subPreprocessor.nextToken();
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)
evaluateDefinedOperator(conditionTokens);
// 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
KickCParser.ExprContext conditionExpr = ExprParser.parseExpression(subPreprocessor);
// 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();
}
}
}

View File

@ -31,6 +31,9 @@ char * const COLORRAM = 0xd800;
// Color Ram
char * const COLS = 0xd800;
// Default address of screen character matrix
char * const DEFAULT_SCREEN = 0x0c00;
// The CIA#1: keyboard matrix, joystick #1/#2
struct MOS6526_CIA * const CIA1 = 0xdc00;
// The CIA#2: Serial bus, RS-232, VIC memory bank

View File

@ -2,12 +2,14 @@ package dk.camelot64.kickc.test;
import dk.camelot64.kickc.CompileLog;
import dk.camelot64.kickc.Compiler;
import dk.camelot64.kickc.SourceLoader;
import dk.camelot64.kickc.asm.AsmProgram;
import dk.camelot64.kickc.fragment.AsmFragmentTemplateSynthesizer;
import dk.camelot64.kickc.model.CompileError;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.TargetCpu;
import dk.camelot64.kickc.model.TargetPlatform;
import dk.camelot64.kickc.parser.CTargetPlatformParser;
import kickass.KickAssembler;
import kickass.nonasm.c64.CharToPetsciiConverter;
import org.junit.AfterClass;
@ -42,10 +44,15 @@ public class TestPrograms {
public TestPrograms() {
}
//@Test
//public void testPlus4Define() throws IOException, URISyntaxException {
// compileAndCompare("plus4-define.c", log());
//}
@Test
public void testPlatformPlus4Define() throws IOException, URISyntaxException {
compileAndCompare("platform-plus4-define.c");
}
@Test
public void testPlatformDefaultDefine() throws IOException, URISyntaxException {
compileAndCompare("platform-default-define.c");
}
@Test
public void testIncludeDefine() throws IOException, URISyntaxException {
@ -4313,7 +4320,6 @@ public class TestPrograms {
compiler.addIncludePath(stdIncludePath);
compiler.addLibraryPath(stdLibPath);
compiler.addTargetPlatformPath(stdPlatformPath);
compiler.initAsmFragmentSynthesizer(asmFragmentSynthesizer);
if(upliftCombinations != null) {
compiler.setUpliftCombinations(upliftCombinations);
}
@ -4321,7 +4327,11 @@ public class TestPrograms {
final Path filePath = Paths.get(fileName);
files.add(filePath);
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());
compileAsm(fileName, program);
boolean success = true;

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

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

View File

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

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

View 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

View 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

View File

@ -0,0 +1,7 @@
(label) @1
(label) @begin
(label) @end
(const nomodify byte*) SCREEN = (byte*) 1024
(void()) main()
(label) main::@return

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

View 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

View 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

View File

@ -0,0 +1,7 @@
(label) @1
(label) @begin
(label) @end
(const nomodify byte*) SCREEN = (byte*) 3072
(void()) main()
(label) main::@return