22 double* fp =
d.data();
23 char** str =
s.data();
30 block->
d.resize(
d.size());
32 memcpy(fp,
d.data(),
d.size() *
sizeof(
double));
35 block->
s.resize(
s.size());
36 str = block->
s.data();
37 memcpy(str,
s.data(),
s.size() *
sizeof(
char*));
41 str[0] =
reinterpret_cast<char*
>(block->
data());
42 str[1] =
reinterpret_cast<char*
>(
static_cast<size_t>(block->
indirectIndex));
46 int end =
static_cast<int>(
ops.size());
49 std::cerr <<
"Running op at " << pc << std::endl;
52 const std::pair<OpF, int>& op =
ops[pc];
53 int* opCurr = &
opData[0] + op.second;
54 pc += op.first(opCurr, fp, str,
callStack);
60 std::cerr <<
"---- ops ----------------------" << std::endl;
61 for (
size_t i = 0; i <
ops.size(); i++) {
62 const char *name =
"";
65 if (dladdr((
void *)
ops[i].first, &info))
66 name = info.dli_sname;
68 fprintf(stderr,
"%s %s %p (", pc == (
int)i ?
"-->" :
" ", name, (
void *)
ops[i].first);
69 int nextGuy = (i ==
ops.size() - 1 ?
static_cast<int>(
opData.size()) :
ops[i + 1].second);
70 for (
int k =
ops[i].second; k < nextGuy; k++) {
71 fprintf(stderr,
" %d",
opData[k]);
73 fprintf(stderr,
")\n");
75 std::cerr <<
"---- opdata ----------------------" << std::endl;
76 for (
size_t k = 0; k <
opData.size(); k++) {
77 std::cerr <<
"opData[" << k <<
"]= " <<
opData[k] << std::endl;
79 std::cerr <<
"----- fp --------------------------" << std::endl;
80 for (
size_t k = 0; k <
d.size(); k++) {
81 std::cerr <<
"fp[" << k <<
"]= " <<
d[k] << std::endl;
83 std::cerr <<
"---- str ----------------------" << std::endl;
84 std::cerr <<
"s[0] reserved for datablock = " <<
reinterpret_cast<size_t>(
s[0]) << std::endl;
85 std::cerr <<
"s[1] is indirectIndex = " <<
reinterpret_cast<size_t>(
s[1]) << std::endl;
86 for (
size_t k = 2; k <
s.size(); k++) {
87 std::cerr <<
"s[" << k <<
"]= " << (
void *)(
s[k]);
89 fprintf(stderr,
" '%c%c%c%c...'",
s[k][0],
s[k][1],
s[k][2],
s[k][3]);
91 std::cerr << std::endl;
102 template <
char c,
template <
char c1,
int d>
class T>
138 assert(
false &&
"Invalid dynamic parameter (not supported template)");
147 struct BinaryStringOp {
148 static int f(
int* opData,
double*,
char** c, std::vector<int>&) {
150 char*& out = *(
char**)c[opData[0]];
151 char* in1 = c[opData[1]];
152 char* in2 = c[opData[2]];
157 size_t len1 = strlen(in1);
158 size_t len2 = strlen(in2);
159 if (out ==
nullptr || len1 + len2 + 1 > strlen(out))
162 out =
new char [len1 + len2 + 1];
166 memset(out, 0, len1 + len2 + 1);
170 strcat(out + len1, in2);
171 out[len1 + len2] =
'\0';
181 template <
char op,
int d>
183 static double niceMod(
double a,
double b) {
184 if (b == 0)
return 0;
185 return a -
floor(a / b) * b;
188 static int f(
int* opData,
double* fp,
char**, std::vector<int>& ) {
189 double* in1 = fp + opData[0];
190 double* in2 = fp + opData[1];
191 double* out = fp + opData[2];
193 for (
int k = 0; k < d; k++) {
196 *out = (*in1) + (*in2);
199 *out = (*in1) - (*in2);
202 *out = (*in1) * (*in2);
205 *out = (*in1) / (*in2);
208 *out = niceMod(*in1, *in2);
211 *out = pow(*in1, *in2);
215 *out = (*in1) < (*in2);
218 *out = (*in1) > (*in2);
221 *out = (*in1) <= (*in2);
224 *out = (*in1) >= (*in2);
227 *out = (*in1) && (*in2);
230 *out = (*in1) || (*in2);
244 template <
char op,
int d>
246 static int f(
int* opData,
double* fp,
char**, std::vector<int>&) {
247 double* in = fp + opData[0];
248 double* out = fp + opData[1];
249 for (
int k = 0; k < d; k++) {
273 static int f(
int* opData,
double* fp,
char**, std::vector<int>&) {
274 int tuple = opData[0];
275 int subscript = int(fp[opData[1]]);
277 if (subscript >= d || subscript < 0)
280 fp[out] = fp[tuple + subscript];
288 static int f(
int* opData,
double* fp,
char**, std::vector<int>&) {
290 for (
int k = 0; k < d; k++) {
291 fp[out + k] = fp[opData[k]];
300 static int f(
int* opData,
double* fp,
char**, std::vector<int>&) {
303 for (
int k = 0; k < d; k++) {
304 fp[out + k] = fp[in + k];
312 static int f(
int* opData,
double*,
char** c, std::vector<int>&) {
321 struct CondJmpRelativeIfFalse {
322 static int f(
int* opData,
double* fp,
char**, std::vector<int>&) {
323 bool cond = (bool)fp[opData[0]];
332 struct CondJmpRelativeIfTrue {
333 static int f(
int* opData,
double* fp,
char**, std::vector<int>&) {
334 bool cond = (bool)fp[opData[0]];
344 static int f(
int* opData,
double*,
char**, std::vector<int>&) {
return opData[0]; }
349 static int f(
int* opData,
double* fp,
char** c, std::vector<int>&) {
350 auto* ref =
reinterpret_cast<ExprVarRef*
>(c[opData[0]]);
351 if (ref->type().isFP()) {
352 ref->eval(fp + opData[1]);
354 ref->eval(
const_cast<const char**
>(c + opData[1]));
362 struct EvalVarBlock {
363 static int f(
int* opData,
double* fp,
char** c, std::vector<int>& callStack) {
365 double* basePointer =
reinterpret_cast<double*
>(c[0]) + opData[0];
366 double* destPointer = fp + opData[1];
367 for (
int i = 0; i < dim; i++) destPointer[i] = basePointer[i];
374 template <
char uniform,
int dim>
375 struct EvalVarBlockIndirect {
376 static int f(
int* opData,
double* fp,
char** c, std::vector<int>&) {
378 int stride = opData[2];
379 int outputVarBlockOffset = opData[0];
380 int destIndex = opData[1];
381 auto indirectIndex =
reinterpret_cast<size_t>(c[1]);
382 double* basePointer =
383 reinterpret_cast<double**
>(c[0])[outputVarBlockOffset] + (uniform ? 0 : (stride * indirectIndex));
384 double* destPointer = fp + destIndex;
385 for (
int i = 0; i < dim; i++) destPointer[i] = basePointer[i];
395 template <
char op,
int d>
397 static int f(
int* opData,
double* fp,
char**, std::vector<int>&) {
399 double* in0 = fp + opData[0];
400 double* in1 = fp + opData[1];
401 double* out = fp + opData[2];
402 for (
int k = 0; k < d; k++) {
405 result &= (*in0) == (*in1);
408 result &= (*in0) != (*in1);
422 struct CompareEqOp<op, 3> {
423 static int f(
int* opData,
double* fp,
char**, std::vector<int>&) {
424 bool eq = fp[opData[0]] == fp[opData[1]] && fp[opData[0] + 1] == fp[opData[1] + 1] &&
425 fp[opData[0] + 2] == fp[opData[1] + 2];
426 if (op ==
'=') fp[opData[2]] = eq;
427 if (op ==
'!') fp[opData[2]] = !eq;
432 template <
char op,
int d>
433 struct StrCompareEqOp {
435 static int f(
int* opData,
double* fp,
char** c, std::vector<int>&) {
438 fp[opData[2]] = strcmp(c[opData[0]], c[opData[1]]) == 0;
441 fp[opData[2]] = strcmp(c[opData[0]], c[opData[1]]) != 0;
450 int ProcedureReturn(
int* opData,
double*,
char**, std::vector<int>& callStack) {
451 int newPC = callStack.back();
452 callStack.pop_back();
453 return newPC - opData[0];
458 int ProcedureCall(
int* opData,
double*,
char**, std::vector<int>& callStack) {
459 callStack.push_back(opData[0]);
468 int basePC = interpreter->
nextPC();
470 interpreter->
addOp(ProcedureReturn);
473 interpreter->
endOp(
false);
480 std::vector<int> operands;
481 for (
int c = 0; c < callerNode->
numChildren(); c++) {
486 if (callerNode->
promote(c) != 0) {
488 interpreter->
addOp(getTemplatizedOp<Promote>(callerNode->
promote(c)));
492 interpreter->
endOp();
497 interpreter->
endOp();
503 operands.push_back(operand);
509 outoperand = interpreter->
allocPtr();
513 int basePC = interpreter->
nextPC();
514 interpreter->
addOp(ProcedureCall);
515 int returnAddress = interpreter->
addOperand(0);
517 interpreter->
endOp(
false);
519 interpreter->
opData[returnAddress] = interpreter->
nextPC();
522 interpreter->
addOp(getTemplatizedOp<AssignOp>(callerNode->
type().
dim()));
525 interpreter->
endOp();
536 int loc = interpreter->
allocFP(1);
537 interpreter->
d[loc] =
value();
543 interpreter->
s[loc] =
const_cast<char*
>(
_str.c_str());
548 std::vector<int> locs;
557 interpreter->
endOp();
564 int dim0 = child0->
type().
dim();
565 int dim1 = child1->
type().
dim();
570 if (dim0 != dimout) {
571 interpreter->
addOp(getTemplatizedOp<Promote>(dimout));
572 int promoteOp0 = interpreter->
allocFP(dimout);
576 interpreter->
endOp();
578 if (dim1 != dimout) {
579 interpreter->
addOp(getTemplatizedOp<Promote>(dimout));
580 int promoteOp1 = interpreter->
allocFP(dimout);
584 interpreter->
endOp();
595 interpreter->
addOp(getTemplatizedOp2<'+', BinaryOp>(dimout));
598 interpreter->
addOp(getTemplatizedOp2<'-', BinaryOp>(dimout));
601 interpreter->
addOp(getTemplatizedOp2<'*', BinaryOp>(dimout));
604 interpreter->
addOp(getTemplatizedOp2<'/', BinaryOp>(dimout));
607 interpreter->
addOp(getTemplatizedOp2<'^', BinaryOp>(dimout));
610 interpreter->
addOp(getTemplatizedOp2<'%', BinaryOp>(dimout));
618 interpreter->
addOp(BinaryStringOp::f);
619 int intermediateOp = interpreter->
allocPtr();
620 interpreter->
s[intermediateOp] = (
char*)(&
_out);
632 op2 = interpreter->
allocFP(dimout);
660 interpreter->
addOp(getTemplatizedOp2<'-', UnaryOp>(dimout));
663 interpreter->
addOp(getTemplatizedOp2<'~', UnaryOp>(dimout));
666 interpreter->
addOp(getTemplatizedOp2<'!', UnaryOp>(dimout));
671 int op1 = interpreter->
allocFP(dimout);
674 interpreter->
endOp();
682 int dimin = child0->
type().
dim();
685 int op2 = interpreter->
allocFP(1);
687 interpreter->
addOp(getTemplatizedOp<Subscript>(dimin));
691 interpreter->
endOp();
699 if (i != interpreter->
varToLoc.end())
702 throw std::runtime_error(
"Unallocated variable encountered.");
708 destLoc = interpreter->
allocFP(dim);
713 if (blockVarRef->type().isLifetimeUniform())
714 interpreter->
addOp(getTemplatizedOp2<1, EvalVarBlockIndirect>(
type.
dim()));
716 interpreter->
addOp(getTemplatizedOp2<0, EvalVarBlockIndirect>(
type.
dim()));
717 interpreter->
addOperand(blockVarRef->offset());
719 interpreter->
addOperand(blockVarRef->stride());
720 interpreter->
endOp();
722 int varRefLoc = interpreter->
allocPtr();
723 interpreter->
addOp(EvalVar::f);
724 interpreter->
s[varRefLoc] =
const_cast<char*
>(
reinterpret_cast<const char*
>(
var));
727 interpreter->
endOp();
735 return interpreter->
varToLoc[
this] =
741 assert(loc != -1 &&
"Invalid type found");
745 if (child0Type.
isFP()) {
746 interpreter->
addOp(getTemplatizedOp<AssignOp>(child0Type.
dim()));
748 interpreter->
addOp(AssignStrOp::f);
750 assert(
false &&
"Invalid desired assign type");
761 int destDim = varDest->
type().
dim();
762 if (destDim != varSource->
type().
dim()) {
763 assert(varSource->
type().
dim() == 1);
764 interpreter->
addOp(getTemplatizedOp<Promote>(destDim));
766 interpreter->
addOp(getTemplatizedOp<AssignOp>(destDim));
770 interpreter->
endOp();
772 interpreter->
addOp(AssignStrOp::f);
775 interpreter->
endOp();
777 assert(
false &&
"failed to promote invalid type");
783 int basePC = interpreter->
nextPC();
789 for (
const auto & it : merges) {
791 if (finalVar->
valid()) {
797 interpreter->
addOp(CondJmpRelativeIfFalse::f);
800 interpreter->
endOp();
804 for (
const auto & it : merges) {
806 if (finalVar->
valid()) {
810 interpreter->
addOp(JmpRelative::f);
812 interpreter->
endOp();
815 int child2PC = interpreter->
nextPC();
817 for (
const auto & it : merges) {
819 if (finalVar->
valid()) {
825 interpreter->
opData[destFalse] = child2PC - basePC;
826 interpreter->
opData[destEnd] = interpreter->
nextPC() - (child2PC - 1);
834 assert(
type().dim() == 1 &&
type().isFP());
836 if (
_op ==
'&' ||
_op ==
'|') {
840 int op2 = interpreter->
allocFP(1);
844 int basePC = (interpreter->
nextPC());
845 interpreter->
addOp(
_op ==
'&' ? CondJmpRelativeIfFalse::f : CondJmpRelativeIfTrue::f);
848 interpreter->
endOp();
852 interpreter->
addOp(
_op ==
'&' ? getTemplatizedOp2<'&', BinaryOp>(1) : getTemplatizedOp2<'|', BinaryOp>(1));
856 interpreter->
endOp();
857 interpreter->
addOp(JmpRelative::f);
859 interpreter->
endOp();
862 int falseConditionPC = interpreter->
nextPC();
863 interpreter->
addOp(AssignOp<1>::f);
866 interpreter->
endOp();
869 interpreter->
opData[destFalse] = falseConditionPC - basePC;
870 interpreter->
opData[destEnd] = interpreter->
nextPC() - (falseConditionPC - 1);
883 interpreter->
addOp(getTemplatizedOp2<'>
', BinaryOp>(1));
886 interpreter->addOp(getTemplatizedOp2<'l
', BinaryOp>(1));
889 interpreter->addOp(getTemplatizedOp2<'g
', BinaryOp>(1));
892 assert(false); // interpreter->addOp(getTemplatizedOp2<'&
',BinaryOp>(1));break;
894 assert(false); // interpreter->addOp(getTemplatizedOp2<'|
',BinaryOp>(1));break;
898 int op2 = interpreter->allocFP(1);
899 interpreter->addOperand(op0);
900 interpreter->addOperand(op1);
901 interpreter->addOperand(op2);
902 interpreter->endOp();
907 int ExprPrototypeNode::buildInterpreter(Interpreter* interpreter) const {
909 _interpreterOps.clear();
910 for (int c = 0; c < numChildren(); c++) {
911 if (const auto* childVarNode = dynamic_cast<const ExprVarNode*>(child(c))) {
912 const ExprType& childType = childVarNode->type();
913 if (childType.isFP()) {
914 int operand = interpreter->allocFP(childType.dim());
915 _interpreterOps.push_back(operand);
916 interpreter->varToLoc[childVarNode->localVar()] = operand;
921 child(c)->buildInterpreter(interpreter);
923 // make sure we have a slot in our global activation record for the variables!
928 int ExprCompareEqNode::buildInterpreter(Interpreter* interpreter) const {
929 const ExprNode * child0 = child(0);
930 const ExprNode *child1 = child(1);
931 int op0 = child0->buildInterpreter(interpreter);
932 int op1 = child1->buildInterpreter(interpreter);
934 if (child0->type().isFP()) {
935 int dim0 = child0->type().dim();
936 int dim1 = child1->type().dim();
937 int dimCompare = std::max(dim0, dim1);
938 if (dimCompare > 1) {
940 interpreter->addOp(getTemplatizedOp<Promote>(dim1));
941 int promotedOp0 = interpreter->allocFP(dim1);
942 interpreter->addOperand(op0);
943 interpreter->addOperand(promotedOp0);
944 interpreter->endOp();
948 interpreter->addOp(getTemplatizedOp<Promote>(dim0));
949 int promotedOp1 = interpreter->allocFP(dim0);
950 interpreter->addOperand(op1);
951 interpreter->addOperand(promotedOp1);
952 interpreter->endOp();
957 interpreter->addOp(getTemplatizedOp2<'=
', CompareEqOp>(dimCompare));
959 interpreter->addOp(getTemplatizedOp2<'!
', CompareEqOp>(dimCompare));
961 assert(false && "Invalid operation");
962 } else if (child0->type().isString()) {
964 interpreter->addOp(getTemplatizedOp2<'=
', StrCompareEqOp>(1));
966 interpreter->addOp(getTemplatizedOp2<'!
', StrCompareEqOp>(1));
968 assert(false && "Invalid operation");
970 assert(false && "Invalid type for comparison");
971 int op2 = interpreter->allocFP(1);
972 interpreter->addOperand(op0);
973 interpreter->addOperand(op1);
974 interpreter->addOperand(op2);
975 interpreter->endOp(child0->type().isString() == false);
979 int ExprCondNode::buildInterpreter(Interpreter* interpreter) const {
981 // TODO: handle strings!
982 int dimout = type().dim();
985 int condOp = child(0)->buildInterpreter(interpreter);
986 int basePC = (interpreter->nextPC());
987 interpreter->addOp(CondJmpRelativeIfFalse::f);
988 interpreter->addOperand(condOp);
989 int destFalse = interpreter->addOperand(0);
990 interpreter->endOp();
992 // true way of working
993 int op1 = child(1)->buildInterpreter(interpreter);
995 interpreter->addOp(getTemplatizedOp<AssignOp>(dimout));
996 else if (type().isString())
997 interpreter->addOp(AssignStrOp::f);
1000 interpreter->addOperand(op1);
1001 int dataOutTrue = interpreter->addOperand(-1);
1002 interpreter->endOp(false);
1004 // jump past false way of working
1005 interpreter->addOp(JmpRelative::f);
1006 int destEnd = interpreter->addOperand(0);
1007 interpreter->endOp();
1009 // record start of false condition
1010 int child2PC = interpreter->nextPC();
1012 // false way of working
1013 int op2 = child(2)->buildInterpreter(interpreter);
1015 interpreter->addOp(getTemplatizedOp<AssignOp>(dimout));
1016 else if (type().isString())
1017 interpreter->addOp(AssignStrOp::f);
1020 interpreter->addOperand(op2);
1021 int dataOutFalse = interpreter->addOperand(-1);
1022 interpreter->endOp(false);
1024 // patch up relative jumps
1025 interpreter->opData[destFalse] = child2PC - basePC;
1026 interpreter->opData[destEnd] = interpreter->nextPC() - (child2PC - 1);
1030 opOut = interpreter->allocFP(type().dim());
1031 else if (type().isString())
1032 opOut = interpreter->allocPtr();
1036 // patch outputs on assigns in each condition
1037 interpreter->opData[dataOutTrue] = opOut;
1038 interpreter->opData[dataOutFalse] = opOut;
1043 int ExprBlockNode::buildInterpreter(Interpreter* interpreter) const {
1044 assert(numChildren() == 2);
1045 child(0)->buildInterpreter(interpreter);
1046 return child(1)->buildInterpreter(interpreter);
1049 int ExprModuleNode::buildInterpreter(Interpreter* interpreter) const {
1051 for (int c = 0; c < numChildren(); c++) {
1052 if (c == numChildren() - 1) interpreter->setPCStart(interpreter->nextPC());
1053 lastIdx = child(c)->buildInterpreter(interpreter);
1057 } // namespace KSeExpr
int buildInterpreter(Interpreter *interpreter) const override
builds an interpreter. Returns the location index for the evaluated data
int buildInterpreter(Interpreter *interpreter) const override
builds an interpreter. Returns the location index for the evaluated data
char _op
_op '<' less-than, 'l' less-than-eq, '>' greater-than, 'g' greater-than-eq
int buildInterpreter(Interpreter *interpreter) const override
builds an interpreter. Returns the location index for the evaluated data
Node that calls a function.
int buildInterpreter(Interpreter *interpreter) const override
builds an interpreter. Returns the location index for the evaluated data
int buildInterpreter(Interpreter *interpreter) const override
Build the interpreter.
int buildInterpreterForCall(const ExprFuncNode *callerNode, Interpreter *interpreter) const
Build interpreter if we are called.
const ExprPrototypeNode * prototype() const
TODO: Accessor for prototype (probably not needed when we use prep right)
ExprLocalVar join (merge) references. Remembers which variables are possible assigners to this.
ExprLocalVar reference, all local variables in seexpr are subclasses of this or this itself.
int buildInterpreter(Interpreter *interpreter) const
Allocates variable for interpreter.
ExprType type() const
returns type of the variable
virtual int buildInterpreter(Interpreter *interpreter) const
builds an interpreter. Returns the location index for the evaluated data
int numChildren() const
Number of children.
const ExprType & type() const
The type of the node.
const ExprNode * child(size_t i) const
Get 0 indexed child.
int buildInterpreter(Interpreter *interpreter) const override
builds an interpreter. Returns the location index for the evaluated data
int buildInterpreter(Interpreter *interpreter) const override
builds an interpreter. Returns the location index for the evaluated data
int buildInterpreter(Interpreter *interpreter) const override
builds an interpreter. Returns the location index for the evaluated data
bool isFP() const
Direct is predicate checks.
int buildInterpreter(Interpreter *interpreter) const override
builds an interpreter. Returns the location index for the evaluated data
std::vector< std::pair< std::string, ExprLocalVarPhi * > > & merge(size_t index)
int buildInterpreter(Interpreter *interpreter) const override
builds an interpreter. Returns the location index for the evaluated data
const ExprVarRef * var() const
abstract class for implementing variable references
virtual ExprType type() const
returns (current) type
int buildInterpreter(Interpreter *interpreter) const override
builds an interpreter. Returns the location index for the evaluated data
std::vector< std::pair< OpF, int > > ops
std::vector< double > d
Double data (constants and evaluated)
int addOp(OpF op)
! adds an operator to the program (pointing to the data at the current location)
void eval(VarBlock *varBlock, bool debug=false)
Evaluate program.
void endOp(bool execute=true)
std::vector< int > callStack
std::vector< char * > s
constant and evaluated pointer data
int allocFP(int n)
! Allocate a floating point set of data of dimension n
int(*)(int *, double *, char **, std::vector< int > &) OpF
Op function pointer arguments are (int* currOpData,double* currD,char** c,std::stack<int>& callStacku...
int nextPC() const
Return the position that the next instruction will be placed at.
int allocPtr()
Allocate a pointer location (can be anything, but typically space for char*)
std::vector< int > opData
Ooperands to op.
int addOperand(int param)
! Adds an operand. Note this should be done after doing the addOp!
void print(int pc=-1) const
Debug by printing program.
Internally implemented var ref used by SeExpr.
A thread local evaluation context. Just allocate and fill in with data.
int indirectIndex
indirect index to add to pointer based data
std::vector< char * > s
copy of Interpreter's str data
std::vector< double > d
copy of Interpreter's double data
char ** data()
Raw data of the data block pointer (used by compiler)
bool threadSafe
if true, interpreter's data will be copied to this instance before evaluation.
KSeExpr_DEFAULT double_t floor(double_t val)
static Interpreter::OpF getTemplatizedOp2(int i)
Return the function f encapsulated in class T for the dynamic i converted to a static d....
const ExprStrNode * isString(const ExprNode *testee)
void copyVarToPromotedPosition(Interpreter *interpreter, ExprLocalVar *varSource, ExprLocalVar *varDest)