Merge branch 'drmortalwombat:main' into patch-1
This commit is contained in:
commit
0f539d239c
|
@ -343,12 +343,9 @@ make/oscar64
|
|||
*.int
|
||||
*.bcs
|
||||
*.crt
|
||||
*.crt
|
||||
*.d64
|
||||
**/*.d64
|
||||
*.tlog
|
||||
*.res
|
||||
*.recipe
|
||||
*.exe
|
||||
*.d64
|
||||
*.d64
|
||||
*.dbj
|
||||
|
|
135
README.md
135
README.md
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
#include "opp_part1.h"
|
||||
|
|
@ -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")
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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")
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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++)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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++)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -18,6 +18,10 @@ extern IOCharMap giocharmap;
|
|||
|
||||
void iocharmap(IOCharMap chmap);
|
||||
|
||||
#if defined(__C128__)
|
||||
void dispmode40col(void);
|
||||
void dispmode80col(void);
|
||||
#endif
|
||||
|
||||
int kbhit(void);
|
||||
|
||||
|
|
448
include/crt.c
448
include/crt.c
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -30,6 +30,9 @@ bool isfinite(float f);
|
|||
#pragma intrinsic(floor)
|
||||
#pragma intrinsic(ceil)
|
||||
|
||||
#pragma intrinsic(sin)
|
||||
#pragma intrinsic(cos)
|
||||
|
||||
#pragma compile("math.c")
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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++];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -183,7 +183,7 @@ void putchar(char c)
|
|||
{
|
||||
__asm {
|
||||
lda c
|
||||
jmp putpch
|
||||
jsr putpch
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
|
||||
};
|
|
@ -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);
|
||||
|
|
|
@ -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
|
@ -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
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue