Skip to content

Commit

Permalink
[ARM] __ARM_ARCH macro definition fix (#81493)
Browse files Browse the repository at this point in the history
This patch changes how the macro __ARM_ARCH is defined to match its
defintion in the ACLE. In ACLE 5.4.1, __ARM_ARCH is defined as equal to
the major architecture version for ISAs up to and including v8. From
v8.1 onwards, its definition is changed to include minor versions, such
that for an architecture vX.Y, __ARM_ARCH = X*100 + Y. Before this
patch, LLVM defined __ARM_ARCH using only the major architecture version
for all architecture versions. This patch adds functionality to define
__ARM_ARCH correctly for architectures greater than or equal to v8.1.
  • Loading branch information
jwestwood921 committed Feb 13, 2024
1 parent 38c706e commit 89c1bf1
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 22 deletions.
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,8 @@ X86 Support
Arm and AArch64 Support
^^^^^^^^^^^^^^^^^^^^^^^

- Fixed the incorrect definition of the __ARM_ARCH macro for architectures greater than or equal to v8.1.

Android Support
^^^^^^^^^^^^^^^

Expand Down
16 changes: 14 additions & 2 deletions clang/lib/Basic/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -367,8 +367,20 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,

// ACLE predefines. Many can only have one possible value on v8 AArch64.
Builder.defineMacro("__ARM_ACLE", "200");
Builder.defineMacro("__ARM_ARCH",
std::to_string(ArchInfo->Version.getMajor()));

// __ARM_ARCH is defined as an integer value indicating the current ARM ISA.
// For ISAs up to and including v8, __ARM_ARCH is equal to the major version
// number. For ISAs from v8.1 onwards, __ARM_ARCH is scaled up to include the
// minor version number, e.g. for ARM architecture ARMvX.Y:
// __ARM_ARCH = X * 100 + Y.
if (ArchInfo->Version.getMajor() == 8 && ArchInfo->Version.getMinor() == 0)
Builder.defineMacro("__ARM_ARCH",
std::to_string(ArchInfo->Version.getMajor()));
else
Builder.defineMacro("__ARM_ARCH",
std::to_string(ArchInfo->Version.getMajor() * 100 +
ArchInfo->Version.getMinor().value()));

Builder.defineMacro("__ARM_ARCH_PROFILE",
std::string("'") + (char)ArchInfo->Profile + "'");

Expand Down
14 changes: 11 additions & 3 deletions clang/lib/Basic/Targets/ARM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ void ARMTargetInfo::setArchInfo(llvm::ARM::ArchKind Kind) {
SubArch = llvm::ARM::getSubArch(ArchKind);
ArchProfile = llvm::ARM::parseArchProfile(SubArch);
ArchVersion = llvm::ARM::parseArchVersion(SubArch);
ArchMinorVersion = llvm::ARM::parseArchMinorVersion(SubArch);

// cache CPU related strings
CPUAttr = getCPUAttr();
Expand Down Expand Up @@ -736,9 +737,16 @@ void ARMTargetInfo::getTargetDefines(const LangOptions &Opts,
if (!CPUAttr.empty())
Builder.defineMacro("__ARM_ARCH_" + CPUAttr + "__");

// ACLE 6.4.1 ARM/Thumb instruction set architecture
// __ARM_ARCH is defined as an integer value indicating the current ARM ISA
Builder.defineMacro("__ARM_ARCH", Twine(ArchVersion));
// __ARM_ARCH is defined as an integer value indicating the current ARM ISA.
// For ISAs up to and including v8, __ARM_ARCH is equal to the major version
// number. For ISAs from v8.1 onwards, __ARM_ARCH is scaled up to include the
// minor version number, e.g. for ARM architecture ARMvX.Y:
// __ARM_ARCH = X * 100 + Y.
if (ArchVersion >= 9 || ArchMinorVersion != 0)
Builder.defineMacro("__ARM_ARCH",
Twine(ArchVersion * 100 + ArchMinorVersion));
else
Builder.defineMacro("__ARM_ARCH", Twine(ArchVersion));

if (ArchVersion >= 8) {
// ACLE 6.5.7 Crypto Extension
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/ARM.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class LLVM_LIBRARY_VISIBILITY ARMTargetInfo : public TargetInfo {
llvm::ARM::ArchKind ArchKind = llvm::ARM::ArchKind::ARMV4T;
llvm::ARM::ProfileKind ArchProfile;
unsigned ArchVersion;
unsigned ArchMinorVersion;

LLVM_PREFERRED_TYPE(FPUMode)
unsigned FPU : 5;
Expand Down
34 changes: 17 additions & 17 deletions clang/test/Preprocessor/arm-target-features.c
Original file line number Diff line number Diff line change
Expand Up @@ -737,7 +737,7 @@

// Test whether predefines are as expected when targeting cortex-m55 (softfp FP ABI as default).
// RUN: %clang -target arm-eabi -mcpu=cortex-m55 -x c -E -dM %s -o - | FileCheck -match-full-lines --check-prefix=M55 %s
// M55: #define __ARM_ARCH 8
// M55: #define __ARM_ARCH 801
// M55: #define __ARM_ARCH_8_1M_MAIN__ 1
// M55: #define __ARM_ARCH_EXT_IDIV__ 1
// M55-NOT: __ARM_ARCH_ISA_ARM
Expand All @@ -764,7 +764,7 @@
// KRAIT-ALLOW-FP-INSTR:#define __ARM_VFPV4__ 1

// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -x c -E -dM %s -o - | FileCheck -match-full-lines --check-prefix=CHECK-V81M %s
// CHECK-V81M: #define __ARM_ARCH 8
// CHECK-V81M: #define __ARM_ARCH 801
// CHECK-V81M: #define __ARM_ARCH_8_1M_MAIN__ 1
// CHECK-V81M: #define __ARM_ARCH_ISA_THUMB 2
// CHECK-V81M: #define __ARM_ARCH_PROFILE 'M'
Expand Down Expand Up @@ -821,14 +821,14 @@
// CHECK-V8M-CDE-MASK2: #define __ARM_FEATURE_CDE_COPROC 0xff

// RUN: %clang -target armv8.1a-none-none-eabi -x c -E -dM %s -o - | FileCheck -match-full-lines --check-prefix=CHECK-V81A %s
// CHECK-V81A: #define __ARM_ARCH 8
// CHECK-V81A: #define __ARM_ARCH 801
// CHECK-V81A: #define __ARM_ARCH_8_1A__ 1
// CHECK-V81A: #define __ARM_ARCH_PROFILE 'A'
// CHECK-V81A: #define __ARM_FEATURE_QRDMX 1
// CHECK-V81A: #define __ARM_FP 0xe

// RUN: %clang -target armv8.2a-none-none-eabi -x c -E -dM %s -o - | FileCheck -match-full-lines --check-prefix=CHECK-V82A %s
// CHECK-V82A: #define __ARM_ARCH 8
// CHECK-V82A: #define __ARM_ARCH 802
// CHECK-V82A: #define __ARM_ARCH_8_2A__ 1
// CHECK-V82A: #define __ARM_ARCH_PROFILE 'A'
// CHECK-V82A: #define __ARM_FEATURE_QRDMX 1
Expand All @@ -838,67 +838,67 @@
// CHECK-DRIVERKIT-NOT: #define __ARM_PCS_VFP 1

// RUN: %clang -target armv8.3a-none-none-eabi -x c -E -dM %s -o - | FileCheck -match-full-lines --check-prefix=CHECK-V83A %s
// CHECK-V83A: #define __ARM_ARCH 8
// CHECK-V83A: #define __ARM_ARCH 803
// CHECK-V83A: #define __ARM_ARCH_8_3A__ 1
// CHECK-V83A: #define __ARM_ARCH_PROFILE 'A'

// RUN: %clang -target armv8.4a-none-none-eabi -x c -E -dM %s -o - | FileCheck -match-full-lines --check-prefix=CHECK-V84A %s
// CHECK-V84A: #define __ARM_ARCH 8
// CHECK-V84A: #define __ARM_ARCH 804
// CHECK-V84A: #define __ARM_ARCH_8_4A__ 1
// CHECK-V84A: #define __ARM_ARCH_PROFILE 'A'

// RUN: %clang -target armv8.5a-none-none-eabi -x c -E -dM %s -o - | FileCheck -match-full-lines --check-prefix=CHECK-V85A %s
// CHECK-V85A: #define __ARM_ARCH 8
// CHECK-V85A: #define __ARM_ARCH 805
// CHECK-V85A: #define __ARM_ARCH_8_5A__ 1
// CHECK-V85A: #define __ARM_ARCH_PROFILE 'A'

// RUN: %clang -target armv8.6a-none-none-eabi -x c -E -dM %s -o - | FileCheck -match-full-lines --check-prefix=CHECK-V86A %s
// CHECK-V86A: #define __ARM_ARCH 8
// CHECK-V86A: #define __ARM_ARCH 806
// CHECK-V86A: #define __ARM_ARCH_8_6A__ 1
// CHECK-V86A: #define __ARM_ARCH_PROFILE 'A'

// RUN: %clang -target armv8.7a-none-none-eabi -x c -E -dM %s -o - | FileCheck -match-full-lines --check-prefix=CHECK-V87A %s
// CHECK-V87A: #define __ARM_ARCH 8
// CHECK-V87A: #define __ARM_ARCH 807
// CHECK-V87A: #define __ARM_ARCH_8_7A__ 1
// CHECK-V87A: #define __ARM_ARCH_PROFILE 'A'

// RUN: %clang -target armv8.8a-none-none-eabi -x c -E -dM %s -o - | FileCheck -match-full-lines --check-prefix=CHECK-V88A %s
// CHECK-V88A: #define __ARM_ARCH 8
// CHECK-V88A: #define __ARM_ARCH 808
// CHECK-V88A: #define __ARM_ARCH_8_8A__ 1
// CHECK-V88A: #define __ARM_ARCH_PROFILE 'A'

// RUN: %clang -target armv8.9a-none-none-eabi -x c -E -dM %s -o - | FileCheck -match-full-lines --check-prefix=CHECK-V89A %s
// CHECK-V89A: #define __ARM_ARCH 8
// CHECK-V89A: #define __ARM_ARCH 809
// CHECK-V89A: #define __ARM_ARCH_8_9A__ 1
// CHECK-V89A: #define __ARM_ARCH_PROFILE 'A'

// RUN: %clang -target armv9a-none-none-eabi -x c -E -dM %s -o - | FileCheck -match-full-lines --check-prefix=CHECK-V9A %s
// CHECK-V9A: #define __ARM_ARCH 9
// CHECK-V9A: #define __ARM_ARCH 900
// CHECK-V9A: #define __ARM_ARCH_9A__ 1
// CHECK-V9A: #define __ARM_ARCH_PROFILE 'A'

// RUN: %clang -target armv9.1a-none-none-eabi -x c -E -dM %s -o - | FileCheck -match-full-lines --check-prefix=CHECK-V91A %s
// CHECK-V91A: #define __ARM_ARCH 9
// CHECK-V91A: #define __ARM_ARCH 901
// CHECK-V91A: #define __ARM_ARCH_9_1A__ 1
// CHECK-V91A: #define __ARM_ARCH_PROFILE 'A'

// RUN: %clang -target armv9.2a-none-none-eabi -x c -E -dM %s -o - | FileCheck -match-full-lines --check-prefix=CHECK-V92A %s
// CHECK-V92A: #define __ARM_ARCH 9
// CHECK-V92A: #define __ARM_ARCH 902
// CHECK-V92A: #define __ARM_ARCH_9_2A__ 1
// CHECK-V92A: #define __ARM_ARCH_PROFILE 'A'

// RUN: %clang -target armv9.3a-none-none-eabi -x c -E -dM %s -o - | FileCheck -match-full-lines --check-prefix=CHECK-V93A %s
// CHECK-V93A: #define __ARM_ARCH 9
// CHECK-V93A: #define __ARM_ARCH 903
// CHECK-V93A: #define __ARM_ARCH_9_3A__ 1
// CHECK-V93A: #define __ARM_ARCH_PROFILE 'A'

// RUN: %clang -target armv9.4a-none-none-eabi -x c -E -dM %s -o - | FileCheck -match-full-lines --check-prefix=CHECK-V94A %s
// CHECK-V94A: #define __ARM_ARCH 9
// CHECK-V94A: #define __ARM_ARCH 904
// CHECK-V94A: #define __ARM_ARCH_9_4A__ 1
// CHECK-V94A: #define __ARM_ARCH_PROFILE 'A'

// RUN: %clang -target armv9.5a-none-none-eabi -x c -E -dM %s -o - | FileCheck -match-full-lines --check-prefix=CHECK-V95A %s
// CHECK-V95A: #define __ARM_ARCH 9
// CHECK-V95A: #define __ARM_ARCH 905
// CHECK-V95A: #define __ARM_ARCH_9_5A__ 1
// CHECK-V95A: #define __ARM_ARCH_PROFILE 'A'

Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/TargetParser/ARMTargetParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ uint64_t parseArchExt(StringRef ArchExt);
ArchKind parseCPUArch(StringRef CPU);
ProfileKind parseArchProfile(StringRef Arch);
unsigned parseArchVersion(StringRef Arch);
unsigned parseArchMinorVersion(StringRef Arch);

void fillValidCPUArchList(SmallVectorImpl<StringRef> &Values);
StringRef computeDefaultTargetABI(const Triple &TT, StringRef CPU);
Expand Down
58 changes: 58 additions & 0 deletions llvm/lib/TargetParser/ARMTargetParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,64 @@ unsigned ARM::parseArchVersion(StringRef Arch) {
llvm_unreachable("Unhandled architecture");
}

unsigned ARM::parseArchMinorVersion(StringRef Arch) {
Arch = getCanonicalArchName(Arch);
switch (parseArch(Arch)) {
case ArchKind::ARMV4:
case ArchKind::ARMV4T:
case ArchKind::ARMV5T:
case ArchKind::ARMV5TE:
case ArchKind::IWMMXT:
case ArchKind::IWMMXT2:
case ArchKind::XSCALE:
case ArchKind::ARMV5TEJ:
case ArchKind::ARMV6:
case ArchKind::ARMV6K:
case ArchKind::ARMV6T2:
case ArchKind::ARMV6KZ:
case ArchKind::ARMV6M:
case ArchKind::ARMV7A:
case ArchKind::ARMV7VE:
case ArchKind::ARMV7R:
case ArchKind::ARMV7M:
case ArchKind::ARMV7S:
case ArchKind::ARMV7EM:
case ArchKind::ARMV7K:
case ArchKind::ARMV8A:
case ArchKind::ARMV8R:
case ArchKind::ARMV8MBaseline:
case ArchKind::ARMV8MMainline:
case ArchKind::ARMV9A:
case ArchKind::INVALID:
return 0;
case ArchKind::ARMV8_1A:
case ArchKind::ARMV8_1MMainline:
case ArchKind::ARMV9_1A:
return 1;
case ArchKind::ARMV8_2A:
case ArchKind::ARMV9_2A:
return 2;
case ArchKind::ARMV8_3A:
case ArchKind::ARMV9_3A:
return 3;
case ArchKind::ARMV8_4A:
case ArchKind::ARMV9_4A:
return 4;
case ArchKind::ARMV8_5A:
case ArchKind::ARMV9_5A:
return 5;
case ArchKind::ARMV8_6A:
return 6;
case ArchKind::ARMV8_7A:
return 7;
case ArchKind::ARMV8_8A:
return 8;
case ArchKind::ARMV8_9A:
return 9;
}
llvm_unreachable("Unhandled architecture");
}

static ARM::ProfileKind getProfileKind(ARM::ArchKind AK) {
switch (AK) {
case ARM::ArchKind::ARMV6M:
Expand Down
8 changes: 8 additions & 0 deletions llvm/unittests/TargetParser/TargetParserTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -976,6 +976,14 @@ TEST(TargetParserTest, ARMparseArchVersion) {
EXPECT_EQ(5u, ARM::parseArchVersion(ARMArch[i]));
}

TEST(TargetParserTest, ARMparseArchMinorVersion) {
for (unsigned i = 0; i < std::size(ARMArch); i++)
if (((std::string)ARMArch[i]).find(".") == 5)
EXPECT_EQ((ARMArch[i][6] - 48u), ARM::parseArchMinorVersion(ARMArch[i]));
else
EXPECT_EQ(0u, ARM::parseArchMinorVersion(ARMArch[i]));
}

TEST(TargetParserTest, getARMCPUForArch) {
// Platform specific defaults.
{
Expand Down

0 comments on commit 89c1bf1

Please sign in to comment.