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]
|
||||
static class Internal
|
||||
{
|
||||
|
|
|
@ -1932,6 +1932,7 @@ BeMCContext::BeMCContext(BeCOFFObject* coffObject) : mOut(coffObject->mTextSect.
|
|||
mCurVRegsInit = NULL;
|
||||
mCurVRegsLive = NULL;
|
||||
mUseBP = false;
|
||||
mHasVAStart = false;
|
||||
mInsertInstIdxRef = NULL;
|
||||
mNativeIntType = mCOFFObject->mBeModule->mContext->GetPrimitiveType(BeTypeCode_Int64);
|
||||
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;
|
||||
if (mUseBP)
|
||||
{
|
||||
|
@ -15801,7 +15832,7 @@ void BeMCContext::Generate(BeFunction* function)
|
|||
mDbgPreferredRegs[32] = X64Reg_R8;*/
|
||||
|
||||
//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 == "?Hey@Blurg@bf@@SAXXZ")
|
||||
// ;
|
||||
|
@ -15871,23 +15902,18 @@ void BeMCContext::Generate(BeFunction* function)
|
|||
break;
|
||||
case BeCallInst::TypeId:
|
||||
{
|
||||
// auto castedInst = (BeCallInst*)inst;
|
||||
//
|
||||
// if (auto intrin = BeValueDynCast<BeIntrinsic>(castedInst->mFunc))
|
||||
// {
|
||||
// // Not a real call
|
||||
// switch (intrin->mKind)
|
||||
// {
|
||||
// case BfIRIntrinsic_Malloc:
|
||||
// case BfIRIntrinsic_MemCpy:
|
||||
// case BfIRIntrinsic_MemMove:
|
||||
// case BfIRIntrinsic_MemSet:
|
||||
// mMaxCallParamCount = BF_MAX(mMaxCallParamCount, 4);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// mMaxCallParamCount = BF_MAX(mMaxCallParamCount, (int)castedInst->mArgs.size());
|
||||
auto castedInst = (BeCallInst*)inst;
|
||||
|
||||
if (auto intrin = BeValueDynCast<BeIntrinsic>(castedInst->mFunc))
|
||||
{
|
||||
// Not a real call
|
||||
switch (intrin->mKind)
|
||||
{
|
||||
case BfIRIntrinsic_VAStart:
|
||||
mHasVAStart = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BeMemSetInst::TypeId:
|
||||
|
@ -17495,6 +17521,60 @@ void BeMCContext::Generate(BeFunction* function)
|
|||
useAltArgs = true;
|
||||
}
|
||||
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:
|
||||
SoftFail(StrFormat("Intrinsic not handled: '%s'", intrin->mName.c_str()), castedInst->mDbgLoc);
|
||||
break;
|
||||
|
|
|
@ -1330,6 +1330,7 @@ public:
|
|||
|
||||
int mStackSize;
|
||||
bool mUseBP;
|
||||
bool mHasVAStart;
|
||||
int mCurLabelIdx;
|
||||
int mCurPhiIdx;
|
||||
int mMaxCallParamCount; // -1 if we have no calls
|
||||
|
|
|
@ -770,8 +770,11 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp
|
|||
anyIsExtension = true;
|
||||
}
|
||||
|
||||
bool hadEnoughArgs = newMethodInstance->GetParamCount() - newImplicitParamCount < (int)mArguments.size();
|
||||
bool prevHadEnoughArgs = prevMethodInstance->GetParamCount() - prevImplicitParamCount < (int)mArguments.size();
|
||||
int newMethodParamCount = newMethodInstance->GetParamCount();
|
||||
int prevMethodParamCount = prevMethodInstance->GetParamCount();
|
||||
|
||||
bool hadEnoughArgs = newMethodParamCount - newImplicitParamCount < (int)mArguments.size();
|
||||
bool prevHadEnoughArgs = prevMethodParamCount - prevImplicitParamCount < (int)mArguments.size();
|
||||
RETURN_BETTER_OR_WORSE(hadEnoughArgs, prevHadEnoughArgs);
|
||||
|
||||
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 prevArgIdx = argIdx + prevImplicitParamCount;
|
||||
|
||||
if (newArgIdx >= newMethodParamCount)
|
||||
break;
|
||||
if (prevArgIdx >= prevMethodParamCount)
|
||||
break;
|
||||
|
||||
bool wasGenericParam = (newArgIdx >= 0) && newMethodInstance->WasGenericParam(newArgIdx);
|
||||
bool prevWasGenericParam = (prevArgIdx >= 0) && prevMethodInstance->WasGenericParam(prevArgIdx);
|
||||
|
||||
|
|
|
@ -457,6 +457,9 @@ enum BfIRIntrinsic : uint8
|
|||
BfIRIntrinsic_Sin,
|
||||
BfIRIntrinsic_Sqrt,
|
||||
BfIRIntrinsic_Sub,
|
||||
BfIRIntrinsic_VAArg,
|
||||
BfIRIntrinsic_VAEnd,
|
||||
BfIRIntrinsic_VAStart,
|
||||
BfIRIntrinsic_Xor,
|
||||
|
||||
BfIRIntrinsic_COUNT,
|
||||
|
|
|
@ -189,6 +189,9 @@ static const BuiltinEntry gIntrinEntries[] =
|
|||
{"sin"},
|
||||
{"sqrt"},
|
||||
{"sub"},
|
||||
{"va_arg"},
|
||||
{"va_end"},
|
||||
{"va_start"},
|
||||
{"xor"},
|
||||
};
|
||||
|
||||
|
@ -2631,6 +2634,9 @@ void BfIRCodeGen::HandleNextCmd()
|
|||
{ llvm::Intrinsic::sin, 0, -1},
|
||||
{ llvm::Intrinsic::sqrt, 0, -1},
|
||||
{ (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
|
||||
};
|
||||
BF_STATIC_ASSERT(BF_ARRAY_COUNT(intrinsics) == BfIRIntrinsic_COUNT);
|
||||
|
@ -3451,6 +3457,16 @@ void BfIRCodeGen::HandleNextCmd()
|
|||
}
|
||||
}
|
||||
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:
|
||||
FatalError("Unhandled intrinsic");
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ Unlocked = ["corlib"]
|
|||
StartupProject = "Tests"
|
||||
|
||||
[Configs.Debug.Win64]
|
||||
BfOptimizationLevel = "O0"
|
||||
IntermediateType = "ObjectAndIRCode"
|
||||
|
||||
[Configs.Test.Win64]
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#pragma warning disable 168
|
||||
|
||||
using System;
|
||||
|
||||
namespace Tests
|
||||
{
|
||||
class VarArgs
|
||||
class VarArgsTests
|
||||
{
|
||||
#if BF_PLATFORM_WINDOWS
|
||||
[CLink, Import("msvcrt.dll")]
|
||||
|
@ -11,14 +13,75 @@ namespace Tests
|
|||
#endif
|
||||
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]
|
||||
public static void TestBasics()
|
||||
{
|
||||
char8[256] cStr;
|
||||
sprintf(&cStr, "Test %d %0.1f %0.1f", 123, 1.2f, 2.3f);
|
||||
|
||||
String str = scope .(&cStr);
|
||||
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