From 6bde23b75e12d3193a32ad182007dfd5d7ac2f6f Mon Sep 17 00:00:00 2001 From: hermansimensen Date: Thu, 3 Aug 2023 13:29:04 +0200 Subject: [PATCH 1/5] Add em_asm intrinsic --- IDEHelper/Compiler/BfIRCodeGen.cpp | 48 ++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/IDEHelper/Compiler/BfIRCodeGen.cpp b/IDEHelper/Compiler/BfIRCodeGen.cpp index 15315440..6a81da38 100644 --- a/IDEHelper/Compiler/BfIRCodeGen.cpp +++ b/IDEHelper/Compiler/BfIRCodeGen.cpp @@ -3075,11 +3075,53 @@ void BfIRCodeGen::HandleNextCmd() switch (intrinsicData->mIntrinsic) { case BfIRIntrinsic__PLATFORM: + { + if (intrinsicData->mName == "em_asm_internal") { - FatalError(StrFormat("Unable to find intrinsic '%s'", intrinsicData->mName.c_str())); - } - break; + llvm::StringRef strContent; + llvm::ConstantDataArray* dataArray; + if (const llvm::ConstantExpr* ce = llvm::dyn_cast(args[0])) + { + llvm::Value* firstOperand = ce->getOperand(0); + if (llvm::GlobalVariable* gv = llvm::dyn_cast(firstOperand)) + { + if (gv->getType()->isPointerTy()) + { + if (dataArray = llvm::dyn_cast(gv->getInitializer())) + { + strContent = dataArray->getAsString(); + } + } + } + } + else + FatalError("Value is not ConstantExpr"); + + auto charType = llvm::IntegerType::get(*mLLVMContext, 8); + std::vector chars(strContent.size()); + for (unsigned int i = 0; i < strContent.size(); i++) + { + chars[i] = llvm::ConstantInt::get(charType, strContent[i]);; + } + + chars.push_back(llvm::ConstantInt::get(charType, 0)); + auto stringType = llvm::ArrayType::get(charType, chars.size()); + + auto globalVar = (llvm::GlobalVariable*)mLLVMModule->getOrInsertGlobal("", stringType); + globalVar->setSection("em_asm"); + 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_And: case BfIRIntrinsic_Div: From eeea06a22bf7b99284ca2854b93a711571d0f3f2 Mon Sep 17 00:00:00 2001 From: hermansimensen Date: Sun, 6 Aug 2023 15:54:14 +0200 Subject: [PATCH 2/5] Add em_asm funtionality --- BeefLibs/corlib/src/WebAssembly.bf | 121 +++++++++++++++++++++++++++++ IDEHelper/Compiler/BfIRCodeGen.cpp | 30 +++---- 2 files changed, 137 insertions(+), 14 deletions(-) create mode 100644 BeefLibs/corlib/src/WebAssembly.bf diff --git a/BeefLibs/corlib/src/WebAssembly.bf b/BeefLibs/corlib/src/WebAssembly.bf new file mode 100644 index 00000000..b0d87a3a --- /dev/null +++ b/BeefLibs/corlib/src/WebAssembly.bf @@ -0,0 +1,121 @@ +#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 GetStringData(String value) + { + return StringView(value).ToRawData(); + } + + /** + * Returns the string added to the specified data section. + */ + private static char8* AddStringToSection(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, §ionStr); + } + + 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): + case typeof(c_longlong): + 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(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() where TCall : const String + { + if (TCall == null) + return ""; + var argSigs = JSGetArgSig(typeof(T0), .. scope .()); + var argString = GetArgString(.. scope .()); + return new $"result = emscripten_asm_const_{JSGetResultName(typeof(TResult))}(AddStringToSection({TCall.Quote(.. scope .())}, \"em_asm\"), \"{argSigs}\", {argString});"; + } + + public static TResult JSCall(TCall callString, T0 p0) where TCall : const String + { + TResult result = default; + Compiler.Mixin(JSGetCallString()); + return result; + } +} + + +#endif diff --git a/IDEHelper/Compiler/BfIRCodeGen.cpp b/IDEHelper/Compiler/BfIRCodeGen.cpp index 6a81da38..d7bb63bb 100644 --- a/IDEHelper/Compiler/BfIRCodeGen.cpp +++ b/IDEHelper/Compiler/BfIRCodeGen.cpp @@ -3076,40 +3076,42 @@ void BfIRCodeGen::HandleNextCmd() { case BfIRIntrinsic__PLATFORM: { - if (intrinsicData->mName == "em_asm_internal") + if (intrinsicData->mName == "add_string_to_section") { - llvm::StringRef strContent; + llvm::StringRef strContent[2]; llvm::ConstantDataArray* dataArray; - if (const llvm::ConstantExpr* ce = llvm::dyn_cast(args[0])) + + for (int i = 0; i < 2; i++) { - llvm::Value* firstOperand = ce->getOperand(0); - if (llvm::GlobalVariable* gv = llvm::dyn_cast(firstOperand)) + if (const llvm::ConstantExpr* ce = llvm::dyn_cast(args[i])) { - if (gv->getType()->isPointerTy()) + llvm::Value* firstOperand = ce->getOperand(0); + if (llvm::GlobalVariable* gv = llvm::dyn_cast(firstOperand)) { - if (dataArray = llvm::dyn_cast(gv->getInitializer())) + if (gv->getType()->isPointerTy()) { - strContent = dataArray->getAsString(); + if (dataArray = llvm::dyn_cast(gv->getInitializer())) + strContent[i] = dataArray->getAsString(); } } } + else + FatalError("Value is not ConstantExpr"); } - else - FatalError("Value is not ConstantExpr"); auto charType = llvm::IntegerType::get(*mLLVMContext, 8); - std::vector chars(strContent.size()); - for (unsigned int i = 0; i < strContent.size(); i++) + std::vector chars(strContent[0].size()); + for (unsigned int i = 0; i < strContent[0].size(); i++) { - chars[i] = llvm::ConstantInt::get(charType, strContent[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()); auto globalVar = (llvm::GlobalVariable*)mLLVMModule->getOrInsertGlobal("", stringType); - globalVar->setSection("em_asm"); + globalVar->setSection(strContent[1]); globalVar->setInitializer(llvm::ConstantArray::get(stringType, chars)); globalVar->setConstant(true); globalVar->setLinkage(llvm::GlobalValue::LinkageTypes::ExternalLinkage); From 09131c1df0759798ac5104dec73c45ea2e8f06ce Mon Sep 17 00:00:00 2001 From: hermansimensen Date: Sun, 6 Aug 2023 20:33:52 +0200 Subject: [PATCH 3/5] add missing fallthroughs --- BeefLibs/corlib/src/WebAssembly.bf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/BeefLibs/corlib/src/WebAssembly.bf b/BeefLibs/corlib/src/WebAssembly.bf index b0d87a3a..70f9d6b0 100644 --- a/BeefLibs/corlib/src/WebAssembly.bf +++ b/BeefLibs/corlib/src/WebAssembly.bf @@ -42,8 +42,8 @@ class WebAssembly case typeof(double): s.Append('d'); case typeof(c_ulong): fallthrough; - case typeof(c_ulonglong): - case typeof(c_longlong): + case typeof(c_ulonglong): fallthrough; + case typeof(c_longlong): fallthrough; case typeof(c_long): s.Append('j'); default: @@ -63,7 +63,7 @@ class WebAssembly int count = t.FieldCount; for(int i = 0; i < count; i++) { - var type = t.GetField(i).Get().FieldType; + var type = t.GetField(i).Get().FieldType; GetArgSigInternal(type, s); } }else From 67e4b845fd89259396da44aa521b959431a634ad Mon Sep 17 00:00:00 2001 From: hermansimensen Date: Sun, 6 Aug 2023 21:58:28 +0200 Subject: [PATCH 4/5] allow zero arguments --- BeefLibs/corlib/src/WebAssembly.bf | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/BeefLibs/corlib/src/WebAssembly.bf b/BeefLibs/corlib/src/WebAssembly.bf index 70f9d6b0..5ae2ee81 100644 --- a/BeefLibs/corlib/src/WebAssembly.bf +++ b/BeefLibs/corlib/src/WebAssembly.bf @@ -109,13 +109,26 @@ class WebAssembly return new $"result = emscripten_asm_const_{JSGetResultName(typeof(TResult))}(AddStringToSection({TCall.Quote(.. scope .())}, \"em_asm\"), \"{argSigs}\", {argString});"; } + private static String JSGetCallString() 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(TCall callString, T0 p0) where TCall : const String { TResult result = default; Compiler.Mixin(JSGetCallString()); return result; } + + public static TResult JSCall(TCall callString) where TCall : const String + { + TResult result = default; + Compiler.Mixin(JSGetCallString()); + return result; + } } - #endif From ac9feaeaf5ba883a065d9b179496237fb08ad531 Mon Sep 17 00:00:00 2001 From: hermansimensen Date: Mon, 7 Aug 2023 16:51:42 +0200 Subject: [PATCH 5/5] avoid symbol name collisions --- IDEHelper/Compiler/BfIRCodeGen.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/IDEHelper/Compiler/BfIRCodeGen.cpp b/IDEHelper/Compiler/BfIRCodeGen.cpp index d7bb63bb..b3960e6f 100644 --- a/IDEHelper/Compiler/BfIRCodeGen.cpp +++ b/IDEHelper/Compiler/BfIRCodeGen.cpp @@ -3099,6 +3099,8 @@ void BfIRCodeGen::HandleNextCmd() FatalError("Value is not ConstantExpr"); } + static int symbolCount = 0; + symbolCount++; auto charType = llvm::IntegerType::get(*mLLVMContext, 8); std::vector chars(strContent[0].size()); @@ -3109,8 +3111,11 @@ void BfIRCodeGen::HandleNextCmd() chars.push_back(llvm::ConstantInt::get(charType, 0)); auto stringType = llvm::ArrayType::get(charType, chars.size()); - - auto globalVar = (llvm::GlobalVariable*)mLLVMModule->getOrInsertGlobal("", stringType); + + 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);