This is an automated email from the ASF dual-hosted git repository.

tqchen pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm.git


The following commit(s) were added to refs/heads/main by this push:
     new 42c3faf17e [REFACTOR][LLVM] Express AArch64 SME state as function 
attributes (#20568)
42c3faf17e is described below

commit 42c3faf17e8785012ab3225ab92d445152c3d102
Author: Tianqi Chen <[email protected]>
AuthorDate: Tue Oct 6 12:19:14 2026 -0400

    [REFACTOR][LLVM] Express AArch64 SME state as function attributes (#20568)
---
 src/target/llvm/codegen_aarch64.cc | 104 ++++++++++++++++++++-----------------
 src/target/llvm/codegen_cpu.cc     |   2 +-
 src/target/llvm/codegen_cpu.h      |   2 +
 3 files changed, 60 insertions(+), 48 deletions(-)

diff --git a/src/target/llvm/codegen_aarch64.cc 
b/src/target/llvm/codegen_aarch64.cc
index 414b9a75c4..3c62ca095c 100644
--- a/src/target/llvm/codegen_aarch64.cc
+++ b/src/target/llvm/codegen_aarch64.cc
@@ -40,18 +40,68 @@ class CodeGenAArch64 final : public CodeGenCPU {
   CodeGenAArch64() = default;
   virtual ~CodeGenAArch64() = default;
 
-  void Dispatch_(const AttrStmtNode* op);
-  void AddFunction(const GlobalVar& gvar, const PrimFunc& f);
-  void SetTargetAttributes(llvm::Function* func);
+  llvm::Function* DeclareFunction(const GlobalVar& gvar, const PrimFunc& f) 
override;
+  void AddFunction(const GlobalVar& gvar, const PrimFunc& f) override;
+  void SetTargetAttributes(llvm::Function* func) override;
 
-  bool func_has_pstate_sm = false;
-  bool func_has_pstate_za = false;
+ private:
+  void SetComputeScopeAttributes(llvm::Function* func) override;
+  void SetPStateAttributes(llvm::Function* func, const PrimFunc& f);
+
+  ffi::Optional<PrimFunc> current_prim_func_;
+  llvm::Function* packed_function_{nullptr};
 };
 
+llvm::Function* CodeGenAArch64::DeclareFunction(const GlobalVar& gvar, const 
PrimFunc& f) {
+  llvm::Function* func = CodeGenCPU::DeclareFunction(gvar, f);
+  if (f->GetAttr<CallingConv>(tvm::attr::kCallingConv) != 
CallingConv::kCPackedFunc) {
+    SetPStateAttributes(func, f);
+  }
+  return func;
+}
+
 void CodeGenAArch64::AddFunction(const GlobalVar& gvar, const PrimFunc& f) {
-  func_has_pstate_sm = false;
-  func_has_pstate_za = false;
+  llvm::Function* func = DeclareFunction(gvar, f);
+  current_prim_func_ = f;
+  packed_function_ = f->GetAttr<CallingConv>(tvm::attr::kCallingConv) == 
CallingConv::kCPackedFunc
+                         ? func
+                         : nullptr;
   CodeGenCPU::AddFunction(gvar, f);
+  current_prim_func_ = std::nullopt;
+  packed_function_ = nullptr;
+}
+
+void CodeGenAArch64::SetComputeScopeAttributes(llvm::Function* func) {
+  CodeGenCPU::SetComputeScopeAttributes(func);
+  // MakePackedAPI keeps PrimFunc attrs on the packed wrapper, but the SME 
contract belongs
+  // to its outlined compute function. Runtime callbacks and nested helpers 
have separate ABIs.
+  if (function_ == packed_function_) {
+    SetPStateAttributes(func, current_prim_func_.value());
+  }
+}
+
+void CodeGenAArch64::SetPStateAttributes(llvm::Function* func, const PrimFunc& 
f) {
+  // These string PrimFunc attrs are exposed directly through T.func_attr and 
with_attr.
+  if (auto sm = f->GetAttr<ffi::String>("aarch64_pstate_sm")) {
+    // A locally streaming body does not change a bodyless declaration's 
interface.
+    if (sm.value() != "body" || f->body.has_value()) {
+      func->addFnAttr(MakeStringRef("aarch64_pstate_sm_" + sm.value()));
+    }
+  }
+  if (auto za = f->GetAttr<ffi::String>("aarch64_pstate_za")) {
+#if TVM_LLVM_VERSION >= 190
+    // LLVM 19 renamed the new/shared policies. Keep the legacy spelling for 
preserved:
+    // aarch64_preserves_za describes a shared interface, unlike the old 
private interface.
+    if (za.value() == "new") {
+      func->addFnAttr("aarch64_new_za");
+    } else if (za.value() == "shared") {
+      func->addFnAttr("aarch64_inout_za");
+    } else
+#endif
+    {
+      func->addFnAttr(MakeStringRef("aarch64_pstate_za_" + za.value()));
+    }
+  }
 }
 
 void CodeGenAArch64::SetTargetAttributes(llvm::Function* func) {
@@ -80,46 +130,6 @@ void CodeGenAArch64::SetTargetAttributes(llvm::Function* 
func) {
   CodeGenCPU::SetTargetAttributes(func);
 }
 
-/*!
- * \brief Visit and handle AArch64 specific pragmas. To be AArch64 specific,
- * the expectation is that they are prepended with "pragma_aarch64".
- */
-void CodeGenAArch64::Dispatch_(const AttrStmtNode* op) {
-  std::string attr_key = op->attr_key;
-
-  if (!tirx::attr::IsPragmaKey(attr_key)) {
-    CodeGenCPU::Dispatch_(op);
-    return;
-  }
-  bool is_aarch64_specific_pragma = attr_key.substr(7, 7) == "aarch64";
-  if (!is_aarch64_specific_pragma) {
-    CodeGenCPU::Dispatch_(op);
-    return;
-  }
-
-  const auto* attr_value = op->value.as<StringImmNode>();
-  TVM_FFI_ICHECK(attr_value) << "Expect " << attr_key << " to have a 
ffi::String value but was "
-                             << op->value->GetTypeKey();
-
-  std::string aarch64_attr_key = attr_key.substr(7);
-  if (aarch64_attr_key == "aarch64_pstate_sm") {
-    TVM_FFI_ICHECK(!func_has_pstate_sm)
-        << "Multiple definitions of " << op->attr_key << " attribute found in 
the function "
-        << function_->getName().data();
-    function_->addFnAttr({aarch64_attr_key + "_" + attr_value->value});
-    func_has_pstate_sm = true;
-  } else if (aarch64_attr_key == "aarch64_pstate_za") {
-    TVM_FFI_ICHECK(!func_has_pstate_za)
-        << "Multiple definitions of " << op->attr_key << " attribute found in 
the function "
-        << function_->getName().data();
-    function_->addFnAttr({aarch64_attr_key + "_" + attr_value->value});
-    func_has_pstate_za = true;
-  } else {
-    LOG(WARNING) << "Unknown pragma " << op->attr_key;
-  }
-  this->Dispatch(op->body);
-}
-
 TVM_FFI_STATIC_INIT_BLOCK() {
   namespace refl = tvm::ffi::reflection;
   refl::GlobalDef().def_packed("tvm.codegen.llvm.target_aarch64",
diff --git a/src/target/llvm/codegen_cpu.cc b/src/target/llvm/codegen_cpu.cc
index c71a659b64..bb42c87b5b 100644
--- a/src/target/llvm/codegen_cpu.cc
+++ b/src/target/llvm/codegen_cpu.cc
@@ -559,7 +559,7 @@ void CodeGenCPU::CreateComputeScope(const AttrStmtNode* op) 
{
   TVM_FFI_ICHECK(value != nullptr);
   llvm::Function* fcompute = llvm::Function::Create(ftype, 
llvm::Function::InternalLinkage,
                                                     
MakeStringRef(value->value), module_.get());
-  SetTargetAttributes(fcompute);
+  SetComputeScopeAttributes(fcompute);
   for (auto it = fcompute->arg_begin(); it != fcompute->arg_end(); it++) {
     const Var& var = vargs[std::distance(fcompute->arg_begin(), it)];
     it->setName(std::string(var->name));
diff --git a/src/target/llvm/codegen_cpu.h b/src/target/llvm/codegen_cpu.h
index dd9dc57436..a73210d151 100644
--- a/src/target/llvm/codegen_cpu.h
+++ b/src/target/llvm/codegen_cpu.h
@@ -79,6 +79,8 @@ class CodeGenCPU : public CodeGenLLVM {
                                 const ffi::Array<Expr>& args, bool 
skip_first_arg) override;
 
  protected:
+  // Set attributes on the function outlined from a compute scope.
+  virtual void SetComputeScopeAttributes(llvm::Function* func) { 
SetTargetAttributes(func); }
   void AddStartupFunction() final;
   // meta data
   llvm::MDNode* md_tbaa_ctx_ptr_{nullptr};

Reply via email to