llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Tom Vijlbrief (tomtor)

<details>
<summary>Changes</summary>

Newer AVR devices map (part of the) flash to a 32kB window at 0x8000 in the 
data/IO space.

The linker correctly loads readonly data at 0x8000, but we currently always 
pull in `__do_copy_data` when we encounter RO data.
This fails when we have no other initialized data in `.data` because the copy 
loop expects to copy at least 1 byte. When the size is `0` it tries to copy 
0x10000 bytes.

Newer versions of `avr-ld` (invoked via `avr-gcc`) handle this correctly, and 
users of newer devices must always install recent `avr-ld` and `avr-lib` 
versions to gain access to loader spec files and `crt` files. For older devices 
and older `avr-ld` the old approach remains unchanged.

Also add some support for devices with an `flmap` register (xmega2 and xmega4 
with &gt;= 64kB flash).

---
Full diff: https://github.com/llvm/llvm-project/pull/146244.diff


5 Files Affected:

- (modified) clang/include/clang/Driver/Options.td (+4) 
- (modified) clang/lib/Basic/Targets/AVR.cpp (+6) 
- (modified) clang/lib/Driver/ToolChains/AVR.cpp (+13-2) 
- (modified) llvm/lib/Target/AVR/AVRAsmPrinter.cpp (+10-4) 
- (modified) llvm/lib/Target/AVR/AVRDevices.td (+34-22) 


``````````diff
diff --git a/clang/include/clang/Driver/Options.td 
b/clang/include/clang/Driver/Options.td
index 0ffd8c40da7da..3a6f1bb2669a1 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4886,6 +4886,10 @@ def mguard_EQ : Joined<["-"], "mguard=">, Group<m_Group>,
   HelpText<"Enable or disable Control Flow Guard checks and guard tables 
emission">,
   Values<"none,cf,cf-nochecks">;
 def mmcu_EQ : Joined<["-"], "mmcu=">, Group<m_Group>;
+def mflmap : Flag<["-"], "mflmap">, Group<m_Group>,
+  HelpText<"Use AVR mapped memory for RO data">;
+def mrodata_in_ram : Flag<["-"], "mrodata-in-ram">, Group<m_Group>,
+  HelpText<"Copy RO data to ram">;
 def msim : Flag<["-"], "msim">, Group<m_Group>;
 def mfix_and_continue : Flag<["-"], "mfix-and-continue">, 
Group<clang_ignored_m_Group>;
 def mieee_fp : Flag<["-"], "mieee-fp">, Group<clang_ignored_m_Group>;
diff --git a/clang/lib/Basic/Targets/AVR.cpp b/clang/lib/Basic/Targets/AVR.cpp
index bbe7b01ca036d..448e72206776f 100644
--- a/clang/lib/Basic/Targets/AVR.cpp
+++ b/clang/lib/Basic/Targets/AVR.cpp
@@ -418,6 +418,10 @@ static MCUInfo AVRMcus[] = {
 } // namespace targets
 } // namespace clang
 
+static bool ArchHasFLMAP(StringRef Name) {
+  return Name.starts_with("avr64") or Name.starts_with("avr128");
+}
+
 static bool ArchHasELPM(StringRef Arch) {
   return llvm::StringSwitch<bool>(Arch)
     .Cases("31", "51", "6", true)
@@ -529,6 +533,8 @@ void AVRTargetInfo::getTargetDefines(const LangOptions 
&Opts,
   Builder.defineMacro("__AVR_ARCH__", Arch);
 
   // TODO: perhaps we should use the information from AVRDevices.td instead?
+  if (ArchHasFLMAP(DefineName))
+    Builder.defineMacro("__AVR_HAVE_FLMAP__");
   if (ArchHasELPM(Arch))
     Builder.defineMacro("__AVR_HAVE_ELPM__");
   if (ArchHasELPMX(Arch))
diff --git a/clang/lib/Driver/ToolChains/AVR.cpp 
b/clang/lib/Driver/ToolChains/AVR.cpp
index 731076d9754a9..155e0d812c95f 100644
--- a/clang/lib/Driver/ToolChains/AVR.cpp
+++ b/clang/lib/Driver/ToolChains/AVR.cpp
@@ -651,8 +651,19 @@ void AVR::Linker::ConstructJob(Compilation &C, const 
JobAction &JA,
   // This is almost always required because otherwise avr-ld
   // will assume 'avr2' and warn about the program being larger
   // than the bare minimum supports.
-  if (Linker.find("avr-ld") != std::string::npos && FamilyName)
-    CmdArgs.push_back(Args.MakeArgString(std::string("-m") + *FamilyName));
+  if (Linker.find("avr-ld") != std::string::npos && FamilyName) {
+    // Option to use mapped memory for modern devices with >32kB flash.
+    // This is the only option for modern devices with <= 32kB flash,
+    // but the larger default to a copy from flash to RAM (avr-ld version < 14)
+    // or map the highest 32kB to RAM (avr-ld version >= 14).
+    if (Args.hasFlag(options::OPT_mflmap, options::OPT_mrodata_in_ram, false)) 
{
+      CmdArgs.push_back(Args.MakeArgString(std::string("-m") + *FamilyName + 
"_flmap"));
+      CmdArgs.push_back(Args.MakeArgString(std::string("-u")));
+      CmdArgs.push_back(Args.MakeArgString(std::string("__do_flmap_init")));
+    }
+    else
+      CmdArgs.push_back(Args.MakeArgString(std::string("-m") + *FamilyName));
+  }
 
   C.addCommand(std::make_unique<Command>(
       JA, *this, ResponseFileSupport::AtFileCurCP(), 
Args.MakeArgString(Linker),
diff --git a/llvm/lib/Target/AVR/AVRAsmPrinter.cpp 
b/llvm/lib/Target/AVR/AVRAsmPrinter.cpp
index ad8aa5717fb42..decfcc4b67f5d 100644
--- a/llvm/lib/Target/AVR/AVRAsmPrinter.cpp
+++ b/llvm/lib/Target/AVR/AVRAsmPrinter.cpp
@@ -263,11 +263,17 @@ bool AVRAsmPrinter::doFinalization(Module &M) {
     auto *Section = cast<MCSectionELF>(TLOF.SectionForGlobal(&GO, TM));
     if (Section->getName().starts_with(".data"))
       NeedsCopyData = true;
-    else if (Section->getName().starts_with(".rodata") && SubTM->hasLPM())
+    else if (Section->getName().starts_with(".rodata") && SubTM->hasLPM()) {
       // AVRs that have a separate program memory (that's most AVRs) store
-      // .rodata sections in RAM.
-      NeedsCopyData = true;
-    else if (Section->getName().starts_with(".bss"))
+      // .rodata sections in RAM,
+      // but XMEGA3 family maps all flash in the data space.
+      // Invoking __do_copy_data with 0 bytes to copy will crash,
+      // so we let the loader handle this for newer devices.
+      if (!(SubTM->hasFeatureSetFamilyXMEGA2() ||
+            SubTM->hasFeatureSetFamilyXMEGA3() ||
+            SubTM->hasFeatureSetFamilyXMEGA4()))
+        NeedsCopyData = true;
+    } else if (Section->getName().starts_with(".bss"))
       NeedsClearBSS = true;
   }
 
diff --git a/llvm/lib/Target/AVR/AVRDevices.td 
b/llvm/lib/Target/AVR/AVRDevices.td
index ad760d7403573..0b6b0e3696e5f 100644
--- a/llvm/lib/Target/AVR/AVRDevices.td
+++ b/llvm/lib/Target/AVR/AVRDevices.td
@@ -49,6 +49,16 @@ def FeatureEIJMPCALL : SubtargetFeature<"eijmpcall", 
"HasEIJMPCALL", "true",
                                         "The device supports the "
                                         "`EIJMP`/`EICALL` instructions">;
 
+// The device supports `FLMAP` flash bank data mapping to the data space.
+def FeatureFLMAP : SubtargetFeature<"flmap", "HasFLMAP", "true",
+                                        "The device supports the "
+                                        "`FLMAP` mapping">;
+
+// The device maps all flash (<= 32kB) to the data space.
+def FeatureMAP : SubtargetFeature<"map", "HasMAP", "true",
+                                        "The device maps all flash (<= 32kB) "
+                                        "to the data space">;
+
 // The device supports `ADDI Rd, K`, `SUBI Rd, K`.
 def FeatureADDSUBIW : SubtargetFeature<"addsubiw", "HasADDSUBIW", "true",
                                        "Enable 16-bit register-immediate "
@@ -220,6 +230,7 @@ def FamilyXMEGA3 : Family<"xmega3",
                           [FamilyAVR0, FeatureLPM, FeatureIJMPCALL,
                            FeatureADDSUBIW, FeatureSRAM, FeatureJMPCALL,
                            FeatureMultiplication, FeatureMOVW, FeatureLPMX,
+                           FeatureMAP,
                            FeatureBREAK, FeatureLowByteFirst]>;
 
 def FamilyXMEGA4 : Family<"xmega4",
@@ -228,6 +239,7 @@ def FamilyXMEGA4 : Family<"xmega4",
                            FeatureMultiplication, FeatureMOVW, FeatureLPMX,
                            FeatureELPM, FeatureELPMX,
                            FeatureSPM, FeatureSPMX,
+                           FeatureFLMAP,
                            FeatureBREAK, FeatureLowByteFirst]>;
 
 def FamilyXMEGA : Family<"xmega",
@@ -275,9 +287,9 @@ def : Device<"avr5", FamilyAVR5, ELFArchAVR5>;
 def : Device<"avr51", FamilyAVR51, ELFArchAVR51>;
 def : Device<"avr6", FamilyAVR6, ELFArchAVR6>;
 def : Device<"avrxmega1", FamilyXMEGA, ELFArchXMEGA1>;
-def : Device<"avrxmega2", FamilyXMEGA, ELFArchXMEGA2>;
+def : Device<"avrxmega2", FamilyXMEGA2, ELFArchXMEGA2>;
 def : Device<"avrxmega3", FamilyXMEGA3, ELFArchXMEGA3>;
-def : Device<"avrxmega4", FamilyXMEGA, ELFArchXMEGA4>;
+def : Device<"avrxmega4", FamilyXMEGA4, ELFArchXMEGA4>;
 def : Device<"avrxmega5", FamilyXMEGA, ELFArchXMEGA5>;
 def : Device<"avrxmega6", FamilyXMEGA, ELFArchXMEGA6>;
 def : Device<"avrxmega7", FamilyXMEGA, ELFArchXMEGA7>;
@@ -596,26 +608,26 @@ def : Device<"atmega4809", FamilyXMEGA3, ELFArchXMEGA3>;
 
 // Additions from gcc 14:
 
-def : Device<"avr64da28", FamilyXMEGA2, ELFArchXMEGA2>;
-def : Device<"avr64da32", FamilyXMEGA2, ELFArchXMEGA2>;
-def : Device<"avr64da48", FamilyXMEGA2, ELFArchXMEGA2>;
-def : Device<"avr64da64", FamilyXMEGA2, ELFArchXMEGA2>;
-def : Device<"avr64db28", FamilyXMEGA2, ELFArchXMEGA2>;
-def : Device<"avr64db32", FamilyXMEGA2, ELFArchXMEGA2>;
-def : Device<"avr64db48", FamilyXMEGA2, ELFArchXMEGA2>;
-def : Device<"avr64db64", FamilyXMEGA2, ELFArchXMEGA2>;
-def : Device<"avr64dd14", FamilyXMEGA2, ELFArchXMEGA2>;
-def : Device<"avr64dd20", FamilyXMEGA2, ELFArchXMEGA2>;
-def : Device<"avr64dd28", FamilyXMEGA2, ELFArchXMEGA2>;
-def : Device<"avr64dd32", FamilyXMEGA2, ELFArchXMEGA2>;
-def : Device<"avr64du28", FamilyXMEGA2, ELFArchXMEGA2>;
-def : Device<"avr64du32", FamilyXMEGA2, ELFArchXMEGA2>;
-def : Device<"avr64ea28", FamilyXMEGA2, ELFArchXMEGA2>;
-def : Device<"avr64ea32", FamilyXMEGA2, ELFArchXMEGA2>;
-def : Device<"avr64ea48", FamilyXMEGA2, ELFArchXMEGA2>;
-def : Device<"avr64sd28", FamilyXMEGA2, ELFArchXMEGA2>;
-def : Device<"avr64sd32", FamilyXMEGA2, ELFArchXMEGA2>;
-def : Device<"avr64sd48", FamilyXMEGA2, ELFArchXMEGA2>;
+def : Device<"avr64da28", FamilyXMEGA2, ELFArchXMEGA2, [FeatureFLMAP]>;
+def : Device<"avr64da32", FamilyXMEGA2, ELFArchXMEGA2, [FeatureFLMAP]>;
+def : Device<"avr64da48", FamilyXMEGA2, ELFArchXMEGA2, [FeatureFLMAP]>;
+def : Device<"avr64da64", FamilyXMEGA2, ELFArchXMEGA2, [FeatureFLMAP]>;
+def : Device<"avr64db28", FamilyXMEGA2, ELFArchXMEGA2, [FeatureFLMAP]>;
+def : Device<"avr64db32", FamilyXMEGA2, ELFArchXMEGA2, [FeatureFLMAP]>;
+def : Device<"avr64db48", FamilyXMEGA2, ELFArchXMEGA2, [FeatureFLMAP]>;
+def : Device<"avr64db64", FamilyXMEGA2, ELFArchXMEGA2, [FeatureFLMAP]>;
+def : Device<"avr64dd14", FamilyXMEGA2, ELFArchXMEGA2, [FeatureFLMAP]>;
+def : Device<"avr64dd20", FamilyXMEGA2, ELFArchXMEGA2, [FeatureFLMAP]>;
+def : Device<"avr64dd28", FamilyXMEGA2, ELFArchXMEGA2, [FeatureFLMAP]>;
+def : Device<"avr64dd32", FamilyXMEGA2, ELFArchXMEGA2, [FeatureFLMAP]>;
+def : Device<"avr64du28", FamilyXMEGA2, ELFArchXMEGA2, [FeatureFLMAP]>;
+def : Device<"avr64du32", FamilyXMEGA2, ELFArchXMEGA2, [FeatureFLMAP]>;
+def : Device<"avr64ea28", FamilyXMEGA2, ELFArchXMEGA2, [FeatureFLMAP]>;
+def : Device<"avr64ea32", FamilyXMEGA2, ELFArchXMEGA2, [FeatureFLMAP]>;
+def : Device<"avr64ea48", FamilyXMEGA2, ELFArchXMEGA2, [FeatureFLMAP]>;
+def : Device<"avr64sd28", FamilyXMEGA2, ELFArchXMEGA2, [FeatureFLMAP]>;
+def : Device<"avr64sd32", FamilyXMEGA2, ELFArchXMEGA2, [FeatureFLMAP]>;
+def : Device<"avr64sd48", FamilyXMEGA2, ELFArchXMEGA2, [FeatureFLMAP]>;
 
 def : Device<"avr16dd20", FamilyXMEGA3, ELFArchXMEGA3>;
 def : Device<"avr16dd28", FamilyXMEGA3, ELFArchXMEGA3>;

``````````

</details>


https://github.com/llvm/llvm-project/pull/146244
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to