Lunderberg commented on code in PR #17145:
URL: https://github.com/apache/tvm/pull/17145#discussion_r1672412396


##########
python/tvm/relax/op/memory/view.py:
##########
@@ -92,3 +92,20 @@ def _normalize(expr, relax_cls):
     relative_byte_offset = _normalize(relative_byte_offset, PrimValue)
 
     return _ffi_api.view(data, shape, dtype, relative_byte_offset)  # type: 
ignore
+
+
+def ensure_aligned(data: Expr) -> Expr:

Review Comment:
   Can we rename this to `ensure_zero_offset`?  The alignment for a view 
depends on whether `byte_offset % desired_alignment == 0`, not whether 
`byte_offset==0`.  That is, a buffer with a non-zero `byte_offset` can be 
aligned.



##########
src/relax/op/memory/view.cc:
##########
@@ -355,5 +354,28 @@ TVM_REGISTER_OP("relax.memory.view")
     .set_attr<FLegalize>("FLegalize", LegalizeView)
     .set_attr<Bool>("FPurity", Bool(true));
 
+Expr ensure_aligned(const Expr& x) {

Review Comment:
   Same name change request here, to replace `ensure_aligned` with 
`ensure_zero_offset`.



##########
src/runtime/relax_vm/builtin.cc:
##########
@@ -545,6 +545,19 @@ 
TVM_REGISTER_GLOBAL("vm.builtin.tensor_to_shape").set_body_typed([](NDArray data
   return ShapeTuple(out_shape);
 });
 
+TVM_REGISTER_GLOBAL("vm.builtin.ensure_aligned").set_body_typed([](NDArray 
data) {
+  if (data->byte_offset == 0) {
+    return data;
+  }
+  DLManagedTensor* dl_tensor = data.ToDLPack();
+  dl_tensor->dl_tensor.data =
+      reinterpret_cast<char*>(dl_tensor->dl_tensor.data) + 
dl_tensor->dl_tensor.byte_offset;
+  dl_tensor->dl_tensor.byte_offset = 0;
+  // For platforms that does not support pointer arithmetic, we need to copy 
the data to a new
+  // buffer.
+  return NDArray::FromDLPack(dl_tensor);

Review Comment:
   This constructs a new `NDArray`, but does not actually copy the data.  
Instead, `NDArray::FromDLPack` takes ownership of the `DLManagedTensor*`.  The 
pointer arithmetic performed earlier would still be invalid.



##########
src/relax/backend/vm/vm_builtin_lower.cc:
##########
@@ -124,6 +128,19 @@ class VMBuiltinLowerMutator : public ExprMutator {
     }
   }
 
+  Expr View(const Call& view_node) {

Review Comment:
   The handling of `R.memory.view` is already handled by 
`relax.transform.LegalizeOps`, and doesn't require any additional handling here.



##########
src/relax/transform/static_plan_block_memory.cc:
##########
@@ -286,8 +286,13 @@ class TokenAllocator1D {
   std::vector<StorageToken> full_pool_;
 };
 
-/*! \brief Check if the input op is "relax.reshape". */
-bool IsReshape(const Expr& op) { return op.same_as(Op::Get("relax.reshape")); }
+/*! \brief Check if the input op is a memory op that return the same buffer as 
the input buffer. */

Review Comment:
   Nitpick: Replace "a memory op that return the same buffer" with "a memory op 
that **may** return the same buffer", since it isn't guaranteed whether 
`ensure_zero_offset` will return a copy or an alias.



##########
src/runtime/relax_vm/builtin.cc:
##########
@@ -545,6 +545,19 @@ 
TVM_REGISTER_GLOBAL("vm.builtin.tensor_to_shape").set_body_typed([](NDArray data
   return ShapeTuple(out_shape);
 });
 
+TVM_REGISTER_GLOBAL("vm.builtin.ensure_aligned").set_body_typed([](NDArray 
data) {
+  if (data->byte_offset == 0) {
+    return data;
+  }
+  DLManagedTensor* dl_tensor = data.ToDLPack();
+  dl_tensor->dl_tensor.data =

Review Comment:
   This pointer addition is not valid on all targets.  Can we add a method to 
the `DeviceAPI` that returns a boolean, indicating whether the host may perform 
pointer arithmetic on a `DLTensor::data` pointer?



##########
src/relax/op/memory/view.cc:
##########
@@ -334,13 +334,12 @@ Expr LegalizeView(const BlockBuilder& bb, const Call& 
call) {
     relative_byte_offset = relax::PrimValue::Int64(0);
   }
 
-  StructInfoDeriveFunc infer_sinfo_env_func;
-  infer_sinfo_env_func = 
EnvFunc::Get("tvm.relax.struct_info.infer_view_sinfo");
-  auto runtime_view_sinfo = FuncStructInfo::OpaqueFunc(infer_sinfo_env_func, 
true);
-
-  ExternFunc runtime_view_func("runtime.TVMArrayCreateView", 
runtime_view_sinfo);
+  if (shape.same_as(call->args[1]) && dtype.same_as(call->args[2]) &&
+      relative_byte_offset.same_as(call->args[3])) {
+    return call;
+  }
 
-  return Call(runtime_view_func, {data, shape, dtype, relative_byte_offset});
+  return Call(call->op, {data, shape, dtype, relative_byte_offset});

Review Comment:
   This change means that `R.memory.view` is still present in the output of 
`LegalizeOps`, but a legalization function should replace the operator with a 
lowered form.



##########
tests/python/relax/test_op_view.py:
##########
@@ -483,18 +483,7 @@ def main(A: R.Tensor([4096], "float32")):
     class Expected:
         @R.function
         def main(A: R.Tensor([4096], "float32")):
-            B = R.ExternFunc(
-                "runtime.TVMArrayCreateView",
-                R.Callable(
-                    derive_func="tvm.relax.struct_info.infer_view_sinfo",
-                    purity=True,
-                ),
-            )(
-                A,
-                R.shape([64, 64]),
-                R.dtype("float32"),
-                R.prim_value(0),
-            )
+            B = R.memory.view(A, shape=R.shape([64, 64]), dtype="float32", 
relative_byte_offset=0)

Review Comment:
   I don't think this is the desired behavior for `R.memory.view`, as the 
operator hasn't actually been legalized.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to