1use crate::tensor::DeviceTensorExt;
2use crate::utils::compute_broadcast_strides;
3use tract_core::internal::*;
4use tract_core::ops::array::Slice;
5
6#[derive(Clone, Debug, PartialEq, Eq, Hash)]
7pub struct GpuSlice {
8 pub inner: Slice,
9}
10
11impl GpuSlice {
12 pub fn new(inner: Slice) -> Self {
13 Self { inner }
14 }
15}
16
17impl Op for GpuSlice {
18 fn name(&self) -> StaticName {
19 "GpuSlice".into()
20 }
21
22 fn info(&self) -> TractResult<Vec<String>> {
23 self.inner.info()
24 }
25
26 op_as_typed_op!();
27}
28
29impl EvalOp for GpuSlice {
30 op_out_of_plan!();
31
32 fn eval(&self, ctx: &EvalContext, inputs: TVec<TValue>) -> TractResult<TVec<TValue>> {
33 let input_value = args_1!(inputs);
34 let input = input_value.to_device_tensor()?;
35
36 let start = self.inner.start.eval(ctx.symbols).to_usize()?;
37 let end = self.inner.end.eval(ctx.symbols).to_usize()?;
38 let axis = self.inner.axis;
39
40 let input_shape = input.shape();
41 let input_strides = input.strides();
42 let input_dt = input.datum_type();
43
44 ensure!(
45 end <= input_shape[axis] && start <= end,
46 "Invalid range {}..{} for slicing {:?} on axis {}",
47 start,
48 end,
49 input,
50 axis
51 );
52
53 let mut o_shape: TVec<usize> = input_shape.into();
54 o_shape[axis] = end - start;
55
56 let offset = (start * input_strides[axis] as usize) * input_dt.size_of();
57
58 let output = crate::turn_handler::make_tensor_for_node(ctx, input.datum_type(), &o_shape)?;
59
60 if o_shape[axis] != 0 {
61 let broadcast_strides: TVec<isize> =
63 compute_broadcast_strides(&o_shape, input_strides)?;
64 let ctx = crate::device::get_context()?;
65 ctx.copy_nd(
66 input,
67 offset,
68 &broadcast_strides,
69 &output,
70 0,
71 output.shape(),
72 output.strides(),
73 )?;
74 }
75 Ok(tvec![output.into_tensor().into_tvalue()])
76 }
77}
78
79impl TypedOp for GpuSlice {
80 fn output_facts(&self, inputs: &[&TypedFact]) -> TractResult<TVec<TypedFact>> {
81 crate::utils::facts_to_device_facts(inputs, |facts| self.inner.output_facts(facts))
82 .with_context(|| format!("Error while computing facts for {:?}", self.name()))
83 }
84
85 fn set_symbols(
86 &self,
87 _source: &TypedModel,
88 node: &TypedNode,
89 target: &mut TypedModel,
90 mapping: &HashMap<OutletId, OutletId>,
91 subs: &HashMap<Symbol, TDim>,
92 ) -> TractResult<TVec<OutletId>> {
93 let op = GpuSlice {
94 inner: Slice {
95 axis: self.inner.axis,
96 start: self.inner.start.substitute_all(subs)?,
97 end: self.inner.end.substitute_all(subs)?,
98 },
99 };
100 let inputs = node.inputs.iter().map(|i| mapping[i]).collect::<TVec<_>>();
101 target.wire_node(&node.name, op, &inputs)
102 }
103
104 as_op!();
105}