diff --git a/.gitignore b/.gitignore index 102aef8..ad6600a 100644 --- a/.gitignore +++ b/.gitignore @@ -343,12 +343,9 @@ make/oscar64 *.int *.bcs *.crt -*.crt -*.d64 +**/*.d64 *.tlog *.res *.recipe *.exe -*.d64 -*.d64 *.dbj diff --git a/README.md b/README.md index e5b187b..3ab4eff 100644 --- a/README.md +++ b/README.md @@ -20,10 +20,11 @@ The goal was also to implement the C99 standard and not some subset for performa After extensive optimizations it turns out, that the interpreted code is not significantly smaller than the native code in most scenarios (although there are cases where the difference is significant). - + ## 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(, ) + +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 diff --git a/autotest/arrayconstruct.cpp b/autotest/arrayconstruct.cpp new file mode 100644 index 0000000..171f109 --- /dev/null +++ b/autotest/arrayconstruct.cpp @@ -0,0 +1,154 @@ +#include + +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; +} + diff --git a/autotest/arrayindexintrangecheck.c b/autotest/arrayindexintrangecheck.c index e71ce42..946ceba 100644 --- a/autotest/arrayindexintrangecheck.c +++ b/autotest/arrayindexintrangecheck.c @@ -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; } diff --git a/autotest/autotest.bat b/autotest/autotest.bat index 7f5306e..37f4864 100644 --- a/autotest/autotest.bat +++ b/autotest/autotest.bat @@ -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 diff --git a/autotest/bitfields.cpp b/autotest/bitfields.cpp new file mode 100644 index 0000000..02031e7 --- /dev/null +++ b/autotest/bitfields.cpp @@ -0,0 +1,355 @@ +#include + +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; +} diff --git a/autotest/constructortest.cpp b/autotest/constructortest.cpp new file mode 100644 index 0000000..1418277 --- /dev/null +++ b/autotest/constructortest.cpp @@ -0,0 +1,165 @@ +#include + +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; +} diff --git a/autotest/copyassign.cpp b/autotest/copyassign.cpp new file mode 100644 index 0000000..886a321 --- /dev/null +++ b/autotest/copyassign.cpp @@ -0,0 +1,126 @@ +#include + +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; +} diff --git a/autotest/copyconstructor.cpp b/autotest/copyconstructor.cpp new file mode 100644 index 0000000..71f3d0f --- /dev/null +++ b/autotest/copyconstructor.cpp @@ -0,0 +1,216 @@ +#include + +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; +} \ No newline at end of file diff --git a/autotest/floatcmptest.c b/autotest/floatcmptest.c index 9afa51f..8e3b202 100644 --- a/autotest/floatcmptest.c +++ b/autotest/floatcmptest.c @@ -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; } diff --git a/autotest/makefile b/autotest/makefile new file mode 100644 index 0000000..d54b0d5 --- /dev/null +++ b/autotest/makefile @@ -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 diff --git a/autotest/mmultest.c b/autotest/mmultest.c new file mode 100644 index 0000000..edcb10c --- /dev/null +++ b/autotest/mmultest.c @@ -0,0 +1,43 @@ +#include +#include +#include + +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; +} diff --git a/autotest/operatoroverload.cpp b/autotest/operatoroverload.cpp new file mode 100644 index 0000000..93c02bb --- /dev/null +++ b/autotest/operatoroverload.cpp @@ -0,0 +1,90 @@ +#include + +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; +} diff --git a/autotest/opp_array.cpp b/autotest/opp_array.cpp new file mode 100644 index 0000000..b4d0984 --- /dev/null +++ b/autotest/opp_array.cpp @@ -0,0 +1,23 @@ +#include +#include + +int main(void) +{ + opp::array a10; + opp::array 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; +} diff --git a/autotest/opp_pairtest.cpp b/autotest/opp_pairtest.cpp new file mode 100644 index 0000000..7a1113c --- /dev/null +++ b/autotest/opp_pairtest.cpp @@ -0,0 +1,28 @@ +#include +#include +#include +#include + +using namespace opp; + +int main(void) +{ + vector > 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; +} diff --git a/autotest/opp_part1.cpp b/autotest/opp_part1.cpp new file mode 100644 index 0000000..8fc18fb --- /dev/null +++ b/autotest/opp_part1.cpp @@ -0,0 +1,2 @@ +#include "opp_part1.h" + diff --git a/autotest/opp_part1.h b/autotest/opp_part1.h new file mode 100644 index 0000000..7b227ff --- /dev/null +++ b/autotest/opp_part1.h @@ -0,0 +1,40 @@ +#pragma once + +#include + +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 va; +public: + AS(const opp::vector & v) + : va(v) + {} + + int sum(void) + { + int s = 0; + for(const auto & a : va) + s += a.sum(); + return s; + } +}; + +#pragma compile("opp_part1.cpp") + diff --git a/autotest/opp_part2.cpp b/autotest/opp_part2.cpp new file mode 100644 index 0000000..f30400c --- /dev/null +++ b/autotest/opp_part2.cpp @@ -0,0 +1,13 @@ +#include "opp_part2.h" + +BS::BS(const opp::vector & v) + : va(v) + {} + +int BS::sum(void) +{ + int s = 0; + for(const auto & a : va) + s += a.sum(); + return s; +} diff --git a/autotest/opp_part2.h b/autotest/opp_part2.h new file mode 100644 index 0000000..5606e0e --- /dev/null +++ b/autotest/opp_part2.h @@ -0,0 +1,16 @@ +#pragma once + +#include "opp_part1.h" + +class BS +{ +protected: + opp::vector va; +public: + BS(const opp::vector & v); + int sum(void); +}; + + + +#pragma compile("opp_part2.cpp") diff --git a/autotest/opp_parts.cpp b/autotest/opp_parts.cpp new file mode 100644 index 0000000..364753e --- /dev/null +++ b/autotest/opp_parts.cpp @@ -0,0 +1,25 @@ +#include + +#include "opp_part1.h" +#include "opp_part2.h" + + +int main(void) +{ + opp::vector 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; +} diff --git a/autotest/opp_streamtest.cpp b/autotest/opp_streamtest.cpp new file mode 100644 index 0000000..940f106 --- /dev/null +++ b/autotest/opp_streamtest.cpp @@ -0,0 +1,83 @@ +#include +#include +#include +#include +#include + +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; +} diff --git a/autotest/opp_string.cpp b/autotest/opp_string.cpp new file mode 100644 index 0000000..3a52312 --- /dev/null +++ b/autotest/opp_string.cpp @@ -0,0 +1,103 @@ +#include +#include +#include +#include + +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; +} diff --git a/autotest/opp_vector.cpp b/autotest/opp_vector.cpp new file mode 100644 index 0000000..f2d56a1 --- /dev/null +++ b/autotest/opp_vector.cpp @@ -0,0 +1,68 @@ +#include +#include +#include +#include + +int main(void) +{ + opp::vector a; + + for(int i=0; i<10; i++) + a.push_back(i); + + int s = 0; + for(int i=0; i 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; +} diff --git a/autotest/opp_vector_string.cpp b/autotest/opp_vector_string.cpp new file mode 100644 index 0000000..96642be --- /dev/null +++ b/autotest/opp_vector_string.cpp @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include + +using opp::string; +using opp::vector; + +string join(const vector & vs) +{ + string sj; + for(int i=0; i 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; +} diff --git a/autotest/stdlibtest.c b/autotest/stdlibtest.c index 2409c2b..84d3268 100644 --- a/autotest/stdlibtest.c +++ b/autotest/stdlibtest.c @@ -51,16 +51,15 @@ void heapcheck(void) for(i=0; i + +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; +} diff --git a/autotest/vcalltree.cpp b/autotest/vcalltree.cpp new file mode 100644 index 0000000..ef3ef13 --- /dev/null +++ b/autotest/vcalltree.cpp @@ -0,0 +1,79 @@ +#include + +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; +} diff --git a/autotest/virtualdestruct.cpp b/autotest/virtualdestruct.cpp new file mode 100644 index 0000000..a9bd394 --- /dev/null +++ b/autotest/virtualdestruct.cpp @@ -0,0 +1,63 @@ +#include + +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; +} diff --git a/include/c64/iecbus.c b/include/c64/iecbus.c index 1a93755..a9560ff 100644 --- a/include/c64/iecbus.c +++ b/include/c64/iecbus.c @@ -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--; + __asm { + 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 - } + delay(5); + clock_high(); + data_low(); } - data_low(); - clock_high(); 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; iDoneTrampoline 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; } diff --git a/include/c64/memmap.h b/include/c64/memmap.h index aebb768..947ffec 100644 --- a/include/c64/memmap.h +++ b/include/c64/memmap.h @@ -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") diff --git a/include/c64/mouse.c b/include/c64/mouse.c index 5fcf93a..70a7078 100644 --- a/include/c64/mouse.c +++ b/include/c64/mouse.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; } diff --git a/include/c64/rasterirq.c b/include/c64/rasterirq.c index 5ccc8c5..442dcfc 100644 --- a/include/c64/rasterirq.c +++ b/include/c64/rasterirq.c @@ -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 diff --git a/include/c64/sprites.c b/include/c64/sprites.c index e2902be..912d3da 100644 --- a/include/c64/sprites.c +++ b/include/c64/sprites.c @@ -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++) diff --git a/include/c64/sprites.h b/include/c64/sprites.h index 69f7cee..a676614 100644 --- a/include/c64/sprites.h +++ b/include/c64/sprites.h @@ -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 diff --git a/include/c64/vic.c b/include/c64/vic.c index 28d6827..ba602fa 100644 --- a/include/c64/vic.c +++ b/include/c64/vic.c @@ -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; diff --git a/include/c64/vic.h b/include/c64/vic.h index 718ae88..d420778 100644 --- a/include/c64/vic.h +++ b/include/c64/vic.h @@ -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); diff --git a/include/conio.c b/include/conio.c index afc8e1a..6b4b008 100644 --- a/include/conio.c +++ b/include/conio.c @@ -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; diff --git a/include/conio.h b/include/conio.h index 28a72b4..f1749b3 100644 --- a/include/conio.h +++ b/include/conio.h @@ -18,6 +18,10 @@ extern IOCharMap giocharmap; void iocharmap(IOCharMap chmap); +#if defined(__C128__) +void dispmode40col(void); +void dispmode80col(void); +#endif int kbhit(void); diff --git a/include/crt.c b/include/crt.c index d4087bf..6f85487 100644 --- a/include/crt.c +++ b/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 + 1 + + // set end of memory block to end of heap + lda #HeapEnd + sta HeapStart + 3 + +hasHeap: + // remember address of pointer to this + // heap block, to correct if block is a + // perfect fit + + lda #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 + +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 diff --git a/include/crt.h b/include/crt.h index 5844f9c..2cc7fc0 100644 --- a/include/crt.h +++ b/include/crt.h @@ -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, diff --git a/include/ctype.c b/include/ctype.c index bac6f8e..650cb36 100644 --- a/include/ctype.c +++ b/include/ctype.c @@ -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; +} diff --git a/include/ctype.h b/include/ctype.h index 3da3a47..f4f9a61 100644 --- a/include/ctype.h +++ b/include/ctype.h @@ -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") diff --git a/include/math.h b/include/math.h index 842d32d..4c58d7f 100644 --- a/include/math.h +++ b/include/math.h @@ -30,6 +30,9 @@ bool isfinite(float f); #pragma intrinsic(floor) #pragma intrinsic(ceil) +#pragma intrinsic(sin) +#pragma intrinsic(cos) + #pragma compile("math.c") diff --git a/include/new b/include/new new file mode 100644 index 0000000..24cda01 --- /dev/null +++ b/include/new @@ -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); + +} diff --git a/include/opp/algorithm.h b/include/opp/algorithm.h new file mode 100644 index 0000000..a6f5a19 --- /dev/null +++ b/include/opp/algorithm.h @@ -0,0 +1,84 @@ +#ifndef OPP_ALGORITHM_H +#define OPP_ALGORITHM_H + +#include "utility.h" +namespace opp { + +template +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(s, p); + p++; + s = p; + } +} + +template +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 +OI copy(II first, II last, OI result) +{ + while (first != last) + { + *result = *first; + ++result; ++first; + } + return result; +} + + +template +II find (II first, II last, const T& val) +{ + while (first != last) + { + if (*first == val) return first; + ++first; + } + return last; +} + +} + +#endif diff --git a/include/opp/array.h b/include/opp/array.h new file mode 100644 index 0000000..207e2e2 --- /dev/null +++ b/include/opp/array.h @@ -0,0 +1,120 @@ +#ifndef OPP_ARRAY_H +#define OPP_ARRAY_H + +namespace opp { + +template +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 +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 + +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); +} + +} diff --git a/include/opp/ifstream.h b/include/opp/ifstream.h new file mode 100644 index 0000000..6a0394e --- /dev/null +++ b/include/opp/ifstream.h @@ -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 \ No newline at end of file diff --git a/include/opp/iostream.cpp b/include/opp/iostream.cpp new file mode 100644 index 0000000..d853de8 --- /dev/null +++ b/include/opp/iostream.cpp @@ -0,0 +1,1003 @@ +#include "iostream.h" +#include +#include + +namespace opp { + +ios::ios(void) + : mFlags(0), mState(0), mWidth(0), mPrecision(6), mFill(' ') +{} + +inline ios::~ios(void) +{ + +} + +char ios::fill(void) const +{ + return mFill; +} + +char ios::fill(char fillch) +{ + char c = mFill; + mFill = fillch; + return c; +} + +char ios::width() const +{ + return mWidth; +} + +char ios::width(char wide) +{ + char w = mWidth; + mWidth = wide; + return w; +} + +char ios::precision() const +{ + return mPrecision; +} + +char ios::precision(char wide) +{ + char w = mPrecision; + mPrecision = wide; + return w; +} + +ios::fmtflags ios::flags(void) const +{ + return mFlags; +} + +ios::fmtflags ios::flags(ios::fmtflags f) +{ + fmtflags pf = mFlags; + mFlags = f; + return pf; +} + +ios::fmtflags ios::setf(ios::fmtflags f) +{ + fmtflags pf = mFlags; + mFlags |= f; + return pf; +} + +ios::fmtflags ios::setf(ios::fmtflags f, ios::fmtflags m) +{ + fmtflags pf = mFlags; + mFlags = (mFlags & ~m) | f; + return pf; +} + +ios::fmtflags ios::unsetf(ios::fmtflags f) +{ + fmtflags pf = mFlags; + mFlags &= ~f; + return pf; +} + +bool ios::good(void) const +{ + return mState == goodbit; +} + +bool ios::eof(void) const +{ + return (mState & eofbit) != 0; +} + +bool ios::fail(void) const +{ + return (mState & (badbit | failbit)) != 0; +} + +bool ios::bad(void) const +{ + return (mState & badbit) != 0; +} + +bool ios::operator!(void) const +{ + return fail(); +} + +ios::operator bool(void) +{ + return !fail(); +} + + +ios::statebits ios::rdstate(void) const +{ + return mState; +} + +void ios::clear(void) +{ + mState = goodbit; +} + + + + +ostream & endl(ostream & os) +{ + os.put('\n'); + return os; +} + + +iosetf setf(ios::fmtflags flags) +{ + return iosetf(flags); +} + +ostream & operator<<(ostream & os, const iosetf & s) +{ + os.setf(s.flags); + return os; +} + +iosetw setw(char width) +{ + return iosetw(width); +} + +ostream & operator<<(ostream & os, const iosetw & s) +{ + os.width(s.width); + return os; +} + + +iosetprecision setprecision(char precision) +{ + return iosetprecision(precision); +} + +ostream & operator<<(ostream & os, const iosetprecision & s) +{ + os.precision(s.precision); + return os; +} + + +iosetfill setfill(char fill) +{ + return iosetfill(fill); +} + +ostream & operator<<(ostream & os, const iosetfill & s) +{ + os.fill(s.fill); + return os; +} + +inline ostream::ostream(void) + {} + + +void ostream::bput(char ch) +{ +} + +ostream & ostream::put(char c) +{ + bput(c); + return * this; +} + +ostream & ostream::write(const char * s, int n) +{ + for(int i=0; i prefix) + bput(buffer[--size]); + } + + if (adj != left) + { + while (r > 0) + { + bput(mFill); + r--; + } + } + + while (size > 0) + bput(buffer[--size]); + + while (r > 0) + { + bput(mFill); + r--; + } + + mFlags = 0; + mWidth = 0; + mFill = ' '; +} + +void ostream::numput(unsigned n, char sign) +{ + char buffer[10]; + + char base = 10; + if (mFlags & hex) + base = 16; + else if (mFlags & oct) + base = 8; + + char i = 0; + char o = 'a' - 10; + if (mFlags & uppercase) + o = 'A' - 10; + + unsigned nt = n; + while (nt) + { + char d = nt % base; + nt /= base; + + if (d < 10) + d += '0'; + else + d += o; + buffer[i++] = d; + } + + if (!i) + buffer[i++] = '0'; + char prefix = i; + if (sign) + buffer[i++] = sign; + + putnum(buffer, prefix, i); +} + +void ostream::numput(unsigned long n, char sign) +{ + char buffer[20]; + + char base = 10; + if (mFlags & hex) + base = 16; + else if (mFlags & oct) + base = 8; + + char i = 0; + char o = 'a' - 10; + if (mFlags & uppercase) + o = 'A' - 10; + + unsigned long nt = n; + while (nt) + { + char d = nt % base; + nt /= base; + + if (d < 10) + d += '0'; + else + d += o; + buffer[i++] = d; + } + + if (!i) + buffer[i++] = '0'; + char prefix = i; + if (sign) + buffer[i++] = sign; + + putnum(buffer, prefix, i); +} + + +ostream & ostream::operator<<(bool val) +{ + if (val) + bput('1'); + else + bput('0'); + return *this; +} + +ostream & ostream::operator<<(char val) +{ + bput(val); + return *this; +} + +ostream & ostream::operator<<(int val) +{ + if (val < 0) + numput((unsigned)-val, '-'); + else if (mFlags & showpos) + numput((unsigned)val, '+'); + else + numput((unsigned)val, 0); + return *this; +} + +ostream & ostream::operator<<(unsigned val) +{ + numput(val, 0); + return *this; +} + +ostream & ostream::operator<<(long val) +{ + if (val < 0) + numput(-val, '-'); + else if (mFlags & showpos) + numput(val, '+'); + else + numput(val, 0); + return *this; +} + +ostream & ostream::operator<<(unsigned long val) +{ + numput(val, 0); + return *this; +} + +static float fround5[] = { + 0.5e-0, 0.5e-1, 0.5e-2, 0.5e-3, 0.5e-4, 0.5e-5, 0.5e-6 +}; + +ostream & ostream::operator<<(float val) +{ + char buffer[20]; + + char d = 0; + + float f = val; + + if (f < 0.0) + { + f = -f; + buffer[d++] = '-'; + } + else if (mFlags & showpos) + buffer[d++] = '+'; + + char prefix = d; + + if (isinf(f)) + { + buffer[d++] = 'I'; + buffer[d++] = 'N'; + buffer[d++] = 'F'; + } + else + { + int exp = 0; + + char fdigits = mPrecision; + + if (f != 0.0) + { + while (f >= 1000.0) + { + f /= 1000; + exp += 3; + } + + while (f < 1.0) + { + f *= 1000; + exp -= 3; + } + + while (f >= 10.0) + { + f /= 10; + exp ++; + } + + } + + char digits = fdigits + 1; + bool fexp = mFlags & scientific; + + if (!(mFlags & fixed)) + { + if (exp > 3 || exp < 0) + fexp = true; + } + + if (!fexp) + { + while (exp < 0) + { + f /= 10.0; + exp++; + } + + digits = fdigits + exp + 1; + + if (digits < 7) + f += fround5[digits - 1]; + else + f += fround5[6]; + + if (f >= 10.0) + { + f /= 10.0; + fdigits--; + } + } + else + { + if (digits < 7) + f += fround5[digits - 1]; + else + f += fround5[6]; + + if (f >= 10.0) + { + f /= 10.0; + exp ++; + } + } + + + char pdigits = digits - fdigits; + + if (digits > 20) + digits = 20; + + if (pdigits == 0) + buffer[d++] = '0'; + + for(char i=0; i 6) + buffer[d++] = '0'; + else + { + int c = (int)f; + f -= (float)c; + f *= 10.0; + buffer[d++] = c + '0'; + } + } + + if (fexp) + { + buffer[d++] = 'E'; + if (exp < 0) + { + buffer[d++] = '-'; + exp = -exp; + } + else + buffer[d++] = '+'; + + buffer[d++] = exp / 10 + '0'; + buffer[d++] = exp % 10 + '0'; + } + } + + char r = 0; + if (d < mWidth) + r = mWidth - d; + + fmtflags adj = mFlags & adjustfield; + + char i = 0; + if (adj == internal) + { + while (i < prefix) + bput(buffer[i++]); + } + + if (adj != left) + { + while (r > 0) + { + bput(mFill); + r--; + } + } + + while (i < d) + bput(buffer[i++]); + + while (r > 0) + { + bput(mFill); + r--; + } + + mFlags = 0; + mWidth = 0; + mFill = ' '; + + return *this; +} + +ostream & ostream::operator<<(const char * p) +{ + char i = 0; + while (p[i]) + bput(p[i++]); + return *this; +} + +ostream & ostream::operator<<(const string & s) +{ + for(char i=0; i ' ') + { + unget(); + return; + } + } +} + + + +istream & istream::get(char & c) +{ + c = get(); + return *this; +} + +istream & istream::get(char * s, char size) +{ + return get(s, size, '\n'); +} + +istream & istream::get(char * s, char size, char delim) +{ + char i = 0; + while (i + 1 < size) + { + char c = get(); + if (c == delim) + { + unget(); + break; + } + s[i++] = c; + } + if (size) + s[i++] = 0; + return *this; +} + +istream & istream::getline(char * s, char size) +{ + return getline(s, size, '\n'); +} + +istream & istream::getline(char * s, char size, char delim) +{ + char i = 0; + while (i + 1 < size) + { + char c = get(); + if (c == delim) + break; + s[i++] = c; + } + if (size) + s[i++] = 0; + return *this; +} + +istream & istream::ignore(char size) +{ + ignore(size, '\n'); + return *this; +} + +istream & istream::ignore(char size, char delim) +{ + while (size) + { + char c = get(); + if (c == delim) + break; + size--; + } + + return *this; +} + +istream & istream::operator>>(bool & val) +{ + return *this; +} + +unsigned istream::getnum(void) +{ + doskipws(); + + fmtflags bflags = mFlags & basefield; + + char base = 10; + if (bflags == hex) + base = 16; + else if (bflags == oct) + base = 8; + + unsigned n = 0; + bool sign = false; + + char ch = get(); + if (ch == '-') + { + sign = true; + ch = get(); + } + else if (ch == '+') + ch = get(); + + bool digits = false; + + if (ch == '0') + { + if (bflags == 0) + { + base = 8; + ch = get(); + if (ch == 'x' || ch == 'X') + { + base = 16; + ch = get(); + } + else + digits = true; + } + else + digits = true; + } + + for(;;) + { + if (ch >= '0' && ch <= '9') + n = n * base + (ch - '0'); + else if (base > 10 && ch >= 'A' && ch <= 'F') + n = n * base + (ch - 'A' + 10); + else if (base > 10 && ch >= 'a' && ch <= 'f') + n = n * base + (ch - 'a' + 10); + else + break; + ch = get(); + digits = true; + } + unget(); + + if (!digits) + mState |= failbit; + + if (sign) + return -n; + else + return n; +} + +unsigned long istream::getnuml(void) +{ + doskipws(); + + fmtflags bflags = mFlags & basefield; + + char base = 10; + if (bflags == hex) + base = 16; + else if (bflags == oct) + base = 8; + + unsigned long n = 0; + bool sign = false; + + char ch = get(); + if (ch == '-') + { + sign = true; + ch = get(); + } + else if (ch == '+') + ch = get(); + + if (ch == '0') + { + if (bflags == 0) + { + base = 8; + ch = get(); + if (ch == 'x' || ch == 'X') + { + base = 16; + ch = get(); + } + } + } + + bool digits = false; + for(;;) + { + if (ch >= '0' && ch <= '9') + n = n * base + (ch - '0'); + else if (base > 10 && ch >= 'A' && ch <= 'F') + n = n * base + (ch - 'A' + 10); + else if (base > 10 && ch >= 'a' && ch <= 'f') + n = n * base + (ch - 'a' + 10); + else + break; + ch = get(); + digits = true; + } + unget(); + + if (!digits) + mState |= failbit; + + if (sign) + return -n; + else + return n; +} + +float istream::getnumf(void) +{ + doskipws(); + + char cs = get(); + + bool sign = false; + if (cs == '-') + { + sign = true; + cs = get(); + } + else if (cs == '+') + cs = get(); + + if (cs >= '0' && cs <= '9' || cs == '.') + { + float vf = 0; + while (cs >= '0' && cs <= '9') + { + vf = vf * 10 + (int)(cs - '0'); + cs = get(); + } + + if (cs == '.') + { + float digits = 1.0; + cs = get(); + while (cs >= '0' && cs <= '9') + { + vf = vf * 10 + (int)(cs - '0'); + digits *= 10; + cs = get(); + } + vf /= digits; + } + + char e = 0; + bool eneg = false; + + if (cs == 'e' || cs == 'E') + { + cs = get(); + if (cs == '-') + { + eneg = true; + cs = get(); + } + else if (cs == '+') + { + cs = get(); + } + + while (cs >= '0' && cs <= '9') + { + e = e * 10 + cs - '0'; + cs = get(); + } + + } + + if (e) + { + if (eneg) + { + while (e > 6) + { + vf /= 1000000.0; + e -= 6; + } + vf /= tpow10[e]; + } + else + { + while (e > 6) + { + vf *= 1000000.0; + e -= 6; + } + vf *= tpow10[e]; + } + } + + if (sign) + return -vf; + else + return vf; + } + else + mState |= failbit; + + return 0; +} + +istream & istream::operator>>(int & val) +{ + val = getnum(); + return *this; +} + +istream & istream::operator>>(unsigned & val) +{ + val = getnum(); + return *this; +} + +istream & istream::operator>>(long & val) +{ + val = getnuml(); + return *this; +} + +istream & istream::operator>>(unsigned long & val) +{ + val = getnuml(); + return *this; +} + +istream & istream::operator>>(float & val) +{ + val = getnumf(); + return *this; +} + +istream & istream::operator>>(char * p) +{ + doskipws(); + char i = 0; + char c = get(); + while (c > ' ') + { + p[i++] = c; + c = get(); + } + return *this; +} + +istream & istream::operator>>(string & s) +{ + doskipws(); + s.clear(); + char c = get(); + while (c > ' ') + { + s += c; + c = get(); + } + return *this; +} + +cistream::cistream(void) +{} + +void cistream::refill(void) +{ + mBufferPos = 0; + + char fill = 0; + while (fill < 32) + { + char ch = getchar(); + mBuffer[fill++] = ch; + if (ch == '\n') + break; + } + + mBufferFill = fill; +} + +cistream cin; +costream cout; + +} \ No newline at end of file diff --git a/include/opp/iostream.h b/include/opp/iostream.h new file mode 100644 index 0000000..f42d1e5 --- /dev/null +++ b/include/opp/iostream.h @@ -0,0 +1,216 @@ +#ifndef OPP_IOSTREAM_H +#define OPP_IOSTREAM_H + +#include + +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 diff --git a/include/opp/iterator.h b/include/opp/iterator.h new file mode 100644 index 0000000..2cedc75 --- /dev/null +++ b/include/opp/iterator.h @@ -0,0 +1,137 @@ +#ifndef OPP_ITERATOR_H +#define OPP_ITERATOR_H + +namespace opp +{ + +template +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 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 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 +front_insert_iterator front_inserter (CT & c) +{ + return front_insert_iterator(c); +} + +template +back_insert_iterator back_inserter (CT & c) +{ + return back_insert_iterator(c); +} + +template +insert_iterator inserter (CT & c, const CT::iterator_type & i) +{ + return insert_iterator(c, i); +} + +} diff --git a/include/opp/list.h b/include/opp/list.h new file mode 100644 index 0000000..a99c4d2 --- /dev/null +++ b/include/opp/list.h @@ -0,0 +1,298 @@ +#ifndef OPP_LIST +#define OPP_LIST + +namespace opp +{ + +template +class listhead +{ +public: + listnode * succ, * pred; + + listhead() + { + succ = (listnode *)this; + pred = (listnode *)this; + } +}; + +template +class listnode : public listhead +{ +public: + T data; + + listnode(const T & t) : data(t) {} + listnode(T && t) : data(t) {} +}; + +template +class list_iterator +{ +public: + listnode * node; +public: + list_iterator(void) : node(nullptr) {} + list_iterator(listnode * 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 * 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 * 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 list +{ +private: + typedef listnode ln; + listhead head; +public: + typedef T element_type; + typedef list_iterator iterator_type; + + list(void) + {} + + ~list(void) + { + listnode * n = head.succ; + while (n != &head) + { + listnode * m = n->succ; + delete n; + n = m; + } + } + + list_iterator begin(void) + { + return list_iterator(head.succ); + } + + list_iterator end(void) + { + return list_iterator((listnode *)&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 erase(list_iterator it); + + list_iterator erase(list_iterator first, list_iterator 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 insert(list_iterator it, const T & t); + + list_iterator insert(list_iterator it, T && t); +}; + +template +void list::pop_front(void) +{ + listnode * n = head.succ; + head.succ = n->succ; + n->succ->pred = (listnode *)&head; + delete n; +} + +template +void list::pop_back(void) +{ + listnode * n = head.pred; + head.pred = n->pred; + n->pred->succ = (listnode *)&head; + delete n; +} + +template +void list::push_front(const T & t) +{ + listnode * n = new listnode(t); + n->pred = (listnode *)&head; + n->succ = head.succ; + head.succ->pred = n; + head.succ = n; +} + +template +void list::push_front(T && t) +{ + listnode * n = new listnode(t); + n->pred = (listnode *)&head; + n->succ = head.succ; + head.succ->pred = n; + head.succ = n; +} + +template +void list::push_back(const T & t) +{ + listnode * n = new listnode(t); + n->succ = (listnode *)&head; + n->pred = head.pred; + head.pred->succ = n; + head.pred = n; +} + +template +void list::push_back(T && t) +{ + listnode * n = new listnode(t); + n->succ = (listnode *)&head; + n->pred = head.pred; + head.pred->succ = n; + head.pred = n; +} + + +template +list_iterator list::erase(list_iterator it) +{ + listnode * n = it.node; + listnode * s = n->succ; + + n->succ->pred = n->pred; + n->pred->succ = n->succ; + delete n; + + return list_iterator(s); +} + +template +list_iterator list::erase(list_iterator first, list_iterator last) +{ + listnode * n = first.node; + listnode * s = last.node; + + n->pred->succ = s; + s->pred = n->pred; + + while (n != s) + { + listnode * m = n->succ; + delete n; + n = m; + } + + return list_iterator(s); +} + +template +list_iterator list::insert(list_iterator it, const T & t) +{ + listnode * n = new listnode(t); + n->succ = it.node; + n->pred = it.node->pred; + it.node->pred->succ = n; + it.node->pred = n; + return list_iterator(n); +} + +template +list_iterator list::insert(list_iterator it, T && t) +{ + listnode * n = new listnode(t); + n->succ = it.node; + n->pred = it.node->pred; + it.node->pred->succ = n; + it.node->pred = n; + return list_iterator(n); +} + +} + +#endif diff --git a/include/opp/ofstream.cpp b/include/opp/ofstream.cpp new file mode 100644 index 0000000..bbbbaaa --- /dev/null +++ b/include/opp/ofstream.cpp @@ -0,0 +1,32 @@ +#include "ofstream.h" +#include + +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; + } +} + +} diff --git a/include/opp/ofstream.h b/include/opp/ofstream.h new file mode 100644 index 0000000..6367fec --- /dev/null +++ b/include/opp/ofstream.h @@ -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 diff --git a/include/opp/slab.h b/include/opp/slab.h new file mode 100644 index 0000000..1a61d4d --- /dev/null +++ b/include/opp/slab.h @@ -0,0 +1,80 @@ +#ifndef OPP_SLAB_H +#define OPP_SLAB_H + +template +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 slab +{ +protected: + static __striped T buffer[N]; + static char head; + static char next[N]; + +public: + typedef slabptr ptr; + + static void init(void); + static auto alloc(void); + static void free(ptr p); +}; + + +template +inline auto slabptr::operator-> () +{ + return slab::buffer + index; +} + +template +inline auto & slabptr::operator* () +{ + return slab::buffer[index]; +} + + +template +void slab::init(void) +{ + head = 0; + for(char i=0; i +auto slab::alloc(void) +{ + char i = head; + head = next[head]; + return slabptr(i); +} + +template +void slab::free(slabptr p) +{ + next[p.index] = head; + head = p.index; +} + +#endif + diff --git a/include/opp/sstream.cpp b/include/opp/sstream.cpp new file mode 100644 index 0000000..5954939 --- /dev/null +++ b/include/opp/sstream.cpp @@ -0,0 +1,86 @@ +#include "sstream.h" +#include + +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 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++]; + } +} + +} diff --git a/include/opp/sstream.h b/include/opp/sstream.h new file mode 100644 index 0000000..8a0b4a7 --- /dev/null +++ b/include/opp/sstream.h @@ -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 diff --git a/include/opp/static_vector.h b/include/opp/static_vector.h new file mode 100644 index 0000000..c5358c6 --- /dev/null +++ b/include/opp/static_vector.h @@ -0,0 +1,258 @@ +#ifndef OPP_STATIC_VECTOR_H +#define OPP_STATIC_VECTOR_H + +#include +#include +#include + +namespace opp { + +template +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 + void emplace_back(const P&... p); +}; + + + +template +void static_vector::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 +void static_vector::push_back(const T & t) +{ + new ((T*)_space + _size++)T(t); +} + +template +void static_vector::push_back(T && t) +{ + new ((T*)_space + _size++)T(t); +} + +template +template +void static_vector::emplace_back(const P&... p) +{ + new ((T*)_space + _size++)T(p...); +} + +template +void static_vector::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 +void static_vector::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 +T * static_vector::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 + diff --git a/include/opp/string.cpp b/include/opp/string.cpp new file mode 100644 index 0000000..0b4da19 --- /dev/null +++ b/include/opp/string.cpp @@ -0,0 +1,1132 @@ +#include "string.h" +#include +#include +#include + +namespace opp { + +static inline void smemcpy(char * dp, const char * sp, char s) +{ + for(char i=0; i 0 && cstr) + { + if (n >= cstr[0]) + { + free(cstr); + cstr = nullptr; + } + else + { + char i = 1; + n++; + while (cstr[n]) + cstr[i++] = cstr[n++]; + cstr[i] = 0; + cstr[0] = i - 1; + } + } + return *this; +} + +string & string::operator>>=(char n) +{ + if (n > 0 && cstr) + { + if (n >= cstr[0]) + { + free(cstr); + cstr = nullptr; + } + else + { + cstr[0] -= n; + cstr[n + 1] = 0; + } + } + return *this; +} + +string string::operator<<(char n) const +{ + if (n > 0 && cstr) + { + if (n >= cstr[0]) + return string(); + else + { + + } + } + else + return *this; +} + +string string::operator>>(char n) const +{ + +} + +static int scmp(const char * s1, const char * s2) +{ + char n = 0; + while (s1[n]) + { + if (s1[n] != s2[n]) + return s1[n] - s2[n]; + n++; + } + return 0; +} + +inline bool string::operator==(const string & s) const +{ + if (cstr && s.cstr) + return scmp(cstr + 1, s.cstr + 1) == 0; + else + return !cstr && !s.cstr; +} + +inline bool string::operator==(const char * s) const +{ + if (cstr) + return scmp(cstr + 1, s) == 0; + else + return s[0] == 0; +} + +inline bool string::operator!=(const string & s) const +{ + if (cstr && s.cstr) + return scmp(cstr + 1, s.cstr + 1) != 0; + else + return cstr || s.cstr; +} + +inline bool string::operator!=(const char * s) const +{ + if (cstr) + return scmp(cstr + 1, s) == 0; + else + return s[0] != 0; +} + +inline bool string::operator<(const string & s) const +{ + if (cstr && s.cstr) + return scmp(cstr + 1, s.cstr + 1) < 0; + else + return s.cstr; +} + +inline bool string::operator<(const char * s) const +{ + if (cstr) + return scmp(cstr + 1, s) < 0; + else + return s[0] != 0; +} + +inline bool string::operator<=(const string & s) const +{ + if (cstr && s.cstr) + return scmp(cstr + 1, s.cstr + 1) <= 0; + else + return !cstr || s.cstr; +} + +inline bool string::operator<=(const char * s) const +{ + if (cstr) + return scmp(cstr + 1, s) <= 0; + else + return true; +} + +inline bool string::operator>(const string & s) const +{ + if (cstr && s.cstr) + return scmp(cstr + 1, s.cstr + 1) > 0; + else + return cstr; +} + +inline bool string::operator>(const char * s) const +{ + if (cstr) + return scmp(cstr + 1, s) > 0; + else + return false; +} + +inline bool string::operator>=(const string & s) const +{ + if (cstr && s.cstr) + return scmp(cstr + 1, s.cstr + 1) >= 0; + else + return cstr || !s.cstr; +} + +inline bool string::operator>=(const char * s) const +{ + if (cstr) + return scmp(cstr + 1, s) >= 0; + else + return s[0] == 0; +} + +inline char & string::operator[](char t) +{ + return cstr[t + 1]; +} + +inline char string::operator[](char t) const +{ + return cstr[t + 1]; +} + +char * string::begin(void) +{ + return cstr ? cstr + 1 : nullptr; +} + +const char * string::begin(void) const +{ + return cstr ? cstr + 1 : nullptr; +} + +const char * string::cbegin(void) const +{ + return cstr ? cstr + 1 : nullptr; +} + +char * string::end(void) +{ + return cstr ? cstr + 1 + cstr[0] : nullptr; +} + +const char * string::end(void) const +{ + return cstr ? cstr + 1 + cstr[0] : nullptr; +} + +const char * string::cend(void) const +{ + return cstr ? cstr + 1 + cstr[0] : nullptr; +} + + +string string::substr(char pos, char len) const +{ + if (!cstr || len == 0 || pos >= cstr[0]) + return string(); + else + { + char l = cstr[0]; + if (pos + len > l) + len = l - pos; + + char * p = malloc(len + 2); + memcpy(p + 1, cstr + 1 + pos, len); + return string(len, p); + } +} + +inline int string::find(const string & s) const +{ + return find(s, 0); +} + +inline int string::find(const char * s) const +{ + return find(s, 0); +} + +inline int string::find(char c) const +{ + return find(c, 0); +} + +int string::find(const string & s, char pos) const +{ + if (!s.cstr) + return pos; + if (cstr) + { + char l = cstr[0]; + char sl = s.cstr[0]; + if (sl <= l) + { + l -= sl; + + while (pos <= l) + { + char i = 1; + while (s.cstr[i] && s.cstr[i] == cstr[pos + i]) + i++; + if (!s.cstr[i]) + return pos; + pos++; + } + } + } + + return -1; +} + +int string::find(const char * s, char pos) const +{ + if (cstr) + { + char l = cstr[0]; + char sl = sstrlen(s); + if (sl <= l) + { + l -= sl; + + while (pos <= l) + { + char i = 0; + while (s[i] && s[i] == cstr[pos + i + 1]) + i++; + if (!s[i]) + return pos; + pos++; + } + } + } + + return -1; +} + +int string::find(char c, char pos) const +{ + if (cstr) + { + char l = cstr[0]; + while (pos < l) + { + if (cstr[pos + 1] == c) + return pos; + pos++; + } + } + + return -1; +} + +string to_string(int val) +{ + char buffer[10]; + + bool sign = false; + if (val < 0) + { + val = -val; + sign = true; + } + + char i = 10; + + while (val) + { + char d = val % 10; + val /= 10; + buffer[--i] = d + '0'; + } + + if (i == 10) + buffer[--i] = '0'; + if (sign) + buffer[--i] = '-'; + + return string(buffer + i, 10 - i); +} + +string to_string(long val) +{ + char buffer[12]; + + bool sign = false; + if (val < 0) + { + val = -val; + sign = true; + } + + char i = 12; + + while (val) + { + char d = val % 10; + val /= 10; + buffer[--i] = d + '0'; + } + + if (i == 12) + buffer[--i] = '0'; + if (sign) + buffer[--i] = '-'; + + return string(buffer + i, 12 - i); +} + +string to_string(unsigned int val) +{ + char buffer[10]; + + char i = 10; + + while (val) + { + char d = val % 10; + val /= 10; + buffer[--i] = d + '0'; + } + + if (i == 10) + buffer[--i] = '0'; + + return string(buffer + i, 10 - i); +} + +string to_string(unsigned long val) +{ + char buffer[12]; + + char i = 12; + + while (val) + { + char d = val % 10; + val /= 10; + buffer[--i] = d + '0'; + } + + if (i == 12) + buffer[--i] = '0'; + + return string(buffer + i, 12 - i); +} + +static float fround5[] = { + 0.5e-0, 0.5e-1, 0.5e-2, 0.5e-3, 0.5e-4, 0.5e-5, 0.5e-6 +}; + +string to_string(float val) +{ + char buffer[20]; + + char d = 0; + + float f = val; + + if (f < 0.0) + { + f = -f; + buffer[d++] = '-'; + } + + char prefix = d; + + if (isinf(f)) + { + buffer[d++] = 'I'; + buffer[d++] = 'N'; + buffer[d++] = 'F'; + } + else + { + int exp = 0; + + char fdigits = 6; + + if (f != 0.0) + { + while (f >= 1000.0) + { + f /= 1000; + exp += 3; + } + + while (f < 1.0) + { + f *= 1000; + exp -= 3; + } + + while (f >= 10.0) + { + f /= 10; + exp ++; + } + + } + + char digits = fdigits + 1; + + while (exp < 0) + { + f /= 10.0; + exp++; + } + + digits = fdigits + exp + 1; + + if (digits < 7) + f += fround5[digits - 1]; + else + f += fround5[6]; + + if (f >= 10.0) + { + f /= 10.0; + fdigits--; + } + + char pdigits = digits - fdigits; + + if (digits > 20) + digits = 20; + + if (pdigits == 0) + buffer[d++] = '0'; + + for(char i=0; i 6) + buffer[d++] = '0'; + else + { + int c = (int)f; + f -= (float)c; + f *= 10.0; + buffer[d++] = c + '0'; + } + } + } + + return string(buffer, d); +} + + +int string::to_int(char * idx, char base) const +{ + char i = 1; + unsigned n = 0; + bool sign = false; + + if (cstr) + { + const char * cp = cstr; + + char ch = cp[i]; + + if (ch == '-') + { + sign = true; + ch = cp[++i]; + } + else if (ch == '+') + ch = cp[++i]; + + if (ch == '0' && base == 0) + { + ch = cp[++i]; + if (ch == 'x' || ch == 'X') + { + base = 16; + ch = cp[++i]; + } + else if (ch == 'b' || ch == 'B') + { + base = 2; + ch = cp[++i]; + } + } + + for(;;) + { + char d; + if (ch >= '0' && ch <= '9') + d = (ch - '0'); + else if (base > 10 && ch >= 'A' && ch <= 'F') + d = (ch - 'A' + 10); + else if (base > 10 && ch >= 'a' && ch <= 'f') + d = (ch - 'a' + 10); + else + break; + + n = n * base + d; + ch = cp[++i]; + } + } + + if (idx) + *idx = i - 1; + + if (sign) + return -(int)n; + else + return n; +} + +long string::to_long(char * idx, char base) const +{ + char i = 1; + unsigned long n = 0; + bool sign = false; + + if (cstr) + { + const char * cp = cstr; + + char ch = cp[i++]; + + if (ch == '-') + { + sign = true; + ch = cp[i++]; + } + else if (ch == '+') + ch = cp[i++]; + + if (ch == '0' && base == 0) + { + ch = cp[i++]; + if (ch == 'x' || ch == 'X') + { + base = 16; + ch = cp[i++]; + } + else if (ch == 'b' || ch == 'B') + { + base = 2; + ch = cp[i++]; + } + } + + for(;;) + { + char d; + if (ch >= '0' && ch <= '9') + d = (ch - '0'); + else if (base > 10 && ch >= 'A' && ch <= 'F') + d = (ch - 'A' + 10); + else if (base > 10 && ch >= 'a' && ch <= 'f') + d = (ch - 'a' + 10); + else + break; + + n = n * base + d; + ch = cp[i++]; + } + i--; + } + + if (idx) + *idx = i - 1; + + if (sign) + return -(long)n; + else + return n; +} + +unsigned string::to_uint(char * idx, char base) const +{ + char i = 1; + unsigned n = 0; + + if (cstr) + { + const char * cp = cstr; + + char ch = cp[i]; + + if (ch == '0' && base == 0) + { + ch = cp[++i]; + if (ch == 'x' || ch == 'X') + { + base = 16; + ch = cp[++i]; + } + else if (ch == 'b' || ch == 'B') + { + base = 2; + ch = cp[++i]; + } + } + + for(;;) + { + char d; + if (ch >= '0' && ch <= '9') + d = (ch - '0'); + else if (base > 10 && ch >= 'A' && ch <= 'F') + d = (ch - 'A' + 10); + else if (base > 10 && ch >= 'a' && ch <= 'f') + d = (ch - 'a' + 10); + else + break; + + n = n * base + d; + ch = cp[++i]; + } + } + + if (idx) + *idx = i - 1; + + return n; +} + +unsigned long string::to_ulong(char * idx, char base) const +{ + char i = 1; + unsigned long n = 0; + + if (cstr) + { + const char * cp = cstr; + + char ch = cp[i++]; + + if (ch == '0' && base == 0) + { + ch = cp[i++]; + if (ch == 'x' || ch == 'X') + { + base = 16; + ch = cp[i++]; + } + else if (ch == 'b' || ch == 'B') + { + base = 2; + ch = cp[i++]; + } + } + + for(;;) + { + char d; + if (ch >= '0' && ch <= '9') + d = (ch - '0'); + else if (base > 10 && ch >= 'A' && ch <= 'F') + d = (ch - 'A' + 10); + else if (base > 10 && ch >= 'a' && ch <= 'f') + d = (ch - 'a' + 10); + else + break; + + n = n * base + d; + ch = cp[i++]; + } + i--; + } + + if (idx) + *idx = i - 1; + + return n; +} + +float string::to_float(char * idx) const +{ + char i = 1; + float vf = 0; + bool sign = false; + + if (cstr) + { + const char * cp = cstr; + + char ch = cp[i++]; + if (ch == '-') + { + sign = true; + ch = cp[i++]; + } + else if (ch == '+') + ch = cp[i++]; + + if (ch >= '0' && ch <= '9' || ch == '.') + { + while (ch >= '0' && ch <= '9') + { + vf = vf * 10 + (int)(ch - '0'); + ch = cp[i++]; + } + + if (ch == '.') + { + float digits = 1.0; + ch = cp[i++]; + while (ch >= '0' && ch <= '9') + { + vf = vf * 10 + (int)(ch - '0'); + digits *= 10; + ch = cp[i++]; + } + vf /= digits; + } + + char e = 0; + bool eneg = false; + + if (ch == 'e' || ch == 'E') + { + ch = cp[i++]; + if (ch == '-') + { + eneg = true; + ch = cp[i++]; + } + else if (ch == '+') + { + ch = cp[i++]; + } + + while (ch >= '0' && ch <= '9') + { + e = e * 10 + ch - '0'; + ch = cp[i++]; + } + + } + + if (e) + { + if (eneg) + { + while (e > 6) + { + vf /= 1000000.0; + e -= 6; + } + vf /= tpow10[e]; + } + else + { + while (e > 6) + { + vf *= 1000000.0; + e -= 6; + } + vf *= tpow10[e]; + } + } + } + i--; + } + + if (idx) + *idx = i - 1; + + if (sign) + return -vf; + else + return vf; +} + +} diff --git a/include/opp/string.h b/include/opp/string.h new file mode 100644 index 0000000..7bbb167 --- /dev/null +++ b/include/opp/string.h @@ -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 diff --git a/include/opp/utility.h b/include/opp/utility.h new file mode 100644 index 0000000..503aa8d --- /dev/null +++ b/include/opp/utility.h @@ -0,0 +1,40 @@ +#ifndef OPP_UTILITY_H +#define OPP_UTILITY_H + +namespace opp { + +template +inline T && move(T & m) +{ + return (T &&)m; +} + +template +inline void swap(T & x, T & y) +{ + T t(x); x = y; y = move(t); +} + + +template +struct pair +{ + T1 first; + T2 second; + + pair(T1 && t1, T2 && t2) + : first(t1), second(t2) + {} +}; + +template +constexpr pair make_pair(T1 && t1, T2 && t2) +{ + return pair(t1, t2); +} + +} + + + +#endif diff --git a/include/opp/vector.h b/include/opp/vector.h new file mode 100644 index 0000000..c18c96c --- /dev/null +++ b/include/opp/vector.h @@ -0,0 +1,333 @@ +#ifndef OPP_VECTOR_H +#define OPP_VECTOR_H + +#include +#include +#include + +namespace opp { + +template +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 + void emplace_back(const P&... p); +protected: + T * add_back(void); +}; + + +template +void vector::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 +void vector::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 +void vector::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 +T * vector::add_back(void) +{ + if (_size == _capacity) + reserve(_size + 1 + (_size >> 1)); + return _data + _size++; +} + +template +void vector::push_back(const T & t) +{ + new (add_back())T(t); +} + +template +void vector::push_back(T && t) +{ + new (add_back())T(t); +} + +template +template +void vector::emplace_back(const P&... p) +{ + new (add_back())T(p...); +} + +template +void vector::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 +void vector::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 +T * vector::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 diff --git a/include/stdio.c b/include/stdio.c index 7b41fb3..944dcf6 100644 --- a/include/stdio.c +++ b/include/stdio.c @@ -183,7 +183,7 @@ void putchar(char c) { __asm { lda c - jmp putpch + jsr putpch } } diff --git a/include/stdlib.c b/include/stdlib.c index cfcbda6..7b5709e 100644 --- a/include/stdlib.c +++ b/include/stdlib.c @@ -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) { diff --git a/include/stdlib.h b/include/stdlib.h index 1761f40..4d4eac5 100644 --- a/include/stdlib.h +++ b/include/stdlib.h @@ -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 diff --git a/oscar64/Assembler.cpp b/oscar64/Assembler.cpp index f103ab6..2b9fc21 100644 --- a/oscar64/Assembler.cpp +++ b/oscar64/Assembler.cpp @@ -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; diff --git a/oscar64/BitVector.h b/oscar64/BitVector.h index ebe5300..e3c1fcf 100644 --- a/oscar64/BitVector.h +++ b/oscar64/BitVector.h @@ -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) { diff --git a/oscar64/ByteCodeGenerator.cpp b/oscar64/ByteCodeGenerator.cpp index 94181cc..c3c9b03 100644 --- a/oscar64/ByteCodeGenerator.cpp +++ b/oscar64/ByteCodeGenerator.cpp @@ -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: diff --git a/oscar64/ByteCodeGenerator.h b/oscar64/ByteCodeGenerator.h index 19871bc..fac6acb 100644 --- a/oscar64/ByteCodeGenerator.h +++ b/oscar64/ByteCodeGenerator.h @@ -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); diff --git a/oscar64/CompilationUnits.cpp b/oscar64/CompilationUnits.cpp index 11e381f..a8cf2e2 100644 --- a/oscar64/CompilationUnits.cpp +++ b/oscar64/CompilationUnits.cpp @@ -7,13 +7,15 @@ #include #include -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); diff --git a/oscar64/CompilationUnits.h b/oscar64/CompilationUnits.h index 16c334c..2891f25 100644 --- a/oscar64/CompilationUnits.h +++ b/oscar64/CompilationUnits.h @@ -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); diff --git a/oscar64/Compiler.cpp b/oscar64/Compiler.cpp index c34aa31..2a76edf 100644 --- a/oscar64/Compiler.cpp +++ b/oscar64/Compiler.cpp @@ -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); diff --git a/oscar64/Compiler.h b/oscar64/Compiler.h index 0928278..474dcce 100644 --- a/oscar64/Compiler.h +++ b/oscar64/Compiler.h @@ -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 mByteCodeFunctions; + ExpandingArray 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); }; diff --git a/oscar64/CompilerTypes.h b/oscar64/CompilerTypes.h index 9d8436e..79b8fc5 100644 --- a/oscar64/CompilerTypes.h +++ b/oscar64/CompilerTypes.h @@ -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 { diff --git a/oscar64/Constexpr.cpp b/oscar64/Constexpr.cpp new file mode 100644 index 0000000..a5692e6 --- /dev/null +++ b/oscar64/Constexpr.cpp @@ -0,0 +1,1491 @@ +#include "Constexpr.h" +#include + +ConstexprInterpreter::Value::Value(void) + : mDecType(TheVoidTypeDeclaration), + mBaseValue(nullptr), mOffset(0), + mData(mShortData), mDataSize(0) +{ +} + +ConstexprInterpreter::Value::Value(const Location & location) + : mLocation(location), + mDecType(TheVoidTypeDeclaration), + mBaseValue(nullptr), mOffset(0), + mData(mShortData), mDataSize(0) +{ +} + +ConstexprInterpreter::Value::Value(Expression* exp) + : mLocation(exp->mLocation), + mDecType(exp->mDecType), + mBaseValue(nullptr), mOffset(0), + mDataSize(exp->mDecType->mSize) +{ + assert(exp->mType == EX_CONSTANT); + + if (mDataSize <= 4) + mData = mShortData; + else + mData = new ValueItem[mDataSize]; + + PutConst(0, exp->mDecValue); +} + +void ConstexprInterpreter::Value::PutConst(int offset, Declaration* dec) +{ + switch (dec->mType) + { + case DT_CONST_INTEGER: + case DT_CONST_ADDRESS: + PutIntAt(dec->mInteger, offset, dec->mBase); + break; + case DT_CONST_FLOAT: + PutFloatAt(float(dec->mNumber), offset, dec->mBase); + break; + case DT_CONST_STRUCT: + for (Declaration* pdec = dec->mParams; pdec; pdec = pdec->mNext) + PutConst(pdec->mOffset, pdec); + break; + case DT_CONST_DATA: + for (int i = 0; i < dec->mBase->mSize; i++) + PutIntAt(dec->mData[i], offset + i, TheConstCharTypeDeclaration); + break; + } +} + +ConstexprInterpreter::Value::Value(const Location& location, Declaration* dec) + : mLocation(location), + mDecType(dec), + mBaseValue(nullptr), mOffset(0), + mDataSize(dec->mSize) +{ + if (mDataSize <= 4) + mData = mShortData; + else + mData = new ValueItem[mDataSize]; +} + +ConstexprInterpreter::Value::Value(const Location& location, Declaration* dec, int size) + : mLocation(location), + mDecType(dec), + mBaseValue(nullptr), mOffset(0), + mDataSize(size) +{ + if (mDataSize <= 4) + mData = mShortData; + else + mData = new ValueItem[mDataSize]; +} + +ConstexprInterpreter::Value::Value(const Value& value) + : mLocation(value.mLocation), + mDecType(value.mDecType), + mBaseValue(value.mBaseValue), mOffset(value.mOffset), + mDataSize(value.mDataSize) + +{ + if (mDataSize <= 4) + mData = mShortData; + else + mData = new ValueItem[mDataSize]; + + for (int i = 0; i < mDataSize; i++) + mData[i] = value.mData[i]; +} + +ConstexprInterpreter::Value::Value(Value&& value) + : mLocation(value.mLocation), + mDecType(value.mDecType), + mBaseValue(value.mBaseValue), mOffset(value.mOffset), + mDataSize(value.mDataSize) +{ + if (mDataSize <= 4) + { + mData = mShortData; + for (int i = 0; i < mDataSize; i++) + mData[i] = value.mData[i]; + } + else + { + mData = value.mData; + value.mData = value.mShortData; + } +} + +ConstexprInterpreter::Value::Value(Value* value) + : mLocation(value->mLocation), + mDecType(value->mDecType), + mBaseValue(value), mOffset(0), + mDataSize(0), mData(mShortData) +{ +} + +ConstexprInterpreter::Value::Value(const Location& location, Value* value, Declaration* type, int offset) + : mLocation(location), + mDecType(type), + mBaseValue(value), mOffset(offset), + mDataSize(0), mData(mShortData) +{ +} + +ConstexprInterpreter::Value::Value(const Location& location, const uint8* data, Declaration* type) + : mLocation(location), + mDecType(type), + mBaseValue(nullptr), mOffset(0), + mDataSize(type->mSize) +{ + if (mDataSize <= 4) + mData = mShortData; + else + mData = new ValueItem[mDataSize]; + + for (int i = 0; i < mDataSize; i++) + mData[i].mByte = data[i]; +} + +ConstexprInterpreter::Value::Value(const Location& location, const ValueItem* data, Declaration* type) + : mLocation(location), + mDecType(type), + mBaseValue(nullptr), mOffset(0), + mDataSize(type->mSize) +{ + if (mDataSize <= 4) + mData = mShortData; + else + mData = new ValueItem[mDataSize]; + + for (int i = 0; i < mDataSize; i++) + mData[i] = data[i]; +} + + +ConstexprInterpreter::Value::~Value(void) +{ + if (mData != mShortData) + delete[] mData; +} + + + +ConstexprInterpreter::Value& ConstexprInterpreter::Value::operator=(const Value& v) +{ + if (mData != mShortData) + { + delete[] mData; + mData = mShortData; + } + + mLocation = v.mLocation; + mDecType = v.mDecType; + mBaseValue = v.mBaseValue; + mDataSize = v.mDataSize; + mOffset = v.mOffset; + + if (mDataSize <= 4) + mData = mShortData; + else + mData = new ValueItem[mDataSize]; + + for (int i = 0; i < mDataSize; i++) + mData[i] = v.mData[i]; + + return *this; +} + +ConstexprInterpreter::Value& ConstexprInterpreter::Value::operator=(Value&& v) +{ + if (mData != mShortData) + { + delete[] mData; + mData = mShortData; + } + + mLocation = v.mLocation; + mDecType = v.mDecType; + mBaseValue = v.mBaseValue; + mDataSize = v.mDataSize; + mOffset = v.mOffset; + + if (mDataSize <= 4) + { + mData = mShortData; + for (int i = 0; i < mDataSize; i++) + mData[i] = v.mData[i]; + } + else + { + mData = v.mData; + v.mData = v.mShortData; + } + + return *this; +} + + +ConstexprInterpreter::ValueItem* ConstexprInterpreter::Value::GetAddr(void) +{ + if (mBaseValue) + return mBaseValue->mData + mOffset; + else + return mData; +} + +const ConstexprInterpreter::ValueItem* ConstexprInterpreter::Value::GetAddr(void) const +{ + if (mBaseValue) + return mBaseValue->mData + mOffset; + else + return mData; +} + +int64 ConstexprInterpreter::Value::GetInt(void) const +{ + return GetIntAt(0, mDecType); +} + +double ConstexprInterpreter::Value::GetFloat(void) const +{ + return GetFloatAt(0, mDecType); +} + +ConstexprInterpreter::Value ConstexprInterpreter::Value::GetPtr(void) const +{ + return GetPtrAt(0, mDecType->mBase); +} + +void ConstexprInterpreter::Value::PutInt(int64 v) +{ + PutIntAt(v, 0, mDecType); +} + +void ConstexprInterpreter::Value::PutFloat(double v) +{ + PutFloatAt(v, 0, mDecType); +} + +void ConstexprInterpreter::Value::PutPtr(const Value& v) +{ + PutPtrAt(v, 0, mDecType); +} + + +int64 ConstexprInterpreter::Value::GetIntAt(int at, Declaration* type) const +{ + if (type->mType == DT_TYPE_FLOAT) + { + return int64(GetFloatAt(at, type)); + } + else + { + const ValueItem* dp = GetAddr() + at; + + if (type->mFlags & DTF_SIGNED) + { + switch (type->mSize) + { + case 1: + return int8(dp[0].mByte); + case 2: + return int16(dp[0].mByte | ((uint32)(dp[1].mByte) << 8)); + case 4: + return int32(dp[0].mByte | ((uint32)(dp[1].mByte) << 8) | ((uint32)(dp[2].mByte) << 16) | ((uint32)(dp[3].mByte) << 24)); + } + } + else + { + switch (type->mSize) + { + case 1: + return uint8(dp[0].mByte); + case 2: + return uint16(dp[0].mByte | ((uint32)(dp[1].mByte) << 8)); + case 4: + return uint32(dp[0].mByte | ((uint32)(dp[1].mByte) << 8) | ((uint32)(dp[2].mByte) << 16) | ((uint32)(dp[3].mByte) << 24)); + } + } + } + + return 0; +} + +double ConstexprInterpreter::Value::GetFloatAt(int at, Declaration* type) const +{ + if (type->mType == DT_TYPE_FLOAT) + { + const ValueItem* dp = GetAddr() + at; + + union + { + float f; + uint32 i; + } u; + + u.i = uint32(dp[0].mByte | ((uint32)(dp[1].mByte) << 8) | ((uint32)(dp[2].mByte) << 16) | ((uint32)(dp[3].mByte) << 24)); + return u.f; + } + else + { + int64 iv = GetIntAt(at, type); + return double(iv); + } + +} + +ConstexprInterpreter::Value ConstexprInterpreter::Value::GetPtrAt(int at, Declaration* type) const +{ + const ValueItem* dp = GetAddr() + at; + + return Value(mLocation, dp->mBaseValue, type, uint16(dp[0].mByte | ((uint32)(dp[1].mByte) << 8))); +} + +void ConstexprInterpreter::Value::PutIntAt(int64 v, int at, Declaration* type) +{ + if (type->mType == DT_TYPE_FLOAT) + { + PutFloatAt(float(v), at, type); + } + else + { + ValueItem* dp = GetAddr() + at; + + switch (type->mSize) + { + case 4: + dp[3].mByte = uint8((v >> 24) & 0xff); + dp[2].mByte = uint8((v >> 16) & 0xff); + case 2: + dp[1].mByte = uint8((v >> 8) & 0xff); + case 1: + dp[0].mByte = uint8(v & 0xff); + } + } +} + +void ConstexprInterpreter::Value::PutFloatAt(double v, int at, Declaration* type) +{ + if (type->mType == DT_TYPE_FLOAT) + { + ValueItem* dp = GetAddr() + at; + + union + { + float f; + uint32 i; + } u; + + u.f = float(v); + + dp[3].mByte = uint8((u.i >> 24) & 0xff); + dp[2].mByte = uint8((u.i >> 16) & 0xff); + dp[1].mByte = uint8((u.i >> 8) & 0xff); + dp[0].mByte = uint8(u.i & 0xff); + } + else + { + PutIntAt(int64(v), at, type); + } +} + +void ConstexprInterpreter::Value::PutPtrAt(const Value& v, int at, Declaration* type) +{ + ValueItem* dp = GetAddr() + at; + + dp[0].mBaseValue = v.mBaseValue; + dp[1].mByte = uint8((v.mOffset >> 8) & 0xff); + dp[0].mByte = uint8(v.mOffset & 0xff); +} + +ConstexprInterpreter::Value ConstexprInterpreter::Value::ToRValue(void) const +{ + if (mBaseValue) + return Value(mLocation, GetAddr(), mDecType); + else + return *this; +} + +void ConstexprInterpreter::Value::Assign(const Value& v) +{ + switch (mDecType->mType) + { + case DT_TYPE_INTEGER: + case DT_TYPE_BOOL: + PutInt(v.GetInt()); + break; + case DT_TYPE_FLOAT: + PutFloat(v.GetFloat()); + break; + case DT_TYPE_STRUCT: + case DT_TYPE_UNION: + case DT_TYPE_ARRAY: + { + const ConstexprInterpreter::ValueItem* sp = v.GetAddr(); + ConstexprInterpreter::ValueItem* dp = GetAddr(); + + for (int i = 0; i < mDecType->mSize; i++) + dp[i] = sp[i]; + } break; + case DT_TYPE_POINTER: + PutPtr(v.GetPtr()); + break; + } +} + +Declaration* ConstexprInterpreter::Value::GetConst(int offset, Declaration* type, LinkerSection* dataSection) const +{ + Declaration* dec = nullptr; + + switch (type->mType) + { + case DT_TYPE_INTEGER: + case DT_TYPE_BOOL: + case DT_TYPE_ENUM: + dec = new Declaration(mLocation, DT_CONST_INTEGER); + dec->mBase = type; + dec->mFlags = type->mFlags & DTF_SIGNED; + dec->mSize = type->mSize; + dec->mInteger = GetIntAt(offset, type); + break; + case DT_TYPE_FLOAT: + dec = new Declaration(mLocation, DT_CONST_FLOAT); + dec->mBase = type; + dec->mSize = type->mSize; + dec->mNumber = GetFloatAt(offset, type); + break; + case DT_TYPE_STRUCT: + { + dec = new Declaration(mLocation, DT_CONST_STRUCT); + dec->mBase = type; + dec->mSize = type->mSize; + dec->mSection = dataSection; + dec->mOffset = offset; + + while (type) + { + for (Declaration* mdec = type->mParams; mdec; mdec = mdec->mNext) + { + Declaration* cdec = GetConst(offset + mdec->mOffset, mdec->mBase, dataSection); + cdec->mOffset = mdec->mOffset; + cdec->mNext = dec->mParams; + dec->mParams = cdec; + } + + if (type->mVTable) + { + Declaration * cdec = new Declaration(mLocation, DT_CONST_INTEGER); + cdec->mBase = TheConstCharTypeDeclaration; + cdec->mSize = 1; + cdec->mInteger = type->mVTable->mDefaultConstructor->mInteger; + cdec->mOffset = offset + type->mVTable->mOffset; + cdec->mNext = dec->mParams; + dec->mParams = cdec; + } + + if (type->mBase) + type = type->mBase->mBase; + else + type = nullptr; + } + break; + } + case DT_TYPE_ARRAY: + { + dec = new Declaration(mLocation, DT_CONST_STRUCT); + dec->mBase = type; + dec->mSize = type->mSize; + dec->mSection = dataSection; + dec->mOffset = offset; + Declaration* ldec = nullptr; + for (int i=0; imSize; i += type->mBase->mSize) + { + Declaration* cdec = GetConst(offset + i, type->mBase, dataSection); + cdec->mOffset = i; + + if (ldec) + ldec->mNext = cdec; + else + dec->mParams = cdec; + + ldec = cdec; + } + break; + } + case DT_TYPE_POINTER: + { + Value vp = GetPtrAt(offset, type); + if (vp.mBaseValue) + { + dec = new Declaration(mLocation, DT_CONST_POINTER); + dec->mBase = type; + dec->mSize = type->mSize; + + Declaration* target; + + if (vp.mBaseValue->mDecType->mType == DT_TYPE_ARRAY) + { + target = new Declaration(mLocation, DT_CONST_DATA); + target->mSize = vp.mBaseValue->mDataSize; + target->mBase = vp.mBaseValue->mDecType; + target->mSection = dataSection; + + uint8* buffer = new uint8[target->mSize]; + for (int i = 0; i < target->mSize; i++) + buffer[i] = uint8(vp.mBaseValue->GetIntAt(i, TheUnsignedCharTypeDeclaration)); + target->mData = buffer; + } + else + target = vp.mBaseValue->GetConst(0, vp.mBaseValue->mDecType, dataSection); + + dec->mValue = new Expression(mLocation, EX_CONSTANT); + dec->mValue->mDecType = target->mBase; + dec->mValue->mDecValue = target; + } + else + { + dec = new Declaration(mLocation, DT_CONST_ADDRESS); + dec->mBase = type; + dec->mFlags = 0; + dec->mSize = type->mSize; + dec->mInteger = vp.mOffset; + } + break; + } + + } + + return dec; +} + +Expression* ConstexprInterpreter::Value::ToExpression(LinkerSection* dataSection) const +{ + Expression* exp = new Expression(mLocation, EX_CONSTANT); + + exp->mDecType = mDecType; + exp->mDecValue = GetConst(0, mDecType, dataSection); + + return exp; +} + + +ConstexprInterpreter::ConstexprInterpreter(const Location & location, Errors* err, LinkerSection* dataSection) + : mLocation(location), mErrors(err), mDataSection(dataSection), mParams(Value()), mLocals(Value()), mHeap(nullptr) +{ + +} + +ConstexprInterpreter::~ConstexprInterpreter(void) +{ + for (int i = 0; i < mTemps.Size(); i++) + delete mTemps[i]; +} + +ConstexprInterpreter::Value* ConstexprInterpreter::NewValue(Expression* exp, Declaration* type, int size) +{ + Value* v = new Value(exp->mLocation, type, size); + mHeap->Push(v); + return v; +} + +void ConstexprInterpreter::DeleteValue(Value* v) +{ + int i = mHeap->IndexOf(v); + if (i >= 0) + { + delete v; + mHeap->Remove(i); + } + else + mErrors->Error(v->mLocation, EERR_DOUBLE_FREE, "Freeing not allocated memory"); +} + +Expression* ConstexprInterpreter::EvalConstructor(Expression* exp) +{ + mProcType = exp->mLeft->mDecType; + + Declaration* cdec = exp->mLeft->mDecType->mParams; + + int pos = 0; + mResult = Value(exp->mLocation, cdec->mBase->mBase); + mParams[pos] = Value(exp->mLocation, cdec->mBase); + mParams[pos].PutPtr(Value(&mResult)); + pos = 2; + + mHeap = new ExpandingArray(); + + Execute(exp->mLeft->mDecValue->mValue); + + if (mHeap->Size() > 0) + mErrors->Error(exp->mLocation, EERR_UNBALANCED_HEAP_USE, "Unbalanced heap use in constexpr"); + delete mHeap; + + return mResult.ToExpression(mDataSection); +} + +Expression* ConstexprInterpreter::EvalTempConstructor(Expression* exp) +{ + Expression* cexp = exp->mLeft->mLeft; + + mProcType = cexp->mLeft->mDecType; + + Expression* pex = cexp->mRight; + Declaration* dec = cexp->mLeft->mDecType->mParams; + + Value othis = Value(exp->mLocation, exp->mRight->mDecType); + + mParams[0] = Value(exp->mLocation, dec->mBase); + mParams[0].PutPtr(Value(&othis)); + + int pos = 2; + if (pex->mType == EX_LIST) + pex = pex->mRight; + else + pex = nullptr; + dec = dec->mNext; + + while (pex && pex->mType == EX_LIST) + { + if (!AddParam(pos, pex->mLeft, dec)) + return exp; + + pex = pex->mRight; + if (dec) + dec = dec->mNext; + } + + if (pex) + { + if (!AddParam(pos, pex, dec)) + return exp; + } + + mHeap = new ExpandingArray(); + + Execute(cexp->mLeft->mDecValue->mValue); + + if (mHeap->Size() > 0) + mErrors->Error(exp->mLocation, EERR_UNBALANCED_HEAP_USE, "Unbalanced heap use in constexpr"); + delete mHeap; + + return othis.ToExpression(mDataSection); +} + +bool ConstexprInterpreter::AddParam(int& pos, Expression* pex, Declaration* dec) +{ + if (dec) + pos = dec->mVarIndex; + + if (pex->mType == EX_CONSTANT) + { + if (pex->mDecType->mType == DT_TYPE_ARRAY) + { + Value* tmp = new Value(pex); + mTemps.Push(tmp); + mParams[pos] = Value(pex->mLocation, pex->mDecType->BuildArrayPointer()); + mParams[pos].PutPtr(Value(tmp)); + } + else + mParams[pos] = Value(pex); + } + else if (pex->mType == EX_VARIABLE && (pex->mDecValue->mFlags & DTF_CONST)) + { + mParams[pos] = Value(pex->mLocation, pex->mDecValue->mBase); + if (pex->mDecValue->mSize > 0) + mParams[pos].PutConst(0, pex->mDecValue->mValue->mDecValue); + } + else + return false; + + return true; +} + +Expression* ConstexprInterpreter::EvalCall(Expression* exp) +{ + mProcType = exp->mLeft->mDecType; + + Expression* pex = exp->mRight; + Declaration* dec = exp->mLeft->mDecType->mParams; + + int pos = 0; + if (mProcType->mBase && mProcType->mBase->mType == DT_TYPE_STRUCT) + { + mResult = Value(exp->mLocation, mProcType->mBase); + mParams[0] = Value(&mResult); + pos = 2; + } + + while (pex && pex->mType == EX_LIST) + { + if (!AddParam(pos, pex->mLeft, dec)) + return exp; + + pex = pex->mRight; + if (dec) + dec = dec->mNext; + } + + if (pex) + { + if (!AddParam(pos, pex, dec)) + return exp; + } + + mHeap = new ExpandingArray(); + + Execute(exp->mLeft->mDecValue->mValue); + + if (mHeap->Size() > 0) + mErrors->Error(exp->mLocation, EERR_UNBALANCED_HEAP_USE, "Unbalanced heap use in constexpr"); + delete mHeap; + + return mResult.ToExpression(mDataSection); +} + +ConstexprInterpreter::Value ConstexprInterpreter::EvalBinary(Expression * exp, const Value& vl, const Value& vr) +{ + Value v(exp->mLocation, exp->mDecType); + + if (exp->mDecType->mType == DT_TYPE_FLOAT) + { + switch (exp->mToken) + { + case TK_ADD: + case TK_ASSIGN_ADD: + v.PutFloat(vl.GetFloat() + vr.GetFloat()); + break; + case TK_SUB: + case TK_ASSIGN_SUB: + v.PutFloat(vl.GetFloat() - vr.GetFloat()); + break; + case TK_MUL: + case TK_ASSIGN_MUL: + v.PutFloat(vl.GetFloat() * vr.GetFloat()); + break; + case TK_DIV: + case TK_ASSIGN_DIV: + if (vr.GetInt() == 0) + mErrors->Error(exp->mLocation, EERR_INVALID_VALUE, "Constant division by zero"); + else + v.PutFloat(vl.GetFloat() / vr.GetFloat()); + break; + default: + mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Incompatible operator", TokenNames[exp->mToken]); + } + } + else if (exp->mDecType->mType == DT_TYPE_POINTER) + { + Value vlp = vl.GetPtr(); + vlp.mOffset += int(vr.GetInt() * vl.mDecType->mBase->mSize); + v.PutPtr(vlp); + } + else + { + switch (exp->mToken) + { + case TK_ADD: + case TK_ASSIGN_ADD: + v.PutInt(vl.GetInt() + vr.GetInt()); + break; + case TK_SUB: + case TK_ASSIGN_SUB: + v.PutInt(vl.GetInt() - vr.GetInt()); + break; + case TK_MUL: + case TK_ASSIGN_MUL: + v.PutInt(vl.GetInt() * vr.GetInt()); + break; + case TK_DIV: + case TK_ASSIGN_DIV: + if (vr.GetInt() == 0) + mErrors->Error(exp->mLocation, EERR_INVALID_VALUE, "Constant division by zero"); + else + v.PutInt(vl.GetInt() / vr.GetInt()); + break; + case TK_MOD: + case TK_ASSIGN_MOD: + if (vr.GetInt() == 0) + mErrors->Error(exp->mLocation, EERR_INVALID_VALUE, "Constant division by zero"); + else + v.PutInt(vl.GetInt() % vr.GetInt()); + break; + case TK_LEFT_SHIFT: + case TK_ASSIGN_SHL: + v.PutInt(vl.GetInt() << vr.GetInt()); + break; + case TK_RIGHT_SHIFT: + case TK_ASSIGN_SHR: + v.PutInt(vl.GetInt() >> vr.GetInt()); + break; + case TK_BINARY_AND: + case TK_ASSIGN_AND: + v.PutInt(vl.GetInt() & vr.GetInt()); + break; + case TK_BINARY_OR: + case TK_ASSIGN_OR: + v.PutInt(vl.GetInt() | vr.GetInt()); + break; + case TK_BINARY_XOR: + case TK_ASSIGN_XOR: + v.PutInt(vl.GetInt() ^ vr.GetInt()); + break; + default: + mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Incompatible operator", TokenNames[exp->mToken]); + } + } + + return v; +} + +ConstexprInterpreter::Value ConstexprInterpreter::EvalRelational(Expression* exp, const Value& vl, const Value& vr) +{ + Value v(exp->mLocation, TheBoolTypeDeclaration); + + bool check = false; + if (vl.mDecType->mType == DT_TYPE_FLOAT || vr.mDecType->mType == DT_TYPE_FLOAT) + { + switch (exp->mToken) + { + case TK_EQUAL: + check = vl.GetFloat() == vr.GetFloat(); + break; + case TK_NOT_EQUAL: + check = vl.GetFloat() != vr.GetFloat(); + break; + case TK_GREATER_THAN: + check = vl.GetFloat() > vr.GetFloat(); + break; + case TK_GREATER_EQUAL: + check = vl.GetFloat() >= vr.GetFloat(); + break; + case TK_LESS_THAN: + check = vl.GetFloat() < vr.GetFloat(); + break; + case TK_LESS_EQUAL: + check = vl.GetFloat() <= vr.GetFloat(); + break; + default: + mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Incompatible operator", TokenNames[exp->mToken]); + } + } + else if (vl.mDecType->mType == DT_TYPE_POINTER && vr.mDecType->mType == DT_TYPE_POINTER) + { + Value pl = vl.GetPtr(); + Value pr = vr.GetPtr(); + + if (pl.mBaseValue == pr.mBaseValue) + { + switch (exp->mToken) + { + case TK_EQUAL: + check = pl.mOffset == pr.mOffset; + break; + case TK_NOT_EQUAL: + check = pl.mOffset != pr.mOffset; + break; + case TK_GREATER_THAN: + check = pl.mOffset > pr.mOffset; + break; + case TK_GREATER_EQUAL: + check = pl.mOffset >= pr.mOffset; + break; + case TK_LESS_THAN: + check = pl.mOffset < pr.mOffset; + break; + case TK_LESS_EQUAL: + check = pl.mOffset <= pr.mOffset; + break; + default: + mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Incompatible operator", TokenNames[exp->mToken]); + } + } + else + { + switch (exp->mToken) + { + case TK_EQUAL: + check = false; + break; + case TK_NOT_EQUAL: + check = true; + break; + default: + mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Incompatible operator", TokenNames[exp->mToken]); + } + } + } + else + { + switch (exp->mToken) + { + case TK_EQUAL: + check = vl.GetInt() == vr.GetInt(); + break; + case TK_NOT_EQUAL: + check = vl.GetInt() != vr.GetInt(); + break; + case TK_GREATER_THAN: + check = vl.GetInt() > vr.GetInt(); + break; + case TK_GREATER_EQUAL: + check = vl.GetInt() >= vr.GetInt(); + break; + case TK_LESS_THAN: + check = vl.GetInt() < vr.GetInt(); + break; + case TK_LESS_EQUAL: + check = vl.GetInt() <= vr.GetInt(); + break; + default: + mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Incompatible operator", TokenNames[exp->mToken]); + } + } + + v.PutInt(check ? 1 : 0); + + return v; +} + +ConstexprInterpreter::Value ConstexprInterpreter::EvalUnary(Expression* exp, const Value& vl) +{ + Value v(exp->mLocation, exp->mDecType); + + if (exp->mDecType->mType == DT_TYPE_FLOAT) + { + switch (exp->mToken) + { + case TK_ADD: + v.PutFloat(vl.GetFloat()); + break; + case TK_SUB: + v.PutFloat(-vl.GetFloat()); + break; + case TK_INC: + v.PutFloat(vl.GetFloat() + 1); + break; + case TK_DEC: + v.PutFloat(vl.GetFloat() - 1); + break; + case TK_MUL: + return vl.GetPtr(); + default: + mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Incompatible operator", TokenNames[exp->mToken]); + } + } + else + { + switch (exp->mToken) + { + case TK_ADD: + v.PutInt(vl.GetInt()); + break; + case TK_SUB: + v.PutInt(-vl.GetInt()); + break; + case TK_BINARY_NOT: + v.PutInt(~vl.GetInt()); + break; + case TK_INC: + v.PutInt(vl.GetInt() + 1); + break; + case TK_DEC: + v.PutInt(vl.GetInt() - 1); + break; + case TK_BINARY_AND: + if (vl.mBaseValue) + v.PutPtr(vl); + else + mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Not an addressable value"); + break; + case TK_MUL: + return vl.GetPtr(); + case TK_NEW: + v.PutPtr(Value(NewValue(exp, exp->mDecType->mBase, int(vl.GetInt())))); + break; + case TK_DELETE: + DeleteValue(vl.GetPtr().mBaseValue); + break; + default: + mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Incompatible operator", TokenNames[exp->mToken]); + } + } + + return v; +} + +ConstexprInterpreter::Value ConstexprInterpreter::EvalTypeCast(Expression* exp, const Value& vl, Declaration* type) +{ + Value v(exp->mLocation, type); + + if (type->mType == DT_TYPE_FLOAT) + v.PutFloat(vl.GetFloat()); + else if (type->IsIntegerType()) + v.PutInt(vl.GetInt()); + + return v; +} + +ConstexprInterpreter::Value ConstexprInterpreter::REval(Expression* exp) +{ + return Eval(exp).ToRValue(); +} + +ConstexprInterpreter::Value ConstexprInterpreter::EvalCall(Expression* exp, ConstexprInterpreter* caller) +{ + mHeap = caller->mHeap; + + mProcType = exp->mLeft->mDecType; + + Expression* pex = exp->mRight; + Declaration* dec = exp->mLeft->mDecType->mParams; + + int pos = 0; + if (mProcType->mBase && mProcType->mBase->mType == DT_TYPE_STRUCT) + { + mResult = Value(exp->mLocation, mProcType->mBase); + mParams[0] = Value(&mResult); + pos = 2; + } + + while (pex && pex->mType == EX_LIST) + { + if (dec) + pos = dec->mVarIndex; + + if (dec) + mParams[pos] = caller->EvalCoerce(pex->mLeft, caller->Eval(pex->mLeft), dec->mBase); + else + mParams[pos] = caller->REval(pex->mLeft); + + pos += dec->mSize; + pex = pex->mRight; + if (dec) + dec = dec->mNext; + } + if (pex) + { + if (dec) + pos = dec->mVarIndex; + if (dec) + mParams[pos] = caller->EvalCoerce(pex, caller->Eval(pex), dec->mBase); + else + mParams[pos] = caller->REval(pex); + } + + if (exp->mLeft->mDecValue->mFlags & DTF_INTRINSIC) + { + const Ident* iname = exp->mLeft->mDecValue->mIdent; + + if (!strcmp(iname->mString, "fabs")) + { + mResult = Value(exp->mLocation, TheFloatTypeDeclaration); + mResult.PutFloat(fabs(mParams[0].GetFloat())); + } + else if (!strcmp(iname->mString, "floor")) + { + mResult = Value(exp->mLocation, TheFloatTypeDeclaration); + mResult.PutFloat(floor(mParams[0].GetFloat())); + } + else if (!strcmp(iname->mString, "ceil")) + { + mResult = Value(exp->mLocation, TheFloatTypeDeclaration); + mResult.PutFloat(ceil(mParams[0].GetFloat())); + } + else if (!strcmp(iname->mString, "sin")) + { + mResult = Value(exp->mLocation, TheFloatTypeDeclaration); + mResult.PutFloat(sin(mParams[0].GetFloat())); + } + else if (!strcmp(iname->mString, "cos")) + { + mResult = Value(exp->mLocation, TheFloatTypeDeclaration); + mResult.PutFloat(cos(mParams[0].GetFloat())); + } + else + mErrors->Error(exp->mLeft->mDecValue->mLocation, EERR_OBJECT_NOT_FOUND, "Unknown intrinsic function", iname); + } + else + { + Execute(exp->mLeft->mDecValue->mValue); + UnwindDestructStack(0); + } + + return mResult; +} + +ConstexprInterpreter::Value ConstexprInterpreter::EvalCoerce(Expression* exp, const Value& vl, Declaration* type) +{ + if (type->IsReference()) + return vl; + else + { + Value v = vl.ToRValue(); + while (v.mDecType->IsReference()) + v.mDecType = v.mDecType->mBase; + + if (type->mType == DT_TYPE_FLOAT && v.mDecType->IsIntegerType()) + { + Value vf(exp->mLocation, type); + vf.PutFloat(v.GetFloat()); + v = vf; + } + else if (v.mDecType->mType == DT_TYPE_FLOAT && type->IsIntegerType()) + { + Value vf(exp->mLocation, type); + vf.PutInt(v.GetInt()); + v = vf; + } + + return v; + } +} + +ConstexprInterpreter::Value ConstexprInterpreter::Eval(Expression* exp) +{ + switch (exp->mType) + { + case EX_SCOPE: + return Eval(exp->mLeft); + case EX_CONSTANT: + return Value(exp); + case EX_VARIABLE: + if (exp->mDecValue->mType == DT_ARGUMENT) + { + if (mParams[exp->mDecValue->mVarIndex].mBaseValue) + return mParams[exp->mDecValue->mVarIndex]; + else + return Value(&mParams[exp->mDecValue->mVarIndex]); + } + else if (exp->mDecValue->mType == DT_VARIABLE) + { + if (!(exp->mDecValue->mFlags & (DTF_STATIC | DTF_GLOBAL))) + { + if (!mLocals[exp->mDecValue->mVarIndex].mDataSize) + { + mLocals[exp->mDecValue->mVarIndex] = Value(exp->mDecValue->mLocation, exp->mDecValue->mBase); + return Value(&mLocals[exp->mDecValue->mVarIndex]); + } + else if (mLocals[exp->mDecValue->mVarIndex].mBaseValue) + return mLocals[exp->mDecValue->mVarIndex]; + else + return Value(&mLocals[exp->mDecValue->mVarIndex]); + } + } + break; + case EX_BINARY: + return EvalBinary(exp, REval(exp->mLeft), REval(exp->mRight)); + + case EX_RELATIONAL: + return EvalRelational(exp, REval(exp->mLeft), REval(exp->mRight)); + + case EX_PREFIX: + return EvalUnary(exp, Eval(exp->mLeft)); + + case EX_TYPECAST: + return EvalTypeCast(exp, REval(exp->mLeft), exp->mDecType); + + case EX_CALL: + { + ConstexprInterpreter cinter(exp->mLocation, mErrors, mDataSection); + return cinter.EvalCall(exp, this); + } + + case EX_LIST: + case EX_COMMA: + Eval(exp->mLeft); + return Eval(exp->mRight); + + case EX_CONDITIONAL: + { + Value v = REval(exp->mLeft); + if (v.GetInt()) + return Eval(exp->mRight->mLeft); + else + return Eval(exp->mRight->mRight); + } + + case EX_LOGICAL_AND: + { + Value v = REval(exp->mLeft); + if (!v.GetInt()) + return v; + else + return REval(exp->mRight); + } + + case EX_LOGICAL_OR: + { + Value v = REval(exp->mLeft); + if (v.GetInt()) + return v; + else + return REval(exp->mRight); + } + + case EX_LOGICAL_NOT: + { + Value v(exp->mLocation, TheBoolTypeDeclaration); + Value vr = REval(exp->mLeft); + if (v.GetInt()) + v.PutInt(0); + else + v.PutInt(1); + return v; + } + + case EX_INITIALIZATION: + case EX_ASSIGNMENT: + { + Value lexp = Eval(exp->mLeft); + Value rexp = REval(exp->mRight); + + if (exp->mToken != TK_ASSIGN) + rexp = EvalBinary(exp, lexp.ToRValue(), rexp); + lexp.Assign(EvalCoerce(exp, rexp, lexp.mDecType)); + return lexp; + } + + case EX_POSTINCDEC: + { + Value vl = Eval(exp->mLeft); + Value vr = vl.ToRValue(); + vl.Assign(EvalUnary(exp, vr)); + return vr; + } + + case EX_PREINCDEC: + { + Value vl = Eval(exp->mLeft); + vl.Assign(EvalUnary(exp, vl.ToRValue())); + return vl; + } + + case EX_QUALIFY: + { + Value v = Eval(exp->mLeft); + if (v.mBaseValue) + return Value(exp->mLocation, v.mBaseValue, exp->mDecType, v.mOffset + exp->mDecValue->mOffset); + break; + } + + case EX_INDEX: + { + Value v = Eval(exp->mLeft); + Value vi = REval(exp->mRight); + + if (v.mDecType->mType == DT_TYPE_ARRAY) + { + if (v.mBaseValue) + return Value(exp->mLocation, v.mBaseValue, exp->mDecType, v.mOffset + v.mDecType->mBase->mSize * int(vi.GetInt())); + } + else if (v.mDecType->mType == DT_TYPE_POINTER) + { + Value p = v.GetPtr(); + return Value(exp->mLocation, p.mBaseValue, exp->mDecType, p.mOffset + v.mDecType->mBase->mSize * int(vi.GetInt())); + } + break; + } + + case EX_RESULT: + if (mParams[0].mBaseValue) + return mParams[0]; + else + return Value(&mParams[0]); + + case EX_CONSTRUCT: + if (exp->mLeft->mLeft) + Eval(exp->mLeft->mLeft); + return Eval(exp->mRight); + + case EX_VOID: + return Value(exp->mLocation); + + } + + mErrors->Error(exp->mLocation, EERR_INVALID_CONSTEXPR, "Invalid constexpr"); + + return Value(); +} + +ConstexprInterpreter::Flow ConstexprInterpreter::Execute(Expression* exp) +{ + for (;;) + { + switch (exp->mType) + { + case EX_SCOPE: + { + int ds = mDestructStack.Size(); + Flow f = Execute(exp->mLeft); + UnwindDestructStack(ds); + + return f; + } + + case EX_RETURN: + mResult = EvalCoerce(exp, Eval(exp->mLeft), mProcType->mBase); + return FLOW_RETURN; + case EX_CONSTANT: + case EX_VARIABLE: + case EX_BINARY: + case EX_RELATIONAL: + case EX_PREFIX: + case EX_TYPECAST: + case EX_CALL: + case EX_COMMA: + case EX_LIST: + case EX_CONDITIONAL: + case EX_LOGICAL_AND: + case EX_LOGICAL_OR: + case EX_LOGICAL_NOT: + case EX_INITIALIZATION: + case EX_ASSIGNMENT: + case EX_POSTINCDEC: + case EX_PREINCDEC: + case EX_QUALIFY: + case EX_INDEX: + case EX_RESULT: + Eval(exp); + return FLOW_NEXT; + + case EX_SEQUENCE: + if (exp->mRight) + { + Flow f = Execute(exp->mLeft); + if (f == FLOW_NEXT) + return Execute(exp->mRight); + return f; + } + else + return Execute(exp->mLeft); + + case EX_BREAK: + return FLOW_BREAK; + + case EX_CONTINUE: + return FLOW_CONTINUE; + + case EX_IF: + if (REval(exp->mLeft).GetInt()) + return Execute(exp->mRight->mLeft); + else if (exp->mRight->mRight) + return Execute(exp->mRight->mRight); + else + return FLOW_NEXT; + + case EX_SWITCH: + { + int64 v = REval(exp->mLeft).GetInt(); + + bool found = false; + Expression* sexp = exp->mRight; + while (sexp) + { + Expression* cexp = sexp->mLeft; + if (found || cexp->mType == EX_DEFAULT || v == REval(cexp->mLeft).GetInt()) + { + found = true; + if (cexp->mRight) + { + Flow f = Execute(cexp->mRight); + if (f == FLOW_BREAK) + return FLOW_NEXT; + else if (f != FLOW_NEXT) + return f; + } + } + sexp = sexp->mRight; + } + + return FLOW_NEXT; + } + + case EX_WHILE: + { + int ds = mDestructStack.Size(); + while (REval(exp->mLeft).GetInt()) + { + int ls = mDestructStack.Size(); + Flow f = Execute(exp->mRight); + UnwindDestructStack(ls); + + if (f == FLOW_RETURN) + return FLOW_RETURN; + else if (f == FLOW_BREAK) + break; + } + UnwindDestructStack(ds); + return FLOW_NEXT; + } + + case EX_DO: + { + int ds = mDestructStack.Size(); + do { + int ls = mDestructStack.Size(); + Flow f = Execute(exp->mRight); + UnwindDestructStack(ls); + + if (f == FLOW_RETURN) + return FLOW_RETURN; + else if (f == FLOW_BREAK) + break; + + } while (REval(exp->mLeft).GetInt()); + UnwindDestructStack(ds); + return FLOW_NEXT; + } + + case EX_FOR: + { + int ds = mDestructStack.Size(); + if (exp->mLeft->mRight) + Eval(exp->mLeft->mRight); + + while (!exp->mLeft->mLeft->mLeft || REval(exp->mLeft->mLeft->mLeft).GetInt()) + { + int ls = mDestructStack.Size(); + Flow f = Execute(exp->mRight); + UnwindDestructStack(ls); + + if (f == FLOW_RETURN) + return FLOW_RETURN; + else if (f == FLOW_BREAK) + break; + + if (exp->mLeft->mLeft->mRight) + Eval(exp->mLeft->mLeft->mRight); + } + UnwindDestructStack(ds); + + return FLOW_NEXT; + } + + case EX_CONSTRUCT: + if (exp->mLeft->mLeft) + Eval(exp->mLeft->mLeft); + + if (exp->mLeft->mRight) + mDestructStack.Push(exp->mLeft->mRight); + + if (exp->mRight) + return Execute(exp->mRight); + return FLOW_NEXT; + + case EX_VOID: + return FLOW_NEXT; + + default: + mErrors->Error(exp->mLocation, EERR_INVALID_CONSTEXPR, "Invalid constexpr"); + } + } +} + +void ConstexprInterpreter::UnwindDestructStack(int level) +{ + while (mDestructStack.Size() > level) + Eval(mDestructStack.Pop()); +} + +ConstexprInterpreter::ValueItem::ValueItem(void) + : mByte(0), mBaseValue(nullptr) +{ +} diff --git a/oscar64/Constexpr.h b/oscar64/Constexpr.h new file mode 100644 index 0000000..7cfc825 --- /dev/null +++ b/oscar64/Constexpr.h @@ -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 mParams, mLocals; + ExpandingArray mDestructStack; + ExpandingArray * mHeap; + ExpandingArray mTemps; + + Errors * mErrors; + Value mResult; + +}; \ No newline at end of file diff --git a/oscar64/Declaration.cpp b/oscar64/Declaration.cpp index ee4bc30..19ab071 100644 --- a/oscar64/Declaration.cpp +++ b/oscar64/Declaration.cpp @@ -1,4 +1,6 @@ #include "Declaration.h" +#include "Constexpr.h" +#include DeclarationScope::DeclarationScope(DeclarationScope* parent, ScopeLevel level, const Ident* name) { @@ -10,6 +12,19 @@ DeclarationScope::DeclarationScope(DeclarationScope* parent, ScopeLevel level, c mHash = nullptr; } +void DeclarationScope::Clear(void) +{ + mHashFill = 0; + if (mHash) + { + for (int i = 0; i < mHashSize; i++) + { + mHash[i].mDec = nullptr; + mHash[i].mIdent = nullptr; + } + } +} + DeclarationScope::~DeclarationScope(void) { delete[] mHash; @@ -17,7 +32,7 @@ DeclarationScope::~DeclarationScope(void) const Ident* DeclarationScope::Mangle(const Ident* ident) const { - if (mName) + if (mName && ident) { char buffer[200]; strcpy_s(buffer, mName->mString); @@ -92,8 +107,8 @@ Declaration* DeclarationScope::Lookup(const Ident* ident, ScopeLevel limit) if (mHashSize > 0) { - int hm = mHashSize - 1; - int hi = ident->mHash & hm; + unsigned int hm = mHashSize - 1; + unsigned int hi = ident->mHash & hm; while (mHash[hi].mIdent) { @@ -103,14 +118,20 @@ Declaration* DeclarationScope::Lookup(const Ident* ident, ScopeLevel limit) } } + if (limit == SLEVEL_SCOPE) + return nullptr; + for (int i = 0; i < mUsed.Size(); i++) { - Declaration* dec = mUsed[i]->Lookup(ident); + Declaration* dec = mUsed[i]->Lookup(ident, SLEVEL_NAMESPACE); if (dec) return dec; } - return mParent ? mParent->Lookup(ident) : nullptr; + if (limit == SLEVEL_USING) + return nullptr; + + return mParent ? mParent->Lookup(ident, limit) : nullptr; } void DeclarationScope::End(const Location& loc) @@ -123,7 +144,7 @@ void DeclarationScope::End(const Location& loc) } Expression::Expression(const Location& loc, ExpressionType type) - : mLocation(loc), mEndLocation(loc), mType(type), mLeft(nullptr), mRight(nullptr), mConst(false) + : mLocation(loc), mEndLocation(loc), mType(type), mLeft(nullptr), mRight(nullptr), mConst(false), mDecType(nullptr), mDecValue(nullptr), mToken(TK_NONE) { } @@ -133,6 +154,170 @@ Expression::~Expression(void) } +void Expression::Dump(int ident) const +{ + for (int i = 0; i < ident; i++) + printf("| "); + + switch (mType) + { + case EX_ERROR: + printf("ERROR"); + break; + case EX_VOID: + printf("VOID"); + break; + case EX_CONSTANT: + printf("CONST"); + if (mDecValue->mIdent) + printf(" '%s'", mDecValue->mIdent->mString); + break; + case EX_VARIABLE: + printf("VAR"); + if (mDecValue->mIdent) + printf(" '%s'", mDecValue->mIdent->mString); + break; + case EX_ASSIGNMENT: + printf("ASSIGN<%s>", TokenNames[mToken]); + break; + case EX_INITIALIZATION: + printf("INIT"); + break; + case EX_BINARY: + printf("BINARY<%s>", TokenNames[mToken]); + break; + case EX_RELATIONAL: + printf("RELATIONAL<%s>", TokenNames[mToken]); + break; + case EX_PREINCDEC: + printf("PREOP<%s>", TokenNames[mToken]); + break; + case EX_PREFIX: + printf("PREFIX<%s>", TokenNames[mToken]); + break; + case EX_POSTFIX: + printf("POSTFIX<%s>", TokenNames[mToken]); + break; + case EX_POSTINCDEC: + printf("POSTOP<%s>", TokenNames[mToken]); + break; + case EX_INDEX: + printf("INDEX"); + break; + case EX_QUALIFY: + printf("QUALIFY<%s>", mDecValue->mIdent->mString); + break; + case EX_CALL: + printf("CALL"); + break; + case EX_INLINE: + printf("INLINE"); + break; + case EX_VCALL: + printf("VCALL"); + break; + case EX_DISPATCH: + printf("DISPATCH"); + break; + case EX_LIST: + printf("LIST"); + break; + case EX_COMMA: + printf("COMMA"); + break; + case EX_RETURN: + printf("RETURN"); + break; + case EX_SEQUENCE: + printf("SEQUENCE"); + break; + case EX_WHILE: + printf("WHILE"); + break; + case EX_IF: + printf("IF"); + break; + case EX_ELSE: + printf("ELSE"); + break; + case EX_FOR: + printf("FOR"); + break; + case EX_DO: + printf("DO"); + break; + case EX_SCOPE: + printf("SCOPE"); + break; + case EX_BREAK: + printf("BREAK"); + break; + case EX_CONTINUE: + printf("CONTINUE"); + break; + case EX_TYPE: + printf("TYPE"); + break; + case EX_TYPECAST: + printf("TYPECAST"); + break; + case EX_LOGICAL_AND: + printf("AND"); + break; + case EX_LOGICAL_OR: + printf("OR"); + break; + case EX_LOGICAL_NOT: + printf("NOT"); + break; + case EX_ASSEMBLER: + printf("ASSEMBLER"); + break; + case EX_UNDEFINED: + printf("UNDEFINED"); + break; + case EX_SWITCH: + printf("SWITCH"); + break; + case EX_CASE: + printf("CASE"); + break; + case EX_DEFAULT: + printf("DEFAULT"); + break; + case EX_CONDITIONAL: + printf("COND"); + break; + case EX_ASSUME: + printf("ASSUME"); + break; + case EX_BANKOF: + printf("BANKOF"); + break; + case EX_CONSTRUCT: + printf("CONSTRUCT"); + break; + case EX_CLEANUP: + printf("CLEANUP"); + break; + case EX_RESULT: + printf("RESULT"); + break; + case EX_PACK: + printf("PACK"); + break; + case EX_PACK_TYPE: + printf("PACK_TYPE"); + break; + } + printf("\n"); + + if (mLeft) + mLeft->Dump(ident + 1); + if (mRight) + mRight->Dump(ident + 1); +} + bool Expression::HasSideEffects(void) const { switch (mType) @@ -157,6 +342,47 @@ bool Expression::HasSideEffects(void) const } } +bool Expression::IsRValue(void) const +{ + if (mDecType->mType == DT_TYPE_RVALUEREF) + return true; + else if (mDecType->mType == DT_TYPE_REFERENCE) + return false; + else if (mType == EX_VARIABLE) + { + if (mDecValue->mFlags & DTF_TEMPORARY) + return true; + else + return false; + } + else if (mType == EX_QUALIFY || mType == EX_INDEX || mType == EX_ASSIGNMENT || mType == EX_CONSTANT || mType == EX_PREFIX && mToken == TK_MUL) + return false; + else + return true; +} + +bool Expression::IsConstRef(void) const +{ + if (mDecType->mType == DT_TYPE_RVALUEREF || mDecType->mType == DT_TYPE_REFERENCE) + return true; + else if (mType == EX_VARIABLE || mType == EX_QUALIFY || mType == EX_INDEX || mType == EX_PREFIX && mToken == TK_MUL) + return true; + else + return false; +} + +bool Expression::IsLValue(void) const +{ + if (mDecType->mFlags & DTF_CONST) + return false; + else if (mDecType->mType == DT_TYPE_RVALUEREF || mDecType->mType == DT_TYPE_REFERENCE) + return true; + else if (mType == EX_VARIABLE || mType == EX_QUALIFY || mType == EX_INDEX || mType == EX_PREFIX && mToken == TK_MUL) + return true; + else + return false; +} + bool Expression::IsSame(const Expression* exp) const { if (!exp || mType != exp->mType) @@ -225,7 +451,7 @@ Expression* Expression::LogicInvertExpression(void) } } -Expression* Expression::ConstantFold(Errors * errors) +Expression* Expression::ConstantFold(Errors * errors, LinkerSection * dataSection) { if (mType == EX_PREFIX && mLeft->mType == EX_CONSTANT) { @@ -300,47 +526,51 @@ Expression* Expression::ConstantFold(Errors * errors) ex->mDecType = mDecType; return ex; } -#endif - else if (mType == EX_TYPECAST && mRight->mType == EX_CONSTANT) + else if (mType == EX_PREFIX && mToken == TK_BINARY_AND && mLeft->mType == EX_PREFIX && mLeft->mToken == TK_MUL) { - if (mLeft->mDecType->mType == DT_TYPE_POINTER) + return mLeft->mLeft; + } +#endif + else if (mType == EX_TYPECAST && mLeft->mType == EX_CONSTANT) + { + if (mDecType->mType == DT_TYPE_POINTER) { - if (mRight->mDecValue->mType == DT_CONST_ADDRESS || mRight->mDecValue->mType == DT_CONST_INTEGER) + if (mLeft->mDecValue->mType == DT_CONST_ADDRESS || mLeft->mDecValue->mType == DT_CONST_INTEGER) { Expression* ex = new Expression(mLocation, EX_CONSTANT); Declaration* dec = new Declaration(mLocation, DT_CONST_ADDRESS); - dec->mBase = mLeft->mDecType; - dec->mInteger = mRight->mDecValue->mInteger; + dec->mBase = mDecType; + dec->mInteger = mLeft->mDecValue->mInteger; ex->mDecValue = dec; - ex->mDecType = mLeft->mDecType; + ex->mDecType = mDecType; return ex; } - else if (mRight->mDecValue->mType == DT_CONST_FUNCTION) + else if (mLeft->mDecValue->mType == DT_CONST_FUNCTION) { Expression* ex = new Expression(mLocation, EX_CONSTANT); - ex->mDecValue = mRight->mDecValue; - ex->mDecType = mLeft->mDecType; + ex->mDecValue = mLeft->mDecValue; + ex->mDecType = mDecType; return ex; } } - else if (mLeft->mDecType->mType == DT_TYPE_INTEGER) + else if (mDecType->mType == DT_TYPE_INTEGER) { - if (mRight->mDecValue->mType == DT_CONST_FLOAT) + if (mLeft->mDecValue->mType == DT_CONST_FLOAT) { Expression* ex = new Expression(mLocation, EX_CONSTANT); Declaration* dec = new Declaration(mLocation, DT_CONST_INTEGER); - dec->mBase = mLeft->mDecType; - dec->mInteger = int64(mRight->mDecValue->mNumber); + dec->mBase = mDecType; + dec->mInteger = int64(mLeft->mDecValue->mNumber); ex->mDecValue = dec; - ex->mDecType = mLeft->mDecType; + ex->mDecType = mDecType; return ex; } - else if (mRight->mDecValue->mType == DT_CONST_INTEGER) + else if (mLeft->mDecValue->mType == DT_CONST_INTEGER) { - int64 sval = 1ULL << (8 * mLeft->mDecType->mSize); - int64 v = mRight->mDecValue->mInteger & (sval - 1); + int64 sval = 1ULL << (8 * mDecType->mSize); + int64 v = mLeft->mDecValue->mInteger & (sval - 1); - if (mLeft->mDecType->mFlags & DTF_SIGNED) + if (mDecType->mFlags & DTF_SIGNED) { if (v & (sval >> 1)) v -= sval; @@ -348,23 +578,23 @@ Expression* Expression::ConstantFold(Errors * errors) Expression* ex = new Expression(mLocation, EX_CONSTANT); Declaration* dec = new Declaration(mLocation, DT_CONST_INTEGER); - dec->mBase = mLeft->mDecType; + dec->mBase = mDecType; dec->mInteger = v; ex->mDecValue = dec; - ex->mDecType = mLeft->mDecType; + ex->mDecType = mDecType; return ex; } } - else if (mLeft->mDecType->mType == DT_TYPE_FLOAT) + else if (mDecType->mType == DT_TYPE_FLOAT) { - if (mRight->mDecValue->mType == DT_CONST_INTEGER) + if (mLeft->mDecValue->mType == DT_CONST_INTEGER) { Expression* ex = new Expression(mLocation, EX_CONSTANT); Declaration* dec = new Declaration(mLocation, DT_CONST_FLOAT); - dec->mBase = mLeft->mDecType; - dec->mNumber = double(mRight->mDecValue->mInteger); + dec->mBase = mDecType; + dec->mNumber = double(mLeft->mDecValue->mInteger); ex->mDecValue = dec; - ex->mDecType = mLeft->mDecType; + ex->mDecType = mDecType; return ex; } } @@ -570,9 +800,9 @@ Expression* Expression::ConstantFold(Errors * errors) if (mLeft->mDecValue->mType == DT_CONST_INTEGER) { if (mLeft->mDecValue->mInteger != 0) - return mRight->mLeft->ConstantFold(errors); + return mRight->mLeft->ConstantFold(errors, dataSection); else - return mRight->mRight->ConstantFold(errors); + return mRight->mRight->ConstantFold(errors, dataSection); } } else if (mType == EX_BINARY && mToken == TK_ADD && mLeft->mType == EX_VARIABLE && mLeft->mDecValue->mType == DT_VARIABLE && (mLeft->mDecValue->mFlags & DTF_GLOBAL) && mLeft->mDecType->mType == DT_TYPE_ARRAY && mRight->mType == EX_CONSTANT && mRight->mDecValue->mType == DT_CONST_INTEGER) @@ -602,7 +832,7 @@ Expression* Expression::ConstantFold(Errors * errors) else if (mType == EX_BINARY && mToken == TK_ADD && mLeft->mType == EX_VARIABLE && mLeft->mDecValue->mType == DT_VARIABLE && (mLeft->mDecValue->mFlags & DTF_CONST) && mLeft->mDecType->mType == DT_TYPE_POINTER && mRight->mType == EX_CONSTANT && mRight->mDecValue->mType == DT_CONST_INTEGER) { mLeft = mLeft->mDecValue->mValue; - return this->ConstantFold(errors); + return this->ConstantFold(errors, dataSection); } else if (mType == EX_QUALIFY && mLeft->mType == EX_VARIABLE && mLeft->mDecValue->mType == DT_VARIABLE && (mLeft->mDecValue->mFlags & DTF_GLOBAL) && mLeft->mDecType->mType == DT_TYPE_STRUCT) { @@ -612,6 +842,8 @@ Expression* Expression::ConstantFold(Errors * errors) dec->mBase = mLeft->mDecValue; dec->mOffset = mDecValue->mOffset; dec->mSize = mDecValue->mSize; + dec->mBits = mDecValue->mBits; + dec->mShift = mDecValue->mShift; ex->mDecValue = dec; ex->mDecType = mDecType; return ex; @@ -624,22 +856,74 @@ Expression* Expression::ConstantFold(Errors * errors) dec->mBase = mLeft->mDecValue->mBase; dec->mOffset = mLeft->mDecValue->mOffset + mDecValue->mOffset; dec->mSize = mDecValue->mSize; + dec->mBits = mDecValue->mBits; + dec->mShift = mDecValue->mShift; ex->mDecValue = dec; ex->mDecType = mDecType; return ex; } + else if (mType == EX_CALL && mLeft->mType == EX_CONSTANT && (mLeft->mDecValue->mFlags & DTF_INTRINSIC) && mRight->mType == EX_CONSTANT) + { + Declaration* decf = mLeft->mDecValue, * decp = mRight->mDecValue; + const Ident* iname = decf->mQualIdent; + + if (decp->mType == DT_CONST_FLOAT || decp->mType == DT_CONST_INTEGER) + { + double d = decp->mType == DT_CONST_FLOAT ? decp->mNumber : decp->mInteger; + + bool check = false; + + if (!strcmp(iname->mString, "fabs")) + d = fabs(d); + else if (!strcmp(iname->mString, "floor")) + d = floor(d); + else if (!strcmp(iname->mString, "ceil")) + d = ceil(d); + else if (!strcmp(iname->mString, "sin")) + d = sin(d); + else if (!strcmp(iname->mString, "cos")) + d = cos(d); + else + return this; + + Expression* ex = new Expression(mLocation, EX_CONSTANT); + Declaration* dec = new Declaration(mLocation, DT_CONST_FLOAT); + dec->mBase = TheFloatTypeDeclaration; + dec->mNumber = d; + ex->mDecValue = dec; + ex->mDecType = dec->mBase; + return ex; + } + } + else if (mType == EX_CALL && mLeft->mType == EX_CONSTANT && (mLeft->mDecValue->mFlags & DTF_CONSTEXPR) && dataSection) + { + ConstexprInterpreter cinter(mLocation, errors, dataSection); + return cinter.EvalCall(this); + } + else if (mType == EX_CONSTRUCT && mLeft->mType == EX_LIST && !mLeft->mRight && mLeft->mLeft->mType == EX_CALL && + mLeft->mLeft->mLeft->mType == EX_CONSTANT && (mLeft->mLeft->mLeft->mDecValue->mFlags & DTF_CONSTEXPR) && + (mRight->mDecValue->mFlags & DTF_TEMPORARY) && + dataSection) + { + ConstexprInterpreter cinter(mLocation, errors, dataSection); + return cinter.EvalTempConstructor(this); + } return this; } Declaration::Declaration(const Location& loc, DecType type) - : mLocation(loc), mEndLocation(loc), mType(type), mScope(nullptr), mData(nullptr), mIdent(nullptr), mQualIdent(nullptr), - mSize(0), mOffset(0), mFlags(0), mComplexity(0), mLocalSize(0), - mBase(nullptr), mParams(nullptr), mValue(nullptr), mNext(nullptr), mConst(nullptr), - mConstructor(nullptr), mDestructor(nullptr), - mVarIndex(-1), mLinkerObject(nullptr), mCallers(nullptr), mCalled(nullptr), mAlignment(1), + : mLocation(loc), mEndLocation(loc), mType(type), mScope(nullptr), mData(nullptr), mIdent(nullptr), mQualIdent(nullptr), mMangleIdent(nullptr), + mSize(0), mOffset(0), mFlags(0), mComplexity(0), mLocalSize(0), mNumVars(0), + mBase(nullptr), mParams(nullptr), mParamPack(nullptr), mValue(nullptr), mReturn(nullptr), mNext(nullptr), mPrev(nullptr), + mConst(nullptr), mMutable(nullptr), + mDefaultConstructor(nullptr), mDestructor(nullptr), mCopyConstructor(nullptr), mCopyAssignment(nullptr), mMoveConstructor(nullptr), mMoveAssignment(nullptr), + mVectorConstructor(nullptr), mVectorDestructor(nullptr), mVectorCopyConstructor(nullptr), mVectorCopyAssignment(nullptr), + mVTable(nullptr), mTemplate(nullptr), + mVarIndex(-1), mLinkerObject(nullptr), mCallers(nullptr), mCalled(nullptr), mAlignment(1), mFriends(nullptr), mInteger(0), mNumber(0), mMinValue(-0x80000000LL), mMaxValue(0x7fffffffLL), mFastCallBase(0), mFastCallSize(0), mStride(0), mStripe(1), - mCompilerOptions(0), mUseCount(0) + mCompilerOptions(0), mUseCount(0), mTokens(nullptr), mParser(nullptr), + mShift(0), mBits(0), mOptFlags(0) {} Declaration::~Declaration(void) @@ -650,9 +934,693 @@ Declaration::~Declaration(void) int Declaration::Stride(void) const { - return mStride > 0 ? mStride : mBase->mSize; + if (mStride > 0) + return mStride; + else if (mBase) + return mBase->mSize; + else + return 1; } +Declaration* Declaration::BuildConstPointer(const Location& loc) +{ + Declaration* pdec = new Declaration(loc, DT_TYPE_POINTER); + pdec->mBase = this; + pdec->mFlags = DTF_DEFINED | DTF_CONST; + pdec->mSize = 2; + return pdec; +} + +Declaration* Declaration::BuildConstReference(const Location& loc, DecType type) +{ + Declaration* pdec = new Declaration(loc, type); + pdec->mBase = this; + pdec->mFlags = DTF_DEFINED | DTF_CONST; + pdec->mSize = 2; + return pdec; +} + +Declaration* Declaration::BuildArrayPointer(void) +{ + if (mType == DT_TYPE_ARRAY) + { + Declaration* pdec = new Declaration(mLocation, DT_TYPE_POINTER); + pdec->mBase = mBase; + pdec->mFlags = DTF_DEFINED; + pdec->mSize = 2; + pdec->mStride = mStride; + return pdec; + } + else + return this; +} + +Declaration* Declaration::BuildAddressOfPointer(void) +{ + if (mType == DT_TYPE_ARRAY) + return BuildArrayPointer(); + else + return BuildPointer(mLocation); +} + +bool Declaration::IsNullConst(void) const +{ + if (mType == DT_CONST_INTEGER || mType == DT_CONST_ADDRESS) + return mInteger == 0; + else if (mType == DT_CONST_FLOAT) + return mNumber == 0; + else + return false; +} + +Declaration* Declaration::ConstCast(Declaration* ntype) +{ + if (ntype == mBase) + return this; + else if (ntype->mType == DT_TYPE_POINTER) + { + if (mBase->mType == DT_TYPE_POINTER) + { + if (mBase->mBase->IsSame(ntype->mBase)) + return this; + + Declaration* pdec = this->Clone(); + pdec->mBase = ntype; + return pdec; + } + else if (mType == DT_TYPE_INTEGER) + { + Declaration* pdec = this->Clone(); + pdec->mType = DT_CONST_ADDRESS; + pdec->mBase = ntype; + pdec->mSize = 2; + return pdec; + } + else + return this; + } + else if (ntype->mType == DT_TYPE_INTEGER || ntype->mType == DT_TYPE_BOOL || ntype->mType == DT_TYPE_ENUM) + { + if (mType == DT_TYPE_FLOAT) + { + Declaration* pdec = this->Clone(); + pdec->mInteger = int64(mNumber); + pdec->mBase = ntype; + pdec->mSize = ntype->mSize; + return pdec; + } + else + { + Declaration* pdec = this->Clone(); + pdec->mBase = ntype; + pdec->mSize = ntype->mSize; + return pdec; + } + } + else if (ntype->mType == DT_TYPE_FLOAT) + { + if (mType == DT_TYPE_FLOAT) + { + Declaration* pdec = this->Clone(); + pdec->mBase = ntype; + return pdec; + } + else + { + Declaration* pdec = this->Clone(); + pdec->mNumber = float(mInteger); + pdec->mBase = ntype; + pdec->mSize = ntype->mSize; + return pdec; + } + } + else + return this; +} + +Declaration* Declaration::BuildPointer(const Location& loc) +{ + Declaration* pdec = new Declaration(loc, DT_TYPE_POINTER); + pdec->mBase = this; + pdec->mFlags = DTF_DEFINED; + pdec->mSize = 2; + return pdec; +} + +Declaration* Declaration::BuildReference(const Location& loc, DecType type) +{ + Declaration* pdec = new Declaration(loc, type); + pdec->mBase = this; + pdec->mFlags = DTF_DEFINED; + pdec->mSize = 2; + return pdec; +} + +Declaration* Declaration::BuildRValueRef(const Location& loc) +{ + Declaration* pdec = new Declaration(loc, DT_TYPE_RVALUEREF); + pdec->mBase = this; + pdec->mFlags = DTF_DEFINED; + pdec->mSize = 2; + return pdec; +} + +Declaration* Declaration::NonRefBase(void) +{ + if (IsReference()) + return mBase; + else + return this; +} + +bool Declaration::IsAuto(void) const +{ + return (mType == DT_TYPE_AUTO || IsReference() && mBase->mType == DT_TYPE_AUTO); +} + +Declaration* Declaration::DeduceAuto(Declaration * dec) +{ + if (mType == DT_TYPE_AUTO || IsReference() && mBase->mType == DT_TYPE_AUTO) + { + dec = dec->NonRefBase(); + + if (dec->mType == DT_TYPE_ARRAY) + dec = dec->mBase->BuildPointer(mLocation); + + if ((IsReference() ? mBase->mFlags : mFlags) & DTF_CONST) + dec = dec->ToConstType(); + else + dec = dec->ToMutableType(); + + if (IsReference()) + dec = dec->BuildReference(mLocation, mType); + + return dec; + } + else + return this; +} + + +Declaration* Declaration::BuildConstRValueRef(const Location& loc) +{ + Declaration* pdec = new Declaration(loc, DT_TYPE_RVALUEREF); + pdec->mBase = this; + pdec->mFlags = DTF_DEFINED | DTF_CONST; + pdec->mSize = 2; + return pdec; +} + +DecType Declaration::ValueType(void) const +{ + if (IsReference()) + return mBase->mType; + else + return mType; +} + +Declaration* Declaration::Last(void) +{ + mPrev = nullptr; + Declaration* p = this; + while (p->mNext) + { + p->mNext->mPrev = p; + p = p->mNext; + } + return p; +} + +const Ident* Declaration::MangleIdent(void) +{ + if (!this) + return Ident::Unique("null"); + + if (!mMangleIdent) + { + if (mType == DT_CONST_INTEGER) + { + char buffer[20]; + sprintf_s(buffer, "%d", (int)mInteger); + mMangleIdent = Ident::Unique(buffer); + } + else if (mType == DT_CONST_FUNCTION) + { + mMangleIdent = mQualIdent; + } + else if (mType == DT_TYPE_FUNCTION) + { + mMangleIdent = mBase->MangleIdent(); + mMangleIdent = mMangleIdent->Mangle("(*)("); + Declaration* dec = mParams; + while (dec) + { + mMangleIdent = mMangleIdent->Mangle(dec->mBase->MangleIdent()->mString); + dec = dec->mNext; + if (dec) + mMangleIdent = mMangleIdent->Mangle(","); + } + mMangleIdent = mMangleIdent->Mangle(")"); + } + else if (mType == DT_TYPE_INTEGER) + { + char buffer[20]; + sprintf_s(buffer, "%c%d", (mFlags & DTF_SIGNED) ? 'i' : 'u', mSize * 8); + mMangleIdent = Ident::Unique(buffer); + } + else if (mType == DT_TYPE_FLOAT) + { + mMangleIdent = Ident::Unique("float"); + } + else if (mType == DT_TYPE_BOOL) + { + mMangleIdent = Ident::Unique("bool"); + } + else if (mType == DT_TYPE_REFERENCE) + { + mMangleIdent = mBase->MangleIdent()->Mangle("&"); + } + else if (mType == DT_TYPE_RVALUEREF) + { + mMangleIdent = mBase->MangleIdent()->Mangle("&&"); + } + else if (mType == DT_TYPE_POINTER) + { + mMangleIdent = mBase->MangleIdent()->Mangle("*"); + } + else if (mType == DT_TYPE_ARRAY) + { + mMangleIdent = mBase->MangleIdent()->Mangle("[]"); + } + else if (mType == DT_TYPE_STRUCT) + { + mMangleIdent = mQualIdent->PreMangle("struct "); + } + else if (mType == DT_TYPE_ENUM) + { + mMangleIdent = mQualIdent->PreMangle("enum "); + } + else if (mType == DT_TYPE_VOID) + { + mMangleIdent = Ident::Unique("void"); + } + else if (mType == DT_TEMPLATE) + { + mMangleIdent = Ident::Unique("<"); + + Declaration* dec = mParams; + while (dec) + { + const Ident* id; + if (dec->mBase) + id = dec->mBase->MangleIdent(); + else + id = dec->MangleIdent(); + if (id) + mMangleIdent = mMangleIdent->Mangle(id->mString); + + dec = dec->mNext; + if (dec) + mMangleIdent = mMangleIdent->Mangle(","); + } + mMangleIdent = mMangleIdent->Mangle(">"); + } + else if (mType == DT_PACK_TYPE) + { + Declaration* dec = mParams; + while (dec) + { + const Ident* id = dec->MangleIdent(); + + if (id) + { + if (mMangleIdent) + mMangleIdent = mMangleIdent->Mangle(id->mString); + else + mMangleIdent = id; + } + + dec = dec->mNext; + if (dec) + mMangleIdent = mMangleIdent->Mangle(","); + } + } + else + mMangleIdent = mQualIdent; + + if (mTemplate) + { + + } + + if (mFlags & DTF_CONST) + mMangleIdent = mMangleIdent->PreMangle("const "); + } + + return mMangleIdent; +} + +Declaration* Declaration::ExpandTemplate(DeclarationScope* scope) +{ + if (mType == DT_CONST_FUNCTION) + { + Declaration* dec = this->Clone(); + dec->mBase = dec->mBase->ExpandTemplate(scope); + return dec; + } + else if (mType == DT_TYPE_FUNCTION) + { + Declaration* dec = this->Clone(); + dec->mParams = mParams ? mParams->ExpandTemplate(scope) : nullptr; + dec->mBase = mBase->ExpandTemplate(scope); + Declaration* pdec = dec->mParams; + if (pdec) + { + int vi = pdec->mVarIndex; + while (pdec) + { + pdec->mVarIndex = vi; + vi += pdec->mSize; + pdec = pdec->mNext; + } + } + return dec; + } + else if (mType == DT_ARGUMENT) + { + Declaration* ndec = mNext ? mNext->ExpandTemplate(scope) : nullptr; + Declaration* bdec = mBase->ExpandTemplate(scope); + if (ndec != mNext || bdec != mBase) + { + Declaration* dec = this->Clone(); + dec->mBase = bdec; + dec->mSize = bdec->mSize; + dec->mNext = ndec; + return dec; + } + } + else if (mType == DT_TYPE_REFERENCE || mType == DT_TYPE_POINTER || mType == DT_TYPE_RVALUEREF) + { + Declaration* bdec = mBase->ExpandTemplate(scope); + if (bdec != mBase) + { + Declaration* dec = this->Clone(); + dec->mBase = bdec; + return dec; + } + } + else if (mType == DT_TYPE_TEMPLATE) + return scope->Lookup(mIdent); + + return this; +} + +bool Declaration::ResolveTemplate(Expression* pexp, Declaration* tdec) +{ + Declaration* pdec = tdec->mBase->mParams; + + // Insert partially resolved templates + Declaration* ptdec = tdec->mTemplate->mParams; + while (ptdec) + { + if (ptdec->mBase) + mScope->Insert(ptdec->mIdent, ptdec->mBase); + ptdec = ptdec->mNext; + } + + Declaration* phead = nullptr, * ptail = nullptr; + int pcnt = 0; + + while (pexp) + { + Expression* ex = pexp; + if (pexp->mType == EX_LIST) + { + ex = pexp->mLeft; + pexp = pexp->mRight; + } + else + pexp = nullptr; + + if (pdec) + { + if (pdec->mType == DT_PACK_ARGUMENT) + { + Declaration* tpdec = ex->mDecType; + if (tpdec->IsReference()) + tpdec = tpdec->mBase; + + if (tpdec->mType == DT_TYPE_ARRAY) + tpdec = tpdec->mBase->BuildPointer(tpdec->mLocation); + else + tpdec = tpdec->Clone(); + + if (ptail) + ptail->mNext = tpdec; + else + phead = tpdec; + ptail = tpdec; + } + else + { + if (!ResolveTemplate(ex->mDecType, pdec->mBase)) + return false; + + pdec = pdec->mNext; + } + } + else + return false; + } + + if (pdec) + { + if (pdec->mType == DT_PACK_ARGUMENT) + { + Declaration* tpdec = new Declaration(pdec->mLocation, DT_PACK_TYPE); + if (pdec->mBase->mType == DT_TYPE_REFERENCE) + tpdec->mIdent = pdec->mBase->mBase->mIdent; + else + tpdec->mIdent = pdec->mBase->mIdent; + tpdec->mParams = phead; + mScope->Insert(tpdec->mIdent, tpdec); + } + else + return false; + } + + Declaration* ppdec = nullptr; + ptdec = tdec->mTemplate->mParams; + while (ptdec) + { + Declaration* pdec = mScope->Lookup(ptdec->mIdent); + if (!pdec) + return false; + + Declaration * epdec = ptdec->Clone(); + epdec->mBase = pdec; + epdec->mFlags |= DTF_DEFINED; + + if (ppdec) + ppdec->mNext = epdec; + else + mParams = epdec; + ppdec = epdec; + ptdec = ptdec->mNext; + } + + mScope->Clear(); + + return true; +} + +bool Declaration::CanResolveTemplate(Expression* pexp, Declaration* tdec) +{ + Declaration* pdec = tdec->mBase->mParams; + + while (pexp) + { + Expression* ex = pexp; + if (pexp->mType == EX_LIST) + { + ex = pexp->mLeft; + pexp = pexp->mRight; + } + else + pexp = nullptr; + + if (pdec) + { + if (!ResolveTemplate(ex->mDecType, pdec->mBase)) + return false; + + if (pdec->mType != DT_PACK_ARGUMENT) + pdec = pdec->mNext; + } + else + return false; + } + + if (pdec) + return pdec->mType == DT_PACK_ARGUMENT; + else + return true; +} + +bool Declaration::ResolveTemplate(Declaration* fdec, Declaration* tdec) +{ + if (tdec->IsSame(fdec)) + return true; + else if (fdec->IsReference()) + return ResolveTemplate(fdec->mBase, tdec); + else if (tdec->mType == DT_TYPE_FUNCTION) + { + if (fdec->mType == DT_TYPE_FUNCTION) + { + if (fdec->mBase) + { + if (!tdec->mBase || !ResolveTemplate(fdec->mBase, tdec->mBase)) + return false; + } + else if (tdec->mBase) + return false; + + Declaration* fpdec = fdec->mParams; + Declaration* tpdec = tdec->mParams; + while (fpdec && tpdec) + { + if (!ResolveTemplate(fpdec->mBase, tpdec->mBase)) + return false; + fpdec = fpdec->mNext; + tpdec = tpdec->mNext; + } + if (fpdec || tpdec) + return false; + } + else + return false; + + return true; + } + else if (tdec->mType == DT_TYPE_REFERENCE) + { + return ResolveTemplate(fdec, tdec->mBase); + } + else if (tdec->mType == DT_TYPE_RVALUEREF) + { + return ResolveTemplate(fdec, tdec->mBase); + } + else if (tdec->mType == DT_TYPE_POINTER) + { + if (fdec->mType == DT_TYPE_POINTER || fdec->mType == DT_TYPE_ARRAY) + return ResolveTemplate(fdec->mBase, tdec->mBase); + else + return false; + } + else if (tdec->mType == DT_TYPE_TEMPLATE) + { + if (fdec->mType == DT_TYPE_ARRAY) + fdec = fdec->mBase->BuildPointer(fdec->mLocation); + else if (fdec->mType == DT_TYPE_FUNCTION) + fdec = fdec->BuildPointer(fdec->mLocation); + + Declaration* pdec; + if (tdec->mBase) + { + pdec = mScope->Lookup(tdec->mBase->mIdent); + if (!pdec) + return false; + if (pdec->mType == DT_TYPE_STRUCT) + pdec = pdec->mScope->Lookup(tdec->mIdent); + } + else + pdec = mScope->Insert(tdec->mIdent, fdec); + + if (pdec && !pdec->IsSame(fdec)) + return false; + + return true; + } + else if (tdec->mType == DT_PACK_TEMPLATE) + { + return true; + } + else if (tdec->mType == DT_TYPE_STRUCT && fdec->mType == DT_TYPE_STRUCT && tdec->mTemplate) + { + Declaration *ftdec = tdec->mTemplate; + while (ftdec) + { + if (ftdec->mBase->mQualIdent == fdec->mQualIdent) + { + Declaration* fpdec = ftdec->mParams; + Declaration* tpdec = tdec->mTemplate->mParams; + + while (fpdec && tpdec) + { + if (tpdec->mBase->mType == DT_TYPE_TEMPLATE || tpdec->mBase->mType == DT_CONST_TEMPLATE) + { + Declaration * pdec = mScope->Insert(tpdec->mBase->mIdent, fpdec->mBase); + if (pdec && !pdec->IsSame(fpdec->mBase)) + return false; + } + else if (tpdec->mBase->mType == DT_PACK_TEMPLATE) + { + Declaration* tppack; + if (fpdec->mType == DT_PACK_TEMPLATE) + tppack = fpdec->mBase; + else + { + tppack = new Declaration(fpdec->mLocation, DT_PACK_TYPE); + + Declaration* ppdec = nullptr; + + while (fpdec) + { + if (fpdec->mType == DT_PACK_TEMPLATE) + { + if (ppdec) + ppdec->mNext = fpdec->mBase->mParams; + else + tppack->mParams = fpdec->mBase->mParams; + break; + } + + Declaration* ndec = fpdec->mBase->Clone(); + + if (ppdec) + ppdec->mNext = ndec; + else + tppack->mParams = ndec; + ppdec = ndec; + + fpdec = fpdec->mNext; + } + + } + + Declaration* pdec = mScope->Insert(tpdec->mBase->mIdent, tppack); + if (pdec && !pdec->IsSame(fpdec->mBase)) + return false; + + return true; + } + + fpdec = fpdec->mNext; + tpdec = tpdec->mNext; + } + + return !fpdec && !tpdec; + } + + ftdec = ftdec->mNext; + } + return false; + } + else + return tdec->CanAssign(fdec); +} + + Declaration* Declaration::Clone(void) { Declaration* ndec = new Declaration(mLocation, mType); @@ -664,6 +1632,7 @@ Declaration* Declaration::Clone(void) ndec->mFlags = mFlags; ndec->mScope = mScope; ndec->mParams = mParams; + ndec->mParamPack = mParamPack; ndec->mIdent = mIdent; ndec->mQualIdent = mQualIdent; ndec->mValue = mValue; @@ -671,6 +1640,13 @@ Declaration* Declaration::Clone(void) ndec->mLinkerObject = mLinkerObject; ndec->mAlignment = mAlignment; ndec->mSection = mSection; + ndec->mVTable = mVTable; + ndec->mInteger = mInteger; + ndec->mNumber = mNumber; + ndec->mMinValue = mMinValue; + ndec->mMaxValue = mMaxValue; + ndec->mCompilerOptions = mCompilerOptions; + ndec->mParser = mParser; return ndec; } @@ -749,6 +1725,10 @@ Declaration* Declaration::ToStriped(int stripe) p = p->mNext; } } + else if (mType == DT_TYPE_FUNCTION) + { + ndec->mParams = mParams; + } else if (mType == DT_TYPE_ARRAY) { ndec->mStride = stripe; @@ -779,21 +1759,86 @@ Declaration* Declaration::ToConstType(void) ndec->mParams = mParams; ndec->mIdent = mIdent; ndec->mQualIdent = mQualIdent; + ndec->mTemplate = mTemplate; + + ndec->mDestructor = mDestructor; + ndec->mDefaultConstructor = mDefaultConstructor; + ndec->mCopyConstructor = mCopyConstructor; + ndec->mMoveConstructor = mMoveConstructor; + ndec->mVectorConstructor = mVectorConstructor; + ndec->mVectorCopyConstructor = mVectorCopyConstructor; + ndec->mVTable = mVTable; + + ndec->mMutable = this; mConst = ndec; } return mConst; } +Declaration* Declaration::ToMutableType(void) +{ + if (!(mFlags & DTF_CONST)) + return this; + + if (!mMutable) + { + Declaration* ndec = new Declaration(mLocation, mType); + ndec->mSize = mSize; + ndec->mStride = mStride; + ndec->mBase = mBase; + ndec->mFlags = mFlags | DTF_CONST; + ndec->mScope = mScope; + ndec->mParams = mParams; + ndec->mIdent = mIdent; + ndec->mQualIdent = mQualIdent; + ndec->mTemplate = mTemplate; + + ndec->mDestructor = mDestructor; + ndec->mDefaultConstructor = mDefaultConstructor; + ndec->mCopyConstructor = mCopyConstructor; + ndec->mMoveConstructor = mMoveConstructor; + ndec->mVectorConstructor = mVectorConstructor; + ndec->mVectorCopyConstructor = mVectorCopyConstructor; + ndec->mVTable = mVTable; + + ndec->mConst = this; + mMutable = ndec; + } + + return mMutable; +} + +bool Declaration::IsSameTemplate(const Declaration* dec) const +{ + if (this == dec) + return true; + if (this->mType != dec->mType) + return false; + + if (mType == DT_CONST_FUNCTION) + return mBase->IsSame(dec->mBase); + else if (mType == DT_TYPE_STRUCT) + return true; + + return false; +} + bool Declaration::IsSubType(const Declaration* dec) const { if (this == dec) return true; + if (mType == DT_TYPE_VOID) + return true; + + if (IsReference() && dec->IsReference()) + return mBase->IsSubType(dec->mBase); + if (mType == DT_TYPE_POINTER || mType == DT_TYPE_ARRAY) { - if (dec->mType == DT_TYPE_POINTER) - return this->Stride() == dec->Stride() && mBase->IsSubType(dec->mBase); + if (dec->mType == DT_TYPE_POINTER || dec->mType == DT_TYPE_ARRAY) + return /*this->Stride() == dec->Stride() &&*/ mBase->IsSubType(dec->mBase); } if (mType != dec->mType) @@ -819,7 +1864,15 @@ bool Declaration::IsSubType(const Declaration* dec) const return true; if (dec->mBase) - return IsSubType(dec->mBase); + { + Declaration* bcdec = dec->mBase; + while (bcdec) + { + if (IsSubType(bcdec->mBase)) + return true; + bcdec = bcdec->mNext; + } + } return false; } @@ -855,6 +1908,57 @@ bool Declaration::IsSubType(const Declaration* dec) const return false; } +bool Declaration::IsSameMutable(const Declaration* dec) const +{ + if (this == dec) + return true; + if (mType != dec->mType) + return false; + if (mSize != dec->mSize) + return false; + if (mStripe != dec->mStripe) + return false; + + if ((mFlags & DTF_SIGNED) != (dec->mFlags & DTF_SIGNED)) + return false; + if ((dec->mFlags & DTF_CONST) && !(mFlags & DTF_CONST)) + return false; + + if (mType == DT_TYPE_INTEGER) + return true; + else if (mType == DT_TYPE_BOOL || mType == DT_TYPE_FLOAT || mType == DT_TYPE_VOID) + return true; + else if (mType == DT_TYPE_ENUM) + return mIdent == dec->mIdent; + else if (mType == DT_TYPE_POINTER || mType == DT_TYPE_ARRAY) + return this->Stride() == dec->Stride() && mBase->IsSame(dec->mBase); + else if (mType == DT_TYPE_STRUCT) + return mScope == dec->mScope || (mIdent == dec->mIdent && mSize == dec->mSize); + else if (mType == DT_TYPE_FUNCTION) + { + if (!mBase->IsSame(dec->mBase)) + return false; + Declaration* dl = mParams, * dr = dec->mParams; + while (dl && dr) + { + if (!dl->mBase->IsSame(dr->mBase)) + return false; + dl = dl->mNext; + dr = dr->mNext; + } + + if (dl || dr) + return false; + + if ((mFlags & DTF_VARIADIC) != (dec->mFlags & DTF_VARIADIC)) + return false; + + return true; + } + + return false; +} + bool Declaration::IsConstSame(const Declaration* dec) const { if (this == dec) @@ -904,6 +2008,28 @@ bool Declaration::IsConstSame(const Declaration* dec) const return false; } +bool Declaration::IsTemplateSameParams(const Declaration* dec, const Declaration* tdec) const +{ + if (mType == DT_TYPE_FUNCTION && dec->mType == DT_TYPE_FUNCTION) + { + Declaration* ld = mParams, * rd = dec->mParams; + if (mFlags & DTF_FUNC_THIS) + ld = ld->mNext; + + while (ld && rd) + { + if (!ld->mBase->IsTemplateSame(rd->mBase, tdec)) + return false; + ld = ld->mNext; + rd = rd->mNext; + } + + return !ld && !rd; + } + else + return false; +} + bool Declaration::IsSameParams(const Declaration* dec) const { if (mType == DT_TYPE_FUNCTION && dec->mType == DT_TYPE_FUNCTION) @@ -919,10 +2045,73 @@ bool Declaration::IsSameParams(const Declaration* dec) const return !ld && !rd; } + else if (mType == DT_TEMPLATE && dec->mType == DT_TEMPLATE) + { + Declaration* ld = mParams, * rd = dec->mParams; + while (ld && rd) + { + if (ld->mType == DT_CONST_FUNCTION && rd->mType == DT_CONST_FUNCTION) + { + if (ld->mValue != rd->mValue) + return false; + } + else if (ld->mType == DT_PACK_TEMPLATE && rd->mType == DT_PACK_TEMPLATE) + { + if (!ld->mBase->IsSameParams(rd->mBase)) + return false; + } + else if (!ld->mBase || !rd->mBase) + return false; + else if (!ld->mBase->IsSame(rd->mBase)) + return false; + ld = ld->mNext; + rd = rd->mNext; + } + + return !ld && !rd; + } + else if (mType == DT_PACK_TYPE && dec->mType == DT_PACK_TYPE) + { + Declaration* ld = mParams, * rd = dec->mParams; + while (ld && rd) + { + if (!ld->IsSame(rd)) + return false; + ld = ld->mNext; + rd = rd->mNext; + } + + return !ld && !rd; + } else return false; } +bool Declaration::IsDerivedFrom(const Declaration* dec) const +{ + if (mType != DT_TYPE_FUNCTION || dec->mType != DT_TYPE_FUNCTION) + return false; + + if (!(mFlags & DTF_FUNC_THIS) || !(dec->mFlags & DTF_FUNC_THIS)) + return false; + + if (!mBase->IsSame(dec->mBase)) + return false; + Declaration* dl = mParams->mNext, * dr = dec->mParams->mNext; + while (dl && dr) + { + if (!dl->mBase->IsSame(dr->mBase)) + return false; + dl = dl->mNext; + dr = dr->mNext; + } + + if (dl || dr) + return false; + + return true; +} + bool Declaration::IsSame(const Declaration* dec) const { if (this == dec) @@ -937,14 +2126,29 @@ bool Declaration::IsSame(const Declaration* dec) const if ((mFlags & (DTF_SIGNED | DTF_CONST | DTF_VOLATILE)) != (dec->mFlags & (DTF_SIGNED | DTF_CONST | DTF_VOLATILE))) return false; - if (mType == DT_TYPE_INTEGER) + if (mType == DT_CONST_INTEGER) + return mInteger == dec->mInteger; + else if (mType == DT_TYPE_INTEGER) return true; - else if (mType == DT_TYPE_BOOL || mType == DT_TYPE_FLOAT || mType == DT_TYPE_VOID) + else if (mType == DT_TYPE_BOOL || mType == DT_TYPE_FLOAT || mType == DT_TYPE_VOID || mType == DT_TYPE_AUTO) return true; else if (mType == DT_TYPE_ENUM) return mIdent == dec->mIdent; else if (mType == DT_TYPE_POINTER || mType == DT_TYPE_ARRAY) - return this->Stride() == dec->Stride() && mBase->IsSame(dec->mBase); + { + if (mBase->mType == DT_TYPE_STRUCT && dec->mBase->mType == DT_TYPE_STRUCT && mBase->mStripe == dec->mBase->mStripe) + { + if (mBase->mQualIdent == dec->mBase->mQualIdent && + (mBase->mFlags & (DTF_CONST | DTF_VOLATILE)) == (dec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE))) + return true; + else + return false; + } + else + return this->Stride() == dec->Stride() && mBase->IsSame(dec->mBase); + } + else if (IsReference()) + return mBase->IsSame(dec->mBase); else if (mType == DT_TYPE_STRUCT) return mScope == dec->mScope || (mIdent == dec->mIdent && mSize == dec->mSize); else if (mType == DT_TYPE_FUNCTION) @@ -968,6 +2172,96 @@ bool Declaration::IsSame(const Declaration* dec) const return true; } + else if (mType == DT_TYPE_TEMPLATE) + { + return mIdent == dec->mIdent; + } + + return false; +} + +bool Declaration::IsTemplateSame(const Declaration* dec, const Declaration * tdec) const +{ + uint64 dflags = dec->mFlags; + + if (dec->mType == DT_TYPE_TEMPLATE) + { + dec = tdec->mScope->Lookup(dec->mIdent); + if (!dec) + return true; + dflags |= dec->mFlags; + } + else if (dec->mType == DT_PACK_TEMPLATE) + { + dec = tdec->mScope->Lookup(dec->mIdent); + if (!dec) + return true; + dflags |= dec->mFlags; + } + + if (this == dec) + return true; + + if (mType != dec->mType) + return false; + + if (dec->mType == DT_TYPE_STRUCT && dec->mTemplate) + return true; + + if (mSize != dec->mSize) + return false; + if (mStripe != dec->mStripe) + return false; + + if ((mFlags & (DTF_SIGNED | DTF_CONST | DTF_VOLATILE)) != (dflags & (DTF_SIGNED | DTF_CONST | DTF_VOLATILE))) + return false; + + if (mType == DT_TYPE_INTEGER) + return true; + else if (mType == DT_TYPE_BOOL || mType == DT_TYPE_FLOAT || mType == DT_TYPE_VOID) + return true; + else if (mType == DT_TYPE_ENUM) + return mIdent == dec->mIdent; + else if (mType == DT_TYPE_POINTER || mType == DT_TYPE_ARRAY) + { + if (mBase->mType == DT_TYPE_STRUCT && dec->mBase->mType == DT_TYPE_STRUCT && mBase->mStripe == dec->mBase->mStripe) + { + if (mBase->mQualIdent == dec->mBase->mQualIdent && + (mBase->mFlags & (DTF_CONST | DTF_VOLATILE)) == (dec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE))) + return true; + else + return false; + } + else if (dec->mBase->mType == DT_TYPE_TEMPLATE) + return mBase->IsTemplateSame(dec->mBase, tdec); + else + return this->Stride() == dec->Stride() && mBase->IsTemplateSame(dec->mBase, tdec); + } + else if (IsReference()) + return mBase->IsTemplateSame(dec->mBase, tdec); + else if (mType == DT_TYPE_STRUCT) + return mScope == dec->mScope || (mIdent == dec->mIdent && mSize == dec->mSize); + else if (mType == DT_TYPE_FUNCTION) + { + if (!mBase->IsTemplateSame(dec->mBase, tdec)) + return false; + Declaration* dl = mParams, * dr = dec->mParams; + while (dl && dr) + { + if (!dl->mBase->IsTemplateSame(dr->mBase, tdec)) + return false; + dl = dl->mNext; + dr = dr->mNext; + } + + if (dl || dr) + return false; + + if ((mFlags & DTF_VARIADIC) != (dec->mFlags & DTF_VARIADIC)) + return false; + + return true; + } return false; } @@ -994,10 +2288,10 @@ bool Declaration::IsSameValue(const Declaration* dec) const bool Declaration::CanAssign(const Declaration* fromType) const { - if (mType == DT_TYPE_REFERENCE) - return mBase->IsSubType(fromType); - else if (fromType->mType == DT_TYPE_REFERENCE) + if (fromType->IsReference()) return this->CanAssign(fromType->mBase); + if (IsReference()) + return mBase->IsSubType(fromType); if (this->IsSame(fromType)) return true; @@ -1020,7 +2314,7 @@ bool Declaration::CanAssign(const Declaration* fromType) const { if (mBase->mType == DT_TYPE_VOID || fromType->mBase->mType == DT_TYPE_VOID) return (mBase->mFlags & DTF_CONST) || !(fromType->mBase->mFlags & DTF_CONST); - else if (mBase->IsSubType(fromType->mBase)) + else if (mBase->mStripe == fromType->mBase->mStripe && mBase->IsSubType(fromType->mBase)) return true; } else if (mBase->mType == DT_TYPE_FUNCTION && fromType->mType == DT_TYPE_FUNCTION) @@ -1050,16 +2344,36 @@ bool Declaration::IsNumericType(void) const return mType == DT_TYPE_INTEGER || mType == DT_TYPE_BOOL || mType == DT_TYPE_FLOAT || mType == DT_TYPE_ENUM; } + +bool Declaration::IsReference(void) const +{ + return mType == DT_TYPE_REFERENCE || mType == DT_TYPE_RVALUEREF; +} + +bool Declaration::IsIndexed(void) const +{ + return mType == DT_TYPE_ARRAY || mType == DT_TYPE_POINTER; +} + + bool Declaration::IsSimpleType(void) const { return mType == DT_TYPE_INTEGER || mType == DT_TYPE_BOOL || mType == DT_TYPE_FLOAT || mType == DT_TYPE_ENUM || mType == DT_TYPE_POINTER; } +void Declaration::SetDefined(void) +{ + mFlags |= DTF_DEFINED; + if (mConst) + mConst->mFlags |= DTF_DEFINED; +} Declaration* TheVoidTypeDeclaration, * TheConstVoidTypeDeclaration, * TheSignedIntTypeDeclaration, * TheUnsignedIntTypeDeclaration, * TheConstCharTypeDeclaration, * TheCharTypeDeclaration, * TheSignedCharTypeDeclaration, * TheUnsignedCharTypeDeclaration; Declaration* TheBoolTypeDeclaration, * TheFloatTypeDeclaration, * TheConstVoidPointerTypeDeclaration, * TheVoidPointerTypeDeclaration, * TheSignedLongTypeDeclaration, * TheUnsignedLongTypeDeclaration; Declaration* TheVoidFunctionTypeDeclaration, * TheConstVoidValueDeclaration; Declaration* TheCharPointerTypeDeclaration, * TheConstCharPointerTypeDeclaration; +Expression* TheVoidExpression; +Declaration* TheNullptrConstDeclaration, * TheZeroIntegerConstDeclaration, * TheZeroFloatConstDeclaration; void InitDeclarations(void) { @@ -1138,4 +2452,20 @@ void InitDeclarations(void) TheConstCharPointerTypeDeclaration->mBase = TheConstCharTypeDeclaration; TheConstCharPointerTypeDeclaration->mSize = 2; TheConstCharPointerTypeDeclaration->mFlags = DTF_DEFINED; + + TheVoidExpression = new Expression(noloc, EX_CONSTANT); + TheVoidExpression->mDecType = TheConstVoidTypeDeclaration; + TheVoidExpression->mDecValue = TheConstVoidValueDeclaration; + + + TheNullptrConstDeclaration = new Declaration(noloc, DT_CONST_ADDRESS); + TheNullptrConstDeclaration->mBase = TheVoidPointerTypeDeclaration; + TheNullptrConstDeclaration->mSize = 2; + TheZeroIntegerConstDeclaration = new Declaration(noloc, DT_CONST_INTEGER); + TheZeroIntegerConstDeclaration->mBase = TheSignedIntTypeDeclaration; + TheZeroIntegerConstDeclaration->mSize = 2; + TheZeroFloatConstDeclaration = new Declaration(noloc, DT_CONST_FLOAT); + TheZeroFloatConstDeclaration->mBase = TheFloatTypeDeclaration; + TheZeroFloatConstDeclaration->mSize = 4; + } diff --git a/oscar64/Declaration.h b/oscar64/Declaration.h index df00664..c4da608 100644 --- a/oscar64/Declaration.h +++ b/oscar64/Declaration.h @@ -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 void Iterate(F && f); + ScopeLevel mLevel; const Ident * mName; @@ -141,6 +167,15 @@ protected: ExpandingArray mUsed; }; +template 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 mCallers, mCalled; + GrowingArray 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; diff --git a/oscar64/Disassembler.cpp b/oscar64/Disassembler.cpp index 042ce48..10e868b 100644 --- a/oscar64/Disassembler.cpp +++ b/oscar64/Disassembler.cpp @@ -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); diff --git a/oscar64/Disassembler.h b/oscar64/Disassembler.h index 68a764e..846a25e 100644 --- a/oscar64/Disassembler.h +++ b/oscar64/Disassembler.h @@ -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); }; diff --git a/oscar64/DiskImage.cpp b/oscar64/DiskImage.cpp index 13b1020..5b5be37 100644 --- a/oscar64/DiskImage.cpp +++ b/oscar64/DiskImage.cpp @@ -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); diff --git a/oscar64/Emulator.cpp b/oscar64/Emulator.cpp index c7f1bdf..3f32dc2 100644 --- a/oscar64/Emulator.cpp +++ b/oscar64/Emulator.cpp @@ -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]; diff --git a/oscar64/Errors.cpp b/oscar64/Errors.cpp index ff29cf5..e77fbb0 100644 --- a/oscar64/Errors.cpp +++ b/oscar64/Errors.cpp @@ -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); } diff --git a/oscar64/Errors.h b/oscar64/Errors.h index 8e157ab..5a62749 100644 --- a/oscar64/Errors.h +++ b/oscar64/Errors.h @@ -3,10 +3,14 @@ class Location { public: - const char* mFileName; - int mLine, mColumn; + 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,7 +18,8 @@ class Ident; enum ErrorID { EINFO_GENERIC = 1000, - + EINFO_EXPANDED = 1001, + EWARN_GENERIC = 2000, EWARN_CONSTANT_TRUNCATED, EWARN_UNKNOWN_PRAGMA, @@ -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); }; diff --git a/oscar64/GlobalAnalyzer.cpp b/oscar64/GlobalAnalyzer.cpp index b51e40a..bc2b778 100644 --- a/oscar64/GlobalAnalyzer.cpp +++ b/oscar64/GlobalAnalyzer.cpp @@ -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)) @@ -170,10 +172,9 @@ void GlobalAnalyzer::AutoInline(void) doinline = true; 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) + { + 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->mFlags & DTF_DYNSTACK) procDec->mFlags |= DTF_DYNSTACK; - CheckFastcall(cf, false); - -// if (!(cf->mBase->mFlags & DTF_FASTCALL)) -// procDec->mBase->mFlags |= DTF_STACKCALL; + // 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)) { @@ -714,10 +871,23 @@ Declaration * GlobalAnalyzer::Analyze(Expression* exp, Declaration* procDec, boo } #endif } + + 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 && pex->mDecType->mType == DT_TYPE_STRUCT) + 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->mLeft) - ldec = Analyze(exp->mLeft, procDec, false); - exp = exp->mRight; + 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; diff --git a/oscar64/GlobalAnalyzer.h b/oscar64/GlobalAnalyzer.h index 7b8570d..882d731 100644 --- a/oscar64/GlobalAnalyzer.h +++ b/oscar64/GlobalAnalyzer.h @@ -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); }; diff --git a/oscar64/GlobalOptimizer.cpp b/oscar64/GlobalOptimizer.cpp new file mode 100644 index 0000000..1f7034f --- /dev/null +++ b/oscar64/GlobalOptimizer.cpp @@ -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; +} diff --git a/oscar64/GlobalOptimizer.h b/oscar64/GlobalOptimizer.h new file mode 100644 index 0000000..c03a1bc --- /dev/null +++ b/oscar64/GlobalOptimizer.h @@ -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 mCalledFunctions, mCallingFunctions, mVariableFunctions, mFunctions; + ExpandingArray 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); + +}; diff --git a/oscar64/Ident.cpp b/oscar64/Ident.cpp index daabd53..e0c0305 100644 --- a/oscar64/Ident.cpp +++ b/oscar64/Ident.cpp @@ -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); diff --git a/oscar64/Ident.h b/oscar64/Ident.h index 661c83c..93d1470 100644 --- a/oscar64/Ident.h +++ b/oscar64/Ident.h @@ -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); }; diff --git a/oscar64/InterCode.cpp b/oscar64/InterCode.cpp index 3e8963b..7b366d9 100644 --- a/oscar64/InterCode.cpp +++ b/oscar64/InterCode.cpp @@ -5,6 +5,7 @@ #include static bool CheckFunc; +static bool CheckCase; int InterTypeSize[] = { 0, @@ -28,7 +29,10 @@ static bool IsIntegerType(InterType type) IntegerValueRange::IntegerValueRange(void) : mMinState(S_UNKNOWN), mMaxState(S_UNKNOWN) -{} +{ + mMinExpanded = 0; + mMaxExpanded = 0; +} IntegerValueRange::~IntegerValueRange(void) {} @@ -37,6 +41,16 @@ void IntegerValueRange::Reset(void) { mMinState = S_UNKNOWN; mMaxState = S_UNKNOWN; + mMinExpanded = 0; + mMaxExpanded = 0; +} + +void IntegerValueRange::Restart(void) +{ + if (mMinState == IntegerValueRange::S_UNBOUND) + mMinState = IntegerValueRange::S_UNKNOWN; + if (mMaxState == IntegerValueRange::S_UNBOUND) + mMaxState = IntegerValueRange::S_UNKNOWN; } @@ -109,6 +123,26 @@ bool IntegerValueRange::IsConstant(void) const return mMinState == S_BOUND && mMaxState == S_BOUND && mMinValue == mMaxValue; } +void IntegerValueRange::MergeUnknown(const IntegerValueRange& range) +{ + if (mMinState != S_BOUND) + { + mMinState = range.mMinState; + mMinValue = range.mMinValue; + } + else if (range.mMinState == S_BOUND && mMinValue < range.mMinValue) + mMinValue = range.mMinValue; + + if (mMaxState != S_BOUND) + { + mMaxState = range.mMaxState; + mMaxValue = range.mMaxValue; + } + else if (range.mMaxState == S_BOUND && mMaxValue > range.mMaxValue) + mMaxValue = range.mMaxValue; +} + + void IntegerValueRange::Limit(const IntegerValueRange& range) { if (range.mMinState == S_BOUND) @@ -126,6 +160,58 @@ void IntegerValueRange::SetLimit(int64 minValue, int64 maxValue) mMaxValue = maxValue; } +void IntegerValueRange::Expand(const IntegerValueRange& range) +{ + if (range.mMinState == S_BOUND && mMinState == S_BOUND && range.mMinValue < mMinValue) + { + mMinValue = range.mMinValue; + mMinExpanded++; + if (mMinExpanded >= 32) + mMinState = S_UNBOUND; + } + else + { + mMinState = range.mMinState; + mMinValue = range.mMinValue; + } + if (range.mMaxState == S_BOUND && mMaxState == S_BOUND && range.mMaxValue > mMaxValue) + { + mMaxValue = range.mMaxValue; + mMaxExpanded++; + if (mMaxExpanded >= 32) + mMaxState = S_UNBOUND; + } + else + { + mMaxState = range.mMaxState; + mMaxValue = range.mMaxValue; + } +} + +void IntegerValueRange::Union(const IntegerValueRange& range) +{ + if (range.mMinState == S_UNBOUND || mMinState == S_UNBOUND) + mMinState = S_UNBOUND; + else if (range.mMinState == S_UNKNOWN || mMinState == S_UNKNOWN) + mMinState = S_UNKNOWN; + else + { + mMinValue = int64min(mMinValue, range.mMinValue); + if (range.mMinState == S_WEAK) + mMinState = S_WEAK; + } + if (range.mMaxState == S_UNBOUND || mMaxState == S_UNBOUND) + mMaxState = S_UNBOUND; + else if (range.mMaxState == S_UNKNOWN || mMaxState == S_UNKNOWN) + mMaxState = S_UNKNOWN; + else + { + mMaxValue = int64max(mMaxValue, range.mMaxValue); + if (range.mMaxState == S_WEAK) + mMaxState = S_WEAK; + } +} + bool IntegerValueRange::Merge(const IntegerValueRange& range, bool head, bool initial) { bool changed = false; @@ -412,7 +498,9 @@ bool InterCodeBasicBlock::CollidingMem(const InterOperand& op1, InterType type1, { if (op1.mMemory == IM_INDIRECT) { - if (op2.mMemory == IM_GLOBAL) + if (op1.mRestricted) + return false; + else if (op2.mMemory == IM_GLOBAL) return mProc->mModule->mGlobalVars[op2.mVarIndex]->mAliased; else if (op2.mMemory == IM_FPARAM || op2.mMemory == IM_FFRAME) return false; @@ -423,7 +511,9 @@ bool InterCodeBasicBlock::CollidingMem(const InterOperand& op1, InterType type1, } else if (op2.mMemory == IM_INDIRECT) { - if (op1.mMemory == IM_GLOBAL) + if (op2.mRestricted) + return false; + else if (op1.mMemory == IM_GLOBAL) return mProc->mModule->mGlobalVars[op1.mVarIndex]->mAliased; else if (op1.mMemory == IM_FPARAM || op1.mMemory == IM_FFRAME) return false; @@ -454,6 +544,8 @@ bool InterCodeBasicBlock::CollidingMem(const InterOperand& op1, InterType type1, return op1.mIntConst < op2.mIntConst + op2.mOperandSize && op2.mIntConst < op1.mIntConst + op1.mOperandSize; else if (op1.mLinkerObject && op2.mLinkerObject && op1.mLinkerObject != op2.mLinkerObject) return false; + else if (op1.mRestricted && op2.mRestricted && op1.mRestricted != op2.mRestricted) + return false; else return CollidingMemType(type1, type2); default: @@ -497,6 +589,18 @@ bool InterCodeBasicBlock::DestroyingMem(const InterInstruction* lins, const Inte return false; } +bool InterCodeBasicBlock::DestroyingMem(InterCodeBasicBlock* block, InterInstruction* lins, int from, int to) const +{ + for (int i = from; i < to; i++) + { + InterInstruction* ins = block->mInstructions[i]; + if (DestroyingMem(lins, ins)) + return true; + } + + return false; +} + static bool SameMem(const InterOperand& op1, const InterOperand& op2) { if (op1.mMemory != op2.mMemory || op1.mType != op2.mType || op1.mIntConst != op2.mIntConst) @@ -598,6 +702,16 @@ static bool SameMem(const InterOperand& op, const InterInstruction* ins) return false; } +static bool SameMemAndSize(const InterOperand& op, const InterInstruction* ins) +{ + if (ins->mCode == IC_LOAD) + return SameMemAndSize(op, ins->mSrc[0]); + else if (ins->mCode == IC_STORE) + return SameMemAndSize(op, ins->mSrc[1]); + else + return false; +} + static bool SameInstruction(const InterInstruction* ins1, const InterInstruction* ins2) { if (ins1->mCode == ins2->mCode && ins1->mNumOperands == ins2->mNumOperands) @@ -626,7 +740,7 @@ static bool SameInstruction(const InterInstruction* ins1, const InterInstruction bool InterCodeBasicBlock::CanSwapInstructions(const InterInstruction* ins0, const InterInstruction* ins1) const { // Cannot swap branches - if (ins1->mCode == IC_JUMP || ins1->mCode == IC_BRANCH) + if (ins1->mCode == IC_JUMP || ins1->mCode == IC_BRANCH || ins1->mCode == IC_DISPATCH) return false; // Check function call @@ -634,22 +748,51 @@ bool InterCodeBasicBlock::CanSwapInstructions(const InterInstruction* ins0, cons { if (ins0->mCode == IC_CALL || ins0->mCode == IC_CALL_NATIVE || ins0->mCode == IC_ASSEMBLER || ins0->mCode == IC_RETURN || ins0->mCode == IC_RETURN_STRUCT || ins0->mCode == IC_RETURN_VALUE || - ins0->mCode == IC_PUSH_FRAME || ins0->mCode == IC_POP_FRAME) + ins0->mCode == IC_PUSH_FRAME || ins0->mCode == IC_POP_FRAME || ins0->mCode == IC_MALLOC || ins0->mCode == IC_FREE) return false; - if (ins0->mCode == IC_LOAD || ins0->mCode == IC_STORE || ins0->mCode == IC_COPY || ins0->mCode == IC_STRCPY) + if (ins0->mCode == IC_LOAD) + { + if (ins0->mSrc[0].mTemp >= 0) + return false; + if (ins0->mSrc[0].mMemory == IM_PARAM || ins0->mSrc[0].mMemory == IM_FPARAM) + { + if (mProc->mParamAliasedSet[ins0->mSrc[0].mVarIndex]) + return false; + } + else + return false; + } + else if (ins0->mCode == IC_STORE || ins0->mCode == IC_COPY || ins0->mCode == IC_STRCPY) return false; } if (ins0->mCode == IC_CALL || ins0->mCode == IC_CALL_NATIVE || ins0->mCode == IC_ASSEMBLER) { if (ins1->mCode == IC_RETURN || ins1->mCode == IC_RETURN_STRUCT || ins1->mCode == IC_RETURN_VALUE || - ins1->mCode == IC_PUSH_FRAME || ins1->mCode == IC_POP_FRAME) + ins1->mCode == IC_PUSH_FRAME || ins1->mCode == IC_POP_FRAME || ins1->mCode == IC_MALLOC || ins1->mCode == IC_FREE) return false; if (ins1->mCode == IC_LOAD || ins1->mCode == IC_STORE || ins1->mCode == IC_COPY || ins1->mCode == IC_STRCPY) return false; } + if (ins0->mCode == IC_MALLOC || ins0->mCode == IC_FREE) + { + if (ins1->mCode == IC_MALLOC || ins1->mCode == IC_FREE) + return false; + } + + if (ins0->mCode == IC_FREE) + { + if (ins1->mCode == IC_LOAD || ins1->mCode == IC_STORE || ins1->mCode == IC_COPY || ins1->mCode == IC_STRCPY) + return false; + } + if (ins1->mCode == IC_FREE) + { + if (ins0->mCode == IC_LOAD || ins0->mCode == IC_STORE || ins0->mCode == IC_COPY || ins0->mCode == IC_STRCPY) + return false; + } + // Check frame pointer if (ins0->mCode == IC_PUSH_FRAME || ins0->mCode == IC_POP_FRAME) { @@ -1151,19 +1294,19 @@ void ValueSet::InsertValue(InterInstruction * ins) static bool HasSideEffect(InterCode code) { - return code == IC_CALL || code == IC_CALL_NATIVE || code == IC_ASSEMBLER; + return code == IC_CALL || code == IC_CALL_NATIVE || code == IC_ASSEMBLER || code == IC_DISPATCH /* || code == IC_MALLOC || code == IC_FREE */; } static bool IsObservable(InterCode code) { - return code == IC_CALL || code == IC_CALL_NATIVE || code == IC_ASSEMBLER || code == IC_STORE || code == IC_COPY || code == IC_STRCPY; + return code == IC_CALL || code == IC_CALL_NATIVE || code == IC_ASSEMBLER || code == IC_DISPATCH || code == IC_STORE || code == IC_COPY || code == IC_STRCPY || code == IC_MALLOC || code == IC_FREE; } static bool IsMoveable(InterCode code) { - if (HasSideEffect(code) || code == IC_COPY || code == IC_STRCPY || code == IC_STORE || code == IC_BRANCH || code == IC_POP_FRAME || code == IC_PUSH_FRAME) + if (HasSideEffect(code) || code == IC_COPY || code == IC_STRCPY || code == IC_STORE || code == IC_BRANCH || code == IC_POP_FRAME || code == IC_PUSH_FRAME || code == IC_MALLOC || code == IC_FREE) return false; - if (code == IC_RETURN || code == IC_RETURN_STRUCT || code == IC_RETURN_VALUE) + if (code == IC_RETURN || code == IC_RETURN_STRUCT || code == IC_RETURN_VALUE || code == IC_DISPATCH) return false; return true; @@ -1747,6 +1890,7 @@ InterInstruction* InterInstruction::Clone(void) const { InterInstruction* ins = new InterInstruction(mLocation, mCode); *ins = *this; + ins->mRemove = false; return ins; } @@ -2762,12 +2906,43 @@ void ValueSet::UpdateValue(InterInstruction * ins, const GrowingInstructionPtrAr case IC_BRANCH: if (ins->mSrc[0].mTemp >= 0 && tvalue[ins->mSrc[0].mTemp] && tvalue[ins->mSrc[0].mTemp]->mCode == IC_CONSTANT) { - if (tvalue[ins->mSrc[0].mTemp]->mConst.mIntConst) - ins->mCode = IC_JUMP; - else - ins->mCode = IC_JUMPF; - ins->mSrc[0].mTemp = -1; - ins->mNumOperands = 0; + InterInstruction* tins = tvalue[ins->mSrc[0].mTemp]; + if (IsIntegerType(tins->mConst.mType) || tins->mConst.mType == IT_BOOL) + { + if (tins->mConst.mIntConst) + ins->mCode = IC_JUMP; + else + ins->mCode = IC_JUMPF; + ins->mSrc[0].mTemp = -1; + ins->mNumOperands = 0; + } + else if (tins->mConst.mType == IT_POINTER) + { + if (tins->mConst.mMemory == IM_ABSOLUTE) + { + if (tins->mConst.mIntConst) + ins->mCode = IC_JUMP; + else + ins->mCode = IC_JUMPF; + ins->mSrc[0].mTemp = -1; + ins->mNumOperands = 0; + } + else if (tins->mConst.mMemory == IM_GLOBAL || tins->mConst.mMemory == IM_LOCAL || tins->mConst.mMemory == IM_PARAM || tins->mConst.mMemory == IM_FPARAM) + { + ins->mCode = IC_JUMP; + ins->mSrc[0].mTemp = -1; + ins->mNumOperands = 0; + } + } + else if (tins->mConst.mType == IT_FLOAT) + { + if (tins->mConst.mFloatConst) + ins->mCode = IC_JUMP; + else + ins->mCode = IC_JUMPF; + ins->mSrc[0].mTemp = -1; + ins->mNumOperands = 0; + } } break; case IC_PUSH_FRAME: @@ -2784,7 +2959,7 @@ void ValueSet::UpdateValue(InterInstruction * ins, const GrowingInstructionPtrAr InterOperand::InterOperand(void) - : mTemp(INVALID_TEMPORARY), mType(IT_NONE), mFinal(false), mIntConst(0), mFloatConst(0), mVarIndex(-1), mOperandSize(0), mLinkerObject(nullptr), mMemory(IM_NONE), mStride(1) + : mTemp(INVALID_TEMPORARY), mType(IT_NONE), mFinal(false), mIntConst(0), mFloatConst(0), mVarIndex(-1), mOperandSize(0), mLinkerObject(nullptr), mMemory(IM_NONE), mStride(1), mRestricted(0) {} bool InterOperand::IsNotUByte(void) const @@ -2851,6 +3026,7 @@ void InterOperand::ForwardMem(const InterOperand& op) mType = op.mType; mRange = op.mRange; mStride = op.mStride; + mRestricted = op.mRestricted; mFinal = false; } @@ -2897,6 +3073,7 @@ InterInstruction::InterInstruction(const Location& loc, InterCode code) case IC_RETURN_VALUE: case IC_RETURN_STRUCT: case IC_CONVERSION_OPERATOR: + case IC_DISPATCH: mNumOperands = 1; break; @@ -2974,7 +3151,6 @@ void InterInstruction::CollectLocalAddressTemps(GrowingIntArray& localTable, Gro if (mConst.mVarIndex >= nparams) nparams = mConst.mVarIndex + 1; } - } else if (mCode == IC_LEA) { @@ -3000,6 +3176,11 @@ void InterInstruction::CollectLocalAddressTemps(GrowingIntArray& localTable, Gro nparams = mSrc[1].mVarIndex + 1; } } + else if (mSrc[1].mTemp >= 0) + { + localTable[mDst.mTemp] = localTable[mSrc[1].mTemp]; + paramTable[mDst.mTemp] = paramTable[mSrc[1].mTemp]; + } } else if (mCode == IC_LOAD_TEMPORARY) { @@ -3071,7 +3252,7 @@ void InterInstruction::FilterStaticVarsUsage(const GrowingVariableArray& staticV } else if (mSrc[0].mMemory == IM_GLOBAL) { - if (!providedVars[mSrc[0].mVarIndex]) + if (mSrc[0].mVarIndex >= 0 && !providedVars[mSrc[0].mVarIndex]) requiredVars += mSrc[0].mVarIndex; } } @@ -3087,13 +3268,54 @@ void InterInstruction::FilterStaticVarsUsage(const GrowingVariableArray& staticV } else if (mSrc[1].mMemory == IM_GLOBAL) { - if (mSrc[1].mIntConst == 0 && mSrc[1].mOperandSize == staticVars[mSrc[1].mVarIndex]->mSize) - providedVars += mSrc[1].mVarIndex; - else if (!providedVars[mSrc[1].mVarIndex]) - requiredVars += mSrc[1].mVarIndex; + if (mSrc[1].mVarIndex >= 0) + { + if (mSrc[1].mIntConst == 0 && mSrc[1].mOperandSize == staticVars[mSrc[1].mVarIndex]->mSize) + providedVars += mSrc[1].mVarIndex; + else if (!providedVars[mSrc[1].mVarIndex]) + requiredVars += mSrc[1].mVarIndex; + } } } - else if (mCode == IC_COPY || mCode == IC_CALL || mCode == IC_CALL_NATIVE || mCode == IC_RETURN || mCode == IC_RETURN_STRUCT || mCode == IC_RETURN_VALUE || mCode == IC_STRCPY) + else if (mCode == IC_COPY || mCode == IC_CALL || mCode == IC_CALL_NATIVE || mCode == IC_RETURN || mCode == IC_RETURN_STRUCT || mCode == IC_RETURN_VALUE || mCode == IC_STRCPY || mCode == IC_DISPATCH) + { + requiredVars.OrNot(providedVars); + } +} + +void InterInstruction::FilterStaticVarsByteUsage(const GrowingVariableArray& staticVars, NumberSet& requiredVars, NumberSet& providedVars) +{ + if (mCode == IC_LOAD) + { + if (mSrc[0].mMemory == IM_INDIRECT) + { + if (!mSrc[0].mRestricted) + { + for (int i = 0; i < staticVars.Size(); i++) + { + if (staticVars[i]->mAliased && !providedVars[i]) + requiredVars.AddRange(staticVars[i]->mByteIndex, staticVars[i]->mSize); + } + } + } + else if (mSrc[0].mMemory == IM_GLOBAL) + { + if (mSrc[0].mVarIndex >= 0 && !providedVars.RangeFilled(staticVars[mSrc[0].mVarIndex]->mByteIndex + int(mSrc[0].mIntConst), InterTypeSize[mDst.mType])) + requiredVars.AddRange(staticVars[mSrc[0].mVarIndex]->mByteIndex + int(mSrc[0].mIntConst), InterTypeSize[mDst.mType]); + } + } + else if (mCode == IC_STORE) + { + if (mSrc[1].mMemory == IM_INDIRECT) + { + } + else if (mSrc[1].mMemory == IM_GLOBAL) + { + if (mSrc[1].mVarIndex >= 0) + providedVars.AddRange(staticVars[mSrc[1].mVarIndex]->mByteIndex + int(mSrc[1].mIntConst), InterTypeSize[mSrc[0].mType]); + } + } + else if (mCode == IC_COPY || mCode == IC_CALL || mCode == IC_CALL_NATIVE || mCode == IC_RETURN || mCode == IC_RETURN_STRUCT || mCode == IC_RETURN_VALUE || mCode == IC_STRCPY || mCode == IC_DISPATCH) { requiredVars.OrNot(providedVars); } @@ -3303,9 +3525,33 @@ bool InterInstruction::PropagateConstTemps(const GrowingInstructionPtrArray& cte { InterType t = mSrc[i].mType; InterInstruction* ains = ctemps[mSrc[i].mTemp]; - mSrc[i] = ains->mConst; - mSrc[i].mType = t; - changed = true; + + if (t != IT_POINTER || ains->mConst.mMemory == IM_ABSOLUTE) + { + mSrc[i] = ains->mConst; + mSrc[i].mType = t; + changed = true; + } + } + } + + if (!changed) + { + if (mSrc[0].mType == IT_POINTER && mSrc[1].mType == IT_POINTER && + mSrc[0].mTemp >= 0 && mSrc[1].mTemp >= 0 && + ctemps[mSrc[0].mTemp] && ctemps[mSrc[1].mTemp]) + { + InterInstruction* si0 = ctemps[mSrc[0].mTemp]; + InterInstruction* si1 = ctemps[mSrc[1].mTemp]; + + if (si0->mConst.mMemory != IM_INDIRECT && si1->mConst.mMemory != IM_INDIRECT) + { + mCode = IC_CONSTANT; + mConst.mIntConst = ::ConstantRelationalPointerFolding(mOperator, si1->mConst, si0->mConst); + mConst.mType = IT_BOOL; + mNumOperands = 0; + return true; + } } } @@ -3314,8 +3560,25 @@ bool InterInstruction::PropagateConstTemps(const GrowingInstructionPtrArray& cte this->ConstantFolding(); return true; } + } break; + case IC_FREE: + { + if (mSrc[0].mTemp >= 0 && ctemps[mSrc[0].mTemp]) + { + InterInstruction* ains = ctemps[mSrc[0].mTemp]; + + if (ains->mConst.mMemory == IM_ABSOLUTE && ains->mConst.mIntConst == 0) + { + mCode = IC_NONE; + mNumOperands = 0; + return true; + } + } + + } break; + case IC_CONVERSION_OPERATOR: case IC_UNARY_OPERATOR: { @@ -3457,7 +3720,7 @@ void InterInstruction::BuildCallerSaveTempSet(NumberSet& requiredTemps, NumberSe if (mDst.mTemp >= 0) requiredTemps -= mDst.mTemp; - if (mCode == IC_CALL || mCode == IC_CALL_NATIVE) + if (mCode == IC_CALL || mCode == IC_CALL_NATIVE || mCode == IC_DISPATCH) callerSaveTemps |= requiredTemps; for (int i = 0; i < mNumOperands; i++) @@ -3514,6 +3777,34 @@ bool InterInstruction::RemoveUnusedStoreInstructions(const GrowingVariableArray& } } } + else if (mCode == IC_SELECT) + { + if (mDst.mType == IT_POINTER) + { + if (mSrc[1].mTemp < 0) + { + if (mSrc[1].mMemory == IM_LOCAL) + { + requiredVars += mSrc[1].mVarIndex; + } + else if (mSrc[1].mMemory == paramMemory) + { + requiredParams += mSrc[1].mVarIndex; + } + } + if (mSrc[2].mTemp < 0) + { + if (mSrc[2].mMemory == IM_LOCAL) + { + requiredVars += mSrc[2].mVarIndex; + } + else if (mSrc[2].mMemory == paramMemory) + { + requiredParams += mSrc[2].mVarIndex; + } + } + } + } else if (mCode == IC_CONSTANT) { if (mConst.mType == IT_POINTER) @@ -3593,7 +3884,8 @@ bool InterInstruction::RemoveUnusedStaticStoreInstructions(InterCodeBasicBlock* } else if (mSrc[0].mMemory == IM_GLOBAL) { - requiredVars += mSrc[0].mVarIndex; + if (mSrc[0].mVarIndex >= 0) + requiredVars += mSrc[0].mVarIndex; } int k = 0; @@ -3606,7 +3898,7 @@ bool InterInstruction::RemoveUnusedStaticStoreInstructions(InterCodeBasicBlock* } else if (mCode == IC_STORE) { - if (mSrc[1].mMemory == IM_GLOBAL) + if (mSrc[1].mMemory == IM_GLOBAL && mSrc[1].mVarIndex >= 0) { if (requiredVars[mSrc[1].mVarIndex]) { @@ -3643,12 +3935,28 @@ bool InterInstruction::RemoveUnusedStaticStoreInstructions(InterCodeBasicBlock* } } } + else if (mCode == IC_SELECT) + { + if (mDst.mType == IT_POINTER) + { + if (mSrc[1].mTemp < 0) + { + if (mSrc[1].mMemory == IM_GLOBAL && mSrc[1].mVarIndex >= 0) + requiredVars += mSrc[1].mVarIndex; + } + if (mSrc[2].mTemp < 0) + { + if (mSrc[2].mMemory == IM_GLOBAL && mSrc[2].mVarIndex >= 0) + requiredVars += mSrc[2].mVarIndex; + } + } + } else if (mCode == IC_COPY || mCode == IC_STRCPY) { requiredVars.Fill(); storeIns.SetSize(0); } - else if (mCode == IC_CALL || mCode == IC_CALL_NATIVE || mCode == IC_RETURN || mCode == IC_RETURN_STRUCT || mCode == IC_RETURN_VALUE) + else if (mCode == IC_CALL || mCode == IC_CALL_NATIVE || mCode == IC_RETURN || mCode == IC_RETURN_STRUCT || mCode == IC_RETURN_VALUE || mCode == IC_DISPATCH) { requiredVars.Fill(); storeIns.SetSize(0); @@ -3660,6 +3968,57 @@ bool InterInstruction::RemoveUnusedStaticStoreInstructions(InterCodeBasicBlock* return changed; } +bool InterInstruction::RemoveUnusedStaticStoreByteInstructions(InterCodeBasicBlock* block, const GrowingVariableArray& staticVars, NumberSet& requiredVars) +{ + bool changed = false; + + if (mCode == IC_LOAD) + { + if (mSrc[0].mMemory == IM_INDIRECT) + { + if (!mSrc[0].mRestricted) + { + for (int i = 0; i < staticVars.Size(); i++) + { + if (staticVars[i]->mAliased) + requiredVars.AddRange(staticVars[i]->mByteIndex, staticVars[i]->mSize); + } + } + } + else if (mSrc[0].mMemory == IM_GLOBAL) + { + if (mSrc[0].mVarIndex >= 0) + requiredVars.AddRange(staticVars[mSrc[0].mVarIndex]->mByteIndex + int(mSrc[0].mIntConst), InterTypeSize[mDst.mType]); + } + } + else if (mCode == IC_STORE) + { + if (mSrc[1].mMemory == IM_GLOBAL && mSrc[1].mVarIndex >= 0) + { + if (!requiredVars.RangeClear(staticVars[mSrc[1].mVarIndex]->mByteIndex + int(mSrc[1].mIntConst), InterTypeSize[mSrc[0].mType])) + { + requiredVars.SubRange(staticVars[mSrc[1].mVarIndex]->mByteIndex + int(mSrc[1].mIntConst), InterTypeSize[mSrc[0].mType]); + } + else if (!mVolatile) + { + mSrc[0].mTemp = -1; + mCode = IC_NONE; + changed = true; + } + } + } + else if (mCode == IC_COPY || mCode == IC_STRCPY) + { + requiredVars.Fill(); + } + else if (mCode == IC_CALL || mCode == IC_CALL_NATIVE || mCode == IC_RETURN || mCode == IC_RETURN_STRUCT || mCode == IC_RETURN_VALUE || mCode == IC_DISPATCH) + { + requiredVars.Fill(); + } + + return changed; +} + int InterInstruction::NumUsedTemps(void) const { int n = 0; @@ -3780,6 +4139,8 @@ void InterInstruction::BuildCollisionTable(NumberSet& liveTemps, NumberSet* coll { if (mDst.mTemp >= 0) { + // Ensure collision with unused destination register + UpdateCollisionSet(liveTemps, collisionSets, mDst.mTemp); // if (!liveTemps[ttemp]) __asm int 3 liveTemps -= mDst.mTemp; } @@ -3892,6 +4253,13 @@ void InterInstruction::CollectSimpleLocals(FastNumberSet& complexLocals, FastNum } } +void InterInstruction::UnionRanges(InterInstruction* ins) +{ + mDst.mRange.Union(ins->mDst.mRange); + for(int i=0; imSrc[i].mRange); +} + void InterInstruction::SimpleLocalToTemp(int vindex, int temp) { switch (mCode) @@ -4111,7 +4479,7 @@ bool InterInstruction::ConstantFolding(void) } -void InterOperand::Disassemble(FILE* file) +void InterOperand::Disassemble(FILE* file, InterCodeProcedure* proc) { static char typechars[] = "NBCILFP"; @@ -4123,7 +4491,12 @@ void InterOperand::Disassemble(FILE* file) fprintf(file, "R%d(%c)", mTemp, typechars[mType]); if (mType == IT_POINTER && mMemory == IM_INDIRECT) + { fprintf(file, "+%d", int(mIntConst)); + } + + if (mRestricted) + fprintf(file, "{%d}", mRestricted); if (mRange.mMinState >= IntegerValueRange::S_WEAK || mRange.mMaxState >= IntegerValueRange::S_WEAK) { @@ -4146,7 +4519,42 @@ void InterOperand::Disassemble(FILE* file) } else if (mType == IT_POINTER) { - fprintf(file, "V%d+%d", mVarIndex, int(mIntConst)); + const char* vname = ""; + + if (mMemory == IM_LOCAL) + { + if (!proc->mLocalVars[mVarIndex]) + vname = "null"; + else if (!proc->mLocalVars[mVarIndex]->mIdent) + vname = ""; + else + vname = proc->mLocalVars[mVarIndex]->mIdent->mString; + } + else if (mMemory == IM_PROCEDURE) + { + if (proc->mModule->mProcedures[mVarIndex]) + vname = proc->mModule->mProcedures[mVarIndex]->mIdent->mString; + else if (mLinkerObject && mLinkerObject->mIdent) + vname = mLinkerObject->mIdent->mString; + } + else if (mMemory == IM_GLOBAL) + { + if (mVarIndex < 0) + { + if (mLinkerObject && mLinkerObject->mIdent) + vname = mLinkerObject->mIdent->mString; + else + vname = ""; + } + else if (!proc->mModule->mGlobalVars[mVarIndex]) + vname = "null"; + else if (!proc->mModule->mGlobalVars[mVarIndex]->mIdent) + vname = ""; + else + vname = proc->mModule->mGlobalVars[mVarIndex]->mIdent->mString; + } + + fprintf(file, "V(%d '%s')+%d ", mVarIndex, vname, int(mIntConst)); } else if (IsIntegerType(mType) || mType == IT_BOOL) { @@ -4158,7 +4566,7 @@ void InterOperand::Disassemble(FILE* file) } } -void InterInstruction::Disassemble(FILE* file) +void InterInstruction::Disassemble(FILE* file, InterCodeProcedure* proc) { if (this->mCode != IC_NONE) { @@ -4214,6 +4622,16 @@ void InterInstruction::Disassemble(FILE* file) else fprintf(file, "COPY%c%c", memchars[mSrc[0].mMemory], memchars[mSrc[1].mMemory]); break; + + case IC_MALLOC: + assert(mNumOperands == 1); + fprintf(file, "MALLOC"); + break; + case IC_FREE: + assert(mNumOperands == 1); + fprintf(file, "FREE"); + break; + case IC_STRCPY: fprintf(file, "STRCPY%c%c", memchars[mSrc[0].mMemory], memchars[mSrc[1].mMemory]); break; @@ -4260,6 +4678,9 @@ void InterInstruction::Disassemble(FILE* file) case IC_ASSEMBLER: fprintf(file, "JSR"); break; + case IC_DISPATCH: + fprintf(file, "DISPATCH"); + break; case IC_RETURN_VALUE: assert(mNumOperands == 1); fprintf(file, "RETV"); @@ -4279,15 +4700,50 @@ void InterInstruction::Disassemble(FILE* file) fprintf(file, "\t"); if (mDst.mTemp >= 0) - mDst.Disassemble(file); + mDst.Disassemble(file, proc); fprintf(file, "\t<-\t"); if (this->mCode == IC_CONSTANT) { if (mDst.mType == IT_POINTER) - { - fprintf(file, "C%c%d(%d:%d)", memchars[mConst.mMemory], mConst.mOperandSize, mConst.mVarIndex, int(mConst.mIntConst)); + { + const char* vname = ""; + + if (mConst.mMemory == IM_LOCAL) + { + if (mConst.mVarIndex < 0 || !proc->mLocalVars[mConst.mVarIndex]) + vname = "null"; + else if (!proc->mLocalVars[mConst.mVarIndex]->mIdent) + vname = ""; + else + vname = proc->mLocalVars[mConst.mVarIndex]->mIdent->mString; + } + else if (mConst.mMemory == IM_PROCEDURE) + { + if (mConst.mVarIndex >= 0 && proc->mModule->mProcedures[mConst.mVarIndex]) + vname = proc->mModule->mProcedures[mConst.mVarIndex]->mIdent->mString; + else if (mConst.mLinkerObject && mConst.mLinkerObject->mIdent) + vname = mConst.mLinkerObject->mIdent->mString; + } + else if (mConst.mMemory == IM_GLOBAL) + { + if (mConst.mVarIndex < 0) + { + if (mConst.mLinkerObject && mConst.mLinkerObject->mIdent) + vname = mConst.mLinkerObject->mIdent->mString; + else + vname = ""; + } + else if (!proc->mModule->mGlobalVars[mConst.mVarIndex]) + vname = "null"; + else if (!proc->mModule->mGlobalVars[mConst.mVarIndex]->mIdent) + vname = ""; + else + vname = proc->mModule->mGlobalVars[mConst.mVarIndex]->mIdent->mString; + } + + fprintf(file, "C%c%d(%d:%d '%s')", memchars[mConst.mMemory], mConst.mOperandSize, mConst.mVarIndex, int(mConst.mIntConst), vname); } else if (mDst.mType == IT_FLOAT) fprintf(file, "CF:%f", mConst.mFloatConst); @@ -4310,7 +4766,7 @@ void InterInstruction::Disassemble(FILE* file) fprintf(file, ", "); if (mSrc[j].mType != IT_NONE) { - mSrc[j].Disassemble(file); + mSrc[j].Disassemble(file, proc); first = false; } } @@ -4336,7 +4792,7 @@ InterCodeBasicBlock::InterCodeBasicBlock(InterCodeProcedure * proc) mInstructions(nullptr), mEntryRenameTable(-1), mExitRenameTable(-1), mMergeTValues(nullptr), mMergeAValues(nullptr), mTrueJump(nullptr), mFalseJump(nullptr), mLoopPrefix(nullptr), mDominator(nullptr), mEntryValueRange(IntegerValueRange()), mTrueValueRange(IntegerValueRange()), mFalseValueRange(IntegerValueRange()), mLocalValueRange(IntegerValueRange()), mEntryParamValueRange(IntegerValueRange()), mTrueParamValueRange(IntegerValueRange()), mFalseParamValueRange(IntegerValueRange()), mLocalParamValueRange(IntegerValueRange()), - mReverseValueRange(IntegerValueRange()), mEntryBlocks(nullptr), mLoadStoreInstructions(nullptr), mLoopPathBlocks(nullptr), mMemoryValueSize(0), mEntryMemoryValueSize(0) + mReverseValueRange(IntegerValueRange()), mLoadStoreInstructions(nullptr), mMemoryValueSize(0), mEntryMemoryValueSize(0) { mVisited = false; mInPath = false; @@ -4361,6 +4817,23 @@ void InterCodeBasicBlock::Append(InterInstruction * code) { assert(code->mSrc[1].mType != IT_POINTER); } + if (code->mCode == IC_CONSTANT) + { + assert(code->mDst.mType == code->mConst.mType); + } + if (code->mCode == IC_CONSTANT && code->mConst.mType == IT_POINTER && code->mConst.mMemory == IM_GLOBAL && code->mConst.mVarIndex >= 0) + { + assert(code->mConst.mVarIndex < mProc->mModule->mGlobalVars.Size()); + assert(mProc->mModule->mGlobalVars[code->mConst.mVarIndex]); + } + if (code->mCode == IC_STORE) + { + assert(code->mSrc[1].mOperandSize > 0); + } + if (code->mDst.mTemp >= 0) + assert(code->mDst.mType != IT_NONE); + for (int i = 0; i < code->mNumOperands; i++) + assert(code->mSrc[i].mType != IT_NONE); assert(!(code->mInUse)); code->mInUse = true; @@ -4491,14 +4964,32 @@ void InterCodeBasicBlock::GenerateTraces(bool expand, bool compact) if (mInPath) mLoopHead = true; + assert(mIndex != 0 || !mLoopHead); + if (!mVisited) { mVisited = true; mInPath = true; // Limit number of contractions - for (int i=0; i<100; i++) + for (int i = 0; i < 100; i++) { + int sz = mInstructions.Size(); + + if (mFalseJump && sz > 0 && mInstructions[sz - 1]->mCode == IC_BRANCH && mInstructions[sz - 1]->mSrc[0].mType == IT_BOOL && mInstructions[sz - 1]->mSrc[0].mTemp < 0) + { + mInstructions[sz - 1]->mCode = IC_JUMP; + mInstructions[sz - 1]->mNumOperands = 0; + if (!mInstructions[sz - 1]->mSrc[0].mIntConst) + { + mTrueJump->mNumEntries--; + mTrueJump = mFalseJump; + } + else + mFalseJump->mNumEntries--; + mFalseJump = nullptr; + } + if (mTrueJump && mTrueJump->mInstructions.Size() == 1 && mTrueJump->mInstructions[0]->mCode == IC_JUMP && !mTrueJump->mLoopHead && mTrueJump->mTraceIndex != mIndex) { mTrueJump->mTraceIndex = mIndex; @@ -4541,6 +5032,27 @@ void InterCodeBasicBlock::GenerateTraces(bool expand, bool compact) if (mFalseJump) mFalseJump->mNumEntries++; } + else if ( + compact && + mFalseJump && + mInstructions.Size() > 0 && + mInstructions.Last()->mCode == IC_BRANCH && + mInstructions.Last()->mSrc[0].mTemp < 0) + { + int ns = mInstructions.Size(); + + if (mInstructions.Last()->mSrc[0].mIntConst) + mFalseJump->mNumEntries--; + else + { + mTrueJump->mNumEntries--; + mTrueJump = mFalseJump; + } + + mFalseJump = nullptr; + mInstructions[ns - 1]->mCode = IC_JUMP; + mInstructions[ns - 1]->mNumOperands = 0; + } else if (mTrueJump && !mFalseJump && ((expand && mTrueJump->mInstructions.Size() < 10 && mTrueJump->mInstructions.Size() > 1 && !mLoopHead) || mTrueJump->mNumEntries == 1) && !mTrueJump->mLoopHead && !IsInfiniteLoop(mTrueJump, mTrueJump)) { mTrueJump->mNumEntries--; @@ -4613,7 +5125,7 @@ bool InterCodeBasicBlock::MergeSameConditionTraces(void) if (mb1 && mb1->mNumEntries == 2 && mb0 != mb1) { int tc = mInstructions.Last()->mSrc[0].mTemp; - if (tc == mb0->mInstructions.Last()->mSrc[0].mTemp) + if (tc >= 0 && tc == mb0->mInstructions.Last()->mSrc[0].mTemp) { if (!mTrueJump->mLocalModifiedTemps[tc] && !mFalseJump->mLocalModifiedTemps[tc] && !mb0->mLocalModifiedTemps[tc]) { @@ -4790,6 +5302,7 @@ void InterCodeBasicBlock::CheckValueUsage(InterInstruction * ins, const GrowingI break; } } + break; case IC_LOAD: @@ -4816,6 +5329,7 @@ void InterCodeBasicBlock::CheckValueUsage(InterInstruction * ins, const GrowingI break; } } + OptimizeAddress(ins, tvalue, 1); break; case IC_COPY: @@ -4962,12 +5476,11 @@ void InterCodeBasicBlock::CheckValueUsage(InterInstruction * ins, const GrowingI break; case IC_SELECT: - for(int i=0; i<3; i++) + for (int i = 0; i < 3; i++) { - if (ins->mSrc[i].mTemp >= 0 && tvalue[ins->mSrc[i].mTemp] && tvalue[ins->mSrc[i].mTemp]->mCode == IC_CONSTANT) + if (ins->mSrc[i].mTemp >= 0 && tvalue[ins->mSrc[i].mTemp] && tvalue[ins->mSrc[i].mTemp]->mCode == IC_CONSTANT && ins->mSrc[i].mType != IT_POINTER) { ins->mSrc[i] = tvalue[ins->mSrc[i].mTemp]->mConst; - ins->mSrc[i].mType = ins->mDst.mType; ins->mSrc[i].mTemp = -1; } } @@ -5393,6 +5906,7 @@ void InterCodeBasicBlock::CheckValueUsage(InterInstruction * ins, const GrowingI if (ins->mSrc[0].mTemp >= 0 && tvalue[ins->mSrc[0].mTemp] && tvalue[ins->mSrc[0].mTemp]->mCode == IC_CONSTANT) { ins->mSrc[0].mIntConst = tvalue[ins->mSrc[0].mTemp]->mConst.mIntConst; + ins->mSrc[0].mMemory = tvalue[ins->mSrc[0].mTemp]->mConst.mMemory; ins->mSrc[0].mTemp = -1; } break; @@ -5565,6 +6079,8 @@ void InterCodeBasicBlock::CollectConstTemps(GrowingInstructionPtrArray& ctemps, { if (mInstructions[i]->mCode == IC_CONSTANT) ltemps[ttemp] = mInstructions[i]; + else + ltemps[ttemp] = nullptr; if (assignedTemps[ttemp]) ctemps[ttemp] = nullptr; @@ -5831,7 +6347,11 @@ void InterCodeBasicBlock::SimplifyIntegerRangeRelops(void) constFalse = true; break; case IA_CMPLU: - if (cins->mSrc[1].IsUnsigned() && cins->mSrc[0].IsUnsigned()) + if (cins->mSrc[0].mTemp < 0 && cins->mSrc[0].mIntConst == 0) + { + constFalse = true; + } + else if (cins->mSrc[1].IsUnsigned() && cins->mSrc[0].IsUnsigned()) { if (cins->mSrc[1].mRange.mMaxValue < cins->mSrc[0].mRange.mMinValue) constTrue = true; @@ -5861,7 +6381,15 @@ void InterCodeBasicBlock::SimplifyIntegerRangeRelops(void) constFalse = true; break; case IA_CMPGU: - if (cins->mSrc[1].IsUnsigned() && cins->mSrc[0].IsUnsigned()) + if (cins->mSrc[1].mTemp < 0 && cins->mSrc[1].mIntConst == 0) + { + constFalse = true; + } + else if (cins->mSrc[1].IsUnsigned() && cins->mSrc[1].mRange.mMaxValue == 0) + { + constFalse = true; + } + else if (cins->mSrc[1].IsUnsigned() && cins->mSrc[0].IsUnsigned()) { if (cins->mSrc[1].mRange.mMinValue > cins->mSrc[0].mRange.mMaxValue) constTrue = true; @@ -6082,7 +6610,10 @@ bool InterCodeBasicBlock::BuildGlobalIntegerRangeSets(bool initial, const Growin else { for (int i = 0; i < mLocalValueRange.Size(); i++) - mLocalValueRange[i].Merge(range[i], mLoopHead, initial); + { + if (this != from || IsTempModified(i)) + mLocalValueRange[i].Merge(range[i], mLoopHead, initial); + } for (int i = 0; i < mLocalParamValueRange.Size(); i++) mLocalParamValueRange[i].Merge(prange[i], mLoopHead, initial); } @@ -6118,8 +6649,15 @@ bool InterCodeBasicBlock::BuildGlobalIntegerRangeSets(bool initial, const Growin if (changed) { - mEntryValueRange = mLocalValueRange; - mEntryParamValueRange = mLocalParamValueRange; + for (int i = 0; i < mLocalValueRange.Size(); i++) + mEntryValueRange[i].Expand(mLocalValueRange[i]); + for (int i = 0; i < mLocalParamValueRange.Size(); i++) + mEntryParamValueRange[i].Expand(mLocalParamValueRange[i]); + mLocalValueRange = mEntryValueRange; + mLocalParamValueRange = mEntryParamValueRange; + +// mEntryValueRange = mLocalValueRange; +// mEntryParamValueRange = mLocalParamValueRange; UpdateLocalIntegerRangeSets(localVars, paramVars); @@ -6171,6 +6709,70 @@ static int64 BuildLowerBitsMask(int64 v) return v; } +void InterCodeBasicBlock::UnionIntegerRanges(const InterCodeBasicBlock* block) +{ + if (mEntryValueRange.Size() > 0) + { + if (block->mEntryValueRange.Size()) + { + assert(mEntryValueRange.Size() == block->mEntryValueRange.Size()); + + for (int i = 0; i < mEntryValueRange.Size(); i++) + mEntryValueRange[i].Union(block->mEntryValueRange[i]); + } + else + mEntryValueRange.SetSize(0); + } + + for (int i = 0; i < mInstructions.Size(); i++) + { + assert(mInstructions[i]->IsEqual(block->mInstructions[i])); + mInstructions[i]->UnionRanges(block->mInstructions[i]); + } + +} + +void InterCodeBasicBlock::MarkIntegerRangeBoundUp(int temp, int64 value, GrowingIntegerValueRangeArray& range) +{ + range[temp].SetLimit(value, value); + + for (int i = mInstructions.Size() - 1; i >= 0; i--) + { + InterInstruction* ins(mInstructions[i]); + + if (ins->mDst.mTemp == temp) + { + if (ins->mCode == IC_BINARY_OPERATOR && ins->mSrc[1].mTemp == temp && ins->mSrc[0].mTemp < 0) + { + switch (ins->mOperator) + { + case IA_ADD: + value -= ins->mSrc[0].mIntConst; + break; + case IA_SUB: + value += ins->mSrc[0].mIntConst; + break; + default: + return; + } + } + else if (ins->mCode == IC_LOAD_TEMPORARY) + { + if (!IsTempModifiedInRange(i + 1, mInstructions.Size(), ins->mSrc[0].mTemp)) + range[ins->mSrc[0].mTemp].SetLimit(value, value); + temp = ins->mSrc[0].mTemp; + } + else + return; + } + else if (ins->mCode == IC_LOAD_TEMPORARY && ins->mSrc[0].mTemp == temp) + { + if (!IsTempModifiedInRange(i + 1, mInstructions.Size(), ins->mDst.mTemp)) + range[ins->mDst.mTemp].SetLimit(value, value); + } + } +} + void InterCodeBasicBlock::UpdateLocalIntegerRangeSets(const GrowingVariableArray& localVars, const GrowingVariableArray& paramVars) { mLocalValueRange = mEntryValueRange; @@ -6246,7 +6848,7 @@ void InterCodeBasicBlock::UpdateLocalIntegerRangeSets(const GrowingVariableArray { if (ins->mSrc[i].mTemp >= 0) { - ins->mSrc[i].mRange = mLocalValueRange[ins->mSrc[i].mTemp]; + ins->mSrc[i].mRange.MergeUnknown(mLocalValueRange[ins->mSrc[i].mTemp]); #if 1 if (ins->mCode != IC_ASSEMBLER&& ins->mSrc[i].mRange.mMinState == IntegerValueRange::S_BOUND && ins->mSrc[i].mRange.mMaxState == IntegerValueRange::S_BOUND && ins->mSrc[i].mRange.mMinValue == ins->mSrc[i].mRange.mMaxValue) { @@ -6310,12 +6912,16 @@ void InterCodeBasicBlock::UpdateLocalIntegerRangeSets(const GrowingVariableArray { if (ins->mDst.mType == IT_INT8) { - bool isUnsigned = false; - if (i + 1 < mInstructions.Size() && mInstructions[i + 1]->mCode == IC_CONVERSION_OPERATOR && mInstructions[i + 1]->mOperator == IA_EXT8TO16U && - mInstructions[i + 1]->mSrc[0].mTemp == mInstructions[i + 0]->mDst.mTemp && mInstructions[i + 1]->mSrc[0].mFinal) - isUnsigned = true; + bool isUnsigned = false, isSigned = false; + if (i + 1 < mInstructions.Size() && mInstructions[i + 1]->mCode == IC_CONVERSION_OPERATOR && mInstructions[i + 1]->mSrc[0].mTemp == mInstructions[i + 0]->mDst.mTemp && mInstructions[i + 1]->mSrc[0].mFinal) + { + if (mInstructions[i + 1]->mOperator == IA_EXT8TO16U) + isUnsigned = true; + else if (mInstructions[i + 1]->mOperator == IA_EXT8TO16S) + isSigned = true; + } - int mi = 0, ma = 0; + int mi = 255, ma = 0; if (vr.mMinState == IntegerValueRange::S_BOUND && vr.mMaxState == IntegerValueRange::S_BOUND && vr.mMinValue >= -128 && vr.mMaxValue <= 127) @@ -6334,8 +6940,15 @@ void InterCodeBasicBlock::UpdateLocalIntegerRangeSets(const GrowingVariableArray for (int j = 0; j < lo->mSize; j++) { int v = lo->mData[j]; - if (!isUnsigned && (v & 0x80)) + if (isUnsigned) + ; + else if (isSigned) + v = (int8)v; + else if (v & 0x80) mi = -128; + + if (v < mi) + mi = v; if (v > ma) ma = v; } @@ -6384,6 +6997,7 @@ void InterCodeBasicBlock::UpdateLocalIntegerRangeSets(const GrowingVariableArray switch (ins->mOperator) { case IA_EXT8TO16S: + case IA_EXT8TO32S: vr = ins->mSrc[0].mRange; if (vr.mMaxState != IntegerValueRange::S_BOUND || vr.mMaxValue < -128 || vr.mMaxValue > 127) { @@ -6397,17 +7011,56 @@ void InterCodeBasicBlock::UpdateLocalIntegerRangeSets(const GrowingVariableArray } break; - case IA_EXT8TO16U: + case IA_EXT16TO32S: vr = ins->mSrc[0].mRange; - if (vr.mMaxState != IntegerValueRange::S_BOUND || vr.mMaxValue < 0 || vr.mMaxValue > 255 || vr.mMinValue < 0 || - vr.mMinState != IntegerValueRange::S_BOUND) + if (vr.mMaxState != IntegerValueRange::S_BOUND || vr.mMaxValue < -65536 || vr.mMaxValue > 65535) + { + vr.mMaxState = IntegerValueRange::S_BOUND; + vr.mMaxValue = 65535; + } + if (vr.mMinState != IntegerValueRange::S_BOUND || vr.mMinValue < -65536 || vr.mMinValue > 65535) + { + vr.mMinState = IntegerValueRange::S_BOUND; + vr.mMinValue = -65536; + } + break; + + case IA_EXT8TO16U: + case IA_EXT8TO32U: + vr = ins->mSrc[0].mRange; + if (vr.mMaxState != IntegerValueRange::S_UNKNOWN && vr.mMinState == IntegerValueRange::S_BOUND && vr.mMinValue > 0) { vr.mMaxState = IntegerValueRange::S_BOUND; vr.mMaxValue = 255; + } + else + { + if (vr.mMaxState != IntegerValueRange::S_BOUND || vr.mMaxValue < 0 || vr.mMaxValue > 255 || vr.mMinValue < 0 || + vr.mMinState != IntegerValueRange::S_BOUND) + { + vr.mMaxState = IntegerValueRange::S_BOUND; + vr.mMaxValue = 255; + vr.mMinState = IntegerValueRange::S_BOUND; + vr.mMinValue = 0; + } + if (vr.mMinState != IntegerValueRange::S_BOUND || vr.mMinValue < 0 || vr.mMinValue > 255) + { + vr.mMinState = IntegerValueRange::S_BOUND; + vr.mMinValue = 0; + } + } + break; + case IA_EXT16TO32U: + vr = ins->mSrc[0].mRange; + if (vr.mMaxState != IntegerValueRange::S_BOUND || vr.mMaxValue < 0 || vr.mMaxValue > 65535 || vr.mMinValue < 0 || + vr.mMinState != IntegerValueRange::S_BOUND) + { + vr.mMaxState = IntegerValueRange::S_BOUND; + vr.mMaxValue = 65535; vr.mMinState = IntegerValueRange::S_BOUND; vr.mMinValue = 0; } - if (vr.mMinState != IntegerValueRange::S_BOUND || vr.mMinValue < 0 || vr.mMinValue > 255) + if (vr.mMinState != IntegerValueRange::S_BOUND || vr.mMinValue < 0 || vr.mMinValue > 65535) { vr.mMinState = IntegerValueRange::S_BOUND; vr.mMinValue = 0; @@ -6497,16 +7150,21 @@ void InterCodeBasicBlock::UpdateLocalIntegerRangeSets(const GrowingVariableArray else if (ins->mSrc[1].mTemp < 0) { vr = mLocalValueRange[ins->mSrc[0].mTemp]; + + IntegerValueRange::State s = vr.mMinState; + vr.mMinState = vr.mMaxState; + vr.mMaxState = s; + int64 maxv = vr.mMaxValue, minv = vr.mMinValue; - if (vr.mMaxState == IntegerValueRange::S_WEAK) - { - if (vr.mMinState == IntegerValueRange::S_WEAK) - vr.mMaxState = IntegerValueRange::S_UNBOUND; - vr.mMinState = IntegerValueRange::S_UNBOUND; - } if (vr.mMinState == IntegerValueRange::S_WEAK) + { + if (vr.mMaxState == IntegerValueRange::S_WEAK) + vr.mMinState = IntegerValueRange::S_UNBOUND; vr.mMaxState = IntegerValueRange::S_UNBOUND; + } + if (vr.mMaxState == IntegerValueRange::S_WEAK) + vr.mMinState = IntegerValueRange::S_UNBOUND; vr.mMaxValue = ins->mSrc[1].mIntConst - minv; vr.mMinValue = ins->mSrc[1].mIntConst - maxv; @@ -6817,6 +7475,10 @@ void InterCodeBasicBlock::UpdateLocalIntegerRangeSets(const GrowingVariableArray vr.LimitMax(ins->mSrc[0].mIntConst - 1); else if (ins->mSrc[0].mRange.mMaxState == IntegerValueRange::S_BOUND) vr.LimitMax(ins->mSrc[0].mRange.mMaxValue - 1); + else if (ins->mSrc[1].mRange.mMaxState == IntegerValueRange::S_BOUND) + vr.LimitMax(ins->mSrc[1].mRange.mMaxValue); + else + vr.mMaxState = IntegerValueRange::S_UNBOUND; break; #endif default: @@ -6840,7 +7502,7 @@ void InterCodeBasicBlock::UpdateLocalIntegerRangeSets(const GrowingVariableArray vr.LimitMaxBound(65535); } #endif - ins->mDst.mRange = vr; + ins->mDst.mRange.MergeUnknown(vr); #if 1 if (vr.mMaxState == IntegerValueRange::S_BOUND && vr.mMinState == IntegerValueRange::S_BOUND && vr.mMaxValue == vr.mMinValue) { @@ -6930,11 +7592,36 @@ void InterCodeBasicBlock::UpdateLocalIntegerRangeSets(const GrowingVariableArray case IA_SHL: if (ins->mSrc[0].mTemp < 0 && ins->mSrc[1].mTemp >= 0) { - if (vr.mMinState == IntegerValueRange::S_BOUND) - ins->mSrc[1].mRange.LimitMin(vr.mMinValue >> ins->mSrc[0].mIntConst); - if (vr.mMaxState == IntegerValueRange::S_BOUND) - ins->mSrc[1].mRange.LimitMax(vr.mMaxValue >> ins->mSrc[0].mIntConst); - mReverseValueRange[ins->mSrc[1].mTemp].Limit(ins->mSrc[1].mRange); + if (ins->mDst.mType == IT_INT16) + { + if (vr.mMinState == IntegerValueRange::S_BOUND && vr.mMinValue >= -0x4000 && + vr.mMaxState == IntegerValueRange::S_BOUND && vr.mMaxValue < 0x4000) + { + ins->mSrc[1].mRange.LimitMin(vr.mMinValue >> ins->mSrc[0].mIntConst); + ins->mSrc[1].mRange.LimitMax(vr.mMaxValue >> ins->mSrc[0].mIntConst); + mReverseValueRange[ins->mSrc[1].mTemp].Limit(ins->mSrc[1].mRange); + } + } + else if (ins->mDst.mType == IT_INT8) + { + if (vr.mMinState == IntegerValueRange::S_BOUND && vr.mMinValue >= -0x40 && + vr.mMaxState == IntegerValueRange::S_BOUND && vr.mMaxValue < 0x40) + { + ins->mSrc[1].mRange.LimitMin(vr.mMinValue >> ins->mSrc[0].mIntConst); + ins->mSrc[1].mRange.LimitMax(vr.mMaxValue >> ins->mSrc[0].mIntConst); + mReverseValueRange[ins->mSrc[1].mTemp].Limit(ins->mSrc[1].mRange); + } + } + else if (ins->mDst.mType == IT_INT32) + { + if (vr.mMinState == IntegerValueRange::S_BOUND && vr.mMinValue >= -0x40000000 && + vr.mMaxState == IntegerValueRange::S_BOUND && vr.mMaxValue < 0x40000000) + { + ins->mSrc[1].mRange.LimitMin(vr.mMinValue >> ins->mSrc[0].mIntConst); + ins->mSrc[1].mRange.LimitMax(vr.mMaxValue >> ins->mSrc[0].mIntConst); + mReverseValueRange[ins->mSrc[1].mTemp].Limit(ins->mSrc[1].mRange); + } + } } break; case IA_SUB: @@ -7076,34 +7763,46 @@ void InterCodeBasicBlock::UpdateLocalIntegerRangeSets(const GrowingVariableArray case IA_CMPEQ: if (s0 < 0) { + MarkIntegerRangeBoundUp(s1, mInstructions[sz - 2]->mSrc[0].mIntConst, mTrueValueRange); +#if 0 mTrueValueRange[s1].mMinState = IntegerValueRange::S_BOUND; mTrueValueRange[s1].mMinValue = mInstructions[sz - 2]->mSrc[0].mIntConst; mTrueValueRange[s1].mMaxState = IntegerValueRange::S_BOUND; mTrueValueRange[s1].mMaxValue = mInstructions[sz - 2]->mSrc[0].mIntConst; +#endif } else if (s1 < 0) { + MarkIntegerRangeBoundUp(s0, mInstructions[sz - 2]->mSrc[1].mIntConst, mTrueValueRange); +#if 0 mTrueValueRange[s0].mMinState = IntegerValueRange::S_BOUND; mTrueValueRange[s0].mMinValue = mInstructions[sz - 2]->mSrc[1].mIntConst; mTrueValueRange[s0].mMaxState = IntegerValueRange::S_BOUND; mTrueValueRange[s0].mMaxValue = mInstructions[sz - 2]->mSrc[1].mIntConst; +#endif } break; case IA_CMPNE: if (s0 < 0) { + MarkIntegerRangeBoundUp(s1, mInstructions[sz - 2]->mSrc[0].mIntConst, mFalseValueRange); +#if 0 mFalseValueRange[s1].mMinState = IntegerValueRange::S_BOUND; mFalseValueRange[s1].mMinValue = mInstructions[sz - 2]->mSrc[0].mIntConst; mFalseValueRange[s1].mMaxState = IntegerValueRange::S_BOUND; mFalseValueRange[s1].mMaxValue = mInstructions[sz - 2]->mSrc[0].mIntConst; +#endif } else if (s1 < 0) { + MarkIntegerRangeBoundUp(s0, mInstructions[sz - 2]->mSrc[1].mIntConst, mFalseValueRange); +#if 0 mFalseValueRange[s0].mMinState = IntegerValueRange::S_BOUND; mFalseValueRange[s0].mMinValue = mInstructions[sz - 2]->mSrc[1].mIntConst; mFalseValueRange[s0].mMaxState = IntegerValueRange::S_BOUND; mFalseValueRange[s0].mMaxValue = mInstructions[sz - 2]->mSrc[1].mIntConst; +#endif } break; #endif @@ -7145,16 +7844,37 @@ void InterCodeBasicBlock::UpdateLocalIntegerRangeSets(const GrowingVariableArray else { if (mLocalValueRange[s0].mMaxState == IntegerValueRange::S_BOUND) - mTrueValueRange[s1].LimitMax(mLocalValueRange[s0].mMaxValue - 1); + mTrueValueRange[s1].LimitMaxWeak(mLocalValueRange[s0].mMaxValue - 1); if (mLocalValueRange[s0].mMinState == IntegerValueRange::S_BOUND) - mFalseValueRange[s1].LimitMin(mLocalValueRange[s0].mMinValue); + mFalseValueRange[s1].LimitMinWeak(mLocalValueRange[s0].mMinValue); } break; case IA_CMPLES: if (s0 < 0) { mTrueValueRange[s1].LimitMax(mInstructions[sz - 2]->mSrc[0].mIntConst); + mTrueValueRange[s1].LimitMinWeak(SignedTypeMin(mInstructions[sz - 2]->mSrc[1].mType)); mFalseValueRange[s1].LimitMin(mInstructions[sz - 2]->mSrc[0].mIntConst + 1); + mFalseValueRange[s1].LimitMaxWeak(SignedTypeMax(mInstructions[sz - 2]->mSrc[1].mType)); + } + else if (s1 < 0) + { + mTrueValueRange[s0].LimitMin(mInstructions[sz - 2]->mSrc[1].mIntConst); + mTrueValueRange[s0].LimitMaxWeak(SignedTypeMax(mInstructions[sz - 2]->mSrc[0].mType)); + mFalseValueRange[s0].LimitMax(mInstructions[sz - 2]->mSrc[1].mIntConst - 1); + mFalseValueRange[s0].LimitMinWeak(SignedTypeMin(mInstructions[sz - 2]->mSrc[0].mType)); + } + else + { + if (mLocalValueRange[s0].mMaxState == IntegerValueRange::S_BOUND) + mFalseValueRange[s1].LimitMin(mLocalValueRange[s0].mMinValue + 1); + if (mLocalValueRange[s0].mMinState == IntegerValueRange::S_BOUND) + mTrueValueRange[s1].LimitMax(mLocalValueRange[s0].mMaxValue); + + if (mLocalValueRange[s1].mMaxState == IntegerValueRange::S_BOUND) + mFalseValueRange[s0].LimitMax(mLocalValueRange[s1].mMaxValue - 1); + if (mLocalValueRange[s1].mMinState == IntegerValueRange::S_BOUND) + mTrueValueRange[s0].LimitMin(mLocalValueRange[s1].mMinValue); } break; case IA_CMPGS: @@ -7201,7 +7921,7 @@ void InterCodeBasicBlock::UpdateLocalIntegerRangeSets(const GrowingVariableArray if (s0 < 0) { mTrueValueRange[s1].LimitMax(mInstructions[sz - 2]->mSrc[0].mIntConst - 1); - mTrueValueRange[s1].LimitMin(0); + mTrueValueRange[s1].LimitMinWeak(0); if (mFalseValueRange[s1].mMinState == IntegerValueRange::S_BOUND && mFalseValueRange[s1].mMinValue >= 0) { @@ -7211,7 +7931,7 @@ void InterCodeBasicBlock::UpdateLocalIntegerRangeSets(const GrowingVariableArray else if (mInstructions[sz - 2]->mSrc[0].mRange.mMaxState == IntegerValueRange::S_BOUND) { mTrueValueRange[s1].LimitMax(mInstructions[sz - 2]->mSrc[0].mRange.mMaxValue - 1); - mTrueValueRange[s1].LimitMin(0); + mTrueValueRange[s1].LimitMinWeak(0); if (mFalseValueRange[s1].mMinState == IntegerValueRange::S_BOUND && mFalseValueRange[s1].mMinValue >= 0) { @@ -7287,6 +8007,26 @@ void InterCodeBasicBlock::UpdateLocalIntegerRangeSets(const GrowingVariableArray +void InterCodeBasicBlock::PruneUnusedIntegerRangeSets(void) +{ + if (!mVisited) + { + mVisited = true; + + if (mEntryValueRange.Size() > 0 && mEntryRequiredTemps.Size()) + { + for (int i = 0; i < mEntryValueRange.Size(); i++) + { + if (!mEntryRequiredTemps[i]) + mEntryValueRange[i].Reset(); + } + } + + if (mTrueJump) mTrueJump->PruneUnusedIntegerRangeSets(); + if (mFalseJump) mFalseJump->PruneUnusedIntegerRangeSets(); + } +} + void InterCodeBasicBlock::RestartLocalIntegerRangeSets(int num, const GrowingVariableArray& localVars, const GrowingVariableArray& paramVars) { if (!mVisited) @@ -7308,21 +8048,16 @@ void InterCodeBasicBlock::RestartLocalIntegerRangeSets(int num, const GrowingVar mLocalParamValueRange.SetSize(paramVars.Size(), false); for (int i = 0; i < mEntryValueRange.Size(); i++) - { - IntegerValueRange& vr(mEntryValueRange[i]); - if (vr.mMinState == IntegerValueRange::S_UNBOUND) - vr.mMinState = IntegerValueRange::S_UNKNOWN; - if (vr.mMaxState == IntegerValueRange::S_UNBOUND) - vr.mMaxState = IntegerValueRange::S_UNKNOWN; - } + mEntryValueRange[i].Restart(); for (int i = 0; i < mEntryParamValueRange.Size(); i++) + mEntryParamValueRange[i].Restart(); + + for (int i = 0; i < mInstructions.Size(); i++) { - IntegerValueRange& vr(mEntryParamValueRange[i]); - if (vr.mMinState == IntegerValueRange::S_UNBOUND) - vr.mMinState = IntegerValueRange::S_UNKNOWN; - if (vr.mMaxState == IntegerValueRange::S_UNBOUND) - vr.mMaxState = IntegerValueRange::S_UNKNOWN; + mInstructions[i]->mDst.mRange.Restart(); + for (int j = 0; j < mInstructions[i]->mNumOperands; j++) + mInstructions[i]->mSrc[j].mRange.Restart(); } UpdateLocalIntegerRangeSets(localVars, paramVars); @@ -7365,8 +8100,8 @@ void InterCodeBasicBlock::BuildConstTempSets(void) { mVisited = true; - mEntryConstTemp = NumberSet(mEntryRequiredTemps.Size()); - mExitConstTemp = NumberSet(mEntryRequiredTemps.Size()); + mEntryConstTemp.Reset(mEntryRequiredTemps.Size()); + mExitConstTemp.Reset(mEntryRequiredTemps.Size()); for (i = 0; i < mInstructions.Size(); i++) { @@ -7571,6 +8306,8 @@ static bool SameSingleAssignment(const GrowingInstructionPtrArray& tunified, con { return false; } + else if (!tunified[ins->mSrc[i].mTemp]) + return false; else if (tunified[ins->mSrc[i].mTemp] != tunified[cins->mSrc[i].mTemp]) return false; } @@ -7696,11 +8433,13 @@ bool InterCodeBasicBlock::CalculateSingleAssignmentTemps(FastNumberSet& tassigne bool valid = j == ins->mNumOperands; if (valid) { - if (ins->mCode == IC_CALL || ins->mCode == IC_CALL_NATIVE || ins->mCode == IC_ASSEMBLER) + if (ins->mCode == IC_CALL || ins->mCode == IC_CALL_NATIVE || ins->mCode == IC_ASSEMBLER || ins->mCode == IC_MALLOC || ins->mCode == IC_FREE) valid = false; else if (ins->mCode == IC_LOAD) { - if (ins->mSrc[0].mMemory == paramMemory) + if (ins->mVolatile) + valid = false; + else if (ins->mSrc[0].mMemory == paramMemory) { if (modifiedParams[ins->mSrc[0].mVarIndex]) valid = false; @@ -7789,7 +8528,7 @@ void InterCodeBasicBlock::PerformTempForwarding(const TempForwardingTable& forwa } else if (mLoopPrefix && checkloops) { - GrowingArray body(nullptr); + ExpandingArray body; body.Push(this); bool innerLoop = true; @@ -7797,7 +8536,7 @@ void InterCodeBasicBlock::PerformTempForwarding(const TempForwardingTable& forwa { if (mEntryBlocks[i] != mLoopPrefix) { - if (!mEntryBlocks[i]->CollectLoopBody(this, body)) + if (!mEntryBlocks[i]->CollectLoopBodyRecursive(this, body)) innerLoop = false; } } @@ -7855,18 +8594,20 @@ bool InterCodeBasicBlock::BuildGlobalRequiredTempSet(NumberSet& fromRequiredTemp { mVisited = true; - NumberSet newRequiredTemps(mExitRequiredTemps); + mNewRequiredTemps = mExitRequiredTemps; - if (mTrueJump && mTrueJump->BuildGlobalRequiredTempSet(newRequiredTemps)) revisit = true; - if (mFalseJump && mFalseJump->BuildGlobalRequiredTempSet(newRequiredTemps)) revisit = true; +// NumberSet newRequiredTemps(mExitRequiredTemps); - if (!(newRequiredTemps <= mExitRequiredTemps)) + if (mTrueJump && mTrueJump->BuildGlobalRequiredTempSet(mNewRequiredTemps)) revisit = true; + if (mFalseJump && mFalseJump->BuildGlobalRequiredTempSet(mNewRequiredTemps)) revisit = true; + + if (!(mNewRequiredTemps <= mExitRequiredTemps)) { revisit = true; - mExitRequiredTemps = newRequiredTemps; - newRequiredTemps -= mLocalProvidedTemps; - mEntryRequiredTemps |= newRequiredTemps; + mExitRequiredTemps = mNewRequiredTemps; + mNewRequiredTemps -= mLocalProvidedTemps; + mEntryRequiredTemps |= mNewRequiredTemps; } } @@ -7913,6 +8654,44 @@ bool InterCodeBasicBlock::RemoveUnusedResultInstructions(void) return changed; } +bool InterCodeBasicBlock::RemoveUnusedLocalStoreInstructions(void) +{ + bool changed = false; + + if (!mVisited) + { + mVisited = true; + if (mInstructions.Size() > 0 && mInstructions.Last()->mCode == IC_RETURN) + { + int i = mInstructions.Size(); + while (i > 0) + { + i--; + InterInstruction* ins = mInstructions[i]; + if (ins->mCode == IC_STORE && ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mMemory == IM_LOCAL) + { + ins->mCode = IC_NONE; + ins->mNumOperands = 0; + changed = true; + } + else if (ins->mCode == IC_LOAD) + break; + else if (ins->mCode == IC_CALL || ins->mCode == IC_CALL_NATIVE) + break; + else if (ins->mCode == IC_COPY || ins->mCode == IC_STRCPY) + break; + } + } + + if (mTrueJump && mTrueJump->RemoveUnusedLocalStoreInstructions()) + changed = true; + if (mFalseJump && mFalseJump->RemoveUnusedLocalStoreInstructions()) + changed = true; + } + + return false; +} + void InterCodeBasicBlock::BuildCallerSaveTempSet(NumberSet& callerSaveTemps) { if (!mVisited) @@ -7939,13 +8718,13 @@ void InterCodeBasicBlock::BuildStaticVariableSet(const GrowingVariableArray& sta { mVisited = true; - mLocalRequiredStatics = NumberSet(staticVars.Size()); - mLocalProvidedStatics = NumberSet(staticVars.Size()); + mLocalRequiredStatics.Reset(staticVars.Size()); + mLocalProvidedStatics.Reset(staticVars.Size()); - mEntryRequiredStatics = NumberSet(staticVars.Size()); - mEntryProvidedStatics = NumberSet(staticVars.Size()); - mExitRequiredStatics = NumberSet(staticVars.Size()); - mExitProvidedStatics = NumberSet(staticVars.Size()); + mEntryRequiredStatics.Reset(staticVars.Size()); + mEntryProvidedStatics.Reset(staticVars.Size()); + mExitRequiredStatics.Reset(staticVars.Size()); + mExitProvidedStatics.Reset(staticVars.Size()); for (int i = 0; i < mInstructions.Size(); i++) mInstructions[i]->FilterStaticVarsUsage(staticVars, mLocalRequiredStatics, mLocalProvidedStatics); @@ -8035,6 +8814,67 @@ bool InterCodeBasicBlock::RemoveUnusedStaticStoreInstructions(const GrowingVaria return changed; } + +void InterCodeBasicBlock::BuildStaticVariableByteSet(const GrowingVariableArray& staticVars, int bsize) +{ + if (!mVisited) + { + mVisited = true; + + mLocalRequiredStatics.Reset(bsize); + mLocalProvidedStatics.Reset(bsize); + + mEntryRequiredStatics.Reset(bsize); + mEntryProvidedStatics.Reset(bsize); + mExitRequiredStatics.Reset(bsize); + mExitProvidedStatics.Reset(bsize); + + for (int i = 0; i < mInstructions.Size(); i++) + mInstructions[i]->FilterStaticVarsByteUsage(staticVars, mLocalRequiredStatics, mLocalProvidedStatics); + + mEntryRequiredStatics = mLocalRequiredStatics; + mExitProvidedStatics = mLocalProvidedStatics; + + if (mTrueJump) mTrueJump->BuildStaticVariableByteSet(staticVars, bsize); + if (mFalseJump) mFalseJump->BuildStaticVariableByteSet(staticVars, bsize); + } +} + +bool InterCodeBasicBlock::RemoveUnusedStaticStoreByteInstructions(const GrowingVariableArray& staticVars, int bsize) +{ + bool changed = false; + + if (!mVisited) + { + mVisited = true; + + NumberSet requiredVars(mExitRequiredStatics); + + int i; + + for (i = mInstructions.Size() - 1; i >= 0; i--) + { + if (mInstructions[i]->RemoveUnusedStaticStoreByteInstructions(this, staticVars, requiredVars)) + changed = true; + } + + if (mTrueJump) + { + if (mTrueJump->RemoveUnusedStaticStoreByteInstructions(staticVars, bsize)) + changed = true; + } + if (mFalseJump) + { + if (mFalseJump->RemoveUnusedStaticStoreByteInstructions(staticVars, bsize)) + changed = true; + } + } + + return changed; +} + + + void InterCodeBasicBlock::BuildLocalVariableSets(const GrowingVariableArray& localVars, const GrowingVariableArray& params, InterMemory paramMemory) { int i; @@ -8043,21 +8883,21 @@ void InterCodeBasicBlock::BuildLocalVariableSets(const GrowingVariableArray& loc { mVisited = true; - mLocalRequiredVars = NumberSet(localVars.Size()); - mLocalProvidedVars = NumberSet(localVars.Size()); + mLocalRequiredVars.Reset(localVars.Size()); + mLocalProvidedVars.Reset(localVars.Size()); - mEntryRequiredVars = NumberSet(localVars.Size()); - mEntryProvidedVars = NumberSet(localVars.Size()); - mExitRequiredVars = NumberSet(localVars.Size()); - mExitProvidedVars = NumberSet(localVars.Size()); + mEntryRequiredVars.Reset(localVars.Size()); + mEntryProvidedVars.Reset(localVars.Size()); + mExitRequiredVars.Reset(localVars.Size()); + mExitProvidedVars.Reset(localVars.Size()); - mLocalRequiredParams = NumberSet(params.Size()); - mLocalProvidedParams = NumberSet(params.Size()); + mLocalRequiredParams.Reset(params.Size()); + mLocalProvidedParams.Reset(params.Size()); - mEntryRequiredParams = NumberSet(params.Size()); - mEntryProvidedParams = NumberSet(params.Size()); - mExitRequiredParams = NumberSet(params.Size()); - mExitProvidedParams = NumberSet(params.Size()); + mEntryRequiredParams.Reset(params.Size()); + mEntryProvidedParams.Reset(params.Size()); + mExitRequiredParams.Reset(params.Size()); + mExitProvidedParams.Reset(params.Size()); for (i = 0; i < mInstructions.Size(); i++) { @@ -8162,6 +9002,72 @@ bool InterCodeBasicBlock::RemoveUnusedStoreInstructions(const GrowingVariableArr } +bool InterCodeBasicBlock::RemoveUnusedIndirectStoreInstructions(void) +{ + bool changed = false; + + if (!mVisited) + { + mVisited = true; + + ExpandingArray stores; + + for (int i = mInstructions.Size() - 1; i >= 0; i--) + { + InterInstruction* ins = mInstructions[i]; + + if (ins->mCode == IC_STORE) + { + int j = 0; + while (j < stores.Size() && !SameMemAndSize(ins->mSrc[1], stores[j]->mSrc[1])) + j++; + + if (j < stores.Size()) + { + if (ins->mVolatile) + stores[j] = ins; + else + { + ins->mCode = IC_NONE; + ins->mNumOperands = 0; + } + } + else + { + j = 0; + while (j < stores.Size()) + { + if (CollidingMem(ins, stores[j])) + stores.Remove(j); + else + j++; + } + stores.Push(ins); + } + } + else + { + int j = 0; + while (j < stores.Size()) + { + if (CollidingMem(ins, stores[j]) || ins->mDst.mTemp >= 0 && ins->mDst.mTemp == stores[j]->mSrc[1].mTemp) + stores.Remove(j); + else + j++; + } + } + } + + if (mTrueJump && mTrueJump->RemoveUnusedIndirectStoreInstructions()) + changed = true; + if (mFalseJump && mFalseJump->RemoveUnusedIndirectStoreInstructions()) + changed = true; + } + + return changed; +} + + bool InterCodeBasicBlock::EliminateAliasValues(const GrowingInstructionPtrArray& tvalue, const GrowingInstructionPtrArray& avalue) { bool changed = false; @@ -8502,7 +9408,7 @@ bool InterCodeBasicBlock::SimplifyIntegerNumeric(const GrowingInstructionPtrArra { InterInstruction* ains = ltvalue[pins->mSrc[0].mTemp]; - if (ains->mCode == IC_BINARY_OPERATOR && ains->mOperator == IA_ADD && ains->mSrc[0].mTemp < 0) + if (ains->mCode == IC_BINARY_OPERATOR && (ains->mOperator == IA_ADD || ains->mOperator == IA_SUB) && ains->mSrc[0].mTemp < 0) { if (spareTemps + 2 >= ltvalue.Size()) return true; @@ -8525,7 +9431,7 @@ bool InterCodeBasicBlock::SimplifyIntegerNumeric(const GrowingInstructionPtrArra nins->mDst.mRange = ins->mDst.mRange; mInstructions.Insert(i + 1, nins); - ins->mOperator = IA_ADD; + ins->mOperator = ains->mOperator; ins->mSrc[0] = ains->mSrc[0]; ins->mSrc[0].mIntConst <<= nins->mSrc[0].mIntConst; ins->mSrc[1] = nins->mDst; @@ -9470,7 +10376,7 @@ bool InterCodeBasicBlock::LoadStoreForwarding(const GrowingInstructionPtrArray& if (ins->mCode == IC_LOAD) { j = 0; - while (j < tvalue.Size() && !SameMem(ins->mSrc[0], tvalue[j])) + while (j < tvalue.Size() && !SameMemAndSize(ins->mSrc[0], tvalue[j])) j++; if (j < tvalue.Size()) { @@ -9483,7 +10389,7 @@ bool InterCodeBasicBlock::LoadStoreForwarding(const GrowingInstructionPtrArray& else if (ins->mCode == IC_STORE) { j = 0; - while (j < tvalue.Size() && !SameMem(ins->mSrc[1], tvalue[j])) + while (j < tvalue.Size() && !SameMemAndSize(ins->mSrc[1], tvalue[j])) j++; if (j < tvalue.Size()) { @@ -9548,7 +10454,7 @@ bool InterCodeBasicBlock::LoadStoreForwarding(const GrowingInstructionPtrArray& if (!ins->mVolatile) { int j = 0; - while (j < mLoadStoreInstructions.Size() && !SameMem(ins->mSrc[0], mLoadStoreInstructions[j])) + while (j < mLoadStoreInstructions.Size() && !SameMemAndSize(ins->mSrc[0], mLoadStoreInstructions[j])) j++; if (j < mLoadStoreInstructions.Size()) { @@ -9557,6 +10463,7 @@ bool InterCodeBasicBlock::LoadStoreForwarding(const GrowingInstructionPtrArray& { ins->mCode = IC_LOAD_TEMPORARY; ins->mSrc[0] = lins->mDst; + ins->mSrc[0].mRestricted = ins->mDst.mRestricted = lins->mDst.mRestricted; ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); changed = true; @@ -9574,6 +10481,8 @@ bool InterCodeBasicBlock::LoadStoreForwarding(const GrowingInstructionPtrArray& { ins->mCode = IC_LOAD_TEMPORARY; ins->mSrc[0] = lins->mSrc[0]; + ins->mSrc[0].mRestricted = ins->mDst.mRestricted = lins->mSrc[0].mRestricted; + ins->mDst.mRange.Limit(ins->mSrc[0].mRange); ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); changed = true; @@ -9588,7 +10497,7 @@ bool InterCodeBasicBlock::LoadStoreForwarding(const GrowingInstructionPtrArray& { int j = 0, k = 0; - while (j < mLoadStoreInstructions.Size() && !SameMem(ins->mSrc[1], mLoadStoreInstructions[j])) + while (j < mLoadStoreInstructions.Size() && !SameMemAndSize(ins->mSrc[1], mLoadStoreInstructions[j])) j++; if (!ins->mVolatile && j < mLoadStoreInstructions.Size() && mLoadStoreInstructions[j]->mCode == IC_LOAD && ins->mSrc[0].mTemp == mLoadStoreInstructions[j]->mDst.mTemp) @@ -9636,6 +10545,8 @@ bool InterCodeBasicBlock::LoadStoreForwarding(const GrowingInstructionPtrArray& assert(lins->mDst.mTemp >= 0); ins->mCode = IC_LOAD_TEMPORARY; ins->mSrc[0] = lins->mDst; + ins->mSrc[0].mRestricted = ins->mDst.mRestricted = lins->mDst.mRestricted; + ins->mDst.mRange.Limit(ins->mSrc[0].mRange); ins->mNumOperands = 1; changed = true; } @@ -9665,6 +10576,39 @@ bool InterCodeBasicBlock::LoadStoreForwarding(const GrowingInstructionPtrArray& else nins = ins; } + else if (ins->mCode == IC_CALL_NATIVE && ins->mSrc[0].mTemp < 0 && ins->mSrc[0].mLinkerObject && ins->mSrc[0].mLinkerObject->mProc && ins->mSrc[0].mLinkerObject->mProc->mGlobalsChecked) + { + InterCodeProcedure* proc = ins->mSrc[0].mLinkerObject->mProc; + + int j = 0, k = 0; + while (j < mLoadStoreInstructions.Size()) + { + InterOperand* op = nullptr; + + if (mLoadStoreInstructions[j]->mCode == IC_LOAD) + op = mLoadStoreInstructions[j]->mSrc + 0; + else if (mLoadStoreInstructions[j]->mCode == IC_STORE) + op = mLoadStoreInstructions[j]->mSrc + 1; + + bool flush = false; + if (op) + { + if (op->mTemp >= 0) + flush = proc->mStoresIndirect; + else if (op->mMemory == IM_FFRAME || op->mMemory == IM_FRAME) + flush = true; + else if (op->mMemory == IM_GLOBAL) + flush = proc->ModifiesGlobal(op->mVarIndex); + else + flush = true; + } + + if (!flush) + mLoadStoreInstructions[k++] = mLoadStoreInstructions[j]; + j++; + } + mLoadStoreInstructions.SetSize(k); + } else if (HasSideEffect(ins->mCode)) flushMem = true; @@ -9746,6 +10690,8 @@ void InterCodeBasicBlock::LocalRenameRegister(const GrowingIntArray& renameTable } } + RenameValueRanges(mEntryRenameTable, num); + for (i = 0; i < mInstructions.Size(); i++) { mInstructions[i]->LocalRenameRegister(mExitRenameTable, num); @@ -9790,11 +10736,32 @@ void InterCodeBasicBlock::GlobalRenameRegister(const GrowingIntArray& renameTabl mInstructions[i]->GlobalRenameRegister(renameTable, temporaries); } + RenameValueRanges(renameTable, temporaries.Size()); + if (mTrueJump) mTrueJump->GlobalRenameRegister(renameTable, temporaries); if (mFalseJump) mFalseJump->GlobalRenameRegister(renameTable, temporaries); } } +void InterCodeBasicBlock::RenameValueRanges(const GrowingIntArray& renameTable, int numTemps) +{ + if (mEntryValueRange.Size() > 0) + { + mLocalValueRange = mEntryValueRange; + mEntryValueRange.SetSize(numTemps, true); + for (int i = 0; i < mLocalValueRange.Size(); i++) + { + if (renameTable[i] >= 0) + { + assert(mLocalValueRange[i].mMinState == IntegerValueRange::S_UNKNOWN || mEntryValueRange[renameTable[i]].mMinState == IntegerValueRange::S_UNKNOWN); + assert(mLocalValueRange[i].mMaxState == IntegerValueRange::S_UNKNOWN || mEntryValueRange[renameTable[i]].mMaxState == IntegerValueRange::S_UNKNOWN); + + mEntryValueRange[renameTable[i]].Limit(mLocalValueRange[i]); + } + } + } +} + void InterCodeBasicBlock::BuildCollisionTable(NumberSet* collisionSets) { if (!mVisited) @@ -10025,7 +10992,7 @@ bool InterCodeBasicBlock::CanMoveInstructionDown(int si, int ti) const #if 1 if (ins->mCode == IC_COPY || ins->mCode == IC_PUSH_FRAME || ins->mCode == IC_POP_FRAME || - ins->mCode == IC_RETURN || ins->mCode == IC_RETURN_STRUCT || ins->mCode == IC_RETURN_VALUE) + ins->mCode == IC_RETURN || ins->mCode == IC_RETURN_STRUCT || ins->mCode == IC_RETURN_VALUE || ins->mCode == IC_DISPATCH) return false; for (int i = si + 1; i < ti; i++) @@ -10087,7 +11054,7 @@ bool InterCodeBasicBlock::CanMoveInstructionBeforeBlock(int ii, const InterInstr #if 1 if (ins->mCode == IC_CALL || ins->mCode == IC_CALL_NATIVE || ins->mCode == IC_COPY || ins->mCode == IC_PUSH_FRAME || ins->mCode == IC_POP_FRAME || - ins->mCode == IC_RETURN || ins->mCode == IC_RETURN_STRUCT || ins->mCode == IC_RETURN_VALUE) + ins->mCode == IC_RETURN || ins->mCode == IC_RETURN_STRUCT || ins->mCode == IC_RETURN_VALUE || ins->mCode == IC_DISPATCH) return false; for (int i = 0; i < ii; i++) @@ -10252,6 +11219,91 @@ static bool CanMoveInstructionBeforePath(const GrowingInterCodeBasicBlockPtrArra return true; } +bool InterCodeBasicBlock::IsDirectDominatorBlock(InterCodeBasicBlock* block) +{ + if (this == block) + return true; + + if (block->mLoopHead) + return false; + + if (block->mEntryBlocks.Size() == 0) + return false; + + for (int i = 0; i < block->mEntryBlocks.Size(); i++) + if (!IsDirectDominatorBlock(block->mEntryBlocks[i])) + return false; + + return true; +} + +bool InterCodeBasicBlock::HoistCommonConditionalPath(void) +{ + bool changed = false; + + if (!mVisited) + { + mVisited = true; + + if (mFalseJump) + { + InterCodeBasicBlock* cblock = nullptr, * eblock = nullptr; + + if (!mTrueJump->mFalseJump && mTrueJump->mTrueJump && IsDirectDominatorBlock(mTrueJump->mTrueJump)) + { + cblock = mTrueJump; + eblock = mTrueJump->mTrueJump; + } + else if (!mFalseJump->mFalseJump && mFalseJump->mTrueJump && IsDirectDominatorBlock(mFalseJump->mTrueJump)) + { + cblock = mFalseJump; + eblock = mFalseJump->mTrueJump; + } + + if (cblock && cblock->mNumEntries == 1) + { + for (int i = 0; i < cblock->mInstructions.Size(); i++) + { + InterInstruction* ins = cblock->mInstructions[i]; + + if (cblock->CanMoveInstructionBeforeBlock(i) && !HasSideEffect(ins->mCode) && ins->mDst.mTemp >= 0 && !cblock->IsTempModifiedInRange(i + 1, cblock->mInstructions.Size(), ins->mDst.mTemp)) + { + int j = 0; + while (j < eblock->mInstructions.Size() && !eblock->mInstructions[j]->IsEqualSource(ins)) + j++; + + if (j < eblock->mInstructions.Size() && !eblock->IsTempModifiedInRange(0, j, ins->mDst.mTemp) && eblock->CanMoveInstructionBeforeBlock(j) && cblock->CanMoveInstructionBeforeBlock(cblock->mInstructions.Size(), eblock->mInstructions[j])) + { + eblock->mInstructions[j]->mCode = IC_LOAD_TEMPORARY; + eblock->mInstructions[j]->mSrc[0] = ins->mDst; + eblock->mInstructions[j]->mNumOperands = 1; + + mInstructions.Insert(mInstructions.Size() - 1, ins); + cblock->mInstructions.Remove(i); + + mExitRequiredTemps += ins->mDst.mTemp; + cblock->mEntryRequiredTemps += ins->mDst.mTemp; + cblock->mExitRequiredTemps += ins->mDst.mTemp; + eblock->mEntryRequiredTemps += ins->mDst.mTemp; + i--; + changed = true; + } + } + } + } + } + + if (mTrueJump && mTrueJump->HoistCommonConditionalPath()) + changed = true; + if (mFalseJump && mFalseJump->HoistCommonConditionalPath()) + changed = true; + } + + return changed; +} + + + bool InterCodeBasicBlock::MoveTrainCrossBlock(void) { bool changed = false; @@ -10352,7 +11404,7 @@ bool InterCodeBasicBlock::ForwardLoopMovedTemp(void) else if (mTrueJump->mFalseJump == mTrueJump) eblock = mTrueJump->mTrueJump; - if (eblock) + if (eblock && eblock->mNumEntries == 1) { int i = mInstructions.Size() - 1; while (i >= 0) @@ -10416,7 +11468,7 @@ bool InterCodeBasicBlock::ForwardDiamondMovedTemp(void) if (fblock && tblock) { - if (tblock->mInstructions[0]->IsEqual(fblock->mInstructions.Last()) && !fblock->mLocalModifiedTemps[tblock->mInstructions[0]->mSrc[0].mTemp]) + if (tblock->mInstructions[0]->IsEqual(fblock->mInstructions.Last()) && (tblock->mInstructions[0]->mSrc[0].mTemp < 0 || !fblock->mLocalModifiedTemps[tblock->mInstructions[0]->mSrc[0].mTemp])) { fblock->mTrueJump = tblock; fblock->mFalseJump = nullptr; @@ -10803,6 +11855,43 @@ void InterCodeBasicBlock::RemoveNonRelevantStatics(void) } } +bool InterCodeBasicBlock::RecheckOuterFrame(void) +{ + if (!mVisited) + { + mVisited = true; + + for (int i = 0; i < mInstructions.Size(); i++) + { + InterInstruction* ins(mInstructions[i]); + if (ins->mCode == IC_LOAD) + { + if (ins->mSrc[0].mMemory == IM_FRAME) + return true; + } + else if (ins->mCode == IC_STORE || ins->mCode == IC_LEA) + { + if (ins->mSrc[1].mMemory == IM_FRAME) + return true; + } + else if (ins->mCode == IC_CONSTANT) + { + if (ins->mConst.mType == IT_POINTER && ins->mConst.mMemory == IM_FRAME) + return true; + } + else if (ins->mCode == IC_PUSH_FRAME) + return true; + } + + if (mTrueJump && mTrueJump->RecheckOuterFrame()) + return true; + if (mFalseJump && mFalseJump->RecheckOuterFrame()) + return true; + } + + return false; +} + void InterCodeBasicBlock::CollectOuterFrame(int level, int& size, bool &inner, bool &inlineAssembler, bool &byteCodeCall) { int i; @@ -10853,7 +11942,7 @@ bool InterCodeBasicBlock::IsLeafProcedure(void) mVisited = true; for (i = 0; i < mInstructions.Size(); i++) - if (mInstructions[i]->mCode == IC_CALL || mInstructions[i]->mCode == IC_CALL_NATIVE) + if (mInstructions[i]->mCode == IC_CALL || mInstructions[i]->mCode == IC_CALL_NATIVE || mInstructions[i]->mCode == IC_DISPATCH) return false; if (mTrueJump && !mTrueJump->IsLeafProcedure()) @@ -10999,6 +12088,44 @@ bool InterCodeBasicBlock::IsEqual(const InterCodeBasicBlock* block) const return false; } +bool InterCodeBasicBlock::PreventsCallerStaticStack(void) +{ + if (!mVisited) + { + mVisited = true; + + for (int i = 0; i < mInstructions.Size(); i++) + { + InterInstruction* ins(mInstructions[i]); + if (ins->mCode == IC_CALL || ins->mCode == IC_CALL_NATIVE) + { + if (ins->mSrc[0].mTemp >= 0 || !ins->mSrc[0].mLinkerObject) + return false; + else if (ins->mSrc[0].mLinkerObject == mProc->mLinkerObject) + ; // Simple recursion + else if (!(ins->mSrc[0].mLinkerObject->mFlags & LOBJF_STATIC_STACK)) + return false; + } + else if (ins->mCode == IC_DISPATCH) + { + for (int j = 0; j < mProc->mCalledFunctions.Size(); j++) + { + if (!(mProc->mCalledFunctions[j]->mLinkerObject && (mProc->mCalledFunctions[j]->mLinkerObject->mFlags & LOBJF_STATIC_STACK))) + return false; + } + } + } + + if (mTrueJump && mTrueJump->PreventsCallerStaticStack()) + return true; + if (mFalseJump && mFalseJump->PreventsCallerStaticStack()) + return true; + } + + return false; +} + + bool InterCodeBasicBlock::CheckStaticStack(void) { if (!mVisited) @@ -11014,6 +12141,14 @@ bool InterCodeBasicBlock::CheckStaticStack(void) else if (!(mInstructions[i]->mSrc[0].mLinkerObject->mFlags & LOBJF_STATIC_STACK)) return false; } + else if (mInstructions[i]->mCode == IC_DISPATCH) + { + for (int j = 0; j < mProc->mCalledFunctions.Size(); j++) + { + if (!(mProc->mCalledFunctions[j]->mLinkerObject && (mProc->mCalledFunctions[j]->mLinkerObject->mFlags & LOBJF_STATIC_STACK))) + return false; + } + } } if (mTrueJump && !mTrueJump->CheckStaticStack()) @@ -11025,10 +12160,12 @@ bool InterCodeBasicBlock::CheckStaticStack(void) return true; } -void ApplyStaticStack(InterOperand & iop, const GrowingVariableArray& localVars) +void InterCodeBasicBlock::ApplyStaticStack(InterOperand & iop, const GrowingVariableArray& localVars) { if (iop.mMemory == IM_LOCAL) { + assert(localVars[iop.mVarIndex]->mIndex < mProc->mModule->mGlobalVars.Size()); + iop.mMemory = IM_GLOBAL; iop.mLinkerObject = localVars[iop.mVarIndex]->mLinkerObject; iop.mVarIndex = localVars[iop.mVarIndex]->mIndex; @@ -11043,7 +12180,7 @@ void InterCodeBasicBlock::CollectStaticStack(LinkerObject* lobj, const GrowingVa for (int i = 0; i < mInstructions.Size(); i++) { - if (mInstructions[i]->mCode == IC_CALL || mInstructions[i]->mCode == IC_CALL_NATIVE) + if ((mInstructions[i]->mCode == IC_CALL || mInstructions[i]->mCode == IC_CALL_NATIVE) && mInstructions[i]->mSrc[0].mLinkerObject->mStackSection) lobj->mStackSection->mSections.Push(mInstructions[i]->mSrc[0].mLinkerObject->mStackSection); if (mInstructions[i]->mCode == IC_LOAD) @@ -11074,6 +12211,7 @@ void PromoteStaticStackParam(InterOperand& iop, LinkerObject* paramlobj) iop.mMemory = IM_GLOBAL; iop.mIntConst += offset; iop.mLinkerObject = paramlobj; + iop.mVarIndex = -1; paramlobj->EnsureSpace(int(iop.mIntConst), iop.mOperandSize); } } @@ -11335,6 +12473,10 @@ void InterCodeBasicBlock::BuildLoopSuffix(void) if (mFalseJump->mNumEntries > 1) { InterCodeBasicBlock* suffix = new InterCodeBasicBlock(mProc); + suffix->mEntryRequiredTemps = mFalseJump->mEntryRequiredTemps; + suffix->mExitRequiredTemps = mFalseJump->mEntryRequiredTemps; + suffix->mLocalModifiedTemps.Reset(mExitRequiredTemps.Size()); + InterInstruction* jins = new InterInstruction(mInstructions[0]->mLocation, IC_JUMP); suffix->Append(jins); suffix->Close(mFalseJump, nullptr); @@ -11347,6 +12489,10 @@ void InterCodeBasicBlock::BuildLoopSuffix(void) if (mTrueJump->mNumEntries > 1) { InterCodeBasicBlock* suffix = new InterCodeBasicBlock(mProc); + suffix->mEntryRequiredTemps = mTrueJump->mEntryRequiredTemps; + suffix->mExitRequiredTemps = mTrueJump->mEntryRequiredTemps; + suffix->mLocalModifiedTemps.Reset(mExitRequiredTemps.Size()); + InterInstruction* jins = new InterInstruction(mInstructions[0]->mLocation, IC_JUMP); suffix->Append(jins); suffix->Close(mTrueJump, nullptr); @@ -11377,6 +12523,10 @@ InterCodeBasicBlock* InterCodeBasicBlock::BuildLoopPrefix(void) if (mLoopHead) { mLoopPrefix = new InterCodeBasicBlock(mProc); + mLoopPrefix->mEntryRequiredTemps = mEntryRequiredTemps; + mLoopPrefix->mExitRequiredTemps = mEntryRequiredTemps; + mLoopPrefix->mLocalModifiedTemps.Reset(mEntryRequiredTemps.Size()); + InterInstruction* jins = new InterInstruction(mInstructions[0]->mLocation, IC_JUMP); mLoopPrefix->Append(jins); mLoopPrefix->Close(this, nullptr); @@ -11386,7 +12536,7 @@ InterCodeBasicBlock* InterCodeBasicBlock::BuildLoopPrefix(void) return mLoopPrefix ? mLoopPrefix : this; } -bool InterCodeBasicBlock::CollectLoopBody(InterCodeBasicBlock* head, GrowingArray & body) +bool InterCodeBasicBlock::CollectLoopBody(InterCodeBasicBlock* head, ExpandingArray & body) { if (mLoopHead) return this == head; @@ -11402,7 +12552,23 @@ bool InterCodeBasicBlock::CollectLoopBody(InterCodeBasicBlock* head, GrowingArra return true; } -void InterCodeBasicBlock::CollectLoopPath(const GrowingArray& body, GrowingArray& path) +bool InterCodeBasicBlock::CollectLoopBodyRecursive(InterCodeBasicBlock* head, ExpandingArray& body) +{ + if (this == head) + return true; + + if (body.IndexOf(this) != -1) + return true; + body.Push(this); + + for (int i = 0; i < mEntryBlocks.Size(); i++) + if (!mEntryBlocks[i]->CollectLoopBodyRecursive(head, body)) + return false; + + return true; +} + +void InterCodeBasicBlock::CollectLoopPath(const ExpandingArray& body, ExpandingArray& path) { if (body.IndexOf(this) >= 0) { @@ -11413,7 +12579,7 @@ void InterCodeBasicBlock::CollectLoopPath(const GrowingArrayCollectLoopPath(body, mLoopPathBlocks); if (mFalseJump) { - GrowingArray fpath(nullptr); + ExpandingArray fpath; if (!mFalseJump->mLoopHead) mFalseJump->CollectLoopPath(body, fpath); @@ -11519,6 +12685,45 @@ static InterInstruction * FindSourceInstruction(InterCodeBasicBlock* block, int } } +bool InterCodeBasicBlock::MoveLoopHeadCheckToTail(void) +{ + bool modified = false; + if (!mVisited) + { + mVisited = true; + + if (mLoopHead && mEntryBlocks.Size() == 2 && mInstructions.Size() == 2) + { + if (mInstructions[0]->mCode == IC_RELATIONAL_OPERATOR && mInstructions[1]->mCode == IC_BRANCH && + mInstructions[1]->mSrc[0].mTemp == mInstructions[0]->mDst.mTemp) + { + if (mFalseJump != this && mTrueJump->mTrueJump == this && !mTrueJump->mFalseJump) + { + mTrueJump->mInstructions.SetSize(mTrueJump->mInstructions.Size() - 1); + mTrueJump->mInstructions.Push(mInstructions[0]->Clone()); + mTrueJump->mInstructions.Push(mInstructions[1]->Clone()); + mTrueJump->mTrueJump = mTrueJump; + mTrueJump->mFalseJump = mFalseJump; + mTrueJump->mEntryBlocks.Push(mTrueJump); + mTrueJump->mNumEntries++; + mFalseJump->mEntryBlocks.Push(mTrueJump); + mFalseJump->mNumEntries++; + mNumEntries--; + mEntryBlocks.Remove(mEntryBlocks.IndexOf(mTrueJump)); + modified = true; + } + } + } + + if (mTrueJump && mTrueJump->MoveLoopHeadCheckToTail()) + modified = true; + if (mFalseJump && mFalseJump->MoveLoopHeadCheckToTail()) + modified = true; + } + + return modified; +} + bool InterCodeBasicBlock::SingleTailLoopOptimization(const NumberSet& aliasedParams, const GrowingVariableArray& staticVars) { bool modified = false; @@ -11580,8 +12785,12 @@ bool InterCodeBasicBlock::SingleTailLoopOptimization(const NumberSet& aliasedPar mins->mConst.mType = ai->mDst.mType; mins->mConst.mIntConst = num; mins->mDst = ai->mDst; + mins->mDst.mRange.SetLimit(num, num); mLoopPrefix->mInstructions.Insert(mLoopPrefix->mInstructions.Size() - 1, mins); + if (mEntryValueRange.Size()) + mEntryValueRange[ai->mSrc[1].mTemp].SetLimit(1, num); + ai->mSrc[1].mRange.SetLimit(1, num); ai->mDst.mRange.SetLimit(0, num - 1); ci->mSrc[1].mRange.SetLimit(0, num - 1); @@ -11629,6 +12838,17 @@ bool InterCodeBasicBlock::SingleTailLoopOptimization(const NumberSet& aliasedPar } } #endif + bool hasStore = false; + for (int j = 0; j < body.Size(); j++) + { + int sz = body[j]->mInstructions.Size(); + for (int i = 0; i < sz; i++) + { + InterInstruction* ins = body[j]->mInstructions[i]; + if (IsObservable(ins->mCode)) + hasStore = true; + } + } int i = 0; while (i < mInstructions.Size()) @@ -11637,7 +12857,8 @@ bool InterCodeBasicBlock::SingleTailLoopOptimization(const NumberSet& aliasedPar if (lins->mCode == IC_BINARY_OPERATOR || lins->mCode == IC_CONSTANT || lins->mCode == IC_UNARY_OPERATOR || lins->mCode == IC_CONVERSION_OPERATOR || lins->mCode == IC_SELECT || - lins->mCode == IC_RELATIONAL_OPERATOR) + lins->mCode == IC_LEA || + lins->mCode == IC_RELATIONAL_OPERATOR || (lins->mCode == IC_LOAD && !hasStore && !lins->mVolatile)) { #if 1 if (CanMoveInstructionBeforeBlock(i) && !IsInsModifiedInRange(i + 1, mInstructions.Size(), lins) && !tail->IsInsModified(lins) && !lins->UsesTemp(lins->mDst.mTemp)) @@ -11658,7 +12879,7 @@ bool InterCodeBasicBlock::SingleTailLoopOptimization(const NumberSet& aliasedPar } #endif } - else if (lins->mCode == IC_LOAD && lins->mSrc[0].mTemp < 0 && !tail->mExitRequiredTemps[lins->mDst.mTemp]) + else if (lins->mCode == IC_LOAD && !lins->mVolatile && lins->mSrc[0].mTemp < 0 && !tail->mExitRequiredTemps[lins->mDst.mTemp]) { if (CanMoveInstructionBeforeBlock(i)) { @@ -11720,8 +12941,36 @@ bool InterCodeBasicBlock::SingleTailLoopOptimization(const NumberSet& aliasedPar } } } + else + { + int k = 0; + while (k < body.Size() && !DestroyingMem(body[k], lins, 0, body[k]->mInstructions.Size())) + k++; + if (k == body.Size()) + { +#if 1 + if (!IsInsModifiedInRange(i + 1, mInstructions.Size(), lins) && !tail->IsInsModified(lins)) + { + int j = 1; + while (j < body.Size() && !body[j]->IsInsModified(lins)) + j++; + if (j == body.Size()) + { + mLoopPrefix->mInstructions.Insert(mLoopPrefix->mInstructions.Size() - 1, lins); + mLoopPrefix->mExitRequiredTemps += lins->mDst.mTemp; + mEntryRequiredTemps += lins->mDst.mTemp; + mInstructions.Remove(i); + i--; + + modified = true; + } + } +#endif + } + } } } + i++; } } @@ -11745,7 +12994,7 @@ void InterCodeBasicBlock::InnerLoopOptimization(const NumberSet& aliasedParams) if (mLoopHead) { - GrowingArray body(nullptr), path(nullptr); + ExpandingArray body, path; body.Push(this); bool innerLoop = true; @@ -11775,7 +13024,7 @@ void InterCodeBasicBlock::InnerLoopOptimization(const NumberSet& aliasedParams) for (int i = 0; i < path.Size(); i++) printf("path %d\n", path[i]->mIndex); #endif - bool hasCall = false, hasFrame = false; + bool hasCall = false, hasFrame = false, hasStore = false; for (int bi = 0; bi < body.Size(); bi++) { InterCodeBasicBlock* block = body[bi]; @@ -11789,6 +13038,17 @@ void InterCodeBasicBlock::InnerLoopOptimization(const NumberSet& aliasedParams) hasCall = true; else if (ins->mCode == IC_PUSH_FRAME) hasFrame = true; + else if (ins->mCode == IC_STORE) + { + if (ins->mSrc[1].mTemp >= 0) + hasStore = true; + else if ((ins->mSrc[1].mMemory == IM_PARAM || ins->mSrc[1].mMemory == IM_FPARAM) && !aliasedParams[ins->mSrc[1].mVarIndex]) + ; + else + hasStore = true; + } + else if (ins->mCode == IC_COPY || ins->mCode == IC_STRCPY) + hasStore = true; } } @@ -11809,7 +13069,11 @@ void InterCodeBasicBlock::InnerLoopOptimization(const NumberSet& aliasedParams) ins->mInvariant = false; else if (ins->mCode == IC_LOAD) { - if (ins->mSrc[0].mTemp >= 0 || ins->mVolatile) + if (ins->mVolatile) + { + ins->mInvariant = false; + } + else if (ins->mSrc[0].mTemp >= 0 && (hasStore || hasCall)) { ins->mInvariant = false; } @@ -11821,6 +13085,10 @@ void InterCodeBasicBlock::InnerLoopOptimization(const NumberSet& aliasedParams) { ins->mInvariant = false; } + else if (ins->mSrc[0].mMemory == IM_PARAM && hasCall && aliasedParams[ins->mSrc[0].mVarIndex]) + { + ins->mInvariant = false; + } else { for (int bj = 0; bj < body.Size(); bj++) @@ -11890,6 +13158,10 @@ void InterCodeBasicBlock::InnerLoopOptimization(const NumberSet& aliasedParams) for (int i = 0; i < block->mInstructions.Size(); i++) { InterInstruction* ins = block->mInstructions[i]; + InterInstruction* nins = nullptr; + if (i + 1 < block->mInstructions.Size()) + nins = block->mInstructions[i + 1]; + int t = ins->mDst.mTemp; if (t >= 0) { @@ -11919,6 +13191,8 @@ void InterCodeBasicBlock::InnerLoopOptimization(const NumberSet& aliasedParams) ins->mExpensive = true; else if (ins->mSrc[0].mTemp >= 0 && ins->mSrc[0].mRange.mMaxState == IntegerValueRange::S_BOUND && ins->mSrc[0].mRange.mMaxValue >= 256) ins->mExpensive = true; + else if (nins && nins->mCode == IC_LEA && nins->mSrc[0].mTemp >= 0 && (nins->mSrc[0].mRange.mMaxState == IntegerValueRange::S_UNBOUND || nins->mSrc[0].mRange.mMaxValue >= 255)) + ins->mExpensive = true; break; case IC_LOAD: case IC_STORE: @@ -12026,10 +13300,7 @@ void InterCodeBasicBlock::InnerLoopOptimization(const NumberSet& aliasedParams) block->mInstructions[j++] = ins; } } -#ifdef _DEBUG - if (j != block->mInstructions.Size()) - printf("Moved %d %d\n", mIndex, block->mInstructions.Size() - j); -#endif + block->mInstructions.SetSize(j); } #endif @@ -12116,6 +13387,309 @@ void InterCodeBasicBlock::SingleBlockLoopUnrolling(void) } } +static int FindStore(InterCodeBasicBlock* block, int pos, const InterOperand& op) +{ + while (pos > 0) + { + pos--; + InterInstruction* ins(block->mInstructions[pos]); + if (ins->mCode == IC_STORE && ins->mSrc[1].mTemp < 0) + { + if ((op.mMemory == IM_PARAM && ins->mSrc[1].mMemory == IM_FRAME || + op.mMemory == IM_FPARAM && ins->mSrc[1].mMemory == IM_FFRAME) && + op.mVarIndex == ins->mSrc[1].mVarIndex) + return pos; + } + if (ins->mCode == IC_POP_FRAME && op.mMemory == IM_PARAM) + return -1; + } + + return -1; +} + +bool InterCodeBasicBlock::CheapInlining(int & numTemps) +{ + bool changed = false; + + if (!mVisited) + { + mVisited = true; + + for (int i = 0; i < mInstructions.Size(); i++) + { + InterInstruction* ins(mInstructions[i]); + + if (ins->mCode == IC_CALL_NATIVE && ins->mSrc[0].mTemp < 0 && ins->mSrc[0].mLinkerObject && ins->mSrc[0].mLinkerObject->mProc && ins->mSrc[0].mLinkerObject->mProc->mCheapInline) + { + InterCodeBasicBlock* block = ins->mSrc[0].mLinkerObject->mProc->mEntryBlock; + + int ntemps = numTemps; + GrowingArray tmap(-1); + + bool fail = false; + for (int j = 0; j < block->mInstructions.Size(); j++) + { + InterInstruction* nins(block->mInstructions[j]); + if (nins->mCode == IC_LOAD && FindStore(this, i, nins->mSrc[0]) < 0) + fail = true; + } + + if (!fail) + { + for (int j = 0; j < i; j++) + mInstructions[j]->mRemove = false; + + mInstructions.Remove(i); + changed = true; + + for (int j = 0; j < block->mInstructions.Size(); j++) + { + InterInstruction* nins(block->mInstructions[j]); + switch (nins->mCode) + { + case IC_LOAD: + { + int k = FindStore(this, i, nins->mSrc[0]); + InterInstruction* pins = mInstructions[k]->Clone(); + mInstructions[k]->mRemove = true; + + if (pins->mSrc[0].mTemp < 0) + { + pins->mCode = IC_CONSTANT; + pins->mConst = pins->mSrc[0]; + pins->mNumOperands = 0; + } + else + { + pins->mCode = IC_LOAD_TEMPORARY; + pins->mNumOperands = 1; + } + + pins->mDst = nins->mDst; + pins->mDst.mTemp = ntemps; + mInstructions.Insert(k + 1, pins); + i++; + } break; + case IC_STORE: + { + InterInstruction* pins = nins->Clone(); + if (pins->mSrc[0].mTemp >= 0) + pins->mSrc[0].mTemp = tmap[pins->mSrc[0].mTemp]; + if (pins->mSrc[1].mTemp >= 0) + pins->mSrc[1].mTemp = tmap[pins->mSrc[1].mTemp]; + mInstructions.Insert(i, pins); + i++; + } break; + case IC_CALL: + case IC_CALL_NATIVE: + { + InterInstruction* pins = nins->Clone(); + if (pins->mDst.mTemp >= 0) + pins->mDst.mTemp = ntemps; + mInstructions.Insert(i, pins); + i++; + } break; + case IC_RETURN: + break; + case IC_RETURN_VALUE: + { + if (ins->mDst.mTemp >= 0) + { + InterInstruction* pins = nins->Clone(); + if (pins->mSrc[0].mTemp < 0) + { + pins->mCode = IC_CONSTANT; + pins->mConst = pins->mSrc[0]; + pins->mNumOperands = 0; + } + else + { + pins->mCode = IC_LOAD_TEMPORARY; + pins->mNumOperands = 1; + } + + pins->mDst = ins->mDst; + if (pins->mSrc[0].mTemp >= 0) + pins->mSrc[0].mTemp = tmap[pins->mSrc[0].mTemp]; + mInstructions.Insert(i, pins); + i++; + } + } break; + default: + { + InterInstruction* pins = nins->Clone(); + for (int k = 0; k < pins->mNumOperands; k++) + if (pins->mSrc[k].mTemp >= 0) + pins->mSrc[k].mTemp = tmap[pins->mSrc[k].mTemp]; + if (pins->mDst.mTemp >= 0) + pins->mDst.mTemp = ntemps; + mInstructions.Insert(i, pins); + i++; + } break; + } + + if (nins->mDst.mTemp >= 0) + tmap[nins->mDst.mTemp] = ntemps++; + } + + numTemps = ntemps; + + for (int j = 0; j < i; j++) + { + if (mInstructions[j]->mRemove) + { + mInstructions[j]->mCode = IC_NONE; + mInstructions[j]->mDst.mTemp = -1; + mInstructions[j]->mNumOperands = 0; + } + } + } + } + } + + if (mTrueJump && mTrueJump->CheapInlining(numTemps)) + changed = true; + if (mFalseJump && mFalseJump->CheapInlining(numTemps)) + changed = true; + } + + return changed; +} + +void InterCodeBasicBlock::RemoveUnusedMallocs(void) +{ + if (!mVisited) + { + mVisited = true; + + for (int i = 0; i < mInstructions.Size(); i++) + { + InterInstruction* mins = mInstructions[i]; + if (mins->mCode == IC_MALLOC) + { + int mtemp = mins->mDst.mTemp; + bool used = false; + int j = i + 1; + while (j < mInstructions.Size() && !used) + { + InterInstruction* fins = mInstructions[j]; + if (fins->mCode == IC_FREE && fins->mSrc[0].mTemp == mtemp) + break; + if (fins->ReferencesTemp(mtemp)) + { + if (fins->mCode != IC_STORE || fins->mSrc[1].mTemp != mtemp) + used = true; + } + j++; + } + + if (j < mInstructions.Size() && !used) + { + mins->mCode = IC_NONE; mins->mNumOperands = 0; + for (int k = i + 1; k <= j; k++) + { + InterInstruction* lins = mInstructions[k]; + if (lins->UsesTemp(mtemp)) + { + lins->mCode = IC_NONE; + lins->mNumOperands = 0; + } + } + } + } + } + + if (mTrueJump) mTrueJump->RemoveUnusedMallocs(); + if (mFalseJump) mFalseJump->RemoveUnusedMallocs(); + } +} + +void InterCodeBasicBlock::PropagateMemoryAliasingInfo(const GrowingInstructionPtrArray& tvalue) +{ + if (!mVisited) + { + GrowingInstructionPtrArray ltvalue(tvalue); + + if (mLoopHead) + { + if (mNumEntries == 2 && (mTrueJump == this || mFalseJump == this)) + { + for (int i = 0; i < ltvalue.Size(); i++) + { + if (ltvalue[i]) + { + for (int j = 0; j < mInstructions.Size(); j++) + { + if (mInstructions[j]->mDst.mTemp == i) + { + if (mInstructions[j]->mCode == IC_LEA && mInstructions[j]->mSrc[1].mTemp == i) + ; + else + { + ltvalue[i] = nullptr; + break; + } + } + } + } + } + } + else + ltvalue.Clear(); + } + else if (mNumEntries > 0) + { + if (mNumEntered > 0) + { + for (int i = 0; i < ltvalue.Size(); i++) + { + if (mMergeTValues[i] != ltvalue[i]) + ltvalue[i] = nullptr; + } + } + + mNumEntered++; + + if (mNumEntered < mNumEntries) + { + mMergeTValues = ltvalue; + return; + } + } + + mVisited = true; + + for (int i = 0; i < mInstructions.Size(); i++) + { + InterInstruction* ins = mInstructions[i]; + + for (int j = 0; j < ins->mNumOperands; j++) + { + if (ins->mSrc[j].mTemp > 0 && ltvalue[ins->mSrc[j].mTemp] && ins->mSrc[j].mType == IT_POINTER) + ins->mSrc[j].mRestricted = ltvalue[ins->mSrc[j].mTemp]->mDst.mRestricted; + } + + if (ins->mDst.mTemp >= 0) + { + if (ins->mDst.mRestricted) + ltvalue[ins->mDst.mTemp] = ins; + else + ltvalue[ins->mDst.mTemp] = nullptr; + } + + if (ins->mCode == IC_LEA) + ins->mDst.mRestricted = ins->mSrc[1].mRestricted; + else if (ins->mCode == IC_LOAD_TEMPORARY) + ins->mDst.mRestricted = ins->mSrc[0].mRestricted; + } + + + if (mTrueJump) mTrueJump->PropagateMemoryAliasingInfo(ltvalue); + if (mFalseJump) mFalseJump->PropagateMemoryAliasingInfo(ltvalue); + } +} + + void InterCodeBasicBlock::PushMoveOutOfLoop(void) { if (!mVisited) @@ -12230,7 +13804,7 @@ void InterCodeBasicBlock::PushMoveOutOfLoop(void) bool InterCodeBasicBlock::CheckSingleBlockLimitedLoop(InterCodeBasicBlock*& pblock, int64& nloop) { - if (mLoopHead && mNumEntries == 2 && mFalseJump && (mTrueJump == this || mFalseJump == this) && mInstructions.Size() > 3) + if (mLoopHead && mEntryBlocks.Size() == 2 && mFalseJump && (mTrueJump == this || mFalseJump == this) && mInstructions.Size() > 3) { int nins = mInstructions.Size(); @@ -12761,6 +14335,31 @@ void InterCodeBasicBlock::SingleBlockLoopOptimisation(const NumberSet& aliasedPa InterCodeBasicBlock* tailBlock = this == mTrueJump ? mFalseJump : mTrueJump; assert(tailBlock->mNumEntries == 1); + // remove counting loop without body + if (mInstructions.Size() == 3) + { + InterInstruction* ains = mInstructions[0]; + InterInstruction* cins = mInstructions[1]; + InterInstruction* bins = mInstructions[2]; + + if (ains->mCode == IC_BINARY_OPERATOR && cins->mCode == IC_RELATIONAL_OPERATOR && bins->mCode == IC_BRANCH) + { + if (ains->mSrc[1].mTemp == ains->mDst.mTemp && ains->mSrc[0].mTemp < 0 && + cins->mSrc[1].mTemp == ains->mDst.mTemp && ains->mSrc[0].mTemp < 0 && + bins->mSrc[0].mTemp == cins->mDst.mTemp && bins->mSrc[0].mFinal) + { + if (ains->mOperator == IA_ADD && ains->mSrc[0].mIntConst == 1 && + cins->mOperator == IA_CMPLU && mTrueJump == this && !tailBlock->mEntryRequiredTemps[ains->mDst.mTemp]) + { + cins->mCode = IC_CONSTANT; + cins->mConst.mType = IT_BOOL; + cins->mConst.mIntConst = 0; + cins->mNumOperands = 0; + } + } + } + } + if (!hasCall) { // Check forwarding globals @@ -12811,6 +14410,18 @@ void InterCodeBasicBlock::SingleBlockLoopOptimisation(const NumberSet& aliasedPa sins->mSrc[0].mFinal = false; assert(nins->mSrc[0].mTemp >= 0); + // Propagate all loads to move temps + + for (int t = j + 1; t < mInstructions.Size(); t++) + { + InterInstruction* ti = mInstructions[t]; + if (ti->mCode == IC_LOAD && SameMem(ti->mSrc[0], ins->mSrc[0])) + { + ti->mCode = IC_LOAD_TEMPORARY; + ti->mSrc[0].mTemp = ins->mDst.mTemp; + } + } + // Move store behind loop tailBlock->mInstructions.Insert(0, sins); mInstructions.Remove(j); @@ -13509,7 +15120,10 @@ void InterCodeBasicBlock::CheckBlocks(void) for (int i = 0; i < mInstructions.Size(); i++) assert(mInstructions[i] != nullptr); - + + assert(!mTrueJump || mTrueJump->mIndex > 0); + assert(!mFalseJump || mFalseJump->mIndex > 0); + if (mTrueJump) mTrueJump->CheckBlocks(); if (mFalseJump) mFalseJump->CheckBlocks(); } @@ -13757,7 +15371,6 @@ bool InterCodeBasicBlock::PeepholeReplaceOptimization(const GrowingVariableArray int64 mshift = mInstructions[i + 1]->mSrc[0].mIntConst; mInstructions[i + 0]->mOperator = IA_AND; - mInstructions[i + 0]->mSrc[0].mType = IT_INT16; mInstructions[i + 0]->mSrc[0].mType = mInstructions[i + 1]->mSrc[0].mType; switch (mInstructions[i + 0]->mSrc[1].mType) @@ -13800,6 +15413,61 @@ bool InterCodeBasicBlock::PeepholeReplaceOptimization(const GrowingVariableArray } } #endif +#if 1 + else if ( + mInstructions[i + 0]->mCode == IC_BINARY_OPERATOR && mInstructions[i + 0]->mOperator == IA_SHL && mInstructions[i + 0]->mSrc[0].mTemp < 0 && + mInstructions[i + 1]->mCode == IC_BINARY_OPERATOR && mInstructions[i + 1]->mOperator == IA_SHR && mInstructions[i + 1]->mSrc[0].mTemp < 0 && + mInstructions[i + 1]->mSrc[1].mTemp == mInstructions[i + 0]->mDst.mTemp && mInstructions[i + 1]->mSrc[1].mFinal) + { + + int64 shift = mInstructions[i + 0]->mSrc[0].mIntConst; + if (shift & 7) + { + int64 mshift = mInstructions[i + 1]->mSrc[0].mIntConst; + + mInstructions[i + 0]->mOperator = IA_AND; + mInstructions[i + 0]->mSrc[0].mType = mInstructions[i + 1]->mSrc[0].mType; + + switch (mInstructions[i + 0]->mSrc[1].mType) + { + case IT_INT8: + mInstructions[i + 0]->mSrc[0].mIntConst = 0xffu >> shift; + break; + case IT_INT16: + mInstructions[i + 0]->mSrc[0].mIntConst = 0xffffu >> shift; + break; + case IT_INT32: + mInstructions[i + 0]->mSrc[0].mIntConst = 0xffffffffu >> shift; + break; + } + + if (shift > mshift && mInstructions[i + 0]->mDst.mType > mInstructions[i + 1]->mSrc[1].mType) + { + mInstructions[i + 1]->mSrc[1].mType = mInstructions[i + 0]->mDst.mType; + mInstructions[i + 1]->mDst.mType = mInstructions[i + 0]->mDst.mType; + } + + if (shift > mshift) + { + mInstructions[i + 1]->mOperator = IA_SHL; + mInstructions[i + 1]->mSrc[0].mIntConst = shift - mshift; + } + else if (shift < mshift) + { + mInstructions[i + 1]->mOperator = IA_SHR; + mInstructions[i + 1]->mSrc[0].mIntConst = mshift - shift; + } + else + { + mInstructions[i + 0]->mDst = mInstructions[i + 1]->mDst; + mInstructions[i + 1]->mCode = IC_NONE; + mInstructions[i + 1]->mNumOperands = 0; + } + + changed = true; + } + } +#endif #if 1 else if ( mInstructions[i + 0]->mCode == IC_LOAD_TEMPORARY && @@ -13995,6 +15663,27 @@ bool InterCodeBasicBlock::PeepholeReplaceOptimization(const GrowingVariableArray mInstructions[i + 1]->mCode = IC_NONE; mInstructions[i + 1]->mNumOperands = 0; changed = true; } +#endif +#if 1 + else if ( + mInstructions[i + 0]->mCode == IC_LEA && mInstructions[i + 0]->mSrc[0].mTemp >= 0 && + mInstructions[i + 1]->mCode == IC_LEA && mInstructions[i + 1]->mSrc[0].mTemp >= 0 && + mInstructions[i + 1]->mSrc[1].mTemp == mInstructions[i + 0]->mDst.mTemp && + mInstructions[i + 1]->mSrc[1].mFinal && + mInstructions[i + 0]->mSrc[0].IsUByte() && mInstructions[i + 1]->mSrc[0].IsUByte() && mInstructions[i + 0]->mSrc[0].mRange.mMaxValue + mInstructions[i + 1]->mSrc[0].mRange.mMaxValue < 256) + { + mInstructions[i + 1]->mSrc[1] = mInstructions[i + 0]->mSrc[1]; + + mInstructions[i + 0]->mCode = IC_BINARY_OPERATOR; + mInstructions[i + 0]->mOperator = IA_ADD; + mInstructions[i + 0]->mDst.mType = IT_INT16; + mInstructions[i + 0]->mSrc[1] = mInstructions[i + 1]->mSrc[0]; + mInstructions[i + 0]->mDst.mRange = mInstructions[i + 0]->mSrc[0].mRange; + mInstructions[i + 0]->mDst.mRange.mMaxValue += mInstructions[i + 0]->mSrc[1].mRange.mMaxValue; + + mInstructions[i + 1]->mSrc[0] = mInstructions[i + 0]->mDst; + changed = true; + } #endif else if ( mInstructions[i + 0]->mCode == IC_BINARY_OPERATOR && mInstructions[i + 0]->mOperator == IA_ADD && mInstructions[i + 0]->mSrc[1].mTemp < 0 && mInstructions[i + 0]->mSrc[0].mType == IT_INT16 && @@ -14112,6 +15801,7 @@ bool InterCodeBasicBlock::PeepholeReplaceOptimization(const GrowingVariableArray { mInstructions[i + 1]->mSrc[0].mTemp = mInstructions[i + 0]->mSrc[1].mTemp; mInstructions[i + 1]->mSrc[0].mIntConst += mInstructions[i + 0]->mSrc[0].mIntConst; + mInstructions[i + 1]->mSrc[0].mFinal = mInstructions[i + 0]->mSrc[1].mFinal; mInstructions[i + 0]->mCode = IC_NONE; mInstructions[i + 0]->mNumOperands = 0; changed = true; @@ -14168,7 +15858,7 @@ bool InterCodeBasicBlock::PeepholeReplaceOptimization(const GrowingVariableArray mInstructions[i + 1]->mCode == IC_RELATIONAL_OPERATOR && mInstructions[i + 1]->mSrc[1].mTemp == mInstructions[i + 0]->mDst.mTemp && mInstructions[i + 1]->mSrc[1].mFinal && mInstructions[i + 1]->mSrc[0].mTemp < 0 && mInstructions[i + 0]->mDst.mIntConst >= 0 && mInstructions[i + 0]->mSrc[1].mRange.mMaxState == IntegerValueRange::S_BOUND && mInstructions[i + 0]->mSrc[1].mRange.mMaxValue + mInstructions[i + 0]->mSrc[0].mIntConst < 32767 && - (IsSignedRelational(mInstructions[i + 1]->mOperator) || mInstructions[i + 0]->mSrc[1].mRange.mMinState == IntegerValueRange::S_BOUND && mInstructions[i + 0]->mSrc[1].mRange.mMinValue >= 0) && + (IsSignedRelational(mInstructions[i + 1]->mOperator) || mInstructions[i + 0]->mSrc[1].mRange.mMinState == IntegerValueRange::S_BOUND && mInstructions[i + 0]->mSrc[1].mRange.mMinValue >= 0) && mInstructions[i + 1]->mSrc[0].mIntConst - mInstructions[i + 0]->mSrc[0].mIntConst >= (IsSignedRelational(mInstructions[i + 1]->mOperator) ? 0 : -32768) && mInstructions[i + 1]->mSrc[0].mIntConst - mInstructions[i + 0]->mSrc[0].mIntConst <= 32767) { @@ -14190,6 +15880,18 @@ bool InterCodeBasicBlock::PeepholeReplaceOptimization(const GrowingVariableArray mInstructions[i + 0]->mSrc[1].mFinal = false; changed = true; } + else if ( + mInstructions[i + 0]->mCode == IC_LEA && + mInstructions[i + 1]->mCode == IC_BINARY_OPERATOR && + mInstructions[i + 2]->mCode == IC_LOAD && + mInstructions[i + 2]->mSrc[0].mTemp == mInstructions[i + 0]->mDst.mTemp && mInstructions[i + 2]->mSrc[0].mFinal && + CanSwapInstructions(mInstructions[i + 1], mInstructions[i + 2])) + { + InterInstruction* ins = mInstructions[i + 2]; + mInstructions[i + 2] = mInstructions[i + 1]; + mInstructions[i + 1] = ins; + changed = true; + } else if ( mInstructions[i + 0]->mCode == IC_STORE && mInstructions[i + 1]->mCode == IC_STORE && SameMemSegment(mInstructions[i + 1]->mSrc[1], mInstructions[i + 0]->mSrc[1]) && @@ -14199,7 +15901,115 @@ bool InterCodeBasicBlock::PeepholeReplaceOptimization(const GrowingVariableArray mInstructions[i + 0]->mNumOperands = 0; changed = true; } + else if ( + mInstructions[i + 0]->mCode == IC_LEA && + mInstructions[i + 0]->mSrc[0].mTemp >= 0 && mInstructions[i + 0]->mSrc[1].mTemp >= 0 && + mInstructions[i + 1]->mCode == IC_LOAD && + mInstructions[i + 1]->mSrc[0].mTemp == mInstructions[i + 0]->mDst.mTemp && mInstructions[i + 1]->mSrc[0].mFinal && + + mInstructions[i + 2]->mCode == IC_BINARY_OPERATOR && mInstructions[i + 2]->mOperator == IA_ADD && + mInstructions[i + 2]->mSrc[1].mTemp == mInstructions[i + 2]->mDst.mTemp && + mInstructions[i + 2]->mSrc[1].mTemp == mInstructions[i + 0]->mSrc[0].mTemp && + mInstructions[i + 2]->mSrc[0].mTemp < 0 && + mInstructions[i + 2]->mSrc[0].mIntConst == mInstructions[i + 1]->mSrc[0].mIntConst && + mInstructions[i + 2]->mSrc[1].mTemp != mInstructions[i + 1]->mDst.mTemp) + { + InterInstruction* iadd = mInstructions[i + 2]; + mInstructions[i + 2] = mInstructions[i + 1]; + mInstructions[i + 1] = mInstructions[i + 0]; + mInstructions[i + 0] = iadd; + mInstructions[i + 2]->mSrc[0].mIntConst = 0; + changed = true; + } +#if 1 + if (i + 2 < mInstructions.Size() && + mInstructions[i + 0]->mCode == IC_BINARY_OPERATOR && mInstructions[i + 0]->mOperator == IA_AND && + mInstructions[i + 0]->mSrc[0].mTemp < 0 && + mInstructions[i + 1]->mCode == IC_BINARY_OPERATOR && mInstructions[i + 1]->mOperator == IA_SHR && + mInstructions[i + 1]->mSrc[0].mTemp < 0 && + mInstructions[i + 1]->mSrc[1].mTemp == mInstructions[i + 0]->mDst.mTemp && mInstructions[i + 1]->mSrc[1].mFinal && + mInstructions[i + 2]->mCode == IC_RELATIONAL_OPERATOR && + mInstructions[i + 2]->mSrc[1].mTemp == mInstructions[i + 1]->mDst.mTemp && mInstructions[i + 2]->mSrc[0].mFinal && + mInstructions[i + 2]->mSrc[0].mTemp < 0) + { + mInstructions[i + 0]->mSrc[0].mIntConst &= ~((1 << mInstructions[i + 1]->mSrc[0].mIntConst) - 1); + mInstructions[i + 2]->mSrc[0].mIntConst <<= mInstructions[i + 1]->mSrc[0].mIntConst; + mInstructions[i + 2]->mSrc[1] = mInstructions[i + 0]->mDst; + mInstructions[i + 1]->mCode = IC_NONE; + mInstructions[i + 1]->mNumOperands = 0; + changed = true; + } + + if (i + 2 < mInstructions.Size() && + mInstructions[i + 0]->mCode == IC_BINARY_OPERATOR && mInstructions[i + 0]->mOperator == IA_SHR && + mInstructions[i + 0]->mSrc[0].mTemp < 0 && + mInstructions[i + 1]->mCode == IC_RELATIONAL_OPERATOR && + mInstructions[i + 1]->mSrc[1].mTemp == mInstructions[i + 0]->mDst.mTemp && mInstructions[i + 1]->mSrc[0].mFinal && + mInstructions[i + 1]->mSrc[0].mTemp < 0) + { + mInstructions[i + 1]->mSrc[0].mIntConst <<= mInstructions[i + 0]->mSrc[0].mIntConst; + + mInstructions[i + 0]->mOperator = IA_AND; + mInstructions[i + 0]->mSrc[0].mIntConst = ~((1 << mInstructions[i + 0]->mSrc[0].mIntConst) - 1); + mInstructions[i + 0]->mDst.mRange.Reset(); + mInstructions[i + 1]->mSrc[1].mRange.Reset(); + changed = true; + } + + if (i + 3 < mInstructions.Size() && + mInstructions[i + 0]->mCode == IC_BINARY_OPERATOR && mInstructions[i + 0]->mOperator == IA_SHR && + mInstructions[i + 0]->mSrc[0].mTemp < 0 && + + mInstructions[i + 1]->mCode == IC_BINARY_OPERATOR && (mInstructions[i + 1]->mOperator == IA_ADD || mInstructions[i + 1]->mOperator == IA_SUB) && + mInstructions[i + 1]->mSrc[0].mTemp < 0 && + mInstructions[i + 1]->mSrc[1].mTemp == mInstructions[i + 0]->mDst.mTemp && mInstructions[i + 1]->mSrc[1].mFinal && + + mInstructions[i + 2]->mCode == IC_BINARY_OPERATOR && mInstructions[i + 2]->mOperator == IA_SHL && + mInstructions[i + 2]->mSrc[0].mTemp < 0 && + mInstructions[i + 2]->mSrc[1].mTemp == mInstructions[i + 1]->mDst.mTemp && mInstructions[i + 2]->mSrc[1].mFinal && + + mInstructions[i + 3]->mCode == IC_BINARY_OPERATOR && mInstructions[i + 3]->mOperator == IA_AND && + mInstructions[i + 3]->mSrc[0].mTemp < 0 && + mInstructions[i + 3]->mSrc[1].mTemp == mInstructions[i + 2]->mDst.mTemp && mInstructions[i + 3]->mSrc[1].mFinal && + + mInstructions[i + 0]->mSrc[0].mIntConst == mInstructions[i + 2]->mSrc[0].mIntConst) + { + mInstructions[i + 3]->mSrc[0].mIntConst &= ~((1 << mInstructions[i + 0]->mSrc[0].mIntConst) - 1); + mInstructions[i + 1]->mSrc[0].mIntConst <<= mInstructions[i + 0]->mSrc[0].mIntConst; + + mInstructions[i + 1]->mSrc[1] = mInstructions[i + 0]->mSrc[1]; + mInstructions[i + 1]->mDst = mInstructions[i + 2]->mDst; + + mInstructions[i + 0]->mCode = IC_NONE; + mInstructions[i + 0]->mNumOperands = 0; + mInstructions[i + 2]->mCode = IC_NONE; + mInstructions[i + 2]->mNumOperands = 0; + changed = true; + } + if (i + 2 < mInstructions.Size() && + mInstructions[i + 0]->mCode == IC_BINARY_OPERATOR && mInstructions[i + 0]->mOperator == IA_AND && + mInstructions[i + 0]->mSrc[0].mTemp < 0 && + + mInstructions[i + 1]->mCode == IC_BINARY_OPERATOR && (mInstructions[i + 1]->mOperator == IA_ADD || mInstructions[i + 1]->mOperator == IA_SUB) && + mInstructions[i + 1]->mSrc[0].mTemp < 0 && + mInstructions[i + 1]->mSrc[1].mTemp == mInstructions[i + 0]->mDst.mTemp && mInstructions[i + 1]->mSrc[1].mFinal && + + mInstructions[i + 2]->mCode == IC_BINARY_OPERATOR && mInstructions[i + 2]->mOperator == IA_AND && + mInstructions[i + 2]->mSrc[0].mTemp < 0 && + mInstructions[i + 2]->mSrc[1].mTemp == mInstructions[i + 1]->mDst.mTemp && mInstructions[i + 2]->mSrc[1].mFinal && + + (mInstructions[i + 0]->mSrc[0].mIntConst & (mInstructions[i + 0]->mSrc[0].mIntConst + 1)) == 0 && // Is power of two - 1 + (~mInstructions[i + 0]->mSrc[0].mIntConst & mInstructions[i + 1]->mSrc[0].mIntConst) == 0 && // add is part of initial mask + (~mInstructions[i + 0]->mSrc[0].mIntConst & mInstructions[i + 2]->mSrc[0].mIntConst) == 0) // final mask is part of initial mask + { + mInstructions[i + 1]->mSrc[1] = mInstructions[i + 0]->mSrc[1]; + + mInstructions[i + 0]->mCode = IC_NONE; + mInstructions[i + 0]->mNumOperands = 0; + changed = true; + } +#endif #if 1 if (i + 2 < mInstructions.Size() && mInstructions[i + 0]->mCode == IC_BINARY_OPERATOR && @@ -14366,6 +16176,193 @@ bool InterCodeBasicBlock::PeepholeReplaceOptimization(const GrowingVariableArray } } #endif +#if 1 + if (i + 1 < mInstructions.Size()) + { + if (mInstructions[i + 0]->mCode == IC_LEA && mInstructions[i + 0]->mSrc[1].mTemp < 0 && + mInstructions[i + 1]->mCode == IC_RELATIONAL_OPERATOR && mInstructions[i + 1]->mSrc[1].mTemp == mInstructions[i + 0]->mDst.mTemp && mInstructions[i + 1]->mSrc[0].mTemp < 0 && + mInstructions[i + 1]->mSrc[0].mMemory == IM_ABSOLUTE && mInstructions[i + 1]->mSrc[0].mIntConst == 0) + { + if (mInstructions[i + 0]->mSrc[1].mMemory != IM_ABSOLUTE) + { + if (mInstructions[i + 1]->mOperator == IA_CMPEQ) + { + mInstructions[i + 1]->mNumOperands = 0; + mInstructions[i + 1]->mCode = IC_CONSTANT; + mInstructions[i + 1]->mConst.mType = IT_BOOL; + mInstructions[i + 1]->mConst.mIntConst = 0; + changed = true; + } + else if (mInstructions[i + 1]->mOperator == IA_CMPNE) + { + mInstructions[i + 1]->mNumOperands = 0; + mInstructions[i + 1]->mCode = IC_CONSTANT; + mInstructions[i + 1]->mConst.mType = IT_BOOL; + mInstructions[i + 1]->mConst.mIntConst = 1; + changed = true; + } + } + } + } +#endif + } + + return changed; +} + +static int TempUseDelta(const InterInstruction* ins) +{ + int d = 0; + if (ins->mDst.mTemp >= 0) + d++; + for (int i = 0; i < ins->mNumOperands; i++) + if (ins->mSrc[i].mTemp >= 0 && ins->mSrc[i].mFinal) + d--; + return d; +} + +bool InterCodeBasicBlock::IsConstExitTemp(int temp) const +{ + int n = mInstructions.Size() - 1; + while (n >= 0 && mInstructions[n]->mDst.mTemp != temp) + n--; + return n >= 0 && mInstructions[n]->mCode == IC_CONSTANT; +} + +bool InterCodeBasicBlock::SplitSingleBranchUseConst(void) +{ + bool changed = false; + + if (!mVisited) + { + mVisited = true; + + if (!mLoopHead && mFalseJump) + { + for (int i = 0; i + 1 < mInstructions.Size(); i++) + { + InterInstruction* ins = mInstructions[i]; + + if (ins->mCode == IC_CONSTANT) + { + if (CanMoveInstructionBehindBlock(i)) + { + InterCodeBasicBlock* tblock = nullptr; + + if (mTrueJump->mEntryRequiredTemps[ins->mDst.mTemp] && !mFalseJump->mEntryRequiredTemps[ins->mDst.mTemp]) + tblock = mTrueJump; + else if (!mTrueJump->mEntryRequiredTemps[ins->mDst.mTemp] && mFalseJump->mEntryRequiredTemps[ins->mDst.mTemp]) + tblock = mFalseJump; + + if (tblock) + { + if (tblock->mNumEntries > 1) + { + InterCodeBasicBlock* nblock = new InterCodeBasicBlock(mProc); + + nblock->mEntryRequiredTemps = tblock->mEntryRequiredTemps; + nblock->mExitRequiredTemps = tblock->mEntryRequiredTemps; + + mExitRequiredTemps -= ins->mDst.mTemp; + nblock->mEntryRequiredTemps -= ins->mDst.mTemp; + + tblock->mEntryBlocks.RemoveAll(this); + tblock->mEntryBlocks.Push(nblock); + + if (tblock == mTrueJump) + mTrueJump = nblock; + else + mFalseJump = nblock; + + InterInstruction* jins = new InterInstruction(mInstructions.Last()->mLocation, IC_JUMP); + nblock->mInstructions.Push(jins); + nblock->Close(tblock, nullptr); + + nblock->mEntryBlocks.Push(this); + nblock->mNumEntries = 1; + + tblock = nblock; + } + + tblock->mInstructions.Insert(0, ins); + mInstructions.Remove(i); + i--; + changed = true; + } + } + } + } + } + + + if (mTrueJump && mTrueJump->SplitSingleBranchUseConst()) + changed = true; + if (mFalseJump && mFalseJump->SplitSingleBranchUseConst()) + changed = true; + } + + return changed; +} + + +bool InterCodeBasicBlock::CommonTailCodeMerge(void) +{ + bool changed = false; + + if (!mVisited) + { + mVisited = true; + + if (!mLoopHead) + { + for (int i = 0; i + 1 < mInstructions.Size(); i++) + { + InterInstruction* ins = mInstructions[i]; + + if (CanMoveInstructionBeforeBlock(i)) + { + bool aconst = true, aany = false; + for (int j = 0; j < ins->mNumOperands; j++) + { + if (ins->mSrc[j].mTemp >= 0) + { + aany = true; + int k = 0; + while (k < mEntryBlocks.Size() && mEntryBlocks[k]->IsConstExitTemp(ins->mSrc[j].mTemp) && !mEntryBlocks[k]->mFalseJump) + k++; + if (k < mEntryBlocks.Size()) + { + aconst = false; + break; + } + } + } + + if (aconst && aany) + { + for (int j = 0; j < mEntryBlocks.Size(); j++) + { + InterCodeBasicBlock* eblock = mEntryBlocks[j]; + eblock->mInstructions.Insert(eblock->mInstructions.Size() - 1, ins->Clone()); + if (ins->mDst.mTemp >= 0) + eblock->mExitRequiredTemps += ins->mDst.mTemp; + } + if (ins->mDst.mTemp >= 0) + mEntryRequiredTemps += ins->mDst.mTemp; + ins->mCode = IC_NONE; + ins->mNumOperands = 0; + ins->mDst.mTemp = -1; + changed = true; + } + + } + } + } + + if (mTrueJump && mTrueJump->CommonTailCodeMerge()) + changed = true; + if (mFalseJump && mFalseJump->CommonTailCodeMerge()) + changed = true; } return changed; @@ -14685,25 +16682,26 @@ void InterCodeBasicBlock::PeepholeOptimization(const GrowingVariableArray& stati j--; while (j >= 0) { + InterInstruction* jins = mInstructions[j]; + if (j < ti - 1) { if (CanMoveInstructionDown(j, ti)) { - InterInstruction* jins = mInstructions[j]; for (int k = j; k < ti - 1; k++) { SwapInstructions(jins, mInstructions[k + 1]); mInstructions[k] = mInstructions[k + 1]; } mInstructions[ti - 1] = jins; - if (mInstructions[ti - 1]->NumUsedTemps() <= 1) - ti--; + if (jins->NumUsedTemps() <= 1 && !(jins->mCode == IC_CALL || jins->mCode == IC_CALL_NATIVE)) + ti--; // mInstructions.Insert(i, mInstructions[j]); // mInstructions.Remove(j); } } - else if (mInstructions[j]->NumUsedTemps() <= 1) + else if (jins->NumUsedTemps() <= 1 && !(jins->mCode == IC_CALL || jins->mCode == IC_CALL_NATIVE)) ti--; j--; @@ -14714,6 +16712,33 @@ void InterCodeBasicBlock::PeepholeOptimization(const GrowingVariableArray& stati #endif CheckFinalLocal(); + // check move calls our of range to save register spilling + i = 0; + while (i < mInstructions.Size()) + { + InterInstruction* ins(mInstructions[i]); + if (ins->mCode == IC_CALL || ins->mCode == IC_CALL_NATIVE) + { + int j = i; + while (j > 0 && CanSwapInstructions(ins, mInstructions[j - 1]) && TempUseDelta(mInstructions[j - 1]) >= 0) + j--; + while (j < i && TempUseDelta(mInstructions[j]) == 0) + j++; + + if (j < i) + { + while (i > j) + { + i--; + SwapInstructions(mInstructions[i], ins); + mInstructions[i + 1] = mInstructions[i]; + } + mInstructions[j] = ins; + } + } + i++; + } + // sort stores up bool changed; @@ -14801,6 +16826,26 @@ void InterCodeBasicBlock::PeepholeOptimization(const GrowingVariableArray& stati } } +void InterCodeBasicBlock::CheckNullptrDereference(void) +{ + if (!mVisited) + { + mVisited = true; + + for (int i = 0; i < mInstructions.Size(); i++) + { + InterInstruction* ins = mInstructions[i]; + if (ins->mCode == IC_LOAD && ins->mSrc[0].mTemp < 0 && ins->mSrc[0].mMemory == IM_ABSOLUTE && ins->mSrc[0].mIntConst == 0 && !ins->mVolatile) + mProc->mModule->mErrors->Error(ins->mLocation, EWARN_NULL_POINTER_DEREFERENCED, "nullptr dereferenced"); + else if (ins->mCode == IC_STORE && ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mMemory == IM_ABSOLUTE && ins->mSrc[1].mIntConst == 0 && !ins->mVolatile) + mProc->mModule->mErrors->Error(ins->mLocation, EWARN_NULL_POINTER_DEREFERENCED, "nullptr dereferenced"); + } + + if (mTrueJump) mTrueJump->CheckNullptrDereference(); + if (mFalseJump) mFalseJump->CheckNullptrDereference(); + } +} + void InterCodeBasicBlock::CheckValueReturn(void) { if (!mVisited) @@ -14810,7 +16855,7 @@ void InterCodeBasicBlock::CheckValueReturn(void) for (int i = 0; i < mInstructions.Size(); i++) { InterInstruction* ins = mInstructions[i]; - if (ins->mCode == IC_ASSEMBLER) + if (ins->mCode == IC_ASSEMBLER || ins->mCode == IC_DISPATCH) return; else if (ins->mCode == IC_RETURN) mProc->mModule->mErrors->Error(ins->mLocation, EWARN_MISSING_RETURN_STATEMENT, "Missing return statement"); @@ -14821,6 +16866,94 @@ void InterCodeBasicBlock::CheckValueReturn(void) } } +void InterCodeBasicBlock::CollectGlobalReferences(NumberSet& referencedGlobals, NumberSet& modifiedGlobals, bool& storesIndirect, bool& loadsIndirect, bool& globalsChecked) +{ + if (!mVisited) + { + mVisited = true; + + for (int i = 0; i < mInstructions.Size(); i++) + { + InterInstruction* ins = mInstructions[i]; + + switch (ins->mCode) + { + case IC_LOAD: + if (ins->mSrc[0].mTemp < 0 && ins->mSrc[0].mMemory == IM_GLOBAL && ins->mSrc[0].mVarIndex >= 0) + referencedGlobals += ins->mSrc[0].mVarIndex; + else if (ins->mSrc[0].mTemp >= 0) + loadsIndirect = true; + break; + case IC_STORE: + if (ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mMemory == IM_GLOBAL && ins->mSrc[1].mVarIndex >= 0) + { + referencedGlobals += ins->mSrc[1].mVarIndex; + modifiedGlobals += ins->mSrc[1].mVarIndex; + } + else if (ins->mSrc[1].mTemp >= 0) + storesIndirect = true; + break; + case IC_COPY: + case IC_STRCPY: + if (ins->mSrc[0].mTemp < 0 && ins->mSrc[0].mMemory == IM_GLOBAL && ins->mSrc[0].mVarIndex >= 0) + referencedGlobals += ins->mSrc[0].mVarIndex; + else if (ins->mSrc[0].mTemp >= 0) + loadsIndirect = true; + if (ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mMemory == IM_GLOBAL && ins->mSrc[1].mVarIndex >= 0) + { + referencedGlobals += ins->mSrc[1].mVarIndex; + modifiedGlobals += ins->mSrc[1].mVarIndex; + } + else if (ins->mSrc[1].mTemp >= 0) + storesIndirect = true; + break; + case IC_CALL: + case IC_CALL_NATIVE: + if (ins->mSrc[0].mTemp < 0 && ins->mSrc[0].mLinkerObject && ins->mSrc[0].mLinkerObject->mProc) + { + InterCodeProcedure* proc = ins->mSrc[0].mLinkerObject->mProc; + if (proc->mGlobalsChecked) + { + if (proc->mStoresIndirect) + storesIndirect = true; + if (proc->mLoadsIndirect) + loadsIndirect = true; + referencedGlobals |= proc->mReferencedGlobals; + modifiedGlobals |= proc->mModifiedGlobals; + } + else + globalsChecked = false; + } + else + globalsChecked = false; + break; + case IC_DISPATCH: + { + for (int j = 0; j < mProc->mCalledFunctions.Size(); j++) + { + InterCodeProcedure* proc = mProc->mCalledFunctions[j]; + + if (proc->mGlobalsChecked) + { + if (proc->mStoresIndirect) + storesIndirect = true; + if (proc->mLoadsIndirect) + loadsIndirect = true; + referencedGlobals |= proc->mReferencedGlobals; + modifiedGlobals |= proc->mModifiedGlobals; + } + else + globalsChecked = false; + } + } + break; + } + } + + if (mTrueJump) mTrueJump->CollectGlobalReferences(referencedGlobals, modifiedGlobals, storesIndirect, loadsIndirect, globalsChecked); + if (mFalseJump) mFalseJump->CollectGlobalReferences(referencedGlobals, modifiedGlobals, storesIndirect, loadsIndirect, globalsChecked); + } +} void InterCodeBasicBlock::WarnUsedUndefinedVariables(void) { @@ -14887,7 +17020,6 @@ void InterCodeBasicBlock::WarnUsedUndefinedVariables(void) } } - void InterCodeBasicBlock::CollectVariables(GrowingVariableArray& globalVars, GrowingVariableArray& localVars, GrowingVariableArray& paramVars, InterMemory paramMemory) { int i; @@ -15109,7 +17241,11 @@ void InterCodeBasicBlock::Disassemble(FILE* file, bool dumpSets) const char* s = mLoopHead ? "Head" : ""; - fprintf(file, "L%d: <= D%d: (%d) %s P%d\n", mIndex, (mDominator ? mDominator->mIndex : -1), mNumEntries, s, (mLoopPrefix ? mLoopPrefix->mIndex : -1)); + fprintf(file, "L%d: <= D%d: (%d) %s P%d", mIndex, (mDominator ? mDominator->mIndex : -1), mNumEntries, s, (mLoopPrefix ? mLoopPrefix->mIndex : -1)); + if (mInstructions.Size()) + fprintf(file, " %s\n", mInstructions[0]->mLocation.mFileName); + else + fprintf(file, "\n"); if (dumpSets) { @@ -15137,8 +17273,8 @@ void InterCodeBasicBlock::Disassemble(FILE* file, bool dumpSets) { if (mInstructions[i]->mCode != IC_NONE) { - fprintf(file, "%04x\t", i); - mInstructions[i]->Disassemble(file); + fprintf(file, "%04x (%4d)\t", i, mInstructions[i]->mLocation.mLine); + mInstructions[i]->Disassemble(file, mProc); } } @@ -15153,7 +17289,7 @@ void InterCodeBasicBlock::Disassemble(FILE* file, bool dumpSets) void InterCodeBasicBlock::WarnUnreachable(void) { - if (mNumEntries == 0) + if (mNumEntries == 0 && mProc->mCheckUnreachable) { int i = 0; while (i < mInstructions.Size() && !IsObservable(mInstructions[i]->mCode)) @@ -15171,13 +17307,16 @@ InterCodeProcedure::InterCodeProcedure(InterCodeModule * mod, const Location & l mValueForwardingTable(nullptr), mLocalVars(nullptr), mParamVars(nullptr), mModule(mod), mIdent(ident), mLinkerObject(linkerObject), mNativeProcedure(false), mLeafProcedure(false), mCallsFunctionPointer(false), mCalledFunctions(nullptr), mFastCallProcedure(false), - mInterrupt(false), mHardwareInterrupt(false), mCompiled(false), mInterruptCalled(false), mDynamicStack(false), + mInterrupt(false), mHardwareInterrupt(false), mCompiled(false), mInterruptCalled(false), mDynamicStack(false), mAssembled(false), mSaveTempsLinkerObject(nullptr), mValueReturn(false), mFramePointer(false), - mDeclaration(nullptr) + mCheckUnreachable(true), mReturnType(IT_NONE), mCheapInline(false), + mDeclaration(nullptr), mGlobalsChecked(false), mDispatchedCall(false), + mNumRestricted(1) { mID = mModule->mProcedures.Size(); mModule->mProcedures.Push(this); mLinkerObject->mProc = this; + mLinkerObject->mFlags |= LOBJF_CONST; mCallerSavedTemps = BC_REG_TMP_SAVED - BC_REG_TMP; } @@ -15231,11 +17370,18 @@ void InterCodeProcedure::ResetVisited(void) int InterCodeProcedure::AddTemporary(InterType type) { + assert(type != IT_NONE); + int temp = mTemporaries.Size(); mTemporaries.Push(type); return temp; } +int InterCodeProcedure::AddRestricted(void) +{ + return mNumRestricted++; +} + void InterCodeProcedure::CheckBlocks(void) { ResetVisited(); @@ -15299,6 +17445,10 @@ void InterCodeProcedure::BuildTraces(bool expand, bool dominators, bool compact) mBlocks[i]->mNumEntries = 0; mEntryBlock->CollectEntries(); + ResetEntryBlocks(); + ResetVisited(); + mEntryBlock->CollectEntryBlocks(nullptr); + ResetVisited(); for (int i = 0; i < mBlocks.Size(); i++) mBlocks[i]->mDominator = nullptr; @@ -15435,12 +17585,12 @@ void InterCodeProcedure::SingleAssignmentForwarding(void) ResetVisited(); mEntryBlock->SingleAssignmentTempForwarding(tunified, tvalues); + DisassembleDebug("single assignment forwarding"); + BuildDataFlowSets(); TempForwarding(); RemoveUnusedInstructions(); - DisassembleDebug("single assignment forwarding"); - } void InterCodeProcedure::PeepholeOptimization(void) @@ -15475,6 +17625,17 @@ void InterCodeProcedure::CheckUsedDefinedTemps(void) #endif } +void InterCodeProcedure::PropagateMemoryAliasingInfo(void) +{ + GrowingInstructionPtrArray tvalue(nullptr); + + ResetVisited(); + mEntryBlock->PropagateMemoryAliasingInfo(tvalue); + + Disassemble("PropagateMemoryAliasingInfo"); +} + + void InterCodeProcedure::WarnUsedUndefinedVariables(void) { ResetEntryBlocks(); @@ -15542,6 +17703,52 @@ void InterCodeProcedure::RemoveUnusedInstructions(void) } while (mEntryBlock->RemoveUnusedResultInstructions()); } +void InterCodeProcedure::RemoveUnusedLocalStoreInstructions(void) +{ + if (mCompilerOptions & COPT_OPTIMIZE_BASIC) + { + ResetVisited(); + mEntryBlock->RemoveUnusedLocalStoreInstructions(); + } +} + +void InterCodeProcedure::RemoveUnusedPartialStoreInstructions(void) +{ + if (mCompilerOptions & COPT_OPTIMIZE_BASIC) + { + if (mModule->mGlobalVars.Size()) + { + int byteIndex = 0; + for (int i = 0; i < mModule->mGlobalVars.Size(); i++) + { + if (mModule->mGlobalVars[i]) + { + mModule->mGlobalVars[i]->mByteIndex = byteIndex; + byteIndex += mModule->mGlobalVars[i]->mSize; + } + } + + do { + ResetVisited(); + mEntryBlock->BuildStaticVariableByteSet(mModule->mGlobalVars, byteIndex); + + ResetVisited(); + mEntryBlock->BuildGlobalProvidedStaticVariableSet(mModule->mGlobalVars, NumberSet(byteIndex)); + + NumberSet totalRequired2(byteIndex); + + do { + ResetVisited(); + } while (mEntryBlock->BuildGlobalRequiredStaticVariableSet(mModule->mGlobalVars, totalRequired2)); + + ResetVisited(); + } while (mEntryBlock->RemoveUnusedStaticStoreByteInstructions(mModule->mGlobalVars, byteIndex)); + + DisassembleDebug("removed unused static byte stores"); + } + } +} + void InterCodeProcedure::RemoveUnusedStoreInstructions(InterMemory paramMemory) { if (mCompilerOptions & COPT_OPTIMIZE_BASIC) @@ -15606,6 +17813,11 @@ void InterCodeProcedure::RemoveUnusedStoreInstructions(InterMemory paramMemory) DisassembleDebug("removed unused static stores"); } + + // Remove unused indirect stores + + ResetVisited(); + mEntryBlock->RemoveUnusedIndirectStoreInstructions(); } } @@ -15936,6 +18148,8 @@ void InterCodeProcedure::LoadStoreForwarding(InterMemory paramMemory) bool changed; do { + PropagateMemoryAliasingInfo(); + GrowingInstructionPtrArray gipa(nullptr); ResetVisited(); changed = mEntryBlock->LoadStoreForwarding(gipa, mModule->mGlobalVars); @@ -15944,11 +18158,15 @@ void InterCodeProcedure::LoadStoreForwarding(InterMemory paramMemory) RemoveUnusedStoreInstructions(paramMemory); + GlobalConstantPropagation(); + RemoveUnusedMallocs(); + TempForwarding(); RemoveUnusedInstructions(); DisassembleDebug("Load/Store forwarding"); } while (changed); + } void InterCodeProcedure::CombineIndirectAddressing(void) @@ -15972,6 +18190,17 @@ void InterCodeProcedure::PropagateConstOperationsUp(void) do { changed = false; + ResetVisited(); + if (mEntryBlock->SplitSingleBranchUseConst()) + changed = true; + + ResetVisited(); + if (mEntryBlock->CommonTailCodeMerge()) + { + changed = true; + BuildDataFlowSets(); + } + ResetVisited(); mEntryBlock->BuildConstTempSets(); @@ -16002,6 +18231,9 @@ void InterCodeProcedure::BuildLocalAliasTable(void) GrowingIntArray localTable(-1), paramTable(-1); int nlocals = 0, nparams = 0; + localTable.SetSize(mTemporaries.Size()); + paramTable.SetSize(mTemporaries.Size()); + ResetVisited(); mEntryBlock->CollectLocalAddressTemps(localTable, paramTable, nlocals, nparams); @@ -16017,7 +18249,8 @@ void InterCodeProcedure::Close(void) { GrowingTypeArray tstack(IT_NONE); - CheckFunc = !strcmp(mIdent->mString, "main"); + CheckFunc = !strcmp(mIdent->mString, "dungeon_rand_path"); + CheckCase = false; mEntryBlock = mBlocks[0]; @@ -16115,10 +18348,30 @@ void InterCodeProcedure::Close(void) ResetVisited(); mEntryBlock->PerformMachineSpecificValueUsageCheck(mValueForwardingTable, tvalidSet, mModule->mGlobalVars, fsingleSet); - GlobalConstantPropagation(); - DisassembleDebug("machine value forwarding"); + GlobalConstantPropagation(); + + DisassembleDebug("Global Constant Propagation"); + + // Check for cheap inlining + // + + if (mCompilerOptions & COPT_OPTIMIZE_INLINE) + { + ResetVisited(); + if (mEntryBlock->CheapInlining(numTemps)) + { + mValueForwardingTable.SetSize(numTemps, true); + mTemporaries.SetSize(numTemps, true); + + DisassembleDebug("Cheap Inlining"); + + BuildDataFlowSets(); + } + } + + // // // Now remove needless temporary moves, that appear due to // stack evaluation @@ -16146,8 +18399,14 @@ void InterCodeProcedure::Close(void) else CollectVariables(paramMemory); + for (int i = 0; i < mLocalVars.Size(); i++) + if (i < mLocalAliasedSet.Size() && mLocalAliasedSet[i]) + mLocalVars[i]->mAliased = true; + BuildDataFlowSets(); + LoadStoreForwarding(paramMemory); + ResetVisited(); mEntryBlock->OptimizeIntervalCompare(); @@ -16172,6 +18431,8 @@ void InterCodeProcedure::Close(void) TempForwarding(); RemoveUnusedInstructions(); + DisassembleDebug("pre single block loop opt"); + ResetVisited(); mEntryBlock->SingleBlockLoopOptimisation(mParamAliasedSet, mModule->mGlobalVars); @@ -16282,8 +18543,14 @@ void InterCodeProcedure::Close(void) Disassemble("gcp-"); #endif + BuildTraces(false); + DisassembleDebug("Rebuilt traces"); + BuildDataFlowSets(); + TempForwarding(); + RemoveUnusedInstructions(); + #if 1 ResetVisited(); mEntryBlock->BuildLocalIntegerRangeSets(mTemporaries.Size(), mLocalVars, mParamVars); @@ -16294,6 +18561,9 @@ void InterCodeProcedure::Close(void) ResetVisited(); } while (mEntryBlock->BuildGlobalIntegerRangeSets(true, mLocalVars, mParamVars)); + TempForwarding(); + RemoveUnusedInstructions(); + do { DisassembleDebug("tq"); @@ -16303,6 +18573,7 @@ void InterCodeProcedure::Close(void) DisassembleDebug("Estimated value range"); + GrowingInstructionPtrArray pipa(nullptr); ResetVisited(); mEntryBlock->LinkerObjectForwarding(pipa); @@ -16312,16 +18583,12 @@ void InterCodeProcedure::Close(void) ResetVisited(); mEntryBlock->SimplifyIntegerRangeRelops(); - DisassembleDebug("Simplified range limited relational ops"); + DisassembleDebug("Simplified range limited relational ops 1"); #endif BuildTraces(false); DisassembleDebug("Rebuilt traces"); - ResetEntryBlocks(); - ResetVisited(); - mEntryBlock->CollectEntryBlocks(nullptr); - #if 1 SimplifyIntegerNumeric(activeSet); @@ -16364,6 +18631,15 @@ void InterCodeProcedure::Close(void) DisassembleDebug("MoveTrainCrossBlock"); +#endif + + HoistCommonConditionalPath(); + DisassembleDebug("HoistCommonConditionalPath"); + +#if 1 + ResetVisited(); + mEntryBlock->MoveLoopHeadCheckToTail(); + #endif #if 1 @@ -16385,9 +18661,6 @@ void InterCodeProcedure::Close(void) #endif BuildTraces(false); - ResetEntryBlocks(); - ResetVisited(); - mEntryBlock->CollectEntryBlocks(nullptr); #if 1 SingleBlockLoopPointerSplit(activeSet); @@ -16468,7 +18741,7 @@ void InterCodeProcedure::Close(void) ResetVisited(); mEntryBlock->SimplifyIntegerRangeRelops(); - DisassembleDebug("Simplified range limited relational ops"); + DisassembleDebug("Simplified range limited relational ops 2"); #endif #if 1 @@ -16521,6 +18794,8 @@ void InterCodeProcedure::Close(void) LoadStoreForwarding(paramMemory); + RebuildIntegerRangeSet(); + #if 1 BuildLoopPrefix(); DisassembleDebug("added dominators"); @@ -16587,6 +18862,8 @@ void InterCodeProcedure::Close(void) mEntryBlock->CollectEntryBlocks(nullptr); BuildTraces(false); + BuildDataFlowSets(); + BuildTraces(false); #endif PropagateConstOperationsUp(); @@ -16598,6 +18875,11 @@ void InterCodeProcedure::Close(void) #endif + ResetVisited(); + mEntryBlock->SimplifyIntegerRangeRelops(); + + DisassembleDebug("Simplified range limited relational ops 3"); + #if 1 BuildDataFlowSets(); @@ -16610,8 +18892,11 @@ void InterCodeProcedure::Close(void) RemoveUnusedInstructions(); #endif + RemoveUnusedLocalStoreInstructions(); + #if 1 ResetVisited(); + if (!mInterruptCalled && !mDynamicStack && mNativeProcedure && mEntryBlock->CheckStaticStack()) { mLinkerObject->mFlags |= LOBJF_STATIC_STACK; @@ -16649,7 +18934,7 @@ void InterCodeProcedure::Close(void) ResetVisited(); mEntryBlock->SingleBlockLoopOptimisation(mParamAliasedSet, mModule->mGlobalVars); - DisassembleDebug("single block loop opt 3"); + DisassembleDebug("single block loop opt 4"); BuildDataFlowSets(); @@ -16659,15 +18944,23 @@ void InterCodeProcedure::Close(void) } #endif + DisassembleDebug("PreLoopTemp"); BuildDataFlowSets(); ResetVisited(); mEntryBlock->ForwardLoopMovedTemp(); + DisassembleDebug("PostLoopTemp"); + CheckFinal(); + DisassembleDebug("PreConstP"); #if 1 do { + DisassembleDebug("InConstP"); TempForwarding(); } while (GlobalConstantPropagation()); + BuildTraces(false); + DisassembleDebug("Rebuilt traces"); + PeepholeOptimization(); TempForwarding(); @@ -16696,18 +18989,31 @@ void InterCodeProcedure::Close(void) CombineIndirectAddressing(); #if 1 - for (int i = 0; i < 4; i++) + for (int i = 0; i < 8; i++) { + BuildTraces(false); + + LoadStoreForwarding(paramMemory); + + RebuildIntegerRangeSet(); + PeepholeOptimization(); DisassembleDebug("Peephole Temp Check"); + + if (i == 1) + CheckCase = true; RemoveUnusedInstructions(); ReduceTemporaries(); + CheckBlocks(); + MergeBasicBlocks(); + CheckBlocks(); + DisassembleDebug("TempForward Rev 1"); BuildDataFlowSets(); @@ -16716,6 +19022,8 @@ void InterCodeProcedure::Close(void) RemoveUnusedInstructions(); + CheckBlocks(); + BuildDataFlowSets(); DisassembleDebug("TempForward Rev 2"); @@ -16724,6 +19032,8 @@ void InterCodeProcedure::Close(void) DisassembleDebug("TempForward Rev 3"); + CheckBlocks(); + BuildLoopPrefix(); BuildDataFlowSets(); @@ -16769,6 +19079,8 @@ void InterCodeProcedure::Close(void) } #endif + RemoveUnusedPartialStoreInstructions(); + MapVariables(); DisassembleDebug("mapped variabled"); @@ -16796,6 +19108,9 @@ void InterCodeProcedure::Close(void) mEntryBlock->CheckValueReturn(); } + ResetVisited(); + mEntryBlock->CheckNullptrDereference(); + if (mSaveTempsLinkerObject && mTempSize > BC_REG_TMP_SAVED - BC_REG_TMP) mSaveTempsLinkerObject->AddSpace(mTempSize - (BC_REG_TMP_SAVED - BC_REG_TMP)); @@ -16817,6 +19132,112 @@ void InterCodeProcedure::Close(void) } } } + + if (mTempSize <= BC_REG_TMP_SAVED - BC_REG_TMP && !(mLinkerObject->mFlags & LOBJF_STATIC_STACK) && mLeafProcedure) + { + bool hasLocals = false; + + for (int i = 0; i < mLocalVars.Size(); i++) + if (mLocalVars[i] && mLocalVars[i]->mUsed) + hasLocals = true; + + if (!hasLocals) + mLinkerObject->mFlags |= LOBJF_STATIC_STACK; + } + + if (!(mLinkerObject->mFlags & LOBJF_STATIC_STACK)) + { + ResetVisited(); + if (!mEntryBlock->PreventsCallerStaticStack()) + mLinkerObject->mFlags |= LOBJF_STATIC_STACK; + } + + if (!mEntryBlock->mTrueJump) + { + int nconst = 0, nvariables = 0, nparams = 0, ncalls = 0, nret = 0, nother = 0, nops = 0; + for (int i = 0; i < mEntryBlock->mInstructions.Size(); i++) + { + InterInstruction* ins = mEntryBlock->mInstructions[i]; + switch (ins->mCode) + { + case IC_LOAD: + if (ins->mSrc[0].mTemp < 0) + { + if (ins->mSrc[0].mMemory == IM_FPARAM || ins->mSrc[0].mMemory == IM_PARAM) + nparams++; + else if (ins->mSrc[0].mMemory == IM_GLOBAL || ins->mSrc[0].mMemory == IM_ABSOLUTE) + nvariables++; + else + nother++; + } + else + nother++; + break; + case IC_STORE: + if (ins->mSrc[1].mTemp >= 0 || (ins->mSrc[1].mMemory != IM_FFRAME && ins->mSrc[1].mMemory != IM_FRAME)) + nops++; + if (ins->mSrc[0].mTemp < 0) + nconst++; + break; + +#if 1 + case IC_CONSTANT: + if (ins->mDst.mType == IT_POINTER && (ins->mConst.mMemory == IM_FPARAM || ins->mConst.mMemory == IM_PARAM || ins->mConst.mMemory == IM_LOCAL)) + nother++; + else + nconst++; + break; +#endif +#if 1 + case IC_LEA: + if (ins->mSrc[1].mTemp >= 0 || (ins->mSrc[1].mMemory != IM_FPARAM && ins->mSrc[1].mMemory != IM_PARAM && ins->mSrc[1].mMemory != IM_LOCAL)) + nops++; + else + nother++; + break; +#endif +#if 1 + case IC_BINARY_OPERATOR: + case IC_UNARY_OPERATOR: + case IC_RELATIONAL_OPERATOR: + nops++; + break; +#endif + case IC_CALL: + case IC_CALL_NATIVE: + if (ins->mSrc[0].mTemp < 0) + ncalls++; + else + nother++; + break; + case IC_RETURN: + case IC_RETURN_VALUE: + nret++; + break; + default: + nother++; + } + } + + if (nother == 0 && ncalls <= 1 && nret == 1 && nconst <= 1 + nparams && nops <= 1 + nparams) + mCheapInline = true; + } + + mGlobalsChecked = true; + mStoresIndirect = false; + mLoadsIndirect = false; + mReferencedGlobals.Reset(mModule->mGlobalVars.Size()); + mModifiedGlobals.Reset(mModule->mGlobalVars.Size()); +#if 1 + if (!mLeafProcedure && mCommonFrameSize > 0) + { + ResetVisited(); + if (!mEntryBlock->RecheckOuterFrame()) + mCommonFrameSize = 0; + } +#endif + ResetVisited(); + mEntryBlock->CollectGlobalReferences(mReferencedGlobals, mModifiedGlobals, mStoresIndirect, mLoadsIndirect, mGlobalsChecked); } void InterCodeProcedure::AddCalledFunction(InterCodeProcedure* proc) @@ -16884,7 +19305,6 @@ void InterCodeProcedure::SingleTailLoopOptimization(InterMemory paramMemory) } while (changed); } - void InterCodeProcedure::MapVariables(void) { ResetVisited(); @@ -17021,9 +19441,11 @@ void InterCodeProcedure::MergeBasicBlocks(void) if (block->mNumEntries) { int j = 0; - while (j < i && !(mBlocks[j]->mNumEntries && mBlocks[j]->IsEqual(block))) + while (j < i && !(mBlocks[j]->mNumEntries && mBlocks[j]->IsEqual(block) && mBlocks[j]->mIndex != 0)) j++; blockMap[i] = mBlocks[j]; + if (i != j) + mBlocks[j]->UnionIntegerRanges(block); } } @@ -17131,9 +19553,21 @@ void InterCodeProcedure::MergeBasicBlocks(void) { assert(mblocks[j]->mInstructions[mblocks[j]->mInstructions.Size() - 1]->mCode == IC_JUMP); assert(mblocks[j]->mInstructions[mblocks[j]->mInstructions.Size() - 2]->IsEqual(ins)); + + ins->UnionRanges(mblocks[j]->mInstructions[mblocks[j]->mInstructions.Size() - 2]); mblocks[j]->mInstructions.Remove(mblocks[j]->mInstructions.Size() - 2); } + + if (nblock->mEntryValueRange.Size()) + { + for (int j = 0; j < ins->mNumOperands; j++) + { + if (ins->mSrc[j].mTemp >= 0) + nblock->mEntryValueRange[ins->mSrc[j].mTemp] = ins->mSrc[j].mRange; + } + } + changed = true; } } @@ -17147,6 +19581,46 @@ void InterCodeProcedure::MergeBasicBlocks(void) } +bool InterCodeProcedure::ReferencesGlobal(int varindex) +{ + if (mGlobalsChecked) + { + if (varindex >= 0) + { + if (mModule->mGlobalVars[varindex]->mAliased) + return mLoadsIndirect || mStoresIndirect; + else if (varindex < mReferencedGlobals.Size()) + return mReferencedGlobals[varindex]; + else + return false; + } + else + return false; + } + else + return true; +} + +bool InterCodeProcedure::ModifiesGlobal(int varindex) +{ + if (mGlobalsChecked) + { + if (varindex >= 0) + { + if (mModule->mGlobalVars[varindex]->mAliased) + return mStoresIndirect; + else if (varindex < mModifiedGlobals.Size()) + return mModifiedGlobals[varindex]; + else + return false; + } + else + return false; + } + else + return true; +} + void InterCodeProcedure::BuildLoopPrefix(void) { ResetVisited(); @@ -17186,6 +19660,25 @@ bool InterCodeProcedure::GlobalConstantPropagation(void) return mEntryBlock->PropagateConstTemps(ctemps); } +void InterCodeProcedure::RemoveUnusedMallocs(void) +{ + ResetVisited(); + mEntryBlock->RemoveUnusedMallocs(); +} + +void InterCodeProcedure::HoistCommonConditionalPath(void) +{ + for(;;) + { + ResetVisited(); + if (!mEntryBlock->HoistCommonConditionalPath()) + return; + TempForwarding(); + RemoveUnusedInstructions(); + } +} + + void InterCodeProcedure::ReduceTemporaries(void) { NumberSet* collisionSet; @@ -17204,6 +19697,9 @@ void InterCodeProcedure::ReduceTemporaries(void) ResetVisited(); } while (mEntryBlock->BuildGlobalRequiredTempSet(totalRequired2)); + ResetVisited(); + mEntryBlock->PruneUnusedIntegerRangeSets(); + collisionSet = new NumberSet[numTemps]; for (i = 0; i < numTemps; i++) diff --git a/oscar64/InterCode.h b/oscar64/InterCode.h index 0c7f5fd..34ed462 100644 --- a/oscar64/InterCode.h +++ b/oscar64/InterCode.h @@ -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 mMemoryValueSize, mEntryMemoryValueSize; - GrowingArray mEntryBlocks, mLoopPathBlocks; + ExpandingArray 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 & body); - void CollectLoopPath(const GrowingArray& body, GrowingArray& path); + bool CollectLoopBody(InterCodeBasicBlock* head, ExpandingArray & body); + bool CollectLoopBodyRecursive(InterCodeBasicBlock* head, ExpandingArray& body); + void CollectLoopPath(const ExpandingArray& body, ExpandingArray& path); void InnerLoopOptimization(const NumberSet& aliasedParams); void PushMoveOutOfLoop(void); - + + void PropagateMemoryAliasingInfo(const GrowingInstructionPtrArray& tvalue); + void RemoveUnusedMallocs(void); + bool CollectSingleHeadLoopBody(InterCodeBasicBlock* head, InterCodeBasicBlock* tail, GrowingArray& 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); diff --git a/oscar64/InterCodeGenerator.cpp b/oscar64/InterCodeGenerator.cpp index 70418cd..f0a1165 100644 --- a/oscar64/InterCodeGenerator.cpp +++ b/oscar64/InterCodeGenerator.cpp @@ -1,4 +1,5 @@ #include "InterCodeGenerator.h" +#include "Constexpr.h" InterCodeGenerator::InterCodeGenerator(Errors* errors, Linker* linker) : mErrors(errors), mLinker(linker), mCompilerOptions(COPT_DEFAULT) @@ -34,15 +35,27 @@ static inline InterType InterTypeOf(const Declaration* dec) case DT_TYPE_FUNCTION: case DT_TYPE_ARRAY: case DT_TYPE_REFERENCE: + case DT_TYPE_RVALUEREF: return IT_POINTER; } } -InterCodeGenerator::ExValue InterCodeGenerator::Dereference(InterCodeProcedure* proc, Expression* exp, InterCodeBasicBlock*& block, ExValue v, int level) +InterCodeGenerator::ExValue InterCodeGenerator::ToValue(InterCodeProcedure* proc, Expression* exp, InterCodeBasicBlock*& block, InlineMapper* inlineMapper, ExValue v) +{ + if (v.mType && v.mType->IsReference()) + { + v.mType = v.mType->mBase; + v.mReference++; + } + + return v; +} + +InterCodeGenerator::ExValue InterCodeGenerator::Dereference(InterCodeProcedure* proc, Expression* exp, InterCodeBasicBlock*& block, InlineMapper* inlineMapper, ExValue v, int level) { while (v.mReference > level) { - InterInstruction * ins = new InterInstruction(exp->mLocation, IC_LOAD); + InterInstruction * ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_LOAD); ins->mSrc[0].mMemory = IM_INDIRECT; ins->mSrc[0].mType = IT_POINTER; ins->mSrc[0].mTemp = v.mTemp; @@ -51,28 +64,243 @@ InterCodeGenerator::ExValue InterCodeGenerator::Dereference(InterCodeProcedure* ins->mSrc[0].mOperandSize = v.mReference == 1 ? v.mType->mSize : 2; ins->mSrc[0].mStride = v.mReference == 1 ? v.mType->mStripe : 1; + if (ins->mDst.mType == IT_NONE) + { + mErrors->Error(exp->mLocation, EERR_INVALID_VALUE, "Not a simple type"); + return v; + } + if (v.mReference == 1 && v.mType->mType == DT_TYPE_ENUM) { ins->mDst.mRange.LimitMin(v.mType->mMinValue); ins->mDst.mRange.LimitMax(v.mType->mMaxValue); } + if (v.mType->mFlags & DTF_VOLATILE) ins->mVolatile = true; block->Append(ins); - v = ExValue(v.mType, ins->mDst.mTemp, v.mReference - 1); + if (v.mReference == 1 && v.mBits) + { + if (v.mBits + v.mShift <= 8) + ins->mDst.mType = IT_INT8; + else if (v.mBits + v.mShift <= 16) + ins->mDst.mType = IT_INT16; + else + ins->mDst.mType = IT_INT32; + + ins->mSrc[0].mOperandSize = InterTypeSize[ins->mDst.mType]; + int nbits = ins->mSrc[0].mOperandSize * 8; + + InterInstruction* clsins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + clsins->mDst.mType = IT_INT8; + clsins->mDst.mTemp = proc->AddTemporary(clsins->mDst.mType); + clsins->mConst.mType = IT_INT8; + clsins->mConst.mIntConst = nbits - v.mShift - v.mBits; + clsins->mNumOperands = 0; + block->Append(clsins); + + InterInstruction* crsins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + crsins->mDst.mType = IT_INT8; + crsins->mDst.mTemp = proc->AddTemporary(crsins->mDst.mType); + crsins->mConst.mType = IT_INT8; + crsins->mConst.mIntConst = nbits - v.mBits; + crsins->mNumOperands = 0; + block->Append(crsins); + + InterInstruction* slins = new InterInstruction(MapLocation(exp, inlineMapper), IC_BINARY_OPERATOR); + slins->mOperator = IA_SHL; + slins->mDst.mType = ins->mDst.mType; + slins->mDst.mTemp = proc->AddTemporary(slins->mDst.mType); + slins->mSrc[1] = ins->mDst; + slins->mSrc[0] = clsins->mDst; + slins->mNumOperands = 2; + block->Append(slins); + + InterInstruction* srins = new InterInstruction(MapLocation(exp, inlineMapper), IC_BINARY_OPERATOR); + srins->mOperator = (v.mType->mFlags & DTF_SIGNED) ? IA_SAR : IA_SHR; + srins->mDst.mType = ins->mDst.mType; + srins->mDst.mTemp = proc->AddTemporary(slins->mDst.mType); + srins->mSrc[1] = slins->mDst; + srins->mSrc[0] = crsins->mDst; + srins->mNumOperands = 2; + block->Append(srins); + + if (InterTypeSize[ins->mDst.mType] < v.mType->mSize) + { + InterInstruction* crins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONVERSION_OPERATOR); + crins->mDst.mType = InterTypeOf(v.mType); + crins->mDst.mTemp = proc->AddTemporary(crins->mDst.mType); + crins->mSrc[0] = srins->mDst; + crins->mNumOperands = 1; + if (ins->mDst.mType == IT_INT16) + crins->mOperator = (v.mType->mFlags & DTF_SIGNED) ? IA_EXT16TO32S : IA_EXT16TO32U; + else if (v.mType->mSize == 2) + crins->mOperator = (v.mType->mFlags & DTF_SIGNED) ? IA_EXT8TO16S : IA_EXT8TO16U; + else + crins->mOperator = (v.mType->mFlags & DTF_SIGNED) ? IA_EXT8TO32S : IA_EXT8TO32U; + block->Append(crins); + v = ExValue(v.mType, crins->mDst.mTemp, v.mReference - 1); + } + else + v = ExValue(v.mType, srins->mDst.mTemp, v.mReference - 1); + } + else + v = ExValue(v.mType, ins->mDst.mTemp, v.mReference - 1, v.mBits, v.mShift); } return v; } -InterCodeGenerator::ExValue InterCodeGenerator::CoerceType(InterCodeProcedure* proc, Expression* exp, InterCodeBasicBlock*& block, ExValue v, Declaration* type, bool checkTrunc) +void InterCodeGenerator::StoreValue(InterCodeProcedure* proc, Expression* exp, InterCodeBasicBlock*& block, InlineMapper* inlineMapper, ExValue vl, ExValue vr) +{ + // Bitfield assignment + if (vl.mBits) + { + InterType itype; + + if (vl.mBits + vl.mShift <= 8) + itype = IT_INT8; + else if (vl.mBits + vl.mShift <= 16) + itype = IT_INT16; + else + itype = IT_INT32; + + int nbits = InterTypeSize[itype] * 8; + + InterInstruction* lins = new InterInstruction(MapLocation(exp, inlineMapper), IC_LOAD); + lins->mDst.mType = itype; + lins->mDst.mTemp = proc->AddTemporary(lins->mDst.mType); + lins->mSrc[0].mMemory = IM_INDIRECT; + lins->mSrc[0].mType = IT_POINTER; + lins->mSrc[0].mTemp = vl.mTemp; + lins->mSrc[0].mOperandSize = InterTypeSize[itype]; + lins->mVolatile = vl.mType->mFlags & DTF_VOLATILE; + lins->mNumOperands = 1; + block->Append(lins); + + InterInstruction* csins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + csins->mDst.mType = IT_INT8; + csins->mDst.mTemp = proc->AddTemporary(csins->mDst.mType); + csins->mConst.mType = IT_INT8; + csins->mConst.mIntConst = vl.mShift; + csins->mNumOperands = 0; + block->Append(csins); + + InterInstruction* cmsins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + cmsins->mDst.mType = itype; + cmsins->mDst.mTemp = proc->AddTemporary(cmsins->mDst.mType); + cmsins->mConst.mType = itype; + cmsins->mConst.mIntConst = ((1 << vl.mBits) - 1) << vl.mShift; + cmsins->mNumOperands = 0; + block->Append(cmsins); + + InterInstruction* cmlins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + cmlins->mDst.mType = itype; + cmlins->mDst.mTemp = proc->AddTemporary(cmlins->mDst.mType); + cmlins->mConst.mType = itype; + cmlins->mConst.mIntConst = ~cmsins->mConst.mIntConst; + cmlins->mNumOperands = 0; + block->Append(cmlins); + + int rtemp = vr.mTemp; + + if (InterTypeSize[itype] > vr.mType->mSize) + { + InterInstruction* cins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONVERSION_OPERATOR); + + if (InterTypeSize[itype] == 2) + cins->mOperator = IA_EXT8TO16U; + else if (vr.mType->mSize == 1) + cins->mOperator = IA_EXT8TO32U; + else + cins->mOperator = IA_EXT8TO16U; + + cins->mDst.mType = itype; + cins->mDst.mTemp = proc->AddTemporary(itype); + cins->mSrc[0].mTemp = rtemp; + cins->mSrc[0].mType = InterTypeOf(vr.mType); + block->Append(cins); + + rtemp = cins->mDst.mTemp; + } + + InterInstruction* sins = new InterInstruction(MapLocation(exp, inlineMapper), IC_BINARY_OPERATOR); + sins->mOperator = IA_SHL; + sins->mDst.mType = itype; + sins->mDst.mTemp = proc->AddTemporary(sins->mDst.mType); + sins->mSrc[1].mTemp = rtemp; + sins->mSrc[1].mType = itype; + sins->mSrc[0] = csins->mDst; + sins->mNumOperands = 2; + block->Append(sins); + + InterInstruction* msins = new InterInstruction(MapLocation(exp, inlineMapper), IC_BINARY_OPERATOR); + msins->mOperator = IA_AND; + msins->mDst.mType = itype; + msins->mDst.mTemp = proc->AddTemporary(msins->mDst.mType); + msins->mSrc[0] = sins->mDst; + msins->mSrc[1] = cmsins->mDst; + msins->mNumOperands = 2; + block->Append(msins); + + InterInstruction* mlins = new InterInstruction(MapLocation(exp, inlineMapper), IC_BINARY_OPERATOR); + mlins->mOperator = IA_AND; + mlins->mDst.mType = itype; + mlins->mDst.mTemp = proc->AddTemporary(mlins->mDst.mType); + mlins->mSrc[0] = lins->mDst; + mlins->mSrc[1] = cmlins->mDst; + mlins->mNumOperands = 2; + block->Append(mlins); + + InterInstruction* oins = new InterInstruction(MapLocation(exp, inlineMapper), IC_BINARY_OPERATOR); + oins->mOperator = IA_OR; + oins->mDst.mType = itype; + oins->mDst.mTemp = proc->AddTemporary(oins->mDst.mType); + oins->mSrc[0] = msins->mDst; + oins->mSrc[1] = mlins->mDst; + oins->mNumOperands = 2; + block->Append(oins); + + InterInstruction* ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_STORE); + ins->mSrc[1].mMemory = IM_INDIRECT; + ins->mSrc[0] = oins->mDst; + ins->mSrc[1].mType = IT_POINTER; + ins->mSrc[1].mTemp = vl.mTemp; + ins->mSrc[1].mOperandSize = InterTypeSize[itype]; + ins->mVolatile = vl.mType->mFlags & DTF_VOLATILE; + ins->mNumOperands = 2; + block->Append(ins); + } + else + { + InterInstruction* ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_STORE); + + ins->mSrc[1].mMemory = IM_INDIRECT; + ins->mSrc[0].mType = InterTypeOf(vr.mType); + ins->mSrc[0].mTemp = vr.mTemp; + ins->mSrc[1].mType = IT_POINTER; + ins->mSrc[1].mTemp = vl.mTemp; + ins->mSrc[1].mOperandSize = vl.mType->mSize; + ins->mSrc[1].mStride = vl.mType->mStripe; + ins->mVolatile = vl.mType->mFlags & DTF_VOLATILE; + ins->mNumOperands = 2; + block->Append(ins); + } +} + +InterCodeGenerator::ExValue InterCodeGenerator::CoerceType(InterCodeProcedure* proc, Expression* exp, InterCodeBasicBlock*& block, InlineMapper* inlineMapper, ExValue v, Declaration* type, bool checkTrunc) { int stemp = v.mTemp; - if (type->mType == DT_TYPE_REFERENCE) + if (type->IsReference()) { - if (!type->mBase->IsSubType(v.mType)) + if (v.mType->IsReference()) + { + if (!type->mBase->IsSubType(v.mType->mBase)) + mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Incompatible type for reference"); + } + else if (!type->mBase->IsSubType(v.mType)) mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Incompatible type for reference"); return v; @@ -83,13 +311,20 @@ InterCodeGenerator::ExValue InterCodeGenerator::CoerceType(InterCodeProcedure* p return v; } + if (v.mType->IsReference() && type->IsSimpleType()) + { + v.mReference++; + v.mType = v.mType->mBase; + v = Dereference(proc, exp, block, inlineMapper, v); + } + if (v.mType->IsIntegerType() && type->mType == DT_TYPE_FLOAT) { if (v.mType->mSize == 1) { if (v.mType->mFlags & DTF_SIGNED) { - InterInstruction * xins = new InterInstruction(exp->mLocation, IC_CONVERSION_OPERATOR); + InterInstruction * xins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONVERSION_OPERATOR); xins->mOperator = IA_EXT8TO16S; xins->mSrc[0].mType = IT_INT8; xins->mSrc[0].mTemp = stemp; @@ -100,7 +335,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::CoerceType(InterCodeProcedure* p } else { - InterInstruction * xins = new InterInstruction(exp->mLocation, IC_CONVERSION_OPERATOR); + InterInstruction * xins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONVERSION_OPERATOR); xins->mOperator = IA_EXT8TO16U; xins->mSrc[0].mType = IT_INT8; xins->mSrc[0].mTemp = stemp; @@ -111,7 +346,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::CoerceType(InterCodeProcedure* p } } - InterInstruction * cins = new InterInstruction(exp->mLocation, IC_CONVERSION_OPERATOR); + InterInstruction * cins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONVERSION_OPERATOR); cins->mOperator = (v.mType->mFlags & DTF_SIGNED) ? IA_INT2FLOAT : IA_UINT2FLOAT; cins->mSrc[0].mType = IT_INT16; cins->mSrc[0].mTemp = stemp; @@ -124,7 +359,9 @@ InterCodeGenerator::ExValue InterCodeGenerator::CoerceType(InterCodeProcedure* p } else if (v.mType->mType == DT_TYPE_FLOAT && type->IsIntegerType()) { - InterInstruction * cins = new InterInstruction(exp->mLocation, IC_CONVERSION_OPERATOR); + mErrors->Error(exp->mLocation, EWARN_FLOAT_TO_INT, "Float to int conversion, potential loss of precision"); + + InterInstruction * cins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONVERSION_OPERATOR); cins->mOperator = IA_FLOAT2INT; cins->mSrc[0].mType = IT_FLOAT; cins->mSrc[0].mTemp = v.mTemp; @@ -134,13 +371,44 @@ InterCodeGenerator::ExValue InterCodeGenerator::CoerceType(InterCodeProcedure* p v.mTemp = cins->mDst.mTemp; v.mType = type; } + else if (type->mType == DT_TYPE_POINTER && v.mType->mType == DT_TYPE_ARRAY) + { + v.mType = type; + return v; + } + else if (type->mType == DT_TYPE_POINTER && v.mType->IsNumericType() && (mCompilerOptions & COPT_CPLUSPLUS)) + { + mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign numeric value to pointer"); + } + else if( type->mType == DT_TYPE_BOOL && v.mType->mType == DT_TYPE_POINTER) + { + InterInstruction* zins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + zins->mDst.mType = IT_POINTER; + zins->mDst.mTemp = proc->AddTemporary(IT_POINTER); + zins->mConst.mType = IT_POINTER; + zins->mConst.mMemory = IM_ABSOLUTE; + zins->mConst.mIntConst = 0; + block->Append(zins); + + InterInstruction* cins = new InterInstruction(MapLocation(exp, inlineMapper), IC_RELATIONAL_OPERATOR); + cins->mOperator = IA_CMPNE; + cins->mSrc[0].mType = IT_POINTER; + cins->mSrc[0].mTemp = v.mTemp; + cins->mSrc[1].mType = IT_POINTER; + cins->mSrc[1].mTemp = zins->mDst.mTemp; + cins->mDst.mType = IT_BOOL; + cins->mDst.mTemp = proc->AddTemporary(IT_BOOL); + block->Append(cins); + v.mTemp = cins->mDst.mTemp; + v.mType = type; + } else if (v.mType->mSize < type->mSize) { if (v.mType->mSize == 1 && type->mSize == 2) { if (v.mType->mFlags & DTF_SIGNED) { - InterInstruction * xins = new InterInstruction(exp->mLocation, IC_CONVERSION_OPERATOR); + InterInstruction * xins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONVERSION_OPERATOR); xins->mOperator = IA_EXT8TO16S; xins->mSrc[0].mType = IT_INT8; xins->mSrc[0].mTemp = stemp; @@ -151,7 +419,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::CoerceType(InterCodeProcedure* p } else { - InterInstruction * xins = new InterInstruction(exp->mLocation, IC_CONVERSION_OPERATOR); + InterInstruction * xins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONVERSION_OPERATOR); xins->mOperator = IA_EXT8TO16U; xins->mSrc[0].mType = IT_INT8; xins->mSrc[0].mTemp = stemp; @@ -165,7 +433,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::CoerceType(InterCodeProcedure* p { if (v.mType->mFlags & DTF_SIGNED) { - InterInstruction* xins = new InterInstruction(exp->mLocation, IC_CONVERSION_OPERATOR); + InterInstruction* xins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONVERSION_OPERATOR); xins->mOperator = IA_EXT16TO32S; xins->mSrc[0].mType = IT_INT16; xins->mSrc[0].mTemp = stemp; @@ -176,7 +444,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::CoerceType(InterCodeProcedure* p } else { - InterInstruction* xins = new InterInstruction(exp->mLocation, IC_CONVERSION_OPERATOR); + InterInstruction* xins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONVERSION_OPERATOR); xins->mOperator = IA_EXT16TO32U; xins->mSrc[0].mType = IT_INT16; xins->mSrc[0].mTemp = stemp; @@ -190,7 +458,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::CoerceType(InterCodeProcedure* p { if (v.mType->mFlags & DTF_SIGNED) { - InterInstruction* xins = new InterInstruction(exp->mLocation, IC_CONVERSION_OPERATOR); + InterInstruction* xins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONVERSION_OPERATOR); xins->mOperator = IA_EXT8TO32S; xins->mSrc[0].mType = IT_INT8; xins->mSrc[0].mTemp = stemp; @@ -201,7 +469,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::CoerceType(InterCodeProcedure* p } else { - InterInstruction* xins = new InterInstruction(exp->mLocation, IC_CONVERSION_OPERATOR); + InterInstruction* xins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONVERSION_OPERATOR); xins->mOperator = IA_EXT8TO32U; xins->mSrc[0].mType = IT_INT8; xins->mSrc[0].mTemp = stemp; @@ -305,7 +573,13 @@ void InterCodeGenerator::InitLocalVariable(InterCodeProcedure* proc, Declaration proc->mLocalVars[index]->mIdent = dec->mIdent; proc->mLocalVars[index]->mDeclaration = dec; } + else + { + assert(proc->mLocalVars[index]->mIdent == dec->mIdent); + assert(proc->mLocalVars[index]->mDeclaration == dec); + } } + static const Ident* StructIdent(const Ident* base, const Ident* item) { if (base) @@ -433,6 +707,11 @@ void InterCodeGenerator::InitGlobalVariable(InterCodeModule * mod, Declaration* else mErrors->Error(dec->mLocation, EERR_INCOMPATIBLE_TYPES, "Incompatible constant initializer"); } + else if (dec->mValue->mType == EX_CONSTRUCT) + { + DestructStack* destack = nullptr; + TranslateExpression(nullptr, mMainInitProc, mMainInitBlock, dec->mValue, destack, BranchTarget(), BranchTarget(), nullptr); + } else mErrors->Error(dec->mLocation, EERR_CONSTANT_INITIALIZER, "Non constant initializer"); } @@ -451,7 +730,7 @@ void InterCodeGenerator::TranslateAssembler(InterCodeModule* mod, Expression* ex Declaration* dec = exp->mDecValue; - dec->mLinkerObject = mLinker->AddObject(dec->mLocation, dec->mQualIdent, dec->mSection, LOT_NATIVE_CODE); + dec->mLinkerObject = mLinker->AddObject(dec->mLocation, dec->mQualIdent, dec->mSection, LOT_NATIVE_CODE, dec->mAlignment); uint8* d = dec->mLinkerObject->AddSpace(osize); @@ -578,7 +857,20 @@ void InterCodeGenerator::TranslateAssembler(InterCodeModule* mod, Expression* ex } else if (aexp->mType == DT_ARGUMENT || aexp->mType == DT_VARIABLE) { - if (refvars) + if (aexp->mFlags & DTF_GLOBAL) + { + InitGlobalVariable(mod, aexp); + + LinkerReference ref; + ref.mObject = dec->mLinkerObject; + ref.mOffset = offset; + ref.mFlags = LREF_LOWBYTE; + ref.mRefObject = aexp->mLinkerObject; + ref.mRefOffset = 0; + ref.mRefObject->mFlags |= LOBJF_RELEVANT; + dec->mLinkerObject->AddReference(ref); + } + else if (refvars) { int j = 0; while (j < refvars->Size() && (*refvars)[j] != aexp) @@ -759,63 +1051,77 @@ void InterCodeGenerator::TranslateAssembler(InterCodeModule* mod, Expression* ex assert(offset == osize); } -void InterCodeGenerator::BuildSwitchTree(InterCodeProcedure* proc, Expression* exp, InterCodeBasicBlock* block, ExValue v, const SwitchNodeArray& nodes, int left, int right, InterCodeBasicBlock* dblock) +void InterCodeGenerator::BuildSwitchTree(InterCodeProcedure* proc, Expression* exp, InterCodeBasicBlock* block, InlineMapper * inlineMapper, ExValue v, const SwitchNodeArray& nodes, int left, int right, int vleft, int vright, InterCodeBasicBlock* dblock) { - if (right - left < 5) + if (right - left < 3) { for (int i = left; i < right; i++) { - InterCodeBasicBlock* cblock = new InterCodeBasicBlock(proc); + if (vleft == vright) + { + InterInstruction* jins = new InterInstruction(MapLocation(exp, inlineMapper), IC_JUMP); + block->Append(jins); + block->Close(nodes[i].mBlock, nullptr); + return; + } + else + { + InterCodeBasicBlock* cblock = new InterCodeBasicBlock(proc); - InterInstruction* vins = new InterInstruction(exp->mLocation, IC_CONSTANT); - vins->mConst.mType = IT_INT16; - vins->mConst.mIntConst = nodes[i].mValue; - vins->mDst.mType = IT_INT16; - vins->mDst.mTemp = proc->AddTemporary(vins->mDst.mType); - block->Append(vins); + InterInstruction* vins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + vins->mConst.mType = IT_INT16; + vins->mConst.mIntConst = nodes[i].mValue; + vins->mDst.mType = IT_INT16; + vins->mDst.mTemp = proc->AddTemporary(vins->mDst.mType); + block->Append(vins); - InterInstruction* cins = new InterInstruction(exp->mLocation, IC_RELATIONAL_OPERATOR); - cins->mOperator = IA_CMPEQ; - cins->mSrc[0].mType = vins->mDst.mType; - cins->mSrc[0].mTemp = vins->mDst.mTemp; - cins->mSrc[1].mType = vins->mDst.mType; - cins->mSrc[1].mTemp = v.mTemp; - cins->mDst.mType = IT_BOOL; - cins->mDst.mTemp = proc->AddTemporary(cins->mDst.mType); + InterInstruction* cins = new InterInstruction(MapLocation(exp, inlineMapper), IC_RELATIONAL_OPERATOR); + cins->mOperator = IA_CMPEQ; + cins->mSrc[0].mType = vins->mDst.mType; + cins->mSrc[0].mTemp = vins->mDst.mTemp; + cins->mSrc[1].mType = vins->mDst.mType; + cins->mSrc[1].mTemp = v.mTemp; + cins->mDst.mType = IT_BOOL; + cins->mDst.mTemp = proc->AddTemporary(cins->mDst.mType); - block->Append(cins); + block->Append(cins); - InterInstruction* bins = new InterInstruction(exp->mLocation, IC_BRANCH); - bins->mSrc[0].mType = IT_BOOL; - bins->mSrc[0].mTemp = cins->mDst.mTemp; - block->Append(bins); + InterInstruction* bins = new InterInstruction(MapLocation(exp, inlineMapper), IC_BRANCH); + bins->mSrc[0].mType = IT_BOOL; + bins->mSrc[0].mTemp = cins->mDst.mTemp; + block->Append(bins); - block->Close(nodes[i].mBlock, cblock); + block->Close(nodes[i].mBlock, cblock); - block = cblock; + block = cblock; + + if (vleft == nodes[i].mValue) + vleft = nodes[i].mValue + 1; + } } - InterInstruction* jins = new InterInstruction(exp->mLocation, IC_JUMP); + InterInstruction* jins = new InterInstruction(MapLocation(exp, inlineMapper), IC_JUMP); block->Append(jins); block->Close(dblock, nullptr); } else { - int center = (left + right + 1) >> 1; + int center = (left + right) >> 1; + int vcenter = nodes[center].mValue; InterCodeBasicBlock* cblock = new InterCodeBasicBlock(proc); InterCodeBasicBlock* rblock = new InterCodeBasicBlock(proc); InterCodeBasicBlock* lblock = new InterCodeBasicBlock(proc); - InterInstruction* vins = new InterInstruction(exp->mLocation, IC_CONSTANT); + InterInstruction* vins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); vins->mConst.mType = IT_INT16; - vins->mConst.mIntConst = nodes[center].mValue; + vins->mConst.mIntConst = vcenter; vins->mDst.mType = IT_INT16; vins->mDst.mTemp = proc->AddTemporary(vins->mDst.mType); block->Append(vins); - InterInstruction* cins = new InterInstruction(exp->mLocation, IC_RELATIONAL_OPERATOR); + InterInstruction* cins = new InterInstruction(MapLocation(exp, inlineMapper), IC_RELATIONAL_OPERATOR); cins->mOperator = IA_CMPEQ; cins->mSrc[0].mType = vins->mDst.mType; cins->mSrc[0].mTemp = vins->mDst.mTemp; @@ -826,14 +1132,14 @@ void InterCodeGenerator::BuildSwitchTree(InterCodeProcedure* proc, Expression* e block->Append(cins); - InterInstruction* bins = new InterInstruction(exp->mLocation, IC_BRANCH); + InterInstruction* bins = new InterInstruction(MapLocation(exp, inlineMapper), IC_BRANCH); bins->mSrc[0].mType = IT_BOOL; bins->mSrc[0].mTemp = cins->mDst.mTemp; block->Append(bins); block->Close(nodes[center].mBlock, cblock); - InterInstruction* rins = new InterInstruction(exp->mLocation, IC_RELATIONAL_OPERATOR); + InterInstruction* rins = new InterInstruction(MapLocation(exp, inlineMapper), IC_RELATIONAL_OPERATOR); rins->mOperator = IA_CMPLS; rins->mSrc[0].mType = vins->mDst.mType; rins->mSrc[0].mTemp = vins->mDst.mTemp; @@ -844,30 +1150,60 @@ void InterCodeGenerator::BuildSwitchTree(InterCodeProcedure* proc, Expression* e cblock->Append(rins); - InterInstruction* rbins = new InterInstruction(exp->mLocation, IC_BRANCH); + InterInstruction* rbins = new InterInstruction(MapLocation(exp, inlineMapper), IC_BRANCH); rbins->mSrc[0].mType = IT_BOOL; rbins->mSrc[0].mTemp = rins->mDst.mTemp; cblock->Append(rbins); cblock->Close(lblock, rblock); - BuildSwitchTree(proc, exp, lblock, v, nodes, left, center, dblock); - BuildSwitchTree(proc, exp, rblock, v, nodes, center + 1, right, dblock); + BuildSwitchTree(proc, exp, lblock, inlineMapper, v, nodes, left, center, vleft, vcenter -1, dblock); + BuildSwitchTree(proc, exp, rblock, inlineMapper, v, nodes, center + 1, right, vcenter + 1, vright, dblock); } } -InterCodeGenerator::ExValue InterCodeGenerator::TranslateInline(Declaration* procType, InterCodeProcedure* proc, InterCodeBasicBlock*& block, Expression* exp, InterCodeBasicBlock* breakBlock, InterCodeBasicBlock* continueBlock, InlineMapper* inlineMapper, bool inlineConstexpr) +void InterCodeGenerator::UnwindDestructStack(Declaration* procType, InterCodeProcedure* proc, InterCodeBasicBlock*& block, DestructStack* stack, DestructStack* bottom, InlineMapper* inlineMapper) { + while (stack && stack != bottom) + { + if (stack->mDestruct) + { + DestructStack* destack = nullptr; + TranslateExpression(procType, proc, block, stack->mDestruct, destack, BranchTarget(), BranchTarget(), inlineMapper); + } + + stack = stack->mNext; + } + + if (stack != bottom) + mErrors->Error(proc->mLocation, EWARN_DESTRUCTOR_MISMATCH, "Destructor sequence mismatch"); +} + +Location InterCodeGenerator::MapLocation(Expression* exp, InlineMapper* inlineMapper) +{ + if (inlineMapper) + return Location(exp->mLocation, inlineMapper->mLocation); + else + return exp->mLocation; +} + +InterCodeGenerator::ExValue InterCodeGenerator::TranslateInline(Declaration* procType, InterCodeProcedure* proc, InterCodeBasicBlock*& block, Expression* exp, const BranchTarget& breakBlock, const BranchTarget& continueBlock, InlineMapper* inlineMapper, bool inlineConstexpr, ExValue* lrexp) +{ + DestructStack* destack = nullptr; + ExValue vl, vr; Declaration* fdec = exp->mLeft->mDecValue; Expression* fexp = fdec->mValue; Declaration* ftype = fdec->mBase; + proc->mCheckUnreachable = false; + InlineMapper nmapper; nmapper.mReturn = new InterCodeBasicBlock(proc); nmapper.mVarIndex = proc->mNumLocals; nmapper.mConstExpr = inlineConstexpr; + nmapper.mLocation = new Location(MapLocation(exp, inlineMapper)); proc->mNumLocals += fdec->mNumVars; if (inlineMapper) nmapper.mDepth = inlineMapper->mDepth + 1; @@ -879,20 +1215,21 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateInline(Declaration* pro int nindex = proc->mNumLocals++; Declaration* vdec = new Declaration(pex->mLocation, DT_VARIABLE); - InterInstruction* ains = new InterInstruction(pex->mLocation, IC_CONSTANT); + InterInstruction* ains = new InterInstruction(MapLocation(pex, inlineMapper), IC_CONSTANT); ains->mDst.mType = IT_POINTER; ains->mDst.mTemp = proc->AddTemporary(ains->mDst.mType); + ains->mConst.mType = IT_POINTER; ains->mConst.mMemory = IM_LOCAL; ains->mConst.mVarIndex = nindex; if (pdec) { - if (!(pdec->mFlags & DTF_FPARAM_CONST)) + if (!(pdec->mFlags & DTF_FPARAM_UNUSED)) nmapper.mParams[pdec->mVarIndex] = nindex; vdec->mVarIndex = nindex; vdec->mBase = pdec->mBase; - if (pdec->mBase->mType == DT_TYPE_ARRAY || pdec->mBase->mType == DT_TYPE_REFERENCE) + if (pdec->mBase->mType == DT_TYPE_ARRAY || pdec->mBase->mType == DT_TYPE_REFERENCE || pdec->mBase->mType == DT_TYPE_RVALUEREF) ains->mConst.mOperandSize = 2; else ains->mConst.mOperandSize = pdec->mSize; @@ -922,66 +1259,62 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateInline(Declaration* pro ExValue vp(pdec ? pdec->mBase : TheSignedIntTypeDeclaration, ains->mDst.mTemp, 1); - vr = TranslateExpression(procType, proc, block, texp, breakBlock, continueBlock, inlineMapper, &vp); + if (pdec && (pdec->mBase->mType == DT_TYPE_STRUCT || pdec->mBase->mType == DT_TYPE_UNION)) + vr = TranslateExpression(procType, proc, block, texp, destack, breakBlock, continueBlock, inlineMapper, &vp); + else + vr = TranslateExpression(procType, proc, block, texp, destack, breakBlock, continueBlock, inlineMapper, nullptr); - if (!(pdec && pdec->mBase->mType == DT_TYPE_REFERENCE) && (vr.mType->mType == DT_TYPE_STRUCT || vr.mType->mType == DT_TYPE_UNION)) + if (!(pdec && pdec->mBase->IsReference()) && (vr.mType->mType == DT_TYPE_STRUCT || vr.mType->mType == DT_TYPE_UNION)) { if (pdec && !pdec->mBase->CanAssign(vr.mType)) - mErrors->Error(texp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types"); + mErrors->Error(texp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types", pdec->mBase->MangleIdent(), vr.mType->MangleIdent()); - vr = Dereference(proc, texp, block, vr, 1); + vr = Dereference(proc, texp, block, inlineMapper, vr, 1); if (vr.mReference != 1) mErrors->Error(exp->mLeft->mLocation, EERR_NOT_AN_LVALUE, "Not an addressable expression"); if (vp.mTemp != vr.mTemp) - { - InterInstruction* cins = new InterInstruction(exp->mLocation, IC_COPY); - - cins->mSrc[0].mType = IT_POINTER; - cins->mSrc[0].mTemp = vr.mTemp; - cins->mSrc[0].mMemory = IM_INDIRECT; - cins->mSrc[0].mOperandSize = vp.mType->mSize; - cins->mSrc[0].mStride = vr.mType->mStripe; - - cins->mSrc[1].mType = IT_POINTER; - cins->mSrc[1].mTemp = ains->mDst.mTemp; - cins->mSrc[1].mMemory = IM_INDIRECT; - cins->mSrc[1].mOperandSize = vp.mType->mSize; - - cins->mConst.mOperandSize = vp.mType->mSize; - block->Append(cins); - } + CopyStructSimple(proc, exp, block, inlineMapper, vp, vr); } else { if (vr.mType->mType == DT_TYPE_ARRAY || vr.mType->mType == DT_TYPE_FUNCTION) - vr = Dereference(proc, texp, block, vr, 1); - else if (pdec && pdec->mBase->mType == DT_TYPE_REFERENCE) - vr = Dereference(proc, texp, block, vr, 1); + vr = Dereference(proc, texp, block, inlineMapper, vr, 1); + else if (pdec && (pdec->mBase->IsReference() && !vr.mType->IsReference())) + vr = Dereference(proc, texp, block, inlineMapper, vr, 1); + else if (vr.mType->IsReference() && !(pdec && pdec->mBase->IsReference())) + { + vr.mReference++; + vr = Dereference(proc, texp, block, inlineMapper, vr); + } else - vr = Dereference(proc, texp, block, vr); + vr = Dereference(proc, texp, block, inlineMapper, vr); if (pdec) { if (!pdec->mBase->CanAssign(vr.mType)) - mErrors->Error(texp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types"); - vr = CoerceType(proc, texp, block, vr, pdec->mBase); + { + pdec->mBase->CanAssign(vr.mType); + mErrors->Error(texp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types", pdec->mBase->MangleIdent(), vr.mType->MangleIdent()); + } + vr = CoerceType(proc, texp, block, inlineMapper, vr, pdec->mBase); } else if (vr.mType->IsIntegerType() && vr.mType->mSize < 2) { - vr = CoerceType(proc, texp, block, vr, TheSignedIntTypeDeclaration); + vr = CoerceType(proc, texp, block, inlineMapper, vr, TheSignedIntTypeDeclaration); } - InterInstruction* wins = new InterInstruction(texp->mLocation, IC_STORE); + InterInstruction* wins = new InterInstruction(MapLocation(texp, inlineMapper), IC_STORE); wins->mSrc[1].mMemory = IM_INDIRECT; - wins->mSrc[0].mType = InterTypeOf(vr.mType);; + wins->mSrc[0].mType = vr.mReference > 0 ? IT_POINTER : InterTypeOf(vr.mType); wins->mSrc[0].mTemp = vr.mTemp; + assert(wins->mSrc[0].mType != IT_NONE); wins->mSrc[1].mType = IT_POINTER; wins->mSrc[1].mTemp = ains->mDst.mTemp; if (pdec) { - if (pdec->mBase->mType == DT_TYPE_ARRAY || pdec->mBase->mType == DT_TYPE_REFERENCE) + if (pdec->mBase->mType == DT_TYPE_ARRAY || pdec->mBase->mType == DT_TYPE_REFERENCE || pdec->mBase->mType == DT_TYPE_RVALUEREF) wins->mSrc[1].mOperandSize = 2; else wins->mSrc[1].mOperandSize = pdec->mSize; @@ -991,7 +1324,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateInline(Declaration* pro else wins->mSrc[1].mOperandSize = 2; - if (!pdec || !(pdec->mFlags & DTF_FPARAM_CONST)) + if (!pdec || !(pdec->mFlags & DTF_FPARAM_UNUSED)) block->Append(wins); } @@ -1005,28 +1338,44 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateInline(Declaration* pro Declaration* rdec = nullptr; if (ftype->mBase->mType != DT_TYPE_VOID) { - int nindex = proc->mNumLocals++; - nmapper.mResult = nindex; + if (lrexp) + { + nmapper.mResultExp = lrexp; + } + else + { + int nindex = proc->mNumLocals++; + nmapper.mResult = nindex; - rdec = new Declaration(ftype->mLocation, DT_VARIABLE); - rdec->mVarIndex = nindex; - rdec->mBase = ftype->mBase; - rdec->mSize = rdec->mBase->mSize; + rdec = new Declaration(ftype->mLocation, DT_VARIABLE); + rdec->mVarIndex = nindex; + rdec->mBase = ftype->mBase; + rdec->mSize = rdec->mBase->mSize; + } } - vl = TranslateExpression(ftype, proc, block, fexp, nullptr, nullptr, &nmapper); + DestructStack* idestack = nullptr; - InterInstruction* jins = new InterInstruction(exp->mLocation, IC_JUMP); + vl = TranslateExpression(ftype, proc, block, fexp, idestack, BranchTarget(), BranchTarget(), &nmapper); + + InterInstruction* jins = new InterInstruction(MapLocation(exp, inlineMapper), IC_JUMP); block->Append(jins); block->Close(nmapper.mReturn, nullptr); block = nmapper.mReturn; + // Unwind inner destruct stack + UnwindDestructStack(ftype, proc, block, idestack, nullptr, &nmapper); + + // Uwind parameter passing stack + UnwindDestructStack(ftype, proc, block, destack, nullptr, inlineMapper); + if (rdec) { - InterInstruction* ins = new InterInstruction(exp->mLocation, IC_CONSTANT); + InterInstruction* ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); ins->mDst.mType = IT_POINTER; ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType); + ins->mConst.mType = IT_POINTER; ins->mConst.mOperandSize = rdec->mSize; ins->mConst.mIntConst = rdec->mOffset; ins->mConst.mVarIndex = rdec->mVarIndex; @@ -1034,13 +1383,288 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateInline(Declaration* pro block->Append(ins); - return ExValue(rdec->mBase, ins->mDst.mTemp, 1); + ExValue rv(rdec->mBase, ins->mDst.mTemp, 1); + if (!rdec->mBase->IsReference() && rdec->mBase->mType != DT_TYPE_STRUCT) + rv = Dereference(proc, exp, block, inlineMapper, rv); + return rv; + } + else if (lrexp) + { + return *lrexp; } else return ExValue(TheVoidTypeDeclaration); } -InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* procType, InterCodeProcedure* proc, InterCodeBasicBlock*& block, Expression* exp, InterCodeBasicBlock* breakBlock, InterCodeBasicBlock* continueBlock, InlineMapper* inlineMapper, ExValue* lrexp) +void InterCodeGenerator::CopyStructSimple(InterCodeProcedure* proc, Expression * exp, InterCodeBasicBlock* block, InlineMapper * inlineMapper, ExValue vl, ExValue vr) +{ + int ne = 0; + Declaration* mdec = nullptr; + if (vl.mType->mType == DT_TYPE_STRUCT) + { + Declaration* dec = vl.mType->mParams; + while (dec) + { + if (dec->mType == DT_ELEMENT && !(dec->mFlags & DTF_STATIC) && dec->mBase->IsSimpleType()) + { + mdec = dec->mBase; + ne++; + } + dec = dec->mNext; + } + } + + // Single element structs are copied as individual value + if (ne == 1 && mdec->mSize == vl.mType->mSize) + { + InterInstruction* lins = new InterInstruction(MapLocation(exp, inlineMapper), IC_LOAD); + lins->mNumOperands = 1; + + lins->mSrc[0].mType = IT_POINTER; + lins->mSrc[0].mTemp = vr.mTemp; + lins->mSrc[0].mMemory = IM_INDIRECT; + lins->mSrc[0].mOperandSize = mdec->mSize; + lins->mSrc[0].mStride = mdec->mStripe; + + lins->mDst.mType = InterTypeOf(mdec); + lins->mDst.mTemp = proc->AddTemporary(lins->mDst.mType); + block->Append(lins); + + InterInstruction* sins = new InterInstruction(MapLocation(exp, inlineMapper), IC_STORE); + sins->mNumOperands = 2; + + sins->mSrc[1].mType = IT_POINTER; + sins->mSrc[1].mTemp = vl.mTemp; + sins->mSrc[1].mMemory = IM_INDIRECT; + sins->mSrc[1].mOperandSize = mdec->mSize; + sins->mSrc[1].mStride = mdec->mStripe; + + sins->mSrc[0] = lins->mDst; + block->Append(sins); + } + else + { + InterInstruction* cins = new InterInstruction(MapLocation(exp, inlineMapper), IC_COPY); + cins->mNumOperands = 2; + + cins->mSrc[0].mType = IT_POINTER; + cins->mSrc[0].mTemp = vr.mTemp; + cins->mSrc[0].mMemory = IM_INDIRECT; + cins->mSrc[0].mOperandSize = vr.mType->mSize; + cins->mSrc[0].mStride = vr.mType->mStripe; + + cins->mSrc[1].mOperandSize = vl.mType->mSize; + cins->mSrc[1].mType = IT_POINTER; + cins->mSrc[1].mTemp = vl.mTemp; + cins->mSrc[1].mMemory = IM_INDIRECT; + cins->mSrc[1].mStride = vl.mType->mStripe; + + cins->mConst.mOperandSize = vl.mType->mSize; + block->Append(cins); + } +} + +void InterCodeGenerator::CopyStruct(InterCodeProcedure* proc, Expression* exp, InterCodeBasicBlock*& block, ExValue vl, ExValue vr, InlineMapper* inlineMapper, bool moving) +{ + if (vr.mTemp == vl.mTemp) + return; + + if (vl.mType->mCopyConstructor || moving && vl.mType->mMoveConstructor) + { + Declaration* ccdec = vl.mType->mCopyConstructor; + if (moving && vl.mType->mMoveConstructor) + ccdec = vl.mType->mMoveConstructor; + + if (!ccdec->mLinkerObject) + this->TranslateProcedure(proc->mModule, ccdec->mValue, ccdec); + + bool canInline = (mCompilerOptions & COPT_OPTIMIZE_INLINE) && !(inlineMapper && inlineMapper->mDepth > 10); + bool doInline = false; + + if (canInline) + { + if (ccdec->mFlags & DTF_INLINE) + { + if ((ccdec->mFlags & DTF_REQUEST_INLINE) || (mCompilerOptions & COPT_OPTIMIZE_AUTO_INLINE)) + { + if (proc->mNativeProcedure || !(ccdec->mFlags & DTF_NATIVE)) + doInline = true; + } + } + } + + if (doInline) + { + DestructStack* destack = nullptr; + + Expression* fexp = ccdec->mValue; + Declaration* ftype = ccdec->mBase; + + InlineMapper nmapper; + nmapper.mReturn = new InterCodeBasicBlock(proc); + nmapper.mVarIndex = proc->mNumLocals; + nmapper.mConstExpr = false; + proc->mNumLocals += ccdec->mNumVars; + if (inlineMapper) + nmapper.mDepth = inlineMapper->mDepth + 1; + + Declaration* pdec = ftype->mParams; + int nindex = proc->mNumLocals++; + Declaration* vdec = new Declaration(exp->mLocation, DT_VARIABLE); + + InterInstruction* ains = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + ains->mDst.mType = IT_POINTER; + ains->mDst.mTemp = proc->AddTemporary(ains->mDst.mType); + ains->mConst.mType = IT_POINTER; + ains->mConst.mMemory = IM_LOCAL; + ains->mConst.mVarIndex = nindex; + + if (!(pdec->mFlags & DTF_FPARAM_UNUSED)) + nmapper.mParams[pdec->mVarIndex] = nindex; + + vdec->mVarIndex = nindex; + vdec->mBase = pdec->mBase; + ains->mConst.mOperandSize = 2; + vdec->mSize = ains->mConst.mOperandSize; + vdec->mIdent = pdec->mIdent; + vdec->mQualIdent = pdec->mQualIdent; + block->Append(ains); + + InterInstruction* wins = new InterInstruction(MapLocation(exp, inlineMapper), IC_STORE); + wins->mNumOperands = 2; + wins->mSrc[1].mMemory = IM_INDIRECT; + wins->mSrc[0].mType = vl.mReference > 0 ? IT_POINTER : InterTypeOf(vl.mType); + wins->mSrc[0].mTemp = vl.mTemp; + wins->mSrc[1].mType = IT_POINTER; + wins->mSrc[1].mTemp = ains->mDst.mTemp; + wins->mSrc[1].mOperandSize = 2; + if (!(pdec->mFlags & DTF_FPARAM_UNUSED)) + block->Append(wins); + + pdec = pdec->mNext; + + nindex = proc->mNumLocals++; + vdec = new Declaration(exp->mLocation, DT_VARIABLE); + + ains = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + ains->mNumOperands = 0; + ains->mDst.mType = IT_POINTER; + ains->mDst.mTemp = proc->AddTemporary(ains->mDst.mType); + ains->mConst.mType = IT_POINTER; + ains->mConst.mMemory = IM_LOCAL; + ains->mConst.mVarIndex = nindex; + + if (!(pdec->mFlags & DTF_FPARAM_UNUSED)) + nmapper.mParams[pdec->mVarIndex] = nindex; + + vdec->mVarIndex = nindex; + vdec->mBase = pdec->mBase; + ains->mConst.mOperandSize = 2; + vdec->mSize = ains->mConst.mOperandSize; + vdec->mIdent = pdec->mIdent; + vdec->mQualIdent = pdec->mQualIdent; + block->Append(ains); + + wins = new InterInstruction(MapLocation(exp, inlineMapper), IC_STORE); + wins->mNumOperands = 2; + wins->mSrc[1].mMemory = IM_INDIRECT; + wins->mSrc[0].mType = vr.mReference > 0 ? IT_POINTER : InterTypeOf(vr.mType);; + wins->mSrc[0].mTemp = vr.mTemp; + wins->mSrc[1].mType = IT_POINTER; + wins->mSrc[1].mTemp = ains->mDst.mTemp; + wins->mSrc[1].mOperandSize = 2; + if (!(pdec->mFlags & DTF_FPARAM_UNUSED)) + block->Append(wins); + + TranslateExpression(ftype, proc, block, fexp, destack, BranchTarget(), BranchTarget(), &nmapper); + + InterInstruction* jins = new InterInstruction(MapLocation(exp, inlineMapper), IC_JUMP); + block->Append(jins); + + block->Close(nmapper.mReturn, nullptr); + block = nmapper.mReturn; + } + else if (ccdec->mBase->mFlags & DTF_FASTCALL) + { + InterInstruction* psins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + psins->mDst.mType = IT_POINTER; + psins->mDst.mTemp = proc->AddTemporary(IT_POINTER); + psins->mDst.mOperandSize = 2; + psins->mConst.mType = IT_POINTER; + psins->mConst.mVarIndex = 0; + psins->mConst.mIntConst = 0; + psins->mConst.mOperandSize = 2; + if (ccdec->mBase->mFlags & DTF_FASTCALL) + { + psins->mConst.mMemory = IM_FFRAME; + psins->mConst.mVarIndex += ccdec->mBase->mFastCallBase; + } + else + psins->mConst.mMemory = IM_FRAME; + block->Append(psins); + + InterInstruction* ssins = new InterInstruction(MapLocation(exp, inlineMapper), IC_STORE); + ssins->mSrc[0].mType = IT_POINTER; + ssins->mSrc[0].mTemp = vl.mTemp; + ssins->mSrc[0].mMemory = IM_INDIRECT; + ssins->mSrc[0].mOperandSize = 2; + ssins->mSrc[1] = psins->mDst; + block->Append(ssins); + + InterInstruction* plins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + plins->mDst.mType = IT_POINTER; + plins->mDst.mTemp = proc->AddTemporary(IT_POINTER); + plins->mDst.mOperandSize = 2; + plins->mConst.mType = IT_POINTER; + plins->mConst.mVarIndex = 2; + plins->mConst.mIntConst = 0; + plins->mConst.mOperandSize = 2; + if (ccdec->mBase->mFlags & DTF_FASTCALL) + { + plins->mConst.mMemory = IM_FFRAME; + plins->mConst.mVarIndex += ccdec->mBase->mFastCallBase; + } + else + plins->mConst.mMemory = IM_FRAME; + block->Append(plins); + + InterInstruction* slins = new InterInstruction(MapLocation(exp, inlineMapper), IC_STORE); + slins->mSrc[0].mType = IT_POINTER; + slins->mSrc[0].mTemp = vr.mTemp; + slins->mSrc[0].mMemory = IM_INDIRECT; + slins->mSrc[0].mOperandSize = 2; + slins->mSrc[1] = plins->mDst; + block->Append(slins); + + proc->AddCalledFunction(proc->mModule->mProcedures[ccdec->mVarIndex]); + + InterInstruction* pcins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + pcins->mDst.mType = IT_POINTER; + pcins->mDst.mTemp = proc->AddTemporary(IT_POINTER); + pcins->mConst.mType = IT_POINTER; + pcins->mConst.mVarIndex = ccdec->mVarIndex; + pcins->mConst.mIntConst = 0; + pcins->mConst.mOperandSize = 2; + pcins->mConst.mMemory = IM_PROCEDURE; + pcins->mConst.mLinkerObject = ccdec->mLinkerObject; + block->Append(pcins); + + InterInstruction* cins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CALL); + if (ccdec->mFlags & DTF_NATIVE) + cins->mCode = IC_CALL_NATIVE; + else + cins->mCode = IC_CALL; + cins->mSrc[0] = pcins->mDst; + cins->mNumOperands = 1; + + block->Append(cins); + } + } + else + CopyStructSimple(proc, exp, block, inlineMapper, vl, vr); +} + +InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* procType, InterCodeProcedure* proc, InterCodeBasicBlock*& block, Expression* exp, DestructStack*& destack, const BranchTarget& breakBlock, const BranchTarget& continueBlock, InlineMapper* inlineMapper, ExValue* lrexp) { Declaration* dec; ExValue vl, vr; @@ -1054,20 +1678,112 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* case EX_SEQUENCE: case EX_LIST: - vr = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper); + case EX_COMMA: + if (exp->mLeft) + vr = TranslateExpression(procType, proc, block, exp->mLeft, destack, breakBlock, continueBlock, inlineMapper); exp = exp->mRight; if (!exp) return ExValue(TheVoidTypeDeclaration); break; + + case EX_CONSTRUCT: + { + if (exp->mLeft->mLeft) + TranslateExpression(procType, proc, block, exp->mLeft->mLeft, destack, breakBlock, continueBlock, inlineMapper, lrexp); + + if (exp->mLeft->mRight) + { + DestructStack* de = new DestructStack(); + de->mNext = destack; + de->mDestruct = exp->mLeft->mRight; + destack = de; + } + + exp = exp->mRight; + if (!exp) + return ExValue(TheVoidTypeDeclaration); + } + break; + + case EX_PACK: + case EX_PACK_TYPE: + mErrors->Error(exp->mLocation, EERR_INVALID_PACK_USAGE, "Invalid pack usage"); + return ExValue(TheVoidTypeDeclaration); + + case EX_RESULT: + { + if (lrexp) + return *lrexp; + + InterInstruction* ains = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + + if (inlineMapper) + { + if (inlineMapper->mResultExp) + { + ains->mDst.mTemp = inlineMapper->mResultExp->mTemp; + } + else + { + ains->mCode = IC_CONSTANT; + ains->mDst.mType = IT_POINTER; + ains->mDst.mTemp = proc->AddTemporary(IT_POINTER); + ains->mConst.mType = IT_POINTER; + ains->mConst.mOperandSize = procType->mBase->mSize; + ains->mConst.mIntConst = 0; + ains->mConst.mVarIndex = inlineMapper->mResult; + ains->mConst.mMemory = IM_LOCAL; + block->Append(ains); + } + } + else + { + InterInstruction* pins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + pins->mDst.mType = IT_POINTER; + pins->mDst.mTemp = proc->AddTemporary(IT_POINTER); + pins->mConst.mType = IT_POINTER; + pins->mConst.mVarIndex = 0; + pins->mConst.mIntConst = 0; + pins->mConst.mOperandSize = 2; + if (procType->mFlags & DTF_FASTCALL) + { + pins->mConst.mMemory = IM_FPARAM; + pins->mConst.mVarIndex += procType->mFastCallBase; + } + else + pins->mConst.mMemory = IM_PARAM; + block->Append(pins); + + ains->mCode = IC_LOAD; + ains->mSrc[0].mMemory = IM_INDIRECT; + ains->mSrc[0].mType = IT_POINTER; + ains->mSrc[0].mTemp = pins->mDst.mTemp; + ains->mDst.mType = IT_POINTER; + ains->mDst.mTemp = proc->AddTemporary(IT_POINTER); + ains->mNumOperands = 1; + block->Append(ains); + } + + return ExValue(exp->mDecType, ains->mDst.mTemp, 1); + } + case EX_CLEANUP: + { + vl = TranslateExpression(procType, proc, block, exp->mLeft, destack, breakBlock, continueBlock, inlineMapper); + TranslateExpression(procType, proc, block, exp->mRight, destack, breakBlock, continueBlock, inlineMapper); + return vl; + } + case EX_CONSTANT: dec = exp->mDecValue; switch (dec->mType) { case DT_CONST_INTEGER: { - InterInstruction * ins = new InterInstruction(exp->mLocation, IC_CONSTANT); + InterInstruction * ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); ins->mDst.mType = InterTypeOf(dec->mBase); ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType); + ins->mConst.mType = ins->mDst.mType; + if (ins->mDst.mType == IT_INT8) { if (dec->mBase->mFlags & DTF_SIGNED) @@ -1124,9 +1840,10 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* case DT_CONST_FLOAT: { - InterInstruction * ins = new InterInstruction(exp->mLocation, IC_CONSTANT); + InterInstruction * ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); ins->mDst.mType = InterTypeOf(dec->mBase); ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType); + ins->mConst.mType = ins->mDst.mType; ins->mConst.mFloatConst = dec->mNumber; block->Append(ins); return ExValue(dec->mBase, ins->mDst.mTemp); @@ -1135,9 +1852,10 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* case DT_CONST_ADDRESS: { - InterInstruction * ins = new InterInstruction(exp->mLocation, IC_CONSTANT); + InterInstruction * ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); ins->mDst.mType = IT_POINTER; ins->mDst.mTemp = proc->AddTemporary(IT_POINTER); + ins->mConst.mType = IT_POINTER; ins->mConst.mIntConst = dec->mInteger; ins->mConst.mMemory = IM_ABSOLUTE; block->Append(ins); @@ -1152,9 +1870,10 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* InterCodeProcedure* cproc = this->TranslateProcedure(proc->mModule, dec->mValue, dec); } - InterInstruction * ins = new InterInstruction(exp->mLocation, IC_CONSTANT); + InterInstruction * ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); ins->mDst.mType = InterTypeOf(dec->mBase); ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType); + ins->mConst.mType = ins->mDst.mType; ins->mConst.mVarIndex = dec->mVarIndex; ins->mConst.mLinkerObject = dec->mLinkerObject; ins->mConst.mMemory = IM_PROCEDURE; @@ -1169,9 +1888,10 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* if (!dec->mLinkerObject) TranslateAssembler(proc->mModule, dec->mValue, nullptr); - InterInstruction* ins = new InterInstruction(exp->mLocation, IC_CONSTANT); + InterInstruction* ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); ins->mDst.mType = IT_POINTER; ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType); + ins->mConst.mType = IT_POINTER; ins->mConst.mVarIndex = dec->mVarIndex; ins->mConst.mLinkerObject = dec->mLinkerObject; ins->mConst.mMemory = IM_PROCEDURE; @@ -1182,7 +1902,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* case DT_CONST_POINTER: { - vl = TranslateExpression(procType, proc, block, dec->mValue, breakBlock, continueBlock, inlineMapper); + vl = TranslateExpression(procType, proc, block, dec->mValue, destack, breakBlock, continueBlock, inlineMapper); vl.mReference--; vl.mType = exp->mDecType; return vl; @@ -1197,17 +1917,26 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* var->mIdent = dec->mQualIdent; var->mOffset = 0; var->mSize = dec->mSize; - if ((dec->mFlags & DTF_VAR_ALIASING) || dec->mBase->mType == DT_TYPE_ARRAY) - var->mAliased = true; var->mLinkerObject = mLinker->AddObject(dec->mLocation, dec->mQualIdent, dec->mSection, LOT_DATA, dec->mAlignment); - dec->mLinkerObject = var->mLinkerObject; + + if (dec->mBase->mFlags & DTF_CONST) + var->mLinkerObject->mFlags |= LOBJF_CONST; + else if ((dec->mFlags & DTF_VAR_ALIASING) || dec->mBase->mType == DT_TYPE_ARRAY) + var->mAliased = true; var->mLinkerObject->AddData(dec->mData, dec->mSize); + + LinkerObject* aobj = mLinker->FindSame(var->mLinkerObject); + if (aobj) + var->mLinkerObject = aobj; + + dec->mLinkerObject = var->mLinkerObject; proc->mModule->mGlobalVars.Push(var); } - InterInstruction * ins = new InterInstruction(exp->mLocation, IC_CONSTANT); + InterInstruction * ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); ins->mDst.mType = IT_POINTER; ins->mDst.mTemp = proc->AddTemporary(IT_POINTER); + ins->mConst.mType = IT_POINTER; ins->mConst.mIntConst = 0; ins->mConst.mVarIndex = dec->mVarIndex; assert(dec->mVarIndex >= 0); @@ -1238,9 +1967,10 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* BuildInitializer(proc->mModule, d, 0, dec, var); } - InterInstruction * ins = new InterInstruction(exp->mLocation, IC_CONSTANT); + InterInstruction * ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); ins->mDst.mType = IT_POINTER; ins->mDst.mTemp = proc->AddTemporary(IT_POINTER); + ins->mConst.mType = IT_POINTER; ins->mConst.mIntConst = 0; ins->mConst.mVarIndex = dec->mVarIndex; assert(dec->mVarIndex >= 0); @@ -1260,13 +1990,15 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* { dec = exp->mDecValue; - InterInstruction * ins = new InterInstruction(exp->mLocation, IC_CONSTANT); + InterInstruction * ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); ins->mDst.mType = IT_POINTER; ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType); ins->mConst.mType = IT_POINTER; ins->mConst.mOperandSize = dec->mSize; ins->mConst.mIntConst = dec->mOffset; + int lbits = dec->mBits, lshift = dec->mShift; + if (dec->mType == DT_VARIABLE_REF) dec = dec->mBase; @@ -1275,12 +2007,13 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* int ref = 1; if (dec->mType == DT_ARGUMENT) { - if (dec->mFlags & DTF_FPARAM_CONST) + if (dec->mFlags & DTF_FPARAM_UNUSED) { ins->mConst.mMemory = IM_LOCAL; if (inlineMapper) ins->mConst.mVarIndex += inlineMapper->mVarIndex; InitLocalVariable(proc, dec, ins->mConst.mVarIndex); + proc->mCheckUnreachable = false; } else if (inlineMapper) { @@ -1329,37 +2062,46 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* if (!(dec->mBase->mFlags & DTF_DEFINED)) mErrors->Error(dec->mLocation, EERR_VARIABLE_TYPE, "Undefined variable type"); - if (exp->mDecType->mType == DT_TYPE_REFERENCE) + if (exp->mDecType->IsReference()) return ExValue(exp->mDecType->mBase, ins->mDst.mTemp, ref + 1); else - return ExValue(exp->mDecType, ins->mDst.mTemp, ref); + return ExValue(exp->mDecType, ins->mDst.mTemp, ref, lbits, lshift); } case EX_ASSIGNMENT: case EX_INITIALIZATION: - { + { if (exp->mLeft->mDecType && exp->mLeft->mDecType->mType == DT_TYPE_STRUCT) { - vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper); - vr = TranslateExpression(procType, proc, block, exp->mRight, breakBlock, continueBlock, inlineMapper, &vl); + vl = TranslateExpression(procType, proc, block, exp->mLeft, destack, breakBlock, continueBlock, inlineMapper); + vr = TranslateExpression(procType, proc, block, exp->mRight, destack, breakBlock, continueBlock, inlineMapper, &vl); } - else if (exp->mType == EX_INITIALIZATION && exp->mLeft->mDecType && exp->mLeft->mDecType->mType == DT_TYPE_REFERENCE) + else if (exp->mType == EX_INITIALIZATION && exp->mLeft->mDecType && exp->mLeft->mDecType->IsReference()) { - vr = TranslateExpression(procType, proc, block, exp->mRight, breakBlock, continueBlock, inlineMapper); - vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper); + vr = TranslateExpression(procType, proc, block, exp->mRight, destack, breakBlock, continueBlock, inlineMapper); + vl = TranslateExpression(procType, proc, block, exp->mLeft, destack, breakBlock, continueBlock, inlineMapper); vl.mType = exp->mLeft->mDecType; } else { - vr = TranslateExpression(procType, proc, block, exp->mRight, breakBlock, continueBlock, inlineMapper); - vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper); + vr = TranslateExpression(procType, proc, block, exp->mRight, destack, breakBlock, continueBlock, inlineMapper); + vl = TranslateExpression(procType, proc, block, exp->mLeft, destack, breakBlock, continueBlock, inlineMapper); + } + + if (exp->mType == EX_ASSIGNMENT) + { + vl = ToValue(proc, exp, block, inlineMapper, vl); + vr = ToValue(proc, exp, block, inlineMapper, vr); } if (exp->mToken == TK_ASSIGN || !(vl.mType->mType == DT_TYPE_POINTER && vr.mType->IsIntegerType() && (exp->mToken == TK_ASSIGN_ADD || exp->mToken == TK_ASSIGN_SUB))) { if (!vl.mType->CanAssign(vr.mType)) - mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types"); + { + vl.mType->CanAssign(vr.mType); + mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types", vl.mType->MangleIdent(), vr.mType->MangleIdent()); + } } if (exp->mType != EX_INITIALIZATION && (vl.mType->mFlags & DTF_CONST)) @@ -1370,19 +2112,26 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* exp->mRight->mDecValue->mLinkerObject->mFlags |= LOBJF_CONST; } - if (vl.mType->mType == DT_TYPE_REFERENCE) + + if (vl.mType->IsReference()) { - vr = Dereference(proc, exp, block, vr, 1); - vl = Dereference(proc, exp, block, vl, 2); + if (vr.mType->IsReference()) + vr = Dereference(proc, exp, block, inlineMapper, vr, 0); + else + { + vr = Dereference(proc, exp, block, inlineMapper, vr, 1); + if (vr.mReference != 1) + mErrors->Error(exp->mLeft->mLocation, EERR_NOT_AN_LVALUE, "Not an addressable expression"); + } + + vl = Dereference(proc, exp, block, inlineMapper, vl, 2); if (vl.mReference != 2) mErrors->Error(exp->mLeft->mLocation, EERR_NOT_AN_LVALUE, "Not a left hand reference expression"); - if (vr.mReference != 1) - mErrors->Error(exp->mLeft->mLocation, EERR_NOT_AN_LVALUE, "Not an addressable expression"); if (vr.mTemp != vl.mTemp) { - InterInstruction* ins = new InterInstruction(exp->mLocation, IC_STORE); + InterInstruction* ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_STORE); ins->mSrc[0].mType = IT_POINTER; ins->mSrc[0].mTemp = vr.mTemp; ins->mSrc[0].mMemory = IM_INDIRECT; @@ -1394,14 +2143,17 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* ins->mSrc[1].mMemory = IM_INDIRECT; ins->mSrc[1].mOperandSize = 2; ins->mSrc[1].mStride = vl.mType->mStripe; + ins->mNumOperands = 2; block->Append(ins); } } else if (vl.mType->mType == DT_TYPE_STRUCT || vl.mType->mType == DT_TYPE_ARRAY || vl.mType->mType == DT_TYPE_UNION) { - vr = Dereference(proc, exp, block, vr, 1); - vl = Dereference(proc, exp, block, vl, 1); + vr = ToValue(proc, exp, block, inlineMapper, vr); + + vr = Dereference(proc, exp, block, inlineMapper, vr, 1); + vl = Dereference(proc, exp, block, inlineMapper, vl, 1); if (vl.mReference != 1) mErrors->Error(exp->mLeft->mLocation, EERR_NOT_AN_LVALUE, "Not a left hand expression"); @@ -1409,48 +2161,34 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* mErrors->Error(exp->mLeft->mLocation, EERR_NOT_AN_LVALUE, "Not an addressable expression"); if (vr.mTemp != vl.mTemp) - { - InterInstruction* ins = new InterInstruction(exp->mLocation, IC_COPY); - ins->mSrc[0].mType = IT_POINTER; - ins->mSrc[0].mTemp = vr.mTemp; - ins->mSrc[0].mMemory = IM_INDIRECT; - ins->mSrc[0].mOperandSize = vl.mType->mSize; - ins->mSrc[0].mStride = vr.mType->mStripe; - - ins->mSrc[1].mType = IT_POINTER; - ins->mSrc[1].mTemp = vl.mTemp; - ins->mSrc[1].mMemory = IM_INDIRECT; - ins->mSrc[1].mOperandSize = vl.mType->mSize; - ins->mSrc[1].mStride = vl.mType->mStripe; - ins->mConst.mOperandSize = vl.mType->mSize; - block->Append(ins); - } + CopyStructSimple(proc, exp, block, inlineMapper, vl, vr); } else { + vr = ToValue(proc, exp, block, inlineMapper, vr); + if (vl.mType->mType == DT_TYPE_POINTER && (vr.mType->mType == DT_TYPE_ARRAY || vr.mType->mType == DT_TYPE_FUNCTION)) { - vr = Dereference(proc, exp, block, vr, 1); + vr = Dereference(proc, exp, block, inlineMapper, vr, 1); vr.mReference = 0; vr.mType = vl.mType; } else - vr = Dereference(proc, exp, block, vr); + vr = Dereference(proc, exp, block, inlineMapper, vr); - vl = Dereference(proc, exp, block, vl, 1); + vl = Dereference(proc, exp, block, inlineMapper, vl, 1); if (vl.mReference != 1) mErrors->Error(exp->mLeft->mLocation, EERR_NOT_AN_LVALUE, "Not a left hand expression"); - InterInstruction * ins = new InterInstruction(exp->mLocation, IC_STORE); - if (exp->mToken != TK_ASSIGN) { - ExValue vll = Dereference(proc, exp, block, vl); + ExValue vll = Dereference(proc, exp, block, inlineMapper, vl); if (vl.mType->mType == DT_TYPE_POINTER) { - InterInstruction * cins = new InterInstruction(exp->mLocation, IC_CONSTANT); + InterInstruction * cins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + cins->mConst.mType = IT_INT16; if (exp->mToken == TK_ASSIGN_ADD) { @@ -1464,15 +2202,15 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Invalid pointer assignment"); if (!vr.mType->IsIntegerType()) - mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Invalid argument for pointer inc/dec"); + mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Invalid argument for pointer inc/dec", vr.mType->MangleIdent()); cins->mDst.mType = IT_INT16; cins->mDst.mTemp = proc->AddTemporary(cins->mDst.mType); block->Append(cins); - vr = CoerceType(proc, exp, block, vr, TheSignedIntTypeDeclaration); + vr = CoerceType(proc, exp, block, inlineMapper, vr, TheSignedIntTypeDeclaration); - InterInstruction * mins = new InterInstruction(exp->mLocation, IC_BINARY_OPERATOR); + InterInstruction * mins = new InterInstruction(MapLocation(exp, inlineMapper), IC_BINARY_OPERATOR); mins->mOperator = IA_MUL; mins->mSrc[0].mType = IT_INT16; mins->mSrc[0].mTemp = vr.mTemp; @@ -1482,7 +2220,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* mins->mDst.mTemp = proc->AddTemporary(mins->mDst.mType); block->Append(mins); - InterInstruction * ains = new InterInstruction(exp->mLocation, IC_LEA); + InterInstruction * ains = new InterInstruction(MapLocation(exp, inlineMapper), IC_LEA); ains->mSrc[1].mMemory = IM_INDIRECT; ains->mSrc[0].mType = IT_INT16; ains->mSrc[0].mTemp = mins->mDst.mTemp; @@ -1508,12 +2246,12 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* otype = TheSignedIntTypeDeclaration; else otype = TheUnsignedIntTypeDeclaration; - vll = CoerceType(proc, exp, block, vll, otype); + vll = CoerceType(proc, exp, block, inlineMapper, vll, otype); } - vr = CoerceType(proc, exp, block, vr, otype, exp->mToken != TK_ASSIGN_AND); + vr = CoerceType(proc, exp, block, inlineMapper, vr, otype, exp->mToken != TK_ASSIGN_AND); - InterInstruction * oins = new InterInstruction(exp->mLocation, IC_BINARY_OPERATOR); + InterInstruction * oins = new InterInstruction(MapLocation(exp, inlineMapper), IC_BINARY_OPERATOR); oins->mSrc[0].mType = InterTypeOf(otype); oins->mSrc[0].mTemp = vr.mTemp; oins->mSrc[1].mType = InterTypeOf(otype); @@ -1574,34 +2312,27 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* block->Append(oins); - vr = CoerceType(proc, exp, block, vr, vl.mType); + vr = CoerceType(proc, exp, block, inlineMapper, vr, vl.mType); } } else { - vr = CoerceType(proc, exp, block, vr, vl.mType); + vr = CoerceType(proc, exp, block, inlineMapper, vr, vl.mType); } - ins->mCode = IC_STORE; - ins->mSrc[1].mMemory = IM_INDIRECT; - ins->mSrc[0].mType = InterTypeOf(vr.mType); - ins->mSrc[0].mTemp = vr.mTemp; - ins->mSrc[1].mType = IT_POINTER; - ins->mSrc[1].mTemp = vl.mTemp; - ins->mSrc[1].mOperandSize = vl.mType->mSize; - ins->mSrc[1].mStride = vl.mType->mStripe; - ins->mVolatile = vl.mType->mFlags & DTF_VOLATILE; - ins->mNumOperands = 2; - block->Append(ins); + StoreValue(proc, exp, block, inlineMapper, vl, vr); } } - return vr; + return vl; case EX_INDEX: { - vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper); - vr = TranslateExpression(procType, proc, block, exp->mRight, breakBlock, continueBlock, inlineMapper); + vl = TranslateExpression(procType, proc, block, exp->mLeft, destack, breakBlock, continueBlock, inlineMapper); + vr = TranslateExpression(procType, proc, block, exp->mRight, destack, breakBlock, continueBlock, inlineMapper); + + vl = ToValue(proc, exp, block, inlineMapper, vl); + vr = ToValue(proc, exp, block, inlineMapper, vr); int stride = vl.mType->Stride(); @@ -1615,24 +2346,28 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* } } - vl = Dereference(proc, exp, block, vl, vl.mType->mType == DT_TYPE_POINTER ? 0 : 1); - vr = Dereference(proc, exp, block, vr); + vl = Dereference(proc, exp, block, inlineMapper, vl, vl.mType->mType == DT_TYPE_POINTER ? 0 : 1); + vr = Dereference(proc, exp, block, inlineMapper, vr); if (vl.mType->mType != DT_TYPE_ARRAY && vl.mType->mType != DT_TYPE_POINTER) + { mErrors->Error(exp->mLocation, EERR_INVALID_INDEX, "Invalid type for indexing"); + return ExValue(TheConstVoidTypeDeclaration, -1); + } if (!vr.mType->IsIntegerType()) mErrors->Error(exp->mLocation, EERR_INVALID_INDEX, "Index operand is not integral number"); - vr = CoerceType(proc, exp, block, vr, TheSignedIntTypeDeclaration); + vr = CoerceType(proc, exp, block, inlineMapper, vr, TheSignedIntTypeDeclaration); - InterInstruction * cins = new InterInstruction(exp->mLocation, IC_CONSTANT); + InterInstruction * cins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + cins->mConst.mType = IT_INT16; cins->mConst.mIntConst = stride; cins->mDst.mType = IT_INT16; cins->mDst.mTemp = proc->AddTemporary(cins->mDst.mType); block->Append(cins); - InterInstruction * mins = new InterInstruction(exp->mLocation, IC_BINARY_OPERATOR); + InterInstruction * mins = new InterInstruction(MapLocation(exp, inlineMapper), IC_BINARY_OPERATOR); mins->mOperator = IA_MUL; mins->mSrc[0].mType = IT_INT16; mins->mSrc[0].mTemp = vr.mTemp; @@ -1642,7 +2377,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* mins->mDst.mTemp = proc->AddTemporary(mins->mDst.mType); block->Append(mins); - InterInstruction * ains = new InterInstruction(exp->mLocation, IC_LEA); + InterInstruction * ains = new InterInstruction(MapLocation(exp, inlineMapper), IC_LEA); ains->mSrc[1].mMemory = IM_INDIRECT; ains->mSrc[0].mType = IT_INT16; ains->mSrc[0].mTemp = mins->mDst.mTemp; @@ -1657,19 +2392,23 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* case EX_QUALIFY: { - vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper); - vl = Dereference(proc, exp, block, vl, 1); + vl = TranslateExpression(procType, proc, block, exp->mLeft, destack, breakBlock, continueBlock, inlineMapper); + + vl = ToValue(proc, exp, block, inlineMapper, vl); + + vl = Dereference(proc, exp, block, inlineMapper, vl, 1); if (vl.mReference != 1) mErrors->Error(exp->mLocation, EERR_NOT_AN_LVALUE, "Not an addressable expression"); - InterInstruction * cins = new InterInstruction(exp->mLocation, IC_CONSTANT); + InterInstruction * cins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + cins->mConst.mType = IT_INT16; cins->mConst.mIntConst = exp->mDecValue->mOffset; cins->mDst.mType = IT_INT16; cins->mDst.mTemp = proc->AddTemporary(cins->mDst.mType); block->Append(cins); - InterInstruction * ains = new InterInstruction(exp->mLocation, IC_LEA); + InterInstruction * ains = new InterInstruction(MapLocation(exp, inlineMapper), IC_LEA); ains->mSrc[1].mMemory = IM_INDIRECT; ains->mSrc[0].mType = IT_INT16; ains->mSrc[0].mTemp = cins->mDst.mTemp; @@ -1679,24 +2418,31 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* ains->mDst.mTemp = proc->AddTemporary(ains->mDst.mType); block->Append(ains); - return ExValue(exp->mDecValue->mBase, ains->mDst.mTemp, 1); + if (exp->mDecType->IsReference()) + return ExValue(exp->mDecValue->mBase->mBase, ains->mDst.mTemp, 2); + else + return ExValue(exp->mDecValue->mBase, ains->mDst.mTemp, 1, exp->mDecValue->mBits, exp->mDecValue->mShift); } case EX_BINARY: { - vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper); - vr = TranslateExpression(procType, proc, block, exp->mRight, breakBlock, continueBlock, inlineMapper); - vr = Dereference(proc, exp, block, vr); + vl = TranslateExpression(procType, proc, block, exp->mLeft, destack, breakBlock, continueBlock, inlineMapper); + vr = TranslateExpression(procType, proc, block, exp->mRight, destack, breakBlock, continueBlock, inlineMapper); - InterInstruction * ins = new InterInstruction(exp->mLocation, IC_BINARY_OPERATOR); + vl = ToValue(proc, exp, block, inlineMapper, vl); + vr = ToValue(proc, exp, block, inlineMapper, vr); + + vr = Dereference(proc, exp, block, inlineMapper, vr); + + InterInstruction * ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_BINARY_OPERATOR); if (vl.mType->mType == DT_TYPE_POINTER || vl.mType->mType == DT_TYPE_ARRAY) { if (vl.mType->mType == DT_TYPE_POINTER) - vl = Dereference(proc, exp, block, vl); + vl = Dereference(proc, exp, block, inlineMapper, vl); else { - vl = Dereference(proc, exp, block, vl, 1); + vl = Dereference(proc, exp, block, inlineMapper, vl, 1); Declaration* ptype = new Declaration(exp->mLocation, DT_TYPE_POINTER); ptype->mBase = vl.mType->mBase; @@ -1707,7 +2453,8 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* if (vr.mType->IsIntegerType()) { - InterInstruction * cins = new InterInstruction(exp->mLocation, IC_CONSTANT); + InterInstruction * cins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + cins->mConst.mType = IT_INT16; if (exp->mToken == TK_ADD) { @@ -1724,9 +2471,9 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* cins->mDst.mTemp = proc->AddTemporary(cins->mDst.mType); block->Append(cins); - vr = CoerceType(proc, exp, block, vr, TheSignedIntTypeDeclaration); + vr = CoerceType(proc, exp, block, inlineMapper, vr, TheSignedIntTypeDeclaration); - InterInstruction * mins = new InterInstruction(exp->mLocation, IC_BINARY_OPERATOR); + InterInstruction * mins = new InterInstruction(MapLocation(exp, inlineMapper), IC_BINARY_OPERATOR); mins->mCode = IC_BINARY_OPERATOR; mins->mOperator = IA_MUL; mins->mSrc[0].mType = IT_INT16; @@ -1751,7 +2498,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* { if (exp->mToken == TK_SUB) { - InterInstruction * clins = new InterInstruction(exp->mLocation, IC_TYPECAST), * crins = new InterInstruction(exp->mLocation, IC_TYPECAST); + InterInstruction * clins = new InterInstruction(MapLocation(exp, inlineMapper), IC_TYPECAST), * crins = new InterInstruction(MapLocation(exp, inlineMapper), IC_TYPECAST); clins->mSrc[0].mTemp = vl.mTemp; clins->mSrc[0].mType = IT_POINTER; clins->mDst.mType = IT_INT16; @@ -1764,13 +2511,27 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* crins->mDst.mTemp = proc->AddTemporary(crins->mDst.mType); block->Append(crins); - InterInstruction * cins = new InterInstruction(exp->mLocation, IC_CONSTANT); - cins->mConst.mIntConst = vl.mType->Stride(); + int s = vl.mType->Stride(); + bool binary = !(s & (s - 1)); + if (binary) + { + int n = 0; + while (s > 1) + { + s >>= 1; + n++; + } + s = n; + } + + InterInstruction * cins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + cins->mConst.mType = IT_INT16; + cins->mConst.mIntConst = s; cins->mDst.mType = IT_INT16; cins->mDst.mTemp = proc->AddTemporary(cins->mDst.mType); block->Append(cins); - InterInstruction * sins = new InterInstruction(exp->mLocation, IC_BINARY_OPERATOR), * dins = new InterInstruction(exp->mLocation, IC_BINARY_OPERATOR); + InterInstruction * sins = new InterInstruction(MapLocation(exp, inlineMapper), IC_BINARY_OPERATOR), * dins = new InterInstruction(MapLocation(exp, inlineMapper), IC_BINARY_OPERATOR); sins->mOperator = IA_SUB; sins->mSrc[0].mType = IT_INT16; sins->mSrc[0].mTemp = crins->mDst.mTemp; @@ -1780,7 +2541,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* sins->mDst.mTemp = proc->AddTemporary(sins->mDst.mType); block->Append(sins); - dins->mOperator = IA_DIVS; + dins->mOperator = binary ? IA_SAR : IA_DIVS; dins->mSrc[0].mType = IT_INT16; dins->mSrc[0].mTemp = cins->mDst.mTemp; dins->mSrc[1].mType = IT_INT16; @@ -1800,10 +2561,10 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* else if (vr.mType->mType == DT_TYPE_POINTER || vr.mType->mType == DT_TYPE_ARRAY) { if (vr.mType->mType == DT_TYPE_POINTER) - vr = Dereference(proc, exp, block, vr); + vr = Dereference(proc, exp, block, inlineMapper, vr); else { - vr = Dereference(proc, exp, block, vr, 1); + vr = Dereference(proc, exp, block, inlineMapper, vr, 1); Declaration* ptype = new Declaration(exp->mLocation, DT_TYPE_POINTER); ptype->mBase = vr.mType->mBase; @@ -1813,7 +2574,8 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* if (vl.mType->IsIntegerType()) { - InterInstruction* cins = new InterInstruction(exp->mLocation, IC_CONSTANT); + InterInstruction* cins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + cins->mConst.mType = IT_INT16; if (exp->mToken == TK_ADD) { @@ -1826,9 +2588,9 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* cins->mDst.mTemp = proc->AddTemporary(cins->mDst.mType); block->Append(cins); - vl = CoerceType(proc, exp, block, vl, TheSignedIntTypeDeclaration); + vl = CoerceType(proc, exp, block, inlineMapper, vl, TheSignedIntTypeDeclaration); - InterInstruction* mins = new InterInstruction(exp->mLocation, IC_BINARY_OPERATOR); + InterInstruction* mins = new InterInstruction(MapLocation(exp, inlineMapper), IC_BINARY_OPERATOR); mins->mOperator = IA_MUL; mins->mSrc[0].mType = IT_INT16; mins->mSrc[0].mTemp = vl.mTemp; @@ -1855,7 +2617,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* } else { - vl = Dereference(proc, exp, block, vl); + vl = Dereference(proc, exp, block, inlineMapper, vl); if (!vl.mType->IsNumericType()) mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Left hand operand type is not numeric"); @@ -1926,8 +2688,8 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* dtype = TheUnsignedCharTypeDeclaration; } - vl = CoerceType(proc, exp, block, vl, dtype); - vr = CoerceType(proc, exp, block, vr, dtype); + vl = CoerceType(proc, exp, block, inlineMapper, vl, dtype); + vr = CoerceType(proc, exp, block, inlineMapper, vr, dtype); bool signedOP = dtype->mFlags & DTF_SIGNED; @@ -1981,8 +2743,9 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* case EX_PREINCDEC: { - vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper); - vl = Dereference(proc, exp, block, vl, 1); + vl = TranslateExpression(procType, proc, block, exp->mLeft, destack, breakBlock, continueBlock, inlineMapper); + vl = ToValue(proc, exp, block, inlineMapper, vl); + vl = Dereference(proc, exp, block, inlineMapper, vl, 1); if (vl.mReference != 1) mErrors->Error(exp->mLeft->mLocation, EERR_NOT_AN_LVALUE, "Not a left hand expression"); @@ -1990,18 +2753,23 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* if (vl.mType->mFlags & DTF_CONST) mErrors->Error(exp->mLocation, EERR_CONST_ASSIGN, "Cannot change const value"); - InterInstruction * cins = new InterInstruction(exp->mLocation, IC_CONSTANT), * ains = new InterInstruction(exp->mLocation, IC_BINARY_OPERATOR), * sins = new InterInstruction(exp->mLocation, IC_STORE); + InterInstruction* cins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT), * ains = new InterInstruction(MapLocation(exp, inlineMapper), IC_BINARY_OPERATOR);// , * sins = new InterInstruction(MapLocation(exp, inlineMapper), IC_STORE); - ExValue vdl = Dereference(proc, exp, block, vl); + ExValue vdl = Dereference(proc, exp, block, inlineMapper, vl); bool ftype = vl.mType->mType == DT_TYPE_FLOAT; cins->mDst.mType = ftype ? IT_FLOAT : IT_INT16; cins->mDst.mTemp = proc->AddTemporary(cins->mDst.mType); + cins->mConst.mType = cins->mDst.mType; + if (vdl.mType->mType == DT_TYPE_POINTER) cins->mConst.mIntConst = exp->mToken == TK_INC ? vdl.mType->Stride() : -(vdl.mType->Stride()); else if (vdl.mType->IsNumericType()) + { cins->mConst.mIntConst = exp->mToken == TK_INC ? 1 : -1; + cins->mConst.mFloatConst = double(cins->mConst.mIntConst); + } else mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Not a numeric value or pointer"); @@ -2026,6 +2794,8 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* ains->mDst.mTemp = proc->AddTemporary(ains->mDst.mType); block->Append(ains); + StoreValue(proc, exp, block, inlineMapper, vl, ExValue(vl.mType, ains->mDst.mTemp)); +#if 0 sins->mSrc[1].mMemory = IM_INDIRECT; sins->mSrc[0].mType = ains->mDst.mType; sins->mSrc[0].mTemp = ains->mDst.mTemp; @@ -2034,6 +2804,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* sins->mSrc[1].mOperandSize = vl.mType->mSize; sins->mVolatile = vl.mType->mFlags & DTF_VOLATILE; block->Append(sins); +#endif // Return reference to value return ExValue(vl.mType, vl.mTemp, 1); @@ -2042,8 +2813,9 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* case EX_POSTINCDEC: { - vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper); - vl = Dereference(proc, exp, block, vl, 1); + vl = TranslateExpression(procType, proc, block, exp->mLeft, destack, breakBlock, continueBlock, inlineMapper); + vl = ToValue(proc, exp, block, inlineMapper, vl); + vl = Dereference(proc, exp, block, inlineMapper, vl, 1); if (vl.mReference != 1) mErrors->Error(exp->mLeft->mLocation, EERR_NOT_AN_LVALUE, "Not a left hand expression"); @@ -2051,18 +2823,23 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* if (vl.mType->mFlags & DTF_CONST) mErrors->Error(exp->mLocation, EERR_CONST_ASSIGN, "Cannot change const value"); - InterInstruction * cins = new InterInstruction(exp->mLocation, IC_CONSTANT), * ains = new InterInstruction(exp->mLocation, IC_BINARY_OPERATOR), * sins = new InterInstruction(exp->mLocation, IC_STORE); + InterInstruction* cins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT), * ains = new InterInstruction(MapLocation(exp, inlineMapper), IC_BINARY_OPERATOR);// , * sins = new InterInstruction(MapLocation(exp, inlineMapper), IC_STORE); - ExValue vdl = Dereference(proc, exp, block, vl); + ExValue vdl = Dereference(proc, exp, block, inlineMapper, vl); bool ftype = vl.mType->mType == DT_TYPE_FLOAT; cins->mDst.mType = ftype ? IT_FLOAT : IT_INT16; cins->mDst.mTemp = proc->AddTemporary(cins->mDst.mType); + cins->mConst.mType = cins->mDst.mType; + if (vdl.mType->mType == DT_TYPE_POINTER) cins->mConst.mIntConst = exp->mToken == TK_INC ? vdl.mType->Stride() : -(vdl.mType->Stride()); else if (vdl.mType->IsNumericType()) + { cins->mConst.mIntConst = exp->mToken == TK_INC ? 1 : -1; + cins->mConst.mFloatConst = double(cins->mConst.mIntConst); + } else mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Not a numeric value or pointer"); block->Append(cins); @@ -2086,6 +2863,8 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* ains->mDst.mTemp = proc->AddTemporary(ttype); block->Append(ains); + StoreValue(proc, exp, block, inlineMapper, vl, ExValue(vl.mType, ains->mDst.mTemp)); +#if 0 sins->mSrc[1].mMemory = IM_INDIRECT; sins->mSrc[0].mType = ains->mDst.mType; sins->mSrc[0].mTemp = ains->mDst.mTemp; @@ -2094,50 +2873,53 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* sins->mSrc[1].mOperandSize = vl.mType->mSize; sins->mVolatile = vl.mType->mFlags & DTF_VOLATILE; block->Append(sins); - +#endif return ExValue(vdl.mType, vdl.mTemp); } break; case EX_PREFIX: { - vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper); + vl = TranslateExpression(procType, proc, block, exp->mLeft, destack, breakBlock, continueBlock, inlineMapper); + vl = ToValue(proc, exp, block, inlineMapper, vl); - InterInstruction * ins = new InterInstruction(exp->mLocation, IC_UNARY_OPERATOR); + InterInstruction * ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_UNARY_OPERATOR); switch (exp->mToken) { case TK_ADD: - vl = Dereference(proc, exp, block, vl); + vl = Dereference(proc, exp, block, inlineMapper, vl); ins->mOperator = IA_NONE; break; case TK_SUB: - vl = Dereference(proc, exp, block, vl); + vl = Dereference(proc, exp, block, inlineMapper, vl); if (!vl.mType->IsNumericType()) mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Not a numeric type"); else if (vl.mType->mType == DT_TYPE_INTEGER && vl.mType->mSize < 2) - vl = CoerceType(proc, exp, block, vl, TheSignedIntTypeDeclaration); + vl = CoerceType(proc, exp, block, inlineMapper, vl, TheSignedIntTypeDeclaration); ins->mOperator = IA_NEG; break; case TK_BINARY_NOT: - vl = Dereference(proc, exp, block, vl); + vl = Dereference(proc, exp, block, inlineMapper, vl); if (!(vl.mType->mType == DT_TYPE_POINTER || vl.mType->IsNumericType())) mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Not a numeric or pointer type"); else if (vl.mType->mType == DT_TYPE_INTEGER && vl.mType->mSize < 2) - vl = CoerceType(proc, exp, block, vl, TheUnsignedIntTypeDeclaration); + vl = CoerceType(proc, exp, block, inlineMapper, vl, TheUnsignedIntTypeDeclaration); ins->mOperator = IA_NOT; break; case TK_MUL: if (vl.mType->mType == DT_TYPE_ARRAY) - vl = Dereference(proc, exp, block, vl, 1); + vl = Dereference(proc, exp, block, inlineMapper, vl, 1); else if (vl.mType->mType != DT_TYPE_POINTER) mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Not a pointer type"); else if (vl.mType->mStride != 1) - vl = Dereference(proc, exp, block, vl, 0); - return ExValue(vl.mType->mBase, vl.mTemp, vl.mReference + 1); + vl = Dereference(proc, exp, block, inlineMapper, vl, 0); + else + return ExValue(vl.mType->mBase, vl.mTemp, vl.mReference + 1); + return ExValue(vl.mType->mBase, vl.mTemp, 1); case TK_BINARY_AND: { - if (vl.mReference < 1) + if (vl.mReference < 1 || vl.mBits) mErrors->Error(exp->mLocation, EERR_NOT_AN_LVALUE, "Not an addressable value"); Declaration* dec = new Declaration(exp->mLocation, DT_TYPE_POINTER); @@ -2168,6 +2950,31 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* } mErrors->Error(exp->mLocation, ERRR_CANNOT_FIND_BANK_OF_EXPRESSION, "Cannot find bank of expressiohn"); } break; + + case TK_NEW: + { + ins->mCode = IC_MALLOC; + ins->mSrc[0].mType = InterTypeOf(vl.mType); + ins->mSrc[0].mTemp = vl.mTemp; + ins->mDst.mType = IT_POINTER; + ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType); + ins->mDst.mRestricted = proc->AddRestricted(); + block->Append(ins); + return ExValue(exp->mDecType, ins->mDst.mTemp, 0); + + } break; + + case TK_DELETE: + { + vl = Dereference(proc, exp, block, inlineMapper, vl, 0); + + ins->mCode = IC_FREE; + ins->mSrc[0].mType = IT_POINTER; + ins->mSrc[0].mTemp = vl.mTemp; + block->Append(ins); + return ExValue(TheConstVoidTypeDeclaration, -1); + + } break; } ins->mSrc[0].mType = InterTypeOf(vl.mType); @@ -2182,26 +2989,39 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* case EX_RELATIONAL: { - vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper); - vl = Dereference(proc, exp, block, vl, vl.mType->mType == DT_TYPE_ARRAY ? 1 : 0); - vr = TranslateExpression(procType, proc, block, exp->mRight, breakBlock, continueBlock, inlineMapper); - vr = Dereference(proc, exp, block, vr, vr.mType->mType == DT_TYPE_ARRAY ? 1 : 0); + vl = TranslateExpression(procType, proc, block, exp->mLeft, destack, breakBlock, continueBlock, inlineMapper); + vl = ToValue(proc, exp, block, inlineMapper, vl); + vl = Dereference(proc, exp, block, inlineMapper, vl, vl.mType->mType == DT_TYPE_ARRAY ? 1 : 0); + vr = TranslateExpression(procType, proc, block, exp->mRight, destack, breakBlock, continueBlock, inlineMapper); + vr = ToValue(proc, exp, block, inlineMapper, vr); + vr = Dereference(proc, exp, block, inlineMapper, vr, vr.mType->mType == DT_TYPE_ARRAY ? 1 : 0); - InterInstruction * ins = new InterInstruction(exp->mLocation, IC_RELATIONAL_OPERATOR); + + InterInstruction * ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_RELATIONAL_OPERATOR); Declaration* dtype = TheSignedIntTypeDeclaration; if (vl.mType->mType == DT_TYPE_POINTER || vr.mType->mType == DT_TYPE_POINTER) { dtype = vl.mType; - if (vl.mType->IsIntegerType() || vr.mType->IsIntegerType()) - ; + if (vl.mType->IsIntegerType()) + { + if ((mCompilerOptions & COPT_CPLUSPLUS) || exp->mLeft->mType != EX_CONSTANT || exp->mLeft->mDecValue->mInteger != 0) + mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot compare integer and pointer"); + } + else if (vr.mType->IsIntegerType()) + { + if ((mCompilerOptions & COPT_CPLUSPLUS) || exp->mRight->mType != EX_CONSTANT || exp->mRight->mDecValue->mInteger != 0) + mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot compare integer and pointer"); + } else if ((vl.mType->mType == DT_TYPE_POINTER || vl.mType->mType == DT_TYPE_ARRAY) && (vr.mType->mType == DT_TYPE_POINTER || vr.mType->mType == DT_TYPE_ARRAY)) { if (vl.mType->mBase->mType == DT_TYPE_VOID || vr.mType->mBase->mType == DT_TYPE_VOID) ; + else if ((mCompilerOptions & COPT_CPLUSPLUS) && (vl.mType->mBase->IsSubType(vr.mType->mBase) || vr.mType->mBase->IsSubType(vl.mType->mBase))) + ; else if (!vl.mType->mBase->IsConstSame(vr.mType->mBase)) - mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Incompatible pointer types"); + mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Incompatible pointer types", vl.mType->mBase->MangleIdent(), vr.mType->mBase->MangleIdent()); } else mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Incompatible pointer types"); @@ -2239,8 +3059,8 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* dtype = TheUnsignedIntTypeDeclaration; } - vl = CoerceType(proc, exp, block, vl, dtype); - vr = CoerceType(proc, exp, block, vr, dtype); + vl = CoerceType(proc, exp, block, inlineMapper, vl, dtype); + vr = CoerceType(proc, exp, block, inlineMapper, vr, dtype); bool signedCompare = dtype->mFlags & DTF_SIGNED; @@ -2277,6 +3097,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* return ExValue(TheBoolTypeDeclaration, ins->mDst.mTemp); } + case EX_VCALL: case EX_CALL: case EX_INLINE: { @@ -2287,14 +3108,14 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* if (!strcmp(iname->mString, "fabs")) { - vr = TranslateExpression(procType, proc, block, exp->mRight, breakBlock, continueBlock, inlineMapper); - vr = Dereference(proc, exp, block, vr); + vr = TranslateExpression(procType, proc, block, exp->mRight, destack, breakBlock, continueBlock, inlineMapper); + vr = Dereference(proc, exp, block, inlineMapper, vr); if (decf->mBase->mParams->CanAssign(vr.mType)) mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types"); - vr = CoerceType(proc, exp, block, vr, decf->mBase->mParams); + vr = CoerceType(proc, exp, block, inlineMapper, vr, decf->mBase->mParams); - InterInstruction * ins = new InterInstruction(exp->mLocation, IC_UNARY_OPERATOR); + InterInstruction * ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_UNARY_OPERATOR); ins->mOperator = IA_ABS; ins->mSrc[0].mType = IT_FLOAT; ins->mSrc[0].mTemp = vr.mTemp; @@ -2306,14 +3127,14 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* } else if (!strcmp(iname->mString, "floor")) { - vr = TranslateExpression(procType, proc, block, exp->mRight, breakBlock, continueBlock, inlineMapper); - vr = Dereference(proc, exp, block, vr); + vr = TranslateExpression(procType, proc, block, exp->mRight, destack, breakBlock, continueBlock, inlineMapper); + vr = Dereference(proc, exp, block, inlineMapper, vr); if (decf->mBase->mParams->CanAssign(vr.mType)) mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types"); - vr = CoerceType(proc, exp, block, vr, decf->mBase->mParams); + vr = CoerceType(proc, exp, block, inlineMapper, vr, decf->mBase->mParams); - InterInstruction * ins = new InterInstruction(exp->mLocation, IC_UNARY_OPERATOR); + InterInstruction * ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_UNARY_OPERATOR); ins->mOperator = IA_FLOOR; ins->mSrc[0].mType = IT_FLOAT; ins->mSrc[0].mTemp = vr.mTemp; @@ -2325,14 +3146,14 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* } else if (!strcmp(iname->mString, "ceil")) { - vr = TranslateExpression(procType, proc, block, exp->mRight, breakBlock, continueBlock, inlineMapper); - vr = Dereference(proc, exp, block, vr); + vr = TranslateExpression(procType, proc, block, exp->mRight, destack, breakBlock, continueBlock, inlineMapper); + vr = Dereference(proc, exp, block, inlineMapper, vr); if (decf->mBase->mParams->CanAssign(vr.mType)) mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types"); - vr = CoerceType(proc, exp, block, vr, decf->mBase->mParams); + vr = CoerceType(proc, exp, block, inlineMapper, vr, decf->mBase->mParams); - InterInstruction * ins = new InterInstruction(exp->mLocation, IC_UNARY_OPERATOR); + InterInstruction * ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_UNARY_OPERATOR); ins->mOperator = IA_CEIL; ins->mSrc[0].mType = IT_FLOAT; ins->mSrc[0].mTemp = vr.mTemp; @@ -2342,6 +3163,49 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* return ExValue(TheFloatTypeDeclaration, ins->mDst.mTemp); } + else if (!strcmp(iname->mString, "sin")) + { + } + else if (!strcmp(iname->mString, "cos")) + { + } + else if (!strcmp(iname->mString, "malloc")) + { + vr = TranslateExpression(procType, proc, block, exp->mRight, destack, breakBlock, continueBlock, inlineMapper); + vr = Dereference(proc, exp, block, inlineMapper, vr); + + if (decf->mBase->mParams->CanAssign(vr.mType)) + mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types"); + vr = CoerceType(proc, exp, block, inlineMapper, vr, decf->mBase->mParams); + + InterInstruction* ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_MALLOC); + ins->mSrc[0].mType = IT_INT16; + ins->mSrc[0].mTemp = vr.mTemp; + ins->mNumOperands = 1; + ins->mDst.mType = IT_POINTER; + ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType); + ins->mDst.mRestricted = proc->AddRestricted(); + block->Append(ins); + + return ExValue(TheVoidPointerTypeDeclaration, ins->mDst.mTemp); + } + else if (!strcmp(iname->mString, "free")) + { + vr = TranslateExpression(procType, proc, block, exp->mRight, destack, breakBlock, continueBlock, inlineMapper); + vr = Dereference(proc, exp, block, inlineMapper, vr); + + if (decf->mBase->mParams->CanAssign(vr.mType)) + mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types"); + vr = CoerceType(proc, exp, block, inlineMapper, vr, decf->mBase->mParams); + + InterInstruction* ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_FREE); + ins->mSrc[0].mType = IT_POINTER; + ins->mSrc[0].mTemp = vr.mTemp; + ins->mNumOperands = 1; + block->Append(ins); + + return ExValue(TheVoidTypeDeclaration, 0); + } else if (!strcmp(iname->mString, "strcpy")) { if (exp->mRight->mType == EX_LIST) @@ -2350,24 +3214,26 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* if ((tex->mDecType->mType == DT_TYPE_ARRAY && tex->mDecType->mSize <= 256) || (sex->mDecType->mType == DT_TYPE_ARRAY && sex->mDecType->mSize <= 256)) { - vl = TranslateExpression(procType, proc, block, tex, breakBlock, continueBlock, inlineMapper); + vl = TranslateExpression(procType, proc, block, tex, destack, breakBlock, continueBlock, inlineMapper); if (vl.mType->mType == DT_TYPE_ARRAY) - vl = Dereference(proc, exp, block, vl, 1); + vl = Dereference(proc, exp, block, inlineMapper, vl, 1); else - vl = Dereference(proc, exp, block, vl); + vl = Dereference(proc, exp, block, inlineMapper, vl); - vr = TranslateExpression(procType, proc, block, sex, breakBlock, continueBlock, inlineMapper); + vr = TranslateExpression(procType, proc, block, sex, destack, breakBlock, continueBlock, inlineMapper); if (vr.mType->mType == DT_TYPE_ARRAY) - vr = Dereference(proc, exp, block, vr, 1); + vr = Dereference(proc, exp, block, inlineMapper, vr, 1); else - vr = Dereference(proc, exp, block, vr); + vr = Dereference(proc, exp, block, inlineMapper, vr); if (!TheCharPointerTypeDeclaration->CanAssign(vl.mType)) mErrors->Error(tex->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types"); if (!TheConstCharPointerTypeDeclaration->CanAssign(vr.mType)) mErrors->Error(sex->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types"); - InterInstruction* ins = new InterInstruction(exp->mLocation, IC_STRCPY); + InterInstruction* ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_STRCPY); + ins->mNumOperands = 2; + ins->mSrc[0].mType = IT_POINTER; ins->mSrc[0].mMemory = IM_INDIRECT; ins->mSrc[0].mTemp = vr.mTemp; @@ -2387,24 +3253,26 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* Expression* tex = exp->mRight->mLeft, * sex = exp->mRight->mRight->mLeft, * nex = exp->mRight->mRight->mRight; if (nex && nex->mType == EX_CONSTANT && nex->mDecValue->mType == DT_CONST_INTEGER && nex->mDecValue->mInteger < 512) { - vl = TranslateExpression(procType, proc, block, tex, breakBlock, continueBlock, inlineMapper); + vl = TranslateExpression(procType, proc, block, tex, destack, breakBlock, continueBlock, inlineMapper); if (vl.mType->mType == DT_TYPE_ARRAY) - vl = Dereference(proc, exp, block, vl, 1); + vl = Dereference(proc, exp, block, inlineMapper, vl, 1); else - vl = Dereference(proc, exp, block, vl); + vl = Dereference(proc, exp, block, inlineMapper, vl); - vr = TranslateExpression(procType, proc, block, sex, breakBlock, continueBlock, inlineMapper); + vr = TranslateExpression(procType, proc, block, sex, destack, breakBlock, continueBlock, inlineMapper); if (vr.mType->mType == DT_TYPE_ARRAY) - vr = Dereference(proc, exp, block, vr, 1); + vr = Dereference(proc, exp, block, inlineMapper, vr, 1); else - vr = Dereference(proc, exp, block, vr); + vr = Dereference(proc, exp, block, inlineMapper, vr); if (!TheVoidPointerTypeDeclaration->CanAssign(vl.mType)) mErrors->Error(tex->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types"); if (!TheConstVoidPointerTypeDeclaration->CanAssign(vr.mType)) mErrors->Error(sex->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types"); - InterInstruction* ins = new InterInstruction(exp->mLocation, IC_COPY); + InterInstruction* ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_COPY); + ins->mNumOperands = 2; + ins->mSrc[0].mType = IT_POINTER; ins->mSrc[0].mMemory = IM_INDIRECT; ins->mSrc[0].mTemp = vr.mTemp; @@ -2430,7 +3298,8 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* bool canInline = exp->mLeft->mType == EX_CONSTANT && exp->mLeft->mDecValue->mType == DT_CONST_FUNCTION && (mCompilerOptions & COPT_OPTIMIZE_INLINE) && - !(inlineMapper && inlineMapper->mDepth > 10); + !(inlineMapper && inlineMapper->mDepth > 10) && + exp->mType != EX_VCALL; bool doInline = false, inlineConstexpr = false; if (canInline) @@ -2474,12 +3343,15 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* if (doInline) { - return TranslateInline(procType, proc, block, exp, breakBlock, continueBlock, inlineMapper, inlineConstexpr); + return TranslateInline(procType, proc, block, exp, breakBlock, continueBlock, inlineMapper, inlineConstexpr, lrexp); } else { - vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper); - vl = Dereference(proc, exp, block, vl); + Expression * funcexp = exp->mLeft; + + vl = TranslateExpression(procType, proc, block, funcexp, destack, breakBlock, continueBlock, inlineMapper); + + vl = Dereference(proc, exp, block, inlineMapper, vl); int atotal = 0; @@ -2497,12 +3369,14 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* } else { - fins = new InterInstruction(exp->mLocation, IC_PUSH_FRAME); + fins = new InterInstruction(MapLocation(exp, inlineMapper), IC_PUSH_FRAME); + fins->mNumOperands = 0; fins->mConst.mIntConst = atotal; block->Append(fins); } Declaration * decResult = nullptr; + GrowingArray defins(nullptr); if (ftype->mBase->mType == DT_TYPE_STRUCT) { @@ -2525,9 +3399,10 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* decResult = vdec; - InterInstruction* vins = new InterInstruction(exp->mLocation, IC_CONSTANT); + InterInstruction* vins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); vins->mDst.mType = IT_POINTER; vins->mDst.mTemp = proc->AddTemporary(IT_POINTER); + vins->mConst.mType = IT_POINTER; vins->mConst.mMemory = IM_LOCAL; vins->mConst.mVarIndex = nindex; vins->mConst.mOperandSize = ftype->mBase->mSize; @@ -2536,9 +3411,10 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* ttemp = vins->mDst.mTemp; } - InterInstruction* ains = new InterInstruction(exp->mLocation, IC_CONSTANT); + InterInstruction* ains = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); ains->mDst.mType = IT_POINTER; ains->mDst.mTemp = proc->AddTemporary(IT_POINTER); + ains->mConst.mType = IT_POINTER; ains->mConst.mVarIndex = 0; ains->mConst.mIntConst = 0; ains->mConst.mOperandSize = 2; @@ -2551,30 +3427,34 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* ains->mConst.mMemory = IM_FRAME; block->Append(ains); - InterInstruction* wins = new InterInstruction(exp->mLocation, IC_STORE); + InterInstruction* wins = new InterInstruction(MapLocation(exp, inlineMapper), IC_STORE); wins->mSrc[1].mMemory = IM_INDIRECT; wins->mSrc[0].mType = IT_POINTER; wins->mSrc[0].mTemp = ttemp; wins->mSrc[1].mType = IT_POINTER; wins->mSrc[1].mTemp = ains->mDst.mTemp; wins->mSrc[1].mOperandSize = 2; - block->Append(wins); + + if (ftype->mFlags & DTF_FASTCALL) + defins.Push(wins); + else + block->Append(wins); atotal = 2; } - if (exp->mLeft->mDecValue && exp->mLeft->mDecValue->mType == DT_CONST_FUNCTION) - proc->AddCalledFunction(proc->mModule->mProcedures[exp->mLeft->mDecValue->mVarIndex]); + if (funcexp->mDecValue && funcexp->mDecValue->mType == DT_CONST_FUNCTION) + proc->AddCalledFunction(proc->mModule->mProcedures[funcexp->mDecValue->mVarIndex]); else proc->CallsFunctionPointer(); - GrowingArray defins(nullptr); - Declaration* pdec = ftype->mParams; Expression* pex = exp->mRight; while (pex) { - InterInstruction * ains = new InterInstruction(exp->mLocation, IC_CONSTANT); + InterInstruction * ains = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + ains->mConst.mType = IT_POINTER; + ains->mDst.mType = IT_POINTER; ains->mDst.mTemp = proc->AddTemporary(ains->mDst.mType); if (pdec) @@ -2621,22 +3501,54 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* pex = nullptr; } - ExValue vp(pdec ? pdec->mBase : TheSignedIntTypeDeclaration, ains->mDst.mTemp, 1); + Declaration* ptype = pdec ? pdec->mBase : texp->mDecType; - vr = TranslateExpression(procType, proc, block, texp, breakBlock, continueBlock, inlineMapper, &vp); - - if (!(pdec && pdec->mBase->mType == DT_TYPE_REFERENCE) && (vr.mType->mType == DT_TYPE_STRUCT || vr.mType->mType == DT_TYPE_UNION)) + ExValue vp(ptype ? ptype : TheSignedIntTypeDeclaration, ains->mDst.mTemp, 1); + + if (pdec && pdec->mBase->IsReference() && texp->mType == EX_CALL && !texp->mDecType->IsReference()) + { + mErrors->Error(texp->mLocation, EERR_MISSING_TEMP, "Missing temporary variable"); +#if 0 + int nindex = proc->mNumLocals++; + + Declaration* vdec = new Declaration(exp->mLocation, DT_VARIABLE); + + vdec->mVarIndex = nindex; + vdec->mBase = pdec->mBase->mBase; + vdec->mSize = pdec->mBase->mBase->mSize; + + InterInstruction* vins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + vins->mDst.mType = IT_POINTER; + vins->mDst.mTemp = proc->AddTemporary(IT_POINTER); + vins->mConst.mMemory = IM_LOCAL; + vins->mConst.mVarIndex = nindex; + vins->mConst.mOperandSize = vdec->mSize; + block->Append(vins); + + vp.mType = pdec->mBase->mBase; + vp.mTemp = vins->mDst.mTemp; +#endif + } + + if (ptype && (ptype->mType == DT_TYPE_STRUCT || ptype->mType == DT_TYPE_UNION)) + vr = TranslateExpression(procType, proc, block, texp, destack, breakBlock, continueBlock, inlineMapper, &vp); + else + vr = TranslateExpression(procType, proc, block, texp, destack, breakBlock, continueBlock, inlineMapper, nullptr); + + if (!(pdec && pdec->mBase->IsReference()) && (vr.mType->mType == DT_TYPE_STRUCT || vr.mType->mType == DT_TYPE_UNION)) { if (pdec && !pdec->mBase->CanAssign(vr.mType)) - mErrors->Error(texp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types"); + mErrors->Error(texp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types", pdec->mBase->MangleIdent(), vr.mType->MangleIdent()); - vr = Dereference(proc, texp, block, vr, 1); + vr = Dereference(proc, texp, block, inlineMapper, vr, 1); if (vr.mReference != 1) mErrors->Error(exp->mLeft->mLocation, EERR_NOT_AN_LVALUE, "Not an addressable expression"); if (vp.mTemp != vr.mTemp) { + CopyStruct(proc, exp, block, vp, vr, inlineMapper, false); +#if 0 InterInstruction* cins = new InterInstruction(texp->mLocation, IC_COPY); cins->mSrc[0].mType = IT_POINTER; cins->mSrc[0].mTemp = vr.mTemp; @@ -2651,33 +3563,43 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* cins->mConst.mOperandSize = vp.mType->mSize; block->Append(cins); +#endif } atotal += vr.mType->mSize; } else { - if (vr.mType->mType == DT_TYPE_ARRAY || vr.mType->mType == DT_TYPE_FUNCTION) - vr = Dereference(proc, texp, block, vr, 1); + if (vr.mType->mType == DT_TYPE_ARRAY)// || vr.mType->mType == DT_TYPE_FUNCTION) + vr = Dereference(proc, texp, block, inlineMapper, vr, 1); else if (pdec && pdec->mBase->mType == DT_TYPE_POINTER && vr.mType->mType == DT_TYPE_INTEGER && texp->mType == EX_CONSTANT && texp->mDecValue->mType == DT_CONST_INTEGER && texp->mDecValue->mInteger == 0) - vr = CoerceType(proc, texp, block, vr, pdec->mBase); - else if (pdec && pdec->mBase->mType == DT_TYPE_REFERENCE) - vr = Dereference(proc, texp, block, vr, 1); + { + mErrors->Error(texp->mLocation, EWARN_NUMERIC_0_USED_AS_NULLPTR, "Numeric 0 used for nullptr"); + vr = CoerceType(proc, texp, block, inlineMapper, vr, pdec->mBase); + } + else if (pdec && (pdec->mBase->IsReference() && !vr.mType->IsReference())) + vr = Dereference(proc, texp, block, inlineMapper, vr, 1); + else if (vr.mType->IsReference() && !(pdec && pdec->mBase->IsReference())) + { + vr.mReference++; + vr = Dereference(proc, texp, block, inlineMapper, vr); + vr.mType = vr.mType->mBase; + } else - vr = Dereference(proc, texp, block, vr); + vr = Dereference(proc, texp, block, inlineMapper, vr); if (pdec) { - if (!pdec->mBase->CanAssign(vr.mType)) + if (!(pdec->mFlags & DTF_FPARAM_UNUSED) && !pdec->mBase->CanAssign(vr.mType)) { pdec->mBase->CanAssign(vr.mType); - mErrors->Error(texp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types"); + mErrors->Error(texp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types", pdec->mBase->MangleIdent(), vr.mType->MangleIdent()); } - vr = CoerceType(proc, texp, block, vr, pdec->mBase); + vr = CoerceType(proc, texp, block, inlineMapper, vr, pdec->mBase); } else if (vr.mType->IsIntegerType() && vr.mType->mSize < 2) { - vr = CoerceType(proc, texp, block, vr, TheSignedIntTypeDeclaration); + vr = CoerceType(proc, texp, block, inlineMapper, vr, TheSignedIntTypeDeclaration); } @@ -2689,7 +3611,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* wins->mSrc[1].mTemp = ains->mDst.mTemp; if (pdec) { - if (pdec->mBase->mType == DT_TYPE_ARRAY || pdec->mBase->mType == DT_TYPE_REFERENCE) + if (pdec->mBase->mType == DT_TYPE_ARRAY || pdec->mBase->mType == DT_TYPE_REFERENCE || pdec->mBase->mType == DT_TYPE_RVALUEREF || pdec->mBase->mType == DT_TYPE_FUNCTION) { wins->mSrc[1].mOperandSize = 2; wins->mSrc[0].mType = IT_POINTER; @@ -2702,7 +3624,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* else wins->mSrc[1].mOperandSize = 2; - if (!pdec || !(pdec->mFlags & DTF_FPARAM_CONST)) + if (!pdec || !(pdec->mFlags & DTF_FPARAM_UNUSED)) { if (ftype->mFlags & DTF_FASTCALL) defins.Push(wins); @@ -2723,16 +3645,17 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* for (int i = 0; i < defins.Size(); i++) block->Append(defins[i]); - InterInstruction * cins = new InterInstruction(exp->mLocation, IC_CALL); - if (exp->mLeft->mDecValue && (exp->mLeft->mDecValue->mFlags & DTF_NATIVE)) + InterInstruction * cins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CALL); + cins->mNumOperands = 1; + if (funcexp->mDecValue && (funcexp->mDecValue->mFlags & DTF_NATIVE) || (mCompilerOptions & COPT_NATIVE)) cins->mCode = IC_CALL_NATIVE; else cins->mCode = IC_CALL; - if (exp->mLeft->mDecValue && (exp->mLeft->mDecValue->mFlags & DTF_FUNC_PURE)) + if (funcexp->mDecValue && (funcexp->mDecValue->mFlags & DTF_FUNC_PURE)) cins->mNoSideEffects = true; - if (exp->mLeft->mType == EX_CONSTANT && (exp->mLeft->mDecValue->mFlags & DTF_FUNC_CONSTEXPR)) + if (funcexp->mType == EX_CONSTANT && (funcexp->mDecValue->mFlags & DTF_FUNC_CONSTEXPR)) cins->mConstExpr = true; cins->mSrc[0].mType = IT_POINTER; @@ -2754,7 +3677,8 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* { fins->mConst.mIntConst = atotal; - InterInstruction* xins = new InterInstruction(exp->mLocation, IC_POP_FRAME); + InterInstruction* xins = new InterInstruction(MapLocation(exp, inlineMapper), IC_POP_FRAME); + xins->mNumOperands = 0; xins->mConst.mIntConst = atotal; block->Append(xins); } @@ -2764,16 +3688,17 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* if (lrexp) return *lrexp; - InterInstruction* vins = new InterInstruction(exp->mLocation, IC_CONSTANT); + InterInstruction* vins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); vins->mDst.mType = IT_POINTER; vins->mDst.mTemp = proc->AddTemporary(IT_POINTER); + vins->mConst.mType = IT_POINTER; vins->mConst.mMemory = IM_LOCAL; vins->mConst.mVarIndex = decResult->mVarIndex; block->Append(vins); return ExValue(ftype->mBase, vins->mDst.mTemp, 1); } - else if (ftype->mBase->mType == DT_TYPE_REFERENCE) + else if (ftype->mBase->IsReference()) return ExValue(ftype->mBase->mBase, cins->mDst.mTemp, 1); else return ExValue(ftype->mBase, cins->mDst.mTemp); @@ -2793,9 +3718,10 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* { dec->mLinkerObject->mFlags |= LOBJF_INLINE; - InterInstruction* ins = new InterInstruction(exp->mLocation, IC_CONSTANT); + InterInstruction* ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); ins->mDst.mType = IT_POINTER; ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType); + ins->mConst.mType = IT_POINTER; ins->mConst.mOperandSize = dec->mSize; ins->mConst.mIntConst = 0; ins->mConst.mMemory = IM_GLOBAL; @@ -2803,7 +3729,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* ins->mConst.mVarIndex = dec->mVarIndex; block->Append(ins); - InterInstruction * jins = new InterInstruction(exp->mLocation, IC_ASSEMBLER); + InterInstruction * jins = new InterInstruction(MapLocation(exp, inlineMapper), IC_ASSEMBLER); jins->mDst.mTemp = proc->AddTemporary(IT_INT32); jins->mDst.mType = IT_INT32; @@ -2813,7 +3739,9 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* for (int i = 0; i < refvars.Size(); i++) { - InterInstruction* vins = new InterInstruction(exp->mLocation, IC_CONSTANT); + InterInstruction* vins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + vins->mConst.mType = IT_POINTER; + vins->mDst.mType = IT_POINTER; vins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType); @@ -2821,7 +3749,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* if (vdec->mType == DT_ARGUMENT) { vins->mConst.mVarIndex = vdec->mVarIndex; - if (vdec->mFlags & DTF_FPARAM_CONST) + if (vdec->mFlags & DTF_FPARAM_UNUSED) { vins->mConst.mMemory = IM_LOCAL; if (inlineMapper) @@ -2852,7 +3780,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* block->Append(vins); - InterInstruction* lins = new InterInstruction(exp->mLocation, IC_LOAD); + InterInstruction* lins = new InterInstruction(MapLocation(exp, inlineMapper), IC_LOAD); lins->mSrc[0].mMemory = IM_INDIRECT; lins->mSrc[0].mType = IT_POINTER; lins->mSrc[0].mTemp = vins->mDst.mTemp; @@ -2876,16 +3804,25 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* case EX_RETURN: { - InterInstruction * ins = new InterInstruction(exp->mLocation, IC_RETURN); + InterInstruction * ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_RETURN); if (exp->mLeft) { - vr = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper); - - if (procType->mBase->mType == DT_TYPE_REFERENCE) + if (procType->mBase->IsReference()) { - vr = Dereference(proc, exp, block, vr, 1); + vr = TranslateExpression(procType, proc, block, exp->mLeft, destack, breakBlock, continueBlock, inlineMapper); - vr = CoerceType(proc, exp, block, vr, procType->mBase); + if (vr.mType->IsReference()) + { + vr.mReference++; + vr.mType = vr.mType->mBase; + } + + vr = Dereference(proc, exp, block, inlineMapper, vr, 1); + + vr = CoerceType(proc, exp, block, inlineMapper, vr, procType->mBase); + + if (vr.mReference == 0) + mErrors->Error(exp->mLocation, EERR_INVALID_VALUE, "Returning value as reference"); ins->mSrc[0].mType = IT_POINTER; ins->mSrc[0].mTemp = vr.mTemp; @@ -2893,21 +3830,44 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* if (inlineMapper) { - InterInstruction* ains = new InterInstruction(exp->mLocation, IC_CONSTANT); - ains->mDst.mType = IT_POINTER; - ains->mDst.mTemp = proc->AddTemporary(ins->mDst.mType); - ains->mConst.mOperandSize = procType->mBase->mSize; - ains->mConst.mIntConst = 0; - ains->mConst.mVarIndex = inlineMapper->mResult;; - ains->mConst.mMemory = IM_LOCAL; - block->Append(ains); + if (inlineMapper->mResultExp) + { + if (inlineMapper->mResultExp->mType->IsReference()) + { + ins->mSrc[1].mType = IT_POINTER; + ins->mSrc[1].mTemp = inlineMapper->mResultExp->mTemp; + ins->mSrc[1].mMemory = IM_INDIRECT; + ins->mCode = IC_STORE; + ins->mSrc[1].mOperandSize = 2; + ins->mNumOperands = 2; + } + else + { + //bool moving = exp->mLeft->IsRValue() || exp->mLeft->mType == EX_VARIABLE && !(exp->mLeft->mDecValue->mFlags & (DTF_STATIC | DTF_GLOBAL)) && exp->mLeft->mDecType->mType != DT_TYPE_REFERENCE; - ins->mSrc[1].mType = ains->mDst.mType; - ins->mSrc[1].mTemp = ains->mDst.mTemp; - ins->mSrc[1].mMemory = IM_INDIRECT; - ins->mCode = IC_STORE; - ins->mSrc[1].mOperandSize = ains->mConst.mOperandSize; - ins->mNumOperands = 2; + CopyStruct(proc, exp, block, *(inlineMapper->mResultExp), vr, inlineMapper, false); + ins->mCode = IC_NONE; + } + } + else + { + InterInstruction* ains = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + ains->mDst.mType = IT_POINTER; + ains->mDst.mTemp = proc->AddTemporary(ains->mDst.mType); + ains->mConst.mType = IT_POINTER; + ains->mConst.mOperandSize = procType->mBase->mSize; + ains->mConst.mIntConst = 0; + ains->mConst.mVarIndex = inlineMapper->mResult;; + ains->mConst.mMemory = IM_LOCAL; + block->Append(ains); + + ins->mSrc[1].mType = ains->mDst.mType; + ins->mSrc[1].mTemp = ains->mDst.mTemp; + ins->mSrc[1].mMemory = IM_INDIRECT; + ins->mCode = IC_STORE; + ins->mSrc[1].mOperandSize = ains->mConst.mOperandSize; + ins->mNumOperands = 2; + } } else { @@ -2917,35 +3877,36 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* } else if (procType->mBase->mType == DT_TYPE_STRUCT) { - vr = Dereference(proc, exp, block, vr, 1); - if (!procType->mBase || procType->mBase->mType == DT_TYPE_VOID) - mErrors->Error(exp->mLocation, EERR_INVALID_RETURN, "Function has void return type"); - else if (!procType->mBase->CanAssign(vr.mType)) - mErrors->Error(exp->mLocation, EERR_INVALID_RETURN, "Cannot return incompatible type"); - else if (vr.mReference != 1) - mErrors->Error(exp->mLocation, EERR_INVALID_RETURN, "Non addressable object"); - - InterInstruction* ains = new InterInstruction(exp->mLocation, IC_CONSTANT); + InterInstruction* ains = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); if (inlineMapper) { - ains->mCode = IC_CONSTANT; - ains->mDst.mType = IT_POINTER; - ains->mDst.mTemp = proc->AddTemporary(IT_POINTER); - ains->mConst.mOperandSize = procType->mBase->mSize; - ains->mConst.mIntConst = 0; - ains->mConst.mVarIndex = inlineMapper->mResult; - ains->mConst.mMemory = IM_LOCAL; - block->Append(ains); + if (inlineMapper->mResultExp) + { + ains->mDst.mTemp = inlineMapper->mResultExp->mTemp; + } + else + { + ains->mCode = IC_CONSTANT; + ains->mDst.mType = IT_POINTER; + ains->mDst.mTemp = proc->AddTemporary(IT_POINTER); + ains->mConst.mType = IT_POINTER; + ains->mConst.mOperandSize = procType->mBase->mSize; + ains->mConst.mIntConst = 0; + ains->mConst.mVarIndex = inlineMapper->mResult; + ains->mConst.mMemory = IM_LOCAL; + block->Append(ains); + } ins->mCode = IC_NONE; } else { - InterInstruction* pins = new InterInstruction(exp->mLocation, IC_CONSTANT); + InterInstruction* pins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); pins->mDst.mType = IT_POINTER; pins->mDst.mTemp = proc->AddTemporary(IT_POINTER); + pins->mConst.mType = IT_POINTER; pins->mConst.mVarIndex = 0; pins->mConst.mIntConst = 0; pins->mConst.mOperandSize = 2; @@ -2970,52 +3931,173 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* ins->mCode = IC_RETURN; } - InterInstruction* cins = new InterInstruction(exp->mLocation, IC_COPY); - cins->mSrc[0].mType = IT_POINTER; - cins->mSrc[0].mTemp = vr.mTemp; - cins->mSrc[0].mMemory = IM_INDIRECT; - cins->mSrc[0].mOperandSize = procType->mBase->mSize; - cins->mSrc[0].mStride = vr.mType->mStripe; + ExValue rvr(procType->mBase, ains->mDst.mTemp, 1); - cins->mSrc[1].mOperandSize = procType->mBase->mSize; - cins->mSrc[1].mType = IT_POINTER; - cins->mSrc[1].mTemp = ains->mDst.mTemp; - cins->mSrc[1].mMemory = IM_INDIRECT; + vr = TranslateExpression(procType, proc, block, exp->mLeft, destack, breakBlock, continueBlock, inlineMapper, &rvr); - cins->mConst.mOperandSize = procType->mBase->mSize; - block->Append(cins); - } - else - { - vr = Dereference(proc, exp, block, vr); + vr = Dereference(proc, exp, block, inlineMapper, vr, 1); if (!procType->mBase || procType->mBase->mType == DT_TYPE_VOID) mErrors->Error(exp->mLocation, EERR_INVALID_RETURN, "Function has void return type"); else if (!procType->mBase->CanAssign(vr.mType)) mErrors->Error(exp->mLocation, EERR_INVALID_RETURN, "Cannot return incompatible type"); + else if (vr.mReference != 1) + mErrors->Error(exp->mLocation, EERR_INVALID_RETURN, "Non addressable object"); - vr = CoerceType(proc, exp, block, vr, procType->mBase); + bool moving = exp->mLeft->IsRValue() || exp->mLeft->mType == EX_VARIABLE && !(exp->mLeft->mDecValue->mFlags & (DTF_STATIC | DTF_GLOBAL)) && exp->mLeft->mDecType->mType != DT_TYPE_REFERENCE; + + CopyStruct(proc, exp, block, rvr, vr, inlineMapper, moving); +#if 0 + if (procType->mBase->mCopyConstructor) + { + Declaration* ccdec = procType->mBase->mCopyConstructor; + if (ccdec->mBase->mFlags & DTF_FASTCALL) + { + if (!ccdec->mLinkerObject) + this->TranslateProcedure(proc->mModule, ccdec->mValue, ccdec); + + InterInstruction* psins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + psins->mDst.mType = IT_POINTER; + psins->mDst.mTemp = proc->AddTemporary(IT_POINTER); + psins->mConst.mVarIndex = 0; + psins->mConst.mIntConst = 0; + psins->mConst.mOperandSize = 2; + if (procType->mFlags & DTF_FASTCALL) + { + psins->mConst.mMemory = IM_FPARAM; + psins->mConst.mVarIndex += ccdec->mBase->mFastCallBase; + } + else + psins->mConst.mMemory = IM_PARAM; + block->Append(psins); + + InterInstruction* ssins = new InterInstruction(MapLocation(exp, inlineMapper), IC_STORE); + ssins->mSrc[0] = ains->mDst; + ssins->mSrc[1] = psins->mDst; + block->Append(ssins); + + InterInstruction* plins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + plins->mDst.mType = IT_POINTER; + plins->mDst.mTemp = proc->AddTemporary(IT_POINTER); + plins->mConst.mVarIndex = 2; + plins->mConst.mIntConst = 0; + plins->mConst.mOperandSize = 2; + if (procType->mFlags & DTF_FASTCALL) + { + plins->mConst.mMemory = IM_FPARAM; + plins->mConst.mVarIndex += ccdec->mBase->mFastCallBase; + } + else + plins->mConst.mMemory = IM_PARAM; + block->Append(plins); + + InterInstruction* slins = new InterInstruction(MapLocation(exp, inlineMapper), IC_STORE); + slins->mSrc[0].mType = IT_POINTER; + slins->mSrc[0].mTemp = vr.mTemp; + slins->mSrc[0].mMemory = IM_INDIRECT; + slins->mSrc[0].mOperandSize = procType->mBase->mSize; + slins->mSrc[0].mStride = vr.mType->mStripe; + slins->mSrc[1] = plins->mDst; + block->Append(slins); + + proc->AddCalledFunction(proc->mModule->mProcedures[ccdec->mVarIndex]); + + InterInstruction* pcins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + pcins->mDst.mType = IT_POINTER; + pcins->mDst.mTemp = proc->AddTemporary(IT_POINTER); + pcins->mConst.mType = IT_POINTER; + pcins->mConst.mVarIndex = ccdec->mVarIndex; + pcins->mConst.mIntConst = 0; + pcins->mConst.mOperandSize = 2; + pcins->mConst.mMemory = IM_GLOBAL; + pcins->mConst.mLinkerObject = ccdec->mLinkerObject; + block->Append(pcins); + + InterInstruction* cins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CALL); + if (ccdec->mFlags & DTF_NATIVE) + cins->mCode = IC_CALL_NATIVE; + else + cins->mCode = IC_CALL; + cins->mSrc[0] = pcins->mDst; + cins->mNumOperands = 1; + + block->Append(cins); + } + } + else + { + InterInstruction* cins = new InterInstruction(MapLocation(exp, inlineMapper), IC_COPY); + cins->mSrc[0].mType = IT_POINTER; + cins->mSrc[0].mTemp = vr.mTemp; + cins->mSrc[0].mMemory = IM_INDIRECT; + cins->mSrc[0].mOperandSize = procType->mBase->mSize; + cins->mSrc[0].mStride = vr.mType->mStripe; + + cins->mSrc[1].mOperandSize = procType->mBase->mSize; + cins->mSrc[1].mType = IT_POINTER; + cins->mSrc[1].mTemp = ains->mDst.mTemp; + cins->mSrc[1].mMemory = IM_INDIRECT; + + cins->mConst.mOperandSize = procType->mBase->mSize; + block->Append(cins); + } +#endif + } + else + { + vr = TranslateExpression(procType, proc, block, exp->mLeft, destack, breakBlock, continueBlock, inlineMapper); + + if (procType->mBase->mType == DT_TYPE_POINTER && (vr.mType->mType == DT_TYPE_ARRAY || vr.mType->mType == DT_TYPE_FUNCTION)) + { + vr = Dereference(proc, exp, block, inlineMapper, vr, 1); + vr.mReference = 0; + vr.mType = procType->mBase; + } + else + vr = Dereference(proc, exp, block, inlineMapper, vr); + + if (!procType->mBase || procType->mBase->mType == DT_TYPE_VOID) + mErrors->Error(exp->mLocation, EERR_INVALID_RETURN, "Function has void return type"); + else if (procType->mBase->mType == DT_TYPE_BOOL && (vr.mType->IsIntegerType() || vr.mType->mType == DT_TYPE_POINTER)) + ; + else if (!procType->mBase->CanAssign(vr.mType)) + mErrors->Error(exp->mLocation, EERR_INVALID_RETURN, "Cannot return incompatible type"); + + vr = CoerceType(proc, exp, block, inlineMapper, vr, procType->mBase); ins->mSrc[0].mType = InterTypeOf(vr.mType); ins->mSrc[0].mTemp = vr.mTemp; if (inlineMapper) { - InterInstruction* ains = new InterInstruction(exp->mLocation, IC_CONSTANT); - ains->mDst.mType = IT_POINTER; - ains->mDst.mTemp = proc->AddTemporary(ins->mDst.mType); - ains->mConst.mOperandSize = procType->mBase->mSize; - ains->mConst.mIntConst = 0; - ains->mConst.mVarIndex = inlineMapper->mResult;; - ains->mConst.mMemory = IM_LOCAL; - block->Append(ains); + if (inlineMapper->mResultExp) + { + ins->mSrc[1].mType = IT_POINTER; + ins->mSrc[1].mTemp = inlineMapper->mResultExp->mTemp; + ins->mSrc[1].mMemory = IM_INDIRECT; + ins->mCode = IC_STORE; + ins->mSrc[1].mOperandSize = procType->mBase->mSize; + ins->mNumOperands = 2; + } + else + { + InterInstruction* ains = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + ains->mDst.mType = IT_POINTER; + ains->mDst.mTemp = proc->AddTemporary(ains->mDst.mType); + ains->mConst.mType = IT_POINTER; + ains->mConst.mOperandSize = procType->mBase->mSize; + ains->mConst.mIntConst = 0; + ains->mConst.mVarIndex = inlineMapper->mResult;; + ains->mConst.mMemory = IM_LOCAL; + block->Append(ains); - ins->mSrc[1].mType = ains->mDst.mType; - ins->mSrc[1].mTemp = ains->mDst.mTemp; - ins->mSrc[1].mMemory = IM_INDIRECT; - ins->mCode = IC_STORE; - ins->mSrc[1].mOperandSize = ains->mConst.mOperandSize; - ins->mNumOperands = 2; + ins->mSrc[1].mType = ains->mDst.mType; + ins->mSrc[1].mTemp = ains->mDst.mTemp; + ins->mSrc[1].mMemory = IM_INDIRECT; + ins->mCode = IC_STORE; + ins->mSrc[1].mOperandSize = ains->mConst.mOperandSize; + ins->mNumOperands = 2; + } } else { @@ -3036,12 +4118,14 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* ins->mCode = IC_RETURN; } + UnwindDestructStack(procType, proc, block, destack, nullptr, inlineMapper); + if (ins->mCode != IC_NONE) block->Append(ins); if (inlineMapper) { - InterInstruction* jins = new InterInstruction(exp->mLocation, IC_JUMP); + InterInstruction* jins = new InterInstruction(MapLocation(exp, inlineMapper), IC_JUMP); block->Append(jins); block->Close(inlineMapper->mReturn, nullptr); } @@ -3054,12 +4138,13 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* case EX_BREAK: { - if (breakBlock) + if (breakBlock.mBlock) { - InterInstruction * jins = new InterInstruction(exp->mLocation, IC_JUMP); + UnwindDestructStack(procType, proc, block, destack, breakBlock.mStack, inlineMapper); + InterInstruction * jins = new InterInstruction(MapLocation(exp, inlineMapper), IC_JUMP); block->Append(jins); - block->Close(breakBlock, nullptr); + block->Close(breakBlock.mBlock, nullptr); block = new InterCodeBasicBlock(proc); } else @@ -3070,12 +4155,13 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* case EX_CONTINUE: { - if (continueBlock) + if (continueBlock.mBlock) { - InterInstruction * jins = new InterInstruction(exp->mLocation, IC_JUMP); + UnwindDestructStack(procType, proc, block, destack, continueBlock.mStack, inlineMapper); + InterInstruction * jins = new InterInstruction(MapLocation(exp, inlineMapper), IC_JUMP); block->Append(jins); - block->Close(continueBlock, nullptr); + block->Close(continueBlock.mBlock, nullptr); block = new InterCodeBasicBlock(proc); } else @@ -3090,9 +4176,10 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* InterCodeBasicBlock* tblock = new InterCodeBasicBlock(proc); InterCodeBasicBlock* fblock = new InterCodeBasicBlock(proc); - TranslateLogic(procType, proc, block, tblock, fblock, exp->mLeft, inlineMapper); + TranslateLogic(procType, proc, block, tblock, fblock, exp->mLeft, destack, inlineMapper); - InterInstruction* ins = new InterInstruction(exp->mLocation, IC_UNREACHABLE); + InterInstruction* ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_UNREACHABLE); + ins->mNumOperands = 0; fblock->Append(ins); fblock->Close(nullptr, nullptr); @@ -3102,16 +4189,17 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* } case EX_LOGICAL_NOT: { - vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper); - vl = Dereference(proc, exp, block, vl); + vl = TranslateExpression(procType, proc, block, exp->mLeft, destack, breakBlock, continueBlock, inlineMapper); + vl = Dereference(proc, exp, block, inlineMapper, vl); - InterInstruction * zins = new InterInstruction(exp->mLocation, IC_CONSTANT); + InterInstruction * zins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); zins->mDst.mType = InterTypeOf(vl.mType); zins->mDst.mTemp = proc->AddTemporary(zins->mDst.mType); + zins->mConst.mType = zins->mDst.mType; zins->mConst.mIntConst = 0; block->Append(zins); - InterInstruction * ins = new InterInstruction(exp->mLocation, IC_RELATIONAL_OPERATOR); + InterInstruction * ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_RELATIONAL_OPERATOR); ins->mOperator = IA_CMPEQ; ins->mSrc[0].mType = InterTypeOf(vl.mType); ins->mSrc[0].mTemp = zins->mDst.mTemp; @@ -3129,31 +4217,41 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* #if 1 if (!exp->mRight->mLeft->HasSideEffects() && !exp->mRight->mRight->HasSideEffects()) { - ExValue vc = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper); + ExValue vc = TranslateExpression(procType, proc, block, exp->mLeft, destack, breakBlock, continueBlock, inlineMapper); - vl = TranslateExpression(procType, proc, block, exp->mRight->mLeft, breakBlock, continueBlock, inlineMapper); - vr = TranslateExpression(procType, proc, block, exp->mRight->mRight, breakBlock, continueBlock, inlineMapper); + vl = TranslateExpression(procType, proc, block, exp->mRight->mLeft, destack, breakBlock, continueBlock, inlineMapper); + vr = TranslateExpression(procType, proc, block, exp->mRight->mRight, destack, breakBlock, continueBlock, inlineMapper); - vc = Dereference(proc, exp, block, vc); + vc = Dereference(proc, exp, block, inlineMapper, vc); - int ttemp; + int ttemp, tref = 0; InterType ttype, stypel, styper; stypel = InterTypeOf(vl.mType); styper = InterTypeOf(vr.mType); - Declaration* dtype; - if (stypel == IT_POINTER || styper == IT_POINTER) + Declaration* dtype = exp->mDecType; + + if (dtype->IsReference()) + { + vl = Dereference(proc, exp, block, inlineMapper, vl, 1); + vr = Dereference(proc, exp, block, inlineMapper, vr, 1); + tref = 1; + + dtype = dtype->mBase; + ttype = IT_POINTER; + } + else if (stypel == IT_POINTER || styper == IT_POINTER) { if (vl.mType->mType == DT_TYPE_ARRAY) - vl = Dereference(proc, exp, block, vl, 1); + vl = Dereference(proc, exp, block, inlineMapper, vl, 1); else - vl = Dereference(proc, exp, block, vl); + vl = Dereference(proc, exp, block, inlineMapper, vl); if (vr.mType->mType == DT_TYPE_ARRAY) - vr = Dereference(proc, exp, block, vr, 1); + vr = Dereference(proc, exp, block, inlineMapper, vr, 1); else - vr = Dereference(proc, exp, block, vr); + vr = Dereference(proc, exp, block, inlineMapper, vr); if (vl.mType->mBase->IsSubType(vr.mType->mBase)) dtype = vr.mType; @@ -3173,8 +4271,8 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* } else { - vl = Dereference(proc, exp, block, vl); - vr = Dereference(proc, exp, block, vr); + vl = Dereference(proc, exp, block, inlineMapper, vl); + vr = Dereference(proc, exp, block, inlineMapper, vr); if (stypel == styper) { @@ -3186,22 +4284,22 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* ttype = stypel; dtype = vl.mType; - vr = CoerceType(proc, exp, block, vr, dtype); + vr = CoerceType(proc, exp, block, inlineMapper, vr, dtype); } else { ttype = styper; dtype = vr.mType; - vl = CoerceType(proc, exp, block, vl, dtype); + vl = CoerceType(proc, exp, block, inlineMapper, vl, dtype); } } - vc = CoerceType(proc, exp, block, vc, TheBoolTypeDeclaration); + vc = CoerceType(proc, exp, block, inlineMapper, vc, TheBoolTypeDeclaration); ttemp = proc->AddTemporary(ttype); - InterInstruction* sins = new InterInstruction(exp->mLocation, IC_SELECT); + InterInstruction* sins = new InterInstruction(MapLocation(exp, inlineMapper), IC_SELECT); sins->mSrc[2].mType = InterTypeOf(vc.mType); sins->mSrc[2].mTemp = vc.mTemp; sins->mSrc[1].mType = ttype; @@ -3212,22 +4310,22 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* sins->mDst.mTemp = ttemp; block->Append(sins); - return ExValue(dtype, ttemp); + return ExValue(dtype, ttemp, tref); } else #endif { - InterInstruction* jins0 = new InterInstruction(exp->mLocation, IC_JUMP); - InterInstruction* jins1 = new InterInstruction(exp->mLocation, IC_JUMP); + InterInstruction* jins0 = new InterInstruction(MapLocation(exp, inlineMapper), IC_JUMP); + InterInstruction* jins1 = new InterInstruction(MapLocation(exp, inlineMapper), IC_JUMP); InterCodeBasicBlock* tblock = new InterCodeBasicBlock(proc); InterCodeBasicBlock* fblock = new InterCodeBasicBlock(proc); InterCodeBasicBlock* eblock = new InterCodeBasicBlock(proc); - TranslateLogic(procType, proc, block, tblock, fblock, exp->mLeft, inlineMapper); + TranslateLogic(procType, proc, block, tblock, fblock, exp->mLeft, destack, inlineMapper); - vl = TranslateExpression(procType, proc, tblock, exp->mRight->mLeft, breakBlock, continueBlock, inlineMapper); - vr = TranslateExpression(procType, proc, fblock, exp->mRight->mRight, breakBlock, continueBlock, inlineMapper); + vl = TranslateExpression(procType, proc, tblock, exp->mRight->mLeft, destack, breakBlock, continueBlock, inlineMapper); + vr = TranslateExpression(procType, proc, fblock, exp->mRight->mRight, destack, breakBlock, continueBlock, inlineMapper); int ttemp; InterType ttype, stypel, styper; @@ -3239,14 +4337,14 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* if (stypel == IT_POINTER || styper == IT_POINTER) { if (vl.mType->mType == DT_TYPE_ARRAY) - vl = Dereference(proc, exp, tblock, vl, 1); + vl = Dereference(proc, exp, tblock, inlineMapper, vl, 1); else - vl = Dereference(proc, exp, tblock, vl); + vl = Dereference(proc, exp, tblock, inlineMapper, vl); if (vr.mType->mType == DT_TYPE_ARRAY) - vr = Dereference(proc, exp, fblock, vr, 1); + vr = Dereference(proc, exp, fblock, inlineMapper, vr, 1); else - vr = Dereference(proc, exp, fblock, vr); + vr = Dereference(proc, exp, fblock, inlineMapper, vr); if (vl.mType->mBase->IsSubType(vr.mType->mBase)) dtype = vr.mType; @@ -3266,8 +4364,8 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* } else { - vl = Dereference(proc, exp, tblock, vl); - vr = Dereference(proc, exp, fblock, vr); + vl = Dereference(proc, exp, tblock, inlineMapper, vl); + vr = Dereference(proc, exp, fblock, inlineMapper, vr); if (stypel == styper) { @@ -3279,27 +4377,27 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* ttype = stypel; dtype = vl.mType; - vr = CoerceType(proc, exp, fblock, vr, dtype); + vr = CoerceType(proc, exp, fblock, inlineMapper, vr, dtype); } else { ttype = styper; dtype = vr.mType; - vl = CoerceType(proc, exp, tblock, vl, dtype); + vl = CoerceType(proc, exp, tblock, inlineMapper, vl, dtype); } } ttemp = proc->AddTemporary(ttype); - InterInstruction* rins = new InterInstruction(exp->mLocation, IC_LOAD_TEMPORARY); + InterInstruction* rins = new InterInstruction(MapLocation(exp, inlineMapper), IC_LOAD_TEMPORARY); rins->mSrc[0].mType = ttype; rins->mSrc[0].mTemp = vr.mTemp; rins->mDst.mType = ttype; rins->mDst.mTemp = ttemp; fblock->Append(rins); - InterInstruction* lins = new InterInstruction(exp->mLocation, IC_LOAD_TEMPORARY); + InterInstruction* lins = new InterInstruction(MapLocation(exp, inlineMapper), IC_LOAD_TEMPORARY); lins->mSrc[0].mType = ttype; lins->mSrc[0].mTemp = vl.mTemp; lins->mDst.mType = ttype; @@ -3322,13 +4420,13 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* case EX_TYPECAST: { - vr = TranslateExpression(procType, proc, block, exp->mRight, breakBlock, continueBlock, inlineMapper); + vr = TranslateExpression(procType, proc, block, exp->mLeft, destack, breakBlock, continueBlock, inlineMapper); - InterInstruction * ins = new InterInstruction(exp->mLocation, IC_CONVERSION_OPERATOR); + InterInstruction * ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONVERSION_OPERATOR); - if (exp->mLeft->mDecType->mType == DT_TYPE_FLOAT && vr.mType->IsIntegerType()) + if (exp->mDecType->mType == DT_TYPE_FLOAT && vr.mType->IsIntegerType()) { - vr = Dereference(proc, exp, block, vr); + vr = Dereference(proc, exp, block, inlineMapper, vr); int stemp = vr.mTemp; @@ -3336,7 +4434,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* { if (vr.mType->mFlags & DTF_SIGNED) { - InterInstruction* xins = new InterInstruction(exp->mLocation, IC_CONVERSION_OPERATOR); + InterInstruction* xins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONVERSION_OPERATOR); xins->mOperator = IA_EXT8TO16S; xins->mSrc[0].mType = IT_INT8; xins->mSrc[0].mTemp = stemp; @@ -3347,7 +4445,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* } else { - InterInstruction* xins = new InterInstruction(exp->mLocation, IC_CONVERSION_OPERATOR); + InterInstruction* xins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONVERSION_OPERATOR); xins->mOperator = IA_EXT8TO16U; xins->mSrc[0].mType = IT_INT8; xins->mSrc[0].mTemp = stemp; @@ -3361,87 +4459,100 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* ins->mOperator = (vr.mType->mFlags & DTF_SIGNED) ? IA_INT2FLOAT : IA_UINT2FLOAT; ins->mSrc[0].mType = IT_INT16; ins->mSrc[0].mTemp = stemp; - ins->mDst.mType = InterTypeOf(exp->mLeft->mDecType); + ins->mDst.mType = InterTypeOf(exp->mDecType); ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType); block->Append(ins); } - else if (exp->mLeft->mDecType->IsIntegerType() && vr.mType->mType == DT_TYPE_FLOAT) + else if (exp->mDecType->IsIntegerType() && vr.mType->mType == DT_TYPE_FLOAT) { - vr = Dereference(proc, exp, block, vr); - ins->mOperator = (exp->mLeft->mDecType->mFlags & DTF_SIGNED) ? IA_FLOAT2INT : IA_FLOAT2UINT; + vr = Dereference(proc, exp, block, inlineMapper, vr); + ins->mOperator = (exp->mDecType->mFlags & DTF_SIGNED) ? IA_FLOAT2INT : IA_FLOAT2UINT; ins->mSrc[0].mType = InterTypeOf(vr.mType); ins->mSrc[0].mTemp = vr.mTemp; ins->mDst.mType = IT_INT16; ins->mDst.mTemp = proc->AddTemporary(IT_INT16); block->Append(ins); - if (exp->mLeft->mDecType->mSize == 1) + if (exp->mDecType->mSize == 1) { - InterInstruction* xins = new InterInstruction(exp->mLocation, IC_TYPECAST); + InterInstruction* xins = new InterInstruction(MapLocation(exp, inlineMapper), IC_TYPECAST); xins->mSrc[0].mType = IT_INT16; xins->mSrc[0].mTemp = ins->mDst.mTemp; - xins->mDst.mType = InterTypeOf(exp->mLeft->mDecType); + xins->mDst.mType = InterTypeOf(exp->mDecType); xins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType); block->Append(xins); ins = xins; } } - else if (exp->mLeft->mDecType->mType == DT_TYPE_POINTER && vr.mType->mType == DT_TYPE_POINTER) + else if (exp->mDecType->mType == DT_TYPE_POINTER && vr.mType->mType == DT_TYPE_POINTER) { // no need for actual operation when casting pointer to pointer - return ExValue(exp->mLeft->mDecType, vr.mTemp, vr.mReference); + return ExValue(exp->mDecType, vr.mTemp, vr.mReference); } - else if (exp->mLeft->mDecType->mType == DT_TYPE_POINTER && vr.mType->mType == DT_TYPE_ARRAY) + else if (exp->mDecType->mType == DT_TYPE_POINTER && vr.mType->mType == DT_TYPE_ARRAY) { // no need for actual operation when casting pointer to pointer - return ExValue(exp->mLeft->mDecType, vr.mTemp, vr.mReference - 1); + return ExValue(exp->mDecType, vr.mTemp, vr.mReference - 1); } - else if (exp->mLeft->mDecType->mType != DT_TYPE_VOID && vr.mType->mType == DT_TYPE_VOID) + else if (exp->mDecType->mType != DT_TYPE_VOID && vr.mType->mType == DT_TYPE_VOID) { mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Cannot cast void object to non void object"); - return ExValue(exp->mLeft->mDecType, vr.mTemp, vr.mReference); + return ExValue(exp->mDecType, vr.mTemp, vr.mReference); } - else if (exp->mLeft->mDecType->IsIntegerType() && vr.mType->IsIntegerType()) + else if (exp->mDecType->IsIntegerType() && vr.mType->IsIntegerType()) { - vr = Dereference(proc, exp, block, vr); - return CoerceType(proc, exp, block, vr, exp->mLeft->mDecType); + vr = Dereference(proc, exp, block, inlineMapper, vr); + return CoerceType(proc, exp, block, inlineMapper, vr, exp->mDecType); + } + else if (exp->mDecType->mType == DT_TYPE_VOID) + { + } + else if (exp->mDecType->IsReference() && exp->mDecType->mBase->IsConstSame(vr.mType)) + { + if (vr.mReference == 0) + mErrors->Error(exp->mLocation, EERR_NOT_AN_LVALUE, "Not an L value"); + + vr = Dereference(proc, exp, block, inlineMapper, vr, 1); + return ExValue(exp->mDecType, vr.mTemp); } else { - vr = Dereference(proc, exp, block, vr); + vr = Dereference(proc, exp, block, inlineMapper, vr); ins->mCode = IC_TYPECAST; - ins->mSrc[0].mType = InterTypeOf(vr.mType); + ins->mSrc[0].mType = vr.mReference > 0 ? IT_POINTER : InterTypeOf(vr.mType); ins->mSrc[0].mTemp = vr.mTemp; - ins->mDst.mType = InterTypeOf(exp->mLeft->mDecType); + ins->mDst.mType = InterTypeOf(exp->mDecType); ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType); block->Append(ins); } - return ExValue(exp->mLeft->mDecType, ins->mDst.mTemp); + return ExValue(exp->mDecType, ins->mDst.mTemp); } break; case EX_LOGICAL_AND: case EX_LOGICAL_OR: { - InterInstruction* jins0 = new InterInstruction(exp->mLocation, IC_JUMP); - InterInstruction* jins1 = new InterInstruction(exp->mLocation, IC_JUMP); + InterInstruction* jins0 = new InterInstruction(MapLocation(exp, inlineMapper), IC_JUMP); + InterInstruction* jins1 = new InterInstruction(MapLocation(exp, inlineMapper), IC_JUMP); InterCodeBasicBlock* tblock = new InterCodeBasicBlock(proc); InterCodeBasicBlock* fblock = new InterCodeBasicBlock(proc); InterCodeBasicBlock* eblock = new InterCodeBasicBlock(proc); - TranslateLogic(procType, proc, block, tblock, fblock, exp, inlineMapper); + TranslateLogic(procType, proc, block, tblock, fblock, exp, destack, inlineMapper); int ttemp = proc->AddTemporary(IT_BOOL); - InterInstruction* tins = new InterInstruction(exp->mLocation, IC_CONSTANT); + InterInstruction* tins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + tins->mConst.mType = IT_BOOL; tins->mConst.mIntConst = 1; tins->mDst.mType = IT_BOOL; tins->mDst.mTemp = ttemp; tblock->Append(tins); - InterInstruction* fins = new InterInstruction(exp->mLocation, IC_CONSTANT); + InterInstruction* fins = new InterInstruction(MapLocation(exp, inlineMapper), IC_CONSTANT); + fins->mConst.mType = IT_BOOL; fins->mConst.mIntConst = 0; fins->mDst.mType = IT_BOOL; fins->mDst.mTemp = ttemp; @@ -3459,10 +4570,50 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* } break; + case EX_SCOPE: + { + DestructStack* odestack = destack; + + TranslateExpression(procType, proc, block, exp->mLeft, destack, breakBlock, continueBlock, inlineMapper); + + UnwindDestructStack(procType, proc, block, destack, odestack, inlineMapper); + destack = odestack; + + return ExValue(TheVoidTypeDeclaration); + + } break; + + case EX_DISPATCH: + { + vl = TranslateExpression(procType, proc, block, exp->mLeft, destack, breakBlock, continueBlock, inlineMapper); + vl = Dereference(proc, exp, block, inlineMapper, vl); + + InterInstruction* ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_DISPATCH); + ins->mSrc[0].mType = IT_POINTER; + ins->mSrc[0].mTemp = vl.mTemp; + + block->Append(ins); + + Declaration* dinit = exp->mLeft->mLeft->mDecValue->mValue->mDecValue->mParams; + while (dinit) + { + proc->mModule->mProcedures[dinit->mValue->mDecValue->mVarIndex]->mDispatchedCall = true; + proc->AddCalledFunction(proc->mModule->mProcedures[dinit->mValue->mDecValue->mVarIndex]); + dinit = dinit->mNext; + } + + +// proc->CallsFunctionPointer(); + + return ExValue(TheVoidTypeDeclaration); + } + case EX_WHILE: { - InterInstruction * jins0 = new InterInstruction(exp->mLocation, IC_JUMP); - InterInstruction* jins1 = new InterInstruction(exp->mLocation, IC_JUMP); + DestructStack* odestack = destack; + + InterInstruction * jins0 = new InterInstruction(MapLocation(exp, inlineMapper), IC_JUMP); + InterInstruction* jins1 = new InterInstruction(MapLocation(exp, inlineMapper), IC_JUMP); InterCodeBasicBlock* cblock = new InterCodeBasicBlock(proc); InterCodeBasicBlock* lblock = cblock; @@ -3472,52 +4623,77 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* block->Append(jins0); block->Close(cblock, nullptr); - TranslateLogic(procType, proc, cblock, bblock, eblock, exp->mLeft, inlineMapper); + TranslateLogic(procType, proc, cblock, bblock, eblock, exp->mLeft, destack, inlineMapper); + + DestructStack* idestack = destack; + + vr = TranslateExpression(procType, proc, bblock, exp->mRight, destack, BranchTarget(eblock, odestack), BranchTarget(lblock, idestack), inlineMapper); + + UnwindDestructStack(procType, proc, bblock, destack, idestack, inlineMapper); + destack = idestack; - vr = TranslateExpression(procType, proc, bblock, exp->mRight, eblock, lblock, inlineMapper); bblock->Append(jins1); bblock->Close(lblock, nullptr); block = eblock; + UnwindDestructStack(procType, proc, block, destack, odestack, inlineMapper); + destack = odestack; + return ExValue(TheVoidTypeDeclaration); } case EX_IF: { - InterInstruction * jins0 = new InterInstruction(exp->mLocation, IC_JUMP); - InterInstruction* jins1 = new InterInstruction(exp->mLocation, IC_JUMP); + DestructStack* odestack = destack; + + InterInstruction * jins0 = new InterInstruction(MapLocation(exp, inlineMapper), IC_JUMP); + InterInstruction* jins1 = new InterInstruction(MapLocation(exp, inlineMapper), IC_JUMP); InterCodeBasicBlock* tblock = new InterCodeBasicBlock(proc); InterCodeBasicBlock* fblock = new InterCodeBasicBlock(proc); InterCodeBasicBlock* eblock = new InterCodeBasicBlock(proc); - TranslateLogic(procType, proc, block, tblock, fblock, exp->mLeft, inlineMapper); + TranslateLogic(procType, proc, block, tblock, fblock, exp->mLeft, destack, inlineMapper); + + DestructStack* itdestack = destack; + vr = TranslateExpression(procType, proc, tblock, exp->mRight->mLeft, destack, breakBlock, continueBlock, inlineMapper); + UnwindDestructStack(procType, proc, tblock, destack, itdestack, inlineMapper); + destack = itdestack; - vr = TranslateExpression(procType, proc, tblock, exp->mRight->mLeft, breakBlock, continueBlock, inlineMapper); tblock->Append(jins0); tblock->Close(eblock, nullptr); if (exp->mRight->mRight) - vr = TranslateExpression(procType, proc, fblock, exp->mRight->mRight, breakBlock, continueBlock, inlineMapper); + { + DestructStack* ifdestack = destack; + vr = TranslateExpression(procType, proc, fblock, exp->mRight->mRight, destack, breakBlock, continueBlock, inlineMapper); + UnwindDestructStack(procType, proc, fblock, destack, ifdestack, inlineMapper); + destack = ifdestack; + } fblock->Append(jins1); fblock->Close(eblock, nullptr); block = eblock; + UnwindDestructStack(procType, proc, block, destack, odestack, inlineMapper); + destack = odestack; + return ExValue(TheVoidTypeDeclaration); } case EX_FOR: { + DestructStack* odestack = destack; + // assignment if (exp->mLeft->mRight) - TranslateExpression(procType, proc, block, exp->mLeft->mRight, breakBlock, continueBlock, inlineMapper); + TranslateExpression(procType, proc, block, exp->mLeft->mRight, destack, breakBlock, continueBlock, inlineMapper); - InterInstruction* jins0 = new InterInstruction(exp->mLocation, IC_JUMP); - InterInstruction* jins1 = new InterInstruction(exp->mLocation, IC_JUMP); - InterInstruction* jins2 = new InterInstruction(exp->mLocation, IC_JUMP); - InterInstruction* jins3 = new InterInstruction(exp->mLocation, IC_JUMP); + InterInstruction* jins0 = new InterInstruction(MapLocation(exp, inlineMapper), IC_JUMP); + InterInstruction* jins1 = new InterInstruction(MapLocation(exp, inlineMapper), IC_JUMP); + InterInstruction* jins2 = new InterInstruction(MapLocation(exp, inlineMapper), IC_JUMP); + InterInstruction* jins3 = new InterInstruction(MapLocation(exp, inlineMapper), IC_JUMP); InterCodeBasicBlock* cblock = new InterCodeBasicBlock(proc); InterCodeBasicBlock* lblock = cblock; @@ -3530,33 +4706,45 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* // condition if (exp->mLeft->mLeft->mLeft) - TranslateLogic(procType, proc, cblock, bblock, eblock, exp->mLeft->mLeft->mLeft, inlineMapper); + TranslateLogic(procType, proc, cblock, bblock, eblock, exp->mLeft->mLeft->mLeft, destack, inlineMapper); else { cblock->Append(jins1); cblock->Close(bblock, nullptr); } - vr = TranslateExpression(procType, proc, bblock, exp->mRight, eblock, iblock, inlineMapper); + // Body + + DestructStack* idestack = destack; + + vr = TranslateExpression(procType, proc, bblock, exp->mRight, destack, BranchTarget(eblock, odestack), BranchTarget(iblock, idestack), inlineMapper); + + UnwindDestructStack(procType, proc, bblock, destack, idestack, inlineMapper); + destack = idestack; bblock->Append(jins2); bblock->Close(iblock, nullptr); // increment if (exp->mLeft->mLeft->mRight) - TranslateExpression(procType, proc, iblock, exp->mLeft->mLeft->mRight, breakBlock, continueBlock, inlineMapper); + TranslateExpression(procType, proc, iblock, exp->mLeft->mLeft->mRight, destack, breakBlock, continueBlock, inlineMapper); iblock->Append(jins3); iblock->Close(lblock, nullptr); block = eblock; + UnwindDestructStack(procType, proc, block, destack, odestack, inlineMapper); + destack = odestack; + return ExValue(TheVoidTypeDeclaration); } case EX_DO: { - InterInstruction * jins = new InterInstruction(exp->mLocation, IC_JUMP); + DestructStack* odestack = destack; + + InterInstruction * jins = new InterInstruction(MapLocation(exp, inlineMapper), IC_JUMP); InterCodeBasicBlock* cblock = new InterCodeBasicBlock(proc); InterCodeBasicBlock* lblock = cblock; @@ -3565,20 +4753,49 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* block->Append(jins); block->Close(cblock, nullptr); - vr = TranslateExpression(procType, proc, cblock, exp->mRight, eblock, cblock, inlineMapper); + DestructStack* idestack = destack; - TranslateLogic(procType, proc, cblock, lblock, eblock, exp->mLeft, inlineMapper); + vr = TranslateExpression(procType, proc, cblock, exp->mRight, destack, BranchTarget(eblock, odestack), BranchTarget(cblock, idestack), inlineMapper); + + UnwindDestructStack(procType, proc, cblock, destack, idestack, inlineMapper); + destack = idestack; + + TranslateLogic(procType, proc, cblock, lblock, eblock, exp->mLeft, destack, inlineMapper); block = eblock; + UnwindDestructStack(procType, proc, block, destack, odestack, inlineMapper); + destack = odestack; + return ExValue(TheVoidTypeDeclaration); } case EX_SWITCH: { - vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper); - vl = Dereference(proc, exp, block, vl); - vl = CoerceType(proc, exp, block, vl, TheSignedIntTypeDeclaration); + DestructStack* odestack = destack; + + vl = TranslateExpression(procType, proc, block, exp->mLeft, destack, breakBlock, continueBlock, inlineMapper); + vl = Dereference(proc, exp, block, inlineMapper, vl); + + int vleft = 0, vright = 65535; + + if (vl.mType->mSize == 1) + { + if (vl.mType->mFlags & DTF_SIGNED) + { + vleft = -128; + vright = 127; + } + else + vright = 255; + } + else if (vl.mType->mFlags & DTF_SIGNED) + { + vleft = -32768; + vright = 32767; + } + + vl = CoerceType(proc, exp, block, inlineMapper, vl, TheSignedIntTypeDeclaration); InterCodeBasicBlock * dblock = nullptr; InterCodeBasicBlock* sblock = block; @@ -3616,7 +4833,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* if (block) { - InterInstruction* jins = new InterInstruction(exp->mLocation, IC_JUMP); + InterInstruction* jins = new InterInstruction(MapLocation(exp, inlineMapper), IC_JUMP); block->Append(jins); block->Close(nblock, nullptr); @@ -3632,7 +4849,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* if (block) { - InterInstruction* jins = new InterInstruction(exp->mLocation, IC_JUMP); + InterInstruction* jins = new InterInstruction(MapLocation(exp, inlineMapper), IC_JUMP); block->Append(jins); block->Close(dblock, nullptr); @@ -3645,22 +4862,27 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* } if (cexp->mRight) - TranslateExpression(procType, proc, block, cexp->mRight, eblock, continueBlock, inlineMapper); + TranslateExpression(procType, proc, block, cexp->mRight, destack, BranchTarget(eblock, odestack), continueBlock, inlineMapper); sexp = sexp->mRight; } - BuildSwitchTree(proc, exp, sblock, vl, switchNodes, 0, switchNodes.Size(), dblock ? dblock : eblock); + + BuildSwitchTree(proc, exp, sblock, inlineMapper, vl, switchNodes, 0, switchNodes.Size(), vleft, vright, dblock ? dblock : eblock); if (block) { - InterInstruction* jins = new InterInstruction(exp->mLocation, IC_JUMP); + UnwindDestructStack(procType, proc, block, destack, odestack, inlineMapper); + + InterInstruction* jins = new InterInstruction(MapLocation(exp, inlineMapper), IC_JUMP); block->Append(jins); block->Close(eblock, nullptr); } block = eblock; + + destack = odestack; return ExValue(TheVoidTypeDeclaration); } @@ -3689,10 +4911,38 @@ void InterCodeGenerator::BuildInitializer(InterCodeModule * mod, uint8* dp, int else if (data->mType == DT_CONST_INTEGER) { int64 t = data->mInteger; - for (int i = 0; i < data->mBase->mSize; i++) + if (data->mBits) { - dp[offset + i * data->mBase->mStripe] = uint8(t & 0xff); - t >>= 8; + if (data->mBits + data->mShift <= 8) + { + uint8 mask = uint8(((1 << data->mBits) - 1) << data->mShift); + dp[offset] = (dp[offset] & ~mask) | (uint8(t << data->mShift) & mask); + } + else if (data->mBits + data->mShift <= 16) + { + uint16 mask = uint16(((1 << data->mBits) - 1) << data->mShift); + + dp[offset + 0] = (dp[offset + 0] & ~(mask & 0xff)) | (uint8(t << data->mShift) & (mask & 0xff)); + dp[offset + 1] = (dp[offset + 1] & ~(mask >> 8)) | (uint8(t >> (8 - data->mShift)) & (mask >> 8)); + } + else + { + uint32 mask = uint32(((1 << data->mBits) - 1) << data->mShift); + t = (t << data->mShift) & mask; + + dp[offset + 0] = (dp[offset + 0] & ~(mask & 0xff)) | (uint8(t )); + dp[offset + 1] = (dp[offset + 1] & ~(mask >> 8)) | (uint8(t >> 8)); + dp[offset + 2] = (dp[offset + 2] & ~(mask >> 16)) | (uint8(t >> 16)); + dp[offset + 3] = (dp[offset + 3] & ~(mask >> 24)) | (uint8(t >> 24)); + } + } + else + { + for (int i = 0; i < data->mBase->mSize; i++) + { + dp[offset + i * data->mBase->mStripe] = uint8(t & 0xff); + t >>= 8; + } } } else if (data->mType == DT_CONST_ADDRESS) @@ -3809,36 +5059,41 @@ void InterCodeGenerator::BuildInitializer(InterCodeModule * mod, uint8* dp, int } } -void InterCodeGenerator::TranslateLogic(Declaration* procType, InterCodeProcedure* proc, InterCodeBasicBlock* block, InterCodeBasicBlock* tblock, InterCodeBasicBlock* fblock, Expression* exp, InlineMapper* inlineMapper) +void InterCodeGenerator::TranslateLogic(Declaration* procType, InterCodeProcedure* proc, InterCodeBasicBlock* block, InterCodeBasicBlock* tblock, InterCodeBasicBlock* fblock, Expression* exp, DestructStack*& destack, InlineMapper* inlineMapper) { switch (exp->mType) { case EX_LOGICAL_NOT: - TranslateLogic(procType, proc, block, fblock, tblock, exp->mLeft, inlineMapper); + TranslateLogic(procType, proc, block, fblock, tblock, exp->mLeft, destack, inlineMapper); break; case EX_LOGICAL_AND: { InterCodeBasicBlock* ablock = new InterCodeBasicBlock(proc); - TranslateLogic(procType, proc, block, ablock, fblock, exp->mLeft, inlineMapper); - TranslateLogic(procType, proc, ablock, tblock, fblock, exp->mRight, inlineMapper); + TranslateLogic(procType, proc, block, ablock, fblock, exp->mLeft, destack, inlineMapper); + TranslateLogic(procType, proc, ablock, tblock, fblock, exp->mRight, destack, inlineMapper); break; } case EX_LOGICAL_OR: { InterCodeBasicBlock* oblock = new InterCodeBasicBlock(proc); - TranslateLogic(procType, proc, block, tblock, oblock, exp->mLeft, inlineMapper); - TranslateLogic(procType, proc, oblock, tblock, fblock, exp->mRight, inlineMapper); + TranslateLogic(procType, proc, block, tblock, oblock, exp->mLeft, destack, inlineMapper); + TranslateLogic(procType, proc, oblock, tblock, fblock, exp->mRight, destack, inlineMapper); break; } default: { - ExValue vr = TranslateExpression(procType, proc, block, exp, nullptr, nullptr, inlineMapper); - vr = Dereference(proc, exp, block, vr); + ExValue vr = TranslateExpression(procType, proc, block, exp, destack, BranchTarget(), BranchTarget(), inlineMapper); - if (!vr.mType->IsSimpleType()) - mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Not a valid condition value"); + if (vr.mType->mType == DT_TYPE_ARRAY) + vr = Dereference(proc, exp, block, inlineMapper, vr, 1); + else + { + vr = Dereference(proc, exp, block, inlineMapper, vr); + if (!vr.mType->IsSimpleType()) + mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Not a valid condition value"); + } - InterInstruction* ins = new InterInstruction(exp->mLocation, IC_BRANCH); + InterInstruction* ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_BRANCH); ins->mSrc[0].mType = InterTypeOf(vr.mType); ins->mSrc[0].mTemp = vr.mTemp; block->Append(ins); @@ -3851,13 +5106,26 @@ void InterCodeGenerator::TranslateLogic(Declaration* procType, InterCodeProcedur InterCodeProcedure* InterCodeGenerator::TranslateProcedure(InterCodeModule * mod, Expression* exp, Declaration * dec) { - InterCodeProcedure* proc = new InterCodeProcedure(mod, dec->mLocation, dec->mQualIdent, mLinker->AddObject(dec->mLocation, dec->mQualIdent, dec->mSection, LOT_BYTE_CODE)); + InterCodeProcedure* proc = new InterCodeProcedure(mod, dec->mLocation, dec->mQualIdent, mLinker->AddObject(dec->mLocation, dec->mQualIdent, dec->mSection, LOT_BYTE_CODE, dec->mAlignment)); + +#if 0 + if (proc->mIdent && !strcmp(proc->mIdent->mString, "main")) + exp->Dump(0); +#endif +#if 0 + if (proc->mIdent) + { + printf("TRANS %s\n", proc->mIdent->mString); + exp->Dump(0); + } +#endif uint64 outerCompilerOptions = mCompilerOptions; mCompilerOptions = dec->mCompilerOptions; proc->mCompilerOptions = mCompilerOptions; + dec->mVarIndex = proc->mID; dec->mLinkerObject = proc->mLinkerObject; proc->mNumLocals = dec->mNumVars; @@ -3899,10 +5167,20 @@ InterCodeProcedure* InterCodeGenerator::TranslateProcedure(InterCodeModule * mod proc->mFastCallBase = BC_REG_FPARAMS_END - BC_REG_FPARAMS; if (dec->mBase->mBase->mType != DT_TYPE_VOID && dec->mBase->mBase->mType != DT_TYPE_STRUCT) + { proc->mValueReturn = true; + proc->mReturnType = InterTypeOf(dec->mBase->mBase); + } InterCodeBasicBlock* entryBlock = new InterCodeBasicBlock(proc); + if (!strcmp(proc->mIdent->mString, "main")) + { + mMainInitBlock = entryBlock; + mMainInitProc = proc; + entryBlock = new InterCodeBasicBlock(proc); + } + InterCodeBasicBlock* exitBlock = entryBlock; if (dec->mFlags & DTF_DEFINED) @@ -3937,7 +5215,18 @@ InterCodeProcedure* InterCodeGenerator::TranslateProcedure(InterCodeModule * mod } #endif - TranslateExpression(dec->mBase, proc, exitBlock, exp, nullptr, nullptr, nullptr); + DestructStack* destack = nullptr; + + TranslateExpression(dec->mBase, proc, exitBlock, exp, destack, BranchTarget(), BranchTarget(), nullptr); + + UnwindDestructStack(dec->mBase, proc, exitBlock, destack, nullptr, nullptr); + + if (!strcmp(proc->mIdent->mString, "main")) + { + InterInstruction* ins = new InterInstruction(proc->mLocation, IC_JUMP); + mMainInitBlock->Append(ins); + mMainInitBlock->Close(entryBlock, nullptr); + } } else mErrors->Error(dec->mLocation, EERR_UNDEFINED_OBJECT, "Calling undefined function", dec->mQualIdent->mString); diff --git a/oscar64/InterCodeGenerator.h b/oscar64/InterCodeGenerator.h index 870633c..e261f33 100644 --- a/oscar64/InterCodeGenerator.h +++ b/oscar64/InterCodeGenerator.h @@ -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 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); }; diff --git a/oscar64/Linker.cpp b/oscar64/Linker.cpp index fdf3317..030b9c1 100644 --- a/oscar64/Linker.cpp +++ b/oscar64/Linker.cpp @@ -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 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; diff --git a/oscar64/Linker.h b/oscar64/Linker.h index ab6b3a8..c9d9348 100644 --- a/oscar64/Linker.h +++ b/oscar64/Linker.h @@ -90,11 +90,13 @@ public: struct FreeChunk { int mStart, mEnd; + LinkerObject* mLastObject; }; GrowingArray 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 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; diff --git a/oscar64/MachineTypes.h b/oscar64/MachineTypes.h index 7badfad..77ea5d0 100644 --- a/oscar64/MachineTypes.h +++ b/oscar64/MachineTypes.h @@ -16,10 +16,10 @@ typedef __int64 int64; typedef unsigned __int64 uint64; #define MAXPATHLEN _MAX_PATH #else -#if __APPLE__ -#include "limits.h" -#else /* __linux__ */ +#if __linux__ #include "linux/limits.h" +#else /* __APPLE__ */ +#include "limits.h" #endif typedef long long int64; @@ -105,4 +105,4 @@ inline int64 int64max(int64 a, int64 b) inline int64 int64min(int64 a, int64 b) { return a < b ? a : b; -} \ No newline at end of file +} diff --git a/oscar64/NativeCodeGenerator.cpp b/oscar64/NativeCodeGenerator.cpp index 21f4b70..4f11a58 100644 --- a/oscar64/NativeCodeGenerator.cpp +++ b/oscar64/NativeCodeGenerator.cpp @@ -95,13 +95,9 @@ void NativeRegisterDataSet::ResetMask(void) void NativeRegisterDataSet::ResetWorkRegs(void) { ResetZeroPage(BC_REG_WORK_Y); - ResetZeroPage(BC_REG_ADDR + 0); - ResetZeroPage(BC_REG_ADDR + 1); - - for (int i = 0; i < 4; i++) - ResetZeroPage(BC_REG_ACCU + i); - for (int i = 0; i < 8; i++) - ResetZeroPage(BC_REG_WORK + i); + ResetZeroPageRange(BC_REG_ADDR, 2); + ResetZeroPageRange(BC_REG_ACCU, 4); + ResetZeroPageRange(BC_REG_WORK, 8); } void NativeRegisterDataSet::ResetWorkMasks(void) @@ -129,6 +125,20 @@ void NativeRegisterDataSet::ResetZeroPage(int addr) } } +void NativeRegisterDataSet::ResetZeroPageRange(int addr, int num) +{ + for(int i=0; i= addr && mRegs[i].mValue < addr + num) + mRegs[i].Reset(); + else if (mRegs[i].mMode == NRDM_INDIRECT_Y && mRegs[i].mValue + 1 >= addr && mRegs[i].mValue < addr + num) + mRegs[i].Reset(); + } +} + + int NativeRegisterDataSet::FindAbsolute(LinkerObject* linkerObject, int addr) { for (int i = 0; i < 256; i++) @@ -379,7 +389,7 @@ NativeCodeInstruction::NativeCodeInstruction(const InterInstruction* ins, AsmIns } if (mode == ASMIM_ZERO_PAGE) { - assert(address >= 2 && address < 256); + assert(address >= 1 && address < 256); } } @@ -478,6 +488,9 @@ bool NativeCodeInstruction::IsUsedResultInstructions(NumberSet& requiredTemps) if (mType == ASMIT_RTS) { #if 1 + if (mFlags & NCIF_USE_CPU_REG_A) + requiredTemps += CPU_REG_A; + if (mFlags & NCIF_LOWER) { requiredTemps += BC_REG_ACCU; @@ -2400,6 +2413,16 @@ void NativeCodeInstruction::Simulate(NativeRegisterDataSet& data) } } break; + + case ASMIT_CLC: + data.mRegs[CPU_REG_C].mValue = 0; + data.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE; + break; + + case ASMIT_SEC: + data.mRegs[CPU_REG_C].mValue = 1; + data.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE; + break; } } @@ -3490,7 +3513,7 @@ bool NativeCodeInstruction::ValueForwarding(NativeRegisterDataSet& data, AsmInsT } changed = true; } - else if (data.mRegs[mAddress].mMode == NRDM_ZERO_PAGE) + else if (data.mRegs[mAddress].mMode == NRDM_ZERO_PAGE && (mAddress < BC_REG_FPARAMS || mAddress >= BC_REG_FPARAMS_END)) { data.mRegs[CPU_REG_A] = data.mRegs[mAddress]; mAddress = data.mRegs[CPU_REG_A].mValue; @@ -3925,6 +3948,13 @@ bool NativeCodeInstruction::ValueForwarding(NativeRegisterDataSet& data, AsmInsT mMode = ASMIM_IMPLIED; changed = true; } + else if (data.mRegs[CPU_REG_A].mMode == NRDM_ABSOLUTE_X && data.mRegs[CPU_REG_A].mLinkerObject == mLinkerObject && data.mRegs[CPU_REG_A].mValue == mAddress) + { + mType = ASMIT_TAY; + mMode = ASMIM_IMPLIED; + data.mRegs[CPU_REG_Y] = data.mRegs[CPU_REG_A]; + changed = true; + } else { data.mRegs[CPU_REG_Y].mMode = NRDM_ABSOLUTE_X; @@ -3982,6 +4012,13 @@ bool NativeCodeInstruction::ValueForwarding(NativeRegisterDataSet& data, AsmInsT mMode = ASMIM_IMPLIED; changed = true; } + else if (data.mRegs[CPU_REG_A].mMode == NRDM_ABSOLUTE_Y && data.mRegs[CPU_REG_A].mLinkerObject == mLinkerObject && data.mRegs[CPU_REG_A].mValue == mAddress) + { + mType = ASMIT_TAX; + mMode = ASMIM_IMPLIED; + data.mRegs[CPU_REG_X] = data.mRegs[CPU_REG_A]; + changed = true; + } else { data.mRegs[CPU_REG_X].mMode = NRDM_ABSOLUTE_Y; @@ -4189,6 +4226,12 @@ void NativeCodeInstruction::FilterRegUsage(NumberSet& requiredTemps, NumberSet& if (mType == ASMIT_RTS) { #if 1 + if (mFlags & NCIF_USE_CPU_REG_A) + { + if (!providedTemps[CPU_REG_A]) + requiredTemps += CPU_REG_A; + } + if (mFlags & NCIF_LOWER) { if (!providedTemps[BC_REG_ACCU + 0]) requiredTemps += BC_REG_ACCU + 0; @@ -5888,6 +5931,29 @@ void NativeCodeBasicBlock::StoreByteIndexedValue(InterCodeProcedure* proc, const } +void NativeCodeBasicBlock::StoreByteOffsetIndexedValue(InterCodeProcedure* proc, const InterInstruction* iins, const InterInstruction* wins) +{ + mIns.Push(NativeCodeInstruction(iins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[iins->mSrc[0].mTemp])); + mIns.Push(NativeCodeInstruction(iins, ASMIT_CLC)); + mIns.Push(NativeCodeInstruction(iins, ASMIT_ADC, ASMIM_IMMEDIATE, wins->mSrc[1].mIntConst)); + mIns.Push(NativeCodeInstruction(iins, ASMIT_TAY)); + + uint32 flags = NCIF_LOWER | NCIF_UPPER; + if (wins->mVolatile) + flags |= NCIF_VOLATILE; + + for (int i = 0; i < InterTypeSize[wins->mSrc[0].mType]; i++) + { + if (i != 0) + mIns.Push(NativeCodeInstruction(wins, ASMIT_INY, ASMIM_IMPLIED)); + if (wins->mSrc[0].mTemp < 0) + mIns.Push(NativeCodeInstruction(wins, ASMIT_LDA, ASMIM_IMMEDIATE, (wins->mSrc[0].mIntConst >> (8 * i)) & 0xff)); + else + mIns.Push(NativeCodeInstruction(wins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[wins->mSrc[0].mTemp] + i)); + mIns.Push(NativeCodeInstruction(wins, ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[iins->mSrc[1].mTemp], nullptr, flags)); + } +} + void NativeCodeBasicBlock::LoadStoreIndirectValue(InterCodeProcedure* proc, const InterInstruction* rins, const InterInstruction* wins) { int size = InterTypeSize[wins->mSrc[0].mType]; @@ -7100,10 +7166,34 @@ NativeCodeBasicBlock * NativeCodeBasicBlock::CopyValue(InterCodeProcedure* proc, if (size <= msize) { - for (int i = 0; i < size; i++) + LinkerObject* slo = ins->mSrc[0].mLinkerObject; + if (slo && (slo->mFlags & LOBJF_CONST)) { - block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + offset + i * sstride, ins->mSrc[0].mLinkerObject, flags)); - block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + offset + i * dstride, ins->mSrc[1].mLinkerObject, flags)); + + for (int i = 0; i < size; i++) + { + int64 si = ins->mSrc[0].mIntConst + offset + i * sstride; + + LinkerReference* lr = slo->FindReference(si); + if (lr) + { + if ((lr->mFlags & LREF_LOWBYTE) && lr->mOffset == si) + block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, lr->mRefOffset, lr->mRefObject, NCIF_LOWER)); + else + block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, lr->mRefOffset, lr->mRefObject, NCIF_UPPER)); + } + else + block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, slo->mData[si])); + block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + offset + i * dstride, ins->mSrc[1].mLinkerObject, flags)); + } + } + else + { + for (int i = 0; i < size; i++) + { + block->mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + offset + i * sstride, ins->mSrc[0].mLinkerObject, flags)); + block->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ABSOLUTE, ins->mSrc[1].mIntConst + offset + i * dstride, ins->mSrc[1].mLinkerObject, flags)); + } } } else @@ -7123,6 +7213,40 @@ NativeCodeBasicBlock * NativeCodeBasicBlock::CopyValue(InterCodeProcedure* proc, return block; } + else if ((ins->mSrc[0].mMemory == IM_GLOBAL || ins->mSrc[0].mMemory == IM_ABSOLUTE) && (ins->mSrc[1].mMemory == IM_FPARAM || ins->mSrc[1].mMemory == IM_FFRAME)) + { + LinkerObject* slo = ins->mSrc[0].mLinkerObject; + if (slo && (slo->mFlags & LOBJF_CONST)) + { + + for (int i = 0; i < size; i++) + { + int64 si = ins->mSrc[0].mIntConst + i * sstride; + + LinkerReference* lr = slo->FindReference(si); + if (lr) + { + if ((lr->mFlags & LREF_LOWBYTE) && lr->mOffset == si) + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, lr->mRefOffset, lr->mRefObject, NCIF_LOWER)); + else + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, lr->mRefOffset, lr->mRefObject, NCIF_UPPER)); + } + else + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, slo->mData[si])); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + i * dstride)); + } + } + else + { + for (int i = 0; i < size; i++) + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ABSOLUTE, ins->mSrc[0].mIntConst + i * sstride, ins->mSrc[0].mLinkerObject, flags)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_FPARAMS + ins->mSrc[1].mVarIndex + ins->mSrc[1].mIntConst + i * dstride)); + } + } + + return this; + } } #endif @@ -7346,6 +7470,57 @@ NativeCodeBasicBlock * NativeCodeBasicBlock::CopyValue(InterCodeProcedure* proc, } } +void NativeCodeBasicBlock::CallMalloc(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc) +{ + if (ins->mSrc[0].mTemp < 0) + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); + } + else + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); + } + + NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("malloc"))); + mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER)); + + if (ins->mDst.mTemp >= 0) + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1)); + } +} + +void NativeCodeBasicBlock::CallFree(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc) +{ + if (ins->mSrc[0].mTemp < 0) + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, ins->mSrc[0].mIntConst & 0xff)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, (ins->mSrc[0].mIntConst >> 8) & 0xff)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); + } + else + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); + } + + NativeCodeGenerator::Runtime& frt(nproc->mGenerator->ResolveRuntime(Ident::Unique("free"))); + mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_RUNTIME | NCIF_LOWER | NCIF_UPPER)); +} + + NativeCodeBasicBlock* NativeCodeBasicBlock::StrcpyValue(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc) { int sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp], dreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]; @@ -7383,6 +7558,75 @@ bool NativeCodeBasicBlock::CheckPredAccuStore(int reg) return true; } +void NativeCodeBasicBlock::ShiftRegisterRight(const InterInstruction* ins, int reg, int shift) +{ + if (shift == 0) + { + } + else if (shift == 1) + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_ZERO_PAGE, reg + 1)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, reg)); + } + else if (shift == 15) + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 1)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 0)); + } + else if (shift == 14) + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 1)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 3)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); + } + else if (shift >= 8) + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 1)); + for (int i = 8; i < shift; i++) + mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0x00)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); + } + else if (shift >= 5) + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_ZERO_PAGE, reg + 1)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STX, ASMIM_ZERO_PAGE, reg)); + + mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED)); + for (int i = shift; i < 8; i++) + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_ZERO_PAGE, reg)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED)); + } + mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0xff >> shift)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); + } + else + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, reg)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_ZERO_PAGE, reg + 1)); + + mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED)); + for (int i = 1; i < shift; i++) + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_ZERO_PAGE, reg + 1)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_IMPLIED)); + } + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, reg)); + } +} + void NativeCodeBasicBlock::ShiftRegisterLeft(InterCodeProcedure* proc, const InterInstruction* ins, int reg, int shift) { if (shift == 0) @@ -8636,7 +8880,23 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p int shift = ins->mSrc[0].mIntConst & 31; int sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]; - int nregs = 4; + int nvbits = 32; + if (ins->mSrc[1].IsUnsigned() && ins->mSrc[1].mRange.mMaxState == IntegerValueRange::S_BOUND) + { + int64 mv = ins->mSrc[1].mRange.mMaxValue; + while (nvbits > 0 && mv < (1LL << (nvbits - 1))) + nvbits--; + } + + if (shift >= nvbits) + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); + return this; + } if (shift >= 24) { @@ -8648,7 +8908,7 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); sreg = treg; shift -= 24; - nregs = 1; + nvbits -= 24; } else if (shift >= 16) { @@ -8661,7 +8921,7 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); sreg = treg; shift -= 16; - nregs = 2; + nvbits -= 16; } else if (shift >= 8) { @@ -8676,7 +8936,7 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); sreg = treg; shift -= 8; - nregs = 3; + nvbits -= 8; } if (shift == 0) @@ -8749,9 +9009,6 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p } else { - NativeCodeBasicBlock* lblock = nproc->AllocateBlock(); - NativeCodeBasicBlock* eblock = nproc->AllocateBlock(); - if (sreg != treg) { mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, sreg)); @@ -8764,22 +9021,44 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); } - mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg + nregs - 1)); + int nregs = (nvbits + 7) >> 3; - mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_IMMEDIATE, shift)); - this->Close(ins, lblock, nullptr, ASMIT_JMP); + if ((nvbits & 7) == 1) + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_ZERO_PAGE, treg + nregs - 1)); + for (int i = nregs - 1; i > 0; i--) + mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + i - 1)); + nvbits--; + nregs--; + shift--; + } - lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED)); - for(int i=nregs -1; i>0 ; i--) - lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + i - 1)); + if (nregs <= 2) + { + ShiftRegisterRight(ins, treg, shift); + } + else + { + NativeCodeBasicBlock* lblock = nproc->AllocateBlock(); + NativeCodeBasicBlock* eblock = nproc->AllocateBlock(); -// lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1)); -// lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0)); - lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED)); - lblock->Close(ins, lblock, eblock, ASMIT_BNE); + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, treg + nregs - 1)); - eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + nregs - 1)); - return eblock; + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_IMMEDIATE, shift)); + this->Close(ins, lblock, nullptr, ASMIT_JMP); + + lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED)); + for (int i = nregs - 1; i > 0; i--) + lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + i - 1)); + + // lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1)); + // lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0)); + lblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_DEX, ASMIM_IMPLIED)); + lblock->Close(ins, lblock, eblock, ASMIT_BNE); + + eblock->mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + nregs - 1)); + return eblock; + } } } else @@ -9542,7 +9821,7 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p int sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]; int shift = ins->mSrc[0].mIntConst & 15; - if (ins->mDst.IsUByte()) + if (ins->mDst.IsUByte() || InterTypeSize[ins->mDst.mType] == 1) { if (shift == 0) { @@ -9588,8 +9867,11 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg)); } - mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0)); - mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); + if (InterTypeSize[ins->mDst.mType] > 1) + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); + } } else { @@ -9799,7 +10081,7 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p { int shift = ins->mSrc[0].mIntConst & 15; #if 1 - if (ins->mSrc[1].IsUByte()) + if (ins->mSrc[1].IsUByte() || InterTypeSize[ins->mSrc[1].mType] == 1) { if (shift == 0) { @@ -9807,8 +10089,11 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p { mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg)); - mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0)); - mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); + if (InterTypeSize[ins->mDst.mType] > 1) + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); + } } } else if (shift == 7) @@ -9816,7 +10101,8 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0)); - mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); + if (InterTypeSize[ins->mDst.mType] > 1) + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); } @@ -9828,14 +10114,18 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 3)); mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); - mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0)); - mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); + if (InterTypeSize[ins->mDst.mType] > 1) + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); + } } else if (shift >= 8) { mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0)); mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); - mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); + if (InterTypeSize[ins->mDst.mType] > 1) + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } else { @@ -9843,8 +10133,11 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p for (int i = 0; i < shift; i++) mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED)); mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); - mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0)); - mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); + if (InterTypeSize[ins->mDst.mType] > 1) + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_IMMEDIATE, 0)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); + } } } else @@ -10131,6 +10424,33 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 1)); } } + else if (InterTypeSize[ins->mDst.mType] == 1) + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); + + if (shift > 5) + { + mIns.Push(NativeCodeInstruction(ins, ASMIT_ASL, ASMIM_IMPLIED)); + for (int i = shift; i < 8; i++) + mIns.Push(NativeCodeInstruction(ins, ASMIT_ROL, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_AND, ASMIM_IMMEDIATE, 0xff >> shift)); + + mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80 >> shift)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, 0x80 >> shift)); + } + else if (shift > 0) + { + for (int i = 0; i < shift; i++) + mIns.Push(NativeCodeInstruction(ins, ASMIT_LSR, ASMIM_IMPLIED)); + + mIns.Push(NativeCodeInstruction(ins, ASMIT_EOR, ASMIM_IMMEDIATE, 0x80 >> shift)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_SEC, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ins, ASMIT_SBC, ASMIM_IMMEDIATE, 0x80 >> shift)); + } + + mIns.Push(NativeCodeInstruction(ins, ASMIT_STA, ASMIM_ZERO_PAGE, treg + 0)); + } else if (ins->mSrc[1].IsSByte() && shift != 0 && shift < 5) { mIns.Push(NativeCodeInstruction(ins, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp])); @@ -12157,13 +12477,13 @@ void NativeCodeBasicBlock::BuildLocalRegSets(void) { mVisited = true; - mLocalRequiredRegs = NumberSet(NUM_REGS); - mLocalProvidedRegs = NumberSet(NUM_REGS); + mLocalRequiredRegs.Reset(NUM_REGS); + mLocalProvidedRegs.Reset(NUM_REGS); - mEntryRequiredRegs = NumberSet(NUM_REGS); - mEntryProvidedRegs = NumberSet(NUM_REGS); - mExitRequiredRegs = NumberSet(NUM_REGS); - mExitProvidedRegs = NumberSet(NUM_REGS); + mEntryRequiredRegs.Reset(NUM_REGS); + mEntryProvidedRegs.Reset(NUM_REGS); + mExitRequiredRegs.Reset(NUM_REGS); + mExitProvidedRegs.Reset(NUM_REGS); if (mEntryRegA) mLocalProvidedRegs += CPU_REG_A; @@ -12236,18 +12556,18 @@ bool NativeCodeBasicBlock::BuildGlobalRequiredRegSet(NumberSet& fromRequiredRegs { mVisited = true; - NumberSet newRequiredRegs(mExitRequiredRegs); + mNewRequiredRegs = mExitRequiredRegs; - if (mTrueJump && mTrueJump->BuildGlobalRequiredRegSet(newRequiredRegs)) revisit = true; - if (mFalseJump && mFalseJump->BuildGlobalRequiredRegSet(newRequiredRegs)) revisit = true; + if (mTrueJump && mTrueJump->BuildGlobalRequiredRegSet(mNewRequiredRegs)) revisit = true; + if (mFalseJump && mFalseJump->BuildGlobalRequiredRegSet(mNewRequiredRegs)) revisit = true; - if (!(newRequiredRegs <= mExitRequiredRegs)) + if (!(mNewRequiredRegs <= mExitRequiredRegs)) { revisit = true; - mExitRequiredRegs = newRequiredRegs; - newRequiredRegs -= mLocalProvidedRegs; - mEntryRequiredRegs |= newRequiredRegs; + mExitRequiredRegs = mNewRequiredRegs; + mNewRequiredRegs -= mLocalProvidedRegs; + mEntryRequiredRegs |= mNewRequiredRegs; } } @@ -12350,7 +12670,7 @@ void NativeCodeBasicBlock::BuildCollisionTable(NumberSet* collisionSets) } } -void NativeCodeBasicBlock::BuildDominatorTree(NativeCodeBasicBlock* from) +void NativeCodeBasicBlock::BuildDominatorTree(NativeCodeBasicBlock* from, DominatorStacks& stacks) { if (from == this) return; @@ -12360,25 +12680,26 @@ void NativeCodeBasicBlock::BuildDominatorTree(NativeCodeBasicBlock* from) return; else { - ExpandingArray< NativeCodeBasicBlock * > d1, d2; + stacks.d1.SetSize(0); + stacks.d2.SetSize(0); NativeCodeBasicBlock* b = mDominator; while (b) { - d1.Push(b); + stacks.d1.Push(b); b = b->mDominator; } b = from; while (b) { - d2.Push(b); + stacks.d2.Push(b); b = b->mDominator; } b = nullptr; - while (d1.Size() > 0 && d2.Size() > 0 && d1.Last() == d2.Last()) + while (stacks.d1.Size() > 0 && stacks.d2.Size() > 0 && stacks.d1.Last() == stacks.d2.Last()) { - b = d1.Pop(); d2.Pop(); + b = stacks.d1.Pop(); stacks.d2.Pop(); } if (mDominator == b) @@ -12388,9 +12709,9 @@ void NativeCodeBasicBlock::BuildDominatorTree(NativeCodeBasicBlock* from) } if (mTrueJump) - mTrueJump->BuildDominatorTree(this); + mTrueJump->BuildDominatorTree(this, stacks); if (mFalseJump) - mFalseJump->BuildDominatorTree(this); + mFalseJump->BuildDominatorTree(this, stacks); } @@ -12474,7 +12795,7 @@ bool NativeCodeBasicBlock::FindSameBlocks(NativeCodeProcedure* nproc) { mVisited = true; - if (!mSameBlock) + if (!mSameBlock && this != mProc->mEntryBlock) { for (int i = 0; i < nproc->mBlocks.Size(); i++) { @@ -12503,6 +12824,16 @@ bool NativeCodeBasicBlock::MergeSameBlocks(NativeCodeProcedure* nproc) { mVisited = true; + if (this == mProc->mEntryBlock && mSameBlock && mIns.Size() > 1) + { + mTrueJump = mSameBlock; + mFalseJump = nullptr; + mBranch = ASMIT_JMP; + mIns.SetSize(0); + changed = true; + mSameBlock = nullptr; + } + if (mTrueJump && mTrueJump->mSameBlock) { mTrueJump = mTrueJump->mSameBlock; @@ -12799,10 +13130,26 @@ void NativeCodeBasicBlock::BuildEntryDataSet(const NativeRegisterDataSet& set) for (int i = 0; i < mIns.Size(); i++) mIns[i].Simulate(mNDataSet); + mFDataSet = mNDataSet; + if (mBranch == ASMIT_BCC) + { + mNDataSet.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE; + mNDataSet.mRegs[CPU_REG_C].mValue = 0; + mFDataSet.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE; + mFDataSet.mRegs[CPU_REG_C].mValue = 1; + } + else if (mBranch == ASMIT_BCS) + { + mNDataSet.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE; + mNDataSet.mRegs[CPU_REG_C].mValue = 1; + mFDataSet.mRegs[CPU_REG_C].mMode = NRDM_IMMEDIATE; + mFDataSet.mRegs[CPU_REG_C].mValue = 0; + } + if (mTrueJump) mTrueJump->BuildEntryDataSet(mNDataSet); if (mFalseJump) - mFalseJump->BuildEntryDataSet(mNDataSet); + mFalseJump->BuildEntryDataSet(mFDataSet); } } @@ -12877,7 +13224,7 @@ void NativeCodeBasicBlock::FindZeroPageAlias(const NumberSet& statics, NumberSet } } -bool NativeCodeBasicBlock::CollectZeroPageSet(ZeroPageSet& locals, ZeroPageSet& global) +bool NativeCodeBasicBlock::CollectZeroPageSet(ZeroPageSet& locals, ZeroPageSet& global, bool ignorefcall) { if (!mVisited) { @@ -12894,12 +13241,20 @@ bool NativeCodeBasicBlock::CollectZeroPageSet(ZeroPageSet& locals, ZeroPageSet& case ASMIM_ABSOLUTE: if (mIns[i].mType == ASMIT_JSR) { - if ((mIns[i].mFlags & NCIF_RUNTIME) && !(mIns[i].mFlags & NCIF_FEXEC)) + if (mIns[i].mFlags & NCIF_RUNTIME) { - for (int j = 0; j < 4; j++) + if (mIns[i].mFlags & NCIF_FEXEC) { - locals += BC_REG_ACCU + j; - locals += BC_REG_WORK + j; + if (!ignorefcall) + return false; + } + else + { + for (int j = 0; j < 4; j++) + { + locals += BC_REG_ACCU + j; + locals += BC_REG_WORK + j; + } } } @@ -12944,9 +13299,9 @@ bool NativeCodeBasicBlock::CollectZeroPageSet(ZeroPageSet& locals, ZeroPageSet& } } - if (mTrueJump && !mTrueJump->CollectZeroPageSet(locals, global)) + if (mTrueJump && !mTrueJump->CollectZeroPageSet(locals, global, ignorefcall)) return false; - if (mFalseJump && !mFalseJump->CollectZeroPageSet(locals, global)) + if (mFalseJump && !mFalseJump->CollectZeroPageSet(locals, global, ignorefcall)) return false; } @@ -13352,6 +13707,7 @@ bool NativeCodeBasicBlock::ForwardAXYReg(void) bool xisa = false, yisa = false; int xoffset = -1, yoffset = -1; + int zpx = -1, zpy = -1, zpa = -1; for (int i = 0; i < mIns.Size(); i++) { @@ -13359,32 +13715,102 @@ bool NativeCodeBasicBlock::ForwardAXYReg(void) { xisa = true; xoffset = i; + zpx = zpa; } else if (mIns[i].mType == ASMIT_TXA) { xisa = true; yisa = false; xoffset = i; + zpa = zpx; } else if (mIns[i].mType == ASMIT_TAY) { yisa = true; yoffset = i; + zpy = zpa; } else if (mIns[i].mType == ASMIT_TYA) { yisa = true; xisa = false; yoffset = i; + zpa = zpy; } - else if (mIns[i].ChangesXReg()) - xisa = false; - else if (mIns[i].ChangesYReg()) - xisa = false; - else if (mIns[i].ChangesAccu()) + else if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE) + { + if (zpx == mIns[i].mAddress) + { + mIns[i].mType = ASMIT_TXA; mIns[i].mMode = ASMIM_IMPLIED; + xisa = true; + yisa = false; + int j = i; + while (j > 0 && !(mIns[j - 1].mLive & LIVE_CPU_REG_X)) + { + mIns[j - 1].mLive |= LIVE_CPU_REG_X; + j--; + } + } + else if (zpy == mIns[i].mAddress) + { + mIns[i].mType = ASMIT_TYA; mIns[i].mMode = ASMIM_IMPLIED; + yisa = true; + xisa = false; + int j = i; + while (j > 0 && !(mIns[j - 1].mLive & LIVE_CPU_REG_Y)) + { + mIns[j - 1].mLive |= LIVE_CPU_REG_Y; + j--; + } + } + else + { + xisa = false; + yisa = false; + } + zpa = mIns[i].mAddress; + } + else if (mIns[i].mType == ASMIT_LDX && mIns[i].mMode == ASMIM_ZERO_PAGE) { xisa = false; + zpx = mIns[i].mAddress; + } + else if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_ZERO_PAGE) + { yisa = false; + zpy = mIns[i].mAddress; + } + else if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE) + { + zpa = mIns[i].mAddress; + if (yisa) + zpy = mIns[i].mAddress; + else if (zpy == mIns[i].mAddress) + zpy = -1; + if (xisa) + zpx = mIns[i].mAddress; + else if (zpx == mIns[i].mAddress) + zpx = -1; + } + else if (mIns[i].mType == ASMIT_STX && mIns[i].mMode == ASMIM_ZERO_PAGE) + { + zpx = mIns[i].mAddress; + if (xisa) + zpa = mIns[i].mAddress; + else if (zpa == mIns[i].mAddress) + zpa = -1; + if (zpy == mIns[i].mAddress) + zpy = -1; + } + else if (mIns[i].mType == ASMIT_STY && mIns[i].mMode == ASMIM_ZERO_PAGE) + { + zpy = mIns[i].mAddress; + if (yisa) + zpa = mIns[i].mAddress; + else if (zpa == mIns[i].mAddress) + zpa = -1; + if (zpx == mIns[i].mAddress) + zpx = -1; } else if (i + 1 < mIns.Size() && mIns[i].mType == ASMIT_CLC && mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && !(mIns[i + 1].mLive & LIVE_CPU_REG_C)) @@ -13414,6 +13840,33 @@ bool NativeCodeBasicBlock::ForwardAXYReg(void) } } } + else + { + if (mIns[i].ChangesXReg()) + { + xisa = false; + zpx = -1; + } + if (mIns[i].ChangesYReg()) + { + yisa = false; + zpy = -1; + } + if (mIns[i].ChangesAccu()) + { + xisa = false; + yisa = false; + zpa = -1; + } + + if (zpa >= 0 && mIns[i].ChangesZeroPage(zpa)) + zpa = -1; + if (zpx >= 0 && mIns[i].ChangesZeroPage(zpx)) + zpx = -1; + if (zpy >= 0 && mIns[i].ChangesZeroPage(zpy)) + zpy = -1; + } + } if (mTrueJump && mTrueJump->ForwardAXYReg()) @@ -13706,6 +14159,15 @@ bool NativeCodeBasicBlock::ForwardZpYIndex(bool full) yoffset = 0; ypred = i; } + else if (mIns[i].mType == ASMIT_INC && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == yreg && yoffset == 1 && !(mIns[i].mLive & LIVE_CPU_REG_Z)) + { + mIns[i].mType = ASMIT_STY; + for (int j = ypred; j < i; j++) + mIns[j].mLive |= LIVE_CPU_REG_Y; + yoffset = 0; + ypred = i; + changed = true; + } #if 1 else if (mIns[i].mType == ASMIT_INC && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == yreg && yoffset == 0 && mIns[ypred].mType == ASMIT_STY && !(mIns[i].mLive & LIVE_CPU_REG_Y)) { @@ -13779,6 +14241,10 @@ bool NativeCodeBasicBlock::CombineSameXtoY(int xpos, int ypos, int end) { ReplaceXRegWithYReg(xpos, ypos); ReplaceXRegWithYReg(ypos + 1, end); + + for (int i = xpos; i < ypos; i++) + mIns[i].mLive |= LIVE_CPU_REG_Y; + if (!(mIns[ypos].mLive & LIVE_CPU_REG_Z)) { mIns[ypos].mType = ASMIT_NOP; @@ -13792,6 +14258,9 @@ bool NativeCodeBasicBlock::CombineSameXtoY(int xpos, int ypos, int end) if (CanCombineSameXtoY(xpos, end)) { ReplaceXRegWithYReg(xpos, end); + for (int i = ypos; i < xpos; i++) + mIns[i].mLive |= LIVE_CPU_REG_Y; + if (!(mIns[xpos].mLive & LIVE_CPU_REG_Z)) { mIns[xpos].mType = ASMIT_NOP; @@ -13814,6 +14283,10 @@ bool NativeCodeBasicBlock::CombineSameYtoX(int xpos, int ypos, int end) { ReplaceYRegWithXReg(ypos, xpos); ReplaceYRegWithXReg(xpos + 1, end); + + for (int i = ypos; i < xpos; i++) + mIns[i].mLive |= LIVE_CPU_REG_X; + if (!(mIns[xpos].mLive & LIVE_CPU_REG_Z)) { mIns[xpos].mType = ASMIT_NOP; @@ -13827,6 +14300,9 @@ bool NativeCodeBasicBlock::CombineSameYtoX(int xpos, int ypos, int end) if (CanCombineSameYtoX(ypos, end)) { ReplaceYRegWithXReg(ypos, end); + for (int i = xpos; i < ypos; i++) + mIns[i].mLive |= LIVE_CPU_REG_X; + if (!(mIns[ypos].mLive & LIVE_CPU_REG_Z)) { mIns[ypos].mType = ASMIT_NOP; @@ -13868,6 +14344,7 @@ bool NativeCodeBasicBlock::CombineSameXY(void) changed = true; yreg = -1; } + CheckLive(); } xreg = -1; @@ -13884,6 +14361,7 @@ bool NativeCodeBasicBlock::CombineSameXY(void) changed = true; xreg = -1; } + CheckLive(); } yreg = -1; @@ -15370,9 +15848,9 @@ bool NativeCodeBasicBlock::CanHoistStore(const NativeCodeInstruction& ains) cons return true; } -bool NativeCodeBasicBlock::CanBytepassLoad(const NativeCodeInstruction& ains) const +bool NativeCodeBasicBlock::CanBytepassLoad(const NativeCodeInstruction& ains, int from) const { - for (int i = 0; i < mIns.Size(); i++) + for (int i = from; i < mIns.Size(); i++) { if (ains.MayBeChangedOnAddress(mIns[i])) return false; @@ -15423,7 +15901,7 @@ bool NativeCodeBasicBlock::SimplifyDiamond(NativeCodeProcedure* proc) sz--; if (sz >= 0 && mIns[sz].mType == ASMIT_LDY && (mIns[sz].mMode == ASMIM_ZERO_PAGE || mIns[sz].mMode == ASMIM_ABSOLUTE) && !(mIns[sz].mLive & LIVE_CPU_REG_Z)) { - if (mTrueJump->CanBytepassLoad(mIns[sz]) && mFalseJump->CanBytepassLoad(mIns[sz])) + if (this->CanBytepassLoad(mIns[sz], sz + 1) && mTrueJump->CanBytepassLoad(mIns[sz]) && mFalseJump->CanBytepassLoad(mIns[sz])) { mTrueJump->mTrueJump->mIns.Insert(0, NativeCodeInstruction(mIns[sz].mIns, ASMIT_LDY, mIns[sz])); changed = true; @@ -15438,7 +15916,7 @@ bool NativeCodeBasicBlock::SimplifyDiamond(NativeCodeProcedure* proc) sz--; if (sz >= 0 && mIns[sz].mType == ASMIT_LDX && (mIns[sz].mMode == ASMIM_ZERO_PAGE || mIns[sz].mMode == ASMIM_ABSOLUTE) && !(mIns[sz].mLive & LIVE_CPU_REG_Z)) { - if (mTrueJump->CanBytepassLoad(mIns[sz]) && mFalseJump->CanBytepassLoad(mIns[sz])) + if (this->CanBytepassLoad(mIns[sz], sz + 1) && mTrueJump->CanBytepassLoad(mIns[sz]) && mFalseJump->CanBytepassLoad(mIns[sz])) { mTrueJump->mTrueJump->mIns.Insert(0, NativeCodeInstruction(mIns[sz].mIns, ASMIT_LDX, mIns[sz])); changed = true; @@ -15629,6 +16107,60 @@ bool NativeCodeBasicBlock::Split16BitLoopCount(NativeCodeProcedure* proc) return changed; } +bool NativeCodeBasicBlock::EliminateDeadLoops(void) +{ + bool changed = false; + if (!mVisited) + { + mVisited = true; + + if (mLoopHead && mNumEntries == 2 && mFalseJump) + { + NativeCodeBasicBlock* eblock = nullptr; + if (mTrueJump == this) + eblock = mFalseJump; + else if (mFalseJump == this) + eblock = mTrueJump; + + if (eblock) + { + if (mIns.Size() == 2 && (mIns[0].mType == ASMIT_INX || mIns[0].mType == ASMIT_DEX) && mIns[1].mType == ASMIT_CPX) + { + if (!(eblock->mEntryRequiredRegs[CPU_REG_X])) + { + mLoopHead = false; + mTrueJump = eblock; + mBranch = ASMIT_JMP; + mEntryBlocks.RemoveAll(this); + mNumEntries--; + changed = true; + } + } + else if (mIns.Size() == 2 && (mIns[0].mType == ASMIT_INY || mIns[0].mType == ASMIT_DEY) && mIns[1].mType == ASMIT_CPY) + { + if (!(eblock->mEntryRequiredRegs[CPU_REG_Y])) + { + mLoopHead = false; + mTrueJump = eblock; + mBranch = ASMIT_JMP; + mEntryBlocks.RemoveAll(this); + mNumEntries--; + changed = true; + } + } + } + } + + if (mTrueJump && mTrueJump->EliminateDeadLoops()) + changed = true; + if (mFalseJump && mFalseJump->EliminateDeadLoops()) + changed = true; + } + + return changed; +} + + bool NativeCodeBasicBlock::CrossBlockStoreLoadBypass(NativeCodeProcedure* proc) { bool changed = false; @@ -15636,7 +16168,7 @@ bool NativeCodeBasicBlock::CrossBlockStoreLoadBypass(NativeCodeProcedure* proc) { mVisited = true; - if (mTrueJump && !mFalseJump && mIns.Size() > 0 && mTrueJump->mIns.Size() > 0) + if (mTrueJump && mTrueJump->mTrueJump && !mFalseJump && mIns.Size() > 0 && mTrueJump->mIns.Size() > 0) { int sz = mIns.Size(); @@ -15702,6 +16234,10 @@ bool NativeCodeBasicBlock::ExpandADCToBranch(NativeCodeProcedure* proc) { mVisited = true; + int carry = -1; + if (mEntryRegisterDataSet.mRegs[CPU_REG_C].mMode == NRDM_IMMEDIATE) + carry = mEntryRegisterDataSet.mRegs[CPU_REG_C].mValue; + for (int i = 0; i < mIns.Size(); i++) { if (i + 2 < mIns.Size() && @@ -16023,7 +16559,7 @@ bool NativeCodeBasicBlock::ExpandADCToBranch(NativeCodeProcedure* proc) fblock->mFalseJump = mFalseJump; fblock->mBranch = mBranch; - mIns[i + 0].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; + mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 1].mType = ASMIT_NOP; mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 3].mType = ASMIT_INC; mIns[i + 3].mLive |= LIVE_CPU_REG_Z; @@ -16042,6 +16578,45 @@ bool NativeCodeBasicBlock::ExpandADCToBranch(NativeCodeProcedure* proc) break; } + if (carry == 0 && + mIns[i + 0].mType == ASMIT_LDA && + mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 1 && + mIns[i + 2].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 2]) && + mIns[i + 3].mType == ASMIT_LDA && + mIns[i + 4].mType == ASMIT_ADC && mIns[i + 4].mMode == ASMIM_IMMEDIATE && mIns[i + 4].mAddress == 0 && + mIns[i + 5].mType == ASMIT_STA && mIns[i + 3].SameEffectiveAddress(mIns[i + 5]) && + HasAsmInstructionMode(ASMIT_INC, mIns[i + 2].mMode) && + HasAsmInstructionMode(ASMIT_INC, mIns[i + 5].mMode) && + !(mIns[i + 5].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z))) + { + changed = true; + + NativeCodeBasicBlock* iblock = proc->AllocateBlock(); + NativeCodeBasicBlock* fblock = proc->AllocateBlock(); + + fblock->mTrueJump = mTrueJump; + fblock->mFalseJump = mFalseJump; + fblock->mBranch = mBranch; + + mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED; + mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; + mIns[i + 2].mType = ASMIT_INC; mIns[i + 2].mLive |= LIVE_CPU_REG_Z; + + for (int j = i + 6; j < mIns.Size(); j++) + fblock->mIns.Push(mIns[j]); + iblock->mIns.Push(mIns[i + 5]); + mIns.SetSize(i + 3); + iblock->mIns[0].mType = ASMIT_INC; + iblock->mTrueJump = fblock; + iblock->mBranch = ASMIT_JMP; + + mTrueJump = fblock; + mFalseJump = iblock; + mBranch = ASMIT_BNE; + break; + } + + if (mIns[i + 0].mType == ASMIT_CLC && mIns[i + 1].mType == ASMIT_LDA && mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0xff && @@ -16148,7 +16723,7 @@ bool NativeCodeBasicBlock::ExpandADCToBranch(NativeCodeProcedure* proc) mIns[i + 0].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 1].mType = ASMIT_NOP; - mIns[i + 2].mType = ASMIT_INX; mIns[i + 2].mLive |= LIVE_CPU_REG_Z | LIVE_CPU_REG_X; + mIns[i + 2].mType = ASMIT_INX; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mLive |= LIVE_CPU_REG_Z | LIVE_CPU_REG_X; mIns[i + 3].mType = ASMIT_STX; mIns[i + 3].mLive |= LIVE_CPU_REG_Z; fblock->mIns.Push(mIns[i + 4]); @@ -16840,8 +17415,37 @@ bool NativeCodeBasicBlock::ExpandADCToBranch(NativeCodeProcedure* proc) } } + + if (mIns[i].mType == ASMIT_CLC) + carry = 0; + else if (mIns[i].mType == ASMIT_SEC) + carry = 0; + else if (mIns[i].ChangesCarry()) + carry = -1; } +#if 1 + if (mIns.Size() >= 4 && mTrueJump && mFalseJump && mTrueJump->mEntryRequiredRegs.Size() > 0 && mFalseJump->mEntryRequiredRegs.Size() > 0) + { + int sz = mIns.Size(); + + if (mIns[sz - 4].mType == ASMIT_TYA && + mIns[sz - 3].mType == ASMIT_CLC && + mIns[sz - 2].mType == ASMIT_ADC && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 1 && + mIns[sz - 1].mType == ASMIT_TAY && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) && + (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS) && + !mTrueJump->mEntryRequiredRegs[CPU_REG_C] && !mFalseJump->mEntryRequiredRegs[CPU_REG_C]) + { + mIns[sz - 4].mType = ASMIT_INY; mIns[sz - 4].mLive |= LIVE_CPU_REG_Y | LIVE_CPU_REG_Z; + if (mBranch == ASMIT_BCC) + mBranch = ASMIT_BNE; + else + mBranch = ASMIT_BEQ; + mIns.SetSize(sz - 3); + changed = true; + } + } +#endif if (mIns.Size() >= 2) { int sz = mIns.Size(); @@ -16950,6 +17554,36 @@ bool NativeCodeBasicBlock::ExpandADCToBranch(NativeCodeProcedure* proc) } } + if (mIns.Size() >= 2 && !mFalseJump && mTrueJump && mTrueJump->mIns.Size() > 0) + { + int sz = mIns.Size(); + if (mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && + mIns[sz - 1].mType == ASMIT_ADC && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0 && + mTrueJump->mIns[0].mType == ASMIT_STA && mTrueJump->mIns[0].SameEffectiveAddress(mIns[sz - 2]) && !(mTrueJump->mIns[0].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z))) + { + NativeCodeBasicBlock * tblock = mTrueJump->SplitAt(1); + mTrueJump->mNumEntries--; + mTrueJump->mEntryBlocks.RemoveAll(this); + + NativeCodeBasicBlock* iblock = proc->AllocateBlock(); + iblock->Close(mBranchIns, tblock, nullptr, ASMIT_JMP); + iblock->mIns.Push(NativeCodeInstruction(mIns[sz - 2].mIns, ASMIT_INC, mIns[sz - 2])); + mIns.SetSize(sz - 2); + mBranch = ASMIT_BCC; + mTrueJump = tblock; + mFalseJump = iblock; + + tblock->mNumEntries += 2; + tblock->mEntryBlocks.Push(this); + tblock->mEntryBlocks.Push(iblock); + iblock->mNumEntries = 1; + iblock->mEntryBlocks.Push(this); + + changed = true; + } + + } + if (mIns.Size() >= 8 && mFalseJump && (mBranch == ASMIT_BNE || mBranch == ASMIT_BEQ)) { int sz = mIns.Size(); @@ -17037,6 +17671,34 @@ bool NativeCodeBasicBlock::ExpandADCToBranch(NativeCodeProcedure* proc) } + if (mIns.Size() >= 2 && mFalseJump && mBranch == ASMIT_BMI) + { + int sz = mIns.Size(); + if (mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && mIns[sz - 2].mAddress == 0 && + mIns[sz - 1].mType == ASMIT_SBC && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0) + { + if (mExitRequiredRegs[CPU_REG_Z]) + { + if (mFalseJump->mIns.Size() == 0 && mFalseJump->mBranch == ASMIT_BNE) + { + mFalseJump = mFalseJump->mFalseJump; + changed = true; + } + else if (mFalseJump->mIns.Size() == 0 && mFalseJump->mBranch == ASMIT_BEQ) + { + mFalseJump = mFalseJump->mTrueJump; + changed = true; + } + } + else if (!mExitRequiredRegs[CPU_REG_A]) + { + mBranch = ASMIT_BCC; + mIns.SetSize(sz - 2); + changed = true; + } + } + } + #if 1 if (mIns.Size() >= 1 && mFalseJump) { @@ -17315,10 +17977,13 @@ bool NativeCodeBasicBlock::CombineZPPair(int at, int r0, int r1, bool use0, bool } } } - else if (ins.ChangesZeroPage(r0)) - valid0 = false; - else if (ins.ChangesZeroPage(r1)) - valid1 = false; + else + { + if (ins.ChangesZeroPage(r0)) + valid0 = false; + if (ins.ChangesZeroPage(r1)) + valid1 = false; + } i++; } @@ -17386,6 +18051,183 @@ bool NativeCodeBasicBlock::RemoveDoubleZPStore(void) return changed; } +struct ValueNumbers +{ + int zvalues[256], avalue, xvalue, yvalue; + int ivalue = 0; + + void Reset(void) + { + for (int i = 0; i < 256; i++) + zvalues[i] = ivalue++; + avalue = ivalue++; + xvalue = ivalue++; + yvalue = ivalue++; + } + +}; + +bool NativeCodeBasicBlock::LocalZeroPageValueNumbering(void) +{ + bool changed = false; + + if (!mVisited) + { + mVisited = true; + + ValueNumbers vn; + vn.Reset(); + + for (int i = 0; i < mIns.Size(); i++) + { + NativeCodeInstruction& ins = mIns[i]; + + if (ins.mType == ASMIT_LDA && ins.mMode == ASMIM_ZERO_PAGE) + { + if (vn.avalue == vn.zvalues[ins.mAddress]) + { + if (ins.mLive & LIVE_CPU_REG_Z) + { + ins.mType = ASMIT_ORA; + ins.mMode = ASMIM_IMMEDIATE; + ins.mAddress = 0; + changed = true; + } + else + { + ins.mType = ASMIT_NOP; + ins.mMode = ASMIM_IMPLIED; + changed = true; + } + } + else + vn.avalue = vn.zvalues[ins.mAddress]; + } + else if (ins.mType == ASMIT_LDX && ins.mMode == ASMIM_ZERO_PAGE) + { + if (vn.xvalue == vn.zvalues[ins.mAddress] && !(ins.mLive & LIVE_CPU_REG_Z)) + { + ins.mType = ASMIT_NOP; + ins.mMode = ASMIM_IMPLIED; + changed = true; + } + else + vn.xvalue = vn.zvalues[ins.mAddress]; + } + else if (ins.mType == ASMIT_LDY && ins.mMode == ASMIM_ZERO_PAGE) + { + if (vn.yvalue == vn.zvalues[ins.mAddress] && !(ins.mLive & LIVE_CPU_REG_Z)) + { + ins.mType = ASMIT_NOP; + ins.mMode = ASMIM_IMPLIED; + changed = true; + } + else + vn.yvalue = vn.zvalues[ins.mAddress]; + } + else if (ins.mType == ASMIT_STA && ins.mMode == ASMIM_ZERO_PAGE) + { + if (vn.avalue == vn.zvalues[ins.mAddress]) + { + ins.mType = ASMIT_NOP; + ins.mMode = ASMIM_IMPLIED; + changed = true; + } + else + vn.zvalues[ins.mAddress] = vn.avalue; + } + else if (ins.mType == ASMIT_STX && ins.mMode == ASMIM_ZERO_PAGE) + { + if (vn.xvalue == vn.zvalues[ins.mAddress]) + { + ins.mType = ASMIT_NOP; + ins.mMode = ASMIM_IMPLIED; + changed = true; + } + else + vn.zvalues[ins.mAddress] = vn.xvalue; + } + else if (ins.mType == ASMIT_STY && ins.mMode == ASMIM_ZERO_PAGE) + { + if (vn.yvalue == vn.zvalues[ins.mAddress]) + { + ins.mType = ASMIT_NOP; + ins.mMode = ASMIM_IMPLIED; + changed = true; + } + else + vn.zvalues[ins.mAddress] = vn.yvalue; + } + else if (ins.mType == ASMIT_TAX) + { + if (vn.avalue == vn.xvalue && !(ins.mLive & LIVE_CPU_REG_Z)) + { + ins.mType = ASMIT_NOP; + ins.mMode = ASMIM_IMPLIED; + changed = true; + } + else + vn.xvalue = vn.avalue; + } + else if (ins.mType == ASMIT_TAY) + { + if (vn.avalue == vn.yvalue && !(ins.mLive & LIVE_CPU_REG_Z)) + { + ins.mType = ASMIT_NOP; + ins.mMode = ASMIM_IMPLIED; + changed = true; + } + else + vn.yvalue = vn.avalue; + } + else if (ins.mType == ASMIT_TXA) + { + if (vn.xvalue == vn.avalue && !(ins.mLive & LIVE_CPU_REG_Z)) + { + ins.mType = ASMIT_NOP; + ins.mMode = ASMIM_IMPLIED; + changed = true; + } + else + vn.avalue = vn.xvalue; + } + else if (ins.mType == ASMIT_TYA) + { + if (vn.yvalue == vn.avalue && !(ins.mLive & LIVE_CPU_REG_Z)) + { + ins.mType = ASMIT_NOP; + ins.mMode = ASMIM_IMPLIED; + changed = true; + } + else + vn.avalue = vn.yvalue; + } + else if (ins.mType == ASMIT_JSR) + vn.Reset(); + else + { + if (ins.ChangesAccu()) + vn.avalue = vn.ivalue++; + if (ins.ChangesXReg()) + vn.xvalue = vn.ivalue++; + if (ins.ChangesYReg()) + vn.yvalue = vn.ivalue++; + if (ins.mMode == ASMIM_ZERO_PAGE && ins.ChangesAddress()) + vn.zvalues[ins.mAddress] = vn.ivalue++; + } + } + + + if (mTrueJump && mTrueJump->LocalZeroPageValueNumbering()) + changed = true; + + if (mFalseJump && mFalseJump->LocalZeroPageValueNumbering()) + changed = true; + } + + return changed; +} + bool NativeCodeBasicBlock::LocalRegisterXYMap(void) { bool changed = false; @@ -18021,6 +18863,63 @@ void NativeCodeBasicBlock::PrependInstruction(const NativeCodeInstruction& ins) mIns[0].mLive |= LIVE_CPU_REG_C; } +bool NativeCodeBasicBlock::ShortcutBlockExit(void) +{ + bool changed = false; + if (!mVisited) + { + mVisited = true; + + if (!mLoopHead && mTrueJump && mFalseJump && !mTrueJump->mLoopHead && !mFalseJump->mLoopHead) + { + for (int i = 0; i < mTrueJump->mEntryBlocks.Size(); i++) + { + NativeCodeBasicBlock* eblock = mTrueJump->mEntryBlocks[i]; + if (eblock != this) + { + if (eblock->mTrueJump == mTrueJump && eblock->mFalseJump == mFalseJump && eblock->mBranch == mBranch) + { + int n = mIns.Size(), m = eblock->mIns.Size(); + if (m > 0 && n >= m) + { + while (m > 0 && mIns[n - 1].IsSame(eblock->mIns[m - 1])) + { + n--; + m--; + } + + if (m == 0) + { + mTrueJump->mNumEntries--; + mTrueJump->mEntryBlocks.RemoveAll(this); + mFalseJump->mNumEntries--; + mFalseJump->mEntryBlocks.RemoveAll(this); + mFalseJump = nullptr; + mTrueJump = eblock; + eblock->mNumEntries++; + eblock->mEntryBlocks.Push(this); + + mIns.SetSize(n); + mBranch = ASMIT_JMP; + changed = true; + break; + } + } + } + } + } + } + + if (mTrueJump && mTrueJump->ShortcutBlockExit()) + changed = true; + if (mFalseJump && mFalseJump->ShortcutBlockExit()) + changed = true; + + } + + return changed; +} + bool NativeCodeBasicBlock::PropagateSinglePath(void) { bool changed = false; @@ -18157,6 +19056,19 @@ bool NativeCodeBasicBlock::PropagateSinglePath(void) changed = true; } } + if (mTrueJump->mNumEntries == 1 && mTrueJump->mIns.Size() > 0 && mTrueJump->mIns[0].mType == ASMIT_TAX && !mFalseJump->mEntryRequiredRegs[CPU_REG_A] && !mFalseJump->mEntryRequiredRegs[CPU_REG_X] && !(mTrueJump->mIns[0].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))) + { + int sz = mIns.Size(); + if (sz >= 2 && mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 1].mType == ASMIT_CMP && HasAsmInstructionMode(ASMIT_LDX, mIns[sz - 2].mMode) && HasAsmInstructionMode(ASMIT_CPX, mIns[sz - 1].mMode)) + { + mIns[sz - 2].mType = ASMIT_LDX; mIns[sz - 2].mLive |= LIVE_CPU_REG_X; + mIns[sz - 1].mType = ASMIT_CPX; mIns[sz - 1].mLive |= LIVE_CPU_REG_X; + mExitRequiredRegs += CPU_REG_X; + mTrueJump->mEntryRequiredRegs += CPU_REG_X; + mTrueJump->mIns[0].mType = ASMIT_NOP; + changed = true; + } + } } #endif @@ -18466,6 +19378,148 @@ bool NativeCodeBasicBlock::ShortcutPointerAddForward(void) return changed; } +bool NativeCodeBasicBlock::MoveIndirectLoadZeroStoreDown(int at) +{ + int yval = mIns[at].mAddress; + + for (int i = at + 3; i < mIns.Size(); i++) + { + if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[at + 2].mAddress) + { + if (mIns[i].mLive & LIVE_CPU_REG_Y) + return false; + mIns.Insert(i, mIns[at]); + mIns.Insert(i + 1, mIns[at + 1]); + mIns[i + 2].mType = ASMIT_STA; + mIns[i].mLive |= mIns[i + 2].mLive; + mIns[i + 1].mLive |= mIns[i + 2].mLive; + mIns.Remove(at + 1, 2); + return true; + } + + if (mIns[i].ChangesZeroPage(mIns[at + 1].mAddress) || mIns[i].ChangesZeroPage(mIns[at + 1].mAddress + 1) || mIns[i].ReferencesZeroPage(mIns[at + 2].mAddress)) + return false; + + if (mIns[i].mType == ASMIT_JSR) + return false; + + if (mIns[i].ChangesAddress()) + { + if (mIns[i].mMode == ASMIM_INDIRECT_Y && mIns[i].mAddress == mIns[at + 1].mAddress) + { + if (yval == -1 || yval == mIns[at].mAddress) + return false; + } + else if (mIns[at + 1].MayBeChangedOnAddress(mIns[i])) + return false; + } + + if (mIns[i].ChangesYReg()) + { + if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_IMMEDIATE) + yval = mIns[i].mAddress; + else if (mIns[i].mType == ASMIT_INY && yval >= 0) + yval = (yval + 1) & 255; + else if (mIns[i].mType == ASMIT_DEY && yval >= 0) + yval = (yval - 1) & 255; + else + yval = -1; + } + + } + + return false; +} + +bool NativeCodeBasicBlock::MoveLoadZeroStoreIndirectUp(int at) +{ + int i = at - 1; + while (i >= 0 && !(mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[at].mAddress)) + i--; + + if (i >= 0 && mIns[i].mType == ASMIT_STA && !(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_Y))) + { + int yval = -1; + for (int j = i + 1; j < at; j++) + { + if (mIns[j].mType == ASMIT_JSR) + return false; + if (mIns[j].ChangesZeroPage(mIns[at + 2].mAddress) || mIns[j].ChangesZeroPage(mIns[at + 2].mAddress + 1)) + return false; + + if (mIns[j].mMode == ASMIM_INDIRECT_Y && mIns[j].mAddress == mIns[at + 2].mAddress) + { + if (yval == -1 || yval == mIns[at].mAddress) + return false; + } + else if (mIns[j].MayBeSameAddress(mIns[at + 2])) + return false; + + if (mIns[j].ChangesYReg()) + { + if (mIns[j].mType == ASMIT_LDY && mIns[j].mMode == ASMIM_IMMEDIATE) + yval = mIns[j].mAddress; + else if (mIns[j].mType == ASMIT_INY && yval >= 0) + yval = (yval + 1) & 255; + else if (mIns[j].mType == ASMIT_DEY && yval >= 0) + yval = (yval - 1) & 255; + else + yval = -1; + } + } + + NativeCodeInstruction i0 = mIns[at + 1], i1 = mIns[at + 2]; + mIns.Remove(at + 1, 2); + + mIns.Insert(i + 1, i0); + mIns.Insert(i + 2, i1); + mIns[i].mLive |= LIVE_CPU_REG_A; + mIns[i + 1].mLive |= mIns[i].mLive; + mIns[i + 2].mLive |= mIns[i].mLive; + + return true; + } + + return false; +} + + +bool NativeCodeBasicBlock::ShortcutIndirectLoadStore(void) +{ + bool changed = false; + + if (!mVisited) + { + mVisited = true; + + for (int i = 0; i + 2 < mIns.Size(); i++) + { + if (mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && + mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_INDIRECT_Y && + mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) && + mIns[i + 2].mAddress != mIns[i + 1].mAddress && mIns[i + 2].mAddress != mIns[i + 1].mAddress + 1) + { + if (MoveIndirectLoadZeroStoreDown(i)) + changed = true; + } + else if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && + mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_IMMEDIATE && + mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_INDIRECT_Y && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))) + { + if (MoveLoadZeroStoreIndirectUp(i)) + changed = true; + } + } + + if (mTrueJump && mTrueJump->ShortcutIndirectLoadStore()) + changed = true; + if (mFalseJump && mFalseJump->ShortcutIndirectLoadStore()) + changed = true; + } + + return changed; +} + #if 0 static int NativeCodeExpressionID; @@ -18894,6 +19948,8 @@ bool NativeCodeBasicBlock::JoinTailCodeSequences(NativeCodeProcedure* proc, bool i++; if (i == mEntryBlocks.Size()) { + mEntryRequiredRegs += CPU_REG_A; + mIns.Insert(0, eb->mIns[index]); mIns[0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_Y; for (int i = 0; i < mEntryBlocks.Size(); i++) @@ -18915,6 +19971,8 @@ bool NativeCodeBasicBlock::JoinTailCodeSequences(NativeCodeProcedure* proc, bool i++; if (i == mEntryBlocks.Size()) { + mEntryRequiredRegs += CPU_REG_X; + mIns.Insert(0, eb->mIns[index]); mIns[0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_Y; for (int i = 0; i < mEntryBlocks.Size(); i++) @@ -18936,6 +19994,8 @@ bool NativeCodeBasicBlock::JoinTailCodeSequences(NativeCodeProcedure* proc, bool i++; if (i == mEntryBlocks.Size()) { + mEntryRequiredRegs += CPU_REG_Y; + mIns.Insert(0, eb->mIns[index]); mIns[0].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_Y; for (int i = 0; i < mEntryBlocks.Size(); i++) @@ -19130,6 +20190,55 @@ bool NativeCodeBasicBlock::JoinTailCodeSequences(NativeCodeProcedure* proc, bool } } +#if 1 + if (mTrueJump && mFalseJump && mIns.Size() >= 2) + { + int nins = mIns.Size(); + if (mIns[nins - 2].mType == ASMIT_LDA && mIns[nins - 2].mMode == ASMIM_IMMEDIATE && + mIns[nins - 1].mType == ASMIT_CMP && mIns[nins - 1].mMode == ASMIM_ZERO_PAGE && (mIns[nins - 1].mLive & LIVE_MEM) && !(mIns[nins - 1].mLive & LIVE_CPU_REG_A) && + !mTrueJump->mEntryRequiredRegs[CPU_REG_C] && !mFalseJump->mEntryRequiredRegs[CPU_REG_C] && !mTrueJump->mEntryRequiredRegs[CPU_REG_Z] && !mFalseJump->mEntryRequiredRegs[CPU_REG_Z]) + { + int im = mIns[nins - 2].mAddress; + + mIns[nins - 2].CopyMode(mIns[nins - 1]); + mIns[nins - 2].mLive |= LIVE_MEM; + mIns[nins - 1].mMode = ASMIM_IMMEDIATE; + mIns[nins - 1].mFlags = NCIF_LOWER | NCIF_UPPER; + + if (mBranch == ASMIT_BCC) + { + if (im == 255) + { + mIns[nins - 1].mType = ASMIT_SEC; + mIns[nins - 1].mMode = ASMIM_IMPLIED; + } + else + { + mIns[nins - 1].mAddress = im + 1; + mBranch = ASMIT_BCS; + } + } + else if (mBranch == ASMIT_BCS) + { + if (im == 255) + { + mIns[nins - 1].mType = ASMIT_SEC; + mIns[nins - 1].mMode = ASMIM_IMPLIED; + } + else + { + mIns[nins - 1].mAddress = im + 1; + mBranch = ASMIT_BCC; + } + } + else + mIns[nins - 1].mAddress = im; + + + changed = true; + } + } +#endif CheckLive(); if (mTrueJump && mFalseJump) @@ -20341,6 +21450,100 @@ bool NativeCodeBasicBlock::CanCrossBlockYShortcut(int addr) return false; } +bool NativeCodeBasicBlock::CrossBlockRegisterAlias(bool sameAX, bool sameAY) +{ + bool changed = false; + if (!mVisited) + { + mVisited = true; + + if (mNumEntries > 1) + { + sameAX = false; + sameAY = false; + } + + bool direct = false; + for (int i = 0; i < mIns.Size(); i++) + { + NativeCodeInstruction& ins(mIns[i]); + switch (ins.mType) + { + case ASMIT_TAY: + sameAY = true; + break; + case ASMIT_TAX: + sameAX = true; + break; + case ASMIT_TYA: + sameAY = true; + sameAX = false; + direct = true; + break; + case ASMIT_TXA: + sameAY = false; + sameAX = true; + direct = true; + break; + case ASMIT_CMP: + if (!(ins.mLive & LIVE_CPU_REG_A)) + { + if (sameAY && (ins.mLive & LIVE_CPU_REG_Y) && HasAsmInstructionMode(ASMIT_CPY, ins.mMode)) + { + ins.mType = ASMIT_CPY; + changed = true; + } + else if (sameAX && (ins.mLive & LIVE_CPU_REG_X) && HasAsmInstructionMode(ASMIT_CPX, ins.mMode)) + { + ins.mType = ASMIT_CPX; + changed = true; + } + } + break; + case ASMIT_CPX: + if (!direct && !(ins.mLive & LIVE_CPU_REG_X)) + { + if (sameAX && (ins.mLive & LIVE_CPU_REG_A)) + { + ins.mType = ASMIT_CMP; + changed = true; + } + } + break; + case ASMIT_CPY: + if (!direct && !(ins.mLive & LIVE_CPU_REG_Y)) + { + if (sameAY && (ins.mLive & LIVE_CPU_REG_A)) + { + ins.mType = ASMIT_CMP; + changed = true; + } + } + break; + default: + if (ins.ChangesAccu()) + { + sameAY = false; + sameAX = false; + } + if (ins.ChangesXReg()) + sameAX = false; + if (ins.ChangesYReg()) + sameAY = false; + break; + } + } + + + if (mTrueJump && mTrueJump->CrossBlockRegisterAlias(sameAX, sameAY)) + changed = true; + if (mFalseJump && mFalseJump->CrossBlockRegisterAlias(sameAX, sameAY)) + changed = true; + } + + return changed; +} + bool NativeCodeBasicBlock::CrossBlockYAliasProgpagation(const int* yalias, int yoffset) { bool changed = false; @@ -21109,7 +22312,7 @@ bool NativeCodeBasicBlock::CheckSingleUseGlobalLoad(const NativeCodeBasicBlock* } else { - if (mExitRequiredRegs[reg]) +// if (mExitRequiredRegs[reg]) { if (mTrueJump && !mTrueJump->CheckPatchFailReg(block, reg)) return false; @@ -21122,7 +22325,7 @@ bool NativeCodeBasicBlock::CheckSingleUseGlobalLoad(const NativeCodeBasicBlock* } else { - if (mExitRequiredRegs[reg]) +// if (mExitRequiredRegs[reg]) { if (mTrueJump && !mTrueJump->CheckPatchFailReg(block, reg)) return false; @@ -21304,7 +22507,7 @@ bool NativeCodeBasicBlock::PatchForwardLowYPointer(const NativeCodeBasicBlock* b return changed; } -bool NativeCodeBasicBlock::CheckForwardSumYPointer(const NativeCodeBasicBlock* block, int reg, int base, const NativeCodeInstruction& iins, int at, int yval) +bool NativeCodeBasicBlock::CheckForwardSumYPointer(const NativeCodeBasicBlock* block, int reg, int base, const NativeCodeInstruction& iins, int at, int yval, int ymax) { if (!mPatched) { @@ -21346,10 +22549,11 @@ bool NativeCodeBasicBlock::CheckForwardSumYPointer(const NativeCodeBasicBlock* b { if (iins.mMode == ASMIM_IMMEDIATE && yval + iins.mAddress > 255) return false; - if (yval < 0 || yval > 3) + if (yval < 0 || yval > ymax) return false; else if (!(ins.mLive & LIVE_MEM)) return true; + if (yval == 0) ymax = 3; } if (ins.mType == ASMIT_LDY && ins.mMode == ASMIM_IMMEDIATE) @@ -21377,9 +22581,9 @@ bool NativeCodeBasicBlock::CheckForwardSumYPointer(const NativeCodeBasicBlock* b at++; } - if (mTrueJump && !mTrueJump->CheckForwardSumYPointer(block, reg, base, iins, 0, yval)) + if (mTrueJump && !mTrueJump->CheckForwardSumYPointer(block, reg, base, iins, 0, yval, ymax)) return false; - if (mFalseJump && !mFalseJump->CheckForwardSumYPointer(block, reg, base, iins, 0, yval)) + if (mFalseJump && !mFalseJump->CheckForwardSumYPointer(block, reg, base, iins, 0, yval, ymax)) return false; } @@ -21629,8 +22833,8 @@ bool NativeCodeBasicBlock::PatchCrossBlock16BitFlood(const NativeCodeBasicBlock* mPatchExit = true; - mExitRequiredRegs |= sreg; - mExitRequiredRegs |= sreg + 1; + mExitRequiredRegs += sreg; + mExitRequiredRegs += sreg + 1; if (mTrueJump && mTrueJump->PatchCrossBlock16BitFlood(block, sreg, dreg, 0)) changed = true; @@ -22551,6 +23755,53 @@ void NativeCodeBasicBlock::PropagateZPAbsolute(void) } } +void NativeCodeBasicBlock::RegisterFunctionCalls(void) +{ + if (!mVisited) + { + mVisited = true; + + for (int i = 0; i < mIns.Size(); i++) + { + if (mIns[i].mType == ASMIT_JSR && mIns[i].mLinkerObject) + mProc->mGenerator->RegisterFunctionCall(this, i); + } + + if (mTrueJump) mTrueJump->RegisterFunctionCalls(); + if (mFalseJump) mFalseJump->RegisterFunctionCalls(); + } +} + +bool NativeCodeBasicBlock::MergeFunctionCalls(void) +{ + bool changed = false; + + if (!mVisited) + { + mVisited = true; + + for (int i = 0; i < mIns.Size(); i++) + { + if (mIns[i].mType == ASMIT_JSR && mIns[i].mLinkerObject) + { + if (mProc->mGenerator->MergeFunctionCall(this, i)) + changed = true; + } + } + + if (changed) + RemoveNops(); + + if (mTrueJump && mTrueJump->MergeFunctionCalls()) + changed = true; + if (mFalseJump && mFalseJump->MergeFunctionCalls()) + changed = true; + } + + return changed; +} + + bool NativeCodeBasicBlock::IsDominatedBy(const NativeCodeBasicBlock* block) const { if (this == block) @@ -22755,17 +24006,17 @@ bool NativeCodeBasicBlock::PatchGlobalAddressSumYPointer(const NativeCodeBasicBl int naddr = address + mIns[at + 2].mAddress + 256 * mIns[at + 5].mAddress; mIns[at + 2].mType = ASMIT_ADC; - mIns[at + 2].mMode = ASMIM_IMMEDIATE_ADDRESS; + mIns[at + 2].mMode = lobj ? ASMIM_IMMEDIATE_ADDRESS : ASMIM_IMMEDIATE; mIns[at + 2].mLinkerObject = lobj; - mIns[at + 2].mAddress = naddr; + mIns[at + 2].mAddress = lobj ? naddr : naddr & 0xff; mIns[at + 2].mFlags = NCIF_LOWER; mIns[at + 4].mMode = ASMIM_IMMEDIATE; mIns[at + 4].mAddress = 0; - mIns[at + 5].mMode = ASMIM_IMMEDIATE_ADDRESS; + mIns[at + 5].mMode = lobj ? ASMIM_IMMEDIATE_ADDRESS : ASMIM_IMMEDIATE;; mIns[at + 5].mLinkerObject = lobj; - mIns[at + 5].mAddress = naddr; + mIns[at + 5].mAddress = lobj ? naddr : naddr >> 8; mIns[at + 5].mFlags = NCIF_UPPER; at += 6; @@ -23452,7 +24703,7 @@ bool NativeCodeBasicBlock::JoinTAXARange(int from, int to) mIns[i].mType = ASMIT_LDX; else if (mIns[i].mType == ASMIT_STA) mIns[i].mType = ASMIT_STX; - mIns[i].mLive |= LIVE_CPU_REG_X; + mIns[i].mLive |= LIVE_CPU_REG_X | LIVE_CPU_REG_A; } mIns[from].mType = ASMIT_NOP; mIns[from].mMode = ASMIM_IMPLIED; mIns[to].mType = ASMIT_NOP; mIns[to].mMode = ASMIM_IMPLIED; @@ -24607,6 +25858,9 @@ bool NativeCodeBasicBlock::MoveIndirectLoadStoreUp(int at) { if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at].mAddress) { + if (mIns[j].mLive & LIVE_CPU_REG_Y) + return false; + mIns[at + 1].mLive |= mIns[j].mLive; mIns[at + 2].mLive |= mIns[j].mLive; @@ -24619,8 +25873,18 @@ bool NativeCodeBasicBlock::MoveIndirectLoadStoreUp(int at) return true; } - if (mIns[j].ReferencesYReg()) + if (mIns[j].mMode == ASMIM_INDIRECT_Y && mIns[j].mAddress == mIns[at + 2].mAddress) + { + if (j > 0 && mIns[j - 1].mType == ASMIT_LDY && mIns[j - 1].mMode == ASMIM_IMMEDIATE && mIns[j - 1].mAddress != mIns[at + 1].mAddress) + ; + else + return false; + } + else if (mIns[at + 2].MayBeSameAddress(mIns[j])) return false; + else if (mIns[j].mType == ASMIT_JSR) + return false; + if (mIns[j].ChangesZeroPage(mIns[at].mAddress)) return false; if (mIns[j].ChangesZeroPage(mIns[at + 2].mAddress)) @@ -24725,6 +25989,8 @@ bool NativeCodeBasicBlock::MoveAbsoluteLoadStoreUp(int at) return false; if (mIns[at + 1].mMode == ASMIM_ABSOLUTE_Y && mIns[j].ChangesYReg()) return false; + if (mIns[at + 1].mMode == ASMIM_INDIRECT_Y && (mIns[j].ChangesYReg() || mIns[j].ChangesZeroPage(mIns[at + 1].mAddress) || mIns[j].ChangesZeroPage(mIns[at + 1].mAddress + 1))) + return false; if (mIns[j].mType == ASMIT_JSR) return false; @@ -24812,6 +26078,8 @@ bool NativeCodeBasicBlock::MoveZeroPageCrossBlockUp(int at, const NativeCodeInst return false; if (mIns[i].ReferencesZeroPage(sins.mAddress)) return false; + if (mIns[i].mMode == ASMIM_INDIRECT_Y && (mIns[i].mAddress + 1 == lins.mAddress || mIns[i].mAddress == lins.mAddress)) + return false; } at = mIns.Size(); @@ -24844,6 +26112,8 @@ bool NativeCodeBasicBlock::MoveZeroPageCrossBlockUp(int at, const NativeCodeInst return false; else if (mIns[i].ReferencesZeroPage(sins.mAddress)) return false; + else if (mIns[i].mType == ASMIT_JSR && mIns[i].ReferencesZeroPage(lins.mAddress)) + return false; } } @@ -25107,7 +26377,7 @@ bool NativeCodeBasicBlock::Check16BitSum(int at, NativeRegisterSum16Info& info) return false; } -bool NativeCodeBasicBlock::IsFinalZeroPageUse(const NativeCodeBasicBlock* block, int at, int from, int to, bool pair) +bool NativeCodeBasicBlock::IsFinalZeroPageUse(const NativeCodeBasicBlock* block, int at, int from, int to, bool pair, bool fchanged) { if (at == 0 && mVisited) return false; @@ -25116,70 +26386,80 @@ bool NativeCodeBasicBlock::IsFinalZeroPageUse(const NativeCodeBasicBlock* block, { mPatched = true; - if (at == 0) + if (at != 0 || (mEntryRequiredRegs[from] || mEntryRequiredRegs[to] || (pair && (mEntryRequiredRegs[from + 1] || mEntryRequiredRegs[to + 1])))) { - mPatched = true; + if (at == 0) + { + mPatched = true; - if (mNumEntries > 1) - { - for (int i = 0; i < mEntryBlocks.Size(); i++) - if (!mEntryBlocks[i]->IsDominatedBy(block)) - return false; - } - } - - while (at < mIns.Size()) - { - if (mIns[at].mMode == ASMIM_ZERO_PAGE) - { - if (mIns[at].mAddress == to) - return false; - if (pair && mIns[at].mAddress == to + 1) - return false; - } - else if (mIns[at].mMode == ASMIM_INDIRECT_Y) - { - if (mIns[at].mAddress == to) - return false; - if (mIns[at].mAddress + 1 == to) - return false; - if (pair && mIns[at].mAddress == to + 1) - return false; - if (!pair && mIns[at].mAddress == from) - return false; - if (mIns[at].mAddress + 1 == from) - return false; - if (pair && mIns[at].mAddress == from + 1) - return false; - } - else if (mIns[at].mType == ASMIT_JSR) - { - LinkerObject* lo = mIns[at].mLinkerObject; - if (lo) + if (mNumEntries > 1) { - for (int i = 0; i < lo->mNumTemporaries; i++) + fchanged = true; + for (int i = 0; i < mEntryBlocks.Size(); i++) + if (mEntryBlocks[i] != block && !mEntryBlocks[i]->IsDominatedBy(block)) + return false; + } + } + + while (at < mIns.Size()) + { + if (mIns[at].mMode == ASMIM_ZERO_PAGE) + { + if (mIns[at].mAddress == to && (fchanged || mIns[at].ChangesAddress())) + return false; + if (pair && mIns[at].mAddress == to + 1 && (fchanged || mIns[at].ChangesAddress())) + return false; + if (mIns[at].mAddress == from && mIns[at].ChangesAddress()) + fchanged = true; + if (pair && mIns[at].mAddress == from + 1 && mIns[at].ChangesAddress()) + fchanged = true; + } + else if (mIns[at].mMode == ASMIM_INDIRECT_Y) + { + if (mIns[at].mAddress == to) + return false; + if (mIns[at].mAddress + 1 == to) + return false; + if (pair && mIns[at].mAddress == to + 1) + return false; + if (!pair && mIns[at].mAddress == from) + return false; + if (mIns[at].mAddress + 1 == from) + return false; + if (pair && mIns[at].mAddress == from + 1) + return false; + } + else if (mIns[at].mType == ASMIT_JSR) + { + fchanged = true; + + LinkerObject* lo = mIns[at].mLinkerObject; + if (lo) { - if (from >= lo->mTemporaries[i] && from < lo->mTemporaries[i] + lo->mTempSizes[i] || - to >= lo->mTemporaries[i] && to < lo->mTemporaries[i] + lo->mTempSizes[i]) + for (int i = 0; i < lo->mNumTemporaries; i++) + { + if (from >= lo->mTemporaries[i] && from < lo->mTemporaries[i] + lo->mTempSizes[i] || + to >= lo->mTemporaries[i] && to < lo->mTemporaries[i] + lo->mTempSizes[i]) return false; + } + } + + if (mIns[at].mFlags & NCIF_USE_ZP_32_X) + { + if (to >= mIns[at].mParam && to < mIns[at].mParam + 4 || + from >= mIns[at].mParam && from < mIns[at].mParam + 4) + return false; } } - if (mIns[at].mFlags & NCIF_USE_ZP_32_X) - { - if (to >= mIns[at].mParam && to < mIns[at].mParam + 4 || - from >= mIns[at].mParam && from < mIns[at].mParam + 4) - return false; - } + at++; } - at++; + if (mTrueJump && !mTrueJump->IsFinalZeroPageUse(block, 0, from, to, pair, fchanged)) + return false; + if (mFalseJump && !mFalseJump->IsFinalZeroPageUse(block, 0, from, to, pair, fchanged)) + return false; } - - if (mTrueJump && !mTrueJump->IsFinalZeroPageUse(block, 0, from, to, pair)) - return false; - if (mFalseJump && !mFalseJump->IsFinalZeroPageUse(block, 0, from, to, pair)) - return false; } return true; @@ -25204,7 +26484,7 @@ bool NativeCodeBasicBlock::ReplaceFinalZeroPageUse(NativeCodeProcedure* nproc) mIns[i + 1].mAddress >= BC_REG_TMP) { nproc->ResetPatched(); - if (IsFinalZeroPageUse(this, i + 2, mIns[i + 1].mAddress, mIns[i + 0].mAddress, false)) + if (IsFinalZeroPageUse(this, i + 2, mIns[i + 1].mAddress, mIns[i + 0].mAddress, false, false)) { nproc->ResetPatched(); if (ForwardReplaceZeroPage(i + 2, mIns[i + 1].mAddress, mIns[i + 0].mAddress)) @@ -25223,7 +26503,7 @@ bool NativeCodeBasicBlock::ReplaceFinalZeroPageUse(NativeCodeProcedure* nproc) mIns[i + 1].mAddress >= BC_REG_TMP) { nproc->ResetPatched(); - if (IsFinalZeroPageUse(this, i + 4, mIns[i + 1].mAddress, mIns[i + 0].mAddress, true)) + if (IsFinalZeroPageUse(this, i + 4, mIns[i + 1].mAddress, mIns[i + 0].mAddress, true, false)) { nproc->ResetPatched(); if (ForwardReplaceZeroPage(i + 4, mIns[i + 1].mAddress, mIns[i + 0].mAddress)) @@ -25249,7 +26529,7 @@ bool NativeCodeBasicBlock::ReplaceFinalZeroPageUse(NativeCodeProcedure* nproc) mIns[i + 2].mAddress >= BC_REG_TMP) { nproc->ResetPatched(); - if (IsFinalZeroPageUse(this, i + 6, mIns[i + 2].mAddress, mIns[i + 0].mAddress, true)) + if (IsFinalZeroPageUse(this, i + 6, mIns[i + 2].mAddress, mIns[i + 0].mAddress, true, false)) { nproc->ResetPatched(); if (ForwardReplaceZeroPage(i + 6, mIns[i + 2].mAddress, mIns[i + 0].mAddress)) @@ -25274,7 +26554,7 @@ bool NativeCodeBasicBlock::ReplaceFinalZeroPageUse(NativeCodeProcedure* nproc) mIns[i + 1].mAddress >= BC_REG_TMP) { nproc->ResetPatched(); - if (IsFinalZeroPageUse(this, i + 5, mIns[i + 1].mAddress, mIns[i + 0].mAddress, true)) + if (IsFinalZeroPageUse(this, i + 5, mIns[i + 1].mAddress, mIns[i + 0].mAddress, true, false)) { nproc->ResetPatched(); if (ForwardReplaceZeroPage(i + 5, mIns[i + 1].mAddress, mIns[i + 0].mAddress)) @@ -25472,6 +26752,9 @@ bool NativeCodeBasicBlock::ForwardReplaceZeroPage(int at, int from, int to) changed = true; if (mFalseJump && mFalseJump->ForwardReplaceZeroPage(0, from, to)) changed = true; + + if (mEntryRequiredRegs[from]) + mEntryRequiredRegs += to; } return changed; @@ -26230,6 +27513,105 @@ bool NativeCodeBasicBlock::FoldShiftORAIntoLoadImmUp(int at) return false; } +// TAX +// CLC +// ADC #1, 2, 3 +// STA +// +// convert to INX/DEX/STX when X not needed anymore + +bool NativeCodeBasicBlock::MoveTAXADCSTADown(int at) +{ + int n = mIns[at + 2].mAddress; + int addr = mIns[at + 3].mAddress; + + int si = at + 4; + while (si < mIns.Size()) + { + if (!(mIns[si].mLive & LIVE_CPU_REG_X)) + { + if (mIns[si].mLive & LIVE_CPU_REG_Z) + return false; + + mIns[si].mLive |= LIVE_CPU_REG_X; + si++; + + for (int i = 0; i < n; i++) + { + mIns.Insert(si, NativeCodeInstruction(mIns[at].mIns, ASMIT_INX)); + si++; + } + mIns.Insert(si, NativeCodeInstruction(mIns[at].mIns, ASMIT_STX, ASMIM_ZERO_PAGE, addr)); + return true; + } + + if (mIns[si].ChangesXReg()) + return false; + if (mIns[si].ReferencesZeroPage(addr)) + return false; + + si++; + } + + return false; +} + + +// CLC +// LDA zp0 +// ADC #1, 2, 3 +// STA zp1 +// ... +// LDX zp1 +// +// Convert to INX/DEX + +bool NativeCodeBasicBlock::MoveSimpleADCToINCDECDown(int at) +{ + if (at >= 4) + { + int si = at - 4; + + while (si >= 0) + { + if (mIns[si + 3].ReferencesZeroPage(mIns[at].mAddress)) + { + if (mIns[si + 0].mType == ASMIT_CLC && + mIns[si + 1].mType == ASMIT_LDA && mIns[si + 1].mMode == ASMIM_ZERO_PAGE && + mIns[si + 2].mType == ASMIT_ADC && mIns[si + 2].mMode == ASMIM_IMMEDIATE && (mIns[si + 2].mAddress >= 0 && mIns[si + 2].mAddress <= 4) && + mIns[si + 3].mType == ASMIT_STA && !(mIns[si + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C))) + { + int i = si + 4; + while (i < at && !mIns[i].ChangesZeroPage(mIns[si + 1].mAddress)) + i++; + if (i != at) + return false; + + AsmInsType t = mIns[at].mType == ASMIT_LDX ? ASMIT_INX : ASMIT_INY; + + mIns[at].mAddress = mIns[si + 1].mAddress; + for (int i = 0; i < mIns[si + 2].mAddress; i++) + mIns.Insert(at + 1, NativeCodeInstruction(mIns[si].mIns, t)); + + mIns[si + 0].mType = ASMIT_NOP; mIns[si + 0].mMode = ASMIM_IMPLIED; + mIns[si + 1].mType = ASMIT_NOP; mIns[si + 1].mMode = ASMIM_IMPLIED; + mIns[si + 2].mType = ASMIT_NOP; mIns[si + 2].mMode = ASMIM_IMPLIED; + mIns[si + 3].mType = ASMIT_NOP; mIns[si + 3].mMode = ASMIM_IMPLIED; + + return true; + } + else + return false; + } + + si--; + } + + } + + return false; +} + bool NativeCodeBasicBlock::CombineImmediateADCUp(int at) { int addr = mIns[at].mAddress; @@ -26644,6 +28026,58 @@ bool NativeCodeBasicBlock::ReverseLoadCommutativeOpUp(int aload, int aop) return false; } +bool NativeCodeBasicBlock::MoveTYADCStoreDown(int at) +{ + // [at + 0] TYA + // [at + 1] CLC + // [at + 2] ADC # + // [at + 3] STA + + int offset = mIns[at + 2].mAddress; + int addr = mIns[at + 3].mAddress; + + for (int i = at + 4; i < mIns.Size(); i++) + { + NativeCodeInstruction& ins(mIns[i]); + + if (mIns[i].mType == ASMIT_INY) + offset--; + else if (mIns[i].mType == ASMIT_DEY) + offset++; + else if (mIns[i].ChangesYReg()) + return false; + else if (mIns[i].ReferencesZeroPage(addr)) + return false; + else if (!(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Y | LIVE_CPU_REG_Z))) + { + if (offset < -2 || offset > 2) + return false; + while (offset < 0) + { + mIns.Insert(i, NativeCodeInstruction(mIns[at].mIns, ASMIT_DEY)); + offset++; + i++; + } + while (offset > 0) + { + mIns.Insert(i, NativeCodeInstruction(mIns[at].mIns, ASMIT_INY)); + offset--; + i++; + } + mIns.Insert(i, NativeCodeInstruction(mIns[at].mIns, ASMIT_STY, ASMIM_ZERO_PAGE, addr)); + while (i > at) + { + mIns[i].mLive |= LIVE_CPU_REG_Y; + i--; + } + mIns.Remove(at, 4); + return true; + } + } + + return false; +} + bool NativeCodeBasicBlock::MoveLDSTXOutOfRange(int at) { int j = at + 2; @@ -26662,7 +28096,7 @@ bool NativeCodeBasicBlock::MoveLDSTXOutOfRange(int at) if (mIns[j].mType == ASMIT_JSR) return false; - if (!(mIns[j].mLive & LIVE_CPU_REG_A)) + if (!(mIns[j].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))) { mIns.Insert(j + 1, NativeCodeInstruction(mIns[at + 1].mIns, ASMIT_STA, mIns[at + 1])); mIns.Insert(j + 1, NativeCodeInstruction(mIns[at].mIns, ASMIT_LDA, mIns[at])); @@ -26833,6 +28267,11 @@ bool NativeCodeBasicBlock::MoveCLCLoadAddZPStoreDown(int at) mIns.Insert(j, mIns[at + 1]); // LDA mIns.Insert(j, mIns[at + 0]); // CLC + mIns[j + 0].mLive |= mIns[j - 1].mLive; + mIns[j + 1].mLive |= mIns[j - 1].mLive; + mIns[j + 2].mLive |= mIns[j - 1].mLive; + mIns[j + 3].mLive |= mIns[j - 1].mLive; + mIns[at + 0].mType = ASMIT_NOP; mIns[at + 0].mMode = ASMIM_IMPLIED; mIns[at + 1].mType = ASMIT_NOP; mIns[at + 1].mMode = ASMIM_IMPLIED; mIns[at + 2].mType = ASMIT_NOP; mIns[at + 2].mMode = ASMIM_IMPLIED; @@ -26983,11 +28422,6 @@ bool NativeCodeBasicBlock::ReverseBitfieldForwarding(void) return changed; } -struct NativeCodeLoadStorePair -{ - NativeCodeInstruction mLoad, mStore; -}; - bool NativeCodeBasicBlock::RemoveLocalUnusedLinkerObjects(void) { bool changed = false; @@ -27038,7 +28472,7 @@ void NativeCodeBasicBlock::MarkLocalUsedLinkerObjects(void) } } -bool NativeCodeBasicBlock::AbsoluteValueForwarding(void) +bool NativeCodeBasicBlock::AbsoluteValueForwarding(const ExpandingArray & npairs) { bool changed = false; @@ -27047,6 +28481,8 @@ bool NativeCodeBasicBlock::AbsoluteValueForwarding(void) mVisited = true; ExpandingArray pairs; + if (mNumEntries == 1) + pairs = npairs; int ains = -1; @@ -27119,9 +28555,9 @@ bool NativeCodeBasicBlock::AbsoluteValueForwarding(void) } } - if (mTrueJump && mTrueJump->AbsoluteValueForwarding()) + if (mTrueJump && mTrueJump->AbsoluteValueForwarding(pairs)) changed = true; - if (mFalseJump && mFalseJump->AbsoluteValueForwarding()) + if (mFalseJump && mFalseJump->AbsoluteValueForwarding(pairs)) changed = true; } @@ -28217,15 +29653,19 @@ bool NativeCodeBasicBlock::OptimizeSingleEntryLoop(NativeCodeProcedure* proc) i++; } - int aimm = -1; + bool aimm = false; + NativeCodeInstruction ains; if (!pblock->mExitRequiredRegs[CPU_REG_A] || !pblock->mExitRequiredRegs[CPU_REG_X]) { for (int i = 0; i < mIns.Size(); i++) { - if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_IMMEDIATE) - aimm = mIns[i].mAddress; - else if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && aimm >= 0) + if (mIns[i].mType == ASMIT_LDA && (mIns[i].mMode == ASMIM_IMMEDIATE || mIns[i].mMode == ASMIM_IMMEDIATE_ADDRESS)) + { + aimm = true; + ains = mIns[i]; + } + else if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && aimm) { int reg = mIns[i].mAddress; if (!ReferencedOnPath(this, 0, i, reg) && !ChangedOnPath(this, i + 1, mIns.Size(), reg)) @@ -28237,12 +29677,12 @@ bool NativeCodeBasicBlock::OptimizeSingleEntryLoop(NativeCodeProcedure* proc) { if (!pblock->mExitRequiredRegs[CPU_REG_A]) { - pblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, aimm)); + pblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ains)); pblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, reg)); } else if (!pblock->mExitRequiredRegs[CPU_REG_X]) { - pblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDX, ASMIM_IMMEDIATE, aimm)); + pblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDX, ains)); pblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_STX, ASMIM_ZERO_PAGE, reg)); } @@ -28263,7 +29703,7 @@ bool NativeCodeBasicBlock::OptimizeSingleEntryLoop(NativeCodeProcedure* proc) } } else if (mIns[i].ChangesAccu()) - aimm = -1; + aimm = false; } } } @@ -28355,7 +29795,8 @@ bool NativeCodeBasicBlock::OptimizeLoopCarryOver(void) mExitRequiredRegs += CPU_REG_Y; changed = true; } - else if (sz > 1 && hblock->mIns[0].mType == ASMIT_LDA && mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 2].mType == ASMIT_LDA && hblock->mIns[0].SameEffectiveAddress(mIns[sz - 2]) && !(hblock->mIns[0].mLive & LIVE_CPU_REG_Z)) + else if (sz > 1 && hblock->mIns[0].mType == ASMIT_LDA && mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 2].mType == ASMIT_LDA + && hblock->mIns[0].SameEffectiveAddress(mIns[sz - 2]) && !(hblock->mIns[0].mLive & LIVE_CPU_REG_Z) && !(hblock->mIns[0].mFlags & NCIF_VOLATILE)) { pblock->mIns.Push(hblock->mIns[0]); hblock->mIns.Remove(0); @@ -28588,6 +30029,8 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc mIns[1].mType = ASMIT_LDA; mIns[1].mLive |= LIVE_CPU_REG_A; mIns[0].mType = ASMIT_CMP; mIns[0].mLive |= LIVE_CPU_REG_Z; prevBlock->mIns.Push(mIns[1]); + prevBlock->mExitRequiredRegs += CPU_REG_A; + mEntryRequiredRegs += CPU_REG_A; mIns.Remove(1); CheckLive(); @@ -28866,7 +30309,7 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc i++; while (i < mIns.Size() && !mIns[i].ReferencesZeroPage(mIns[si].mAddress)) i++; - if (i < mIns.Size() && (mIns[i].mType == ASMIT_DEC || mIns[i].mType == ASMIT_INC)) + if (i < mIns.Size() && (mIns[i].mType == ASMIT_DEC || mIns[i].mType == ASMIT_INC) && (!(mIns[ei].mLive & LIVE_CPU_REG_Z) || mIns[ei].ChangesAccuAndFlag())) { int j = i + 1; while (j < mIns.Size() && !mIns[j].ReferencesZeroPage(mIns[si].mAddress)) @@ -28876,6 +30319,9 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc // So we have an LDX from ZP, and exactly one INC/DECof this ZP and X never changes in the loop if (!prevBlock) return OptimizeSimpleLoopInvariant(proc, full); + + bool needRecheck = mIns[ei].mLive & LIVE_CPU_REG_Z; + prevBlock->mIns.Push(mIns[si]); exitBlock->mIns.Insert(0, NativeCodeInstruction(mIns[si].mIns, ASMIT_STX, mIns[si])); mIns[si].mType = ASMIT_NOP; @@ -28890,6 +30336,12 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED; + if (needRecheck) + { + mIns[ei].mLive |= LIVE_CPU_REG_A; + mIns.Insert(ei + 1, NativeCodeInstruction(mIns[ei].mIns, ASMIT_ORA, ASMIM_IMMEDIATE, 0)); + } + mIns.Insert(ei + 1, NativeCodeInstruction(mIns[i].mIns, t)); for (int i = 0; i < mIns.Size(); i++) @@ -29278,6 +30730,8 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc mIns.Remove(ai); mEntryRequiredRegs += CPU_REG_A; + for (int i = 0; i < mIns.Size(); i++) + mIns[i].mLive |= LIVE_CPU_REG_A; mExitRequiredRegs += CPU_REG_A; prevBlock->mExitRequiredRegs += CPU_REG_A; @@ -29457,7 +30911,7 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc } mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; } - else if (j > i && !(mIns[i + 0].mLive & LIVE_MEM) && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) && !mExitRequiredRegs[mIns[i + 1].mAddress]) + else if (j > i && !(mIns[i + 0].mLive & LIVE_MEM) && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) && !mExitRequiredRegs[mIns[i + 1].mAddress] && !ReferencesZeroPage(mIns[i + 0].mAddress, 0, i)) { int j = mIns.Size() - 1; @@ -30139,6 +31593,7 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoop(NativeCodeProcedure * proc, bool f mBranch = ASMIT_BCC; mIns[sz - 2].mMode = ASMIM_ZERO_PAGE; mIns[sz - 2].mAddress = mIns[sz - 1].mAddress; mIns[sz - 1].mMode = ASMIM_IMMEDIATE; mIns[sz - 1].mAddress = val; + mIns[sz - 2].mLive |= mIns[sz - 1].mLive & LIVE_MEM; } else if (mBranch == ASMIT_BCC && mIns[sz - 2].mAddress < 0xff) { @@ -30146,12 +31601,14 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoop(NativeCodeProcedure * proc, bool f mBranch = ASMIT_BCS; mIns[sz - 2].mMode = ASMIM_ZERO_PAGE; mIns[sz - 2].mAddress = mIns[sz - 1].mAddress; mIns[sz - 1].mMode = ASMIM_IMMEDIATE; mIns[sz - 1].mAddress = val; + mIns[sz - 2].mLive |= mIns[sz - 1].mLive & LIVE_MEM; } else if ((mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE) && !(mIns[sz - 1].mLive & LIVE_CPU_REG_C)) { int val = mIns[sz - 2].mAddress; mIns[sz - 2].mMode = ASMIM_ZERO_PAGE; mIns[sz - 2].mAddress = mIns[sz - 1].mAddress; mIns[sz - 1].mMode = ASMIM_IMMEDIATE; mIns[sz - 1].mAddress = val; + mIns[sz - 2].mLive |= mIns[sz - 1].mLive & LIVE_MEM; } } #endif @@ -30412,7 +31869,7 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoop(NativeCodeProcedure * proc, bool f { // check for usage of Y register - bool yother = false, yindex = false; + bool yother = false, yindex = false, xother = false, xindex = false; int zreg = mIns[sz - 1].mAddress; int yinc = 0, xinc = 0; @@ -30420,6 +31877,8 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoop(NativeCodeProcedure * proc, bool f if (mIns[sz - 1].mLive & LIVE_CPU_REG_Y) yother = true; + if (mIns[sz - 1].mLive & LIVE_CPU_REG_X) + xother = true; for (int i = 0; i < sz - 1; i++) { @@ -30443,6 +31902,27 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoop(NativeCodeProcedure * proc, bool f yother = true; else if (mIns[i].mType != ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg) yother = true; + + if (mIns[i].mType == ASMIT_TAX) + xother = true; + else if (mIns[i].mType == ASMIT_INX) + xinc++; + else if (mIns[i].mType == ASMIT_DEX) + xinc--; + else if (mIns[i].mType == ASMIT_LDX) + { + if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg && xinc >= -1 && xinc <= 1) + { + xinc = 0; + xindex = true; + } + else + xother = true; + } + else if (!xindex && (mIns[i].mType == ASMIT_STX || mIns[i].mType == ASMIT_TXA || mIns[i].mMode == ASMIM_ABSOLUTE_X)) + xother = true; + else if (mIns[i].mType != ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg) + xother = true; } if (!yother) @@ -30526,6 +32006,89 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoop(NativeCodeProcedure * proc, bool f changed = true; + assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV); + } + else if (!xother) + { + int linc = xinc + 1; + + NativeCodeBasicBlock* lblock = proc->AllocateBlock(); + NativeCodeBasicBlock* eblock = proc->AllocateBlock(); + + yinc = 0; + for (int i = 0; i + 1 < sz; i++) + { + mIns[i].mLive |= LIVE_CPU_REG_X; + + if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg) + lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_TXA, ASMIM_IMPLIED)); + else if (mIns[i].mType == ASMIT_LDX) + { + if (yinc > 0) + lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_DEX)); + else if (yinc < 0) + lblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_INX)); + yinc = 0; + } + else + { + lblock->mIns.Push(mIns[i]); + if (mIns[i].mType == ASMIT_INX) + yinc++; + else if (mIns[i].mType == ASMIT_DEX) + yinc--; + } + } + + if (linc == 0) + { + lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_CPX, ASMIM_IMMEDIATE, 0)); + } + else + { + while (linc < 0) + { + lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_INX, ASMIM_IMPLIED)); + linc++; + } + while (linc > 0) + { + lblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_DEX, ASMIM_IMPLIED)); + linc--; + } + } + + lblock->mBranch = mBranch; + lblock->mTrueJump = lblock; + lblock->mFalseJump = eblock; + + eblock->mIns.Push(NativeCodeInstruction(iins, ASMIT_STX, ASMIM_ZERO_PAGE, zreg)); + eblock->mBranch = ASMIT_JMP; + eblock->mTrueJump = mFalseJump; + eblock->mFalseJump = nullptr; + + lblock->mEntryRequiredRegs = mEntryRequiredRegs; + lblock->mExitRequiredRegs = mExitRequiredRegs; + eblock->mEntryRequiredRegs = mExitRequiredRegs; + eblock->mExitRequiredRegs = mExitRequiredRegs; + mExitRequiredRegs = mEntryRequiredRegs; + mExitRequiredRegs += CPU_REG_X; + lblock->mEntryRequiredRegs += CPU_REG_X; + lblock->mExitRequiredRegs += CPU_REG_X; + eblock->mEntryRequiredRegs += CPU_REG_X; + + mIns.SetSize(0); + mIns.Push(NativeCodeInstruction(iins, ASMIT_LDX, ASMIM_ZERO_PAGE, zreg)); + mBranch = ASMIT_JMP; + mTrueJump = lblock; + mFalseJump = nullptr; + + lblock->OptimizeSimpleLoopInvariant(proc, this, eblock, full); + + lblock->CheckLive(); + + changed = true; + assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV); } } @@ -31063,7 +32626,7 @@ bool NativeCodeBasicBlock::OptimizeGenericLoop(NativeCodeProcedure* proc) ExpandingArray lblocks; proc->ResetPatched(); - if (CollectGenericLoop(proc, lblocks)) + if (CollectSingleEntryGenericLoop(proc, lblocks)) { int yreg = -1, xreg = -1, areg = -1; int zyreg[NUM_REGS], zxreg[NUM_REGS], zareg[NUM_REGS]; @@ -31086,6 +32649,7 @@ bool NativeCodeBasicBlock::OptimizeGenericLoop(NativeCodeProcedure* proc) NativeCodeBasicBlock* block = lblocks[i]; int yoffset = 0, xoffset = 0, aoffset = 0; + int yskew = 0, xskew = 0; for (int j = 0; j < block->mIns.Size(); j++) { @@ -31104,6 +32668,7 @@ bool NativeCodeBasicBlock::OptimizeGenericLoop(NativeCodeProcedure* proc) zareg[ins.mAddress] = -1; } yoffset = 0; + yskew = 0; zareg[CPU_REG_Y] = -1; break; case ASMIT_LDX: @@ -31117,6 +32682,7 @@ bool NativeCodeBasicBlock::OptimizeGenericLoop(NativeCodeProcedure* proc) zareg[ins.mAddress] = -1; } xoffset = 0; + xskew = 0; zareg[CPU_REG_X] = -1; break; case ASMIT_STY: @@ -31150,13 +32716,55 @@ bool NativeCodeBasicBlock::OptimizeGenericLoop(NativeCodeProcedure* proc) zareg[CPU_REG_X] = -1; break; case ASMIT_INC: + if (ins.mMode == ASMIM_ZERO_PAGE) + { + if (zxreg[ins.mAddress] >= 0) + { + if (ins.mLive & LIVE_CPU_REG_X) + zxreg[ins.mAddress] = -1; + else + { + zxreg[ins.mAddress] += 3; + xskew++; + } + } + if (zyreg[ins.mAddress] >= 0) + { + if (ins.mLive & LIVE_CPU_REG_Y) + zyreg[ins.mAddress] = -1; + else + { + zyreg[ins.mAddress] += 3; + yskew++; + } + } + + zareg[ins.mAddress] = -1; + } + break; case ASMIT_DEC: if (ins.mMode == ASMIM_ZERO_PAGE) { if (zxreg[ins.mAddress] >= 0) - zxreg[ins.mAddress] += 3; + { + if (ins.mLive & LIVE_CPU_REG_X) + zxreg[ins.mAddress] = -1; + else + { + zxreg[ins.mAddress] += 3; + xskew--; + } + } if (zyreg[ins.mAddress] >= 0) - zyreg[ins.mAddress] += 3; + { + if (ins.mLive & LIVE_CPU_REG_Y) + zyreg[ins.mAddress] = -1; + else + { + zyreg[ins.mAddress] += 3; + yskew--; + } + } zareg[ins.mAddress] = -1; } @@ -31250,6 +32858,11 @@ bool NativeCodeBasicBlock::OptimizeGenericLoop(NativeCodeProcedure* proc) areg = -2; } + if (xreg >= 0 && ins.mMode == ASMIM_ABSOLUTE_X && xskew != xoffset) + zxreg[xreg] = -1; + if (yreg >= 0 && (ins.mMode == ASMIM_ABSOLUTE_Y || ins.mMode == ASMIM_INDIRECT_Y) && yskew != yoffset) + zyreg[yreg] = -1; + if (!(ins.mLive & LIVE_CPU_REG_Y)) yoffset = 0; if (!(ins.mLive & LIVE_CPU_REG_X)) @@ -31349,47 +32962,6 @@ bool NativeCodeBasicBlock::OptimizeGenericLoop(NativeCodeProcedure* proc) block->mExitRequiredRegs += CPU_REG_A; } - if (block->mTrueJump && !lblocks.Contains(block->mTrueJump)) - { - block->mTrueJump = block->BuildSingleEntry(proc, block->mTrueJump); - if (areg >= 0 && block->mTrueJump->mEntryRequiredRegs[areg]) - { - if (areg < 256) - block->mTrueJump->mIns.Insert(0, NativeCodeInstruction(block->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, areg)); - block->mTrueJump->mEntryRequiredRegs += CPU_REG_A; - } - if (yreg >= 0 && block->mTrueJump->mEntryRequiredRegs[yreg]) - { - block->mTrueJump->mIns.Insert(0, NativeCodeInstruction(block->mBranchIns, ASMIT_STY, ASMIM_ZERO_PAGE, yreg)); - block->mTrueJump->mEntryRequiredRegs += CPU_REG_Y; - } - if (xreg >= 0 && block->mTrueJump->mEntryRequiredRegs[xreg]) - { - block->mTrueJump->mIns.Insert(0, NativeCodeInstruction(block->mBranchIns, ASMIT_STX, ASMIM_ZERO_PAGE, xreg)); - block->mTrueJump->mEntryRequiredRegs += CPU_REG_X; - } - } - if (block->mFalseJump && !lblocks.Contains(block->mFalseJump)) - { - block->mFalseJump = block->BuildSingleEntry(proc, block->mFalseJump); - if (areg >= 0 && block->mFalseJump->mEntryRequiredRegs[areg]) - { - if (areg < 256) - block->mFalseJump->mIns.Insert(0, NativeCodeInstruction(block->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, areg)); - block->mFalseJump->mEntryRequiredRegs += CPU_REG_A; - } - if (yreg >= 0 && block->mFalseJump->mEntryRequiredRegs[yreg]) - { - block->mFalseJump->mIns.Insert(0, NativeCodeInstruction(block->mBranchIns, ASMIT_STY, ASMIM_ZERO_PAGE, yreg)); - block->mFalseJump->mEntryRequiredRegs += CPU_REG_Y; - } - if (xreg >= 0 && block->mFalseJump->mEntryRequiredRegs[xreg]) - { - block->mFalseJump->mIns.Insert(0, NativeCodeInstruction(block->mBranchIns, ASMIT_STX, ASMIM_ZERO_PAGE, xreg)); - block->mFalseJump->mEntryRequiredRegs += CPU_REG_X; - } - } - for (int j = 0; j < block->mEntryBlocks.Size(); j++) { if (!lblocks.Contains(block->mEntryBlocks[j])) @@ -31418,7 +32990,7 @@ bool NativeCodeBasicBlock::OptimizeGenericLoop(NativeCodeProcedure* proc) } } - int yoffset = 0, xoffset = 0; + int yoffset = 0, xoffset = 0, xskew = 0, yskew = 0; for (int j = 0; j < block->mIns.Size(); j++) { @@ -31433,6 +33005,7 @@ bool NativeCodeBasicBlock::OptimizeGenericLoop(NativeCodeProcedure* proc) ins.mType = ASMIT_NOP; ins.mMode = ASMIM_IMPLIED; yoffset = 0; + yskew = 0; } break; case ASMIT_LDX: @@ -31442,6 +33015,7 @@ bool NativeCodeBasicBlock::OptimizeGenericLoop(NativeCodeProcedure* proc) ins.mType = ASMIT_NOP; ins.mMode = ASMIM_IMPLIED; xoffset = 0; + xskew = 0; } break; case ASMIT_INC: @@ -31449,11 +33023,13 @@ bool NativeCodeBasicBlock::OptimizeGenericLoop(NativeCodeProcedure* proc) { ins.mType = ASMIT_INY; ins.mMode = ASMIM_IMPLIED; + yskew += 1; } else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == xreg) { ins.mType = ASMIT_INX; ins.mMode = ASMIM_IMPLIED; + xskew += 1; } break; case ASMIT_DEC: @@ -31461,11 +33037,13 @@ bool NativeCodeBasicBlock::OptimizeGenericLoop(NativeCodeProcedure* proc) { ins.mType = ASMIT_DEY; ins.mMode = ASMIM_IMPLIED; + yskew -= 1; } else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == xreg) { ins.mType = ASMIT_DEX; ins.mMode = ASMIM_IMPLIED; + xskew -= 1; } break; @@ -31582,6 +33160,47 @@ bool NativeCodeBasicBlock::OptimizeGenericLoop(NativeCodeProcedure* proc) } + if (block->mTrueJump && !lblocks.Contains(block->mTrueJump)) + { + block->mTrueJump = block->BuildSingleEntry(proc, block->mTrueJump); + if (areg >= 0 && block->mTrueJump->mEntryRequiredRegs[areg]) + { + if (areg < 256) + block->mTrueJump->mIns.Insert(0, NativeCodeInstruction(block->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, areg)); + block->mTrueJump->mEntryRequiredRegs += CPU_REG_A; + } + if (yreg >= 0 && block->mTrueJump->mEntryRequiredRegs[yreg]) + { + block->mTrueJump->mIns.Insert(0, NativeCodeInstruction(block->mBranchIns, ASMIT_STY, ASMIM_ZERO_PAGE, yreg)); + block->mTrueJump->mEntryRequiredRegs += CPU_REG_Y; + } + if (xreg >= 0 && block->mTrueJump->mEntryRequiredRegs[xreg]) + { + block->mTrueJump->mIns.Insert(0, NativeCodeInstruction(block->mBranchIns, ASMIT_STX, ASMIM_ZERO_PAGE, xreg)); + block->mTrueJump->mEntryRequiredRegs += CPU_REG_X; + } + } + if (block->mFalseJump && !lblocks.Contains(block->mFalseJump)) + { + block->mFalseJump = block->BuildSingleEntry(proc, block->mFalseJump); + if (areg >= 0 && block->mFalseJump->mEntryRequiredRegs[areg]) + { + if (areg < 256) + block->mFalseJump->mIns.Insert(0, NativeCodeInstruction(block->mBranchIns, ASMIT_STA, ASMIM_ZERO_PAGE, areg)); + block->mFalseJump->mEntryRequiredRegs += CPU_REG_A; + } + if (yreg >= 0 && block->mFalseJump->mEntryRequiredRegs[yreg]) + { + block->mFalseJump->mIns.Insert(0, NativeCodeInstruction(block->mBranchIns, ASMIT_STY, ASMIM_ZERO_PAGE, yreg)); + block->mFalseJump->mEntryRequiredRegs += CPU_REG_Y; + } + if (xreg >= 0 && block->mFalseJump->mEntryRequiredRegs[xreg]) + { + block->mFalseJump->mIns.Insert(0, NativeCodeInstruction(block->mBranchIns, ASMIT_STX, ASMIM_ZERO_PAGE, xreg)); + block->mFalseJump->mEntryRequiredRegs += CPU_REG_X; + } + } + block->CheckLive(); } @@ -31646,6 +33265,28 @@ bool NativeCodeBasicBlock::CollectGenericLoop(NativeCodeProcedure* proc, Expandi return lblocks.Size() > 0; } +bool NativeCodeBasicBlock::CollectSingleEntryGenericLoop(NativeCodeProcedure* proc, ExpandingArray& lblocks) +{ + if (CollectGenericLoop(proc, lblocks)) + { + for (int i = 0; i < lblocks.Size(); i++) + { + NativeCodeBasicBlock* block = lblocks[i]; + + if (block != this) + { + for (int j = 0; j < block->mEntryBlocks.Size(); j++) + if (!lblocks.Contains(block->mEntryBlocks[j])) + return false; + } + } + + return true; + } + else + return false; +} + bool NativeCodeBasicBlock::OptimizeFindLoop(NativeCodeProcedure* proc) { bool changed = false; @@ -31691,6 +33332,11 @@ bool NativeCodeBasicBlock::OptimizeFindLoop(NativeCodeProcedure* proc) body->mIns[fsz - 1].mMode = ASMIM_IMPLIED; mIns.Remove(0); + body->mEntryRequiredRegs += CPU_REG_Y; + body->mExitRequiredRegs += CPU_REG_Y; + mEntryRequiredRegs += CPU_REG_Y; + mExitRequiredRegs += CPU_REG_Y; + for (int i = 0; i < mIns.Size(); i++) mIns[i].mLive |= LIVE_CPU_REG_Y; for (int i = 0; i < fsz; i++) @@ -33048,6 +34694,8 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass bool changed = RemoveNops(); + mIns.Reserve(mIns.Size() * 2 + 32); + mVisited = true; CheckLive(); @@ -33172,7 +34820,6 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass } } CheckLive(); - #endif #if 1 @@ -33222,6 +34869,20 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass #endif +#if 1 + for (int i = 0; i + 4 < mIns.Size(); i++) + { + if (mIns[i + 0].mType == ASMIT_TYA && mIns[i + 1].mType == ASMIT_CLC && + mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && + mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z))) + { + if (MoveTYADCStoreDown(i)) + changed = true; + } + } + CheckLive(); +#endif + #if 1 // move load - store abs up to initial store // @@ -33229,7 +34890,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass for (int i = 2; i + 1 < mIns.Size(); i++) { if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mType == ASMIT_STA && - (mIns[i + 1].mMode == ASMIM_ABSOLUTE || mIns[i + 1].mMode == ASMIM_ABSOLUTE_X || mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y)) + (mIns[i + 1].mMode == ASMIM_ABSOLUTE || mIns[i + 1].mMode == ASMIM_ABSOLUTE_X || mIns[i + 1].mMode == ASMIM_ABSOLUTE_Y || mIns[i + 1].mMode == ASMIM_INDIRECT_Y)) { if (MoveAbsoluteLoadStoreUp(i)) changed = true; @@ -33368,6 +35029,34 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass } CheckLive(); +#endif + +#if 1 + for (int i = 0; i + 3 < mIns.Size(); i++) + { + if (mIns[i + 0].mType == ASMIT_TAX && mIns[i + 1].mType == ASMIT_CLC && + mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 && + mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z))) + + { + if (MoveTAXADCSTADown(i)) + changed = true; + } + } + + CheckLive(); +#endif + +#if 1 + for (int i = 0; i < mIns.Size(); i++) + { + if ((mIns[i + 0].mType == ASMIT_LDX || mIns[i + 0].mType == ASMIT_LDY) && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 0].mLive & LIVE_MEM)) + { + if (MoveSimpleADCToINCDECDown(i)) + changed = true; + } + } + #endif // @@ -33739,6 +35428,46 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass CheckLive(); #endif +#if 1 + // Move TAX and TAY down + + for (int i = 0; i + 1 < mIns.Size(); i++) + { + if (mIns[i].mType == ASMIT_TAX) + { + int j = i + 1; + while (j < mIns.Size() && !mIns[j].ReferencesXReg() && !mIns[j].ChangesAccu()) + j++; + if (j < mIns.Size() && mIns[j].mType == ASMIT_CPX && !(mIns[j].mLive & LIVE_CPU_REG_X)) + { + mIns[j].mType = ASMIT_CMP; + while (j > i) + { + j--; + mIns[j].mLive |= LIVE_CPU_REG_A; + } + changed = true; + } + } + else if (mIns[i].mType == ASMIT_TAY) + { + int j = i + 1; + while (j < mIns.Size() && !mIns[j].ReferencesYReg() && !mIns[j].ChangesAccu()) + j++; + if (j < mIns.Size() && mIns[j].mType == ASMIT_CPY && !(mIns[j].mLive & LIVE_CPU_REG_Y)) + { + mIns[j].mType = ASMIT_CMP; + while (j > i) + { + j--; + mIns[j].mLive |= LIVE_CPU_REG_A; + } + changed = true; + } + } + } + CheckLive(); +#endif #if 1 int taxPos = -1, tayPos = -1; for (int i = 0; i < mIns.Size(); i++) @@ -33945,6 +35674,39 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass #endif +#if 1 + for (int i = 0; i + 1 < mIns.Size(); i++) + { + if (mIns[i + 0].mType == ASMIT_ASL && mIns[i + 0].mMode == ASMIM_IMPLIED && + mIns[i + 1].mType == ASMIT_LSR && mIns[i + 1].mMode == ASMIM_IMPLIED && !(mIns[i + 1].mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_C))) + { + int j = 1; + while (i >= j && i + j + 1 < mIns.Size() && + mIns[i - j].mType == ASMIT_ASL && mIns[i - j].mMode == ASMIM_IMPLIED && + mIns[i + 1 + j].mType == ASMIT_LSR && mIns[i + 1 + j].mMode == ASMIM_IMPLIED && !(mIns[i + 1 + j].mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_C))) + j++; + mIns[i + 1 - j].mType = ASMIT_AND; + mIns[i + 1 - j].mMode = ASMIM_IMMEDIATE; + mIns[i + 1 - j].mAddress = 0xff >> j; + + while (j > 1) + { + mIns[i + j].mType = ASMIT_NOP; + mIns[i + j].mMode = ASMIM_IMPLIED; + j--; + mIns[i + 1 - j].mType = ASMIT_NOP; + mIns[i + 1 - j].mMode = ASMIM_IMPLIED; + } + mIns[i + 1].mType = ASMIT_NOP; + mIns[i + 1].mMode = ASMIM_IMPLIED; + changed = true; + } + } + + CheckLive(); + +#endif + #if 1 bool progress = false; do { @@ -34249,7 +36011,6 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass if (FindImmediateStore(i, mIns[i].mAddress + 1, ains)) { mIns.Insert(i, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDX, ASMIM_ZERO_PAGE, mIns[i].mAddress)); - mIns[i + 0].mLive = mIns[i + 1].mLive | LIVE_CPU_REG_X; mIns[i + 1].mMode = ASMIM_ABSOLUTE_X; if (ains->mMode == ASMIM_IMMEDIATE) @@ -34287,13 +36048,13 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass } else if (mIns[i].mType == ASMIT_STA && mIns[i + 1].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[i + 1].mAddress && (mIns[i + 1].mLive & LIVE_CPU_REG_Z) == 0) { - mIns[i + 1].mLive |= LIVE_CPU_REG_A; + mIns[i + 0].mLive |= LIVE_CPU_REG_A; mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; progress = true; } else if (mIns[i].mType == ASMIT_STA && mIns[i + 1].mType == ASMIT_LDA && mIns[i].SameEffectiveAddress(mIns[i + 1]) && !(mIns[i + 1].mFlags & NCIF_VOLATILE) && (mIns[i + 1].mLive & LIVE_CPU_REG_Z) == 0) { - mIns[i + 1].mLive |= LIVE_CPU_REG_A; + mIns[i + 0].mLive |= LIVE_CPU_REG_A; mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; progress = true; } @@ -34555,6 +36316,16 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; progress = true; } + else if ( + mIns[i + 0].mType == ASMIT_ROR && mIns[i + 0].mMode == ASMIM_IMPLIED && + mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED) + { + mIns[i + 0].mType = ASMIT_AND; + mIns[i + 0].mMode = ASMIM_IMMEDIATE; + mIns[i + 0].mAddress = 0xfe; + mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; + progress = true; + } else if ( (mIns[i + 0].mType == ASMIT_INX || mIns[i + 0].mType == ASMIT_DEX) && @@ -34621,6 +36392,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; progress = true; } + else if ( mIns[i + 0].mType == ASMIT_INX && mIns[i + 1].mType == ASMIT_DEX && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z)) @@ -34654,6 +36426,39 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass progress = true; } + else if ( + mIns[i + 0].mType == ASMIT_LDX && mIns[i + 0].mMode == ASMIM_IMMEDIATE && + mIns[i + 1].mType == ASMIT_DEX) + { + mIns[i + 0].mAddress = (mIns[i + 0].mAddress - 1) & 255; + mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; + progress = true; + } + else if ( + mIns[i + 0].mType == ASMIT_LDX && mIns[i + 0].mMode == ASMIM_IMMEDIATE && + mIns[i + 1].mType == ASMIT_INX) + { + mIns[i + 0].mAddress = (mIns[i + 0].mAddress + 1) & 255; + mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; + progress = true; + } + else if ( + mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && + mIns[i + 1].mType == ASMIT_DEY) + { + mIns[i + 0].mAddress = (mIns[i + 0].mAddress - 1) & 255; + mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; + progress = true; + } + else if ( + mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && + mIns[i + 1].mType == ASMIT_INY) + { + mIns[i + 0].mAddress = (mIns[i + 0].mAddress + 1) & 255; + mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; + progress = true; + } + else if ( mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_IMMEDIATE || mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE || mIns[i + 0].mMode == ASMIM_ABSOLUTE_X) && mIns[i + 1].mType == ASMIT_TAY && !(mIns[i + 1].mLive & LIVE_CPU_REG_A)) @@ -34762,7 +36567,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass mIns[i + 1].mType == ASMIT_AND && mIns[i + 1].mMode == ASMIM_IMMEDIATE && (mIns[i + 1].mAddress & 0x01) && !(mIns[i + 1].mLive & LIVE_CPU_REG_C)) { mIns[i + 0] = mIns[i + 1]; - mIns[i + 0].mLive |= LIVE_CPU_REG_C; + mIns[i + 0].mLive |= LIVE_CPU_REG_C | LIVE_CPU_REG_A; mIns[i + 0].mAddress = (mIns[i + 0].mAddress >> 1) & 0x7f; mIns[i + 1].mType = ASMIT_ROL; mIns[i + 1].mMode = ASMIM_IMPLIED; progress = true; @@ -34772,7 +36577,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass mIns[i + 1].mType == ASMIT_AND && mIns[i + 1].mMode == ASMIM_IMMEDIATE && (mIns[i + 1].mAddress & 0x80) && !(mIns[i + 1].mLive & LIVE_CPU_REG_C)) { mIns[i + 0] = mIns[i + 1]; - mIns[i + 0].mLive |= LIVE_CPU_REG_C; + mIns[i + 0].mLive |= LIVE_CPU_REG_C | LIVE_CPU_REG_A; mIns[i + 0].mAddress = (mIns[i + 0].mAddress << 1) & 0xfe; mIns[i + 1].mType = ASMIT_ROR; mIns[i + 1].mMode = ASMIM_IMPLIED; progress = true; @@ -34816,7 +36621,31 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass progress = true; } #endif - + else if ( + mIns[i + 0].mType == ASMIT_INC && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && + mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 1].mAddress && !(mIns[i + 1].mLive & LIVE_MEM)) + { + if (!(mIns[i + 0].mLive & LIVE_CPU_REG_X)) + { + mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= LIVE_CPU_REG_X; + mIns.Insert(i + 1, NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_INX)); + mIns[i + 2].mType = ASMIT_TXA; mIns[i + 2].mMode = ASMIM_IMPLIED; + progress = true; + } + else if (!(mIns[i + 0].mLive & LIVE_CPU_REG_Y)) + { + mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y; + mIns.Insert(i + 1, NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_INY)); + mIns[i + 2].mType = ASMIT_TYA; mIns[i + 2].mMode = ASMIM_IMPLIED; + progress = true; + } + else if (!(mIns[i + 0].mLive & LIVE_CPU_REG_C)) + { + mIns.Insert(i + 1, NativeCodeInstruction(mIns[i + 1].mIns, ASMIT_CLC)); + mIns[i + 2].mType = ASMIT_ADC; mIns[i + 2].mMode = ASMIM_IMMEDIATE; mIns[i + 2].mAddress = 1; + progress = true; + } + } #if 0 else if ( mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && @@ -34952,7 +36781,10 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass if (FindPageStartAddress(i, mIns[i + 1].mAddress, addr)) { if (mIns[i + 1].mLive & LIVE_CPU_REG_Y) + { mIns.Insert(i + 2, mIns[i + 0]); + mIns[i + 2].mLive |= mIns[i + 1].mLive; + } int absaddr = addr + mIns[i + 0].mAddress; @@ -35152,6 +36984,10 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass { mIns[i + 0].mType = ASMIT_LDY; mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; + if (mIns[i + 1].ChangesYReg()) + { + mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; + } mIns[i + 0].mLive |= LIVE_CPU_REG_Y; mIns[i + 1].mLive |= LIVE_CPU_REG_Y; progress = true; @@ -35567,7 +37403,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass } else if ( mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && - !mIns[i + 1].ChangesZeroPage(mIns[i + 0].mAddress) && !mIns[i + 1].RequiresYReg() && + !mIns[i + 1].ChangesZeroPage(mIns[i + 0].mAddress) && !mIns[i + 1].RequiresYReg() && !mIns[i + 1].ChangesYReg() && mIns[i + 2].mType == ASMIT_LDY && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 2].mLive & LIVE_MEM)) { mIns[i + 0].mType = ASMIT_TAY; mIns[i + 0].mMode = ASMIM_IMPLIED; @@ -35938,6 +37774,19 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; progress = true; } +#endif +#if 1 + else if ( + mIns[i + 0].mType == ASMIT_LSR && mIns[i + 0].mMode == ASMIM_IMPLIED && + mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 && + mIns[i + 2].mType == ASMIT_ROL && mIns[i + 2].mMode == ASMIM_IMPLIED && !(mIns[i + 2].mLive & LIVE_CPU_REG_C)) + { + mIns[i + 1].mType = ASMIT_AND; mIns[i + 1].mAddress = 1; + mIns[i + 0].mAddress &= (mIns[i + 2].mAddress << 1) | 1; + mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED; + mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; + progress = true; + } #endif else if ( mIns[i + 0].IsShift() && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && @@ -36182,6 +38031,15 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass mIns.Remove(i + 2); progress = true; } + else if ( + mIns[i + 0].mType == ASMIT_LDA && + mIns[i + 1].mType == ASMIT_STA && + mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && + !(mIns[i + 0].mMode == ASMIM_INDIRECT_Y && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && (mIns[i + 1].mAddress == mIns[i + 0].mAddress || mIns[i + 1].mAddress + 1 == mIns[i + 0].mAddress))) + { + mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; + progress = true; + } if ( mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress <= 1 && @@ -36354,7 +38212,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass else if ( mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 && mIns[i + 1].mType == ASMIT_ROL && mIns[i + 1].mMode == ASMIM_IMPLIED && - mIns[i + 2].mType == ASMIT_CLC && + mIns[i + 2].mType == ASMIT_CLC && mIns[i + 3].mType == ASMIT_ADC) { mIns[i + 1].mType = ASMIT_NOP; @@ -36421,20 +38279,21 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass progress = true; } else if ( - mIns[i + 0].mType == ASMIT_LDA && + mIns[i + 0].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !mIns[i + 0].MayBeChangedOnAddress(mIns[i + 1]) && mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mType == ASMIT_ORA && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && mIns[i + 3].mMode != ASMIM_IMMEDIATE) { + mIns[i + 1].mLive |= LIVE_CPU_REG_A; mIns[i + 2].mType = ASMIT_ORA; mIns[i + 2].mLive |= mIns[i + 3].mLive & LIVE_CPU_REG_Z; mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED; progress = true; } else if ( - mIns[i + 0].mType == ASMIT_LDA && + mIns[i + 0].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_EOR && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0xff && - mIns[i + 2].mType == ASMIT_SEC && + (mIns[i + 2].mType == ASMIT_SEC || mIns[i + 2].mType == ASMIT_CLC) && mIns[i + 3].mType == ASMIT_ADC) { mIns.Insert(i + 4, mIns[i + 0]); @@ -37280,8 +39139,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass // Flip arguments of ADC if second parameter in accu at entry mIns[i + 3].CopyMode(mIns[i + 2]); - mIns[i + 2].mMode = ASMIM_ZERO_PAGE; - mIns[i + 2].mAddress = mIns[i + 0].mAddress; + mIns[i + 2].CopyMode(mIns[i + 0]); progress = true; } @@ -37579,7 +39437,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass { mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 1].mType = ASMIT_STX; mIns[i + 1].CopyMode(mIns[i + 3]); - mIns[i + 3].mType = mIns[i + 2].mType; + mIns[i + 3].mType = mIns[i + 2].mType; mIns[i + 3].mLive |= LIVE_CPU_REG_A; mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED; progress = true; @@ -37593,11 +39451,38 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass { mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 1].mType = ASMIT_STY; mIns[i + 1].CopyMode(mIns[i + 3]); - mIns[i + 3].mType = mIns[i + 2].mType; + mIns[i + 3].mType = mIns[i + 2].mType; mIns[i + 3].mLive |= LIVE_CPU_REG_A; mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED; progress = true; } +#if 1 + else if ( + mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) && + (mIns[i + 1].mType == ASMIT_TAY || mIns[i + 1].mType == ASMIT_TAX) && + mIns[i + 2].mType == ASMIT_CLC && + mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && (mIns[i + 3].mAddress == 0xff || mIns[i + 3].mAddress == 0x01) && + mIns[i + 4].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 4]) && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C))) + { + if (mIns[i + 1].mType == ASMIT_TAY) + { + mIns[i + 0].mType = ASMIT_LDY; mIns[i + 0].mLive |= LIVE_CPU_REG_Y; + } + else + { + mIns[i + 0].mType = ASMIT_LDX; mIns[i + 0].mLive |= LIVE_CPU_REG_X; + } + + mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; + mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; + mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED; + if (mIns[i + 3].mAddress == 0x01) + mIns[i + 4].mType = ASMIT_INC; + else + mIns[i + 4].mType = ASMIT_DEC; + progress = true; + } +#endif #endif } #endif @@ -37781,6 +39666,26 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass progress = true; } #endif +#if 1 + else if ( + mIns[i + 0].mType == ASMIT_TYA && + mIns[i + 1].mType == ASMIT_TAX && + mIns[i + 2].mType == ASMIT_CLC && + mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress <= 2 && + mIns[i + 4].mType == ASMIT_TAY && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C))) + { + mIns[i + 0].mLive |= LIVE_CPU_REG_Y; + mIns[i + 1].mLive |= LIVE_CPU_REG_Y; + mIns[i + 2].mType = ASMIT_INY; mIns[i + 2].mLive |= LIVE_CPU_REG_Y; + mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED; + if (mIns[i + 3].mAddress > 1) + mIns[i + 4].mType = ASMIT_INY; + else + mIns[i + 4].mType = ASMIT_NOP; + + progress = true; + } +#endif #if 0 else if ( mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && @@ -38342,7 +40247,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass { int yval = RetrieveYValue(i); proc->ResetPatched(); - if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 1], i + 7, yval)) + if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 1], i + 7, yval, 0)) { proc->ResetPatched(); if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 1], i + 7, yval)) @@ -38373,7 +40278,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass { int yval = RetrieveYValue(i); proc->ResetPatched(); - if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval)) + if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval, 0)) { proc->ResetPatched(); if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval)) @@ -38394,15 +40299,30 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass if (mIns[i + 0].mType == ASMIT_CLC && mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && - mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress != mIns[i + 1].mAddress && + mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 3].mAddress + 1 && !(mIns[i + 6].mLive & LIVE_CPU_REG_A)) { int yval = RetrieveYValue(i); + + bool subs1 = mIns[i + 3].mAddress != mIns[i + 1].mAddress; + bool subs2 = mIns[i + 3].mAddress != mIns[i + 2].mAddress; + + if (subs1 && subs2) + { + if (mLoopHead) + { + if (ChangesZeroPage(mIns[i + 1].mAddress)) + subs2 = false; + else if (ChangesZeroPage(mIns[i + 2].mAddress)) + subs1 = false; + } + } + proc->ResetPatched(); - if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 1], i + 7, yval)) + if (subs1 && CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 1], i + 7, yval, 0)) { proc->ResetPatched(); if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 1], i + 7, yval)) @@ -38418,6 +40338,25 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass if (mFalseJump) mFalseJump->CheckLive(); } + else if (subs2) + { + proc->ResetPatched(); + if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval, 0)) + { + proc->ResetPatched(); + if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval)) + { + mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; + + progress = true; + } + + if (mTrueJump) + mTrueJump->CheckLive(); + if (mFalseJump) + mFalseJump->CheckLive(); + } + } } #endif #if 1 @@ -38432,7 +40371,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass { int yval = RetrieveYValue(i); proc->ResetPatched(); - if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 7, yval)) + if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 7, yval, 3)) { proc->ResetPatched(); if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 7, yval)) @@ -38466,7 +40405,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass { int yval = RetrieveYValue(i); proc->ResetPatched(); - if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 2].mAddress, mIns[i + 0], i + 7, yval)) + if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 2].mAddress, mIns[i + 0], i + 7, yval, 3)) { proc->ResetPatched(); if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 2].mAddress, mIns[i + 0], i + 7, yval)) @@ -38495,11 +40434,12 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 1].mAddress + 1 && mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 6].mType == ASMIT_STA && mIns[i + 6].mMode == ASMIM_ZERO_PAGE && mIns[i + 6].mAddress == mIns[i + 3].mAddress + 1 && + mIns[i + 2].mAddress != mIns[i + 3].mAddress && !(mIns[i + 6].mLive & LIVE_CPU_REG_A)) { int yval = RetrieveYValue(i); proc->ResetPatched(); - if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval)) + if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval, 3)) { proc->ResetPatched(); if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval)) @@ -38528,7 +40468,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass int yval = RetrieveYValue(i); proc->ResetPatched(); - if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval)) + if (CheckForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval, 3)) { proc->ResetPatched(); if (PatchForwardSumYPointer(this, mIns[i + 3].mAddress, mIns[i + 3].mAddress, mIns[i + 2], i + 7, yval)) @@ -38557,7 +40497,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass int yval = RetrieveYValue(i); proc->ResetPatched(); - if (CheckForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, mIns[i + 1], i + 7, yval)) + if (CheckForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, mIns[i + 1], i + 7, yval, 3)) { proc->ResetPatched(); if (PatchForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 2].mAddress, mIns[i + 1], i + 7, yval)) @@ -38584,7 +40524,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass { int yval = RetrieveYValue(i); proc->ResetPatched(); - if (CheckForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 6, yval)) + if (CheckForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 6, yval, 0)) { proc->ResetPatched(); if (PatchForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 6, yval)) @@ -38612,7 +40552,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass { int yval = RetrieveYValue(i); proc->ResetPatched(); - if (CheckForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 6, yval)) + if (CheckForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 6, yval, 3)) { proc->ResetPatched(); if (PatchForwardSumYPointer(this, mIns[i + 2].mAddress, mIns[i + 1].mAddress, mIns[i + 2], i + 6, yval)) @@ -38643,7 +40583,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass NativeCodeInstruction iins(mIns[i + 0].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, reg); proc->ResetPatched(); - if (CheckForwardSumYPointer(this, mIns[i + 1].mAddress, mIns[i + 1].mAddress, iins, i + 6, yval)) + if (CheckForwardSumYPointer(this, mIns[i + 1].mAddress, mIns[i + 1].mAddress, iins, i + 6, yval, 3)) { mIns[i + 0] = iins; for (int j = 1; j < 6; j++) @@ -38721,6 +40661,23 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass #endif } + if (i + 5 < mIns.Size() && + mIns[i + 0].mType == ASMIT_LSR && mIns[i + 0].mMode == ASMIM_IMPLIED && + mIns[i + 1].mType == ASMIT_LSR && mIns[i + 1].mMode == ASMIM_IMPLIED && + mIns[i + 2].mType == ASMIT_LSR && mIns[i + 2].mMode == ASMIM_IMPLIED && + mIns[i + 3].mType == ASMIT_LSR && mIns[i + 3].mMode == ASMIM_IMPLIED && + mIns[i + 4].mType == ASMIT_LSR && mIns[i + 4].mMode == ASMIM_IMPLIED && + mIns[i + 5].mType == ASMIT_LSR && mIns[i + 5].mMode == ASMIM_IMPLIED && !(mIns[i + 5].mLive & LIVE_CPU_REG_C)) + { + mIns[i + 0].mType = ASMIT_ASL; mIns[i + 0].mLive |= LIVE_CPU_REG_C; + mIns[i + 1].mType = ASMIT_ROL; mIns[i + 1].mLive |= LIVE_CPU_REG_C; + mIns[i + 2].mType = ASMIT_ROL; + mIns[i + 3].mType = ASMIT_NOP; + mIns[i + 4].mType = ASMIT_NOP; + mIns[i + 5].mType = ASMIT_AND; mIns[i + 5].mMode = ASMIM_IMMEDIATE; mIns[i + 5].mAddress = 3; + progress = true; + } + #if 1 if (i + 1 < mIns.Size() && mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 && mIns[i + 1].mMode == ASMIM_INDIRECT_Y) { @@ -39342,6 +41299,26 @@ void NativeCodeBasicBlock::CheckVisited(void) #endif } +void NativeCodeBasicBlock::CheckAsmCode(void) +{ +#if _DEBUG + if (!mVisited) + { + mVisited = true; + + for (int j = 0; j < mIns.Size(); j++) + { + if (mIns[j].mMode == ASMIM_IMMEDIATE_ADDRESS) + assert(HasAsmInstructionMode(mIns[j].mType, ASMIM_IMMEDIATE)); + else + assert(HasAsmInstructionMode(mIns[j].mType, mIns[j].mMode)); + } + + if (mTrueJump) mTrueJump->CheckAsmCode(); + if (mFalseJump) mFalseJump->CheckAsmCode(); + } +#endif +} void NativeCodeBasicBlock::CheckBlocks(bool sequence) @@ -39350,6 +41327,9 @@ void NativeCodeBasicBlock::CheckBlocks(bool sequence) if (!mVisited) { mVisited = true; + + assert(this != mProc->mEntryBlock || mNumEntries < 2); + CheckLive(); if (sequence) @@ -39450,6 +41430,28 @@ void NativeCodeBasicBlock::Close(const InterInstruction* ins, NativeCodeBasicBlo this->mBranchIns = ins; } +NativeCodeBasicBlock* NativeCodeBasicBlock::SplitAt(int at) +{ + NativeCodeBasicBlock* eblock = mProc->AllocateBlock(); + eblock->Close(mBranchIns, mTrueJump, mFalseJump, mBranch); + this->mBranch = ASMIT_JMP; + this->mFalseJump = nullptr; + this->mTrueJump = eblock; + for (int i = at; i < mIns.Size(); i++) + eblock->mIns.Push(mIns[i]); + mIns.SetSize(at); + eblock->mNumEntries = 1; + eblock->mEntryBlocks.Push(this); + eblock->mTrueJump->mEntryBlocks.RemoveAll(this); + eblock->mTrueJump->mEntryBlocks.Push(eblock); + if (eblock->mFalseJump) + { + eblock->mFalseJump->mEntryBlocks.RemoveAll(this); + eblock->mFalseJump->mEntryBlocks.Push(eblock); + } + return eblock; +} + NativeCodeBasicBlock* NativeCodeBasicBlock::BypassEmptyBlocks(void) { if (mBypassed) @@ -39663,6 +41665,45 @@ bool NativeCodeBasicBlock::CalculateOffset(int& total) return changed; } +void NativeCodeBasicBlock::ShortcutJump(int offset) +{ + if (mCode[offset] == 0x4c) + { + int i = 0; + while (i < mRelocations.Size() && mRelocations[i].mOffset != offset + 1) + i++; + if (i < mRelocations.Size()) + { + LinkerReference& ref(mRelocations[i]); + if (ref.mRefObject && ref.mRefObject->mData) + { + LinkerObject* lo = ref.mRefObject; + + if (lo->mData[ref.mRefOffset] == 0x4c || lo->mData[ref.mRefOffset] == 0x6c) + { + int j = 0; + while (j < lo->mReferences.Size() && lo->mReferences[j]->mOffset != ref.mRefOffset + 1) + j++; + if (j < lo->mReferences.Size()) + { + mCode[offset] = lo->mData[ref.mRefOffset]; + ref.mRefObject = lo->mReferences[j]->mRefObject; + ref.mRefOffset = lo->mReferences[j]->mRefOffset; + ref.mFlags = lo->mReferences[j]->mFlags; + } + else + { + mCode[offset] = lo->mData[ref.mRefOffset]; + mCode[offset + 1] = lo->mData[ref.mRefOffset + 1]; + mCode[offset + 2] = lo->mData[ref.mRefOffset + 2]; + mRelocations.Remove(i); + } + } + } + } + } +} + void NativeCodeBasicBlock::ShortcutTailRecursion() { if (!mVisited) @@ -39673,6 +41714,7 @@ void NativeCodeBasicBlock::ShortcutTailRecursion() this->mCode[this->mCode.Size() - 3] = 0x4c; mTrueJump->mNumEntries--; mTrueJump = nullptr; + ShortcutJump(this->mCode.Size() - 3); } else if (!mFalseJump && !mTrueJump) { @@ -39681,6 +41723,7 @@ void NativeCodeBasicBlock::ShortcutTailRecursion() { this->mCode.Remove(this->mCode.Size() - 1); this->mCode[this->mCode.Size() - 3] = 0x4c; + ShortcutJump(this->mCode.Size() - 3); } } @@ -39993,11 +42036,12 @@ void NativeCodeProcedure::LoadTempsFromStack(int tempSave) } } + void NativeCodeProcedure::Compile(InterCodeProcedure* proc) { mInterProc = proc; - CheckFunc = !strcmp(mInterProc->mIdent->mString, "sprintf"); + CheckFunc = !strcmp(mInterProc->mIdent->mString, "enemies_move_show"); int nblocks = proc->mBlocks.Size(); tblocks = new NativeCodeBasicBlock * [nblocks]; @@ -40052,12 +42096,30 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc) // Place a temporary RTS - mExitBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_RTS, ASMIM_IMPLIED, 0, nullptr, 0)); + uint32 rflags = 0; + switch (proc->mReturnType) + { + case IT_BOOL: + case IT_INT8: + rflags = NCIF_LOWER; + break; + case IT_INT16: + case IT_POINTER: + rflags = NCIF_LOWER | NCIF_UPPER; + break; + case IT_INT32: + case IT_FLOAT: + rflags = NCIF_LOWER | NCIF_UPPER | NCIF_LONG; + break; + + } + + mExitBlock->mIns.Push(NativeCodeInstruction(nullptr, ASMIT_RTS, ASMIM_IMPLIED, 0, nullptr, rflags)); mEntryBlock->mTrueJump = CompileBlock(mInterProc, mInterProc->mBlocks[0]); mEntryBlock->mBranch = ASMIT_JMP; - if (proc->mLeafProcedure && proc->mFastCallProcedure && !proc->mInterrupt && mNoFrame && mStackExpand == 0 && commonFrameSize == 0 && (mGenerator->mCompilerOptions & COPT_NATIVE)) + if (proc->mLeafProcedure && proc->mFastCallProcedure && !proc->mInterrupt && !proc->mDispatchedCall && mNoFrame && mStackExpand == 0 && commonFrameSize == 0 && proc->mTempSize <= BC_REG_TMP_SAVED - BC_REG_TMP && (mGenerator->mCompilerOptions & COPT_NATIVE)) { #if 1 if (proc->mParamVars.Size() == 1 && proc->mParamVars[0]->mSize == 1) @@ -40070,10 +42132,9 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc) } #endif #if 1 - if (mExitBlock->mIns[0].mFlags == NCIF_LOWER) if (mExitBlock->mIns[0].mFlags == NCIF_LOWER) { - mExitBlock->mIns[0].mFlags = 0; + mExitBlock->mIns[0].mFlags = NCIF_USE_CPU_REG_A; mExitBlock->mIns.Insert(0, NativeCodeInstruction(nullptr, ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU)); mExitBlock->mExitRegA = true; proc->mLinkerObject->mFlags |= LOBJF_RET_REG_A; @@ -40111,7 +42172,7 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc) ZeroPageSet zpLocal, zpGlobal; ResetVisited(); - if (mEntryBlock->CollectZeroPageSet(zpLocal, zpGlobal)) + if (mEntryBlock->CollectZeroPageSet(zpLocal, zpGlobal, true)) zpLocal |= zpGlobal; else mGenerator->mErrors->Error(mInterProc->mLocation, ERRR_INTERRUPT_TO_COMPLEX, "No recursive functions in interrupt"); @@ -40399,7 +42460,7 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc) ZeroPageSet zpLocal, zpGlobal; ResetVisited(); - if (mEntryBlock->CollectZeroPageSet(zpLocal, zpGlobal)) + if (mEntryBlock->CollectZeroPageSet(zpLocal, zpGlobal, false)) { zpLocal |= zpGlobal; @@ -40425,15 +42486,32 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc) else mExitBlock->mIns.Push(NativeCodeInstruction(mExitBlock->mBranchIns, ASMIT_RTS, ASMIM_IMPLIED)); + + proc->mLinkerObject->mType = LOT_NATIVE_CODE; + + if (mInterProc->mCompilerOptions & COPT_OPTIMIZE_MERGE_CALLS) + { + ResetVisited(); + mEntryBlock->RegisterFunctionCalls(); + } +} + +void NativeCodeProcedure::Assemble(void) +{ + if (mInterProc->mCompilerOptions & COPT_OPTIMIZE_MERGE_CALLS) + { + ResetVisited(); + mEntryBlock->MergeFunctionCalls(); + } + mEntryBlock->Assemble(); + ResetVisited(); mEntryBlock = mEntryBlock->BypassEmptyBlocks(); ResetVisited(); mEntryBlock->ShortcutTailRecursion(); - proc->mLinkerObject->mType = LOT_NATIVE_CODE; - ExpandingArray placement; int total; @@ -40453,7 +42531,7 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc) progress = true; } while (progress); - uint8* data = proc->mLinkerObject->AddSpace(total); + uint8* data = mInterProc->mLinkerObject->AddSpace(total); for (int i = 0; i < placement.Size(); i++) { @@ -40467,7 +42545,7 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc) range.mIdent = Ident::Unique(buffer); range.mOffset = placement[i]->mOffset; range.mSize = placement[i]->mSize; - proc->mLinkerObject->mRanges.Push(range); + mInterProc->mLinkerObject->mRanges.Push(range); placement[i]->CopyCode(this, data); } @@ -40475,10 +42553,10 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc) for (int i = 0; i < mRelocations.Size(); i++) { LinkerReference& rl(mRelocations[i]); - rl.mObject = proc->mLinkerObject; + rl.mObject = mInterProc->mLinkerObject; if (!rl.mRefObject) - rl.mRefObject = proc->mLinkerObject; - proc->mLinkerObject->AddReference(rl); + rl.mRefObject = mInterProc->mLinkerObject; + mInterProc->mLinkerObject->AddReference(rl); } if (mGenerator->mCompilerOptions & COPT_DEBUGINFO) @@ -40499,12 +42577,11 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc) } mCodeLocations.SetSize(j + 1); - proc->mLinkerObject->AddLocations(mCodeLocations); + mInterProc->mLinkerObject->AddLocations(mCodeLocations); } } } - bool NativeCodeProcedure::MapFastParamsToTemps(void) { NumberSet used(256), modified(256), statics(256), pairs(256); @@ -40562,8 +42639,9 @@ void NativeCodeProcedure::RebuildEntry(void) ResetVisited(); mEntryBlock->CollectEntryBlocks(nullptr); + NativeCodeBasicBlock::DominatorStacks stacks; - mEntryBlock->BuildDominatorTree(nullptr); + mEntryBlock->BuildDominatorTree(nullptr, stacks); } void NativeCodeProcedure::Optimize(void) @@ -40585,6 +42663,7 @@ void NativeCodeProcedure::Optimize(void) RebuildEntry(); + assert(mEntryBlock->mNumEntries < 2); #if 1 if (step > 3) { @@ -40596,6 +42675,8 @@ void NativeCodeProcedure::Optimize(void) } } #endif + RebuildEntry(); + assert(mEntryBlock->mNumEntries < 2); if (step == 4) { @@ -40610,6 +42691,7 @@ void NativeCodeProcedure::Optimize(void) } RebuildEntry(); + assert(mEntryBlock->mNumEntries < 2); #if 1 if (step > 3) @@ -40628,7 +42710,7 @@ void NativeCodeProcedure::Optimize(void) ResetPatched(); mEntryBlock->CheckVisited(); } - + } while (bchanged); } @@ -40643,10 +42725,18 @@ void NativeCodeProcedure::Optimize(void) #if 1 if (step == 2) { + BuildDataFlowSets(); ResetVisited(); mEntryBlock->ReplaceFinalZeroPageUse(this); } #endif + + if (step > 1) + { + ResetVisited(); + mEntryBlock->LocalZeroPageValueNumbering(); + } + int t = 0; #if 1 do @@ -40655,8 +42745,8 @@ void NativeCodeProcedure::Optimize(void) BuildDataFlowSets(); ResetVisited(); - changed = mEntryBlock->RemoveUnusedResultInstructions(); + changed = mEntryBlock->RemoveUnusedResultInstructions(); if (step == 0) { @@ -40695,7 +42785,7 @@ void NativeCodeProcedure::Optimize(void) t++; - } while (changed); + } while (changed && t < 20); #endif BuildDataFlowSets(); @@ -40710,6 +42800,11 @@ void NativeCodeProcedure::Optimize(void) { changed = true; +#if _DEBUG + ResetVisited(); + mEntryBlock->CheckBlocks(); +#endif + BuildDataFlowSets(); ResetVisited(); mEntryBlock->RemoveUnusedResultInstructions(); @@ -40719,9 +42814,14 @@ void NativeCodeProcedure::Optimize(void) if (step == 9) { ResetVisited(); - if (mEntryBlock->AbsoluteValueForwarding()) + ExpandingArray pairs; + if (mEntryBlock->AbsoluteValueForwarding(pairs)) { changed = true; +#if _DEBUG + ResetVisited(); + mEntryBlock->CheckBlocks(); +#endif BuildDataFlowSets(); ResetVisited(); @@ -40740,6 +42840,13 @@ void NativeCodeProcedure::Optimize(void) changed = true; #endif + if (step == 2) + { + ResetVisited(); + if (mEntryBlock->ShortcutIndirectLoadStore()) + changed = true; + } + #if 1 if (step >= 3) { @@ -40784,13 +42891,12 @@ void NativeCodeProcedure::Optimize(void) } #endif - if (step == 5) + if (step == 5 && cnt < 10) { ResetVisited(); if (mEntryBlock->RemoveDoubleZPStore()) changed = true; } - if (step == 3 || step == 5 || step == 9) { ResetVisited(); @@ -40862,6 +42968,14 @@ void NativeCodeProcedure::Optimize(void) if (mEntryBlock->PropagateSinglePath()) changed = true; } + + if (step > 4) + { + ResetVisited(); + if (mEntryBlock->ShortcutBlockExit()) + changed = true; + } + #endif #if _DEBUG @@ -41000,6 +43114,7 @@ void NativeCodeProcedure::Optimize(void) } } #endif + if (!changed) { if (step == 5) @@ -41055,6 +43170,13 @@ void NativeCodeProcedure::Optimize(void) } #endif + if (step == 7) + { + ResetVisited(); + if (mEntryBlock->CrossBlockRegisterAlias(false, false)) + changed = true; + } + if (step == 8) { ResetVisited(); @@ -41131,6 +43253,13 @@ void NativeCodeProcedure::Optimize(void) changed = true; } + if (step >= 9) + { + ResetVisited(); + if (mEntryBlock->EliminateDeadLoops()) + changed = true; + } + #if _DEBUG ResetVisited(); mEntryBlock->CheckBlocks(); @@ -41165,6 +43294,11 @@ void NativeCodeProcedure::Optimize(void) } #endif +#if _DEBUG + ResetVisited(); + mEntryBlock->CheckAsmCode(); +#endif + #if 1 if (step == 8) { @@ -41183,11 +43317,19 @@ void NativeCodeProcedure::Optimize(void) #if 1 if (step >= 7) { + ResetVisited(); + NativeRegisterDataSet data; + mEntryBlock->BuildEntryDataSet(data); + ResetVisited(); if (mEntryBlock->ExpandADCToBranch(this)) changed = true; } #endif +#if _DEBUG + ResetVisited(); + mEntryBlock->CheckAsmCode(); +#endif #if 1 if (step == 9) { @@ -41199,6 +43341,10 @@ void NativeCodeProcedure::Optimize(void) #endif RebuildEntry(); +#if _DEBUG + ResetVisited(); + mEntryBlock->CheckAsmCode(); +#endif #if 1 if (step == 2 && !changed) { @@ -41209,7 +43355,7 @@ void NativeCodeProcedure::Optimize(void) #endif #if 1 - if (step == 10) + if (step == 10 && (mInterProc->mCompilerOptions & COPT_OPTIMIZE_BASIC)) { ResetVisited(); mEntryBlock->MarkLocalUsedLinkerObjects(); @@ -41245,6 +43391,10 @@ void NativeCodeProcedure::Optimize(void) } } #endif +#if _DEBUG + ResetVisited(); + mEntryBlock->CheckAsmCode(); +#endif #if 1 if (cnt > 190) @@ -41273,7 +43423,6 @@ void NativeCodeProcedure::Optimize(void) } while (changed); - #if 1 ResetVisited(); mEntryBlock->ReduceLocalYPressure(); @@ -41340,6 +43489,7 @@ void NativeCodeProcedure::Optimize(void) changed = mEntryBlock->JoinTailCodeSequences(this, true); } + } while (changed); #endif @@ -41429,13 +43579,14 @@ void NativeCodeProcedure::ResetPatched(void) { for (int i = 0; i < mBlocks.Size(); i++) { - mBlocks[i]->mPatched = false; - mBlocks[i]->mPatchFail = false; - mBlocks[i]->mPatchChecked = false; - mBlocks[i]->mPatchStart = false; - mBlocks[i]->mPatchLoop = false; - mBlocks[i]->mPatchLoopChanged = false; - mBlocks[i]->mPatchExit = false; + NativeCodeBasicBlock* b = mBlocks[i]; + b->mPatched = false; + b->mPatchFail = false; + b->mPatchChecked = false; + b->mPatchStart = false; + b->mPatchLoop = false; + b->mPatchLoopChanged = false; + b->mPatchExit = false; } } @@ -41606,6 +43757,14 @@ void NativeCodeProcedure::CompileInterBlock(InterCodeProcedure* iproc, InterCode case IC_STRCPY: block = block->StrcpyValue(iproc, ins, this); break; + + case IC_MALLOC: + block->CallMalloc(iproc, ins, this); + break; + case IC_FREE: + block->CallFree(iproc, ins, this); + break; + case IC_LOAD_TEMPORARY: { if (ins->mSrc[0].mTemp != ins->mDst.mTemp) @@ -41692,6 +43851,16 @@ void NativeCodeProcedure::CompileInterBlock(InterCodeProcedure* iproc, InterCode block->StoreByteIndexedValue(iproc, ins, iblock->mInstructions[i + 1]); i++; } + else if (i + 1 < iblock->mInstructions.Size() && + iblock->mInstructions[i + 1]->mCode == IC_STORE && iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[1].mFinal && + ins->mSrc[1].mTemp >= 0 && ins->mSrc[0].IsUByte() && ins->mSrc[0].mTemp >= 0 && + iblock->mInstructions[i + 1]->mSrc[1].mIntConst + ins->mSrc[0].mRange.mMaxValue + InterTypeSize[iblock->mInstructions[i + 1]->mSrc[0].mType] <= 256 && + (iblock->mInstructions[i + 1]->mSrc[0].mTemp >= 0 || iblock->mInstructions[i + 1]->mSrc[0].mType <= IT_INT32) && + (InterTypeSize[iblock->mInstructions[i + 1]->mSrc[0].mType] == 1 || iblock->mInstructions[i + 1]->mSrc[1].mStride == 1)) + { + block->StoreByteOffsetIndexedValue(iproc, ins, iblock->mInstructions[i + 1]); + i++; + } else if (i + 2 < iblock->mInstructions.Size() && ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mMemory == IM_GLOBAL && ins->mSrc[1].mLinkerObject->mSize <= 256 && // ins->mSrc[0].IsUByte() && @@ -41722,6 +43891,7 @@ void NativeCodeProcedure::CompileInterBlock(InterCodeProcedure* iproc, InterCode case IC_CONSTANT: block->LoadConstant(iproc, ins); break; + case IC_DISPATCH: case IC_CALL: block->CallFunction(iproc, this, ins); break; @@ -41916,7 +44086,7 @@ void NativeCodeProcedure::CompileInterBlock(InterCodeProcedure* iproc, InterCode NativeCodeGenerator::NativeCodeGenerator(Errors* errors, Linker* linker, LinkerSection* runtimeSection) - : mErrors(errors), mLinker(linker), mRuntimeSection(runtimeSection), mCompilerOptions(COPT_DEFAULT) + : mErrors(errors), mLinker(linker), mRuntimeSection(runtimeSection), mCompilerOptions(COPT_DEFAULT), mFunctionCalls(nullptr) { } @@ -42024,6 +44194,242 @@ NativeCodeGenerator::Runtime& NativeCodeGenerator::ResolveRuntime(const Ident* i return mRuntime[i]; } +void NativeCodeGenerator::RegisterFunctionCall(NativeCodeBasicBlock* block, int at) +{ + LinkerObject* lo = block->mIns[at].mLinkerObject; + if (lo->mIdent && !(block->mIns[at].mFlags & NCIF_USE_ZP_32_X)) + { + int i = at; + while (i >= 2 && + block->mIns[i - 1].mType == ASMIT_STA && block->mIns[i - 1].mMode == ASMIM_ZERO_PAGE && + block->mIns[i - 1].mAddress >= BC_REG_FPARAMS && block->mIns[i - 1].mAddress < BC_REG_FPARAMS_END && + block->mIns[i - 2].mType == ASMIT_LDA && (block->mIns[i - 2].mMode == ASMIM_IMMEDIATE || block->mIns[i - 2].mMode == ASMIM_IMMEDIATE_ADDRESS || block->mIns[i - 2].mMode == ASMIM_ZERO_PAGE)) + { + i -= 2; + } + + if (i < at) + { + FunctionCall* ncp = new FunctionCall(); + ncp->mLinkerObject = lo; + ncp->mProxyObject = nullptr; + ncp->mCount = 1; + while (i < at) + { + ncp->mIns[block->mIns[i + 1].mAddress - BC_REG_FPARAMS] = block->mIns[i]; + i += 2; + } + + FunctionCall* cp = mFunctionCalls; + while (cp && cp->mLinkerObject != ncp->mLinkerObject) + cp = cp->mNext; + if (!cp) + { + ncp->mNext = mFunctionCalls; + mFunctionCalls = ncp; + ncp->mSame = nullptr; + } + else + { + FunctionCall* scp = cp; + while (scp && !scp->IsSame(ncp)) + scp = scp->mSame; + if (!scp) + { + ncp->mSame = cp->mSame; + cp->mSame = ncp; + } + else + { + scp->mCount++; + ncp = scp; + } + } + } + } + +} + +bool NativeCodeGenerator::MergeFunctionCall(NativeCodeBasicBlock* block, int at) +{ + LinkerObject* lo = block->mIns[at].mLinkerObject; + if (lo->mIdent) + { + int i = at; + while (i >= 2 && + block->mIns[i - 1].mType == ASMIT_STA && block->mIns[i - 1].mMode == ASMIM_ZERO_PAGE && + block->mIns[i - 1].mAddress >= BC_REG_FPARAMS && block->mIns[i - 1].mAddress < BC_REG_FPARAMS_END && + block->mIns[i - 2].mType == ASMIT_LDA && (block->mIns[i - 2].mMode == ASMIM_IMMEDIATE || block->mIns[i - 2].mMode == ASMIM_IMMEDIATE_ADDRESS || block->mIns[i - 2].mMode == ASMIM_ZERO_PAGE || block->mIns[i - 2].mMode == ASMIM_ABSOLUTE)) + { + i -= 2; + } + + if (i < at) + { + FunctionCall ncp; + ncp.mLinkerObject = lo; + int j = i; + while (i < at) + { + ncp.mIns[block->mIns[i + 1].mAddress - BC_REG_FPARAMS] = block->mIns[i]; + i += 2; + } + + FunctionCall* cp = mFunctionCalls; + while (cp && cp->mLinkerObject != ncp.mLinkerObject) + cp = cp->mNext; + if (cp) + { + FunctionCall* bcp = nullptr; + int bmatch = 0; + + FunctionCall* scp = cp; + while (scp) + { + if (scp->mProxyObject) + { + int m = ncp.Matches(scp); + if (m > bmatch) + { + bmatch = m; + bcp = scp; + } + } + scp = scp->mSame; + } + + if (bcp) + { + while (j < at) + { + if (bcp->mIns[block->mIns[j + 1].mAddress - BC_REG_FPARAMS].mType != ASMIT_INV) + { + block->mIns[j + 0].mType = ASMIT_NOP; block->mIns[j + 0].mMode = ASMIM_IMPLIED; + block->mIns[j + 1].mType = ASMIT_NOP; block->mIns[j + 1].mMode = ASMIM_IMPLIED; + } + j += 2; + } + block->mIns[j].mLinkerObject = bcp->mProxyObject; + return true; + } + } + } + } + return false; +} + +void NativeCodeGenerator::BuildFunctionProxies(void) +{ + FunctionCall* cp = mFunctionCalls; + while (cp) + { + FunctionCall* ncp = cp; + while (ncp) + { + if (ncp->mCount > 1) + { + printf("RFC %s : %d\n", ncp->mLinkerObject->mIdent->mString, ncp->mCount); + ncp->mProxyObject = mLinker->AddObject(ncp->mLinkerObject->mLocation, ncp->mLinkerObject->mIdent->Mangle("@proxy"), ncp->mLinkerObject->mSection, ncp->mLinkerObject->mType); + + ExpandingArray code; + for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS_END; i++) + { + NativeCodeInstruction& ins(ncp->mIns[i - BC_REG_FPARAMS]); + if (ins.mType == ASMIT_LDA) + { + switch (ins.mMode) + { + case ASMIM_IMMEDIATE: + code.Push(uint8(AsmInsOpcodes[ASMIT_LDA][ASMIM_IMMEDIATE])); + code.Push(uint8(ins.mAddress)); + break; + case ASMIM_ZERO_PAGE: + code.Push(uint8(AsmInsOpcodes[ASMIT_LDA][ASMIM_ZERO_PAGE])); + if (ins.mLinkerObject) + { + LinkerReference rl; + rl.mObject = ncp->mProxyObject; + rl.mOffset = code.Size(); + + rl.mRefObject = ins.mLinkerObject; + rl.mRefOffset = ins.mAddress; + rl.mFlags = LREF_LOWBYTE; + + ncp->mProxyObject->AddReference(rl); + code.Push(0); + } + else + code.Push(uint8(ins.mAddress)); + break; + case ASMIM_IMMEDIATE_ADDRESS: + code.Push(uint8(AsmInsOpcodes[ASMIT_LDA][ASMIM_IMMEDIATE])); + if (ins.mLinkerObject) + { + LinkerReference rl; + rl.mObject = ncp->mProxyObject; + rl.mOffset = code.Size(); + rl.mFlags = 0; + if (ins.mFlags & NCIF_LOWER) + rl.mFlags |= LREF_LOWBYTE; + if (ins.mFlags & NCIF_UPPER) + rl.mFlags |= LREF_HIGHBYTE; + rl.mRefObject = ins.mLinkerObject; + rl.mRefOffset = ins.mAddress; + + ins.mLinkerObject->mFlags |= LOBJF_NO_CROSS; + + ncp->mProxyObject->AddReference(rl); + code.Push(0); + } + else + code.Push(uint8(ins.mAddress)); + break; + case ASMIM_ABSOLUTE: + code.Push(uint8(AsmInsOpcodes[ASMIT_LDA][ASMIM_ABSOLUTE])); + if (ins.mLinkerObject) + { + LinkerReference rl; + rl.mObject = ncp->mProxyObject; + rl.mOffset = code.Size(); + rl.mRefObject = ins.mLinkerObject; + rl.mRefOffset = ins.mAddress; + rl.mFlags = LREF_LOWBYTE | LREF_HIGHBYTE; + ncp->mProxyObject->AddReference(rl); + code.Push(0); + code.Push(0); + } + else + { + code.Push(uint8(ins.mAddress & 0xff)); + code.Push(uint8(ins.mAddress >> 8)); + } + break; + } + code.Push(uint8(AsmInsOpcodes[ASMIT_STA][ASMIM_ZERO_PAGE])); + code.Push(uint8(i)); + } + } + code.Push(uint8(AsmInsOpcodes[ASMIT_JMP][ASMIM_ABSOLUTE])); + + LinkerReference rl; + rl.mObject = ncp->mProxyObject; + rl.mOffset = code.Size(); + rl.mRefObject = ncp->mLinkerObject; + rl.mRefOffset = 0; + rl.mFlags = LREF_LOWBYTE | LREF_HIGHBYTE; + ncp->mProxyObject->AddReference(rl); + code.Push(0); + code.Push(0); + + ncp->mProxyObject->AddData(&(code[0]), code.Size()); + } + ncp = ncp->mSame; + } + cp = cp->mNext; + } +} + + void NativeCodeGenerator::RegisterRuntime(const Ident* ident, LinkerObject* object, int offset) { Runtime rt; @@ -42032,3 +44438,29 @@ void NativeCodeGenerator::RegisterRuntime(const Ident* ident, LinkerObject* obje rt.mOffset = offset; mRuntime.Push(rt); } + +bool NativeCodeGenerator::FunctionCall::IsSame(const FunctionCall* fc) const +{ + for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS_END; i++) + if (!mIns[i - BC_REG_FPARAMS].IsSame(fc->mIns[i - BC_REG_FPARAMS])) + return false; + return true; +} + +int NativeCodeGenerator::FunctionCall::Matches(const FunctionCall* fc) const +{ + int match = 0; + + for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS_END; i++) + { + if (fc->mIns[i - BC_REG_FPARAMS].mType != ASMIT_INV && mIns[i - BC_REG_FPARAMS].mType != ASMIT_INV) + { + if (!mIns[i - BC_REG_FPARAMS].IsSame(fc->mIns[i - BC_REG_FPARAMS])) + return -1; + match++; + } + } + + return match; +} + diff --git a/oscar64/NativeCodeGenerator.h b/oscar64/NativeCodeGenerator.h index 1479b4d..07c27dd 100644 --- a/oscar64/NativeCodeGenerator.h +++ b/oscar64/NativeCodeGenerator.h @@ -45,6 +45,7 @@ struct NativeRegisterDataSet void ResetMask(void); void ResetZeroPage(int addr); + void ResetZeroPageRange(int addr, int num); void ResetAbsolute(LinkerObject * linkerObject, int addr); int FindAbsolute(LinkerObject* linkerObject, int addr); void ResetIndirect(int reg); @@ -207,6 +208,12 @@ public: uint32 NeedsLive(void) const; }; +struct NativeCodeLoadStorePair +{ + NativeCodeInstruction mLoad, mStore; +}; + + class NativeCodeBasicBlock { public: @@ -249,6 +256,8 @@ public: int JumpByteSize(NativeCodeBasicBlock * target, int offset); int BranchByteSize(NativeCodeBasicBlock* target, int from, int to); + NativeCodeBasicBlock* SplitAt(int at); + NativeCodeBasicBlock* BypassEmptyBlocks(void); int LeadsInto(NativeCodeBasicBlock* block, int dist); @@ -263,6 +272,7 @@ public: void PrependInstruction(const NativeCodeInstruction& ins); void ShortcutTailRecursion(); + void ShortcutJump(int offset); bool ReferencesAccu(int from = 0, int to = 65536) const; bool ReferencesYReg(int from = 0, int to = 65536) const; @@ -300,6 +310,7 @@ public: bool OptimizeGenericLoop(NativeCodeProcedure* proc); bool CollectGenericLoop(NativeCodeProcedure* proc, ExpandingArray& lblocks); + bool CollectSingleEntryGenericLoop(NativeCodeProcedure* proc, ExpandingArray& lblocks); void CollectReachable(ExpandingArray& lblock); bool OptimizeFindLoop(NativeCodeProcedure* proc); @@ -324,6 +335,8 @@ public: bool LoadUnopStoreIndirectValue(InterCodeProcedure* proc, const InterInstruction* rins, const InterInstruction* oins, const InterInstruction* wins); bool LoadLoadOpStoreIndirectValue(InterCodeProcedure* proc, const InterInstruction* rins1, const InterInstruction* rins0, const InterInstruction* oins, const InterInstruction* wins); void LoadStoreIndirectValue(InterCodeProcedure* proc, const InterInstruction* rins, const InterInstruction* wins); + void StoreByteOffsetIndexedValue(InterCodeProcedure* proc, const InterInstruction* iins, const InterInstruction* sins); + NativeCodeBasicBlock* BinaryOperator(InterCodeProcedure* proc, NativeCodeProcedure* nproc, const InterInstruction * ins, const InterInstruction* sins1, const InterInstruction* sins0); void UnaryOperator(InterCodeProcedure* proc, NativeCodeProcedure* nproc, const InterInstruction * ins); void RelationalOperator(InterCodeProcedure* proc, const InterInstruction * ins, NativeCodeProcedure * nproc, NativeCodeBasicBlock* trueJump, NativeCodeBasicBlock * falseJump); @@ -336,12 +349,16 @@ public: NativeCodeBasicBlock * StrcpyValue(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc); void AddAsrSignedByte(InterCodeProcedure* proc, const InterInstruction* ains, const InterInstruction* sins); + void CallMalloc(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc); + void CallFree(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc); + void LoadByteIndexedValue(InterCodeProcedure* proc, const InterInstruction* iins, const InterInstruction* rins); void StoreByteIndexedValue(InterCodeProcedure* proc, const InterInstruction* iins, const InterInstruction* rins); void CallAssembler(InterCodeProcedure* proc, NativeCodeProcedure* nproc, const InterInstruction * ins); void CallFunction(InterCodeProcedure* proc, NativeCodeProcedure* nproc, const InterInstruction * ins); + void ShiftRegisterRight( const InterInstruction* ins, int reg, int shift); void ShiftRegisterLeft(InterCodeProcedure* proc, const InterInstruction* ins, int reg, int shift); void ShiftRegisterLeftByte(InterCodeProcedure* proc, const InterInstruction* ins, int reg, int shift); void ShiftRegisterLeftFromByte(InterCodeProcedure* proc, const InterInstruction* ins, int reg, int shift, int max); @@ -353,6 +370,7 @@ public: NumberSet mLocalRequiredRegs, mLocalProvidedRegs; NumberSet mEntryRequiredRegs, mEntryProvidedRegs; NumberSet mExitRequiredRegs, mExitProvidedRegs; + NumberSet mNewRequiredRegs; NumberSet mTempRegs; void BuildLocalRegSets(void); @@ -370,7 +388,13 @@ public: NativeCodeBasicBlock * ForwardAccuBranch(bool eq, bool ne, bool pl, bool mi, int limit); bool MergeBasicBlocks(void); void MarkLoopHead(void); - void BuildDominatorTree(NativeCodeBasicBlock * from); + + struct DominatorStacks + { + ExpandingArray< NativeCodeBasicBlock* > d1, d2; + }; + + void BuildDominatorTree(NativeCodeBasicBlock * from, DominatorStacks & stacks); bool MoveLoadStoreUp(int at); bool MoveLoadStoreXUp(int at); @@ -393,6 +417,7 @@ public: bool MoveLoadAddZPStoreUp(int at); bool MoveLoadShiftRotateUp(int at); bool MoveLoadShiftStoreUp(int at); + bool MoveTYADCStoreDown(int at); bool MoveLDSTXOutOfRange(int at); @@ -424,6 +449,10 @@ public: bool MoveTXADCDown(int at); bool FoldShiftORAIntoLoadImmUp(int at); + bool MoveSimpleADCToINCDECDown(int at); + bool MoveTAXADCSTADown(int at); + + bool MoveZeroPageCrossBlockUp(int at, const NativeCodeInstruction & lins, const NativeCodeInstruction & sins); bool ShortcutCrossBlockMoves(NativeCodeProcedure* proc); @@ -465,7 +494,7 @@ public: bool BitFieldForwarding(const NativeRegisterDataSet& data); bool ReverseBitfieldForwarding(void); bool OffsetValueForwarding(const ValueNumberingDataSet & data); - bool AbsoluteValueForwarding(void); + bool AbsoluteValueForwarding(const ExpandingArray& npairs); void MarkLocalUsedLinkerObjects(void); bool RemoveLocalUnusedLinkerObjects(void); @@ -488,6 +517,7 @@ public: bool IsExitXRegZP(int addr, int& index) const; bool IsExitARegZP(int addr, int& index) const; + bool ShortcutBlockExit(void); bool PropagateSinglePath(void); bool CanChangeTailZPStoreToX(int addr, const NativeCodeBasicBlock * nblock, const NativeCodeBasicBlock* fblock = nullptr) const; @@ -508,6 +538,8 @@ public: bool CrossBlockYAliasProgpagation(const int * yalias, int yoffset); + bool CrossBlockRegisterAlias(bool sameAX, bool sameAY); + bool BypassRegisterConditionBlock(void); bool FoldLoopEntry(void); @@ -521,7 +553,7 @@ public: bool Check16BitSum(const NativeCodeBasicBlock* block, int origin, int at, int reg); bool EliminateUpper16BitSum(NativeCodeProcedure* nproc); - bool IsFinalZeroPageUse(const NativeCodeBasicBlock* block, int at, int from, int to, bool pair); + bool IsFinalZeroPageUse(const NativeCodeBasicBlock* block, int at, int from, int to, bool pair, bool fchanged); bool ReplaceFinalZeroPageUse(NativeCodeProcedure* nproc); bool ForwardReplaceZeroPage(int at, int from, int to); @@ -534,7 +566,7 @@ public: void BuildEntryDataSet(const NativeRegisterDataSet& set); bool ApplyEntryDataSet(void); - bool CollectZeroPageSet(ZeroPageSet& locals, ZeroPageSet& global); + bool CollectZeroPageSet(ZeroPageSet& locals, ZeroPageSet& global, bool ignorefcall); void CollectZeroPageUsage(NumberSet& used, NumberSet& modified, NumberSet& pairs); void FindZeroPageAlias(const NumberSet& statics, NumberSet& invalid, uint8* alias, int accu); bool RemapZeroPage(const uint8* remap); @@ -545,6 +577,7 @@ public: bool LocalRegisterXYMap(void); bool ReduceLocalYPressure(void); bool ReduceLocalXPressure(void); + bool LocalZeroPageValueNumbering(void); bool CombineZPPair(int at, int r0, int r1, bool use0, bool use1, bool & swap); bool RemoveDoubleZPStore(void); @@ -554,8 +587,9 @@ public: bool SimplifyDiamond(NativeCodeProcedure* proc); bool SimplifyLoopEnd(NativeCodeProcedure* proc); bool CrossBlockStoreLoadBypass(NativeCodeProcedure* proc); + bool EliminateDeadLoops(void); - bool CanBytepassLoad(const NativeCodeInstruction& ains) const; + bool CanBytepassLoad(const NativeCodeInstruction& ains, int from = 0) const; bool CanHoistStore(const NativeCodeInstruction& ains) const; bool MoveAccuTrainUp(int at, int end); @@ -584,6 +618,10 @@ public: bool CheckShortcutPointerAddForward(int at); bool ShortcutPointerAddForward(void); + bool ShortcutIndirectLoadStore(void); + bool MoveIndirectLoadZeroStoreDown(int at); + bool MoveLoadZeroStoreIndirectUp(int at); + bool CommonSubExpressionElimination(void); bool CheckPatchFailReg(const NativeCodeBasicBlock* block, int reg); @@ -592,6 +630,12 @@ public: bool CheckPatchFailLoop(const NativeCodeBasicBlock* block, const NativeCodeBasicBlock* head, int reg, bool changed); + // reg : base register pair to replace + // index: index register + // at : start position in block + // yval: known y immediate value of -1 if not known + // lobj: linker object addressed + // address: offset into linker object bool CheckGlobalAddressSumYPointer(const NativeCodeBasicBlock * block, int reg, int index, int at, int yval); bool PatchGlobalAddressSumYPointer(const NativeCodeBasicBlock* block, int reg, int index, int at, int yval, LinkerObject * lobj, int address, uint32 flags = NCIF_LOWER | NCIF_UPPER); @@ -603,7 +647,7 @@ public: // iins : indexing instruction // at : start position in block // yval: known y immediate value of -1 if not known - bool CheckForwardSumYPointer(const NativeCodeBasicBlock* block, int reg, int base, const NativeCodeInstruction & iins, int at, int yval); + bool CheckForwardSumYPointer(const NativeCodeBasicBlock* block, int reg, int base, const NativeCodeInstruction & iins, int at, int yval, int ymax); bool PatchForwardSumYPointer(const NativeCodeBasicBlock* block, int reg, int base, const NativeCodeInstruction & iins, int at, int yval); // reg : base register pair to replace LSB with zero @@ -639,10 +683,14 @@ public: void PropagateZPAbsolute(void); + void RegisterFunctionCalls(void); + bool MergeFunctionCalls(void); + bool IsDominatedBy(const NativeCodeBasicBlock* block) const; void CheckLive(void); void CheckBlocks(bool sequence = false); + void CheckAsmCode(void); void CheckVisited(void); }; @@ -671,6 +719,7 @@ class NativeCodeProcedure void Compile(InterCodeProcedure* proc); void Optimize(void); + void Assemble(void); NativeCodeBasicBlock* CompileBlock(InterCodeProcedure* iproc, InterCodeBasicBlock* block); NativeCodeBasicBlock* AllocateBlock(void); @@ -725,4 +774,21 @@ public: ExpandingArray mRuntime; ExpandingArray mMulTables; + + struct FunctionCall + { + LinkerObject * mLinkerObject, * mProxyObject; + NativeCodeInstruction mIns[64]; + FunctionCall * mNext, * mSame; + int mCount; + + bool IsSame(const FunctionCall* fc) const; + int Matches(const FunctionCall* fc) const; + }; + + FunctionCall* mFunctionCalls; + + void RegisterFunctionCall(NativeCodeBasicBlock* block, int at); + void BuildFunctionProxies(void); + bool MergeFunctionCall(NativeCodeBasicBlock* block, int at); }; diff --git a/oscar64/NumberSet.cpp b/oscar64/NumberSet.cpp index 5fa614b..74b2dd8 100644 --- a/oscar64/NumberSet.cpp +++ b/oscar64/NumberSet.cpp @@ -73,6 +73,34 @@ void NumberSet::Reset(int size, bool set) } } +void NumberSet::AddRange(int elem, int num) +{ + for (int i = 0; i < num; i++) + *this += elem + i; +} + +void NumberSet::SubRange(int elem, int num) +{ + for (int i = 0; i < num; i++) + *this -= elem + i; +} + +bool NumberSet::RangeClear(int elem, int num) const +{ + for (int i = 0; i < num; i++) + if ((*this)[elem + i]) + return false; + return true; +} + +bool NumberSet::RangeFilled(int elem, int num) const +{ + for (int i = 0; i < num; i++) + if (!(*this)[elem + i]) + return false; + return true; +} + void NumberSet::Fill(void) { int i; @@ -120,6 +148,8 @@ NumberSet& NumberSet::operator=(const NumberSet& set) NumberSet& NumberSet::operator&=(const NumberSet& set) { + assert(dwsize == set.dwsize); + int size = dwsize; const uint32* sbits = set.bits; uint32* dbits = bits; @@ -132,7 +162,9 @@ NumberSet& NumberSet::operator&=(const NumberSet& set) NumberSet& NumberSet::operator|=(const NumberSet& set) { - int size = dwsize; + assert(dwsize >= set.dwsize); + + int size = dwsize < set.dwsize ? dwsize : set.dwsize; const uint32* sbits = set.bits; uint32* dbits = bits; @@ -144,6 +176,8 @@ NumberSet& NumberSet::operator|=(const NumberSet& set) NumberSet& NumberSet::operator-=(const NumberSet& set) { + assert(dwsize == set.dwsize); + int i; for (i = 0; i < dwsize; i++) @@ -154,6 +188,8 @@ NumberSet& NumberSet::operator-=(const NumberSet& set) bool NumberSet::operator<=(const NumberSet& set) const { + assert(dwsize == set.dwsize); + int i; for (i = 0; i < dwsize; i++) diff --git a/oscar64/NumberSet.h b/oscar64/NumberSet.h index 624e398..45cea76 100644 --- a/oscar64/NumberSet.h +++ b/oscar64/NumberSet.h @@ -34,6 +34,10 @@ public: void Clear(void); void Fill(void); + void AddRange(int elem, int num); + void SubRange(int elem, int num); + bool RangeClear(int elem, int num) const; + bool RangeFilled(int elem, int num) const; int Size(void) { return size; } }; diff --git a/oscar64/Parser.cpp b/oscar64/Parser.cpp index 762a34d..4bcae45 100644 --- a/oscar64/Parser.cpp +++ b/oscar64/Parser.cpp @@ -2,12 +2,14 @@ #include #include "Assembler.h" #include "MachineTypes.h" +#include "Constexpr.h" Parser::Parser(Errors* errors, Scanner* scanner, CompilationUnits* compilationUnits) : mErrors(errors), mScanner(scanner), mCompilationUnits(compilationUnits) { mGlobals = new DeclarationScope(compilationUnits->mScope, SLEVEL_STATIC); mScope = mGlobals; + mTemplateScope = nullptr; mCodeSection = compilationUnits->mSectionCode; mDataSection = compilationUnits->mSectionData; @@ -18,6 +20,11 @@ Parser::Parser(Errors* errors, Scanner* scanner, CompilationUnits* compilationUn mInlineCall = false; mCompilerOptionSP = 0; mThisPointer = nullptr; + mFunction = nullptr; + mFunctionType = nullptr; + mLambda = nullptr; + mCaptureScope = nullptr; + mTempVars = nullptr; for (int i = 0; i < 256; i++) mCharMap[i] = i; @@ -28,19 +35,118 @@ Parser::~Parser(void) } -Declaration* Parser::ParseStructDeclaration(uint64 flags, DecType dt) +Parser* Parser::Clone(void) +{ + Parser* p = new Parser(mErrors, new Scanner(mErrors, mScanner->mPreprocessor), mCompilationUnits); + + p->mGlobals = mGlobals; + p->mScope = mScope; + p->mCompilerOptions = mCompilerOptions; + p->mCodeSection = mCodeSection; + p->mDataSection = mDataSection; + p->mBSSection = mBSSection; + + return p; +} + +Declaration* Parser::FindBaseMemberFunction(Declaration* dec, Declaration* mdec) +{ + const Ident* ident = mdec->mIdent; + + if (ident->mString[0] == '~') + { + // this is the destructor, need special search + + Declaration * pdec = dec; + Declaration * pmdec = nullptr; + + while (pdec->mBase && !pmdec) + { + pdec = pdec->mBase->mBase; + pmdec = pdec->mScope->Lookup(pdec->mIdent->PreMangle("~")); + } + + return pmdec; + } + else + { + Declaration * pdec = dec; + Declaration * pmdec = nullptr; + + while (pdec->mBase && !pmdec) + { + pdec = pdec->mBase->mBase; + pmdec = pdec->mScope->Lookup(ident); + + while (pmdec && !mdec->mBase->IsDerivedFrom(pmdec->mBase)) + pmdec = pmdec->mNext; + + if (pmdec) + return pmdec; + } + + return pmdec; + } +} + +void Parser::AddMemberFunction(Declaration* dec, Declaration* mdec) +{ + Declaration* pmdec = FindBaseMemberFunction(dec, mdec); + if (pmdec) + mdec->mBase->mFlags |= pmdec->mBase->mFlags & DTF_VIRTUAL; + + Declaration* gdec = mCompilationUnits->mScope->Insert(mdec->mQualIdent, mdec); + if (gdec) + { + if (gdec->mType == DT_CONST_FUNCTION) + { + Declaration* pcdec = nullptr; + Declaration* pdec = gdec; + + while (pdec && !mdec->mBase->IsSameParams(pdec->mBase)) + { + pcdec = pdec; + pdec = pdec->mNext; + } + + if (!pdec) + pcdec->mNext = mdec; + + dec->mScope->Insert(mdec->mIdent, gdec); + if (dec->mConst) + dec->mConst->mScope->Insert(mdec->mIdent, gdec); + + } + else + mErrors->Error(mdec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate struct member declaration", mdec->mIdent); + } + else + dec->mScope->Insert(mdec->mIdent, mdec); +} + +Declaration* Parser::ParseStructDeclaration(uint64 flags, DecType dt, Declaration* ptempl) { const Ident* structName = nullptr; Declaration * dec = new Declaration(mScanner->mLocation, dt); + bool needVTable = false; + mScanner->NextToken(); if (mScanner->mToken == TK_IDENT) { structName = mScanner->mTokenIdent; mScanner->NextToken(); Declaration* edec = mScope->Lookup(structName); - if (edec && mScanner->mToken != TK_OPEN_BRACE && mScanner->mToken != TK_COLON) + if (edec && edec->mTemplate) + { + mTemplateScope->Insert(structName, dec); + + dec->mIdent = structName; + dec->mQualIdent = mScope->Mangle(structName->Mangle(mTemplateScope->mName->mString)); + dec->mScope = new DeclarationScope(nullptr, SLEVEL_CLASS, dec->mQualIdent); + } + else if (edec && mScanner->mToken != TK_OPEN_BRACE && mScanner->mToken != TK_COLON) { dec = edec; } @@ -65,19 +171,41 @@ Declaration* Parser::ParseStructDeclaration(uint64 flags, DecType dt) { dec->mIdent = structName; dec->mQualIdent = mScope->Mangle(structName); - dec->mScope = new DeclarationScope(nullptr, SLEVEL_CLASS, structName); + dec->mScope = new DeclarationScope(nullptr, SLEVEL_CLASS, dec->mQualIdent); } + if (ptempl) + ptempl->mBase = dec; + if ((mCompilerOptions & COPT_CPLUSPLUS) && mScanner->mToken == TK_COLON) { mScanner->NextToken(); - Declaration* pdec = ParseQualIdent(); + uint64 pflags = flags; + + if (ConsumeTokenIf(TK_PUBLIC)) + pflags &= ~(DTF_PRIVATE | DTF_PROTECTED); + else if (ConsumeTokenIf(TK_PROTECTED)) + pflags = (pflags & ~DTF_PRIVATE) | DTF_PROTECTED; + else if (ConsumeTokenIf(TK_PRIVATE)) + pflags |= DTF_PRIVATE | DTF_PROTECTED; + + Declaration* pdec = ParseBaseTypeDeclaration(0, false); if (pdec) { if (pdec->mType == DT_TYPE_STRUCT) { - dec->mBase = pdec; + Declaration* bcdec = new Declaration(mScanner->mLocation, DT_BASECLASS); + bcdec->mBase = pdec; + bcdec->mFlags = pflags; + + dec->mScope->UseScope(pdec->mScope); + + if (pdec->mVTable) + needVTable = true; + dec->mSize = pdec->mSize; + + dec->mBase = bcdec; } else mErrors->Error(mScanner->mLocation, ERRO_NOT_A_BASE_CLASS, "Not a base class", dec->mIdent); @@ -88,128 +216,448 @@ Declaration* Parser::ParseStructDeclaration(uint64 flags, DecType dt) { Declaration* pthis = nullptr; + DeclarationScope* oscope = mScope; + if (mCompilerOptions & COPT_CPLUSPLUS) { pthis = new Declaration(mScanner->mLocation, DT_TYPE_POINTER); pthis->mFlags |= DTF_CONST | DTF_DEFINED; pthis->mBase = dec; pthis->mSize = 2; + + dec->mScope->mParent = mScope; + mScope = dec->mScope; } mScanner->NextToken(); - Declaration* mlast = nullptr; - for (;;) + if (ConsumeTokenIf(TK_CLOSE_BRACE)) { - Declaration* mdec = ParseDeclaration(nullptr, false, false, pthis); + dec->mParams = nullptr; + } + else + { + int bitsleft = 0; - mdec->mQualIdent = dec->mScope->Mangle(mdec->mIdent); - - int offset = dec->mSize; - if (dt == DT_TYPE_UNION) - offset = 0; - - if (mdec->mBase->mType == DT_TYPE_FUNCTION) + Declaration* mlast = nullptr; + for (;;) { - mdec->mType = DT_CONST_FUNCTION; - mdec->mSection = mCodeSection; - mdec->mFlags |= DTF_GLOBAL; - mdec->mBase->mFlags |= DTF_FUNC_THIS; + do {} while (ConsumeTokenIf(TK_SEMICOLON)); - if (mCompilerOptions & COPT_NATIVE) - mdec->mFlags |= DTF_NATIVE; - - if (!(mdec->mFlags & DTF_FUNC_CONSTRUCTOR)) + if (ConsumeTokenIf(TK_PUBLIC)) { - Declaration* pdec = dec->mScope->Insert(mdec->mIdent, mdec); - - if (pdec) - { - if (pdec->mType == DT_CONST_FUNCTION) - { - Declaration* pcdec = nullptr; - - while (pdec && !mdec->mBase->IsSameParams(pdec->mBase)) - { - pcdec = pdec; - pdec = pdec->mNext; - } - - if (!pdec) - pcdec->mNext = mdec; - else - mErrors->Error(mdec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate struct member declaration", mdec->mIdent); - } - else - mErrors->Error(mdec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate struct member declaration", mdec->mIdent); - } - else if (mCompilationUnits->mScope->Insert(mdec->mQualIdent, mdec)) - mErrors->Error(mdec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate struct member declaration", mdec->mIdent); + flags &= ~(DTF_PRIVATE | DTF_PROTECTED); + ConsumeToken(TK_COLON); } - - if (!(mdec->mFlags & DTF_DEFINED)) - ConsumeToken(TK_SEMICOLON); - } - else - { - while (mdec) + else if (ConsumeTokenIf(TK_PROTECTED)) { - if (!(mdec->mBase->mFlags & DTF_DEFINED)) - mErrors->Error(mdec->mLocation, EERR_UNDEFINED_OBJECT, "Undefined type used in struct member declaration"); - - if (mdec->mType != DT_VARIABLE) - { - mErrors->Error(mdec->mLocation, EERR_UNDEFINED_OBJECT, "Named structure element expected"); - break; - } - - mdec->mType = DT_ELEMENT; - mdec->mOffset = offset; - - offset += mdec->mBase->mSize; - if (offset > dec->mSize) - dec->mSize = offset; - - if (dec->mScope->Insert(mdec->mIdent, mdec)) - mErrors->Error(mdec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate struct member declaration", mdec->mIdent); - - if (mlast) - mlast->mNext = mdec; - else - dec->mParams = mdec; - mlast = mdec; - mdec = mdec->mNext; + flags &= ~DTF_PRIVATE; + flags |= DTF_PROTECTED; + ConsumeToken(TK_COLON); } - - if (mScanner->mToken == TK_SEMICOLON) - mScanner->NextToken(); - else + else if (ConsumeTokenIf(TK_PRIVATE)) + { + flags |= DTF_PRIVATE | DTF_PROTECTED; + ConsumeToken(TK_COLON); + } + else if (ConsumeTokenIf(TK_FRIEND)) + { + mScope = oscope; + Declaration* fdec = ParseDeclaration(nullptr, true, false); + if (fdec->mType == DT_ANON) + fdec = fdec->mBase; + dec->mFriends.Push(fdec); + mScope = dec->mScope; + } + else if (ConsumeTokenIf(TK_CLOSE_BRACE)) { - mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "';' expected"); break; } + else if (ConsumeTokenIf(TK_TEMPLATE)) + { + ParseTemplateDeclaration(pthis); + } + else + { + Declaration* mdec = ParseDeclaration(nullptr, false, false, pthis); + if (mdec) + { + mdec->mQualIdent = dec->mScope->Mangle(mdec->mIdent); + + int offset = dec->mSize; + if (dt == DT_TYPE_UNION) + offset = 0; + + if (mdec->mBase->mType == DT_TYPE_FUNCTION) + { + mdec->mFlags |= flags & (DTF_PRIVATE | DTF_PROTECTED); + + if (mdec->mBase->mFlags & DTF_VIRTUAL) + needVTable = true; + + mdec->mType = DT_CONST_FUNCTION; + mdec->mSection = mCodeSection; + mdec->mFlags |= DTF_GLOBAL; +// mdec->mBase->mFlags |= DTF_FUNC_THIS; + + if (mCompilerOptions & COPT_NATIVE) + mdec->mFlags |= DTF_NATIVE; + + AddMemberFunction(dec, mdec); + } + else if ((mCompilerOptions & COPT_CPLUSPLUS) && mdec->mType == DT_ANON) + { + mdec->mFlags |= flags & (DTF_PRIVATE | DTF_PROTECTED); + + ConsumeToken(TK_SEMICOLON); + // anon element + } + else + { + while (mdec) + { + mdec->mFlags |= flags & (DTF_PRIVATE | DTF_PROTECTED); + + if (!(mdec->mBase->mFlags & DTF_DEFINED)) + mErrors->Error(mdec->mLocation, EERR_UNDEFINED_OBJECT, "Undefined type used in struct member declaration"); + + if (mdec->mType != DT_VARIABLE) + { + mErrors->Error(mdec->mLocation, EERR_UNDEFINED_OBJECT, "Named structure element expected"); + break; + } + + if (mdec->mFlags & DTF_STATIC) + { + mdec->mFlags |= DTF_GLOBAL; + mdec->mVarIndex = -1; + mdec->mQualIdent = mScope->Mangle(mdec->mIdent); + + Declaration * pdec = mCompilationUnits->mScope->Insert(mdec->mQualIdent, mdec); + + if (pdec) + mdec = pdec; + + if (dec->mScope->Insert(mdec->mIdent, mdec)) + mErrors->Error(mdec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate struct member declaration", mdec->mIdent); + } + else + { + mdec->mType = DT_ELEMENT; + mdec->mOffset = offset; + + if (mdec->mBits) + { + if (mdec->mBits <= 8) + { + if (bitsleft == 0) + { + bitsleft = 8 - mdec->mBits; + offset++; + } + else if (bitsleft >= mdec->mBits) + { + mdec->mOffset--; + mdec->mShift = 8 - bitsleft; + bitsleft -= mdec->mBits; + } + else + { + mdec->mOffset--; + mdec->mShift = 8 - bitsleft; + bitsleft = 8 + bitsleft - mdec->mBits; + offset++; + } + } + else if (mdec->mBits <= 16) + { + if (bitsleft == 0) + { + bitsleft = 16 - mdec->mBits; + offset += 2; + } + else if (bitsleft + 8 >= mdec->mBits) + { + mdec->mOffset--; + mdec->mShift = 8 - bitsleft; + bitsleft = bitsleft + 8 - mdec->mBits; + offset++; + } + else + { + mdec->mOffset -= 3; + mdec->mShift = 24 - bitsleft; + bitsleft = bitsleft + 16 - mdec->mBits; + offset += 2; + } + } + else if (mdec->mBits <= 24) + { + if (bitsleft == 0) + { + bitsleft = 24 - mdec->mBits; + offset += 3; + } + else if (bitsleft + 16 >= mdec->mBits) + { + mdec->mOffset -= 2; + mdec->mShift = 16 - bitsleft; + bitsleft = bitsleft + 16 - mdec->mBits; + offset += 2; + } + else + { + mdec->mOffset -= 1; + mdec->mShift = 8 - bitsleft; + bitsleft = bitsleft + 24 - mdec->mBits; + offset += 3; + } + } + else + { + if (bitsleft == 0) + { + bitsleft = 32 - mdec->mBits; + offset += 4; + } + else if (bitsleft + 24 >= mdec->mBits) + { + mdec->mOffset--; + mdec->mShift = 8 - bitsleft; + bitsleft = bitsleft + 24 - mdec->mBits; + offset+=2; + } + else + { + bitsleft = 32 - mdec->mBits; + offset += mdec->mBase->mSize; + } + } + + if (mdec->mShift == 0 && mdec->mBits == 8 * mdec->mSize) + mdec->mBits = 0; + } + else + { + bitsleft = 0; + offset += mdec->mBase->mSize; + } + + if (offset > dec->mSize) + dec->mSize = offset; + + if (dec->mScope->Insert(mdec->mIdent, mdec)) + mErrors->Error(mdec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate struct member declaration", mdec->mIdent); + + if (dec->mConst) + { + Declaration* cmdec = mdec->Clone(); + cmdec->mBase = mdec->mBase->ToConstType(); + + dec->mConst->mScope->Insert(cmdec->mIdent, cmdec); + dec->mConst->mSize = dec->mSize; + } + + if (mlast) + mlast->mNext = mdec; + else + dec->mParams = mdec; + mlast = mdec; + } + + mdec = mdec->mNext; + } + + if (mScanner->mToken == TK_SEMICOLON) + mScanner->NextToken(); + else + { + mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "';' expected"); + break; + } + } + } + } } - if (mScanner->mToken == TK_CLOSE_BRACE) - { - mScanner->NextToken(); - break; - } + if (mlast) + mlast->mNext = nullptr; + else + dec->mParams = nullptr; } - if (mlast) - mlast->mNext = nullptr; - else - dec->mParams = nullptr; + dec->SetDefined(); + if (dec->mConst) + dec->mConst->mSize = dec->mSize; - dec->mFlags |= DTF_DEFINED; + if ((mCompilerOptions & COPT_CPLUSPLUS) && dec->mType == DT_TYPE_STRUCT && dec->mIdent) + { + if (needVTable) + { + Declaration* vdec = mCompilationUnits->mVTableScope->Lookup(dec->mQualIdent); + if (!vdec) + { + vdec = new Declaration(dec->mLocation, DT_VTABLE); + + if (dec->mBase) + { + vdec->mBase = dec->mBase->mBase->mVTable; + vdec->mSize = vdec->mBase->mSize; + vdec->mOffset = vdec->mBase->mOffset; + } + else + { + vdec->mOffset = 0; + } + + vdec->mDefaultConstructor = new Declaration(dec->mLocation, DT_CONST_INTEGER); + vdec->mDefaultConstructor->mBase = TheConstCharTypeDeclaration; + vdec->mDefaultConstructor->mSize = 1; + vdec->mDefaultConstructor->mInteger = -1; + + vdec->mClass = dec; + vdec->mScope = new DeclarationScope(nullptr, SLEVEL_CLASS); + vdec->mIdent = dec->mIdent; + vdec->mQualIdent = dec->mQualIdent; + mCompilationUnits->mVTableScope->Insert(vdec->mQualIdent, vdec); + } + + dec->mVTable = vdec; + + if (!dec->mBase) + { + Declaration* mdec = dec->mParams; + while (mdec) + { + mdec->mOffset++; + mdec = mdec->mNext; + } + dec->mSize++; + if (dec->mConst) + dec->mConst->mSize = dec->mSize; + } + + dec->mScope->Iterate([=](const Ident* ident, Declaration* mdec) + { + if (mdec->mType == DT_CONST_FUNCTION) + { + while (mdec) + { + if (mdec->mBase->mFlags & DTF_VIRTUAL) + { + Declaration* vpdec = vdec; + Declaration* vmdec; + if (mdec->mIdent->mString[0] == '~') + { + // this is the destructor, need special search + + vmdec = vpdec->mScope->Lookup(vpdec->mIdent->PreMangle("~")); + while (!vmdec && vpdec->mBase) + { + vpdec = vpdec->mBase; + vmdec = vpdec->mScope->Lookup(vpdec->mIdent->PreMangle("~")); + } + } + else + { + vmdec = vpdec->mScope->Lookup(ident); + while (!vmdec && vpdec->mBase) + { + vpdec = vpdec->mBase; + vmdec = vpdec->mScope->Lookup(ident); + } + } + + Declaration* vmpdec = nullptr; + + while (vmdec && !mdec->mBase->IsDerivedFrom(vmdec->mBase)) + { + vmpdec = vmdec; + vmdec = vmdec->mNext; + } + + if (!vmdec) + { + vmdec = mdec->Clone(); + vmdec->mNext = nullptr; + vmdec->mDefaultConstructor = dec->mVTable; + vmdec->mFlags |= DTF_NATIVE; + + if (vmpdec) + vmpdec->mNext = vmdec; + else + vdec->mScope->Insert(ident, vmdec); + } + + mdec->mVTable = vmdec; + } + + mdec = mdec->mNext; + } + } + } + ); + } + + AddDefaultConstructors(pthis); + + if (pthis->mBase->mConst) + { + pthis->mBase->mConst->mDestructor = pthis->mBase->mDestructor; + pthis->mBase->mConst->mDefaultConstructor = pthis->mBase->mDefaultConstructor; + pthis->mBase->mConst->mCopyConstructor = pthis->mBase->mCopyConstructor; + pthis->mBase->mConst->mMoveConstructor = pthis->mBase->mMoveConstructor; + pthis->mBase->mConst->mVectorConstructor = pthis->mBase->mVectorConstructor; + pthis->mBase->mConst->mVectorCopyConstructor = pthis->mBase->mVectorCopyConstructor; + } + + // Lookup constructors, have same name as class + Declaration* cdec = dec->mScope->Lookup(dec->mIdent->PreMangle("+"), SLEVEL_SCOPE); + while (cdec) + { + if (cdec->mFlags & DTF_DEFINED) + PrependMemberConstructor(pthis, cdec); + cdec = cdec->mNext; + } + + AppendMemberDestructor(pthis); + + } + + mScope = oscope; } return dec; } -Declaration* Parser::ParseBaseTypeDeclaration(uint64 flags) +Declaration* Parser::ParseBaseTypeQualify(bool qualified, Declaration* dec, const Ident*& pident) +{ + while (dec && (dec->mType == DT_NAMESPACE || (qualified && (dec->mType == DT_TYPE_STRUCT || dec->mType == DT_TYPE_TEMPLATE)) && !dec->mTemplate) && ConsumeTokenIf(TK_COLCOLON)) + { + if (ExpectToken(TK_IDENT)) + { + pident = mScanner->mTokenIdent; + if (dec->mType == DT_TYPE_TEMPLATE) + { + Declaration* ndec = new Declaration(mScanner->mLocation, DT_TYPE_TEMPLATE); + ndec->mFlags |= DTF_DEFINED; + ndec->mBase = dec; + ndec->mIdent = pident; + dec = ndec; + } + else + dec = dec->mScope->Lookup(pident); + + mScanner->NextToken(); + } + } + + return dec; +} + +Declaration* Parser::ParseBaseTypeDeclaration(uint64 flags, bool qualified, Declaration* ptempl) { Declaration* dec = nullptr; + const Ident* pident = nullptr; switch (mScanner->mToken) { @@ -262,11 +710,11 @@ Declaration* Parser::ParseBaseTypeDeclaration(uint64 flags) case TK_CONST: mScanner->NextToken(); - return ParseBaseTypeDeclaration(flags | DTF_CONST); + return ParseBaseTypeDeclaration(flags | DTF_CONST, qualified); case TK_VOLATILE: mScanner->NextToken(); - return ParseBaseTypeDeclaration(flags | DTF_VOLATILE); + return ParseBaseTypeDeclaration(flags | DTF_VOLATILE, qualified); case TK_LONG: dec = new Declaration(mScanner->mLocation, DT_TYPE_INTEGER); @@ -319,41 +767,73 @@ Declaration* Parser::ParseBaseTypeDeclaration(uint64 flags) break; case TK_IDENT: - dec = mScope->Lookup(mScanner->mTokenIdent); - if (dec && dec->mType <= DT_TYPE_FUNCTION) + pident = mScanner->mTokenIdent; + mScanner->NextToken(); + + if (mTemplateScope) { - if (dec->IsSimpleType() && (flags & ~dec->mFlags)) - { - Declaration* ndec = new Declaration(dec->mLocation, dec->mType); - ndec->mFlags = dec->mFlags | flags; - ndec->mSize = dec->mSize; - ndec->mBase = dec->mBase; - dec = ndec; - } - else if (dec->mType == DT_TYPE_STRUCT && (flags & ~dec->mFlags)) - { - Declaration* ndec = new Declaration(dec->mLocation, dec->mType); - ndec->mFlags = dec->mFlags | flags; - ndec->mSize = dec->mSize; - ndec->mBase = dec->mBase; - ndec->mScope = dec->mScope; - ndec->mParams = dec->mParams; - ndec->mIdent = dec->mIdent; - ndec->mQualIdent = dec->mQualIdent; - dec = ndec; - } - mScanner->NextToken(); + dec = mTemplateScope->Lookup(pident); + if (dec && mScanner->mToken == TK_LESS_THAN && !dec->mTemplate) + dec = nullptr; } - else if (!dec) + + if (!dec) { - mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Identifier not defined", mScanner->mTokenIdent); - mScanner->NextToken(); + dec = mScope->Lookup(pident); + if (dec && dec->mType == DT_CONST_FUNCTION && mScope->mLevel == SLEVEL_CLASS) + dec = mScope->mParent->Lookup(pident); + + dec = ParseBaseTypeQualify(qualified, dec, pident); + + if (dec && dec->mTemplate) + dec = ParseTemplateExpansion(dec->mTemplate, nullptr); + } + + dec = ParseBaseTypeQualify(qualified, dec, pident); + + if (dec) + { + if (dec->mType <= DT_TYPE_FUNCTION) + { + if ((flags & ~dec->mFlags) == DTF_CONST) + dec = dec->ToConstType(); + else if (dec->IsSimpleType() && (flags & ~dec->mFlags)) + { + Declaration* ndec = new Declaration(dec->mLocation, dec->mType); + ndec->mFlags = dec->mFlags | flags; + ndec->mSize = dec->mSize; + ndec->mBase = dec->mBase; + dec = ndec; + } + else if (dec->mType == DT_TYPE_STRUCT && (flags & ~dec->mFlags)) + { + if ((flags & ~dec->mFlags) == DTF_CONST) + dec = dec->ToConstType(); + else + { + Declaration* ndec = new Declaration(dec->mLocation, dec->mType); + ndec->mFlags = dec->mFlags | flags; + ndec->mSize = dec->mSize; + ndec->mBase = dec->mBase; + ndec->mScope = dec->mScope; + ndec->mParams = dec->mParams; + ndec->mIdent = dec->mIdent; + ndec->mQualIdent = dec->mQualIdent; + dec = ndec; + } + } + } + else if (dec->mType == DT_PACK_TEMPLATE || dec->mType == DT_PACK_TYPE) + { + if ((flags & ~dec->mFlags) == DTF_CONST) + dec = dec->ToConstType(); + } + else + mErrors->Error(mScanner->mLocation, EERR_NOT_A_TYPE, "Identifier is no type", dec->mQualIdent); } else - { - mErrors->Error(mScanner->mLocation, EERR_NOT_A_TYPE, "Identifier is no type", mScanner->mTokenIdent); - mScanner->NextToken(); - } + mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Identifier not defined", pident); + break; case TK_ENUM: @@ -445,10 +925,13 @@ Declaration* Parser::ParseBaseTypeDeclaration(uint64 flags) break; } case TK_STRUCT: - dec = ParseStructDeclaration(flags, DT_TYPE_STRUCT); + dec = ParseStructDeclaration(flags, DT_TYPE_STRUCT, ptempl); + break; + case TK_CLASS: + dec = ParseStructDeclaration(flags | DTF_PRIVATE | DTF_PROTECTED, DT_TYPE_STRUCT, ptempl); break; case TK_UNION: - dec = ParseStructDeclaration(flags, DT_TYPE_UNION); + dec = ParseStructDeclaration(flags, DT_TYPE_UNION, ptempl); break; default: mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Declaration starts with invalid token", TokenNames[mScanner->mToken]); @@ -532,9 +1015,36 @@ Declaration* Parser::ParsePostfixDeclaration(void) ndec->mBase = dec; return ndec; } - else if (mScanner->mToken == TK_OPEN_PARENTHESIS) + else if (mScanner->mToken == TK_LOGICAL_AND && (mCompilerOptions & COPT_CPLUSPLUS)) { mScanner->NextToken(); + + Declaration* ndec = new Declaration(mScanner->mLocation, DT_TYPE_RVALUEREF); + ndec->mSize = 2; + ndec->mFlags |= DTF_DEFINED; + + for (;;) + { + if (mScanner->mToken == TK_CONST) + { + ndec->mFlags |= DTF_CONST; + mScanner->NextToken(); + } + else if (mScanner->mToken == TK_VOLATILE) + { + ndec->mFlags |= DTF_VOLATILE; + mScanner->NextToken(); + } + else + break; + } + + Declaration* dec = ParsePostfixDeclaration(); + ndec->mBase = dec; + return ndec; + } + else if (ConsumeTokenIf(TK_OPEN_PARENTHESIS)) + { Declaration* vdec = ParsePostfixDeclaration(); if (mScanner->mToken == TK_CLOSE_PARENTHESIS) mScanner->NextToken(); @@ -542,14 +1052,52 @@ Declaration* Parser::ParsePostfixDeclaration(void) mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "')' expected"); dec = vdec; } + else if (ConsumeTokenIf(TK_ELLIPSIS)) + { + if (mScanner->mToken == TK_IDENT) + { + dec = new Declaration(mScanner->mLocation, DT_PACK_VARIABLE); + dec->mIdent = mScanner->mTokenIdent; + dec->mSection = mBSSection; + dec->mBase = nullptr; + mScanner->NextToken(); + } + else + { + mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Identifier expected"); + dec = new Declaration(mScanner->mLocation, DT_ANON); + dec->mBase = nullptr; + } + } else if (mScanner->mToken == TK_IDENT) { dec = new Declaration(mScanner->mLocation, DT_VARIABLE); dec->mIdent = mScanner->mTokenIdent; - dec->mQualIdent = mScope->Mangle(dec->mIdent); dec->mSection = mBSSection; dec->mBase = nullptr; mScanner->NextToken(); + + if (mScanner->mToken == TK_LESS_THAN && mTemplateScope) + { + Declaration* tdec = mScope->Lookup(dec->mIdent); + if (tdec && tdec->mTemplate) + { + // for now just skip over template stuff + while (!ConsumeTokenIf(TK_GREATER_THAN)) + mScanner->NextToken(); + + if (mTemplateScope->mParent) + { + if (mTemplateScope->mParent->mName) + dec->mIdent = dec->mIdent->Mangle(mTemplateScope->mParent->mName->mString); + } + else if (mTemplateScope->mName) + dec->mIdent = dec->mIdent->Mangle(mTemplateScope->mName->mString); + } + } + + dec->mQualIdent = mScope->Mangle(dec->mIdent); + if (mScanner->mToken == TK_OPEN_PARENTHESIS && mScope->mLevel >= SLEVEL_FUNCTION) { // Can't be a function declaration in local context, so it must be an object @@ -631,7 +1179,7 @@ Declaration * Parser::ParseFunctionDeclaration(Declaration* bdec) break; } - Declaration* bdec = ParseBaseTypeDeclaration(0); + Declaration* bdec = ParseBaseTypeDeclaration(0, true); Declaration* adec = ParsePostfixDeclaration(); adec = ReverseDeclaration(adec, bdec); @@ -644,29 +1192,103 @@ Declaration * Parser::ParseFunctionDeclaration(Declaration* bdec) } else { - if (!(adec->mBase->mFlags & DTF_DEFINED) && adec->mBase->mType != DT_TYPE_ARRAY) + if (!(adec->mBase->mFlags & DTF_DEFINED) && adec->mBase->mType != DT_TYPE_ARRAY && !adec->mBase->mTemplate) mErrors->Error(adec->mLocation, EERR_UNDEFINED_OBJECT, "Type of argument not defined"); - adec->mType = DT_ARGUMENT; - adec->mVarIndex = vi; - adec->mOffset = 0; - if (adec->mBase->mType == DT_TYPE_ARRAY) + if (adec->mType == DT_PACK_VARIABLE) { - Declaration* ndec = new Declaration(adec->mBase->mLocation, DT_TYPE_POINTER); - ndec->mBase = adec->mBase->mBase; - ndec->mSize = 2; - ndec->mFlags |= DTF_DEFINED; - adec->mBase = ndec; + adec->mType = DT_PACK_ARGUMENT; + if (adec->mBase) + { + ndec->mParamPack = adec; + + Declaration* atdec = adec->mBase; + + if (atdec->IsReference()) + atdec = atdec->mBase; + if (atdec->mType == DT_PACK_TYPE) + { + atdec = atdec->mParams; + + Declaration* apdec = adec; + while (atdec) + { + apdec = new Declaration(adec->mLocation, DT_ARGUMENT); + if (!adec->mParams) + adec->mParams = apdec; + + if (adec->mBase->IsReference()) + { + if (adec->mBase->mBase->mFlags & DTF_CONST) + apdec->mBase = atdec->ToConstType()->BuildReference(adec->mLocation, adec->mBase->mType); + else + apdec->mBase = atdec->BuildReference(adec->mLocation, adec->mBase->mType); + } + else + apdec->mBase = atdec; + + atdec = atdec->mNext; + apdec->mFlags = DTF_DEFINED; + apdec->mVarIndex = vi; + apdec->mOffset = 0; + + if (apdec->mBase->mType == DT_TYPE_ARRAY) + { + Declaration* ndec = new Declaration(apdec->mBase->mLocation, DT_TYPE_POINTER); + ndec->mBase = apdec->mBase->mBase; + ndec->mSize = 2; + ndec->mFlags |= DTF_DEFINED; + apdec->mBase = ndec; + } + + apdec->mSize = apdec->mBase->mSize; + + vi += apdec->mSize; + if (pdec) + pdec->mNext = apdec; + else + ndec->mParams = apdec; + pdec = apdec; + } + } + else + { + if (pdec) + pdec->mNext = adec; + else + ndec->mParams = adec; + pdec = adec; + } + } } - - adec->mSize = adec->mBase->mSize; - - vi += adec->mSize; - if (pdec) - pdec->mNext = adec; else - ndec->mParams = adec; - pdec = adec; + { + adec->mType = DT_ARGUMENT; + adec->mVarIndex = vi; + adec->mOffset = 0; + if (adec->mBase->mType == DT_TYPE_ARRAY) + { + Declaration* ndec = new Declaration(adec->mBase->mLocation, DT_TYPE_POINTER); + ndec->mBase = adec->mBase->mBase; + ndec->mSize = 2; + ndec->mFlags |= DTF_DEFINED; + adec->mBase = ndec; + } + + adec->mSize = adec->mBase->mSize; + + if ((mCompilerOptions & COPT_CPLUSPLUS) && ConsumeTokenIf(TK_ASSIGN)) + { + adec->mValue = ParseExpression(false); + } + + vi += adec->mSize; + if (pdec) + pdec->mNext = adec; + else + ndec->mParams = adec; + pdec = adec; + } if (mScanner->mToken == TK_COMMA) mScanner->NextToken(); @@ -934,6 +1556,7 @@ Expression* Parser::ParseInitExpression(Declaration* dtype) } Expression* texp = ParseInitExpression(dtype->mBase); + texp = texp->ConstantFold(mErrors, mDataSection); for (int i = 0; i < nrep; i++) { Declaration* cdec = CopyConstantInitializer(index, dtype->mBase, texp); @@ -963,18 +1586,37 @@ Expression* Parser::ParseInitExpression(Declaration* dtype) } else { - Declaration* mdec = dtype->mParams; - while (mdec) + ExpandingArray path; + + Declaration* ttype = dtype; + while (ttype->mBase) + { + path.Push(ttype); + ttype = ttype->mBase->mBase; + } + + Declaration* mdec = ttype->mParams; + for(;;) { if (ConsumeTokenIf(TK_DOT)) { if (mScanner->mToken == TK_IDENT) { - Declaration* ndec = dtype->mScope->Lookup(mScanner->mTokenIdent); + ttype = dtype; + + path.SetSize(0); + Declaration* ndec = ttype->mScope->Lookup(mScanner->mTokenIdent, SLEVEL_SCOPE); + while (!ndec && ttype->mBase) + { + path.Push(ttype); + ttype = ttype->mBase->mBase; + ndec = ttype->mScope->Lookup(mScanner->mTokenIdent, SLEVEL_SCOPE); + } + if (ndec) mdec = ndec; else - mErrors->Error(mScanner->mLocation, EERR_CONSTANT_INITIALIZER, "Struct member not found"); + mErrors->Error(mScanner->mLocation, EERR_CONSTANT_INITIALIZER, "Struct member not found", mScanner->mTokenIdent); mScanner->NextToken(); ConsumeToken(TK_ASSIGN); @@ -982,20 +1624,30 @@ Expression* Parser::ParseInitExpression(Declaration* dtype) else mErrors->Error(mScanner->mLocation, EERR_CONSTANT_INITIALIZER, "Identifier expected"); } + + if (mdec) + { + Expression* texp = ParseInitExpression(mdec->mBase); - Expression* texp = ParseInitExpression(mdec->mBase); + Declaration* cdec = CopyConstantInitializer(mdec->mOffset, mdec->mBase, texp); + cdec->mBits = mdec->mBits; + cdec->mShift = mdec->mShift; - Declaration* cdec = CopyConstantInitializer(mdec->mOffset, mdec->mBase, texp); + if (last) + last->mNext = cdec; + else + dec->mParams = cdec; + last = cdec; - if (last) - last->mNext = cdec; - else - dec->mParams = cdec; - last = cdec; + if (!ConsumeTokenIf(TK_COMMA)) + break; - if (!ConsumeTokenIf(TK_COMMA)) + mdec = mdec->mNext; + while (!mdec && path.Size()) + mdec = path.Pop()->mParams; + } + else if (!ConsumeTokenIf(TK_COMMA)) break; - mdec = mdec->mNext; } } @@ -1141,18 +1793,1403 @@ Expression* Parser::ParseInitExpression(Declaration* dtype) return exp; } +Expression* Parser::BuildMemberInitializer(Expression* vexp) +{ + Declaration* fcons = (vexp->mDecType->mType == DT_TYPE_STRUCT && vexp->mDecType->mScope) ? vexp->mDecType->mScope->Lookup(vexp->mDecType->mIdent->PreMangle("+")) : nullptr; + + if (fcons) + { + Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); + cexp->mDecValue = fcons; + cexp->mDecType = cexp->mDecValue->mBase; + + Expression* fexp = new Expression(mScanner->mLocation, EX_CALL); + fexp->mLeft = cexp; + + mScanner->NextToken(); + if (mScanner->mToken != TK_CLOSE_PARENTHESIS) + { + fexp->mRight = ParseListExpression(false); + ConsumeToken(TK_CLOSE_PARENTHESIS); + } + else + { + fexp->mRight = nullptr; + mScanner->NextToken(); + } + + Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX); + texp->mToken = TK_BINARY_AND; + texp->mLeft = vexp; + texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER); + texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + texp->mDecType->mBase = vexp->mDecType; + texp->mDecType->mSize = 2; + + if (fexp->mRight) + { + Expression* lexp = new Expression(mScanner->mLocation, EX_LIST); + lexp->mLeft = texp; + lexp->mRight = fexp->mRight; + fexp->mRight = lexp; + } + else + fexp->mRight = texp; + + fexp = ResolveOverloadCall(fexp); + + return fexp; + } + else + { + Expression* nexp = new Expression(mScanner->mLocation, EX_INITIALIZATION); + nexp->mToken = TK_ASSIGN; + nexp->mDecType = vexp->mDecType; + nexp->mLeft = vexp; + ConsumeToken(TK_OPEN_PARENTHESIS); + if (!ConsumeTokenIf(TK_CLOSE_PARENTHESIS)) + { + nexp->mRight = ParseRExpression(); + ConsumeToken(TK_CLOSE_PARENTHESIS); + } + + return nexp; + } +} + +void Parser::PrependMemberConstructor(Declaration* pthis, Declaration* cfunc) +{ + if (cfunc->mFlags & DTF_COMPLETED) + return; + + cfunc->mFlags |= DTF_COMPLETED; + + Expression* pthisexp = new Expression(pthis->mLocation, EX_VARIABLE); + pthisexp->mDecType = pthis; + pthisexp->mDecValue = cfunc->mBase->mParams; + + Expression* thisexp = new Expression(mScanner->mLocation, EX_PREFIX); + thisexp->mToken = TK_MUL; + thisexp->mDecType = pthis->mBase; + thisexp->mLeft = pthisexp; + + Declaration* bcdec = pthis->mBase->mBase; + while (bcdec) + { + Declaration* mfunc = cfunc->mScope ? cfunc->mScope->Lookup(bcdec->mBase->mIdent) : nullptr; + + if (mfunc) + { + Expression* sexp = new Expression(cfunc->mLocation, EX_SEQUENCE); + sexp->mLeft = mfunc->mValue; + sexp->mRight = cfunc->mValue; + cfunc->mValue = sexp; + } + else if (bcdec->mBase->mDefaultConstructor) + { + Declaration* mdec = bcdec->mBase->mDefaultConstructor; + + Expression* cexp = new Expression(pthis->mLocation, EX_CONSTANT); + cexp->mDecValue = mdec; + cexp->mDecType = cexp->mDecValue->mBase; + + Expression * dexp = new Expression(mScanner->mLocation, EX_CALL); + dexp->mLeft = cexp; + dexp->mRight = pthisexp; + + Expression* sexp = new Expression(mScanner->mLocation, EX_SEQUENCE); + + sexp->mLeft = dexp; + sexp->mRight = cfunc->mValue; + cfunc->mValue = sexp; + } + + bcdec = bcdec->mNext; + } + + Declaration* dec = pthis->mBase->mParams; + if (dec) + { + + dec = dec->Last(); + while (dec) + { + if (dec->mType == DT_ELEMENT) + { + Declaration* mfunc = cfunc->mScope ? cfunc->mScope->Lookup(dec->mIdent) : nullptr; + + if (mfunc) + { + Expression* sexp = new Expression(cfunc->mLocation, EX_SEQUENCE); + sexp->mLeft = mfunc->mValue; + sexp->mRight = cfunc->mValue; + cfunc->mValue = sexp; + } + else + { + Declaration* bdec = dec->mBase; + while (bdec->mType == DT_TYPE_ARRAY) + bdec = bdec->mBase; + + if (bdec->mType == DT_TYPE_STRUCT && bdec->mDefaultConstructor || dec->mValue) + { + Expression* qexp = new Expression(pthis->mLocation, EX_QUALIFY); + qexp->mLeft = thisexp; + qexp->mDecValue = dec; + + Expression* dexp; + + if (dec->mValue) + { + qexp->mDecType = bdec; + + dexp = new Expression(mScanner->mLocation, EX_INITIALIZATION); + dexp->mToken = TK_ASSIGN; + dexp->mDecType = bdec; + dexp->mLeft = qexp; + dexp->mRight = dec->mValue; + } + else if (dec->mSize == bdec->mSize) + { + qexp->mDecType = bdec; + + Expression* pexp = new Expression(pthis->mLocation, EX_PREFIX); + pexp->mLeft = qexp; + pexp->mToken = TK_BINARY_AND; + pexp->mDecType = new Declaration(pthis->mLocation, DT_TYPE_POINTER); + pexp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + pexp->mDecType->mBase = bdec; + pexp->mDecType->mSize = 2; + + Declaration* mdec = bdec->mDefaultConstructor; + + Expression* cexp = new Expression(pthis->mLocation, EX_CONSTANT); + if (mdec) + { + cexp->mDecValue = mdec; + cexp->mDecType = cexp->mDecValue->mBase; + } + else + mErrors->Error(dec->mLocation, EERR_NO_DEFAULT_CONSTRUCTOR, "No default constructor"); + + dexp = new Expression(mScanner->mLocation, EX_CALL); + dexp->mLeft = cexp; + dexp->mRight = pexp; + } + else + { + qexp->mDecType = dec->mBase->mBase; + + while (qexp->mDecType->mType == DT_TYPE_ARRAY) + { + Expression* iexp = new Expression(pthis->mLocation, EX_PREFIX); + iexp->mToken = TK_MUL; + iexp->mLeft = qexp; + iexp->mDecType = qexp->mDecType->mBase; + qexp = iexp; + } + + qexp->mDecType = new Declaration(pthis->mLocation, DT_TYPE_POINTER); + qexp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + qexp->mDecType->mBase = bdec; + qexp->mDecType->mSize = 2; + + Expression* cexp = new Expression(pthis->mLocation, EX_CONSTANT); + cexp->mDecValue = bdec->mVectorConstructor; + cexp->mDecType = cexp->mDecValue->mBase; + + Declaration* ncdec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER); + ncdec->mBase = TheUnsignedIntTypeDeclaration; + ncdec->mInteger = dec->mSize / bdec->mSize; + + dexp = new Expression(mScanner->mLocation, EX_CALL); + dexp->mLeft = cexp; + dexp->mRight = new Expression(mScanner->mLocation, EX_LIST); + dexp->mRight->mLeft = qexp; + dexp->mRight->mRight = new Expression(mScanner->mLocation, EX_BINARY); + dexp->mRight->mRight->mToken = TK_ADD; + dexp->mRight->mRight->mLeft = qexp; + dexp->mRight->mRight->mDecType = qexp->mDecType; + dexp->mRight->mRight->mRight = new Expression(mScanner->mLocation, EX_CONSTANT); + dexp->mRight->mRight->mRight->mDecType = ncdec->mBase; + dexp->mRight->mRight->mRight->mDecValue = ncdec; + } + + Expression* sexp = new Expression(mScanner->mLocation, EX_SEQUENCE); + + sexp->mLeft = dexp; + sexp->mRight = cfunc->mValue; + cfunc->mValue = sexp; + } + } + } + + dec = dec->mPrev; + } + } + + if (pthis->mBase->mVTable) + { + Expression* sexp = new Expression(cfunc->mLocation, EX_SEQUENCE); + sexp->mLeft = cfunc->mValue; + + Expression* vexp = new Expression(pthis->mLocation, EX_QUALIFY); + vexp->mLeft = thisexp; + vexp->mDecValue = new Declaration(pthis->mLocation, DT_ELEMENT); + vexp->mDecValue->mBase = TheCharTypeDeclaration; + vexp->mDecValue->mOffset = pthis->mBase->mVTable->mOffset; + vexp->mDecValue->mSize = 1; + vexp->mDecType = TheCharTypeDeclaration; + + Expression* nexp = new Expression(cfunc->mLocation, EX_INITIALIZATION); + nexp->mToken = TK_ASSIGN; + nexp->mDecType = TheCharTypeDeclaration; + nexp->mLeft = vexp; + nexp->mRight = new Expression(cfunc->mLocation, EX_CONSTANT); + nexp->mRight->mDecType = TheCharTypeDeclaration; + nexp->mRight->mDecValue = pthis->mBase->mVTable->mDefaultConstructor; + + sexp->mRight = nexp; + cfunc->mValue = sexp; + } +} + +void Parser::BuildMemberConstructor(Declaration* pthis, Declaration* cfunc) +{ + Expression* pthisexp = new Expression(pthis->mLocation, EX_VARIABLE); + pthisexp->mDecType = pthis; + pthisexp->mDecValue = cfunc->mBase->mParams; + + Expression* thisexp = new Expression(mScanner->mLocation, EX_PREFIX); + thisexp->mToken = TK_MUL; + thisexp->mDecType = pthis->mBase; + thisexp->mLeft = pthisexp; + + cfunc->mScope = new DeclarationScope(nullptr, SLEVEL_CLASS); + + DeclarationScope* scope = new DeclarationScope(mScope, SLEVEL_FUNCTION); + mScope = scope; + + Declaration* pdec = cfunc->mBase->mParams; + while (pdec) + { + if (pdec->mIdent) + scope->Insert(pdec->mIdent, pdec); + pdec = pdec->mNext; + } + if (cfunc->mBase->mParamPack) + mScope->Insert(cfunc->mBase->mParamPack->mIdent, cfunc->mBase->mParamPack); + + Declaration* othis = mThisPointer; + mThisPointer = pthis; + + mScanner->NextToken(); + do { + if (ExpectToken(TK_IDENT)) + { + Declaration* dec = pthis->mBase->mScope->Lookup(mScanner->mTokenIdent); + + Declaration* pcdec = pthis->mBase->mBase; + while (pcdec && pcdec->mBase->mIdent != mScanner->mTokenIdent) + pcdec = pcdec->mNext; + + if (pcdec) + { + Expression* qexp = new Expression(mScanner->mLocation, EX_PREFIX); + qexp->mToken = TK_MUL; + qexp->mDecType = pcdec->mBase; + qexp->mLeft = pthisexp; + + Declaration* dec = new Declaration(mScanner->mLocation, DT_CONST_CONSTRUCTOR); + dec->mIdent = mScanner->mTokenIdent; + + mScanner->NextToken(); + + dec->mValue = BuildMemberInitializer(qexp); + + cfunc->mScope->Insert(dec->mIdent, dec); + } + else if (dec && dec->mType == DT_ELEMENT) + { + Expression* qexp = new Expression(pthis->mLocation, EX_QUALIFY); + qexp->mLeft = thisexp; + qexp->mDecValue = dec; + qexp->mDecType = dec->mBase; + + Declaration* dec = new Declaration(mScanner->mLocation, DT_CONST_CONSTRUCTOR); + dec->mIdent = mScanner->mTokenIdent; + + mScanner->NextToken(); + + dec->mValue = BuildMemberInitializer(qexp); + + cfunc->mScope->Insert(dec->mIdent, dec); + } + else + mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Base class or member not found", mScanner->mTokenIdent); + } + + } while (ConsumeTokenIf(TK_COMMA)); + + mScope = mScope->mParent; + mThisPointer = othis; +} + +void Parser::AddDefaultConstructors(Declaration* pthis) +{ + bool simpleDestructor = true, simpleAssignment = true, simpleConstructor = true, simpleCopy = true, simpleMove = true; + bool inlineDestructor = true; + bool inlineConstructor = true; + bool inlineCopy = true; + bool inlineMove = true; + + + const Ident* dtorident = pthis->mBase->mIdent->PreMangle("~");; + const Ident* ctorident = pthis->mBase->mIdent->PreMangle("+");; + + // Extract constructor and destructor from scope + + Declaration* cdec = pthis->mBase->mScope->Lookup(ctorident, SLEVEL_SCOPE); + while (cdec) + { + Declaration* ctdec = cdec->mBase; + Declaration* tparam = ctdec->mParams->mNext; + + if (!tparam) + pthis->mBase->mDefaultConstructor = cdec; + else if (!tparam->mNext && tparam->mBase->mType == DT_TYPE_REFERENCE && pthis->mBase->IsConstSame(tparam->mBase->mBase)) + pthis->mBase->mCopyConstructor = cdec; + else if (!tparam->mNext && tparam->mBase->mType == DT_TYPE_RVALUEREF && pthis->mBase->IsConstSame(tparam->mBase->mBase)) + pthis->mBase->mMoveConstructor = cdec; + + cdec = cdec->mNext; + } + + Declaration* ddec = pthis->mBase->mScope->Lookup(dtorident, SLEVEL_SCOPE); + if (ddec) + pthis->mBase->mDestructor = ddec; + + Declaration* adec = pthis->mBase->mScope->Lookup(Ident::Unique("operator="), SLEVEL_SCOPE); + while (adec) + { + Declaration* atdec = adec->mBase; + Declaration* tparam = atdec->mParams->mNext; + + if (!tparam->mNext && tparam->mBase->mType == DT_TYPE_REFERENCE && pthis->mBase->IsConstSame(tparam->mBase->mBase)) + pthis->mBase->mCopyAssignment = adec; + + adec = adec->mNext; + } + + Declaration* bcdec = pthis->mBase->mBase; + while (bcdec) + { + if (bcdec->mBase->mDestructor) + { + if (!(bcdec->mBase->mDestructor->mBase->mFlags & DTF_REQUEST_INLINE)) + inlineConstructor = false; + simpleDestructor = false; + } + if (bcdec->mBase->mDefaultConstructor) + { + simpleConstructor = false; + if (!(bcdec->mBase->mDefaultConstructor->mBase->mFlags & DTF_REQUEST_INLINE)) + inlineConstructor = false; + } + if (bcdec->mBase->mCopyConstructor) + { + simpleCopy = false; + if (!(bcdec->mBase->mCopyConstructor->mBase->mFlags & DTF_REQUEST_INLINE)) + inlineCopy = false; + } + if (bcdec->mBase->mMoveConstructor) + { + simpleMove = false; + if (!(bcdec->mBase->mMoveConstructor->mBase->mFlags & DTF_REQUEST_INLINE)) + inlineCopy = false; + } + if (bcdec->mBase->mCopyAssignment) + simpleAssignment = false; + bcdec = bcdec->mNext; + } + + if (pthis->mBase->mVTable) + simpleConstructor = false; + + Declaration* dec = pthis->mBase->mParams; + while (dec) + { + if (dec->mType == DT_ELEMENT) + { + Declaration* bdec = dec->mBase; + int nitems = 1; + + while (bdec->mType == DT_TYPE_ARRAY) + bdec = bdec->mBase; + + if (bdec->mType == DT_TYPE_STRUCT) + { + if (bdec->mDestructor) + { + simpleDestructor = false; + if (!(bdec->mDestructor->mBase->mFlags & DTF_REQUEST_INLINE)) + inlineDestructor = false; + } + if (bdec->mDefaultConstructor) + { + simpleConstructor = false; + if (!(bdec->mDefaultConstructor->mBase->mFlags & DTF_REQUEST_INLINE)) + inlineConstructor = false; + } + if (bdec->mCopyConstructor) + simpleCopy = false; + if (bdec->mCopyAssignment) + simpleAssignment = false; + if (bdec->mMoveConstructor) + simpleMove = false; + } + if (dec->mValue) + simpleConstructor = false; + } + dec = dec->mNext; + } + + if (!simpleDestructor) + { + if (!pthis->mBase->mDestructor) + { + Declaration* ctdec = new Declaration(mScanner->mLocation, DT_TYPE_FUNCTION); + ctdec->mSize = 0; + Declaration* pdec = nullptr; + ctdec->mBase = TheVoidTypeDeclaration; + ctdec->mFlags |= DTF_DEFINED; + + PrependThisArgument(ctdec, pthis); + + Declaration* cdec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION); + cdec->mBase = ctdec; + + cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE); + if (inlineDestructor) + cdec->mFlags |= DTF_REQUEST_INLINE; + + cdec->mSection = mCodeSection; + + if (mCompilerOptions & COPT_NATIVE) + cdec->mFlags |= DTF_NATIVE; + + pthis->mBase->mDestructor = cdec; + + cdec->mIdent = dtorident; + cdec->mQualIdent = pthis->mBase->mScope->Mangle(cdec->mIdent); + + cdec->mCompilerOptions = mCompilerOptions; + cdec->mBase->mCompilerOptions = mCompilerOptions; + + cdec->mVarIndex = -1; + + cdec->mFlags |= DTF_DEFINED; + + cdec->mValue = new Expression(mScanner->mLocation, EX_VOID); + } + } + + if (!simpleConstructor) + { + if (!pthis->mBase->mDefaultConstructor) + { + Declaration* ctdec = new Declaration(mScanner->mLocation, DT_TYPE_FUNCTION); + ctdec->mSize = 0; + + Declaration* pdec = nullptr; + ctdec->mBase = TheVoidTypeDeclaration; + ctdec->mFlags |= DTF_DEFINED; + + PrependThisArgument(ctdec, pthis); + + Declaration* cdec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION); + cdec->mBase = ctdec; + + cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE); + if (inlineConstructor) + cdec->mFlags |= DTF_REQUEST_INLINE; + + cdec->mSection = mCodeSection; + + if (mCompilerOptions & COPT_NATIVE) + cdec->mFlags |= DTF_NATIVE; + + pthis->mBase->mDefaultConstructor = cdec; + + cdec->mIdent = ctorident; + cdec->mQualIdent = pthis->mBase->mScope->Mangle(cdec->mIdent); + + AddMemberFunction(pthis->mBase, cdec); + + cdec->mCompilerOptions = mCompilerOptions; + cdec->mBase->mCompilerOptions = mCompilerOptions; + + cdec->mVarIndex = -1; + + cdec->mFlags |= DTF_DEFINED; + + cdec->mValue = new Expression(mScanner->mLocation, EX_VOID); + } + } + + if (!simpleCopy) + { + if (!pthis->mBase->mCopyConstructor) + { + Declaration* ctdec = new Declaration(mScanner->mLocation, DT_TYPE_FUNCTION); + ctdec->mSize = 0; + ctdec->mBase = TheVoidTypeDeclaration; + ctdec->mFlags |= DTF_DEFINED; + + Declaration* adec = new Declaration(mScanner->mLocation, DT_ARGUMENT); + adec->mVarIndex = 0; + adec->mOffset = 0; + adec->mBase = new Declaration(mScanner->mLocation, DT_TYPE_REFERENCE); + adec->mBase->mSize = 2; + adec->mBase->mBase = pthis->mBase->ToConstType(); + adec->mBase->mFlags |= DTF_CONST | DTF_DEFINED; + adec->mSize = adec->mBase->mSize; + adec->mIdent = adec->mQualIdent = Ident::Unique("_"); + + ctdec->mParams = adec; + + PrependThisArgument(ctdec, pthis); + + Declaration* cdec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION); + cdec->mBase = ctdec; + + cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE); + if (inlineCopy) + cdec->mFlags |= DTF_REQUEST_INLINE; + + cdec->mSection = mCodeSection; + + if (mCompilerOptions & COPT_NATIVE) + cdec->mFlags |= DTF_NATIVE; + + pthis->mBase->mCopyConstructor = cdec; + + cdec->mIdent = ctorident; + cdec->mQualIdent = pthis->mBase->mScope->Mangle(cdec->mIdent); + + AddMemberFunction(pthis->mBase, cdec); + + cdec->mCompilerOptions = mCompilerOptions; + cdec->mBase->mCompilerOptions = mCompilerOptions; + + cdec->mVarIndex = -1; + + cdec->mValue = new Expression(mScanner->mLocation, EX_VOID); + + // Now add all the copying + + Expression* pthisexp = new Expression(pthis->mLocation, EX_VARIABLE); + pthisexp->mDecType = pthis; + pthisexp->mDecValue = cdec->mBase->mParams; + + Expression* thisexp = new Expression(mScanner->mLocation, EX_PREFIX); + thisexp->mToken = TK_MUL; + thisexp->mDecType = pthis->mBase; + thisexp->mLeft = pthisexp; + + Expression* thatexp = new Expression(pthis->mLocation, EX_VARIABLE); + thatexp->mDecType = adec->mBase; + thatexp->mDecValue = cdec->mBase->mParams->mNext; + + cdec->mScope = new DeclarationScope(nullptr, SLEVEL_CLASS); + + Declaration* dec = pthis->mBase->mParams; + while (dec) + { + if (dec->mType == DT_ELEMENT) + { + Expression* lexp = new Expression(pthis->mLocation, EX_QUALIFY); + lexp->mLeft = thisexp; + lexp->mDecValue = dec; + lexp->mDecType = dec->mBase; + + Expression* rexp = new Expression(pthis->mLocation, EX_QUALIFY); + rexp->mLeft = thatexp; + rexp->mDecValue = dec; + rexp->mDecType = dec->mBase; + + Expression* mexp; + + Declaration* bdec = dec->mBase; + while (bdec->mType == DT_TYPE_ARRAY) + bdec = bdec->mBase; + + if (bdec->mType == DT_TYPE_STRUCT && bdec->mCopyConstructor) + { + if (dec->mSize == bdec->mSize) + { + Expression* pexp = new Expression(pthis->mLocation, EX_PREFIX); + pexp->mLeft = lexp; + pexp->mToken = TK_BINARY_AND; + pexp->mDecType = new Declaration(pthis->mLocation, DT_TYPE_POINTER); + pexp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + pexp->mDecType->mBase = dec->mBase; + pexp->mDecType->mSize = 2; + + Declaration* mdec = dec->mBase->mCopyConstructor; + + Expression* cexp = new Expression(pthis->mLocation, EX_CONSTANT); + cexp->mDecValue = mdec; + cexp->mDecType = cexp->mDecValue->mBase; + + mexp = new Expression(mScanner->mLocation, EX_CALL); + mexp->mLeft = cexp; + mexp->mRight = new Expression(mScanner->mLocation, EX_LIST); + mexp->mRight->mLeft = pexp; + mexp->mRight->mRight = rexp; + } + else + { + lexp->mDecType = new Declaration(pthis->mLocation, DT_TYPE_POINTER); + lexp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + lexp->mDecType->mBase = bdec; + lexp->mDecType->mSize = 2; + + rexp->mDecType = new Declaration(pthis->mLocation, DT_TYPE_POINTER); + rexp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + rexp->mDecType->mBase = bdec; + rexp->mDecType->mSize = 2; + + Expression* cexp = new Expression(pthis->mLocation, EX_CONSTANT); + cexp->mDecValue = bdec->mVectorCopyConstructor; + cexp->mDecType = cexp->mDecValue->mBase; + + Declaration* ncdec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER); + ncdec->mBase = TheUnsignedIntTypeDeclaration; + ncdec->mInteger = dec->mSize / bdec->mSize; + + mexp = new Expression(mScanner->mLocation, EX_CALL); + mexp->mLeft = cexp; + mexp->mRight = new Expression(mScanner->mLocation, EX_LIST); + mexp->mRight->mLeft = lexp; + mexp->mRight->mRight = new Expression(mScanner->mLocation, EX_LIST); + mexp->mRight->mRight->mLeft = rexp; + mexp->mRight->mRight->mRight = new Expression(mScanner->mLocation, EX_CONSTANT); + mexp->mRight->mRight->mRight->mDecType = ncdec->mBase; + mexp->mRight->mRight->mRight->mDecValue = ncdec; + + } + } + else + { + mexp = new Expression(mScanner->mLocation, EX_INITIALIZATION); + mexp->mToken = TK_ASSIGN; + mexp->mLeft = lexp; + mexp->mRight = rexp; + mexp->mDecType = lexp->mDecType; + } + + Declaration* mcdec = new Declaration(mScanner->mLocation, DT_CONST_CONSTRUCTOR); + mcdec->mIdent = mScanner->mTokenIdent; + mcdec->mValue = mexp; + + cdec->mScope->Insert(dec->mIdent, mcdec); + } + + dec = dec->mNext; + } + + cdec->mFlags |= DTF_DEFINED; + } + } + + if (!simpleAssignment) + { + // Copy assignment operator + if (!pthis->mBase->mCopyAssignment) + { + Declaration* ctdec = new Declaration(mScanner->mLocation, DT_TYPE_FUNCTION); + ctdec->mSize = 0; + ctdec->mBase = new Declaration(mScanner->mLocation, DT_TYPE_REFERENCE); + ctdec->mBase->mSize = 2; + ctdec->mBase->mBase = pthis->mBase; + ctdec->mBase->mFlags |= DTF_DEFINED; + ctdec->mFlags |= DTF_DEFINED; + + Declaration* adec = new Declaration(mScanner->mLocation, DT_ARGUMENT); + adec->mVarIndex = 0; + adec->mOffset = 0; + adec->mBase = new Declaration(mScanner->mLocation, DT_TYPE_REFERENCE); + adec->mBase->mSize = 2; + adec->mBase->mBase = pthis->mBase; + adec->mBase->mFlags |= DTF_CONST | DTF_DEFINED; + adec->mSize = adec->mBase->mSize; + adec->mIdent = adec->mQualIdent = Ident::Unique("_"); + + ctdec->mParams = adec; + + PrependThisArgument(ctdec, pthis); + + Declaration* cdec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION); + cdec->mBase = ctdec; + + cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE); + + cdec->mSection = mCodeSection; + + if (mCompilerOptions & COPT_NATIVE) + cdec->mFlags |= DTF_NATIVE; + + cdec->mIdent = Ident::Unique("operator="); + cdec->mQualIdent = pthis->mBase->mScope->Mangle(cdec->mIdent); + + pthis->mBase->mCopyAssignment = cdec; + + cdec->mCompilerOptions = mCompilerOptions; + cdec->mBase->mCompilerOptions = mCompilerOptions; + + AddMemberFunction(pthis->mBase, cdec); + + cdec->mVarIndex = -1; + + Expression* pthisexp = new Expression(pthis->mLocation, EX_VARIABLE); + pthisexp->mDecType = pthis; + pthisexp->mDecValue = cdec->mBase->mParams; + + Expression* thisexp = new Expression(mScanner->mLocation, EX_PREFIX); + thisexp->mToken = TK_MUL; + thisexp->mDecType = pthis->mBase->ToMutableType(); + thisexp->mLeft = pthisexp; + + cdec->mValue = new Expression(mScanner->mLocation, EX_RETURN); + cdec->mValue->mLeft = thisexp; + cdec->mValue->mDecType = cdec->mBase; + + // Now add all the copying + + Expression* thatexp = new Expression(pthis->mLocation, EX_VARIABLE); + thatexp->mDecType = adec->mBase; + thatexp->mDecValue = cdec->mBase->mParams->mNext; + + cdec->mScope = new DeclarationScope(nullptr, SLEVEL_CLASS); + + Declaration* dec = pthis->mBase->mParams; + if (dec) + { + dec = dec->Last(); + while (dec) + { + if (dec->mType == DT_ELEMENT) + { + Expression* lexp = new Expression(pthis->mLocation, EX_QUALIFY); + lexp->mLeft = thisexp; + lexp->mDecValue = dec; + lexp->mDecType = dec->mBase; + + Expression* rexp = new Expression(pthis->mLocation, EX_QUALIFY); + rexp->mLeft = thatexp; + rexp->mDecValue = dec; + rexp->mDecType = dec->mBase; + + Expression* mexp; + + Declaration* bdec = dec->mBase; + while (bdec->mType == DT_TYPE_ARRAY) + bdec = bdec->mBase; + + if (bdec->mType == DT_TYPE_STRUCT && bdec->mCopyAssignment) + { + if (dec->mSize == bdec->mSize) + { + Expression* pexp = new Expression(pthis->mLocation, EX_PREFIX); + pexp->mLeft = lexp; + pexp->mToken = TK_BINARY_AND; + pexp->mDecType = new Declaration(pthis->mLocation, DT_TYPE_POINTER); + pexp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + pexp->mDecType->mBase = dec->mBase; + pexp->mDecType->mSize = 2; + + Declaration* mdec = bdec->mCopyAssignment; + + Expression* cexp = new Expression(pthis->mLocation, EX_CONSTANT); + cexp->mDecValue = mdec; + cexp->mDecType = cexp->mDecValue->mBase; + + mexp = new Expression(mScanner->mLocation, EX_CALL); + mexp->mLeft = cexp; + mexp->mRight = new Expression(mScanner->mLocation, EX_LIST); + mexp->mRight->mLeft = pexp; + mexp->mRight->mRight = rexp; + } + else + { + lexp->mDecType = new Declaration(pthis->mLocation, DT_TYPE_POINTER); + lexp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + lexp->mDecType->mBase = bdec; + lexp->mDecType->mSize = 2; + + rexp->mDecType = new Declaration(pthis->mLocation, DT_TYPE_POINTER); + rexp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + rexp->mDecType->mBase = bdec; + rexp->mDecType->mSize = 2; + + Expression* cexp = new Expression(pthis->mLocation, EX_CONSTANT); + cexp->mDecValue = bdec->mVectorCopyAssignment; + cexp->mDecType = cexp->mDecValue->mBase; + + Declaration* ncdec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER); + ncdec->mBase = TheUnsignedIntTypeDeclaration; + ncdec->mInteger = dec->mSize / bdec->mSize; + + mexp = new Expression(mScanner->mLocation, EX_CALL); + mexp->mLeft = cexp; + mexp->mRight = new Expression(mScanner->mLocation, EX_LIST); + mexp->mRight->mLeft = lexp; + mexp->mRight->mRight = new Expression(mScanner->mLocation, EX_LIST); + mexp->mRight->mRight->mLeft = rexp; + mexp->mRight->mRight->mRight = new Expression(mScanner->mLocation, EX_CONSTANT); + mexp->mRight->mRight->mRight->mDecType = ncdec->mBase; + mexp->mRight->mRight->mRight->mDecValue = ncdec; + } + } + else + { + mexp = new Expression(mScanner->mLocation, EX_ASSIGNMENT); + mexp->mToken = TK_ASSIGN; + mexp->mLeft = lexp; + mexp->mRight = rexp; + mexp->mDecType = lexp->mDecType; + } + + Expression* sexp = new Expression(mScanner->mLocation, EX_SEQUENCE); + sexp->mLeft = mexp; + sexp->mRight = cdec->mValue; + cdec->mValue = sexp; + } + + dec = dec->mPrev; + } + } + + cdec->mFlags |= DTF_DEFINED; + } + } + + if (pthis->mBase->mDefaultConstructor && !pthis->mBase->mVectorConstructor) + { + Declaration* ctdec = new Declaration(mScanner->mLocation, DT_TYPE_FUNCTION); + ctdec->mSize = 0; + Declaration* pdec = nullptr; + ctdec->mBase = TheVoidTypeDeclaration; + ctdec->mFlags |= DTF_DEFINED; + + Declaration* vthis = pthis->Clone(); + vthis->mFlags &= ~DTF_CONST; + + Declaration* adec = new Declaration(mScanner->mLocation, DT_ARGUMENT); + adec->mVarIndex = 0; + adec->mOffset = 0; + adec->mBase = pthis; + adec->mSize = adec->mBase->mSize; + adec->mIdent = adec->mQualIdent = Ident::Unique("end"); + + ctdec->mParams = adec; + + PrependThisArgument(ctdec, vthis); + + Declaration* cdec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION); + cdec->mBase = ctdec; + + cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE); + + cdec->mSection = mCodeSection; + + if (mCompilerOptions & COPT_NATIVE) + cdec->mFlags |= DTF_NATIVE; + + pthis->mBase->mVectorConstructor = cdec; + + cdec->mIdent = ctorident; + cdec->mQualIdent = pthis->mBase->mScope->Mangle(cdec->mIdent); + + cdec->mCompilerOptions = mCompilerOptions; + cdec->mBase->mCompilerOptions = mCompilerOptions; + + cdec->mVarIndex = -1; + + cdec->mFlags |= DTF_DEFINED; + + Expression* pexp = new Expression(mScanner->mLocation, EX_VARIABLE); + pexp->mDecType = vthis; + pexp->mDecValue = ctdec->mParams; + + Expression* aexp = new Expression(mScanner->mLocation, EX_VARIABLE); + aexp->mDecType = pthis; + aexp->mDecValue = adec; + + Expression* iexp = new Expression(mScanner->mLocation, EX_POSTINCDEC); + iexp->mToken = TK_INC; + iexp->mLeft = pexp; + iexp->mDecType = pexp->mDecType; + + Expression* fexp = new Expression(mScanner->mLocation, EX_CONSTANT); + fexp->mDecValue = pthis->mBase->mDefaultConstructor; + fexp->mDecType = fexp->mDecValue->mBase; + + Expression*cexp = new Expression(mScanner->mLocation, EX_CALL); + cexp->mLeft = fexp; + cexp->mRight = iexp; + + Expression * wexp = new Expression(mScanner->mLocation, EX_WHILE); + wexp->mLeft = new Expression(mScanner->mLocation, EX_RELATIONAL); + wexp->mLeft->mToken = TK_NOT_EQUAL; + wexp->mLeft->mLeft = pexp; + wexp->mLeft->mRight = aexp; + wexp->mLeft->mDecType = TheBoolTypeDeclaration; + wexp->mRight = cexp; + + cdec->mValue = wexp; + } + + if (pthis->mBase->mDestructor && !pthis->mBase->mVectorDestructor) + { + Declaration* ctdec = new Declaration(mScanner->mLocation, DT_TYPE_FUNCTION); + ctdec->mSize = 0; + Declaration* pdec = nullptr; + ctdec->mBase = TheVoidTypeDeclaration; + ctdec->mFlags |= DTF_DEFINED; + + Declaration* vthis = pthis->Clone(); + vthis->mFlags &= ~DTF_CONST; + + Declaration* adec = new Declaration(mScanner->mLocation, DT_ARGUMENT); + adec->mVarIndex = 0; + adec->mOffset = 0; + adec->mBase = pthis; + adec->mSize = adec->mBase->mSize; + adec->mIdent = adec->mQualIdent = Ident::Unique("end"); + + ctdec->mParams = adec; + + PrependThisArgument(ctdec, vthis); + + Declaration* cdec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION); + cdec->mBase = ctdec; + + cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE); + + cdec->mSection = mCodeSection; + + if (mCompilerOptions & COPT_NATIVE) + cdec->mFlags |= DTF_NATIVE; + + pthis->mBase->mVectorDestructor = cdec; + + cdec->mIdent = dtorident; + cdec->mQualIdent = pthis->mBase->mScope->Mangle(cdec->mIdent); + + cdec->mCompilerOptions = mCompilerOptions; + cdec->mBase->mCompilerOptions = mCompilerOptions; + + cdec->mVarIndex = -1; + + cdec->mFlags |= DTF_DEFINED; + + Expression* pexp = new Expression(mScanner->mLocation, EX_VARIABLE); + pexp->mDecType = vthis; + pexp->mDecValue = ctdec->mParams; + + Expression* aexp = new Expression(mScanner->mLocation, EX_VARIABLE); + aexp->mDecType = pthis; + aexp->mDecValue = adec; + + Expression* iexp = new Expression(mScanner->mLocation, EX_POSTINCDEC); + iexp->mToken = TK_INC; + iexp->mLeft = pexp; + iexp->mDecType = pexp->mDecType; + + Expression* fexp = new Expression(mScanner->mLocation, EX_CONSTANT); + fexp->mDecValue = pthis->mBase->mDestructor; + fexp->mDecType = fexp->mDecValue->mBase; + + Expression* cexp = new Expression(mScanner->mLocation, EX_CALL); + cexp->mLeft = fexp; + cexp->mRight = iexp; + + Expression* wexp = new Expression(mScanner->mLocation, EX_WHILE); + wexp->mLeft = new Expression(mScanner->mLocation, EX_RELATIONAL); + wexp->mLeft->mToken = TK_NOT_EQUAL; + wexp->mLeft->mLeft = pexp; + wexp->mLeft->mRight = aexp; + wexp->mLeft->mDecType = TheBoolTypeDeclaration; + + wexp->mRight = cexp; + + cdec->mValue = wexp; + } + + if (pthis->mBase->mCopyConstructor && !pthis->mBase->mVectorCopyConstructor) + { + Declaration* ctdec = new Declaration(mScanner->mLocation, DT_TYPE_FUNCTION); + ctdec->mSize = 0; + Declaration* pdec = nullptr; + ctdec->mBase = TheVoidTypeDeclaration; + ctdec->mFlags |= DTF_DEFINED; + + Declaration* sdec = new Declaration(mScanner->mLocation, DT_ARGUMENT); + sdec->mVarIndex = 0; + sdec->mOffset = 0; + sdec->mBase = pthis->Clone(); + sdec->mBase->mFlags &= ~DTF_CONST; + sdec->mSize = sdec->mBase->mSize; + sdec->mIdent = sdec->mQualIdent = Ident::Unique("_"); + + Declaration* adec = new Declaration(mScanner->mLocation, DT_ARGUMENT); + adec->mVarIndex = 2; + adec->mOffset = 0; + adec->mBase = TheUnsignedIntTypeDeclaration; + adec->mSize = adec->mBase->mSize; + adec->mIdent = adec->mQualIdent = Ident::Unique("n"); + + sdec->mNext = adec; + ctdec->mParams = sdec; + + Declaration* vthis = pthis->Clone(); + vthis->mFlags &= ~DTF_CONST; + PrependThisArgument(ctdec, vthis); + + Declaration* cdec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION); + cdec->mBase = ctdec; + + cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE); + + cdec->mSection = mCodeSection; + + if (mCompilerOptions & COPT_NATIVE) + cdec->mFlags |= DTF_NATIVE; + + pthis->mBase->mVectorCopyConstructor = cdec; + + cdec->mIdent = ctorident; + cdec->mQualIdent = pthis->mBase->mScope->Mangle(cdec->mIdent); + + cdec->mCompilerOptions = mCompilerOptions; + cdec->mBase->mCompilerOptions = mCompilerOptions; + + cdec->mVarIndex = -1; + + cdec->mFlags |= DTF_DEFINED; + + Expression* pexp = new Expression(mScanner->mLocation, EX_VARIABLE); + pexp->mDecType = vthis; + pexp->mDecValue = ctdec->mParams; + + Expression* psexp = new Expression(mScanner->mLocation, EX_VARIABLE); + psexp->mDecType = vthis; + psexp->mDecValue = sdec; + + Expression* aexp = new Expression(mScanner->mLocation, EX_VARIABLE); + aexp->mDecType = TheUnsignedIntTypeDeclaration; + aexp->mDecValue = adec; + + Expression* iexp = new Expression(mScanner->mLocation, EX_POSTINCDEC); + iexp->mToken = TK_INC; + iexp->mLeft = pexp; + iexp->mDecType = pexp->mDecType; + + Expression* isexp = new Expression(mScanner->mLocation, EX_POSTINCDEC); + isexp->mToken = TK_INC; + isexp->mLeft = psexp; + isexp->mDecType = psexp->mDecType; + + Expression* disexp = new Expression(mScanner->mLocation, EX_PREFIX); + disexp->mToken = TK_MUL; + disexp->mLeft = isexp; + disexp->mDecType = vthis->mBase; + + Expression* dexp = new Expression(mScanner->mLocation, EX_POSTINCDEC); + dexp->mToken = TK_DEC; + dexp->mLeft = aexp; + dexp->mDecType = aexp->mDecType; + + Expression* fexp = new Expression(mScanner->mLocation, EX_CONSTANT); + fexp->mDecValue = pthis->mBase->mCopyConstructor; + fexp->mDecType = fexp->mDecValue->mBase; + + Expression* cexp = new Expression(mScanner->mLocation, EX_CALL); + cexp->mLeft = fexp; + cexp->mRight = new Expression(mScanner->mLocation, EX_LIST); + cexp->mRight->mLeft = iexp; + cexp->mRight->mRight = disexp; + + Expression* wexp = new Expression(mScanner->mLocation, EX_WHILE); + wexp->mLeft = aexp; + wexp->mRight = new Expression(mScanner->mLocation, EX_SEQUENCE); + wexp->mRight->mLeft = cexp; + wexp->mRight->mRight = dexp; + + cdec->mValue = wexp; + } + + if (pthis->mBase->mCopyAssignment && !pthis->mBase->mVectorCopyAssignment) + { + Declaration* ctdec = new Declaration(mScanner->mLocation, DT_TYPE_FUNCTION); + ctdec->mSize = 0; + Declaration* pdec = nullptr; + ctdec->mBase = TheVoidTypeDeclaration; + ctdec->mFlags |= DTF_DEFINED; + + Declaration* sdec = new Declaration(mScanner->mLocation, DT_ARGUMENT); + sdec->mVarIndex = 0; + sdec->mOffset = 0; + sdec->mBase = pthis->Clone(); + sdec->mBase->mFlags &= ~DTF_CONST; + sdec->mSize = sdec->mBase->mSize; + sdec->mIdent = sdec->mQualIdent = Ident::Unique("_"); + + Declaration* adec = new Declaration(mScanner->mLocation, DT_ARGUMENT); + adec->mVarIndex = 2; + adec->mOffset = 0; + adec->mBase = TheUnsignedIntTypeDeclaration; + adec->mSize = adec->mBase->mSize; + adec->mIdent = adec->mQualIdent = Ident::Unique("n"); + + sdec->mNext = adec; + ctdec->mParams = sdec; + + Declaration* vthis = pthis->Clone(); + vthis->mFlags &= ~DTF_CONST; + PrependThisArgument(ctdec, vthis); + + Declaration* cdec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION); + cdec->mBase = ctdec; + + cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE); + + cdec->mSection = mCodeSection; + + if (mCompilerOptions & COPT_NATIVE) + cdec->mFlags |= DTF_NATIVE; + + pthis->mBase->mVectorCopyAssignment = cdec; + + cdec->mIdent = ctorident; + cdec->mQualIdent = pthis->mBase->mScope->Mangle(cdec->mIdent); + + cdec->mCompilerOptions = mCompilerOptions; + cdec->mBase->mCompilerOptions = mCompilerOptions; + + cdec->mVarIndex = -1; + + cdec->mFlags |= DTF_DEFINED; + + Expression* pexp = new Expression(mScanner->mLocation, EX_VARIABLE); + pexp->mDecType = vthis; + pexp->mDecValue = ctdec->mParams; + + Expression* psexp = new Expression(mScanner->mLocation, EX_VARIABLE); + psexp->mDecType = vthis; + psexp->mDecValue = sdec; + + Expression* aexp = new Expression(mScanner->mLocation, EX_VARIABLE); + aexp->mDecType = TheUnsignedIntTypeDeclaration; + aexp->mDecValue = adec; + + Expression* iexp = new Expression(mScanner->mLocation, EX_POSTINCDEC); + iexp->mToken = TK_INC; + iexp->mLeft = pexp; + iexp->mDecType = pexp->mDecType; + + Expression* isexp = new Expression(mScanner->mLocation, EX_POSTINCDEC); + isexp->mToken = TK_INC; + isexp->mLeft = psexp; + isexp->mDecType = psexp->mDecType; + + Expression* disexp = new Expression(mScanner->mLocation, EX_PREFIX); + disexp->mToken = TK_MUL; + disexp->mLeft = isexp; + disexp->mDecType = vthis->mBase; + + Expression* dexp = new Expression(mScanner->mLocation, EX_POSTINCDEC); + dexp->mToken = TK_DEC; + dexp->mLeft = aexp; + dexp->mDecValue = aexp->mDecType; + + Expression* fexp = new Expression(mScanner->mLocation, EX_CONSTANT); + fexp->mDecValue = pthis->mBase->mCopyAssignment; + fexp->mDecType = fexp->mDecValue->mBase; + + Expression* cexp = new Expression(mScanner->mLocation, EX_CALL); + cexp->mLeft = fexp; + cexp->mRight = new Expression(mScanner->mLocation, EX_LIST); + cexp->mRight->mLeft = iexp; + cexp->mRight->mRight = disexp; + + Expression* wexp = new Expression(mScanner->mLocation, EX_WHILE); + wexp->mLeft = aexp; + wexp->mRight = new Expression(mScanner->mLocation, EX_SEQUENCE); + wexp->mRight->mLeft = cexp; + wexp->mRight->mRight = dexp; + + cdec->mValue = wexp; + } +} + +void Parser::AppendMemberDestructor(Declaration* pthis) +{ + if (pthis->mBase->mDestructor) + { + if (pthis->mBase->mDestructor->mFlags & DTF_DEFINED) + { + if (pthis->mBase->mDestructor->mFlags & DTF_COMPLETED) + return; + pthis->mBase->mDestructor->mFlags |= DTF_COMPLETED; + + Expression* pthisexp = new Expression(pthis->mLocation, EX_VARIABLE); + pthisexp->mDecType = pthis; + pthisexp->mDecValue = pthis->mBase->mDestructor->mBase->mParams; + + Expression* thisexp = new Expression(mScanner->mLocation, EX_PREFIX); + thisexp->mToken = TK_MUL; + thisexp->mDecType = pthis->mBase; + thisexp->mLeft = pthisexp; + + Declaration * dec = pthis->mBase->mParams; + if (dec) + { + dec = dec->Last(); + while (dec) + { + if (dec->mType == DT_ELEMENT) + { + Declaration* bdec = dec->mBase; + while (bdec->mType == DT_TYPE_ARRAY) + bdec = bdec->mBase; + + if (bdec->mType == DT_TYPE_STRUCT && bdec->mDestructor) + { + Expression* qexp = new Expression(pthis->mLocation, EX_QUALIFY); + qexp->mLeft = thisexp; + qexp->mDecValue = dec; + + Expression* dexp; + + if (dec->mSize == bdec->mSize) + { + qexp->mDecType = bdec; + + Expression* pexp = new Expression(pthis->mLocation, EX_PREFIX); + pexp->mLeft = qexp; + pexp->mToken = TK_BINARY_AND; + pexp->mDecType = new Declaration(pthis->mLocation, DT_TYPE_POINTER); + pexp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + pexp->mDecType->mBase = bdec; + pexp->mDecType->mSize = 2; + + Expression* cexp = new Expression(pthis->mLocation, EX_CONSTANT); + cexp->mDecValue = bdec->mDestructor; + cexp->mDecType = cexp->mDecValue->mBase; + + dexp = new Expression(mScanner->mLocation, EX_CALL); + dexp->mLeft = cexp; + dexp->mRight = pexp; + } + else + { + qexp->mDecType = dec->mBase->mBase; + + while (qexp->mDecType->mType == DT_TYPE_ARRAY) + { + Expression* iexp = new Expression(pthis->mLocation, EX_PREFIX); + iexp->mToken = TK_MUL; + iexp->mLeft = qexp; + iexp->mDecType = qexp->mDecType->mBase; + qexp = iexp; + } + + qexp->mDecType = new Declaration(pthis->mLocation, DT_TYPE_POINTER); + qexp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + qexp->mDecType->mBase = bdec; + qexp->mDecType->mSize = 2; + + Expression* cexp = new Expression(pthis->mLocation, EX_CONSTANT); + cexp->mDecValue = bdec->mVectorDestructor; + cexp->mDecType = cexp->mDecValue->mBase; + + Declaration* ncdec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER); + ncdec->mBase = TheUnsignedIntTypeDeclaration; + ncdec->mInteger = dec->mSize / bdec->mSize; + + dexp = new Expression(mScanner->mLocation, EX_CALL); + dexp->mLeft = cexp; + dexp->mRight = new Expression(mScanner->mLocation, EX_LIST); + dexp->mRight->mLeft = qexp; + dexp->mRight->mRight = new Expression(mScanner->mLocation, EX_BINARY); + dexp->mRight->mRight->mToken = TK_ADD; + dexp->mRight->mRight->mLeft = qexp; + dexp->mRight->mRight->mDecType = qexp->mDecType; + dexp->mRight->mRight->mRight = new Expression(mScanner->mLocation, EX_CONSTANT); + dexp->mRight->mRight->mRight->mDecType = ncdec->mBase; + dexp->mRight->mRight->mRight->mDecValue = ncdec; + } + + Expression* sexp = new Expression(mScanner->mLocation, EX_SEQUENCE); + + sexp->mLeft = pthis->mBase->mDestructor->mValue; + sexp->mRight = dexp; + + pthis->mBase->mDestructor->mValue = sexp; + } + } + + dec = dec->mPrev; + } + } + + Declaration* bcdec = pthis->mBase->mBase; + while (bcdec) + { + if (bcdec->mBase->mDestructor) + { + Declaration* mdec = bcdec->mBase->mDestructor; + + Expression* cexp = new Expression(pthis->mLocation, EX_CONSTANT); + cexp->mDecValue = mdec; + cexp->mDecType = cexp->mDecValue->mBase; + + Expression* dexp = new Expression(mScanner->mLocation, EX_CALL); + dexp->mLeft = cexp; + dexp->mRight = pthisexp; + + Expression* sexp = new Expression(mScanner->mLocation, EX_SEQUENCE); + + sexp->mLeft = pthis->mBase->mDestructor->mValue; + sexp->mRight = dexp; + pthis->mBase->mDestructor->mValue = sexp; + } + + bcdec = bcdec->mNext; + } + } + } +} + void Parser::PrependThisArgument(Declaration* fdec, Declaration* pthis) { Declaration* adec = new Declaration(fdec->mLocation, DT_ARGUMENT); - adec->mVarIndex = 0; + if (fdec->mBase->mType == DT_TYPE_STRUCT) + adec->mVarIndex = 2; + else + adec->mVarIndex = 0; + adec->mOffset = 0; adec->mBase = pthis; adec->mSize = adec->mBase->mSize; adec->mNext = fdec->mParams; adec->mIdent = adec->mQualIdent = Ident::Unique("this"); - Declaration* p = adec->mBase->mParams; + Declaration* p = fdec->mParams; while (p) { p->mVarIndex += 2; @@ -1160,13 +3197,444 @@ void Parser::PrependThisArgument(Declaration* fdec, Declaration* pthis) } fdec->mParams = adec; - + fdec->mClass = pthis; fdec->mFlags |= DTF_FUNC_THIS; } -Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool expression, Declaration* pthis) +static Expression* ConcatExpression(Expression* e1, Expression* e2) { - bool definingType = false; + if (e1) + { + if (e2) + { + Expression* seq = new Expression(e1->mLocation, EX_SEQUENCE); + seq->mLeft = e1; + seq->mRight = e2; + return seq; + } + return e1; + } + else + return e2; +} + +Declaration* Parser::AllocTempVar(Declaration* type) +{ + Declaration* ptemp = nullptr, * vtemp = mTempVars; + while (vtemp && !vtemp->mBase->IsSame(type)) + { + ptemp = vtemp; + vtemp = vtemp->mNext; + } + + if (vtemp) + { + if (ptemp) + ptemp->mNext = vtemp->mNext; + else + mTempVars = vtemp->mNext; + vtemp->mNext = nullptr; + vtemp->mValue = nullptr; + } + else + { + vtemp = new Declaration(mScanner->mLocation, DT_VARIABLE); + vtemp->mBase = type; + vtemp->mSize = type->mSize; + vtemp->mVarIndex = mLocalIndex++; + vtemp->mFlags |= DTF_DEFINED; + } + + return vtemp; +} + +void Parser::FreeTempVar(Declaration* var) +{ + var->mNext = mTempVars; + mTempVars = var; +} + +void Parser::FreeTempVarExp(Expression* exp) +{ + if (exp->mType == EX_SEQUENCE) + { + FreeTempVarExp(exp->mLeft); + FreeTempVarExp(exp->mRight); + } + else if (exp->mType == EX_CALL && exp->mLeft->mType == EX_CONSTANT && + exp->mRight->mType == EX_PREFIX && exp->mRight->mToken == TK_BINARY_AND && exp->mRight->mLeft->mType == EX_VARIABLE) + { + if (exp->mLeft->mDecValue->mIdent->mString[0] == '~' && exp->mRight->mLeft->mDecValue->mIdent == nullptr) + FreeTempVar(exp->mRight->mLeft->mDecValue); + } +} + +Expression* Parser::CleanupExpression(Expression* exp) +{ + if (exp) + { + Expression* xexp = AddFunctionCallRefReturned(exp); + if (xexp) + { + Expression* cexp = new Expression(exp->mLocation, EX_CLEANUP); + cexp->mLeft = exp; + cexp->mRight = xexp; + cexp->mDecType = exp->mDecType; + + FreeTempVarExp(xexp); + return cexp; + } + } + return exp; +} + +Expression* Parser::AddFunctionCallRefReturned(Expression* exp) +{ + Expression* lexp = nullptr, * rexp = nullptr; + + if (exp->mType == EX_PREFIX && exp->mToken == TK_BINARY_AND && exp->mLeft->mType == EX_CALL && exp->mLeft->mDecType->mType != DT_TYPE_REFERENCE && exp->mLeft->mDecType->mType != DT_TYPE_RVALUEREF) + { + lexp = AddFunctionCallRefReturned(exp->mLeft); + + // Returning a value object for pass by address + // add a temporary variable + + //int nindex = mLocalIndex++; + + Declaration* rtdec = exp->mLeft->mDecType; + + Declaration* vdec = AllocTempVar(rtdec); +#if 0 + Declaration* vdec = new Declaration(exp->mLocation, DT_VARIABLE); + + vdec->mVarIndex = nindex; + vdec->mBase = rtdec; + vdec->mSize = rtdec->mSize; +#endif + Expression* vexp = new Expression(exp->mLocation, EX_VARIABLE); + vexp->mDecType = rtdec; + vexp->mDecValue = vdec; + + Expression* pex = new Expression(exp->mLocation, EX_INITIALIZATION); + pex->mToken = TK_ASSIGN; + pex->mLeft = vexp; + pex->mRight = exp->mLeft; + pex->mDecValue = nullptr; + pex->mDecType = vdec->mBase; + + exp->mLeft = pex; + + if (rtdec->mDestructor) + { + Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX); + texp->mToken = TK_BINARY_AND; + texp->mLeft = vexp; + texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER); + texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + texp->mDecType->mBase = vdec->mBase; + texp->mDecType->mSize = 2; + + Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); + cexp->mDecValue = rtdec->mDestructor; + cexp->mDecType = cexp->mDecValue->mBase; + + Expression* dexp = new Expression(mScanner->mLocation, EX_CALL); + dexp->mLeft = cexp; + dexp->mRight = texp; + + rexp = ConcatExpression(rexp, dexp); + } + } + else if (exp->mType == EX_QUALIFY && exp->mLeft->mType == EX_CALL && exp->mLeft->mDecType->mType != DT_TYPE_REFERENCE && exp->mLeft->mDecType->mType != DT_TYPE_RVALUEREF) + { + lexp = AddFunctionCallRefReturned(exp->mLeft); + + // Returning a value object for pass by address + // add a temporary variable + +// int nindex = mLocalIndex++; + + Declaration* rtdec = exp->mLeft->mDecType; + + Declaration* vdec = AllocTempVar(rtdec); +#if 0 + Declaration* vdec = new Declaration(exp->mLocation, DT_VARIABLE); + + vdec->mVarIndex = nindex; + vdec->mBase = rtdec; + vdec->mSize = rtdec->mSize; +#endif + Expression* vexp = new Expression(exp->mLocation, EX_VARIABLE); + vexp->mDecType = rtdec; + vexp->mDecValue = vdec; + + Expression* pex = new Expression(exp->mLocation, EX_INITIALIZATION); + pex->mToken = TK_ASSIGN; + pex->mLeft = vexp; + pex->mRight = exp->mLeft; + pex->mDecValue = nullptr; + pex->mDecType = vdec->mBase; + + exp->mLeft = pex; + + if (rtdec->mDestructor) + { + Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX); + texp->mToken = TK_BINARY_AND; + texp->mLeft = vexp; + texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER); + texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + texp->mDecType->mBase = vdec->mBase; + texp->mDecType->mSize = 2; + + Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); + cexp->mDecValue = rtdec->mDestructor; + cexp->mDecType = cexp->mDecValue->mBase; + + Expression* dexp = new Expression(mScanner->mLocation, EX_CALL); + dexp->mLeft = cexp; + dexp->mRight = texp; + + rexp = ConcatExpression(rexp, dexp); + } + } + else if (exp->mType == EX_CALL) + { + lexp = AddFunctionCallRefReturned(exp->mLeft); + if (exp->mRight) + { + Declaration* pdec = exp->mLeft->mDecType->mParams; + Expression* rex = exp->mRight; + + while (pdec && rex) + { + Expression* pex = rex->mType == EX_LIST ? rex->mLeft : rex; + if (rex->mType == EX_LIST) + rex = rex->mRight; + else + rex = nullptr; + + rexp = ConcatExpression(rexp, AddFunctionCallRefReturned(pex)); + + if ((pdec->mBase->mType == DT_TYPE_REFERENCE || pdec->mBase->mType == DT_TYPE_RVALUEREF) && + (pex->mDecType->mType != DT_TYPE_REFERENCE && pex->mDecType->mType != DT_TYPE_RVALUEREF) && pex->mType == EX_CALL) + { + // Returning a value object for pass as reference + // add a temporary variable + + Declaration* vdec = AllocTempVar(pex->mDecType); +#if 0 + int nindex = mLocalIndex++; + + Declaration* vdec = new Declaration(exp->mLocation, DT_VARIABLE); + + vdec->mVarIndex = nindex; + vdec->mBase = pex->mDecType; + vdec->mSize = pex->mDecType->mSize; +#endif + Expression* vexp = new Expression(pex->mLocation, EX_VARIABLE); + vexp->mDecType = pex->mDecType; + vexp->mDecValue = vdec; + + Expression* cexp = new Expression(pex->mLocation, pex->mType); + cexp->mDecType = pex->mDecType; + cexp->mDecValue = pex->mDecValue; + cexp->mLeft = pex->mLeft; + cexp->mRight = pex->mRight; + cexp->mToken = pex->mToken; + + pex->mType = EX_INITIALIZATION; + pex->mToken = TK_ASSIGN; + pex->mLeft = vexp; + pex->mRight = cexp; + pex->mDecValue = nullptr; + pex->mDecType = vdec->mBase; + + if (vdec->mBase->mDestructor) + { + Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX); + texp->mToken = TK_BINARY_AND; + texp->mLeft = vexp; + texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER); + texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + texp->mDecType->mBase = vdec->mBase; + texp->mDecType->mSize = 2; + + Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); + cexp->mDecValue = vdec->mBase->mDestructor; + cexp->mDecType = cexp->mDecValue->mBase; + + Expression * dexp = new Expression(mScanner->mLocation, EX_CALL); + dexp->mLeft = cexp; + dexp->mRight = texp; + + rexp = ConcatExpression(rexp, dexp); + } + } + else if ((pdec->mBase->mType == DT_TYPE_REFERENCE || pdec->mBase->mType == DT_TYPE_RVALUEREF) && pex->mType == EX_CONSTRUCT && pex->mRight->mType == EX_VARIABLE) + { + // A constructed object is passed by reference + + if (pex->mLeft->mRight) + { + rexp = ConcatExpression(rexp, pex->mLeft->mRight); + pex->mLeft->mRight = nullptr; + } + } + else if ((pdec->mBase->mType == DT_TYPE_REFERENCE || pdec->mBase->mType == DT_TYPE_RVALUEREF) && pex->mType == EX_CONSTANT) + { + // A simple constant is passed by const ref + if (pex->mDecValue->mType == DT_CONST_INTEGER || pex->mDecValue->mType == DT_CONST_FLOAT || pex->mDecValue->mType == DT_CONST_POINTER || pex->mDecValue->mType == DT_CONST_ADDRESS) + { + if (pdec->mType == DT_TYPE_REFERENCE && !(pdec->mBase->mFlags & DTF_CONST)) + mErrors->Error(pex->mLocation, EERR_INCOMPATIBLE_TYPES, "Can't pass constant as non constante reference"); + + Declaration* vdec = AllocTempVar(pdec->mBase->mBase); + + Expression* vexp = new Expression(pex->mLocation, EX_VARIABLE); + vexp->mDecType = pdec->mBase->mBase; + vexp->mDecValue = vdec; + + Expression* cexp = new Expression(pex->mLocation, pex->mType); + cexp->mDecType = pex->mDecType; + cexp->mDecValue = pex->mDecValue; + cexp->mLeft = pex->mLeft; + cexp->mRight = pex->mRight; + cexp->mToken = pex->mToken; + + pex->mType = EX_INITIALIZATION; + pex->mToken = TK_ASSIGN; + pex->mLeft = vexp; + pex->mRight = cexp; + pex->mDecValue = nullptr; + pex->mDecType = vdec->mBase; + } + } + else if ((pdec->mBase->mType == DT_TYPE_REFERENCE && !pex->IsConstRef()) || (pdec->mBase->mType == DT_TYPE_RVALUEREF && !pex->IsLValue())) + { + Declaration* vdec = AllocTempVar(pex->mDecType); + + Expression* vexp = new Expression(pex->mLocation, EX_VARIABLE); + vexp->mDecType = pex->mDecType; + vexp->mDecValue = vdec; + + Expression* cexp = new Expression(pex->mLocation, pex->mType); + cexp->mDecType = pex->mDecType; + cexp->mDecValue = pex->mDecValue; + cexp->mLeft = pex->mLeft; + cexp->mRight = pex->mRight; + cexp->mToken = pex->mToken; + + pex->mType = EX_INITIALIZATION; + pex->mToken = TK_ASSIGN; + pex->mLeft = vexp; + pex->mRight = cexp; + pex->mDecValue = nullptr; + pex->mDecType = vdec->mBase; + } + + pdec = pdec->mNext; + } + } + } + else + { + if (exp->mLeft) + lexp = AddFunctionCallRefReturned(exp->mLeft); + if (exp->mRight) + rexp = AddFunctionCallRefReturned(exp->mRight); + } + + return ConcatExpression(lexp, rexp); +} + +void Parser::ParseVariableInit(Declaration* ndec) +{ + Expression* pexp = nullptr; + + mScanner->NextToken(); + if (mScanner->mToken != TK_CLOSE_PARENTHESIS) + { + pexp = ParseListExpression(false); + ConsumeToken(TK_CLOSE_PARENTHESIS); + } + else + mScanner->NextToken(); + + Declaration* fcons = ndec->mBase->mScope ? ndec->mBase->mScope->Lookup(ndec->mBase->mIdent->PreMangle("+"), SLEVEL_CLASS) : nullptr; + + if (fcons) + { + Declaration* mtype = ndec->mBase->ToMutableType(); + + Expression* vexp = new Expression(mScanner->mLocation, EX_VARIABLE); + vexp->mDecType = mtype; + vexp->mDecValue = ndec; + + Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); + cexp->mDecValue = fcons; + cexp->mDecType = cexp->mDecValue->mBase; + + Expression* fexp = new Expression(mScanner->mLocation, EX_CALL); + fexp->mLeft = cexp; + fexp->mRight = pexp; + + Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX); + texp->mToken = TK_BINARY_AND; + texp->mLeft = vexp; + texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER); + texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + texp->mDecType->mBase = mtype; + texp->mDecType->mSize = 2; + + if (fexp->mRight) + { + Expression* lexp = new Expression(mScanner->mLocation, EX_LIST); + lexp->mLeft = texp; + lexp->mRight = fexp->mRight; + fexp->mRight = lexp; + } + else + fexp->mRight = texp; + + fexp = ResolveOverloadCall(fexp); + + Expression* dexp = nullptr; + if (ndec->mBase->mDestructor) + { + Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); + cexp->mDecValue = ndec->mBase->mDestructor; + cexp->mDecType = cexp->mDecValue->mBase; + + dexp = new Expression(mScanner->mLocation, EX_CALL); + dexp->mLeft = cexp; + dexp->mRight = texp; + } + + Expression* nexp = new Expression(mScanner->mLocation, EX_CONSTRUCT); + + nexp->mLeft = new Expression(mScanner->mLocation, EX_LIST); + nexp->mLeft->mLeft = fexp; + nexp->mLeft->mRight = dexp; + + nexp->mRight = vexp; + nexp->mDecType = vexp->mDecType; + + ndec->mValue = nexp; + } + else if (pexp && pexp->mType != EX_LIST && ndec->mBase->CanAssign(pexp->mDecType)) + { + ndec->mValue = pexp; + } + else if (pexp) + mErrors->Error(pexp->mLocation, EERR_INCOMPATIBLE_TYPES, "Can not initialize variable with expression", ndec->mIdent); + else + mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_TYPES, "Can not initialize variable with expression", ndec->mIdent); +} + +Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool expression, Declaration* pthis, Declaration* ptempl) +{ + bool definingType = false, destructor = false; uint64 storageFlags = 0, typeFlags = 0; Declaration* bdec; @@ -1202,13 +3670,20 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex } else { - Declaration* dec = ParseQualIdent(); - if (dec) - { - Declaration* pdec = mScope->Insert(dec->mIdent, dec); - if (pdec && pdec != dec) - mErrors->Error(dec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate declaration", dec->mIdent); - } + Declaration* dec; + + do { + dec = ParseQualIdent(); + if (dec) + { + Declaration* pdec = mScope->Insert(dec->mIdent, dec); + if (pdec && pdec != dec) + mErrors->Error(dec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate declaration", dec->mIdent); + } + else + break; + + } while (ConsumeTokenIf(TK_COMMA)); return dec; } @@ -1217,11 +3692,21 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex { for (;;) { - if (mScanner->mToken == TK_STATIC) + if (mScanner->mToken == TK_VIRTUAL) + { + storageFlags |= DTF_VIRTUAL; + mScanner->NextToken(); + } + else if (mScanner->mToken == TK_STATIC) { storageFlags |= DTF_STATIC; mScanner->NextToken(); } + else if (mScanner->mToken == TK_CONSTEXPR) + { + storageFlags |= DTF_CONSTEXPR | DTF_REQUEST_INLINE; + mScanner->NextToken(); + } else if (mScanner->mToken == TK_EXTERN) { storageFlags |= DTF_EXTERN; @@ -1282,7 +3767,116 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex } } - bdec = ParseBaseTypeDeclaration(typeFlags); + if ((mCompilerOptions & COPT_CPLUSPLUS) && pthis && mScanner->mToken == TK_BINARY_NOT) + { + // Destructor declaration + mScanner->NextToken(); + if (mScanner->mToken == TK_IDENT) + { + const Ident* ident = mScanner->mTokenIdent; + if (mTemplateScope) + { + Declaration* dec = mTemplateScope->Lookup(ident); + if (dec) + ident = dec->mIdent; + } + + if (ident != pthis->mBase->mIdent) + mErrors->Error(mScanner->mLocation, EERR_INVALID_IDENTIFIER, "Wrong class name for destructor", pthis->mBase->mIdent); + mScanner->NextToken(); + } + else + mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Identifier expected"); + + Declaration* ctdec = ParseFunctionDeclaration(TheVoidTypeDeclaration); + + if (ctdec->mParams) + mErrors->Error(ctdec->mLocation, EERR_WRONG_PARAMETER, "Destructor can't have parameter"); + + PrependThisArgument(ctdec, pthis); + + Declaration* cdec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION); + cdec->mBase = ctdec; + + cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE); + ctdec->mFlags |= storageFlags & (DTF_REQUEST_INLINE | DTF_CONSTEXPR | DTF_VIRTUAL); + + cdec->mSection = mCodeSection; + cdec->mBase->mFlags |= typeFlags; + + if (mCompilerOptions & COPT_NATIVE) + cdec->mFlags |= DTF_NATIVE; + + cdec->mIdent = pthis->mBase->mIdent->PreMangle("~"); + cdec->mQualIdent = pthis->mBase->mScope->Mangle(cdec->mIdent); + + if (mScanner->mToken == TK_OPEN_BRACE) + { + cdec->mCompilerOptions = mCompilerOptions; + cdec->mBase->mCompilerOptions = mCompilerOptions; + + cdec->mVarIndex = -1; + + cdec->mValue = ParseFunction(cdec->mBase); + + cdec->mFlags |= DTF_DEFINED | DTF_REQUEST_INLINE; + cdec->mNumVars = mLocalIndex; + } + + return cdec; + } + if ((mCompilerOptions & COPT_CPLUSPLUS) && pthis && mScanner->mToken == TK_OPERATOR) + { + mScanner->NextToken(); + bdec = ParseBaseTypeDeclaration(typeFlags, false); + + Declaration* ctdec = ParseFunctionDeclaration(bdec); + + if (ctdec->mParams) + mErrors->Error(ctdec->mLocation, EERR_WRONG_PARAMETER, "Cast operators can't have parameter"); + + Declaration* bthis = new Declaration(mScanner->mLocation, DT_TYPE_POINTER); + bthis->mFlags |= DTF_CONST | DTF_DEFINED; + if (ConsumeTokenIf(TK_CONST)) + bthis->mBase = pthis->mBase->ToConstType(); + else + bthis->mBase = pthis->mBase; + bthis->mSize = 2; + + PrependThisArgument(ctdec, bthis); + + Declaration* cdec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION); + cdec->mBase = ctdec; + + cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE); + ctdec->mFlags |= storageFlags & (DTF_REQUEST_INLINE | DTF_CONSTEXPR | DTF_VIRTUAL); + + cdec->mSection = mCodeSection; + cdec->mBase->mFlags |= typeFlags; + + if (mCompilerOptions & COPT_NATIVE) + cdec->mFlags |= DTF_NATIVE; + + cdec->mIdent = Ident::Unique("(cast)"); + cdec->mQualIdent = pthis->mBase->mScope->Mangle(cdec->mIdent); + + if (mScanner->mToken == TK_OPEN_BRACE) + { + cdec->mCompilerOptions = mCompilerOptions; + cdec->mBase->mCompilerOptions = mCompilerOptions; + + cdec->mVarIndex = -1; + + cdec->mValue = ParseFunction(cdec->mBase); + + cdec->mFlags |= DTF_DEFINED | DTF_REQUEST_INLINE; + cdec->mNumVars = mLocalIndex; + } + + return cdec; + } + + bdec = ParseBaseTypeDeclaration(typeFlags, false, ptempl); } Declaration* rdec = nullptr, * ldec = nullptr; @@ -1293,13 +3887,14 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex { Declaration* ctdec = ParseFunctionDeclaration(TheVoidTypeDeclaration); + Declaration* cdec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION); + PrependThisArgument(ctdec, pthis); - Declaration* cdec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION); cdec->mBase = ctdec; cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE); - cdec->mFlags |= DTF_FUNC_CONSTRUCTOR; + cdec->mFlags |= storageFlags & (DTF_INLINE | DTF_CONSTEXPR); cdec->mSection = mCodeSection; cdec->mBase->mFlags |= typeFlags; @@ -1307,13 +3902,15 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex if (mCompilerOptions & COPT_NATIVE) cdec->mFlags |= DTF_NATIVE; - Declaration* pdec = pthis->mBase->mConstructor; + Declaration* pdec = pthis->mBase->mScope ? pthis->mBase->mScope->Lookup(pthis->mBase->mIdent->PreMangle("+"), SLEVEL_CLASS) : nullptr; if (pdec) { while (pdec && !cdec->mBase->IsSameParams(pdec->mBase)) pdec = pdec->mNext; } + Declaration* dec = cdec; + if (pdec) { if (!cdec->mBase->IsSame(pdec->mBase)) @@ -1338,17 +3935,20 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex } } - cdec = pdec; - } - else - { - cdec->mNext = pthis->mBase->mConstructor; - pthis->mBase->mConstructor = cdec; + dec = pdec; + if (!(pdec->mFlags & DTF_DEFINED)) + cdec = pdec; } - cdec->mIdent = pthis->mBase->mIdent; + cdec->mIdent = pthis->mBase->mIdent->PreMangle("+"); cdec->mQualIdent = pthis->mBase->mScope->Mangle(cdec->mIdent); + // Initializer list + if (mScanner->mToken == TK_COLON) + { + BuildMemberConstructor(pthis, cdec); + } + if (mScanner->mToken == TK_OPEN_BRACE) { if (cdec->mFlags & DTF_DEFINED) @@ -1361,11 +3961,184 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex cdec->mValue = ParseFunction(cdec->mBase); - cdec->mFlags |= DTF_DEFINED; + cdec->mFlags |= DTF_DEFINED | DTF_REQUEST_INLINE; cdec->mNumVars = mLocalIndex; } - return cdec; + return dec; + } + + if (bdec && bdec->mType == DT_TYPE_STRUCT && ConsumeTokenIf(TK_COLCOLON)) + { + if (mScanner->mToken == TK_IDENT) + { + if (mScanner->mTokenIdent == bdec->mIdent) + { + mScanner->NextToken(); + + Declaration* ctdec = ParseFunctionDeclaration(TheVoidTypeDeclaration); + + Declaration* bthis = new Declaration(mScanner->mLocation, DT_TYPE_POINTER); + bthis->mFlags |= DTF_CONST | DTF_DEFINED; + if (ConsumeTokenIf(TK_CONST)) + bthis->mBase = bdec->ToConstType(); + else + bthis->mBase = bdec; + bthis->mSize = 2; + + PrependThisArgument(ctdec, bthis); + + Declaration* cdec = bdec->mScope->Lookup(bdec->mIdent->PreMangle("+"), SLEVEL_CLASS); + if (cdec) + { + while (cdec && !cdec->mBase->IsSameParams(ctdec)) + cdec = cdec->mNext; + } + + if (cdec) + { + cdec->mFlags |= storageFlags & (DTF_REQUEST_INLINE | DTF_CONSTEXPR); + + // Initializer list + if (mScanner->mToken == TK_COLON) + { + BuildMemberConstructor(bthis, cdec); + } + + if (mScanner->mToken == TK_OPEN_BRACE) + { + // + // Take parameter names from new declaration + // + Declaration* npdec = ctdec->mParams, * ppdec = cdec->mBase->mParams; + while (npdec && ppdec) + { + if (npdec->mIdent) + { + ppdec->mIdent = npdec->mIdent; + ppdec->mQualIdent = npdec->mQualIdent; + } + npdec = npdec->mNext; + ppdec = ppdec->mNext; + } + + if (cdec->mFlags & DTF_DEFINED) + mErrors->Error(cdec->mLocation, EERR_DUPLICATE_DEFINITION, "Function already has a body"); + + cdec->mCompilerOptions = mCompilerOptions; + cdec->mBase->mCompilerOptions = mCompilerOptions; + + cdec->mVarIndex = -1; + + cdec->mValue = ParseFunction(cdec->mBase); + + cdec->mFlags |= DTF_DEFINED; + cdec->mNumVars = mLocalIndex; + + PrependMemberConstructor(bthis, cdec); + } + + return cdec; + } + else + { + mErrors->Error(bdec->mLocation, ERRO_NO_MATCHING_FUNCTION_CALL, "No matching constructor"); + return bdec; + } + } + else + { + Declaration* mdec = bdec->mScope->Lookup(mScanner->mTokenIdent, SLEVEL_CLASS); + if (mdec) + bdec = mdec; + else + mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Member not found", mScanner->mTokenIdent); + mScanner->NextToken(); + } + } + + if (ConsumeTokenIf(TK_BINARY_NOT)) + { + if (mScanner->mToken == TK_IDENT) + { + if (mScanner->mTokenIdent != bdec->mIdent) + mErrors->Error(mScanner->mLocation, EERR_INVALID_IDENTIFIER, "Wrong class name for destructor", bdec->mIdent); + mScanner->NextToken(); + } + else + mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Identifier expected"); + + Declaration* ctdec = ParseFunctionDeclaration(TheVoidTypeDeclaration); + + if (ctdec->mParams) + mErrors->Error(ctdec->mLocation, EERR_WRONG_PARAMETER, "Destructor can't have parameter"); + + if (bdec->mDestructor) + { + bdec->mDestructor->mFlags |= storageFlags & (DTF_REQUEST_INLINE | DTF_CONSTEXPR); + + Declaration* bthis = new Declaration(mScanner->mLocation, DT_TYPE_POINTER); + bthis->mFlags |= DTF_CONST | DTF_DEFINED; + bthis->mBase = bdec; + bthis->mSize = 2; + + bdec->mDestructor->mCompilerOptions = mCompilerOptions; + bdec->mDestructor->mBase->mCompilerOptions = mCompilerOptions; + + bdec->mDestructor->mVarIndex = -1; + + bdec->mDestructor->mValue = ParseFunction(bdec->mDestructor->mBase); + + bdec->mDestructor->mFlags |= DTF_DEFINED; + bdec->mDestructor->mNumVars = mLocalIndex; + + AppendMemberDestructor(bthis); + } + else + mErrors->Error(ctdec->mLocation, EERR_DUPLICATE_DEFINITION, "Destructor not declared", bdec->mIdent); + + return bdec->mDestructor; + } + else if (ConsumeTokenIf(TK_OPERATOR)) + { + Declaration* tdec = ParseBaseTypeDeclaration(0, true); + + Declaration* ctdec = ParseFunctionDeclaration(tdec); + + if (ctdec->mParams) + mErrors->Error(ctdec->mLocation, EERR_WRONG_PARAMETER, "Cast operators can't have parameter"); + + Declaration* bthis = new Declaration(mScanner->mLocation, DT_TYPE_POINTER); + bthis->mFlags |= DTF_CONST | DTF_DEFINED; + if (ConsumeTokenIf(TK_CONST)) + bthis->mBase = bdec->ToConstType(); + else + bthis->mBase = bdec; + bthis->mSize = 2; + + PrependThisArgument(ctdec, bthis); + + Declaration* fdec = bdec->mScope->Lookup(Ident::Unique("(cast)")); + while (fdec && !fdec->mBase->IsSame(ctdec)) + fdec = fdec->mNext; + + if (fdec) + { + fdec->mCompilerOptions = mCompilerOptions; + fdec->mBase->mCompilerOptions = mCompilerOptions; + + fdec->mVarIndex = -1; + + fdec->mValue = ParseFunction(fdec->mBase); + + fdec->mFlags |= DTF_DEFINED; + fdec->mNumVars = mLocalIndex; + } + else + mErrors->Error(ctdec->mLocation, EERR_DUPLICATE_DEFINITION, "Cast operator not declared", tdec->mIdent); + + return fdec; + } } } @@ -1395,7 +4168,7 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex } if (npdec->mBase->mType == DT_TYPE_FUNCTION) - npdec->mBase->mFlags |= storageFlags & (DTF_INTERRUPT | DTF_NATIVE | TK_FASTCALL); + npdec->mBase->mFlags |= storageFlags & (DTF_INTERRUPT | DTF_NATIVE | DTF_FASTCALL | DTF_VIRTUAL); if (definingType) { @@ -1408,11 +4181,33 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex } else { - if (ndec->mBase->mType == DT_TYPE_FUNCTION && pthis) + if (ptempl) + ptempl->mBase = ndec; + + if (ptempl && mTemplateScope && ndec->mIdent) { - PrependThisArgument(ndec->mBase, pthis); + if (!strstr(ndec->mQualIdent->mString, mTemplateScope->mName->mString)) + { + ndec->mIdent = ndec->mIdent->Mangle(mTemplateScope->mName->mString); + ndec->mQualIdent = ndec->mQualIdent->Mangle(mTemplateScope->mName->mString); + } } + if (ndec->mBase->mType == DT_TYPE_FUNCTION) + { + ndec->mBase->mClass = pthis; + + if (pthis && !(storageFlags & DTF_STATIC)) + { + if (ConsumeTokenIf(TK_CONST)) + PrependThisArgument(ndec->mBase, pthis->mBase->ToConstType()->BuildConstPointer(ndec->mLocation)); + else + PrependThisArgument(ndec->mBase, pthis); + ndec->mBase->mFlags |= DTF_FUNC_THIS; + } + } + + if (variable) { ndec->mFlags |= storageFlags; @@ -1426,6 +4221,10 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex if (mCompilerOptions & COPT_NATIVE) ndec->mFlags |= DTF_NATIVE; + + Declaration* ntdec = FunctionAutoParamsToTemplate(ndec); + if (ntdec) + return ntdec; } if (ndec->mIdent) @@ -1444,9 +4243,26 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex { pdec = mCompilationUnits->mScope->Insert(ndec->mQualIdent, ndec); - Declaration * ldec = mScope->Insert(ndec->mIdent, pdec ? pdec : ndec); - if (ldec && ldec != pdec) - mErrors->Error(ndec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate definition"); + if (mScope->Mangle(ndec->mIdent) == ndec->mQualIdent) + { + Declaration* ldec = mScope->Insert(ndec->mIdent, pdec ? pdec : ndec); +#if 0 + if (ldec && ldec->mTemplate && mTemplateScope) + { + ndec->mQualIdent = ndec->mQualIdent->Mangle(mTemplateScope->mName->mString); + } + else +#endif + + if (ldec && ldec != pdec) + mErrors->Error(ndec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate definition"); + } + else if (ptempl && mTemplateScope && pthis) + { + } + else if (!pdec) + mErrors->Error(ndec->mLocation, EERR_OBJECT_NOT_FOUND, "Object not declarared in scope", ndec->mQualIdent); + } else pdec = mScope->Insert(ndec->mIdent, ndec); @@ -1457,19 +4273,41 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex { if (pdec->mBase->mFlags & DTF_FUNC_THIS) { - Declaration* adec = pdec->mBase->mParams->Clone(); - adec->mNext = ndec->mBase->mParams; - - Declaration* p = adec->mBase->mParams; - while (p) + if (!(ndec->mBase->mFlags & DTF_FUNC_THIS)) { - p->mVarIndex += 2; - p = p->mNext; + Declaration* adec = pdec->mBase->mParams->Clone(); + adec->mNext = ndec->mBase->mParams; + + if (ConsumeTokenIf(TK_CONST)) + { + if (!(adec->mBase->mBase->mFlags & DTF_CONST)) + adec->mBase = adec->mBase->mBase->ToConstType()->BuildConstPointer(adec->mLocation); + } + else + { + if (adec->mBase->mBase->mFlags & DTF_CONST) + adec->mBase = adec->mBase->mBase->ToMutableType()->BuildConstPointer(adec->mLocation); + } + + Declaration* p = adec->mBase->mParams; + while (p) + { + p->mVarIndex += 2; + p = p->mNext; + } + + ndec->mBase->mParams = adec; + + ndec->mBase->mFlags |= DTF_FUNC_THIS; } - - ndec->mBase->mParams = adec; - - ndec->mBase->mFlags |= DTF_FUNC_THIS; + } + else if (ndec->mBase->mFlags & DTF_FUNC_THIS) + { + if (pdec->mBase->mParams) + ndec->mBase->mParams = pdec->mBase->mParams->Clone(); + else + ndec->mBase->mParams = nullptr; + ndec->mBase->mFlags &= ~DTF_FUNC_THIS; } if (mCompilerOptions & COPT_CPLUSPLUS) @@ -1483,13 +4321,22 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex } if (!pdec) + { + if (!pthis && (ndec->mBase->mFlags & DTF_FUNC_THIS)) + mErrors->Error(ndec->mLocation, EERR_DECLARATION_DIFFERS, "Function declaration differs", ndec->mIdent); + pcdec->mNext = ndec; + } } if (pdec) { if (!ndec->mBase->IsSame(pdec->mBase)) + { + ndec->mBase->IsSameParams(pdec->mBase); + ndec->mBase->IsSame(pdec->mBase); mErrors->Error(ndec->mLocation, EERR_DECLARATION_DIFFERS, "Function declaration differs", ndec->mIdent); + } else if (ndec->mFlags & ~pdec->mFlags & (DTF_HWINTERRUPT | DTF_INTERRUPT | DTF_FASTCALL | DTF_NATIVE)) mErrors->Error(ndec->mLocation, EERR_DECLARATION_DIFFERS, "Function call type declaration differs", ndec->mIdent); else @@ -1510,6 +4357,8 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex } } + pdec->mFlags |= ndec->mFlags & DTF_REQUEST_INLINE; + ndec = pdec; } } @@ -1566,6 +4415,10 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex else ndec->mVarIndex = mLocalIndex++; } + else if (pthis) + { + ndec->mFlags |= storageFlags & DTF_STATIC; + } ndec->mOffset = 0; @@ -1574,22 +4427,23 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex else rdec = ndec; ldec = ndec; - ndec->mNext = nullptr; +// ndec->mNext = nullptr; - if (mScanner->mToken == TK_ASSIGN) + if (!mFunctionType && ConsumeTokenIf(TK_COLON)) + { + Expression* exp = ParseRExpression(); + if (!ndec->mBase->IsIntegerType()) + mErrors->Error(exp->mLocation, EERR_INVALID_BITFIELD, "Invalid bitfield for non integer type"); + else if (exp->mType == EX_CONSTANT && exp->mDecType->IsIntegerType() && exp->mDecValue->mType == DT_CONST_INTEGER) + ndec->mBits = uint8(exp->mDecValue->mInteger); + else + mErrors->Error(exp->mLocation, EERR_CONSTANT_TYPE, "Constant integer expression expected"); + } + + if (ConsumeTokenIf(TK_ASSIGN)) { - mScanner->NextToken(); ndec->mValue = ParseInitExpression(ndec->mBase); - if (ndec->mBase->mType == DT_TYPE_AUTO) - { - ndec->mBase = ndec->mValue->mDecType; - if (ndec->mBase->mType == DT_TYPE_ARRAY) - { - ndec->mBase = ndec->mBase->Clone(); - ndec->mBase->mType = DT_TYPE_POINTER; - ndec->mBase->mSize = 2; - } - } + ndec->mBase = ndec->mBase->DeduceAuto(ndec->mValue->mDecType); if (ndec->mFlags & DTF_GLOBAL) { @@ -1602,96 +4456,133 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex } else if (mScanner->mToken == TK_OPEN_PARENTHESIS && (mCompilerOptions & COPT_CPLUSPLUS)) { - if (ndec->mBase->mConstructor) - { - Expression* vexp = new Expression(mScanner->mLocation, EX_VARIABLE); - vexp->mDecType = ndec->mBase; - vexp->mDecValue = ndec; - - Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); - cexp->mDecValue = ndec->mBase->mConstructor; - cexp->mDecType = cexp->mDecValue->mBase; - - Expression* fexp = new Expression(mScanner->mLocation, EX_CALL); - fexp->mLeft = cexp; - - mScanner->NextToken(); - if (mScanner->mToken != TK_CLOSE_PARENTHESIS) - { - fexp->mRight = ParseListExpression(); - ConsumeToken(TK_CLOSE_PARENTHESIS); - } - else - { - fexp->mRight = nullptr; - mScanner->NextToken(); - } - - Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX); - texp->mToken = TK_BINARY_AND; - texp->mLeft = vexp; - texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER); - texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; - texp->mDecType->mBase = ndec->mBase; - texp->mDecType->mSize = 2; - - if (fexp->mRight) - { - Expression* lexp = new Expression(mScanner->mLocation, EX_LIST); - lexp->mLeft = texp; - lexp->mRight = fexp->mRight; - fexp->mRight = lexp; - } - else - fexp->mRight = texp; - - ResolveOverloadCall(cexp, fexp->mRight); - - Expression* nexp = new Expression(mScanner->mLocation, EX_SEQUENCE); - nexp->mLeft = fexp; - nexp->mRight = vexp; - nexp->mDecType = vexp->mDecType; - - ndec->mValue = nexp; - } + ParseVariableInit(ndec); } - else if ((mCompilerOptions & COPT_CPLUSPLUS) && ndec->mBase->mConstructor) + else if ((mCompilerOptions & COPT_CPLUSPLUS) && ndec->mType == DT_VARIABLE && !pthis && !(storageFlags & DTF_EXTERN)) { // Find default constructor - Declaration* cdec = ndec->mBase->mConstructor; - while (cdec && cdec->mBase->mParams->mNext) - cdec = cdec->mNext; + Declaration* bdec = ndec->mBase; + while (bdec && bdec->mType == DT_TYPE_ARRAY) + bdec = bdec->mBase; - if (cdec) + if (bdec && bdec->mDefaultConstructor) { + bdec = bdec->ToMutableType(); + Expression* vexp = new Expression(ndec->mLocation, EX_VARIABLE); vexp->mDecType = ndec->mBase; vexp->mDecValue = ndec; - Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); - cexp->mDecValue = cdec; - cexp->mDecType = cexp->mDecValue->mBase; - - Expression* fexp = new Expression(mScanner->mLocation, EX_CALL); - fexp->mLeft = cexp; - Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX); texp->mToken = TK_BINARY_AND; texp->mLeft = vexp; texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER); - texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; - texp->mDecType->mBase = ndec->mBase; + texp->mDecType->mFlags |= DTF_DEFINED; + texp->mDecType->mBase = bdec; texp->mDecType->mSize = 2; - fexp->mRight = texp; + if (bdec->mSize == ndec->mBase->mSize) + { + Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); + cexp->mDecValue = bdec->mDefaultConstructor; + cexp->mDecType = cexp->mDecValue->mBase; - Expression* nexp = new Expression(mScanner->mLocation, EX_SEQUENCE); - nexp->mLeft = fexp; - nexp->mRight = vexp; - nexp->mDecType = vexp->mDecType; + Expression* fexp = new Expression(mScanner->mLocation, EX_CALL); + fexp->mLeft = cexp; + fexp->mRight = texp; + + if (bdec->mDefaultConstructor->mFlags & DTF_CONSTEXPR) + ndec->mSection = mDataSection; + + Expression* dexp = nullptr; + if (ndec->mBase->mDestructor) + { + Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); + cexp->mDecValue = ndec->mBase->mDestructor; + cexp->mDecType = cexp->mDecValue->mBase; + + dexp = new Expression(mScanner->mLocation, EX_CALL); + dexp->mLeft = cexp; + dexp->mRight = texp; + } + + Expression* nexp = new Expression(mScanner->mLocation, EX_CONSTRUCT); + + nexp->mLeft = new Expression(mScanner->mLocation, EX_LIST); + nexp->mLeft->mLeft = fexp; + nexp->mLeft->mRight = dexp; + + nexp->mRight = vexp; + nexp->mDecType = vexp->mDecType; + + ndec->mValue = nexp; + } + else + { + Expression* texp = vexp; + + while (texp->mDecType->mBase->mType == DT_TYPE_ARRAY) + { + Expression* iexp = new Expression(vexp->mLocation, EX_PREFIX); + iexp->mToken = TK_MUL; + iexp->mLeft = texp; + iexp->mDecType = texp->mDecType->mBase; + texp = iexp; + } + + //texp->mDecType = bdec->BuildPointer(vexp->mLocation); + + Declaration* ncdec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER); + ncdec->mBase = TheUnsignedIntTypeDeclaration; + ncdec->mInteger = ndec->mSize / bdec->mSize; + + Expression * ncexp = new Expression(mScanner->mLocation, EX_CONSTANT); + ncexp->mDecType = ncdec->mBase; + ncexp->mDecValue = ncdec; + + Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); + cexp->mDecValue = bdec->mVectorConstructor; + cexp->mDecType = cexp->mDecValue->mBase; + + Expression* fexp = new Expression(mScanner->mLocation, EX_CALL); + fexp->mLeft = cexp; + + fexp->mRight = new Expression(mScanner->mLocation, EX_LIST); + fexp->mRight->mLeft = texp; + fexp->mRight->mRight = new Expression(mScanner->mLocation, EX_BINARY); + fexp->mRight->mRight->mToken = TK_ADD; + fexp->mRight->mRight->mLeft = texp; + fexp->mRight->mRight->mDecType = texp->mDecType; + fexp->mRight->mRight->mRight = new Expression(mScanner->mLocation, EX_CONSTANT); + fexp->mRight->mRight->mRight->mDecType = ncdec->mBase; + fexp->mRight->mRight->mRight->mDecValue = ncdec; + + Expression* dexp = nullptr; + if (bdec->mDestructor) + { + Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); + cexp->mDecValue = bdec->mVectorDestructor; + cexp->mDecType = cexp->mDecValue->mBase; + + dexp = new Expression(mScanner->mLocation, EX_CALL); + dexp->mLeft = cexp; + dexp->mRight = fexp->mRight; + } + + Expression* nexp = new Expression(mScanner->mLocation, EX_CONSTRUCT); + + nexp->mLeft = new Expression(mScanner->mLocation, EX_LIST); + nexp->mLeft->mLeft = fexp; + nexp->mLeft->mRight = dexp; + + nexp->mRight = vexp; + nexp->mDecType = vexp->mDecType; + + ndec->mValue = nexp; + } } - else + else if (bdec && bdec->mDestructor) mErrors->Error(ndec->mLocation, EERR_NO_DEFAULT_CONSTRUCTOR, "No default constructor for class", ndec->mBase->mIdent); } @@ -1707,15 +4598,20 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex { if (ndec->mBase->mType == DT_TYPE_FUNCTION) { - if (ndec->mFlags & DTF_DEFINED) - mErrors->Error(ndec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate function definition"); + if ((ndec->mFlags & DTF_DEFINED) && !(ndec->mFlags & DTF_REQUEST_INLINE)) + mErrors->Error(mScanner->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate function definition", ndec->mQualIdent); ndec->mCompilerOptions = mCompilerOptions; ndec->mBase->mCompilerOptions = mCompilerOptions; ndec->mVarIndex = -1; + mFunction = ndec; ndec->mValue = ParseFunction(ndec->mBase); + mFunction = nullptr; + + if (pthis) + ndec->mFlags |= DTF_REQUEST_INLINE; ndec->mFlags |= DTF_DEFINED; ndec->mNumVars = mLocalIndex; @@ -1751,11 +4647,11 @@ Expression* Parser::ParseDeclarationExpression(Declaration * pdec) { while (dec) { + Expression* nexp; + if (dec->mValue && !(dec->mFlags & DTF_GLOBAL)) { - Expression* nexp; - - if ((mCompilerOptions & COPT_CPLUSPLUS) && dec->mValue->mType == EX_SEQUENCE) + if ((mCompilerOptions & COPT_CPLUSPLUS) && dec->mValue->mType == EX_CONSTRUCT) { nexp = dec->mValue; @@ -1765,6 +4661,66 @@ Expression* Parser::ParseDeclarationExpression(Declaration * pdec) vdec->mDecValue = dec; } } + else if ((mCompilerOptions & COPT_CPLUSPLUS) && dec->mBase->mDestructor) + { + Expression* vexp = new Expression(dec->mLocation, EX_VARIABLE); + vexp->mDecType = dec->mBase; + vexp->mDecValue = dec; + + Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX); + texp->mToken = TK_BINARY_AND; + texp->mLeft = vexp; + texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER); + texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + texp->mDecType->mBase = dec->mBase; + texp->mDecType->mSize = 2; + + Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); + cexp->mDecValue = dec->mBase->mDestructor; + cexp->mDecType = cexp->mDecValue->mBase; + + Expression* dexp = new Expression(mScanner->mLocation, EX_CALL); + dexp->mLeft = cexp; + dexp->mRight = texp; + + Expression* aexp; + + Declaration* fcons = dec->mBase->mScope->Lookup(dec->mBase->mIdent->PreMangle("+")); + + if (fcons && !(dec->mValue->mType == EX_CALL && dec->mValue->mDecType->mType == DT_TYPE_STRUCT)) + { + + Expression* cexp = new Expression(dec->mLocation, EX_CONSTANT); + cexp->mDecValue = fcons; + cexp->mDecType = cexp->mDecValue->mBase; + + aexp = new Expression(mScanner->mLocation, EX_CALL); + aexp->mLeft = cexp; + aexp->mRight = new Expression(dec->mLocation, EX_LIST); + aexp->mRight->mLeft = texp; + aexp->mRight->mRight = dec->mValue; + + ResolveOverloadCall(aexp); + } + else + { + aexp = new Expression(dec->mValue->mLocation, EX_INITIALIZATION); + aexp->mToken = TK_ASSIGN; + aexp->mLeft = new Expression(dec->mLocation, EX_VARIABLE); + aexp->mLeft->mDecValue = dec; + aexp->mLeft->mDecType = dec->mBase; + aexp->mDecType = aexp->mLeft->mDecType; + aexp->mRight = dec->mValue; + } + + nexp = new Expression(mScanner->mLocation, EX_CONSTRUCT); + + nexp->mLeft = new Expression(mScanner->mLocation, EX_LIST); + nexp->mLeft->mLeft = aexp; + nexp->mLeft->mRight = dexp; + nexp->mRight = vexp; + nexp->mDecType = vexp->mDecType; + } else { nexp = new Expression(dec->mValue->mLocation, EX_INITIALIZATION); @@ -1776,21 +4732,27 @@ Expression* Parser::ParseDeclarationExpression(Declaration * pdec) nexp->mRight = dec->mValue; } + } + else + { + nexp = new Expression(dec->mLocation, EX_VARIABLE); + nexp->mDecValue = dec; + nexp->mDecType = dec->mBase; + } - if (!exp) - exp = nexp; - else + if (!exp) + exp = nexp; + else + { + if (!rexp) { - if (!rexp) - { - rexp = new Expression(nexp->mLocation, EX_SEQUENCE); - rexp->mLeft = exp; - exp = rexp; - } - rexp->mRight = new Expression(nexp->mLocation, EX_SEQUENCE); - rexp = rexp->mRight; - rexp->mLeft = nexp; + rexp = new Expression(nexp->mLocation, EX_SEQUENCE); + rexp->mLeft = exp; + exp = rexp; } + rexp->mRight = new Expression(nexp->mLocation, EX_SEQUENCE); + rexp = rexp->mRight; + rexp->mLeft = nexp; } dec = dec->mNext; @@ -1802,7 +4764,15 @@ Expression* Parser::ParseDeclarationExpression(Declaration * pdec) Declaration* Parser::ParseQualIdent(void) { - Declaration* dec = mScope->Lookup(mScanner->mTokenIdent); + Declaration* dec = nullptr; + if (mTemplateScope) + { + dec = mTemplateScope->Lookup(mScanner->mTokenIdent); + } + + if (!dec) + dec = mScope->Lookup(mScanner->mTokenIdent); + if (dec) { mScanner->NextToken(); @@ -1810,9 +4780,9 @@ Declaration* Parser::ParseQualIdent(void) { if (mScanner->mToken == TK_IDENT) { - if (dec->mType == DT_NAMESPACE) + if (dec->mType == DT_NAMESPACE || dec->mType == DT_TYPE_STRUCT) { - Declaration* ndec = dec->mScope->Lookup(mScanner->mTokenIdent); + Declaration* ndec = dec->mScope->Lookup(mScanner->mTokenIdent, SLEVEL_USING); if (ndec) dec = ndec; @@ -1838,9 +4808,296 @@ Declaration* Parser::ParseQualIdent(void) return dec; } +Expression* Parser::ParseLambdaExpression(void) +{ + Declaration* cdec = new Declaration(mScanner->mLocation, DT_TYPE_STRUCT); + cdec->mIdent = Ident::Unique("lambda", mCompilationUnits->UniqueID()); + cdec->mQualIdent = mScope->Mangle(cdec->mIdent); + cdec->mFlags |= DTF_DEFINED; + + cdec->mScope = new DeclarationScope(nullptr, SLEVEL_CLASS, cdec->mIdent); + + Declaration* olambda = mLambda; + mLambda = cdec; + + Token octoken = mCaptureToken; + mCaptureToken = TK_NONE; + + Declaration* vdec = new Declaration(mScanner->mLocation, DT_VARIABLE); + + Declaration* cpdec = cdec->BuildConstPointer(mScanner->mLocation); + + Declaration* fdec = new Declaration(mScanner->mLocation, DT_CONST_FUNCTION); + fdec->mIdent = Ident::Unique("operator()"); + fdec->mQualIdent = cdec->mScope->Mangle(fdec->mIdent); + fdec->mCompilerOptions = mCompilerOptions; + cdec->mScope->Insert(fdec->mIdent, fdec); + + Declaration* pdec = new Declaration(mScanner->mLocation, DT_ARGUMENT); + pdec->mBase = cpdec; + pdec->mSize = 2; + + Expression* einit = nullptr; + + bool capture = false; + + ConsumeToken(TK_OPEN_BRACKET); + if (!ConsumeTokenIf(TK_CLOSE_BRACKET)) + { + capture = true; + + // Parse capture list list + do { + bool reference = false; + + if (ConsumeTokenIf(TK_BINARY_AND)) + { + if (mScanner->mToken == TK_IDENT) + reference = true; + else + mCaptureToken = TK_BINARY_AND; + } + + if (ConsumeTokenIf(TK_ASSIGN)) + mCaptureToken = TK_ASSIGN; + else if (ConsumeTokenIf(TK_THIS)) + { + Declaration* mdec = new Declaration(mScanner->mLocation, DT_ELEMENT); + mdec->mIdent = Ident::Unique("this"); + mdec->mQualIdent = cdec->mScope->Mangle(mdec->mIdent); + if (cdec->mScope->Insert(mdec->mIdent, mdec)) + mErrors->Error(mdec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate lambda capture", mdec->mIdent); + + if (mThisPointer) + { + Expression* iexp = new Expression(mScanner->mLocation, EX_VARIABLE); + iexp->mDecType = mThisPointer->mBase; + iexp->mDecValue = mThisPointer; + + mdec->mBase = iexp->mDecType; + mdec->mValue = iexp; + mdec->mNext = cdec->mParams; + cdec->mParams = mdec; + } + else + mErrors->Error(mScanner->mLocation, ERRO_THIS_OUTSIDE_OF_METHOD, "Use of this outside of method"); + + mdec->mOffset = cdec->mSize; + mdec->mSize = mdec->mBase->mSize; + cdec->mSize += mdec->mSize; + } + else if (mScanner->mToken == TK_IDENT) + { + Declaration* mdec = new Declaration(mScanner->mLocation, DT_ELEMENT); + mdec->mIdent = mScanner->mTokenIdent; + mdec->mQualIdent = cdec->mScope->Mangle(mdec->mIdent); + if (cdec->mScope->Insert(mdec->mIdent, mdec)) + mErrors->Error(mdec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate lambda capture", mdec->mIdent); + + Expression* iexp = nullptr; + + mScanner->NextToken(); + if (ConsumeTokenIf(TK_ASSIGN)) + iexp = ParseExpression(false); + else + { + Declaration* mvdec = mScope->Lookup(mdec->mIdent); + if (mvdec && mvdec->mType == DT_VARIABLE) + { + iexp = new Expression(mdec->mLocation, EX_VARIABLE); + iexp->mDecType = mvdec->mBase; + iexp->mDecValue = mvdec; + } + else + mErrors->Error(mdec->mLocation, EERR_INVALID_CAPTURE, "Invalid variable capture", mdec->mIdent); + } + + if (iexp) + { + if (reference) + mdec->mBase = iexp->mDecType->BuildReference(mdec->mLocation); + else + mdec->mBase = iexp->mDecType; + mdec->mValue = iexp; + mdec->mNext = cdec->mParams; + cdec->mParams = mdec; + } + + mdec->mOffset = cdec->mSize; + mdec->mSize = mdec->mBase->mSize; + cdec->mSize += mdec->mSize; + } + + } while (ConsumeTokenIf(TK_COMMA)); + + ConsumeToken(TK_CLOSE_BRACKET); + } + + Declaration* rtype = new Declaration(mScanner->mLocation, DT_TYPE_AUTO); + + if (mScanner->mToken == TK_OPEN_PARENTHESIS) + { + fdec->mBase = ParseFunctionDeclaration(rtype); + } + else + { + ConsumeToken(TK_OPEN_PARENTHESIS); + fdec->mBase = TheConstVoidTypeDeclaration; + } + + if (capture) + PrependThisArgument(fdec->mBase, cpdec); + + fdec->mFlags |= fdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE); + + fdec->mSection = mCodeSection; + + if (mCompilerOptions & COPT_NATIVE) + fdec->mFlags |= DTF_NATIVE; + + fdec->mCompilerOptions = mCompilerOptions; + fdec->mBase->mCompilerOptions = mCompilerOptions; + + fdec->mVarIndex = -1; + + + int li = mLocalIndex; + + DeclarationScope * oscope = mCaptureScope; + mCaptureScope = mScope; + + while (mScope->mLevel >= SLEVEL_NAMESPACE) + mScope = mScope->mParent; + + Declaration* tfdec = FunctionAutoParamsToTemplate(fdec); + if (tfdec) + { + fdec = tfdec; + } + else + fdec->mValue = ParseFunction(fdec->mBase); + + mScope = mCaptureScope; + mLambda = olambda; + mCaptureScope = oscope; + mCaptureToken = octoken; + + Declaration* pmdec = cdec->mParams; + while (pmdec) + { + Declaration* fcons = pmdec->mBase->mType == DT_TYPE_STRUCT && pmdec->mBase->mScope ? pmdec->mBase->mScope->Lookup(pmdec->mBase->mIdent->PreMangle("+"), SLEVEL_CLASS) : nullptr; + + Expression* ciexp; + + if (fcons) + { + Expression* vexp = new Expression(pmdec->mLocation, EX_QUALIFY); + vexp->mLeft = new Expression(pmdec->mLocation, EX_VARIABLE); + vexp->mLeft->mDecType = cdec; + vexp->mLeft->mDecValue = vdec; + vexp->mDecValue = pmdec; + vexp->mDecType = pmdec->mBase; + + Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); + cexp->mDecValue = fcons; + cexp->mDecType = cexp->mDecValue->mBase; + + Expression* fexp = new Expression(mScanner->mLocation, EX_CALL); + fexp->mLeft = cexp; + fexp->mRight = pmdec->mValue; + + Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX); + texp->mToken = TK_BINARY_AND; + texp->mLeft = vexp; + texp->mDecType = pmdec->mBase->BuildPointer(mScanner->mLocation); + + Expression* lexp = new Expression(mScanner->mLocation, EX_LIST); + lexp->mLeft = texp; + lexp->mRight = fexp->mRight; + fexp->mRight = lexp; + + fexp = ResolveOverloadCall(fexp); + + Expression* dexp = nullptr; + if (pmdec->mBase->mDestructor) + { + Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); + cexp->mDecValue = pmdec->mBase->mDestructor; + cexp->mDecType = cexp->mDecValue->mBase; + + dexp = new Expression(mScanner->mLocation, EX_CALL); + dexp->mLeft = cexp; + dexp->mRight = texp; + } + + ciexp = new Expression(mScanner->mLocation, EX_CONSTRUCT); + + ciexp->mLeft = new Expression(mScanner->mLocation, EX_LIST); + ciexp->mLeft->mLeft = fexp; + ciexp->mLeft->mRight = dexp; + } + else + { + ciexp = new Expression(pmdec->mLocation, EX_INITIALIZATION); + ciexp->mToken = TK_ASSIGN; + ciexp->mDecType = pmdec->mValue->mDecType; + ciexp->mRight = pmdec->mValue; + ciexp->mLeft = new Expression(pmdec->mLocation, EX_QUALIFY); + ciexp->mLeft->mLeft = new Expression(pmdec->mLocation, EX_VARIABLE); + ciexp->mLeft->mLeft->mDecType = cdec; + ciexp->mLeft->mLeft->mDecValue = vdec; + ciexp->mLeft->mDecValue = pmdec; + ciexp->mLeft->mDecType = pmdec->mBase; + } + + if (einit) + { + Expression* lexp = new Expression(mScanner->mLocation, EX_LIST); + lexp->mLeft = einit; + lexp->mRight = ciexp; + einit = lexp; + } + else + einit = ciexp; + + pmdec = pmdec->mNext; + } + + fdec->mFlags |= DTF_DEFINED | DTF_REQUEST_INLINE; + fdec->mNumVars = mLocalIndex; + + mLocalIndex = li; + + vdec->mBase = cdec; + vdec->mVarIndex = mLocalIndex++; + vdec->mSize = cdec->mSize; + vdec->mFlags |= DTF_DEFINED | DTF_CONST; + vdec->mIdent = cdec->mIdent; + + Expression* vexp = new Expression(mScanner->mLocation, EX_VARIABLE); + vexp->mDecType = vdec->mBase; + vexp->mDecValue = vdec; + + + if (einit) + { + Expression* conex = new Expression(mScanner->mLocation, EX_CONSTRUCT); + conex->mRight = vexp; + conex->mDecType = vexp->mDecType; + + conex->mLeft = new Expression(mScanner->mLocation, EX_LIST); + conex->mLeft->mLeft = einit; + conex->mLeft->mRight = nullptr; + + return conex; + } + else + return vexp; +} + Expression* Parser::ParseSimpleExpression(bool lhs) { - Declaration* dec; + Declaration* dec = nullptr; Expression* exp = nullptr, * rexp = nullptr; switch (mScanner->mToken) @@ -1860,12 +5117,32 @@ Expression* Parser::ParseSimpleExpression(bool lhs) { exp = new Expression(mScanner->mLocation, EX_TYPE); exp->mDecValue = nullptr; - exp->mDecType = ParseBaseTypeDeclaration(0); + exp->mDecType = ParseBaseTypeDeclaration(0, true); + while (ConsumeTokenIf(TK_MUL)) + exp->mDecType = exp->mDecType->BuildPointer(mScanner->mLocation); + while (ConsumeTokenIf(TK_BINARY_AND)) + exp->mDecType = exp->mDecType->BuildReference(mScanner->mLocation); } break; case TK_CONST: + if (lhs) + exp = ParseDeclarationExpression(nullptr); + else + { + mScanner->NextToken(); + exp = new Expression(mScanner->mLocation, EX_TYPE); + exp->mDecValue = nullptr; + exp->mDecType = ParseBaseTypeDeclaration(DTF_CONST, true); + while (ConsumeTokenIf(TK_MUL)) + exp->mDecType = exp->mDecType->BuildPointer(mScanner->mLocation); + while (ConsumeTokenIf(TK_BINARY_AND)) + exp->mDecType = exp->mDecType->BuildReference(mScanner->mLocation); + } + break; + case TK_VOLATILE: case TK_STRUCT: + case TK_CLASS: case TK_UNION: case TK_TYPEDEF: case TK_STATIC: @@ -1877,7 +5154,7 @@ Expression* Parser::ParseSimpleExpression(bool lhs) case TK_CHARACTER: dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER); dec->mInteger = mCharMap[(unsigned char)mScanner->mTokenInteger]; - dec->mBase = TheUnsignedIntTypeDeclaration; + dec->mBase = TheUnsignedCharTypeDeclaration; exp = new Expression(mScanner->mLocation, EX_CONSTANT); exp->mDecValue = dec; exp->mDecType = dec->mBase; @@ -1950,7 +5227,7 @@ Expression* Parser::ParseSimpleExpression(bool lhs) dec->mBase = new Declaration(mScanner->mLocation, DT_TYPE_ARRAY); dec->mBase->mSize = dec->mSize; dec->mBase->mBase = TheConstCharTypeDeclaration; - dec->mBase->mFlags |= DTF_DEFINED; + dec->mBase->mFlags |= DTF_DEFINED | DTF_CONST; uint8* d = new uint8[size + 1]; dec->mData = d; @@ -2020,7 +5297,31 @@ Expression* Parser::ParseSimpleExpression(bool lhs) mScanner->NextToken(); break; case TK_THIS: - if (mThisPointer) + if (mLambda) + { + dec = mLambda->mScope->Lookup(Ident::Unique("this"), SLEVEL_CLASS); + if (dec) + { + Expression* texp = new Expression(mScanner->mLocation, EX_VARIABLE); + texp->mDecType = mThisPointer->mBase; + texp->mDecValue = mThisPointer; + + Expression* dexp = new Expression(mScanner->mLocation, EX_PREFIX); + dexp->mToken = TK_MUL; + dexp->mDecType = texp->mDecType->mBase; + dexp->mLeft = texp; + + dexp = dexp->ConstantFold(mErrors, mDataSection); + + exp = new Expression(mScanner->mLocation, EX_QUALIFY); + exp->mLeft = dexp; + exp->mDecType = dec->mBase; + exp->mDecValue = dec; + } + else + mErrors->Error(mScanner->mLocation, ERRO_THIS_OUTSIDE_OF_METHOD, "Use of this outside of method"); + } + else if (mThisPointer) { exp = new Expression(mScanner->mLocation, EX_VARIABLE); exp->mDecType = mThisPointer->mBase; @@ -2032,29 +5333,100 @@ Expression* Parser::ParseSimpleExpression(bool lhs) mScanner->NextToken(); break; case TK_IDENT: + if (mLambda && mCaptureToken != TK_NONE && !mScope->Lookup(mScanner->mTokenIdent, SLEVEL_CLASS) && !mLambda->mScope->Lookup(mScanner->mTokenIdent, SLEVEL_CLASS)) + { + Declaration * mvdec = mCaptureScope->Lookup(mScanner->mTokenIdent, SLEVEL_CLASS); + if (mvdec && mvdec->mType == DT_VARIABLE) + { + Declaration* mdec = new Declaration(mScanner->mLocation, DT_ELEMENT); + mdec->mIdent = mScanner->mTokenIdent; + mdec->mQualIdent = mLambda->mScope->Mangle(mdec->mIdent); + if (mLambda->mScope->Insert(mdec->mIdent, mdec)) + mErrors->Error(mdec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate lambda capture", mdec->mIdent); + + Expression* iexp = new Expression(mdec->mLocation, EX_VARIABLE); + iexp->mDecType = mvdec->mBase; + iexp->mDecValue = mvdec; + + if (mCaptureToken == TK_BINARY_AND) + mdec->mBase = iexp->mDecType->BuildReference(mdec->mLocation); + else + mdec->mBase = iexp->mDecType; + mdec->mValue = iexp; + mdec->mNext = mLambda->mParams; + mLambda->mParams = mdec; + + mdec->mOffset = mLambda->mSize; + mdec->mSize = mdec->mBase->mSize; + mLambda->mSize += mdec->mSize; + } + } + if (mThisPointer && !mScope->Lookup(mScanner->mTokenIdent, SLEVEL_FUNCTION)) { - dec = mThisPointer->mBase->mBase->mScope->Lookup(mScanner->mTokenIdent); + int offset; + uint64 flags; + + if (mThisPointer->mType == DT_ARGUMENT) + dec = MemberLookup(mThisPointer->mBase->mBase, mScanner->mTokenIdent, offset, flags); + else if (mThisPointer->mType == DT_TYPE_POINTER) + dec = MemberLookup(mThisPointer->mBase, mScanner->mTokenIdent, offset, flags); + if (dec) { - Expression * texp = new Expression(mScanner->mLocation, EX_VARIABLE); - texp->mDecType = mThisPointer->mBase; - texp->mDecValue = mThisPointer; + if ((dec->mType == DT_ELEMENT || dec->mType == DT_CONST_FUNCTION) && !(dec->mFlags & DTF_STATIC)) + { + Expression* texp = new Expression(mScanner->mLocation, EX_VARIABLE); + texp->mDecType = mThisPointer->mBase; + texp->mDecValue = mThisPointer; - Expression* dexp = new Expression(mScanner->mLocation, EX_PREFIX); - dexp->mToken = TK_MUL; - dexp->mDecType = texp->mDecType->mBase; - dexp->mLeft = texp; + Expression* dexp = new Expression(mScanner->mLocation, EX_PREFIX); + dexp->mToken = TK_MUL; + dexp->mDecType = texp->mDecType->mBase; + dexp->mLeft = texp; - exp = ParseQualify(dexp); + dexp = dexp->ConstantFold(mErrors, mDataSection); + + exp = ParseQualify(dexp); + } + else + mScanner->NextToken(); } } if (!exp) { - dec = ParseQualIdent(); + if (!dec) + dec = ParseQualIdent(); if (dec) { + if (dec->mTemplate && mScanner->mToken == TK_LESS_THAN) + { + dec = ParseTemplateExpansion(dec->mTemplate, nullptr); + while (ConsumeTokenIf(TK_COLCOLON)) + { + if (mScanner->mToken == TK_IDENT) + { + if (dec->mType == DT_NAMESPACE || dec->mType == DT_TYPE_STRUCT) + { + Declaration* ndec = dec->mScope->Lookup(mScanner->mTokenIdent, SLEVEL_USING); + + if (ndec) + dec = ndec; + else + mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Unknown identifier", mScanner->mTokenIdent); + } + else + mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Not a class or namespace"); + + } + else + mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Identifier expected"); + + mScanner->NextToken(); + } + } + if (dec->mType == DT_CONST_INTEGER || dec->mType == DT_CONST_FLOAT || dec->mType == DT_CONST_FUNCTION || dec->mType == DT_CONST_ASSEMBLER || dec->mType == DT_LABEL || dec->mType == DT_LABEL_REF) { exp = new Expression(mScanner->mLocation, EX_CONSTANT); @@ -2085,6 +5457,18 @@ Expression* Parser::ParseSimpleExpression(bool lhs) exp->mDecType = dec->mBase; } } + else if (dec->mType == DT_PACK_ARGUMENT) + { + exp = new Expression(mScanner->mLocation, EX_PACK); + exp->mDecValue = dec; + exp->mDecType = dec->mBase; + } + else if (dec->mType == DT_PACK_TYPE) + { + exp = new Expression(mScanner->mLocation, EX_PACK_TYPE); + exp->mDecValue = nullptr; + exp->mDecType = dec; + } else if (dec->mType <= DT_TYPE_FUNCTION) { if (lhs) @@ -2094,8 +5478,27 @@ Expression* Parser::ParseSimpleExpression(bool lhs) exp = new Expression(mScanner->mLocation, EX_TYPE); exp->mDecValue = nullptr; exp->mDecType = dec; + while (ConsumeTokenIf(TK_MUL)) + exp->mDecType = exp->mDecType->BuildPointer(mScanner->mLocation); + while (ConsumeTokenIf(TK_BINARY_AND)) + exp->mDecType = exp->mDecType->BuildReference(mScanner->mLocation); } } + else if (dec->mType == DT_CONST_TEMPLATE) + { + exp = new Expression(mScanner->mLocation, EX_CONSTANT); + exp->mDecValue = dec; + exp->mDecType = TheSignedIntTypeDeclaration; + } + else if (dec->mType == DT_PACK_TEMPLATE) + { + exp = new Expression(mScanner->mLocation, EX_PACK_TYPE); + exp->mDecType = dec; + } + else if (dec->mType == DT_ELEMENT) + { + mErrors->Error(mScanner->mLocation, EERR_NON_STATIC_MEMBER, "Non static member access", mScanner->mTokenIdent); + } else { mErrors->Error(mScanner->mLocation, EERR_INVALID_IDENTIFIER, "Invalid identifier", mScanner->mTokenIdent); @@ -2106,10 +5509,32 @@ Expression* Parser::ParseSimpleExpression(bool lhs) break; case TK_SIZEOF: mScanner->NextToken(); - rexp = ParseParenthesisExpression(); + dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER); dec->mBase = TheSignedIntTypeDeclaration; - dec->mInteger = rexp->mDecType->mSize; + + if (ConsumeTokenIf(TK_ELLIPSIS)) + { + rexp = ParseParenthesisExpression(); + if (rexp->mType == EX_PACK) + { + int n = 0; + Declaration* vdec = rexp->mDecValue->mParams; + while (vdec) + { + n++; + vdec = vdec->mNext; + } + dec->mInteger = n; + } + else + mErrors->Error(mScanner->mLocation, EERR_INVALID_PACK_USAGE, "variadic pack expected"); + } + else + { + rexp = ParseParenthesisExpression(); + dec->mInteger = rexp->mDecType->mSize; + } exp = new Expression(mScanner->mLocation, EX_CONSTANT); exp->mDecValue = dec; exp->mDecType = dec->mBase; @@ -2117,7 +5542,7 @@ Expression* Parser::ParseSimpleExpression(bool lhs) case TK_OPEN_PARENTHESIS: mScanner->NextToken(); - exp = ParseExpression(true); + exp = ParseListExpression(true); if (mScanner->mToken == TK_CLOSE_PARENTHESIS) mScanner->NextToken(); else @@ -2145,12 +5570,21 @@ Expression* Parser::ParseSimpleExpression(bool lhs) { Expression* nexp = new Expression(mScanner->mLocation, EX_TYPECAST); nexp->mDecType = exp->mDecType; - nexp->mLeft = exp; - nexp->mRight = ParsePrefixExpression(false); - exp = nexp->ConstantFold(mErrors); + nexp->mLeft = ParsePrefixExpression(false); + nexp = CheckOperatorOverload(nexp); + exp = nexp->ConstantFold(mErrors, mDataSection); } } break; + case TK_OPEN_BRACKET: + if (mCompilerOptions & COPT_CPLUSPLUS) + exp = ParseLambdaExpression(); + else + { + mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Term starts with invalid token", TokenNames[mScanner->mToken]); + mScanner->NextToken(); + } + break; case TK_ASM: mScanner->NextToken(); if (mScanner->mToken == TK_OPEN_BRACE) @@ -2183,24 +5617,110 @@ Expression* Parser::ParseSimpleExpression(bool lhs) return exp; } +Declaration* Parser::MemberLookup(Declaration* dtype, const Ident* ident, int & offset, uint64& flags) +{ + if (ident == dtype->mIdent) + return nullptr; + + Declaration* mdec = dtype->mScope->Lookup(ident, SLEVEL_CLASS); + offset = 0; + flags = 0; + + if (!mdec) + { + Declaration* bcdec = dtype->mBase; + + while (bcdec) + { + int noffset; + uint64 nflags; + + Declaration* ndec = MemberLookup(bcdec->mBase, ident, noffset, nflags); + if (ndec) + { + if (mdec) + mErrors->Error(mScanner->mLocation, EERR_DUPLICATE_DEFINITION, "Multiple definitions for member", ident); + else + { + mdec = ndec; + offset = noffset + bcdec->mOffset; + flags = nflags | bcdec->mFlags; + } + } + bcdec = bcdec->mNext; + } + } + else + flags = mdec->mFlags; + + return mdec; +} + Expression* Parser::ParseQualify(Expression* exp) { Declaration* dtype = exp->mDecType; - if (dtype->mType == DT_TYPE_REFERENCE) + exp = exp->ConstantFold(mErrors, mDataSection); + + if (dtype->mType == DT_TYPE_REFERENCE || dtype->mType == DT_TYPE_RVALUEREF) dtype = dtype->mBase; if (dtype->mType == DT_TYPE_STRUCT || dtype->mType == DT_TYPE_UNION) { Expression* nexp = new Expression(mScanner->mLocation, EX_QUALIFY); nexp->mLeft = exp; - if (mScanner->mToken == TK_IDENT) + + int moffset = 0; + uint64 mflags = 0; + Declaration* mdec = nullptr; + const Ident* ident = nullptr; + bool destructor = false; + + if ((mCompilerOptions & COPT_CPLUSPLUS) && mScanner->mToken == TK_BINARY_NOT) { - Declaration* mdec = dtype->mScope->Lookup(mScanner->mTokenIdent); + mScanner->NextToken(); + if (mScanner->mToken == TK_IDENT) + { + ident = mScanner->mTokenIdent; + if (mTemplateScope) + { + Declaration* dec = mTemplateScope->Lookup(ident); + if (dec) + ident = dec->mIdent; + } + + ident = ident->PreMangle("~"); + destructor = true; + } + else + mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Identifier expected"); + } + else if (mScanner->mToken == TK_IDENT) + ident = mScanner->mTokenIdent; + + if (ident) + { + mdec = MemberLookup(dtype, ident, moffset, mflags); if (mdec) { + if (mflags & DTF_PROTECTED) + { + Declaration* tp = mThisPointer; + if (tp && tp->mType == DT_ARGUMENT) + tp = tp->mBase; + if (!(tp && tp->mBase->IsConstSame(dtype))) + { + if (dtype->mFriends.Contains(mFunction)) + ; + else if (mThisPointer && mThisPointer->mBase && mThisPointer->mBase->mBase && dtype->mFriends.Contains(mThisPointer->mBase->mBase->ToMutableType())) + ; + else + mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Struct member identifier not visible", ident); + } + } + mScanner->NextToken(); if (mdec->mType == DT_ELEMENT) { @@ -2209,63 +5729,127 @@ Expression* Parser::ParseQualify(Expression* exp) if (exp->mDecType->mFlags & DTF_CONST) nexp->mDecType = nexp->mDecType->ToConstType(); - exp = nexp->ConstantFold(mErrors); + exp = nexp->ConstantFold(mErrors, mDataSection); + } + else if (mdec->mType == DT_VARIABLE) + { + nexp = new Expression(mScanner->mLocation, EX_VARIABLE); + nexp->mDecValue = mdec; + nexp->mDecType = mdec->mBase; + exp = nexp->ConstantFold(mErrors, mDataSection); } else if (mdec->mType == DT_CONST_FUNCTION) { - ConsumeToken(TK_OPEN_PARENTHESIS); - - nexp = new Expression(mScanner->mLocation, EX_CALL); - if (mInlineCall) - nexp->mType = EX_INLINE; - mInlineCall = false; - - nexp->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT); - nexp->mLeft->mDecType = mdec->mBase; - nexp->mLeft->mDecValue = mdec; - - nexp->mDecType = mdec->mBase; - if (ConsumeTokenIf(TK_CLOSE_PARENTHESIS)) - nexp->mRight = nullptr; - else + if (mdec->mBase->mFlags & DTF_FUNC_THIS) { - nexp->mRight = ParseListExpression(); - ConsumeToken(TK_CLOSE_PARENTHESIS); - } + ConsumeToken(TK_OPEN_PARENTHESIS); - Expression* texp = new Expression(nexp->mLocation, EX_PREFIX); - texp->mToken = TK_BINARY_AND; - texp->mLeft = exp; - texp->mDecType = new Declaration(nexp->mLocation, DT_TYPE_POINTER); - texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; - texp->mDecType->mBase = exp->mDecType; - texp->mDecType->mSize = 2; + nexp = new Expression(mScanner->mLocation, EX_CALL); + if (mInlineCall) + nexp->mType = EX_INLINE; + mInlineCall = false; - if (nexp->mRight) - { - Expression* lexp = new Expression(nexp->mLocation, EX_LIST); - lexp->mLeft = texp; - lexp->mRight = nexp->mRight; - nexp->mRight = lexp; + nexp->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT); + nexp->mLeft->mDecType = mdec->mBase; + nexp->mLeft->mDecValue = mdec; + + nexp->mDecType = mdec->mBase; + if (ConsumeTokenIf(TK_CLOSE_PARENTHESIS)) + nexp->mRight = nullptr; + else + { + nexp->mRight = ParseListExpression(false); + ConsumeToken(TK_CLOSE_PARENTHESIS); + } + + Expression* texp = new Expression(nexp->mLocation, EX_PREFIX); + texp->mToken = TK_BINARY_AND; + texp->mLeft = exp; + texp->mDecType = new Declaration(nexp->mLocation, DT_TYPE_POINTER); + texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + if (exp->mDecType->mType == DT_TYPE_REFERENCE) + texp->mDecType->mBase = exp->mDecType->mBase; + else + texp->mDecType->mBase = exp->mDecType; + texp->mDecType->mSize = 2; + + if (nexp->mRight) + { + Expression* lexp = new Expression(nexp->mLocation, EX_LIST); + lexp->mLeft = texp; + lexp->mRight = nexp->mRight; + nexp->mRight = lexp; + } + else + nexp->mRight = texp; + + nexp = ResolveOverloadCall(nexp); + + nexp->mDecType = nexp->mLeft->mDecType->mBase; + + if (nexp->mLeft->mDecType->mFlags & DTF_VIRTUAL) + nexp->mType = EX_VCALL; + + exp = nexp; } else - nexp->mRight = texp; - - ResolveOverloadCall(nexp->mLeft, nexp->mRight); - nexp->mDecType = nexp->mLeft->mDecType->mBase; - - exp = nexp; + { + nexp = new Expression(mScanner->mLocation, EX_CONSTANT); + nexp->mDecValue = mdec; + nexp->mDecType = mdec->mBase; + exp = nexp; + } } } + else if (destructor) + { + mScanner->NextToken(); + ConsumeToken(TK_OPEN_PARENTHESIS); + ConsumeToken(TK_CLOSE_PARENTHESIS); + } else { mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Struct member identifier not found", mScanner->mTokenIdent); mScanner->NextToken(); } - } else mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Struct member identifier expected"); + + } + else if ((mCompilerOptions & COPT_CPLUSPLUS) && mScanner->mToken == TK_BINARY_NOT) + { + mScanner->NextToken(); + if (mScanner->mToken == TK_IDENT) + { + const Ident * ident = mScanner->mTokenIdent; + if (mTemplateScope) + { + Declaration* dec = mTemplateScope->Lookup(ident); + if (dec == dtype) + { + mScanner->NextToken(); + ConsumeToken(TK_OPEN_PARENTHESIS); + ConsumeToken(TK_CLOSE_PARENTHESIS); + + exp = new Expression(mScanner->mLocation, EX_VOID); + exp->mDecType = TheConstVoidTypeDeclaration; + } + } + else if (ident == dtype->mIdent) + { + mScanner->NextToken(); + ConsumeToken(TK_OPEN_PARENTHESIS); + ConsumeToken(TK_CLOSE_PARENTHESIS); + + exp = new Expression(mScanner->mLocation, EX_VOID); + exp->mDecType = TheConstVoidTypeDeclaration; + } + else + mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Destructor identifier expected"); + } + else + mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Identifier expected"); } else mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Struct expected"); @@ -2273,12 +5857,23 @@ Expression* Parser::ParseQualify(Expression* exp) return exp; } +static const int NOOVERLOAD = 0x7fffffff; + int Parser::OverloadDistance(Declaration* fdec, Expression* pexp) { - Declaration* pdec = fdec->mParams; + if (fdec->mTemplate) + { + Declaration* tdec = new Declaration(mScanner->mLocation, DT_TEMPLATE); + tdec->mScope = new DeclarationScope(nullptr, SLEVEL_TEMPLATE); + if (!tdec->CanResolveTemplate(pexp, fdec)) + return NOOVERLOAD; + } + + Declaration* pdec = fdec->mBase->mParams; int dist = 0; + bool packtemp = false; while (pexp) { Expression* ex = pexp; @@ -2297,71 +5892,433 @@ int Parser::OverloadDistance(Declaration* fdec, Expression* pexp) if (etype->mType == DT_TYPE_REFERENCE) etype = etype->mBase; - if (ptype->mType == DT_TYPE_INTEGER && etype->mType == DT_TYPE_INTEGER) - ; - else if (ptype->mType == DT_TYPE_FLOAT && etype->mType == DT_TYPE_FLOAT) - ; - else if (ptype->mType == DT_TYPE_INTEGER && etype->mType == DT_TYPE_FLOAT) - dist += 8; - else if (ptype->mType == DT_TYPE_FLOAT && etype->mType == DT_TYPE_INTEGER) - dist++; - else if (ptype->IsSame(ex->mDecType)) - ; - else if (ptype->mType == DT_TYPE_REFERENCE && ptype->mBase->mType == DT_TYPE_STRUCT && etype->mType == DT_TYPE_STRUCT) + if (ptype->mType == DT_PACK_TEMPLATE || ptype->mType == DT_TYPE_REFERENCE && ptype->mBase->mType == DT_PACK_TEMPLATE) + packtemp = true; + + if (ptype->mType == DT_TYPE_TEMPLATE || ptype->mType == DT_PACK_TEMPLATE) { - int ncast = 0; - Declaration* ext = ex->mDecType; - while (ext && !ext->IsConstSame(ptype->mBase)) - ext = ext->mBase; - - if (ext) + dist += 1; + } + else if (ptype->mType == DT_TYPE_REFERENCE && (ptype->mBase->mType == DT_TYPE_TEMPLATE || ptype->mBase->mType == DT_PACK_TEMPLATE)) + { + if (ex->IsLValue()) + dist += 1; + else if (ptype->mBase->mFlags & DTF_CONST) + dist += 1; + else + return NOOVERLOAD; + } + else if (ptype->mType == DT_TYPE_INTEGER && etype->mType == DT_TYPE_INTEGER) + { + if (ptype->mSize == etype->mSize) { - if ((etype->mFlags & DTF_CONST) && !(ptype->mBase->mFlags & DTF_CONST)) - return INT_MAX; + if ((ptype->mFlags & DTF_SIGNED) == (etype->mFlags & DTF_SIGNED)) + dist += 0; + else + dist += 8; + } + else if (ptype->mSize > etype->mSize) + { + if (ptype->mFlags & DTF_SIGNED) + { + dist += 2; + } + else if (etype->mFlags & DTF_SIGNED) + { + dist += 8; + } + else + dist += 2; + } + else if (ex->mType == EX_CONSTANT && ex->mDecValue->mType == DT_CONST_INTEGER) + { + int64 v = ex->mDecValue->mInteger; - dist += 16 * ncast; + if (ptype->mFlags & DTF_SIGNED) + { + if (v >= -128 && v <= 127) + dist += 2; + else if (ptype->mSize >= 2 && v >= -32768 && v <= 32767) + dist += 2; + else if (ptype->mSize == 4) + dist += 2; + else + dist += 32; + } + else if (v >= 0) + { + if (v <= 255) + dist += 2; + else if (ptype->mSize >= 2 && v <= 65535) + dist += 2; + else if (ptype->mSize == 4) + dist += 2; + else + dist += 32; + } + else + dist += 32; } else - return INT_MAX; + dist += 32; } - else if (ptype->IsSubType(ex->mDecType)) - dist += 256; - else - return INT_MAX; + else if (ptype->mType == DT_TYPE_FLOAT && etype->mType == DT_TYPE_FLOAT) + dist += 0; + else if (ptype->mType == DT_TYPE_INTEGER && etype->mType == DT_TYPE_FLOAT) + dist += 16; + else if (ptype->mType == DT_TYPE_FLOAT && etype->mType == DT_TYPE_INTEGER) + dist += 8; + else if (ptype->IsSame(ex->mDecType)) + ; + else if (CanCoerceExpression(ex, ptype)) + { + dist += 512; + if (ptype->mType == DT_TYPE_REFERENCE) + dist += 8; + else if (ptype->mType == DT_TYPE_RVALUEREF) + dist += 4; + } + else if (ptype->mType == DT_TYPE_REFERENCE && ptype->mBase->mType == DT_TYPE_STRUCT && etype->mType == DT_TYPE_STRUCT) + { + if (ex->IsLValue()) + dist += 4; + else if (ptype->mBase->mFlags & DTF_CONST) + dist += 8; + else + return NOOVERLOAD; - pdec = pdec->mNext; + if (ptype->mBase->mTemplate) + { + dist += 16; + } + else + { + int ncast = 0; + Declaration* ext = ex->mDecType; + while (ext && !ext->IsConstSame(ptype->mBase)) + { + ncast++; + ext = ext->mBase; + } + + if (ext) + { + if ((etype->mFlags & DTF_CONST) && !(ptype->mBase->mFlags & DTF_CONST)) + return NOOVERLOAD; + + dist += 32 * ncast; + } + else + return NOOVERLOAD; + } + } + else if (ptype->mType == DT_TYPE_POINTER && (etype->mType == DT_TYPE_ARRAY || etype->mType == DT_TYPE_POINTER) && ptype->mBase->IsSameMutable(etype->mBase)) + dist += 2; + else if (ptype->mType == DT_TYPE_POINTER && etype->mType == DT_TYPE_FUNCTION && ptype->mBase->IsSame(etype)) + dist += 0; + else if (ptype->mType == DT_TYPE_POINTER && etype->mType == DT_TYPE_POINTER && etype->mBase->mType == DT_TYPE_VOID) + dist += 0; + else if (ptype->IsSubType(etype)) + dist += 256; + else if (ptype->mType == DT_TYPE_RVALUEREF && ptype->mBase->IsSameMutable(etype) && ex->IsRValue()) + { + dist += 2; + } + else if (ptype->mType == DT_TYPE_REFERENCE && ptype->mBase->IsSameMutable(etype)) + { + if (ex->IsLValue()) + dist += 4; + else if (ptype->mBase->mFlags & DTF_CONST) + dist += 8; + else + return NOOVERLOAD; + } + else if (ptype->mType == DT_TYPE_REFERENCE && (ptype->mBase->mFlags & DTF_CONST) && ptype->mBase->CanAssign(etype)) + { + dist += 32; + } + else + return NOOVERLOAD; + + if (!packtemp) + pdec = pdec->mNext; } - else if (fdec->mFlags & DTF_VARIADIC) + else if (fdec->mBase->mFlags & DTF_VARIADIC) { dist += 1024; break; } else - return INT_MAX; + return NOOVERLOAD; + } + + while (pdec && pdec->mValue) + { + dist += 1024; + pdec = pdec->mNext; } if (pdec) - return INT_MAX; + { + Declaration* ptype = pdec->mBase; + if (ptype->mType == DT_PACK_TEMPLATE || ptype->mType == DT_TYPE_REFERENCE && ptype->mBase->mType == DT_PACK_TEMPLATE) + packtemp = true; + } + + if (pdec && packtemp) + return dist; + + if (pdec) + return NOOVERLOAD; return dist; } -void Parser::ResolveOverloadCall(Expression* cexp, Expression* pexp) +bool Parser::CanCoerceExpression(Expression* exp, Declaration* type) { - if (cexp->mDecValue) + Declaration* tdec = exp->mDecType; + while (tdec->mType == DT_TYPE_REFERENCE || tdec->mType == DT_TYPE_RVALUEREF) + tdec = tdec->mBase; + while (type->mType == DT_TYPE_REFERENCE || type->mType == DT_TYPE_RVALUEREF) + type = type->mBase; + + if (tdec->mType == DT_TYPE_STRUCT) { - Declaration* fdec = cexp->mDecValue; - if (fdec->mType == DT_CONST_FUNCTION && fdec->mNext) + Declaration* fexp = tdec->mScope->Lookup(Ident::Unique("(cast)")); + if (fexp) + { + while (fexp && !fexp->mBase->mBase->IsSame(type)) + fexp = fexp->mNext; + if (fexp) + return true; + } + } + + if (type->mType == DT_TYPE_STRUCT) + { + if (!type->IsConstSame(tdec)) + { + Declaration* fcons = type->mScope ? type->mScope->Lookup(type->mIdent->PreMangle("+")) : nullptr; + if (fcons) + { + while (fcons && !(fcons->mBase->mParams && fcons->mBase->mParams->mNext && !fcons->mBase->mParams->mNext->mNext && fcons->mBase->mParams->mNext->mBase->CanAssign(tdec))) + fcons = fcons->mNext; + + if (fcons) + return true; + } + } + } + + return false; +} + +Expression* Parser::CoerceExpression(Expression* exp, Declaration* type) +{ + Declaration* tdec = exp->mDecType; + while (tdec->mType == DT_TYPE_REFERENCE || tdec->mType == DT_TYPE_RVALUEREF) + tdec = tdec->mBase; + while (type->mType == DT_TYPE_REFERENCE || type->mType == DT_TYPE_RVALUEREF) + type = type->mBase; + + if (tdec->mType == DT_TYPE_STRUCT) + { + Declaration* fexp = tdec->mScope->Lookup(Ident::Unique("(cast)")); + if (fexp) + { + while (fexp && !fexp->mBase->mBase->IsSame(type)) + fexp = fexp->mNext; + if (fexp) + { + Expression* aexp = new Expression(exp->mLocation, EX_PREFIX); + aexp->mToken = TK_BINARY_AND; + aexp->mDecType = tdec->BuildPointer(exp->mLocation); + aexp->mLeft = exp; + + Expression* nexp = new Expression(exp->mLocation, EX_CALL); + nexp->mLeft = new Expression(exp->mLocation, EX_CONSTANT); + nexp->mLeft->mDecType = fexp->mBase; + nexp->mLeft->mDecValue = fexp; + nexp->mRight = aexp; + + return nexp; + } + } + + if (type->mType == DT_TYPE_POINTER && type->mBase->mType == DT_TYPE_FUNCTION) + { + Declaration* fr = tdec->mScope->Lookup(Ident::Unique("operator()")); + if (fr && !(fr->mBase->mFlags & DTF_FUNC_THIS)) + { + Expression* nexp = new Expression(exp->mLocation, EX_CONSTANT); + nexp->mDecType = fr->mBase; + nexp->mDecValue = fr; + + return nexp; + } + } + } + + if (type->mType == DT_TYPE_STRUCT) + { + if (!type->IsConstSame(tdec)) + { + Declaration* fcons = type->mScope ? type->mScope->Lookup(type->mIdent->PreMangle("+")) : nullptr; + if (fcons) + { + while (fcons && !(fcons->mBase->mParams && fcons->mBase->mParams->mNext && !fcons->mBase->mParams->mNext->mNext && fcons->mBase->mParams->mNext->mBase->CanAssign(tdec))) + fcons = fcons->mNext; + + if (fcons) + { + Declaration* vdec = AllocTempVar(type->ToMutableType()); +#if 0 + Declaration* vdec = new Declaration(mScanner->mLocation, DT_VARIABLE); + + vdec->mBase = type->ToMutableType(); + vdec->mVarIndex = mLocalIndex++; + vdec->mSize = type->mSize; + vdec->mFlags |= DTF_DEFINED; +#endif + + Expression* vexp = new Expression(mScanner->mLocation, EX_VARIABLE); + vexp->mDecType = vdec->mBase; + vexp->mDecValue = vdec; + + Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); + cexp->mDecValue = fcons; + cexp->mDecType = cexp->mDecValue->mBase; + + Expression* fexp = new Expression(mScanner->mLocation, EX_CALL); + fexp->mLeft = cexp; + + fexp->mRight = exp; + + Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX); + texp->mToken = TK_BINARY_AND; + texp->mLeft = vexp; + texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER); + texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + texp->mDecType->mBase = vdec->mBase; + texp->mDecType->mSize = 2; + + Expression* lexp = new Expression(mScanner->mLocation, EX_LIST); + lexp->mLeft = texp; + lexp->mRight = fexp->mRight; + fexp->mRight = lexp; + + Expression* dexp = nullptr; + if (type->mDestructor) + { + Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); + cexp->mDecValue = type->mDestructor; + cexp->mDecType = cexp->mDecValue->mBase; + + dexp = new Expression(mScanner->mLocation, EX_CALL); + dexp->mLeft = cexp; + dexp->mRight = texp; + } + + Expression* nexp = new Expression(mScanner->mLocation, EX_CONSTRUCT); + + nexp->mLeft = new Expression(mScanner->mLocation, EX_LIST); + nexp->mLeft->mLeft = fexp; + nexp->mLeft->mRight = dexp; + + nexp->mRight = vexp; + nexp->mDecType = vexp->mDecType; + + return nexp; + } + } + } + } + + return exp; +} + +void Parser::ExpandFunctionCallTemplate(Expression* exp) +{ + if (exp->mLeft->mDecValue->mTemplate) + { + Declaration* tdec = new Declaration(mScanner->mLocation, DT_TEMPLATE); + tdec->mScope = new DeclarationScope(nullptr, SLEVEL_TEMPLATE); + if (tdec->ResolveTemplate(exp->mRight, exp->mLeft->mDecValue)) + { + exp->mLeft->mDecValue = ParseTemplateExpansion(exp->mLeft->mDecValue->mTemplate, tdec); + exp->mLeft->mDecType = exp->mLeft->mDecValue->mBase; + } + } +} + +void Parser::CompleteFunctionDefaultParams(Expression* exp) +{ + Declaration* fdec = exp->mLeft->mDecValue; + Expression* lexp = exp; + + Declaration* pdec = fdec->mBase->mParams; + Expression* pexp = lexp->mRight; + while (pdec) + { + if (pexp) + { + Expression* exp = pexp; + + if (pexp->mType == EX_LIST) + { + pexp->mLeft = CoerceExpression(pexp->mLeft, pdec->mBase); + lexp = pexp; + pexp = pexp->mRight; + } + else + { + lexp->mRight = CoerceExpression(lexp->mRight, pdec->mBase); + pexp = nullptr; + } + } + else if (pdec->mValue) + { + if (lexp->mRight) + { + Expression* nexp = new Expression(exp->mLocation, EX_LIST); + nexp->mLeft = lexp->mRight; + nexp->mRight = pdec->mValue; + lexp->mRight = nexp; + lexp = nexp; + } + else + lexp->mRight = pdec->mValue; + } + + pdec = pdec->mNext; + } +} + +Expression * Parser::ResolveOverloadCall(Expression* exp, Expression* exp2) +{ + if (exp->mType == EX_CALL && exp->mLeft->mDecValue) + { + if (exp->mRight && FindPackExpression(exp->mRight)) + return exp; + + Declaration* fdec = exp->mLeft->mDecValue; + Declaration* fdec2 = exp2 ? exp2->mLeft->mDecValue : nullptr; + + if (fdec->mType == DT_CONST_FUNCTION && fdec->mNext || fdec2) { Declaration* dbest = nullptr; - int ibest = INT_MAX, nbest = 0; + Expression* pbest = nullptr; + int ibest = NOOVERLOAD, nbest = 0; while (fdec) { - int d = OverloadDistance(fdec->mBase, pexp); - if (d < ibest) + int d = OverloadDistance(fdec, exp->mRight); + if (d == NOOVERLOAD) + ; + else if (d < ibest) { dbest = fdec; + pbest = exp->mRight; ibest = d; nbest = 1; } @@ -2370,17 +6327,51 @@ void Parser::ResolveOverloadCall(Expression* cexp, Expression* pexp) fdec = fdec->mNext; } - if (ibest == INT_MAX) - mErrors->Error(cexp->mLocation, ERRO_NO_MATCHING_FUNCTION_CALL, "No matching function call"); + while (fdec2) + { + int d = OverloadDistance(fdec2, exp2->mRight); + if (d == NOOVERLOAD) + ; + else if (d < ibest) + { + dbest = fdec2; + pbest = exp2->mRight; + ibest = d; + nbest = 1; + } + else if (d == ibest) + nbest++; + fdec2 = fdec2->mNext; + } + + if (ibest == NOOVERLOAD) + { +#if _DEBUG + fdec = exp->mLeft->mDecValue; + while (fdec) + { + int d = OverloadDistance(exp->mLeft->mDecValue, exp->mRight); + fdec = fdec->mNext; + } +#endif + mErrors->Error(exp->mLocation, ERRO_NO_MATCHING_FUNCTION_CALL, "No matching function call", exp->mLeft->mDecValue->mQualIdent); + } else if (nbest > 1) - mErrors->Error(cexp->mLocation, ERRO_AMBIGUOUS_FUNCTION_CALL, "Ambiguous function call"); + mErrors->Error(exp->mLocation, ERRO_AMBIGUOUS_FUNCTION_CALL, "Ambiguous function call", exp->mLeft->mDecValue->mQualIdent); else { - cexp->mDecValue = dbest; - cexp->mDecType = dbest->mBase; + exp->mLeft->mDecValue = dbest; + exp->mLeft->mDecType = dbest->mBase; + exp->mDecType = dbest->mBase->mBase; + exp->mRight = pbest; } } + + ExpandFunctionCallTemplate(exp); + CompleteFunctionDefaultParams(exp); } + + return exp; } Expression* Parser::ParsePostfixExpression(bool lhs) @@ -2389,19 +6380,30 @@ Expression* Parser::ParsePostfixExpression(bool lhs) for (;;) { - if (mScanner->mToken == TK_OPEN_BRACKET) + if (ConsumeTokenIf(TK_COLCOLON)) + { + + } + else if (ConsumeTokenIf(TK_OPEN_BRACKET)) { - if (exp->mDecType->mType != DT_TYPE_ARRAY && exp->mDecType->mType != DT_TYPE_POINTER) - mErrors->Error(mScanner->mLocation, EERR_INVALID_INDEX, "Array expected for indexing"); - mScanner->NextToken(); Expression* nexp = new Expression(mScanner->mLocation, EX_INDEX); nexp->mLeft = exp; nexp->mRight = ParseExpression(false); - if (mScanner->mToken == TK_CLOSE_BRACKET) - mScanner->NextToken(); + ConsumeToken(TK_CLOSE_BRACKET); + + if (exp->mDecType->ValueType() == DT_TYPE_STRUCT) + { + nexp = CheckOperatorOverload(nexp); + if (nexp->mType == EX_INDEX) + mErrors->Error(mScanner->mLocation, EERR_INVALID_INDEX, "No indexing operator found"); + } + else if (exp->mDecType->mType == DT_TYPE_ARRAY || exp->mDecType->mType == DT_TYPE_POINTER) + { + nexp->mDecType = exp->mDecType->mBase; + } else - mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "']' expected"); - nexp->mDecType = exp->mDecType->mBase; + mErrors->Error(mScanner->mLocation, EERR_INVALID_INDEX, "Array expected for indexing"); + if (!nexp->mDecType) nexp->mDecType = TheVoidTypeDeclaration; exp = nexp; @@ -2410,78 +6412,125 @@ Expression* Parser::ParsePostfixExpression(bool lhs) { if (exp->mType == EX_TYPE) { - if (exp->mDecType->mConstructor) + Expression * pexp = nullptr; + + if (exp->mDecType->mTemplate) { - Declaration* tdec = new Declaration(mScanner->mLocation, DT_VARIABLE); - - tdec->mBase = exp->mDecType; - tdec->mVarIndex = mLocalIndex++; - tdec->mSize = exp->mDecType->mSize; - tdec->mFlags |= DTF_DEFINED; - - Expression* vexp = new Expression(mScanner->mLocation, EX_VARIABLE); - vexp->mDecType = exp->mDecType; - vexp->mDecValue = tdec; - - Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); - cexp->mDecValue = exp->mDecType->mConstructor; - cexp->mDecType = cexp->mDecValue->mBase; - - Expression* fexp = new Expression(mScanner->mLocation, EX_CALL); - fexp->mLeft = cexp; + mErrors->Error(mScanner->mLocation, EERR_TEMPLATE_PARAMS, "Missing template parameters", exp->mDecType->mQualIdent); + exp->mDecType = TheConstVoidTypeDeclaration; + } + mScanner->NextToken(); + if (mScanner->mToken != TK_CLOSE_PARENTHESIS) + { + pexp = ParseListExpression(false); + ConsumeToken(TK_CLOSE_PARENTHESIS); + } + else mScanner->NextToken(); - if (mScanner->mToken != TK_CLOSE_PARENTHESIS) - { - fexp->mRight = ParseListExpression(); - ConsumeToken(TK_CLOSE_PARENTHESIS); - } - else - { - fexp->mRight = nullptr; - mScanner->NextToken(); - } - Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX); - texp->mToken = TK_BINARY_AND; - texp->mLeft = vexp; - texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER); - texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; - texp->mDecType->mBase = exp->mDecType; - texp->mDecType->mSize = 2; - - if (fexp->mRight) - { - Expression* lexp = new Expression(mScanner->mLocation, EX_LIST); - lexp->mLeft = texp; - lexp->mRight = fexp->mRight; - fexp->mRight = lexp; - } - else - fexp->mRight = texp; - - ResolveOverloadCall(cexp, fexp->mRight); - - Expression* nexp = new Expression(mScanner->mLocation, EX_SEQUENCE); - nexp->mLeft = fexp; - nexp->mRight = vexp; - nexp->mDecType = vexp->mDecType; - - exp = nexp; + if (pexp && pexp->mType != EX_LIST && pexp->mDecType->IsSame(exp->mDecType)) + { + // Simple copy + exp = pexp; } else { - Expression* nexp = new Expression(mScanner->mLocation, EX_TYPECAST); - nexp->mDecType = exp->mDecType; - nexp->mLeft = exp; - mScanner->NextToken(); - nexp->mRight = ParseListExpression(); - ConsumeToken(TK_CLOSE_PARENTHESIS); - exp = nexp->ConstantFold(mErrors); + Declaration* fcons = exp->mDecType->mScope ? exp->mDecType->mScope->Lookup(exp->mDecType->mIdent->PreMangle("+")) : nullptr; + if (fcons) + { + Declaration* tdec = new Declaration(mScanner->mLocation, DT_VARIABLE); + + tdec->mBase = exp->mDecType; + tdec->mVarIndex = mLocalIndex++; + tdec->mSize = exp->mDecType->mSize; + tdec->mFlags |= DTF_DEFINED | DTF_TEMPORARY; + + Expression* vexp = new Expression(mScanner->mLocation, EX_VARIABLE); + vexp->mDecType = exp->mDecType; + vexp->mDecValue = tdec; + + Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); + cexp->mDecValue = fcons; + cexp->mDecType = cexp->mDecValue->mBase; + + Expression* fexp = new Expression(mScanner->mLocation, EX_CALL); + fexp->mLeft = cexp; + + fexp->mRight = pexp; + + Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX); + texp->mToken = TK_BINARY_AND; + texp->mLeft = vexp; + texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER); + texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + texp->mDecType->mBase = exp->mDecType; + texp->mDecType->mSize = 2; + + if (fexp->mRight) + { + Expression* lexp = new Expression(mScanner->mLocation, EX_LIST); + lexp->mLeft = texp; + lexp->mRight = fexp->mRight; + fexp->mRight = lexp; + } + else + fexp->mRight = texp; + + fexp = ResolveOverloadCall(fexp); + + Expression* dexp = nullptr; + if (exp->mDecType->mDestructor) + { + Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); + cexp->mDecValue = exp->mDecType->mDestructor; + cexp->mDecType = cexp->mDecValue->mBase; + + dexp = new Expression(mScanner->mLocation, EX_CALL); + dexp->mLeft = cexp; + dexp->mRight = texp; + } + + Expression* nexp = new Expression(mScanner->mLocation, EX_CONSTRUCT); + + nexp->mLeft = new Expression(mScanner->mLocation, EX_LIST); + nexp->mLeft->mLeft = fexp; + nexp->mLeft->mRight = dexp; + + nexp->mRight = vexp; + nexp->mDecType = vexp->mDecType; + + exp = nexp; + } + else if (pexp) + { + Expression* nexp = new Expression(mScanner->mLocation, EX_TYPECAST); + nexp->mDecType = exp->mDecType; + nexp->mLeft = pexp; + nexp = CheckOperatorOverload(nexp); + exp = nexp->ConstantFold(mErrors, mDataSection); + } + else + { + Declaration* tdec = new Declaration(mScanner->mLocation, DT_VARIABLE); + + tdec->mBase = exp->mDecType; + tdec->mVarIndex = mLocalIndex++; + tdec->mSize = exp->mDecType->mSize; + tdec->mFlags |= DTF_DEFINED | DTF_TEMPORARY; + + Expression* nexp = new Expression(mScanner->mLocation, EX_VARIABLE); + nexp->mDecType = exp->mDecType; + nexp->mDecValue = tdec; + + exp = nexp; + } } } else { + Expression* thisExp = nullptr; + if (exp->mDecType->mType == DT_TYPE_POINTER && exp->mDecType->mBase->mType == DT_TYPE_FUNCTION) { } @@ -2490,8 +6539,38 @@ Expression* Parser::ParsePostfixExpression(bool lhs) } else { - mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Function expected for call"); - exp->mDecType = TheVoidFunctionTypeDeclaration; + Declaration* tdec = exp->mDecType; + while (tdec->mType == DT_TYPE_REFERENCE || tdec->mType == DT_TYPE_RVALUEREF) + tdec = tdec->mBase; + + if (tdec->mType == DT_TYPE_STRUCT && tdec->mScope) + { + const Ident* opident = Ident::Unique("operator()"); + + Declaration* mdec = tdec->mScope->Lookup(opident); + if (mdec) + { + thisExp = new Expression(exp->mLocation, EX_PREFIX); + thisExp->mToken = TK_BINARY_AND; + thisExp->mLeft = exp; + thisExp->mDecType = exp->mDecType->BuildPointer(exp->mLocation); + + exp = new Expression(exp->mLocation, EX_CONSTANT); + exp->mDecValue = mdec; + exp->mDecType = mdec->mBase; + } + else + { + mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Function expected for call"); + exp->mDecType = TheVoidFunctionTypeDeclaration; + } + } + else + { + mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Function expected for call"); + exp->mDecType = TheVoidFunctionTypeDeclaration; + } + } mScanner->NextToken(); @@ -2503,7 +6582,7 @@ Expression* Parser::ParsePostfixExpression(bool lhs) nexp->mLeft = exp; if (mScanner->mToken != TK_CLOSE_PARENTHESIS) { - nexp->mRight = ParseListExpression(); + nexp->mRight = ParseListExpression(false); ConsumeToken(TK_CLOSE_PARENTHESIS); } else @@ -2512,10 +6591,56 @@ Expression* Parser::ParsePostfixExpression(bool lhs) mScanner->NextToken(); } - ResolveOverloadCall(exp, nexp->mRight); + bool parentCall = false; + if (exp->mDecType->mFlags & DTF_FUNC_THIS) + { + if (thisExp) + { + if (nexp->mRight) + { + Expression* lexp = new Expression(nexp->mLocation, EX_LIST); + lexp->mLeft = thisExp; + lexp->mRight = nexp->mRight; + nexp->mRight = lexp; + } + else + nexp->mRight = thisExp; + } + else + { + if (mThisPointer && mThisPointer->mType == DT_ARGUMENT) + { + Expression* texp = new Expression(mScanner->mLocation, EX_VARIABLE); + texp->mDecType = mThisPointer->mBase; + texp->mDecValue = mThisPointer; + + if (nexp->mRight) + { + Expression* lexp = new Expression(nexp->mLocation, EX_LIST); + lexp->mLeft = texp; + lexp->mRight = nexp->mRight; + nexp->mRight = lexp; + } + else + nexp->mRight = texp; + + parentCall = true; + } + } + } + + nexp = ResolveOverloadCall(nexp); nexp->mDecType = exp->mDecType->mBase; - exp = nexp; + if (nexp->mLeft->mDecType->mFlags & DTF_VIRTUAL) + { + if (parentCall) + exp->mDecType->mFlags |= DTF_STACKCALL; + else + nexp->mType = EX_VCALL; + } + + exp = nexp->ConstantFold(mErrors, mDataSection); } } else if (mScanner->mToken == TK_INC || mScanner->mToken == TK_DEC) @@ -2524,12 +6649,25 @@ Expression* Parser::ParsePostfixExpression(bool lhs) nexp->mToken = mScanner->mToken; nexp->mLeft = exp; nexp->mDecType = exp->mDecType; - exp = nexp; mScanner->NextToken(); + exp = CheckOperatorOverload(nexp); } else if (mScanner->mToken == TK_ARROW) { mScanner->NextToken(); + while (exp->mDecType->mType != DT_TYPE_POINTER) + { + Expression* dexp = new Expression(mScanner->mLocation, EX_PREFIX); + dexp->mToken = TK_ARROW; + dexp->mDecType = TheVoidPointerTypeDeclaration; + dexp->mLeft = exp; + + Expression* oexp = CheckOperatorOverload(dexp); + if (oexp == dexp) + break; + exp = oexp; + } + if (exp->mDecType->mType == DT_TYPE_POINTER) { Expression * dexp = new Expression(mScanner->mLocation, EX_PREFIX); @@ -2588,11 +6726,245 @@ Expression* Parser::ParsePostfixExpression(bool lhs) } +Expression* Parser::ParseNewOperator(void) +{ + Expression* nexp; + + nexp = new Expression(mScanner->mLocation, EX_PREFIX); + nexp->mToken = TK_NEW; + mScanner->NextToken(); + + bool placement = false; + + // Check for placement new + if (ConsumeTokenIf(TK_OPEN_PARENTHESIS)) + { + nexp->mType = EX_TYPECAST; + nexp->mLeft = ParseExpression(false); + + ConsumeToken(TK_CLOSE_PARENTHESIS); + placement = true; + } + + Declaration* dec = ParseBaseTypeDeclaration(0, true); + + Declaration* sconst = new Declaration(mScanner->mLocation, DT_CONST_INTEGER); + sconst->mBase = TheUnsignedIntTypeDeclaration; + sconst->mInteger = dec->mSize; + + Expression* sexp = new Expression(mScanner->mLocation, EX_CONSTANT); + sexp->mDecValue = sconst; + sexp->mDecType = TheUnsignedIntTypeDeclaration; + + Declaration* nudec = new Declaration(mScanner->mLocation, DT_CONST_ADDRESS); + nudec->mBase = TheVoidPointerTypeDeclaration; + nudec->mInteger = 0; + Expression* nuexp = new Expression(mScanner->mLocation, EX_CONSTANT); + nuexp->mDecValue = nudec; + nuexp->mDecType = nudec->mBase; + + if (ConsumeTokenIf(TK_OPEN_BRACKET)) + { + Expression* mexp = new Expression(mScanner->mLocation, EX_BINARY); + mexp->mToken = TK_MUL; + mexp->mLeft = sexp; + mexp->mRight = ParseExpression(false); + mexp->mDecType = TheUnsignedIntTypeDeclaration; + ConsumeToken(TK_CLOSE_BRACKET); + + if (!placement) + nexp->mLeft = mexp; + + nexp->mDecType = dec->BuildPointer(mScanner->mLocation); + + if (dec->mVectorConstructor) + { + Declaration* vdec = new Declaration(mScanner->mLocation, DT_VARIABLE); + vdec->mVarIndex = mLocalIndex++; + vdec->mBase = nexp->mDecType; + vdec->mSize = 2; + + Expression* vexp = new Expression(mScanner->mLocation, EX_VARIABLE); + vexp->mDecType = vdec->mBase; + vexp->mDecValue = vdec; + + Expression* iexp = new Expression(mScanner->mLocation, EX_INITIALIZATION); + iexp->mToken = TK_ASSIGN; + iexp->mLeft = vexp; + iexp->mRight = nexp; + iexp->mDecType = nexp->mDecType; + + Expression* csexp = new Expression(mScanner->mLocation, EX_TYPECAST); + csexp->mLeft = vexp; + csexp->mDecType = nexp->mDecType->BuildPointer(mScanner->mLocation); + + Declaration* mdec = dec->mVectorConstructor; + + Expression* pexp = new Expression(mScanner->mLocation, EX_LIST); + pexp->mLeft = vexp; + pexp->mRight = new Expression(mScanner->mLocation, EX_INDEX); + pexp->mRight->mLeft = csexp; + pexp->mRight->mRight = new Expression(mScanner->mLocation, EX_CONSTANT); + pexp->mRight->mRight->mDecType = TheSignedIntTypeDeclaration; + pexp->mRight->mRight->mDecValue = new Declaration(mScanner->mLocation, DT_CONST_INTEGER); + pexp->mRight->mRight->mDecValue->mBase = TheSignedIntTypeDeclaration; + pexp->mRight->mRight->mDecValue->mInteger = -1; + + Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); + cexp->mDecValue = mdec; + cexp->mDecType = cexp->mDecValue->mBase; + + Expression* dexp = new Expression(mScanner->mLocation, EX_CALL); + dexp->mLeft = cexp; + dexp->mRight = pexp; + + Expression* coexp = nexp = new Expression(mScanner->mLocation, EX_CONDITIONAL); + coexp->mLeft = new Expression(mScanner->mLocation, EX_RELATIONAL); + coexp->mLeft->mDecType = TheBoolTypeDeclaration; + coexp->mLeft->mToken = TK_EQUAL; + coexp->mLeft->mLeft = vexp; + coexp->mLeft->mRight = nuexp; + coexp->mRight = new Expression(mScanner->mLocation, EX_LIST); + coexp->mRight->mLeft = vexp; + coexp->mRight->mRight = new Expression(mScanner->mLocation, EX_SEQUENCE); + coexp->mRight->mRight->mLeft = dexp; + coexp->mRight->mRight->mRight = vexp; + coexp->mDecType = vexp->mDecType; + + Expression* sexp = new Expression(mScanner->mLocation, EX_SEQUENCE); + sexp->mLeft = iexp; + sexp->mRight = coexp; + sexp->mDecType = coexp->mDecType; + + nexp = sexp; + } + } + else + { + if (!placement) + nexp->mLeft = sexp; + + nexp->mDecType = dec->BuildPointer(mScanner->mLocation); + + if (mScanner->mToken == TK_OPEN_PARENTHESIS || dec->mDefaultConstructor) + { + Declaration* mdec = dec->mDefaultConstructor; + Expression* pexp = nullptr; + + if (ConsumeTokenIf(TK_OPEN_PARENTHESIS)) + { + if (!ConsumeTokenIf(TK_CLOSE_PARENTHESIS)) + { + pexp = ParseListExpression(false); + ConsumeToken(TK_CLOSE_PARENTHESIS); + } + } + + if (dec->mType == DT_TYPE_STRUCT) + { + mdec = dec->mScope ? dec->mScope->Lookup(dec->mIdent->PreMangle("+")) : nullptr; + if (pexp && pexp->mType != EX_LIST) + { + if (pexp->mDecType->IsSame(dec)) + mdec = dec->mCopyConstructor; + else if (pexp->mDecType->mType == DT_TYPE_REFERENCE && pexp->mDecType->mBase->IsSame(dec)) + mdec = dec->mCopyConstructor; + else if (pexp->mDecType->mType == DT_TYPE_RVALUEREF && pexp->mDecType->mBase->IsSame(dec)) + mdec = dec->mMoveConstructor; + } + } + else + mdec = nullptr; + + if (mdec) + { + Declaration* vdec = new Declaration(mScanner->mLocation, DT_VARIABLE); + vdec->mVarIndex = mLocalIndex++; + vdec->mBase = nexp->mDecType; + vdec->mSize = 2; + + Expression* vexp = new Expression(mScanner->mLocation, EX_VARIABLE); + vexp->mDecType = vdec->mBase; + vexp->mDecValue = vdec; + + Expression* iexp = new Expression(mScanner->mLocation, EX_INITIALIZATION); + iexp->mToken = TK_ASSIGN; + iexp->mLeft = vexp; + iexp->mRight = nexp; + iexp->mDecType = nexp->mDecType; + + Expression* lexp = new Expression(mScanner->mLocation, EX_LIST); + lexp->mLeft = vexp; + lexp->mRight = pexp; + pexp = lexp; + + Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); + cexp->mDecValue = mdec; + cexp->mDecType = cexp->mDecValue->mBase; + + Expression* dexp = new Expression(mScanner->mLocation, EX_CALL); + dexp->mLeft = cexp; + dexp->mRight = pexp; + + dexp = ResolveOverloadCall(dexp); + + Expression* sexp = new Expression(mScanner->mLocation, EX_SEQUENCE); + + sexp->mLeft = dexp; + sexp->mRight = vexp; + sexp->mDecType = vexp->mDecType; + + Expression* coexp = nexp = new Expression(mScanner->mLocation, EX_CONDITIONAL); + coexp->mLeft = new Expression(mScanner->mLocation, EX_RELATIONAL); + coexp->mLeft->mDecType = TheBoolTypeDeclaration; + coexp->mLeft->mToken = TK_EQUAL; + coexp->mLeft->mLeft = vexp; + coexp->mLeft->mRight = nuexp; + coexp->mRight = new Expression(mScanner->mLocation, EX_LIST); + coexp->mRight->mLeft = vexp; + coexp->mRight->mRight = new Expression(mScanner->mLocation, EX_SEQUENCE); + coexp->mRight->mRight->mLeft = dexp; + coexp->mRight->mRight->mRight = vexp; + coexp->mDecType = vexp->mDecType; + + nexp = new Expression(mScanner->mLocation, EX_SEQUENCE); + nexp->mLeft = iexp; + nexp->mRight = coexp; + nexp->mDecType = coexp->mDecType; + } + else if (pexp && pexp->mType != EX_LIST) + { + Expression* dexp = new Expression(mScanner->mLocation, EX_PREFIX); + dexp->mToken = TK_MUL; + dexp->mLeft = nexp; + dexp->mDecType = nexp->mDecType->mBase; + + Expression* iexp = new Expression(mScanner->mLocation, EX_INITIALIZATION); + iexp->mToken = TK_ASSIGN; + iexp->mLeft = dexp; + iexp->mRight = pexp; + iexp->mDecType = nexp->mDecType; + + nexp = new Expression(mScanner->mLocation, EX_PREFIX); + nexp->mToken = TK_BINARY_AND; + nexp->mDecType = nexp->mDecType; + nexp->mLeft = iexp; + } + else if (pexp) + { + mErrors->Error(mScanner->mLocation, ERRO_NO_MATCHING_FUNCTION_CALL, "No matching constructor", dec->mIdent); + } + } + } + + return nexp; +} + Expression* Parser::ParsePrefixExpression(bool lhs) { if (mScanner->mToken == TK_SUB || mScanner->mToken == TK_BINARY_NOT || mScanner->mToken == TK_LOGICAL_NOT || mScanner->mToken == TK_MUL || mScanner->mToken == TK_INC || mScanner->mToken == TK_DEC || mScanner->mToken == TK_BINARY_AND || - mScanner->mToken == TK_BANKOF) + mScanner->mToken == TK_BANKOF || mScanner->mToken == TK_NEW || mScanner->mToken == TK_DELETE) { Expression* nexp; if (mScanner->mToken == TK_LOGICAL_NOT) @@ -2600,6 +6972,8 @@ Expression* Parser::ParsePrefixExpression(bool lhs) mScanner->NextToken(); nexp = ParsePrefixExpression(false); nexp = nexp->LogicInvertExpression(); + nexp = CheckOperatorOverload(nexp); + } else if (mScanner->mToken == TK_INC || mScanner->mToken == TK_DEC) { @@ -2608,6 +6982,104 @@ Expression* Parser::ParsePrefixExpression(bool lhs) mScanner->NextToken(); nexp->mLeft = ParsePrefixExpression(false);; nexp->mDecType = nexp->mLeft->mDecType; + nexp = CheckOperatorOverload(nexp); + } + else if (mScanner->mToken == TK_NEW) + { + nexp = ParseNewOperator(); + } + else if (mScanner->mToken == TK_DELETE) + { + bool vdelete = false; + + mScanner->NextToken(); + if (ConsumeTokenIf(TK_OPEN_BRACKET)) + { + ConsumeToken(TK_CLOSE_BRACKET); + vdelete = true; + } + + Declaration* nudec = new Declaration(mScanner->mLocation, DT_CONST_ADDRESS); + nudec->mBase = TheVoidPointerTypeDeclaration; + nudec->mInteger = 0; + Expression* nuexp = new Expression(mScanner->mLocation, EX_CONSTANT); + nuexp->mDecValue = nudec; + nuexp->mDecType = nudec->mBase; + + nexp = new Expression(mScanner->mLocation, EX_PREFIX); + nexp->mToken = TK_DELETE; + nexp->mLeft = ParsePrefixExpression(false); + nexp->mDecType = TheVoidTypeDeclaration; + if (nexp->mLeft->mDecType->mType == DT_TYPE_POINTER) + { + Declaration* dec = nexp->mLeft->mDecType->mBase; + if (dec->mDestructor) + { + Declaration* vdec = new Declaration(mScanner->mLocation, DT_VARIABLE); + vdec->mVarIndex = mLocalIndex++; + vdec->mBase = nexp->mLeft->mDecType; + vdec->mSize = 2; + + Expression* vexp = new Expression(mScanner->mLocation, EX_VARIABLE); + vexp->mDecType = vdec->mBase; + vexp->mDecValue = vdec; + + Expression* iexp = new Expression(mScanner->mLocation, EX_INITIALIZATION); + iexp->mToken = TK_ASSIGN; + iexp->mLeft = vexp; + iexp->mRight = nexp->mLeft; + iexp->mDecType = nexp->mLeft->mDecType; + + Declaration* mdec = dec->mDestructor; + Expression* pexp = vexp; + + if (vdelete) + { + mdec = dec->mVectorDestructor; + + Expression* csexp = new Expression(mScanner->mLocation, EX_TYPECAST); + csexp->mLeft = vexp; + csexp->mDecType = nexp->mLeft->mDecType->BuildPointer(mScanner->mLocation); + + pexp = new Expression(mScanner->mLocation, EX_LIST); + pexp->mLeft = vexp; + pexp->mRight = new Expression(mScanner->mLocation, EX_INDEX); + pexp->mRight->mLeft = csexp; + pexp->mRight->mRight = new Expression(mScanner->mLocation, EX_CONSTANT); + pexp->mRight->mRight->mDecType = TheSignedIntTypeDeclaration; + pexp->mRight->mRight->mDecValue = new Declaration(mScanner->mLocation, DT_CONST_INTEGER); + pexp->mRight->mRight->mDecValue->mBase = TheSignedIntTypeDeclaration; + pexp->mRight->mRight->mDecValue->mInteger = -1; + } + + Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); + cexp->mDecValue = mdec; + cexp->mDecType = cexp->mDecValue->mBase; + + Expression* dexp = new Expression(mScanner->mLocation, EX_CALL); + dexp->mLeft = cexp; + dexp->mRight = pexp; + + if (cexp->mDecValue->mBase->mFlags & DTF_VIRTUAL) + dexp->mType = EX_VCALL; + + Expression* sexp = new Expression(mScanner->mLocation, EX_SEQUENCE); + sexp->mLeft = iexp; + sexp->mRight = new Expression(mScanner->mLocation, EX_IF); + sexp->mRight->mLeft = new Expression(mScanner->mLocation, EX_RELATIONAL); + sexp->mRight->mLeft->mDecType = TheBoolTypeDeclaration; + sexp->mRight->mLeft->mToken = TK_NOT_EQUAL; + sexp->mRight->mLeft->mLeft = vexp; + sexp->mRight->mLeft->mRight = nuexp; + sexp->mRight->mRight = new Expression(mScanner->mLocation, EX_LIST); + sexp->mRight->mRight->mLeft = new Expression(mScanner->mLocation, EX_SEQUENCE); + sexp->mRight->mRight->mLeft->mLeft = dexp; + sexp->mRight->mRight->mLeft->mRight = nexp; + nexp->mLeft = iexp; + + nexp = sexp; + } + } } else { @@ -2624,6 +7096,10 @@ Expression* Parser::ParsePrefixExpression(bool lhs) return nexp->mLeft; nexp->mDecType = nexp->mLeft->mDecType->mBase; } + else if ((mCompilerOptions & COPT_CPLUSPLUS) && nexp->mLeft->mDecType->mType == DT_TYPE_STRUCT) + { + nexp->mDecType = nexp->mLeft->mDecType; + } else { mErrors->Error(nexp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Pointer or array type expected"); @@ -2632,11 +7108,7 @@ Expression* Parser::ParsePrefixExpression(bool lhs) } else if (nexp->mToken == TK_BINARY_AND) { - Declaration* pdec = new Declaration(nexp->mLocation, DT_TYPE_POINTER); - pdec->mBase = nexp->mLeft->mDecType; - pdec->mSize = 2; - pdec->mFlags |= DTF_DEFINED; - nexp->mDecType = pdec; + nexp->mDecType = nexp->mLeft->mDecType->BuildAddressOfPointer(); } else if (nexp->mToken == TK_BANKOF) { @@ -2645,7 +7117,8 @@ Expression* Parser::ParsePrefixExpression(bool lhs) else nexp->mDecType = nexp->mLeft->mDecType; } - return nexp->ConstantFold(mErrors); + nexp = CheckOperatorOverload(nexp); + return nexp->ConstantFold(mErrors, mDataSection); } else return ParsePostfixExpression(lhs); @@ -2661,6 +7134,10 @@ Expression* Parser::ParseMulExpression(bool lhs) nexp->mToken = mScanner->mToken; nexp->mLeft = exp; mScanner->NextToken(); + + if (ConsumeTokenIf(TK_ELLIPSIS)) + return ParseBinaryFoldExpression(nexp); + nexp->mRight = ParsePrefixExpression(false); if (nexp->mLeft->mDecType->mType == DT_TYPE_FLOAT || nexp->mRight->mDecType->mType == DT_TYPE_FLOAT) @@ -2668,12 +7145,200 @@ Expression* Parser::ParseMulExpression(bool lhs) else nexp->mDecType = exp->mDecType; - exp = nexp->ConstantFold(mErrors); + exp = CheckOperatorOverload(nexp); + + exp = exp->ConstantFold(mErrors, mDataSection); } return exp; } +Expression* Parser::FindPackExpression(Expression* exp) +{ + if (exp->mType == EX_PACK) + return exp; + + if (exp->mLeft) + { + Expression* nexp = FindPackExpression(exp->mLeft); + if (nexp) + return nexp; + } + + if (exp->mRight) + { + Expression* nexp = FindPackExpression(exp->mRight); + if (nexp) + return nexp; + } + + return nullptr; +} + +Expression* Parser::ExpandPackExpression(Expression* exp, Expression* pack, Expression* item) +{ + if (exp == pack) + return item; + + Expression* left = exp->mLeft ? ExpandPackExpression(exp->mLeft, pack, item) : nullptr; + Expression* right = exp->mRight ? ExpandPackExpression(exp->mRight, pack, item) : nullptr; + + if (left == exp->mLeft && right == exp->mRight) + return exp; + + Expression* nexp = new Expression(exp->mLocation, exp->mType); + nexp->mToken = exp->mToken; + nexp->mLeft = left; + nexp->mRight = right; + nexp->mDecValue = exp->mDecValue; + nexp->mDecType = exp->mDecType; + + if (nexp->mType == EX_CALL) + nexp = ResolveOverloadCall(nexp); + + return nexp; +} + +Declaration* Parser::OperatorResultType(Expression* exp) +{ + if (exp->mType == EX_BINARY) + { + Declaration* lt = exp->mLeft->mDecType->NonRefBase(); + Declaration* rt = exp->mRight->mDecType->NonRefBase(); + + switch (exp->mToken) + { + case TK_MUL: + case TK_DIV: + case TK_MOD: + if (lt->mType == DT_TYPE_FLOAT || rt->mType == DT_TYPE_FLOAT) + return TheFloatTypeDeclaration; + else + return lt; + + case TK_ADD: + case TK_SUB: + if (lt->IsIndexed() && rt->IsIntegerType()) + return lt->BuildArrayPointer(); + else if (rt->IsIndexed() && lt->IsIntegerType()) + return rt->BuildArrayPointer(); + else if (lt->mType == DT_TYPE_FLOAT || rt->mType == DT_TYPE_FLOAT) + return TheFloatTypeDeclaration; + else if (lt->IsIndexed() && rt->IsIndexed()) + return TheSignedIntTypeDeclaration; + else + return lt; + + case TK_LEFT_SHIFT: + case TK_RIGHT_SHIFT: + case TK_BINARY_AND: + case TK_BINARY_OR: + case TK_BINARY_XOR: + return lt; + } + } + else if (exp->mType == EX_RELATIONAL || exp->mType == EX_LOGICAL_AND || exp->mType == EX_LOGICAL_OR || exp->mType == EX_LOGICAL_NOT) + return TheBoolTypeDeclaration; + else if (exp->mType == EX_LIST) + return exp->mRight->mDecType; + + return exp->mLeft->mDecType; +} + +Expression* Parser::ParseBinaryFoldExpression(Expression * exp) +{ + if (ConsumeTokenIf(exp->mToken)) + exp->mRight = ParsePrefixExpression(false); + + if (exp->mLeft) + { + Expression* pexp = FindPackExpression(exp->mLeft); + if (pexp) + { + Declaration* dpack = pexp->mDecValue->mParams; + Expression* nexp = exp->mRight; + if (dpack) + { + dpack = dpack->Last(); + if (!nexp) + { + Expression* vexp = new Expression(exp->mLocation, EX_VARIABLE); + vexp->mDecType = dpack->mBase; + vexp->mDecValue = dpack; + nexp = ExpandPackExpression(exp->mLeft, pexp, vexp); + dpack = dpack->mPrev; + } + + while (dpack) + { + Expression* vexp = new Expression(exp->mLocation, EX_VARIABLE); + vexp->mDecType = dpack->mBase; + vexp->mDecValue = dpack; + + Expression* oexp = new Expression(exp->mLocation, exp->mType); + oexp->mToken = exp->mToken; + oexp->mLeft = ExpandPackExpression(exp->mLeft, pexp, vexp); + oexp->mRight = nexp; + oexp->mDecType = OperatorResultType(oexp); + + nexp = CheckOperatorOverload(oexp); + + nexp = nexp->ConstantFold(mErrors, mDataSection); + + dpack = dpack->mPrev; + } + } + + return nexp; + } + } + + if (exp->mRight) + { + Expression* pexp = FindPackExpression(exp->mRight); + if (pexp) + { + Declaration* dpack = pexp->mDecValue->mParams; + Expression* nexp = exp->mLeft; + if (dpack) + { + if (!nexp) + { + Expression* vexp = new Expression(exp->mLocation, EX_VARIABLE); + vexp->mDecType = dpack->mBase; + vexp->mDecValue = dpack; + nexp = ExpandPackExpression(exp->mRight, pexp, vexp); + dpack = dpack->mNext; + } + + while (dpack) + { + Expression* vexp = new Expression(exp->mLocation, EX_VARIABLE); + vexp->mDecType = dpack->mBase; + vexp->mDecValue = dpack; + + Expression* oexp = new Expression(exp->mLocation, exp->mType); + oexp->mToken = exp->mToken; + oexp->mLeft = nexp; + oexp->mRight = ExpandPackExpression(exp->mRight, pexp, vexp); + oexp->mDecType = OperatorResultType(oexp); + + nexp = CheckOperatorOverload(oexp); + + nexp = nexp->ConstantFold(mErrors, mDataSection); + + dpack = dpack->mNext; + } + } + + return nexp; + } + } + + mErrors->Error(exp->mLocation, EERR_INVALID_FOLD_EXPRESSION, "No parameter pack"); + return exp; +} + Expression* Parser::ParseAddExpression(bool lhs) { Expression* exp = ParseMulExpression(lhs); @@ -2684,6 +7349,10 @@ Expression* Parser::ParseAddExpression(bool lhs) nexp->mToken = mScanner->mToken; nexp->mLeft = exp; mScanner->NextToken(); + + if (ConsumeTokenIf(TK_ELLIPSIS)) + return ParseBinaryFoldExpression(nexp); + nexp->mRight = ParseMulExpression(false); if (nexp->mLeft->mDecType->mType == DT_TYPE_POINTER && nexp->mRight->mDecType->IsIntegerType()) nexp->mDecType = nexp->mLeft->mDecType; @@ -2714,7 +7383,9 @@ Expression* Parser::ParseAddExpression(bool lhs) else nexp->mDecType = exp->mDecType; - exp = nexp->ConstantFold(mErrors); + exp = CheckOperatorOverload(nexp); + + exp = exp->ConstantFold(mErrors, mDataSection); } return exp; @@ -2730,10 +7401,16 @@ Expression* Parser::ParseShiftExpression(bool lhs) nexp->mToken = mScanner->mToken; nexp->mLeft = exp; mScanner->NextToken(); + + if (ConsumeTokenIf(TK_ELLIPSIS)) + return ParseBinaryFoldExpression(nexp); + nexp->mRight = ParseAddExpression(false); nexp->mDecType = exp->mDecType; - exp = nexp->ConstantFold(mErrors); + exp = nexp->ConstantFold(mErrors, mDataSection); + + exp = CheckOperatorOverload(exp); } return exp; @@ -2749,10 +7426,16 @@ Expression* Parser::ParseRelationalExpression(bool lhs) nexp->mToken = mScanner->mToken; nexp->mLeft = exp; mScanner->NextToken(); + + if (ConsumeTokenIf(TK_ELLIPSIS)) + return ParseBinaryFoldExpression(nexp); + nexp->mRight = ParseShiftExpression(false); nexp->mDecType = TheBoolTypeDeclaration; - exp = nexp->ConstantFold(mErrors); + exp = nexp->ConstantFold(mErrors, mDataSection); + + exp = CheckOperatorOverload(exp); } return exp; @@ -2771,7 +7454,9 @@ Expression* Parser::ParseBinaryAndExpression(bool lhs) nexp->mRight = ParseRelationalExpression(false); nexp->mDecType = exp->mDecType; - exp = nexp->ConstantFold(mErrors); + exp = nexp->ConstantFold(mErrors, mDataSection); + + exp = CheckOperatorOverload(exp); } return exp; @@ -2787,9 +7472,15 @@ Expression* Parser::ParseBinaryXorExpression(bool lhs) nexp->mToken = mScanner->mToken; nexp->mLeft = exp; mScanner->NextToken(); + + if (ConsumeTokenIf(TK_ELLIPSIS)) + return ParseBinaryFoldExpression(nexp); + nexp->mRight = ParseBinaryAndExpression(false); nexp->mDecType = exp->mDecType; - exp = nexp->ConstantFold(mErrors); + exp = nexp->ConstantFold(mErrors, mDataSection); + + exp = CheckOperatorOverload(exp); } return exp; @@ -2805,9 +7496,15 @@ Expression* Parser::ParseBinaryOrExpression(bool lhs) nexp->mToken = mScanner->mToken; nexp->mLeft = exp; mScanner->NextToken(); + + if (ConsumeTokenIf(TK_ELLIPSIS)) + return ParseBinaryFoldExpression(nexp); + nexp->mRight = ParseBinaryXorExpression(false); nexp->mDecType = exp->mDecType; - exp = nexp->ConstantFold(mErrors); + exp = nexp->ConstantFold(mErrors, mDataSection); + + exp = CheckOperatorOverload(exp); } return exp; @@ -2821,11 +7518,15 @@ Expression* Parser::ParseLogicAndExpression(bool lhs) { Expression* nexp = new Expression(mScanner->mLocation, EX_LOGICAL_AND); nexp->mToken = mScanner->mToken; - nexp->mLeft = exp; + nexp->mLeft = CoerceExpression(exp, TheBoolTypeDeclaration); mScanner->NextToken(); - nexp->mRight = ParseBinaryOrExpression(false); + + if (ConsumeTokenIf(TK_ELLIPSIS)) + return ParseBinaryFoldExpression(nexp); + + nexp->mRight = CoerceExpression(ParseBinaryOrExpression(false), TheBoolTypeDeclaration); nexp->mDecType = TheBoolTypeDeclaration; - exp = nexp->ConstantFold(mErrors); + exp = nexp->ConstantFold(mErrors, mDataSection); } return exp; @@ -2839,11 +7540,15 @@ Expression* Parser::ParseLogicOrExpression(bool lhs) { Expression* nexp = new Expression(mScanner->mLocation, EX_LOGICAL_OR); nexp->mToken = mScanner->mToken; - nexp->mLeft = exp; + nexp->mLeft = CoerceExpression(exp, TheBoolTypeDeclaration); mScanner->NextToken(); - nexp->mRight = ParseLogicAndExpression(false); + + if (ConsumeTokenIf(TK_ELLIPSIS)) + return ParseBinaryFoldExpression(nexp); + + nexp->mRight = CoerceExpression(ParseLogicAndExpression(false), TheBoolTypeDeclaration); nexp->mDecType = TheBoolTypeDeclaration; - exp = nexp->ConstantFold(mErrors); + exp = nexp->ConstantFold(mErrors, mDataSection); } return exp; @@ -2856,7 +7561,7 @@ Expression* Parser::ParseConditionalExpression(bool lhs) if (mScanner->mToken == TK_QUESTIONMARK) { Expression* nexp = new Expression(mScanner->mLocation, EX_CONDITIONAL); - nexp->mLeft = exp; + nexp->mLeft = CoerceExpression(exp, TheBoolTypeDeclaration); mScanner->NextToken(); Expression* texp = new Expression(mScanner->mLocation, EX_SEQUENCE); nexp->mRight = texp; @@ -2866,7 +7571,7 @@ Expression* Parser::ParseConditionalExpression(bool lhs) texp->mRight = ParseConditionalExpression(false); nexp->mDecType = texp->mLeft->mDecType; - exp = nexp->ConstantFold(mErrors); + exp = nexp->ConstantFold(mErrors, mDataSection); } return exp; @@ -2874,7 +7579,7 @@ Expression* Parser::ParseConditionalExpression(bool lhs) Expression* Parser::ParseRExpression(void) { - return ParseConditionalExpression(false); + return ParseConditionalExpression(false)->ConstantFold(mErrors, mDataSection); } Expression* Parser::ParseParenthesisExpression(void) @@ -2894,6 +7599,583 @@ Expression* Parser::ParseParenthesisExpression(void) return exp; } +Expression* Parser::CheckOperatorOverload(Expression* exp) +{ + if (mCompilerOptions & COPT_CPLUSPLUS) + { + if (exp->mType == EX_ASSIGNMENT) + { + Declaration* tdec = exp->mLeft->mDecType; + while (tdec->mType == DT_TYPE_REFERENCE || tdec->mType == DT_TYPE_RVALUEREF) + tdec = tdec->mBase; + + if (tdec->mType == DT_TYPE_STRUCT) + { + const Ident* opident = nullptr; + switch (exp->mToken) + { + case TK_ASSIGN: + opident = Ident::Unique("operator="); + break; + case TK_ASSIGN_ADD: + opident = Ident::Unique("operator+="); + break; + case TK_ASSIGN_SUB: + opident = Ident::Unique("operator-="); + break; + case TK_ASSIGN_MUL: + opident = Ident::Unique("operator*="); + break; + case TK_ASSIGN_DIV: + opident = Ident::Unique("operator/="); + break; + case TK_ASSIGN_MOD: + opident = Ident::Unique("operator%="); + break; + case TK_ASSIGN_SHL: + opident = Ident::Unique("operator<<="); + break; + case TK_ASSIGN_SHR: + opident = Ident::Unique("operator>>="); + break; + case TK_ASSIGN_AND: + opident = Ident::Unique("operator&="); + break; + case TK_ASSIGN_XOR: + opident = Ident::Unique("operator^="); + break; + case TK_ASSIGN_OR: + opident = Ident::Unique("operator|="); + break; + } + + if (opident) + { + Expression* nexp2 = nullptr; + + Declaration* mdec2 = mScope->Lookup(opident); + if (mdec2) + { + nexp2 = new Expression(mScanner->mLocation, EX_CALL); + + nexp2->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT); + nexp2->mLeft->mDecType = mdec2->mBase; + nexp2->mLeft->mDecValue = mdec2; + + nexp2->mDecType = mdec2->mBase; + nexp2->mRight = new Expression(mScanner->mLocation, EX_LIST); + nexp2->mRight->mLeft = exp->mLeft; + nexp2->mRight->mRight = exp->mRight; + } + + Declaration* mdec = tdec->mScope->Lookup(opident); + if (mdec) + { + Expression * nexp = new Expression(mScanner->mLocation, EX_CALL); + + nexp->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT); + nexp->mLeft->mDecType = mdec->mBase; + nexp->mLeft->mDecValue = mdec; + + nexp->mDecType = mdec->mBase; + nexp->mRight = exp->mRight; + + Expression* texp = new Expression(nexp->mLocation, EX_PREFIX); + texp->mToken = TK_BINARY_AND; + texp->mLeft = exp->mLeft; + texp->mDecType = new Declaration(nexp->mLocation, DT_TYPE_POINTER); + texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + texp->mDecType->mBase = tdec; + texp->mDecType->mSize = 2; + + Expression* lexp = new Expression(nexp->mLocation, EX_LIST); + lexp->mLeft = texp->ConstantFold(mErrors, mDataSection); + lexp->mRight = nexp->mRight; + nexp->mRight = lexp; + + nexp = ResolveOverloadCall(nexp, nexp2); + nexp->mDecType = nexp->mLeft->mDecType->mBase; + + exp = nexp; + } + } + } + } + else if (exp->mType == EX_INITIALIZATION) + { + Declaration* tdec = exp->mLeft->mDecType; + if (tdec->mType == DT_TYPE_STRUCT && exp->mToken == TK_ASSIGN) + { + Declaration* fcons = tdec->mScope ? tdec->mScope->Lookup(tdec->mIdent->PreMangle("+"), SLEVEL_CLASS) : nullptr; + if (fcons) + { + Declaration* mtype = tdec->ToMutableType(); + + Expression* vexp = exp->mLeft; + + Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); + cexp->mDecValue = fcons; + cexp->mDecType = cexp->mDecValue->mBase; + + Expression* fexp = new Expression(mScanner->mLocation, EX_CALL); + fexp->mLeft = cexp; + fexp->mRight = exp->mRight; + + Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX); + texp->mToken = TK_BINARY_AND; + texp->mLeft = vexp; + texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER); + texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + texp->mDecType->mBase = mtype; + texp->mDecType->mSize = 2; + + if (fexp->mRight) + { + Expression* lexp = new Expression(mScanner->mLocation, EX_LIST); + lexp->mLeft = texp; + lexp->mRight = fexp->mRight; + fexp->mRight = lexp; + } + else + fexp->mRight = texp; + + fexp = ResolveOverloadCall(fexp); + + Expression* dexp = nullptr; + if (tdec->mDestructor) + { + Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); + cexp->mDecValue = tdec->mDestructor; + cexp->mDecType = cexp->mDecValue->mBase; + + dexp = new Expression(mScanner->mLocation, EX_CALL); + dexp->mLeft = cexp; + dexp->mRight = texp; + } + + Expression* nexp = new Expression(mScanner->mLocation, EX_CONSTRUCT); + + nexp->mLeft = new Expression(mScanner->mLocation, EX_LIST); + nexp->mLeft->mLeft = fexp; + nexp->mLeft->mRight = dexp; + + nexp->mRight = vexp; + nexp->mDecType = vexp->mDecType; + + exp = nexp; + } + } + } + else if (exp->mType == EX_INDEX) + { + Declaration* tdec = exp->mLeft->mDecType; + while (tdec->mType == DT_TYPE_REFERENCE || tdec->mType == DT_TYPE_RVALUEREF) + tdec = tdec->mBase; + + if (tdec->mType == DT_TYPE_STRUCT && tdec->mScope) + { + const Ident* opident = Ident::Unique("operator[]"); + + Declaration* mdec = tdec->mScope->Lookup(opident); + if (mdec) + { + Expression* nexp = new Expression(mScanner->mLocation, EX_CALL); + + nexp->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT); + nexp->mLeft->mDecType = mdec->mBase; + nexp->mLeft->mDecValue = mdec; + + nexp->mDecType = mdec->mBase; + nexp->mRight = exp->mRight; + + Expression* texp = new Expression(nexp->mLocation, EX_PREFIX); + texp->mToken = TK_BINARY_AND; + texp->mLeft = exp->mLeft; + texp->mDecType = new Declaration(nexp->mLocation, DT_TYPE_POINTER); + texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + texp->mDecType->mBase = tdec; + texp->mDecType->mSize = 2; + + Expression* lexp = new Expression(nexp->mLocation, EX_LIST); + lexp->mLeft = texp->ConstantFold(mErrors, mDataSection); + lexp->mRight = nexp->mRight; + nexp->mRight = lexp; + + nexp = ResolveOverloadCall(nexp); + nexp->mDecType = nexp->mLeft->mDecType->mBase; + + exp = nexp; + } + } + } + else if (exp->mType == EX_PREINCDEC) + { + const Ident* opident = nullptr; + switch (exp->mToken) + { + case TK_INC: + opident = Ident::Unique("operator++"); + break; + case TK_DEC: + opident = Ident::Unique("operator--"); + break; + } + + if (opident) + { + Declaration* tdec = exp->mLeft->mDecType; + if (tdec->mType == DT_TYPE_STRUCT && tdec->mScope) + { + Declaration* mdec = tdec->mScope->Lookup(opident); + if (mdec) + { + Expression* nexp = new Expression(mScanner->mLocation, EX_CALL); + + nexp->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT); + nexp->mLeft->mDecType = mdec->mBase; + nexp->mLeft->mDecValue = mdec; + + nexp->mDecType = mdec->mBase; + nexp->mRight = exp->mRight; + + Expression* texp = new Expression(nexp->mLocation, EX_PREFIX); + texp->mToken = TK_BINARY_AND; + texp->mLeft = exp->mLeft; + texp->mDecType = new Declaration(nexp->mLocation, DT_TYPE_POINTER); + texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + texp->mDecType->mBase = exp->mLeft->mDecType; + texp->mDecType->mSize = 2; + + nexp->mRight = texp->ConstantFold(mErrors, mDataSection); + + nexp = ResolveOverloadCall(nexp); + nexp->mDecType = nexp->mLeft->mDecType->mBase; + + exp = nexp; + } + } + } + } + else if (exp->mType == EX_POSTINCDEC) + { + const Ident* opident = nullptr; + switch (exp->mToken) + { + case TK_INC: + opident = Ident::Unique("operator++"); + break; + case TK_DEC: + opident = Ident::Unique("operator--"); + break; + } + + if (opident) + { + Declaration* tdec = exp->mLeft->mDecType; + if (tdec->mType == DT_TYPE_STRUCT) + { + Declaration* mdec = tdec->mScope->Lookup(opident); + if (mdec) + { + Expression* nexp = new Expression(mScanner->mLocation, EX_CALL); + + nexp->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT); + nexp->mLeft->mDecType = mdec->mBase; + nexp->mLeft->mDecValue = mdec; + + nexp->mDecType = mdec->mBase; + nexp->mRight = exp->mRight; + + Expression* texp = new Expression(nexp->mLocation, EX_PREFIX); + texp->mToken = TK_BINARY_AND; + texp->mLeft = exp->mLeft; + texp->mDecType = new Declaration(nexp->mLocation, DT_TYPE_POINTER); + texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + texp->mDecType->mBase = exp->mLeft->mDecType; + texp->mDecType->mSize = 2; + + Expression* lexp = new Expression(nexp->mLocation, EX_LIST); + lexp->mLeft = texp->ConstantFold(mErrors, mDataSection); + lexp->mRight = new Expression(nexp->mLocation, EX_CONSTANT); + lexp->mRight->mDecType = TheSignedIntTypeDeclaration; + lexp->mRight->mDecValue = new Declaration(nexp->mLocation, DT_CONST_INTEGER); + lexp->mRight->mDecValue->mBase = TheSignedIntTypeDeclaration; + nexp->mRight = lexp; + + nexp = ResolveOverloadCall(nexp); + nexp->mDecType = nexp->mLeft->mDecType->mBase; + + exp = nexp; + } + } + } + } + else if (exp->mType == EX_BINARY || exp->mType == EX_RELATIONAL) + { + const Ident* opident = nullptr; + switch (exp->mToken) + { + case TK_ADD: + opident = Ident::Unique("operator+"); + break; + case TK_SUB: + opident = Ident::Unique("operator-"); + break; + case TK_MUL: + opident = Ident::Unique("operator*"); + break; + case TK_DIV: + opident = Ident::Unique("operator/"); + break; + case TK_MOD: + opident = Ident::Unique("operator%"); + break; + case TK_BINARY_AND: + opident = Ident::Unique("operator&"); + break; + case TK_BINARY_OR: + opident = Ident::Unique("operator|"); + break; + case TK_BINARY_XOR: + opident = Ident::Unique("operator^"); + break; + case TK_LEFT_SHIFT: + opident = Ident::Unique("operator<<"); + break; + case TK_RIGHT_SHIFT: + opident = Ident::Unique("operator>>"); + break; + case TK_EQUAL: + opident = Ident::Unique("operator=="); + break; + case TK_NOT_EQUAL: + opident = Ident::Unique("operator!="); + break; + case TK_GREATER_THAN: + opident = Ident::Unique("operator>"); + break; + case TK_GREATER_EQUAL: + opident = Ident::Unique("operator>="); + break; + case TK_LESS_THAN: + opident = Ident::Unique("operator<"); + break; + case TK_LESS_EQUAL: + opident = Ident::Unique("operator<="); + break; + } + + if (opident) + { + Expression* nexp2 = nullptr; + + Declaration* mdec2 = mScope->Lookup(opident); + if (mdec2) + { + nexp2 = new Expression(mScanner->mLocation, EX_CALL); + + nexp2->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT); + nexp2->mLeft->mDecType = mdec2->mBase; + nexp2->mLeft->mDecValue = mdec2; + + nexp2->mDecType = mdec2->mBase; + nexp2->mRight = new Expression(mScanner->mLocation, EX_LIST); + nexp2->mRight->mLeft = exp->mLeft; + nexp2->mRight->mRight = exp->mRight; + } + + Declaration* tdec = exp->mLeft->mDecType; + while (tdec->mType == DT_TYPE_REFERENCE || tdec->mType == DT_TYPE_RVALUEREF) + tdec = tdec->mBase; + + if (tdec->mType == DT_TYPE_STRUCT) + { + Declaration* mdec = tdec->mScope->Lookup(opident); + if (mdec) + { + Expression* nexp = new Expression(mScanner->mLocation, EX_CALL); + + nexp->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT); + nexp->mLeft->mDecType = mdec->mBase; + nexp->mLeft->mDecValue = mdec; + + nexp->mDecType = mdec->mBase; + nexp->mRight = exp->mRight; + + Expression* texp = new Expression(nexp->mLocation, EX_PREFIX); + texp->mToken = TK_BINARY_AND; + texp->mLeft = exp->mLeft; + texp->mDecType = new Declaration(nexp->mLocation, DT_TYPE_POINTER); + texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + texp->mDecType->mBase = tdec; + texp->mDecType->mSize = 2; + + Expression* lexp = new Expression(nexp->mLocation, EX_LIST); + lexp->mLeft = texp->ConstantFold(mErrors, mDataSection); + lexp->mRight = nexp->mRight; + nexp->mRight = lexp; + + nexp = ResolveOverloadCall(nexp, nexp2); + nexp->mDecType = nexp->mLeft->mDecType->mBase; + + exp = nexp; + } + } + } + } + else if (exp->mType == EX_PREFIX) + { + const Ident* opident = nullptr; + switch (exp->mToken) + { + case TK_ADD: + opident = Ident::Unique("operator+"); + break; + case TK_SUB: + opident = Ident::Unique("operator-"); + break; + case TK_MUL: + opident = Ident::Unique("operator*"); + break; + case TK_BINARY_NOT: + opident = Ident::Unique("operator~"); + break; + case TK_ARROW: + opident = Ident::Unique("operator->"); + break; + } + + if (opident) + { + Declaration* tdec = exp->mLeft->mDecType; + while (tdec->mType == DT_TYPE_REFERENCE || tdec->mType == DT_TYPE_RVALUEREF) + tdec = tdec->mBase; + + if (tdec->mType == DT_TYPE_STRUCT) + { + Declaration* mdec = tdec->mScope->Lookup(opident); + if (mdec) + { + Expression* nexp = new Expression(mScanner->mLocation, EX_CALL); + + nexp->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT); + nexp->mLeft->mDecType = mdec->mBase; + nexp->mLeft->mDecValue = mdec; + + nexp->mDecType = mdec->mBase; + nexp->mRight = exp->mRight; + + Expression* texp = new Expression(nexp->mLocation, EX_PREFIX); + texp->mToken = TK_BINARY_AND; + texp->mLeft = exp->mLeft; + texp->mDecType = new Declaration(nexp->mLocation, DT_TYPE_POINTER); + texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + texp->mDecType->mBase = tdec; + texp->mDecType->mSize = 2; + + nexp->mRight = texp->ConstantFold(mErrors, mDataSection); + + nexp = ResolveOverloadCall(nexp); + nexp->mDecType = nexp->mLeft->mDecType->mBase; + + exp = nexp; + } + } + } + } + else if (exp->mType == EX_TYPECAST) + { + Declaration* tdec = exp->mLeft->mDecType; + if (exp->mLeft->mDecType) + { + while (tdec->mType == DT_TYPE_REFERENCE || tdec->mType == DT_TYPE_RVALUEREF) + tdec = tdec->mBase; + + if (tdec->mType == DT_TYPE_STRUCT) + { + Declaration* mdec = tdec->mScope->Lookup(Ident::Unique("(cast)")); + while (mdec && !mdec->mBase->mBase->IsSame(exp->mDecType)) + mdec = mdec->mNext; + while (!mdec && tdec->mBase && tdec->mBase->mBase) + { + tdec = tdec->mBase->mBase; + mdec = tdec->mScope->Lookup(Ident::Unique("(cast)")); + while (mdec && !mdec->mBase->mBase->IsSame(exp->mDecType)) + mdec = mdec->mNext; + } + + if (mdec) + { + Expression* nexp = new Expression(mScanner->mLocation, EX_CALL); + + nexp->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT); + nexp->mLeft->mDecType = mdec->mBase; + nexp->mLeft->mDecValue = mdec; + + nexp->mDecType = mdec->mBase; + nexp->mRight = exp->mRight; + + Expression* texp = new Expression(nexp->mLocation, EX_PREFIX); + texp->mToken = TK_BINARY_AND; + texp->mLeft = exp->mLeft; + texp->mDecType = new Declaration(nexp->mLocation, DT_TYPE_POINTER); + texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + texp->mDecType->mBase = tdec; + texp->mDecType->mSize = 2; + + nexp->mRight = texp->ConstantFold(mErrors, mDataSection); + + nexp = ResolveOverloadCall(nexp); + nexp->mDecType = nexp->mLeft->mDecType->mBase; + + exp = nexp; + } + } + } + } + else if (exp->mType == EX_LOGICAL_NOT) + { + const Ident* opident = Ident::Unique("operator!"); + Declaration* tdec = exp->mLeft->mDecType; + while (tdec->mType == DT_TYPE_REFERENCE || tdec->mType == DT_TYPE_RVALUEREF) + tdec = tdec->mBase; + + if (tdec->mType == DT_TYPE_STRUCT) + { + Declaration* mdec = tdec->mScope->Lookup(opident); + if (mdec) + { + Expression* nexp = new Expression(mScanner->mLocation, EX_CALL); + + nexp->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT); + nexp->mLeft->mDecType = mdec->mBase; + nexp->mLeft->mDecValue = mdec; + + nexp->mDecType = mdec->mBase; + nexp->mRight = exp->mRight; + + Expression* texp = new Expression(nexp->mLocation, EX_PREFIX); + texp->mToken = TK_BINARY_AND; + texp->mLeft = exp->mLeft; + texp->mDecType = new Declaration(nexp->mLocation, DT_TYPE_POINTER); + texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + texp->mDecType->mBase = tdec; + texp->mDecType->mSize = 2; + + nexp->mRight = texp->ConstantFold(mErrors, mDataSection); + + nexp = ResolveOverloadCall(nexp); + nexp->mDecType = nexp->mLeft->mDecType->mBase; + + exp = nexp; + } + } + } + } + + return exp; +} + Expression* Parser::ParseAssignmentExpression(bool lhs) { Expression* exp = ParseConditionalExpression(lhs); @@ -2906,7 +8188,9 @@ Expression* Parser::ParseAssignmentExpression(bool lhs) mScanner->NextToken(); nexp->mRight = ParseAssignmentExpression(false); nexp->mDecType = exp->mDecType; - exp = nexp; + + exp = CheckOperatorOverload(nexp); + assert(exp->mDecType); } @@ -2918,16 +8202,97 @@ Expression* Parser::ParseExpression(bool lhs) return ParseAssignmentExpression(lhs); } -Expression* Parser::ParseListExpression(void) +Expression* Parser::ExpandArgumentPack(Expression* exp, Declaration* dec) { - Expression* exp = ParseExpression(true); - if (mScanner->mToken == TK_COMMA) + Expression* vex = new Expression(exp->mLocation, EX_VARIABLE); + vex->mDecType = dec->mBase; + vex->mDecValue = dec; + + if (dec->mNext) + { + Expression* lex = new Expression(exp->mLocation, EX_LIST); + lex->mToken = TK_COMMA; + lex->mLeft = vex; + lex->mRight = ExpandArgumentPack(exp, dec->mNext); + return lex; + } + else + return vex; +} + +Expression* Parser::ParseListExpression(bool lhs) +{ + if (ConsumeTokenIf(TK_ELLIPSIS)) + { + ExpressionType et = EX_ERROR; + switch (mScanner->mToken) + { + case TK_MUL: + case TK_DIV: + case TK_MOD: + case TK_ADD: + case TK_SUB: + case TK_LEFT_SHIFT: + case TK_RIGHT_SHIFT: + case TK_BINARY_AND: + case TK_BINARY_OR: + case TK_BINARY_XOR: + et = EX_BINARY; + break; + case TK_EQUAL: + case TK_NOT_EQUAL: + case TK_GREATER_THAN: + case TK_GREATER_EQUAL: + case TK_LESS_THAN: + case TK_LESS_EQUAL: + et = EX_RELATIONAL; + break; + case TK_LOGICAL_AND: + et = EX_LOGICAL_AND; + break; + case TK_LOGICAL_OR: + et = EX_LOGICAL_OR; + break; + case TK_LOGICAL_NOT: + et = EX_LOGICAL_NOT; + break; + case TK_COMMA: + et = EX_LIST; + break; + } + + if (et == EX_ERROR) + mErrors->Error(mScanner->mLocation, EERR_INVALID_FOLD_EXPRESSION, "Invalid operator in fold expression"); + + Expression* nexp = new Expression(mScanner->mLocation, et); + nexp->mToken = mScanner->mToken; + mScanner->NextToken(); + nexp->mRight = ParseExpression(false); + return ParseBinaryFoldExpression(nexp); + } + + Expression* exp = ParseExpression(lhs); + if (exp->mType == EX_PACK) + { + if (ConsumeTokenIf(TK_ELLIPSIS)) + { + if (exp->mDecValue->mParams) + exp = ExpandArgumentPack(exp, exp->mDecValue->mParams); + else + exp = nullptr; + } + } + + if (ConsumeTokenIf(TK_COMMA)) { Expression* nexp = new Expression(mScanner->mLocation, EX_LIST); - nexp->mToken = mScanner->mToken; + nexp->mToken = TK_COMMA; nexp->mLeft = exp; - mScanner->NextToken(); - nexp->mRight = ParseListExpression(); + + if (ConsumeTokenIf(TK_ELLIPSIS)) + return ParseBinaryFoldExpression(nexp); + + nexp->mRight = ParseListExpression(false); exp = nexp; } return exp; @@ -2937,9 +8302,18 @@ Expression* Parser::ParseListExpression(void) Expression* Parser::ParseFunction(Declaration * dec) { Declaration* othis = mThisPointer; + Declaration* ofunc = mFunctionType; + if (dec->mFlags & DTF_FUNC_THIS) mThisPointer = dec->mParams; + else + mThisPointer = dec->mClass; + mFunctionType = dec; + + DeclarationScope* oscope = mScope; + while (mScope->mLevel == SLEVEL_CLASS) + mScope = mScope->mParent; DeclarationScope* scope = new DeclarationScope(mScope, SLEVEL_FUNCTION); mScope = scope; @@ -2951,18 +8325,93 @@ Expression* Parser::ParseFunction(Declaration * dec) scope->Insert(pdec->mIdent, pdec); pdec = pdec->mNext; } + if (dec->mParamPack) + mScope->Insert(dec->mParamPack->mIdent, dec->mParamPack); mLocalIndex = 0; + mTempVars = nullptr; Expression * exp = ParseStatement(); + if (mCompilerOptions & COPT_CPLUSPLUS) + { + // Add destructors for parameters + Declaration* pdec = dec->mParams; + + while (pdec) + { + if (pdec->mBase->mType == DT_TYPE_STRUCT && pdec->mBase->mDestructor) + { + Expression* vexp = new Expression(pdec->mLocation, EX_VARIABLE); + vexp->mDecType = pdec->mBase; + vexp->mDecValue = pdec; + + Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX); + texp->mToken = TK_BINARY_AND; + texp->mLeft = vexp; + texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER); + texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + texp->mDecType->mBase = pdec->mBase; + texp->mDecType->mSize = 2; + + Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); + cexp->mDecValue = pdec->mBase->mDestructor; + cexp->mDecType = cexp->mDecValue->mBase; + + Expression * dexp = new Expression(mScanner->mLocation, EX_CALL); + dexp->mLeft = cexp; + dexp->mRight = texp; + + Expression* nexp = new Expression(mScanner->mLocation, EX_CONSTRUCT); + + nexp->mLeft = new Expression(mScanner->mLocation, EX_LIST); + nexp->mLeft->mLeft = nullptr; + nexp->mLeft->mRight = dexp; + nexp->mRight = vexp; + nexp->mDecType = vexp->mDecType; + + Expression* sexp = new Expression(mScanner->mLocation, EX_SEQUENCE); + sexp->mLeft = nexp; + sexp->mRight = exp; + exp = sexp; + } + + pdec = pdec->mNext; + } + } + mScope->End(mScanner->mLocation); - mScope = mScope->mParent; + mScope = oscope; mThisPointer = othis; + mFunctionType = ofunc; return exp; } +void Parser::SkipStatement(void) +{ + if (ConsumeTokenIf(TK_OPEN_BRACE)) + { + int cnt = 1; + while (cnt > 0) + { + if (ConsumeTokenIf(TK_OPEN_BRACE)) + cnt++; + else if (ConsumeTokenIf(TK_CLOSE_BRACE)) + cnt--; + else + mScanner->NextToken(); + } + } + else + { + while (!ConsumeTokenIf(TK_SEMICOLON)) + { + mScanner->NextToken(); + } + } +} + Expression* Parser::ParseStatement(void) { Expression* exp = nullptr; @@ -2981,6 +8430,8 @@ Expression* Parser::ParseStatement(void) mScanner->NextToken(); if (mScanner->mToken != TK_CLOSE_BRACE) { + Expression* sexp = new Expression(mScanner->mLocation, EX_SCOPE); + Expression* pexp = nullptr; do { @@ -3002,12 +8453,17 @@ Expression* Parser::ParseStatement(void) exp = nexp; } while (mScanner->mToken != TK_CLOSE_BRACE && mScanner->mToken != TK_EOF); + if (mScanner->mToken != TK_CLOSE_BRACE) mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "'}' expected"); exp->mEndLocation = mScanner->mLocation; mScope->End(mScanner->mLocation); mScanner->NextToken(); + + sexp->mLeft = exp; + + exp = sexp; } else { @@ -3023,19 +8479,48 @@ Expression* Parser::ParseStatement(void) switch (mScanner->mToken) { case TK_IF: + { mScanner->NextToken(); - exp = new Expression(mScanner->mLocation, EX_IF); - exp->mLeft = ParseParenthesisExpression(); - exp->mRight = new Expression(mScanner->mLocation, EX_ELSE); - exp->mRight->mLeft = ParseStatement(); - if (mScanner->mToken == TK_ELSE) + + if (ConsumeTokenIf(TK_CONSTEXPR)) { - mScanner->NextToken(); - exp->mRight->mRight = ParseStatement(); + exp = CoerceExpression(CleanupExpression(ParseParenthesisExpression()), TheBoolTypeDeclaration)->ConstantFold(mErrors, mDataSection); + if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_INTEGER) + { + if (exp->mDecValue->mInteger) + { + exp = ParseStatement(); + if (ConsumeTokenIf(TK_ELSE)) + SkipStatement(); + } + else + { + SkipStatement(); + if (ConsumeTokenIf(TK_ELSE)) + exp = ParseStatement(); + else + exp = new Expression(mScanner->mLocation, EX_VOID); + } + } + else + mErrors->Error(exp->mLocation, EERR_INVALID_CONSTEXPR, "Condition is not constant"); } else - exp->mRight->mRight = nullptr; - break; + { + exp = new Expression(mScanner->mLocation, EX_IF); + exp->mLeft = CoerceExpression(CleanupExpression(ParseParenthesisExpression()), TheBoolTypeDeclaration); + exp->mRight = new Expression(mScanner->mLocation, EX_ELSE); + exp->mRight->mLeft = ParseStatement(); + if (mScanner->mToken == TK_ELSE) + { + mScanner->NextToken(); + exp->mRight->mRight = ParseStatement(); + } + else + exp->mRight->mRight = nullptr; + } + + } break; case TK_WHILE: { mScanner->NextToken(); @@ -3044,7 +8529,7 @@ Expression* Parser::ParseStatement(void) mScope = scope; exp = new Expression(mScanner->mLocation, EX_WHILE); - exp->mLeft = ParseParenthesisExpression(); + exp->mLeft = CoerceExpression(CleanupExpression(ParseParenthesisExpression()), TheBoolTypeDeclaration); exp->mRight = ParseStatement(); mScope->End(mScanner->mLocation); @@ -3058,7 +8543,7 @@ Expression* Parser::ParseStatement(void) if (mScanner->mToken == TK_WHILE) { mScanner->NextToken(); - exp->mLeft = ParseParenthesisExpression(); + exp->mLeft = CoerceExpression(CleanupExpression(ParseParenthesisExpression()), TheBoolTypeDeclaration); ConsumeToken(TK_SEMICOLON); } else @@ -3081,32 +8566,219 @@ Expression* Parser::ParseStatement(void) Expression* initExp = nullptr, * iterateExp = nullptr, * conditionExp = nullptr, * bodyExp = nullptr, * finalExp = nullptr; - // Assignment if (mScanner->mToken != TK_SEMICOLON) - initExp = ParseExpression(true); - if (mScanner->mToken == TK_SEMICOLON) - mScanner->NextToken(); - else - mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "';' expected"); + initExp = CleanupExpression(ParseExpression(true)); - // Condition - if (mScanner->mToken != TK_SEMICOLON) - conditionExp = ParseExpression(false); + if ((mCompilerOptions & COPT_CPLUSPLUS) && ConsumeTokenIf(TK_COLON)) + { + Expression* containerExp = ParseExpression(false); + if (initExp->mType == EX_VARIABLE) + { + if (containerExp->mDecType->mType == DT_TYPE_ARRAY) + { + Declaration* iterVarDec = new Declaration(mScanner->mLocation, DT_VARIABLE); + iterVarDec->mBase = containerExp->mDecType->mBase->BuildPointer(mScanner->mLocation); + iterVarDec->mVarIndex = mLocalIndex++; + iterVarDec->mSize = iterVarDec->mBase->mSize; + iterVarDec->mFlags |= DTF_DEFINED; - if (mScanner->mToken == TK_SEMICOLON) - mScanner->NextToken(); - else - mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "';' expected"); + Declaration* endVarDec = new Declaration(mScanner->mLocation, DT_VARIABLE); + endVarDec->mBase = iterVarDec->mBase; + endVarDec->mVarIndex = mLocalIndex++; + endVarDec->mSize = endVarDec->mBase->mSize; + endVarDec->mFlags |= DTF_DEFINED; - // Iteration - if (mScanner->mToken != TK_CLOSE_PARENTHESIS) - iterateExp = ParseExpression(false); - if (mScanner->mToken == TK_CLOSE_PARENTHESIS) - mScanner->NextToken(); + Declaration* valueVarDec = initExp->mDecValue; + valueVarDec->mBase = valueVarDec->mBase->DeduceAuto(containerExp->mDecType->mBase); + valueVarDec->mSize = valueVarDec->mBase->mSize; + + initExp = new Expression(mScanner->mLocation, EX_LIST); + initExp->mLeft = new Expression(mScanner->mLocation, EX_INITIALIZATION); + initExp->mLeft->mToken = TK_ASSIGN; + initExp->mLeft->mLeft = new Expression(mScanner->mLocation, EX_VARIABLE); + initExp->mLeft->mLeft->mDecType = iterVarDec->mBase; + initExp->mLeft->mLeft->mDecValue = iterVarDec; + initExp->mLeft->mRight = containerExp; + + initExp->mRight = new Expression(mScanner->mLocation, EX_INITIALIZATION); + initExp->mRight->mToken = TK_ASSIGN; + initExp->mRight->mLeft = new Expression(mScanner->mLocation, EX_VARIABLE); + initExp->mRight->mLeft->mDecType = endVarDec->mBase; + initExp->mRight->mLeft->mDecValue = endVarDec; + initExp->mRight->mRight = new Expression(mScanner->mLocation, EX_BINARY); + initExp->mRight->mRight->mToken = TK_ADD; + initExp->mRight->mRight->mDecType = iterVarDec->mBase; + initExp->mRight->mRight->mLeft = new Expression(mScanner->mLocation, EX_VARIABLE); + initExp->mRight->mRight->mLeft->mDecType = iterVarDec->mBase; + initExp->mRight->mRight->mLeft->mDecValue = iterVarDec; + initExp->mRight->mRight->mRight = new Expression(mScanner->mLocation, EX_CONSTANT); + initExp->mRight->mRight->mRight->mDecType = TheSignedIntTypeDeclaration; + initExp->mRight->mRight->mRight->mDecValue = new Declaration(mScanner->mLocation, DT_CONST_INTEGER); + initExp->mRight->mRight->mRight->mDecValue->mBase = TheSignedIntTypeDeclaration; + initExp->mRight->mRight->mRight->mDecValue->mSize = 2; + initExp->mRight->mRight->mRight->mDecValue->mInteger = containerExp->mDecType->mSize; + + iterateExp = new Expression(mScanner->mLocation, EX_PREINCDEC); + iterateExp->mToken = TK_INC; + iterateExp->mLeft = new Expression(mScanner->mLocation, EX_VARIABLE); + iterateExp->mLeft->mDecType = iterVarDec->mBase; + iterateExp->mLeft->mDecValue = iterVarDec; + + conditionExp = new Expression(mScanner->mLocation, EX_RELATIONAL); + conditionExp->mToken = TK_NOT_EQUAL; + conditionExp->mLeft = new Expression(mScanner->mLocation, EX_VARIABLE); + conditionExp->mLeft->mDecType = iterVarDec->mBase; + conditionExp->mLeft->mDecValue = iterVarDec; + conditionExp->mRight = new Expression(mScanner->mLocation, EX_VARIABLE); + conditionExp->mRight->mDecType = endVarDec->mBase; + conditionExp->mRight->mDecValue = endVarDec; + + bodyExp = new Expression(mScanner->mLocation, EX_ASSIGNMENT); + bodyExp->mToken = TK_ASSIGN; + bodyExp->mLeft = new Expression(mScanner->mLocation, EX_VARIABLE); + bodyExp->mLeft->mDecType = valueVarDec->mBase; + bodyExp->mLeft->mDecValue = valueVarDec; + bodyExp->mRight = new Expression(mScanner->mLocation, EX_PREFIX); + bodyExp->mRight->mToken = TK_MUL; + bodyExp->mRight->mDecType = containerExp->mDecType->mBase; + bodyExp->mRight->mLeft = new Expression(mScanner->mLocation, EX_VARIABLE); + bodyExp->mRight->mLeft->mDecType = iterVarDec->mBase; + bodyExp->mRight->mLeft->mDecValue = iterVarDec; + } + else if (containerExp->mDecType->mType == DT_TYPE_STRUCT) + { + Declaration* fbegin = containerExp->mDecType->mScope->Lookup(Ident::Unique("begin")); + Declaration* fend = containerExp->mDecType->mScope->Lookup(Ident::Unique("end")); + + if (fbegin && fend) + { + Expression* cexp = new Expression(mScanner->mLocation, EX_PREFIX); + cexp->mToken = TK_BINARY_AND; + cexp->mDecType = containerExp->mDecType->BuildPointer(mScanner->mLocation); + cexp->mLeft = containerExp; + + Declaration* iterVarDec = new Declaration(mScanner->mLocation, DT_VARIABLE); + iterVarDec->mBase = fbegin->mBase->mBase->NonRefBase(); + iterVarDec->mVarIndex = mLocalIndex++; + iterVarDec->mSize = iterVarDec->mBase->mSize; + iterVarDec->mFlags |= DTF_DEFINED; + + Declaration* endVarDec = new Declaration(mScanner->mLocation, DT_VARIABLE); + endVarDec->mBase = fend->mBase->mBase->NonRefBase(); + endVarDec->mVarIndex = mLocalIndex++; + endVarDec->mSize = endVarDec->mBase->mSize; + endVarDec->mFlags |= DTF_DEFINED; + + Declaration* valueVarDec = initExp->mDecValue; + + initExp = new Expression(mScanner->mLocation, EX_LIST); + initExp->mLeft = new Expression(mScanner->mLocation, EX_INITIALIZATION); + initExp->mLeft->mToken = TK_ASSIGN; + initExp->mLeft->mLeft = new Expression(mScanner->mLocation, EX_VARIABLE); + initExp->mLeft->mLeft->mDecType = iterVarDec->mBase; + initExp->mLeft->mLeft->mDecValue = iterVarDec; + initExp->mLeft->mRight = new Expression(mScanner->mLocation, EX_CALL); + initExp->mLeft->mRight->mDecType = fbegin->mBase->mBase; + initExp->mLeft->mRight->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT); + initExp->mLeft->mRight->mLeft->mDecType = fbegin->mBase; + initExp->mLeft->mRight->mLeft->mDecValue = fbegin; + initExp->mLeft->mRight->mRight = cexp; + + initExp->mRight = new Expression(mScanner->mLocation, EX_INITIALIZATION); + initExp->mRight->mToken = TK_ASSIGN; + initExp->mRight->mLeft = new Expression(mScanner->mLocation, EX_VARIABLE); + initExp->mRight->mLeft->mDecType = endVarDec->mBase; + initExp->mRight->mLeft->mDecValue = endVarDec; + initExp->mRight->mRight = new Expression(mScanner->mLocation, EX_CALL); + initExp->mRight->mRight->mDecType = fend->mBase->mBase; + initExp->mRight->mRight->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT); + initExp->mRight->mRight->mLeft->mDecType = fend->mBase; + initExp->mRight->mRight->mLeft->mDecValue = fend; + initExp->mRight->mRight->mRight = cexp; + + iterateExp = new Expression(mScanner->mLocation, EX_PREINCDEC); + iterateExp->mToken = TK_INC; + iterateExp->mLeft = new Expression(mScanner->mLocation, EX_VARIABLE); + iterateExp->mLeft->mDecType = iterVarDec->mBase; + iterateExp->mLeft->mDecValue = iterVarDec; + iterateExp = CheckOperatorOverload(iterateExp); + + conditionExp = new Expression(mScanner->mLocation, EX_RELATIONAL); + conditionExp->mToken = TK_NOT_EQUAL; + conditionExp->mLeft = new Expression(mScanner->mLocation, EX_VARIABLE); + conditionExp->mLeft->mDecType = iterVarDec->mBase; + conditionExp->mLeft->mDecValue = iterVarDec; + conditionExp->mRight = new Expression(mScanner->mLocation, EX_VARIABLE); + conditionExp->mRight->mDecType = endVarDec->mBase; + conditionExp->mRight->mDecValue = endVarDec; + conditionExp = CheckOperatorOverload(conditionExp); + + bodyExp = new Expression(mScanner->mLocation, EX_INITIALIZATION); + bodyExp->mToken = TK_ASSIGN; + bodyExp->mLeft = new Expression(mScanner->mLocation, EX_VARIABLE); + + bodyExp->mRight = new Expression(mScanner->mLocation, EX_PREFIX); + bodyExp->mRight->mToken = TK_MUL; + bodyExp->mRight->mDecType = valueVarDec->mBase; + bodyExp->mRight->mLeft = new Expression(mScanner->mLocation, EX_VARIABLE); + bodyExp->mRight->mLeft->mDecType = iterVarDec->mBase; + bodyExp->mRight->mLeft->mDecValue = iterVarDec; + if (iterVarDec->mBase->mType == DT_TYPE_POINTER) + bodyExp->mRight->mDecType = iterVarDec->mBase->mBase; + else + bodyExp->mRight = CheckOperatorOverload(bodyExp->mRight); + + valueVarDec->mBase = valueVarDec->mBase->DeduceAuto(bodyExp->mRight->mDecType); + valueVarDec->mSize = valueVarDec->mBase->mSize; + + bodyExp->mLeft->mDecType = valueVarDec->mBase; + bodyExp->mLeft->mDecValue = valueVarDec; + bodyExp = CheckOperatorOverload(bodyExp); + } + else + mErrors->Error(containerExp->mLocation, EERR_INCOMPATIBLE_TYPES, "Array or container expected"); + } + else + mErrors->Error(containerExp->mLocation, EERR_INCOMPATIBLE_TYPES, "Array or container expected"); + } + else + mErrors->Error(initExp->mLocation, EERR_INCOMPATIBLE_TYPES, "Variable expected"); + } else - mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "')' expected"); - bodyExp = ParseStatement(); + { + if (mScanner->mToken == TK_SEMICOLON) + mScanner->NextToken(); + else + mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "';' expected"); + + // Condition + if (mScanner->mToken != TK_SEMICOLON) + conditionExp = CoerceExpression(CleanupExpression(ParseExpression(false)), TheBoolTypeDeclaration); + + if (mScanner->mToken == TK_SEMICOLON) + mScanner->NextToken(); + else + mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "';' expected"); + + // Iteration + if (mScanner->mToken != TK_CLOSE_PARENTHESIS) + iterateExp = CleanupExpression(ParseExpression(false)); + } + + ConsumeToken(TK_CLOSE_PARENTHESIS); + + Expression * innerExp = ParseStatement(); + if (bodyExp) + { + Expression* exp = new Expression(bodyExp->mLocation, EX_SEQUENCE); + exp->mLeft = bodyExp; + exp->mRight = innerExp; + bodyExp = exp; + } + else + bodyExp = innerExp; + mScope->End(mScanner->mLocation); exp->mLeft = new Expression(mScanner->mLocation, EX_SEQUENCE); @@ -3277,7 +8949,37 @@ Expression* Parser::ParseStatement(void) mScanner->NextToken(); exp = new Expression(mScanner->mLocation, EX_RETURN); if (mScanner->mToken != TK_SEMICOLON) + { exp->mLeft = ParseRExpression(); + if (mFunctionType && mFunctionType->mBase) + { + if (mFunctionType->mBase->mType == DT_TYPE_AUTO || mFunctionType->mBase->IsReference() && mFunctionType->mBase->mBase->mType == DT_TYPE_AUTO) + { + mFunctionType->mBase = mFunctionType->mBase->DeduceAuto(exp->mLeft->mDecType); + ; + if (mFunctionType->mBase->mType == DT_TYPE_STRUCT) + { + // Make room for value struct return + Declaration* p = mFunctionType->mParams; + while (p) + { + p->mVarIndex += 2; + p = p->mNext; + } + } + } + exp->mLeft = CoerceExpression(exp->mLeft, mFunctionType->mBase); + } + exp->mLeft = CleanupExpression(exp->mLeft); + if (exp->mLeft->mType == EX_CONSTRUCT && mFunctionType && mFunctionType->mBase && mFunctionType->mBase->mType == DT_TYPE_STRUCT) + { + Expression* cexp = exp->mLeft->mLeft->mLeft; + + exp->mLeft->mLeft->mRight = nullptr; + + exp->mLeft->mRight->mType = EX_RESULT; + } + } ConsumeToken(TK_SEMICOLON); break; case TK_BREAK: @@ -3319,7 +9021,7 @@ Expression* Parser::ParseStatement(void) break; default: - exp = ParseListExpression(); + exp = CleanupExpression(ParseListExpression(true)); ConsumeToken(TK_SEMICOLON); } } @@ -3336,7 +9038,7 @@ Expression* Parser::ParseSwitchStatement(void) if (mScanner->mToken == TK_OPEN_PARENTHESIS) { mScanner->NextToken(); - sexp->mLeft = ParseRExpression(); + sexp->mLeft = CleanupExpression(ParseRExpression()); if (mScanner->mToken == TK_CLOSE_PARENTHESIS) mScanner->NextToken(); else @@ -3424,6 +9126,939 @@ Expression* Parser::ParseSwitchStatement(void) return sexp; } +int Parser::ExpansionDistance(Declaration* tdec, Declaration* spec) +{ + Declaration* ptdec = tdec->mParams; + Declaration* psdec = spec->mParams; + + int cost = 0; + if (tdec->mParser) + cost = 100000; + + while (ptdec && psdec) + { + if (ptdec->mType == DT_CONST_TEMPLATE && psdec->mType == DT_CONST_TEMPLATE) + { + if (ptdec->mBase) + { + if (ptdec->mBase->mInteger != psdec->mBase->mInteger) + return NOOVERLOAD; + } + else + cost += 100; + } + else if (ptdec->mType == DT_TYPE_TEMPLATE && psdec->mType == DT_TYPE_TEMPLATE) + { + if (ptdec->mBase) + { + if (!ptdec->mBase->IsSame(psdec->mBase)) + return NOOVERLOAD; + } + else + cost += 100; + } + else if (ptdec->mType == DT_PACK_TEMPLATE && psdec->mType == DT_PACK_TEMPLATE) + { + if (ptdec->mBase) + { + + Declaration* tvp = ptdec->mBase->mParams; + Declaration* svp = psdec->mBase->mParams; + + while (tvp && svp && tvp->IsSame(svp)) + { + tvp = tvp->mNext; + svp = svp->mNext; + } + + if (tvp || svp) + return NOOVERLOAD; + } + else if (psdec->mBase) + { + Declaration* dec = psdec->mBase->mParams; + while (dec) + { + cost += 200; + dec = dec->mNext; + } + } + } + else if (ptdec->mType == DT_PACK_TEMPLATE) + { + if (ptdec->mBase) + { + ptdec = ptdec->mBase->mParams; + continue; + } + else + { + while (psdec) + { + cost += 200; + psdec = psdec->mNext; + } + + return cost; + } + } + else + return NOOVERLOAD; + + ptdec = ptdec->mNext; + psdec = psdec->mNext; + } + + if (ptdec && ptdec->mType == DT_PACK_TEMPLATE) + { + if (ptdec->mBase) + { + if (ptdec->mBase->mParams) + return NOOVERLOAD; + } + else + cost += 50; + } + else if (ptdec || psdec) + return NOOVERLOAD; + + return cost; +} + +Declaration* Parser::ParseTemplateExpansion(Declaration* tmpld, Declaration* expd) +{ + Declaration * tdec = new Declaration(mScanner->mLocation, DT_TEMPLATE); + tdec->mScope = new DeclarationScope(nullptr, SLEVEL_TEMPLATE); + +#if 1 + if (expd) + { + if (tmpld->mBase->mType == DT_TEMPLATE) + { + Parser* p = tmpld->mBase->mParser->Clone(); + + p->mScanner->Replay(tmpld->mBase->mTokens); + + tdec = tmpld->mBase->Clone(); + tdec->mScope->mName = expd->mScope->mName; + tdec->mScope->mParent = expd->mScope; + + p->ParseTemplateDeclarationBody(tdec, nullptr); + + return tdec; + } + + Declaration* ppdec = nullptr; + Declaration* dec = expd->mParams; + + while (dec) + { + Declaration* epdec = dec->Clone(); + + if (ppdec) + ppdec->mNext = epdec; + else + tdec->mParams = epdec; + ppdec = epdec; + + dec = dec->mNext; + } + } + else + { + ConsumeToken(TK_LESS_THAN); + + Declaration* ppdec = nullptr; + + if (!ConsumeTokenIf(TK_GREATER_THAN)) + { + do + { + Expression* exp = ParseShiftExpression(false); + Declaration* pdec = nullptr; + + if (exp->mType == EX_TYPE) + { + pdec = new Declaration(exp->mLocation, DT_TYPE_TEMPLATE); + pdec->mBase = exp->mDecType; + } + else if (exp->mType == EX_PACK_TYPE) + { + ConsumeToken(TK_ELLIPSIS); + + if (exp->mDecType->mType == DT_PACK_TYPE) + { + Declaration* ptdec = exp->mDecType->mParams; + while (ptdec) + { + pdec = new Declaration(exp->mLocation, DT_TYPE_TEMPLATE); + pdec->mBase = ptdec; + + if (pdec) + { + if (ppdec) + ppdec->mNext = pdec; + else + tdec->mParams = pdec; + ppdec = pdec; + } + + ptdec = ptdec->mNext; + } + continue; + } + else + { + pdec = new Declaration(exp->mLocation, DT_PACK_TEMPLATE); + pdec->mBase = exp->mDecType; + } + } + else if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_FUNCTION) + { + pdec = new Declaration(exp->mLocation, DT_TYPE_TEMPLATE); + pdec->mBase = exp->mDecValue; + } + else if (exp->mType == EX_CONSTANT && (exp->mDecValue->mType == DT_CONST_INTEGER || exp->mDecValue->mType == DT_CONST_TEMPLATE)) + { + pdec = new Declaration(exp->mLocation, DT_CONST_TEMPLATE); + pdec->mBase = exp->mDecValue; + } + else + mErrors->Error(exp->mLocation, EERR_TEMPLATE_PARAMS, "Template specification expected"); + + if (pdec) + { + if (ppdec) + ppdec->mNext = pdec; + else + tdec->mParams = pdec; + ppdec = pdec; + } + + } while (ConsumeTokenIf(TK_COMMA)); + + ConsumeToken(TK_GREATER_THAN); + } + } + + while (!tmpld->mTokens) + tmpld = tmpld->mNext; + + Declaration* epdec = tdec->mParams; + while (epdec && epdec->mBase && epdec->mBase->mType != DT_TYPE_TEMPLATE && epdec->mBase->mType != DT_CONST_TEMPLATE && epdec->mBase->mType != DT_PACK_TEMPLATE) + epdec = epdec->mNext; + + if (epdec) + { + // Partial template specification + Declaration* bdec = new Declaration(mScanner->mLocation, tmpld->mBase->mType); + tdec->mBase = bdec; + bdec->mTemplate = tdec; + bdec->mBase = tmpld->mBase->mBase; + tdec->mIdent = tmpld->mIdent; + tdec->mQualIdent = tmpld->mQualIdent; + tdec->mScope->mName = tdec->mIdent; + tdec->mNext = tmpld; + bdec->mIdent = tdec->MangleIdent(); + + return bdec; + } + + Declaration* pthis = tmpld->mClass; + + int mindist = NOOVERLOAD; + Declaration* etdec = nullptr; + + Declaration* dec = tmpld; + while (dec) + { + int dist = ExpansionDistance(dec, tdec); + if (dist < mindist) + { + mindist = dist; + etdec = dec; + } + dec = dec->mNext; + } + + if (mindist == 0) + return etdec->mBase; + else if (mindist == NOOVERLOAD) + mErrors->Error(tdec->mLocation, EERR_TEMPLATE_PARAMS, "No matching template parameters"); + else + tmpld = etdec; + + dec = tdec->mParams; + Declaration * pdec = tmpld->mParams; + + Declaration * ppdec = nullptr; + while (pdec) + { + if (pdec->mType == DT_PACK_TEMPLATE) + { + if (!dec) + { + Declaration* packd = new Declaration(tdec->mLocation, DT_PACK_TEMPLATE); + packd->mBase = new Declaration(tdec->mLocation, DT_PACK_TYPE); + if (ppdec) + ppdec->mNext = packd; + else + tdec->mParams = packd; + dec = packd; + } + else if (dec->mType != DT_PACK_TEMPLATE) + { + Declaration* packd = new Declaration(dec->mLocation, DT_PACK_TEMPLATE); + packd->mBase = new Declaration(dec->mLocation, DT_PACK_TYPE); + if (ppdec) + ppdec->mNext = packd; + else + tdec->mParams = packd; + + ppdec = nullptr; + while (dec) + { + Declaration* ndec = dec->mBase->Clone(); + + if (ppdec) + ppdec->mNext = ndec; + else + packd->mBase->mParams = ndec; + ppdec = ndec; + dec = dec->mNext; + } + + dec = packd; + } + } + + if (dec) + { + dec->mIdent = pdec->mIdent; + tdec->mScope->Insert(dec->mIdent, dec->mBase); + + ppdec = dec; + dec = dec->mNext; + } + + pdec = pdec->mNext; + } + + +#else + if (expd) + { + if (tmpld->mBase->mType == DT_TEMPLATE) + { + Parser* p = tmpld->mBase->mParser->Clone(); + + p->mScanner->Replay(tmpld->mBase->mTokens); + + tdec = tmpld->mBase->Clone(); + tdec->mScope->mName = expd->mScope->mName; + tdec->mScope->mParent = expd->mScope; + + p->ParseTemplateDeclarationBody(tdec, nullptr); + + return tdec; + } + + Declaration* ppdec = nullptr; + Declaration* dec = expd->mParams; + Declaration* pdec = tmpld->mParams; + + while (dec) + { + Declaration* epdec = dec->Clone(); + + tdec->mScope->Insert(epdec->mIdent, epdec->mBase); + epdec->mFlags |= DTF_DEFINED; + + if (ppdec) + ppdec->mNext = epdec; + else + tdec->mParams = epdec; + ppdec = epdec; + + dec = dec->mNext; + pdec = pdec->mNext; + } + + if (pdec) + { + if (ppdec) + ppdec->mNext = pdec; + else + tdec->mParams = pdec; + } + + } + else + { + ConsumeToken(TK_LESS_THAN); + + Declaration* ppdec = nullptr; + Declaration* pdec = tmpld->mParams; + + // Carry over already specialized parameters + while (pdec && (pdec->mType != DT_TYPE_TEMPLATE && pdec->mType != DT_CONST_TEMPLATE)) + { + Declaration* epdec = pdec->Clone(); + + tdec->mScope->Insert(epdec->mIdent, epdec->mBase); + epdec->mFlags |= DTF_DEFINED; + + if (ppdec) + ppdec->mNext = epdec; + else + tdec->mParams = epdec; + ppdec = epdec; + + pdec = pdec->mNext; + } + + // Now to the new parameters + while (pdec) + { + Declaration* epdec = pdec->Clone(); + Expression* exp = ParseShiftExpression(false); + + if (epdec->mType == DT_TYPE_TEMPLATE) + { + if (exp->mType == EX_TYPE) + epdec->mBase = exp->mDecType; + else if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_FUNCTION) + epdec->mBase = exp->mDecValue; + else + { + mErrors->Error(exp->mLocation, EERR_TEMPLATE_PARAMS, "Type parameter expected", pdec->mIdent); + epdec->mBase = TheVoidTypeDeclaration; + } + } + else if (epdec->mType == DT_CONST_TEMPLATE) + { + if (exp->mType == EX_CONSTANT && (exp->mDecValue->mType == DT_CONST_INTEGER || exp->mDecValue->mType == DT_CONST_TEMPLATE)) + epdec->mBase = exp->mDecValue; + else + mErrors->Error(exp->mLocation, EERR_TEMPLATE_PARAMS, "Const integer parameter expected", pdec->mIdent); + } + + tdec->mScope->Insert(epdec->mIdent, epdec->mBase); + epdec->mFlags |= DTF_DEFINED; + + if (ppdec) + ppdec->mNext = epdec; + else + tdec->mParams = epdec; + ppdec = epdec; + + pdec = pdec->mNext; + if (pdec && !ConsumeTokenIf(TK_COMMA)) + break; + } + + ConsumeToken(TK_GREATER_THAN); + + // Partial template arguments given + if (pdec) + { + if (ppdec) + ppdec->mNext = pdec; + else + tdec->mParams = pdec; + } + } + + while (!tmpld->mTokens) + tmpld = tmpld->mNext; + + Declaration* pthis = tmpld->mClass; + + Declaration* etdec = tmpld->mNext; + while (etdec && !etdec->IsSameParams(tdec)) + etdec = etdec->mNext; +#endif + + Parser* p = tmpld->mParser->Clone(); + + p->mScanner->Replay(tmpld->mTokens); + + tdec->mScope->mName = tdec->MangleIdent(); + tdec->mNext = tmpld->mNext; + tmpld->mNext = tdec; + + tdec->mScope->mParent = tmpld->mScope->mParent; + + p->mTemplateScope = tdec->mScope; + if (tmpld->mFlags & DTF_AUTO_TEMPLATE) + { + Declaration * ndec = tmpld->mBase->ExpandTemplate(tdec->mScope); + + Declaration* pdec = tmpld->mBase; + + if (pdec) + { + Declaration* pcdec = nullptr; + + while (pdec && !ndec->mBase->IsSameParams(pdec->mBase)) + { + pcdec = pdec; + pdec = pdec->mNext; + } + + if (!pdec) + pcdec->mNext = ndec; + } + + tdec->mBase = ndec; + ndec->mValue = p->ParseFunction(ndec->mBase); + ndec->mNumVars = mLocalIndex; + ndec->mFlags |= DTF_DEFINED; + + ndec->mIdent = ndec->mIdent->Mangle(tdec->mScope->mName->mString); + ndec->mQualIdent = ndec->mQualIdent->Mangle(tdec->mScope->mName->mString); + } + else + { + Declaration* tpthis = nullptr; + if (tmpld->mClass) + tpthis = tmpld->mClass; + else if (expd && expd->mBase) + tpthis = expd->mBase->BuildConstPointer(tdec->mLocation); + + tdec->mBase = p->ParseDeclaration(nullptr, true, false, tpthis, tdec); + } + + p->mTemplateScope = nullptr; + + if (tdec->mBase->mType == DT_ANON) + { + tdec->mBase = tdec->mBase->mBase; + mCompilationUnits->mTemplateScope->Insert(tmpld->mQualIdent, tmpld); + + tdec->mBase->mScope->Iterate([=](const Ident* ident, Declaration* mdec) + { + if (mdec->mType == DT_CONST_FUNCTION) + { + while (mdec) + { + if (!(mdec->mFlags & DTF_DEFINED)) + { + Declaration* mpdec = mCompilationUnits->mScope->Lookup(tmpld->mScope->Mangle(mdec->mIdent)); + while (mpdec && !mdec->mBase->IsTemplateSameParams(mpdec->mBase, tdec)) + mpdec = mpdec->mNext; + if (mpdec && mpdec->mTemplate) + { + Declaration* rdec; + if (mdec->mTemplate) + { + Declaration * mtdec = p->ParseTemplateExpansion(mpdec->mTemplate, tdec); + mtdec->mClass = mdec->mTemplate->mClass; + mdec->mTemplate = mtdec; + mdec->mTemplate->mBase = mdec; + rdec = mtdec; + } + else + rdec = p->ParseTemplateExpansion(mpdec->mTemplate, tdec); + if (mdec->mBase->mBase->IsAuto()) + mdec->mBase->mBase = rdec->mBase->mBase; + } + } + + mdec = mdec->mNext; + } + } + }); + } + + return tdec->mBase; +} + +void Parser::CompleteTemplateExpansion(Declaration* tmpld) +{ + tmpld = tmpld->mNext; + while (tmpld) + { + if (tmpld->mBase->mType == DT_TYPE_STRUCT) + { + // now expand the templated members + + tmpld->mBase->mScope->Iterate([=](const Ident* ident, Declaration* mdec) + { + if (mdec->mType == DT_CONST_FUNCTION) + { + while (mdec) + { + Declaration* mpdec = mCompilationUnits->mScope->Lookup(mdec->mQualIdent); + while (mpdec && !mpdec->IsSameParams(mdec->mParams)) + mpdec = mpdec->mNext; + if (mpdec && mpdec->mType == DT_TEMPLATE) + { + ParseTemplateExpansion(mpdec, tmpld); + } + + mdec = mdec->mNext; + } + } + }); + } + } +} + + +Declaration* Parser::FunctionAutoParamsToTemplate(Declaration* fdec) +{ + Declaration* pdec = fdec->mBase->mParams; + while (pdec && !pdec->mBase->IsAuto()) + pdec = pdec->mNext; + + if (pdec) + { + Declaration* tdec = new Declaration(fdec->mLocation, DT_TEMPLATE); + tdec->mParser = this->Clone(); + tdec->mScope = new DeclarationScope(mTemplateScope, SLEVEL_TEMPLATE); + Declaration* ppdec = nullptr; + + int ntp = 0; + pdec = fdec->mBase->mParams; + while (pdec) + { + Declaration* ptdec = nullptr; + + if (pdec->mBase->mType == DT_TYPE_AUTO) + { + ptdec = new Declaration(mScanner->mLocation, DT_TYPE_TEMPLATE); + pdec->mBase = ptdec; + } + else if (pdec->mBase->IsReference() && pdec->mBase->mBase->mType == DT_TYPE_AUTO) + { + ptdec = new Declaration(mScanner->mLocation, DT_TYPE_TEMPLATE); + pdec->mBase->mBase = ptdec; + } + + if (ptdec) + { + ptdec->mIdent = Ident::Unique("T" + ntp++); + tdec->mScope->Insert(ptdec->mIdent, ptdec); + ptdec->mFlags |= DTF_DEFINED; + + if (ppdec) + ppdec->mNext = ptdec; + else + tdec->mParams = ptdec; + ppdec = ptdec; + } + + pdec = pdec->mNext; + } + + fdec->mCompilerOptions = mCompilerOptions; + fdec->mBase->mCompilerOptions = mCompilerOptions; + + tdec->mBase = fdec; + fdec->mTemplate = tdec; + + mScanner->BeginRecord(); + + if (ConsumeTokenIf(TK_OPEN_BRACE)) + { + int qdepth = 1; + while (qdepth) + { + if (ConsumeTokenIf(TK_OPEN_BRACE)) + qdepth++; + else if (ConsumeTokenIf(TK_CLOSE_BRACE)) + qdepth--; + else + mScanner->NextToken(); + } + } + + tdec->mTokens = mScanner->CompleteRecord(); + + tdec->mIdent = tdec->mBase->mIdent; + tdec->mQualIdent = tdec->mBase->mQualIdent; + tdec->mScope->mName = tdec->mQualIdent; + tdec->mFlags |= DTF_AUTO_TEMPLATE; + + if (tdec->mQualIdent == mScope->Mangle(tdec->mIdent)) + mScope->Insert(tdec->mIdent, tdec->mBase); + + Declaration* pdec = mCompilationUnits->mScope->Insert(tdec->mQualIdent, tdec->mBase); + if (pdec) + { + Declaration* ppdec = pdec; + while (pdec && !pdec->IsSameTemplate(tdec->mBase)) + { + ppdec = pdec; + pdec = pdec->mNext; + } + + if (!pdec) + { + ppdec->mNext = tdec->mBase; + tdec->mBase->mNext = nullptr; + } + } + + return fdec; + } + else + return nullptr; +} + +Declaration * Parser::ParseTemplateDeclaration(Declaration* pthis) +{ + Declaration* tdec = new Declaration(mScanner->mLocation, DT_TEMPLATE); + tdec->mParser = this->Clone(); + tdec->mScope = new DeclarationScope(mTemplateScope, SLEVEL_TEMPLATE); + tdec->mClass = pthis; + Declaration* ppdec = nullptr; + + ConsumeToken(TK_LESS_THAN); + if (mScanner->mToken != TK_GREATER_THAN) + { + for (;;) + { + Declaration* pdec = nullptr; + + if (ConsumeTokenIf(TK_CLASS) || ConsumeTokenIf(TK_TYPENAME)) + { + if (ConsumeTokenIf(TK_ELLIPSIS)) + { + if (mScanner->mToken == TK_IDENT) + { + pdec = new Declaration(mScanner->mLocation, DT_PACK_TEMPLATE); + pdec->mIdent = mScanner->mTokenIdent; + mScanner->NextToken(); + } + else + mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Identifier expected"); + } + else if (mScanner->mToken == TK_IDENT) + { + pdec = new Declaration(mScanner->mLocation, DT_TYPE_TEMPLATE); + pdec->mIdent = mScanner->mTokenIdent; + mScanner->NextToken(); + } + else + mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Identifier expected"); + } + else if (ConsumeTokenIf(TK_INT)) + { + if (mScanner->mToken == TK_IDENT) + { + pdec = new Declaration(mScanner->mLocation, DT_CONST_TEMPLATE); + pdec->mIdent = mScanner->mTokenIdent; + mScanner->NextToken(); + } + else + mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Identifier expected"); + } + else + mErrors->Error(mScanner->mLocation, EERR_TEMPLATE_PARAMS, "'class' or 'int' expected as template parameter"); + + if (pdec) + { + tdec->mScope->Insert(pdec->mIdent, pdec); + pdec->mFlags |= DTF_DEFINED; + + if (ppdec) + ppdec->mNext = pdec; + else + tdec->mParams = pdec; + ppdec = pdec; + } + + if (!ConsumeTokenIf(TK_COMMA)) + break; + } + } + + ConsumeToken(TK_GREATER_THAN); + + if (ConsumeTokenIf(TK_TEMPLATE)) + { + mTemplateScope = tdec->mScope; + tdec->mBase = ParseTemplateDeclaration(pthis); + mTemplateScope = tdec->mScope->mParent; + tdec->mBase->mBase->mTemplate = tdec; + } + else + ParseTemplateDeclarationBody(tdec, pthis); + + return tdec; +} + +void Parser::ParseTemplateDeclarationBody(Declaration * tdec, Declaration * pthis) +{ + mScanner->BeginRecord(); + if (mScanner->mToken == TK_CLASS || mScanner->mToken == TK_STRUCT) + { + // Class template + Declaration* bdec = new Declaration(mScanner->mLocation, DT_TYPE_STRUCT); + tdec->mBase = bdec; + bdec->mTemplate = tdec; + + mScanner->NextToken(); + if (mScanner->mToken == TK_IDENT) + { + bdec->mIdent = mScanner->mTokenIdent; + bdec->mQualIdent = mScope->Mangle(mScanner->mTokenIdent); + bdec->mScope = new DeclarationScope(nullptr, SLEVEL_CLASS, bdec->mQualIdent); + + while (mScanner->mToken != TK_SEMICOLON && mScanner->mToken != TK_OPEN_BRACE) + mScanner->NextToken(); + + if (ConsumeTokenIf(TK_OPEN_BRACE)) + { + int qdepth = 1; + while (qdepth) + { + if (ConsumeTokenIf(TK_OPEN_BRACE)) + qdepth++; + else if (ConsumeTokenIf(TK_CLOSE_BRACE)) + qdepth--; + else + mScanner->NextToken(); + } + } + } + else + mErrors->Error(bdec->mLocation, EERR_FUNCTION_TEMPLATE, "Class template expected"); + } + else + { + // Function template + mTemplateScope = tdec->mScope; + + ConsumeTokenIf(TK_INLINE); + ConsumeTokenIf(TK_CONSTEXPR); + + Declaration* bdec = ParseBaseTypeDeclaration(0, true); + Declaration* adec = nullptr; + + if (ConsumeTokenIf(TK_COLCOLON) && ExpectToken(TK_IDENT) && mScanner->mTokenIdent == bdec->mTemplate->mIdent) + { + mScanner->NextToken(); + + Declaration* ctdec = ParseFunctionDeclaration(TheVoidTypeDeclaration); + + adec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION); + + adec->mBase = ctdec; + adec->mIdent = bdec->mTemplate->mIdent->PreMangle("+"); + + char buffer[200]; + strcpy_s(buffer, bdec->mTemplate->mQualIdent->mString); + strcat_s(buffer, "::"); + strcat_s(buffer, adec->mIdent->mString); + adec->mQualIdent = Ident::Unique(buffer); + } + else + { + adec = ParsePostfixDeclaration(); + adec = ReverseDeclaration(adec, bdec); + } + + mTemplateScope = tdec->mScope->mParent; + + if (adec->mBase->mType == DT_TYPE_FUNCTION) + { + if (pthis) + PrependThisArgument(adec->mBase, pthis); + + if (ConsumeTokenIf(TK_CONST)) + adec->mBase->mFlags |= DTF_CONST; + + adec->mType = DT_CONST_FUNCTION; + adec->mSection = mCodeSection; + + if (mCompilerOptions & COPT_NATIVE) + adec->mFlags |= DTF_NATIVE; + + tdec->mBase = adec; + adec->mTemplate = tdec; + + if (ConsumeTokenIf(TK_OPEN_BRACE)) + { + int qdepth = 1; + while (qdepth) + { + if (ConsumeTokenIf(TK_OPEN_BRACE)) + qdepth++; + else if (ConsumeTokenIf(TK_CLOSE_BRACE)) + qdepth--; + else + mScanner->NextToken(); + } + } + else if (ConsumeTokenIf(TK_SEMICOLON)) + { + + } + else + { + mErrors->Error(bdec->mLocation, EERR_FUNCTION_TEMPLATE, "Function template body expected"); + adec->mType = DT_TYPE_VOID; + tdec->mBase = adec; + adec->mIdent = adec->mQualIdent = Ident::Unique("_"); + adec->mTemplate = tdec; + } + } + else + { + mErrors->Error(bdec->mLocation, EERR_FUNCTION_TEMPLATE, "Function template expected"); + adec->mType = DT_TYPE_VOID; + tdec->mBase = adec; + adec->mIdent = adec->mQualIdent = Ident::Unique("_"); + adec->mTemplate = tdec; + } + } + + tdec->mTokens = mScanner->CompleteRecord(); + + tdec->mIdent = tdec->mBase->mIdent; + tdec->mQualIdent = tdec->mBase->mQualIdent; + tdec->mScope->mName = tdec->mQualIdent; + + if (tdec->mQualIdent == mScope->Mangle(tdec->mIdent)) + { + Declaration* pdec = mScope->Insert(tdec->mIdent, tdec->mBase); + if (pdec) + { + Declaration* ppdec = pdec; + while (pdec && !pdec->IsSameTemplate(tdec->mBase)) + { + ppdec = pdec; + pdec = pdec->mNext; + } + + if (pdec && pdec->mTemplate) + { + tdec->mNext = pdec->mTemplate->mNext; + pdec->mTemplate->mNext = tdec; + } + } + } + + Declaration* pdec = mCompilationUnits->mScope->Insert(tdec->mQualIdent, tdec->mBase); + if (pdec) + { + Declaration* ppdec = pdec; + while (pdec && !pdec->IsSameTemplate(tdec->mBase)) + { + ppdec = pdec; + pdec = pdec->mNext; + } + + if (!pdec) + { + ppdec->mNext = tdec->mBase; + tdec->mBase->mNext = nullptr; + } + } +} Expression* Parser::ParseAssemblerBaseOperand(Declaration* pcasm, int pcoffset) @@ -3488,7 +10123,7 @@ Expression* Parser::ParseAssemblerBaseOperand(Declaration* pcasm, int pcoffset) case TK_CHARACTER: dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER); dec->mInteger = mCharMap[(unsigned char)mScanner->mTokenInteger]; - dec->mBase = TheUnsignedIntTypeDeclaration; + dec->mBase = TheUnsignedCharTypeDeclaration; exp = new Expression(mScanner->mLocation, EX_CONSTANT); exp->mDecValue = dec; exp->mDecType = dec->mBase; @@ -3589,7 +10224,7 @@ Expression* Parser::ParseAssemblerMulOperand(Declaration* pcasm, int pcoffset) nexp->mLeft = exp; mScanner->NextToken(); nexp->mRight = ParseAssemblerBaseOperand(pcasm, pcoffset); - exp = nexp->ConstantFold(mErrors); + exp = nexp->ConstantFold(mErrors, mDataSection); } return exp; } @@ -3648,11 +10283,58 @@ Expression* Parser::ParseAssemblerAddOperand(Declaration* pcasm, int pcoffset) mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Integer offset expected"); } else - exp = nexp->ConstantFold(mErrors); + exp = nexp->ConstantFold(mErrors, mDataSection); } return exp; } +Expression* Parser::ParseAssemblerShiftOperand(Declaration* pcasm, int pcoffset) +{ + Expression* exp = ParseAssemblerAddOperand(pcasm, pcoffset); + while (mScanner->mToken == TK_LEFT_SHIFT || mScanner->mToken == TK_RIGHT_SHIFT) + { + Expression* nexp = new Expression(mScanner->mLocation, EX_BINARY); + nexp->mToken = mScanner->mToken; + nexp->mLeft = exp; + mScanner->NextToken(); + nexp->mRight = ParseAssemblerAddOperand(pcasm, pcoffset); + exp = nexp->ConstantFold(mErrors, mDataSection); + } + return exp; +} + + +Expression* Parser::ParseAssemblerAndOperand(Declaration* pcasm, int pcoffset) +{ + Expression* exp = ParseAssemblerShiftOperand(pcasm, pcoffset); + while (mScanner->mToken == TK_BINARY_AND) + { + Expression* nexp = new Expression(mScanner->mLocation, EX_BINARY); + nexp->mToken = mScanner->mToken; + nexp->mLeft = exp; + mScanner->NextToken(); + nexp->mRight = ParseAssemblerShiftOperand(pcasm, pcoffset); + exp = nexp->ConstantFold(mErrors, mDataSection); + } + return exp; +} + +Expression* Parser::ParseAssemblerOrOperand(Declaration* pcasm, int pcoffset) +{ + Expression* exp = ParseAssemblerAndOperand(pcasm, pcoffset); + while (mScanner->mToken == TK_BINARY_OR) + { + Expression* nexp = new Expression(mScanner->mLocation, EX_BINARY); + nexp->mToken = mScanner->mToken; + nexp->mLeft = exp; + mScanner->NextToken(); + nexp->mRight = ParseAssemblerAndOperand(pcasm, pcoffset); + exp = nexp->ConstantFold(mErrors, mDataSection); + } + return exp; +} + + Expression* Parser::ParseAssemblerOperand(Declaration* pcasm, int pcoffset) { if (mScanner->mToken == TK_LESS_THAN) @@ -3796,7 +10478,7 @@ Expression* Parser::ParseAssemblerOperand(Declaration* pcasm, int pcoffset) return exp; } else - return ParseAssemblerAddOperand(pcasm, pcoffset); + return ParseAssemblerOrOperand(pcasm, pcoffset); } void Parser::AddAssemblerRegister(const Ident* ident, int value) @@ -3977,7 +10659,8 @@ Expression* Parser::ParseAssembler(void) if ((ilast->mLeft->mDecValue->mType == DT_CONST_INTEGER && ilast->mLeft->mDecValue->mInteger < 256) || (ilast->mLeft->mDecValue->mType == DT_VARIABLE_REF && !(ilast->mLeft->mDecValue->mBase->mFlags & DTF_GLOBAL)) || (ilast->mLeft->mDecValue->mType == DT_VARIABLE && !(ilast->mLeft->mDecValue->mFlags & DTF_GLOBAL)) || - ilast->mLeft->mDecValue->mType == DT_ARGUMENT) + (ilast->mLeft->mDecValue->mType == DT_VARIABLE && (ilast->mLeft->mDecValue->mFlags & DTF_ZEROPAGE)) || + ilast->mLeft->mDecValue->mType == DT_ARGUMENT) { if (ilast->mAsmInsMode == ASMIM_ABSOLUTE && HasAsmInstructionMode(ilast->mAsmInsType, ASMIM_ZERO_PAGE)) ilast->mAsmInsMode = ASMIM_ZERO_PAGE; @@ -4064,6 +10747,21 @@ Expression* Parser::ParseAssembler(void) return ifirst; } +bool Parser::ExpectToken(Token token) +{ + if (mScanner->mToken == token) + { + return true; + } + else + { + char buffer[100]; + sprintf_s(buffer, "%s expected", TokenNames[token]); + mErrors->Error(mScanner->mLocation, EERR_SYNTAX, buffer); + return false; + } +} + bool Parser::ConsumeToken(Token token) { if (mScanner->mToken == token) @@ -4118,6 +10816,11 @@ void Parser::ParsePragma(void) } ConsumeToken(TK_CLOSE_PARENTHESIS); } + else if (!strcmp(mScanner->mTokenIdent->mString, "once")) + { + mScanner->MarkSourceOnce(); + mScanner->NextToken(); + } else if (!strcmp(mScanner->mTokenIdent->mString, "compile")) { mScanner->NextToken(); @@ -4712,6 +11415,19 @@ void Parser::ParsePragma(void) else mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Integer number for alignment expected"); } + else if (dec && dec->mType == DT_CONST_FUNCTION) + { + mScanner->NextToken(); + ConsumeToken(TK_COMMA); + + Expression* exp = ParseRExpression(); + if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_INTEGER) + { + dec->mAlignment = int(exp->mDecValue->mInteger); + } + else + mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Integer number for alignment expected"); + } else { mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Variable not found"); @@ -4870,6 +11586,10 @@ void Parser::ParsePragma(void) mCompilerOptions |= COPT_OPTIMIZE_AUTO_INLINE | COPT_OPTIMIZE_AUTO_INLINE; else if (ConsumeIdentIf("maxinline")) mCompilerOptions |= COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_AUTO_INLINE | COPT_OPTIMIZE_AUTO_INLINE_ALL; + else if (ConsumeIdentIf("constparams")) + mCompilerOptions |= COPT_OPTIMIZE_CONST_PARAMS; + else if (ConsumeIdentIf("noconstparams")) + mCompilerOptions &= ~COPT_OPTIMIZE_CONST_PARAMS; else mErrors->Error(mScanner->mLocation, EERR_INVALID_IDENTIFIER, "Invalid option"); @@ -4917,8 +11637,11 @@ void Parser::ParseNamespace(void) if (!ns) { ns = new Declaration(mScanner->mLocation, DT_NAMESPACE); - mScope->Insert(ident, ns); ns->mScope = new DeclarationScope(mScope, SLEVEL_NAMESPACE, ident); + ns->mIdent = ident; + ns->mQualIdent = mScope->Mangle(ident); + + mScope->Insert(ident, ns); } mScanner->NextToken(); @@ -4935,6 +11658,11 @@ void Parser::ParseNamespace(void) } else if (mScanner->mToken == TK_SEMICOLON) mScanner->NextToken(); + else if (mScanner->mToken == TK_TEMPLATE) + { + mScanner->NextToken(); + ParseTemplateDeclaration(nullptr); + } else if (mScanner->mToken == TK_NAMESPACE) { mScanner->NextToken(); @@ -5013,6 +11741,11 @@ void Parser::Parse(void) } else if (mScanner->mToken == TK_SEMICOLON) mScanner->NextToken(); + else if (mScanner->mToken == TK_TEMPLATE) + { + mScanner->NextToken(); + ParseTemplateDeclaration(nullptr); + } else if (mScanner->mToken == TK_NAMESPACE) { mScanner->NextToken(); diff --git a/oscar64/Parser.h b/oscar64/Parser.h index 44bcc7e..ade1d6c 100644 --- a/oscar64/Parser.h +++ b/oscar64/Parser.h @@ -10,10 +10,13 @@ public: Parser(Errors * errors, Scanner* scanner, CompilationUnits * compilationUnits); ~Parser(void); - DeclarationScope * mGlobals, * mScope; + Parser* Clone(void); + + DeclarationScope * mGlobals, * mScope, * mTemplateScope, * mCaptureScope; int mLocalIndex; CompilationUnits * mCompilationUnits; - Declaration * mThisPointer; + Declaration * mThisPointer, * mFunctionType, * mFunction, * mLambda, * mTempVars; + Token mCaptureToken; LinkerSection * mCodeSection, * mDataSection, * mBSSection; @@ -23,6 +26,7 @@ public: void Parse(void); protected: + bool ExpectToken(Token token); bool ConsumeToken(Token token); bool ConsumeTokenIf(Token token); bool ConsumeIdentIf(const char* ident); @@ -32,6 +36,10 @@ protected: bool mUnrollLoopPage; bool mInlineCall; + Declaration* AllocTempVar(Declaration* type); + void FreeTempVar(Declaration* var); + void FreeTempVarExp(Expression* exp); + uint8* ParseStringLiteral(int msize); void ParseNamespace(void); @@ -40,10 +48,24 @@ protected: Declaration * ParseFunctionDeclaration(Declaration* bdec); void PrependThisArgument(Declaration* fdec, Declaration * pthis); + void AppendMemberDestructor(Declaration* pthis); + void BuildMemberConstructor(Declaration* pthis, Declaration* cfunc); + Expression* BuildMemberInitializer(Expression* vexp); + void PrependMemberConstructor(Declaration* pthis, Declaration* cfunc); - Declaration* ParseBaseTypeDeclaration(uint64 flags); - Declaration* ParseDeclaration(Declaration* pdec, bool variable, bool expression, Declaration * pthis = nullptr); - Declaration* ParseStructDeclaration(uint64 flags, DecType dt); + void AddDefaultConstructors(Declaration* pthis); + + void ParseVariableInit(Declaration* ndec); + void AddMemberFunction(Declaration* dec, Declaration* mdec); + Declaration* FindBaseMemberFunction(Declaration* dec, Declaration* mdec); + + Expression * AddFunctionCallRefReturned(Expression * exp); + Expression* CleanupExpression(Expression* exp); + + Declaration* ParseBaseTypeQualify(bool qualified, Declaration* dec, const Ident *& pident); + Declaration* ParseBaseTypeDeclaration(uint64 flags, bool qualified, Declaration* ptempl = nullptr); + Declaration* ParseDeclaration(Declaration* pdec, bool variable, bool expression, Declaration * pthis = nullptr, Declaration * ptempl = nullptr); + Declaration* ParseStructDeclaration(uint64 flags, DecType dt, Declaration* ptempl = nullptr); Declaration* CopyConstantInitializer(int offset, Declaration* dtype, Expression* exp); Expression* ParseInitExpression(Declaration* dtype); @@ -58,19 +80,48 @@ protected: Expression* ParseAssemblerBaseOperand(Declaration* pcasm, int pcoffset); Expression* ParseAssemblerMulOperand(Declaration* pcasm, int pcoffset); Expression* ParseAssemblerAddOperand(Declaration* pcasm, int pcoffset); + Expression* ParseAssemblerShiftOperand(Declaration* pcasm, int pcoffset); + Expression* ParseAssemblerAndOperand(Declaration* pcasm, int pcoffset); + Expression* ParseAssemblerOrOperand(Declaration* pcasm, int pcoffset); Expression* ParseAssemblerOperand(Declaration * pcasm, int pcoffset); + Expression* CheckOperatorOverload(Expression* exp); + void AddAssemblerRegister(const Ident* ident, int value); Declaration* ParseQualIdent(void); + void SkipStatement(void); Expression* ParseStatement(void); Expression* ParseSwitchStatement(void); + Declaration* MemberLookup(Declaration* dtype, const Ident * ident, int& offset, uint64 & flags); + Expression* ParseQualify(Expression * exp); int OverloadDistance(Declaration* pdec, Expression* pexp); - void ResolveOverloadCall(Expression* cexp, Expression* pexp); + Expression * ResolveOverloadCall(Expression* exp, Expression * exp2 = nullptr); + Expression* CoerceExpression(Expression* exp, Declaration* type); + bool CanCoerceExpression(Expression* exp, Declaration* type); + void CompleteFunctionDefaultParams(Expression* exp); + void ExpandFunctionCallTemplate(Expression* exp); + + Declaration * ParseTemplateDeclaration(Declaration* pthis); + void ParseTemplateDeclarationBody(Declaration* tdec, Declaration* pthis); + Declaration* FunctionAutoParamsToTemplate(Declaration* fdec); + + int ExpansionDistance(Declaration* tdec, Declaration* spec); + Declaration* ParseTemplateExpansion(Declaration* tmpld, Declaration* expd); + void CompleteTemplateExpansion(Declaration* tmpld); + + Expression* ParseNewOperator(void); + Expression* ParseLambdaExpression(void); + + Declaration* OperatorResultType(Expression* exp); + + Expression* FindPackExpression(Expression* exp); + Expression* ExpandPackExpression(Expression* exp, Expression* pack, Expression* item); + Expression* ParseBinaryFoldExpression(Expression * exp); Expression* ParseSimpleExpression(bool lhs); Expression* ParsePrefixExpression(bool lhs); @@ -88,7 +139,9 @@ protected: Expression* ParseAssignmentExpression(bool lhs); Expression* ParseExpression(bool lhs); Expression* ParseRExpression(void); - Expression* ParseListExpression(void); + + Expression* ExpandArgumentPack(Expression * exp, Declaration* dec); + Expression* ParseListExpression(bool lhs); Expression* ParseParenthesisExpression(void); diff --git a/oscar64/Preprocessor.cpp b/oscar64/Preprocessor.cpp index 75bfb0e..787a048 100644 --- a/oscar64/Preprocessor.cpp +++ b/oscar64/Preprocessor.cpp @@ -608,6 +608,7 @@ bool SourceFile::Open(const char* name, const char* path, SourceFileMode mode) *p = '/'; p++; } + strcpy_s(mLocationFileName, mFileName); mMode = mode; mLimit = 0x10000; mFill = 0; @@ -731,7 +732,7 @@ bool Preprocessor::EmbedData(const char* reason, const char* name, bool local, i source->mUp = mSource; mSource = source; - mLocation.mFileName = mSource->mFileName; + mLocation.mFileName = mSource->mLocationFileName; mLocation.mLine = 0; mLine[0] = 0; @@ -791,7 +792,7 @@ bool Preprocessor::OpenSource(const char * reason, const char* name, bool local) source->mUp = mSource; mSource = source; - mLocation.mFileName = mSource->mFileName; + mLocation.mFileName = mSource->mLocationFileName; mLocation.mLine = 0; mLine[0] = 0; diff --git a/oscar64/Preprocessor.h b/oscar64/Preprocessor.h index 19e1d54..a849ba6 100644 --- a/oscar64/Preprocessor.h +++ b/oscar64/Preprocessor.h @@ -39,7 +39,7 @@ enum SourceFileDecoder class SourceFile { public: - char mFileName[MAXPATHLEN]; + char mFileName[MAXPATHLEN], mLocationFileName[MAXPATHLEN]; SourceFile * mUp, * mNext; Location mLocation; diff --git a/oscar64/Scanner.cpp b/oscar64/Scanner.cpp index 923167c..ca60f20 100644 --- a/oscar64/Scanner.cpp +++ b/oscar64/Scanner.cpp @@ -143,17 +143,31 @@ const char* TokenNames[] = "'#ifdef'", "'#ifndef'", "'#pragma'", + "'#line'", "'#assign'", "'#repeat'", "'#until'", "'#embed'", + "'#for'", "'##'", "'namespace'", "'using'", "'this'", - "'::'" + "'::'", + "'class'", + "'public'", + "'protected'", + "'private'", + "'new'", + "'delete'", + "'virtual'", + "'operator'", + "'template'", + "'friend'", + "'constexpr'", + "'typename'", }; @@ -298,6 +312,25 @@ Macro* MacroDict::Lookup(const Ident* ident) } +TokenSequence::TokenSequence(Scanner* scanner) + : mNext(nullptr), mLocation(scanner->mLocation), mToken(scanner->mToken), + mTokenIdent(scanner->mTokenIdent), + mTokenInteger(scanner->mTokenInteger), mTokenNumber(scanner->mTokenNumber), + mTokenString(nullptr) +{ + if (mToken == TK_STRING) + { + int ssize = strlen(scanner->mTokenString); + char * str = new char[ssize + 1]; + strcpy_s(str, ssize + 1, scanner->mTokenString); + mTokenString = str; + } +} + +TokenSequence::~TokenSequence(void) +{ + delete[] mTokenString; +} Scanner::Scanner(Errors* errors, Preprocessor* preprocessor) : mErrors(errors), mPreprocessor(preprocessor) @@ -310,10 +343,16 @@ Scanner::Scanner(Errors* errors, Preprocessor* preprocessor) mAssemblerMode = false; mPreprocessorMode = false; mMacroExpansion = nullptr; + mMacroExpansionDepth = 0; mDefines = new MacroDict(); mDefineArguments = nullptr; mToken = TK_NONE; + mUngetToken = TK_NONE; + mReplay = nullptr; + mRecord = mRecordLast = nullptr; + + mOnceDict = new MacroDict(); NextChar(); @@ -326,6 +365,26 @@ Scanner::~Scanner(void) } +void Scanner::BeginRecord(void) +{ + mRecord = mRecordLast = new TokenSequence(this); +} + +TokenSequence* Scanner::CompleteRecord(void) +{ + TokenSequence* seq = mRecord; + mRecord = mRecordLast = nullptr; + return seq; +} + +const TokenSequence* Scanner::Replay(const TokenSequence* replay) +{ + const TokenSequence* seq = mReplay; + mReplay = replay; + NextToken(); + return seq; +} + const char* Scanner::TokenName(Token token) const { return TokenNames[token]; @@ -402,7 +461,40 @@ void Scanner::AddMacro(const Ident* ident, const char* value) mDefines->Insert(macro); } +void Scanner::MarkSourceOnce(void) +{ + const Ident* fident = Ident::Unique(mPreprocessor->mSource->mFileName); + + Macro* macro = new Macro(fident, nullptr); + mOnceDict->Insert(macro); +} + void Scanner::NextToken(void) +{ + if (mReplay) + { + mLocation = mReplay->mLocation; + mToken = mReplay->mToken; + + mTokenIdent = mReplay->mTokenIdent; + mTokenNumber = mReplay->mTokenNumber; + mTokenInteger = mReplay->mTokenInteger; + if (mReplay->mTokenString) + strcpy_s(mTokenString, mReplay->mTokenString); + + mReplay = mReplay->mNext; + } + else + NextPreToken(); + + if (mRecord) + { + mRecordLast->mNext = new TokenSequence(this); + mRecordLast = mRecordLast->mNext; + } +} + +void Scanner::NextPreToken(void) { for (;;) { @@ -450,7 +542,7 @@ void Scanner::NextToken(void) mPreprocessorMode = true; mPrepCondFalse = 0; - NextToken(); + NextPreToken(); int64 v = PrepParseConditional(); if (v) { @@ -493,6 +585,8 @@ void Scanner::NextToken(void) { if (!mPreprocessor->OpenSource("Including", mTokenString, true)) mErrors->Error(mLocation, EERR_FILE_NOT_FOUND, "Could not open source file", mTokenString); + else if (mOnceDict->Lookup(Ident::Unique(mPreprocessor->mSource->mFileName))) + mPreprocessor->CloseSource(); } else if (mToken == TK_LESS_THAN) { @@ -500,8 +594,102 @@ void Scanner::NextToken(void) StringToken('>', 'a'); if (!mPreprocessor->OpenSource("Including", mTokenString, false)) mErrors->Error(mLocation, EERR_FILE_NOT_FOUND, "Could not open source file", mTokenString); + else if (mOnceDict->Lookup(Ident::Unique(mPreprocessor->mSource->mFileName))) + mPreprocessor->CloseSource(); } } + else if (mToken == TK_PREP_LINE) + { + mPreprocessorMode = true; + NextPreToken(); + int l = mLocation.mLine; + int64 v = PrepParseConditional(); + if (mLocation.mLine == l && mToken == TK_STRING) + { + strcpy_s(mPreprocessor->mSource->mLocationFileName, mTokenString); + NextRawToken(); + } + mPreprocessor->mLocation.mLine = int(v) + mLocation.mLine - l; + mPreprocessorMode = false; + } + else if (mToken == TK_PREP_FOR) + { + NextRawToken(); + if (mToken == TK_OPEN_PARENTHESIS) + { + NextRawToken(); + Macro* macro = new Macro(Ident::Unique("@for"), nullptr); + if (mToken == TK_IDENT) + { + const Ident* loopindex = mTokenIdent; + NextRawToken(); + + if (mToken == TK_COMMA) + { + mPreprocessorMode = true; + NextPreToken(); + int64 loopCount = PrepParseConditional(); + mPreprocessorMode = false; + + if (mToken == TK_CLOSE_PARENTHESIS) + { + int slen = mOffset; + bool quote = false; + while (mLine[slen] && (quote || mLine[slen] != '/' || mLine[slen + 1] != '/')) + { + if (mLine[slen] == '"') + quote = !quote; + slen++; + } + + macro->SetString(mLine + mOffset, slen - mOffset); + + mOffset = slen; + while (mLine[mOffset]) + mOffset++; + + if (loopCount > 0) + { + MacroExpansion* ex = new MacroExpansion(); + MacroDict* scope = mDefineArguments; + mDefineArguments = new MacroDict(); + + Macro* arg = new Macro(loopindex, scope); + mDefineArguments->Insert(arg); + + arg->SetString("0"); + + ex->mLine = mLine; + ex->mOffset = mOffset; + ex->mLink = mMacroExpansion; + ex->mChar = mTokenChar; + ex->mLoopCount = 0; + ex->mLoopIndex = arg; + ex->mLoopLimit = loopCount; + + mMacroExpansion = ex; + mMacroExpansionDepth++; + if (mMacroExpansionDepth > 1024) + mErrors->Error(mLocation, EFATAL_MACRO_EXPANSION_DEPTH, "Maximum macro expansion depth exceeded", mTokenIdent); + mLine = macro->mString; + mOffset = 0; + NextChar(); + } + } + else + mErrors->Error(mLocation, EERR_INVALID_PREPROCESSOR, "')' expected in defined parameter list"); + } + else + mErrors->Error(mLocation, EERR_INVALID_PREPROCESSOR, "',' expected"); + + } + else + mErrors->Error(mLocation, EERR_INVALID_PREPROCESSOR, "'loop index variable expected"); + } + else + mErrors->Error(mLocation, EERR_INVALID_PREPROCESSOR, "'('(' expected"); + + } else if (mToken == TK_PREP_DEFINE) { NextRawToken(); @@ -598,7 +786,7 @@ void Scanner::NextToken(void) else if (mToken == TK_PREP_IF) { mPreprocessorMode = true; - NextToken(); + NextPreToken(); int64 v = PrepParseConditional(); if (v) mPrepCondDepth++; @@ -616,7 +804,7 @@ void Scanner::NextToken(void) { const Ident* ident = mTokenIdent; - NextToken(); + NextPreToken(); int64 v = PrepParseConditional(); Macro* macro = mDefines->Lookup(ident); @@ -640,7 +828,7 @@ void Scanner::NextToken(void) else if (mToken == TK_PREP_UNTIL) { mPreprocessorMode = true; - NextToken(); + NextPreToken(); int64 v = PrepParseConditional(); if (mToken != TK_EOL) mErrors->Error(mLocation, ERRR_PREPROCESSOR, "End of line expected"); @@ -808,6 +996,9 @@ void Scanner::NextToken(void) ex->mChar = mTokenChar; mMacroExpansion = ex; + mMacroExpansionDepth++; + if (mMacroExpansionDepth > 1024) + mErrors->Error(mLocation, EFATAL_MACRO_EXPANSION_DEPTH, "Maximum macro expansion depth exceeded", mTokenIdent); mLine = def->mString; mOffset = 0; NextChar(); @@ -866,7 +1057,12 @@ void Scanner::NextToken(void) void Scanner::NextRawToken(void) { - if (mToken != TK_EOF) + if (mUngetToken) + { + mToken = mUngetToken; + mUngetToken = TK_NONE; + } + else if (mToken != TK_EOF) { mToken = TK_ERROR; @@ -955,14 +1151,14 @@ void Scanner::NextRawToken(void) } } NextChar(); - NextToken(); + NextPreToken(); } else if (mTokenChar == '/') { NextChar(); while (!IsLineBreak(mTokenChar) && NextChar()) ; - NextToken(); + NextPreToken(); } else if (mTokenChar == '=') { @@ -1174,6 +1370,7 @@ void Scanner::NextRawToken(void) { int n = 0; char tkprep[128]; + tkprep[0] = 0; while (NextChar() && IsAlpha(mTokenChar)) { @@ -1202,6 +1399,8 @@ void Scanner::NextRawToken(void) mToken = TK_PREP_ENDIF; else if (!strcmp(tkprep, "pragma")) mToken = TK_PREP_PRAGMA; + else if (!strcmp(tkprep, "line")) + mToken = TK_PREP_LINE; else if (!strcmp(tkprep, "assign")) mToken = TK_PREP_ASSIGN; else if (!strcmp(tkprep, "repeat")) @@ -1210,6 +1409,8 @@ void Scanner::NextRawToken(void) mToken = TK_PREP_UNTIL; else if (!strcmp(tkprep, "embed")) mToken = TK_PREP_EMBED; + else if (!strcmp(tkprep, "for")) + mToken = TK_PREP_FOR; else mErrors->Error(mLocation, EERR_INVALID_PREPROCESSOR, "Invalid preprocessor command", tkprep); } @@ -1268,6 +1469,8 @@ void Scanner::NextRawToken(void) { int n = 0; char tkident[256]; + tkident[0] = 0; + for (;;) { if (IsIdentChar(mTokenChar)) @@ -1394,6 +1597,165 @@ void Scanner::NextRawToken(void) mToken = TK_USING; else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "this")) mToken = TK_THIS; + else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "class")) + mToken = TK_CLASS; + else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "public")) + mToken = TK_PUBLIC; + else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "protected")) + mToken = TK_PROTECTED; + else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "private")) + mToken = TK_PRIVATE; + else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "new")) + mToken = TK_NEW; + else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "delete")) + mToken = TK_DELETE; + else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "virtual")) + mToken = TK_VIRTUAL; + else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "template")) + mToken = TK_TEMPLATE; + else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "friend")) + mToken = TK_FRIEND; + else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "constexpr")) + mToken = TK_CONSTEXPR; + else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "typename")) + mToken = TK_TYPENAME; + else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "operator")) + { + NextRawToken(); + switch (mToken) + { + case TK_ASSIGN: + mTokenIdent = Ident::Unique("operator="); + break; + + case TK_ASSIGN_ADD: + mTokenIdent = Ident::Unique("operator+="); + break; + case TK_ASSIGN_SUB: + mTokenIdent = Ident::Unique("operator-="); + break; + case TK_ASSIGN_MUL: + mTokenIdent = Ident::Unique("operator*="); + break; + case TK_ASSIGN_DIV: + mTokenIdent = Ident::Unique("operator/="); + break; + case TK_ASSIGN_MOD: + mTokenIdent = Ident::Unique("operator%="); + break; + case TK_ASSIGN_SHL: + mTokenIdent = Ident::Unique("operator<<="); + break; + case TK_ASSIGN_SHR: + mTokenIdent = Ident::Unique("operator>>="); + break; + case TK_ASSIGN_AND: + mTokenIdent = Ident::Unique("operator&="); + break; + case TK_ASSIGN_XOR: + mTokenIdent = Ident::Unique("operator^="); + break; + case TK_ASSIGN_OR: + mTokenIdent = Ident::Unique("operator|="); + break; + + case TK_ADD: + mTokenIdent = Ident::Unique("operator+"); + break; + case TK_SUB: + mTokenIdent = Ident::Unique("operator-"); + break; + case TK_MUL: + mTokenIdent = Ident::Unique("operator*"); + break; + case TK_DIV: + mTokenIdent = Ident::Unique("operator/"); + break; + case TK_MOD: + mTokenIdent = Ident::Unique("operator%"); + break; + + case TK_BINARY_AND: + mTokenIdent = Ident::Unique("operator&"); + break; + case TK_BINARY_OR: + mTokenIdent = Ident::Unique("operator|"); + break; + case TK_BINARY_XOR: + mTokenIdent = Ident::Unique("operator^"); + break; + case TK_LOGICAL_NOT: + mTokenIdent = Ident::Unique("operator!"); + break; + + case TK_LEFT_SHIFT: + mTokenIdent = Ident::Unique("operator<<"); + break; + case TK_RIGHT_SHIFT: + mTokenIdent = Ident::Unique("operator>>"); + break; + + case TK_EQUAL: + mTokenIdent = Ident::Unique("operator=="); + break; + case TK_NOT_EQUAL: + mTokenIdent = Ident::Unique("operator!="); + break; + case TK_GREATER_THAN: + mTokenIdent = Ident::Unique("operator>"); + break; + case TK_GREATER_EQUAL: + mTokenIdent = Ident::Unique("operator>="); + break; + case TK_LESS_THAN: + mTokenIdent = Ident::Unique("operator<"); + break; + case TK_LESS_EQUAL: + mTokenIdent = Ident::Unique("operator<="); + break; + + case TK_INC: + mTokenIdent = Ident::Unique("operator++"); + break; + case TK_DEC: + mTokenIdent = Ident::Unique("operator--"); + break; + + case TK_OPEN_BRACKET: + NextRawToken(); + if (mToken != TK_CLOSE_BRACKET) + mErrors->Error(mLocation, EERR_INVALID_OPERATOR, "']' expected"); + mTokenIdent = Ident::Unique("operator[]"); + break; + + case TK_OPEN_PARENTHESIS: + NextRawToken(); + if (mToken != TK_CLOSE_PARENTHESIS) + mErrors->Error(mLocation, EERR_INVALID_OPERATOR, "')' expected"); + mTokenIdent = Ident::Unique("operator()"); + break; + + case TK_ARROW: + mTokenIdent = Ident::Unique("operator->"); + break; + + case TK_NEW: + mTokenIdent = Ident::Unique("operator-new"); + break; + case TK_DELETE: + mTokenIdent = Ident::Unique("operator-delete"); + break; + + default: + // dirty little hack to implement token preview, got to fix + // this with an infinit preview sequence at one point + mUngetToken = mToken; + mToken = TK_OPERATOR; + return; + } + + mToken = TK_IDENT; + } else { mToken = TK_IDENT; @@ -1655,6 +2017,19 @@ bool Scanner::NextChar(void) { if (mMacroExpansion) { + if (mMacroExpansion->mLoopIndex) + { + mMacroExpansion->mLoopCount++; + if (mMacroExpansion->mLoopCount < mMacroExpansion->mLoopLimit) + { + char buffer[20]; + sprintf_s(buffer, "%d", int(mMacroExpansion->mLoopCount)); + mMacroExpansion->mLoopIndex->SetString(buffer); + mOffset = 0; + continue; + } + } + MacroExpansion* mac = mMacroExpansion->mLink; // delete mDefineArguments; @@ -1665,6 +2040,8 @@ bool Scanner::NextChar(void) delete mMacroExpansion; mMacroExpansion = mac; + mMacroExpansionDepth--; + return true; } else if (mPreprocessor->NextLine()) @@ -1877,32 +2254,32 @@ int64 Scanner::PrepParseSimple(void) case TK_INTEGERL: case TK_INTEGERUL: v = mTokenInteger; - NextToken(); + NextPreToken(); break; case TK_SUB: - NextToken(); + NextPreToken(); v = -PrepParseSimple(); break; case TK_LOGICAL_NOT: - NextToken(); + NextPreToken(); v = !PrepParseSimple(); break; case TK_BINARY_NOT: - NextToken(); + NextPreToken(); v = ~PrepParseSimple(); break; case TK_OPEN_PARENTHESIS: - NextToken(); + NextPreToken(); v = PrepParseConditional(); if (mToken == TK_CLOSE_PARENTHESIS) - NextToken(); + NextPreToken(); else mErrors->Error(mLocation, ERRR_PREPROCESSOR, "')' expected"); break; case TK_IDENT: if (strcmp(mTokenIdent->mString, "defined") == 0) { - NextToken(); + NextPreToken(); if (mToken == TK_OPEN_PARENTHESIS) { NextRawToken(); @@ -1917,13 +2294,13 @@ int64 Scanner::PrepParseSimple(void) v = 1; else v = 0; - NextToken(); + NextPreToken(); } else mErrors->Error(mLocation, ERRR_PREPROCESSOR, "Identifier expected"); if (mToken == TK_CLOSE_PARENTHESIS) - NextToken(); + NextPreToken(); else mErrors->Error(mLocation, ERRR_PREPROCESSOR, "')' expected"); } @@ -1936,7 +2313,7 @@ int64 Scanner::PrepParseSimple(void) default: mErrors->Error(mLocation, ERRR_PREPROCESSOR, "Invalid preprocessor token", TokenName(mToken)); if (mToken != TK_EOL) - NextToken(); + NextPreToken(); } return v; @@ -1951,11 +2328,11 @@ int64 Scanner::PrepParseMul(void) switch (mToken) { case TK_MUL: - NextToken(); + NextPreToken(); v *= PrepParseSimple(); break; case TK_DIV: - NextToken(); + NextPreToken(); u = PrepParseSimple(); if (u == 0) mErrors->Error(mLocation, ERRR_PREPROCESSOR, "Division by zero"); @@ -1983,11 +2360,11 @@ int64 Scanner::PrepParseAdd(void) switch (mToken) { case TK_ADD: - NextToken(); + NextPreToken(); v += PrepParseMul(); break; case TK_SUB: - NextToken(); + NextPreToken(); v -= PrepParseMul(); break; default: @@ -2004,11 +2381,11 @@ int64 Scanner::PrepParseShift(void) switch (mToken) { case TK_LEFT_SHIFT: - NextToken(); + NextPreToken(); v <<= PrepParseAdd(); break; case TK_RIGHT_SHIFT: - NextToken(); + NextPreToken(); v >>= PrepParseAdd(); break; default: @@ -2025,27 +2402,27 @@ int64 Scanner::PrepParseRel(void) switch (mToken) { case TK_LESS_THAN: - NextToken(); + NextPreToken(); v = v < PrepParseShift(); break; case TK_GREATER_THAN: - NextToken(); + NextPreToken(); v = v > PrepParseShift(); break; case TK_LESS_EQUAL: - NextToken(); + NextPreToken(); v = v <= PrepParseShift(); break; case TK_GREATER_EQUAL: - NextToken(); + NextPreToken(); v = v >= PrepParseShift(); break; case TK_EQUAL: - NextToken(); + NextPreToken(); v = v == PrepParseShift(); break; case TK_NOT_EQUAL: - NextToken(); + NextPreToken(); v = v != PrepParseShift(); break; default: @@ -2060,7 +2437,7 @@ int64 Scanner::PrepParseBinaryAnd(void) int64 v = PrepParseRel(); while (mToken == TK_BINARY_AND) { - NextToken(); + NextPreToken(); v &= PrepParseRel(); } return v; @@ -2071,7 +2448,7 @@ int64 Scanner::PrepParseBinaryXor(void) int64 v = PrepParseBinaryAnd(); while (mToken == TK_BINARY_XOR) { - NextToken(); + NextPreToken(); v ^= PrepParseBinaryAnd(); } return v; @@ -2082,7 +2459,7 @@ int64 Scanner::PrepParseBinaryOr(void) int64 v = PrepParseBinaryXor(); while (mToken == TK_BINARY_OR) { - NextToken(); + NextPreToken(); v |= PrepParseBinaryXor(); } return v; @@ -2093,7 +2470,7 @@ int64 Scanner::PrepParseLogicalAnd(void) int64 v = PrepParseBinaryOr(); while (mToken == TK_LOGICAL_AND) { - NextToken(); + NextPreToken(); if (!PrepParseBinaryOr()) v = 0; } @@ -2105,7 +2482,7 @@ int64 Scanner::PrepParseLogicalOr(void) int64 v = PrepParseLogicalAnd(); while (mToken == TK_LOGICAL_OR) { - NextToken(); + NextPreToken(); if (PrepParseLogicalAnd()) v = 1; } @@ -2117,10 +2494,10 @@ int64 Scanner::PrepParseConditional(void) int64 v = PrepParseLogicalOr(); if (mToken == TK_QUESTIONMARK) { - NextToken(); + NextPreToken(); int64 vt = PrepParseConditional(); if (mToken == TK_COLON) - NextToken(); + NextPreToken(); else mErrors->Error(mLocation, ERRR_PREPROCESSOR, "':' expected"); int64 vf = PrepParseConditional(); diff --git a/oscar64/Scanner.h b/oscar64/Scanner.h index 08a4992..1f41adc 100644 --- a/oscar64/Scanner.h +++ b/oscar64/Scanner.h @@ -141,11 +141,13 @@ enum Token TK_PREP_IFDEF, TK_PREP_IFNDEF, TK_PREP_PRAGMA, + TK_PREP_LINE, TK_PREP_ASSIGN, TK_PREP_REPEAT, TK_PREP_UNTIL, TK_PREP_EMBED, + TK_PREP_FOR, TK_PREP_CONCAT, @@ -153,6 +155,18 @@ enum Token TK_USING, TK_THIS, TK_COLCOLON, + TK_CLASS, + TK_PUBLIC, + TK_PROTECTED, + TK_PRIVATE, + TK_NEW, + TK_DELETE, + TK_VIRTUAL, + TK_OPERATOR, + TK_TEMPLATE, + TK_FRIEND, + TK_CONSTEXPR, + TK_TYPENAME, NUM_TOKENS }; @@ -196,6 +210,23 @@ protected: MacroDict * mParent; }; +class Scanner; + +struct TokenSequence +{ + TokenSequence * mNext; + Location mLocation; + Token mToken; + + const Ident * mTokenIdent; + const char * mTokenString; + double mTokenNumber; + int64 mTokenInteger; + + TokenSequence(Scanner* scanner); + ~TokenSequence(void); +}; + class Scanner { public: @@ -206,6 +237,11 @@ public: void NextToken(void); + void BeginRecord(void); + TokenSequence* CompleteRecord(void); + + const TokenSequence* Replay(const TokenSequence * sequence); + void Warning(const char * error); void Error(const char * error); @@ -239,8 +275,10 @@ public: uint64 mCompilerOptions; void AddMacro(const Ident* ident, const char* value); + void MarkSourceOnce(void); protected: void NextRawToken(void); + void NextPreToken(void); struct MacroExpansion { @@ -248,10 +286,24 @@ protected: const char * mLine; int mOffset; char mChar; + Macro * mLoopIndex; + int64 mLoopCount, mLoopLimit; MacroDict* mDefinedArguments; + + MacroExpansion(void) + : mLink(nullptr), mLine(nullptr), mOffset(0), mChar(0), mLoopIndex(nullptr), mLoopCount(0), mLoopLimit(0), mDefinedArguments(nullptr) + {} + } * mMacroExpansion; - MacroDict* mDefines, * mDefineArguments; + int mMacroExpansionDepth; + + MacroDict* mDefines, * mDefineArguments, * mOnceDict; + + Token mUngetToken; + + const TokenSequence* mReplay; + TokenSequence* mRecord, * mRecordLast; void StringToken(char terminator, char mode); void CharToken(char mode); diff --git a/oscar64/oscar64.cpp b/oscar64/oscar64.cpp index 1ad5bb6..b588cd6 100644 --- a/oscar64/oscar64.cpp +++ b/oscar64/oscar64.cpp @@ -74,7 +74,7 @@ int main2(int argc, const char** argv) #else strcpy(strProductName, "oscar64"); - strcpy(strProductVersion, "1.20.208"); + strcpy(strProductVersion, "1.26.225"); #ifdef __APPLE__ uint32_t length = sizeof(basePath); @@ -102,6 +102,8 @@ int main2(int argc, const char** argv) Compiler* compiler = new Compiler(); + compiler->mCompilerOptions |= COPT_NATIVE; + Location loc; GrowingArray dataFiles(nullptr); @@ -114,7 +116,8 @@ int main2(int argc, const char** argv) strcpy_s(crtPath, includePath); strcat_s(crtPath, "crt.c"); - bool emulate = false, profile = false, trace = false; + bool emulate = false, profile = false; + int trace = 0; targetPath[0] = 0; diskPath[0] = 0; @@ -177,7 +180,10 @@ int main2(int argc, const char** argv) else if (arg[1] == 'n') { compiler->mCompilerOptions |= COPT_NATIVE; - compiler->AddDefine(Ident::Unique("OSCAR_NATIVE_ALL"), "1"); + } + else if (arg[1] == 'b' && arg[2] == 'c') + { + compiler->mCompilerOptions &= ~COPT_NATIVE; } else if (arg[1] == 'O') { @@ -197,6 +203,10 @@ int main2(int argc, const char** argv) compiler->mCompilerOptions |= COPT_OPTIMIZE_AUTO_INLINE; else if (arg[2] == 'z') compiler->mCompilerOptions |= COPT_OPTIMIZE_AUTO_ZEROPAGE; + else if (arg[2] == 'p') + compiler->mCompilerOptions |= COPT_OPTIMIZE_CONST_PARAMS; + else if (arg[2] == 'g') + compiler->mCompilerOptions |= COPT_OPTIMIZE_GLOBAL; } else if (arg[1] == 'e') { @@ -204,7 +214,9 @@ int main2(int argc, const char** argv) if (arg[2] == 'p') profile = true; else if (arg[2] == 't') - trace = true; + trace = 2; + else if (arg[2] == 'b') + trace = 1; } else if (arg[1] == 'd') { @@ -261,6 +273,16 @@ int main2(int argc, const char** argv) } } + if (compiler->mCompilerOptions & COPT_NATIVE) + { + compiler->AddDefine(Ident::Unique("OSCAR_NATIVE_ALL"), "1"); + } + + + // REMOVE ME + // compiler->mCompilerOptions |= COPT_OPTIMIZE_GLOBAL; + // REMOVE ME + char basicStart[10]; strcpy_s(basicStart, "0x0801"); @@ -481,7 +503,7 @@ int main2(int argc, const char** argv) } else { - printf("oscar64 {-i=includePath} [-o=output.prg] [-rt=runtime.c] [-tf=target] [-tm=machine] [-e] [-n] [-g] [-O(0|1|2|3)] {-dSYMBOL[=value]} [-v] [-d64=diskname] {-f[z]=file.xxx} {source.c}\n"); + printf("oscar64 {-i=includePath} [-o=output.prg] [-rt=runtime.c] [-tf=target] [-tm=machine] [-e] [-n] [-g] [-O(0|1|2|3)] [-pp] {-dSYMBOL[=value]} [-v] [-d64=diskname] {-f[z]=file.xxx} {source.c}\n"); return 0; } diff --git a/oscar64/oscar64.rc b/oscar64/oscar64.rc index 80cd98b..60ea412 100644 --- a/oscar64/oscar64.rc +++ b/oscar64/oscar64.rc @@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,20,208,0 - PRODUCTVERSION 1,20,208,0 + FILEVERSION 1,26,225,0 + PRODUCTVERSION 1,26,225,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -43,12 +43,12 @@ BEGIN BEGIN VALUE "CompanyName", "oscar64" VALUE "FileDescription", "oscar64 compiler" - VALUE "FileVersion", "1.20.208.0" + VALUE "FileVersion", "1.26.225.0" VALUE "InternalName", "oscar64.exe" VALUE "LegalCopyright", "Copyright (C) 2021" VALUE "OriginalFilename", "oscar64.exe" VALUE "ProductName", "oscar64" - VALUE "ProductVersion", "1.20.208.0" + VALUE "ProductVersion", "1.26.225.0" END END BLOCK "VarFileInfo" diff --git a/oscar64/oscar64.vcxproj b/oscar64/oscar64.vcxproj index 619162a..56e143c 100644 --- a/oscar64/oscar64.vcxproj +++ b/oscar64/oscar64.vcxproj @@ -158,12 +158,14 @@ + + @@ -184,12 +186,14 @@ + + diff --git a/oscar64/oscar64.vcxproj.filters b/oscar64/oscar64.vcxproj.filters index d4cd396..98e8470 100644 --- a/oscar64/oscar64.vcxproj.filters +++ b/oscar64/oscar64.vcxproj.filters @@ -78,6 +78,12 @@ Source Files + + Source Files + + + Source Files + @@ -152,6 +158,12 @@ Header Files + + Header Files + + + Header Files + diff --git a/oscar64setup/oscar64setup.vdproj b/oscar64setup/oscar64setup.vdproj index df8af4f..0eea676 100644 --- a/oscar64setup/oscar64setup.vdproj +++ b/oscar64setup/oscar64setup.vdproj @@ -52,6 +52,18 @@ } "Entry" { + "MsmKey" = "8:_071415C872DB4A94B28137BD7FE1F669" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_071CF34574024DBD95D2203D6E4279D0" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_0819C3D33D0942EF9E319C754E6C43D8" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" @@ -82,6 +94,12 @@ } "Entry" { + "MsmKey" = "8:_0EE9160CA4D44278A3929B0A4E0789F8" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_1088B8AF518A4841A419B723AEB6C2BA" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" @@ -94,6 +112,12 @@ } "Entry" { + "MsmKey" = "8:_12ACD00110E34BF9A3C06E00A16449D9" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_12C998C755E643038CDF5D9F56983ECA" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" @@ -124,6 +148,12 @@ } "Entry" { + "MsmKey" = "8:_1A605A19ADAD413CB754523D4FE7C32F" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_1AAB1F90101E40B6937A64FD4BF9D469" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" @@ -178,6 +208,12 @@ } "Entry" { + "MsmKey" = "8:_26E38AB4F85C4C9DB284803C4A3473F3" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_29ED5D9B606D45DA80CFF329A7643DC8" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" @@ -412,6 +448,12 @@ } "Entry" { + "MsmKey" = "8:_63A827ECF1BC48CE96DB82B554FC323D" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_64C12019C1114C3282B32CD6B866C20A" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" @@ -448,6 +490,12 @@ } "Entry" { + "MsmKey" = "8:_6EE9325B01F74FFF8146A6AD7FE71A31" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_7127D91089DA4162BB8DC8EAB0C107F0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" @@ -484,6 +532,12 @@ } "Entry" { + "MsmKey" = "8:_7789738FE8854CE488C5248434E47211" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_79985361F09A43299E258E1A8E5ED934" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" @@ -550,6 +604,18 @@ } "Entry" { + "MsmKey" = "8:_82C11E2A96FE49E399EEEAC2FEE9DCDC" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_85AF458C41734A099F879A01E6CEB35F" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_8827B6B07A1C4B32B08DF784E090381D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" @@ -664,6 +730,12 @@ } "Entry" { + "MsmKey" = "8:_A14BC161099E420286E6A1595596D0F0" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_A18504BA88CE40128ED44BD1854F0A33" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" @@ -700,6 +772,12 @@ } "Entry" { + "MsmKey" = "8:_A62BFFC051304130B85007261BC97749" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_A8820F3446B9408E88692E85817C1B07" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" @@ -934,12 +1012,24 @@ } "Entry" { + "MsmKey" = "8:_D38EB85FE8E3492DA4BD8E6E4F7CEBEB" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_D52B954DFBCE4EB0932433DE7FCE9090" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { + "MsmKey" = "8:_D651A6B3342C4D1ABC7FE873E253A1C5" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_D76DA8C7D3964C93ABE193A7B53A0A9B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" @@ -970,6 +1060,12 @@ } "Entry" { + "MsmKey" = "8:_DBCD7B3D63C34E31A882799F3C82F0E9" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_DE1058FFA9E149D1909C819592A12273" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" @@ -988,6 +1084,12 @@ } "Entry" { + "MsmKey" = "8:_E11BDCFFB9944A1F893FE4EC86ACCD6C" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_E218D776D9014F99BE2B046AEF2D6E8B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" @@ -1048,6 +1150,18 @@ } "Entry" { + "MsmKey" = "8:_EC599856E7AE44F4A2F51AA76A4D044C" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_ED20DE3FDC8A400296E92AE0D37D8665" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_ED5FED616EA64689AB793E5D8BD3F13D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" @@ -1090,6 +1204,12 @@ } "Entry" { + "MsmKey" = "8:_F472CF5FA6CF43649B4CD8E5F204DA65" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_F715B9FA6E0048388F451AB4670FD1EB" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" @@ -1331,6 +1451,46 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_071415C872DB4A94B28137BD7FE1F669" + { + "SourcePath" = "8:..\\include\\opp\\slab.h" + "TargetName" = "8:slab.h" + "Tag" = "8:" + "Folder" = "8:_D76A1802AFD04C48A519C9F8700E53CC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_071CF34574024DBD95D2203D6E4279D0" + { + "SourcePath" = "8:..\\include\\opp\\iostream.h" + "TargetName" = "8:iostream.h" + "Tag" = "8:" + "Folder" = "8:_D76A1802AFD04C48A519C9F8700E53CC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_0819C3D33D0942EF9E319C754E6C43D8" { "SourcePath" = "8:..\\include\\gfx\\bitmap.h" @@ -1431,6 +1591,26 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_0EE9160CA4D44278A3929B0A4E0789F8" + { + "SourcePath" = "8:..\\include\\opp\\vector.h" + "TargetName" = "8:vector.h" + "Tag" = "8:" + "Folder" = "8:_D76A1802AFD04C48A519C9F8700E53CC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1088B8AF518A4841A419B723AEB6C2BA" { "SourcePath" = "8:..\\samples\\fractals\\mbmulti3d.c" @@ -1471,6 +1651,26 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_12ACD00110E34BF9A3C06E00A16449D9" + { + "SourcePath" = "8:..\\include\\opp\\string.cpp" + "TargetName" = "8:string.cpp" + "Tag" = "8:" + "Folder" = "8:_D76A1802AFD04C48A519C9F8700E53CC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_12C998C755E643038CDF5D9F56983ECA" { "SourcePath" = "8:..\\include\\fixmath.h" @@ -1571,6 +1771,26 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1A605A19ADAD413CB754523D4FE7C32F" + { + "SourcePath" = "8:..\\include\\opp\\sstream.cpp" + "TargetName" = "8:sstream.cpp" + "Tag" = "8:" + "Folder" = "8:_D76A1802AFD04C48A519C9F8700E53CC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1AAB1F90101E40B6937A64FD4BF9D469" { "SourcePath" = "8:..\\include\\setjmp.c" @@ -1751,6 +1971,26 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_26E38AB4F85C4C9DB284803C4A3473F3" + { + "SourcePath" = "8:..\\include\\new" + "TargetName" = "8:new" + "Tag" = "8:" + "Folder" = "8:_7C0D28C244F14A21B5F72213BBE59B6F" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_29ED5D9B606D45DA80CFF329A7643DC8" { "SourcePath" = "8:..\\samples\\kernalio\\diskdir.c" @@ -2531,6 +2771,26 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_63A827ECF1BC48CE96DB82B554FC323D" + { + "SourcePath" = "8:..\\include\\opp\\iostream.cpp" + "TargetName" = "8:iostream.cpp" + "Tag" = "8:" + "Folder" = "8:_D76A1802AFD04C48A519C9F8700E53CC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_64C12019C1114C3282B32CD6B866C20A" { "SourcePath" = "8:..\\include\\c64\\reu.h" @@ -2651,6 +2911,26 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6EE9325B01F74FFF8146A6AD7FE71A31" + { + "SourcePath" = "8:..\\include\\opp\\string.h" + "TargetName" = "8:string.h" + "Tag" = "8:" + "Folder" = "8:_D76A1802AFD04C48A519C9F8700E53CC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7127D91089DA4162BB8DC8EAB0C107F0" { "SourcePath" = "8:..\\include\\c64\\vic.c" @@ -2771,6 +3051,26 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7789738FE8854CE488C5248434E47211" + { + "SourcePath" = "8:..\\include\\opp\\ifstream.h" + "TargetName" = "8:ifstream.h" + "Tag" = "8:" + "Folder" = "8:_D76A1802AFD04C48A519C9F8700E53CC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_79985361F09A43299E258E1A8E5ED934" { "SourcePath" = "8:..\\include\\gfx\\mcbitmap.c" @@ -2991,6 +3291,46 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_82C11E2A96FE49E399EEEAC2FEE9DCDC" + { + "SourcePath" = "8:..\\include\\opp\\list.h" + "TargetName" = "8:list.h" + "Tag" = "8:" + "Folder" = "8:_D76A1802AFD04C48A519C9F8700E53CC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_85AF458C41734A099F879A01E6CEB35F" + { + "SourcePath" = "8:..\\include\\opp\\ofstream.cpp" + "TargetName" = "8:ofstream.cpp" + "Tag" = "8:" + "Folder" = "8:_D76A1802AFD04C48A519C9F8700E53CC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8827B6B07A1C4B32B08DF784E090381D" { "SourcePath" = "8:..\\samples\\memmap\\tsr.c" @@ -3371,6 +3711,26 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A14BC161099E420286E6A1595596D0F0" + { + "SourcePath" = "8:..\\include\\opp\\ofstream.h" + "TargetName" = "8:ofstream.h" + "Tag" = "8:" + "Folder" = "8:_D76A1802AFD04C48A519C9F8700E53CC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A18504BA88CE40128ED44BD1854F0A33" { "SourcePath" = "8:..\\samples\\memmap\\easyflashreloc.c" @@ -3491,6 +3851,26 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A62BFFC051304130B85007261BC97749" + { + "SourcePath" = "8:..\\include\\opp\\sstream.h" + "TargetName" = "8:sstream.h" + "Tag" = "8:" + "Folder" = "8:_D76A1802AFD04C48A519C9F8700E53CC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A8820F3446B9408E88692E85817C1B07" { "SourcePath" = "8:..\\samples\\make.bat" @@ -4271,6 +4651,26 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D38EB85FE8E3492DA4BD8E6E4F7CEBEB" + { + "SourcePath" = "8:..\\include\\opp\\utility.h" + "TargetName" = "8:utility.h" + "Tag" = "8:" + "Folder" = "8:_D76A1802AFD04C48A519C9F8700E53CC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D52B954DFBCE4EB0932433DE7FCE9090" { "SourcePath" = "8:..\\samples\\hiresmc\\paint.c" @@ -4291,6 +4691,26 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D651A6B3342C4D1ABC7FE873E253A1C5" + { + "SourcePath" = "8:..\\include\\opp\\ifstream.cpp" + "TargetName" = "8:ifstream.cpp" + "Tag" = "8:" + "Folder" = "8:_D76A1802AFD04C48A519C9F8700E53CC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D76DA8C7D3964C93ABE193A7B53A0A9B" { "SourcePath" = "8:..\\samples\\stdio\\make.bat" @@ -4391,6 +4811,26 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_DBCD7B3D63C34E31A882799F3C82F0E9" + { + "SourcePath" = "8:..\\include\\opp\\iterator.h" + "TargetName" = "8:iterator.h" + "Tag" = "8:" + "Folder" = "8:_D76A1802AFD04C48A519C9F8700E53CC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_DE1058FFA9E149D1909C819592A12273" { "SourcePath" = "8:..\\samples\\particles\\fireworks_stripe.c" @@ -4451,6 +4891,26 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E11BDCFFB9944A1F893FE4EC86ACCD6C" + { + "SourcePath" = "8:..\\include\\opp\\algorithm.h" + "TargetName" = "8:algorithm.h" + "Tag" = "8:" + "Folder" = "8:_D76A1802AFD04C48A519C9F8700E53CC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E218D776D9014F99BE2B046AEF2D6E8B" { "SourcePath" = "8:..\\include\\stdlib.c" @@ -4651,6 +5111,46 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_EC599856E7AE44F4A2F51AA76A4D044C" + { + "SourcePath" = "8:..\\include\\opp\\bidxlist.h" + "TargetName" = "8:bidxlist.h" + "Tag" = "8:" + "Folder" = "8:_D76A1802AFD04C48A519C9F8700E53CC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_ED20DE3FDC8A400296E92AE0D37D8665" + { + "SourcePath" = "8:..\\include\\opp\\static_vector.h" + "TargetName" = "8:static_vector.h" + "Tag" = "8:" + "Folder" = "8:_D76A1802AFD04C48A519C9F8700E53CC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_ED5FED616EA64689AB793E5D8BD3F13D" { "SourcePath" = "8:..\\include\\nes\\mmc3.c" @@ -4791,6 +5291,26 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F472CF5FA6CF43649B4CD8E5F204DA65" + { + "SourcePath" = "8:..\\include\\opp\\array.h" + "TargetName" = "8:array.h" + "Tag" = "8:" + "Folder" = "8:_D76A1802AFD04C48A519C9F8700E53CC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F715B9FA6E0048388F451AB4670FD1EB" { "SourcePath" = "8:..\\samples\\resources\\friendlybear.bin" @@ -5202,6 +5722,17 @@ { } } + "{9EF0B969-E518-4E46-987F-47570745A589}:_D76A1802AFD04C48A519C9F8700E53CC" + { + "Name" = "8:opp" + "AlwaysCreate" = "11:FALSE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:_36F6D5A5C23349D190D89E25E1F78C22" + "Folders" + { + } + } "{9EF0B969-E518-4E46-987F-47570745A589}:_E0C7A8689A4144D0842BCEDA85A07B5D" { "Name" = "8:gfx" @@ -5233,15 +5764,15 @@ { "Name" = "8:Microsoft Visual Studio" "ProductName" = "8:oscar64" - "ProductCode" = "8:{30CBD281-E43B-4539-A830-C8EA3D9ECEEC}" - "PackageCode" = "8:{B24DA444-F39A-4974-97A1-BF31AB02202C}" + "ProductCode" = "8:{50B8F261-E014-4D97-807C-8B181651E0CF}" + "PackageCode" = "8:{73E601A2-834D-4280-AFAD-0E275AEDBF01}" "UpgradeCode" = "8:{9AB61EFF-ACAC-4079-9950-8D96615CD4EF}" "AspNetVersion" = "8:2.0.50727.0" "RestartWWWService" = "11:FALSE" "RemovePreviousVersions" = "11:TRUE" "DetectNewerInstalledVersion" = "11:TRUE" "InstallAllUsers" = "11:FALSE" - "ProductVersion" = "8:1.20.208" + "ProductVersion" = "8:1.26.225" "Manufacturer" = "8:oscar64" "ARPHELPTELEPHONE" = "8:" "ARPHELPLINK" = "8:" diff --git a/samples/hires/build.sh b/samples/hires/build.sh index e1886b3..ca60279 100755 --- a/samples/hires/build.sh +++ b/samples/hires/build.sh @@ -4,5 +4,6 @@ ../../bin/oscar64 lines.c -n ../../bin/oscar64 polygon.c -n ../../bin/oscar64 bitblit.c -n +../../bin/oscar64 cube3d.c -n ../../bin/oscar64 fractaltree.c -n ../../bin/oscar64 qsort.c -n diff --git a/samples/hires/makefile b/samples/hires/makefile index c7d47ea..1159dda 100644 --- a/samples/hires/makefile +++ b/samples/hires/makefile @@ -4,7 +4,7 @@ CFLAGS=-n %.prg: %.c $(CC) $(CFLAGS) $< -all: splitscreen.prg func3d.prg lines.prg polygon.prg bitblit.prg fractaltree.prg qsort.prg +all: splitscreen.prg func3d.prg lines.prg polygon.prg bitblit.prg cube3d.prg fractaltree.prg qsort.prg splitscreen.prg: splitscreen.c $(CC) $< diff --git a/samples/memmap/charsetload.d64 b/samples/memmap/charsetload.d64 deleted file mode 100644 index 10be50b..0000000 Binary files a/samples/memmap/charsetload.d64 and /dev/null differ diff --git a/samples/sprites/sprmux64.c b/samples/sprites/sprmux64.c index 8191f0b..09099c2 100644 --- a/samples/sprites/sprmux64.c +++ b/samples/sprites/sprmux64.c @@ -100,7 +100,7 @@ __interrupt void setspr(void) // Wait for end of current sprite, xpos will take effect // at start of line, so we need to patch it after the last // pixel line has started - vic_waitLine(yoffset - 4); + vic_waitLine(yoffset - 3); // Left to right or right to left to get a matching z order if (phase & 0x80)