2019-08-23 11:56:54 -07:00
# include "BfCompiler.h"
# include "BfSystem.h"
# include "BfParser.h"
# include "BfCodeGen.h"
# include "BfExprEvaluator.h"
# include <fcntl.h>
# include "BfConstResolver.h"
# include "BfMangler.h"
# include "BeefySysLib/util/PerfTimer.h"
# include "BeefySysLib/util/BeefPerf.h"
2024-03-18 05:44:02 -04:00
# include "BeefySysLib/util/StackHelper.h"
2019-08-23 11:56:54 -07:00
# include "BfSourceClassifier.h"
# include "BfAutoComplete.h"
# include "BfDemangler.h"
# include "BfResolvePass.h"
# include "BfFixits.h"
# include "BfIRCodeGen.h"
# include "BfDefBuilder.h"
# pragma warning(push)
# pragma warning(disable:4141)
# pragma warning(disable:4146)
# pragma warning(disable:4291)
# pragma warning(disable:4244)
# pragma warning(disable:4267)
# pragma warning(disable:4624)
# pragma warning(disable:4800)
# pragma warning(disable:4996)
2024-05-01 06:26:14 -04:00
# include "llvm/IR/DIBuilder.h"
2019-08-23 11:56:54 -07:00
# include "llvm/IR/Module.h"
# include "llvm/IR/Constants.h"
# include "llvm/IR/GlobalValue.h"
# include "llvm/IR/GlobalVariable.h"
# include "llvm/ADT/ArrayRef.h"
# include "llvm/IR/InlineAsm.h"
# include "llvm/Support/FileSystem.h"
# include "BeefySysLib/util/AllocDebug.h"
# pragma warning(pop)
USING_NS_BF ;
bool BfModule : : AddDeferredCallEntry ( BfDeferredCallEntry * deferredCallEntry , BfScopeData * scopeData )
2022-07-26 13:27:03 -04:00
{
if ( ( ( ( mCompiler - > mIsResolveOnly ) & & ( ! mIsComptimeModule ) ) | |
2020-12-17 04:51:05 -08:00
( mBfIRBuilder - > mIgnoreWrites ) ) & & ( deferredCallEntry - > mDeferredBlock = = NULL ) )
2019-08-23 11:56:54 -07:00
{
// 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
delete deferredCallEntry ;
return false ;
}
if ( mBfIRBuilder - > mIgnoreWrites )
{
deferredCallEntry - > mIgnored = true ;
scopeData - > mDeferredCallEntries . PushBack ( deferredCallEntry ) ;
return true ;
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
// We don't need to do a "clear handlers" if we're just adding another dyn to an existing dyn list
2022-07-26 13:27:03 -04:00
bool isDyn = mCurMethodState - > mCurScope - > IsDyn ( scopeData ) ;
2022-01-08 11:26:56 -05:00
if ( mCurMethodState - > mPendingNullConditional ! = NULL )
isDyn = true ;
2022-01-25 12:05:15 -05:00
deferredCallEntry - > mOrigScopeArgs = deferredCallEntry - > mScopeArgs ;
2019-08-23 11:56:54 -07:00
if ( ! isDyn )
{
mCurMethodState - > mCurScope - > ClearHandlers ( scopeData ) ;
if ( ! mBfIRBuilder - > mIgnoreWrites )
{
if ( ( IsTargetingBeefBackend ( ) ) & & ( deferredCallEntry - > mModuleMethodInstance . mMethodInstance ! = NULL ) & &
( ! mContext - > IsSentinelMethod ( deferredCallEntry - > mModuleMethodInstance . mMethodInstance ) ) )
{
SizedArray < BfIRType , 8 > origParamTypes ;
BfIRType origReturnType ;
deferredCallEntry - > mModuleMethodInstance . mMethodInstance - > GetIRFunctionInfo ( this , origReturnType , origParamTypes ) ;
2022-07-26 13:27:03 -04:00
2021-07-05 17:28:15 -07:00
int sretIdx = deferredCallEntry - > mModuleMethodInstance . mMethodInstance - > GetStructRetIdx ( ) ;
BF_ASSERT ( origParamTypes . size ( ) = = deferredCallEntry - > mScopeArgs . size ( ) + ( ( sretIdx ! = - 1 ) ? 1 : 0 ) ) ;
2019-08-23 11:56:54 -07:00
2021-07-05 17:28:15 -07:00
int argIdx = 0 ;
int paramIdx = 0 ;
for ( int argIdx = 0 ; argIdx < ( int ) deferredCallEntry - > mScopeArgs . size ( ) ; argIdx + + , paramIdx + + )
2019-08-23 11:56:54 -07:00
{
2021-07-05 17:28:15 -07:00
if ( argIdx = = sretIdx )
paramIdx + + ;
auto scopeArg = deferredCallEntry - > mScopeArgs [ argIdx ] ;
2022-07-26 13:27:03 -04:00
if ( ( scopeArg . IsConst ( ) ) | | ( scopeArg . IsFake ( ) ) )
2019-08-23 11:56:54 -07:00
continue ;
auto prevInsertBlock = mBfIRBuilder - > GetInsertBlock ( ) ;
mBfIRBuilder - > SetInsertPoint ( mCurMethodState - > mIRHeadBlock ) ;
auto allocaInst = mBfIRBuilder - > CreateAlloca ( origParamTypes [ paramIdx ] ) ;
2021-06-29 11:58:33 -07:00
mBfIRBuilder - > ClearDebugLocation_Last ( ) ;
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > SetInsertPoint ( prevInsertBlock ) ;
2019-09-18 08:14:38 -07:00
if ( WantsLifetimes ( ) )
2021-06-29 11:58:33 -07:00
{
2019-09-18 08:14:38 -07:00
mBfIRBuilder - > CreateLifetimeStart ( allocaInst ) ;
2021-06-29 11:58:33 -07:00
mBfIRBuilder - > ClearDebugLocation_Last ( ) ;
}
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > CreateStore ( scopeArg , allocaInst ) ;
2021-06-29 11:58:33 -07:00
mBfIRBuilder - > ClearDebugLocation_Last ( ) ;
2021-07-05 17:28:15 -07:00
deferredCallEntry - > mScopeArgs [ argIdx ] = allocaInst ;
2019-09-18 08:14:38 -07:00
if ( WantsLifetimes ( ) )
scopeData - > mDeferredLifetimeEnds . push_back ( allocaInst ) ;
2019-08-23 11:56:54 -07:00
}
deferredCallEntry - > mArgsNeedLoad = true ;
}
}
scopeData - > mDeferredCallEntries . PushFront ( deferredCallEntry ) ;
return true ;
}
bool isLooped = mCurMethodState - > mCurScope - > IsLooped ( scopeData ) ;
BfDeferredCallEntry * listEntry = NULL ;
if ( ! scopeData - > mDeferredCallEntries . IsEmpty ( ) )
{
listEntry = scopeData - > mDeferredCallEntries . mHead ;
if ( ! listEntry - > IsDynList ( ) )
listEntry = NULL ;
}
auto deferredCallEntryType = ResolveTypeDef ( mCompiler - > mDeferredCallTypeDef ) ;
AddDependency ( deferredCallEntryType , mCurTypeInstance , BfDependencyMap : : DependencyFlag_Allocates ) ;
mBfIRBuilder - > PopulateType ( deferredCallEntryType ) ;
auto deferredCallEntryTypePtr = CreatePointerType ( deferredCallEntryType ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
UpdateSrcPos ( mCurMethodInstance - > mMethodDef - > GetRefNode ( ) , BfSrcPosFlag_NoSetDebugLoc ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
if ( listEntry = = NULL )
{
listEntry = new BfDeferredCallEntry ( ) ;
if ( ! mBfIRBuilder - > mIgnoreWrites )
{
listEntry - > mDynCallTail = CreateAlloca ( deferredCallEntryTypePtr , false , " deferredCallTail " ) ;
2019-09-18 08:14:38 -07:00
if ( WantsLifetimes ( ) )
scopeData - > mDeferredLifetimeEnds . push_back ( listEntry - > mDynCallTail ) ;
2019-08-23 11:56:54 -07:00
auto prevInsertBlock = mBfIRBuilder - > GetInsertBlock ( ) ;
mBfIRBuilder - > SaveDebugLocation ( ) ;
mBfIRBuilder - > SetInsertPointAtStart ( mCurMethodState - > mIRInitBlock ) ;
auto scopeHead = & mCurMethodState - > mHeadScope ;
2022-02-07 15:15:58 -05:00
if ( scopeHead - > mDIScope )
mBfIRBuilder - > SetCurrentDebugLocation ( mCurFilePosition . mCurLine + 1 , 0 , scopeHead - > mDIScope , BfIRMDNode ( ) ) ;
2019-08-23 11:56:54 -07:00
2019-09-18 08:14:38 -07:00
if ( WantsLifetimes ( ) )
mBfIRBuilder - > CreateLifetimeStart ( listEntry - > mDynCallTail ) ;
2019-08-23 11:56:54 -07:00
auto storeInst = mBfIRBuilder - > CreateStore ( GetDefaultValue ( deferredCallEntryTypePtr ) , listEntry - > mDynCallTail ) ;
mBfIRBuilder - > ClearDebugLocation ( storeInst ) ;
if ( WantsDebugInfo ( ) )
{
auto deferredCallEntryType = ResolveTypeDef ( mCompiler - > mDeferredCallTypeDef ) ;
auto deferredCallEntryTypePtr = CreatePointerType ( deferredCallEntryType ) ;
String varName = StrFormat ( " __deferred%d " , mCurMethodState - > mDeferredLoopListCount ) ;
mBfIRBuilder - > SetInsertPoint ( mCurMethodState - > mIRInitBlock ) ;
2022-02-07 15:15:58 -05:00
if ( scopeHead - > mDIScope )
mBfIRBuilder - > SetCurrentDebugLocation ( mCurFilePosition . mCurLine + 1 , 0 , scopeHead - > mDIScope , BfIRMDNode ( ) ) ;
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > CreateStatementStart ( ) ;
//TODO: Make this work for LLVM - we need a proper debug location
//if (IsTargetingBeefBackend())
{
auto diVariable = mBfIRBuilder - > DbgCreateAutoVariable ( scopeHead - > mDIScope , varName , mCurFilePosition . mFileInstance - > mDIFile , mCurFilePosition . mCurLine , mBfIRBuilder - > DbgGetType ( deferredCallEntryTypePtr ) ) ;
mBfIRBuilder - > DbgInsertDeclare ( listEntry - > mDynCallTail , diVariable ) ;
}
mCurMethodState - > mDeferredLoopListCount + + ;
}
mBfIRBuilder - > SetInsertPoint ( prevInsertBlock ) ;
mBfIRBuilder - > RestoreDebugLocation ( ) ;
}
mCurMethodState - > mCurScope - > ClearHandlers ( scopeData ) ;
2022-07-26 13:27:03 -04:00
scopeData - > mDeferredCallEntries . PushFront ( listEntry ) ;
2019-08-23 11:56:54 -07:00
}
2022-07-26 13:27:03 -04:00
BfIRValue deferredAlloca ;
2019-08-23 11:56:54 -07:00
SizedArray < BfType * , 4 > types ;
SizedArray < String , 8 > memberNames ;
int instAlign = 1 ;
int dataPos = 0 ;
int instSize = 0 ;
Array < int > memberPositions ;
String typeName ;
BfDeferredMethodCallData * deferredMethodCallData = NULL ;
if ( deferredCallEntry - > mDeferredBlock ! = NULL )
{
2019-12-11 12:55:50 -08:00
HashContext hashCtx ;
hashCtx . Mixin ( deferredCallEntry - > mDeferredBlock - > GetSrcStart ( ) ) ;
2022-07-26 13:27:03 -04:00
2019-12-11 12:55:50 -08:00
auto parserData = deferredCallEntry - > mDeferredBlock - > GetParserData ( ) ;
2022-07-26 13:27:03 -04:00
if ( parserData ! = NULL )
2019-12-11 12:55:50 -08:00
hashCtx . MixinStr ( parserData - > mFileName ) ;
2022-07-26 13:27:03 -04:00
2019-12-11 12:55:50 -08:00
int64 blockId = BfDeferredMethodCallData : : GenerateMethodId ( this , hashCtx . Finish64 ( ) ) ;
2019-12-13 14:22:23 -08:00
deferredCallEntry - > mBlockId = blockId ;
2019-08-23 11:56:54 -07:00
auto deferType = deferredCallEntryType ;
2022-07-26 13:27:03 -04:00
BfIRType deferIRType ;
2019-08-23 11:56:54 -07:00
auto int64Type = GetPrimitiveType ( BfTypeCode_Int64 ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
types . push_back ( int64Type ) ;
memberNames . push_back ( " __methodId " ) ;
types . push_back ( deferredCallEntryTypePtr ) ;
memberNames . push_back ( " __next " ) ;
for ( auto & capture : deferredCallEntry - > mCaptures )
{
BfType * type = capture . mValue . mType ;
types . push_back ( type ) ;
memberNames . push_back ( capture . mName ) ;
}
SizedArray < BfIRType , 4 > llvmTypes ;
SizedArray < BfIRMDNode , 8 > diFieldTypes ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
typeName = StrFormat ( " _BF_DeferredData_%s " , BfTypeUtils : : HashEncode64 ( blockId ) . c_str ( ) ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
auto valueType = ResolveTypeDef ( mCompiler - > mValueTypeTypeDef ) ;
llvmTypes . push_back ( mBfIRBuilder - > MapType ( valueType ) ) ;
//int dataPos = 0;
for ( int i = 0 ; i < ( int ) memberNames . size ( ) ; i + + )
{
auto type = types [ i ] ;
auto memberName = memberNames [ i ] ;
if ( ! type - > IsValuelessType ( ) )
{
llvmTypes . push_back ( mBfIRBuilder - > MapType ( type ) ) ;
instAlign = BF_MAX ( instAlign , ( int ) type - > mAlign ) ;
int alignSize = ( int ) type - > mAlign ;
int dataSize = type - > mSize ;
if ( alignSize > 1 )
dataPos = ( dataPos + ( alignSize - 1 ) ) & ~ ( alignSize - 1 ) ;
memberPositions . push_back ( dataPos ) ;
dataPos + = type - > mSize ;
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
}
instSize = dataPos ;
deferIRType = mBfIRBuilder - > CreateStructType ( typeName ) ;
2021-01-18 14:09:16 -08:00
mBfIRBuilder - > StructSetBody ( deferIRType , llvmTypes , instSize , instAlign , false ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
auto prevInsertPoint = mBfIRBuilder - > GetInsertBlock ( ) ;
if ( ! isLooped )
mBfIRBuilder - > SetInsertPoint ( mCurMethodState - > mIRHeadBlock ) ;
deferredAlloca = mBfIRBuilder - > CreateAlloca ( deferIRType ) ;
2022-07-26 13:27:03 -04:00
mBfIRBuilder - > SetAllocaAlignment ( deferredAlloca , instAlign ) ;
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > SetAllocaNoChkStkHint ( deferredAlloca ) ;
if ( ! isLooped )
mBfIRBuilder - > SetInsertPoint ( prevInsertPoint ) ;
auto gepInstance = mBfIRBuilder - > CreateInBoundsGEP ( deferredAlloca , 0 , 2 ) ; // mNext
auto prevVal = mBfIRBuilder - > CreateLoad ( listEntry - > mDynCallTail ) ;
mBfIRBuilder - > CreateStore ( prevVal , gepInstance ) ;
gepInstance = mBfIRBuilder - > CreateInBoundsGEP ( deferredAlloca , 0 , 1 ) ; // mMethodId
mBfIRBuilder - > CreateStore ( GetConstValue64 ( blockId ) , gepInstance ) ;
if ( ! deferredCallEntry - > mCaptures . empty ( ) )
{
int dataIdx = 3 ;
for ( int captureIdx = 0 ; captureIdx < ( int ) deferredCallEntry - > mCaptures . size ( ) ; captureIdx + + )
{
auto & capture = deferredCallEntry - > mCaptures [ captureIdx ] ;
if ( ! capture . mValue . mType - > IsValuelessType ( ) )
{
auto gepInstance = mBfIRBuilder - > CreateInBoundsGEP ( deferredAlloca , 0 , dataIdx ) ;
mBfIRBuilder - > CreateStore ( capture . mValue . mValue , gepInstance ) ;
dataIdx + + ;
}
}
}
mBfIRBuilder - > CreateStore ( mBfIRBuilder - > CreateBitCast ( deferredAlloca , mBfIRBuilder - > MapType ( deferredCallEntryTypePtr ) ) , listEntry - > mDynCallTail ) ;
deferredCallEntry - > mDeferredAlloca = deferredAlloca ;
listEntry - > mDynList . PushFront ( deferredCallEntry ) ;
}
else
{
auto & llvmArgs = deferredCallEntry - > mScopeArgs ;
auto moduleMethodInstance = deferredCallEntry - > mModuleMethodInstance ;
auto methodInstance = moduleMethodInstance . mMethodInstance ;
auto methodDef = methodInstance - > mMethodDef ;
auto owningType = methodInstance - > mMethodInstanceGroup - > mOwner ;
auto voidType = GetPrimitiveType ( BfTypeCode_None ) ;
auto voidPtrType = CreatePointerType ( voidType ) ;
BfDeferredMethodCallData * * deferredMethodCallDataPtr = NULL ;
if ( mDeferredMethodCallData . TryGetValue ( methodInstance , & deferredMethodCallDataPtr ) )
{
deferredMethodCallData = * deferredMethodCallDataPtr ;
}
else
{
deferredMethodCallData = new BfDeferredMethodCallData ( ) ;
mDeferredMethodCallData [ methodInstance ] = deferredMethodCallData ;
2019-12-11 12:55:50 -08:00
deferredMethodCallData - > mMethodId = BfDeferredMethodCallData : : GenerateMethodId ( this , methodInstance - > mIdHash ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
auto int64Type = GetPrimitiveType ( BfTypeCode_Int64 ) ;
auto methodDef = moduleMethodInstance . mMethodInstance - > mMethodDef ;
auto thisType = moduleMethodInstance . mMethodInstance - > mMethodInstanceGroup - > mOwner ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
types . push_back ( int64Type ) ;
memberNames . push_back ( " __methodId " ) ;
types . push_back ( deferredCallEntryTypePtr ) ;
memberNames . push_back ( " __next " ) ;
if ( ! methodDef - > mIsStatic )
{
types . push_back ( thisType ) ;
memberNames . push_back ( " __this " ) ;
}
for ( int paramIdx = 0 ; paramIdx < ( int ) methodInstance - > GetParamCount ( ) ; paramIdx + + )
{
if ( methodInstance - > IsParamSkipped ( paramIdx ) )
paramIdx + + ;
types . push_back ( methodInstance - > GetParamType ( paramIdx ) ) ;
memberNames . push_back ( methodInstance - > GetParamName ( paramIdx ) ) ;
}
2022-07-26 13:27:03 -04:00
SizedArray < BfIRType , 4 > llvmTypes ;
2019-08-23 11:56:54 -07:00
2022-07-26 13:27:03 -04:00
//String typeName;
2019-08-23 11:56:54 -07:00
typeName + = StrFormat ( " _BF_DeferredData_%s " , BfTypeUtils : : HashEncode64 ( deferredMethodCallData - > mMethodId ) . c_str ( ) ) ;
BfLogSysM ( " Building type: %s from methodInstance:%p \n " , typeName . c_str ( ) , methodInstance ) ;
//Array<int> memberPositions;
//int instAlign = 1;
//int dataPos = 0;
BF_ASSERT ( types . size ( ) = = memberNames . size ( ) ) ;
for ( int i = 0 ; i < ( int ) types . size ( ) ; i + + )
{
auto type = types [ i ] ;
auto memberName = memberNames [ i ] ;
if ( ! type - > IsValuelessType ( ) )
{
llvmTypes . push_back ( mBfIRBuilder - > MapType ( type ) ) ;
instAlign = BF_MAX ( instAlign , ( int ) type - > mAlign ) ;
int alignSize = ( int ) type - > mAlign ;
int dataSize = type - > mSize ;
if ( alignSize > 1 )
dataPos = ( dataPos + ( alignSize - 1 ) ) & ~ ( alignSize - 1 ) ;
memberPositions . push_back ( dataPos ) ;
dataPos + = type - > mSize ;
}
}
instSize = dataPos ;
deferredMethodCallData - > mAlign = instAlign ;
deferredMethodCallData - > mSize = instSize ;
deferredMethodCallData - > mDeferType = mBfIRBuilder - > CreateStructType ( typeName ) ;
2021-01-18 14:09:16 -08:00
mBfIRBuilder - > StructSetBody ( deferredMethodCallData - > mDeferType , llvmTypes , instSize , instAlign , false ) ;
2019-08-23 11:56:54 -07:00
deferredMethodCallData - > mDeferTypePtr = mBfIRBuilder - > GetPointerTo ( deferredMethodCallData - > mDeferType ) ;
}
auto deferType = deferredMethodCallData - > mDeferType ;
auto prevInsertPoint = mBfIRBuilder - > GetInsertBlock ( ) ;
if ( ! isLooped )
mBfIRBuilder - > SetInsertPoint ( mCurMethodState - > mIRHeadBlock ) ;
deferredAlloca = mBfIRBuilder - > CreateAlloca ( BfIRType ( deferredMethodCallData - > mDeferType ) ) ;
mBfIRBuilder - > ClearDebugLocation ( deferredAlloca ) ;
2022-07-26 13:27:03 -04:00
mBfIRBuilder - > SetAllocaAlignment ( deferredAlloca , deferredMethodCallData - > mAlign ) ;
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > SetAllocaNoChkStkHint ( deferredAlloca ) ;
if ( ! isLooped )
2022-07-26 13:27:03 -04:00
mBfIRBuilder - > SetInsertPoint ( prevInsertPoint ) ;
2019-08-23 11:56:54 -07:00
auto gepInstance = mBfIRBuilder - > CreateInBoundsGEP ( deferredAlloca , 0 , 1 ) ;
auto prevVal = mBfIRBuilder - > CreateLoad ( listEntry - > mDynCallTail ) ;
mBfIRBuilder - > CreateStore ( prevVal , gepInstance ) ;
gepInstance = mBfIRBuilder - > CreateInBoundsGEP ( deferredAlloca , 0 , 0 ) ;
mBfIRBuilder - > CreateStore ( GetConstValue64 ( deferredMethodCallData - > mMethodId ) , gepInstance ) ;
int dataIdx = 2 ;
int argIdx = 0 ;
2023-01-23 06:56:05 -05:00
if ( ( ! methodDef - > mIsStatic ) & & ( ! owningType - > IsValuelessType ( ) ) )
2019-08-23 11:56:54 -07:00
{
gepInstance = mBfIRBuilder - > CreateInBoundsGEP ( deferredAlloca , 0 , 2 ) ;
2023-01-23 06:56:05 -05:00
if ( owningType - > IsValueType ( ) )
2019-08-23 11:56:54 -07:00
{
if ( ( ! methodDef - > mIsMutating ) & & ( owningType - > IsSplattable ( ) ) )
{
BfTypedValue splatVal ( llvmArgs [ 0 ] , owningType , BfTypedValueKind_ThisSplatHead ) ;
BfTypedValue aggVal = AggregateSplat ( splatVal , & llvmArgs [ 0 ] ) ;
aggVal = LoadValue ( aggVal ) ;
mBfIRBuilder - > CreateStore ( aggVal . mValue , gepInstance ) ;
BfTypeUtils : : SplatIterate ( [ & ] ( BfType * checkType ) { argIdx + + ; } , owningType ) ;
}
else
{
auto thisArg = mBfIRBuilder - > CreateLoad ( llvmArgs [ 0 ] ) ;
mBfIRBuilder - > CreateStore ( thisArg , gepInstance ) ;
argIdx + + ;
}
}
else
{
mBfIRBuilder - > CreateStore ( llvmArgs [ 0 ] , gepInstance ) ;
argIdx + + ;
}
dataIdx + + ;
}
for ( int paramIdx = 0 ; paramIdx < ( int ) methodInstance - > GetParamCount ( ) ; paramIdx + + , dataIdx + + )
{
if ( methodInstance - > IsParamSkipped ( paramIdx ) )
paramIdx + + ;
auto paramType = methodInstance - > GetParamType ( paramIdx ) ;
bool paramIsSplat = methodInstance - > GetParamIsSplat ( paramIdx ) ;
gepInstance = mBfIRBuilder - > CreateInBoundsGEP ( deferredAlloca , 0 , dataIdx /*, methodDef->mParams[paramIdx]->mName*/ ) ;
if ( paramType - > IsStruct ( ) )
{
if ( paramIsSplat )
{
BfTypedValue splatVal ( llvmArgs [ argIdx ] , paramType , BfTypedValueKind_SplatHead ) ;
BfTypedValue aggVal = AggregateSplat ( splatVal , & llvmArgs [ argIdx ] ) ;
aggVal = LoadValue ( aggVal ) ;
mBfIRBuilder - > CreateStore ( aggVal . mValue , gepInstance ) ;
BfTypeUtils : : SplatIterate ( [ & ] ( BfType * checkType ) { argIdx + + ; } , paramType ) ;
}
else
{
2022-07-26 13:27:03 -04:00
auto val = mBfIRBuilder - > CreateLoad ( llvmArgs [ argIdx ] ) ;
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > CreateStore ( val , gepInstance ) ;
argIdx + + ;
}
}
else
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > CreateStore ( llvmArgs [ argIdx ] , gepInstance ) ;
argIdx + + ;
}
}
mBfIRBuilder - > CreateStore ( mBfIRBuilder - > CreateBitCast ( deferredAlloca , mBfIRBuilder - > MapType ( deferredCallEntryTypePtr ) ) , listEntry - > mDynCallTail ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
deferredCallEntry - > mDeferredAlloca = deferredAlloca ;
listEntry - > mDynList . PushFront ( deferredCallEntry ) ;
}
2022-03-15 16:33:30 -07:00
if ( ( mBfIRBuilder - > DbgHasInfo ( ) ) & & ( mHasFullDebugInfo ) & & ( mCompiler - > mOptions . mEmitDebugInfo ) & & ( mCurMethodState - > mCurScope - > mDIScope ) )
2019-08-23 11:56:54 -07:00
{
auto int64Type = GetPrimitiveType ( BfTypeCode_Int64 ) ;
auto moduleMethodInstance = deferredCallEntry - > mModuleMethodInstance ;
auto methodInstance = moduleMethodInstance . mMethodInstance ;
BfIRMDNode deferDIType ;
if ( ( deferredMethodCallData ! = NULL ) & & ( deferredMethodCallData - > mDeferDIType ) )
{
deferDIType = deferredMethodCallData - > mDeferDIType ;
}
else
{
2020-09-14 06:54:49 -07:00
BfIRMDNode diForwardDecl ;
2019-08-23 11:56:54 -07:00
SizedArray < BfIRMDNode , 8 > diFieldTypes ;
if ( ( mBfIRBuilder - > DbgHasInfo ( ) ) & & ( mHasFullDebugInfo ) )
{
String dbgTypeName ;
if ( mCompiler - > mOptions . IsCodeView ( ) )
dbgTypeName + = " _bf:: " ;
dbgTypeName + = typeName ;
diForwardDecl = mBfIRBuilder - > DbgCreateReplaceableCompositeType ( llvm : : dwarf : : DW_TAG_structure_type , dbgTypeName , mCurFilePosition . mFileInstance - > mDIFile , mCurFilePosition . mFileInstance - > mDIFile ,
mCurFilePosition . mCurLine , instSize * 8 , instAlign * 8 ) ;
if ( methodInstance ! = NULL )
{
// We make a fake member to get inserted into the DbgModule data so we can show what method this deferred call goes to
StringT < 128 > mangledName ;
BfMangler : : Mangle ( mangledName , mCompiler - > GetMangleKind ( ) , methodInstance ) ;
auto memberType = mBfIRBuilder - > DbgCreateMemberType ( diForwardDecl , mangledName , mCurFilePosition . mFileInstance - > mDIFile , mCurFilePosition . mCurLine ,
0 , 0 , - 1 , 0 , mBfIRBuilder - > DbgGetType ( int64Type ) ) ;
diFieldTypes . push_back ( memberType ) ;
}
}
for ( int i = 0 ; i < ( int ) types . size ( ) ; i + + )
{
auto type = types [ i ] ;
auto memberName = memberNames [ i ] ;
if ( ( mBfIRBuilder - > DbgHasInfo ( ) ) & & ( mHasFullDebugInfo ) )
{
int memberFlags = 0 ;
auto memberType = mBfIRBuilder - > DbgCreateMemberType ( diForwardDecl , memberName , mCurFilePosition . mFileInstance - > mDIFile , mCurFilePosition . mCurLine ,
type - > mSize * 8 , type - > mAlign * 8 , memberPositions [ i ] * 8 , memberFlags , mBfIRBuilder - > DbgGetType ( type ) ) ;
diFieldTypes . push_back ( memberType ) ;
}
}
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
int diFlags = 0 ;
mBfIRBuilder - > DbgMakePermanent ( diForwardDecl , BfIRMDNode ( ) , diFieldTypes ) ;
deferDIType = mBfIRBuilder - > DbgCreatePointerType ( diForwardDecl ) ;
if ( deferredMethodCallData ! = NULL )
2022-07-26 13:27:03 -04:00
deferredMethodCallData - > mDeferDIType = deferDIType ;
2019-08-23 11:56:54 -07:00
}
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
// We don't actually want to see this, and it doesn't emit properly in LLVM CodeView anyway - it only accepts static allocs,
// not dynamic allocas
2022-07-26 13:27:03 -04:00
String varName = StrFormat ( " $__deferredCall_%d " , mCurMethodState - > mDeferredLoopListEntryCount ) ;
mCurMethodState - > mDeferredLoopListEntryCount + + ;
2019-08-23 11:56:54 -07:00
auto diVariable = mBfIRBuilder - > DbgCreateAutoVariable ( mCurMethodState - > mCurScope - > mDIScope ,
varName , mCurFilePosition . mFileInstance - > mDIFile , mCurFilePosition . mCurLine , deferDIType ) ;
2020-05-18 06:58:02 -07:00
mBfIRBuilder - > DbgInsertDeclare ( deferredAlloca , diVariable ) ;
2019-08-23 11:56:54 -07:00
}
return true ;
}
2021-01-13 05:09:09 -08:00
BfDeferredCallEntry * BfModule : : AddDeferredBlock ( BfBlock * block , BfScopeData * scopeData , Array < BfDeferredCapture > * captures )
2019-08-23 11:56:54 -07:00
{
BfDeferredCallEntry * deferredCallEntry = new BfDeferredCallEntry ( ) ;
deferredCallEntry - > mDeferredBlock = block ;
if ( captures ! = NULL )
deferredCallEntry - > mCaptures = * captures ;
2020-02-17 05:39:05 -08:00
AddDeferredCallEntry ( deferredCallEntry , scopeData ) ;
2021-01-13 05:09:09 -08:00
return deferredCallEntry ;
2019-08-23 11:56:54 -07:00
}
BfDeferredCallEntry * BfModule : : AddDeferredCall ( const BfModuleMethodInstance & moduleMethodInstance , SizedArrayImpl < BfIRValue > & llvmArgs , BfScopeData * scopeData , BfAstNode * srcNode , bool bypassVirtual , bool doNullCheck )
{
BfDeferredCallEntry * deferredCallEntry = new BfDeferredCallEntry ( ) ;
BF_ASSERT ( moduleMethodInstance ) ;
deferredCallEntry - > mModuleMethodInstance = moduleMethodInstance ;
for ( auto arg : llvmArgs )
{
2022-07-26 13:27:03 -04:00
deferredCallEntry - > mScopeArgs . push_back ( arg ) ;
2019-08-23 11:56:54 -07:00
}
deferredCallEntry - > mSrcNode = srcNode ;
deferredCallEntry - > mBypassVirtual = bypassVirtual ;
deferredCallEntry - > mDoNullCheck = doNullCheck ;
if ( ! AddDeferredCallEntry ( deferredCallEntry , scopeData ) )
return NULL ;
return deferredCallEntry ;
}
void BfModule : : EmitDeferredCall ( BfModuleMethodInstance moduleMethodInstance , SizedArrayImpl < BfIRValue > & llvmArgs , BfDeferredBlockFlags flags )
2022-07-26 13:27:03 -04:00
{
2020-05-18 06:58:02 -07:00
if ( moduleMethodInstance . mMethodInstance - > GetOwner ( ) - > IsInstanceOf ( mCompiler - > mInternalTypeDef ) )
{
if ( moduleMethodInstance . mMethodInstance - > mMethodDef - > mName . StartsWith ( " SetDeleted " ) )
2022-07-26 13:27:03 -04:00
{
2020-05-18 06:58:02 -07:00
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 " ) )
2022-07-26 13:27:03 -04:00
{
2020-05-18 06:58:02 -07:00
auto constant = mBfIRBuilder - > GetConstant ( llvmArgs [ 1 ] ) ;
if ( constant ! = NULL )
typeSize = constant - > mInt64 ;
constant = mBfIRBuilder - > GetConstant ( llvmArgs [ 2 ] ) ;
if ( constant ! = NULL )
typeAlign = constant - > mInt64 ;
2020-05-18 08:30:42 -07:00
if ( llvmArgs . size ( ) > = 4 )
2022-07-26 13:27:03 -04:00
arraySize = llvmArgs [ 3 ] ;
2020-05-18 06:58:02 -07:00
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 ;
2022-07-26 13:27:03 -04:00
}
2020-05-18 06:58:02 -07:00
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 ) ) ;
2020-05-18 09:12:03 -07:00
mBfIRBuilder - > CreateStore ( mBfIRBuilder - > CreateConst ( clearTypeCode , ( uint64 ) 0xDDDDDDDDDDDDDDDDULL ) , intPtrVal ) ;
2020-05-18 06:58:02 -07:00
mBfIRBuilder - > CreateBr ( ddDoneBlock ) ;
mBfIRBuilder - > AddBlock ( ddDoneBlock ) ;
mBfIRBuilder - > SetInsertPoint ( ddDoneBlock ) ;
2020-05-18 08:30:42 -07:00
if ( ( flags & BfDeferredBlockFlag_MoveNewBlocksToEnd ) ! = 0 )
2022-07-26 13:27:03 -04:00
{
2020-05-18 08:30:42 -07:00
mCurMethodState - > mCurScope - > mAtEndBlocks . push_back ( ddSize1Block ) ;
mCurMethodState - > mCurScope - > mAtEndBlocks . push_back ( ddDoneBlock ) ;
}
2020-05-18 06:58:02 -07:00
}
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 ) ) ;
2020-05-18 09:12:03 -07:00
mBfIRBuilder - > CreateStore ( mBfIRBuilder - > CreateConst ( BfTypeCode_IntPtr , ( uint64 ) 0xDDDDDDDDDDDDDDDDULL ) , intptrPtrVal ) ;
2020-05-18 06:58:02 -07:00
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 ) ) ;
2020-05-18 09:12:03 -07:00
mBfIRBuilder - > CreateStore ( mBfIRBuilder - > CreateConst ( clearTypeCode , ( uint64 ) 0xDDDDDDDDDDDDDDDDULL ) , intPtrVal ) ;
2020-05-18 06:58:02 -07:00
mBfIRBuilder - > CreateBr ( ddDoneBlock ) ;
mBfIRBuilder - > AddBlock ( ddDoneBlock ) ;
mBfIRBuilder - > SetInsertPoint ( ddDoneBlock ) ;
2020-05-18 08:30:42 -07:00
if ( ( flags & BfDeferredBlockFlag_MoveNewBlocksToEnd ) ! = 0 )
{
mCurMethodState - > mCurScope - > mAtEndBlocks . push_back ( ddSizePtrBlock ) ;
mCurMethodState - > mCurScope - > mAtEndBlocks . push_back ( ddCheck1Block ) ;
if ( mayBeZero )
mCurMethodState - > mCurScope - > mAtEndBlocks . push_back ( ddSize1Block ) ;
mCurMethodState - > mCurScope - > mAtEndBlocks . push_back ( ddDoneBlock ) ;
}
2020-05-18 06:58:02 -07:00
}
}
else
{
auto intPtrVal = mBfIRBuilder - > CreateBitCast ( ptrValue , mBfIRBuilder - > MapType ( intPtrType ) ) ;
2020-05-18 09:12:03 -07:00
mBfIRBuilder - > CreateStore ( mBfIRBuilder - > CreateConst ( clearTypeCode , ( uint64 ) 0xDDDDDDDDDDDDDDDDULL ) , intPtrVal ) ;
2020-05-18 06:58:02 -07:00
}
}
return ;
}
}
2019-08-23 11:56:54 -07:00
if ( moduleMethodInstance . mMethodInstance = = mContext - > mValueTypeDeinitSentinel )
{
BF_ASSERT ( llvmArgs . size ( ) = = 3 ) ;
auto sizeConstant = mBfIRBuilder - > GetConstant ( llvmArgs [ 1 ] ) ;
int clearSize = BF_MIN ( sizeConstant - > mInt32 , 32 ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
auto alignConstant = mBfIRBuilder - > GetConstant ( llvmArgs [ 2 ] ) ;
int clearAlign = alignConstant - > mInt32 ;
mBfIRBuilder - > CreateMemSet ( llvmArgs [ 0 ] , GetConstValue8 ( 0xDD ) , GetConstValue ( clearSize ) , clearAlign ) ;
return ;
}
auto methodInstance = moduleMethodInstance . mMethodInstance ;
auto methodOwner = methodInstance - > mMethodInstanceGroup - > mOwner ;
bool isDtor = methodInstance - > mMethodDef - > mMethodType = = BfMethodType_Dtor ;
bool isScopeDtor = isDtor & & ( ( flags & BfDeferredBlockFlag_BypassVirtual ) ! = 0 ) ;
if ( ( isDtor ) & & ( methodInstance - > GetParamCount ( ) ! = 0 ) )
{
// Dtor declared with params
2022-07-26 13:27:03 -04:00
AssertErrorState ( ) ;
2019-08-23 11:56:54 -07:00
return ;
}
BfIRBlock nullLabel ;
BfIRBlock notNullLabel ;
if ( ( flags & BfDeferredBlockFlag_DoNullChecks ) ! = 0 )
{
nullLabel = mBfIRBuilder - > CreateBlock ( " deferred.isNull " ) ;
notNullLabel = mBfIRBuilder - > CreateBlock ( " deferred.notNull " ) ;
auto notNullVal = mBfIRBuilder - > CreateIsNotNull ( llvmArgs [ 0 ] ) ;
mBfIRBuilder - > CreateCondBr ( notNullVal , notNullLabel , nullLabel ) ;
mBfIRBuilder - > AddBlock ( notNullLabel ) ;
mBfIRBuilder - > SetInsertPoint ( notNullLabel ) ;
}
bool skipAccessCheck = false ;
if ( ( flags & BfDeferredBlockFlag_SkipObjectAccessCheck ) ! = 0 )
skipAccessCheck = true ;
if ( ( ! methodInstance - > mMethodDef - > mIsStatic ) & & ( methodOwner - > IsObjectOrInterface ( ) ) & & ( ! isScopeDtor ) & &
( ! skipAccessCheck ) )
{
EmitObjectAccessCheck ( BfTypedValue ( llvmArgs [ 0 ] , methodOwner ) ) ;
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
BfExprEvaluator expressionEvaluator ( this ) ;
2020-12-14 03:50:28 -08:00
expressionEvaluator . CreateCall ( NULL , moduleMethodInstance . mMethodInstance , moduleMethodInstance . mFunc , ( ( flags & BfDeferredBlockFlag_BypassVirtual ) ! = 0 ) , llvmArgs ) ;
2019-08-23 11:56:54 -07:00
if ( ( flags & BfDeferredBlockFlag_DoNullChecks ) ! = 0 )
{
mBfIRBuilder - > CreateBr ( nullLabel ) ;
mBfIRBuilder - > AddBlock ( nullLabel ) ;
mBfIRBuilder - > SetInsertPoint ( nullLabel ) ;
if ( ! mBfIRBuilder - > mIgnoreWrites )
{
if ( ( flags & BfDeferredBlockFlag_MoveNewBlocksToEnd ) ! = 0 )
{
mCurMethodState - > mCurScope - > mAtEndBlocks . push_back ( notNullLabel ) ;
mCurMethodState - > mCurScope - > mAtEndBlocks . push_back ( nullLabel ) ;
}
}
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
}
2022-08-24 14:49:05 -07:00
void BfModule : : EmitDeferredCallProcessorInstances ( BfScopeData * scopeData )
{
BF_ASSERT ( scopeData - > mDone ) ;
for ( auto & deferredProcessor : scopeData - > mDeferredCallProcessorInstances )
{
SetAndRestoreValue < bool > prevHadReturn ( mCurMethodState - > mHadReturn , false ) ;
SetAndRestoreValue < bool > prevInPostReturn ( mCurMethodState - > mInPostReturn , false ) ;
SetAndRestoreValue < bool > prevLeftBlockUncond ( mCurMethodState - > mLeftBlockUncond , false ) ;
auto prevBlock = mBfIRBuilder - > GetInsertBlock ( ) ;
mBfIRBuilder - > AddBlock ( deferredProcessor . mProcessorBlock ) ;
mBfIRBuilder - > SetInsertPoint ( deferredProcessor . mProcessorBlock ) ;
EmitDeferredCallProcessor ( scopeData , deferredProcessor . mDeferredCallEntry - > mDynList , deferredProcessor . mDeferredCallEntry - > mDynCallTail ) ;
mBfIRBuilder - > CreateBr ( deferredProcessor . mContinueBlock ) ;
mBfIRBuilder - > SetInsertPoint ( prevBlock ) ;
}
}
void BfModule : : EmitDeferredCall ( BfScopeData * scopeData , BfDeferredCallEntry & deferredCallEntry , bool moveBlocks )
2022-07-26 13:27:03 -04:00
{
2021-01-08 16:21:03 -08:00
if ( ( mCompiler - > mIsResolveOnly ) & & ( ! mIsComptimeModule ) & & ( deferredCallEntry . mHandlerCount > 0 ) )
2019-08-23 11:56:54 -07:00
{
// We only want to process deferred blocks once, otherwise it could significantly slow down autocompletion
return ;
}
deferredCallEntry . mHandlerCount + + ;
if ( deferredCallEntry . IsDynList ( ) )
{
2022-08-24 14:49:05 -07:00
if ( scopeData - > mDone )
{
EmitDeferredCallProcessor ( scopeData , deferredCallEntry . mDynList , deferredCallEntry . mDynCallTail ) ;
}
else
{
BfDeferredCallProcessorInstance deferredProcessor ;
deferredProcessor . mProcessorBlock = mBfIRBuilder - > CreateBlock ( " dyn.processor " ) ;
deferredProcessor . mContinueBlock = mBfIRBuilder - > CreateBlock ( " dyn.continue " ) ;
deferredProcessor . mDeferredCallEntry = & deferredCallEntry ;
scopeData - > mDeferredCallProcessorInstances . Add ( deferredProcessor ) ;
mBfIRBuilder - > CreateBr ( deferredProcessor . mProcessorBlock ) ;
mBfIRBuilder - > AddBlock ( deferredProcessor . mContinueBlock ) ;
mBfIRBuilder - > SetInsertPoint ( deferredProcessor . mContinueBlock ) ;
2022-08-24 15:44:19 -07:00
SetIllegalSrcPos ( ) ;
EmitEnsureInstructionAt ( ) ;
2022-08-24 14:49:05 -07:00
}
2019-08-23 11:56:54 -07:00
return ;
}
if ( deferredCallEntry . mDeferredBlock ! = NULL )
{
// Only show warnings on the first pass
// For errors, show on the first pass OR as long as we haven't gotten any errors within this method. I'm not sure if there's a case
2022-07-26 13:27:03 -04:00
// where the first emission succeeds but a subsequent one would fail, but we leave this logic to handle that possibility
2019-08-23 11:56:54 -07:00
SetAndRestoreValue < bool > prevIgnoreErrors ( mIgnoreErrors , ( deferredCallEntry . mHandlerCount > 1 ) & & ( mCurMethodInstance - > mHasFailed ) ) ;
SetAndRestoreValue < bool > prevIgnoreWarnings ( mIgnoreWarnings , ( deferredCallEntry . mHandlerCount > 1 ) ) ;
BfScopeData scopeData ;
mCurMethodState - > AddScope ( & scopeData ) ;
NewScopeState ( ) ;
for ( auto & capture : deferredCallEntry . mCaptures )
{
BfLocalVariable * localVar = new BfLocalVariable ( ) ;
localVar - > mIsReadOnly = true ;
2020-09-21 13:58:00 -07:00
localVar - > mAssignedKind = BfLocalVarAssignKind_Unconditional ;
2019-08-23 11:56:54 -07:00
localVar - > mReadFromId = 0 ;
localVar - > mName = capture . mName ;
localVar - > mValue = capture . mValue . mValue ;
localVar - > mResolvedType = capture . mValue . mType ;
if ( ( mBfIRBuilder - > DbgHasInfo ( ) ) & & ( ! localVar - > mResolvedType - > IsValuelessType ( ) ) )
{
auto addr = CreateAlloca ( localVar - > mResolvedType ) ;
mBfIRBuilder - > CreateAlignedStore ( localVar - > mValue , addr , localVar - > mResolvedType - > mAlign ) ;
2022-07-26 13:27:03 -04:00
localVar - > mAddr = addr ;
}
2019-08-23 11:56:54 -07:00
AddLocalVariableDef ( localVar , true ) ;
}
2022-07-26 13:27:03 -04:00
2021-01-13 05:09:09 -08:00
SetAndRestoreValue < BfAstNode * > prevCustomAttribute ( mCurMethodState - > mEmitRefNode , deferredCallEntry . mEmitRefNode ) ;
2022-07-26 13:27:03 -04:00
VisitEmbeddedStatement ( deferredCallEntry . mDeferredBlock , NULL , BfEmbeddedStatementFlags_IsDeferredBlock ) ;
2019-08-23 11:56:54 -07:00
RestoreScopeState ( ) ;
return ;
}
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
auto args = deferredCallEntry . mScopeArgs ;
if ( deferredCallEntry . mArgsNeedLoad )
{
for ( auto & arg : args )
{
if ( ! arg . IsConst ( ) )
arg = mBfIRBuilder - > CreateLoad ( arg ) ;
}
}
if ( deferredCallEntry . mCastThis )
{
args [ 0 ] = mBfIRBuilder - > CreateBitCast ( args [ 0 ] , mBfIRBuilder - > MapTypeInstPtr ( deferredCallEntry . mModuleMethodInstance . mMethodInstance - > GetOwner ( ) ) ) ;
}
BfDeferredBlockFlags flags = BfDeferredBlockFlag_None ;
if ( deferredCallEntry . mBypassVirtual )
flags = ( BfDeferredBlockFlags ) ( flags | BfDeferredBlockFlag_BypassVirtual ) ;
if ( deferredCallEntry . mDoNullCheck )
flags = ( BfDeferredBlockFlags ) ( flags | BfDeferredBlockFlag_DoNullChecks | BfDeferredBlockFlag_SkipObjectAccessCheck | BfDeferredBlockFlag_MoveNewBlocksToEnd ) ;
2020-05-18 08:30:42 -07:00
if ( moveBlocks )
flags = ( BfDeferredBlockFlags ) ( flags | BfDeferredBlockFlag_MoveNewBlocksToEnd ) ;
2019-08-23 11:56:54 -07:00
EmitDeferredCall ( deferredCallEntry . mModuleMethodInstance , args , flags ) ;
}
2022-08-24 14:49:05 -07:00
void BfModule : : EmitDeferredCallProcessor ( BfScopeData * scopeData , SLIList < BfDeferredCallEntry * > & callEntries , BfIRValue callTail )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
int64 collisionId = 0 ;
struct _CallInfo
{
BfModuleMethodInstance mModuleMethodInstance ;
bool mBypassVirtual ;
} ;
//typedef std::map<int64, _CallInfo> MapType;
//MapType methodInstanceMap;
2022-07-26 13:27:03 -04:00
Dictionary < int64 , _CallInfo > methodInstanceMap ;
2019-08-23 11:56:54 -07:00
int blockCount = 0 ;
HashSet < BfMethodInstance * > nullCheckMethodSet ;
BfDeferredCallEntry * deferredCallEntry = callEntries . mHead ;
while ( deferredCallEntry ! = NULL )
{
2022-07-26 13:27:03 -04:00
BfModuleMethodInstance moduleMethodInstance = deferredCallEntry - > mModuleMethodInstance ;
2019-08-23 11:56:54 -07:00
int64 methodId = 0 ;
if ( moduleMethodInstance . mMethodInstance ! = NULL )
{
int64 idHash = moduleMethodInstance . mMethodInstance - > mIdHash ;
auto deferredMethodCallData = mDeferredMethodCallData [ moduleMethodInstance . mMethodInstance ] ;
BF_ASSERT ( deferredMethodCallData - > mMethodId ! = 0 ) ;
//methodInstanceMap[deferredMethodCallData->mMethodId] = moduleMethodInstance;
_CallInfo * callInfo = NULL ;
if ( methodInstanceMap . TryAdd ( deferredMethodCallData - > mMethodId , NULL , & callInfo ) )
{
callInfo - > mModuleMethodInstance = moduleMethodInstance ;
callInfo - > mBypassVirtual = deferredCallEntry - > mBypassVirtual ;
}
else
{
// Only bypass virtual if ALL these calls are devirtualized
callInfo - > mBypassVirtual & = deferredCallEntry - > mBypassVirtual ;
}
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
else
blockCount + + ;
if ( deferredCallEntry - > mDoNullCheck )
nullCheckMethodSet . Add ( deferredCallEntry - > mModuleMethodInstance . mMethodInstance ) ;
deferredCallEntry = deferredCallEntry - > mNext ;
}
bool moveBlocks = mCurMethodState - > mCurScope ! = mCurMethodState - > mTailScope ;
auto valueScopeStart = ValueScopeStart ( ) ;
if ( valueScopeStart )
mBfIRBuilder - > SetName ( valueScopeStart , " deferredScopeVal " ) ;
BfIRBlock condBB = mBfIRBuilder - > CreateBlock ( " deferCall.cond " , true ) ;
if ( moveBlocks )
mCurMethodState - > mCurScope - > mAtEndBlocks . push_back ( condBB ) ;
2022-07-26 13:27:03 -04:00
mBfIRBuilder - > CreateBr ( condBB ) ;
2019-08-23 11:56:54 -07:00
auto deferredCallEntryType = ResolveTypeDef ( mCompiler - > mDeferredCallTypeDef ) ;
auto deferredCallEntryTypePtr = CreatePointerType ( deferredCallEntryType ) ;
2022-07-26 13:27:03 -04:00
BfIRBlock bodyBB = mBfIRBuilder - > CreateBlock ( " deferCall.body " ) ;
2019-08-23 11:56:54 -07:00
if ( moveBlocks )
mCurMethodState - > mCurScope - > mAtEndBlocks . push_back ( bodyBB ) ;
BfIRBlock endBB = mBfIRBuilder - > CreateBlock ( " deferCall.end " ) ;
if ( moveBlocks )
mCurMethodState - > mCurScope - > mAtEndBlocks . push_back ( endBB ) ;
BfIRBlock exitBB = endBB ;
BfIRValue deferredCallTail ;
mBfIRBuilder - > SetInsertPoint ( condBB ) ;
2022-07-26 13:27:03 -04:00
deferredCallTail = mBfIRBuilder - > CreateLoad ( callTail ) ;
2019-08-23 11:56:54 -07:00
auto isNotNull = mBfIRBuilder - > CreateIsNotNull ( deferredCallTail ) ;
ValueScopeEnd ( valueScopeStart ) ;
2022-07-26 13:27:03 -04:00
mBfIRBuilder - > CreateCondBr ( isNotNull , bodyBB , exitBB ) ;
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > AddBlock ( bodyBB ) ;
mBfIRBuilder - > SetInsertPoint ( bodyBB ) ;
2022-07-26 13:27:03 -04:00
BfIRValue switchInst ;
2019-08-23 11:56:54 -07:00
bool wantsSwitch = ( ( int ) methodInstanceMap . size ( ) + blockCount ) > 1 ;
if ( blockCount > 0 )
{
// A block may embed a switch so we need a switch whenever we have blocks
wantsSwitch = true ;
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
if ( mCurMethodState - > mCancelledDeferredCall )
wantsSwitch = true ;
if ( wantsSwitch )
{
if ( IsTargetingBeefBackend ( ) )
deferredCallTail = mBfIRBuilder - > CreateLoad ( callTail ) ;
auto idPtr = mBfIRBuilder - > CreateInBoundsGEP ( deferredCallTail , 0 , 1 ) ; // mMethodId
2022-07-26 13:27:03 -04:00
auto id = mBfIRBuilder - > CreateLoad ( idPtr ) ;
2019-08-23 11:56:54 -07:00
switchInst = mBfIRBuilder - > CreateSwitch ( id , exitBB , ( int ) methodInstanceMap . size ( ) ) ;
ValueScopeEnd ( valueScopeStart ) ;
}
BfDeferredCallEntry * prevHead = callEntries . mHead ;
BfDeferredCallEntry * prevCallEntry = NULL ;
HashSet < BfDeferredCallEntry * > handledSet ;
deferredCallEntry = callEntries . mHead ;
while ( deferredCallEntry ! = NULL )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
auto block = deferredCallEntry - > mDeferredBlock ;
if ( block = = NULL )
{
deferredCallEntry = deferredCallEntry - > mNext ;
continue ;
}
2019-12-13 14:22:23 -08:00
int64 blockId = deferredCallEntry - > mBlockId ;
2019-08-23 11:56:54 -07:00
//auto itr = handledSet.insert(deferredCallEntry);
//if (!itr.second)
if ( ! handledSet . Add ( deferredCallEntry ) )
{
// Already handled, can happen if we defer again within the block
deferredCallEntry = deferredCallEntry - > mNext ;
continue ;
}
if ( switchInst )
{
String caseName = StrFormat ( " deferCall.%s " , BfTypeUtils : : HashEncode64 ( blockId ) . c_str ( ) ) ;
auto caseBB = mBfIRBuilder - > CreateBlock ( caseName , true ) ;
if ( moveBlocks )
mCurMethodState - > mCurScope - > mAtEndBlocks . push_back ( caseBB ) ;
mBfIRBuilder - > AddSwitchCase ( switchInst , GetConstValue64 ( blockId ) , caseBB ) ;
mBfIRBuilder - > SetInsertPoint ( caseBB ) ;
}
// Update .mDeferredAlloca to use the deferredCallTail
if ( IsTargetingBeefBackend ( ) )
deferredCallTail = mBfIRBuilder - > CreateLoad ( callTail ) ;
auto nextPtr = mBfIRBuilder - > CreateInBoundsGEP ( deferredCallTail , 0 , 2 ) ; // mNext
auto next = mBfIRBuilder - > CreateLoad ( nextPtr ) ;
mBfIRBuilder - > CreateStore ( next , callTail ) ;
deferredCallEntry - > mDeferredAlloca = mBfIRBuilder - > CreateBitCast ( deferredCallTail , mBfIRBuilder - > GetType ( deferredCallEntry - > mDeferredAlloca ) ) ;
int dataIdx = 3 ;
// Update .mCaptures to contain the stored values at the time the defer occurred
for ( int captureIdx = 0 ; captureIdx < ( int ) deferredCallEntry - > mCaptures . size ( ) ; captureIdx + + )
{
auto & capture = deferredCallEntry - > mCaptures [ captureIdx ] ;
if ( ! capture . mValue . mType - > IsValuelessType ( ) )
{
auto gepInstance = mBfIRBuilder - > CreateInBoundsGEP ( deferredCallEntry - > mDeferredAlloca , 0 , dataIdx ) ;
capture . mValue . mValue = mBfIRBuilder - > CreateLoad ( gepInstance ) ;
dataIdx + + ;
}
}
auto prevHead = callEntries . mHead ;
2022-08-24 14:49:05 -07:00
EmitDeferredCall ( scopeData , * deferredCallEntry , moveBlocks ) ;
2019-08-23 11:56:54 -07:00
ValueScopeEnd ( valueScopeStart ) ;
mBfIRBuilder - > CreateBr ( condBB ) ;
if ( prevHead ! = callEntries . mHead )
{
// The list changed, start over and ignore anything we've already handled
deferredCallEntry = callEntries . mHead ;
}
else
deferredCallEntry = deferredCallEntry - > mNext ;
}
// Blocks may have added new method types, so rebuild map
if ( blockCount > 0 )
{
deferredCallEntry = callEntries . mHead ;
while ( deferredCallEntry ! = NULL )
{
BfModuleMethodInstance moduleMethodInstance = deferredCallEntry - > mModuleMethodInstance ;
if ( moduleMethodInstance . mMethodInstance ! = NULL )
{
2022-07-26 13:27:03 -04:00
auto deferredMethodCallData = mDeferredMethodCallData [ moduleMethodInstance . mMethodInstance ] ;
2019-08-23 11:56:54 -07:00
//methodInstanceMap.insert(MapType::value_type(deferredMethodCallData->mMethodId, moduleMethodInstance));
_CallInfo * callInfo = NULL ;
if ( methodInstanceMap . TryAdd ( deferredMethodCallData - > mMethodId , NULL , & callInfo ) )
{
callInfo - > mModuleMethodInstance = moduleMethodInstance ;
callInfo - > mBypassVirtual = deferredCallEntry - > mBypassVirtual ;
}
}
deferredCallEntry = deferredCallEntry - > mNext ;
}
}
BfExprEvaluator exprEvaluator ( this ) ;
//for (auto itr = methodInstanceMap.begin(); itr != methodInstanceMap.end(); ++itr)
for ( auto & callInfoKV : methodInstanceMap )
{
auto moduleMethodInstance = callInfoKV . mValue . mModuleMethodInstance ;
bool bypassVirtual = callInfoKV . mValue . mBypassVirtual ;
auto methodInstance = moduleMethodInstance . mMethodInstance ;
auto methodDef = methodInstance - > mMethodDef ;
auto methodOwner = methodInstance - > mMethodInstanceGroup - > mOwner ;
BfIRValue deferredCallInst = deferredCallTail ;
auto deferredMethodCallData = mDeferredMethodCallData [ methodInstance ] ;
int64 methodId = deferredMethodCallData - > mMethodId ;
if ( switchInst )
{
String caseName = StrFormat ( " deferCall.%s " , BfTypeUtils : : HashEncode64 ( methodId ) . c_str ( ) ) ;
auto caseBB = mBfIRBuilder - > CreateBlock ( caseName , true ) ;
if ( moveBlocks )
mCurMethodState - > mCurScope - > mAtEndBlocks . push_back ( caseBB ) ;
mBfIRBuilder - > AddSwitchCase ( switchInst , GetConstValue64 ( methodId ) , caseBB ) ;
2022-07-26 13:27:03 -04:00
mBfIRBuilder - > SetInsertPoint ( caseBB ) ;
2019-08-23 11:56:54 -07:00
}
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
if ( IsTargetingBeefBackend ( ) )
2022-07-26 13:27:03 -04:00
deferredCallTail = mBfIRBuilder - > CreateLoad ( callTail ) ;
2019-08-23 11:56:54 -07:00
auto nextPtr = mBfIRBuilder - > CreateInBoundsGEP ( deferredCallTail , 0 , 2 ) ; // mNext
auto next = mBfIRBuilder - > CreateLoad ( nextPtr ) ;
mBfIRBuilder - > CreateStore ( next , callTail ) ;
2022-07-26 13:27:03 -04:00
deferredCallInst = mBfIRBuilder - > CreateBitCast ( deferredCallTail , deferredMethodCallData - > mDeferTypePtr ) ;
2019-08-23 11:56:54 -07:00
int paramIdx = 0 ;
if ( ! methodDef - > mIsStatic )
paramIdx = - 1 ;
2022-07-26 13:27:03 -04:00
SizedArray < BfIRValue , 8 > llvmArgs ;
2019-08-23 11:56:54 -07:00
for ( int argIdx = 0 ; paramIdx < methodInstance - > GetParamCount ( ) ; argIdx + + , paramIdx + + )
{
auto argPtr = mBfIRBuilder - > CreateInBoundsGEP ( deferredCallInst , 0 , argIdx + 2 ) ;
bool isStruct = false ;
bool doSplat = methodInstance - > GetParamIsSplat ( paramIdx ) ; ;
2022-07-26 13:27:03 -04:00
BfTypedValue typedVal ;
2019-08-23 11:56:54 -07:00
if ( paramIdx = = - 1 )
{
2022-07-26 13:27:03 -04:00
typedVal = BfTypedValue ( argPtr , methodOwner , true ) ;
2019-08-23 11:56:54 -07:00
}
else
{
auto paramType = methodInstance - > GetParamType ( paramIdx ) ;
typedVal = BfTypedValue ( argPtr , paramType , true ) ;
}
if ( doSplat )
{
exprEvaluator . SplatArgs ( typedVal , llvmArgs ) ;
continue ;
}
if ( ( argIdx = = 0 ) & & ( ! methodDef - > mIsStatic ) )
{
// 'this'
2023-01-23 06:56:05 -05:00
isStruct = methodOwner - > IsValueType ( ) ;
2019-08-23 11:56:54 -07:00
}
else
{
while ( methodInstance - > IsParamSkipped ( paramIdx ) )
paramIdx + + ;
if ( paramIdx > = methodInstance - > GetParamCount ( ) )
break ;
auto paramType = methodInstance - > GetParamType ( paramIdx ) ;
2022-07-26 13:27:03 -04:00
isStruct = paramType - > IsStruct ( ) ;
2019-08-23 11:56:54 -07:00
}
if ( isStruct )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
llvmArgs . push_back ( argPtr ) ;
}
else
{
auto arg = mBfIRBuilder - > CreateLoad ( argPtr ) ;
llvmArgs . push_back ( arg ) ;
}
}
BfDeferredBlockFlags flags = BfDeferredBlockFlag_None ;
if ( moveBlocks )
flags = ( BfDeferredBlockFlags ) ( flags | BfDeferredBlockFlag_MoveNewBlocksToEnd ) ;
if ( nullCheckMethodSet . Contains ( moduleMethodInstance . mMethodInstance ) )
flags = ( BfDeferredBlockFlags ) ( flags | BfDeferredBlockFlag_DoNullChecks | BfDeferredBlockFlag_SkipObjectAccessCheck ) ;
if ( bypassVirtual )
flags = ( BfDeferredBlockFlags ) ( flags | BfDeferredBlockFlag_BypassVirtual ) ;
EmitDeferredCall ( moduleMethodInstance , llvmArgs , flags ) ;
ValueScopeEnd ( valueScopeStart ) ;
mBfIRBuilder - > CreateBr ( condBB ) ;
}
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
if ( endBB )
{
mBfIRBuilder - > AddBlock ( endBB ) ;
mBfIRBuilder - > SetInsertPoint ( endBB ) ;
}
}
void BfModule : : TryInitVar ( BfAstNode * checkNode , BfLocalVariable * localVar , BfTypedValue initValue , BfTypedValue & checkResult )
{
BF_ASSERT ( ! localVar - > mAddr ) ;
localVar - > mAddr = AllocLocalVariable ( localVar - > mResolvedType , localVar - > mName ) ;
auto boolType = GetPrimitiveType ( BfTypeCode_Boolean ) ;
auto varType = localVar - > mResolvedType ;
AddDependency ( varType , mCurTypeInstance , BfDependencyMap : : DependencyFlag_ExprTypeReference ) ;
if ( ! initValue )
{
AssertErrorState ( ) ;
checkResult = BfTypedValue ( mBfIRBuilder - > CreateConst ( BfTypeCode_Boolean , 0 ) , boolType ) ;
return ;
}
auto initType = initValue . mType ;
bool isDynamicCast = false ;
if ( varType - > IsGenericParam ( ) )
2022-07-26 13:27:03 -04:00
{
2022-06-11 07:56:43 -07:00
int pass = 0 ;
while ( varType - > IsGenericParam ( ) )
{
auto genericParamType = ( BfGenericParamType * ) varType ;
auto genericParam = GetGenericParamInstance ( genericParamType ) ;
auto typeConstraint = genericParam - > mTypeConstraint ;
if ( ( typeConstraint = = NULL ) & & ( genericParam - > mGenericParamFlags & ( BfGenericParamFlag_Class | BfGenericParamFlag_Interface ) ) )
typeConstraint = mContext - > mBfObjectType ;
if ( typeConstraint ! = NULL )
varType = typeConstraint ;
else
break ;
if ( + + pass > = 100 ) // Sanity - but we should have caught circular error before
break ;
}
initValue = GetDefaultTypedValue ( varType , false , BfDefaultValueKind_Undef ) ;
2019-08-23 11:56:54 -07:00
}
BfTypeInstance * srcTypeInstance = initValue . mType - > ToTypeInstance ( ) ;
BfTypeInstance * varTypeInstance = varType - > ToTypeInstance ( ) ;
2020-01-24 10:36:22 -08:00
if ( CanCast ( initValue , varType ) )
2019-08-23 11:56:54 -07:00
{
2022-01-19 10:38:20 -05:00
if ( ( ! varType - > IsPointer ( ) ) & & ( ! varType - > IsObjectOrInterface ( ) ) & & ( ! varType - > IsVar ( ) ) )
2019-08-23 11:56:54 -07:00
{
if ( ! IsInSpecializedSection ( ) )
{
if ( initValue . mType ! = varType )
2022-07-26 13:27:03 -04:00
Warn ( BfWarning_CS0472_ValueTypeNullCompare , StrFormat ( " Variable declaration is always 'true' because static cast cannot fail and a value of type '%s' can never be null " ,
TypeToString ( varType ) . c_str ( ) ) , checkNode ) ;
2019-08-23 11:56:54 -07:00
else
2022-07-26 13:27:03 -04:00
Warn ( BfWarning_CS0472_ValueTypeNullCompare , StrFormat ( " Variable declaration is always 'true' because a value of type '%s' can never be null " ,
2019-08-23 11:56:54 -07:00
TypeToString ( varType ) . c_str ( ) ) , checkNode ) ;
}
}
}
// else if ((initType->IsInterface()) || (initType == mContext->mBfObjectType))
// {
// // Interface or System.Object -> *
// isDynamicCast = true;
// }
// else if ((srcTypeInstance != NULL) && (varTypeInstance != NULL) &&
// ((srcTypeInstance->IsObject()) && (TypeIsSubTypeOf(varTypeInstance, srcTypeInstance))))
// {
// // Class downcast
// isDynamicCast = true;
// }
2020-01-24 10:36:22 -08:00
// else if ((!CanCast(GetFakeTypedValue(varType), initType)) && (!initType->IsGenericParam()))
2019-08-23 11:56:54 -07:00
// {
// if (!IsInSpecializedSection())
// {
// Fail(StrFormat("Cannot convert type '%s' to '%s' via any conversion",
// TypeToString(initValue.mType).c_str(), TypeToString(varType).c_str()), checkNode);
// }
// }
if ( ! isDynamicCast )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
//initValue = Cast(checkNode, initValue, varType, (BfCastFlags)(BfCastFlags_Explicit | BfCastFlags_SilentFail));
initValue = Cast ( checkNode , initValue , varType ) ;
if ( ! initValue )
{
checkResult = BfTypedValue ( GetConstValue ( 0 , boolType ) , boolType ) ;
}
2022-07-26 13:27:03 -04:00
else
2019-08-23 11:56:54 -07:00
{
if ( localVar - > mAddr )
{
initValue = LoadValue ( initValue ) ;
2021-08-27 10:08:01 -07:00
if ( ! initValue . mType - > IsVar ( ) )
mBfIRBuilder - > CreateAlignedStore ( initValue . mValue , localVar - > mAddr , initValue . mType - > mAlign ) ;
2019-08-23 11:56:54 -07:00
}
2022-01-19 10:38:20 -05:00
if ( varType - > IsVar ( ) )
{
checkResult = GetDefaultTypedValue ( boolType , false , BfDefaultValueKind_Undef ) ;
}
else if ( ( varType - > IsPointer ( ) ) | | ( varType - > IsObjectOrInterface ( ) ) )
2019-08-23 11:56:54 -07:00
{
checkResult = BfTypedValue ( mBfIRBuilder - > CreateIsNotNull ( initValue . mValue ) , boolType ) ;
}
else
{
checkResult = BfTypedValue ( GetConstValue ( 1 , boolType ) , boolType ) ;
}
}
return ;
}
if ( mCompiler - > IsAutocomplete ( ) )
{
auto allocaResult = mBfIRBuilder - > CreateAlloca ( mBfIRBuilder - > MapType ( boolType ) ) ;
auto val = mBfIRBuilder - > CreateLoad ( allocaResult ) ;
checkResult = BfTypedValue ( val , boolType ) ;
return ;
}
int wantTypeId = 0 ;
if ( ! varType - > IsGenericParam ( ) )
wantTypeId = varType - > mTypeId ;
auto objectType = mContext - > mBfObjectType ;
PopulateType ( objectType , BfPopulateType_Full ) ;
initValue = LoadValue ( initValue ) ;
auto prevBB = mBfIRBuilder - > GetInsertBlock ( ) ;
auto matchBB = mBfIRBuilder - > CreateBlock ( " is.match " ) ;
auto endBB = mBfIRBuilder - > CreateBlock ( " is.done " ) ;
BfIRValue boolResult = CreateAlloca ( boolType ) ;
mBfIRBuilder - > CreateStore ( mBfIRBuilder - > CreateConst ( BfTypeCode_Boolean , 0 ) , boolResult ) ;
EmitDynamicCastCheck ( initValue , varType , matchBB , endBB ) ;
AddBasicBlock ( matchBB ) ;
mBfIRBuilder - > CreateStore ( mBfIRBuilder - > CreateConst ( BfTypeCode_Boolean , 1 ) , boolResult ) ;
mBfIRBuilder - > CreateBr ( endBB ) ;
AddBasicBlock ( endBB ) ;
checkResult = BfTypedValue ( mBfIRBuilder - > CreateLoad ( boolResult ) , boolType ) ;
}
BfLocalVariable * BfModule : : HandleVariableDeclaration ( BfVariableDeclaration * varDecl , BfExprEvaluator * exprEvaluator )
{
if ( mCurMethodState = = NULL )
{
Fail ( " Invalid variable declaration " , varDecl ) ;
return NULL ;
}
BfAutoComplete * bfAutocomplete = NULL ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
// Just a check
mBfIRBuilder - > GetInsertBlock ( ) ;
if ( mCompiler - > mResolvePassData ! = NULL )
2022-07-26 13:27:03 -04:00
bfAutocomplete = mCompiler - > mResolvePassData - > mAutoComplete ;
if ( bfAutocomplete ! = NULL )
bfAutocomplete - > CheckTypeRef ( varDecl - > mTypeRef , true , true ) ;
2019-08-23 11:56:54 -07:00
bool isConst = ( varDecl - > mModSpecifier ! = NULL ) & & ( varDecl - > mModSpecifier - > GetToken ( ) = = BfToken_Const ) ;
bool isReadOnly = ( varDecl - > mModSpecifier ! = NULL ) & & ( varDecl - > mModSpecifier - > GetToken ( ) = = BfToken_ReadOnly ) ;
2022-02-11 10:38:57 -05:00
bool isStatic = ( varDecl - > mModSpecifier ! = NULL ) & & ( varDecl - > mModSpecifier - > GetToken ( ) = = BfToken_Static ) ;
2019-08-23 11:56:54 -07:00
BfLocalVariable * localDef = new BfLocalVariable ( ) ;
if ( varDecl - > mNameNode ! = NULL )
{
2019-11-19 09:58:35 -08:00
varDecl - > mNameNode - > ToString ( localDef - > mName ) ;
2019-08-23 11:56:54 -07:00
localDef - > mNameNode = BfNodeDynCast < BfIdentifierNode > ( varDecl - > mNameNode ) ;
}
else
{
localDef - > mName = " val " ;
}
2022-02-11 10:38:57 -05:00
localDef - > mIsStatic = isStatic ;
2019-08-23 11:56:54 -07:00
bool handledExprBoolResult = false ;
bool handledVarInit = false ;
bool handledVarStore = false ;
BfType * unresolvedType = NULL ;
BfType * resolvedType = NULL ;
BfTypedValue initValue ;
bool hadVarType = false ;
bool isLet = varDecl - > mTypeRef - > IsA < BfLetTypeReference > ( ) ;
bool initHandled = false ;
auto _DoConditionalInit = [ & ] ( BfType * expectedType )
{
auto boolType = GetPrimitiveType ( BfTypeCode_Boolean ) ;
auto _EmitCond = [ & ] ( BfIRValue condVal , BfTypedValue initValue )
{
initValue = Cast ( varDecl - > mInitializer , initValue , expectedType ) ;
if ( ! initValue )
return ;
initHandled = true ;
if ( localDef - > mIsReadOnly )
{
if ( ( initValue . IsReadOnly ( ) ) | |
( initValue . mKind = = BfTypedValueKind_TempAddr ) )
{
localDef - > mAddr = initValue . mValue ;
exprEvaluator - > mResult = BfTypedValue ( condVal , boolType ) ;
return ;
}
}
localDef - > mAddr = AllocLocalVariable ( resolvedType , localDef - > mName ) ;
auto doAssignBlock = mBfIRBuilder - > CreateBlock ( " assign " ) ;
auto skipAssignBlock = mBfIRBuilder - > CreateBlock ( " skipAssign " ) ;
auto insertBlock = mBfIRBuilder - > GetInsertBlock ( ) ;
mBfIRBuilder - > CreateCondBr ( condVal , doAssignBlock , skipAssignBlock ) ;
mBfIRBuilder - > AddBlock ( doAssignBlock ) ;
mBfIRBuilder - > SetInsertPoint ( doAssignBlock ) ;
initValue = LoadValue ( initValue ) ;
mBfIRBuilder - > CreateStore ( initValue . mValue , localDef - > mAddr ) ;
mBfIRBuilder - > CreateBr ( skipAssignBlock ) ;
mBfIRBuilder - > AddBlock ( skipAssignBlock ) ;
mBfIRBuilder - > SetInsertPoint ( skipAssignBlock ) ;
auto phiVal = mBfIRBuilder - > CreatePhi ( mBfIRBuilder - > MapType ( boolType ) , 2 ) ;
mBfIRBuilder - > AddPhiIncoming ( phiVal , mBfIRBuilder - > CreateConst ( BfTypeCode_Boolean , 0 ) , insertBlock ) ;
mBfIRBuilder - > AddPhiIncoming ( phiVal , mBfIRBuilder - > CreateConst ( BfTypeCode_Boolean , 1 ) , doAssignBlock ) ;
2022-07-26 13:27:03 -04:00
exprEvaluator - > mResult = BfTypedValue ( phiVal , boolType ) ;
2019-08-23 11:56:54 -07:00
} ;
bool handled = false ;
if ( ( initValue ) & & ( initValue . mType - > IsPayloadEnum ( ) ) )
{
auto typeInst = initValue . mType - > ToTypeInstance ( ) ;
PopulateType ( typeInst ) ;
BfType * outType = NULL ;
int tagId = - 1 ;
if ( typeInst - > GetResultInfo ( outType , tagId ) )
{
int dscDataIdx = - 1 ;
auto dscType = typeInst - > GetDiscriminatorType ( & dscDataIdx ) ;
BfIRValue dscVal = ExtractValue ( initValue , dscDataIdx ) ;
auto eqVal = mBfIRBuilder - > CreateCmpEQ ( dscVal , GetConstValue ( tagId , dscType ) ) ;
exprEvaluator - > mResult = BfTypedValue ( eqVal , boolType ) ;
2022-07-26 13:27:03 -04:00
2022-02-17 05:51:05 -05:00
PopulateType ( outType ) ;
2019-08-23 11:56:54 -07:00
if ( ! outType - > IsValuelessType ( ) )
{
auto outPtrType = CreatePointerType ( outType ) ;
initValue = MakeAddressable ( initValue ) ;
auto payloadVal = mBfIRBuilder - > CreateBitCast ( initValue . mValue , mBfIRBuilder - > MapType ( outPtrType ) ) ;
auto payload = BfTypedValue ( payloadVal , outType , true ) ;
if ( ( initValue . mKind = = BfTypedValueKind_ReadOnlyAddr ) | |
( initValue . mKind = = BfTypedValueKind_TempAddr ) | |
( initValue . mKind = = BfTypedValueKind_ReadOnlyTempAddr ) )
payload . mKind = initValue . mKind ;
_EmitCond ( eqVal , payload ) ;
}
handled = true ;
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
}
if ( handled )
{
handledExprBoolResult = true ;
handledVarInit = true ;
handledVarStore = true ;
}
else if ( ( initValue ) & & ( initValue . mType - > IsNullable ( ) ) )
{
auto underlyingType = initValue . mType - > GetUnderlyingType ( ) ;
exprEvaluator - > mResult = BfTypedValue ( ExtractValue ( initValue , 2 ) , boolType ) ;
handledExprBoolResult = true ;
if ( ! resolvedType - > IsNullable ( ) )
{
if ( initValue . IsAddr ( ) )
initValue = BfTypedValue ( mBfIRBuilder - > CreateInBoundsGEP ( initValue . mValue , 0 , 1 ) , initValue . mType - > GetUnderlyingType ( ) , true ) ;
else
initValue = BfTypedValue ( mBfIRBuilder - > CreateExtractValue ( initValue . mValue , 1 ) , initValue . mType - > GetUnderlyingType ( ) ) ;
}
if ( ( initValue ) & & ( ! initValue . mType - > IsValuelessType ( ) ) )
{
_EmitCond ( exprEvaluator - > mResult . mValue , initValue ) ;
handledVarStore = true ;
}
handledVarInit = true ;
}
else if ( initValue )
{
BfAstNode * refNode = varDecl ;
if ( varDecl - > mInitializer ! = NULL )
refNode = varDecl - > mInitializer ;
TryInitVar ( refNode , localDef , initValue , exprEvaluator - > mResult ) ;
handledExprBoolResult = true ;
handledVarInit = true ;
handledVarStore = true ;
}
2022-07-26 13:27:03 -04:00
} ;
2019-08-23 11:56:54 -07:00
if ( ( varDecl - > mTypeRef - > IsA < BfVarTypeReference > ( ) ) | | ( isLet ) )
{
hadVarType = true ;
if ( varDecl - > mInitializer = = NULL )
{
if ( ! isLet )
{
BfLocalVarEntry * shadowEntry ;
if ( mCurMethodState - > mLocalVarSet . TryGet ( BfLocalVarEntry ( localDef ) , & shadowEntry ) )
{
auto prevLocal = shadowEntry - > mLocalVar ;
2022-07-26 13:27:03 -04:00
if ( prevLocal - > mLocalVarIdx > = mCurMethodState - > GetLocalStartIdx ( ) )
2019-08-23 11:56:54 -07:00
{
BfExprEvaluator exprEvaluator ( this ) ;
initValue = exprEvaluator . LoadLocal ( prevLocal ) ;
resolvedType = initValue . mType ;
unresolvedType = resolvedType ;
localDef - > mLocalVarId = prevLocal - > mLocalVarId ;
2020-09-21 13:58:00 -07:00
localDef - > mAssignedKind = BfLocalVarAssignKind_Unconditional ;
2019-08-23 11:56:54 -07:00
localDef - > mIsShadow = true ;
exprEvaluator . mResultLocalVarRefNode = varDecl - > mNameNode ;
exprEvaluator . mResultLocalVar = prevLocal ;
exprEvaluator . CheckResultForReading ( initValue ) ;
if ( bfAutocomplete ! = NULL )
bfAutocomplete - > CheckVarResolution ( varDecl - > mTypeRef , resolvedType ) ;
}
}
}
if ( ! initValue )
{
Fail ( " Implicitly-typed variables must be initialized " , varDecl ) ;
initValue = GetDefaultTypedValue ( mContext - > mBfObjectType ) ;
}
}
else
{
if ( isConst )
{
BfConstResolver constResolver ( this ) ;
initValue = constResolver . Resolve ( varDecl - > mInitializer ) ;
}
else
{
BfExprEvaluator valExprEvaluator ( this ) ;
valExprEvaluator . mAllowReadOnlyReference = isLet ;
initValue = CreateValueFromExpression ( valExprEvaluator , varDecl - > mInitializer , NULL , ( BfEvalExprFlags ) ( BfEvalExprFlags_AllowSplat | BfEvalExprFlags_AllowRefExpr | BfEvalExprFlags_VariableDeclaration ) ) ;
if ( ( exprEvaluator ! = NULL ) & & ( initValue ) )
{
if ( initValue . mType - > IsNullable ( ) )
{
auto boolType = GetPrimitiveType ( BfTypeCode_Boolean ) ;
initValue = LoadValue ( initValue ) ;
exprEvaluator - > mResult = BfTypedValue ( mBfIRBuilder - > CreateExtractValue ( initValue . mValue , 2 ) , boolType ) ;
handledExprBoolResult = true ;
initValue = BfTypedValue ( mBfIRBuilder - > CreateExtractValue ( initValue . mValue , 1 ) , initValue . mType - > GetUnderlyingType ( ) ) ;
}
else
{
auto typeInst = initValue . mType - > ToTypeInstance ( ) ;
if ( typeInst ! = NULL )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
PopulateType ( typeInst ) ;
BfType * outType = NULL ;
2022-07-26 13:27:03 -04:00
int tagId = - 1 ;
2019-08-23 11:56:54 -07:00
if ( typeInst - > GetResultInfo ( outType , tagId ) )
{
handledExprBoolResult = true ;
unresolvedType = outType ;
resolvedType = outType ;
isReadOnly = isLet ;
2022-07-26 13:27:03 -04:00
localDef - > mIsReadOnly = isLet ;
_DoConditionalInit ( outType ) ;
2019-08-23 11:56:54 -07:00
}
}
}
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
}
}
2022-07-26 13:27:03 -04:00
if ( ! initValue )
2019-10-04 10:38:36 -07:00
{
2022-07-26 13:27:03 -04:00
initValue = GetDefaultTypedValue ( GetPrimitiveType ( BfTypeCode_Var ) ) ;
2019-10-04 10:38:36 -07:00
}
2019-08-23 11:56:54 -07:00
if ( initValue . mType - > IsNull ( ) )
{
Fail ( " Implicitly-typed variables cannot be initialized to 'null' " , varDecl - > mInitializer ) ;
initValue = GetDefaultTypedValue ( mContext - > mBfObjectType ) ;
}
if ( unresolvedType = = NULL )
unresolvedType = initValue . mType ;
resolvedType = unresolvedType ;
2020-06-16 07:50:00 -07:00
if ( ( initValue . IsTempAddr ( ) ) & & ( ! localDef - > mAddr ) & & ( initValue . mType = = resolvedType ) )
2019-08-23 11:56:54 -07:00
{
// Take over value
2022-07-26 13:27:03 -04:00
localDef - > mAddr = initValue . mValue ;
handledVarInit = true ;
2019-08-23 11:56:54 -07:00
if ( isLet )
{
2022-07-26 13:27:03 -04:00
localDef - > mValue = mBfIRBuilder - > CreateLoad ( localDef - > mAddr ) ;
2019-08-23 11:56:54 -07:00
}
}
if ( bfAutocomplete ! = NULL )
bfAutocomplete - > CheckVarResolution ( varDecl - > mTypeRef , resolvedType ) ;
}
else
{
2020-06-13 08:36:39 -07:00
BfTypeState typeState ;
typeState . mCurVarInitializer = varDecl - > mInitializer ;
SetAndRestoreValue < BfTypeState * > prevTypeState ( mContext - > mCurTypeState , & typeState ) ;
2021-07-19 08:45:25 -07:00
BfResolveTypeRefFlags flags = ( BfResolveTypeRefFlags ) ( BfResolveTypeRefFlag_NoResolveGenericParam | BfResolveTypeRefFlag_AllowRef ) ;
if ( varDecl - > mInitializer ! = NULL )
flags = ( BfResolveTypeRefFlags ) ( flags | BfResolveTypeRefFlag_AllowInferredSizedArray ) ;
unresolvedType = ResolveTypeRef ( varDecl - > mTypeRef , BfPopulateType_Data , flags ) ;
2019-08-23 11:56:54 -07:00
if ( unresolvedType = = NULL )
2022-07-26 13:27:03 -04:00
unresolvedType = GetPrimitiveType ( BfTypeCode_Var ) ;
resolvedType = unresolvedType ;
}
2019-08-23 11:56:54 -07:00
auto _CheckConst = [ & ]
{
if ( initValue . mValue . IsConst ( ) )
{
auto constant = mBfIRBuilder - > GetConstant ( initValue . mValue ) ;
2019-12-24 13:13:04 -08:00
// NullPtr is stand-in for GlobalVar during autocomplete
2019-08-23 11:56:54 -07:00
if ( ( constant - > mConstType = = BfConstType_GlobalVar ) | |
( constant - > mTypeCode = = BfTypeCode_NullPtr ) )
{
// Not really constant
// localNeedsAddr = false;
// isConst = false;
// initHandled = true;
// localDef->mValue = initValue.mValue;
2022-02-04 14:26:50 -05:00
if ( GetStringPoolIdx ( initValue . mValue , mBfIRBuilder ) = = - 1 )
isConst = false ;
2019-08-23 11:56:54 -07:00
}
}
} ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
localDef - > mResolvedType = resolvedType ;
2022-07-26 13:27:03 -04:00
localDef - > mIsReadOnly = isReadOnly ;
2019-08-23 11:56:54 -07:00
if ( ! initHandled )
{
if ( isLet )
{
localDef - > mIsReadOnly = true ;
if ( initValue )
{
if ( ( initValue . mValue ) & & ( initValue . mValue . IsConst ( ) ) )
{
isConst = true ;
}
}
}
}
_CheckConst ( ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
bool localNeedsAddr = false ;
bool allowValueAccess = true ;
if ( mHasFullDebugInfo )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
//if (!IsTargetingBeefBackend())
if ( ! isConst )
localNeedsAddr = true ;
/*if (mCurMethodInstance->mMethodDef->mName != "Boop2")
dbgNeedsAddr = true ; */
}
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
// This is required because of lifetime and LLVM domination rules for certain instances of variable declarations in binary conditionals.
// IE: if ((something) && (let a = somethingElse))
if ( ( exprEvaluator ! = NULL ) & & ( ! isConst ) )
{
localNeedsAddr = true ;
allowValueAccess = false ;
}
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
if ( ( varDecl - > mEqualsNode ! = NULL ) & & ( mCompiler - > mResolvePassData ! = NULL ) & & ( mCompiler - > mResolvePassData - > mAutoComplete ! = NULL ) & & ( ! initHandled ) )
{
mCompiler - > mResolvePassData - > mAutoComplete - > CheckEmptyStart ( varDecl - > mEqualsNode , resolvedType ) ;
}
BfIRInitType initType = BfIRInitType_NotSet ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
if ( varDecl - > mInitializer ! = NULL )
{
initType = BfIRInitType_NotNeeded_AliveOnDecl ;
if ( ( ! initValue ) & & ( ! initHandled ) )
{
2022-02-11 10:38:57 -05:00
if ( ( isConst ) | | ( isStatic ) )
2019-08-23 11:56:54 -07:00
{
BfConstResolver constResolver ( this ) ;
2021-02-25 10:14:22 -08:00
initValue = constResolver . Resolve ( varDecl - > mInitializer , resolvedType , BfConstResolveFlag_ActualizeValues ) ;
2022-07-26 13:27:03 -04:00
if ( ! initValue )
2020-12-22 04:50:37 -08:00
initValue = GetDefaultTypedValue ( resolvedType ) ;
2019-08-23 11:56:54 -07:00
}
2022-07-26 13:27:03 -04:00
else if ( varDecl - > mInitializer - > IsA < BfUninitializedExpression > ( ) )
{
2019-08-23 11:56:54 -07:00
// Fake 'is assigned'
}
else
{ //
auto expectedType = resolvedType ;
if ( expectedType - > IsRef ( ) )
expectedType = expectedType - > GetUnderlyingType ( ) ;
BfExprEvaluator valExprEvaluator ( this ) ;
valExprEvaluator . mAllowReadOnlyReference = isReadOnly ;
initValue = CreateValueFromExpression ( valExprEvaluator , varDecl - > mInitializer , expectedType , ( BfEvalExprFlags ) ( BfEvalExprFlags_NoCast | BfEvalExprFlags_AllowRefExpr | BfEvalExprFlags_VariableDeclaration ) ) ;
2023-01-23 06:56:05 -05:00
2022-09-05 06:28:23 -07:00
if ( ( initValue ) & & ( resolvedType - > IsUndefSizedArray ( ) ) )
{
int stringId = GetStringPoolIdx ( initValue . mValue , mBfIRBuilder ) ;
if ( stringId > = 0 )
{
BfStringPoolEntry * entry = NULL ;
if ( mContext - > mStringObjectIdMap . TryGetValue ( stringId , & entry ) )
resolvedType = CreateSizedArrayType ( ( ( BfSizedArrayType * ) resolvedType ) - > mElementType , entry - > mString . mLength ) ;
}
}
2019-08-23 11:56:54 -07:00
auto boolType = GetPrimitiveType ( BfTypeCode_Boolean ) ;
if ( exprEvaluator ! = NULL )
_DoConditionalInit ( expectedType ) ;
if ( ( ! handledVarInit ) & & ( initValue ) )
initValue = Cast ( varDecl - > mInitializer , initValue , resolvedType , BfCastFlags_PreferAddr ) ;
2020-12-22 04:50:37 -08:00
}
2022-07-26 13:27:03 -04:00
2020-12-22 04:50:37 -08:00
if ( ( initValue ) & & ( resolvedType - > IsUndefSizedArray ( ) ) )
{
resolvedType = initValue . mType ;
unresolvedType = resolvedType ;
2019-08-23 11:56:54 -07:00
}
2024-12-31 07:48:03 -08:00
if ( auto autoComplete = mCompiler - > GetAutoComplete ( ) )
{
autoComplete - > CheckResult ( varDecl - > mInitializer , initValue ) ;
}
2019-08-23 11:56:54 -07:00
}
if ( ( ! handledVarInit ) & & ( ! isConst ) )
{
if ( initValue )
{
// Handled later
}
2022-07-26 13:27:03 -04:00
else if ( varDecl - > mInitializer - > IsA < BfUninitializedExpression > ( ) )
{
2019-08-23 11:56:54 -07:00
// Fake 'is assigned'
initType = BfIRInitType_Uninitialized ;
}
else
{
AssertErrorState ( ) ;
}
}
2020-09-21 13:58:00 -07:00
localDef - > mAssignedKind = BfLocalVarAssignKind_Unconditional ;
2019-08-23 11:56:54 -07:00
}
else
{
if ( isConst )
{
Fail ( " Const locals must be initialized " , varDecl - > mModSpecifier ) ;
2022-02-05 11:26:58 -05:00
initValue = GetDefaultTypedValue ( resolvedType , true ) ;
2019-08-23 11:56:54 -07:00
}
else if ( isReadOnly )
{
Fail ( " Readonly locals must be initialized " , varDecl - > mModSpecifier ) ;
2022-02-05 11:26:58 -05:00
initValue = GetDefaultTypedValue ( resolvedType , true ) ;
2019-08-23 11:56:54 -07:00
}
else if ( auto refTypeRef = BfNodeDynCast < BfRefTypeRef > ( varDecl - > mTypeRef ) )
{
Fail ( " Ref locals must be initialized " , refTypeRef - > mRefToken ) ;
}
else
{
2020-12-22 04:50:37 -08:00
BF_ASSERT ( ! resolvedType - > IsRef ( ) ) ;
2019-08-23 11:56:54 -07:00
}
}
2020-12-22 04:50:37 -08:00
PopulateType ( resolvedType ) ;
AddDependency ( resolvedType , mCurTypeInstance , BfDependencyMap : : DependencyFlag_LocalUsage ) ;
localDef - > mResolvedType = resolvedType ;
2019-08-23 11:56:54 -07:00
_CheckConst ( ) ;
if ( ( initValue . mKind = = BfTypedValueKind_TempAddr ) & & ( ! initHandled ) )
{
BF_ASSERT ( initValue . IsAddr ( ) ) ;
BF_ASSERT ( initValue . mType - > IsComposite ( ) ) ;
handledVarInit = true ;
handledVarStore = true ;
if ( ! localDef - > mAddr )
{
localDef - > mAddr = initValue . mValue ;
if ( localDef - > mIsReadOnly )
2022-07-26 13:27:03 -04:00
localDef - > mValue = mBfIRBuilder - > CreateLoad ( localDef - > mAddr ) ;
}
2019-09-18 08:14:38 -07:00
if ( WantsLifetimes ( ) )
mCurMethodState - > mCurScope - > mDeferredLifetimeEnds . push_back ( localDef - > mAddr ) ;
2019-08-23 11:56:54 -07:00
}
2022-02-11 10:38:57 -05:00
if ( ( ! localDef - > mAddr ) & & ( ! isConst ) & & ( ! isStatic ) & & ( ( ! localDef - > mIsReadOnly ) | | ( localNeedsAddr ) ) )
2019-08-23 11:56:54 -07:00
{
if ( ( exprEvaluator ! = NULL ) & & ( exprEvaluator - > mResultIsTempComposite ) )
{
//TODO: Can we remove this one?
BF_ASSERT ( initValue . IsAddr ( ) ) ;
BF_ASSERT ( initValue . mType - > IsComposite ( ) ) ;
localDef - > mAddr = initValue . mValue ;
}
else
localDef - > mAddr = AllocLocalVariable ( resolvedType , localDef - > mName ) ;
}
2022-02-11 10:38:57 -05:00
if ( isStatic )
{
String name = mModuleName + " _ " + mCurMethodInstance - > mMethodDef - > mName + " _ " + localDef - > mName ;
HashContext closureHashCtx ;
closureHashCtx . Mixin ( varDecl - > mSrcStart ) ;
uint64 closureHash = closureHashCtx . Finish64 ( ) ;
name + = " $ " ;
name + = BfTypeUtils : : HashEncode64 ( closureHash ) ;
initValue = LoadValue ( initValue ) ;
if ( ( initValue ) & & ( ! initValue . mValue . IsConst ( ) ) )
{
Fail ( " Static local variables can only be initialized with a const value " , varDecl - > mInitializer ) ;
initValue = BfTypedValue ( ) ;
}
2022-06-27 11:08:03 -07:00
if ( ! initValue )
initValue = GetDefaultTypedValue ( localDef - > mResolvedType ) ;
2022-02-11 10:38:57 -05:00
localDef - > mAddr = mBfIRBuilder - > CreateGlobalVariable ( mBfIRBuilder - > MapType ( localDef - > mResolvedType ) , false , BfIRLinkageType_Internal , initValue . mValue , name ) ; ;
initHandled = true ;
}
2019-09-24 08:58:04 -07:00
bool wantsStore = false ;
2019-08-23 11:56:54 -07:00
if ( ( initValue ) & & ( ! handledVarStore ) & & ( ! isConst ) & & ( ! initHandled ) )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
initValue = LoadValue ( initValue ) ;
if ( initValue . IsSplat ( ) )
{
2021-01-08 16:21:03 -08:00
BF_ASSERT ( ! mIsComptimeModule ) ;
2019-08-23 11:56:54 -07:00
if ( ! localDef - > mAddr )
localDef - > mAddr = AllocLocalVariable ( resolvedType , localDef - > mName ) ;
AggregateSplatIntoAddr ( initValue , localDef - > mAddr ) ;
initHandled = true ;
}
else
{
initValue = AggregateSplat ( initValue ) ;
localDef - > mValue = initValue . mValue ;
if ( ( localDef - > mAddr ) & & ( ! localDef - > mResolvedType - > IsValuelessType ( ) ) )
{
2019-10-05 10:26:26 -07:00
if ( ! initValue . mType - > IsVar ( ) )
wantsStore = true ;
2019-08-23 11:56:54 -07:00
}
else
{
BF_ASSERT ( isReadOnly | | isLet | | initValue . mType - > IsValuelessType ( ) | | ( mBfIRBuilder - > mIgnoreWrites ) ) ;
}
}
}
if ( ( localDef - > mIsReadOnly ) & & ( ! isConst ) & & ( ! localDef - > mValue ) & & ( ! initHandled ) )
{
if ( ! resolvedType - > IsValuelessType ( ) )
{
AssertErrorState ( ) ;
2022-06-06 13:04:35 -07:00
initValue = GetDefaultTypedValue ( resolvedType , true , BfDefaultValueKind_Undef ) ;
2019-08-23 11:56:54 -07:00
localDef - > mValue = initValue . mValue ;
}
}
if ( ( ! localDef - > mAddr ) & & ( ! isConst ) & & ( ( ! localDef - > mIsReadOnly ) | | ( localNeedsAddr ) ) )
{
localDef - > mAddr = AllocLocalVariable ( resolvedType , localDef - > mName ) ;
}
if ( ( exprEvaluator ! = NULL ) & & ( ! handledExprBoolResult ) )
{
auto boolType = GetPrimitiveType ( BfTypeCode_Boolean ) ;
if ( ! initValue )
{
AssertErrorState ( ) ;
exprEvaluator - > mResult = BfTypedValue ( mBfIRBuilder - > CreateConst ( BfTypeCode_Boolean , 0 ) , boolType ) ;
}
else if ( ( resolvedType - > IsPointer ( ) ) | | ( resolvedType - > IsObjectOrInterface ( ) ) )
{
exprEvaluator - > mResult = BfTypedValue ( mBfIRBuilder - > CreateIsNotNull ( initValue . mValue ) , boolType ) ;
2022-07-26 13:27:03 -04:00
}
2022-01-19 10:38:20 -05:00
else if ( resolvedType - > IsVar ( ) )
2019-08-23 11:56:54 -07:00
{
2022-01-19 10:38:20 -05:00
exprEvaluator - > mResult = GetDefaultTypedValue ( GetPrimitiveType ( BfTypeCode_Boolean ) , false , BfDefaultValueKind_Undef ) ;
}
else
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
// Always true
2020-12-05 13:27:51 -08:00
if ( ( ! IsInSpecializedSection ( ) ) & & ( ! resolvedType - > IsGenericParam ( ) ) )
2022-07-26 13:27:03 -04:00
Warn ( BfWarning_CS0472_ValueTypeNullCompare , StrFormat ( " Variable declaration is always 'true' since a value of type '%s' can never be null " ,
2019-08-23 11:56:54 -07:00
TypeToString ( initValue . mType ) . c_str ( ) ) , varDecl ) ;
exprEvaluator - > mResult = BfTypedValue ( mBfIRBuilder - > CreateConst ( BfTypeCode_Boolean , 1 ) , boolType ) ;
}
}
if ( ( unresolvedType - > IsGenericParam ( ) ) & & ( resolvedType - > IsValuelessType ( ) ) & & ( mHasFullDebugInfo ) )
{
// We do this in order to be able to bind to lines that contain valueless variable declarations in some generics
// We don't need to do this in non-generics because the breakpoint will just move to the next line that actually has instructions
EmitEnsureInstructionAt ( ) ;
}
if ( ( resolvedType - > IsVoid ( ) ) & & ( ! IsInSpecializedSection ( ) ) )
{
Warn ( 0 , StrFormat ( " Variable '%s' is declared as 'void' " , localDef - > mName . c_str ( ) ) , varDecl - > mTypeRef ) ;
}
if ( ( ! handledVarInit ) & & ( isConst ) )
localDef - > mConstValue = initValue . mValue ;
if ( ! allowValueAccess )
localDef - > mValue = BfIRValue ( ) ;
if ( ! localDef - > mIsShadow )
CheckVariableDef ( localDef ) ;
ValidateAllocation ( localDef - > mResolvedType , varDecl - > mTypeRef ) ;
if ( ( exprEvaluator = = NULL ) & & ( varDecl - > GetSourceData ( ) ! = NULL ) )
2022-07-26 13:27:03 -04:00
UpdateSrcPos ( varDecl ) ;
2019-08-23 11:56:54 -07:00
localDef - > Init ( ) ;
if ( localDef - > mConstValue )
2022-07-26 13:27:03 -04:00
initType = BfIRInitType_NotNeeded ;
2019-08-23 11:56:54 -07:00
2019-09-24 08:58:04 -07:00
BfLocalVariable * localVar = AddLocalVariableDef ( localDef , true , false , BfIRValue ( ) , initType ) ;
if ( wantsStore )
2022-04-16 13:22:32 -07:00
mBfIRBuilder - > CreateAlignedStore ( initValue . mValue , localVar - > mAddr , localVar - > mResolvedType - > mAlign ) ;
2022-06-27 10:55:31 -07:00
if ( ( mCurMethodState - > mConstResolveState ! = NULL ) & & ( mCurMethodState - > mConstResolveState - > mInCalcAppend ) )
{
if ( localDef - > mValue . IsConst ( ) )
localDef - > mConstValue = localDef - > mValue ;
}
2019-09-24 08:58:04 -07:00
return localVar ;
2019-08-23 11:56:54 -07:00
}
2022-06-24 09:25:43 -07:00
BfLocalVariable * BfModule : : HandleVariableDeclaration ( BfType * type , BfAstNode * nameNode , BfTypedValue val , bool updateSrcLoc , bool forceAddr )
{
BfLocalVariable * localDef = new BfLocalVariable ( ) ;
nameNode - > ToString ( localDef - > mName ) ;
localDef - > mNameNode = BfNodeDynCast < BfIdentifierNode > ( nameNode ) ;
localDef - > mResolvedType = type ;
localDef - > mAssignedKind = BfLocalVarAssignKind_Unconditional ;
localDef - > mValue = val . mValue ;
if ( ( ! localDef - > mIsReadOnly ) | | ( mHasFullDebugInfo ) )
{
localDef - > mAddr = AllocLocalVariable ( localDef - > mResolvedType , localDef - > mName ) ;
if ( ( val . mValue ) & & ( ! localDef - > mResolvedType - > IsValuelessType ( ) ) & & ( ! localDef - > mResolvedType - > IsVar ( ) ) )
{
if ( localDef - > mResolvedType - > IsRef ( ) )
val = MakeAddressable ( val , true , true ) ;
if ( val . IsSplat ( ) )
{
AggregateSplatIntoAddr ( val , localDef - > mAddr ) ;
}
else
mBfIRBuilder - > CreateAlignedStore ( val . mValue , localDef - > mAddr , localDef - > mResolvedType - > mAlign ) ;
}
}
CheckVariableDef ( localDef ) ;
if ( nameNode - > GetSourceData ( ) ! = NULL )
UpdateSrcPos ( nameNode ) ;
localDef - > Init ( ) ;
2022-07-26 13:27:03 -04:00
return AddLocalVariableDef ( localDef , true ) ;
2022-06-24 09:25:43 -07:00
}
2019-08-23 11:56:54 -07:00
BfLocalVariable * BfModule : : HandleVariableDeclaration ( BfVariableDeclaration * varDecl , BfTypedValue val , bool updateSrcLoc , bool forceAddr )
{
if ( varDecl - > mEqualsNode ! = NULL )
Fail ( " Unexpected initialization " , varDecl - > mEqualsNode ) ;
if ( varDecl - > mInitializer ! = NULL )
CreateValueFromExpression ( varDecl - > mInitializer ) ;
2022-07-26 13:27:03 -04:00
auto isLet = varDecl - > mTypeRef - > IsA < BfLetTypeReference > ( ) ;
2019-08-23 11:56:54 -07:00
auto isVar = varDecl - > mTypeRef - > IsA < BfVarTypeReference > ( ) ;
bool isRef = false ;
if ( auto varRefTypeReference = BfNodeDynCast < BfVarRefTypeReference > ( varDecl - > mTypeRef ) )
{
isRef = true ;
isLet = varRefTypeReference - > mVarToken - > GetToken ( ) = = BfToken_Let ;
isVar = varRefTypeReference - > mVarToken - > GetToken ( ) = = BfToken_Var ;
}
else
{
BF_ASSERT ( ! val . IsAddr ( ) ) ;
}
auto autoComplete = mCompiler - > GetAutoComplete ( ) ;
if ( ( autoComplete ! = NULL ) & & ( ( isLet ) | | ( isVar ) ) )
autoComplete - > CheckVarResolution ( varDecl - > mTypeRef , val . mType ) ;
// BfType* type = val.mType;
// if (type == NULL)
// {
// type = ResolveTypeRef(varDecl->mTypeRef);
// if (type == NULL)
// type = mContext->mBfObjectType;
2022-07-26 13:27:03 -04:00
// }
2019-08-23 11:56:54 -07:00
BfType * type = NULL ;
if ( ( isLet ) | | ( isVar ) )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
type = val . mType ;
}
else
{
type = ResolveTypeRef ( varDecl - > mTypeRef ) ;
}
if ( type = = NULL )
2022-07-26 13:27:03 -04:00
{
2021-01-04 13:44:11 -08:00
type = GetPrimitiveType ( BfTypeCode_Var ) ;
val = GetDefaultTypedValue ( type ) ;
}
2019-08-23 11:56:54 -07:00
if ( ( type - > IsVar ( ) ) | | ( type - > IsLet ( ) ) )
{
}
if ( isRef )
{
type = CreateRefType ( type ) ;
}
BfLocalVariable * localDef = new BfLocalVariable ( ) ;
if ( varDecl - > mNameNode ! = NULL )
2019-11-19 09:58:35 -08:00
varDecl - > mNameNode - > ToString ( localDef - > mName ) ;
2019-08-23 11:56:54 -07:00
localDef - > mNameNode = BfNodeDynCast < BfIdentifierNode > ( varDecl - > mNameNode ) ;
localDef - > mResolvedType = type ;
2022-07-26 13:27:03 -04:00
localDef - > mAssignedKind = BfLocalVarAssignKind_Unconditional ;
2019-08-23 11:56:54 -07:00
localDef - > mValue = val . mValue ;
if ( isLet )
{
2022-07-26 13:27:03 -04:00
localDef - > mIsReadOnly = true ;
2019-08-23 11:56:54 -07:00
}
if ( ( ! localDef - > mIsReadOnly ) | | ( mHasFullDebugInfo ) | | ( forceAddr ) )
{
2022-07-26 13:27:03 -04:00
localDef - > mAddr = AllocLocalVariable ( localDef - > mResolvedType , localDef - > mName ) ;
2021-03-02 06:31:39 -08:00
if ( ( val . mValue ) & & ( ! localDef - > mResolvedType - > IsValuelessType ( ) ) & & ( ! localDef - > mResolvedType - > IsVar ( ) ) )
2019-08-23 11:56:54 -07:00
{
2022-06-22 12:06:40 -07:00
if ( localDef - > mResolvedType - > IsRef ( ) )
val = MakeAddressable ( val , true , true ) ;
2019-08-23 11:56:54 -07:00
if ( val . IsSplat ( ) )
2022-06-22 12:06:40 -07:00
{
2019-08-23 11:56:54 -07:00
AggregateSplatIntoAddr ( val , localDef - > mAddr ) ;
2022-06-22 12:06:40 -07:00
}
2019-08-23 11:56:54 -07:00
else
mBfIRBuilder - > CreateAlignedStore ( val . mValue , localDef - > mAddr , localDef - > mResolvedType - > mAlign ) ;
}
if ( forceAddr )
localDef - > mValue = BfIRValue ( ) ;
}
CheckVariableDef ( localDef ) ;
if ( ( updateSrcLoc ) & & ( varDecl - > GetSourceData ( ) ! = NULL ) )
UpdateSrcPos ( varDecl ) ;
localDef - > Init ( ) ;
2022-07-26 13:27:03 -04:00
return AddLocalVariableDef ( localDef , true ) ;
2019-08-23 11:56:54 -07:00
}
void BfModule : : CheckTupleVariableDeclaration ( BfTupleExpression * tupleExpr , BfType * initType )
{
if ( initType = = NULL )
return ;
2020-06-04 15:02:46 -07:00
BfTypeInstance * initTupleType = NULL ;
2019-08-23 11:56:54 -07:00
if ( ( initType ! = NULL ) & & ( initType - > IsTuple ( ) ) )
2020-06-04 15:02:46 -07:00
initTupleType = ( BfTypeInstance * ) initType ;
2019-08-23 11:56:54 -07:00
if ( initTupleType ! = NULL )
{
mBfIRBuilder - > PopulateType ( initTupleType ) ;
AddDependency ( initTupleType , mCurTypeInstance , BfDependencyMap : : DependencyFlag_LocalUsage ) ;
int paramCountDiff = ( int ) tupleExpr - > mValues . size ( ) - ( int ) initTupleType - > mFieldInstances . size ( ) ;
if ( paramCountDiff > 0 )
{
Fail ( StrFormat ( " Too many variable names, expected %d fewer. " , paramCountDiff ) , tupleExpr - > mValues [ ( int ) initTupleType - > mFieldInstances . size ( ) ] ) ;
}
else if ( paramCountDiff < 0 )
{
BfAstNode * refNode = tupleExpr - > mCloseParen ;
if ( refNode = = NULL )
refNode = tupleExpr ;
Fail ( StrFormat ( " Too few variable names, expected %d more. " , - paramCountDiff ) , refNode ) ;
}
}
else
{
Fail ( StrFormat ( " Value result type '%s' must be a tuple type to be applicable for tuple decomposition " , TypeToString ( initType ) . c_str ( ) ) , tupleExpr ) ;
}
}
void BfModule : : HandleTupleVariableDeclaration ( BfVariableDeclaration * varDecl , BfTupleExpression * tupleExpr , BfTypedValue initTupleValue , bool isReadOnly , bool isConst , bool forceAddr , BfIRBlock * declBlock )
{
2020-06-04 15:02:46 -07:00
BfTypeInstance * initTupleType = NULL ;
2019-08-23 11:56:54 -07:00
if ( ( initTupleValue ) & & ( initTupleValue . mType - > IsTuple ( ) ) )
2020-06-04 15:02:46 -07:00
initTupleType = ( BfTypeInstance * ) initTupleValue . mType ;
2019-08-23 11:56:54 -07:00
CheckTupleVariableDeclaration ( tupleExpr , initTupleValue . mType ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
for ( int varIdx = 0 ; varIdx < ( int ) tupleExpr - > mValues . size ( ) ; varIdx + + )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
BfType * resolvedType = NULL ;
BfTypedValue initValue ;
if ( ( initTupleType ! = NULL ) & & ( varIdx < ( int ) initTupleType - > mFieldInstances . size ( ) ) )
{
auto fieldInstance = & initTupleType - > mFieldInstances [ varIdx ] ;
auto fieldDef = fieldInstance - > GetFieldDef ( ) ;
resolvedType = fieldInstance - > GetResolvedType ( ) ;
if ( fieldInstance - > mDataIdx ! = - 1 )
{
if ( initTupleValue . IsAddr ( ) )
{
initValue = BfTypedValue ( mBfIRBuilder - > CreateInBoundsGEP ( initTupleValue . mValue , 0 , fieldInstance - > mDataIdx ) , resolvedType , true ) ;
initValue = LoadValue ( initValue ) ;
}
else
initValue = BfTypedValue ( mBfIRBuilder - > CreateExtractValue ( initTupleValue . mValue , fieldInstance - > mDataIdx ) , resolvedType ) ;
}
BfTupleNameNode * tupleNameNode = NULL ;
if ( varIdx < ( int ) tupleExpr - > mNames . size ( ) )
tupleNameNode = tupleExpr - > mNames [ varIdx ] ;
if ( ! fieldDef - > IsUnnamedTupleField ( ) )
{
if ( tupleNameNode ! = NULL )
{
if ( fieldDef - > mName ! = tupleNameNode - > mNameNode - > ToString ( ) )
{
Fail ( StrFormat ( " Mismatched tuple field name, expected '%s' " , fieldDef - > mName . c_str ( ) ) , tupleNameNode - > mNameNode ) ;
}
}
}
else if ( ( tupleNameNode ! = NULL ) & & ( tupleNameNode - > mNameNode ! = NULL ) )
{
Fail ( StrFormat ( " Unexpected tuple field name, expected unnamed tuple field " , fieldDef - > mName . c_str ( ) ) , tupleNameNode - > mNameNode ) ;
}
}
else
{
resolvedType = mContext - > mBfObjectType ;
initValue = GetDefaultTypedValue ( resolvedType ) ;
}
BfExpression * varNameNode = tupleExpr - > mValues [ varIdx ] ;
if ( ! varNameNode - > IsExact < BfIdentifierNode > ( ) )
{
if ( BfTupleExpression * innerTupleExpr = BfNodeDynCast < BfTupleExpression > ( varNameNode ) )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
HandleTupleVariableDeclaration ( varDecl , innerTupleExpr , initValue , isReadOnly , isConst , false , declBlock ) ;
}
else if ( ! varNameNode - > IsExact < BfUninitializedExpression > ( ) )
Fail ( " Variable name expected " , varNameNode ) ;
continue ;
}
bool initHandled = false ;
BfLocalVariable * localDef = new BfLocalVariable ( ) ;
2019-11-19 09:58:35 -08:00
varNameNode - > ToString ( localDef - > mName ) ;
2022-07-26 13:27:03 -04:00
localDef - > mNameNode = BfNodeDynCast < BfIdentifierNode > ( varNameNode ) ;
2019-08-23 11:56:54 -07:00
localDef - > mResolvedType = resolvedType ;
localDef - > mReadFromId = 0 ; // Don't give usage errors for binds
if ( isReadOnly )
{
localDef - > mIsReadOnly = true ;
if ( ( initValue ) & & ( initValue . mValue . IsConst ( ) ) )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
isConst = true ;
}
}
CheckVariableDef ( localDef ) ;
if ( ( ! isConst ) & & ( ( forceAddr ) | | ( ! localDef - > mIsReadOnly ) | | ( mHasFullDebugInfo ) ) )
2022-07-26 13:27:03 -04:00
{
localDef - > mAddr = AllocLocalVariable ( resolvedType , localDef - > mName ) ;
2019-08-23 11:56:54 -07:00
}
if ( ( varDecl ! = NULL ) & & ( varDecl - > mEqualsNode ! = NULL ) & & ( mCompiler - > mResolvePassData ! = NULL ) & & ( mCompiler - > mResolvePassData - > mAutoComplete ! = NULL ) & & ( ! initHandled ) )
{
mCompiler - > mResolvePassData - > mAutoComplete - > CheckEmptyStart ( varDecl - > mEqualsNode , resolvedType ) ;
}
if ( ( varDecl = = NULL ) | | ( varDecl - > mInitializer ! = NULL ) )
{
if ( ( ! isConst ) & & ( ! initHandled ) )
{
if ( initValue )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
if ( ! forceAddr )
localDef - > mValue = initValue . mValue ;
if ( localDef - > mAddr )
{
mBfIRBuilder - > CreateStore ( initValue . mValue , localDef - > mAddr ) ;
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
}
else if ( ( varDecl = = NULL ) | | ( varDecl - > mInitializer - > IsA < BfUninitializedExpression > ( ) ) )
{
// Fake 'is assigned'
}
else
{
AssertErrorState ( ) ;
}
}
2022-07-26 13:27:03 -04:00
localDef - > mAssignedKind = BfLocalVarAssignKind_Unconditional ;
2019-08-23 11:56:54 -07:00
}
else if ( ( varDecl ! = NULL ) & & ( varDecl - > mInitializer = = NULL ) )
{
if ( auto refTypeRef = BfNodeDynCast < BfRefTypeRef > ( varDecl - > mTypeRef ) )
{
Fail ( " Ref variables must be initialized " , refTypeRef - > mRefToken ) ;
}
else
{
BF_ASSERT ( ! localDef - > mResolvedType - > IsRef ( ) ) ;
}
}
if ( isConst )
localDef - > mConstValue = initValue . mValue ;
CheckVariableDef ( localDef ) ;
if ( ( varDecl ! = NULL ) & & ( varDecl - > GetSourceData ( ) ! = NULL ) )
UpdateSrcPos ( varDecl ) ;
localDef - > Init ( ) ;
auto defBlock = mBfIRBuilder - > GetInsertBlock ( ) ;
if ( declBlock ! = NULL )
mBfIRBuilder - > SetInsertPoint ( * declBlock ) ;
AddLocalVariableDef ( localDef , true , false , BfIRValue ( ) , BfIRInitType_NotNeeded ) ;
if ( declBlock ! = NULL )
mBfIRBuilder - > SetInsertPoint ( defBlock ) ;
}
}
void BfModule : : HandleTupleVariableDeclaration ( BfVariableDeclaration * varDecl )
{
BfAutoComplete * bfAutocomplete = mCompiler - > GetAutoComplete ( ) ;
if ( bfAutocomplete ! = NULL )
bfAutocomplete - > CheckTypeRef ( varDecl - > mTypeRef , true ) ;
BfTupleExpression * tupleExpr = BfNodeDynCast < BfTupleExpression > ( varDecl - > mNameNode ) ;
bool isConst = ( varDecl - > mModSpecifier ! = NULL ) & & ( varDecl - > mModSpecifier - > GetToken ( ) = = BfToken_Const ) ;
bool isReadOnly = ( varDecl - > mModSpecifier ! = NULL ) & & ( varDecl - > mModSpecifier - > GetToken ( ) = = BfToken_ReadOnly ) ;
BfTypedValue initTupleValue ;
bool hadVarType = false ;
bool isLet = varDecl - > mTypeRef - > IsA < BfLetTypeReference > ( ) ;
2022-07-26 13:27:03 -04:00
bool isVar = varDecl - > mTypeRef - > IsA < BfVarTypeReference > ( ) ;
2019-08-23 11:56:54 -07:00
bool wasVarOrLet = isVar | | isLet ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
if ( ( ! isLet ) & & ( ! isVar ) )
{
ResolveTypeRef ( varDecl - > mTypeRef ) ;
Fail ( " 'var' or 'let' expected " , varDecl - > mTypeRef ) ;
isVar = true ;
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
if ( ( isVar ) | | ( isLet ) )
{
hadVarType = true ;
if ( varDecl - > mInitializer = = NULL )
{
Fail ( " Implicitly-typed variables must be initialized " , varDecl ) ;
initTupleValue = GetDefaultTypedValue ( mContext - > mBfObjectType ) ;
}
else
{
if ( isConst )
{
BfConstResolver constResolver ( this ) ;
initTupleValue = constResolver . Resolve ( varDecl - > mInitializer ) ;
}
else
{
initTupleValue = CreateValueFromExpression ( varDecl - > mInitializer , NULL ) ;
}
}
initTupleValue = LoadValue ( initTupleValue ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
if ( ( bfAutocomplete ! = NULL ) & & ( wasVarOrLet ) )
bfAutocomplete - > CheckVarResolution ( varDecl - > mTypeRef , initTupleValue . mType ) ;
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
bool isCompatible = false ;
if ( initTupleValue )
HandleTupleVariableDeclaration ( varDecl , tupleExpr , initTupleValue , isLet | | isReadOnly , isConst , false ) ;
else
AssertErrorState ( ) ;
}
2022-05-24 06:52:28 -07:00
void BfModule : : HandleCaseEnumMatch_Tuple ( BfTypedValue tupleVal , const BfSizedArray < BfExpression * > & arguments , BfAstNode * tooFewRef , BfIRValue phiVal , BfIRBlock & matchedBlockStart , BfIRBlock & matchedBlockEnd , BfIRBlock & falseBlockStart , BfIRBlock & falseBlockEnd , bool & hadConditional , bool clearOutOnMismatch , bool prevHadFallthrough )
2019-08-23 11:56:54 -07:00
{
SetAndRestoreValue < bool > prevInCondBlock ( mCurMethodState - > mInConditionalBlock ) ;
auto tupleType = tupleVal . mType - > ToTypeInstance ( ) ;
struct DeferredAssign
{
BfExpression * mExpr ;
BfTypedValue mArgValue ;
BfTypedValue mTupleElement ;
int mFieldIdx ;
} ;
Array < DeferredAssign > deferredAssigns ;
auto autoComplete = mCompiler - > GetAutoComplete ( ) ;
for ( int tupleFieldIdx = 0 ; tupleFieldIdx < ( int ) tupleType - > mFieldInstances . size ( ) ; tupleFieldIdx + + )
{
auto tupleFieldInstance = & tupleType - > mFieldInstances [ tupleFieldIdx ] ;
if ( tupleFieldIdx > = arguments . size ( ) )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
BfError * error = Fail ( StrFormat ( " Not enough parameters specified, expected %d more. " , tupleType - > mFieldInstances . size ( ) - ( int ) arguments . size ( ) ) , tooFewRef ) ;
break ;
}
BfTypedValue tupleElement ;
if ( tupleFieldInstance - > mDataIdx > = 0 )
{
tupleElement = ExtractValue ( tupleVal , tupleFieldInstance , tupleFieldInstance - > mDataIdx ) ;
}
else
tupleElement = GetDefaultTypedValue ( tupleFieldInstance - > GetResolvedType ( ) ) ;
auto expr = BfNodeDynCast < BfExpression > ( arguments [ tupleFieldIdx ] ) ;
if ( auto varDecl = BfNodeDynCast < BfVariableDeclaration > ( expr ) )
{
bool isVarOrLet = ( varDecl - > mTypeRef - > IsExact < BfLetTypeReference > ( ) ) | | ( varDecl - > mTypeRef - > IsExact < BfVarTypeReference > ( ) ) ;
bool isRef = false ;
if ( varDecl - > mTypeRef - > IsExact < BfVarRefTypeReference > ( ) )
{
isVarOrLet = true ;
isRef = true ;
}
if ( ! isVarOrLet )
{
auto wantType = ResolveTypeRef ( varDecl - > mTypeRef ) ;
2019-09-29 07:42:58 -07:00
if ( wantType = = NULL )
wantType = mContext - > mBfObjectType ;
2019-08-23 11:56:54 -07:00
if ( wantType ! = NULL )
2022-07-26 13:27:03 -04:00
tupleElement = Cast ( varDecl - > mTypeRef , tupleElement , wantType ) ;
2019-08-23 11:56:54 -07:00
if ( ! tupleElement )
tupleElement = GetDefaultTypedValue ( wantType ) ;
}
PopulateType ( tupleElement . mType ) ;
if ( ! isRef )
tupleElement = LoadValue ( tupleElement ) ;
2022-05-24 06:52:28 -07:00
if ( prevHadFallthrough )
Fail ( " Destructuring cannot be used when the previous case contains a fallthrough " , expr ) ;
2019-08-23 11:56:54 -07:00
auto localVar = HandleVariableDeclaration ( varDecl , tupleElement , false , true ) ;
localVar - > mReadFromId = 0 ; // Don't give usage errors for binds
continue ;
}
2022-06-24 09:25:43 -07:00
if ( auto binOpExpr = BfNodeDynCast < BfBinaryOperatorExpression > ( expr ) )
{
if ( binOpExpr - > mOp = = BfBinaryOp_Multiply )
{
SetAndRestoreValue < bool > prevIgnoreError ( mIgnoreErrors , true ) ;
auto resolvedType = ResolveTypeRef ( binOpExpr - > mLeft , NULL ) ;
prevIgnoreError . Restore ( ) ;
if ( resolvedType ! = NULL )
{
resolvedType = CreatePointerType ( resolvedType ) ;
2022-07-26 13:27:03 -04:00
PopulateType ( tupleElement . mType ) ;
2022-06-24 09:25:43 -07:00
tupleElement = LoadValue ( tupleElement ) ;
tupleElement = Cast ( binOpExpr - > mLeft , tupleElement , resolvedType ) ;
if ( prevHadFallthrough )
Fail ( " Destructuring cannot be used when the previous case contains a fallthrough " , expr ) ;
auto localVar = HandleVariableDeclaration ( resolvedType , binOpExpr - > mRight , tupleElement , false , true ) ;
localVar - > mReadFromId = 0 ; // Don't give usage errors for binds
continue ;
}
}
}
2019-08-23 11:56:54 -07:00
if ( auto uninitExpr = BfNodeDynCast < BfUninitializedExpression > ( expr ) )
{
continue ;
}
if ( tupleFieldInstance - > mDataIdx > = 0 )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
if ( auto tupleExpr = BfNodeDynCast < BfTupleExpression > ( expr ) )
{
if ( tupleElement . mType - > IsTuple ( ) )
{
BfAstNode * tooFewRef = tupleExpr - > mCloseParen ;
if ( tupleExpr - > mValues . size ( ) > 0 )
tooFewRef = tupleExpr - > mValues [ tupleExpr - > mValues . size ( ) - 1 ] ;
if ( tooFewRef = = NULL )
2022-07-26 13:27:03 -04:00
tooFewRef = tupleExpr - > mOpenParen ;
2022-05-24 06:52:28 -07:00
HandleCaseEnumMatch_Tuple ( tupleElement , tupleExpr - > mValues , tooFewRef , phiVal , matchedBlockStart , matchedBlockEnd , falseBlockStart , falseBlockEnd , hadConditional , clearOutOnMismatch , prevHadFallthrough ) ;
2019-08-23 11:56:54 -07:00
continue ;
}
}
}
if ( expr = = NULL )
{
// Error would have occured in the parser
//AssertErrorState();
}
else
{
mCurMethodState - > mInConditionalBlock = true ;
auto tupleElementAddr = tupleElement ;
BfTypedValue exprResult ;
if ( auto invocationExpr = BfNodeDynCast < BfInvocationExpression > ( expr ) )
{
if ( auto memberRefExpr = BfNodeDynCast < BfMemberReferenceExpression > ( invocationExpr - > mTarget ) )
{
if ( memberRefExpr - > mTarget = = NULL )
{
if ( tupleElement . mType - > IsPayloadEnum ( ) )
{
auto intType = GetPrimitiveType ( BfTypeCode_Int32 ) ;
BfTypedValue enumTagVal ;
if ( tupleElement . IsAddr ( ) )
{
enumTagVal = BfTypedValue ( mBfIRBuilder - > CreateInBoundsGEP ( tupleElement . mValue , 0 , 2 ) , intType , true ) ;
enumTagVal = LoadValue ( enumTagVal ) ;
}
else
enumTagVal = BfTypedValue ( mBfIRBuilder - > CreateExtractValue ( tupleElement . mValue , 2 ) , intType , false ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
int uncondTagId = - 1 ;
bool hadConditional = false ;
2022-05-24 06:52:28 -07:00
exprResult = TryCaseEnumMatch ( tupleElementAddr , enumTagVal , expr , NULL , NULL , NULL , uncondTagId , hadConditional , clearOutOnMismatch , prevHadFallthrough ) ;
2019-08-23 11:56:54 -07:00
}
}
}
}
if ( ! exprResult )
{
tupleElement = LoadValue ( tupleElement ) ;
2021-11-15 16:44:28 -08:00
bool isMatchedBlockEnd = matchedBlockEnd = = mBfIRBuilder - > GetInsertBlock ( ) ;
bool isFalseBlockEnd = falseBlockEnd = = mBfIRBuilder - > GetInsertBlock ( ) ;
2019-08-23 11:56:54 -07:00
BfExprEvaluator exprEvaluator ( this ) ;
exprEvaluator . mExpectingType = tupleFieldInstance - > GetResolvedType ( ) ;
exprEvaluator . mBfEvalExprFlags = BfEvalExprFlags_AllowOutExpr ;
2022-02-13 10:40:10 -05:00
if ( mCurMethodState - > mDeferredLocalAssignData ! = NULL )
{
SetAndRestoreValue < bool > prevIsIfCondition ( mCurMethodState - > mDeferredLocalAssignData - > mIsIfCondition , true ) ;
SetAndRestoreValue < bool > prevIfMayBeSkipped ( mCurMethodState - > mDeferredLocalAssignData - > mIfMayBeSkipped , true ) ;
exprEvaluator . Evaluate ( expr ) ;
}
else
{
exprEvaluator . Evaluate ( expr ) ;
}
2021-11-15 16:44:28 -08:00
if ( isMatchedBlockEnd )
matchedBlockEnd = mBfIRBuilder - > GetInsertBlock ( ) ;
if ( isFalseBlockEnd )
falseBlockEnd = mBfIRBuilder - > GetInsertBlock ( ) ;
2022-02-13 10:40:10 -05:00
auto argValue = exprEvaluator . mResult ;
2019-08-23 11:56:54 -07:00
if ( ! argValue )
continue ;
if ( argValue . mType - > IsRef ( ) )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
auto refType = ( BfRefType * ) argValue . mType ;
if ( refType - > mRefKind ! = BfRefType : : RefKind_Out )
{
BfAstNode * refNode = expr ;
if ( auto unaryOperatorExpr = BfNodeDynCast < BfUnaryOperatorExpression > ( expr ) )
refNode = unaryOperatorExpr - > mOpToken ;
Fail ( " Only 'out' refs can be used to assign to an existing value " , refNode ) ;
}
DeferredAssign deferredAssign = { expr , argValue , tupleElement , tupleFieldIdx } ;
deferredAssigns . push_back ( deferredAssign ) ;
2022-02-13 10:40:10 -05:00
if ( mCurMethodState - > mDeferredLocalAssignData ! = NULL )
{
SetAndRestoreValue < bool > prevIsIfCondition ( mCurMethodState - > mDeferredLocalAssignData - > mIsIfCondition , true ) ;
SetAndRestoreValue < bool > prevIfMayBeSkipped ( mCurMethodState - > mDeferredLocalAssignData - > mIfMayBeSkipped , true ) ;
exprEvaluator . MarkResultAssigned ( ) ;
}
else
{
exprEvaluator . MarkResultAssigned ( ) ;
}
2019-08-23 11:56:54 -07:00
continue ;
}
if ( ! argValue . mType - > IsValueType ( ) )
argValue = LoadValue ( argValue ) ;
argValue = Cast ( expr , argValue , tupleFieldInstance - > GetResolvedType ( ) ) ;
if ( ! argValue )
2022-07-26 13:27:03 -04:00
continue ;
2019-08-23 11:56:54 -07:00
exprEvaluator . PerformBinaryOperation ( expr , expr , BfBinaryOp_Equality , expr , BfBinOpFlag_NoClassify , tupleElement , argValue ) ;
exprResult = exprEvaluator . mResult ;
}
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
if ( exprResult )
{
hadConditional = true ;
if ( phiVal )
{
2022-07-26 13:27:03 -04:00
auto insertBlock = mBfIRBuilder - > GetInsertBlock ( ) ;
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > AddPhiIncoming ( phiVal , mBfIRBuilder - > CreateConst ( BfTypeCode_Boolean , 0 ) , insertBlock ) ;
}
2022-07-26 13:27:03 -04:00
2021-11-15 16:44:28 -08:00
matchedBlockStart = matchedBlockEnd = mBfIRBuilder - > CreateBlock ( " match " , false ) ;
2022-07-26 13:27:03 -04:00
2021-11-15 16:44:28 -08:00
mBfIRBuilder - > CreateCondBr ( exprResult . mValue , matchedBlockStart , falseBlockStart ) ;
mBfIRBuilder - > AddBlock ( matchedBlockStart ) ;
mBfIRBuilder - > SetInsertPoint ( matchedBlockStart ) ;
2019-08-23 11:56:54 -07:00
}
}
}
if ( ! deferredAssigns . empty ( ) )
2021-11-15 16:44:28 -08:00
mBfIRBuilder - > SetInsertPoint ( matchedBlockEnd ) ;
2019-08-23 11:56:54 -07:00
// We assign these only after the value checks succeed
for ( auto & deferredAssign : deferredAssigns )
{
auto argValue = RemoveRef ( deferredAssign . mArgValue ) ;
auto tupleElement = Cast ( deferredAssign . mExpr , deferredAssign . mTupleElement , argValue . mType ) ;
if ( ! tupleElement )
continue ;
2023-02-08 10:06:38 -05:00
tupleElement = LoadOrAggregateValue ( tupleElement ) ;
2022-01-03 07:43:06 -05:00
if ( ! tupleElement . mType - > IsValuelessType ( ) )
mBfIRBuilder - > CreateStore ( tupleElement . mValue , argValue . mValue ) ;
2019-08-23 11:56:54 -07:00
}
if ( ( clearOutOnMismatch ) & & ( ! deferredAssigns . IsEmpty ( ) ) )
{
auto curInsertPoint = mBfIRBuilder - > GetInsertBlock ( ) ;
2021-11-15 16:44:28 -08:00
mBfIRBuilder - > SetInsertPoint ( falseBlockEnd ) ;
2019-08-23 11:56:54 -07:00
for ( auto & deferredAssign : deferredAssigns )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
auto tupleFieldInstance = & tupleType - > mFieldInstances [ deferredAssign . mFieldIdx ] ;
// We have to re-process the expr because we haven't done it in this branch, and then clear the result out
SetAndRestoreValue < bool > prevIgnoreErrors ( mIgnoreErrors , mHadBuildError ) ; // Don't fail twice
BfExprEvaluator exprEvaluator ( this ) ;
exprEvaluator . mExpectingType = tupleFieldInstance - > GetResolvedType ( ) ;
exprEvaluator . mBfEvalExprFlags = BfEvalExprFlags_AllowOutExpr ;
exprEvaluator . Evaluate ( deferredAssign . mExpr ) ;
auto argValue = exprEvaluator . mResult ;
if ( ! argValue )
continue ;
mBfIRBuilder - > CreateMemSet ( argValue . mValue , GetConstValue8 ( 0 ) , GetConstValue ( argValue . mType - > mSize ) , GetConstValue ( argValue . mType - > mAlign ) ) ;
}
2021-11-15 16:44:28 -08:00
falseBlockEnd = mBfIRBuilder - > GetInsertBlock ( ) ;
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > SetInsertPoint ( curInsertPoint ) ;
}
if ( arguments . size ( ) > tupleType - > mFieldInstances . size ( ) )
{
for ( int i = ( int ) tupleType - > mFieldInstances . size ( ) ; i < ( int ) arguments . size ( ) ; i + + )
{
// For autocomplete and such
auto expr = arguments [ i ] ;
if ( expr ! = NULL )
CreateValueFromExpression ( expr ) ;
}
2022-07-26 13:27:03 -04:00
BfAstNode * errorRef = arguments [ ( int ) tupleType - > mFieldInstances . size ( ) ] ;
2019-08-23 11:56:54 -07:00
BfError * error = Fail ( StrFormat ( " Too many arguments, expected %d fewer. " , arguments . size ( ) - tupleType - > mFieldInstances . size ( ) ) , errorRef ) ;
}
}
2022-05-24 06:52:28 -07:00
BfTypedValue BfModule : : TryCaseTupleMatch ( BfTypedValue tupleVal , BfTupleExpression * tupleExpr , BfIRBlock * eqBlock , BfIRBlock * notEqBlock , BfIRBlock * matchBlock , bool & hadConditional , bool clearOutOnMismatch , bool prevHadFallthrough )
2019-11-27 08:00:15 -08:00
{
if ( ! tupleVal . mType - > IsTuple ( ) )
2019-11-27 08:55:00 -08:00
return BfTypedValue ( ) ;
2019-11-27 08:00:15 -08:00
2020-06-04 15:02:46 -07:00
auto tupleType = ( BfTypeInstance * ) tupleVal . mType ;
2019-11-27 08:00:15 -08:00
BfAstNode * tooFewRef = tupleExpr - > mCloseParen ;
if ( ( tooFewRef = = NULL ) & & ( ! tupleExpr - > mCommas . IsEmpty ( ) ) )
tooFewRef = tupleExpr - > mCommas [ tupleExpr - > mCommas . size ( ) - 1 ] ;
else if ( tooFewRef = = NULL )
tooFewRef = tupleExpr - > mOpenParen ;
///
auto autoComplete = mCompiler - > GetAutoComplete ( ) ;
bool wasCapturingMethodInfo = false ;
if ( autoComplete ! = NULL )
{
wasCapturingMethodInfo = autoComplete - > mIsCapturingMethodMatchInfo ;
autoComplete - > CheckInvocation ( tupleExpr , tupleExpr - > mOpenParen , tupleExpr - > mCloseParen , tupleExpr - > mCommas ) ;
if ( autoComplete - > mIsCapturingMethodMatchInfo )
{
autoComplete - > mMethodMatchInfo - > mInstanceList . Clear ( ) ;
auto methodMatchInfo = autoComplete - > mMethodMatchInfo ;
// auto methodDef = tupleType->mTypeDef->mMethods[0];
2022-07-26 13:27:03 -04:00
//
2019-11-27 08:00:15 -08:00
// BfAutoComplete::MethodMatchEntry methodMatchEntry;
// methodMatchEntry.mMethodDef = methodDef;
// methodMatchEntry.mTypeInstance = tupleType;
// methodMatchEntry.mCurMethodInstance = mCurMethodInstance;
// //methodMatchEntry.mPayloadEnumField = fieldInstance;
//autoComplete->mMethodMatchInfo->mInstanceList.push_back(methodMatchEntry);
methodMatchInfo - > mBestIdx = 0 ;
methodMatchInfo - > mMostParamsMatched = 0 ;
int cursorIdx = tupleExpr - > GetParser ( ) - > mCursorIdx ;
if ( ( tupleExpr - > mCloseParen = = NULL ) | | ( cursorIdx < = tupleExpr - > mCloseParen - > GetSrcStart ( ) ) )
{
int paramIdx = 0 ;
for ( int commaIdx = 0 ; commaIdx < ( int ) tupleExpr - > mCommas . size ( ) ; commaIdx + + )
{
auto commaNode = tupleExpr - > mCommas [ commaIdx ] ;
if ( ( commaNode ! = NULL ) & & ( cursorIdx > = commaNode - > GetSrcStart ( ) ) )
paramIdx = commaIdx + 1 ;
}
bool isEmpty = true ;
if ( paramIdx < ( int ) tupleExpr - > mValues . size ( ) )
{
auto paramNode = tupleExpr - > mValues [ paramIdx ] ;
if ( paramNode ! = NULL )
isEmpty = false ;
}
if ( isEmpty )
{
if ( paramIdx < ( int ) tupleType - > mFieldInstances . size ( ) )
{
auto fieldDef = tupleType - > mFieldInstances [ paramIdx ] . GetFieldDef ( ) ;
String insertStr ;
if ( fieldDef - > IsUnnamedTupleField ( ) )
insertStr = " p " ;
insertStr + = fieldDef - > mName ;
insertStr . Insert ( 0 , " let " ) ;
autoComplete - > mEntriesSet . Clear ( ) ;
autoComplete - > AddEntry ( AutoCompleteEntry ( " paramName " , insertStr ) ) ;
autoComplete - > mInsertStartIdx = cursorIdx ;
autoComplete - > mInsertEndIdx = cursorIdx ;
}
}
}
}
}
defer
(
if ( autoComplete ! = NULL )
autoComplete - > mIsCapturingMethodMatchInfo = ( wasCapturingMethodInfo ) & & ( ! autoComplete - > mIsCapturingMethodMatchInfo ) ;
) ;
///
//BfIRValue phiVal;
auto boolType = GetPrimitiveType ( BfTypeCode_Boolean ) ;
//phiVal = mBfIRBuilder->CreatePhi(mBfIRBuilder->MapType(boolType), 2);
auto startBlock = mBfIRBuilder - > GetInsertBlock ( ) ;
//auto dscrType = enumType->GetDiscriminatorType();
//BfIRValue eqResult = mBfIRBuilder->CreateCmpEQ(tagVal.mValue, mBfIRBuilder->CreateConst(dscrType->mTypeDef->mTypeCode, tagId));
2021-11-15 16:44:28 -08:00
BfIRBlock falseBlockStart ;
BfIRBlock falseBlockEnd ;
BfIRBlock doneBlockStart ;
2019-11-27 08:00:15 -08:00
if ( notEqBlock ! = NULL )
2021-11-15 16:44:28 -08:00
doneBlockStart = * notEqBlock ;
2019-11-27 08:00:15 -08:00
else
2021-11-15 16:44:28 -08:00
doneBlockStart = mBfIRBuilder - > CreateBlock ( " caseDone " , false ) ;
BfIRBlock doneBlockEnd = doneBlockStart ;
2019-11-27 08:00:15 -08:00
if ( clearOutOnMismatch )
{
2021-11-15 16:44:28 -08:00
falseBlockStart = falseBlockEnd = mBfIRBuilder - > CreateBlock ( " caseNotEq " , false ) ;
mBfIRBuilder - > AddBlock ( falseBlockStart ) ;
2019-11-27 08:00:15 -08:00
}
2021-11-15 16:44:28 -08:00
BfIRBlock matchedBlockStart = mBfIRBuilder - > CreateBlock ( " caseMatch " , false ) ;
2019-11-27 08:00:15 -08:00
if ( matchBlock ! = NULL )
2021-11-15 16:44:28 -08:00
* matchBlock = matchedBlockStart ;
mBfIRBuilder - > CreateBr ( matchedBlockStart ) ;
mBfIRBuilder - > AddBlock ( matchedBlockStart ) ;
2019-11-27 08:00:15 -08:00
2021-11-15 16:44:28 -08:00
mBfIRBuilder - > SetInsertPoint ( doneBlockEnd ) ;
2019-11-27 08:00:15 -08:00
BfIRValue phiVal ;
if ( eqBlock = = NULL )
phiVal = mBfIRBuilder - > CreatePhi ( mBfIRBuilder - > MapType ( boolType ) , 2 ) ;
2022-07-26 13:27:03 -04:00
2021-11-15 16:44:28 -08:00
mBfIRBuilder - > SetInsertPoint ( matchedBlockStart ) ;
BfIRBlock matchedBlockEnd = matchedBlockStart ;
2022-07-26 13:27:03 -04:00
HandleCaseEnumMatch_Tuple ( tupleVal , tupleExpr - > mValues , tooFewRef , falseBlockStart ? BfIRValue ( ) : phiVal , matchedBlockStart , matchedBlockEnd ,
2022-05-24 06:52:28 -07:00
falseBlockStart ? falseBlockStart : doneBlockStart , falseBlockEnd ? falseBlockEnd : doneBlockEnd , hadConditional , clearOutOnMismatch , prevHadFallthrough ) ;
2022-07-26 13:27:03 -04:00
2019-11-27 08:00:15 -08:00
if ( phiVal )
{
auto falseVal = mBfIRBuilder - > CreateConst ( BfTypeCode_Boolean , 0 ) ;
2021-11-15 16:44:28 -08:00
if ( falseBlockEnd )
mBfIRBuilder - > AddPhiIncoming ( phiVal , falseVal , falseBlockEnd ) ;
2019-11-27 08:00:15 -08:00
auto trueVal = mBfIRBuilder - > CreateConst ( BfTypeCode_Boolean , 1 ) ;
2021-11-15 16:44:28 -08:00
mBfIRBuilder - > AddPhiIncoming ( phiVal , trueVal , matchedBlockEnd ) ;
2019-11-27 08:00:15 -08:00
}
if ( eqBlock ! = NULL )
mBfIRBuilder - > CreateBr ( * eqBlock ) ;
else
2021-11-15 16:44:28 -08:00
mBfIRBuilder - > CreateBr ( doneBlockStart ) ;
2019-11-27 08:00:15 -08:00
2021-11-15 16:44:28 -08:00
if ( falseBlockEnd )
2019-11-27 08:00:15 -08:00
{
2021-11-15 16:44:28 -08:00
mBfIRBuilder - > SetInsertPoint ( falseBlockEnd ) ;
mBfIRBuilder - > CreateBr ( doneBlockStart ) ;
2019-11-27 08:00:15 -08:00
//mBfIRBuilder->AddPhiIncoming(phiVal, mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 0), falseBlock);
}
2021-11-15 16:44:28 -08:00
mBfIRBuilder - > AddBlock ( doneBlockStart ) ;
mBfIRBuilder - > SetInsertPoint ( doneBlockEnd ) ;
2019-11-27 08:00:15 -08:00
if ( phiVal )
return BfTypedValue ( phiVal , boolType ) ;
else
return GetDefaultTypedValue ( boolType ) ;
}
2022-05-24 06:52:28 -07:00
BfTypedValue BfModule : : TryCaseEnumMatch ( BfTypedValue enumVal , BfTypedValue tagVal , BfExpression * expr , BfIRBlock * eqBlock , BfIRBlock * notEqBlock , BfIRBlock * matchBlock , int & tagId , bool & hadConditional , bool clearOutOnMismatch , bool prevHadFallthrough )
2019-08-23 11:56:54 -07:00
{
auto invocationExpr = BfNodeDynCast < BfInvocationExpression > ( expr ) ;
if ( invocationExpr = = NULL )
return BfTypedValue ( ) ;
auto activeTypeDef = GetActiveTypeDef ( ) ;
BfType * targetType = NULL ;
BfIdentifierNode * nameNode = NULL ;
BfTokenNode * dotNode = NULL ;
if ( auto memberRefExpr = BfNodeDynCast < BfMemberReferenceExpression > ( invocationExpr - > mTarget ) )
{
if ( memberRefExpr - > mTarget = = NULL )
{
targetType = enumVal . mType ;
}
2022-07-26 13:27:03 -04:00
else if ( auto typeRef = BfNodeDynCast < BfTypeReference > ( memberRefExpr - > mTarget ) )
2019-08-23 11:56:54 -07:00
{
SetAndRestoreValue < bool > prevIgnoreErrors ( mIgnoreErrors , true ) ;
targetType = ResolveTypeRef ( typeRef ) ;
}
else if ( auto identifier = BfNodeDynCast < BfIdentifierNode > ( memberRefExpr - > mTarget ) )
{
SetAndRestoreValue < bool > prevIgnoreErrors ( mIgnoreErrors , true ) ;
targetType = ResolveTypeRef ( identifier , NULL ) ;
}
if ( auto nameIdentifier = BfNodeDynCast < BfIdentifierNode > ( memberRefExpr - > mMemberName ) )
{
dotNode = memberRefExpr - > mDotToken ;
nameNode = nameIdentifier ;
}
else
return BfTypedValue ( ) ;
}
else if ( auto qualifiedNameNode = BfNodeDynCast < BfQualifiedNameNode > ( invocationExpr - > mTarget ) )
{
SetAndRestoreValue < bool > prevIgnoreErrors ( mIgnoreErrors , true ) ;
targetType = ResolveTypeRef ( qualifiedNameNode - > mLeft , NULL ) ;
nameNode = qualifiedNameNode - > mRight ;
}
2022-01-09 12:20:43 -05:00
else if ( auto identiferNode = BfNodeDynCast < BfIdentifierNode > ( invocationExpr - > mTarget ) )
{
targetType = mCurTypeInstance ;
nameNode = identiferNode ;
}
2019-08-23 11:56:54 -07:00
else
return BfTypedValue ( ) ;
// These may have been colorized as methods, so change that
SetElementType ( nameNode , BfSourceElementType_Normal ) ;
if ( ( targetType = = NULL ) | | ( ! targetType - > IsPayloadEnum ( ) ) )
return BfTypedValue ( ) ;
auto enumType = targetType - > ToTypeInstance ( ) ;
PopulateType ( enumType ) ;
2019-11-19 09:58:35 -08:00
StringT < 128 > enumCaseName ;
2019-08-23 11:56:54 -07:00
if ( nameNode ! = NULL )
2019-11-19 09:58:35 -08:00
nameNode - > ToString ( enumCaseName ) ;
2019-08-23 11:56:54 -07:00
auto tagType = GetPrimitiveType ( BfTypeCode_Int32 ) ;
if ( enumVal . mType ! = enumType )
{
Fail ( StrFormat ( " Cannot match enum type '%s' with type '%s' " ,
TypeToString ( enumVal . mType ) . c_str ( ) , TypeToString ( enumType ) . c_str ( ) ) ) ;
enumVal = GetDefaultTypedValue ( enumType ) ;
tagVal = GetDefaultTypedValue ( tagType ) ;
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
for ( int fieldIdx = 0 ; fieldIdx < ( int ) enumType - > mFieldInstances . size ( ) ; fieldIdx + + )
{
auto fieldInstance = & enumType - > mFieldInstances [ fieldIdx ] ;
auto fieldDef = fieldInstance - > GetFieldDef ( ) ;
if ( fieldDef = = NULL )
continue ;
if ( ( fieldInstance - > mIsEnumPayloadCase ) & & ( fieldDef - > mName = = enumCaseName ) )
{
2023-11-18 07:42:04 -05:00
if ( ! IsInSpecializedSection ( ) )
{
if ( ( ! enumType - > IsTypeMemberIncluded ( fieldDef - > mDeclaringType , activeTypeDef , this ) ) | |
( ! enumType - > IsTypeMemberAccessible ( fieldDef - > mDeclaringType , activeTypeDef ) ) )
continue ;
}
2019-08-23 11:56:54 -07:00
auto resolvePassData = mCompiler - > mResolvePassData ;
if ( resolvePassData ! = NULL )
{
if ( resolvePassData - > mGetSymbolReferenceKind = = BfGetSymbolReferenceKind_Field )
resolvePassData - > HandleFieldReference ( nameNode , enumType - > mTypeDef , fieldDef ) ;
String filter ;
2022-07-26 13:27:03 -04:00
auto autoComplete = resolvePassData - > mAutoComplete ;
2019-08-23 11:56:54 -07:00
if ( ( autoComplete ! = NULL ) & & ( autoComplete - > InitAutocomplete ( dotNode , nameNode , filter ) ) )
autoComplete - > AddEnumTypeMembers ( enumType , enumCaseName , false , enumType = = mCurTypeInstance ) ;
}
BF_ASSERT ( fieldInstance - > mResolvedType - > IsTuple ( ) ) ;
2020-06-04 15:02:46 -07:00
auto tupleType = ( BfTypeInstance * ) fieldInstance - > mResolvedType ;
2019-08-23 11:56:54 -07:00
PopulateType ( tupleType ) ;
mBfIRBuilder - > PopulateType ( tupleType ) ;
auto boolType = GetPrimitiveType ( BfTypeCode_Boolean ) ;
tagId = - fieldInstance - > mDataIdx - 1 ;
auto startBlock = mBfIRBuilder - > GetInsertBlock ( ) ;
auto dscrType = enumType - > GetDiscriminatorType ( ) ;
BfIRValue eqResult = mBfIRBuilder - > CreateCmpEQ ( tagVal . mValue , mBfIRBuilder - > CreateConst ( dscrType - > mTypeDef - > mTypeCode , tagId ) ) ;
2021-11-15 16:44:28 -08:00
BfIRBlock falseBlockStart ;
BfIRBlock falseBlockEnd ;
BfIRBlock doneBlockStart ;
BfIRBlock doneBlockEnd ;
2022-07-26 13:27:03 -04:00
if ( notEqBlock ! = NULL )
2021-11-15 16:44:28 -08:00
doneBlockStart = doneBlockEnd = * notEqBlock ;
2022-07-26 13:27:03 -04:00
else
doneBlockStart = doneBlockEnd = mBfIRBuilder - > CreateBlock ( " caseDone " , false ) ;
2019-08-23 11:56:54 -07:00
if ( clearOutOnMismatch )
{
2021-11-15 16:44:28 -08:00
falseBlockStart = falseBlockEnd = mBfIRBuilder - > CreateBlock ( " caseNotEq " , false ) ;
mBfIRBuilder - > AddBlock ( falseBlockStart ) ;
2019-08-23 11:56:54 -07:00
}
2021-11-15 16:44:28 -08:00
BfIRBlock matchedBlockStart = mBfIRBuilder - > CreateBlock ( " caseMatch " , false ) ;
BfIRBlock matchedBlockEnd = matchedBlockStart ;
2019-08-23 11:56:54 -07:00
if ( matchBlock ! = NULL )
2021-11-15 16:44:28 -08:00
* matchBlock = matchedBlockStart ;
mBfIRBuilder - > CreateCondBr ( eqResult , matchedBlockStart , falseBlockStart ? falseBlockStart : doneBlockStart ) ;
2022-07-26 13:27:03 -04:00
2021-11-15 16:44:28 -08:00
mBfIRBuilder - > AddBlock ( matchedBlockStart ) ;
2022-07-26 13:27:03 -04:00
2021-11-15 16:44:28 -08:00
mBfIRBuilder - > SetInsertPoint ( doneBlockEnd ) ;
2019-08-23 11:56:54 -07:00
BfIRValue phiVal ;
if ( eqBlock = = NULL )
phiVal = mBfIRBuilder - > CreatePhi ( mBfIRBuilder - > MapType ( boolType ) , 1 + ( int ) tupleType - > mFieldInstances . size ( ) ) ;
2022-07-26 13:27:03 -04:00
2021-11-15 16:44:28 -08:00
mBfIRBuilder - > SetInsertPoint ( matchedBlockEnd ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
BfTypedValue tupleVal ;
if ( ! enumVal . IsAddr ( ) )
{
auto unionInnerType = enumType - > GetUnionInnerType ( ) ;
if ( unionInnerType = = tupleType )
2022-07-26 13:27:03 -04:00
{
tupleVal = ExtractValue ( enumVal , NULL , 1 ) ;
2019-08-23 11:56:54 -07:00
}
}
if ( ! tupleVal )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
if ( ! tupleType - > IsValuelessType ( ) )
{
tupleVal = ExtractValue ( enumVal , NULL , 1 ) ;
2022-07-26 13:27:03 -04:00
tupleVal = Cast ( NULL , tupleVal , tupleType , BfCastFlags_Force ) ;
2019-08-23 11:56:54 -07:00
}
else
tupleVal = GetDefaultTypedValue ( tupleType ) ;
}
2019-11-27 08:00:15 -08:00
////
2019-08-23 11:56:54 -07:00
BfAstNode * tooFewRef = invocationExpr - > mCloseParen ;
if ( ( tooFewRef = = NULL ) & & ( ! invocationExpr - > mCommas . IsEmpty ( ) ) )
tooFewRef = invocationExpr - > mCommas [ invocationExpr - > mCommas . size ( ) - 1 ] ;
else if ( tooFewRef = = NULL )
2022-07-26 13:27:03 -04:00
tooFewRef = invocationExpr - > mOpenParen ;
2019-08-23 11:56:54 -07:00
///
auto autoComplete = mCompiler - > GetAutoComplete ( ) ;
bool wasCapturingMethodInfo = false ;
if ( autoComplete ! = NULL )
{
wasCapturingMethodInfo = autoComplete - > mIsCapturingMethodMatchInfo ;
autoComplete - > CheckInvocation ( invocationExpr , invocationExpr - > mOpenParen , invocationExpr - > mCloseParen , invocationExpr - > mCommas ) ;
if ( autoComplete - > mIsCapturingMethodMatchInfo )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
autoComplete - > mMethodMatchInfo - > mInstanceList . Clear ( ) ;
auto methodMatchInfo = autoComplete - > mMethodMatchInfo ;
BfAutoComplete : : MethodMatchEntry methodMatchEntry ;
methodMatchEntry . mTypeInstance = enumType ;
methodMatchEntry . mCurMethodInstance = mCurMethodInstance ;
methodMatchEntry . mPayloadEnumField = fieldInstance ;
autoComplete - > mMethodMatchInfo - > mInstanceList . push_back ( methodMatchEntry ) ;
methodMatchInfo - > mBestIdx = 0 ;
methodMatchInfo - > mMostParamsMatched = 0 ;
int cursorIdx = invocationExpr - > GetParser ( ) - > mCursorIdx ;
if ( ( invocationExpr - > mCloseParen = = NULL ) | | ( cursorIdx < = invocationExpr - > mCloseParen - > GetSrcStart ( ) ) )
{
int paramIdx = 0 ;
for ( int commaIdx = 0 ; commaIdx < ( int ) invocationExpr - > mCommas . size ( ) ; commaIdx + + )
{
auto commaNode = invocationExpr - > mCommas [ commaIdx ] ;
if ( ( commaNode ! = NULL ) & & ( cursorIdx > = commaNode - > GetSrcStart ( ) ) )
paramIdx = commaIdx + 1 ;
}
bool isEmpty = true ;
if ( paramIdx < ( int ) invocationExpr - > mArguments . size ( ) )
{
auto paramNode = invocationExpr - > mArguments [ paramIdx ] ;
if ( paramNode ! = NULL )
isEmpty = false ;
}
if ( isEmpty )
{
if ( paramIdx < ( int ) tupleType - > mFieldInstances . size ( ) )
{
auto fieldDef = tupleType - > mFieldInstances [ paramIdx ] . GetFieldDef ( ) ;
String insertStr ;
if ( fieldDef - > IsUnnamedTupleField ( ) )
insertStr = " p " ;
insertStr + = fieldDef - > mName ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
insertStr . Insert ( 0 , " let " ) ;
autoComplete - > mEntriesSet . Clear ( ) ;
autoComplete - > AddEntry ( AutoCompleteEntry ( " paramName " , insertStr ) ) ;
autoComplete - > mInsertStartIdx = cursorIdx ;
autoComplete - > mInsertEndIdx = cursorIdx ;
}
}
}
}
}
defer
2019-10-15 12:28:21 -07:00
(
2019-08-23 11:56:54 -07:00
if ( autoComplete ! = NULL )
autoComplete - > mIsCapturingMethodMatchInfo = ( wasCapturingMethodInfo ) & & ( ! autoComplete - > mIsCapturingMethodMatchInfo ) ;
2019-10-15 12:28:21 -07:00
) ;
2019-08-23 11:56:54 -07:00
///
2022-07-26 13:27:03 -04:00
HandleCaseEnumMatch_Tuple ( tupleVal , invocationExpr - > mArguments , tooFewRef , falseBlockStart ? BfIRValue ( ) : phiVal , matchedBlockStart , matchedBlockEnd ,
2021-11-15 16:44:28 -08:00
falseBlockStart ? falseBlockStart : doneBlockStart , falseBlockEnd ? falseBlockEnd : doneBlockEnd ,
2022-05-24 06:52:28 -07:00
hadConditional , clearOutOnMismatch , prevHadFallthrough ) ;
2019-08-23 11:56:54 -07:00
2019-11-27 08:00:15 -08:00
///////
2019-08-23 11:56:54 -07:00
if ( phiVal )
{
2021-11-15 16:44:28 -08:00
auto falseVal = mBfIRBuilder - > CreateConst ( BfTypeCode_Boolean , 0 ) ;
if ( falseBlockEnd )
mBfIRBuilder - > AddPhiIncoming ( phiVal , falseVal , falseBlockEnd ) ;
else
mBfIRBuilder - > AddPhiIncoming ( phiVal , falseVal , startBlock ) ;
2019-08-23 11:56:54 -07:00
auto trueVal = mBfIRBuilder - > CreateConst ( BfTypeCode_Boolean , 1 ) ;
2021-11-15 16:44:28 -08:00
mBfIRBuilder - > AddPhiIncoming ( phiVal , trueVal , matchedBlockEnd ) ;
2019-08-23 11:56:54 -07:00
}
if ( eqBlock ! = NULL )
mBfIRBuilder - > CreateBr ( * eqBlock ) ;
else
2021-11-15 16:44:28 -08:00
mBfIRBuilder - > CreateBr ( doneBlockStart ) ;
2019-08-23 11:56:54 -07:00
2021-11-15 16:44:28 -08:00
if ( falseBlockEnd )
2022-07-26 13:27:03 -04:00
{
2021-11-15 16:44:28 -08:00
mBfIRBuilder - > SetInsertPoint ( falseBlockEnd ) ;
mBfIRBuilder - > CreateBr ( doneBlockStart ) ;
2019-08-23 11:56:54 -07:00
//mBfIRBuilder->AddPhiIncoming(phiVal, mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 0), falseBlock);
}
2021-11-15 16:44:28 -08:00
mBfIRBuilder - > AddBlock ( doneBlockStart ) ;
mBfIRBuilder - > SetInsertPoint ( doneBlockEnd ) ;
2019-08-23 11:56:54 -07:00
if ( phiVal )
return BfTypedValue ( phiVal , boolType ) ;
else
return GetDefaultTypedValue ( boolType ) ;
}
}
return BfTypedValue ( ) ;
}
BfTypedValue BfModule : : HandleCaseBind ( BfTypedValue enumVal , const BfTypedValue & tagVal , BfEnumCaseBindExpression * bindExpr , BfIRBlock * eqBlock , BfIRBlock * notEqBlock , BfIRBlock * matchBlock , int * outEnumIdx )
{
2022-07-26 13:27:03 -04:00
BfTypeInstance * tupleType = NULL ;
2019-08-23 11:56:54 -07:00
auto activeTypeDef = GetActiveTypeDef ( ) ;
auto boolType = GetPrimitiveType ( BfTypeCode_Boolean ) ;
BfIRValue eqResult ;
if ( bindExpr - > mEnumMemberExpr ! = NULL )
{
int enumIdx = - 1 ;
String findName ;
BfType * type = NULL ;
BfAstNode * targetNode = NULL ;
BfAstNode * nameNode = NULL ;
BfAstNode * dotNode = NULL ;
if ( auto memberExpr = BfNodeDynCast < BfMemberReferenceExpression > ( bindExpr - > mEnumMemberExpr ) )
{
dotNode = memberExpr - > mDotToken ;
if ( memberExpr - > mMemberName ! = NULL )
{
nameNode = memberExpr - > mMemberName ;
findName = memberExpr - > mMemberName - > ToString ( ) ;
if ( memberExpr - > mTarget = = NULL )
{
type = enumVal . mType ;
}
else if ( auto typeRef = BfNodeDynCast < BfTypeReference > ( memberExpr - > mTarget ) )
{
2022-07-26 13:27:03 -04:00
type = ResolveTypeRef ( typeRef ) ;
2019-08-23 11:56:54 -07:00
}
}
targetNode = memberExpr - > mTarget ;
}
else if ( auto identiferNode = BfNodeDynCast < BfIdentifierNode > ( bindExpr - > mEnumMemberExpr ) )
{
if ( mCurTypeInstance - > IsPayloadEnum ( ) )
{
nameNode = identiferNode ;
findName = nameNode - > ToString ( ) ;
targetNode = identiferNode ;
type = mCurTypeInstance ;
}
else
{
Fail ( " Expected a qualified enum case name. Consider prefixing name with a dot to infer enum type name. " , bindExpr - > mEnumMemberExpr ) ;
}
}
if ( ! findName . empty ( ) )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
if ( type ! = NULL )
{
if ( type ! = enumVal . mType )
{
Fail ( StrFormat ( " Enum case type '%s' does not match compared value of type '%s' " ,
TypeToString ( enumVal . mType ) . c_str ( ) , TypeToString ( type ) . c_str ( ) ) , targetNode ) ;
}
if ( type - > IsEnum ( ) )
{
auto enumType = ( BfTypeInstance * ) type ;
2022-02-11 05:47:32 -05:00
for ( auto & fieldInstance : enumType - > mFieldInstances )
2019-08-23 11:56:54 -07:00
{
auto fieldDef = fieldInstance . GetFieldDef ( ) ;
if ( ( fieldDef ! = NULL ) & & ( fieldDef - > IsEnumCaseEntry ( ) ) & & ( fieldDef - > mName = = findName ) )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
if ( ( ! enumType - > IsTypeMemberIncluded ( fieldDef - > mDeclaringType , activeTypeDef , this ) ) | |
( ! enumType - > IsTypeMemberAccessible ( fieldDef - > mDeclaringType , activeTypeDef ) ) )
continue ;
auto resolvePassData = mCompiler - > mResolvePassData ;
if ( resolvePassData ! = NULL )
{
if ( resolvePassData - > mGetSymbolReferenceKind = = BfGetSymbolReferenceKind_Field )
resolvePassData - > HandleFieldReference ( nameNode , enumType - > mTypeDef , fieldDef ) ;
String filter ;
2022-07-26 13:27:03 -04:00
auto autoComplete = resolvePassData - > mAutoComplete ;
2019-08-23 11:56:54 -07:00
if ( ( autoComplete ! = NULL ) & & ( autoComplete - > InitAutocomplete ( dotNode , nameNode , filter ) ) )
autoComplete - > AddEnumTypeMembers ( enumType , findName , false , enumType = = mCurTypeInstance ) ;
}
enumIdx = - fieldInstance . mDataIdx - 1 ;
if ( outEnumIdx ! = NULL )
* outEnumIdx = enumIdx ;
if ( fieldInstance . mIsEnumPayloadCase )
tupleType = fieldInstance . mResolvedType - > ToTypeInstance ( ) ;
}
}
if ( enumIdx = = - 1 )
{
Fail ( " Enum case not found " , nameNode ) ;
}
}
else
{
Fail ( StrFormat ( " Type '%s' is not an enum type " , TypeToString ( type ) . c_str ( ) ) , targetNode ) ;
}
2022-07-26 13:27:03 -04:00
}
}
2019-08-23 11:56:54 -07:00
BF_ASSERT ( tagVal . mType - > IsPrimitiveType ( ) ) ;
eqResult = mBfIRBuilder - > CreateCmpEQ ( tagVal . mValue , mBfIRBuilder - > CreateConst ( ( ( BfPrimitiveType * ) tagVal . mType ) - > mTypeDef - > mTypeCode , enumIdx ) ) ;
}
else
{
eqResult = mBfIRBuilder - > CreateConst ( BfTypeCode_Boolean , 0 ) ;
}
BfIRBlock falseBlock ;
if ( notEqBlock ! = NULL )
{
falseBlock = * notEqBlock ;
}
else
{
falseBlock = mBfIRBuilder - > CreateBlock ( " notEqBlock " , false ) ;
}
auto mainBlock = mBfIRBuilder - > GetInsertBlock ( ) ;
2022-07-26 13:27:03 -04:00
BfIRBlock trueBlock = mBfIRBuilder - > CreateBlock ( " eqBlock " , false ) ;
2019-08-23 11:56:54 -07:00
if ( matchBlock ! = NULL )
* matchBlock = trueBlock ;
mBfIRBuilder - > AddBlock ( trueBlock ) ;
mBfIRBuilder - > SetInsertPoint ( trueBlock ) ;
if ( ( tupleType ! = NULL ) & & ( bindExpr - > mBindNames ! = NULL ) )
{
BfIRValue valueScopeStart ;
if ( IsTargetingBeefBackend ( ) )
valueScopeStart = mBfIRBuilder - > CreateValueScopeStart ( ) ;
bool isVar = bindExpr - > mBindToken - > GetToken ( ) = = BfToken_Var ;
bool isLet = bindExpr - > mBindToken - > GetToken ( ) = = BfToken_Let ;
BfTypedValue tupleVal ;
if ( enumVal . IsAddr ( ) )
{
auto ptrVal = mBfIRBuilder - > CreateInBoundsGEP ( enumVal . mValue , 0 , 1 ) ;
tupleVal = BfTypedValue ( mBfIRBuilder - > CreateBitCast ( ptrVal , mBfIRBuilder - > MapTypeInstPtr ( tupleType ) ) , tupleType , true ) ;
}
else
{
auto unionInnerType = enumVal . mType - > ToTypeInstance ( ) - > GetUnionInnerType ( ) ;
tupleVal = ExtractValue ( enumVal , NULL , 1 ) ;
if ( unionInnerType ! = tupleType )
{
tupleVal = MakeAddressable ( tupleVal ) ;
tupleVal = BfTypedValue ( mBfIRBuilder - > CreateBitCast ( tupleVal . mValue , mBfIRBuilder - > MapTypeInstPtr ( tupleType ) ) , tupleType , true ) ;
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
}
HandleTupleVariableDeclaration ( NULL , bindExpr - > mBindNames , tupleVal , isLet , false , true /*, &mainBlock*/ ) ;
auto autoComplete = mCompiler - > GetAutoComplete ( ) ;
if ( ( autoComplete ! = NULL ) & & ( ( isVar | | isLet ) ) )
autoComplete - > CheckVarResolution ( bindExpr - > mBindToken , tupleType ) ;
if ( valueScopeStart )
mBfIRBuilder - > CreateValueScopeSoftEnd ( valueScopeStart ) ;
}
if ( eqBlock ! = NULL )
mBfIRBuilder - > CreateBr ( * eqBlock ) ;
else
mBfIRBuilder - > CreateBr ( falseBlock ) ;
// Don't create the condBr until now, so HandleTupleVariableDeclaration can create the variable declarations in mainBlock--
2022-07-26 13:27:03 -04:00
// we need them there since the code that uses the new variables is created outside the eqBlock
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > SetInsertPoint ( mainBlock ) ;
mBfIRBuilder - > CreateCondBr ( eqResult , trueBlock , falseBlock ) ;
mBfIRBuilder - > AddBlock ( falseBlock ) ;
2022-07-26 13:27:03 -04:00
mBfIRBuilder - > SetInsertPoint ( falseBlock ) ;
2019-08-23 11:56:54 -07:00
return BfTypedValue ( eqResult , boolType ) ;
}
void BfModule : : AddBasicBlock ( BfIRBlock bb , bool activate )
{
mBfIRBuilder - > AddBlock ( bb ) ;
if ( activate )
mBfIRBuilder - > SetInsertPoint ( bb ) ;
}
2019-09-12 09:46:54 -07:00
void BfModule : : VisitEmbeddedStatement ( BfAstNode * stmt , BfExprEvaluator * exprEvaluator , BfEmbeddedStatementFlags flags )
2019-08-23 11:56:54 -07:00
{
2024-03-18 05:44:02 -04:00
if ( ( flags & BfEmbeddedStatementFlags_CheckStack ) ! = 0 )
{
BP_ZONE ( " BfModule.VisitEmbeddedStatement " ) ;
StackHelper stackHelper ;
if ( ! stackHelper . CanStackExpand ( 64 * 1024 ) )
{
if ( ! stackHelper . Execute ( [ & ] ( )
{
VisitEmbeddedStatement ( stmt , exprEvaluator , flags ) ;
} ) )
{
Fail ( " Statement too complex to parse " , stmt ) ;
}
return ;
}
}
2019-08-23 11:56:54 -07:00
auto block = BfNodeDynCast < BfBlock > ( stmt ) ;
BfLabelNode * labelNode = NULL ;
if ( block = = NULL )
{
auto labeledBlock = BfNodeDynCast < BfLabeledBlock > ( stmt ) ;
if ( labeledBlock ! = NULL )
{
block = labeledBlock - > mBlock ;
labelNode = labeledBlock - > mLabelNode ;
}
}
BfAstNode * openBrace = NULL ;
BfAstNode * closeBrace = NULL ;
if ( block ! = NULL )
{
openBrace = block - > mOpenBrace ;
closeBrace = block - > mCloseBrace ;
if ( openBrace = = NULL )
{
auto checkScope = mCurMethodState - > mCurScope ;
while ( ( checkScope ! = NULL ) & & ( closeBrace = = NULL ) )
{
closeBrace = checkScope - > mCloseNode ;
checkScope = checkScope - > mPrevScope ;
}
BF_ASSERT ( closeBrace ! = NULL ) ;
}
}
if ( ( block ! = NULL ) & & ( openBrace ! = NULL ) )
UpdateSrcPos ( openBrace ) ;
2021-01-04 06:33:39 -08:00
if ( ( flags & BfEmbeddedStatementFlags_Unscoped ) ! = 0 )
{
SetAndRestoreValue < BfExprEvaluator * > prevExprEvaluator ( mCurMethodState - > mCurScope - > mExprEvaluator , exprEvaluator ) ;
2022-01-29 15:02:19 -05:00
SetAndRestoreValue < bool > prevAllowReturn ( mCurMethodState - > mDisableReturns , true ) ;
2021-01-04 06:33:39 -08:00
VisitCodeBlock ( block ) ;
}
else if ( mCurMethodState ! = NULL )
2019-08-23 11:56:54 -07:00
{
2022-07-26 13:27:03 -04:00
bool isIgnore = mBfIRBuilder - > mIgnoreWrites ;
2019-08-23 11:56:54 -07:00
mCurMethodState - > mInHeadScope = false ;
2022-07-26 13:27:03 -04:00
BfScopeData scopeData ;
2019-08-23 11:56:54 -07:00
if ( IsTargetingBeefBackend ( ) )
scopeData . mValueScopeStart = mBfIRBuilder - > CreateValueScopeStart ( ) ;
2021-01-04 06:33:39 -08:00
2019-08-23 11:56:54 -07:00
mCurMethodState - > AddScope ( & scopeData ) ;
if ( block ! = NULL )
{
mCurMethodState - > mCurScope - > mAstBlock = block ;
mCurMethodState - > mCurScope - > mCloseNode = closeBrace ;
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
if ( labelNode ! = NULL )
scopeData . mLabelNode = labelNode - > mLabel ;
NewScopeState ( block ! = NULL ) ;
2019-09-12 09:46:54 -07:00
mCurMethodState - > mCurScope - > mOuterIsConditional = ( flags & BfEmbeddedStatementFlags_IsConditional ) ! = 0 ;
mCurMethodState - > mCurScope - > mIsDeferredBlock = ( flags & BfEmbeddedStatementFlags_IsDeferredBlock ) ! = 0 ;
2022-07-26 13:27:03 -04:00
mCurMethodState - > mCurScope - > mExprEvaluator = exprEvaluator ;
2022-07-05 08:04:38 -07:00
2019-09-12 09:46:54 -07:00
//
2019-08-23 11:56:54 -07:00
{
2019-09-12 09:46:54 -07:00
SetAndRestoreValue < bool > inDeferredBlock ( mCurMethodState - > mInDeferredBlock , mCurMethodState - > mInDeferredBlock | | mCurMethodState - > mCurScope - > mIsDeferredBlock ) ;
if ( block ! = NULL )
{
if ( labelNode ! = NULL )
VisitCodeBlock ( block , BfIRBlock ( ) , BfIRBlock ( ) , BfIRBlock ( ) , false , NULL , labelNode ) ;
else
VisitCodeBlock ( block ) ;
}
2019-08-23 11:56:54 -07:00
else
2020-06-18 06:12:14 -07:00
{
if ( auto varDecl = BfNodeDynCast < BfVariableDeclaration > ( stmt ) )
{
Fail ( " Variable declarations must be wrapped in a block statement " , varDecl ) ;
}
2019-09-12 09:46:54 -07:00
VisitChild ( stmt ) ;
2020-06-18 06:12:14 -07:00
}
2019-08-23 11:56:54 -07:00
}
2019-09-12 09:46:54 -07:00
2019-08-23 11:56:54 -07:00
if ( ( block ! = NULL ) & & ( closeBrace ! = NULL ) )
{
UpdateSrcPos ( closeBrace ) ;
if ( ! mCurMethodState - > mLeftBlockUncond )
EmitEnsureInstructionAt ( ) ;
}
if ( block ! = NULL )
{
BfAutoParentNodeEntry autoParentNodeEntry ( this , block ) ;
RestoreScopeState ( ) ;
}
else
RestoreScopeState ( ) ;
BF_ASSERT ( isIgnore = = mBfIRBuilder - > mIgnoreWrites ) ;
}
else
{
if ( block ! = NULL )
VisitCodeBlock ( block ) ;
else
VisitChild ( stmt ) ;
}
}
2022-07-05 08:04:38 -07:00
void BfModule : : VisitCodeBlock ( BfBlock * block , BfIRBlock continueBlock , BfIRBlock breakBlock , BfIRBlock fallthroughBlock , bool defaultBreak , bool * hadReturn , BfLabelNode * labelNode , bool closeScope , BfEmbeddedStatementFlags flags )
2019-08-23 11:56:54 -07:00
{
BfBreakData breakData ;
breakData . mIRContinueBlock = continueBlock ;
breakData . mIRBreakBlock = breakBlock ;
breakData . mIRFallthroughBlock = fallthroughBlock ;
breakData . mScope = mCurMethodState - > mCurScope ;
breakData . mPrevBreakData = mCurMethodState - > mBreakData ;
SetAndRestoreValue < BfBreakData * > prevBreakData ( mCurMethodState - > mBreakData , & breakData ) ;
2022-07-05 08:04:38 -07:00
VisitEmbeddedStatement ( block , NULL , flags ) ;
2019-08-23 11:56:54 -07:00
2022-07-26 13:27:03 -04:00
if ( closeScope )
2019-08-23 11:56:54 -07:00
RestoreScopeState ( ) ;
if ( ( ! mCurMethodState - > mLeftBlockUncond ) & & ( defaultBreak ) )
{
mBfIRBuilder - > CreateBr ( breakBlock ) ;
}
if ( hadReturn ! = NULL )
{
* hadReturn = mCurMethodState - > mHadReturn ;
mCurMethodState - > SetHadReturn ( false ) ;
mCurMethodState - > mLeftBlockUncond = false ;
}
}
void BfModule : : VisitCodeBlock ( BfBlock * block )
{
2022-05-06 12:03:39 -07:00
//BP_ZONE("BfModule::VisitCodeBlock");
2019-08-23 11:56:54 -07:00
BfAutoParentNodeEntry autoParentNodeEntry ( this , block ) ;
BfIRBlock prevInsertBlock ;
bool hadReturn = false ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
int startLocalMethod = 0 ; // was -1
auto rootMethodState = mCurMethodState - > GetRootMethodState ( ) ;
2022-07-26 13:27:03 -04:00
BfIRBlock startInsertBlock = mBfIRBuilder - > GetInsertBlock ( ) ;
2021-09-14 08:00:43 -07:00
2019-08-23 11:56:54 -07:00
bool allowLocalMethods = mCurMethodInstance ! = NULL ;
//int startDeferredLocalIdx = (int)rootMethodState->mDeferredLocalMethods.size();
2022-07-26 13:27:03 -04:00
2019-09-11 10:04:58 -07:00
int curLocalMethodIdx = - 1 ;
2019-08-23 11:56:54 -07:00
// Scan for any local method declarations
if ( allowLocalMethods )
{
startLocalMethod = ( int ) mCurMethodState - > mLocalMethods . size ( ) ;
curLocalMethodIdx = startLocalMethod ;
auto itr = block - > begin ( ) ;
while ( itr ! = block - > end ( ) )
{
BfAstNode * child = * itr ;
if ( auto localMethodDecl = BfNodeDynCastExact < BfLocalMethodDeclaration > ( child ) )
{
BfLocalMethod * localMethod ;
auto rootMethodState = mCurMethodState - > GetRootMethodState ( ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
String methodName ;
if ( localMethodDecl - > mMethodDeclaration - > mNameNode ! = NULL )
{
methodName = GetLocalMethodName ( localMethodDecl - > mMethodDeclaration - > mNameNode - > ToString ( ) , localMethodDecl - > mMethodDeclaration - > mOpenParen , mCurMethodState , mCurMethodState - > mMixinState ) ;
BfLocalMethod * * localMethodPtr = NULL ;
if ( rootMethodState - > mLocalMethodCache . TryGetValue ( methodName , & localMethodPtr ) )
{
localMethod = * localMethodPtr ;
}
else
{
localMethod = new BfLocalMethod ( ) ;
localMethod - > mSystem = mSystem ;
localMethod - > mModule = this ;
localMethod - > mMethodDeclaration = localMethodDecl - > mMethodDeclaration ;
localMethod - > mSource = mCurTypeInstance - > mTypeDef - > mSource ;
localMethod - > mSource - > mRefCount + + ;
if ( mCurMethodState - > mClosureState ! = NULL )
localMethod - > mOuterLocalMethod = mCurMethodState - > mClosureState - > mLocalMethod ;
auto autoComplete = mCompiler - > GetAutoComplete ( ) ;
if ( ( autoComplete ! = NULL ) & & ( autoComplete - > mResolveType = = BfResolveType_Autocomplete ) )
{
auto autoComplete = mCompiler - > mResolvePassData - > mAutoComplete ;
if ( ! autoComplete - > IsAutocompleteNode ( localMethod - > mMethodDeclaration ) )
localMethod - > mDeclOnly = true ;
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
if ( localMethod - > mMethodDeclaration - > mNameNode ! = NULL )
localMethod - > mMethodName = localMethod - > mMethodDeclaration - > mNameNode - > ToString ( ) ;
localMethod - > mExpectedFullName = methodName ;
rootMethodState - > mLocalMethodCache [ methodName ] = localMethod ;
mContext - > mLocalMethodGraveyard . push_back ( localMethod ) ;
}
BF_ASSERT ( mCurMethodState - > mCurScope ! = NULL ) ;
localMethod - > mDeclDIScope = mCurMethodState - > mCurScope - > mDIScope ;
localMethod - > mDeclMethodState = mCurMethodState ;
localMethod - > mDeclMixinState = mCurMethodState - > mMixinState ;
if ( localMethod - > mDeclMixinState ! = NULL )
localMethod - > mDeclMixinState - > mHasDeferredUsage = true ;
mCurMethodState - > mLocalMethods . push_back ( localMethod ) ;
2022-07-26 13:27:03 -04:00
String * namePtr ;
if ( ! mCurMethodState - > mLocalMethodMap . TryAdd ( localMethod - > mMethodName , & namePtr , & localMethodPtr ) )
{
2019-09-12 09:46:54 -07:00
BF_ASSERT ( localMethod ! = * localMethodPtr ) ;
2022-07-26 13:27:03 -04:00
localMethod - > mNextWithSameName = * localMethodPtr ;
2019-09-11 10:04:58 -07:00
}
2019-08-23 11:56:54 -07:00
* localMethodPtr = localMethod ;
}
}
+ + itr ;
}
}
bool wantsAllLocalMethods = true ;
2022-07-26 13:27:03 -04:00
auto autoComplete = mCompiler - > GetAutoComplete ( ) ;
2019-08-23 11:56:54 -07:00
if ( autoComplete ! = NULL )
{
// If we only need reasoning "at the cursor" then we don't need all local methods
if ( ( ! autoComplete - > mIsAutoComplete ) | |
( autoComplete - > mResolveType = = BfResolveType_GetCurrentLocation ) | |
( autoComplete - > mResolveType = = BfResolveType_GetFixits ) | |
2019-12-24 13:13:04 -08:00
( autoComplete - > mResolveType = = BfResolveType_GetResultString ) | |
2019-08-23 11:56:54 -07:00
( autoComplete - > mResolveType = = BfResolveType_GetSymbolInfo ) | |
( autoComplete - > mResolveType = = BfResolveType_ShowFileSymbolReferences ) )
wantsAllLocalMethods = false ;
}
/*if ((mCompiler->mResolvePassData != NULL) && (mCompiler->mResolvePassData->mResolveType == BfResolveType_ShowFileSymbolReferences))
{
if ( mCompiler - > mResolvePassData - > mSymbolReferenceLocalIdx ! = - 1 )
{
// We need to reproduce the behavior when we found the symbol - only process autocomplete nodes, otherwise local method ids will be wrong
// when we have local methods that were skipped the first time but not the second
wantsAllLocalMethods = false ;
}
} */
2020-09-16 04:29:21 -07:00
SetAndRestoreValue < bool > prevIgnoreWrite ( mBfIRBuilder - > mIgnoreWrites ) ;
bool hadUnreachableCode = false ;
2019-08-23 11:56:54 -07:00
// Handle statements
auto itr = block - > begin ( ) ;
while ( itr ! = block - > end ( ) )
{
BfAstNode * child = * itr ;
if ( auto localMethodDecl = BfNodeDynCastExact < BfLocalMethodDeclaration > ( child ) )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
/*if ((mCurMethodInstance != NULL) && (mCurMethodInstance->mMethodDef->mMethodType == BfMethodType_Mixin))
Fail ( " Mixins cannot contain local methods " , child ) ; */
if ( ! allowLocalMethods )
{
Fail ( " Invalid use of local methods " , child ) ;
}
else if ( localMethodDecl - > mMethodDeclaration - > mNameNode ! = NULL )
{
BfLocalMethod * localMethod = mCurMethodState - > mLocalMethods [ curLocalMethodIdx ] ;
BF_ASSERT ( localMethod - > mMethodDeclaration = = localMethodDecl - > mMethodDeclaration ) ;
2022-07-28 06:52:52 -04:00
bool wantsLocalMethod = ( wantsAllLocalMethods ) | | ( autoComplete - > IsAutocompleteNode ( localMethod - > mMethodDeclaration ) ) ;
if ( ( ! wantsLocalMethod ) & & ( mCurMethodInstance - > mMethodDef - > mIsLocalMethod ) )
wantsLocalMethod = true ;
if ( wantsLocalMethod )
2019-08-23 11:56:54 -07:00
{
if ( ! mCurMethodInstance - > IsSpecializedGenericMethodOrType ( ) )
GetLocalMethodInstance ( localMethod , BfTypeVector ( ) , NULL , true ) ; // Only necessary on unspecialized pass
}
if ( ( mCompiler - > mResolvePassData ! = NULL ) & & ( mCompiler - > mResolvePassData - > mAutoComplete ! = NULL ) )
mCompiler - > mResolvePassData - > mAutoComplete - > CheckMethod ( localMethod - > mMethodDeclaration , true ) ;
curLocalMethodIdx + + ;
}
+ + itr ;
continue ;
}
if ( ( mCurMethodState ! = NULL ) & & ( mCurMethodState - > mLeftBlockUncond ) ) // mLeftBlock is cleared after conditional block is completed
{
if ( mCurMethodState - > mHadReturn )
hadReturn = true ;
2022-07-26 13:27:03 -04:00
2020-09-16 04:29:21 -07:00
if ( ( ! hadUnreachableCode ) & & ( ! mCurMethodState - > mInPostReturn ) )
2019-08-23 11:56:54 -07:00
{
2022-03-19 09:16:51 -07:00
if ( ( mCurMethodState - > mCurScope = = NULL ) | | ( ! mCurMethodState - > mCurScope - > mSupressNextUnreachable ) )
Warn ( BfWarning_CS0162_UnreachableCode , " Unreachable code " , child ) ;
2019-08-23 11:56:54 -07:00
2020-09-16 04:29:21 -07:00
hadUnreachableCode = true ;
2019-08-23 11:56:54 -07:00
prevInsertBlock = mBfIRBuilder - > GetInsertBlock ( ) ;
2022-07-26 13:27:03 -04:00
mCurMethodState - > mInPostReturn = true ;
2020-09-16 04:29:21 -07:00
mBfIRBuilder - > mIgnoreWrites = true ;
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
}
2022-03-19 09:16:51 -07:00
if ( ( mCurMethodState ! = NULL ) & & ( mCurMethodState - > mCurScope ! = NULL ) )
mCurMethodState - > mCurScope - > mSupressNextUnreachable = false ;
2019-08-23 11:56:54 -07:00
if ( itr . IsLast ( ) )
{
if ( auto expr = BfNodeDynCast < BfExpression > ( child ) )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
if ( expr - > IsExpression ( ) )
{
if ( mCurMethodState ! = NULL )
{
if ( mCurMethodState - > mCurScope - > mExprEvaluator ! = NULL )
{
2020-08-16 08:33:51 -07:00
if ( ( mAttributeState ! = NULL ) & &
( ( mAttributeState - > mFlags & ( BfAttributeState : : Flag_StopOnError | BfAttributeState : : Flag_HadError ) ) = = ( BfAttributeState : : Flag_StopOnError | BfAttributeState : : Flag_HadError ) ) )
{
// Resolve as just 'false'
mCurMethodState - > mCurScope - > mExprEvaluator - > mResult = GetDefaultTypedValue ( GetPrimitiveType ( BfTypeCode_Boolean ) ) ;
}
else
{
2021-09-11 07:34:44 -07:00
auto exprEvaluator = mCurMethodState - > mCurScope - > mExprEvaluator ;
2020-08-16 08:33:51 -07:00
// Evaluate last child as an expression
2021-09-11 07:34:44 -07:00
exprEvaluator - > VisitChild ( expr ) ;
exprEvaluator - > FinishExpressionResult ( ) ;
2022-04-18 10:42:08 -07:00
if ( ( exprEvaluator - > mResult ) & & ( ! exprEvaluator - > mResult . mType - > IsValuelessType ( ) ) & & ( ! exprEvaluator - > mResult . mValue . IsConst ( ) ) & &
2023-08-18 12:04:33 -07:00
( ! exprEvaluator - > mResult . IsAddr ( ) ) & & ( exprEvaluator - > mResult . mValue ) & & ( ! exprEvaluator - > mResult . mValue . IsFake ( ) ) )
2022-07-26 13:27:03 -04:00
{
if ( ( mCurMethodState - > mCurScope ! = NULL ) & & ( mCurMethodState - > mCurScope - > mPrevScope ! = NULL ) )
2021-09-14 08:00:43 -07:00
{
// We need to make sure we don't retain any values through the scope's ValueScopeHardEnd - and extend alloca through previous scope
bool wasReadOnly = exprEvaluator - > mResult . IsReadOnly ( ) ;
2022-07-26 13:27:03 -04:00
FixIntUnknown ( exprEvaluator - > mResult , exprEvaluator - > mExpectingType ) ;
auto prevInsertBlock = mBfIRBuilder - > GetInsertBlock ( ) ;
2021-09-14 08:00:43 -07:00
auto tempVar = CreateAlloca ( exprEvaluator - > mResult . mType , false , " blockExpr " ) ;
mBfIRBuilder - > SetInsertPointAtStart ( startInsertBlock ) ;
auto lifetimeStart = mBfIRBuilder - > CreateLifetimeStart ( tempVar ) ;
mBfIRBuilder - > ClearDebugLocation ( lifetimeStart ) ;
2022-07-26 13:27:03 -04:00
2022-07-26 16:07:14 -04:00
if ( ( ! mBfIRBuilder - > mIgnoreWrites ) & & ( IsTargetingBeefBackend ( ) ) )
2021-09-21 09:58:43 -07:00
mCurMethodState - > mCurScope - > mPrevScope - > mDeferredLifetimeEnds . push_back ( tempVar ) ;
2021-09-14 08:00:43 -07:00
mBfIRBuilder - > SetInsertPoint ( prevInsertBlock ) ;
if ( exprEvaluator - > mResult . IsSplat ( ) )
AggregateSplatIntoAddr ( exprEvaluator - > mResult , tempVar ) ;
2023-08-18 12:04:33 -07:00
else if ( ! exprEvaluator - > mResult . mType - > IsValuelessType ( ) )
2021-09-14 08:00:43 -07:00
mBfIRBuilder - > CreateAlignedStore ( exprEvaluator - > mResult . mValue , tempVar , exprEvaluator - > mResult . mType - > mAlign ) ;
exprEvaluator - > mResult = BfTypedValue ( tempVar , exprEvaluator - > mResult . mType ,
exprEvaluator - > mResult . IsThis ( ) ?
( wasReadOnly ? BfTypedValueKind_ReadOnlyThisAddr : BfTypedValueKind_ThisAddr ) :
2022-07-26 13:27:03 -04:00
( wasReadOnly ? BfTypedValueKind_ReadOnlyAddr : BfTypedValueKind_Addr ) ) ;
2021-09-14 08:00:43 -07:00
}
2021-09-11 07:34:44 -07:00
}
2022-06-16 07:21:19 -07:00
if ( exprEvaluator - > mResult . IsAddr ( ) )
{
if ( mCurMethodState - > mCurScope - > ExtendLifetime ( exprEvaluator - > mResult . mValue ) )
mBfIRBuilder - > CreateLifetimeSoftEnd ( exprEvaluator - > mResult . mValue ) ;
}
2020-08-16 08:33:51 -07:00
}
2019-08-23 11:56:54 -07:00
break ;
}
else if ( mCurMethodState - > InMainMixinScope ( ) )
{
mCurMethodState - > mMixinState - > mResultExpr = expr ;
break ;
}
2022-03-08 06:27:06 -08:00
else if ( ( mCurMethodInstance ! = NULL ) & & ( mCurMethodInstance - > IsMixin ( ) ) & & ( mCurMethodState - > mCurScope = = & mCurMethodState - > mHeadScope ) )
2019-08-23 11:56:54 -07:00
{
2021-12-27 06:47:46 -05:00
// Only in mixin definition - result ignored
2022-06-15 06:45:53 -07:00
CreateValueFromExpression ( expr , NULL , BfEvalExprFlags_AllowRefExpr ) ;
2021-12-27 06:47:46 -05:00
break ;
2019-08-23 11:56:54 -07:00
}
else
{
2021-01-04 06:33:39 -08:00
FailAfter ( " Expression block cannot be used here. Consider adding semicolon if a statement was intended. " , expr ) ;
2019-08-23 11:56:54 -07:00
}
}
}
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
}
2022-07-26 13:27:03 -04:00
UpdateSrcPos ( child ) ;
2019-08-23 11:56:54 -07:00
BfAutoParentNodeEntry autoParentNode ( this , child ) ;
2020-08-16 08:33:51 -07:00
if ( ( mAttributeState ! = NULL ) & &
( ( mAttributeState - > mFlags & ( BfAttributeState : : Flag_StopOnError | BfAttributeState : : Flag_HadError ) ) = = ( BfAttributeState : : Flag_StopOnError | BfAttributeState : : Flag_HadError ) ) )
{
// Ignore child
}
else
child - > Accept ( this ) ;
2022-07-26 13:27:03 -04:00
2021-01-15 14:28:21 -08:00
mContext - > CheckLockYield ( ) ;
2019-08-23 11:56:54 -07:00
+ + itr ;
}
if ( mCurMethodState ! = NULL )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
// Any local method that hasn't been called needs to be processed now
for ( int localMethodIdx = startLocalMethod ; localMethodIdx < ( int ) mCurMethodState - > mLocalMethods . size ( ) ; localMethodIdx + + )
{
auto localMethod = mCurMethodState - > mLocalMethods [ localMethodIdx ] ;
if ( ( wantsAllLocalMethods ) | | ( autoComplete - > IsAutocompleteNode ( localMethod - > mMethodDeclaration ) ) )
{
//??
auto moduleMethodInstance = GetLocalMethodInstance ( localMethod , BfTypeVector ( ) , NULL , true ) ;
}
2021-01-15 14:28:21 -08:00
mContext - > CheckLockYield ( ) ;
2019-08-23 11:56:54 -07:00
}
while ( ( int ) mCurMethodState - > mLocalMethods . size ( ) > startLocalMethod )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
auto localMethod = mCurMethodState - > mLocalMethods . back ( ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
# if _DEBUG
BfLocalMethod * * localMethodPtr = NULL ;
mCurMethodState - > mLocalMethodMap . TryGetValue ( localMethod - > mMethodName , & localMethodPtr ) ;
BF_ASSERT ( * localMethodPtr = = localMethod ) ;
# endif
if ( localMethod - > mNextWithSameName = = NULL )
mCurMethodState - > mLocalMethodMap . Remove ( localMethod - > mMethodName ) ;
else
2019-09-11 10:04:58 -07:00
{
mCurMethodState - > mLocalMethodMap [ localMethod - > mMethodName ] = localMethod - > mNextWithSameName ;
localMethod - > mNextWithSameName = NULL ;
}
2022-07-26 13:27:03 -04:00
mCurMethodState - > mLocalMethods . pop_back ( ) ;
2019-08-23 11:56:54 -07:00
}
2020-09-16 04:29:21 -07:00
if ( hadUnreachableCode )
2019-08-23 11:56:54 -07:00
{
if ( hadReturn )
mCurMethodState - > SetHadReturn ( true ) ;
mCurMethodState - > mLeftBlockUncond = true ;
mCurMethodState - > mInPostReturn = false ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
if ( prevInsertBlock )
mBfIRBuilder - > SetInsertPoint ( prevInsertBlock ) ;
}
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
}
void BfModule : : Visit ( BfAstNode * astNode )
{
AssertErrorState ( ) ;
}
void BfModule : : Visit ( BfIdentifierNode * identifierNode )
{
2022-07-26 13:27:03 -04:00
Visit ( ( BfExpression * ) identifierNode ) ;
2019-08-23 11:56:54 -07:00
}
void BfModule : : Visit ( BfTypeReference * typeRef )
{
Visit ( ( BfAstNode * ) typeRef ) ;
if ( ( mCompiler - > mResolvePassData ! = NULL ) & & ( mCompiler - > mResolvePassData - > mAutoComplete ! = NULL ) )
mCompiler - > mResolvePassData - > mAutoComplete - > CheckTypeRef ( typeRef , true ) ;
}
void BfModule : : Visit ( BfEmptyStatement * astNode )
{
}
void BfModule : : Visit ( BfTryStatement * tryStmt )
{
Fail ( " Exceptions not supported " , tryStmt - > mTryToken ) ;
VisitChild ( tryStmt - > mStatement ) ;
}
void BfModule : : Visit ( BfCatchStatement * catchStmt )
{
Fail ( " Exceptions not supported " , catchStmt - > mCatchToken ) ;
}
void BfModule : : Visit ( BfFinallyStatement * finallyStmt )
{
Fail ( " Exceptions not supported " , finallyStmt - > mFinallyToken ) ;
VisitChild ( finallyStmt - > mStatement ) ;
}
void BfModule : : Visit ( BfCheckedStatement * checkedStmt )
{
Fail ( " 'checked' not supported " , checkedStmt - > mCheckedToken ) ;
VisitChild ( checkedStmt - > mStatement ) ;
}
void BfModule : : Visit ( BfUncheckedStatement * uncheckedStmt )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
VisitChild ( uncheckedStmt - > mStatement ) ;
}
void BfModule : : DoIfStatement ( BfIfStatement * ifStmt , bool includeTrueStmt , bool includeFalseStmt )
{
2020-05-26 06:10:51 -07:00
auto autoComplete = mCompiler - > GetAutoComplete ( ) ;
if ( autoComplete ! = NULL )
autoComplete - > CheckIdentifier ( ifStmt - > mIfToken , true ) ;
2019-08-23 11:56:54 -07:00
if ( ifStmt - > mCondition = = NULL )
{
AssertErrorState ( ) ;
return ;
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
//TODO: Only conditionally create the scopeData here if we create a variable inside the condition statement
UpdateSrcPos ( ifStmt ) ;
BfScopeData newScope ;
2022-02-16 08:28:05 -05:00
newScope . mOuterIsConditional = true ;
2020-09-21 17:53:22 -07:00
newScope . mScopeKind = BfScopeKind_StatementTarget ;
2019-08-23 11:56:54 -07:00
if ( ifStmt - > mLabelNode ! = NULL )
newScope . mLabelNode = ifStmt - > mLabelNode - > mLabel ;
2022-07-26 13:27:03 -04:00
mCurMethodState - > AddScope ( & newScope ) ;
2019-08-23 11:56:54 -07:00
NewScopeState ( ) ;
2022-07-26 13:27:03 -04:00
BfBreakData breakData ;
2019-08-23 11:56:54 -07:00
breakData . mScope = & newScope ;
2022-07-26 13:27:03 -04:00
breakData . mPrevBreakData = mCurMethodState - > mBreakData ;
SetAndRestoreValue < BfBreakData * > prevBreakData ( mCurMethodState - > mBreakData , & breakData ) ;
2019-08-23 11:56:54 -07:00
2022-07-26 13:27:03 -04:00
auto boolType = GetPrimitiveType ( BfTypeCode_Boolean ) ;
2019-08-23 11:56:54 -07:00
2022-07-26 13:27:03 -04:00
BfDeferredLocalAssignData deferredLocalAssignData ( mCurMethodState - > mCurScope ) ;
2019-08-23 11:56:54 -07:00
deferredLocalAssignData . mIsIfCondition = true ;
deferredLocalAssignData . ExtendFrom ( mCurMethodState - > mDeferredLocalAssignData , true ) ;
deferredLocalAssignData . mVarIdBarrier = mCurMethodState - > GetRootMethodState ( ) - > mCurLocalVarId ;
SetAndRestoreValue < BfDeferredLocalAssignData * > prevDLA ( mCurMethodState - > mDeferredLocalAssignData , & deferredLocalAssignData ) ;
BfAutoParentNodeEntry autoParentNodeEntry ( this , ifStmt ) ;
2022-07-26 13:27:03 -04:00
BfTypedValue condValue = CreateValueFromExpression ( ifStmt - > mCondition , boolType ) ;
2019-08-23 11:56:54 -07:00
2020-09-21 17:53:22 -07:00
newScope . mScopeKind = BfScopeKind_Normal ;
2019-08-23 11:56:54 -07:00
deferredLocalAssignData . mIsIfCondition = false ;
2022-07-26 13:27:03 -04:00
// The "extend chain" is only valid for the conditional -- since that expression may contain unconditionally executed and
2019-08-23 11:56:54 -07:00
// conditionally executed code (in the case of "(GetVal(out a) && GetVal(out b))" for example
mCurMethodState - > mDeferredLocalAssignData - > BreakExtendChain ( ) ;
if ( ! condValue )
{
AssertErrorState ( ) ;
condValue = BfTypedValue ( GetDefaultValue ( boolType ) , boolType ) ;
}
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
BfIRBlock trueBB ;
BfIRBlock falseBB ;
bool isConstBranch = false ;
bool constResult = false ;
if ( condValue . mValue . IsConst ( ) )
{
auto constant = mBfIRBuilder - > GetConstant ( condValue . mValue ) ;
if ( ( constant ! = NULL ) & & ( constant - > mTypeCode = = BfTypeCode_Boolean ) )
{
isConstBranch = true ;
constResult = constant - > mBool ;
}
}
if ( ! isConstBranch )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
trueBB = mBfIRBuilder - > CreateBlock ( " if.then " , true ) ;
falseBB = ( ifStmt - > mFalseStatement = = NULL ) ? BfIRBlock ( ) : mBfIRBuilder - > CreateBlock ( " if.else " ) ;
}
else
EmitEnsureInstructionAt ( ) ;
auto contBB = mBfIRBuilder - > CreateBlock ( " if.end " ) ;
if ( ! isConstBranch )
{
mBfIRBuilder - > CreateCondBr ( condValue . mValue , trueBB , ( falseBB ) ? falseBB : contBB ) ;
}
2022-07-26 13:27:03 -04:00
// TRUE statement
2019-08-23 11:56:54 -07:00
bool ignoredLastBlock = true ;
if ( includeTrueStmt )
{
2022-05-30 11:40:49 -07:00
SetAndRestoreValue < bool > prevIgnoreWrites ( mBfIRBuilder - > mIgnoreWrites ) ;
SetAndRestoreValue < bool > prevInConstIgnore ( mCurMethodState - > mCurScope - > mInConstIgnore ) ;
2019-08-23 11:56:54 -07:00
if ( trueBB )
mBfIRBuilder - > SetInsertPoint ( trueBB ) ;
if ( ( isConstBranch ) & & ( constResult ! = true ) )
2022-05-30 11:40:49 -07:00
{
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > mIgnoreWrites = true ;
2022-05-30 11:40:49 -07:00
mCurMethodState - > mCurScope - > mInConstIgnore = true ;
}
2019-08-23 11:56:54 -07:00
else
ignoredLastBlock = false ;
VisitEmbeddedStatement ( ifStmt - > mTrueStatement ) ;
}
2022-07-26 13:27:03 -04:00
prevDLA . Restore ( ) ;
2022-07-05 08:04:38 -07:00
2021-06-19 09:29:36 -07:00
if ( mCurMethodState - > mDeferredLocalAssignData ! = NULL )
2021-06-19 11:00:57 -07:00
mCurMethodState - > mDeferredLocalAssignData - > mHadBreak | = deferredLocalAssignData . mHadBreak ;
2019-08-23 11:56:54 -07:00
2022-07-26 13:27:03 -04:00
bool trueHadReturn = mCurMethodState - > mHadReturn ;
2019-08-23 11:56:54 -07:00
// We restore the scopeData before the False block because we don't want variables created in the if condition to
// be visible in the false section
//RestoreScopeState();
2022-09-05 05:34:24 -07:00
RestoreScoreState_LocalVariables ( mCurMethodState - > mCurScope - > mLocalVarStart ) ;
2019-08-23 11:56:54 -07:00
if ( ( ! mCurMethodState - > mLeftBlockUncond ) & & ( ! ignoredLastBlock ) )
mBfIRBuilder - > CreateBr_NoCollapse ( contBB ) ;
if ( mCurMethodState - > mLeftBlockUncond )
2022-07-05 08:04:38 -07:00
{
deferredLocalAssignData . mLeftBlockUncond = true ;
2019-08-23 11:56:54 -07:00
mCurMethodState - > mLeftBlockCond = true ;
2022-07-05 08:04:38 -07:00
}
2019-08-23 11:56:54 -07:00
mCurMethodState - > mLeftBlockUncond = false ;
mCurMethodState - > SetHadReturn ( false ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
bool falseHadReturn = false ;
if ( ifStmt - > mFalseStatement ! = NULL )
{
2020-09-21 13:58:00 -07:00
BfDeferredLocalAssignData falseDeferredLocalAssignData ( & newScope ) ;
falseDeferredLocalAssignData . mVarIdBarrier = mCurMethodState - > GetRootMethodState ( ) - > mCurLocalVarId ;
2019-08-23 11:56:54 -07:00
if ( falseBB )
{
mBfIRBuilder - > AddBlock ( falseBB ) ;
mBfIRBuilder - > SetInsertPoint ( falseBB ) ;
}
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
ignoredLastBlock = true ;
2022-07-26 13:27:03 -04:00
//
2019-08-23 11:56:54 -07:00
{
2022-05-30 11:40:49 -07:00
SetAndRestoreValue < bool > prevIgnoreWrites ( mBfIRBuilder - > mIgnoreWrites ) ;
SetAndRestoreValue < bool > prevInConstIgnore ( mCurMethodState - > mCurScope - > mInConstIgnore ) ;
2019-08-23 11:56:54 -07:00
if ( ( isConstBranch ) & & ( constResult ! = false ) )
2022-05-30 11:40:49 -07:00
{
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > mIgnoreWrites = true ;
2022-05-30 11:40:49 -07:00
mCurMethodState - > mCurScope - > mInConstIgnore = true ;
}
2019-08-23 11:56:54 -07:00
else
ignoredLastBlock = false ;
falseDeferredLocalAssignData . ExtendFrom ( mCurMethodState - > mDeferredLocalAssignData ) ;
2022-07-26 13:27:03 -04:00
SetAndRestoreValue < BfDeferredLocalAssignData * > prevDLA ( mCurMethodState - > mDeferredLocalAssignData , & falseDeferredLocalAssignData ) ;
2019-08-23 11:56:54 -07:00
if ( includeFalseStmt )
2024-03-18 05:44:02 -04:00
VisitEmbeddedStatement ( ifStmt - > mFalseStatement , NULL , ( BfEmbeddedStatementFlags ) ( BfEmbeddedStatementFlags_IsConditional | BfEmbeddedStatementFlags_CheckStack ) ) ;
2019-08-23 11:56:54 -07:00
}
if ( ( ! mCurMethodState - > mLeftBlockUncond ) & & ( ! ignoredLastBlock ) )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
if ( IsTargetingBeefBackend ( ) )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
// If we don't do this, then with:
// if (a) { } else if (b) { }
// Then we hit the closing second brace even if 'b' is false
//SetIllegalSrcPos();
//BfIRBuilder->ClearDebugLocation();
}
auto br = mBfIRBuilder - > CreateBr_NoCollapse ( contBB ) ;
//mBfIRBuilder->ClearDebugLocation(br);
}
falseHadReturn = mCurMethodState - > mHadReturn ;
if ( mCurMethodState - > mLeftBlockUncond )
2022-07-05 08:04:38 -07:00
{
falseDeferredLocalAssignData . mLeftBlockUncond = true ;
2019-08-23 11:56:54 -07:00
mCurMethodState - > mLeftBlockCond = true ;
2022-07-05 08:04:38 -07:00
}
2019-08-23 11:56:54 -07:00
mCurMethodState - > mLeftBlockUncond = false ;
mCurMethodState - > SetHadReturn ( false ) ;
deferredLocalAssignData . SetIntersection ( falseDeferredLocalAssignData ) ;
mCurMethodState - > ApplyDeferredLocalAssignData ( deferredLocalAssignData ) ;
}
else
{
// If we had a const-ignored if statement with no else
if ( ignoredLastBlock )
{
if ( ! mCurMethodState - > mLeftBlockUncond )
mBfIRBuilder - > CreateBr_NoCollapse ( contBB ) ;
}
}
mBfIRBuilder - > AddBlock ( contBB ) ;
mBfIRBuilder - > SetInsertPoint ( contBB ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
if ( isConstBranch )
mCurMethodState - > SetHadReturn ( constResult ? trueHadReturn : falseHadReturn ) ;
else
2022-07-26 13:27:03 -04:00
mCurMethodState - > SetHadReturn ( trueHadReturn & & falseHadReturn ) ;
2019-08-23 11:56:54 -07:00
mCurMethodState - > mLeftBlockUncond = mCurMethodState - > mHadReturn ;
if ( mCurMethodState - > mHadReturn )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > EraseFromParent ( contBB ) ;
}
else
{
mBfIRBuilder - > SetInsertPoint ( contBB ) ;
}
RestoreScopeState ( ) ;
}
void BfModule : : Visit ( BfIfStatement * ifStmt )
{
DoIfStatement ( ifStmt , true , true ) ;
}
void BfModule : : Visit ( BfVariableDeclaration * varDecl )
{
2022-05-06 12:03:39 -07:00
//BP_ZONE("BfModule::Visit(BfVariableDeclaration)");
2019-08-23 11:56:54 -07:00
UpdateSrcPos ( varDecl ) ;
BfTupleExpression * tupleVariableDeclaration = BfNodeDynCast < BfTupleExpression > ( varDecl - > mNameNode ) ;
if ( tupleVariableDeclaration ! = NULL )
{
2022-07-26 13:27:03 -04:00
HandleTupleVariableDeclaration ( varDecl ) ;
2019-08-23 11:56:54 -07:00
}
else
2022-07-26 13:27:03 -04:00
HandleVariableDeclaration ( varDecl ) ;
2019-08-23 11:56:54 -07:00
}
void BfModule : : Visit ( BfLocalMethodDeclaration * methodDecl )
{
2022-07-26 13:27:03 -04:00
Fail ( " Local method declarations must be wrapped in a block statement " , methodDecl - > mMethodDeclaration - > mNameNode ) ;
2019-08-23 11:56:54 -07:00
}
2020-08-16 08:33:51 -07:00
void BfModule : : Visit ( BfAttributedStatement * attribStmt )
{
BfAttributeState attributeState ;
2020-08-16 15:56:09 -07:00
attributeState . mSrc = attribStmt - > mAttributes ;
2020-08-16 08:33:51 -07:00
attributeState . mTarget = ( BfAttributeTargets ) ( BfAttributeTargets_Invocation | BfAttributeTargets_MemberAccess ) ;
if ( auto block = BfNodeDynCast < BfBlock > ( attribStmt - > mStatement ) )
attributeState . mTarget = BfAttributeTargets_Block ;
attributeState . mCustomAttributes = GetCustomAttributes ( attribStmt - > mAttributes , attributeState . mTarget ) ;
SetAndRestoreValue < BfAttributeState * > prevAttributeState ( mAttributeState , & attributeState ) ;
if ( auto ignoreErrorsAttrib = attributeState . mCustomAttributes - > Get ( mCompiler - > mIgnoreErrorsAttributeTypeDef ) )
{
SetAndRestoreValue < bool > ignoreErrors ( mIgnoreErrors , true ) ;
if ( ! ignoreErrorsAttrib - > mCtorArgs . IsEmpty ( ) )
{
auto constant = mCurTypeInstance - > mConstHolder - > GetConstant ( ignoreErrorsAttrib - > mCtorArgs [ 0 ] ) ;
if ( constant - > mBool )
attributeState . mFlags = BfAttributeState : : Flag_StopOnError ;
}
VisitChild ( attribStmt - > mStatement ) ;
attributeState . mUsed = true ;
}
2022-05-30 11:40:49 -07:00
else if ( attributeState . mCustomAttributes - > Contains ( mCompiler - > mConstSkipAttributeTypeDef ) )
{
if ( ( mCurMethodState = = NULL ) | | ( mCurMethodState - > mCurScope = = NULL ) | | ( ! mCurMethodState - > mCurScope - > mInConstIgnore ) )
{
VisitChild ( attribStmt - > mStatement ) ;
}
else
{
BF_ASSERT ( mBfIRBuilder - > mIgnoreWrites ) ;
}
attributeState . mUsed = true ;
}
2020-08-16 08:33:51 -07:00
else
{
VisitChild ( attribStmt - > mStatement ) ;
}
2022-07-26 13:27:03 -04:00
FinishAttributeState ( & attributeState ) ;
2020-08-16 08:33:51 -07:00
}
2019-08-23 11:56:54 -07:00
void BfModule : : Visit ( BfExpression * expression )
2022-07-26 13:27:03 -04:00
{
UpdateSrcPos ( expression ) ;
BfExprEvaluator exprEvaluator ( this ) ;
2019-08-23 11:56:54 -07:00
exprEvaluator . mUsedAsStatement = true ;
exprEvaluator . Evaluate ( expression ) ;
}
void BfModule : : Visit ( BfExpressionStatement * expressionStmt )
{
expressionStmt - > mExpression - > Accept ( this ) ;
}
void BfModule : : Visit ( BfThrowStatement * throwStmt )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
if ( throwStmt - > mExpression = = NULL )
{
AssertErrorState ( ) ;
return ;
}
UpdateSrcPos ( throwStmt - > mThrowToken ) ;
auto throwValue = CreateValueFromExpression ( throwStmt - > mExpression ) ;
2020-05-08 16:36:31 -07:00
Fail ( " Exceptions are not supported " , throwStmt - > mThrowToken ) ;
2019-08-23 11:56:54 -07:00
if ( mCurMethodInstance - > mReturnType - > IsVoid ( ) )
2020-12-30 13:24:13 -08:00
EmitReturn ( BfTypedValue ( ) ) ;
2019-08-23 11:56:54 -07:00
else
2022-07-26 13:27:03 -04:00
EmitReturn ( GetDefaultTypedValue ( mCurMethodInstance - > mReturnType ) ) ;
2019-08-23 11:56:54 -07:00
}
void BfModule : : Visit ( BfDeleteStatement * deleteStmt )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
UpdateSrcPos ( deleteStmt ) ;
2020-05-26 06:10:51 -07:00
auto autoComplete = mCompiler - > GetAutoComplete ( ) ;
if ( autoComplete ! = NULL )
autoComplete - > CheckIdentifier ( deleteStmt - > mDeleteToken , true ) ;
2019-08-23 11:56:54 -07:00
bool isAppendDelete = false ;
BfTypedValue customAllocator ;
if ( deleteStmt - > mAllocExpr ! = NULL )
{
if ( auto expr = BfNodeDynCast < BfExpression > ( deleteStmt - > mAllocExpr ) )
customAllocator = CreateValueFromExpression ( expr ) ;
else if ( auto tokenNode = BfNodeDynCast < BfTokenNode > ( deleteStmt - > mAllocExpr ) )
{
if ( tokenNode - > mToken = = BfToken_Append )
isAppendDelete = true ;
}
}
2020-03-09 06:34:16 -07:00
BfAttributeState attributeState ;
attributeState . mTarget = BfAttributeTargets_Delete ;
SetAndRestoreValue < BfAttributeState * > prevAttributeState ( mAttributeState , & attributeState ) ;
attributeState . mCustomAttributes = GetCustomAttributes ( deleteStmt - > mAttributes , attributeState . mTarget ) ;
2019-08-23 11:56:54 -07:00
if ( deleteStmt - > mExpression = = NULL )
{
AssertErrorState ( ) ;
return ;
}
auto val = CreateValueFromExpression ( deleteStmt - > mExpression ) ;
if ( ! val )
return ;
2025-01-15 11:24:56 -08:00
auto checkType = val . mType ;
for ( int pass = 0 ; pass < 2 ; pass + + )
{
BfGenericParamType * genericType = NULL ;
if ( checkType - > IsGenericParam ( ) )
genericType = ( BfGenericParamType * ) checkType ;
if ( ( checkType - > IsPointer ( ) ) & & ( checkType - > GetUnderlyingType ( ) - > IsGenericParam ( ) ) )
genericType = ( BfGenericParamType * ) checkType - > GetUnderlyingType ( ) ;
if ( ( genericType ! = NULL ) | | ( checkType - > IsUnspecializedType ( ) ) )
{
BfGenericParamFlags genericParamFlags = BfGenericParamFlag_None ;
BfType * typeConstraint = NULL ;
BfGenericParamInstance * genericParam = NULL ;
if ( genericType ! = NULL )
genericParam = GetMergedGenericParamData ( genericType , genericParamFlags , typeConstraint ) ;
if ( genericParam = = NULL )
GetMergedGenericParamData ( checkType , genericParamFlags , typeConstraint ) ;
2019-08-23 11:56:54 -07:00
2025-01-15 11:24:56 -08:00
if ( typeConstraint ! = NULL )
checkType = typeConstraint ;
bool canAlwaysDelete = checkType - > IsDelegate ( ) | | checkType - > IsFunction ( ) | | checkType - > IsArray ( ) ;
if ( auto checkTypeInst = checkType - > ToTypeInstance ( ) )
{
if ( ( checkTypeInst - > IsInstanceOf ( mCompiler - > mDelegateTypeDef ) ) | |
( checkTypeInst - > IsInstanceOf ( mCompiler - > mFunctionTypeDef ) ) )
canAlwaysDelete = true ;
}
2022-07-26 13:27:03 -04:00
2025-01-15 11:24:56 -08:00
if ( ! canAlwaysDelete )
{
bool success = false ;
if ( genericParamFlags & ( BfGenericParamFlag_Delete | BfGenericParamFlag_Var ) )
success = true ;
else if ( genericParamFlags & BfGenericParamFlag_StructPtr )
success = true ;
else if ( ( genericParamFlags & BfGenericParamFlag_Struct ) & & ( checkType - > IsPointer ( ) ) )
success = true ;
if ( success )
{
if ( ( pass = = 1 ) & & ( genericType ! = NULL ) )
{
auto genericParamInst = GetGenericParamInstance ( genericType ) ;
Warn ( 0 , StrFormat ( " Must add 'where alloctype(%s) : delete' constraint to generic parameter to delete generic type '%s' " ,
genericParamInst - > GetGenericParamDef ( ) - > mName . c_str ( ) , TypeToString ( val . mType ) . c_str ( ) ) , deleteStmt - > mExpression ) ;
}
return ;
}
2020-02-20 11:57:25 -08:00
2025-01-15 11:24:56 -08:00
if ( genericType ! = NULL )
{
auto genericParamInst = GetGenericParamInstance ( genericType ) ;
Fail ( StrFormat ( " Must add 'where %s : delete' constraint to generic parameter to delete generic type '%s' " ,
genericParamInst - > GetGenericParamDef ( ) - > mName . c_str ( ) , TypeToString ( val . mType ) . c_str ( ) ) , deleteStmt - > mExpression ) ;
return ;
}
}
2020-02-20 11:57:25 -08:00
}
2025-01-15 11:24:56 -08:00
if ( pass = = 0 )
2020-02-20 11:57:25 -08:00
{
2025-01-15 11:24:56 -08:00
if ( checkType - > IsAllocType ( ) )
checkType = checkType - > GetUnderlyingType ( ) ;
else
break ;
2020-02-20 11:57:25 -08:00
}
2025-01-15 11:24:56 -08:00
}
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
if ( checkType - > IsVar ( ) )
{
// Mixin or unconstrained generic
return ;
}
2020-09-16 15:56:28 -07:00
if ( ( ! checkType - > IsPointer ( ) ) & & ( ! checkType - > IsObjectOrInterface ( ) ) )
2019-08-23 11:56:54 -07:00
{
2020-06-17 06:06:03 -07:00
Fail ( StrFormat ( " Cannot delete a value of type '%s' " , TypeToString ( val . mType ) . c_str ( ) ) , deleteStmt - > mExpression ) ;
2019-08-23 11:56:54 -07:00
return ;
}
if ( val . mType - > IsGenericParam ( ) )
return ;
auto bodyBB = mBfIRBuilder - > CreateBlock ( " delete.body " ) ;
auto endBB = mBfIRBuilder - > CreateBlock ( " delete.end " ) ;
bool mayBeSentinel = false ;
if ( checkType - > IsPointer ( ) )
{
auto innerType = checkType - > GetUnderlyingType ( ) ;
2020-05-01 16:29:12 -07:00
PopulateType ( innerType ) ;
2019-08-23 11:56:54 -07:00
if ( innerType - > IsValuelessType ( ) )
mayBeSentinel = true ;
}
BfIRValue isNotNull ;
if ( mayBeSentinel )
{
auto intVal = mBfIRBuilder - > CreatePtrToInt ( val . mValue , BfTypeCode_IntPtr ) ;
isNotNull = mBfIRBuilder - > CreateCmpGT ( intVal , mBfIRBuilder - > CreateConst ( BfTypeCode_IntPtr , 1 ) , false ) ;
}
else
{
2022-07-26 13:27:03 -04:00
isNotNull = mBfIRBuilder - > CreateIsNotNull ( val . mValue ) ;
}
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > CreateCondBr ( isNotNull , bodyBB , endBB ) ;
mBfIRBuilder - > AddBlock ( bodyBB ) ;
mBfIRBuilder - > SetInsertPoint ( bodyBB ) ;
if ( val . mType - > IsObjectOrInterface ( ) )
{
2022-07-26 13:27:03 -04:00
EmitObjectAccessCheck ( val ) ;
}
2019-08-23 11:56:54 -07:00
SizedArray < BfIRValue , 4 > llvmArgs ;
auto bitAddr = mBfIRBuilder - > CreateBitCast ( val . mValue , mBfIRBuilder - > GetPrimitiveType ( BfTypeCode_NullPtr ) ) ;
llvmArgs . push_back ( bitAddr ) ;
if ( val . mType - > IsObjectOrInterface ( ) )
{
auto objectType = mContext - > mBfObjectType ;
2022-07-26 13:27:03 -04:00
BfTypeInstance * checkTypeInst = val . mType - > ToTypeInstance ( ) ;
2019-08-23 11:56:54 -07:00
bool allowPrivate = checkTypeInst = = mCurTypeInstance ;
bool allowProtected = allowPrivate | | TypeIsSubTypeOf ( mCurTypeInstance , checkTypeInst ) ;
while ( checkTypeInst ! = NULL )
{
2021-02-25 10:14:22 -08:00
auto dtorMethodDef = checkTypeInst - > mTypeDef - > GetMethodByName ( " ~this " ) ;
2021-01-11 10:52:44 -08:00
if ( dtorMethodDef )
2019-08-23 11:56:54 -07:00
{
2021-01-11 10:52:44 -08:00
if ( ! CheckProtection ( dtorMethodDef - > mProtection , checkTypeInst - > mTypeDef , allowProtected , allowPrivate ) )
2019-08-23 11:56:54 -07:00
{
2022-07-26 13:27:03 -04:00
auto error = Fail ( StrFormat ( " '%s.~this()' is inaccessible due to its protection level " , TypeToString ( checkTypeInst ) . c_str ( ) ) , deleteStmt - > mExpression ) ; // CS0122
2019-08-23 11:56:54 -07:00
}
}
checkTypeInst = checkTypeInst - > mBaseType ;
allowPrivate = false ;
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
2021-01-08 16:21:03 -08:00
if ( ( mCompiler - > mOptions . mObjectHasDebugFlags ) & & ( ! mIsComptimeModule ) )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
auto preDelete = GetInternalMethod ( ( deleteStmt - > mTargetTypeToken ! = NULL ) ? " Dbg_ObjectPreCustomDelete " : " Dbg_ObjectPreDelete " ) ;
SizedArray < BfIRValue , 4 > llvmArgs ;
llvmArgs . push_back ( mBfIRBuilder - > CreateBitCast ( val . mValue , mBfIRBuilder - > MapType ( objectType ) ) ) ;
mBfIRBuilder - > CreateCall ( preDelete . mFunc , llvmArgs ) ;
}
// call dtor
BfExprEvaluator expressionEvaluator ( this ) ;
2022-07-26 13:27:03 -04:00
PopulateType ( val . mType ) ;
2019-08-23 11:56:54 -07:00
PopulateType ( objectType , BfPopulateType_DataAndMethods ) ;
if ( objectType - > mVirtualMethodTable . size ( ) = = 0 )
{
if ( ! mCompiler - > IsAutocomplete ( ) )
AssertErrorState ( ) ;
}
2020-12-13 08:04:42 -08:00
else if ( ! IsSkippingExtraResolveChecks ( ) )
2019-08-23 11:56:54 -07:00
{
BfMethodInstance * methodInstance = objectType - > mVirtualMethodTable [ mCompiler - > GetVTableMethodOffset ( ) + 0 ] . mImplementingMethod ;
BF_ASSERT ( methodInstance - > mMethodDef - > mName = = " ~this " ) ;
SizedArray < BfIRValue , 4 > llvmArgs ;
llvmArgs . push_back ( mBfIRBuilder - > CreateBitCast ( val . mValue , mBfIRBuilder - > MapType ( objectType ) ) ) ;
2021-01-26 06:33:23 -08:00
expressionEvaluator . CreateCall ( deleteStmt - > mDeleteToken , methodInstance , mBfIRBuilder - > GetFakeVal ( ) , false , llvmArgs ) ;
2019-08-23 11:56:54 -07:00
}
if ( ( deleteStmt - > mTargetTypeToken ! = NULL ) & & ( ! isAppendDelete ) )
{
if ( deleteStmt - > mAllocExpr ! = NULL )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
if ( customAllocator )
{
auto customAllocTypeInst = customAllocator . mType - > ToTypeInstance ( ) ;
if ( customAllocTypeInst ! = NULL )
{
if ( ( customAllocTypeInst ! = NULL ) & & ( customAllocTypeInst - > mTypeDef - > GetMethodByName ( " FreeObject " ) ! = NULL ) )
{
BfTypedValueExpression typedValueExpr ;
typedValueExpr . Init ( val ) ;
typedValueExpr . mRefNode = deleteStmt - > mAllocExpr ;
BfExprEvaluator exprEvaluator ( this ) ;
SizedArray < BfExpression * , 2 > argExprs ;
argExprs . push_back ( & typedValueExpr ) ;
BfSizedArray < BfExpression * > sizedArgExprs ( argExprs ) ;
BfResolvedArgs argValues ( & sizedArgExprs ) ;
exprEvaluator . ResolveArgValues ( argValues ) ;
exprEvaluator . mNoBind = true ;
2022-02-05 13:47:19 -05:00
exprEvaluator . MatchMethod ( deleteStmt - > mAllocExpr , NULL , customAllocator , false , true , " FreeObject " , argValues , BfMethodGenericArguments ( ) ) ;
2019-08-23 11:56:54 -07:00
customAllocator = BfTypedValue ( ) ;
}
}
}
}
}
else
{
2021-01-08 16:21:03 -08:00
if ( ( mCompiler - > mOptions . mEnableRealtimeLeakCheck ) & & ( ! mIsComptimeModule ) )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
SizedArray < BfIRValue , 4 > llvmArgs ;
llvmArgs . push_back ( mBfIRBuilder - > CreateBitCast ( val . mValue , mBfIRBuilder - > MapType ( objectType ) ) ) ;
auto moduleMethodInstance = GetInternalMethod ( " Dbg_MarkObjectDeleted " ) ;
mBfIRBuilder - > CreateCall ( moduleMethodInstance . mFunc , llvmArgs ) ;
}
else if ( ! isAppendDelete )
{
mBfIRBuilder - > CreateCall ( GetBuiltInFunc ( BfBuiltInFuncType_Free ) , llvmArgs ) ;
}
}
}
else
{
if ( ( isAppendDelete ) | | ( customAllocator ) )
{
// Do nothing
}
else
{
2022-07-26 13:27:03 -04:00
auto func = GetBuiltInFunc ( BfBuiltInFuncType_Free ) ;
2019-08-23 11:56:54 -07:00
if ( ! func )
{
BF_ASSERT ( mCompiler - > mIsResolveOnly ) ;
}
else
mBfIRBuilder - > CreateCall ( func , llvmArgs ) ;
}
}
2020-06-17 06:06:03 -07:00
if ( customAllocator . mType = = GetPrimitiveType ( BfTypeCode_NullPtr ) )
{
if ( ! checkType - > IsObjectOrInterface ( ) )
Warn ( 0 , " Type '%' has no destructor, so delete:null has no effect " , deleteStmt - > mExpression ) ;
}
else if ( customAllocator )
2019-08-23 11:56:54 -07:00
{
auto voidPtrType = GetPrimitiveType ( BfTypeCode_NullPtr ) ;
auto ptrValue = BfTypedValue ( mBfIRBuilder - > CreateBitCast ( val . mValue , mBfIRBuilder - > MapType ( voidPtrType ) ) , voidPtrType ) ;
BfTypedValueExpression typedValueExpr ;
2022-07-26 13:27:03 -04:00
typedValueExpr . Init ( ptrValue ) ;
2019-08-23 11:56:54 -07:00
BfExprEvaluator exprEvaluator ( this ) ;
SizedArray < BfExpression * , 2 > argExprs ;
argExprs . push_back ( & typedValueExpr ) ;
BfSizedArray < BfExpression * > sizedArgExprs ( argExprs ) ;
BfResolvedArgs argValues ( & sizedArgExprs ) ;
exprEvaluator . ResolveArgValues ( argValues ) ;
exprEvaluator . mNoBind = true ;
2022-02-05 13:47:19 -05:00
exprEvaluator . MatchMethod ( deleteStmt - > mAllocExpr , NULL , customAllocator , false , false , " Free " , argValues , BfMethodGenericArguments ( ) ) ;
2019-08-23 11:56:54 -07:00
}
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > CreateBr ( endBB ) ;
mBfIRBuilder - > AddBlock ( endBB ) ;
mBfIRBuilder - > SetInsertPoint ( endBB ) ;
}
void BfModule : : Visit ( BfSwitchStatement * switchStmt )
2020-09-04 09:53:47 -07:00
{
2022-07-26 16:07:14 -04:00
if ( mModuleName = = " BeefTest_TestProgram " )
{
NOP ;
}
2020-09-04 09:53:47 -07:00
BfScopeData outerScope ;
outerScope . mInnerIsConditional = false ;
outerScope . mCloseNode = switchStmt ;
2019-08-23 11:56:54 -07:00
if ( switchStmt - > mCloseBrace ! = NULL )
2022-07-26 13:27:03 -04:00
outerScope . mCloseNode = switchStmt - > mCloseBrace ;
2020-09-04 09:53:47 -07:00
mCurMethodState - > AddScope ( & outerScope ) ;
NewScopeState ( ) ;
2019-08-23 11:56:54 -07:00
auto valueScopeStartOuter = ValueScopeStart ( ) ;
BfTypedValue switchValue ;
if ( switchStmt - > mSwitchValue = = NULL )
{
AssertErrorState ( ) ;
2022-07-26 13:27:03 -04:00
UpdateSrcPos ( switchStmt - > mSwitchToken ) ;
2019-08-23 11:56:54 -07:00
}
else
{
2022-07-26 13:27:03 -04:00
UpdateExprSrcPos ( switchStmt - > mSwitchValue ) ;
2019-08-23 11:56:54 -07:00
BfEvalExprFlags flags = BfEvalExprFlags_None ;
flags = BfEvalExprFlags_AllowSplat ;
switchValue = CreateValueFromExpression ( switchStmt - > mSwitchValue , NULL , flags ) ;
}
EmitEnsureInstructionAt ( ) ;
if ( ! switchValue )
{
AssertErrorState ( ) ;
switchValue = GetDefaultTypedValue ( mContext - > mBfObjectType ) ;
}
2020-03-24 15:25:43 -07:00
if ( switchValue . mType - > IsPointer ( ) )
{
auto underlyingType = switchValue . mType - > GetUnderlyingType ( ) ;
if ( underlyingType - > IsEnum ( ) )
{
switchValue = LoadValue ( switchValue ) ;
switchValue = BfTypedValue ( switchValue . mValue , underlyingType , true ) ;
}
}
2019-08-23 11:56:54 -07:00
// We make the switch value conditional, but all other uses of this scope is conditional since it's conditional on cases
2020-09-04 09:53:47 -07:00
BfScopeData newScope ;
2019-08-23 11:56:54 -07:00
newScope . mInnerIsConditional = true ;
2020-09-04 09:53:47 -07:00
newScope . mCloseNode = switchStmt ;
if ( switchStmt - > mCloseBrace ! = NULL )
2020-09-06 11:10:04 -07:00
newScope . mCloseNode = switchStmt - > mCloseBrace ;
if ( switchStmt - > mLabelNode ! = NULL )
newScope . mLabelNode = switchStmt - > mLabelNode - > mLabel ;
2020-09-04 09:53:47 -07:00
mCurMethodState - > AddScope ( & newScope ) ;
2022-07-26 13:27:03 -04:00
NewScopeState ( ) ;
2019-08-23 11:56:54 -07:00
BfTypedValue switchValueAddr = switchValue ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
BfLocalVariable * localDef = new BfLocalVariable ( ) ;
2022-07-26 13:27:03 -04:00
localDef - > mName = " _ " ;
2019-08-23 11:56:54 -07:00
localDef - > mResolvedType = switchValueAddr . mType ;
localDef - > mIsReadOnly = true ;
2020-09-21 13:58:00 -07:00
localDef - > mAssignedKind = BfLocalVarAssignKind_Unconditional ;
2019-08-23 11:56:54 -07:00
if ( switchValue . IsAddr ( ) )
{
localDef - > mAddr = switchValue . mValue ;
}
else
{
localDef - > mValue = switchValue . mValue ;
localDef - > mIsSplat = switchValue . IsSplat ( ) ;
}
bool wantsDebugInfo = mHasFullDebugInfo & & ! mBfIRBuilder - > mIgnoreWrites ;
bool tryExtendValue = false ;
bool addDebugInfo = true ;
2020-04-16 00:30:55 -07:00
if ( ( wantsDebugInfo ) & & ( ! switchValue . mType - > IsValuelessType ( ) ) & & ( ! switchValue . mType - > IsVar ( ) ) )
2019-08-23 11:56:54 -07:00
{
if ( IsTargetingBeefBackend ( ) )
{
// We don't need to make a copy
if ( switchValue . IsSplat ( ) )
{
localDef - > mIsSplat = true ;
if ( WantsDebugInfo ( ) )
{
bool found = false ;
String varName = " _ " ;
for ( auto dbgVar : mCurMethodState - > mLocals )
{
if ( dbgVar - > mAddr = = switchValue . mValue )
{
varName + = " $a$ " + dbgVar - > mName ;
found = true ;
break ;
}
}
if ( found )
{
auto fakeVal = CreateAlloca ( GetPrimitiveType ( BfTypeCode_Int32 ) , true , " _fake " ) ;
addDebugInfo = false ;
auto diVariable = mBfIRBuilder - > DbgCreateAutoVariable ( mCurMethodState - > mCurScope - > mDIScope , varName , mCurFilePosition . mFileInstance - > mDIFile , mCurFilePosition . mCurLine , mBfIRBuilder - > DbgGetType ( localDef - > mResolvedType ) , BfIRInitType_NotNeeded_AliveOnDecl ) ;
mBfIRBuilder - > DbgInsertDeclare ( fakeVal , diVariable ) ;
}
}
}
else
{
// if (!localDef->mAddr)
// {
// BfIRValue value = localDef->mValue;
// if (newLocalVar->mConstValue)
// value = localDef->mConstValue;
// auto aliasValue = mBfIRBuilder->CreateAliasValue(value);
// mBfIRBuilder->DbgInsertValueIntrinsic(aliasValue, diVariable);
// scopeData.mDeferredLifetimeEnds.push_back(aliasValue);
// }
tryExtendValue = true ;
}
}
else if ( ( switchValue . mType - > IsComposite ( ) ) & & ( switchValue . IsAddr ( ) ) )
{
auto refType = CreateRefType ( switchValue . mType ) ;
2022-07-26 13:27:03 -04:00
auto allocaVal = CreateAlloca ( refType ) ;
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > CreateStore ( switchValue . mValue , allocaVal ) ;
auto diType = mBfIRBuilder - > DbgGetType ( refType ) ;
auto diVariable = mBfIRBuilder - > DbgCreateAutoVariable ( mCurMethodState - > mCurScope - > mDIScope ,
localDef - > mName , mCurFilePosition . mFileInstance - > mDIFile , mCurFilePosition . mCurLine , diType ) ;
mBfIRBuilder - > DbgInsertDeclare ( allocaVal , diVariable ) ;
addDebugInfo = false ;
}
else
{
if ( switchValueAddr . IsSplat ( ) )
{
auto addr = CreateAlloca ( switchValue . mType ) ;
2022-07-26 13:27:03 -04:00
if ( switchValue . IsSplat ( ) )
2019-08-23 11:56:54 -07:00
AggregateSplatIntoAddr ( switchValue , addr ) ;
else
mBfIRBuilder - > CreateStore ( switchValue . mValue , addr ) ;
localDef - > mAddr = addr ;
localDef - > mValue = BfIRValue ( ) ;
localDef - > mIsSplat = false ;
}
2022-07-26 13:27:03 -04:00
}
}
2019-08-23 11:56:54 -07:00
2020-04-16 00:30:55 -07:00
if ( ! localDef - > mResolvedType - > IsVar ( ) )
AddLocalVariableDef ( localDef , addDebugInfo , true ) ;
2019-08-23 11:56:54 -07:00
BfDeferredLocalAssignData deferredLocalAssignData ( mCurMethodState - > mCurScope ) ;
deferredLocalAssignData . mVarIdBarrier = mCurMethodState - > GetRootMethodState ( ) - > mCurLocalVarId ;
int numExpressions = 0 ;
SizedArray < BfIRBlock , 8 > blocks ;
SizedArray < BfWhenExpression * , 8 > whenExprs ;
SizedArray < BfIRBlock , 8 > whenFailBlocks ;
2022-07-26 13:27:03 -04:00
BfIRBlock defaultBlock ;
2019-08-23 11:56:54 -07:00
auto endBlock = mBfIRBuilder - > CreateBlock ( " switch.end " ) ;
for ( BfSwitchCase * switchCase : switchStmt - > mSwitchCases )
{
auto caseBlock = mBfIRBuilder - > CreateBlock ( StrFormat ( " switch.%d " , blocks . size ( ) ) ) ;
blocks . push_back ( caseBlock ) ;
numExpressions + = ( int ) switchCase - > mCaseExpressions . size ( ) ;
}
2020-02-21 07:54:19 -08:00
defaultBlock = mBfIRBuilder - > CreateBlock ( " default " ) ;
2020-02-21 15:34:08 -08:00
bool hasDefaultCase = switchStmt - > mDefaultCase ! = NULL ;
2022-07-26 13:27:03 -04:00
if ( hasDefaultCase )
blocks . push_back ( defaultBlock ) ;
2019-08-23 11:56:54 -07:00
SizedArray < BfDeferredLocalAssignData , 8 > deferredLocalAssignDataVec ;
deferredLocalAssignDataVec . resize ( blocks . size ( ) ) ;
auto boolType = GetPrimitiveType ( BfTypeCode_Boolean ) ;
BfTypedValue enumTagVal ;
// Declare cases
int blockIdx = 0 ;
bool hadConstIntVals = false ;
bool hadWhen = false ;
BfIRValue switchStatement ;
auto switchBlock = mBfIRBuilder - > GetInsertBlock ( ) ;
BfIRBlock noSwitchBlock = mBfIRBuilder - > CreateBlock ( " noSwitch " , true ) ;
2022-07-26 13:27:03 -04:00
BfPrimitiveType * intCoercibleType = GetIntCoercibleType ( switchValue . mType ) ;
2019-08-23 11:56:54 -07:00
bool isConstSwitch = false ;
if ( ( switchValue . mValue . IsConst ( ) ) | | ( switchValue . mType - > IsValuelessType ( ) ) )
{
isConstSwitch = true ;
}
if ( switchValue . mValue )
{
mBfIRBuilder - > PopulateType ( switchValue . mType ) ;
if ( intCoercibleType ! = NULL )
{
auto intValue = GetIntCoercible ( switchValue ) ;
switchStatement = mBfIRBuilder - > CreateSwitch ( intValue . mValue , noSwitchBlock , numExpressions ) ;
}
else if ( switchValue . mType - > IsPayloadEnum ( ) )
{
enumTagVal = ExtractValue ( switchValue , NULL , 2 ) ;
enumTagVal = LoadValue ( enumTagVal ) ;
switchStatement = mBfIRBuilder - > CreateSwitch ( enumTagVal . mValue , noSwitchBlock , numExpressions ) ;
}
2020-04-16 00:30:55 -07:00
else if ( ( ! isConstSwitch ) & & ( ! switchValue . mType - > IsVar ( ) ) )
2022-07-26 13:27:03 -04:00
switchStatement = mBfIRBuilder - > CreateSwitch ( switchValue . mValue , noSwitchBlock , numExpressions ) ;
2019-08-23 11:56:54 -07:00
}
auto valueScopeStartInner = ValueScopeStart ( ) ;
mBfIRBuilder - > SetInsertPoint ( noSwitchBlock ) ;
bool isPayloadEnum = switchValue . mType - > IsPayloadEnum ( ) ;
2021-11-27 11:11:41 -08:00
bool isTuple = switchValue . mType - > IsTuple ( ) ;
2019-08-23 11:56:54 -07:00
bool isIntegralSwitch = switchValue . mType - > IsIntegral ( ) | | ( intCoercibleType ! = NULL ) | | ( ( switchValue . mType - > IsEnum ( ) ) & & ( ! isPayloadEnum ) ) ;
auto _ShowCaseError = [ & ] ( int64 id , BfAstNode * errNode )
{
if ( isPayloadEnum )
{
auto enumType = switchValue . mType - > ToTypeInstance ( ) ;
2024-06-30 08:20:55 +02:00
for ( auto & fieldInstance : enumType - > mFieldInstances )
2019-08-23 11:56:54 -07:00
{
auto fieldDef = fieldInstance . GetFieldDef ( ) ;
if ( fieldDef - > IsEnumCaseEntry ( ) )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
int enumIdx = - fieldInstance . mDataIdx - 1 ;
if ( enumIdx = = id )
{
Fail ( StrFormat ( " The switch statement already contains a case for the the value '%s' " , fieldDef - > mName . c_str ( ) ) , errNode ) ;
return ;
}
}
}
}
Fail ( StrFormat ( " The switch statement already contains a case for the the value '%lld' " , id ) , errNode ) ;
} ;
int caseCount = 0 ;
bool allHadReturns = true ;
bool hadCondCase = false ;
BfIRBlock lastDefaultBlock ;
struct _CaseState
{
BfIRBlock mCondBlock ;
BfIRBlock mUncondBlock ;
} ;
bool hadConstMatch = false ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
auto startingLocalVarId = mCurMethodState - > GetRootMethodState ( ) - > mCurLocalVarId ;
2020-11-04 09:23:34 -08:00
bool prevHadFallthrough = false ;
2019-08-23 11:56:54 -07:00
Dictionary < int64 , _CaseState > handledCases ;
2023-07-24 12:52:23 -07:00
HashSet < int64 > condCases ;
2019-08-23 11:56:54 -07:00
for ( BfSwitchCase * switchCase : switchStmt - > mSwitchCases )
{
deferredLocalAssignDataVec [ blockIdx ] . mScopeData = mCurMethodState - > mCurScope ;
deferredLocalAssignDataVec [ blockIdx ] . ExtendFrom ( mCurMethodState - > mDeferredLocalAssignData ) ;
SetAndRestoreValue < BfDeferredLocalAssignData * > prevDLA ( mCurMethodState - > mDeferredLocalAssignData , & deferredLocalAssignDataVec [ blockIdx ] ) ;
mCurMethodState - > mDeferredLocalAssignData - > mVarIdBarrier = startingLocalVarId ;
SetIllegalSrcPos ( ) ;
auto caseBlock = blocks [ blockIdx ] ;
BfScopeData caseScopeData ;
bool openedScope = false ;
if ( ( mCompiler - > mResolvePassData ! = NULL ) & & ( mCompiler - > mResolvePassData - > mAutoComplete ! = NULL ) )
{
2022-07-26 13:27:03 -04:00
// This does the enum autocomplete popup
2019-08-23 11:56:54 -07:00
BfAstNode * checkNode = NULL ;
int caseExprIdx = ( int ) switchCase - > mCaseExpressions . size ( ) ;
if ( caseExprIdx = = 0 )
checkNode = switchCase - > mCaseToken ;
else if ( caseExprIdx - 1 < ( int ) switchCase - > mCaseCommas . size ( ) )
checkNode = switchCase - > mCaseCommas [ caseExprIdx - 1 ] ;
if ( checkNode ! = NULL )
mCompiler - > mResolvePassData - > mAutoComplete - > CheckEmptyStart ( checkNode , switchValue . mType ) ;
}
bool mayHaveMatch = false ;
BfWhenExpression * whenExpr = NULL ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
for ( BfExpression * caseExpr : switchCase - > mCaseExpressions )
{
if ( auto checkWhenExpr = BfNodeDynCast < BfWhenExpression > ( caseExpr ) )
{
hadWhen = true ;
whenExpr = checkWhenExpr ;
}
}
2021-11-27 11:11:41 -08:00
bool wantsOpenedScope = isPayloadEnum | | isTuple ;
2019-08-23 11:56:54 -07:00
BfIRBlock lastNotEqBlock ;
for ( BfExpression * caseExpr : switchCase - > mCaseExpressions )
{
BfConstant * constantInt = NULL ;
if ( auto checkWhenExpr = BfNodeDynCast < BfWhenExpression > ( caseExpr ) )
continue ;
2021-11-27 11:11:41 -08:00
if ( ( ! openedScope ) & & ( wantsOpenedScope ) )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
openedScope = true ;
caseScopeData . mOuterIsConditional = true ;
2022-07-05 08:04:38 -07:00
caseScopeData . mIsSharedTempBlock = true ;
2019-08-23 11:56:54 -07:00
mCurMethodState - > AddScope ( & caseScopeData ) ;
NewScopeState ( ) ;
2022-07-26 13:27:03 -04:00
UpdateSrcPos ( caseExpr ) ;
2019-08-23 11:56:54 -07:00
SetIllegalSrcPos ( ) ;
}
BfIRValue eqResult ;
BfIRBlock notEqBB ;
bool handled = false ;
BfTypedValue caseValue ;
BfIRBlock doBlock = caseBlock ;
bool hadConditional = false ;
2023-07-24 10:32:31 -07:00
bool isEnumDescValue = isPayloadEnum ;
2019-08-23 11:56:54 -07:00
if ( isPayloadEnum )
{
auto dscrType = switchValue . mType - > ToTypeInstance ( ) - > GetDiscriminatorType ( ) ;
if ( ! enumTagVal )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
enumTagVal = ExtractValue ( switchValue , NULL , 2 ) ;
enumTagVal = LoadValue ( enumTagVal ) ;
}
notEqBB = mBfIRBuilder - > CreateBlock ( StrFormat ( " switch.notEq.%d " , blockIdx ) , false ) ;
int tagId = - 1 ;
BfIRBlock matchBlock ;
2022-07-26 13:27:03 -04:00
BfTypedValue eqTypedResult ;
2019-08-23 11:56:54 -07:00
if ( auto bindExpr = BfNodeDynCast < BfEnumCaseBindExpression > ( caseExpr ) )
{
2022-07-26 13:27:03 -04:00
eqTypedResult = HandleCaseBind ( switchValueAddr , enumTagVal , bindExpr , & caseBlock , & notEqBB , & matchBlock , & tagId ) ;
2019-08-23 11:56:54 -07:00
}
else
{
2022-05-24 06:52:28 -07:00
eqTypedResult = TryCaseEnumMatch ( switchValueAddr , enumTagVal , caseExpr , & caseBlock , & notEqBB , & matchBlock , tagId , hadConditional , false , prevHadFallthrough ) ;
2019-08-23 11:56:54 -07:00
if ( hadConditional )
hadCondCase = true ;
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
if ( tagId ! = - 1 )
{
doBlock = matchBlock ; // Jump to binds rather than just the code
caseValue = BfTypedValue ( GetConstValue ( tagId , GetPrimitiveType ( dscrType - > mTypeDef - > mTypeCode ) ) , dscrType ) ;
}
else
2022-07-26 13:27:03 -04:00
hadCondCase = true ;
2019-08-23 11:56:54 -07:00
if ( eqTypedResult )
{
handled = true ;
2022-07-26 13:27:03 -04:00
eqResult = eqTypedResult . mValue ;
2019-08-23 11:56:54 -07:00
}
}
2019-11-27 08:00:15 -08:00
else if ( auto tupleExpr = BfNodeDynCast < BfTupleExpression > ( caseExpr ) )
{
notEqBB = mBfIRBuilder - > CreateBlock ( StrFormat ( " switch.notEq.%d " , blockIdx ) , false ) ;
BfIRBlock matchBlock ;
2022-05-24 06:52:28 -07:00
BfTypedValue eqTypedResult = TryCaseTupleMatch ( switchValue , tupleExpr , & caseBlock , & notEqBB , & matchBlock , hadConditional , false , prevHadFallthrough ) ;
2019-11-27 08:00:15 -08:00
if ( hadConditional )
hadCondCase = true ;
if ( eqTypedResult )
{
mayHaveMatch = true ;
handled = true ;
eqResult = eqTypedResult . mValue ;
}
}
2019-08-23 11:56:54 -07:00
if ( ! eqResult )
{
caseValue = CreateValueFromExpression ( caseExpr , switchValue . mType , ( BfEvalExprFlags ) ( BfEvalExprFlags_AllowEnumId | BfEvalExprFlags_NoCast ) ) ;
if ( ! caseValue )
continue ;
2023-07-24 10:32:31 -07:00
isEnumDescValue = false ;
2019-08-23 11:56:54 -07:00
}
BfTypedValue caseIntVal = caseValue ;
if ( ( isIntegralSwitch ) | | ( isPayloadEnum ) )
{
2022-07-26 13:27:03 -04:00
if ( ( intCoercibleType ! = NULL ) & &
( caseValue . mType = = switchValue . mType ) & &
2019-08-23 11:56:54 -07:00
( caseValue . mValue . IsConst ( ) ) )
{
caseIntVal = GetIntCoercible ( caseValue ) ;
constantInt = mBfIRBuilder - > GetConstant ( caseIntVal . mValue ) ;
}
2022-07-26 13:27:03 -04:00
else
2019-08-23 11:56:54 -07:00
{
// For a non-const case, allow for conversion operators, otherwise cast now
if ( ( isIntegralSwitch ) & & ( caseValue . mValue . IsConst ( ) ) )
{
if ( caseValue . mType ! = switchValue . mType )
{
caseValue = Cast ( caseExpr , caseValue , switchValue . mType ) ;
if ( ! caseValue )
continue ;
caseIntVal = caseValue ;
}
}
2020-12-19 11:01:10 -08:00
if ( ( caseValue . mType = = switchValue . mType ) | | ( eqResult ) )
2020-12-19 08:26:00 -08:00
{
constantInt = mBfIRBuilder - > GetConstant ( caseValue . mValue ) ;
if ( ( constantInt ! = NULL ) & & ( ! mBfIRBuilder - > IsInt ( constantInt - > mTypeCode ) ) )
constantInt = NULL ;
}
2019-08-23 11:56:54 -07:00
}
}
if ( ( ! switchStatement ) & & ( ! isConstSwitch ) )
{
// Do nothing
mayHaveMatch = true ;
}
else if ( ( constantInt ! = NULL ) & & ( ! hadWhen ) & & ( ! isConstSwitch ) )
{
2023-07-24 12:52:23 -07:00
if ( hadConditional )
{
condCases . Add ( constantInt - > mInt64 ) ;
}
else
2019-08-23 11:56:54 -07:00
{
_CaseState * caseState = NULL ;
handledCases . TryAdd ( constantInt - > mInt64 , NULL , & caseState ) ;
2022-07-26 13:27:03 -04:00
2023-07-24 12:52:23 -07:00
if ( condCases . Contains ( constantInt - > mInt64 ) )
2019-08-23 11:56:54 -07:00
{
2023-07-24 12:52:23 -07:00
// This is a 'case .A:' after a 'case .A(let value):'
eqResult = mBfIRBuilder - > CreateCmpEQ ( enumTagVal . mValue , caseValue . mValue ) ;
notEqBB = mBfIRBuilder - > CreateBlock ( StrFormat ( " switch.notEq.%d " , blockIdx ) ) ;
mayHaveMatch = true ;
mBfIRBuilder - > CreateCondBr ( eqResult , caseBlock , notEqBB ) ;
mBfIRBuilder - > AddBlock ( notEqBB ) ;
mBfIRBuilder - > SetInsertPoint ( notEqBB ) ;
2019-08-23 11:56:54 -07:00
}
else
{
2023-07-24 12:52:23 -07:00
if ( caseState - > mUncondBlock )
{
_ShowCaseError ( constantInt - > mInt64 , caseExpr ) ;
}
else
{
caseState - > mUncondBlock = doBlock ;
mBfIRBuilder - > AddSwitchCase ( switchStatement , caseIntVal . mValue , doBlock ) ;
hadConstIntVals = true ;
}
2019-08-23 11:56:54 -07:00
}
}
2023-07-24 12:52:23 -07:00
2019-08-23 11:56:54 -07:00
mayHaveMatch = true ;
}
else if ( ! handled )
{
hadCondCase = true ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
if ( ! eqResult )
{
BfExprEvaluator exprEvaluator ( this ) ;
BfAstNode * refNode = switchCase - > mColonToken ;
2023-07-24 10:32:31 -07:00
if ( ( caseValue . mType - > IsPayloadEnum ( ) ) & & ( caseValue . mValue . IsConst ( ) ) & & ( switchValue . mType = = caseValue . mType ) & & ( isEnumDescValue ) )
2019-08-23 11:56:54 -07:00
{
if ( ! enumTagVal )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
enumTagVal = ExtractValue ( switchValue , NULL , 2 ) ;
enumTagVal = LoadValue ( enumTagVal ) ;
}
eqResult = mBfIRBuilder - > CreateCmpEQ ( enumTagVal . mValue , caseValue . mValue ) ;
}
else
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
exprEvaluator . PerformBinaryOperation ( switchStmt - > mSwitchValue , caseExpr , BfBinaryOp_Equality , refNode , ( BfBinOpFlags ) ( BfBinOpFlag_ForceLeftType ) , switchValue , caseValue ) ;
if ( switchStmt - > mSwitchValue ! = NULL )
UpdateSrcPos ( switchStmt - > mSwitchValue ) ;
SetIllegalSrcPos ( ) ;
eqResult = exprEvaluator . mResult . mValue ;
if ( ! eqResult )
eqResult = GetConstValue ( 0 , boolType ) ;
}
}
ValueScopeEnd ( valueScopeStartInner ) ;
bool isConstResult = false ;
bool constResult = false ;
if ( eqResult . IsConst ( ) )
{
auto constant = mBfIRBuilder - > GetConstant ( eqResult ) ;
if ( constant - > mTypeCode = = BfTypeCode_Boolean )
{
isConstResult = true ;
2022-07-26 13:27:03 -04:00
constResult = constant - > mBool ;
2019-08-23 11:56:54 -07:00
}
}
if ( isConstResult )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
if ( constResult )
{
mBfIRBuilder - > CreateBr ( caseBlock ) ;
mayHaveMatch = true ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
if ( whenExpr = = NULL )
{
hadConstMatch = true ;
}
else
{
notEqBB = mBfIRBuilder - > CreateBlock ( StrFormat ( " switch.notEq.%d " , blockIdx ) ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > AddBlock ( notEqBB ) ;
mBfIRBuilder - > SetInsertPoint ( notEqBB ) ;
}
}
}
else
{
notEqBB = mBfIRBuilder - > CreateBlock ( StrFormat ( " switch.notEq.%d " , blockIdx ) ) ;
mayHaveMatch = true ;
mBfIRBuilder - > CreateCondBr ( eqResult , caseBlock , notEqBB ) ;
mBfIRBuilder - > AddBlock ( notEqBB ) ;
mBfIRBuilder - > SetInsertPoint ( notEqBB ) ;
}
2022-07-26 13:27:03 -04:00
}
2024-11-01 19:01:21 -04:00
else if ( whenExpr ! = NULL )
{
mayHaveMatch = true ;
}
2019-08-23 11:56:54 -07:00
if ( notEqBB )
lastNotEqBlock = notEqBB ;
if ( ( ! hadCondCase ) & & ( notEqBB ) )
lastDefaultBlock = notEqBB ;
}
2020-02-23 06:14:14 -08:00
if ( ( whenExpr ! = NULL ) & & ( switchCase - > mCaseExpressions . size ( ) = = 1 ) )
{
// This was a "case when" expression, always matches
mayHaveMatch = true ;
auto notEqBB = mBfIRBuilder - > CreateBlock ( StrFormat ( " switch.notEq_when.%d " , blockIdx ) ) ;
2022-07-26 13:27:03 -04:00
mBfIRBuilder - > CreateBr ( caseBlock ) ;
2020-02-23 06:14:14 -08:00
mBfIRBuilder - > AddBlock ( notEqBB ) ;
mBfIRBuilder - > SetInsertPoint ( notEqBB ) ;
lastNotEqBlock = notEqBB ;
}
2021-01-06 04:31:23 -08:00
if ( ( lastDefaultBlock ) & & ( switchStatement ) )
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > SetSwitchDefaultDest ( switchStatement , lastDefaultBlock ) ;
auto prevInsertBlock = mBfIRBuilder - > GetInsertBlock ( ) ;
2022-07-26 13:27:03 -04:00
2022-05-30 11:40:49 -07:00
bool isConstIgnore = ! mayHaveMatch & & ! prevHadFallthrough ;
SetAndRestoreValue < bool > prevIgnoreWrites ( mBfIRBuilder - > mIgnoreWrites , true , isConstIgnore ) ;
SetAndRestoreValue < bool > prevInConstIgnore ( mCurMethodState - > mCurScope - > mInConstIgnore , true , isConstIgnore ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > AddBlock ( caseBlock ) ;
mBfIRBuilder - > SetInsertPoint ( caseBlock ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
if ( whenExpr ! = NULL )
{
UpdateSrcPos ( whenExpr ) ;
BfTypedValue whenValue ;
if ( whenExpr - > mExpression ! = NULL )
whenValue = CreateValueFromExpression ( whenExpr - > mExpression , boolType , BfEvalExprFlags_AllowEnumId ) ;
if ( ! whenValue )
{
AssertErrorState ( ) ;
whenValue = GetDefaultTypedValue ( boolType ) ;
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
bool constResult = false ;
if ( mBfIRBuilder - > TryGetBool ( whenValue . mValue , constResult ) )
{
if ( ! constResult )
prevIgnoreWrites . Set ( ) ;
}
else
{
BfIRBlock eqBB = mBfIRBuilder - > CreateBlock ( StrFormat ( " switch.when.%d " , blockIdx ) ) ;
mBfIRBuilder - > CreateCondBr ( whenValue . mValue , eqBB , lastNotEqBlock ) ;
mBfIRBuilder - > AddBlock ( eqBB ) ;
mBfIRBuilder - > SetInsertPoint ( eqBB ) ;
}
}
BfIRBlock fallthroughBlock ;
if ( blockIdx < ( int ) blocks . size ( ) - 1 )
fallthroughBlock = blocks [ blockIdx + 1 ] ;
else
fallthroughBlock = defaultBlock ;
bool hadReturn = false ;
if ( ( switchCase - > mCodeBlock ! = NULL ) & & ( ! switchCase - > mCodeBlock - > mChildArr . IsEmpty ( ) ) )
{
2022-07-26 13:27:03 -04:00
UpdateSrcPos ( switchCase - > mCodeBlock ) ;
2019-08-23 11:56:54 -07:00
2022-07-05 08:04:38 -07:00
VisitCodeBlock ( switchCase - > mCodeBlock , BfIRBlock ( ) , endBlock , fallthroughBlock , true , & hadReturn , switchStmt - > mLabelNode , openedScope /*, BfEmbeddedStatementFlags_RescopeDLA*/ ) ;
2019-08-23 11:56:54 -07:00
openedScope = false ;
deferredLocalAssignDataVec [ blockIdx ] . mHadReturn = hadReturn ;
caseCount + + ;
2022-07-26 13:27:03 -04:00
if ( ( ! hadReturn ) & &
2021-06-19 11:00:57 -07:00
( ( ! mCurMethodState - > mDeferredLocalAssignData - > mHadFallthrough ) | | ( mCurMethodState - > mDeferredLocalAssignData - > mHadBreak ) ) )
2019-08-23 11:56:54 -07:00
allHadReturns = false ;
if ( auto block = BfNodeDynCast < BfBlock > ( switchCase - > mCodeBlock ) )
{
//
}
else
{
if ( switchStmt - > mCloseBrace ! = NULL )
2022-07-26 13:27:03 -04:00
{
UpdateSrcPos ( switchStmt - > mCloseBrace ) ;
2019-08-23 11:56:54 -07:00
}
EmitEnsureInstructionAt ( ) ;
}
//UpdateSrcPos(switchCase->mCodeBlock);
//SetIllegalSrcPos();
mBfIRBuilder - > ClearDebugLocation ( ) ;
}
else
{
if ( openedScope )
RestoreScopeState ( ) ;
mBfIRBuilder - > CreateBr ( endBlock ) ;
allHadReturns = false ;
}
prevIgnoreWrites . Restore ( ) ;
mBfIRBuilder - > SetInsertPoint ( prevInsertBlock ) ;
2022-07-26 13:27:03 -04:00
prevHadFallthrough = mCurMethodState - > mDeferredLocalAssignData - > mHadFallthrough ;
2019-08-23 11:56:54 -07:00
blockIdx + + ;
}
// Check for comprehensiveness
bool isComprehensive = true ;
if ( ( switchValue ) & & ( switchStmt - > mDefaultCase = = NULL ) )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
if ( switchValue . mType - > IsEnum ( ) )
{
2021-10-04 07:50:05 -07:00
if ( hadConstMatch )
2019-08-23 11:56:54 -07:00
{
2021-10-04 07:50:05 -07:00
// Already handled
2019-08-23 11:56:54 -07:00
}
else
{
2021-10-04 07:50:05 -07:00
auto enumType = switchValue . mType - > ToTypeInstance ( ) ;
if ( enumType - > IsPayloadEnum ( ) )
2019-08-23 11:56:54 -07:00
{
2021-10-04 07:50:05 -07:00
int lastTagId = - 1 ;
for ( auto & field : enumType - > mFieldInstances )
2019-08-23 11:56:54 -07:00
{
2021-10-04 07:50:05 -07:00
auto fieldDef = field . GetFieldDef ( ) ;
if ( fieldDef = = NULL )
continue ;
2022-02-13 08:24:15 -05:00
if ( ! fieldDef - > IsEnumCaseEntry ( ) )
continue ;
2021-10-04 07:50:05 -07:00
if ( field . mDataIdx < 0 )
lastTagId = - field . mDataIdx - 1 ;
}
isComprehensive = lastTagId = = ( int ) handledCases . size ( ) - 1 ;
}
else
{
for ( auto & field : enumType - > mFieldInstances )
{
auto fieldDef = field . GetFieldDef ( ) ;
2022-02-13 08:24:15 -05:00
if ( ( fieldDef ! = NULL ) & & ( fieldDef - > IsEnumCaseEntry ( ) ) )
2019-08-23 11:56:54 -07:00
{
2021-10-04 07:50:05 -07:00
if ( field . mConstIdx ! = - 1 )
{
auto constant = enumType - > mConstHolder - > GetConstantById ( field . mConstIdx ) ;
isComprehensive & = handledCases . ContainsKey ( constant - > mInt64 ) ;
}
2019-08-23 11:56:54 -07:00
}
}
}
}
if ( ! isComprehensive )
{
BfAstNode * refNode = switchStmt - > mSwitchToken ;
Fail ( " Switch must be exhaustive, consider adding a default clause " , switchStmt - > mSwitchToken ) ;
if ( ( switchStmt - > mCloseBrace ) & & ( mCompiler - > IsAutocomplete ( ) ) & & ( mCompiler - > mResolvePassData - > mAutoComplete - > CheckFixit ( ( refNode ) ) ) )
{
BfParserData * parser = refNode - > GetSourceData ( ) - > ToParserData ( ) ;
if ( parser ! = NULL )
{
int fileLoc = switchStmt - > mCloseBrace - > GetSrcStart ( ) ;
mCompiler - > mResolvePassData - > mAutoComplete - > AddEntry ( AutoCompleteEntry ( " fixit " , StrFormat ( " default: \t default:|%s|%d||default: " , parser - > mFileName . c_str ( ) , fileLoc ) . c_str ( ) ) ) ;
}
}
}
}
else
isComprehensive = false ;
}
if ( ! hadConstMatch )
mBfIRBuilder - > CreateBr ( defaultBlock ) ;
mBfIRBuilder - > SetInsertPoint ( switchBlock ) ;
if ( ! hadConstIntVals )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
if ( switchStatement )
2022-07-26 13:27:03 -04:00
mBfIRBuilder - > EraseInstFromParent ( switchStatement ) ;
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > CreateBr ( noSwitchBlock ) ;
}
if ( switchStmt - > mDefaultCase ! = NULL )
{
SetAndRestoreValue < bool > prevIgnoreWrites ( mBfIRBuilder - > mIgnoreWrites , true , hadConstMatch ) ;
2022-05-30 11:40:49 -07:00
SetAndRestoreValue < bool > prevInConstIgnore ( mCurMethodState - > mCurScope - > mInConstIgnore , true , hadConstMatch ) ;
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > AddBlock ( defaultBlock ) ;
mBfIRBuilder - > SetInsertPoint ( defaultBlock ) ;
auto switchCase = switchStmt - > mDefaultCase ;
if ( switchCase - > mCodeBlock ! = NULL )
{
isComprehensive = true ;
2022-07-05 08:41:16 -07:00
UpdateSrcPos ( switchCase - > mCodeBlock ) ;
2019-08-23 11:56:54 -07:00
deferredLocalAssignDataVec [ blockIdx ] . mScopeData = mCurMethodState - > mCurScope ;
deferredLocalAssignDataVec [ blockIdx ] . ExtendFrom ( mCurMethodState - > mDeferredLocalAssignData ) ;
SetAndRestoreValue < BfDeferredLocalAssignData * > prevDLA ( mCurMethodState - > mDeferredLocalAssignData , & deferredLocalAssignDataVec [ blockIdx ] ) ;
mCurMethodState - > mDeferredLocalAssignData - > mVarIdBarrier = startingLocalVarId ;
2022-07-05 08:41:16 -07:00
BfScopeData caseScopeData ;
caseScopeData . mOuterIsConditional = true ;
caseScopeData . mIsSharedTempBlock = true ;
mCurMethodState - > AddScope ( & caseScopeData ) ;
NewScopeState ( ) ;
2024-11-20 11:33:28 -05:00
caseScopeData . mLabel = newScope . mLabel ;
2022-07-05 08:41:16 -07:00
2019-08-23 11:56:54 -07:00
bool hadReturn = false ;
2022-07-05 08:04:38 -07:00
VisitCodeBlock ( switchCase - > mCodeBlock , BfIRBlock ( ) , endBlock , BfIRBlock ( ) , true , & hadReturn , switchStmt - > mLabelNode ) ;
2019-08-23 11:56:54 -07:00
deferredLocalAssignDataVec [ blockIdx ] . mHadReturn = hadReturn ;
caseCount + + ;
if ( ! hadReturn )
allHadReturns = false ;
2022-07-05 08:41:16 -07:00
RestoreScopeState ( ) ;
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
}
2020-02-21 07:54:19 -08:00
else
{
mBfIRBuilder - > AddBlock ( defaultBlock ) ;
mBfIRBuilder - > SetInsertPoint ( defaultBlock ) ;
if ( isComprehensive )
2020-02-21 15:34:08 -08:00
{
2020-02-21 07:54:19 -08:00
mBfIRBuilder - > CreateUnreachable ( ) ;
2020-02-21 15:34:08 -08:00
//TODO: This masks a bug in our backend
if ( IsTargetingBeefBackend ( ) )
mBfIRBuilder - > CreateBr ( endBlock ) ;
}
2022-07-26 13:27:03 -04:00
else
2020-02-21 15:34:08 -08:00
mBfIRBuilder - > CreateBr ( endBlock ) ;
2020-02-21 07:54:19 -08:00
}
2019-08-23 11:56:54 -07:00
if ( isComprehensive )
{
// Merge and apply deferred local assign data
2022-07-26 13:27:03 -04:00
// We only do this if there's a default case, otherwise we assume we may have missed a case
2019-08-23 11:56:54 -07:00
// that by definition had no local assigns
BfDeferredLocalAssignData * mergedDeferredLocalAssignData = NULL ;
for ( blockIdx = 0 ; blockIdx < ( int ) blocks . size ( ) ; blockIdx + + )
{
auto deferredLocalAssignData = & deferredLocalAssignDataVec [ blockIdx ] ;
if ( deferredLocalAssignData - > mHadFallthrough )
continue ;
if ( mergedDeferredLocalAssignData = = NULL )
mergedDeferredLocalAssignData = deferredLocalAssignData ;
else
mergedDeferredLocalAssignData - > SetIntersection ( * deferredLocalAssignData ) ;
}
if ( mergedDeferredLocalAssignData ! = NULL )
mCurMethodState - > ApplyDeferredLocalAssignData ( * mergedDeferredLocalAssignData ) ;
}
if ( ( caseCount > 0 ) & & ( allHadReturns ) & &
2020-02-21 15:34:08 -08:00
( ( hasDefaultCase ) | | ( isComprehensive ) ) )
2019-08-23 11:56:54 -07:00
{
mCurMethodState - > SetHadReturn ( true ) ;
mCurMethodState - > mLeftBlockUncond = true ;
2020-02-21 15:34:08 -08:00
if ( ( ! hasDefaultCase ) & & ( ! isComprehensive ) )
2022-07-26 13:27:03 -04:00
mBfIRBuilder - > DeleteBlock ( endBlock ) ;
2019-08-23 11:56:54 -07:00
else
{
if ( switchStmt - > mCloseBrace ! = NULL )
UpdateSrcPos ( switchStmt - > mCloseBrace ) ;
mBfIRBuilder - > AddBlock ( endBlock ) ;
mBfIRBuilder - > SetInsertPoint ( endBlock ) ;
mBfIRBuilder - > CreateUnreachable ( ) ;
}
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
else
{
if ( switchStmt - > mCloseBrace ! = NULL )
UpdateSrcPos ( switchStmt - > mCloseBrace ) ;
mBfIRBuilder - > AddBlock ( endBlock ) ;
mBfIRBuilder - > SetInsertPoint ( endBlock ) ;
}
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
BfIRValue lifetimeExtendVal ;
if ( tryExtendValue )
{
if ( localDef - > mAddr )
lifetimeExtendVal = localDef - > mAddr ;
else
2022-07-26 13:27:03 -04:00
lifetimeExtendVal = localDef - > mValue ;
2019-08-23 11:56:54 -07:00
}
2022-07-26 13:27:03 -04:00
2020-09-04 09:53:47 -07:00
RestoreScopeState ( ) ; // newScope
RestoreScopeState ( ) ; // outerScope
2019-08-23 11:56:54 -07:00
if ( lifetimeExtendVal )
mBfIRBuilder - > CreateLifetimeExtend ( lifetimeExtendVal ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
ValueScopeEnd ( valueScopeStartOuter ) ;
}
static int gRetIdx = 0 ;
void BfModule : : Visit ( BfReturnStatement * returnStmt )
2022-07-26 13:27:03 -04:00
{
2022-01-29 15:02:19 -05:00
if ( ( mCurMethodInstance = = NULL ) | | ( mCurMethodState - > mDisableReturns ) )
2019-08-23 11:56:54 -07:00
{
Fail ( " Unexpected return " , returnStmt ) ;
2022-01-29 15:02:19 -05:00
if ( returnStmt - > mExpression ! = NULL )
{
BfExprEvaluator exprEvaluator ( this ) ;
CreateValueFromExpression ( exprEvaluator , returnStmt - > mExpression ) ;
}
2019-08-23 11:56:54 -07:00
return ;
}
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
UpdateSrcPos ( returnStmt ) ;
EmitEnsureInstructionAt ( ) ;
auto retType = mCurMethodInstance - > mReturnType ;
if ( mCurMethodInstance - > IsMixin ( ) )
retType = NULL ;
2021-01-14 06:24:34 -08:00
bool inferReturnType = false ;
if ( mCurMethodState - > mClosureState ! = NULL )
{
2019-08-23 11:56:54 -07:00
retType = mCurMethodState - > mClosureState - > mReturnType ;
2021-01-14 06:24:34 -08:00
inferReturnType = ( mCurMethodState - > mClosureState - > mReturnTypeInferState ! = BfReturnTypeInferState_None ) ;
}
2019-08-23 11:56:54 -07:00
2019-09-12 09:46:54 -07:00
auto checkScope = mCurMethodState - > mCurScope ;
while ( checkScope ! = NULL )
{
if ( checkScope - > mIsDeferredBlock )
{
Fail ( " Deferred blocks cannot contain 'return' statements " , returnStmt ) ;
if ( returnStmt - > mExpression ! = NULL )
{
BfExprEvaluator exprEvaluator ( this ) ;
CreateValueFromExpression ( exprEvaluator , returnStmt - > mExpression , GetPrimitiveType ( BfTypeCode_Var ) , BfEvalExprFlags_None ) ;
}
return ;
}
2020-12-04 06:29:25 -08:00
if ( checkScope - > mInInitBlock )
{
Fail ( " Initialization blocks cannot contain 'return' statements " , returnStmt ) ;
}
2022-07-26 13:27:03 -04:00
checkScope = checkScope - > mPrevScope ;
2020-09-21 13:58:00 -07:00
}
auto checkLocalAssignData = mCurMethodState - > mDeferredLocalAssignData ;
while ( checkLocalAssignData ! = NULL )
{
if ( checkLocalAssignData - > mScopeData ! = NULL )
checkLocalAssignData - > mLeftBlock = true ;
checkLocalAssignData = checkLocalAssignData - > mChainedAssignData ;
}
2019-09-12 09:46:54 -07:00
2021-01-14 06:24:34 -08:00
if ( ( retType = = NULL ) & & ( ! inferReturnType ) )
2019-08-23 11:56:54 -07:00
{
if ( returnStmt - > mExpression ! = NULL )
{
2022-07-26 13:27:03 -04:00
BfExprEvaluator exprEvaluator ( this ) ;
2019-08-23 11:56:54 -07:00
CreateValueFromExpression ( exprEvaluator , returnStmt - > mExpression , GetPrimitiveType ( BfTypeCode_Var ) , BfEvalExprFlags_None ) ;
}
MarkScopeLeft ( & mCurMethodState - > mHeadScope ) ;
return ;
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
if ( returnStmt - > mExpression = = NULL )
{
MarkScopeLeft ( & mCurMethodState - > mHeadScope ) ;
2022-07-26 13:27:03 -04:00
2021-02-28 12:56:02 -08:00
if ( ( retType ! = NULL ) & & ( retType - > IsVoid ( ) ) )
2019-08-23 11:56:54 -07:00
{
2020-12-30 13:24:13 -08:00
EmitReturn ( BfTypedValue ( ) ) ;
2019-08-23 11:56:54 -07:00
return ;
}
2021-02-28 12:56:02 -08:00
Fail ( " Expected return value " , returnStmt ) ;
2022-07-26 13:27:03 -04:00
if ( retType ! = NULL )
2021-02-28 12:56:02 -08:00
EmitReturn ( GetDefaultTypedValue ( retType ) ) ;
else
EmitReturn ( BfTypedValue ( ) ) ;
2022-07-26 13:27:03 -04:00
return ;
2019-08-23 11:56:54 -07:00
}
BfType * expectingReturnType = retType ;
BfType * origType ;
BfExprEvaluator exprEvaluator ( this ) ;
bool alreadyWritten = false ;
2021-01-08 16:21:03 -08:00
if ( ( ! mIsComptimeModule ) & & ( mCurMethodInstance - > GetStructRetIdx ( ) ! = - 1 ) )
2022-07-26 13:27:03 -04:00
exprEvaluator . mReceivingValue = & mCurMethodState - > mRetVal ;
2019-08-23 11:56:54 -07:00
if ( mCurMethodInstance - > mMethodDef - > mIsReadOnly )
exprEvaluator . mAllowReadOnlyReference = true ;
2021-01-14 06:24:34 -08:00
if ( inferReturnType )
expectingReturnType = NULL ;
2022-07-26 13:27:03 -04:00
auto retValue = CreateValueFromExpression ( exprEvaluator , returnStmt - > mExpression , expectingReturnType , BfEvalExprFlags_AllowRefExpr , & origType ) ;
2021-01-14 06:24:34 -08:00
if ( ( retValue ) & & ( inferReturnType ) )
{
if ( mCurMethodState - > mClosureState - > mReturnType = = NULL )
mCurMethodState - > mClosureState - > mReturnType = retValue . mType ;
else
{
if ( ( retValue . mType = = mCurMethodState - > mClosureState - > mReturnType ) | |
( CanCast ( retValue , mCurMethodState - > mClosureState - > mReturnType ) ) )
{
// Leave as-is
}
else if ( CanCast ( GetFakeTypedValue ( mCurMethodState - > mClosureState - > mReturnType ) , retValue . mType ) )
{
mCurMethodState - > mClosureState - > mReturnType = retValue . mType ;
}
else
{
mCurMethodState - > mClosureState - > mReturnTypeInferState = BfReturnTypeInferState_Fail ;
}
}
}
if ( ( retType = = NULL ) & & ( inferReturnType ) )
retType = mCurMethodState - > mClosureState - > mReturnType ;
if ( retType = = NULL )
retType = GetPrimitiveType ( BfTypeCode_None ) ;
2021-01-08 16:21:03 -08:00
if ( ( ! mIsComptimeModule ) & & ( mCurMethodInstance - > GetStructRetIdx ( ) ! = - 1 ) )
2019-08-23 11:56:54 -07:00
alreadyWritten = exprEvaluator . mReceivingValue = = NULL ;
MarkScopeLeft ( & mCurMethodState - > mHeadScope ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
if ( ! retValue )
{
AssertErrorState ( ) ;
if ( ( expectingReturnType ! = NULL ) & & ( ! expectingReturnType - > IsVoid ( ) ) )
{
retValue = GetDefaultTypedValue ( expectingReturnType , true ) ;
}
else
{
2020-12-30 13:24:13 -08:00
EmitReturn ( BfTypedValue ( ) ) ;
2019-08-23 11:56:54 -07:00
return ;
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
}
2020-03-10 08:27:57 -07:00
if ( retValue . mType - > IsVar ( ) )
{
2020-12-30 13:24:13 -08:00
EmitReturn ( BfTypedValue ( ) ) ;
2020-03-10 08:27:57 -07:00
}
else if ( retValue . mType - > IsVoid ( ) )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
if ( retType - > IsVoid ( ) )
{
Warn ( 0 , " Returning void value " , returnStmt - > mReturnToken ) ;
2020-12-30 13:24:13 -08:00
EmitReturn ( BfTypedValue ( ) ) ;
2019-08-23 11:56:54 -07:00
}
}
else
{
if ( retType - > IsVoid ( ) )
{
expectingReturnType = NULL ;
Fail ( " Attempting to return value from void method " , returnStmt - > mExpression ) ;
2020-12-30 13:24:13 -08:00
EmitReturn ( BfTypedValue ( ) ) ;
2019-08-23 11:56:54 -07:00
return ;
}
if ( ( origType ! = NULL ) & & ( origType - > IsStructOrStructPtr ( ) ) & & ( retValue . mType - > IsObjectOrInterface ( ) ) )
{
Fail ( StrFormat ( " Stack boxing of type '%s' is not allowed on return statements. Use 'new box' to box on the heap. " , TypeToString ( origType ) . c_str ( ) ) , returnStmt - > mExpression ) ;
}
if ( ! alreadyWritten )
2020-12-30 13:24:13 -08:00
EmitReturn ( LoadOrAggregateValue ( retValue ) ) ;
2019-08-23 11:56:54 -07:00
else
2020-12-30 13:24:13 -08:00
EmitReturn ( BfTypedValue ( ) ) ;
2019-08-23 11:56:54 -07:00
}
}
void BfModule : : Visit ( BfYieldStatement * yieldStmt )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
Fail ( " Yield not supported " , yieldStmt ) ;
}
void BfModule : : Visit ( BfBreakStatement * breakStmt )
{
bool inMixinDecl = ( mCurMethodInstance ! = NULL ) & & ( mCurMethodInstance - > IsMixin ( ) ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
UpdateSrcPos ( breakStmt ) ;
2022-08-24 15:44:19 -07:00
EmitEnsureInstructionAt ( ) ;
2019-08-23 11:56:54 -07:00
BfBreakData * breakData = mCurMethodState - > mBreakData ;
if ( breakStmt - > mLabel ! = NULL )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
breakData = FindBreakData ( breakStmt - > mLabel ) ;
}
else
{
while ( breakData ! = NULL )
{
if ( breakData - > mIRBreakBlock )
break ;
breakData = breakData - > mPrevBreakData ;
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
}
2020-05-29 16:58:47 -07:00
if ( ( mCompiler - > mResolvePassData ! = NULL ) & & ( mCompiler - > mResolvePassData - > mAutoComplete ! = NULL ) )
{
BfScopeData * scope = NULL ;
if ( breakData ! = NULL )
scope = breakData - > mScope ;
if ( auto identifer = BfNodeDynCast < BfIdentifierNode > ( breakStmt - > mLabel ) )
mCompiler - > mResolvePassData - > mAutoComplete - > CheckLabel ( identifer , breakStmt - > mBreakNode , scope ) ;
}
2019-08-23 11:56:54 -07:00
if ( ( breakData = = NULL ) | | ( ! breakData - > mIRBreakBlock ) )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
if ( inMixinDecl )
{
// Our mixin may just require that we're injected into a breakable scope
}
else
Fail ( " 'break' not applicable in this block " , breakStmt ) ;
return ;
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
2019-09-12 09:46:54 -07:00
if ( mCurMethodState - > mInDeferredBlock )
{
auto checkScope = mCurMethodState - > mCurScope ;
while ( checkScope ! = NULL )
{
if ( checkScope = = breakData - > mScope )
break ;
if ( checkScope - > mIsDeferredBlock )
2022-07-26 13:27:03 -04:00
{
2019-12-09 10:29:31 -08:00
Fail ( " The break target crosses a deferred block boundary " , breakStmt ) ;
return ;
2019-09-12 09:46:54 -07:00
}
checkScope = checkScope - > mPrevScope ;
}
}
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
if ( HasDeferredScopeCalls ( breakData - > mScope ) )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
EmitDeferredScopeCalls ( true , breakData - > mScope , breakData - > mIRBreakBlock ) ;
}
else
2022-07-26 13:27:03 -04:00
{
mBfIRBuilder - > CreateBr ( breakData - > mIRBreakBlock ) ;
2019-08-23 11:56:54 -07:00
}
2022-07-26 13:27:03 -04:00
mCurMethodState - > mLeftBlockUncond = true ;
2019-08-23 11:56:54 -07:00
2022-07-05 08:04:38 -07:00
bool isCond = false ;
int uncondScopeDepth = 0 ;
if ( mCurMethodState - > mCurScope ! = NULL )
uncondScopeDepth = mCurMethodState - > mCurScope - > mScopeDepth + 1 ;
2022-07-26 13:27:03 -04:00
BfIRValue earliestValueScopeStart ;
2019-08-23 11:56:54 -07:00
auto checkScope = mCurMethodState - > mCurScope ;
while ( checkScope ! = NULL )
2022-07-26 13:27:03 -04:00
{
2022-07-05 08:04:38 -07:00
if ( ! isCond )
uncondScopeDepth = checkScope - > mScopeDepth ;
if ( ( checkScope - > mOuterIsConditional ) & & ( ! checkScope - > mIsSharedTempBlock ) )
isCond = true ;
2019-08-23 11:56:54 -07:00
if ( checkScope - > mValueScopeStart )
earliestValueScopeStart = checkScope - > mValueScopeStart ;
if ( checkScope = = breakData - > mScope )
break ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
checkScope = checkScope - > mPrevScope ;
}
2022-07-05 08:04:38 -07:00
auto checkLocalAssignData = mCurMethodState - > mDeferredLocalAssignData ;
while ( checkLocalAssignData ! = NULL )
{
if ( ( checkLocalAssignData - > mScopeData ! = NULL ) & & ( checkLocalAssignData - > mScopeData - > mScopeDepth > = breakData - > mScope - > mScopeDepth ) )
{
if ( checkLocalAssignData - > mScopeData - > mScopeDepth > = uncondScopeDepth )
checkLocalAssignData - > mLeftBlockUncond = true ;
checkLocalAssignData - > mLeftBlock = true ;
checkLocalAssignData - > mHadBreak = true ;
}
checkLocalAssignData = checkLocalAssignData - > mChainedAssignData ;
}
2019-08-23 11:56:54 -07:00
MarkScopeLeft ( breakData - > mScope ) ;
2022-07-26 13:27:03 -04:00
ValueScopeEnd ( earliestValueScopeStart ) ;
2019-08-23 11:56:54 -07:00
auto checkBreakData = mCurMethodState - > mBreakData ;
while ( true )
{
checkBreakData - > mHadBreak = true ;
if ( checkBreakData = = breakData )
break ;
checkBreakData = checkBreakData - > mPrevBreakData ;
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
}
void BfModule : : Visit ( BfContinueStatement * continueStmt )
{
bool inMixinDecl = ( mCurMethodInstance ! = NULL ) & & ( mCurMethodInstance - > IsMixin ( ) ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
UpdateSrcPos ( continueStmt ) ;
2022-08-24 15:44:19 -07:00
EmitEnsureInstructionAt ( ) ;
2019-08-23 11:56:54 -07:00
// If we're in a switch, 'break' is valid but we need to continue looking outward for a 'continue' target
BfBreakData * breakData = mCurMethodState - > mBreakData ;
if ( continueStmt - > mLabel ! = NULL )
{
breakData = FindBreakData ( continueStmt - > mLabel ) ;
if ( ( breakData ! = NULL ) & & ( ! breakData - > mIRContinueBlock ) )
{
Fail ( StrFormat ( " 'continue' not applicable in '%s " , continueStmt - > mLabel - > ToString ( ) . c_str ( ) ) , continueStmt ) ;
return ;
}
}
else
{
while ( breakData ! = NULL )
{
if ( breakData - > mIRContinueBlock )
break ;
breakData = breakData - > mPrevBreakData ;
}
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
2020-05-29 16:58:47 -07:00
if ( ( mCompiler - > mResolvePassData ! = NULL ) & & ( mCompiler - > mResolvePassData - > mAutoComplete ! = NULL ) )
{
BfScopeData * scope = NULL ;
if ( breakData ! = NULL )
scope = breakData - > mScope ;
if ( auto identifer = BfNodeDynCast < BfIdentifierNode > ( continueStmt - > mLabel ) )
mCompiler - > mResolvePassData - > mAutoComplete - > CheckLabel ( identifer , continueStmt - > mContinueNode , scope ) ;
}
2019-08-23 11:56:54 -07:00
if ( ( breakData = = NULL ) | | ( ! breakData - > mIRContinueBlock ) )
{
if ( inMixinDecl )
{
// Our mixin may just require that we're injected into a breakable scope
}
else
2022-04-16 13:40:30 -07:00
Fail ( " 'continue' not applicable in this block " , continueStmt ) ;
2019-08-23 11:56:54 -07:00
return ;
}
BfIRValue earliestValueScopeStart ;
// We don't want to close out our own scope, we want to close out any scopes that were opened after us
auto nextScope = mCurMethodState - > mCurScope ;
while ( nextScope ! = NULL )
{
if ( nextScope - > mValueScopeStart )
earliestValueScopeStart = nextScope - > mValueScopeStart ;
if ( nextScope - > mPrevScope = = breakData - > mScope )
break ;
nextScope = nextScope - > mPrevScope ;
}
if ( breakData - > mInnerValueScopeStart )
earliestValueScopeStart = breakData - > mInnerValueScopeStart ;
2019-09-12 09:46:54 -07:00
if ( mCurMethodState - > mInDeferredBlock )
{
auto checkScope = mCurMethodState - > mCurScope ;
while ( checkScope ! = NULL )
{
if ( checkScope = = breakData - > mScope )
break ;
if ( checkScope - > mIsDeferredBlock )
{
Fail ( " The continue target crosses a deferred block boundary " , continueStmt ) ;
return ;
}
checkScope = checkScope - > mPrevScope ;
}
}
2019-08-23 11:56:54 -07:00
if ( ( nextScope ! = NULL ) & & ( HasDeferredScopeCalls ( nextScope ) ) )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
EmitDeferredScopeCalls ( true , nextScope , breakData - > mIRContinueBlock ) ;
}
else
{
mBfIRBuilder - > CreateBr ( breakData - > mIRContinueBlock ) ;
}
MarkScopeLeft ( breakData - > mScope ) ;
ValueScopeEnd ( earliestValueScopeStart ) ;
mCurMethodState - > mLeftBlockUncond = true ;
if ( ! mCurMethodState - > mInPostReturn )
mCurMethodState - > mHadContinue = true ;
}
void BfModule : : Visit ( BfFallthroughStatement * fallthroughStmt )
{
UpdateSrcPos ( fallthroughStmt ) ;
2022-04-16 13:40:30 -07:00
BfBreakData * breakData = mCurMethodState - > mBreakData ;
2023-12-16 07:38:27 -05:00
if ( fallthroughStmt - > mLabel ! = NULL )
2022-04-16 13:40:30 -07:00
{
2023-12-16 07:38:27 -05:00
breakData = FindBreakData ( fallthroughStmt - > mLabel ) ;
}
else
{
while ( breakData ! = NULL )
{
if ( breakData - > mIRFallthroughBlock )
break ;
breakData = breakData - > mPrevBreakData ;
}
}
if ( ( mCompiler - > mResolvePassData ! = NULL ) & & ( mCompiler - > mResolvePassData - > mAutoComplete ! = NULL ) )
{
BfScopeData * scope = NULL ;
if ( breakData ! = NULL )
scope = breakData - > mScope ;
if ( auto identifer = BfNodeDynCast < BfIdentifierNode > ( fallthroughStmt - > mLabel ) )
mCompiler - > mResolvePassData - > mAutoComplete - > CheckLabel ( identifer , fallthroughStmt - > mFallthroughToken , scope ) ;
2022-04-16 13:40:30 -07:00
}
if ( mCurMethodState - > mInDeferredBlock )
{
auto checkScope = mCurMethodState - > mCurScope ;
while ( checkScope ! = NULL )
{
if ( checkScope = = breakData - > mScope )
break ;
if ( checkScope - > mIsDeferredBlock )
{
Fail ( " The fallthrough crosses a deferred block boundary " , fallthroughStmt ) ;
return ;
}
checkScope = checkScope - > mPrevScope ;
}
}
if ( breakData = = NULL )
2019-08-23 11:56:54 -07:00
{
2022-04-16 13:40:30 -07:00
Fail ( " 'fallthrough' not applicable in this block " , fallthroughStmt ) ;
2019-08-23 11:56:54 -07:00
return ;
}
2022-04-16 13:40:30 -07:00
EmitDeferredScopeCalls ( true , breakData - > mScope , breakData - > mIRFallthroughBlock ) ;
2019-08-23 11:56:54 -07:00
mCurMethodState - > mLeftBlockUncond = true ; // Not really a return, but handled the same way
if ( mCurMethodState - > mDeferredLocalAssignData ! = NULL )
mCurMethodState - > mDeferredLocalAssignData - > mHadFallthrough = true ;
2023-12-16 07:38:27 -05:00
auto checkBreakData = mCurMethodState - > mBreakData ;
while ( true )
{
if ( checkBreakData = = breakData )
break ;
checkBreakData - > mHadBreak = true ;
checkBreakData = checkBreakData - > mPrevBreakData ;
}
2019-08-23 11:56:54 -07:00
}
void BfModule : : Visit ( BfUsingStatement * usingStmt )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
UpdateSrcPos ( usingStmt ) ;
mCurMethodState - > mInHeadScope = false ;
BfScopeData newScope ;
2022-07-26 13:27:03 -04:00
mCurMethodState - > AddScope ( & newScope ) ;
2019-08-23 11:56:54 -07:00
NewScopeState ( ) ;
if ( usingStmt - > mVariableDeclaration ! = NULL )
UpdateSrcPos ( usingStmt - > mVariableDeclaration ) ;
BfTypedValue embeddedValue ;
SizedArray < BfIRValue , 1 > llvmArgs ;
BfModuleMethodInstance moduleMethodInstance ;
BfFunctionBindResult functionBindResult ;
BfExprEvaluator exprEvaluator ( this ) ;
bool failed = false ;
if ( usingStmt - > mVariableDeclaration = = NULL )
{
AssertErrorState ( ) ;
failed = true ;
}
else if ( usingStmt - > mVariableDeclaration - > mNameNode ! = NULL )
{
BfLocalVariable * localVar = HandleVariableDeclaration ( usingStmt - > mVariableDeclaration ) ;
if ( localVar = = NULL )
{
AssertErrorState ( ) ;
failed = true ;
}
2022-07-26 13:27:03 -04:00
else
2019-09-29 07:42:58 -07:00
{
2022-07-26 13:27:03 -04:00
embeddedValue = exprEvaluator . LoadLocal ( localVar ) ;
2019-09-29 07:42:58 -07:00
}
//exprEvaluator.CheckModifyResult(embeddedValue, usingStmt->mVariableDeclaration->mNameNode,);
2019-08-23 11:56:54 -07:00
}
2022-07-26 13:27:03 -04:00
else
{
2019-08-23 11:56:54 -07:00
embeddedValue = CreateValueFromExpression ( usingStmt - > mVariableDeclaration - > mInitializer ) ;
if ( ! embeddedValue )
failed = true ;
}
if ( ! failed )
2022-07-26 13:27:03 -04:00
{
2020-02-17 05:39:05 -08:00
auto iDisposableType = ResolveTypeDef ( mCompiler - > mIDisposableTypeDef ) - > ToTypeInstance ( ) ;
auto dispMethod = GetMethodByName ( iDisposableType , " Dispose " ) ;
if ( ( ! dispMethod ) | | ( ! CanCast ( embeddedValue , iDisposableType ) ) )
2019-08-23 11:56:54 -07:00
{
2020-02-17 05:39:05 -08:00
Fail ( StrFormat ( " Type '%s' must be implicitly convertible to 'System.IDisposable' for use in 'using' statement " , TypeToString ( embeddedValue . mType ) . c_str ( ) ) , usingStmt - > mVariableDeclaration ) ;
failed = true ;
}
else
{
bool mayBeNull = true ;
if ( embeddedValue . mType - > IsStruct ( ) )
{
// It's possible that a struct can convert to an IDisposable through a conversion operator that CAN
// return null, so the only way we can know we are not null is if we are a struct that directly
// implements the interface
if ( TypeIsSubTypeOf ( embeddedValue . mType - > ToTypeInstance ( ) , iDisposableType ) )
mayBeNull = false ;
}
2022-07-26 13:27:03 -04:00
exprEvaluator . mFunctionBindResult = & functionBindResult ;
2020-02-17 05:39:05 -08:00
SizedArray < BfResolvedArg , 0 > resolvedArgs ;
2022-02-05 13:47:19 -05:00
BfMethodMatcher methodMatcher ( usingStmt - > mVariableDeclaration , this , dispMethod . mMethodInstance , resolvedArgs , BfMethodGenericArguments ( ) ) ;
2020-02-17 05:39:05 -08:00
methodMatcher . CheckType ( iDisposableType , embeddedValue , false ) ;
methodMatcher . TryDevirtualizeCall ( embeddedValue ) ;
auto retVal = exprEvaluator . CreateCall ( & methodMatcher , embeddedValue ) ;
if ( functionBindResult . mMethodInstance ! = NULL )
{
moduleMethodInstance = BfModuleMethodInstance ( functionBindResult . mMethodInstance , functionBindResult . mFunc ) ;
AddDeferredCall ( moduleMethodInstance , functionBindResult . mIRArgs , mCurMethodState - > mCurScope , NULL , false , mayBeNull ) ;
}
}
2019-08-23 11:56:54 -07:00
}
if ( usingStmt - > mEmbeddedStatement = = NULL )
{
AssertErrorState ( ) ;
}
else
{
VisitEmbeddedStatement ( usingStmt - > mEmbeddedStatement ) ;
}
RestoreScopeState ( ) ;
}
void BfModule : : Visit ( BfDoStatement * doStmt )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
UpdateSrcPos ( doStmt ) ;
2022-07-26 13:27:03 -04:00
auto bodyBB = mBfIRBuilder - > CreateBlock ( " do.body " , true ) ;
2019-08-23 11:56:54 -07:00
auto endBB = mBfIRBuilder - > CreateBlock ( " do.end " ) ;
2022-07-26 13:27:03 -04:00
BfScopeData scopeData ;
2019-08-23 11:56:54 -07:00
if ( doStmt - > mLabelNode ! = NULL )
scopeData . mLabelNode = doStmt - > mLabelNode - > mLabel ;
mCurMethodState - > AddScope ( & scopeData ) ;
NewScopeState ( ) ;
2022-07-26 13:27:03 -04:00
BfBreakData breakData ;
2019-08-23 11:56:54 -07:00
breakData . mIRBreakBlock = endBB ;
breakData . mScope = & scopeData ;
2022-07-26 13:27:03 -04:00
breakData . mPrevBreakData = mCurMethodState - > mBreakData ;
2019-08-23 11:56:54 -07:00
SetAndRestoreValue < BfBreakData * > prevBreakData ( mCurMethodState - > mBreakData , & breakData ) ;
2020-09-21 13:58:00 -07:00
BfDeferredLocalAssignData deferredLocalAssignData ( mCurMethodState - > mCurScope ) ;
deferredLocalAssignData . ExtendFrom ( mCurMethodState - > mDeferredLocalAssignData , false ) ;
deferredLocalAssignData . mVarIdBarrier = mCurMethodState - > GetRootMethodState ( ) - > mCurLocalVarId ;
2022-07-26 13:27:03 -04:00
SetAndRestoreValue < BfDeferredLocalAssignData * > prevDLA ( mCurMethodState - > mDeferredLocalAssignData , & deferredLocalAssignData ) ;
2020-09-21 13:58:00 -07:00
2019-08-23 11:56:54 -07:00
// We may have a call in the loop body
mCurMethodState - > mMayNeedThisAccessCheck = true ;
mBfIRBuilder - > CreateBr ( bodyBB ) ;
2022-07-26 13:27:03 -04:00
mBfIRBuilder - > SetInsertPoint ( bodyBB ) ;
VisitEmbeddedStatement ( doStmt - > mEmbeddedStatement ) ;
2020-09-21 13:58:00 -07:00
prevDLA . Restore ( ) ;
mCurMethodState - > ApplyDeferredLocalAssignData ( deferredLocalAssignData ) ;
2020-05-30 06:43:30 -07:00
2022-07-26 13:27:03 -04:00
RestoreScopeState ( ) ;
2020-05-30 06:43:30 -07:00
2019-08-23 11:56:54 -07:00
if ( ! mCurMethodState - > mLeftBlockUncond )
mBfIRBuilder - > CreateBr ( endBB ) ;
mCurMethodState - > SetHadReturn ( false ) ;
mCurMethodState - > mLeftBlockUncond = false ;
mBfIRBuilder - > AddBlock ( endBB ) ;
2022-07-26 13:27:03 -04:00
mBfIRBuilder - > SetInsertPoint ( endBB ) ;
2019-08-23 11:56:54 -07:00
}
void BfModule : : Visit ( BfRepeatStatement * repeatStmt )
{
// if (repeatStmt->mCondition != NULL)
// UpdateSrcPos(repeatStmt->mCondition);
// else
UpdateSrcPos ( repeatStmt ) ;
if ( repeatStmt - > mRepeatToken - > mToken = = BfToken_Do )
{
Fail ( " Repeat block requires 'repeat' token " , repeatStmt - > mRepeatToken ) ;
}
auto bodyBB = mBfIRBuilder - > CreateBlock ( " repeat.body " , true ) ;
auto condBB = mBfIRBuilder - > CreateBlock ( " repeat.cond " ) ;
auto endBB = mBfIRBuilder - > CreateBlock ( " repeat.end " ) ;
BfScopeData scopeData ;
2022-07-26 13:27:03 -04:00
// We set mIsLoop later
2019-08-23 11:56:54 -07:00
if ( repeatStmt - > mLabelNode ! = NULL )
scopeData . mLabelNode = repeatStmt - > mLabelNode - > mLabel ;
mCurMethodState - > AddScope ( & scopeData ) ;
NewScopeState ( ) ;
BfBreakData breakData ;
breakData . mIRContinueBlock = condBB ;
breakData . mIRBreakBlock = endBB ;
breakData . mScope = & scopeData ;
2022-07-26 13:27:03 -04:00
breakData . mPrevBreakData = mCurMethodState - > mBreakData ;
2019-08-23 11:56:54 -07:00
SetAndRestoreValue < BfBreakData * > prevBreakData ( mCurMethodState - > mBreakData , & breakData ) ;
// We may have a call in the loop body
mCurMethodState - > mMayNeedThisAccessCheck = true ;
mBfIRBuilder - > CreateBr ( bodyBB ) ;
2022-07-26 13:27:03 -04:00
mBfIRBuilder - > SetInsertPoint ( bodyBB ) ;
scopeData . mIsLoop = true ;
2022-07-05 08:04:38 -07:00
BfDeferredLocalAssignData deferredLocalAssignData ( mCurMethodState - > mCurScope ) ;
deferredLocalAssignData . ExtendFrom ( mCurMethodState - > mDeferredLocalAssignData , false ) ;
deferredLocalAssignData . mVarIdBarrier = mCurMethodState - > GetRootMethodState ( ) - > mCurLocalVarId ;
SetAndRestoreValue < BfDeferredLocalAssignData * > prevDLA ( mCurMethodState - > mDeferredLocalAssignData , & deferredLocalAssignData ) ;
VisitEmbeddedStatement ( repeatStmt - > mEmbeddedStatement ) ;
2019-08-23 11:56:54 -07:00
if ( ! mCurMethodState - > mLeftBlockUncond )
mBfIRBuilder - > CreateBr ( condBB ) ;
2022-07-26 13:27:03 -04:00
mCurMethodState - > SetHadReturn ( false ) ;
2019-08-23 11:56:54 -07:00
mCurMethodState - > mLeftBlockUncond = false ;
mCurMethodState - > mLeftBlockCond = false ;
2022-07-26 13:27:03 -04:00
mBfIRBuilder - > AddBlock ( condBB ) ;
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > SetInsertPoint ( condBB ) ;
bool isInfiniteLoop = false ;
2022-07-26 13:27:03 -04:00
if ( repeatStmt - > mCondition ! = NULL )
{
2019-08-23 11:56:54 -07:00
UpdateSrcPos ( repeatStmt - > mCondition ) ;
auto checkVal = CreateValueFromExpression ( repeatStmt - > mCondition , GetPrimitiveType ( BfTypeCode_Boolean ) ) ;
2022-07-26 13:27:03 -04:00
if ( checkVal )
2019-08-23 11:56:54 -07:00
{
if ( ( ! breakData . mHadBreak ) & & ( checkVal . mValue . IsConst ( ) ) )
{
auto constVal = mBfIRBuilder - > GetConstantById ( checkVal . mValue . mId ) ;
if ( constVal - > mTypeCode = = BfTypeCode_Boolean )
isInfiniteLoop = constVal - > mBool ;
}
mBfIRBuilder - > CreateCondBr ( checkVal . mValue , bodyBB , endBB ) ;
mBfIRBuilder - > AddBlock ( endBB ) ;
mBfIRBuilder - > SetInsertPoint ( endBB ) ;
}
}
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
RestoreScopeState ( ) ;
2022-07-05 08:41:16 -07:00
prevDLA . Restore ( ) ;
mCurMethodState - > ApplyDeferredLocalAssignData ( deferredLocalAssignData ) ;
2019-08-23 11:56:54 -07:00
if ( isInfiniteLoop )
EmitDefaultReturn ( ) ;
}
void BfModule : : Visit ( BfWhileStatement * whileStmt )
{
UpdateSrcPos ( whileStmt ) ;
2020-05-05 07:33:02 -07:00
bool prevHadReturn = mCurMethodState - > mHadReturn ;
2019-08-23 11:56:54 -07:00
auto condBB = mBfIRBuilder - > CreateBlock ( " while.cond " ) ;
2022-07-26 13:27:03 -04:00
auto bodyBB = mBfIRBuilder - > CreateBlock ( " while.body " ) ;
auto endBB = mBfIRBuilder - > CreateBlock ( " while.end " ) ;
2019-08-23 11:56:54 -07:00
mCurMethodState - > mInHeadScope = false ;
BfScopeData scopeData ;
2022-02-16 09:01:15 -05:00
scopeData . mScopeKind = BfScopeKind_StatementTarget_Conditional ;
2019-08-23 11:56:54 -07:00
scopeData . mIsLoop = true ;
if ( whileStmt - > mLabelNode ! = NULL )
scopeData . mLabelNode = whileStmt - > mLabelNode - > mLabel ;
scopeData . mValueScopeStart = ValueScopeStart ( ) ;
2022-07-26 13:27:03 -04:00
mCurMethodState - > AddScope ( & scopeData ) ;
2019-08-23 11:56:54 -07:00
NewScopeState ( ) ;
BfBreakData breakData ;
breakData . mIRContinueBlock = condBB ;
breakData . mIRBreakBlock = endBB ;
breakData . mScope = & scopeData ;
2022-07-26 13:27:03 -04:00
breakData . mPrevBreakData = mCurMethodState - > mBreakData ;
2019-08-23 11:56:54 -07:00
breakData . mInnerValueScopeStart = scopeData . mValueScopeStart ;
SetAndRestoreValue < BfBreakData * > prevBreakData ( mCurMethodState - > mBreakData , & breakData ) ;
mBfIRBuilder - > AddBlock ( condBB ) ;
mBfIRBuilder - > CreateBr ( condBB ) ;
mBfIRBuilder - > SetInsertPoint ( condBB ) ;
BfTypedValue checkVal ;
if ( whileStmt - > mCondition ! = NULL )
{
UpdateSrcPos ( whileStmt - > mCondition ) ;
checkVal = CreateValueFromExpression ( whileStmt - > mCondition , GetPrimitiveType ( BfTypeCode_Boolean ) ) ;
}
if ( ! checkVal )
{
AssertErrorState ( ) ;
checkVal = GetDefaultTypedValue ( GetPrimitiveType ( BfTypeCode_Boolean ) ) ;
}
bool isInfiniteLoop = false ;
2020-05-04 17:32:03 -07:00
bool isFalseLoop = false ;
2019-08-23 11:56:54 -07:00
if ( checkVal . mValue . IsConst ( ) )
{
2022-08-24 15:44:19 -07:00
EmitEnsureInstructionAt ( ) ;
2020-05-04 17:32:03 -07:00
2019-08-23 11:56:54 -07:00
auto constVal = mBfIRBuilder - > GetConstantById ( checkVal . mValue . mId ) ;
if ( constVal - > mTypeCode = = BfTypeCode_Boolean )
2020-05-04 17:32:03 -07:00
{
2019-08-23 11:56:54 -07:00
isInfiniteLoop = constVal - > mBool ;
2020-05-04 17:32:03 -07:00
isFalseLoop = ! isInfiniteLoop ;
}
2019-08-23 11:56:54 -07:00
}
// We may have a call in the loop body
mCurMethodState - > mMayNeedThisAccessCheck = true ;
2020-05-05 07:33:02 -07:00
// For BeefBackend we continue to do CondBr because it helps our flow analysis and we optimize it anyway
if ( ( isInfiniteLoop ) & & ( ! IsTargetingBeefBackend ( ) ) )
mBfIRBuilder - > CreateBr ( bodyBB ) ;
2020-12-06 09:06:14 -08:00
else if ( isFalseLoop )
2020-05-05 07:33:02 -07:00
mBfIRBuilder - > CreateBr ( endBB ) ;
2022-07-26 13:27:03 -04:00
else
2020-05-05 07:33:02 -07:00
mBfIRBuilder - > CreateCondBr ( checkVal . mValue , bodyBB , endBB ) ;
2019-08-23 11:56:54 -07:00
// Apply deferred local assign to mEmbeddedStatement and itrStmt
BfDeferredLocalAssignData deferredLocalAssignData ( mCurMethodState - > mCurScope ) ;
deferredLocalAssignData . ExtendFrom ( mCurMethodState - > mDeferredLocalAssignData , false ) ;
deferredLocalAssignData . mVarIdBarrier = mCurMethodState - > GetRootMethodState ( ) - > mCurLocalVarId ;
SetAndRestoreValue < BfDeferredLocalAssignData * > prevDLA ( mCurMethodState - > mDeferredLocalAssignData , & deferredLocalAssignData ) ;
deferredLocalAssignData . mIsUnconditional = isInfiniteLoop ;
mBfIRBuilder - > AddBlock ( bodyBB ) ;
2022-07-26 13:27:03 -04:00
mBfIRBuilder - > SetInsertPoint ( bodyBB ) ;
2019-08-23 11:56:54 -07:00
if ( whileStmt - > mEmbeddedStatement ! = NULL )
{
2020-05-04 17:32:03 -07:00
if ( isFalseLoop )
{
SetAndRestoreValue < bool > ignoreWrites ( mBfIRBuilder - > mIgnoreWrites , true ) ;
2022-05-30 11:40:49 -07:00
SetAndRestoreValue < bool > prevInConstIgnore ( mCurMethodState - > mCurScope - > mInConstIgnore , true ) ;
2020-05-04 17:32:03 -07:00
VisitEmbeddedStatement ( whileStmt - > mEmbeddedStatement ) ;
}
else
2022-07-26 13:27:03 -04:00
VisitEmbeddedStatement ( whileStmt - > mEmbeddedStatement ) ;
2019-08-23 11:56:54 -07:00
}
else
{
AssertErrorState ( ) ;
}
if ( breakData . mHadBreak )
{
isInfiniteLoop = false ;
}
2022-07-26 13:27:03 -04:00
2020-05-05 07:33:02 -07:00
if ( ( ! mCurMethodState - > mLeftBlockUncond ) & & ( ! isFalseLoop ) )
2019-08-23 11:56:54 -07:00
{
2020-05-05 07:33:02 -07:00
mBfIRBuilder - > CreateBr ( condBB ) ;
2022-07-26 13:27:03 -04:00
}
2020-05-04 17:32:03 -07:00
if ( ! isInfiniteLoop )
2020-05-05 07:33:02 -07:00
mCurMethodState - > mHadReturn = prevHadReturn ;
2020-05-04 17:32:03 -07:00
2022-07-26 13:27:03 -04:00
mCurMethodState - > mLeftBlockUncond = false ;
mCurMethodState - > mLeftBlockCond = false ;
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > AddBlock ( endBB ) ;
mBfIRBuilder - > SetInsertPoint ( endBB ) ;
2020-05-05 07:33:02 -07:00
if ( isFalseLoop )
{
2022-07-26 13:27:03 -04:00
mBfIRBuilder - > EraseFromParent ( bodyBB ) ;
2020-05-05 07:33:02 -07:00
}
2019-08-23 11:56:54 -07:00
RestoreScopeState ( ) ;
if ( ( isInfiniteLoop ) & & ( mCurMethodInstance ! = NULL ) )
EmitDefaultReturn ( ) ;
}
void BfModule : : Visit ( BfForStatement * forStmt )
{
2020-05-26 06:10:51 -07:00
auto autoComplete = mCompiler - > GetAutoComplete ( ) ;
if ( autoComplete ! = NULL )
autoComplete - > CheckIdentifier ( forStmt - > mForToken , true ) ;
2019-08-23 11:56:54 -07:00
UpdateSrcPos ( forStmt ) ;
auto startBB = mBfIRBuilder - > CreateBlock ( " for.start " , true ) ;
mBfIRBuilder - > CreateBr ( startBB ) ;
mBfIRBuilder - > SetInsertPoint ( startBB ) ;
BfScopeData scopeData ;
scopeData . mIsLoop = true ;
if ( forStmt - > mLabelNode ! = NULL )
scopeData . mLabelNode = forStmt - > mLabelNode - > mLabel ;
scopeData . mCloseNode = forStmt ;
scopeData . mValueScopeStart = ValueScopeStart ( ) ;
mCurMethodState - > AddScope ( & scopeData ) ;
NewScopeState ( ) ;
for ( auto initializer : forStmt - > mInitializers )
{
VisitChild ( initializer ) ;
}
// We may have a call in the loop body
mCurMethodState - > mMayNeedThisAccessCheck = true ;
auto boolType = GetPrimitiveType ( BfTypeCode_Boolean ) ;
auto condBB = mBfIRBuilder - > CreateBlock ( " for.cond " , true ) ;
auto bodyBB = mBfIRBuilder - > CreateBlock ( " for.body " ) ;
auto incBB = mBfIRBuilder - > CreateBlock ( " for.inc " ) ;
auto endBB = mBfIRBuilder - > CreateBlock ( " for.end " ) ;
2022-07-26 13:27:03 -04:00
BfBreakData breakData ;
2019-08-23 11:56:54 -07:00
breakData . mIRContinueBlock = incBB ;
breakData . mIRBreakBlock = endBB ;
breakData . mScope = & scopeData ;
2022-07-26 13:27:03 -04:00
breakData . mPrevBreakData = mCurMethodState - > mBreakData ;
SetAndRestoreValue < BfBreakData * > prevBreakData ( mCurMethodState - > mBreakData , & breakData ) ;
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > CreateBr ( condBB ) ;
2022-07-26 13:27:03 -04:00
bool isInfiniteLoop = false ;
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > SetInsertPoint ( condBB ) ;
if ( forStmt - > mCondition ! = NULL )
{
auto conditionValue = CreateValueFromExpression ( forStmt - > mCondition , boolType ) ;
if ( ! conditionValue )
2022-07-26 13:27:03 -04:00
conditionValue = GetDefaultTypedValue ( boolType ) ;
2019-08-23 11:56:54 -07:00
auto constant = mBfIRBuilder - > GetConstant ( conditionValue . mValue ) ;
if ( ( constant ! = NULL ) & & ( constant - > mTypeCode = = BfTypeCode_Boolean ) )
isInfiniteLoop = constant - > mBool ;
ValueScopeEnd ( scopeData . mValueScopeStart ) ;
mBfIRBuilder - > CreateCondBr ( conditionValue . mValue , bodyBB , endBB ) ;
}
else
{
isInfiniteLoop = true ;
mBfIRBuilder - > CreateBr ( bodyBB ) ;
}
// Apply deferred local assign to mEmbeddedStatement and itrStmt
BfDeferredLocalAssignData deferredLocalAssignData ( mCurMethodState - > mCurScope ) ;
deferredLocalAssignData . ExtendFrom ( mCurMethodState - > mDeferredLocalAssignData , false ) ;
deferredLocalAssignData . mVarIdBarrier = mCurMethodState - > GetRootMethodState ( ) - > mCurLocalVarId ;
SetAndRestoreValue < BfDeferredLocalAssignData * > prevDLA ( mCurMethodState - > mDeferredLocalAssignData , & deferredLocalAssignData ) ;
mBfIRBuilder - > AddBlock ( bodyBB ) ;
mBfIRBuilder - > SetInsertPoint ( bodyBB ) ;
if ( forStmt - > mEmbeddedStatement ! = NULL )
2022-07-26 13:27:03 -04:00
{
VisitEmbeddedStatement ( forStmt - > mEmbeddedStatement ) ;
2019-08-23 11:56:54 -07:00
}
if ( ! mCurMethodState - > mLeftBlockUncond )
mBfIRBuilder - > CreateBr ( incBB ) ;
mBfIRBuilder - > AddBlock ( incBB ) ;
mBfIRBuilder - > SetInsertPoint ( incBB ) ;
for ( auto itrStmt : forStmt - > mIterators )
{
VisitChild ( itrStmt ) ;
if ( ( mCurMethodState - > mLeftBlockUncond ) & & ( ! mCurMethodState - > mHadContinue ) & & ( ! mCurMethodState - > mInPostReturn ) )
Warn ( BfWarning_CS0162_UnreachableCode , " Unreachable code " , itrStmt ) ;
}
ValueScopeEnd ( scopeData . mValueScopeStart ) ;
mBfIRBuilder - > CreateBr ( condBB ) ;
mBfIRBuilder - > AddBlock ( endBB ) ;
2022-07-26 13:27:03 -04:00
mBfIRBuilder - > SetInsertPoint ( endBB ) ;
2019-08-23 11:56:54 -07:00
// The 'return' may have been inside the block, which may not have been entered if preconditions were not met
mCurMethodState - > SetHadReturn ( false ) ;
mCurMethodState - > mLeftBlockUncond = false ;
mCurMethodState - > mLeftBlockCond = false ;
if ( breakData . mHadBreak )
isInfiniteLoop = false ;
RestoreScopeState ( ) ;
if ( isInfiniteLoop )
EmitDefaultReturn ( ) ;
}
void BfModule : : DoForLess ( BfForEachStatement * forEachStmt )
2021-11-15 16:44:28 -08:00
{
2019-08-23 11:56:54 -07:00
UpdateSrcPos ( forEachStmt ) ;
2021-07-20 12:28:23 -07:00
auto startBB = mBfIRBuilder - > GetInsertBlock ( ) ;
auto condBB = mBfIRBuilder - > CreateBlock ( " forless.cond " , true ) ;
mBfIRBuilder - > SetInsertPoint ( condBB ) ;
2019-08-23 11:56:54 -07:00
BfScopeData scopeData ;
2022-07-26 13:27:03 -04:00
// We set mIsLoop later
2019-08-23 11:56:54 -07:00
if ( forEachStmt - > mLabelNode ! = NULL )
scopeData . mLabelNode = forEachStmt - > mLabelNode - > mLabel ;
2022-07-26 13:27:03 -04:00
mCurMethodState - > AddScope ( & scopeData ) ;
2019-08-23 11:56:54 -07:00
NewScopeState ( ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
auto autoComplete = mCompiler - > GetAutoComplete ( ) ;
auto isLet = BfNodeDynCast < BfLetTypeReference > ( forEachStmt - > mVariableTypeRef ) ! = 0 ;
auto isVar = BfNodeDynCast < BfVarTypeReference > ( forEachStmt - > mVariableTypeRef ) ! = 0 ;
2022-07-26 13:27:03 -04:00
BfTypedValue target ;
BfType * varType = NULL ;
2019-08-23 11:56:54 -07:00
bool didInference = false ;
if ( isLet | | isVar )
{
if ( forEachStmt - > mCollectionExpression ! = NULL )
target = CreateValueFromExpression ( forEachStmt - > mCollectionExpression ) ;
if ( target )
{
FixIntUnknown ( target ) ;
varType = target . mType ;
}
if ( autoComplete ! = NULL )
2022-07-26 13:27:03 -04:00
autoComplete - > CheckVarResolution ( forEachStmt - > mVariableTypeRef , varType ) ;
2019-08-23 11:56:54 -07:00
didInference = true ;
}
else
{
2022-07-26 13:27:03 -04:00
varType = ResolveTypeRef ( forEachStmt - > mVariableTypeRef , BfPopulateType_Data , BfResolveTypeRefFlag_AllowRef ) ;
2019-08-23 11:56:54 -07:00
if ( forEachStmt - > mCollectionExpression ! = NULL )
target = CreateValueFromExpression ( forEachStmt - > mCollectionExpression , varType ) ;
}
if ( varType = = NULL )
varType = GetPrimitiveType ( BfTypeCode_IntPtr ) ;
2020-09-22 07:44:47 -07:00
BfDeferredLocalAssignData deferredLocalAssignData ( mCurMethodState - > mCurScope ) ;
deferredLocalAssignData . mIsIfCondition = true ;
deferredLocalAssignData . ExtendFrom ( mCurMethodState - > mDeferredLocalAssignData , true ) ;
deferredLocalAssignData . mVarIdBarrier = mCurMethodState - > GetRootMethodState ( ) - > mCurLocalVarId ;
SetAndRestoreValue < BfDeferredLocalAssignData * > prevDLA ( mCurMethodState - > mDeferredLocalAssignData , & deferredLocalAssignData ) ;
2020-09-21 13:58:00 -07:00
deferredLocalAssignData . mIsIfCondition = false ;
2022-07-26 13:27:03 -04:00
// The "extend chain" is only valid for the conditional -- since that expression may contain unconditionally executed and
2020-09-21 13:58:00 -07:00
// conditionally executed code (in the case of "(GetVal(out a) && GetVal(out b))" for example
mCurMethodState - > mDeferredLocalAssignData - > BreakExtendChain ( ) ;
2019-10-05 11:27:30 -07:00
BfType * checkType = varType ;
if ( checkType - > IsTypedPrimitive ( ) )
checkType = checkType - > GetUnderlyingType ( ) ;
if ( ! checkType - > IsIntegral ( ) )
2019-08-23 11:56:54 -07:00
{
Fail ( StrFormat ( " Cannot iterate over '%s' in for-less statements, only integer types are allowed " , TypeToString ( varType ) . c_str ( ) ) , forEachStmt - > mVariableTypeRef ) ;
2019-10-05 11:27:30 -07:00
varType = GetPrimitiveType ( BfTypeCode_IntPtr ) ;
2019-08-23 11:56:54 -07:00
if ( didInference )
target = GetDefaultTypedValue ( varType ) ;
}
2022-07-26 13:27:03 -04:00
PopulateType ( varType , BfPopulateType_Data ) ;
2021-07-20 12:28:23 -07:00
auto condEndBB = mBfIRBuilder - > GetInsertBlock ( ) ;
mBfIRBuilder - > SetInsertPoint ( startBB ) ;
2022-07-26 13:27:03 -04:00
BfLocalVariable * localDef = new BfLocalVariable ( ) ;
2019-08-23 11:56:54 -07:00
localDef - > mNameNode = BfNodeDynCast < BfIdentifierNode > ( forEachStmt - > mVariableName ) ;
localDef - > mName = localDef - > mNameNode - > ToString ( ) ;
localDef - > mResolvedType = varType ;
BfIRValue varInst ;
if ( ! varType - > IsValuelessType ( ) )
{
2022-07-26 13:27:03 -04:00
varInst = CreateAlloca ( varType ) ;
2019-08-23 11:56:54 -07:00
}
localDef - > mAddr = varInst ;
2020-09-21 13:58:00 -07:00
localDef - > mAssignedKind = BfLocalVarAssignKind_Unconditional ;
2019-08-23 11:56:54 -07:00
localDef - > mReadFromId = 0 ;
localDef - > mIsReadOnly = isLet | | ( forEachStmt - > mReadOnlyToken ! = NULL ) ;
CheckVariableDef ( localDef ) ;
2022-04-16 13:22:32 -07:00
mBfIRBuilder - > CreateAlignedStore ( GetDefaultValue ( varType ) , localDef - > mAddr , varType - > mAlign ) ;
2019-08-23 11:56:54 -07:00
localDef - > Init ( ) ;
UpdateExprSrcPos ( forEachStmt - > mVariableName ) ;
AddLocalVariableDef ( localDef , true ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
auto bodyBB = mBfIRBuilder - > CreateBlock ( " forless.body " ) ;
auto incBB = mBfIRBuilder - > CreateBlock ( " forless.inc " ) ;
auto endBB = mBfIRBuilder - > CreateBlock ( " forless.end " ) ;
BfBreakData breakData ;
breakData . mIRContinueBlock = incBB ;
breakData . mIRBreakBlock = endBB ;
breakData . mScope = & scopeData ;
2022-07-26 13:27:03 -04:00
breakData . mPrevBreakData = mCurMethodState - > mBreakData ;
2019-08-23 11:56:54 -07:00
SetAndRestoreValue < BfBreakData * > prevBreakData ( mCurMethodState - > mBreakData , & breakData ) ;
mBfIRBuilder - > CreateBr ( condBB ) ;
2021-07-20 12:28:23 -07:00
mBfIRBuilder - > SetInsertPoint ( condEndBB ) ;
2019-08-23 11:56:54 -07:00
if ( forEachStmt - > mCollectionExpression ! = NULL )
UpdateExprSrcPos ( forEachStmt - > mCollectionExpression ) ;
BfIRValue conditionValue ;
// We may have a call in the loop body
mCurMethodState - > mMayNeedThisAccessCheck = true ;
// Cond
auto valueScopeStart = ValueScopeStart ( ) ;
2022-04-16 13:22:32 -07:00
auto localVal = mBfIRBuilder - > CreateAlignedLoad ( localDef - > mAddr , localDef - > mResolvedType - > mAlign ) ;
2019-08-23 11:56:54 -07:00
if ( ! target )
{
// Soldier on
target = GetDefaultTypedValue ( varType ) ;
}
2019-10-05 11:27:30 -07:00
if ( forEachStmt - > mInToken - > mToken = = BfToken_LessEquals )
conditionValue = mBfIRBuilder - > CreateCmpLTE ( localVal , target . mValue , varType - > IsSigned ( ) ) ;
else
conditionValue = mBfIRBuilder - > CreateCmpLT ( localVal , target . mValue , varType - > IsSigned ( ) ) ;
2022-07-26 13:27:03 -04:00
mBfIRBuilder - > CreateCondBr ( conditionValue , bodyBB , endBB ) ;
2019-08-23 11:56:54 -07:00
ValueScopeEnd ( valueScopeStart ) ;
mBfIRBuilder - > AddBlock ( bodyBB ) ;
mBfIRBuilder - > SetInsertPoint ( bodyBB ) ;
// Body
scopeData . mIsLoop = true ;
if ( forEachStmt - > mEmbeddedStatement ! = NULL )
2022-07-26 13:27:03 -04:00
{
VisitEmbeddedStatement ( forEachStmt - > mEmbeddedStatement ) ;
2019-08-23 11:56:54 -07:00
}
// Inc
if ( ! mCurMethodState - > mLeftBlockUncond )
{
mBfIRBuilder - > CreateBr ( incBB ) ;
}
mBfIRBuilder - > AddBlock ( incBB ) ;
mBfIRBuilder - > SetInsertPoint ( incBB ) ;
if ( forEachStmt - > mCollectionExpression ! = NULL )
UpdateExprSrcPos ( forEachStmt - > mCollectionExpression ) ;
auto one = GetConstValue ( 1 , localDef - > mResolvedType ) ;
// We have to reload localVal before the inc, user logic could have changed it
2022-04-16 13:22:32 -07:00
localVal = mBfIRBuilder - > CreateAlignedLoad ( localDef - > mAddr , localDef - > mResolvedType - > mAlign ) ;
2019-08-23 11:56:54 -07:00
auto result = mBfIRBuilder - > CreateAdd ( localVal , one ) ;
2022-04-16 13:22:32 -07:00
mBfIRBuilder - > CreateAlignedStore ( result , localDef - > mAddr , localDef - > mResolvedType - > mAlign ) ;
2019-08-23 11:56:54 -07:00
ValueScopeEnd ( valueScopeStart ) ;
2022-07-26 13:27:03 -04:00
mBfIRBuilder - > CreateBr ( condBB ) ;
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > AddBlock ( endBB ) ;
2022-07-26 13:27:03 -04:00
mBfIRBuilder - > SetInsertPoint ( endBB ) ;
2019-08-23 11:56:54 -07:00
// The 'return' may have been inside the block, which may not have been entered if preconditions were not met
mCurMethodState - > SetHadReturn ( false ) ;
mCurMethodState - > mLeftBlockUncond = false ;
mCurMethodState - > mLeftBlockCond = false ;
2022-07-26 13:27:03 -04:00
2020-09-22 07:44:47 -07:00
bool definitelyExecuted = false ;
if ( target . mValue . IsConst ( ) )
{
auto constant = mBfIRBuilder - > GetConstant ( target . mValue ) ;
if ( constant - > mInt32 > 0 )
definitelyExecuted = true ;
}
prevDLA . Restore ( ) ;
if ( definitelyExecuted )
mCurMethodState - > ApplyDeferredLocalAssignData ( deferredLocalAssignData ) ;
2019-08-23 11:56:54 -07:00
RestoreScopeState ( ) ;
}
void BfModule : : Visit ( BfForEachStatement * forEachStmt )
2022-07-26 13:27:03 -04:00
{
if ( ( forEachStmt - > mInToken ! = NULL ) & &
2019-10-05 11:27:30 -07:00
( ( forEachStmt - > mInToken - > GetToken ( ) = = BfToken_LChevron ) | | ( forEachStmt - > mInToken - > GetToken ( ) = = BfToken_LessEquals ) ) )
2019-08-23 11:56:54 -07:00
{
DoForLess ( forEachStmt ) ;
return ;
}
auto autoComplete = mCompiler - > GetAutoComplete ( ) ;
2022-07-26 13:27:03 -04:00
UpdateSrcPos ( forEachStmt ) ;
2019-08-23 11:56:54 -07:00
2021-05-31 07:01:56 -07:00
BfScopeData scopeData ;
2022-07-26 13:27:03 -04:00
// We set mIsLoop after the non-looped initializations
2019-08-23 11:56:54 -07:00
scopeData . mValueScopeStart = ValueScopeStart ( ) ;
mCurMethodState - > AddScope ( & scopeData ) ;
NewScopeState ( ) ;
bool isRefExpression = false ;
BfExpression * collectionExpr = forEachStmt - > mCollectionExpression ;
if ( auto unaryOpExpr = BfNodeDynCast < BfUnaryOperatorExpression > ( collectionExpr ) )
{
if ( ( unaryOpExpr - > mOp = = BfUnaryOp_Ref ) | | ( unaryOpExpr - > mOp = = BfUnaryOp_Mut ) )
{
isRefExpression = true ;
collectionExpr = unaryOpExpr - > mExpression ;
}
}
BfTypedValue target ;
2021-11-06 07:26:37 -07:00
if ( collectionExpr ! = NULL )
2019-08-23 11:56:54 -07:00
target = CreateValueFromExpression ( collectionExpr ) ;
if ( ! target )
{
// Soldier on
target = BfTypedValue ( GetDefaultValue ( mContext - > mBfObjectType ) , mContext - > mBfObjectType ) ;
}
bool isLet = ( forEachStmt - > mVariableTypeRef ! = NULL ) & & ( forEachStmt - > mVariableTypeRef - > IsA < BfLetTypeReference > ( ) ) ;
BfType * varType = NULL ;
2022-07-26 13:27:03 -04:00
bool inferVarType = false ;
2019-08-23 11:56:54 -07:00
if ( ( forEachStmt - > mVariableTypeRef = = NULL ) | | ( forEachStmt - > mVariableTypeRef - > IsA < BfVarTypeReference > ( ) ) | | ( isLet ) )
{
if ( target . mType - > IsSizedArray ( ) )
{
varType = target . mType - > GetUnderlyingType ( ) ;
if ( isRefExpression )
varType = CreateRefType ( varType ) ;
}
else if ( target . mType - > IsArray ( ) )
{
varType = target . mType - > GetUnderlyingType ( ) ;
if ( isRefExpression )
varType = CreateRefType ( varType ) ;
}
else
inferVarType = true ;
}
else
{
if ( autoComplete ! = NULL )
autoComplete - > CheckTypeRef ( forEachStmt - > mVariableTypeRef , false ) ;
varType = ResolveTypeRef ( forEachStmt - > mVariableTypeRef , BfPopulateType_Data , BfResolveTypeRefFlag_AllowRef ) ;
}
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
if ( varType = = NULL )
2022-02-16 18:28:23 -05:00
varType = GetPrimitiveType ( BfTypeCode_Var ) ;
2019-08-23 11:56:54 -07:00
bool isArray = target . mType - > IsArray ( ) ;
bool isSizedArray = target . mType - > IsSizedArray ( ) ;
bool isVarEnumerator = target . mType - > IsVar ( ) ;
// Array
BfType * itrType ;
BfTypedValue itr ;
BfTypeInstance * itrInterface = NULL ;
2022-07-26 13:27:03 -04:00
BfTypeInstance * refItrInterface = NULL ;
2019-08-23 11:56:54 -07:00
if ( isVarEnumerator )
varType = GetPrimitiveType ( BfTypeCode_Var ) ;
2020-06-03 05:23:20 -07:00
BfGenericParamInstance * genericParamInst = NULL ;
2019-08-23 11:56:54 -07:00
if ( target . mType - > IsGenericParam ( ) )
{
2020-06-03 05:23:20 -07:00
genericParamInst = GetGenericParamInstance ( ( BfGenericParamType * ) target . mType ) ;
2019-08-23 11:56:54 -07:00
if ( ( genericParamInst - > mGenericParamFlags & BfGenericParamFlag_Var ) ! = 0 )
{
varType = GetPrimitiveType ( BfTypeCode_Var ) ;
isVarEnumerator = true ;
}
if ( genericParamInst - > mTypeConstraint ! = NULL )
{
if ( genericParamInst - > mTypeConstraint - > IsVar ( ) )
{
varType = GetPrimitiveType ( BfTypeCode_Var ) ;
isVarEnumerator = true ;
}
if ( genericParamInst - > mTypeConstraint - > IsGenericTypeInstance ( ) )
{
2022-07-26 13:27:03 -04:00
auto genericConstraintType = ( BfTypeInstance * ) genericParamInst - > mTypeConstraint ;
2021-10-28 08:05:14 -07:00
if ( genericConstraintType - > IsInstanceOf ( mCompiler - > mSizedArrayTypeDef ) )
2019-08-23 11:56:54 -07:00
{
2020-06-05 07:01:58 -07:00
varType = genericConstraintType - > mGenericTypeInfo - > mTypeGenericArguments [ 0 ] ;
2019-08-23 11:56:54 -07:00
isVarEnumerator = true ;
2022-07-26 13:27:03 -04:00
}
}
}
2019-08-23 11:56:54 -07:00
}
2021-01-15 15:01:45 -08:00
if ( target . mType - > IsConcreteInterfaceType ( ) )
target . mType = target . mType - > GetUnderlyingType ( ) ;
2019-08-23 11:56:54 -07:00
if ( isArray | | isSizedArray )
{
itrType = GetPrimitiveType ( BfTypeCode_IntPtr ) ;
2022-07-26 13:27:03 -04:00
BfIRValue itrInst = CreateAlloca ( itrType ) ;
2019-08-23 11:56:54 -07:00
itr = BfTypedValue ( itrInst , itrType , true ) ;
}
else if ( isVarEnumerator )
{
2022-07-26 13:27:03 -04:00
// Generic method or mixin decl
}
2020-06-03 05:23:20 -07:00
else if ( ( ! target . mType - > IsTypeInstance ( ) ) & & ( genericParamInst = = NULL ) )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
Fail ( StrFormat ( " Type '%s' cannot be used in enumeration " , TypeToString ( target . mType ) . c_str ( ) ) , forEachStmt - > mCollectionExpression ) ;
}
else if ( forEachStmt - > mCollectionExpression ! = NULL )
{
2022-07-26 13:27:03 -04:00
auto targetTypeInstance = target . mType - > ToTypeInstance ( ) ;
2019-08-23 11:56:54 -07:00
itr = target ;
2020-06-04 11:46:02 -07:00
bool hadGetEnumeratorType = false ;
2020-06-03 05:23:20 -07:00
2021-01-13 09:24:15 -08:00
if ( genericParamInst ! = NULL )
2022-07-26 13:27:03 -04:00
{
2021-01-13 09:24:15 -08:00
for ( auto ifaceConstraint : genericParamInst - > mInterfaceConstraints )
{
if ( ifaceConstraint - > IsInstanceOf ( mCompiler - > mGenericIEnumerableTypeDef ) )
{
if ( targetTypeInstance ! = NULL )
{
targetTypeInstance = NULL ;
break ;
}
2022-07-26 13:27:03 -04:00
targetTypeInstance = ifaceConstraint - > ToTypeInstance ( ) ;
2021-01-13 09:24:15 -08:00
}
}
}
2020-06-03 05:23:20 -07:00
if ( targetTypeInstance ! = NULL )
2019-08-23 11:56:54 -07:00
{
2020-06-03 05:23:20 -07:00
PopulateType ( targetTypeInstance , BfPopulateType_DataAndMethods ) ;
2022-06-27 15:39:50 -07:00
2020-06-03 05:23:20 -07:00
auto getEnumeratorMethod = GetMethodByName ( targetTypeInstance , " GetEnumerator " , 0 , true ) ;
if ( ! getEnumeratorMethod )
{
hadGetEnumeratorType = false ;
}
else if ( getEnumeratorMethod . mMethodInstance - > mMethodDef - > mIsStatic )
{
hadGetEnumeratorType = true ;
Fail ( StrFormat ( " Type '%s' does not contain a non-static 'GetEnumerator' method " , TypeToString ( targetTypeInstance ) . c_str ( ) ) , forEachStmt - > mCollectionExpression ) ;
2022-07-26 13:27:03 -04:00
}
2020-06-03 05:23:20 -07:00
else
{
2021-01-13 09:24:15 -08:00
if ( getEnumeratorMethod . mMethodInstance - > mMethodDef - > mIsConcrete )
{
hadGetEnumeratorType = true ;
if ( genericParamInst ! = NULL )
{
if ( ( genericParamInst - > mGenericParamFlags & BfGenericParamFlag_Concrete ) = = 0 )
Fail ( StrFormat ( " Iteration requires a concrete implementation of '%s', consider adding 'concrete' constraint to '%s' " , TypeToString ( targetTypeInstance ) . c_str ( ) , genericParamInst - > GetName ( ) . c_str ( ) ) , forEachStmt - > mCollectionExpression ) ;
}
else
Fail ( StrFormat ( " Iteration requires a concrete implementation of '%s' " , TypeToString ( targetTypeInstance ) . c_str ( ) ) , forEachStmt - > mCollectionExpression ) ;
}
2020-06-03 05:23:20 -07:00
hadGetEnumeratorType = true ;
BfExprEvaluator exprEvaluator ( this ) ;
SizedArray < BfIRValue , 1 > args ;
auto castedTarget = Cast ( forEachStmt - > mCollectionExpression , target , getEnumeratorMethod . mMethodInstance - > GetOwner ( ) ) ;
exprEvaluator . PushThis ( forEachStmt - > mCollectionExpression , castedTarget , getEnumeratorMethod . mMethodInstance , args ) ;
2020-12-14 03:50:28 -08:00
itr = exprEvaluator . CreateCall ( forEachStmt - > mCollectionExpression , getEnumeratorMethod . mMethodInstance , IsSkippingExtraResolveChecks ( ) ? BfIRValue ( ) : getEnumeratorMethod . mFunc , false , args ) ;
2021-01-13 09:24:15 -08:00
if ( itr . mType - > IsConcreteInterfaceType ( ) )
itr . mType = itr . mType - > GetUnderlyingType ( ) ;
2020-06-03 05:23:20 -07:00
}
2019-08-23 11:56:54 -07:00
}
if ( itr )
{
PopulateType ( itr . mType , BfPopulateType_DataAndMethods ) ;
2020-06-05 07:01:58 -07:00
BfTypeInstance * genericItrInterface = NULL ;
2020-06-03 05:23:20 -07:00
auto _CheckInterface = [ & ] ( BfTypeInstance * interface )
2019-08-23 11:56:54 -07:00
{
2021-10-28 08:05:14 -07:00
if ( interface - > IsInstanceOf ( isRefExpression ? mCompiler - > mGenericIRefEnumeratorTypeDef : mCompiler - > mGenericIEnumeratorTypeDef ) )
2019-08-23 11:56:54 -07:00
{
2020-06-03 05:23:20 -07:00
if ( genericItrInterface ! = NULL )
2019-08-23 11:56:54 -07:00
{
2020-06-03 05:23:20 -07:00
Fail ( StrFormat ( " Type '%s' implements multiple %s<T> interfaces " , TypeToString ( itr . mType ) . c_str ( ) , isRefExpression ? " IRefEnumerator " : " IEnumerator " ) , forEachStmt - > mCollectionExpression ) ;
}
2019-08-23 11:56:54 -07:00
2020-06-03 05:23:20 -07:00
itrInterface = interface ;
genericItrInterface = itrInterface - > ToGenericTypeInstance ( ) ;
if ( inferVarType )
{
2020-06-05 07:01:58 -07:00
varType = genericItrInterface - > mGenericTypeInfo - > mTypeGenericArguments [ 0 ] ;
2020-06-03 05:23:20 -07:00
if ( isRefExpression )
2019-08-23 11:56:54 -07:00
{
2020-06-03 05:23:20 -07:00
if ( varType - > IsPointer ( ) )
varType = CreateRefType ( varType - > GetUnderlyingType ( ) ) ;
2019-08-23 11:56:54 -07:00
}
}
}
2020-06-03 05:23:20 -07:00
} ;
auto enumeratorTypeInst = itr . mType - > ToTypeInstance ( ) ;
2022-06-27 15:39:50 -07:00
while ( enumeratorTypeInst ! = NULL )
2020-06-03 05:23:20 -07:00
{
2022-06-27 15:39:50 -07:00
PopulateType ( enumeratorTypeInst , Beefy : : BfPopulateType_Interfaces_All ) ;
2020-06-03 05:23:20 -07:00
for ( auto & interfaceRef : enumeratorTypeInst - > mInterfaces )
{
BfTypeInstance * interface = interfaceRef . mInterfaceType ;
2022-07-26 13:27:03 -04:00
_CheckInterface ( interface ) ;
2020-06-03 05:23:20 -07:00
}
2019-08-23 11:56:54 -07:00
2021-10-28 08:05:14 -07:00
if ( enumeratorTypeInst - > IsInstanceOf ( isRefExpression ? mCompiler - > mGenericIRefEnumeratorTypeDef : mCompiler - > mGenericIEnumeratorTypeDef ) )
2019-08-23 11:56:54 -07:00
{
itrInterface = enumeratorTypeInst ;
genericItrInterface = itrInterface - > ToGenericTypeInstance ( ) ;
if ( inferVarType )
{
2020-06-05 07:01:58 -07:00
varType = genericItrInterface - > mGenericTypeInfo - > mTypeGenericArguments [ 0 ] ;
2019-08-23 11:56:54 -07:00
if ( isRefExpression )
2020-05-01 16:29:12 -07:00
{
if ( varType - > IsPointer ( ) )
varType = CreateRefType ( varType ) ;
}
2019-08-23 11:56:54 -07:00
}
2022-06-27 15:39:50 -07:00
break ;
2019-08-23 11:56:54 -07:00
}
2022-06-27 15:39:50 -07:00
2022-07-06 06:30:12 -07:00
if ( itrInterface ! = NULL )
break ;
2022-06-27 15:39:50 -07:00
enumeratorTypeInst = enumeratorTypeInst - > mBaseType ;
2019-08-23 11:56:54 -07:00
}
2020-06-03 05:23:20 -07:00
if ( ( genericItrInterface = = NULL ) & & ( genericParamInst ! = NULL ) )
{
for ( auto interface : genericParamInst - > mInterfaceConstraints )
_CheckInterface ( interface ) ;
}
2019-08-23 11:56:54 -07:00
if ( genericItrInterface = = NULL )
{
if ( ! hadGetEnumeratorType )
{
2020-06-03 05:23:20 -07:00
Fail ( StrFormat ( " Type '%s' must contain a 'GetEnumerator' method or implement an IEnumerator<T> interface " , TypeToString ( target . mType ) . c_str ( ) ) , forEachStmt - > mCollectionExpression ) ;
2019-08-23 11:56:54 -07:00
}
else
Fail ( StrFormat ( " Enumerator type '%s' must implement an %s<T> interface " , TypeToString ( itr . mType ) . c_str ( ) , isRefExpression ? " IRefEnumerator " : " IEnumerator " ) , forEachStmt - > mCollectionExpression ) ;
itrInterface = NULL ;
itr = BfTypedValue ( ) ;
}
else
{
itrInterface = genericItrInterface ;
if ( isRefExpression )
{
refItrInterface = itrInterface ;
PopulateType ( refItrInterface ) ;
// Must IRefEnumeratorf<T> must include only IEnumerator<T>
2020-05-01 16:29:12 -07:00
// BF_ASSERT(refItrInterface->mInterfaces.size() == 1);
// if (refItrInterface->mInterfaces.size() == 1)
// itrInterface = refItrInterface->mInterfaces[0].mInterfaceType;
2019-08-23 11:56:54 -07:00
}
itr = MakeAddressable ( itr ) ;
itr = RemoveReadOnly ( itr ) ;
}
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
}
else
2022-07-26 13:27:03 -04:00
{
AssertErrorState ( ) ;
2019-08-23 11:56:54 -07:00
}
PopulateType ( varType , BfPopulateType_Data ) ;
// Apply deferred local assign to mEmbeddedStatement and itrStmt
BfDeferredLocalAssignData deferredLocalAssignData ( mCurMethodState - > mCurScope ) ;
deferredLocalAssignData . ExtendFrom ( mCurMethodState - > mDeferredLocalAssignData , false ) ;
deferredLocalAssignData . mVarIdBarrier = mCurMethodState - > GetRootMethodState ( ) - > mCurLocalVarId ;
SetAndRestoreValue < BfDeferredLocalAssignData * > prevDLA ( mCurMethodState - > mDeferredLocalAssignData , & deferredLocalAssignData ) ;
2021-01-19 05:40:15 -08:00
SetAndRestoreValue < bool > prevIgnoreWrites ( mBfIRBuilder - > mIgnoreWrites ) ;
2019-08-23 11:56:54 -07:00
if ( ( target . mType - > IsSizedArray ( ) ) & & ( ( ( BfSizedArrayType * ) target . mType ) - > mElementCount = = 0 ) )
{
EmitEnsureInstructionAt ( ) ;
2021-01-19 05:40:15 -08:00
mBfIRBuilder - > mIgnoreWrites = true ;
2019-08-23 11:56:54 -07:00
}
BfIdentifierNode * nameNode = NULL ;
String variableName ;
struct _TupleBind
{
BfIdentifierNode * mNameNode ;
2022-07-26 13:27:03 -04:00
String mName ;
2019-08-23 11:56:54 -07:00
BfType * mType ;
BfLocalVariable * mVariable ;
} ;
Array < _TupleBind > tupleBinds ;
if ( forEachStmt - > mVariableName ! = NULL )
{
if ( auto tupleExpr = BfNodeDynCast < BfTupleExpression > ( forEachStmt - > mVariableName ) )
{
CheckTupleVariableDeclaration ( tupleExpr , varType ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
if ( varType - > IsTuple ( ) )
{
2020-06-04 15:02:46 -07:00
auto tupleType = ( BfTypeInstance * ) varType ;
2019-08-23 11:56:54 -07:00
for ( int idx = 0 ; idx < BF_MIN ( ( int ) tupleExpr - > mValues . size ( ) , ( int ) tupleType - > mFieldInstances . size ( ) ) ; idx + + )
2022-07-26 13:27:03 -04:00
{
auto nameNode = tupleExpr - > mValues [ idx ] ;
2019-08-23 11:56:54 -07:00
_TupleBind tupleBind ;
tupleBind . mNameNode = BfNodeDynCast < BfIdentifierNode > ( nameNode ) ;
if ( ( tupleBind . mNameNode = = NULL ) & & ( nameNode ! = NULL ) )
{
Fail ( " Variable name expected " , nameNode ) ;
}
tupleBind . mName = nameNode - > ToString ( ) ;
tupleBind . mType = tupleType - > mFieldInstances [ idx ] . mResolvedType ;
tupleBind . mVariable = NULL ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
tupleBinds . Add ( tupleBind ) ;
if ( idx = = 0 )
variableName = tupleBind . mName ;
}
}
}
else
{
nameNode = BfNodeDynCast < BfIdentifierNode > ( forEachStmt - > mVariableName ) ;
if ( nameNode ! = NULL )
variableName = nameNode - > ToString ( ) ;
}
}
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
if ( variableName . IsEmpty ( ) )
variableName = " _ " ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
BfModuleMethodInstance getNextMethodInst ;
2020-03-20 09:24:08 -07:00
BfType * nextEmbeddedType = NULL ;
2019-08-23 11:56:54 -07:00
BfTypedValue nextResult ;
if ( ( refItrInterface ) | | ( itrInterface ) )
{
if ( isRefExpression )
{
PopulateType ( refItrInterface , BfPopulateType_Full_Force ) ;
getNextMethodInst = GetMethodByName ( refItrInterface , " GetNextRef " ) ;
}
else
{
PopulateType ( itrInterface , BfPopulateType_Full_Force ) ;
getNextMethodInst = GetMethodByName ( itrInterface , " GetNext " ) ;
}
2024-03-16 07:23:29 -04:00
if ( getNextMethodInst )
{
nextResult = BfTypedValue ( CreateAlloca ( getNextMethodInst . mMethodInstance - > mReturnType ) , getNextMethodInst . mMethodInstance - > mReturnType , true ) ;
2020-03-20 09:24:08 -07:00
2024-03-16 07:23:29 -04:00
if ( nextResult . mType - > IsGenericTypeInstance ( ) )
{
nextEmbeddedType = ( ( BfTypeInstance * ) nextResult . mType ) - > mGenericTypeInfo - > mTypeGenericArguments [ 0 ] ;
}
}
else
2020-03-20 09:24:08 -07:00
{
2024-03-16 07:23:29 -04:00
InternalError ( " Failed to find GetNext " ) ;
2020-03-20 09:24:08 -07:00
}
2019-08-23 11:56:54 -07:00
}
2020-03-20 09:24:08 -07:00
if ( nextEmbeddedType = = NULL )
2022-02-16 18:28:23 -05:00
nextEmbeddedType = GetPrimitiveType ( BfTypeCode_Var ) ;
2019-08-23 11:56:54 -07:00
BfLocalVariable * itrLocalDef = NULL ;
// Iterator local def
if ( itr )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
BfLocalVariable * localDef = new BfLocalVariable ( ) ;
itrLocalDef = localDef ;
2022-07-26 13:27:03 -04:00
localDef - > mNameNode = nameNode ;
localDef - > mName = variableName ;
2019-08-23 11:56:54 -07:00
localDef - > mResolvedType = itr . mType ;
localDef - > mAddr = itr . mValue ;
2020-09-21 13:58:00 -07:00
localDef - > mAssignedKind = BfLocalVarAssignKind_Unconditional ;
2022-07-26 13:27:03 -04:00
localDef - > mReadFromId = 0 ;
2021-05-31 07:01:56 -07:00
localDef - > Init ( ) ;
2019-08-23 11:56:54 -07:00
UpdateSrcPos ( forEachStmt ) ;
CheckVariableDef ( localDef ) ;
2022-07-26 13:27:03 -04:00
AddLocalVariableDef ( localDef , true ) ;
2019-08-23 11:56:54 -07:00
}
BfIRValue varInst ;
BfTypedValue varTypedVal ;
bool needsValCopy = true ;
2022-07-26 13:27:03 -04:00
2024-10-13 10:22:54 -04:00
BfType * origVarType = varType ;
2019-08-23 11:56:54 -07:00
// Local variable
{
if ( ! tupleBinds . IsEmpty ( ) )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
BF_ASSERT ( varType - > IsTuple ( ) ) ;
2020-06-04 15:02:46 -07:00
auto tupleType = ( BfTypeInstance * ) varType ;
2019-08-23 11:56:54 -07:00
2022-07-26 13:27:03 -04:00
// Tuple binds
2019-08-23 11:56:54 -07:00
needsValCopy = false ;
if ( ! nextResult )
{
varInst = CreateAlloca ( varType ) ;
varTypedVal = BfTypedValue ( varInst , varType , true ) ;
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
// Local
2022-07-26 13:27:03 -04:00
for ( int idx = 0 ; idx < ( int ) tupleBinds . size ( ) ; idx + + )
{
2019-08-23 11:56:54 -07:00
auto & tupleBind = tupleBinds [ idx ] ;
BfLocalVariable * localDef = new BfLocalVariable ( ) ;
localDef - > mNameNode = tupleBind . mNameNode ;
localDef - > mName = tupleBind . mName ;
localDef - > mResolvedType = tupleBind . mType ;
if ( ! needsValCopy )
localDef - > mResolvedType = CreateRefType ( localDef - > mResolvedType ) ;
localDef - > mAddr = CreateAlloca ( localDef - > mResolvedType ) ;
2020-09-21 13:58:00 -07:00
localDef - > mAssignedKind = BfLocalVarAssignKind_Unconditional ;
2019-08-23 11:56:54 -07:00
localDef - > mReadFromId = 0 ;
if ( ( isLet ) | | ( forEachStmt - > mReadOnlyToken ! = NULL ) )
localDef - > mIsReadOnly = true ;
localDef - > Init ( ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
auto fieldInstance = & tupleType - > mFieldInstances [ idx ] ;
if ( fieldInstance - > mDataIdx > = 0 )
{
auto tuplePtrType = CreatePointerType ( varType ) ;
BfIRValue tuplePtr ;
if ( nextResult )
tuplePtr = mBfIRBuilder - > CreateBitCast ( nextResult . mValue , mBfIRBuilder - > MapType ( tuplePtrType ) ) ;
else
tuplePtr = mBfIRBuilder - > CreateBitCast ( varInst , mBfIRBuilder - > MapType ( tuplePtrType ) ) ;
auto valAddr = mBfIRBuilder - > CreateInBoundsGEP ( tuplePtr , 0 , fieldInstance - > mDataIdx ) ;
2022-04-16 13:22:32 -07:00
mBfIRBuilder - > CreateAlignedStore ( valAddr , localDef - > mAddr , localDef - > mResolvedType - > mAlign ) ;
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
UpdateSrcPos ( forEachStmt ) ;
if ( ( itrLocalDef ! = NULL ) & & ( idx = = 0 ) )
{
localDef - > mLocalVarId = itrLocalDef - > mLocalVarId ;
localDef - > mIsShadow = true ;
}
else
{
CheckVariableDef ( localDef ) ;
}
AddLocalVariableDef ( localDef , true , false , BfIRValue ( ) , BfIRInitType_NotNeeded_AliveOnDecl ) ;
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
}
else
{
2022-07-26 13:27:03 -04:00
// Normal case
2023-05-30 09:16:24 -04:00
if ( ( nextResult ) & & ( varType - > IsComposite ( ) ) & & ( ! varType - > IsValuelessType ( ) ) & & ( ! isRefExpression ) )
2019-08-23 11:56:54 -07:00
{
needsValCopy = false ;
varType = CreateRefType ( varType ) ;
}
// Local
BfLocalVariable * localDef = new BfLocalVariable ( ) ;
localDef - > mNameNode = nameNode ;
localDef - > mName = variableName ;
localDef - > mResolvedType = varType ;
2023-05-30 09:16:24 -04:00
if ( ! varType - > IsValuelessType ( ) )
varInst = CreateAlloca ( varType ) ;
else
varInst = mBfIRBuilder - > GetFakeVal ( ) ;
2019-08-23 11:56:54 -07:00
localDef - > mAddr = varInst ;
2020-09-21 13:58:00 -07:00
localDef - > mAssignedKind = BfLocalVarAssignKind_Unconditional ;
2019-08-23 11:56:54 -07:00
localDef - > mReadFromId = 0 ;
if ( ( isLet ) | | ( forEachStmt - > mReadOnlyToken ! = NULL ) )
localDef - > mIsReadOnly = true ;
localDef - > Init ( ) ;
if ( ! needsValCopy )
{
auto valAddr = mBfIRBuilder - > CreateBitCast ( nextResult . mValue , mBfIRBuilder - > MapType ( varType ) ) ;
2022-04-16 13:22:32 -07:00
mBfIRBuilder - > CreateAlignedStore ( valAddr , varInst , varType - > mAlign ) ;
2019-08-23 11:56:54 -07:00
}
UpdateSrcPos ( forEachStmt ) ;
if ( itrLocalDef ! = NULL )
{
localDef - > mLocalVarId = itrLocalDef - > mLocalVarId ;
localDef - > mIsShadow = true ;
}
else
{
CheckVariableDef ( localDef ) ;
}
AddLocalVariableDef ( localDef , true , false , BfIRValue ( ) , BfIRInitType_NotNeeded_AliveOnDecl ) ;
varTypedVal = BfTypedValue ( varInst , varType , true ) ;
}
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
// Iterator
if ( itr )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
if ( ( ! isArray ) & & ( ! isSizedArray ) )
{
BfFunctionBindResult functionBindResult ;
BfExprEvaluator exprEvaluator ( this ) ;
exprEvaluator . mFunctionBindResult = & functionBindResult ;
// Allow for "Dispose" not to exist
2022-07-26 13:27:03 -04:00
SetAndRestoreValue < bool > prevIgnoreErrors ( mIgnoreErrors , true ) ;
2019-08-23 11:56:54 -07:00
BfResolvedArgs resolvedArgs ;
2020-11-30 09:56:43 -08:00
exprEvaluator . mBfEvalExprFlags = ( BfEvalExprFlags ) ( exprEvaluator . mBfEvalExprFlags | BfEvalExprFlags_NoAutoComplete ) ;
2022-02-05 13:47:19 -05:00
exprEvaluator . MatchMethod ( forEachStmt - > mCollectionExpression , NULL , itr , false , false , " Dispose " , resolvedArgs , BfMethodGenericArguments ( ) ) ;
2019-08-23 11:56:54 -07:00
if ( functionBindResult . mMethodInstance ! = NULL )
{
BfModuleMethodInstance moduleMethodInstance ;
moduleMethodInstance = BfModuleMethodInstance ( functionBindResult . mMethodInstance , functionBindResult . mFunc ) ;
AddDeferredCall ( moduleMethodInstance , functionBindResult . mIRArgs , mCurMethodState - > mCurScope ) ;
}
}
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
2021-05-31 07:01:56 -07:00
BfScopeData innerScopeData ;
2021-05-31 07:30:33 -07:00
if ( forEachStmt - > mLabelNode ! = NULL )
innerScopeData . mLabelNode = forEachStmt - > mLabelNode - > mLabel ;
2021-05-31 07:01:56 -07:00
innerScopeData . mValueScopeStart = ValueScopeStart ( ) ;
mCurMethodState - > AddScope ( & innerScopeData ) ;
NewScopeState ( true , false ) ;
innerScopeData . mIsLoop = true ;
2019-08-23 11:56:54 -07:00
2020-01-06 13:49:35 -08:00
if ( ( autoComplete ! = NULL ) & & ( forEachStmt - > mVariableTypeRef ! = NULL ) )
2024-10-13 10:22:54 -04:00
autoComplete - > CheckVarResolution ( forEachStmt - > mVariableTypeRef , origVarType ) ;
2020-01-06 13:49:35 -08:00
2022-07-26 13:27:03 -04:00
if ( isArray | | isSizedArray )
mBfIRBuilder - > CreateAlignedStore ( GetConstValue ( 0 ) , itr . mValue , itr . mType - > mAlign ) ;
2019-08-23 11:56:54 -07:00
2021-05-31 07:01:56 -07:00
auto valueScopeStartInner = ValueScopeStart ( ) ;
2019-08-23 11:56:54 -07:00
// We may have a call in the loop body
mCurMethodState - > mMayNeedThisAccessCheck = true ;
auto condBB = mBfIRBuilder - > CreateBlock ( " foreach.cond " , true ) ;
auto bodyBB = mBfIRBuilder - > CreateBlock ( " foreach.body " ) ;
auto incBB = mBfIRBuilder - > CreateBlock ( " foreach.inc " ) ;
auto endBB = mBfIRBuilder - > CreateBlock ( " foreach.end " ) ;
BfBreakData breakData ;
breakData . mIRContinueBlock = incBB ;
breakData . mIRBreakBlock = endBB ;
2021-05-31 07:01:56 -07:00
breakData . mScope = & innerScopeData ;
2019-08-23 11:56:54 -07:00
breakData . mInnerValueScopeStart = valueScopeStartInner ;
2022-07-26 13:27:03 -04:00
breakData . mPrevBreakData = mCurMethodState - > mBreakData ;
2019-08-23 11:56:54 -07:00
SetAndRestoreValue < BfBreakData * > prevBreakData ( mCurMethodState - > mBreakData , & breakData ) ;
mBfIRBuilder - > CreateBr ( condBB ) ;
mBfIRBuilder - > SetInsertPoint ( condBB ) ;
if ( forEachStmt - > mCollectionExpression ! = NULL )
UpdateExprSrcPos ( forEachStmt - > mCollectionExpression ) ;
BfIRValue conditionValue ;
if ( isSizedArray ) // if (i < lengthof(array)
{
auto itrVal = mBfIRBuilder - > CreateLoad ( itr . mValue ) ;
auto arrayType = ( BfSizedArrayType * ) target . mType ;
2022-07-26 13:27:03 -04:00
PopulateType ( arrayType , BfPopulateType_DataAndMethods ) ;
2019-08-23 11:56:54 -07:00
BfIRValue lengthVal = GetConstValue ( arrayType - > mElementCount ) ;
2022-07-26 13:27:03 -04:00
conditionValue = mBfIRBuilder - > CreateCmpLT ( itrVal , lengthVal , true ) ;
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > CreateCondBr ( conditionValue , bodyBB , endBB ) ;
ValueScopeEnd ( valueScopeStartInner ) ;
}
else if ( isArray ) // if (i < array.mLength)
2022-07-26 13:27:03 -04:00
{
2022-04-16 13:22:32 -07:00
auto itrVal = mBfIRBuilder - > CreateAlignedLoad ( itr . mValue , itr . mType - > mAlign ) ;
2022-07-26 13:27:03 -04:00
auto arrayType = ( BfArrayType * ) target . mType ;
2019-08-23 11:56:54 -07:00
PopulateType ( arrayType ) ;
auto arrayBaseValue = mBfIRBuilder - > CreateBitCast ( target . mValue , mBfIRBuilder - > MapType ( arrayType - > mBaseType , BfIRPopulateType_Full ) ) ;
int getLengthBitCount = arrayType - > GetLengthBitCount ( ) ;
BfIRValue lengthVal ;
if ( arrayType - > mBaseType - > mTypeFailed )
{
AssertErrorState ( ) ;
if ( getLengthBitCount = = 64 )
lengthVal = GetConstValue64 ( 0 ) ;
else
lengthVal = GetConstValue32 ( 0 ) ;
}
else
{
2022-04-16 13:22:32 -07:00
auto fieldInst = GetFieldInstance ( arrayType - > mBaseType , 0 , " mLength " ) ;
if ( fieldInst ! = NULL )
{
auto lengthValAddr = mBfIRBuilder - > CreateInBoundsGEP ( arrayBaseValue , 0 , fieldInst - > mDataIdx ) ;
lengthVal = mBfIRBuilder - > CreateAlignedLoad ( lengthValAddr , fieldInst - > mResolvedType - > mAlign ) ;
}
2019-08-23 11:56:54 -07:00
}
lengthVal = mBfIRBuilder - > CreateNumericCast ( lengthVal , true , BfTypeCode_IntPtr ) ;
2022-07-26 13:27:03 -04:00
conditionValue = mBfIRBuilder - > CreateCmpLT ( itrVal , lengthVal , true ) ;
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > CreateCondBr ( conditionValue , bodyBB , endBB ) ;
ValueScopeEnd ( valueScopeStartInner ) ;
}
else // if (itr.MoveNext())
{
if ( ! itr )
{
if ( ! isVarEnumerator )
AssertErrorState ( ) ;
2022-05-30 11:40:49 -07:00
mBfIRBuilder - > CreateBr ( endBB ) ;
2019-08-23 11:56:54 -07:00
}
else
2022-07-26 13:27:03 -04:00
{
BfExprEvaluator exprEvaluator ( this ) ;
2019-08-23 11:56:54 -07:00
auto itrTypeInstance = itr . mType - > ToTypeInstance ( ) ;
2022-07-26 13:27:03 -04:00
SizedArray < BfResolvedArg , 0 > resolvedArgs ;
2022-02-05 13:47:19 -05:00
BfMethodMatcher methodMatcher ( forEachStmt - > mCollectionExpression , this , getNextMethodInst . mMethodInstance , resolvedArgs , BfMethodGenericArguments ( ) ) ;
2019-08-23 11:56:54 -07:00
if ( isRefExpression )
methodMatcher . CheckType ( refItrInterface , itr , false ) ;
else
methodMatcher . CheckType ( itrInterface , itr , false ) ;
methodMatcher . TryDevirtualizeCall ( itr ) ;
2022-07-26 13:27:03 -04:00
exprEvaluator . mReceivingValue = & nextResult ;
auto retVal = exprEvaluator . CreateCall ( & methodMatcher , itr ) ;
2019-08-23 11:56:54 -07:00
if ( exprEvaluator . mReceivingValue ! = NULL )
{
2021-01-08 16:21:03 -08:00
if ( mIsComptimeModule )
2020-12-23 08:53:38 -08:00
{
2021-02-26 08:01:43 -08:00
retVal = LoadValue ( retVal ) ;
2020-12-23 08:53:38 -08:00
mBfIRBuilder - > CreateStore ( retVal . mValue , nextResult . mValue ) ;
}
else
AssertErrorState ( ) ;
2019-08-23 11:56:54 -07:00
}
2020-05-12 09:16:17 -07:00
if ( ( retVal ) & & ( ! retVal . mType - > IsVar ( ) ) )
2019-08-23 11:56:54 -07:00
{
auto i8Result = ExtractValue ( nextResult , NULL , 2 ) ;
i8Result = LoadValue ( i8Result ) ;
BF_ASSERT ( i8Result . mType = = GetPrimitiveType ( BfTypeCode_Int8 ) ) ;
conditionValue = mBfIRBuilder - > CreateCmpEQ ( i8Result . mValue , GetConstValue8 ( 0 ) ) ;
}
else
2022-07-26 13:27:03 -04:00
conditionValue = GetDefaultValue ( GetPrimitiveType ( BfTypeCode_Boolean ) ) ;
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > CreateCondBr ( conditionValue , bodyBB , endBB ) ;
ValueScopeEnd ( valueScopeStartInner ) ;
}
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > AddBlock ( bodyBB ) ;
mBfIRBuilder - > SetInsertPoint ( bodyBB ) ;
if ( ! varTypedVal )
{
// Nothing to do...
}
else if ( isSizedArray ) // val = array[i]
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
auto itrVal = mBfIRBuilder - > CreateLoad ( itr . mValue ) ;
auto arrayType = ( BfSizedArrayType * ) target . mType ;
BfType * ptrType = CreatePointerType ( arrayType - > mElementType ) ;
BfTypedValue arrayItem ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
if ( arrayType - > mElementType - > IsValuelessType ( ) )
{
arrayItem = GetDefaultTypedValue ( arrayType - > mElementType ) ;
}
else
{
2021-01-18 14:09:16 -08:00
target = MakeAddressable ( target ) ;
arrayItem = BfTypedValue ( CreateIndexedValue ( arrayType - > mElementType , target . mValue , itrVal , true ) , arrayType - > mElementType , true ) ;
2021-01-20 13:18:03 -08:00
if ( isRefExpression )
arrayItem = BfTypedValue ( arrayItem . mValue , CreateRefType ( arrayItem . mType ) ) ;
2019-08-23 11:56:54 -07:00
}
arrayItem = Cast ( forEachStmt - > mCollectionExpression , arrayItem , varType , BfCastFlags_Explicit ) ;
if ( ( arrayItem ) & & ( ! arrayItem . mValue . IsFake ( ) ) )
{
arrayItem = LoadValue ( arrayItem ) ;
if ( arrayItem )
mBfIRBuilder - > CreateStore ( arrayItem . mValue , varInst ) ;
}
}
else if ( isArray ) // val = array[i]
{
auto itrVal = mBfIRBuilder - > CreateLoad ( itr . mValue ) ;
BfTypedValueExpression typedValueExpr ;
typedValueExpr . Init ( BfTypedValue ( itrVal , itrType ) ) ;
BfExprEvaluator exprEvaluator ( this ) ;
SizedArray < BfExpression * , 1 > indices ;
indices . push_back ( & typedValueExpr ) ;
BfSizedArray < BfExpression * > sizedArgExprs ( indices ) ;
2022-07-26 13:27:03 -04:00
BfResolvedArgs argValues ( & sizedArgExprs ) ;
2019-08-23 11:56:54 -07:00
exprEvaluator . ResolveArgValues ( argValues ) ;
bool boundsCheck = mCompiler - > mOptions . mRuntimeChecks ;
auto typeOptions = GetTypeOptions ( ) ;
if ( typeOptions ! = NULL )
2020-07-11 16:24:07 -07:00
boundsCheck = typeOptions - > Apply ( boundsCheck , BfOptionFlags_RuntimeChecks ) ;
2022-07-26 13:27:03 -04:00
2022-02-05 13:47:19 -05:00
BfMethodMatcher methodMatcher ( forEachStmt - > mVariableName , this , " get__ " , argValues . mResolvedArgs , BfMethodGenericArguments ( ) ) ;
2019-08-23 11:56:54 -07:00
methodMatcher . mMethodType = BfMethodType_PropertyGetter ;
methodMatcher . CheckType ( target . mType - > ToTypeInstance ( ) , target , false ) ;
2019-12-01 10:17:09 -08:00
if ( methodMatcher . mBestMethodDef = = NULL )
2019-08-23 11:56:54 -07:00
{
2019-12-01 10:17:09 -08:00
Fail ( " Failed to find indexer method in array " , forEachStmt ) ;
}
else
{
methodMatcher . mCheckedKind = boundsCheck ? BfCheckedKind_Checked : BfCheckedKind_Unchecked ;
BfTypedValue arrayItem = exprEvaluator . CreateCall ( & methodMatcher , target ) ;
if ( ( varInst ) & & ( arrayItem ) )
{
if ( isRefExpression )
arrayItem = BfTypedValue ( arrayItem . mValue , CreateRefType ( arrayItem . mType ) ) ;
else if ( ! arrayItem . mType - > IsComposite ( ) )
arrayItem = LoadValue ( arrayItem ) ;
arrayItem = Cast ( forEachStmt - > mCollectionExpression , arrayItem , varType , BfCastFlags_Explicit ) ;
2019-08-23 11:56:54 -07:00
arrayItem = LoadValue ( arrayItem ) ;
2019-12-01 10:17:09 -08:00
if ( arrayItem )
mBfIRBuilder - > CreateStore ( arrayItem . mValue , varInst ) ;
}
2019-08-23 11:56:54 -07:00
}
}
else
{
if ( ! itr )
{
if ( ! isVarEnumerator )
AssertErrorState ( ) ;
}
else if ( mCompiler - > IsAutocomplete ( ) )
{
2022-07-26 13:27:03 -04:00
// If we don't do this shortcut, we can end up creating temporary "boxed" objects
2019-08-23 11:56:54 -07:00
}
else
{
if ( needsValCopy )
2022-07-26 13:27:03 -04:00
{
2020-03-20 09:24:08 -07:00
auto nextVal = BfTypedValue ( mBfIRBuilder - > CreateBitCast ( nextResult . mValue , mBfIRBuilder - > MapType ( CreatePointerType ( nextEmbeddedType ) ) ) , nextEmbeddedType , true ) ;
if ( isRefExpression )
2020-05-01 16:29:12 -07:00
{
if ( nextVal . mType - > IsPointer ( ) )
nextVal = BfTypedValue ( nextVal . mValue , CreateRefType ( nextVal . mType - > GetUnderlyingType ( ) ) , true ) ;
}
2020-03-20 09:24:08 -07:00
nextVal = Cast ( forEachStmt - > mCollectionExpression , nextVal , varType , BfCastFlags_Explicit ) ;
nextVal = LoadValue ( nextVal ) ;
2020-07-22 15:32:27 -07:00
if ( ( nextVal ) & & ( ! nextVal . mType - > IsValuelessType ( ) ) )
2022-04-16 13:22:32 -07:00
mBfIRBuilder - > CreateAlignedStore ( nextVal . mValue , varInst , nextVal . mType - > mAlign ) ;
2019-08-23 11:56:54 -07:00
}
}
}
if ( forEachStmt - > mEmbeddedStatement ! = NULL )
2022-07-26 13:27:03 -04:00
{
VisitEmbeddedStatement ( forEachStmt - > mEmbeddedStatement ) ;
2019-08-23 11:56:54 -07:00
}
if ( ! mCurMethodState - > mLeftBlockUncond )
{
ValueScopeEnd ( valueScopeStartInner ) ;
mBfIRBuilder - > CreateBr ( incBB ) ;
}
mBfIRBuilder - > AddBlock ( incBB ) ;
mBfIRBuilder - > SetInsertPoint ( incBB ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
if ( isArray | | isSizedArray )
{
auto val = mBfIRBuilder - > CreateLoad ( itr . mValue ) ;
auto result = mBfIRBuilder - > CreateAdd ( val , GetConstValue ( 1 ) ) ;
mBfIRBuilder - > CreateStore ( result , itr . mValue ) ;
}
else
{
2022-07-26 13:27:03 -04:00
// Nothing to do
2019-08-23 11:56:54 -07:00
}
2022-07-26 13:27:03 -04:00
mBfIRBuilder - > CreateBr ( condBB ) ;
2019-08-23 11:56:54 -07:00
mBfIRBuilder - > AddBlock ( endBB ) ;
mBfIRBuilder - > SetInsertPoint ( endBB ) ;
if ( ( itrLocalDef ! = NULL ) & & ( itrLocalDef - > mDbgVarInst ) & & ( IsTargetingBeefBackend ( ) ) )
{
// If this shadows another enumerator variable then we need to explicitly mark the end of this one
mBfIRBuilder - > DbgLifetimeEnd ( itrLocalDef - > mDbgVarInst ) ;
}
// The 'return' may have been inside the block, which may not have been entered if preconditions were not met
mCurMethodState - > SetHadReturn ( false ) ;
mCurMethodState - > mLeftBlockUncond = false ;
mCurMethodState - > mLeftBlockCond = false ;
RestoreScopeState ( ) ;
2021-05-31 07:01:56 -07:00
RestoreScopeState ( ) ;
2019-08-23 11:56:54 -07:00
}
void BfModule : : Visit ( BfDeferStatement * deferStmt )
{
if ( deferStmt - > mTargetNode = = NULL )
{
AssertErrorState ( ) ;
return ;
}
//TODO: Why in the world didn't we want to be able to step onto a defer statement?
// We only want the breakpoint to hit on execution of the defer, not on insertion of it
//SetAndRestoreValue<bool> prevSetIllegalSrcPos(mSetIllegalSrcPosition, true);
2022-07-26 13:27:03 -04:00
UpdateSrcPos ( deferStmt ) ;
2019-08-23 11:56:54 -07:00
EmitEnsureInstructionAt ( ) ;
2022-07-26 13:27:03 -04:00
2019-08-23 11:56:54 -07:00
BfScopeData * scope = NULL ;
if ( deferStmt - > mScopeToken ! = NULL )
{
if ( deferStmt - > mScopeToken - > GetToken ( ) = = BfToken_Scope )
scope = mCurMethodState - > mCurScope - > GetTargetable ( ) ;
else
scope = & mCurMethodState - > mHeadScope ;
}
else if ( deferStmt - > mScopeName ! = NULL )
2019-09-12 09:46:54 -07:00
scope = FindScope ( deferStmt - > mScopeName , true ) ;
2019-08-23 11:56:54 -07:00
else
scope = mCurMethodState - > mCurScope ;
2020-05-29 16:58:47 -07:00
if ( ( mCompiler - > mResolvePassData ! = NULL ) & & ( mCompiler - > mResolvePassData - > mAutoComplete ! = NULL ) )
2022-07-26 13:27:03 -04:00
{
2020-05-29 16:58:47 -07:00
auto targetIdentifier = BfNodeDynCast < BfIdentifierNode > ( deferStmt - > mScopeName ) ;
if ( ( deferStmt - > mScopeName = = NULL ) | | ( targetIdentifier ! = NULL ) )
mCompiler - > mResolvePassData - > mAutoComplete - > CheckLabel ( targetIdentifier , deferStmt - > mColonToken , scope ) ;
}
2020-02-19 13:16:33 -08:00
if ( ( scope = = mCurMethodState - > mCurScope ) & & ( scope - > mCloseNode = = NULL ) )
{
2021-02-25 10:14:22 -08:00
auto parser = deferStmt - > GetParser ( ) ;
2022-07-26 13:27:03 -04:00
if ( ( parser = = NULL ) | | ( ! parser - > mIsEmitted ) )
2021-02-25 10:14:22 -08:00
Warn ( 0 , " This defer will immediately execute. Consider specifying a wider scope target such as 'defer::' " , deferStmt - > mDeferToken ) ;
2020-02-19 13:16:33 -08:00
}
2019-08-23 11:56:54 -07:00
if ( auto block = BfNodeDynCast < BfBlock > ( deferStmt - > mTargetNode ) )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
if ( deferStmt - > mBind ! = NULL )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
Array < BfDeferredCapture > captures ;
for ( auto identifier : deferStmt - > mBind - > mParams )
{
BfDeferredCapture deferredCapture ;
deferredCapture . mName = identifier - > ToString ( ) ;
deferredCapture . mValue = CreateValueFromExpression ( identifier ) ;
if ( deferredCapture . mValue )
{
captures . push_back ( deferredCapture ) ;
}
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
AddDeferredBlock ( block , scope , & captures ) ;
2021-01-13 05:09:09 -08:00
}
2019-08-23 11:56:54 -07:00
else
AddDeferredBlock ( block , scope ) ;
}
else if ( auto exprStmt = BfNodeDynCast < BfExpressionStatement > ( deferStmt - > mTargetNode ) )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
BfExprEvaluator expressionEvaluator ( this ) ;
expressionEvaluator . mDeferCallRef = exprStmt - > mExpression ;
expressionEvaluator . mDeferScopeAlloc = scope ;
2022-07-26 13:27:03 -04:00
expressionEvaluator . VisitChild ( exprStmt - > mExpression ) ;
2022-01-08 11:26:56 -05:00
if ( mCurMethodState - > mPendingNullConditional ! = NULL )
FlushNullConditional ( expressionEvaluator . mResult , true ) ;
2019-08-23 11:56:54 -07:00
}
else if ( auto deleteStmt = BfNodeDynCast < BfDeleteStatement > ( deferStmt - > mTargetNode ) )
{
if ( deleteStmt - > mExpression = = NULL )
{
AssertErrorState ( ) ;
return ;
}
auto val = CreateValueFromExpression ( deleteStmt - > mExpression ) ;
if ( ! val )
return ;
if ( mCompiler - > IsAutocomplete ( ) )
return ;
bool isGenericParam = false ;
auto checkType = val . mType ;
if ( val . mType - > IsGenericParam ( ) )
{
isGenericParam = true ;
auto genericParamInst = GetGenericParamInstance ( ( BfGenericParamType * ) val . mType ) ;
2022-07-26 13:27:03 -04:00
if ( genericParamInst - > mGenericParamFlags & BfGenericParamFlag_Delete )
return ;
if ( genericParamInst - > mTypeConstraint ! = NULL )
2019-08-23 11:56:54 -07:00
checkType = genericParamInst - > mTypeConstraint ;
}
bool isAppendDelete = false ;
BfTypedValue customAllocator ;
if ( deleteStmt - > mAllocExpr ! = NULL )
{
if ( auto expr = BfNodeDynCast < BfExpression > ( deleteStmt - > mAllocExpr ) )
customAllocator = CreateValueFromExpression ( expr ) ;
else if ( auto tokenNode = BfNodeDynCast < BfTokenNode > ( deleteStmt - > mAllocExpr ) )
{
if ( tokenNode - > mToken = = BfToken_Append )
isAppendDelete = true ;
}
}
auto internalType = ResolveTypeDef ( mCompiler - > mInternalTypeDef ) ;
PopulateType ( checkType ) ;
if ( checkType - > IsVar ( ) )
return ;
if ( ( ! checkType - > IsObjectOrInterface ( ) ) & & ( ! checkType - > IsPointer ( ) ) )
{
VisitChild ( deferStmt - > mTargetNode ) ;
Fail ( StrFormat ( " Cannot delete a value of type '%s' " , TypeToString ( val . mType ) . c_str ( ) ) , deferStmt - > mTargetNode ) ;
return ;
}
if ( isGenericParam )
return ;
2020-06-17 06:06:03 -07:00
bool isDtorOnly = false ;
if ( customAllocator . mType = = GetPrimitiveType ( BfTypeCode_NullPtr ) )
{
if ( ! checkType - > IsObjectOrInterface ( ) )
Warn ( 0 , " Type '%' has no destructor, so delete:null has no effect " , deleteStmt - > mExpression ) ;
}
else if ( customAllocator )
2019-08-23 11:56:54 -07:00
{
2022-07-26 13:27:03 -04:00
BfFunctionBindResult functionBindResult ;
2019-08-23 11:56:54 -07:00
functionBindResult . mWantsArgs = true ;
auto customAllocTypeInst = customAllocator . mType - > ToTypeInstance ( ) ;
if ( ( checkType - > IsObjectOrInterface ( ) ) & & ( customAllocTypeInst ! = NULL ) & & ( customAllocTypeInst - > mTypeDef - > GetMethodByName ( " FreeObject " ) ! = NULL ) )
{
BfTypedValueExpression typedValueExpr ;
typedValueExpr . Init ( val ) ;
typedValueExpr . mRefNode = deleteStmt - > mAllocExpr ;
BfExprEvaluator exprEvaluator ( this ) ;
SizedArray < BfExpression * , 2 > argExprs ;
argExprs . push_back ( & typedValueExpr ) ;
BfSizedArray < BfExpression * > sizedArgExprs ( argExprs ) ;
BfResolvedArgs argValues ( & sizedArgExprs ) ;
exprEvaluator . ResolveArgValues ( argValues ) ;
exprEvaluator . mNoBind = true ;
exprEvaluator . mFunctionBindResult = & functionBindResult ;
2022-02-05 13:47:19 -05:00
exprEvaluator . MatchMethod ( deleteStmt - > mAllocExpr , NULL , customAllocator , false , false , " FreeObject " , argValues , BfMethodGenericArguments ( ) ) ;
2019-08-23 11:56:54 -07:00
}
else
{
auto voidPtrType = GetPrimitiveType ( BfTypeCode_NullPtr ) ;
auto ptrValue = BfTypedValue ( mBfIRBuilder - > CreateBitCast ( val . mValue , mBfIRBuilder - > MapType ( voidPtrType ) ) , voidPtrType ) ;
BfTypedValueExpression typedValueExpr ;
2022-07-26 13:27:03 -04:00
typedValueExpr . Init ( ptrValue ) ;
2019-08-23 11:56:54 -07:00
BfExprEvaluator exprEvaluator ( this ) ;
SizedArray < BfExpression * , 2 > argExprs ;
argExprs . push_back ( & typedValueExpr ) ;
BfSizedArray < BfExpression * > sizedArgExprs ( argExprs ) ;
BfResolvedArgs argValues ( & sizedArgExprs ) ;
exprEvaluator . ResolveArgValues ( argValues ) ;
exprEvaluator . mNoBind = true ;
exprEvaluator . mFunctionBindResult = & functionBindResult ;
2022-02-05 13:47:19 -05:00
exprEvaluator . MatchMethod ( deleteStmt - > mAllocExpr , NULL , customAllocator , false , false , " Free " , argValues , BfMethodGenericArguments ( ) ) ;
2019-08-23 11:56:54 -07:00
}
if ( functionBindResult . mMethodInstance ! = NULL )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
AddDeferredCall ( BfModuleMethodInstance ( functionBindResult . mMethodInstance , functionBindResult . mFunc ) , functionBindResult . mIRArgs , scope , deleteStmt , true ) ;
}
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
if ( checkType - > IsObjectOrInterface ( ) )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
auto objectType = mContext - > mBfObjectType ;
PopulateType ( objectType ) ;
BfMethodInstance * methodInstance = objectType - > mVirtualMethodTable [ mCompiler - > GetVTableMethodOffset ( ) + 0 ] . mImplementingMethod ;
BF_ASSERT ( methodInstance - > mMethodDef - > mName = = " ~this " ) ;
SizedArray < BfIRValue , 1 > llvmArgs ;
llvmArgs . push_back ( mBfIRBuilder - > CreateBitCast ( val . mValue , mBfIRBuilder - > MapType ( objectType ) ) ) ;
if ( ! customAllocator )
{
2021-01-08 16:21:03 -08:00
if ( ( mCompiler - > mOptions . mEnableRealtimeLeakCheck ) & & ( ! mIsComptimeModule ) )
2019-08-23 11:56:54 -07:00
{
auto moduleMethodInstance = GetInternalMethod ( " Dbg_MarkObjectDeleted " ) ;
AddDeferredCall ( moduleMethodInstance , llvmArgs , scope , deleteStmt , false , true ) ;
}
else
{
auto moduleMethodInstance = GetInternalMethod ( " Free " ) ;
SizedArray < BfIRValue , 1 > llvmArgs ;
llvmArgs . push_back ( mBfIRBuilder - > CreateBitCast ( val . mValue , mBfIRBuilder - > GetPrimitiveType ( BfTypeCode_NullPtr ) ) ) ;
AddDeferredCall ( moduleMethodInstance , llvmArgs , scope , deleteStmt , false , true ) ;
}
2022-07-26 13:27:03 -04:00
}
2019-08-23 11:56:54 -07:00
auto moduleMethodInstance = GetMethodInstance ( objectType , methodInstance - > mMethodDef , BfTypeVector ( ) ) ;
AddDeferredCall ( moduleMethodInstance , llvmArgs , scope , deleteStmt , false , true ) ;
2021-01-08 16:21:03 -08:00
if ( ( mCompiler - > mOptions . mObjectHasDebugFlags ) & & ( ! mIsComptimeModule ) )
2019-08-23 11:56:54 -07:00
{
auto moduleMethodInstance = GetMethodByName ( internalType - > ToTypeInstance ( ) , ( deleteStmt - > mTargetTypeToken ! = NULL ) ? " Dbg_ObjectPreCustomDelete " : " Dbg_ObjectPreDelete " ) ;
AddDeferredCall ( moduleMethodInstance , llvmArgs , scope , deleteStmt , false , true ) ;
2022-07-26 13:27:03 -04:00
}
}
2019-08-23 11:56:54 -07:00
else
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
if ( ( ! customAllocator ) & & ( ! isAppendDelete ) )
{
val = LoadValue ( val ) ;
BfModuleMethodInstance moduleMethodInstance ;
2021-01-08 16:21:03 -08:00
if ( ( mCompiler - > mOptions . mDebugAlloc ) & & ( ! mIsComptimeModule ) )
2019-08-23 11:56:54 -07:00
moduleMethodInstance = GetMethodByName ( internalType - > ToTypeInstance ( ) , " Dbg_RawFree " ) ;
else
moduleMethodInstance = GetMethodByName ( internalType - > ToTypeInstance ( ) , " Free " ) ;
SizedArray < BfIRValue , 1 > llvmArgs ;
llvmArgs . push_back ( mBfIRBuilder - > CreateBitCast ( val . mValue , mBfIRBuilder - > GetPrimitiveType ( BfTypeCode_NullPtr ) ) ) ;
AddDeferredCall ( moduleMethodInstance , llvmArgs , scope , deleteStmt , false , true ) ;
2022-07-26 13:27:03 -04:00
}
}
2019-08-23 11:56:54 -07:00
}
else
{
AssertErrorState ( ) ;
VisitChild ( deferStmt - > mTargetNode ) ;
}
}
void BfModule : : Visit ( BfBlock * block )
{
VisitEmbeddedStatement ( block ) ;
}
2021-01-04 06:33:39 -08:00
void BfModule : : Visit ( BfUnscopedBlock * block )
{
VisitEmbeddedStatement ( block , NULL , BfEmbeddedStatementFlags_Unscoped ) ;
}
2019-08-23 11:56:54 -07:00
void BfModule : : Visit ( BfLabeledBlock * labeledBlock )
{
VisitEmbeddedStatement ( labeledBlock ) ;
}
void BfModule : : Visit ( BfRootNode * rootNode )
2022-07-26 13:27:03 -04:00
{
2019-08-23 11:56:54 -07:00
VisitMembers ( rootNode ) ;
}
void BfModule : : Visit ( BfInlineAsmStatement * asmStmt )
{
#if 0
enum RegClobberFlags //CDH TODO add support for mmx/xmm/fpst etc (how are these signified in LLVM? check LangRef inline asm docs clobber list info)
{
// please keep eax through edx in alphabetical order (grep $BYTEREGS for why)
REGCLOBBERF_EAX = ( 1 < < 0 ) ,
REGCLOBBERF_EBX = ( 1 < < 1 ) ,
REGCLOBBERF_ECX = ( 1 < < 2 ) ,
REGCLOBBERF_EDX = ( 1 < < 3 ) ,
REGCLOBBERF_ESI = ( 1 < < 4 ) ,
REGCLOBBERF_EDI = ( 1 < < 5 ) ,
REGCLOBBERF_ESP = ( 1 < < 6 ) ,
REGCLOBBERF_EBP = ( 1 < < 7 ) ,
REGCLOBBERF_XMM0 = ( 1 < < 8 ) ,
REGCLOBBERF_XMM1 = ( 1 < < 9 ) ,
REGCLOBBERF_XMM2 = ( 1 < < 10 ) ,
REGCLOBBERF_XMM3 = ( 1 < < 11 ) ,
REGCLOBBERF_XMM4 = ( 1 < < 12 ) ,
REGCLOBBERF_XMM5 = ( 1 < < 13 ) ,
REGCLOBBERF_XMM6 = ( 1 < < 14 ) ,
REGCLOBBERF_XMM7 = ( 1 < < 15 ) ,
REGCLOBBERF_FPST0 = ( 1 < < 16 ) ,
REGCLOBBERF_FPST1 = ( 1 < < 17 ) ,
REGCLOBBERF_FPST2 = ( 1 < < 18 ) ,
REGCLOBBERF_FPST3 = ( 1 < < 19 ) ,
REGCLOBBERF_FPST4 = ( 1 < < 20 ) ,
REGCLOBBERF_FPST5 = ( 1 < < 21 ) ,
REGCLOBBERF_FPST6 = ( 1 < < 22 ) ,
REGCLOBBERF_FPST7 = ( 1 < < 23 ) ,
REGCLOBBERF_MM0 = ( 1 < < 24 ) ,
REGCLOBBERF_MM1 = ( 1 < < 25 ) ,
REGCLOBBERF_MM2 = ( 1 < < 26 ) ,
REGCLOBBERF_MM3 = ( 1 < < 27 ) ,
REGCLOBBERF_MM4 = ( 1 < < 28 ) ,
REGCLOBBERF_MM5 = ( 1 < < 29 ) ,
REGCLOBBERF_MM6 = ( 1 < < 30 ) ,
REGCLOBBERF_MM7 = ( 1 < < 31 ) ,
} ;
const char * regClobberNames [ ] = { " eax " , " ebx " , " ecx " , " edx " , " esi " , " edi " , " esp " , " ebp " , nullptr } ; // must be in same order as flags
unsigned long regClobberFlags = 0 ;
std : : function < bool ( const StringImpl & , bool ) > matchRegFunc = [ this , & regClobberNames , & regClobberFlags ] ( const StringImpl & name , bool isClobber )
{
bool found = false ;
int nameLen = name . length ( ) ;
if ( nameLen = = 3 )
{
if ( ( name [ 0 ] = = ' s ' ) & & ( name [ 1 ] = = ' t ' ) & & ( name [ 2 ] > = ' 0 ' ) & & ( name [ 2 ] < = ' 7 ' ) )
{
// st# regs (unparenthesized at this point)
if ( isClobber )
regClobberFlags | = ( REGCLOBBERF_FPST0 < < ( name [ 2 ] - ' 0 ' ) ) ;
found = true ;
}
else if ( ( name [ 0 ] = = ' m ' ) & & ( name [ 1 ] = = ' m ' ) & & ( name [ 2 ] > = ' 0 ' ) & & ( name [ 2 ] < = ' 7 ' ) )
{
// mm regs
if ( isClobber )
regClobberFlags | = ( REGCLOBBERF_MM0 < < ( name [ 2 ] - ' 0 ' ) ) ;
found = true ;
}
else
{
// dword regs
for ( int iRegCheck = 0 ; regClobberNames [ iRegCheck ] ! = nullptr ; + + iRegCheck )
{
if ( ! strcmp ( name . c_str ( ) , regClobberNames [ iRegCheck ] ) )
{
if ( isClobber )
regClobberFlags | = ( 1 < < iRegCheck ) ;
found = true ;
break ;
}
}
}
}
else if ( nameLen = = 2 )
{
// word & byte regs
for ( int iRegCheck = 0 ; regClobberNames [ iRegCheck ] ! = nullptr ; + + iRegCheck )
{
if ( ! strcmp ( name . c_str ( ) , regClobberNames [ iRegCheck ] + 1 ) ) // skip leading 'e'
{
if ( isClobber )
regClobberFlags | = ( 1 < < iRegCheck ) ;
found = true ;
break ;
}
}
if ( ! found )
{
// check for byte regs for eax through edx (e.g. al, ah, bl, bh....)
if ( ( nameLen = = 2 ) & & ( name [ 0 ] > = ' a ' ) & & ( name [ 0 ] < = ' d ' ) & & ( ( name [ 1 ] = = ' l ' ) | | ( name [ 1 ] = = ' h ' ) ) )
{
if ( isClobber )
regClobberFlags | = ( 1 < < ( name [ 0 ] - ' a ' ) ) ; // $BYTEREGS this is why we want alphabetical order
found = true ;
}
}
}
else if ( ( nameLen = = 4 ) & & ( name [ 0 ] = = ' x ' ) & & ( name [ 1 ] = = ' m ' ) & & ( name [ 2 ] = = ' m ' ) & & ( name [ 3 ] > = ' 0 ' ) & & ( name [ 3 ] < = ' 7 ' ) )
{
// xmm regs
if ( isClobber )
regClobberFlags | = ( REGCLOBBERF_XMM0 < < ( name [ 3 ] - ' 0 ' ) ) ;
found = true ;
}
return found ;
} ;
int asmInstCount = ( int ) asmStmt - > mInstructions . size ( ) ;
typedef std : : map < String , int > StrToVarIndexMap ;
StrToVarIndexMap strToVarIndexMap ;
if ( mCompiler - > IsAutocomplete ( ) )
{
// auto-complete "fast-pass" just to eliminate unused/unassigned variable yellow warning flashes
for ( int iInst = 0 ; iInst < asmInstCount ; + + iInst )
{
auto instNode = asmStmt - > mInstructions [ iInst ] ;
BfInlineAsmInstruction : : AsmInst & asmInst = instNode - > mAsmInst ;
bool hasLabel = ! asmInst . mLabel . empty ( ) ;
bool hasOpCode = ! asmInst . mOpCode . empty ( ) ;
if ( hasLabel | | hasOpCode ) // check against blank lines
{
if ( hasOpCode ) // check against label-only lines (which still get written out, but don't do any other processing)
{
2022-07-26 13:27:03 -04:00
int argCount = ( int ) asmInst . mArgs . size ( ) ;
2019-08-23 11:56:54 -07:00
for ( int iArg = 0 ; iArg < argCount ; + + iArg )
{
BfInlineAsmInstruction : : AsmArg * arg = & asmInst . mArgs [ iArg ] ;
if ( arg - > mType = = BfInlineAsmInstruction : : AsmArg : : ARGTYPE_IntReg )
{
bool found = matchRegFunc ( arg - > mReg , false ) ;
if ( ! found )
{
StrToVarIndexMap : : iterator it = strToVarIndexMap . find ( arg - > mReg ) ;
if ( it = = strToVarIndexMap . end ( ) )
{
for ( int i = 0 ; i < ( int ) mCurMethodState - > mLocals . size ( ) ; i + + )
{
auto & checkLocal = mCurMethodState - > mLocals [ i ] ;
if ( checkLocal . mName = = arg - > mReg )
{
// if you access a variable in asm, we suppress any warnings related to used or assigned, regardless of usage
checkLocal . mIsReadFrom = true ;
2020-09-21 13:58:00 -07:00
checkLocal . mAssignedKind = BfLocalVarAssignKind_Unconditional ;
2019-08-23 11:56:54 -07:00
found = true ;
break ;
}
}
}
}
}
}
}
}
}
return ;
}
2022-07-26 13:27:03 -04:00
int debugLocOffset = 0 ;
2019-08-23 11:56:54 -07:00
if ( ! asmStmt - > mInstructions . empty ( ) )
debugLocOffset = asmStmt - > mInstructions . front ( ) - > GetSrcStart ( ) - asmStmt - > GetSrcStart ( ) ;
UpdateSrcPos ( asmStmt , true , debugLocOffset ) ;
mCurMethodState - > mInHeadScope = false ;
BfScopeData prevScope = mCurMethodState - > mCurScope ;
mCurMethodState - > mCurScope - > mPrevScope = & prevScope ;
NewScopeState ( ) ;
bool failed = false ;
if ( ! mCpu )
mCpu = new Beefy : : X86Cpu ( ) ;
//const char* srcAsmText = "nop\nnop\n\n\nmov eax, i\ninc eax\nmov i, eax\n_emit 0x0F\n_emit 0xC7\n_emit 0xF0\n\n\nnop\nnop"; //CDH TODO extract from actual lexical text block
//const char* srcAsmText = "nop\nnop\n\n\nmov eax, i\ninc eax\nmov i, eax\nrdrand eax\n\n\nnop\nnop"; //CDH TODO extract from actual lexical text block
//String srcAsmTextStr(&asmStmt->mParser->mSrc[asmStmt->mSrcStart], asmStmt->mSrcEnd - asmStmt->mSrcStart);
//const char* srcAsmText = srcAsmTextStr.c_str();
String dstAsmText ;
String constraintStr , clobberStr ;
int constraintCount = 0 ;
bool hasMemoryClobber = false ;
Array < Type * > paramTypes ;
SizedArray < Value * , 1 > llvmArgs ;
int lastDebugLine = - 1 ;
int curDebugLineDeltaValue = 0 , curDebugLineDeltaRunCount = 0 ;
String debugLineSequenceStr ;
int isFirstDebugLine = 1 ;
auto maybeEmitDebugLineRun = [ & curDebugLineDeltaValue , & curDebugLineDeltaRunCount , & debugLineSequenceStr , & isFirstDebugLine ] ( )
{
if ( curDebugLineDeltaRunCount > 0 )
{
for ( int i = isFirstDebugLine ; i < 2 ; + + i )
{
int value = i ? curDebugLineDeltaValue : curDebugLineDeltaRunCount ;
String encodedValue ;
EncodeULEB32 ( value , encodedValue ) ;
if ( encodedValue . length ( ) > 1 )
debugLineSequenceStr + = String ( " $ " ) + encodedValue + " $ " ;
else
debugLineSequenceStr + = encodedValue ;
}
curDebugLineDeltaRunCount = 0 ;
isFirstDebugLine = 0 ;
}
} ;
auto mangledLabelName = [ & asmStmt ] ( const StringImpl & labelName , int numericLabel ) - > String
{
return StrFormat ( " %d " , numericLabel ) ;
//return String(".") + labelName;
//return StrFormat("%s_%p_%d", labelName.c_str(), asmStmt->mSource, asmStmt->mSrcStart); // suffix label name with location information to make it block-specific (since labels get external linkage)
} ;
typedef std : : pair < String , int > LabelPair ;
std : : unordered_map < String , LabelPair > labelNames ;
// pre-scan instructions for label names
for ( int iInst = 0 ; iInst < asmInstCount ; + + iInst )
{
auto instNode = asmStmt - > mInstructions [ iInst ] ;
BfInlineAsmInstruction : : AsmInst & asmInst = instNode - > mAsmInst ;
if ( ! asmInst . mLabel . empty ( ) )
{
if ( labelNames . find ( asmInst . mLabel ) ! = labelNames . end ( ) )
{
Fail ( StrFormat ( " Label \" %s \" already defined in asm block " , asmInst . mLabel . c_str ( ) ) , instNode , true ) ;
failed = true ;
}
else
{
String mangledLabel ( mangledLabelName ( asmInst . mLabel , instNode - > GetSrcStart ( ) ) ) ;
labelNames [ asmInst . mLabel ] = LabelPair ( mangledLabel , instNode - > GetSrcStart ( ) ) ;
asmInst . mLabel = mangledLabel ;
}
}
}
for ( int iInst = 0 ; iInst < asmInstCount ; + + iInst )
{
auto instNode = asmStmt - > mInstructions [ iInst ] ;
BfInlineAsmInstruction : : AsmInst & asmInst = instNode - > mAsmInst ;
bool hasLabel = ! asmInst . mLabel . empty ( ) ;
bool hasOpCode = ! asmInst . mOpCode . empty ( ) ;
if ( hasLabel | | hasOpCode ) // check against blank lines
{
if ( hasOpCode ) // check against label-only lines (which still get written out, but don't do any other processing)
{
int argCount = ( int ) asmInst . mArgs . size ( ) ;
// reasonable defaults for clobber info
int clobberCount = 1 ; // destination is usually first arg in Intel syntax
bool mayClobberMem = true ; // we only care about this when it gets turned to false by GetClobbersForMnemonic (no operand form of the instruction clobbers mem)
// pseudo-ops
if ( asmInst . mOpCode = = " _emit " )
{
asmInst . mOpCode = " .byte " ;
}
else
{
Array < int > opcodes ;
if ( ! mCpu - > GetOpcodesForMnemonic ( asmInst . mOpCode , opcodes ) )
{
Fail ( StrFormat ( " Unrecognized instruction mnemonic \" %s \" " , asmInst . mOpCode . c_str ( ) ) , instNode , true ) ;
failed = true ;
}
else
{
Array < int > implicitClobbers ;
mCpu - > GetClobbersForMnemonic ( asmInst . mOpCode , argCount , implicitClobbers , clobberCount , mayClobberMem ) ;
for ( int iClobberReg : implicitClobbers )
{
String regName = CPURegisters : : GetRegisterName ( iClobberReg ) ;
std : : transform ( regName . begin ( ) , regName . end ( ) , regName . begin ( ) , : : tolower ) ;
matchRegFunc ( regName , true ) ;
}
}
}
String fakeLabel ; // used when running label-using instructions through LLVM semantic pre-check
for ( int iArg = 0 ; iArg < argCount ; + + iArg )
{
BfInlineAsmInstruction : : AsmArg * arg = & asmInst . mArgs [ iArg ] ;
if ( arg - > mType = = BfInlineAsmInstruction : : AsmArg : : ARGTYPE_IntReg )
{
bool isClobber = ( iArg < clobberCount ) ;
bool found = matchRegFunc ( arg - > mReg , isClobber ) ;
if ( ! found )
{
StrToVarIndexMap : : iterator it = strToVarIndexMap . find ( arg - > mReg ) ;
if ( it ! = strToVarIndexMap . end ( ) )
{
arg - > mReg = StrFormat ( " $%d " , it - > second ) ;
if ( isClobber )
mayClobberMem = true ;
found = true ;
}
else
{
for ( int i = 0 ; i < ( int ) mCurMethodState - > mLocals . size ( ) ; i + + )
{
auto & checkLocal = mCurMethodState - > mLocals [ i ] ;
if ( checkLocal . mName = = arg - > mReg )
{
BfIRValue testValue = checkLocal . mAddr ;
llvmArgs . push_back ( testValue ) ;
paramTypes . push_back ( testValue - > getType ( ) ) ;
arg - > mReg = StrFormat ( " $%d " , constraintCount ) ; //CDH TODO does this need size qualifiers for "dword ptr $0" or whatever?
strToVarIndexMap [ checkLocal . mName ] = constraintCount ;
constraintStr + = " =*m, " ;
+ + constraintCount ;
if ( isClobber )
mayClobberMem = true ;
// if you access a variable in asm, we suppress any warnings related to used or assigned, regardless of usage
checkLocal . mIsReadFrom = true ;
2020-09-21 13:58:00 -07:00
checkLocal . mAssignedKind = BfLocalVarAssignKind_Unconditional ;
2019-08-23 11:56:54 -07:00
found = true ;
break ;
}
}
}
}
if ( ! found )
{
auto labelIt = labelNames . find ( arg - > mReg ) ;
if ( labelIt ! = labelNames . end ( ) )
{
arg - > mReg = labelIt - > second . first ;
if ( labelIt - > second . second < = instNode - > GetSrcStart ( ) )
{
fakeLabel = arg - > mReg ;
arg - > mReg + = " b " ;
}
else
arg - > mReg + = " f " ;
}
else
{
Fail ( StrFormat ( " Unrecognized variable \" %s \" " , arg - > mReg . c_str ( ) ) , instNode , true ) ;
failed = true ;
}
}
}
else if ( arg - > mType = = BfInlineAsmInstruction : : AsmArg : : ARGTYPE_FloatReg )
{
//CDH individual reg clobber is probably insufficient for fp regs since it's stack-based; without deeper knowledge of how individual instructions
// manipulate the FP stack, the safest approach is to clobber all FP regs as soon as one of them is involved
//bool isClobber = (iArg == 0); // destination is first arg in Intel syntax
//bool found = matchRegFunc(StrFormat("st%d", arg->mInt), isClobber);
//BF_ASSERT(found);
for ( int iRegCheck = 0 ; iRegCheck < 8 ; + + iRegCheck )
regClobberFlags | = ( REGCLOBBERF_FPST0 < < iRegCheck ) ;
}
else if ( arg - > mType = = BfInlineAsmInstruction : : AsmArg : : ARGTYPE_Memory )
{
bool isClobber = ( iArg < clobberCount ) ;
// check regs for clobber flags
/*
//CDH TODO do we need to set clobber flags for regs that are used *indirectly* like this? Actually I don't think so; commenting out for now
if ( ! arg - > mReg . empty ( ) )
matchRegFunc ( arg - > mReg , isClobber ) ;
if ( ! arg - > mAdjReg . empty ( ) )
matchRegFunc ( arg - > mAdjReg , isClobber ) ;
*/
if ( isClobber )
mayClobberMem = true ;
if ( ! arg - > mMemberSuffix . empty ( ) )
{
//CDH TODO add member support once I know the right way to look up struct member offsets. Once we know the offset,
// add it to arg->mInt, and set ARGMEMF_ImmediateDisp if it's not set already (member support is just used as an offset)
Fail ( " Member suffix syntax is not yet supported " , instNode , true ) ;
failed = true ;
}
}
}
if ( mayClobberMem )
hasMemoryClobber = true ;
//debugLineSequenceStr += StrFormat("%d_", asmInst.mDebugLine);
int curDebugLine = asmInst . mDebugLine ;
int debugLineDelta = ( lastDebugLine > 0 ) ? curDebugLine - lastDebugLine : curDebugLine ;
lastDebugLine = curDebugLine ;
//String encodedDebugLineDelta;
//EncodeULEB32(debugLineDelta, encodedDebugLineDelta);
//debugLineSequenceStr += encodedDebugLineDelta + "_";
if ( curDebugLineDeltaValue ! = debugLineDelta )
{
maybeEmitDebugLineRun ( ) ;
curDebugLineDeltaValue = debugLineDelta ;
}
+ + curDebugLineDeltaRunCount ;
// run instruction through LLVM for better semantic errors (can be slow in debug; feel free to comment out this scopeData if it's intolerable; the errors will still be caught at compile time)
//if (false)
{
BfInlineAsmInstruction : : AsmInst tempAsmInst ( asmInst ) ;
tempAsmInst . mLabel = fakeLabel ;
for ( auto & arg : tempAsmInst . mArgs )
{
if ( ( arg . mType = = BfInlineAsmInstruction : : AsmArg : : ARGTYPE_IntReg ) & & ! arg . mReg . empty ( ) & & ( arg . mReg [ 0 ] = = ' $ ' ) )
{
// if we've rewritten a local variable instruction arg to use a $-prefixed input, we can't pass that to LLVM
// at this stage as it won't recognize it; the actual compilation would have changed all these to use actual
// memory operand syntax first. However, those changes all work down in LLVM to printIntelMemReference inside
// of X86AsmPrinter.cpp, and that always results in a [bracketed] memory access string no matter what, which
// means for our semantic checking purposes here it's sufficient to just use "[eax]" for all such cases,
// rather than go through an even more expensive setup & teardown process to use the AsmPrinter itself.
arg . mType = BfInlineAsmInstruction : : AsmArg : : ARGTYPE_Memory ;
arg . mMemFlags = BfInlineAsmInstruction : : AsmArg : : ARGMEMF_BaseReg ;
arg . mReg = " eax " ;
}
}
String llvmError ;
if ( ! mCpu - > ParseInlineAsmInstructionLLVM ( tempAsmInst . ToString ( ) , llvmError ) )
{
Fail ( StrFormat ( " Inline asm error: %s " , llvmError . c_str ( ) ) , instNode , true ) ;
failed = true ;
}
}
}
dstAsmText + = asmInst . ToString ( ) ;
dstAsmText + = " \n " ;
}
}
maybeEmitDebugLineRun ( ) ; // leftovers
if ( failed )
{
RestoreScopeState ( & prevScope ) ;
return ;
}
// prepare constraints/clobbers
{
for ( int iRegCheck = 0 ; regClobberNames [ iRegCheck ] ! = nullptr ; + + iRegCheck )
{
if ( regClobberFlags & ( 1 < < iRegCheck ) )
clobberStr + = StrFormat ( " ~{%s}, " , regClobberNames [ iRegCheck ] ) ;
}
for ( int iRegCheck = 0 ; iRegCheck < 8 ; + + iRegCheck )
{
if ( regClobberFlags & ( REGCLOBBERF_XMM0 < < iRegCheck ) )
clobberStr + = StrFormat ( " ~{xmm%d}, " , iRegCheck ) ;
if ( regClobberFlags & ( REGCLOBBERF_FPST0 < < iRegCheck ) )
clobberStr + = StrFormat ( " ~{fp%d},~{st(%d)}, " , iRegCheck , iRegCheck ) ; // both fp# and st(#) are listed in X86RegisterInfo.td
if ( regClobberFlags & ( REGCLOBBERF_MM0 < < iRegCheck ) )
clobberStr + = StrFormat ( " ~{mm%d}, " , iRegCheck ) ;
}
// add wrapping instructions to preserve certain regs (e.g. ESI), due to LLVM bypassing register allocator when choosing a base register
//CDH TODO currently I'm only shielding against ESI stompage; people generally know not to mess with ESP & EBP, but ESI is still a "general" reg and should be allowed to be clobbered
//if (regClobberFlags & REGCLOBBERF_ESI)
//{
//CDH TODO Bah! This doesn't actually work, because if you do any local variable access after mutating ESI, the variable substitution could have generated a base address dependency
// on ESI which will not expect it to have changed, e.g. "mov esi, var\ninc esi\nmov var, esi\n" dies if "var" gets internally rewritten to "[esi + displacement]". What to do? Hmm.
//dstAsmText = String("push esi\n") + dstAsmText + String("pop esi\n");
//}
if ( hasMemoryClobber )
clobberStr + = " ~{memory}, " ;
clobberStr + = " ~{dirflag},~{fpsr},~{flags} " ;
constraintStr + = clobberStr ;
}
bool wantsDIData = ( mBfIRBuilder - > DbgHasInfo ( ) ) & & ( ! mCurMethodInstance - > mIsUnspecialized ) & & ( mHasFullDebugInfo ) ;
if ( wantsDIData )
{
static int sVarNum = 0 ;
String varName ( StrFormat ( " __asmLines_%d.%s " , + + sVarNum , debugLineSequenceStr . c_str ( ) ) ) ;
auto varType = GetPrimitiveType ( BfTypeCode_Int32 ) ;
auto allocaInst = mBfIRBuilder - > CreateAlloca ( varType - > mLLVMType , 0 , varName + " .addr " ) ;
allocaInst - > setAlignment ( varType - > mAlign ) ;
//paramVar->mAddr = allocaInst;
auto varValue = GetConstValue ( 0 , varType ) ;
auto diVariable = mDIBuilder - > createAutoVariable ( mCurMethodState - > mCurScope - > mDIScope ,
varName . c_str ( ) , mCurFilePosition . mFileInstance - > mDIFile , mCurFilePosition . mCurLine , varType - > mDIType /*, true*/ ) ;
//auto varValue = llvm::ConstantInt::getTrue(*mLLVMContext);
//auto varValue = GetDefaultValue(varType);
//auto varValue = CreateGlobalConstValue(varName, llvm::ConstantInt::getTrue(*mLLVMContext), true);
//auto varValue = AllocGlobalVariable(*mIRModule, diType->getType(), false, GlobalValue::ExternalLinkage, llvm::ConstantInt::getTrue(*mLLVMContext), varName.c_str());
//auto diVariable = mDIBuilder->createGlobalVariable(mCurMethodState->mCurScope->mDIScope, varName.c_str(), "", mCurFilePosition.mFileInstance->mDIFile, mCurFilePosition.mCurLine, diType, false, varValue);
//BasicBlock* block = mBfIRBuilder->GetInsertBlock();
//auto declareVar = mDIBuilder->insertDeclare(varValue, diVariable, mBfIRBuilder->GetInsertBlock());
2022-07-26 13:27:03 -04:00
auto declareVar = mDIBuilder - > insertDeclare ( allocaInst , diVariable , mDIBuilder - > createExpression ( ) ,
2019-08-23 11:56:54 -07:00
mIRBuilder - > getCurrentDebugLocation ( ) , mBfIRBuilder - > GetInsertBlock ( ) ) ;
//auto declareVar = mDIBuilder->insertDbgValueIntrinsic(varValue, 0, diVariable, mBfIRBuilder->GetInsertBlock());
declareVar - > setDebugLoc ( mIRBuilder - > getCurrentDebugLocation ( ) ) ;
}
/*
BfIRValue testValue = NULL ;
for ( int i = 0 ; i < ( int ) mCurMethodState - > mLocals . size ( ) ; i + + )
{
auto & checkLocal = mCurMethodState - > mLocals [ i ] ;
if ( checkLocal . mName = = " i " )
{
testValue = checkLocal . mAddr ;
break ;
}
}
*/
//BF_ASSERT((testValue != NULL) && "Need local variable \"i\"");
//if (testValue != NULL)
{
//Type* voidPtrType = Type::getInt8PtrTy(*mLLVMContext);
//if (mContext->mAsmObjectCheckFuncType == NULL)
//{
//Array<Type*> paramTypes;
//paramTypes.push_back(voidPtrType);
//mContext->mAsmObjectCheckFuncType = FunctionType::get(Type::getVoidTy(*mLLVMContext), paramTypes, false);
//}
FunctionType * funcType = FunctionType : : get ( Type : : getVoidTy ( * mLLVMContext ) , paramTypes , false ) ;
//SizedArray<Value*, 1> llvmArgs;
//llvmArgs.push_back(testValue);
//CDH REMOVE NOTE
//generates IR (e.g.):
// call void asm sideeffect "#4\0Anop\0Anop\0Amovl %eax, %eax\0Anop\0Anop", "~{cc},~{dirflag},~{fpsr},~{flags},~{eax}"() #0, !dbg !492
static int asmIdx = 0 ;
asmIdx + + ;
String asmStr = StrFormat ( " #%d \n " , asmIdx ) +
//"nop\nnop\nmovl $0, %eax\nincl %eax\nmovl %eax, $0\nmovl $$0, %ecx\nmovl $$0, %esp\nnop\nnop";
//"nop\nnop\nmovl ($0), %eax\nincl %eax\nmovl %eax, ($0)\nmovl $$0, %ecx\nmovl $$0, %esp\nnop\nnop";
//"nop\nnop\nmovl %eax, %eax\nmovl $$0, %ecx\nmovl $$0, %esp\nnop\nnop";
//"nop\nnop\nmovl %eax, %eax\nnop\nnop";
//"nop\nnop\n.byte 0x0F\n.byte 0xC7\n.byte 0xF0\nmov eax, 7\nmov ecx, 0\ncpuid\nmov eax, dword ptr $0\ninc eax\nmov dword ptr $0, eax\nmov ecx, 0\nmov esp, 0\nnop\nnop"; // rdrand test
dstAsmText ;
llvm : : InlineAsm * inlineAsm = llvm : : InlineAsm : : get ( funcType ,
//asmStr.c_str(), "~{r},~{cc},~{dirflag},~{fpsr},~{flags},~{eax},~{memory},~{esi},~{esp}", true,
//asmStr.c_str(), "~{cc},~{dirflag},~{fpsr},~{flags},~{memory},~{ecx},~{esp}", true,
//DOES NOT WORK (mem not written back to from reg:
//asmStr.c_str(), "+r,~{cc},~{dirflag},~{fpsr},~{flags},~{memory},~{eax},~{ecx},~{esp}", true,
//asmStr.c_str(), "+rm,~{cc},~{dirflag},~{fpsr},~{flags},~{memory},~{eax},~{ecx},~{esp}", true,
asmStr . c_str ( ) , constraintStr . c_str ( ) , true ,
false , /*llvm::InlineAsm::AD_ATT*/ llvm : : InlineAsm : : AD_Intel ) ;
llvm : : CallInst * callInst = mIRBuilder - > CreateCall ( inlineAsm , llvmArgs ) ;
//llvm::CallInst* callInst = mIRBuilder->CreateCall(inlineAsm);
callInst - > addAttribute ( llvm : : AttributeSet : : FunctionIndex , llvm : : Attribute : : NoUnwind ) ;
}
RestoreScopeState ( & prevScope ) ;
# endif
2022-07-26 13:27:03 -04:00
}