diff --git a/Makefile b/Makefile index b7e1157..b754bf9 100644 --- a/Makefile +++ b/Makefile @@ -26,9 +26,6 @@ all: $(LIBNAME) $(OBJ) Makefile %.o: %.cpp $(CXX) $(CXXFLAGS) -o $@ -c $< -%.o: %.c - $(CXX) $(CXXFLAGS) -o $@ -c $< - $(LIBNAME): make -C $(LIBDIR) all diff --git a/PropellerCompiler.sln b/PropellerCompiler.sln index fead7cc..8069b73 100644 --- a/PropellerCompiler.sln +++ b/PropellerCompiler.sln @@ -1,7 +1,9 @@  -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PropellerCompiler", "PropellerCompiler\PropellerCompiler.vcproj", "{DE0E4A74-1C7F-4479-918D-9040BB599F90}" +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PropellerCompiler", "PropellerCompiler\PropellerCompiler.vcxproj", "{DE0E4A74-1C7F-4479-918D-9040BB599F90}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/PropellerCompiler/CompileDatBlocks.cpp b/PropellerCompiler/CompileDatBlocks.cpp index be612ac..0acf0f0 100644 --- a/PropellerCompiler/CompileDatBlocks.cpp +++ b/PropellerCompiler/CompileDatBlocks.cpp @@ -97,7 +97,7 @@ bool CompileDatBlocks_Enter(int value, int count, int size) bool CompileDatBlocks_Advance(bool bSymbol, bool bResSymbol, int size) { int testVal = (1 << size) - 1; - while (1) + for (;;) { if ((g_pCompilerData->obj_ptr & testVal) == 0) { diff --git a/PropellerCompiler/CompileExpression.cpp b/PropellerCompiler/CompileExpression.cpp index ef229cc..fbb1d6d 100644 --- a/PropellerCompiler/CompileExpression.cpp +++ b/PropellerCompiler/CompileExpression.cpp @@ -155,7 +155,7 @@ bool CompileSubExpression(int precedence) } } - while (1) + for (;;) { bool bEof = false; if (!g_pElementizer->GetNext(bEof)) @@ -230,7 +230,7 @@ bool CompileTerm_ConStr() } // get the string into the string constant buffer - while(1) + for (;;) { if (!GetTryValue(true, false)) { @@ -334,7 +334,7 @@ bool CompileTerm_ObjPub(unsigned char anchor, int value) int objPubValue = g_pElementizer->GetValue(); - // compile any paramaters the pub has + // compile any parameters the pub has if (!CompileParameters((objPubValue & 0x0000FF00) >> 8)) { return false; @@ -424,7 +424,7 @@ bool CompileLook(int column, int param) { return false; } - if (!CompileExpression()) // compile primarey value + if (!CompileExpression()) // compile primary value { return false; } @@ -433,7 +433,7 @@ bool CompileLook(int column, int param) return false; } - while (1) + for (;;) { bool bRange = false; if (!CompileRange(bRange)) // compile (next) value/range diff --git a/PropellerCompiler/CompileInstruction.cpp b/PropellerCompiler/CompileInstruction.cpp index 6005485..41ec436 100644 --- a/PropellerCompiler/CompileInstruction.cpp +++ b/PropellerCompiler/CompileInstruction.cpp @@ -36,7 +36,7 @@ bool CompileInst_NextQuit(int value) int caseDepth = 0; // find repeat block - while(1) + for (;;) { if (blockNestPtr == 0) { diff --git a/PropellerCompiler/DistillObjects.cpp b/PropellerCompiler/DistillObjects.cpp index f2f79b5..f3ef417 100644 --- a/PropellerCompiler/DistillObjects.cpp +++ b/PropellerCompiler/DistillObjects.cpp @@ -34,6 +34,9 @@ bool DistillSetup_Enter(unsigned short value) return true; } +// create a table of all objects with their offsets and sub objects +// each entry contains: +// id, offset, number sub objects, [sub object ids] bool DistillSetup_Record(short id, unsigned short offset, unsigned short& subObjectId) { if (!DistillSetup_Enter(id)) @@ -83,6 +86,9 @@ bool DistillSetup() return false; } + // Clear all the objects table of offsets to their sub objects + // this needs to be done so that objects will binary compare with each other properly + // these offsets get replaced in the reconnect step int disPtr = 0; while (disPtr < g_pCompilerData->dis_ptr) { @@ -109,6 +115,8 @@ bool DistillSetup() return true; } +// update all objects of the given id to the new id +// also flags them as "distilled" with the upper bit being on void DistillEliminate_Update(unsigned short objectId, int newDisPtr) { int disPtr = 0; @@ -267,7 +275,7 @@ void DistillReconnect(int disPtr = 0) // find offset of sub-object int scanDisPtr = 0; - while(1) + for (;;) { if (g_pCompilerData->dis[scanDisPtr] == subObjectId) { diff --git a/PropellerCompiler/Elementizer.cpp b/PropellerCompiler/Elementizer.cpp index 28d10f7..0767966 100644 --- a/PropellerCompiler/Elementizer.cpp +++ b/PropellerCompiler/Elementizer.cpp @@ -96,7 +96,7 @@ bool Elementizer::GetNext(bool& bEof) m_currentSymbol[0] = 0; int symbolOffset = 0; - while(1) + for (;;) { char currentChar = pSource[m_sourceOffset++]; @@ -281,7 +281,7 @@ bool Elementizer::GetNext(bool& bEof) bDocComment = true; g_pCompilerData->doc_flag = true; } - while(1) + for (;;) { currentChar = pSource[m_sourceOffset++]; if (currentChar == 0) @@ -318,7 +318,7 @@ bool Elementizer::GetNext(bool& bEof) m_sourceOffset++; // skip over end if present } } - while(1) + for (;;) { currentChar = pSource[m_sourceOffset++]; if (currentChar == 0) diff --git a/PropellerCompiler/InstructionBlockCompiler.cpp b/PropellerCompiler/InstructionBlockCompiler.cpp index 4ef70c4..3f0e300 100644 --- a/PropellerCompiler/InstructionBlockCompiler.cpp +++ b/PropellerCompiler/InstructionBlockCompiler.cpp @@ -337,7 +337,7 @@ bool CompileCase(int column, int param) g_pCompilerData->error_msg = g_pErrorStrings[error_loxce]; return false; } - while (1) + for (;;) { bool bRange = false; if (!CompileRange(bRange)) @@ -442,8 +442,8 @@ bool CompileCase(int column, int param) } else { - // skip over range/values(s), allready compiled - while (1) + // skip over range/values(s), already compiled + for (;;) { if (!SkipRange()) { @@ -493,7 +493,7 @@ bool CompileRepeatPlain(int column, int param) { param = param; // stop warning - BlockStack_Write(2, g_pCompilerData->obj_ptr); // set revearse address + BlockStack_Write(2, g_pCompilerData->obj_ptr); // set reverse address if (!s_bHasPost) { BlockStack_Write(0, g_pCompilerData->obj_ptr); // set plain 'next' address @@ -830,7 +830,7 @@ bool OptimizeBlock(int column, int param, bool (*pCompileFunction)(int, int)) int savedObjPtr = g_pCompilerData->obj_ptr; int size = 0; - while(1) + for (;;) { g_pElementizer->SetSourcePtr(savedSourcePtr); g_pCompilerData->obj_ptr = savedObjPtr; diff --git a/PropellerCompiler/Makefile b/PropellerCompiler/Makefile index c8c760d..498eb1a 100644 --- a/PropellerCompiler/Makefile +++ b/PropellerCompiler/Makefile @@ -24,6 +24,7 @@ OBJ=$(SRCDIR)/BlockNestStackRoutines.o \ $(SRCDIR)/StringConstantRoutines.o \ $(SRCDIR)/SymbolEngine.o \ $(SRCDIR)/Utilities.o \ + $(SRCDIR)/UnusedMethodUtils.o \ $(SRCDIR)/PropellerCompiler.o \ diff --git a/PropellerCompiler/PropellerCompiler.cpp b/PropellerCompiler/PropellerCompiler.cpp index a0c71d4..7603a7c 100644 --- a/PropellerCompiler/PropellerCompiler.cpp +++ b/PropellerCompiler/PropellerCompiler.cpp @@ -1,7 +1,7 @@ ////////////////////////////////////////////////////////////// // // // Propeller Spin/PASM Compiler // -// (c)2012 Parallax Inc. DBA Parallax Semiconductor. // +// (c)2012-2015 Parallax Inc. DBA Parallax Semiconductor. // // Adapted from Chip Gracey's x86 asm code by Roy Eltham // // See end of file for terms of use. // // // @@ -19,6 +19,7 @@ #include "SymbolEngine.h" #include "Elementizer.h" #include "ErrorStrings.h" +#include "UnusedMethodUtils.h" ////////////////////////////////////////// // declarations for internal functions @@ -460,7 +461,7 @@ bool CompileConBlocks(int pass) return true; } -bool CompileSubBlocksId_Compile(int blockType, bool &bFirst) +bool CompileSubBlocksId_Compile(int blockType, bool &bFirst, int &nMethodIndex) { bool bEof = false; g_pElementizer->Reset(); @@ -631,36 +632,40 @@ bool CompileSubBlocksId_Compile(int blockType, bool &bFirst) } } - // enter sub symbol - int value = params; - value <<= 8; - value |= (g_pCompilerData->obj_ptr >> 2) & 0xFF; - g_pSymbolEngine->AddSymbol(g_pCompilerData->symbolBackup, type_sub, value, blockType); + if (!g_pCompilerData->bFinalCompile || IsMethodUsed(g_pCompilerData->current_filename, nMethodIndex)) + { + // enter sub symbol + int value = params; + value <<= 8; + value |= (g_pCompilerData->obj_ptr >> 2) & 0xFF; + g_pSymbolEngine->AddSymbol(g_pCompilerData->symbolBackup, type_sub, value, blockType); #ifdef RPE_DEBUG - printf("Pub/Pri %s %d (%d, %d)\n", g_pCompilerData->symbolBackup, value, params, g_pCompilerData->obj_ptr); + printf("Pub/Pri %s %d (%d, %d)\n", g_pCompilerData->symbolBackup, value, params, g_pCompilerData->obj_ptr); #endif - if (!g_pCompilerData->bDATonly) - { - // enter locals count into index - EnterObjLong(locals<<16); - } + if (!g_pCompilerData->bDATonly) + { + // enter locals count into index (shifted up 16 to leave space for the sub offset which will be fixed up later) + EnterObjLong(locals<<16); + } - if (blockType == block_pub) - { - if (!AddSymbolToPubConList()) + if (blockType == block_pub) { - return false; + if (!AddSymbolToPubConList()) + { + return false; + } + if (!AddPubConListByte(params)) + { + return false; + } } - if (!AddPubConListByte(params)) + if (bFirst == false) { - return false; + g_pCompilerData->first_pub_parameters = params; + bFirst = true; } } - if (bFirst == false) - { - g_pCompilerData->first_pub_parameters = params; - bFirst = true; - } + nMethodIndex++; } else { @@ -682,7 +687,8 @@ bool CompileSubBlocksId_Compile(int blockType, bool &bFirst) bool CompileSubBlocksId() { bool bFirst = false; - if (!CompileSubBlocksId_Compile(block_pub, bFirst)) + int nMethodIndex = 0; + if (!CompileSubBlocksId_Compile(block_pub, bFirst, nMethodIndex)) { return false; } @@ -693,7 +699,7 @@ bool CompileSubBlocksId() g_pCompilerData->source_start = g_pCompilerData->source_finish; return false; } - if (!CompileSubBlocksId_Compile(block_pri, bFirst)) + if (!CompileSubBlocksId_Compile(block_pri, bFirst, nMethodIndex)) { return false; } @@ -706,6 +712,7 @@ bool CompileObjBlocksId() g_pCompilerData->obj_start = g_pCompilerData->obj_ptr; g_pCompilerData->obj_count = 0; g_pCompilerData->obj_files = 0; + g_pCompilerData->unused_obj_files = 0; bool bEof = false; g_pElementizer->Reset(); @@ -770,41 +777,52 @@ bool CompileObjBlocksId() { return false; } - - // is it a new obj? - if (objFileIndex == (g_pCompilerData->obj_files - 1)) + if ( !g_pCompilerData->bFinalCompile || IsObjectUsed(&g_pCompilerData->obj_filenames[objFileIndex<<8]) ) { - // reset instances - g_pCompilerData->obj_instances[objFileIndex] = 0; - } + // is it a new obj? + if (objFileIndex == (g_pCompilerData->obj_files - 1)) + { + // reset instances + g_pCompilerData->obj_instances[objFileIndex] = 0; + } - // enter obj symbol - int value = objFileIndex; - value <<= 8; - value |= (g_pCompilerData->obj_ptr >> 2) & 0xFF; - g_pSymbolEngine->AddSymbol(g_pCompilerData->symbolBackup, type_obj, value); + // enter obj symbol + int value = objFileIndex; + value <<= 8; + value |= (g_pCompilerData->obj_ptr >> 2) & 0xFF; + g_pSymbolEngine->AddSymbol(g_pCompilerData->symbolBackup, type_obj, value); #ifdef RPE_DEBUG - printf("Obj %s %d (%d, %d)\n", g_pCompilerData->symbolBackup, value, instanceCount, g_pCompilerData->obj_ptr); + printf("Obj %s %d (%d, %d)\n", g_pCompilerData->symbolBackup, value, instanceCount, g_pCompilerData->obj_ptr); #endif - for (int i=0; i < instanceCount; i++) - { - if (g_pCompilerData->obj_ptr < 256*4) - { - // enter locals count into index - EnterObjLong(objFileIndex); - g_pCompilerData->obj_count++; - } - else + for (int i=0; i < instanceCount; i++) { - g_pCompilerData->error = true; - g_pCompilerData->error_msg = g_pErrorStrings[error_loxspoe]; - return false; + if (g_pCompilerData->obj_ptr < 256*4) + { + // enter object index into table + EnterObjLong(objFileIndex); + g_pCompilerData->obj_count++; + } + else + { + g_pCompilerData->error = true; + g_pCompilerData->error_msg = g_pErrorStrings[error_loxspoe]; + return false; + } } - } - // accumulate instances - g_pCompilerData->obj_instances[objFileIndex] += instanceCount; + // accumulate instances + g_pCompilerData->obj_instances[objFileIndex] += instanceCount; + } + else + { + strcpy(&(g_pCompilerData->obj_unused[g_pCompilerData->unused_obj_files<<8]), &(g_pCompilerData->obj_filenames[objFileIndex<<8])); + int value = g_pCompilerData->unused_obj_files | 0x40; + value <<= 8; + g_pSymbolEngine->AddSymbol(g_pCompilerData->symbolBackup, type_obj, value); + g_pCompilerData->unused_obj_files++; + g_pCompilerData->obj_files--; + } if (!g_pElementizer->GetElement(type_end)) { @@ -958,8 +976,8 @@ bool CompileObjSymbols() #ifdef RPE_DEBUG printf("objpub: %s %d \n", g_pCompilerData->symbolBackup, value); #endif - pData++; // adjust pointer to after param count nPub++; + pData++; // adjust pointer to after param count break; } else // handle objcon or objcon_float symbol @@ -982,6 +1000,53 @@ bool CompileObjSymbols() } } } + + // now add any CON symbols from unused objects + for (int nUnusedFile = 0; nUnusedFile < g_pCompilerData->unused_obj_files; nUnusedFile++) + { + unsigned char* pData = 0; + int nDataSize = 0; + if (GetObjectPubConList(&(g_pCompilerData->obj_unused[nUnusedFile<<8]), &pData, &nDataSize)) + { + unsigned char *pDataEnd = pData + nDataSize; + // go thru symbols validating them and adding them to the symbol table + while (pData < pDataEnd) + { + for (int i = 0; i < symbol_limit+1; i++) + { + if (!CheckWordChar((char)(*pData))) + { + CompileObjSymbol_BadObj(nFile); + return false; + } + g_pCompilerData->symbolBackup[i] = (char)(*pData); + pData++; + if (pData[0] < 18) // 0 to 15 = pub param count, 16 and 17 are constants + { + g_pCompilerData->symbolBackup[i+1] = (char)(0x40 | (nUnusedFile + 1)); + g_pCompilerData->symbolBackup[i+2] = 0; + if (pData[0] < 16) // handle objpub symbol + { + // we don't add pubs in this case + pData++; // adjust pointer to after param count + break; + } + else // handle objcon or objcon_float symbol + { + int value = (int)pData[1] | ((int)pData[2] << 8) | ((int)pData[3] << 16) | ((int)pData[4] << 24); + g_pSymbolEngine->AddSymbol(g_pCompilerData->symbolBackup, (pData[0] == 16) ? type_objcon : type_objcon_float, value); +#ifdef RPE_DEBUG + float fValue = *((float*)(&value)); + printf("objcon: %s %d %f *\n", g_pCompilerData->symbolBackup, value, fValue); +#endif + pData+=5; // adjust pointer to after value + break; + } + } + } + } + } + } return true; } @@ -1117,7 +1182,7 @@ bool CompileVarBlocks() return true; } -bool CompileSubBlocks_Compile(int blockType, int &subCount) +bool CompileSubBlocks_Compile(int blockType, int &subCount, int &nMethodIndex) { bool bEof = false; g_pElementizer->Reset(); @@ -1310,33 +1375,36 @@ bool CompileSubBlocks_Compile(int blockType, int &subCount) } } - // enter sub offset into index - *((short*)&(g_pCompilerData->obj[4 + (subCount * 4)])) = (short)g_pCompilerData->obj_ptr; - - if (!CompileTopBlock()) // instruction block compiler + if (!g_pCompilerData->bFinalCompile || IsMethodUsed(g_pCompilerData->current_filename, nMethodIndex)) { - return false; - } + // enter sub offset into index + *((short*)&(g_pCompilerData->obj[4 + (subCount * 4)])) = (short)g_pCompilerData->obj_ptr; - g_pCompilerData->inf_start = saved_inf_start; - g_pCompilerData->inf_finish = g_pElementizer->GetSourcePtr(); - g_pCompilerData->inf_data0 = saved_inf_data0; - g_pCompilerData->inf_data1 = g_pCompilerData->obj_ptr; - g_pCompilerData->inf_data2 = saved_inf_data2; - g_pCompilerData->inf_data3 = saved_inf_data3; - g_pCompilerData->inf_data4 = (paramCount << 16) | subCount; - if (blockType == block_pub) - { - g_pCompilerData->inf_type = info_pub; - } - else - { - g_pCompilerData->inf_type = info_pri; - } - EnterInfo(); + if (!CompileTopBlock()) // instruction block compiler + { + return false; + } - subCount++; + g_pCompilerData->inf_start = saved_inf_start; + g_pCompilerData->inf_finish = g_pElementizer->GetSourcePtr(); + g_pCompilerData->inf_data0 = saved_inf_data0; + g_pCompilerData->inf_data1 = g_pCompilerData->obj_ptr; + g_pCompilerData->inf_data2 = saved_inf_data2; + g_pCompilerData->inf_data3 = saved_inf_data3; + g_pCompilerData->inf_data4 = (paramCount << 16) | subCount; + if (blockType == block_pub) + { + g_pCompilerData->inf_type = info_pub; + } + else + { + g_pCompilerData->inf_type = info_pri; + } + EnterInfo(); + subCount++; + } + nMethodIndex++; g_pSymbolEngine->Reset(true); // cancel local symbols } } @@ -1352,11 +1420,12 @@ bool CompileSubBlocks_Compile(int blockType, int &subCount) bool CompileSubBlocks() { int subCount = 0; - if (!CompileSubBlocks_Compile(block_pub, subCount)) + int nMethodIndex = 0; + if (!CompileSubBlocks_Compile(block_pub, subCount, nMethodIndex)) { return false; } - if (!CompileSubBlocks_Compile(block_pri, subCount)) + if (!CompileSubBlocks_Compile(block_pri, subCount, nMethodIndex)) { return false; } @@ -1485,6 +1554,11 @@ bool CompileFinal() return false; } + if (!g_pCompilerData->bFinalCompile) + { + AddObjectPubConList(g_pCompilerData->current_filename, g_pCompilerData->pubcon_list, g_pCompilerData->pubcon_list_size); + } + // copy pubcon_list into obj (RPE: this could be optimized) for (int i = 0; i < g_pCompilerData->pubcon_list_size; i++) { @@ -1806,7 +1880,7 @@ bool CompileDoc_ScanInterface(bool bPrint, int& nCount) char currentChar = CompileDoc_ScanSkip(scanPtr); if (currentChar == '(') { - while (1) + for (;;) { currentChar = g_pCompilerData->source[scanPtr++]; nCount++; diff --git a/PropellerCompiler/PropellerCompiler.h b/PropellerCompiler/PropellerCompiler.h index 4abcf39..130a689 100644 --- a/PropellerCompiler/PropellerCompiler.h +++ b/PropellerCompiler/PropellerCompiler.h @@ -13,6 +13,8 @@ #ifndef _PROPELLER_COMPILER_H_ #define _PROPELLER_COMPILER_H_ +#include "UnusedMethodUtils.h" + // // OpenSpin code uses _stricmp() which is the VC++ name for the function. // this needs to be remapped to stricmp or strcasecmp depending on the compiler and OS being compiled on @@ -34,8 +36,7 @@ #endif // -// Everything here needs to stay in the order it is in (for the enums and struct) and remain -// the same size, in order to be the same as the asm code version and work with Prop Tool / Propellent +// no longer compatible with Prop Tool / Propellent // #define language_version '0' @@ -47,11 +48,10 @@ #define info_limit 1000 #define distiller_limit 0x4000 #define symbol_limit 256 // was 32 -//#define symbol_table_limit 0x8000 -#define pubcon_list_limit 0x2000 +#define pubcon_list_limit 0x8000 #define block_nest_limit 8 -#define block_stack_limit 256 -#define case_limit 64 +#define block_stack_limit 4096 +#define case_limit 256 #define if_limit 16 #define str_limit 256 #define str_buffer_limit 0x8000 @@ -149,6 +149,11 @@ struct CompilerData unsigned int vsize; // used to hold last vsize (in case it is greater than 65536) unsigned int psize; // used to hold last psize (in case it is greater than 65536) + char current_filename[256]; // name of object being compiled at the moment + bool bFinalCompile; // set to true after unused method scan complete + + int unused_obj_files; // number of unused object files + char obj_unused[file_limit*256]; // hold filenames of unused objects }; // public functions diff --git a/PropellerCompiler/PropellerCompiler.vcproj b/PropellerCompiler/PropellerCompiler.vcproj deleted file mode 100644 index 2b0267f..0000000 --- a/PropellerCompiler/PropellerCompiler.vcproj +++ /dev/null @@ -1,237 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/PropellerCompiler/PropellerCompiler.vcxproj b/PropellerCompiler/PropellerCompiler.vcxproj new file mode 100644 index 0000000..56c8814 --- /dev/null +++ b/PropellerCompiler/PropellerCompiler.vcxproj @@ -0,0 +1,109 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {DE0E4A74-1C7F-4479-918D-9040BB599F90} + PropellerCompiler + Win32Proj + + + + StaticLibrary + v120 + Unicode + true + + + StaticLibrary + v120 + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>12.0.30501.0 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + + + + Disabled + WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + false + + Level4 + EditAndContinue + + + + + MaxSpeed + true + WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + true + + false + + Level3 + ProgramDatabase + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PropellerCompiler/PropellerCompilerInternal.h b/PropellerCompiler/PropellerCompilerInternal.h index 35235f8..1b40b8d 100644 --- a/PropellerCompiler/PropellerCompilerInternal.h +++ b/PropellerCompiler/PropellerCompilerInternal.h @@ -100,7 +100,6 @@ struct CompilerDataInternal : public CompilerData int bstack_ptr; int bstack_base[block_nest_limit]; int bstack[block_stack_limit]; - }; class Elementizer; diff --git a/PropellerCompiler/UnusedMethodUtils.cpp b/PropellerCompiler/UnusedMethodUtils.cpp new file mode 100644 index 0000000..519e995 --- /dev/null +++ b/PropellerCompiler/UnusedMethodUtils.cpp @@ -0,0 +1,875 @@ + +/////////////////////////////////////////////////////////////// +// // +// Propeller Spin/PASM Compiler Command Line Tool 'OpenSpin' // +// (c)2012-2015 Parallax Inc. DBA Parallax Semiconductor. // +// See end of file for terms of use. // +// // +/////////////////////////////////////////////////////////////// +// +// UnusedMethodElimination.cpp +// + +#include +#include +#include + +#include "../PropellerCompiler/PropellerCompiler.h" + +// +// track object names based on "indent" or which child/parent level +// note: the same name can be in here multiple times at different indent levels +// + +struct ObjectNameEntry +{ + char filename[256]; + int indent; +}; + +ObjectNameEntry s_objectNames[128]; +int s_nNumObjectNames = 0; + +void AddObjectName(char* pFilename, int indent) +{ + strcpy(s_objectNames[s_nNumObjectNames].filename, pFilename); + + // chop off the .spin extension + char* pExtension = strstr(s_objectNames[s_nNumObjectNames].filename, ".spin"); + if (pExtension != 0) + { + *pExtension = 0; + } + + s_objectNames[s_nNumObjectNames].indent = indent-1; + s_nNumObjectNames++; +} + +int GetObjectName(int indent, int index) +{ + int nCurrIndex = 0; + for (int i = 0; i < s_nNumObjectNames; i++) + { + if (s_objectNames[i].indent == indent) + { + if (nCurrIndex == index) + { + return i; + } + nCurrIndex++; + } + } + return -1; +} + +// +// track method usage by object +// + +struct IndexEntry +{ + short offset; // offset in longs to method (or sub object) + short vars; // var offset for objs, locals size for methods +}; + +struct CallEntry +{ + unsigned int objaddress; + unsigned int callOffset; + unsigned short objoffset; + unsigned char opcode; + unsigned char pubnum; + unsigned char objnum; +}; + +struct MethodUsage +{ + int nLength; + int nCalled; + int nCalls; + CallEntry *pCalls; + int nCurrCall; + int nNewIndex; +}; + +struct ObjectEntry +{ + int nObjectNameIndex; + unsigned char* pObject; + int nObjectMethodCount; + int nObjectSubObjectCount; + int nObjectIndexCount; + int nMethodsCalled; + int nNewObjectIndex; + IndexEntry* pIndexTable; + MethodUsage* pMethods; +}; + +ObjectEntry s_objects[file_limit]; +int s_nNumObjects; + +bool HaveObject(unsigned char* pObject) +{ + for (int i = 0; i < s_nNumObjects; i++) + { + if (s_objects[i].pObject == pObject) + { + return true; + } + } + + return false; +} + +ObjectEntry* GetObject(unsigned char* pObject) +{ + for (int i = 0; i < s_nNumObjects; i++) + { + if (s_objects[i].pObject == pObject) + { + return &s_objects[i]; + } + } + + return NULL; +} + +ObjectEntry* GetObjectByName(char* pFilename) +{ + for (int i = 0; i < s_nNumObjects; i++) + { + if (strcmp(s_objectNames[s_objects[i].nObjectNameIndex].filename, pFilename) == 0) + { + return &s_objects[i]; + } + } + + return NULL; +} + +int AddObject(unsigned char* pObject, int nObjectNameIndex) +{ + s_objects[s_nNumObjects].pObject = pObject; + s_objects[s_nNumObjects].nObjectNameIndex = nObjectNameIndex; + s_objects[s_nNumObjects].nObjectMethodCount = pObject[2]-1; + s_objects[s_nNumObjects].nObjectSubObjectCount = pObject[3]; + s_objects[s_nNumObjects].nObjectIndexCount = s_objects[s_nNumObjects].nObjectMethodCount + s_objects[s_nNumObjects].nObjectSubObjectCount; + s_objects[s_nNumObjects].pIndexTable = (IndexEntry *)&(pObject[4]); + s_objects[s_nNumObjects].pMethods = new MethodUsage[s_objects[s_nNumObjects].nObjectMethodCount]; + for (int i = 0; i < s_objects[s_nNumObjects].nObjectMethodCount; i++) + { + s_objects[s_nNumObjects].pMethods[i].nCalled = 0; + s_objects[s_nNumObjects].pMethods[i].nCalls = 0; + s_objects[s_nNumObjects].pMethods[i].pCalls = 0; + s_objects[s_nNumObjects].pMethods[i].nCurrCall = 0; + s_objects[s_nNumObjects].pMethods[i].nNewIndex = 0; + s_objects[s_nNumObjects].pMethods[i].nLength = 0; + } + return s_nNumObjects++; +} + +bool IsObjectUsed(char* pFilename) +{ + ObjectEntry* pObject = GetObjectByName(pFilename); + if (pObject && pObject->nMethodsCalled > 0) + { + return true; + } + + return false; +} + +bool IsMethodUsed(char* pFilename, int nMethod) +{ + ObjectEntry* pObject = GetObjectByName(pFilename); + if (pObject && pObject->nMethodsCalled > 0 && pObject->pMethods[nMethod].nCalled > 0) + { + return true; + } + + return false; +} + +// +// store pubcon list data so it can be used in the final compile +// note: this is needed to allow removing a child object where the parent used only CONs from the child +// + +struct ObjectPubConListEntry +{ + char filename[256]; + unsigned char* pPubConList; + int nPubConListSize; +}; + +ObjectPubConListEntry s_objectPubConLists[512]; +int s_nNumObjectPubConLists; + +ObjectPubConListEntry* GetObjectPubConListEntryByName(char* pFilename) +{ + for (int i = 0; i < s_nNumObjectPubConLists; i++) + { + if (strcmp(s_objectPubConLists[i].filename, pFilename) == 0) + { + return &s_objectPubConLists[i]; + } + } + + return NULL; +} + +void AddObjectPubConList(char* pFilename, unsigned char* pPubConList, int nPubConListSize) +{ + strcpy(s_objectPubConLists[s_nNumObjectPubConLists].filename, pFilename); + s_objectPubConLists[s_nNumObjectPubConLists].pPubConList = new unsigned char[nPubConListSize]; + s_objectPubConLists[s_nNumObjectPubConLists].nPubConListSize = nPubConListSize; + memcpy(s_objectPubConLists[s_nNumObjectPubConLists].pPubConList, pPubConList, s_objectPubConLists[s_nNumObjectPubConLists].nPubConListSize); + s_nNumObjectPubConLists++; +} + +bool GetObjectPubConList(char* pFilename, unsigned char** ppPubConList, int* pnPubConListSize) +{ + ObjectPubConListEntry* pObject = GetObjectPubConListEntryByName(pFilename); + if (pObject && pObject->pPubConList != 0 && pObject->nPubConListSize > 0) + { + *ppPubConList = pObject->pPubConList; + *pnPubConListSize = pObject->nPubConListSize; + return true; + } + return false; +} + +void CleanUpUnusedMethodData() +{ + for (int i = 0; i < s_nNumObjects; i++) + { + s_objects[i].pObject = 0; + s_objects[i].pIndexTable = 0; + + for (int j = 0; j < s_objects[s_nNumObjects].nObjectMethodCount; j++) + { + if (s_objects[i].pMethods[j].pCalls) + { + delete [] s_objects[i].pMethods[j].pCalls; + s_objects[i].pMethods[j].pCalls = 0; + } + } + delete [] s_objects[i].pMethods; + s_objects[i].pMethods = 0; + } + s_nNumObjects = 0; + s_nNumObjectNames = 0; + + for (int i = 0; i < s_nNumObjectPubConLists; i++) + { + delete [] s_objectPubConLists[i].pPubConList; + s_objectPubConLists[i].pPubConList = 0; + } + s_nNumObjectPubConLists = 0; +} + +void InitUnusedMethodData() +{ + for (int i = 0; i < file_limit; i++) + { + s_objectPubConLists[i].filename[0] = 0; + s_objectPubConLists[i].pPubConList = 0; + s_objectPubConLists[i].nPubConListSize = 0; + } + s_nNumObjectPubConLists = 0; + s_nNumObjectNames = 0; +} + +void BuildTables(unsigned char* pObject, int indent, int index) +{ +#ifdef RPE_DEBUG + char *s_indent = " "; +#define MAX_INDENT 32 +#endif + + if (HaveObject(pObject)) + { +#ifdef RPE_DEBUG + printf("%sObject Already Added\n", &s_indent[MAX_INDENT-indent]); +#endif + return; + } + int nNextObjOffset = *((unsigned short *)pObject); + int nObjectName = GetObjectName(indent, index); + int nObject = AddObject(pObject, nObjectName); + +#ifdef RPE_DEBUG + printf("%sObject Index Table: %s\n", &s_indent[MAX_INDENT-indent], s_objectNames[s_objects[nObject].nObjectNameIndex].filename); +#endif + for (int i = 0; i < s_objects[nObject].nObjectIndexCount; i++) + { + if (s_objects[nObject].pIndexTable[i].offset >= nNextObjOffset) + { +#ifdef RPE_DEBUG + printf("%s Object Offset: %04d Vars Offset: %d\n", &s_indent[MAX_INDENT-indent], s_objects[nObject].pIndexTable[i].offset, s_objects[nObject].pIndexTable[i].vars); +#endif + BuildTables(&(pObject[s_objects[nObject].pIndexTable[i].offset]), indent + 1, i - s_objects[nObject].nObjectMethodCount); + } +#ifdef RPE_DEBUG + else + { + printf("%s Method Offset: %04d Locals size: %d\n", &s_indent[MAX_INDENT-indent], s_objects[nObject].pIndexTable[i].offset, s_objects[nObject].pIndexTable[i].vars); + } +#endif + } +} + +// +// byte code scanning stuff +// borrowed from Dave Hein's spinsim code and then modified for my needs (mostly stripped down to just skip intelligently over byte code) +// + +int SkipSignedOffset(unsigned char* pOpcode) +{ + return (*pOpcode < 0x80) ? 1 : 2; +} + +int SkipUnsignedOffset(unsigned char* pOpcode) +{ + return (*pOpcode & 0x80) ? 2 : 1; +} + +int ScanMathOpcode(unsigned char* pOpcode) +{ + bool execflag = false; + int opcode = *pOpcode; + + if (opcode < 0xe0) + { + execflag = true; + opcode += 0xe0 - 0x40; + } + + // Execute the math op + switch (opcode) + { + case 0xe0: // ror + case 0xe1: // rol + case 0xe2: // shr + case 0xe3: // shl + case 0xe4: // min + case 0xe5: // max + case 0xe6: // neg + case 0xe7: // com + case 0xe8: // and + case 0xe9: // abs + case 0xea: // or + case 0xeb: // xor + case 0xec: // add + case 0xed: // sub + case 0xee: // sar + case 0xef: // rev + case 0xf0: // andl + case 0xf1: // encode + case 0xf4: // mul + case 0xf5: // mulh + case 0xf2: // orl + case 0xf3: // decode + case 0xf6: // div + case 0xf7: // mod + case 0xf8: // sqrt + case 0xf9: // cmplt + case 0xfa: // cmpgt + case 0xfb: // cmpne + case 0xfc: // cmpeq + case 0xfd: // cmple + case 0xfe: // cmpgr + case 0xff: // notl + break; + + default: + break; + } + + return (execflag ? 0 : 1); +} + +int ScanExtraOpcode(unsigned char* pOpcode, int opcode) +{ + int nOpSize = 0; + + opcode &= 0x7f; + + if (opcode >= 0x40 && opcode < 0x60) // math op + { + nOpSize += ScanMathOpcode(pOpcode); + } + else if ((opcode & 0x7e) == 0x00) // store + { + } + else if ((opcode & 0x7a) == 0x02) // repeat, repeats + { + nOpSize += SkipSignedOffset(pOpcode); + } + else if ((opcode & 0x78) == 8) // randf, randr + { + } + else if ((opcode & 0x7c) == 0x10) // sexb + { + } + else if ((opcode & 0x7c) == 0x14) // sexw + { + } + else if ((opcode & 0x7c) == 0x18) // postclr + { + } + else if ((opcode & 0x7c) == 0x1c) // postset + { + } + else if ((opcode & 0x78) == 0x20) // preinc + { + } + else if ((opcode & 0x78) == 0x28) // postinc + { + } + else if ((opcode & 0x78) == 0x30) // predec + { + } + else if ((opcode & 0x78) == 0x38) // postdec + { + } + else + { + printf("NOT IMPLEMENTED\n"); + } + + return nOpSize; +} + + +int ScanMemoryOpcode(unsigned char* pOpcode) +{ + int opcode = *pOpcode; + int memfunc = opcode & 3; + + int nOpSize = 1; + + if (opcode < 0x80) // Compact offset + { + } + else + { + if ((opcode & 0x0c) >> 2) + { + nOpSize += SkipUnsignedOffset(&pOpcode[nOpSize]); + } + } + + if (memfunc == 3) // la + { + } + else if (memfunc == 0) // ld + { + } + else if (memfunc == 1) // st + { + } + else // ex + { + opcode = pOpcode[nOpSize]; + nOpSize++; + + nOpSize += ScanExtraOpcode(&pOpcode[nOpSize], opcode); + } + + return nOpSize; +} + +int ScanRegisterOpcode(unsigned char* pOpcode, int operand) +{ + int opcode; + int nOpSize = 0; + int memfunc = (operand >> 5) & 3; + + if (memfunc == 1) // store + { + } + else if (memfunc == 0) // load + { + } + else if (memfunc == 2) // execute + { + opcode = *pOpcode; + nOpSize++; + + nOpSize += ScanExtraOpcode(&pOpcode[nOpSize], opcode); + } + else + { + printf("Undefined register operation\n"); + } + + return nOpSize; +} + +int ScanLowerOpcode(unsigned char* pOpcode, MethodUsage* pUsage, ObjectEntry* pObject, unsigned char* pMethodStart) +{ + int opcode = *pOpcode; + int nOpSize = 1; + + if (opcode <= 3) // ldfrmr, ldfrm, ldfrmar, ldfrma + { + } + else if (opcode == 0x04) // jmp + { + nOpSize += SkipSignedOffset(&pOpcode[nOpSize]); + } + else if (opcode >= 0x05 && opcode <= 0x07) // call, callobj, callobjx + { + int objnum = 0; + + if (opcode > 0x05) + { + objnum = pOpcode[nOpSize]; + nOpSize++; + if (opcode == 0x07) + { + // indexed + } + } + + int pubnum = pOpcode[nOpSize]; + nOpSize++; + + // need to update usage here + if (pUsage->pCalls == 0) + { + pUsage->nCalls++; + } + else + { + pUsage->pCalls[pUsage->nCurrCall].opcode = (unsigned char)opcode; + pUsage->pCalls[pUsage->nCurrCall].pubnum = (unsigned char)pubnum; + pUsage->pCalls[pUsage->nCurrCall].callOffset = ((&pOpcode[1]) - pMethodStart); + + if (opcode > 0x05) + { + pUsage->pCalls[pUsage->nCurrCall].objnum = (unsigned char)objnum; + pUsage->pCalls[pUsage->nCurrCall].objoffset = pObject->pIndexTable[objnum-1].offset; + pUsage->pCalls[pUsage->nCurrCall].objaddress = (unsigned int)&pObject->pObject[pUsage->pCalls[pUsage->nCurrCall].objoffset]; +#ifdef RPE_DEBUG + printf(" callobj %02X:%02X (%08X)\n", pUsage->pCalls[pUsage->nCurrCall].objnum, pUsage->pCalls[pUsage->nCurrCall].pubnum, pUsage->pCalls[pUsage->nCurrCall].objaddress); +#endif + } + else + { + pUsage->pCalls[pUsage->nCurrCall].objnum = 0; + pUsage->pCalls[pUsage->nCurrCall].objoffset = 0; + pUsage->pCalls[pUsage->nCurrCall].objaddress = (unsigned int)(pObject->pObject); +#ifdef RPE_DEBUG + printf(" call %02X (%08X)\n", pUsage->pCalls[pUsage->nCurrCall].pubnum, pUsage->pCalls[pUsage->nCurrCall].objaddress); +#endif + } + pUsage->nCurrCall++; + } + } + else if (opcode == 0x08) // tjz + { + nOpSize += SkipSignedOffset(&pOpcode[nOpSize]); + } + else if (opcode == 0x09) // djnz + { + nOpSize += SkipSignedOffset(&pOpcode[nOpSize]); + } + else if (opcode == 0x0a) // jz + { + nOpSize += SkipSignedOffset(&pOpcode[nOpSize]); + } + else if (opcode == 0x0b) // jnz + { + nOpSize += SkipSignedOffset(&pOpcode[nOpSize]); + } + else if (opcode >= 0x0c && opcode <= 0x15) + { + if (opcode == 0x0c) // casedone + { + } + else if (opcode == 0x0d) // casevalue + { + nOpSize += SkipSignedOffset(&pOpcode[nOpSize]); + } + else if (opcode == 0x0e) // caserange + { + nOpSize += SkipSignedOffset(&pOpcode[nOpSize]); + } + else if (opcode == 0x0f) // lookdone + { + } + else if (opcode == 0x10) // lookupval + { + } + else if (opcode == 0x11) // lookdnval + { + } + else if (opcode == 0x12) // lookuprng + { + } + else if (opcode == 0x13) // lookdnrng + { + } + else if (opcode == 0x14) // pop + { + } + else if (opcode == 0x15) // run + { + } + else + { + printf("%2.2x - NOT IMPLEMENTED\n", opcode); + } + } + else if (opcode >= 0x16 && opcode <= 0x23) + { + if (opcode == 0x16) // strsize + { + } + else if (opcode == 0x17) // strcomp + { + } + else if (opcode == 0x18) // bytefill + { + } + else if (opcode == 0x19) // wordfill + { + } + else if (opcode == 0x1a) // longfill + { + } + else if (opcode == 0x1b) // waitpeq + { + } + else if (opcode >= 0x1c && opcode <= 0x1e ) // bytemove, wordmove, longmove + { + } + else if (opcode == 0x1f) // waitpne + { + } + else if (opcode == 0x20) // clkset + { + } + else if (opcode == 0x21) // cogstop + { + } + else if (opcode == 0x22) // lockret + { + } + else if (opcode == 0x23) // waitcnt + { + } + } + else if (opcode >= 0x24 && opcode <= 0x2f) + { + if (opcode >= 0x24 && opcode <= 0x26) // ldregx, stregx, exregx + { + int operand = ((opcode & 3) << 5); + nOpSize += ScanRegisterOpcode(&pOpcode[nOpSize], operand); + } + else if (opcode == 0x27) // waitvid + { + } + else if (opcode == 0x28 || opcode == 0x2c) // coginitret, coginit + { + } + else if (opcode == 0x29 || opcode == 0x2d) // locknewret, locknew + { + } + else if (opcode == 0x2a || opcode == 0x2b || opcode == 0x2e || opcode == 0x2f) // locksetret, lockclrret, lockset, lockclr + { + } + } + else if (opcode >= 0x30 && opcode <= 0x33) // abort, abortval, ret, retval + { + } + else if (opcode >= 0x34 && opcode < 0x3c) + { + if (opcode == 0x35) // dli0 + { + } + else if (opcode == 0x36) // dli1 + { + } + else if (opcode == 0x34) // dlim1 + { + } + else if (opcode == 0x37) // ldlip + { + nOpSize++; + } + else // ldbi, ldwi, ldmi, ldli + { + while (opcode-- >= 0x38) + { + nOpSize++; + } + } + } + else if (opcode == 0x3d) // ldregbit, stregbit, exregbit + { + int operand = pOpcode[nOpSize]; + nOpSize++; + + nOpSize += ScanRegisterOpcode(&pOpcode[nOpSize], operand); + } + else if (opcode == 0x3e) // ldregbits, stregbits, exregbits + { + int operand = pOpcode[nOpSize]; + nOpSize++; + + nOpSize += ScanRegisterOpcode(&pOpcode[nOpSize], operand); + } + else if (opcode == 0x3f) // ldreg, streg, exreg + { + int operand = pOpcode[nOpSize]; + nOpSize++; + + nOpSize += ScanRegisterOpcode(&pOpcode[nOpSize], operand); + } + else + { + printf("NOT PROCESSED\n"); + } + + return nOpSize; +} + + +int ScanOpcode(unsigned char* pOpcode, MethodUsage* pUsage, ObjectEntry* pObject, unsigned char* pMethodStart) +{ + if (*pOpcode < 0x40) + { + return ScanLowerOpcode(pOpcode, pUsage, pObject, pMethodStart); + } + else if (*pOpcode < 0xe0) + { + return ScanMemoryOpcode(pOpcode); + } + else + { + return ScanMathOpcode(pOpcode); + } +} + + +void ScanMethod(unsigned char* pMethod, MethodUsage* pUsage, ObjectEntry* pObject) +{ +#ifdef RPE_DEBUG + for (int i = 0; i < pUsage->nLength; i++) + { + printf("%02x ", pMethod[i]); + } + printf("\n"); +#endif + + // scan once to count calls + int nOffset = 0; + while (nOffset < pUsage->nLength) + { + nOffset += ScanOpcode(&pMethod[nOffset], pUsage, pObject, pMethod); + } + if (pUsage->nCalls > 0) + { + // if there were calls then allocate space and scan again to fill in call info + pUsage->pCalls = new CallEntry[pUsage->nCalls]; + nOffset = 0; + while (nOffset < pUsage->nLength) + { + nOffset += ScanOpcode(&pMethod[nOffset], pUsage, pObject, pMethod); + } + } +} + +void ScanObjectMethods(ObjectEntry* pObjectEntry) +{ + for (int i = 0; i < pObjectEntry->nObjectMethodCount; i++) + { + unsigned char* pMethod = pObjectEntry->pObject + pObjectEntry->pIndexTable[i].offset; + int nLength = 0; + if (i < pObjectEntry->nObjectMethodCount-1) + { + nLength = pObjectEntry->pIndexTable[i+1].offset - pObjectEntry->pIndexTable[i].offset; + } + else + { + int nNextObjectOffset = *((unsigned short *)(pObjectEntry->pObject)); + nLength = nNextObjectOffset - pObjectEntry->pIndexTable[i].offset; + } + pObjectEntry->pMethods[i].nLength = nLength; + ScanMethod(pMethod, &(pObjectEntry->pMethods[i]), pObjectEntry); + } +} + +void MarkCalls(MethodUsage* pMethod, ObjectEntry* pObject) +{ + if (pMethod->nCalled == 0) + { + pMethod->nCalled = 1; + pObject->nMethodsCalled++; + + for (int nCall = 0; nCall < pMethod->nCalls; nCall++) + { + CallEntry* pCall = &(pMethod->pCalls[nCall]); + if ( pCall->opcode == 5 ) // normal call + { + MarkCalls(&(pObject->pMethods[pCall->pubnum-1]), pObject); + } + else // obj call + { + ObjectEntry* pSubObject = GetObject((unsigned char*)(pCall->objaddress)); + MarkCalls(&(pSubObject->pMethods[pCall->pubnum-1]), pSubObject); + } + } + } +} + +void FindUnusedMethods(CompilerData* pCompilerData) +{ + for (int i = 0; i < file_limit; i++) + { + s_objects[i].pObject = 0; + s_objects[i].nObjectMethodCount = 0; + s_objects[i].nObjectSubObjectCount = 0; + s_objects[i].nObjectIndexCount = 0; + s_objects[i].nMethodsCalled = 0; + s_objects[i].nNewObjectIndex = 0; + s_objects[i].pIndexTable = 0; + s_objects[i].pMethods = 0; + } + s_nNumObjects = 0; + + BuildTables(&(pCompilerData->obj[4]), 0, 0); + + for (int i = 0; i < s_nNumObjects; i++) + { + ScanObjectMethods(&s_objects[i]); + } + + ObjectEntry* pObject = &(s_objects[0]); + MethodUsage* pMethod = &(pObject->pMethods[0]); + MarkCalls(pMethod, pObject); +} + +/////////////////////////////////////////////////////////////////////////////////////////// +// TERMS OF USE: MIT License // +/////////////////////////////////////////////////////////////////////////////////////////// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this // +// software and associated documentation files (the "Software"), to deal in the Software // +// without restriction, including without limitation the rights to use, copy, modify, // +// merge, publish, distribute, sublicense, and/or sell copies of the Software, and to // +// permit persons to whom the Software is furnished to do so, subject to the following // +// conditions: // +// // +// The above copyright notice and this permission notice shall be included in all copies // +// or substantial portions of the Software. // +// // +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, // +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A // +// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE // +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +/////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/PropellerCompiler/UnusedMethodUtils.h b/PropellerCompiler/UnusedMethodUtils.h new file mode 100644 index 0000000..f021a6c --- /dev/null +++ b/PropellerCompiler/UnusedMethodUtils.h @@ -0,0 +1,44 @@ +/////////////////////////////////////////////////////////////// +// // +// Propeller Spin/PASM Compiler Command Line Tool 'OpenSpin' // +// (c)2012-2015 Parallax Inc. DBA Parallax Semiconductor. // +// See end of file for terms of use. // +// // +/////////////////////////////////////////////////////////////// +// +// UnusedMethodUtils.h +// + +struct CompilerData; + +void AddObjectName(char* pFilename, int indent); +void FindUnusedMethods(CompilerData* pCompilerData); +void CleanUpUnusedMethodData(); +void InitUnusedMethodData(); + +bool IsObjectUsed(char* pFilename); +bool IsMethodUsed(char* pFilename, int nMethod); +void AddObjectPubConList(char* pFilename, unsigned char* pPubConList, int nPubConListSize); +bool GetObjectPubConList(char* pFilename, unsigned char** ppPubConList, int* pnPubConListSize); + + +/////////////////////////////////////////////////////////////////////////////////////////// +// TERMS OF USE: MIT License // +/////////////////////////////////////////////////////////////////////////////////////////// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this // +// software and associated documentation files (the "Software"), to deal in the Software // +// without restriction, including without limitation the rights to use, copy, modify, // +// merge, publish, distribute, sublicense, and/or sell copies of the Software, and to // +// permit persons to whom the Software is furnished to do so, subject to the following // +// conditions: // +// // +// The above copyright notice and this permission notice shall be included in all copies // +// or substantial portions of the Software. // +// // +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, // +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A // +// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE // +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +/////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/PropellerCompiler/Utilities.cpp b/PropellerCompiler/Utilities.cpp index 93f370c..6304385 100644 --- a/PropellerCompiler/Utilities.cpp +++ b/PropellerCompiler/Utilities.cpp @@ -480,7 +480,7 @@ bool GetFilename(int& filenameStart, int& filenameFinish) filenameStart = g_pCompilerData->source_start; g_pElementizer->Backup(); - while(1) + for (;;) { g_pElementizer->GetNext(bEof); if (g_pElementizer->GetType() != type_con) @@ -498,7 +498,7 @@ bool GetFilename(int& filenameStart, int& filenameFinish) { g_pCompilerData->error = true; g_pCompilerData->error_msg = g_pErrorStrings[error_ifc]; - return false; + break; } // add character @@ -510,7 +510,7 @@ bool GetFilename(int& filenameStart, int& filenameFinish) { g_pCompilerData->error = true; g_pCompilerData->error_msg = g_pErrorStrings[error_ftl]; - return false; + break; } if (!g_pElementizer->CheckElement(type_comma)) diff --git a/SpinSource/SpinSource.vcproj b/SpinSource/SpinSource.vcproj deleted file mode 100644 index cd76e55..0000000 --- a/SpinSource/SpinSource.vcproj +++ /dev/null @@ -1,249 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/SpinSource/SpinSource.vcxproj b/SpinSource/SpinSource.vcxproj new file mode 100644 index 0000000..3107024 --- /dev/null +++ b/SpinSource/SpinSource.vcxproj @@ -0,0 +1,119 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + openspin + {A52778A6-7ABC-4FC5-B238-A6337AB2CC1F} + spin + Win32Proj + + + + Application + v120 + Unicode + true + + + Application + v120 + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>12.0.30501.0 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + + Disabled + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + Level4 + EditAndContinue + + + true + Console + MachineX86 + false + + + + + MaxSpeed + true + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + true + + Level4 + ProgramDatabase + + + true + Console + true + true + MachineX86 + + + + + CompileAsCpp + + + + + + CompileAsCpp + + + + + + + + + + + + + {de0e4a74-1c7f-4479-918d-9040bb599f90} + false + + + + + + \ No newline at end of file diff --git a/SpinSource/flexbuf.c b/SpinSource/flexbuf.cpp similarity index 100% rename from SpinSource/flexbuf.c rename to SpinSource/flexbuf.cpp diff --git a/SpinSource/openspin.cpp b/SpinSource/openspin.cpp index 70bc5a2..a7e2c4a 100644 --- a/SpinSource/openspin.cpp +++ b/SpinSource/openspin.cpp @@ -1,7 +1,7 @@ /////////////////////////////////////////////////////////////// // // // Propeller Spin/PASM Compiler Command Line Tool 'OpenSpin' // -// (c)2012-2013 Parallax Inc. DBA Parallax Semiconductor. // +// (c)2012-2015 Parallax Inc. DBA Parallax Semiconductor. // // Adapted from Jeff Martin's Delphi code by Roy Eltham // // See end of file for terms of use. // // // @@ -21,10 +21,8 @@ #include "preprocess.h" #define ObjFileStackLimit 16 - #define ListLimit 2000000 #define DocLimit 2000000 - #define MAX_FILES 2048 // an object can only reference 32 other objects and only 32 dat files, so the worst case is 32*32*2 files static struct preprocess s_preprocessor; @@ -34,6 +32,7 @@ static bool s_bAlternatePreprocessorMode = false; static int s_nObjStackPtr = 0; static int s_nFilesAccessed = 0; static char s_filesAccessed[MAX_FILES][PATH_MAX]; +static bool s_bFinalCompile = false; static void Banner(void) { @@ -63,6 +62,7 @@ usage: openspin\n\ [ -D ] add a define\n\ [ -M ] size of eeprom (up to 16777216 bytes)\n\ [ -s ] dump PUB & CON symbol information for top object\n\ + [ -u ] enable unused method elimination\n\ spin file to compile\n\ \n"); } @@ -277,6 +277,18 @@ bool CompileRecursively(char* pFilename, bool bQuiet, bool bFileTreeOutputOnly) return false; } + if ( !s_pCompilerData->bFinalCompile ) + { + AddObjectName(pFilename, s_nObjStackPtr); + } + + strcpy(s_pCompilerData->current_filename, pFilename); + char* pExtension = strstr(s_pCompilerData->current_filename, ".spin"); + if (pExtension != 0) + { + *pExtension = 0; + } + // first pass on object const char* pErrorString = Compile1(); if (pErrorString != 0) @@ -320,6 +332,12 @@ bool CompileRecursively(char* pFilename, bool bQuiet, bool bFileTreeOutputOnly) return false; } + strcpy(s_pCompilerData->current_filename, pFilename); + char* pExtension = strstr(s_pCompilerData->current_filename, ".spin"); + if (pExtension != 0) + { + *pExtension = 0; + } pErrorString = Compile1(); if (pErrorString != 0) { @@ -364,6 +382,12 @@ bool CompileRecursively(char* pFilename, bool bQuiet, bool bFileTreeOutputOnly) } // second pass of object + strcpy(s_pCompilerData->current_filename, pFilename); + pExtension = strstr(s_pCompilerData->current_filename, ".spin"); + if (pExtension != 0) + { + *pExtension = 0; + } pErrorString = Compile2(); if (pErrorString != 0) { @@ -470,7 +494,8 @@ bool ComposeRAM(unsigned char** ppBuffer, int& bufferSize, bool bDATonly, bool b return true; } -void CleanupMemory() + +void CleanupMemory(bool bPathsAndUnusedMethodData = true) { // cleanup if ( s_pCompilerData ) @@ -481,7 +506,11 @@ void CleanupMemory() delete [] s_pCompilerData->source; } CleanObjectHeap(); - CleanupPathEntries(); + if (bPathsAndUnusedMethodData) + { + CleanupPathEntries(); + CleanUpUnusedMethodData(); + } Cleanup(); } @@ -504,6 +533,7 @@ int main(int argc, char* argv[]) bool bFileTreeOutputOnly = false; bool bFileListOutputOnly = false; bool bDumpSymbols = false; + bool bUnusedMethodElimination = false; // go through the command line arguments, skipping over any -D for(int i = 1; i < argc; i++) @@ -644,6 +674,10 @@ int main(int argc, char* argv[]) bDumpSymbols = true; break; + case 'u': + bUnusedMethodElimination = true; + break; + case 'h': default: Usage(); @@ -777,7 +811,11 @@ int main(int argc, char* argv[]) printf("%s\n", infile); } + InitUnusedMethodData(); + +restart_compile: s_pCompilerData = InitStruct(); + s_pCompilerData->bFinalCompile = s_bFinalCompile; s_pCompilerData->list = new char[ListLimit]; s_pCompilerData->list_limit = ListLimit; @@ -823,6 +861,13 @@ int main(int argc, char* argv[]) if (!bFileTreeOutputOnly && !bFileListOutputOnly && !bDumpSymbols) { + if (!s_bFinalCompile && bUnusedMethodElimination) + { + FindUnusedMethods(s_pCompilerData); + s_bFinalCompile = true; + CleanupMemory(false); + goto restart_compile; + } unsigned char* pBuffer = NULL; int bufferSize = 0; if (ComposeRAM(&pBuffer, bufferSize, bDATonly, bBinary, eeprom_size)) diff --git a/SpinSource/preprocess.c b/SpinSource/preprocess.cpp similarity index 99% rename from SpinSource/preprocess.c rename to SpinSource/preprocess.cpp index 0860ce4..8ad3ef2 100644 --- a/SpinSource/preprocess.c +++ b/SpinSource/preprocess.cpp @@ -824,7 +824,10 @@ do_line(struct preprocess *pp) // because spin has the # as a valid part of it's syntax and that can be at the start of a line, // this isn't an error, but instead needs to be parsed like a normal line // first restore the line - *(P.save) = (char)(P.c); + if (P.save) + { + *(P.save) = (char)(P.c); + } r = expand_macros(pp, &pp->line, data); } } diff --git a/openspin.sln b/openspin.sln index 54f7587..5eecc41 100644 --- a/openspin.sln +++ b/openspin.sln @@ -1,12 +1,11 @@  -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spin", "SpinSource\SpinSource.vcproj", "{A52778A6-7ABC-4FC5-B238-A6337AB2CC1F}" - ProjectSection(ProjectDependencies) = postProject - {DE0E4A74-1C7F-4479-918D-9040BB599F90} = {DE0E4A74-1C7F-4479-918D-9040BB599F90} - EndProjectSection +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openspin", "SpinSource\SpinSource.vcxproj", "{A52778A6-7ABC-4FC5-B238-A6337AB2CC1F}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PropellerCompiler", "PropellerCompiler\PropellerCompiler.vcproj", "{DE0E4A74-1C7F-4479-918D-9040BB599F90}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PropellerCompiler", "PropellerCompiler\PropellerCompiler.vcxproj", "{DE0E4A74-1C7F-4479-918D-9040BB599F90}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution