[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
This commit is contained in:
Ayke van Laethem 2022-11-07 18:46:38 +01:00
parent 27aabca058
commit a8efcb96e6
No known key found for this signature in database
GPG Key ID: E97FF5335DFDFDED
3 changed files with 82 additions and 0 deletions

View File

@ -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)

View File

@ -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

View File

@ -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