https://github.com/tomtor created https://github.com/llvm/llvm-project/pull/146244
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 >= 64kB flash). >From 47e76c16b4352d968b0194bd7a046da3f83b37e3 Mon Sep 17 00:00:00 2001 From: Tom Vijlbrief <tvijlbr...@gmail.com> Date: Fri, 27 Jun 2025 17:16:35 +0200 Subject: [PATCH] [AVR] Handle mapped RO data for newer devices --- clang/include/clang/Driver/Options.td | 4 ++ clang/lib/Basic/Targets/AVR.cpp | 6 +++ clang/lib/Driver/ToolChains/AVR.cpp | 15 ++++++- llvm/lib/Target/AVR/AVRAsmPrinter.cpp | 14 +++++-- llvm/lib/Target/AVR/AVRDevices.td | 56 ++++++++++++++++----------- 5 files changed, 67 insertions(+), 28 deletions(-) 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>; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits