1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 19:48:20 +02:00

Added VarArgs

This commit is contained in:
Brian Fiete 2021-01-22 04:58:08 -08:00
parent fd1d9644f7
commit 9ccdf7282e
8 changed files with 228 additions and 26 deletions

View file

@ -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
{

View file

@ -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;

View file

@ -1330,6 +1330,7 @@ public:
int mStackSize;
bool mUseBP;
bool mHasVAStart;
int mCurLabelIdx;
int mCurPhiIdx;
int mMaxCallParamCount; // -1 if we have no calls

View file

@ -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);

View file

@ -457,6 +457,9 @@ enum BfIRIntrinsic : uint8
BfIRIntrinsic_Sin,
BfIRIntrinsic_Sqrt,
BfIRIntrinsic_Sub,
BfIRIntrinsic_VAArg,
BfIRIntrinsic_VAEnd,
BfIRIntrinsic_VAStart,
BfIRIntrinsic_Xor,
BfIRIntrinsic_COUNT,

View file

@ -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");
}

View file

@ -6,7 +6,6 @@ Unlocked = ["corlib"]
StartupProject = "Tests"
[Configs.Debug.Win64]
BfOptimizationLevel = "O0"
IntermediateType = "ObjectAndIRCode"
[Configs.Test.Win64]

View file

@ -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));
}
}
}