1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-14 14:24:10 +02:00

Merge pull request #1882 from hermansimensen/master

Add intrinsic for emscripten assembly/javascript.
This commit is contained in:
Brian Fiete 2023-08-09 07:29:47 -07:00 committed by GitHub
commit 7bc7ccbbc4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 186 additions and 3 deletions

View file

@ -0,0 +1,134 @@
#if BF_PLATFORM_WASM
namespace System;
using System.Interop;
class WebAssembly
{
[CLink]
private static extern int32 emscripten_asm_const_int(char8* code, char8* arg_sigs, ...);
[CLink]
private static extern void emscripten_asm_const_ptr(char8* code, char8* arg_sigs, ...);
[CLink]
private static extern double emscripten_asm_const_double(char8* code, char8* arg_sigs, ...);
[Intrinsic(":add_string_to_section")]
private static extern char8* add_string_to_section(uint8* string, uint8* section);
private static Span<uint8> GetStringData(String value)
{
return StringView(value).ToRawData();
}
/**
* Returns the string added to the specified data section.
*/
private static char8* AddStringToSection<T0, T1>(T0 value, T1 section) where T0 : const String where T1 : const String
{
static uint8[?] data = GetStringData(value);
static uint8[?] sectionStr = GetStringData(section);
#unwarn
return add_string_to_section(&data, &sectionStr);
}
private static void GetArgSigInternal(Type t, String s)
{
switch(t)
{
case typeof(float):
s.Append('f');
case typeof(double):
s.Append('d');
case typeof(c_ulong): fallthrough;
case typeof(c_ulonglong): fallthrough;
case typeof(c_longlong): fallthrough;
case typeof(c_long):
s.Append('j');
default:
#if BF_32_BIT
s.Append('i');
#else
s.Append('p');
#endif
}
}
[Comptime]
static void JSGetArgSig(Type t, String s)
{
if(t.IsTuple)
{
int count = t.FieldCount;
for(int i = 0; i < count; i++)
{
var type = t.GetField(i).Get().FieldType;
GetArgSigInternal(type, s);
}
}else
GetArgSigInternal(t, s);
}
private static String JSGetResultName(Type t)
{
if(t.IsPointer)
return "ptr";
else if (t.IsFloatingPoint)
return "double";
else
return "int";
}
[Comptime]
private static void GetArgString<T>(String s)
{
Type type = typeof(T);
int fieldCount = 0;
if (type.IsTuple)
{
fieldCount = type.FieldCount;
for(int i = 0; i< fieldCount; i++)
{
if(i == fieldCount-1)
s.AppendF("p0.{}", i);
else
s.AppendF("p0.{}, ", i);
}
}
else
s.Append("p0");
}
private static String JSGetCallString<TResult, TCall, T0>() where TCall : const String
{
if (TCall == null)
return "";
var argSigs = JSGetArgSig(typeof(T0), .. scope .());
var argString = GetArgString<T0>(.. scope .());
return new $"result = emscripten_asm_const_{JSGetResultName(typeof(TResult))}(AddStringToSection({TCall.Quote(.. scope .())}, \"em_asm\"), \"{argSigs}\", {argString});";
}
private static String JSGetCallString<TResult, TCall>() where TCall : const String
{
if (TCall == null)
return "";
return new $"result = emscripten_asm_const_{JSGetResultName(typeof(TResult))}(AddStringToSection({TCall.Quote(.. scope .())}, \"em_asm\"), \"i\");";
}
public static TResult JSCall<TResult, TCall, T0>(TCall callString, T0 p0) where TCall : const String
{
TResult result = default;
Compiler.Mixin(JSGetCallString<TResult, const TCall, T0>());
return result;
}
public static TResult JSCall<TResult, TCall>(TCall callString) where TCall : const String
{
TResult result = default;
Compiler.Mixin(JSGetCallString<TResult, const TCall>());
return result;
}
}
#endif

View file

@ -3075,11 +3075,60 @@ void BfIRCodeGen::HandleNextCmd()
switch (intrinsicData->mIntrinsic) switch (intrinsicData->mIntrinsic)
{ {
case BfIRIntrinsic__PLATFORM: case BfIRIntrinsic__PLATFORM:
{
if (intrinsicData->mName == "add_string_to_section")
{ {
FatalError(StrFormat("Unable to find intrinsic '%s'", intrinsicData->mName.c_str())); llvm::StringRef strContent[2];
} llvm::ConstantDataArray* dataArray;
break;
for (int i = 0; i < 2; i++)
{
if (const llvm::ConstantExpr* ce = llvm::dyn_cast<llvm::ConstantExpr>(args[i]))
{
llvm::Value* firstOperand = ce->getOperand(0);
if (llvm::GlobalVariable* gv = llvm::dyn_cast<llvm::GlobalVariable>(firstOperand))
{
if (gv->getType()->isPointerTy())
{
if (dataArray = llvm::dyn_cast<llvm::ConstantDataArray>(gv->getInitializer()))
strContent[i] = dataArray->getAsString();
}
}
}
else
FatalError("Value is not ConstantExpr");
}
static int symbolCount = 0;
symbolCount++;
auto charType = llvm::IntegerType::get(*mLLVMContext, 8);
std::vector<llvm::Constant*> chars(strContent[0].size());
for (unsigned int i = 0; i < strContent[0].size(); i++)
{
chars[i] = llvm::ConstantInt::get(charType, strContent[0][i]);;
}
chars.push_back(llvm::ConstantInt::get(charType, 0));
auto stringType = llvm::ArrayType::get(charType, chars.size());
std::string symbolName = strContent[1].str() + "_" + std::to_string(symbolCount);
llvm::StringRef resultStringRef(symbolName);
auto globalVar = (llvm::GlobalVariable*)mLLVMModule->getOrInsertGlobal(symbolName, stringType);
globalVar->setSection(strContent[1]);
globalVar->setInitializer(llvm::ConstantArray::get(stringType, chars));
globalVar->setConstant(true);
globalVar->setLinkage(llvm::GlobalValue::LinkageTypes::ExternalLinkage);
globalVar->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
SetResult(curId, llvm::ConstantExpr::getBitCast(globalVar, charType->getPointerTo()));
break;
}
FatalError(StrFormat("Unable to find intrinsic '%s'", intrinsicData->mName.c_str()));
break;
}
case BfIRIntrinsic_Add: case BfIRIntrinsic_Add:
case BfIRIntrinsic_And: case BfIRIntrinsic_And:
case BfIRIntrinsic_Div: case BfIRIntrinsic_Div: