diff --git a/clang/lib/Basic/Targets/AVR.cpp b/clang/lib/Basic/Targets/AVR.cpp --- 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 @@ } // namespace targets } // namespace clang +static bool ArchHasELPM(StringRef Arch) { + return llvm::StringSwitch(Arch) + .Cases("31", "51", "6", true) + .Cases("102", "104", "105", "106", "107", true) + .Default(false); +} + +static bool ArchHasELPMX(StringRef Arch) { + return llvm::StringSwitch(Arch) + .Cases("51", "6", true) + .Cases("102", "104", "105", "106", "107", true) + .Default(false); +} + +static bool ArchHasMOVW(StringRef Arch) { + return llvm::StringSwitch(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(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(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(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 @@ 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 --- 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 --- 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