diff --git a/IDEHelper/Backend/BeIRCodeGen.cpp b/IDEHelper/Backend/BeIRCodeGen.cpp index 89d1e3c5..664e01f5 100644 --- a/IDEHelper/Backend/BeIRCodeGen.cpp +++ b/IDEHelper/Backend/BeIRCodeGen.cpp @@ -379,9 +379,11 @@ BeType* BeIRCodeGen::GetBeType(BfTypeCode typeCode, bool& isSigned) else return llvm::Type::getInt64Ty(*mLLVMContext);*/ case BfTypeCode_Float: + isSigned = true; beTypeCode = BeTypeCode_Float; break; case BfTypeCode_Double: + isSigned = true; beTypeCode = BeTypeCode_Double; break; } @@ -2330,6 +2332,13 @@ void BeIRCodeGen::HandleNextCmd() SetResult(curId, mBeModule->CreateRet(val)); } break; + case BfIRCmd_CreateSetRet: + { + CMD_PARAM(BeValue*, val); + CMD_PARAM(int, returnTypeId); + SetResult(curId, mBeModule->CreateSetRet(val, returnTypeId)); + } + break; case BfIRCmd_CreateRetVoid: { mBeModule->CreateRetVoid(); @@ -2433,7 +2442,9 @@ void BeIRCodeGen::HandleNextCmd() } else { - if (attribute == BFIRAttribute_AlwaysInline) + if (attribute == BfIRAttribute_VarRet) + func->mIsVarReturn = true; + else if (attribute == BFIRAttribute_AlwaysInline) func->mAlwaysInline = true; else if (attribute == BFIRAttribute_NoUnwind) func->mNoUnwind = true; @@ -3483,3 +3494,33 @@ BeType* BeIRCodeGen::GetBeTypeById(int id) { return GetTypeEntry(id).mBeType; } + +BeState BeIRCodeGen::GetState() +{ + BeState state; + state.mActiveFunction = mActiveFunction; + state.mSavedDebugLocs = mSavedDebugLocs; + state.mHasDebugLoc = mHasDebugLoc; + + state.mActiveBlock = mBeModule->mActiveBlock; + state.mInsertPos = mBeModule->mInsertPos; + state.mCurDbgLoc = mBeModule->mCurDbgLoc; + state.mPrevDbgLocInline = mBeModule->mPrevDbgLocInline; + state.mLastDbgLoc = mBeModule->mLastDbgLoc; + + return state; +} + +void BeIRCodeGen::SetState(const BeState& state) +{ + mActiveFunction = state.mActiveFunction; + mBeModule->mActiveFunction = mActiveFunction; + mSavedDebugLocs = state.mSavedDebugLocs; + mHasDebugLoc = state.mHasDebugLoc; + + mBeModule->mActiveBlock = state.mActiveBlock; + mBeModule->mInsertPos = state.mInsertPos; + mBeModule->mCurDbgLoc = state.mCurDbgLoc; + mBeModule->mPrevDbgLocInline = state.mPrevDbgLocInline; + mBeModule->mLastDbgLoc = state.mLastDbgLoc; +} diff --git a/IDEHelper/Backend/BeIRCodeGen.h b/IDEHelper/Backend/BeIRCodeGen.h index 0f3beee8..d3ae1e25 100644 --- a/IDEHelper/Backend/BeIRCodeGen.h +++ b/IDEHelper/Backend/BeIRCodeGen.h @@ -53,6 +53,19 @@ public: } }; +class BeState +{ +public: + BeFunction* mActiveFunction; + Array mSavedDebugLocs; + bool mHasDebugLoc; + + BeBlock* mActiveBlock; + int mInsertPos; + BeDbgLoc* mCurDbgLoc; + BeDbgLoc* mPrevDbgLocInline; + BeDbgLoc* mLastDbgLoc; +}; template class CmdParamVec : public SizedArray @@ -139,6 +152,9 @@ public: BeMDNode* GetBeMetadata(int streamId); BeType* GetBeTypeById(int id); + + BeState GetState(); + void SetState(const BeState& state); }; NS_BF_END \ No newline at end of file diff --git a/IDEHelper/Backend/BeModule.cpp b/IDEHelper/Backend/BeModule.cpp index 4c563d1b..39484c71 100644 --- a/IDEHelper/Backend/BeModule.cpp +++ b/IDEHelper/Backend/BeModule.cpp @@ -2349,6 +2349,7 @@ String BeModule::ToString(BeFunction* wantFunc) str += " void"; } break; + DISPLAY_INST2(BeSetRetInst, "setret", mRetValue, mReturnTypeId); case BeCallInst::TypeId: { auto castedInst = (BeCallInst*)inst; @@ -3383,6 +3384,15 @@ BeRetInst* BeModule::CreateRet(BeValue* value) return inst; } +BeSetRetInst* BeModule::CreateSetRet(BeValue* value, int returnTypeId) +{ + auto inst = mAlloc.Alloc(); + inst->mRetValue = value; + inst->mReturnTypeId = returnTypeId; + AddInst(inst); + return inst; +} + BeCallInst* BeModule::CreateCall(BeValue* func, const SizedArrayImpl& args) { auto inst = mOwnedValues.Alloc(); diff --git a/IDEHelper/Backend/BeModule.h b/IDEHelper/Backend/BeModule.h index ca3a90e2..bf09a910 100644 --- a/IDEHelper/Backend/BeModule.h +++ b/IDEHelper/Backend/BeModule.h @@ -518,6 +518,7 @@ public: String mName; #endif BfIRLinkageType mLinkageType; + bool mIsVarReturn; bool mAlwaysInline; bool mNoUnwind; bool mUWTable; @@ -539,6 +540,7 @@ public: mLinkageType = BfIRLinkageType_External; mModule = NULL; mDbgFunction = NULL; + mIsVarReturn = false; mAlwaysInline = false; mDidInlinePass = false; mNoUnwind = false; @@ -1265,6 +1267,15 @@ public: } }; +class BeSetRetInst : public BeRetInst +{ +public: + BE_VALUE_TYPE(BeSetRetInst, BeRetInst); + +public: + int32 mReturnTypeId; +}; + class BeCallInst : public BeInst { public: @@ -2311,6 +2322,7 @@ public: BeCondBrInst* CreateCondBr(BeValue* cond, BeBlock* trueBlock, BeBlock* falseBlock); BeRetInst* CreateRetVoid(); BeRetInst* CreateRet(BeValue* value); + BeSetRetInst* CreateSetRet(BeValue* value, int returnTypeId); BeCallInst* CreateCall(BeValue* func, const SizedArrayImpl& args); diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 20598a8b..41b0c033 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -5025,8 +5025,8 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance* bool forceBind = false; if (mModule->mCompiler->mCEMachine != NULL) - { - if (mModule->mIsConstModule) + { + if ((mModule->mIsConstModule) && (!methodInstance->mReturnType->IsVar())) { mModule->mCompiler->mCEMachine->QueueMethod(methodInstance, func); } @@ -5043,9 +5043,12 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance* else { CeEvalFlags evalFlags = CeEvalFlags_None; - auto constRet = mModule->mCompiler->mCEMachine->Call(targetSrc, mModule, methodInstance, irArgs, evalFlags, mExpectingType); + auto constRet = mModule->mCompiler->mCEMachine->Call(targetSrc, mModule, methodInstance, irArgs, evalFlags, mExpectingType); if (constRet) + { + BF_ASSERT(!constRet.mType->IsVar()); return constRet; + } } } } diff --git a/IDEHelper/Compiler/BfIRBuilder.cpp b/IDEHelper/Compiler/BfIRBuilder.cpp index 408566d6..91f11e30 100644 --- a/IDEHelper/Compiler/BfIRBuilder.cpp +++ b/IDEHelper/Compiler/BfIRBuilder.cpp @@ -730,6 +730,13 @@ BfIRValue BfIRConstHolder::CreateConstStructZero(BfIRType aggType) BfIRValue BfIRConstHolder::CreateConstAgg(BfIRType type, const BfSizedArray& values) { +#ifdef _DEBUG + for (auto& val : values) + { + BF_ASSERT(val); + } +#endif + BfConstantAgg* constant = mTempAlloc.Alloc(); constant->mConstType = BfConstType_Agg; constant->mType = type = type; @@ -4766,6 +4773,13 @@ BfIRValue BfIRBuilder::CreateRet(BfIRValue val) return retVal; } +BfIRValue BfIRBuilder::CreateSetRet(BfIRValue val, int returnTypeId) +{ + BfIRValue retVal = WriteCmd(BfIRCmd_CreateSetRet, val, returnTypeId); + NEW_CMD_INSERTED; + return retVal; +} + void BfIRBuilder::CreateRetVoid() { WriteCmd(BfIRCmd_CreateRetVoid); @@ -5391,4 +5405,22 @@ void BfIRBuilder::DbgCreateAnnotation(BfIRMDNode scope, const StringImpl& name, NEW_CMD_INSERTED; } +BfIRState BfIRBuilder::GetState() +{ + BfIRState state; + state.mActualInsertBlock = mActualInsertBlock; + state.mInsertBlock = mInsertBlock; + state.mActiveFunction = mActiveFunction; + state.mActiveFunctionHasBody = mActiveFunctionHasBody; + state.mSavedDebugLocs = mSavedDebugLocs; + return state; +} +void BfIRBuilder::SetState(const BfIRState& state) +{ + mActualInsertBlock = state.mActualInsertBlock; + mInsertBlock = state.mInsertBlock; + mActiveFunction = state.mActiveFunction; + mActiveFunctionHasBody = state.mActiveFunctionHasBody; + mSavedDebugLocs = state.mSavedDebugLocs; +} diff --git a/IDEHelper/Compiler/BfIRBuilder.h b/IDEHelper/Compiler/BfIRBuilder.h index 406b9635..83bdf55c 100644 --- a/IDEHelper/Compiler/BfIRBuilder.h +++ b/IDEHelper/Compiler/BfIRBuilder.h @@ -270,6 +270,7 @@ enum BfIRCmd : uint8 BfIRCmd_SetTailCall, BfIRCmd_SetCallAttribute, BfIRCmd_CreateRet, + BfIRCmd_CreateSetRet, BfIRCmd_CreateRetVoid, BfIRCmd_CreateUnreachable, BfIRCmd_Call_AddAttribute, @@ -627,6 +628,7 @@ enum BfIRAttribute BfIRAttribute_NoAlias, BfIRAttribute_NoCapture, BfIRAttribute_StructRet, + BfIRAttribute_VarRet, BfIRAttribute_ZExt, BfIRAttribute_ByVal, BfIRAttribute_Dereferencable, @@ -916,6 +918,15 @@ enum BfIRPopulateType BfIRPopulateType_Full_ForceDefinition }; +struct BfIRState +{ + BfIRBlock mActualInsertBlock; // Only when not ignoring writes + BfIRBlock mInsertBlock; + BfIRFunction mActiveFunction; + bool mActiveFunctionHasBody; + Array mSavedDebugLocs; +}; + class BfIRBuilder : public BfIRConstHolder { public: @@ -1227,6 +1238,7 @@ public: void SetTailCall(BfIRValue callInst); void SetCallAttribute(BfIRValue callInst, int paramIdx, BfIRAttribute attribute); BfIRValue CreateRet(BfIRValue val); + BfIRValue CreateSetRet(BfIRValue val, int returnTypeId); void CreateRetVoid(); void CreateUnreachable(); void Call_AddAttribute(BfIRValue callInst, int argIdx, BfIRAttribute attr); @@ -1315,6 +1327,9 @@ public: BfIRMDNode type, bool isLocalToUnit, BfIRValue val, BfIRMDNode Decl = BfIRMDNode()); BfIRMDNode DbgCreateLexicalBlock(BfIRMDNode scope, BfIRMDNode file, int line, int col); void DbgCreateAnnotation(BfIRMDNode scope, const StringImpl& name, BfIRValue value); + + BfIRState GetState(); + void SetState(const BfIRState& state); }; NS_BF_END diff --git a/IDEHelper/Compiler/BfIRCodeGen.cpp b/IDEHelper/Compiler/BfIRCodeGen.cpp index 9f1d8237..6f293c8e 100644 --- a/IDEHelper/Compiler/BfIRCodeGen.cpp +++ b/IDEHelper/Compiler/BfIRCodeGen.cpp @@ -3522,7 +3522,11 @@ void BfIRCodeGen::HandleNextCmd() NULL, llvm::GlobalValue::NotThreadLocal); } else - func->addAttribute(argIdx, LLVMMapAttribute(attribute)); + { + auto attr = LLVMMapAttribute(attribute); + if (attr != llvm::Attribute::None) + func->addAttribute(argIdx, attr); + } } break; case BfIRCmd_Func_AddAttribute1: diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index e56bd99f..f01a7e86 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -2731,7 +2731,7 @@ BfError* BfModule::Fail(const StringImpl& error, BfAstNode* refNode, bool isPers { BP_ZONE("BfModule::Fail"); - if (mIgnoreErrors) + if (mIgnoreErrors) { mHadIgnoredError = true; if (mAttributeState != NULL) @@ -13639,6 +13639,9 @@ void BfModule::DoAddLocalVariable(BfLocalVariable* localVar) void BfModule::DoLocalVariableDebugInfo(BfLocalVariable* localVarDef, bool doAliasValue, BfIRValue declareBefore, BfIRInitType initType) { + if (localVarDef->mResolvedType->IsVar()) + return; + if ((mBfIRBuilder->DbgHasInfo()) && ((mCurMethodInstance == NULL) || (!mCurMethodInstance->mIsUnspecialized)) && (mHasFullDebugInfo) && @@ -14460,7 +14463,7 @@ void BfModule::CreateReturn(BfIRValue val) mBfIRBuilder->CreateRet(val); } -void BfModule::EmitReturn(BfIRValue val) +void BfModule::EmitReturn(const BfTypedValue& val) { if (mCurMethodState->mIRExitBlock) { @@ -14468,11 +14471,23 @@ void BfModule::EmitReturn(BfIRValue val) { if (val) // We allow for val to be empty if we know we've already written the value to mRetVal { - BfIRValue retVal = mCurMethodState->mRetVal.mValue; - if (!mCurMethodState->mRetVal) - retVal = mBfIRBuilder->CreateLoad(mCurMethodState->mRetValAddr); - - mBfIRBuilder->CreateStore(val, retVal); + if ((mCurMethodState->mRetValAddr) || (mCurMethodState->mRetVal)) + { + BfIRValue retVal = mCurMethodState->mRetVal.mValue; + if (!mCurMethodState->mRetVal) + retVal = mBfIRBuilder->CreateLoad(mCurMethodState->mRetValAddr); + + mBfIRBuilder->CreateStore(val.mValue, retVal); + } + else if (mIsConstModule) + { + mBfIRBuilder->CreateSetRet(val.mValue, val.mType->mTypeId); + } + else + { + // Just ignore + BF_ASSERT(mCurMethodInstance->mReturnType->IsVar()); + } } } EmitDeferredScopeCalls(true, NULL, mCurMethodState->mIRExitBlock); @@ -14486,7 +14501,7 @@ void BfModule::EmitReturn(BfIRValue val) if (mCurMethodInstance->mReturnType->IsValuelessType()) mBfIRBuilder->CreateRetVoid(); else - mBfIRBuilder->CreateRet(val); + mBfIRBuilder->CreateRet(val.mValue); } } @@ -15601,7 +15616,7 @@ void BfModule::SetupIRMethod(BfMethodInstance* methodInstance, BfIRFunction func return; if (mCompiler->mOptions.mNoFramePointerElim) - mBfIRBuilder->Func_AddAttribute(func, -1, BFIRAttribute_NoFramePointerElim); + mBfIRBuilder->Func_AddAttribute(func, -1, BFIRAttribute_NoFramePointerElim); mBfIRBuilder->Func_AddAttribute(func, -1, BFIRAttribute_NoUnwind); if (mSystem->mPtrSize == 8) // We need unwind info for debugging mBfIRBuilder->Func_AddAttribute(func, -1, BFIRAttribute_UWTable); @@ -15609,6 +15624,8 @@ void BfModule::SetupIRMethod(BfMethodInstance* methodInstance, BfIRFunction func if (methodInstance == NULL) return; + if (methodInstance->mReturnType->IsVar()) + mBfIRBuilder->Func_AddAttribute(func, -1, BfIRAttribute_VarRet); if (methodDef->mImportKind == BfImportKind_Export) mBfIRBuilder->Func_AddAttribute(func, -1, BFIRAttribute_DllExport); if (methodDef->mIsNoReturn) @@ -19278,6 +19295,12 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup) else if (!skipBody) { bool isEmptyBodied = BfNodeDynCast(methodDef->mBody) != NULL; + + bool wantsRetVal = true; + if ((mIsConstModule) && (methodDef->mMethodType != BfMethodType_CtorCalcAppend)) + wantsRetVal = false; + else if (mCurMethodInstance->mReturnType->IsVar()) + wantsRetVal = false; if ((!mCurMethodInstance->mReturnType->IsValuelessType()) && (!isEmptyBodied)) { @@ -19291,7 +19314,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup) mBfIRBuilder->ClearDebugLocation(storeInst); mCurMethodState->mRetValAddr = allocaInst; } - else + else if (wantsRetVal) { auto allocaInst = AllocLocalVariable(mCurMethodInstance->mReturnType, "__return", false); mCurMethodState->mRetVal = BfTypedValue(allocaInst, mCurMethodInstance->mReturnType, true); @@ -19414,7 +19437,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup) { mCurMethodState->mHadReturn = true; retVal = LoadOrAggregateValue(retVal); - EmitReturn(retVal.mValue); + EmitReturn(retVal); } } } @@ -21211,14 +21234,13 @@ genericParam->mExternType = GetPrimitiveType(BfTypeCode_Var); (methodDef->mReturnTypeRef != NULL)) { SetAndRestoreValue prevIngoreErrors(mIgnoreErrors, mIgnoreErrors || (methodDef->GetPropertyDeclaration() != NULL)); - resolvedReturnType = ResolveTypeRef(methodDef->mReturnTypeRef, BfPopulateType_Declaration, - (BfResolveTypeRefFlags)(BfResolveTypeRefFlag_NoResolveGenericParam | BfResolveTypeRefFlag_AllowRef | BfResolveTypeRefFlag_AllowRefGeneric)); - if ((resolvedReturnType != NULL) && (resolvedReturnType->IsVar()) && (methodDef->mMethodType != BfMethodType_Mixin)) - { - Fail("Cannot declare var return types", methodDef->mReturnTypeRef); - resolvedReturnType = GetPrimitiveType(BfTypeCode_Var); - } + BfResolveTypeRefFlags flags = (BfResolveTypeRefFlags)(BfResolveTypeRefFlag_NoResolveGenericParam | BfResolveTypeRefFlag_AllowRef | BfResolveTypeRefFlag_AllowRefGeneric); + + if ((methodDef->mIsConstEval) && (methodDef->mReturnTypeRef->IsA())) + resolvedReturnType = GetPrimitiveType(BfTypeCode_Var); + else + resolvedReturnType = ResolveTypeRef(methodDef->mReturnTypeRef, BfPopulateType_Declaration, flags); if (resolvedReturnType == NULL) resolvedReturnType = GetPrimitiveType(BfTypeCode_Var); diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index 7c83fcef..d1a27ab9 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -1552,7 +1552,7 @@ public: // Util void CreateReturn(BfIRValue val); - void EmitReturn(BfIRValue val); + void EmitReturn(const BfTypedValue& val); void EmitDefaultReturn(); void EmitDeferredCall(BfModuleMethodInstance moduleMethodInstance, SizedArrayImpl& llvmArgs, BfDeferredBlockFlags flags = BfDeferredBlockFlag_None); bool AddDeferredCallEntry(BfDeferredCallEntry* deferredCallEntry, BfScopeData* scope); diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index d1473bc4..a53a0b5d 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -1148,7 +1148,7 @@ void BfMethodInstance::GetIRFunctionInfo(BfModule* module, BfIRType& returnType, auto irReturnType = module->GetIRLoweredType(loweredReturnTypeCode, loweredReturnTypeCode2); returnType = irReturnType; } - else if (mReturnType->IsValuelessType()) + else if ((mReturnType->IsValuelessType()) || (mReturnType->IsVar())) { auto voidType = module->GetPrimitiveType(BfTypeCode_None); returnType = module->mBfIRBuilder->MapType(voidType); diff --git a/IDEHelper/Compiler/BfStmtEvaluator.cpp b/IDEHelper/Compiler/BfStmtEvaluator.cpp index c471d699..753d473c 100644 --- a/IDEHelper/Compiler/BfStmtEvaluator.cpp +++ b/IDEHelper/Compiler/BfStmtEvaluator.cpp @@ -3787,9 +3787,9 @@ void BfModule::Visit(BfThrowStatement* throwStmt) Fail("Exceptions are not supported", throwStmt->mThrowToken); if (mCurMethodInstance->mReturnType->IsVoid()) - EmitReturn(BfIRValue()); + EmitReturn(BfTypedValue()); else - EmitReturn(GetDefaultValue(mCurMethodInstance->mReturnType)); + EmitReturn(GetDefaultTypedValue(mCurMethodInstance->mReturnType)); } void BfModule::Visit(BfDeleteStatement* deleteStmt) @@ -4927,7 +4927,7 @@ void BfModule::Visit(BfReturnStatement* returnStmt) MarkScopeLeft(&mCurMethodState->mHeadScope); if (retType->IsVoid()) { - EmitReturn(BfIRValue()); + EmitReturn(BfTypedValue()); return; } @@ -4937,11 +4937,13 @@ void BfModule::Visit(BfReturnStatement* returnStmt) return; } - EmitReturn(GetDefaultValue(retType)); + EmitReturn(GetDefaultTypedValue(retType)); return; } BfType* expectingReturnType = retType; + if ((expectingReturnType != NULL) && (expectingReturnType->IsVar())) + expectingReturnType = NULL; BfType* origType; BfExprEvaluator exprEvaluator(this); @@ -4964,21 +4966,21 @@ void BfModule::Visit(BfReturnStatement* returnStmt) } else { - EmitReturn(BfIRValue()); + EmitReturn(BfTypedValue()); return; } } if (retValue.mType->IsVar()) { - EmitReturn(BfIRValue()); + EmitReturn(BfTypedValue()); } else if (retValue.mType->IsVoid()) { if (retType->IsVoid()) { Warn(0, "Returning void value", returnStmt->mReturnToken); - EmitReturn(BfIRValue()); + EmitReturn(BfTypedValue()); } } else @@ -4987,7 +4989,7 @@ void BfModule::Visit(BfReturnStatement* returnStmt) { expectingReturnType = NULL; Fail("Attempting to return value from void method", returnStmt->mExpression); - EmitReturn(BfIRValue()); + EmitReturn(BfTypedValue()); return; } @@ -4997,9 +4999,9 @@ void BfModule::Visit(BfReturnStatement* returnStmt) } if (!alreadyWritten) - EmitReturn(LoadOrAggregateValue(retValue).mValue); + EmitReturn(LoadOrAggregateValue(retValue)); else - EmitReturn(BfIRValue()); + EmitReturn(BfTypedValue()); } } diff --git a/IDEHelper/Compiler/CeMachine.cpp b/IDEHelper/Compiler/CeMachine.cpp index b3ad6680..1a32d9c6 100644 --- a/IDEHelper/Compiler/CeMachine.cpp +++ b/IDEHelper/Compiler/CeMachine.cpp @@ -83,6 +83,7 @@ static CeOpInfo gOpInfo[] = { {"InvalidOp"}, {"Ret"}, + {"SetRet", CEOI_None, CEOI_IMM32}, {"Jmp", CEOI_None, CEOI_JMPREL}, {"JmpIf", CEOI_None, CEOI_JMPREL, CEOI_FrameRef}, {"JmpIfNot", CEOI_None, CEOI_JMPREL, CEOI_FrameRef}, @@ -1123,13 +1124,11 @@ void CeBuilder::HandleParams() int frameOffset = 0; - if (retType->mSize > 0) + if (mCeFunction->mMaxReturnSize > 0) { mReturnVal.mKind = CeOperandKind_AllocaAddr; mReturnVal.mFrameOfs = frameOffset; - mReturnVal.mType = retType; - - frameOffset += retType->mSize; + frameOffset += mCeFunction->mMaxReturnSize; } int paramOfs = 0; @@ -1157,6 +1156,7 @@ void CeBuilder::HandleParams() void CeBuilder::Build() { auto irCodeGen = mCeMachine->mCeModule->mBfIRBuilder->mBeIRCodeGen; + auto irBuilder = mCeMachine->mCeModule->mBfIRBuilder; auto beModule = irCodeGen->mBeModule; mCeFunction->mFailed = true; @@ -1168,16 +1168,18 @@ void CeBuilder::Build() auto methodDef = methodInstance->mMethodDef; BfMethodInstance dupMethodInstance; - dupMethodInstance.CopyFrom(methodInstance); - //dupMethodInstance.mIRFunction = workItem.mFunc; + dupMethodInstance.CopyFrom(methodInstance); dupMethodInstance.mIsReified = true; dupMethodInstance.mInCEMachine = false; // Only have the original one int startFunctionCount = (int)beModule->mFunctions.size(); - //int startGlobalVariableCount = (int)beModule->mGlobalVariables.size(); - + mCeMachine->mCeModule->mHadBuildError = false; + auto irState = irBuilder->GetState(); + auto beState = irCodeGen->GetState(); mCeMachine->mCeModule->ProcessMethod(&dupMethodInstance, true); + irCodeGen->SetState(beState); + irBuilder->SetState(irState); if (!dupMethodInstance.mIRFunction) { @@ -1197,6 +1199,7 @@ void CeBuilder::Build() continue; CeFunction* innerFunction = new CeFunction(); + innerFunction->mIsVarReturn = beFunction->mIsVarReturn; innerFunction->mCeInnerFunctionInfo = new CeInnerFunctionInfo(); innerFunction->mCeInnerFunctionInfo->mName = beFunction->mName; innerFunction->mCeInnerFunctionInfo->mBeFunction = beFunction; @@ -1294,6 +1297,17 @@ void CeBuilder::Build() } } break; + case BeRetInst::TypeId: + case BeSetRetInst::TypeId: + { + auto castedInst = (BeRetInst*)inst; + if (castedInst->mRetValue != NULL) + { + auto retType = castedInst->mRetValue->GetType(); + mCeFunction->mMaxReturnSize = BF_MAX(retType->mSize, mCeFunction->mMaxReturnSize); + } + } + break; } } } @@ -1788,18 +1802,27 @@ void CeBuilder::Build() } break; case BeRetInst::TypeId: - { + case BeSetRetInst::TypeId: + { auto castedInst = (BeRetInst*)inst; if (castedInst->mRetValue != NULL) { - auto mcVal = GetOperand(castedInst->mRetValue); + auto mcVal = GetOperand(castedInst->mRetValue); BF_ASSERT(mReturnVal.mKind == CeOperandKind_AllocaAddr); EmitSizedOp(CeOp_Move_8, mcVal, NULL, true); - Emit((int32)mReturnVal.mFrameOfs); + Emit((int32)mReturnVal.mFrameOfs); + } + + if (instType == BeRetInst::TypeId) + Emit(CeOp_Ret); + else + { + auto setRetInst = (BeSetRetInst*)inst; + Emit(CeOp_SetRetType); + Emit((int32)setRetInst->mReturnTypeId); } - Emit(CeOp_Ret); } - break; + break; case BeCmpInst::TypeId: { auto castedInst = (BeCmpInst*)inst; @@ -3483,6 +3506,9 @@ BfIRValue CeMachine::CreateConstant(BfModule* module, uint8* ptr, BfType* bfType { auto typeInst = bfType->ToTypeInstance(); + if (typeInst->mIsUnion) + return BfIRValue(); + uint8* instData = ptr; // if ((typeInst->IsObject()) && (!isBaseType)) // { @@ -3744,11 +3770,12 @@ BfIRValue CeMachine::CreateConstant(BfModule* module, uint8* ptr, BfType* bfType instPtr = &ceFunction->mCode[0]; \ CE_CHECKSTACK(); -bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* startFramePtr) +bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* startFramePtr, BfType*& returnType) { mExecuteId++; CeFunction* ceFunction = startFunction; + returnType = startFunction->mMethodInstance->mReturnType; uint8* memStart = &mMemory[0]; int memSize = mMemory.mSize; uint8* instPtr = (ceFunction->mCode.IsEmpty()) ? NULL : &ceFunction->mCode[0]; @@ -3758,11 +3785,11 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* volatile bool* cancelPtr = &mCompiler->mCanceling; - auto _GetCurFrame = [&]() { CeFrame ceFrame; ceFrame.mFunction = ceFunction; + ceFrame.mReturnType = returnType; ceFrame.mFrameAddr = framePtr - memStart; ceFrame.mStackAddr = stackPtr - memStart; ceFrame.mInstPtr = instPtr; @@ -4026,6 +4053,7 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* Fail(_GetCurFrame(), StrFormat("Unable to invoke extern method '%s'", mCeModule->MethodToString(checkFunction->mMethodInstance).c_str())); return false; } + if (!checkFunction->mFailed) return true; @@ -4070,10 +4098,18 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* instPtr = ceFrame.mInstPtr; stackPtr = memStart + ceFrame.mStackAddr; framePtr = memStart + ceFrame.mFrameAddr; + returnType = ceFrame.mReturnType; mCallStack.pop_back(); } break; + case CeOp_SetRetType: + { + int typeId = CE_GETINST(int32); + returnType = GetBfType(typeId); + BF_ASSERT(returnType != NULL); + } + break; case CeOp_Jmp: { auto relOfs = CE_GETINST(int32); @@ -4666,6 +4702,8 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* bool handled = false; if (!_CheckFunction(callFunction, handled)) return false; + if (callFunction->mIsVarReturn) + _Fail("Illegal call to method with 'var' return."); if (handled) break; @@ -5284,14 +5322,17 @@ void CeMachine::PrepareFunction(CeFunction* ceFunction, CeBuilder* parentBuilder BF_ASSERT(!ceFunction->mInitialized); ceFunction->mInitialized = true; + ceFunction->mGenerating = true; CeBuilder ceBuilder; ceBuilder.mParentBuilder = parentBuilder; ceBuilder.mPtrSize = mCeModule->mCompiler->mSystem->mPtrSize; ceBuilder.mCeMachine = this; - ceBuilder.mCeFunction = ceFunction; + ceBuilder.mCeFunction = ceFunction; ceBuilder.Build(); + ceFunction->mGenerating = false; + /*if (!ceFunction->mCode.IsEmpty()) { CeDumpContext dumpCtx; @@ -5375,6 +5416,7 @@ CeFunction* CeMachine::GetFunction(BfMethodInstance* methodInstance, BfIRValue f BF_ASSERT(ceFunctionInfo->mCeFunction == NULL); ceFunction = new CeFunction(); + ceFunction->mIsVarReturn = methodInstance->mReturnType->IsVar(); ceFunction->mCeFunctionInfo = ceFunctionInfo; ceFunction->mMethodInstance = methodInstance; @@ -5441,7 +5483,7 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns SetAndRestoreValue prevTargetSrc(mCurTargetSrc, targetSrc); SetAndRestoreValue prevModule(mCurModule, module); SetAndRestoreValue prevMethodInstance(mCurMethodInstance, methodInstance); - SetAndRestoreValue prevExpectingType(mCurExpectingType, expectingType); + SetAndRestoreValue prevExpectingType(mCurExpectingType, expectingType); // Reentrancy may occur as methods need defining SetAndRestoreValue prevMethodStateInConstEval(module->mCurMethodState, NULL); @@ -5453,7 +5495,7 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns Fail("Non-constant append alloc"); return BfTypedValue(); } - } + } int thisArgIdx = -1; int appendAllocIdx = -1; @@ -5505,6 +5547,13 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns bool added = false; CeFunction* ceFunction = GetFunction(methodInstance, BfIRValue(), added); + + if (ceFunction->mGenerating) + { + Fail("Recursive var-inference"); + return BfTypedValue(); + } + if (!ceFunction->mInitialized) PrepareFunction(ceFunction, NULL); @@ -5631,15 +5680,15 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns } addr_ce retAddr = 0; - auto returnType = methodInstance->mReturnType; - if (!returnType->IsValuelessType()) + if (ceFunction->mMaxReturnSize > 0) { - int retSize = methodInstance->mReturnType->mSize; + int retSize = ceFunction->mMaxReturnSize; stackPtr -= retSize; retAddr = stackPtr - memStart; } - bool success = Execute(ceFunction, stackPtr - ceFunction->mFrameSize, stackPtr); + BfType* returnType = NULL; + bool success = Execute(ceFunction, stackPtr - ceFunction->mFrameSize, stackPtr, returnType); memStart = &mMemory[0]; addr_ce retInstAddr = retAddr; diff --git a/IDEHelper/Compiler/CeMachine.h b/IDEHelper/Compiler/CeMachine.h index 2f707a0f..6d53c964 100644 --- a/IDEHelper/Compiler/CeMachine.h +++ b/IDEHelper/Compiler/CeMachine.h @@ -65,6 +65,7 @@ enum CeOp : int16 { CeOp_InvalidOp, CeOp_Ret, + CeOp_SetRetType, CeOp_Jmp, CeOp_JmpIf, CeOp_JmpIfNot, @@ -331,8 +332,10 @@ public: CeInnerFunctionInfo* mCeInnerFunctionInfo; BfMethodInstance* mMethodInstance; CeFunctionKind mFunctionKind; + bool mGenerating; bool mInitialized; - bool mFailed; + bool mFailed; + bool mIsVarReturn; Array mCode; Array mFiles; Array mEmitTable; @@ -344,6 +347,7 @@ public: Array mInnerFunctions; String mGenError; int mFrameSize; + int mMaxReturnSize; int mId; public: @@ -352,10 +356,13 @@ public: mCeFunctionInfo = NULL; mCeInnerFunctionInfo = NULL; mFunctionKind = CeFunctionKind_Normal; + mGenerating = false; mInitialized = false; mMethodInstance = NULL; mFailed = false; + mIsVarReturn = false; mFrameSize = 0; + mMaxReturnSize = 0; mId = -1; } @@ -559,6 +566,7 @@ public: addr_ce mStackAddr; addr_ce mFrameAddr; uint8* mInstPtr; + BfType* mReturnType; public: CeFrame() @@ -567,6 +575,7 @@ public: mStackAddr = 0; mFrameAddr = 0; mInstPtr = NULL; + mReturnType = NULL; } }; @@ -621,7 +630,7 @@ public: BfAstNode* mCurTargetSrc; BfMethodInstance* mCurMethodInstance; BfModule* mCurModule; - BfType* mCurExpectingType; + BfType* mCurExpectingType; public: CeMachine(BfCompiler* compiler); @@ -648,7 +657,7 @@ public: CeErrorKind WriteConstant(CeConstStructData& data, BeConstant* constVal); BfIRValue CreateConstant(BfModule* module, uint8* ptr, BfType* type, BfType** outType = NULL); void CreateFunction(BfMethodInstance* methodInstance, CeFunction* ceFunction); - bool Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* startFramePtr); + bool Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* startFramePtr, BfType*& returnType); void PrepareFunction(CeFunction* methodInstance, CeBuilder* parentBuilder); void MapFunctionId(CeFunction* ceFunction); diff --git a/IDEHelper/Tests/src/ConstEval.bf b/IDEHelper/Tests/src/ConstEval.bf index f6d250b5..94284897 100644 --- a/IDEHelper/Tests/src/ConstEval.bf +++ b/IDEHelper/Tests/src/ConstEval.bf @@ -121,9 +121,26 @@ namespace Tests return sa.mA + sa.mB + tup.0 + tup.1 + arr[0] + arr[1]; } + [ConstEval] + static var StrToValue(String str) + { + if (str.Contains('.')) + return float.Parse(str).Value; + return int.Parse(str).Value; + } + + class ClassA + { + public const let cVal0 = StrToValue("123"); + public const let cVal1 = StrToValue("1.23"); + } + [Test] public static void TestBasics() { + Test.Assert(ClassA.cVal0 == 123); + Test.Assert(ClassA.cVal0 == 1.23); + const int fac = Factorial(8); Test.Assert(fac == 40320); const int fib = Fibonacci(27);