1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
|
#include "WAVM/LLVMJIT/LLVMJIT.h"
#include <utility>
#include "LLVMJITPrivate.h"
#include "WAVM/IR/FeatureSpec.h"
#include "WAVM/Inline/Assert.h"
#include "WAVM/Inline/BasicTypes.h"
#include "WAVM/Inline/Errors.h"
#include "WAVM/Inline/HashMap.h"
PUSH_DISABLE_WARNINGS_FOR_LLVM_HEADERS
#include <llvm/ADT/APInt.h>
#include <llvm/ADT/StringRef.h>
#include <llvm/CodeGen/TargetSubtargetInfo.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/ExecutionEngine/JITSymbol.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/Type.h>
#include <llvm/Support/DynamicLibrary.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Target/TargetMachine.h>
POP_DISABLE_WARNINGS_FOR_LLVM_HEADERS
namespace llvm {
class Constant;
}
using namespace WAVM;
using namespace WAVM::IR;
using namespace WAVM::LLVMJIT;
namespace LLVMRuntimeSymbols {
#ifdef _WIN32
// the LLVM X86 code generator calls __chkstk when allocating more than 4KB of stack space
extern "C" void __chkstk();
extern "C" void __CxxFrameHandler3();
#else
#if defined(__APPLE__)
// LLVM's memset intrinsic lowers to calling __bzero on MacOS when writing a constant zero.
extern "C" void __bzero();
#endif
#if defined(__i386__) || defined(__x86_64__)
extern "C" void wavm_probe_stack();
#endif
extern "C" int __gxx_personality_v0();
extern "C" void* __cxa_begin_catch(void*) throw();
extern "C" void __cxa_end_catch();
#endif
static HashMap<std::string, void*> map = {
{"memmove", (void*)&memmove},
{"memset", (void*)&memset},
#ifdef _WIN32
{"__chkstk", (void*)&__chkstk},
{"__CxxFrameHandler3", (void*)&__CxxFrameHandler3},
#else
#if defined(__APPLE__)
{"__bzero", (void*)&__bzero},
#endif
#if defined(__i386__) || defined(__x86_64__)
{"wavm_probe_stack", (void*)&wavm_probe_stack},
#endif
{"__gxx_personality_v0", (void*)&__gxx_personality_v0},
{"__cxa_begin_catch", (void*)&__cxa_begin_catch},
{"__cxa_end_catch", (void*)&__cxa_end_catch},
#endif
};
}
llvm::JITEvaluatedSymbol LLVMJIT::resolveJITImport(llvm::StringRef name)
{
// Allow some intrinsics used by LLVM
void** symbolValue = LLVMRuntimeSymbols::map.get(name.str());
if(!symbolValue)
{
Errors::fatalf("LLVM generated code references unknown external symbol: %s",
name.str().c_str());
}
return llvm::JITEvaluatedSymbol(reinterpret_cast<Uptr>(*symbolValue),
llvm::JITSymbolFlags::None);
}
static bool globalInitLLVM()
{
llvm::InitializeNativeTarget();
llvm::InitializeNativeTargetAsmParser();
llvm::InitializeNativeTargetAsmPrinter();
llvm::InitializeNativeTargetDisassembler();
llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr);
return true;
}
static void globalInitLLVMOnce()
{
static bool isLLVMInitialized = globalInitLLVM();
WAVM_ASSERT(isLLVMInitialized);
}
LLVMContext::LLVMContext()
{
globalInitLLVMOnce();
i8Type = llvm::Type::getInt8Ty(*this);
i16Type = llvm::Type::getInt16Ty(*this);
i32Type = llvm::Type::getInt32Ty(*this);
i64Type = llvm::Type::getInt64Ty(*this);
f32Type = llvm::Type::getFloatTy(*this);
f64Type = llvm::Type::getDoubleTy(*this);
i8PtrType = i8Type->getPointerTo();
externrefType = llvm::StructType::create("Object", i8Type)->getPointerTo();
i8x8Type = FixedVectorType::get(i8Type, 8);
i16x4Type = FixedVectorType::get(i16Type, 4);
i32x2Type = FixedVectorType::get(i32Type, 2);
i64x1Type = FixedVectorType::get(i64Type, 1);
f32x2Type = FixedVectorType::get(f32Type, 2);
f64x1Type = FixedVectorType::get(f64Type, 1);
i8x16Type = FixedVectorType::get(i8Type, 16);
i16x8Type = FixedVectorType::get(i16Type, 8);
i32x4Type = FixedVectorType::get(i32Type, 4);
i64x2Type = FixedVectorType::get(i64Type, 2);
f32x4Type = FixedVectorType::get(f32Type, 4);
f64x2Type = FixedVectorType::get(f64Type, 2);
i8x32Type = FixedVectorType::get(i8Type, 32);
i16x16Type = FixedVectorType::get(i16Type, 16);
i32x8Type = FixedVectorType::get(i32Type, 8);
i64x4Type = FixedVectorType::get(i64Type, 4);
i8x48Type = FixedVectorType::get(i8Type, 48);
i16x24Type = FixedVectorType::get(i16Type, 24);
i32x12Type = FixedVectorType::get(i32Type, 12);
i64x6Type = FixedVectorType::get(i64Type, 6);
i8x64Type = FixedVectorType::get(i8Type, 64);
i16x32Type = FixedVectorType::get(i16Type, 32);
i32x16Type = FixedVectorType::get(i32Type, 16);
i64x8Type = FixedVectorType::get(i64Type, 8);
valueTypes[(Uptr)ValueType::none] = valueTypes[(Uptr)ValueType::any] = nullptr;
valueTypes[(Uptr)ValueType::i32] = i32Type;
valueTypes[(Uptr)ValueType::i64] = i64Type;
valueTypes[(Uptr)ValueType::f32] = f32Type;
valueTypes[(Uptr)ValueType::f64] = f64Type;
valueTypes[(Uptr)ValueType::v128] = i64x2Type;
valueTypes[(Uptr)ValueType::externref] = externrefType;
valueTypes[(Uptr)ValueType::funcref] = externrefType;
// Create zero constants of each type.
typedZeroConstants[(Uptr)ValueType::none] = nullptr;
typedZeroConstants[(Uptr)ValueType::any] = nullptr;
typedZeroConstants[(Uptr)ValueType::i32] = emitLiteral(*this, (U32)0);
typedZeroConstants[(Uptr)ValueType::i64] = emitLiteral(*this, (U64)0);
typedZeroConstants[(Uptr)ValueType::f32] = emitLiteral(*this, (F32)0.0f);
typedZeroConstants[(Uptr)ValueType::f64] = emitLiteral(*this, (F64)0.0);
typedZeroConstants[(Uptr)ValueType::v128] = emitLiteral(*this, V128());
typedZeroConstants[(Uptr)ValueType::externref] = typedZeroConstants[(Uptr)ValueType::funcref]
= llvm::Constant::getNullValue(externrefType);
}
TargetSpec LLVMJIT::getHostTargetSpec()
{
TargetSpec result;
result.triple = llvm::sys::getProcessTriple();
result.cpu = std::string(llvm::sys::getHostCPUName());
return result;
}
std::unique_ptr<llvm::TargetMachine> LLVMJIT::getTargetMachine(const TargetSpec& targetSpec)
{
globalInitLLVMOnce();
llvm::Triple triple(targetSpec.triple);
llvm::SmallVector<std::string, 1> targetAttributes;
#if LLVM_VERSION_MAJOR < 10
if(triple.getArch() == llvm::Triple::x86 || triple.getArch() == llvm::Triple::x86_64)
{
// Disable AVX-512 on X86 targets to workaround a LLVM backend bug:
// https://bugs.llvm.org/show_bug.cgi?id=43750
targetAttributes.push_back("-avx512f");
}
#endif
return std::unique_ptr<llvm::TargetMachine>(
llvm::EngineBuilder().selectTarget(triple, "", targetSpec.cpu, targetAttributes));
}
TargetValidationResult LLVMJIT::validateTargetMachine(
const std::unique_ptr<llvm::TargetMachine>& targetMachine,
const FeatureSpec& featureSpec)
{
const llvm::Triple::ArchType targetArch = targetMachine->getTargetTriple().getArch();
if(targetArch == llvm::Triple::x86_64)
{
// If the SIMD feature is enabled, then require the SSE4.1 CPU feature.
if(featureSpec.simd && !targetMachine->getMCSubtargetInfo()->checkFeatures("+sse4.1"))
{ return TargetValidationResult::x86CPUDoesNotSupportSSE41; }
return TargetValidationResult::valid;
}
else if(targetArch == llvm::Triple::aarch64)
{
if(featureSpec.simd && !targetMachine->getMCSubtargetInfo()->checkFeatures("+neon"))
{ return TargetValidationResult::wavmDoesNotSupportSIMDOnArch; }
return TargetValidationResult::valid;
}
else
{
if(featureSpec.simd) { return TargetValidationResult::wavmDoesNotSupportSIMDOnArch; }
if(featureSpec.memory64) { return TargetValidationResult::memory64Requires64bitTarget; }
if(featureSpec.table64) { return TargetValidationResult::table64Requires64bitTarget; }
return TargetValidationResult::unsupportedArchitecture;
}
}
TargetValidationResult LLVMJIT::validateTarget(const TargetSpec& targetSpec,
const IR::FeatureSpec& featureSpec)
{
std::unique_ptr<llvm::TargetMachine> targetMachine = getTargetMachine(targetSpec);
if(!targetMachine) { return TargetValidationResult::invalidTargetSpec; }
return validateTargetMachine(targetMachine, featureSpec);
}
Version LLVMJIT::getVersion()
{
return Version{LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR, LLVM_VERSION_PATCH, 5};
}
|