From 6bb363fb4bace6b9786ea8131867ec534390969d Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Thu, 17 Dec 2020 04:51:05 -0800 Subject: [PATCH] CTFE updates, including heap support --- BeefLibs/corlib/src/Diagnostics/Debug.bf | 2 + BeefySysLib/BeefySysLib.vcxproj | 2 + BeefySysLib/BeefySysLib.vcxproj.filters | 6 + BeefySysLib/BeefySysLib_static.vcxproj | 2 + .../BeefySysLib_static.vcxproj.filters | 6 + BeefySysLib/platform/win/CrashCatcher.cpp | 3 + BeefySysLib/util/AllocDebug.h | 29 +- BeefySysLib/util/Heap.cpp | 335 +++ BeefySysLib/util/Heap.h | 32 + IDE/src/Compiler/BfPassInstance.bf | 2 +- IDE/src/IDEApp.bf | 14 +- IDE/src/ui/SourceViewPanel.bf | 7 +- IDEHelper/Backend/BeIRCodeGen.cpp | 64 +- IDEHelper/Backend/BeModule.cpp | 11 + IDEHelper/Backend/BeModule.h | 115 + IDEHelper/Compiler/BfCompiler.cpp | 7 +- IDEHelper/Compiler/BfCompiler.h | 1 + IDEHelper/Compiler/BfContext.cpp | 22 +- IDEHelper/Compiler/BfExprEvaluator.cpp | 40 +- IDEHelper/Compiler/BfIRBuilder.cpp | 58 +- IDEHelper/Compiler/BfIRBuilder.h | 10 + IDEHelper/Compiler/BfModule.cpp | 119 +- IDEHelper/Compiler/BfResolvedTypeUtils.cpp | 15 +- IDEHelper/Compiler/BfResolvedTypeUtils.h | 5 +- IDEHelper/Compiler/BfStmtEvaluator.cpp | 5 +- IDEHelper/Compiler/BfSystem.cpp | 49 +- IDEHelper/Compiler/BfSystem.h | 20 +- IDEHelper/Compiler/CeMachine.cpp | 2466 ++++++++++++++--- IDEHelper/Compiler/CeMachine.h | 198 +- 29 files changed, 3050 insertions(+), 595 deletions(-) create mode 100644 BeefySysLib/util/Heap.cpp create mode 100644 BeefySysLib/util/Heap.h diff --git a/BeefLibs/corlib/src/Diagnostics/Debug.bf b/BeefLibs/corlib/src/Diagnostics/Debug.bf index b88b55a8..d4df7bd4 100644 --- a/BeefLibs/corlib/src/Diagnostics/Debug.bf +++ b/BeefLibs/corlib/src/Diagnostics/Debug.bf @@ -36,6 +36,8 @@ namespace System.Diagnostics [CallingConvention(.Cdecl)] static extern void Write(char8* str, int strLen); + [CallingConvention(.Cdecl)] + static extern void Write(int val); public static void Write(String line) { diff --git a/BeefySysLib/BeefySysLib.vcxproj b/BeefySysLib/BeefySysLib.vcxproj index aa1fb938..46f8d0c6 100644 --- a/BeefySysLib/BeefySysLib.vcxproj +++ b/BeefySysLib/BeefySysLib.vcxproj @@ -1932,6 +1932,7 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\" + @@ -2159,6 +2160,7 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\" + diff --git a/BeefySysLib/BeefySysLib.vcxproj.filters b/BeefySysLib/BeefySysLib.vcxproj.filters index 0b9db518..a4f7ebce 100644 --- a/BeefySysLib/BeefySysLib.vcxproj.filters +++ b/BeefySysLib/BeefySysLib.vcxproj.filters @@ -704,6 +704,9 @@ src\platform\win + + src\util + @@ -1069,6 +1072,9 @@ src\platform\win + + src\util + diff --git a/BeefySysLib/BeefySysLib_static.vcxproj b/BeefySysLib/BeefySysLib_static.vcxproj index b65c738e..b7398576 100644 --- a/BeefySysLib/BeefySysLib_static.vcxproj +++ b/BeefySysLib/BeefySysLib_static.vcxproj @@ -868,6 +868,7 @@ + @@ -1029,6 +1030,7 @@ + diff --git a/BeefySysLib/BeefySysLib_static.vcxproj.filters b/BeefySysLib/BeefySysLib_static.vcxproj.filters index 5bb87d3d..486d3602 100644 --- a/BeefySysLib/BeefySysLib_static.vcxproj.filters +++ b/BeefySysLib/BeefySysLib_static.vcxproj.filters @@ -569,6 +569,9 @@ src\util + + src\util + @@ -871,6 +874,9 @@ src\util + + src\util + diff --git a/BeefySysLib/platform/win/CrashCatcher.cpp b/BeefySysLib/platform/win/CrashCatcher.cpp index 2d7ce4fd..0177eb57 100644 --- a/BeefySysLib/platform/win/CrashCatcher.cpp +++ b/BeefySysLib/platform/win/CrashCatcher.cpp @@ -1156,6 +1156,9 @@ void CrashCatcher::Crash(const StringImpl& str) { }*/ + + for (auto func : CrashCatcher::Get()->mCrashInfoFuncs) + func(); exit(1); } diff --git a/BeefySysLib/util/AllocDebug.h b/BeefySysLib/util/AllocDebug.h index c0ce11d1..cf6bc8af 100644 --- a/BeefySysLib/util/AllocDebug.h +++ b/BeefySysLib/util/AllocDebug.h @@ -2,6 +2,8 @@ //#define BP_ALLOC_TRACK +#include + #ifdef BF_PLATFORM_WINDOWS #define _CRTDBG_MAP_ALLOC @@ -87,4 +89,29 @@ void BpDump(); #endif void* StompAlloc(int size); -void StompFree(void* addr); \ No newline at end of file +void StompFree(void* addr); + +template +class AllocatorStomp +{ +public: + T* allocate(intptr_t count) + { + return (T*)StompAlloc((int)(sizeof(T) * count)); + } + + void deallocate(T* ptr) + { + StompFree(ptr); + } + + void* rawAllocate(intptr_t size) + { + return StompAlloc((int)size); + } + + void rawDeallocate(void* ptr) + { + StompFree(ptr); + } +}; diff --git a/BeefySysLib/util/Heap.cpp b/BeefySysLib/util/Heap.cpp new file mode 100644 index 00000000..2410a9d5 --- /dev/null +++ b/BeefySysLib/util/Heap.cpp @@ -0,0 +1,335 @@ +#include "Heap.h" +#include "DLIList.h" + +USING_NS_BF; + +////////////////////////////////////////////////////////////////////////// + +#define CH_REL_TO_ABS(VAL) ((ChBlock*)((uint8*)mMetadata + (VAL))) +#define CH_REL_TO_ABS(VAL) ((ChBlock*)((uint8*)mMetadata + (VAL))) +#define CH_ABS_TO_REL(VAL) (int)((uint8*)(VAL) - (uint8*)mMetadata) + +enum ChBlockKind +{ + ChBlockKind_Bad = 0xBEEF0BAD, + ChBlockKind_Unused = 0xBEEF1212, + ChBlockKind_Used = 0xBEEF2323, + ChBlockKind_Merged = 0xBEEF3434, +}; + +struct ChBlock +{ + ContiguousHeap::AllocRef mPrev; + ContiguousHeap::AllocRef mNext; + int mSize; + ChBlockKind mKind; + + ChBlock() + { + mPrev = -1; + mNext = -1; + mSize = 0; + mKind = ChBlockKind_Bad; + } +}; + +class ChList +{ +public: + void* mMetadata; + int32 mHead; + int32 mTail; + +public: + ChList() + { + mHead = -1; + mTail = -1; + } + + void Size() + { + int size = 0; + int checkNode = mHead; + while (checkNode != NULL) + { + size++; + checkNode = CH_REL_TO_ABS(checkNode)->mNext; + } + } + + void PushBack(int node) + { + BF_ASSERT(CH_REL_TO_ABS(node)->mNext == -1); + + if (mHead == -1) + mHead = node; + else + { + CH_REL_TO_ABS(mTail)->mNext = node; + CH_REL_TO_ABS(node)->mPrev = mTail; + } + mTail = node; + } + + void AddAfter(int refNode, int newNode) + { + int32 prevNext = CH_REL_TO_ABS(refNode)->mNext; + CH_REL_TO_ABS(refNode)->mNext = newNode; + CH_REL_TO_ABS(newNode)->mPrev = refNode; + CH_REL_TO_ABS(newNode)->mNext = prevNext; + if (prevNext != -1) + CH_REL_TO_ABS(prevNext)->mPrev = newNode; + if (refNode == mTail) + mTail = newNode; + } + + void Remove(int node) + { + if (CH_REL_TO_ABS(node)->mPrev == -1) + { + mHead = CH_REL_TO_ABS(node)->mNext; + if (mHead != -1) + CH_REL_TO_ABS(mHead)->mPrev = -1; + } + else + CH_REL_TO_ABS(CH_REL_TO_ABS(node)->mPrev)->mNext = CH_REL_TO_ABS(node)->mNext; + + if (CH_REL_TO_ABS(node)->mNext == -1) + { + mTail = CH_REL_TO_ABS(node)->mPrev; + if (mTail != -1) + CH_REL_TO_ABS(mTail)->mNext = -1; + } + else + CH_REL_TO_ABS(CH_REL_TO_ABS(node)->mNext)->mPrev = CH_REL_TO_ABS(node)->mPrev; + + CH_REL_TO_ABS(node)->mPrev = -1; + CH_REL_TO_ABS(node)->mNext = -1; + } + + bool IsEmpty() + { + return mHead == -1; + } +}; + +////////////////////////////////////////////////////////////////////////// + +ContiguousHeap::ContiguousHeap() +{ + mMetadata = NULL; + mMemorySize = 0; + mBlockDataOfs = 0; + mFreeIdx = 0; +} + +ContiguousHeap::~ContiguousHeap() +{ + free(mMetadata); +} + +void ContiguousHeap::Clear(int maxAllocSize) +{ + if (mBlockDataOfs == 0) + return; + + mBlockDataOfs = 0; + mFreeList.Clear(); + if ((mMemorySize != -1) && (mMemorySize > maxAllocSize)) + { + free(mMetadata); + mMetadata = NULL; + mMemorySize = 0; + return; + } + + auto blockList = (ChList*)mMetadata; + if (blockList->mHead != -1) + { + auto block = CH_REL_TO_ABS(blockList->mHead); + while (block != NULL) + { + block->mKind = ChBlockKind_Bad; + block = CH_REL_TO_ABS(block->mNext); + } + } + blockList->mHead = -1; + blockList->mTail = -1; +} + +ContiguousHeap::AllocRef ContiguousHeap::Alloc(int size) +{ + if (size == 0) + return 0; + + size = BF_ALIGN(size, 16); + + auto blockList = (ChList*)mMetadata; + + while (true) + { + for (int itr = 0; itr < (int)mFreeList.size(); itr++) + { + auto block = (ChBlock*)((uint8*)mMetadata + mFreeList[mFreeIdx]); + + if (block->mKind == ChBlockKind_Merged) + { + itr--; + if (mFreeIdx >= mFreeList.mSize) + mFreeIdx = 0; + block->mKind = (ChBlockKind)0; + mFreeList.RemoveAtFast(mFreeIdx); + continue; + } + + BF_ASSERT(block->mKind == ChBlockKind_Unused); + + if (block->mSize >= size) + { + mFreeList.RemoveAtFast(mFreeIdx); + if (block->mSize >= size + 64) + { + // Split block + auto newBlock = new ((uint8*)block + size) ChBlock(); + newBlock->mSize = block->mSize - size; + newBlock->mKind = ChBlockKind_Unused; + blockList->AddAfter(CH_ABS_TO_REL(block), CH_ABS_TO_REL(newBlock)); + block->mSize = size; + + mFreeList.Add(CH_ABS_TO_REL(newBlock)); + } + + block->mKind = ChBlockKind_Used; + return CH_ABS_TO_REL(block); + } + + mFreeIdx = (mFreeIdx + 1) % mFreeList.mSize; + } + + int wantSize = BF_MAX(mMemorySize + mMemorySize / 2, mMemorySize + BF_MAX(size, 64 * 1024)); + mMetadata = realloc(mMetadata, wantSize); + + memset((uint8*)mMetadata + mMemorySize, 0, wantSize - mMemorySize); + + blockList = (ChList*)mMetadata; + mMemorySize = wantSize; + + if (mBlockDataOfs == 0) + { + blockList = new (mMetadata) ChList(); + mBlockDataOfs = sizeof(ChList); + } + blockList->mMetadata = mMetadata; + + auto block = new ((uint8*)mMetadata + mBlockDataOfs) ChBlock(); + block->mSize = mMemorySize - mBlockDataOfs; + block->mKind = ChBlockKind_Unused; + mBlockDataOfs += block->mSize; + blockList->PushBack(CH_ABS_TO_REL(block)); + + mFreeList.Add(CH_ABS_TO_REL(block)); + } +} + +bool ContiguousHeap::Free(AllocRef ref) +{ + if ((ref < 0) || (ref > mMemorySize - sizeof(ChBlock))) + return false; + + auto blockList = (ChList*)mMetadata; + auto block = CH_REL_TO_ABS(ref); + + if (block->mKind != ChBlockKind_Used) + return false; + + int headAccSize = 0; + auto mergeHead = block; + while (mergeHead->mPrev != -1) + { + auto checkBlock = CH_REL_TO_ABS(mergeHead->mPrev); + if (checkBlock->mKind != ChBlockKind_Unused) + break; + headAccSize += mergeHead->mSize; + // Mark PREVIOUS as merged, only leave the current alive + mergeHead->mKind = ChBlockKind_Merged; + blockList->Remove(CH_ABS_TO_REL(mergeHead)); + mergeHead = checkBlock; + } + + int tailAccSize = 0; + if (mergeHead->mNext != -1) + { + auto mergeTail = CH_REL_TO_ABS(mergeHead->mNext); + while (mergeTail->mKind == ChBlockKind_Unused) + { + ChBlock* nextBlock = NULL; + if (mergeTail->mNext != -1) + nextBlock = CH_REL_TO_ABS(mergeTail->mNext); + tailAccSize += mergeTail->mSize; + mergeTail->mKind = ChBlockKind_Merged; + blockList->Remove(CH_ABS_TO_REL(mergeTail)); + if (nextBlock == NULL) + break; + mergeTail = nextBlock; + } + } + + mergeHead->mSize += tailAccSize + headAccSize; + if ((mergeHead->mKind != ChBlockKind_Unused) && (mergeHead->mKind != ChBlockKind_Merged)) + { + // If it were MERGED that means it's still in the free list + mFreeList.Add(CH_ABS_TO_REL(mergeHead)); + } + mergeHead->mKind = ChBlockKind_Unused; + return true; +} + +void ContiguousHeap::DebugDump() +{ + String str = "Heap Dump:\n"; + + auto blockList = (ChList*)mMetadata; + + if (blockList->mHead != -1) + { + int totalSize = 0; + + auto block = CH_REL_TO_ABS(blockList->mHead); + while (block != NULL) + { + str += StrFormat("@%d: %d ", CH_ABS_TO_REL(block), block->mSize); + switch (block->mKind) + { + case ChBlockKind_Unused: + str += "Unused"; + break; + case ChBlockKind_Used: + str += "Used"; + break; + case ChBlockKind_Merged: + str += "Merged"; + break; + default: + str += "??????"; + } + + str += "\n"; + + totalSize += block->mSize; + + if (block->mNext == -1) + break; + block = CH_REL_TO_ABS(block->mNext); + } + + str += StrFormat("Sum: %d Allocated: %d\n", totalSize, mMemorySize); + } + + str += "\nFree List:\n"; + for (auto val : mFreeList) + str += StrFormat("@%d\n", val); + str += "\n"; + + OutputDebugStrF(str.c_str()); +} diff --git a/BeefySysLib/util/Heap.h b/BeefySysLib/util/Heap.h new file mode 100644 index 00000000..d1a8cf57 --- /dev/null +++ b/BeefySysLib/util/Heap.h @@ -0,0 +1,32 @@ +#pragma once + +#include "../Common.h" + +NS_BF_BEGIN + +class ContiguousHeap +{ +public: + typedef int AllocRef; + +public: + void* mMetadata; + + int mMemorySize; + int mBlockDataOfs; + Array mFreeList; + int mFreeIdx; + +public: + ContiguousHeap(); + virtual ~ContiguousHeap(); + + void Clear(int maxAllocSize = -1); + + AllocRef Alloc(int size); + bool Free(AllocRef ref); + + void DebugDump(); +}; + +NS_BF_END \ No newline at end of file diff --git a/IDE/src/Compiler/BfPassInstance.bf b/IDE/src/Compiler/BfPassInstance.bf index 49e22c40..0e98d30e 100644 --- a/IDE/src/Compiler/BfPassInstance.bf +++ b/IDE/src/Compiler/BfPassInstance.bf @@ -141,7 +141,7 @@ namespace IDE.Compiler { char8* fileName = null; char8* errorStr = BfPassInstance_Error_GetMoreInfoData(mNativeBfPassInstance, errorIdx, moreInfoIdx, out fileName, out bfError.mSrcStart, out bfError.mSrcEnd, - getLine ? &bfError.mLine : null, getLine ? &bfError.mColumn : null); + &bfError.mLine, &bfError.mColumn); Debug.Assert(bfError.mFilePath == null); if (fileName != null) bfError.mFilePath = new String(fileName); diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index 2d528b57..aa492127 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -1054,13 +1054,25 @@ namespace IDE if (var sourceViewPanel = GetActiveSourceViewPanel(true)) sourceViewPanel.RecordHistoryLocation(); - int32 charIdx = int32.Parse(cmds[2]).GetValueOrDefault(); + StringView loc = cmds[2]; + int32 charIdx = int32.Parse(loc).GetValueOrDefault(); if (charIdx < 0) return; var sourceViewPanel = ShowSourceFile(cmds[1], null, SourceShowType.Temp); if (sourceViewPanel == null) return; var editWidgetContent = sourceViewPanel.mEditWidget.mEditWidgetContent; + + int colonIdx = loc.IndexOf(':'); + if (colonIdx != -1) + { + int line = int.Parse(loc.Substring(0, colonIdx)).GetValueOrDefault(); + int column = int.Parse(loc.Substring(colonIdx + 1)).GetValueOrDefault(); + charIdx = (.)editWidgetContent.GetTextIdx(line, column); + } + if (charIdx < 0) + return; + int line; int lineChar; editWidgetContent.GetLineCharAtIdx(charIdx, out line, out lineChar); diff --git a/IDE/src/ui/SourceViewPanel.bf b/IDE/src/ui/SourceViewPanel.bf index 744bc21b..bcd17036 100644 --- a/IDE/src/ui/SourceViewPanel.bf +++ b/IDE/src/ui/SourceViewPanel.bf @@ -4966,7 +4966,12 @@ namespace IDE.ui { for (var moreInfo in bestError.mMoreInfo) { - showMouseoverString.AppendF("\n@{0}\t{1}\t{2}", moreInfo.mFilePath, moreInfo.mSrcStart, moreInfo.mError); + if ((moreInfo.mSrcStart == -1) && (moreInfo.mSrcStart == -1) && (moreInfo.mLine != -1)) + { + showMouseoverString.AppendF("\n@{}\t{}:{}\t{}", moreInfo.mFilePath, moreInfo.mLine, moreInfo.mColumn, moreInfo.mError); + } + else + showMouseoverString.AppendF("\n@{0}\t{1}\t{2}", moreInfo.mFilePath, moreInfo.mSrcStart, moreInfo.mError); } } } diff --git a/IDEHelper/Backend/BeIRCodeGen.cpp b/IDEHelper/Backend/BeIRCodeGen.cpp index fc2ff4e9..240e0c5c 100644 --- a/IDEHelper/Backend/BeIRCodeGen.cpp +++ b/IDEHelper/Backend/BeIRCodeGen.cpp @@ -889,6 +889,9 @@ void BeIRCodeGen::Read(BeValue*& beValue) beValue = result.mBeValue; BE_MEM_END("ParamType_StreamId"); } + + if (beValue != NULL) + beValue->mRefCount++; } void BeIRCodeGen::Read(BeConstant*& llvmConstant) @@ -922,6 +925,8 @@ void BeIRCodeGen::Read(BeFunction*& beFunc) BF_ASSERT(BeValueDynCast(result.mBeValue)); beFunc = (BeFunction*)result.mBeValue; BE_MEM_END("BeFunction"); + + beFunc->mRefCount++; } void BeIRCodeGen::Read(BeBlock*& beBlock) @@ -932,6 +937,8 @@ void BeIRCodeGen::Read(BeBlock*& beBlock) BF_ASSERT(result.mKind == BeIRCodeGenEntryKind_Block); beBlock = (BeBlock*)result.mBeType; BE_MEM_END("BeBlock"); + + beBlock->mRefCount++; } void BeIRCodeGen::Read(BeMDNode*& llvmMD) @@ -947,6 +954,8 @@ void BeIRCodeGen::Read(BeMDNode*& llvmMD) BF_ASSERT(result.mKind == BeIRCodeGenEntryKind_Metadata); llvmMD = result.mBeMetadata; BE_MEM_END("BeMDNode"); + + llvmMD->mRefCount++; } void BeIRCodeGen::HandleNextCmd() @@ -2522,9 +2531,62 @@ void BeIRCodeGen::HandleNextCmd() auto inst = mBeModule->AllocInst(); inst->mValue = val; - SetResult(curId, mBeModule->GetInsertBlock()); + SetResult(curId, mBeModule->GetInsertBlock()); } break; + case BfIRCmd_ConstEval_GetBfType: + { + CMD_PARAM(int32, typeId); + CMD_PARAM(BeType*, resultType); + + auto inst = mBeModule->AllocInst(); + inst->mTypeId = typeId; + inst->mResultType = resultType; + SetResult(curId, inst); + } + break; + case BfIRCmd_ConstEval_DynamicCastCheck: + { + CMD_PARAM(BeValue*, value); + CMD_PARAM(int32, typeId); + CMD_PARAM(BeType*, resultType); + + auto inst = mBeModule->AllocInst(); + inst->mValue = value; + inst->mTypeId = typeId; + inst->mResultType = resultType; + SetResult(curId, inst); + } + break; + case BfIRCmd_ConstEval_GetVirtualFunc: + { + CMD_PARAM(BeValue*, value); + CMD_PARAM(int32, virtualTableIdx); + CMD_PARAM(BeType*, resultType); + + auto inst = mBeModule->AllocInst(); + inst->mValue = value; + inst->mVirtualTableIdx = virtualTableIdx; + inst->mResultType = resultType; + SetResult(curId, inst); + } + break; + case BfIRCmd_ConstEval_GetInterfaceFunc: + { + CMD_PARAM(BeValue*, value); + CMD_PARAM(int32, ifaceTypeId); + CMD_PARAM(int32, virtualTableIdx); + CMD_PARAM(BeType*, resultType); + + auto inst = mBeModule->AllocInst(); + inst->mValue = value; + inst->mIFaceTypeId = ifaceTypeId; + inst->mVirtualTableIdx = virtualTableIdx; + inst->mResultType = resultType; + SetResult(curId, inst); + } + break; + case BfIRCmd_DbgInit: { /*mDIBuilder = new BeDIBuilder(*mBeModule); */ diff --git a/IDEHelper/Backend/BeModule.cpp b/IDEHelper/Backend/BeModule.cpp index b52fadbe..2f337cc8 100644 --- a/IDEHelper/Backend/BeModule.cpp +++ b/IDEHelper/Backend/BeModule.cpp @@ -1723,6 +1723,13 @@ void BeDbgFile::ToString(String& str) str = '\\'; } +void BeDbgFile::GetFilePath(String& outStr) +{ + outStr.Append(mDirectory); + outStr.Append(DIR_SEP_CHAR); + outStr.Append(mFileName); +} + ////////////////////////////////////////////////////////////////////////// BeModule::BeModule(const StringImpl& moduleName, BeContext* context) @@ -2442,6 +2449,10 @@ String BeModule::ToString(BeFunction* wantFunc) } } break; + DISPLAY_INST1(BeConstEvalGetType, "ConstEvalGetType", mTypeId); + DISPLAY_INST2(BeConstEvalDynamicCastCheck, "ConstEvalDynamicCastCheck", mValue, mTypeId); + DISPLAY_INST2(BeConstEvalGetVirtualFunc, "ConstEvalGetVirtualFunc", mValue, mVirtualTableIdx); + DISPLAY_INST3(BeConstEvalGetInterfaceFunc, "ConstEvalGetInterfaceFunc", mValue, mIFaceTypeId, mVirtualTableIdx); default: BF_FATAL("Notimpl"); str += ""; diff --git a/IDEHelper/Backend/BeModule.h b/IDEHelper/Backend/BeModule.h index e24465ac..88e7ecf1 100644 --- a/IDEHelper/Backend/BeModule.h +++ b/IDEHelper/Backend/BeModule.h @@ -208,10 +208,12 @@ public: #ifdef _DEBUG bool mLifetimeEnded; bool mWasRemoved; + int mRefCount; BeValue() { mLifetimeEnded = false; mWasRemoved = false; + mRefCount = 0; } #endif @@ -264,6 +266,16 @@ T* BeValueDynCast(BeValue* value) return (T*)result; } +template +T* BeValueDynCastExact(BeValue* value) +{ + if (value == NULL) + return NULL; + if (value->GetTypeId() != T::TypeId) + return NULL; + return (T*)value; +} + class BeBlock; class BeInst; class BeModule; @@ -1320,6 +1332,106 @@ public: } }; +////////////////////////////////////////////////////////////////////////// + +class BeConstEvalGetType : public BeInst +{ +public: + BE_VALUE_TYPE(BeConstEvalGetType, BeInst); + +public: + int mTypeId; + BeType* mResultType; + +public: + virtual BeType* GetType() override + { + return mResultType; + } + + virtual void HashInst(BeHashContext& hashCtx) override + { + hashCtx.Mixin(TypeId); + hashCtx.Mixin(mTypeId); + } +}; + +class BeConstEvalDynamicCastCheck : public BeInst +{ +public: + BE_VALUE_TYPE(BeConstEvalDynamicCastCheck, BeInst); + +public: + BeValue* mValue; + int mTypeId; + BeType* mResultType; + +public: + virtual BeType* GetType() override + { + return mResultType; + } + + virtual void HashInst(BeHashContext& hashCtx) override + { + hashCtx.Mixin(TypeId); + mValue->HashReference(hashCtx); + hashCtx.Mixin(mTypeId); + } +}; + +class BeConstEvalGetVirtualFunc : public BeInst +{ +public: + BE_VALUE_TYPE(BeConstEvalGetVirtualFunc, BeInst); + +public: + BeValue* mValue; + int mVirtualTableIdx; + BeType* mResultType; + +public: + virtual BeType* GetType() override + { + return mResultType; + } + + virtual void HashInst(BeHashContext& hashCtx) override + { + hashCtx.Mixin(TypeId); + mValue->HashReference(hashCtx); + hashCtx.Mixin(mVirtualTableIdx); + } +}; + +class BeConstEvalGetInterfaceFunc : public BeInst +{ +public: + BE_VALUE_TYPE(BeConstEvalGetInterfaceFunc, BeInst); + +public: + BeValue* mValue; + int mIFaceTypeId; + int mVirtualTableIdx; + BeType* mResultType; + +public: + virtual BeType* GetType() override + { + return mResultType; + } + + virtual void HashInst(BeHashContext& hashCtx) override + { + hashCtx.Mixin(TypeId); + mValue->HashReference(hashCtx); + hashCtx.Mixin(mIFaceTypeId); + hashCtx.Mixin(mVirtualTableIdx); + } +}; + +////////////////////////////////////////////////////////////////////////// + class BeArgument : public BeValue { public: @@ -2007,6 +2119,7 @@ public: int mIdx; void ToString(String& str); + void GetFilePath(String& outStr); virtual void HashContent(BeHashContext& hashCtx) override { @@ -2175,6 +2288,8 @@ public: BeRetInst* CreateRet(BeValue* value); BeCallInst* CreateCall(BeValue* func, const SizedArrayImpl& args); + + BeConstant* GetConstant(BeType* type, double floatVal); BeConstant* GetConstant(BeType* type, int64 intVal); BeConstant* GetConstant(BeType* type, bool boolVal); diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index 5ffa7139..cc4d6def 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/IDEHelper/Compiler/BfCompiler.cpp @@ -406,6 +406,7 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly) mGenericIRefEnumeratorTypeDef = NULL; mInlineAttributeTypeDef = NULL; mInternalTypeDef = NULL; + mDiagnosticsDebugTypeDef = NULL; mIDisposableTypeDef = NULL; mIPrintableTypeDef = NULL; mIHashableTypeDef = NULL; @@ -452,11 +453,12 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly) BfCompiler::~BfCompiler() { + delete mCEMachine; + mCEMachine = NULL; delete mContext; delete mHotData; delete mHotState; - delete mHotResolveData; - delete mCEMachine; + delete mHotResolveData; } bool BfCompiler::IsTypeAccessible(BfType* checkType, BfProject* curProject) @@ -6580,6 +6582,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory) mGenericIRefEnumeratorTypeDef = _GetRequiredType("System.Collections.IRefEnumerator", 1); mInlineAttributeTypeDef = _GetRequiredType("System.InlineAttribute"); mInternalTypeDef = _GetRequiredType("System.Internal"); + mDiagnosticsDebugTypeDef = _GetRequiredType("System.Diagnostics.Debug"); mIDisposableTypeDef = _GetRequiredType("System.IDisposable"); mIPrintableTypeDef = _GetRequiredType("System.IPrintable"); mIHashableTypeDef = _GetRequiredType("System.IHashable"); diff --git a/IDEHelper/Compiler/BfCompiler.h b/IDEHelper/Compiler/BfCompiler.h index 0a9228fc..24bd2211 100644 --- a/IDEHelper/Compiler/BfCompiler.h +++ b/IDEHelper/Compiler/BfCompiler.h @@ -356,6 +356,7 @@ public: BfTypeDef* mGenericIRefEnumeratorTypeDef; BfTypeDef* mInternalTypeDef; + BfTypeDef* mDiagnosticsDebugTypeDef; BfTypeDef* mIDisposableTypeDef; BfTypeDef* mIPrintableTypeDef; BfTypeDef* mIHashableTypeDef; diff --git a/IDEHelper/Compiler/BfContext.cpp b/IDEHelper/Compiler/BfContext.cpp index 9b08023b..9c4f7454 100644 --- a/IDEHelper/Compiler/BfContext.cpp +++ b/IDEHelper/Compiler/BfContext.cpp @@ -2756,12 +2756,17 @@ void BfContext::Cleanup() // Can't clean up LLVM types, they are allocated with a bump allocator RemoveInvalidFailTypes(); + // Clean up deleted BfTypes + // These need to get deleted before the modules because we access mModule in the MethodInstance dtors + for (auto type : mTypeGraveyard) + { + BF_ASSERT(type->mRebuildFlags & BfTypeRebuildFlag_Deleted); + delete type; + } + mTypeGraveyard.Clear(); + for (auto module : mDeletingModules) { -// auto itr = std::find(mFinishedModuleWorkList.begin(), mFinishedModuleWorkList.end(), module); -// if (itr != mFinishedModuleWorkList.end()) -// mFinishedModuleWorkList.erase(itr); - int idx = (int)mFinishedModuleWorkList.IndexOf(module); if (idx != -1) mFinishedModuleWorkList.RemoveAt(idx); @@ -2773,14 +2778,7 @@ void BfContext::Cleanup() delete module; } mDeletingModules.Clear(); - - // Clean up deleted BfTypes - for (auto type : mTypeGraveyard) - { - BF_ASSERT(type->mRebuildFlags & BfTypeRebuildFlag_Deleted); - delete type; - } - mTypeGraveyard.Clear(); + for (auto typeDef : mTypeDefGraveyard) delete typeDef; mTypeDefGraveyard.Clear(); diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index f36ab0b4..21bcd855 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -5025,18 +5025,29 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance* if (methodInstance->mMethodInstanceGroup->mOwner->IsInterface()) { - // IFace dispatch - auto ifaceTypeInst = methodInstance->mMethodInstanceGroup->mOwner; - BfIRValue slotOfs = mModule->GetInterfaceSlotNum(methodInstance->mMethodInstanceGroup->mOwner); + if (mModule->mIsConstModule) + { + funcCallInst = mModule->mBfIRBuilder->ConstEval_GetInterfaceFunc(irArgs[0], methodInstance->mMethodInstanceGroup->mOwner->mTypeId, methodInstance->mVirtualTableIdx, funcPtrType1); + } + else + { + // IFace dispatch + auto ifaceTypeInst = methodInstance->mMethodInstanceGroup->mOwner; + BfIRValue slotOfs = mModule->GetInterfaceSlotNum(methodInstance->mMethodInstanceGroup->mOwner); - auto vDataPtrPtr = mModule->mBfIRBuilder->CreateBitCast(irArgs[0], funcPtrType4); - auto vDataPtr = mModule->FixClassVData(mModule->mBfIRBuilder->CreateLoad(vDataPtrPtr/*, "vtable"*/)); + auto vDataPtrPtr = mModule->mBfIRBuilder->CreateBitCast(irArgs[0], funcPtrType4); + auto vDataPtr = mModule->FixClassVData(mModule->mBfIRBuilder->CreateLoad(vDataPtrPtr/*, "vtable"*/)); - auto ifacePtrPtr = mModule->mBfIRBuilder->CreateInBoundsGEP(vDataPtr, slotOfs/*, "iface"*/); - auto ifacePtr = mModule->mBfIRBuilder->CreateLoad(ifacePtrPtr); + auto ifacePtrPtr = mModule->mBfIRBuilder->CreateInBoundsGEP(vDataPtr, slotOfs/*, "iface"*/); + auto ifacePtr = mModule->mBfIRBuilder->CreateLoad(ifacePtrPtr); - auto funcPtr = mModule->mBfIRBuilder->CreateInBoundsGEP(ifacePtr, methodInstance->mVirtualTableIdx/*, "vfn"*/); - funcCallInst = mModule->mBfIRBuilder->CreateLoad(funcPtr); + auto funcPtr = mModule->mBfIRBuilder->CreateInBoundsGEP(ifacePtr, methodInstance->mVirtualTableIdx/*, "vfn"*/); + funcCallInst = mModule->mBfIRBuilder->CreateLoad(funcPtr); + } + } + else if (mModule->mIsConstModule) + { + funcCallInst = mModule->mBfIRBuilder->ConstEval_GetVirtualFunc(irArgs[0], methodInstance->mVirtualTableIdx, funcPtrType1); } else { @@ -6435,7 +6446,7 @@ SplatArgs(lookupVal, irArgs); if (!argValue) { - if ((argValues[argExprIdx].mArgFlags & BfArgFlag_StringInterpolateArg) != 0) + if ((argExprIdx < (int)argValues.size()) && ((argValues[argExprIdx].mArgFlags & BfArgFlag_StringInterpolateArg) != 0)) { BfAstNode* errorRef = NULL; int checkIdx = argExprIdx - 1; @@ -12761,7 +12772,8 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs } // Actually leave it alone? - if ((isUninit) && (mModule->IsOptimized())) + if ((isUninit) && + ((mModule->IsOptimized()) || (mModule->mIsConstModule) || (mModule->mBfIRBuilder->mIgnoreWrites))) return; bool doClear = true; @@ -18223,7 +18235,8 @@ void BfExprEvaluator::Visit(BfIndexerExpression* indexerExpr) } } } - else if ((mModule->HasCompiledOutput()) && (wantsChecks)) + else if (((mModule->HasCompiledOutput()) || (mModule->mIsConstModule)) && + (wantsChecks)) { if (checkedKind == BfCheckedKind_NotSet) checkedKind = mModule->GetDefaultCheckedKind(); @@ -18254,6 +18267,9 @@ void BfExprEvaluator::Visit(BfIndexerExpression* indexerExpr) OutputDebugStrF("-OOB %d %d\n", oobFunc.mFunc.mId, oobFunc.mFunc.mFlags); }*/ + if (mModule->mIsConstModule) + mModule->mCompiler->mCEMachine->QueueMethod(oobFunc.mMethodInstance, oobFunc.mFunc); + SizedArray args; args.push_back(mModule->GetConstValue(0)); mModule->mBfIRBuilder->CreateCall(oobFunc.mFunc, args); diff --git a/IDEHelper/Compiler/BfIRBuilder.cpp b/IDEHelper/Compiler/BfIRBuilder.cpp index 4bb61d26..c575b170 100644 --- a/IDEHelper/Compiler/BfIRBuilder.cpp +++ b/IDEHelper/Compiler/BfIRBuilder.cpp @@ -3117,6 +3117,7 @@ void BfIRBuilder::CreateTypeDefinition(BfType* type, bool forceDbgDefine) auto& fieldInst = boxedType->mFieldInstances.back(); auto elementType = fieldInst.mResolvedType; + populateModule->PopulateType(elementType, BfPopulateType_Data); if (!elementType->IsValuelessType()) { @@ -3872,8 +3873,20 @@ BfIRValue BfIRBuilder::CreateMul(BfIRValue lhs, BfIRValue rhs) BfIRValue BfIRBuilder::CreateDiv(BfIRValue lhs, BfIRValue rhs, bool isSigned) { if ((lhs.IsConst()) && (rhs.IsConst())) - { - BINOP_APPLY(lhs, rhs, /); + { + auto constLHS = GetConstantById(lhs.mId); + auto constRHS = GetConstantById(rhs.mId); + + if ((constLHS->mTypeCode == BfTypeCode_Float) || (constLHS->mTypeCode == BfTypeCode_Double)) + { + double fVal = constLHS->mDouble / constRHS->mDouble; + return CreateConst(constLHS->mTypeCode, fVal); + } + + if (constRHS->mInt64 != 0) + { + INT_BINOP_APPLY(constLHS, constRHS, /); + } } auto retVal = WriteCmd(isSigned ? BfIRCmd_SDiv : BfIRCmd_UDiv, lhs, rhs); @@ -3887,10 +3900,17 @@ BfIRValue BfIRBuilder::CreateRem(BfIRValue lhs, BfIRValue rhs, bool isSigned) { auto constLHS = GetConstantById(lhs.mId); auto constRHS = GetConstantById(rhs.mId); - INT_BINOP_APPLY(constLHS, constRHS, %); - double fVal = fmod(constLHS->mDouble, constRHS->mDouble); - return CreateConst(constLHS->mTypeCode, fVal); + if ((constLHS->mTypeCode == BfTypeCode_Float) || (constLHS->mTypeCode == BfTypeCode_Double)) + { + double fVal = fmod(constLHS->mDouble, constRHS->mDouble); + return CreateConst(constLHS->mTypeCode, fVal); + } + + if (constRHS->mInt64 != 0) + { + INT_BINOP_APPLY(constLHS, constRHS, %); + } } auto retVal = WriteCmd(isSigned ? BfIRCmd_SRem : BfIRCmd_URem, lhs, rhs); @@ -4779,6 +4799,34 @@ void BfIRBuilder::Func_SetLinkage(BfIRFunction func, BfIRLinkageType linkage) NEW_CMD_INSERTED; } +BfIRValue BfIRBuilder::ConstEval_GetBfType(int typeId, BfIRType resultType) +{ + BfIRValue retVal = WriteCmd(BfIRCmd_ConstEval_GetBfType, typeId, resultType); + NEW_CMD_INSERTED; + return retVal; +} + +BfIRValue BfIRBuilder::ConstEval_DynamicCastCheck(BfIRValue value, int typeId, BfIRType resultType) +{ + BfIRValue retVal = WriteCmd(BfIRCmd_ConstEval_DynamicCastCheck, value, typeId, resultType); + NEW_CMD_INSERTED; + return retVal; +} + +BfIRValue BfIRBuilder::ConstEval_GetVirtualFunc(BfIRValue value, int virtualTableId, BfIRType resultType) +{ + BfIRValue retVal = WriteCmd(BfIRCmd_ConstEval_GetVirtualFunc, value, virtualTableId, resultType); + NEW_CMD_INSERTED; + return retVal; +} + +BfIRValue BfIRBuilder::ConstEval_GetInterfaceFunc(BfIRValue value, int typeId, int virtualTableId, BfIRType resultType) +{ + BfIRValue retVal = WriteCmd(BfIRCmd_ConstEval_GetInterfaceFunc, value, typeId, virtualTableId, resultType); + NEW_CMD_INSERTED; + return retVal; +} + void BfIRBuilder::SaveDebugLocation() { if (!mIgnoreWrites) diff --git a/IDEHelper/Compiler/BfIRBuilder.h b/IDEHelper/Compiler/BfIRBuilder.h index 4482e838..93d6b732 100644 --- a/IDEHelper/Compiler/BfIRBuilder.h +++ b/IDEHelper/Compiler/BfIRBuilder.h @@ -281,6 +281,11 @@ enum BfIRCmd : uint8 BfIRCmd_Func_SafeRename, BfIRCmd_Func_SetLinkage, + BfIRCmd_ConstEval_GetBfType, + BfIRCmd_ConstEval_DynamicCastCheck, + BfIRCmd_ConstEval_GetVirtualFunc, + BfIRCmd_ConstEval_GetInterfaceFunc, + BfIRCmd_SaveDebugLocation, BfIRCmd_RestoreDebugLocation, BfIRCmd_DupDebugLocation, @@ -1224,6 +1229,11 @@ public: void Func_SafeRename(BfIRFunction func); void Func_SetLinkage(BfIRFunction func, BfIRLinkageType linkage); + BfIRValue ConstEval_GetBfType(int typeId, BfIRType resultType); + BfIRValue ConstEval_DynamicCastCheck(BfIRValue value, int typeId, BfIRType resultType); + BfIRValue ConstEval_GetVirtualFunc(BfIRValue value, int virtualTableId, BfIRType resultType); + BfIRValue ConstEval_GetInterfaceFunc(BfIRValue value, int typeId, int virtualTableId, BfIRType resultType); + void SaveDebugLocation(); void RestoreDebugLocation(); void DupDebugLocation(); diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index f7917903..048c58a0 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -24,6 +24,7 @@ #include "BfIRCodeGen.h" #include "BfDefBuilder.h" #include "BfDeferEvalChecker.h" +#include "CeMachine.h" #include #include @@ -1532,7 +1533,7 @@ BfIRValue BfModule::CreateStringObjectValue(const StringImpl& str, int stringId, auto lenByteCount = stringTypeInst->mFieldInstances[0].mResolvedType->mSize; typeValueParams.clear(); - typeValueParams.push_back(objData); + typeValueParams.push_back(objData); if (lenByteCount == 4) { typeValueParams.push_back(GetConstValue32((int)str.length())); // mLength @@ -1928,8 +1929,7 @@ void BfModule::AddStackAlloc(BfTypedValue val, BfIRValue arraySize, BfAstNode* r //TODO: In the future we could be smarter about statically determining that our value hasn't escaped and eliding this if (mayEscape) { - - if ((!IsOptimized()) && (!val.mType->IsValuelessType()) && (!mBfIRBuilder->mIgnoreWrites) && (!mCompiler->mIsResolveOnly)) + if ((!IsOptimized()) && (!mIsConstModule) && (!val.mType->IsValuelessType()) && (!mBfIRBuilder->mIgnoreWrites) && (!mCompiler->mIsResolveOnly)) { auto nullPtrType = GetPrimitiveType(BfTypeCode_NullPtr); bool isDyn = mCurMethodState->mCurScope->IsDyn(scopeData); @@ -1945,7 +1945,10 @@ void BfModule::AddStackAlloc(BfTypedValue val, BfIRValue arraySize, BfAstNode* r else { SizedArray llvmArgs; - llvmArgs.push_back(mBfIRBuilder->CreateBitCast(val.mValue, mBfIRBuilder->MapType(nullPtrType))); + if (IsTargetingBeefBackend()) + llvmArgs.push_back(mBfIRBuilder->CreateBitCast(val.mValue, mBfIRBuilder->MapType(nullPtrType))); + else + llvmArgs.push_back(val.mValue); llvmArgs.push_back(GetConstValue(val.mType->mSize)); llvmArgs.push_back(GetConstValue32(val.mType->mAlign)); if (arraySize) @@ -2029,7 +2032,7 @@ bool BfModule::TryLocalVariableInit(BfLocalVariable* localVar) if (!fieldDef->mDeclaringType->IsExtension()) return false; - if ((fieldInstance.mDataIdx != -1) && (!mBfIRBuilder->mIgnoreWrites) && (!mCompiler->mIsResolveOnly)) + if ((fieldInstance.mDataIdx != -1) && (!mBfIRBuilder->mIgnoreWrites) && (!mCompiler->mIsResolveOnly) && (!mIsConstModule)) { auto curInsertBlock = mBfIRBuilder->GetInsertBlock(); @@ -2724,6 +2727,12 @@ BfError* BfModule::Fail(const StringImpl& error, BfAstNode* refNode, bool isPers //BF_ASSERT(refNode != NULL); + if (mIsConstModule) + { + mHadBuildError = true; + return NULL; + } + if (mCurMethodInstance != NULL) mCurMethodInstance->mHasFailed = true; @@ -4706,6 +4715,8 @@ BfIRValue BfModule::CreateClassVDataGlobal(BfTypeInstance* typeInstance, int* ou BfIRValue BfModule::GetClassVDataPtr(BfTypeInstance* typeInstance) { auto classVDataType = ResolveTypeDef(mCompiler->mClassVDataTypeDef); + if (mIsConstModule) + return mBfIRBuilder->ConstEval_GetBfType(typeInstance->mTypeId, mBfIRBuilder->MapType(CreatePointerType(classVDataType))); return mBfIRBuilder->CreateBitCast(CreateClassVDataGlobal(typeInstance), mBfIRBuilder->MapType(CreatePointerType(classVDataType))); } @@ -6728,7 +6739,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin BfIRValue BfModule::FixClassVData(BfIRValue value) { - if (!mCompiler->mOptions.mObjectHasDebugFlags) + if ((!mCompiler->mOptions.mObjectHasDebugFlags) || (mIsConstModule)) return value; auto intptrValue = mBfIRBuilder->CreatePtrToInt(value, BfTypeCode_IntPtr); auto maskedValue = mBfIRBuilder->CreateAnd(intptrValue, mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, (uint64)~0xFFULL)); @@ -8025,7 +8036,7 @@ void BfModule::InitTypeInst(BfTypedValue typedValue, BfScopeData* scopeData, boo auto destAddr = mBfIRBuilder->CreateBitCast(vObjectAddr, mBfIRBuilder->MapType(ptrPtrType)); if (!isAutocomplete) { - if (mCompiler->mOptions.mObjectHasDebugFlags) + if ((mCompiler->mOptions.mObjectHasDebugFlags) && (!mIsConstModule)) { auto objectPtr = mBfIRBuilder->CreateBitCast(destAddr, mBfIRBuilder->MapType(mContext->mBfObjectType)); @@ -8414,8 +8425,7 @@ BfIRValue BfModule::AllocFromType(BfType* type, const BfAllocTarget& allocTarget BfIRValue allocaInst; BfIRValue result; if ((typeInstance == NULL) || (typeInstance->mIsCRepr)) - { - sizeValue = mBfIRBuilder->CreateMul(GetConstValue(typeSize), arraySize); + { allocaInst = mBfIRBuilder->CreateAlloca(mBfIRBuilder->MapType(type), arraySize); result = allocaInst; } @@ -8450,28 +8460,32 @@ BfIRValue BfModule::AllocFromType(BfType* type, const BfAllocTarget& allocTarget bool isConstSize = arraySize.IsConst(); BfIRBlock clearBlock; BfIRBlock contBlock; + + bool wantsDeinit = ((!IsOptimized()) && (!mIsConstModule) && (!mBfIRBuilder->mIgnoreWrites) && (!mCompiler->mIsResolveOnly)); - if (!isConstSize) + if (wantsDeinit) { - clearBlock = mBfIRBuilder->CreateBlock("clear"); - contBlock = mBfIRBuilder->CreateBlock("clearCont"); - mBfIRBuilder->CreateCondBr(mBfIRBuilder->CreateCmpNE(arraySize, mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, 0)), clearBlock, contBlock); + if (!isConstSize) + { + clearBlock = mBfIRBuilder->CreateBlock("clear"); + contBlock = mBfIRBuilder->CreateBlock("clearCont"); + mBfIRBuilder->CreateCondBr(mBfIRBuilder->CreateCmpNE(arraySize, mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, 0)), clearBlock, contBlock); - mBfIRBuilder->AddBlock(clearBlock); - mBfIRBuilder->SetInsertPoint(clearBlock); + mBfIRBuilder->AddBlock(clearBlock); + mBfIRBuilder->SetInsertPoint(clearBlock); + } + + AddStackAlloc(typedVal, arraySize, NULL, scopeData, false, true); + + if (!isConstSize) + { + mBfIRBuilder->CreateBr(contBlock); + + mBfIRBuilder->AddBlock(contBlock); + mBfIRBuilder->SetInsertPoint(contBlock); + } } - - AddStackAlloc(typedVal, arraySize, NULL, scopeData, false, true); - - if (!isConstSize) - { - mBfIRBuilder->CreateBr(contBlock); - - mBfIRBuilder->AddBlock(contBlock); - mBfIRBuilder->SetInsertPoint(contBlock); - } - } - //InitTypeInst(typedVal, scopeData, zeroMemory, sizeValue); + } return result; } @@ -8707,6 +8721,8 @@ BfIRValue BfModule::AllocFromType(BfType* type, const BfAllocTarget& allocTarget auto typeOptions = mSystem->GetTypeOptions(typeInstance->mTypeOptionsIdx); stackCount = BfTypeOptions::Apply(stackCount, typeOptions->mAllocStackTraceDepth); } + if (mIsConstModule) + stackCount = 0; if (!sizeValue) sizeValue = GetConstValue(typeInstance->mInstSize); @@ -8777,7 +8793,7 @@ BfIRValue BfModule::AllocFromType(BfType* type, const BfAllocTarget& allocTarget { if (hasCustomAllocator) result = AllocBytes(allocTarget.mRefNode, allocTarget, typeInstance, sizeValue, GetConstValue(typeInstance->mInstAlign), (BfAllocFlags)(BfAllocFlags_ZeroMemory | BfAllocFlags_NoDefaultToMalloc)); - else if ((mCompiler->mOptions.mObjectHasDebugFlags) && (!mCompiler->mOptions.mDebugAlloc)) + else if ((mCompiler->mOptions.mObjectHasDebugFlags) && (!mCompiler->mOptions.mDebugAlloc) && (!mIsConstModule)) { SizedArray llvmArgs; llvmArgs.push_back(sizeValue); @@ -8790,7 +8806,7 @@ BfIRValue BfModule::AllocFromType(BfType* type, const BfAllocTarget& allocTarget if (result) { - if (mCompiler->mOptions.mObjectHasDebugFlags) + if ((mCompiler->mOptions.mObjectHasDebugFlags) && (!mIsConstModule)) { auto objectPtr = mBfIRBuilder->CreateBitCast(result, mBfIRBuilder->MapTypeInstPtr(mContext->mBfObjectType)); SizedArray llvmArgs; @@ -8828,7 +8844,7 @@ BfIRValue BfModule::AllocFromType(BfType* type, const BfAllocTarget& allocTarget auto classVDataType = ResolveTypeDef(mCompiler->mClassVDataTypeDef); auto vData = mBfIRBuilder->CreateBitCast(vDataRef, mBfIRBuilder->MapTypeInstPtr(classVDataType->ToTypeInstance())); - if (mCompiler->mOptions.mObjectHasDebugFlags) + if ((mCompiler->mOptions.mObjectHasDebugFlags) && (!mIsConstModule)) { SizedArray llvmArgs; llvmArgs.push_back(vData); @@ -8844,7 +8860,7 @@ BfIRValue BfModule::AllocFromType(BfType* type, const BfAllocTarget& allocTarget SizedArray llvmArgs; llvmArgs.push_back(sizeValue); BfIRFunction irFunc; - if (mCompiler->mOptions.mDebugAlloc) + if ((mCompiler->mOptions.mDebugAlloc) && (!mIsConstModule)) { auto moduleMethodInstance = GetInternalMethod("Dbg_RawObjectAlloc", 1); irFunc = moduleMethodInstance.mFunc; @@ -9062,7 +9078,7 @@ BfIRValue BfModule::AppendAllocFromType(BfType* type, BfIRValue appendSizeValue, auto curThis = GetThis(); BfIRValue newFlags; - if (mCompiler->mOptions.mObjectHasDebugFlags) + if ((mCompiler->mOptions.mObjectHasDebugFlags) && (!mIsConstModule)) { auto thisFlagsPtr = mBfIRBuilder->CreateBitCast(curThis.mValue, ptrType); auto thisFlags = mBfIRBuilder->CreateLoad(thisFlagsPtr); @@ -9078,7 +9094,7 @@ BfIRValue BfModule::AppendAllocFromType(BfType* type, BfIRValue appendSizeValue, auto srcVal = mBfIRBuilder->CreateBitCast(vDataRef, ptrType); mBfIRBuilder->CreateStore(srcVal, destAddr); - if (mCompiler->mOptions.mObjectHasDebugFlags) + if ((mCompiler->mOptions.mObjectHasDebugFlags) && (!mIsConstModule)) { auto flagsPtr = mBfIRBuilder->CreateBitCast(destAddr, ptrType); mBfIRBuilder->CreateStore(newFlags, flagsPtr); @@ -9129,7 +9145,7 @@ void BfModule::SkipObjectAccessCheck(BfTypedValue typedVal) if ((mBfIRBuilder->mIgnoreWrites) || (!typedVal.mType->IsObjectOrInterface()) || (mCurMethodState == NULL) || (mCurMethodState->mIgnoreObjectAccessCheck)) return; - if (!mCompiler->mOptions.mObjectHasDebugFlags) + if ((!mCompiler->mOptions.mObjectHasDebugFlags) || (mIsConstModule)) return; if ((typedVal.mValue.mFlags & BfIRValueFlags_Value) == 0) @@ -9143,7 +9159,7 @@ void BfModule::EmitObjectAccessCheck(BfTypedValue typedVal) if ((mBfIRBuilder->mIgnoreWrites) || (!typedVal.mType->IsObjectOrInterface()) || (mCurMethodState == NULL) || (mCurMethodState->mIgnoreObjectAccessCheck)) return; - if (!mCompiler->mOptions.mObjectHasDebugFlags) + if ((!mCompiler->mOptions.mObjectHasDebugFlags) || (mIsConstModule)) return; if (typedVal.mValue.IsConst()) @@ -9187,8 +9203,17 @@ void BfModule::EmitDynamicCastCheck(const BfTypedValue& targetValue, BfType* tar { if (mBfIRBuilder->mIgnoreWrites) return; // Nothing needed here - + auto irb = mBfIRBuilder; + + if (mIsConstModule) + { + auto callResult = mBfIRBuilder->ConstEval_DynamicCastCheck(targetValue.mValue, targetType->mTypeId, mBfIRBuilder->MapType(mContext->mBfObjectType)); + auto cmpResult = mBfIRBuilder->CreateCmpNE(callResult, GetDefaultValue(mContext->mBfObjectType)); + irb->CreateCondBr(cmpResult, trueBlock, falseBlock); + return; + } + auto checkBB = irb->CreateBlock("as.check"); auto isNull = irb->CreateIsNull(targetValue.mValue); mBfIRBuilder->CreateCondBr(isNull, nullSucceeds ? trueBlock : falseBlock, checkBB); @@ -9212,7 +9237,6 @@ void BfModule::EmitDynamicCastCheck(const BfTypedValue& targetValue, BfType* tar irArgs.push_back(objectParam); irArgs.push_back(GetConstValue32(targetType->mTypeId)); auto callResult = exprEvaluator.CreateCall(NULL, moduleMethodInstance.mMethodInstance, moduleMethodInstance.mFunc, false, irArgs); - auto resultType = ResolveTypeDef(mSystem->mTypeBool); auto cmpResult = mBfIRBuilder->CreateCmpNE(callResult.mValue, GetDefaultValue(callResult.mType)); irb->CreateCondBr(cmpResult, trueBlock, falseBlock); } @@ -9221,7 +9245,7 @@ void BfModule::EmitDynamicCastCheck(const BfTypedValue& targetValue, BfType* tar AddBasicBlock(checkBB); BfIRValue vDataPtr = irb->CreateBitCast(targetValue.mValue, irb->MapType(intPtrType)); vDataPtr = irb->CreateLoad(vDataPtr); - if (mCompiler->mOptions.mObjectHasDebugFlags) + if ((mCompiler->mOptions.mObjectHasDebugFlags) && (!mIsConstModule)) vDataPtr = irb->CreateAnd(vDataPtr, irb->CreateConst(BfTypeCode_IntPtr, (uint64)~0xFFULL)); if (targetType->IsInterface()) @@ -13531,13 +13555,13 @@ BfLocalVariable* BfModule::AddLocalVariableDef(BfLocalVariable* localVarDef, boo BF_ASSERT(rootMethodState->mCurLocalVarId >= 0); localVarDef->mLocalVarId = rootMethodState->mCurLocalVarId++; } - if ((localVarDef->mNameNode != NULL) && (mCompiler->mResolvePassData != NULL) && (mCompiler->mResolvePassData->mAutoComplete != NULL)) + if ((localVarDef->mNameNode != NULL) && (mCompiler->mResolvePassData != NULL) && (mCompiler->mResolvePassData->mAutoComplete != NULL) && (!mIsConstModule)) mCompiler->mResolvePassData->mAutoComplete->CheckLocalDef(localVarDef->mNameNode, localVarDef); if ((localVarDef->mNameNode != NULL) && (mCurMethodInstance != NULL)) { bool isClosureProcessing = (mCurMethodState->mClosureState != NULL) && (!mCurMethodState->mClosureState->mCapturing); - if ((!isClosureProcessing) && (mCompiler->mResolvePassData != NULL) && (localVarDef->mNameNode != NULL)) + if ((!isClosureProcessing) && (mCompiler->mResolvePassData != NULL) && (localVarDef->mNameNode != NULL) && (!mIsConstModule)) mCompiler->mResolvePassData->HandleLocalReference(localVarDef->mNameNode, rootMethodState->mMethodInstance->GetOwner()->mTypeDef, rootMethodState->mMethodInstance->mMethodDef, localVarDef->mLocalVarId); } @@ -14513,7 +14537,7 @@ BfTypedValue BfModule::TryConstCalcAppend(BfMethodInstance* methodInst, SizedArr { BP_ZONE("BfModule::TryConstCalcAppend"); - if (mCompiler->mIsResolveOnly) + if ((mCompiler->mIsResolveOnly) && (!mIsConstModule)) return BfTypedValue(); // We want to regenerate all ctor calls when the method internals change @@ -14798,7 +14822,7 @@ BfTypedValue BfModule::CallBaseCtorCalc(bool constOnly) // This method never throws errors - it relies on the proper ctor actually throwing the errors void BfModule::EmitCtorCalcAppend() { - if (mCompiler->mIsResolveOnly) + if ((mCompiler->mIsResolveOnly) && (!mIsConstModule)) return; auto methodDef = mCurMethodInstance->mMethodDef; @@ -14939,6 +14963,8 @@ void BfModule::EmitDtorBody() // Fall through to Object::~this call auto dtorFunc = GetMethodByName(mContext->mBfObjectType, "~this"); + if (mIsConstModule) + mCompiler->mCEMachine->QueueMethod(dtorFunc.mMethodInstance, dtorFunc.mFunc); auto basePtr = mBfIRBuilder->CreateBitCast(thisVal.mValue, mBfIRBuilder->MapTypeInstPtr(mContext->mBfObjectType)); SizedArray vals = { basePtr }; result = mBfIRBuilder->CreateCall(dtorFunc.mFunc, vals); @@ -15115,6 +15141,8 @@ void BfModule::EmitDtorBody() auto basePtr = mBfIRBuilder->CreateBitCast(mCurMethodState->mLocals[0]->mValue, mBfIRBuilder->MapTypeInstPtr(checkBaseType)); SizedArray vals = { basePtr }; auto callInst = mBfIRBuilder->CreateCall(dtorMethodInstance.mFunc, vals); + if (mIsConstModule) + mCompiler->mCEMachine->QueueMethod(dtorMethodInstance.mMethodInstance, dtorMethodInstance.mFunc); mBfIRBuilder->SetCallCallingConv(callInst, GetIRCallingConvention(dtorMethodInstance.mMethodInstance)); } } @@ -15649,6 +15677,8 @@ void BfModule::EmitCtorBody(bool& skipBody) SizedArray irArgs; exprEvaluator.PushThis(NULL, GetThis(), moduleMethodInstance.mMethodInstance, irArgs); exprEvaluator.CreateCall(NULL, moduleMethodInstance.mMethodInstance, moduleMethodInstance.mFunc, false, irArgs); + if (mIsConstModule) + mCompiler->mCEMachine->QueueMethod(moduleMethodInstance); calledCtorNoBody = true; } @@ -15984,6 +16014,8 @@ void BfModule::EmitCtorBody(bool& skipBody) auto callingConv = GetIRCallingConvention(ctorBodyMethodInstance.mMethodInstance); if (callingConv != BfIRCallingConv_CDecl) mBfIRBuilder->SetCallCallingConv(callInst, callingConv); + if (mIsConstModule) + mCompiler->mCEMachine->QueueMethod(ctorBodyMethodInstance); } if (matchedMethod == NULL) @@ -20384,7 +20416,8 @@ void BfModule::SetupIRFunction(BfMethodInstance* methodInstance, StringImpl& man // We can have a collision of names when we have generic methods that differ only in // their constraints, but they should only collide in their unspecialized form // since only one will be chosen for a given concrete type - mCurMethodInstance->mMangleWithIdx = true; + if (!mIsConstModule) + mCurMethodInstance->mMangleWithIdx = true; mangledName.Clear(); BfMangler::Mangle(mangledName, mCompiler->GetMangleKind(), mCurMethodInstance); prevFunc = mBfIRBuilder->GetFunction(mangledName); diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index 892f74e6..330b2700 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -535,6 +535,13 @@ BfMethodInfoEx::~BfMethodInfoEx() BfMethodInstance::~BfMethodInstance() { + if (mInCEMachine) + { + auto module = GetOwner()->mModule; + if (module->mCompiler->mCEMachine != NULL) + module->mCompiler->mCEMachine->RemoveMethod(this); + } + if (mHasMethodRefType) { auto module = GetOwner()->mModule; @@ -557,13 +564,7 @@ BfMethodInstance::~BfMethodInstance() mHotMethod->Deref(); } - delete mMethodInfoEx; - - if (mInCEMachine) - { - auto module = GetOwner()->mModule; - module->mCompiler->mCEMachine->RemoveMethod(this); - } + delete mMethodInfoEx; } BfImportKind BfMethodInstance::GetImportKind() diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index 30e16b11..005e28cb 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -55,7 +55,8 @@ enum BfMethodNameFlags : uint8 BfMethodNameFlag_None = 0, BfMethodNameFlag_ResolveGenericParamNames = 1, BfMethodNameFlag_OmitTypeName = 2, - BfMethodNameFlag_IncludeReturnType = 4 + BfMethodNameFlag_IncludeReturnType = 4, + BfMethodNameFlag_OmitParams = 8 }; enum BfGetMethodInstanceFlags : uint16 @@ -1416,7 +1417,7 @@ public: mMethodRefFlags = BfMethodRefFlag_None; } - BfMethodRef(BfMethodInstance* methodInstance); + BfMethodRef(BfMethodInstance* methodInstance); operator BfMethodInstance*() const; bool IsNull() { return mTypeInstance == NULL; }; diff --git a/IDEHelper/Compiler/BfStmtEvaluator.cpp b/IDEHelper/Compiler/BfStmtEvaluator.cpp index 13f71f53..29960fe8 100644 --- a/IDEHelper/Compiler/BfStmtEvaluator.cpp +++ b/IDEHelper/Compiler/BfStmtEvaluator.cpp @@ -42,7 +42,8 @@ USING_NS_BF; bool BfModule::AddDeferredCallEntry(BfDeferredCallEntry* deferredCallEntry, BfScopeData* scopeData) { - if (((mCompiler->mIsResolveOnly) || (mBfIRBuilder->mIgnoreWrites)) && (deferredCallEntry->mDeferredBlock == NULL)) + if ((((mCompiler->mIsResolveOnly) && (!mIsConstModule)) || + (mBfIRBuilder->mIgnoreWrites)) && (deferredCallEntry->mDeferredBlock == NULL)) { // For resolve entries, we only keep deferred blocks because we need to process them later so we can // resolve inside of them. This is also required for lambda bind scan-pass @@ -782,7 +783,7 @@ void BfModule::EmitDeferredCall(BfModuleMethodInstance moduleMethodInstance, Siz void BfModule::EmitDeferredCall(BfDeferredCallEntry& deferredCallEntry, bool moveBlocks) { - if ((mCompiler->mIsResolveOnly) && (deferredCallEntry.mHandlerCount > 0)) + if ((mCompiler->mIsResolveOnly) && (!mIsConstModule) && (deferredCallEntry.mHandlerCount > 0)) { // We only want to process deferred blocks once, otherwise it could significantly slow down autocompletion return; diff --git a/IDEHelper/Compiler/BfSystem.cpp b/IDEHelper/Compiler/BfSystem.cpp index 77bc5af9..5804572b 100644 --- a/IDEHelper/Compiler/BfSystem.cpp +++ b/IDEHelper/Compiler/BfSystem.cpp @@ -928,6 +928,7 @@ bool BfProject::IsTestProject() BfErrorBase::~BfErrorBase() { + delete mLocation; } void BfErrorBase::SetSource(BfPassInstance* passInstance, BfSourceData* source) @@ -1598,9 +1599,8 @@ BfError* BfPassInstance::WarnAfter(int warningNumber, const StringImpl& warning, return WarnAt(warningNumber, warning, refNode->GetSourceData(), refNode->GetSrcEnd()); } -BfError* BfPassInstance::MoreInfoAt(const StringImpl& info, BfSourceData* bfSource, int srcIdx, int srcLen, BfFailFlags flags) -{ - String msgPrefix; +BfMoreInfo* BfPassInstance::MoreInfoAt(const StringImpl& info, BfSourceData* bfSource, int srcIdx, int srcLen, BfFailFlags flags) +{ if (!mLastWasDisplayed) { if (mLastWasAdded) @@ -1612,25 +1612,20 @@ BfError* BfPassInstance::MoreInfoAt(const StringImpl& info, BfSourceData* bfSour moreInfo->mSrcStart = srcIdx; moreInfo->mSrcEnd = srcIdx + srcLen; - if (lastError->mIsWarning) - msgPrefix = ":warn"; - else - msgPrefix = ":error"; - lastError->mMoreInfo.push_back(moreInfo); + return moreInfo; } return NULL; } + String msgPrefix; MessageAt(msgPrefix, " > " + info, bfSource, srcIdx, srcLen, flags); return NULL; } -BfError* BfPassInstance::MoreInfo(const StringImpl& info) -{ - String outText; - +BfMoreInfo* BfPassInstance::MoreInfo(const StringImpl& info) +{ if (!mLastWasDisplayed) { if (mLastWasAdded) @@ -1642,23 +1637,21 @@ BfError* BfPassInstance::MoreInfo(const StringImpl& info) moreInfo->mSrcStart = -1; moreInfo->mSrcEnd = -1; - if (lastError->mIsWarning) - outText = ":warn "; - else - outText = ":error "; - lastError->mMoreInfo.push_back(moreInfo); + return moreInfo; } return NULL; } + String outText; + outText += " > "; outText += info; OutputLine(outText); return NULL; } -BfError* BfPassInstance::MoreInfo(const StringImpl& info, BfAstNode* refNode) +BfMoreInfo* BfPassInstance::MoreInfo(const StringImpl& info, BfAstNode* refNode) { if (refNode == NULL) return MoreInfo(info); @@ -1666,7 +1659,7 @@ BfError* BfPassInstance::MoreInfo(const StringImpl& info, BfAstNode* refNode) return MoreInfoAt(info, refNode->GetSourceData(), refNode->GetSrcStart(), refNode->GetSrcLength()); } -BfError* BfPassInstance::MoreInfoAfter(const StringImpl& info, BfAstNode* refNode) +BfMoreInfo* BfPassInstance::MoreInfoAfter(const StringImpl& info, BfAstNode* refNode) { return MoreInfoAt(info, refNode->GetSourceData(), refNode->GetSrcEnd(), 1); } @@ -3486,6 +3479,14 @@ BF_EXPORT const char* BF_CALLTYPE BfPassInstance_GetErrorData(BfPassInstance* bf } } } + + if (bfError->mLocation != NULL) + { + fileName = (char*)bfError->mLocation->mFile.c_str(); + *outLine = bfError->mLocation->mLine; + *outColumn = bfError->mLocation->mColumn; + } + outSrcStart = bfError->mSrcStart; outSrcEnd = bfError->mSrcEnd; outMoreInfoCount = (int)bfError->mMoreInfo.size(); @@ -3504,6 +3505,16 @@ BF_EXPORT const char* BfPassInstance_Error_GetMoreInfoData(BfPassInstance* bfPas fileName = (char*)srcFileName->c_str(); } } + + if (moreInfo->mLocation != NULL) + { + fileName = (char*)moreInfo->mLocation->mFile.c_str(); + if (outLine != NULL) + *outLine = moreInfo->mLocation->mLine; + if (outColumn != NULL) + *outColumn = moreInfo->mLocation->mColumn; + } + srcStart = moreInfo->mSrcStart; srcEnd = moreInfo->mSrcEnd; return moreInfo->mInfo.c_str(); diff --git a/IDEHelper/Compiler/BfSystem.h b/IDEHelper/Compiler/BfSystem.h index 95ed3b3a..1836bc81 100644 --- a/IDEHelper/Compiler/BfSystem.h +++ b/IDEHelper/Compiler/BfSystem.h @@ -1122,6 +1122,14 @@ enum BfWarning BfWarning_C4554_PossiblePrecedenceError = 4554 }; +class BfErrorLocation +{ +public: + String mFile; + int mLine; + int mColumn; +}; + class BfErrorBase { public: @@ -1129,7 +1137,8 @@ public: bool mIsDeferred; BfSourceData* mSource; int mSrcStart; - int mSrcEnd; + int mSrcEnd; + BfErrorLocation* mLocation; public: BfErrorBase() @@ -1139,6 +1148,7 @@ public: mSource = NULL; mSrcStart = -1; mSrcEnd = -1; + mLocation = NULL; } ~BfErrorBase(); @@ -1278,10 +1288,10 @@ public: BfError* Warn(int warningNumber, const StringImpl& warning, BfAstNode* refNode); BfError* WarnAfter(int warningNumber, const StringImpl& warning, BfAstNode* refNode); - BfError* MoreInfoAt(const StringImpl& info, BfSourceData* bfSource, int srcIdx, int srcLen, BfFailFlags flags = BfFailFlag_None); - BfError* MoreInfo(const StringImpl& info); - BfError* MoreInfo(const StringImpl& info, BfAstNode* refNode); - BfError* MoreInfoAfter(const StringImpl& info, BfAstNode* refNode); + BfMoreInfo* MoreInfoAt(const StringImpl& info, BfSourceData* bfSource, int srcIdx, int srcLen, BfFailFlags flags = BfFailFlag_None); + BfMoreInfo* MoreInfo(const StringImpl& info); + BfMoreInfo* MoreInfo(const StringImpl& info, BfAstNode* refNode); + BfMoreInfo* MoreInfoAfter(const StringImpl& info, BfAstNode* refNode); BfError* FailAt(const StringImpl& error, BfSourceData* bfSource, int srcIdx, int srcLen = 1, BfFailFlags flags = BfFailFlag_None); BfError* FailAfterAt(const StringImpl& error, BfSourceData* bfSource, int srcIdx); diff --git a/IDEHelper/Compiler/CeMachine.cpp b/IDEHelper/Compiler/CeMachine.cpp index d52f3e01..a07dad96 100644 --- a/IDEHelper/Compiler/CeMachine.cpp +++ b/IDEHelper/Compiler/CeMachine.cpp @@ -4,8 +4,9 @@ #include "BfIRBuilder.h" #include "../Backend/BeIRCodeGen.h" -USING_NS_BF; +#define CE_ENABLE_HEAP +USING_NS_BF; struct CeOpInfo { @@ -37,12 +38,11 @@ struct CeOpInfo {OPNAME "_64", OPINFOA, OPINFOB, OPINFOC}, \ {OPNAME "_X", OPINFOA, CEOI_IMM32, OPINFOB, OPINFOC} -#define CEOPINFO_SIZED_NUMERIC(OPNAME, OPINFOA, OPINFOB, OPINFOC) \ - {OPNAME "_I8", OPINFOA, OPINFOB, OPINFOC}, \ - {OPNAME "_I16", OPINFOA, OPINFOB, OPINFOC}, \ - {OPNAME "_I32", OPINFOA, OPINFOB, OPINFOC}, \ - {OPNAME "_I64", OPINFOA, OPINFOB, OPINFOC} - +#define CEOPINFO_SIZED_NUMERIC_2(OPNAME, OPINFOA, OPINFOB) \ + {OPNAME "_I8", OPINFOA, OPINFOB}, \ + {OPNAME "_I16", OPINFOA, OPINFOB}, \ + {OPNAME "_I32", OPINFOA, OPINFOB}, \ + {OPNAME "_I64", OPINFOA, OPINFOB} #define CEOPINFO_SIZED_NUMERIC_PLUSF_2(OPNAME, OPINFOA, OPINFOB) \ {OPNAME "_I8", OPINFOA, OPINFOB}, \ {OPNAME "_I16", OPINFOA, OPINFOB}, \ @@ -55,6 +55,11 @@ struct CeOpInfo {OPNAME "_I16", OPINFOA, OPINFOB, OPINFOC}, \ {OPNAME "_I32", OPINFOA, OPINFOB, OPINFOC}, \ {OPNAME "_I64", OPINFOA, OPINFOB, OPINFOC} +#define CEOPINFO_SIZED_UNUMERIC_3(OPNAME, OPINFOA, OPINFOB, OPINFOC) \ + {OPNAME "_U8", OPINFOA, OPINFOB, OPINFOC}, \ + {OPNAME "_U16", OPINFOA, OPINFOB, OPINFOC}, \ + {OPNAME "_U32", OPINFOA, OPINFOB, OPINFOC}, \ + {OPNAME "_U64", OPINFOA, OPINFOB, OPINFOC} #define CEOPINFO_SIZED_NUMERIC_PLUSF_3(OPNAME, OPINFOA, OPINFOB, OPINFOC) \ {OPNAME "_I8", OPINFOA, OPINFOB, OPINFOC}, \ {OPNAME "_I16", OPINFOA, OPINFOB, OPINFOC}, \ @@ -70,9 +75,18 @@ static CeOpInfo gOpInfo[] = {"Jmp", CEOI_None, CEOI_JMPREL}, {"JmpIf", CEOI_None, CEOI_JMPREL, CEOI_FrameRef}, {"JmpIfNot", CEOI_None, CEOI_JMPREL, CEOI_FrameRef}, + {"Error", CEOI_None, CEOI_IMM32}, + {"DynamicCastCheck", CEOI_FrameRef, CEOI_FrameRef, CEOI_IMM32}, + {"GetString", CEOI_FrameRef, CEOI_IMM32}, + {"Malloc", CEOI_FrameRef, CEOI_FrameRef}, + {"Free", CEOI_None, CEOI_FrameRef}, + + {"MemSet", CEOI_None, CEOI_FrameRef, CEOI_FrameRef, CEOI_FrameRef}, + {"MemSet_Const", CEOI_None, CEOI_FrameRef, CEOI_IMM8, CEOI_IMM32}, + {"MemCpy", CEOI_None, CEOI_FrameRef, CEOI_FrameRef, CEOI_FrameRef}, {"FrameAddr_32", CEOI_FrameRef, CEOI_FrameRef}, {"FrameAddr_64", CEOI_FrameRef, CEOI_FrameRef}, - {"Zero", CEOI_FrameRef, CEOI_IMM32}, + {"Zero", CEOI_None, CEOI_FrameRef, CEOI_IMM32}, {"Const_8", CEOI_FrameRef, CEOI_IMM8}, {"Const_16", CEOI_FrameRef, CEOI_IMM16}, @@ -87,10 +101,53 @@ static CeOpInfo gOpInfo[] = CEOPINFO_SIZED_1("Pop", CEOI_FrameRef), {"AdjustSP", CEOI_None, CEOI_FrameRef}, + {"AdjustSPNeg", CEOI_None, CEOI_FrameRef}, + {"AdjustSPConst", CEOI_None, CEOI_IMM32}, + {"CeOp_GetSP", CEOI_FrameRef}, + {"CeOp_SetSP", CEOI_None, CEOI_FrameRef}, {"Call", CEOI_None, CEOI_IMM32}, + {"Call_Virt", CEOI_None, CEOI_FrameRef, CEOI_IMM32}, + {"CeOp_Call_IFace", CEOI_None, CEOI_FrameRef, CEOI_IMM32, CEOI_IMM32}, - {"Conv_I32_I64", CEOI_FrameRef, CEOI_FrameRef}, - + {"CeOp_Conv_I8_I16", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_I8_I32", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_I8_I64", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_I8_F32", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_I8_F64", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_I16_I32", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_I16_I64", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_I16_F32", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_I16_F64", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_I32_I64", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_I32_F32", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_I32_F64", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_I64_F32", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_I64_F64", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_U8_U16", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_U8_U32", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_U8_U64", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_U8_F32", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_U8_F64", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_U16_U32", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_U16_U64", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_U16_F32", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_U16_F64", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_U32_U64", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_U32_F32", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_U32_F64", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_U64_F32", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_U64_F64", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_F32_I8", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_F32_I16", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_F32_I32", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_F32_I64", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_F32_F64", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_F64_I8", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_F64_I16", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_F64_I32", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_F64_I64", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_F64_F32", CEOI_FrameRef, CEOI_FrameRef}, + {"AddConst_I8", CEOI_FrameRef, CEOI_FrameRef, CEOI_IMM8}, {"AddConst_I16", CEOI_FrameRef, CEOI_FrameRef, CEOI_IMM16}, {"AddConst_I32", CEOI_FrameRef, CEOI_FrameRef, CEOI_IMM32}, @@ -105,19 +162,36 @@ static CeOpInfo gOpInfo[] = CEOPINFO_SIZED_NUMERIC_3("UDiv", CEOI_FrameRef, CEOI_FrameRef, CEOI_FrameRef), CEOPINFO_SIZED_NUMERIC_PLUSF_3("SMod", CEOI_FrameRef, CEOI_FrameRef, CEOI_FrameRef), CEOPINFO_SIZED_NUMERIC_3("UMod", CEOI_FrameRef, CEOI_FrameRef, CEOI_FrameRef), + CEOPINFO_SIZED_NUMERIC_3("And", CEOI_FrameRef, CEOI_FrameRef, CEOI_FrameRef), + CEOPINFO_SIZED_NUMERIC_3("Or", CEOI_FrameRef, CEOI_FrameRef, CEOI_FrameRef), + CEOPINFO_SIZED_NUMERIC_3("Xor", CEOI_FrameRef, CEOI_FrameRef, CEOI_FrameRef), + CEOPINFO_SIZED_NUMERIC_3("Shl", CEOI_FrameRef, CEOI_FrameRef, CEOI_FrameRef), + CEOPINFO_SIZED_NUMERIC_3("Shr", CEOI_FrameRef, CEOI_FrameRef, CEOI_FrameRef), + CEOPINFO_SIZED_UNUMERIC_3("Shr", CEOI_FrameRef, CEOI_FrameRef, CEOI_FrameRef), CEOPINFO_SIZED_NUMERIC_PLUSF_3("Cmp_EQ", CEOI_FrameRef, CEOI_FrameRef, CEOI_FrameRef), + CEOPINFO_SIZED_NUMERIC_PLUSF_3("Cmp_NE", CEOI_FrameRef, CEOI_FrameRef, CEOI_FrameRef), CEOPINFO_SIZED_NUMERIC_PLUSF_3("Cmp_SLT", CEOI_FrameRef, CEOI_FrameRef, CEOI_FrameRef), CEOPINFO_SIZED_NUMERIC_3("Cmp_ULT", CEOI_FrameRef, CEOI_FrameRef, CEOI_FrameRef), CEOPINFO_SIZED_NUMERIC_PLUSF_3("Cmp_SLE", CEOI_FrameRef, CEOI_FrameRef, CEOI_FrameRef), CEOPINFO_SIZED_NUMERIC_3("Cmp_ULE", CEOI_FrameRef, CEOI_FrameRef, CEOI_FrameRef), - //{"Cmp_SLT_I32", CEOI_FrameRef, CEOI_FrameRef, CEOI_FrameRef}, - + CEOPINFO_SIZED_NUMERIC_PLUSF_3("Cmp_SGT", CEOI_FrameRef, CEOI_FrameRef, CEOI_FrameRef), + CEOPINFO_SIZED_NUMERIC_3("Cmp_UGT", CEOI_FrameRef, CEOI_FrameRef, CEOI_FrameRef), + CEOPINFO_SIZED_NUMERIC_PLUSF_3("Cmp_SGE", CEOI_FrameRef, CEOI_FrameRef, CEOI_FrameRef), + CEOPINFO_SIZED_NUMERIC_3("Cmp_UGE", CEOI_FrameRef, CEOI_FrameRef, CEOI_FrameRef), CEOPINFO_SIZED_NUMERIC_PLUSF_2("Neg", CEOI_FrameRef, CEOI_FrameRef), + {"Not_I1", CEOI_FrameRef, CEOI_FrameRef}, + CEOPINFO_SIZED_NUMERIC_2("Not", CEOI_FrameRef, CEOI_FrameRef), }; static_assert(BF_ARRAY_COUNT(gOpInfo) == (int)CeOp_COUNT, "gOpName incorrect size"); +////////////////////////////////////////////////////////////////////////// + +CeFunction::~CeFunction() +{ + +} ////////////////////////////////////////////////////////////////////////// @@ -211,9 +285,8 @@ void CeDumpContext::Dump() { int ofs = mPtr - start; - while ((curEmitIdx < mCeFunction->mEmitTable.mSize) && (ofs > mCeFunction->mEmitTable[curEmitIdx].mCodePos)) + while ((curEmitIdx < mCeFunction->mEmitTable.mSize - 1) && (ofs >= mCeFunction->mEmitTable[curEmitIdx + 1].mCodePos)) curEmitIdx++; - if (curEmitIdx < mCeFunction->mEmitTable.mSize) curEmitEntry = &mCeFunction->mEmitTable[curEmitIdx]; @@ -267,7 +340,11 @@ void CeBuilder::Fail(const StringImpl& str) String errStr = StrFormat("Failure during const code generation of %s: %s", mBeFunction->mName.c_str(), str.c_str()); if (mCurDbgLoc != NULL) - errStr += StrFormat(" at line %d:%d in %s", mCurDbgLoc->mLine + 1, mCurDbgLoc->mColumn + 1, mCurDbgLoc->GetDbgFile()->mFileName.c_str()); + { + String filePath; + mCurDbgLoc->GetDbgFile()->GetFilePath(filePath); + errStr += StrFormat(" at line %d:%d in %s", mCurDbgLoc->mLine + 1, mCurDbgLoc->mColumn + 1, filePath.c_str()); + } mCeFunction->mGenError = errStr; } @@ -282,6 +359,11 @@ void CeBuilder::Emit(CeOp val) *(CeOp*)mCeFunction->mCode.GrowUninitialized(sizeof(CeOp)) = val; } +void CeBuilder::EmitSizedOp(CeOp val, int size) +{ + Emit((CeOp)(val + GetSizeClass(size))); +} + void CeBuilder::Emit(int32 val) { *(int32*)mCeFunction->mCode.GrowUninitialized(4) = val; @@ -386,7 +468,7 @@ void CeBuilder::FlushPhi(CeBlock* ceBlock, int targetBlockIdx) void CeBuilder::EmitBinaryOp(CeOp iOp, CeOp fOp, const CeOperand& lhs, const CeOperand& rhs, CeOperand& result) { CeOp op = iOp; - if (lhs.mType->IsIntegral()) + if (lhs.mType->IsIntable()) { if (lhs.mType->mSize == 1) op = iOp; @@ -421,7 +503,7 @@ void CeBuilder::EmitBinaryOp(CeOp iOp, CeOp fOp, const CeOperand& lhs, const CeO void CeBuilder::EmitUnaryOp(CeOp iOp, CeOp fOp, const CeOperand& val, CeOperand& result) { CeOp op = iOp; - if (val.mType->IsIntegral()) + if (val.mType->IsIntable()) { if (val.mType->mSize == 1) op = iOp; @@ -499,33 +581,99 @@ CeOperand CeBuilder::FrameAlloc(BeType* type) return result; } +CeOperand CeBuilder::EmitConst(int64 val, int size) +{ + BeType* type = mIntPtrType; + switch (size) + { + case 1: + type = mCeMachine->GetBeContext()->GetPrimitiveType(BeTypeCode_Int8); + break; + case 2: + type = mCeMachine->GetBeContext()->GetPrimitiveType(BeTypeCode_Int16); + break; + case 4: + type = mCeMachine->GetBeContext()->GetPrimitiveType(BeTypeCode_Int32); + break; + case 8: + type = mCeMachine->GetBeContext()->GetPrimitiveType(BeTypeCode_Int64); + break; + default: + Fail("Bad const size"); + } + + auto result = FrameAlloc(type); + + EmitSizedOp(CeOp_Const_8, type->mSize); + EmitFrameOffset(result); + Emit(&val, size); + return result; +} + CeOperand CeBuilder::GetOperand(BeValue* value, bool allowAlloca, bool allowImmediate) { if (value == NULL) return CeOperand(); + + BeType* errorType = mIntPtrType; + CeErrorKind errorKind = CeErrorKind_None; switch (value->GetTypeId()) { case BeGlobalVariable::TypeId: { -// auto globalVar = (BeGlobalVariable*)value; -// if ((globalVar->mIsTLS) && (mTLSVRegIdx == -1)) -// { -// auto tlsVReg = AllocVirtualReg(mNativeIntType); -// auto vregInfo = GetVRegInfo(tlsVReg); -// vregInfo->mMustExist = true; -// vregInfo->mForceReg = true; -// mTLSVRegIdx = tlsVReg.mVRegIdx; -// } -// -// auto sym = mCOFFObject->GetSymbol(globalVar); -// if (sym != NULL) -// { -// CeOperand mcOperand; -// mcOperand.mKind = CeOperandKind_SymbolAddr; -// mcOperand.mSymbolIdx = sym->mIdx; -// return mcOperand; -// } + auto globalVar = (BeGlobalVariable*)value; + if (globalVar->mName.StartsWith("__bfStrObj")) + { + int stringId = atoi(globalVar->mName.c_str() + 10); + + int* stringTableIdxPtr = NULL; + if (mStringMap.TryAdd(stringId, NULL, &stringTableIdxPtr)) + { + *stringTableIdxPtr = (int)mCeFunction->mStringTable.size(); + CeStringEntry ceStringEntry; + ceStringEntry.mStringId = stringId; + mCeFunction->mStringTable.Add(ceStringEntry); + } + + auto result = FrameAlloc(mCeMachine->GetBeContext()->GetPointerTo(globalVar->mType)); + + Emit(CeOp_GetString); + EmitFrameOffset(result); + Emit((int32)*stringTableIdxPtr); + return result; + } + else if (globalVar->mName.StartsWith("__bfStrData")) + { + int stringId = atoi(globalVar->mName.c_str() + 11); + + int* stringTableIdxPtr = NULL; + if (mStringMap.TryAdd(stringId, NULL, &stringTableIdxPtr)) + { + *stringTableIdxPtr = (int)mCeFunction->mStringTable.size(); + CeStringEntry ceStringEntry; + ceStringEntry.mStringId = stringId; + mCeFunction->mStringTable.Add(ceStringEntry); + } + + auto result = FrameAlloc(mCeMachine->GetBeContext()->GetPointerTo(globalVar->mType)); + + Emit(CeOp_GetString); + EmitFrameOffset(result); + Emit((int32)*stringTableIdxPtr); + + BfTypeInstance* stringTypeInst = (BfTypeInstance*)mCeMachine->mCeModule->ResolveTypeDef( + mCeMachine->mCeModule->mCompiler->mStringTypeDef, BfPopulateType_Data); + + Emit(CeOp_AddConst_I32); + EmitFrameOffset(result); + EmitFrameOffset(result); + Emit((int32)stringTypeInst->mInstSize); + + return result; + } + errorKind = CeErrorKind_GlobalVariable; + errorType = mCeMachine->GetBeContext()->GetPointerTo(globalVar->mType); } break; case BeCastConstant::TypeId: @@ -533,22 +681,9 @@ CeOperand CeBuilder::GetOperand(BeValue* value, bool allowAlloca, bool allowImme auto constant = (BeCastConstant*)value; CeOperand mcOperand; - auto relTo = GetOperand(constant->mTarget); - if (relTo.mKind == CeOperandKind_Immediate) - { - mcOperand.mKind = CeOperandKind_Immediate; - mcOperand.mType = constant->mType; - return mcOperand; - } - - //Fail("Invalid operand"); -// mcOperand = AllocVirtualReg(constant->mType); -// auto vregInfo = GetVRegInfo(mcOperand); -// vregInfo->mDefOnFirstUse = true; -// vregInfo->mRelTo = relTo; -// vregInfo->mIsExpr = true; - - //return mcOperand; + auto result = GetOperand(constant->mTarget); + result.mType = constant->mType; + return result; } break; case BeConstant::TypeId: @@ -665,43 +800,49 @@ CeOperand CeBuilder::GetOperand(BeValue* value, bool allowAlloca, bool allowImme } case BeGEPConstant::TypeId: { -// auto gepConstant = (BeGEPConstant*)value; -// -// auto mcVal = GetOperand(gepConstant->mTarget); -// -// BePointerType* ptrType = (BePointerType*)GetType(mcVal); -// BEMC_ASSERT(ptrType->mTypeCode == BeTypeCode_Pointer); -// -// auto result = mcVal; -// -// // We assume we never do both an idx0 and idx1 at once. Fix if we change that. -// int byteOffset = 0; -// BeType* elementType = NULL; -// byteOffset += gepConstant->mIdx0 * ptrType->mElementType->mSize; -// -// if (ptrType->mElementType->mTypeCode == BeTypeCode_Struct) -// { -// BeStructType* structType = (BeStructType*)ptrType->mElementType; -// auto& structMember = structType->mMembers[gepConstant->mIdx1]; -// elementType = structMember.mType; -// byteOffset = structMember.mByteOffset; -// } -// else -// { -// BEMC_ASSERT(ptrType->mElementType->mTypeCode == BeTypeCode_SizedArray); -// auto arrayType = (BeSizedArrayType*)ptrType->mElementType; -// elementType = arrayType->mElementType; -// byteOffset = gepConstant->mIdx1 * elementType->mSize; -// } -// -// auto elementPtrType = mModule->mContext->GetPointerTo(elementType); + auto gepConstant = (BeGEPConstant*)value; + + auto mcVal = GetOperand(gepConstant->mTarget); + + BePointerType* ptrType = (BePointerType*)mcVal.mType; + BF_ASSERT(ptrType->mTypeCode == BeTypeCode_Pointer); + + auto result = mcVal; + + // We assume we never do both an idx0 and idx1 at once. Fix if we change that. + int64 byteOffset = 0; + BeType* elementType = NULL; + byteOffset += gepConstant->mIdx0 * ptrType->mElementType->mSize; + + if (ptrType->mElementType->mTypeCode == BeTypeCode_Struct) + { + BeStructType* structType = (BeStructType*)ptrType->mElementType; + auto& structMember = structType->mMembers[gepConstant->mIdx1]; + elementType = structMember.mType; + byteOffset = structMember.mByteOffset; + } + else + { + BF_ASSERT(ptrType->mElementType->mTypeCode == BeTypeCode_SizedArray); + auto arrayType = (BeSizedArrayType*)ptrType->mElementType; + elementType = arrayType->mElementType; + byteOffset = gepConstant->mIdx1 * elementType->mSize; + } + + auto elementPtrType = mCeMachine->GetBeContext()->GetPointerTo(elementType); + result = FrameAlloc(elementPtrType); + EmitSizedOp(CeOp_AddConst_I8, mPtrSize); + EmitFrameOffset(result); + EmitFrameOffset(mcVal); + Emit(&byteOffset, mPtrSize); + // result = AllocRelativeVirtualReg(elementPtrType, result, GetImmediate(byteOffset), 1); -// // The def is primary to create a single 'master location' for the GEP vreg to become legalized before use -// auto vregInfo = GetVRegInfo(result); -// vregInfo->mDefOnFirstUse = true; -// result.mKind = CeOperandKind_VReg; -// -// return result; +// // The def is primary to create a single 'master location' for the GEP vreg to become legalized before use +// auto vregInfo = GetVRegInfo(result); +// vregInfo->mDefOnFirstUse = true; +// result.mKind = CeOperandKind_VReg; + + return result; } break; case BeExtractValueConstant::TypeId: @@ -744,7 +885,12 @@ CeOperand CeBuilder::GetOperand(BeValue* value, bool allowAlloca, bool allowImme CeOperand* operandPtr = NULL; mValueToOperand.TryGetValue(value, &operandPtr); - //if (!allowFail) + if (errorKind != CeErrorKind_None) + { + Emit(CeOp_Error); + Emit((int32)errorKind); + } + else { if (operandPtr == NULL) { @@ -756,7 +902,7 @@ CeOperand CeBuilder::GetOperand(BeValue* value, bool allowAlloca, bool allowImme } if (operandPtr == NULL) { - return FrameAlloc(mIntPtrType); + return FrameAlloc(errorType); } auto operand = *operandPtr; @@ -773,160 +919,6 @@ CeOperand CeBuilder::GetOperand(BeValue* value, bool allowAlloca, bool allowImme return result; } -// if ((operand.mKind == CeOperandKind_Phi) && (!allowMetaResult)) -// { -// auto phi = operand.mPhi; -// -// int phiInstIdx = 0; -// -// auto mcBlock = phi->mBlock; -// for (auto instIdx = 0; instIdx < mcBlock->mInstructions.size(); instIdx++) -// { -// auto inst = mcBlock->mInstructions[instIdx]; -// if (inst->mKind == BeMCInstKind_DefPhi) -// { -// BEMC_ASSERT(inst->mArg0.mPhi == phi); -// phiInstIdx = instIdx; -// RemoveInst(mcBlock, phiInstIdx); -// break; -// } -// } -// -// SetAndRestoreValue prevBlock(mActiveBlock, mcBlock); -// SetAndRestoreValue prevInstIdxRef(mInsertInstIdxRef, &phiInstIdx); -// -// auto resultType = value->GetType(); -// auto result = AllocVirtualReg(resultType); -// auto vregInfo = GetVRegInfo(result); -// vregInfo->mHasDynLife = true; // No specific 'def' location -// mValueToOperand[value] = result; -// -// if (resultType->mTypeCode == BeTypeCode_Boolean) -// { -// CreateDefineVReg(result); -// -// CeOperand falseLabel = CeOperand::FromLabel(mCurLabelIdx++); -// CeOperand trueLabel = CeOperand::FromLabel(mCurLabelIdx++); -// CeOperand endLabel = CeOperand::FromLabel(mCurLabelIdx++); -// CreateCondBr(mActiveBlock, operand, trueLabel, falseLabel); -// -// AllocInst(BeMCInstKind_Label, falseLabel); -// AllocInst(BeMCInstKind_Mov, result, CeOperand::FromImmediate(0)); -// AllocInst(BeMCInstKind_Br, endLabel); -// AllocInst(BeMCInstKind_Label, trueLabel); -// AllocInst(BeMCInstKind_Mov, result, CeOperand::FromImmediate(1)); -// AllocInst(BeMCInstKind_Label, endLabel); -// } -// else -// { -// // Attempt to find common ancestor to insert a 'def' at -// SizedArray blockSearch; -// blockSearch.reserve(phi->mValues.size()); -// BeMCBlock* lowestBlock = NULL; -// for (auto& phiValue : phi->mValues) -// { -// if ((lowestBlock == NULL) || (phiValue.mBlockFrom->mBlockIdx < lowestBlock->mBlockIdx)) -// lowestBlock = phiValue.mBlockFrom; -// blockSearch.push_back(phiValue.mBlockFrom); -// } -// while (true) -// { -// bool allMatched = true; -// bool didWork = false; -// for (int searchIdx = 0; searchIdx < (int)blockSearch.size(); searchIdx++) -// { -// auto& blockRef = blockSearch[searchIdx]; -// if (blockRef != lowestBlock) -// { -// allMatched = false; -// -// for (auto& pred : blockRef->mPreds) -// { -// // Try find a block closer to start, but not below the current lowestBlock -// if ((pred->mBlockIdx >= lowestBlock->mBlockIdx) && (pred->mBlockIdx < blockRef->mBlockIdx)) -// { -// blockRef = pred; -// didWork = true; -// } -// } -// } -// } -// -// if (allMatched) -// { -// SetAndRestoreValue prevActiveBlock(mActiveBlock, lowestBlock); -// SetAndRestoreValue prevInstIdxRef(mInsertInstIdxRef, NULL); -// auto inst = CreateDefineVReg(result); -// inst->mVRegsInitialized = NULL; -// inst->mDbgLoc = NULL; -// break; -// } -// -// if (!didWork) -// { -// BeMCBlock* nextLowestBlock = NULL; -// -// // Find the next candidate block -// for (auto& blockRef : blockSearch) -// { -// for (auto& pred : blockRef->mPreds) -// { -// if (pred->mBlockIdx < lowestBlock->mBlockIdx) -// { -// if ((nextLowestBlock == NULL) || (pred->mBlockIdx > nextLowestBlock->mBlockIdx)) -// nextLowestBlock = pred; -// } -// } -// } -// -// if (nextLowestBlock == NULL) -// break; -// lowestBlock = nextLowestBlock; -// } -// } -// -// CeOperand doneLabel = CeOperand::FromLabel(mCurLabelIdx++); -// CreatePhiAssign(mActiveBlock, operand, result, doneLabel); -// -// // Don't use an explicit dbgLoc -// SetAndRestoreValue prevDbgLoc(mCurDbgLoc, NULL); -// AllocInst(BeMCInstKind_Label, doneLabel); -// } -// -// return result; -// } -// -// if ((operand.mKind == CeOperandKind_CmpResult) && (!allowMetaResult)) -// { -// auto& cmpResult = mCmpResults[operand.mCmpResultIdx]; -// if (cmpResult.mResultVRegIdx == -1) -// { -// // Create the vreg now, and insert the CmpToBool during legalization -// BeType* boolType = mModule->mContext->GetPrimitiveType(BeTypeCode_Boolean); -// operand = AllocVirtualReg(boolType); -// cmpResult.mResultVRegIdx = operand.mVRegIdx; -// -// auto vregInfo = GetVRegInfo(operand); -// vregInfo->mDefOnFirstUse = true; -// } -// -// operand = CeOperand::FromVReg(cmpResult.mResultVRegIdx); -// } -// -// if ((operand.mKind == CeOperandKind_NotResult) && (!allowMetaResult)) -// { -// auto mcValue = GetOperand(operand.mNotResult->mValue, false, allowFail); -// -// operand = AllocVirtualReg(GetType(mcValue)); -// CreateDefineVReg(operand); -// AllocInst(BeMCInstKind_Mov, operand, mcValue); -// -// CeOperand xorVal; -// xorVal.mKind = CeOperandKind_Immediate_i8; -// xorVal.mImmediate = 0x1; -// AllocInst(BeMCInstKind_Xor, operand, xorVal); -// } - return operand; } @@ -1010,9 +1002,11 @@ void CeBuilder::Build() dupMethodInstance.mIsReified = true; dupMethodInstance.mHotMethod = NULL; dupMethodInstance.mInCEMachine = false; // Only have the original one - + + mCeMachine->mCeModule->mIgnoreWarnings = true; + mCeMachine->mCeModule->mHadBuildError = false; mCeMachine->mCeModule->ProcessMethod(&dupMethodInstance, true); - + if (!dupMethodInstance.mIRFunction) { mCeFunction->mFailed = true; @@ -1023,8 +1017,23 @@ void CeBuilder::Build() mIntPtrType = irCodeGen->mBeContext->GetPrimitiveType((mPtrSize == 4) ? BeTypeCode_Int32 : BeTypeCode_Int64); mBeFunction = (BeFunction*)irCodeGen->GetBeValue(dupMethodInstance.mIRFunction.mId); - mCeFunction->mName = mBeFunction->mName; - mCeMachine->mNamedFunctionMap[mCeFunction->mName] = mCeFunction; + if (!mCeFunction->mCeFunctionInfo->mName.IsEmpty()) + { + BF_ASSERT(mCeFunction->mCeFunctionInfo->mName == mBeFunction->mName); + } + else + { + mCeFunction->mCeFunctionInfo->mName = mBeFunction->mName; + mCeMachine->mNamedFunctionMap[mCeFunction->mCeFunctionInfo->mName] = mCeFunction->mCeFunctionInfo; + } + + if (mCeMachine->mCeModule->mHadBuildError) + { + mCeFunction->mGenError = "Method had errors"; + mCeMachine->mCeModule->mHadBuildError = false; + return; + } + auto beModule = irCodeGen->mBeModule; SetAndRestoreValue prevBeFunction(beModule->mActiveFunction, mBeFunction); @@ -1128,32 +1137,85 @@ void CeBuilder::Build() case BeLifetimeExtendInst::TypeId: case BeValueScopeStartInst::TypeId: case BeValueScopeEndInst::TypeId: + case BeValueScopeRetainInst::TypeId: + case BeConstEvalGetVirtualFunc::TypeId: + case BeConstEvalGetInterfaceFunc::TypeId: break; case BeUnreachableInst::TypeId: Emit(CeOp_InvalidOp); break; + case BeUndefValueInst::TypeId: + { + auto castedInst = (BeUndefValueInst*)inst; + result = FrameAlloc(castedInst->mType); + } + break; case BeAllocaInst::TypeId: { auto castedInst = (BeAllocaInst*)inst; - int size = castedInst->mType->mSize; + + CeOperand ceSize; + ceSize.mKind = CeOperandKind_Immediate; + ceSize.mImmediate = castedInst->mType->mSize; + ceSize.mType = mIntPtrType; bool isAligned16 = false; int align = castedInst->mAlign; BeType* allocType = castedInst->mType; - bool preservedVolatiles = false; - bool doPtrCast = false; + bool preservedVolatiles = false; + + if (castedInst->mArraySize != NULL) + { + auto mcArraySize = GetOperand(castedInst->mArraySize, false, true); + if (mcArraySize.IsImmediate()) + { + ceSize.mImmediate = ceSize.mImmediate * mcArraySize.mImmediate; + } + else + { + inHeadAlloca = false; + if (ceSize.mImmediate == 1) + { + ceSize = mcArraySize; + } + else + { + ceSize = EmitConst(ceSize.mImmediate, mcArraySize.mType->mSize); + + EmitSizedOp(CeOp_Mul_I8, ceSize.mType->mSize); + EmitFrameOffset(ceSize); + EmitFrameOffset(ceSize); + EmitFrameOffset(mcArraySize); + } + } + } if (inHeadAlloca) { - mFrameSize += size; + BF_ASSERT(ceSize.mKind == CeOperandKind_Immediate); + mFrameSize += ceSize.mImmediate; result.mKind = CeOperandKind_AllocaAddr; result.mFrameOfs = -mFrameSize; - result.mType = castedInst->mType; + result.mType = castedInst->mType; } else { - Fail("Non-head alloca"); - return; + if (ceSize.mKind == CeOperandKind_Immediate) + { + Emit(CeOp_AdjustSPConst); + Emit((int32)-ceSize.mImmediate); + } + else + { + Emit(CeOp_AdjustSPNeg); + EmitFrameOffset(ceSize); + } + + auto ptrType = beModule->mContext->GetPointerTo(allocType); + + result = FrameAlloc(ptrType); + Emit(CeOp_GetSP); + EmitFrameOffset(result); } } break; @@ -1164,8 +1226,18 @@ void CeBuilder::Build() if (ceTarget.mKind == CeOperandKind_AllocaAddr) { - result = ceTarget; - result.mKind = CeOperandKind_FrameOfs; + if (inst->mRefCount <= 1) + { + result = ceTarget; + result.mKind = CeOperandKind_FrameOfs; + } + else + { + ceTarget.mKind = CeOperandKind_FrameOfs; + result = FrameAlloc(ceTarget.mType); + EmitSizedOp(CeOp_Move_8, ceTarget, NULL, true); + Emit((int32)result.mFrameOfs); + } } else { @@ -1185,21 +1257,6 @@ void CeBuilder::Build() auto ceLHS = GetOperand(castedInst->mLHS); auto ceRHS = GetOperand(castedInst->mRHS); -// if (castedInst->mOpKind == BeBinaryOpKind_Subtract) -// { -// if (((mcLHS.IsImmediateFloat()) && (mcLHS.GetImmediateDouble() == 0.0)) || -// ((mcLHS.IsImmediateInt()) && (mcLHS.mImmediate == 0))) -// { -// auto castedInst = (BeNumericCastInst*)inst; -// -// result = AllocVirtualReg(GetType(mcRHS)); -// CreateDefineVReg(result); -// AllocInst(BeMCInstKind_Mov, result, mcRHS); -// AllocInst(BeMCInstKind_Neg, result); -// break; -// } -// } - switch (castedInst->mOpKind) { case BeBinaryOpKind_Add: @@ -1212,39 +1269,78 @@ void CeBuilder::Build() EmitBinaryOp(CeOp_Mul_I8, CeOp_Mul_F32, ceLHS, ceRHS, result); break; case BeBinaryOpKind_SDivide: - EmitBinaryOp(CeOp_SDiv_I8, CeOp_SDiv_F32, ceLHS, ceRHS, result); + EmitBinaryOp(CeOp_Div_I8, CeOp_Div_F32, ceLHS, ceRHS, result); break; case BeBinaryOpKind_UDivide: - EmitBinaryOp(CeOp_UDiv_I8, CeOp_InvalidOp, ceLHS, ceRHS, result); + EmitBinaryOp(CeOp_Div_U8, CeOp_InvalidOp, ceLHS, ceRHS, result); break; case BeBinaryOpKind_SModulus: - EmitBinaryOp(CeOp_SMod_I8, CeOp_SMod_F32, ceLHS, ceRHS, result); + EmitBinaryOp(CeOp_Mod_I8, CeOp_Mod_F32, ceLHS, ceRHS, result); break; case BeBinaryOpKind_UModulus: - EmitBinaryOp(CeOp_UMod_I8, CeOp_InvalidOp, ceLHS, ceRHS, result); + EmitBinaryOp(CeOp_Mod_U8, CeOp_InvalidOp, ceLHS, ceRHS, result); + break; + case BeBinaryOpKind_BitwiseAnd: + EmitBinaryOp(CeOp_And_I8, CeOp_InvalidOp, ceLHS, ceRHS, result); + break; + case BeBinaryOpKind_BitwiseOr: + EmitBinaryOp(CeOp_Or_I8, CeOp_InvalidOp, ceLHS, ceRHS, result); + break; + case BeBinaryOpKind_ExclusiveOr: + EmitBinaryOp(CeOp_Xor_I8, CeOp_InvalidOp, ceLHS, ceRHS, result); + break; + case BeBinaryOpKind_LeftShift: + EmitBinaryOp(CeOp_Shl_I8, CeOp_InvalidOp, ceLHS, ceRHS, result); + break; + case BeBinaryOpKind_RightShift: + EmitBinaryOp(CeOp_Shr_I8, CeOp_InvalidOp, ceLHS, ceRHS, result); + break; + case BeBinaryOpKind_ARightShift: + EmitBinaryOp(CeOp_Shr_U8, CeOp_InvalidOp, ceLHS, ceRHS, result); break; default: Fail("Invalid binary op"); } + } + break; + case BeBitCastInst::TypeId: + { + auto castedInst = (BeBitCastInst*)inst; + auto mcValue = GetOperand(castedInst->mValue, false, true); + if (castedInst->mToType->IsInt()) + { + BF_ASSERT(castedInst->mToType->mSize == 8); + } + else + BF_ASSERT(castedInst->mToType->IsPointer()); + auto toType = castedInst->mToType; -// auto type = GetType(mcLHS); -// -// switch (castedInst->mOpKind) -// { -// case BeBinaryOpKind_Add: result = AllocBinaryOp(BeMCInstKind_Add, mcLHS, mcRHS, BeMCBinIdentityKind_Any_IsZero); break; -// case BeBinaryOpKind_Subtract: result = AllocBinaryOp(BeMCInstKind_Sub, mcLHS, mcRHS, BeMCBinIdentityKind_Right_IsZero); break; -// case BeBinaryOpKind_Multiply: result = AllocBinaryOp(BeMCInstKind_IMul, mcLHS, mcRHS, BeMCBinIdentityKind_Any_IsOne); break; -// case BeBinaryOpKind_SDivide: result = AllocBinaryOp(BeMCInstKind_IDiv, mcLHS, mcRHS, BeMCBinIdentityKind_Right_IsOne); break; -// case BeBinaryOpKind_UDivide: result = AllocBinaryOp(BeMCInstKind_Div, mcLHS, mcRHS, BeMCBinIdentityKind_Right_IsOne); break; -// case BeBinaryOpKind_SModulus: result = AllocBinaryOp(BeMCInstKind_IRem, mcLHS, mcRHS, type->IsFloat() ? BeMCBinIdentityKind_None : BeMCBinIdentityKind_Right_IsOne_Result_Zero); break; -// case BeBinaryOpKind_UModulus: result = AllocBinaryOp(BeMCInstKind_Rem, mcLHS, mcRHS, type->IsFloat() ? BeMCBinIdentityKind_None : BeMCBinIdentityKind_Right_IsOne_Result_Zero); break; -// case BeBinaryOpKind_BitwiseAnd: result = AllocBinaryOp(BeMCInstKind_And, mcLHS, mcRHS, BeMCBinIdentityKind_None); break; -// case BeBinaryOpKind_BitwiseOr: result = AllocBinaryOp(BeMCInstKind_Or, mcLHS, mcRHS, BeMCBinIdentityKind_Any_IsZero); break; -// case BeBinaryOpKind_ExclusiveOr: result = AllocBinaryOp(BeMCInstKind_Xor, mcLHS, mcRHS, BeMCBinIdentityKind_Any_IsZero); break; -// case BeBinaryOpKind_LeftShift: result = AllocBinaryOp(BeMCInstKind_Shl, mcLHS, mcRHS, BeMCBinIdentityKind_Any_IsZero); break; -// case BeBinaryOpKind_RightShift: result = AllocBinaryOp(BeMCInstKind_Shr, mcLHS, mcRHS, BeMCBinIdentityKind_Any_IsZero); break; -// case BeBinaryOpKind_ARightShift: result = AllocBinaryOp(BeMCInstKind_Sar, mcLHS, mcRHS, BeMCBinIdentityKind_Any_IsZero); break; -// } + if (mcValue.IsImmediate()) + { + if (mcValue.mImmediate == 0) + { + CeOperand newImmediate; + newImmediate.mKind = CeOperandKind_Immediate; + newImmediate.mType = toType; + result = newImmediate; + } + else + { + // Non-zero constant. Weird case, just do an actual MOV + result = FrameAlloc(toType); + EmitSizedOp(CeOp_Const_8, result, NULL, true); + int64 val = mcValue.mImmediate; + Emit(&val, toType->mSize); + } + } + else + { + if (toType->mSize != mcValue.mType->mSize) + Fail("Invalid bitcast"); + + result = mcValue; + result.mType = toType; + } } break; case BeNumericCastInst::TypeId: @@ -1259,46 +1355,210 @@ void CeBuilder::Build() } else { - auto toType = castedInst->mToType; - if ((toType->IsIntable()) && (fromType->IsIntable()) && (toType->mSize < fromType->mSize)) + auto toType = castedInst->mToType; + if ((toType->IsIntable()) && (fromType->IsIntable()) && (toType->mSize <= fromType->mSize)) { // For truncating values, no actual instructions are needed + // Note that a copy is not needed because of SSA rules result = ceValue; - result.mType = toType; + result.mType = toType; } else - { - bool doSignExtension = (toType->IsIntable()) && (fromType->IsIntable()) && (toType->mSize > fromType->mSize) && (castedInst->mToSigned) && (castedInst->mValSigned); -// if ((toType->IsFloat()) && (fromType->IsIntable()) && (castedInst->mValSigned)) -// doSignExtension = true; - + { result = FrameAlloc(toType); CeOp op = CeOp_InvalidOp; - - if (doSignExtension) - { - switch (fromType->mTypeCode) + + BeTypeCode fromTypeCode = fromType->mTypeCode; + BeTypeCode toTypeCode = toType->mTypeCode; + + if (castedInst->mToSigned) + { + switch (fromTypeCode) { + case BeTypeCode_Int8: + switch (toTypeCode) + { + case BeTypeCode_Int16: + op = CeOp_Conv_I8_I16; + break; + case BeTypeCode_Int32: + op = CeOp_Conv_I8_I32; + break; + case BeTypeCode_Int64: + op = CeOp_Conv_I8_I64; + break; + case BeTypeCode_Float: + op = CeOp_Conv_I8_F32; + break; + case BeTypeCode_Double: + op = CeOp_Conv_I8_F64; + break; + } + break; + case BeTypeCode_Int16: + switch (toTypeCode) + { + case BeTypeCode_Int32: + op = CeOp_Conv_I16_I32; + break; + case BeTypeCode_Int64: + op = CeOp_Conv_I16_I64; + break; + case BeTypeCode_Float: + op = CeOp_Conv_I16_F32; + break; + case BeTypeCode_Double: + op = CeOp_Conv_I16_F64; + break; + } + break; case BeTypeCode_Int32: - switch (toType->mTypeCode) + switch (toTypeCode) { case BeTypeCode_Int64: op = CeOp_Conv_I32_I64; + break; + case BeTypeCode_Float: + op = CeOp_Conv_I32_F32; + break; + case BeTypeCode_Double: + op = CeOp_Conv_I32_F64; + break; } + break; + case BeTypeCode_Int64: + switch (toTypeCode) + { + case BeTypeCode_Float: + op = CeOp_Conv_I64_F32; + break; + case BeTypeCode_Double: + op = CeOp_Conv_I64_F64; + break; + } + break; + case BeTypeCode_Float: + switch (toTypeCode) + { + case BeTypeCode_Int8: + op = CeOp_Conv_F32_I8; + break; + case BeTypeCode_Int16: + op = CeOp_Conv_F32_I16; + break; + case BeTypeCode_Int32: + op = CeOp_Conv_F32_I32; + break; + case BeTypeCode_Int64: + op = CeOp_Conv_F32_I64; + break; + case BeTypeCode_Double: + op = CeOp_Conv_F32_F64; + break; + } + break; + case BeTypeCode_Double: + switch (toTypeCode) + { + case BeTypeCode_Int8: + op = CeOp_Conv_F64_I8; + break; + case BeTypeCode_Int16: + op = CeOp_Conv_F64_I16; + break; + case BeTypeCode_Int32: + op = CeOp_Conv_F64_I32; + break; + case BeTypeCode_Int64: + op = CeOp_Conv_F64_I64; + break; + case BeTypeCode_Float: + op = CeOp_Conv_F64_F32; + break; + } + break; } } else { - + switch (fromTypeCode) + { + case BeTypeCode_Int8: + switch (toTypeCode) + { + case BeTypeCode_Int16: + op = CeOp_Conv_U8_U16; + break; + case BeTypeCode_Int32: + op = CeOp_Conv_U8_U32; + break; + case BeTypeCode_Int64: + op = CeOp_Conv_U8_U64; + break; + case BeTypeCode_Float: + op = CeOp_Conv_I8_F32; + break; + case BeTypeCode_Double: + op = CeOp_Conv_I8_F64; + break; + } + break; + case BeTypeCode_Int16: + switch (toTypeCode) + { + case BeTypeCode_Int32: + op = CeOp_Conv_U16_U32; + break; + case BeTypeCode_Int64: + op = CeOp_Conv_U16_U64; + break; + case BeTypeCode_Float: + op = CeOp_Conv_U16_F32; + break; + case BeTypeCode_Double: + op = CeOp_Conv_U16_F64; + break; + } + break; + case BeTypeCode_Int32: + switch (toTypeCode) + { + case BeTypeCode_Int64: + op = CeOp_Conv_U32_U64; + break; + case BeTypeCode_Float: + op = CeOp_Conv_U32_F32; + break; + case BeTypeCode_Double: + op = CeOp_Conv_U32_F64; + break; + } + break; + case BeTypeCode_Int64: + switch (toTypeCode) + { + case BeTypeCode_Float: + op = CeOp_Conv_I64_F32; + break; + case BeTypeCode_Double: + op = CeOp_Conv_I64_F64; + break; + } + break; + } } if (op == CeOp_InvalidOp) + { Fail("Invalid conversion op"); - - Emit(op); - EmitFrameOffset(result); - EmitFrameOffset(ceValue); + } + else + { + Emit(op); + EmitFrameOffset(result); + EmitFrameOffset(ceValue); + } } } } @@ -1310,7 +1570,7 @@ void CeBuilder::Build() auto mcPtr = GetOperand(castedInst->mPtr, true); if (mcPtr.mKind == CeOperandKind_AllocaAddr) - { + { EmitSizedOp(CeOp_Move_8, mcVal, NULL, true); Emit((int32)mcPtr.mFrameOfs); } @@ -1346,6 +1606,15 @@ void CeBuilder::Build() switch (castedInst->mCmpKind) { + case BeCmpKind_EQ: + iOp = CeOp_Cmp_EQ_I8; + fOp = CeOp_Cmp_EQ_F32; + break; + case BeCmpKind_NE: + iOp = CeOp_Cmp_NE_I8; + fOp = CeOp_Cmp_NE_F32; + break; + case BeCmpKind_SLT: iOp = CeOp_Cmp_SLT_I8; fOp = CeOp_Cmp_SLT_F32; @@ -1360,6 +1629,21 @@ void CeBuilder::Build() case BeCmpKind_ULE: iOp = CeOp_Cmp_ULE_I8; break; + + case BeCmpKind_SGT: + iOp = CeOp_Cmp_SGT_I8; + fOp = CeOp_Cmp_SGT_F32; + break; + case BeCmpKind_UGT: + iOp = CeOp_Cmp_UGT_I8; + break; + case BeCmpKind_SGE: + iOp = CeOp_Cmp_SGE_I8; + fOp = CeOp_Cmp_SGE_F32; + break; + case BeCmpKind_UGE: + iOp = CeOp_Cmp_UGE_I8; + break; } if (iOp == CeOp_InvalidOp) @@ -1434,32 +1718,46 @@ void CeBuilder::Build() { auto ptrValue = FrameAlloc(elementPtrType); result = ptrValue; - } -// auto ptrValue = AllocVirtualReg(elementPtrType); -// auto ptrInfo = GetVRegInfo(ptrValue); -// ptrInfo->mIsExpr = true; -// ptrInfo->mRelTo = result; -// CreateDefineVReg(ptrValue); -// result = ptrValue; -// -// BeMCOperand mcRelOffset; -// int relScale = 1; -// if (mcIdx1.IsImmediate()) -// { -// mcRelOffset = BeMCOperand::FromImmediate(mcIdx1.mImmediate * arrayType->mElementType->mSize); -// } -// else -// { -// mcRelOffset = mcIdx1; -// relScale = arrayType->mElementType->mSize; -// } -// -// result = AllocRelativeVirtualReg(elementPtrType, result, mcRelOffset, relScale); -// // The def is primary to create a single 'master location' for the GEP vreg to become legalized before use -// CreateDefineVReg(result); -// //TODO: Always correct? -// result.mKind = BeMCOperandKind_VReg; + result = FrameAlloc(elementPtrType); + + if (mPtrSize == 4) + { + auto mcElementSize = FrameAlloc(mIntPtrType); + Emit(CeOp_Const_32); + EmitFrameOffset(mcElementSize); + Emit((int32)arrayType->mElementType->mSize); + + auto ofsValue = FrameAlloc(mIntPtrType); + Emit(CeOp_Mul_I32); + EmitFrameOffset(ofsValue); + EmitFrameOffset(ceIdx1); + EmitFrameOffset(mcElementSize); + + Emit(CeOp_Add_I32); + EmitFrameOffset(result); + EmitFrameOffset(ceVal); + EmitFrameOffset(ofsValue); + } + else + { + auto mcElementSize = FrameAlloc(mIntPtrType); + Emit(CeOp_Const_64); + EmitFrameOffset(mcElementSize); + Emit((int64)arrayType->mElementType->mSize); + + auto ofsValue = FrameAlloc(mIntPtrType); + Emit(CeOp_Mul_I64); + EmitFrameOffset(ofsValue); + EmitFrameOffset(ceIdx1); + EmitFrameOffset(mcElementSize); + + Emit(CeOp_Add_I64); + EmitFrameOffset(result); + EmitFrameOffset(ceVal); + EmitFrameOffset(ofsValue); + } + } } else Fail("Invalid GEP"); @@ -1493,7 +1791,7 @@ void CeBuilder::Build() Fail("Invalid gep target"); } - auto elementPtrType = beModule->mContext->GetPointerTo(elementType); + auto elementPtrType = beModule->mContext->GetPointerTo(elementType); if (byteOffset != 0) { @@ -1510,29 +1808,61 @@ void CeBuilder::Build() } } else - { - // It's temping to do a (IsNonZero) precondition, but if we make a reference to a VReg that is NOT in Addr form, - // then this will encode that so we will know we need to do a Load on that value at the Def during legalization + { + CeOperand mcRelOffset; + int relScale = 1; + if (ceIdx0.IsImmediate()) + { + int byteOffset = ceIdx0.mImmediate * ptrType->mElementType->mSize; + if (byteOffset != 0) + { + result = FrameAlloc(ptrType); + Emit((CeOp)(CeOp_AddConst_I32)); + EmitFrameOffset(result); + EmitFrameOffset(ceVal); + Emit((int32)byteOffset); + } + } + else + { + result = FrameAlloc(ptrType); + if (mPtrSize == 4) + { + auto mcElementSize = FrameAlloc(mIntPtrType); + Emit(CeOp_Const_32); + EmitFrameOffset(mcElementSize); + Emit((int32)ptrType->mElementType->mSize); - Fail("Unhandled gep"); + auto ofsValue = FrameAlloc(mIntPtrType); + Emit(CeOp_Mul_I32); + EmitFrameOffset(ofsValue); + EmitFrameOffset(ceIdx0); + EmitFrameOffset(mcElementSize); -// BeMCOperand mcRelOffset; -// int relScale = 1; -// if (mcIdx0.IsImmediate()) -// { -// mcRelOffset = BeMCOperand::FromImmediate(mcIdx0.mImmediate * ptrType->mElementType->mSize); -// } -// else -// { -// mcRelOffset = mcIdx0; -// relScale = ptrType->mElementType->mSize; -// } -// -// result = AllocRelativeVirtualReg(ptrType, result, mcRelOffset, relScale); -// // The def is primary to create a single 'master location' for the GEP vreg to become legalized before use -// CreateDefineVReg(result); -// //TODO: Always correct? -// result.mKind = BeMCOperandKind_VReg; + Emit(CeOp_Add_I32); + EmitFrameOffset(result); + EmitFrameOffset(ceVal); + EmitFrameOffset(ofsValue); + } + else + { + auto mcElementSize = FrameAlloc(mIntPtrType); + Emit(CeOp_Const_64); + EmitFrameOffset(mcElementSize); + Emit((int64)ptrType->mElementType->mSize); + + auto ofsValue = FrameAlloc(mIntPtrType); + Emit(CeOp_Mul_I64); + EmitFrameOffset(ofsValue); + EmitFrameOffset(ceIdx0); + EmitFrameOffset(mcElementSize); + + Emit(CeOp_Add_I64); + EmitFrameOffset(result); + EmitFrameOffset(ceVal); + EmitFrameOffset(ofsValue); + } + } } } break; @@ -1577,11 +1907,21 @@ void CeBuilder::Build() break; case BeNegInst::TypeId: { - auto castedInst = (BeNumericCastInst*)inst; + auto castedInst = (BeNegInst*)inst; auto ceValue = GetOperand(castedInst->mValue); EmitUnaryOp(CeOp_Neg_I8, CeOp_Neg_F32, ceValue, result); } break; + case BeNotInst::TypeId: + { + auto castedInst = (BeNotInst*)inst; + auto ceValue = GetOperand(castedInst->mValue); + if (ceValue.mType->mTypeCode == BeTypeCode_Boolean) + EmitUnaryOp(CeOp_Not_I1, CeOp_InvalidOp, ceValue, result); + else + EmitUnaryOp(CeOp_Not_I8, CeOp_InvalidOp, ceValue, result); + } + break; case BeSwitchInst::TypeId: { auto castedInst = (BeSwitchInst*)inst; @@ -1613,43 +1953,158 @@ void CeBuilder::Build() //SizedArray args; int callIdx = -1; + BeFunctionType* beFuncType = NULL; + CeOperand virtTarget; + int ifaceTypeId = -1; + int virtualTableIdx = -1; if (auto intrin = BeValueDynCast(castedInst->mFunc)) { - Fail("Intrinsics not allowed"); + switch (intrin->mKind) + { + case BfIRIntrinsic_Cast: + { + result = GetOperand(castedInst->mArgs[0].mValue); + result.mType = intrin->mReturnType; + } + break; + case BfIRIntrinsic_MemCpy: + { + CeOperand ceDestPtr = GetOperand(castedInst->mArgs[0].mValue); + CeOperand ceSrcPtr = GetOperand(castedInst->mArgs[1].mValue); + CeOperand ceSize = GetOperand(castedInst->mArgs[2].mValue); + + Emit(CeOp_MemCpy); + EmitFrameOffset(ceDestPtr); + EmitFrameOffset(ceSrcPtr); + EmitFrameOffset(ceSize); + } + break; + default: + Emit(CeOp_Error); + Emit((int32)CeErrorKind_Intrinsic); + break; + } } else if (auto beFunction = BeValueDynCast(castedInst->mFunc)) { + beFuncType = beFunction->GetFuncType(); + + if (beFunction->mName == "malloc") + { + result = FrameAlloc(beFuncType->mReturnType); + auto ceSize = GetOperand(castedInst->mArgs[0].mValue); + Emit(CeOp_Malloc); + EmitFrameOffset(result); + EmitFrameOffset(ceSize); + break; + } + + if (beFunction->mName == "free") + { + auto cePtr = GetOperand(castedInst->mArgs[0].mValue); + Emit(CeOp_Free); + EmitFrameOffset(cePtr); + break; + } + int* callIdxPtr = NULL; if (mFunctionMap.TryAdd(beFunction, NULL, &callIdxPtr)) { + CeFunctionInfo* ceFunctionInfo = NULL; + mCeMachine->mNamedFunctionMap.TryGetValue(beFunction->mName, &ceFunctionInfo); + if (ceFunctionInfo != NULL) + ceFunctionInfo->mRefCount++; + else + { + Fail(StrFormat("Unable to locate method %s", beFunction->mName.c_str())); + } + CeCallEntry callEntry; - callEntry.mFunctionName = beFunction->mName; + callEntry.mFunctionInfo = ceFunctionInfo; *callIdxPtr = (int)mCeFunction->mCallTable.size(); mCeFunction->mCallTable.Add(callEntry); } + + callIdx = *callIdxPtr; + } + else if (auto beGetVirtualFunc = BeValueDynCast(castedInst->mFunc)) + { + virtTarget = GetOperand(beGetVirtualFunc->mValue); + virtualTableIdx = beGetVirtualFunc->mVirtualTableIdx; + + auto resultType = beGetVirtualFunc->GetType(); + BF_ASSERT(resultType->IsPointer()); + beFuncType = (BeFunctionType*)((BePointerType*)resultType)->mElementType; + } + else if (auto beGetInterfaceFunc = BeValueDynCast(castedInst->mFunc)) + { + virtTarget = GetOperand(beGetInterfaceFunc->mValue); + ifaceTypeId = beGetInterfaceFunc->mIFaceTypeId; + virtualTableIdx = beGetInterfaceFunc->mVirtualTableIdx; - callIdx = *callIdxPtr; + auto resultType = beGetInterfaceFunc->GetType(); + BF_ASSERT(resultType->IsPointer()); + beFuncType = (BeFunctionType*)((BePointerType*)resultType)->mElementType; + } + else + { + Emit(CeOp_Error); + Emit((int32)CeErrorKind_FunctionPointer); + + auto funcType = castedInst->mFunc->GetType(); + if (funcType->IsPointer()) + { + auto ptrType = (BePointerType*)funcType; + if (ptrType->mElementType->mTypeCode == BeTypeCode_Function) + { + auto beFuncType = (BeFunctionType*)ptrType->mElementType; + if (beFuncType->mReturnType->mSize > 0) + result = FrameAlloc(beFuncType->mReturnType); + } + } + } + + if ((callIdx != -1) || (virtualTableIdx != -1)) + { + CeOperand thisOperand; for (int argIdx = (int)castedInst->mArgs.size() - 1; argIdx >= 0; argIdx--) { auto& arg = castedInst->mArgs[argIdx]; auto ceArg = GetOperand(arg.mValue); + if (argIdx == 0) + thisOperand = ceArg; EmitSizedOp(CeOp_Push_8, ceArg, NULL, true); } int stackAdjust = 0; - - auto beFuncType = beFunction->GetFuncType(); + if (beFuncType->mReturnType->mSize > 0) { - Emit(CeOp_AdjustSP); + Emit(CeOp_AdjustSPConst); Emit((int32)-beFuncType->mReturnType->mSize); stackAdjust += beFuncType->mReturnType->mSize; } - - Emit(CeOp_Call); - Emit((int32)callIdx); + + if (ifaceTypeId != -1) + { + Emit(CeOp_Call_IFace); + EmitFrameOffset(thisOperand); + Emit((int32)ifaceTypeId); + Emit((int32)virtualTableIdx); + } + else if (virtualTableIdx != -1) + { + Emit(CeOp_Call_Virt); + EmitFrameOffset(thisOperand); + Emit((int32)virtualTableIdx); + } + else + { + Emit(CeOp_Call); + Emit((int32)callIdx); + } if (beFuncType->mReturnType->mSize > 0) { @@ -1659,26 +2114,79 @@ void CeBuilder::Build() if (stackAdjust > 0) { - Emit(CeOp_AdjustSP); + Emit(CeOp_AdjustSPConst); Emit(stackAdjust); } } - else + } + break; + case BeMemSetInst::TypeId: + { + auto castedInst = (BeMemSetInst*)inst; + auto ceAddr = GetOperand(castedInst->mAddr); + + if (auto constVal = BeValueDynCast(castedInst->mVal)) { - Fail("Cannot call through function pointers"); -// auto funcPtrType = castedInst->mFunc->GetType(); -// if (funcPtrType->IsPointer()) -// { -// auto elementType = ((BePointerType*)funcPtrType)->mElementType; -// if (elementType->mTypeCode == BeTypeCode_Function) -// { -// isVarArg = ((BeFunctionType*)elementType)->mIsVarArg; -// } -// } -// -// returnType = castedInst->GetType(); -// ceFunc = GetOperand(castedInst->mFunc); - } + if (auto constSize = BeValueDynCast(castedInst->mSize)) + { + if (constVal->mUInt8 == 0) + { + Emit(CeOp_MemSet_Const); + EmitFrameOffset(ceAddr); + Emit((uint8)0); + Emit((int32)constSize->mUInt32); + break; + } + } + } + + auto ceVal = GetOperand(castedInst->mVal); + auto ceSize = GetOperand(castedInst->mSize); + + Emit(CeOp_MemSet); + EmitFrameOffset(ceAddr); + EmitFrameOffset(ceVal); + EmitFrameOffset(ceSize); + } + break; + case BeFenceInst::TypeId: + break; + case BeStackSaveInst::TypeId: + { + result = FrameAlloc(mIntPtrType); + Emit(CeOp_GetSP); + EmitFrameOffset(result); + } + break; + case BeStackRestoreInst::TypeId: + { + auto castedInst = (BeStackRestoreInst*)inst; + + auto mcStackVal = GetOperand(castedInst->mStackVal); + Emit(CeOp_SetSP); + EmitFrameOffset(mcStackVal); + } + break; + case BeConstEvalGetType::TypeId: + { + auto castedInst = (BeConstEvalGetType*)inst; + result.mKind = CeOperandKind_Immediate; + result.mImmediate = castedInst->mTypeId; + result.mType = beModule->mContext->GetPrimitiveType(BeTypeCode_Int32); + } + break; + case BeConstEvalDynamicCastCheck::TypeId: + { + auto castedInst = (BeConstEvalDynamicCastCheck*)inst; + auto mcValue = GetOperand(castedInst->mValue); + + auto ptrType = beModule->mContext->GetPrimitiveType(BeTypeCode_NullPtr); + result = FrameAlloc(ptrType); + + Emit(CeOp_DynamicCastCheck); + EmitFrameOffset(result); + EmitFrameOffset(mcValue); + Emit((int32)castedInst->mTypeId); } break; default: @@ -1702,7 +2210,10 @@ void CeBuilder::Build() if (mDbgFileMap.TryAdd(dbgFile, NULL, &valuePtr)) { fileIdx = (int)mCeFunction->mFiles.size(); - mCeFunction->mFiles.Add(dbgFile->mFileName); + String filePath = dbgFile->mDirectory; + filePath.Append(DIR_SEP_CHAR); + filePath += dbgFile->mFileName; + mCeFunction->mFiles.Add(filePath); *valuePtr = fileIdx; } else @@ -1749,21 +2260,90 @@ void CeBuilder::Build() CeMachine::CeMachine(BfCompiler* compiler) { mCompiler = compiler; - mCeModule = NULL; - mStackMin = NULL; + mCeModule = NULL; mRevision = 0; + mExecuteId = 0; mCurTargetSrc = NULL; mCurModule = NULL; + mHeap = NULL; } CeMachine::~CeMachine() { delete mCeModule; + delete mHeap; + + for (auto kv : mFunctions) + { + auto functionInfo = kv.mValue; + delete functionInfo; + } } BfError* CeMachine::Fail(const CeFrame& curFrame, const StringImpl& str) { - return mCurModule->Fail(str, mCurTargetSrc); + auto bfError = mCurModule->Fail("Unable to const-evaluate function", mCurTargetSrc); + if (bfError == NULL) + return NULL; + + auto passInstance = mCompiler->mPassInstance; + + for (int stackIdx = mCallStack.size(); stackIdx >= 0; stackIdx--) + { + bool isHeadEntry = stackIdx == mCallStack.size(); + auto* ceFrame = (isHeadEntry) ? &curFrame : &mCallStack[stackIdx]; + + auto ceFunction = ceFrame->mFunction; + + int i = 0; + CeEmitEntry* emitEntry = NULL; + + if (!ceFunction->mCode.IsEmpty()) + { + int lo = 0; + int hi = ceFunction->mEmitTable.size() - 1; + int instIdx = ceFrame->mInstPtr - &ceFunction->mCode[0] - 1; + while (lo <= hi) + { + i = (lo + hi) / 2; + emitEntry = &ceFunction->mEmitTable.mVals[i]; + //int c = midVal <=> value; + if (emitEntry->mCodePos == instIdx) break; + if (emitEntry->mCodePos < instIdx) + lo = i + 1; + else + hi = i - 1; + } + if ((emitEntry != NULL) && (emitEntry->mCodePos > instIdx) && (i > 0)) + emitEntry = &ceFunction->mEmitTable.mVals[i - 1]; + } + + StringT<256> err; + if (isHeadEntry) + err = str; + else + { + StrFormat("in const evaluation of"); + err += mCeModule->MethodToString(ceFunction->mMethodInstance, BfMethodNameFlag_OmitParams); + //err += "("; + //err += ")"; + } + + if (emitEntry != NULL) + err += StrFormat(" at line% d:%d in %s", emitEntry->mLine + 1, emitEntry->mColumn + 1, ceFunction->mFiles[emitEntry->mFile].c_str()); + + auto moreInfo = passInstance->MoreInfo(err); + if ((moreInfo != NULL) && (emitEntry != NULL)) + { + BfErrorLocation* location = new BfErrorLocation(); + location->mFile = ceFunction->mFiles[emitEntry->mFile]; + location->mLine = emitEntry->mLine; + location->mColumn = emitEntry->mColumn; + moreInfo->mLocation = location; + } + } + + return bfError; } void CeMachine::Init() @@ -1783,6 +2363,30 @@ void CeMachine::Init() mCeModule->mWantsIRIgnoreWrites = false; } +uint8* CeMachine::CeMalloc(int size) +{ +#ifdef CE_ENABLE_HEAP + auto heapRef = mHeap->Alloc(size); + auto ceAddr = BF_CE_STACK_SIZE + heapRef; + int sizeDelta = (ceAddr + size) - mMemory.mSize; + if (sizeDelta > 0) + mMemory.GrowUninitialized(sizeDelta); + return mMemory.mVals + ceAddr; +#else + return mMemory.GrowUninitialized(size); +#endif +} + +bool CeMachine::CeFree(addr_ce addr) +{ +#ifdef CE_ENABLE_HEAP + ContiguousHeap::AllocRef heapRef = addr - BF_CE_STACK_SIZE; + return mHeap->Free(heapRef); +#else + return true; +#endif +} + BeContext* CeMachine::GetBeContext() { if (mCeModule == NULL) @@ -1807,14 +2411,44 @@ void CeMachine::CompileStarted() } } +void CeMachine::DerefMethodInfo(CeFunctionInfo* ceFunctionInfo) +{ + ceFunctionInfo->mRefCount--; + if (ceFunctionInfo->mRefCount > 0) + return; + BF_ASSERT(ceFunctionInfo->mMethodInstance == NULL); + + auto itr = mNamedFunctionMap.Find(ceFunctionInfo->mName); + if (itr->mValue == ceFunctionInfo) + mNamedFunctionMap.Remove(itr); + delete ceFunctionInfo; +} + void CeMachine::RemoveMethod(BfMethodInstance* methodInstance) { auto itr = mFunctions.Find(methodInstance); - auto ceFunction = itr->mValue; + auto ceFunctionInfo = itr->mValue; BF_ASSERT(itr != mFunctions.end()); if (itr != mFunctions.end()) - { - mNamedFunctionMap.Remove(ceFunction->mName); + { + auto ceFunction = ceFunctionInfo->mCeFunction; + for (auto& callEntry : ceFunction->mCallTable) + { + if (callEntry.mFunctionInfo != NULL) + DerefMethodInfo(callEntry.mFunctionInfo); + } + delete ceFunction; + ceFunctionInfo->mCeFunction = NULL; + ceFunctionInfo->mMethodInstance = NULL; + + if (ceFunctionInfo->mRefCount > 1) + { + // Generate a methodref + ceFunctionInfo->mMethodRef = methodInstance; + } + + DerefMethodInfo(ceFunctionInfo); + mFunctions.Remove(itr); } } @@ -1888,15 +2522,21 @@ void CeMachine::WriteConstant(uint8* ptr, BfConstant* constant) } } #define CE_CHECKSTACK() \ - if (stackPtr < mStackMin) \ + if (stackPtr < memStart) \ { \ _Fail("Stack overflow"); \ return false; \ } +#define CE_CHECKALLOC(SIZE) \ + if ((uintptr)memSize + (uintptr)SIZE > BF_CE_MAX_MEMORY) \ + { \ + _Fail("Maximum memory size exceeded"); \ + } + // This check will fail for addresses < 64K (null pointer), or out-of-bounds #define CE_CHECKADDR(ADDR, SIZE) \ - if (((ADDR) - 0x10000) + sizeof(uint32) > (BF_CE_STACK_SIZE - 0x10000)) \ + if (((ADDR) - 0x10000) + (SIZE) > (memSize - 0x10000)) \ { \ _Fail("Access violation"); \ return false; \ @@ -1911,6 +2551,25 @@ void CeMachine::WriteConstant(uint8* ptr, BfConstant* constant) auto rhs = CE_GETFRAME(T); \ result = lhs OP rhs; \ } +#define CEOP_BIN_DIV(OP, T) \ + { \ + auto& result = CE_GETFRAME(T); \ + auto lhs = CE_GETFRAME(T); \ + auto rhs = CE_GETFRAME(T); \ + if (rhs == 0) \ + { \ + _Fail("Division by zero"); \ + return false; \ + } \ + result = lhs OP rhs; \ + } +#define CEOP_BIN2(OP, TLHS, TRHS) \ + { \ + auto& result = CE_GETFRAME(TLHS); \ + auto lhs = CE_GETFRAME(TLHS); \ + auto rhs = CE_GETFRAME(TRHS); \ + result = lhs OP rhs; \ + } #define CEOP_BIN_CONST(OP, T) \ { \ auto& result = CE_GETFRAME(T); \ @@ -1940,14 +2599,14 @@ void CeMachine::WriteConstant(uint8* ptr, BfConstant* constant) #define CE_LOAD(T) \ { \ auto& result = CE_GETFRAME(T); \ - auto ceAddr = CE_GETFRAME(uint32); \ + auto ceAddr = CE_GETFRAME(addr_ce); \ CE_CHECKADDR(ceAddr, sizeof(T)); \ result = *(T*)(memStart + ceAddr); \ } #define CE_STORE(T) \ { \ auto val = CE_GETFRAME(T); \ - auto ceAddr = CE_GETFRAME(uint32); \ + auto ceAddr = CE_GETFRAME(addr_ce); \ CE_CHECKADDR(ceAddr, sizeof(T)); \ *(T*)(memStart + ceAddr) = val; \ } @@ -1970,11 +2629,26 @@ void CeMachine::WriteConstant(uint8* ptr, BfConstant* constant) result = *((T*)stackPtr); \ stackPtr += sizeof(T); \ } +#define CE_CALL(CEFUNC) \ + if (CEFUNC == NULL) \ + { \ + _Fail("Unable to locate function entry"); \ + return false; \ + } \ + mCallStack.Add(_GetCurFrame()); \ + ceFunction = CEFUNC; \ + framePtr = stackPtr; \ + stackPtr -= ceFunction->mFrameSize; \ + instPtr = &ceFunction->mCode[0]; \ + CE_CHECKSTACK(); bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* startFramePtr) -{ +{ + mExecuteId++; + CeFunction* ceFunction = startFunction; uint8* memStart = &mMemory[0]; + int memSize = mMemory.mSize; uint8* instPtr = (ceFunction->mCode.IsEmpty()) ? NULL : &ceFunction->mCode[0]; uint8* stackPtr = startStackPtr; uint8* framePtr = startFramePtr; @@ -1983,34 +2657,134 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* { CeFrame ceFrame; ceFrame.mFunction = ceFunction; - ceFrame.mFramePtr = framePtr; - ceFrame.mStackPtr = stackPtr; + ceFrame.mFrameAddr = framePtr - memStart; + ceFrame.mStackAddr = stackPtr - memStart; ceFrame.mInstPtr = instPtr; return ceFrame; }; + auto _FixVariables = [&]() + { + memSize = mMemory.mSize; + intptr memOffset = &mMemory[0] - memStart; + if (memOffset == 0) + return; + memStart += memOffset; + stackPtr += memOffset; + framePtr += memOffset; + }; + auto _Fail = [&](const StringImpl& error) { Fail(_GetCurFrame(), error); }; - auto _CheckFunction = [&](CeFunction* checkFunction) + auto _CheckFunction = [&](CeFunction* checkFunction, bool& handled) { + if (checkFunction == NULL) + { + Fail(_GetCurFrame(), "Const method not available"); + return false; + } + if (checkFunction->mFunctionKind == CeFunctionKind_OOB) + { + Fail(_GetCurFrame(), "Array out of bounds"); + return false; + } + else if (checkFunction->mFunctionKind == CeFunctionKind_DebugWrite) + { + int32 ptrVal = *(int32*)((uint8*)stackPtr + 0); + auto size = *(int32*)(stackPtr + mCeModule->mSystem->mPtrSize); + CE_CHECKADDR(ptrVal, size); + char* strPtr = (char*)(ptrVal + memStart); + String str; + str.Insert(0, strPtr, size); + OutputDebugStr(str); + handled = true; + return true; + } + else if (checkFunction->mFunctionKind == CeFunctionKind_DebugWrite_Int) + { + int32 intVal = *(int32*)((uint8*)stackPtr + 0); + OutputDebugStrF("Debug Val: %d\n", intVal); + handled = true; + return true; + } + else if (checkFunction->mFunctionKind == CeFunctionKind_FatalError) + { + int32 strInstAddr = *(int32*)((uint8*)stackPtr + 0); + CE_CHECKADDR(strInstAddr, 0); + + BfTypeInstance* stringTypeInst = (BfTypeInstance*)mCeModule->ResolveTypeDef(mCompiler->mStringTypeDef, BfPopulateType_Data); + + auto lenByteCount = stringTypeInst->mFieldInstances[0].mResolvedType->mSize; + auto lenOffset = stringTypeInst->mFieldInstances[0].mDataOffset; + auto allocSizeOffset = stringTypeInst->mFieldInstances[1].mDataOffset; + auto ptrOffset = stringTypeInst->mFieldInstances[2].mDataOffset; + + uint8* strInst = (uint8*)(strInstAddr + memStart); + int32 lenVal = *(int32*)(strInst + lenOffset); + + char* charPtr = NULL; + + if (lenByteCount == 4) + { + int32 allocSizeVal = *(int32*)(strInst + allocSizeOffset); + if ((allocSizeVal & 0x40000000) != 0) + { + int32 ptrVal = *(int32*)(strInst + ptrOffset); + charPtr = (char*)(ptrVal + memStart); + } + else + { + charPtr = (char*)(strInst + ptrOffset); + } + } + + int32 ptrVal = *(int32*)(strInst + ptrOffset); + + String error = "Fatal Error: "; + if (charPtr != NULL) + error.Insert(error.length(), charPtr, lenVal); + _Fail(error); + + return false; + } + else if (checkFunction->mFunctionKind != CeFunctionKind_Normal) + { + Fail(_GetCurFrame(), StrFormat("Unable to invoke extern method '%s'", mCeModule->MethodToString(checkFunction->mMethodInstance).c_str())); + return false; + } + if (!checkFunction->mFailed) return true; auto error = Fail(_GetCurFrame(), "Method call failed"); if ((error != NULL) && (!checkFunction->mGenError.IsEmpty())) - mCeModule->mCompiler->mPassInstance->MoreInfo("Const Method Generation Error: " + checkFunction->mGenError); + mCompiler->mPassInstance->MoreInfo("Const Method Generation Error: " + checkFunction->mGenError); return false; }; + + // + { + bool handled = false; + if (!_CheckFunction(ceFunction, handled)) + return false; + if (handled) + return true; + } - if (!_CheckFunction(ceFunction)) - return false; + volatile bool* cancelPtr = &mCompiler->mCanceling; int callCount = 0; while (true) { + if (*cancelPtr) + { + _Fail("Cancelled"); + return false; + } + CeOp op = CE_GETINST(CeOp); switch (op) { @@ -2022,8 +2796,8 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* auto& ceFrame = mCallStack.back(); ceFunction = ceFrame.mFunction; instPtr = ceFrame.mInstPtr; - stackPtr = ceFrame.mStackPtr; - framePtr = ceFrame.mFramePtr; + stackPtr = memStart + ceFrame.mStackAddr; + framePtr = memStart + ceFrame.mFrameAddr; mCallStack.pop_back(); } @@ -2050,6 +2824,138 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* instPtr += relOfs - 4; } break; + case CeOp_Error: + { + auto errorKind = (CeErrorKind)CE_GETINST(int32); + switch (errorKind) + { + case CeErrorKind_GlobalVariable: + _Fail("Global variable access not allowed"); + break; + case CeErrorKind_FunctionPointer: + _Fail("Function pointer calls not allowed"); + break; + case CeErrorKind_Intrinsic: + _Fail("Intrinsic not allowed"); + break; + default: + _Fail("Operation not allowed"); + break; + } + } + break; + case CeOp_DynamicCastCheck: + { + auto& result = CE_GETFRAME(uint32); + auto valueAddr = CE_GETFRAME(addr_ce); + int32 ifaceId = CE_GETINST(int32); + + CE_CHECKADDR(valueAddr, sizeof(int32)); + + auto ifaceType = mCeModule->mContext->mTypes[ifaceId]; + int32 objTypeId = *(int32*)(memStart + valueAddr); + auto valueType = mCeModule->mContext->mTypes[objTypeId]; + if (mCeModule->TypeIsSubTypeOf(valueType->ToTypeInstance(), ifaceType->ToTypeInstance(), false)) + result = valueAddr; + else + result = 0; + } + break; + case CeOp_GetString: + { + auto frameOfs = CE_GETINST(int32); + auto stringTableIdx = CE_GETINST(int32); + auto& ceStringEntry = ceFunction->mStringTable[stringTableIdx]; + if (ceStringEntry.mBindExecuteId != mExecuteId) + { + addr_ce* ceAddrPtr = NULL; + if (mStringMap.TryAdd(ceStringEntry.mStringId, NULL, &ceAddrPtr)) + { + String str; + BfStringPoolEntry* entry = NULL; + if (mCeModule->mContext->mStringObjectIdMap.TryGetValue(ceStringEntry.mStringId, &entry)) + { + str = entry->mString; + } + + BfTypeInstance* stringTypeInst = (BfTypeInstance*)mCeModule->ResolveTypeDef(mCompiler->mStringTypeDef, BfPopulateType_Data); + + int allocSize = stringTypeInst->mInstSize + (int)str.length() + 1; + int charsOffset = stringTypeInst->mInstSize; + + CE_CHECKALLOC(allocSize); + uint8* mem = CeMalloc(allocSize); + _FixVariables(); + + memset(mem, 0, allocSize); + + auto lenByteCount = stringTypeInst->mFieldInstances[0].mResolvedType->mSize; + auto lenOffset = stringTypeInst->mFieldInstances[0].mDataOffset; + auto allocSizeOffset = stringTypeInst->mFieldInstances[1].mDataOffset; + auto ptrOffset = stringTypeInst->mFieldInstances[2].mDataOffset; + + // Write TypeId into there + *(int32*)(mem) = stringTypeInst->mTypeId; + *(int32*)(mem + lenOffset) = (int)str.length(); + if (lenByteCount == 4) + *(int32*)(mem + allocSizeOffset) = 0x40000000 + (int)str.length() + 1; + else + *(int64*)(mem + allocSizeOffset) = 0x4000000000000000LL + (int)str.length() + 1; + *(int32*)(mem + ptrOffset) = (mem + charsOffset) - memStart; + memcpy(mem + charsOffset, str.c_str(), str.length()); + + *ceAddrPtr = mem - memStart; + } + + ceStringEntry.mStringAddr = *ceAddrPtr; + ceStringEntry.mBindExecuteId = mExecuteId; + } + + *(addr_ce*)(framePtr + frameOfs) = ceStringEntry.mStringAddr; + } + break; + case CeOp_Malloc: + { + auto frameOfs = CE_GETINST(int32); + int32 size = CE_GETFRAME(int32); + CE_CHECKALLOC(size); + uint8* mem = CeMalloc(size); + _FixVariables(); + *(addr_ce*)(framePtr + frameOfs) = mem - memStart; + } + break; + case CeOp_Free: + { + auto freeAddr = CE_GETFRAME(addr_ce); + bool success = CeFree(freeAddr); + if (!success) + _Fail("Invalid heap address"); + } + break; + case CeOp_MemSet: + { + auto destAddr = CE_GETFRAME(addr_ce); + uint8 setValue = CE_GETFRAME(uint8); + int32 setSize = CE_GETFRAME(int32); + memset(memStart + destAddr, setValue, setSize); + } + break; + case CeOp_MemSet_Const: + { + auto destAddr = CE_GETFRAME(addr_ce); + uint8 setValue = CE_GETINST(uint8); + int32 setSize = CE_GETINST(int32); + memset(memStart + destAddr, setValue, setSize); + } + break; + case CeOp_MemCpy: + { + auto destAddr = CE_GETFRAME(addr_ce); + auto srcAddr = CE_GETFRAME(addr_ce); + int32 size = CE_GETFRAME(int32); + memcpy(memStart + destAddr, memStart + srcAddr, size); + } + break; case CeOp_FrameAddr_64: { auto& result = CE_GETFRAME(int64); @@ -2096,18 +3002,39 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* instPtr += constSize; } break; + case CeOp_Load_8: + CE_LOAD(uint8); + break; + case CeOp_Load_16: + CE_LOAD(uint16); + break; case CeOp_Load_32: - CE_LOAD(uint32); + CE_LOAD(uint32); break; case CeOp_Load_64: CE_LOAD(uint64); break; + case CeOp_Store_8: + CE_STORE(uint8); + break; + case CeOp_Store_16: + CE_STORE(uint16); + break; case CeOp_Store_32: CE_STORE(uint32); break; case CeOp_Store_64: CE_STORE(uint64); break; + case CeOp_Store_X: + { + auto size = CE_GETINST(int32); + auto srcPtr = &CE_GETFRAME(uint8); + auto ceAddr = CE_GETFRAME(addr_ce); + CE_CHECKADDR(ceAddr, size); + memcpy(memStart + ceAddr, srcPtr, size); + } + break; case CeOp_Move_8: CEOP_MOVE(int8); break; @@ -2153,11 +3080,35 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* CEOP_POP(int64); break; case CeOp_AdjustSP: + { + int32 adjust = CE_GETFRAME(int32); + stackPtr += adjust; + } + break; + case CeOp_AdjustSPNeg: + { + int32 adjust = CE_GETFRAME(int32); + stackPtr -= adjust; + } + break; + case CeOp_AdjustSPConst: { int32 adjust = CE_GETINST(int32); stackPtr += adjust; } break; + case CeOp_GetSP: + { + auto& result = CE_GETFRAME(int32); + result = stackPtr - memStart; + } + break; + case CeOp_SetSP: + { + auto addr = CE_GETFRAME(int32); + stackPtr = memStart + addr; + } + break; case CeOp_Call: { callCount++; @@ -2167,94 +3118,595 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* if (callEntry.mBindRevision != mRevision) { callEntry.mFunction = NULL; - mNamedFunctionMap.TryGetValue(callEntry.mFunctionName, &callEntry.mFunction); + //mNamedFunctionMap.TryGetValue(callEntry.mFunctionName, &callEntry.mFunction); + + if (callEntry.mFunctionInfo == NULL) + { + _Fail("Unable to locate function entry"); + break; + } - if ((callEntry.mFunction != NULL) && (!callEntry.mFunction->mInitialized)) + if ((callEntry.mFunctionInfo->mCeFunction == NULL) && (!callEntry.mFunctionInfo->mMethodRef.IsNull())) + { + auto methodRef = callEntry.mFunctionInfo->mMethodRef; + auto methodDef = methodRef.mTypeInstance->mTypeDef->mMethods[methodRef.mMethodNum]; + auto moduleMethodInstance = mCeModule->GetMethodInstance(methodRef.mTypeInstance, methodDef, + methodRef.mMethodGenericArguments); + + if (moduleMethodInstance) + { + QueueMethod(moduleMethodInstance.mMethodInstance, moduleMethodInstance.mFunc); + } + } + + if (callEntry.mFunctionInfo->mCeFunction == NULL) + { + _Fail("Method not generated"); + break; + } + + callEntry.mFunction = callEntry.mFunctionInfo->mCeFunction; + if (!callEntry.mFunction->mInitialized) { PrepareFunction(callEntry.mFunction); } - if (!_CheckFunction(callEntry.mFunction)) - return false; + bool handled = false; + if (!_CheckFunction(callEntry.mFunction, handled)) + return false; + if (handled) + break; callEntry.mBindRevision = mRevision; } - if (callEntry.mFunction == NULL) - { - _Fail("Unable to locate function entry"); - break; - } + CE_CALL(callEntry.mFunction); + // if (callEntry.mFunction->mName.Contains("__static_dump")) // { // int32 val = *(int32*)(stackPtr); // OutputDebugStrF("__static_dump: %d\n", val); -// } - - if (callEntry.mFunction != NULL) - { - mCallStack.Add(_GetCurFrame()); - - ceFunction = callEntry.mFunction; - framePtr = stackPtr; - stackPtr -= ceFunction->mFrameSize; - instPtr = &ceFunction->mCode[0]; - CE_CHECKSTACK(); - } +// } } break; + case CeOp_Call_Virt: + { + auto valueAddr = CE_GETFRAME(addr_ce); + int32 virtualIdx = CE_GETINST(int32); + + CE_CHECKADDR(valueAddr, sizeof(int32)); + int32 objTypeId = *(int32*)(memStart + valueAddr); + auto valueType = mCeModule->mContext->mTypes[objTypeId]->ToTypeInstance(); + if (valueType->mVirtualMethodTable.IsEmpty()) + mCeModule->PopulateType(valueType, BfPopulateType_DataAndMethods); + auto methodInstance = (BfMethodInstance*)valueType->mVirtualMethodTable[virtualIdx].mImplementingMethod; + + auto callFunction = GetPreparedFunction(methodInstance); + CE_CALL(callFunction); + } + break; + case CeOp_Conv_I8_I16: + CE_CAST(int8, int16); + break; + case CeOp_Conv_I8_I32: + CE_CAST(int8, int32); + break; + case CeOp_Conv_I8_I64: + CE_CAST(int8, int64); + break; + case CeOp_Conv_I8_F32: + CE_CAST(int8, float); + break; + case CeOp_Conv_I8_F64: + CE_CAST(int8, double); + break; + case CeOp_Conv_I16_I32: + CE_CAST(int16, int32); + break; + case CeOp_Conv_I16_I64: + CE_CAST(int16, int64); + break; + case CeOp_Conv_I16_F32: + CE_CAST(int16, float); + break; + case CeOp_Conv_I16_F64: + CE_CAST(int16, double); + break; case CeOp_Conv_I32_I64: CE_CAST(int32, int64); break; + case CeOp_Conv_I32_F32: + CE_CAST(int32, float); + break; + case CeOp_Conv_I32_F64: + CE_CAST(int32, double); + break; + case CeOp_Conv_I64_F32: + CE_CAST(int64, float); + break; + case CeOp_Conv_I64_F64: + CE_CAST(int64, double); + break; + case CeOp_Conv_U8_U16: + CE_CAST(uint8, uint16); + break; + case CeOp_Conv_U8_U32: + CE_CAST(uint8, uint32); + break; + case CeOp_Conv_U8_U64: + CE_CAST(uint8, uint64); + break; + case CeOp_Conv_U8_F32: + CE_CAST(uint8, float); + break; + case CeOp_Conv_U8_F64: + CE_CAST(uint8, double); + break; + case CeOp_Conv_U16_U32: + CE_CAST(uint16, uint32); + break; + case CeOp_Conv_U16_U64: + CE_CAST(uint16, uint64); + break; + case CeOp_Conv_U16_F32: + CE_CAST(uint16, float); + break; + case CeOp_Conv_U16_F64: + CE_CAST(uint16, double); + break; + case CeOp_Conv_U32_U64: + CE_CAST(uint32, uint64); + break; + case CeOp_Conv_U32_F32: + CE_CAST(uint32, float); + break; + case CeOp_Conv_U32_F64: + CE_CAST(uint32, double); + break; + case CeOp_Conv_U64_F32: + CE_CAST(uint64, float); + break; + case CeOp_Conv_U64_F64: + CE_CAST(uint64, double); + break; + case CeOp_Conv_F32_I8: + CE_CAST(float, int8); + break; + case CeOp_Conv_F32_I16: + CE_CAST(float, int16); + break; + case CeOp_Conv_F32_I32: + CE_CAST(float, int32); + break; + case CeOp_Conv_F32_I64: + CE_CAST(float, int64); + break; + case CeOp_Conv_F32_F64: + CE_CAST(float, double); + break; + case CeOp_Conv_F64_I8: + CE_CAST(double, int8); + break; + case CeOp_Conv_F64_I16: + CE_CAST(double, int16); + break; + case CeOp_Conv_F64_I32: + CE_CAST(double, int32); + break; + case CeOp_Conv_F64_I64: + CE_CAST(double, int64); + break; + case CeOp_Conv_F64_F32: + CE_CAST(double, float); + break; + case CeOp_AddConst_I8: + CEOP_BIN_CONST(+, int8); + break; + case CeOp_AddConst_I16: + CEOP_BIN_CONST(+, int16); + break; case CeOp_AddConst_I32: CEOP_BIN_CONST(+, int32); break; case CeOp_AddConst_I64: CEOP_BIN_CONST(+, int64); break; + case CeOp_Add_I8: + CEOP_BIN(+, int8); + break; + case CeOp_Add_I16: + CEOP_BIN(+, int16); + break; case CeOp_Add_I32: CEOP_BIN(+, int32); break; case CeOp_Add_I64: CEOP_BIN(+, int64); break; + case CeOp_Add_F32: + CEOP_BIN(+, float); + break; + case CeOp_Add_F64: + CEOP_BIN(+, double); + break; + case CeOp_Sub_I8: + CEOP_BIN(-, int8); + break; + case CeOp_Sub_I16: + CEOP_BIN(-, int16); + break; case CeOp_Sub_I32: CEOP_BIN(-, int32); break; case CeOp_Sub_I64: CEOP_BIN(-, int64); break; + case CeOp_Sub_F32: + CEOP_BIN(-, float); + break; + case CeOp_Sub_F64: + CEOP_BIN(-, double); + break; + case CeOp_Mul_I8: + CEOP_BIN(*, int8); + break; + case CeOp_Mul_I16: + CEOP_BIN(*, int16); + break; case CeOp_Mul_I32: CEOP_BIN(*, int32); break; case CeOp_Mul_I64: CEOP_BIN(*, int64); break; + case CeOp_Mul_F32: + CEOP_BIN(*, float); + break; + case CeOp_Mul_F64: + CEOP_BIN(*, double); + break; + case CeOp_Div_I8: + CEOP_BIN_DIV(/, int8); + break; + case CeOp_Div_I16: + CEOP_BIN_DIV(/, int16); + break; + case CeOp_Div_I32: + CEOP_BIN_DIV(/, int32); + break; + case CeOp_Div_I64: + CEOP_BIN_DIV(/, int64); + break; + case CeOp_Div_F32: + CEOP_BIN_DIV(/, float); + break; + case CeOp_Div_F64: + CEOP_BIN_DIV(/, double); + break; + case CeOp_Div_U8: + CEOP_BIN_DIV(/, uint8); + break; + case CeOp_Div_U16: + CEOP_BIN_DIV(/, uint16); + break; + case CeOp_Div_U32: + CEOP_BIN_DIV(/, uint32); + break; + case CeOp_Div_U64: + CEOP_BIN_DIV(/, uint64); + break; + case CeOp_Mod_I8: + CEOP_BIN_DIV(%, int8); + break; + case CeOp_Mod_I16: + CEOP_BIN_DIV(%, int16); + break; + case CeOp_Mod_I32: + CEOP_BIN_DIV(%, int32); + break; + case CeOp_Mod_I64: + CEOP_BIN_DIV(%, int64); + break; + case CeOp_Mod_F32: + { + auto& result = CE_GETFRAME(float); + auto lhs = CE_GETFRAME(float); + auto rhs = CE_GETFRAME(float); + if (rhs == 0) + { + _Fail("Division by zero"); + return false; + } + result = fmodf(lhs, rhs); + } + break; + case CeOp_Mod_F64: + { + auto& result = CE_GETFRAME(double); + auto lhs = CE_GETFRAME(double); + auto rhs = CE_GETFRAME(double); + if (rhs == 0) + { + _Fail("Division by zero"); + return false; + } + result = fmod(lhs, rhs); + } + break; + case CeOp_Mod_U8: + CEOP_BIN_DIV(%, uint8); + break; + case CeOp_Mod_U16: + CEOP_BIN_DIV(%, uint16); + break; + case CeOp_Mod_U32: + CEOP_BIN_DIV(%, uint32); + break; + case CeOp_Mod_U64: + CEOP_BIN_DIV(%, uint64); + break; + + case CeOp_And_I8: + CEOP_BIN(&, uint8); + break; + case CeOp_And_I16: + CEOP_BIN(&, uint16); + break; + case CeOp_And_I32: + CEOP_BIN(&, uint32); + break; + case CeOp_And_I64: + CEOP_BIN(&, uint64); + break; + case CeOp_Or_I8: + CEOP_BIN(|, uint8); + break; + case CeOp_Or_I16: + CEOP_BIN(|, uint16); + break; + case CeOp_Or_I32: + CEOP_BIN(|, uint32); + break; + case CeOp_Or_I64: + CEOP_BIN(|, uint64); + break; + case CeOp_Xor_I8: + CEOP_BIN(^, uint8); + break; + case CeOp_Xor_I16: + CEOP_BIN(^, uint16); + break; + case CeOp_Xor_I32: + CEOP_BIN(^, uint32); + break; + case CeOp_Xor_I64: + CEOP_BIN(^, uint64); + break; + case CeOp_Shl_I8: + CEOP_BIN2(<<, int8, uint8); + break; + case CeOp_Shl_I16: + CEOP_BIN2(<<, int16, uint8); + break; + case CeOp_Shl_I32: + CEOP_BIN2(<<, int32, uint8); + break; + case CeOp_Shl_I64: + CEOP_BIN2(<<, int64, uint8); + break; + case CeOp_Shr_I8: + CEOP_BIN2(>>, int8, uint8); + break; + case CeOp_Shr_I16: + CEOP_BIN2(>>, int16, uint8); + break; + case CeOp_Shr_I32: + CEOP_BIN2(>>, int32, uint8); + break; + case CeOp_Shr_I64: + CEOP_BIN2(>>, int64, uint8); + break; + case CeOp_Shr_U8: + CEOP_BIN2(>>, uint8, uint8); + break; + case CeOp_Shr_U16: + CEOP_BIN2(>>, uint16, uint8); + break; + case CeOp_Shr_U32: + CEOP_BIN2(>>, uint32, uint8); + break; + case CeOp_Shr_U64: + CEOP_BIN2(>>, uint64, uint8); + break; + case CeOp_Cmp_NE_I8: + CEOP_CMP(!= , int8); + break; + case CeOp_Cmp_NE_I16: + CEOP_CMP(!= , int16); + break; + case CeOp_Cmp_NE_I32: + CEOP_CMP(!=, int32); + break; + case CeOp_Cmp_NE_I64: + CEOP_CMP(!=, int64); + break; + case CeOp_Cmp_NE_F32: + CEOP_CMP(!= , float); + break; + case CeOp_Cmp_NE_F64: + CEOP_CMP(!= , double); + break; + case CeOp_Cmp_EQ_I8: + CEOP_CMP(==, int8); + break; + case CeOp_Cmp_EQ_I16: + CEOP_CMP(==, int16); + break; case CeOp_Cmp_EQ_I32: CEOP_CMP(==, int32); break; + case CeOp_Cmp_EQ_I64: + CEOP_CMP(==, int64); + break; + case CeOp_Cmp_EQ_F32: + CEOP_CMP(== , float); + break; + case CeOp_Cmp_EQ_F64: + CEOP_CMP(== , double); + break; + case CeOp_Cmp_SLT_I8: + CEOP_CMP(< , int8); + break; + case CeOp_Cmp_SLT_I16: + CEOP_CMP(< , int16); + break; case CeOp_Cmp_SLT_I32: CEOP_CMP(<, int32); break; + case CeOp_Cmp_SLT_I64: + CEOP_CMP(<, int64); + break; + case CeOp_Cmp_SLT_F32: + CEOP_CMP(<, float); + break; + case CeOp_Cmp_SLT_F64: + CEOP_CMP(< , double); + break; + case CeOp_Cmp_ULT_I8: + CEOP_CMP(<, uint8); + break; + case CeOp_Cmp_ULT_I16: + CEOP_CMP(<, uint16); + break; case CeOp_Cmp_ULT_I32: CEOP_CMP(<, uint32); break; + case CeOp_Cmp_ULT_I64: + CEOP_CMP(<, uint64); + break; + case CeOp_Cmp_SLE_I8: + CEOP_CMP(<=, int8); + break; + case CeOp_Cmp_SLE_I16: + CEOP_CMP(<=, int16); + break; case CeOp_Cmp_SLE_I32: CEOP_CMP(<=, int32); break; case CeOp_Cmp_SLE_I64: - CEOP_CMP(<= , int64); + CEOP_CMP(<=, int64); + break; + case CeOp_Cmp_SLE_F32: + CEOP_CMP(<= , float); + break; + case CeOp_Cmp_SLE_F64: + CEOP_CMP(<= , double); + break; + case CeOp_Cmp_ULE_I8: + CEOP_CMP(<=, uint8); + break; + case CeOp_Cmp_ULE_I16: + CEOP_CMP(<=, uint16); break; case CeOp_Cmp_ULE_I32: CEOP_CMP(<=, uint32); break; + case CeOp_Cmp_ULE_I64: + CEOP_CMP(<=, uint64); + break; + case CeOp_Cmp_SGT_I8: + CEOP_CMP(>, int8); + break; + case CeOp_Cmp_SGT_I16: + CEOP_CMP(>, int16); + break; + case CeOp_Cmp_SGT_I32: + CEOP_CMP(>, int32); + break; + case CeOp_Cmp_SGT_I64: + CEOP_CMP(>, int64); + break; + case CeOp_Cmp_SGT_F32: + CEOP_CMP(>, float); + break; + case CeOp_Cmp_SGT_F64: + CEOP_CMP(>, double); + break; + case CeOp_Cmp_UGT_I8: + CEOP_CMP(>, uint8); + break; + case CeOp_Cmp_UGT_I16: + CEOP_CMP(>, uint16); + break; + case CeOp_Cmp_UGT_I32: + CEOP_CMP(>, uint32); + break; + case CeOp_Cmp_UGT_I64: + CEOP_CMP(>, uint64); + break; + case CeOp_Cmp_SGE_I8: + CEOP_CMP(>=, int8); + break; + case CeOp_Cmp_SGE_I16: + CEOP_CMP(>=, int16); + break; + case CeOp_Cmp_SGE_I32: + CEOP_CMP(>=, int32); + break; + case CeOp_Cmp_SGE_I64: + CEOP_CMP(>=, int64); + break; + case CeOp_Cmp_SGE_F32: + CEOP_CMP(>=, float); + break; + case CeOp_Cmp_SGE_F64: + CEOP_CMP(>=, double); + break; + case CeOp_Cmp_UGE_I8: + CEOP_CMP(>=, uint8); + break; + case CeOp_Cmp_UGE_I16: + CEOP_CMP(>=, uint16); + break; + case CeOp_Cmp_UGE_I32: + CEOP_CMP(>=, uint32); + break; + case CeOp_Cmp_UGE_I64: + CEOP_CMP(>=, uint64); + break; + case CeOp_Neg_I8: + CEOP_UNARY(-, int8); + break; + case CeOp_Neg_I16: + CEOP_UNARY(-, int16); + break; case CeOp_Neg_I32: CEOP_UNARY(-, int32); break; case CeOp_Neg_I64: CEOP_UNARY(-, int64); break; + case CeOp_Neg_F32: + CEOP_UNARY(-, float); + case CeOp_Neg_F64: + CEOP_UNARY(-, double); + break; + case CeOp_Not_I1: + CEOP_UNARY(!, bool); + break; + case CeOp_Not_I8: + CEOP_UNARY(~, int8); + break; + case CeOp_Not_I16: + CEOP_UNARY(~, int16); + break; + case CeOp_Not_I32: + CEOP_UNARY(~, int32); + break; + case CeOp_Not_I64: + CEOP_UNARY(~, int64); + break; default: _Fail("Unhandled op"); return false; @@ -2265,9 +3717,39 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* } void CeMachine::PrepareFunction(CeFunction* ceFunction) -{ - if (mCeModule == NULL) - Init(); +{ + auto methodDef = ceFunction->mMethodInstance->mMethodDef; + if (methodDef->mIsExtern) + { + ceFunction->mFunctionKind = CeFunctionKind_Extern; + + auto owner = ceFunction->mMethodInstance->GetOwner(); + if (owner->IsInstanceOf(mCeModule->mCompiler->mDiagnosticsDebugTypeDef)) + { + if (methodDef->mName == "Write") + { + if (ceFunction->mMethodInstance->GetParamCount() == 1) + ceFunction->mFunctionKind = CeFunctionKind_DebugWrite_Int; + else + ceFunction->mFunctionKind = CeFunctionKind_DebugWrite; + } + + //MAKE CeFunctionKind_DebugWrite_Int + } + else if (owner->IsInstanceOf(mCeModule->mCompiler->mInternalTypeDef)) + { + if (methodDef->mName == "ThrowIndexOutOfRange") + { + ceFunction->mFunctionKind = CeFunctionKind_OOB; + } + else if (methodDef->mName == "FatalError") + { + ceFunction->mFunctionKind = CeFunctionKind_FatalError; + } + } + + return; + } BF_ASSERT(!ceFunction->mInitialized); ceFunction->mInitialized = true; @@ -2292,32 +3774,80 @@ void CeMachine::PrepareFunction(CeFunction* ceFunction) } CeFunction* CeMachine::GetFunction(BfMethodInstance* methodInstance, BfIRValue func, bool& added) -{ - CeFunction** functionValuePtr = NULL; +{ + if (func) + { + if ((func.IsConst()) || (func.IsFake())) + return NULL; + } + + CeFunctionInfo** functionInfoPtr = NULL; + CeFunctionInfo* ceFunctionInfo = NULL; CeFunction* ceFunction = NULL; - if (mFunctions.TryAdd(methodInstance, NULL, &functionValuePtr)) + if (!mFunctions.TryAdd(methodInstance, NULL, &functionInfoPtr)) + { + ceFunctionInfo = *functionInfoPtr; + BF_ASSERT(ceFunctionInfo->mCeFunction != NULL); + return ceFunctionInfo->mCeFunction; + } + + if (!func) + { + ceFunctionInfo = new CeFunctionInfo(); + } + else + { + auto funcVal = mCeModule->mBfIRBuilder->mBeIRCodeGen->GetBeValue(func.mId); + + if (auto function = BeValueDynCast(funcVal)) + { + CeFunctionInfo** namedFunctionInfoPtr = NULL; + if (mNamedFunctionMap.TryAdd(function->mName, NULL, &namedFunctionInfoPtr)) + { + ceFunctionInfo = new CeFunctionInfo(); + ceFunctionInfo->mName = function->mName; + *namedFunctionInfoPtr = ceFunctionInfo; + } + else + { + ceFunctionInfo = *namedFunctionInfoPtr; + } + } + else + { + ceFunctionInfo = new CeFunctionInfo(); + } + } + + ceFunctionInfo->mRefCount++; + *functionInfoPtr = ceFunctionInfo; + + if (ceFunctionInfo->mMethodInstance == NULL) { added = true; auto module = methodInstance->GetOwner()->mModule; BF_ASSERT(!methodInstance->mInCEMachine); - methodInstance->mInCEMachine = true; + methodInstance->mInCEMachine = true; ceFunction = new CeFunction(); - ceFunction->mMethodInstance = methodInstance; + ceFunction->mCeFunctionInfo = ceFunctionInfo; + ceFunction->mMethodInstance = methodInstance; - if ((func) && (!func.IsConst()) && (!func.IsFake())) - { - if (auto function = BeValueDynCast(mCeModule->mBfIRBuilder->mBeIRCodeGen->GetBeValue(func.mId))) - { - mNamedFunctionMap[function->mName] = ceFunction; - } - } - - *functionValuePtr = ceFunction; + ceFunctionInfo->mMethodInstance = methodInstance; + ceFunctionInfo->mCeFunction = ceFunction; } - else - ceFunction = *functionValuePtr; + return ceFunction; +} + +CeFunction* CeMachine::GetPreparedFunction(BfMethodInstance* methodInstance) +{ + bool added = false; + auto ceFunction = GetFunction(methodInstance, BfIRValue(), added); + if (ceFunction == NULL) + return NULL; + if (!ceFunction->mInitialized) + PrepareFunction(ceFunction); return ceFunction; } @@ -2327,6 +3857,11 @@ void CeMachine::QueueMethod(BfMethodInstance* methodInstance, BfIRValue func) auto ceFunction = GetFunction(methodInstance, func, added); } +void CeMachine::QueueMethod(BfModuleMethodInstance moduleMethodInstance) +{ + QueueMethod(moduleMethodInstance.mMethodInstance, moduleMethodInstance.mFunc); +} + BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodInstance* methodInstance, const BfSizedArray& args, CeEvalFlags flags) { // for (int argIdx = 0; argIdx < (int)args.size(); argIdx++) @@ -2351,14 +3886,20 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns return BfTypedValue(); } + if (mCeModule == NULL) + Init(); + bool added = false; CeFunction* ceFunction = GetFunction(methodInstance, BfIRValue(), added); if (!ceFunction->mInitialized) PrepareFunction(ceFunction); - + + if (mHeap == NULL) + mHeap = new ContiguousHeap(); mMemory.Resize(BF_CE_STACK_SIZE); - auto stackPtr = &mMemory[0] + mMemory.mSize; - mStackMin = &mMemory[0]; + + auto stackPtr = &mMemory[0] + mMemory.mSize; + auto* memStart = &mMemory[0]; for (int argIdx = (int)args.size() - 1; argIdx >= 0; argIdx--) { @@ -2375,26 +3916,28 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns WriteConstant(stackPtr, constant); } - uint8* retPtr = NULL; + addr_ce retAddr = 0; auto returnType = methodInstance->mReturnType; if (!returnType->IsValuelessType()) { int retSize = methodInstance->mReturnType->mSize; stackPtr -= retSize; - retPtr = stackPtr; + retAddr = stackPtr - memStart; } bool success = Execute(ceFunction, stackPtr - ceFunction->mFrameSize, stackPtr); - - mCallStack.Clear(); - + memStart = &mMemory[0]; + auto constHolder = module->mBfIRBuilder; + BfTypedValue returnValue; + if (success) { BfTypedValue retValue; - if (retPtr != NULL) + if (retAddr != 0) { + auto* retPtr = memStart + retAddr; BfIRValue constVal; if (returnType->IsPrimitiveType()) @@ -2441,13 +3984,18 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns } if (constVal) - return BfTypedValue(constVal, returnType); + returnValue = BfTypedValue(constVal, returnType); } else { - return BfTypedValue(module->mBfIRBuilder->GetFakeVal(), returnType); + returnValue = BfTypedValue(module->mBfIRBuilder->GetFakeVal(), returnType); } } + + mStringMap.Clear(); + mMemory.Clear(); + mCallStack.Clear(); + mHeap->Clear(); - return BfTypedValue(); + return returnValue; } diff --git a/IDEHelper/Compiler/CeMachine.h b/IDEHelper/Compiler/CeMachine.h index 990e6347..e3c02630 100644 --- a/IDEHelper/Compiler/CeMachine.h +++ b/IDEHelper/Compiler/CeMachine.h @@ -2,6 +2,8 @@ #include "BfSystem.h" #include "BfModule.h" +#include "BeefySysLib/util/Heap.h" +#include "BeefySysLib/util/AllocDebug.h" NS_BF_BEGIN @@ -19,6 +21,8 @@ class BeSwitchInst; class CeMachine; class CeFunction; +typedef int addr_ce; + #define CEOP_SIZED(OPNAME) \ CeOp_##OPNAME##_8, \ CeOp_##OPNAME##_16, \ @@ -32,6 +36,12 @@ class CeFunction; CeOp_##OPNAME##_I32, \ CeOp_##OPNAME##_I64 +#define CEOP_SIZED_UNUMERIC(OPNAME) \ + CeOp_##OPNAME##_U8, \ + CeOp_##OPNAME##_U16, \ + CeOp_##OPNAME##_U32, \ + CeOp_##OPNAME##_U64 + #define CEOP_SIZED_NUMERIC_PLUSF(OPNAME) \ CeOp_##OPNAME##_I8, \ CeOp_##OPNAME##_I16, \ @@ -40,6 +50,14 @@ class CeFunction; CeOp_##OPNAME##_F32, \ CeOp_##OPNAME##_F64 +enum CeErrorKind +{ + CeErrorKind_None, + CeErrorKind_GlobalVariable, + CeErrorKind_FunctionPointer, + CeErrorKind_Intrinsic +}; + enum CeOp : int16 { CeOp_InvalidOp, @@ -48,6 +66,16 @@ enum CeOp : int16 CeOp_JmpIf, CeOp_JmpIfNot, + CeOp_Error, + CeOp_DynamicCastCheck, + CeOp_GetString, + CeOp_Malloc, + CeOp_Free, + + CeOp_MemSet, + CeOp_MemSet_Const, + CeOp_MemCpy, + CeOp_FrameAddr_32, CeOp_FrameAddr_64, @@ -60,25 +88,82 @@ enum CeOp : int16 CEOP_SIZED(Pop), CeOp_AdjustSP, + CeOp_AdjustSPNeg, + CeOp_AdjustSPConst, + CeOp_GetSP, + CeOp_SetSP, CeOp_Call, - + CeOp_Call_Virt, + CeOp_Call_IFace, + + CeOp_Conv_I8_I16, + CeOp_Conv_I8_I32, + CeOp_Conv_I8_I64, + CeOp_Conv_I8_F32, + CeOp_Conv_I8_F64, + CeOp_Conv_I16_I32, + CeOp_Conv_I16_I64, + CeOp_Conv_I16_F32, + CeOp_Conv_I16_F64, CeOp_Conv_I32_I64, + CeOp_Conv_I32_F32, + CeOp_Conv_I32_F64, + CeOp_Conv_I64_F32, + CeOp_Conv_I64_F64, + CeOp_Conv_U8_U16, + CeOp_Conv_U8_U32, + CeOp_Conv_U8_U64, + CeOp_Conv_U8_F32, + CeOp_Conv_U8_F64, + CeOp_Conv_U16_U32, + CeOp_Conv_U16_U64, + CeOp_Conv_U16_F32, + CeOp_Conv_U16_F64, + CeOp_Conv_U32_U64, + CeOp_Conv_U32_F32, + CeOp_Conv_U32_F64, + CeOp_Conv_U64_F32, + CeOp_Conv_U64_F64, + CeOp_Conv_F32_I8, + CeOp_Conv_F32_I16, + CeOp_Conv_F32_I32, + CeOp_Conv_F32_I64, + CeOp_Conv_F32_F64, + CeOp_Conv_F64_I8, + CeOp_Conv_F64_I16, + CeOp_Conv_F64_I32, + CeOp_Conv_F64_I64, + CeOp_Conv_F64_F32, CEOP_SIZED_NUMERIC_PLUSF(AddConst), CEOP_SIZED_NUMERIC_PLUSF(Add), CEOP_SIZED_NUMERIC_PLUSF(Sub), CEOP_SIZED_NUMERIC_PLUSF(Mul), - CEOP_SIZED_NUMERIC_PLUSF(SDiv), - CEOP_SIZED_NUMERIC(UDiv), - CEOP_SIZED_NUMERIC_PLUSF(SMod), - CEOP_SIZED_NUMERIC(UMod), + CEOP_SIZED_NUMERIC_PLUSF(Div), + CEOP_SIZED_UNUMERIC(Div), + CEOP_SIZED_NUMERIC_PLUSF(Mod), + CEOP_SIZED_UNUMERIC(Mod), + CEOP_SIZED_NUMERIC(And), + CEOP_SIZED_NUMERIC(Or), + CEOP_SIZED_NUMERIC(Xor), + CEOP_SIZED_NUMERIC(Shl), + CEOP_SIZED_NUMERIC(Shr), + CEOP_SIZED_UNUMERIC(Shr), + CEOP_SIZED_NUMERIC_PLUSF(Cmp_EQ), + CEOP_SIZED_NUMERIC_PLUSF(Cmp_NE), CEOP_SIZED_NUMERIC_PLUSF(Cmp_SLT), CEOP_SIZED_NUMERIC(Cmp_ULT), CEOP_SIZED_NUMERIC_PLUSF(Cmp_SLE), CEOP_SIZED_NUMERIC(Cmp_ULE), + CEOP_SIZED_NUMERIC_PLUSF(Cmp_SGT), + CEOP_SIZED_NUMERIC(Cmp_UGT), + CEOP_SIZED_NUMERIC_PLUSF(Cmp_SGE), + CEOP_SIZED_NUMERIC(Cmp_UGE), CEOP_SIZED_NUMERIC_PLUSF(Neg), + CeOp_Not_I1, + CEOP_SIZED_NUMERIC(Not), CeOp_COUNT }; @@ -91,43 +176,95 @@ struct CeEmitEntry int mColumn; }; +class CeFunctionInfo +{ +public: + String mName; + BfMethodInstance* mMethodInstance; + BfMethodRef mMethodRef; + CeFunction* mCeFunction; + int mRefCount; + +public: + CeFunctionInfo() + { + mMethodInstance = NULL; + mCeFunction = NULL; + mRefCount = 0; + } +}; + class CeCallEntry { public: - String mFunctionName; + CeFunctionInfo* mFunctionInfo; int mBindRevision; CeFunction* mFunction; public: CeCallEntry() { + mFunctionInfo = NULL; mBindRevision = -1; mFunction = NULL; } }; +class CeStringEntry +{ +public: + int mStringId; + int mBindExecuteId; + addr_ce mStringAddr; + +public: + CeStringEntry() + { + mStringId = -1; + mBindExecuteId = -1; + mStringAddr = 0; + } +}; + +enum CeFunctionKind +{ + CeFunctionKind_Normal, + CeFunctionKind_Extern, + CeFunctionKind_OOB, + CeFunctionKind_FatalError, + CeFunctionKind_DebugWrite, + CeFunctionKind_DebugWrite_Int, +}; + class CeFunction { public: + CeFunctionInfo* mCeFunctionInfo; BfMethodInstance* mMethodInstance; - String mName; + CeFunctionKind mFunctionKind; bool mInitialized; bool mFailed; Array mCode; Array mFiles; Array mEmitTable; Array mCallTable; + Array mStringTable; + Array mTypeTable; String mGenError; - int mFrameSize; + int mFrameSize; public: CeFunction() { + mCeFunctionInfo = NULL; + mFunctionKind = CeFunctionKind_Normal; mInitialized = false; mMethodInstance = NULL; mFailed = false; mFrameSize = 0; } + + ~CeFunction(); }; enum CeEvalFlags @@ -176,6 +313,7 @@ public: }; #define BF_CE_STACK_SIZE 1024*1024 +#define BF_CE_MAX_MEMORY 128*1024*1024 enum CeOperandInfoKind { @@ -247,7 +385,7 @@ public: class CeBuilder { public: - CeMachine* mCeMachine; + CeMachine* mCeMachine; CeFunction* mCeFunction; BeFunction* mBeFunction; CeOperand mReturnVal; @@ -262,6 +400,7 @@ public: int mFrameSize; Dictionary mDbgFileMap; Dictionary mFunctionMap; + Dictionary mStringMap; public: CeBuilder() @@ -277,14 +416,16 @@ public: void Fail(const StringImpl& error); CeOperand FrameAlloc(BeType* type); + CeOperand EmitConst(int64 val, int size); CeOperand GetOperand(BeValue* value, bool allowAlloca = false, bool allowImmediate = false); CeSizeClass GetSizeClass(int size); int GetCodePos(); void HandleParams(); - - void Emit(uint8 val); + + void Emit(uint8 val); void Emit(CeOp val); + void EmitSizedOp(CeOp val, int size); void Emit(int32 val); void Emit(int64 val); void Emit(bool val); @@ -305,35 +446,42 @@ class CeFrame { public: CeFunction* mFunction; - uint8* mStackPtr; - uint8* mFramePtr; + addr_ce mStackAddr; + addr_ce mFrameAddr; uint8* mInstPtr; public: CeFrame() { mFunction = NULL; - mStackPtr = NULL; - mFramePtr = NULL; + mStackAddr = NULL; + mFrameAddr = NULL; mInstPtr = NULL; } }; +class CeFunctionRef +{ + //CeFunction* ; +}; + class CeMachine { public: - Dictionary mFunctions; - Dictionary mNamedFunctionMap; + Dictionary mFunctions; + Dictionary mNamedFunctionMap; BfCompiler* mCompiler; BfModule* mCeModule; int mRevision; - - Array mCallStack; - Array mMemory; - uint8* mStackMin; + int mExecuteId; + ContiguousHeap* mHeap; + Array mCallStack; + Array mMemory; + Dictionary mStringMap; + BfAstNode* mCurTargetSrc; - BfModule* mCurModule; + BfModule* mCurModule; public: CeMachine(BfCompiler* compiler); @@ -342,8 +490,12 @@ public: BfError* Fail(const CeFrame& curFrame, const StringImpl& error); void Init(); + uint8* CeMalloc(int size); + bool CeFree(addr_ce addr); + BeContext* GetBeContext(); BeModule* GetBeModule(); + void DerefMethodInfo(CeFunctionInfo* ceFunctionInfo); void RemoveMethod(BfMethodInstance* methodInstance); int GetConstantSize(BfConstant* constant); void WriteConstant(uint8* ptr, BfConstant* constant); @@ -352,10 +504,12 @@ public: void PrepareFunction(CeFunction* methodInstance); CeFunction* GetFunction(BfMethodInstance* methodInstance, BfIRValue func, bool& added); + CeFunction* GetPreparedFunction(BfMethodInstance* methodInstance); public: void CompileStarted(); void QueueMethod(BfMethodInstance* methodInstance, BfIRValue func); + void QueueMethod(BfModuleMethodInstance moduleMethodInstance); BfTypedValue Call(BfAstNode* targetSrc, BfModule* module, BfMethodInstance* methodInstance, const BfSizedArray& args, CeEvalFlags flags); };