diff options
author | Arne H Juul <arnej27959@users.noreply.github.com> | 2020-12-03 19:12:22 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-03 19:12:22 +0100 |
commit | f88b7e59d00a59b623221d453e24c74e5b26c677 (patch) | |
tree | cfedc9b00df8bcbc5cad534d28c554639a3b5d2f /eval | |
parent | 34de8912bdfd669141633fef0d4ecd8f64830839 (diff) | |
parent | 78b6e23e5de6b80ef73fabb69bc76627ee642de4 (diff) |
Merge pull request #15646 from vespa-engine/havardpe/only-factory-in-interpreted-function
only factory in interpreted function
Diffstat (limited to 'eval')
53 files changed, 233 insertions, 422 deletions
diff --git a/eval/src/tests/eval/interpreted_function/interpreted_function_test.cpp b/eval/src/tests/eval/interpreted_function/interpreted_function_test.cpp index 7092d354b10..871a564bfa4 100644 --- a/eval/src/tests/eval/interpreted_function/interpreted_function_test.cpp +++ b/eval/src/tests/eval/interpreted_function/interpreted_function_test.cpp @@ -70,14 +70,14 @@ struct MyEvalTest : test::EvalSpec::EvalTest { } } - void verify_result(EngineOrFactory engine, + void verify_result(const ValueBuilderFactory &factory, const Function &function, const vespalib::string &description, const SimpleParams ¶ms, double expected_result) { auto node_types = NodeTypes(function, std::vector<ValueType>(params.params.size(), ValueType::double_type())); - InterpretedFunction ifun(engine, function, node_types); + InterpretedFunction ifun(factory, function, node_types); InterpretedFunction::Context ictx(ifun); const Value &result_value = ifun.eval(ictx, params); report_result(result_value.is_double(), result_value.as_double(), expected_result, description); diff --git a/eval/src/tests/eval/tensor_function/tensor_function_test.cpp b/eval/src/tests/eval/tensor_function/tensor_function_test.cpp index b5f9e22a5cb..4396a6773ea 100644 --- a/eval/src/tests/eval/tensor_function/tensor_function_test.cpp +++ b/eval/src/tests/eval/tensor_function/tensor_function_test.cpp @@ -16,14 +16,14 @@ using namespace vespalib::eval::tensor_function; const auto &simple_factory = SimpleValueBuilderFactory::get(); struct EvalCtx { - EngineOrFactory engine; + const ValueBuilderFactory &factory; Stash stash; std::vector<Value::UP> tensors; std::vector<Value::CREF> params; InterpretedFunction::UP ifun; std::unique_ptr<InterpretedFunction::Context> ictx; - EvalCtx(EngineOrFactory engine_in) - : engine(engine_in), stash(), tensors(), params(), ifun(), ictx() {} + EvalCtx(const ValueBuilderFactory &factory_in) + : factory(factory_in), stash(), tensors(), params(), ifun(), ictx() {} ~EvalCtx() {} size_t add_tensor(Value::UP tensor) { size_t id = params.size(); @@ -36,18 +36,18 @@ struct EvalCtx { tensors[idx] = std::move(tensor); } const Value &eval(const TensorFunction &fun) { - ifun = std::make_unique<InterpretedFunction>(engine, fun); + ifun = std::make_unique<InterpretedFunction>(factory, fun); ictx = std::make_unique<InterpretedFunction::Context>(*ifun); return ifun->eval(*ictx, SimpleObjectParams(params)); } Value::UP make_double(double value) { - return engine.from_spec(TensorSpec("double").add({}, value)); + return value_from_spec(TensorSpec("double").add({}, value), factory); } Value::UP make_true() { - return engine.from_spec(TensorSpec("double").add({}, 1.0)); + return value_from_spec(TensorSpec("double").add({}, 1.0), factory); } Value::UP make_false() { - return engine.from_spec(TensorSpec("double").add({}, 0.0)); + return value_from_spec(TensorSpec("double").add({}, 0.0), factory); } Value::UP make_vector(std::initializer_list<double> cells, vespalib::string dim = "x", bool mapped = false) { vespalib::string type_spec = mapped @@ -61,119 +61,119 @@ struct EvalCtx { : TensorSpec::Label(idx++); spec.add({{dim, label}}, cell_value); } - return engine.from_spec(spec); + return value_from_spec(spec, factory); } Value::UP make_mixed_tensor(double a, double b, double c, double d) { - return engine.from_spec( + return value_from_spec( TensorSpec("tensor(x{},y[2])") .add({{"x", "foo"}, {"y", 0}}, a) .add({{"x", "foo"}, {"y", 1}}, b) .add({{"x", "bar"}, {"y", 0}}, c) - .add({{"x", "bar"}, {"y", 1}}, d)); + .add({{"x", "bar"}, {"y", 1}}, d), factory); } Value::UP make_tensor_matrix_first_half() { - return engine.from_spec( + return value_from_spec( TensorSpec("tensor(x[2])") .add({{"x", 0}}, 1.0) - .add({{"x", 1}}, 3.0)); + .add({{"x", 1}}, 3.0), factory); } Value::UP make_tensor_matrix_second_half() { - return engine.from_spec( + return value_from_spec( TensorSpec("tensor(x[2])") .add({{"x", 0}}, 2.0) - .add({{"x", 1}}, 4.0)); + .add({{"x", 1}}, 4.0), factory); } Value::UP make_tensor_matrix() { - return engine.from_spec( + return value_from_spec( TensorSpec("tensor(x[2],y[2])") .add({{"x", 0}, {"y", 0}}, 1.0) .add({{"x", 0}, {"y", 1}}, 2.0) .add({{"x", 1}, {"y", 0}}, 3.0) - .add({{"x", 1}, {"y", 1}}, 4.0)); + .add({{"x", 1}, {"y", 1}}, 4.0), factory); } Value::UP make_tensor_matrix_renamed() { - return engine.from_spec( + return value_from_spec( TensorSpec("tensor(y[2],z[2])") .add({{"z", 0}, {"y", 0}}, 1.0) .add({{"z", 0}, {"y", 1}}, 2.0) .add({{"z", 1}, {"y", 0}}, 3.0) - .add({{"z", 1}, {"y", 1}}, 4.0)); + .add({{"z", 1}, {"y", 1}}, 4.0), factory); } Value::UP make_tensor_reduce_input() { - return engine.from_spec( + return value_from_spec( TensorSpec("tensor(x[3],y[2])") .add({{"x",0},{"y",0}}, 1) .add({{"x",1},{"y",0}}, 2) .add({{"x",2},{"y",0}}, 3) .add({{"x",0},{"y",1}}, 4) .add({{"x",1},{"y",1}}, 5) - .add({{"x",2},{"y",1}}, 6)); + .add({{"x",2},{"y",1}}, 6), factory); } Value::UP make_tensor_reduce_y_output() { - return engine.from_spec( + return value_from_spec( TensorSpec("tensor(x[3])") .add({{"x",0}}, 5) .add({{"x",1}}, 7) - .add({{"x",2}}, 9)); + .add({{"x",2}}, 9), factory); } Value::UP make_tensor_map_input() { - return engine.from_spec( + return value_from_spec( TensorSpec("tensor(x{},y{})") .add({{"x","1"},{"y","1"}}, 1) .add({{"x","2"},{"y","1"}}, -3) - .add({{"x","1"},{"y","2"}}, 5)); + .add({{"x","1"},{"y","2"}}, 5), factory); } Value::UP make_tensor_map_output() { - return engine.from_spec( + return value_from_spec( TensorSpec("tensor(x{},y{})") .add({{"x","1"},{"y","1"}}, -1) .add({{"x","2"},{"y","1"}}, 3) - .add({{"x","1"},{"y","2"}}, -5)); + .add({{"x","1"},{"y","2"}}, -5), factory); } Value::UP make_tensor_join_lhs() { - return engine.from_spec( + return value_from_spec( TensorSpec("tensor(x{},y{})") .add({{"x","1"},{"y","1"}}, 1) .add({{"x","2"},{"y","1"}}, 3) - .add({{"x","1"},{"y","2"}}, 5)); + .add({{"x","1"},{"y","2"}}, 5), factory); } Value::UP make_tensor_join_rhs() { - return engine.from_spec( + return value_from_spec( TensorSpec("tensor(y{},z{})") .add({{"y","1"},{"z","1"}}, 7) .add({{"y","2"},{"z","1"}}, 11) - .add({{"y","1"},{"z","2"}}, 13)); + .add({{"y","1"},{"z","2"}}, 13), factory); } Value::UP make_tensor_join_output() { - return engine.from_spec( + return value_from_spec( TensorSpec("tensor(x{},y{},z{})") .add({{"x","1"},{"y","1"},{"z","1"}}, 7) .add({{"x","1"},{"y","1"},{"z","2"}}, 13) .add({{"x","2"},{"y","1"},{"z","1"}}, 21) .add({{"x","2"},{"y","1"},{"z","2"}}, 39) - .add({{"x","1"},{"y","2"},{"z","1"}}, 55)); + .add({{"x","1"},{"y","2"},{"z","1"}}, 55), factory); } Value::UP make_tensor_merge_lhs() { - return engine.from_spec( + return value_from_spec( TensorSpec("tensor(x{})") .add({{"x","1"}}, 1) .add({{"x","2"}}, 3) - .add({{"x","3"}}, 5)); + .add({{"x","3"}}, 5), factory); } Value::UP make_tensor_merge_rhs() { - return engine.from_spec( + return value_from_spec( TensorSpec("tensor(x{})") .add({{"x","2"}}, 7) .add({{"x","3"}}, 9) - .add({{"x","4"}}, 11)); + .add({{"x","4"}}, 11), factory); } Value::UP make_tensor_merge_output() { - return engine.from_spec( + return value_from_spec( TensorSpec("tensor(x{})") .add({{"x","1"}}, 1) .add({{"x","2"}}, 10) .add({{"x","3"}}, 14) - .add({{"x","4"}}, 11)); + .add({{"x","4"}}, 11), factory); } }; diff --git a/eval/src/tests/tensor/dense_replace_type_function/dense_replace_type_function_test.cpp b/eval/src/tests/tensor/dense_replace_type_function/dense_replace_type_function_test.cpp index 14edde24c4d..dd4ddb9044a 100644 --- a/eval/src/tests/tensor/dense_replace_type_function/dense_replace_type_function_test.cpp +++ b/eval/src/tests/tensor/dense_replace_type_function/dense_replace_type_function_test.cpp @@ -2,6 +2,7 @@ #include <vespa/vespalib/testkit/test_kit.h> #include <vespa/eval/eval/fast_value.h> +#include <vespa/eval/eval/value_codec.h> #include <vespa/eval/eval/interpreted_function.h> #include <vespa/eval/tensor/dense/dense_tensor_view.h> #include <vespa/eval/tensor/dense/dense_replace_type_function.h> @@ -13,7 +14,7 @@ using namespace vespalib::eval; using namespace vespalib::tensor; using namespace vespalib; -EngineOrFactory prod_factory{FastValueBuilderFactory::get()}; +const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get(); TypedCells getCellsRef(const eval::Value &value) { return value.cells(); @@ -23,7 +24,7 @@ struct ChildMock : Leaf { bool is_mutable; ChildMock(const ValueType &type) : Leaf(type), is_mutable(true) {} bool result_is_mutable() const override { return is_mutable; } - InterpretedFunction::Instruction compile_self(EngineOrFactory, Stash &) const override { abort(); } + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &, Stash &) const override { abort(); } }; struct Fixture { @@ -34,7 +35,7 @@ struct Fixture { std::vector<TensorFunction::Child::CREF> children; InterpretedFunction::State state; Fixture() - : my_value(prod_factory.from_spec(spec({x(10)}, N()))), + : my_value(value_from_spec(spec({x(10)}, N()), prod_factory)), new_type(ValueType::from_spec("tensor(x[5],y[2])")), mock_child(my_value->type()), my_fun(new_type, mock_child), diff --git a/eval/src/tests/tensor/instruction_benchmark/instruction_benchmark.cpp b/eval/src/tests/tensor/instruction_benchmark/instruction_benchmark.cpp index 4a822121c4a..3bddf69f53f 100644 --- a/eval/src/tests/tensor/instruction_benchmark/instruction_benchmark.cpp +++ b/eval/src/tests/tensor/instruction_benchmark/instruction_benchmark.cpp @@ -34,7 +34,6 @@ #include <vespa/eval/eval/operation.h> #include <vespa/eval/eval/tensor_function.h> #include <vespa/eval/eval/optimize_tensor_function.h> -#include <vespa/eval/tensor/default_tensor_engine.h> #include <vespa/vespalib/util/benchmark_timer.h> #include <vespa/vespalib/util/stringfmt.h> #include <vespa/vespalib/objects/nbostream.h> @@ -131,16 +130,16 @@ void my_multi_instruction_op(InterpretedFunction::State &state, uint64_t param_i } } -void collect_op1_chain(const TensorFunction &node, const EngineOrFactory &engine, Stash &stash, std::vector<Instruction> &list) { +void collect_op1_chain(const TensorFunction &node, const ValueBuilderFactory &factory, Stash &stash, std::vector<Instruction> &list) { if (auto op1 = as<tensor_function::Op1>(node)) { - collect_op1_chain(op1->child(), engine, stash, list); - list.push_back(node.compile_self(engine, stash)); + collect_op1_chain(op1->child(), factory, stash, list); + list.push_back(node.compile_self(factory, stash)); } } -Instruction compile_op1_chain(const TensorFunction &node, const EngineOrFactory &engine, Stash &stash) { +Instruction compile_op1_chain(const TensorFunction &node, const ValueBuilderFactory &factory, Stash &stash) { auto ¶m = stash.create<MultiOpParam>(); - collect_op1_chain(node, engine, stash, param.list); + collect_op1_chain(node, factory, stash, param.list); return {my_multi_instruction_op,(uint64_t)(¶m)}; } @@ -150,60 +149,60 @@ struct Impl { size_t order; vespalib::string name; vespalib::string short_name; - EngineOrFactory engine; + const ValueBuilderFactory &factory; bool optimize; - Impl(size_t order_in, const vespalib::string &name_in, const vespalib::string &short_name_in, EngineOrFactory engine_in, bool optimize_in) - : order(order_in), name(name_in), short_name(short_name_in), engine(engine_in), optimize(optimize_in) {} - Value::UP create_value(const TensorSpec &spec) const { return engine.from_spec(spec); } - TensorSpec create_spec(const Value &value) const { return engine.to_spec(value); } + Impl(size_t order_in, const vespalib::string &name_in, const vespalib::string &short_name_in, const ValueBuilderFactory &factory_in, bool optimize_in) + : order(order_in), name(name_in), short_name(short_name_in), factory(factory_in), optimize(optimize_in) {} + Value::UP create_value(const TensorSpec &spec) const { return value_from_spec(spec, factory); } + TensorSpec create_spec(const Value &value) const { return spec_from_value(value); } Instruction create_join(const ValueType &lhs, const ValueType &rhs, operation::op2_t function, Stash &stash) const { // create a complete tensor function, but only compile the relevant instruction const auto &lhs_node = tensor_function::inject(lhs, 0, stash); const auto &rhs_node = tensor_function::inject(rhs, 1, stash); const auto &join_node = tensor_function::join(lhs_node, rhs_node, function, stash); - const auto &node = optimize ? optimize_tensor_function(engine, join_node, stash) : join_node; - return node.compile_self(engine, stash); + const auto &node = optimize ? optimize_tensor_function(factory, join_node, stash) : join_node; + return node.compile_self(factory, stash); } Instruction create_reduce(const ValueType &lhs, Aggr aggr, const std::vector<vespalib::string> &dims, Stash &stash) const { // create a complete tensor function, but only compile the relevant instruction const auto &lhs_node = tensor_function::inject(lhs, 0, stash); const auto &reduce_node = tensor_function::reduce(lhs_node, aggr, dims, stash); - const auto &node = optimize ? optimize_tensor_function(engine, reduce_node, stash) : reduce_node; + const auto &node = optimize ? optimize_tensor_function(factory, reduce_node, stash) : reduce_node; // since reduce might be optimized into multiple chained // instructions, we need some extra magic to package these // instructions into a single compound instruction. - return compile_op1_chain(node, engine, stash); + return compile_op1_chain(node, factory, stash); } Instruction create_rename(const ValueType &lhs, const std::vector<vespalib::string> &from, const std::vector<vespalib::string> &to, Stash &stash) const { // create a complete tensor function, but only compile the relevant instruction const auto &lhs_node = tensor_function::inject(lhs, 0, stash); const auto &rename_node = tensor_function::rename(lhs_node, from, to, stash); - const auto &node = optimize ? optimize_tensor_function(engine, rename_node, stash) : rename_node; - return node.compile_self(engine, stash); + const auto &node = optimize ? optimize_tensor_function(factory, rename_node, stash) : rename_node; + return node.compile_self(factory, stash); } Instruction create_merge(const ValueType &lhs, const ValueType &rhs, operation::op2_t function, Stash &stash) const { // create a complete tensor function, but only compile the relevant instruction const auto &lhs_node = tensor_function::inject(lhs, 0, stash); const auto &rhs_node = tensor_function::inject(rhs, 1, stash); const auto &merge_node = tensor_function::merge(lhs_node, rhs_node, function, stash); - const auto &node = optimize ? optimize_tensor_function(engine, merge_node, stash) : merge_node; - return node.compile_self(engine, stash); + const auto &node = optimize ? optimize_tensor_function(factory, merge_node, stash) : merge_node; + return node.compile_self(factory, stash); } Instruction create_concat(const ValueType &lhs, const ValueType &rhs, const std::string &dimension, Stash &stash) const { // create a complete tensor function, but only compile the relevant instruction const auto &lhs_node = tensor_function::inject(lhs, 0, stash); const auto &rhs_node = tensor_function::inject(rhs, 1, stash); const auto &concat_node = tensor_function::concat(lhs_node, rhs_node, dimension, stash); - return concat_node.compile_self(engine, stash); - const auto &node = optimize ? optimize_tensor_function(engine, concat_node, stash) : concat_node; - return node.compile_self(engine, stash); + return concat_node.compile_self(factory, stash); + const auto &node = optimize ? optimize_tensor_function(factory, concat_node, stash) : concat_node; + return node.compile_self(factory, stash); } Instruction create_map(const ValueType &lhs, operation::op1_t function, Stash &stash) const { // create a complete tensor function, but only compile the relevant instruction const auto &lhs_node = tensor_function::inject(lhs, 0, stash); const auto &map_node = tensor_function::map(lhs_node, function, stash); - const auto &node = optimize ? optimize_tensor_function(engine, map_node, stash) : map_node; - return node.compile_self(engine, stash); + const auto &node = optimize ? optimize_tensor_function(factory, map_node, stash) : map_node; + return node.compile_self(factory, stash); } Instruction create_tensor_create(const ValueType &proto_type, const TensorSpec &proto, Stash &stash) const { // create a complete tensor function, but only compile the relevant instruction @@ -213,8 +212,8 @@ struct Impl { spec.emplace(cell.first, my_double); } const auto &create_tensor_node = tensor_function::create(proto_type, spec, stash); - const auto &node = optimize ? optimize_tensor_function(engine, create_tensor_node, stash) : create_tensor_node; - return node.compile_self(engine, stash); + const auto &node = optimize ? optimize_tensor_function(factory, create_tensor_node, stash) : create_tensor_node; + return node.compile_self(factory, stash); } Instruction create_tensor_lambda(const ValueType &type, const Function &function, const ValueType &p0_type, Stash &stash) const { std::vector<ValueType> arg_types(type.dimensions().size(), ValueType::double_type()); @@ -222,8 +221,8 @@ struct Impl { NodeTypes types(function, arg_types); EXPECT_EQ(types.errors(), std::vector<vespalib::string>()); const auto &tensor_lambda_node = tensor_function::lambda(type, {0}, function, std::move(types), stash); - const auto &node = optimize ? optimize_tensor_function(engine, tensor_lambda_node, stash) : tensor_lambda_node; - return node.compile_self(engine, stash); + const auto &node = optimize ? optimize_tensor_function(factory, tensor_lambda_node, stash) : tensor_lambda_node; + return node.compile_self(factory, stash); } Instruction create_tensor_peek(const ValueType &type, const MyPeekSpec &my_spec, Stash &stash) const { // create a complete tensor function, but only compile the relevant instruction @@ -246,8 +245,8 @@ struct Impl { } } const auto &peek_node = tensor_function::peek(my_param, spec, stash); - const auto &node = optimize ? optimize_tensor_function(engine, peek_node, stash) : peek_node; - return node.compile_self(engine, stash); + const auto &node = optimize ? optimize_tensor_function(factory, peek_node, stash) : peek_node; + return node.compile_self(factory, stash); } }; @@ -357,7 +356,7 @@ struct EvalOp { EvalOp(const EvalOp &) = delete; EvalOp &operator=(const EvalOp &) = delete; EvalOp(Stash &&stash_in, Instruction op, const std::vector<CREF<TensorSpec>> &stack_spec, const Impl &impl_in) - : my_stash(std::move(stash_in)), impl(impl_in), my_param(), values(), stack(), single(impl.engine, op) + : my_stash(std::move(stash_in)), impl(impl_in), my_param(), values(), stack(), single(impl.factory, op) { for (const TensorSpec &spec: stack_spec) { values.push_back(impl.create_value(spec)); @@ -367,7 +366,7 @@ struct EvalOp { } } EvalOp(Stash &&stash_in, Instruction op, const TensorSpec &p0, const Impl &impl_in) - : my_stash(std::move(stash_in)), impl(impl_in), my_param(p0, impl), values(), stack(), single(impl.engine, op, my_param) + : my_stash(std::move(stash_in)), impl(impl_in), my_param(p0, impl), values(), stack(), single(impl.factory, op, my_param) { } TensorSpec result() { return impl.create_spec(single.eval(stack)); } @@ -645,10 +644,10 @@ void benchmark_encode_decode(const vespalib::string &desc, const TensorSpec &pro for (const Impl &impl: impl_list) { vespalib::nbostream data; auto value = impl.create_value(proto); - impl.engine.encode(*value, data); - auto new_value = impl.engine.decode(data); + encode_value(*value, data); + auto new_value = decode_value(data, impl.factory); ASSERT_EQ(data.size(), 0); - ASSERT_EQ(proto, impl.engine.to_spec(*new_value)); + ASSERT_EQ(proto, spec_from_value(*new_value)); } fprintf(stderr, "--------------------------------------------------------\n"); fprintf(stderr, "Benchmarking encode/decode for: [%s]\n", desc.c_str()); @@ -664,12 +663,12 @@ void benchmark_encode_decode(const vespalib::string &desc, const TensorSpec &pro std::array<Value::UP, loop_cnt> object; encode_timer.before(); for (size_t i = 0; i < loop_cnt; ++i) { - impl.engine.encode(*value, data[i]); + encode_value(*value, data[i]); } encode_timer.after(); decode_timer.before(); for (size_t i = 0; i < loop_cnt; ++i) { - object[i] = impl.engine.decode(data[i]); + object[i] = decode_value(data[i], impl.factory); } decode_timer.after(); } diff --git a/eval/src/vespa/eval/eval/compile_tensor_function.cpp b/eval/src/vespa/eval/eval/compile_tensor_function.cpp index 6fd754b9cc8..4f45aa731b5 100644 --- a/eval/src/vespa/eval/eval/compile_tensor_function.cpp +++ b/eval/src/vespa/eval/eval/compile_tensor_function.cpp @@ -32,11 +32,11 @@ struct Frame { }; struct ProgramCompiler { - EngineOrFactory engine; + const ValueBuilderFactory &factory; Stash &stash; std::vector<Frame> stack; std::vector<Instruction> prog; - ProgramCompiler(EngineOrFactory engine_in, Stash &stash_in) : engine(engine_in), stash(stash_in), stack(), prog() {} + ProgramCompiler(const ValueBuilderFactory &factory_in, Stash &stash_in) : factory(factory_in), stash(stash_in), stack(), prog() {} void append(const std::vector<Instruction> &other_prog) { prog.insert(prog.end(), other_prog.begin(), other_prog.end()); @@ -44,9 +44,9 @@ struct ProgramCompiler { void open(const TensorFunction &node) { if (auto if_node = as<tensor_function::If>(node)) { - append(compile_tensor_function(engine, if_node->cond(), stash)); - auto true_prog = compile_tensor_function(engine, if_node->true_child(), stash); - auto false_prog = compile_tensor_function(engine, if_node->false_child(), stash); + append(compile_tensor_function(factory, if_node->cond(), stash)); + auto true_prog = compile_tensor_function(factory, if_node->true_child(), stash); + auto false_prog = compile_tensor_function(factory, if_node->false_child(), stash); true_prog.emplace_back(op_skip, false_prog.size()); prog.emplace_back(op_skip_if_false, true_prog.size()); append(true_prog); @@ -57,7 +57,7 @@ struct ProgramCompiler { } void close(const TensorFunction &node) { - prog.push_back(node.compile_self(engine, stash)); + prog.push_back(node.compile_self(factory, stash)); } std::vector<Instruction> compile(const TensorFunction &function) { @@ -76,8 +76,8 @@ struct ProgramCompiler { } // namespace vespalib::eval::<unnamed> -std::vector<Instruction> compile_tensor_function(EngineOrFactory engine, const TensorFunction &function, Stash &stash) { - ProgramCompiler compiler(engine, stash); +std::vector<Instruction> compile_tensor_function(const ValueBuilderFactory &factory, const TensorFunction &function, Stash &stash) { + ProgramCompiler compiler(factory, stash); return compiler.compile(function); } diff --git a/eval/src/vespa/eval/eval/compile_tensor_function.h b/eval/src/vespa/eval/eval/compile_tensor_function.h index b12705e8bb5..40570df391a 100644 --- a/eval/src/vespa/eval/eval/compile_tensor_function.h +++ b/eval/src/vespa/eval/eval/compile_tensor_function.h @@ -2,7 +2,6 @@ #pragma once -#include "engine_or_factory.h" #include "interpreted_function.h" #include <vector> @@ -10,8 +9,9 @@ namespace vespalib { class Stash; } namespace vespalib::eval { +class ValueBuilderFactory; struct TensorFunction; -std::vector<InterpretedFunction::Instruction> compile_tensor_function(EngineOrFactory engine, const TensorFunction &function, Stash &stash); +std::vector<InterpretedFunction::Instruction> compile_tensor_function(const ValueBuilderFactory &factory, const TensorFunction &function, Stash &stash); } // namespace vespalib::eval diff --git a/eval/src/vespa/eval/eval/interpreted_function.cpp b/eval/src/vespa/eval/eval/interpreted_function.cpp index 37817843ce2..5ac401aee39 100644 --- a/eval/src/vespa/eval/eval/interpreted_function.cpp +++ b/eval/src/vespa/eval/eval/interpreted_function.cpp @@ -4,7 +4,6 @@ #include "node_visitor.h" #include "node_traverser.h" #include "tensor_nodes.h" -#include "tensor_engine.h" #include "make_tensor_function.h" #include "optimize_tensor_function.h" #include "compile_tensor_function.h" @@ -33,8 +32,8 @@ const Function *get_lambda(const nodes::Node &node) { } // namespace vespalib::<unnamed> -InterpretedFunction::State::State(EngineOrFactory engine_in) - : engine(engine_in), +InterpretedFunction::State::State(const ValueBuilderFactory &factory_in) + : factory(factory_in), params(nullptr), stash(), stack(), @@ -55,26 +54,26 @@ InterpretedFunction::State::init(const LazyParams ¶ms_in) { } InterpretedFunction::Context::Context(const InterpretedFunction &ifun) - : _state(ifun._tensor_engine) + : _state(ifun._factory) { } -InterpretedFunction::InterpretedFunction(EngineOrFactory engine, const TensorFunction &function) +InterpretedFunction::InterpretedFunction(const ValueBuilderFactory &factory, const TensorFunction &function) : _program(), _stash(), - _tensor_engine(engine) + _factory(factory) { - _program = compile_tensor_function(engine, function, _stash); + _program = compile_tensor_function(factory, function, _stash); } -InterpretedFunction::InterpretedFunction(EngineOrFactory engine, const nodes::Node &root, const NodeTypes &types) +InterpretedFunction::InterpretedFunction(const ValueBuilderFactory &factory, const nodes::Node &root, const NodeTypes &types) : _program(), _stash(), - _tensor_engine(engine) + _factory(factory) { - const TensorFunction &plain_fun = make_tensor_function(engine, root, types, _stash); - const TensorFunction &optimized = optimize_tensor_function(engine, plain_fun, _stash); - _program = compile_tensor_function(engine, optimized, _stash); + const TensorFunction &plain_fun = make_tensor_function(factory, root, types, _stash); + const TensorFunction &optimized = optimize_tensor_function(factory, plain_fun, _stash); + _program = compile_tensor_function(factory, optimized, _stash); } InterpretedFunction::~InterpretedFunction() = default; @@ -118,8 +117,8 @@ InterpretedFunction::detect_issues(const Function &function) return Function::Issues(std::move(checker.issues)); } -InterpretedFunction::EvalSingle::EvalSingle(EngineOrFactory engine, Instruction op, const LazyParams ¶ms) - : _state(engine), +InterpretedFunction::EvalSingle::EvalSingle(const ValueBuilderFactory &factory, Instruction op, const LazyParams ¶ms) + : _state(factory), _op(op) { _state.params = ¶ms; diff --git a/eval/src/vespa/eval/eval/interpreted_function.h b/eval/src/vespa/eval/eval/interpreted_function.h index f374322ca51..eca434b1260 100644 --- a/eval/src/vespa/eval/eval/interpreted_function.h +++ b/eval/src/vespa/eval/eval/interpreted_function.h @@ -2,7 +2,7 @@ #pragma once -#include "engine_or_factory.h" +#include "value.h" #include "function.h" #include "node_types.h" #include "lazy_params.h" @@ -28,14 +28,14 @@ class InterpretedFunction { public: struct State { - EngineOrFactory engine; - const LazyParams *params; - Stash stash; - std::vector<Value::CREF> stack; - uint32_t program_offset; - uint32_t if_cnt; + const ValueBuilderFactory &factory; + const LazyParams *params; + Stash stash; + std::vector<Value::CREF> stack; + uint32_t program_offset; + uint32_t if_cnt; - State(EngineOrFactory engine_in); + State(const ValueBuilderFactory &factory_in); ~State(); void init(const LazyParams ¶ms_in); @@ -85,17 +85,17 @@ public: }; private: - std::vector<Instruction> _program; - Stash _stash; - EngineOrFactory _tensor_engine; + std::vector<Instruction> _program; + Stash _stash; + const ValueBuilderFactory &_factory; public: typedef std::unique_ptr<InterpretedFunction> UP; // for testing; use with care; the tensor function must be kept alive - InterpretedFunction(EngineOrFactory engine, const TensorFunction &function); - InterpretedFunction(EngineOrFactory engine, const nodes::Node &root, const NodeTypes &types); - InterpretedFunction(EngineOrFactory engine, const Function &function, const NodeTypes &types) - : InterpretedFunction(engine, function.root(), types) {} + InterpretedFunction(const ValueBuilderFactory &factory, const TensorFunction &function); + InterpretedFunction(const ValueBuilderFactory &factory, const nodes::Node &root, const NodeTypes &types); + InterpretedFunction(const ValueBuilderFactory &factory, const Function &function, const NodeTypes &types) + : InterpretedFunction(factory, function.root(), types) {} InterpretedFunction(InterpretedFunction &&rhs) = default; ~InterpretedFunction(); size_t program_size() const { return _program.size(); } @@ -116,8 +116,8 @@ public: State _state; Instruction _op; public: - EvalSingle(EngineOrFactory engine, Instruction op, const LazyParams ¶ms); - EvalSingle(EngineOrFactory engine, Instruction op) : EvalSingle(engine, op, NoParams::params) {} + EvalSingle(const ValueBuilderFactory &factory, Instruction op, const LazyParams ¶ms); + EvalSingle(const ValueBuilderFactory &factory, Instruction op) : EvalSingle(factory, op, NoParams::params) {} const Value &eval(const std::vector<Value::CREF> &stack); }; }; diff --git a/eval/src/vespa/eval/eval/make_tensor_function.cpp b/eval/src/vespa/eval/eval/make_tensor_function.cpp index dc76c914c06..3f8c8b8861b 100644 --- a/eval/src/vespa/eval/eval/make_tensor_function.cpp +++ b/eval/src/vespa/eval/eval/make_tensor_function.cpp @@ -1,13 +1,13 @@ // Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "make_tensor_function.h" +#include "value_codec.h" #include "tensor_function.h" #include "node_visitor.h" #include "node_traverser.h" #include "tensor_spec.h" #include "operation.h" #include "node_types.h" -#include "tensor_engine.h" #include <vespa/eval/eval/llvm/compile_cache.h> namespace vespalib::eval { @@ -19,13 +19,13 @@ using namespace nodes; //----------------------------------------------------------------------------- struct TensorFunctionBuilder : public NodeVisitor, public NodeTraverser { - Stash &stash; - EngineOrFactory tensor_engine; - const NodeTypes &types; + Stash &stash; + const ValueBuilderFactory &factory; + const NodeTypes &types; std::vector<TensorFunction::CREF> stack; - TensorFunctionBuilder(Stash &stash_in, EngineOrFactory tensor_engine_in, const NodeTypes &types_in) - : stash(stash_in), tensor_engine(tensor_engine_in), types(types_in), stack() {} + TensorFunctionBuilder(Stash &stash_in, const ValueBuilderFactory &factory_in, const NodeTypes &types_in) + : stash(stash_in), factory(factory_in), types(types_in), stack() {} //------------------------------------------------------------------------- @@ -85,7 +85,7 @@ struct TensorFunctionBuilder : public NodeVisitor, public NodeTraverser { for (size_t i = 0; i < create->num_children(); ++i) { spec.add(create->get_child_address(i), create->get_child(i).get_const_value()); } - make_const(node, *stash.create<Value::UP>(tensor_engine.from_spec(spec))); + make_const(node, *stash.create<Value::UP>(value_from_spec(spec, factory))); return true; } } @@ -105,9 +105,9 @@ struct TensorFunctionBuilder : public NodeVisitor, public NodeTraverser { void make_lambda(const TensorLambda &node) { if (node.bindings().empty()) { NoParams no_bound_params; - InterpretedFunction my_fun(tensor_engine, node.lambda().root(), types); + InterpretedFunction my_fun(factory, node.lambda().root(), types); TensorSpec spec = tensor_function::Lambda::create_spec_impl(node.type(), no_bound_params, node.bindings(), my_fun); - make_const(node, *stash.create<Value::UP>(tensor_engine.from_spec(spec))); + make_const(node, *stash.create<Value::UP>(value_from_spec(spec, factory))); } else { stack.push_back(tensor_function::lambda(node.type(), node.bindings(), node.lambda(), types.export_types(node.lambda().root()), stash)); } @@ -356,8 +356,8 @@ struct TensorFunctionBuilder : public NodeVisitor, public NodeTraverser { } // namespace vespalib::eval::<unnamed> -const TensorFunction &make_tensor_function(EngineOrFactory engine, const nodes::Node &root, const NodeTypes &types, Stash &stash) { - TensorFunctionBuilder builder(stash, engine, types); +const TensorFunction &make_tensor_function(const ValueBuilderFactory &factory, const nodes::Node &root, const NodeTypes &types, Stash &stash) { + TensorFunctionBuilder builder(stash, factory, types); root.traverse(builder); assert(builder.stack.size() == 1); return builder.stack[0]; diff --git a/eval/src/vespa/eval/eval/make_tensor_function.h b/eval/src/vespa/eval/eval/make_tensor_function.h index 7cf9515e243..28701a88457 100644 --- a/eval/src/vespa/eval/eval/make_tensor_function.h +++ b/eval/src/vespa/eval/eval/make_tensor_function.h @@ -2,17 +2,16 @@ #pragma once -#include "engine_or_factory.h" - namespace vespalib { class Stash; } namespace vespalib::eval { +class ValueBuilderFactory; class NodeTypes; struct TensorFunction; namespace nodes { struct Node; } -const TensorFunction &make_tensor_function(EngineOrFactory engine, const nodes::Node &root, const NodeTypes &types, Stash &stash); +const TensorFunction &make_tensor_function(const ValueBuilderFactory &factory, const nodes::Node &root, const NodeTypes &types, Stash &stash); } // namespace vespalib::eval diff --git a/eval/src/vespa/eval/eval/optimize_tensor_function.cpp b/eval/src/vespa/eval/eval/optimize_tensor_function.cpp index 21f4ce4dabe..e13582e0fe9 100644 --- a/eval/src/vespa/eval/eval/optimize_tensor_function.cpp +++ b/eval/src/vespa/eval/eval/optimize_tensor_function.cpp @@ -2,7 +2,6 @@ #include "optimize_tensor_function.h" #include "tensor_function.h" -#include "tensor_engine.h" #include "simple_value.h" #include <vespa/eval/instruction/dense_dot_product_function.h> @@ -82,11 +81,9 @@ const TensorFunction &optimize_for_factory(const ValueBuilderFactory &factory, c } // namespace vespalib::eval::<unnamed> -const TensorFunction &optimize_tensor_function(EngineOrFactory engine, const TensorFunction &function, Stash &stash) { +const TensorFunction &optimize_tensor_function(const ValueBuilderFactory &factory, const TensorFunction &function, Stash &stash) { LOG(debug, "tensor function before optimization:\n%s\n", function.as_string().c_str()); - const TensorFunction &optimized = (engine.is_engine()) - ? engine.engine().optimize(function, stash) - : optimize_for_factory(engine.factory(), function, stash); + const TensorFunction &optimized = optimize_for_factory(factory, function, stash); LOG(debug, "tensor function after optimization:\n%s\n", optimized.as_string().c_str()); return optimized; } diff --git a/eval/src/vespa/eval/eval/optimize_tensor_function.h b/eval/src/vespa/eval/eval/optimize_tensor_function.h index bc2bc10cca6..dfe95f92b40 100644 --- a/eval/src/vespa/eval/eval/optimize_tensor_function.h +++ b/eval/src/vespa/eval/eval/optimize_tensor_function.h @@ -2,14 +2,13 @@ #pragma once -#include "engine_or_factory.h" - namespace vespalib { class Stash; } namespace vespalib::eval { +class ValueBuilderFactory; struct TensorFunction; -const TensorFunction &optimize_tensor_function(EngineOrFactory engine, const TensorFunction &function, Stash &stash); +const TensorFunction &optimize_tensor_function(const ValueBuilderFactory &factory, const TensorFunction &function, Stash &stash); } // namespace vespalib::eval diff --git a/eval/src/vespa/eval/eval/tensor_function.cpp b/eval/src/vespa/eval/eval/tensor_function.cpp index 0492b810d62..fc83889a853 100644 --- a/eval/src/vespa/eval/eval/tensor_function.cpp +++ b/eval/src/vespa/eval/eval/tensor_function.cpp @@ -4,7 +4,6 @@ #include "value.h" #include "operation.h" #include "tensor.h" -#include "tensor_engine.h" #include "visit_stuff.h" #include "string_stuff.h" #include <vespa/eval/instruction/generic_concat.h> @@ -60,151 +59,12 @@ using Instruction = InterpretedFunction::Instruction; //----------------------------------------------------------------------------- -uint64_t to_param(map_fun_t value) { return (uint64_t)value; } -uint64_t to_param(join_fun_t value) { return (uint64_t)value; } -map_fun_t to_map_fun(uint64_t param) { return (map_fun_t)param; } -join_fun_t to_join_fun(uint64_t param) { return (join_fun_t)param; } - -//----------------------------------------------------------------------------- - void op_load_const(State &state, uint64_t param) { state.stack.push_back(unwrap_param<Value>(param)); } //----------------------------------------------------------------------------- -void op_double_map(State &state, uint64_t param) { - state.pop_push(state.stash.create<DoubleValue>(to_map_fun(param)(state.peek(0).as_double()))); -} - -void op_double_mul(State &state, uint64_t) { - state.pop_pop_push(state.stash.create<DoubleValue>(state.peek(1).as_double() * state.peek(0).as_double())); -} - -void op_double_add(State &state, uint64_t) { - state.pop_pop_push(state.stash.create<DoubleValue>(state.peek(1).as_double() + state.peek(0).as_double())); -} - -void op_double_join(State &state, uint64_t param) { - state.pop_pop_push(state.stash.create<DoubleValue>(to_join_fun(param)(state.peek(1).as_double(), state.peek(0).as_double()))); -} - -//----------------------------------------------------------------------------- - -void op_tensor_map(State &state, uint64_t param) { - state.pop_push(state.engine.map(state.peek(0), to_map_fun(param), state.stash)); -} - -void op_tensor_join(State &state, uint64_t param) { - state.pop_pop_push(state.engine.join(state.peek(1), state.peek(0), to_join_fun(param), state.stash)); -} - -void op_tensor_merge(State &state, uint64_t param) { - state.pop_pop_push(state.engine.merge(state.peek(1), state.peek(0), to_join_fun(param), state.stash)); -} - -using ReduceParams = std::pair<Aggr,std::vector<vespalib::string>>; -void op_tensor_reduce(State &state, uint64_t param) { - const ReduceParams ¶ms = unwrap_param<ReduceParams>(param); - state.pop_push(state.engine.reduce(state.peek(0), params.first, params.second, state.stash)); -} - -using RenameParams = std::pair<std::vector<vespalib::string>,std::vector<vespalib::string>>; -void op_tensor_rename(State &state, uint64_t param) { - const RenameParams ¶ms = unwrap_param<RenameParams>(param); - state.pop_push(state.engine.rename(state.peek(0), params.first, params.second, state.stash)); -} - -void op_tensor_concat(State &state, uint64_t param) { - const vespalib::string &dimension = unwrap_param<vespalib::string>(param); - state.pop_pop_push(state.engine.concat(state.peek(1), state.peek(0), dimension, state.stash)); -} - -void op_tensor_create(State &state, uint64_t param) { - const Create &self = unwrap_param<Create>(param); - TensorSpec spec(self.result_type().to_spec()); - size_t i = 0; - for (auto pos = self.map().rbegin(); pos != self.map().rend(); ++pos) { - spec.add(pos->first, state.peek(i++).as_double()); - } - const Value &result = *state.stash.create<Value::UP>(state.engine.from_spec(spec)); - state.pop_n_push(i, result); -} - -struct LambdaParams { - const Lambda &parent; - InterpretedFunction fun; - LambdaParams(const Lambda &parent_in, InterpretedFunction fun_in) - : parent(parent_in), fun(std::move(fun_in)) {} -}; - -void op_tensor_lambda(State &state, uint64_t param) { - const LambdaParams ¶ms = unwrap_param<LambdaParams>(param); - TensorSpec spec = params.parent.create_spec(*state.params, params.fun); - const Value &result = *state.stash.create<Value::UP>(state.engine.from_spec(spec)); - state.stack.emplace_back(result); -} - -const Value &extract_single_value(const TensorSpec &spec, const TensorSpec::Address &addr, State &state) { - auto pos = spec.cells().find(addr); - if (pos == spec.cells().end()) { - return state.stash.create<DoubleValue>(0.0); - } - return state.stash.create<DoubleValue>(pos->second); -} - -const Value &extract_tensor_subspace(const ValueType &my_type, const TensorSpec &spec, const TensorSpec::Address &addr, State &state) { - TensorSpec my_spec(my_type.to_spec()); - for (const auto &cell: spec.cells()) { - bool keep = true; - TensorSpec::Address my_addr; - for (const auto &binding: cell.first) { - auto pos = addr.find(binding.first); - if (pos == addr.end()) { - my_addr.emplace(binding.first, binding.second); - } else { - if (!(pos->second == binding.second)) { - keep = false; - } - } - } - if (keep) { - my_spec.add(my_addr, cell.second); - } - } - return *state.stash.create<Value::UP>(state.engine.from_spec(my_spec)); -} - -void op_tensor_peek(State &state, uint64_t param) { - const Peek &self = unwrap_param<Peek>(param); - TensorSpec::Address addr; - size_t child_cnt = 0; - for (auto pos = self.map().rbegin(); pos != self.map().rend(); ++pos) { - std::visit(vespalib::overload - { - [&](const TensorSpec::Label &label) { - addr.emplace(pos->first, label); - }, - [&](const TensorFunction::Child &) { - double index = state.peek(child_cnt++).as_double(); - size_t dim_idx = self.param_type().dimension_index(pos->first); - assert(dim_idx != ValueType::Dimension::npos); - const auto ¶m_dim = self.param_type().dimensions()[dim_idx]; - if (param_dim.is_mapped()) { - addr.emplace(pos->first, vespalib::make_string("%" PRId64, int64_t(index))); - } else { - addr.emplace(pos->first, size_t(index)); - } - } - }, pos->second); - } - TensorSpec spec = state.engine.to_spec(state.peek(child_cnt++)); - const Value &result = self.result_type().is_double() - ? extract_single_value(spec, addr, state) - : extract_tensor_subspace(self.result_type(), spec, addr, state); - state.pop_n_push(child_cnt, result); -} - } // namespace vespalib::eval::tensor_function::<unnamed> //----------------------------------------------------------------------------- @@ -247,7 +107,7 @@ Op2::visit_children(vespalib::ObjectVisitor &visitor) const //----------------------------------------------------------------------------- Instruction -ConstValue::compile_self(EngineOrFactory, Stash &) const +ConstValue::compile_self(const ValueBuilderFactory &, Stash &) const { return Instruction(op_load_const, wrap_param<Value>(_value)); } @@ -266,7 +126,7 @@ ConstValue::visit_self(vespalib::ObjectVisitor &visitor) const //----------------------------------------------------------------------------- Instruction -Inject::compile_self(EngineOrFactory, Stash &) const +Inject::compile_self(const ValueBuilderFactory &, Stash &) const { return Instruction::fetch_param(_param_idx); } @@ -281,13 +141,9 @@ Inject::visit_self(vespalib::ObjectVisitor &visitor) const //----------------------------------------------------------------------------- Instruction -Reduce::compile_self(EngineOrFactory engine, Stash &stash) const +Reduce::compile_self(const ValueBuilderFactory &factory, Stash &stash) const { - if (engine.is_factory()) { - return instruction::GenericReduce::make_instruction(child().result_type(), aggr(), dimensions(), engine.factory(), stash); - } - ReduceParams ¶ms = stash.create<ReduceParams>(_aggr, _dimensions); - return Instruction(op_tensor_reduce, wrap_param<ReduceParams>(params)); + return instruction::GenericReduce::make_instruction(child().result_type(), aggr(), dimensions(), factory, stash); } void @@ -301,15 +157,9 @@ Reduce::visit_self(vespalib::ObjectVisitor &visitor) const //----------------------------------------------------------------------------- Instruction -Map::compile_self(EngineOrFactory engine, Stash &) const +Map::compile_self(const ValueBuilderFactory &, Stash &) const { - if (engine.is_factory()) { - return instruction::GenericMap::make_instruction(result_type(), _function); - } - if (result_type().is_double()) { - return Instruction(op_double_map, to_param(_function)); - } - return Instruction(op_tensor_map, to_param(_function)); + return instruction::GenericMap::make_instruction(result_type(), _function); } void @@ -322,21 +172,9 @@ Map::visit_self(vespalib::ObjectVisitor &visitor) const //----------------------------------------------------------------------------- Instruction -Join::compile_self(EngineOrFactory engine, Stash &stash) const +Join::compile_self(const ValueBuilderFactory &factory, Stash &stash) const { - if (engine.is_factory()) { - return instruction::GenericJoin::make_instruction(lhs().result_type(), rhs().result_type(), function(), engine.factory(), stash); - } - if (result_type().is_double()) { - if (_function == operation::Mul::f) { - return Instruction(op_double_mul); - } - if (_function == operation::Add::f) { - return Instruction(op_double_add); - } - return Instruction(op_double_join, to_param(_function)); - } - return Instruction(op_tensor_join, to_param(_function)); + return instruction::GenericJoin::make_instruction(lhs().result_type(), rhs().result_type(), function(), factory, stash); } void @@ -349,12 +187,9 @@ Join::visit_self(vespalib::ObjectVisitor &visitor) const //----------------------------------------------------------------------------- Instruction -Merge::compile_self(EngineOrFactory engine, Stash &stash) const +Merge::compile_self(const ValueBuilderFactory &factory, Stash &stash) const { - if (engine.is_factory()) { - return instruction::GenericMerge::make_instruction(lhs().result_type(), rhs().result_type(), function(), engine.factory(), stash); - } - return Instruction(op_tensor_merge, to_param(_function)); + return instruction::GenericMerge::make_instruction(lhs().result_type(), rhs().result_type(), function(), factory, stash); } void @@ -367,12 +202,9 @@ Merge::visit_self(vespalib::ObjectVisitor &visitor) const //----------------------------------------------------------------------------- Instruction -Concat::compile_self(EngineOrFactory engine, Stash &stash) const +Concat::compile_self(const ValueBuilderFactory &factory, Stash &stash) const { - if (engine.is_factory()) { - return instruction::GenericConcat::make_instruction(lhs().result_type(), rhs().result_type(), dimension(), engine.factory(), stash); - } - return Instruction(op_tensor_concat, wrap_param<vespalib::string>(_dimension)); + return instruction::GenericConcat::make_instruction(lhs().result_type(), rhs().result_type(), dimension(), factory, stash); } void @@ -404,12 +236,9 @@ Create::make_spec() const } Instruction -Create::compile_self(EngineOrFactory engine, Stash &stash) const +Create::compile_self(const ValueBuilderFactory &factory, Stash &stash) const { - if (engine.is_factory()) { - return instruction::GenericCreate::make_instruction(result_type(), make_spec(), engine.factory(), stash); - } - return Instruction(op_tensor_create, wrap_param<Create>(*this)); + return instruction::GenericCreate::make_instruction(result_type(), make_spec(), factory, stash); } void @@ -469,14 +298,9 @@ Lambda::create_spec_impl(const ValueType &type, const LazyParams ¶ms, const } InterpretedFunction::Instruction -Lambda::compile_self(EngineOrFactory engine, Stash &stash) const +Lambda::compile_self(const ValueBuilderFactory &factory, Stash &stash) const { - if (engine.is_factory()) { - return instruction::GenericLambda::make_instruction(*this, engine.factory(), stash); - } - InterpretedFunction fun(engine, _lambda->root(), _lambda_types); - LambdaParams ¶ms = stash.create<LambdaParams>(*this, std::move(fun)); - return Instruction(op_tensor_lambda, wrap_param<LambdaParams>(params)); + return instruction::GenericLambda::make_instruction(*this, factory, stash); } void @@ -524,12 +348,9 @@ Peek::make_spec() const } Instruction -Peek::compile_self(EngineOrFactory engine, Stash &stash) const +Peek::compile_self(const ValueBuilderFactory &factory, Stash &stash) const { - if (engine.is_factory()) { - return instruction::GenericPeek::make_instruction(param_type(), result_type(), make_spec(), engine.factory(), stash); - } - return Instruction(op_tensor_peek, wrap_param<Peek>(*this)); + return instruction::GenericPeek::make_instruction(param_type(), result_type(), make_spec(), factory, stash); } void @@ -556,13 +377,9 @@ Peek::visit_children(vespalib::ObjectVisitor &visitor) const //----------------------------------------------------------------------------- Instruction -Rename::compile_self(EngineOrFactory engine, Stash &stash) const +Rename::compile_self(const ValueBuilderFactory &factory, Stash &stash) const { - if (engine.is_factory()) { - return instruction::GenericRename::make_instruction(child().result_type(), from(), to(), engine.factory(), stash); - } - RenameParams ¶ms = stash.create<RenameParams>(_from, _to); - return Instruction(op_tensor_rename, wrap_param<RenameParams>(params)); + return instruction::GenericRename::make_instruction(child().result_type(), from(), to(), factory, stash); } void @@ -583,7 +400,7 @@ If::push_children(std::vector<Child::CREF> &children) const } Instruction -If::compile_self(EngineOrFactory, Stash &) const +If::compile_self(const ValueBuilderFactory &, Stash &) const { // 'if' is handled directly by compile_tensor_function to enable // lazy-evaluation of true/false sub-expressions. diff --git a/eval/src/vespa/eval/eval/tensor_function.h b/eval/src/vespa/eval/eval/tensor_function.h index 3c4eb6c53a4..26d28bac350 100644 --- a/eval/src/vespa/eval/eval/tensor_function.h +++ b/eval/src/vespa/eval/eval/tensor_function.h @@ -21,6 +21,9 @@ namespace vespalib { class Stash; class ObjectVisitor; +// TODO: remove this type injection when the 'tensor' namespace is removed +namespace tensor { using ValueBuilderFactory = vespalib::eval::ValueBuilderFactory; } + namespace eval { class Tensor; @@ -104,10 +107,10 @@ struct TensorFunction * the value stack during execution. * * @return instruction representing the operation of this node - * @param engine the tensor engine used for evaluation + * @param factory the value builder factory used during evaluation * @param stash heterogeneous object store **/ - virtual InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const = 0; + virtual InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const = 0; // for debug dumping vespalib::string as_string() const; @@ -188,7 +191,7 @@ public: ConstValue(const Value &value_in) : Super(value_in.type()), _value(value_in) {} const Value &value() const { return _value; } bool result_is_mutable() const override { return false; } - InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const final override; + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const final override; void visit_self(vespalib::ObjectVisitor &visitor) const override; }; @@ -204,7 +207,7 @@ public: : Super(result_type_in), _param_idx(param_idx_in) {} size_t param_idx() const { return _param_idx; } bool result_is_mutable() const override { return false; } - InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const final override; + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const final override; void visit_self(vespalib::ObjectVisitor &visitor) const override; }; @@ -225,7 +228,7 @@ public: Aggr aggr() const { return _aggr; } const std::vector<vespalib::string> &dimensions() const { return _dimensions; } bool result_is_mutable() const override { return true; } - InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const final override; + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const final override; void visit_self(vespalib::ObjectVisitor &visitor) const override; }; @@ -243,7 +246,7 @@ public: : Super(result_type_in, child_in), _function(function_in) {} map_fun_t function() const { return _function; } bool result_is_mutable() const override { return true; } - InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const override; + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; void visit_self(vespalib::ObjectVisitor &visitor) const override; }; @@ -262,7 +265,7 @@ public: : Super(result_type_in, lhs_in, rhs_in), _function(function_in) {} join_fun_t function() const { return _function; } bool result_is_mutable() const override { return true; } - InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const override; + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; void visit_self(vespalib::ObjectVisitor &visitor) const override; }; @@ -281,7 +284,7 @@ public: : Super(result_type_in, lhs_in, rhs_in), _function(function_in) {} join_fun_t function() const { return _function; } bool result_is_mutable() const override { return true; } - InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const override; + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; void visit_self(vespalib::ObjectVisitor &visitor) const override; }; @@ -300,7 +303,7 @@ public: : Super(result_type_in, lhs_in, rhs_in), _dimension(dimension_in) {} const vespalib::string &dimension() const { return _dimension; } bool result_is_mutable() const override { return true; } - InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const final override; + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const final override; void visit_self(vespalib::ObjectVisitor &visitor) const override; }; @@ -324,7 +327,7 @@ public: using Spec = std::map<TensorSpec::Address, size_t>; Spec make_spec() const; bool result_is_mutable() const override { return true; } - InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const final override; + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const final override; void push_children(std::vector<Child::CREF> &children) const final override; void visit_children(vespalib::ObjectVisitor &visitor) const final override; }; @@ -349,7 +352,7 @@ public: return create_spec_impl(result_type(), params, _bindings, fun); } bool result_is_mutable() const override { return true; } - InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const final override; + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const final override; void visit_self(vespalib::ObjectVisitor &visitor) const override; }; @@ -388,7 +391,7 @@ public: Spec make_spec() const; const ValueType ¶m_type() const { return _param.get().result_type(); } bool result_is_mutable() const override { return true; } - InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const final override; + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const final override; void push_children(std::vector<Child::CREF> &children) const final override; void visit_children(vespalib::ObjectVisitor &visitor) const final override; }; @@ -410,7 +413,7 @@ public: const std::vector<vespalib::string> &from() const { return _from; } const std::vector<vespalib::string> &to() const { return _to; } bool result_is_mutable() const override { return true; } - InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const final override; + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const final override; void visit_self(vespalib::ObjectVisitor &visitor) const override; }; @@ -436,7 +439,7 @@ public: return (true_child().result_is_mutable() && false_child().result_is_mutable()); } - InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const final override; + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const final override; void visit_children(vespalib::ObjectVisitor &visitor) const final override; }; diff --git a/eval/src/vespa/eval/eval/test/eval_fixture.cpp b/eval/src/vespa/eval/eval/test/eval_fixture.cpp index b7b2571ba93..58d8905baf3 100644 --- a/eval/src/vespa/eval/eval/test/eval_fixture.cpp +++ b/eval/src/vespa/eval/eval/test/eval_fixture.cpp @@ -4,6 +4,7 @@ #include "eval_fixture.h" #include "reference_evaluation.h" #include <vespa/eval/eval/make_tensor_function.h> +#include <vespa/eval/eval/value_codec.h> #include <vespa/eval/eval/optimize_tensor_function.h> #include <vespa/vespalib/util/stringfmt.h> @@ -81,14 +82,14 @@ const TensorFunction &maybe_patch(bool allow_mutable, const TensorFunction &plai return root.get(); } -std::vector<Value::UP> make_params(EngineOrFactory engine, const Function &function, +std::vector<Value::UP> make_params(const ValueBuilderFactory &factory, const Function &function, const ParamRepo ¶m_repo) { std::vector<Value::UP> result; for (size_t i = 0; i < function.num_params(); ++i) { auto pos = param_repo.map.find(function.param_name(i)); ASSERT_TRUE(pos != param_repo.map.end()); - result.push_back(engine.from_spec(pos->second.value)); + result.push_back(value_from_spec(pos->second.value, factory)); } return result; } @@ -188,29 +189,29 @@ EvalFixture::detect_param_tampering(const ParamRepo ¶m_repo, bool allow_muta ASSERT_TRUE(pos != param_repo.map.end()); bool allow_tampering = allow_mutable && pos->second.is_mutable; if (!allow_tampering) { - ASSERT_EQUAL(pos->second.value, _engine.to_spec(*_param_values[i])); + ASSERT_EQUAL(pos->second.value, spec_from_value(*_param_values[i])); } } } -EvalFixture::EvalFixture(EngineOrFactory engine, +EvalFixture::EvalFixture(const ValueBuilderFactory &factory, const vespalib::string &expr, const ParamRepo ¶m_repo, bool optimized, bool allow_mutable) - : _engine(engine), + : _factory(factory), _stash(), _function(verify_function(Function::parse(expr))), _node_types(get_types(*_function, param_repo)), _mutable_set(get_mutable(*_function, param_repo)), - _plain_tensor_function(make_tensor_function(_engine, _function->root(), _node_types, _stash)), + _plain_tensor_function(make_tensor_function(_factory, _function->root(), _node_types, _stash)), _patched_tensor_function(maybe_patch(allow_mutable, _plain_tensor_function, _mutable_set, _stash)), - _tensor_function(optimized ? optimize_tensor_function(engine, _patched_tensor_function, _stash) : _patched_tensor_function), - _ifun(_engine, _tensor_function), + _tensor_function(optimized ? optimize_tensor_function(_factory, _patched_tensor_function, _stash) : _patched_tensor_function), + _ifun(_factory, _tensor_function), _ictx(_ifun), - _param_values(make_params(_engine, *_function, param_repo)), + _param_values(make_params(_factory, *_function, param_repo)), _params(get_refs(_param_values)), - _result(_engine.to_spec(_ifun.eval(_ictx, _params))) + _result(spec_from_value(_ifun.eval(_ictx, _params))) { auto result_type = ValueType::from_spec(_result.type()); ASSERT_TRUE(!result_type.is_error()); @@ -221,7 +222,7 @@ const TensorSpec EvalFixture::get_param(size_t idx) const { ASSERT_LESS(idx, _param_values.size()); - return _engine.to_spec(*(_param_values[idx])); + return spec_from_value(*(_param_values[idx])); } size_t diff --git a/eval/src/vespa/eval/eval/test/eval_fixture.h b/eval/src/vespa/eval/eval/test/eval_fixture.h index b02424169a1..dc49cf7e4dc 100644 --- a/eval/src/vespa/eval/eval/test/eval_fixture.h +++ b/eval/src/vespa/eval/eval/test/eval_fixture.h @@ -44,7 +44,7 @@ public: }; private: - EngineOrFactory _engine; + const ValueBuilderFactory &_factory; Stash _stash; std::shared_ptr<Function const> _function; NodeTypes _node_types; @@ -73,7 +73,7 @@ private: void detect_param_tampering(const ParamRepo ¶m_repo, bool allow_mutable) const; public: - EvalFixture(EngineOrFactory engine, const vespalib::string &expr, const ParamRepo ¶m_repo, + EvalFixture(const ValueBuilderFactory &factory, const vespalib::string &expr, const ParamRepo ¶m_repo, bool optimized = true, bool allow_mutable = false); ~EvalFixture() {} template <typename T> diff --git a/eval/src/vespa/eval/eval/value_cache/constant_tensor_loader.cpp b/eval/src/vespa/eval/eval/value_cache/constant_tensor_loader.cpp index 2005caa18ec..b14892d4c1c 100644 --- a/eval/src/vespa/eval/eval/value_cache/constant_tensor_loader.cpp +++ b/eval/src/vespa/eval/eval/value_cache/constant_tensor_loader.cpp @@ -2,8 +2,8 @@ #include "constant_tensor_loader.h" #include <vespa/eval/eval/tensor.h> -#include <vespa/eval/eval/tensor_engine.h> #include <vespa/eval/eval/tensor_spec.h> +#include <vespa/eval/eval/value_codec.h> #include <vespa/vespalib/objects/nbostream.h> #include <vespa/vespalib/io/mapped_file_input.h> #include <vespa/vespalib/data/lz4_input_decoder.h> @@ -82,7 +82,7 @@ ConstantTensorLoader::create(const vespalib::string &path, const vespalib::strin vespalib::Memory content = file.get(); vespalib::nbostream stream(content.data, content.size); try { - return std::make_unique<SimpleConstantValue>(_engine.decode(stream)); + return std::make_unique<SimpleConstantValue>(decode_value(stream, _factory)); } catch (std::exception &) { return std::make_unique<BadConstantValue>(); } @@ -104,7 +104,7 @@ ConstantTensorLoader::create(const vespalib::string &path, const vespalib::strin spec.add(address, cells[i]["value"].asDouble()); } try { - return std::make_unique<SimpleConstantValue>(_engine.from_spec(spec)); + return std::make_unique<SimpleConstantValue>(value_from_spec(spec, _factory)); } catch (std::exception &) { return std::make_unique<BadConstantValue>(); } diff --git a/eval/src/vespa/eval/eval/value_cache/constant_tensor_loader.h b/eval/src/vespa/eval/eval/value_cache/constant_tensor_loader.h index 8fb6460efcf..1f32b3119c5 100644 --- a/eval/src/vespa/eval/eval/value_cache/constant_tensor_loader.h +++ b/eval/src/vespa/eval/eval/value_cache/constant_tensor_loader.h @@ -3,7 +3,6 @@ #pragma once #include "constant_value.h" -#include <vespa/eval/eval/engine_or_factory.h> #include <vespa/vespalib/stllike/string.h> namespace vespalib { @@ -12,16 +11,14 @@ namespace eval { /** * A ConstantValueFactory that will load constant tensor values from * file. The file is expected to be in json format with the same - * structure used when feeding. The tensor is created by first - * building a generic TensorSpec object and then converting it to a - * specific tensor using the TensorEngine interface. + * structure used when feeding. **/ class ConstantTensorLoader : public ConstantValueFactory { private: - EngineOrFactory _engine; + const ValueBuilderFactory &_factory; public: - ConstantTensorLoader(EngineOrFactory engine) : _engine(engine) {} + ConstantTensorLoader(const ValueBuilderFactory &factory) : _factory(factory) {} ConstantValue::UP create(const vespalib::string &path, const vespalib::string &type) const override; }; diff --git a/eval/src/vespa/eval/instruction/dense_cell_range_function.cpp b/eval/src/vespa/eval/instruction/dense_cell_range_function.cpp index 5f43e16088d..18ccb33fadf 100644 --- a/eval/src/vespa/eval/instruction/dense_cell_range_function.cpp +++ b/eval/src/vespa/eval/instruction/dense_cell_range_function.cpp @@ -37,7 +37,7 @@ DenseCellRangeFunction::DenseCellRangeFunction(const ValueType &result_type, DenseCellRangeFunction::~DenseCellRangeFunction() = default; InterpretedFunction::Instruction -DenseCellRangeFunction::compile_self(EngineOrFactory, Stash &) const +DenseCellRangeFunction::compile_self(const ValueBuilderFactory &, Stash &) const { assert(result_type().cell_type() == child().result_type().cell_type()); diff --git a/eval/src/vespa/eval/instruction/dense_cell_range_function.h b/eval/src/vespa/eval/instruction/dense_cell_range_function.h index 07793f5d72c..b201e15c49f 100644 --- a/eval/src/vespa/eval/instruction/dense_cell_range_function.h +++ b/eval/src/vespa/eval/instruction/dense_cell_range_function.h @@ -24,7 +24,7 @@ public: ~DenseCellRangeFunction() override; size_t offset() const { return _offset; } size_t length() const { return _length; } - InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const override; + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; bool result_is_mutable() const override { return child().result_is_mutable(); } }; diff --git a/eval/src/vespa/eval/instruction/dense_dot_product_function.cpp b/eval/src/vespa/eval/instruction/dense_dot_product_function.cpp index 5dcfcba025d..ce27bec35d4 100644 --- a/eval/src/vespa/eval/instruction/dense_dot_product_function.cpp +++ b/eval/src/vespa/eval/instruction/dense_dot_product_function.cpp @@ -67,7 +67,7 @@ DenseDotProductFunction::DenseDotProductFunction(const TensorFunction &lhs_in, } InterpretedFunction::Instruction -DenseDotProductFunction::compile_self(EngineOrFactory, Stash &) const +DenseDotProductFunction::compile_self(const ValueBuilderFactory &, Stash &) const { auto op = my_select(lhs().result_type().cell_type(), rhs().result_type().cell_type()); return InterpretedFunction::Instruction(op); diff --git a/eval/src/vespa/eval/instruction/dense_dot_product_function.h b/eval/src/vespa/eval/instruction/dense_dot_product_function.h index d1c1c0538fc..efdfbf561fa 100644 --- a/eval/src/vespa/eval/instruction/dense_dot_product_function.h +++ b/eval/src/vespa/eval/instruction/dense_dot_product_function.h @@ -14,7 +14,7 @@ class DenseDotProductFunction : public tensor_function::Op2 public: DenseDotProductFunction(const TensorFunction &lhs_in, const TensorFunction &rhs_in); - InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const override; + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; bool result_is_mutable() const override { return true; } static bool compatible_types(const ValueType &res, const ValueType &lhs, const ValueType &rhs); static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash); diff --git a/eval/src/vespa/eval/instruction/dense_lambda_peek_function.cpp b/eval/src/vespa/eval/instruction/dense_lambda_peek_function.cpp index 5e9ff6a0ef0..c590feb3d4c 100644 --- a/eval/src/vespa/eval/instruction/dense_lambda_peek_function.cpp +++ b/eval/src/vespa/eval/instruction/dense_lambda_peek_function.cpp @@ -53,7 +53,7 @@ DenseLambdaPeekFunction::DenseLambdaPeekFunction(const ValueType &result_type, DenseLambdaPeekFunction::~DenseLambdaPeekFunction() = default; InterpretedFunction::Instruction -DenseLambdaPeekFunction::compile_self(EngineOrFactory, Stash &stash) const +DenseLambdaPeekFunction::compile_self(const ValueBuilderFactory &, Stash &stash) const { const Self &self = stash.create<Self>(result_type(), *_idx_fun); using MyTypify = TypifyCellType; diff --git a/eval/src/vespa/eval/instruction/dense_lambda_peek_function.h b/eval/src/vespa/eval/instruction/dense_lambda_peek_function.h index c7432ed72ee..ecd0a15a86e 100644 --- a/eval/src/vespa/eval/instruction/dense_lambda_peek_function.h +++ b/eval/src/vespa/eval/instruction/dense_lambda_peek_function.h @@ -23,7 +23,7 @@ public: const TensorFunction &child, std::shared_ptr<Function const> idx_fun); ~DenseLambdaPeekFunction() override; - InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const override; + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; vespalib::string idx_fun_dump() const; bool result_is_mutable() const override { return true; } }; diff --git a/eval/src/vespa/eval/instruction/dense_matmul_function.cpp b/eval/src/vespa/eval/instruction/dense_matmul_function.cpp index 5d4ebb88931..66b4fe05cde 100644 --- a/eval/src/vespa/eval/instruction/dense_matmul_function.cpp +++ b/eval/src/vespa/eval/instruction/dense_matmul_function.cpp @@ -160,7 +160,7 @@ DenseMatMulFunction::DenseMatMulFunction(const ValueType &result_type, DenseMatMulFunction::~DenseMatMulFunction() = default; InterpretedFunction::Instruction -DenseMatMulFunction::compile_self(EngineOrFactory, Stash &stash) const +DenseMatMulFunction::compile_self(const ValueBuilderFactory &, Stash &stash) const { using MyTypify = TypifyValue<TypifyCellType,TypifyBool>; Self &self = stash.create<Self>(result_type(), _lhs_size, _common_size, _rhs_size); diff --git a/eval/src/vespa/eval/instruction/dense_matmul_function.h b/eval/src/vespa/eval/instruction/dense_matmul_function.h index 6e4093e70f3..a5432a7d86f 100644 --- a/eval/src/vespa/eval/instruction/dense_matmul_function.h +++ b/eval/src/vespa/eval/instruction/dense_matmul_function.h @@ -50,7 +50,7 @@ public: bool lhs_common_inner() const { return _lhs_common_inner; } bool rhs_common_inner() const { return _rhs_common_inner; } - InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const override; + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; void visit_self(vespalib::ObjectVisitor &visitor) const override; static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash); }; diff --git a/eval/src/vespa/eval/instruction/dense_multi_matmul_function.cpp b/eval/src/vespa/eval/instruction/dense_multi_matmul_function.cpp index 42e7deb9523..a5ece2e84cd 100644 --- a/eval/src/vespa/eval/instruction/dense_multi_matmul_function.cpp +++ b/eval/src/vespa/eval/instruction/dense_multi_matmul_function.cpp @@ -177,7 +177,7 @@ DenseMultiMatMulFunction::DenseMultiMatMulFunction(const ValueType &result_type, DenseMultiMatMulFunction::~DenseMultiMatMulFunction() = default; InterpretedFunction::Instruction -DenseMultiMatMulFunction::compile_self(EngineOrFactory, Stash &) const +DenseMultiMatMulFunction::compile_self(const ValueBuilderFactory &, Stash &) const { auto op = my_select(lhs().result_type().cell_type()); return InterpretedFunction::Instruction(op, wrap_param<DenseMultiMatMulFunction>(*this)); diff --git a/eval/src/vespa/eval/instruction/dense_multi_matmul_function.h b/eval/src/vespa/eval/instruction/dense_multi_matmul_function.h index 289ba6c4d89..3038bdf7fdc 100644 --- a/eval/src/vespa/eval/instruction/dense_multi_matmul_function.h +++ b/eval/src/vespa/eval/instruction/dense_multi_matmul_function.h @@ -44,7 +44,7 @@ public: bool lhs_common_inner() const { return _lhs_common_inner; } bool rhs_common_inner() const { return _rhs_common_inner; } - InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const override; + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; void visit_self(vespalib::ObjectVisitor &visitor) const override; static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash); }; diff --git a/eval/src/vespa/eval/instruction/dense_simple_expand_function.cpp b/eval/src/vespa/eval/instruction/dense_simple_expand_function.cpp index d0318d371f5..4f2551211db 100644 --- a/eval/src/vespa/eval/instruction/dense_simple_expand_function.cpp +++ b/eval/src/vespa/eval/instruction/dense_simple_expand_function.cpp @@ -95,7 +95,7 @@ DenseSimpleExpandFunction::DenseSimpleExpandFunction(const ValueType &result_typ DenseSimpleExpandFunction::~DenseSimpleExpandFunction() = default; Instruction -DenseSimpleExpandFunction::compile_self(EngineOrFactory, Stash &stash) const +DenseSimpleExpandFunction::compile_self(const ValueBuilderFactory &, Stash &stash) const { size_t result_size = result_type().dense_subspace_size(); const ExpandParams ¶ms = stash.create<ExpandParams>(result_type(), result_size, function()); diff --git a/eval/src/vespa/eval/instruction/dense_simple_expand_function.h b/eval/src/vespa/eval/instruction/dense_simple_expand_function.h index cca051fcde9..4abb3d5df02 100644 --- a/eval/src/vespa/eval/instruction/dense_simple_expand_function.h +++ b/eval/src/vespa/eval/instruction/dense_simple_expand_function.h @@ -32,7 +32,7 @@ public: Inner inner_in); ~DenseSimpleExpandFunction() override; Inner inner() const { return _inner; } - InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const override; + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash); }; diff --git a/eval/src/vespa/eval/instruction/dense_tensor_peek_function.cpp b/eval/src/vespa/eval/instruction/dense_tensor_peek_function.cpp index fd93cd62fa9..323909227f7 100644 --- a/eval/src/vespa/eval/instruction/dense_tensor_peek_function.cpp +++ b/eval/src/vespa/eval/instruction/dense_tensor_peek_function.cpp @@ -61,7 +61,7 @@ DenseTensorPeekFunction::push_children(std::vector<Child::CREF> &target) const } InterpretedFunction::Instruction -DenseTensorPeekFunction::compile_self(EngineOrFactory, Stash &) const +DenseTensorPeekFunction::compile_self(const ValueBuilderFactory &, Stash &) const { using MyTypify = TypifyCellType; auto op = typify_invoke<1,MyTypify,MyTensorPeekOp>(_children[0].get().result_type().cell_type()); diff --git a/eval/src/vespa/eval/instruction/dense_tensor_peek_function.h b/eval/src/vespa/eval/instruction/dense_tensor_peek_function.h index 37979cd592d..bfd217991aa 100644 --- a/eval/src/vespa/eval/instruction/dense_tensor_peek_function.h +++ b/eval/src/vespa/eval/instruction/dense_tensor_peek_function.h @@ -26,7 +26,7 @@ public: ~DenseTensorPeekFunction(); const ValueType &result_type() const override { return DoubleValue::shared_type(); } void push_children(std::vector<Child::CREF> &children) const override; - InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const override; + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; bool result_is_mutable() const override { return true; } static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash); }; diff --git a/eval/src/vespa/eval/instruction/dense_xw_product_function.cpp b/eval/src/vespa/eval/instruction/dense_xw_product_function.cpp index 44332bbacee..3727e782718 100644 --- a/eval/src/vespa/eval/instruction/dense_xw_product_function.cpp +++ b/eval/src/vespa/eval/instruction/dense_xw_product_function.cpp @@ -137,7 +137,7 @@ DenseXWProductFunction::DenseXWProductFunction(const ValueType &result_type, } InterpretedFunction::Instruction -DenseXWProductFunction::compile_self(EngineOrFactory, Stash &stash) const +DenseXWProductFunction::compile_self(const ValueBuilderFactory &, Stash &stash) const { Self &self = stash.create<Self>(result_type(), _vector_size, _result_size); using MyTypify = TypifyValue<TypifyCellType,vespalib::TypifyBool>; diff --git a/eval/src/vespa/eval/instruction/dense_xw_product_function.h b/eval/src/vespa/eval/instruction/dense_xw_product_function.h index e66afa72f93..6883c8a981f 100644 --- a/eval/src/vespa/eval/instruction/dense_xw_product_function.h +++ b/eval/src/vespa/eval/instruction/dense_xw_product_function.h @@ -44,7 +44,7 @@ public: size_t result_size() const { return _result_size; } bool common_inner() const { return _common_inner; } - InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const override; + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; void visit_self(vespalib::ObjectVisitor &visitor) const override; static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash); }; diff --git a/eval/src/vespa/eval/instruction/join_with_number_function.cpp b/eval/src/vespa/eval/instruction/join_with_number_function.cpp index dd3512a5e74..cd95a109e60 100644 --- a/eval/src/vespa/eval/instruction/join_with_number_function.cpp +++ b/eval/src/vespa/eval/instruction/join_with_number_function.cpp @@ -73,7 +73,7 @@ JoinWithNumberFunction::inplace() const { using MyTypify = TypifyValue<TypifyCellType,vespalib::TypifyBool,operation::TypifyOp2>; InterpretedFunction::Instruction -JoinWithNumberFunction::compile_self(EngineOrFactory, Stash &) const +JoinWithNumberFunction::compile_self(const ValueBuilderFactory &, Stash &) const { auto op = typify_invoke<4,MyTypify,SelectJoinWithNumberOp>(result_type().cell_type(), _function, diff --git a/eval/src/vespa/eval/instruction/join_with_number_function.h b/eval/src/vespa/eval/instruction/join_with_number_function.h index 6e3f9aa4106..351f9b005cb 100644 --- a/eval/src/vespa/eval/instruction/join_with_number_function.h +++ b/eval/src/vespa/eval/instruction/join_with_number_function.h @@ -26,7 +26,7 @@ public: bool inplace() const; bool result_is_mutable() const override { return true; } - InterpretedFunction::Instruction compile_self(EngineOrFactory engine, Stash &stash) const override; + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; void visit_self(vespalib::ObjectVisitor &visitor) const override; static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash); }; diff --git a/eval/src/vespa/eval/tensor/default_tensor_engine.cpp b/eval/src/vespa/eval/tensor/default_tensor_engine.cpp index 68c8dc990c6..3ac342217ac 100644 --- a/eval/src/vespa/eval/tensor/default_tensor_engine.cpp +++ b/eval/src/vespa/eval/tensor/default_tensor_engine.cpp @@ -27,6 +27,7 @@ #include "dense/dense_tensor_create_function.h" #include <vespa/eval/instruction/dense_tensor_peek_function.h> #include <vespa/eval/eval/value.h> +#include <vespa/eval/eval/engine_or_factory.h> #include <vespa/eval/eval/tensor_spec.h> #include <vespa/eval/eval/simple_value.h> #include <vespa/eval/eval/operation.h> diff --git a/eval/src/vespa/eval/tensor/dense/dense_lambda_function.cpp b/eval/src/vespa/eval/tensor/dense/dense_lambda_function.cpp index 95d90a02a9e..cdbe396dda4 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_lambda_function.cpp +++ b/eval/src/vespa/eval/tensor/dense/dense_lambda_function.cpp @@ -3,7 +3,6 @@ #include "dense_lambda_function.h" #include "dense_tensor_view.h" #include <vespa/vespalib/objects/objectvisitor.h> -#include <vespa/eval/tensor/default_tensor_engine.h> #include <vespa/eval/eval/llvm/compiled_function.h> #include <vespa/eval/eval/llvm/compile_cache.h> #include <assert.h> @@ -15,7 +14,6 @@ using eval::CompiledFunction; using eval::InterpretedFunction; using eval::LazyParams; using eval::PassParams; -using eval::TensorEngine; using eval::TensorFunction; using eval::Value; using eval::DoubleValue; @@ -103,11 +101,11 @@ struct InterpretedParams { const std::vector<size_t> &bindings; size_t num_cells; InterpretedFunction fun; - InterpretedParams(const Lambda &lambda, eval::EngineOrFactory engine) + InterpretedParams(const Lambda &lambda, const ValueBuilderFactory &factory) : result_type(lambda.result_type()), bindings(lambda.bindings()), num_cells(result_type.dense_subspace_size()), - fun(engine, lambda.lambda().root(), lambda.types()) + fun(factory, lambda.lambda().root(), lambda.types()) { assert(lambda.lambda().num_params() == (result_type.dimensions().size() + bindings.size())); } @@ -157,7 +155,7 @@ DenseLambdaFunction::eval_mode() const } Instruction -DenseLambdaFunction::compile_self(eval::EngineOrFactory engine, Stash &stash) const +DenseLambdaFunction::compile_self(const ValueBuilderFactory &factory, Stash &stash) const { auto mode = eval_mode(); using MyTypify = eval::TypifyCellType; @@ -167,7 +165,7 @@ DenseLambdaFunction::compile_self(eval::EngineOrFactory engine, Stash &stash) co return Instruction(op, wrap_param<CompiledParams>(params)); } else { assert(mode == EvalMode::INTERPRETED); - InterpretedParams ¶ms = stash.create<InterpretedParams>(_lambda, engine); + InterpretedParams ¶ms = stash.create<InterpretedParams>(_lambda, factory); auto op = typify_invoke<1,MyTypify,MyInterpretedLambdaOp>(result_type().cell_type()); return Instruction(op, wrap_param<InterpretedParams>(params)); } diff --git a/eval/src/vespa/eval/tensor/dense/dense_lambda_function.h b/eval/src/vespa/eval/tensor/dense/dense_lambda_function.h index e82c022d781..6698bb44ef0 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_lambda_function.h +++ b/eval/src/vespa/eval/tensor/dense/dense_lambda_function.h @@ -23,7 +23,7 @@ public: ~DenseLambdaFunction() override; bool result_is_mutable() const override { return true; } EvalMode eval_mode() const; - eval::InterpretedFunction::Instruction compile_self(eval::EngineOrFactory engine, Stash &stash) const override; + eval::InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash); }; diff --git a/eval/src/vespa/eval/tensor/dense/dense_number_join_function.cpp b/eval/src/vespa/eval/tensor/dense/dense_number_join_function.cpp index c41743200da..d4b1ee4506e 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_number_join_function.cpp +++ b/eval/src/vespa/eval/tensor/dense/dense_number_join_function.cpp @@ -96,7 +96,7 @@ DenseNumberJoinFunction::inplace() const } Instruction -DenseNumberJoinFunction::compile_self(eval::EngineOrFactory, Stash &) const +DenseNumberJoinFunction::compile_self(const ValueBuilderFactory &, Stash &) const { auto op = typify_invoke<4,MyTypify,MyGetFun>(result_type().cell_type(), function(), inplace(), (_primary == Primary::RHS)); diff --git a/eval/src/vespa/eval/tensor/dense/dense_number_join_function.h b/eval/src/vespa/eval/tensor/dense/dense_number_join_function.h index c4478ce43b6..3acbd83e1bb 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_number_join_function.h +++ b/eval/src/vespa/eval/tensor/dense/dense_number_join_function.h @@ -27,7 +27,7 @@ public: ~DenseNumberJoinFunction() override; Primary primary() const { return _primary; } bool inplace() const; - eval::InterpretedFunction::Instruction compile_self(eval::EngineOrFactory engine, Stash &stash) const override; + eval::InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash); }; diff --git a/eval/src/vespa/eval/tensor/dense/dense_replace_type_function.cpp b/eval/src/vespa/eval/tensor/dense/dense_replace_type_function.cpp index 004edf06d92..c12ad21c7fb 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_replace_type_function.cpp +++ b/eval/src/vespa/eval/tensor/dense/dense_replace_type_function.cpp @@ -34,7 +34,7 @@ DenseReplaceTypeFunction::~DenseReplaceTypeFunction() } eval::InterpretedFunction::Instruction -DenseReplaceTypeFunction::compile_self(eval::EngineOrFactory, Stash &) const +DenseReplaceTypeFunction::compile_self(const ValueBuilderFactory &, Stash &) const { return eval::InterpretedFunction::Instruction(my_replace_type_op, wrap_param<ValueType>(result_type())); } diff --git a/eval/src/vespa/eval/tensor/dense/dense_replace_type_function.h b/eval/src/vespa/eval/tensor/dense/dense_replace_type_function.h index 504d3f1649b..adf5023b0cb 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_replace_type_function.h +++ b/eval/src/vespa/eval/tensor/dense/dense_replace_type_function.h @@ -16,7 +16,7 @@ public: DenseReplaceTypeFunction(const eval::ValueType &result_type, const eval::TensorFunction &child); ~DenseReplaceTypeFunction(); - eval::InterpretedFunction::Instruction compile_self(eval::EngineOrFactory engine, Stash &stash) const override; + eval::InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; bool result_is_mutable() const override { return child().result_is_mutable(); } static const DenseReplaceTypeFunction &create_compact(const eval::ValueType &result_type, const eval::TensorFunction &child, diff --git a/eval/src/vespa/eval/tensor/dense/dense_simple_join_function.cpp b/eval/src/vespa/eval/tensor/dense/dense_simple_join_function.cpp index f492d12f05a..02867f646b4 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_simple_join_function.cpp +++ b/eval/src/vespa/eval/tensor/dense/dense_simple_join_function.cpp @@ -191,7 +191,7 @@ DenseSimpleJoinFunction::factor() const } Instruction -DenseSimpleJoinFunction::compile_self(eval::EngineOrFactory, Stash &stash) const +DenseSimpleJoinFunction::compile_self(const ValueBuilderFactory &, Stash &stash) const { const JoinParams ¶ms = stash.create<JoinParams>(result_type(), factor(), function()); auto op = typify_invoke<6,MyTypify,MyGetFun>(lhs().result_type().cell_type(), diff --git a/eval/src/vespa/eval/tensor/dense/dense_simple_join_function.h b/eval/src/vespa/eval/tensor/dense/dense_simple_join_function.h index 2cd918e1b06..4cb4a0fc4ff 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_simple_join_function.h +++ b/eval/src/vespa/eval/tensor/dense/dense_simple_join_function.h @@ -32,7 +32,7 @@ public: Overlap overlap() const { return _overlap; } bool primary_is_mutable() const; size_t factor() const; - eval::InterpretedFunction::Instruction compile_self(eval::EngineOrFactory engine, Stash &stash) const override; + eval::InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash); }; diff --git a/eval/src/vespa/eval/tensor/dense/dense_simple_map_function.cpp b/eval/src/vespa/eval/tensor/dense/dense_simple_map_function.cpp index d3297b335d3..4c7b1b3dee8 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_simple_map_function.cpp +++ b/eval/src/vespa/eval/tensor/dense/dense_simple_map_function.cpp @@ -72,7 +72,7 @@ DenseSimpleMapFunction::DenseSimpleMapFunction(const ValueType &result_type, DenseSimpleMapFunction::~DenseSimpleMapFunction() = default; Instruction -DenseSimpleMapFunction::compile_self(eval::EngineOrFactory, Stash &) const +DenseSimpleMapFunction::compile_self(const ValueBuilderFactory &, Stash &) const { auto op = typify_invoke<3,MyTypify,MyGetFun>(result_type().cell_type(), function(), inplace()); static_assert(sizeof(uint64_t) == sizeof(function())); diff --git a/eval/src/vespa/eval/tensor/dense/dense_simple_map_function.h b/eval/src/vespa/eval/tensor/dense/dense_simple_map_function.h index ce0498c9ab7..02a81ec137b 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_simple_map_function.h +++ b/eval/src/vespa/eval/tensor/dense/dense_simple_map_function.h @@ -18,7 +18,7 @@ public: map_fun_t function_in); ~DenseSimpleMapFunction() override; bool inplace() const { return child().result_is_mutable(); } - eval::InterpretedFunction::Instruction compile_self(eval::EngineOrFactory engine, Stash &stash) const override; + eval::InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash); }; diff --git a/eval/src/vespa/eval/tensor/dense/dense_single_reduce_function.cpp b/eval/src/vespa/eval/tensor/dense/dense_single_reduce_function.cpp index 5f688657645..c692f7c4a0f 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_single_reduce_function.cpp +++ b/eval/src/vespa/eval/tensor/dense/dense_single_reduce_function.cpp @@ -236,7 +236,7 @@ DenseSingleReduceFunction::DenseSingleReduceFunction(const DenseSingleReduceSpec DenseSingleReduceFunction::~DenseSingleReduceFunction() = default; InterpretedFunction::Instruction -DenseSingleReduceFunction::compile_self(eval::EngineOrFactory, Stash &stash) const +DenseSingleReduceFunction::compile_self(const ValueBuilderFactory &, Stash &stash) const { auto op = typify_invoke<4,MyTypify,MyGetFun>(result_type().cell_type(), _aggr, (_reduce_size >= 8), (_inner_size == 1)); diff --git a/eval/src/vespa/eval/tensor/dense/dense_single_reduce_function.h b/eval/src/vespa/eval/tensor/dense/dense_single_reduce_function.h index f2db3155290..8bdcf82d4ab 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_single_reduce_function.h +++ b/eval/src/vespa/eval/tensor/dense/dense_single_reduce_function.h @@ -48,7 +48,7 @@ public: size_t inner_size() const { return _inner_size; } eval::Aggr aggr() const { return _aggr; } bool result_is_mutable() const override { return true; } - eval::InterpretedFunction::Instruction compile_self(eval::EngineOrFactory engine, Stash &stash) const override; + eval::InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash); }; diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_create_function.cpp b/eval/src/vespa/eval/tensor/dense/dense_tensor_create_function.cpp index 4b7f4936815..f425ce4fd1c 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_tensor_create_function.cpp +++ b/eval/src/vespa/eval/tensor/dense/dense_tensor_create_function.cpp @@ -69,7 +69,7 @@ DenseTensorCreateFunction::push_children(std::vector<Child::CREF> &target) const } eval::InterpretedFunction::Instruction -DenseTensorCreateFunction::compile_self(eval::EngineOrFactory, Stash &) const +DenseTensorCreateFunction::compile_self(const ValueBuilderFactory &, Stash &) const { using MyTypify = eval::TypifyCellType; auto op = typify_invoke<1,MyTypify,MyTensorCreateOp>(result_type().cell_type()); diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_create_function.h b/eval/src/vespa/eval/tensor/dense/dense_tensor_create_function.h index a2ca71ce894..c0c238a2a89 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_tensor_create_function.h +++ b/eval/src/vespa/eval/tensor/dense/dense_tensor_create_function.h @@ -25,7 +25,7 @@ public: ~DenseTensorCreateFunction(); const eval::ValueType &result_type() const override { return _self.result_type; } void push_children(std::vector<Child::CREF> &children) const override; - eval::InterpretedFunction::Instruction compile_self(eval::EngineOrFactory engine, Stash &stash) const override; + eval::InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; bool result_is_mutable() const override { return true; } static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash); }; diff --git a/eval/src/vespa/eval/tensor/dense/vector_from_doubles_function.cpp b/eval/src/vespa/eval/tensor/dense/vector_from_doubles_function.cpp index ac91d073fd7..a5e26665741 100644 --- a/eval/src/vespa/eval/tensor/dense/vector_from_doubles_function.cpp +++ b/eval/src/vespa/eval/tensor/dense/vector_from_doubles_function.cpp @@ -92,7 +92,7 @@ VectorFromDoublesFunction::push_children(std::vector<Child::CREF> &target) const } eval::InterpretedFunction::Instruction -VectorFromDoublesFunction::compile_self(eval::EngineOrFactory, Stash &) const +VectorFromDoublesFunction::compile_self(const ValueBuilderFactory &, Stash &) const { return eval::InterpretedFunction::Instruction(my_vector_from_doubles_op, wrap_param<VectorFromDoublesFunction::Self>(_self)); } diff --git a/eval/src/vespa/eval/tensor/dense/vector_from_doubles_function.h b/eval/src/vespa/eval/tensor/dense/vector_from_doubles_function.h index e2bd0386331..d21a339e7d9 100644 --- a/eval/src/vespa/eval/tensor/dense/vector_from_doubles_function.h +++ b/eval/src/vespa/eval/tensor/dense/vector_from_doubles_function.h @@ -30,7 +30,7 @@ public: return _self.resultType.dimensions()[0].name; } size_t size() const { return _self.resultSize; } - eval::InterpretedFunction::Instruction compile_self(eval::EngineOrFactory engine, Stash &stash) const override; + eval::InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; bool result_is_mutable() const override { return true; } static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash); }; |