Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2008-2017, Petr Kobalicek
3 :
4 : This software is provided 'as-is', without any express or implied
5 : warranty. In no event will the authors be held liable for any damages
6 : arising from the use of this software.
7 :
8 : Permission is granted to anyone to use this software for any purpose,
9 : including commercial applications, and to alter it and redistribute it
10 : freely, subject to the following restrictions:
11 :
12 : 1. The origin of this software must not be misrepresented; you must not
13 : claim that you wrote the original software. If you use this software
14 : in a product, an acknowledgment in the product documentation would be
15 : appreciated but is not required.
16 : 2. Altered source versions must be plainly marked as such, and must not be
17 : misrepresented as being the original software.
18 : 3. This notice may not be removed or altered from any source distribution.
19 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
20 : #ifdef __PLUMED_HAS_ASMJIT
21 : #pragma GCC diagnostic push
22 : #pragma GCC diagnostic ignored "-Wpedantic"
23 : // [AsmJit]
24 : // Complete x86/x64 JIT and Remote Assembler for C++.
25 : //
26 : // [License]
27 : // Zlib - See LICENSE.md file in the package.
28 :
29 : // [Export]
30 : #define ASMJIT_EXPORTS
31 :
32 : // [Guard]
33 : #include "./asmjit_build.h"
34 : #if defined(ASMJIT_BUILD_X86) && !defined(ASMJIT_DISABLE_COMPILER)
35 :
36 : // [Dependencies]
37 : #include "./utils.h"
38 : #include "./x86compiler.h"
39 : #include "./x86regalloc_p.h"
40 :
41 : // [Api-Begin]
42 : #include "./asmjit_apibegin.h"
43 :
44 : namespace PLMD {
45 : namespace asmjit {
46 :
47 : // ============================================================================
48 : // [asmjit::X86Compiler - Construction / Destruction]
49 : // ============================================================================
50 :
51 1944 : X86Compiler::X86Compiler(CodeHolder* code) noexcept : CodeCompiler() {
52 1944 : if (code)
53 1944 : code->attach(this);
54 1944 : }
55 1944 : X86Compiler::~X86Compiler() noexcept {}
56 :
57 : // ============================================================================
58 : // [asmjit::X86Compiler - Events]
59 : // ============================================================================
60 :
61 1944 : Error X86Compiler::onAttach(CodeHolder* code) noexcept {
62 : uint32_t archType = code->getArchType();
63 1944 : if (!ArchInfo::isX86Family(archType))
64 : return DebugUtils::errored(kErrorInvalidArch);
65 :
66 3888 : ASMJIT_PROPAGATE(_cbPasses.willGrow(&_cbHeap, 1));
67 1944 : ASMJIT_PROPAGATE(Base::onAttach(code));
68 :
69 1944 : if (archType == ArchInfo::kTypeX86)
70 0 : _nativeGpArray = x86OpData.gpd;
71 : else
72 1944 : _nativeGpArray = x86OpData.gpq;
73 1944 : _nativeGpReg = _nativeGpArray[0];
74 :
75 3888 : return addPassT<X86RAPass>();
76 : }
77 :
78 : // ============================================================================
79 : // [asmjit::X86Compiler - Finalize]
80 : // ============================================================================
81 :
82 1944 : Error X86Compiler::finalize() {
83 1944 : if (_lastError) return _lastError;
84 :
85 : // Flush the global constant pool.
86 1944 : if (_globalConstPool) {
87 0 : addNode(_globalConstPool);
88 0 : _globalConstPool = nullptr;
89 : }
90 :
91 : Error err = kErrorOk;
92 : ZoneVector<CBPass*>& passes = _cbPasses;
93 :
94 3888 : for (size_t i = 0, len = passes.getLength(); i < len; i++) {
95 1944 : CBPass* pass = passes[i];
96 1944 : err = pass->process(&_cbPassZone);
97 1944 : _cbPassZone.reset();
98 1944 : if (err) break;
99 : }
100 :
101 1944 : _cbPassZone.reset();
102 1944 : if (ASMJIT_UNLIKELY(err)) return setLastError(err);
103 :
104 : // TODO: There must be possibility to attach more assemblers, this is not so nice.
105 1944 : if (_code->_cgAsm) {
106 0 : return serialize(_code->_cgAsm);
107 : }
108 : else {
109 1944 : X86Assembler a(_code);
110 1944 : return serialize(&a);
111 1944 : }
112 : }
113 :
114 : // ============================================================================
115 : // [asmjit::X86Compiler - Inst]
116 : // ============================================================================
117 :
118 : static ASMJIT_INLINE bool isJumpInst(uint32_t instId) noexcept {
119 46618 : return (instId >= X86Inst::kIdJa && instId <= X86Inst::kIdJz ) ||
120 46618 : (instId >= X86Inst::kIdLoop && instId <= X86Inst::kIdLoopne) ;
121 : }
122 :
123 46618 : Error X86Compiler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) {
124 46618 : uint32_t options = getOptions() | getGlobalOptions();
125 : const char* inlineComment = getInlineComment();
126 :
127 46618 : uint32_t opCount = static_cast<uint32_t>(!o0.isNone()) +
128 46618 : static_cast<uint32_t>(!o1.isNone()) +
129 46618 : static_cast<uint32_t>(!o2.isNone()) +
130 46618 : static_cast<uint32_t>(!o3.isNone()) ;
131 :
132 : // Handle failure and rare cases first.
133 : const uint32_t kErrorsAndSpecialCases = kOptionMaybeFailureCase | // CodeEmitter is in error state.
134 : kOptionStrictValidation ; // Strict validation.
135 :
136 46618 : if (ASMJIT_UNLIKELY(options & kErrorsAndSpecialCases)) {
137 : // Don't do anything if we are in error state.
138 0 : if (_lastError) return _lastError;
139 :
140 : #if !defined(ASMJIT_DISABLE_VALIDATION)
141 : // Strict validation.
142 0 : if (options & kOptionStrictValidation) {
143 : Operand opArray[] = {
144 : Operand(o0),
145 : Operand(o1),
146 : Operand(o2),
147 : Operand(o3)
148 : };
149 :
150 : Inst::Detail instDetail(instId, options, _extraReg);
151 0 : Error err = Inst::validate(getArchType(), instDetail, opArray, opCount);
152 :
153 0 : if (err) {
154 : #if !defined(ASMJIT_DISABLE_LOGGING)
155 : StringBuilderTmp<256> sb;
156 0 : sb.appendString(DebugUtils::errorAsString(err));
157 : sb.appendString(": ");
158 0 : Logging::formatInstruction(sb, 0, this, getArchType(), instDetail, opArray, opCount);
159 0 : return setLastError(err, sb.getData());
160 : #else
161 : return setLastError(err);
162 : #endif
163 : }
164 :
165 : // Clear it as it must be enabled explicitly on assembler side.
166 0 : options &= ~kOptionStrictValidation;
167 : }
168 : #endif // ASMJIT_DISABLE_VALIDATION
169 : }
170 :
171 : resetOptions();
172 : resetInlineComment();
173 :
174 : // decide between `CBInst` and `CBJump`.
175 46618 : if (isJumpInst(instId)) {
176 0 : CBJump* node = _cbHeap.allocT<CBJump>(sizeof(CBJump) + opCount * sizeof(Operand));
177 0 : Operand* opArray = reinterpret_cast<Operand*>(reinterpret_cast<uint8_t*>(node) + sizeof(CBJump));
178 :
179 0 : if (ASMJIT_UNLIKELY(!node))
180 0 : return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
181 :
182 0 : if (opCount > 0) opArray[0].copyFrom(o0);
183 0 : if (opCount > 1) opArray[1].copyFrom(o1);
184 0 : if (opCount > 2) opArray[2].copyFrom(o2);
185 0 : if (opCount > 3) opArray[3].copyFrom(o3);
186 :
187 : new(node) CBJump(this, instId, options, opArray, opCount);
188 0 : node->_instDetail.extraReg = _extraReg;
189 : _extraReg.reset();
190 :
191 0 : CBLabel* jTarget = nullptr;
192 0 : if (!(options & kOptionUnfollow)) {
193 0 : if (opArray[0].isLabel()) {
194 0 : Error err = getCBLabel(&jTarget, static_cast<Label&>(opArray[0]));
195 0 : if (err) return setLastError(err);
196 : }
197 : else {
198 0 : options |= kOptionUnfollow;
199 : }
200 : }
201 : node->setOptions(options);
202 :
203 0 : node->orFlags(instId == X86Inst::kIdJmp ? CBNode::kFlagIsJmp | CBNode::kFlagIsTaken : CBNode::kFlagIsJcc);
204 0 : node->_target = jTarget;
205 0 : node->_jumpNext = nullptr;
206 :
207 0 : if (jTarget) {
208 0 : node->_jumpNext = static_cast<CBJump*>(jTarget->_from);
209 0 : jTarget->_from = node;
210 : jTarget->addNumRefs();
211 : }
212 :
213 : // The 'jmp' is always taken, conditional jump can contain hint, we detect it.
214 0 : if (instId == X86Inst::kIdJmp)
215 : node->orFlags(CBNode::kFlagIsTaken);
216 0 : else if (options & X86Inst::kOptionTaken)
217 : node->orFlags(CBNode::kFlagIsTaken);
218 :
219 0 : if (inlineComment) {
220 0 : inlineComment = static_cast<char*>(_cbDataZone.dup(inlineComment, ::strlen(inlineComment), true));
221 : node->setInlineComment(inlineComment);
222 : }
223 :
224 0 : addNode(node);
225 0 : return kErrorOk;
226 : }
227 : else {
228 46618 : CBInst* node = _cbHeap.allocT<CBInst>(sizeof(CBInst) + opCount * sizeof(Operand));
229 46618 : Operand* opArray = reinterpret_cast<Operand*>(reinterpret_cast<uint8_t*>(node) + sizeof(CBInst));
230 :
231 46618 : if (ASMJIT_UNLIKELY(!node))
232 0 : return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
233 :
234 46618 : if (opCount > 0) opArray[0].copyFrom(o0);
235 46618 : if (opCount > 1) opArray[1].copyFrom(o1);
236 46618 : if (opCount > 2) opArray[2].copyFrom(o2);
237 46618 : if (opCount > 3) opArray[3].copyFrom(o3);
238 :
239 : node = new(node) CBInst(this, instId, options, opArray, opCount);
240 46618 : node->_instDetail.extraReg = _extraReg;
241 : _extraReg.reset();
242 :
243 46618 : if (inlineComment) {
244 0 : inlineComment = static_cast<char*>(_cbDataZone.dup(inlineComment, ::strlen(inlineComment), true));
245 : node->setInlineComment(inlineComment);
246 : }
247 :
248 46618 : addNode(node);
249 46618 : return kErrorOk;
250 : }
251 : }
252 :
253 0 : Error X86Compiler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) {
254 0 : uint32_t options = getOptions() | getGlobalOptions();
255 : const char* inlineComment = getInlineComment();
256 :
257 0 : uint32_t opCount = static_cast<uint32_t>(!o0.isNone()) +
258 0 : static_cast<uint32_t>(!o1.isNone()) +
259 0 : static_cast<uint32_t>(!o2.isNone()) +
260 0 : static_cast<uint32_t>(!o3.isNone()) ;
261 :
262 : // Count 5th and 6th operands.
263 0 : if (!o4.isNone()) opCount = 5;
264 0 : if (!o5.isNone()) opCount = 6;
265 :
266 : // Handle failure and rare cases first.
267 : const uint32_t kErrorsAndSpecialCases = kOptionMaybeFailureCase | // CodeEmitter in error state.
268 : kOptionStrictValidation ; // Strict validation.
269 :
270 0 : if (ASMJIT_UNLIKELY(options & kErrorsAndSpecialCases)) {
271 : // Don't do anything if we are in error state.
272 0 : if (_lastError) return _lastError;
273 :
274 : #if !defined(ASMJIT_DISABLE_VALIDATION)
275 : // Strict validation.
276 0 : if (options & kOptionStrictValidation) {
277 : Operand opArray[] = {
278 : Operand(o0),
279 : Operand(o1),
280 : Operand(o2),
281 : Operand(o3),
282 : Operand(o4),
283 : Operand(o5)
284 : };
285 :
286 : Inst::Detail instDetail(instId, options, _extraReg);
287 0 : Error err = Inst::validate(getArchType(), instDetail, opArray, opCount);
288 :
289 0 : if (err) {
290 : #if !defined(ASMJIT_DISABLE_LOGGING)
291 : StringBuilderTmp<256> sb;
292 0 : sb.appendString(DebugUtils::errorAsString(err));
293 : sb.appendString(": ");
294 0 : Logging::formatInstruction(sb, 0, this, getArchType(), instDetail, opArray, opCount);
295 0 : return setLastError(err, sb.getData());
296 : #else
297 : return setLastError(err);
298 : #endif
299 : }
300 :
301 : // Clear it as it must be enabled explicitly on assembler side.
302 0 : options &= ~kOptionStrictValidation;
303 : }
304 : #endif // ASMJIT_DISABLE_VALIDATION
305 : }
306 :
307 : resetOptions();
308 : resetInlineComment();
309 :
310 : // decide between `CBInst` and `CBJump`.
311 0 : if (isJumpInst(instId)) {
312 0 : CBJump* node = _cbHeap.allocT<CBJump>(sizeof(CBJump) + opCount * sizeof(Operand));
313 0 : Operand* opArray = reinterpret_cast<Operand*>(reinterpret_cast<uint8_t*>(node) + sizeof(CBJump));
314 :
315 0 : if (ASMJIT_UNLIKELY(!node))
316 0 : return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
317 :
318 0 : if (opCount > 0) opArray[0].copyFrom(o0);
319 0 : if (opCount > 1) opArray[1].copyFrom(o1);
320 0 : if (opCount > 2) opArray[2].copyFrom(o2);
321 0 : if (opCount > 3) opArray[3].copyFrom(o3);
322 0 : if (opCount > 4) opArray[4].copyFrom(o4);
323 0 : if (opCount > 5) opArray[5].copyFrom(o5);
324 :
325 : new(node) CBJump(this, instId, options, opArray, opCount);
326 0 : node->_instDetail.extraReg = _extraReg;
327 : _extraReg.reset();
328 :
329 0 : CBLabel* jTarget = nullptr;
330 0 : if (!(options & kOptionUnfollow)) {
331 0 : if (opArray[0].isLabel()) {
332 0 : Error err = getCBLabel(&jTarget, static_cast<Label&>(opArray[0]));
333 0 : if (err) return setLastError(err);
334 : }
335 : else {
336 0 : options |= kOptionUnfollow;
337 : }
338 : }
339 : node->setOptions(options);
340 :
341 0 : node->orFlags(instId == X86Inst::kIdJmp ? CBNode::kFlagIsJmp | CBNode::kFlagIsTaken : CBNode::kFlagIsJcc);
342 0 : node->_target = jTarget;
343 0 : node->_jumpNext = nullptr;
344 :
345 0 : if (jTarget) {
346 0 : node->_jumpNext = static_cast<CBJump*>(jTarget->_from);
347 0 : jTarget->_from = node;
348 : jTarget->addNumRefs();
349 : }
350 :
351 : // The 'jmp' is always taken, conditional jump can contain hint, we detect it.
352 0 : if (instId == X86Inst::kIdJmp)
353 : node->orFlags(CBNode::kFlagIsTaken);
354 0 : else if (options & X86Inst::kOptionTaken)
355 : node->orFlags(CBNode::kFlagIsTaken);
356 :
357 0 : if (inlineComment) {
358 0 : inlineComment = static_cast<char*>(_cbDataZone.dup(inlineComment, ::strlen(inlineComment), true));
359 : node->setInlineComment(inlineComment);
360 : }
361 :
362 0 : addNode(node);
363 0 : return kErrorOk;
364 : }
365 : else {
366 0 : CBInst* node = _cbHeap.allocT<CBInst>(sizeof(CBInst) + opCount * sizeof(Operand));
367 0 : Operand* opArray = reinterpret_cast<Operand*>(reinterpret_cast<uint8_t*>(node) + sizeof(CBInst));
368 :
369 0 : if (ASMJIT_UNLIKELY(!node))
370 0 : return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
371 :
372 0 : if (opCount > 0) opArray[0].copyFrom(o0);
373 0 : if (opCount > 1) opArray[1].copyFrom(o1);
374 0 : if (opCount > 2) opArray[2].copyFrom(o2);
375 0 : if (opCount > 3) opArray[3].copyFrom(o3);
376 0 : if (opCount > 4) opArray[4].copyFrom(o4);
377 0 : if (opCount > 5) opArray[5].copyFrom(o5);
378 :
379 : node = new(node) CBInst(this, instId, options, opArray, opCount);
380 0 : node->_instDetail.extraReg = _extraReg;
381 : _extraReg.reset();
382 :
383 0 : if (inlineComment) {
384 0 : inlineComment = static_cast<char*>(_cbDataZone.dup(inlineComment, ::strlen(inlineComment), true));
385 : node->setInlineComment(inlineComment);
386 : }
387 :
388 0 : addNode(node);
389 0 : return kErrorOk;
390 : }
391 : }
392 :
393 : } // asmjit namespace
394 : } // namespace PLMD
395 :
396 : // [Api-End]
397 : #include "./asmjit_apiend.h"
398 :
399 : // [Guard]
400 : #endif // ASMJIT_BUILD_X86 && !ASMJIT_DISABLE_COMPILER
401 : #pragma GCC diagnostic pop
402 : #endif // __PLUMED_HAS_ASMJIT
|