[clang] a8efcb9 - [AVR][Clang] Implement __AVR_HAVE_*__ macros

Ayke van Laethem via cfe-commits cfe-commits at lists.llvm.org
Tue Nov 22 16:22:36 PST 2022


Author: Ayke van Laethem
Date: 2022-11-23T01:21:09+01:00
New Revision: a8efcb96e6db91d1bcc5e56e08814330dbdbfccb

URL: https://github.com/llvm/llvm-project/commit/a8efcb96e6db91d1bcc5e56e08814330dbdbfccb
DIFF: https://github.com/llvm/llvm-project/commit/a8efcb96e6db91d1bcc5e56e08814330dbdbfccb.diff

LOG: [AVR][Clang] Implement __AVR_HAVE_*__ macros

These macros are defined in avr-gcc and are useful when working with
assembly. For example, startup code needs to copy the contents of .data
from flash to RAM, but should use elpm (instead of lpm) on devices with
more than 64kB flash. Without __AVR_HAVE_ELPM__, there is no way to know
whether the elpm instruction is supported.

This partially fixes https://github.com/llvm/llvm-project/issues/56157.

Differential Revision: https://reviews.llvm.org/D137572

Added: 
    

Modified: 
    clang/lib/Basic/Targets/AVR.cpp
    clang/test/Preprocessor/avr-atmega328p.c
    clang/test/Preprocessor/avr-attiny104.c

Removed: 
    


################################################################################
diff  --git a/clang/lib/Basic/Targets/AVR.cpp b/clang/lib/Basic/Targets/AVR.cpp
index e3d1c661df5a3..f2e5d970f3210 100644
--- a/clang/lib/Basic/Targets/AVR.cpp
+++ b/clang/lib/Basic/Targets/AVR.cpp
@@ -12,6 +12,7 @@
 
 #include "AVR.h"
 #include "clang/Basic/MacroBuilder.h"
+#include "llvm/ADT/StringSwitch.h"
 
 using namespace clang;
 using namespace clang::targets;
@@ -348,6 +349,58 @@ static MCUInfo AVRMcus[] = {
 } // namespace targets
 } // namespace clang
 
+static bool ArchHasELPM(StringRef Arch) {
+  return llvm::StringSwitch<bool>(Arch)
+    .Cases("31", "51", "6", true)
+    .Cases("102", "104", "105", "106", "107", true)
+    .Default(false);
+}
+
+static bool ArchHasELPMX(StringRef Arch) {
+  return llvm::StringSwitch<bool>(Arch)
+    .Cases("51", "6", true)
+    .Cases("102", "104", "105", "106", "107", true)
+    .Default(false);
+}
+
+static bool ArchHasMOVW(StringRef Arch) {
+  return llvm::StringSwitch<bool>(Arch)
+    .Cases("25", "35", "4", "5", "51", "6", true)
+    .Cases("102", "103", "104", "105", "106", "107", true)
+    .Default(false);
+}
+
+static bool ArchHasLPMX(StringRef Arch) {
+  return ArchHasMOVW(Arch); // same architectures
+}
+
+static bool ArchHasMUL(StringRef Arch) {
+  return llvm::StringSwitch<bool>(Arch)
+    .Cases("4", "5", "51", "6", true)
+    .Cases("102", "103", "104", "105", "106", "107", true)
+    .Default(false);
+}
+
+static bool ArchHasJMPCALL(StringRef Arch) {
+  return llvm::StringSwitch<bool>(Arch)
+    .Cases("3", "31", "35", "5", "51", "6", true)
+    .Cases("102", "103", "104", "105", "106", "107", true)
+    .Default(false);
+}
+
+static bool ArchHas3BytePC(StringRef Arch) {
+  // These devices have more than 128kB of program memory.
+  // Note:
+  //   - Not fully correct for arch 106: only about half the chips have more
+  //     than 128kB program memory and therefore a 3 byte PC.
+  //   - Doesn't match GCC entirely: avr-gcc thinks arch 107 goes beyond 128kB
+  //     but in fact it doesn't.
+  return llvm::StringSwitch<bool>(Arch)
+    .Case("6", true)
+    .Case("106", true)
+    .Default(false);
+}
+
 bool AVRTargetInfo::isValidCPUName(StringRef Name) const {
   return llvm::any_of(
       AVRMcus, [&](const MCUInfo &Info) { return Info.Name == Name; });
@@ -390,6 +443,30 @@ void AVRTargetInfo::getTargetDefines(const LangOptions &Opts,
 
   Builder.defineMacro("__AVR_ARCH__", Arch);
 
+  // TODO: perhaps we should use the information from AVRDevices.td instead?
+  if (ArchHasELPM(Arch))
+    Builder.defineMacro("__AVR_HAVE_ELPM__");
+  if (ArchHasELPMX(Arch))
+    Builder.defineMacro("__AVR_HAVE_ELPMX__");
+  if (ArchHasMOVW(Arch))
+    Builder.defineMacro("__AVR_HAVE_MOVW__");
+  if (ArchHasLPMX(Arch))
+    Builder.defineMacro("__AVR_HAVE_LPMX__");
+  if (ArchHasMUL(Arch))
+    Builder.defineMacro("__AVR_HAVE_MUL__");
+  if (ArchHasJMPCALL(Arch))
+    Builder.defineMacro("__AVR_HAVE_JMP_CALL__");
+  if (ArchHas3BytePC(Arch)) {
+    // Note: some devices do support eijmp/eicall even though this macro isn't
+    // set. This is the case if they have less than 128kB flash and so
+    // eijmp/eicall isn't very useful anyway. (This matches gcc, although it's
+    // debatable whether we should be bug-compatible in this case).
+    Builder.defineMacro("__AVR_HAVE_EIJMP_EICALL__");
+    Builder.defineMacro("__AVR_3_BYTE_PC__");
+  } else {
+    Builder.defineMacro("__AVR_2_BYTE_PC__");
+  }
+
   if (NumFlashBanks >= 1)
     Builder.defineMacro("__flash", "__attribute__((address_space(1)))");
   if (NumFlashBanks >= 2)

diff  --git a/clang/test/Preprocessor/avr-atmega328p.c b/clang/test/Preprocessor/avr-atmega328p.c
index 3ba71445d8cb5..f5f1ef13f151b 100644
--- a/clang/test/Preprocessor/avr-atmega328p.c
+++ b/clang/test/Preprocessor/avr-atmega328p.c
@@ -4,5 +4,9 @@
 // CHECK: #define __AVR 1
 // CHECK: #define __AVR_ARCH__ 5
 // CHECK: #define __AVR_ATmega328P__ 1
+// CHECK-NOT: #define __AVR_HAVE_EIJMP_EICALL__
+// CHECK: #define __AVR_HAVE_LPMX__ 1
+// CHECK: #define __AVR_HAVE_MOVW__ 1
+// CHECK: #define __AVR_HAVE_MUL__ 1
 // CHECK: #define __AVR__ 1
 // CHECK: #define __ELF__ 1

diff  --git a/clang/test/Preprocessor/avr-attiny104.c b/clang/test/Preprocessor/avr-attiny104.c
index f4f7fb8b8fa0c..16745a762ecb1 100644
--- a/clang/test/Preprocessor/avr-attiny104.c
+++ b/clang/test/Preprocessor/avr-attiny104.c
@@ -4,5 +4,6 @@
 // CHECK: #define __AVR 1
 // CHECK: #define __AVR_ARCH__ 100
 // CHECK: #define __AVR_ATtiny104__ 1
+// CHECK-NOT: #define __AVR_HAVE_MUL__ 1
 // CHECK: #define __AVR__ 1
 // CHECK: #define __ELF__ 1


        


More information about the cfe-commits mailing list