From 76dfe97d78af8407050ece659bac851d9fb4e746 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 18 May 2020 06:58:02 -0700 Subject: [PATCH] Another pass at marking scoped raw arrays as deleted --- BeefLibs/corlib/src/Internal.bf | 31 ++--- IDE/mintest/minlib/src/System/Internal.bf | 31 ++--- IDEHelper/Compiler/BfModule.cpp | 129 +++++++++++------ IDEHelper/Compiler/BfModule.h | 2 +- IDEHelper/Compiler/BfStmtEvaluator.cpp | 161 +++++++++++++++++++++- 5 files changed, 273 insertions(+), 81 deletions(-) diff --git a/BeefLibs/corlib/src/Internal.bf b/BeefLibs/corlib/src/Internal.bf index 21e8c208..347b0fd4 100644 --- a/BeefLibs/corlib/src/Internal.bf +++ b/BeefLibs/corlib/src/Internal.bf @@ -140,23 +140,20 @@ namespace System #endif } - static void SetDeleted1(void* dest) - { - *((uint8*)dest) = 0xDD; - } - static void SetDeleted4(void* dest) - { - *((uint32*)dest) = 0xDDDDDDDD; - } - static void SetDeleted8(void* dest) - { - *((uint64*)dest) = 0xDDDDDDDDDDDDDDDDUL; - } - static void SetDeleted16(void* dest) - { - *((uint64*)dest) = 0xDDDDDDDDDDDDDDDDUL; - *((uint64*)dest + 1) = 0xDDDDDDDDDDDDDDDDUL; - } + [Error("Cannot be called directly"), SkipCall] + static void SetDeleted1(void* dest); + [Error("Cannot be called directly"), SkipCall] + static void SetDeleted4(void* dest); + [Error("Cannot be called directly"), SkipCall] + static void SetDeleted8(void* dest); + [Error("Cannot be called directly"), SkipCall] + static void SetDeleted16(void* dest); + [Error("Cannot be called directly"), SkipCall] + static extern void SetDeletedX(void* dest, int size); + [Error("Cannot be called directly"), SkipCall] + static extern void SetDeleted(void* dest, int size, int32 align, int arrayCount); + [Error("Cannot be called directly"), SkipCall] + static extern void SetDeletedArray(void* dest, int size, int32 align, int arrayCount); public static int MemCmp(void* memA, void* memB, int length) { diff --git a/IDE/mintest/minlib/src/System/Internal.bf b/IDE/mintest/minlib/src/System/Internal.bf index dcdb9e70..9c564cfb 100644 --- a/IDE/mintest/minlib/src/System/Internal.bf +++ b/IDE/mintest/minlib/src/System/Internal.bf @@ -118,23 +118,20 @@ namespace System #endif } - static void SetDeleted1(void* dest) - { - *((uint8*)dest) = 0xDD; - } - static void SetDeleted4(void* dest) - { - *((uint32*)dest) = 0xDDDDDDDD; - } - static void SetDeleted8(void* dest) - { - *((uint64*)dest) = 0xDDDDDDDDDDDDDDDDUL; - } - static void SetDeleted16(void* dest) - { - *((uint64*)dest) = 0xDDDDDDDDDDDDDDDDUL; - *((uint64*)dest + 1) = 0xDDDDDDDDDDDDDDDDUL; - } + [Error("Cannot be called directly"), SkipCall] + static void SetDeleted1(void* dest); + [Error("Cannot be called directly"), SkipCall] + static void SetDeleted4(void* dest); + [Error("Cannot be called directly"), SkipCall] + static void SetDeleted8(void* dest); + [Error("Cannot be called directly"), SkipCall] + static void SetDeleted16(void* dest); + [Error("Cannot be called directly"), SkipCall] + static extern void SetDeletedX(void* dest, int size); + [Error("Cannot be called directly"), SkipCall] + static extern void SetDeleted(void* dest, int size, int32 align, int arrayCount); + [Error("Cannot be called directly"), SkipCall] + static extern void SetDeletedArray(void* dest, int size, int32 align, int arrayCount); public static int MemCmp(void* memA, void* memB, int length) { diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 8318a1b4..72e8959b 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -1809,7 +1809,7 @@ BfIRValue BfModule::CreateAllocaInst(BfTypeInstance* typeInst, bool addLifetime, return allocaInst; } -void BfModule::AddStackAlloc(BfTypedValue val, BfAstNode* refNode, BfScopeData* scopeData, bool condAlloca, bool mayEscape) +void BfModule::AddStackAlloc(BfTypedValue val, BfIRValue arraySize, BfAstNode* refNode, BfScopeData* scopeData, bool condAlloca, bool mayEscape) { //This was removed because we want the alloc to be added to the __deferred list if it's actually a "stack" // 'stack' in a head scopeData is really the same as 'scopeData', so use the simpler scopeData handling @@ -1869,41 +1869,84 @@ void BfModule::AddStackAlloc(BfTypedValue val, BfAstNode* refNode, BfScopeData* //TODO: In the future we could be smarter about statically determining that our value hasn't escaped and eliding this if (mayEscape) { - // Is this worth it? -// if ((!IsOptimized()) && (val.mType->IsComposite()) && (!val.mType->IsValuelessType()) && (!mBfIRBuilder->mIgnoreWrites) && (!mCompiler->mIsResolveOnly)) -// { -// auto nullPtrType = GetPrimitiveType(BfTypeCode_NullPtr); -// bool isDyn = mCurMethodState->mCurScope->IsDyn(scopeData); -// if (!isDyn) -// { -// int clearSize = val.mType->mSize; -// BfModuleMethodInstance dtorMethodInstance = GetInternalMethod("MemSet"); -// BF_ASSERT(dtorMethodInstance.mMethodInstance != NULL); -// SizedArray llvmArgs; -// llvmArgs.push_back(mBfIRBuilder->CreateBitCast(val.mValue, mBfIRBuilder->MapType(nullPtrType))); -// llvmArgs.push_back(GetConstValue8(0xDD)); -// llvmArgs.push_back(GetConstValue(clearSize)); -// llvmArgs.push_back(GetConstValue32(val.mType->mAlign)); -// llvmArgs.push_back(mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 0)); -// AddDeferredCall(dtorMethodInstance, llvmArgs, scopeData, refNode, true); -// } -// else -// { -// const char* funcName = "SetDeleted1"; -// if (val.mType->mSize >= 16) -// funcName = "SetDeleted16"; -// else if (val.mType->mSize >= 8) -// funcName = "SetDeleted8"; -// else if (val.mType->mSize >= 4) -// funcName = "SetDeleted4"; -// -// BfModuleMethodInstance dtorMethodInstance = GetInternalMethod(funcName); -// BF_ASSERT(dtorMethodInstance.mMethodInstance != NULL); -// SizedArray llvmArgs; -// llvmArgs.push_back(mBfIRBuilder->CreateBitCast(val.mValue, mBfIRBuilder->MapType(nullPtrType))); -// AddDeferredCall(dtorMethodInstance, llvmArgs, scopeData, refNode, true); -// } -// } + + if ((!IsOptimized()) && (!val.mType->IsValuelessType()) && (!mBfIRBuilder->mIgnoreWrites) && (!mCompiler->mIsResolveOnly)) + { + auto nullPtrType = GetPrimitiveType(BfTypeCode_NullPtr); + bool isDyn = mCurMethodState->mCurScope->IsDyn(scopeData); + if (!isDyn) + { + const char* methodName = arraySize ? "SetDeletedArray" : "SetDeleted"; + BfModuleMethodInstance dtorMethodInstance = GetInternalMethod(methodName); + BF_ASSERT(dtorMethodInstance.mMethodInstance != NULL); + if (!dtorMethodInstance.mMethodInstance) + { + Fail(StrFormat("Unable to find %s", methodName)); + } + else + { + SizedArray llvmArgs; + llvmArgs.push_back(mBfIRBuilder->CreateBitCast(val.mValue, mBfIRBuilder->MapType(nullPtrType))); + llvmArgs.push_back(GetConstValue(val.mType->mSize)); + llvmArgs.push_back(GetConstValue32(val.mType->mAlign)); + if (arraySize) + llvmArgs.push_back(arraySize); + AddDeferredCall(dtorMethodInstance, llvmArgs, scopeData, refNode, true); + } + } + else + { + if ((arraySize) && (!arraySize.IsConst()) && (val.mType->mSize < mSystem->mPtrSize)) + { + BfIRValue clearSize = arraySize; + if (val.mType->GetStride() > 1) + clearSize = mBfIRBuilder->CreateMul(clearSize, GetConstValue(val.mType->GetStride())); + + const char* methodName = "SetDeletedX"; + BfModuleMethodInstance dtorMethodInstance = GetInternalMethod(methodName); + BF_ASSERT(dtorMethodInstance); + if (!dtorMethodInstance) + { + Fail(StrFormat("Unable to find %s", methodName)); + } + else + { + SizedArray llvmArgs; + llvmArgs.push_back(mBfIRBuilder->CreateBitCast(val.mValue, mBfIRBuilder->MapType(nullPtrType))); + llvmArgs.push_back(clearSize); + AddDeferredCall(dtorMethodInstance, llvmArgs, scopeData, refNode, true); + } + } + else + { + intptr clearSize = val.mType->mSize; + auto constant = mBfIRBuilder->GetConstant(arraySize); + if (constant != NULL) + clearSize = (intptr)(clearSize * constant->mInt64); + + const char* funcName = "SetDeleted1"; + if (clearSize >= 16) + funcName = "SetDeleted16"; + else if (clearSize >= 8) + funcName = "SetDeleted8"; + else if (clearSize >= 4) + funcName = "SetDeleted4"; + + BfModuleMethodInstance dtorMethodInstance = GetInternalMethod(funcName); + BF_ASSERT(dtorMethodInstance.mMethodInstance != NULL); + if (!dtorMethodInstance) + { + Fail(StrFormat("Unable to find %s", funcName)); + } + else + { + SizedArray llvmArgs; + llvmArgs.push_back(mBfIRBuilder->CreateBitCast(val.mValue, mBfIRBuilder->MapType(nullPtrType))); + AddDeferredCall(dtorMethodInstance, llvmArgs, scopeData, refNode, true); + } + } + } + } } } @@ -3904,6 +3947,8 @@ void BfModule::CreateFakeCallerMethod(const String& funcName) { if (mCurMethodInstance->mHasFailed) return; + if (mCurMethodInstance->mMethodDef->mIsSkipCall) + return; BF_ASSERT(mCurMethodInstance->mIRFunction); @@ -7809,7 +7854,7 @@ BfIRValue BfModule::AllocFromType(BfType* type, const BfAllocTarget& allocTarget mBfIRBuilder->SetInsertPoint(clearBlock); } - AddStackAlloc(typedVal, NULL, scopeData, false, true); + AddStackAlloc(typedVal, arraySize, NULL, scopeData, false, true); if (!isConstSize) { @@ -7839,7 +7884,7 @@ BfIRValue BfModule::AllocFromType(BfType* type, const BfAllocTarget& allocTarget auto loadedPtr = _CreateDynAlloc(sizeValue, arrayType->mAlign); auto typedVal = BfTypedValue(mBfIRBuilder->CreateBitCast(loadedPtr, mBfIRBuilder->MapType(arrayType)), arrayType); if (!noDtorCall) - AddStackAlloc(typedVal, NULL, scopeData, false, true); + AddStackAlloc(typedVal, arraySize, NULL, scopeData, false, true); InitTypeInst(typedVal, scopeData, zeroMemory, sizeValue); return typedVal.mValue; } @@ -7878,7 +7923,7 @@ BfIRValue BfModule::AllocFromType(BfType* type, const BfAllocTarget& allocTarget if (!isDynAlloc) mBfIRBuilder->SetInsertPoint(prevBlock); if (!noDtorCall) - AddStackAlloc(typedVal, NULL, scopeData, false, true); + AddStackAlloc(typedVal, arraySize, NULL, scopeData, false, true); InitTypeInst(typedVal, scopeData, zeroMemory, sizeValue); return typedVal.mValue; } @@ -7898,7 +7943,7 @@ BfIRValue BfModule::AllocFromType(BfType* type, const BfAllocTarget& allocTarget auto loadedPtr = _CreateDynAlloc(sizeValue, typeInstance->mAlign); auto typedVal = BfTypedValue(mBfIRBuilder->CreateBitCast(loadedPtr, mBfIRBuilder->MapTypeInstPtr(typeInstance)), typeInstance); if (!noDtorCall) - AddStackAlloc(typedVal, NULL, scopeData, mCurMethodState->mInConditionalBlock, true); + AddStackAlloc(typedVal, arraySize, NULL, scopeData, mCurMethodState->mInConditionalBlock, true); InitTypeInst(typedVal, scopeData, zeroMemory, sizeValue); return typedVal.mValue; } @@ -7965,7 +8010,7 @@ BfIRValue BfModule::AllocFromType(BfType* type, const BfAllocTarget& allocTarget bool doCondAlloca = false; if (!IsTargetingBeefBackend()) doCondAlloca = !wasDynAlloc && isDynAlloc && mCurMethodState->mInConditionalBlock; - AddStackAlloc(typedVal, NULL, scopeData, doCondAlloca, true); + AddStackAlloc(typedVal, arraySize, NULL, scopeData, doCondAlloca, true); } InitTypeInst(typedVal, scopeData, zeroMemory, sizeValue); @@ -8009,7 +8054,7 @@ BfIRValue BfModule::AllocFromType(BfType* type, const BfAllocTarget& allocTarget } } if (!noDtorCall) - AddStackAlloc(typedVal, NULL, scopeData, false, true); + AddStackAlloc(typedVal, BfIRValue(), NULL, scopeData, false, true); if (typeInstance != NULL) { InitTypeInst(typedVal, scopeData, zeroMemory, GetConstValue(typeInstance->mInstSize)); diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index 36a05e30..9e840da5 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -1468,7 +1468,7 @@ public: void NewScopeState(bool createLexicalBlock = true, bool flushValueScope = true); // returns prev scope data BfIRValue CreateAlloca(BfType* type, bool addLifetime = true, const char* name = NULL, BfIRValue arraySize = BfIRValue()); BfIRValue CreateAllocaInst(BfTypeInstance* typeInst, bool addLifetime = true, const char* name = NULL); - void AddStackAlloc(BfTypedValue val, BfAstNode* refNode, BfScopeData* scope, bool condAlloca = false, bool mayEscape = false); + void AddStackAlloc(BfTypedValue val, BfIRValue arraySize, BfAstNode* refNode, BfScopeData* scope, bool condAlloca = false, bool mayEscape = false); void RestoreScoreState_LocalVariables(); void RestoreScopeState(); void MarkDynStack(BfScopeData* scope); diff --git a/IDEHelper/Compiler/BfStmtEvaluator.cpp b/IDEHelper/Compiler/BfStmtEvaluator.cpp index e5bc2504..ac663b78 100644 --- a/IDEHelper/Compiler/BfStmtEvaluator.cpp +++ b/IDEHelper/Compiler/BfStmtEvaluator.cpp @@ -505,7 +505,7 @@ bool BfModule::AddDeferredCallEntry(BfDeferredCallEntry* deferredCallEntry, BfSc mCurMethodState->mDeferredLoopListEntryCount++; auto diVariable = mBfIRBuilder->DbgCreateAutoVariable(mCurMethodState->mCurScope->mDIScope, varName, mCurFilePosition.mFileInstance->mDIFile, mCurFilePosition.mCurLine, deferDIType); - mBfIRBuilder->DbgInsertDeclare(deferredAlloca, diVariable); + mBfIRBuilder->DbgInsertDeclare(deferredAlloca, diVariable); } return true; @@ -539,7 +539,161 @@ BfDeferredCallEntry* BfModule::AddDeferredCall(const BfModuleMethodInstance& mod } void BfModule::EmitDeferredCall(BfModuleMethodInstance moduleMethodInstance, SizedArrayImpl& llvmArgs, BfDeferredBlockFlags flags) -{ +{ + if (moduleMethodInstance.mMethodInstance->GetOwner()->IsInstanceOf(mCompiler->mInternalTypeDef)) + { + if (moduleMethodInstance.mMethodInstance->mMethodDef->mName.StartsWith("SetDeleted")) + { + intptr typeSize = 0; + intptr typeAlign = 1; + intptr clearSize = 0; + bool isDynSize = false; + + bool mayBeZero = false; + auto ptrValue = llvmArgs[0]; + BfIRValue arraySize; + + if ((moduleMethodInstance.mMethodInstance->mMethodDef->mName == "SetDeleted") || + (moduleMethodInstance.mMethodInstance->mMethodDef->mName == "SetDeletedArray")) + { + auto constant = mBfIRBuilder->GetConstant(llvmArgs[1]); + if (constant != NULL) + typeSize = constant->mInt64; + constant = mBfIRBuilder->GetConstant(llvmArgs[2]); + if (constant != NULL) + typeAlign = constant->mInt64; + auto arraySize = llvmArgs[3]; + + intptr allocSize = typeSize; + if (arraySize) + { + allocSize = BF_ALIGN(typeSize, typeAlign); + auto constant = mBfIRBuilder->GetConstant(arraySize); + if (constant != NULL) + allocSize = allocSize * (intptr)constant->mInt64; + else + { + isDynSize = true; + mayBeZero = true; + } + } + + clearSize = BF_MIN(allocSize, mSystem->mPtrSize); + } + else if (moduleMethodInstance.mMethodInstance->mMethodDef->mName == "SetDeletedX") + { + // Note: this infers that mayBeZero is false still, because the deferred call would not have + // been added if the array size was zero + typeSize = 1; + clearSize = typeSize; + arraySize = llvmArgs[1]; + isDynSize = true; + } + else if (moduleMethodInstance.mMethodInstance->mMethodDef->mName == "SetDeleted1") + { + clearSize = 1; + } + else if (moduleMethodInstance.mMethodInstance->mMethodDef->mName == "SetDeleted2") + { + clearSize = 2; + } + else if (moduleMethodInstance.mMethodInstance->mMethodDef->mName == "SetDeleted4") + { + clearSize = 4; + } + else if (moduleMethodInstance.mMethodInstance->mMethodDef->mName == "SetDeleted8") + { + clearSize = 8; + } + else if (moduleMethodInstance.mMethodInstance->mMethodDef->mName == "SetDeleted16") + { + clearSize = 16; + } + + if (clearSize > 0) + { + BfTypeCode clearTypeCode = BfTypeCode_Int8; + if (clearSize >= mSystem->mPtrSize) + clearTypeCode = BfTypeCode_IntPtr; + else if (clearSize >= 4) + clearTypeCode = BfTypeCode_Int32; + else if (clearSize >= 2) + clearTypeCode = BfTypeCode_Int16; + + auto intType = GetPrimitiveType(clearTypeCode); + auto intPtrType = CreatePointerType(intType); + + if (isDynSize) + { + if (clearSize >= mSystem->mPtrSize) + { + auto ddSize1Block = mBfIRBuilder->CreateBlock("DDSize1"); + auto ddDoneBlock = mBfIRBuilder->CreateBlock("DDDone"); + + auto cmp = mBfIRBuilder->CreateCmpGT(arraySize, mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, 0), true); + mBfIRBuilder->CreateCondBr(cmp, ddSize1Block, ddDoneBlock); + + mBfIRBuilder->AddBlock(ddSize1Block); + mBfIRBuilder->SetInsertPoint(ddSize1Block); + auto intPtrVal = mBfIRBuilder->CreateBitCast(ptrValue, mBfIRBuilder->MapType(intPtrType)); + mBfIRBuilder->CreateStore(mBfIRBuilder->CreateConst(clearTypeCode, 0xDDDDDDDDDDDDDDDDULL), intPtrVal); + mBfIRBuilder->CreateBr(ddDoneBlock); + + mBfIRBuilder->AddBlock(ddDoneBlock); + mBfIRBuilder->SetInsertPoint(ddDoneBlock); + } + else + { + // If we allocate at least this many then we can do an IntPtr-sized marking, otherwise just one element's worth + int intPtrCount = (int)((mSystem->mPtrSize + typeSize - 1) / typeSize); + + BfIRBlock ddSizePtrBlock = mBfIRBuilder->CreateBlock("DDSizePtr"); + BfIRBlock ddCheck1Block = mBfIRBuilder->CreateBlock("DDCheck1"); + BfIRBlock ddSize1Block; + if (mayBeZero) + ddSize1Block = mBfIRBuilder->CreateBlock("DDSize1"); + BfIRBlock ddDoneBlock = mBfIRBuilder->CreateBlock("DDDone"); + + auto intptrType = GetPrimitiveType(BfTypeCode_IntPtr); + auto intptrPtrType = CreatePointerType(intptrType); + + auto cmpPtr = mBfIRBuilder->CreateCmpGTE(arraySize, mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, intPtrCount), true); + mBfIRBuilder->CreateCondBr(cmpPtr, ddSizePtrBlock, ddCheck1Block); + + mBfIRBuilder->AddBlock(ddSizePtrBlock); + mBfIRBuilder->SetInsertPoint(ddSizePtrBlock); + auto intptrPtrVal = mBfIRBuilder->CreateBitCast(ptrValue, mBfIRBuilder->MapType(intptrPtrType)); + mBfIRBuilder->CreateStore(mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, 0xDDDDDDDDDDDDDDDDULL), intptrPtrVal); + mBfIRBuilder->CreateBr(ddDoneBlock); + + mBfIRBuilder->AddBlock(ddCheck1Block); + mBfIRBuilder->SetInsertPoint(ddCheck1Block); + if (mayBeZero) + { + auto cmp1 = mBfIRBuilder->CreateCmpGT(arraySize, mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, 0), true); + mBfIRBuilder->CreateCondBr(cmp1, ddSize1Block, ddDoneBlock); + + mBfIRBuilder->AddBlock(ddSize1Block); + mBfIRBuilder->SetInsertPoint(ddSize1Block); + } + auto intPtrVal = mBfIRBuilder->CreateBitCast(ptrValue, mBfIRBuilder->MapType(intPtrType)); + mBfIRBuilder->CreateStore(mBfIRBuilder->CreateConst(clearTypeCode, 0xDDDDDDDDDDDDDDDDULL), intPtrVal); + mBfIRBuilder->CreateBr(ddDoneBlock); + + mBfIRBuilder->AddBlock(ddDoneBlock); + mBfIRBuilder->SetInsertPoint(ddDoneBlock); + } + } + else + { + auto intPtrVal = mBfIRBuilder->CreateBitCast(ptrValue, mBfIRBuilder->MapType(intPtrType)); + mBfIRBuilder->CreateStore(mBfIRBuilder->CreateConst(clearTypeCode, 0xDDDDDDDDDDDDDDDDULL), intPtrVal); + } + } + return; + } + } + if (moduleMethodInstance.mMethodInstance == mContext->mValueTypeDeinitSentinel) { BF_ASSERT(llvmArgs.size() == 3); @@ -659,8 +813,7 @@ void BfModule::EmitDeferredCall(BfDeferredCallEntry& deferredCallEntry) RestoreScopeState(); return; } - - auto moduleMethodInstance = deferredCallEntry.mModuleMethodInstance; + auto args = deferredCallEntry.mScopeArgs; if (deferredCallEntry.mArgsNeedLoad) {