1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-09 03:52:19 +02:00

Another pass at marking scoped raw arrays as deleted

This commit is contained in:
Brian Fiete 2020-05-18 06:58:02 -07:00
parent 81f8a95cd8
commit 76dfe97d78
5 changed files with 273 additions and 81 deletions

View file

@ -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)
{

View file

@ -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)
{

View file

@ -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<BfIRValue, 1> 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<BfIRValue, 1> 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<BfIRValue, 1> 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<BfIRValue, 1> 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<BfIRValue, 1> 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));

View file

@ -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);

View file

@ -540,6 +540,160 @@ BfDeferredCallEntry* BfModule::AddDeferredCall(const BfModuleMethodInstance& mod
void BfModule::EmitDeferredCall(BfModuleMethodInstance moduleMethodInstance, SizedArrayImpl<BfIRValue>& 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);
@ -660,7 +814,6 @@ void BfModule::EmitDeferredCall(BfDeferredCallEntry& deferredCallEntry)
return;
}
auto moduleMethodInstance = deferredCallEntry.mModuleMethodInstance;
auto args = deferredCallEntry.mScopeArgs;
if (deferredCallEntry.mArgsNeedLoad)
{