summaryrefslogtreecommitdiffstats
path: root/contrib/restricted/wavm/Lib/LLVMJIT/EmitModule.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/restricted/wavm/Lib/LLVMJIT/EmitModule.cpp')
-rw-r--r--contrib/restricted/wavm/Lib/LLVMJIT/EmitModule.cpp292
1 files changed, 292 insertions, 0 deletions
diff --git a/contrib/restricted/wavm/Lib/LLVMJIT/EmitModule.cpp b/contrib/restricted/wavm/Lib/LLVMJIT/EmitModule.cpp
new file mode 100644
index 00000000000..34cf4c580ec
--- /dev/null
+++ b/contrib/restricted/wavm/Lib/LLVMJIT/EmitModule.cpp
@@ -0,0 +1,292 @@
+#include <stdint.h>
+#include <vector>
+#include "EmitFunctionContext.h"
+#include "EmitModuleContext.h"
+#include "LLVMJITPrivate.h"
+#include "WAVM/IR/Module.h"
+#include "WAVM/IR/Types.h"
+#include "WAVM/Inline/BasicTypes.h"
+#include "WAVM/Inline/Timing.h"
+
+PUSH_DISABLE_WARNINGS_FOR_LLVM_HEADERS
+#include <llvm/ADT/Twine.h>
+#include <llvm/BinaryFormat/Dwarf.h>
+#include <llvm/IR/Constants.h>
+#include <llvm/IR/DIBuilder.h>
+#include <llvm/IR/DebugInfoMetadata.h>
+#include <llvm/IR/DerivedTypes.h>
+#include <llvm/IR/Function.h>
+#include <llvm/IR/GlobalValue.h>
+#include <llvm/IR/GlobalVariable.h>
+#include <llvm/IR/Metadata.h>
+#include <llvm/IR/Module.h>
+#include <llvm/IR/Type.h>
+POP_DISABLE_WARNINGS_FOR_LLVM_HEADERS
+
+namespace llvm {
+ class Constant;
+}
+
+using namespace WAVM;
+using namespace WAVM::IR;
+using namespace WAVM::LLVMJIT;
+using namespace WAVM::Runtime;
+
+EmitModuleContext::EmitModuleContext(const IR::Module& inIRModule,
+ LLVMContext& inLLVMContext,
+ llvm::Module* inLLVMModule,
+ llvm::TargetMachine* inTargetMachine)
+: irModule(inIRModule)
+, llvmContext(inLLVMContext)
+, llvmModule(inLLVMModule)
+, targetMachine(inTargetMachine)
+, defaultTableOffset(nullptr)
+, diBuilder(*inLLVMModule)
+{
+ targetArch = targetMachine->getTargetTriple().getArch();
+ useWindowsSEH = targetMachine->getTargetTriple().getOS() == llvm::Triple::Win32;
+
+#if LLVM_VERSION_MAJOR >= 7
+ const U32 numPointerBytes = targetMachine->getProgramPointerSize();
+#else
+ const U32 numPointerBytes = targetMachine->getPointerSize();
+#endif
+ iptrAlignment = numPointerBytes;
+ iptrType = getIptrType(llvmContext, numPointerBytes);
+ switch(iptrAlignment)
+ {
+ case 4: iptrValueType = ValueType::i32; break;
+ case 8: iptrValueType = ValueType::i64; break;
+ default: Errors::fatalf("Unexpected pointer size: %u bytes", numPointerBytes);
+ };
+
+ diModuleScope = diBuilder.createFile("unknown", "unknown");
+#if LLVM_VERSION_MAJOR >= 9
+ diCompileUnit
+ = diBuilder.createCompileUnit(0xffff,
+ diModuleScope,
+ "WAVM",
+ true,
+ "",
+ 0,
+ llvm::StringRef(),
+ llvm::DICompileUnit::DebugEmissionKind::LineTablesOnly,
+ 0,
+ true,
+ false,
+ llvm::DICompileUnit::DebugNameTableKind::None,
+ false);
+#else
+ diCompileUnit = diBuilder.createCompileUnit(0xffff, diModuleScope, "WAVM", true, "", 0);
+#endif
+
+ diValueTypes[(Uptr)ValueType::any] = nullptr;
+ diValueTypes[(Uptr)ValueType::i32]
+ = diBuilder.createBasicType("i32", 32, llvm::dwarf::DW_ATE_signed);
+ diValueTypes[(Uptr)ValueType::i64]
+ = diBuilder.createBasicType("i64", 64, llvm::dwarf::DW_ATE_signed);
+ diValueTypes[(Uptr)ValueType::f32]
+ = diBuilder.createBasicType("f32", 32, llvm::dwarf::DW_ATE_float);
+ diValueTypes[(Uptr)ValueType::f64]
+ = diBuilder.createBasicType("f64", 64, llvm::dwarf::DW_ATE_float);
+ diValueTypes[(Uptr)ValueType::v128]
+ = diBuilder.createBasicType("v128", 128, llvm::dwarf::DW_ATE_signed);
+ diValueTypes[(Uptr)ValueType::externref]
+ = diBuilder.createBasicType("externref", 8, llvm::dwarf::DW_ATE_address);
+ diValueTypes[(Uptr)ValueType::funcref]
+ = diBuilder.createBasicType("funcref", 8, llvm::dwarf::DW_ATE_address);
+
+ auto zeroAsMetadata = llvm::ConstantAsMetadata::get(emitLiteral(llvmContext, I32(0)));
+ auto i32MaxAsMetadata = llvm::ConstantAsMetadata::get(emitLiteral(llvmContext, I32(INT32_MAX)));
+ likelyFalseBranchWeights = llvm::MDTuple::getDistinct(
+ llvmContext,
+ {llvm::MDString::get(llvmContext, "branch_weights"), zeroAsMetadata, i32MaxAsMetadata});
+ likelyTrueBranchWeights = llvm::MDTuple::getDistinct(
+ llvmContext,
+ {llvm::MDString::get(llvmContext, "branch_weights"), i32MaxAsMetadata, zeroAsMetadata});
+
+ fpRoundingModeMetadata = llvm::MetadataAsValue::get(
+ llvmContext, llvm::MDString::get(llvmContext, "round.tonearest"));
+ fpExceptionMetadata = llvm::MetadataAsValue::get(
+ llvmContext, llvm::MDString::get(llvmContext, "fpexcept.strict"));
+}
+
+static llvm::Constant* createImportedConstant(llvm::Module& llvmModule, llvm::Twine externalName)
+{
+ return new llvm::GlobalVariable(llvmModule,
+ llvm::Type::getInt8Ty(llvmModule.getContext()),
+ false,
+ llvm::GlobalVariable::ExternalLinkage,
+ nullptr,
+ externalName);
+}
+
+void LLVMJIT::emitModule(const IR::Module& irModule,
+ LLVMContext& llvmContext,
+ llvm::Module& outLLVMModule,
+ llvm::TargetMachine* targetMachine)
+{
+ Timing::Timer emitTimer;
+ EmitModuleContext moduleContext(irModule, llvmContext, &outLLVMModule, targetMachine);
+
+ // Set the module data layout for the target machine.
+ outLLVMModule.setDataLayout(targetMachine->createDataLayout());
+
+ // Create an external reference to the appropriate exception personality function.
+ auto personalityFunction = llvm::Function::Create(
+ llvm::FunctionType::get(llvmContext.i32Type, {}, false),
+ llvm::GlobalValue::LinkageTypes::ExternalLinkage,
+ moduleContext.useWindowsSEH ? "__CxxFrameHandler3" : "__gxx_personality_v0",
+ &outLLVMModule);
+
+ // Create LLVM external globals corresponding to the encoded function types for the module's
+ // indexed function types.
+ for(Uptr typeIndex = 0; typeIndex < irModule.types.size(); ++typeIndex)
+ {
+ moduleContext.typeIds.push_back(llvm::ConstantExpr::getPtrToInt(
+ createImportedConstant(outLLVMModule, getExternalName("typeId", typeIndex)),
+ moduleContext.iptrType));
+ }
+
+ // Create LLVM external globals corresponding to offsets to table base pointers in
+ // CompartmentRuntimeData for the module's declared table objects.
+ for(Uptr tableIndex = 0; tableIndex < irModule.tables.size(); ++tableIndex)
+ {
+ moduleContext.tableOffsets.push_back(llvm::ConstantExpr::getPtrToInt(
+ createImportedConstant(outLLVMModule, getExternalName("tableOffset", tableIndex)),
+ moduleContext.iptrType));
+ }
+ if(moduleContext.tableOffsets.size())
+ { moduleContext.defaultTableOffset = moduleContext.tableOffsets[0]; }
+
+ // Create LLVM external globals corresponding to offsets to memory base pointers in
+ // CompartmentRuntimeData for the module's declared memory objects.
+ for(Uptr memoryIndex = 0; memoryIndex < irModule.memories.size(); ++memoryIndex)
+ {
+ moduleContext.memoryOffsets.push_back(llvm::ConstantExpr::getPtrToInt(
+ createImportedConstant(outLLVMModule, getExternalName("memoryOffset", memoryIndex)),
+ moduleContext.iptrType));
+ }
+
+ // Create LLVM external globals for the module's globals.
+ for(Uptr globalIndex = 0; globalIndex < irModule.globals.size(); ++globalIndex)
+ {
+ moduleContext.globals.push_back(
+ createImportedConstant(outLLVMModule, getExternalName("global", globalIndex)));
+ }
+
+ // Create LLVM external globals corresponding to pointers to ExceptionTypes for the
+ // module's declared exception types.
+ for(Uptr exceptionTypeIndex = 0; exceptionTypeIndex < irModule.exceptionTypes.size();
+ ++exceptionTypeIndex)
+ {
+ llvm::Constant* biasedExceptionTypeIdAsPointer = createImportedConstant(
+ outLLVMModule, getExternalName("biasedExceptionTypeId", exceptionTypeIndex));
+ llvm::Constant* biasedExceptionTypeId = llvm::ConstantExpr::getPtrToInt(
+ biasedExceptionTypeIdAsPointer, moduleContext.iptrType);
+ llvm::Constant* exceptionTypeId = llvm::ConstantExpr::getSub(
+ biasedExceptionTypeId, emitLiteralIptr(1, moduleContext.iptrType));
+ moduleContext.exceptionTypeIds.push_back(exceptionTypeId);
+ }
+
+ // Create a LLVM external global that will point to the Instance.
+ llvm::Constant* biasedInstanceIdAsPointer
+ = createImportedConstant(outLLVMModule, "biasedInstanceId");
+ llvm::Constant* biasedInstanceId
+ = llvm::ConstantExpr::getPtrToInt(biasedInstanceIdAsPointer, moduleContext.iptrType);
+ moduleContext.instanceId
+ = llvm::ConstantExpr::getSub(biasedInstanceId, emitLiteralIptr(1, moduleContext.iptrType));
+
+ // Create a LLVM external global that will be a bias applied to all references in a table.
+ moduleContext.tableReferenceBias = llvm::ConstantExpr::getPtrToInt(
+ createImportedConstant(outLLVMModule, "tableReferenceBias"), moduleContext.iptrType);
+
+#if LLVM_VERSION_MAJOR < 10
+ // Create a LLVM external global that will be a constant Iptr 1 that is opaque to the optimizer.
+ moduleContext.unoptimizableOne = llvm::ConstantExpr::getPtrToInt(
+ createImportedConstant(outLLVMModule, "unoptimizableOne"), moduleContext.iptrType);
+#endif
+
+ // Create a LLVM external global that will point to the std::type_info for Runtime::Exception.
+ if(moduleContext.useWindowsSEH)
+ {
+ // The Windows type_info is referenced by the exception handling tables with a 32-bit
+ // image-relative offset, so we have to create a copy of it in the image.
+ const char* typeMangledName = ".PEAUException@Runtime@WAVM@@";
+ llvm::Type* typeDescriptorTypeElements[3]
+ = {llvmContext.i8PtrType->getPointerTo(),
+ llvmContext.i8PtrType,
+ llvm::ArrayType::get(llvmContext.i8Type, strlen(typeMangledName) + 1)};
+ llvm::StructType* typeDescriptorType = llvm::StructType::create(typeDescriptorTypeElements);
+ llvm::Constant* typeDescriptorElements[3]
+ = {llvm::ConstantPointerNull::get(llvmContext.i8PtrType->getPointerTo()),
+ llvm::ConstantPointerNull::get(llvmContext.i8PtrType),
+ llvm::ConstantDataArray::getString(llvmContext, typeMangledName, true)};
+ llvm::Constant* typeDescriptor
+ = llvm::ConstantStruct::get(typeDescriptorType, typeDescriptorElements);
+ llvm::GlobalVariable* typeDescriptorVariable
+ = new llvm::GlobalVariable(*moduleContext.llvmModule,
+ typeDescriptorType,
+ false,
+ llvm::GlobalVariable::LinkOnceODRLinkage,
+ typeDescriptor,
+ "??_R0PEAUException@Runtime@WAVM@@@8");
+ typeDescriptorVariable->setComdat(
+ moduleContext.llvmModule->getOrInsertComdat("??_R0PEAUException@Runtime@WAVM@@@8"));
+ moduleContext.runtimeExceptionTypeInfo = typeDescriptorVariable;
+ }
+ else
+ {
+ moduleContext.runtimeExceptionTypeInfo = llvm::ConstantExpr::getPointerCast(
+ createImportedConstant(*moduleContext.llvmModule, "runtimeExceptionTypeInfo"),
+ llvmContext.i8PtrType);
+ }
+
+ // Create the LLVM functions.
+ moduleContext.functions.resize(irModule.functions.size());
+ for(Uptr functionIndex = 0; functionIndex < irModule.functions.size(); ++functionIndex)
+ {
+ FunctionType functionType = irModule.types[irModule.functions.getType(functionIndex).index];
+
+ llvm::Function* function = llvm::Function::Create(
+ asLLVMType(llvmContext, functionType),
+ llvm::Function::ExternalLinkage,
+ functionIndex >= irModule.functions.imports.size()
+ ? getExternalName("functionDef", functionIndex - irModule.functions.imports.size())
+ : getExternalName("functionImport", functionIndex),
+ &outLLVMModule);
+ function->setCallingConv(asLLVMCallingConv(functionType.callingConvention()));
+ moduleContext.functions[functionIndex] = function;
+ }
+
+ // Compile each function in the module.
+ for(Uptr functionDefIndex = 0; functionDefIndex < irModule.functions.defs.size();
+ ++functionDefIndex)
+ {
+ const FunctionDef& functionDef = irModule.functions.defs[functionDefIndex];
+ llvm::Function* function
+ = moduleContext.functions[irModule.functions.imports.size() + functionDefIndex];
+
+ function->setPersonalityFn(personalityFunction);
+
+ llvm::Constant* functionDefMutableData = createImportedConstant(
+ outLLVMModule, getExternalName("functionDefMutableDatas", functionDefIndex));
+ llvm::Constant* functionDefMutableDataAsIptr
+ = llvm::ConstantExpr::getPtrToInt(functionDefMutableData, moduleContext.iptrType);
+
+ setRuntimeFunctionPrefix(llvmContext,
+ moduleContext.iptrType,
+ function,
+ functionDefMutableDataAsIptr,
+ moduleContext.instanceId,
+ moduleContext.typeIds[functionDef.type.index]);
+ setFunctionAttributes(targetMachine, function);
+
+ EmitFunctionContext(llvmContext, moduleContext, irModule, functionDef, function).emit();
+ }
+
+ // Finalize the debug info.
+ moduleContext.diBuilder.finalize();
+
+ Timing::logRatePerSecond("Emitted LLVM IR", emitTimer, (F64)outLLVMModule.size(), "functions");
+}