mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-09 03:52:19 +02:00
Added VarArgs
This commit is contained in:
parent
fd1d9644f7
commit
9ccdf7282e
8 changed files with 228 additions and 26 deletions
|
@ -21,6 +21,38 @@ namespace System
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct VarArgs
|
||||||
|
{
|
||||||
|
void* mVAList;
|
||||||
|
|
||||||
|
[Intrinsic("va_start")]
|
||||||
|
static extern void Start(void* vaList);
|
||||||
|
[Intrinsic("va_end")]
|
||||||
|
static extern void End(void* vaList);
|
||||||
|
[Intrinsic("va_arg")]
|
||||||
|
static extern void Arg(void* vaList, void* destPtr, int32 typeId);
|
||||||
|
|
||||||
|
[Inline]
|
||||||
|
public mixin Start() mut
|
||||||
|
{
|
||||||
|
Start(&mVAList);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Inline]
|
||||||
|
public mixin End() mut
|
||||||
|
{
|
||||||
|
End(&mVAList);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Inline]
|
||||||
|
public mixin Get<T>() mut
|
||||||
|
{
|
||||||
|
T val = ?;
|
||||||
|
Arg(&mVAList, &val, (.)typeof(T).TypeId);
|
||||||
|
val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[AlwaysInclude]
|
[AlwaysInclude]
|
||||||
static class Internal
|
static class Internal
|
||||||
{
|
{
|
||||||
|
|
|
@ -1932,6 +1932,7 @@ BeMCContext::BeMCContext(BeCOFFObject* coffObject) : mOut(coffObject->mTextSect.
|
||||||
mCurVRegsInit = NULL;
|
mCurVRegsInit = NULL;
|
||||||
mCurVRegsLive = NULL;
|
mCurVRegsLive = NULL;
|
||||||
mUseBP = false;
|
mUseBP = false;
|
||||||
|
mHasVAStart = false;
|
||||||
mInsertInstIdxRef = NULL;
|
mInsertInstIdxRef = NULL;
|
||||||
mNativeIntType = mCOFFObject->mBeModule->mContext->GetPrimitiveType(BeTypeCode_Int64);
|
mNativeIntType = mCOFFObject->mBeModule->mContext->GetPrimitiveType(BeTypeCode_Int64);
|
||||||
mDebugging = false;
|
mDebugging = false;
|
||||||
|
@ -8519,6 +8520,36 @@ void BeMCContext::DoFrameObjPass()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mHasVAStart)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
auto regSaveVReg = AllocVirtualReg(mModule->mContext->GetPointerTo(mModule->mContext->GetPrimitiveType(BeTypeCode_Int64)));
|
||||||
|
auto vregInfo = GetVRegInfo(regSaveVReg);
|
||||||
|
vregInfo->mRelTo = BeMCOperand::FromReg(X64Reg_RSP);
|
||||||
|
vregInfo->mRelOffset = BeMCOperand::FromImmediate(i * 8 + 8);
|
||||||
|
vregInfo->mIsExpr = true;
|
||||||
|
|
||||||
|
X64CPURegister reg;
|
||||||
|
switch (i)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
reg = X64Reg_RCX;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
reg = X64Reg_RDX;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
reg = X64Reg_R8;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
reg = X64Reg_R9;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
AllocInst(BeMCInstKind_Mov, BeMCOperand::ToLoad(regSaveVReg), BeMCOperand::FromReg(reg), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BeMCOperand restoreBPVal;
|
BeMCOperand restoreBPVal;
|
||||||
if (mUseBP)
|
if (mUseBP)
|
||||||
{
|
{
|
||||||
|
@ -15801,7 +15832,7 @@ void BeMCContext::Generate(BeFunction* function)
|
||||||
mDbgPreferredRegs[32] = X64Reg_R8;*/
|
mDbgPreferredRegs[32] = X64Reg_R8;*/
|
||||||
|
|
||||||
//mDbgPreferredRegs[8] = X64Reg_RAX;
|
//mDbgPreferredRegs[8] = X64Reg_RAX;
|
||||||
//mDebugging = (function->mName == "?ConvertType@TestC@BeefTest@bf@@SAPEAVType@System@3@PEAVString@53@@Z");
|
//mDebugging = (function->mName == "?Zoips@TestProgram@BeefTest@bf@@SAXXZ");
|
||||||
// || (function->mName == "?MethodA@TestProgram@BeefTest@bf@@CAXXZ");
|
// || (function->mName == "?MethodA@TestProgram@BeefTest@bf@@CAXXZ");
|
||||||
// || (function->mName == "?Hey@Blurg@bf@@SAXXZ")
|
// || (function->mName == "?Hey@Blurg@bf@@SAXXZ")
|
||||||
// ;
|
// ;
|
||||||
|
@ -15871,23 +15902,18 @@ void BeMCContext::Generate(BeFunction* function)
|
||||||
break;
|
break;
|
||||||
case BeCallInst::TypeId:
|
case BeCallInst::TypeId:
|
||||||
{
|
{
|
||||||
// auto castedInst = (BeCallInst*)inst;
|
auto castedInst = (BeCallInst*)inst;
|
||||||
//
|
|
||||||
// if (auto intrin = BeValueDynCast<BeIntrinsic>(castedInst->mFunc))
|
if (auto intrin = BeValueDynCast<BeIntrinsic>(castedInst->mFunc))
|
||||||
// {
|
{
|
||||||
// // Not a real call
|
// Not a real call
|
||||||
// switch (intrin->mKind)
|
switch (intrin->mKind)
|
||||||
// {
|
{
|
||||||
// case BfIRIntrinsic_Malloc:
|
case BfIRIntrinsic_VAStart:
|
||||||
// case BfIRIntrinsic_MemCpy:
|
mHasVAStart = true;
|
||||||
// case BfIRIntrinsic_MemMove:
|
break;
|
||||||
// case BfIRIntrinsic_MemSet:
|
}
|
||||||
// mMaxCallParamCount = BF_MAX(mMaxCallParamCount, 4);
|
}
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// mMaxCallParamCount = BF_MAX(mMaxCallParamCount, (int)castedInst->mArgs.size());
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BeMemSetInst::TypeId:
|
case BeMemSetInst::TypeId:
|
||||||
|
@ -17495,6 +17521,60 @@ void BeMCContext::Generate(BeFunction* function)
|
||||||
useAltArgs = true;
|
useAltArgs = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case BfIRIntrinsic_VAArg:
|
||||||
|
{
|
||||||
|
auto mcListPtr = GetOperand(castedInst->mArgs[0].mValue);
|
||||||
|
auto mcDestVoidPtr = GetOperand(castedInst->mArgs[1].mValue);
|
||||||
|
auto mcType = GetOperand(castedInst->mArgs[2].mValue);
|
||||||
|
|
||||||
|
BeType* beType = mModule->mBeIRCodeGen->GetBeTypeById((int32)mcType.mImmediate);
|
||||||
|
|
||||||
|
auto mcList = AllocVirtualReg(mModule->mContext->GetPointerTo(mModule->mContext->GetPrimitiveType(BeTypeCode_NullPtr)));
|
||||||
|
CreateDefineVReg(mcList);
|
||||||
|
auto listVRegInfo = GetVRegInfo(mcList);
|
||||||
|
listVRegInfo->mRelTo = mcListPtr;
|
||||||
|
listVRegInfo->mIsExpr = true;
|
||||||
|
|
||||||
|
auto mcSrc = AllocVirtualReg(mModule->mContext->GetPointerTo(beType));
|
||||||
|
CreateDefineVReg(mcSrc);
|
||||||
|
auto srcVRegInfo = GetVRegInfo(mcSrc);
|
||||||
|
srcVRegInfo->mRelTo = BeMCOperand::ToLoad(mcList);
|
||||||
|
srcVRegInfo->mIsExpr = true;
|
||||||
|
|
||||||
|
auto mcDest = AllocVirtualReg(mModule->mContext->GetPointerTo(beType));
|
||||||
|
CreateDefineVReg(mcDest);
|
||||||
|
auto destVRegInfo = GetVRegInfo(mcDest);
|
||||||
|
destVRegInfo->mRelTo = mcDestVoidPtr;
|
||||||
|
destVRegInfo->mIsExpr = true;
|
||||||
|
|
||||||
|
AllocInst(BeMCInstKind_Mov, BeMCOperand::ToLoad(mcDest), BeMCOperand::ToLoad(mcSrc));
|
||||||
|
AllocInst(BeMCInstKind_Add, BeMCOperand::ToLoad(mcList), BeMCOperand::FromImmediate(8));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BfIRIntrinsic_VAEnd:
|
||||||
|
break;
|
||||||
|
case BfIRIntrinsic_VAStart:
|
||||||
|
{
|
||||||
|
auto mcTarget = GetOperand(castedInst->mArgs[0].mValue);
|
||||||
|
|
||||||
|
auto destVal = AllocVirtualReg(mModule->mContext->GetPointerTo(mModule->mContext->GetPrimitiveType(BeTypeCode_NullPtr)));
|
||||||
|
auto destVRegInfo = GetVRegInfo(destVal);
|
||||||
|
destVRegInfo->mRelTo = mcTarget;
|
||||||
|
destVRegInfo->mIsExpr = true;
|
||||||
|
CreateDefineVReg(destVal);
|
||||||
|
|
||||||
|
auto nullPtrType = mModule->mContext->GetPrimitiveType(BeTypeCode_NullPtr);
|
||||||
|
auto vaStartVal = AllocVirtualReg(nullPtrType);
|
||||||
|
auto vRegInfo = GetVRegInfo(vaStartVal);
|
||||||
|
vRegInfo->mMustExist = true;
|
||||||
|
vRegInfo->mForceMem = true;
|
||||||
|
vRegInfo->mFrameOffset = (int)mBeFunction->mParams.size() * 8 + 8;
|
||||||
|
vRegInfo->mRefCount++;
|
||||||
|
CreateDefineVReg(vaStartVal);
|
||||||
|
|
||||||
|
AllocInst(BeMCInstKind_Mov, BeMCOperand::ToLoad(destVal), BeMCOperand::FromVRegAddr(vaStartVal.mVRegIdx));
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
SoftFail(StrFormat("Intrinsic not handled: '%s'", intrin->mName.c_str()), castedInst->mDbgLoc);
|
SoftFail(StrFormat("Intrinsic not handled: '%s'", intrin->mName.c_str()), castedInst->mDbgLoc);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1330,6 +1330,7 @@ public:
|
||||||
|
|
||||||
int mStackSize;
|
int mStackSize;
|
||||||
bool mUseBP;
|
bool mUseBP;
|
||||||
|
bool mHasVAStart;
|
||||||
int mCurLabelIdx;
|
int mCurLabelIdx;
|
||||||
int mCurPhiIdx;
|
int mCurPhiIdx;
|
||||||
int mMaxCallParamCount; // -1 if we have no calls
|
int mMaxCallParamCount; // -1 if we have no calls
|
||||||
|
|
|
@ -770,8 +770,11 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp
|
||||||
anyIsExtension = true;
|
anyIsExtension = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hadEnoughArgs = newMethodInstance->GetParamCount() - newImplicitParamCount < (int)mArguments.size();
|
int newMethodParamCount = newMethodInstance->GetParamCount();
|
||||||
bool prevHadEnoughArgs = prevMethodInstance->GetParamCount() - prevImplicitParamCount < (int)mArguments.size();
|
int prevMethodParamCount = prevMethodInstance->GetParamCount();
|
||||||
|
|
||||||
|
bool hadEnoughArgs = newMethodParamCount - newImplicitParamCount < (int)mArguments.size();
|
||||||
|
bool prevHadEnoughArgs = prevMethodParamCount - prevImplicitParamCount < (int)mArguments.size();
|
||||||
RETURN_BETTER_OR_WORSE(hadEnoughArgs, prevHadEnoughArgs);
|
RETURN_BETTER_OR_WORSE(hadEnoughArgs, prevHadEnoughArgs);
|
||||||
|
|
||||||
bool chainSkip = (newMethodInstance->mChainType == BfMethodChainType_ChainMember) || (newMethodInstance->mChainType == BfMethodChainType_ChainSkip);
|
bool chainSkip = (newMethodInstance->mChainType == BfMethodChainType_ChainMember) || (newMethodInstance->mChainType == BfMethodChainType_ChainSkip);
|
||||||
|
@ -808,6 +811,11 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp
|
||||||
int newArgIdx = argIdx + newImplicitParamCount;
|
int newArgIdx = argIdx + newImplicitParamCount;
|
||||||
int prevArgIdx = argIdx + prevImplicitParamCount;
|
int prevArgIdx = argIdx + prevImplicitParamCount;
|
||||||
|
|
||||||
|
if (newArgIdx >= newMethodParamCount)
|
||||||
|
break;
|
||||||
|
if (prevArgIdx >= prevMethodParamCount)
|
||||||
|
break;
|
||||||
|
|
||||||
bool wasGenericParam = (newArgIdx >= 0) && newMethodInstance->WasGenericParam(newArgIdx);
|
bool wasGenericParam = (newArgIdx >= 0) && newMethodInstance->WasGenericParam(newArgIdx);
|
||||||
bool prevWasGenericParam = (prevArgIdx >= 0) && prevMethodInstance->WasGenericParam(prevArgIdx);
|
bool prevWasGenericParam = (prevArgIdx >= 0) && prevMethodInstance->WasGenericParam(prevArgIdx);
|
||||||
|
|
||||||
|
|
|
@ -457,6 +457,9 @@ enum BfIRIntrinsic : uint8
|
||||||
BfIRIntrinsic_Sin,
|
BfIRIntrinsic_Sin,
|
||||||
BfIRIntrinsic_Sqrt,
|
BfIRIntrinsic_Sqrt,
|
||||||
BfIRIntrinsic_Sub,
|
BfIRIntrinsic_Sub,
|
||||||
|
BfIRIntrinsic_VAArg,
|
||||||
|
BfIRIntrinsic_VAEnd,
|
||||||
|
BfIRIntrinsic_VAStart,
|
||||||
BfIRIntrinsic_Xor,
|
BfIRIntrinsic_Xor,
|
||||||
|
|
||||||
BfIRIntrinsic_COUNT,
|
BfIRIntrinsic_COUNT,
|
||||||
|
|
|
@ -189,6 +189,9 @@ static const BuiltinEntry gIntrinEntries[] =
|
||||||
{"sin"},
|
{"sin"},
|
||||||
{"sqrt"},
|
{"sqrt"},
|
||||||
{"sub"},
|
{"sub"},
|
||||||
|
{"va_arg"},
|
||||||
|
{"va_end"},
|
||||||
|
{"va_start"},
|
||||||
{"xor"},
|
{"xor"},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2631,6 +2634,9 @@ void BfIRCodeGen::HandleNextCmd()
|
||||||
{ llvm::Intrinsic::sin, 0, -1},
|
{ llvm::Intrinsic::sin, 0, -1},
|
||||||
{ llvm::Intrinsic::sqrt, 0, -1},
|
{ llvm::Intrinsic::sqrt, 0, -1},
|
||||||
{ (llvm::Intrinsic::ID)-2, -1}, // sub,
|
{ (llvm::Intrinsic::ID)-2, -1}, // sub,
|
||||||
|
{ (llvm::Intrinsic::ID)-2, -1}, // va_arg,
|
||||||
|
{ llvm::Intrinsic::vaend, -1}, // va_end,
|
||||||
|
{ llvm::Intrinsic::vastart, -1}, // va_start,
|
||||||
{ (llvm::Intrinsic::ID)-2, -1}, // xor
|
{ (llvm::Intrinsic::ID)-2, -1}, // xor
|
||||||
};
|
};
|
||||||
BF_STATIC_ASSERT(BF_ARRAY_COUNT(intrinsics) == BfIRIntrinsic_COUNT);
|
BF_STATIC_ASSERT(BF_ARRAY_COUNT(intrinsics) == BfIRIntrinsic_COUNT);
|
||||||
|
@ -3451,6 +3457,16 @@ void BfIRCodeGen::HandleNextCmd()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case BfIRIntrinsic_VAArg:
|
||||||
|
{
|
||||||
|
auto constInt = llvm::dyn_cast<llvm::ConstantInt>(args[2]);
|
||||||
|
auto argType = GetLLVMTypeById((int)constInt->getSExtValue());
|
||||||
|
auto vaArgVal = mIRBuilder->CreateVAArg(args[0], argType);
|
||||||
|
|
||||||
|
auto resultPtr = mIRBuilder->CreateBitCast(args[1], argType->getPointerTo());
|
||||||
|
mIRBuilder->CreateStore(vaArgVal, resultPtr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
FatalError("Unhandled intrinsic");
|
FatalError("Unhandled intrinsic");
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ Unlocked = ["corlib"]
|
||||||
StartupProject = "Tests"
|
StartupProject = "Tests"
|
||||||
|
|
||||||
[Configs.Debug.Win64]
|
[Configs.Debug.Win64]
|
||||||
BfOptimizationLevel = "O0"
|
|
||||||
IntermediateType = "ObjectAndIRCode"
|
IntermediateType = "ObjectAndIRCode"
|
||||||
|
|
||||||
[Configs.Test.Win64]
|
[Configs.Test.Win64]
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
|
#pragma warning disable 168
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Tests
|
namespace Tests
|
||||||
{
|
{
|
||||||
class VarArgs
|
class VarArgsTests
|
||||||
{
|
{
|
||||||
#if BF_PLATFORM_WINDOWS
|
#if BF_PLATFORM_WINDOWS
|
||||||
[CLink, Import("msvcrt.dll")]
|
[CLink, Import("msvcrt.dll")]
|
||||||
|
@ -11,14 +13,75 @@ namespace Tests
|
||||||
#endif
|
#endif
|
||||||
public static extern int32 sprintf(char8* dest, char8* fmt, ...);
|
public static extern int32 sprintf(char8* dest, char8* fmt, ...);
|
||||||
|
|
||||||
|
#if BF_PLATFORM_WINDOWS
|
||||||
|
[CLink, Import("msvcrt.dll")]
|
||||||
|
#else
|
||||||
|
[CLink]
|
||||||
|
#endif
|
||||||
|
public static extern int32 vsprintf(char8* dest, char8* fmt, VarArgs varArgs);
|
||||||
|
|
||||||
|
public static (int, int, int) MethodA(...)
|
||||||
|
{
|
||||||
|
VarArgs vaArgs = .();
|
||||||
|
vaArgs.Start!();
|
||||||
|
int val = vaArgs.Get!<int>();
|
||||||
|
int val2 = vaArgs.Get!<int>();
|
||||||
|
int val3 = (int)vaArgs.Get!<double>();
|
||||||
|
vaArgs.End!();
|
||||||
|
|
||||||
|
return (val, val2, val3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static (int, int, int) MethodB(int a, ...)
|
||||||
|
{
|
||||||
|
VarArgs vaArgs = .();
|
||||||
|
vaArgs.Start!();
|
||||||
|
int val = vaArgs.Get!<int>();
|
||||||
|
int val2 = vaArgs.Get!<int>();
|
||||||
|
int val3 = (int)vaArgs.Get!<double>();
|
||||||
|
vaArgs.End!();
|
||||||
|
|
||||||
|
return (val, val2, val3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static (int, int, int) MethodC(int a, ...)
|
||||||
|
{
|
||||||
|
uint8* data = scope uint8[a]*;
|
||||||
|
|
||||||
|
VarArgs vaArgs = .();
|
||||||
|
vaArgs.Start!();
|
||||||
|
int val = vaArgs.Get!<int>();
|
||||||
|
int val2 = vaArgs.Get!<int>();
|
||||||
|
int val3 = (int)vaArgs.Get!<double>();
|
||||||
|
vaArgs.End!();
|
||||||
|
|
||||||
|
return (val, val2, val3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int32 SPrintF(char8* dest, char8* fmt, ...)
|
||||||
|
{
|
||||||
|
VarArgs vaArgs = .();
|
||||||
|
vaArgs.Start!();
|
||||||
|
int32 result = vsprintf(dest, fmt, vaArgs);
|
||||||
|
vaArgs.End!();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public static void TestBasics()
|
public static void TestBasics()
|
||||||
{
|
{
|
||||||
char8[256] cStr;
|
char8[256] cStr;
|
||||||
sprintf(&cStr, "Test %d %0.1f %0.1f", 123, 1.2f, 2.3f);
|
sprintf(&cStr, "Test %d %0.1f %0.1f", 123, 1.2f, 2.3f);
|
||||||
|
|
||||||
String str = scope .(&cStr);
|
String str = scope .(&cStr);
|
||||||
Test.Assert(str == "Test 123 1.2 2.3");
|
Test.Assert(str == "Test 123 1.2 2.3");
|
||||||
|
|
||||||
|
SPrintF(&cStr, "Test %d %0.1f %0.1f", 223, 2.2f, 3.3f);
|
||||||
|
str.Set(StringView(&cStr));
|
||||||
|
Test.Assert(str == "Test 223 2.2 3.3");
|
||||||
|
|
||||||
|
Test.Assert(MethodA( 12, 23, 123.0f) == (12, 23, 123));
|
||||||
|
Test.Assert(MethodB( 9, 22, 33, 223.0f) == (22, 33, 223));
|
||||||
|
Test.Assert(MethodC(11, 32, 43, 323.0f) == (32, 43, 323));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue