| 461 | } |
| 462 | |
| 463 | void XlaOpKernelContext::SetOutputExpression(int index, |
| 464 | const XlaExpression& expression) { |
| 465 | Status status = [&] { |
| 466 | // The step's default allocator is the dummy XlaCompilationAllocator which |
| 467 | // simply allocates a metadata buffer to hold the expression to which it |
| 468 | // corresponds. |
| 469 | // Provides a special behavior for DT_VARIANT and other types that are not |
| 470 | // trivially copyable. In those cases, allocate a tensor of type DT_UINT8. |
| 471 | if (!DataTypeCanUseMemcpy(expression.dtype())) { |
| 472 | // tensor_data() is not supported for tensors that cannot be copied via |
| 473 | // memcpy, as the copy logic might try to inspect the stored data (e.g. |
| 474 | // a std::string). This is likely to fail, as the data is invalid given |
| 475 | // that it actually encodes an XlaExpression. Using a uint8 tensor is |
| 476 | // always safe, so simply do that. |
| 477 | // TODO(jpienaar): This should be refactored to stop masquerading |
| 478 | // XlaExpressions as Tensors. |
| 479 | Tensor output; |
| 480 | TensorShape tensor_shape; |
| 481 | TF_RETURN_IF_ERROR( |
| 482 | context_->allocate_temp(DT_UINT8, tensor_shape, &output)); |
| 483 | context_->set_output(index, output); |
| 484 | } else { |
| 485 | Tensor* output = nullptr; |
| 486 | TF_ASSIGN_OR_RETURN(TensorShape shape, expression.GetShape()); |
| 487 | TF_RETURN_IF_ERROR(context_->allocate_output(index, shape, &output)); |
| 488 | } |
| 489 | AssignExpressionToTensor(context_->mutable_output(index), expression); |
| 490 | return Status::OK(); |
| 491 | }(); |
| 492 | if (!status.ok()) { |
| 493 | SetStatus(status); |
| 494 | } |
| 495 | } |
| 496 | |
| 497 | xla::PrimitiveType XlaOpKernelContext::output_xla_type(int index) { |
| 498 | xla::PrimitiveType type; |
no test coverage detected