Merge branch 'drmortalwombat:main' into patch-1

This commit is contained in:
Janne Johansson 2023-10-24 21:06:24 +02:00 committed by GitHub
commit 0f539d239c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
120 changed files with 27908 additions and 1883 deletions

5
.gitignore vendored
View File

@ -343,12 +343,9 @@ make/oscar64
*.int
*.bcs
*.crt
*.crt
*.d64
**/*.d64
*.tlog
*.res
*.recipe
*.exe
*.d64
*.d64
*.dbj

135
README.md
View File

@ -23,7 +23,8 @@ After extensive optimizations it turns out, that the interpreted code is not sig
## Limits and Errors
There are still several open areas, but most targets have been reached. The current Dhrystone performance is 94 iterations per second with byte code (11696) and 395 iterations with native code (10425 Bytes). This clearly shows that Dhrystone is not a valid benchmark for optimizing compilers, because it puts the 6502 on par with a 4MHz 8088 or 68k, which it clearly is not.
There are still several open areas, but most targets have been reached. The current
stone performance is 94 iterations per second with byte code (11696) and 395 iterations with native code (10425 Bytes). This clearly shows that Dhrystone is not a valid benchmark for optimizing compilers, because it puts the 6502 on par with a 4MHz 8088 or 68k, which it clearly is not.
### Language
@ -48,6 +49,31 @@ There are still several open areas, but most targets have been reached. The cur
### Native code generation
### C++ support level
The compiler will most likely not support a current C++ standard in the near future, but several C++ features are already implemented. The compiler can be switched into C++ mode with the command line option -pp or by providing a source file with a .cpp extension.
Supported Features:
* namespaces
* reference types
* member functions
* constructors and destructors
* operator overloading
* single inheritance of class and struct
* const member functions
* new, delete, new[] and delete[]
* virtual member functions
* string and iostream classes
* default parameters for class members and functions
* templates
* vector, array and list template classes
* lambda functions
* auto variables, parameters and return types
* for range loop
* constexpr compile time evaluation
* parameter packs and templates
## Installation and Usage
### Installing on windows
@ -67,7 +93,7 @@ You should build from a subdirectory of Oscar64 so that references in the makefi
The compiler is command line driven, and creates an executable .prg file.
oscar64 {-i=includePath} [-o=output.prg] [-rt=runtime.c] [-tf=format] [-tm=machine] [-e] [-n] [-dSYMBOL[=value]] {source.c}
oscar64 {-i=includePath} [-o=output.prg] [-rt=runtime.c] [-tf=format] [-tm=machine] [-e] [-n] [-dSYMBOL[=value]] {source.c|source.cpp}
* -v : verbose output for diagnostics
* -v2 : more verbose output
@ -76,7 +102,8 @@ The compiler is command line driven, and creates an executable .prg file.
* -rt : alternative runtime library, replaces the crt.c (or empty for none)
* -e : execute the result in the integrated emulator
* -ep : execute and profile the result in the integrated emulator
* -n : create pure native code for all functions
* -bc : create byte code for all functions
* -n : create pure native code for all functions (now default)
* -d : define a symbol (e.g. NOFLOAT or NOLONG to avoid float/long code in printf)
* -O1 or -O : default optimizations
* -O0 : disable optimizations
@ -86,6 +113,7 @@ The compiler is command line driven, and creates an executable .prg file.
* -Oi : enable auto inline of small functions (part of O2/O3)
* -Oa : optimize inline assembler (part of O2/O3)
* -Oz : enable auto placement of global variables in zero page (part of O3)
* -Op : optimize constant parameters
* -g : create source level debug info and add source line numbers to asm listing
* -tf : target format, may be prg, crt or bin
* -tm : target machine
@ -94,6 +122,7 @@ The compiler is command line driven, and creates an executable .prg file.
* -fz : add a compressed binary file to the disk image
* -xz : extended zero page usage, more zero page space, but no return to basic
* -cid : cartridge type ID, used by vice emulator
* -pp : compile in C++ mode
A list of source files can be provided.
@ -165,6 +194,80 @@ Creates vice monitor commands to define all static labels.
One can load the label file in the monitor using the load_labels (ll) command or provide it on the command line for vice with the "-moncommands" command line argument.
#### Complete debug information ".dbj"
This is a JSON file that contains detailed debug information.
it has four top sections:
* memory : complete memory map with lables and source location
* variables : list of all global/static variables with address and type index
* functions : list of all functions with local variables, line numbers and addresses
* types : list of all types
##### Debug memory information
The memory partitioning is described using a list of
* name : name of the memory object
* start : start address (inclusive)
* end : end address (exclusive)
* type : linkage type of memory object
* source : source file that declared this memory object
* line : source line that declared this memory object
##### Debug type information
Every defined type has a unique numeric typeid that is used to reference it from the variable sections or from composite types.
Each type has up to five attributes:
* name : a string, present for all named types
* typeid : the unique numeric ID for this type
* size : size of a variable of this type in bytes
* type : base type or composition method for this type
* int : signed Integer
* uint : unsigned integer
* bool : boolean value
* enum : enumeration
* ptr : pointer to
* ref : reference
* struct : struct/class
* union
* members : list of members of a composite type or enum
* eid : typeid for pointer or reference targets
##### Debug variables information
Global variables have a name, a memory range and a typeid
* name : a string, present for named variables
* start : start address (inclusive)
* end : end address (exclusive)
* typeid : the type id for this variable
##### Debug function information
* name : a string, present for named functions
* start : start address (inclusive)
* end : end address (exclusive)
* source : source file that declared this function
* line : source line that declared this function
* lines : list of all source lines for this function
* start : start address (inclusive)
* end : end address (exclusive)
* source : source file that declared this function
* line : source line that declared this function
* variables : list of all local variables for this function
* name : a string, present for named variables
* start : start address (inclusive)
* end : end address (exclusive)
* enter : first line where the vaiable becomes visible
* leave : last line where the variable is visible
* typeid : the type id for this variable
* base : zero page register pair for (sp/fp) for stack based variables
### Creating a d64 disk file
The compiler can create a .d64 disk file, that includes the compiled .prg file as the first file in the directory and a series of additional resource files. The name of the disk file is provided with the -d64 command line options, additional files with the -f or -fz option.
@ -177,7 +280,7 @@ The compressed files can be loaded into memory and decompressed using the oscar_
The windows installer puts the samples into the users documents folder, using the directory "%userprofile%\documents\oscar64\samples". A batch file *make.bat* is also placed into this directory which invokes the compiler and builds all samples. It invokes a second batch file in "%userprofile%\documents\oscar64\bin\oscar64.bat" that calls the compiler.
On a linux installation one can build the samples invoking the *build.sh* shell script in the samples directory.
On a linux installation one can build the samples invoking the *build.sh* shell script in the samples directory, for multithreading use *make -C samples -j*.
### Debugging
@ -316,6 +419,8 @@ Set optimizer options that are active for the functions after it
* inline : inline if requesed with inline storage attribute
* autoinline : auto inline of small or only once used functions
* maxinline : inline any function suitable
* constparams : enable constant parameter folding into called functions
* noconstparams : disable constant parameter folding into called functions
* 0 : no optimization
* 1 : default optimizations
* 2 : aggressive optimizations
@ -459,6 +564,28 @@ This sample fills a single screen column with a given color, by generating 25 as
This sample initially assigns the value 0 to the pre processor macro ry and increments it each time the loop body is replicated. The loop generates 25 copies of the body, each with a different value for ry.
A simpler loop with only a single line template expansion is provided with the for preprocessor command:
#for(<iterator>, <count>) <text>
This sample generates an array with pointers to screen rows:
char * const ScreenRows2[] = {
#for(i,SCREEN_HEIGHT) Screen + SCREEN_WIDTH * i,
};
The preprocessor keeps track of the source location while parsing a file to generate error messages and debug symbols. This is problematic for generated code, where the C source file position does not reflect the actual source position.
The source position can be set with the #line directiv
#line linenum
sets the line number
#line linenum "sourcefile"
sets the line number and source file name
### Linker control

154
autotest/arrayconstruct.cpp Normal file
View File

@ -0,0 +1,154 @@
#include <assert.h>
int t, n, m, k;
struct C1
{
int a;
C1(void);
~C1(void);
C1(const C1 & c);
C1 & operator=(const C1 & c);
};
struct C2
{
C1 nc[10], mc[20];
};
C1::C1(void)
{
a = 1;
n++;
t++;
}
C1::C1(const C1 & c)
{
a = c.a;
k++;
t++;
}
C1 & C1::operator=(const C1 & c)
{
a = c.a;
m++;
return *this;
}
C1::~C1(void)
{
t--;
}
void test_local_init(void)
{
n = 0;
{
C1 c[10];
}
assert(n == 10 && t == 0);
}
void test_member_init(void)
{
n = 0;
{
C2 d;
}
assert(n == 30 && t == 0);
}
void test_member_array_init(void)
{
n = 0;
{
C2 d[5];
}
assert(n == 150 && t == 0);
}
void test_local_copy(void)
{
n = 0;
k = 0;
{
C1 c[10];
C1 d(c[4]);
}
assert(n == 10 && k == 1 && t == 0);
}
void test_member_copy(void)
{
n = 0;
k = 0;
{
C2 d;
C2 e(d);
}
assert(n == 30 && k == 30 && t == 0);
}
void test_local_assign(void)
{
n = 0;
k = 0;
m = 0;
{
C1 c[10];
C1 d[5];
d[4] = c[2];
}
assert(n == 15 && k == 0 && m == 1 && t == 0);
}
void test_member_assign(void)
{
n = 0;
k = 0;
m = 0;
{
C2 d;
C2 e;
e = d;
}
assert(n == 60 && k == 0 && m == 30 && t == 0);
}
int main(void)
{
#if 0
test_local_init();
test_member_init();
#endif
test_member_array_init();
#if 0
test_local_copy();
test_member_copy();
test_local_assign();
test_member_assign();
#endif
return 0;
}

View File

@ -16,7 +16,7 @@ int main(void)
put(j, j);
int s = -45;
for(int j=0; j<10; j++)
s += get[j];
s += get(j);
return s;
}

View File

@ -1,5 +1,53 @@
rem @echo off
@call :test bitfields.cpp
@if %errorlevel% neq 0 goto :error
@call :test opp_string.cpp
@if %errorlevel% neq 0 goto :error
@call :test opp_array.cpp
@if %errorlevel% neq 0 goto :error
@call :test opp_vector.cpp
@if %errorlevel% neq 0 goto :error
@call :test opp_vector_string.cpp
@if %errorlevel% neq 0 goto :error
@call :test opp_streamtest.cpp
@if %errorlevel% neq 0 goto :error
@call :test opp_pairtest.cpp
@if %errorlevel% neq 0 goto :error
@call :test opp_parts.cpp
@if %errorlevel% neq 0 goto :error
@call :test operatoroverload.cpp
@if %errorlevel% neq 0 goto :error
@call :test virtualdestruct.cpp
@if %errorlevel% neq 0 goto :error
@call :test vcalltest.cpp
@if %errorlevel% neq 0 goto :error
@call :test vcalltree.cpp
@if %errorlevel% neq 0 goto :error
@call :test constructortest.cpp
@if %errorlevel% neq 0 goto :error
@call :test copyconstructor.cpp
@if %errorlevel% neq 0 goto :error
@call :test copyassign.cpp
@if %errorlevel% neq 0 goto :error
@call :test arrayconstruct.cpp
@if %errorlevel% neq 0 goto :error
@call :test stdlibtest.c
@if %errorlevel% neq 0 goto :error
@ -57,6 +105,9 @@ rem @echo off
@call :test arrayinittest.c
@if %errorlevel% neq 0 goto :error
@call :test arrayindexintrangecheck.c
@if %errorlevel% neq 0 goto :error
@call :test array2stringinittest.c
@if %errorlevel% neq 0 goto :error
@ -165,6 +216,9 @@ rem @echo off
@call :testn stripedarraytest.c
@if %errorlevel% neq 0 goto :error
@call :testn mmultest.c
@if %errorlevel% neq 0 goto :error
@exit /b 0
:error
@ -172,31 +226,31 @@ echo Failed with error #%errorlevel%.
exit /b %errorlevel%
:test
..\release\oscar64 -e %~1
..\release\oscar64 -e -bc %~1
@if %errorlevel% neq 0 goto :error
..\release\oscar64 -e -n %~1
@if %errorlevel% neq 0 goto :error
..\release\oscar64 -e -O2 %~1
..\release\oscar64 -e -O2 -bc %~1
@if %errorlevel% neq 0 goto :error
..\release\oscar64 -e -O2 -n %~1
@if %errorlevel% neq 0 goto :error
..\release\oscar64 -e -O0 %~1
..\release\oscar64 -e -O0 -bc %~1
@if %errorlevel% neq 0 goto :error
..\release\oscar64 -e -O0 -n %~1
@if %errorlevel% neq 0 goto :error
..\release\oscar64 -e -Os %~1
..\release\oscar64 -e -Os -bc %~1
@if %errorlevel% neq 0 goto :error
..\release\oscar64 -e -Os -n %~1
@if %errorlevel% neq 0 goto :error
..\release\oscar64 -e -O3 %~1
..\release\oscar64 -e -O3 -bc %~1
@if %errorlevel% neq 0 goto :error
..\release\oscar64 -e -O3 -n %~1
@ -205,19 +259,19 @@ exit /b %errorlevel%
@exit /b 0
:testb
..\release\oscar64 -e %~1
..\release\oscar64 -e -bc %~1
@if %errorlevel% neq 0 goto :error
..\release\oscar64 -e -O2 %~1
..\release\oscar64 -e -bc -O2 %~1
@if %errorlevel% neq 0 goto :error
..\release\oscar64 -e -O0 %~1
..\release\oscar64 -e -bc -O0 %~1
@if %errorlevel% neq 0 goto :error
..\release\oscar64 -e -Os %~1
..\release\oscar64 -e -bc -Os %~1
@if %errorlevel% neq 0 goto :error
..\release\oscar64 -e -O3 %~1
..\release\oscar64 -e -bc -O3 %~1
@if %errorlevel% neq 0 goto :error
@exit /b 0

355
autotest/bitfields.cpp Normal file
View File

@ -0,0 +1,355 @@
#include <assert.h>
struct A
{
char x : 4;
char y : 1;
char z : 3;
};
A a = {7, 1, 2};
void test_char_fit(void)
{
assert(a.x == 7);
assert(a.y == 1);
assert(a.z == 2);
assert(sizeof(A) == 1);
for(int i=0; i<16; i++)
{
a.x = i;
a.y = 0;
a.z = 3;
assert(a.x == i);
assert(a.y == 0);
assert(a.z == 3);
}
}
struct B
{
char x : 6;
char y : 6;
char z : 6;
char w : 6;
};
B b = {11, 22, 33, 44};
void test_char_cross(void)
{
assert(b.x == 11);
assert(b.y == 22);
assert(b.z == 33);
assert(b.w == 44);
assert(sizeof(B) == 3);
for(int i=0; i<64; i++)
{
b.x = i * 1;
b.y = i * 3;
b.z = i * 5;
b.w = i * 7;
assert(b.x == ((i * 1) & 0x3f));
assert(b.y == ((i * 3) & 0x3f));
assert(b.z == ((i * 5) & 0x3f));
assert(b.w == ((i * 7) & 0x3f));
}
}
struct C
{
unsigned x : 4;
unsigned y : 1;
unsigned z : 3;
};
C c = {7, 1, 2};
void test_word_fit(void)
{
assert(c.x == 7);
assert(c.y == 1);
assert(c.z == 2);
assert(sizeof(C) == 1);
for(int i=0; i<16; i++)
{
c.x = i;
c.y = 0;
c.z = 3;
assert(c.x == i);
assert(c.y == 0);
assert(c.z == 3);
}
}
struct D
{
unsigned x : 10;
unsigned y : 10;
unsigned z : 10;
unsigned w : 10;
};
D d = {111, 222, 333, 444};
void test_word_cross(void)
{
assert(d.x == 111);
assert(d.y == 222);
assert(d.z == 333);
assert(d.w == 444);
assert(sizeof(D) == 5);
for(int i=0; i<1024; i++)
{
d.x = i * 1;
d.y = i * 3;
d.z = i * 5;
d.w = i * 7;
assert(d.x == ((i * 1) & 0x3ff));
assert(d.y == ((i * 3) & 0x3ff));
assert(d.z == ((i * 5) & 0x3ff));
assert(d.w == ((i * 7) & 0x3ff));
}
}
struct E
{
unsigned long x : 4;
unsigned long y : 1;
unsigned long z : 3;
};
E e = {7, 1, 2};
void test_dword_fit(void)
{
assert(e.x == 7);
assert(e.y == 1);
assert(e.z == 2);
assert(sizeof(E) == 1);
for(int i=0; i<16; i++)
{
e.x = i;
e.y = 0;
e.z = 3;
assert(e.x == i);
assert(e.y == 0);
assert(e.z == 3);
}
}
struct F
{
unsigned long x : 20;
unsigned long y : 20;
unsigned long z : 20;
unsigned long w : 20;
};
F f = {111111UL, 222222UL, 333333UL, 444444UL};
void test_dword_cross(void)
{
assert(f.x == 111111UL);
assert(f.y == 222222UL);
assert(f.z == 333333UL);
assert(f.w == 444444UL);
assert(sizeof(F) == 10);
for(int i=0; i<1024; i++)
{
f.x = i * 11UL;
f.y = i * 33UL;
f.z = i * 55UL;
f.w = i * 77UL;
assert(f.x == ((i * 11UL) & 0xfffffUL));
assert(f.y == ((i * 33UL) & 0xfffffUL));
assert(f.z == ((i * 55UL) & 0xfffffUL));
assert(f.w == ((i * 77UL) & 0xfffffUL));
}
}
struct G
{
signed char x : 1;
signed char y : 5;
signed char z : 2;
};
G g = {0, -1, -2};
void test_char_signed(void)
{
assert(g.x == 0);
assert(g.y == -1);
assert(g.z == -2);
assert(sizeof(G) == 1);
for(int i=-16; i<16; i++)
{
g.x = -1;
g.y = i;
g.z = 1;
assert(g.x == -1);
assert(g.y == i);
assert(g.z == 1);
}
}
struct H
{
int x : 10;
int y : 10;
int z : 10;
int w : 10;
};
H h = {111, -222, -333, 444};
void test_word_signed(void)
{
assert(h.x == 111);
assert(h.y == -222);
assert(h.z == -333);
assert(h.w == 444);
assert(sizeof(H) == 5);
for(int i=-32; i<32; i++)
{
h.x = i * 1;
h.y = i * 3;
h.z = i * 5;
h.w = i * 7;
assert(h.x == i * 1);
assert(h.y == i * 3);
assert(h.z == i * 5);
assert(h.w == i * 7);
}
}
void test_inc_char_fit(void)
{
A ai;
ai.x = 7;
ai.y = 1;
ai.z = 2;
for(int i=0; i<16; i++)
{
assert(ai.x == ((7 + i) & 15));
assert(ai.y == ((1 + i) & 1));
assert(ai.z == ((2 + i) & 7));
ai.x++;
ai.y++;
ai.z++;
}
}
void test_inc_char_cross(void)
{
B bi;
bi.x = 11;
bi.y = 22;
bi.z = 33;
bi.w = 44;
for(int i=0; i<64; i++)
{
assert(bi.x == ((11 + i) & 0x3f));
assert(bi.y == ((22 + i) & 0x3f));
assert(bi.z == ((33 + i) & 0x3f));
assert(bi.w == ((44 + i) & 0x3f));
bi.x++;
bi.y++;
bi.z++;
bi.w++;
}
}
void test_add_char_cross(void)
{
B bi= {0};
bi.x = 11;
bi.y = 22;
bi.z = 33;
bi.w = 44;
for(int i=0; i<64; i++)
{
assert(bi.x == ((11 + 5 * i) & 0x3f));
assert(bi.y == ((22 + 21 * i) & 0x3f));
assert(bi.z == ((33 - 4 * i) & 0x3f));
assert(bi.w == ((44 - 11 * i) & 0x3f));
bi.x += 5;
bi.y += 21;
bi.z -= 4;
bi.w -= 11;
}
}
void test_add_word_fit(void)
{
C ci = {0};
ci.x = 7;
ci.y = 1;
ci.z = 2;
for(int i=0; i<16; i++)
{
assert(ci.x == ((7 + 5 * i) & 15));
assert(ci.y == ((1 + 21 * i) & 1));
assert(ci.z == ((2 - 4 * i) & 7));
ci.x += 5;
ci.y += 21;
ci.z -= 4;
}
}
void test_add_word_cross(void)
{
D di = {0};
di.x = 111;
di.y = 222;
di.z = 333;
di.w = 444;
for(int i=0; i<1024; i++)
{
assert(di.x == ((111 + 5 * i) & 0x3ff));
assert(di.y == ((222 + 21 * i) & 0x3ff));
assert(di.z == ((333 - 4 * i) & 0x3ff));
assert(di.w == ((444 - 11 * i) & 0x3ff));
di.x += 5;
di.y += 21;
di.z -= 4;
di.w -= 11;
}
}
int main(void)
{
test_char_fit();
test_char_cross();
test_word_fit();
test_word_cross();
test_dword_fit();
test_dword_cross();
test_char_signed();
test_word_signed();
test_inc_char_fit();
test_inc_char_cross();
test_add_char_cross();
test_add_word_fit();
test_add_word_cross();
return 0;
}

View File

@ -0,0 +1,165 @@
#include <assert.h>
int t, n;
struct C1
{
int a;
C1(int x);
~C1(void);
};
C1::C1(int x) : a(x)
{
t += a;
n++;
}
C1::~C1(void)
{
t -= a;
}
void test_base(void)
{
n = 0;
{
C1 x(2);
C1 y(1);
}
assert(t == 0 && n == 2);
}
void test_base_loop(void)
{
n = 0;
for(int i=0; i<10; i++)
{
C1 x(2);
C1 y(1);
}
assert(t == 0 && n == 20);
}
struct C2
{
C1 c, d;
C2(void);
};
C2::C2(void)
: c(7), d(11)
{
}
void test_member(void)
{
n = 0;
{
C2 x();
C2 y();
}
assert(t == 0 && n == 4);
}
void test_member_loop(void)
{
n = 0;
for(int i=0; i<10; i++)
{
C2 x();
C2 y();
}
assert(t == 0 && n == 40);
}
struct C3
{
C2 x, y;
};
void test_default(void)
{
n = 0;
{
C3 x();
C3 y();
}
assert(t == 0 && n == 8);
}
void test_default_loop(void)
{
n = 0;
for(int i=0; i<10; i++)
{
C3 x();
C3 y();
}
assert(t == 0 && n == 80);
}
inline void test_inline_x(void)
{
C1 x(1), y(2);
}
void test_inline(void)
{
n = 0;
test_inline_x();
assert(t == 0 && n == 2);
}
inline void test_inline_xr(void)
{
C1 x(1), y(2);
{
C1 x(3);
return;
}
}
void test_inline_return(void)
{
n = 0;
test_inline_xr();
assert(t == 0 && n == 3);
}
int main(void)
{
test_base();
test_base_loop();
test_member();
test_member_loop();
test_default();
test_default_loop();
test_inline();
test_inline_return();
return 0;
}

126
autotest/copyassign.cpp Normal file
View File

@ -0,0 +1,126 @@
#include <assert.h>
int t, n;
struct C0
{
int u;
C0(int a);
~C0(void);
};
C0::C0(int a) : u(a)
{
t += u;
n++;
}
C0::~C0(void)
{
t -= u;
}
struct C1
{
int u;
C1(int a);
~C1(void);
C1(const C1 & c);
C1 & operator=(const C1 & c);
};
C1::C1(int a) : u(a)
{
t += u;
n++;
}
C1::~C1(void)
{
t -= u;
}
C1::C1(const C1 & c) : u(c.u)
{
t += u;
n++;
}
C1 & C1::operator=(const C1 & c)
{
t -= u;
u = c.u;
t += u;
return *this;
}
void test_assign(void)
{
n = 0;
{
C1 c(4);
C1 d(5);
c = d;
}
assert(n == 2 && t == 0);
}
struct C2
{
C1 a, b;
C2(int x, int y) : a(x), b(y)
{}
};
void test_assign_deflt(void)
{
n = 0;
{
C2 c(2, 3);
C2 d(5, 10);
c = d;
}
assert(n == 4 && t == 0);
}
int k;
C2 test_ret_v(void)
{
C2 c(5, 10);
return c;
}
C2 & test_ret_r(C2 & r)
{
return r;
}
void test_assign_return_value(void)
{
n = 0;
{
C2 c(2, 3);
c = test_ret_v();
}
assert(n == 6 && t == 0);
}
int main(void)
{
test_assign();
test_assign_deflt();
test_assign_return_value();
return 0;
}

View File

@ -0,0 +1,216 @@
#include <assert.h>
int t, n;
struct C0
{
int u;
C0(int a);
~C0(void);
};
C0::C0(int a) : u(a)
{
t += u;
n++;
}
C0::~C0(void)
{
t -= u;
}
struct C1
{
int u;
C1(int a);
~C1(void);
C1(const C1 & c);
};
C1::C1(int a) : u(a)
{
t += u;
n++;
}
C1::~C1(void)
{
t -= u;
}
C1::C1(const C1 & c) : u(c.u)
{
t += u;
n++;
}
void test_dcopy_init(void)
{
n = 0;
{
C0 x(4);
C0 y(x);
}
assert(n == 1 && t == -4);
t = 0;
}
void test_copy_init(void)
{
n = 0;
{
C1 x(4);
C1 y(x);
}
assert(n == 2 && t == 0);
}
struct C2
{
C1 a, b;
C2(void);
};
C2::C2(void) : a(1), b(3)
{}
void test_minit(void)
{
n = 0;
{
C2 x;
}
assert(n == 2 && t == 0);
}
void test_minit_copy(void)
{
n = 0;
{
C2 x;
C2 y(x);
}
assert(n == 4 && t == 0);
}
int k;
void test_param_fv(C2 c)
{
k += c.a.u;
}
void test_param_fr(C2 & c)
{
k += c.a.u;
}
void test_param_value(void)
{
n = 0;
{
C2 x;
test_param_fv(x);
}
assert(n == 4 && t == 0);
}
void test_param_ref(void)
{
n = 0;
{
C2 x;
test_param_fr(x);
}
assert(n == 2 && t == 0);
}
C2 test_ret_v(void)
{
C2 c;
return c;
}
C2 & test_ret_r(C2 & r)
{
return r;
}
void test_return_value(void)
{
n = 0;
{
C2 c(test_ret_v());
}
assert(n == 4 && t == 0);
}
void test_return_reference(void)
{
n = 0;
{
C2 d;
C2 c(test_ret_r(d));
}
assert(n == 2 && t == 0);
}
void test_retparam_value(void)
{
n = 0;
{
test_param_fv(test_ret_v());
}
assert(n == 4 && t == 0);
}
void test_retparam_reference(void)
{
n = 0;
{
test_param_fr(test_ret_v());
}
assert(n == 4 && t == 0);
}
int main(void)
{
#if 0
test_dcopy_init();
test_copy_init();
test_minit();
test_minit_copy();
test_param_value();
test_param_ref();
test_return_value();
#endif
test_retparam_value();
// test_retparam_reference();
return 0;
}

View File

@ -65,7 +65,7 @@ int main(void)
cmpflt( 1.0, 0.0, false, false, true);
cmpflt(-1.0, 0.0, false, true, false);
#if 1
cmpflt( 1.0, 1.0, true, false, false);
cmpflt( 1.0, 2.0, false, true, false);
cmpflt( 2.0, 1.0, false, false, true);
@ -94,7 +94,6 @@ int main(void)
cmpflt( -1.0, -1.000001, false, false, true);
cmpflt( -1.000001, -1.0, false, true, false);
cmpflt( -1.000001, -1.000001, true, false, false);
#endif
return 0;
}

50
autotest/makefile Normal file
View File

@ -0,0 +1,50 @@
CC=../bin/oscar64
CXX=$(CC)
SRCS=$(wildcard *.c *.cpp)
EXES=$(patsubst %.c,%,$(SRCS))
EXES:=$(patsubst %.cpp,%,$(EXES))
all: $(EXES)
%: %.c
$(CC) -e -bc $<
$(CC) -e -n $<
$(CC) -e -O2 -bc $<
$(CC) -e -O2 -n $<
$(CC) -e -O0 -bc $<
$(CC) -e -O0 -n $<
$(CC) -e -Os -bc $<
$(CC) -e -Os -n $<
$(CC) -e -O3 -bc $<
$(CC) -e -O3 -n $<
%: %.cpp
$(CXX) -e -bc $<
$(CXX) -e -n $<
$(CXX) -e -O2 -bc $<
$(CXX) -e -O2 -n $<
$(CXX) -e -O0 -bc $<
$(CXX) -e -O0 -n $<
$(CXX) -e -Os -bc $<
$(CXX) -e -Os -n $<
$(CXX) -e -O3 -bc $<
$(CXX) -e -O3 -n $<
# testb
bitshifttest: bitshifttest.c
$(CC) -e -bc $<
$(CC) -e -bc -O2 $<
$(CC) -e -bc -O0 $<
$(CC) -e -bc -Os $<
$(CC) -e -bc -O3 $<
$(CC) -e -n $<
# testn
stripedarraytest: stripedarraytest.c
$(CC) -e -O2 -n $<
$(CC) -e -O0 -n $<
$(CC) -e -Os -n $<
$(CC) -e -O3 -n $<
clean:
$(RM) *.asm *.bcs *.int *.lbl *.map *.prg

43
autotest/mmultest.c Normal file
View File

@ -0,0 +1,43 @@
#include <gfx/vector3d.h>
#include <assert.h>
#include <stdio.h>
Matrix4 ml, mr;
int main(void)
{
for(char i=0; i<16; i++)
{
for(char j=0; j<16; j++)
{
for(char k=0; k<16; k++)
{
ml.m[k] = (i == k) ? 1.0 : 0.0;
mr.m[k] = (j == k) ? 1.0 : 0.0;
}
mat4_mmul(&ml, &mr);
#if 0
printf("%d, %d\n", i, j);
for(char k=0; k<16; k++)
printf("%f ", ml.m[k]);
printf("\n");
#endif
for(char k=0; k<16; k++)
{
char ix = i & 3, iy = i >> 2;
char jx = j & 3, jy = j >> 2;
char kx = k & 3, ky = k >> 2;
if (ky == jy && kx == ix && jx == iy)
assert(ml.m[k] == 1.0);
else
assert(ml.m[k] == 0.0);
}
}
}
return 0;
}

View File

@ -0,0 +1,90 @@
#include <assert.h>
struct A
{
int n;
A(int n_)
: n(n_) {}
A(const A & a)
: n(a.n) {}
A operator+(const A & a) const
{
return A(n + a.n);
}
A operator-(const A & a) const
{
return A(n - a.n);
}
A & operator+=(const A & a)
{
n += a.n;
return *this;
}
A & operator-=(const A & a)
{
n -= a.n;
return *this;
}
A operator-(void) const
{
return A(-n);
}
A & operator++(void)
{
n++;
return *this;
}
A & operator--(void)
{
n--;
return *this;
}
A operator++(int);
A operator--(int);
};
A A::operator++(int)
{
A a(*this);
n++;
return a;
}
A A::operator--(int)
{
A a(*this);
n--;
return a;
}
int main(void)
{
A a(7), b(8), c(9);
assert((++a).n == 8);
assert(a.n == 8);
assert((--a).n == 7);
assert(a.n == 7);
assert((a++).n == 7);
assert(a.n == 8);
assert((a--).n == 8);
assert(a.n == 7);
assert((a + b - c + -a + -b - -c).n == 0);
return 0;
}

23
autotest/opp_array.cpp Normal file
View File

@ -0,0 +1,23 @@
#include <opp/array.h>
#include <assert.h>
int main(void)
{
opp::array<int, 10> a10;
opp::array<int, 20> a20;
for(int i=0; i<10; i++)
a10[i] = i;
for(int i=0; i<20; i++)
a20[i] = i;
int s = 0;
for(int i=0; i<10; i++)
s += a10[i];
for(int i=10; i<20; i++)
s -= a20[i];
assert(s == -100);
return 0;
}

28
autotest/opp_pairtest.cpp Normal file
View File

@ -0,0 +1,28 @@
#include <assert.h>
#include <opp/vector.h>
#include <opp/utility.h>
#include <opp/iostream.h>
using namespace opp;
int main(void)
{
vector<pair<int, int> > vii;
for(int i=0; i<100; i++)
vii.push_back(make_pair(i, i * i));
int sum1 = 0;
long sum2 = 0;
for(const auto & v : vii)
{
sum1 += v.first;
sum2 += v.second;
}
assert(sum1 == 4950);
assert(sum2 == 328350l);
return 0;
}

2
autotest/opp_part1.cpp Normal file
View File

@ -0,0 +1,2 @@
#include "opp_part1.h"

40
autotest/opp_part1.h Normal file
View File

@ -0,0 +1,40 @@
#pragma once
#include <opp/vector.h>
class A
{
protected:
int a, b;
public:
A(int a_, int b_)
: a(a_), b(b_)
{}
int sum(void) const
{
return a * b;
}
};
class AS
{
protected:
opp::vector<A> va;
public:
AS(const opp::vector<A> & v)
: va(v)
{}
int sum(void)
{
int s = 0;
for(const auto & a : va)
s += a.sum();
return s;
}
};
#pragma compile("opp_part1.cpp")

13
autotest/opp_part2.cpp Normal file
View File

@ -0,0 +1,13 @@
#include "opp_part2.h"
BS::BS(const opp::vector<A> & v)
: va(v)
{}
int BS::sum(void)
{
int s = 0;
for(const auto & a : va)
s += a.sum();
return s;
}

16
autotest/opp_part2.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include "opp_part1.h"
class BS
{
protected:
opp::vector<A> va;
public:
BS(const opp::vector<A> & v);
int sum(void);
};
#pragma compile("opp_part2.cpp")

25
autotest/opp_parts.cpp Normal file
View File

@ -0,0 +1,25 @@
#include <assert.h>
#include "opp_part1.h"
#include "opp_part2.h"
int main(void)
{
opp::vector<A> va;
va.push_back(A(1, 2));
va.push_back(A(3, 4));
va.push_back(A(6, 4));
va.push_back(A(0, 9));
AS as(va);
va.push_back(A(7, 1));
BS bs(va);
assert(bs.sum() == 2 + 12 + 24 + 7);
assert(as.sum() == 2 + 12 + 24);
return 0;
}

View File

@ -0,0 +1,83 @@
#include <opp/string.h>
#include <stdlib.h>
#include <assert.h>
#include <opp/sstream.h>
#include <math.h>
using opp::ostringstream;
using opp::istringstream;
using opp::endl;
float fdist(float a, float b)
{
float d = fabs(a - b);
a = fabs(a);
b = fabs(b);
return d / (a > b ? a : b);
}
int main(void)
{
ostringstream os;
for(int i=0; i<40; i++)
{
os << i << endl;
}
istringstream is(os.str());
int j = 0, k = 47;
#if 1
while (is >> k)
{
assert(k == j++);
}
assert(j == 40);
#endif
os.str(opp::string());
#if 0
cout << "[" << os.str() << "]" << endl;
os << "HELLO";
cout << "[" << os.str() << "]" << endl;
#endif
#if 1
float f = 1.0, g = 1.0;
for(int i=0; i<10; i++)
{
os << f << " " << g << endl;
// cout << os.str();
f *= 5.1;
g *= 0.12;
}
is.str(os.str());
f = 1.0, g = 1.0;
float fr, gr;
j = 0;
while (is >> fr >> gr)
{
// cout << f << " " << fr << ", " << g << " " << gr << ", " << fdist(fr, f) << endl;
assert(fdist(fr, f) < 1.0e-5);
assert(fdist(gr, g) < 1.0e-5);
f *= 5.1;
g *= 0.12;
j++;
}
assert(j == 10);
#endif
return 0;
}

103
autotest/opp_string.cpp Normal file
View File

@ -0,0 +1,103 @@
#include <opp/string.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
using opp::string;
static const char HelloWorld[] = "Hello World";
static const char AndBeyond[] = "And Beyond";
static const char And[] = "And";
static const char HelloWorldAndBeyond[] = "Hello World And Beyond";
__noinline void test_create(void)
{
string s1();
string s2(HelloWorld);
string s3(s2);
string s4('a');
assert(!strcmp(s2.tocstr(), HelloWorld));
assert(!strcmp(s3.tocstr(), HelloWorld));
assert(s4.size() == 1 && s4[0] == 'a');
}
__noinline void test_concat(void)
{
string s1();
string s2(HelloWorld);
string s3(AndBeyond);
string s4 = s1 + s2;
string s5 = s2 + " " + s3;
string s6 = s2 + " " + AndBeyond;
assert(!strcmp(s4.tocstr(), HelloWorld));
assert(!strcmp(s5.tocstr(), HelloWorldAndBeyond));
assert(!strcmp(s6.tocstr(), HelloWorldAndBeyond));
}
__noinline void test_find(void)
{
string s1(HelloWorldAndBeyond);
string s2(And);
assert(s1.find(HelloWorld) == 0);
assert(s1.find(AndBeyond) == 12);
assert(s1.find(And) == 12);
assert(s1.find(s2) == 12);
assert(s1.find(' ') == 5);
assert(s1.find(' ', 6) == 11);
}
__noinline void test_assign(void)
{
string s1(HelloWorld);
string s2(AndBeyond);
string s3;
s3 = s1;
s3 = s2;
s3 = s1;
s3 += " ";
s3 += s2;
assert(!strcmp(s3.tocstr(), HelloWorldAndBeyond));
s3 <<= 12;
assert(!strcmp(s3.tocstr(), AndBeyond));
s3 = HelloWorldAndBeyond;
assert(!strcmp(s3.tocstr(), HelloWorldAndBeyond));
s3 >>= 11;
assert(!strcmp(s3.tocstr(), HelloWorld));
}
static char * test;
int main(void)
{
test = new char;
unsigned avail = heapfree();
test_create();
assert(avail == heapfree());
test_concat();
assert(avail == heapfree());
test_find();
assert(avail == heapfree());
test_assign();
assert(avail == heapfree());
delete test;
return 0;
}

68
autotest/opp_vector.cpp Normal file
View File

@ -0,0 +1,68 @@
#include <opp/vector.h>
#include <opp/algorithm.h>
#include <assert.h>
#include <opp/iostream.h>
int main(void)
{
opp::vector<int> a;
for(int i=0; i<10; i++)
a.push_back(i);
int s = 0;
for(int i=0; i<a.size(); i++)
s += a[i];
assert(s == 45);
for(int i=0; i<5; i++)
a.erase(i);
s = 0;
for(int i=0; i<a.size(); i++)
s += a[i];
assert(s == 1 + 3 + 5 + 7 + 9);
opp::vector<int> v;
for(int i=0; i<10; i++)
v.push_back(i);
assert(v.size() == 10);
v.insert(0, 20);
assert(v.size() == 11);
v.insert(6, 21);
assert(v.size() == 12);
v.insert(12, 22);
int * fi = opp::find(v.begin(), v.end(), 21);
fi = v.insert(fi, 30);
fi = v.insert(fi, 31);
fi = v.insert(fi, 32);
assert(v.size() == 16);
assert(v[0] == 20);
assert(v[15] == 22);
assert(v[8] == 32);
fi = opp::find(v.begin(), v.end(), 32);
for(int i=0; i<30; i++)
{
fi = v.insert(fi, i + 40);
}
assert(v.size() == 46);
assert(v[28] == 60);
v.erase(10, 10);
for(int i : v)
opp::cout << i << ", ";
opp::cout << "\n";
return 0;
}

View File

@ -0,0 +1,38 @@
#include <opp/vector.h>
#include <opp/string.h>
#include <assert.h>
#include <stdlib.h>
#include <opp/iostream.h>
using opp::string;
using opp::vector;
string join(const vector<string> & vs)
{
string sj;
for(int i=0; i<vs.size(); i++)
sj += vs[i];
return sj;
}
int main(void)
{
vector<string> vs;
string a;
for(int i=0; i<10; i++)
{
vs.push_back(a);
a += "x";
}
int s = 0;
for(int i=0; i<10; i++)
s += vs[i].size();
assert(s == 45);
assert(join(vs).size() == 45);
return 0;
}

View File

@ -51,16 +51,15 @@ void heapcheck(void)
for(i=0; i<s; i++)
{
if (p[i] != n)
{
printf("MemError %d at %d:%d != %d\n", k, i, n, p[i]);
exit(-2);
}
}
free(memp[n]);
s = rand() % 100 + 3;
mems[n] = s;
memp[n] = malloc(s);
if (!memp[n])
exit(-3);
memset(memp[n], n, s);
}
}

View File

@ -54,7 +54,6 @@ long sieve(long size)
int main(void)
{
testmuli(0, 0, 0);
testmuli(1, 0, 0);
testmuli(0, 1, 0);
@ -111,7 +110,6 @@ int main(void)
assert(sieve(200) == 47);
assert(sieve(1000) == 169);
long a = 0, b = 0;
for(long i=0; i<10000; i++)
{

93
autotest/vcalltest.cpp Normal file
View File

@ -0,0 +1,93 @@
#include <assert.h>
struct A
{
virtual int f(int x);
};
struct B : A
{
virtual int f(int x);
};
struct C : A
{
virtual int f(int x);
virtual int g(int y, int z);
};
struct D : B
{
virtual int f(int x);
};
struct E : C
{
virtual int f(int x);
virtual int g(int y, int z);
};
struct F : C
{
virtual int g(int y, int z);
};
int A::f(int x)
{
return x * 1;
}
int B::f(int x)
{
return x * 2;
}
int C::f(int x)
{
return x * 3;
}
int C::g(int y, int z)
{
return (y + z) * 3;
}
int D::f(int x)
{
return x * 4;
}
int E::f(int x)
{
return x * 5;
}
int E::g(int y, int z)
{
return (y + z) * 5;
}
int F::g(int y, int z)
{
return (y + z) * 6;
}
int main(void)
{
A a;
B b;
C c;
D d;
E e;
F f;
assert(a.f(3) == c.f(1));
assert(b.f(4) == d.f(2));
assert(e.f(2) == b.f(5));
assert(f.f(5) == e.f(3));
assert(c.g(3, 2) == e.g(1, 2));
assert(c.g(1, 5) == f.g(0, 3));
return 0;
}

79
autotest/vcalltree.cpp Normal file
View File

@ -0,0 +1,79 @@
#include <assert.h>
struct Node
{
virtual float eval(void)
{
return 1.0e6;
}
};
struct ConstNode : Node
{
float c;
ConstNode(float c_)
: c(c_) {}
virtual float eval(void)
{
return c;
}
};
struct BinopNode : Node
{
Node * left, * right;
BinopNode(Node * left_, Node * right_)
: left(left_), right(right_)
{}
};
struct AddNode : BinopNode
{
AddNode(Node * left_, Node * right_)
: BinopNode(left_, right_)
{}
virtual float eval(void)
{
return left->eval() + right->eval();
}
};
struct SubNode : BinopNode
{
SubNode(Node * left_, Node * right_)
: BinopNode(left_, right_)
{}
virtual float eval(void)
{
return left->eval() - right->eval();
}
};
struct MulNode : BinopNode
{
MulNode(Node * left_, Node * right_)
: BinopNode(left_, right_)
{}
virtual float eval(void)
{
return left->eval() * right->eval();
}
};
int main(void)
{
Node * n =
new SubNode(
new MulNode(new ConstNode(4), new ConstNode(5)),
new AddNode(new ConstNode(12), new ConstNode(7)));
assert(n->eval() == 1.0);
return 0;
}

View File

@ -0,0 +1,63 @@
#include <assert.h>
int a, b, c;
struct A
{
A(void)
{
a++;
}
virtual ~A(void)
{
a--;
}
};
struct B : A
{
B(void)
{
b++;
}
virtual ~B(void)
{
b--;
}
};
struct C : B
{
C(void)
{
c++;
}
virtual ~C(void)
{
c--;
}
};
int main()
{
A * t[3];
t[0] = new A();
t[1] = new B();
t[2] = new C();
assert(a == 3 && b == 2 && c == 1);
delete t[0];
delete t[1];
delete t[2];
assert(a == 0 && b == 0 && c == 0);
return 0;
}

View File

@ -14,14 +14,14 @@ IEC_STATUS iec_status;
#pragma optimize(push)
#pragma optimize(1)
// multiples of 5us
static void delay(char n)
{
while (n)
{
__asm {
nop
}
n--;
ldx n
l1:
dex
bne l1
}
}
@ -70,7 +70,7 @@ static bool data_check(void)
return true;
else
{
iec_status = IEC_TIMEOUT;
iec_status = IEC_DATA_CHECK;
return false;
}
}
@ -81,7 +81,7 @@ bool iec_eoi(void)
while (!(cia2.pra & CIA2B_DATAIN))
;
delay(50);
delay(40);
return data_check();
}
@ -93,25 +93,21 @@ bool iec_write(char b)
while (!(cia2.pra & CIA2B_DATAIN))
;
clock_high();
for(char i=0; i<8; i++)
{
clock_high();
if (b & 1)
data_low();
else
data_high();
delay(5);
clock_low();
b >>= 1;
__asm
{
nop
nop
nop
nop
}
}
data_low();
delay(5);
clock_high();
data_low();
}
return data_check();
}
@ -131,13 +127,7 @@ char iec_read(void)
{
iec_status = IEC_EOF;
data_high();
__asm
{
nop
nop
nop
nop
}
delay(4);
data_low();
cnt = 200;
@ -172,10 +162,11 @@ char iec_read(void)
void iec_atn(char dev, char sec)
{
cdata_low();
atn_high();
clock_high();
delay(100);
delay(200);
iec_write(dev);
if (sec != 0xff)
@ -190,8 +181,10 @@ void iec_talk(char dev, char sec)
{
iec_status = IEC_OK;
iec_atn(dev | 0x40, sec);
iec_atn(dev | 0x40, sec | 0x60);
clock_low();
delay(10);
}
void iec_untalk(void)
@ -203,7 +196,7 @@ void iec_listen(char dev, char sec)
{
iec_status = IEC_OK;
iec_atn(dev | 0x20, sec);
iec_atn(dev | 0x20, sec | 0x60);
}
void iec_unlisten(void)
@ -216,6 +209,7 @@ void iec_open(char dev, char sec, const char * fname)
iec_status = IEC_OK;
iec_atn(dev | 0x20, sec | 0xf0);
char i = 0;
while (fname[i])
{
@ -233,6 +227,28 @@ void iec_close(char dev, char sec)
iec_unlisten();
}
int iec_write_bytes(const char * data, int num)
{
for(int i=0; i<num; i++)
{
if (!iec_write(data[i]))
return i;
}
return num;
}
int iec_read_bytes(char * data, int num)
{
for(int i=0; i<num; i++)
{
char ch = iec_read();
if (iec_status != IEC_OK)
return i;
data[i] = ch;
}
return num;
}
#pragma optimize(pop)

View File

@ -7,7 +7,8 @@ enum IEC_STATUS
IEC_EOF = 0x01,
IEC_ERROR = 0x80,
IEC_TIMEOUT
IEC_TIMEOUT,
IEC_DATA_CHECK
};
extern IEC_STATUS iec_status;
@ -32,6 +33,11 @@ void iec_open(char dev, char sec, const char * fname);
void iec_close(char dev, char sec);
int iec_write_bytes(const char * data, int num);
int iec_read_bytes(char * data, int num);
#pragma compile("iecbus.c")
#endif

View File

@ -1,11 +1,8 @@
#include "memmap.h"
volatile char PLAShadow;
__asm DoneTrampoline
{
lda PLAShadow
sta $01
stx $01
pla
tax
pla
@ -17,8 +14,6 @@ __asm IRQTrampoline
pha
txa
pha
lda #$36
sta $01
lda #>DoneTrampoline
pha
@ -27,7 +22,10 @@ __asm IRQTrampoline
tsx
lda $0105, x
pha
jmp ($fffa)
ldx $01
lda #$36
sta $01
jmp ($fffe)
}
__asm NMITrampoline
@ -35,8 +33,6 @@ __asm NMITrampoline
pha
txa
pha
lda #$36
sta $01
lda #>DoneTrampoline
pha
@ -45,19 +41,23 @@ __asm NMITrampoline
tsx
lda $0105, x
pha
jmp ($fffe)
ldx $01
lda #$36
sta $01
jmp ($fffa)
}
void mmap_trampoline(void)
{
*((void **)0xfffa) = IRQTrampoline;
*((void **)0xfffe) = NMITrampoline;
*((void **)0xfffa) = NMITrampoline;
*((void **)0xfffe) = IRQTrampoline;
}
#pragma native(mmap_trampoline)
void mmap_set(char pla)
char mmap_set(char pla)
{
PLAShadow = pla;
char ppla = *((char *)0x01);
*((volatile char *)0x01) = pla;
return ppla;
}

View File

@ -18,9 +18,9 @@
void mmap_trampoline(void);
// Set the memory map in a way that is compatible with the IRQ
// trampoline
// trampoline, returns the previous state
inline void mmap_set(char pla);
inline char mmap_set(char pla);
#pragma compile("memmap.c")

View File

@ -7,20 +7,20 @@ bool mouse_lb, mouse_rb;
static char mouse_px, mouse_py;
static char mouse_port;
inline signed char dpos(char * old, char new)
inline signed char dpos(char * old, char mnew)
{
new = (new & 0x7f) >> 1;
mnew = (mnew & 0x7f) >> 1;
char diff = (new - *old) & 0x3f;
char diff = (mnew - *old) & 0x3f;
if (diff >= 0x20)
{
*old = new;
*old = mnew;
return diff | 0xe0;
}
else if (diff)
{
*old = new;
*old = mnew;
return diff;
}

View File

@ -97,6 +97,9 @@ __asm irq2
tya
pha
lda $01
pha
lda #$35
sta $01
@ -136,7 +139,7 @@ ji:
ex:
lda PLAShadow
pla
sta $01
pla

View File

@ -1,7 +1,7 @@
#include "sprites.h"
#include "rasterirq.h"
static char * vspriteScreen;
static volatile char * vspriteScreen;
void spr_init(char * screen)
@ -108,6 +108,22 @@ void spr_color(char sp, char color)
vic.spr_color[sp] = color;
}
void spr_expand(char sp, bool xexpand, bool yexpand)
{
__assume (sp < 8);
char m = 1 << sp;
if (xexpand)
vic.spr_expand_x |= m;
else
vic.spr_expand_x &= ~m;
if (yexpand)
vic.spr_expand_y |= m;
else
vic.spr_expand_y &= ~m;
}
static char vspriteYLow[VSPRITES_MAX], vspriteXLow[VSPRITES_MAX], vspriteXHigh[VSPRITES_MAX];
static char vspriteImage[VSPRITES_MAX], vspriteColor[VSPRITES_MAX];
@ -217,7 +233,7 @@ void vspr_sort(void)
void vspr_update(void)
{
char xymask = 0;
char * vsprs = vspriteScreen;
volatile char * vsprs = vspriteScreen;
#pragma unroll(full)
for(char ui=0; ui<8; ui++)

View File

@ -39,6 +39,10 @@ inline void spr_image(char sp, char image);
inline void spr_color(char sp, char color);
// change the image of a sprite
inline void spr_expand(char sp, bool xexpand, bool yexpand);
// The virtual sprite system works with the rasterirq library to multiplex
// 16 virtual sprites onto the actual eight hardware sprites. It uses the slots
// 0 to 8 of the rasterirq library to switch the sprites mid screen. The

View File

@ -21,7 +21,7 @@ int vic_sprgetx(byte s)
return vic.spr_pos[s].x | ((vic.spr_msbx & (1 << s)) ? 256 : 0);
}
void vic_setmode(VicMode mode, char * text, char * font)
void vic_setmode(VicMode mode, const char * text, const char * font)
{
switch (mode)
{
@ -73,6 +73,15 @@ void vic_waitFrame(void)
;
}
void vic_waitFrames(char n)
{
while (n > 0)
{
vic_waitFrame();
n--;
}
}
void vic_waitLine(int line)
{
char upper = (char)(line >> 1) & VIC_CTRL1_RST8;

View File

@ -91,7 +91,7 @@ enum VicMode
// set the display mode and base address. This will also
// adapt the bank.
void vic_setmode(VicMode mode, char * text, char * font);
void vic_setmode(VicMode mode, const char * text, const char * font);
// put a sprite at the given x/y location, taking care of the
// x MSB
@ -109,6 +109,9 @@ inline void vic_waitTop(void);
// wait for the top of the frame and then for the bottom of the visual area
inline void vic_waitFrame(void);
// wait for n frames
void vic_waitFrames(char n);
// wait for a specific raster line
void vic_waitLine(int line);

View File

@ -32,6 +32,12 @@ __asm bsinit
jsr 0xff81
sta 0xff01
}
__asm dswap
{
sta 0xff00
jsr 0xff5f
sta 0xff01
}
#pragma code(code)
#elif defined(__PLUS4__)
#pragma code(lowcode)
@ -94,6 +100,31 @@ __asm bsinit
#define bsinit 0xff81
#endif
#if defined(__C128__)
void dispmode40col(void)
{
if (*(volatile char *)0xd7 >= 128)
{
__asm
{
jsr dswap
}
}
}
void dispmode80col(void)
{
if (*(volatile char *)0xd7 < 128)
{
__asm
{
jsr dswap
}
}
}
#endif
void iocharmap(IOCharMap chmap)
{
giocharmap = chmap;

View File

@ -18,6 +18,10 @@ extern IOCharMap giocharmap;
void iocharmap(IOCharMap chmap);
#if defined(__C128__)
void dispmode40col(void);
void dispmode80col(void);
#endif
int kbhit(void);

View File

@ -160,7 +160,7 @@ wx1:
jmp lx2
w0:
lda #$3f
lda #$2f
sta $00
lda #$36
sta $01
@ -4112,3 +4112,449 @@ cmpne:
}
#pragma bytecode(BC_BINOP_CMP_S32, inp_op_cmp_s32)
void HeapStart, HeapEnd;
struct Heap {
Heap * next, * end;
} HeapNode;
#pragma section(heap, 0x0000, HeapStart, HeapEnd)
__asm malloc
{
// make room for two additional bytes
// to store pointer to end of used memory
clc
lda accu + 0
adc #2
sta tmp
lda accu + 1
adc #$00
sta tmp + 1
// check if heap is initialized
lda HeapNode + 2
bne hasHeap
// initialize heap
// set next pointer to null
lda #0
sta HeapStart + 0
sta HeapStart + 1
// set size of dummy node to null
inc HeapNode + 2
// set next pointer of dummy node to first free heap block
lda #<HeapStart
sta HeapNode + 0
lda #>HeapStart
sta HeapNode + 1
// set end of memory block to end of heap
lda #<HeapEnd
sta HeapStart + 2
lda #>HeapEnd
sta HeapStart + 3
hasHeap:
// remember address of pointer to this
// heap block, to correct if block is a
// perfect fit
lda #<HeapNode
ldx #>HeapNode
// Now loop over free nodes, until we find a match
loop:
sta accu + 2
stx accu + 3
// next heap block
// calculate potential end of block
clc
ldy #0
lda (accu + 2), y
sta accu + 0
adc tmp
sta tmp + 2
iny
lda (accu + 2), y
sta accu + 1
// exit if out of blocks
beq hempty
adc tmp + 1
sta tmp + 3
// Check if in range of current free block
ldy #2
lda (accu), y
cmp tmp + 2
iny
lda (accu), y
sbc tmp + 3
bcs avail
// move current block pointer to prev pointer
lda accu
ldx accu + 1
jmp loop
hempty:
// no more heap blocks
rts
avail:
// calculate new end of block
clc
lda tmp + 2
adc #3
and #$fc
sta tmp + 4
lda tmp + 3
adc #0
sta tmp + 5
// compare with end of free block
ldy #2
lda tmp + 4
cmp (accu), y
bne nofit
iny
lda tmp + 5
cmp (accu), y
bne nofit
// perfect fit, so have previous block point to
// next free block
ldy #0
lda (accu), y
sta (accu + 2), y
iny
lda (accu), y
sta (accu + 2), y
jmp found
nofit:
// set next link in new link block
ldy #0
lda (accu), y
sta (tmp + 4), y
lda tmp + 4
sta (accu + 2), y
iny
lda (accu), y
sta (tmp + 4), y
lda tmp + 5
sta (accu + 2), y
// set new end of remaining block
iny
lda (accu), y
sta (tmp + 4), y
iny
lda (accu), y
sta (tmp + 4), y
found:
// remember end of allocated block
ldy #0
lda tmp + 2
sta (accu), y
iny
lda tmp + 3
sta (accu), y
// advanve by two bytes to skip size
lda accu
ora #2
sta accu
rts
}
__asm inp_malloc
{
sty tmpy
jsr malloc
ldy tmpy
jmp startup.exec
}
#pragma bytecode(BC_MALLOC, inp_malloc)
__asm free
{
// two bytes back to fix remembered end of block
lda accu
and #$fc
sta accu
// check nullptr free
ora accu + 1
bne notnull
rts
notnull:
// cache end of block, rounding to next four byte
// address
clc
ldy #0
lda (accu), y
adc #3
and #$fc
sta accu + 2
iny
lda (accu), y
adc #0
sta accu + 3
// pointer to heap block, starting with
// dummy block
lda #<HeapNode
ldx #>HeapNode
loop:
sta tmp + 2
stx tmp + 3
// check if end of heap
ldy #1
lda (tmp + 2), y
beq noend
tax
dey
lda (tmp + 2), y
// Check if next block is behind the block to free
cpx accu + 3
bcc loop
bne noend
cmp accu + 2
bcc loop
bne noend
// The end of the block to free matches the
// start of the next free block
// Pointer to next next block
ldy #0
lda (accu + 2), y
sta (accu), y
iny
lda (accu + 2), y
sta (accu), y
// Append free space to new block
iny
lda (accu + 2), y
sta (accu), y
iny
lda (accu + 2), y
sta (accu), y
jmp start
noend:
// Link to next block
ldy #0
lda (tmp + 2), y
sta (accu), y
iny
lda (tmp + 2), y
sta (accu), y
// End of new free block
iny
lda accu + 2
sta (accu), y
iny
lda accu + 3
sta (accu), y
start:
// Check if new block matches end of previous block
ldy #2
lda (tmp + 2), y
cmp accu
bne nostart
iny
lda (tmp + 2), y
cmp accu + 1
bne nostart
// If so, increase the size of previous block and link
// to free block after
ldy #0
lda (accu), y
sta (tmp + 2), y
iny
lda (accu), y
sta (tmp + 2), y
iny
lda (accu), y
sta (tmp + 2), y
iny
lda (accu), y
sta (tmp + 2), y
rts
nostart:
// Link to new free block
ldy #0
lda accu
sta (tmp + 2), y
iny
lda accu + 1
sta (tmp + 2), y
rts
}
__asm inp_free
{
sty tmpy
jsr free
ldy tmpy
jmp startup.exec
}
#pragma bytecode(BC_FREE, inp_free)
#pragma runtime(malloc, malloc)
#pragma runtime(free, free)
#if 0
void * malloc(unsigned int size)
{
size = (size + 7) & ~3;
if (!freeHeapInit)
{
freeHeap = (Heap *)&HeapStart;
freeHeap->next = nullptr;
freeHeap->size = (unsigned int)&HeapEnd - (unsigned int)&HeapStart;
freeHeapInit = true;
}
Heap * pheap = nullptr, * heap = freeHeap;
while (heap)
{
if (size <= heap->size)
{
if (size == heap->size)
{
if (pheap)
pheap->next = heap->next;
else
freeHeap = heap->next;
}
else
{
Heap * nheap = (Heap *)((int)heap + size);
nheap->size = heap->size - size;
nheap->next = heap->next;
if (pheap)
pheap->next = nheap;
else
freeHeap = nheap;
heap->size = size;
}
return (void *)((int)heap + 2);
}
pheap = heap;
heap = heap->next;
}
return nullptr;
}
void free(void * ptr)
{
if (!ptr)
return;
Heap * fheap = (Heap *)((int)ptr - 2);
Heap * eheap = (Heap *)((int)ptr - 2 + fheap->size);
if (freeHeap)
{
if (eheap == freeHeap)
{
fheap->size += freeHeap->size;
fheap->next = freeHeap->next;
freeHeap = fheap;
}
else if (eheap < freeHeap)
{
fheap->next = freeHeap;
freeHeap = fheap;
}
else
{
Heap * pheap = freeHeap;
while (pheap->next && pheap->next < fheap)
pheap = pheap->next;
Heap * nheap = (Heap *)((int)pheap + pheap->size);
if (nheap == fheap)
{
pheap->size += fheap->size;
if (pheap->next == eheap)
{
pheap->size += pheap->next->size;
pheap->next = pheap->next->next;
}
}
else if (pheap->next == eheap)
{
fheap->next = pheap->next->next;
fheap->size += pheap->next->size;
pheap->next = fheap;
}
else
{
fheap->next = pheap->next;
pheap->next = fheap;
}
}
}
else
{
freeHeap = fheap;
freeHeap->next = nullptr;
}
}
#endif

View File

@ -142,8 +142,8 @@ enum ByteCode
BC_BRANCHF_LE,
BC_LOOP_U8,
BC_UNUSED_2,
BC_UNUSED_3,
BC_MALLOC,
BC_FREE,
BC_UNUSED_4,
BC_UNUSED_5,
BC_UNUSED_6,

View File

@ -1,4 +1,5 @@
#include "ctype.h"
#include "conio.h"
#define CC_CTRL 0x00
#define CC_BREAK 0x01
@ -86,3 +87,19 @@ bool isxdigit(char c)
{
return (c < 128) && (_cinfo[c] & CC_HEX);
}
char tolower(char c)
{
if (c >= 'A' && c <= 'Z')
return c + ('a' - 'A');
else
return c;
}
char toupper(char c)
{
if (c >= 'a' && c <= 'z')
return c + ('A' - 'a');
else
return c;
}

View File

@ -25,6 +25,9 @@ inline bool isdigit(char c);
inline bool isxdigit(char c);
char tolower(char c);
char toupper(char c);
#pragma compile("ctype.c")

View File

@ -30,6 +30,9 @@ bool isfinite(float f);
#pragma intrinsic(floor)
#pragma intrinsic(ceil)
#pragma intrinsic(sin)
#pragma intrinsic(cos)
#pragma compile("math.c")

11
include/new Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include "stddef.h"
namespace std
{
void * operator new(size_t size);
void * operator new(void * ptr, size_t size);
}

84
include/opp/algorithm.h Normal file
View File

@ -0,0 +1,84 @@
#ifndef OPP_ALGORITHM_H
#define OPP_ALGORITHM_H
#include "utility.h"
namespace opp {
template<class T, class LT>
void sort(T s, T e)
{
while (s != e)
{
auto p = s;
auto q = s;
q++;
while (q != e)
{
if (LT(*q, *p))
{
swap(*q, *p);
p++;
swap(*q, *p);
}
q++;
}
sort<T, LT>(s, p);
p++;
s = p;
}
}
template<class T, class LF>
void sort(T s, T e, LF lt)
{
while (s != e)
{
auto p = s;
auto q = s;
q++;
while (q != e)
{
if (lt(*q, *p))
{
swap(*q, *p);
p++;
swap(*q, *p);
}
q++;
}
sort(s, p, lt);
p++;
s = p;
}
}
template<class II, class OI>
OI copy(II first, II last, OI result)
{
while (first != last)
{
*result = *first;
++result; ++first;
}
return result;
}
template<class II, class T>
II find (II first, II last, const T& val)
{
while (first != last)
{
if (*first == val) return first;
++first;
}
return last;
}
}
#endif

120
include/opp/array.h Normal file
View File

@ -0,0 +1,120 @@
#ifndef OPP_ARRAY_H
#define OPP_ARRAY_H
namespace opp {
template <class T, int n>
class array
{
protected:
T _data[n];
public:
typedef T element_type;
int size(void) const
{
return n;
}
int max_size(void) const
{
return n;
}
bool empty(void) const
{
return n == 0;
}
const T & at(int at) const
{
return _data[at];
}
T & at(int at)
{
return _data[at];
}
T & operator[] (int at)
{
return _data[at];
}
const T & operator[] (int at) const
{
return _data[at];
}
T * begin(void)
{
return _data;
}
const T * begin(void) const
{
return _data;
}
const T * cbegin(void) const
{
return _data;
}
T * end(void)
{
return _data + n;
}
const T * end(void) const
{
return _data + n;
}
const T * cend(void) const
{
return _data + n;
}
T & back(void)
{
return _data[n - 1];
}
const T & back(void) const
{
return _data[n - 1];
}
T & front(void)
{
return _data[0];
}
const T & front(void) const
{
return _data[0];
}
T * data(void)
{
return _data;
}
const T * data(void) const
{
return _data;
}
void fill(const T & t)
{
for(int i=0; i<n; i++)
_data[i] = t;
}
};
}
#endif

207
include/opp/bidxlist.h Normal file
View File

@ -0,0 +1,207 @@
#ifndef OPP_BIDXLIST_H
#ifndef OPP_BIDXLIST_H
template <class T, int n>
class bindexlist
{
public:
char _free;
char _pred[n], _succ[n];
T _data[n];
class iterator
{
public:
bindexlist * _l;
char _i;
iterator(void) : _l(nullptr) {}
iterator(bindexlist * l, char i)
: _l(l), _i(i) {}
iterator(const iterator & li) : _l(li._l), _i(li._i) {}
iterator & operator=(const iterator & li)
{
_l = li._l;
_i = li._i;
return *this;
}
T & operator*()
{
return _l->_data[_i];
}
T * operator->()
{
return _l->_data + _i;
}
iterator & operator++(void)
{
_i = _l->_succ[_i];
return *this;
}
iterator operator++(int)
{
char i = _i;
_i = _l->_succ[_i];
return bindexlist::iterator(_l, i);
}
iterator & operator+=(char n)
{
while (n--)
_i = _l->_succ[_i];
return *this;
}
iterator & operator--(void)
{
_i = _l->_pred[_i];
return *this;
}
iterator operator++(int)
{
char i = _i;
_i = _l->_pred[_i];
return bindexlist::iterator(_l, i);
}
iterator & operator-=(char n)
{
while (n--)
_i = _l->_pred[_i];
return *this;
}
bool operator==(const iterator & li)
{
return _i == li._i;
}
bool operator!=(const iterator & li)
{
return _i != li._i;
}
};
public:
typedef T element_type;
typedef iterator iterator_type;
bindexlist(void)
{
_succ[0] = 0;
_pred[0] = 0;
for(char i=1; i<n; i++)
_succ[i] = i + 1;
_free = 1;
}
~bindexlist(void)
{
}
iterator begin(void)
{
return iterator(this, _succ[0]);
}
iterator end(void)
{
return iterator(this, 0);
}
T & front(void)
{
return _data[_succ[0]];
}
const T & front(void) const
{
return _data[_succ[0]];
}
T & back(void)
{
return _data[_pred[0]];
}
const T & back(void) const
{
return _data[_pred[0]];
}
iterator erase(iterator it)
{
char s = _succ[it._i];
_succ[_pred[it._i]] = _pred[it._i];
_pred[_succ[it._i]] = s;
_succ[it._i] = _free;
_free = it._i;
return iterator(this, s);
}
iterator erase(iterator first, iterator last)
{
char s = _succ[last._i];
_succ[_pred[last._i]] = _pred[first._i];
_pred[_succ[first._i]] = s;
_succ[last._i] = _free;
_free = first._i;
return iterator(this, s);
}
void pop_front(void)
{
char i = _succ[0];
char s = _succ[i];
_pred[s] = 0;
_succ[0] = s;
_succ[i] = _free;
_free = i;
}
void pop_back(void)
{
char i = _pred[0];
char p = _pred[i];
_succ[p] = 0;
_pred[0] = p;
_pred[i] = _free;
_free = i;
}
void push_back(const T & t)
{
char i = _free;
_data[i] = t;
_free = _succ[_free];
_succ[i] = 0;
_pred[i] = _pred[0];
_succ[_pred[0]] = i;
_pred[0] = i;
}
void push_front(const T & t)
{
char i = _free;
_data[i] = t;
_free = _succ[_free];
_succ[i] = 0;
_succ[i] = _succ[0];
_pred[_succ[0]] = i;
_succ[0] = i;
}
};
#endif

24
include/opp/ifstream.cpp Normal file
View File

@ -0,0 +1,24 @@
#include "ifstream.h"
#include <c64/kernalio.h>
namespace opp {
ifstream::ifstream(char fnum, char device, char channel, const string & name)
{
this->fnum = fnum;
krnio_setnam(name);
krnio_open(fnum, device, channel);
}
ifstream::~ifstream(void)
{
krnio_close(fnum);
}
void ifstream::refill(void)
{
mBufferPos = 0;
mBufferFill = krnio_read(fnum, mBuffer, 32);
}
}

25
include/opp/ifstream.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef OPP_IFSTREAM_H
#define OPP_IFSTREAM_H
#include "iostream.h"
#include "string.h"
namespace opp {
class ifstream : public istream
{
public:
ifstream(char fnum, char device, char channel, const string & name);
~ifstream(void);
protected:
virtual void refill(void);
char fnum;
};
}
#pragma compile("ifstream.cpp")
#endif

1003
include/opp/iostream.cpp Normal file

File diff suppressed because it is too large Load Diff

216
include/opp/iostream.h Normal file
View File

@ -0,0 +1,216 @@
#ifndef OPP_IOSTREAM_H
#define OPP_IOSTREAM_H
#include <opp/string.h>
namespace opp {
class ios
{
public:
constexpr ios(void);
virtual ~ios(void);
char fill() const;
char fill(char cillch);
char width() const;
char width(char wide);
char precision() const;
char precision(char prec);
enum fmtflags
{
boolalpha = 0x0001,
dec = 0x0002,
fixed = 0x0004,
hex = 0x0008,
internal = 0x0010,
left = 0x0020,
oct = 0x0040,
right = 0x0080,
scientific = 0x0100,
showbase = 0x0200,
showpoint = 0x0400,
showpos = 0x0800,
skipws = 0x1000,
unitbuf = 0x2000,
uppercase = 0x3000,
adjustfield = 0x00b0,
basefield = 0x004a,
floatfield = 0x0104
};
enum statebits
{
goodbit = 0,
badbit = 1,
eofbit = 2,
failbit = 4,
};
fmtflags flags(void) const;
fmtflags flags(fmtflags f);
fmtflags setf(fmtflags f);
fmtflags setf(fmtflags f, fmtflags m);
fmtflags unsetf(fmtflags f);
bool good(void) const;
bool eof(void) const;
bool fail(void) const;
bool bad(void) const;
bool operator!(void) const;
operator bool(void);
statebits rdstate(void) const;
void clear(void);
protected:
fmtflags mFlags;
statebits mState;
char mWidth;
char mPrecision;
char mFill;
};
class ostream;
typedef ostream & (* manip)(ostream &);
class ostream : public ios
{
public:
constexpr ostream(void);
ostream & put(char c);
ostream & write(const char * s, int n);
ostream & operator<<(bool val);
ostream & operator<<(char val);
ostream & operator<<(int val);
ostream & operator<<(unsigned val);
ostream & operator<<(long val);
ostream & operator<<(unsigned long val);
ostream & operator<<(float val);
ostream & operator<<(const char * p);
ostream & operator<<(const string & s);
ostream & operator<<(manip m);
protected:
void putnum(const char * buffer, char prefix, char size);
void numput(unsigned n, char sign);
void numput(unsigned long n, char sign);
virtual void bput(char ch);
};
class istream : public ios
{
public:
char get(void);
istream & get(char & c);
istream & get(char * s, char size);
istream & get(char * s, char size, char delim);
istream & getline(char * s, char size);
istream & getline(char * s, char size, char delim);
istream & ignore(char size);
istream & ignore(char size, char delim);
istream & putback(char c);
istream & unget(void);
istream & operator>>(bool & val);
istream & operator>>(int & val);
istream & operator>>(unsigned & val);
istream & operator>>(long & val);
istream & operator>>(unsigned long & val);
istream & operator>>(float & val);
istream & operator>>(char * p);
istream & operator>>(string & s);
istream(void);
protected:
char mBuffer[32];
char mBufferPos, mBufferFill;
virtual void refill(void);
unsigned getnum(void);
unsigned long getnuml(void);
float getnumf(void);
void doskipws(void);
};
class costream : public ostream
{
public:
constexpr costream(void);
protected:
void bput(char ch);
};
class cistream : public istream
{
public:
cistream(void);
protected:
void refill(void);
};
ostream & endl(ostream & os);
struct iosetf {
ios::fmtflags flags;
iosetf(ios::fmtflags flags_) : flags(flags_) {}
};
ostream & operator<<(ostream & os, const iosetf & s);
iosetf setf(ios::fmtflags flags);
struct iosetw {
char width;
iosetw(char width_) : width(width_) {}
};
iosetw setw(char width);
ostream & operator<<(ostream & os, const iosetw & s);
struct iosetprecision {
char precision;
iosetprecision(char precision_) : precision(precision_) {}
};
iosetprecision setprecision(char precision);
ostream & operator<<(ostream & os, const iosetprecision & s);
struct iosetfill {
char fill;
iosetfill(char fill_) : fill(fill_) {}
};
iosetfill setfill(char fill);
ostream & operator<<(ostream & os, const iosetfill & s);
extern cistream cin;
extern costream cout;
}
#pragma compile("iostream.cpp");
#endif

137
include/opp/iterator.h Normal file
View File

@ -0,0 +1,137 @@
#ifndef OPP_ITERATOR_H
#define OPP_ITERATOR_H
namespace opp
{
template <class CT>
class back_insert_iterator
{
protected:
CT * co;
public:
back_insert_iterator (CT & c) : co(&c) {}
back_insert_iterator & operator= (const CT::element_type & t)
{
co->push_back(t);
return *this;
}
back_insert_iterator & operator= (CT::element_type && t)
{
co->push_back(t);
return *this;
}
back_insert_iterator & operator* (void)
{
return *this;
}
back_insert_iterator & operator++ (void)
{
return *this;
}
back_insert_iterator operator++ (int)
{
return *this;
}
};
template <class CT>
class front_insert_iterator
{
protected:
CT * co;
public:
front_insert_iterator (CT & c) : co(&c) {}
front_insert_iterator & operator= (const CT::element_type & t)
{
co->push_front(t);
return *this;
}
front_insert_iterator & operator= (CT::element_type && t)
{
co->push_front(t);
return *this;
}
front_insert_iterator & operator* (void)
{
return *this;
}
front_insert_iterator & operator++ (void)
{
return *this;
}
front_insert_iterator operator++ (int)
{
return *this;
}
};
template <class CT>
class insert_iterator
{
protected:
CT * co;
CT::iterator_type ci;
public:
insert_iterator (CT & c, const CT::iterator_type & i) : co(&c), ci(i) {}
insert_iterator & operator= (const CT::element_type & t)
{
ci = co->insert(ci, t); ++ci;
return *this;
}
insert_iterator & operator= (CT::element_type && t)
{
ci = co->insert(ci, t); ++ci;
return *this;
}
insert_iterator & operator* (void)
{
return *this;
}
insert_iterator & operator++ (void)
{
return *this;
}
insert_iterator operator++ (int)
{
return *this;
}
};
template <class CT>
front_insert_iterator<CT> front_inserter (CT & c)
{
return front_insert_iterator<CT>(c);
}
template <class CT>
back_insert_iterator<CT> back_inserter (CT & c)
{
return back_insert_iterator<CT>(c);
}
template <class CT>
insert_iterator<CT> inserter (CT & c, const CT::iterator_type & i)
{
return insert_iterator<CT>(c, i);
}
}

298
include/opp/list.h Normal file
View File

@ -0,0 +1,298 @@
#ifndef OPP_LIST
#define OPP_LIST
namespace opp
{
template <class T>
class listhead
{
public:
listnode<T> * succ, * pred;
listhead()
{
succ = (listnode<T> *)this;
pred = (listnode<T> *)this;
}
};
template <class T>
class listnode : public listhead<T>
{
public:
T data;
listnode(const T & t) : data(t) {}
listnode(T && t) : data(t) {}
};
template <class T>
class list_iterator
{
public:
listnode<T> * node;
public:
list_iterator(void) : node(nullptr) {}
list_iterator(listnode<T> * n) : node(n) {}
list_iterator(const list_iterator & li) : node(li.node) {}
list_iterator & operator=(const list_iterator & li)
{
node = li.node;
return *this;
}
T & operator*()
{
return node->data;
}
T * operator->()
{
return &(node->data);
}
list_iterator & operator++(void)
{
node = node->succ;
return *this;
}
list_iterator operator++(int)
{
listnode<T> * n = node;
node = node->succ;
return list_iterator(n);
}
list_iterator & operator+=(int n)
{
while (n--)
node = node->succ;
return *this;
}
list_iterator & operator--(void)
{
node = node->pred;
return *this;
}
list_iterator operator++(int)
{
listnode<T> * n = node;
node = node->pred;
return list_iterator(n);
}
list_iterator & operator-=(int n)
{
while (n--)
node = node->pred;
return *this;
}
bool operator==(const list_iterator & li)
{
return node == li.node;
}
bool operator!=(const list_iterator & li)
{
return node != li.node;
}
};
template <class T>
class list
{
private:
typedef listnode<T> ln;
listhead<T> head;
public:
typedef T element_type;
typedef list_iterator<T> iterator_type;
list(void)
{}
~list(void)
{
listnode<T> * n = head.succ;
while (n != &head)
{
listnode<T> * m = n->succ;
delete n;
n = m;
}
}
list_iterator<T> begin(void)
{
return list_iterator<T>(head.succ);
}
list_iterator<T> end(void)
{
return list_iterator<T>((listnode<T> *)&head);
}
T & front(void)
{
return head.succ->data;
}
const T & front(void) const
{
return head.succ->data;
}
T & back(void)
{
return head.pred->data;
}
const T & back(void) const
{
return head.pred->data;
}
list_iterator<T> erase(list_iterator<T> it);
list_iterator<T> erase(list_iterator<T> first, list_iterator<T> last);
void pop_front(void);
void pop_back(void);
void push_front(const T & t);
void push_front(T && t);
void push_back(const T & t);
void push_back(T && t);
list_iterator<T> insert(list_iterator<T> it, const T & t);
list_iterator<T> insert(list_iterator<T> it, T && t);
};
template <class T>
void list<T>::pop_front(void)
{
listnode<T> * n = head.succ;
head.succ = n->succ;
n->succ->pred = (listnode<T> *)&head;
delete n;
}
template <class T>
void list<T>::pop_back(void)
{
listnode<T> * n = head.pred;
head.pred = n->pred;
n->pred->succ = (listnode<T> *)&head;
delete n;
}
template <class T>
void list<T>::push_front(const T & t)
{
listnode<T> * n = new listnode<T>(t);
n->pred = (listnode<T> *)&head;
n->succ = head.succ;
head.succ->pred = n;
head.succ = n;
}
template <class T>
void list<T>::push_front(T && t)
{
listnode<T> * n = new listnode<T>(t);
n->pred = (listnode<T> *)&head;
n->succ = head.succ;
head.succ->pred = n;
head.succ = n;
}
template <class T>
void list<T>::push_back(const T & t)
{
listnode<T> * n = new listnode<T>(t);
n->succ = (listnode<T> *)&head;
n->pred = head.pred;
head.pred->succ = n;
head.pred = n;
}
template <class T>
void list<T>::push_back(T && t)
{
listnode<T> * n = new listnode<T>(t);
n->succ = (listnode<T> *)&head;
n->pred = head.pred;
head.pred->succ = n;
head.pred = n;
}
template <class T>
list_iterator<T> list<T>::erase(list_iterator<T> it)
{
listnode<T> * n = it.node;
listnode<T> * s = n->succ;
n->succ->pred = n->pred;
n->pred->succ = n->succ;
delete n;
return list_iterator<T>(s);
}
template <class T>
list_iterator<T> list<T>::erase(list_iterator<T> first, list_iterator<T> last)
{
listnode<T> * n = first.node;
listnode<T> * s = last.node;
n->pred->succ = s;
s->pred = n->pred;
while (n != s)
{
listnode<T> * m = n->succ;
delete n;
n = m;
}
return list_iterator<T>(s);
}
template <class T>
list_iterator<T> list<T>::insert(list_iterator<T> it, const T & t)
{
listnode<T> * n = new listnode<T>(t);
n->succ = it.node;
n->pred = it.node->pred;
it.node->pred->succ = n;
it.node->pred = n;
return list_iterator<T>(n);
}
template <class T>
list_iterator<T> list<T>::insert(list_iterator<T> it, T && t)
{
listnode<T> * n = new listnode<T>(t);
n->succ = it.node;
n->pred = it.node->pred;
it.node->pred->succ = n;
it.node->pred = n;
return list_iterator<T>(n);
}
}
#endif

32
include/opp/ofstream.cpp Normal file
View File

@ -0,0 +1,32 @@
#include "ofstream.h"
#include <c64/kernalio.h>
namespace opp {
ofstream::ofstream(char fnum, char device, char channel, const string & name)
{
this->fnum = fnum;
krnio_setnam(name.tocstr());
krnio_open(fnum, device, channel);
mBufferFill = 0;
}
ofstream::~ofstream(void)
{
if (mBufferFill > 0)
krnio_write(fnum, mBuffer, mBufferFill);
krnio_close(fnum);
}
void ofstream::bput(char ch)
{
mBuffer[mBufferFill++] = ch;
if (mBufferFill == 32)
{
krnio_write(fnum, mBuffer, mBufferFill);
mBufferFill = 0;
}
}
}

28
include/opp/ofstream.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef OPP_OFSTREAM_H
#define OPP_OFSTREAM_H
#include "iostream.h"
#include "string.h"
namespace opp {
class ofstream : public ostream
{
public:
ofstream(char fnum, char device, char channel, const string & name);
~ofstream(void);
protected:
virtual void bput(char ch);
char mBuffer[32];
char mBufferFill;
char fnum;
};
}
#pragma compile("ofstream.cpp")
#endif

80
include/opp/slab.h Normal file
View File

@ -0,0 +1,80 @@
#ifndef OPP_SLAB_H
#define OPP_SLAB_H
template<class T, int N>
class slabptr
{
public:
char index;
slabptr(void)
: index(N)
{}
slabptr(char i)
: index(i)
{}
slabptr(const slabptr & i)
: index(i.index)
{}
auto operator-> ();
auto & operator* ();
};
template <class T, int N>
class slab
{
protected:
static __striped T buffer[N];
static char head;
static char next[N];
public:
typedef slabptr<T, N> ptr;
static void init(void);
static auto alloc(void);
static void free(ptr p);
};
template<class T, int N>
inline auto slabptr<T, N>::operator-> ()
{
return slab<T, N>::buffer + index;
}
template<class T, int N>
inline auto & slabptr<T, N>::operator* ()
{
return slab<T, N>::buffer[index];
}
template <class T, int N>
void slab<T, N>::init(void)
{
head = 0;
for(char i=0; i<N; i++)
next[i] = i + 1;
}
template <class T, int N>
auto slab<T, N>::alloc(void)
{
char i = head;
head = next[head];
return slabptr<T, N>(i);
}
template <class T, int N>
void slab<T, N>::free(slabptr<T, N> p)
{
next[p.index] = head;
head = p.index;
}
#endif

86
include/opp/sstream.cpp Normal file
View File

@ -0,0 +1,86 @@
#include "sstream.h"
#include <stdlib.h>
namespace opp {
ostringstream::ostringstream(void)
{
mBuffer = nullptr;
mBFill = mBSize = 0;
}
ostringstream::~ostringstream(void)
{
free(mBuffer);
}
void ostringstream::bput(char ch)
{
if (!mBuffer)
{
mBSize = 15;
mBFill = 0;
mBuffer = malloc(15);
}
else if (mBFill == mBSize)
{
mBSize *= 2;
char * b = malloc(mBSize);
for(char i=0; i<mBFill; i++)
b[i] = mBuffer[i];
free(mBuffer);
mBuffer = b;
}
mBuffer[mBFill++] = ch;
}
string ostringstream::str(void) const
{
return string(mBuffer, mBFill);
}
void ostringstream::str(const string & str)
{
mBFill = str.size();
if (mBFill > mBSize)
{
free(mBuffer);
mBSize = mBFill;
mBuffer = malloc(mBSize);
}
str.copyseg(mBuffer, 0, mBFill);
}
istringstream::istringstream(const string & str)
: mString(str), mSPos(0)
{}
istringstream::~istringstream(void)
{}
string istringstream::str(void) const
{
return mString;
}
void istringstream::str(const string & str)
{
mState = goodbit;
mString = str;
mSPos = 0;
}
void istringstream::refill(void)
{
mBufferFill = 0;
mBufferPos = 0;
char ch;
while (mSPos < mString.size() && mBufferFill < 32)
{
mBuffer[mBufferFill++] = mString[mSPos++];
}
}
}

42
include/opp/sstream.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef OPP_SSTREAM_H
#define OPP_SSTREAM_H
#include "iostream.h"
namespace opp {
class ostringstream : public ostream
{
public:
ostringstream(void);
~ostringstream(void);
string str(void) const;
void str(const string & str);
protected:
void bput(char ch);
char * mBuffer;
char mBFill, mBSize;
};
class istringstream : public istream
{
public:
istringstream(const string & str);
~istringstream(void);
string str(void) const;
void str(const string & str);
protected:
virtual void refill(void);
string mString;
char mSPos;
};
}
#pragma compile("sstream.cpp")
#endif

258
include/opp/static_vector.h Normal file
View File

@ -0,0 +1,258 @@
#ifndef OPP_STATIC_VECTOR_H
#define OPP_STATIC_VECTOR_H
#include <new>
#include <stdlib.h>
#include <opp/utility.h>
namespace opp {
template <class T, int N>
class static_vector
{
protected:
char _space[N * sizeof(T)];
enum { m = N } _size;
public:
typedef T element_type;
static_vector(void) : _size(0) {}
static_vector(size_t n) : _size(n)
{
T * data = (T*)_space;
for(size_t i=0; i<n; i++)
new (data + i) T;
}
static_vector(const static_vector & v)
: _size(v._size)
{
T * data = (T*)_space, * vdata = (T*)(v._space);
for(size_t i=0; i<_size; i++)
new (data + i)T(vdata[i]);
}
~static_vector(void)
{
T * data = (T*)_space;
for(size_t i=0; i<_size; i++)
data[i].~T();
}
static_vector & operator=(const static_vector & v)
{
if (this != &v)
{
T * data = (T*)_space, * vdata = (T*)(v._space);
for(size_t i=0; i<_size; i++)
data[i].~T();
_size = v._size;
for(size_t i=0; i<_size; i++)
new (data + i)T(vdata[i]);
}
return *this;
}
size_t size(void) const
{
return _size;
}
size_t max_size(void) const
{
return N;
}
bool empty(void) const
{
return _size == 0;
}
size_t capacity(void) const
{
return N;
}
void resize(size_t n);
T & at(size_t at)
{
return ((T*)_space)[at];
}
const T & at(size_t at) const
{
return ((T*)_space)[at];
}
T & operator[](size_t at)
{
return ((T*)_space)[at];
}
const T & operator[](size_t at) const
{
return ((T*)_space)[at];
}
T * begin(void)
{
return (T*)_space;
}
const T * begin(void) const
{
return (T*)_space;
}
const T * cbegin(void) const
{
return (T*)_space;
}
T * end(void)
{
return (T*)_space + _size;
}
const T * end(void) const
{
return (T*)_space + _size;
}
const T * cend(void) const
{
return (T*)_space + _size;
}
T & front(void)
{
return ((T*)_space)[0];
}
const T & front(void) const
{
return ((T*)_space)[0];
}
T & back(void)
{
return ((T*)_space)[_size - 1];
}
const T & back(void) const
{
return ((T*)_space)[_size - 1];
}
T * data(void)
{
return (T*)_space;
}
const T * at(void) const
{
return (T*)_space;
}
void push_back(const T & t);
void push_back(T && t);
void pop_back(void)
{
_size--;
((T*)_space)[_size].~T();
}
void insert(size_t at, const T & t);
void erase(size_t at, size_t n = 1);
T * insert(T * at, const T & t);
template <typename ...P>
void emplace_back(const P&... p);
};
template <class T, int N>
void static_vector<T, N>::resize(size_t n)
{
T * data = (T*)_space;
if (n < _size)
{
for(size_t i=n; i<_size; i++)
data[i].~T();
_size = n;
}
else
{
for(size_t i=_size; i<n; i++)
new(data + i)T;
_size = n;
}
}
template <class T, int N>
void static_vector<T, N>::push_back(const T & t)
{
new ((T*)_space + _size++)T(t);
}
template <class T, int N>
void static_vector<T, N>::push_back(T && t)
{
new ((T*)_space + _size++)T(t);
}
template <class T, int N>
template <typename ...P>
void static_vector<T, N>::emplace_back(const P&... p)
{
new ((T*)_space + _size++)T(p...);
}
template <class T, int N>
void static_vector<T, N>::insert(size_t at, const T & t)
{
T * data = (T*)_space;
new (data + _size)T;
for(size_t i=_size; i>at; i--)
data[i] = move(data[i - 1]);
data[at] = t;
_size++;
}
template <class T, int N>
void static_vector<T, N>::erase(size_t at, size_t n)
{
T * data = (T*)_space;
_size -= n;
for(size_t i=at; i<_size; i++)
data[i] = move(data[i + n]);
for(size_t i=0; i<n; i++)
data[_size + i].~T();
}
template <class T, int N>
T * static_vector<T, N>::insert(T * at, const T & t)
{
T * data = (T*)_space;
T * dp = data + _size;
new (dp)T;
while (dp != at)
{
dp--;
dp[1] = move(dp[0]);
}
dp[0] = t;
_size++;
return dp + 1;
}
}
#endif

1132
include/opp/string.cpp Normal file

File diff suppressed because it is too large Load Diff

109
include/opp/string.h Normal file
View File

@ -0,0 +1,109 @@
#ifndef OPP_STRING_H
#define OPP_STRING_H
namespace opp {
class string
{
private:
char * cstr;
friend void swap(string & u, string & v);
public:
string(void);
string(const string & s);
string(string && s);
string(const char * s);
string(const char * s, char size);
string(char c);
~string(void);
unsigned size(void) const;
void clear(void);
string & operator=(const string & s);
string & operator=(string && s);
string & operator=(const char * s);
string & operator+=(const string & s);
string & operator+=(const char * s);
string & operator+=(char c);
string operator+(const string & s) const;
string operator+(const char * s) const;
string operator+(char c) const;
string & operator<<=(char n);
string & operator>>=(char n);
string operator<<(char n) const;
string operator>>(char n) const;
bool operator==(const string & s) const;
bool operator==(const char * s) const;
bool operator!=(const string & s) const;
bool operator!=(const char * s) const;
bool operator<(const string & s) const;
bool operator<(const char * s) const;
bool operator<=(const string & s) const;
bool operator<=(const char * s) const;
bool operator>(const string & s) const;
bool operator>(const char * s) const;
bool operator>=(const string & s) const;
bool operator>=(const char * s) const;
char & operator[](char t);
char operator[](char t) const;
char * begin(void);
const char * begin(void) const;
const char * cbegin(void) const;
char * end(void);
const char * end(void) const;
const char * cend(void) const;
const char * tocstr(void) const;
string substr(char pos, char len) const;
int find(const string & s) const;
int find(const char * s) const;
int find(char c) const;
int find(const string & s, char pos) const;
int find(const char * s, char pos) const;
int find(char c, char pos) const;
void copyseg(char * p, char at, char num) const;
int to_int(char * idx = nullptr, char base = 10) const;
long to_long(char * idx = nullptr, char base = 10) const;
unsigned to_uint(char * idx = nullptr, char base = 10) const;
unsigned long to_ulong(char * idx = nullptr, char base = 10) const;
float to_float(char * idx = nullptr) const;
protected:
string(char l, char * b);
};
void swap(string & u, string & v);
string to_string(int val);
string to_string(long val);
string to_string(unsigned int val);
string to_string(unsigned long val);
string to_string(float val);
}
#pragma compile("string.cpp")
#endif

40
include/opp/utility.h Normal file
View File

@ -0,0 +1,40 @@
#ifndef OPP_UTILITY_H
#define OPP_UTILITY_H
namespace opp {
template <class T>
inline T && move(T & m)
{
return (T &&)m;
}
template <class T>
inline void swap(T & x, T & y)
{
T t(x); x = y; y = move(t);
}
template<class T1, class T2>
struct pair
{
T1 first;
T2 second;
pair(T1 && t1, T2 && t2)
: first(t1), second(t2)
{}
};
template<class T1, class T2>
constexpr pair<T1, T2> make_pair(T1 && t1, T2 && t2)
{
return pair<T1, T2>(t1, t2);
}
}
#endif

333
include/opp/vector.h Normal file
View File

@ -0,0 +1,333 @@
#ifndef OPP_VECTOR_H
#define OPP_VECTOR_H
#include <new>
#include <stdlib.h>
#include <opp/utility.h>
namespace opp {
template <class T>
class vector
{
protected:
T * _data;
size_t _size, _capacity;
public:
typedef T element_type;
vector(void) : _data(nullptr), _size(0), _capacity(0) {}
vector(size_t n) : _data((T*)malloc(n * sizeof(T))), _size(n), _capacity(n)
{
for(size_t i=0; i<n; i++)
new (_data + i) T;
}
vector(const vector & v)
: _data((T*)malloc(v._size * sizeof(T))), _size(v._size), _capacity(v._size)
{
for(size_t i=0; i<_size; i++)
new (_data + i)T(v._data[i]);
}
vector(vector && v)
: _data(v._data), _size(v._size), _capacity(v._capacity)
{
v._data = nullptr;
v._size = 0;
v._capacity = 0;
}
~vector(void)
{
for(size_t i=0; i<_size; i++)
_data[i].~T();
free(_data);
}
vector & operator=(const vector & v)
{
if (this != &v)
{
for(size_t i=0; i<_size; i++)
_data[i].~T();
free(_data);
_data = (T*)malloc(v._size * sizeof(T));
_size = v._size;
_capacity = v._size;
for(size_t i=0; i<_size; i++)
new (_data + i)T(v._data[i]);
}
return *this;
}
vector & operator=(vector && v)
{
if (this != &v)
{
swap(_data, v._data);
swap(_size, v._size);
swap(_capacity, v._capacity);
}
return *this;
}
int size(void) const
{
return _size;
}
int max_size(void) const
{
return 32767;
}
bool empty(void) const
{
return _size == 0;
}
int capacity(void) const
{
return _capacity;
}
void resize(size_t n);
void reserve(size_t n);
void shrink_to_fit(void);
T & at(size_t at)
{
return _data[at];
}
const T & at(size_t at) const
{
return _data[at];
}
T & operator[](size_t at)
{
return _data[at];
}
const T & operator[](size_t at) const
{
return _data[at];
}
T * begin(void)
{
return _data;
}
const T * begin(void) const
{
return _data;
}
const T * cbegin(void) const
{
return _data;
}
T * end(void)
{
return _data + _size;
}
const T * end(void) const
{
return _data + _size;
}
const T * cend(void) const
{
return _data + _size;
}
T & front(void)
{
return _data[0];
}
const T & front(void) const
{
return _data[0];
}
T & back(void)
{
return _data[_size - 1];
}
const T & back(void) const
{
return _data[_size - 1];
}
T * data(void)
{
return _data;
}
const T * at(void) const
{
return _data;
}
void push_back(const T & t);
void push_back(T && t);
void pop_back(void)
{
_size--;
_data[_size].~T();
}
void insert(size_t at, const T & t);
void erase(size_t at, size_t n = 1);
T * insert(T * at, const T & t);
template <typename ...P>
void emplace_back(const P&... p);
protected:
T * add_back(void);
};
template <class T>
void vector<T>::reserve(size_t n)
{
if (n > _capacity)
{
_capacity = n;
T * d = (T *)malloc(_capacity * sizeof(T));
for(size_t i=0; i<_size; i++)
{
new (d + i)T(move(_data[i]));
_data[i].~T();
}
free(_data);
_data = d;
}
}
template <class T>
void vector<T>::resize(size_t n)
{
if (n < _size)
{
for(size_t i=n; i<_size; i++)
_data[i].~T();
_size = n;
}
else if (n < _capacity)
{
for(size_t i=_size; i<n; i++)
new(_data + i)T;
_size = n;
}
else
{
reserve(n);
_size = n;
}
}
template <class T>
void vector<T>::shrink_to_fit(void)
{
if (_size < _capacity)
{
_capacity = _size;
T * d = (T *)malloc(_capacity * sizeof(T));
for(size_t i=0; i<_size; i++)
{
new (d + i)T(move(_data[i]));
_data[i].~T();
}
free(_data);
_data = d;
}
}
template <class T>
T * vector<T>::add_back(void)
{
if (_size == _capacity)
reserve(_size + 1 + (_size >> 1));
return _data + _size++;
}
template <class T>
void vector<T>::push_back(const T & t)
{
new (add_back())T(t);
}
template <class T>
void vector<T>::push_back(T && t)
{
new (add_back())T(t);
}
template <class T>
template <typename ...P>
void vector<T>::emplace_back(const P&... p)
{
new (add_back())T(p...);
}
template <class T>
void vector<T>::insert(size_t at, const T & t)
{
if (_size == _capacity)
reserve(_size + 1 + (_size >> 1));
new (_data + _size)T;
for(size_t i=_size; i>at; i--)
_data[i] = move(_data[i - 1]);
_data[at] = t;
_size++;
}
template <class T>
void vector<T>::erase(size_t at, size_t n)
{
_size -= n;
for(size_t i=at; i<_size; i++)
_data[i] = move(_data[i + n]);
for(size_t i=0; i<n; i++)
_data[_size + i].~T();
}
template <class T>
T * vector<T>::insert(T * at, const T & t)
{
if (_size == _capacity)
{
unsigned f = unsigned(at) - unsigned(_data);
reserve(_size + 1 + (_size >> 1));
at = (T *)(f + unsigned(_data));
}
T * dp = _data + _size;
new (dp)T;
while (dp != at)
{
dp--;
dp[1] = move(dp[0]);
}
dp[0] = t;
_size++;
return dp + 1;
}
}
#endif

View File

@ -183,7 +183,7 @@ void putchar(char c)
{
__asm {
lda c
jmp putpch
jsr putpch
}
}

View File

@ -524,6 +524,23 @@ void exit(int status)
}
}
extern struct Heap {
Heap * next, * end;
} HeapNode;
unsigned heapfree(void)
{
unsigned avail = 0;
Heap * h = HeapNode.next;
while (h)
{
avail += (h->end - h) * sizeof(Heap);
h = h->next;
}
return avail;
}
#if 0
struct Heap {
unsigned int size;
Heap * next;
@ -636,6 +653,7 @@ void free(void * ptr)
freeHeap->next = nullptr;
}
}
#endif
void * calloc(int num, int size)
{

View File

@ -43,10 +43,16 @@ void free(void * ptr);
void * calloc(int num, int size);
unsigned heapfree(void);
unsigned int rand(void);
void srand(unsigned int seed);
#pragma intrinsic(malloc)
#pragma intrinsic(free)
#pragma compile("stdlib.c")
#endif

View File

@ -333,7 +333,7 @@ void InitAssembler(void)
int AsmInsSize(AsmInsType type, AsmInsMode mode)
{
if (type < ASMIT_INV)
if (type < ASMIT_INV && mode >= ASMIM_IMPLIED && mode < NUM_ASM_INS_MODES)
return AsmInsModeSize[mode];
else
return 1;

View File

@ -71,7 +71,7 @@ inline BitVector::BitVector(int size, unsigned char * data)
else
bits = nullptr;
if (size)
if (size > 0)
{
memcpy(bits, data, (size + 7) / 8);
}
@ -93,7 +93,7 @@ inline BitVector::BitVector(int size, bool set)
else
bits = NULL;
if (size)
if (size > 0)
{
if (set)
{

View File

@ -142,8 +142,8 @@ static const char* ByteCodeNames[] = {
"BRANCHF_LE",
"LOOP_U8",
nullptr,
nullptr,
"MALLOC",
"FREE",
nullptr,
nullptr,
nullptr,
@ -565,6 +565,11 @@ bool ByteCodeInstruction::CheckAccuSize(uint32 & used)
used = 0;
break;
case BC_MALLOC:
case BC_FREE:
used = 0x0000ffff;
break;
case BC_BINOP_ADDA_16:
used |= 0x0000ffff;
break;
@ -779,6 +784,8 @@ bool ByteCodeInstruction::UsesRegister(uint32 reg) const
return true;
if (mCode == BC_BINOP_ADDA_16)
return true;
if (mCode == BC_MALLOC || mCode == BC_FREE)
return true;
}
if (reg == BC_REG_ADDR)
@ -851,6 +858,8 @@ bool ByteCodeInstruction::ChangesRegister(uint32 reg) const
return true;
if (mCode == BC_LOOP_U8)
return true;
if (mCode == BC_MALLOC || mCode == BC_FREE)
return true;
}
if (reg == BC_REG_ADDR)
@ -869,6 +878,8 @@ bool ByteCodeInstruction::ChangesRegister(uint32 reg) const
{
if (mCode == BC_JSR || mCode == BC_CALL_ADDR || mCode == BC_CALL_ABS)
return true;
if (mCode == BC_MALLOC || mCode == BC_FREE)
return true;
if (mCode == BC_BINOP_DIVR_I16 || mCode == BC_BINOP_DIVR_U16 || mCode == BC_BINOP_MODR_I16 || mCode == BC_BINOP_MODR_U16 ||
mCode == BC_BINOP_DIV_I32 || mCode == BC_BINOP_DIV_U32 || mCode == BC_BINOP_MOD_I32 || mCode == BC_BINOP_MOD_U32 ||
@ -1149,6 +1160,8 @@ void ByteCodeInstruction::Assemble(ByteCodeGenerator* generator, ByteCodeBasicBl
assert(false);
break;
case BC_MALLOC:
case BC_FREE:
case BC_CALL_ADDR:
block->PutCode(generator, mCode);
break;
@ -1578,6 +1591,53 @@ void ByteCodeBasicBlock::StrcpyValue(InterCodeProcedure* proc, const InterInstru
mIns.Push(cins);
}
void ByteCodeBasicBlock::CallMalloc(InterCodeProcedure* proc, const InterInstruction* ins)
{
if (ins->mSrc[0].mTemp < 0)
{
ByteCodeInstruction dins(BC_CONST_16);
dins.mRegister = BC_REG_ACCU;
dins.mValue = int(ins->mSrc[0].mIntConst & 0xffff);
mIns.Push(dins);
}
else
{
ByteCodeInstruction dins(BC_LOAD_REG_16);
dins.mRegister = BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp];
dins.mRegisterFinal = ins->mSrc[0].mFinal;
mIns.Push(dins);
}
ByteCodeInstruction cins(BC_MALLOC);
mIns.Push(cins);
if (ins->mDst.mTemp >= 0)
{
ByteCodeInstruction bins(BC_STORE_REG_16);
bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp];
mIns.Push(bins);
}
}
void ByteCodeBasicBlock::CallFree(InterCodeProcedure* proc, const InterInstruction* ins)
{
if (ins->mSrc[0].mTemp < 0)
{
ByteCodeInstruction dins(BC_CONST_16);
dins.mRegister = BC_REG_ACCU;
dins.mValue = int(ins->mSrc[0].mIntConst & 0xffff);
mIns.Push(dins);
}
else
{
ByteCodeInstruction dins(BC_LOAD_REG_16);
dins.mRegister = BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp];
dins.mRegisterFinal = ins->mSrc[0].mFinal;
mIns.Push(dins);
}
ByteCodeInstruction cins(BC_FREE);
mIns.Push(cins);
}
void ByteCodeBasicBlock::StoreDirectValue(InterCodeProcedure* proc, const InterInstruction * ins)
{
if (ins->mSrc[0].mType == IT_FLOAT)
@ -3211,7 +3271,7 @@ ByteCode ByteCodeBasicBlock::RelationalOperator(InterCodeProcedure* proc, const
cins.mRegisterFinal = ins->mSrc[1].mFinal;
mIns.Push(cins);
}
else if (ins->mSrc[0].mType == IT_INT8)
else if (ins->mSrc[0].mType == IT_INT8 || ins->mSrc[0].mType == IT_BOOL)
{
if (ins->mSrc[1].mTemp < 0)
{
@ -4186,8 +4246,8 @@ void ByteCodeBasicBlock::BinaryOperator(InterCodeProcedure* proc, const InterIns
case IA_SAR:
{
ByteCode rbc = ByteCodeBinRegOperator(ins);
ByteCode ibc = ByteCodeBinImmOperator(ins);
if (ins->mSrc[1].mTemp < 0)
{
IntConstToAccu(ins->mSrc[1].mIntConst);
@ -4199,18 +4259,25 @@ void ByteCodeBasicBlock::BinaryOperator(InterCodeProcedure* proc, const InterIns
}
else if (ins->mSrc[0].mTemp < 0)
{
ByteCodeInstruction lins(BC_LOAD_REG_16);
ByteCodeInstruction lins(InterTypeSize[ins->mSrc[1].mType] == 1 ? BC_LOAD_REG_8 : BC_LOAD_REG_16);
lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
lins.mRegisterFinal = ins->mSrc[1].mFinal;
mIns.Push(lins);
if (ins->mOperator == IA_SAR && InterTypeSize[ins->mSrc[1].mType] == 1)
{
ByteCodeInstruction xins(BC_CONV_I8_I16);
xins.mRegister = BC_REG_ACCU;
mIns.Push(xins);
}
ByteCodeInstruction bins(ibc);
bins.mValue = int(ins->mSrc[0].mIntConst);
mIns.Push(bins);
}
else
{
ByteCodeInstruction lins(BC_LOAD_REG_16);
ByteCodeInstruction lins(InterTypeSize[ins->mSrc[1].mType] == 1 ? BC_LOAD_REG_8 : BC_LOAD_REG_16);
lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp];
lins.mRegisterFinal = ins->mSrc[1].mFinal && (ins->mSrc[1].mTemp != ins->mSrc[0].mTemp);;
mIns.Push(lins);
@ -4259,6 +4326,12 @@ void ByteCodeBasicBlock::Compile(InterCodeProcedure* iproc, ByteCodeProcedure* p
case IC_STRCPY:
StrcpyValue(iproc, ins);
break;
case IC_MALLOC:
CallMalloc(iproc, ins);
break;
case IC_FREE:
CallFree(iproc, ins);
break;
case IC_LOAD_TEMPORARY:
{
if (ins->mSrc[0].mTemp != ins->mDst.mTemp)
@ -4318,6 +4391,7 @@ void ByteCodeBasicBlock::Compile(InterCodeProcedure* iproc, ByteCodeProcedure* p
LoadConstant(iproc, ins);
break;
case IC_CALL:
case IC_DISPATCH:
CallFunction(iproc, ins);
break;
case IC_CALL_NATIVE:

View File

@ -143,8 +143,8 @@ enum ByteCode
BC_BRANCHF_LE,
BC_LOOP_U8,
BC_UNUSED_2,
BC_UNUSED_3,
BC_MALLOC,
BC_FREE,
BC_UNUSED_4,
BC_UNUSED_5,
BC_UNUSED_6,
@ -283,6 +283,8 @@ public:
void FloatConstToWork(double val);
void CopyValue(InterCodeProcedure* proc, const InterInstruction * ins);
void StrcpyValue(InterCodeProcedure* proc, const InterInstruction* ins);
void CallMalloc(InterCodeProcedure* proc, const InterInstruction* ins);
void CallFree(InterCodeProcedure* proc, const InterInstruction* ins);
void LoadConstant(InterCodeProcedure* proc, const InterInstruction * ins);
void StoreDirectValue(InterCodeProcedure* proc, const InterInstruction * ins);
void LoadDirectValue(InterCodeProcedure* proc, const InterInstruction * ins);

View File

@ -7,13 +7,15 @@
#include <stdio.h>
#include <string.h>
CompilationUnits::CompilationUnits(Errors * errors)
: mErrors(errors), mReferenced(nullptr)
CompilationUnits::CompilationUnits(Errors* errors)
: mErrors(errors), mReferenced(nullptr), mUniqueID(0)
{
mCompilationUnits = nullptr;
mPendingUnits = nullptr;
mScope = new DeclarationScope(nullptr, SLEVEL_GLOBAL);
mRuntimeScope = new DeclarationScope(nullptr, SLEVEL_GLOBAL);
mVTableScope = new DeclarationScope(nullptr, SLEVEL_GLOBAL);
mTemplateScope = new DeclarationScope(nullptr, SLEVEL_GLOBAL);
mStartup = nullptr;
for (int i = 0; i < 256; i++)
@ -25,6 +27,12 @@ CompilationUnits::~CompilationUnits(void)
}
int CompilationUnits::UniqueID(void)
{
return mUniqueID++;
}
void CompilationUnits::AddReferenced(Declaration* ref)
{
mReferenced.Push(ref);

View File

@ -19,7 +19,7 @@ public:
CompilationUnits(Errors * errors);
~CompilationUnits(void);
DeclarationScope* mScope;
DeclarationScope* mScope, * mVTableScope, * mTemplateScope;
CompilationUnit* mCompilationUnits, * mPendingUnits;
Declaration* mStartup;
@ -31,6 +31,10 @@ public:
LinkerSection* mSectionCode, * mSectionData, * mSectionBSS, * mSectionHeap, * mSectionStack, * mSectionZeroPage, * mSectionLowCode, * mSectionBoot;
Linker* mLinker;
int mUniqueID;
int UniqueID(void);
bool AddUnit(Location & location, const char* name, const char * from);
CompilationUnit* PendingUnit(void);

View File

@ -33,6 +33,7 @@ Compiler::Compiler(void)
mNativeCodeGenerator = new NativeCodeGenerator(mErrors, mLinker, mCompilationUnits->mSectionCode);
mInterCodeModule = new InterCodeModule(mErrors, mLinker);
mGlobalAnalyzer = new GlobalAnalyzer(mErrors, mLinker);
mGlobalOptimizer = new GlobalOptimizer(mErrors, mLinker);
mCartridgeID = 0x0000;
}
@ -200,6 +201,251 @@ void Compiler::RegisterRuntime(const Location & loc, const Ident* ident)
}
}
static void IndexVTableTree(Declaration* vdec, int & index)
{
vdec->mVarIndex = index;
vdec->mDefaultConstructor->mInteger = index;
index++;
Declaration* cvdec = vdec->mParams;
while (cvdec)
{
IndexVTableTree(cvdec, index);
cvdec = cvdec->mNext;
}
vdec->mSize = index - vdec->mVarIndex;
}
static void FillVTableTree(Declaration* vdec)
{
Declaration* cdec = vdec->mClass;
cdec->mScope->Iterate([=](const Ident* mident, Declaration* mdec)
{
if (mdec->mType == DT_CONST_FUNCTION)
{
while (mdec)
{
if (mdec->mBase->mFlags & DTF_VIRTUAL)
{
for (int i = 0; i < vdec->mSize; i++)
mdec->mVTable->mCalled[vdec->mVarIndex + i - mdec->mVTable->mDefaultConstructor->mVarIndex] = mdec;
}
mdec = mdec->mNext;
}
}
});
Declaration* cvdec = vdec->mParams;
while (cvdec)
{
FillVTableTree(cvdec);
cvdec = cvdec->mNext;
}
}
void Compiler::CompleteTemplateExpansion(void)
{
}
bool IsSimpleConstReturn(Declaration * mdec)
{
if (mdec->mBase->mBase->IsSimpleType() && mdec->mBase->mParams->mNext == nullptr)
{
Expression* ex = mdec->mValue;
if (ex->mType == EX_SCOPE)
ex = ex->mLeft;
if (ex->mType == EX_RETURN && ex->mLeft->mType == EX_CONSTANT)
return true;
}
return false;
}
void Compiler::BuildVTables(void)
{
// Connect vdecs with parents
mCompilationUnits->mVTableScope->Iterate([=](const Ident* ident, Declaration* vdec)
{
if (vdec->mBase)
{
vdec->mNext = vdec->mBase->mParams;
vdec->mBase->mParams = vdec;
}
});
// Number the child vtables
mCompilationUnits->mVTableScope->Iterate([=](const Ident* ident, Declaration* vdec)
{
if (!vdec->mBase)
{
int index = 0;
IndexVTableTree(vdec, index);
}
});
mCompilationUnits->mVTableScope->Iterate([=](const Ident* ident, Declaration* vdec)
{
if (!vdec->mBase)
{
FillVTableTree(vdec);
}
});
// Build vtables for functions
mCompilationUnits->mVTableScope->Iterate([=](const Ident* ident, Declaration* vdec)
{
vdec->mScope->Iterate([=](const Ident* mident, Declaration* mdec)
{
bool simpleConst = vdec->mSize > 0;
for (int i = 0; i < vdec->mSize; i++)
if (!IsSimpleConstReturn(mdec->mCalled[i]))
simpleConst = false;
if (simpleConst)
{
Declaration* vtabt = new Declaration(mdec->mLocation, DT_TYPE_ARRAY);
vtabt->mBase = mdec->mBase->mBase->ToConstType()->ToStriped(vdec->mSize);
vtabt->mSize = vdec->mSize * mdec->mBase->mBase->mSize;
vtabt->mStride = 1;
vtabt->mStripe = 1;
vtabt->mFlags |= DTF_CONST | DTF_DEFINED;
Declaration* vtaba = new Declaration(mdec->mLocation, DT_VARIABLE);
vtaba->mFlags = DTF_CONST | DTF_GLOBAL | DTF_DEFINED;
vtaba->mBase = vtabt;
vtaba->mSize = vtabt->mSize;
vtaba->mValue = new Expression(mdec->mLocation, EX_CONSTANT);
vtaba->mValue->mDecType = vtabt;
vtaba->mValue->mDecValue = new Declaration(mdec->mLocation, DT_CONST_STRUCT);
vtaba->mIdent = mdec->mIdent;
vtaba->mQualIdent = mdec->mQualIdent->Mangle("$vltable");
vtaba->mSection = mdec->mSection;
vtaba->mOffset = -vdec->mVarIndex;
Declaration* last = nullptr;
for (int i = 0; i < vdec->mSize; i++)
{
Declaration* vmdec = mdec->mCalled[i];
Expression* texp = vmdec->mValue;
if (texp->mType == EX_SCOPE)
texp = texp->mLeft;
texp = texp->mLeft;
Declaration* cdec = texp->mDecValue->Clone();
cdec->mOffset = i;
if (last)
last->mNext = cdec;
else
vtaba->mValue->mDecValue->mParams = cdec;
last = cdec;
}
Expression* vexp = new Expression(mdec->mLocation, EX_QUALIFY);
vexp->mLeft = new Expression(mdec->mLocation, EX_PREFIX);
vexp->mLeft->mDecType = mdec->mBase->mParams->mBase->mBase;
vexp->mLeft->mToken = TK_MUL;
vexp->mLeft->mLeft = new Expression(mdec->mLocation, EX_VARIABLE);
vexp->mLeft->mLeft->mDecType = mdec->mBase->mParams->mBase;
vexp->mLeft->mLeft->mDecValue = mdec->mBase->mParams;
vexp->mDecValue = new Declaration(mdec->mLocation, DT_ELEMENT);
vexp->mDecValue->mBase = TheCharTypeDeclaration;
vexp->mDecValue->mOffset = vdec->mOffset;
vexp->mDecValue->mSize = 1;
vexp->mDecType = TheCharTypeDeclaration;
Expression* ecall = new Expression(mdec->mLocation, EX_RETURN);
ecall->mLeft = new Expression(mdec->mLocation, EX_INDEX);
ecall->mLeft->mDecType = mdec->mBase->mBase;
ecall->mDecType = mdec->mBase->mBase;
ecall->mLeft->mLeft = new Expression(mdec->mLocation, EX_VARIABLE);
ecall->mLeft->mLeft->mDecType = vtabt;
ecall->mLeft->mLeft->mDecValue = vtaba;
ecall->mLeft->mRight = vexp;
mdec->mCalled.SetSize(0);
mdec->mFlags |= DTF_DEFINED;
mdec->mBase->mFlags &= ~DTF_VIRTUAL;
mdec->mValue = ecall;
}
else
{
Declaration* vtabt = new Declaration(mdec->mLocation, DT_TYPE_ARRAY);
vtabt->mBase = mdec->mBase->ToStriped(vdec->mSize);
vtabt->mSize = vdec->mSize * 2;
vtabt->mStride = 1;
vtabt->mStripe = 1;
vtabt->mFlags |= DTF_CONST | DTF_DEFINED;
Declaration* vtaba = new Declaration(mdec->mLocation, DT_VARIABLE);
vtaba->mFlags = DTF_CONST | DTF_GLOBAL | DTF_DEFINED;
vtaba->mBase = vtabt;
vtaba->mSize = vtabt->mSize;
vtaba->mValue = new Expression(mdec->mLocation, EX_CONSTANT);
vtaba->mValue->mDecType = vtabt;
vtaba->mValue->mDecValue = new Declaration(mdec->mLocation, DT_CONST_STRUCT);
vtaba->mIdent = mdec->mIdent;
vtaba->mQualIdent = mdec->mQualIdent->Mangle("$vtable");
vtaba->mSection = mdec->mSection;
vtaba->mOffset = -vdec->mVarIndex;
Declaration* last = nullptr;
for (int i = 0; i < vdec->mSize; i++)
{
Declaration* vmdec = mdec->mCalled[i];
Expression* texp = new Expression(vmdec->mLocation, EX_CONSTANT);
texp->mDecType = vtabt->mBase;
texp->mDecValue = vmdec;
Declaration* cdec = new Declaration(vmdec->mLocation, DT_CONST_POINTER);
cdec->mValue = texp;
cdec->mBase = vtabt->mBase;
cdec->mOffset = i;
if (last)
last->mNext = cdec;
else
vtaba->mValue->mDecValue->mParams = cdec;
last = cdec;
}
// mCompilationUnits->AddReferenced(vtaba);
Expression* vexp = new Expression(mdec->mLocation, EX_QUALIFY);
vexp->mLeft = new Expression(mdec->mLocation, EX_PREFIX);
vexp->mLeft->mDecType = mdec->mBase->mParams->mBase->mBase;
vexp->mLeft->mToken = TK_MUL;
vexp->mLeft->mLeft = new Expression(mdec->mLocation, EX_VARIABLE);
vexp->mLeft->mLeft->mDecType = mdec->mBase->mParams->mBase;
vexp->mLeft->mLeft->mDecValue = mdec->mBase->mParams;
vexp->mDecValue = new Declaration(mdec->mLocation, DT_ELEMENT);
vexp->mDecValue->mBase = TheCharTypeDeclaration;
vexp->mDecValue->mOffset = vdec->mOffset;
vexp->mDecValue->mSize = 1;
vexp->mDecType = TheCharTypeDeclaration;
Expression* ecall = new Expression(mdec->mLocation, EX_DISPATCH);
ecall->mLeft = new Expression(mdec->mLocation, EX_INDEX);
ecall->mLeft->mDecType = mdec->mBase;
ecall->mDecType = vtabt->mBase;
ecall->mLeft->mLeft = new Expression(mdec->mLocation, EX_VARIABLE);
ecall->mLeft->mLeft->mDecType = vtabt;
ecall->mLeft->mLeft->mDecValue = vtaba;
ecall->mLeft->mRight = vexp;
mdec->mFlags |= DTF_DEFINED;
mdec->mValue = ecall;
}
});
});
}
void Compiler::CompileProcedure(InterCodeProcedure* proc)
{
if (!proc->mCompiled)
@ -218,6 +464,7 @@ void Compiler::CompileProcedure(InterCodeProcedure* proc)
printf("Generate native code <%s>\n", proc->mIdent->mString);
ncproc->Compile(proc);
mNativeProcedures.Push(ncproc);
}
else
{
@ -589,6 +836,38 @@ bool Compiler::GenerateCode(void)
dcrtstart->mSection = sectionStartup;
if (mCompilerOptions & COPT_CPLUSPLUS)
{
if (mCompilerOptions & COPT_VERBOSE)
printf("Build VTables\n");
BuildVTables();
}
if (mCompilerOptions & COPT_OPTIMIZE_GLOBAL)
{
mGlobalOptimizer->mCompilerOptions = mCompilerOptions;
if (mCompilerOptions & COPT_VERBOSE)
printf("Global optimizer\n");
do {
mGlobalOptimizer->Reset();
mGlobalOptimizer->AnalyzeAssembler(dcrtstart->mValue, nullptr);
for (int i = 0; i < mCompilationUnits->mReferenced.Size(); i++)
{
Declaration* dec = mCompilationUnits->mReferenced[i];
if (dec->mType == DT_CONST_FUNCTION)
mGlobalOptimizer->AnalyzeProcedure(dec->mValue, dec);
else
mGlobalOptimizer->AnalyzeGlobalVariable(dec);
}
} while (mGlobalOptimizer->Optimize());
}
mGlobalAnalyzer->mCompilerOptions = mCompilerOptions;
if (mCompilerOptions & COPT_VERBOSE)
@ -669,6 +948,9 @@ bool Compiler::GenerateCode(void)
RegisterRuntime(loc, Ident::Unique("mods32"));
RegisterRuntime(loc, Ident::Unique("divu32"));
RegisterRuntime(loc, Ident::Unique("modu32"));
RegisterRuntime(loc, Ident::Unique("malloc"));
RegisterRuntime(loc, Ident::Unique("free"));
}
// Register extended byte code functions
@ -727,6 +1009,15 @@ bool Compiler::GenerateCode(void)
mCompilationUnits->mSectionStack->mSections.Push(proc->mLinkerObject->mStackSection);
}
mNativeCodeGenerator->BuildFunctionProxies();
for (int i = 0; i < mNativeProcedures.Size(); i++)
{
if (mCompilerOptions & COPT_VERBOSE2)
printf("Assemble native code <%s>\n", mNativeProcedures[i]->mInterProc->mIdent->mString);
mNativeProcedures[i]->Assemble();
}
LinkerObject* byteCodeObject = nullptr;
if (!(mCompilerOptions & COPT_NATIVE))
{
@ -793,6 +1084,9 @@ bool Compiler::GenerateCode(void)
for (int i = 0; i < mCompilationUnits->mReferenced.Size(); i++)
mLinker->ReferenceObject(mCompilationUnits->mReferenced[i]->mLinkerObject);
if (mCompilerOptions & COPT_OPTIMIZE_BASIC)
mLinker->CombineSameConst();
if (mCompilerOptions & COPT_VERBOSE)
printf("Link executable\n");
@ -808,7 +1102,7 @@ bool Compiler::BuildLZO(const char* targetPath)
CompilationUnit* cunit;
char data[65536];
char * data = new char[65536];
int n = 0;
while (mErrors->mErrorCount == 0 && (cunit = mCompilationUnits->PendingUnit()))
@ -851,14 +1145,20 @@ bool Compiler::BuildLZO(const char* targetPath)
{
int done = fwrite(data, 1, n, file);
fclose(file);
delete[] data;
return done == n;
}
else
{
delete[] data;
return false;
}
}
else
{
delete[] data;
return false;
}
}
bool Compiler::WriteOutputFile(const char* targetPath, DiskImage * d64)
@ -977,7 +1277,7 @@ bool Compiler::WriteOutputFile(const char* targetPath, DiskImage * d64)
return true;
}
int Compiler::ExecuteCode(bool profile, bool trace)
int Compiler::ExecuteCode(bool profile, int trace)
{
Location loc;
@ -990,12 +1290,12 @@ int Compiler::ExecuteCode(bool profile, bool trace)
memcpy(emu->mMemory + mLinker->mProgramStart, mLinker->mMemory + mLinker->mProgramStart, mLinker->mProgramEnd - mLinker->mProgramStart);
emu->mMemory[0x2d] = mLinker->mProgramEnd & 0xff;
emu->mMemory[0x2e] = mLinker->mProgramEnd >> 8;
ecode = emu->Emulate(2061, trace ? 2 : 0);
ecode = emu->Emulate(2061, trace);
}
else if (mCompilerOptions & COPT_TARGET_CRT)
{
memcpy(emu->mMemory + 0x8000, mLinker->mMemory + 0x0800, 0x4000);
ecode = emu->Emulate(0x8009, trace ? 2 : 0);
ecode = emu->Emulate(0x8009, trace);
}
printf("Emulation result %d\n", ecode);
@ -1184,6 +1484,9 @@ bool Compiler::WriteDbjFile(const char* filename)
case DT_TYPE_REFERENCE:
fprintf(file, "\t\t{\"name\": \"%s\", \"typeid\": %d, \"size\": %d, \"type\": \"ref\", eid: %d}", dec->mQualIdent ? dec->mQualIdent->mString : "", i, dec->mSize, types.IndexOrPush(dec->mBase));
break;
case DT_TYPE_RVALUEREF:
fprintf(file, "\t\t{\"name\": \"%s\", \"typeid\": %d, \"size\": %d, \"type\": \"rref\", eid: %d}", dec->mQualIdent ? dec->mQualIdent->mString : "", i, dec->mSize, types.IndexOrPush(dec->mBase));
break;
case DT_TYPE_ENUM:
{
fprintf(file, "\t\t{\"name\": \"%s\", \"typeid\": %d, \"size\": %d, \"type\": \"enum\",\"members\": [\n", dec->mQualIdent ? dec->mQualIdent->mString : "", i, dec->mSize);

View File

@ -7,6 +7,7 @@
#include "NativeCodeGenerator.h"
#include "InterCodeGenerator.h"
#include "GlobalAnalyzer.h"
#include "GlobalOptimizer.h"
#include "Linker.h"
#include "CompilerTypes.h"
@ -25,8 +26,10 @@ public:
InterCodeGenerator* mInterCodeGenerator;
InterCodeModule* mInterCodeModule;
GlobalAnalyzer* mGlobalAnalyzer;
GlobalOptimizer* mGlobalOptimizer;
GrowingArray<ByteCodeProcedure*> mByteCodeFunctions;
ExpandingArray<NativeCodeProcedure*> mNativeProcedures;
TargetMachine mTargetMachine;
uint64 mCompilerOptions;
@ -44,13 +47,15 @@ public:
bool ParseSource(void);
bool GenerateCode(void);
bool WriteOutputFile(const char* targetPath, DiskImage * d64);
int ExecuteCode(bool profile, bool trace);
int ExecuteCode(bool profile, int trace);
void AddDefine(const Ident* ident, const char* value);
void RegisterRuntime(const Location& loc, const Ident* ident);
void CompileProcedure(InterCodeProcedure* proc);
void BuildVTables(void);
void CompleteTemplateExpansion(void);
bool WriteDbjFile(const char* filename);
};

View File

@ -11,6 +11,9 @@ static const uint64 COPT_OPTIMIZE_AUTO_INLINE_ALL = 1ULL << 5;
static const uint64 COPT_OPTIMIZE_AUTO_UNROLL = 1ULL << 6;
static const uint64 COPT_OPTIMIZE_CONST_EXPRESSIONS = 1ULL << 7;
static const uint64 COPT_OPTIMIZE_AUTO_ZEROPAGE = 1ULL << 8;
static const uint64 COPT_OPTIMIZE_CONST_PARAMS = 1ULL << 9;
static const uint64 COPT_OPTIMIZE_MERGE_CALLS = 1ULL << 10;
static const uint64 COPT_OPTIMIZE_GLOBAL = 1ULL << 11;
static const uint64 COPT_OPTIMIZE_CODE_SIZE = 1ULL << 16;
static const uint64 COPT_NATIVE = 1ULL << 17;
@ -42,11 +45,11 @@ static const uint64 COPT_DEFAULT = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE |
static const uint64 COPT_OPTIMIZE_DEFAULT = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_CONST_EXPRESSIONS;
static const uint64 COPT_OPTIMIZE_SIZE = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_CONST_EXPRESSIONS | COPT_OPTIMIZE_CODE_SIZE;
static const uint64 COPT_OPTIMIZE_SIZE = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_CONST_EXPRESSIONS | COPT_OPTIMIZE_CODE_SIZE | COPT_OPTIMIZE_CONST_PARAMS | COPT_OPTIMIZE_MERGE_CALLS | COPT_OPTIMIZE_GLOBAL;
static const uint64 COPT_OPTIMIZE_SPEED = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_AUTO_INLINE | COPT_OPTIMIZE_AUTO_UNROLL | COPT_OPTIMIZE_CONST_EXPRESSIONS | COPT_OPTIMIZE_ASSEMBLER;
static const uint64 COPT_OPTIMIZE_SPEED = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_AUTO_INLINE | COPT_OPTIMIZE_AUTO_UNROLL | COPT_OPTIMIZE_CONST_EXPRESSIONS | COPT_OPTIMIZE_ASSEMBLER | COPT_OPTIMIZE_CONST_PARAMS | COPT_OPTIMIZE_MERGE_CALLS | COPT_OPTIMIZE_GLOBAL;
static const uint64 COPT_OPTIMIZE_ALL = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_AUTO_INLINE | COPT_OPTIMIZE_AUTO_INLINE_ALL | COPT_OPTIMIZE_AUTO_UNROLL | COPT_OPTIMIZE_CONST_EXPRESSIONS | COPT_OPTIMIZE_ASSEMBLER | COPT_OPTIMIZE_AUTO_ZEROPAGE;
static const uint64 COPT_OPTIMIZE_ALL = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_AUTO_INLINE | COPT_OPTIMIZE_AUTO_INLINE_ALL | COPT_OPTIMIZE_AUTO_UNROLL | COPT_OPTIMIZE_CONST_EXPRESSIONS | COPT_OPTIMIZE_ASSEMBLER | COPT_OPTIMIZE_AUTO_ZEROPAGE | COPT_OPTIMIZE_CONST_PARAMS | COPT_OPTIMIZE_MERGE_CALLS | COPT_OPTIMIZE_GLOBAL;
enum TargetMachine
{

1491
oscar64/Constexpr.cpp Normal file

File diff suppressed because it is too large Load Diff

114
oscar64/Constexpr.h Normal file
View File

@ -0,0 +1,114 @@
#pragma once
#include "Declaration.h"
class ConstexprInterpreter
{
public:
ConstexprInterpreter(const Location & loc, Errors * err, LinkerSection * dataSection);
~ConstexprInterpreter(void);
Expression* EvalConstructor(Expression* exp);
Expression* EvalCall(Expression* exp);
Expression* EvalTempConstructor(Expression* exp);
protected:
bool AddParam(int& pos, Expression* pex, Declaration* dec);
struct Value;
struct ValueItem
{
uint8 mByte;
Value* mBaseValue;
ValueItem(void);
};
struct Value
{
~Value(void);
Value(const Location& location);
Value(Expression * exp);
Value(const Location& location, Declaration * dec);
Value(const Location& location, Declaration* dec, int count);
Value(const Value& value);
Value(Value&& value);
Value(const Location& location, Value * value, Declaration * type, int offset);
Value(Value* value);
Value(const Location& location, const uint8 * data, Declaration* type);
Value(const Location& location, const ValueItem* data, Declaration* type);
Value(void);
Value& operator=(const Value& v);
Value& operator=(Value&& v);
Value ToRValue(void) const;
Expression* ToExpression(LinkerSection* dataSection) const;
void Assign(const Value& v);
Location mLocation;
Declaration * mDecType;
Value * mBaseValue;
int mOffset;
ValueItem * mData;
int mDataSize;
ValueItem mShortData[4];
ValueItem* GetAddr(void);
const ValueItem* GetAddr(void) const;
int64 GetInt(void) const;
double GetFloat(void) const;
Value GetPtr(void) const;
void PutInt(int64 v);
void PutFloat(double v);
void PutPtr(const Value& v);
int64 GetIntAt(int at, Declaration* type) const;
double GetFloatAt(int at, Declaration* type) const;
Value GetPtrAt(int at, Declaration* type) const;
void PutIntAt(int64 v, int at, Declaration* type);
void PutFloatAt(double v, int at, Declaration* type);
void PutPtrAt(const Value& v, int at, Declaration* type);
void PutConst(int offset, Declaration * dec);
Declaration* GetConst(int offset, Declaration* type, LinkerSection* dataSection) const;
};
Value * NewValue(Expression* exp, Declaration* type, int size);
void DeleteValue(Value* v);
Value EvalCall(Expression* exp, ConstexprInterpreter* caller);
Value EvalBinary(Expression* exp, const Value& vl, const Value& vr);
Value EvalUnary(Expression* exp, const Value& vl);
Value EvalRelational(Expression* exp, const Value& vl, const Value& vr);
Value EvalTypeCast(Expression* exp, const Value& vl, Declaration* type);
Value EvalCoerce(Expression* exp, const Value& vl, Declaration* type);
Value REval(Expression* exp);
Value Eval(Expression* exp);
enum Flow
{
FLOW_NEXT,
FLOW_CONTINUE,
FLOW_BREAK,
FLOW_RETURN
};
Flow Execute(Expression* exp);
void UnwindDestructStack(int level);
Declaration* mProcType;
Location mLocation;
LinkerSection* mDataSection;
GrowingArray<Value> mParams, mLocals;
ExpandingArray<Expression*> mDestructStack;
ExpandingArray<Value *> * mHeap;
ExpandingArray<Value*> mTemps;
Errors * mErrors;
Value mResult;
};

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,7 @@
class LinkerObject;
class LinkerSection;
class Parser;
enum DecType
{
@ -19,16 +20,15 @@ enum DecType
DT_TYPE_ENUM,
DT_TYPE_POINTER,
DT_TYPE_REFERENCE,
DT_TYPE_RVALUEREF,
DT_TYPE_ARRAY,
DT_TYPE_STRUCT,
DT_TYPE_UNION,
DT_TYPE_TEMPLATE,
DT_TYPE_FUNCTION,
DT_TYPE_ASSEMBLER,
DT_TYPE_AUTO,
DT_TYPE_CONST,
DT_TYPE_VOLATILE,
DT_CONST_INTEGER,
DT_CONST_FLOAT,
DT_CONST_FUNCTION,
@ -38,6 +38,13 @@ enum DecType
DT_CONST_POINTER,
DT_CONST_REFERENCE,
DT_CONST_ASSEMBLER,
DT_CONST_CONSTRUCTOR,
DT_CONST_TEMPLATE,
DT_PACK_TEMPLATE,
DT_PACK_VARIABLE,
DT_PACK_ARGUMENT,
DT_PACK_TYPE,
DT_VARIABLE,
DT_ARGUMENT,
@ -48,6 +55,11 @@ enum DecType
DT_FUNCTION_REF,
DT_LABEL_REF,
DT_NAMESPACE,
DT_BASECLASS,
DT_TEMPLATE,
DT_VTABLE
};
// TypeFlags
@ -78,37 +90,48 @@ static const uint64 DTF_ZEROPAGE = (1ULL << 22);
static const uint64 DTF_PREVENT_INLINE = (1ULL << 23);
static const uint64 DTF_STRIPED = (1ULL << 24);
static const uint64 DTF_DYNSTACK = (1ULL << 25);
static const uint64 DTF_PRIVATE = (1ULL << 26);
static const uint64 DTF_PROTECTED = (1ULL << 27);
static const uint64 DTF_VIRTUAL = (1ULL << 28);
static const uint64 DTF_TEMPORARY = (1ULL << 29);
static const uint64 DTF_COMPLETED = (1ULL << 30);
static const uint64 DTF_CONSTEXPR = (1ULL << 31);
static const uint64 DTF_FUNC_VARIABLE = (1ULL << 32);
static const uint64 DTF_FUNC_ASSEMBLER = (1ULL << 33);
static const uint64 DTF_FUNC_RECURSIVE = (1ULL << 34);
static const uint64 DTF_FUNC_ANALYZING = (1ULL << 35);
static const uint64 DTF_AUTO_TEMPLATE = (1ULL << 32);
static const uint64 DTF_FUNC_CONSTEXPR = (1ULL << 36);
static const uint64 DTF_FUNC_INTRSAVE = (1ULL << 37);
static const uint64 DTF_FUNC_INTRCALLED = (1ULL << 38);
static const uint64 DTF_FUNC_PURE = (1ULL << 39);
static const uint64 DTF_FUNC_VARIABLE = (1ULL << 36);
static const uint64 DTF_FUNC_ASSEMBLER = (1ULL << 37);
static const uint64 DTF_FUNC_RECURSIVE = (1ULL << 38);
static const uint64 DTF_FUNC_ANALYZING = (1ULL << 39);
static const uint64 DTF_FPARAM_CONST = (1ULL << 40);
static const uint64 DTF_FPARAM_NOCONST = (1ULL << 41);
static const uint64 DTF_FUNC_CONSTEXPR = (1ULL << 40);
static const uint64 DTF_FUNC_INTRSAVE = (1ULL << 41);
static const uint64 DTF_FUNC_INTRCALLED = (1ULL << 42);
static const uint64 DTF_FUNC_PURE = (1ULL << 43);
static const uint64 DTF_FUNC_THIS = (1ULL << 42);
static const uint64 DTF_FUNC_CONSTRUCTOR = (1ULL << 43);
static const uint64 DTF_FPARAM_CONST = (1ULL << 44);
static const uint64 DTF_FPARAM_NOCONST = (1ULL << 45);
static const uint64 DTF_VAR_ADDRESS = (1ULL << 46);
static const uint64 DTF_FUNC_THIS = (1ULL << 47);
static const uint64 DTF_VAR_ALIASING = (1ULL << 48);
static const uint64 DTF_FPARAM_UNUSED = (1ULL << 49);
class Declaration;
enum ScopeLevel
{
SLEVEL_SCOPE,
SLEVEL_USING,
SLEVEL_GLOBAL,
SLEVEL_STATIC,
SLEVEL_NAMESPACE,
SLEVEL_TEMPLATE,
SLEVEL_CLASS,
SLEVEL_FUNCTION,
SLEVEL_LOCAL
SLEVEL_LOCAL,
};
class DeclarationScope
@ -123,9 +146,12 @@ public:
Declaration* Lookup(const Ident* ident, ScopeLevel limit = SLEVEL_GLOBAL);
void End(const Location & loc);
void Clear(void);
void UseScope(DeclarationScope* scope);
template<typename F> void Iterate(F && f);
ScopeLevel mLevel;
const Ident * mName;
@ -141,6 +167,15 @@ protected:
ExpandingArray<DeclarationScope*> mUsed;
};
template<typename F> void DeclarationScope::Iterate(F&& f)
{
for (int i = 0; i < mHashSize; i++)
{
if (mHash[i].mIdent)
f(mHash[i].mIdent, mHash[i].mDec);
}
}
enum ExpressionType
{
EX_ERROR,
@ -159,7 +194,10 @@ enum ExpressionType
EX_QUALIFY,
EX_CALL,
EX_INLINE,
EX_VCALL,
EX_DISPATCH,
EX_LIST,
EX_COMMA,
EX_RETURN,
EX_SEQUENCE,
EX_WHILE,
@ -167,6 +205,7 @@ enum ExpressionType
EX_ELSE,
EX_FOR,
EX_DO,
EX_SCOPE,
EX_BREAK,
EX_CONTINUE,
EX_TYPE,
@ -181,7 +220,12 @@ enum ExpressionType
EX_DEFAULT,
EX_CONDITIONAL,
EX_ASSUME,
EX_BANKOF
EX_BANKOF,
EX_CONSTRUCT,
EX_CLEANUP,
EX_RESULT,
EX_PACK,
EX_PACK_TYPE,
};
class Expression
@ -200,10 +244,15 @@ public:
bool mConst;
Expression* LogicInvertExpression(void);
Expression* ConstantFold(Errors * errors);
Expression* ConstantFold(Errors * errors, LinkerSection* dataSection);
bool HasSideEffects(void) const;
bool IsSame(const Expression* exp) const;
bool IsRValue(void) const;
bool IsLValue(void) const;
bool IsConstRef(void) const;
void Dump(int ident) const;
};
class Declaration
@ -215,36 +264,80 @@ public:
Location mLocation, mEndLocation;
DecType mType;
Token mToken;
Declaration* mBase, *mParams, * mNext, * mConst, * mConstructor, * mDestructor;
Expression* mValue;
Declaration * mBase, * mParams, * mParamPack, * mNext, * mPrev, * mConst, * mMutable;
Declaration * mDefaultConstructor, * mDestructor, * mCopyConstructor, * mCopyAssignment, * mMoveConstructor, * mMoveAssignment;
Declaration * mVectorConstructor, * mVectorDestructor, * mVectorCopyConstructor, * mVectorCopyAssignment;
Declaration * mVTable, * mClass, * mTemplate;
Expression* mValue, * mReturn;
DeclarationScope* mScope;
int mOffset, mSize, mVarIndex, mNumVars, mComplexity, mLocalSize, mAlignment, mFastCallBase, mFastCallSize, mStride, mStripe;
uint8 mShift, mBits;
int64 mInteger, mMinValue, mMaxValue;
double mNumber;
uint64 mFlags, mCompilerOptions;
const Ident * mIdent, * mQualIdent;
uint64 mFlags, mCompilerOptions, mOptFlags;
const Ident * mIdent, * mQualIdent, * mMangleIdent;
LinkerSection * mSection;
const uint8 * mData;
LinkerObject * mLinkerObject;
int mUseCount;
TokenSequence * mTokens;
Parser * mParser;
GrowingArray<Declaration*> mCallers, mCalled;
GrowingArray<Declaration*> mCallers, mCalled, mFriends;
bool CanAssign(const Declaration* fromType) const;
bool IsSame(const Declaration* dec) const;
bool IsDerivedFrom(const Declaration* dec) const;
bool IsSubType(const Declaration* dec) const;
bool IsConstSame(const Declaration* dec) const;
bool IsSameValue(const Declaration* dec) const;
bool IsSameParams(const Declaration* dec) const;
bool IsSameMutable(const Declaration* dec) const;
bool IsTemplateSame(const Declaration* dec, const Declaration* tdec) const;
bool IsTemplateSameParams(const Declaration* dec, const Declaration* tdec) const;
bool IsSameTemplate(const Declaration* dec) const;
bool IsIntegerType(void) const;
bool IsNumericType(void) const;
bool IsSimpleType(void) const;
bool IsReference(void) const;
bool IsIndexed(void) const;
void SetDefined(void);
Declaration* ToConstType(void);
Declaration* ToMutableType(void);
Declaration* ToStriped(int stripe);
Declaration* ToStriped(Errors* errors);
Declaration* Clone(void);
Declaration* Last(void);
Declaration* BuildPointer(const Location& loc);
Declaration* BuildReference(const Location& loc, DecType type = DT_TYPE_REFERENCE);
Declaration* BuildConstPointer(const Location& loc);
Declaration* BuildConstReference(const Location& loc, DecType type = DT_TYPE_REFERENCE);
Declaration* BuildRValueRef(const Location& loc);
Declaration* BuildConstRValueRef(const Location& loc);
Declaration* NonRefBase(void);
Declaration* BuildArrayPointer(void);
Declaration* BuildAddressOfPointer(void);
Declaration* DeduceAuto(Declaration* dec);
Declaration* ConstCast(Declaration* ntype);
bool IsNullConst(void) const;
bool IsAuto(void) const;
DecType ValueType(void) const;
bool CanResolveTemplate(Expression* pexp, Declaration* tdec);
bool ResolveTemplate(Declaration* fdec, Declaration * tdec);
bool ResolveTemplate(Expression* pexp, Declaration* tdec);
Declaration* ExpandTemplate(DeclarationScope* scope);
const Ident* MangleIdent(void);
int Stride(void) const;
};
@ -255,4 +348,6 @@ extern Declaration* TheVoidTypeDeclaration, * TheConstVoidTypeDeclaration, * The
extern Declaration* TheBoolTypeDeclaration, * TheFloatTypeDeclaration, * TheVoidPointerTypeDeclaration, * TheConstVoidPointerTypeDeclaration, * TheSignedLongTypeDeclaration, * TheUnsignedLongTypeDeclaration;
extern Declaration* TheVoidFunctionTypeDeclaration, * TheConstVoidValueDeclaration;
extern Declaration* TheCharPointerTypeDeclaration, * TheConstCharPointerTypeDeclaration;
extern Declaration* TheNullptrConstDeclaration, * TheZeroIntegerConstDeclaration, * TheZeroFloatConstDeclaration;
extern Expression* TheVoidExpression;

View File

@ -476,6 +476,13 @@ void ByteCodeDisassembler::Disassemble(FILE* file, const uint8* memory, int bank
fprintf(file, "CNVFS\tACCU");
break;
case BC_MALLOC:
fprintf(file, "MALLOC\tACCU");
break;
case BC_FREE:
fprintf(file, "FREE\tACCU");
break;
case BC_JUMPS:
fprintf(file, "JUMP\t$%04X", start + i + 1 + int8(memory[start + i + 0]));
i++;
@ -711,29 +718,29 @@ void NativeCodeDisassembler::Disassemble(FILE* file, const uint8* memory, int ba
break;
case ASMIM_ZERO_PAGE:
addr = memory[ip++];
fprintf(file, "%04x : %02x %02x __ %s %s %s\n", iip, memory[iip], memory[iip + 1], AsmInstructionNames[d.mType], TempName(addr, tbuffer, proc, linker), AddrName(addr, abuffer, proc, linker));
fprintf(file, "%04x : %02x %02x __ %s %s %s\n", iip, memory[iip], memory[iip + 1], AsmInstructionNames[d.mType], TempName(addr, tbuffer, proc, linker), AddrName(bank, addr, abuffer, proc, linker));
break;
case ASMIM_ZERO_PAGE_X:
addr = memory[ip++];
fprintf(file, "%04x : %02x %02x __ %s %s,x %s\n", iip, memory[iip], memory[iip + 1], AsmInstructionNames[d.mType], TempName(addr, tbuffer, proc, linker), AddrName(addr, abuffer, proc, linker));
fprintf(file, "%04x : %02x %02x __ %s %s,x %s\n", iip, memory[iip], memory[iip + 1], AsmInstructionNames[d.mType], TempName(addr, tbuffer, proc, linker), AddrName(bank, addr, abuffer, proc, linker));
break;
case ASMIM_ZERO_PAGE_Y:
addr = memory[ip++];
fprintf(file, "%04x : %02x %02x __ %s %s,y %s\n", iip, memory[iip], memory[iip + 1], AsmInstructionNames[d.mType], TempName(addr, tbuffer, proc, linker), AddrName(addr, abuffer, proc, linker));
fprintf(file, "%04x : %02x %02x __ %s %s,y %s\n", iip, memory[iip], memory[iip + 1], AsmInstructionNames[d.mType], TempName(addr, tbuffer, proc, linker), AddrName(bank, addr, abuffer, proc, linker));
break;
case ASMIM_ABSOLUTE:
addr = memory[ip] + 256 * memory[ip + 1];
fprintf(file, "%04x : %02x %02x %02x %s $%04x %s\n", iip, memory[iip], memory[iip + 1], memory[iip + 2], AsmInstructionNames[d.mType], addr, AddrName(addr, abuffer, proc, linker));
fprintf(file, "%04x : %02x %02x %02x %s $%04x %s\n", iip, memory[iip], memory[iip + 1], memory[iip + 2], AsmInstructionNames[d.mType], addr, AddrName(bank, addr, abuffer, proc, linker));
ip += 2;
break;
case ASMIM_ABSOLUTE_X:
addr = memory[ip] + 256 * memory[ip + 1];
fprintf(file, "%04x : %02x %02x %02x %s $%04x,x %s\n", iip, memory[iip], memory[iip + 1], memory[iip + 2], AsmInstructionNames[d.mType], addr, AddrName(addr, abuffer, proc, linker));
fprintf(file, "%04x : %02x %02x %02x %s $%04x,x %s\n", iip, memory[iip], memory[iip + 1], memory[iip + 2], AsmInstructionNames[d.mType], addr, AddrName(bank, addr, abuffer, proc, linker));
ip += 2;
break;
case ASMIM_ABSOLUTE_Y:
addr = memory[ip] + 256 * memory[ip + 1];
fprintf(file, "%04x : %02x %02x %02x %s $%04x,y %s\n", iip, memory[iip], memory[iip + 1], memory[iip + 2], AsmInstructionNames[d.mType], addr, AddrName(addr, abuffer, proc, linker));
fprintf(file, "%04x : %02x %02x %02x %s $%04x,y %s\n", iip, memory[iip], memory[iip + 1], memory[iip + 2], AsmInstructionNames[d.mType], addr, AddrName(bank, addr, abuffer, proc, linker));
ip += 2;
break;
case ASMIM_INDIRECT:
@ -743,11 +750,11 @@ void NativeCodeDisassembler::Disassemble(FILE* file, const uint8* memory, int ba
break;
case ASMIM_INDIRECT_X:
addr = memory[ip++];
fprintf(file, "%04x : %02x %02x __ %s (%s,x) %s\n", iip, memory[iip], memory[iip + 1], AsmInstructionNames[d.mType], TempName(addr, tbuffer, proc, linker), AddrName(addr, abuffer, proc, linker));
fprintf(file, "%04x : %02x %02x __ %s (%s,x) %s\n", iip, memory[iip], memory[iip + 1], AsmInstructionNames[d.mType], TempName(addr, tbuffer, proc, linker), AddrName(bank, addr, abuffer, proc, linker));
break;
case ASMIM_INDIRECT_Y:
addr = memory[ip++];
fprintf(file, "%04x : %02x %02x __ %s (%s),y %s\n", iip, memory[iip], memory[iip + 1], AsmInstructionNames[d.mType], TempName(addr, tbuffer, proc, linker), AddrName(addr, abuffer, proc, linker));
fprintf(file, "%04x : %02x %02x __ %s (%s),y %s\n", iip, memory[iip], memory[iip + 1], AsmInstructionNames[d.mType], TempName(addr, tbuffer, proc, linker), AddrName(bank, addr, abuffer, proc, linker));
break;
case ASMIM_RELATIVE:
addr = memory[ip++];
@ -755,14 +762,14 @@ void NativeCodeDisassembler::Disassemble(FILE* file, const uint8* memory, int ba
addr = addr + ip - 256;
else
addr = addr + ip;
fprintf(file, "%04x : %02x %02x __ %s $%04x %s\n", iip, memory[iip], memory[iip + 1], AsmInstructionNames[d.mType], addr, AddrName(addr, abuffer, proc, linker));
fprintf(file, "%04x : %02x %02x __ %s $%04x %s\n", iip, memory[iip], memory[iip + 1], AsmInstructionNames[d.mType], addr, AddrName(bank, addr, abuffer, proc, linker));
break;
}
}
}
const char* NativeCodeDisassembler::AddrName(int addr, char* buffer, InterCodeProcedure* proc, Linker* linker)
const char* NativeCodeDisassembler::AddrName(int bank, int addr, char* buffer, InterCodeProcedure* proc, Linker* linker)
{
if (linker)
{
@ -787,14 +794,14 @@ const char* NativeCodeDisassembler::AddrName(int addr, char* buffer, InterCodePr
if (proc && proc->mLinkerObject && addr >= proc->mLinkerObject->mAddress && addr < proc->mLinkerObject->mAddress + proc->mLinkerObject->mSize)
obj = proc->mLinkerObject;
else
obj = linker->FindObjectByAddr(addr);
obj = linker->FindObjectByAddr(bank, addr);
if (obj && obj->mIdent)
{
int i = 0;
while (i < obj->mRanges.Size() && (addr - obj->mAddress < obj->mRanges[i].mOffset || addr - obj->mAddress - obj->mRanges[i].mOffset >= obj->mRanges[i].mSize))
i++;
if (i < obj->mRanges.Size())
if (i < obj->mRanges.Size() && obj->mRanges[i].mIdent)
sprintf_s(buffer, 160, "; (%s.%s + %d)", obj->mIdent->mString, obj->mRanges[i].mIdent->mString, addr - obj->mAddress - obj->mRanges[i].mOffset);
else
sprintf_s(buffer, 160, "; (%s + %d)", obj->mIdent->mString, addr - obj->mAddress);

View File

@ -31,7 +31,7 @@ public:
void DumpMemory(FILE* file, const uint8* memory, int bank, int start, int size, InterCodeProcedure* proc, const Ident* ident, Linker* linker, LinkerObject * lobj);
protected:
const char* TempName(uint8 tmp, char* buffer, InterCodeProcedure* proc, Linker* linker);
const char* AddrName(int addr, char* buffer, InterCodeProcedure* proc, Linker* linker);
const char* AddrName(int bank, int addr, char* buffer, InterCodeProcedure* proc, Linker* linker);
};

View File

@ -250,7 +250,7 @@ bool DiskImage::WriteFile(const char* fname, bool compressed)
if (OpenFile(dname))
{
uint8 buffer[65536], cbuffer[65536];
uint8 * buffer = new uint8[65536], * cbuffer = new uint8[65536];
int size = fread(buffer, 1, 65536, file);
int csize = 0;
@ -311,6 +311,9 @@ bool DiskImage::WriteFile(const char* fname, bool compressed)
else
WriteBytes(buffer, size);
CloseFile();
delete[] buffer;
delete[] cbuffer;
}
fclose(file);

View File

@ -545,6 +545,12 @@ int Emulator::Emulate(int startIP, int trace)
mIP = mMemory[0x101 + mRegS] + 256 * mMemory[0x102 + mRegS] + 1;
mRegS += 2;
}
else if (mIP == 0xff81)
{
printf("------------------ CLEAR ---------------\n");
mIP = mMemory[0x101 + mRegS] + 256 * mMemory[0x102 + mRegS] + 1;
mRegS += 2;
}
uint8 opcode = mMemory[mIP];
AsmInsData d = DecInsData[opcode];
@ -643,7 +649,7 @@ int Emulator::Emulate(int startIP, int trace)
break;
}
if ((trace & 1) && ip == 0x0855)
if ((trace & 1) && ip == 0x0862)
{
unsigned accu = mMemory[BC_REG_ACCU] + (mMemory[BC_REG_ACCU + 1] << 8) + (mMemory[BC_REG_ACCU + 2] << 16) + (mMemory[BC_REG_ACCU + 3] << 24);
int ptr = mMemory[BC_REG_ADDR] + 256 * mMemory[BC_REG_ADDR + 1];

View File

@ -9,15 +9,18 @@ Errors::Errors(void)
}
void Errors::Error(const Location& loc, ErrorID eid, const char* msg, const Ident* info)
void Errors::Error(const Location& loc, ErrorID eid, const char* msg, const Ident* info1, const Ident* info2)
{
if (info)
this->Error(loc, eid, msg, info->mString);
else
if (!info1)
this->Error(loc, eid, msg);
else if (!info2)
this->Error(loc, eid, msg, info1->mString);
else
this->Error(loc, eid, msg, info1->mString, info2->mString);
}
void Errors::Error(const Location& loc, ErrorID eid, const char* msg, const char* info)
void Errors::Error(const Location& loc, ErrorID eid, const char* msg, const char* info1, const char * info2)
{
const char* level = "info";
if (eid >= EERR_GENERIC)
@ -30,12 +33,18 @@ void Errors::Error(const Location& loc, ErrorID eid, const char* msg, const char
level = "warning";
}
if (info)
fprintf(stderr, "%s(%d, %d) : %s %d: %s '%s'\n", loc.mFileName, loc.mLine, loc.mColumn, level ,eid, msg, info);
else
if (!info1)
fprintf(stderr, "%s(%d, %d) : %s %d: %s\n", loc.mFileName, loc.mLine, loc.mColumn, level, eid, msg);
else if (!info2)
fprintf(stderr, "%s(%d, %d) : %s %d: %s '%s'\n", loc.mFileName, loc.mLine, loc.mColumn, level ,eid, msg, info1);
else
fprintf(stderr, "%s(%d, %d) : %s %d: %s '%s' != '%s'\n", loc.mFileName, loc.mLine, loc.mColumn, level, eid, msg, info1, info2);
if (mErrorCount > 10)
if (loc.mFrom)
Error(*(loc.mFrom), EINFO_EXPANDED, "While expanding here");
if (mErrorCount > 10 || eid >= EFATAL_GENERIC)
exit(20);
}

View File

@ -3,10 +3,14 @@
class Location
{
public:
const char* mFileName;
const char * mFileName;
int mLine, mColumn;
const Location * mFrom;
Location() : mFileName(nullptr), mLine(0), mColumn(0) {}
Location() : mFileName(nullptr), mLine(0), mColumn(0), mFrom(nullptr) {}
Location(const Location& loc, const Location* from)
: mFileName(loc.mFileName), mLine(loc.mLine), mColumn(loc.mColumn), mFrom(from)
{}
};
class Ident;
@ -14,6 +18,7 @@ class Ident;
enum ErrorID
{
EINFO_GENERIC = 1000,
EINFO_EXPANDED = 1001,
EWARN_GENERIC = 2000,
EWARN_CONSTANT_TRUNCATED,
@ -28,13 +33,15 @@ enum ErrorID
EWARN_MISSING_RETURN_STATEMENT,
EWARN_UNREACHABLE_CODE,
EWARN_NULL_POINTER_DEREFERENCED,
EWARN_DESTRUCTOR_MISMATCH,
EWARN_NUMERIC_0_USED_AS_NULLPTR,
EWARN_FLOAT_TO_INT,
EERR_GENERIC = 3000,
EERR_FILE_NOT_FOUND,
EERR_RUNTIME_CODE,
EERR_UNIMPLEMENTED,
EERR_COMMAND_LINE,
EERR_OUT_OF_MEMORY,
EERR_OBJECT_NOT_FOUND,
EERR_SYNTAX,
EERR_EXECUTION_FAILED,
@ -76,11 +83,29 @@ enum ErrorID
ERRO_NO_MATCHING_FUNCTION_CALL,
ERRO_AMBIGUOUS_FUNCTION_CALL,
EERR_NO_DEFAULT_CONSTRUCTOR,
EERR_INVALID_OPERATOR,
EERR_MISSING_TEMP,
EERR_NON_STATIC_MEMBER,
EERR_TEMPLATE_PARAMS,
EERR_FUNCTION_TEMPLATE,
EERR_INVALID_BITFIELD,
EERR_INVALID_CAPTURE,
EERR_INVALID_PACK_USAGE,
EERR_INVALID_FOLD_EXPRESSION,
EERR_INVALID_CONSTEXPR,
EERR_DOUBLE_FREE,
EERR_UNBALANCED_HEAP_USE,
ERRR_STACK_OVERFLOW,
ERRR_INVALID_NUMBER,
EERR_OVERLAPPING_DATA_SECTIONS,
EERR_INVALID_PREPROCESSOR,
EFATAL_GENERIC = 4000,
EFATAL_OUT_OF_MEMORY,
EFATAL_MACRO_EXPANSION_DEPTH,
};
class Errors
@ -90,6 +115,6 @@ public:
int mErrorCount;
void Error(const Location& loc, ErrorID eid, const char* msg, const Ident * info);
void Error(const Location& loc, ErrorID eid, const char* msg, const char* info = nullptr);
void Error(const Location& loc, ErrorID eid, const char* msg, const Ident* info1, const Ident* info2 = nullptr);
void Error(const Location& loc, ErrorID eid, const char* msg, const char* info1 = nullptr, const char* info2 = nullptr);
};

View File

@ -155,11 +155,13 @@ void GlobalAnalyzer::AutoInline(void)
Declaration* dec = f->mBase->mParams;
while (dec)
{
nparams++;
nparams += dec->mSize;
dec = dec->mNext;
}
int cost = (f->mComplexity - 20 * nparams);
int cost = (f->mComplexity - 20 * nparams - 20);
// printf("CHEK INLINING %s %d * (%d - 1)\n", f->mIdent->mString, cost, f->mCallers.Size());
bool doinline = false;
if ((f->mCompilerOptions & COPT_OPTIMIZE_INLINE) && (f->mFlags & DTF_REQUEST_INLINE))
@ -171,9 +173,8 @@ void GlobalAnalyzer::AutoInline(void)
if (doinline)
{
#if 0
printf("INLINING %s %d * (%d - 1)\n", f->mIdent->mString, cost, f->mCallers.Size());
#endif
// printf("INLINING %s %d * (%d - 1)\n", f->mIdent->mString, cost, f->mCallers.Size());
f->mFlags |= DTF_INLINE;
for (int j = 0; j < f->mCallers.Size(); j++)
{
@ -218,9 +219,11 @@ void GlobalAnalyzer::AutoInline(void)
{
if (pdec->mFlags & DTF_FPARAM_CONST)
{
pdec->mFlags |= DTF_FPARAM_UNUSED;
pdec->mVarIndex = dec->mNumVars++;
Expression* aexp = new Expression(pdec->mLocation, EX_ASSIGNMENT);
Expression* aexp = new Expression(pdec->mLocation, EX_INITIALIZATION);
Expression* pexp = new Expression(pdec->mLocation, EX_VARIABLE);
Expression* lexp = new Expression(dec->mLocation, EX_SEQUENCE);
@ -284,7 +287,7 @@ void GlobalAnalyzer::MarkRecursions(void)
void GlobalAnalyzer::CheckFastcall(Declaration* procDec, bool head)
{
if (!(procDec->mBase->mFlags & DTF_FASTCALL) && !(procDec->mBase->mFlags & DTF_STACKCALL) && (procDec->mType == DT_CONST_FUNCTION) && !(procDec->mFlags & DTF_FUNC_ANALYZING))
if (!(procDec->mBase->mFlags & DTF_FASTCALL) && (procDec->mType == DT_CONST_FUNCTION) && !(procDec->mFlags & DTF_FUNC_ANALYZING))
{
procDec->mFlags |= DTF_FUNC_ANALYZING;
int nbase = 0;
@ -293,12 +296,31 @@ void GlobalAnalyzer::CheckFastcall(Declaration* procDec, bool head)
Declaration* cf = procDec->mCalled[i];
if (cf->mType == DT_TYPE_FUNCTION)
procDec->mFlags |= DTF_DYNSTACK;
{
for (int i = 0; i < mVariableFunctions.Size(); i++)
{
Declaration* vf = mVariableFunctions[i];
if (vf->mBase->IsSame(cf))
{
CheckFastcall(vf, false);
int n = vf->mBase->mFastCallBase + vf->mBase->mFastCallSize;
if (n > nbase)
nbase = n;
}
}
// procDec->mFlags |= DTF_DYNSTACK;
}
else
CheckFastcall(cf, false);
// if (!(cf->mBase->mFlags & DTF_FASTCALL))
// procDec->mBase->mFlags |= DTF_STACKCALL;
if (cf->mFlags & DTF_DYNSTACK)
procDec->mFlags |= DTF_DYNSTACK;
// if (!(cf->mBase->mFlags & DTF_FASTCALL))
// procDec->mBase->mFlags |= DTF_STACKCALL;
cf = cf->mBase;
int n = cf->mFastCallBase + cf->mFastCallSize;
@ -306,6 +328,50 @@ void GlobalAnalyzer::CheckFastcall(Declaration* procDec, bool head)
nbase = n;
}
if (procDec->mValue && procDec->mValue->mType == EX_DISPATCH)
{
Declaration* maxf = nullptr;
for (int i = 0; i < procDec->mCalled.Size(); i++)
{
Declaration* cf = procDec->mCalled[i];
if (!maxf)
maxf = cf;
else if (!(maxf->mBase->mFlags & DTF_STACKCALL))
{
if (cf->mBase->mFlags & DTF_STACKCALL)
maxf = cf;
else if (cf->mBase->mFastCallBase > maxf->mBase->mFastCallBase)
maxf = cf;
}
}
for (int i = 0; i < procDec->mCalled.Size(); i++)
{
Declaration* cf = procDec->mCalled[i];
if (cf != maxf)
{
if (maxf->mBase->mFlags & DTF_STACKCALL)
{
cf->mBase->mFlags &= ~DTF_FASTCALL;
cf->mBase->mFlags |= DTF_STACKCALL;
}
cf->mParams = maxf->mParams;
cf->mBase->mFastCallBase = cf->mFastCallBase = maxf->mBase->mFastCallBase;
cf->mBase->mFastCallSize = cf->mFastCallSize = maxf->mBase->mFastCallSize;
}
}
procDec->mFastCallBase = procDec->mBase->mFastCallBase;
procDec->mFastCallSize = procDec->mBase->mFastCallSize;
procDec->mFlags &= ~DTF_FUNC_ANALYZING;
return;
}
procDec->mFastCallBase = nbase;
procDec->mFastCallSize = 0;
procDec->mBase->mFastCallBase = nbase;
@ -319,7 +385,7 @@ void GlobalAnalyzer::CheckFastcall(Declaration* procDec, bool head)
}
else if (procDec->mFlags & DTF_FUNC_RECURSIVE)
{
if (head)
// if (head)
procDec->mBase->mFlags |= DTF_STACKCALL;
}
else if (!(procDec->mBase->mFlags & DTF_VARIADIC) && !(procDec->mFlags & DTF_FUNC_VARIABLE) && !(procDec->mFlags & DTF_DYNSTACK))
@ -413,6 +479,42 @@ void GlobalAnalyzer::CheckInterrupt(void)
} while (changed);
}
bool GlobalAnalyzer::IsStackParam(const Declaration* pdec) const
{
if (pdec->mType == DT_TYPE_STRUCT)
{
if (pdec->mSize > 4)
return true;
if (pdec->mCopyConstructor)
{
if (!((mCompilerOptions & COPT_OPTIMIZE_INLINE) && (pdec->mCopyConstructor->mFlags & DTF_REQUEST_INLINE)))
return true;
}
if (pdec->mDestructor)
{
if (!((mCompilerOptions & COPT_OPTIMIZE_INLINE) && (pdec->mDestructor->mFlags & DTF_REQUEST_INLINE)))
return true;
}
}
return false;
}
void GlobalAnalyzer::UndoParamReference(Expression* exp, Declaration * param)
{
if (exp)
{
if (exp->mType == EX_VARIABLE)
{
if (exp->mDecValue == param)
exp->mDecType = param->mBase;
}
UndoParamReference(exp->mLeft, param);
UndoParamReference(exp->mRight, param);
}
}
void GlobalAnalyzer::AnalyzeProcedure(Expression* exp, Declaration* dec)
{
dec->mUseCount++;
@ -429,6 +531,14 @@ void GlobalAnalyzer::AnalyzeProcedure(Expression* exp, Declaration* dec)
mFunctions.Push(dec);
Declaration* pdec = dec->mBase->mParams;
while (pdec)
{
if (IsStackParam(pdec->mBase))
dec->mBase->mFlags |= DTF_STACKCALL;
pdec = pdec->mNext;
}
dec->mFlags |= DTF_ANALYZED;
dec->mFlags |= DTF_FUNC_INTRSAVE;
@ -443,6 +553,22 @@ void GlobalAnalyzer::AnalyzeProcedure(Expression* exp, Declaration* dec)
dec->mFlags |= DTF_FUNC_CONSTEXPR;
dec->mFlags |= DTF_FUNC_PURE;
Analyze(exp, dec, false);
Declaration* pdec = dec->mBase->mParams;
int vi = 0;
while (pdec)
{
pdec->mVarIndex += vi;
if (pdec->mBase->mType == DT_TYPE_REFERENCE && pdec->mBase->mBase->IsSimpleType() && !(pdec->mFlags & DTF_VAR_ADDRESS) && (pdec->mBase->mBase->mFlags & DTF_CONST))
{
pdec->mBase = pdec->mBase->mBase;
pdec->mSize = pdec->mBase->mSize;
vi += pdec->mSize - 2;
UndoParamReference(exp, pdec);
}
pdec = pdec->mNext;
}
}
else
mErrors->Error(dec->mLocation, EERR_UNDEFINED_OBJECT, "Calling undefined function", dec->mQualIdent);
@ -532,8 +658,6 @@ Declaration * GlobalAnalyzer::Analyze(Expression* exp, Declaration* procDec, boo
{
Declaration* ldec, * rdec;
procDec->mComplexity += 10;
switch (exp->mType)
{
case EX_ERROR:
@ -580,6 +704,9 @@ Declaration * GlobalAnalyzer::Analyze(Expression* exp, Declaration* procDec, boo
}
else
{
if (lhs)
exp->mDecValue->mFlags |= DTF_VAR_ADDRESS;
if (!(exp->mDecValue->mFlags & DTF_ANALYZED))
{
procDec->mLocalSize += exp->mDecValue->mSize;
@ -589,22 +716,32 @@ Declaration * GlobalAnalyzer::Analyze(Expression* exp, Declaration* procDec, boo
return exp->mDecValue;
case EX_INITIALIZATION:
case EX_ASSIGNMENT:
procDec->mComplexity += 10 * exp->mLeft->mDecType->mSize;
ldec = Analyze(exp->mLeft, procDec, true);
rdec = Analyze(exp->mRight, procDec, false);
if (exp->mLeft->mType == EX_VARIABLE && exp->mRight->mType == EX_CALL && exp->mLeft->mDecType->mType == DT_TYPE_STRUCT)
exp->mLeft->mDecValue->mFlags |= DTF_VAR_ALIASING;
RegisterProc(rdec);
return ldec;
case EX_BINARY:
procDec->mComplexity += 10 * exp->mDecType->mSize;
ldec = Analyze(exp->mLeft, procDec, lhs);
rdec = Analyze(exp->mRight, procDec, lhs);
return ldec;
case EX_RELATIONAL:
procDec->mComplexity += 10 * exp->mLeft->mDecType->mSize;
ldec = Analyze(exp->mLeft, procDec, false);
rdec = Analyze(exp->mRight, procDec, false);
return TheBoolTypeDeclaration;
case EX_PREINCDEC:
procDec->mComplexity += 10 * exp->mLeft->mDecType->mSize;
return Analyze(exp->mLeft, procDec, true);
case EX_PREFIX:
if (exp->mToken == TK_BINARY_AND)
@ -623,13 +760,21 @@ Declaration * GlobalAnalyzer::Analyze(Expression* exp, Declaration* procDec, boo
return exp->mDecType;
}
else
{
procDec->mComplexity += 10 * exp->mLeft->mDecType->mSize;
return Analyze(exp->mLeft, procDec, false);
}
break;
case EX_POSTFIX:
procDec->mComplexity += 10 * exp->mLeft->mDecType->mSize;
break;
case EX_POSTINCDEC:
procDec->mComplexity += 10 * exp->mLeft->mDecType->mSize;
return Analyze(exp->mLeft, procDec, true);
case EX_INDEX:
procDec->mComplexity += 10 * exp->mLeft->mDecType->mSize;
ldec = Analyze(exp->mLeft, procDec, lhs);
if (ldec->mType == DT_VARIABLE || ldec->mType == DT_ARGUMENT)
{
@ -648,8 +793,18 @@ Declaration * GlobalAnalyzer::Analyze(Expression* exp, Declaration* procDec, boo
case EX_QUALIFY:
Analyze(exp->mLeft, procDec, lhs);
return exp->mDecValue->mBase;
case EX_DISPATCH:
Analyze(exp->mLeft, procDec, lhs);
// RegisterCall(procDec, exp->mLeft->mDecType);
break;
case EX_VCALL:
exp->mType = EX_CALL;
exp->mLeft->mDecValue = exp->mLeft->mDecValue->mVTable;
// intentional fall through
case EX_CALL:
case EX_INLINE:
procDec->mComplexity += 10;
ldec = Analyze(exp->mLeft, procDec, false);
if ((ldec->mFlags & DTF_INTRINSIC) && !ldec->mValue)
{
@ -677,10 +832,12 @@ Declaration * GlobalAnalyzer::Analyze(Expression* exp, Declaration* procDec, boo
{
Expression* pex = rex->mType == EX_LIST ? rex->mLeft : rex;
procDec->mComplexity += 5 * pex->mDecType->mSize;
if (pdec && !(ldec->mBase->mFlags & DTF_VARIADIC) && !(ldec->mFlags & (DTF_INTRINSIC | DTF_FUNC_ASSEMBLER)))
{
#if 1
if (mCompilerOptions & COPT_OPTIMIZE_BASIC)
if (mCompilerOptions & COPT_OPTIMIZE_CONST_PARAMS)
{
if (!(pdec->mFlags & DTF_FPARAM_NOCONST))
{
@ -715,9 +872,22 @@ Declaration * GlobalAnalyzer::Analyze(Expression* exp, Declaration* procDec, boo
#endif
}
if (pex->mType == EX_CALL && pex->mDecType->mType == DT_TYPE_STRUCT)
if (pdec && pdec->mBase->mType == DT_TYPE_STRUCT && pdec->mBase->mCopyConstructor)
{
if (pdec->mBase->mMoveConstructor)
{
AnalyzeProcedure(pdec->mBase->mMoveConstructor->mValue, pdec->mBase->mMoveConstructor);
RegisterCall(procDec, pdec->mBase->mMoveConstructor);
}
AnalyzeProcedure(pdec->mBase->mCopyConstructor->mValue, pdec->mBase->mCopyConstructor);
RegisterCall(procDec, pdec->mBase->mCopyConstructor);
}
if (pex->mType == EX_CALL && IsStackParam(pex->mDecType) && !(pdec && (pdec->mBase->mType == DT_TYPE_REFERENCE || pdec->mBase->mType == DT_TYPE_RVALUEREF)))
ldec->mBase->mFlags |= DTF_STACKCALL;
RegisterProc(Analyze(pex, procDec, pdec && pdec->mBase->IsReference()));
if (pdec)
pdec = pdec->mNext;
@ -726,31 +896,71 @@ Declaration * GlobalAnalyzer::Analyze(Expression* exp, Declaration* procDec, boo
else
rex = nullptr;
}
RegisterProc(Analyze(exp->mRight, procDec, false));
}
break;
case EX_LIST:
case EX_COMMA:
RegisterProc(Analyze(exp->mLeft, procDec, false));
return Analyze(exp->mRight, procDec, false);
case EX_RETURN:
if (exp->mLeft)
RegisterProc(Analyze(exp->mLeft, procDec, false));
{
RegisterProc(Analyze(exp->mLeft, procDec, procDec->mBase->mBase->IsReference()));
if (procDec->mBase->mBase && procDec->mBase->mBase->mType == DT_TYPE_STRUCT && procDec->mBase->mBase->mCopyConstructor)
{
if (procDec->mBase->mBase->mMoveConstructor)
{
AnalyzeProcedure(procDec->mBase->mBase->mMoveConstructor->mValue, procDec->mBase->mBase->mMoveConstructor);
RegisterCall(procDec, procDec->mBase->mBase->mMoveConstructor);
}
AnalyzeProcedure(procDec->mBase->mBase->mCopyConstructor->mValue, procDec->mBase->mBase->mCopyConstructor);
RegisterCall(procDec, procDec->mBase->mBase->mCopyConstructor);
}
}
break;
case EX_SEQUENCE:
do
{
if (exp->mType == EX_SEQUENCE)
{
if (exp->mLeft)
ldec = Analyze(exp->mLeft, procDec, false);
exp = exp->mRight;
}
else
return Analyze(exp, procDec, false);
} while (exp);
break;
case EX_SCOPE:
Analyze(exp->mLeft, procDec, false);
break;
case EX_CONSTRUCT:
if (exp->mLeft->mLeft)
Analyze(exp->mLeft->mLeft, procDec, false);
if (exp->mLeft->mRight)
Analyze(exp->mLeft->mRight, procDec, false);
if (exp->mRight)
return Analyze(exp->mRight, procDec, false);
break;
case EX_CLEANUP:
Analyze(exp->mRight, procDec, false);
return Analyze(exp->mLeft, procDec, lhs);
case EX_WHILE:
procDec->mFlags &= ~DTF_FUNC_CONSTEXPR;
procDec->mComplexity += 20;
ldec = Analyze(exp->mLeft, procDec, false);
rdec = Analyze(exp->mRight, procDec, false);
break;
case EX_IF:
procDec->mComplexity += 20;
ldec = Analyze(exp->mLeft, procDec, false);
rdec = Analyze(exp->mRight->mLeft, procDec, false);
if (exp->mRight->mRight)
@ -761,6 +971,8 @@ Declaration * GlobalAnalyzer::Analyze(Expression* exp, Declaration* procDec, boo
case EX_FOR:
procDec->mFlags &= ~DTF_FUNC_CONSTEXPR;
procDec->mComplexity += 30;
if (exp->mLeft->mRight)
ldec = Analyze(exp->mLeft->mRight, procDec, false);
if (exp->mLeft->mLeft->mLeft)
@ -770,6 +982,8 @@ Declaration * GlobalAnalyzer::Analyze(Expression* exp, Declaration* procDec, boo
ldec = Analyze(exp->mLeft->mLeft->mRight, procDec, false);
break;
case EX_DO:
procDec->mComplexity += 20;
ldec = Analyze(exp->mLeft, procDec, false);
rdec = Analyze(exp->mRight, procDec, false);
break;
@ -780,7 +994,7 @@ Declaration * GlobalAnalyzer::Analyze(Expression* exp, Declaration* procDec, boo
case EX_TYPE:
break;
case EX_TYPECAST:
return Analyze(exp->mRight, procDec, false);
return Analyze(exp->mLeft, procDec, false);
break;
case EX_LOGICAL_AND:
ldec = Analyze(exp->mLeft, procDec, false);
@ -806,6 +1020,8 @@ Declaration * GlobalAnalyzer::Analyze(Expression* exp, Declaration* procDec, boo
exp = exp->mRight;
while (exp)
{
procDec->mComplexity += 10;
if (exp->mLeft->mRight)
rdec = Analyze(exp->mLeft->mRight, procDec, false);
exp = exp->mRight;
@ -816,9 +1032,11 @@ Declaration * GlobalAnalyzer::Analyze(Expression* exp, Declaration* procDec, boo
case EX_DEFAULT:
break;
case EX_CONDITIONAL:
procDec->mComplexity += exp->mDecType->mSize * 10;
ldec = Analyze(exp->mLeft, procDec, false);
RegisterProc(Analyze(exp->mRight->mLeft, procDec, false));
RegisterProc(Analyze(exp->mRight->mRight, procDec, false));
RegisterProc(Analyze(exp->mRight->mLeft, procDec, lhs));
RegisterProc(Analyze(exp->mRight->mRight, procDec, lhs));
break;
}
@ -843,6 +1061,9 @@ void GlobalAnalyzer::RegisterCall(Declaration* from, Declaration* to)
{
if (from)
{
if (to->mType == DT_VARIABLE || to->mType == DT_ARGUMENT)
to = to->mBase;
if (to->mType == DT_CONST_FUNCTION)
{
if (to->mFlags & DTF_DYNSTACK)
@ -879,6 +1100,13 @@ void GlobalAnalyzer::RegisterProc(Declaration* to)
{
if (to->mType == DT_CONST_FUNCTION)
{
#if 1
if (to->mBase->mFlags & DTF_VIRTUAL)
{
}
else
#endif
if (!(to->mFlags & DTF_FUNC_VARIABLE))
{
to->mFlags |= DTF_FUNC_VARIABLE;

View File

@ -34,10 +34,12 @@ protected:
Declaration* Analyze(Expression* exp, Declaration* procDec, bool lhs);
bool IsStackParam(const Declaration* pdec) const;
bool MarkCycle(Declaration* rootDec, Declaration* procDec);
uint64 GetProcFlags(Declaration* to) const;
void RegisterCall(Declaration* from, Declaration* to);
void RegisterProc(Declaration* to);
void UndoParamReference(Expression* ex, Declaration* param);
};

925
oscar64/GlobalOptimizer.cpp Normal file
View File

@ -0,0 +1,925 @@
#include "GlobalOptimizer.h"
#include "Constexpr.h"
#define DUMP_OPTS 0
static const uint64 OPTF_ANALYZED = (1ULL << 0);
static const uint64 OPTF_ANALYZING = (1ULL << 1);
static const uint64 OPTF_RECURSIVE = (1ULL << 2);
static const uint64 OPTF_FUNC_VARIABLE = (1ULL << 3);
static const uint64 OPTF_CALLED = (1ULL << 4);
static const uint64 OPTF_CALLING = (1ULL << 5);
static const uint64 OPTF_VAR_MODIFIED = (1ULL << 6);
static const uint64 OPTF_VAR_ADDRESS = (1ULL << 7);
static const uint64 OPTF_VAR_USED = (1ULL << 8);
static const uint64 OPTF_VAR_CONST = (1ULL << 9);
static const uint64 OPTF_VAR_NOCONST = (1ULL << 10);
static const uint64 OPTF_SINGLE_RETURN = (1ULL << 11);
static const uint64 OPTF_MULTI_RETURN = (1ULL << 12);
GlobalOptimizer::GlobalOptimizer(Errors* errors, Linker* linker)
: mErrors(errors), mLinker(linker)
{
}
GlobalOptimizer::~GlobalOptimizer(void)
{
}
void GlobalOptimizer::Reset(void)
{
for (int i = 0; i < mFunctions.Size(); i++)
{
Declaration* func = mFunctions[i];
Declaration* ftype = func->mBase;
func->mOptFlags = 0;
ftype->mOptFlags = 0;
func->mReturn = nullptr;
Declaration* pdec = ftype->mParams;
while (pdec)
{
pdec->mOptFlags = 0;
pdec = pdec->mNext;
}
}
for (int i = 0; i < mGlobalVariables.Size(); i++)
{
mGlobalVariables[i]->mOptFlags = 0;
}
mFunctions.SetSize(0);
mGlobalVariables.SetSize(0);
mCalledFunctions.SetSize(0);
mCalledFunctions.SetSize(0);
}
void GlobalOptimizer::PropagateParamCommas(Expression*& fexp, Expression*& exp)
{
PropagateCommas(exp);
if (exp->mType == EX_COMMA)
{
Expression* cexp = exp;
exp = cexp->mRight;
cexp->mRight = fexp;
fexp = cexp;
fexp->mDecType = cexp->mRight->mDecType;
}
}
void GlobalOptimizer::PropagateCommas(Expression*& exp)
{
if (exp->mType == EX_PREFIX && exp->mLeft->mType == EX_COMMA)
{
Expression* cexp = exp->mLeft;
exp->mLeft = cexp->mRight;
cexp->mDecType = exp->mDecType;
cexp->mRight = exp->ConstantFold(mErrors, nullptr);
exp = cexp;
}
else if (exp->mType == EX_CALL)
{
Expression* pexp = exp;
Expression* rexp = pexp->mRight;
if (rexp)
{
while (rexp && rexp->mType == EX_LIST)
{
PropagateParamCommas(exp, rexp->mLeft);
if (rexp->mLeft-> mType == EX_COMMA)
pexp = rexp;
rexp = rexp->mRight;
}
if (rexp)
PropagateParamCommas(exp, pexp->mRight);
}
}
else
{
if (exp->mLeft)
PropagateCommas(exp->mLeft);
if (exp->mRight)
PropagateCommas(exp->mRight);
}
}
bool GlobalOptimizer::CheckConstReturns(Expression*& exp)
{
bool changed = false;
if (exp->mType == EX_CALL && exp->mDecType && exp->mDecType->mType != DT_TYPE_VOID)
{
if (exp->mLeft->mType == EX_CONSTANT)
{
Declaration* pcall = exp->mLeft->mDecValue;
if ((pcall->mOptFlags & OPTF_SINGLE_RETURN) && pcall->mReturn->mLeft)
{
Expression * rexp = pcall->mReturn->mLeft;
if (rexp->mType == EX_CONSTANT)
{
#if DUMP_OPTS
printf("Extract const return\n");
#endif
Expression* lexp = new Expression(exp->mLocation, EX_COMMA);
lexp->mLeft = exp;
lexp->mRight = new Expression(pcall->mReturn->mLocation, EX_CONSTANT);
lexp->mRight->mDecValue = pcall->mReturn->mLeft->mDecValue;
lexp->mRight->mDecType = exp->mDecType;
lexp->mDecType = exp->mDecType;
exp->mDecType = TheVoidTypeDeclaration;
exp = lexp;
return true;
}
else if (rexp->mType == EX_PREFIX && rexp->mToken == TK_MUL && rexp->mLeft->mType == EX_VARIABLE && rexp->mLeft->mDecValue->mType == DT_ARGUMENT)
{
Declaration* pdec = rexp->mLeft->mDecValue;
if (pdec->mVarIndex == 0 && !(pdec->mOptFlags & OPTF_VAR_ADDRESS))
{
Expression* pex = exp->mRight;
if (pex->mType == EX_LIST)
pex = pex->mLeft;
if (pex->mType == EX_CONSTANT)
{
#if DUMP_OPTS
printf("Forward this pointer\n");
#endif
Expression* lexp = new Expression(exp->mLocation, EX_COMMA);
lexp->mLeft = exp;
lexp->mRight = new Expression(pcall->mReturn->mLocation, EX_PREFIX);
lexp->mRight->mToken = TK_MUL;
lexp->mRight->mLeft = pex;
lexp->mRight->mDecType = pcall->mBase->mBase;
exp->mDecType = TheVoidTypeDeclaration;
exp = lexp;
return true;
}
}
}
}
}
}
if (exp->mLeft && CheckConstReturns(exp->mLeft))
changed = true;
if (exp->mRight && CheckConstReturns(exp->mRight))
changed = true;
return changed;
}
bool GlobalOptimizer::CheckUnusedLocals(Expression*& exp)
{
bool changed = false;
if (exp->mType == EX_INITIALIZATION)
{
Expression* vexp = exp->mLeft;
if (vexp->mType == EX_VARIABLE)
{
Declaration* vdec = vexp->mDecValue;
if (vdec->mType == DT_VARIABLE && !(vdec->mFlags & (DTF_GLOBAL | DTF_STATIC)) && !(vdec->mOptFlags & OPTF_VAR_USED))
{
exp = exp->mRight;
return true;
}
}
}
if (exp->mLeft && CheckUnusedLocals(exp->mLeft))
changed = true;
if (exp->mRight && CheckUnusedLocals(exp->mRight))
changed = true;
return changed;
}
void GlobalOptimizer::RemoveValueReturn(Expression* exp)
{
if (exp->mType == EX_RETURN && exp->mLeft)
{
if (exp->mLeft->HasSideEffects())
{
exp->mType = EX_SEQUENCE;
exp->mRight = new Expression(exp->mLocation, EX_RETURN);
}
else
exp->mLeft = nullptr;
}
if (exp->mLeft)
RemoveValueReturn(exp->mLeft);
if (exp->mRight)
RemoveValueReturn(exp->mRight);
}
void GlobalOptimizer::UndoParamReference(Expression* exp, Declaration* param)
{
if (exp)
{
if (exp->mType == EX_VARIABLE && exp->mDecValue == param)
{
exp->mDecType = param->mBase;
}
UndoParamReference(exp->mLeft, param);
UndoParamReference(exp->mRight, param);
}
}
bool GlobalOptimizer::ReplaceParamConst(Expression* exp, Declaration* param)
{
bool changed = false;
if (exp)
{
if (exp->mType == EX_VARIABLE && exp->mDecValue == param)
{
exp->mType = EX_CONSTANT;
exp->mDecType = param->mBase;
exp->mDecValue = param->mValue->mDecValue->ConstCast(param->mBase);
changed = true;
}
if (ReplaceParamConst(exp->mLeft, param))
changed = true;
if (ReplaceParamConst(exp->mRight, param))
changed = true;
}
return changed;
}
bool GlobalOptimizer::Optimize(void)
{
bool changed = false;
#if DUMP_OPTS
printf("OPT---\n");
#endif
for (int i = 0; i < mFunctions.Size(); i++)
{
Declaration* func = mFunctions[i];
Declaration* ftype = func->mBase;
if (func->mValue && func->mValue->mType != EX_DISPATCH)
{
#if DUMP_OPTS
printf("%s %08llx\n", mFunctions[i]->mQualIdent->mString, mFunctions[i]->mOptFlags);
#endif
if (CheckUnusedLocals(func->mValue))
changed = true;
if (CheckConstReturns(func->mValue))
changed = true;
if (!(func->mOptFlags & OPTF_FUNC_VARIABLE) && !(func->mBase->mFlags & DTF_VIRTUAL))
{
if (!(func->mOptFlags & OPTF_VAR_USED) && func->mBase->mBase && (func->mBase->mBase->IsSimpleType() || func->mBase->mBase->IsReference()))
{
#if DUMP_OPTS
printf("Remove return value\n");
#endif
RemoveValueReturn(func->mValue);
func->mBase->mBase = TheVoidTypeDeclaration;
changed = true;
}
else if (!(func->mOptFlags & OPTF_VAR_ADDRESS) && func->mBase->mBase && func->mBase->mBase->IsReference() && func->mBase->mBase->mBase->IsSimpleType())
{
#if DUMP_OPTS
printf("Demote reference return\n");
#endif
func->mBase->mBase = func->mBase->mBase->mBase;
changed = true;
}
Declaration* pdec = ftype->mParams;
int vi = 0;
while (pdec)
{
pdec->mVarIndex += vi;
if (!(pdec->mOptFlags & OPTF_VAR_USED) && !(pdec->mFlags & DTF_FPARAM_UNUSED))
{
if (!pdec->mBase->IsReference() || !(pdec->mOptFlags & OPTF_VAR_ADDRESS))
{
#if DUMP_OPTS
printf("Unused parameter %s\n", pdec->mIdent ? pdec->mIdent->mString : "_");
#endif
vi -= pdec->mSize;
pdec->mFlags |= DTF_FPARAM_UNUSED;
changed = true;
}
}
else if (!(pdec->mOptFlags & OPTF_VAR_ADDRESS) && pdec->mBase->IsReference() && pdec->mBase->mBase->IsSimpleType())
{
#if DUMP_OPTS
printf("Reference parameter %s to value\n", pdec->mIdent ? pdec->mIdent->mString : "_");
#endif
vi += pdec->mSize - 2;
pdec->mBase = pdec->mBase->mBase;
pdec->mSize = pdec->mBase->mSize;
UndoParamReference(func->mValue, pdec);
changed = true;
}
else if ((pdec->mOptFlags & OPTF_VAR_CONST) && !(pdec->mOptFlags & OPTF_VAR_ADDRESS))
{
if (ReplaceParamConst(func->mValue, pdec))
{
#if DUMP_OPTS
printf("Const parameter %s\n", pdec->mIdent ? pdec->mIdent->mString : "_");
#endif
changed = true;
}
}
pdec->mOptFlags = 0;
pdec = pdec->mNext;
}
}
PropagateCommas(func->mValue);
}
else if (func->mValue && func->mValue->mType == EX_DISPATCH)
{
if (!(func->mOptFlags & OPTF_FUNC_VARIABLE))
{
Declaration* pdec = ftype->mParams;
while (pdec)
{
if ((pdec->mOptFlags & OPTF_VAR_CONST) && !(pdec->mOptFlags & OPTF_VAR_ADDRESS))
{
if (ReplaceParamConst(func->mValue, pdec))
{
#if DUMP_OPTS
printf("Const parameter %s\n", pdec->mIdent ? pdec->mIdent->mString : "_");
#endif
changed = true;
}
}
pdec->mOptFlags = 0;
pdec = pdec->mNext;
}
}
}
}
return changed;
}
void GlobalOptimizer::AnalyzeProcedure(Expression* exp, Declaration* procDec)
{
if (procDec->mOptFlags & OPTF_ANALYZING)
{
procDec->mOptFlags |= OPTF_RECURSIVE;
}
else if (!(procDec->mOptFlags & OPTF_ANALYZED))
{
procDec->mOptFlags |= OPTF_ANALYZING | OPTF_ANALYZED;
mFunctions.Push(procDec);
if ((procDec->mFlags & DTF_INTRINSIC) && !procDec->mValue)
;
else if (procDec->mFlags & DTF_DEFINED)
{
Analyze(exp, procDec, false);
}
else
mErrors->Error(procDec->mLocation, EERR_UNDEFINED_OBJECT, "Calling undefined function", procDec->mQualIdent);
procDec->mOptFlags &= ~OPTF_ANALYZING;
}
}
void GlobalOptimizer::AnalyzeAssembler(Expression* exp, Declaration* procDec)
{
while (exp)
{
if (exp->mLeft && exp->mLeft->mDecValue)
{
Declaration* adec = exp->mLeft->mDecValue;
if (adec->mType == DT_LABEL_REF)
{
}
else if (adec->mType == DT_VARIABLE_REF)
{
if (adec->mBase->mFlags & DTF_GLOBAL)
AnalyzeGlobalVariable(adec->mBase);
else
adec->mBase->mOptFlags |= OPTF_VAR_USED | OPTF_VAR_ADDRESS;
}
else if (adec->mType == DT_LABEL)
{
}
else if (adec->mType == DT_VARIABLE)
{
if (adec->mFlags & DTF_GLOBAL)
AnalyzeGlobalVariable(adec);
else
adec->mOptFlags |= OPTF_VAR_USED | OPTF_VAR_ADDRESS;
}
else if (adec->mType == DT_ARGUMENT)
{
adec->mOptFlags |= OPTF_VAR_USED;
}
else if (adec->mType == DT_FUNCTION_REF)
{
adec->mBase->mOptFlags |= OPTF_VAR_USED;
AnalyzeProcedure(adec->mBase->mValue, adec->mBase);
RegisterProc(adec->mBase);
}
else if (adec->mType == DT_CONST_FUNCTION)
{
adec->mOptFlags |= OPTF_VAR_USED;
AnalyzeProcedure(adec->mValue, adec);
RegisterCall(procDec, adec);
}
}
exp = exp->mRight;
}
}
void GlobalOptimizer::AnalyzeGlobalVariable(Declaration* dec)
{
while (dec->mType == DT_VARIABLE_REF)
dec = dec->mBase;
if (!(dec->mOptFlags & OPTF_ANALYZED))
{
dec->mOptFlags |= OPTF_ANALYZED;
if (dec->mValue && dec->mValue->mType == EX_CONSTRUCT)
{
if (dec->mValue->mLeft->mLeft->mType == EX_CALL && (dec->mValue->mLeft->mLeft->mLeft->mDecValue->mFlags & DTF_CONSTEXPR))
{
ConstexprInterpreter cinter(dec->mLocation, mErrors, dec->mSection);
dec->mValue = cinter.EvalConstructor(dec->mValue->mLeft->mLeft);
}
}
mGlobalVariables.Push(dec);
if (dec->mValue)
{
Analyze(dec->mValue, dec, false);
}
}
}
void GlobalOptimizer::AnalyzeInit(Declaration* mdec)
{
while (mdec)
{
if (mdec->mValue)
RegisterProc(Analyze(mdec->mValue, mdec, false));
else if (mdec->mParams)
AnalyzeInit(mdec->mParams);
mdec = mdec->mNext;
}
}
void GlobalOptimizer::RegisterCall(Declaration* from, Declaration* to)
{
if (from)
{
if (to->mType == DT_VARIABLE || to->mType == DT_ARGUMENT)
to = to->mBase;
if (to->mType == DT_CONST_FUNCTION)
{
if (!(to->mOptFlags & OPTF_CALLED))
{
to->mOptFlags |= OPTF_CALLED;
mCalledFunctions.Push(to);
}
if (!(from->mOptFlags & OPTF_CALLING))
{
from->mOptFlags |= OPTF_CALLING;
mCallingFunctions.Push(from);
}
}
else if (to->mType == DT_TYPE_FUNCTION)
{
if (!(from->mOptFlags & OPTF_CALLING))
{
from->mOptFlags |= OPTF_CALLING;
mCallingFunctions.Push(from);
}
}
else if (to->mType == DT_TYPE_POINTER && to->mBase->mType == DT_TYPE_FUNCTION)
{
if (!(from->mOptFlags & OPTF_CALLING))
{
from->mOptFlags |= OPTF_CALLING;
mCallingFunctions.Push(from);
}
}
}
}
void GlobalOptimizer::RegisterProc(Declaration* to)
{
if (to->mType == DT_CONST_FUNCTION)
{
if (to->mBase->mFlags & DTF_VIRTUAL)
{
}
else if (!(to->mOptFlags & OPTF_FUNC_VARIABLE))
{
to->mOptFlags |= OPTF_FUNC_VARIABLE;
mVariableFunctions.Push(to);
}
}
}
static const uint32 ANAFL_LHS = (1U << 0);
static const uint32 ANAFL_RHS = (1U << 1);
Declaration* GlobalOptimizer::Analyze(Expression* exp, Declaration* procDec, uint32 flags)
{
Declaration* ldec, * rdec;
switch (exp->mType)
{
case EX_ERROR:
case EX_VOID:
break;
case EX_CONSTANT:
if (exp->mDecValue->mType == DT_CONST_FUNCTION)
{
AnalyzeProcedure(exp->mDecValue->mValue, exp->mDecValue);
}
else if (exp->mDecValue->mType == DT_CONST_STRUCT)
{
AnalyzeInit(exp->mDecValue->mParams);
}
else if (exp->mDecValue->mType == DT_CONST_POINTER)
{
ldec = Analyze(exp->mDecValue->mValue, procDec, ANAFL_LHS | ANAFL_RHS);
RegisterProc(ldec);
}
else if (exp->mDecValue->mType == DT_CONST_ADDRESS)
{
}
else if (exp->mDecValue->mType == DT_CONST_ASSEMBLER)
{
AnalyzeAssembler(exp->mDecValue->mValue, procDec);
}
return exp->mDecValue;
case EX_VARIABLE:
if ((exp->mDecValue->mFlags & DTF_STATIC) || (exp->mDecValue->mFlags & DTF_GLOBAL))
{
Declaration* type = exp->mDecValue->mBase;
while (type->mType == DT_TYPE_ARRAY)
type = type->mBase;
AnalyzeGlobalVariable(exp->mDecValue);
}
else
{
if (flags & ANAFL_RHS)
exp->mDecValue->mOptFlags |= OPTF_VAR_USED;
if (flags & ANAFL_LHS)
exp->mDecValue->mOptFlags |= OPTF_VAR_ADDRESS;
}
return exp->mDecValue;
case EX_INITIALIZATION:
case EX_ASSIGNMENT:
ldec = Analyze(exp->mLeft, procDec, ANAFL_LHS | flags);
rdec = Analyze(exp->mRight, procDec, ANAFL_RHS);
RegisterProc(rdec);
return ldec;
case EX_BINARY:
ldec = Analyze(exp->mLeft, procDec, flags);
rdec = Analyze(exp->mRight, procDec, flags);
return ldec;
case EX_RELATIONAL:
ldec = Analyze(exp->mLeft, procDec, flags);
rdec = Analyze(exp->mRight, procDec, flags);
return TheBoolTypeDeclaration;
case EX_PREINCDEC:
return Analyze(exp->mLeft, procDec, ANAFL_LHS | ANAFL_RHS);
case EX_PREFIX:
if (exp->mToken == TK_BINARY_AND)
ldec = Analyze(exp->mLeft, procDec, ANAFL_LHS | ANAFL_RHS);
else if (exp->mToken == TK_MUL)
{
ldec = Analyze(exp->mLeft, procDec, ANAFL_RHS);
return exp->mDecType;
}
else
return Analyze(exp->mLeft, procDec, flags);
break;
case EX_POSTFIX:
break;
case EX_POSTINCDEC:
return Analyze(exp->mLeft, procDec, ANAFL_LHS | ANAFL_RHS);
case EX_INDEX:
ldec = Analyze(exp->mLeft, procDec, ANAFL_RHS);
if (ldec->mType == DT_VARIABLE || ldec->mType == DT_ARGUMENT)
ldec = ldec->mBase;
rdec = Analyze(exp->mRight, procDec, ANAFL_RHS);
if (ldec->mBase)
return ldec->mBase;
break;
case EX_QUALIFY:
Analyze(exp->mLeft, procDec, flags);
return exp->mDecValue->mBase;
case EX_DISPATCH:
Analyze(exp->mLeft, procDec, flags);
break;
case EX_VCALL:
exp->mType = EX_CALL;
exp->mLeft->mDecValue = exp->mLeft->mDecValue->mVTable;
// intentional fall through
case EX_CALL:
case EX_INLINE:
if (exp->mLeft->mType == EX_CONSTANT)
{
if (flags & ANAFL_RHS)
exp->mLeft->mDecValue->mOptFlags |= OPTF_VAR_USED;
if (flags & ANAFL_LHS)
exp->mLeft->mDecValue->mOptFlags |= OPTF_VAR_ADDRESS;
}
ldec = Analyze(exp->mLeft, procDec, ANAFL_RHS);
if ((ldec->mFlags & DTF_INTRINSIC) && !ldec->mValue)
{
}
else
{
RegisterCall(procDec, ldec);
}
if (exp->mRight)
{
// Check for struct to struct forwarding
Expression* rex = exp->mRight;
if (rex)
{
Expression* prex = exp;
while (rex && rex->mType == EX_LIST)
{
rex->mLeft = rex->mLeft->ConstantFold(mErrors, nullptr);
prex = rex;
rex = rex->mRight;
}
if (rex)
prex->mRight = rex->ConstantFold(mErrors, nullptr);
rex = exp->mRight;
}
Declaration* pdec = ldec->mBase->mParams;
while (rex)
{
Expression *& pex(rex->mType == EX_LIST ? rex->mLeft : rex);
if (pdec)
{
if ((pdec->mFlags & DTF_FPARAM_UNUSED) && !pex->HasSideEffects() && (pex->mType != EX_CONSTANT || !pex->mDecValue->IsNullConst()))
{
if (pdec->mBase->IsSimpleType())
{
pex = new Expression(pex->mLocation, EX_CONSTANT);
switch (pdec->mBase->mType)
{
case DT_TYPE_INTEGER:
case DT_TYPE_ENUM:
case DT_TYPE_BOOL:
pex->mDecValue = TheZeroIntegerConstDeclaration;
break;
case DT_TYPE_FLOAT:
pex->mDecValue = TheZeroFloatConstDeclaration;
break;
case DT_TYPE_POINTER:
case DT_TYPE_FUNCTION:
pex->mDecValue = TheNullptrConstDeclaration;
break;
}
pex->mDecType = pdec->mBase;
}
}
if (!(pdec->mFlags & DTF_FPARAM_UNUSED) && !(pdec->mOptFlags & OPTF_VAR_NOCONST))
{
if (pex->mType == EX_CONSTANT && pdec->mBase->IsSimpleType())
{
if (pdec->mOptFlags & OPTF_VAR_CONST)
{
if (!pex->mDecValue->IsSameValue(pdec->mValue->mDecValue))
{
pdec->mOptFlags |= OPTF_VAR_NOCONST;
pdec->mOptFlags &= ~OPTF_VAR_CONST;
}
}
else
{
pdec->mValue = pex;
pdec->mOptFlags |= OPTF_VAR_CONST;
}
}
else
{
pdec->mOptFlags |= OPTF_VAR_NOCONST;
pdec->mOptFlags &= ~OPTF_VAR_CONST;
}
}
if (pdec->mBase->mType == DT_TYPE_STRUCT && pdec->mBase->mCopyConstructor)
{
if (pdec->mBase->mMoveConstructor)
{
AnalyzeProcedure(pdec->mBase->mMoveConstructor->mValue, pdec->mBase->mMoveConstructor);
RegisterCall(procDec, pdec->mBase->mMoveConstructor);
}
AnalyzeProcedure(pdec->mBase->mCopyConstructor->mValue, pdec->mBase->mCopyConstructor);
RegisterCall(procDec, pdec->mBase->mCopyConstructor);
}
}
if (pdec && (pdec->mFlags & DTF_FPARAM_UNUSED))
RegisterProc(Analyze(pex, procDec, 0));
else if (pdec && pdec->mBase->IsReference())
RegisterProc(Analyze(pex, procDec, ANAFL_LHS | ANAFL_RHS));
else
RegisterProc(Analyze(pex, procDec, ANAFL_RHS));
if (pdec)
pdec = pdec->mNext;
if (rex->mType == EX_LIST)
rex = rex->mRight;
else
rex = nullptr;
}
}
break;
case EX_LIST:
case EX_COMMA:
{
RegisterProc(Analyze(exp->mLeft, procDec, 0));
Declaration* dec = Analyze(exp->mRight, procDec, flags);
RegisterProc(dec);
return dec;
}
case EX_RETURN:
if (exp->mLeft)
{
exp->mLeft = exp->mLeft->ConstantFold(mErrors, nullptr);
if (procDec->mOptFlags & OPTF_SINGLE_RETURN)
{
procDec->mOptFlags &= ~OPTF_SINGLE_RETURN;
procDec->mOptFlags |= OPTF_MULTI_RETURN;
}
else if (!(procDec->mOptFlags & OPTF_MULTI_RETURN))
{
procDec->mOptFlags |= OPTF_SINGLE_RETURN;
procDec->mReturn = exp;
}
if (procDec->mBase->mBase->IsReference())
RegisterProc(Analyze(exp->mLeft, procDec, ANAFL_LHS | ANAFL_RHS));
else
RegisterProc(Analyze(exp->mLeft, procDec, ANAFL_RHS));
if (procDec->mBase->mBase && procDec->mBase->mBase->mType == DT_TYPE_STRUCT && procDec->mBase->mBase->mCopyConstructor)
{
if (procDec->mBase->mBase->mMoveConstructor)
{
AnalyzeProcedure(procDec->mBase->mBase->mMoveConstructor->mValue, procDec->mBase->mBase->mMoveConstructor);
RegisterCall(procDec, procDec->mBase->mBase->mMoveConstructor);
}
AnalyzeProcedure(procDec->mBase->mBase->mCopyConstructor->mValue, procDec->mBase->mBase->mCopyConstructor);
RegisterCall(procDec, procDec->mBase->mBase->mCopyConstructor);
}
}
break;
case EX_SEQUENCE:
do
{
if (exp->mType == EX_SEQUENCE)
{
if (exp->mLeft)
ldec = Analyze(exp->mLeft, procDec, 0);
exp = exp->mRight;
}
else
return Analyze(exp, procDec, 0);
} while (exp);
break;
case EX_SCOPE:
Analyze(exp->mLeft, procDec, 0);
break;
case EX_CONSTRUCT:
if (exp->mLeft->mLeft)
Analyze(exp->mLeft->mLeft, procDec, 0);
if (exp->mLeft->mRight)
Analyze(exp->mLeft->mRight, procDec, 0);
if (exp->mRight)
return Analyze(exp->mRight, procDec, ANAFL_RHS);
break;
case EX_CLEANUP:
Analyze(exp->mRight, procDec, 0);
return Analyze(exp->mLeft, procDec, flags);
case EX_WHILE:
ldec = Analyze(exp->mLeft, procDec, ANAFL_RHS);
rdec = Analyze(exp->mRight, procDec, 0);
break;
case EX_IF:
ldec = Analyze(exp->mLeft, procDec, ANAFL_RHS);
rdec = Analyze(exp->mRight->mLeft, procDec, 0);
if (exp->mRight->mRight)
rdec = Analyze(exp->mRight->mRight, procDec, 0);
break;
case EX_ELSE:
break;
case EX_FOR:
if (exp->mLeft->mRight)
ldec = Analyze(exp->mLeft->mRight, procDec, 0);
if (exp->mLeft->mLeft->mLeft)
ldec = Analyze(exp->mLeft->mLeft->mLeft, procDec, ANAFL_RHS);
rdec = Analyze(exp->mRight, procDec, 0);
if (exp->mLeft->mLeft->mRight)
ldec = Analyze(exp->mLeft->mLeft->mRight, procDec, 0);
break;
case EX_DO:
ldec = Analyze(exp->mLeft, procDec, 0);
rdec = Analyze(exp->mRight, procDec, ANAFL_RHS);
break;
case EX_BREAK:
case EX_CONTINUE:
case EX_ASSUME:
break;
case EX_TYPE:
break;
case EX_TYPECAST:
return Analyze(exp->mLeft, procDec, ANAFL_RHS);
break;
case EX_LOGICAL_AND:
ldec = Analyze(exp->mLeft, procDec, ANAFL_RHS);
rdec = Analyze(exp->mRight, procDec, ANAFL_RHS);
break;
case EX_LOGICAL_OR:
ldec = Analyze(exp->mLeft, procDec, ANAFL_RHS);
rdec = Analyze(exp->mRight, procDec, ANAFL_RHS);
break;
case EX_LOGICAL_NOT:
ldec = Analyze(exp->mLeft, procDec, ANAFL_RHS);
break;
case EX_ASSEMBLER:
AnalyzeAssembler(exp, procDec);
break;
case EX_UNDEFINED:
break;
case EX_SWITCH:
ldec = Analyze(exp->mLeft, procDec, ANAFL_RHS);
exp = exp->mRight;
while (exp)
{
if (exp->mLeft->mRight)
rdec = Analyze(exp->mLeft->mRight, procDec, 0);
exp = exp->mRight;
}
break;
case EX_CASE:
break;
case EX_DEFAULT:
break;
case EX_CONDITIONAL:
ldec = Analyze(exp->mLeft, procDec, ANAFL_RHS);
RegisterProc(Analyze(exp->mRight->mLeft, procDec, flags));
RegisterProc(Analyze(exp->mRight->mRight, procDec, flags));
break;
}
return TheVoidTypeDeclaration;
}

43
oscar64/GlobalOptimizer.h Normal file
View File

@ -0,0 +1,43 @@
#pragma once
#include "Declaration.h"
#include "Linker.h"
#include "CompilerTypes.h"
class GlobalOptimizer
{
public:
GlobalOptimizer(Errors* errors, Linker* linker);
~GlobalOptimizer(void);
void Reset(void);
bool Optimize(void);
void AnalyzeProcedure(Expression* exp, Declaration* dec);
void AnalyzeAssembler(Expression* exp, Declaration* dec);
void AnalyzeGlobalVariable(Declaration* dec);
uint64 mCompilerOptions;
protected:
Errors* mErrors;
Linker* mLinker;
ExpandingArray<Declaration*> mCalledFunctions, mCallingFunctions, mVariableFunctions, mFunctions;
ExpandingArray<Declaration*> mGlobalVariables;
void AnalyzeInit(Declaration* mdec);
Declaration* Analyze(Expression* exp, Declaration* procDec, uint32 flags);
void RegisterCall(Declaration* from, Declaration* to);
void RegisterProc(Declaration* to);
void RemoveValueReturn(Expression* exp);
bool CheckConstReturns(Expression*& exp);
bool CheckUnusedLocals(Expression*& exp);
void UndoParamReference(Expression* exp, Declaration* param);
bool ReplaceParamConst(Expression* exp, Declaration* param);
void PropagateCommas(Expression*& exp);
void PropagateParamCommas(Expression *& fexp, Expression*& exp);
};

View File

@ -45,9 +45,24 @@ const Ident* Ident::Unique(const char* str)
}
const Ident* Ident::PreMangle(const char* str) const
{
char buffer[200];
strcpy_s(buffer, str);
strcat_s(buffer, mString);
return Unique(buffer);
}
const Ident* Ident::Unique(const char* str, int id)
{
char buffer[200];
sprintf_s(buffer, "%s#%d", str, id);
return Unique(buffer);
}
const Ident* Ident::Mangle(const char* str) const
{
char buffer[100];
char buffer[200];
strcpy_s(buffer, mString);
strcat_s(buffer, str);
return Unique(buffer);

View File

@ -9,7 +9,9 @@ public:
unsigned int mHash;
static const Ident* Unique(const char* str);
static const Ident* Unique(const char* str, int id);
const Ident* Mangle(const char* str) const;
const Ident* PreMangle(const char* str) const;
protected:
Ident(const char* str, unsigned int hash);
};

File diff suppressed because it is too large Load Diff

View File

@ -24,6 +24,8 @@ enum InterCode
IC_LEA,
IC_COPY,
IC_STRCPY,
IC_MALLOC,
IC_FREE,
IC_TYPECAST,
IC_CONSTANT,
IC_BRANCH,
@ -38,6 +40,7 @@ enum InterCode
IC_ASSEMBLER,
IC_JUMPF,
IC_SELECT,
IC_DISPATCH,
IC_UNREACHABLE
};
@ -57,16 +60,16 @@ extern int InterTypeSize[];
enum InterMemory
{
IM_NONE,
IM_PARAM,
IM_PARAM, // Memory used to access parameters on stack
IM_LOCAL,
IM_GLOBAL,
IM_FRAME,
IM_FRAME, // Memory used to pass parameters on stack
IM_PROCEDURE,
IM_INDIRECT,
IM_TEMPORARY,
IM_ABSOLUTE,
IM_FPARAM,
IM_FFRAME,
IM_FPARAM, // Memory used to access parameters in zp
IM_FFRAME, // Memory used to pass parameters in zp
};
enum InterOperator
@ -145,8 +148,10 @@ public:
~IntegerValueRange(void);
void Reset(void);
void Restart(void);
int64 mMinValue, mMaxValue;
int mMinExpanded, mMaxExpanded;
enum State
{
@ -158,8 +163,11 @@ public:
bool Same(const IntegerValueRange& range) const;
bool Merge(const IntegerValueRange& range, bool head, bool initial);
void Expand(const IntegerValueRange& range);
void Union(const IntegerValueRange& range);
void Limit(const IntegerValueRange& range);
void MergeUnknown(const IntegerValueRange& range);
void SetLimit(int64 minValue, int64 maxValue);
bool IsConstant(void) const;
@ -240,7 +248,7 @@ class InterVariable
{
public:
bool mUsed, mAliased, mTemp;
int mIndex, mSize, mOffset, mAddr, mTempIndex;
int mIndex, mSize, mOffset, mTempIndex, mByteIndex;
int mNumReferences;
const Ident * mIdent;
LinkerObject * mLinkerObject;
@ -260,7 +268,7 @@ public:
bool mFinal;
int64 mIntConst;
double mFloatConst;
int mVarIndex, mOperandSize, mStride;
int mVarIndex, mOperandSize, mStride, mRestricted;
LinkerObject * mLinkerObject;
InterMemory mMemory;
IntegerValueRange mRange;
@ -280,7 +288,7 @@ public:
bool IsNotUByte(void) const;
void Disassemble(FILE* file);
void Disassemble(FILE* file, InterCodeProcedure* proc);
};
class InterInstruction
@ -294,7 +302,7 @@ public:
InterOperator mOperator;
int mNumOperands;
bool mInUse, mInvariant, mVolatile, mExpensive, mSingleAssignment, mNoSideEffects, mConstExpr;
bool mInUse, mInvariant, mVolatile, mExpensive, mSingleAssignment, mNoSideEffects, mConstExpr, mRemove;
InterInstruction(const Location& loc, InterCode code);
@ -313,10 +321,12 @@ public:
void FilterTempUsage(NumberSet& requiredTemps, NumberSet& providedTemps);
void FilterVarsUsage(const GrowingVariableArray& localVars, NumberSet& requiredVars, NumberSet& providedVars, const GrowingVariableArray& params, NumberSet& requiredParams, NumberSet& providedParams, InterMemory paramMemory);
void FilterStaticVarsUsage(const GrowingVariableArray& staticVars, NumberSet& requiredVars, NumberSet& providedVars);
void FilterStaticVarsByteUsage(const GrowingVariableArray& staticVars, NumberSet& requiredVars, NumberSet& providedVars);
bool RemoveUnusedResultInstructions(InterInstruction* pre, NumberSet& requiredTemps);
bool RemoveUnusedStoreInstructions(const GrowingVariableArray& localVars, NumberSet& requiredVars, const GrowingVariableArray& params, NumberSet& requiredParams, InterMemory paramMemory);
bool RemoveUnusedStaticStoreInstructions(InterCodeBasicBlock * block, const GrowingVariableArray& staticVars, NumberSet& requiredVars, GrowingInstructionPtrArray& storeIns);
bool RemoveUnusedStaticStoreByteInstructions(InterCodeBasicBlock* block, const GrowingVariableArray& staticVars, NumberSet& requiredVars);
void PerformValueForwarding(GrowingInstructionPtrArray& tvalue, FastNumberSet& tvalid);
void BuildCallerSaveTempSet(NumberSet& requiredTemps, NumberSet& callerSaveTemps);
@ -338,7 +348,9 @@ public:
bool ConstantFolding(void);
bool ConstantFoldingRelationRange(void);
void Disassemble(FILE* file);
void UnionRanges(InterInstruction* ins);
void Disassemble(FILE* file, InterCodeProcedure * proc);
};
class InterCodeBasicBlock
@ -356,6 +368,7 @@ public:
NumberSet mEntryRequiredTemps, mEntryProvidedTemps, mEntryPotentialTemps;
NumberSet mExitRequiredTemps, mExitProvidedTemps, mExitPotentialTemps;
NumberSet mEntryConstTemp, mExitConstTemp;
NumberSet mNewRequiredTemps;
NumberSet mLocalRequiredVars, mLocalProvidedVars;
NumberSet mEntryRequiredVars, mEntryProvidedVars;
@ -376,7 +389,7 @@ public:
GrowingArray<int64> mMemoryValueSize, mEntryMemoryValueSize;
GrowingArray<InterCodeBasicBlock*> mEntryBlocks, mLoopPathBlocks;
ExpandingArray<InterCodeBasicBlock*> mEntryBlocks, mLoopPathBlocks;
GrowingInstructionPtrArray mMergeTValues, mMergeAValues;
ValueSet mMergeValues;
@ -417,17 +430,22 @@ public:
void BuildCallerSaveTempSet(NumberSet& callerSaveTemps);
void BuildConstTempSets(void);
bool PropagateConstOperationsUp(void);
bool RemoveUnusedLocalStoreInstructions(void);
void BuildLocalVariableSets(const GrowingVariableArray& localVars, const GrowingVariableArray& params, InterMemory paramMemory);
void BuildGlobalProvidedVariableSet(const GrowingVariableArray& localVars, NumberSet fromProvidedVars, const GrowingVariableArray& params, NumberSet fromProvidedParams, InterMemory paramMemory);
bool BuildGlobalRequiredVariableSet(const GrowingVariableArray& localVars, NumberSet& fromRequiredVars, const GrowingVariableArray& params, NumberSet& fromRequiredParams, InterMemory paramMemory);
bool RemoveUnusedStoreInstructions(const GrowingVariableArray& localVars, const GrowingVariableArray& params, InterMemory paramMemory);
bool RemoveUnusedIndirectStoreInstructions(void);
void BuildStaticVariableSet(const GrowingVariableArray& staticVars);
void BuildGlobalProvidedStaticVariableSet(const GrowingVariableArray& staticVars, NumberSet fromProvidedVars);
bool BuildGlobalRequiredStaticVariableSet(const GrowingVariableArray& staticVars, NumberSet& fromRequiredVars);
bool RemoveUnusedStaticStoreInstructions(const GrowingVariableArray& staticVars);
void BuildStaticVariableByteSet(const GrowingVariableArray& staticVars, int bsize);
bool RemoveUnusedStaticStoreByteInstructions(const GrowingVariableArray& staticVars, int bsize);
bool CheckSingleBlockLimitedLoop(InterCodeBasicBlock*& pblock, int64 & nloop);
void RestartLocalIntegerRangeSets(int num, const GrowingVariableArray& localVars, const GrowingVariableArray& paramVars);
@ -435,6 +453,9 @@ public:
void UpdateLocalIntegerRangeSets(const GrowingVariableArray& localVars, const GrowingVariableArray& paramVars);
bool BuildGlobalIntegerRangeSets(bool initial, const GrowingVariableArray& localVars, const GrowingVariableArray& paramVars);
void SimplifyIntegerRangeRelops(void);
void MarkIntegerRangeBoundUp(int temp, int64 value, GrowingIntegerValueRangeArray& range);
void UnionIntegerRanges(const InterCodeBasicBlock* block);
void PruneUnusedIntegerRangeSets(void);
bool CombineIndirectAddressing(void);
@ -449,6 +470,7 @@ public:
void LocalRenameRegister(const GrowingIntArray& renameTable, int& num);
void BuildGlobalRenameRegisterTable(const GrowingIntArray& renameTable, GrowingIntArray& globalRenameTable);
void GlobalRenameRegister(const GrowingIntArray& renameTable, GrowingTypeArray& temporaries);
void RenameValueRanges(const GrowingIntArray& renameTable, int numTemps);
void CheckValueUsage(InterInstruction * ins, const GrowingInstructionPtrArray& tvalue, const GrowingVariableArray& staticVars, FastNumberSet& fsingle);
void PerformTempForwarding(const TempForwardingTable& forwardingTable, bool reverse, bool checkloops);
@ -482,13 +504,17 @@ public:
void MapVariables(GrowingVariableArray& globalVars, GrowingVariableArray& localVars);
void CollectOuterFrame(int level, int& size, bool& inner, bool& inlineAssembler, bool& byteCodeCall);
bool RecheckOuterFrame(void);
bool IsLeafProcedure(void);
bool PreventsCallerStaticStack(void);
bool ForwardDiamondMovedTemp(void);
bool ForwardLoopMovedTemp(void);
bool MoveTrainCrossBlock(void);
bool HoistCommonConditionalPath(void);
bool IsDirectDominatorBlock(InterCodeBasicBlock* block);
void MarkRelevantStatics(void);
void RemoveNonRelevantStatics(void);
@ -497,6 +523,7 @@ public:
bool IsTempReferencedOnPath(int temp, int at) const;
bool DestroyingMem(const InterInstruction* lins, const InterInstruction* sins) const;
bool DestroyingMem(InterCodeBasicBlock* block, InterInstruction* lins, int from, int to) const;
bool CollidingMem(const InterInstruction* ins1, const InterInstruction* ins2) const;
bool CollidingMem(const InterOperand& op, InterType type, const InterInstruction* ins) const;
bool CollidingMem(const InterOperand& op1, InterType type1, const InterOperand& op2, InterType type2) const;
@ -523,22 +550,33 @@ public:
InterInstruction* FindTempOrigin(int temp) const;
bool CheapInlining(int & numTemps);
void CheckFinalLocal(void);
void CheckFinal(void);
void CheckBlocks(void);
bool IsConstExitTemp(int temp) const;
bool CommonTailCodeMerge(void);
bool SplitSingleBranchUseConst(void);
void PeepholeOptimization(const GrowingVariableArray& staticVars);
bool PeepholeReplaceOptimization(const GrowingVariableArray& staticVars);
bool MoveLoopHeadCheckToTail(void);
void SingleBlockLoopOptimisation(const NumberSet& aliasedParams, const GrowingVariableArray& staticVars);
void SingleBlockLoopUnrolling(void);
bool SingleBlockLoopPointerSplit(int& spareTemps);
bool SingleBlockLoopPointerToByte(int& spareTemps);
bool CollectLoopBody(InterCodeBasicBlock* head, GrowingArray<InterCodeBasicBlock*> & body);
void CollectLoopPath(const GrowingArray<InterCodeBasicBlock*>& body, GrowingArray<InterCodeBasicBlock*>& path);
bool CollectLoopBody(InterCodeBasicBlock* head, ExpandingArray<InterCodeBasicBlock*> & body);
bool CollectLoopBodyRecursive(InterCodeBasicBlock* head, ExpandingArray<InterCodeBasicBlock*>& body);
void CollectLoopPath(const ExpandingArray<InterCodeBasicBlock*>& body, ExpandingArray<InterCodeBasicBlock*>& path);
void InnerLoopOptimization(const NumberSet& aliasedParams);
void PushMoveOutOfLoop(void);
void PropagateMemoryAliasingInfo(const GrowingInstructionPtrArray& tvalue);
void RemoveUnusedMallocs(void);
bool CollectSingleHeadLoopBody(InterCodeBasicBlock* head, InterCodeBasicBlock* tail, GrowingArray<InterCodeBasicBlock*>& body);
bool SingleTailLoopOptimization(const NumberSet& aliasedParams, const GrowingVariableArray& staticVars);
@ -559,6 +597,7 @@ public:
bool DropUnreachable(void);
bool CheckStaticStack(void);
void ApplyStaticStack(InterOperand& iop, const GrowingVariableArray& localVars);
void CollectStaticStack(LinkerObject * lobj, const GrowingVariableArray& localVars);
void PromoteStaticStackParams(LinkerObject* paramlobj);
@ -566,6 +605,9 @@ public:
void WarnUsedUndefinedVariables(void);
void CheckValueReturn(void);
void CheckNullptrDereference(void);
void CollectGlobalReferences(NumberSet& referencedGlobals, NumberSet& modifiedGlobals, bool & storesIndirect, bool & loadsIndirect, bool & globalsChecked);
};
@ -583,10 +625,13 @@ public:
GrowingInterCodeBasicBlockPtrArray mBlocks;
GrowingTypeArray mTemporaries;
GrowingIntArray mTempOffset, mTempSizes;
int mTempSize, mCommonFrameSize, mCallerSavedTemps, mFreeCallerSavedTemps, mFastCallBase;
int mTempSize, mCommonFrameSize, mCallerSavedTemps, mFreeCallerSavedTemps, mFastCallBase, mNumRestricted;
bool mLeafProcedure, mNativeProcedure, mCallsFunctionPointer, mHasDynamicStack, mHasInlineAssembler, mCallsByteCode, mFastCallProcedure;
bool mInterrupt, mHardwareInterrupt, mCompiled, mInterruptCalled, mValueReturn, mFramePointer, mDynamicStack;
bool mInterrupt, mHardwareInterrupt, mCompiled, mInterruptCalled, mValueReturn, mFramePointer, mDynamicStack, mAssembled;
bool mDispatchedCall;
bool mCheckUnreachable;
GrowingInterCodeProcedurePtrArray mCalledFunctions;
bool mCheapInline;
InterCodeModule * mModule;
int mID;
@ -600,13 +645,17 @@ public:
LinkerObject * mLinkerObject, * mSaveTempsLinkerObject;
Declaration * mDeclaration;
InterType mReturnType;
uint64 mCompilerOptions;
bool mLoadsIndirect, mStoresIndirect, mGlobalsChecked;
NumberSet mReferencedGlobals, mModifiedGlobals;
InterCodeProcedure(InterCodeModule * module, const Location & location, const Ident * ident, LinkerObject* linkerObject);
~InterCodeProcedure(void);
int AddTemporary(InterType type);
int AddRestricted(void);
void Close(void);
@ -620,6 +669,9 @@ public:
void MapCallerSavedTemps(void);
bool ReferencesGlobal(int varindex);
bool ModifiesGlobal(int varindex);
void MapVariables(void);
void ReduceTemporaries(void);
void Disassemble(FILE* file);
@ -636,6 +688,8 @@ protected:
void BuildLoopPrefix(void);
void SingleAssignmentForwarding(void);
void RemoveUnusedStoreInstructions(InterMemory paramMemory);
void RemoveUnusedPartialStoreInstructions(void);
void RemoveUnusedLocalStoreInstructions(void);
void MergeCommonPathInstructions(void);
void PushSinglePathResultInstructions(void);
void CollectVariables(InterMemory paramMemory);
@ -651,10 +705,13 @@ protected:
void RebuildIntegerRangeSet(void);
void CombineIndirectAddressing(void);
void SingleTailLoopOptimization(InterMemory paramMemory);
void HoistCommonConditionalPath(void);
void RemoveUnusedMallocs(void);
void MergeBasicBlocks(void);
void CheckUsedDefinedTemps(void);
void WarnUsedUndefinedVariables(void);
void PropagateMemoryAliasingInfo(void);
void PeepholeOptimization(void);

File diff suppressed because it is too large Load Diff

View File

@ -11,16 +11,37 @@ public:
InterCodeGenerator(Errors * errors, Linker * linker);
~InterCodeGenerator(void);
struct DestructStack
{
Expression * mDestruct;
DestructStack* mNext;
};
struct ExValue
{
Declaration* mType;
int mTemp, mReference;
int mBits, mShift;
ExValue(Declaration* type = nullptr, int temp = -1, int reference = 0)
: mType(type), mTemp(temp), mReference(reference)
ExValue(Declaration* type = nullptr, int temp = -1, int reference = 0, int bits = 0, int shift = 0)
: mType(type), mTemp(temp), mReference(reference), mBits(bits), mShift(shift)
{}
};
struct BranchTarget
{
InterCodeBasicBlock* mBlock;
DestructStack* mStack;
BranchTarget(void)
: mBlock(nullptr), mStack(nullptr)
{}
BranchTarget(InterCodeBasicBlock * block, DestructStack * stack)
: mBlock(block), mStack(stack)
{}
};
uint64 mCompilerOptions;
InterCodeProcedure* TranslateProcedure(InterCodeModule* mod, Expression* exp, Declaration * dec);
@ -39,9 +60,11 @@ protected:
InterCodeBasicBlock * mReturn;
int mResult, mDepth, mVarIndex;
bool mConstExpr;
ExValue * mResultExp;
Location * mLocation;
InlineMapper(void)
: mParams(-1), mResult(-1), mDepth(0)
: mParams(-1), mResult(-1), mDepth(0), mResultExp(nullptr)
{}
};
@ -53,13 +76,23 @@ protected:
typedef GrowingArray<SwitchNode> SwitchNodeArray;
void BuildSwitchTree(InterCodeProcedure* proc, Expression* exp, InterCodeBasicBlock* block, ExValue v, const SwitchNodeArray& nodes, int left, int right, InterCodeBasicBlock* dblock);
InterCodeProcedure* mMainInitProc;
InterCodeBasicBlock* mMainInitBlock;
ExValue Dereference(InterCodeProcedure* proc, Expression* exp, InterCodeBasicBlock*& block, ExValue v, int level = 0);
ExValue CoerceType(InterCodeProcedure* proc, Expression* exp, InterCodeBasicBlock*& block, ExValue v, Declaration * type, bool checkTrunc = true);
ExValue TranslateExpression(Declaration * procType, InterCodeProcedure * proc, InterCodeBasicBlock*& block, Expression* exp, InterCodeBasicBlock* breakBlock, InterCodeBasicBlock* continueBlock, InlineMapper * inlineMapper, ExValue * lrexp = nullptr);
void TranslateLogic(Declaration* procType, InterCodeProcedure* proc, InterCodeBasicBlock* block, InterCodeBasicBlock* tblock, InterCodeBasicBlock* fblock, Expression* exp, InlineMapper* inlineMapper);
ExValue TranslateInline(Declaration* procType, InterCodeProcedure* proc, InterCodeBasicBlock*& block, Expression* exp, InterCodeBasicBlock* breakBlock, InterCodeBasicBlock* continueBlock, InlineMapper* inlineMapper, bool inlineConstexpr);
Location MapLocation(Expression * exp, InlineMapper* inlineMapper);
void BuildSwitchTree(InterCodeProcedure* proc, Expression* exp, InterCodeBasicBlock* block, InlineMapper * inlineMapper, ExValue v, const SwitchNodeArray& nodes, int left, int right, int vleft, int vright, InterCodeBasicBlock* dblock);
ExValue ToValue(InterCodeProcedure* proc, Expression* exp, InterCodeBasicBlock*& block, InlineMapper* inlineMapper, ExValue v);
ExValue Dereference(InterCodeProcedure* proc, Expression* exp, InterCodeBasicBlock*& block, InlineMapper* inlineMapper, ExValue v, int level = 0);
ExValue CoerceType(InterCodeProcedure* proc, Expression* exp, InterCodeBasicBlock*& block, InlineMapper* inlineMapper, ExValue v, Declaration * type, bool checkTrunc = true);
ExValue TranslateExpression(Declaration * procType, InterCodeProcedure * proc, InterCodeBasicBlock*& block, Expression* exp, DestructStack*& destack, const BranchTarget & breakBlock, const BranchTarget& continueBlock, InlineMapper * inlineMapper, ExValue * lrexp = nullptr);
void TranslateLogic(Declaration* procType, InterCodeProcedure* proc, InterCodeBasicBlock* block, InterCodeBasicBlock* tblock, InterCodeBasicBlock* fblock, Expression* exp, DestructStack*& destack, InlineMapper* inlineMapper);
ExValue TranslateInline(Declaration* procType, InterCodeProcedure* proc, InterCodeBasicBlock*& block, Expression* exp, const BranchTarget& breakBlock, const BranchTarget& continueBlock, InlineMapper* inlineMapper, bool inlineConstexpr, ExValue* lrexp);
void CopyStruct(InterCodeProcedure* proc, Expression* exp, InterCodeBasicBlock*& block, ExValue vl, ExValue vr, InlineMapper* inlineMapper, bool moving);
void CopyStructSimple(InterCodeProcedure* proc, Expression* exp, InterCodeBasicBlock * block, InlineMapper* inlineMapper, ExValue vl, ExValue vr);
void StoreValue(InterCodeProcedure* proc, Expression* exp, InterCodeBasicBlock*& block, InlineMapper* inlineMapper, ExValue vl, ExValue vr);
void UnwindDestructStack(Declaration* procType, InterCodeProcedure* proc, InterCodeBasicBlock*& block, DestructStack* stack, DestructStack * bottom, InlineMapper* inlineMapper);
void BuildInitializer(InterCodeModule* mod, uint8 * dp, int offset, Declaration* data, InterVariable * variable);
};

View File

@ -4,7 +4,7 @@
#include "CompilerTypes.h"
LinkerRegion::LinkerRegion(void)
: mSections(nullptr), mFreeChunks(FreeChunk{ 0, 0 } )
: mSections(nullptr), mFreeChunks(FreeChunk{ 0, 0 } ), mLastObject(nullptr)
{}
LinkerSection::LinkerSection(void)
@ -28,6 +28,21 @@ void LinkerSection::AddObject(LinkerObject* obj)
obj->mSection = this;
}
bool LinkerReference::operator==(const LinkerReference& ref)
{
return
mFlags == ref.mFlags &&
mOffset == ref.mOffset &&
mRefOffset == ref.mRefOffset &&
mObject->mMapID == ref.mObject->mMapID &&
mRefObject->mMapID == ref.mRefObject->mMapID;
}
bool LinkerReference::operator!=(const LinkerReference& ref)
{
return !(*this == ref);
}
LinkerObject::LinkerObject(void)
: mReferences(nullptr), mNumTemporaries(0), mSize(0), mAlignment(1), mStackSection(nullptr)
{}
@ -43,12 +58,14 @@ void LinkerObject::AddReference(const LinkerReference& ref)
mReferences.Push(nref);
}
LinkerReference* LinkerObject::FindReference(int offset)
LinkerReference* LinkerObject::FindReference(int64 offset)
{
for (int i = 0; i < mReferences.Size(); i++)
{
if (mReferences[i]->mOffset == offset)
return mReferences[i];
else if ((mReferences[i]->mFlags & LREF_LOWBYTE) && (mReferences[i]->mFlags & LREF_HIGHBYTE) && mReferences[i]->mOffset + 1 == offset)
return mReferences[i];
}
return nullptr;
@ -239,11 +256,61 @@ LinkerObject* Linker::FindObjectByAddr(int addr)
return nullptr;
}
LinkerObject* Linker::FindObjectByAddr(int bank, int addr)
{
for (int i = 0; i < mObjects.Size(); i++)
{
LinkerObject* lobj = mObjects[i];
if (lobj->mFlags & LOBJF_PLACED)
{
if (lobj->mRegion && ((1ULL << bank) & lobj->mRegion->mCartridgeBanks))
{
if (addr >= lobj->mAddress && addr < lobj->mAddress + lobj->mSize)
return lobj;
}
}
}
return FindObjectByAddr(addr);
}
LinkerObject* Linker::FindSame(LinkerObject* obj)
{
for (int i = 0; i < mObjects.Size(); i++)
{
LinkerObject* lobj = mObjects[i];
if (lobj != obj && obj->IsSameConst(lobj))
return lobj;
}
return nullptr;
}
bool LinkerObject::IsSameConst(const LinkerObject* obj) const
{
if ((mFlags & LOBJF_CONST) && mFlags == obj->mFlags &&
mSection == obj->mSection && mSize == obj->mSize && mAlignment == obj->mAlignment &&
mReferences.Size() == obj->mReferences.Size())
{
for (int i = 0; i < mSize; i++)
if (mData[i] != obj->mData[i])
return false;
for (int i = 0; i < mReferences.Size(); i++)
if (mReferences[i] != obj->mReferences[i])
return false;
return true;
}
return false;
}
LinkerObject * Linker::AddObject(const Location& location, const Ident* ident, LinkerSection * section, LinkerObjectType type, int alignment)
{
LinkerObject* obj = new LinkerObject;
obj->mLocation = location;
obj->mID = mObjects.Size();
obj->mID = obj->mMapID = mObjects.Size();
obj->mType = type;
obj->mData = nullptr;
obj->mSize = 0;
@ -258,6 +325,70 @@ LinkerObject * Linker::AddObject(const Location& location, const Ident* ident, L
return obj;
}
void Linker::CombineSameConst(void)
{
bool changed = true;
while (changed)
{
changed = false;
for (int i = 0; i < mObjects.Size(); i++)
{
LinkerObject* dobj(mObjects[i]);
while (dobj->mMapID != mObjects[dobj->mMapID]->mMapID)
dobj->mMapID = mObjects[dobj->mMapID]->mMapID;
if ((dobj->mFlags & LOBJF_REFERENCED) && (dobj->mFlags & LOBJF_CONST) && dobj->mMapID == dobj->mID)
{
for (int j = i + 1; j < mObjects.Size(); j++)
{
LinkerObject* sobj(mObjects[j]);
if ((sobj->mFlags & LOBJF_REFERENCED) && (sobj->mFlags & LOBJF_CONST) && sobj->mMapID == sobj->mID)
{
if (dobj->mSize == sobj->mSize && dobj->mSection == sobj->mSection && dobj->mReferences.Size() == sobj->mReferences.Size())
{
int i = 0;
while (i < sobj->mSize && sobj->mData[i] == dobj->mData[i])
i++;
if (i == sobj->mSize)
{
i = 0;
while (i < sobj->mReferences.Size() && sobj->mReferences[i] == dobj->mReferences[i])
i++;
if (i == sobj->mReferences.Size())
{
sobj->mMapID = dobj->mMapID;
changed = true;
if (dobj->mIdent && sobj->mIdent)
{
printf("Match %s : %s\n", dobj->mIdent->mString, sobj->mIdent->mString);
}
}
}
}
}
}
}
}
}
for (int i = 0; i < mObjects.Size(); i++)
{
LinkerObject* lobj(mObjects[i]);
if (lobj->mFlags & LOBJF_REFERENCED)
{
if (lobj->mMapID != lobj->mID)
lobj->mFlags &= ~LOBJF_REFERENCED;
else
{
for (int j = 0; j < lobj->mReferences.Size(); j++)
lobj->mReferences[j]->mRefObject = mObjects[lobj->mReferences[j]->mRefObject->mMapID];
}
}
}
}
void Linker::CollectReferences(void)
{
for (int i = 0; i < mObjects.Size(); i++)
@ -282,7 +413,31 @@ void Linker::ReferenceObject(LinkerObject* obj)
}
}
bool LinkerRegion::Allocate(Linker * linker, LinkerObject* lobj)
static bool Forwards(LinkerObject* pobj, LinkerObject* lobj)
{
if (lobj->mAlignment == 1 && pobj && lobj->mType == LOT_NATIVE_CODE && pobj->mType == LOT_NATIVE_CODE)
{
if (pobj->mSize >= 3 && pobj->mData[pobj->mSize - 3] == 0x4c && pobj->mReferences.Size() > 0)
{
int i = 0;
while (i < pobj->mReferences.Size() && pobj->mReferences[i]->mOffset != pobj->mSize - 2)
i++;
if (i < pobj->mReferences.Size() && pobj->mReferences[i]->mRefObject == lobj && pobj->mReferences[i]->mRefOffset == 0)
{
printf("Direct %s -> %s\n", pobj->mIdent->mString, lobj->mIdent->mString);
pobj->mReferences[i]->mFlags = 0;
pobj->mSize -= 3;
return true;
}
}
}
return false;
}
bool LinkerRegion::Allocate(Linker * linker, LinkerObject* lobj, bool merge)
{
int i = 0;
while (i < mFreeChunks.Size())
@ -294,6 +449,13 @@ bool LinkerRegion::Allocate(Linker * linker, LinkerObject* lobj)
;
else if (end <= mFreeChunks[i].mEnd)
{
// Check if directly follows an object that jumps to this new object
if (merge && Forwards(mFreeChunks[i].mLastObject, lobj))
{
start -= 3;
end -= 3;
}
lobj->mFlags |= LOBJF_PLACED;
lobj->mAddress = start;
lobj->mRefAddress = start + mReloc;
@ -304,7 +466,10 @@ bool LinkerRegion::Allocate(Linker * linker, LinkerObject* lobj)
if (end == mFreeChunks[i].mEnd)
mFreeChunks.Remove(i);
else
{
mFreeChunks[i].mStart = end;
mFreeChunks[i].mLastObject = lobj;
}
}
else if (end == mFreeChunks[i].mEnd)
{
@ -312,7 +477,7 @@ bool LinkerRegion::Allocate(Linker * linker, LinkerObject* lobj)
}
else
{
mFreeChunks.Insert(i + 1, FreeChunk{ end, mFreeChunks[i].mEnd } );
mFreeChunks.Insert(i + 1, FreeChunk{ end, mFreeChunks[i].mEnd, lobj } );
mFreeChunks[i].mEnd = start;
}
@ -332,16 +497,27 @@ bool LinkerRegion::Allocate(Linker * linker, LinkerObject* lobj)
if (end <= mEnd)
{
// Check if directly follows an object that jumps to this new object
if (merge && Forwards(mLastObject, lobj))
{
start -= 3;
end -= 3;
mLastObject = nullptr;
}
lobj->mFlags |= LOBJF_PLACED;
lobj->mAddress = start;
lobj->mRefAddress = start + mReloc;
lobj->mRegion = this;
#if 1
if (start != mStart + mUsed)
mFreeChunks.Push( FreeChunk{ mStart + mUsed, start } );
mFreeChunks.Push( FreeChunk{ mStart + mUsed, start, mLastObject } );
#endif
mUsed = end - mStart;
mLastObject = lobj;
return true;
}
@ -407,7 +583,7 @@ void Linker::Link(void)
for (int k = 0; k < lsec->mObjects.Size(); k++)
{
LinkerObject* lobj = lsec->mObjects[k];
if ((lobj->mFlags & LOBJF_REFERENCED) && !(lobj->mFlags & LOBJF_PLACED) && lrgn->Allocate(this, lobj))
if ((lobj->mFlags & LOBJF_REFERENCED) && !(lobj->mFlags & LOBJF_PLACED) && lrgn->Allocate(this, lobj, mCompilerOptions & COPT_OPTIMIZE_MERGE_CALLS))
{
if (lobj->mIdent && lobj->mIdent->mString && (mCompilerOptions & COPT_VERBOSE2))
printf("Placed object <%s> $%04x - $%04x\n", lobj->mIdent->mString, lobj->mAddress, lobj->mAddress + lobj->mSize);
@ -489,8 +665,8 @@ void Linker::Link(void)
if (lsec->mType == LST_HEAP)
{
lsec->mStart = lrgn->mStart + lrgn->mUsed;
lsec->mEnd = lrgn->mEnd;
lsec->mStart = (lrgn->mStart + lrgn->mUsed + 3) & ~3;
lsec->mEnd = lrgn->mEnd & ~3;
if (lsec->mStart + lsec->mSize > lsec->mEnd)
{
@ -592,6 +768,29 @@ void Linker::Link(void)
}
}
}
for (int i = 0; i < mObjects.Size(); i++)
{
LinkerObject* oi = mObjects[i];
if (oi->mSection->mType == LST_DATA && (oi->mFlags & LOBJF_PLACED) && oi->mRegion)
{
for (int j = i + 1; j < mObjects.Size(); j++)
{
LinkerObject* oj = mObjects[j];
if (oj->mSection->mType == LST_DATA && (oj->mFlags & LOBJF_PLACED) && oj->mRegion)
{
if (oj->mAddress < oi->mAddress + oi->mSize && oi->mAddress < oj->mAddress + oj->mSize && (oj->mRegion->mCartridgeBanks & oi->mRegion->mCartridgeBanks))
{
mErrors->Error(oi->mLocation, EERR_OVERLAPPING_DATA_SECTIONS, "Overlapping data section", oi->mIdent);
mErrors->Error(oj->mLocation, EERR_OVERLAPPING_DATA_SECTIONS, "Overlapping data section", oj->mIdent);
}
}
}
}
}
}
}
@ -1084,6 +1283,31 @@ bool Linker::WriteMapFile(const char* filename)
}
}
fprintf(file, "\nobjects by size\n");
ExpandingArray<const LinkerObject*> so;
for (int i = 0; i < mObjects.Size(); i++)
{
LinkerObject* obj = mObjects[i];
if ((obj->mFlags & LOBJF_REFERENCED) && obj->mIdent)
{
int k = so.Size();
so.Push(obj);
while (k > 0 && so[k - 1]->mSize < obj->mSize)
{
so[k] = so[k - 1];
k--;
}
so[k] = obj;
}
}
for (int i = 0; i < so.Size(); i++)
{
const LinkerObject* obj = so[i];
fprintf(file, "%04x (%04x) : %s, %s:%s\n", obj->mAddress, obj->mSize, obj->mIdent->mString, LinkerObjectTypeNames[obj->mType], obj->mSection->mIdent->mString);
}
fclose(file);
return true;

View File

@ -90,11 +90,13 @@ public:
struct FreeChunk
{
int mStart, mEnd;
LinkerObject* mLastObject;
};
GrowingArray<FreeChunk> mFreeChunks;
LinkerObject * mLastObject;
bool Allocate(Linker * linker, LinkerObject* obj);
bool Allocate(Linker * linker, LinkerObject* obj, bool merge);
void PlaceStackSection(LinkerSection* stackSection, LinkerSection* section);
};
@ -110,6 +112,10 @@ public:
LinkerObject* mObject, * mRefObject;
int mOffset, mRefOffset;
uint32 mFlags;
bool operator==(const LinkerReference& ref);
bool operator!=(const LinkerReference& ref);
};
static const uint32 LSECF_PACKED = 0x00000001;
@ -175,7 +181,7 @@ public:
Location mLocation;
const Ident * mIdent;
LinkerObjectType mType;
int mID;
int mID, mMapID;
int mAddress, mRefAddress;
int mSize, mAlignment;
LinkerSection * mSection;
@ -202,13 +208,15 @@ public:
GrowingArray<LinkerReference*> mReferences;
LinkerReference* FindReference(int offset);
LinkerReference* FindReference(int64 offset);
void AddReference(const LinkerReference& ref);
void MoveToSection(LinkerSection* section);
void MarkRelevant(void);
bool IsSameConst(const LinkerObject* obj) const;
};
class LinkerOverlay
@ -237,10 +245,12 @@ public:
LinkerRegion* FindRegionOfSection(LinkerSection* section);
LinkerObject* FindObjectByAddr(int addr);
LinkerObject* FindObjectByAddr(int bank, int addr);
bool IsSectionPlaced(LinkerSection* section);
LinkerObject * AddObject(const Location & location, const Ident* ident, LinkerSection * section, LinkerObjectType type, int alignment = 1);
LinkerObject* FindSame(LinkerObject* obj);
LinkerOverlay* AddOverlay(const Location& location, const Ident* ident, int bank);
@ -280,6 +290,7 @@ public:
void ReferenceObject(LinkerObject* obj);
void CollectReferences(void);
void CombineSameConst(void);
void Link(void);
protected:
NativeCodeDisassembler mNativeDisassembler;

Some files were not shown because too many files have changed in this diff Show More