29 static_assert(
sizeof(
char*) ==
sizeof(
size_t),
"Expect to fit size_t in char*");
30 s[0] =
reinterpret_cast<char*
>(block->
data());
39 std::cerr <<
"Running op at " << pc << std::endl;
42 const std::pair<OpF, int>& op =
ops[pc];
43 int* opCurr = &
opData[0] + op.second;
44 pc += op.first(opCurr, fp, str,
callStack);
49 std::cerr <<
"---- ops ----------------------" << std::endl;
50 for (
size_t i = 0; i <
ops.size(); i++) {
52 const char* name =
"";
53 if (dladdr((
void*)
ops[i].first, &info)) name = info.dli_sname;
54 fprintf(stderr,
"%s %s %p (", pc == (
int)i ?
"-->" :
" ", name,
ops[i].first);
55 int nextGuy = (i ==
ops.size() - 1 ?
opData.size() :
ops[i + 1].second);
56 for (
int k =
ops[i].second; k < nextGuy; k++) {
57 fprintf(stderr,
" %d",
opData[k]);
59 fprintf(stderr,
")\n");
61 std::cerr <<
"---- opdata ----------------------" << std::endl;
62 for (
size_t k = 0; k <
opData.size(); k++) {
63 std::cerr <<
"opData[" << k <<
"]= " <<
opData[k] << std::endl;
66 std::cerr <<
"----- fp --------------------------" << std::endl;
67 for (
size_t k = 0; k <
d.size(); k++) {
68 std::cerr <<
"fp[" << k <<
"]= " <<
d[k] << std::endl;
71 std::cerr <<
"---- str ----------------------" << std::endl;
72 std::cerr <<
"s[0] reserved for datablock = " <<
reinterpret_cast<size_t>(
s[0]) << std::endl;
73 std::cerr <<
"s[1] is indirectIndex = " <<
reinterpret_cast<size_t>(
s[1]) << std::endl;
74 for (
size_t k = 2; k <
s.size(); k++) {
75 std::cerr <<
"s[" << k <<
"]= 0x" <<
s[k];
76 if (s[k]) std::cerr <<
" '" << s[k][0] << s[k][1] << s[k][2] << s[k][3] <<
"...'";
77 std::cerr << std::endl;
87 template <
char c,
template <
char c1,
int d>
class T>
123 assert(
false &&
"Invalid dynamic parameter (not supported template)");
132 template <
char op,
int d>
134 static double niceMod(
double a,
double b) {
135 if (b == 0)
return 0;
136 return a - floor(a / b) *
b;
139 static int f(
int* opData,
double* fp,
char** c, std::vector<int>& callStack) {
140 double* in1 = fp + opData[0];
141 double* in2 = fp + opData[1];
142 double* out = fp + opData[2];
144 for (
int k = 0; k < d; k++) {
147 *out = (*in1) + (*in2);
150 *out = (*in1) - (*in2);
153 *out = (*in1) * (*in2);
156 *out = (*in1) / (*in2);
159 *out = niceMod(*in1, *in2);
162 *out =
pow(*in1, *in2);
166 *out = (*in1) < (*in2);
169 *out = (*in1) > (*in2);
172 *out = (*in1) <= (*in2);
175 *out = (*in1) >= (*in2);
178 *out = (*in1) && (*in2);
181 *out = (*in1) || (*in2);
195 template <
char op,
int d>
197 static int f(
int* opData,
double* fp,
char** c, std::vector<int>& callStack) {
198 double* in = fp + opData[0];
199 double* out = fp + opData[1];
200 for (
int k = 0; k < d; k++) {
224 static int f(
int* opData,
double* fp,
char** c, std::vector<int>& callStack) {
225 int tuple = opData[0];
226 int subscript = int(fp[opData[1]]);
228 if (subscript >= d || subscript < 0)
231 fp[out] = fp[tuple + subscript];
239 static int f(
int* opData,
double* fp,
char** c, std::vector<int>& callStack) {
241 for (
int k = 0; k < d; k++) {
242 fp[out + k] = fp[opData[k]];
251 static int f(
int* opData,
double* fp,
char** c, std::vector<int>& callStack) {
254 for (
int k = 0; k < d; k++) {
255 fp[out + k] = fp[in + k];
263 static int f(
int* opData,
double* fp,
char** c, std::vector<int>& callStack) {
272 struct CondJmpRelativeIfFalse {
273 static int f(
int* opData,
double* fp,
char** c, std::vector<int>& callStack) {
274 bool cond = (bool)fp[opData[0]];
283 struct CondJmpRelativeIfTrue {
284 static int f(
int* opData,
double* fp,
char** c, std::vector<int>& callStack) {
285 bool cond = (bool)fp[opData[0]];
295 static int f(
int* opData,
double* fp,
char** c, std::vector<int>& callStack) {
return opData[0]; }
300 static int f(
int* opData,
double* fp,
char** c, std::vector<int>& callStack) {
301 ExprVarRef* ref =
reinterpret_cast<ExprVarRef*
>(c[opData[0]]);
302 ref->eval(fp + opData[1]);
309 struct EvalVarBlock {
310 static int f(
int* opData,
double* fp,
char** c, std::vector<int>& callStack) {
312 double* basePointer =
reinterpret_cast<double*
>(c[0]) + opData[0];
313 double* destPointer = fp + opData[1];
314 for (
int i = 0; i < dim; i++) destPointer[i] = basePointer[i];
321 template <
char uniform,
int dim>
322 struct EvalVarBlockIndirect {
323 static int f(
int* opData,
double* fp,
char** c, std::vector<int>& callStack) {
325 int stride = opData[2];
326 int outputVarBlockOffset = opData[0];
327 int destIndex = opData[1];
328 size_t indirectIndex =
reinterpret_cast<size_t>(c[1]);
329 double* basePointer =
330 reinterpret_cast<double**
>(c[0])[outputVarBlockOffset] + (uniform ? 0 : (stride * indirectIndex));
331 double* destPointer = fp + destIndex;
332 for (
int i = 0; i < dim; i++) destPointer[i] = basePointer[i];
342 template <
char op,
int d>
344 static int f(
int* opData,
double* fp,
char** c, std::vector<int>& callStack) {
346 double* in0 = fp + opData[0];
347 double* in1 = fp + opData[1];
348 double* out = fp + opData[2];
349 for (
int k = 0; k < d; k++) {
352 result &= (*in0) == (*in1);
355 result &= (*in0) != (*in1);
369 struct CompareEqOp<op, 3> {
370 static int f(
int* opData,
double* fp,
char** c, std::vector<int>& callStack) {
371 bool eq = fp[opData[0]] == fp[opData[1]] && fp[opData[0] + 1] == fp[opData[1] + 1] &&
372 fp[opData[0] + 2] == fp[opData[1] + 2];
373 if (op ==
'=') fp[opData[2]] = eq;
374 if (op ==
'!') fp[opData[2]] = !eq;
379 template <
char op,
int d>
380 struct StrCompareEqOp {
382 static int f(
int* opData,
double* fp,
char** c, std::vector<int>& callStack) {
385 fp[opData[2]] = strcmp(c[opData[0]], c[opData[1]]) == 0;
388 fp[opData[2]] = strcmp(c[opData[0]], c[opData[1]]) == 0;
397 int ProcedureReturn(
int* opData,
double* fp,
char** c, std::vector<int>& callStack) {
398 int newPC = callStack.back();
399 callStack.pop_back();
400 return newPC - opData[0];
405 int ProcedureCall(
int* opData,
double* fp,
char** c, std::vector<int>& callStack) {
406 callStack.push_back(opData[0]);
415 int basePC = interpreter->
nextPC();
417 interpreter->
addOp(ProcedureReturn);
420 interpreter->
endOp(
false);
427 std::vector<int> operands;
428 for (
int c = 0; c < callerNode->
numChildren(); c++) {
433 if (callerNode->
promote(c) != 0) {
435 interpreter->
addOp(getTemplatizedOp<Promote>(callerNode->
promote(c)));
439 interpreter->
endOp();
441 interpreter->
addOp(getTemplatizedOp<AssignOp>(child->
type().
dim()));
444 interpreter->
endOp();
450 operands.push_back(operand);
456 outoperand = interpreter->
allocPtr();
460 int basePC = interpreter->
nextPC();
461 interpreter->
addOp(ProcedureCall);
462 int returnAddress = interpreter->
addOperand(0);
464 interpreter->
endOp(
false);
466 interpreter->
opData[returnAddress] = interpreter->
nextPC();
469 interpreter->
addOp(getTemplatizedOp<AssignOp>(callerNode->
type().
dim()));
472 interpreter->
endOp();
483 int loc = interpreter->
allocFP(1);
484 interpreter->
d[loc] =
value();
490 interpreter->
s[loc] =
const_cast<char*
>(
_str.c_str());
495 std::vector<int> locs;
504 interpreter->
endOp();
510 int dim0 = child0->
type().
dim(), dim1 = child1->type().dim(), dimout =
type().
dim();
512 int op1 = child1->buildInterpreter(interpreter);
514 if (dim0 != dimout) {
515 interpreter->
addOp(getTemplatizedOp<Promote>(dimout));
516 int promoteOp0 = interpreter->
allocFP(dimout);
520 interpreter->
endOp();
522 if (dim1 != dimout) {
523 interpreter->
addOp(getTemplatizedOp<Promote>(dimout));
524 int promoteOp1 = interpreter->
allocFP(dimout);
528 interpreter->
endOp();
534 interpreter->
addOp(getTemplatizedOp2<'+', BinaryOp>(dimout));
537 interpreter->
addOp(getTemplatizedOp2<'-', BinaryOp>(dimout));
540 interpreter->
addOp(getTemplatizedOp2<'*', BinaryOp>(dimout));
543 interpreter->
addOp(getTemplatizedOp2<'/', BinaryOp>(dimout));
546 interpreter->
addOp(getTemplatizedOp2<'^', BinaryOp>(dimout));
549 interpreter->
addOp(getTemplatizedOp2<'%', BinaryOp>(dimout));
554 int op2 = interpreter->
allocFP(dimout);
558 interpreter->
endOp();
570 interpreter->
addOp(getTemplatizedOp2<'-', UnaryOp>(dimout));
573 interpreter->
addOp(getTemplatizedOp2<'~', UnaryOp>(dimout));
576 interpreter->
addOp(getTemplatizedOp2<'!', UnaryOp>(dimout));
581 int op1 = interpreter->
allocFP(dimout);
584 interpreter->
endOp();
591 int dimin = child0->
type().
dim();
593 int op1 = child1->buildInterpreter(interpreter);
594 int op2 = interpreter->
allocFP(1);
596 interpreter->
addOp(getTemplatizedOp<Subscript>(dimin));
600 interpreter->
endOp();
607 Interpreter::VarToLoc::iterator i = interpreter->
varToLoc.find(
var);
608 if (i != interpreter->
varToLoc.end())
return i->second;
609 else throw std::runtime_error(
"Unallocated variable encountered.");
614 int dim = type.
dim();
615 destLoc = interpreter->
allocFP(dim);
618 if (
const auto* blockVarRef = dynamic_cast<const VarBlockCreator::Ref*>(
var)) {
620 if (blockVarRef->type().isLifetimeUniform())
621 interpreter->
addOp(getTemplatizedOp2<1, EvalVarBlockIndirect>(type.
dim()));
623 interpreter->
addOp(getTemplatizedOp2<0, EvalVarBlockIndirect>(type.
dim()));
624 interpreter->
addOperand(blockVarRef->offset());
626 interpreter->
addOperand(blockVarRef->stride());
627 interpreter->
endOp();
629 int varRefLoc = interpreter->
allocPtr();
631 interpreter->
s[varRefLoc] =
const_cast<char*
>(
reinterpret_cast<const char*
>(
var));
634 interpreter->
endOp();
649 assert(loc != -1 &&
"Invalid type found");
653 if (child0Type.
isFP()) {
654 interpreter->
addOp(getTemplatizedOp<AssignOp>(child0Type.
dim()));
658 assert(
false &&
"Invalid desired assign type");
663 interpreter->
endOp();
669 int destDim=varDest->
type().
dim();
670 if(destDim!=varSource->
type().
dim()){
671 assert(varSource->
type().
dim()==1);
672 interpreter->
addOp(getTemplatizedOp<Promote>(destDim));
674 interpreter->
addOp(getTemplatizedOp<AssignOp>(destDim));
678 interpreter->
endOp();
683 interpreter->
endOp();
685 assert(
false &&
"failed to promote invalid type");
691 int basePC = interpreter->
nextPC();
697 for(
auto&
it:merges){
699 if(finalVar->
valid()){
708 interpreter->
endOp();
712 for(
auto&
it:merges){
714 if(finalVar->
valid()){
720 interpreter->
endOp();
723 int child2PC = interpreter->
nextPC();
725 for(
auto&
it:merges){
727 if(finalVar->
valid()){
733 interpreter->
opData[destFalse] = child2PC - basePC;
734 interpreter->
opData[destEnd] = interpreter->
nextPC() - (child2PC - 1);
741 assert(
type().dim() == 1 &&
type().isFP());
743 if (
_op ==
'&' ||
_op ==
'|') {
747 int op2 = interpreter->
allocFP(1);
751 int basePC = (interpreter->
nextPC());
755 interpreter->
endOp();
757 int op1 = child1->buildInterpreter(interpreter);
759 interpreter->
addOp(
_op ==
'&' ? getTemplatizedOp2<'&', BinaryOp>(1) : getTemplatizedOp2<'|', BinaryOp>(1));
763 interpreter->
endOp();
766 interpreter->
endOp();
769 int falseConditionPC = interpreter->
nextPC();
773 interpreter->
endOp();
776 interpreter->
opData[destFalse] = falseConditionPC - basePC;
777 interpreter->
opData[destEnd] = interpreter->
nextPC() - (falseConditionPC - 1);
784 int op1 = child1->buildInterpreter(interpreter);
790 interpreter->
addOp(getTemplatizedOp2<'>
', BinaryOp>(1));
793 interpreter->addOp(getTemplatizedOp2<'l
', BinaryOp>(1));
796 interpreter->addOp(getTemplatizedOp2<'g
', BinaryOp>(1));
799 assert(false); // interpreter->addOp(getTemplatizedOp2<'&
',BinaryOp>(1));break;
801 assert(false); // interpreter->addOp(getTemplatizedOp2<'|
',BinaryOp>(1));break;
805 int op2 = interpreter->allocFP(1);
806 interpreter->addOperand(op0);
807 interpreter->addOperand(op1);
808 interpreter->addOperand(op2);
809 interpreter->endOp();
814 int ExprPrototypeNode::buildInterpreter(Interpreter* interpreter) const {
816 _interpreterOps.clear();
817 for (int c = 0; c < numChildren(); c++) {
818 if (const ExprVarNode* childVarNode = dynamic_cast<const ExprVarNode*>(child(c))) {
819 ExprType childType = childVarNode->type();
820 if (childType.isFP()) {
821 int operand = interpreter->allocFP(childType.dim());
822 _interpreterOps.push_back(operand);
823 interpreter->varToLoc[childVarNode->localVar()] = operand;
828 child(c)->buildInterpreter(interpreter);
830 // make sure we have a slot in our global activation record for the variables!
835 int ExprCompareEqNode::buildInterpreter(Interpreter* interpreter) const {
836 const ExprNode* child0 = child(0), *child1 = child(1);
837 int op0 = child0->buildInterpreter(interpreter);
838 int op1 = child1->buildInterpreter(interpreter);
840 if (child0->type().isFP()) {
841 int dim0 = child0->type().dim(), dim1 = child1->type().dim();
842 int dimCompare = std::max(dim0, dim1);
843 if (dimCompare > 1) {
845 interpreter->addOp(getTemplatizedOp<Promote>(dim1));
846 int promotedOp0 = interpreter->allocFP(dim1);
847 interpreter->addOperand(op0);
848 interpreter->addOperand(promotedOp0);
849 interpreter->endOp();
853 interpreter->addOp(getTemplatizedOp<Promote>(dim0));
854 int promotedOp1 = interpreter->allocFP(dim0);
855 interpreter->addOperand(op1);
856 interpreter->addOperand(promotedOp1);
857 interpreter->endOp();
862 interpreter->addOp(getTemplatizedOp2<'=
', CompareEqOp>(dimCompare));
864 interpreter->addOp(getTemplatizedOp2<'!
', CompareEqOp>(dimCompare));
866 assert(false && "Invalid operation");
867 } else if (child0->type().isString()) {
869 interpreter->addOp(getTemplatizedOp2<'=
', StrCompareEqOp>(1));
871 interpreter->addOp(getTemplatizedOp2<'!
', StrCompareEqOp>(1));
873 assert(false && "Invalid operation");
875 assert(false && "Invalid type for comparison");
876 int op2 = interpreter->allocFP(1);
877 interpreter->addOperand(op0);
878 interpreter->addOperand(op1);
879 interpreter->addOperand(op2);
880 interpreter->endOp();
884 int ExprCondNode::buildInterpreter(Interpreter* interpreter) const {
886 // TODO: handle strings!
887 int dimout = type().dim();
890 int condOp = child(0)->buildInterpreter(interpreter);
891 int basePC = (interpreter->nextPC());
892 interpreter->addOp(CondJmpRelativeIfFalse::f);
893 interpreter->addOperand(condOp);
894 int destFalse = interpreter->addOperand(0);
895 interpreter->endOp();
897 // true way of working
898 int op1 = child(1)->buildInterpreter(interpreter);
900 interpreter->addOp(getTemplatizedOp<AssignOp>(dimout));
901 else if (type().isString())
902 interpreter->addOp(AssignStrOp::f);
905 interpreter->addOperand(op1);
906 int dataOutTrue = interpreter->addOperand(-1);
907 interpreter->endOp(false);
909 // jump past false way of working
910 interpreter->addOp(JmpRelative::f);
911 int destEnd = interpreter->addOperand(0);
912 interpreter->endOp();
914 // record start of false condition
915 int child2PC = interpreter->nextPC();
917 // false way of working
918 int op2 = child(2)->buildInterpreter(interpreter);
920 interpreter->addOp(getTemplatizedOp<AssignOp>(dimout));
921 else if (type().isString())
922 interpreter->addOp(AssignStrOp::f);
925 interpreter->addOperand(op2);
926 int dataOutFalse = interpreter->addOperand(-1);
927 interpreter->endOp(false);
929 // patch up relative jumps
930 interpreter->opData[destFalse] = child2PC - basePC;
931 interpreter->opData[destEnd] = interpreter->nextPC() - (child2PC - 1);
935 opOut = interpreter->allocFP(type().dim());
936 else if (type().isString())
937 opOut = interpreter->allocPtr();
941 // patch outputs on assigns in each condition
942 interpreter->opData[dataOutTrue] = opOut;
943 interpreter->opData[dataOutFalse] = opOut;
948 int ExprBlockNode::buildInterpreter(Interpreter* interpreter) const {
949 assert(numChildren() == 2);
950 child(0)->buildInterpreter(interpreter);
951 return child(1)->buildInterpreter(interpreter);
954 int ExprModuleNode::buildInterpreter(Interpreter* interpreter) const {
956 for (int c = 0; c < numChildren(); c++) {
957 if (c == numChildren() - 1) interpreter->setPCStart(interpreter->nextPC());
958 lastIdx = child(c)->buildInterpreter(interpreter);
std::vector< int > callStack
int allocFP(int n)
! Allocate a floating point set of data of dimension n
virtual int buildInterpreter(Interpreter *interpreter) const
builds an interpreter. Returns the location index for the evaluated data
A thread local evaluation context. Just allocate and fill in with data.
static Interpreter::OpF getTemplatizedOp2(int i)
Return the function f encapsulated in class T for the dynamic i converted to a static d...
const ExprType & type() const
The type of the node.
int nextPC()
Return the position that the next instruction will be placed at.
virtual int buildInterpreter(Interpreter *interpreter) const
builds an interpreter. Returns the location index for the evaluated data
virtual int buildInterpreter(Interpreter *interpreter) const
builds an interpreter. Returns the location index for the evaluated data
std::vector< char * > s
constant and evaluated pointer data
char ** data()
Raw data of the data block pointer (used by compiler)
bool isFP() const
Direct is predicate checks.
virtual int buildInterpreter(Interpreter *interpreter) const
builds an interpreter. Returns the location index for the evaluated data
ExprType type() const
returns type of the variable
void copyVarToPromotedPosition(Interpreter *interpreter, ExprLocalVar *varSource, ExprLocalVar *varDest)
void print(int pc=-1) const
Debug by printing program.
virtual int buildInterpreter(Interpreter *interpreter) const
builds an interpreter. Returns the location index for the evaluated data
int buildInterpreter(Interpreter *interpreter) const
Allocates variable for interpreter.
with numParticles numAttributes A variable block contains variable names and types but doesn t care what the values are< pre > void f(const std::string &s, MyParticleData *p, int outputDim=3)
int allocPtr()
Allocate a pointer location (can be anything, but typically space for char*)
virtual int buildInterpreter(Interpreter *interpreter) const
builds an interpreter. Returns the location index for the evaluated data
ExprLocalVar reference, all local variables in seexpr are subclasses of this or this itself...
Node that calls a function.
std::vector< std::pair< OpF, int > > ops
< br > pow($a, 0.5)+$b< br >< br ></div > External variables can also be overridden by local assignment. 
const ExprVarRef * var() const
void eval(VarBlock *varBlock, bool debug=false)
Evaluate program.
int addOperand(int param)
! Adds an operand. Note this should be done after doing the addOp!
virtual int buildInterpreter(Interpreter *interpreter) const
builds an interpreter. Returns the location index for the evaluated data
int addOp(OpF op)
! adds an operator to the program (pointing to the data at the current location)
std::vector< double > d
Double data (constants and evaluated)
virtual int buildInterpreter(Interpreter *interpreter) const
builds an interpreter. Returns the location index for the evaluated data
int numChildren() const
Number of children.
void endOp(bool execute=true)
char _op
_op '<' less-than, 'l' less-than-eq, '>' greater-than, 'g' greater-than-eq
int buildInterpreterForCall(const ExprFuncNode *callerNode, Interpreter *interpreter) const
Build interpreter if we are called.
int indirectIndex
indirect index to add to pointer based data
std::vector< int > opData
Ooperands to op.
virtual int buildInterpreter(Interpreter *interpreter) const
builds an interpreter. Returns the location index for the evaluated data
ExprLocalVar join (merge) references. Remembers which variables are possible assigners to this...
const ExprNode * child(size_t i) const
Get 0 indexed child.
virtual ExprType type() const
returns (current) type
you may not use this file except in compliance with the License and the following modification to it
virtual int buildInterpreter(Interpreter *interpreter) const
builds an interpreter. Returns the location index for the evaluated data
Defined as a *alpha b *alpha< br ></div >< br > float< b > float a
abstract class for implementing variable references
std::vector< std::pair< std::string, ExprLocalVarPhi * > > & merge(size_t index)
const ExprPrototypeNode * prototype() const
TODO: Accessor for prototype (probably not needed when we use prep right)
int(* OpF)(int *, double *, char **, std::vector< int > &)
Op function pointer arguments are (int* currOpData,double* currD,char** c,std::stack<int>& callStacku...
virtual int buildInterpreter(Interpreter *interpreter) const
builds an interpreter. Returns the location index for the evaluated data
int buildInterpreter(Interpreter *interpreter) const
Build the interpreter.