| 178 | } |
| 179 | |
| 180 | void Compile(XlaOpKernelContext* ctx) override { |
| 181 | xla::XlaBuilder* b = ctx->builder(); |
| 182 | |
| 183 | XlaResource* resource; |
| 184 | OP_REQUIRES_OK(ctx, ctx->GetResourceInput(0, &resource)); |
| 185 | |
| 186 | // There is a somewhat subtle issue here: here "uninitialized" means we have |
| 187 | // not yet seen a pop in the order that we compile operators, not the order |
| 188 | // that we run them. However, in practice the two orders should be the same |
| 189 | // for the sole user of the stack operators (loop gradients). |
| 190 | OP_REQUIRES(ctx, resource->initialized(), |
| 191 | errors::InvalidArgument("Stack pop on uninitialized stack")); |
| 192 | |
| 193 | TensorShape stack_shape; |
| 194 | OP_REQUIRES_OK(ctx, GetStackShape(b, resource, &stack_shape)); |
| 195 | |
| 196 | xla::XlaOp state = resource->value(); |
| 197 | xla::XlaOp ta = xla::GetTupleElement(state, 0); |
| 198 | xla::XlaOp index = xla::GetTupleElement(state, 1); |
| 199 | |
| 200 | index = Sub(index, xla::ConstantR0<int32>(b, 1)); |
| 201 | OP_REQUIRES_OK(ctx, resource->SetValue(xla::Tuple(b, {ta, index}))); |
| 202 | |
| 203 | // start_indices of the DynamicSlice are [index, 0, 0, ..., 0]. |
| 204 | std::vector<xla::XlaOp> start_indices(stack_shape.dims(), |
| 205 | xla::ConstantR0<int32>(b, 0)); |
| 206 | start_indices[0] = index; |
| 207 | |
| 208 | auto slice_shape = stack_shape.dim_sizes(); |
| 209 | slice_shape[0] = 1LL; |
| 210 | |
| 211 | // TODO(phawkins): We don't check the index is in bounds --- there is no |
| 212 | // error mechanism in XLA. |
| 213 | xla::XlaOp read = xla::DynamicSlice(ta, start_indices, slice_shape); |
| 214 | |
| 215 | // Remove the leading '1' dimension. |
| 216 | std::vector<int64> value_shape(slice_shape.begin() + 1, slice_shape.end()); |
| 217 | ctx->SetOutput(0, xla::Reshape(read, value_shape)); |
| 218 | } |
| 219 | |
| 220 | private: |
| 221 | DataType dtype_; |
nothing calls this directly
no test coverage detected