Sfoglia il codice sorgente

Interop fixes and tests, fixing xplat struct passing issues

Brian Fiete 5 anni fa
parent
commit
5da74382d4

+ 17 - 7
BeefLibs/corlib/src/Type.bf

@@ -509,13 +509,23 @@ namespace System
 		Let,
 	    Boolean,
 	    Int8,
-	    UInt8,
-	    Int16,
-	    UInt16,
-	    Int32,
-	    UInt32,
-	    Int64,
-	    UInt64, 
+		UInt8,
+		Int16,
+		UInt16,
+		Int24,
+		UInt24,
+		Int32,
+		UInt32,
+		Int40,
+		UInt40,
+		Int48,
+		UInt48,
+		Int56,
+		UInt56,
+		Int64,
+		UInt64,
+		Int128,
+		UInt128,
 	    Int,
 	    UInt,
 		IntUnknown,

+ 17 - 7
IDE/mintest/minlib/src/System/Type.bf

@@ -476,13 +476,23 @@ namespace System
 		Let,
 	    Boolean,
 	    Int8,
-	    UInt8,
-	    Int16,
-	    UInt16,
-	    Int32,
-	    UInt32,
-	    Int64,
-	    UInt64, 
+		UInt8,
+		Int16,
+		UInt16,
+		Int24,
+		UInt24,
+		Int32,
+		UInt32,
+		Int40,
+		UInt40,
+		Int48,
+		UInt48,
+		Int56,
+		UInt56,
+		Int64,
+		UInt64,
+		Int128,
+		UInt128,
 	    Int,
 	    UInt,
 		IntUnknown,

+ 16 - 0
IDEHelper/Backend/BeContext.cpp

@@ -71,6 +71,22 @@ BeStructType* BeContext::CreateStruct(const StringImpl& name)
 	return structType;
 }
 
+BeStructType* BeContext::CreateStruct(const SizedArrayImpl<BeType*>& types)
+{	
+	BeStructType** valuePtr = NULL;	
+	if (mAnonymousStructMap.TryGetValueWith(types, &valuePtr))	
+		return *valuePtr;	
+
+	Array<BeType*> key;
+	for (auto type : types)
+		key.Add(type);
+	
+	BeStructType* structType = CreateStruct("");
+	SetStructBody(structType, types, false);
+	mAnonymousStructMap.TryAdd(key, structType);	
+	return structType;
+}
+
 BePointerType* BeContext::GetPointerTo(BeType* beType)
 {
 	if (beType->mPointerType == NULL)

+ 3 - 1
IDEHelper/Backend/BeContext.h

@@ -226,14 +226,16 @@ public:
 	//BumpAllocator mAlloc;
 	BeType* mPrimitiveTypes[BeTypeCode_COUNT];
 	OwnedVector<BeType> mTypes;
+	Dictionary<Array<BeType*>, BeStructType*> mAnonymousStructMap;
 
 public:
 	void NotImpl();
 
 public:
 	BeContext();	
-	BeType* GetPrimitiveType(BeTypeCode typeCode);
+	BeType* GetPrimitiveType(BeTypeCode typeCode);	
 	BeStructType* CreateStruct(const StringImpl& name);
+	BeStructType* CreateStruct(const SizedArrayImpl<BeType*>& types);
 	BePointerType* GetPointerTo(BeType* beType);
 	void SetStructBody(BeStructType* structType, const SizedArrayImpl<BeType*>& types, bool packed);
 	BeSizedArrayType* CreateSizedArrayType(BeType* type, int length);

+ 28 - 1
IDEHelper/Backend/BeIRCodeGen.cpp

@@ -963,6 +963,13 @@ void BeIRCodeGen::HandleNextCmd()
 			SetResult(curId, mBeContext->CreateStruct(typeName));
 		}
 		break;
+	case BfIRCmd_CreateAnonymousStruct:
+		{
+			CMD_PARAM(CmdParamVec<BeType*>, members);
+			BeStructType* structType = mBeContext->CreateStruct(members);
+			SetResult(curId, structType);
+		}
+		break;
 	case BfIRCmd_StructSetBody:
 		{			
 			CMD_PARAM(BeType*, type);
@@ -2143,7 +2150,8 @@ void BeIRCodeGen::HandleNextCmd()
 			{
 				if (attribute == BfIRAttribute_StructRet)
 				{
-					BF_ASSERT(argIdx == 1);
+					auto valType = callInst->mArgs[argIdx - 1].mValue->GetType();
+					BF_ASSERT(valType->IsPointer());
 					callInst->mArgs[argIdx - 1].mStructRet = true;
 				}
 				else if (attribute == BfIRAttribute_ZExt)
@@ -2152,6 +2160,9 @@ void BeIRCodeGen::HandleNextCmd()
 					callInst->mArgs[argIdx - 1].mNoAlias = true;
 				else if (attribute == BfIRAttribute_NoCapture)
 					callInst->mArgs[argIdx - 1].mNoCapture = true;
+				else if (attribute == BfIRAttribute_ByVal)
+				{									
+				}
 				else
 					BF_FATAL("Unhandled");
 			}
@@ -2177,7 +2188,21 @@ void BeIRCodeGen::HandleNextCmd()
 				if (argIdx > 0)
 				{
 					if (attribute == BfIRAttribute_Dereferencable)
+					{
 						callInst->mArgs[argIdx - 1].mDereferenceableSize = arg;
+						if (auto func = BeValueDynCast<BeFunction>(callInst->mFunc))
+						{
+							BF_ASSERT(func->mParams[argIdx - 1].mDereferenceableSize == arg);
+						}
+					}
+					else if (attribute == BfIRAttribute_ByVal)
+					{
+						callInst->mArgs[argIdx - 1].mByRefSize = arg;
+						if (auto func = BeValueDynCast<BeFunction>(callInst->mFunc))
+						{
+							BF_ASSERT(func->mParams[argIdx - 1].mByValSize == arg);
+						}
+					}
 					else
 						BF_FATAL("Unhandled");
 				}
@@ -2242,6 +2267,8 @@ void BeIRCodeGen::HandleNextCmd()
 			{
 				if (attribute == BfIRAttribute_Dereferencable)
 					func->mParams[argIdx - 1].mDereferenceableSize = arg;
+				else if (attribute == BfIRAttribute_ByVal)				
+					func->mParams[argIdx - 1].mByValSize = arg;				
 				else
 					BF_FATAL("Unhandled");
 			}

+ 1 - 0
IDEHelper/Backend/BeModule.cpp

@@ -532,6 +532,7 @@ void BeFunction::HashContent(BeHashContext& hashCtx)
 		hashCtx.Mixin(param.mStructRet);
 		hashCtx.Mixin(param.mZExt);
 		hashCtx.Mixin(param.mDereferenceableSize);
+		hashCtx.Mixin(param.mByValSize);
 	}
 	if (mDbgFunction != NULL)
 		mDbgFunction->HashReference(hashCtx);

+ 6 - 0
IDEHelper/Backend/BeModule.h

@@ -410,6 +410,7 @@ public:
 	bool mNoCapture;
 	bool mZExt;
 	int mDereferenceableSize;
+	int mByValSize;
 
 	BeFunctionParam()
 	{
@@ -418,6 +419,7 @@ public:
 		mNoCapture = false;
 		mZExt = false;
 		mDereferenceableSize = -1;
+		mByValSize = -1;
 	}
 };
 
@@ -1207,6 +1209,7 @@ public:
 	{
 		BeValue* mValue;
 		int mDereferenceableSize;
+		int mByRefSize;
 		bool mStructRet;
 		bool mZExt;
 		bool mNoAlias;
@@ -1219,6 +1222,7 @@ public:
 			mNoAlias = false;
 			mNoCapture = false;
 			mDereferenceableSize = -1;
+			mByRefSize = -1;
 		}
 	};
 
@@ -1254,6 +1258,8 @@ public:
 			arg.mValue->HashReference(hashCtx);
 			hashCtx.Mixin(arg.mStructRet);
 			hashCtx.Mixin(arg.mZExt);
+			hashCtx.Mixin(arg.mDereferenceableSize);
+			hashCtx.Mixin(arg.mByRefSize);
 		}
 		hashCtx.Mixin(mCallingConv);
 		hashCtx.Mixin(mNoReturn);

+ 2 - 0
IDEHelper/Compiler/BfCompiler.cpp

@@ -3470,6 +3470,8 @@ void BfCompiler::VisitSourceExteriorNodes()
 		if (parser->mAwaitingDelete)
 			return;		
 
+		if (parser->mParserData == NULL)
+			return;
 		if (parser->mParserData->mExteriorNodesCheckIdx == mSystem->mTypeMapVersion)
 			return;
 

+ 2 - 0
IDEHelper/Compiler/BfDemangler.cpp

@@ -2496,6 +2496,8 @@ void MsDemangleScanner::Process(const StringImpl& mangledName)
 
 String BfDemangler::Demangle(const StringImpl& mangledName, DbgLanguage language, Flags flags)
 {	
+	if (mangledName.IsEmpty())
+		return "";
 	if (mangledName[0] == '?')
 	{
 		MsDemangler demangler;

+ 147 - 60
IDEHelper/Compiler/BfExprEvaluator.cpp

@@ -4484,7 +4484,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfMethodInstance* methodInstance, BfIRV
 		}
 		else
 		{						
-			auto val = mModule->GetDefaultTypedValue(returnType, true, methodInstance->HasStructRet() ? BfDefaultValueKind_Addr : BfDefaultValueKind_Value);
+			auto val = mModule->GetDefaultTypedValue(returnType, true, (methodInstance->GetStructRetIdx() != -1) ? BfDefaultValueKind_Addr : BfDefaultValueKind_Value);
 			if (val.mKind == BfTypedValueKind_Addr)
 				val.mKind = BfTypedValueKind_TempAddr;
 			return val;
@@ -4492,7 +4492,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfMethodInstance* methodInstance, BfIRV
 	};
 
 	mModule->PopulateType(origReturnType, BfPopulateType_Data);
-	if (methodInstance->HasStructRet())
+	if (methodInstance->GetStructRetIdx() != -1)
 	{
 		// We need to ensure that mReceivingValue has the correct type, otherwise it's possible that a conversion operator needs to be applied
 		//  This happens for returning Result<T>'s with a 'T' value
@@ -4756,13 +4756,23 @@ BfTypedValue BfExprEvaluator::CreateCall(BfMethodInstance* methodInstance, BfIRV
 		mModule->mBfIRBuilder->PopulateType(returnType);
 	
 	BfIRValue callInst;
+	int callIRArgCount = (int)irArgs.size();
 	if (sret != NULL)
 	{
 		SizedArray<BfIRValue, 8> sretIRArgs; 
-		sretIRArgs.push_back(sret->mValue);
-		if (!irArgs.IsEmpty())
-			sretIRArgs.Insert(sretIRArgs.size(), &irArgs[0], irArgs.size());
+		int sretIdx = methodInstance->GetStructRetIdx();
+		int inIdx = 0;
+		for (int outIdx = 0; outIdx < irArgs.size() + 1; outIdx++)
+		{
+			if (outIdx == sretIdx)
+			{
+				sretIRArgs.Add(sret->mValue);
+				continue;
+			}
+			sretIRArgs.Add(irArgs[inIdx++]);
+		}
 		callInst = mModule->mBfIRBuilder->CreateCall(funcCallInst, sretIRArgs);
+		callIRArgCount++;
 	}
 	else
 	{
@@ -4780,18 +4790,23 @@ BfTypedValue BfExprEvaluator::CreateCall(BfMethodInstance* methodInstance, BfIRV
 	int paramIdx = 0;
 	bool doingThis = !methodDef->mIsStatic;
 	int argIdx = 0;
-	if (sret != NULL)
+	
+
+	if (methodInstance->mIdHash == 1140)
 	{
-		mModule->mBfIRBuilder->Call_AddAttribute(callInst, argIdx + 1, BfIRAttribute_StructRet);
-		argIdx++;
+		NOP;
 	}
 
 	int paramCount = methodInstance->GetParamCount();
 
-	for ( ; argIdx < (int)irArgs.size(); /*argIdx++*/)
+	for ( ; argIdx < callIRArgCount ; )
 	{	
-		if (argIdx >= paramCount)
-			break;
+		if (argIdx == methodInstance->GetStructRetIdx())
+		{
+			mModule->mBfIRBuilder->Call_AddAttribute(callInst, argIdx + 1, BfIRAttribute_StructRet);
+			argIdx++;
+			continue;
+		}
 
 		auto _HandleParamType = [&] (BfType* paramType)
 		{
@@ -4799,10 +4814,13 @@ BfTypedValue BfExprEvaluator::CreateCall(BfMethodInstance* methodInstance, BfIRV
 			{
 				if ((!doingThis) || (!methodDef->mIsMutating && methodInstance->AllowsSplatting()))
 				{
-					auto loweredTypeCode = paramType->GetLoweredType();
-					if (loweredTypeCode != BfTypeCode_None)
+					BfTypeCode loweredTypeCode = BfTypeCode_None;
+					BfTypeCode loweredTypeCode2 = BfTypeCode_None;					
+					if (paramType->GetLoweredType(BfTypeUsage_Parameter, &loweredTypeCode, &loweredTypeCode2))
 					{
 						argIdx++;
+						if (loweredTypeCode2 != BfTypeCode_None)
+							argIdx++;
 						return; // Lowering never requires attributes
 					}
 				}
@@ -4818,8 +4836,9 @@ BfTypedValue BfExprEvaluator::CreateCall(BfMethodInstance* methodInstance, BfIRV
 				if ((addDeref <= 0) && (!elementType->IsValuelessType()))
 					mModule->AssertErrorState();
 			}
+
 			if ((paramType->IsComposite()) && (!paramType->IsTypedPrimitive()))
-			{				
+			{
 				if (mModule->mCompiler->mOptions.mAllowStructByVal)
 				{
 					//byval
@@ -4835,8 +4854,15 @@ BfTypedValue BfExprEvaluator::CreateCall(BfMethodInstance* methodInstance, BfIRV
 					}
 					else
 					{
-						mModule->mBfIRBuilder->Call_AddAttribute(callInst, argIdx + 1, BfIRAttribute_NoCapture);						
-						addDeref = paramType->mSize;
+						if (doingThis)
+						{
+							mModule->mBfIRBuilder->Call_AddAttribute(callInst, argIdx + 1, BfIRAttribute_NoCapture);
+							addDeref = paramType->mSize;
+						}
+						else
+						{
+							mModule->mBfIRBuilder->Call_AddAttribute(callInst, argIdx + 1, BfIRAttribute_ByVal, mModule->mSystem->mPtrSize);
+						}
 					}
 				}
 			}
@@ -4876,13 +4902,28 @@ BfTypedValue BfExprEvaluator::CreateCall(BfMethodInstance* methodInstance, BfIRV
 		}
 		else
 		{
+			if (paramIdx >= methodInstance->GetParamCount())
+				break;
+
 			paramType = methodInstance->GetParamType(paramIdx);
+
+			BfTypeCode loweredTypeCode = BfTypeCode_None;
+			BfTypeCode loweredTypeCode2 = BfTypeCode_None;
+			if (paramType->GetLoweredType(BfTypeUsage_Parameter, &loweredTypeCode, &loweredTypeCode2))
+			{
+				argIdx++;
+				paramIdx++;
+				if (loweredTypeCode2 != BfTypeCode_None)
+					argIdx++;
+				continue;
+			}
+
 			if ((paramType->IsValuelessType()) && (!paramType->IsMethodRef()))
 			{
 				paramIdx++;
 				continue;
 			}
-			//if (resolvedTypeRef->IsSplattable())
+			
 			if (methodInstance->GetParamIsSplat(paramIdx))
 			{
 				BfTypeUtils::SplatIterate(_HandleParamType, paramType);
@@ -4893,8 +4934,6 @@ BfTypedValue BfExprEvaluator::CreateCall(BfMethodInstance* methodInstance, BfIRV
 				_HandleParamType(methodInstance->GetParamType(paramIdx));
 		}
 
-		
-
 		if (doingThis)
 			doingThis = false;
 		else
@@ -4936,13 +4975,14 @@ BfTypedValue BfExprEvaluator::CreateCall(BfMethodInstance* methodInstance, BfIRV
 		result = *sret;
 	else if (hasResult)
 	{
-		if (methodInstance->mReturnType->GetLoweredType() != BfTypeCode_None)
+		BfTypeCode loweredRetType = BfTypeCode_None;
+		BfTypeCode loweredRetType2 = BfTypeCode_None;		
+		if (methodInstance->GetLoweredReturnType(&loweredRetType, &loweredRetType2))
 		{
-			auto loweredType = mModule->GetPrimitiveType(methodInstance->mReturnType->GetLoweredType());
-			auto loweredPtrType = mModule->CreatePointerType(loweredType);
-
 			auto retVal = mModule->CreateAlloca(methodInstance->mReturnType);
-			auto castedRetVal = mModule->mBfIRBuilder->CreateBitCast(retVal, mModule->mBfIRBuilder->MapType(loweredPtrType));
+			BfIRType loweredIRType = mModule->GetIRLoweredType(loweredRetType, loweredRetType2);			
+			loweredIRType = mModule->mBfIRBuilder->GetPointerTo(loweredIRType);							
+			auto castedRetVal = mModule->mBfIRBuilder->CreateBitCast(retVal, loweredIRType);
 			mModule->mBfIRBuilder->CreateStore(callInst, castedRetVal);
 			result = BfTypedValue(retVal, methodInstance->mReturnType, BfTypedValueKind_TempAddr);
 		}
@@ -5116,14 +5156,40 @@ void BfExprEvaluator::PushArg(BfTypedValue argVal, SizedArrayImpl<BfIRValue>& ir
 			
 			if (!disableLowering)
 			{
-				auto loweredTypeCode = argVal.mType->GetLoweredType();
-				if (loweredTypeCode != BfTypeCode_None)
+				BfTypeCode loweredTypeCode = BfTypeCode_None;
+				BfTypeCode loweredTypeCode2 = BfTypeCode_None;				
+				if (argVal.mType->GetLoweredType(BfTypeUsage_Parameter, &loweredTypeCode, &loweredTypeCode2))
 				{
-					auto primType = mModule->GetPrimitiveType(loweredTypeCode);
-					auto ptrType = mModule->CreatePointerType(primType);
-					BfIRValue primPtrVal = mModule->mBfIRBuilder->CreateBitCast(argVal.mValue, mModule->mBfIRBuilder->MapType(ptrType));
+// 					auto primType = mModule->GetPrimitiveType(loweredTypeCode);
+// 					auto ptrType = mModule->CreatePointerType(primType);
+// 					BfIRValue primPtrVal = mModule->mBfIRBuilder->CreateBitCast(argVal.mValue, mModule->mBfIRBuilder->MapType(ptrType));
+// 					auto primVal = mModule->mBfIRBuilder->CreateLoad(primPtrVal);
+// 					irArgs.push_back(primVal);
+// 
+// 					if (loweredTypeCode2 != BfTypeCode_None)
+// 					{
+// 						auto primType2 = mModule->GetPrimitiveType(loweredTypeCode2);
+// 						auto ptrType2 = mModule->CreatePointerType(primType2);
+// 						BfIRValue primPtrVal2 = mModule->mBfIRBuilder->CreateBitCast(mModule->mBfIRBuilder->CreateInBoundsGEP(primPtrVal, 1), mModule->mBfIRBuilder->MapType(ptrType2));
+// 						auto primVal2 = mModule->mBfIRBuilder->CreateLoad(primPtrVal2);
+// 						irArgs.push_back(primVal2);
+// 					}
+
+					auto primType = mModule->mBfIRBuilder->GetPrimitiveType(loweredTypeCode);
+					auto ptrType = mModule->mBfIRBuilder->GetPointerTo(primType);
+					BfIRValue primPtrVal = mModule->mBfIRBuilder->CreateBitCast(argVal.mValue, ptrType);
 					auto primVal = mModule->mBfIRBuilder->CreateLoad(primPtrVal);
 					irArgs.push_back(primVal);
+
+					if (loweredTypeCode2 != BfTypeCode_None)
+					{
+						auto primType2 = mModule->mBfIRBuilder->GetPrimitiveType(loweredTypeCode2);
+						auto ptrType2 = mModule->mBfIRBuilder->GetPointerTo(primType2);
+						BfIRValue primPtrVal2 = mModule->mBfIRBuilder->CreateBitCast(mModule->mBfIRBuilder->CreateInBoundsGEP(primPtrVal, 1), ptrType2);
+						auto primVal2 = mModule->mBfIRBuilder->CreateLoad(primPtrVal2);
+						irArgs.push_back(primVal2);
+					}
+
 					return;
 				}
 			}			
@@ -5244,7 +5310,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
  	if (!mModule->mCompiler->mIsResolveOnly)
 		sCallIdx++;
 	int callIdx = sCallIdx;
-	if (callIdx == 4348)
+	if (callIdx == 1177)
 	{
 		NOP;
 	}
@@ -5436,9 +5502,10 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
 		}
 		else
 		{
-			wantsSplat = methodInstance->GetParamIsSplat(paramIdx);
+			wantsSplat = methodInstance->GetParamIsSplat(paramIdx);			
 			if (methodInstance->IsImplicitCapture(paramIdx))
 			{
+				auto paramType = methodInstance->GetParamType(paramIdx);
 				if (mModule->mCurMethodInstance->IsMixin())
 				{					
 					// Don't bother, also- can fail on captures					
@@ -5461,10 +5528,12 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
 						{
 							SplatArgs(lookupVal, irArgs);
 						}
-						else
+						else if (paramType->IsRef())
 						{														
 							irArgs.push_back(lookupVal.mValue);
 						}
+						else
+							PushArg(lookupVal, irArgs, true);
 					}
 				}
 				paramIdx++;
@@ -5549,7 +5618,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
 		bool hadMissingArg = false;
 
 		int argExprIdx = argIdx;
-		if ((methodDef->mMethodType == BfMethodType_Extension))
+		if (methodDef->mMethodType == BfMethodType_Extension)
 		{
 			argExprIdx--;
 			if (argExprIdx == -1)
@@ -5718,12 +5787,8 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
 					{
 					 	if (methodRefType->WantsDataPassedAsSplat(dataIdx))
 					 		SplatArgs(lookupVal, irArgs);
-						else if (lookupVal.mType->IsComposite())
-						{
-							irArgs.push_back(lookupVal.mValue);
-						}
 						else
-					 		irArgs.push_back(lookupVal.mValue);
+							irArgs.push_back(lookupVal.mValue);
 					}
 				}
 
@@ -6814,11 +6879,6 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
 			methodMatcher.CheckType(lookupTypeInst, target, true);		
 	}
 
-	if ((methodMatcher.mBestMethodDef != NULL) && (methodMatcher.mBestMethodDef->mName == "Zorf"))
-	{
-		NOP;
-	}
-
 	BfTypedValue staticResult;
 	methodMatcher.TryDevirtualizeCall(target, &origTarget, &staticResult);
 	if (staticResult)
@@ -9909,8 +9969,10 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr)
 		if (hasCaptures)
 		{
 			hasThis = true;
-			methodInstance->GetIRFunctionInfo(mModule, irReturnType, irParamTypes);
-			int thisIdx = methodInstance->HasStructRet() ? 1 : 0;
+			methodInstance->GetIRFunctionInfo(mModule, irReturnType, irParamTypes);			
+			int thisIdx = 0;
+			if (methodInstance->GetStructRetIdx() == 0)
+				thisIdx = 1;
 			irParamTypes[thisIdx] = mModule->mBfIRBuilder->MapType(useTypeInstance);
 		}
 		else
@@ -9927,10 +9989,10 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr)
 		auto funcType = mModule->mBfIRBuilder->CreateFunctionType(irReturnType, irParamTypes);
 		funcValue = mModule->mBfIRBuilder->CreateFunction(funcType, BfIRLinkageType_External, methodName);
 
-		if (methodInstance->HasStructRet())
-		{
-			mModule->mBfIRBuilder->Func_AddAttribute(funcValue, 1, BfIRAttribute_NoAlias);
-			mModule->mBfIRBuilder->Func_AddAttribute(funcValue, 1, BfIRAttribute_StructRet);
+		if (methodInstance->GetStructRetIdx() != -1)
+		{			
+			mModule->mBfIRBuilder->Func_AddAttribute(funcValue, methodInstance->GetStructRetIdx() + 1, BfIRAttribute_NoAlias);
+			mModule->mBfIRBuilder->Func_AddAttribute(funcValue, methodInstance->GetStructRetIdx() + 1, BfIRAttribute_StructRet);
 		}
 
 		auto srcCallingConv = mModule->GetIRCallingConvention(methodInstance);
@@ -9947,10 +10009,18 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr)
 		fieldIdx = 0;
 		SizedArray<BfIRValue, 8> irArgs;
 
-		int argIdx = 0;
-		if (methodInstance->HasStructRet())
-			irArgs.push_back(mModule->mBfIRBuilder->GetArgument(argIdx++));
+		if (methodInstance->mIdHash == 775)
+		{
+			NOP;
+		}
 
+		int argIdx = 0;
+		if (bindMethodInstance->GetStructRetIdx() == 0)
+		{
+			irArgs.push_back(mModule->mBfIRBuilder->GetArgument(methodInstance->GetStructRetIdx()));
+			argIdx++;
+		}
+		
 		for (int implicitParamIdx = bindMethodInstance->HasThis() ? -1 : 0; implicitParamIdx < implicitParamCount; implicitParamIdx++)
 		{
 			auto fieldInst = &useTypeInstance->mFieldInstances[fieldIdx];
@@ -9965,7 +10035,10 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr)
 					disableSplat = true;
 				}
 			}
-			int thisIdx = methodInstance->HasStructRet() ? 1 : 0;
+			
+			int thisIdx = 0;
+			if (methodInstance->GetStructRetIdx() == 0)
+				thisIdx = 1;
 			auto fieldPtr = mModule->mBfIRBuilder->CreateInBoundsGEP(mModule->mBfIRBuilder->GetArgument(thisIdx), 0, gepIdx);
 			BfTypedValue typedVal(fieldPtr, fieldType, true);
 			PushArg(typedVal, irArgs, disableSplat);
@@ -9974,6 +10047,12 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr)
 
 		if (hasThis)
 			argIdx++;
+		
+		if (bindMethodInstance->GetStructRetIdx() == 1)
+		{
+			irArgs.push_back(mModule->mBfIRBuilder->GetArgument(methodInstance->GetStructRetIdx()));
+			argIdx++;
+		}
 
 		for (int paramIdx = 0; paramIdx < methodInstance->GetParamCount(); paramIdx++)
 		{
@@ -9992,12 +10071,12 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr)
 		if (mModule->mCompiler->mOptions.mAllowHotSwapping)
 			bindFuncVal = mModule->mBfIRBuilder->RemapBindFunction(bindFuncVal);
 		auto callInst = mModule->mBfIRBuilder->CreateCall(bindFuncVal, irArgs);
-		if (methodInstance->HasStructRet())
-			mModule->mBfIRBuilder->Call_AddAttribute(callInst, 1, BfIRAttribute_StructRet);
+		if (bindMethodInstance->GetStructRetIdx() != -1)
+			mModule->mBfIRBuilder->Call_AddAttribute(callInst, bindMethodInstance->GetStructRetIdx() + 1, BfIRAttribute_StructRet);
 		auto destCallingConv = mModule->GetIRCallingConvention(bindMethodInstance);
 		if (destCallingConv != BfIRCallingConv_CDecl)
 			mModule->mBfIRBuilder->SetCallCallingConv(callInst, destCallingConv);
-		if ((methodInstance->mReturnType->IsValuelessType()) || (methodInstance->HasStructRet()))
+		if ((methodInstance->mReturnType->IsValuelessType()) || (methodInstance->GetStructRetIdx() != -1))
 		{
 			mModule->mBfIRBuilder->CreateRetVoid();
 		}
@@ -10783,14 +10862,17 @@ BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lam
 		origReturnType = mModule->mBfIRBuilder->MapType(mModule->GetPrimitiveType(BfTypeCode_None));
 	}
 
-	SizedArray<BfIRType, 3> newTypes;
-	if ((invokeMethodInstance != NULL) && (invokeMethodInstance->HasStructRet()))
+	SizedArray<BfIRType, 3> newTypes;	
+
+	if ((invokeMethodInstance != NULL) && (invokeMethodInstance->GetStructRetIdx() == 0))
 		newTypes.push_back(origParamTypes[0]);
 	if (!methodDef->mIsStatic)
 		newTypes.push_back(mModule->mBfIRBuilder->MapType(useTypeInstance));
+	if ((invokeMethodInstance != NULL) && (invokeMethodInstance->GetStructRetIdx() == 1))
+		newTypes.push_back(origParamTypes[1]);
 
 	int paramStartIdx = 0;
-	if ((invokeMethodInstance != NULL) && (invokeMethodInstance->HasStructRet()))
+	if ((invokeMethodInstance != NULL) && (invokeMethodInstance->GetStructRetIdx() != -1))
 		paramStartIdx++;
 	if (!methodDef->mIsStatic)
 		paramStartIdx++;
@@ -14585,6 +14667,11 @@ BfTypedValue BfExprEvaluator::GetResult(bool clearResult, bool resolveGenericTyp
 				return mResult;
 			}
 
+			if (matchedMethod->mName == "get__CultureName")
+			{
+				NOP;
+			}
+
 			auto methodInstance = GetPropertyMethodInstance(matchedMethod);
 			if (methodInstance.mMethodInstance == NULL)
 				return mResult;
@@ -14662,7 +14749,7 @@ BfTypedValue BfExprEvaluator::GetResult(bool clearResult, bool resolveGenericTyp
 					}
 					else
 					{
-						auto val = mModule->GetDefaultTypedValue(returnType, true, methodInstance.mMethodInstance->HasStructRet() ? BfDefaultValueKind_Addr : BfDefaultValueKind_Value);
+						auto val = mModule->GetDefaultTypedValue(returnType, true, (methodInstance.mMethodInstance->GetStructRetIdx() != -1) ? BfDefaultValueKind_Addr : BfDefaultValueKind_Value);
 						if (val.mKind == BfTypedValueKind_Addr)
 							val.mKind = BfTypedValueKind_TempAddr;
 						return val;

+ 12 - 0
IDEHelper/Compiler/BfIRBuilder.cpp

@@ -3305,6 +3305,13 @@ BfIRType BfIRBuilder::CreateStructType(const StringImpl& name)
 	return retType;
 }
 
+BfIRType BfIRBuilder::CreateStructType(const BfSizedArray<BfIRType>& memberTypes)
+{
+	BfIRType retType = WriteCmd(BfIRCmd_CreateAnonymousStruct, memberTypes);
+	NEW_CMD_INSERTED_IRTYPE;
+	return retType;
+}
+
 void BfIRBuilder::StructSetBody(BfIRType type, const BfSizedArray<BfIRType>& memberTypes, bool isPacked)
 {
 	WriteCmd(BfIRCmd_StructSetBody, type, memberTypes, isPacked);
@@ -4421,6 +4428,11 @@ BfIRFunction BfIRBuilder::CreateFunction(BfIRFunctionType funcType, BfIRLinkageT
 	NEW_CMD_INSERTED_IRVALUE;	
 	mFunctionMap[name] = retVal;
 
+	if (name == "?TestStructRetCapture$Rt@Lambdas@Tests@bf@@QEAA?AUStructA@123@XZ")
+	{
+		NOP;
+	}
+
 	//BfLogSys(mModule->mSystem, "BfIRBuilder::CreateFunction: %d %s Module:%p\n", retVal.mId, name.c_str(), mModule);
 
 	return retVal;

+ 13 - 1
IDEHelper/Compiler/BfIRBuilder.h

@@ -94,10 +94,20 @@ enum BfTypeCode : uint8
 	BfTypeCode_UInt8,
 	BfTypeCode_Int16,
 	BfTypeCode_UInt16,
+	BfTypeCode_Int24,
+	BfTypeCode_UInt24,
 	BfTypeCode_Int32,
 	BfTypeCode_UInt32,
+	BfTypeCode_Int40,
+	BfTypeCode_UInt40,
+	BfTypeCode_Int48,
+	BfTypeCode_UInt48,
+	BfTypeCode_Int56,
+	BfTypeCode_UInt56,
 	BfTypeCode_Int64,
-	BfTypeCode_UInt64,	
+	BfTypeCode_UInt64,
+	BfTypeCode_Int128,
+	BfTypeCode_UInt128,
 	BfTypeCode_IntPtr,
 	BfTypeCode_UIntPtr,
 	BfTypeCode_IntUnknown,
@@ -152,6 +162,7 @@ enum BfIRCmd : uint8
 	BfIRCmd_SetType,
 	BfIRCmd_SetInstType,	
 	BfIRCmd_PrimitiveType,
+	BfIRCmd_CreateAnonymousStruct,
 	BfIRCmd_CreateStruct,
 	BfIRCmd_StructSetBody,
 	BfIRCmd_Type,
@@ -1050,6 +1061,7 @@ public:
 
 	BfIRType GetPrimitiveType(BfTypeCode typeCode);
 	BfIRType CreateStructType(const StringImpl& name);
+	BfIRType CreateStructType(const BfSizedArray<BfIRType>& memberTypes);
 	void StructSetBody(BfIRType type, const BfSizedArray<BfIRType>& memberTypes, bool isPacked);	
 	BfIRType MapType(BfType* type, BfIRPopulateType populateType = BfIRPopulateType_Declaration);
 	BfIRType MapTypeInst(BfTypeInstance* typeInst, BfIRPopulateType populateType = BfIRPopulateType_Declaration);

+ 51 - 1
IDEHelper/Compiler/BfIRCodeGen.cpp

@@ -434,17 +434,42 @@ llvm::Type* BfIRCodeGen::GetLLVMType(BfTypeCode typeCode, bool& isSigned)
 	case BfTypeCode_UInt16:
 	case BfTypeCode_Char16:
 		return llvm::Type::getInt16Ty(*mLLVMContext);
+	case BfTypeCode_Int24:
+		isSigned = true;
+		return llvm::Type::getIntNTy(*mLLVMContext, 24);
+	case BfTypeCode_UInt24:
+		return llvm::Type::getIntNTy(*mLLVMContext, 24);
 	case BfTypeCode_Int32:
 		isSigned = true;
 		return llvm::Type::getInt32Ty(*mLLVMContext);
 	case BfTypeCode_UInt32:
 	case BfTypeCode_Char32:
 		return llvm::Type::getInt32Ty(*mLLVMContext);
+	case BfTypeCode_Int40:
+		isSigned = true;
+		return llvm::Type::getIntNTy(*mLLVMContext, 40);
+	case BfTypeCode_UInt40:
+		return llvm::Type::getIntNTy(*mLLVMContext, 40);
+	case BfTypeCode_Int48:
+		isSigned = true;
+		return llvm::Type::getIntNTy(*mLLVMContext, 48);
+	case BfTypeCode_UInt48:
+		return llvm::Type::getIntNTy(*mLLVMContext, 48);
+	case BfTypeCode_Int56:
+		isSigned = true;
+		return llvm::Type::getIntNTy(*mLLVMContext, 56);
+	case BfTypeCode_UInt56:
+		return llvm::Type::getIntNTy(*mLLVMContext, 56);
 	case BfTypeCode_Int64:
 		isSigned = true;
 		return llvm::Type::getInt64Ty(*mLLVMContext);
 	case BfTypeCode_UInt64:
 		return llvm::Type::getInt64Ty(*mLLVMContext);
+	case BfTypeCode_Int128:
+		isSigned = true;
+		return llvm::Type::getInt128Ty(*mLLVMContext);
+	case BfTypeCode_UInt128:
+		return llvm::Type::getInt128Ty(*mLLVMContext);
 	case BfTypeCode_IntPtr:
 		BF_FATAL("Illegal");
 		/*isSigned = true;
@@ -1116,12 +1141,19 @@ void BfIRCodeGen::HandleNextCmd()
 			SetResult(curId, GetLLVMType(typeCode, isSigned));
 		}
 		break;
+	case BfIRCmd_CreateAnonymousStruct:
+		{
+			CMD_PARAM(CmdParamVec<llvm::Type*>, members);
+			llvm::StructType* structType = llvm::StructType::get(*mLLVMContext, members);			
+			SetResult(curId, structType);
+		}
+		break;
 	case BfIRCmd_CreateStruct:
 		{
 			CMD_PARAM(String, typeName);
 			SetResult(curId, llvm::StructType::create(*mLLVMContext, typeName.c_str()));
 		}
-		break;
+		break;	
 	case BfIRCmd_StructSetBody:
 		{
 			CMD_PARAM(llvm::Type*, type);
@@ -2621,6 +2653,15 @@ void BfIRCodeGen::HandleNextCmd()
 				{
 					((llvm::CallInst*)callInst)->addDereferenceableAttr(argIdx, arg);
 				}
+				else if (attribute == BfIRAttribute_ByVal)
+				{
+					llvm::AttrBuilder B;
+					B.addAttribute(llvm::Attribute::ByVal);
+					B.addAlignmentAttr(arg);
+					auto attrList = ((llvm::CallInst*)callInst)->getAttributes();
+					attrList = attrList.addAttributes(*mLLVMContext, argIdx, B);
+					((llvm::CallInst*)callInst)->setAttributes(attrList);
+				}
 			}
 		}
 		break;
@@ -2655,6 +2696,15 @@ void BfIRCodeGen::HandleNextCmd()
 			{
 				((llvm::Function*)func)->addDereferenceableAttr(argIdx, arg);		
 			}
+			else if (attribute == BfIRAttribute_ByVal)
+			{
+				llvm::AttrBuilder B;
+				B.addAttribute(llvm::Attribute::ByVal);
+				B.addAlignmentAttr(arg);
+				auto attrList = ((llvm::Function*)func)->getAttributes();
+				attrList = attrList.addAttributes(*mLLVMContext, argIdx, B);
+				((llvm::Function*)func)->setAttributes(attrList);				
+			}
 		}
 		break;
 	case BfIRCmd_Func_SetParamName:

+ 1 - 1
IDEHelper/Compiler/BfIRCodeGen.h

@@ -82,7 +82,7 @@ public:
 	Dictionary<int, BfIRCodeGenEntry> mResults;
 	Dictionary<int, BfIRTypeEntry> mTypes;
 	Dictionary<int, llvm::Function*> mIntrinsicMap;
-	Dictionary<llvm::Function*, int> mIntrinsicReverseMap;
+	Dictionary<llvm::Function*, int> mIntrinsicReverseMap;	
 	Array<llvm::Constant*> mConfigConsts32;
 	Array<llvm::Constant*> mConfigConsts64;	
 

+ 2 - 2
IDEHelper/Compiler/BfMangler.cpp

@@ -1566,7 +1566,7 @@ void BfMSMangler::Mangle(MangleContext& mangleContext, StringImpl& name, BfType*
 		}
 	}
 	else if (type->IsTypeInstance())
-	{		
+	{
 		auto typeInstance = (BfTypeInstance*)type;
 		auto typeDef = typeInstance->mTypeDef;
 
@@ -1577,7 +1577,7 @@ void BfMSMangler::Mangle(MangleContext& mangleContext, StringImpl& name, BfType*
 				name += "E";
 			name += "A";
 		}
-		else if (((type->IsGenericTypeInstance()) || (type->IsTuple()) || (type->IsEnum())) && (mangleContext.mInRet))
+		else if (((type->IsGenericTypeInstance()) || (type->IsComposite()) || (type->IsEnum())) && (mangleContext.mInRet))
 			name += "?A";
 
 		Mangle(mangleContext, name, typeInstance, false);		

+ 169 - 80
IDEHelper/Compiler/BfModule.cpp

@@ -1088,7 +1088,7 @@ void BfModule::EnsureIRBuilder(bool dbgVerifyCodeGen)
 			}
 		}
 		else if (!mIsReified)
-		{			
+		{
 			mBfIRBuilder->mIgnoreWrites = true;
 		}
 		else
@@ -1097,10 +1097,9 @@ void BfModule::EnsureIRBuilder(bool dbgVerifyCodeGen)
 			//  code as we walk the AST
 			//mBfIRBuilder->mDbgVerifyCodeGen = true;			
 			if (
-                (mModuleName == "-")
-				//|| (mModuleName == "Blurg")
-				//|| (mModuleName == "System_Int32")
-				//|| (mModuleName == "Hey_Dude_Bro_TestClass")
+                (mModuleName == "-") 
+				//|| (mModuleName == "Tests_FuncRefs_Class")
+				//|| (mModuleName == "Tests_FuncRefs")
 				)
 				mBfIRBuilder->mDbgVerifyCodeGen = true;
 			
@@ -3993,7 +3992,7 @@ void BfModule::CreateFakeCallerMethod(const String& funcName)
 	SizedArray<BfIRValue, 8> args;
 	BfExprEvaluator exprEvaluator(this);
 
-	if (mCurMethodInstance->HasStructRet())
+	if (mCurMethodInstance->GetStructRetIdx() != -1)
 	{
 		auto retPtrType = CreatePointerType(mCurMethodInstance->mReturnType);		
 		exprEvaluator.PushArg(GetDefaultTypedValue(retPtrType, true, BfDefaultValueKind_Const), args);
@@ -4001,7 +4000,7 @@ void BfModule::CreateFakeCallerMethod(const String& funcName)
 
 	if (mCurMethodInstance->HasThis())
 	{
-		auto thisValue = GetDefaultTypedValue(mCurMethodInstance->GetOwner(), true);
+		auto thisValue = GetDefaultTypedValue(mCurMethodInstance->GetOwner(), true, mCurTypeInstance->IsComposite() ? BfDefaultValueKind_Addr : BfDefaultValueKind_Const);
 		exprEvaluator.PushThis(NULL, thisValue, mCurMethodInstance, args);
 	}
 
@@ -12705,7 +12704,7 @@ void BfModule::CreateDIRetVal()
 	{		
 		BfType* dbgType = mCurMethodInstance->mReturnType;
 		BfIRValue dbgValue = mCurMethodState->mRetVal.mValue;
-		if (mCurMethodInstance->HasStructRet())
+		if (mCurMethodInstance->GetStructRetIdx() != -1)
 		{
 			BF_ASSERT(mCurMethodState->mRetValAddr);
 			dbgType = CreatePointerType(dbgType);
@@ -13207,11 +13206,11 @@ void BfModule::MarkScopeLeft(BfScopeData* scopeData)
 
 void BfModule::CreateReturn(BfIRValue val)
 {
-	if (mCurMethodInstance->HasStructRet())
+	if (mCurMethodInstance->GetStructRetIdx() != -1)
 	{
 		// Store to sret
 		BF_ASSERT(val);
-		mBfIRBuilder->CreateStore(val, mBfIRBuilder->GetArgument(0));
+		mBfIRBuilder->CreateStore(val, mBfIRBuilder->GetArgument(mCurMethodInstance->GetStructRetIdx()));
 		mBfIRBuilder->CreateRetVoid();
 	}
 	else
@@ -13222,14 +13221,18 @@ void BfModule::CreateReturn(BfIRValue val)
 		}
 		else if (mCurMethodInstance->mReturnType->IsStruct())
 		{
-			auto loweredType = GetPrimitiveType(mCurMethodInstance->mReturnType->GetLoweredType());			
-			auto ptrReturnType = CreatePointerType(mCurMethodInstance->mReturnType);
-			auto ptrLoweredValue = CreateAlloca(loweredType);
-			auto ptrReturnValue = mBfIRBuilder->CreateBitCast(ptrLoweredValue, mBfIRBuilder->MapType(ptrReturnType));
-			mBfIRBuilder->CreateStore(val, ptrReturnValue);
+			BfTypeCode loweredReturnType = BfTypeCode_None;
+			BfTypeCode loweredReturnType2 = BfTypeCode_None;
+			mCurMethodInstance->GetLoweredReturnType(&loweredReturnType, &loweredReturnType2);
+
+			auto retVal = CreateAlloca(mCurMethodInstance->mReturnType);
+			mBfIRBuilder->CreateStore(val, retVal);
 
-			auto loadedLoweredValue = mBfIRBuilder->CreateLoad(ptrLoweredValue);
-			mBfIRBuilder->CreateRet(loadedLoweredValue);
+			auto irRetType = GetIRLoweredType(loweredReturnType, loweredReturnType2);
+			irRetType = mBfIRBuilder->GetPointerTo(irRetType);
+			auto ptrReturnValue = mBfIRBuilder->CreateBitCast(retVal, irRetType);
+			auto loadedReturnValue = mBfIRBuilder->CreateLoad(ptrReturnValue);
+			mBfIRBuilder->CreateRet(loadedReturnValue);
 		}
 		else
 		{
@@ -13286,7 +13289,7 @@ void BfModule::EmitDefaultReturn()
 	{
 		if (mCurMethodInstance->mReturnType->IsVoid())
 			mBfIRBuilder->CreateRetVoid();
-		else if (!mCurMethodInstance->HasStructRet())		
+		else if (mCurMethodInstance->GetStructRetIdx() == -1)		
 			mBfIRBuilder->CreateRet(GetDefaultValue(mCurMethodInstance->mReturnType));
 	}
 
@@ -13394,16 +13397,20 @@ void BfModule::CreateDelegateInvokeMethod()
 
 	if (mCurMethodInstance->mReturnType->IsValueType())
 		mBfIRBuilder->PopulateType(mCurMethodInstance->mReturnType, BfIRPopulateType_Full);
+		
+	if (mCurMethodInstance->GetStructRetIdx() != 0)
+		memberFuncArgs.push_back(BfIRValue()); // Push 'target'
 
 	int thisIdx = 0;
-	if (mCurMethodInstance->HasStructRet())
-	{
-		thisIdx = 1;
-		staticFuncArgs.push_back(mBfIRBuilder->GetArgument(0));
-		memberFuncArgs.push_back(mBfIRBuilder->GetArgument(0));
+	if (mCurMethodInstance->GetStructRetIdx() != -1)
+	{		
+		thisIdx = mCurMethodInstance->GetStructRetIdx() ^ 1;
+		staticFuncArgs.push_back(mBfIRBuilder->GetArgument(mCurMethodInstance->GetStructRetIdx()));
+		memberFuncArgs.push_back(mBfIRBuilder->GetArgument(mCurMethodInstance->GetStructRetIdx()));
 	}
-	
-	memberFuncArgs.push_back(BfIRValue()); // Push 'target'
+
+	if (mCurMethodInstance->GetStructRetIdx() == 0)
+		memberFuncArgs.push_back(BfIRValue()); // Push 'target'
 
 	mCurMethodInstance->GetIRFunctionInfo(this, origReturnType, staticParamTypes, true);
 	
@@ -13441,8 +13448,8 @@ void BfModule::CreateDelegateInvokeMethod()
 		auto funcPtrPtr = mBfIRBuilder->CreateBitCast(fieldPtr, memberFuncPtrPtr);
 		auto funcPtr = mBfIRBuilder->CreateLoad(funcPtrPtr);		
 		nonStaticResult = mBfIRBuilder->CreateCall(funcPtr, memberFuncArgs);
-		if (mCurMethodInstance->HasStructRet())
-			mBfIRBuilder->Call_AddAttribute(nonStaticResult, 1, BfIRAttribute_StructRet);
+		if (mCurMethodInstance->GetStructRetIdx() != -1)
+			mBfIRBuilder->Call_AddAttribute(nonStaticResult, mCurMethodInstance->GetStructRetIdx() + 1, BfIRAttribute_StructRet);
 		if (callingConv != BfIRCallingConv_CDecl)
 			mBfIRBuilder->SetCallCallingConv(nonStaticResult, callingConv);
 		mCurMethodState->SetHadReturn(false);
@@ -13459,8 +13466,11 @@ void BfModule::CreateDelegateInvokeMethod()
 		auto funcPtrPtr = mBfIRBuilder->CreateBitCast(fieldPtr, staticFuncPtrPtr);
 		auto funcPtr = mBfIRBuilder->CreateLoad(funcPtrPtr);		
 		staticResult = mBfIRBuilder->CreateCall(funcPtr, staticFuncArgs);
-		if (mCurMethodInstance->HasStructRet())
-			mBfIRBuilder->Call_AddAttribute(staticResult, 1, BfIRAttribute_StructRet);
+		if (mCurMethodInstance->GetStructRetIdx() != -1)
+		{
+			// Note: since this is a forced static invocation, we know the sret will be the first parameter
+			mBfIRBuilder->Call_AddAttribute(staticResult, 0 + 1, BfIRAttribute_StructRet);
+		}
 		if (callingConv == BfIRCallingConv_ThisCall)
 			callingConv = BfIRCallingConv_CDecl;
 		if (callingConv != BfIRCallingConv_CDecl)
@@ -13473,16 +13483,20 @@ void BfModule::CreateDelegateInvokeMethod()
 
 	mBfIRBuilder->AddBlock(doneBB);
 	mBfIRBuilder->SetInsertPoint(doneBB);
-	if ((mCurMethodInstance->mReturnType->IsValuelessType()) || (mCurMethodInstance->HasStructRet()))
+	if ((mCurMethodInstance->mReturnType->IsValuelessType()) || (mCurMethodInstance->GetStructRetIdx() != -1))
 	{
 		mBfIRBuilder->CreateRetVoid();
 	}
 	else
 	{
-		auto loweredReturnType = mCurMethodInstance->mReturnType;
-		if (loweredReturnType->GetLoweredType() != BfTypeCode_None)
-			loweredReturnType = GetPrimitiveType(loweredReturnType->GetLoweredType());
-		auto phi = mBfIRBuilder->CreatePhi(mBfIRBuilder->MapType(loweredReturnType), 2);
+		BfIRType loweredIRReturnType;
+		BfTypeCode loweredTypeCode = BfTypeCode_None;
+		BfTypeCode loweredTypeCode2 = BfTypeCode_None;
+		if (mCurMethodInstance->GetLoweredReturnType(&loweredTypeCode, &loweredTypeCode2))
+			loweredIRReturnType = GetIRLoweredType(loweredTypeCode, loweredTypeCode2);
+		else
+			loweredIRReturnType = mBfIRBuilder->MapType(mCurMethodInstance->mReturnType);
+		auto phi = mBfIRBuilder->CreatePhi(loweredIRReturnType, 2);
 		mBfIRBuilder->AddPhiIncoming(phi, nonStaticResult, trueBB);
 		mBfIRBuilder->AddPhiIncoming(phi, staticResult, falseBB);		
 		mBfIRBuilder->CreateRet(phi);
@@ -14364,22 +14378,25 @@ void BfModule::SetupIRMethod(BfMethodInstance* methodInstance, BfIRFunction func
 	}
 
 	int argCount = methodInstance->GetIRFunctionParamCount(this);
-
-	if (methodInstance->HasStructRet())
-	{				
-		mBfIRBuilder->Func_AddAttribute(func, argIdx + 1, BfIRAttribute_NoAlias);
-		mBfIRBuilder->Func_AddAttribute(func, argIdx + 1, BfIRAttribute_StructRet);
-		argIdx++;
-	}
-
+	
 	while (argIdx < argCount)
 	{
+		if (argIdx == methodInstance->GetStructRetIdx())
+		{
+			mBfIRBuilder->Func_AddAttribute(func, argIdx + 1, BfIRAttribute_NoAlias);
+			mBfIRBuilder->Func_AddAttribute(func, argIdx + 1, BfIRAttribute_StructRet);
+			argIdx++;
+			continue;
+		}
+
 		while ((paramIdx != -1) && (methodInstance->IsParamSkipped(paramIdx)))
 			paramIdx++;
 
 		BfType* resolvedTypeRef = NULL;
+		BfType* resolvedTypeRef2 = NULL;
 		String paramName;
 		bool isSplattable = false;
+		bool tryLowering = true;
 		bool isThis = paramIdx == -1;
 		if (isThis)
 		{
@@ -14389,6 +14406,7 @@ void BfModule::SetupIRMethod(BfMethodInstance* methodInstance, BfIRFunction func
 			else
 				resolvedTypeRef = methodInstance->GetOwner();
 			isSplattable = (resolvedTypeRef->IsSplattable()) && (methodInstance->AllowsThisSplatting());
+			tryLowering = methodInstance->AllowsThisSplatting();
         }
 		else
 		{
@@ -14409,11 +14427,24 @@ void BfModule::SetupIRMethod(BfMethodInstance* methodInstance, BfIRFunction func
 			}			
 		}
 
-		//
+		if (tryLowering)
 		{
-			auto loweredTypeCode = resolvedTypeRef->GetLoweredType();
-			if (loweredTypeCode != BfTypeCode_None)
-				resolvedTypeRef = GetPrimitiveType(loweredTypeCode);
+			BfTypeCode loweredTypeCode = BfTypeCode_None;
+			BfTypeCode loweredTypeCode2 = BfTypeCode_None;
+			if (resolvedTypeRef->GetLoweredType(BfTypeUsage_Parameter, &loweredTypeCode, &loweredTypeCode2))
+			{	
+				mBfIRBuilder->Func_SetParamName(func, argIdx + 1, paramName + "__1");
+				argIdx++;
+
+				if (loweredTypeCode2 != BfTypeCode_None)
+				{
+					mBfIRBuilder->Func_SetParamName(func, argIdx + 1, paramName + "__2");
+					argIdx++;
+				}
+
+				paramIdx++;
+				continue;
+			}			
 		}
 
 		auto _SetupParam = [&](const StringImpl& paramName, BfType* resolvedTypeRef)
@@ -14432,16 +14463,17 @@ void BfModule::SetupIRMethod(BfMethodInstance* methodInstance, BfIRFunction func
 			}
 			if ((resolvedTypeRef->IsComposite()) && (!resolvedTypeRef->IsTypedPrimitive()))
 			{
-				if (mCompiler->mOptions.mAllowStructByVal)
-				{
-					mBfIRBuilder->Func_AddAttribute(func, argIdx + 1, BfIRAttribute_ByVal);
-				}
-				else
+				if (paramIdx == -1)
 				{
 					mBfIRBuilder->Func_AddAttribute(func, argIdx + 1, BfIRAttribute_NoCapture);
 					PopulateType(resolvedTypeRef, BfPopulateType_Data);
 					addDeref = resolvedTypeRef->mSize;
 				}
+				else
+				{
+					mBfIRBuilder->PopulateType(resolvedTypeRef);
+					mBfIRBuilder->Func_AddAttribute(func, argIdx + 1, BfIRAttribute_ByVal, mSystem->mPtrSize);
+				}
 			}
 			else if (resolvedTypeRef->IsPrimitiveType())
 			{
@@ -14521,8 +14553,9 @@ void BfModule::SetupIRMethod(BfMethodInstance* methodInstance, BfIRFunction func
 		}
 
 		_SetupParam(paramName, resolvedTypeRef);
-		
-		//argIdx++;
+		if (resolvedTypeRef2 != NULL)
+			_SetupParam(paramName, resolvedTypeRef2);
+				
 		paramIdx++;
 	}
 }
@@ -15412,11 +15445,15 @@ void BfModule::ProcessMethod_SetupParams(BfMethodInstance* methodInstance, BfTyp
 		isThisStruct = thisType->IsStruct() && !thisType->IsTypedPrimitive();
 	
 	int argIdx = 0;
-	if (methodInstance->HasStructRet())
+	
+	if (argIdx == methodInstance->GetStructRetIdx())
 		argIdx++;
 
 	if (!methodDef->mIsStatic)
 	{
+		BfTypeCode loweredTypeCode = BfTypeCode_None;
+		BfTypeCode loweredTypeCode2 = BfTypeCode_None;
+
 		BfLocalVariable* paramVar = new BfLocalVariable();
 		paramVar->mResolvedType = thisType;
 		paramVar->mName = "this";
@@ -15431,7 +15468,7 @@ void BfModule::ProcessMethod_SetupParams(BfMethodInstance* methodInstance, BfTyp
 				paramVar->mIsSplat = true;
 		}
 		else if ((!methodDef->mIsMutating) && (methodInstance->mCallingConvention == BfCallingConvention_Unspecified))
-			paramVar->mIsLowered = thisType->GetLoweredType() != BfTypeCode_None;
+			paramVar->mIsLowered = thisType->GetLoweredType(BfTypeUsage_Parameter, &loweredTypeCode, &loweredTypeCode2) != BfTypeCode_None;
 
 		auto thisTypeInst = thisType->ToTypeInstance();
 		paramVar->mIsStruct = isThisStruct;
@@ -15472,19 +15509,28 @@ void BfModule::ProcessMethod_SetupParams(BfMethodInstance* methodInstance, BfTyp
 				argIdx++;
 			}
 		}
+
+		if (loweredTypeCode2 != BfTypeCode_None)
+			argIdx++;
 	}
 
+	if (argIdx == methodInstance->GetStructRetIdx())
+		argIdx++;
+
 	bool hadParams = false;
 	bool hasDefault = false;
 
 	int compositeVariableIdx = -1;
 	int paramIdx = 0;
 	for (paramIdx = 0; paramIdx < methodInstance->GetParamCount(); paramIdx++)
-	{
+	{		
 		// We already issues a type error for this param if we had one in declaration processing
 		SetAndRestoreValue<bool> prevIgnoreErrors(mIgnoreErrors, true);
 		BfLocalVariable* paramVar = new BfLocalVariable();
 
+		BfTypeCode loweredTypeCode = BfTypeCode_None;
+		BfTypeCode loweredTypeCode2 = BfTypeCode_None;
+
 		bool isParamSkipped = methodInstance->IsParamSkipped(paramIdx);
 
 		BfType* unresolvedType = methodInstance->GetParamType(paramIdx, false);
@@ -15529,7 +15575,7 @@ void BfModule::ProcessMethod_SetupParams(BfMethodInstance* methodInstance, BfTyp
 			paramVar->mIsSplat = true; // Treat skipped (valueless) as a splat
 			paramVar->mValue = mBfIRBuilder->GetFakeVal();
 		}
-		paramVar->mIsLowered = resolvedType->GetLoweredType() != BfTypeCode_None;
+		paramVar->mIsLowered = resolvedType->GetLoweredType(BfTypeUsage_Parameter, &loweredTypeCode, &loweredTypeCode2) != BfTypeCode_None;
 		paramVar->mIsStruct = resolvedType->IsComposite() && !resolvedType->IsTypedPrimitive();
 		paramVar->mParamIdx = paramIdx;
 		paramVar->mIsImplicitParam = methodInstance->IsImplicitCapture(paramIdx);
@@ -15639,6 +15685,9 @@ void BfModule::ProcessMethod_SetupParams(BfMethodInstance* methodInstance, BfTyp
 			{
 				argIdx++;
 			}
+
+			if (loweredTypeCode2 != BfTypeCode_None)
+				argIdx++;
 		}
 	}
 
@@ -16754,10 +16803,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
 	{
 		int localIdx = 0;
 		int argIdx = 0;				
-
-		if (methodInstance->HasStructRet())		
-			argIdx++;		
-		
+				
 		Array<BfIRValue> splatAddrValues;
 
 		for ( ; argIdx < irParamCount; localIdx++)
@@ -16766,6 +16812,13 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
 			if ((isThis) && (thisType->IsValuelessType()))
 				isThis = false;
 
+			if (methodInstance->GetStructRetIdx() == argIdx)
+			{
+				argIdx++;
+				if (argIdx == irParamCount)
+					break;
+			}
+
 			BfLocalVariable* paramVar = NULL;
 			while (true)
 			{
@@ -16782,7 +16835,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
 				paramVar->mIsReadOnly = true;
 			}
 			
-			bool wantsAddr = (wantsDIVariables) || (!paramVar->mIsReadOnly) || (paramVar->mResolvedType->GetLoweredType() != BfTypeCode_None);
+			bool wantsAddr = (wantsDIVariables) || (!paramVar->mIsReadOnly) || (paramVar->mResolvedType->GetLoweredType(BfTypeUsage_Parameter));
 
 			if (paramVar->mResolvedType->IsMethodRef())
 				wantsAddr = false;			
@@ -16895,6 +16948,15 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
 			{
 				BfTypeUtils::SplatIterate([&](BfType* checkType) { argIdx++; }, paramVar->mResolvedType);
 			}
+			else if (paramVar->mIsLowered)
+			{
+				BfTypeCode loweredTypeCode = BfTypeCode_None;
+				BfTypeCode loweredTypeCode2 = BfTypeCode_None;
+				paramVar->mResolvedType->GetLoweredType(BfTypeUsage_Parameter, &loweredTypeCode, &loweredTypeCode2);
+				argIdx++;
+				if (loweredTypeCode2 != BfTypeCode_None)
+					argIdx++;
+			}
 			else
 			{
 				argIdx++;
@@ -16909,12 +16971,13 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
 		int declArgIdx = 0;
 		localIdx = 0;
 		argIdx = 0;
-		if (methodInstance->HasStructRet())
-			argIdx++;				
-	
+		
 		int splatAddrIdx = 0;		
 		while (localIdx < (int)methodState.mLocals.size())
 		{
+			if (argIdx == methodInstance->GetStructRetIdx())
+				argIdx++;
+
 			int curLocalIdx = localIdx++;
 			BfLocalVariable* paramVar = methodState.mLocals[curLocalIdx];
 			if (!paramVar->IsParam())
@@ -17010,19 +17073,34 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
 					bool handled = false;					
 					if (paramVar->mIsLowered)
 					{						
-						auto loweredTypeCode = paramVar->mResolvedType->GetLoweredType();
-						BF_ASSERT(loweredTypeCode != BfTypeCode_None);
-						if (loweredTypeCode != BfTypeCode_None)
+						BfTypeCode loweredTypeCode = BfTypeCode_None;
+						BfTypeCode loweredTypeCode2 = BfTypeCode_None;						
+						if (paramVar->mResolvedType->GetLoweredType(BfTypeUsage_Parameter, &loweredTypeCode, &loweredTypeCode2))
 						{
 							// We have a lowered type coming in, so we have to cast the .addr before storing
-							auto primType = GetPrimitiveType(loweredTypeCode);
-							auto primPtrType = CreatePointerType(primType);
-							auto primPtrVal = mBfIRBuilder->CreateBitCast(paramVar->mAddr, mBfIRBuilder->MapType(primPtrType));
-							mBfIRBuilder->CreateAlignedStore(paramVar->mValue, primPtrVal, paramVar->mResolvedType->mSize);
+							auto primType = mBfIRBuilder->GetPrimitiveType(loweredTypeCode);
+							auto primPtrType = mBfIRBuilder->GetPointerTo(primType);
+							auto primPtrVal = mBfIRBuilder->CreateBitCast(paramVar->mAddr, primPtrType);
+							mBfIRBuilder->CreateStore(paramVar->mValue, primPtrVal);
+
+							if (loweredTypeCode2 != BfTypeCode_None)
+							{
+								declArgIdx++;
+
+								auto primType2 = mBfIRBuilder->GetPrimitiveType(loweredTypeCode2);
+								auto primPtrType2 = mBfIRBuilder->GetPointerTo(primType2);
+								auto primPtrVal2 = mBfIRBuilder->CreateBitCast(mBfIRBuilder->CreateInBoundsGEP(primPtrVal, 1), primPtrType2);
+								mBfIRBuilder->CreateStore(mBfIRBuilder->GetArgument(argIdx + 1), primPtrVal2);
+							}
+
 							// We don't want to allow directly using value
 							paramVar->mValue = BfIRValue();
 							handled = true;
 						}						
+						else
+						{
+							BF_ASSERT("Expected lowered");
+						}
 					}
 
 					if (!handled)
@@ -17190,6 +17268,15 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
 			{
 				BfTypeUtils::SplatIterate([&](BfType* checkType) { argIdx++; }, paramVar->mResolvedType);
 			}
+			else if (paramVar->mIsLowered)
+			{
+				argIdx++;
+				BfTypeCode loweredTypeCode = BfTypeCode_None;
+				BfTypeCode loweredTypeCode2 = BfTypeCode_None;
+				paramVar->mResolvedType->GetLoweredType(BfTypeUsage_Parameter, &loweredTypeCode, &loweredTypeCode2);
+				if (loweredTypeCode != BfTypeCode_None)
+					argIdx++;
+			}
 			else if (!paramVar->mResolvedType->IsValuelessType())
 			{
 				argIdx++;
@@ -17322,10 +17409,10 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
 				{
 					BF_ASSERT(innerType->IsUnspecializedType());
 				}
-				else if (methodInstance->HasStructRet())
+				else if (methodInstance->GetStructRetIdx() != -1)
 				{
 					mBfIRBuilder->PopulateType(methodInstance->mReturnType);
-					auto returnType = BfTypedValue(mBfIRBuilder->GetArgument(0), methodInstance->mReturnType, true);
+					auto returnType = BfTypedValue(mBfIRBuilder->GetArgument(methodInstance->GetStructRetIdx()), methodInstance->mReturnType, true);
 					exprEvaluator.mReceivingValue = &returnType;
 					auto retVal = exprEvaluator.CreateCall(innerMethodInstance.mMethodInstance, innerMethodInstance.mFunc, true, innerParams, NULL, true);					
 					BF_ASSERT(exprEvaluator.mReceivingValue == NULL); // Ensure it was actually used
@@ -17692,11 +17779,11 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
 		{			
 			mBfIRBuilder->PopulateType(mCurMethodInstance->mReturnType);
 			
-			if (mCurMethodInstance->HasStructRet())
+			if (mCurMethodInstance->GetStructRetIdx() != -1)
 			{			
 				auto ptrType = CreatePointerType(mCurMethodInstance->mReturnType);
 				auto allocaInst = AllocLocalVariable(ptrType, "__return.addr", false);				
-				auto storeInst = mBfIRBuilder->CreateStore(mBfIRBuilder->GetArgument(0), allocaInst);
+				auto storeInst = mBfIRBuilder->CreateStore(mBfIRBuilder->GetArgument(mCurMethodInstance->GetStructRetIdx()), allocaInst);
 				mBfIRBuilder->ClearDebugLocation(storeInst);
 				mCurMethodState->mRetValAddr = allocaInst;
 			}
@@ -17886,7 +17973,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
 
 	if (mCurMethodState->mIRExitBlock)
 	{
-		if ((mCurMethodState->mRetVal) && (!mCurMethodInstance->HasStructRet()))
+		if ((mCurMethodState->mRetVal) && (mCurMethodInstance->GetStructRetIdx() == -1))
 		{			
 			auto loadedVal = mBfIRBuilder->CreateLoad(mCurMethodState->mRetVal.mValue);
 			
@@ -19913,9 +20000,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
 	}
 
 	int argIdx = 0;
-	PopulateType(methodInstance->mReturnType, BfPopulateType_Data);
-	if (methodInstance->HasStructRet())
-		argIdx++;
+	PopulateType(methodInstance->mReturnType, BfPopulateType_Data);	
 	if (!methodDef->mIsStatic)
     {
 		if (methodInstance->GetParamIsSplat(-1))
@@ -19923,6 +20008,10 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
 		else if (!methodInstance->GetOwner()->IsValuelessType())
 			argIdx++;
 	}
+
+	if (methodInstance->GetStructRetIdx() != -1)
+		argIdx++;
+
 	for (auto& methodParam : mCurMethodInstance->mParams)
 	{
 		if (methodParam.mResolvedType->IsMethodRef())

+ 1 - 0
IDEHelper/Compiler/BfModule.h

@@ -1631,6 +1631,7 @@ public:
 	BfTypeInstance* GetWrappedStructType(BfType* type, bool allowSpecialized = true);
 	BfTypeInstance* GetPrimitiveStructType(BfTypeCode typeCode);
 	BfPrimitiveType* GetPrimitiveType(BfTypeCode typeCode);	
+	BfIRType GetIRLoweredType(BfTypeCode loweredTypeCode, BfTypeCode loweredTypeCode2);
 	BfMethodRefType* CreateMethodRefType(BfMethodInstance* methodInstance, bool mustAlreadyExist = false);
 	BfType* FixIntUnknown(BfType* type);
 	void FixIntUnknown(BfTypedValue& typedVal, BfType* matchType = NULL);	

+ 16 - 31
IDEHelper/Compiler/BfModuleTypeUtils.cpp

@@ -3136,37 +3136,6 @@ bool BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 			if (isCRepr)
 			{				
 				typeInstance->mIsSplattable = false;
-
-				if ((mCompiler->mOptions.mPlatformType == BfPlatformType_Windows) && (mCompiler->mSystem->mPtrSize == 4))
-				{					
-					// Win32 splat rules
-					if ((typeInstance->mBaseType->mInstSize == 0) && (typeInstance->mInstSize <= 16))
-					{
-						typeInstance->mIsSplattable = true;
-
-						for (int fieldIdx = 0; fieldIdx < (int)typeInstance->mFieldInstances.size(); fieldIdx++)
-						{
-							auto fieldInstance = (BfFieldInstance*)&typeInstance->mFieldInstances[fieldIdx];
-							if (fieldInstance->mDataIdx >= 0)
-							{
-								if (!fieldInstance->mResolvedType->IsPrimitiveType())
-									typeInstance->mIsSplattable = false;
-								else
-								{
-									auto primType = (BfPrimitiveType*)fieldInstance->mResolvedType;
-									if ((primType->mTypeDef->mTypeCode != BfTypeCode_Int32) &&
-										(primType->mTypeDef->mTypeCode != BfTypeCode_UInt32) &&
-										(primType->mTypeDef->mTypeCode != BfTypeCode_IntPtr) &&
-										(primType->mTypeDef->mTypeCode != BfTypeCode_UIntPtr) &&
-										(primType->mTypeDef->mTypeCode != BfTypeCode_Pointer) &&
-										(primType->mTypeDef->mTypeCode != BfTypeCode_Single) &&
-										(primType->mTypeDef->mTypeCode != BfTypeCode_Double))
-										typeInstance->mIsSplattable = false;
-								}
-							}
-						}
-					}
-				}
 			}
 			else
 				typeInstance->mIsSplattable = (dataCount <= 3) && (!hadNonSplattable);
@@ -4736,6 +4705,18 @@ BfPrimitiveType* BfModule::GetPrimitiveType(BfTypeCode typeCode)
 	return primType;
 }
 
+BfIRType BfModule::GetIRLoweredType(BfTypeCode loweredTypeCode, BfTypeCode loweredTypeCode2)
+{
+	BF_ASSERT(loweredTypeCode != BfTypeCode_None);	
+	if (loweredTypeCode2 == BfTypeCode_None)	
+		return mBfIRBuilder->GetPrimitiveType(loweredTypeCode);	
+		
+	SizedArray<BfIRType, 2> types;
+	types.push_back(mBfIRBuilder->GetPrimitiveType(loweredTypeCode));
+	types.push_back(mBfIRBuilder->GetPrimitiveType(loweredTypeCode2));
+	return mBfIRBuilder->CreateStructType(types);	
+}
+
 BfMethodRefType* BfModule::CreateMethodRefType(BfMethodInstance* methodInstance, bool mustAlreadyExist)
 {
 	auto methodRefType = new BfMethodRefType();
@@ -7803,6 +7784,10 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 					genericTypeInst = new BfTypeInstance();
 				genericTypeInst->mGenericTypeInfo = new BfGenericTypeInfo();
 				genericTypeInst->mTypeDef = typeDef;
+
+				if (parentGenericTypeInstance->mGenericTypeInfo->mGenericParams.IsEmpty())
+					PopulateType(parentGenericTypeInstance, BfPopulateType_Declaration);
+
 				for (int i = 0; i < numParentGenericParams; i++)
 				{
 					genericTypeInst->mGenericTypeInfo->mGenericParams.push_back(parentGenericTypeInstance->mGenericTypeInfo->mGenericParams[i]->AddRef());

+ 2 - 1
IDEHelper/Compiler/BfReducer.cpp

@@ -7370,7 +7370,8 @@ BfObjectCreateExpression* BfReducer::CreateObjectCreateExpression(BfAstNode* all
 			SetAndRestoreValue<BfVisitorPos> prevVisitorPos(mVisitorPos, BfVisitorPos(block));
 			ReadArguments(objectCreateExpr, objectCreateExpr, &arguments, &commas, BfToken_None, true);
 		}
-		MEMBER_SET(objectCreateExpr, mCloseToken, block->mCloseBrace);
+		if (block->mCloseBrace != NULL)
+			MEMBER_SET(objectCreateExpr, mCloseToken, block->mCloseBrace);
 		return objectCreateExpr;
 	}	
 

+ 146 - 31
IDEHelper/Compiler/BfResolvedTypeUtils.cpp

@@ -611,9 +611,24 @@ bool BfMethodInstance::HasParamsArray()
 	return GetParamKind((int)mParams.size() - 1) == BfParamKind_Params;
 }
 
-bool BfMethodInstance::HasStructRet()
+int BfMethodInstance::GetStructRetIdx()
 {
-	return (mReturnType->IsComposite()) && (!mReturnType->IsValuelessType()) && (mReturnType->GetLoweredType() == BfTypeCode_None);
+	if ((mReturnType->IsComposite()) && (!mReturnType->IsValuelessType()) && (!GetLoweredReturnType()))
+	{
+		auto owner = mMethodInstanceGroup->mOwner;
+		if (owner->mModule->mCompiler->mOptions.mPlatformType != BfPlatformType_Windows)
+			return 0;
+
+		if (!HasThis())
+			return 0;		
+		if (!owner->IsValueType())
+			return 1;		
+		if ((mMethodDef->mIsMutating) || ((!AllowsSplatting()) && (!owner->GetLoweredType(BfTypeUsage_Parameter))))
+			return 1;
+		return 0;		
+	}
+
+	return -1;
 }
 
 bool BfMethodInstance::HasSelf()
@@ -626,6 +641,11 @@ bool BfMethodInstance::HasSelf()
 	return false;
 }
 
+bool BfMethodInstance::GetLoweredReturnType(BfTypeCode* loweredTypeCode, BfTypeCode* loweredTypeCode2)
+{	
+	return mReturnType->GetLoweredType(mMethodDef->mIsStatic ? BfTypeUsage_Return_Static : BfTypeUsage_Return_NonStatic, loweredTypeCode, loweredTypeCode2);	
+}
+
 bool BfMethodInstance::IsSkipCall(bool bypassVirtual)
 {	
 	if ((mMethodDef->mIsSkipCall) && 
@@ -743,7 +763,7 @@ BfType* BfMethodInstance::GetParamType(int paramIdx, bool useResolvedType)
 			return mMethodInfoEx->mClosureInstanceInfo->mThisOverride;
 		BF_ASSERT(!mMethodDef->mIsStatic);
 		auto owner = mMethodInstanceGroup->mOwner;
-		if ((owner->IsValueType()) && ((mMethodDef->mIsMutating) || (!AllowsSplatting())) && (owner->GetLoweredType() == BfTypeCode_None))
+		if ((owner->IsValueType()) && ((mMethodDef->mIsMutating) || (!AllowsSplatting())) && (!owner->GetLoweredType(BfTypeUsage_Parameter)))
 			return owner->mModule->CreatePointerType(owner);
 		return owner;
 	}
@@ -849,8 +869,6 @@ BfIdentifierNode* BfMethodInstance::GetParamNameNode(int paramIdx)
 	BfParameterDef* paramDef = mMethodDef->mParams[methodParam->mParamDefIdx];
 	if (paramDef->mParamDeclaration != NULL)
 		return BfNodeDynCast<BfIdentifierNode>(paramDef->mParamDeclaration->mNameNode);
-// 	else if ((mClosureInstanceInfo != NULL) && (paramIdx < (int)mClosureInstanceInfo->mCaptureNodes.size()))
-// 		return mClosureInstanceInfo->mCaptureNodes[paramIdx];
 	return NULL;
 }
 
@@ -894,37 +912,39 @@ int BfMethodInstance::DbgGetVirtualMethodNum()
 }
 
 void BfMethodInstance::GetIRFunctionInfo(BfModule* module, BfIRType& returnType, SizedArrayImpl<BfIRType>& paramTypes, bool forceStatic)
-{	
+{
 	module->PopulateType(mReturnType);
-
-	BfType* loweredReturnType = mReturnType;
-	auto loweredReturnTypeCode = mReturnType->GetLoweredType();
-	if (loweredReturnTypeCode != BfTypeCode_None)
-		loweredReturnType = module->GetPrimitiveType(loweredReturnTypeCode);
-
-	if (loweredReturnType->IsValuelessType())
+	
+	BfTypeCode loweredReturnTypeCode = BfTypeCode_None;
+	BfTypeCode loweredReturnTypeCode2 = BfTypeCode_None;	
+	if (GetLoweredReturnType(&loweredReturnTypeCode, &loweredReturnTypeCode2))
+	{
+		auto irReturnType = module->GetIRLoweredType(loweredReturnTypeCode, loweredReturnTypeCode2);
+		returnType = irReturnType;
+	}
+	else if (mReturnType->IsValuelessType())
 	{
 		auto voidType = module->GetPrimitiveType(BfTypeCode_None);
 		returnType = module->mBfIRBuilder->MapType(voidType);
 	}
-	else if (loweredReturnType->IsComposite())
+	else if (mReturnType->IsComposite())
 	{
 		auto voidType = module->GetPrimitiveType(BfTypeCode_None);
 		returnType = module->mBfIRBuilder->MapType(voidType);
-		auto typeInst = loweredReturnType->ToTypeInstance();
+		auto typeInst = mReturnType->ToTypeInstance();
 		if (typeInst != NULL)
 		{
 			paramTypes.push_back(module->mBfIRBuilder->MapTypeInstPtr(typeInst));
 		}
 		else
 		{
-			auto ptrType = module->CreatePointerType(loweredReturnType);
+			auto ptrType = module->CreatePointerType(mReturnType);
 			paramTypes.push_back(module->mBfIRBuilder->MapType(ptrType));
 		}
 	}
 	else
 	{
-		returnType = module->mBfIRBuilder->MapType(loweredReturnType);
+		returnType = module->mBfIRBuilder->MapType(mReturnType);
 	}	
 
 	for (int paramIdx = -1; paramIdx < GetParamCount(); paramIdx++)
@@ -972,11 +992,18 @@ void BfMethodInstance::GetIRFunctionInfo(BfModule* module, BfIRType& returnType,
 				checkLowered = true;
 		}
 
+		BfType* checkType2 = NULL;
 		if (checkLowered)
 		{
-			auto loweredTypeCode = checkType->GetLoweredType();
-			if (loweredTypeCode != BfTypeCode_None)
-				checkType = module->GetPrimitiveType(loweredTypeCode);
+			BfTypeCode loweredTypeCode = BfTypeCode_None;
+			BfTypeCode loweredTypeCode2 = BfTypeCode_None;
+			if (checkType->GetLoweredType(BfTypeUsage_Parameter, &loweredTypeCode, &loweredTypeCode2))
+			{
+				paramTypes.push_back(module->mBfIRBuilder->GetPrimitiveType(loweredTypeCode));
+				if (loweredTypeCode2 != BfTypeCode_None)
+					paramTypes.push_back(module->mBfIRBuilder->GetPrimitiveType(loweredTypeCode2));
+				continue;
+			}							
 		}
 
 		if ((paramIdx == 0) && (GetParamName(0) == "this") && (checkType->IsPointer()))
@@ -1032,8 +1059,15 @@ void BfMethodInstance::GetIRFunctionInfo(BfModule* module, BfIRType& returnType,
 			}, checkType);
 		}
 		else
-			_AddType(checkType);
-		
+			_AddType(checkType);		
+
+		if (checkType2 != NULL)
+			_AddType(checkType2);
+	}
+
+	if ((GetStructRetIdx() == 1) && (!forceStatic))
+	{		
+		BF_SWAP(paramTypes[0], paramTypes[1]);
 	}
 }
 
@@ -1414,19 +1448,100 @@ BfPrimitiveType* BfTypeInstance::GetDiscriminatorType(int* outDataIdx)
 	return (BfPrimitiveType*)fieldInstance.mResolvedType;
 }
 
-BfTypeCode BfTypeInstance::GetLoweredType()
-{
-	if ((mTypeDef->mTypeCode != BfTypeCode_Struct) || (mIsSplattable))
-		return BfTypeCode_None;
+bool BfTypeInstance::GetLoweredType(BfTypeUsage typeUsage, BfTypeCode* outTypeCode, BfTypeCode* outTypeCode2)
+{	 	
+	if ((mTypeDef->mTypeCode != BfTypeCode_Struct) || (IsBoxed()) || (mIsSplattable))
+		return false;
+
+	if (mModule->mCompiler->mOptions.mPlatformType == BfPlatformType_Windows)
+	{
+		// Odd Windows rule: composite returns for non-static methods are always sret
+		if (typeUsage == BfTypeUsage_Return_NonStatic)
+			return false;
+	}
+	else
+	{		
+		// Non-Windows systems allow lowered splitting of composites over two int params
+ 		if (mModule->mSystem->mPtrSize == 8)
+ 		{
+ 			if (mInstSize == 12)
+ 			{
+ 				if (outTypeCode != NULL)
+ 					*outTypeCode = BfTypeCode_Int64;
+ 				if (outTypeCode2 != NULL)
+ 					*outTypeCode2 = BfTypeCode_Int32;
+ 				return true;
+ 			}
+ 
+ 			if (mInstSize == 16)
+ 			{
+ 				if (outTypeCode != NULL)
+ 					*outTypeCode = BfTypeCode_Int64;
+ 				if (outTypeCode2 != NULL)
+ 					*outTypeCode2 = BfTypeCode_Int64;
+ 				return true;
+ 			}
+ 		}	
+	}
+
+	BfTypeCode typeCode = BfTypeCode_None;
+	BfTypeCode pow2TypeCode = BfTypeCode_None;
 	
 	switch (mInstSize)
 	{
-	case 1: return BfTypeCode_Int8;
-	case 2: return BfTypeCode_Int16;
-	case 4: return BfTypeCode_Int32;
-	case 8: if (mModule->mSystem->mPtrSize == 8) return BfTypeCode_Int64;
+	case 1: 
+		pow2TypeCode = BfTypeCode_Int8;
+		break;
+	case 2: 
+		pow2TypeCode = BfTypeCode_Int16;
+		break;
+	case 3:
+		typeCode = BfTypeCode_Int24;
+		break;
+	case 4: 
+		pow2TypeCode = BfTypeCode_Int32;
+		break;
+	case 5:
+		typeCode = BfTypeCode_Int40;
+		break;
+	case 6:
+		typeCode = BfTypeCode_Int48;
+		break;
+	case 7:
+		typeCode = BfTypeCode_Int56;
+		break;
+	case 8: 					
+		if (mModule->mSystem->mPtrSize == 8)
+		{
+			pow2TypeCode = BfTypeCode_Int64;
+			break;
+		}
+		if (typeUsage == BfTypeUsage_Return_Static)
+		{
+			pow2TypeCode = BfTypeCode_Int64;
+			break;
+		}
+		break;	
+	}
+
+	if (pow2TypeCode != BfTypeCode_None)
+	{
+		if (outTypeCode != NULL)
+			*outTypeCode = pow2TypeCode;
+		return true;
+	}
+	
+	if (mModule->mCompiler->mOptions.mPlatformType != BfPlatformType_Windows)
+	{
+		if (typeCode != BfTypeCode_None)
+		{
+			if (outTypeCode != NULL)
+				*outTypeCode = typeCode;
+			return true;
+		}
 	}
-	return BfTypeCode_None;
+
+	return false;
 }
 
 bool BfTypeInstance::HasEquivalentLayout(BfTypeInstance* compareTo)

+ 14 - 5
IDEHelper/Compiler/BfResolvedTypeUtils.h

@@ -428,6 +428,14 @@ public:
 	}
 };
 
+enum BfTypeUsage
+{
+	BfTypeUsage_Unspecified,
+	BfTypeUsage_Return_Static,
+	BfTypeUsage_Return_NonStatic,	
+	BfTypeUsage_Parameter,
+};
+
 class BfType
 {
 public:
@@ -539,7 +547,7 @@ public:
 	virtual bool IsConstExprValue() { return false; }
 	virtual bool IsDependentOnUnderlyingType() { return false; }
 	virtual bool WantsGCMarking() { return false; }
-	virtual BfTypeCode GetLoweredType() { return BfTypeCode_None; }
+	virtual bool GetLoweredType(BfTypeUsage typeUsage, BfTypeCode* outTypeCode = NULL, BfTypeCode* outTypeCode2 = NULL) { return false; }
 	virtual BfType* GetUnderlyingType() { return NULL; }	
 	virtual bool HasWrappedRepresentation() { return IsWrappableType(); }
 	virtual bool IsTypeMemberIncluded(BfTypeDef* declaringTypeDef, BfTypeDef* activeTypeDef = NULL, BfModule* module = NULL) { return true; } // May be 'false' only for generic extensions with constraints
@@ -852,8 +860,9 @@ public:
 	bool IsSpecializedByAutoCompleteMethod();
 	bool HasThis();	
 	bool HasParamsArray();
-	bool HasStructRet();
+	int GetStructRetIdx();
 	bool HasSelf();
+	bool GetLoweredReturnType(BfTypeCode* loweredTypeCode = NULL, BfTypeCode* loweredTypeCode2 = NULL);
 	bool IsAutocompleteMethod() { /*return mIdHash == -1;*/ return mIsAutocompleteMethod; }
 	bool IsSkipCall(bool bypassVirtual = false);	
 	bool IsVarArgs();
@@ -1827,11 +1836,11 @@ public:
 	virtual bool IsTypeMemberAccessible(BfTypeDef* declaringTypeDef, BfTypeDef* activeTypeDef) override;
 	virtual bool IsTypeMemberAccessible(BfTypeDef* declaringTypeDef, BfProject* curProject) override;	
 	virtual bool WantsGCMarking() override;
-	virtual BfTypeCode GetLoweredType() override;
+	virtual bool GetLoweredType(BfTypeUsage typeUsage, BfTypeCode* outTypeCode = NULL, BfTypeCode* outTypeCode2 = NULL) override;
 
 	BfGenericTypeInfo* GetGenericTypeInfo() { return mGenericTypeInfo; }
  
-	virtual BfTypeInstance* ToGenericTypeInstance() { return (mGenericTypeInfo != NULL) ? this : NULL; }
+	virtual BfTypeInstance* ToGenericTypeInstance() override { return (mGenericTypeInfo != NULL) ? this : NULL; }
  	virtual bool IsGenericTypeInstance() override { return mGenericTypeInfo != NULL; }
  	virtual bool IsSpecializedType() override { return (mGenericTypeInfo != NULL) && (!mGenericTypeInfo->mIsUnspecialized); }
  	virtual bool IsSpecializedByAutoCompleteMethod() override;
@@ -2020,7 +2029,7 @@ public:
 	virtual bool IsUnspecializedType() override { return mIsUnspecializedType; }
 	virtual bool IsUnspecializedTypeVariation() override { return mIsUnspecializedTypeVariation; }
 
-	virtual BfDelegateInfo* GetDelegateInfo() { return &mDelegateInfo; }
+	virtual BfDelegateInfo* GetDelegateInfo() override { return &mDelegateInfo; }
 };
 
 class BfTupleType : public BfTypeInstance

+ 2 - 2
IDEHelper/Compiler/BfStmtEvaluator.cpp

@@ -4885,12 +4885,12 @@ void BfModule::Visit(BfReturnStatement* returnStmt)
 	BfType* origType;
 	BfExprEvaluator exprEvaluator(this);
 	bool alreadyWritten = false;
-	if (mCurMethodInstance->HasStructRet())	
+	if (mCurMethodInstance->GetStructRetIdx() != -1)	
 		exprEvaluator.mReceivingValue = &mCurMethodState->mRetVal;	
 	if (mCurMethodInstance->mMethodDef->mIsReadOnly)
 		exprEvaluator.mAllowReadOnlyReference = true;
 	auto retValue = CreateValueFromExpression(exprEvaluator, returnStmt->mExpression, expectingReturnType, BfEvalExprFlags_AllowRefExpr, &origType);	
-	if (mCurMethodInstance->HasStructRet())	
+	if (mCurMethodInstance->GetStructRetIdx() != -1)
 		alreadyWritten = exprEvaluator.mReceivingValue == NULL;
 	MarkScopeLeft(&mCurMethodState->mHeadScope);
 	

+ 23 - 2
IDEHelper/DbgExprEvaluator.cpp

@@ -6734,7 +6734,7 @@ DbgTypedValue DbgExprEvaluator::CreateCall(BfAstNode* targetSrc, DbgTypedValue t
 
 		if ((param != NULL) && (param->mType != NULL) && (param->mType->IsCompositeType()))
 		{
-			if (splatParams.Contains(param->mName))
+			if ((param->mName != NULL) && (splatParams.Contains(param->mName)))
 			{
 				std::function<void(const DbgTypedValue& typedVal)> _SplatArgs = [&](const DbgTypedValue& typedVal)
 				{
@@ -7267,7 +7267,7 @@ DbgTypedValue DbgExprEvaluator::MatchMethod(BfAstNode* targetSrc, DbgTypedValue
 	}
 	else if (methodName == "__demangleMethod")
 	{
-		if (argValues.size() == 1)
+		if (argValues.size() == 2)
 		{
 			auto checkType = argValues[0].mType;
 			if (checkType->IsPointer())
@@ -7293,6 +7293,27 @@ DbgTypedValue DbgExprEvaluator::MatchMethod(BfAstNode* targetSrc, DbgTypedValue
 			}
 		}
 	}
+	else if (methodName == "__demangle")
+	{
+		if (argValues.size() == 1)
+		{
+			auto rawTextType = mDbgModule->GetPrimitiveType(DbgType_RawText, GetLanguage());
+
+			String mangledName = argValues[0].mCharPtr;
+
+			static String demangledName;
+			demangledName = BfDemangler::Demangle(mangledName, DbgLanguage_Unknown);
+
+			if (demangledName.StartsWith("bf."))
+				demangledName.Remove(0, 3);
+
+			DbgTypedValue result;
+			result.mType = rawTextType;
+			result.mCharPtr = demangledName.c_str();
+			result.mIsLiteral = true;
+			return result;
+		}
+	}
 	else if (methodName == "__demangleFakeMember")
 	{
 		if (argValues.size() == 1)

+ 12 - 0
IDEHelper/DbgExprEvaluator.h

@@ -158,6 +158,18 @@ public:
 		return mPtr;
 	}
 
+	String GetString() const
+	{
+		if (!mType->IsPointer())
+			return "";
+		if ((mType->mTypeParam->mTypeCode != DbgType_SChar) && (mType->mTypeParam->mTypeCode != DbgType_UChar))
+			return "";
+		if (mIsLiteral)
+			return mCharPtr;
+		//return (const char*)mPtr;
+		return "";
+	}
+
 	operator bool() const
 	{
 		return (mType != NULL) && (!mHasNoValue);

+ 31 - 0
IDEHelper/Tests/CLib/CLib.sln

@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.28307.645
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CLib", "CLib.vcxproj", "{D72A956A-5D9C-42F4-B35B-05F0B05B632C}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{D72A956A-5D9C-42F4-B35B-05F0B05B632C}.Debug|x64.ActiveCfg = Debug|x64
+		{D72A956A-5D9C-42F4-B35B-05F0B05B632C}.Debug|x64.Build.0 = Debug|x64
+		{D72A956A-5D9C-42F4-B35B-05F0B05B632C}.Debug|x86.ActiveCfg = Debug|Win32
+		{D72A956A-5D9C-42F4-B35B-05F0B05B632C}.Debug|x86.Build.0 = Debug|Win32
+		{D72A956A-5D9C-42F4-B35B-05F0B05B632C}.Release|x64.ActiveCfg = Release|x64
+		{D72A956A-5D9C-42F4-B35B-05F0B05B632C}.Release|x64.Build.0 = Release|x64
+		{D72A956A-5D9C-42F4-B35B-05F0B05B632C}.Release|x86.ActiveCfg = Release|Win32
+		{D72A956A-5D9C-42F4-B35B-05F0B05B632C}.Release|x86.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {B4D3315D-D9A9-4A82-BEC4-B05271FC794E}
+	EndGlobalSection
+EndGlobal

+ 162 - 0
IDEHelper/Tests/CLib/CLib.vcxproj

@@ -0,0 +1,162 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <VCProjectVersion>15.0</VCProjectVersion>
+    <ProjectGuid>{D72A956A-5D9C-42F4-B35B-05F0B05B632C}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>CLib</RootNamespace>
+    <WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="Shared">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <LinkIncremental>false</LinkIncremental>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+      <BufferSecurityCheck>false</BufferSecurityCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClInclude Include="stdafx.h" />
+    <ClInclude Include="targetver.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="main.cpp" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 30 - 0
IDEHelper/Tests/CLib/CLib.vcxproj.filters

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="stdafx.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="targetver.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="main.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+</Project>

+ 371 - 0
IDEHelper/Tests/CLib/main.cpp

@@ -0,0 +1,371 @@
+#include <inttypes.h>
+
+namespace Tests
+{
+	struct Interop
+	{
+		struct StructA
+		{
+			int mA;
+
+			int MethodA0(int arg0)
+			{
+				return arg0 + mA * 100;
+			}
+
+			StructA MethodA1(StructA other, int arg0)
+			{
+				StructA ret;
+				ret.mA = mA + other.mA + arg0;
+				return ret;
+			}
+		};
+
+		struct StructB
+		{
+			int mA;
+			char mB;
+
+			int MethodB0(int arg0)
+			{
+				return arg0 + mA * 100 + mB * 10000;
+			}
+
+			StructB MethodB1(StructB other, int arg0)
+			{
+				StructB ret;
+				ret.mA = mA + other.mA + arg0;
+				ret.mB = mB + other.mB;
+				return ret;
+			}
+		};
+
+		struct StructC
+		{
+			char mA;
+			int mB;
+
+			int MethodC0(int arg0)
+			{
+				return arg0 + mA * 100 + mB * 10000;
+			}
+
+			StructC MethodC1(StructC other, int arg0)
+			{
+				StructC ret;
+				ret.mA = mA + other.mA + arg0;
+				ret.mB = mB + other.mB;
+				return ret;
+			}
+		};
+
+		struct StructD
+		{
+			int mA;
+			int mB;
+
+			int MethodD0(int arg0)
+			{
+				return arg0 + mA * 100 + mB * 10000;
+			}
+
+			StructD MethodD1(StructD other, int arg0)
+			{
+				StructD ret;
+				ret.mA = mA + other.mA + arg0;
+				ret.mB = mB + other.mB;
+				return ret;
+			}
+		};
+
+		struct StructE
+		{
+			int mA;
+			int mB;
+			int mC;
+
+			int MethodE0(int arg0)
+			{
+				return arg0 + mA * 100 + mC * 10000;
+			}
+
+			StructE MethodE1(StructE other, int arg0)
+			{
+				StructE ret;
+				ret.mA = mA + other.mA + arg0;
+				ret.mB = mB + other.mB;
+				return ret;
+			}
+		};
+
+		struct StructF
+		{
+			char mA;
+			char mB;
+			char mC;
+
+			int MethodF0(int arg0)
+			{
+				return arg0 + mA * 100 + mC * 10000;
+			}
+
+			StructF MethodF1(StructF other, int arg0)
+			{
+				StructF ret;
+				ret.mA = mA + other.mA + arg0;
+				ret.mB = mB + other.mB;
+				return ret;
+			}
+		};
+
+		struct StructG
+		{
+			char mA;
+			char mB;
+			char mC;
+			char mD;
+
+			int MethodG0(int arg0)
+			{
+				return arg0 + mA * 100 + mC * 10000;
+			}
+
+			StructG MethodG1(StructG other, int arg0)
+			{
+				StructG ret;
+				ret.mA = mA + other.mA + arg0;
+				ret.mB = mB + other.mB;
+				return ret;
+			}
+		};
+
+		struct StructH
+		{
+			int64_t mA;
+			int64_t mB;
+			int64_t mC;			
+
+			int MethodH0(int arg0)
+			{
+				return arg0 + (int)mA * 100 + (int)mC * 10000;
+			}
+
+			StructH MethodH1(StructH other, int arg0)
+			{
+				StructH ret;
+				ret.mA = mA + other.mA + arg0;
+				ret.mB = mB + other.mB;
+				return ret;
+			}
+		};
+
+		struct StructI
+		{
+			char mA;
+			char mB;
+			char mC;
+			char mD;
+			char mE;
+
+			int MethodI0(int arg0)
+			{
+				return arg0 + (int)mA * 100 + (int)mC * 10000;
+			}
+
+			StructI MethodI1(StructI other, int arg0)
+			{
+				StructI ret;
+				ret.mA = mA + other.mA + arg0;
+				ret.mB = mB + other.mB;
+				return ret;
+			}
+		};
+	};
+}
+
+using namespace Tests;
+
+extern "C" int Func0(int a, int b)
+{
+	return a + b * 100;
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+extern "C" int Func1A(Interop::StructA arg0, Interop::StructA arg1, int arg2)
+{
+	return arg0.mA + arg1.mA * 100 + arg2 * 10000;
+}
+
+extern "C" int Func1B(Interop::StructB arg0, Interop::StructB arg1, int arg2)
+{
+	return arg0.mA + arg1.mA * 100 + arg2 * 10000;
+}
+
+extern "C" int Func1C(Interop::StructC arg0, Interop::StructC arg1, int arg2)
+{
+	return arg0.mA + arg1.mA * 100 + arg2 * 10000;
+}
+
+extern "C" int Func1D(Interop::StructD arg0, Interop::StructD arg1, int arg2)
+{
+	return arg0.mA + arg1.mA * 100 + arg2 * 10000;
+}
+
+extern "C" int Func1E(Interop::StructE arg0, Interop::StructE arg1, int arg2)
+{
+	return arg0.mA + arg1.mA * 100 + arg2 * 10000;
+}
+
+extern "C" int Func1F(Interop::StructF arg0, Interop::StructF arg1, int arg2)
+{
+	return arg0.mA + arg1.mA * 100 + arg2 * 10000;
+}
+
+extern "C" int Func1G(Interop::StructG arg0, Interop::StructG arg1, int arg2)
+{
+	return arg0.mA + arg1.mA * 100 + arg2 * 10000;
+}
+
+extern "C" int Func1H(Interop::StructH arg0, Interop::StructH arg1, int arg2)
+{
+	return (int)arg0.mA + (int)arg1.mA * 100 + arg2 * 10000;
+}
+
+extern "C" int Func1I(Interop::StructI arg0, Interop::StructI arg1, int arg2)
+{
+	return (int)arg0.mA + (int)arg1.mA * 100 + arg2 * 10000;
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+extern "C" Interop::StructA Func2A(Interop::StructA arg0, int arg1)
+{
+	Interop::StructA ret;
+	ret.mA = arg0.mA + arg1;
+	return ret;
+}
+
+extern "C" Interop::StructB Func2B(Interop::StructB arg0, int arg1)
+{
+	Interop::StructB ret;
+	ret.mA = arg0.mA + arg1;
+	return ret;
+}
+
+extern "C" Interop::StructC Func2C(Interop::StructC arg0, int arg1)
+{
+	Interop::StructC ret;
+	ret.mA = arg0.mA + arg1;
+	return ret;
+}
+
+extern "C" Interop::StructD Func2D(Interop::StructD arg0, int arg1)
+{
+	Interop::StructD ret;
+	ret.mA = arg0.mA + arg1;
+	return ret;
+}
+
+extern "C" Interop::StructE Func2E(Interop::StructE arg0, int arg1)
+{
+	Interop::StructE ret;
+	ret.mA = arg0.mA + arg1;
+	return ret;
+}
+
+extern "C" Interop::StructF Func2F(Interop::StructF arg0, int arg1)
+{
+	Interop::StructF ret;
+	ret.mA = arg0.mA + arg1;
+	return ret;
+}
+
+extern "C" Interop::StructG Func2G(Interop::StructG arg0, int arg1)
+{
+	Interop::StructG ret;
+	ret.mA = arg0.mA + arg1;
+	return ret;
+}
+
+extern "C" Interop::StructH Func2H(Interop::StructH arg0, int arg1)
+{
+	Interop::StructH ret;
+	ret.mA = arg0.mA + arg1;
+	return ret;
+}
+
+extern "C" Interop::StructI Func2I(Interop::StructI arg0, int arg1)
+{
+	Interop::StructI ret;
+	ret.mA = arg0.mA + arg1;
+	return ret;
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+extern "C" int Func3A(Interop::StructA* ptr)
+{
+	return ptr[0].mA + ptr[1].mA * 100;
+}
+
+extern "C" int Func3B(Interop::StructB* ptr)
+{
+	return ptr[0].mA + ptr[1].mA * 100;
+}
+
+extern "C" int Func3C(Interop::StructC* ptr)
+{
+	return ptr[0].mA + ptr[1].mA * 100;
+}
+
+extern "C" int Func3D(Interop::StructD* ptr)
+{
+	return ptr[0].mA + ptr[1].mA * 100;
+}
+
+extern "C" int Func3E(Interop::StructE* ptr)
+{
+	return ptr[0].mA + ptr[1].mA * 100;
+}
+
+extern "C" int Func3F(Interop::StructF* ptr)
+{
+	return ptr[0].mA + ptr[1].mA * 100;
+}
+
+extern "C" int Func3G(Interop::StructG* ptr)
+{
+	return ptr[0].mA + ptr[1].mA * 100;
+}
+
+void UseIt()
+{
+	Interop::StructA sa;
+	sa.MethodA0(0);
+	sa.MethodA1(sa, 1);
+	Interop::StructB sb;
+	sb.MethodB0(0);
+	sb.MethodB1(sb, 1);
+	Interop::StructC sc;
+	sc.MethodC0(0);
+	sc.MethodC1(sc, 1);
+	Interop::StructD sd;
+	sd.MethodD0(0);
+	sd.MethodD1(sd, 1);
+	Interop::StructE se;
+	se.MethodE0(0);
+	se.MethodE1(se, 1);
+	Interop::StructF sf;
+	sf.MethodF0(0);
+	sf.MethodF1(sf, 1);
+	Interop::StructG sg;
+	sg.MethodG0(0);
+	sg.MethodG1(sg, 1);
+	Interop::StructH sh;
+	sh.MethodH0(0);
+	sh.MethodH1(sh, 1);
+	Interop::StructI si;
+	si.MethodI0(0);
+	si.MethodI1(si, 1);
+}

+ 261 - 0
IDEHelper/Tests/src/Interop.bf

@@ -0,0 +1,261 @@
+using System;
+
+namespace Tests
+{
+	class Interop
+	{
+		[CRepr]
+		public struct StructA
+		{
+			public int32 mA;
+
+			[LinkName(.CPP)]
+			public extern int32 MethodA0(int32 arg0) mut;
+			[LinkName(.CPP)]
+			public extern StructA MethodA1(StructA sa, int32 arg0) mut;
+		}
+
+		[CRepr]
+		public struct StructB
+		{
+			public int32 mA;
+			public int8 mB;
+
+			[LinkName(.CPP)]
+			public extern int32 MethodB0(int32 arg0) mut;
+			[LinkName(.CPP)]
+			public extern StructB MethodB1(StructB sa, int32 arg0) mut;
+		}
+
+		[CRepr]
+		public struct StructC
+		{
+			public int8 mA;
+			public int32 mB;
+
+			[LinkName(.CPP)]
+			public extern int32 MethodC0(int32 arg0) mut;
+			[LinkName(.CPP)]
+			public extern StructC MethodC1(StructC sa, int32 arg0) mut;
+		}
+
+		[CRepr]
+		public struct StructD
+		{
+			public int32 mA;
+			public int32 mB;
+
+			[LinkName(.CPP)]
+			public extern int32 MethodD0(int32 arg0) mut;
+			[LinkName(.CPP)]
+			public extern StructD MethodD1(StructD sa, int32 arg0) mut;
+		}
+
+		[CRepr]
+		public struct StructE
+		{
+			public int32 mA;
+			public int32 mB;
+			public int32 mC;
+
+			[LinkName(.CPP)]
+			public extern int32 MethodE0(int32 arg0) mut;
+			[LinkName(.CPP)]
+			public extern StructE MethodE1(StructE sa, int32 arg0) mut;
+		}
+
+		[CRepr]
+		public struct StructF
+		{
+			public int8 mA;
+			public int8 mB;
+			public int8 mC;
+
+			[LinkName(.CPP)]
+			public extern int32 MethodF0(int32 arg0) mut;
+			[LinkName(.CPP)]
+			public extern StructF MethodF1(StructF sa, int32 arg0) mut;
+		}
+
+		[CRepr]
+		public struct StructG
+		{
+			public int8 mA;
+			public int8 mB;
+			public int8 mC;
+			public int8 mD;
+
+			[LinkName(.CPP)]
+			public extern int32 MethodG0(int32 arg0) mut;
+			[LinkName(.CPP)]
+			public extern StructG MethodG1(StructG sa, int32 arg0) mut;
+		}
+
+		[CRepr]
+		public struct StructH
+		{
+			public int64 mA;
+			public int64 mB;
+			public int64 mC;
+
+			[LinkName(.CPP)]
+			public extern int32 MethodH0(int32 arg0) mut;
+			[LinkName(.CPP)]
+			public extern StructH MethodH1(StructH sa, int32 arg0) mut;
+		}
+
+		[CRepr]
+		public struct StructI
+		{
+			public int8 mA;
+			public int8 mB;
+			public int8 mC;
+			public int8 mD;
+			public int8 mE;
+
+			[LinkName(.CPP)]
+			public extern int32 MethodI0(int32 arg0) mut;
+			[LinkName(.CPP)]
+			public extern StructI MethodI1(StructI sa, int32 arg0) mut;
+		}
+
+		[LinkName(.C)]
+		public static extern int32 Func0(int32 a, int32 b);
+
+		[LinkName(.C)]
+		public static extern int32 Func1A(StructA arg0, StructA arg1, int32 arg2);
+		[LinkName(.C)]
+		public static extern int32 Func1B(StructB arg0, StructB arg1, int32 arg2);
+		[LinkName(.C)]
+		public static extern int32 Func1C(StructC arg0, StructC arg1, int32 arg2);
+		[LinkName(.C)]
+		public static extern int32 Func1D(StructD arg0, StructD arg1, int32 arg2);
+		[LinkName(.C)]
+		public static extern int32 Func1E(StructE arg0, StructE arg1, int32 arg2);
+		[LinkName(.C)]
+		public static extern int32 Func1F(StructF arg0, StructF arg1, int32 arg2);
+		[LinkName(.C)]
+		public static extern int32 Func1G(StructG arg0, StructG arg1, int32 arg2);
+		[LinkName(.C)]
+		public static extern int32 Func1H(StructH arg0, StructH arg1, int32 arg2);
+		[LinkName(.C)]
+		public static extern int32 Func1I(StructI arg0, StructI arg1, int32 arg2);
+
+		[LinkName(.C)]
+		public static extern StructA Func2A(StructA arg0, int32 arg2);
+		[LinkName(.C)]
+		public static extern StructB Func2B(StructB arg0, int32 arg2);
+		[LinkName(.C)]
+		public static extern StructC Func2C(StructC arg0, int32 arg2);
+		[LinkName(.C)]
+		public static extern StructD Func2D(StructD arg0, int32 arg2);
+		[LinkName(.C)]
+		public static extern StructE Func2E(StructE arg0, int32 arg2);
+		[LinkName(.C)]
+		public static extern StructF Func2F(StructF arg0, int32 arg2);
+		[LinkName(.C)]
+		public static extern StructG Func2G(StructG arg0, int32 arg2);
+		[LinkName(.C)]
+		public static extern StructH Func2H(StructH arg0, int32 arg2);
+		[LinkName(.C)]
+		public static extern StructI Func2I(StructI arg0, int32 arg2);
+
+		[Test]
+		public static void TestBasics()
+		{
+			//return;
+
+			StructA sa0 = default;
+			sa0.mA = 10;
+			StructA sa1 = default;
+			sa1.mA = 11;
+
+			StructB sb0 = default;
+			sb0.mA = 20;
+			StructB sb1 = default;
+			sb1.mA = 21;
+
+			StructC sc0 = default;
+			sc0.mA = 30;
+			StructC sc1 = default;
+			sc1.mA = 31;
+
+			StructD sd0 = default;
+			sd0.mA = 40;
+			StructD sd1 = default;
+			sd1.mA = 41;
+
+			StructE se0 = default;
+			se0.mA = 50;
+			StructE se1 = default;
+			se1.mA = 51;
+
+			StructF sf0 = default;
+			sf0.mA = 60;
+			StructF sf1 = default;
+			sf1.mA = 61;
+
+			StructG sg0 = default;
+			sg0.mA = 70;
+			StructG sg1 = default;
+			sg1.mA = 71;
+
+			StructH sh0 = default;
+			sh0.mA = 80;
+			StructH sh1 = default;
+			sh1.mA = 81;
+
+			StructI si0 = default;
+			si0.mA = 90;
+			StructI si1 = default;
+			si1.mA = 91;
+
+			Test.Assert(Func0(12, 34) == 3412);
+
+			Test.Assert(Func1A(sa0, sa1, 12) == 121110);
+			Test.Assert(sa0.MethodA0(12) == 1012);
+			Test.Assert(sa0.MethodA1(sa1, 12).mA == 33);
+			Test.Assert(Func2A(sa0, 12).mA == 22);
+
+			Test.Assert(Func1B(sb0, sb1, 12) == 122120);
+			Test.Assert(sb0.MethodB0(12) == 2012);
+			Test.Assert(sb0.MethodB1(sb1, 12).mA == 53);
+			Test.Assert(Func2B(sb0, 12).mA == 32);
+
+			Test.Assert(Func1C(sc0, sc1, 12) == 123130);
+			Test.Assert(sc0.MethodC0(12) == 3012);
+			Test.Assert(sc0.MethodC1(sc1, 12).mA == 73);
+			Test.Assert(Func2C(sc0, 12).mA == 42);
+
+			Test.Assert(Func1D(sd0, sd1, 12) == 124140);
+			Test.Assert(sd0.MethodD0(12) == 4012);
+			Test.Assert(sd0.MethodD1(sd1, 12).mA == 93);
+			Test.Assert(Func2D(sd0, 12).mA == 52);
+
+			Test.Assert(Func1E(se0, se1, 12) == 125150);
+			Test.Assert(se0.MethodE0(12) == 5012);
+			Test.Assert(se0.MethodE1(se1, 12).mA == 113);
+			Test.Assert(Func2E(se0, 12).mA == 62);
+
+			Test.Assert(Func1F(sf0, sf1, 12) == 126160);
+			Test.Assert(sf0.MethodF0(12) == 6012);
+			Test.Assert(sf0.MethodF1(sf1, 12).mA == (int8)133);
+			Test.Assert(Func2F(sf0, 12).mA == 72);
+
+			Test.Assert(Func1G(sg0, sg1, 12) == 127170);
+			Test.Assert(sg0.MethodG0(12) == 7012);
+			Test.Assert(sg0.MethodG1(sg1, 12).mA == (int8)153);
+			Test.Assert(Func2G(sg0, 12).mA == 82);
+
+			Test.Assert(Func1H(sh0, sh1, 12) == 128180);
+			Test.Assert(sh0.MethodH0(12) == 8012);
+			Test.Assert(sh0.MethodH1(sh1, 12).mA == 173);
+			Test.Assert(Func2H(sh0, 12).mA == 92);
+
+			Test.Assert(Func1I(si0, si1, 12) == 129190);
+			Test.Assert(si0.MethodI0(12) == 9012);
+			Test.Assert(si0.MethodI1(si1, 12).mA == (int8)193);
+			Test.Assert(Func2I(si0, 12).mA == 102);
+		}
+	}
+}

+ 4 - 0
bin/test_build.bat

@@ -9,11 +9,15 @@ md stats
 
 @REM GOTO RANDO
 
+
 @ECHO Testing IDEHelper\Tests
+CALL bin/msbuild.bat IDEHelper\Tests\CLib\CLib.vcxproj /p:Configuration=Debug /p:Platform=x64 /p:SolutionDir=%cd%\ /v:m
+@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR
 IDE\dist\BeefBuild_d -proddir=IDEHelper\Tests -test
 @IF %ERRORLEVEL% NEQ 0 GOTO HADERROR
 
 @ECHO Testing IDEHelper\Tests (Win32)
+CALL bin/msbuild.bat IDEHelper\Tests\CLib\CLib.vcxproj /p:Configuration=Debug /p:Platform=x86 /p:SolutionDir=%cd%\ /v:m
 IDE\dist\BeefBuild_d -proddir=IDEHelper\Tests -test -platform=Win32
 @IF %ERRORLEVEL% NEQ 0 GOTO HADERROR
 

+ 7 - 6
extern/llvm_build.sh

@@ -3,13 +3,14 @@ set -e
 
 if [ ! -d llvm-project_8_0_0 ]; then
 	git clone https://github.com/llvm/llvm-project.git llvm-project_8_0_0
-fi
 
-if [ -d llvm-project_8_0_0 ]; then
-	cd llvm-project_8_0_0
- 	git checkout llvmorg-8.0.0
-	cd ..
-fi 
+	if [ -d llvm-project_8_0_0 ]; then
+		cd llvm-project_8_0_0
+ 		git checkout llvmorg-8.0.0
+		cd ..
+	fi 
+
+fi
 
 if [ ! -d llvm_linux_8_0_0 ]; then
 	mkdir llvm_linux_8_0_0