gemini-code-assist[bot] commented on code in PR #19926:
URL: https://github.com/apache/tvm/pull/19926#discussion_r3510319126


##########
src/tirx/ir/expr_functor.cc:
##########
@@ -27,6 +27,31 @@
 namespace tvm {
 namespace tirx {
 
+void ExprVisitor::VisitExpr(const Expr& expr) {
+  if (auto prim = expr.as<PrimExpr>()) {
+    return this->VisitExpr(prim.value());
+  }
+  if (const auto* op = expr.as<SizeVarNode>()) return VisitExpr_(op);
+  if (const auto* op = expr.as<VarNode>()) return VisitExpr_(op);
+  if (const auto* op = expr.as<CallNode>()) return VisitExpr_(op);
+  if (const auto* op = expr.as<StringImmNode>()) return VisitExpr_(op);
+  TVM_FFI_THROW(TypeError) << "Unsupported non-primitive expression: " << 
expr->GetTypeKey();
+}
+
+Expr ExprMutator::VisitExpr(const Expr& expr) {
+  if (auto prim = expr.as<PrimExpr>()) {
+    return this->VisitExpr(prim.value());
+  }
+  if (expr.as<VarNode>() || expr.as<StringImmNode>()) return expr;

Review Comment:
   ![high](https://www.gstatic.com/codereviewagent/high-priority.svg)
   
   By returning `expr` directly for `VarNode` without calling `VisitExpr_`, any 
custom mutator that overrides `VisitExpr_(const VarNode*)` or `VisitExpr_(const 
SizeVarNode*)` will fail to mutate/remap variables when they are encountered as 
generic `Expr`s (such as in `BindNode::value` or `CallNode::args`).\n\nWe 
should dispatch `VarNode` and `SizeVarNode` to their respective `VisitExpr_` 
methods, similar to how `ExprVisitor::VisitExpr` does.
   
   ```c
     if (const auto* op = expr.as<SizeVarNode>()) return 
this->VisitExpr_(op);\n  if (const auto* op = expr.as<VarNode>()) return 
this->VisitExpr_(op);\n  if (expr.as<StringImmNode>()) return expr;
   ```



##########
src/target/source/codegen_c.cc:
##########
@@ -996,13 +1010,13 @@ void CodeGenC::VisitExpr_(const LetNode* op, 
std::ostream& os) {  // NOLINT(*)
     var_idmap_[op->var.get()] = value;
   } else {
     PrintIndent();
-    if (op->var.ty().IsHandle() && handle_data_type_.count(op->var.get())) {
+    if (op->var->ty.as<PointerTypeNode>() && 
handle_data_type_.count(op->var.get())) {

Review Comment:
   ![medium](https://www.gstatic.com/codereviewagent/medium-priority.svg)
   
   Checking only `op->var->ty.as<PointerTypeNode>()` misses the case where the 
variable's type is a `PrimType` of handle type. This causes the code to bypass 
the `handle_data_type_` lookup and print generic handle types instead of the 
specific pointer types.\n\nWe should use the same robust `is_pointer` check 
that was implemented in `PrintFunctionSignature`.
   
   ```c
       bool is_pointer = op->var->ty.as<PointerTypeNode>() ||\n                 
     (op->var->ty.as<PrimTypeNode>() && op->var.ty().IsHandle());\n    if 
(is_pointer && handle_data_type_.count(op->var.get())) {
   ```



##########
src/arith/ir_mutator_with_analyzer.cc:
##########
@@ -203,17 +203,18 @@ Stmt IRMutatorWithAnalyzer::VisitStmt_(const SBlockNode* 
op) {
 }
 
 Stmt IRMutatorWithAnalyzer::VisitStmt_(const BindNode* op) {
-  PrimExpr value = this->VisitExpr(op->value);
+  ffi::Optional<PrimExpr> prim_value = op->value.as<PrimExpr>();
+  if (!prim_value.defined()) {
+    return ffi::GetRef<Stmt>(op);
+  }
+  PrimExpr value = this->VisitExpr(prim_value.value());
   if (SideEffect(value) <= CallEffectKind::kPure) {
     analyzer_->Bind(op->var, value);
   }
-  if (value.same_as(op->value)) {
-    return ffi::GetRef<Stmt>(op);
-  } else {
-    auto n = this->CopyOnWrite(op);
-    n->value = std::move(value);
-    return Stmt(n);
-  }
+  if (value.same_as(op->value)) return ffi::GetRef<Stmt>(op);
+  auto n = this->CopyOnWrite(op);
+  n->value = std::move(value);
+  return Stmt(n);

Review Comment:
   ![high](https://www.gstatic.com/codereviewagent/high-priority.svg)
   
   Returning early when `op->value` is not a `PrimExpr` completely skips 
mutating non-primitive bindings (such as pointer-typed bindings). This means 
any nested variables or expressions inside these bindings will not be 
mutated/remapped.\n\nWe should mutate `op->value` as an `Expr` first, and then 
conditionally bind to the analyzer if the mutated value is a `PrimExpr`.
   
   ```c
     Expr value = this->VisitExpr(op->value);\n  if (auto prim_value = 
value.as<PrimExpr>()) {\n    if (SideEffect(prim_value.value()) <= 
CallEffectKind::kPure) {\n      analyzer_->Bind(op->var, prim_value.value());\n 
   }\n  }\n  if (value.same_as(op->value)) return ffi::GetRef<Stmt>(op);\n  
auto n = this->CopyOnWrite(op);\n  n->value = std::move(value);\n  return 
Stmt(n);
   ```



##########
src/arith/ir_visitor_with_analyzer.cc:
##########
@@ -50,8 +50,10 @@ void IRVisitorWithAnalyzer::VisitStmt_(const SBlockNode* op) 
{
 }
 
 void IRVisitorWithAnalyzer::VisitStmt_(const BindNode* op) {
-  this->VisitExpr(op->value);
-  analyzer_->Bind(op->var, op->value);
+  if (ffi::Optional<PrimExpr> value = op->value.as<PrimExpr>()) {
+    this->VisitExpr(value.value());
+    analyzer_->Bind(op->var, value.value());
+  }

Review Comment:
   ![high](https://www.gstatic.com/codereviewagent/high-priority.svg)
   
   Skipping the visit of `op->value` when it is not a `PrimExpr` means that any 
variables or sub-expressions inside non-primitive bindings will not be visited. 
This can break analyses that rely on visiting all expressions in the AST.\n\nWe 
should visit `op->value` as an `Expr` first, and then conditionally bind to the 
analyzer if it is a `PrimExpr`.
   
   ```c
     this->VisitExpr(op->value);\n  if (ffi::Optional<PrimExpr> value = 
op->value.as<PrimExpr>()) {\n    analyzer_->Bind(op->var, value.value());\n  }
   ```



##########
src/target/source/codegen_c.cc:
##########
@@ -1121,13 +1135,13 @@ void CodeGenC::VisitStmt_(const BindNode* op) {
     var_idmap_[op->var.get()] = value;
   } else {
     PrintIndent();
-    if (op->var.ty().IsHandle() && handle_data_type_.count(op->var.get())) {
+    if (op->var->ty.as<PointerTypeNode>() && 
handle_data_type_.count(op->var.get())) {

Review Comment:
   ![medium](https://www.gstatic.com/codereviewagent/medium-priority.svg)
   
   Checking only `op->var->ty.as<PointerTypeNode>()` misses the case where the 
variable's type is a `PrimType` of handle type. This causes the code to bypass 
the `handle_data_type_` lookup and print generic handle types instead of the 
specific pointer types.\n\nWe should use the same robust `is_pointer` check 
that was implemented in `PrintFunctionSignature`.
   
   ```c
       bool is_pointer = op->var->ty.as<PointerTypeNode>() ||\n                 
     (op->var->ty.as<PrimTypeNode>() && op->var.ty().IsHandle());\n    if 
(is_pointer && handle_data_type_.count(op->var.get())) {
   ```



-- 
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]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to