Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : * -------------------------------------------------------------------------- *
3 : * Lepton *
4 : * -------------------------------------------------------------------------- *
5 : * This is part of the Lepton expression parser originating from *
6 : * Simbios, the NIH National Center for Physics-Based Simulation of *
7 : * Biological Structures at Stanford, funded under the NIH Roadmap for *
8 : * Medical Research, grant U54 GM072970. See https://simtk.org. *
9 : * *
10 : * Portions copyright (c) 2013-2016 Stanford University and the Authors. *
11 : * Authors: Peter Eastman *
12 : * Contributors: *
13 : * *
14 : * Permission is hereby granted, free of charge, to any person obtaining a *
15 : * copy of this software and associated documentation files (the "Software"), *
16 : * to deal in the Software without restriction, including without limitation *
17 : * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
18 : * and/or sell copies of the Software, and to permit persons to whom the *
19 : * Software is furnished to do so, subject to the following conditions: *
20 : * *
21 : * The above copyright notice and this permission notice shall be included in *
22 : * all copies or substantial portions of the Software. *
23 : * *
24 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
25 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
26 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
27 : * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
28 : * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
29 : * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
30 : * USE OR OTHER DEALINGS IN THE SOFTWARE. *
31 : * -------------------------------------------------------------------------- *
32 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
33 : /* -------------------------------------------------------------------------- *
34 : * lepton *
35 : * -------------------------------------------------------------------------- *
36 : * This is part of the lepton expression parser originating from *
37 : * Simbios, the NIH National Center for Physics-Based Simulation of *
38 : * Biological Structures at Stanford, funded under the NIH Roadmap for *
39 : * Medical Research, grant U54 GM072970. See https://simtk.org. *
40 : * *
41 : * Portions copyright (c) 2013-2019 Stanford University and the Authors. *
42 : * Authors: Peter Eastman *
43 : * Contributors: *
44 : * *
45 : * Permission is hereby granted, free of charge, to any person obtaining a *
46 : * copy of this software and associated documentation files (the "Software"), *
47 : * to deal in the Software without restriction, including without limitation *
48 : * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
49 : * and/or sell copies of the Software, and to permit persons to whom the *
50 : * Software is furnished to do so, subject to the following conditions: *
51 : * *
52 : * The above copyright notice and this permission notice shall be included in *
53 : * all copies or substantial portions of the Software. *
54 : * *
55 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
56 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
57 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
58 : * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
59 : * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
60 : * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
61 : * USE OR OTHER DEALINGS IN THE SOFTWARE. *
62 : * -------------------------------------------------------------------------- */
63 :
64 : #include "CompiledExpression.h"
65 : #include "Operation.h"
66 : #include "ParsedExpression.h"
67 : #ifdef __PLUMED_HAS_ASMJIT
68 : #include "asmjit/asmjit.h"
69 : #endif
70 : #include <utility>
71 :
72 : namespace PLMD {
73 : using namespace lepton;
74 : using namespace std;
75 : #ifdef __PLUMED_HAS_ASMJIT
76 : using namespace asmjit;
77 : #endif
78 :
79 5865 : bool lepton::useAsmJit() {
80 : #ifdef __PLUMED_HAS_ASMJIT
81 70 : static const bool use=[](){
82 70 : if(auto s=std::getenv("PLUMED_USE_ASMJIT")) {
83 2 : auto ss=std::string(s);
84 2 : if(ss=="yes") return true;
85 1 : if(ss=="no") return false;
86 0 : throw Exception("PLUMED_USE_ASMJIT variable is set to " + ss + "; should be yes or no");
87 : }
88 : return true; // by default use asmjit
89 5865 : }();
90 5865 : return use;
91 : #else
92 : return false;
93 : #endif
94 : }
95 :
96 2296 : AsmJitRuntimePtr::AsmJitRuntimePtr()
97 : #ifdef __PLUMED_HAS_ASMJIT
98 2296 : : ptr(useAsmJit()?new asmjit::JitRuntime:nullptr)
99 : #endif
100 2296 : {}
101 :
102 2296 : AsmJitRuntimePtr::~AsmJitRuntimePtr()
103 : {
104 : #ifdef __PLUMED_HAS_ASMJIT
105 2296 : if(useAsmJit()) delete static_cast<asmjit::JitRuntime*>(ptr);
106 : #endif
107 2296 : }
108 :
109 1162 : CompiledExpression::CompiledExpression() : jitCode(NULL) {
110 1162 : }
111 :
112 1134 : CompiledExpression::CompiledExpression(const ParsedExpression& expression) : jitCode(NULL) {
113 1134 : ParsedExpression expr = expression.optimize(); // Just in case it wasn't already optimized.
114 : vector<pair<ExpressionTreeNode, int> > temps;
115 1134 : compileExpression(expr.getRootNode(), temps);
116 : int maxArguments = 1;
117 6785 : for (int i = 0; i < (int) operation.size(); i++)
118 5651 : if (operation[i]->getNumArguments() > maxArguments)
119 615 : maxArguments = operation[i]->getNumArguments();
120 1134 : argValues.resize(maxArguments);
121 : #ifdef __PLUMED_HAS_ASMJIT
122 1134 : if(useAsmJit()) generateJitCode();
123 : #endif
124 2268 : }
125 :
126 2296 : CompiledExpression::~CompiledExpression() {
127 13598 : for (int i = 0; i < (int) operation.size(); i++)
128 11302 : if (operation[i] != NULL)
129 11302 : delete operation[i];
130 4592 : }
131 :
132 0 : CompiledExpression::CompiledExpression(const CompiledExpression& expression) : jitCode(NULL) {
133 0 : *this = expression;
134 0 : }
135 :
136 1134 : CompiledExpression& CompiledExpression::operator=(const CompiledExpression& expression) {
137 1134 : arguments = expression.arguments;
138 1134 : target = expression.target;
139 : variableIndices = expression.variableIndices;
140 : variableNames = expression.variableNames;
141 1134 : workspace.resize(expression.workspace.size());
142 1134 : argValues.resize(expression.argValues.size());
143 1134 : operation.resize(expression.operation.size());
144 6785 : for (int i = 0; i < (int) operation.size(); i++)
145 5651 : operation[i] = expression.operation[i]->clone();
146 1134 : setVariableLocations(variablePointers);
147 1134 : return *this;
148 : }
149 :
150 8569 : void CompiledExpression::compileExpression(const ExpressionTreeNode& node, vector<pair<ExpressionTreeNode, int> >& temps) {
151 8569 : if (findTempIndex(node, temps) != -1)
152 1767 : return; // We have already processed a node identical to this one.
153 :
154 : // Process the child nodes.
155 :
156 : vector<int> args;
157 14237 : for (int i = 0; i < node.getChildren().size(); i++) {
158 7435 : compileExpression(node.getChildren()[i], temps);
159 7435 : args.push_back(findTempIndex(node.getChildren()[i], temps));
160 : }
161 :
162 : // Process this node.
163 :
164 6802 : if (node.getOperation().getId() == Operation::VARIABLE) {
165 1151 : variableIndices[node.getOperation().getName()] = (int) workspace.size();
166 2302 : variableNames.insert(node.getOperation().getName());
167 : }
168 : else {
169 5651 : int stepIndex = (int) arguments.size();
170 5651 : arguments.push_back(vector<int>());
171 5651 : target.push_back((int) workspace.size());
172 5651 : operation.push_back(node.getOperation().clone());
173 5651 : if (args.size() == 0)
174 231 : arguments[stepIndex].push_back(0); // The value won't actually be used. We just need something there.
175 : else {
176 : // If the arguments are sequential, we can just pass a pointer to the first one.
177 :
178 : bool sequential = true;
179 7435 : for (int i = 1; i < args.size(); i++)
180 2015 : if (args[i] != args[i-1]+1)
181 : sequential = false;
182 5420 : if (sequential)
183 4196 : arguments[stepIndex].push_back(args[0]);
184 : else
185 1224 : arguments[stepIndex] = args;
186 : }
187 : }
188 6802 : temps.push_back(make_pair(node, (int) workspace.size()));
189 6802 : workspace.push_back(0.0);
190 : }
191 :
192 16004 : int CompiledExpression::findTempIndex(const ExpressionTreeNode& node, vector<pair<ExpressionTreeNode, int> >& temps) {
193 64034 : for (int i = 0; i < (int) temps.size(); i++)
194 57232 : if (temps[i].first == node)
195 : return i;
196 : return -1;
197 : }
198 :
199 525 : const set<string>& CompiledExpression::getVariables() const {
200 525 : return variableNames;
201 : }
202 :
203 3737 : double& CompiledExpression::getVariableReference(const string& name) {
204 : map<string, double*>::iterator pointer = variablePointers.find(name);
205 3737 : if (pointer != variablePointers.end())
206 0 : return *pointer->second;
207 : map<string, int>::iterator index = variableIndices.find(name);
208 3737 : if (index == variableIndices.end())
209 1100 : throw Exception("getVariableReference: Unknown variable '"+name+"'");
210 3187 : return workspace[index->second];
211 : }
212 :
213 1134 : void CompiledExpression::setVariableLocations(map<string, double*>& variableLocations) {
214 : variablePointers = variableLocations;
215 1134 : static const bool asmjit=useAsmJit();
216 1134 : if(asmjit) {
217 : #ifdef __PLUMED_HAS_ASMJIT
218 : // Rebuild the JIT code.
219 :
220 972 : if (workspace.size() > 0)
221 972 : generateJitCode();
222 : #endif
223 : } else {
224 : // Make a list of all variables we will need to copy before evaluating the expression.
225 :
226 162 : variablesToCopy.clear();
227 292 : for (map<string, int>::const_iterator iter = variableIndices.begin(); iter != variableIndices.end(); ++iter) {
228 130 : map<string, double*>::iterator pointer = variablePointers.find(iter->first);
229 130 : if (pointer != variablePointers.end())
230 0 : variablesToCopy.push_back(make_pair(&workspace[iter->second], pointer->second));
231 : }
232 : }
233 1134 : }
234 :
235 12901514 : double CompiledExpression::evaluate() const {
236 12901514 : static const bool asmjit=useAsmJit();
237 : #ifdef __PLUMED_HAS_ASMJIT
238 12901514 : if(asmjit) return ((double (*)()) jitCode)();
239 : #endif
240 16362 : for (int i = 0; i < variablesToCopy.size(); i++)
241 0 : *variablesToCopy[i].first = *variablesToCopy[i].second;
242 :
243 : // Loop over the operations and evaluate each one.
244 :
245 48480 : for (int step = 0; step < operation.size(); step++) {
246 : const vector<int>& args = arguments[step];
247 32118 : if (args.size() == 1)
248 29290 : workspace[target[step]] = operation[step]->evaluate(&workspace[args[0]], dummyVariables);
249 : else {
250 8888 : for (int i = 0; i < args.size(); i++)
251 6060 : argValues[i] = workspace[args[i]];
252 2828 : workspace[target[step]] = operation[step]->evaluate(&argValues[0], dummyVariables);
253 : }
254 : }
255 16362 : return workspace[workspace.size()-1];
256 : }
257 :
258 : #ifdef __PLUMED_HAS_ASMJIT
259 10694844 : static double evaluateOperation(Operation* op, double* args) {
260 10694844 : static map<string, double> dummyVariables;
261 10694844 : return op->evaluate(args, dummyVariables);
262 : }
263 :
264 : static void generateSingleArgCall(X86Compiler& c, X86Xmm& dest, X86Xmm& arg, double (*function)(double));
265 : static void generateTwoArgCall(X86Compiler& c, X86Xmm& dest, X86Xmm& arg1, X86Xmm& arg2, double (*function)(double, double));
266 :
267 1944 : void CompiledExpression::generateJitCode() {
268 1944 : CodeHolder code;
269 : auto & runtime(*static_cast<asmjit::JitRuntime*>(runtimeptr.get()));
270 1944 : code.init(runtime.getCodeInfo());
271 1944 : X86Compiler c(&code);
272 1944 : c.addFunc(FuncSignature0<double>());
273 1944 : vector<X86Xmm> workspaceVar(workspace.size());
274 14652 : for (int i = 0; i < (int) workspaceVar.size(); i++)
275 12708 : workspaceVar[i] = c.newXmmSd();
276 : X86Gp argsPointer = c.newIntPtr();
277 1944 : c.mov(argsPointer, imm_ptr(&argValues[0]));
278 :
279 : // Load the arguments into variables.
280 :
281 3986 : for (set<string>::const_iterator iter = variableNames.begin(); iter != variableNames.end(); ++iter) {
282 : map<string, int>::iterator index = variableIndices.find(*iter);
283 : X86Gp variablePointer = c.newIntPtr();
284 4084 : c.mov(variablePointer, imm_ptr(&getVariableReference(index->first)));
285 2042 : c.movsd(workspaceVar[index->second], x86::ptr(variablePointer, 0, 0));
286 : }
287 :
288 : // Make a list of all constants that will be needed for evaluation.
289 :
290 1944 : vector<int> operationConstantIndex(operation.size(), -1);
291 12610 : for (int step = 0; step < (int) operation.size(); step++) {
292 : // Find the constant value (if any) used by this operation.
293 :
294 10666 : Operation& op = *operation[step];
295 : double value;
296 10666 : if (op.getId() == Operation::CONSTANT)
297 330 : value = dynamic_cast<Operation::Constant&>(op).getValue();
298 10336 : else if (op.getId() == Operation::ADD_CONSTANT)
299 850 : value = dynamic_cast<Operation::AddConstant&>(op).getValue();
300 9486 : else if (op.getId() == Operation::MULTIPLY_CONSTANT)
301 2884 : value = dynamic_cast<Operation::MultiplyConstant&>(op).getValue();
302 6602 : else if (op.getId() == Operation::RECIPROCAL)
303 148 : value = 1.0;
304 6454 : else if (op.getId() == Operation::STEP)
305 74 : value = 1.0;
306 6380 : else if (op.getId() == Operation::DELTA)
307 40 : value = 1.0/0.0;
308 6340 : else if (op.getId() == Operation::NANDELTA)
309 6 : value = std::numeric_limits<double>::quiet_NaN();
310 : else
311 6334 : continue;
312 :
313 : // See if we already have a variable for this constant.
314 :
315 9206 : for (int i = 0; i < (int) constants.size(); i++)
316 5422 : if (value == constants[i]) {
317 548 : operationConstantIndex[step] = i;
318 548 : break;
319 : }
320 4332 : if (operationConstantIndex[step] == -1) {
321 3784 : operationConstantIndex[step] = constants.size();
322 3784 : constants.push_back(value);
323 : }
324 : }
325 :
326 : // Load constants into variables.
327 :
328 1944 : vector<X86Xmm> constantVar(constants.size());
329 1944 : if (constants.size() > 0) {
330 : X86Gp constantsPointer = c.newIntPtr();
331 1626 : c.mov(constantsPointer, imm_ptr(&constants[0]));
332 5410 : for (int i = 0; i < (int) constants.size(); i++) {
333 3784 : constantVar[i] = c.newXmmSd();
334 3784 : c.movsd(constantVar[i], x86::ptr(constantsPointer, 8*i, 0));
335 : }
336 : }
337 :
338 : // Evaluate the operations.
339 :
340 12610 : for (int step = 0; step < (int) operation.size(); step++) {
341 10666 : Operation& op = *operation[step];
342 10666 : vector<int> args = arguments[step];
343 10666 : if (args.size() == 1) {
344 : // One or more sequential arguments. Fill out the list.
345 :
346 9786 : for (int i = 1; i < op.getNumArguments(); i++)
347 1512 : args.push_back(args[0]+i);
348 : }
349 :
350 : // Generate instructions to execute this operation.
351 :
352 10666 : switch (op.getId()) {
353 330 : case Operation::CONSTANT:
354 330 : c.movsd(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
355 10464 : break;
356 : case Operation::ADD:
357 1140 : c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
358 1140 : c.addsd(workspaceVar[target[step]], workspaceVar[args[1]]);
359 : break;
360 : case Operation::SUBTRACT:
361 862 : c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
362 862 : c.subsd(workspaceVar[target[step]], workspaceVar[args[1]]);
363 : break;
364 : case Operation::MULTIPLY:
365 1736 : c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
366 1736 : c.mulsd(workspaceVar[target[step]], workspaceVar[args[1]]);
367 : break;
368 : case Operation::DIVIDE:
369 122 : c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
370 122 : c.divsd(workspaceVar[target[step]], workspaceVar[args[1]]);
371 : break;
372 : case Operation::POWER:
373 4 : generateTwoArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], workspaceVar[args[1]], pow);
374 : break;
375 132 : case Operation::NEGATE:
376 132 : c.xorps(workspaceVar[target[step]], workspaceVar[target[step]]);
377 132 : c.subsd(workspaceVar[target[step]], workspaceVar[args[0]]);
378 : break;
379 : case Operation::SQRT:
380 126 : c.sqrtsd(workspaceVar[target[step]], workspaceVar[args[0]]);
381 : break;
382 : case Operation::EXP:
383 56 : generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], exp);
384 : break;
385 : case Operation::LOG:
386 2 : generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], log);
387 : break;
388 : case Operation::SIN:
389 506 : generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], sin);
390 : break;
391 : case Operation::COS:
392 798 : generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], cos);
393 : break;
394 : case Operation::TAN:
395 4 : generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], tan);
396 : break;
397 : case Operation::ASIN:
398 2 : generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], asin);
399 : break;
400 : case Operation::ACOS:
401 2 : generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], acos);
402 : break;
403 : case Operation::ATAN:
404 2 : generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], atan);
405 : break;
406 : case Operation::ATAN2:
407 8 : generateTwoArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], workspaceVar[args[1]], atan2);
408 : break;
409 : case Operation::SINH:
410 4 : generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], sinh);
411 : break;
412 : case Operation::COSH:
413 4 : generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], cosh);
414 : break;
415 : case Operation::TANH:
416 6 : generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], tanh);
417 : break;
418 : case Operation::ASINH:
419 2 : generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], asinh);
420 : break;
421 : case Operation::ACOSH:
422 2 : generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], acosh);
423 : break;
424 : case Operation::ATANH:
425 2 : generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], atanh);
426 : break;
427 74 : case Operation::STEP:
428 74 : c.xorps(workspaceVar[target[step]], workspaceVar[target[step]]);
429 74 : c.cmpsd(workspaceVar[target[step]], workspaceVar[args[0]], imm(18)); // Comparison mode is _CMP_LE_OQ = 18
430 74 : c.andps(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
431 : break;
432 40 : case Operation::DELTA:
433 40 : c.xorps(workspaceVar[target[step]], workspaceVar[target[step]]);
434 40 : c.cmpsd(workspaceVar[target[step]], workspaceVar[args[0]], imm(16)); // Comparison mode is _CMP_EQ_OS = 16
435 40 : c.andps(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
436 : break;
437 6 : case Operation::NANDELTA:
438 6 : c.xorps(workspaceVar[target[step]], workspaceVar[target[step]]);
439 6 : c.cmpsd(workspaceVar[target[step]], workspaceVar[args[0]], imm(16)); // Comparison mode is _CMP_EQ_OS = 16
440 6 : c.andps(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
441 : break;
442 : case Operation::SQUARE:
443 514 : c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
444 514 : c.mulsd(workspaceVar[target[step]], workspaceVar[args[0]]);
445 : break;
446 : case Operation::CUBE:
447 66 : c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
448 66 : c.mulsd(workspaceVar[target[step]], workspaceVar[args[0]]);
449 66 : c.mulsd(workspaceVar[target[step]], workspaceVar[args[0]]);
450 : break;
451 148 : case Operation::RECIPROCAL:
452 148 : c.movsd(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
453 148 : c.divsd(workspaceVar[target[step]], workspaceVar[args[0]]);
454 : break;
455 : case Operation::ADD_CONSTANT:
456 850 : c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
457 850 : c.addsd(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
458 : break;
459 : case Operation::MULTIPLY_CONSTANT:
460 2884 : c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
461 2884 : c.mulsd(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
462 : break;
463 : case Operation::ABS:
464 26 : generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], fabs);
465 : break;
466 : case Operation::FLOOR:
467 2 : generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], floor);
468 : break;
469 : case Operation::CEIL:
470 2 : generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], ceil);
471 : break;
472 : default:
473 : // Just invoke evaluateOperation().
474 :
475 444 : for (int i = 0; i < (int) args.size(); i++)
476 242 : c.movsd(x86::ptr(argsPointer, 8*i, 0), workspaceVar[args[i]]);
477 : X86Gp fn = c.newIntPtr();
478 202 : c.mov(fn, imm_ptr((void*) evaluateOperation));
479 202 : CCFuncCall* call = c.call(fn, FuncSignature2<double, Operation*, double*>());
480 202 : call->setArg(0, imm_ptr(&op));
481 202 : call->setArg(1, imm_ptr(&argValues[0]));
482 202 : call->setRet(0, workspaceVar[target[step]]);
483 : }
484 : }
485 1944 : c.ret(workspaceVar[workspace.size()-1]);
486 1944 : c.endFunc();
487 1944 : c.finalize();
488 1944 : runtime.add(&jitCode, &code);
489 1944 : }
490 :
491 1422 : void generateSingleArgCall(X86Compiler& c, X86Xmm& dest, X86Xmm& arg, double (*function)(double)) {
492 : X86Gp fn = c.newIntPtr();
493 1422 : c.mov(fn, imm_ptr((void*) function));
494 1422 : CCFuncCall* call = c.call(fn, FuncSignature1<double, double>());
495 : call->setArg(0, arg);
496 : call->setRet(0, dest);
497 1422 : }
498 :
499 12 : void generateTwoArgCall(X86Compiler& c, X86Xmm& dest, X86Xmm& arg1, X86Xmm& arg2, double (*function)(double, double)) {
500 : X86Gp fn = c.newIntPtr();
501 12 : c.mov(fn, imm_ptr((void*) function));
502 24 : CCFuncCall* call = c.call(fn, FuncSignature2<double, double, double>());
503 : call->setArg(0, arg1);
504 : call->setArg(1, arg2);
505 : call->setRet(0, dest);
506 12 : }
507 :
508 : #endif
509 : }
|