mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-01-01 13:30:50 +00:00
Working on #pragma target handling in preprocessor - to fix the embedded #defines.
This commit is contained in:
parent
362ec9bb0b
commit
b2045c7874
@ -8,11 +8,12 @@ import dk.camelot64.kickc.model.statements.StatementSource;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
import dk.camelot64.kickc.model.values.SymbolRef;
|
||||
import dk.camelot64.kickc.parser.CParser;
|
||||
import dk.camelot64.kickc.parser.KickCLexer;
|
||||
import dk.camelot64.kickc.parser.KickCParser;
|
||||
import dk.camelot64.kickc.passes.*;
|
||||
import dk.camelot64.kickc.preprocessor.CPreprocessor;
|
||||
import org.antlr.v4.runtime.*;
|
||||
import org.antlr.v4.runtime.RuleContext;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.TokenSource;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
@ -145,10 +146,7 @@ public class Compiler {
|
||||
CParser cParser = new CParser(program);
|
||||
if(defines != null) {
|
||||
for(String macroName : defines.keySet()) {
|
||||
final String macroBodyText = "#define " + macroName + " " + defines.get(macroName) + "\n";
|
||||
final CodePointCharStream macroCharStream = CharStreams.fromString(macroBodyText);
|
||||
final KickCLexer macroLexer = cParser.makeLexer(macroCharStream);
|
||||
cParser.addSourceFirst(macroLexer);
|
||||
cParser.define(macroName, defines.get(macroName));
|
||||
}
|
||||
}
|
||||
for(Path cFile : cFiles) {
|
||||
|
@ -349,10 +349,16 @@ public class KickC implements Callable<Integer> {
|
||||
StringBuilder CFileNames = new StringBuilder();
|
||||
cFiles.stream().forEach(path -> CFileNames.append(path.toString()).append(" "));
|
||||
|
||||
Map<String, String> effectiveDefines = new LinkedHashMap<>();
|
||||
if(defines!=null)
|
||||
effectiveDefines.putAll(defines);
|
||||
if(program.getTargetPlatform().getDefines()!=null)
|
||||
effectiveDefines.putAll(program.getTargetPlatform().getDefines());
|
||||
|
||||
if(preprocess) {
|
||||
System.out.println("Preprocessing " + CFileNames);
|
||||
try {
|
||||
compiler.preprocess(cFiles, defines);
|
||||
compiler.preprocess(cFiles, effectiveDefines);
|
||||
} catch(CompileError e) {
|
||||
// Print the error and exit with compile error
|
||||
System.err.println(e.getMessage());
|
||||
@ -363,7 +369,7 @@ public class KickC implements Callable<Integer> {
|
||||
|
||||
System.out.println("Compiling " + CFileNames);
|
||||
try {
|
||||
compiler.compile(cFiles, defines);
|
||||
compiler.compile(cFiles, effectiveDefines);
|
||||
} catch(CompileError e) {
|
||||
// Print the error and exit with compile error
|
||||
System.err.println(e.getMessage());
|
||||
|
@ -6,14 +6,17 @@ 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.
|
||||
@ -113,6 +116,17 @@ public class TargetPlatform {
|
||||
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);
|
||||
|
@ -101,6 +101,26 @@ public class CParser {
|
||||
return preprocessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a new macro
|
||||
* @param macroName The macro name
|
||||
* @param macroBody The macro body
|
||||
*/
|
||||
public void define(String macroName, String macroBody) {
|
||||
final String macroBodyText = "#define " + macroName + " " + macroBody + "\n";
|
||||
final CodePointCharStream macroCharStream = CharStreams.fromString(macroBodyText);
|
||||
final KickCLexer macroLexer = makeLexer(macroCharStream);
|
||||
addSourceFirst(macroLexer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Undef a macro
|
||||
* @param macroName The macro name
|
||||
*/
|
||||
public void undef(String macroName) {
|
||||
getPreprocessor().undef(macroName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token stream containing tokens after the preprocessor.
|
||||
*
|
||||
|
@ -146,12 +146,12 @@ parameterDecl
|
||||
;
|
||||
|
||||
globalDirective
|
||||
: (PRAGMA RESERVE) PAR_BEGIN NUMBER ( COMMA NUMBER )* PAR_END #globalDirectiveReserve
|
||||
| (PRAGMA PC) PAR_BEGIN NUMBER PAR_END #globalDirectivePc
|
||||
| (PRAGMA TARGET) PAR_BEGIN NAME PAR_END #globalDirectivePlatform
|
||||
: (PRAGMA TARGET) PAR_BEGIN NAME PAR_END #globalDirectivePlatform
|
||||
| (PRAGMA CPU) PAR_BEGIN NAME PAR_END #globalDirectiveCpu
|
||||
| (PRAGMA LINK) PAR_BEGIN STRING PAR_END #globalDirectiveLinkScript
|
||||
| (PRAGMA EMULATOR) PAR_BEGIN STRING PAR_END #globalDirectiveEmulator
|
||||
| (PRAGMA RESERVE) PAR_BEGIN NUMBER ( COMMA NUMBER )* PAR_END #globalDirectiveReserve
|
||||
| (PRAGMA PC) PAR_BEGIN NUMBER PAR_END #globalDirectivePc
|
||||
| (PRAGMA CODESEG) PAR_BEGIN NAME PAR_END #globalDirectiveCodeSeg
|
||||
| (PRAGMA DATASEG) PAR_BEGIN NAME PAR_END #globalDirectiveDataSeg
|
||||
| (PRAGMA ENCODING) PAR_BEGIN NAME PAR_END #globalDirectiveEncoding
|
||||
|
@ -182,7 +182,17 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -135,10 +135,49 @@ 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);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle any #pragma that must be handled by the preprocessor
|
||||
*
|
||||
* @param inputToken The #pragma token
|
||||
* @param cTokenSource The token source used for getting more tokens or for pushing macro expansions
|
||||
* @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)
|
||||
// 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);
|
||||
skipWhitespace(cTokenSource);
|
||||
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;
|
||||
}
|
||||
*/
|
||||
|
||||
// Pass on the #pragma to the parser
|
||||
final ArrayList<Token> pragmaTokens = new ArrayList<>();
|
||||
pragmaTokens.add(new PragmaToken(inputToken));
|
||||
pragmaTokens.addAll(ws);
|
||||
pragmaTokens.add(pragmaType);
|
||||
cTokenSource.addSourceFirst(new ListTokenSource(pragmaTokens));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a macro.
|
||||
*
|
||||
@ -258,7 +297,7 @@ public class CPreprocessor implements TokenSource {
|
||||
List<Token> expandedBody = new ArrayList<>();
|
||||
final List<Token> macroBody = macro.body;
|
||||
for(Token macroBodyToken : macroBody) {
|
||||
if(macroBodyToken.getType()==KickCLexer.NAME && macro.parameters.contains(macroBodyToken.getText())) {
|
||||
if(macroBodyToken.getType() == KickCLexer.NAME && macro.parameters.contains(macroBodyToken.getText())) {
|
||||
// body token is a parameter name - replace with expanded parameter value
|
||||
final int paramIndex = macro.parameters.indexOf(macroBodyToken.getText());
|
||||
final List<Token> expandedParamValue = paramValues.get(paramIndex);
|
||||
@ -278,6 +317,7 @@ public class CPreprocessor implements TokenSource {
|
||||
|
||||
/**
|
||||
* Add a macro token to the exapnded macro body. Keeps track of which macros has been used to expand the token using {@link ExpansionToken}
|
||||
*
|
||||
* @param macroBodyToken The macro body token to add
|
||||
* @param macroNameToken The token containing the macro name. Used to get the name and as a source for copying token properties (ensuring file name, line etc. are OK).
|
||||
* @param expandedBody The expanded macro body to add the token to
|
||||
@ -305,6 +345,15 @@ public class CPreprocessor implements TokenSource {
|
||||
// #undef a new macro - find the name
|
||||
skipWhitespace(cTokenSource);
|
||||
String macroName = nextToken(cTokenSource, KickCLexer.NAME).getText();
|
||||
undef(macroName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Undefine a macro.
|
||||
*
|
||||
* @param macroName The macro name
|
||||
*/
|
||||
public void undef(String macroName) {
|
||||
this.defines.remove(macroName);
|
||||
}
|
||||
|
||||
@ -592,16 +641,21 @@ public class CPreprocessor implements TokenSource {
|
||||
* Skip whitespace tokens (except newlines), positioning iterator at the next non-whitespace
|
||||
*
|
||||
* @param cTokenSource The token iterator
|
||||
* @return The skipped tokens
|
||||
*/
|
||||
private void skipWhitespace(CTokenSource cTokenSource) {
|
||||
private List<Token> skipWhitespace(CTokenSource cTokenSource) {
|
||||
List<Token> ws = new ArrayList<>();
|
||||
while(true) {
|
||||
final Token token = cTokenSource.peekToken();
|
||||
if(token.getChannel() != CParser.CHANNEL_WHITESPACE)
|
||||
break;
|
||||
if(token.getText().contains("\n"))
|
||||
break;
|
||||
// The token is whitespace
|
||||
ws.add(token);
|
||||
cTokenSource.nextToken();
|
||||
}
|
||||
return ws;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -676,5 +730,69 @@ 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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
{
|
||||
"link": "c64.ld",
|
||||
"cpu": "MOS6502X",
|
||||
"emulator": "x64sc"
|
||||
"emulator": "x64sc",
|
||||
"defines": {
|
||||
"__C64__": 1
|
||||
}
|
||||
}
|
@ -1,5 +1,8 @@
|
||||
{
|
||||
"link": "c64basic.ld",
|
||||
"cpu": "MOS6502X",
|
||||
"emulator": "x64sc"
|
||||
"emulator": "x64sc",
|
||||
"defines": {
|
||||
"__C64__": 1
|
||||
}
|
||||
}
|
@ -1,5 +1,8 @@
|
||||
{
|
||||
"link": "plus4.ld",
|
||||
"cpu": "MOS6502X",
|
||||
"emulator": "xplus4"
|
||||
"emulator": "xplus4",
|
||||
"defines": {
|
||||
"__PLUS4__": 1
|
||||
}
|
||||
}
|
@ -1,5 +1,8 @@
|
||||
{
|
||||
"link": "plus4basic.ld",
|
||||
"cpu": "MOS6502X",
|
||||
"emulator": "xplus4"
|
||||
"emulator": "xplus4",
|
||||
"defines": {
|
||||
"__PLUS4__": 1
|
||||
}
|
||||
}
|
@ -42,6 +42,16 @@ public class TestPrograms {
|
||||
public TestPrograms() {
|
||||
}
|
||||
|
||||
//@Test
|
||||
//public void testPlus4Define() throws IOException, URISyntaxException {
|
||||
// compileAndCompare("plus4-define.c", log());
|
||||
//}
|
||||
|
||||
@Test
|
||||
public void testIncludeDefine() throws IOException, URISyntaxException {
|
||||
compileAndCompare("include-define.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStructPointerInts() throws IOException, URISyntaxException {
|
||||
compileAndCompare("struct-pointer-ints.c");
|
||||
@ -82,8 +92,6 @@ public class TestPrograms {
|
||||
compileAndCompare("stars-1.c");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* TODO: Add support for var*var
|
||||
@Test
|
||||
public void testMultiply3() throws IOException, URISyntaxException {
|
||||
@ -4314,7 +4322,7 @@ public class TestPrograms {
|
||||
files.add(filePath);
|
||||
Program program = compiler.getProgram();
|
||||
TargetPlatform.setTargetPlatform(TargetPlatform.DEFAULT_NAME, filePath, program, null);
|
||||
compiler.compile(files, null);
|
||||
compiler.compile(files, program.getTargetPlatform().getDefines());
|
||||
compileAsm(fileName, program);
|
||||
boolean success = true;
|
||||
ReferenceHelper helper = new ReferenceHelperFolder(refPath);
|
||||
|
4
src/test/kc/include-define-sub.h
Normal file
4
src/test/kc/include-define-sub.h
Normal file
@ -0,0 +1,4 @@
|
||||
// Test including a files with a #define and using it
|
||||
// This file is included and contains a #define
|
||||
|
||||
#define DEFX char x='a'
|
8
src/test/kc/include-define.c
Normal file
8
src/test/kc/include-define.c
Normal file
@ -0,0 +1,8 @@
|
||||
// Test including a files with a #define and using it
|
||||
|
||||
#include "include-define-sub.h"
|
||||
DEFX;
|
||||
char * const SCREEN = 0x0400;
|
||||
void main() {
|
||||
SCREEN[0] = x;
|
||||
}
|
13
src/test/ref/include-define.asm
Normal file
13
src/test/ref/include-define.asm
Normal file
@ -0,0 +1,13 @@
|
||||
// Test including a files with a #define and using it
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
.const x = 'a'
|
||||
.label SCREEN = $400
|
||||
main: {
|
||||
// SCREEN[0] = x
|
||||
lda #x
|
||||
sta SCREEN
|
||||
// }
|
||||
rts
|
||||
}
|
17
src/test/ref/include-define.cfg
Normal file
17
src/test/ref/include-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) ← (const byte) x
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
[5] return
|
||||
to:@return
|
221
src/test/ref/include-define.log
Normal file
221
src/test/ref/include-define.log
Normal file
@ -0,0 +1,221 @@
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
@begin: scope:[] from
|
||||
to:@1
|
||||
|
||||
(void()) main()
|
||||
main: scope:[main] from @1
|
||||
*((const nomodify byte*) SCREEN + (number) 0) ← (const byte) x
|
||||
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
|
||||
(const byte) x = (byte) 'a'
|
||||
|
||||
Adding number conversion cast (unumber) 0 in *((const nomodify byte*) SCREEN + (number) 0) ← (const byte) x
|
||||
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) ← (const byte) x
|
||||
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) ← (const byte) x
|
||||
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 including a files with a #define and using it
|
||||
// Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
.const x = 'a'
|
||||
.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) ← (const byte) x -- _deref_pbuc1=vbuc2
|
||||
lda #x
|
||||
sta SCREEN
|
||||
jmp __breturn
|
||||
// main::@return
|
||||
__breturn:
|
||||
// [5] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [4] *((const nomodify byte*) SCREEN) ← (const byte) x [ ] ( 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 including a files with a #define and using it
|
||||
// Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
.const x = 'a'
|
||||
.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) ← (const byte) x -- _deref_pbuc1=vbuc2
|
||||
lda #x
|
||||
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
|
||||
(const byte) x = (byte) 'a'
|
||||
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 12
|
||||
|
||||
// File Comments
|
||||
// Test including a files with a #define and using it
|
||||
// Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
.const x = 'a'
|
||||
.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] = x
|
||||
// [4] *((const nomodify byte*) SCREEN) ← (const byte) x -- _deref_pbuc1=vbuc2
|
||||
lda #x
|
||||
sta SCREEN
|
||||
// main::@return
|
||||
// }
|
||||
// [5] return
|
||||
rts
|
||||
}
|
||||
// File Data
|
||||
|
8
src/test/ref/include-define.sym
Normal file
8
src/test/ref/include-define.sym
Normal file
@ -0,0 +1,8 @@
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(const nomodify byte*) SCREEN = (byte*) 1024
|
||||
(void()) main()
|
||||
(label) main::@return
|
||||
(const byte) x = (byte) 'a'
|
||||
|
Loading…
Reference in New Issue
Block a user