[llvm] Reland PR 174731, resolve cyclic dependency issue (PR #180468)

Ruoyu Qiu via llvm-commits llvm-commits at lists.llvm.org
Sun Feb 8 21:05:14 PST 2026


https://github.com/cabbaken created https://github.com/llvm/llvm-project/pull/180468

Reland #174731, resolve cyclic dependency issue.

The use of LLVM_Object in LLVM_Util would cause cyclic dependency.
Fix cyclic dependency by reimplement `getFeatureSetFromEFlag()`.

Original description:

---

This PR updates llvm-objdump to detect the specific AVR architecture from the ELF header flags when no specific CPU is provided.

Fixes: https://github.com/llvm/llvm-project/issues/146451


>From 70f5c20a68ff2e425624024045ae07f1a685b42c Mon Sep 17 00:00:00 2001
From: Ruoyu Qiu <cabbaken at outlook.com>
Date: Mon, 9 Feb 2026 04:56:55 +0000
Subject: [PATCH] Reland PR 174731, resolve cyclic dependency issue

Signed-off-by: Ruoyu Qiu <cabbaken at outlook.com>
---
 .../llvm/TargetParser/AVRTargetParser.h       | 28 ++++++++++
 llvm/include/llvm/TargetParser/Triple.h       |  2 +
 llvm/lib/TargetParser/AVRTargetParser.cpp     | 50 +++++++++++++++++
 llvm/lib/TargetParser/CMakeLists.txt          |  1 +
 .../tools/llvm-objdump/ELF/AVR/lit.local.cfg  |  2 +
 .../tools/llvm-objdump/ELF/AVR/mattr.test     | 55 +++++++++++++++++++
 llvm/tools/llvm-objdump/llvm-objdump.cpp      | 16 ++++++
 7 files changed, 154 insertions(+)
 create mode 100644 llvm/include/llvm/TargetParser/AVRTargetParser.h
 create mode 100644 llvm/lib/TargetParser/AVRTargetParser.cpp
 create mode 100644 llvm/test/tools/llvm-objdump/ELF/AVR/lit.local.cfg
 create mode 100644 llvm/test/tools/llvm-objdump/ELF/AVR/mattr.test

diff --git a/llvm/include/llvm/TargetParser/AVRTargetParser.h b/llvm/include/llvm/TargetParser/AVRTargetParser.h
new file mode 100644
index 0000000000000..6a44448d7b046
--- /dev/null
+++ b/llvm/include/llvm/TargetParser/AVRTargetParser.h
@@ -0,0 +1,28 @@
+//===-- AVRTargetParser - Parser for AVR target features ------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements a target parser to recognise AVR hardware features.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TARGETPARSER_AVRTARGETPARSER_H
+#define LLVM_TARGETPARSER_AVRTARGETPARSER_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include <string>
+
+namespace llvm {
+namespace AVR {
+
+LLVM_ABI Expected<std::string> getFeatureSetFromEFlag(const unsigned EFlag);
+
+} // namespace AVR
+} // namespace llvm
+#endif
diff --git a/llvm/include/llvm/TargetParser/Triple.h b/llvm/include/llvm/TargetParser/Triple.h
index 9480e7b36dc2c..3207c85c485da 100644
--- a/llvm/include/llvm/TargetParser/Triple.h
+++ b/llvm/include/llvm/TargetParser/Triple.h
@@ -1036,6 +1036,8 @@ class Triple {
                : PointerWidth == 64;
   }
 
+  bool isAVR() const { return getArch() == Triple::avr; }
+
   /// Tests whether the target is 32-bit LoongArch.
   bool isLoongArch32() const { return getArch() == Triple::loongarch32; }
 
diff --git a/llvm/lib/TargetParser/AVRTargetParser.cpp b/llvm/lib/TargetParser/AVRTargetParser.cpp
new file mode 100644
index 0000000000000..ef4a5cf09c20f
--- /dev/null
+++ b/llvm/lib/TargetParser/AVRTargetParser.cpp
@@ -0,0 +1,50 @@
+//===-- AVRTargetParser - Parser for AVR target features ------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements a target parser to recognise AVR hardware features.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/TargetParser/AVRTargetParser.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Support/Errc.h"
+
+using namespace llvm;
+
+Expected<std::string> AVR::getFeatureSetFromEFlag(const unsigned EFlag) {
+  static const DenseMap<unsigned, StringRef> EFlagToFeatureSet = {
+      {ELF::EF_AVR_ARCH_AVR1, "avr1"},
+      {ELF::EF_AVR_ARCH_AVR2, "avr2"},
+      {ELF::EF_AVR_ARCH_AVR25, "avr25"},
+      {ELF::EF_AVR_ARCH_AVR3, "avr3"},
+      {ELF::EF_AVR_ARCH_AVR31, "avr31"},
+      {ELF::EF_AVR_ARCH_AVR35, "avr35"},
+      {ELF::EF_AVR_ARCH_AVR4, "avr4"},
+      {ELF::EF_AVR_ARCH_AVR5, "avr5"},
+      {ELF::EF_AVR_ARCH_AVR51, "avr51"},
+      {ELF::EF_AVR_ARCH_AVR6, "avr6"},
+      {ELF::EF_AVR_ARCH_AVRTINY, "avrtiny"},
+      {ELF::EF_AVR_ARCH_XMEGA1, "xmega1"},
+      {ELF::EF_AVR_ARCH_XMEGA2, "xmega2"},
+      {ELF::EF_AVR_ARCH_XMEGA3, "xmega3"},
+      {ELF::EF_AVR_ARCH_XMEGA4, "xmega4"},
+      {ELF::EF_AVR_ARCH_XMEGA5, "xmega"},
+      {ELF::EF_AVR_ARCH_XMEGA6, "xmega"},
+      {ELF::EF_AVR_ARCH_XMEGA7, "xmega"},
+  };
+
+  auto It = EFlagToFeatureSet.find(EFlag);
+  if (It != EFlagToFeatureSet.end())
+    return It->second.str();
+
+  return createStringError(errc::invalid_argument,
+                           "unrecognised AVR version, 0x" +
+                               Twine::utohexstr(EFlag));
+}
diff --git a/llvm/lib/TargetParser/CMakeLists.txt b/llvm/lib/TargetParser/CMakeLists.txt
index e1a30199e1ade..8d474497f5308 100644
--- a/llvm/lib/TargetParser/CMakeLists.txt
+++ b/llvm/lib/TargetParser/CMakeLists.txt
@@ -17,6 +17,7 @@ add_llvm_component_library(LLVMTargetParser
   AArch64TargetParser.cpp
   ARMTargetParserCommon.cpp
   ARMTargetParser.cpp
+  AVRTargetParser.cpp
   CSKYTargetParser.cpp
   Host.cpp
   LoongArchTargetParser.cpp
diff --git a/llvm/test/tools/llvm-objdump/ELF/AVR/lit.local.cfg b/llvm/test/tools/llvm-objdump/ELF/AVR/lit.local.cfg
new file mode 100644
index 0000000000000..1724fb233c169
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/ELF/AVR/lit.local.cfg
@@ -0,0 +1,2 @@
+if not "AVR" in config.root.targets:
+    config.unsupported = True
diff --git a/llvm/test/tools/llvm-objdump/ELF/AVR/mattr.test b/llvm/test/tools/llvm-objdump/ELF/AVR/mattr.test
new file mode 100644
index 0000000000000..40b8f34bb6767
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/ELF/AVR/mattr.test
@@ -0,0 +1,55 @@
+## When --mattr and --mcpu are both empty, disassemble ELF with e_flags derived feature.
+# RUN: yaml2obj -DARCH_ARCHVERSION=EF_AVR_ARCH_AVR1 %s -o %t.avr1
+# RUN: llvm-objdump -d %t.avr1 | FileCheck %s --check-prefix=AVR1
+# RUN: yaml2obj -DARCH_ARCHVERSION=EF_AVR_ARCH_AVR3 %s -o %t.avr3
+# RUN: llvm-objdump -d %t.avr3 | FileCheck %s --check-prefix=ALL
+
+## The mask is being correctly applied before the version is determined.
+# RUN: yaml2obj -DARCH_ARCHVERSION='EF_AVR_ARCH_AVR3, EF_AVR_LINKRELAX_PREPARED' %s -o %t.multiflag
+# RUN: llvm-objdump -d %t.multiflag | FileCheck %s --check-prefix=ALL
+
+## If --mattr or --mcpu is specified, don't default to the file's e_flags derived feature.
+# RUN: llvm-objdump -d --mattr=+avr3 %t.avr1 | FileCheck %s --check-prefix=ALL
+# RUN: llvm-objdump -d --mcpu=avr3 %t.avr1 | FileCheck %s --check-prefix=ALL
+# RUN: llvm-objdump -d --mattr=+avr1 %t.avr3 | FileCheck %s --check-prefix=AVR1
+# RUN: llvm-objdump -d --mcpu=avr1 %t.avr3 | FileCheck %s --check-prefix=AVR1
+
+## If the file's e_flags doesn't representing an AVR version, default to "avr0".
+# RUN: yaml2obj -DARCH_ARCHVERSION=EF_AVR_LINKRELAX_PREPARED %s -o %t.noarchversion
+# RUN: llvm-objdump -d %t.noarchversion 2>&1 | FileCheck -DFILE=%t.noarchversion -DVERSION=0x0 %s --check-prefixes=AVR0,INVALIDARCHINFO
+
+## If file's e_flags is unrecognised, default to "avr0".
+# RUN: yaml2obj -DARCH_ARCHVERSION='EF_AVR_ARCH_AVR1, EF_AVR_ARCH_AVR6' %s -o %t.invalid
+# RUN: llvm-objdump -d %t.invalid 2>&1 | FileCheck -DFILE=%t.invalid -DVERSION=0x7 %s --check-prefixes=AVR0,INVALIDARCHINFO
+
+# AVR1:         <_start>:
+# AVR1-COUNT-2:  <unknown>
+# AVR1-NEXT:     lpm
+# AVR1-NEXT:     rjmp    .-2
+
+# ALL:      <_start>:
+# ALL-NEXT:   call    0x0
+# ALL-NEXT:   jmp     0x0
+# ALL-NEXT:   lpm
+# ALL-NEXT:   rjmp    .-2
+
+# INVALIDARCHINFO: warning: '[[FILE]]': unrecognised AVR version, [[VERSION]]: defaulting to avr0
+# AVR0:         <_start>:
+# AVR0-COUNT-3:   <unknown>
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS32
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_AVR
+  Flags:   [ [[ARCH_ARCHVERSION]] ]
+Sections:
+  - Name:    .text
+    Type:    SHT_PROGBITS
+    Flags:   [ SHF_ALLOC, SHF_EXECINSTR ]
+    Content: 0E9400000C940000C895FFCF
+Symbols:
+  - Name:    _start
+    Section: .text
+    Binding: STB_GLOBAL
diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp
index 97032eca5f2d1..6d0bc1a5942a5 100644
--- a/llvm/tools/llvm-objdump/llvm-objdump.cpp
+++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp
@@ -73,6 +73,7 @@
 #include "llvm/Support/TargetSelect.h"
 #include "llvm/Support/WithColor.h"
 #include "llvm/Support/raw_ostream.h"
+#include "llvm/TargetParser/AVRTargetParser.h"
 #include "llvm/TargetParser/Host.h"
 #include "llvm/TargetParser/Triple.h"
 #include <algorithm>
@@ -2643,6 +2644,21 @@ static void disassembleObject(ObjectFile *Obj, bool InlineRelocs,
       Features.AddFeature(MAttrs[I]);
   } else if (MCPU.empty() && Obj->makeTriple().isAArch64()) {
     Features.AddFeature("+all");
+  } else if (MCPU.empty() && Obj->makeTriple().isAVR()) {
+    if (const auto *Elf = dyn_cast<ELFObjectFileBase>(Obj)) {
+      if (Expected<std::string> VersionOrErr = AVR::getFeatureSetFromEFlag(
+              Elf->getPlatformFlags() & ELF::EF_AVR_ARCH_MASK)) {
+        Features.AddFeature('+' + *VersionOrErr);
+      } else {
+        // If the architecture version cannot be determined from ELF flags,
+        // fall back to the baseline "avr0" ISA. The AVR disassembler
+        // requires a valid feature specification to function correctly.
+        reportWarning(toString(VersionOrErr.takeError()) +
+                          ": defaulting to avr0",
+                      Obj->getFileName());
+        Features.AddFeature("+avr0");
+      }
+    }
   }
 
   if (MCPU.empty())



More information about the llvm-commits mailing list