diff options
author | Arne Juul <arnej@verizonmedia.com> | 2021-03-10 13:20:53 +0000 |
---|---|---|
committer | Arne Juul <arnej@verizonmedia.com> | 2021-03-11 09:08:50 +0000 |
commit | e9f62f97dd3162be72690625b26cd95fd1c14c5b (patch) | |
tree | 47642ef028f8c5814848b8ae6b5b0b8e9aceb45a /eval | |
parent | dbd2b74348866390972450dd30818bf82f803401 (diff) |
prepare GenericMap for different input/output cell types
* also, use apply_op1_vec when possible, from MixedMapFunction
* now uses a MapParam, to wire the result type in an uniform manner
Diffstat (limited to 'eval')
4 files changed, 58 insertions, 23 deletions
diff --git a/eval/src/tests/instruction/generic_map/generic_map_test.cpp b/eval/src/tests/instruction/generic_map/generic_map_test.cpp index bfa7154968d..54ba0ea2a31 100644 --- a/eval/src/tests/instruction/generic_map/generic_map_test.cpp +++ b/eval/src/tests/instruction/generic_map/generic_map_test.cpp @@ -35,11 +35,13 @@ const std::vector<GenSpec> map_layouts = { TensorSpec perform_generic_map(const TensorSpec &a, map_fun_t func, const ValueBuilderFactory &factory) { + Stash stash; auto lhs = value_from_spec(a, factory); auto res_type = lhs->type().map(); - auto my_op = GenericMap::make_instruction(res_type, lhs->type(), func); + auto my_op = GenericMap::make_instruction(res_type, lhs->type(), func, stash); InterpretedFunction::EvalSingle single(factory, my_op); - return spec_from_value(single.eval(std::vector<Value::CREF>({*lhs}))); + const auto & v = single.eval(std::vector<Value::CREF>({*lhs})); + return spec_from_value(v); } void test_generic_map_with(const ValueBuilderFactory &factory) { diff --git a/eval/src/vespa/eval/eval/tensor_function.cpp b/eval/src/vespa/eval/eval/tensor_function.cpp index fd8b20bfed0..c0cd7280212 100644 --- a/eval/src/vespa/eval/eval/tensor_function.cpp +++ b/eval/src/vespa/eval/eval/tensor_function.cpp @@ -158,9 +158,9 @@ Reduce::visit_self(vespalib::ObjectVisitor &visitor) const //----------------------------------------------------------------------------- Instruction -Map::compile_self(const ValueBuilderFactory &, Stash &) const +Map::compile_self(const ValueBuilderFactory &, Stash &stash) const { - return instruction::GenericMap::make_instruction(result_type(), child().result_type(), _function); + return instruction::GenericMap::make_instruction(result_type(), child().result_type(), _function, stash); } void diff --git a/eval/src/vespa/eval/instruction/generic_map.cpp b/eval/src/vespa/eval/instruction/generic_map.cpp index 4f6780c2276..9e584422b01 100644 --- a/eval/src/vespa/eval/instruction/generic_map.cpp +++ b/eval/src/vespa/eval/instruction/generic_map.cpp @@ -1,8 +1,9 @@ // Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "generic_map.h" -#include <vespa/eval/eval/value.h> #include <vespa/eval/eval/inline_operation.h> +#include <vespa/eval/eval/value.h> +#include <vespa/eval/eval/wrap_param.h> #include <vespa/vespalib/util/stash.h> #include <vespa/vespalib/util/typify.h> #include <cassert> @@ -11,54 +12,84 @@ namespace vespalib::eval::instruction { using State = InterpretedFunction::State; using Instruction = InterpretedFunction::Instruction; +using vespalib::eval::tensor_function::unwrap_param; +using vespalib::eval::tensor_function::wrap_param; + +struct MapParam { + const ValueType res_type; + const map_fun_t function; + MapParam(const ValueType &r, map_fun_t f) : res_type(r), function(f) {} +}; namespace { -uint64_t to_param(map_fun_t value) { return (uint64_t)value; } -map_fun_t to_map_fun(uint64_t param) { return (map_fun_t)param; } +template <typename ICT, typename OCT, typename Func> +void my_generic_map_op(State &state, uint64_t param_in) { + const auto ¶m = unwrap_param<MapParam>(param_in); + Func function(param.function); + const Value &a = state.peek(0); + auto input_cells = a.cells().typify<ICT>(); + auto output_cells = state.stash.create_uninitialized_array<OCT>(input_cells.size()); + auto pos = output_cells.begin(); + for (ICT value : input_cells) { + *pos++ = (OCT) function(value); + } + assert(pos == output_cells.end()); + ValueType &result_type = state.stash.create<ValueType>(param.res_type); + // XXX: could we refer to param.res_type from ValueView instead? + Value &result_ref = state.stash.create<ValueView>(result_type, a.index(), TypedCells(output_cells)); + state.pop_push(result_ref); +} template <typename CT, typename Func> -void my_generic_map_op(State &state, uint64_t param_in) { - Func function(to_map_fun(param_in)); +void my_simple_map_op(State &state, uint64_t param_in) { + const auto ¶m = unwrap_param<MapParam>(param_in); + Func function(param.function); const Value &a = state.peek(0); auto input_cells = a.cells().typify<CT>(); auto output_cells = state.stash.create_uninitialized_array<CT>(input_cells.size()); auto pos = output_cells.begin(); - for (CT value : input_cells) { - *pos++ = (CT) function(value); - } - assert(pos == output_cells.end()); + apply_op1_vec(pos, input_cells.begin(), output_cells.size(), function); Value &result_ref = state.stash.create<ValueView>(a.type(), a.index(), TypedCells(output_cells)); state.pop_push(result_ref); } template <typename Func> void my_double_map_op(State &state, uint64_t param_in) { - Func fun(to_map_fun(param_in)); + const auto ¶m = unwrap_param<MapParam>(param_in); + Func fun(param.function); state.pop_push(state.stash.create<DoubleValue>(fun(state.peek(0).as_double()))); } struct SelectGenericMapOp { - template <typename CT, typename Func> static auto invoke(const ValueType &type) { - if (type.is_double()) { - assert((std::is_same_v<CT,double>)); + template <typename ICM, typename Func> static auto invoke() { + if constexpr (ICM::value.is_scalar) { return my_double_map_op<Func>; } - return my_generic_map_op<CT, Func>; + using ICT = CellValueType<ICM::value.cell_type>; + using OCT = CellValueType<ICM::value.map().cell_type>; + if constexpr (std::is_same<ICT,OCT>::value) { + return my_simple_map_op<ICT, Func>; + } else { + return my_generic_map_op<ICT, OCT, Func>; + } } }; } // namespace <unnamed> -using MapTypify = TypifyValue<TypifyCellType,operation::TypifyOp1>; +using MapTypify = TypifyValue<TypifyCellMeta,operation::TypifyOp1>; InterpretedFunction::Instruction GenericMap::make_instruction(const ValueType &result_type, - const ValueType &input_type, map_fun_t function) + const ValueType &input_type, + map_fun_t function, + Stash &stash) { + const auto ¶m = stash.create<MapParam>(result_type, function); assert(result_type == input_type.map()); - auto op = typify_invoke<2,MapTypify,SelectGenericMapOp>(input_type.cell_type(), function, input_type); - return Instruction(op, to_param(function)); + auto op = typify_invoke<2,MapTypify,SelectGenericMapOp>(input_type.cell_meta(), function); + return Instruction(op, wrap_param<MapParam>(param)); } } // namespace diff --git a/eval/src/vespa/eval/instruction/generic_map.h b/eval/src/vespa/eval/instruction/generic_map.h index f6c01760898..6878546018d 100644 --- a/eval/src/vespa/eval/instruction/generic_map.h +++ b/eval/src/vespa/eval/instruction/generic_map.h @@ -15,7 +15,9 @@ using map_fun_t = operation::op1_t; struct GenericMap { static InterpretedFunction::Instruction make_instruction(const ValueType &result_type, - const ValueType &input_type, map_fun_t function); + const ValueType &input_type, + map_fun_t function, + Stash &stash); }; } // namespace |